From 9c3c277ad7bf01b542fde818d7b0c2d713573f88 Mon Sep 17 00:00:00 2001 From: Tino Reichardt Date: Sun, 31 May 2020 13:08:03 +0200 Subject: [PATCH] Normalize all the line endings --- Asm/arm/7zCrcOpt.asm | 200 +- Asm/x86/7zAsm.asm | 294 +- Asm/x86/7zCrcOpt.asm | 294 +- Asm/x86/AesOpt.asm | 474 +- Asm/x86/LzmaDecOpt.asm | 2516 ++-- Asm/x86/XzCrc64Opt.asm | 410 +- C/7z.h | 404 +- C/7zAlloc.c | 160 +- C/7zAlloc.h | 38 +- C/7zArcIn.c | 3542 ++--- C/7zBuf.c | 72 +- C/7zBuf.h | 70 +- C/7zBuf2.c | 104 +- C/7zCrc.c | 256 +- C/7zCrc.h | 50 +- C/7zCrcOpt.c | 230 +- C/7zDec.c | 1182 +- C/7zFile.c | 572 +- C/7zFile.h | 166 +- C/7zStream.c | 352 +- C/7zTypes.h | 750 +- C/7zVersion.h | 54 +- C/7zVersion.rc | 110 +- C/7zVersionTr.h | 28 +- C/Aes.c | 612 +- C/Aes.h | 76 +- C/AesOpt.c | 368 +- C/Alloc.c | 910 +- C/Alloc.h | 102 +- C/Bcj2.c | 514 +- C/Bcj2.h | 292 +- C/Bcj2Enc.c | 622 +- C/Blake2.h | 96 +- C/Blake2s.c | 488 +- C/Bra.c | 460 +- C/Bra.h | 128 +- C/Bra86.c | 164 +- C/BraIA64.c | 106 +- C/BwtSort.c | 1030 +- C/BwtSort.h | 52 +- C/Compiler.h | 66 +- C/CpuArch.c | 436 +- C/CpuArch.h | 672 +- C/Delta.c | 128 +- C/Delta.h | 38 +- C/DllSecur.c | 216 +- C/DllSecur.h | 40 +- C/HuffEnc.c | 296 +- C/HuffEnc.h | 46 +- C/LzFind.c | 2254 +-- C/LzFind.h | 242 +- C/LzFindMt.c | 1706 +-- C/LzFindMt.h | 202 +- C/LzHash.h | 114 +- C/Lzma2Dec.c | 976 +- C/Lzma2Dec.h | 240 +- C/Lzma2DecMt.c | 2164 +-- C/Lzma2DecMt.h | 158 +- C/Lzma2Enc.c | 1606 +-- C/Lzma2Enc.h | 110 +- C/Lzma86.h | 222 +- C/Lzma86Dec.c | 108 +- C/Lzma86Enc.c | 212 +- C/LzmaDec.c | 2370 ++-- C/LzmaDec.h | 468 +- C/LzmaEnc.c | 5952 ++++---- C/LzmaEnc.h | 152 +- C/LzmaLib.c | 80 +- C/LzmaLib.h | 262 +- C/MtCoder.c | 1202 +- C/MtCoder.h | 282 +- C/MtDec.c | 2276 +-- C/MtDec.h | 402 +- C/Ppmd.h | 170 +- C/Ppmd7.c | 1424 +- C/Ppmd7.h | 284 +- C/Ppmd7Dec.c | 382 +- C/Ppmd7Enc.c | 374 +- C/Ppmd8.c | 2246 +-- C/Ppmd8.h | 274 +- C/Ppmd8Dec.c | 314 +- C/Ppmd8Enc.c | 326 +- C/Precomp.h | 20 +- C/RotateDefs.h | 60 +- C/Sha1.c | 680 +- C/Sha1.h | 76 +- C/Sha256.c | 496 +- C/Sha256.h | 52 +- C/Sort.c | 282 +- C/Sort.h | 36 +- C/Threads.c | 190 +- C/Threads.h | 136 +- C/Util/7z/7z.dsp | 482 +- C/Util/7z/7z.dsw | 58 +- C/Util/7z/7zMain.c | 1372 +- C/Util/7z/Precomp.c | 8 +- C/Util/7z/Precomp.h | 20 +- C/Util/7z/makefile | 80 +- C/Util/7z/makefile.gcc | 150 +- C/Util/7zipInstall/7zipInstall.c | 3196 ++--- C/Util/7zipInstall/7zipInstall.dsp | 480 +- C/Util/7zipInstall/7zipInstall.dsw | 58 +- C/Util/7zipInstall/7zipInstall.manifest | 36 +- C/Util/7zipInstall/Precomp.c | 8 +- C/Util/7zipInstall/Precomp.h | 22 +- C/Util/7zipInstall/makefile | 84 +- C/Util/7zipInstall/resource.h | 18 +- C/Util/7zipInstall/resource.rc | 94 +- C/Util/7zipUninstall/7zipUninstall.c | 2166 +-- C/Util/7zipUninstall/7zipUninstall.dsp | 248 +- C/Util/7zipUninstall/7zipUninstall.dsw | 58 +- C/Util/7zipUninstall/7zipUninstall.manifest | 36 +- C/Util/7zipUninstall/Precomp.c | 8 +- C/Util/7zipUninstall/Precomp.h | 22 +- C/Util/7zipUninstall/makefile | 36 +- C/Util/7zipUninstall/resource.h | 18 +- C/Util/7zipUninstall/resource.rc | 94 +- C/Util/Lzma/LzmaUtil.c | 516 +- C/Util/Lzma/LzmaUtil.dsp | 336 +- C/Util/Lzma/LzmaUtil.dsw | 58 +- C/Util/Lzma/makefile | 56 +- C/Util/Lzma/makefile.gcc | 88 +- C/Util/LzmaLib/LzmaLib.def | 8 +- C/Util/LzmaLib/LzmaLib.dsp | 356 +- C/Util/LzmaLib/LzmaLib.dsw | 58 +- C/Util/LzmaLib/LzmaLibExports.c | 28 +- C/Util/LzmaLib/makefile | 68 +- C/Util/LzmaLib/resource.rc | 6 +- C/Util/SfxSetup/Precomp.c | 8 +- C/Util/SfxSetup/Precomp.h | 20 +- C/Util/SfxSetup/SfxSetup.c | 1280 +- C/Util/SfxSetup/SfxSetup.dsp | 462 +- C/Util/SfxSetup/SfxSetup.dsw | 58 +- C/Util/SfxSetup/makefile | 74 +- C/Util/SfxSetup/makefile_con | 76 +- C/Util/SfxSetup/resource.rc | 10 +- C/Xz.c | 180 +- C/Xz.h | 920 +- C/XzCrc64.c | 172 +- C/XzCrc64.h | 52 +- C/XzCrc64Opt.c | 138 +- C/XzDec.c | 5532 ++++---- C/XzEnc.c | 2658 ++-- C/XzEnc.h | 120 +- C/XzIn.c | 638 +- CPP/7zip/7zip.mak | 610 +- CPP/7zip/Aes.mak | 14 +- CPP/7zip/Archive/7z/7z.dsp | 1284 +- CPP/7zip/Archive/7z/7z.dsw | 58 +- CPP/7zip/Archive/7z/7zCompressionMode.cpp | 6 +- CPP/7zip/Archive/7z/7zCompressionMode.h | 152 +- CPP/7zip/Archive/7z/7zDecode.cpp | 1138 +- CPP/7zip/Archive/7z/7zDecode.h | 140 +- CPP/7zip/Archive/7z/7zEncode.cpp | 1356 +- CPP/7zip/Archive/7z/7zEncode.h | 184 +- CPP/7zip/Archive/7z/7zExtract.cpp | 846 +- CPP/7zip/Archive/7z/7zFolderInStream.cpp | 278 +- CPP/7zip/Archive/7z/7zFolderInStream.h | 122 +- CPP/7zip/Archive/7z/7zHandler.cpp | 1758 +-- CPP/7zip/Archive/7z/7zHandler.h | 362 +- CPP/7zip/Archive/7z/7zHandlerOut.cpp | 1886 +-- CPP/7zip/Archive/7z/7zHeader.cpp | 38 +- CPP/7zip/Archive/7z/7zHeader.h | 310 +- CPP/7zip/Archive/7z/7zIn.cpp | 3332 ++--- CPP/7zip/Archive/7z/7zIn.h | 890 +- CPP/7zip/Archive/7z/7zItem.h | 404 +- CPP/7zip/Archive/7z/7zOut.cpp | 1802 +-- CPP/7zip/Archive/7z/7zOut.h | 670 +- CPP/7zip/Archive/7z/7zProperties.cpp | 348 +- CPP/7zip/Archive/7z/7zProperties.h | 44 +- CPP/7zip/Archive/7z/7zRegister.cpp | 42 +- CPP/7zip/Archive/7z/7zSpecStream.cpp | 44 +- CPP/7zip/Archive/7z/7zSpecStream.h | 70 +- CPP/7zip/Archive/7z/7zUpdate.cpp | 5000 +++---- CPP/7zip/Archive/7z/7zUpdate.h | 278 +- CPP/7zip/Archive/7z/StdAfx.cpp | 6 +- CPP/7zip/Archive/7z/StdAfx.h | 16 +- CPP/7zip/Archive/7z/makefile | 162 +- CPP/7zip/Archive/7z/resource.rc | 22 +- CPP/7zip/Archive/ApmHandler.cpp | 630 +- CPP/7zip/Archive/ArHandler.cpp | 1708 +-- CPP/7zip/Archive/Archive.def | 24 +- CPP/7zip/Archive/Archive2.def | 38 +- CPP/7zip/Archive/ArchiveExports.cpp | 302 +- CPP/7zip/Archive/ArjHandler.cpp | 1936 +-- CPP/7zip/Archive/Bz2Handler.cpp | 832 +- CPP/7zip/Archive/Cab/CabBlockInStream.cpp | 200 +- CPP/7zip/Archive/Cab/CabBlockInStream.h | 86 +- CPP/7zip/Archive/Cab/CabHandler.cpp | 2526 ++-- CPP/7zip/Archive/Cab/CabHandler.h | 74 +- CPP/7zip/Archive/Cab/CabHeader.cpp | 30 +- CPP/7zip/Archive/Cab/CabHeader.h | 82 +- CPP/7zip/Archive/Cab/CabIn.cpp | 982 +- CPP/7zip/Archive/Cab/CabIn.h | 352 +- CPP/7zip/Archive/Cab/CabItem.h | 132 +- CPP/7zip/Archive/Cab/CabRegister.cpp | 38 +- CPP/7zip/Archive/Cab/StdAfx.h | 16 +- CPP/7zip/Archive/Chm/ChmHandler.cpp | 1656 +-- CPP/7zip/Archive/Chm/ChmHandler.h | 70 +- CPP/7zip/Archive/Chm/ChmIn.cpp | 2036 +-- CPP/7zip/Archive/Chm/ChmIn.h | 540 +- CPP/7zip/Archive/Chm/StdAfx.h | 16 +- CPP/7zip/Archive/ComHandler.cpp | 1762 +-- CPP/7zip/Archive/Common/CoderMixer2.cpp | 2250 +-- CPP/7zip/Archive/Common/CoderMixer2.h | 894 +- CPP/7zip/Archive/Common/DummyOutStream.cpp | 34 +- CPP/7zip/Archive/Common/DummyOutStream.h | 50 +- CPP/7zip/Archive/Common/FindSignature.cpp | 124 +- CPP/7zip/Archive/Common/FindSignature.h | 24 +- CPP/7zip/Archive/Common/HandlerOut.cpp | 464 +- CPP/7zip/Archive/Common/HandlerOut.h | 220 +- CPP/7zip/Archive/Common/InStreamWithCRC.cpp | 92 +- CPP/7zip/Archive/Common/InStreamWithCRC.h | 134 +- CPP/7zip/Archive/Common/ItemNameUtils.cpp | 176 +- CPP/7zip/Archive/Common/ItemNameUtils.h | 56 +- CPP/7zip/Archive/Common/MultiStream.cpp | 382 +- CPP/7zip/Archive/Common/MultiStream.h | 178 +- CPP/7zip/Archive/Common/OutStreamWithCRC.cpp | 36 +- CPP/7zip/Archive/Common/OutStreamWithCRC.h | 74 +- CPP/7zip/Archive/Common/OutStreamWithSha1.cpp | 36 +- CPP/7zip/Archive/Common/OutStreamWithSha1.h | 72 +- CPP/7zip/Archive/Common/ParseProperties.cpp | 6 +- CPP/7zip/Archive/Common/ParseProperties.h | 12 +- CPP/7zip/Archive/Common/StdAfx.h | 16 +- CPP/7zip/Archive/CpioHandler.cpp | 1590 +-- CPP/7zip/Archive/CramfsHandler.cpp | 1574 +- CPP/7zip/Archive/DeflateProps.cpp | 6 +- CPP/7zip/Archive/DeflateProps.h | 12 +- CPP/7zip/Archive/DllExports.cpp | 188 +- CPP/7zip/Archive/DllExports2.cpp | 244 +- CPP/7zip/Archive/DmgHandler.cpp | 3714 ++--- CPP/7zip/Archive/ElfHandler.cpp | 2212 +-- CPP/7zip/Archive/ExtHandler.cpp | 5684 ++++---- CPP/7zip/Archive/FatHandler.cpp | 2126 +-- CPP/7zip/Archive/FlvHandler.cpp | 1052 +- CPP/7zip/Archive/GptHandler.cpp | 806 +- CPP/7zip/Archive/GzHandler.cpp | 2086 +-- CPP/7zip/Archive/HandlerCont.cpp | 576 +- CPP/7zip/Archive/HandlerCont.h | 232 +- CPP/7zip/Archive/HfsHandler.cpp | 3960 +++--- CPP/7zip/Archive/IArchive.h | 1216 +- CPP/7zip/Archive/IhexHandler.cpp | 994 +- CPP/7zip/Archive/Iso/IsoHandler.cpp | 978 +- CPP/7zip/Archive/Iso/IsoHandler.h | 62 +- CPP/7zip/Archive/Iso/IsoHeader.cpp | 24 +- CPP/7zip/Archive/Iso/IsoHeader.h | 128 +- CPP/7zip/Archive/Iso/IsoIn.cpp | 1338 +- CPP/7zip/Archive/Iso/IsoIn.h | 664 +- CPP/7zip/Archive/Iso/IsoItem.h | 642 +- CPP/7zip/Archive/Iso/IsoRegister.cpp | 42 +- CPP/7zip/Archive/Iso/StdAfx.h | 16 +- CPP/7zip/Archive/LizardHandler.cpp | 732 +- CPP/7zip/Archive/Lz4Handler.cpp | 732 +- CPP/7zip/Archive/Lz5Handler.cpp | 732 +- CPP/7zip/Archive/LzhHandler.cpp | 1516 +- CPP/7zip/Archive/LzmaHandler.cpp | 1258 +- CPP/7zip/Archive/MachoHandler.cpp | 1336 +- CPP/7zip/Archive/MbrHandler.cpp | 890 +- CPP/7zip/Archive/MslzHandler.cpp | 794 +- CPP/7zip/Archive/MubHandler.cpp | 492 +- CPP/7zip/Archive/Nsis/NsisDecode.cpp | 590 +- CPP/7zip/Archive/Nsis/NsisDecode.h | 194 +- CPP/7zip/Archive/Nsis/NsisHandler.cpp | 1372 +- CPP/7zip/Archive/Nsis/NsisHandler.h | 72 +- CPP/7zip/Archive/Nsis/NsisIn.cpp | 11832 ++++++++-------- CPP/7zip/Archive/Nsis/NsisIn.h | 900 +- CPP/7zip/Archive/Nsis/NsisRegister.cpp | 40 +- CPP/7zip/Archive/Nsis/StdAfx.h | 16 +- CPP/7zip/Archive/NtfsHandler.cpp | 5614 ++++---- CPP/7zip/Archive/PeHandler.cpp | 6476 ++++----- CPP/7zip/Archive/PpmdHandler.cpp | 958 +- CPP/7zip/Archive/QcowHandler.cpp | 1222 +- CPP/7zip/Archive/Rar/Rar5Handler.cpp | 6040 ++++---- CPP/7zip/Archive/Rar/Rar5Handler.h | 842 +- CPP/7zip/Archive/Rar/RarHandler.cpp | 3562 ++--- CPP/7zip/Archive/Rar/RarHandler.h | 232 +- CPP/7zip/Archive/Rar/RarHeader.h | 418 +- CPP/7zip/Archive/Rar/RarItem.h | 194 +- CPP/7zip/Archive/Rar/RarVol.h | 258 +- CPP/7zip/Archive/Rar/StdAfx.cpp | 6 +- CPP/7zip/Archive/Rar/StdAfx.h | 16 +- CPP/7zip/Archive/RpmHandler.cpp | 1548 +- CPP/7zip/Archive/SplitHandler.cpp | 718 +- CPP/7zip/Archive/SquashfsHandler.cpp | 4714 +++--- CPP/7zip/Archive/StdAfx.h | 16 +- CPP/7zip/Archive/SwfHandler.cpp | 1960 +-- CPP/7zip/Archive/Tar/StdAfx.h | 16 +- CPP/7zip/Archive/Tar/TarHandler.cpp | 1380 +- CPP/7zip/Archive/Tar/TarHandler.h | 158 +- CPP/7zip/Archive/Tar/TarHandlerOut.cpp | 352 +- CPP/7zip/Archive/Tar/TarHeader.cpp | 46 +- CPP/7zip/Archive/Tar/TarHeader.h | 168 +- CPP/7zip/Archive/Tar/TarIn.cpp | 1004 +- CPP/7zip/Archive/Tar/TarIn.h | 54 +- CPP/7zip/Archive/Tar/TarItem.h | 252 +- CPP/7zip/Archive/Tar/TarOut.cpp | 490 +- CPP/7zip/Archive/Tar/TarOut.h | 72 +- CPP/7zip/Archive/Tar/TarRegister.cpp | 46 +- CPP/7zip/Archive/Tar/TarUpdate.cpp | 532 +- CPP/7zip/Archive/Tar/TarUpdate.h | 76 +- CPP/7zip/Archive/Udf/StdAfx.h | 16 +- CPP/7zip/Archive/Udf/UdfHandler.cpp | 752 +- CPP/7zip/Archive/Udf/UdfHandler.h | 76 +- CPP/7zip/Archive/Udf/UdfIn.cpp | 2262 +-- CPP/7zip/Archive/Udf/UdfIn.h | 788 +- CPP/7zip/Archive/UefiHandler.cpp | 3784 ++--- CPP/7zip/Archive/VdiHandler.cpp | 862 +- CPP/7zip/Archive/VhdHandler.cpp | 1842 +-- CPP/7zip/Archive/VmdkHandler.cpp | 3028 ++-- CPP/7zip/Archive/Wim/StdAfx.h | 16 +- CPP/7zip/Archive/Wim/WimHandler.cpp | 2444 ++-- CPP/7zip/Archive/Wim/WimHandler.h | 206 +- CPP/7zip/Archive/Wim/WimHandlerOut.cpp | 3804 ++--- CPP/7zip/Archive/Wim/WimIn.cpp | 3746 ++--- CPP/7zip/Archive/Wim/WimIn.h | 1318 +- CPP/7zip/Archive/Wim/WimRegister.cpp | 44 +- CPP/7zip/Archive/XarHandler.cpp | 1464 +- CPP/7zip/Archive/XzHandler.cpp | 2616 ++-- CPP/7zip/Archive/XzHandler.h | 22 +- CPP/7zip/Archive/ZHandler.cpp | 472 +- CPP/7zip/Archive/Zip/StdAfx.h | 16 +- CPP/7zip/Archive/Zip/ZipAddCommon.cpp | 956 +- CPP/7zip/Archive/Zip/ZipAddCommon.h | 138 +- CPP/7zip/Archive/Zip/ZipCompressionMode.h | 108 +- CPP/7zip/Archive/Zip/ZipHandler.cpp | 2940 ++-- CPP/7zip/Archive/Zip/ZipHandler.h | 178 +- CPP/7zip/Archive/Zip/ZipHandlerOut.cpp | 1060 +- CPP/7zip/Archive/Zip/ZipHeader.h | 386 +- CPP/7zip/Archive/Zip/ZipIn.cpp | 6462 ++++----- CPP/7zip/Archive/Zip/ZipIn.h | 854 +- CPP/7zip/Archive/Zip/ZipItem.cpp | 734 +- CPP/7zip/Archive/Zip/ZipItem.h | 700 +- CPP/7zip/Archive/Zip/ZipOut.cpp | 696 +- CPP/7zip/Archive/Zip/ZipOut.h | 166 +- CPP/7zip/Archive/Zip/ZipRegister.cpp | 56 +- CPP/7zip/Archive/Zip/ZipUpdate.cpp | 2860 ++-- CPP/7zip/Archive/Zip/ZipUpdate.h | 160 +- CPP/7zip/Archive/ZstdHandler.cpp | 754 +- CPP/7zip/Archive/makefile | 46 +- CPP/7zip/Asm.mak | 18 +- CPP/7zip/Bundles/Alone/Alone.dsp | 6152 ++++---- CPP/7zip/Bundles/Alone/Alone.dsw | 58 +- CPP/7zip/Bundles/Alone/StdAfx.cpp | 6 +- CPP/7zip/Bundles/Alone/StdAfx.h | 16 +- CPP/7zip/Bundles/Alone/afxres.h | 2 +- CPP/7zip/Bundles/Alone/makefile | 696 +- CPP/7zip/Bundles/Alone/resource.rc | 14 +- CPP/7zip/Bundles/Alone7z/Alone.dsp | 3820 ++--- CPP/7zip/Bundles/Alone7z/Alone.dsw | 58 +- CPP/7zip/Bundles/Alone7z/StdAfx.cpp | 6 +- CPP/7zip/Bundles/Alone7z/StdAfx.h | 16 +- CPP/7zip/Bundles/Alone7z/makefile | 308 +- CPP/7zip/Bundles/Alone7z/resource.rc | 14 +- CPP/7zip/Bundles/Codec_brotli/StdAfx.cpp | 6 +- CPP/7zip/Bundles/Codec_brotli/StdAfx.h | 16 +- CPP/7zip/Bundles/Codec_brotli/makefile | 112 +- CPP/7zip/Bundles/Codec_brotli/resource.rc | 12 +- CPP/7zip/Bundles/Codec_lizard/StdAfx.cpp | 6 +- CPP/7zip/Bundles/Codec_lizard/StdAfx.h | 16 +- CPP/7zip/Bundles/Codec_lizard/makefile | 92 +- CPP/7zip/Bundles/Codec_lizard/resource.rc | 12 +- CPP/7zip/Bundles/Codec_lz4/StdAfx.cpp | 6 +- CPP/7zip/Bundles/Codec_lz4/StdAfx.h | 16 +- CPP/7zip/Bundles/Codec_lz4/makefile | 76 +- CPP/7zip/Bundles/Codec_lz4/resource.rc | 12 +- CPP/7zip/Bundles/Codec_lz5/StdAfx.cpp | 6 +- CPP/7zip/Bundles/Codec_lz5/StdAfx.h | 16 +- CPP/7zip/Bundles/Codec_lz5/makefile | 76 +- CPP/7zip/Bundles/Codec_lz5/resource.rc | 12 +- CPP/7zip/Bundles/Codec_zstd/StdAfx.cpp | 6 +- CPP/7zip/Bundles/Codec_zstd/StdAfx.h | 16 +- CPP/7zip/Bundles/Codec_zstd/makefile | 122 +- CPP/7zip/Bundles/Codec_zstd/resource.rc | 12 +- CPP/7zip/Bundles/Fm/FM.dsp | 4304 +++--- CPP/7zip/Bundles/Fm/FM.dsw | 58 +- CPP/7zip/Bundles/Fm/StdAfx.cpp | 6 +- CPP/7zip/Bundles/Fm/StdAfx.h | 32 +- CPP/7zip/Bundles/Fm/makefile | 162 +- CPP/7zip/Bundles/Fm/resource.rc | 14 +- CPP/7zip/Bundles/Format7z/StdAfx.cpp | 6 +- CPP/7zip/Bundles/Format7z/StdAfx.h | 16 +- CPP/7zip/Bundles/Format7z/makefile | 532 +- CPP/7zip/Bundles/Format7z/resource.rc | 10 +- CPP/7zip/Bundles/Format7zExtract/StdAfx.cpp | 6 +- CPP/7zip/Bundles/Format7zExtract/StdAfx.h | 16 +- CPP/7zip/Bundles/Format7zExtract/makefile | 422 +- CPP/7zip/Bundles/Format7zExtract/resource.rc | 10 +- CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp | 6 +- CPP/7zip/Bundles/Format7zExtractR/StdAfx.h | 16 +- CPP/7zip/Bundles/Format7zExtractR/makefile | 192 +- CPP/7zip/Bundles/Format7zExtractR/resource.rc | 10 +- CPP/7zip/Bundles/Format7zF/Arc.mak | 612 +- CPP/7zip/Bundles/Format7zF/Format7z.dsp | 6016 ++++---- CPP/7zip/Bundles/Format7zF/Format7z.dsw | 58 +- CPP/7zip/Bundles/Format7zF/StdAfx.cpp | 6 +- CPP/7zip/Bundles/Format7zF/StdAfx.h | 16 +- CPP/7zip/Bundles/Format7zF/makefile | 278 +- CPP/7zip/Bundles/Format7zF/resource.rc | 80 +- CPP/7zip/Bundles/Format7zR/StdAfx.cpp | 6 +- CPP/7zip/Bundles/Format7zR/StdAfx.h | 16 +- CPP/7zip/Bundles/Format7zR/makefile | 232 +- CPP/7zip/Bundles/Format7zR/resource.rc | 10 +- CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp | 1598 +-- CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp | 954 +- CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw | 58 +- CPP/7zip/Bundles/LzmaCon/StdAfx.cpp | 6 +- CPP/7zip/Bundles/LzmaCon/StdAfx.h | 16 +- CPP/7zip/Bundles/LzmaCon/makefile | 118 +- CPP/7zip/Bundles/LzmaCon/makefile.gcc | 390 +- CPP/7zip/Bundles/LzmaCon/resource.rc | 6 +- CPP/7zip/Bundles/SFXCon/SFXCon.dsp | 1824 +-- CPP/7zip/Bundles/SFXCon/SFXCon.dsw | 58 +- CPP/7zip/Bundles/SFXCon/SfxCon.cpp | 964 +- CPP/7zip/Bundles/SFXCon/StdAfx.cpp | 6 +- CPP/7zip/Bundles/SFXCon/StdAfx.h | 16 +- CPP/7zip/Bundles/SFXCon/makefile | 304 +- CPP/7zip/Bundles/SFXCon/resource.rc | 8 +- .../Bundles/SFXSetup/ExtractCallbackSfx.cpp | 492 +- .../Bundles/SFXSetup/ExtractCallbackSfx.h | 172 +- CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp | 274 +- CPP/7zip/Bundles/SFXSetup/ExtractEngine.h | 22 +- CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp | 1606 +-- CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw | 58 +- CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp | 728 +- CPP/7zip/Bundles/SFXSetup/StdAfx.cpp | 6 +- CPP/7zip/Bundles/SFXSetup/StdAfx.h | 26 +- CPP/7zip/Bundles/SFXSetup/resource.h | 12 +- CPP/7zip/Bundles/SFXSetup/resource.rc | 32 +- CPP/7zip/Bundles/SFXWin/SFXWin.dsp | 1976 +-- CPP/7zip/Bundles/SFXWin/SFXWin.dsw | 58 +- CPP/7zip/Bundles/SFXWin/SfxWin.cpp | 482 +- CPP/7zip/Bundles/SFXWin/StdAfx.cpp | 6 +- CPP/7zip/Bundles/SFXWin/StdAfx.h | 28 +- CPP/7zip/Bundles/SFXWin/makefile | 344 +- CPP/7zip/Bundles/SFXWin/resource.h | 2 +- CPP/7zip/Bundles/SFXWin/resource.rc | 100 +- CPP/7zip/Bundles/makefile | 36 +- CPP/7zip/Common/CWrappers.cpp | 500 +- CPP/7zip/Common/CWrappers.h | 240 +- CPP/7zip/Common/CreateCoder.cpp | 1072 +- CPP/7zip/Common/CreateCoder.h | 384 +- CPP/7zip/Common/FilePathAutoRename.cpp | 92 +- CPP/7zip/Common/FilePathAutoRename.h | 20 +- CPP/7zip/Common/FileStreams.cpp | 950 +- CPP/7zip/Common/FileStreams.h | 332 +- CPP/7zip/Common/FilterCoder.cpp | 870 +- CPP/7zip/Common/FilterCoder.h | 410 +- CPP/7zip/Common/InBuffer.cpp | 326 +- CPP/7zip/Common/InBuffer.h | 184 +- CPP/7zip/Common/InOutTempBuffer.cpp | 254 +- CPP/7zip/Common/InOutTempBuffer.h | 96 +- CPP/7zip/Common/LimitedStreams.cpp | 734 +- CPP/7zip/Common/LimitedStreams.h | 504 +- CPP/7zip/Common/LockedStream.cpp | 6 +- CPP/7zip/Common/LockedStream.h | 12 +- CPP/7zip/Common/MemBlocks.cpp | 366 +- CPP/7zip/Common/MemBlocks.h | 142 +- CPP/7zip/Common/MethodId.cpp | 6 +- CPP/7zip/Common/MethodId.h | 20 +- CPP/7zip/Common/MethodProps.cpp | 1046 +- CPP/7zip/Common/MethodProps.h | 528 +- CPP/7zip/Common/OffsetStream.cpp | 78 +- CPP/7zip/Common/OffsetStream.h | 52 +- CPP/7zip/Common/OutBuffer.cpp | 222 +- CPP/7zip/Common/OutBuffer.h | 132 +- CPP/7zip/Common/OutMemStream.cpp | 284 +- CPP/7zip/Common/OutMemStream.h | 194 +- CPP/7zip/Common/ProgressMt.cpp | 106 +- CPP/7zip/Common/ProgressMt.h | 92 +- CPP/7zip/Common/ProgressUtils.cpp | 102 +- CPP/7zip/Common/ProgressUtils.h | 70 +- CPP/7zip/Common/PropId.cpp | 216 +- CPP/7zip/Common/RegisterArc.h | 156 +- CPP/7zip/Common/RegisterCodec.h | 212 +- CPP/7zip/Common/StdAfx.h | 16 +- CPP/7zip/Common/StreamBinder.cpp | 312 +- CPP/7zip/Common/StreamBinder.h | 120 +- CPP/7zip/Common/StreamObjects.cpp | 570 +- CPP/7zip/Common/StreamObjects.h | 314 +- CPP/7zip/Common/StreamUtils.cpp | 112 +- CPP/7zip/Common/StreamUtils.h | 26 +- CPP/7zip/Common/UniqBlocks.cpp | 114 +- CPP/7zip/Common/UniqBlocks.h | 52 +- CPP/7zip/Common/VirtThread.cpp | 96 +- CPP/7zip/Common/VirtThread.h | 48 +- CPP/7zip/Compress/BZip2Const.h | 132 +- CPP/7zip/Compress/BZip2Crc.cpp | 52 +- CPP/7zip/Compress/BZip2Crc.h | 62 +- CPP/7zip/Compress/BZip2Decoder.cpp | 3490 ++--- CPP/7zip/Compress/BZip2Decoder.h | 764 +- CPP/7zip/Compress/BZip2Encoder.cpp | 1786 +-- CPP/7zip/Compress/BZip2Encoder.h | 478 +- CPP/7zip/Compress/BZip2Register.cpp | 50 +- CPP/7zip/Compress/Bcj2Coder.cpp | 1332 +- CPP/7zip/Compress/Bcj2Coder.h | 240 +- CPP/7zip/Compress/Bcj2Register.cpp | 48 +- CPP/7zip/Compress/BcjCoder.cpp | 48 +- CPP/7zip/Compress/BcjCoder.h | 62 +- CPP/7zip/Compress/BcjRegister.cpp | 34 +- CPP/7zip/Compress/BitlDecoder.cpp | 48 +- CPP/7zip/Compress/BitlDecoder.h | 292 +- CPP/7zip/Compress/BitlEncoder.h | 112 +- CPP/7zip/Compress/BitmDecoder.h | 200 +- CPP/7zip/Compress/BitmEncoder.h | 98 +- CPP/7zip/Compress/BranchMisc.cpp | 46 +- CPP/7zip/Compress/BranchMisc.h | 70 +- CPP/7zip/Compress/BranchRegister.cpp | 82 +- CPP/7zip/Compress/ByteSwap.cpp | 184 +- CPP/7zip/Compress/Codec.def | 12 +- CPP/7zip/Compress/CodecExports.cpp | 688 +- CPP/7zip/Compress/CopyCoder.cpp | 240 +- CPP/7zip/Compress/CopyCoder.h | 98 +- CPP/7zip/Compress/CopyRegister.cpp | 30 +- CPP/7zip/Compress/Deflate64Register.cpp | 52 +- CPP/7zip/Compress/DeflateConst.h | 262 +- CPP/7zip/Compress/DeflateDecoder.cpp | 1034 +- CPP/7zip/Compress/DeflateDecoder.h | 306 +- CPP/7zip/Compress/DeflateEncoder.cpp | 2006 +-- CPP/7zip/Compress/DeflateEncoder.h | 418 +- CPP/7zip/Compress/DeflateRegister.cpp | 50 +- CPP/7zip/Compress/DeltaFilter.cpp | 256 +- CPP/7zip/Compress/DllExports2Compress.cpp | 56 +- CPP/7zip/Compress/DllExportsCompress.cpp | 96 +- CPP/7zip/Compress/HuffmanDecoder.h | 556 +- CPP/7zip/Compress/ImplodeDecoder.cpp | 516 +- CPP/7zip/Compress/ImplodeDecoder.h | 146 +- CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp | 6 +- CPP/7zip/Compress/ImplodeHuffmanDecoder.h | 12 +- CPP/7zip/Compress/LzOutWindow.cpp | 28 +- CPP/7zip/Compress/LzOutWindow.h | 204 +- CPP/7zip/Compress/LzfseDecoder.cpp | 1850 +-- CPP/7zip/Compress/LzfseDecoder.h | 116 +- CPP/7zip/Compress/LzhDecoder.cpp | 500 +- CPP/7zip/Compress/LzhDecoder.h | 148 +- CPP/7zip/Compress/Lzma2Decoder.cpp | 530 +- CPP/7zip/Compress/Lzma2Decoder.h | 192 +- CPP/7zip/Compress/Lzma2Encoder.cpp | 778 +- CPP/7zip/Compress/Lzma2Encoder.h | 186 +- CPP/7zip/Compress/Lzma2Register.cpp | 44 +- CPP/7zip/Compress/LzmaDecoder.cpp | 686 +- CPP/7zip/Compress/LzmaDecoder.h | 226 +- CPP/7zip/Compress/LzmaEncoder.cpp | 364 +- CPP/7zip/Compress/LzmaEncoder.h | 92 +- CPP/7zip/Compress/LzmaRegister.cpp | 44 +- CPP/7zip/Compress/LzmsDecoder.cpp | 1152 +- CPP/7zip/Compress/LzmsDecoder.h | 542 +- CPP/7zip/Compress/Lzx.h | 114 +- CPP/7zip/Compress/LzxDecoder.cpp | 1058 +- CPP/7zip/Compress/LzxDecoder.h | 492 +- CPP/7zip/Compress/Mtf8.h | 424 +- CPP/7zip/Compress/PpmdDecoder.cpp | 340 +- CPP/7zip/Compress/PpmdDecoder.h | 172 +- CPP/7zip/Compress/PpmdEncoder.cpp | 304 +- CPP/7zip/Compress/PpmdEncoder.h | 116 +- CPP/7zip/Compress/PpmdRegister.cpp | 44 +- CPP/7zip/Compress/PpmdZip.cpp | 574 +- CPP/7zip/Compress/PpmdZip.h | 194 +- CPP/7zip/Compress/QuantumDecoder.cpp | 390 +- CPP/7zip/Compress/QuantumDecoder.h | 350 +- CPP/7zip/Compress/Rar1Decoder.cpp | 1032 +- CPP/7zip/Compress/Rar1Decoder.h | 158 +- CPP/7zip/Compress/Rar2Decoder.cpp | 870 +- CPP/7zip/Compress/Rar2Decoder.h | 344 +- CPP/7zip/Compress/Rar3Decoder.cpp | 1920 +-- CPP/7zip/Compress/Rar3Decoder.h | 572 +- CPP/7zip/Compress/Rar3Vm.cpp | 2278 +-- CPP/7zip/Compress/Rar3Vm.h | 390 +- CPP/7zip/Compress/Rar5Decoder.cpp | 1960 +-- CPP/7zip/Compress/Rar5Decoder.h | 614 +- CPP/7zip/Compress/RarCodecsRegister.cpp | 66 +- CPP/7zip/Compress/ShrinkDecoder.cpp | 488 +- CPP/7zip/Compress/ShrinkDecoder.h | 90 +- CPP/7zip/Compress/StdAfx.h | 16 +- CPP/7zip/Compress/XpressDecoder.cpp | 260 +- CPP/7zip/Compress/XpressDecoder.h | 26 +- CPP/7zip/Compress/XzDecoder.cpp | 300 +- CPP/7zip/Compress/XzDecoder.h | 184 +- CPP/7zip/Compress/XzEncoder.cpp | 490 +- CPP/7zip/Compress/XzEncoder.h | 92 +- CPP/7zip/Compress/ZDecoder.cpp | 474 +- CPP/7zip/Compress/ZDecoder.h | 108 +- CPP/7zip/Compress/ZlibDecoder.cpp | 184 +- CPP/7zip/Compress/ZlibDecoder.h | 158 +- CPP/7zip/Compress/ZlibEncoder.cpp | 122 +- CPP/7zip/Compress/ZlibEncoder.h | 96 +- CPP/7zip/Compress/makefile | 14 +- CPP/7zip/Crc.mak | 16 +- CPP/7zip/Crc64.mak | 16 +- CPP/7zip/Crypto/7zAes.cpp | 560 +- CPP/7zip/Crypto/7zAes.h | 236 +- CPP/7zip/Crypto/7zAesRegister.cpp | 34 +- CPP/7zip/Crypto/Codec.def | 8 +- CPP/7zip/Crypto/HmacSha1.cpp | 240 +- CPP/7zip/Crypto/HmacSha1.h | 78 +- CPP/7zip/Crypto/HmacSha256.cpp | 124 +- CPP/7zip/Crypto/HmacSha256.h | 54 +- CPP/7zip/Crypto/MyAes.cpp | 224 +- CPP/7zip/Crypto/MyAes.h | 114 +- CPP/7zip/Crypto/MyAesReg.cpp | 32 +- CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp | 194 +- CPP/7zip/Crypto/Pbkdf2HmacSha1.h | 44 +- CPP/7zip/Crypto/RandGen.cpp | 466 +- CPP/7zip/Crypto/RandGen.h | 80 +- CPP/7zip/Crypto/Rar20Crypto.cpp | 260 +- CPP/7zip/Crypto/Rar20Crypto.h | 96 +- CPP/7zip/Crypto/Rar5Aes.cpp | 514 +- CPP/7zip/Crypto/Rar5Aes.h | 168 +- CPP/7zip/Crypto/RarAes.cpp | 266 +- CPP/7zip/Crypto/RarAes.h | 104 +- CPP/7zip/Crypto/Sha1Cls.h | 102 +- CPP/7zip/Crypto/StdAfx.h | 16 +- CPP/7zip/Crypto/WzAes.cpp | 470 +- CPP/7zip/Crypto/WzAes.h | 274 +- CPP/7zip/Crypto/ZipCrypto.cpp | 228 +- CPP/7zip/Crypto/ZipCrypto.h | 150 +- CPP/7zip/Crypto/ZipStrong.cpp | 480 +- CPP/7zip/Crypto/ZipStrong.h | 130 +- CPP/7zip/GuiCommon.rc | 168 +- CPP/7zip/Guid.txt | 450 +- CPP/7zip/ICoder.h | 830 +- CPP/7zip/IDecl.h | 56 +- CPP/7zip/IPassword.h | 46 +- CPP/7zip/IProgress.h | 38 +- CPP/7zip/IStream.h | 254 +- CPP/7zip/LzmaDec.mak | 10 +- CPP/7zip/MyVersion.h | 4 +- CPP/7zip/MyVersionInfo.rc | 4 +- CPP/7zip/PropID.h | 254 +- CPP/7zip/SubBuild.mak | 6 +- CPP/7zip/UI/Agent/Agent.cpp | 3770 ++--- CPP/7zip/UI/Agent/Agent.h | 688 +- CPP/7zip/UI/Agent/AgentOut.cpp | 1418 +- CPP/7zip/UI/Agent/AgentProxy.cpp | 1434 +- CPP/7zip/UI/Agent/AgentProxy.h | 324 +- CPP/7zip/UI/Agent/ArchiveFolder.cpp | 88 +- CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp | 282 +- CPP/7zip/UI/Agent/ArchiveFolderOut.cpp | 746 +- CPP/7zip/UI/Agent/IFolderArchive.h | 238 +- CPP/7zip/UI/Agent/StdAfx.h | 16 +- CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp | 416 +- CPP/7zip/UI/Agent/UpdateCallbackAgent.h | 44 +- CPP/7zip/UI/Client7z/Client7z.cpp | 1986 +-- CPP/7zip/UI/Client7z/Client7z.dsp | 470 +- CPP/7zip/UI/Client7z/Client7z.dsw | 58 +- CPP/7zip/UI/Client7z/StdAfx.cpp | 6 +- CPP/7zip/UI/Client7z/StdAfx.h | 16 +- CPP/7zip/UI/Client7z/makefile | 56 +- CPP/7zip/UI/Client7z/resource.rc | 6 +- CPP/7zip/UI/Common/ArchiveCommandLine.cpp | 2590 ++-- CPP/7zip/UI/Common/ArchiveCommandLine.h | 272 +- CPP/7zip/UI/Common/ArchiveExtractCallback.cpp | 3430 ++--- CPP/7zip/UI/Common/ArchiveExtractCallback.h | 806 +- CPP/7zip/UI/Common/ArchiveName.cpp | 310 +- CPP/7zip/UI/Common/ArchiveName.h | 20 +- CPP/7zip/UI/Common/ArchiveOpenCallback.cpp | 322 +- CPP/7zip/UI/Common/ArchiveOpenCallback.h | 224 +- CPP/7zip/UI/Common/Bench.cpp | 7236 +++++----- CPP/7zip/UI/Common/Bench.h | 154 +- CPP/7zip/UI/Common/CompressCall.cpp | 764 +- CPP/7zip/UI/Common/CompressCall.h | 46 +- CPP/7zip/UI/Common/CompressCall2.cpp | 552 +- CPP/7zip/UI/Common/DefaultName.cpp | 74 +- CPP/7zip/UI/Common/DefaultName.h | 22 +- CPP/7zip/UI/Common/DirItem.h | 380 +- CPP/7zip/UI/Common/EnumDirItems.cpp | 2192 +-- CPP/7zip/UI/Common/EnumDirItems.h | 84 +- CPP/7zip/UI/Common/ExitCode.h | 54 +- CPP/7zip/UI/Common/Extract.cpp | 964 +- CPP/7zip/UI/Common/Extract.h | 188 +- CPP/7zip/UI/Common/ExtractMode.h | 68 +- CPP/7zip/UI/Common/ExtractingFilePath.cpp | 560 +- CPP/7zip/UI/Common/ExtractingFilePath.h | 62 +- CPP/7zip/UI/Common/HashCalc.cpp | 694 +- CPP/7zip/UI/Common/HashCalc.h | 220 +- CPP/7zip/UI/Common/IFileExtractCallback.h | 228 +- CPP/7zip/UI/Common/LoadCodecs.cpp | 2148 +-- CPP/7zip/UI/Common/LoadCodecs.h | 848 +- CPP/7zip/UI/Common/OpenArchive.cpp | 7108 +++++----- CPP/7zip/UI/Common/OpenArchive.h | 872 +- CPP/7zip/UI/Common/PropIDUtils.cpp | 1336 +- CPP/7zip/UI/Common/PropIDUtils.h | 36 +- CPP/7zip/UI/Common/Property.h | 28 +- CPP/7zip/UI/Common/SetProperties.cpp | 160 +- CPP/7zip/UI/Common/SetProperties.h | 20 +- CPP/7zip/UI/Common/SortUtils.cpp | 50 +- CPP/7zip/UI/Common/SortUtils.h | 20 +- CPP/7zip/UI/Common/StdAfx.h | 16 +- CPP/7zip/UI/Common/TempFiles.cpp | 38 +- CPP/7zip/UI/Common/TempFiles.h | 32 +- CPP/7zip/UI/Common/Update.cpp | 3408 ++--- CPP/7zip/UI/Common/Update.h | 400 +- CPP/7zip/UI/Common/UpdateAction.cpp | 128 +- CPP/7zip/UI/Common/UpdateAction.h | 132 +- CPP/7zip/UI/Common/UpdateCallback.cpp | 1542 +- CPP/7zip/UI/Common/UpdateCallback.h | 324 +- CPP/7zip/UI/Common/UpdatePair.cpp | 466 +- CPP/7zip/UI/Common/UpdatePair.h | 54 +- CPP/7zip/UI/Common/UpdateProduce.cpp | 140 +- CPP/7zip/UI/Common/UpdateProduce.h | 110 +- CPP/7zip/UI/Common/WorkDir.cpp | 188 +- CPP/7zip/UI/Common/WorkDir.h | 52 +- CPP/7zip/UI/Common/ZipRegistry.cpp | 826 +- CPP/7zip/UI/Common/ZipRegistry.h | 262 +- CPP/7zip/UI/Console/BenchCon.cpp | 82 +- CPP/7zip/UI/Console/BenchCon.h | 28 +- CPP/7zip/UI/Console/Console.dsp | 1968 +-- CPP/7zip/UI/Console/Console.dsw | 58 +- CPP/7zip/UI/Console/Console.mak | 86 +- CPP/7zip/UI/Console/Console.manifest | 24 +- CPP/7zip/UI/Console/ConsoleClose.cpp | 138 +- CPP/7zip/UI/Console/ConsoleClose.h | 66 +- .../UI/Console/ExtractCallbackConsole.cpp | 1650 +-- CPP/7zip/UI/Console/ExtractCallbackConsole.h | 328 +- CPP/7zip/UI/Console/HashCon.cpp | 734 +- CPP/7zip/UI/Console/HashCon.h | 96 +- CPP/7zip/UI/Console/List.cpp | 2718 ++-- CPP/7zip/UI/Console/List.h | 54 +- CPP/7zip/UI/Console/Main.cpp | 2308 +-- CPP/7zip/UI/Console/MainAr.cpp | 350 +- CPP/7zip/UI/Console/OpenCallbackConsole.cpp | 230 +- CPP/7zip/UI/Console/OpenCallbackConsole.h | 132 +- CPP/7zip/UI/Console/PercentPrinter.cpp | 366 +- CPP/7zip/UI/Console/PercentPrinter.h | 124 +- CPP/7zip/UI/Console/StdAfx.cpp | 6 +- CPP/7zip/UI/Console/StdAfx.h | 16 +- CPP/7zip/UI/Console/UpdateCallbackConsole.cpp | 1404 +- CPP/7zip/UI/Console/UpdateCallbackConsole.h | 248 +- CPP/7zip/UI/Console/UserInputUtils.cpp | 220 +- CPP/7zip/UI/Console/UserInputUtils.h | 54 +- CPP/7zip/UI/Console/makefile | 128 +- CPP/7zip/UI/Console/resource.rc | 14 +- CPP/7zip/UI/Explorer/7-zip.dll.manifest | 2 +- CPP/7zip/UI/Explorer/ContextMenu.cpp | 2072 +-- CPP/7zip/UI/Explorer/ContextMenu.h | 186 +- CPP/7zip/UI/Explorer/ContextMenuFlags.h | 52 +- CPP/7zip/UI/Explorer/DllExportsExplorer.cpp | 432 +- CPP/7zip/UI/Explorer/Explorer.def | 18 +- CPP/7zip/UI/Explorer/Explorer.dsp | 1118 +- CPP/7zip/UI/Explorer/Explorer.dsw | 58 +- CPP/7zip/UI/Explorer/MyMessages.cpp | 74 +- CPP/7zip/UI/Explorer/MyMessages.h | 32 +- CPP/7zip/UI/Explorer/RegistryContextMenu.cpp | 448 +- CPP/7zip/UI/Explorer/RegistryContextMenu.h | 26 +- CPP/7zip/UI/Explorer/StdAfx.cpp | 6 +- CPP/7zip/UI/Explorer/StdAfx.h | 28 +- CPP/7zip/UI/Explorer/makefile | 150 +- CPP/7zip/UI/Explorer/resource.h | 26 +- CPP/7zip/UI/Explorer/resource.rc | 16 +- CPP/7zip/UI/Explorer/resource2.rc | 36 +- CPP/7zip/UI/Far/ExtractEngine.cpp | 550 +- CPP/7zip/UI/Far/ExtractEngine.h | 114 +- CPP/7zip/UI/Far/Far.cpp | 1268 +- CPP/7zip/UI/Far/Far.def | 70 +- CPP/7zip/UI/Far/Far.dsp | 1518 +- CPP/7zip/UI/Far/Far.dsw | 58 +- CPP/7zip/UI/Far/FarPlugin.h | 1058 +- CPP/7zip/UI/Far/FarUtils.cpp | 1042 +- CPP/7zip/UI/Far/FarUtils.h | 394 +- CPP/7zip/UI/Far/Messages.h | 272 +- CPP/7zip/UI/Far/OverwriteDialogFar.cpp | 290 +- CPP/7zip/UI/Far/OverwriteDialogFar.h | 74 +- CPP/7zip/UI/Far/Plugin.cpp | 1844 +-- CPP/7zip/UI/Far/Plugin.h | 188 +- CPP/7zip/UI/Far/PluginCommon.cpp | 100 +- CPP/7zip/UI/Far/PluginDelete.cpp | 240 +- CPP/7zip/UI/Far/PluginRead.cpp | 590 +- CPP/7zip/UI/Far/PluginWrite.cpp | 1654 +-- CPP/7zip/UI/Far/ProgressBox.cpp | 610 +- CPP/7zip/UI/Far/ProgressBox.h | 166 +- CPP/7zip/UI/Far/StdAfx.cpp | 6 +- CPP/7zip/UI/Far/StdAfx.h | 16 +- CPP/7zip/UI/Far/UpdateCallbackFar.cpp | 474 +- CPP/7zip/UI/Far/UpdateCallbackFar.h | 120 +- CPP/7zip/UI/Far/makefile | 204 +- CPP/7zip/UI/Far/resource.rc | 6 +- CPP/7zip/UI/FileManager/7zFM.exe.manifest | 40 +- CPP/7zip/UI/FileManager/AboutDialog.cpp | 122 +- CPP/7zip/UI/FileManager/AboutDialog.h | 38 +- CPP/7zip/UI/FileManager/AboutDialog.rc | 54 +- CPP/7zip/UI/FileManager/AboutDialogRes.h | 18 +- CPP/7zip/UI/FileManager/AltStreamsFolder.cpp | 1678 +-- CPP/7zip/UI/FileManager/AltStreamsFolder.h | 200 +- CPP/7zip/UI/FileManager/App.cpp | 1994 +-- CPP/7zip/UI/FileManager/App.h | 740 +- CPP/7zip/UI/FileManager/AppState.h | 190 +- CPP/7zip/UI/FileManager/BrowseDialog.cpp | 2050 +-- CPP/7zip/UI/FileManager/BrowseDialog.h | 42 +- CPP/7zip/UI/FileManager/BrowseDialog.rc | 50 +- CPP/7zip/UI/FileManager/BrowseDialogRes.h | 18 +- CPP/7zip/UI/FileManager/ClassDefs.cpp | 22 +- CPP/7zip/UI/FileManager/ComboDialog.cpp | 128 +- CPP/7zip/UI/FileManager/ComboDialog.h | 56 +- CPP/7zip/UI/FileManager/ComboDialog.rc | 32 +- CPP/7zip/UI/FileManager/ComboDialogRes.h | 8 +- CPP/7zip/UI/FileManager/CopyDialog.cpp | 212 +- CPP/7zip/UI/FileManager/CopyDialog.h | 62 +- CPP/7zip/UI/FileManager/CopyDialog.rc | 40 +- CPP/7zip/UI/FileManager/CopyDialogRes.h | 16 +- CPP/7zip/UI/FileManager/DialogSize.h | 32 +- CPP/7zip/UI/FileManager/EditDialog.cpp | 114 +- CPP/7zip/UI/FileManager/EditDialog.h | 50 +- CPP/7zip/UI/FileManager/EditDialog.rc | 30 +- CPP/7zip/UI/FileManager/EditDialogRes.h | 4 +- CPP/7zip/UI/FileManager/EditPage.cpp | 294 +- CPP/7zip/UI/FileManager/EditPage.h | 60 +- CPP/7zip/UI/FileManager/EditPage.rc | 38 +- CPP/7zip/UI/FileManager/EditPage2.rc | 28 +- CPP/7zip/UI/FileManager/EditPageRes.h | 30 +- CPP/7zip/UI/FileManager/EnumFormatEtc.cpp | 216 +- CPP/7zip/UI/FileManager/EnumFormatEtc.h | 20 +- CPP/7zip/UI/FileManager/ExtractCallback.cpp | 2074 +-- CPP/7zip/UI/FileManager/ExtractCallback.h | 656 +- CPP/7zip/UI/FileManager/FM.cpp | 2152 +-- CPP/7zip/UI/FileManager/FM.dsp | 3230 ++--- CPP/7zip/UI/FileManager/FM.dsw | 58 +- CPP/7zip/UI/FileManager/FM.mak | 198 +- CPP/7zip/UI/FileManager/FSDrives.cpp | 988 +- CPP/7zip/UI/FileManager/FSDrives.h | 118 +- CPP/7zip/UI/FileManager/FSFolder.cpp | 2210 +-- CPP/7zip/UI/FileManager/FSFolder.h | 430 +- CPP/7zip/UI/FileManager/FSFolderCopy.cpp | 1340 +- .../UI/FileManager/FileFolderPluginOpen.cpp | 366 +- .../UI/FileManager/FileFolderPluginOpen.h | 18 +- CPP/7zip/UI/FileManager/FilePlugins.cpp | 138 +- CPP/7zip/UI/FileManager/FilePlugins.h | 66 +- CPP/7zip/UI/FileManager/FoldersPage.cpp | 332 +- CPP/7zip/UI/FileManager/FoldersPage.h | 64 +- CPP/7zip/UI/FileManager/FoldersPage.rc | 46 +- CPP/7zip/UI/FileManager/FoldersPage2.rc | 32 +- CPP/7zip/UI/FileManager/FoldersPageRes.h | 24 +- CPP/7zip/UI/FileManager/FormatUtils.cpp | 56 +- CPP/7zip/UI/FileManager/FormatUtils.h | 28 +- CPP/7zip/UI/FileManager/HelpUtils.cpp | 64 +- CPP/7zip/UI/FileManager/HelpUtils.h | 20 +- CPP/7zip/UI/FileManager/IFolder.h | 436 +- CPP/7zip/UI/FileManager/LangPage.cpp | 240 +- CPP/7zip/UI/FileManager/LangPage.h | 50 +- CPP/7zip/UI/FileManager/LangPage.rc | 74 +- CPP/7zip/UI/FileManager/LangPageRes.h | 16 +- CPP/7zip/UI/FileManager/LangUtils.cpp | 584 +- CPP/7zip/UI/FileManager/LangUtils.h | 80 +- CPP/7zip/UI/FileManager/LinkDialog.cpp | 708 +- CPP/7zip/UI/FileManager/LinkDialog.h | 68 +- CPP/7zip/UI/FileManager/LinkDialog.rc | 72 +- CPP/7zip/UI/FileManager/LinkDialogRes.h | 42 +- CPP/7zip/UI/FileManager/ListViewDialog.cpp | 642 +- CPP/7zip/UI/FileManager/ListViewDialog.h | 92 +- CPP/7zip/UI/FileManager/ListViewDialog.rc | 28 +- CPP/7zip/UI/FileManager/ListViewDialogRes.h | 4 +- CPP/7zip/UI/FileManager/MenuPage.cpp | 716 +- CPP/7zip/UI/FileManager/MenuPage.h | 104 +- CPP/7zip/UI/FileManager/MenuPage.rc | 48 +- CPP/7zip/UI/FileManager/MenuPage2.rc | 34 +- CPP/7zip/UI/FileManager/MenuPageRes.h | 22 +- CPP/7zip/UI/FileManager/MessagesDialog.cpp | 152 +- CPP/7zip/UI/FileManager/MessagesDialog.h | 50 +- CPP/7zip/UI/FileManager/MessagesDialog.rc | 28 +- CPP/7zip/UI/FileManager/MessagesDialogRes.h | 6 +- CPP/7zip/UI/FileManager/MyCom2.h | 78 +- CPP/7zip/UI/FileManager/MyLoadMenu.cpp | 1514 +- CPP/7zip/UI/FileManager/MyLoadMenu.h | 72 +- CPP/7zip/UI/FileManager/MyWindowsNew.h | 152 +- CPP/7zip/UI/FileManager/NetFolder.cpp | 562 +- CPP/7zip/UI/FileManager/NetFolder.h | 80 +- CPP/7zip/UI/FileManager/OpenCallback.cpp | 258 +- CPP/7zip/UI/FileManager/OpenCallback.h | 182 +- CPP/7zip/UI/FileManager/OptionsDialog.cpp | 172 +- CPP/7zip/UI/FileManager/OverwriteDialog.cpp | 244 +- CPP/7zip/UI/FileManager/OverwriteDialog.h | 138 +- CPP/7zip/UI/FileManager/OverwriteDialog.rc | 182 +- CPP/7zip/UI/FileManager/OverwriteDialogRes.h | 34 +- CPP/7zip/UI/FileManager/Panel.cpp | 2194 +-- CPP/7zip/UI/FileManager/Panel.h | 1804 +-- CPP/7zip/UI/FileManager/PanelCopy.cpp | 786 +- CPP/7zip/UI/FileManager/PanelCrc.cpp | 842 +- CPP/7zip/UI/FileManager/PanelDrag.cpp | 1912 +-- CPP/7zip/UI/FileManager/PanelFolderChange.cpp | 1752 +-- CPP/7zip/UI/FileManager/PanelItemOpen.cpp | 3780 ++--- CPP/7zip/UI/FileManager/PanelItems.cpp | 2538 ++-- CPP/7zip/UI/FileManager/PanelKey.cpp | 694 +- CPP/7zip/UI/FileManager/PanelListNotify.cpp | 1530 +- CPP/7zip/UI/FileManager/PanelMenu.cpp | 1936 +-- CPP/7zip/UI/FileManager/PanelOperations.cpp | 1052 +- CPP/7zip/UI/FileManager/PanelSelect.cpp | 622 +- CPP/7zip/UI/FileManager/PanelSort.cpp | 538 +- CPP/7zip/UI/FileManager/PanelSplitFile.cpp | 1124 +- CPP/7zip/UI/FileManager/PasswordDialog.cpp | 116 +- CPP/7zip/UI/FileManager/PasswordDialog.h | 56 +- CPP/7zip/UI/FileManager/PasswordDialog.rc | 28 +- CPP/7zip/UI/FileManager/PasswordDialogRes.h | 10 +- CPP/7zip/UI/FileManager/PluginInterface.h | 62 +- CPP/7zip/UI/FileManager/PluginLoader.h | 56 +- CPP/7zip/UI/FileManager/ProgramLocation.cpp | 6 +- CPP/7zip/UI/FileManager/ProgramLocation.h | 12 +- CPP/7zip/UI/FileManager/ProgressDialog.cpp | 392 +- CPP/7zip/UI/FileManager/ProgressDialog.h | 340 +- CPP/7zip/UI/FileManager/ProgressDialog.rc | 24 +- CPP/7zip/UI/FileManager/ProgressDialog2.cpp | 2674 ++-- CPP/7zip/UI/FileManager/ProgressDialog2.h | 702 +- CPP/7zip/UI/FileManager/ProgressDialog2.rc | 80 +- CPP/7zip/UI/FileManager/ProgressDialog2Res.h | 96 +- CPP/7zip/UI/FileManager/ProgressDialog2a.rc | 160 +- CPP/7zip/UI/FileManager/ProgressDialogRes.h | 6 +- CPP/7zip/UI/FileManager/PropertyName.cpp | 46 +- CPP/7zip/UI/FileManager/PropertyName.h | 20 +- CPP/7zip/UI/FileManager/PropertyName.rc | 200 +- CPP/7zip/UI/FileManager/PropertyNameRes.h | 190 +- .../UI/FileManager/RegistryAssociations.cpp | 334 +- .../UI/FileManager/RegistryAssociations.h | 62 +- CPP/7zip/UI/FileManager/RegistryPlugins.cpp | 278 +- CPP/7zip/UI/FileManager/RegistryPlugins.h | 64 +- CPP/7zip/UI/FileManager/RegistryUtils.cpp | 446 +- CPP/7zip/UI/FileManager/RegistryUtils.h | 114 +- CPP/7zip/UI/FileManager/RootFolder.cpp | 630 +- CPP/7zip/UI/FileManager/RootFolder.h | 54 +- CPP/7zip/UI/FileManager/SettingsPage.cpp | 316 +- CPP/7zip/UI/FileManager/SettingsPage.h | 44 +- CPP/7zip/UI/FileManager/SettingsPage.rc | 44 +- CPP/7zip/UI/FileManager/SettingsPage2.rc | 28 +- CPP/7zip/UI/FileManager/SettingsPageRes.h | 30 +- CPP/7zip/UI/FileManager/SplitDialog.cpp | 232 +- CPP/7zip/UI/FileManager/SplitDialog.h | 56 +- CPP/7zip/UI/FileManager/SplitDialog.rc | 32 +- CPP/7zip/UI/FileManager/SplitDialogRes.h | 16 +- CPP/7zip/UI/FileManager/SplitUtils.cpp | 192 +- CPP/7zip/UI/FileManager/SplitUtils.h | 30 +- CPP/7zip/UI/FileManager/StdAfx.cpp | 6 +- CPP/7zip/UI/FileManager/StdAfx.h | 42 +- CPP/7zip/UI/FileManager/StringUtils.cpp | 130 +- CPP/7zip/UI/FileManager/StringUtils.h | 26 +- CPP/7zip/UI/FileManager/SysIconUtils.cpp | 510 +- CPP/7zip/UI/FileManager/SysIconUtils.h | 124 +- CPP/7zip/UI/FileManager/SystemPage.cpp | 922 +- CPP/7zip/UI/FileManager/SystemPage.h | 252 +- CPP/7zip/UI/FileManager/SystemPage.rc | 86 +- CPP/7zip/UI/FileManager/SystemPageRes.h | 18 +- CPP/7zip/UI/FileManager/TextPairs.cpp | 380 +- CPP/7zip/UI/FileManager/TextPairs.h | 64 +- CPP/7zip/UI/FileManager/UpdateCallback100.cpp | 248 +- CPP/7zip/UI/FileManager/UpdateCallback100.h | 104 +- CPP/7zip/UI/FileManager/ViewSettings.cpp | 660 +- CPP/7zip/UI/FileManager/ViewSettings.h | 230 +- CPP/7zip/UI/FileManager/makefile | 204 +- CPP/7zip/UI/FileManager/resource.h | 370 +- CPP/7zip/UI/FileManager/resource.rc | 552 +- CPP/7zip/UI/FileManager/resourceGui.h | 30 +- CPP/7zip/UI/FileManager/resourceGui.rc | 38 +- CPP/7zip/UI/GUI/7zG.exe.manifest | 40 +- CPP/7zip/UI/GUI/BenchmarkDialog.cpp | 1878 +-- CPP/7zip/UI/GUI/BenchmarkDialog.h | 384 +- CPP/7zip/UI/GUI/BenchmarkDialog.rc | 546 +- CPP/7zip/UI/GUI/BenchmarkDialogRes.h | 142 +- CPP/7zip/UI/GUI/CompressDialog.cpp | 4236 +++--- CPP/7zip/UI/GUI/CompressDialog.h | 436 +- CPP/7zip/UI/GUI/CompressDialog.rc | 450 +- CPP/7zip/UI/GUI/CompressDialogRes.h | 174 +- CPP/7zip/UI/GUI/Extract.rc | 118 +- CPP/7zip/UI/GUI/ExtractDialog.cpp | 836 +- CPP/7zip/UI/GUI/ExtractDialog.h | 226 +- CPP/7zip/UI/GUI/ExtractDialog.rc | 196 +- CPP/7zip/UI/GUI/ExtractDialogRes.h | 48 +- CPP/7zip/UI/GUI/ExtractGUI.cpp | 560 +- CPP/7zip/UI/GUI/ExtractGUI.h | 76 +- CPP/7zip/UI/GUI/ExtractRes.h | 102 +- CPP/7zip/UI/GUI/GUI.cpp | 864 +- CPP/7zip/UI/GUI/GUI.dsp | 2374 ++-- CPP/7zip/UI/GUI/GUI.dsw | 58 +- CPP/7zip/UI/GUI/HashGUI.cpp | 716 +- CPP/7zip/UI/GUI/HashGUI.h | 54 +- CPP/7zip/UI/GUI/StdAfx.cpp | 6 +- CPP/7zip/UI/GUI/StdAfx.h | 42 +- CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp | 560 +- CPP/7zip/UI/GUI/UpdateCallbackGUI.h | 68 +- CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp | 118 +- CPP/7zip/UI/GUI/UpdateCallbackGUI2.h | 70 +- CPP/7zip/UI/GUI/UpdateGUI.cpp | 970 +- CPP/7zip/UI/GUI/UpdateGUI.h | 66 +- CPP/7zip/UI/GUI/makefile | 288 +- CPP/7zip/UI/GUI/resource.rc | 50 +- CPP/7zip/UI/GUI/resource2.h | 4 +- CPP/7zip/UI/GUI/resource2.rc | 20 +- CPP/7zip/UI/GUI/resource3.h | 20 +- CPP/7zip/UI/GUI/resource3.rc | 30 +- CPP/7zip/UI/makefile | 24 +- CPP/7zip/makefile | 20 +- CPP/Build.mak | 158 +- CPP/Common/AutoPtr.h | 70 +- CPP/Common/CRC.cpp | 14 +- CPP/Common/C_FileIO.cpp | 184 +- CPP/Common/C_FileIO.h | 106 +- CPP/Common/ComTry.h | 42 +- CPP/Common/CommandLineParser.cpp | 394 +- CPP/Common/CommandLineParser.h | 126 +- CPP/Common/Common.h | 86 +- CPP/Common/CrcReg.cpp | 196 +- CPP/Common/Defs.h | 30 +- CPP/Common/DynLimBuf.cpp | 186 +- CPP/Common/DynLimBuf.h | 82 +- CPP/Common/DynamicBuffer.h | 128 +- CPP/Common/HashesReg.cpp | 474 +- CPP/Common/IntToString.cpp | 386 +- CPP/Common/IntToString.h | 56 +- CPP/Common/Lang.cpp | 326 +- CPP/Common/Lang.h | 46 +- CPP/Common/ListFileUtils.cpp | 264 +- CPP/Common/ListFileUtils.h | 36 +- CPP/Common/Md2Reg.cpp | 86 +- CPP/Common/Md4Reg.cpp | 86 +- CPP/Common/Md5Reg.cpp | 86 +- CPP/Common/MyBuffer.h | 518 +- CPP/Common/MyBuffer2.h | 200 +- CPP/Common/MyCom.h | 554 +- CPP/Common/MyException.h | 28 +- CPP/Common/MyGuidDef.h | 108 +- CPP/Common/MyInitGuid.h | 90 +- CPP/Common/MyLinux.h | 84 +- CPP/Common/MyMap.cpp | 280 +- CPP/Common/MyMap.h | 56 +- CPP/Common/MyString.cpp | 3318 ++--- CPP/Common/MyString.h | 1736 +-- CPP/Common/MyTypes.h | 70 +- CPP/Common/MyUnknown.h | 34 +- CPP/Common/MyVector.cpp | 6 +- CPP/Common/MyVector.h | 1268 +- CPP/Common/MyWindows.cpp | 290 +- CPP/Common/MyWindows.h | 462 +- CPP/Common/MyXml.cpp | 520 +- CPP/Common/MyXml.h | 86 +- CPP/Common/NewHandler.cpp | 326 +- CPP/Common/NewHandler.h | 176 +- CPP/Common/Random.cpp | 56 +- CPP/Common/Random.h | 28 +- CPP/Common/Sha1Reg.cpp | 80 +- CPP/Common/Sha256Reg.cpp | 80 +- CPP/Common/Sha384Reg.cpp | 86 +- CPP/Common/Sha512Reg.cpp | 86 +- CPP/Common/StdAfx.h | 16 +- CPP/Common/StdInStream.cpp | 178 +- CPP/Common/StdInStream.h | 76 +- CPP/Common/StdOutStream.cpp | 326 +- CPP/Common/StdOutStream.h | 142 +- CPP/Common/StringConvert.cpp | 638 +- CPP/Common/StringConvert.h | 176 +- CPP/Common/StringToInt.cpp | 288 +- CPP/Common/StringToInt.h | 42 +- CPP/Common/TextConfig.cpp | 248 +- CPP/Common/TextConfig.h | 38 +- CPP/Common/UTFConvert.cpp | 576 +- CPP/Common/UTFConvert.h | 24 +- CPP/Common/Wildcard.cpp | 1352 +- CPP/Common/Wildcard.h | 298 +- CPP/Common/XXH32Reg.cpp | 90 +- CPP/Common/XXH64Reg.cpp | 88 +- CPP/Common/XzCrc64Init.cpp | 14 +- CPP/Common/XzCrc64Reg.cpp | 84 +- CPP/Windows/COM.cpp | 82 +- CPP/Windows/COM.h | 140 +- CPP/Windows/Clipboard.cpp | 260 +- CPP/Windows/Clipboard.h | 56 +- CPP/Windows/CommonDialog.cpp | 370 +- CPP/Windows/CommonDialog.h | 46 +- CPP/Windows/Console.cpp | 20 +- CPP/Windows/Console.h | 104 +- CPP/Windows/Control/ComboBox.cpp | 132 +- CPP/Windows/Control/ComboBox.h | 130 +- CPP/Windows/Control/CommandBar.h | 104 +- CPP/Windows/Control/Dialog.cpp | 502 +- CPP/Windows/Control/Dialog.h | 340 +- CPP/Windows/Control/Edit.h | 38 +- CPP/Windows/Control/ImageList.cpp | 20 +- CPP/Windows/Control/ImageList.h | 174 +- CPP/Windows/Control/ListView.cpp | 310 +- CPP/Windows/Control/ListView.h | 292 +- CPP/Windows/Control/ProgressBar.h | 70 +- CPP/Windows/Control/PropertyPage.cpp | 286 +- CPP/Windows/Control/PropertyPage.h | 100 +- CPP/Windows/Control/ReBar.h | 68 +- CPP/Windows/Control/Static.h | 56 +- CPP/Windows/Control/StatusBar.h | 84 +- CPP/Windows/Control/StdAfx.h | 16 +- CPP/Windows/Control/ToolBar.h | 86 +- CPP/Windows/Control/Trackbar.h | 54 +- CPP/Windows/Control/Window2.cpp | 400 +- CPP/Windows/Control/Window2.h | 102 +- CPP/Windows/DLL.cpp | 218 +- CPP/Windows/DLL.h | 116 +- CPP/Windows/Defs.h | 34 +- CPP/Windows/ErrorMsg.cpp | 132 +- CPP/Windows/ErrorMsg.h | 30 +- CPP/Windows/FileDir.cpp | 1428 +- CPP/Windows/FileDir.h | 234 +- CPP/Windows/FileFind.cpp | 1498 +- CPP/Windows/FileFind.h | 322 +- CPP/Windows/FileIO.cpp | 864 +- CPP/Windows/FileIO.h | 424 +- CPP/Windows/FileLink.cpp | 880 +- CPP/Windows/FileMapping.cpp | 24 +- CPP/Windows/FileMapping.h | 132 +- CPP/Windows/FileName.cpp | 1678 +-- CPP/Windows/FileName.h | 230 +- CPP/Windows/FileSystem.cpp | 262 +- CPP/Windows/FileSystem.h | 54 +- CPP/Windows/Handle.h | 74 +- CPP/Windows/MemoryGlobal.cpp | 72 +- CPP/Windows/MemoryGlobal.h | 110 +- CPP/Windows/MemoryLock.cpp | 224 +- CPP/Windows/MemoryLock.h | 80 +- CPP/Windows/Menu.cpp | 424 +- CPP/Windows/Menu.h | 316 +- CPP/Windows/NationalTime.cpp | 74 +- CPP/Windows/NationalTime.h | 40 +- CPP/Windows/Net.cpp | 752 +- CPP/Windows/Net.h | 172 +- CPP/Windows/NtCheck.h | 92 +- CPP/Windows/ProcessMessages.cpp | 44 +- CPP/Windows/ProcessMessages.h | 24 +- CPP/Windows/ProcessUtils.cpp | 172 +- CPP/Windows/ProcessUtils.h | 200 +- CPP/Windows/PropVariant.cpp | 694 +- CPP/Windows/PropVariant.h | 228 +- CPP/Windows/PropVariantConv.cpp | 276 +- CPP/Windows/PropVariantConv.h | 74 +- CPP/Windows/PropVariantUtils.cpp | 322 +- CPP/Windows/PropVariantUtils.h | 68 +- CPP/Windows/Registry.cpp | 780 +- CPP/Windows/Registry.h | 168 +- CPP/Windows/ResourceString.cpp | 206 +- CPP/Windows/ResourceString.h | 32 +- CPP/Windows/SecurityUtils.cpp | 362 +- CPP/Windows/SecurityUtils.h | 334 +- CPP/Windows/Shell.cpp | 716 +- CPP/Windows/Shell.h | 188 +- CPP/Windows/StdAfx.h | 16 +- CPP/Windows/Synchronization.cpp | 20 +- CPP/Windows/Synchronization.h | 328 +- CPP/Windows/System.cpp | 284 +- CPP/Windows/System.h | 80 +- CPP/Windows/Thread.h | 76 +- CPP/Windows/TimeUtils.cpp | 426 +- CPP/Windows/TimeUtils.h | 64 +- CPP/Windows/Window.cpp | 358 +- CPP/Windows/Window.h | 568 +- CPP/appveyor.cmd | 88 +- CPP/build-it.cmd | 206 +- DOC/7zC.txt | 374 +- DOC/7zFormat.txt | 938 +- DOC/7zip.hhp | 164 +- DOC/7zip.inf | 110 +- DOC/7zip.nsi | 1118 +- DOC/7zip.wxs | 798 +- DOC/License.txt | 180 +- DOC/Methods.txt | 346 +- DOC/copying.txt | 1004 +- DOC/lzma.txt | 656 +- DOC/readme.txt | 360 +- DOC/src-history.txt | 1190 +- 1156 files changed, 292305 insertions(+), 292305 deletions(-) diff --git a/Asm/arm/7zCrcOpt.asm b/Asm/arm/7zCrcOpt.asm index f008d658c..6001d8e36 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/x86/7zAsm.asm b/Asm/x86/7zAsm.asm index 8c30d7b7e..067db822f 100644 --- a/Asm/x86/7zAsm.asm +++ b/Asm/x86/7zAsm.asm @@ -1,147 +1,147 @@ -; 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 +; 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 diff --git a/Asm/x86/7zCrcOpt.asm b/Asm/x86/7zCrcOpt.asm index 2de51719a..724b9b2c4 100644 --- a/Asm/x86/7zCrcOpt.asm +++ b/Asm/x86/7zCrcOpt.asm @@ -1,147 +1,147 @@ -; 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 +; 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 diff --git a/Asm/x86/AesOpt.asm b/Asm/x86/AesOpt.asm index c32e48f88..214667129 100644 --- a/Asm/x86/AesOpt.asm +++ b/Asm/x86/AesOpt.asm @@ -1,237 +1,237 @@ -; 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 -- 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 diff --git a/Asm/x86/LzmaDecOpt.asm b/Asm/x86/LzmaDecOpt.asm index 0a89eb735..8ebbc5f2a 100644 --- a/Asm/x86/LzmaDecOpt.asm +++ b/Asm/x86/LzmaDecOpt.asm @@ -1,1258 +1,1258 @@ -; 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 -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 -endif - -if NUM_BASE_PROBS ne 1984 - .err -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 +; 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 +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 +endif + +if NUM_BASE_PROBS ne 1984 + .err +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 diff --git a/Asm/x86/XzCrc64Opt.asm b/Asm/x86/XzCrc64Opt.asm index 3e6d49026..734ca5c45 100644 --- a/Asm/x86/XzCrc64Opt.asm +++ b/Asm/x86/XzCrc64Opt.asm @@ -1,205 +1,205 @@ -; 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 +; 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 diff --git a/C/7z.h b/C/7z.h index 82813c298..6c7886e38 100644 --- a/C/7z.h +++ b/C/7z.h @@ -1,202 +1,202 @@ -/* 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 +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 diff --git a/C/7zAlloc.c b/C/7zAlloc.c index ea32809c6..c924a529f 100644 --- a/C/7zAlloc.c +++ b/C/7zAlloc.c @@ -1,80 +1,80 @@ -/* 7zAlloc.c -- Allocation functions -2017-04-03 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -#include "7zAlloc.h" - -/* #define _SZ_ALLOC_DEBUG */ -/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ - -#ifdef _SZ_ALLOC_DEBUG - -#ifdef _WIN32 -#include -#endif - -#include -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 +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zAlloc.h" + +/* #define _SZ_ALLOC_DEBUG */ +/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ + +#ifdef _SZ_ALLOC_DEBUG + +#ifdef _WIN32 +#include +#endif + +#include +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); +} diff --git a/C/7zAlloc.h b/C/7zAlloc.h index c0f89d73c..44778f9b2 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 +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 diff --git a/C/7zArcIn.c b/C/7zArcIn.c index 68cc12ff4..f74d0fad5 100644 --- a/C/7zArcIn.c +++ b/C/7zArcIn.c @@ -1,1771 +1,1771 @@ -/* 7zArcIn.c -- 7z Input functions -2018-12-31 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -#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 +2018-12-31 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#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; + } +} +*/ diff --git a/C/7zBuf.c b/C/7zBuf.c index 438bba68b..8865c32a8 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 5942d6e62..81d1b5b64 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 +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 diff --git a/C/7zBuf2.c b/C/7zBuf2.c index 49b4343b6..208347416 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 - -#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 + +#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 40ab75952..b4d84f023 100644 --- a/C/7zCrc.c +++ b/C/7zCrc.c @@ -1,128 +1,128 @@ -/* 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 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 +} diff --git a/C/7zCrc.h b/C/7zCrc.h index 3b0459402..8fd579587 100644 --- a/C/7zCrc.h +++ b/C/7zCrc.h @@ -1,25 +1,25 @@ -/* 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 +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 diff --git a/C/7zCrcOpt.c b/C/7zCrcOpt.c index 2ee0de845..73beba298 100644 --- a/C/7zCrcOpt.c +++ b/C/7zCrcOpt.c @@ -1,115 +1,115 @@ -/* 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 +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 diff --git a/C/7zDec.c b/C/7zDec.c index 2a7b09030..7c4635211 100644 --- a/C/7zDec.c +++ b/C/7zDec.c @@ -1,591 +1,591 @@ -/* 7zDec.c -- Decoding from 7z folder -2019-02-02 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -/* #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 +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #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; + } +} diff --git a/C/7zFile.c b/C/7zFile.c index e486901e3..8992fb1c5 100644 --- a/C/7zFile.c +++ b/C/7zFile.c @@ -1,286 +1,286 @@ -/* 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 -#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 +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zFile.h" + +#ifndef USE_WINDOWS_FILE + +#ifndef UNDER_CE +#include +#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; +} diff --git a/C/7zFile.h b/C/7zFile.h index 7e263bea1..0e7925382 100644 --- a/C/7zFile.h +++ b/C/7zFile.h @@ -1,83 +1,83 @@ -/* 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 -#else -#include -#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 +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 +#else +#include +#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 diff --git a/C/7zStream.c b/C/7zStream.c index 579741fad..6b5aa1621 100644 --- a/C/7zStream.c +++ b/C/7zStream.c @@ -1,176 +1,176 @@ -/* 7zStream.c -- 7z Stream functions -2017-04-03 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -#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 +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#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; +} diff --git a/C/7zTypes.h b/C/7zTypes.h index 593f5aa25..65b3af63c 100644 --- a/C/7zTypes.h +++ b/C/7zTypes.h @@ -1,375 +1,375 @@ -/* 7zTypes.h -- Basic types -2018-08-04 : Igor Pavlov : Public domain */ - -#ifndef __7Z_TYPES_H -#define __7Z_TYPES_H - -#ifdef _WIN32 -/* #include */ -#endif - -#include - -#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 +2018-08-04 : Igor Pavlov : Public domain */ + +#ifndef __7Z_TYPES_H +#define __7Z_TYPES_H + +#ifdef _WIN32 +/* #include */ +#endif + +#include + +#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 diff --git a/C/7zVersion.h b/C/7zVersion.h index b028e0685..5cdea4934 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 ZS v1.4.5 R1" -#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 "2020-05-27" -#undef MY_COPYRIGHT -#undef MY_VERSION_COPYRIGHT_DATE -#define MY_AUTHOR_NAME "Igor Pavlov, Tino Reichardt" -#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" -#define MY_COPYRIGHT_CR "Copyright (c) 1999-2019 Igor Pavlov, 2016-2020 Tino Reichardt" - -#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 19 +#define MY_VER_MINOR 00 +#define MY_VER_BUILD 0 +#define MY_VERSION_NUMBERS "19.00 ZS v1.4.5 R1" +#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 "2020-05-27" +#undef MY_COPYRIGHT +#undef MY_VERSION_COPYRIGHT_DATE +#define MY_AUTHOR_NAME "Igor Pavlov, Tino Reichardt" +#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" +#define MY_COPYRIGHT_CR "Copyright (c) 1999-2019 Igor Pavlov, 2016-2020 Tino Reichardt" + +#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 5c1184797..63a18f571 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 - -#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, Tino Reichardt" \ - VALUE "FileDescription", descr \ - VALUE "FileVersion", MY_VERSION \ - VALUE "InternalName", intName \ - VALUE "LegalCopyright", MY_COPYRIGHT \ - VALUE "OriginalFilename", origName \ - VALUE "ProductName", "7-Zip ZS" \ - 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 + +#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, Tino Reichardt" \ + VALUE "FileDescription", descr \ + VALUE "FileVersion", MY_VERSION \ + VALUE "InternalName", intName \ + VALUE "LegalCopyright", MY_COPYRIGHT \ + VALUE "OriginalFilename", origName \ + VALUE "ProductName", "7-Zip ZS" \ + 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/7zVersionTr.h b/C/7zVersionTr.h index da485f89a..c6143971b 100644 --- a/C/7zVersionTr.h +++ b/C/7zVersionTr.h @@ -1,14 +1,14 @@ - -#include "7zVersion.h" - -#undef MY_AUTHOR_NAME -#define MY_AUTHOR_NAME "Tino Reichardt" - -#undef MY_COPYRIGHT -#define MY_COPYRIGHT "Copyright (c) 2016 - 2020 Tino Reichardt" - -#undef MY_COPYRIGHT_DATE -#define MY_COPYRIGHT_DATE MY_COPYRIGHT " : " MY_DATE - -#undef MY_VERSION_COPYRIGHT_DATE -#define MY_VERSION_COPYRIGHT_DATE MY_VERSION_CPU " : " MY_COPYRIGHT " : " MY_DATE + +#include "7zVersion.h" + +#undef MY_AUTHOR_NAME +#define MY_AUTHOR_NAME "Tino Reichardt" + +#undef MY_COPYRIGHT +#define MY_COPYRIGHT "Copyright (c) 2016 - 2020 Tino Reichardt" + +#undef MY_COPYRIGHT_DATE +#define MY_COPYRIGHT_DATE MY_COPYRIGHT " : " MY_DATE + +#undef MY_VERSION_COPYRIGHT_DATE +#define MY_VERSION_COPYRIGHT_DATE MY_VERSION_CPU " : " MY_COPYRIGHT " : " MY_DATE diff --git a/C/Aes.c b/C/Aes.c index 8f7d50ea2..1cdd0e787 100644 --- a/C/Aes.c +++ b/C/Aes.c @@ -1,306 +1,306 @@ -/* 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 +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 + } + } +} diff --git a/C/Aes.h b/C/Aes.h index 381e979d1..64979b5bc 100644 --- a/C/Aes.h +++ b/C/Aes.h @@ -1,38 +1,38 @@ -/* 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 +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 diff --git a/C/AesOpt.c b/C/AesOpt.c index 0e7f49a1b..9571c467f 100644 --- a/C/AesOpt.c +++ b/C/AesOpt.c @@ -1,184 +1,184 @@ -/* 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 - -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 -- 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 + +void MY_FAST_CALL AesCbc_Encode_Intel(__m128i *p, __m128i *data, size_t numBlocks) +{ + __m128i m = *p; + for (; numBlocks != 0; numBlocks--, data++) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1; + const __m128i *w = p + 3; + m = _mm_xor_si128(m, *data); + m = _mm_xor_si128(m, p[2]); + do + { + m = _mm_aesenc_si128(m, w[0]); + m = _mm_aesenc_si128(m, w[1]); + w += 2; + } + while (--numRounds2 != 0); + m = _mm_aesenc_si128(m, w[0]); + m = _mm_aesenclast_si128(m, w[1]); + *data = m; + } + *p = m; +} + +#define NUM_WAYS 3 + +#define AES_OP_W(op, n) { \ + const __m128i t = w[n]; \ + m0 = op(m0, t); \ + m1 = op(m1, t); \ + m2 = op(m2, t); \ + } + +#define AES_DEC(n) AES_OP_W(_mm_aesdec_si128, n) +#define AES_DEC_LAST(n) AES_OP_W(_mm_aesdeclast_si128, n) +#define AES_ENC(n) AES_OP_W(_mm_aesenc_si128, n) +#define AES_ENC_LAST(n) AES_OP_W(_mm_aesenclast_si128, n) + +void MY_FAST_CALL AesCbc_Decode_Intel(__m128i *p, __m128i *data, size_t numBlocks) +{ + __m128i iv = *p; + for (; numBlocks >= NUM_WAYS; numBlocks -= NUM_WAYS, data += NUM_WAYS) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1); + const __m128i *w = p + numRounds2 * 2; + __m128i m0, m1, m2; + { + const __m128i t = w[2]; + m0 = _mm_xor_si128(t, data[0]); + m1 = _mm_xor_si128(t, data[1]); + m2 = _mm_xor_si128(t, data[2]); + } + numRounds2--; + do + { + AES_DEC(1) + AES_DEC(0) + w -= 2; + } + while (--numRounds2 != 0); + AES_DEC(1) + AES_DEC_LAST(0) + + { + __m128i t; + t = _mm_xor_si128(m0, iv); iv = data[0]; data[0] = t; + t = _mm_xor_si128(m1, iv); iv = data[1]; data[1] = t; + t = _mm_xor_si128(m2, iv); iv = data[2]; data[2] = t; + } + } + for (; numBlocks != 0; numBlocks--, data++) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1); + const __m128i *w = p + numRounds2 * 2; + __m128i m = _mm_xor_si128(w[2], *data); + numRounds2--; + do + { + m = _mm_aesdec_si128(m, w[1]); + m = _mm_aesdec_si128(m, w[0]); + w -= 2; + } + while (--numRounds2 != 0); + m = _mm_aesdec_si128(m, w[1]); + m = _mm_aesdeclast_si128(m, w[0]); + + m = _mm_xor_si128(m, iv); + iv = *data; + *data = m; + } + *p = iv; +} + +void MY_FAST_CALL AesCtr_Code_Intel(__m128i *p, __m128i *data, size_t numBlocks) +{ + __m128i ctr = *p; + __m128i one; + one.m128i_u64[0] = 1; + one.m128i_u64[1] = 0; + for (; numBlocks >= NUM_WAYS; numBlocks -= NUM_WAYS, data += NUM_WAYS) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1; + const __m128i *w = p; + __m128i m0, m1, m2; + { + const __m128i t = w[2]; + ctr = _mm_add_epi64(ctr, one); m0 = _mm_xor_si128(ctr, t); + ctr = _mm_add_epi64(ctr, one); m1 = _mm_xor_si128(ctr, t); + ctr = _mm_add_epi64(ctr, one); m2 = _mm_xor_si128(ctr, t); + } + w += 3; + do + { + AES_ENC(0) + AES_ENC(1) + w += 2; + } + while (--numRounds2 != 0); + AES_ENC(0) + AES_ENC_LAST(1) + data[0] = _mm_xor_si128(data[0], m0); + data[1] = _mm_xor_si128(data[1], m1); + data[2] = _mm_xor_si128(data[2], m2); + } + for (; numBlocks != 0; numBlocks--, data++) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1; + const __m128i *w = p; + __m128i m; + ctr = _mm_add_epi64(ctr, one); + m = _mm_xor_si128(ctr, p[2]); + w += 3; + do + { + m = _mm_aesenc_si128(m, w[0]); + m = _mm_aesenc_si128(m, w[1]); + w += 2; + } + while (--numRounds2 != 0); + m = _mm_aesenc_si128(m, w[0]); + m = _mm_aesenclast_si128(m, w[1]); + *data = _mm_xor_si128(*data, m); + } + *p = ctr; +} + +#else + +void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks); +void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks); +void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks); + +void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *p, Byte *data, size_t numBlocks) +{ + AesCbc_Encode(p, data, numBlocks); +} + +void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *p, Byte *data, size_t numBlocks) +{ + AesCbc_Decode(p, data, numBlocks); +} + +void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *p, Byte *data, size_t numBlocks) +{ + AesCtr_Code(p, data, numBlocks); +} + +#endif diff --git a/C/Alloc.c b/C/Alloc.c index 30b499e5f..bcede4b85 100644 --- a/C/Alloc.c +++ b/C/Alloc.c @@ -1,455 +1,455 @@ -/* Alloc.c -- Memory allocation functions -2018-04-27 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -#ifdef _WIN32 -#include -#endif -#include - -#include "Alloc.h" - -/* #define _SZ_ALLOC_DEBUG */ - -/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ -#ifdef _SZ_ALLOC_DEBUG - -#include -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 : 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 +2018-04-27 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#ifdef _WIN32 +#include +#endif +#include + +#include "Alloc.h" + +/* #define _SZ_ALLOC_DEBUG */ + +/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ +#ifdef _SZ_ALLOC_DEBUG + +#include +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 : 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; +} diff --git a/C/Alloc.h b/C/Alloc.h index 3d796e5ee..648237646 100644 --- a/C/Alloc.h +++ b/C/Alloc.h @@ -1,51 +1,51 @@ -/* 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 +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 diff --git a/C/Bcj2.c b/C/Bcj2.c index da93985cf..9a0046a65 100644 --- a/C/Bcj2.c +++ b/C/Bcj2.c @@ -1,257 +1,257 @@ -/* 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) +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; +} diff --git a/C/Bcj2.h b/C/Bcj2.h index 68893d2d1..8824080ac 100644 --- a/C/Bcj2.h +++ b/C/Bcj2.h @@ -1,146 +1,146 @@ -/* 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 +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 diff --git a/C/Bcj2Enc.c b/C/Bcj2Enc.c index 7a02ecde2..bfbeb8e49 100644 --- a/C/Bcj2Enc.c +++ b/C/Bcj2Enc.c @@ -1,311 +1,311 @@ -/* 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 -#define PRF(x) x -#else -#define PRF(x) -#endif - -#include - -#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) +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +/* #define SHOW_STAT */ + +#ifdef SHOW_STAT +#include +#define PRF(x) x +#else +#define PRF(x) +#endif + +#include + +#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; + } +} diff --git a/C/Blake2.h b/C/Blake2.h index b4b3d8e02..14f3cb64e 100644 --- a/C/Blake2.h +++ b/C/Blake2.h @@ -1,48 +1,48 @@ -/* Blake2.h -- BLAKE2 Hash -2015-06-30 : Igor Pavlov : Public domain -2015 : Samuel Neves : Public domain */ - -#ifndef __BLAKE2_H -#define __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 +/* Blake2.h -- BLAKE2 Hash +2015-06-30 : Igor Pavlov : Public domain +2015 : Samuel Neves : Public domain */ + +#ifndef __BLAKE2_H +#define __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 index 54779cb8c..6527415e8 100644 --- a/C/Blake2s.c +++ b/C/Blake2s.c @@ -1,244 +1,244 @@ -/* Blake2s.c -- BLAKE2s and BLAKE2sp Hash -2015-06-30 : Igor Pavlov : Public domain -2015 : Samuel Neves : Public domain */ - -#include - -#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 } , -}; - - -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); -} +/* Blake2s.c -- BLAKE2s and BLAKE2sp Hash +2015-06-30 : Igor Pavlov : Public domain +2015 : Samuel Neves : Public domain */ + +#include + +#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 } , +}; + + +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); +} diff --git a/C/Bra.c b/C/Bra.c index cbdcb290d..aed17e330 100644 --- a/C/Bra.c +++ b/C/Bra.c @@ -1,230 +1,230 @@ -/* 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 -- 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); + } + } +} diff --git a/C/Bra.h b/C/Bra.h index aba8dce14..855e37a6b 100644 --- a/C/Bra.h +++ b/C/Bra.h @@ -1,64 +1,64 @@ -/* 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 +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 diff --git a/C/Bra86.c b/C/Bra86.c index a6463c63b..93ed4d762 100644 --- a/C/Bra86.c +++ b/C/Bra86.c @@ -1,82 +1,82 @@ -/* 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 -- 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++; + } + } +} diff --git a/C/BraIA64.c b/C/BraIA64.c index 2656907a0..d1dbc62c5 100644 --- a/C/BraIA64.c +++ b/C/BraIA64.c @@ -1,53 +1,53 @@ -/* 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 +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; +} diff --git a/C/BwtSort.c b/C/BwtSort.c index a87e4d172..cc2f4b29c 100644 --- a/C/BwtSort.c +++ b/C/BwtSort.c @@ -1,515 +1,515 @@ -/* BwtSort.c -- BWT block sorting -2018-07-04 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "BwtSort.h" -#include "Sort.h" - -/* #define BLOCK_SORT_USE_HEAP_SORT */ - -#define NO_INLINE MY_FAST_CALL - -/* Don't change it !!! */ -#define kNumHashBytes 2 -#define kNumHashValues (1 << (kNumHashBytes * 8)) - -/* kNumRefBitsMax must be < (kNumHashBytes * 8) = 16 */ -#define kNumRefBitsMax 12 - -#define BS_TEMP_SIZE kNumHashValues - -#ifdef BLOCK_SORT_EXTERNAL_FLAGS - -/* 32 Flags in UInt32 word */ -#define kNumFlagsBits 5 -#define kNumFlagsInWord (1 << kNumFlagsBits) -#define kFlagsMask (kNumFlagsInWord - 1) -#define kAllFlags 0xFFFFFFFF - -#else - -#define kNumBitsMax 20 -#define kIndexMask ((1 << kNumBitsMax) - 1) -#define kNumExtraBits (32 - kNumBitsMax) -#define kNumExtra0Bits (kNumExtraBits - 2) -#define kNumExtra0Mask ((1 << kNumExtra0Bits) - 1) - -#define SetFinishedGroupSize(p, size) \ - { *(p) |= ((((size) - 1) & kNumExtra0Mask) << kNumBitsMax); \ - if ((size) > (1 << kNumExtra0Bits)) { \ - *(p) |= 0x40000000; *((p) + 1) |= ((((size) - 1)>> kNumExtra0Bits) << kNumBitsMax); } } \ - -static void SetGroupSize(UInt32 *p, UInt32 size) -{ - if (--size == 0) - return; - *p |= 0x80000000 | ((size & kNumExtra0Mask) << kNumBitsMax); - if (size >= (1 << kNumExtra0Bits)) - { - *p |= 0x40000000; - p[1] |= ((size >> kNumExtra0Bits) << kNumBitsMax); - } -} - -#endif - -/* -SortGroup - is recursive Range-Sort function with HeapSort optimization for small blocks - "range" is not real range. It's only for optimization. -returns: 1 - if there are groups, 0 - no more groups -*/ - -UInt32 NO_INLINE SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 groupSize, int NumRefBits, UInt32 *Indices - #ifndef BLOCK_SORT_USE_HEAP_SORT - , UInt32 left, UInt32 range - #endif - ) -{ - UInt32 *ind2 = Indices + groupOffset; - UInt32 *Groups; - if (groupSize <= 1) - { - /* - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - SetFinishedGroupSize(ind2, 1); - #endif - */ - return 0; - } - Groups = Indices + BlockSize + BS_TEMP_SIZE; - if (groupSize <= ((UInt32)1 << NumRefBits) - #ifndef BLOCK_SORT_USE_HEAP_SORT - && groupSize <= range - #endif - ) - { - UInt32 *temp = Indices + BlockSize; - UInt32 j; - UInt32 mask, thereAreGroups, group, cg; - { - UInt32 gPrev; - UInt32 gRes = 0; - { - UInt32 sp = ind2[0] + NumSortedBytes; - if (sp >= BlockSize) sp -= BlockSize; - gPrev = Groups[sp]; - temp[0] = (gPrev << NumRefBits); - } - - for (j = 1; j < groupSize; j++) - { - UInt32 sp = ind2[j] + NumSortedBytes; - UInt32 g; - if (sp >= BlockSize) sp -= BlockSize; - g = Groups[sp]; - temp[j] = (g << NumRefBits) | j; - gRes |= (gPrev ^ g); - } - if (gRes == 0) - { - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - SetGroupSize(ind2, groupSize); - #endif - return 1; - } - } - - HeapSort(temp, groupSize); - mask = ((1 << NumRefBits) - 1); - thereAreGroups = 0; - - group = groupOffset; - cg = (temp[0] >> NumRefBits); - temp[0] = ind2[temp[0] & mask]; - - { - #ifdef BLOCK_SORT_EXTERNAL_FLAGS - UInt32 *Flags = Groups + BlockSize; - #else - UInt32 prevGroupStart = 0; - #endif - - for (j = 1; j < groupSize; j++) - { - UInt32 val = temp[j]; - UInt32 cgCur = (val >> NumRefBits); - - if (cgCur != cg) - { - cg = cgCur; - group = groupOffset + j; - - #ifdef BLOCK_SORT_EXTERNAL_FLAGS - { - UInt32 t = group - 1; - Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); - } - #else - SetGroupSize(temp + prevGroupStart, j - prevGroupStart); - prevGroupStart = j; - #endif - } - else - thereAreGroups = 1; - { - UInt32 ind = ind2[val & mask]; - temp[j] = ind; - Groups[ind] = group; - } - } - - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - SetGroupSize(temp + prevGroupStart, j - prevGroupStart); - #endif - } - - for (j = 0; j < groupSize; j++) - ind2[j] = temp[j]; - return thereAreGroups; - } - - /* Check that all strings are in one group (cannot sort) */ - { - UInt32 group, j; - UInt32 sp = ind2[0] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; - group = Groups[sp]; - for (j = 1; j < groupSize; j++) - { - sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; - if (Groups[sp] != group) - break; - } - if (j == groupSize) - { - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - SetGroupSize(ind2, groupSize); - #endif - return 1; - } - } - - #ifndef BLOCK_SORT_USE_HEAP_SORT - { - /* ---------- Range Sort ---------- */ - UInt32 i; - UInt32 mid; - for (;;) - { - UInt32 j; - if (range <= 1) - { - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - SetGroupSize(ind2, groupSize); - #endif - return 1; - } - mid = left + ((range + 1) >> 1); - j = groupSize; - i = 0; - do - { - UInt32 sp = ind2[i] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; - if (Groups[sp] >= mid) - { - for (j--; j > i; j--) - { - sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; - if (Groups[sp] < mid) - { - UInt32 temp = ind2[i]; ind2[i] = ind2[j]; ind2[j] = temp; - break; - } - } - if (i >= j) - break; - } - } - while (++i < j); - if (i == 0) - { - range = range - (mid - left); - left = mid; - } - else if (i == groupSize) - range = (mid - left); - else - break; - } - - #ifdef BLOCK_SORT_EXTERNAL_FLAGS - { - UInt32 t = (groupOffset + i - 1); - UInt32 *Flags = Groups + BlockSize; - Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); - } - #endif - - { - UInt32 j; - for (j = i; j < groupSize; j++) - Groups[ind2[j]] = groupOffset + i; - } - - { - UInt32 res = SortGroup(BlockSize, NumSortedBytes, groupOffset, i, NumRefBits, Indices, left, mid - left); - return res | SortGroup(BlockSize, NumSortedBytes, groupOffset + i, groupSize - i, NumRefBits, Indices, mid, range - (mid - left)); - } - - } - - #else - - /* ---------- Heap Sort ---------- */ - - { - UInt32 j; - for (j = 0; j < groupSize; j++) - { - UInt32 sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; - ind2[j] = sp; - } - - HeapSortRef(ind2, Groups, groupSize); - - /* Write Flags */ - { - UInt32 sp = ind2[0]; - UInt32 group = Groups[sp]; - - #ifdef BLOCK_SORT_EXTERNAL_FLAGS - UInt32 *Flags = Groups + BlockSize; - #else - UInt32 prevGroupStart = 0; - #endif - - for (j = 1; j < groupSize; j++) - { - sp = ind2[j]; - if (Groups[sp] != group) - { - group = Groups[sp]; - #ifdef BLOCK_SORT_EXTERNAL_FLAGS - { - UInt32 t = groupOffset + j - 1; - Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); - } - #else - SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart); - prevGroupStart = j; - #endif - } - } - - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart); - #endif - } - { - /* Write new Groups values and Check that there are groups */ - UInt32 thereAreGroups = 0; - for (j = 0; j < groupSize; j++) - { - UInt32 group = groupOffset + j; - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - UInt32 subGroupSize = ((ind2[j] & ~0xC0000000) >> kNumBitsMax); - if ((ind2[j] & 0x40000000) != 0) - subGroupSize += ((ind2[(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]; -} +/* BwtSort.c -- BWT block sorting +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "BwtSort.h" +#include "Sort.h" + +/* #define BLOCK_SORT_USE_HEAP_SORT */ + +#define NO_INLINE MY_FAST_CALL + +/* Don't change it !!! */ +#define kNumHashBytes 2 +#define kNumHashValues (1 << (kNumHashBytes * 8)) + +/* kNumRefBitsMax must be < (kNumHashBytes * 8) = 16 */ +#define kNumRefBitsMax 12 + +#define BS_TEMP_SIZE kNumHashValues + +#ifdef BLOCK_SORT_EXTERNAL_FLAGS + +/* 32 Flags in UInt32 word */ +#define kNumFlagsBits 5 +#define kNumFlagsInWord (1 << kNumFlagsBits) +#define kFlagsMask (kNumFlagsInWord - 1) +#define kAllFlags 0xFFFFFFFF + +#else + +#define kNumBitsMax 20 +#define kIndexMask ((1 << kNumBitsMax) - 1) +#define kNumExtraBits (32 - kNumBitsMax) +#define kNumExtra0Bits (kNumExtraBits - 2) +#define kNumExtra0Mask ((1 << kNumExtra0Bits) - 1) + +#define SetFinishedGroupSize(p, size) \ + { *(p) |= ((((size) - 1) & kNumExtra0Mask) << kNumBitsMax); \ + if ((size) > (1 << kNumExtra0Bits)) { \ + *(p) |= 0x40000000; *((p) + 1) |= ((((size) - 1)>> kNumExtra0Bits) << kNumBitsMax); } } \ + +static void SetGroupSize(UInt32 *p, UInt32 size) +{ + if (--size == 0) + return; + *p |= 0x80000000 | ((size & kNumExtra0Mask) << kNumBitsMax); + if (size >= (1 << kNumExtra0Bits)) + { + *p |= 0x40000000; + p[1] |= ((size >> kNumExtra0Bits) << kNumBitsMax); + } +} + +#endif + +/* +SortGroup - is recursive Range-Sort function with HeapSort optimization for small blocks + "range" is not real range. It's only for optimization. +returns: 1 - if there are groups, 0 - no more groups +*/ + +UInt32 NO_INLINE SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 groupSize, int NumRefBits, UInt32 *Indices + #ifndef BLOCK_SORT_USE_HEAP_SORT + , UInt32 left, UInt32 range + #endif + ) +{ + UInt32 *ind2 = Indices + groupOffset; + UInt32 *Groups; + if (groupSize <= 1) + { + /* + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + SetFinishedGroupSize(ind2, 1); + #endif + */ + return 0; + } + Groups = Indices + BlockSize + BS_TEMP_SIZE; + if (groupSize <= ((UInt32)1 << NumRefBits) + #ifndef BLOCK_SORT_USE_HEAP_SORT + && groupSize <= range + #endif + ) + { + UInt32 *temp = Indices + BlockSize; + UInt32 j; + UInt32 mask, thereAreGroups, group, cg; + { + UInt32 gPrev; + UInt32 gRes = 0; + { + UInt32 sp = ind2[0] + NumSortedBytes; + if (sp >= BlockSize) sp -= BlockSize; + gPrev = Groups[sp]; + temp[0] = (gPrev << NumRefBits); + } + + for (j = 1; j < groupSize; j++) + { + UInt32 sp = ind2[j] + NumSortedBytes; + UInt32 g; + if (sp >= BlockSize) sp -= BlockSize; + g = Groups[sp]; + temp[j] = (g << NumRefBits) | j; + gRes |= (gPrev ^ g); + } + if (gRes == 0) + { + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + SetGroupSize(ind2, groupSize); + #endif + return 1; + } + } + + HeapSort(temp, groupSize); + mask = ((1 << NumRefBits) - 1); + thereAreGroups = 0; + + group = groupOffset; + cg = (temp[0] >> NumRefBits); + temp[0] = ind2[temp[0] & mask]; + + { + #ifdef BLOCK_SORT_EXTERNAL_FLAGS + UInt32 *Flags = Groups + BlockSize; + #else + UInt32 prevGroupStart = 0; + #endif + + for (j = 1; j < groupSize; j++) + { + UInt32 val = temp[j]; + UInt32 cgCur = (val >> NumRefBits); + + if (cgCur != cg) + { + cg = cgCur; + group = groupOffset + j; + + #ifdef BLOCK_SORT_EXTERNAL_FLAGS + { + UInt32 t = group - 1; + Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); + } + #else + SetGroupSize(temp + prevGroupStart, j - prevGroupStart); + prevGroupStart = j; + #endif + } + else + thereAreGroups = 1; + { + UInt32 ind = ind2[val & mask]; + temp[j] = ind; + Groups[ind] = group; + } + } + + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + SetGroupSize(temp + prevGroupStart, j - prevGroupStart); + #endif + } + + for (j = 0; j < groupSize; j++) + ind2[j] = temp[j]; + return thereAreGroups; + } + + /* Check that all strings are in one group (cannot sort) */ + { + UInt32 group, j; + UInt32 sp = ind2[0] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; + group = Groups[sp]; + for (j = 1; j < groupSize; j++) + { + sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; + if (Groups[sp] != group) + break; + } + if (j == groupSize) + { + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + SetGroupSize(ind2, groupSize); + #endif + return 1; + } + } + + #ifndef BLOCK_SORT_USE_HEAP_SORT + { + /* ---------- Range Sort ---------- */ + UInt32 i; + UInt32 mid; + for (;;) + { + UInt32 j; + if (range <= 1) + { + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + SetGroupSize(ind2, groupSize); + #endif + return 1; + } + mid = left + ((range + 1) >> 1); + j = groupSize; + i = 0; + do + { + UInt32 sp = ind2[i] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; + if (Groups[sp] >= mid) + { + for (j--; j > i; j--) + { + sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; + if (Groups[sp] < mid) + { + UInt32 temp = ind2[i]; ind2[i] = ind2[j]; ind2[j] = temp; + break; + } + } + if (i >= j) + break; + } + } + while (++i < j); + if (i == 0) + { + range = range - (mid - left); + left = mid; + } + else if (i == groupSize) + range = (mid - left); + else + break; + } + + #ifdef BLOCK_SORT_EXTERNAL_FLAGS + { + UInt32 t = (groupOffset + i - 1); + UInt32 *Flags = Groups + BlockSize; + Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); + } + #endif + + { + UInt32 j; + for (j = i; j < groupSize; j++) + Groups[ind2[j]] = groupOffset + i; + } + + { + UInt32 res = SortGroup(BlockSize, NumSortedBytes, groupOffset, i, NumRefBits, Indices, left, mid - left); + return res | SortGroup(BlockSize, NumSortedBytes, groupOffset + i, groupSize - i, NumRefBits, Indices, mid, range - (mid - left)); + } + + } + + #else + + /* ---------- Heap Sort ---------- */ + + { + UInt32 j; + for (j = 0; j < groupSize; j++) + { + UInt32 sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; + ind2[j] = sp; + } + + HeapSortRef(ind2, Groups, groupSize); + + /* Write Flags */ + { + UInt32 sp = ind2[0]; + UInt32 group = Groups[sp]; + + #ifdef BLOCK_SORT_EXTERNAL_FLAGS + UInt32 *Flags = Groups + BlockSize; + #else + UInt32 prevGroupStart = 0; + #endif + + for (j = 1; j < groupSize; j++) + { + sp = ind2[j]; + if (Groups[sp] != group) + { + group = Groups[sp]; + #ifdef BLOCK_SORT_EXTERNAL_FLAGS + { + UInt32 t = groupOffset + j - 1; + Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); + } + #else + SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart); + prevGroupStart = j; + #endif + } + } + + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart); + #endif + } + { + /* Write new Groups values and Check that there are groups */ + UInt32 thereAreGroups = 0; + for (j = 0; j < groupSize; j++) + { + UInt32 group = groupOffset + j; + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + UInt32 subGroupSize = ((ind2[j] & ~0xC0000000) >> kNumBitsMax); + if ((ind2[j] & 0x40000000) != 0) + subGroupSize += ((ind2[(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 index 00084b81f..7e989a992 100644 --- a/C/BwtSort.h +++ b/C/BwtSort.h @@ -1,26 +1,26 @@ -/* BwtSort.h -- BWT block sorting -2013-01-18 : Igor Pavlov : Public domain */ - -#ifndef __BWT_SORT_H -#define __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 +/* BwtSort.h -- BWT block sorting +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __BWT_SORT_H +#define __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 c788648cd..0cc409d8a 100644 --- a/C/Compiler.h +++ b/C/Compiler.h @@ -1,33 +1,33 @@ -/* 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 +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 diff --git a/C/CpuArch.c b/C/CpuArch.c index ff1890e7f..02e482e08 100644 --- a/C/CpuArch.c +++ b/C/CpuArch.c @@ -1,218 +1,218 @@ -/* 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 -#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 -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 +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 +#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 +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 diff --git a/C/CpuArch.h b/C/CpuArch.h index 5f74c1c0c..bd4293880 100644 --- a/C/CpuArch.h +++ b/C/CpuArch.h @@ -1,336 +1,336 @@ -/* 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 - -#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 +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 + +#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 diff --git a/C/Delta.c b/C/Delta.c index 6cbbe4601..e3edd21ed 100644 --- a/C/Delta.c +++ b/C/Delta.c @@ -1,64 +1,64 @@ -/* 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 +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); +} diff --git a/C/Delta.h b/C/Delta.h index e59d5a252..2fa54ad67 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 +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 diff --git a/C/DllSecur.c b/C/DllSecur.c index 19a22a9f0..5ea108ab8 100644 --- a/C/DllSecur.c +++ b/C/DllSecur.c @@ -1,108 +1,108 @@ -/* DllSecur.c -- DLL loading security -2018-02-21 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#ifdef _WIN32 - -#include - -#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 +2018-02-21 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#ifdef _WIN32 + +#include + +#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 diff --git a/C/DllSecur.h b/C/DllSecur.h index 4c113568e..e2a049ad2 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 +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 diff --git a/C/HuffEnc.c b/C/HuffEnc.c index 5547daece..a54b3d87a 100644 --- a/C/HuffEnc.c +++ b/C/HuffEnc.c @@ -1,148 +1,148 @@ -/* HuffEnc.c -- functions for Huffman encoding -2017-04-03 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "HuffEnc.h" -#include "Sort.h" - -#define kMaxLen 16 -#define NUM_BITS 10 -#define MASK ((1 << NUM_BITS) - 1) - -#define NUM_COUNTERS 64 - -#define HUFFMAN_SPEED_OPT - -void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen) -{ - UInt32 num = 0; - /* if (maxLen > 10) maxLen = 10; */ - { - UInt32 i; - - #ifdef HUFFMAN_SPEED_OPT - - UInt32 counters[NUM_COUNTERS]; - for (i = 0; i < NUM_COUNTERS; i++) - counters[i] = 0; - for (i = 0; i < numSymbols; i++) - { - UInt32 freq = freqs[i]; - counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++; - } - - for (i = 1; i < NUM_COUNTERS; i++) - { - UInt32 temp = counters[i]; - counters[i] = num; - num += temp; - } - - for (i = 0; i < numSymbols; i++) - { - UInt32 freq = freqs[i]; - if (freq == 0) - lens[i] = 0; - else - p[counters[((freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1)]++] = i | (freq << NUM_BITS); - } - counters[0] = 0; - HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]); - - #else - - for (i = 0; i < numSymbols; i++) - { - UInt32 freq = freqs[i]; - if (freq == 0) - lens[i] = 0; - else - p[num++] = i | (freq << NUM_BITS); - } - HeapSort(p, num); - - #endif - } - - if (num < 2) - { - unsigned minCode = 0; - unsigned maxCode = 1; - if (num == 1) - { - maxCode = (unsigned)p[0] & MASK; - if (maxCode == 0) - maxCode++; - } - p[minCode] = 0; - p[maxCode] = 1; - lens[minCode] = lens[maxCode] = 1; - return; - } - - { - UInt32 b, e, i; - - i = b = e = 0; - do - { - UInt32 n, m, freq; - n = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++; - freq = (p[n] & ~MASK); - p[n] = (p[n] & MASK) | (e << NUM_BITS); - m = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++; - freq += (p[m] & ~MASK); - p[m] = (p[m] & MASK) | (e << NUM_BITS); - p[e] = (p[e] & MASK) | freq; - e++; - } - while (num - e > 1); - - { - UInt32 lenCounters[kMaxLen + 1]; - for (i = 0; i <= kMaxLen; i++) - lenCounters[i] = 0; - - p[--e] &= MASK; - lenCounters[1] = 2; - while (e > 0) - { - UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1; - p[e] = (p[e] & MASK) | (len << NUM_BITS); - if (len >= maxLen) - for (len = maxLen - 1; lenCounters[len] == 0; len--); - lenCounters[len]--; - lenCounters[(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]]++; - } - } - } - } -} +/* HuffEnc.c -- functions for Huffman encoding +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "HuffEnc.h" +#include "Sort.h" + +#define kMaxLen 16 +#define NUM_BITS 10 +#define MASK ((1 << NUM_BITS) - 1) + +#define NUM_COUNTERS 64 + +#define HUFFMAN_SPEED_OPT + +void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen) +{ + UInt32 num = 0; + /* if (maxLen > 10) maxLen = 10; */ + { + UInt32 i; + + #ifdef HUFFMAN_SPEED_OPT + + UInt32 counters[NUM_COUNTERS]; + for (i = 0; i < NUM_COUNTERS; i++) + counters[i] = 0; + for (i = 0; i < numSymbols; i++) + { + UInt32 freq = freqs[i]; + counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++; + } + + for (i = 1; i < NUM_COUNTERS; i++) + { + UInt32 temp = counters[i]; + counters[i] = num; + num += temp; + } + + for (i = 0; i < numSymbols; i++) + { + UInt32 freq = freqs[i]; + if (freq == 0) + lens[i] = 0; + else + p[counters[((freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1)]++] = i | (freq << NUM_BITS); + } + counters[0] = 0; + HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]); + + #else + + for (i = 0; i < numSymbols; i++) + { + UInt32 freq = freqs[i]; + if (freq == 0) + lens[i] = 0; + else + p[num++] = i | (freq << NUM_BITS); + } + HeapSort(p, num); + + #endif + } + + if (num < 2) + { + unsigned minCode = 0; + unsigned maxCode = 1; + if (num == 1) + { + maxCode = (unsigned)p[0] & MASK; + if (maxCode == 0) + maxCode++; + } + p[minCode] = 0; + p[maxCode] = 1; + lens[minCode] = lens[maxCode] = 1; + return; + } + + { + UInt32 b, e, i; + + i = b = e = 0; + do + { + UInt32 n, m, freq; + n = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++; + freq = (p[n] & ~MASK); + p[n] = (p[n] & MASK) | (e << NUM_BITS); + m = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++; + freq += (p[m] & ~MASK); + p[m] = (p[m] & MASK) | (e << NUM_BITS); + p[e] = (p[e] & MASK) | freq; + e++; + } + while (num - e > 1); + + { + UInt32 lenCounters[kMaxLen + 1]; + for (i = 0; i <= kMaxLen; i++) + lenCounters[i] = 0; + + p[--e] &= MASK; + lenCounters[1] = 2; + while (e > 0) + { + UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1; + p[e] = (p[e] & MASK) | (len << NUM_BITS); + if (len >= maxLen) + for (len = maxLen - 1; lenCounters[len] == 0; len--); + lenCounters[len]--; + lenCounters[(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]]++; + } + } + } + } +} diff --git a/C/HuffEnc.h b/C/HuffEnc.h index 11bfb362b..92b6878de 100644 --- a/C/HuffEnc.h +++ b/C/HuffEnc.h @@ -1,23 +1,23 @@ -/* HuffEnc.h -- Huffman encoding -2013-01-18 : Igor Pavlov : Public domain */ - -#ifndef __HUFF_ENC_H -#define __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 +/* HuffEnc.h -- Huffman encoding +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __HUFF_ENC_H +#define __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 4eefc17dd..df55e86c1 100644 --- a/C/LzFind.c +++ b/C/LzFind.c @@ -1,1127 +1,1127 @@ -/* LzFind.c -- Match finder for LZ algorithms -2018-07-08 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -#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 +2018-07-08 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#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; + } + */ +} diff --git a/C/LzFind.h b/C/LzFind.h index c77added7..42c13be15 100644 --- a/C/LzFind.h +++ b/C/LzFind.h @@ -1,121 +1,121 @@ -/* 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 +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 diff --git a/C/LzFindMt.c b/C/LzFindMt.c index df32146f9..bb0f42c30 100644 --- a/C/LzFindMt.c +++ b/C/LzFindMt.c @@ -1,853 +1,853 @@ -/* 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 +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; + */ + } +} diff --git a/C/LzFindMt.h b/C/LzFindMt.h index fdd17008c..ef431e3f5 100644 --- a/C/LzFindMt.h +++ b/C/LzFindMt.h @@ -1,101 +1,101 @@ -/* 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 +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 diff --git a/C/LzHash.h b/C/LzHash.h index 219144407..e7c942303 100644 --- a/C/LzHash.h +++ b/C/LzHash.h @@ -1,57 +1,57 @@ -/* 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 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 diff --git a/C/Lzma2Dec.c b/C/Lzma2Dec.c index 2e631051b..4e138a4ae 100644 --- a/C/Lzma2Dec.c +++ b/C/Lzma2Dec.c @@ -1,488 +1,488 @@ -/* Lzma2Dec.c -- LZMA2 Decoder -2019-02-02 : Igor Pavlov : Public domain */ - -/* #define SHOW_DEBUG_INFO */ - -#include "Precomp.h" - -#ifdef SHOW_DEBUG_INFO -#include -#endif - -#include - -#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 +2019-02-02 : Igor Pavlov : Public domain */ + +/* #define SHOW_DEBUG_INFO */ + +#include "Precomp.h" + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include + +#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; +} diff --git a/C/Lzma2Dec.h b/C/Lzma2Dec.h index da5038725..b8ddeac89 100644 --- a/C/Lzma2Dec.h +++ b/C/Lzma2Dec.h @@ -1,120 +1,120 @@ -/* 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 +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 diff --git a/C/Lzma2DecMt.c b/C/Lzma2DecMt.c index 87d5567ad..988643d95 100644 --- a/C/Lzma2DecMt.c +++ b/C/Lzma2DecMt.c @@ -1,1082 +1,1082 @@ -/* 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 -#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 +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#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; + } +} diff --git a/C/Lzma2DecMt.h b/C/Lzma2DecMt.h index 96f89a3ca..7791c310b 100644 --- a/C/Lzma2DecMt.h +++ b/C/Lzma2DecMt.h @@ -1,79 +1,79 @@ -/* 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 +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 diff --git a/C/Lzma2Enc.c b/C/Lzma2Enc.c index d54147752..5c1ad4931 100644 --- a/C/Lzma2Enc.c +++ b/C/Lzma2Enc.c @@ -1,803 +1,803 @@ -/* Lzma2Enc.c -- LZMA2 Encoder -2018-07-04 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -/* #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 +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #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); +} diff --git a/C/Lzma2Enc.h b/C/Lzma2Enc.h index 65f2dd145..6a6110ff7 100644 --- a/C/Lzma2Enc.h +++ b/C/Lzma2Enc.h @@ -1,55 +1,55 @@ -/* 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 +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 diff --git a/C/Lzma86.h b/C/Lzma86.h index 83057e598..bebed5cb7 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 +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 diff --git a/C/Lzma86Dec.c b/C/Lzma86Dec.c index 20ac5e7a9..21031745c 100644 --- a/C/Lzma86Dec.c +++ b/C/Lzma86Dec.c @@ -1,54 +1,54 @@ -/* 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 +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; +} diff --git a/C/Lzma86Enc.c b/C/Lzma86Enc.c index 8d35e6dc5..2617bab8e 100644 --- a/C/Lzma86Enc.c +++ b/C/Lzma86Enc.c @@ -1,106 +1,106 @@ -/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder -2018-07-04 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -#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 +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#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; +} diff --git a/C/LzmaDec.c b/C/LzmaDec.c index 4d1576419..ba3e1dd50 100644 --- a/C/LzmaDec.c +++ b/C/LzmaDec.c @@ -1,1185 +1,1185 @@ -/* LzmaDec.c -- LZMA Decoder -2018-07-04 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -/* #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 +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #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; +} diff --git a/C/LzmaDec.h b/C/LzmaDec.h index 28ce60c3e..1f0927ab1 100644 --- a/C/LzmaDec.h +++ b/C/LzmaDec.h @@ -1,234 +1,234 @@ -/* 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 +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 diff --git a/C/LzmaEnc.c b/C/LzmaEnc.c index 14086fc4f..46a0db000 100644 --- a/C/LzmaEnc.c +++ b/C/LzmaEnc.c @@ -1,2976 +1,2976 @@ -/* LzmaEnc.c -- LZMA Encoder -2019-01-10: Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -/* #define SHOW_STAT */ -/* #define SHOW_STAT2 */ - -#if defined(SHOW_STAT) || defined(SHOW_STAT2) -#include -#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 +2019-01-10: Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #define SHOW_STAT */ +/* #define SHOW_STAT2 */ + +#if defined(SHOW_STAT) || defined(SHOW_STAT2) +#include +#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; +} diff --git a/C/LzmaEnc.h b/C/LzmaEnc.h index c9938f04b..9194ee576 100644 --- a/C/LzmaEnc.h +++ b/C/LzmaEnc.h @@ -1,76 +1,76 @@ -/* 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 +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 diff --git a/C/LzmaLib.c b/C/LzmaLib.c index c10cf1a0f..706e9e58c 100644 --- a/C/LzmaLib.c +++ b/C/LzmaLib.c @@ -1,40 +1,40 @@ -/* 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 +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); +} diff --git a/C/LzmaLib.h b/C/LzmaLib.h index 5c35e5365..88fa87d35 100644 --- a/C/LzmaLib.h +++ b/C/LzmaLib.h @@ -1,131 +1,131 @@ -/* 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 +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 diff --git a/C/MtCoder.c b/C/MtCoder.c index 5667f2d5b..95359857b 100644 --- a/C/MtCoder.c +++ b/C/MtCoder.c @@ -1,601 +1,601 @@ -/* 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 +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 diff --git a/C/MtCoder.h b/C/MtCoder.h index 603329d36..5a5f4d11b 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 +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 diff --git a/C/MtDec.c b/C/MtDec.c index 25a8b046d..7803bf2a9 100644 --- a/C/MtDec.c +++ b/C/MtDec.c @@ -1,1138 +1,1138 @@ -/* MtDec.c -- Multi-thread Decoder -2019-02-02 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -// #define SHOW_DEBUG_INFO - -// #include - -#ifdef SHOW_DEBUG_INFO -#include -#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 -#else -#include -#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 +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #define SHOW_DEBUG_INFO + +// #include + +#ifdef SHOW_DEBUG_INFO +#include +#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 +#else +#include +#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 diff --git a/C/MtDec.h b/C/MtDec.h index 9864cc874..9b5776672 100644 --- a/C/MtDec.h +++ b/C/MtDec.h @@ -1,201 +1,201 @@ -/* 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 +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 diff --git a/C/Ppmd.h b/C/Ppmd.h index 4b9941521..a5c1e3ef2 100644 --- a/C/Ppmd.h +++ b/C/Ppmd.h @@ -1,85 +1,85 @@ -/* 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 +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 diff --git a/C/Ppmd7.c b/C/Ppmd7.c index 80e7de9a6..470aadccf 100644 --- a/C/Ppmd7.c +++ b/C/Ppmd7.c @@ -1,712 +1,712 @@ -/* 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 - -#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 +2018-07-04 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include + +#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); +} diff --git a/C/Ppmd7.h b/C/Ppmd7.h index cce93f120..610539a04 100644 --- a/C/Ppmd7.h +++ b/C/Ppmd7.h @@ -1,142 +1,142 @@ -/* 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 -- 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 diff --git a/C/Ppmd7Dec.c b/C/Ppmd7Dec.c index 202640710..311e9f9dd 100644 --- a/C/Ppmd7Dec.c +++ b/C/Ppmd7Dec.c @@ -1,191 +1,191 @@ -/* 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 -- 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); + } +} diff --git a/C/Ppmd7Enc.c b/C/Ppmd7Enc.c index a74d3002b..286b8712c 100644 --- a/C/Ppmd7Enc.c +++ b/C/Ppmd7Enc.c @@ -1,187 +1,187 @@ -/* 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 -- 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); + } +} diff --git a/C/Ppmd8.c b/C/Ppmd8.c index 3a6ee6c49..58141633a 100644 --- a/C/Ppmd8.c +++ b/C/Ppmd8.c @@ -1,1123 +1,1123 @@ -/* Ppmd8.c -- PPMdI codec -2018-07-04 : Igor Pavlov : Public domain -This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */ - -#include "Precomp.h" - -#include - -#include "Ppmd8.h" - -const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; -static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; - -#define MAX_FREQ 124 -#define UNIT_SIZE 12 - -#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) -#define U2I(nu) (p->Units2Indx[(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) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) -#define STATS(ctx) Ppmd8_GetStats(p, ctx) -#define ONE_STATE(ctx) Ppmd8Context_OneState(ctx) -#define SUFFIX(ctx) CTX((ctx)->Suffix) - -typedef CPpmd8_Context * CTX_PTR; - -struct CPpmd8_Node_; - -typedef - #ifdef PPMD_32BIT - struct CPpmd8_Node_ * - #else - UInt32 - #endif - CPpmd8_Node_Ref; - -typedef struct CPpmd8_Node_ -{ - UInt32 Stamp; - CPpmd8_Node_Ref Next; - UInt32 NU; -} CPpmd8_Node; - -#ifdef PPMD_32BIT - #define NODE(ptr) (ptr) -#else - #define NODE(offs) ((CPpmd8_Node *)(p->Base + (offs))) -#endif - -#define EMPTY_NODE 0xFFFFFFFF - -void Ppmd8_Construct(CPpmd8 *p) -{ - unsigned i, k, m; - - p->Base = 0; - - for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) - { - unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); - do { p->Units2Indx[k++] = (Byte)i; } while (--step); - p->Indx2Units[i] = (Byte)k; - } - - p->NS2BSIndx[0] = (0 << 1); - p->NS2BSIndx[1] = (1 << 1); - memset(p->NS2BSIndx + 2, (2 << 1), 9); - memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); - - for (i = 0; i < 5; i++) - p->NS2Indx[i] = (Byte)i; - for (m = i, k = 1; i < 260; i++) - { - p->NS2Indx[i] = (Byte)m; - if (--k == 0) - k = (++m) - 4; - } -} - -void Ppmd8_Free(CPpmd8 *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->Base); - p->Size = 0; - p->Base = 0; -} - -BoolInt Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAllocPtr alloc) -{ - if (!p->Base || p->Size != size) - { - Ppmd8_Free(p, alloc); - p->AlignOffset = - #ifdef PPMD_32BIT - (4 - size) & 3; - #else - 4 - (size & 3); - #endif - if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size)) == 0) - return False; - p->Size = size; - } - return True; -} - -static void InsertNode(CPpmd8 *p, void *node, unsigned indx) -{ - ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE; - ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx]; - ((CPpmd8_Node *)node)->NU = I2U(indx); - p->FreeList[indx] = REF(node); - p->Stamps[indx]++; -} - -static void *RemoveNode(CPpmd8 *p, unsigned indx) -{ - CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]); - p->FreeList[indx] = node->Next; - p->Stamps[indx]--; - return node; -} - -static void SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx) -{ - unsigned i, nu = I2U(oldIndx) - I2U(newIndx); - ptr = (Byte *)ptr + U2B(I2U(newIndx)); - if (I2U(i = U2I(nu)) != nu) - { - unsigned k = I2U(--i); - InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); - } - InsertNode(p, ptr, i); -} - -static void GlueFreeBlocks(CPpmd8 *p) -{ - CPpmd8_Node_Ref head = 0; - CPpmd8_Node_Ref *prev = &head; - unsigned i; - - p->GlueCount = 1 << 13; - memset(p->Stamps, 0, sizeof(p->Stamps)); - - /* Order-0 context is always at top UNIT, so we don't need guard NODE at the end. - All blocks up to p->LoUnit can be free, so we need guard NODE at LoUnit. */ - if (p->LoUnit != p->HiUnit) - ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; - - /* Glue free blocks */ - for (i = 0; i < PPMD_NUM_INDEXES; i++) - { - CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i]; - p->FreeList[i] = 0; - while (next != 0) - { - CPpmd8_Node *node = NODE(next); - if (node->NU != 0) - { - CPpmd8_Node *node2; - *prev = next; - prev = &(node->Next); - while ((node2 = node + node->NU)->Stamp == EMPTY_NODE) - { - node->NU += node2->NU; - node2->NU = 0; - } - } - next = node->Next; - } - } - *prev = 0; - - /* Fill lists of free blocks */ - while (head != 0) - { - CPpmd8_Node *node = NODE(head); - unsigned nu; - head = node->Next; - nu = node->NU; - if (nu == 0) - continue; - for (; nu > 128; nu -= 128, node += 128) - InsertNode(p, node, PPMD_NUM_INDEXES - 1); - if (I2U(i = U2I(nu)) != nu) - { - unsigned k = I2U(--i); - InsertNode(p, node + k, nu - k - 1); - } - InsertNode(p, node, i); - } -} - -static void *AllocUnitsRare(CPpmd8 *p, unsigned indx) -{ - unsigned i; - void *retVal; - if (p->GlueCount == 0) - { - GlueFreeBlocks(p); - if (p->FreeList[indx] != 0) - return RemoveNode(p, indx); - } - i = indx; - do - { - if (++i == PPMD_NUM_INDEXES) - { - UInt32 numBytes = U2B(I2U(indx)); - p->GlueCount--; - return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); - } - } - while (p->FreeList[i] == 0); - retVal = RemoveNode(p, i); - SplitBlock(p, retVal, i, indx); - return retVal; -} - -static void *AllocUnits(CPpmd8 *p, unsigned indx) -{ - UInt32 numBytes; - if (p->FreeList[indx] != 0) - return RemoveNode(p, indx); - numBytes = U2B(I2U(indx)); - if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) - { - void *retVal = p->LoUnit; - p->LoUnit += numBytes; - return retVal; - } - return AllocUnitsRare(p, indx); -} - -#define MyMem12Cpy(dest, src, num) \ - { UInt32 *d = (UInt32 *)dest; const UInt32 *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 = RemoveNode(p, i1); - MyMem12Cpy(ptr, oldPtr, newNU); - InsertNode(p, oldPtr, i0); - return ptr; - } - SplitBlock(p, oldPtr, i0, i1); - return oldPtr; -} - -static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu) -{ - InsertNode(p, ptr, U2I(nu)); -} - -static void SpecialFreeUnit(CPpmd8 *p, void *ptr) -{ - if ((Byte *)ptr != p->UnitsStart) - InsertNode(p, ptr, 0); - else - { - #ifdef PPMD8_FREEZE_SUPPORT - *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts */ - #endif - p->UnitsStart += UNIT_SIZE; - } -} - -static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu) -{ - unsigned indx = U2I(nu); - void *ptr; - if ((Byte *)oldPtr > p->UnitsStart + 16 * 1024 || REF(oldPtr) > p->FreeList[indx]) - return oldPtr; - ptr = RemoveNode(p, indx); - MyMem12Cpy(ptr, oldPtr, nu); - if ((Byte*)oldPtr != p->UnitsStart) - InsertNode(p, oldPtr, indx); - else - p->UnitsStart += U2B(I2U(indx)); - return ptr; -} - -static void ExpandTextArea(CPpmd8 *p) -{ - UInt32 count[PPMD_NUM_INDEXES]; - unsigned i; - memset(count, 0, sizeof(count)); - if (p->LoUnit != p->HiUnit) - ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; - - { - CPpmd8_Node *node = (CPpmd8_Node *)p->UnitsStart; - for (; node->Stamp == EMPTY_NODE; node += node->NU) - { - node->Stamp = 0; - count[U2I(node->NU)]++; - } - p->UnitsStart = (Byte *)node; - } - - for (i = 0; i < PPMD_NUM_INDEXES; i++) - { - CPpmd8_Node_Ref *next = (CPpmd8_Node_Ref *)&p->FreeList[i]; - while (count[i] != 0) - { - CPpmd8_Node *node = NODE(*next); - while (node->Stamp == 0) - { - *next = node->Next; - node = NODE(*next); - p->Stamps[i]--; - if (--count[i] == 0) - break; - } - next = &node->Next; - } - } -} - -#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) - -static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) -{ - (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); - (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); -} - -#define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); } - -static void RestartModel(CPpmd8 *p) -{ - unsigned i, k, m, r; - - memset(p->FreeList, 0, sizeof(p->FreeList)); - memset(p->Stamps, 0, sizeof(p->Stamps)); - RESET_TEXT(0); - p->HiUnit = p->Text + p->Size; - p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; - p->GlueCount = 0; - - p->OrderFall = p->MaxOrder; - p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; - p->PrevSuccess = 0; - - p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ - p->MinContext->Suffix = 0; - p->MinContext->NumStats = 255; - p->MinContext->Flags = 0; - p->MinContext->SummFreq = 256 + 1; - p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ - p->LoUnit += U2B(256 / 2); - p->MinContext->Stats = REF(p->FoundState); - for (i = 0; i < 256; i++) - { - CPpmd_State *s = &p->FoundState[i]; - s->Symbol = (Byte)i; - s->Freq = 1; - SetSuccessor(s, 0); - } - - for (i = m = 0; m < 25; m++) - { - while (p->NS2Indx[i] == m) - i++; - for (k = 0; k < 8; k++) - { - UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 1)); - UInt16 *dest = p->BinSumm[m] + k; - for (r = 0; r < 64; r += 8) - dest[r] = val; - } - } - - for (i = m = 0; m < 24; m++) - { - while (p->NS2Indx[(size_t)i + 3] == m + 3) - i++; - for (k = 0; k < 32; k++) - { - CPpmd_See *s = &p->See[m][k]; - s->Summ = (UInt16)((2 * i + 5) << (s->Shift = PPMD_PERIOD_BITS - 4)); - s->Count = 7; - } - } -} - -void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod) -{ - p->MaxOrder = maxOrder; - p->RestoreMethod = restoreMethod; - RestartModel(p); - p->DummySee.Shift = PPMD_PERIOD_BITS; - p->DummySee.Summ = 0; /* unused */ - p->DummySee.Count = 64; /* unused */ -} - -static void Refresh(CPpmd8 *p, CTX_PTR ctx, unsigned oldNU, unsigned scale) -{ - unsigned i = ctx->NumStats, escFreq, sumFreq, flags; - CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1); - ctx->Stats = REF(s); - #ifdef PPMD8_FREEZE_SUPPORT - /* fixed over Shkarin's code. Fixed code is not compatible with original code for some files in FREEZE mode. */ - scale |= (ctx->SummFreq >= ((UInt32)1 << 15)); - #endif - flags = (ctx->Flags & (0x10 + 0x04 * scale)) + 0x08 * (s->Symbol >= 0x40); - escFreq = ctx->SummFreq - s->Freq; - sumFreq = (s->Freq = (Byte)((s->Freq + scale) >> scale)); - do - { - escFreq -= (++s)->Freq; - sumFreq += (s->Freq = (Byte)((s->Freq + scale) >> scale)); - flags |= 0x08 * (s->Symbol >= 0x40); - } - while (--i); - ctx->SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale)); - ctx->Flags = (Byte)flags; -} - -static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) -{ - CPpmd_State tmp = *t1; - *t1 = *t2; - *t2 = tmp; -} - -static CPpmd_Void_Ref CutOff(CPpmd8 *p, CTX_PTR ctx, unsigned order) -{ - int i; - unsigned tmp; - CPpmd_State *s; - - if (!ctx->NumStats) - { - s = ONE_STATE(ctx); - if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart) - { - if (order < p->MaxOrder) - SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); - else - SetSuccessor(s, 0); - if (SUCCESSOR(s) || order <= 9) /* O_BOUND */ - return REF(ctx); - } - SpecialFreeUnit(p, ctx); - return 0; - } - - ctx->Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), tmp = ((unsigned)ctx->NumStats + 2) >> 1)); - - for (s = STATS(ctx) + (i = ctx->NumStats); s >= STATS(ctx); s--) - if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) < p->UnitsStart) - { - CPpmd_State *s2 = STATS(ctx) + (i--); - SetSuccessor(s, 0); - SwapStates(s, s2); - } - else if (order < p->MaxOrder) - SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); - else - SetSuccessor(s, 0); - - if (i != ctx->NumStats && order) - { - ctx->NumStats = (Byte)i; - s = STATS(ctx); - if (i < 0) - { - FreeUnits(p, s, tmp); - SpecialFreeUnit(p, ctx); - return 0; - } - if (i == 0) - { - ctx->Flags = (Byte)((ctx->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40)); - *ONE_STATE(ctx) = *s; - FreeUnits(p, s, tmp); - /* 9.31: the code was fixed. It's was not BUG, if Freq <= MAX_FREQ = 124 */ - ONE_STATE(ctx)->Freq = (Byte)(((unsigned)ONE_STATE(ctx)->Freq + 11) >> 3); - } - else - Refresh(p, ctx, tmp, ctx->SummFreq > 16 * i); - } - return REF(ctx); -} - -#ifdef PPMD8_FREEZE_SUPPORT -static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, CTX_PTR ctx, unsigned order) -{ - CPpmd_State *s; - if (!ctx->NumStats) - { - s = ONE_STATE(ctx); - if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder) - SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1)); - else - SetSuccessor(s, 0); - /* Suffix context can be removed already, since different (high-order) - Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */ - if (!SUCCESSOR(s) && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF)) - { - FreeUnits(p, ctx, 1); - return 0; - } - else - return REF(ctx); - } - - for (s = STATS(ctx) + ctx->NumStats; s >= STATS(ctx); s--) - if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder) - SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1)); - else - SetSuccessor(s, 0); - - return REF(ctx); -} -#endif - -static UInt32 GetUsedMemory(const CPpmd8 *p) -{ - UInt32 v = 0; - unsigned i; - for (i = 0; i < PPMD_NUM_INDEXES; i++) - v += p->Stamps[i] * I2U(i); - return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v); -} - -#ifdef PPMD8_FREEZE_SUPPORT - #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor) -#else - #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1) -#endif - -static void RestoreModel(CPpmd8 *p, CTX_PTR c1 - #ifdef PPMD8_FREEZE_SUPPORT - , CTX_PTR fSuccessor - #endif - ) -{ - CTX_PTR c; - CPpmd_State *s; - RESET_TEXT(0); - for (c = p->MaxContext; c != c1; c = SUFFIX(c)) - if (--(c->NumStats) == 0) - { - s = STATS(c); - c->Flags = (Byte)((c->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40)); - *ONE_STATE(c) = *s; - SpecialFreeUnit(p, s); - ONE_STATE(c)->Freq = (Byte)(((unsigned)ONE_STATE(c)->Freq + 11) >> 3); - } - else - Refresh(p, c, (c->NumStats+3) >> 1, 0); - - for (; c != p->MinContext; c = SUFFIX(c)) - if (!c->NumStats) - ONE_STATE(c)->Freq = (Byte)(ONE_STATE(c)->Freq - (ONE_STATE(c)->Freq >> 1)); - else if ((c->SummFreq += 4) > 128 + 4 * c->NumStats) - Refresh(p, c, (c->NumStats + 2) >> 1, 1); - - #ifdef PPMD8_FREEZE_SUPPORT - if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) - { - p->MaxContext = fSuccessor; - p->GlueCount += !(p->Stamps[1] & 1); - } - else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE) - { - while (p->MaxContext->Suffix) - p->MaxContext = SUFFIX(p->MaxContext); - RemoveBinContexts(p, p->MaxContext, 0); - p->RestoreMethod++; - p->GlueCount = 0; - p->OrderFall = p->MaxOrder; - } - else - #endif - if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1)) - RestartModel(p); - else - { - while (p->MaxContext->Suffix) - p->MaxContext = SUFFIX(p->MaxContext); - do - { - CutOff(p, p->MaxContext, 0); - ExpandTextArea(p); - } - while (GetUsedMemory(p) > 3 * (p->Size >> 2)); - p->GlueCount = 0; - p->OrderFall = p->MaxOrder; - } -} - -static CTX_PTR CreateSuccessors(CPpmd8 *p, BoolInt skip, CPpmd_State *s1, CTX_PTR c) -{ - CPpmd_State upState; - Byte flags; - CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); - /* fixed over Shkarin's code. Maybe it could work without + 1 too. */ - CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; - unsigned numPs = 0; - - if (!skip) - ps[numPs++] = p->FoundState; - - while (c->Suffix) - { - CPpmd_Void_Ref successor; - CPpmd_State *s; - c = SUFFIX(c); - if (s1) - { - s = s1; - s1 = NULL; - } - else if (c->NumStats != 0) - { - for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); - if (s->Freq < MAX_FREQ - 9) - { - s->Freq++; - c->SummFreq++; - } - } - else - { - s = ONE_STATE(c); - s->Freq = (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; - } - - upState.Symbol = *(const Byte *)Ppmd8_GetPtr(p, upBranch); - SetSuccessor(&upState, upBranch + 1); - flags = (Byte)(0x10 * (p->FoundState->Symbol >= 0x40) + 0x08 * (upState.Symbol >= 0x40)); - - if (c->NumStats == 0) - upState.Freq = ONE_STATE(c)->Freq; - else - { - UInt32 cf, s0; - CPpmd_State *s; - for (s = STATS(c); s->Symbol != upState.Symbol; s++); - cf = s->Freq - 1; - s0 = c->SummFreq - c->NumStats - cf; - upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0))); - } - - do - { - /* Create Child */ - CTX_PTR c1; /* = AllocContext(p); */ - if (p->HiUnit != p->LoUnit) - c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); - else if (p->FreeList[0] != 0) - c1 = (CTX_PTR)RemoveNode(p, 0); - else - { - c1 = (CTX_PTR)AllocUnitsRare(p, 0); - if (!c1) - return NULL; - } - c1->NumStats = 0; - c1->Flags = flags; - *ONE_STATE(c1) = upState; - c1->Suffix = REF(c); - SetSuccessor(ps[--numPs], REF(c1)); - c = c1; - } - while (numPs != 0); - - return c; -} - -static CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, CTX_PTR c) -{ - CPpmd_State *s = NULL; - CTX_PTR c1 = c; - CPpmd_Void_Ref upBranch = REF(p->Text); - - #ifdef PPMD8_FREEZE_SUPPORT - /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */ - CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; - unsigned numPs = 0; - ps[numPs++] = p->FoundState; - #endif - - SetSuccessor(p->FoundState, upBranch); - p->OrderFall++; - - for (;;) - { - if (s1) - { - c = SUFFIX(c); - s = s1; - s1 = NULL; - } - else - { - if (!c->Suffix) - { - #ifdef PPMD8_FREEZE_SUPPORT - if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) - { - do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); - RESET_TEXT(1); - p->OrderFall = 1; - } - #endif - return c; - } - c = SUFFIX(c); - if (c->NumStats) - { - if ((s = STATS(c))->Symbol != p->FoundState->Symbol) - do { s++; } while (s->Symbol != p->FoundState->Symbol); - if (s->Freq < MAX_FREQ - 9) - { - s->Freq += 2; - c->SummFreq += 2; - } - } - else - { - s = ONE_STATE(c); - s->Freq = (Byte)(s->Freq + (s->Freq < 32)); - } - } - if (SUCCESSOR(s)) - break; - #ifdef PPMD8_FREEZE_SUPPORT - ps[numPs++] = s; - #endif - SetSuccessor(s, upBranch); - p->OrderFall++; - } - - #ifdef PPMD8_FREEZE_SUPPORT - if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) - { - c = CTX(SUCCESSOR(s)); - do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); - RESET_TEXT(1); - p->OrderFall = 1; - return c; - } - else - #endif - if (SUCCESSOR(s) <= upBranch) - { - CTX_PTR successor; - CPpmd_State *s2 = p->FoundState; - p->FoundState = s; - - successor = CreateSuccessors(p, False, NULL, c); - if (successor == NULL) - SetSuccessor(s, 0); - else - SetSuccessor(s, REF(successor)); - p->FoundState = s2; - } - - if (p->OrderFall == 1 && c1 == p->MaxContext) - { - SetSuccessor(p->FoundState, SUCCESSOR(s)); - p->Text--; - } - if (SUCCESSOR(s) == 0) - return NULL; - return CTX(SUCCESSOR(s)); -} - -static void UpdateModel(CPpmd8 *p) -{ - CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); - CTX_PTR c; - unsigned s0, ns, fFreq = p->FoundState->Freq; - Byte flag, fSymbol = p->FoundState->Symbol; - CPpmd_State *s = NULL; - - if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) - { - c = SUFFIX(p->MinContext); - - if (c->NumStats == 0) - { - s = ONE_STATE(c); - if (s->Freq < 32) - s->Freq++; - } - else - { - s = STATS(c); - if (s->Symbol != p->FoundState->Symbol) - { - do { s++; } while (s->Symbol != p->FoundState->Symbol); - if (s[0].Freq >= s[-1].Freq) - { - SwapStates(&s[0], &s[-1]); - s--; - } - } - if (s->Freq < MAX_FREQ - 9) - { - s->Freq += 2; - c->SummFreq += 2; - } - } - } - - c = p->MaxContext; - if (p->OrderFall == 0 && fSuccessor) - { - CTX_PTR cs = CreateSuccessors(p, True, s, p->MinContext); - if (cs == 0) - { - SetSuccessor(p->FoundState, 0); - RESTORE_MODEL(c, CTX(fSuccessor)); - } - else - { - SetSuccessor(p->FoundState, REF(cs)); - p->MaxContext = cs; - } - return; - } - - *p->Text++ = p->FoundState->Symbol; - successor = REF(p->Text); - if (p->Text >= p->UnitsStart) - { - RESTORE_MODEL(c, CTX(fSuccessor)); /* check it */ - return; - } - - if (!fSuccessor) - { - CTX_PTR cs = ReduceOrder(p, s, p->MinContext); - if (cs == NULL) - { - RESTORE_MODEL(c, 0); - return; - } - fSuccessor = REF(cs); - } - else if ((Byte *)Ppmd8_GetPtr(p, fSuccessor) < p->UnitsStart) - { - CTX_PTR cs = CreateSuccessors(p, False, s, p->MinContext); - if (cs == NULL) - { - RESTORE_MODEL(c, 0); - return; - } - fSuccessor = REF(cs); - } - - if (--p->OrderFall == 0) - { - successor = fSuccessor; - p->Text -= (p->MaxContext != p->MinContext); - } - #ifdef PPMD8_FREEZE_SUPPORT - else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) - { - successor = fSuccessor; - RESET_TEXT(0); - p->OrderFall = 0; - } - #endif - - s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - fFreq; - flag = (Byte)(0x08 * (fSymbol >= 0x40)); - - for (; c != p->MinContext; c = SUFFIX(c)) - { - unsigned ns1; - UInt32 cf, sf; - if ((ns1 = c->NumStats) != 0) - { - if ((ns1 & 1) != 0) - { - /* Expand for one UNIT */ - unsigned oldNU = (ns1 + 1) >> 1; - unsigned i = U2I(oldNU); - if (i != U2I((size_t)oldNU + 1)) - { - void *ptr = AllocUnits(p, i + 1); - void *oldPtr; - if (!ptr) - { - RESTORE_MODEL(c, CTX(fSuccessor)); - return; - } - oldPtr = STATS(c); - MyMem12Cpy(ptr, oldPtr, oldNU); - InsertNode(p, oldPtr, i); - c->Stats = STATS_REF(ptr); - } - } - c->SummFreq = (UInt16)(c->SummFreq + (3 * ns1 + 1 < ns)); - } - else - { - CPpmd_State *s2 = (CPpmd_State*)AllocUnits(p, 0); - if (!s2) - { - RESTORE_MODEL(c, CTX(fSuccessor)); - return; - } - *s2 = *ONE_STATE(c); - c->Stats = REF(s2); - if (s2->Freq < MAX_FREQ / 4 - 1) - s2->Freq <<= 1; - else - s2->Freq = MAX_FREQ - 4; - c->SummFreq = (UInt16)(s2->Freq + p->InitEsc + (ns > 2)); - } - cf = 2 * fFreq * (c->SummFreq + 6); - sf = (UInt32)s0 + c->SummFreq; - if (cf < 6 * sf) - { - cf = 1 + (cf > sf) + (cf >= 4 * sf); - c->SummFreq += 4; - } - else - { - cf = 4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf); - c->SummFreq = (UInt16)(c->SummFreq + cf); - } - { - CPpmd_State *s2 = STATS(c) + ns1 + 1; - SetSuccessor(s2, successor); - s2->Symbol = fSymbol; - s2->Freq = (Byte)cf; - c->Flags |= flag; - c->NumStats = (Byte)(ns1 + 1); - } - } - p->MaxContext = p->MinContext = CTX(fSuccessor); -} - -static void Rescale(CPpmd8 *p) -{ - unsigned i, adder, sumFreq, escFreq; - CPpmd_State *stats = STATS(p->MinContext); - CPpmd_State *s = p->FoundState; - { - CPpmd_State tmp = *s; - for (; s != stats; s--) - s[0] = s[-1]; - *s = tmp; - } - escFreq = p->MinContext->SummFreq - s->Freq; - s->Freq += 4; - adder = (p->OrderFall != 0 - #ifdef PPMD8_FREEZE_SUPPORT - || p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE - #endif - ); - s->Freq = (Byte)((s->Freq + adder) >> 1); - sumFreq = s->Freq; - - i = p->MinContext->NumStats; - do - { - escFreq -= (++s)->Freq; - s->Freq = (Byte)((s->Freq + adder) >> 1); - sumFreq += s->Freq; - if (s[0].Freq > s[-1].Freq) - { - CPpmd_State *s1 = s; - CPpmd_State tmp = *s1; - do - s1[0] = s1[-1]; - while (--s1 != stats && tmp.Freq > s1[-1].Freq); - *s1 = tmp; - } - } - while (--i); - - if (s->Freq == 0) - { - unsigned numStats = p->MinContext->NumStats; - unsigned n0, n1; - do { i++; } while ((--s)->Freq == 0); - escFreq += i; - p->MinContext->NumStats = (Byte)(p->MinContext->NumStats - i); - if (p->MinContext->NumStats == 0) - { - CPpmd_State tmp = *stats; - tmp.Freq = (Byte)((2 * tmp.Freq + escFreq - 1) / escFreq); - if (tmp.Freq > MAX_FREQ / 3) - tmp.Freq = MAX_FREQ / 3; - InsertNode(p, stats, U2I((numStats + 2) >> 1)); - p->MinContext->Flags = (Byte)((p->MinContext->Flags & 0x10) + 0x08 * (tmp.Symbol >= 0x40)); - *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; - return; - } - n0 = (numStats + 2) >> 1; - n1 = (p->MinContext->NumStats + 2) >> 1; - if (n0 != n1) - p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); - p->MinContext->Flags &= ~0x08; - p->MinContext->Flags |= 0x08 * ((s = STATS(p->MinContext))->Symbol >= 0x40); - i = p->MinContext->NumStats; - do { p->MinContext->Flags |= 0x08*((++s)->Symbol >= 0x40); } while (--i); - } - p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); - p->MinContext->Flags |= 0x4; - p->FoundState = STATS(p->MinContext); -} - -CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq) -{ - CPpmd_See *see; - if (p->MinContext->NumStats != 0xFF) - { - see = p->See[(size_t)(unsigned)p->NS2Indx[(size_t)(unsigned)p->MinContext->NumStats + 2] - 3] + - (p->MinContext->SummFreq > 11 * ((unsigned)p->MinContext->NumStats + 1)) + - 2 * (unsigned)(2 * (unsigned)p->MinContext->NumStats < - ((unsigned)SUFFIX(p->MinContext)->NumStats + numMasked1)) + - p->MinContext->Flags; - { - unsigned r = (see->Summ >> see->Shift); - see->Summ = (UInt16)(see->Summ - r); - *escFreq = r + (r == 0); - } - } - else - { - see = &p->DummySee; - *escFreq = 1; - } - return see; -} - -static void NextContext(CPpmd8 *p) -{ - CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); - if (p->OrderFall == 0 && (Byte *)c >= p->UnitsStart) - p->MinContext = p->MaxContext = c; - else - { - UpdateModel(p); - p->MinContext = p->MaxContext; - } -} - -void Ppmd8_Update1(CPpmd8 *p) -{ - CPpmd_State *s = p->FoundState; - s->Freq += 4; - p->MinContext->SummFreq += 4; - if (s[0].Freq > s[-1].Freq) - { - SwapStates(&s[0], &s[-1]); - p->FoundState = --s; - if (s->Freq > MAX_FREQ) - Rescale(p); - } - NextContext(p); -} - -void Ppmd8_Update1_0(CPpmd8 *p) -{ - p->PrevSuccess = (2 * p->FoundState->Freq >= p->MinContext->SummFreq); - p->RunLength += p->PrevSuccess; - p->MinContext->SummFreq += 4; - if ((p->FoundState->Freq += 4) > MAX_FREQ) - Rescale(p); - NextContext(p); -} - -void Ppmd8_UpdateBin(CPpmd8 *p) -{ - p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 196)); - p->PrevSuccess = 1; - p->RunLength++; - NextContext(p); -} - -void Ppmd8_Update2(CPpmd8 *p) -{ - p->MinContext->SummFreq += 4; - if ((p->FoundState->Freq += 4) > MAX_FREQ) - Rescale(p); - p->RunLength = p->InitRL; - UpdateModel(p); - p->MinContext = p->MaxContext; -} - -/* H->I changes: - NS2Indx - GlewCount, and Glue method - BinSum - See / EscFreq - CreateSuccessors updates more suffix contexts - UpdateModel consts. - PrevSuccess Update -*/ +/* Ppmd8.c -- PPMdI codec +2018-07-04 : Igor Pavlov : Public domain +This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include + +#include "Ppmd8.h" + +const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; +static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; + +#define MAX_FREQ 124 +#define UNIT_SIZE 12 + +#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) +#define U2I(nu) (p->Units2Indx[(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) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) +#define STATS(ctx) Ppmd8_GetStats(p, ctx) +#define ONE_STATE(ctx) Ppmd8Context_OneState(ctx) +#define SUFFIX(ctx) CTX((ctx)->Suffix) + +typedef CPpmd8_Context * CTX_PTR; + +struct CPpmd8_Node_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd8_Node_ * + #else + UInt32 + #endif + CPpmd8_Node_Ref; + +typedef struct CPpmd8_Node_ +{ + UInt32 Stamp; + CPpmd8_Node_Ref Next; + UInt32 NU; +} CPpmd8_Node; + +#ifdef PPMD_32BIT + #define NODE(ptr) (ptr) +#else + #define NODE(offs) ((CPpmd8_Node *)(p->Base + (offs))) +#endif + +#define EMPTY_NODE 0xFFFFFFFF + +void Ppmd8_Construct(CPpmd8 *p) +{ + unsigned i, k, m; + + p->Base = 0; + + for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) + { + unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); + do { p->Units2Indx[k++] = (Byte)i; } while (--step); + p->Indx2Units[i] = (Byte)k; + } + + p->NS2BSIndx[0] = (0 << 1); + p->NS2BSIndx[1] = (1 << 1); + memset(p->NS2BSIndx + 2, (2 << 1), 9); + memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); + + for (i = 0; i < 5; i++) + p->NS2Indx[i] = (Byte)i; + for (m = i, k = 1; i < 260; i++) + { + p->NS2Indx[i] = (Byte)m; + if (--k == 0) + k = (++m) - 4; + } +} + +void Ppmd8_Free(CPpmd8 *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->Base); + p->Size = 0; + p->Base = 0; +} + +BoolInt Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAllocPtr alloc) +{ + if (!p->Base || p->Size != size) + { + Ppmd8_Free(p, alloc); + p->AlignOffset = + #ifdef PPMD_32BIT + (4 - size) & 3; + #else + 4 - (size & 3); + #endif + if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size)) == 0) + return False; + p->Size = size; + } + return True; +} + +static void InsertNode(CPpmd8 *p, void *node, unsigned indx) +{ + ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE; + ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx]; + ((CPpmd8_Node *)node)->NU = I2U(indx); + p->FreeList[indx] = REF(node); + p->Stamps[indx]++; +} + +static void *RemoveNode(CPpmd8 *p, unsigned indx) +{ + CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]); + p->FreeList[indx] = node->Next; + p->Stamps[indx]--; + return node; +} + +static void SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx) +{ + unsigned i, nu = I2U(oldIndx) - I2U(newIndx); + ptr = (Byte *)ptr + U2B(I2U(newIndx)); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); + } + InsertNode(p, ptr, i); +} + +static void GlueFreeBlocks(CPpmd8 *p) +{ + CPpmd8_Node_Ref head = 0; + CPpmd8_Node_Ref *prev = &head; + unsigned i; + + p->GlueCount = 1 << 13; + memset(p->Stamps, 0, sizeof(p->Stamps)); + + /* Order-0 context is always at top UNIT, so we don't need guard NODE at the end. + All blocks up to p->LoUnit can be free, so we need guard NODE at LoUnit. */ + if (p->LoUnit != p->HiUnit) + ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; + + /* Glue free blocks */ + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i]; + p->FreeList[i] = 0; + while (next != 0) + { + CPpmd8_Node *node = NODE(next); + if (node->NU != 0) + { + CPpmd8_Node *node2; + *prev = next; + prev = &(node->Next); + while ((node2 = node + node->NU)->Stamp == EMPTY_NODE) + { + node->NU += node2->NU; + node2->NU = 0; + } + } + next = node->Next; + } + } + *prev = 0; + + /* Fill lists of free blocks */ + while (head != 0) + { + CPpmd8_Node *node = NODE(head); + unsigned nu; + head = node->Next; + nu = node->NU; + if (nu == 0) + continue; + for (; nu > 128; nu -= 128, node += 128) + InsertNode(p, node, PPMD_NUM_INDEXES - 1); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, node + k, nu - k - 1); + } + InsertNode(p, node, i); + } +} + +static void *AllocUnitsRare(CPpmd8 *p, unsigned indx) +{ + unsigned i; + void *retVal; + if (p->GlueCount == 0) + { + GlueFreeBlocks(p); + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + } + i = indx; + do + { + if (++i == PPMD_NUM_INDEXES) + { + UInt32 numBytes = U2B(I2U(indx)); + p->GlueCount--; + return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); + } + } + while (p->FreeList[i] == 0); + retVal = RemoveNode(p, i); + SplitBlock(p, retVal, i, indx); + return retVal; +} + +static void *AllocUnits(CPpmd8 *p, unsigned indx) +{ + UInt32 numBytes; + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + numBytes = U2B(I2U(indx)); + if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) + { + void *retVal = p->LoUnit; + p->LoUnit += numBytes; + return retVal; + } + return AllocUnitsRare(p, indx); +} + +#define MyMem12Cpy(dest, src, num) \ + { UInt32 *d = (UInt32 *)dest; const UInt32 *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 = RemoveNode(p, i1); + MyMem12Cpy(ptr, oldPtr, newNU); + InsertNode(p, oldPtr, i0); + return ptr; + } + SplitBlock(p, oldPtr, i0, i1); + return oldPtr; +} + +static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu) +{ + InsertNode(p, ptr, U2I(nu)); +} + +static void SpecialFreeUnit(CPpmd8 *p, void *ptr) +{ + if ((Byte *)ptr != p->UnitsStart) + InsertNode(p, ptr, 0); + else + { + #ifdef PPMD8_FREEZE_SUPPORT + *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts */ + #endif + p->UnitsStart += UNIT_SIZE; + } +} + +static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu) +{ + unsigned indx = U2I(nu); + void *ptr; + if ((Byte *)oldPtr > p->UnitsStart + 16 * 1024 || REF(oldPtr) > p->FreeList[indx]) + return oldPtr; + ptr = RemoveNode(p, indx); + MyMem12Cpy(ptr, oldPtr, nu); + if ((Byte*)oldPtr != p->UnitsStart) + InsertNode(p, oldPtr, indx); + else + p->UnitsStart += U2B(I2U(indx)); + return ptr; +} + +static void ExpandTextArea(CPpmd8 *p) +{ + UInt32 count[PPMD_NUM_INDEXES]; + unsigned i; + memset(count, 0, sizeof(count)); + if (p->LoUnit != p->HiUnit) + ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; + + { + CPpmd8_Node *node = (CPpmd8_Node *)p->UnitsStart; + for (; node->Stamp == EMPTY_NODE; node += node->NU) + { + node->Stamp = 0; + count[U2I(node->NU)]++; + } + p->UnitsStart = (Byte *)node; + } + + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + CPpmd8_Node_Ref *next = (CPpmd8_Node_Ref *)&p->FreeList[i]; + while (count[i] != 0) + { + CPpmd8_Node *node = NODE(*next); + while (node->Stamp == 0) + { + *next = node->Next; + node = NODE(*next); + p->Stamps[i]--; + if (--count[i] == 0) + break; + } + next = &node->Next; + } + } +} + +#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) + +static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) +{ + (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); + (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); +} + +#define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); } + +static void RestartModel(CPpmd8 *p) +{ + unsigned i, k, m, r; + + memset(p->FreeList, 0, sizeof(p->FreeList)); + memset(p->Stamps, 0, sizeof(p->Stamps)); + RESET_TEXT(0); + p->HiUnit = p->Text + p->Size; + p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; + p->GlueCount = 0; + + p->OrderFall = p->MaxOrder; + p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; + p->PrevSuccess = 0; + + p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ + p->MinContext->Suffix = 0; + p->MinContext->NumStats = 255; + p->MinContext->Flags = 0; + p->MinContext->SummFreq = 256 + 1; + p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ + p->LoUnit += U2B(256 / 2); + p->MinContext->Stats = REF(p->FoundState); + for (i = 0; i < 256; i++) + { + CPpmd_State *s = &p->FoundState[i]; + s->Symbol = (Byte)i; + s->Freq = 1; + SetSuccessor(s, 0); + } + + for (i = m = 0; m < 25; m++) + { + while (p->NS2Indx[i] == m) + i++; + for (k = 0; k < 8; k++) + { + UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 1)); + UInt16 *dest = p->BinSumm[m] + k; + for (r = 0; r < 64; r += 8) + dest[r] = val; + } + } + + for (i = m = 0; m < 24; m++) + { + while (p->NS2Indx[(size_t)i + 3] == m + 3) + i++; + for (k = 0; k < 32; k++) + { + CPpmd_See *s = &p->See[m][k]; + s->Summ = (UInt16)((2 * i + 5) << (s->Shift = PPMD_PERIOD_BITS - 4)); + s->Count = 7; + } + } +} + +void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod) +{ + p->MaxOrder = maxOrder; + p->RestoreMethod = restoreMethod; + RestartModel(p); + p->DummySee.Shift = PPMD_PERIOD_BITS; + p->DummySee.Summ = 0; /* unused */ + p->DummySee.Count = 64; /* unused */ +} + +static void Refresh(CPpmd8 *p, CTX_PTR ctx, unsigned oldNU, unsigned scale) +{ + unsigned i = ctx->NumStats, escFreq, sumFreq, flags; + CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1); + ctx->Stats = REF(s); + #ifdef PPMD8_FREEZE_SUPPORT + /* fixed over Shkarin's code. Fixed code is not compatible with original code for some files in FREEZE mode. */ + scale |= (ctx->SummFreq >= ((UInt32)1 << 15)); + #endif + flags = (ctx->Flags & (0x10 + 0x04 * scale)) + 0x08 * (s->Symbol >= 0x40); + escFreq = ctx->SummFreq - s->Freq; + sumFreq = (s->Freq = (Byte)((s->Freq + scale) >> scale)); + do + { + escFreq -= (++s)->Freq; + sumFreq += (s->Freq = (Byte)((s->Freq + scale) >> scale)); + flags |= 0x08 * (s->Symbol >= 0x40); + } + while (--i); + ctx->SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale)); + ctx->Flags = (Byte)flags; +} + +static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) +{ + CPpmd_State tmp = *t1; + *t1 = *t2; + *t2 = tmp; +} + +static CPpmd_Void_Ref CutOff(CPpmd8 *p, CTX_PTR ctx, unsigned order) +{ + int i; + unsigned tmp; + CPpmd_State *s; + + if (!ctx->NumStats) + { + s = ONE_STATE(ctx); + if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart) + { + if (order < p->MaxOrder) + SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); + else + SetSuccessor(s, 0); + if (SUCCESSOR(s) || order <= 9) /* O_BOUND */ + return REF(ctx); + } + SpecialFreeUnit(p, ctx); + return 0; + } + + ctx->Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), tmp = ((unsigned)ctx->NumStats + 2) >> 1)); + + for (s = STATS(ctx) + (i = ctx->NumStats); s >= STATS(ctx); s--) + if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) < p->UnitsStart) + { + CPpmd_State *s2 = STATS(ctx) + (i--); + SetSuccessor(s, 0); + SwapStates(s, s2); + } + else if (order < p->MaxOrder) + SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); + else + SetSuccessor(s, 0); + + if (i != ctx->NumStats && order) + { + ctx->NumStats = (Byte)i; + s = STATS(ctx); + if (i < 0) + { + FreeUnits(p, s, tmp); + SpecialFreeUnit(p, ctx); + return 0; + } + if (i == 0) + { + ctx->Flags = (Byte)((ctx->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40)); + *ONE_STATE(ctx) = *s; + FreeUnits(p, s, tmp); + /* 9.31: the code was fixed. It's was not BUG, if Freq <= MAX_FREQ = 124 */ + ONE_STATE(ctx)->Freq = (Byte)(((unsigned)ONE_STATE(ctx)->Freq + 11) >> 3); + } + else + Refresh(p, ctx, tmp, ctx->SummFreq > 16 * i); + } + return REF(ctx); +} + +#ifdef PPMD8_FREEZE_SUPPORT +static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, CTX_PTR ctx, unsigned order) +{ + CPpmd_State *s; + if (!ctx->NumStats) + { + s = ONE_STATE(ctx); + if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder) + SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1)); + else + SetSuccessor(s, 0); + /* Suffix context can be removed already, since different (high-order) + Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */ + if (!SUCCESSOR(s) && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF)) + { + FreeUnits(p, ctx, 1); + return 0; + } + else + return REF(ctx); + } + + for (s = STATS(ctx) + ctx->NumStats; s >= STATS(ctx); s--) + if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder) + SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1)); + else + SetSuccessor(s, 0); + + return REF(ctx); +} +#endif + +static UInt32 GetUsedMemory(const CPpmd8 *p) +{ + UInt32 v = 0; + unsigned i; + for (i = 0; i < PPMD_NUM_INDEXES; i++) + v += p->Stamps[i] * I2U(i); + return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v); +} + +#ifdef PPMD8_FREEZE_SUPPORT + #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor) +#else + #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1) +#endif + +static void RestoreModel(CPpmd8 *p, CTX_PTR c1 + #ifdef PPMD8_FREEZE_SUPPORT + , CTX_PTR fSuccessor + #endif + ) +{ + CTX_PTR c; + CPpmd_State *s; + RESET_TEXT(0); + for (c = p->MaxContext; c != c1; c = SUFFIX(c)) + if (--(c->NumStats) == 0) + { + s = STATS(c); + c->Flags = (Byte)((c->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40)); + *ONE_STATE(c) = *s; + SpecialFreeUnit(p, s); + ONE_STATE(c)->Freq = (Byte)(((unsigned)ONE_STATE(c)->Freq + 11) >> 3); + } + else + Refresh(p, c, (c->NumStats+3) >> 1, 0); + + for (; c != p->MinContext; c = SUFFIX(c)) + if (!c->NumStats) + ONE_STATE(c)->Freq = (Byte)(ONE_STATE(c)->Freq - (ONE_STATE(c)->Freq >> 1)); + else if ((c->SummFreq += 4) > 128 + 4 * c->NumStats) + Refresh(p, c, (c->NumStats + 2) >> 1, 1); + + #ifdef PPMD8_FREEZE_SUPPORT + if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + p->MaxContext = fSuccessor; + p->GlueCount += !(p->Stamps[1] & 1); + } + else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE) + { + while (p->MaxContext->Suffix) + p->MaxContext = SUFFIX(p->MaxContext); + RemoveBinContexts(p, p->MaxContext, 0); + p->RestoreMethod++; + p->GlueCount = 0; + p->OrderFall = p->MaxOrder; + } + else + #endif + if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1)) + RestartModel(p); + else + { + while (p->MaxContext->Suffix) + p->MaxContext = SUFFIX(p->MaxContext); + do + { + CutOff(p, p->MaxContext, 0); + ExpandTextArea(p); + } + while (GetUsedMemory(p) > 3 * (p->Size >> 2)); + p->GlueCount = 0; + p->OrderFall = p->MaxOrder; + } +} + +static CTX_PTR CreateSuccessors(CPpmd8 *p, BoolInt skip, CPpmd_State *s1, CTX_PTR c) +{ + CPpmd_State upState; + Byte flags; + CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); + /* fixed over Shkarin's code. Maybe it could work without + 1 too. */ + CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; + unsigned numPs = 0; + + if (!skip) + ps[numPs++] = p->FoundState; + + while (c->Suffix) + { + CPpmd_Void_Ref successor; + CPpmd_State *s; + c = SUFFIX(c); + if (s1) + { + s = s1; + s1 = NULL; + } + else if (c->NumStats != 0) + { + for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); + if (s->Freq < MAX_FREQ - 9) + { + s->Freq++; + c->SummFreq++; + } + } + else + { + s = ONE_STATE(c); + s->Freq = (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; + } + + upState.Symbol = *(const Byte *)Ppmd8_GetPtr(p, upBranch); + SetSuccessor(&upState, upBranch + 1); + flags = (Byte)(0x10 * (p->FoundState->Symbol >= 0x40) + 0x08 * (upState.Symbol >= 0x40)); + + if (c->NumStats == 0) + upState.Freq = ONE_STATE(c)->Freq; + else + { + UInt32 cf, s0; + CPpmd_State *s; + for (s = STATS(c); s->Symbol != upState.Symbol; s++); + cf = s->Freq - 1; + s0 = c->SummFreq - c->NumStats - cf; + upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0))); + } + + do + { + /* Create Child */ + CTX_PTR c1; /* = AllocContext(p); */ + if (p->HiUnit != p->LoUnit) + c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); + else if (p->FreeList[0] != 0) + c1 = (CTX_PTR)RemoveNode(p, 0); + else + { + c1 = (CTX_PTR)AllocUnitsRare(p, 0); + if (!c1) + return NULL; + } + c1->NumStats = 0; + c1->Flags = flags; + *ONE_STATE(c1) = upState; + c1->Suffix = REF(c); + SetSuccessor(ps[--numPs], REF(c1)); + c = c1; + } + while (numPs != 0); + + return c; +} + +static CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, CTX_PTR c) +{ + CPpmd_State *s = NULL; + CTX_PTR c1 = c; + CPpmd_Void_Ref upBranch = REF(p->Text); + + #ifdef PPMD8_FREEZE_SUPPORT + /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */ + CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; + unsigned numPs = 0; + ps[numPs++] = p->FoundState; + #endif + + SetSuccessor(p->FoundState, upBranch); + p->OrderFall++; + + for (;;) + { + if (s1) + { + c = SUFFIX(c); + s = s1; + s1 = NULL; + } + else + { + if (!c->Suffix) + { + #ifdef PPMD8_FREEZE_SUPPORT + if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); + RESET_TEXT(1); + p->OrderFall = 1; + } + #endif + return c; + } + c = SUFFIX(c); + if (c->NumStats) + { + if ((s = STATS(c))->Symbol != p->FoundState->Symbol) + do { s++; } while (s->Symbol != p->FoundState->Symbol); + if (s->Freq < MAX_FREQ - 9) + { + s->Freq += 2; + c->SummFreq += 2; + } + } + else + { + s = ONE_STATE(c); + s->Freq = (Byte)(s->Freq + (s->Freq < 32)); + } + } + if (SUCCESSOR(s)) + break; + #ifdef PPMD8_FREEZE_SUPPORT + ps[numPs++] = s; + #endif + SetSuccessor(s, upBranch); + p->OrderFall++; + } + + #ifdef PPMD8_FREEZE_SUPPORT + if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + c = CTX(SUCCESSOR(s)); + do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); + RESET_TEXT(1); + p->OrderFall = 1; + return c; + } + else + #endif + if (SUCCESSOR(s) <= upBranch) + { + CTX_PTR successor; + CPpmd_State *s2 = p->FoundState; + p->FoundState = s; + + successor = CreateSuccessors(p, False, NULL, c); + if (successor == NULL) + SetSuccessor(s, 0); + else + SetSuccessor(s, REF(successor)); + p->FoundState = s2; + } + + if (p->OrderFall == 1 && c1 == p->MaxContext) + { + SetSuccessor(p->FoundState, SUCCESSOR(s)); + p->Text--; + } + if (SUCCESSOR(s) == 0) + return NULL; + return CTX(SUCCESSOR(s)); +} + +static void UpdateModel(CPpmd8 *p) +{ + CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); + CTX_PTR c; + unsigned s0, ns, fFreq = p->FoundState->Freq; + Byte flag, fSymbol = p->FoundState->Symbol; + CPpmd_State *s = NULL; + + if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) + { + c = SUFFIX(p->MinContext); + + if (c->NumStats == 0) + { + s = ONE_STATE(c); + if (s->Freq < 32) + s->Freq++; + } + else + { + s = STATS(c); + if (s->Symbol != p->FoundState->Symbol) + { + do { s++; } while (s->Symbol != p->FoundState->Symbol); + if (s[0].Freq >= s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + s--; + } + } + if (s->Freq < MAX_FREQ - 9) + { + s->Freq += 2; + c->SummFreq += 2; + } + } + } + + c = p->MaxContext; + if (p->OrderFall == 0 && fSuccessor) + { + CTX_PTR cs = CreateSuccessors(p, True, s, p->MinContext); + if (cs == 0) + { + SetSuccessor(p->FoundState, 0); + RESTORE_MODEL(c, CTX(fSuccessor)); + } + else + { + SetSuccessor(p->FoundState, REF(cs)); + p->MaxContext = cs; + } + return; + } + + *p->Text++ = p->FoundState->Symbol; + successor = REF(p->Text); + if (p->Text >= p->UnitsStart) + { + RESTORE_MODEL(c, CTX(fSuccessor)); /* check it */ + return; + } + + if (!fSuccessor) + { + CTX_PTR cs = ReduceOrder(p, s, p->MinContext); + if (cs == NULL) + { + RESTORE_MODEL(c, 0); + return; + } + fSuccessor = REF(cs); + } + else if ((Byte *)Ppmd8_GetPtr(p, fSuccessor) < p->UnitsStart) + { + CTX_PTR cs = CreateSuccessors(p, False, s, p->MinContext); + if (cs == NULL) + { + RESTORE_MODEL(c, 0); + return; + } + fSuccessor = REF(cs); + } + + if (--p->OrderFall == 0) + { + successor = fSuccessor; + p->Text -= (p->MaxContext != p->MinContext); + } + #ifdef PPMD8_FREEZE_SUPPORT + else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + successor = fSuccessor; + RESET_TEXT(0); + p->OrderFall = 0; + } + #endif + + s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - fFreq; + flag = (Byte)(0x08 * (fSymbol >= 0x40)); + + for (; c != p->MinContext; c = SUFFIX(c)) + { + unsigned ns1; + UInt32 cf, sf; + if ((ns1 = c->NumStats) != 0) + { + if ((ns1 & 1) != 0) + { + /* Expand for one UNIT */ + unsigned oldNU = (ns1 + 1) >> 1; + unsigned i = U2I(oldNU); + if (i != U2I((size_t)oldNU + 1)) + { + void *ptr = AllocUnits(p, i + 1); + void *oldPtr; + if (!ptr) + { + RESTORE_MODEL(c, CTX(fSuccessor)); + return; + } + oldPtr = STATS(c); + MyMem12Cpy(ptr, oldPtr, oldNU); + InsertNode(p, oldPtr, i); + c->Stats = STATS_REF(ptr); + } + } + c->SummFreq = (UInt16)(c->SummFreq + (3 * ns1 + 1 < ns)); + } + else + { + CPpmd_State *s2 = (CPpmd_State*)AllocUnits(p, 0); + if (!s2) + { + RESTORE_MODEL(c, CTX(fSuccessor)); + return; + } + *s2 = *ONE_STATE(c); + c->Stats = REF(s2); + if (s2->Freq < MAX_FREQ / 4 - 1) + s2->Freq <<= 1; + else + s2->Freq = MAX_FREQ - 4; + c->SummFreq = (UInt16)(s2->Freq + p->InitEsc + (ns > 2)); + } + cf = 2 * fFreq * (c->SummFreq + 6); + sf = (UInt32)s0 + c->SummFreq; + if (cf < 6 * sf) + { + cf = 1 + (cf > sf) + (cf >= 4 * sf); + c->SummFreq += 4; + } + else + { + cf = 4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf); + c->SummFreq = (UInt16)(c->SummFreq + cf); + } + { + CPpmd_State *s2 = STATS(c) + ns1 + 1; + SetSuccessor(s2, successor); + s2->Symbol = fSymbol; + s2->Freq = (Byte)cf; + c->Flags |= flag; + c->NumStats = (Byte)(ns1 + 1); + } + } + p->MaxContext = p->MinContext = CTX(fSuccessor); +} + +static void Rescale(CPpmd8 *p) +{ + unsigned i, adder, sumFreq, escFreq; + CPpmd_State *stats = STATS(p->MinContext); + CPpmd_State *s = p->FoundState; + { + CPpmd_State tmp = *s; + for (; s != stats; s--) + s[0] = s[-1]; + *s = tmp; + } + escFreq = p->MinContext->SummFreq - s->Freq; + s->Freq += 4; + adder = (p->OrderFall != 0 + #ifdef PPMD8_FREEZE_SUPPORT + || p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE + #endif + ); + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq = s->Freq; + + i = p->MinContext->NumStats; + do + { + escFreq -= (++s)->Freq; + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq += s->Freq; + if (s[0].Freq > s[-1].Freq) + { + CPpmd_State *s1 = s; + CPpmd_State tmp = *s1; + do + s1[0] = s1[-1]; + while (--s1 != stats && tmp.Freq > s1[-1].Freq); + *s1 = tmp; + } + } + while (--i); + + if (s->Freq == 0) + { + unsigned numStats = p->MinContext->NumStats; + unsigned n0, n1; + do { i++; } while ((--s)->Freq == 0); + escFreq += i; + p->MinContext->NumStats = (Byte)(p->MinContext->NumStats - i); + if (p->MinContext->NumStats == 0) + { + CPpmd_State tmp = *stats; + tmp.Freq = (Byte)((2 * tmp.Freq + escFreq - 1) / escFreq); + if (tmp.Freq > MAX_FREQ / 3) + tmp.Freq = MAX_FREQ / 3; + InsertNode(p, stats, U2I((numStats + 2) >> 1)); + p->MinContext->Flags = (Byte)((p->MinContext->Flags & 0x10) + 0x08 * (tmp.Symbol >= 0x40)); + *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; + return; + } + n0 = (numStats + 2) >> 1; + n1 = (p->MinContext->NumStats + 2) >> 1; + if (n0 != n1) + p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + p->MinContext->Flags &= ~0x08; + p->MinContext->Flags |= 0x08 * ((s = STATS(p->MinContext))->Symbol >= 0x40); + i = p->MinContext->NumStats; + do { p->MinContext->Flags |= 0x08*((++s)->Symbol >= 0x40); } while (--i); + } + p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); + p->MinContext->Flags |= 0x4; + p->FoundState = STATS(p->MinContext); +} + +CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq) +{ + CPpmd_See *see; + if (p->MinContext->NumStats != 0xFF) + { + see = p->See[(size_t)(unsigned)p->NS2Indx[(size_t)(unsigned)p->MinContext->NumStats + 2] - 3] + + (p->MinContext->SummFreq > 11 * ((unsigned)p->MinContext->NumStats + 1)) + + 2 * (unsigned)(2 * (unsigned)p->MinContext->NumStats < + ((unsigned)SUFFIX(p->MinContext)->NumStats + numMasked1)) + + p->MinContext->Flags; + { + unsigned r = (see->Summ >> see->Shift); + see->Summ = (UInt16)(see->Summ - r); + *escFreq = r + (r == 0); + } + } + else + { + see = &p->DummySee; + *escFreq = 1; + } + return see; +} + +static void NextContext(CPpmd8 *p) +{ + CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); + if (p->OrderFall == 0 && (Byte *)c >= p->UnitsStart) + p->MinContext = p->MaxContext = c; + else + { + UpdateModel(p); + p->MinContext = p->MaxContext; + } +} + +void Ppmd8_Update1(CPpmd8 *p) +{ + CPpmd_State *s = p->FoundState; + s->Freq += 4; + p->MinContext->SummFreq += 4; + if (s[0].Freq > s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + p->FoundState = --s; + if (s->Freq > MAX_FREQ) + Rescale(p); + } + NextContext(p); +} + +void Ppmd8_Update1_0(CPpmd8 *p) +{ + p->PrevSuccess = (2 * p->FoundState->Freq >= p->MinContext->SummFreq); + p->RunLength += p->PrevSuccess; + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + NextContext(p); +} + +void Ppmd8_UpdateBin(CPpmd8 *p) +{ + p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 196)); + p->PrevSuccess = 1; + p->RunLength++; + NextContext(p); +} + +void Ppmd8_Update2(CPpmd8 *p) +{ + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + p->RunLength = p->InitRL; + UpdateModel(p); + p->MinContext = p->MaxContext; +} + +/* H->I changes: + NS2Indx + GlewCount, and Glue method + BinSum + See / EscFreq + CreateSuccessors updates more suffix contexts + UpdateModel consts. + PrevSuccess Update +*/ diff --git a/C/Ppmd8.h b/C/Ppmd8.h index ecaa8bacc..51c497dcf 100644 --- a/C/Ppmd8.h +++ b/C/Ppmd8.h @@ -1,137 +1,137 @@ -/* Ppmd8.h -- PPMdI codec -2018-07-04 : Igor Pavlov : Public domain -This code is based on: - PPMd var.I (2002): Dmitry Shkarin : Public domain - Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ - -#ifndef __PPMD8_H -#define __PPMD8_H - -#include "Ppmd.h" - -EXTERN_C_BEGIN - -#define PPMD8_MIN_ORDER 2 -#define PPMD8_MAX_ORDER 16 - -struct CPpmd8_Context_; - -typedef - #ifdef PPMD_32BIT - struct CPpmd8_Context_ * - #else - UInt32 - #endif - CPpmd8_Context_Ref; - -#pragma pack(push, 1) - -typedef struct CPpmd8_Context_ -{ - Byte NumStats; - Byte Flags; - UInt16 SummFreq; - CPpmd_State_Ref Stats; - CPpmd8_Context_Ref Suffix; -} CPpmd8_Context; - -#pragma pack(pop) - -#define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) - -/* The BUG in Shkarin's code for FREEZE mode was fixed, but that fixed - code is not compatible with original code for some files compressed - in FREEZE mode. So we disable FREEZE mode support. */ - -enum -{ - PPMD8_RESTORE_METHOD_RESTART, - PPMD8_RESTORE_METHOD_CUT_OFF - #ifdef PPMD8_FREEZE_SUPPORT - , PPMD8_RESTORE_METHOD_FREEZE - #endif -}; - -typedef struct -{ - CPpmd8_Context *MinContext, *MaxContext; - CPpmd_State *FoundState; - unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder; - Int32 RunLength, InitRL; /* must be 32-bit at least */ - - UInt32 Size; - UInt32 GlueCount; - Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; - UInt32 AlignOffset; - unsigned RestoreMethod; - - /* Range Coder */ - UInt32 Range; - UInt32 Code; - UInt32 Low; - union - { - IByteIn *In; - IByteOut *Out; - } Stream; - - Byte Indx2Units[PPMD_NUM_INDEXES]; - Byte Units2Indx[128]; - CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; - UInt32 Stamps[PPMD_NUM_INDEXES]; - - Byte NS2BSIndx[256], NS2Indx[260]; - CPpmd_See DummySee, See[24][32]; - UInt16 BinSumm[25][64]; -} CPpmd8; - -void Ppmd8_Construct(CPpmd8 *p); -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 ---------- */ - -extern const Byte PPMD8_kExpEscape[16]; - -#ifdef PPMD_32BIT - #define Ppmd8_GetPtr(p, ptr) (ptr) - #define Ppmd8_GetContext(p, ptr) (ptr) - #define Ppmd8_GetStats(p, ctx) ((ctx)->Stats) -#else - #define Ppmd8_GetPtr(p, offs) ((void *)((p)->Base + (offs))) - #define Ppmd8_GetContext(p, offs) ((CPpmd8_Context *)Ppmd8_GetPtr((p), (offs))) - #define Ppmd8_GetStats(p, ctx) ((CPpmd_State *)Ppmd8_GetPtr((p), ((ctx)->Stats))) -#endif - -void Ppmd8_Update1(CPpmd8 *p); -void Ppmd8_Update1_0(CPpmd8 *p); -void Ppmd8_Update2(CPpmd8 *p); -void Ppmd8_UpdateBin(CPpmd8 *p); - -#define Ppmd8_GetBinSumm(p) \ - &p->BinSumm[p->NS2Indx[(size_t)Ppmd8Context_OneState(p->MinContext)->Freq - 1]][ \ - p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \ - p->PrevSuccess + p->MinContext->Flags + ((p->RunLength >> 26) & 0x20)] - -CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale); - - -/* ---------- Decode ---------- */ - -BoolInt Ppmd8_RangeDec_Init(CPpmd8 *p); -#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0) -int Ppmd8_DecodeSymbol(CPpmd8 *p); /* returns: -1 as EndMarker, -2 as DataError */ - - -/* ---------- Encode ---------- */ - -#define Ppmd8_RangeEnc_Init(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; } -void Ppmd8_RangeEnc_FlushData(CPpmd8 *p); -void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); /* symbol = -1 means EndMarker */ - -EXTERN_C_END - -#endif +/* Ppmd8.h -- PPMdI codec +2018-07-04 : Igor Pavlov : Public domain +This code is based on: + PPMd var.I (2002): Dmitry Shkarin : Public domain + Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#ifndef __PPMD8_H +#define __PPMD8_H + +#include "Ppmd.h" + +EXTERN_C_BEGIN + +#define PPMD8_MIN_ORDER 2 +#define PPMD8_MAX_ORDER 16 + +struct CPpmd8_Context_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd8_Context_ * + #else + UInt32 + #endif + CPpmd8_Context_Ref; + +#pragma pack(push, 1) + +typedef struct CPpmd8_Context_ +{ + Byte NumStats; + Byte Flags; + UInt16 SummFreq; + CPpmd_State_Ref Stats; + CPpmd8_Context_Ref Suffix; +} CPpmd8_Context; + +#pragma pack(pop) + +#define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) + +/* The BUG in Shkarin's code for FREEZE mode was fixed, but that fixed + code is not compatible with original code for some files compressed + in FREEZE mode. So we disable FREEZE mode support. */ + +enum +{ + PPMD8_RESTORE_METHOD_RESTART, + PPMD8_RESTORE_METHOD_CUT_OFF + #ifdef PPMD8_FREEZE_SUPPORT + , PPMD8_RESTORE_METHOD_FREEZE + #endif +}; + +typedef struct +{ + CPpmd8_Context *MinContext, *MaxContext; + CPpmd_State *FoundState; + unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder; + Int32 RunLength, InitRL; /* must be 32-bit at least */ + + UInt32 Size; + UInt32 GlueCount; + Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; + UInt32 AlignOffset; + unsigned RestoreMethod; + + /* Range Coder */ + UInt32 Range; + UInt32 Code; + UInt32 Low; + union + { + IByteIn *In; + IByteOut *Out; + } Stream; + + Byte Indx2Units[PPMD_NUM_INDEXES]; + Byte Units2Indx[128]; + CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; + UInt32 Stamps[PPMD_NUM_INDEXES]; + + Byte NS2BSIndx[256], NS2Indx[260]; + CPpmd_See DummySee, See[24][32]; + UInt16 BinSumm[25][64]; +} CPpmd8; + +void Ppmd8_Construct(CPpmd8 *p); +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 ---------- */ + +extern const Byte PPMD8_kExpEscape[16]; + +#ifdef PPMD_32BIT + #define Ppmd8_GetPtr(p, ptr) (ptr) + #define Ppmd8_GetContext(p, ptr) (ptr) + #define Ppmd8_GetStats(p, ctx) ((ctx)->Stats) +#else + #define Ppmd8_GetPtr(p, offs) ((void *)((p)->Base + (offs))) + #define Ppmd8_GetContext(p, offs) ((CPpmd8_Context *)Ppmd8_GetPtr((p), (offs))) + #define Ppmd8_GetStats(p, ctx) ((CPpmd_State *)Ppmd8_GetPtr((p), ((ctx)->Stats))) +#endif + +void Ppmd8_Update1(CPpmd8 *p); +void Ppmd8_Update1_0(CPpmd8 *p); +void Ppmd8_Update2(CPpmd8 *p); +void Ppmd8_UpdateBin(CPpmd8 *p); + +#define Ppmd8_GetBinSumm(p) \ + &p->BinSumm[p->NS2Indx[(size_t)Ppmd8Context_OneState(p->MinContext)->Freq - 1]][ \ + p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \ + p->PrevSuccess + p->MinContext->Flags + ((p->RunLength >> 26) & 0x20)] + +CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale); + + +/* ---------- Decode ---------- */ + +BoolInt Ppmd8_RangeDec_Init(CPpmd8 *p); +#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0) +int Ppmd8_DecodeSymbol(CPpmd8 *p); /* returns: -1 as EndMarker, -2 as DataError */ + + +/* ---------- Encode ---------- */ + +#define Ppmd8_RangeEnc_Init(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; } +void Ppmd8_RangeEnc_FlushData(CPpmd8 *p); +void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); /* symbol = -1 means EndMarker */ + +EXTERN_C_END + +#endif diff --git a/C/Ppmd8Dec.c b/C/Ppmd8Dec.c index 05c78c50f..a18ec677b 100644 --- a/C/Ppmd8Dec.c +++ b/C/Ppmd8Dec.c @@ -1,157 +1,157 @@ -/* Ppmd8Dec.c -- PPMdI Decoder -2018-07-04 : 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 (1 << 24) -#define kBot (1 << 15) - -BoolInt Ppmd8_RangeDec_Init(CPpmd8 *p) -{ - unsigned i; - p->Low = 0; - p->Range = 0xFFFFFFFF; - p->Code = 0; - for (i = 0; i < 4; i++) - p->Code = (p->Code << 8) | IByteIn_Read(p->Stream.In); - return (p->Code < 0xFFFFFFFF); -} - -static UInt32 RangeDec_GetThreshold(CPpmd8 *p, UInt32 total) -{ - return p->Code / (p->Range /= total); -} - -static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size) -{ - start *= p->Range; - p->Low += start; - p->Code -= start; - p->Range *= size; - - while ((p->Low ^ (p->Low + p->Range)) < kTop || - (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) - { - p->Code = (p->Code << 8) | IByteIn_Read(p->Stream.In); - p->Range <<= 8; - p->Low <<= 8; - } -} - -#define MASK(sym) ((signed char *)charMask)[sym] - -int Ppmd8_DecodeSymbol(CPpmd8 *p) -{ - size_t charMask[256 / sizeof(size_t)]; - if (p->MinContext->NumStats != 0) - { - CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); - unsigned i; - UInt32 count, hiCnt; - if ((count = RangeDec_GetThreshold(p, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) - { - Byte symbol; - RangeDec_Decode(p, 0, s->Freq); - p->FoundState = s; - symbol = s->Symbol; - Ppmd8_Update1_0(p); - return symbol; - } - p->PrevSuccess = 0; - i = p->MinContext->NumStats; - do - { - if ((hiCnt += (++s)->Freq) > count) - { - Byte symbol; - RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); - p->FoundState = s; - symbol = s->Symbol; - Ppmd8_Update1(p); - return symbol; - } - } - while (--i); - if (count >= p->MinContext->SummFreq) - return -2; - RangeDec_Decode(p, hiCnt, p->MinContext->SummFreq - hiCnt); - PPMD_SetAllBitsIn256Bytes(charMask); - MASK(s->Symbol) = 0; - i = p->MinContext->NumStats; - do { MASK((--s)->Symbol) = 0; } while (--i); - } - else - { - UInt16 *prob = Ppmd8_GetBinSumm(p); - if (((p->Code / (p->Range >>= 14)) < *prob)) - { - Byte symbol; - RangeDec_Decode(p, 0, *prob); - *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); - symbol = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol; - Ppmd8_UpdateBin(p); - return symbol; - } - RangeDec_Decode(p, *prob, (1 << 14) - *prob); - *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); - p->InitEsc = PPMD8_kExpEscape[*prob >> 10]; - PPMD_SetAllBitsIn256Bytes(charMask); - MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0; - p->PrevSuccess = 0; - } - for (;;) - { - CPpmd_State *ps[256], *s; - UInt32 freqSum, count, hiCnt; - CPpmd_See *see; - unsigned i, num, numMasked = p->MinContext->NumStats; - do - { - p->OrderFall++; - if (!p->MinContext->Suffix) - return -1; - p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix); - } - while (p->MinContext->NumStats == numMasked); - hiCnt = 0; - s = Ppmd8_GetStats(p, p->MinContext); - i = 0; - num = p->MinContext->NumStats - numMasked; - do - { - int k = (int)(MASK(s->Symbol)); - hiCnt += (s->Freq & k); - ps[i] = s++; - i -= k; - } - while (i != num); - - see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum); - freqSum += hiCnt; - count = RangeDec_GetThreshold(p, freqSum); - - if (count < hiCnt) - { - Byte symbol; - CPpmd_State **pps = ps; - for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); - s = *pps; - RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); - Ppmd_See_Update(see); - p->FoundState = s; - symbol = s->Symbol; - Ppmd8_Update2(p); - return symbol; - } - if (count >= freqSum) - return -2; - RangeDec_Decode(p, hiCnt, freqSum - hiCnt); - see->Summ = (UInt16)(see->Summ + freqSum); - do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); - } -} +/* Ppmd8Dec.c -- PPMdI Decoder +2018-07-04 : 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 (1 << 24) +#define kBot (1 << 15) + +BoolInt Ppmd8_RangeDec_Init(CPpmd8 *p) +{ + unsigned i; + p->Low = 0; + p->Range = 0xFFFFFFFF; + p->Code = 0; + for (i = 0; i < 4; i++) + p->Code = (p->Code << 8) | IByteIn_Read(p->Stream.In); + return (p->Code < 0xFFFFFFFF); +} + +static UInt32 RangeDec_GetThreshold(CPpmd8 *p, UInt32 total) +{ + return p->Code / (p->Range /= total); +} + +static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size) +{ + start *= p->Range; + p->Low += start; + p->Code -= start; + p->Range *= size; + + while ((p->Low ^ (p->Low + p->Range)) < kTop || + (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) + { + p->Code = (p->Code << 8) | IByteIn_Read(p->Stream.In); + p->Range <<= 8; + p->Low <<= 8; + } +} + +#define MASK(sym) ((signed char *)charMask)[sym] + +int Ppmd8_DecodeSymbol(CPpmd8 *p) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 0) + { + CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); + unsigned i; + UInt32 count, hiCnt; + if ((count = RangeDec_GetThreshold(p, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) + { + Byte symbol; + RangeDec_Decode(p, 0, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd8_Update1_0(p); + return symbol; + } + p->PrevSuccess = 0; + i = p->MinContext->NumStats; + do + { + if ((hiCnt += (++s)->Freq) > count) + { + Byte symbol; + RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd8_Update1(p); + return symbol; + } + } + while (--i); + if (count >= p->MinContext->SummFreq) + return -2; + RangeDec_Decode(p, hiCnt, p->MinContext->SummFreq - hiCnt); + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats; + do { MASK((--s)->Symbol) = 0; } while (--i); + } + else + { + UInt16 *prob = Ppmd8_GetBinSumm(p); + if (((p->Code / (p->Range >>= 14)) < *prob)) + { + Byte symbol; + RangeDec_Decode(p, 0, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + symbol = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol; + Ppmd8_UpdateBin(p); + return symbol; + } + RangeDec_Decode(p, *prob, (1 << 14) - *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD8_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0; + p->PrevSuccess = 0; + } + for (;;) + { + CPpmd_State *ps[256], *s; + UInt32 freqSum, count, hiCnt; + CPpmd_See *see; + unsigned i, num, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return -1; + p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + hiCnt = 0; + s = Ppmd8_GetStats(p, p->MinContext); + i = 0; + num = p->MinContext->NumStats - numMasked; + do + { + int k = (int)(MASK(s->Symbol)); + hiCnt += (s->Freq & k); + ps[i] = s++; + i -= k; + } + while (i != num); + + see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum); + freqSum += hiCnt; + count = RangeDec_GetThreshold(p, freqSum); + + if (count < hiCnt) + { + Byte symbol; + CPpmd_State **pps = ps; + for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); + s = *pps; + RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); + Ppmd_See_Update(see); + p->FoundState = s; + symbol = s->Symbol; + Ppmd8_Update2(p); + return symbol; + } + if (count >= freqSum) + return -2; + RangeDec_Decode(p, hiCnt, freqSum - hiCnt); + see->Summ = (UInt16)(see->Summ + freqSum); + do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); + } +} diff --git a/C/Ppmd8Enc.c b/C/Ppmd8Enc.c index aae01d7bb..1cbc17f1a 100644 --- a/C/Ppmd8Enc.c +++ b/C/Ppmd8Enc.c @@ -1,163 +1,163 @@ -/* Ppmd8Enc.c -- PPMdI Encoder -2017-04-03 : 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 (1 << 24) -#define kBot (1 << 15) - -void Ppmd8_RangeEnc_FlushData(CPpmd8 *p) -{ - unsigned i; - for (i = 0; i < 4; i++, p->Low <<= 8 ) - IByteOut_Write(p->Stream.Out, (Byte)(p->Low >> 24)); -} - -static void RangeEnc_Normalize(CPpmd8 *p) -{ - while ((p->Low ^ (p->Low + p->Range)) < kTop || - (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) - { - IByteOut_Write(p->Stream.Out, (Byte)(p->Low >> 24)); - p->Range <<= 8; - p->Low <<= 8; - } -} - -static void RangeEnc_Encode(CPpmd8 *p, UInt32 start, UInt32 size, UInt32 total) -{ - p->Low += start * (p->Range /= total); - p->Range *= size; - RangeEnc_Normalize(p); -} - -static void RangeEnc_EncodeBit_0(CPpmd8 *p, UInt32 size0) -{ - p->Range >>= 14; - p->Range *= size0; - RangeEnc_Normalize(p); -} - -static void RangeEnc_EncodeBit_1(CPpmd8 *p, UInt32 size0) -{ - p->Low += size0 * (p->Range >>= 14); - p->Range *= ((1 << 14) - size0); - RangeEnc_Normalize(p); -} - - -#define MASK(sym) ((signed char *)charMask)[sym] - -void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol) -{ - size_t charMask[256 / sizeof(size_t)]; - if (p->MinContext->NumStats != 0) - { - CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); - UInt32 sum; - unsigned i; - if (s->Symbol == symbol) - { - RangeEnc_Encode(p, 0, s->Freq, p->MinContext->SummFreq); - p->FoundState = s; - Ppmd8_Update1_0(p); - return; - } - p->PrevSuccess = 0; - sum = s->Freq; - i = p->MinContext->NumStats; - do - { - if ((++s)->Symbol == symbol) - { - RangeEnc_Encode(p, sum, s->Freq, p->MinContext->SummFreq); - p->FoundState = s; - Ppmd8_Update1(p); - return; - } - sum += s->Freq; - } - while (--i); - - PPMD_SetAllBitsIn256Bytes(charMask); - MASK(s->Symbol) = 0; - i = p->MinContext->NumStats; - do { MASK((--s)->Symbol) = 0; } while (--i); - RangeEnc_Encode(p, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq); - } - else - { - UInt16 *prob = Ppmd8_GetBinSumm(p); - CPpmd_State *s = Ppmd8Context_OneState(p->MinContext); - if (s->Symbol == symbol) - { - RangeEnc_EncodeBit_0(p, *prob); - *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); - p->FoundState = s; - Ppmd8_UpdateBin(p); - return; - } - else - { - RangeEnc_EncodeBit_1(p, *prob); - *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); - p->InitEsc = PPMD8_kExpEscape[*prob >> 10]; - PPMD_SetAllBitsIn256Bytes(charMask); - MASK(s->Symbol) = 0; - p->PrevSuccess = 0; - } - } - for (;;) - { - UInt32 escFreq; - CPpmd_See *see; - CPpmd_State *s; - UInt32 sum; - unsigned i, numMasked = p->MinContext->NumStats; - do - { - p->OrderFall++; - if (!p->MinContext->Suffix) - return; /* EndMarker (symbol = -1) */ - p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix); - } - while (p->MinContext->NumStats == numMasked); - - see = Ppmd8_MakeEscFreq(p, numMasked, &escFreq); - s = Ppmd8_GetStats(p, p->MinContext); - sum = 0; - i = p->MinContext->NumStats + 1; - do - { - int cur = s->Symbol; - if (cur == symbol) - { - UInt32 low = sum; - CPpmd_State *s1 = s; - do - { - sum += (s->Freq & (int)(MASK(s->Symbol))); - s++; - } - while (--i); - RangeEnc_Encode(p, low, s1->Freq, sum + escFreq); - Ppmd_See_Update(see); - p->FoundState = s1; - Ppmd8_Update2(p); - return; - } - sum += (s->Freq & (int)(MASK(cur))); - MASK(cur) = 0; - s++; - } - while (--i); - - RangeEnc_Encode(p, sum, escFreq, sum + escFreq); - see->Summ = (UInt16)(see->Summ + sum + escFreq); - } -} +/* Ppmd8Enc.c -- PPMdI Encoder +2017-04-03 : 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 (1 << 24) +#define kBot (1 << 15) + +void Ppmd8_RangeEnc_FlushData(CPpmd8 *p) +{ + unsigned i; + for (i = 0; i < 4; i++, p->Low <<= 8 ) + IByteOut_Write(p->Stream.Out, (Byte)(p->Low >> 24)); +} + +static void RangeEnc_Normalize(CPpmd8 *p) +{ + while ((p->Low ^ (p->Low + p->Range)) < kTop || + (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) + { + IByteOut_Write(p->Stream.Out, (Byte)(p->Low >> 24)); + p->Range <<= 8; + p->Low <<= 8; + } +} + +static void RangeEnc_Encode(CPpmd8 *p, UInt32 start, UInt32 size, UInt32 total) +{ + p->Low += start * (p->Range /= total); + p->Range *= size; + RangeEnc_Normalize(p); +} + +static void RangeEnc_EncodeBit_0(CPpmd8 *p, UInt32 size0) +{ + p->Range >>= 14; + p->Range *= size0; + RangeEnc_Normalize(p); +} + +static void RangeEnc_EncodeBit_1(CPpmd8 *p, UInt32 size0) +{ + p->Low += size0 * (p->Range >>= 14); + p->Range *= ((1 << 14) - size0); + RangeEnc_Normalize(p); +} + + +#define MASK(sym) ((signed char *)charMask)[sym] + +void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 0) + { + CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); + UInt32 sum; + unsigned i; + if (s->Symbol == symbol) + { + RangeEnc_Encode(p, 0, s->Freq, p->MinContext->SummFreq); + p->FoundState = s; + Ppmd8_Update1_0(p); + return; + } + p->PrevSuccess = 0; + sum = s->Freq; + i = p->MinContext->NumStats; + do + { + if ((++s)->Symbol == symbol) + { + RangeEnc_Encode(p, sum, s->Freq, p->MinContext->SummFreq); + p->FoundState = s; + Ppmd8_Update1(p); + return; + } + sum += s->Freq; + } + while (--i); + + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats; + do { MASK((--s)->Symbol) = 0; } while (--i); + RangeEnc_Encode(p, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq); + } + else + { + UInt16 *prob = Ppmd8_GetBinSumm(p); + CPpmd_State *s = Ppmd8Context_OneState(p->MinContext); + if (s->Symbol == symbol) + { + RangeEnc_EncodeBit_0(p, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + p->FoundState = s; + Ppmd8_UpdateBin(p); + return; + } + else + { + RangeEnc_EncodeBit_1(p, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD8_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + p->PrevSuccess = 0; + } + } + for (;;) + { + UInt32 escFreq; + CPpmd_See *see; + CPpmd_State *s; + UInt32 sum; + unsigned i, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return; /* EndMarker (symbol = -1) */ + p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + + see = Ppmd8_MakeEscFreq(p, numMasked, &escFreq); + s = Ppmd8_GetStats(p, p->MinContext); + sum = 0; + i = p->MinContext->NumStats + 1; + do + { + int cur = s->Symbol; + if (cur == symbol) + { + UInt32 low = sum; + CPpmd_State *s1 = s; + do + { + sum += (s->Freq & (int)(MASK(s->Symbol))); + s++; + } + while (--i); + RangeEnc_Encode(p, low, s1->Freq, sum + escFreq); + Ppmd_See_Update(see); + p->FoundState = s1; + Ppmd8_Update2(p); + return; + } + sum += (s->Freq & (int)(MASK(cur))); + MASK(cur) = 0; + s++; + } + while (--i); + + RangeEnc_Encode(p, sum, escFreq, sum + escFreq); + see->Summ = (UInt16)(see->Summ + sum + escFreq); + } +} diff --git a/C/Precomp.h b/C/Precomp.h index edb581443..e8ff8b40e 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 +2013-11-12 : Igor Pavlov : Public domain */ + +#ifndef __7Z_PRECOMP_H +#define __7Z_PRECOMP_H + +#include "Compiler.h" +/* #include "7zTypes.h" */ + +#endif diff --git a/C/RotateDefs.h b/C/RotateDefs.h index 6c790e791..8f01d1a6c 100644 --- a/C/RotateDefs.h +++ b/C/RotateDefs.h @@ -1,30 +1,30 @@ -/* RotateDefs.h -- Rotate functions -2015-03-25 : Igor Pavlov : Public domain */ - -#ifndef __ROTATE_DEFS_H -#define __ROTATE_DEFS_H - -#ifdef _MSC_VER - -#include - -/* 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 +2015-03-25 : Igor Pavlov : Public domain */ + +#ifndef __ROTATE_DEFS_H +#define __ROTATE_DEFS_H + +#ifdef _MSC_VER + +#include + +/* 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 diff --git a/C/Sha1.c b/C/Sha1.c index bedbc20de..96b5e7870 100644 --- a/C/Sha1.c +++ b/C/Sha1.c @@ -1,340 +1,340 @@ -/* Sha1.c -- SHA-1 Hash -2017-04-03 : 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 - -#include "CpuArch.h" -#include "RotateDefs.h" -#include "Sha1.h" - -// define it for speed optimization -// #define _SHA1_UNROLL - -#ifdef _SHA1_UNROLL - #define kNumW 16 - #define WW(i) W[(i)&15] -#else - #define kNumW 80 - #define WW(i) W[i] -#endif - -#define w0(i) (W[i] = data[i]) - -#define w1(i) (WW(i) = rotlFixed(WW((i)-3) ^ WW((i)-8) ^ WW((i)-14) ^ WW((i)-16), 1)) - -#define f1(x,y,z) (z^(x&(y^z))) -#define f2(x,y,z) (x^y^z) -#define f3(x,y,z) ((x&y)|(z&(x|y))) -#define f4(x,y,z) (x^y^z) - -#define RK(a,b,c,d,e, fx, w, k) e += fx(b,c,d) + w + k + rotlFixed(a,5); b = rotlFixed(b,30); - -#define R0(a,b,c,d,e, i) RK(a,b,c,d,e, f1, w0(i), 0x5A827999) -#define R1(a,b,c,d,e, i) RK(a,b,c,d,e, f1, w1(i), 0x5A827999) -#define R2(a,b,c,d,e, i) RK(a,b,c,d,e, f2, w1(i), 0x6ED9EBA1) -#define R3(a,b,c,d,e, i) RK(a,b,c,d,e, f3, w1(i), 0x8F1BBCDC) -#define R4(a,b,c,d,e, i) RK(a,b,c,d,e, f4, w1(i), 0xCA62C1D6) - -#define RX_1_4(rx1, rx4, i) \ - rx1(a,b,c,d,e, i); \ - rx4(e,a,b,c,d, i+1); \ - rx4(d,e,a,b,c, i+2); \ - rx4(c,d,e,a,b, i+3); \ - rx4(b,c,d,e,a, i+4); \ - -#define RX_5(rx, i) RX_1_4(rx, rx, i); - -#ifdef _SHA1_UNROLL - - #define RX_15 \ - RX_5(R0, 0); \ - RX_5(R0, 5); \ - RX_5(R0, 10); - - #define RX_20(rx, i) \ - RX_5(rx, i); \ - RX_5(rx, i + 5); \ - RX_5(rx, i + 10); \ - RX_5(rx, i + 15); - -#else - -#define RX_15 { size_t i; for (i = 0; i < 15; i += 5) { RX_5(R0, i); } } -#define RX_20(rx, ii) { size_t i; i = ii; for (; i < ii + 20; i += 5) { RX_5(rx, i); } } - -#endif - - -void Sha1_Init(CSha1 *p) -{ - p->state[0] = 0x67452301; - p->state[1] = 0xEFCDAB89; - p->state[2] = 0x98BADCFE; - p->state[3] = 0x10325476; - p->state[4] = 0xC3D2E1F0; - p->count = 0; -} - -void Sha1_GetBlockDigest(CSha1 *p, const UInt32 *data, UInt32 *destDigest) -{ - UInt32 a, b, c, d, e; - UInt32 W[kNumW]; - - a = p->state[0]; - b = p->state[1]; - c = p->state[2]; - d = p->state[3]; - e = p->state[4]; - - RX_15 - - RX_1_4(R0, R1, 15); - - RX_20(R2, 20); - RX_20(R3, 40); - RX_20(R4, 60); - - destDigest[0] = p->state[0] + a; - destDigest[1] = p->state[1] + b; - destDigest[2] = p->state[2] + c; - destDigest[3] = p->state[3] + d; - destDigest[4] = p->state[4] + e; -} - -void Sha1_UpdateBlock_Rar(CSha1 *p, UInt32 *data, int returnRes) -{ - UInt32 a, b, c, d, e; - UInt32 W[kNumW]; - - a = p->state[0]; - b = p->state[1]; - c = p->state[2]; - d = p->state[3]; - e = p->state[4]; - - RX_15 - - RX_1_4(R0, R1, 15); - - RX_20(R2, 20); - RX_20(R3, 40); - RX_20(R4, 60); - - p->state[0] += a; - p->state[1] += b; - p->state[2] += c; - p->state[3] += d; - p->state[4] += e; - - if (returnRes) - { - size_t i; - for (i = 0 ; i < SHA1_NUM_BLOCK_WORDS; i++) - data[i] = W[kNumW - SHA1_NUM_BLOCK_WORDS + i]; - } -} - -#define Sha1_UpdateBlock(p) Sha1_GetBlockDigest(p, p->buffer, p->state) - -void Sha1_Update(CSha1 *p, const Byte *data, size_t size) -{ - unsigned pos, pos2; - if (size == 0) - return; - pos = (unsigned)p->count & 0x3F; - p->count += size; - pos2 = pos & 3; - pos >>= 2; - - if (pos2 != 0) - { - UInt32 w; - pos2 = (3 - pos2) * 8; - w = ((UInt32)*data++) << pos2; - if (--size && pos2) - { - pos2 -= 8; - w |= ((UInt32)*data++) << pos2; - if (--size && pos2) - { - pos2 -= 8; - w |= ((UInt32)*data++) << pos2; - size--; - } - } - p->buffer[pos] |= w; - if (pos2 == 0) - pos++; - } - - for (;;) - { - if (pos == SHA1_NUM_BLOCK_WORDS) - { - for (;;) - { - size_t i; - Sha1_UpdateBlock(p); - if (size < SHA1_BLOCK_SIZE) - break; - size -= SHA1_BLOCK_SIZE; - for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i += 2) - { - p->buffer[i ] = GetBe32(data); - p->buffer[i + 1] = GetBe32(data + 4); - data += 8; - } - } - pos = 0; - } - if (size < 4) - break; - - p->buffer[pos] = GetBe32(data); - data += 4; - size -= 4; - pos++; - } - - if (size != 0) - { - UInt32 w = ((UInt32)data[0]) << 24; - if (size > 1) - { - w |= ((UInt32)data[1]) << 16; - if (size > 2) - w |= ((UInt32)data[2]) << 8; - } - p->buffer[pos] = w; - } -} - -void Sha1_Update_Rar(CSha1 *p, Byte *data, size_t size /* , int rar350Mode */) -{ - int returnRes = False; - - unsigned pos = (unsigned)p->count & 0x3F; - p->count += size; - - while (size--) - { - unsigned pos2 = (pos & 3); - UInt32 v = ((UInt32)*data++) << (8 * (3 - pos2)); - UInt32 *ref = &(p->buffer[pos >> 2]); - pos++; - if (pos2 == 0) - { - *ref = v; - continue; - } - *ref |= v; - - if (pos == SHA1_BLOCK_SIZE) - { - pos = 0; - Sha1_UpdateBlock_Rar(p, p->buffer, returnRes); - if (returnRes) - { - size_t i; - for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++) - { - UInt32 d = p->buffer[i]; - Byte *prev = data + i * 4 - SHA1_BLOCK_SIZE; - SetUi32(prev, d); - } - } - // returnRes = rar350Mode; - returnRes = True; - } - } -} - -void Sha1_Final(CSha1 *p, Byte *digest) -{ - unsigned pos = (unsigned)p->count & 0x3F; - unsigned pos2 = (pos & 3); - UInt64 numBits; - UInt32 w; - unsigned i; - - pos >>= 2; - - w = 0; - if (pos2 != 0) - w = p->buffer[pos]; - p->buffer[pos++] = w | (((UInt32)0x80000000) >> (8 * pos2)); - - while (pos != (SHA1_NUM_BLOCK_WORDS - 2)) - { - pos &= 0xF; - if (pos == 0) - Sha1_UpdateBlock(p); - p->buffer[pos++] = 0; - } - - numBits = (p->count << 3); - p->buffer[SHA1_NUM_BLOCK_WORDS - 2] = (UInt32)(numBits >> 32); - p->buffer[SHA1_NUM_BLOCK_WORDS - 1] = (UInt32)(numBits); - Sha1_UpdateBlock(p); - - for (i = 0; i < SHA1_NUM_DIGEST_WORDS; i++) - { - UInt32 v = p->state[i]; - SetBe32(digest, v); - digest += 4; - } - - Sha1_Init(p); -} - - -void Sha1_32_PrepareBlock(const CSha1 *p, UInt32 *block, unsigned size) -{ - const UInt64 numBits = (p->count + size) << 5; - block[SHA1_NUM_BLOCK_WORDS - 2] = (UInt32)(numBits >> 32); - block[SHA1_NUM_BLOCK_WORDS - 1] = (UInt32)(numBits); - block[size++] = 0x80000000; - while (size != (SHA1_NUM_BLOCK_WORDS - 2)) - block[size++] = 0; -} - -void Sha1_32_Update(CSha1 *p, const UInt32 *data, size_t size) -{ - unsigned pos = (unsigned)p->count & 0xF; - p->count += size; - while (size--) - { - p->buffer[pos++] = *data++; - if (pos == SHA1_NUM_BLOCK_WORDS) - { - pos = 0; - Sha1_UpdateBlock(p); - } - } -} - -void Sha1_32_Final(CSha1 *p, UInt32 *digest) -{ - UInt64 numBits; - unsigned pos = (unsigned)p->count & 0xF; - p->buffer[pos++] = 0x80000000; - - while (pos != (SHA1_NUM_BLOCK_WORDS - 2)) - { - pos &= 0xF; - if (pos == 0) - Sha1_UpdateBlock(p); - p->buffer[pos++] = 0; - } - - numBits = (p->count << 5); - p->buffer[SHA1_NUM_BLOCK_WORDS - 2] = (UInt32)(numBits >> 32); - p->buffer[SHA1_NUM_BLOCK_WORDS - 1] = (UInt32)(numBits); - - Sha1_GetBlockDigest(p, p->buffer, digest); - - Sha1_Init(p); -} +/* Sha1.c -- SHA-1 Hash +2017-04-03 : 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 + +#include "CpuArch.h" +#include "RotateDefs.h" +#include "Sha1.h" + +// define it for speed optimization +// #define _SHA1_UNROLL + +#ifdef _SHA1_UNROLL + #define kNumW 16 + #define WW(i) W[(i)&15] +#else + #define kNumW 80 + #define WW(i) W[i] +#endif + +#define w0(i) (W[i] = data[i]) + +#define w1(i) (WW(i) = rotlFixed(WW((i)-3) ^ WW((i)-8) ^ WW((i)-14) ^ WW((i)-16), 1)) + +#define f1(x,y,z) (z^(x&(y^z))) +#define f2(x,y,z) (x^y^z) +#define f3(x,y,z) ((x&y)|(z&(x|y))) +#define f4(x,y,z) (x^y^z) + +#define RK(a,b,c,d,e, fx, w, k) e += fx(b,c,d) + w + k + rotlFixed(a,5); b = rotlFixed(b,30); + +#define R0(a,b,c,d,e, i) RK(a,b,c,d,e, f1, w0(i), 0x5A827999) +#define R1(a,b,c,d,e, i) RK(a,b,c,d,e, f1, w1(i), 0x5A827999) +#define R2(a,b,c,d,e, i) RK(a,b,c,d,e, f2, w1(i), 0x6ED9EBA1) +#define R3(a,b,c,d,e, i) RK(a,b,c,d,e, f3, w1(i), 0x8F1BBCDC) +#define R4(a,b,c,d,e, i) RK(a,b,c,d,e, f4, w1(i), 0xCA62C1D6) + +#define RX_1_4(rx1, rx4, i) \ + rx1(a,b,c,d,e, i); \ + rx4(e,a,b,c,d, i+1); \ + rx4(d,e,a,b,c, i+2); \ + rx4(c,d,e,a,b, i+3); \ + rx4(b,c,d,e,a, i+4); \ + +#define RX_5(rx, i) RX_1_4(rx, rx, i); + +#ifdef _SHA1_UNROLL + + #define RX_15 \ + RX_5(R0, 0); \ + RX_5(R0, 5); \ + RX_5(R0, 10); + + #define RX_20(rx, i) \ + RX_5(rx, i); \ + RX_5(rx, i + 5); \ + RX_5(rx, i + 10); \ + RX_5(rx, i + 15); + +#else + +#define RX_15 { size_t i; for (i = 0; i < 15; i += 5) { RX_5(R0, i); } } +#define RX_20(rx, ii) { size_t i; i = ii; for (; i < ii + 20; i += 5) { RX_5(rx, i); } } + +#endif + + +void Sha1_Init(CSha1 *p) +{ + p->state[0] = 0x67452301; + p->state[1] = 0xEFCDAB89; + p->state[2] = 0x98BADCFE; + p->state[3] = 0x10325476; + p->state[4] = 0xC3D2E1F0; + p->count = 0; +} + +void Sha1_GetBlockDigest(CSha1 *p, const UInt32 *data, UInt32 *destDigest) +{ + UInt32 a, b, c, d, e; + UInt32 W[kNumW]; + + a = p->state[0]; + b = p->state[1]; + c = p->state[2]; + d = p->state[3]; + e = p->state[4]; + + RX_15 + + RX_1_4(R0, R1, 15); + + RX_20(R2, 20); + RX_20(R3, 40); + RX_20(R4, 60); + + destDigest[0] = p->state[0] + a; + destDigest[1] = p->state[1] + b; + destDigest[2] = p->state[2] + c; + destDigest[3] = p->state[3] + d; + destDigest[4] = p->state[4] + e; +} + +void Sha1_UpdateBlock_Rar(CSha1 *p, UInt32 *data, int returnRes) +{ + UInt32 a, b, c, d, e; + UInt32 W[kNumW]; + + a = p->state[0]; + b = p->state[1]; + c = p->state[2]; + d = p->state[3]; + e = p->state[4]; + + RX_15 + + RX_1_4(R0, R1, 15); + + RX_20(R2, 20); + RX_20(R3, 40); + RX_20(R4, 60); + + p->state[0] += a; + p->state[1] += b; + p->state[2] += c; + p->state[3] += d; + p->state[4] += e; + + if (returnRes) + { + size_t i; + for (i = 0 ; i < SHA1_NUM_BLOCK_WORDS; i++) + data[i] = W[kNumW - SHA1_NUM_BLOCK_WORDS + i]; + } +} + +#define Sha1_UpdateBlock(p) Sha1_GetBlockDigest(p, p->buffer, p->state) + +void Sha1_Update(CSha1 *p, const Byte *data, size_t size) +{ + unsigned pos, pos2; + if (size == 0) + return; + pos = (unsigned)p->count & 0x3F; + p->count += size; + pos2 = pos & 3; + pos >>= 2; + + if (pos2 != 0) + { + UInt32 w; + pos2 = (3 - pos2) * 8; + w = ((UInt32)*data++) << pos2; + if (--size && pos2) + { + pos2 -= 8; + w |= ((UInt32)*data++) << pos2; + if (--size && pos2) + { + pos2 -= 8; + w |= ((UInt32)*data++) << pos2; + size--; + } + } + p->buffer[pos] |= w; + if (pos2 == 0) + pos++; + } + + for (;;) + { + if (pos == SHA1_NUM_BLOCK_WORDS) + { + for (;;) + { + size_t i; + Sha1_UpdateBlock(p); + if (size < SHA1_BLOCK_SIZE) + break; + size -= SHA1_BLOCK_SIZE; + for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i += 2) + { + p->buffer[i ] = GetBe32(data); + p->buffer[i + 1] = GetBe32(data + 4); + data += 8; + } + } + pos = 0; + } + if (size < 4) + break; + + p->buffer[pos] = GetBe32(data); + data += 4; + size -= 4; + pos++; + } + + if (size != 0) + { + UInt32 w = ((UInt32)data[0]) << 24; + if (size > 1) + { + w |= ((UInt32)data[1]) << 16; + if (size > 2) + w |= ((UInt32)data[2]) << 8; + } + p->buffer[pos] = w; + } +} + +void Sha1_Update_Rar(CSha1 *p, Byte *data, size_t size /* , int rar350Mode */) +{ + int returnRes = False; + + unsigned pos = (unsigned)p->count & 0x3F; + p->count += size; + + while (size--) + { + unsigned pos2 = (pos & 3); + UInt32 v = ((UInt32)*data++) << (8 * (3 - pos2)); + UInt32 *ref = &(p->buffer[pos >> 2]); + pos++; + if (pos2 == 0) + { + *ref = v; + continue; + } + *ref |= v; + + if (pos == SHA1_BLOCK_SIZE) + { + pos = 0; + Sha1_UpdateBlock_Rar(p, p->buffer, returnRes); + if (returnRes) + { + size_t i; + for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++) + { + UInt32 d = p->buffer[i]; + Byte *prev = data + i * 4 - SHA1_BLOCK_SIZE; + SetUi32(prev, d); + } + } + // returnRes = rar350Mode; + returnRes = True; + } + } +} + +void Sha1_Final(CSha1 *p, Byte *digest) +{ + unsigned pos = (unsigned)p->count & 0x3F; + unsigned pos2 = (pos & 3); + UInt64 numBits; + UInt32 w; + unsigned i; + + pos >>= 2; + + w = 0; + if (pos2 != 0) + w = p->buffer[pos]; + p->buffer[pos++] = w | (((UInt32)0x80000000) >> (8 * pos2)); + + while (pos != (SHA1_NUM_BLOCK_WORDS - 2)) + { + pos &= 0xF; + if (pos == 0) + Sha1_UpdateBlock(p); + p->buffer[pos++] = 0; + } + + numBits = (p->count << 3); + p->buffer[SHA1_NUM_BLOCK_WORDS - 2] = (UInt32)(numBits >> 32); + p->buffer[SHA1_NUM_BLOCK_WORDS - 1] = (UInt32)(numBits); + Sha1_UpdateBlock(p); + + for (i = 0; i < SHA1_NUM_DIGEST_WORDS; i++) + { + UInt32 v = p->state[i]; + SetBe32(digest, v); + digest += 4; + } + + Sha1_Init(p); +} + + +void Sha1_32_PrepareBlock(const CSha1 *p, UInt32 *block, unsigned size) +{ + const UInt64 numBits = (p->count + size) << 5; + block[SHA1_NUM_BLOCK_WORDS - 2] = (UInt32)(numBits >> 32); + block[SHA1_NUM_BLOCK_WORDS - 1] = (UInt32)(numBits); + block[size++] = 0x80000000; + while (size != (SHA1_NUM_BLOCK_WORDS - 2)) + block[size++] = 0; +} + +void Sha1_32_Update(CSha1 *p, const UInt32 *data, size_t size) +{ + unsigned pos = (unsigned)p->count & 0xF; + p->count += size; + while (size--) + { + p->buffer[pos++] = *data++; + if (pos == SHA1_NUM_BLOCK_WORDS) + { + pos = 0; + Sha1_UpdateBlock(p); + } + } +} + +void Sha1_32_Final(CSha1 *p, UInt32 *digest) +{ + UInt64 numBits; + unsigned pos = (unsigned)p->count & 0xF; + p->buffer[pos++] = 0x80000000; + + while (pos != (SHA1_NUM_BLOCK_WORDS - 2)) + { + pos &= 0xF; + if (pos == 0) + Sha1_UpdateBlock(p); + p->buffer[pos++] = 0; + } + + numBits = (p->count << 5); + p->buffer[SHA1_NUM_BLOCK_WORDS - 2] = (UInt32)(numBits >> 32); + p->buffer[SHA1_NUM_BLOCK_WORDS - 1] = (UInt32)(numBits); + + Sha1_GetBlockDigest(p, p->buffer, digest); + + Sha1_Init(p); +} diff --git a/C/Sha1.h b/C/Sha1.h index 9d1f16da9..aa22ec36a 100644 --- a/C/Sha1.h +++ b/C/Sha1.h @@ -1,38 +1,38 @@ -/* Sha1.h -- SHA-1 Hash -2016-05-20 : Igor Pavlov : Public domain */ - -#ifndef __7Z_SHA1_H -#define __7Z_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 struct -{ - UInt32 state[SHA1_NUM_DIGEST_WORDS]; - UInt64 count; - UInt32 buffer[SHA1_NUM_BLOCK_WORDS]; -} CSha1; - -void Sha1_Init(CSha1 *p); - -void Sha1_GetBlockDigest(CSha1 *p, const UInt32 *data, UInt32 *destDigest); -void Sha1_Update(CSha1 *p, const Byte *data, size_t size); -void Sha1_Final(CSha1 *p, Byte *digest); - -void Sha1_Update_Rar(CSha1 *p, Byte *data, size_t size /* , int rar350Mode */); - -void Sha1_32_PrepareBlock(const CSha1 *p, UInt32 *block, unsigned size); -void Sha1_32_Update(CSha1 *p, const UInt32 *data, size_t size); -void Sha1_32_Final(CSha1 *p, UInt32 *digest); - -EXTERN_C_END - -#endif +/* Sha1.h -- SHA-1 Hash +2016-05-20 : Igor Pavlov : Public domain */ + +#ifndef __7Z_SHA1_H +#define __7Z_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 struct +{ + UInt32 state[SHA1_NUM_DIGEST_WORDS]; + UInt64 count; + UInt32 buffer[SHA1_NUM_BLOCK_WORDS]; +} CSha1; + +void Sha1_Init(CSha1 *p); + +void Sha1_GetBlockDigest(CSha1 *p, const UInt32 *data, UInt32 *destDigest); +void Sha1_Update(CSha1 *p, const Byte *data, size_t size); +void Sha1_Final(CSha1 *p, Byte *digest); + +void Sha1_Update_Rar(CSha1 *p, Byte *data, size_t size /* , int rar350Mode */); + +void Sha1_32_PrepareBlock(const CSha1 *p, UInt32 *block, unsigned size); +void Sha1_32_Update(CSha1 *p, const UInt32 *data, size_t size); +void Sha1_32_Final(CSha1 *p, UInt32 *digest); + +EXTERN_C_END + +#endif diff --git a/C/Sha256.c b/C/Sha256.c index 90994e5ab..04b688c6b 100644 --- a/C/Sha256.c +++ b/C/Sha256.c @@ -1,248 +1,248 @@ -/* 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 - -#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); -} +/* 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 + +#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); +} diff --git a/C/Sha256.h b/C/Sha256.h index 7f17ccf9c..3f455dbc0 100644 --- a/C/Sha256.h +++ b/C/Sha256.h @@ -1,26 +1,26 @@ -/* 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 +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 diff --git a/C/Sort.c b/C/Sort.c index 73dcbf059..e1097e380 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 7209d7824..2e2963a23 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 +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 diff --git a/C/Threads.c b/C/Threads.c index 8fd86f224..930ad271b 100644 --- a/C/Threads.c +++ b/C/Threads.c @@ -1,95 +1,95 @@ -/* Threads.c -- multithreading library -2017-06-26 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#ifndef UNDER_CE -#include -#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 +2017-06-26 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#ifndef UNDER_CE +#include +#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; +} diff --git a/C/Threads.h b/C/Threads.h index f913241ae..e53ace435 100644 --- a/C/Threads.h +++ b/C/Threads.h @@ -1,68 +1,68 @@ -/* Threads.h -- multithreading library -2017-06-18 : Igor Pavlov : Public domain */ - -#ifndef __7Z_THREADS_H -#define __7Z_THREADS_H - -#ifdef _WIN32 -#include -#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 +2017-06-18 : Igor Pavlov : Public domain */ + +#ifndef __7Z_THREADS_H +#define __7Z_THREADS_H + +#ifdef _WIN32 +#include +#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 diff --git a/C/Util/7z/7z.dsp b/C/Util/7z/7z.dsp index d3bf0fe00..be0f0a743 100644 --- a/C/Util/7z/7z.dsp +++ b/C/Util/7z/7z.dsp @@ -1,241 +1,241 @@ -# 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" /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 diff --git a/C/Util/7z/7z.dsw b/C/Util/7z/7z.dsw index 23089fb79..848d13cb1 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 1c02b48ec..6ccc83052 100644 --- a/C/Util/7z/7zMain.c +++ b/C/Util/7z/7zMain.c @@ -1,686 +1,686 @@ -/* 7zMain.c - Test application for 7z Decoder -2019-02-02 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include -#include - -#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 -#else -#include -#include -#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 \n\n" - "\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 +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include +#include + +#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 +#else +#include +#include +#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 \n\n" + "\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; +} diff --git a/C/Util/7z/Precomp.c b/C/Util/7z/Precomp.c index 34b60f8fc..01605e3c2 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 9f398d08f..588a66f7e 100644 --- a/C/Util/7z/Precomp.h +++ b/C/Util/7z/Precomp.h @@ -1,10 +1,10 @@ -/* 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 +2013-06-16 : Igor Pavlov : Public domain */ + +#ifndef __7Z_PRECOMP_H +#define __7Z_PRECOMP_H + +#include "../../Compiler.h" +#include "../../7zTypes.h" + +#endif diff --git a/C/Util/7z/makefile b/C/Util/7z/makefile index f4a54af73..9a49fd515 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) -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) diff --git a/C/Util/7z/makefile.gcc b/C/Util/7z/makefile.gcc index f707935aa..51053bad6 100644 --- a/C/Util/7z/makefile.gcc +++ b/C/Util/7z/makefile.gcc @@ -1,75 +1,75 @@ -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 +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) diff --git a/C/Util/7zipInstall/7zipInstall.c b/C/Util/7zipInstall/7zipInstall.c index bc0e3c6c2..8dbfcf171 100644 --- a/C/Util/7zipInstall/7zipInstall.c +++ b/C/Util/7zipInstall/7zipInstall.c @@ -1,1598 +1,1598 @@ -/* 7zipInstall.c - 7-Zip Installer -2019-02-19 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#define SZ_ERROR_ABORT 100 - -#ifdef _MSC_VER -#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union -#endif - -#include -#include - -#define LLL_(quote) L##quote -#define LLL(quote) LLL_(quote) - -#include "../../7z.h" -#include "../../7zAlloc.h" -#include "../../7zCrc.h" -#include "../../7zFile.h" -#include "../../7zVersion.h" -#include "../../CpuArch.h" -#include "../../DllSecur.h" - -#include "resource.h" - - -#define wcscat lstrcatW -#define wcslen lstrlenW -#define wcscpy lstrcpyW -#define wcsncpy lstrcpynW - - -#define kInputBufSize ((size_t)1 << 18) - - -#define _7ZIP_CUR_VER ((MY_VER_MAJOR << 16) | MY_VER_MINOR) -#define _7ZIP_DLL_VER_COMPAT ((16 << 16) | 3) - -static LPCWSTR const k_7zip = L"7-Zip-Zstandard"; - -static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip-Zstandard"; - -// #define _64BIT_INSTALLER 1 - -#ifdef _WIN64 - #define _64BIT_INSTALLER 1 -#endif - -#define k_7zip_with_Ver_base L"7-Zip ZS " LLL(MY_VERSION) - -#ifdef _64BIT_INSTALLER - #define k_7zip_with_Ver k_7zip_with_Ver_base L" (x64)" -#else - #define k_7zip_with_Ver k_7zip_with_Ver_base -#endif - -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 _64BIT_INSTALLER - L"64" - #else - L"32" - #endif - ; - -#if defined(_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-20BB-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 path[MAX_PATH * 2 + 40]; - - -#define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) -= 0x20 : (c))) - -static void PrintErrorMessage(const char *s) -{ - WCHAR s2[256 + 4]; - unsigned i; - for (i = 0; i < 256; i++) - { - Byte b = s[i]; - if (b == 0) - break; - s2[i] = b; - } - s2[i] = 0; - MessageBoxW(g_HWND, s2, k_7zip_with_Ver_str, MB_ICONERROR); -} - - -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)GetProcAddress(g_version_dll_hModule, "GetFileVersionInfoSizeW"); - my_GetFileVersionInfoW = (Func_GetFileVersionInfoW)GetProcAddress(g_version_dll_hModule, "GetFileVersionInfoW"); - my_VerQueryValueW = (Func_VerQueryValueW)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() -{ - 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); - { - 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 = pos; - } - } - - for (;;) - { - int pos; - wres = MyCreateDir(s); - if (wres == 0) - break; - if (wres == ERROR_ALREADY_EXISTS) - { - 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 (;;) - { - 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; - LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, (DWORD *)&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; - LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key); - if (res != ERROR_SUCCESS) - return False; - { - 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 _64BIT_INSTALLER - -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 - -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++) - { - 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++) - { - Byte 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-Zstandard")) - return; - wcscat(s, L"7-Zip-Zstandard\\"); -} - - -static int Install(); - -static void OnClose() -{ - 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 INT_PTR 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)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() -{ - 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 - - // wcscpy(link, L"\\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); - wcscat(link, k_7zip); - // wcscat(link, L"2"); - - if (i != 0) - MyCreateDir(link); - - NormalizePrefix(link); - - { - unsigned baseLen = (unsigned)wcslen(link); - unsigned k; - - for (k = 0; k < 2; k++) - { - wcscpy(link + baseLen, k == 0 ? - L"7-Zip File Manager.lnk" : - L"7-Zip Help.lnk" - ); - wcscpy(destPath, path); - wcscat(destPath, k == 0 ? - L"7zFM.exe" : - L"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() -{ - HKEY destKey; - LONG res; - - #ifdef _64BIT_INSTALLER - - 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 + 10]; - wcscpy(destPath, path); - wcscat(destPath, L"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 + 10]; - wcscpy(destPath, path); - wcscat(destPath, L"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 LPCWSTR const k_ShellEx_Items[] = -{ - L"*\\shellex\\ContextMenuHandlers" - , L"Directory\\shellex\\ContextMenuHandlers" - , L"Folder\\shellex\\ContextMenuHandlers" - , L"Directory\\shellex\\DragDropHandlers" - , L"Drive\\shellex\\DragDropHandlers" -}; - -static void WriteShellEx() -{ - unsigned i; - WCHAR destPath[MAX_PATH + 40]; - - for (i = 0; i < sizeof(k_ShellEx_Items) / sizeof(k_ShellEx_Items[0]); i++) - { - wcscpy(destPath, k_ShellEx_Items[i]); - wcscat(destPath, L"\\7-Zip-Zstandard"); - - #ifdef _64BIT_INSTALLER - MyRegistry_CreateKeyAndVal_32(HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID); - #endif - MyRegistry_CreateKeyAndVal (HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID); - } - - #ifdef _64BIT_INSTALLER - 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); - - - { - HKEY destKey = 0; - LONG res = MyRegistry_CreateKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe", &destKey); - if (res == ERROR_SUCCESS) - { - wcscpy(destPath, path); - wcscat(destPath, L"7zFM.exe"); - - 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-Zstandard", &destKey); - if (res == ERROR_SUCCESS) - { - // wcscpy(destPath, path); - // wcscat(destPath, L"7zFM.exe"); - 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); - - wcscpy(destPath, path); - MyRegistry_SetString(destKey, L"InstallLocation", destPath); - wcscat(destPath, L"Uninstall.exe"); - // wcscat(destPath, L"\""); - MyRegistry_SetString(destKey, L"UninstallString", 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) -{ - BoolInt quoteMode = False; - for (;; s++) - { - wchar_t c = *s; - if (c == L'\"') - quoteMode = !quoteMode; - else if (c == 0 || (c == L' ' && !quoteMode)) - 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 (;;) - { - { - wchar_t c = *s; - if (c == 0) - break; - if (c == ' ') - { - s++; - continue; - } - } - - { - const wchar_t *s2 = GetCmdParam(s); - if (s[0] == '/') - { - if (s[1] == 'S' && IS_LIMIT_CHAR(s[2])) - g_SilentMode = True; - else if (s[1] == 'D' && s[2] == '=') - { - size_t num; - s += 3; - num = s2 - s; - if (num > MAX_PATH) - num = MAX_PATH; - wcsncpy(path, s, (unsigned)num); - RemoveQuotes(path); - } - } - s = s2; - } - } - } - - #if defined(_64BIT_INSTALLER) && !defined(_WIN64) - { - BOOL isWow64 = FALSE; - Func_IsWow64Process func_IsWow64Process = (Func_IsWow64Process) - GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "IsWow64Process"); - - if (func_IsWow64Process) - func_IsWow64Process(GetCurrentProcess(), &isWow64); - - if (!isWow64) - { - if (!g_SilentMode) - PrintErrorMessage("This installation requires Windows x64"); - return 1; - } - } - #endif - - - 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); - } - - // ok = False; - if (!ok) - { - /* - #ifdef UNDER_CE - wcscpy(path, L"\\Program Files\\"); - #else - - #ifdef _64BIT_INSTALLER - { - DWORD ttt = GetEnvironmentVariableW(L"ProgramW6432", path, MAX_PATH); - if (ttt == 0 || ttt > MAX_PATH) - wcscpy(path, L"C:\\"); - } - #else - if (!SHGetSpecialFolderPathW(0, path, CSIDL_PROGRAM_FILES, FALSE)) - wcscpy(path, L"C:\\"); - #endif - #endif - */ - if (!MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion", L"ProgramFilesDir", path)) - wcscpy(path, - #ifdef UNDER_CE - L"\\Program Files\\" - #else - L"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; - - { - 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)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() -{ - 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; - - { - 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; - - { - // Remove post spaces - unsigned endPos = 0; - unsigned i = 0; - - for (;;) - { - wchar_t c = path[i++]; - if (c == 0) - break; - if (c != ' ') - endPos = i; - } - - path[endPos] = 0; - } - - 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); - } - - { - 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); - wcscat(path, L".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 _64BIT_INSTALLER - || FindSubString(temp, "7-zip32.dll") - #endif - ) - { - DWORD ver = GetFileVersion(path); - fileLevel = ((ver < _7ZIP_DLL_VER_COMPAT || ver > _7ZIP_CUR_VER) ? 2 : 1); - tempIndex++; - continue; - } - - if (g_SilentMode) - { - tempIndex++; - continue; - } - { - WCHAR message[MAX_PATH * 3 + 100]; - int mbRes; - - wcscpy(message, L"Can't open file\n"); - wcscat(message, path); - wcscat(message, L"\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 - - { - SRes 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); - MessageBoxW(g_HWND, m, k_7zip_with_Ver_str, MB_ICONERROR); - } - 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); - } - } - - return 1; -} +/* 7zipInstall.c - 7-Zip Installer +2019-02-19 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#define SZ_ERROR_ABORT 100 + +#ifdef _MSC_VER +#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union +#endif + +#include +#include + +#define LLL_(quote) L##quote +#define LLL(quote) LLL_(quote) + +#include "../../7z.h" +#include "../../7zAlloc.h" +#include "../../7zCrc.h" +#include "../../7zFile.h" +#include "../../7zVersion.h" +#include "../../CpuArch.h" +#include "../../DllSecur.h" + +#include "resource.h" + + +#define wcscat lstrcatW +#define wcslen lstrlenW +#define wcscpy lstrcpyW +#define wcsncpy lstrcpynW + + +#define kInputBufSize ((size_t)1 << 18) + + +#define _7ZIP_CUR_VER ((MY_VER_MAJOR << 16) | MY_VER_MINOR) +#define _7ZIP_DLL_VER_COMPAT ((16 << 16) | 3) + +static LPCWSTR const k_7zip = L"7-Zip-Zstandard"; + +static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip-Zstandard"; + +// #define _64BIT_INSTALLER 1 + +#ifdef _WIN64 + #define _64BIT_INSTALLER 1 +#endif + +#define k_7zip_with_Ver_base L"7-Zip ZS " LLL(MY_VERSION) + +#ifdef _64BIT_INSTALLER + #define k_7zip_with_Ver k_7zip_with_Ver_base L" (x64)" +#else + #define k_7zip_with_Ver k_7zip_with_Ver_base +#endif + +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 _64BIT_INSTALLER + L"64" + #else + L"32" + #endif + ; + +#if defined(_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-20BB-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 path[MAX_PATH * 2 + 40]; + + +#define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) -= 0x20 : (c))) + +static void PrintErrorMessage(const char *s) +{ + WCHAR s2[256 + 4]; + unsigned i; + for (i = 0; i < 256; i++) + { + Byte b = s[i]; + if (b == 0) + break; + s2[i] = b; + } + s2[i] = 0; + MessageBoxW(g_HWND, s2, k_7zip_with_Ver_str, MB_ICONERROR); +} + + +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)GetProcAddress(g_version_dll_hModule, "GetFileVersionInfoSizeW"); + my_GetFileVersionInfoW = (Func_GetFileVersionInfoW)GetProcAddress(g_version_dll_hModule, "GetFileVersionInfoW"); + my_VerQueryValueW = (Func_VerQueryValueW)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() +{ + 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); + { + 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 = pos; + } + } + + for (;;) + { + int pos; + wres = MyCreateDir(s); + if (wres == 0) + break; + if (wres == ERROR_ALREADY_EXISTS) + { + 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 (;;) + { + 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; + LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, (DWORD *)&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; + LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key); + if (res != ERROR_SUCCESS) + return False; + { + 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 _64BIT_INSTALLER + +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 + +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++) + { + 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++) + { + Byte 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-Zstandard")) + return; + wcscat(s, L"7-Zip-Zstandard\\"); +} + + +static int Install(); + +static void OnClose() +{ + 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 INT_PTR 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)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() +{ + 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 + + // wcscpy(link, L"\\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); + wcscat(link, k_7zip); + // wcscat(link, L"2"); + + if (i != 0) + MyCreateDir(link); + + NormalizePrefix(link); + + { + unsigned baseLen = (unsigned)wcslen(link); + unsigned k; + + for (k = 0; k < 2; k++) + { + wcscpy(link + baseLen, k == 0 ? + L"7-Zip File Manager.lnk" : + L"7-Zip Help.lnk" + ); + wcscpy(destPath, path); + wcscat(destPath, k == 0 ? + L"7zFM.exe" : + L"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() +{ + HKEY destKey; + LONG res; + + #ifdef _64BIT_INSTALLER + + 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 + 10]; + wcscpy(destPath, path); + wcscat(destPath, L"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 + 10]; + wcscpy(destPath, path); + wcscat(destPath, L"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 LPCWSTR const k_ShellEx_Items[] = +{ + L"*\\shellex\\ContextMenuHandlers" + , L"Directory\\shellex\\ContextMenuHandlers" + , L"Folder\\shellex\\ContextMenuHandlers" + , L"Directory\\shellex\\DragDropHandlers" + , L"Drive\\shellex\\DragDropHandlers" +}; + +static void WriteShellEx() +{ + unsigned i; + WCHAR destPath[MAX_PATH + 40]; + + for (i = 0; i < sizeof(k_ShellEx_Items) / sizeof(k_ShellEx_Items[0]); i++) + { + wcscpy(destPath, k_ShellEx_Items[i]); + wcscat(destPath, L"\\7-Zip-Zstandard"); + + #ifdef _64BIT_INSTALLER + MyRegistry_CreateKeyAndVal_32(HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID); + #endif + MyRegistry_CreateKeyAndVal (HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID); + } + + #ifdef _64BIT_INSTALLER + 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); + + + { + HKEY destKey = 0; + LONG res = MyRegistry_CreateKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe", &destKey); + if (res == ERROR_SUCCESS) + { + wcscpy(destPath, path); + wcscat(destPath, L"7zFM.exe"); + + 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-Zstandard", &destKey); + if (res == ERROR_SUCCESS) + { + // wcscpy(destPath, path); + // wcscat(destPath, L"7zFM.exe"); + 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); + + wcscpy(destPath, path); + MyRegistry_SetString(destKey, L"InstallLocation", destPath); + wcscat(destPath, L"Uninstall.exe"); + // wcscat(destPath, L"\""); + MyRegistry_SetString(destKey, L"UninstallString", 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) +{ + BoolInt quoteMode = False; + for (;; s++) + { + wchar_t c = *s; + if (c == L'\"') + quoteMode = !quoteMode; + else if (c == 0 || (c == L' ' && !quoteMode)) + 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 (;;) + { + { + wchar_t c = *s; + if (c == 0) + break; + if (c == ' ') + { + s++; + continue; + } + } + + { + const wchar_t *s2 = GetCmdParam(s); + if (s[0] == '/') + { + if (s[1] == 'S' && IS_LIMIT_CHAR(s[2])) + g_SilentMode = True; + else if (s[1] == 'D' && s[2] == '=') + { + size_t num; + s += 3; + num = s2 - s; + if (num > MAX_PATH) + num = MAX_PATH; + wcsncpy(path, s, (unsigned)num); + RemoveQuotes(path); + } + } + s = s2; + } + } + } + + #if defined(_64BIT_INSTALLER) && !defined(_WIN64) + { + BOOL isWow64 = FALSE; + Func_IsWow64Process func_IsWow64Process = (Func_IsWow64Process) + GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "IsWow64Process"); + + if (func_IsWow64Process) + func_IsWow64Process(GetCurrentProcess(), &isWow64); + + if (!isWow64) + { + if (!g_SilentMode) + PrintErrorMessage("This installation requires Windows x64"); + return 1; + } + } + #endif + + + 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); + } + + // ok = False; + if (!ok) + { + /* + #ifdef UNDER_CE + wcscpy(path, L"\\Program Files\\"); + #else + + #ifdef _64BIT_INSTALLER + { + DWORD ttt = GetEnvironmentVariableW(L"ProgramW6432", path, MAX_PATH); + if (ttt == 0 || ttt > MAX_PATH) + wcscpy(path, L"C:\\"); + } + #else + if (!SHGetSpecialFolderPathW(0, path, CSIDL_PROGRAM_FILES, FALSE)) + wcscpy(path, L"C:\\"); + #endif + #endif + */ + if (!MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion", L"ProgramFilesDir", path)) + wcscpy(path, + #ifdef UNDER_CE + L"\\Program Files\\" + #else + L"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; + + { + 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)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() +{ + 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; + + { + 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; + + { + // Remove post spaces + unsigned endPos = 0; + unsigned i = 0; + + for (;;) + { + wchar_t c = path[i++]; + if (c == 0) + break; + if (c != ' ') + endPos = i; + } + + path[endPos] = 0; + } + + 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); + } + + { + 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); + wcscat(path, L".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 _64BIT_INSTALLER + || FindSubString(temp, "7-zip32.dll") + #endif + ) + { + DWORD ver = GetFileVersion(path); + fileLevel = ((ver < _7ZIP_DLL_VER_COMPAT || ver > _7ZIP_CUR_VER) ? 2 : 1); + tempIndex++; + continue; + } + + if (g_SilentMode) + { + tempIndex++; + continue; + } + { + WCHAR message[MAX_PATH * 3 + 100]; + int mbRes; + + wcscpy(message, L"Can't open file\n"); + wcscat(message, path); + wcscat(message, L"\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 + + { + SRes 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); + MessageBoxW(g_HWND, m, k_7zip_with_Ver_str, MB_ICONERROR); + } + 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); + } + } + + return 1; +} diff --git a/C/Util/7zipInstall/7zipInstall.dsp b/C/Util/7zipInstall/7zipInstall.dsp index a5bbc1865..d3b5c4c97 100644 --- a/C/Util/7zipInstall/7zipInstall.dsp +++ b/C/Util/7zipInstall/7zipInstall.dsp @@ -1,240 +1,240 @@ -# 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=..\..\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=.\7zipInstall.c -# End Source File -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# End Target -# End Project +# 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=..\..\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=.\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 index bb73ae982..b7db73f46 100644 --- a/C/Util/7zipInstall/7zipInstall.dsw +++ b/C/Util/7zipInstall/7zipInstall.dsw @@ -1,29 +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> -{{{ -}}} - -############################################################################### - +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 index 9fbd7b5ac..f5c3ae5e7 100644 --- a/C/Util/7zipInstall/7zipInstall.manifest +++ b/C/Util/7zipInstall/7zipInstall.manifest @@ -1,18 +1,18 @@ - - - -7-Zip Installer - - - - - - - - - - - - -true - + + + +7-Zip Installer + + + + + + + + + + + + +true + diff --git a/C/Util/7zipInstall/Precomp.c b/C/Util/7zipInstall/Precomp.c index 34b60f8fc..01605e3c2 100644 --- a/C/Util/7zipInstall/Precomp.c +++ b/C/Util/7zipInstall/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/7zipInstall/Precomp.h b/C/Util/7zipInstall/Precomp.h index d307e0728..4c90d479d 100644 --- a/C/Util/7zipInstall/Precomp.h +++ b/C/Util/7zipInstall/Precomp.h @@ -1,11 +1,11 @@ -/* Precomp.h -- StdAfx -2015-05-24 : Igor Pavlov : Public domain */ - -#ifndef __7Z_PRECOMP_H -#define __7Z_PRECOMP_H - -#include "../../Compiler.h" - -#include "../../7zTypes.h" - -#endif +/* Precomp.h -- StdAfx +2015-05-24 : Igor Pavlov : Public domain */ + +#ifndef __7Z_PRECOMP_H +#define __7Z_PRECOMP_H + +#include "../../Compiler.h" + +#include "../../7zTypes.h" + +#endif diff --git a/C/Util/7zipInstall/makefile b/C/Util/7zipInstall/makefile index c4338d527..ab8893a9b 100644 --- a/C/Util/7zipInstall/makefile +++ b/C/Util/7zipInstall/makefile @@ -1,42 +1,42 @@ -PROG = 7zipInstall.exe -MY_FIXED = 1 - -!IFDEF _64BIT_INSTALLER -CFLAGS = $(CFLAGS) -D_64BIT_INSTALLER -!ENDIF - -CFLAGS = $(CFLAGS) -D_LZMA_SIZE_OPT - -CFLAGS = $(CFLAGS) \ - -D_7Z_NO_METHOD_LZMA2 \ - -D_7Z_NO_METHODS_FILTERS - -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\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) +PROG = 7zipInstall.exe +MY_FIXED = 1 + +!IFDEF _64BIT_INSTALLER +CFLAGS = $(CFLAGS) -D_64BIT_INSTALLER +!ENDIF + +CFLAGS = $(CFLAGS) -D_LZMA_SIZE_OPT + +CFLAGS = $(CFLAGS) \ + -D_7Z_NO_METHOD_LZMA2 \ + -D_7Z_NO_METHODS_FILTERS + +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\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 index e7811a13a..63c6b4c28 100644 --- a/C/Util/7zipInstall/resource.h +++ b/C/Util/7zipInstall/resource.h @@ -1,9 +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 +#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 index 9fac35b1d..e1d9f231a 100644 --- a/C/Util/7zipInstall/resource.rc +++ b/C/Util/7zipInstall/resource.rc @@ -1,47 +1,47 @@ -#include -#include -#include - -#define USE_COPYRIGHT_CR -#include "../../7zVersion.rc" -#include "resource.h" - -MY_VERSION_INFO(MY_VFT_APP, "7-Zip Installer ZS", "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 ZS" -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 +#include +#include +#include + +#define USE_COPYRIGHT_CR +#include "../../7zVersion.rc" +#include "resource.h" + +MY_VERSION_INFO(MY_VFT_APP, "7-Zip Installer ZS", "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 ZS" +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 index 06b143113..5b24de27f 100644 --- a/C/Util/7zipUninstall/7zipUninstall.c +++ b/C/Util/7zipUninstall/7zipUninstall.c @@ -1,1083 +1,1083 @@ -/* 7zipUninstall.c - 7-Zip Uninstaller -2019-02-02 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#define SZ_ERROR_ABORT 100 - -#ifdef _MSC_VER -#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union -#pragma warning(disable : 4011) // vs2010: identifier truncated to _CRT_SECURE_CPP_OVERLOAD_SECURE -#endif - -#include -#include - -#include "../../7zVersion.h" - -#include "resource.h" - -#define LLL_(quote) L##quote -#define LLL(quote) LLL_(quote) - -// static const WCHAR * const k_7zip = L"7-Zip"; - -// #define _64BIT_INSTALLER 1 - -#ifdef _WIN64 - #define _64BIT_INSTALLER 1 -#endif - -#define k_7zip_with_Ver_base L"7-Zip ZS " LLL(MY_VERSION) - -#ifdef _64BIT_INSTALLER - #define k_7zip_with_Ver k_7zip_with_Ver_base L" (x64)" -#else - #define k_7zip_with_Ver k_7zip_with_Ver_base -#endif - -// static const WCHAR * const k_7zip_with_Ver_str = k_7zip_with_Ver; - -static const WCHAR * const k_Reg_Software_7zip = L"Software\\7-Zip-Zstandard"; - -static const WCHAR * const k_Reg_Path = L"Path"; - -static const WCHAR * const k_Reg_Path32 = L"Path" - #ifdef _64BIT_INSTALLER - L"64" - #else - L"32" - #endif - ; - -#if defined(_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-20BB-278A-1000-000100020000}" - -static const WCHAR * const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID; -static const WCHAR * 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; - -typedef WINADVAPI LONG (APIENTRY *Func_RegDeleteKeyExW)(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired, DWORD Reserved); -static Func_RegDeleteKeyExW func_RegDeleteKeyExW; - -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 const WCHAR * const kUninstallExe = L"Uninstall.exe"; - -#define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) -= 0x20 : (c))) - -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; - 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) -{ - 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; - LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, (DWORD *)&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; - LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key); - if (res != ERROR_SUCCESS) - return False; - { - 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 _64BIT_INSTALLER - -static int MyRegistry_QueryString2_32(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest) -{ - HKEY key = 0; - LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag_32, &key); - if (res != ERROR_SUCCESS) - return False; - { - 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; - 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() -{ - 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); - wcscat(link, L"7-Zip-Zstandard\\"); - - { - const size_t baseLen = wcslen(link); - unsigned k; - BoolInt needDelete = False; - - for (k = 0; k < 2; k++) - { - wcscpy(link + baseLen, k == 0 ? - L"7-Zip File Manager.lnk" : - L"7-Zip Help.lnk"); - wcscpy(destPath, path); - wcscat(destPath, k == 0 ? - L"7zFM.exe" : - L"7-zip.chm"); - - if (CreateShellLink(link, destPath) == S_OK) - { - needDelete = True; - DeleteFileW(link); - } - } - - if (needDelete) - { - link[baseLen] = 0; - RemoveDirectoryW(link); - } - } - } - - #endif -} - - -static const WCHAR * const k_ShellEx_Items[] = -{ - L"*\\shellex\\ContextMenuHandlers" - , L"Directory\\shellex\\ContextMenuHandlers" - , L"Folder\\shellex\\ContextMenuHandlers" - , L"Directory\\shellex\\DragDropHandlers" - , L"Drive\\shellex\\DragDropHandlers" -}; - -static const WCHAR * const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"; - -static const WCHAR * const k_AppPaths_7zFm = L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe"; -#define k_REG_Uninstall L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" -static const WCHAR * const k_Uninstall_7zip = k_REG_Uninstall L"7-Zip-Zstandard"; - - -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() -{ - 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")) - { - { - 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 < sizeof(k_ShellEx_Items) / sizeof(k_ShellEx_Items[0]); i++) - { - WCHAR destPath[MAX_PATH]; - wcscpy(destPath, k_ShellEx_Items[i]); - wcscat(destPath, L"\\7-Zip-Zstandard"); - - MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, destPath); - } - } - - { - HKEY destKey = 0; - 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 _64BIT_INSTALLER - - if (MyRegistry_QueryString2_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, NULL, s)) - { - if (AreEqual_Path_PrefixName(s, path, L"7-zip32.dll")) - { - { - 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 < sizeof(k_ShellEx_Items) / sizeof(k_ShellEx_Items[0]); i++) - { - WCHAR destPath[MAX_PATH]; - wcscpy(destPath, k_ShellEx_Items[i]); - wcscat(destPath, L"\\7-Zip-Zstandard"); - - MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, destPath); - } - } - - { - HKEY destKey = 0; - 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)) - 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)) - if (AreEqual_Path_PrefixName(s, path, kUninstallExe)) - MyRegistry_DeleteKey(HKEY_LOCAL_MACHINE, k_Uninstall_7zip); -} - - -static const wchar_t *GetCmdParam(const wchar_t *s) -{ - BoolInt quoteMode = False; - for (;; s++) - { - wchar_t c = *s; - if (c == L'\"') - quoteMode = !quoteMode; - else if (c == 0 || (c == L' ' && !quoteMode)) - 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() -{ - 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() -{ - return RemoveFileAfterReboot2(path); -} - -#define IS_LIMIT_CHAR(c) (c == 0 || c == ' ') - -static BoolInt IsThereSpace(const wchar_t *s) -{ - for (;;) - { - wchar_t c = *s++; - if (c == 0) - return False; - if (c == ' ') - return True; - } -} - -static void AddPathParam(wchar_t *dest, const wchar_t *src) -{ - BoolInt needQuote = IsThereSpace(src); - if (needQuote) - wcscat(dest, L"\""); - wcscat(dest, src); - if (needQuote) - wcscat(dest, L"\""); -} - - - -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() -{ - DWORD attrib = GetFileAttributesW(path); - if (attrib == INVALID_FILE_ATTRIBUTES) - return TRUE; - if (RemoveDirectoryW(path)) - return TRUE; - return RemoveFileAfterReboot(); -} - - - - - -#define k_Lang L"Lang" - -// NUM_LANG_TXT_FILES files are placed before en.ttt -#define NUM_LANG_TXT_FILES 88 - -#ifdef _64BIT_INSTALLER - #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 ta th tr tt ug uk uz 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 _64BIT_INSTALLER - " 7-zip32.dll" - #endif - " 7-zip.dll" - " Uninstall.exe"; - - - -static int Install() -{ - 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) - wcscpy(temp, k_Lang L"\\"); - - { - WCHAR *dest = temp + wcslen(temp); - - for (;;) - { - char c = *curName; - if (c == 0) - break; - curName++; - if (c == ' ') - break; - *dest++ = (Byte)c; - } - - *dest = 0; - } - - if (i < NUM_LANG_TXT_FILES) - wcscat(temp, L".txt"); - - if (!g_SilentMode) - SetWindowTextW(g_InfoLine_HWND, temp); - - { - 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; - */ - } - } - } - - wcscpy(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)) - wcscpy(m, L"ERROR"); - MessageBoxW(g_HWND, m, L"Error", MB_ICONERROR | MB_OK); - } - - return 1; -} - - -static void OnClose() -{ - if (g_Install_was_Pressed && !g_Finished) - { - if (MessageBoxW(g_HWND, - L"Do you want to cancel uninstallation?", - k_7zip_with_Ver, - MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES) - return; - } - DestroyWindow(g_HWND); - g_HWND = NULL; -} - -static INT_PTR 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 L" 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)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) - 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); - if (s[0] == '/') - { - if (s[1] == 'S' && IS_LIMIT_CHAR(s[2])) - g_SilentMode = True; - else if (s[1] == 'N' && IS_LIMIT_CHAR(s[2])) - useTemp = False; - else if (s[1] == 'D' && s[2] == '=') - { - size_t num; - s += 3; - num = s2 - s; - if (num <= MAX_PATH) - { - wcsncpy(workDir, s, num); - workDir[num] = 0; - RemoveQuotes(workDir); - useTemp = False; - } - } - } - s = s2; - } - } - } - - - { - wchar_t *name; - 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 (;;) - { - 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()) - { - 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()) - continue; - if (CreateDirectoryW(path, NULL)) - { - wcscat(path, WSTRING_PATH_SEPARATOR); - wcscpy(tempPath, path); - break; - } - if (GetLastError() != ERROR_ALREADY_EXISTS) - break; - } - - if (tempPath[0] != 0) - { - wcscpy(copyPath, tempPath); - wcscat(copyPath, L"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); - wcscat(cmdLine, L" /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; - - { - 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)GetDlgItem(g_HWND, IDOK), TRUE); - } - } - } - - if (g_HWND) - { - DestroyWindow(g_HWND); - g_HWND = NULL; - } - } - - return retCode; - } -} +/* 7zipUninstall.c - 7-Zip Uninstaller +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#define SZ_ERROR_ABORT 100 + +#ifdef _MSC_VER +#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union +#pragma warning(disable : 4011) // vs2010: identifier truncated to _CRT_SECURE_CPP_OVERLOAD_SECURE +#endif + +#include +#include + +#include "../../7zVersion.h" + +#include "resource.h" + +#define LLL_(quote) L##quote +#define LLL(quote) LLL_(quote) + +// static const WCHAR * const k_7zip = L"7-Zip"; + +// #define _64BIT_INSTALLER 1 + +#ifdef _WIN64 + #define _64BIT_INSTALLER 1 +#endif + +#define k_7zip_with_Ver_base L"7-Zip ZS " LLL(MY_VERSION) + +#ifdef _64BIT_INSTALLER + #define k_7zip_with_Ver k_7zip_with_Ver_base L" (x64)" +#else + #define k_7zip_with_Ver k_7zip_with_Ver_base +#endif + +// static const WCHAR * const k_7zip_with_Ver_str = k_7zip_with_Ver; + +static const WCHAR * const k_Reg_Software_7zip = L"Software\\7-Zip-Zstandard"; + +static const WCHAR * const k_Reg_Path = L"Path"; + +static const WCHAR * const k_Reg_Path32 = L"Path" + #ifdef _64BIT_INSTALLER + L"64" + #else + L"32" + #endif + ; + +#if defined(_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-20BB-278A-1000-000100020000}" + +static const WCHAR * const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID; +static const WCHAR * 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; + +typedef WINADVAPI LONG (APIENTRY *Func_RegDeleteKeyExW)(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired, DWORD Reserved); +static Func_RegDeleteKeyExW func_RegDeleteKeyExW; + +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 const WCHAR * const kUninstallExe = L"Uninstall.exe"; + +#define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) -= 0x20 : (c))) + +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; + 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) +{ + 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; + LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, (DWORD *)&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; + LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key); + if (res != ERROR_SUCCESS) + return False; + { + 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 _64BIT_INSTALLER + +static int MyRegistry_QueryString2_32(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest) +{ + HKEY key = 0; + LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag_32, &key); + if (res != ERROR_SUCCESS) + return False; + { + 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; + 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() +{ + 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); + wcscat(link, L"7-Zip-Zstandard\\"); + + { + const size_t baseLen = wcslen(link); + unsigned k; + BoolInt needDelete = False; + + for (k = 0; k < 2; k++) + { + wcscpy(link + baseLen, k == 0 ? + L"7-Zip File Manager.lnk" : + L"7-Zip Help.lnk"); + wcscpy(destPath, path); + wcscat(destPath, k == 0 ? + L"7zFM.exe" : + L"7-zip.chm"); + + if (CreateShellLink(link, destPath) == S_OK) + { + needDelete = True; + DeleteFileW(link); + } + } + + if (needDelete) + { + link[baseLen] = 0; + RemoveDirectoryW(link); + } + } + } + + #endif +} + + +static const WCHAR * const k_ShellEx_Items[] = +{ + L"*\\shellex\\ContextMenuHandlers" + , L"Directory\\shellex\\ContextMenuHandlers" + , L"Folder\\shellex\\ContextMenuHandlers" + , L"Directory\\shellex\\DragDropHandlers" + , L"Drive\\shellex\\DragDropHandlers" +}; + +static const WCHAR * const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"; + +static const WCHAR * const k_AppPaths_7zFm = L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe"; +#define k_REG_Uninstall L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" +static const WCHAR * const k_Uninstall_7zip = k_REG_Uninstall L"7-Zip-Zstandard"; + + +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() +{ + 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")) + { + { + 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 < sizeof(k_ShellEx_Items) / sizeof(k_ShellEx_Items[0]); i++) + { + WCHAR destPath[MAX_PATH]; + wcscpy(destPath, k_ShellEx_Items[i]); + wcscat(destPath, L"\\7-Zip-Zstandard"); + + MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, destPath); + } + } + + { + HKEY destKey = 0; + 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 _64BIT_INSTALLER + + if (MyRegistry_QueryString2_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, NULL, s)) + { + if (AreEqual_Path_PrefixName(s, path, L"7-zip32.dll")) + { + { + 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 < sizeof(k_ShellEx_Items) / sizeof(k_ShellEx_Items[0]); i++) + { + WCHAR destPath[MAX_PATH]; + wcscpy(destPath, k_ShellEx_Items[i]); + wcscat(destPath, L"\\7-Zip-Zstandard"); + + MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, destPath); + } + } + + { + HKEY destKey = 0; + 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)) + 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)) + if (AreEqual_Path_PrefixName(s, path, kUninstallExe)) + MyRegistry_DeleteKey(HKEY_LOCAL_MACHINE, k_Uninstall_7zip); +} + + +static const wchar_t *GetCmdParam(const wchar_t *s) +{ + BoolInt quoteMode = False; + for (;; s++) + { + wchar_t c = *s; + if (c == L'\"') + quoteMode = !quoteMode; + else if (c == 0 || (c == L' ' && !quoteMode)) + 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() +{ + 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() +{ + return RemoveFileAfterReboot2(path); +} + +#define IS_LIMIT_CHAR(c) (c == 0 || c == ' ') + +static BoolInt IsThereSpace(const wchar_t *s) +{ + for (;;) + { + wchar_t c = *s++; + if (c == 0) + return False; + if (c == ' ') + return True; + } +} + +static void AddPathParam(wchar_t *dest, const wchar_t *src) +{ + BoolInt needQuote = IsThereSpace(src); + if (needQuote) + wcscat(dest, L"\""); + wcscat(dest, src); + if (needQuote) + wcscat(dest, L"\""); +} + + + +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() +{ + DWORD attrib = GetFileAttributesW(path); + if (attrib == INVALID_FILE_ATTRIBUTES) + return TRUE; + if (RemoveDirectoryW(path)) + return TRUE; + return RemoveFileAfterReboot(); +} + + + + + +#define k_Lang L"Lang" + +// NUM_LANG_TXT_FILES files are placed before en.ttt +#define NUM_LANG_TXT_FILES 88 + +#ifdef _64BIT_INSTALLER + #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 ta th tr tt ug uk uz 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 _64BIT_INSTALLER + " 7-zip32.dll" + #endif + " 7-zip.dll" + " Uninstall.exe"; + + + +static int Install() +{ + 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) + wcscpy(temp, k_Lang L"\\"); + + { + WCHAR *dest = temp + wcslen(temp); + + for (;;) + { + char c = *curName; + if (c == 0) + break; + curName++; + if (c == ' ') + break; + *dest++ = (Byte)c; + } + + *dest = 0; + } + + if (i < NUM_LANG_TXT_FILES) + wcscat(temp, L".txt"); + + if (!g_SilentMode) + SetWindowTextW(g_InfoLine_HWND, temp); + + { + 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; + */ + } + } + } + + wcscpy(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)) + wcscpy(m, L"ERROR"); + MessageBoxW(g_HWND, m, L"Error", MB_ICONERROR | MB_OK); + } + + return 1; +} + + +static void OnClose() +{ + if (g_Install_was_Pressed && !g_Finished) + { + if (MessageBoxW(g_HWND, + L"Do you want to cancel uninstallation?", + k_7zip_with_Ver, + MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES) + return; + } + DestroyWindow(g_HWND); + g_HWND = NULL; +} + +static INT_PTR 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 L" 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)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) + 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); + if (s[0] == '/') + { + if (s[1] == 'S' && IS_LIMIT_CHAR(s[2])) + g_SilentMode = True; + else if (s[1] == 'N' && IS_LIMIT_CHAR(s[2])) + useTemp = False; + else if (s[1] == 'D' && s[2] == '=') + { + size_t num; + s += 3; + num = s2 - s; + if (num <= MAX_PATH) + { + wcsncpy(workDir, s, num); + workDir[num] = 0; + RemoveQuotes(workDir); + useTemp = False; + } + } + } + s = s2; + } + } + } + + + { + wchar_t *name; + 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 (;;) + { + 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()) + { + 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()) + continue; + if (CreateDirectoryW(path, NULL)) + { + wcscat(path, WSTRING_PATH_SEPARATOR); + wcscpy(tempPath, path); + break; + } + if (GetLastError() != ERROR_ALREADY_EXISTS) + break; + } + + if (tempPath[0] != 0) + { + wcscpy(copyPath, tempPath); + wcscat(copyPath, L"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); + wcscat(cmdLine, L" /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; + + { + 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)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 index 1a12bf557..cc7b6b6b8 100644 --- a/C/Util/7zipUninstall/7zipUninstall.dsp +++ b/C/Util/7zipUninstall/7zipUninstall.dsp @@ -1,124 +1,124 @@ -# 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=.\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 +# 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=.\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 index a26aafe6b..2873eda6a 100644 --- a/C/Util/7zipUninstall/7zipUninstall.dsw +++ b/C/Util/7zipUninstall/7zipUninstall.dsw @@ -1,29 +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> -{{{ -}}} - -############################################################################### - +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.manifest b/C/Util/7zipUninstall/7zipUninstall.manifest index e4bafc4af..a60144340 100644 --- a/C/Util/7zipUninstall/7zipUninstall.manifest +++ b/C/Util/7zipUninstall/7zipUninstall.manifest @@ -1,18 +1,18 @@ - - - -7-Zip Uninstaller - - - - - - - - - - - - -true - + + + +7-Zip Uninstaller + + + + + + + + + + + + +true + diff --git a/C/Util/7zipUninstall/Precomp.c b/C/Util/7zipUninstall/Precomp.c index 34b60f8fc..01605e3c2 100644 --- a/C/Util/7zipUninstall/Precomp.c +++ b/C/Util/7zipUninstall/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/7zipUninstall/Precomp.h b/C/Util/7zipUninstall/Precomp.h index d307e0728..4c90d479d 100644 --- a/C/Util/7zipUninstall/Precomp.h +++ b/C/Util/7zipUninstall/Precomp.h @@ -1,11 +1,11 @@ -/* Precomp.h -- StdAfx -2015-05-24 : Igor Pavlov : Public domain */ - -#ifndef __7Z_PRECOMP_H -#define __7Z_PRECOMP_H - -#include "../../Compiler.h" - -#include "../../7zTypes.h" - -#endif +/* Precomp.h -- StdAfx +2015-05-24 : Igor Pavlov : Public domain */ + +#ifndef __7Z_PRECOMP_H +#define __7Z_PRECOMP_H + +#include "../../Compiler.h" + +#include "../../7zTypes.h" + +#endif diff --git a/C/Util/7zipUninstall/makefile b/C/Util/7zipUninstall/makefile index 823759a25..60c2fe20b 100644 --- a/C/Util/7zipUninstall/makefile +++ b/C/Util/7zipUninstall/makefile @@ -1,18 +1,18 @@ -PROG = 7zipUninstall.exe -MY_FIXED = 1 - -!IFDEF _64BIT_INSTALLER -CFLAGS = $(CFLAGS) -D_64BIT_INSTALLER -!ENDIF - -MAIN_OBJS = \ - $O\7zipUninstall.obj \ - -OBJS = \ - $(MAIN_OBJS) \ - $O\resource.res - -!include "../../../CPP/Build.mak" - -$(MAIN_OBJS): $(*B).c - $(COMPL_O1) +PROG = 7zipUninstall.exe +MY_FIXED = 1 + +!IFDEF _64BIT_INSTALLER +CFLAGS = $(CFLAGS) -D_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 index dfbb7c638..b5c33ff1f 100644 --- a/C/Util/7zipUninstall/resource.h +++ b/C/Util/7zipUninstall/resource.h @@ -1,9 +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 +#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 index 87fe1dd01..a630b24f9 100644 --- a/C/Util/7zipUninstall/resource.rc +++ b/C/Util/7zipUninstall/resource.rc @@ -1,47 +1,47 @@ -#include -#include -#include - -#define USE_COPYRIGHT_CR -#include "../../7zVersion.rc" -#include "resource.h" - -MY_VERSION_INFO(MY_VFT_APP, "7-Zip Uninstaller ZS", "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 ZS" -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 +#include +#include +#include + +#define USE_COPYRIGHT_CR +#include "../../7zVersion.rc" +#include "resource.h" + +MY_VERSION_INFO(MY_VFT_APP, "7-Zip Uninstaller ZS", "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 ZS" +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 82130e85d..739bc0fde 100644 --- a/C/Util/Lzma/LzmaUtil.c +++ b/C/Util/Lzma/LzmaUtil.c @@ -1,258 +1,258 @@ -/* LzmaUtil.c -- Test application for LZMA compression -2018-07-04 : Igor Pavlov : Public domain */ - -#include "../../Precomp.h" - -#include -#include -#include - -#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 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 +2018-07-04 : Igor Pavlov : Public domain */ + +#include "../../Precomp.h" + +#include +#include +#include + +#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 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; +} diff --git a/C/Util/Lzma/LzmaUtil.dsp b/C/Util/Lzma/LzmaUtil.dsp index eedde07d8..f060a2670 100644 --- a/C/Util/Lzma/LzmaUtil.dsp +++ b/C/Util/Lzma/LzmaUtil.dsp @@ -1,168 +1,168 @@ -# 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=..\..\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 diff --git a/C/Util/Lzma/LzmaUtil.dsw b/C/Util/Lzma/LzmaUtil.dsw index f43548752..c52eaf6d0 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/makefile b/C/Util/Lzma/makefile index 3b825f21a..479532278 100644 --- a/C/Util/Lzma/makefile +++ b/C/Util/Lzma/makefile @@ -1,28 +1,28 @@ -# 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\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) diff --git a/C/Util/Lzma/makefile.gcc b/C/Util/Lzma/makefile.gcc index 12a72bb8b..67aa8b179 100644 --- a/C/Util/Lzma/makefile.gcc +++ b/C/Util/Lzma/makefile.gcc @@ -1,44 +1,44 @@ -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 = 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) diff --git a/C/Util/LzmaLib/LzmaLib.def b/C/Util/LzmaLib/LzmaLib.def index 43b959778..8bc6add93 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 0d4c981c4..3421de83a 100644 --- a/C/Util/LzmaLib/LzmaLib.dsp +++ b/C/Util/LzmaLib/LzmaLib.dsp @@ -1,178 +1,178 @@ -# 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 +# 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 diff --git a/C/Util/LzmaLib/LzmaLib.dsw b/C/Util/LzmaLib/LzmaLib.dsw index f6c55593f..6faf33365 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 02600c724..4a28a9a6b 100644 --- a/C/Util/LzmaLib/LzmaLibExports.c +++ b/C/Util/LzmaLib/LzmaLibExports.c @@ -1,14 +1,14 @@ -/* LzmaLibExports.c -- LZMA library DLL Entry point -2015-11-08 : Igor Pavlov : Public domain */ - -#include "../../Precomp.h" - -#include - -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 +2015-11-08 : Igor Pavlov : Public domain */ + +#include "../../Precomp.h" + +#include + +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/makefile b/C/Util/LzmaLib/makefile index e0f311471..74103bb05 100644 --- a/C/Util/LzmaLib/makefile +++ b/C/Util/LzmaLib/makefile @@ -1,34 +1,34 @@ -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\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) diff --git a/C/Util/LzmaLib/resource.rc b/C/Util/LzmaLib/resource.rc index d95e3f358..674832e05 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 34b60f8fc..01605e3c2 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 9f398d08f..588a66f7e 100644 --- a/C/Util/SfxSetup/Precomp.h +++ b/C/Util/SfxSetup/Precomp.h @@ -1,10 +1,10 @@ -/* 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 +2013-06-16 : Igor Pavlov : Public domain */ + +#ifndef __7Z_PRECOMP_H +#define __7Z_PRECOMP_H + +#include "../../Compiler.h" +#include "../../7zTypes.h" + +#endif diff --git a/C/Util/SfxSetup/SfxSetup.c b/C/Util/SfxSetup/SfxSetup.c index 394369abd..ef19aeac5 100644 --- a/C/Util/SfxSetup/SfxSetup.c +++ b/C/Util/SfxSetup/SfxSetup.c @@ -1,640 +1,640 @@ -/* 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 -#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 +#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; +} diff --git a/C/Util/SfxSetup/SfxSetup.dsp b/C/Util/SfxSetup/SfxSetup.dsp index be9de6dec..60439a6f7 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 128fcdd3e..ea2311129 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 c9f59ccd3..544da67df 100644 --- a/C/Util/SfxSetup/makefile +++ b/C/Util/SfxSetup/makefile @@ -1,37 +1,37 @@ -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 + +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 6f604ed81..d0f835254 100644 --- a/C/Util/SfxSetup/makefile_con +++ b/C/Util/SfxSetup/makefile_con @@ -1,38 +1,38 @@ -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 + +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 64f4e2ce7..0c1637f23 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 7e061d6e7..d9f83df16 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 +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; +} diff --git a/C/Xz.h b/C/Xz.h index fad56a3fb..544ee18f2 100644 --- a/C/Xz.h +++ b/C/Xz.h @@ -1,460 +1,460 @@ -/* 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 +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 diff --git a/C/XzCrc64.c b/C/XzCrc64.c index e9ca9ec26..b6d02cbeb 100644 --- a/C/XzCrc64.c +++ b/C/XzCrc64.c @@ -1,86 +1,86 @@ -/* 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 +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 +} diff --git a/C/XzCrc64.h b/C/XzCrc64.h index 71b10d57e..08dbc330c 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 - -#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 +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __XZ_CRC64_H +#define __XZ_CRC64_H + +#include + +#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 diff --git a/C/XzCrc64Opt.c b/C/XzCrc64Opt.c index 9273465d4..b2852de4d 100644 --- a/C/XzCrc64Opt.c +++ b/C/XzCrc64Opt.c @@ -1,69 +1,69 @@ -/* 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 +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 diff --git a/C/XzDec.c b/C/XzDec.c index 4f5327207..395e83f67 100644 --- a/C/XzDec.c +++ b/C/XzDec.c @@ -1,2766 +1,2766 @@ -/* XzDec.c -- Xz Decode -2019-02-02 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -// #include - -// #define XZ_DUMP - -/* #define XZ_DUMP */ - -#ifdef XZ_DUMP -#include -#endif - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#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 -#include - -#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 +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #include + +// #define XZ_DUMP + +/* #define XZ_DUMP */ + +#ifdef XZ_DUMP +#include +#endif + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#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 +#include + +#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; + } +} diff --git a/C/XzEnc.c b/C/XzEnc.c index 309eca949..d0a8b4489 100644 --- a/C/XzEnc.c +++ b/C/XzEnc.c @@ -1,1329 +1,1329 @@ -/* XzEnc.c -- Xz Encode -2019-02-02 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include -#include - -#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 +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include +#include + +#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; +} diff --git a/C/XzEnc.h b/C/XzEnc.h index 529ac3fd8..0c29e7e1e 100644 --- a/C/XzEnc.h +++ b/C/XzEnc.h @@ -1,60 +1,60 @@ -/* 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 +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 diff --git a/C/XzIn.c b/C/XzIn.c index 792a61786..ff48e2dd4 100644 --- a/C/XzIn.c +++ b/C/XzIn.c @@ -1,319 +1,319 @@ -/* XzIn.c - Xz input -2018-07-04 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -#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 +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#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; +} diff --git a/CPP/7zip/7zip.mak b/CPP/7zip/7zip.mak index 582dfd854..390ae079c 100644 --- a/CPP/7zip/7zip.mak +++ b/CPP/7zip/7zip.mak @@ -1,305 +1,305 @@ -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) \ - $(BROTLI_OBJS) \ - $(HASHES_OBJS) \ - $(LIZARD_OBJS) \ - $(LZ4_OBJS) \ - $(LZ5_OBJS) \ - $(ZSTD_OBJS) \ - $(ZSTDMT_OBJS) \ - $(FASTLZMA2_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 - -!IFDEF BROTLI_OBJS -$(BROTLI_OBJS): ../../../../C/brotli/$(*B).c - $(COMPL_O2) -!ENDIF - -!IFDEF LIZARD_OBJS -$(LIZARD_OBJS): ../../../../C/lizard/$(*B).c - $(COMPL_O2) -!ENDIF - -!IFDEF LZ4_OBJS -$(LZ4_OBJS): ../../../../C/lz4/$(*B).c - $(COMPL_O2) -!ENDIF - -!IFDEF LZ5_OBJS -$(LZ5_OBJS): ../../../../C/lz5/$(*B).c - $(COMPL_O2) -!ENDIF - -!IFDEF ZSTD_OBJS -$(ZSTD_OBJS): ../../../../C/zstd/$(*B).c - $(COMPL_O2) -!ENDIF - -!IFDEF ZSTDMT_OBJS -$(ZSTDMT_OBJS): ../../../../C/zstdmt/$(*B).c - $(COMPL_O2) -!ENDIF - -!IFDEF FASTLZMA2_OBJS -$(FASTLZMA2_OBJS): ../../../../C/fast-lzma2/$(*B).c - $(COMPL_O2) -DNO_XXHASH -DFL2_7ZIP_BUILD -!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:: - $(COMPLB_O2) -{../../../../C/brotli}.c{$O}.obj:: - $(COMPLB_O2) -{../../../../C/hashes}.c{$O}.obj:: - $(COMPLB_O2) -{../../../../C/lizard}.c{$O}.obj:: - $(COMPLB_O2) -{../../../../C/lz4}.c{$O}.obj:: - $(COMPLB_O2) -{../../../../C/lz5}.c{$O}.obj:: - $(COMPLB_O2) -{../../../../C/zstd}.c{$O}.obj:: - $(COMPLB_O2) -{../../../../C/zstdmt}.c{$O}.obj:: - $(COMPLB_O2) \ - -I ../../../../C/brotli \ - -I ../../../../C/hashes \ - -I ../../../../C/lizard \ - -I ../../../../C/lz4 \ - -I ../../../../C/lz5 \ - -I ../../../../C/zstd -{../../../../C/fast-lzma2}.c{$O}.obj:: - $(COMPLB_O2) -DNO_XXHASH -DFL2_7ZIP_BUILD - -!ENDIF - -!include "Asm.mak" +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) \ + $(BROTLI_OBJS) \ + $(HASHES_OBJS) \ + $(LIZARD_OBJS) \ + $(LZ4_OBJS) \ + $(LZ5_OBJS) \ + $(ZSTD_OBJS) \ + $(ZSTDMT_OBJS) \ + $(FASTLZMA2_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 + +!IFDEF BROTLI_OBJS +$(BROTLI_OBJS): ../../../../C/brotli/$(*B).c + $(COMPL_O2) +!ENDIF + +!IFDEF LIZARD_OBJS +$(LIZARD_OBJS): ../../../../C/lizard/$(*B).c + $(COMPL_O2) +!ENDIF + +!IFDEF LZ4_OBJS +$(LZ4_OBJS): ../../../../C/lz4/$(*B).c + $(COMPL_O2) +!ENDIF + +!IFDEF LZ5_OBJS +$(LZ5_OBJS): ../../../../C/lz5/$(*B).c + $(COMPL_O2) +!ENDIF + +!IFDEF ZSTD_OBJS +$(ZSTD_OBJS): ../../../../C/zstd/$(*B).c + $(COMPL_O2) +!ENDIF + +!IFDEF ZSTDMT_OBJS +$(ZSTDMT_OBJS): ../../../../C/zstdmt/$(*B).c + $(COMPL_O2) +!ENDIF + +!IFDEF FASTLZMA2_OBJS +$(FASTLZMA2_OBJS): ../../../../C/fast-lzma2/$(*B).c + $(COMPL_O2) -DNO_XXHASH -DFL2_7ZIP_BUILD +!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:: + $(COMPLB_O2) +{../../../../C/brotli}.c{$O}.obj:: + $(COMPLB_O2) +{../../../../C/hashes}.c{$O}.obj:: + $(COMPLB_O2) +{../../../../C/lizard}.c{$O}.obj:: + $(COMPLB_O2) +{../../../../C/lz4}.c{$O}.obj:: + $(COMPLB_O2) +{../../../../C/lz5}.c{$O}.obj:: + $(COMPLB_O2) +{../../../../C/zstd}.c{$O}.obj:: + $(COMPLB_O2) +{../../../../C/zstdmt}.c{$O}.obj:: + $(COMPLB_O2) \ + -I ../../../../C/brotli \ + -I ../../../../C/hashes \ + -I ../../../../C/lizard \ + -I ../../../../C/lz4 \ + -I ../../../../C/lz5 \ + -I ../../../../C/zstd +{../../../../C/fast-lzma2}.c{$O}.obj:: + $(COMPLB_O2) -DNO_XXHASH -DFL2_7ZIP_BUILD + +!ENDIF + +!include "Asm.mak" diff --git a/CPP/7zip/Aes.mak b/CPP/7zip/Aes.mak index 3d0d87764..20f1a72fa 100644 --- a/CPP/7zip/Aes.mak +++ b/CPP/7zip/Aes.mak @@ -1,7 +1,7 @@ -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 "$(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 index 4f341edf1..ffd28721e 100644 --- a/CPP/7zip/Archive/7z/7z.dsp +++ b/CPP/7zip/Archive/7z/7z.dsp @@ -1,642 +1,642 @@ -# 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 "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:\Program Files\7-zip\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 "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:\Program Files\7-zip\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=..\DllExports.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\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\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 +# 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 "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:\Program Files\7-zip\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 "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:\Program Files\7-zip\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=..\DllExports.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\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\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 index 5b0e36cca..702a86c72 100644 --- a/CPP/7zip/Archive/7z/7z.dsw +++ b/CPP/7zip/Archive/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/CPP/7zip/Archive/7z/7zCompressionMode.cpp b/CPP/7zip/Archive/7z/7zCompressionMode.cpp index 232c63820..6774fc482 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 23600171d..608293d6d 100644 --- a/CPP/7zip/Archive/7z/7zCompressionMode.h +++ b/CPP/7zip/Archive/7z/7zCompressionMode.h @@ -1,76 +1,76 @@ -// 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 Methods; - CRecordVector 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 __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 Methods; + CRecordVector 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 diff --git a/CPP/7zip/Archive/7z/7zDecode.cpp b/CPP/7zip/Archive/7z/7zDecode.cpp index f61ad4ad9..9df531e0e 100644 --- a/CPP/7zip/Archive/7z/7zDecode.cpp +++ b/CPP/7zip/Archive/7z/7zDecode.cpp @@ -1,569 +1,569 @@ -// 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 _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 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 _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 _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 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 setCoderMt; - decoder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt); - if (setCoderMt) - { - mt_wasUsed = true; - RINOK(setCoderMt->SetNumberOfThreads(numThreads)); - } - } - // if (memUsage != 0) - { - CMyComPtr setMemLimit; - decoder->QueryInterface(IID_ICompressSetMemLimit, (void **)&setMemLimit); - if (setMemLimit) - { - mt_wasUsed = true; - RINOK(setMemLimit->SetMemLimit(memUsage)); - } - } - } - #endif - - { - CMyComPtr 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 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 setFinishMode; - decoder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode); - if (setFinishMode) - { - finishMode = fullUnpack; - RINOK(setFinishMode->SetFinishMode(BoolToInt(finishMode))); - } - } - - UInt32 numStreams = (UInt32)coderInfo.NumStreams; - - CObjArray packSizes(numStreams); - CObjArray 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 > inStreams; - - CLockedInStream *lockedInStreamSpec = new CLockedInStream; - CMyComPtr 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 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 inStreamPointers(num); - for (i = 0; i < num; i++) - inStreamPointers[i] = inStreams[i]; - - if (outStream) - { - CMyComPtr 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 "7zDecode.h" + +namespace NArchive { +namespace N7z { + +class CDecProgress: + public ICompressProgressInfo, + public CMyUnknownImp +{ + CMyComPtr _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 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 _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 _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 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 setCoderMt; + decoder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt); + if (setCoderMt) + { + mt_wasUsed = true; + RINOK(setCoderMt->SetNumberOfThreads(numThreads)); + } + } + // if (memUsage != 0) + { + CMyComPtr setMemLimit; + decoder->QueryInterface(IID_ICompressSetMemLimit, (void **)&setMemLimit); + if (setMemLimit) + { + mt_wasUsed = true; + RINOK(setMemLimit->SetMemLimit(memUsage)); + } + } + } + #endif + + { + CMyComPtr 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 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 setFinishMode; + decoder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode); + if (setFinishMode) + { + finishMode = fullUnpack; + RINOK(setFinishMode->SetFinishMode(BoolToInt(finishMode))); + } + } + + UInt32 numStreams = (UInt32)coderInfo.NumStreams; + + CObjArray packSizes(numStreams); + CObjArray 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 > inStreams; + + CLockedInStream *lockedInStreamSpec = new CLockedInStream; + CMyComPtr 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 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 inStreamPointers(num); + for (i = 0; i < num; i++) + inStreamPointers[i] = inStreams[i]; + + if (outStream) + { + CMyComPtr 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 944f8a317..eeb146e38 100644 --- a/CPP/7zip/Archive/7z/7zDecode.h +++ b/CPP/7zip/Archive/7z/7zDecode.h @@ -1,70 +1,70 @@ -// 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 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 _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 __7Z_DECODE_H +#define __7Z_DECODE_H + +#include "../Common/CoderMixer2.h" + +#include "7zIn.h" + +namespace NArchive { +namespace N7z { + +struct CBindInfoEx: public NCoderMixer2::CBindInfo +{ + CRecordVector 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 _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 diff --git a/CPP/7zip/Archive/7z/7zEncode.cpp b/CPP/7zip/Archive/7z/7zEncode.cpp index 4c0d22149..7d8270f93 100644 --- a/CPP/7zip/Archive/7z/7zEncode.cpp +++ b/CPP/7zip/Archive/7z/7zEncode.cpp @@ -1,678 +1,678 @@ -// 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 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 encoderCommon = cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2; - - #ifndef _7ZIP_ST - { - CMyComPtr setCoderMt; - encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); - if (setCoderMt) - { - RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads)); - } - } - #endif - - RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon)); - - /* - CMyComPtr 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 setCompressCodecsInfo; - encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); - if (setCompressCodecsInfo) - { - // we must use g_ExternalCodecs also - RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs)); - } - #endif - */ - - CMyComPtr 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 _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 &coderUnpackSizes, - UInt64 &unpackSize, - ISequentialOutStream *outStream, - CRecordVector &packSizes, - ICompressProgressInfo *compressProgress) -{ - RINOK(EncoderConstr()); - - if (!_mixerRef) - { - RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce)); - } - - _mixer->ReInit(); - - CMtEncMultiProgress *mtProgressSpec = NULL; - CMyComPtr mtProgress; - - CSequentialOutMtNotify *mtOutStreamNotifySpec = NULL; - CMyComPtr mtOutStreamNotify; - - CObjectVector inOutTempBuffers; - CObjectVector tempBufferSpecs; - CObjectVector > 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 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 inStreamSizeCount = inStreamSizeCountSpec; - - CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL; - CMyComPtr outStreamSizeCount; - - inStreamSizeCountSpec->Init(inStream); - - ISequentialInStream *inStreamPointer = inStreamSizeCount; - CRecordVector outStreamPointers; - - SetFolder(folderItem); - - for (i = 0; i < numMethods; i++) - { - IUnknown *coder = _mixer->GetCoder(i).GetUnknown(); - - CMyComPtr resetInitVector; - coder->QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector); - if (resetInitVector) - { - resetInitVector->ResetInitVector(); - } - - { - CMyComPtr 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 writeCoderProperties; - coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties); - - CByteBuffer &props = folderItem.Coders[numMethods - 1 - i].Props; - - if (writeCoderProperties) - { - CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream; - CMyComPtr 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/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 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 encoderCommon = cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2; + + #ifndef _7ZIP_ST + { + CMyComPtr setCoderMt; + encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); + if (setCoderMt) + { + RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads)); + } + } + #endif + + RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon)); + + /* + CMyComPtr 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 setCompressCodecsInfo; + encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); + if (setCompressCodecsInfo) + { + // we must use g_ExternalCodecs also + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs)); + } + #endif + */ + + CMyComPtr 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 _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 &coderUnpackSizes, + UInt64 &unpackSize, + ISequentialOutStream *outStream, + CRecordVector &packSizes, + ICompressProgressInfo *compressProgress) +{ + RINOK(EncoderConstr()); + + if (!_mixerRef) + { + RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce)); + } + + _mixer->ReInit(); + + CMtEncMultiProgress *mtProgressSpec = NULL; + CMyComPtr mtProgress; + + CSequentialOutMtNotify *mtOutStreamNotifySpec = NULL; + CMyComPtr mtOutStreamNotify; + + CObjectVector inOutTempBuffers; + CObjectVector tempBufferSpecs; + CObjectVector > 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 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 inStreamSizeCount = inStreamSizeCountSpec; + + CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL; + CMyComPtr outStreamSizeCount; + + inStreamSizeCountSpec->Init(inStream); + + ISequentialInStream *inStreamPointer = inStreamSizeCount; + CRecordVector outStreamPointers; + + SetFolder(folderItem); + + for (i = 0; i < numMethods; i++) + { + IUnknown *coder = _mixer->GetCoder(i).GetUnknown(); + + CMyComPtr resetInitVector; + coder->QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector); + if (resetInitVector) + { + resetInitVector->ResetInitVector(); + } + + { + CMyComPtr 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 writeCoderProperties; + coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties); + + CByteBuffer &props = folderItem.Coders[numMethods - 1 - i].Props; + + if (writeCoderProperties) + { + CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream; + CMyComPtr 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() {} + +}} diff --git a/CPP/7zip/Archive/7z/7zEncode.h b/CPP/7zip/Archive/7z/7zEncode.h index 434cbecd3..f1a9b5ad7 100644 --- a/CPP/7zip/Archive/7z/7zEncode.h +++ b/CPP/7zip/Archive/7z/7zEncode.h @@ -1,92 +1,92 @@ -// 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 _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 _mixerRef; - - CCompressionMethodMode _options; - NCoderMixer2::CBindInfo _bindInfo; - CRecordVector _decompressionMethods; - - CRecordVector _SrcIn_to_DestOut; - CRecordVector _SrcOut_to_DestIn; - // CRecordVector _DestIn_to_SrcOut; - CRecordVector _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 &coderUnpackSizes, - UInt64 &unpackSize, - ISequentialOutStream *outStream, - CRecordVector &packSizes, - ICompressProgressInfo *compressProgress); -}; - -}} - -#endif +// 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 _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 _mixerRef; + + CCompressionMethodMode _options; + NCoderMixer2::CBindInfo _bindInfo; + CRecordVector _decompressionMethods; + + CRecordVector _SrcIn_to_DestOut; + CRecordVector _SrcOut_to_DestIn; + // CRecordVector _DestIn_to_SrcOut; + CRecordVector _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 &coderUnpackSizes, + UInt64 &unpackSize, + ISequentialOutStream *outStream, + CRecordVector &packSizes, + ICompressProgressInfo *compressProgress); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/7z/7zExtract.cpp b/CPP/7zip/Archive/7z/7zExtract.cpp index 075644ffd..9ffe2fdcf 100644 --- a/CPP/7zip/Archive/7z/7zExtract.cpp +++ b/CPP/7zip/Archive/7z/7zExtract.cpp @@ -1,423 +1,423 @@ -// 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 _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 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 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 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 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 callbackMessage; - extractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage, &callbackMessage); - - CFolderOutStream *folderOutStream = new CFolderOutStream; - CMyComPtr 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 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 { + +class CFolderOutStream: + public ISequentialOutStream, + public CMyUnknownImp +{ + CMyComPtr _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 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 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 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 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 callbackMessage; + extractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage, &callbackMessage); + + CFolderOutStream *folderOutStream = new CFolderOutStream; + CMyComPtr 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 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 +} + +}} diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.cpp b/CPP/7zip/Archive/7z/7zFolderInStream.cpp index eee11a085..a68edf4eb 100644 --- a/CPP/7zip/Archive/7z/7zFolderInStream.cpp +++ b/CPP/7zip/Archive/7z/7zFolderInStream.cpp @@ -1,139 +1,139 @@ -// 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 stream; - HRESULT result = _updateCallback->GetStream(_indexes[_index], &stream); - if (result != S_OK) - { - if (result != S_FALSE) - return result; - } - - _stream = stream; - - if (stream) - { - CMyComPtr 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 "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 stream; + HRESULT result = _updateCallback->GetStream(_indexes[_index], &stream); + if (result != S_OK) + { + if (result != S_FALSE) + return result; + } + + _stream = stream; + + if (stream) + { + CMyComPtr 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; +} + +}} diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.h b/CPP/7zip/Archive/7z/7zFolderInStream.h index f2b1c599a..805db54e9 100644 --- a/CPP/7zip/Archive/7z/7zFolderInStream.h +++ b/CPP/7zip/Archive/7z/7zFolderInStream.h @@ -1,61 +1,61 @@ -// 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 _stream; - UInt64 _pos; - UInt32 _crc; - bool _size_Defined; - UInt64 _size; - - const UInt32 *_indexes; - unsigned _numFiles; - unsigned _index; - - CMyComPtr _updateCallback; - - HRESULT OpenStream(); - void AddFileInfo(bool isProcessed); - -public: - CRecordVector Processed; - CRecordVector CRCs; - CRecordVector 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 __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 _stream; + UInt64 _pos; + UInt32 _crc; + bool _size_Defined; + UInt64 _size; + + const UInt32 *_indexes; + unsigned _numFiles; + unsigned _index; + + CMyComPtr _updateCallback; + + HRESULT OpenStream(); + void AddFileInfo(bool isProcessed); + +public: + CRecordVector Processed; + CRecordVector CRCs; + CRecordVector 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 diff --git a/CPP/7zip/Archive/7z/7zHandler.cpp b/CPP/7zip/Archive/7z/7zHandler.cpp index 90565bcde..104dc6454 100644 --- a/CPP/7zip/Archive/7z/7zHandler.cpp +++ b/CPP/7zip/Archive/7z/7zHandler.cpp @@ -1,879 +1,879 @@ -// 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_LZHAM) - { - name = "LZHAM"; - if (propsSize == 5) - { - char *dest = s; - *dest++ = 'v'; - ConvertUInt32ToString(props[0], dest); - dest += MyStringLen(dest); - *dest++ = ','; - *dest++ = 'd'; - ConvertUInt32ToString(props[1], dest); - dest += MyStringLen(dest); - *dest++ = ','; - *dest++ = 'l'; - ConvertUInt32ToString(props[2], dest); - dest += MyStringLen(dest); - } - } - else if (id == k_BROTLI) - { - name = "Brotli"; - if (propsSize == 3) - { - char *dest = s; - *dest++ = 'v'; - ConvertUInt32ToString(props[0], dest); - dest += MyStringLen(dest); - *dest++ = '.'; - ConvertUInt32ToString(props[1], dest); - dest += MyStringLen(dest); - *dest++ = ','; - *dest++ = 'l'; - ConvertUInt32ToString(props[2], dest); - dest += MyStringLen(dest); - } - } - else if (id == k_LIZARD) - { - name = "Lizard"; - if (propsSize == 3) - { - char *dest = s; - *dest++ = 'v'; - ConvertUInt32ToString(props[0], dest); - dest += MyStringLen(dest); - *dest++ = '.'; - ConvertUInt32ToString(props[1], dest); - dest += MyStringLen(dest); - *dest++ = ','; - *dest++ = 'l'; - ConvertUInt32ToString(props[2], dest); - dest += MyStringLen(dest); - } - } - else if (id == k_LZ4) - { - name = "LZ4"; - if (propsSize == 3 || propsSize == 5) - { - char *dest = s; - *dest++ = 'v'; - ConvertUInt32ToString(props[0], dest); - dest += MyStringLen(dest); - *dest++ = '.'; - ConvertUInt32ToString(props[1], dest); - dest += MyStringLen(dest); - *dest++ = ','; - *dest++ = 'l'; - ConvertUInt32ToString(props[2], dest); - dest += MyStringLen(dest); - } - } - else if (id == k_LZ5) - { - name = "LZ5"; - if (propsSize == 3 || propsSize == 5) - { - char *dest = s; - *dest++ = 'v'; - ConvertUInt32ToString(props[0], dest); - dest += MyStringLen(dest); - *dest++ = '.'; - ConvertUInt32ToString(props[1], dest); - dest += MyStringLen(dest); - *dest++ = ','; - *dest++ = 'l'; - ConvertUInt32ToString(props[2], dest); - dest += MyStringLen(dest); - } - } - else if (id == k_ZSTD) - { - name = "ZSTD"; - if (propsSize == 3 || propsSize == 5) - { - char *dest = s; - UInt32 l = props[2]; - *dest++ = 'v'; - ConvertUInt32ToString(props[0], dest); - dest += MyStringLen(dest); - *dest++ = '.'; - ConvertUInt32ToString(props[1], dest); - dest += MyStringLen(dest); - *dest++ = ','; - if (l <= 22) { - *dest++ = 'l'; - ConvertUInt32ToString(l, dest); - } else { - *dest++ = 'f'; - *dest++ = 'l'; - ConvertUInt32ToString(l - 32, dest); - } - dest += MyStringLen(dest); - } - } - 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 openArchiveCallbackTemp = openArchiveCallback; - - #ifndef _NO_CRYPTO - CMyComPtr 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 __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_LZHAM) + { + name = "LZHAM"; + if (propsSize == 5) + { + char *dest = s; + *dest++ = 'v'; + ConvertUInt32ToString(props[0], dest); + dest += MyStringLen(dest); + *dest++ = ','; + *dest++ = 'd'; + ConvertUInt32ToString(props[1], dest); + dest += MyStringLen(dest); + *dest++ = ','; + *dest++ = 'l'; + ConvertUInt32ToString(props[2], dest); + dest += MyStringLen(dest); + } + } + else if (id == k_BROTLI) + { + name = "Brotli"; + if (propsSize == 3) + { + char *dest = s; + *dest++ = 'v'; + ConvertUInt32ToString(props[0], dest); + dest += MyStringLen(dest); + *dest++ = '.'; + ConvertUInt32ToString(props[1], dest); + dest += MyStringLen(dest); + *dest++ = ','; + *dest++ = 'l'; + ConvertUInt32ToString(props[2], dest); + dest += MyStringLen(dest); + } + } + else if (id == k_LIZARD) + { + name = "Lizard"; + if (propsSize == 3) + { + char *dest = s; + *dest++ = 'v'; + ConvertUInt32ToString(props[0], dest); + dest += MyStringLen(dest); + *dest++ = '.'; + ConvertUInt32ToString(props[1], dest); + dest += MyStringLen(dest); + *dest++ = ','; + *dest++ = 'l'; + ConvertUInt32ToString(props[2], dest); + dest += MyStringLen(dest); + } + } + else if (id == k_LZ4) + { + name = "LZ4"; + if (propsSize == 3 || propsSize == 5) + { + char *dest = s; + *dest++ = 'v'; + ConvertUInt32ToString(props[0], dest); + dest += MyStringLen(dest); + *dest++ = '.'; + ConvertUInt32ToString(props[1], dest); + dest += MyStringLen(dest); + *dest++ = ','; + *dest++ = 'l'; + ConvertUInt32ToString(props[2], dest); + dest += MyStringLen(dest); + } + } + else if (id == k_LZ5) + { + name = "LZ5"; + if (propsSize == 3 || propsSize == 5) + { + char *dest = s; + *dest++ = 'v'; + ConvertUInt32ToString(props[0], dest); + dest += MyStringLen(dest); + *dest++ = '.'; + ConvertUInt32ToString(props[1], dest); + dest += MyStringLen(dest); + *dest++ = ','; + *dest++ = 'l'; + ConvertUInt32ToString(props[2], dest); + dest += MyStringLen(dest); + } + } + else if (id == k_ZSTD) + { + name = "ZSTD"; + if (propsSize == 3 || propsSize == 5) + { + char *dest = s; + UInt32 l = props[2]; + *dest++ = 'v'; + ConvertUInt32ToString(props[0], dest); + dest += MyStringLen(dest); + *dest++ = '.'; + ConvertUInt32ToString(props[1], dest); + dest += MyStringLen(dest); + *dest++ = ','; + if (l <= 22) { + *dest++ = 'l'; + ConvertUInt32ToString(l, dest); + } else { + *dest++ = 'f'; + *dest++ = 'l'; + ConvertUInt32ToString(l - 32, dest); + } + dest += MyStringLen(dest); + } + } + 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 openArchiveCallbackTemp = openArchiveCallback; + + #ifndef _NO_CRYPTO + CMyComPtr 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 + +}} diff --git a/CPP/7zip/Archive/7z/7zHandler.h b/CPP/7zip/Archive/7z/7zHandler.h index 7d5a5f009..99942eb0e 100644 --- a/CPP/7zip/Archive/7z/7zHandler.h +++ b/CPP/7zip/Archive/7z/7zHandler.h @@ -1,181 +1,181 @@ -// 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 _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 _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 _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 __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 _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 _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 _fileInfoPopIDs; + void FillPopIDs(); + void AddMethodName(AString &s, UInt64 id); + HRESULT SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const; + + #endif + + DECL_EXTERNAL_CODECS_VARS +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp index 123143e71..b1561251d 100644 --- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp +++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp @@ -1,943 +1,943 @@ -// 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 "zstd" -#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 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 &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 &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 &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 getRawProps; - updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps); - - CUniqBlocks secureBlocks; - secureBlocks.AddUniq(NULL, 0); - - CObjectVector treeFolders; - { - CTreeFolder folder; - folder.Parent = -1; - treeFolders.Add(folder); - } - */ - - CObjectVector 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 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); - // use BCJ for all levels, BCJ2 uses LZMA2! /TR 2016-03-03 - // 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 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 EXTRACT_ONLY + +using namespace NWindows; + +namespace NArchive { +namespace N7z { + +#define k_LZMA_Name "LZMA" +#define kDefaultMethodName "zstd" +#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 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 &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 &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 &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 getRawProps; + updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps); + + CUniqBlocks secureBlocks; + secureBlocks.AddUniq(NULL, 0); + + CObjectVector treeFolders; + { + CTreeFolder folder; + folder.Parent = -1; + treeFolders.Add(folder); + } + */ + + CObjectVector 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 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); + // use BCJ for all levels, BCJ2 uses LZMA2! /TR 2016-03-03 + // 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 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 diff --git a/CPP/7zip/Archive/7z/7zHeader.cpp b/CPP/7zip/Archive/7z/7zHeader.cpp index de3990961..acff2fdd8 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 _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 b8789b479..66b8779a8 100644 --- a/CPP/7zip/Archive/7z/7zHeader.h +++ b/CPP/7zip/Archive/7z/7zHeader.h @@ -1,155 +1,155 @@ -// 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_LZHAM = 0x4F71001; -const UInt32 k_ZSTD = 0x4F71101; -const UInt32 k_BROTLI= 0x4F71102; -const UInt32 k_LZ4 = 0x4F71104; -const UInt32 k_LZ5 = 0x4F71105; -const UInt32 k_LIZARD= 0x4F71106; - -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 __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_LZHAM = 0x4F71001; +const UInt32 k_ZSTD = 0x4F71101; +const UInt32 k_BROTLI= 0x4F71102; +const UInt32 k_LZ4 = 0x4F71104; +const UInt32 k_LZ5 = 0x4F71105; +const UInt32 k_LIZARD= 0x4F71106; + +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 diff --git a/CPP/7zip/Archive/7z/7zIn.cpp b/CPP/7zip/Archive/7z/7zIn.cpp index ae5ff196a..ab5b5de4e 100644 --- a/CPP/7zip/Archive/7z/7zIn.cpp +++ b/CPP/7zip/Archive/7z/7zIn.cpp @@ -1,1666 +1,1666 @@ -// 7zIn.cpp - -#include "StdAfx.h" - -#ifdef _WIN32 -#include -#else -#include -#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 *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 *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 *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 &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 *dataVector, - UInt64 &dataOffset, - CFolders &folders, - CRecordVector &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 &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 &dataVector - _7Z_DECODER_CRYPRO_VARS_DECL - ) -{ - CFolders folders; - CRecordVector 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 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 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 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 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 +#else +#include +#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 *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 *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 *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 &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 *dataVector, + UInt64 &dataOffset, + CFolders &folders, + CRecordVector &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 &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 &dataVector + _7Z_DECODER_CRYPRO_VARS_DECL + ) +{ + CFolders folders; + CRecordVector 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 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 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 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 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; + } +} + +}} diff --git a/CPP/7zip/Archive/7z/7zIn.h b/CPP/7zip/Archive/7z/7zIn.h index bb0e47484..6a61d314d 100644 --- a/CPP/7zip/Archive/7z/7zIn.h +++ b/CPP/7zip/Archive/7z/7zIn.h @@ -1,445 +1,445 @@ -// 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 IDs; - - CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {} -}; - -struct CFolderEx: public CFolder -{ - unsigned UnpackCoder; -}; - -struct CFolders -{ - CNum NumPackStreams; - CNum NumFolders; - - CObjArray PackPositions; // NumPackStreams + 1 - // CUInt32DefVector PackCRCs; // we don't use PackCRCs now - - CUInt32DefVector FolderCRCs; // NumFolders - CObjArray NumUnpackStreamsVector; // NumFolders - - CObjArray CoderUnpackSizes; // including unpack sizes of bond coders - CObjArray FoToCoderUnpackSizes; // NumFolders + 1 - CObjArray FoStartPackStreamIndex; // NumFolders + 1 - CObjArray FoToMainUnpackSizeIndex; // NumFolders - - CObjArray 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 Files; - - CUInt64DefVector CTime; - CUInt64DefVector ATime; - CUInt64DefVector MTime; - CUInt64DefVector StartPos; - CUInt32DefVector Attrib; - CBoolVector IsAnti; - /* - CBoolVector IsAux; - CByteBuffer SecureBuf; - CRecordVector SecureIDs; - */ - - CByteBuffer NamesBuf; - CObjArray 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 FileInfoPopIDs; - - void Clear() - { - StartPosition = 0; - StartPositionAfterHeader = 0; - DataStartPosition = 0; - DataStartPosition2 = 0; - FileInfoPopIDs.Clear(); - } -}; - -struct CDbEx: public CDatabase -{ - CInArchiveInfo ArcInfo; - - CObjArray FolderStartFileIndex; - CObjArray FileIndexToFolderIndexMap; - - UInt64 HeadersSize; - UInt64 PhySize; - - /* - CRecordVector 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 _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 *dataVector, - CFolders &folders); - - void ReadSubStreamsInfo( - CFolders &folders, - CRecordVector &unpackSizes, - CUInt32DefVector &digests); - - void ReadStreamsInfo( - const CObjectVector *dataVector, - UInt64 &dataOffset, - CFolders &folders, - CRecordVector &unpackSizes, - CUInt32DefVector &digests); - - void ReadBoolVector(unsigned numItems, CBoolVector &v); - void ReadBoolVector2(unsigned numItems, CBoolVector &v); - void ReadUInt64DefVector(const CObjectVector &dataVector, - CUInt64DefVector &v, unsigned numItems); - HRESULT ReadAndDecodePackedStreams( - DECL_EXTERNAL_CODECS_LOC_VARS - UInt64 baseOffset, UInt64 &dataOffset, - CObjectVector &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 __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 IDs; + + CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {} +}; + +struct CFolderEx: public CFolder +{ + unsigned UnpackCoder; +}; + +struct CFolders +{ + CNum NumPackStreams; + CNum NumFolders; + + CObjArray PackPositions; // NumPackStreams + 1 + // CUInt32DefVector PackCRCs; // we don't use PackCRCs now + + CUInt32DefVector FolderCRCs; // NumFolders + CObjArray NumUnpackStreamsVector; // NumFolders + + CObjArray CoderUnpackSizes; // including unpack sizes of bond coders + CObjArray FoToCoderUnpackSizes; // NumFolders + 1 + CObjArray FoStartPackStreamIndex; // NumFolders + 1 + CObjArray FoToMainUnpackSizeIndex; // NumFolders + + CObjArray 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 Files; + + CUInt64DefVector CTime; + CUInt64DefVector ATime; + CUInt64DefVector MTime; + CUInt64DefVector StartPos; + CUInt32DefVector Attrib; + CBoolVector IsAnti; + /* + CBoolVector IsAux; + CByteBuffer SecureBuf; + CRecordVector SecureIDs; + */ + + CByteBuffer NamesBuf; + CObjArray 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 FileInfoPopIDs; + + void Clear() + { + StartPosition = 0; + StartPositionAfterHeader = 0; + DataStartPosition = 0; + DataStartPosition2 = 0; + FileInfoPopIDs.Clear(); + } +}; + +struct CDbEx: public CDatabase +{ + CInArchiveInfo ArcInfo; + + CObjArray FolderStartFileIndex; + CObjArray FileIndexToFolderIndexMap; + + UInt64 HeadersSize; + UInt64 PhySize; + + /* + CRecordVector 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 _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 *dataVector, + CFolders &folders); + + void ReadSubStreamsInfo( + CFolders &folders, + CRecordVector &unpackSizes, + CUInt32DefVector &digests); + + void ReadStreamsInfo( + const CObjectVector *dataVector, + UInt64 &dataOffset, + CFolders &folders, + CRecordVector &unpackSizes, + CUInt32DefVector &digests); + + void ReadBoolVector(unsigned numItems, CBoolVector &v); + void ReadBoolVector2(unsigned numItems, CBoolVector &v); + void ReadUInt64DefVector(const CObjectVector &dataVector, + CUInt64DefVector &v, unsigned numItems); + HRESULT ReadAndDecodePackedStreams( + DECL_EXTERNAL_CODECS_LOC_VARS + UInt64 baseOffset, UInt64 &dataOffset, + CObjectVector &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 diff --git a/CPP/7zip/Archive/7z/7zItem.h b/CPP/7zip/Archive/7z/7zItem.h index 90cf98c53..ee4aed3f0 100644 --- a/CPP/7zip/Archive/7z/7zItem.h +++ b/CPP/7zip/Archive/7z/7zItem.h @@ -1,202 +1,202 @@ -// 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 Coders; - CObjArray2 Bonds; - CObjArray2 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 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 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 __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 Coders; + CObjArray2 Bonds; + CObjArray2 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 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 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 5bd3a417f..aa977292f 100644 --- a/CPP/7zip/Archive/7z/7zOut.cpp +++ b/CPP/7zip/Archive/7z/7zOut.cpp @@ -1,901 +1,901 @@ -// 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 &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 &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 &folders, - const COutFolders &outFolders, - const CRecordVector &unpackSizes, - const CUInt32DefVector &digests) -{ - const CRecordVector &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 &packSizes, CObjectVector &folders, COutFolders &outFolders) -{ - CBufInStream *streamSpec = new CBufInStream; - CMyComPtr 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 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 packSizes; - CObjectVector 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/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 &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 &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 &folders, + const COutFolders &outFolders, + const CRecordVector &unpackSizes, + const CUInt32DefVector &digests) +{ + const CRecordVector &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 &packSizes, CObjectVector &folders, COutFolders &outFolders) +{ + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr 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 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 packSizes; + CObjectVector 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); +} + +}} diff --git a/CPP/7zip/Archive/7z/7zOut.h b/CPP/7zip/Archive/7z/7zOut.h index 12e965f86..1ebad56d2 100644 --- a/CPP/7zip/Archive/7z/7zOut.h +++ b/CPP/7zip/Archive/7z/7zOut.h @@ -1,335 +1,335 @@ -// 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 NumUnpackStreamsVector; - CRecordVector 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 PackSizes; - CUInt32DefVector PackCRCs; - CObjectVector Folders; - - CRecordVector Files; - UStringVector Names; - CUInt64DefVector CTime; - CUInt64DefVector ATime; - CUInt64DefVector MTime; - CUInt64DefVector StartPos; - CUInt32DefVector Attrib; - CBoolVector IsAnti; - - /* - CBoolVector IsAux; - - CByteBuffer SecureBuf; - CRecordVector SecureSizes; - CRecordVector 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 &packSizes, - const CUInt32DefVector &packCRCs); - - void WriteUnpackInfo( - const CObjectVector &folders, - const COutFolders &outFolders); - - void WriteSubStreamsInfo( - const CObjectVector &folders, - const COutFolders &outFolders, - const CRecordVector &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 &packSizes, CObjectVector &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 Stream; -public: - - COutArchive() { _outByte.Create(1 << 16); } - CMyComPtr 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 __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 NumUnpackStreamsVector; + CRecordVector 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 PackSizes; + CUInt32DefVector PackCRCs; + CObjectVector Folders; + + CRecordVector Files; + UStringVector Names; + CUInt64DefVector CTime; + CUInt64DefVector ATime; + CUInt64DefVector MTime; + CUInt64DefVector StartPos; + CUInt32DefVector Attrib; + CBoolVector IsAnti; + + /* + CBoolVector IsAux; + + CByteBuffer SecureBuf; + CRecordVector SecureSizes; + CRecordVector 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 &packSizes, + const CUInt32DefVector &packCRCs); + + void WriteUnpackInfo( + const CObjectVector &folders, + const COutFolders &outFolders); + + void WriteSubStreamsInfo( + const CObjectVector &folders, + const COutFolders &outFolders, + const CRecordVector &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 &packSizes, CObjectVector &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 Stream; +public: + + COutArchive() { _outByte.Create(1 << 16); } + CMyComPtr 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 diff --git a/CPP/7zip/Archive/7z/7zProperties.cpp b/CPP/7zip/Archive/7z/7zProperties.cpp index 388ac766c..4cb5a5e64 100644 --- a/CPP/7zip/Archive/7z/7zProperties.cpp +++ b/CPP/7zip/Archive/7z/7zProperties.cpp @@ -1,174 +1,174 @@ -// 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 &src, - CRecordVector &dest, UInt32 item) -{ - FOR_VECTOR (i, src) - if (src[i] == item) - { - dest.Add(item); - src.Delete(i); - return; - } -} - -static void RemoveOneItem(CRecordVector &src, UInt32 item) -{ - FOR_VECTOR (i, src) - if (src[i] == item) - { - src.Delete(i); - return; - } -} - -static void InsertToHead(CRecordVector &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 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 "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 &src, + CRecordVector &dest, UInt32 item) +{ + FOR_VECTOR (i, src) + if (src[i] == item) + { + dest.Add(item); + src.Delete(i); + return; + } +} + +static void RemoveOneItem(CRecordVector &src, UInt32 item) +{ + FOR_VECTOR (i, src) + if (src[i] == item) + { + src.Delete(i); + return; + } +} + +static void InsertToHead(CRecordVector &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 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; +} + +}} diff --git a/CPP/7zip/Archive/7z/7zProperties.h b/CPP/7zip/Archive/7z/7zProperties.h index 7b78130ef..661817954 100644 --- a/CPP/7zip/Archive/7z/7zProperties.h +++ b/CPP/7zip/Archive/7z/7zProperties.h @@ -1,22 +1,22 @@ -// 7zProperties.h - -#ifndef __7Z_PROPERTIES_H -#define __7Z_PROPERTIES_H - -#include "../../PropID.h" - -namespace NArchive { -namespace N7z { - -enum -{ - kpidPackedSize0 = kpidUserDefined, - kpidPackedSize1, - kpidPackedSize2, - kpidPackedSize3, - kpidPackedSize4 -}; - -}} - -#endif +// 7zProperties.h + +#ifndef __7Z_PROPERTIES_H +#define __7Z_PROPERTIES_H + +#include "../../PropID.h" + +namespace NArchive { +namespace N7z { + +enum +{ + kpidPackedSize0 = kpidUserDefined, + kpidPackedSize1, + kpidPackedSize2, + kpidPackedSize3, + kpidPackedSize4 +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/7z/7zRegister.cpp b/CPP/7zip/Archive/7z/7zRegister.cpp index 3e8cfb664..389b54074 100644 --- a/CPP/7zip/Archive/7z/7zRegister.cpp +++ b/CPP/7zip/Archive/7z/7zRegister.cpp @@ -1,21 +1,21 @@ -// 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, + NULL); + +}} diff --git a/CPP/7zip/Archive/7z/7zSpecStream.cpp b/CPP/7zip/Archive/7z/7zSpecStream.cpp index e9671a87e..8e45d9875 100644 --- a/CPP/7zip/Archive/7z/7zSpecStream.cpp +++ b/CPP/7zip/Archive/7z/7zSpecStream.cpp @@ -1,22 +1,22 @@ -// 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" + +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); +} diff --git a/CPP/7zip/Archive/7z/7zSpecStream.h b/CPP/7zip/Archive/7z/7zSpecStream.h index 09941287d..21155069f 100644 --- a/CPP/7zip/Archive/7z/7zSpecStream.h +++ b/CPP/7zip/Archive/7z/7zSpecStream.h @@ -1,35 +1,35 @@ -// 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 _stream; - CMyComPtr _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 __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 _stream; + CMyComPtr _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 diff --git a/CPP/7zip/Archive/7z/7zUpdate.cpp b/CPP/7zip/Archive/7z/7zUpdate.cpp index 882ffd6d6..82ca0bc3d 100644 --- a/CPP/7zip/Archive/7z/7zUpdate.cpp +++ b/CPP/7zip/Archive/7z/7zUpdate.cpp @@ -1,2500 +1,2500 @@ -// 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 &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 &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 inStreamLimited(streamSpec); - streamSpec->SetStream(inStream); - streamSpec->Init(size); - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; - CMyComPtr 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 &updateItems = *(const CObjectVector *)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 liz tliz lz tlz lz4 tlz4 lz5 tlz5 lzh lzo lzx pak rar rpm sit zoo zst" - " 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 *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 Indices; - - CRecordVector 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 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 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 _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 _opCallback; - CMyComPtr _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 _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 _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 InStream; - - CFolderOutStream2 *FosSpec; - CMyComPtr Fos; - - UInt64 StartPos; - const CFolders *Folders; - int FolderIndex; - - // bool send_UnpackSize; - // UInt64 UnpackSize; - - #ifndef _NO_CRYPTO - CMyComPtr 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 &updateItems, - // const CObjectVector &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 opCallback; - updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); - - CMyComPtr extractCallback; - updateCallback->QueryInterface(IID_IArchiveExtractCallbackMessage, (void **)&extractCallback); - - // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes(); - - /* - CMyComPtr 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 filters; - CObjectVector 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 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 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 sbInStream; - CRepackStreamBase *repackBase; - CFolderInStream2 *FosSpec2 = NULL; - - CRepackInStreamWithSizes *inStreamSizeCountSpec = new CRepackInStreamWithSizes; - CMyComPtr inStreamSizeCount = inStreamSizeCountSpec; - { - #ifndef _7ZIP_ST - if (options.MultiThreadMixer) - { - repackBase = threadDecoder.FosSpec; - CMyComPtr 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 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 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 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 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/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 &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 &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 inStreamLimited(streamSpec); + streamSpec->SetStream(inStream); + streamSpec->Init(size); + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; + CMyComPtr 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 &updateItems = *(const CObjectVector *)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 liz tliz lz tlz lz4 tlz4 lz5 tlz5 lzh lzo lzx pak rar rpm sit zoo zst" + " 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 *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 Indices; + + CRecordVector 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 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 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 _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 _opCallback; + CMyComPtr _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 _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 _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 InStream; + + CFolderOutStream2 *FosSpec; + CMyComPtr Fos; + + UInt64 StartPos; + const CFolders *Folders; + int FolderIndex; + + // bool send_UnpackSize; + // UInt64 UnpackSize; + + #ifndef _NO_CRYPTO + CMyComPtr 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 &updateItems, + // const CObjectVector &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 opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + + CMyComPtr extractCallback; + updateCallback->QueryInterface(IID_IArchiveExtractCallbackMessage, (void **)&extractCallback); + + // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes(); + + /* + CMyComPtr 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 filters; + CObjectVector 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 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 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 sbInStream; + CRepackStreamBase *repackBase; + CFolderInStream2 *FosSpec2 = NULL; + + CRepackInStreamWithSizes *inStreamSizeCountSpec = new CRepackInStreamWithSizes; + CMyComPtr inStreamSizeCount = inStreamSizeCountSpec; + { + #ifndef _7ZIP_ST + if (options.MultiThreadMixer) + { + repackBase = threadDecoder.FosSpec; + CMyComPtr 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 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 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 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 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; +} + +}} diff --git a/CPP/7zip/Archive/7z/7zUpdate.h b/CPP/7zip/Archive/7z/7zUpdate.h index 06a0b05fb..a7abf779a 100644 --- a/CPP/7zip/Archive/7z/7zUpdate.h +++ b/CPP/7zip/Archive/7z/7zUpdate.h @@ -1,139 +1,139 @@ -// 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 &updateItems, - // const CObjectVector &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 __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 &updateItems, + // const CObjectVector &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 diff --git a/CPP/7zip/Archive/7z/StdAfx.cpp b/CPP/7zip/Archive/7z/StdAfx.cpp index c6d3b1fa6..d0feea85c 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 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Archive/7z/StdAfx.h +++ b/CPP/7zip/Archive/7z/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/7z/makefile b/CPP/7zip/Archive/7z/makefile index 9a7fa222a..a3b077dab 100644 --- a/CPP/7zip/Archive/7z/makefile +++ b/CPP/7zip/Archive/7z/makefile @@ -1,81 +1,81 @@ -PROG = 7z.dll -DEF_FILE = ../Archive.def -CFLAGS = $(CFLAGS) \ - -DEXTERNAL_CODECS \ - -AR_OBJS = \ - $O\ArchiveExports.obj \ - $O\DllExports.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\DLL.obj \ - $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 \ - -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" +PROG = 7z.dll +DEF_FILE = ../Archive.def +CFLAGS = $(CFLAGS) \ + -DEXTERNAL_CODECS \ + +AR_OBJS = \ + $O\ArchiveExports.obj \ + $O\DllExports.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\DLL.obj \ + $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 \ + +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 index 3958af8b9..f79dac088 100644 --- a/CPP/7zip/Archive/7z/resource.rc +++ b/CPP/7zip/Archive/7z/resource.rc @@ -1,11 +1,11 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_DLL("7z Plugin", "7z") - -0 ICON "../Icons/7z.ico" - -STRINGTABLE -BEGIN - 100 "7z:0" -END - +#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/ApmHandler.cpp b/CPP/7zip/Archive/ApmHandler.cpp index 645927ab4..4d3f27289 100644 --- a/CPP/7zip/Archive/ApmHandler.cpp +++ b/CPP/7zip/Archive/ApmHandler.cpp @@ -1,315 +1,315 @@ -// 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; - } -}; - -class CHandler: public CHandlerCont -{ - CRecordVector _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 - { - const CItem &item = _items[index]; - pos = BlocksToBytes(item.StartBlock); - size = BlocksToBytes(item.NumBlocks); - return NExtract::NOperationResult::kOK; - } - -public: - INTERFACE_IInArchive_Cont(;) -}; - -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; -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */) -{ - COM_TRY_BEGIN - Close(); - RINOK(ReadTables(stream)); - _stream = stream; - return S_OK; - COM_TRY_END -} - -STDMETHODIMP 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; -} - -STDMETHODIMP 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 = i; - } - } - if (mainIndex >= 0) - prop = (UInt32)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 -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - const CItem &item = _items[index]; - switch (propID) - { - case kpidPath: - { - AString s (GetString(item.Name)); - if (s.IsEmpty()) - s.Add_UInt32(index); - AString type (GetString(item.Type)); - if (type == "Apple_HFS") - type = "hfs"; - if (!type.IsEmpty()) - { - s += '.'; - s += type; - } - prop = s; - break; - } - case kpidSize: - case kpidPackSize: - prop = 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", 0, 0xD4, - k_Signature, - 0, - 0, - IsArc_Apm) - -}} +// 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; + } +}; + +class CHandler: public CHandlerCont +{ + CRecordVector _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 + { + const CItem &item = _items[index]; + pos = BlocksToBytes(item.StartBlock); + size = BlocksToBytes(item.NumBlocks); + return NExtract::NOperationResult::kOK; + } + +public: + INTERFACE_IInArchive_Cont(;) +}; + +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; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */) +{ + COM_TRY_BEGIN + Close(); + RINOK(ReadTables(stream)); + _stream = stream; + return S_OK; + COM_TRY_END +} + +STDMETHODIMP 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; +} + +STDMETHODIMP 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 = i; + } + } + if (mainIndex >= 0) + prop = (UInt32)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 +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + const CItem &item = _items[index]; + switch (propID) + { + case kpidPath: + { + AString s (GetString(item.Name)); + if (s.IsEmpty()) + s.Add_UInt32(index); + AString type (GetString(item.Type)); + if (type == "Apple_HFS") + type = "hfs"; + if (!type.IsEmpty()) + { + s += '.'; + s += type; + } + prop = s; + break; + } + case kpidSize: + case kpidPackSize: + prop = 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", 0, 0xD4, + k_Signature, + 0, + 0, + IsArc_Apm) + +}} diff --git a/CPP/7zip/Archive/ArHandler.cpp b/CPP/7zip/Archive/ArHandler.cpp index 85feeeabf..09a622017 100644 --- a/CPP/7zip/Archive/ArHandler.cpp +++ b/CPP/7zip/Archive/ArHandler.cpp @@ -1,854 +1,854 @@ -// 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; - -#define SIGNATURE { '!', '<', 'a', 'r', 'c', 'h', '>', 0x0A } - -static const Byte kSignature[kSignatureLen] = SIGNATURE; - -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 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(dataSize + (dataSize & 1), STREAM_SEEK_CUR, &Position); - } -}; - -HRESULT CInArchive::Open(IInStream *inStream) -{ - SubType = kSubType_None; - RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &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; -} - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - CObjectVector _items; - CMyComPtr _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); -public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); -}; - -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, - kpidUser, - kpidGroup -}; - -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(stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL)); - 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; - char c = p[pos]; - if (c == 0 || c == 0x0A) - break; - pos++; - } - item2.Name.SetFrom((const char *)(p + start), pos - start); - } - - _longNames_FileIndex = 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(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) - { - unsigned mid = (left + right) / 2; - UInt64 midVal = _items[mid].HeaderPos; - if (offset == midVal) - return 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) -{ - 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[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(stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL)); - 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++) - { - UInt32 tableSize = Get32(p, be); - pos = 4; - if (size - pos < tableSize || (tableSize & 7) != 0) - continue; - size_t namesStart = pos + tableSize; - UInt32 namesSize = Get32(p + namesStart, be); - namesStart += 4; - if (namesStart > size || namesStart + namesSize != size) - continue; - - UInt32 numSymbols = tableSize >> 3; - UInt32 i; - for (i = 0; i < numSymbols; i++, pos += 8) - { - size_t namePos = Get32(p + pos, be); - 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) - UInt32 numSymbols = GetBe32(p); - pos = 4; - if (numSymbols > (size - pos) / 4) - return S_FALSE; - pos += 4 * numSymbols; - - for (UInt32 i = 0; i < numSymbols; i++) - { - UInt32 offset = GetBe32(p + 4 + i * 4); - RINOK(AddFunc(offset, p, size, pos)); - } - _type = kType_ALib; - } - else - { - // Second linker file (Microsoft .lib) - UInt32 numMembers = GetUi32(p); - pos = 4; - if (numMembers > (size - pos) / 4) - return S_FALSE; - pos += 4 * numMembers; - - if (size - pos < 4) - return S_FALSE; - 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] - UInt32 index = GetUi16(p + indexStart + i * 2); - if (index == 0 || index > numMembers) - return S_FALSE; - 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 = _numLibFiles++; - return S_OK; -} - -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback *callback) -{ - COM_TRY_BEGIN - { - Close(); - - UInt64 fileSize = 0; - RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); - RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); - - CInArchive arc; - RINOK(arc.Open(stream)); - - if (callback) - { - RINOK(callback->SetTotal(NULL, &fileSize)); - 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(_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 = 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 -} - -STDMETHODIMP 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; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items.Size(); - return S_OK; -} - -STDMETHODIMP 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 -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem &item = _items[index]; - switch (propID) - { - case kpidPath: - 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) - { - FILETIME fileTime; - NTime::UnixTimeToFileTime(item.MTime, fileTime); - prop = fileTime; - } - break; - } - case kpidUser: if (item.User != 0) prop = item.User; break; - case kpidGroup: 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 -} - -STDMETHODIMP 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 (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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_stream); - - for (i = 0; i < numItems; i++) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()); - CMyComPtr realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - currentTotalSize += (item.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(_stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL)); - 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 -} - -STDMETHODIMP 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 lib", 0, 0xEC, - kSignature, - 0, - 0, - NULL) - -}} +// 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; + +#define SIGNATURE { '!', '<', 'a', 'r', 'c', 'h', '>', 0x0A } + +static const Byte kSignature[kSignatureLen] = SIGNATURE; + +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 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(dataSize + (dataSize & 1), STREAM_SEEK_CUR, &Position); + } +}; + +HRESULT CInArchive::Open(IInStream *inStream) +{ + SubType = kSubType_None; + RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &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; +} + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CObjectVector _items; + CMyComPtr _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); +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +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, + kpidUser, + kpidGroup +}; + +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(stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL)); + 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; + char c = p[pos]; + if (c == 0 || c == 0x0A) + break; + pos++; + } + item2.Name.SetFrom((const char *)(p + start), pos - start); + } + + _longNames_FileIndex = 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(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) + { + unsigned mid = (left + right) / 2; + UInt64 midVal = _items[mid].HeaderPos; + if (offset == midVal) + return 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) +{ + 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[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(stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL)); + 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++) + { + UInt32 tableSize = Get32(p, be); + pos = 4; + if (size - pos < tableSize || (tableSize & 7) != 0) + continue; + size_t namesStart = pos + tableSize; + UInt32 namesSize = Get32(p + namesStart, be); + namesStart += 4; + if (namesStart > size || namesStart + namesSize != size) + continue; + + UInt32 numSymbols = tableSize >> 3; + UInt32 i; + for (i = 0; i < numSymbols; i++, pos += 8) + { + size_t namePos = Get32(p + pos, be); + 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) + UInt32 numSymbols = GetBe32(p); + pos = 4; + if (numSymbols > (size - pos) / 4) + return S_FALSE; + pos += 4 * numSymbols; + + for (UInt32 i = 0; i < numSymbols; i++) + { + UInt32 offset = GetBe32(p + 4 + i * 4); + RINOK(AddFunc(offset, p, size, pos)); + } + _type = kType_ALib; + } + else + { + // Second linker file (Microsoft .lib) + UInt32 numMembers = GetUi32(p); + pos = 4; + if (numMembers > (size - pos) / 4) + return S_FALSE; + pos += 4 * numMembers; + + if (size - pos < 4) + return S_FALSE; + 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] + UInt32 index = GetUi16(p + indexStart + i * 2); + if (index == 0 || index > numMembers) + return S_FALSE; + 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 = _numLibFiles++; + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + { + Close(); + + UInt64 fileSize = 0; + RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + + CInArchive arc; + RINOK(arc.Open(stream)); + + if (callback) + { + RINOK(callback->SetTotal(NULL, &fileSize)); + 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(_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 = 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 +} + +STDMETHODIMP 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; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP 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 +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem &item = _items[index]; + switch (propID) + { + case kpidPath: + 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) + { + FILETIME fileTime; + NTime::UnixTimeToFileTime(item.MTime, fileTime); + prop = fileTime; + } + break; + } + case kpidUser: if (item.User != 0) prop = item.User; break; + case kpidGroup: 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 +} + +STDMETHODIMP 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 (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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(_stream); + + for (i = 0; i < numItems; i++) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + CMyComPtr realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + currentTotalSize += (item.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(_stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL)); + 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 +} + +STDMETHODIMP 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 lib", 0, 0xEC, + kSignature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/Archive.def b/CPP/7zip/Archive/Archive.def index a3fe6ddaa..145516d79 100644 --- a/CPP/7zip/Archive/Archive.def +++ b/CPP/7zip/Archive/Archive.def @@ -1,12 +1,12 @@ -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 diff --git a/CPP/7zip/Archive/Archive2.def b/CPP/7zip/Archive/Archive2.def index de744b5f7..c75827421 100644 --- a/CPP/7zip/Archive/Archive2.def +++ b/CPP/7zip/Archive/Archive2.def @@ -1,19 +1,19 @@ -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 diff --git a/CPP/7zip/Archive/ArchiveExports.cpp b/CPP/7zip/Archive/ArchiveExports.cpp index 94f2fff00..28e9946d5 100644 --- a/CPP/7zip/Archive/ArchiveExports.cpp +++ b/CPP/7zip/Archive/ArchiveExports.cpp @@ -1,151 +1,151 @@ -// 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 = 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; +} diff --git a/CPP/7zip/Archive/ArjHandler.cpp b/CPP/7zip/Archive/ArjHandler.cpp index 85649d596..fb9e3e7ad 100644 --- a/CPP/7zip/Archive/ArjHandler.cpp +++ b/CPP/7zip/Archive/ArjHandler.cpp @@ -1,968 +1,968 @@ -// 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) - -class CCoder: - public ICompressCoder, - public CMyUnknownImp -{ - CLzOutWindow _outWindow; - NBitm::CDecoder _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: - MY_UNKNOWN_IMP - - bool FinishMode; - CCoder(): FinishMode(false) {} - - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - 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; -} - - - -STDMETHODIMP 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 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; - - 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; - - HRESULT Open(); - HRESULT GetNextItem(CItem &item, bool &filled); - void Close() - { - IsArc = false; - Error = k_ErrorType_OK; - } -private: - UInt32 _blockSize; - Byte _block[kBlockSizeMax + 4]; - - HRESULT ReadBlock(bool &filled, bool readSignature); - HRESULT SkipExtendedHeaders(); - 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, bool readSignature) -{ - Error = k_ErrorType_OK; - filled = false; - Byte buf[4]; - unsigned signSize = readSignature ? 2 : 0; - READ_STREAM(buf, signSize + 2) - if (readSignature) - 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 (_blockSize < kBlockSizeMin || - _blockSize > kBlockSizeMax) - { - Error = k_ErrorType_Corrupted; - return S_OK; - } - READ_STREAM(_block, _blockSize + 4); - if (Get32(_block + _blockSize) != CrcCalc(_block, _blockSize)) - { - Error = k_ErrorType_Corrupted; - return S_OK; - } - filled = true; - return S_OK; -} - -HRESULT CArc::SkipExtendedHeaders() -{ - for (UInt32 i = 0;; i++) - { - bool filled; - RINOK(ReadBlock(filled, false)); - if (!filled) - return S_OK; - if (Callback && (i & 0xFF) == 0) - RINOK(Callback->SetCompleted(&NumFiles, &Processed)); - } -} - -HRESULT CArc::Open() -{ - bool filled; - RINOK(ReadBlock(filled, true)); - if (!filled) - return S_FALSE; - RINOK(Header.Parse(_block, _blockSize)); - IsArc = true; - return SkipExtendedHeaders(); -} - -HRESULT CArc::GetNextItem(CItem &item, bool &filled) -{ - RINOK(ReadBlock(filled, true)); - 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()); - filled = true; - return S_OK; -} - -class CHandler: - public IInArchive, - public CMyUnknownImp -{ - CObjectVector _items; - CMyComPtr _stream; - UInt64 _phySize; - CArc _arc; -public: - MY_UNKNOWN_IMP1(IInArchive) - - INTERFACE_IInArchive(;) - - HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback); -}; - -static const Byte kArcProps[] = -{ - kpidName, - kpidCTime, - kpidMTime, - kpidHostOS, - kpidComment -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPosition, - kpidPackSize, - kpidMTime, - kpidAttrib, - kpidEncrypted, - kpidCRC, - kpidMethod, - kpidHostOS, - kpidComment -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -static void SetTime(UInt32 dosTime, NCOM::CPropVariant &prop) -{ - if (dosTime == 0) - return; - FILETIME localFileTime, utc; - if (NTime::DosTimeToFileTime(dosTime, localFileTime)) - { - if (!LocalFileTimeToFileTime(&localFileTime, &utc)) - utc.dwHighDateTime = utc.dwLowDateTime = 0; - } - else - utc.dwHighDateTime = utc.dwLowDateTime = 0; - prop = utc; -} - -static void SetHostOS(Byte hostOS, 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); -} - -STDMETHODIMP 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; - } - prop = v; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - const CItem &item = _items[index]; - switch (propID) - { - case kpidPath: 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; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -HRESULT CHandler::Open2(IInStream *inStream, IArchiveOpenCallback *callback) -{ - Close(); - - UInt64 endPos = 0; - RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); - RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); - - _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->Seek(pos, STREAM_SEEK_SET, NULL)); - _arc.NumFiles = _items.Size(); - _arc.Processed = pos; - - if (callback && (_items.Size() & 0xFF) == 0) - { - RINOK(callback->SetCompleted(&_arc.NumFiles, &_arc.Processed)); - } - } - return S_OK; -} - -STDMETHODIMP 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 -} - -STDMETHODIMP CHandler::Close() -{ - _arc.Close(); - _phySize = 0; - _items.Clear(); - _stream.Release(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - UInt64 totalUnpacked = 0, totalPacked = 0; - bool allFilesMode = (numItems == (UInt32)(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 lzhDecoder; - - NCompress::NArj::NDecoder::CCoder *arjDecoderSpec = NULL; - CMyComPtr arjDecoder; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream; - CMyComPtr 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 realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - - if (item.IsDir()) - { - // if (!testMode) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - } - continue; - } - - if (!testMode && !realOutStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)); - curUnpacked = item.Size; - curPacked = item.PackSize; - - { - COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; - CMyComPtr outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - realOutStream.Release(); - outStreamSpec->Init(); - - inStreamSpec->Init(item.PackSize); - - UInt64 pos; - _stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos); - - HRESULT result = S_OK; - Int32 opRes = NExtract::NOperationResult::kOK; - - if (item.IsEncrypted()) - opRes = NExtract::NOperationResult::kUnsupportedMethod; - else - { - switch (item.Method) - { - case 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", 0, 4, - k_Signature, - 0, - 0, - IsArc_Arj) - -}} +// 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) + +class CCoder: + public ICompressCoder, + public CMyUnknownImp +{ + CLzOutWindow _outWindow; + NBitm::CDecoder _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: + MY_UNKNOWN_IMP + + bool FinishMode; + CCoder(): FinishMode(false) {} + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + 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; +} + + + +STDMETHODIMP 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 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; + + 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; + + HRESULT Open(); + HRESULT GetNextItem(CItem &item, bool &filled); + void Close() + { + IsArc = false; + Error = k_ErrorType_OK; + } +private: + UInt32 _blockSize; + Byte _block[kBlockSizeMax + 4]; + + HRESULT ReadBlock(bool &filled, bool readSignature); + HRESULT SkipExtendedHeaders(); + 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, bool readSignature) +{ + Error = k_ErrorType_OK; + filled = false; + Byte buf[4]; + unsigned signSize = readSignature ? 2 : 0; + READ_STREAM(buf, signSize + 2) + if (readSignature) + 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 (_blockSize < kBlockSizeMin || + _blockSize > kBlockSizeMax) + { + Error = k_ErrorType_Corrupted; + return S_OK; + } + READ_STREAM(_block, _blockSize + 4); + if (Get32(_block + _blockSize) != CrcCalc(_block, _blockSize)) + { + Error = k_ErrorType_Corrupted; + return S_OK; + } + filled = true; + return S_OK; +} + +HRESULT CArc::SkipExtendedHeaders() +{ + for (UInt32 i = 0;; i++) + { + bool filled; + RINOK(ReadBlock(filled, false)); + if (!filled) + return S_OK; + if (Callback && (i & 0xFF) == 0) + RINOK(Callback->SetCompleted(&NumFiles, &Processed)); + } +} + +HRESULT CArc::Open() +{ + bool filled; + RINOK(ReadBlock(filled, true)); + if (!filled) + return S_FALSE; + RINOK(Header.Parse(_block, _blockSize)); + IsArc = true; + return SkipExtendedHeaders(); +} + +HRESULT CArc::GetNextItem(CItem &item, bool &filled) +{ + RINOK(ReadBlock(filled, true)); + 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()); + filled = true; + return S_OK; +} + +class CHandler: + public IInArchive, + public CMyUnknownImp +{ + CObjectVector _items; + CMyComPtr _stream; + UInt64 _phySize; + CArc _arc; +public: + MY_UNKNOWN_IMP1(IInArchive) + + INTERFACE_IInArchive(;) + + HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback); +}; + +static const Byte kArcProps[] = +{ + kpidName, + kpidCTime, + kpidMTime, + kpidHostOS, + kpidComment +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPosition, + kpidPackSize, + kpidMTime, + kpidAttrib, + kpidEncrypted, + kpidCRC, + kpidMethod, + kpidHostOS, + kpidComment +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +static void SetTime(UInt32 dosTime, NCOM::CPropVariant &prop) +{ + if (dosTime == 0) + return; + FILETIME localFileTime, utc; + if (NTime::DosTimeToFileTime(dosTime, localFileTime)) + { + if (!LocalFileTimeToFileTime(&localFileTime, &utc)) + utc.dwHighDateTime = utc.dwLowDateTime = 0; + } + else + utc.dwHighDateTime = utc.dwLowDateTime = 0; + prop = utc; +} + +static void SetHostOS(Byte hostOS, 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); +} + +STDMETHODIMP 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; + } + prop = v; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + const CItem &item = _items[index]; + switch (propID) + { + case kpidPath: 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; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +HRESULT CHandler::Open2(IInStream *inStream, IArchiveOpenCallback *callback) +{ + Close(); + + UInt64 endPos = 0; + RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); + + _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->Seek(pos, STREAM_SEEK_SET, NULL)); + _arc.NumFiles = _items.Size(); + _arc.Processed = pos; + + if (callback && (_items.Size() & 0xFF) == 0) + { + RINOK(callback->SetCompleted(&_arc.NumFiles, &_arc.Processed)); + } + } + return S_OK; +} + +STDMETHODIMP 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 +} + +STDMETHODIMP CHandler::Close() +{ + _arc.Close(); + _phySize = 0; + _items.Clear(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + UInt64 totalUnpacked = 0, totalPacked = 0; + bool allFilesMode = (numItems == (UInt32)(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 lzhDecoder; + + NCompress::NArj::NDecoder::CCoder *arjDecoderSpec = NULL; + CMyComPtr arjDecoder; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream; + CMyComPtr 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 realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + if (item.IsDir()) + { + // if (!testMode) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + } + continue; + } + + if (!testMode && !realOutStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)); + curUnpacked = item.Size; + curPacked = item.PackSize; + + { + COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; + CMyComPtr outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + realOutStream.Release(); + outStreamSpec->Init(); + + inStreamSpec->Init(item.PackSize); + + UInt64 pos; + _stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos); + + HRESULT result = S_OK; + Int32 opRes = NExtract::NOperationResult::kOK; + + if (item.IsEncrypted()) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else + { + switch (item.Method) + { + case 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", 0, 4, + k_Signature, + 0, + 0, + IsArc_Arj) + +}} diff --git a/CPP/7zip/Archive/Bz2Handler.cpp b/CPP/7zip/Archive/Bz2Handler.cpp index d12ccc8fb..b0c2f7508 100644 --- a/CPP/7zip/Archive/Bz2Handler.cpp +++ b/CPP/7zip/Archive/Bz2Handler.cpp @@ -1,416 +1,416 @@ -// 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 { - -class CHandler: - public IInArchive, - public IArchiveOpenSeq, - public IOutArchive, - public ISetProperties, - public CMyUnknownImp -{ - CMyComPtr _stream; - CMyComPtr _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; - -public: - MY_UNKNOWN_IMP4( - IInArchive, - IArchiveOpenSeq, - IOutArchive, - ISetProperties) - INTERFACE_IInArchive(;) - INTERFACE_IOutArchive(;) - STDMETHOD(OpenSeq)(ISequentialInStream *stream); - STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); - - CHandler() { } -}; - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize -}; - -static const Byte kArcProps[] = -{ - kpidNumStreams, - kpidNumBlocks -}; - -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 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; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = 1; - return S_OK; -} - -STDMETHODIMP 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; -} -} - -STDMETHODIMP 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 -} - - -STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) -{ - Close(); - _isArc = true; - _seqStream = stream; - return S_OK; -} - -STDMETHODIMP 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; -} - - -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 realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); - if (!testMode && !realOutStream) - return S_OK; - - extractCallback->PrepareOperation(askMode); - - if (_needSeekToStart) - { - if (!_stream) - return E_FAIL; - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - } - else - _needSeekToStart = true; - - // try { - - NCompress::NBZip2::CDecoder *decoderSpec = new NCompress::NBZip2::CDecoder; - CMyComPtr decoder = decoderSpec; - - #ifndef _7ZIP_ST - RINOK(decoderSpec->SetNumberOfThreads(_props._numThreads)); - #endif - - CDummyOutStream *outStreamSpec = new CDummyOutStream; - CMyComPtr outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(); - - realOutStream.Release(); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr 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 = decoderSpec->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 UpdateArchive( - UInt64 unpackSize, - ISequentialOutStream *outStream, - const CProps &props, - IArchiveUpdateCallback *updateCallback) -{ - RINOK(updateCallback->SetTotal(unpackSize)); - CMyComPtr fileInStream; - RINOK(updateCallback->GetStream(0, &fileInStream)); - CLocalProgress *localProgressSpec = new CLocalProgress; - CMyComPtr localProgress = localProgressSpec; - localProgressSpec->Init(updateCallback, true); - NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder; - CMyComPtr encoder = encoderSpec; - RINOK(props.SetCoderProps(encoderSpec, NULL)); - RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); - return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); -} - -STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) -{ - *type = NFileTimeType::kUnix; - return S_OK; -} - -STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *updateCallback) -{ - COM_TRY_BEGIN - - 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; - } - - CMethodProps props2 = _props; - #ifndef _7ZIP_ST - props2.AddProp_NumThreads(_props._numThreads); - #endif - - return UpdateArchive(size, outStream, props2, updateCallback); - } - - if (indexInArchive != 0) - return E_INVALIDARG; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(updateCallback, true); - - CMyComPtr opCallback; - updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kInArcIndex, 0, - NUpdateNotifyOp::kReplicate)) - } - - if (_stream) - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - - return NCompress::CopyStream(_stream, outStream, progress); - - COM_TRY_END -} - -STDMETHODIMP 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, - IsArc_BZip2) - -}} +// 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 { + +class CHandler: + public IInArchive, + public IArchiveOpenSeq, + public IOutArchive, + public ISetProperties, + public CMyUnknownImp +{ + CMyComPtr _stream; + CMyComPtr _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; + +public: + MY_UNKNOWN_IMP4( + IInArchive, + IArchiveOpenSeq, + IOutArchive, + ISetProperties) + INTERFACE_IInArchive(;) + INTERFACE_IOutArchive(;) + STDMETHOD(OpenSeq)(ISequentialInStream *stream); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); + + CHandler() { } +}; + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidNumStreams, + kpidNumBlocks +}; + +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 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; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1; + return S_OK; +} + +STDMETHODIMP 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; +} +} + +STDMETHODIMP 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 +} + + +STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) +{ + Close(); + _isArc = true; + _seqStream = stream; + return S_OK; +} + +STDMETHODIMP 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; +} + + +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 realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); + if (!testMode && !realOutStream) + return S_OK; + + extractCallback->PrepareOperation(askMode); + + if (_needSeekToStart) + { + if (!_stream) + return E_FAIL; + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); + } + else + _needSeekToStart = true; + + // try { + + NCompress::NBZip2::CDecoder *decoderSpec = new NCompress::NBZip2::CDecoder; + CMyComPtr decoder = decoderSpec; + + #ifndef _7ZIP_ST + RINOK(decoderSpec->SetNumberOfThreads(_props._numThreads)); + #endif + + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + + realOutStream.Release(); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr 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 = decoderSpec->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 UpdateArchive( + UInt64 unpackSize, + ISequentialOutStream *outStream, + const CProps &props, + IArchiveUpdateCallback *updateCallback) +{ + RINOK(updateCallback->SetTotal(unpackSize)); + CMyComPtr fileInStream; + RINOK(updateCallback->GetStream(0, &fileInStream)); + CLocalProgress *localProgressSpec = new CLocalProgress; + CMyComPtr localProgress = localProgressSpec; + localProgressSpec->Init(updateCallback, true); + NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder; + CMyComPtr encoder = encoderSpec; + RINOK(props.SetCoderProps(encoderSpec, NULL)); + RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); + return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); +} + +STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) +{ + *type = NFileTimeType::kUnix; + return S_OK; +} + +STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback) +{ + COM_TRY_BEGIN + + 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; + } + + CMethodProps props2 = _props; + #ifndef _7ZIP_ST + props2.AddProp_NumThreads(_props._numThreads); + #endif + + return UpdateArchive(size, outStream, props2, updateCallback); + } + + if (indexInArchive != 0) + return E_INVALIDARG; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(updateCallback, true); + + CMyComPtr opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, 0, + NUpdateNotifyOp::kReplicate)) + } + + if (_stream) + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); + + return NCompress::CopyStream(_stream, outStream, progress); + + COM_TRY_END +} + +STDMETHODIMP 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, + IsArc_BZip2) + +}} diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp index 756bb3829..c193434f9 100644 --- a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp +++ b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp @@ -1,100 +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 != 0; -} - -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; -} - -STDMETHODIMP 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; -} - -}} +// 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 != 0; +} + +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; +} + +STDMETHODIMP 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 index 8e5456eed..af89abb64 100644 --- a/CPP/7zip/Archive/Cab/CabBlockInStream.h +++ b/CPP/7zip/Archive/Cab/CabBlockInStream.h @@ -1,43 +1,43 @@ -// CabBlockInStream.h - -#ifndef __CAB_BLOCK_IN_STREAM_H -#define __CAB_BLOCK_IN_STREAM_H - -#include "../../../Common/MyCom.h" -#include "../../IStream.h" - -namespace NArchive { -namespace NCab { - -class CCabBlockInStream: - public ISequentialInStream, - public CMyUnknownImp -{ - Byte *_buf; - UInt32 _size; - UInt32 _pos; - -public: - UInt32 ReservedSize; // < 256 - bool MsZip; - - MY_UNKNOWN_IMP - - CCabBlockInStream(): _buf(0), 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; } - - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); -}; - -}} - -#endif +// CabBlockInStream.h + +#ifndef __CAB_BLOCK_IN_STREAM_H +#define __CAB_BLOCK_IN_STREAM_H + +#include "../../../Common/MyCom.h" +#include "../../IStream.h" + +namespace NArchive { +namespace NCab { + +class CCabBlockInStream: + public ISequentialInStream, + public CMyUnknownImp +{ + Byte *_buf; + UInt32 _size; + UInt32 _pos; + +public: + UInt32 ReservedSize; // < 256 + bool MsZip; + + MY_UNKNOWN_IMP + + CCabBlockInStream(): _buf(0), 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; } + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp index d1275e8fb..4395ae1a8 100644 --- a/CPP/7zip/Archive/Cab/CabHandler.cpp +++ b/CPP/7zip/Archive/Cab/CabHandler.cpp @@ -1,1263 +1,1263 @@ -// CabHandler.cpp - -#include "StdAfx.h" - -// #include - -#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 < ARRAY_SIZE(kMethods)) - { - s = MyStpCpy(s, kMethods[method]); - if (method != NHeader::NMethod::kLZX && - method != NHeader::NMethod::kQuantum) - return; - *s++ = ':'; - method = param; - } - ConvertUInt32ToString(method, s); -} - -STDMETHODIMP 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 &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 -} - -STDMETHODIMP 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: - { - FILETIME localFileTime, utcFileTime; - if (NTime::DosTimeToFileTime(item.Time, localFileTime)) - { - if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime)) - utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; - } - else - utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; - prop = utcFileTime; - break; - } - - case kpidMethod: - { - UInt32 realFolderIndex = item.GetFolderIndex(db.Folders.Size()); - const CFolder &folder = db.Folders[realFolderIndex]; - char s[kMethodNameBufSize];; - SetMethodName(s, folder.GetMethod(), folder.MethodMinor); - prop = s; - break; - } - - case kpidBlock: prop = (Int32)m_Database.GetFolderIndex(&mvItem); break; - - #ifdef _CAB_DETAILS - - // case kpidBlockReal: prop = (UInt32)item.FolderIndex; break; - case kpidOffset: prop = (UInt32)item.Offset; break; - case kpidVolume: prop = (UInt32)mvItem.VolumeIndex; break; - - #endif - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *callback) -{ - COM_TRY_BEGIN - Close(); - - CInArchive archive; - CMyComPtr openVolumeCallback; - callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); - - CMyComPtr 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; - } - } - - 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; -} - -STDMETHODIMP CHandler::Close() -{ - _errorMessage.Empty(); - _isArc = false; - _errorInHeaders = false; - _unexpectedEnd = false; - // _mainVolIndex = -1; - _phySize = 0; - _offset = 0; - - m_Database.Clear(); - return S_OK; -} - -class CFolderOutStream: - public ISequentialOutStream, - public CMyUnknownImp -{ -public: - MY_UNKNOWN_IMP - - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); -private: - const CMvDatabaseEx *m_Database; - const CRecordVector *m_ExtractStatuses; - - Byte *TempBuf; - UInt32 TempBufSize; - UInt32 TempBufWritten; - unsigned NumIdenticalFiles; - bool TempBufMode; - - unsigned m_StartIndex; - unsigned m_CurrentIndex; - CMyComPtr m_ExtractCallback; - bool m_TestMode; - - CMyComPtr 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 *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 *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 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; -} - - -HRESULT 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 callbackMessage; - m_ExtractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage, &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; -} - - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testModeSpec, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - - 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 progress = lps; - lps->Init(extractCallback, false); - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; - CMyComPtr copyCoder = copyCoderSpec; - - NCompress::NDeflate::NDecoder::CCOMCoder *deflateDecoderSpec = NULL; - CMyComPtr deflateDecoder; - - NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL; - CMyComPtr lzxDecoder; - - NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL; - CMyComPtr quantumDecoder; - - CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream(); - CMyComPtr cabBlockInStream = cabBlockInStreamSpec; - if (!cabBlockInStreamSpec->Create()) - return E_OUTOFMEMORY; - - CRecordVector extractStatuses; - - for (i = 0;;) - { - lps->OutSize = totalUnPacked; - lps->InSize = totalPacked; - RINOK(lps->SetCur()); - - if (i >= numItems) - break; - - unsigned index = allFilesMode ? i : indices[i]; - - 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]; - - i++; - if (item.IsDir()) - { - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - RINOK(extractCallback->PrepareOperation(askMode)); - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - - int folderIndex = m_Database.GetFolderIndex(&mvItem); - - if (folderIndex < 0) - { - // If we need previous archive - Int32 askMode= testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - RINOK(extractCallback->PrepareOperation(askMode)); - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError)); - continue; - } - - unsigned startIndex2 = m_Database.FolderStartFileIndex[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++) - { - 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; - 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 outStream(cabFolderOutStream); - - unsigned folderIndex2 = item.GetFolderIndex(db.Folders.Size()); - const CFolder &folder = db.Folders[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]; - const CFolder &folder2 = db2.Folders[locFolderIndex]; - - if (bl == 0) - { - cabBlockInStreamSpec->ReservedSize = db2.ArcInfo.GetDataBlockReserveSize(); - RINOK(db2.Stream->Seek(db2.StartPosition + folder2.DataStart, STREAM_SEEK_SET, NULL)); - } - - 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(folderIndex2)); - } - - totalUnPacked += curUnpack; - } - - return S_OK; - - COM_TRY_END -} - - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = m_Database.Items.Size(); - return S_OK; -} - -}} +// CabHandler.cpp + +#include "StdAfx.h" + +// #include + +#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 < ARRAY_SIZE(kMethods)) + { + s = MyStpCpy(s, kMethods[method]); + if (method != NHeader::NMethod::kLZX && + method != NHeader::NMethod::kQuantum) + return; + *s++ = ':'; + method = param; + } + ConvertUInt32ToString(method, s); +} + +STDMETHODIMP 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 &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 +} + +STDMETHODIMP 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: + { + FILETIME localFileTime, utcFileTime; + if (NTime::DosTimeToFileTime(item.Time, localFileTime)) + { + if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime)) + utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; + } + else + utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; + prop = utcFileTime; + break; + } + + case kpidMethod: + { + UInt32 realFolderIndex = item.GetFolderIndex(db.Folders.Size()); + const CFolder &folder = db.Folders[realFolderIndex]; + char s[kMethodNameBufSize];; + SetMethodName(s, folder.GetMethod(), folder.MethodMinor); + prop = s; + break; + } + + case kpidBlock: prop = (Int32)m_Database.GetFolderIndex(&mvItem); break; + + #ifdef _CAB_DETAILS + + // case kpidBlockReal: prop = (UInt32)item.FolderIndex; break; + case kpidOffset: prop = (UInt32)item.Offset; break; + case kpidVolume: prop = (UInt32)mvItem.VolumeIndex; break; + + #endif + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + Close(); + + CInArchive archive; + CMyComPtr openVolumeCallback; + callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); + + CMyComPtr 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; + } + } + + 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; +} + +STDMETHODIMP CHandler::Close() +{ + _errorMessage.Empty(); + _isArc = false; + _errorInHeaders = false; + _unexpectedEnd = false; + // _mainVolIndex = -1; + _phySize = 0; + _offset = 0; + + m_Database.Clear(); + return S_OK; +} + +class CFolderOutStream: + public ISequentialOutStream, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +private: + const CMvDatabaseEx *m_Database; + const CRecordVector *m_ExtractStatuses; + + Byte *TempBuf; + UInt32 TempBufSize; + UInt32 TempBufWritten; + unsigned NumIdenticalFiles; + bool TempBufMode; + + unsigned m_StartIndex; + unsigned m_CurrentIndex; + CMyComPtr m_ExtractCallback; + bool m_TestMode; + + CMyComPtr 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 *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 *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 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; +} + + +HRESULT 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 callbackMessage; + m_ExtractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage, &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; +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testModeSpec, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + + 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 progress = lps; + lps->Init(extractCallback, false); + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; + CMyComPtr copyCoder = copyCoderSpec; + + NCompress::NDeflate::NDecoder::CCOMCoder *deflateDecoderSpec = NULL; + CMyComPtr deflateDecoder; + + NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL; + CMyComPtr lzxDecoder; + + NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL; + CMyComPtr quantumDecoder; + + CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream(); + CMyComPtr cabBlockInStream = cabBlockInStreamSpec; + if (!cabBlockInStreamSpec->Create()) + return E_OUTOFMEMORY; + + CRecordVector extractStatuses; + + for (i = 0;;) + { + lps->OutSize = totalUnPacked; + lps->InSize = totalPacked; + RINOK(lps->SetCur()); + + if (i >= numItems) + break; + + unsigned index = allFilesMode ? i : indices[i]; + + 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]; + + i++; + if (item.IsDir()) + { + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + CMyComPtr realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + RINOK(extractCallback->PrepareOperation(askMode)); + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + + int folderIndex = m_Database.GetFolderIndex(&mvItem); + + if (folderIndex < 0) + { + // If we need previous archive + Int32 askMode= testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + CMyComPtr realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + RINOK(extractCallback->PrepareOperation(askMode)); + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError)); + continue; + } + + unsigned startIndex2 = m_Database.FolderStartFileIndex[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++) + { + 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; + 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 outStream(cabFolderOutStream); + + unsigned folderIndex2 = item.GetFolderIndex(db.Folders.Size()); + const CFolder &folder = db.Folders[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]; + const CFolder &folder2 = db2.Folders[locFolderIndex]; + + if (bl == 0) + { + cabBlockInStreamSpec->ReservedSize = db2.ArcInfo.GetDataBlockReserveSize(); + RINOK(db2.Stream->Seek(db2.StartPosition + folder2.DataStart, STREAM_SEEK_SET, NULL)); + } + + 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(folderIndex2)); + } + + totalUnPacked += curUnpack; + } + + return S_OK; + + COM_TRY_END +} + + +STDMETHODIMP 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 index ba9df385a..6f44b8752 100644 --- a/CPP/7zip/Archive/Cab/CabHandler.h +++ b/CPP/7zip/Archive/Cab/CabHandler.h @@ -1,37 +1,37 @@ -// CabHandler.h - -#ifndef __CAB_HANDLER_H -#define __CAB_HANDLER_H - -#include "../../../Common/MyCom.h" - -#include "../IArchive.h" - -#include "CabIn.h" - -namespace NArchive { -namespace NCab { - -class CHandler: - public IInArchive, - public CMyUnknownImp -{ -public: - MY_UNKNOWN_IMP1(IInArchive) - - INTERFACE_IInArchive(;) - -private: - CMvDatabaseEx m_Database; - UString _errorMessage; - bool _isArc; - bool _errorInHeaders; - bool _unexpectedEnd; - // int _mainVolIndex; - UInt32 _phySize; - UInt64 _offset; -}; - -}} - -#endif +// CabHandler.h + +#ifndef __CAB_HANDLER_H +#define __CAB_HANDLER_H + +#include "../../../Common/MyCom.h" + +#include "../IArchive.h" + +#include "CabIn.h" + +namespace NArchive { +namespace NCab { + +class CHandler: + public IInArchive, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP1(IInArchive) + + INTERFACE_IInArchive(;) + +private: + CMvDatabaseEx m_Database; + 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 index 76db98e98..370a2f1ef 100644 --- a/CPP/7zip/Archive/Cab/CabHeader.cpp +++ b/CPP/7zip/Archive/Cab/CabHeader.cpp @@ -1,15 +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; - -}}} +// 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 index 5bf6f76e1..2f2bd1093 100644 --- a/CPP/7zip/Archive/Cab/CabHeader.h +++ b/CPP/7zip/Archive/Cab/CabHeader.h @@ -1,41 +1,41 @@ -// Archive/CabHeader.h - -#ifndef __ARCHIVE_CAB_HEADER_H -#define __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 +// Archive/CabHeader.h + +#ifndef __ARCHIVE_CAB_HEADER_H +#define __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 index 2463e479e..ca0052bfe 100644 --- a/CPP/7zip/Archive/Cab/CabIn.cpp +++ b/CPP/7zip/Archive/Cab/CabIn.cpp @@ -1,491 +1,491 @@ -// Archive/CabIn.cpp - -#include "StdAfx.h" - -// #include - -#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(db.Stream->Seek(0, STREAM_SEEK_CUR, &db.StartPosition)); - // UInt64 temp = db.StartPosition; - - CByteBuffer buffer; - CInArcInfo &ai = db.ArcInfo; - UInt64 startInBuf = 0; - - CLimitedSequentialInStream *limitedStreamSpec = NULL; - CMyComPtr limitedStream; - - // for (int iii = 0; iii < 10000; iii++) - { - // db.StartPosition = temp; RINOK(db.Stream->Seek(db.StartPosition, STREAM_SEEK_SET, NULL)); - - 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(db.Stream->Seek(db.StartPosition + ai.FileHeadersOffset, STREAM_SEEK_SET, NULL)); - 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; -} - -}} +// Archive/CabIn.cpp + +#include "StdAfx.h" + +// #include + +#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(db.Stream->Seek(0, STREAM_SEEK_CUR, &db.StartPosition)); + // UInt64 temp = db.StartPosition; + + CByteBuffer buffer; + CInArcInfo &ai = db.ArcInfo; + UInt64 startInBuf = 0; + + CLimitedSequentialInStream *limitedStreamSpec = NULL; + CMyComPtr limitedStream; + + // for (int iii = 0; iii < 10000; iii++) + { + // db.StartPosition = temp; RINOK(db.Stream->Seek(db.StartPosition, STREAM_SEEK_SET, NULL)); + + 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(db.Stream->Seek(db.StartPosition + ai.FileHeadersOffset, STREAM_SEEK_SET, NULL)); + 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 index 130b5b83d..a1fc6bdc4 100644 --- a/CPP/7zip/Archive/Cab/CabIn.h +++ b/CPP/7zip/Archive/Cab/CabIn.h @@ -1,176 +1,176 @@ -// Archive/CabIn.h - -#ifndef __ARCHIVE_CAB_IN_H -#define __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 Folders; - CObjectVector 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 = Folders.Size(); - if (IsTherePrevFolder()) - res--; - return res; - } -}; - - -struct CDatabaseEx: public CDatabase -{ - CMyComPtr Stream; -}; - - -struct CMvItem -{ - unsigned VolumeIndex; - unsigned ItemIndex; -}; - - -class CMvDatabaseEx -{ - bool AreItemsEqual(unsigned i1, unsigned i2); - -public: - CObjectVector Volumes; - CRecordVector Items; - CRecordVector StartFolderOfVol; // can be negative - CRecordVector 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 +// Archive/CabIn.h + +#ifndef __ARCHIVE_CAB_IN_H +#define __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 Folders; + CObjectVector 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 = Folders.Size(); + if (IsTherePrevFolder()) + res--; + return res; + } +}; + + +struct CDatabaseEx: public CDatabase +{ + CMyComPtr Stream; +}; + + +struct CMvItem +{ + unsigned VolumeIndex; + unsigned ItemIndex; +}; + + +class CMvDatabaseEx +{ + bool AreItemsEqual(unsigned i1, unsigned i2); + +public: + CObjectVector Volumes; + CRecordVector Items; + CRecordVector StartFolderOfVol; // can be negative + CRecordVector 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 index 60ad8d25b..9b5132026 100644 --- a/CPP/7zip/Archive/Cab/CabItem.h +++ b/CPP/7zip/Archive/Cab/CabItem.h @@ -1,66 +1,66 @@ -// Archive/CabItem.h - -#ifndef __ARCHIVE_CAB_ITEM_H -#define __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 numFolders - 1; - return FolderIndex; - } -}; - -}} - -#endif +// Archive/CabItem.h + +#ifndef __ARCHIVE_CAB_ITEM_H +#define __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 numFolders - 1; + return FolderIndex; + } +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Cab/CabRegister.cpp b/CPP/7zip/Archive/Cab/CabRegister.cpp index 27a8f9603..0b5cc93a7 100644 --- a/CPP/7zip/Archive/Cab/CabRegister.cpp +++ b/CPP/7zip/Archive/Cab/CabRegister.cpp @@ -1,19 +1,19 @@ -// CabRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "CabHandler.h" - -namespace NArchive { -namespace NCab { - -REGISTER_ARC_I( - "Cab", "cab", 0, 8, - NHeader::kMarker, - 0, - NArcInfoFlags::kFindSignature, - NULL) - -}} +// CabRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "CabHandler.h" + +namespace NArchive { +namespace NCab { + +REGISTER_ARC_I( + "Cab", "cab", 0, 8, + NHeader::kMarker, + 0, + NArcInfoFlags::kFindSignature, + NULL) + +}} diff --git a/CPP/7zip/Archive/Cab/StdAfx.h b/CPP/7zip/Archive/Cab/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Archive/Cab/StdAfx.h +++ b/CPP/7zip/Archive/Cab/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/Chm/ChmHandler.cpp b/CPP/7zip/Archive/Chm/ChmHandler.cpp index b4d5ceba0..7ffdafe0e 100644 --- a/CPP/7zip/Archive/Chm/ChmHandler.cpp +++ b/CPP/7zip/Archive/Chm/ChmHandler.cpp @@ -1,828 +1,828 @@ -// 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 - -STDMETHODIMP 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 -} - -STDMETHODIMP 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 -} - -/* -class CProgressImp: public CProgressVirt -{ - CMyComPtr _callback; -public: - STDMETHOD(SetTotal)(const UInt64 *numFiles); - STDMETHOD(SetCompleted)(const UInt64 *numFiles); - CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {}; -}; - -STDMETHODIMP CProgressImp::SetTotal(const UInt64 *numFiles) -{ - if (_callback) - return _callback->SetCompleted(numFiles, NULL); - return S_OK; -} - -STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles) -{ - if (_callback) - return _callback->SetCompleted(numFiles, NULL); - return S_OK; -} -*/ - -STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback * /* openArchiveCallback */) -{ - COM_TRY_BEGIN - Close(); - try - { - CInArchive archive(_help2); - // CProgressImp progressImp(openArchiveCallback); - 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 -} - -STDMETHODIMP CHandler::Close() -{ - m_ErrorFlags = 0; - m_Database.Clear(); - m_Stream.Release(); - return S_OK; -} - -class CChmFolderOutStream: - public ISequentialOutStream, - public CMyUnknownImp -{ -public: - MY_UNKNOWN_IMP - - HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK); - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); - - UInt64 m_FolderSize; - UInt64 m_PosInFolder; - UInt64 m_PosInSection; - const CRecordVector *m_ExtractStatuses; - unsigned m_StartIndex; - unsigned m_CurrentIndex; - unsigned m_NumFiles; - -private: - const CFilesDatabase *m_Database; - CMyComPtr m_ExtractCallback; - bool m_TestMode; - - bool m_IsOk; - bool m_FileIsOpen; - UInt64 m_RemainFileSize; - CMyComPtr m_RealOutStream; - - HRESULT OpenFile(); - HRESULT WriteEmptyFiles(); -public: - void Init( - const CFilesDatabase *database, - IArchiveExtractCallback *extractCallback, - bool testMode); - HRESULT FlushCorrupted(UInt64 maxSize); -}; - -void CChmFolderOutStream::Init( - const CFilesDatabase *database, - IArchiveExtractCallback *extractCallback, - bool testMode) -{ - m_Database = database; - m_ExtractCallback = extractCallback; - m_TestMode = testMode; - - m_CurrentIndex = 0; - m_FileIsOpen = false; -} - -HRESULT CChmFolderOutStream::OpenFile() -{ - Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract) : - NExtract::NAskMode::kSkip; - m_RealOutStream.Release(); - RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode)); - if (!m_RealOutStream && !m_TestMode) - askMode = NExtract::NAskMode::kSkip; - return m_ExtractCallback->PrepareOperation(askMode); -} - -HRESULT CChmFolderOutStream::WriteEmptyFiles() -{ - if (m_FileIsOpen) - return S_OK; - for (; m_CurrentIndex < m_NumFiles; m_CurrentIndex++) - { - UInt64 fileSize = m_Database->GetFileSize(m_StartIndex + m_CurrentIndex); - if (fileSize != 0) - return S_OK; - HRESULT result = OpenFile(); - m_RealOutStream.Release(); - RINOK(result); - RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - } - return S_OK; -} - -// This is WritePart function -HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK) -{ - UInt32 realProcessed = 0; - if (processedSize) - *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(); -} - -STDMETHODIMP CChmFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) -{ - return Write2(data, size, processedSize, true); -} - -HRESULT CChmFolderOutStream::FlushCorrupted(UInt64 maxSize) -{ - const UInt32 kBufferSize = (1 << 10); - Byte buffer[kBufferSize]; - for (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; -} - - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testModeSpec, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - 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 copyCoder = copyCoderSpec; - UInt32 i; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr 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 realOutStream; - Int32 askMode= testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - - if (m_Database.NewFormat) - { - if (index != 0) - return E_FAIL; - if (!testMode && !realOutStream) - continue; - if (!testMode) - { - UInt32 size = m_Database.NewFormatString.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(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL)); - streamSpec->Init(item.Size); - - RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError)); - } - return S_OK; - } - - UInt64 lastFolderIndex = ((UInt64)0 - 1); - - for (i = 0; i < numItems; i++) - { - UInt32 index = allFilesMode ? i : indices[i]; - 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 §ion = 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 lzxDecoder; - CChmFolderOutStream *chmFolderOutStream = 0; - CMyComPtr outStream; - - currentTotalSize = 0; - - CRecordVector extractStatuses; - - CByteBuffer packBuf; - - for (i = 0;;) - { - RINOK(extractCallback->SetCompleted(¤tTotalSize)); - - 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 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 realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - Int32 opRes = NExtract::NOperationResult::kOK; - if (!testMode && item.Size != 0) - { - RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL)); - streamSpec->Init(item.Size); - RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); - if (copyCoderSpec->TotalSize != item.Size) - opRes = NExtract::NOperationResult::kDataError; - } - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(opRes)); - currentTotalSize += item.Size; - continue; - } - - if (sectionIndex >= m_Database.Sections.Size()) - { - // we must report error here; - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kHeadersError)); - continue; - } - - const CSectionInfo §ion = m_Database.Sections[(unsigned)sectionIndex]; - - if (!section.IsLzx()) - { - CMyComPtr 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(¤tTotalSize)); - - 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; - 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(m_Stream->Seek(compressedPos + offset, STREAM_SEEK_SET, NULL)); - 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 -} - -STDMETHODIMP 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", 0, 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", 0, 0xCE, - k_Signature, - 0, - NArcInfoFlags::kFindSignature, - NULL) - -} - -}} +// 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 + +STDMETHODIMP 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 +} + +STDMETHODIMP 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 +} + +/* +class CProgressImp: public CProgressVirt +{ + CMyComPtr _callback; +public: + STDMETHOD(SetTotal)(const UInt64 *numFiles); + STDMETHOD(SetCompleted)(const UInt64 *numFiles); + CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {}; +}; + +STDMETHODIMP CProgressImp::SetTotal(const UInt64 *numFiles) +{ + if (_callback) + return _callback->SetCompleted(numFiles, NULL); + return S_OK; +} + +STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles) +{ + if (_callback) + return _callback->SetCompleted(numFiles, NULL); + return S_OK; +} +*/ + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + try + { + CInArchive archive(_help2); + // CProgressImp progressImp(openArchiveCallback); + 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 +} + +STDMETHODIMP CHandler::Close() +{ + m_ErrorFlags = 0; + m_Database.Clear(); + m_Stream.Release(); + return S_OK; +} + +class CChmFolderOutStream: + public ISequentialOutStream, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP + + HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK); + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + + UInt64 m_FolderSize; + UInt64 m_PosInFolder; + UInt64 m_PosInSection; + const CRecordVector *m_ExtractStatuses; + unsigned m_StartIndex; + unsigned m_CurrentIndex; + unsigned m_NumFiles; + +private: + const CFilesDatabase *m_Database; + CMyComPtr m_ExtractCallback; + bool m_TestMode; + + bool m_IsOk; + bool m_FileIsOpen; + UInt64 m_RemainFileSize; + CMyComPtr m_RealOutStream; + + HRESULT OpenFile(); + HRESULT WriteEmptyFiles(); +public: + void Init( + const CFilesDatabase *database, + IArchiveExtractCallback *extractCallback, + bool testMode); + HRESULT FlushCorrupted(UInt64 maxSize); +}; + +void CChmFolderOutStream::Init( + const CFilesDatabase *database, + IArchiveExtractCallback *extractCallback, + bool testMode) +{ + m_Database = database; + m_ExtractCallback = extractCallback; + m_TestMode = testMode; + + m_CurrentIndex = 0; + m_FileIsOpen = false; +} + +HRESULT CChmFolderOutStream::OpenFile() +{ + Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract) : + NExtract::NAskMode::kSkip; + m_RealOutStream.Release(); + RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode)); + if (!m_RealOutStream && !m_TestMode) + askMode = NExtract::NAskMode::kSkip; + return m_ExtractCallback->PrepareOperation(askMode); +} + +HRESULT CChmFolderOutStream::WriteEmptyFiles() +{ + if (m_FileIsOpen) + return S_OK; + for (; m_CurrentIndex < m_NumFiles; m_CurrentIndex++) + { + UInt64 fileSize = m_Database->GetFileSize(m_StartIndex + m_CurrentIndex); + if (fileSize != 0) + return S_OK; + HRESULT result = OpenFile(); + m_RealOutStream.Release(); + RINOK(result); + RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + } + return S_OK; +} + +// This is WritePart function +HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK) +{ + UInt32 realProcessed = 0; + if (processedSize) + *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(); +} + +STDMETHODIMP CChmFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + return Write2(data, size, processedSize, true); +} + +HRESULT CChmFolderOutStream::FlushCorrupted(UInt64 maxSize) +{ + const UInt32 kBufferSize = (1 << 10); + Byte buffer[kBufferSize]; + for (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; +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testModeSpec, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + 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 copyCoder = copyCoderSpec; + UInt32 i; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr 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 realOutStream; + Int32 askMode= testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + if (m_Database.NewFormat) + { + if (index != 0) + return E_FAIL; + if (!testMode && !realOutStream) + continue; + if (!testMode) + { + UInt32 size = m_Database.NewFormatString.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(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL)); + streamSpec->Init(item.Size); + + RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError)); + } + return S_OK; + } + + UInt64 lastFolderIndex = ((UInt64)0 - 1); + + for (i = 0; i < numItems; i++) + { + UInt32 index = allFilesMode ? i : indices[i]; + 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 §ion = 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 lzxDecoder; + CChmFolderOutStream *chmFolderOutStream = 0; + CMyComPtr outStream; + + currentTotalSize = 0; + + CRecordVector extractStatuses; + + CByteBuffer packBuf; + + for (i = 0;;) + { + RINOK(extractCallback->SetCompleted(¤tTotalSize)); + + 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 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 realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + Int32 opRes = NExtract::NOperationResult::kOK; + if (!testMode && item.Size != 0) + { + RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL)); + streamSpec->Init(item.Size); + RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize != item.Size) + opRes = NExtract::NOperationResult::kDataError; + } + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(opRes)); + currentTotalSize += item.Size; + continue; + } + + if (sectionIndex >= m_Database.Sections.Size()) + { + // we must report error here; + CMyComPtr realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kHeadersError)); + continue; + } + + const CSectionInfo §ion = m_Database.Sections[(unsigned)sectionIndex]; + + if (!section.IsLzx()) + { + CMyComPtr 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(¤tTotalSize)); + + 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; + 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(m_Stream->Seek(compressedPos + offset, STREAM_SEEK_SET, NULL)); + 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 +} + +STDMETHODIMP 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", 0, 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", 0, 0xCE, + k_Signature, + 0, + NArcInfoFlags::kFindSignature, + NULL) + +} + +}} diff --git a/CPP/7zip/Archive/Chm/ChmHandler.h b/CPP/7zip/Archive/Chm/ChmHandler.h index 509d1d6f5..884f391b1 100644 --- a/CPP/7zip/Archive/Chm/ChmHandler.h +++ b/CPP/7zip/Archive/Chm/ChmHandler.h @@ -1,35 +1,35 @@ -// ChmHandler.h - -#ifndef __ARCHIVE_CHM_HANDLER_H -#define __ARCHIVE_CHM_HANDLER_H - -#include "../../../Common/MyCom.h" - -#include "../IArchive.h" - -#include "ChmIn.h" - -namespace NArchive { -namespace NChm { - -class CHandler: - public IInArchive, - public CMyUnknownImp -{ -public: - MY_UNKNOWN_IMP1(IInArchive) - - INTERFACE_IInArchive(;) - - bool _help2; - CHandler(bool help2): _help2(help2) {} - -private: - CFilesDatabase m_Database; - CMyComPtr m_Stream; - UInt32 m_ErrorFlags; -}; - -}} - -#endif +// ChmHandler.h + +#ifndef __ARCHIVE_CHM_HANDLER_H +#define __ARCHIVE_CHM_HANDLER_H + +#include "../../../Common/MyCom.h" + +#include "../IArchive.h" + +#include "ChmIn.h" + +namespace NArchive { +namespace NChm { + +class CHandler: + public IInArchive, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP1(IInArchive) + + INTERFACE_IInArchive(;) + + bool _help2; + CHandler(bool help2): _help2(help2) {} + +private: + CFilesDatabase m_Database; + CMyComPtr m_Stream; + UInt32 m_ErrorFlags; +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Chm/ChmIn.cpp b/CPP/7zip/Archive/Chm/ChmIn.cpp index 8cea546b4..7e3f155b4 100644 --- a/CPP/7zip/Archive/Chm/ChmIn.cpp +++ b/CPP/7zip/Archive/Chm/ChmIn.cpp @@ -1,1018 +1,1018 @@ -// Archive/ChmIn.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/UTFConvert.h" - -#include "../../Common/LimitedStreams.h" - -#include "ChmIn.h" - -#define Get16(p) GetUi16(p) -#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; - if (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->Seek(pos, STREAM_SEEK_SET, NULL)); - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr 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 &items = *(const CObjectVector *)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 §ion = 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 - UInt32 val32 = ReadUInt32(); - int n = GetLog(val32); - if (n < 0 || n > 16) - return S_FALSE; - li.ResetIntervalBits = n; - } - - { - UInt32 val32 = ReadUInt32(); - int n = GetLog(val32); - if (n < 0 || n > 16) - return S_FALSE; - li.WindowSizeBits = 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->Seek(0, STREAM_SEEK_CUR, &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; -} - -}} +// Archive/ChmIn.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/UTFConvert.h" + +#include "../../Common/LimitedStreams.h" + +#include "ChmIn.h" + +#define Get16(p) GetUi16(p) +#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; + if (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->Seek(pos, STREAM_SEEK_SET, NULL)); + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr 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 &items = *(const CObjectVector *)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 §ion = 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 + UInt32 val32 = ReadUInt32(); + int n = GetLog(val32); + if (n < 0 || n > 16) + return S_FALSE; + li.ResetIntervalBits = n; + } + + { + UInt32 val32 = ReadUInt32(); + int n = GetLog(val32); + if (n < 0 || n > 16) + return S_FALSE; + li.WindowSizeBits = 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->Seek(0, STREAM_SEEK_CUR, &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 index 14ebfc88e..f7b75d811 100644 --- a/CPP/7zip/Archive/Chm/ChmIn.h +++ b/CPP/7zip/Archive/Chm/ChmIn.h @@ -1,270 +1,270 @@ -// Archive/ChmIn.h - -#ifndef __ARCHIVE_CHM_IN_H -#define __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 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 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 ResetOffsets; - - 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; - - 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 Methods; - - bool IsLzx() const; - UString GetMethodName() const; -}; - -class CFilesDatabase: public CDatabase -{ -public: - bool LowLevel; - CUIntVector Indices; - CObjectVector 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 §ion = 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 §ion = 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 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 +// Archive/ChmIn.h + +#ifndef __ARCHIVE_CHM_IN_H +#define __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 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 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 ResetOffsets; + + 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; + + 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 Methods; + + bool IsLzx() const; + UString GetMethodName() const; +}; + +class CFilesDatabase: public CDatabase +{ +public: + bool LowLevel; + CUIntVector Indices; + CObjectVector 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 §ion = 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 §ion = 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 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 index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Archive/Chm/StdAfx.h +++ b/CPP/7zip/Archive/Chm/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp index 5cfa7947f..d2dc6c5f0 100644 --- a/CPP/7zip/Archive/ComHandler.cpp +++ b/CPP/7zip/Archive/ComHandler.cpp @@ -1,881 +1,881 @@ -// 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 { - -#define SIGNATURE { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 } -static const Byte kSignature[] = SIGNATURE; - -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 MiniSids; - - HRESULT AddNode(int parent, UInt32 did); -public: - - CObjArray Fat; - UInt32 FatSize; - - CObjArray Mat; - UInt32 MatSize; - - CObjectVector Items; - CRecordVector Refs; - - UInt32 LongStreamMinSize; - unsigned SectorSizeBits; - unsigned MiniSectorSizeBits; - - Int32 MainSubfile; - - UInt64 PhySize; - EType Type; - - bool IsNotArcType() const - { - return - Type != k_Type_Msi && - Type != k_Type_Msp; - } - - void UpdatePhySize(UInt64 val) - { - if (PhySize < val) - PhySize = val; - } - 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) -{ - UpdatePhySize(((UInt64)sid + 2) << sectorSizeBits); - RINOK(inStream->Seek((((UInt64)sid + 1) << sectorSizeBits), STREAM_SEEK_SET, NULL)); - 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; - - Fat.Free(); - MiniSids.Free(); - Mat.Free(); - Items.Clear(); - Refs.Clear(); -} - -static const UInt32 kNoDid = 0xFFFFFFFF; - -HRESULT CDatabase::AddNode(int parent, UInt32 did) -{ - if (did == kNoDid) - return S_OK; - if (did >= (UInt32)Items.Size()) - return S_FALSE; - const CItem &item = Items[did]; - if (item.IsEmpty()) - return S_FALSE; - CRef ref; - ref.Parent = parent; - ref.Did = did; - int index = Refs.Add(ref); - if (Refs.Size() > Items.Size()) - return S_FALSE; - RINOK(AddNode(parent, item.LeftDid)); - RINOK(AddNode(parent, item.RightDid)); - if (item.IsDir()) - { - RINOK(AddNode(index, item.SonDid)); - } - return S_OK; -} - -static UString CompoundNameToFileName(const UString &s) -{ - UString res; - for (unsigned i = 0; i < s.Len(); i++) - { - wchar_t c = s[i]; - if (c < 0x20) - { - res += '['; - res.Add_UInt32(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 < k_Msi_StartUnicodeChar || c > 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 = 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; - unsigned bsLog = isLargeStream ? SectorSizeBits : MiniSectorSizeBits; - // streamSpec->Size = item.Size; - - UInt32 clusterSize = (UInt32)1 << bsLog; - 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; - UpdatePhySize(((UInt64)sid + 2) << bsLog); - 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, 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 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 = i; - } - } - } - - if (numCabs > 1) - MainSubfile = -1; - - { - FOR_VECTOR (t, Items) - { - Update_PhySize_WithItem(t); - } - } - { - 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; -} - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - CMyComPtr _stream; - CDatabase _db; -public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidPackSize, - kpidCTime, - kpidMTime -}; - -static const Byte kArcProps[] = -{ - kpidExtension, - kpidClusterSize, - kpidSectorSize -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP 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 -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CRef &ref = _db.Refs[index]; - const CItem &item = _db.Items[ref.Did]; - - switch (propID) - { - case kpidPath: prop = _db.GetItemPath(index); break; - case kpidIsDir: prop = item.IsDir(); break; - case kpidCTime: prop = item.CTime; break; - case kpidMTime: prop = item.MTime; break; - case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break; - case kpidSize: if (!item.IsDir()) prop = item.Size; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) -{ - COM_TRY_BEGIN - Close(); - try - { - if (_db.Open(inStream) != S_OK) - return S_FALSE; - _stream = inStream; - } - catch(...) { return S_FALSE; } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _db.Clear(); - _stream.Release(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - Int32 index = allFilesMode ? i : indices[i]; - const CItem &item = _db.Items[_db.Refs[index].Did]; - - CMyComPtr outStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(index, &outStream, askMode)); - - if (item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - - totalPackSize += _db.GetItemPackSize(item.Size); - totalSize += item.Size; - - if (!testMode && !outStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - Int32 res = NExtract::NOperationResult::kDataError; - CMyComPtr inStream; - HRESULT hres = GetStream(index, &inStream); - if (hres == S_FALSE) - res = NExtract::NOperationResult::kDataError; - else if (hres == E_NOTIMPL) - res = NExtract::NOperationResult::kUnsupportedMethod; - else - { - RINOK(hres); - if (inStream) - { - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); - if (copyCoderSpec->TotalSize == item.Size) - res = NExtract::NOperationResult::kOK; - } - } - outStream.Release(); - RINOK(extractCallback->SetOperationResult(res)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _db.Refs.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - *stream = 0; - UInt32 itemIndex = _db.Refs[index].Did; - const CItem &item = _db.Items[itemIndex]; - CClusterInStream *streamSpec = new CClusterInStream; - CMyComPtr streamTemp = streamSpec; - streamSpec->Stream = _stream; - streamSpec->StartOffset = 0; - - bool isLargeStream = (itemIndex == 0 || _db.IsLargeStream(item.Size)); - int bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits; - streamSpec->BlockSizeLog = bsLog; - streamSpec->Size = item.Size; - - UInt32 clusterSize = (UInt32)1 << bsLog; - UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog; - if (numClusters64 >= ((UInt32)1 << 31)) - return E_NOTIMPL; - streamSpec->Vector.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", 0, 0xE5, - kSignature, - 0, - 0, - NULL) - -}} +// 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 { + +#define SIGNATURE { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 } +static const Byte kSignature[] = SIGNATURE; + +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 MiniSids; + + HRESULT AddNode(int parent, UInt32 did); +public: + + CObjArray Fat; + UInt32 FatSize; + + CObjArray Mat; + UInt32 MatSize; + + CObjectVector Items; + CRecordVector Refs; + + UInt32 LongStreamMinSize; + unsigned SectorSizeBits; + unsigned MiniSectorSizeBits; + + Int32 MainSubfile; + + UInt64 PhySize; + EType Type; + + bool IsNotArcType() const + { + return + Type != k_Type_Msi && + Type != k_Type_Msp; + } + + void UpdatePhySize(UInt64 val) + { + if (PhySize < val) + PhySize = val; + } + 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) +{ + UpdatePhySize(((UInt64)sid + 2) << sectorSizeBits); + RINOK(inStream->Seek((((UInt64)sid + 1) << sectorSizeBits), STREAM_SEEK_SET, NULL)); + 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; + + Fat.Free(); + MiniSids.Free(); + Mat.Free(); + Items.Clear(); + Refs.Clear(); +} + +static const UInt32 kNoDid = 0xFFFFFFFF; + +HRESULT CDatabase::AddNode(int parent, UInt32 did) +{ + if (did == kNoDid) + return S_OK; + if (did >= (UInt32)Items.Size()) + return S_FALSE; + const CItem &item = Items[did]; + if (item.IsEmpty()) + return S_FALSE; + CRef ref; + ref.Parent = parent; + ref.Did = did; + int index = Refs.Add(ref); + if (Refs.Size() > Items.Size()) + return S_FALSE; + RINOK(AddNode(parent, item.LeftDid)); + RINOK(AddNode(parent, item.RightDid)); + if (item.IsDir()) + { + RINOK(AddNode(index, item.SonDid)); + } + return S_OK; +} + +static UString CompoundNameToFileName(const UString &s) +{ + UString res; + for (unsigned i = 0; i < s.Len(); i++) + { + wchar_t c = s[i]; + if (c < 0x20) + { + res += '['; + res.Add_UInt32(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 < k_Msi_StartUnicodeChar || c > 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 = 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; + unsigned bsLog = isLargeStream ? SectorSizeBits : MiniSectorSizeBits; + // streamSpec->Size = item.Size; + + UInt32 clusterSize = (UInt32)1 << bsLog; + 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; + UpdatePhySize(((UInt64)sid + 2) << bsLog); + 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, 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 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 = i; + } + } + } + + if (numCabs > 1) + MainSubfile = -1; + + { + FOR_VECTOR (t, Items) + { + Update_PhySize_WithItem(t); + } + } + { + 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; +} + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CMyComPtr _stream; + CDatabase _db; +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidCTime, + kpidMTime +}; + +static const Byte kArcProps[] = +{ + kpidExtension, + kpidClusterSize, + kpidSectorSize +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP 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 +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CRef &ref = _db.Refs[index]; + const CItem &item = _db.Items[ref.Did]; + + switch (propID) + { + case kpidPath: prop = _db.GetItemPath(index); break; + case kpidIsDir: prop = item.IsDir(); break; + case kpidCTime: prop = item.CTime; break; + case kpidMTime: prop = item.MTime; break; + case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break; + case kpidSize: if (!item.IsDir()) prop = item.Size; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + try + { + if (_db.Open(inStream) != S_OK) + return S_FALSE; + _stream = inStream; + } + catch(...) { return S_FALSE; } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _db.Clear(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + Int32 index = allFilesMode ? i : indices[i]; + const CItem &item = _db.Items[_db.Refs[index].Did]; + + CMyComPtr outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + + if (item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + + totalPackSize += _db.GetItemPackSize(item.Size); + totalSize += item.Size; + + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + Int32 res = NExtract::NOperationResult::kDataError; + CMyComPtr inStream; + HRESULT hres = GetStream(index, &inStream); + if (hres == S_FALSE) + res = NExtract::NOperationResult::kDataError; + else if (hres == E_NOTIMPL) + res = NExtract::NOperationResult::kUnsupportedMethod; + else + { + RINOK(hres); + if (inStream) + { + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize == item.Size) + res = NExtract::NOperationResult::kOK; + } + } + outStream.Release(); + RINOK(extractCallback->SetOperationResult(res)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _db.Refs.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = 0; + UInt32 itemIndex = _db.Refs[index].Did; + const CItem &item = _db.Items[itemIndex]; + CClusterInStream *streamSpec = new CClusterInStream; + CMyComPtr streamTemp = streamSpec; + streamSpec->Stream = _stream; + streamSpec->StartOffset = 0; + + bool isLargeStream = (itemIndex == 0 || _db.IsLargeStream(item.Size)); + int bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits; + streamSpec->BlockSizeLog = bsLog; + streamSpec->Size = item.Size; + + UInt32 clusterSize = (UInt32)1 << bsLog; + UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog; + if (numClusters64 >= ((UInt32)1 << 31)) + return E_NOTIMPL; + streamSpec->Vector.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", 0, 0xE5, + kSignature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/Common/CoderMixer2.cpp b/CPP/7zip/Archive/Common/CoderMixer2.cpp index baddddfc8..c7002121d 100644 --- a/CPP/7zip/Archive/Common/CoderMixer2.cpp +++ b/CPP/7zip/Archive/Common/CoderMixer2.cpp @@ -1,1125 +1,1125 @@ -// 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 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 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 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 s; - unk->QueryInterface(IID_ISequentialInStream, (void**)&s); - c2.CanRead = (s != NULL); - } - { - CMyComPtr 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 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 setStream; - coder.QueryInterface(IID_ICompressSetInStream, (void **)&setStream); - if (setStream) - { - CMyComPtr seqInStream2; - RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + 0, &seqInStream2)); - RINOK(setStream->SetInStream(seqInStream2)); - isSet = true; - } - } - - if (!isSet && numInStreams != 0) - { - CMyComPtr setStream2; - coder.QueryInterface(IID_ICompressSetInStream2, (void **)&setStream2); - if (!setStream2) - return E_NOTIMPL; - - for (UInt32 i = 0; i < numInStreams; i++) - { - CMyComPtr 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 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 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 setOutStream; - coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream); - if (setOutStream) - { - CMyComPtr seqOutStream2; - RINOK(GetOutStream(outStreams, /* outSizes, */ startIndex + 0, &seqOutStream2)); - RINOK(setOutStream->SetOutStream(seqOutStream2)); - isSet = true; - } - } - - if (!isSet && numOutStreams != 0) - { - return E_NOTIMPL; - /* - CMyComPtr setStream2; - coder.QueryInterface(IID_ICompressSetOutStream2, (void **)&setStream2); - if (!setStream2) - return E_NOTIMPL; - for (UInt32 i = 0; i < numOutStreams; i++) - { - CMyComPtr 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 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 > seqInStreams; - CObjectVector< CMyComPtr > 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 seqInStream; - RINOK(GetInStream(inStreams, /* inSizes, */ startInIndex + i, &seqInStream)); - seqInStreams.Add(seqInStream); - } - - for (i = 0; i < numOutStreams; i++) - { - CMyComPtr 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 initEncoder; - coder.QueryInterface(IID_ICompressInitEncoder, (void **)&initEncoder); - if (initEncoder) - RINOK(initEncoder->InitEncoder()); - } - else - { - CMyComPtr 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 seqInStream; - - RINOK(GetInStream2(inStreams, /* inSizes, */ - _bi.UnpackCoder, &seqInStream)) - - FOR_VECTOR (i, _coders) - { - CCoder &coder = _coders[i]; - CMyComPtr 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 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 + +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 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 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 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 s; + unk->QueryInterface(IID_ISequentialInStream, (void**)&s); + c2.CanRead = (s != NULL); + } + { + CMyComPtr 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 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 setStream; + coder.QueryInterface(IID_ICompressSetInStream, (void **)&setStream); + if (setStream) + { + CMyComPtr seqInStream2; + RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + 0, &seqInStream2)); + RINOK(setStream->SetInStream(seqInStream2)); + isSet = true; + } + } + + if (!isSet && numInStreams != 0) + { + CMyComPtr setStream2; + coder.QueryInterface(IID_ICompressSetInStream2, (void **)&setStream2); + if (!setStream2) + return E_NOTIMPL; + + for (UInt32 i = 0; i < numInStreams; i++) + { + CMyComPtr 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 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 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 setOutStream; + coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream); + if (setOutStream) + { + CMyComPtr seqOutStream2; + RINOK(GetOutStream(outStreams, /* outSizes, */ startIndex + 0, &seqOutStream2)); + RINOK(setOutStream->SetOutStream(seqOutStream2)); + isSet = true; + } + } + + if (!isSet && numOutStreams != 0) + { + return E_NOTIMPL; + /* + CMyComPtr setStream2; + coder.QueryInterface(IID_ICompressSetOutStream2, (void **)&setStream2); + if (!setStream2) + return E_NOTIMPL; + for (UInt32 i = 0; i < numOutStreams; i++) + { + CMyComPtr 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 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 > seqInStreams; + CObjectVector< CMyComPtr > 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 seqInStream; + RINOK(GetInStream(inStreams, /* inSizes, */ startInIndex + i, &seqInStream)); + seqInStreams.Add(seqInStream); + } + + for (i = 0; i < numOutStreams; i++) + { + CMyComPtr 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 initEncoder; + coder.QueryInterface(IID_ICompressInitEncoder, (void **)&initEncoder); + if (initEncoder) + RINOK(initEncoder->InitEncoder()); + } + else + { + CMyComPtr 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 seqInStream; + + RINOK(GetInStream2(inStreams, /* inSizes, */ + _bi.UnpackCoder, &seqInStream)) + + FOR_VECTOR (i, _coders) + { + CCoder &coder = _coders[i]; + CMyComPtr 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 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 + +} diff --git a/CPP/7zip/Archive/Common/CoderMixer2.h b/CPP/7zip/Archive/Common/CoderMixer2.h index 4bd641835..798411ab8 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 _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 _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 Coders; - CRecordVector Bonds; - CRecordVector 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 Coder_to_Stream; - CRecordVector 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 Coder; - CMyComPtr Coder2; - UInt32 NumStreams; - - UInt64 UnpackSize; - const UInt64 *UnpackSizePointer; - - CRecordVector PackSizes; - CRecordVector 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 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 _coders; - - CObjectVector _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 InStreamPointers; - CRecordVector OutStreamPointers; - -private: - void Execute(); -public: - bool EncodeMode; - HRESULT Result; - CObjectVector< CMyComPtr > InStreams; - CObjectVector< CMyComPtr > 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 _streamBinders; - - HRESULT Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams); - HRESULT ReturnIfError(HRESULT code); - -public: - CObjectVector _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 __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 _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 _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 Coders; + CRecordVector Bonds; + CRecordVector 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 Coder_to_Stream; + CRecordVector 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 Coder; + CMyComPtr Coder2; + UInt32 NumStreams; + + UInt64 UnpackSize; + const UInt64 *UnpackSizePointer; + + CRecordVector PackSizes; + CRecordVector 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 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 _coders; + + CObjectVector _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 InStreamPointers; + CRecordVector OutStreamPointers; + +private: + void Execute(); +public: + bool EncodeMode; + HRESULT Result; + CObjectVector< CMyComPtr > InStreams; + CObjectVector< CMyComPtr > 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 _streamBinders; + + HRESULT Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams); + HRESULT ReturnIfError(HRESULT code); + +public: + CObjectVector _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 diff --git a/CPP/7zip/Archive/Common/DummyOutStream.cpp b/CPP/7zip/Archive/Common/DummyOutStream.cpp index c7d45e7f9..7c4f54879 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" + +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; +} diff --git a/CPP/7zip/Archive/Common/DummyOutStream.h b/CPP/7zip/Archive/Common/DummyOutStream.h index 30e84c55d..b5a51fc07 100644 --- a/CPP/7zip/Archive/Common/DummyOutStream.h +++ b/CPP/7zip/Archive/Common/DummyOutStream.h @@ -1,25 +1,25 @@ -// 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 _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 __DUMMY_OUT_STREAM_H +#define __DUMMY_OUT_STREAM_H + +#include "../../../Common/MyCom.h" + +#include "../../IStream.h" + +class CDummyOutStream: + public ISequentialOutStream, + public CMyUnknownImp +{ + CMyComPtr _stream; + UInt64 _size; +public: + void SetStream(ISequentialOutStream *outStream) { _stream = outStream; } + void ReleaseStream() { _stream.Release(); } + void Init() { _size = 0; } + MY_UNKNOWN_IMP + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + UInt64 GetSize() const { return _size; } +}; + +#endif diff --git a/CPP/7zip/Archive/Common/FindSignature.cpp b/CPP/7zip/Archive/Common/FindSignature.cpp index 20df2f285..fc952fa8e 100644 --- a/CPP/7zip/Archive/Common/FindSignature.cpp +++ b/CPP/7zip/Archive/Common/FindSignature.cpp @@ -1,62 +1,62 @@ -// FindSignature.cpp - -#include "StdAfx.h" - -#include - -#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 != NULL) - if (resPos > *limit) - return S_FALSE; - do - { - UInt32 numReadBytes = kBufferSize - numPrevBytes; - UInt32 processedSize; - RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize)); - numPrevBytes += processedSize; - if (processedSize == 0) - return S_FALSE; - } - while (numPrevBytes < signatureSize); - UInt32 numTests = numPrevBytes - signatureSize + 1; - for (UInt32 pos = 0; pos < numTests; pos++) - { - Byte b = signature[0]; - for (; buffer[pos] != b && pos < numTests; pos++); - if (pos == numTests) - break; - if (memcmp(buffer + pos, signature, signatureSize) == 0) - { - resPos += pos; - return S_OK; - } - } - resPos += numTests; - numPrevBytes -= numTests; - memmove(buffer, buffer + numTests, numPrevBytes); - } -} +// FindSignature.cpp + +#include "StdAfx.h" + +#include + +#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 != NULL) + if (resPos > *limit) + return S_FALSE; + do + { + UInt32 numReadBytes = kBufferSize - numPrevBytes; + UInt32 processedSize; + RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize)); + numPrevBytes += processedSize; + if (processedSize == 0) + return S_FALSE; + } + while (numPrevBytes < signatureSize); + UInt32 numTests = numPrevBytes - signatureSize + 1; + for (UInt32 pos = 0; pos < numTests; pos++) + { + Byte b = signature[0]; + for (; buffer[pos] != b && pos < numTests; pos++); + if (pos == numTests) + break; + if (memcmp(buffer + pos, signature, signatureSize) == 0) + { + resPos += pos; + return S_OK; + } + } + resPos += numTests; + numPrevBytes -= numTests; + memmove(buffer, buffer + numTests, numPrevBytes); + } +} diff --git a/CPP/7zip/Archive/Common/FindSignature.h b/CPP/7zip/Archive/Common/FindSignature.h index bea139396..c359b9edc 100644 --- a/CPP/7zip/Archive/Common/FindSignature.h +++ b/CPP/7zip/Archive/Common/FindSignature.h @@ -1,12 +1,12 @@ -// FindSignature.h - -#ifndef __FIND_SIGNATURE_H -#define __FIND_SIGNATURE_H - -#include "../../IStream.h" - -HRESULT FindSignatureInStream(ISequentialInStream *stream, - const Byte *signature, unsigned signatureSize, - const UInt64 *limit, UInt64 &resPos); - -#endif +// FindSignature.h + +#ifndef __FIND_SIGNATURE_H +#define __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 41762d900..77a35c74c 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.cpp +++ b/CPP/7zip/Archive/Common/HandlerOut.cpp @@ -1,232 +1,232 @@ -// 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; + + 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 + +} diff --git a/CPP/7zip/Archive/Common/HandlerOut.h b/CPP/7zip/Archive/Common/HandlerOut.h index 90b000ac8..bbb4336e7 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.h +++ b/CPP/7zip/Archive/Common/HandlerOut.h @@ -1,110 +1,110 @@ -// 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 _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 __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 _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 diff --git a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp index cddc083d6..a2d688328 100644 --- a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp +++ b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp @@ -1,46 +1,46 @@ -// 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" + +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); +} diff --git a/CPP/7zip/Archive/Common/InStreamWithCRC.h b/CPP/7zip/Archive/Common/InStreamWithCRC.h index 1a4b2c907..31b761e45 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 _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 _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 __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 _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 _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 e0c35a9b0..d5093a24e 100644 --- a/CPP/7zip/Archive/Common/ItemNameUtils.cpp +++ b/CPP/7zip/Archive/Common/ItemNameUtils.cpp @@ -1,88 +1,88 @@ -// 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; +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 + +}} diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.h b/CPP/7zip/Archive/Common/ItemNameUtils.h index 404fce469..311508643 100644 --- a/CPP/7zip/Archive/Common/ItemNameUtils.h +++ b/CPP/7zip/Archive/Common/ItemNameUtils.h @@ -1,28 +1,28 @@ -// 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 __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 diff --git a/CPP/7zip/Archive/Common/MultiStream.cpp b/CPP/7zip/Archive/Common/MultiStream.cpp index 39d15217f..1de74afe4 100644 --- a/CPP/7zip/Archive/Common/MultiStream.cpp +++ b/CPP/7zip/Archive/Common/MultiStream.cpp @@ -1,191 +1,191 @@ -// 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 _volumeStream; - COutArchive _archive; - CCRC _crc; - -public: - MY_UNKNOWN_IMP - - CFileItem _file; - CUpdateOptions _options; - CMyComPtr 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 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" + +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 _volumeStream; + COutArchive _archive; + CCRC _crc; + +public: + MY_UNKNOWN_IMP + + CFileItem _file; + CUpdateOptions _options; + CMyComPtr 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 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; +} +*/ diff --git a/CPP/7zip/Archive/Common/MultiStream.h b/CPP/7zip/Archive/Common/MultiStream.h index 39e041def..c10cd4557 100644 --- a/CPP/7zip/Archive/Common/MultiStream.h +++ b/CPP/7zip/Archive/Common/MultiStream.h @@ -1,89 +1,89 @@ -// 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 Stream; - UInt64 Size; - UInt64 GlobalOffset; - UInt64 LocalPos; - - CSubStreamInfo(): Size(0), GlobalOffset(0), LocalPos(0) {} - }; - - CObjectVector 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 Stream; - UInt64 Size; - UInt64 Pos; - }; - CObjectVector Streams; -public: - CMyComPtr 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 __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 Stream; + UInt64 Size; + UInt64 GlobalOffset; + UInt64 LocalPos; + + CSubStreamInfo(): Size(0), GlobalOffset(0), LocalPos(0) {} + }; + + CObjectVector 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 Stream; + UInt64 Size; + UInt64 Pos; + }; + CObjectVector Streams; +public: + CMyComPtr VolumeCallback; + void Init() + { + _streamIndex = 0; + _offsetPos = 0; + _absPos = 0; + _length = 0; + } + + MY_UNKNOWN_IMP1(IOutStream) + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); +}; +*/ + +#endif diff --git a/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp b/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp index e0d3894b5..f955c2254 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" + +STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, size, &size); + if (_calculate) + _crc = CrcUpdate(_crc, data, size); + _size += size; + if (processedSize != NULL) + *processedSize = size; + return result; +} diff --git a/CPP/7zip/Archive/Common/OutStreamWithCRC.h b/CPP/7zip/Archive/Common/OutStreamWithCRC.h index 0cc9a859f..09b899bbd 100644 --- a/CPP/7zip/Archive/Common/OutStreamWithCRC.h +++ b/CPP/7zip/Archive/Common/OutStreamWithCRC.h @@ -1,37 +1,37 @@ -// 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 _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 __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 _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 diff --git a/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp index a3412d0a3..77252938c 100644 --- a/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp +++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp @@ -1,18 +1,18 @@ -// OutStreamWithSha1.cpp - -#include "StdAfx.h" - -#include "OutStreamWithSha1.h" - -STDMETHODIMP COutStreamWithSha1::Write(const void *data, UInt32 size, UInt32 *processedSize) -{ - HRESULT result = S_OK; - if (_stream) - result = _stream->Write(data, size, &size); - if (_calculate) - Sha1_Update(&_sha, (const Byte *)data, size); - _size += size; - if (processedSize) - *processedSize = size; - return result; -} +// OutStreamWithSha1.cpp + +#include "StdAfx.h" + +#include "OutStreamWithSha1.h" + +STDMETHODIMP COutStreamWithSha1::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, size, &size); + if (_calculate) + 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 index 36f6c1eed..41a84cd6b 100644 --- a/CPP/7zip/Archive/Common/OutStreamWithSha1.h +++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.h @@ -1,36 +1,36 @@ -// OutStreamWithSha1.h - -#ifndef __OUT_STREAM_WITH_SHA1_H -#define __OUT_STREAM_WITH_SHA1_H - -#include "../../../../C/Sha1.h" - -#include "../../../Common/MyCom.h" - -#include "../../IStream.h" - -class COutStreamWithSha1: - public ISequentialOutStream, - public CMyUnknownImp -{ - CMyComPtr _stream; - UInt64 _size; - CSha1 _sha; - bool _calculate; -public: - MY_UNKNOWN_IMP - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - void Init(bool calculate = true) - { - _size = 0; - _calculate = calculate; - Sha1_Init(&_sha); - } - void InitSha1() { Sha1_Init(&_sha); } - UInt64 GetSize() const { return _size; } - void Final(Byte *digest) { Sha1_Final(&_sha, digest); } -}; - -#endif +// OutStreamWithSha1.h + +#ifndef __OUT_STREAM_WITH_SHA1_H +#define __OUT_STREAM_WITH_SHA1_H + +#include "../../../../C/Sha1.h" + +#include "../../../Common/MyCom.h" + +#include "../../IStream.h" + +class COutStreamWithSha1: + public ISequentialOutStream, + public CMyUnknownImp +{ + CMyComPtr _stream; + UInt64 _size; + CSha1 _sha; + bool _calculate; +public: + MY_UNKNOWN_IMP + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init(bool calculate = true) + { + _size = 0; + _calculate = calculate; + 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 0fe89b3d2..63e4f3efc 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 f4367a76f..1038a8c02 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 __PARSE_PROPERTIES_H +#define __PARSE_PROPERTIES_H + +#endif diff --git a/CPP/7zip/Archive/Common/StdAfx.h b/CPP/7zip/Archive/Common/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Archive/Common/StdAfx.h +++ b/CPP/7zip/Archive/Common/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp index 7ec1dca0f..b8fb530f4 100644 --- a/CPP/7zip/Archive/CpioHandler.cpp +++ b/CPP/7zip/Archive/CpioHandler.cpp @@ -1,795 +1,795 @@ -// 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; - - /* - struct CBinRecord - { - unsigned short c_magic; - short c_dev; - unsigned short c_ino; - unsigned short c_mode; - unsigned short c_uid; - unsigned short c_gid; - unsigned short c_nlink; - short c_rdev; - unsigned short c_mtimes[2]; - unsigned short c_namesize; - unsigned short c_filesizes[2]; - }; - - struct CHexRecord - { - char Magic[6]; - char inode[8]; - char Mode[8]; - char UID[8]; - char GID[8]; - char nlink[8]; - char mtime[8]; - char Size[8]; // must be 0 for FIFOs and directories - char DevMajor[8]; - char DevMinor[8]; - char RDevMajor[8]; //only valid for chr and blk special files - char RDevMinor[8]; //only valid for chr and blk special files - char NameSize[8]; // count includes terminating NUL in pathname - char ChkSum[8]; // 0 for "new" portable format; for CRC format the sum of all the bytes in the file - }; -*/ - -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 -{ - AString Name; - UInt32 inode; - UInt32 Mode; - UInt32 UID; - UInt32 GID; - UInt64 Size; - UInt32 MTime; - - UInt32 NumLinks; - UInt32 DevMajor; - UInt32 DevMinor; - UInt32 RDevMajor; - UInt32 RDevMinor; - UInt32 ChkSum; - - UInt32 Align; - EType Type; - - UInt32 HeaderSize; - UInt64 HeaderPos; - - 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 IsTrailer() const { return strcmp(Name, kName_TRAILER) == 0; } - UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; } -}; - -enum EErrorType -{ - k_ErrorType_OK, - k_ErrorType_Corrupted, - k_ErrorType_UnexpectedEnd, -}; - -struct CInArchive -{ - ISequentialInStream *Stream; - UInt64 Processed; - - HRESULT Read(void *data, size_t *size); - HRESULT GetNextItem(CItem &item, EErrorType &errorType); -}; - -HRESULT CInArchive::Read(void *data, size_t *size) -{ - HRESULT res = ReadStream(Stream, data, size); - Processed += *size; - return res; -} - -static bool ReadHex(const Byte *p, UInt32 &resVal) -{ - char sz[16]; - memcpy(sz, p, 8); - sz[8] = 0; - const char *end; - resVal = ConvertHexStringToUInt32(sz, &end); - return (unsigned)(end - sz) == 8; -} - -static bool ReadOct6(const Byte *p, UInt32 &resVal) -{ - char sz[16]; - memcpy(sz, p, 6); - sz[6] = 0; - const char *end; - resVal = ConvertOctStringToUInt32(sz, &end); - return (unsigned)(end - sz) == 6; -} - -static bool ReadOct11(const Byte *p, UInt64 &resVal) -{ - char sz[16]; - memcpy(sz, p, 11); - sz[11] = 0; - const char *end; - resVal = ConvertOctStringToUInt64(sz, &end); - return (unsigned)(end - sz) == 11; -} - - -#define READ_HEX(y) { if (!ReadHex(p2, y)) return S_OK; p2 += 8; } -#define READ_OCT_6(y) { if (!ReadOct6(p2, y)) return S_OK; p2 += 6; } -#define READ_OCT_11(y) { if (!ReadOct11(p2, y)) return S_OK; p2 += 11; } - -static UInt32 GetAlignedSize(UInt32 size, UInt32 align) -{ - while ((size & (align - 1)) != 0) - size++; - return size; -} - -static UInt16 Get16(const Byte *p, bool be) { if (be) return GetBe16(p); return GetUi16(p); } -static UInt32 Get32(const Byte *p, bool be) { return ((UInt32)Get16(p, be) << 16) + Get16(p + 2, be); } - -#define G16(offs, v) v = Get16(p + (offs), be) -#define G32(offs, v) v = Get32(p + (offs), be) - -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 nameSize; - UInt32 numLinks; - 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] == '7') - { - if (size < k_OctRecord_Size) - return k_IsArc_Res_NEED_MORE; - for (int i = 6; i < k_OctRecord_Size; i++) - { - char c = p[i]; - if (c < '0' || c > '7') - return k_IsArc_Res_NO; - } - ReadOct6(p + 6 * 6, numLinks); - ReadOct6(p + 8 * 6 + 11, nameSize); - } - else if (p[5] == '1' || p[5] == '2') - { - if (size < k_HexRecord_Size) - return k_IsArc_Res_NEED_MORE; - for (int i = 6; i < k_HexRecord_Size; i++) - { - char c = p[i]; - if ((c < '0' || c > '9') && - (c < 'A' || c > 'F') && - (c < 'a' || c > 'f')) - return k_IsArc_Res_NO; - } - ReadHex(p + 6 + 4 * 8, numLinks); - ReadHex(p + 6 + 11 * 8, nameSize); - } - else - return k_IsArc_Res_NO; - } - else - { - UInt32 rDevMinor; - if (p[0] == kMagicBin0 && p[1] == kMagicBin1) - { - numLinks = GetUi16(p + 12); - rDevMinor = GetUi16(p + 14); - nameSize = GetUi16(p + 20); - } - else if (p[0] == kMagicBin1 && p[1] == kMagicBin0) - { - numLinks = GetBe16(p + 12); - rDevMinor = GetBe16(p + 14); - nameSize = GetBe16(p + 20); - } - else - return k_IsArc_Res_NO; - - if (rDevMinor != 0) - return k_IsArc_Res_NO; - if (nameSize > (1 << 8)) - return k_IsArc_Res_NO; - } - if (numLinks == 0 || numLinks >= (1 << 10)) - return k_IsArc_Res_NO; - if (nameSize == 0 || nameSize > kNameSizeMax) - 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(CItem &item, EErrorType &errorType) -{ - errorType = k_ErrorType_Corrupted; - - Byte p[k_RecordSize_Max]; - - READ_STREAM(p, k_BinRecord_Size) - - UInt32 nameSize; - - if (p[0] != '0') - { - bool be; - if (p[0] == kMagicBin0 && p[1] == kMagicBin1) { be = false; item.Type = k_Type_BinLe; } - else if (p[0] == kMagicBin1 && p[1] == kMagicBin0) { be = true; item.Type = k_Type_BinBe; } - else return S_FALSE; - - item.Align = 2; - 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); - - /* - if (item.RDevMinor != 0) - return S_FALSE; - */ - - item.HeaderSize = GetAlignedSize(nameSize + k_BinRecord_Size, item.Align); - nameSize = item.HeaderSize - k_BinRecord_Size; - } - else - { - if (p[1] != '7' || - p[2] != '0' || - p[3] != '7' || - p[4] != '0') - return S_FALSE; - if (p[5] == kMagicOct) - { - item.Type = k_Type_Oct; - READ_STREAM(p + k_BinRecord_Size, k_OctRecord_Size - k_BinRecord_Size) - item.Align = 1; - item.DevMajor = 0; - item.RDevMajor = 0; - - const Byte *p2 = p + 6; - READ_OCT_6(item.DevMinor); - READ_OCT_6(item.inode); - READ_OCT_6(item.Mode); - READ_OCT_6(item.UID); - READ_OCT_6(item.GID); - READ_OCT_6(item.NumLinks); - READ_OCT_6(item.RDevMinor); - { - UInt64 mTime64; - READ_OCT_11(mTime64); - item.MTime = 0; - if (mTime64 < (UInt32)(Int32)-1) - item.MTime = (UInt32)mTime64; - } - READ_OCT_6(nameSize); - READ_OCT_11(item.Size); // ????? - item.HeaderSize = GetAlignedSize(nameSize + k_OctRecord_Size, item.Align); - nameSize = item.HeaderSize - 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_FALSE; - - READ_STREAM(p + k_BinRecord_Size, k_HexRecord_Size - k_BinRecord_Size) - - item.Align = 4; - - const Byte *p2 = p + 6; - READ_HEX(item.inode); - READ_HEX(item.Mode); - READ_HEX(item.UID); - READ_HEX(item.GID); - READ_HEX(item.NumLinks); - READ_HEX(item.MTime); - { - UInt32 size32; - READ_HEX(size32); - item.Size = size32; - } - READ_HEX(item.DevMajor); - READ_HEX(item.DevMinor); - READ_HEX(item.RDevMajor); - READ_HEX(item.RDevMinor); - READ_HEX(nameSize); - READ_HEX(item.ChkSum); - if (nameSize >= kNameSizeMax) - return S_OK; - item.HeaderSize = GetAlignedSize(nameSize + k_HexRecord_Size, item.Align); - nameSize = item.HeaderSize - k_HexRecord_Size; - } - } - if (nameSize > kNameSizeMax) - return S_FALSE; - if (nameSize == 0 || nameSize >= kNameSizeMax) - return S_OK; - char *s = item.Name.GetBuf(nameSize); - size_t processedSize = nameSize; - RINOK(Read(s, &processedSize)); - item.Name.ReleaseBuf_CalcLen(nameSize); - if (processedSize != nameSize) - { - errorType = k_ErrorType_UnexpectedEnd; - return S_OK; - } - errorType = k_ErrorType_OK; - return S_OK; -} - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - CObjectVector _items; - CMyComPtr _stream; - UInt64 _phySize; - EType _Type; - EErrorType _error; - bool _isArc; -public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); -}; - -static const Byte kArcProps[] = -{ - kpidSubType -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidMTime, - kpidPosixAttrib, - kpidLinks -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP 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 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; - } - prop = v; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) -{ - COM_TRY_BEGIN - { - Close(); - - UInt64 endPos = 0; - - RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); - RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); - if (callback) - { - RINOK(callback->SetTotal(NULL, &endPos)); - } - - _items.Clear(); - CInArchive arc; - - arc.Stream = stream; - arc.Processed = 0; - - for (;;) - { - CItem item; - item.HeaderPos = arc.Processed; - HRESULT result = arc.GetNextItem(item, _error); - if (result == S_FALSE) - return S_FALSE; - if (result != S_OK) - return S_FALSE; - if (_error != k_ErrorType_OK) - { - if (_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; - - _items.Add(item); - - { - // archive.SkipDataRecords(item.Size, item.Align); - UInt64 dataSize = item.Size; - UInt32 align = item.Align; - while ((dataSize & (align - 1)) != 0) - dataSize++; - - // _error = k_ErrorType_UnexpectedEnd; break; - - arc.Processed += dataSize; - if (arc.Processed > endPos) - { - _error = k_ErrorType_UnexpectedEnd; - break; - } - - UInt64 newPostion; - RINOK(stream->Seek(dataSize, STREAM_SEEK_CUR, &newPostion)); - if (arc.Processed != newPostion) - return E_FAIL; - } - - if (callback && (_items.Size() & 0xFF) == 0) - { - UInt64 numFiles = _items.Size(); - RINOK(callback->SetCompleted(&numFiles, &item.HeaderPos)); - } - } - _phySize = arc.Processed; - if (_error != k_ErrorType_OK) - { - if (_items.Size() == 0) - return S_FALSE; - if (_items.Size() == 1 && _items[0].IsBin()) - { - // probably it's false detected archive. So we return error - return S_FALSE; - } - } - else - { - // Read tailing zeros. - // Most of cpio files use 512-bytes aligned zeros - UInt64 pos = arc.Processed; - const UInt32 kTailSize_MAX = 1 << 9; - Byte buf[kTailSize_MAX]; - - UInt32 rem = (kTailSize_MAX - (UInt32)pos) & (kTailSize_MAX - 1); - if (rem != 0) - { - rem++; // we need to see that it's end of file - size_t processed = rem; - RINOK(ReadStream(stream, buf, &processed)); - if (processed < rem) - { - unsigned i; - for (i = 0; i < processed && buf[i] == 0; i++); - if (i == processed) - _phySize += processed; - } - } - } - - _isArc = true; - _stream = stream; - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _items.Clear(); - _stream.Release(); - _phySize = 0; - _Type = k_Type_BinLe; - _isArc = false; - _error = k_ErrorType_OK; - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - const CItem &item = _items[index]; - - 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: - case kpidPackSize: - prop = (UInt64)item.Size; - break; - case kpidMTime: - { - if (item.MTime != 0) - { - FILETIME utc; - NTime::UnixTimeToFileTime(item.MTime, utc); - prop = utc; - } - break; - } - case kpidPosixAttrib: prop = item.Mode; break; - case kpidLinks: prop = item.NumLinks; break; - /* - case kpidinode: prop = item.inode; break; - case kpidiChkSum: prop = item.ChkSum; break; - */ - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -class COutStreamWithSum: - public ISequentialOutStream, - public CMyUnknownImp -{ - CMyComPtr _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 = 0; - } - void EnableCalc(bool calculate) { _calculate = calculate; } - void InitCRC() { _crc = 0; } - UInt64 GetSize() const { return _size; } - UInt32 GetCRC() const { return _crc; } -}; - -STDMETHODIMP 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; -} - -STDMETHODIMP 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 (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - totalSize += _items[allFilesMode ? i : indices[i]].Size; - extractCallback->SetTotal(totalSize); - - UInt64 currentTotalSize = 0; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_stream); - - COutStreamWithSum *outStreamSumSpec = new COutStreamWithSum; - CMyComPtr outStreamSum(outStreamSumSpec); - - for (i = 0; i < numItems; i++) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()); - CMyComPtr outStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - RINOK(extractCallback->GetStream(index, &outStream, askMode)); - currentTotalSize += item.Size; - if (item.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(_stream->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL)); - 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 -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - const CItem &item = _items[index]; - 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", 0, 0xED, - k_Signature, - 0, - NArcInfoFlags::kMultiSignature, - IsArc_Cpio) - -}} +// 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; + + /* + struct CBinRecord + { + unsigned short c_magic; + short c_dev; + unsigned short c_ino; + unsigned short c_mode; + unsigned short c_uid; + unsigned short c_gid; + unsigned short c_nlink; + short c_rdev; + unsigned short c_mtimes[2]; + unsigned short c_namesize; + unsigned short c_filesizes[2]; + }; + + struct CHexRecord + { + char Magic[6]; + char inode[8]; + char Mode[8]; + char UID[8]; + char GID[8]; + char nlink[8]; + char mtime[8]; + char Size[8]; // must be 0 for FIFOs and directories + char DevMajor[8]; + char DevMinor[8]; + char RDevMajor[8]; //only valid for chr and blk special files + char RDevMinor[8]; //only valid for chr and blk special files + char NameSize[8]; // count includes terminating NUL in pathname + char ChkSum[8]; // 0 for "new" portable format; for CRC format the sum of all the bytes in the file + }; +*/ + +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 +{ + AString Name; + UInt32 inode; + UInt32 Mode; + UInt32 UID; + UInt32 GID; + UInt64 Size; + UInt32 MTime; + + UInt32 NumLinks; + UInt32 DevMajor; + UInt32 DevMinor; + UInt32 RDevMajor; + UInt32 RDevMinor; + UInt32 ChkSum; + + UInt32 Align; + EType Type; + + UInt32 HeaderSize; + UInt64 HeaderPos; + + 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 IsTrailer() const { return strcmp(Name, kName_TRAILER) == 0; } + UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; } +}; + +enum EErrorType +{ + k_ErrorType_OK, + k_ErrorType_Corrupted, + k_ErrorType_UnexpectedEnd, +}; + +struct CInArchive +{ + ISequentialInStream *Stream; + UInt64 Processed; + + HRESULT Read(void *data, size_t *size); + HRESULT GetNextItem(CItem &item, EErrorType &errorType); +}; + +HRESULT CInArchive::Read(void *data, size_t *size) +{ + HRESULT res = ReadStream(Stream, data, size); + Processed += *size; + return res; +} + +static bool ReadHex(const Byte *p, UInt32 &resVal) +{ + char sz[16]; + memcpy(sz, p, 8); + sz[8] = 0; + const char *end; + resVal = ConvertHexStringToUInt32(sz, &end); + return (unsigned)(end - sz) == 8; +} + +static bool ReadOct6(const Byte *p, UInt32 &resVal) +{ + char sz[16]; + memcpy(sz, p, 6); + sz[6] = 0; + const char *end; + resVal = ConvertOctStringToUInt32(sz, &end); + return (unsigned)(end - sz) == 6; +} + +static bool ReadOct11(const Byte *p, UInt64 &resVal) +{ + char sz[16]; + memcpy(sz, p, 11); + sz[11] = 0; + const char *end; + resVal = ConvertOctStringToUInt64(sz, &end); + return (unsigned)(end - sz) == 11; +} + + +#define READ_HEX(y) { if (!ReadHex(p2, y)) return S_OK; p2 += 8; } +#define READ_OCT_6(y) { if (!ReadOct6(p2, y)) return S_OK; p2 += 6; } +#define READ_OCT_11(y) { if (!ReadOct11(p2, y)) return S_OK; p2 += 11; } + +static UInt32 GetAlignedSize(UInt32 size, UInt32 align) +{ + while ((size & (align - 1)) != 0) + size++; + return size; +} + +static UInt16 Get16(const Byte *p, bool be) { if (be) return GetBe16(p); return GetUi16(p); } +static UInt32 Get32(const Byte *p, bool be) { return ((UInt32)Get16(p, be) << 16) + Get16(p + 2, be); } + +#define G16(offs, v) v = Get16(p + (offs), be) +#define G32(offs, v) v = Get32(p + (offs), be) + +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 nameSize; + UInt32 numLinks; + 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] == '7') + { + if (size < k_OctRecord_Size) + return k_IsArc_Res_NEED_MORE; + for (int i = 6; i < k_OctRecord_Size; i++) + { + char c = p[i]; + if (c < '0' || c > '7') + return k_IsArc_Res_NO; + } + ReadOct6(p + 6 * 6, numLinks); + ReadOct6(p + 8 * 6 + 11, nameSize); + } + else if (p[5] == '1' || p[5] == '2') + { + if (size < k_HexRecord_Size) + return k_IsArc_Res_NEED_MORE; + for (int i = 6; i < k_HexRecord_Size; i++) + { + char c = p[i]; + if ((c < '0' || c > '9') && + (c < 'A' || c > 'F') && + (c < 'a' || c > 'f')) + return k_IsArc_Res_NO; + } + ReadHex(p + 6 + 4 * 8, numLinks); + ReadHex(p + 6 + 11 * 8, nameSize); + } + else + return k_IsArc_Res_NO; + } + else + { + UInt32 rDevMinor; + if (p[0] == kMagicBin0 && p[1] == kMagicBin1) + { + numLinks = GetUi16(p + 12); + rDevMinor = GetUi16(p + 14); + nameSize = GetUi16(p + 20); + } + else if (p[0] == kMagicBin1 && p[1] == kMagicBin0) + { + numLinks = GetBe16(p + 12); + rDevMinor = GetBe16(p + 14); + nameSize = GetBe16(p + 20); + } + else + return k_IsArc_Res_NO; + + if (rDevMinor != 0) + return k_IsArc_Res_NO; + if (nameSize > (1 << 8)) + return k_IsArc_Res_NO; + } + if (numLinks == 0 || numLinks >= (1 << 10)) + return k_IsArc_Res_NO; + if (nameSize == 0 || nameSize > kNameSizeMax) + 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(CItem &item, EErrorType &errorType) +{ + errorType = k_ErrorType_Corrupted; + + Byte p[k_RecordSize_Max]; + + READ_STREAM(p, k_BinRecord_Size) + + UInt32 nameSize; + + if (p[0] != '0') + { + bool be; + if (p[0] == kMagicBin0 && p[1] == kMagicBin1) { be = false; item.Type = k_Type_BinLe; } + else if (p[0] == kMagicBin1 && p[1] == kMagicBin0) { be = true; item.Type = k_Type_BinBe; } + else return S_FALSE; + + item.Align = 2; + 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); + + /* + if (item.RDevMinor != 0) + return S_FALSE; + */ + + item.HeaderSize = GetAlignedSize(nameSize + k_BinRecord_Size, item.Align); + nameSize = item.HeaderSize - k_BinRecord_Size; + } + else + { + if (p[1] != '7' || + p[2] != '0' || + p[3] != '7' || + p[4] != '0') + return S_FALSE; + if (p[5] == kMagicOct) + { + item.Type = k_Type_Oct; + READ_STREAM(p + k_BinRecord_Size, k_OctRecord_Size - k_BinRecord_Size) + item.Align = 1; + item.DevMajor = 0; + item.RDevMajor = 0; + + const Byte *p2 = p + 6; + READ_OCT_6(item.DevMinor); + READ_OCT_6(item.inode); + READ_OCT_6(item.Mode); + READ_OCT_6(item.UID); + READ_OCT_6(item.GID); + READ_OCT_6(item.NumLinks); + READ_OCT_6(item.RDevMinor); + { + UInt64 mTime64; + READ_OCT_11(mTime64); + item.MTime = 0; + if (mTime64 < (UInt32)(Int32)-1) + item.MTime = (UInt32)mTime64; + } + READ_OCT_6(nameSize); + READ_OCT_11(item.Size); // ????? + item.HeaderSize = GetAlignedSize(nameSize + k_OctRecord_Size, item.Align); + nameSize = item.HeaderSize - 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_FALSE; + + READ_STREAM(p + k_BinRecord_Size, k_HexRecord_Size - k_BinRecord_Size) + + item.Align = 4; + + const Byte *p2 = p + 6; + READ_HEX(item.inode); + READ_HEX(item.Mode); + READ_HEX(item.UID); + READ_HEX(item.GID); + READ_HEX(item.NumLinks); + READ_HEX(item.MTime); + { + UInt32 size32; + READ_HEX(size32); + item.Size = size32; + } + READ_HEX(item.DevMajor); + READ_HEX(item.DevMinor); + READ_HEX(item.RDevMajor); + READ_HEX(item.RDevMinor); + READ_HEX(nameSize); + READ_HEX(item.ChkSum); + if (nameSize >= kNameSizeMax) + return S_OK; + item.HeaderSize = GetAlignedSize(nameSize + k_HexRecord_Size, item.Align); + nameSize = item.HeaderSize - k_HexRecord_Size; + } + } + if (nameSize > kNameSizeMax) + return S_FALSE; + if (nameSize == 0 || nameSize >= kNameSizeMax) + return S_OK; + char *s = item.Name.GetBuf(nameSize); + size_t processedSize = nameSize; + RINOK(Read(s, &processedSize)); + item.Name.ReleaseBuf_CalcLen(nameSize); + if (processedSize != nameSize) + { + errorType = k_ErrorType_UnexpectedEnd; + return S_OK; + } + errorType = k_ErrorType_OK; + return S_OK; +} + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CObjectVector _items; + CMyComPtr _stream; + UInt64 _phySize; + EType _Type; + EErrorType _error; + bool _isArc; +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +static const Byte kArcProps[] = +{ + kpidSubType +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidMTime, + kpidPosixAttrib, + kpidLinks +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP 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 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; + } + prop = v; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + { + Close(); + + UInt64 endPos = 0; + + RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + if (callback) + { + RINOK(callback->SetTotal(NULL, &endPos)); + } + + _items.Clear(); + CInArchive arc; + + arc.Stream = stream; + arc.Processed = 0; + + for (;;) + { + CItem item; + item.HeaderPos = arc.Processed; + HRESULT result = arc.GetNextItem(item, _error); + if (result == S_FALSE) + return S_FALSE; + if (result != S_OK) + return S_FALSE; + if (_error != k_ErrorType_OK) + { + if (_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; + + _items.Add(item); + + { + // archive.SkipDataRecords(item.Size, item.Align); + UInt64 dataSize = item.Size; + UInt32 align = item.Align; + while ((dataSize & (align - 1)) != 0) + dataSize++; + + // _error = k_ErrorType_UnexpectedEnd; break; + + arc.Processed += dataSize; + if (arc.Processed > endPos) + { + _error = k_ErrorType_UnexpectedEnd; + break; + } + + UInt64 newPostion; + RINOK(stream->Seek(dataSize, STREAM_SEEK_CUR, &newPostion)); + if (arc.Processed != newPostion) + return E_FAIL; + } + + if (callback && (_items.Size() & 0xFF) == 0) + { + UInt64 numFiles = _items.Size(); + RINOK(callback->SetCompleted(&numFiles, &item.HeaderPos)); + } + } + _phySize = arc.Processed; + if (_error != k_ErrorType_OK) + { + if (_items.Size() == 0) + return S_FALSE; + if (_items.Size() == 1 && _items[0].IsBin()) + { + // probably it's false detected archive. So we return error + return S_FALSE; + } + } + else + { + // Read tailing zeros. + // Most of cpio files use 512-bytes aligned zeros + UInt64 pos = arc.Processed; + const UInt32 kTailSize_MAX = 1 << 9; + Byte buf[kTailSize_MAX]; + + UInt32 rem = (kTailSize_MAX - (UInt32)pos) & (kTailSize_MAX - 1); + if (rem != 0) + { + rem++; // we need to see that it's end of file + size_t processed = rem; + RINOK(ReadStream(stream, buf, &processed)); + if (processed < rem) + { + unsigned i; + for (i = 0; i < processed && buf[i] == 0; i++); + if (i == processed) + _phySize += processed; + } + } + } + + _isArc = true; + _stream = stream; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _items.Clear(); + _stream.Release(); + _phySize = 0; + _Type = k_Type_BinLe; + _isArc = false; + _error = k_ErrorType_OK; + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + const CItem &item = _items[index]; + + 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: + case kpidPackSize: + prop = (UInt64)item.Size; + break; + case kpidMTime: + { + if (item.MTime != 0) + { + FILETIME utc; + NTime::UnixTimeToFileTime(item.MTime, utc); + prop = utc; + } + break; + } + case kpidPosixAttrib: prop = item.Mode; break; + case kpidLinks: prop = item.NumLinks; break; + /* + case kpidinode: prop = item.inode; break; + case kpidiChkSum: prop = item.ChkSum; break; + */ + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +class COutStreamWithSum: + public ISequentialOutStream, + public CMyUnknownImp +{ + CMyComPtr _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 = 0; + } + void EnableCalc(bool calculate) { _calculate = calculate; } + void InitCRC() { _crc = 0; } + UInt64 GetSize() const { return _size; } + UInt32 GetCRC() const { return _crc; } +}; + +STDMETHODIMP 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; +} + +STDMETHODIMP 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 (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _items[allFilesMode ? i : indices[i]].Size; + extractCallback->SetTotal(totalSize); + + UInt64 currentTotalSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(_stream); + + COutStreamWithSum *outStreamSumSpec = new COutStreamWithSum; + CMyComPtr outStreamSum(outStreamSumSpec); + + for (i = 0; i < numItems; i++) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + CMyComPtr outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + currentTotalSize += item.Size; + if (item.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(_stream->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL)); + 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 +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + const CItem &item = _items[index]; + 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", 0, 0xED, + k_Signature, + 0, + NArcInfoFlags::kMultiSignature, + IsArc_Cpio) + +}} diff --git a/CPP/7zip/Archive/CramfsHandler.cpp b/CPP/7zip/Archive/CramfsHandler.cpp index a1fa564ea..0f1233210 100644 --- a/CPP/7zip/Archive/CramfsHandler.cpp +++ b/CPP/7zip/Archive/CramfsHandler.cpp @@ -1,787 +1,787 @@ -// 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 { - -#define SIGNATURE { 'C','o','m','p','r','e','s','s','e','d',' ','R','O','M','F','S' } - -static const Byte kSignature[] = SIGNATURE; - -static const UInt32 kArcSizeMax = (256 + 16) << 20; -static const UInt32 kNumFilesMax = (1 << 19); -static const unsigned kNumDirLevelsMax = (1 << 8); - -static const UInt32 kHeaderSize = 0x40; -static const unsigned kHeaderNameSize = 16; -static const UInt32 kNodeSize = 12; - -static const UInt32 kFlag_FsVer2 = (1 << 0); - -static const 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 (p[8] & 0x3F) << 2; -} - -static UInt32 GetOffset(const Byte *p, bool be) -{ - if (be) - return (GetBe32(p + 8) & 0x03FFFFFF) << 2; - else - return GetUi32(p + 8) >> 6 << 2; -} - -struct CItem -{ - UInt32 Offset; - int Parent; -}; - -struct CHeader -{ - bool be; - UInt32 Size; - UInt32 Flags; - // UInt32 Future; - UInt32 Crc; - // UInt32 Edition; - UInt32 NumBlocks; - UInt32 NumFiles; - char Name[kHeaderNameSize]; - - bool Parse(const Byte *p) - { - if (memcmp(p + 16, kSignature, 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; } -}; - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - CRecordVector _items; - CMyComPtr _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 _zlibDecoder; - - CBufInStream *_inStreamSpec; - CMyComPtr _inStream; - - CBufPtrSeqOutStream *_outStreamSpec; - CMyComPtr _outStream; - - UInt32 _curBlocksOffset; - UInt32 _curNumBlocks; - - HRESULT OpenDir(int parent, UInt32 baseOffsetBase, unsigned level); - HRESULT Open2(IInStream *inStream); - AString GetPath(int index) const; - bool GetPackSize(int index, UInt32 &res) const; - void Free(); - - UInt32 GetNumBlocks(UInt32 size) const - { - return (size + ((UInt32)1 << _blockSizeLog) - 1) >> _blockSizeLog; - } - - void UpdatePhySize(UInt32 s) - { - if (_phySize < s) - _phySize = s; - } - -public: - CHandler(): _data(0) {} - ~CHandler() { Free(); } - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); -}; - -static const 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(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->Seek(0, STREAM_SEEK_END, &size)); - if (size > kArcSizeMax) - size = kArcSizeMax; - _h.Size = (UInt32)size; - RINOK(inStream->Seek(kHeaderSize, STREAM_SEEK_SET, NULL)); - } - _data = (Byte *)MidAlloc(_h.Size); - if (_data == 0) - return E_OUTOFMEMORY; - memcpy(_data, buf, kHeaderSize); - size_t processed = _h.Size - kHeaderSize; - RINOK(ReadStream(inStream, _data + kHeaderSize, &processed)); - if (processed < kNodeSize) - return S_FALSE; - _size = kHeaderSize + (UInt32)processed; - if (_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(int index) const -{ - unsigned len = 0; - int indexMem = index; - do - { - const CItem &item = _items[index]; - index = item.Parent; - const Byte *p = _data + item.Offset; - unsigned size = GetNameLen(p, _h.be); - p += kNodeSize; - unsigned i; - for (i = 0; i < size && p[i]; i++); - len += i + 1; - } - while (index >= 0); - len--; - - AString path; - char *dest = path.GetBuf_SetEnd(len) + len; - index = indexMem; - for (;;) - { - const CItem &item = _items[index]; - index = item.Parent; - const Byte *p = _data + item.Offset; - unsigned size = GetNameLen(p, _h.be); - p += kNodeSize; - unsigned i; - for (i = 0; i < size && p[i]; i++); - dest -= i; - memcpy(dest, p, i); - if (index < 0) - break; - *(--dest) = CHAR_PATH_SEPARATOR; - } - return path; -} - -bool CHandler::GetPackSize(int index, UInt32 &res) const -{ - res = 0; - const CItem &item = _items[index]; - const Byte *p = _data + item.Offset; - bool be = _h.be; - UInt32 offset = GetOffset(p, be); - if (offset < kHeaderSize) - return false; - UInt32 numBlocks = GetNumBlocks(GetSize(p, be)); - if (numBlocks == 0) - return true; - UInt32 start = offset + numBlocks * 4; - if (start > _size) - return false; - UInt32 end = Get32(_data + start - 4); - if (end < start) - return false; - res = end - start; - return true; -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */) -{ - COM_TRY_BEGIN - { - Close(); - RINOK(Open2(stream)); - _isArc = true; - _stream = stream; - } - return S_OK; - COM_TRY_END -} - -void CHandler::Free() -{ - MidFree(_data); - _data = 0; -} - -STDMETHODIMP CHandler::Close() -{ - _isArc = false; - _phySize = 0; - _errorFlags = 0; - _headersSize = 0; - _items.Clear(); - _stream.Release(); - Free(); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case 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 -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem &item = _items[index]; - const Byte *p = _data + item.Offset; - bool be = _h.be; - bool isDir = IsDir(p, be); - switch (propID) - { - case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break; - case kpidIsDir: prop = isDir; break; - // case kpidOffset: prop = (UInt32)GetOffset(p, be); break; - case kpidSize: if (!isDir) prop = GetSize(p, be); break; - case kpidPackSize: - if (!isDir) - { - UInt32 size; - if (GetPackSize(index, size)) - prop = size; - } - break; - case kpidPosixAttrib: prop = (UInt32)GetMode(p, be); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -class CCramfsInStream: public CCachedInStream -{ - HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); -public: - CHandler *Handler; -}; - -HRESULT CCramfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) -{ - return Handler->ReadBlock(blockIndex, dest, blockSize); -} - -HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) -{ - if (_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; -} - -STDMETHODIMP 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 (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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - CMyComPtr outStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - UInt32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - RINOK(extractCallback->GetStream(index, &outStream, askMode)); - const Byte *p = _data + item.Offset; - - if (IsDir(p, be)) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - UInt32 curSize = GetSize(p, be); - totalSize += curSize; - UInt32 packSize; - if (GetPackSize(index, packSize)) - totalPackSize += packSize; - - if (!testMode && !outStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - - UInt32 offset = GetOffset(p, be); - if (offset < kHeaderSize) - curSize = 0; - - int res = NExtract::NOperationResult::kDataError; - { - CMyComPtr 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 -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - - const CItem &item = _items[index]; - const Byte *p = _data + item.Offset; - - bool be = _h.be; - if (IsDir(p, be)) - return E_FAIL; - - UInt32 size = GetSize(p, be); - UInt32 numBlocks = GetNumBlocks(size); - UInt32 offset = GetOffset(p, be); - if (offset < kHeaderSize) - { - if (offset != 0) - return S_FALSE; - CBufInStream *streamSpec = new CBufInStream; - CMyComPtr 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 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", 0, 0xD3, - kSignature, - 16, - 0, - NULL) - -}} +// 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 { + +#define SIGNATURE { 'C','o','m','p','r','e','s','s','e','d',' ','R','O','M','F','S' } + +static const Byte kSignature[] = SIGNATURE; + +static const UInt32 kArcSizeMax = (256 + 16) << 20; +static const UInt32 kNumFilesMax = (1 << 19); +static const unsigned kNumDirLevelsMax = (1 << 8); + +static const UInt32 kHeaderSize = 0x40; +static const unsigned kHeaderNameSize = 16; +static const UInt32 kNodeSize = 12; + +static const UInt32 kFlag_FsVer2 = (1 << 0); + +static const 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 (p[8] & 0x3F) << 2; +} + +static UInt32 GetOffset(const Byte *p, bool be) +{ + if (be) + return (GetBe32(p + 8) & 0x03FFFFFF) << 2; + else + return GetUi32(p + 8) >> 6 << 2; +} + +struct CItem +{ + UInt32 Offset; + int Parent; +}; + +struct CHeader +{ + bool be; + UInt32 Size; + UInt32 Flags; + // UInt32 Future; + UInt32 Crc; + // UInt32 Edition; + UInt32 NumBlocks; + UInt32 NumFiles; + char Name[kHeaderNameSize]; + + bool Parse(const Byte *p) + { + if (memcmp(p + 16, kSignature, 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; } +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CRecordVector _items; + CMyComPtr _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 _zlibDecoder; + + CBufInStream *_inStreamSpec; + CMyComPtr _inStream; + + CBufPtrSeqOutStream *_outStreamSpec; + CMyComPtr _outStream; + + UInt32 _curBlocksOffset; + UInt32 _curNumBlocks; + + HRESULT OpenDir(int parent, UInt32 baseOffsetBase, unsigned level); + HRESULT Open2(IInStream *inStream); + AString GetPath(int index) const; + bool GetPackSize(int index, UInt32 &res) const; + void Free(); + + UInt32 GetNumBlocks(UInt32 size) const + { + return (size + ((UInt32)1 << _blockSizeLog) - 1) >> _blockSizeLog; + } + + void UpdatePhySize(UInt32 s) + { + if (_phySize < s) + _phySize = s; + } + +public: + CHandler(): _data(0) {} + ~CHandler() { Free(); } + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); +}; + +static const 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(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->Seek(0, STREAM_SEEK_END, &size)); + if (size > kArcSizeMax) + size = kArcSizeMax; + _h.Size = (UInt32)size; + RINOK(inStream->Seek(kHeaderSize, STREAM_SEEK_SET, NULL)); + } + _data = (Byte *)MidAlloc(_h.Size); + if (_data == 0) + return E_OUTOFMEMORY; + memcpy(_data, buf, kHeaderSize); + size_t processed = _h.Size - kHeaderSize; + RINOK(ReadStream(inStream, _data + kHeaderSize, &processed)); + if (processed < kNodeSize) + return S_FALSE; + _size = kHeaderSize + (UInt32)processed; + if (_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(int index) const +{ + unsigned len = 0; + int indexMem = index; + do + { + const CItem &item = _items[index]; + index = item.Parent; + const Byte *p = _data + item.Offset; + unsigned size = GetNameLen(p, _h.be); + p += kNodeSize; + unsigned i; + for (i = 0; i < size && p[i]; i++); + len += i + 1; + } + while (index >= 0); + len--; + + AString path; + char *dest = path.GetBuf_SetEnd(len) + len; + index = indexMem; + for (;;) + { + const CItem &item = _items[index]; + index = item.Parent; + const Byte *p = _data + item.Offset; + unsigned size = GetNameLen(p, _h.be); + p += kNodeSize; + unsigned i; + for (i = 0; i < size && p[i]; i++); + dest -= i; + memcpy(dest, p, i); + if (index < 0) + break; + *(--dest) = CHAR_PATH_SEPARATOR; + } + return path; +} + +bool CHandler::GetPackSize(int index, UInt32 &res) const +{ + res = 0; + const CItem &item = _items[index]; + const Byte *p = _data + item.Offset; + bool be = _h.be; + UInt32 offset = GetOffset(p, be); + if (offset < kHeaderSize) + return false; + UInt32 numBlocks = GetNumBlocks(GetSize(p, be)); + if (numBlocks == 0) + return true; + UInt32 start = offset + numBlocks * 4; + if (start > _size) + return false; + UInt32 end = Get32(_data + start - 4); + if (end < start) + return false; + res = end - start; + return true; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */) +{ + COM_TRY_BEGIN + { + Close(); + RINOK(Open2(stream)); + _isArc = true; + _stream = stream; + } + return S_OK; + COM_TRY_END +} + +void CHandler::Free() +{ + MidFree(_data); + _data = 0; +} + +STDMETHODIMP CHandler::Close() +{ + _isArc = false; + _phySize = 0; + _errorFlags = 0; + _headersSize = 0; + _items.Clear(); + _stream.Release(); + Free(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case 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 +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem &item = _items[index]; + const Byte *p = _data + item.Offset; + bool be = _h.be; + bool isDir = IsDir(p, be); + switch (propID) + { + case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break; + case kpidIsDir: prop = isDir; break; + // case kpidOffset: prop = (UInt32)GetOffset(p, be); break; + case kpidSize: if (!isDir) prop = GetSize(p, be); break; + case kpidPackSize: + if (!isDir) + { + UInt32 size; + if (GetPackSize(index, size)) + prop = size; + } + break; + case kpidPosixAttrib: prop = (UInt32)GetMode(p, be); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +class CCramfsInStream: public CCachedInStream +{ + HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); +public: + CHandler *Handler; +}; + +HRESULT CCramfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) +{ + return Handler->ReadBlock(blockIndex, dest, blockSize); +} + +HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) +{ + if (_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; +} + +STDMETHODIMP 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 (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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + const Byte *p = _data + item.Offset; + + if (IsDir(p, be)) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + UInt32 curSize = GetSize(p, be); + totalSize += curSize; + UInt32 packSize; + if (GetPackSize(index, packSize)) + totalPackSize += packSize; + + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + + UInt32 offset = GetOffset(p, be); + if (offset < kHeaderSize) + curSize = 0; + + int res = NExtract::NOperationResult::kDataError; + { + CMyComPtr 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 +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + + const CItem &item = _items[index]; + const Byte *p = _data + item.Offset; + + bool be = _h.be; + if (IsDir(p, be)) + return E_FAIL; + + UInt32 size = GetSize(p, be); + UInt32 numBlocks = GetNumBlocks(size); + UInt32 offset = GetOffset(p, be); + if (offset < kHeaderSize) + { + if (offset != 0) + return S_FALSE; + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr 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 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", 0, 0xD3, + kSignature, + 16, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/DeflateProps.cpp b/CPP/7zip/Archive/DeflateProps.cpp index 33c92d747..ca3dc6f56 100644 --- a/CPP/7zip/Archive/DeflateProps.cpp +++ b/CPP/7zip/Archive/DeflateProps.cpp @@ -1,3 +1,3 @@ -// DeflateProps.cpp - -#include "StdAfx.h" +// DeflateProps.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Archive/DeflateProps.h b/CPP/7zip/Archive/DeflateProps.h index 1e9f9077c..9fd2c2e91 100644 --- a/CPP/7zip/Archive/DeflateProps.h +++ b/CPP/7zip/Archive/DeflateProps.h @@ -1,6 +1,6 @@ -// DeflateProps.h - -#ifndef __DEFLATE_PROPS_H -#define __DEFLATE_PROPS_H - -#endif +// DeflateProps.h + +#ifndef __DEFLATE_PROPS_H +#define __DEFLATE_PROPS_H + +#endif diff --git a/CPP/7zip/Archive/DllExports.cpp b/CPP/7zip/Archive/DllExports.cpp index 6b4c24abd..7aee235e5 100644 --- a/CPP/7zip/Archive/DllExports.cpp +++ b/CPP/7zip/Archive/DllExports.cpp @@ -1,94 +1,94 @@ -// DLLExports.cpp - -#include "StdAfx.h" - -#if defined(_7ZIP_LARGE_PAGES) -#include "../../../C/Alloc.h" -#endif - -#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" - -HINSTANCE g_hInstance; - -#define NT_CHECK_FAIL_ACTION return FALSE; - -extern "C" -BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) -{ - if (dwReason == DLL_PROCESS_ATTACH) - { - g_hInstance = hInstance; - NT_CHECK; - } - return TRUE; -} - -DEFINE_GUID(CLSID_CArchiveHandler, - 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(_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 +// DLLExports.cpp + +#include "StdAfx.h" + +#if defined(_7ZIP_LARGE_PAGES) +#include "../../../C/Alloc.h" +#endif + +#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" + +HINSTANCE g_hInstance; + +#define NT_CHECK_FAIL_ACTION return FALSE; + +extern "C" +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + g_hInstance = hInstance; + NT_CHECK; + } + return TRUE; +} + +DEFINE_GUID(CLSID_CArchiveHandler, + 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(_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 diff --git a/CPP/7zip/Archive/DllExports2.cpp b/CPP/7zip/Archive/DllExports2.cpp index c43e72acc..10889e755 100644 --- a/CPP/7zip/Archive/DllExports2.cpp +++ b/CPP/7zip/Archive/DllExports2.cpp @@ -1,122 +1,122 @@ -// 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(_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 diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp index 88238e953..d9fe6016a 100644 --- a/CPP/7zip/Archive/DmgHandler.cpp +++ b/CPP/7zip/Archive/DmgHandler.cpp @@ -1,1857 +1,1857 @@ -// 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 -#define PRF(x) // x - -#define Get16(p) GetBe16(p) -#define Get32(p) GetBe32(p) -#define Get64(p) GetBe64(p) - -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, - 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,77 -}; - -static Byte *Base64ToBin(Byte *dest, const char *src) -{ - UInt32 val = 1; - - for (;;) - { - 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 == 65) // space - continue; - - if (c == 64) // '=' - break; - - if (c == 66 && val == 1) // end of string - return dest; - - return NULL; - } - - if (val < (1 << 12)) - return NULL; - - if (val & (1 << 18)) - { - *dest++ = (Byte)(val >> 10); - *dest++ = (Byte)(val >> 2); - } - else if (k_Base64Table[(Byte)(*src++)] != 64) // '=' - return NULL; - else - *dest++ = (Byte)(val >> 4); - - for (;;) - { - Byte c = k_Base64Table[(Byte)(*src++)]; - if (c == 65) // space - continue; - if (c == 66) // end of string - return dest; - return NULL; - } -} - - -namespace NArchive { -namespace NDmg { - -enum -{ - METHOD_ZERO_0 = 0, - METHOD_COPY = 1, - METHOD_ZERO_2 = 2, // without file CRC calculation - METHOD_ADC = 0x80000004, - METHOD_ZLIB = 0x80000005, - METHOD_BZIP2 = 0x80000006, - METHOD_LZFSE = 0x80000007, - METHOD_COMMENT = 0x7FFFFFFE, // is used to comment "+beg" and "+end" in extra field. - 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 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; - } -}; - - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - CMyComPtr _inStream; - CObjectVector _files; - bool _masterCrcError; - bool _headersError; - - UInt32 _dataStartOffset; - UInt64 _startPos; - UInt64 _phySize; - - AString _name; - - #ifdef DMG_SHOW_RAW - CObjectVector _extras; - #endif - - HRESULT ReadData(IInStream *stream, const CForkPair &pair, CByteBuffer &buf); - bool ParseBlob(const CByteBuffer &data); - HRESULT Open2(IInStream *stream); - HRESULT Extract(IInStream *stream); -public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **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 Types; - CRecordVector 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++) - { - 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" }, - - // 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 = 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 -}; - -STDMETHODIMP 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 = i; - } - break; - } - } - if (n == kNumAppleNames) - { - mainIndex = i; - numUnknown++; - } - } - if (numFS + numUnknown == 1) - prop = (UInt32)mainIndex; - break; - } - case kpidWarning: - if (_masterCrcError) - prop = "Master CRC error"; - - 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 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, 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(stream->Seek(_startPos + pair.Offset, STREAM_SEEK_SET, NULL)); - 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; - RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPos)); - - UInt64 fileSize = 0; - RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); - RINOK(stream->Seek(_startPos, STREAM_SEEK_SET, NULL)); - - 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(stream->Seek(headerPos, STREAM_SEEK_SET, NULL)); - 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 = " len) - xmlPair2.Len = len; - CByteBuffer buf2; - if (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(stream->Seek(_startPos + xmlPair.Offset, STREAM_SEEK_SET, NULL)); - - CXml xml; - { - CObjArray 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; -} - -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) -{ - COM_TRY_BEGIN - { - Close(); - if (Open2(stream) != S_OK) - return S_FALSE; - _inStream = stream; - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _phySize = 0; - _inStream.Release(); - _files.Clear(); - _masterCrcError = false; - _headersError = false; - _name.Empty(); - #ifdef DMG_SHOW_RAW - _extras.Clear(); - #endif - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _files.Size() - #ifdef DMG_SHOW_RAW - + _extras.Size() - #endif - ; - return S_OK; -} - -#define RAW_PREFIX "raw" STRING_PATH_SEPARATOR - -STDMETHODIMP 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++; - 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); - } - } - 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 += '.'; - 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 -} - -class CAdcDecoder: - public ICompressCoder, - public CMyUnknownImp -{ - CLzOutWindow m_OutWindowStream; - CInBuffer m_InStream; - - /* - void ReleaseStreams() - { - m_OutWindowStream.ReleaseStream(); - m_InStream.ReleaseStream(); - } - */ - - class CCoderReleaser - { - CAdcDecoder *m_Coder; - public: - bool NeedFlush; - CCoderReleaser(CAdcDecoder *coder): m_Coder(coder), NeedFlush(true) {} - ~CCoderReleaser() - { - if (NeedFlush) - m_Coder->m_OutWindowStream.Flush(); - // m_Coder->ReleaseStreams(); - } - }; - friend class CCoderReleaser; - -public: - MY_UNKNOWN_IMP - - STDMETHOD(CodeReal)(ISequentialInStream *inStream, - ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, - ICompressProgressInfo *progress); - - STDMETHOD(Code)(ISequentialInStream *inStream, - ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, - ICompressProgressInfo *progress); -}; - -STDMETHODIMP CAdcDecoder::CodeReal(ISequentialInStream *inStream, - ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, - ICompressProgressInfo *progress) -{ - if (!m_OutWindowStream.Create(1 << 18)) - return E_OUTOFMEMORY; - if (!m_InStream.Create(1 << 18)) - return E_OUTOFMEMORY; - - m_OutWindowStream.SetStream(outStream); - m_OutWindowStream.Init(false); - m_InStream.SetStream(inStream); - m_InStream.Init(); - - CCoderReleaser coderReleaser(this); - - const UInt32 kStep = (1 << 20); - UInt64 nextLimit = kStep; - - UInt64 pos = 0; - while (pos < *outSize) - { - if (pos > nextLimit && progress) - { - UInt64 packSize = m_InStream.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&packSize, &pos)); - nextLimit += kStep; - } - Byte b; - if (!m_InStream.ReadByte(b)) - return S_FALSE; - UInt64 rem = *outSize - pos; - if (b & 0x80) - { - unsigned num = (b & 0x7F) + 1; - if (num > rem) - return S_FALSE; - for (unsigned i = 0; i < num; i++) - { - if (!m_InStream.ReadByte(b)) - return S_FALSE; - m_OutWindowStream.PutByte(b); - } - pos += num; - continue; - } - Byte b1; - if (!m_InStream.ReadByte(b1)) - return S_FALSE; - - UInt32 len, distance; - - if (b & 0x40) - { - len = ((UInt32)b & 0x3F) + 4; - Byte b2; - if (!m_InStream.ReadByte(b2)) - return S_FALSE; - distance = ((UInt32)b1 << 8) + b2; - } - else - { - b &= 0x3F; - len = ((UInt32)b >> 2) + 3; - distance = (((UInt32)b & 3) << 8) + b1; - } - - if (distance >= pos || len > rem) - return S_FALSE; - m_OutWindowStream.CopyBlock(distance, len); - pos += len; - } - if (*inSize != m_InStream.GetProcessedSize()) - return S_FALSE; - coderReleaser.NeedFlush = false; - return m_OutWindowStream.Flush(); -} - -STDMETHODIMP CAdcDecoder::Code(ISequentialInStream *inStream, - ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, - ICompressProgressInfo *progress) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress);} - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - - - - - - - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; - - NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder(); - CMyComPtr bzip2Coder = bzip2CoderSpec; - - NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder(); - CMyComPtr zlibCoder = zlibCoderSpec; - - CAdcDecoder *adcCoderSpec = new CAdcDecoder(); - CMyComPtr adcCoder = adcCoderSpec; - - NCompress::NLzfse::CDecoder *lzfseCoderSpec = new NCompress::NLzfse::CDecoder(); - CMyComPtr lzfseCoder = lzfseCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr 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 realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - 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 outCrcStream = outCrcStreamSpec; - outCrcStreamSpec->SetStream(realOutStream); - bool needCrc = false; - outCrcStreamSpec->Init(needCrc); - - CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; - CMyComPtr 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->Seek(_startPos + _dataStartOffset + item.StartPos + block.PackPos, STREAM_SEEK_SET, NULL)); - 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; -}; - -class CInStream: - public IInStream, - public CMyUnknownImp -{ - UInt64 _virtPos; - int _latestChunk; - int _latestBlock; - UInt64 _accessMark; - CObjectVector _chunks; - - NCompress::NBZip2::CDecoder *bzip2CoderSpec; - CMyComPtr bzip2Coder; - - NCompress::NZlib::CDecoder *zlibCoderSpec; - CMyComPtr zlibCoder; - - CAdcDecoder *adcCoderSpec; - CMyComPtr adcCoder; - - NCompress::NLzfse::CDecoder *lzfseCoderSpec; - CMyComPtr lzfseCoder; - - CBufPtrSeqOutStream *outStreamSpec; - CMyComPtr outStream; - - CLimitedSequentialInStream *limitedStreamSpec; - CMyComPtr inStream; - -public: - CMyComPtr 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; - } - - MY_UNKNOWN_IMP1(IInStream) - - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); -}; - - -unsigned FindBlock(const CRecordVector &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; - } -} - -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 (_latestBlock >= 0) - { - const CBlock &block = File->Blocks[_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 = 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(Stream->Seek(_startPos + File->StartPos + block.PackPos, STREAM_SEEK_SET, NULL)); - - 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 = blockIndex; - _latestChunk = chunkIndex; - } - - _chunks[_latestChunk].AccessMark = _accessMark++; - } - - _latestBlock = blockIndex; - } - - const CBlock &block = File->Blocks[_latestBlock]; - UInt64 offset = _virtPos - block.UnpPos; - UInt64 rem = block.UnpSize - offset; - if (size > rem) - size = (UInt32)rem; - - HRESULT res = S_OK; - - if (block.Type == METHOD_COPY) - { - RINOK(Stream->Seek(_startPos + File->StartPos + block.PackPos + offset, STREAM_SEEK_SET, NULL)); - res = Stream->Read(data, size, &size); - } - else if (block.IsZeroMethod()) - memset(data, 0, size); - else if (size != 0) - memcpy(data, _chunks[_latestChunk].Buf + offset, size); - - _virtPos += size; - if (processedSize) - *processedSize = size; - - return res; - 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; -} - -STDMETHODIMP 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 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", 0, 0xE4, - k_Signature, - 0, - NArcInfoFlags::kBackwardOpen | - NArcInfoFlags::kUseGlobalOffset, - NULL) - -}} +// 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 +#define PRF(x) // x + +#define Get16(p) GetBe16(p) +#define Get32(p) GetBe32(p) +#define Get64(p) GetBe64(p) + +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, + 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,77 +}; + +static Byte *Base64ToBin(Byte *dest, const char *src) +{ + UInt32 val = 1; + + for (;;) + { + 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 == 65) // space + continue; + + if (c == 64) // '=' + break; + + if (c == 66 && val == 1) // end of string + return dest; + + return NULL; + } + + if (val < (1 << 12)) + return NULL; + + if (val & (1 << 18)) + { + *dest++ = (Byte)(val >> 10); + *dest++ = (Byte)(val >> 2); + } + else if (k_Base64Table[(Byte)(*src++)] != 64) // '=' + return NULL; + else + *dest++ = (Byte)(val >> 4); + + for (;;) + { + Byte c = k_Base64Table[(Byte)(*src++)]; + if (c == 65) // space + continue; + if (c == 66) // end of string + return dest; + return NULL; + } +} + + +namespace NArchive { +namespace NDmg { + +enum +{ + METHOD_ZERO_0 = 0, + METHOD_COPY = 1, + METHOD_ZERO_2 = 2, // without file CRC calculation + METHOD_ADC = 0x80000004, + METHOD_ZLIB = 0x80000005, + METHOD_BZIP2 = 0x80000006, + METHOD_LZFSE = 0x80000007, + METHOD_COMMENT = 0x7FFFFFFE, // is used to comment "+beg" and "+end" in extra field. + 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 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; + } +}; + + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CMyComPtr _inStream; + CObjectVector _files; + bool _masterCrcError; + bool _headersError; + + UInt32 _dataStartOffset; + UInt64 _startPos; + UInt64 _phySize; + + AString _name; + + #ifdef DMG_SHOW_RAW + CObjectVector _extras; + #endif + + HRESULT ReadData(IInStream *stream, const CForkPair &pair, CByteBuffer &buf); + bool ParseBlob(const CByteBuffer &data); + HRESULT Open2(IInStream *stream); + HRESULT Extract(IInStream *stream); +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **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 Types; + CRecordVector 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++) + { + 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" }, + + // 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 = 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 +}; + +STDMETHODIMP 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 = i; + } + break; + } + } + if (n == kNumAppleNames) + { + mainIndex = i; + numUnknown++; + } + } + if (numFS + numUnknown == 1) + prop = (UInt32)mainIndex; + break; + } + case kpidWarning: + if (_masterCrcError) + prop = "Master CRC error"; + + 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 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, 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(stream->Seek(_startPos + pair.Offset, STREAM_SEEK_SET, NULL)); + 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; + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPos)); + + UInt64 fileSize = 0; + RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); + RINOK(stream->Seek(_startPos, STREAM_SEEK_SET, NULL)); + + 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(stream->Seek(headerPos, STREAM_SEEK_SET, NULL)); + 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 = " len) + xmlPair2.Len = len; + CByteBuffer buf2; + if (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(stream->Seek(_startPos + xmlPair.Offset, STREAM_SEEK_SET, NULL)); + + CXml xml; + { + CObjArray 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; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + { + Close(); + if (Open2(stream) != S_OK) + return S_FALSE; + _inStream = stream; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _phySize = 0; + _inStream.Release(); + _files.Clear(); + _masterCrcError = false; + _headersError = false; + _name.Empty(); + #ifdef DMG_SHOW_RAW + _extras.Clear(); + #endif + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _files.Size() + #ifdef DMG_SHOW_RAW + + _extras.Size() + #endif + ; + return S_OK; +} + +#define RAW_PREFIX "raw" STRING_PATH_SEPARATOR + +STDMETHODIMP 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++; + 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); + } + } + 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 += '.'; + 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 +} + +class CAdcDecoder: + public ICompressCoder, + public CMyUnknownImp +{ + CLzOutWindow m_OutWindowStream; + CInBuffer m_InStream; + + /* + void ReleaseStreams() + { + m_OutWindowStream.ReleaseStream(); + m_InStream.ReleaseStream(); + } + */ + + class CCoderReleaser + { + CAdcDecoder *m_Coder; + public: + bool NeedFlush; + CCoderReleaser(CAdcDecoder *coder): m_Coder(coder), NeedFlush(true) {} + ~CCoderReleaser() + { + if (NeedFlush) + m_Coder->m_OutWindowStream.Flush(); + // m_Coder->ReleaseStreams(); + } + }; + friend class CCoderReleaser; + +public: + MY_UNKNOWN_IMP + + STDMETHOD(CodeReal)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); + + STDMETHOD(Code)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); +}; + +STDMETHODIMP CAdcDecoder::CodeReal(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + if (!m_OutWindowStream.Create(1 << 18)) + return E_OUTOFMEMORY; + if (!m_InStream.Create(1 << 18)) + return E_OUTOFMEMORY; + + m_OutWindowStream.SetStream(outStream); + m_OutWindowStream.Init(false); + m_InStream.SetStream(inStream); + m_InStream.Init(); + + CCoderReleaser coderReleaser(this); + + const UInt32 kStep = (1 << 20); + UInt64 nextLimit = kStep; + + UInt64 pos = 0; + while (pos < *outSize) + { + if (pos > nextLimit && progress) + { + UInt64 packSize = m_InStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &pos)); + nextLimit += kStep; + } + Byte b; + if (!m_InStream.ReadByte(b)) + return S_FALSE; + UInt64 rem = *outSize - pos; + if (b & 0x80) + { + unsigned num = (b & 0x7F) + 1; + if (num > rem) + return S_FALSE; + for (unsigned i = 0; i < num; i++) + { + if (!m_InStream.ReadByte(b)) + return S_FALSE; + m_OutWindowStream.PutByte(b); + } + pos += num; + continue; + } + Byte b1; + if (!m_InStream.ReadByte(b1)) + return S_FALSE; + + UInt32 len, distance; + + if (b & 0x40) + { + len = ((UInt32)b & 0x3F) + 4; + Byte b2; + if (!m_InStream.ReadByte(b2)) + return S_FALSE; + distance = ((UInt32)b1 << 8) + b2; + } + else + { + b &= 0x3F; + len = ((UInt32)b >> 2) + 3; + distance = (((UInt32)b & 3) << 8) + b1; + } + + if (distance >= pos || len > rem) + return S_FALSE; + m_OutWindowStream.CopyBlock(distance, len); + pos += len; + } + if (*inSize != m_InStream.GetProcessedSize()) + return S_FALSE; + coderReleaser.NeedFlush = false; + return m_OutWindowStream.Flush(); +} + +STDMETHODIMP CAdcDecoder::Code(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress);} + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + + + + + + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; + + NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder(); + CMyComPtr bzip2Coder = bzip2CoderSpec; + + NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder(); + CMyComPtr zlibCoder = zlibCoderSpec; + + CAdcDecoder *adcCoderSpec = new CAdcDecoder(); + CMyComPtr adcCoder = adcCoderSpec; + + NCompress::NLzfse::CDecoder *lzfseCoderSpec = new NCompress::NLzfse::CDecoder(); + CMyComPtr lzfseCoder = lzfseCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr 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 realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + 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 outCrcStream = outCrcStreamSpec; + outCrcStreamSpec->SetStream(realOutStream); + bool needCrc = false; + outCrcStreamSpec->Init(needCrc); + + CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; + CMyComPtr 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->Seek(_startPos + _dataStartOffset + item.StartPos + block.PackPos, STREAM_SEEK_SET, NULL)); + 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; +}; + +class CInStream: + public IInStream, + public CMyUnknownImp +{ + UInt64 _virtPos; + int _latestChunk; + int _latestBlock; + UInt64 _accessMark; + CObjectVector _chunks; + + NCompress::NBZip2::CDecoder *bzip2CoderSpec; + CMyComPtr bzip2Coder; + + NCompress::NZlib::CDecoder *zlibCoderSpec; + CMyComPtr zlibCoder; + + CAdcDecoder *adcCoderSpec; + CMyComPtr adcCoder; + + NCompress::NLzfse::CDecoder *lzfseCoderSpec; + CMyComPtr lzfseCoder; + + CBufPtrSeqOutStream *outStreamSpec; + CMyComPtr outStream; + + CLimitedSequentialInStream *limitedStreamSpec; + CMyComPtr inStream; + +public: + CMyComPtr 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; + } + + MY_UNKNOWN_IMP1(IInStream) + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); +}; + + +unsigned FindBlock(const CRecordVector &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; + } +} + +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 (_latestBlock >= 0) + { + const CBlock &block = File->Blocks[_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 = 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(Stream->Seek(_startPos + File->StartPos + block.PackPos, STREAM_SEEK_SET, NULL)); + + 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 = blockIndex; + _latestChunk = chunkIndex; + } + + _chunks[_latestChunk].AccessMark = _accessMark++; + } + + _latestBlock = blockIndex; + } + + const CBlock &block = File->Blocks[_latestBlock]; + UInt64 offset = _virtPos - block.UnpPos; + UInt64 rem = block.UnpSize - offset; + if (size > rem) + size = (UInt32)rem; + + HRESULT res = S_OK; + + if (block.Type == METHOD_COPY) + { + RINOK(Stream->Seek(_startPos + File->StartPos + block.PackPos + offset, STREAM_SEEK_SET, NULL)); + res = Stream->Read(data, size, &size); + } + else if (block.IsZeroMethod()) + memset(data, 0, size); + else if (size != 0) + memcpy(data, _chunks[_latestChunk].Buf + offset, size); + + _virtPos += size; + if (processedSize) + *processedSize = size; + + return res; + 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; +} + +STDMETHODIMP 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 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", 0, 0xE4, + k_Signature, + 0, + NArcInfoFlags::kBackwardOpen | + NArcInfoFlags::kUseGlobalOffset, + NULL) + +}} diff --git a/CPP/7zip/Archive/ElfHandler.cpp b/CPP/7zip/Archive/ElfHandler.cpp index 08771e830..c5ce279ec 100644 --- a/CPP/7zip/Archive/ElfHandler.cpp +++ b/CPP/7zip/Archive/ElfHandler.cpp @@ -1,1106 +1,1106 @@ -// 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 char * const g_SegnmentTypes[] = -{ - "Unused" - , "Loadable segment" - , "Dynamic linking tables" - , "Program interpreter path name" - , "Note section" - , "SHLIB" - , "Program header table" - , "TLS" -}; - -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" -}; - - - - -class CHandler: - public IInArchive, - public IArchiveAllowTail, - public CMyUnknownImp -{ - CRecordVector _segments; - CRecordVector _sections; - CByteBuffer _namesData; - CMyComPtr _inStream; - UInt64 _totalSize; - CHeader _header; - bool _headersError; - bool _allowTail; - - void GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const; - HRESULT Open2(IInStream *stream); -public: - MY_UNKNOWN_IMP2(IInArchive, IArchiveAllowTail) - INTERFACE_IInArchive(;) - STDMETHOD(AllowTail)(Int32 allowTail); - - CHandler(): _allowTail(false) {} -}; - -void CHandler::GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const -{ - if (index >= _sections.Size()) - return; - const CSection §ion = _sections[index]; - 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 - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: prop = _totalSize; break; - case kpidHeadersSize: prop = _header.GetHeadersSize(); break; - case kpidBit64: if (_header.Mode64) prop = _header.Mode64; break; - case kpidBigEndian: if (_header.Be) prop = _header.Be; break; - case kpidShortComment: - - case kpidCpu: - { - AString s; - if (_header.Machine < ARRAY_SIZE(g_Machines)) - { - const char *name = g_Machines[_header.Machine]; - if (name) - s = name; - } - if (s.IsEmpty()) - s = TypePairToString(g_MachinePairs, 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, ARRAY_SIZE(g_ARM_Flags), flags & (((UInt32)1 << 24) - 1)); - s += " ABI:"; - s.Add_UInt32(flags >> 24); - } - else if (_header.Machine == k_Machine_MIPS) - { - 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, 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 -} - -STDMETHODIMP 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: TYPE_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(stream->Seek(_header.ProgOffset, STREAM_SEEK_SET, NULL)); - size_t size = (size_t)_header.SegmentEntrySize * _header.NumSegments; - - CByteArr buf(size); - - RINOK(ReadStream_FALSE(stream, buf, size)); - - 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(stream->Seek(_header.SectOffset, STREAM_SEEK_SET, NULL)); - 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 § = _sections[_header.NamesSectIndex]; - UInt64 size = sect.GetSize(); - if (size != 0 - && size < ((UInt64)1 << 31) - && (Int64)sect.Offset >= 0) - { - _namesData.Alloc((size_t)size); - RINOK(stream->Seek(sect.Offset, STREAM_SEEK_SET, NULL)); - 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(stream->Seek(0, STREAM_SEEK_END, &fileSize)); - if (fileSize > _totalSize) - return S_FALSE; - } - - return S_OK; -} - -STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) -{ - COM_TRY_BEGIN - Close(); - RINOK(Open2(inStream)); - _inStream = inStream; - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _totalSize = 0; - _headersError = false; - - _inStream.Release(); - _segments.Clear(); - _sections.Clear(); - _namesData.Free(); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _segments.Size() + _sections.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - 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++) - { - 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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_inStream); - - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()); - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - UInt32 index = allFilesMode ? i : indices[i]; - 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 outStream; - RINOK(extractCallback->GetStream(index, &outStream, askMode)); - if (!testMode && !outStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(_inStream->Seek(offset, STREAM_SEEK_SET, NULL)); - streamSpec->Init(currentItemSize); - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); - outStream.Release(); - RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::AllowTail(Int32 allowTail) -{ - _allowTail = IntToBool(allowTail); - return S_OK; -} - -static const Byte k_Signature[] = { 0x7F, 'E', 'L', 'F' }; - -REGISTER_ARC_I( - "ELF", "elf", 0, 0xDE, - k_Signature, - 0, - NArcInfoFlags::kPreArc, - NULL) - -}} +// 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 char * const g_SegnmentTypes[] = +{ + "Unused" + , "Loadable segment" + , "Dynamic linking tables" + , "Program interpreter path name" + , "Note section" + , "SHLIB" + , "Program header table" + , "TLS" +}; + +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" +}; + + + + +class CHandler: + public IInArchive, + public IArchiveAllowTail, + public CMyUnknownImp +{ + CRecordVector _segments; + CRecordVector _sections; + CByteBuffer _namesData; + CMyComPtr _inStream; + UInt64 _totalSize; + CHeader _header; + bool _headersError; + bool _allowTail; + + void GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const; + HRESULT Open2(IInStream *stream); +public: + MY_UNKNOWN_IMP2(IInArchive, IArchiveAllowTail) + INTERFACE_IInArchive(;) + STDMETHOD(AllowTail)(Int32 allowTail); + + CHandler(): _allowTail(false) {} +}; + +void CHandler::GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const +{ + if (index >= _sections.Size()) + return; + const CSection §ion = _sections[index]; + 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 + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: prop = _totalSize; break; + case kpidHeadersSize: prop = _header.GetHeadersSize(); break; + case kpidBit64: if (_header.Mode64) prop = _header.Mode64; break; + case kpidBigEndian: if (_header.Be) prop = _header.Be; break; + case kpidShortComment: + + case kpidCpu: + { + AString s; + if (_header.Machine < ARRAY_SIZE(g_Machines)) + { + const char *name = g_Machines[_header.Machine]; + if (name) + s = name; + } + if (s.IsEmpty()) + s = TypePairToString(g_MachinePairs, 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, ARRAY_SIZE(g_ARM_Flags), flags & (((UInt32)1 << 24) - 1)); + s += " ABI:"; + s.Add_UInt32(flags >> 24); + } + else if (_header.Machine == k_Machine_MIPS) + { + 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, 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 +} + +STDMETHODIMP 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: TYPE_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(stream->Seek(_header.ProgOffset, STREAM_SEEK_SET, NULL)); + size_t size = (size_t)_header.SegmentEntrySize * _header.NumSegments; + + CByteArr buf(size); + + RINOK(ReadStream_FALSE(stream, buf, size)); + + 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(stream->Seek(_header.SectOffset, STREAM_SEEK_SET, NULL)); + 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 § = _sections[_header.NamesSectIndex]; + UInt64 size = sect.GetSize(); + if (size != 0 + && size < ((UInt64)1 << 31) + && (Int64)sect.Offset >= 0) + { + _namesData.Alloc((size_t)size); + RINOK(stream->Seek(sect.Offset, STREAM_SEEK_SET, NULL)); + 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(stream->Seek(0, STREAM_SEEK_END, &fileSize)); + if (fileSize > _totalSize) + return S_FALSE; + } + + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(inStream)); + _inStream = inStream; + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _totalSize = 0; + _headersError = false; + + _inStream.Release(); + _segments.Clear(); + _sections.Clear(); + _namesData.Free(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _segments.Size() + _sections.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + 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++) + { + 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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(_inStream); + + for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + 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 outStream; + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + if (!testMode && !outStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(_inStream->Seek(offset, STREAM_SEEK_SET, NULL)); + streamSpec->Init(currentItemSize); + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + outStream.Release(); + RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::AllowTail(Int32 allowTail) +{ + _allowTail = IntToBool(allowTail); + return S_OK; +} + +static const Byte k_Signature[] = { 0x7F, 'E', 'L', 'F' }; + +REGISTER_ARC_I( + "ELF", "elf", 0, 0xDE, + k_Signature, + 0, + NArcInfoFlags::kPreArc, + NULL) + +}} diff --git a/CPP/7zip/Archive/ExtHandler.cpp b/CPP/7zip/Archive/ExtHandler.cpp index 07be3a690..db65fbea8 100644 --- a/CPP/7zip/Archive/ExtHandler.cpp +++ b/CPP/7zip/Archive/ExtHandler.cpp @@ -1,2842 +1,2842 @@ -// ExtHandler.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO - -// #include -// #define PRF2(x) x - -#define PRF2(x) - -#ifdef SHOW_DEBUG_INFO -#include -#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 - -// 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; } - - bool Parse(const Byte *p); -}; - - -static int inline GetLog(UInt32 num) -{ - for (unsigned i = 0; i < 32; i++) - if (((UInt32)1 << i) == num) - return 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) - return false; - if (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 -= (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[] - int SymLinkIndex; // in _symLinks[] - int DirIndex; // in _dirs[] - - UInt16 Mode; - UInt16 Uid; - UInt16 Gid; - // UInt16 Checksum; - - UInt64 FileSize; - CExtTime MTime; - CExtTime ATime; - CExtTime CTime; - // CExtTime InodeChangeTime; - // CExtTime DTime; - - UInt64 NumBlocks; - UInt32 NumLinks; - UInt32 Flags; - - UInt32 NumLinksCalced; - - Byte Block[kNodeBlockFieldSize]; - - CNode(): - ParentNode(-1), - ItemIndex(-1), - SymLinkIndex(-1), - DirIndex(0), - 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; - // InodeChangeTime.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, InodeChangeTime.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) - { - 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, InodeChangeTime.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 - - -class CHandler: - public IInArchive, - public IArchiveGetRawProps, - public IInArchiveGetStream, - public CMyUnknownImp -{ - CObjectVector _items; - CIntVector _refs; - CRecordVector _nodes; - CObjectVector _dirs; // each CUIntVector contains indexes in _items[] only for dir items; - AStringVector _symLinks; - AStringVector _auxItems; - int _auxSysIndex; - int _auxUnknownIndex; - - CMyComPtr _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; - } - - - const 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 &blocks); - HRESULT FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector &blocks); - HRESULT FillExtents(const Byte *p, size_t size, CRecordVector &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; - -public: - CHandler() {} - ~CHandler() {} - - MY_UNKNOWN_IMP3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream) - - INTERFACE_IInArchive(;) - INTERFACE_IArchiveGetRawProps(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); -}; - - - -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 = _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); - unsigned nameLen = p[6]; - 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 = 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) - _isUTF = CheckUTF8(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; - } - - int nodeIndex = _refs[iNode]; - if (nodeIndex < 0) - return S_FALSE; - CNode &node = _nodes[nodeIndex]; - - if (_h.IsThereFileType() && type != 0) - { - if (type >= 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 = iNode; - - if (nodeDir.ParentNode < 0) - nodeDir.ParentNode = 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 = iNodeDir; - else if ((unsigned)node.ParentNode != iNodeDir) - return S_FALSE; - const unsigned itemIndex = _items.Size(); - dir.Add(itemIndex); - node.ItemIndex = itemIndex; - } - - _items.Add(item); - } - - if (parentNode < 0 || !isThereSelfLink) - return S_FALSE; - - return S_OK; -} - - -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]]; - int slash = path.Find('/', pos); - - if (slash < 0) - { - s = path.Ptr(pos); - pos = path.Len(); - } - else - { - s.SetFrom(path.Ptr(pos), slash - pos); - pos = 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 = 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; - } - } - } - - 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->Seek((UInt64)block << _h.BlockBits, STREAM_SEEK_SET, NULL)); - _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; - { - 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.NumBlocks << _h.BlockBits; - - if (_openCallback) - { - RINOK(_openCallback->SetTotal(NULL, &_phySize)); - } - - UInt64 fileSize = 0; - RINOK(inStream->Seek(0, STREAM_SEEK_END, &fileSize)); - - CRecordVector groups; - - { - // ---------- Read groups ---------- - - CByteBuffer gdBuf; - 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); - 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; - 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; - } - - 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(_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) - { - int nodeIndex = _refs[i]; - { - if (nodeIndex < 0) - continue; - const CNode &node = _nodes[nodeIndex]; - if (!node.IsDir()) - continue; - } - RINOK(ExtractNode(nodeIndex, dataBuf)); - if (dataBuf.Size() == 0) - { - // _headersError = true; - return S_FALSE; - } - else - { - RINOK(ParseDir(dataBuf, dataBuf.Size(), i)); - } - RINOK(CheckProgress()); - } - - if (_nodes[_refs[k_INODE_ROOT]].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 (;;) - { - 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] = i; - if (node.ParentNode < 0 || node.ParentNode == k_INODE_ROOT) - break; - if ((unsigned)node.ParentNode == i) - return S_FALSE; - c = node.ParentNode; - } - } - } - - { - // ---------- Fill SymLinks data ---------- - - AString s; - CByteBuffer data; - - unsigned i; - for (i = 0; i < _refs.Size(); i++) - { - 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(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 = _symLinks.Add(s); - RINOK(CheckProgress()); - } - } - - unsigned prev = 0; - unsigned complex = 0; - - for (i = 0; i < _items.Size(); i++) - { - CItem &item = _items[i]; - int sym = _nodes[_refs[item.Node]].SymLinkIndex; - if (sym >= 0 && item.ParentNode >= 0) - { - item.SymLinkItemIndex = FindTargetItem_for_SymLink(item.ParentNode, _symLinks[sym]); - if (_openCallback) - { - complex++; - if (complex - prev >= (1 << 10)) - { - RINOK(CheckProgress2()); - prev = complex; - } - } - } - } - } - - { - // ---------- Add items and aux folders for unreferenced files ---------- - - bool useSys = false; - bool useUnknown = false; - - FOR_VECTOR (i, _refs) - { - 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 < 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 = _auxItems.Add((AString)"[SYS]"); - if (useUnknown) - _auxUnknownIndex = _auxItems.Add((AString)"[UNKNOWN]"); - } - - return S_OK; -} - - -STDMETHODIMP 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; -} - - -STDMETHODIMP 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 = 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; - */ -} - - -STDMETHODIMP 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, - kpidUser, - kpidGroup -}; - - -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) - { - FILETIME ft; - NTime::UnixTimeToFileTime(val, ft); - prop = ft; - } -} - -STDMETHODIMP 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 = _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, -}; -*/ - -STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) -{ - // *numProps = ARRAY_SIZE(kRawProps); - *numProps = 0; - return S_OK; -} - -STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) -{ - // *propID = kRawProps[index]; - *propID = 0; - *name = 0; - return S_OK; -} - -STDMETHODIMP 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) - { - int aux = GetParentAux(item); - if (aux >= 0) - *parent = _items.Size() + aux; - } - else - { - int itemIndex = _nodes[_refs[item.ParentNode]].ItemIndex; - if (itemIndex >= 0) - *parent = itemIndex; - } - - return S_OK; -} - - -STDMETHODIMP 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; - // 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::UnixTime64ToFileTime64(v); - const UInt32 ns = (t.Extra >> 2); - if (ns < 1000000000) - ft64 += 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 = ft; -} - - -STDMETHODIMP 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 < 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.InodeChangeTime, prop); break; - - case kpidUser: prop = (UInt32)node.Uid; break; - case kpidGroup: 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 -} - - -class CClusterInStream2: - public IInStream, - public CMyUnknownImp -{ - UInt64 _virtPos; - UInt64 _physPos; - UInt32 _curRem; -public: - unsigned BlockBits; - UInt64 Size; - CMyComPtr Stream; - CRecordVector Vector; - - HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); } - - HRESULT InitAndSeek() - { - _curRem = 0; - _virtPos = 0; - _physPos = 0; - if (Vector.Size() > 0) - { - _physPos = (Vector[0] << BlockBits); - 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); -}; - - -STDMETHODIMP 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; -} - -STDMETHODIMP 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 = offset; - if (newPosition) - *newPosition = offset; - return S_OK; -} - - -class CExtInStream: - public IInStream, - public CMyUnknownImp -{ - UInt64 _virtPos; - UInt64 _phyPos; -public: - unsigned BlockBits; - UInt64 Size; - CMyComPtr Stream; - CRecordVector Extents; - - CExtInStream() {} - - HRESULT StartSeek() - { - _virtPos = 0; - _phyPos = 0; - return Stream->Seek(_phyPos, STREAM_SEEK_SET, NULL); - } - - MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); -}; - -STDMETHODIMP 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; - } - - UInt64 phyBlock = extent.PhyStart + bo; - UInt64 phy = (phyBlock << BlockBits) + offset; - - if (phy != _phyPos) - { - RINOK(Stream->Seek(phy, STREAM_SEEK_SET, NULL)); - _phyPos = phy; - } - - UInt32 realProcessSize = 0; - - HRESULT res = Stream->Read(data, size, &realProcessSize); - - _phyPos += realProcessSize; - _virtPos += realProcessSize; - if (processedSize) - *processedSize = realProcessSize; - return res; - } -} - - -STDMETHODIMP 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 = offset; - if (newPosition) - *newPosition = offset; - return S_OK; -} - - - -HRESULT CHandler::FillFileBlocks2(UInt32 block, unsigned level, unsigned numBlocks, CRecordVector &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 &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 &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 &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 &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 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 inSeqStream; - RINOK(GetStream_Node(nodeIndex, &inSeqStream)); - if (!inSeqStream) - return S_FALSE; - data.Alloc(size); - _totalRead += size; - return ReadStream_FALSE(inSeqStream, data, size); -} - - -STDMETHODIMP 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() + _auxItems.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 >= _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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - for (i = 0;; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - - if (i == numItems) - break; - - CMyComPtr outStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - - 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 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 -} - - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - *stream = NULL; - if (index >= _items.Size()) - return S_FALSE; - return GetStream_Node(_refs[_items[index].Node], stream); -} - - -API_FUNC_static_IsArc IsArc_Ext(const Byte *p, size_t size) -{ - if (size < kHeaderSize) - return k_IsArc_Res_NEED_MORE; - CHeader h; - if (!h.Parse(p + kHeaderDataOffset)) - return k_IsArc_Res_NO; - return k_IsArc_Res_YES; -} -} - -static const Byte k_Signature[] = { 0x53, 0xEF }; - -REGISTER_ARC_I( - "Ext", "ext ext2 ext3 ext4 img", 0, 0xC7, - k_Signature, - 0x438, - 0, - IsArc_Ext) - -}} +// ExtHandler.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +// #include +// #define PRF2(x) x + +#define PRF2(x) + +#ifdef SHOW_DEBUG_INFO +#include +#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 + +// 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; } + + bool Parse(const Byte *p); +}; + + +static int inline GetLog(UInt32 num) +{ + for (unsigned i = 0; i < 32; i++) + if (((UInt32)1 << i) == num) + return 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) + return false; + if (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 -= (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[] + int SymLinkIndex; // in _symLinks[] + int DirIndex; // in _dirs[] + + UInt16 Mode; + UInt16 Uid; + UInt16 Gid; + // UInt16 Checksum; + + UInt64 FileSize; + CExtTime MTime; + CExtTime ATime; + CExtTime CTime; + // CExtTime InodeChangeTime; + // CExtTime DTime; + + UInt64 NumBlocks; + UInt32 NumLinks; + UInt32 Flags; + + UInt32 NumLinksCalced; + + Byte Block[kNodeBlockFieldSize]; + + CNode(): + ParentNode(-1), + ItemIndex(-1), + SymLinkIndex(-1), + DirIndex(0), + 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; + // InodeChangeTime.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, InodeChangeTime.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) + { + 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, InodeChangeTime.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 + + +class CHandler: + public IInArchive, + public IArchiveGetRawProps, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CObjectVector _items; + CIntVector _refs; + CRecordVector _nodes; + CObjectVector _dirs; // each CUIntVector contains indexes in _items[] only for dir items; + AStringVector _symLinks; + AStringVector _auxItems; + int _auxSysIndex; + int _auxUnknownIndex; + + CMyComPtr _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; + } + + + const 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 &blocks); + HRESULT FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector &blocks); + HRESULT FillExtents(const Byte *p, size_t size, CRecordVector &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; + +public: + CHandler() {} + ~CHandler() {} + + MY_UNKNOWN_IMP3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream) + + INTERFACE_IInArchive(;) + INTERFACE_IArchiveGetRawProps(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + + + +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 = _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); + unsigned nameLen = p[6]; + 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 = 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) + _isUTF = CheckUTF8(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; + } + + int nodeIndex = _refs[iNode]; + if (nodeIndex < 0) + return S_FALSE; + CNode &node = _nodes[nodeIndex]; + + if (_h.IsThereFileType() && type != 0) + { + if (type >= 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 = iNode; + + if (nodeDir.ParentNode < 0) + nodeDir.ParentNode = 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 = iNodeDir; + else if ((unsigned)node.ParentNode != iNodeDir) + return S_FALSE; + const unsigned itemIndex = _items.Size(); + dir.Add(itemIndex); + node.ItemIndex = itemIndex; + } + + _items.Add(item); + } + + if (parentNode < 0 || !isThereSelfLink) + return S_FALSE; + + return S_OK; +} + + +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]]; + int slash = path.Find('/', pos); + + if (slash < 0) + { + s = path.Ptr(pos); + pos = path.Len(); + } + else + { + s.SetFrom(path.Ptr(pos), slash - pos); + pos = 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 = 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; + } + } + } + + 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->Seek((UInt64)block << _h.BlockBits, STREAM_SEEK_SET, NULL)); + _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; + { + 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.NumBlocks << _h.BlockBits; + + if (_openCallback) + { + RINOK(_openCallback->SetTotal(NULL, &_phySize)); + } + + UInt64 fileSize = 0; + RINOK(inStream->Seek(0, STREAM_SEEK_END, &fileSize)); + + CRecordVector groups; + + { + // ---------- Read groups ---------- + + CByteBuffer gdBuf; + 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); + 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; + 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; + } + + 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(_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) + { + int nodeIndex = _refs[i]; + { + if (nodeIndex < 0) + continue; + const CNode &node = _nodes[nodeIndex]; + if (!node.IsDir()) + continue; + } + RINOK(ExtractNode(nodeIndex, dataBuf)); + if (dataBuf.Size() == 0) + { + // _headersError = true; + return S_FALSE; + } + else + { + RINOK(ParseDir(dataBuf, dataBuf.Size(), i)); + } + RINOK(CheckProgress()); + } + + if (_nodes[_refs[k_INODE_ROOT]].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 (;;) + { + 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] = i; + if (node.ParentNode < 0 || node.ParentNode == k_INODE_ROOT) + break; + if ((unsigned)node.ParentNode == i) + return S_FALSE; + c = node.ParentNode; + } + } + } + + { + // ---------- Fill SymLinks data ---------- + + AString s; + CByteBuffer data; + + unsigned i; + for (i = 0; i < _refs.Size(); i++) + { + 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(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 = _symLinks.Add(s); + RINOK(CheckProgress()); + } + } + + unsigned prev = 0; + unsigned complex = 0; + + for (i = 0; i < _items.Size(); i++) + { + CItem &item = _items[i]; + int sym = _nodes[_refs[item.Node]].SymLinkIndex; + if (sym >= 0 && item.ParentNode >= 0) + { + item.SymLinkItemIndex = FindTargetItem_for_SymLink(item.ParentNode, _symLinks[sym]); + if (_openCallback) + { + complex++; + if (complex - prev >= (1 << 10)) + { + RINOK(CheckProgress2()); + prev = complex; + } + } + } + } + } + + { + // ---------- Add items and aux folders for unreferenced files ---------- + + bool useSys = false; + bool useUnknown = false; + + FOR_VECTOR (i, _refs) + { + 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 < 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 = _auxItems.Add((AString)"[SYS]"); + if (useUnknown) + _auxUnknownIndex = _auxItems.Add((AString)"[UNKNOWN]"); + } + + return S_OK; +} + + +STDMETHODIMP 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; +} + + +STDMETHODIMP 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 = 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; + */ +} + + +STDMETHODIMP 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, + kpidUser, + kpidGroup +}; + + +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) + { + FILETIME ft; + NTime::UnixTimeToFileTime(val, ft); + prop = ft; + } +} + +STDMETHODIMP 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 = _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, +}; +*/ + +STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) +{ + // *numProps = ARRAY_SIZE(kRawProps); + *numProps = 0; + return S_OK; +} + +STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) +{ + // *propID = kRawProps[index]; + *propID = 0; + *name = 0; + return S_OK; +} + +STDMETHODIMP 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) + { + int aux = GetParentAux(item); + if (aux >= 0) + *parent = _items.Size() + aux; + } + else + { + int itemIndex = _nodes[_refs[item.ParentNode]].ItemIndex; + if (itemIndex >= 0) + *parent = itemIndex; + } + + return S_OK; +} + + +STDMETHODIMP 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; + // 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::UnixTime64ToFileTime64(v); + const UInt32 ns = (t.Extra >> 2); + if (ns < 1000000000) + ft64 += 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 = ft; +} + + +STDMETHODIMP 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 < 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.InodeChangeTime, prop); break; + + case kpidUser: prop = (UInt32)node.Uid; break; + case kpidGroup: 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 +} + + +class CClusterInStream2: + public IInStream, + public CMyUnknownImp +{ + UInt64 _virtPos; + UInt64 _physPos; + UInt32 _curRem; +public: + unsigned BlockBits; + UInt64 Size; + CMyComPtr Stream; + CRecordVector Vector; + + HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); } + + HRESULT InitAndSeek() + { + _curRem = 0; + _virtPos = 0; + _physPos = 0; + if (Vector.Size() > 0) + { + _physPos = (Vector[0] << BlockBits); + 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); +}; + + +STDMETHODIMP 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; +} + +STDMETHODIMP 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 = offset; + if (newPosition) + *newPosition = offset; + return S_OK; +} + + +class CExtInStream: + public IInStream, + public CMyUnknownImp +{ + UInt64 _virtPos; + UInt64 _phyPos; +public: + unsigned BlockBits; + UInt64 Size; + CMyComPtr Stream; + CRecordVector Extents; + + CExtInStream() {} + + HRESULT StartSeek() + { + _virtPos = 0; + _phyPos = 0; + return Stream->Seek(_phyPos, STREAM_SEEK_SET, NULL); + } + + MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); +}; + +STDMETHODIMP 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; + } + + UInt64 phyBlock = extent.PhyStart + bo; + UInt64 phy = (phyBlock << BlockBits) + offset; + + if (phy != _phyPos) + { + RINOK(Stream->Seek(phy, STREAM_SEEK_SET, NULL)); + _phyPos = phy; + } + + UInt32 realProcessSize = 0; + + HRESULT res = Stream->Read(data, size, &realProcessSize); + + _phyPos += realProcessSize; + _virtPos += realProcessSize; + if (processedSize) + *processedSize = realProcessSize; + return res; + } +} + + +STDMETHODIMP 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 = offset; + if (newPosition) + *newPosition = offset; + return S_OK; +} + + + +HRESULT CHandler::FillFileBlocks2(UInt32 block, unsigned level, unsigned numBlocks, CRecordVector &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 &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 &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 &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 &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 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 inSeqStream; + RINOK(GetStream_Node(nodeIndex, &inSeqStream)); + if (!inSeqStream) + return S_FALSE; + data.Alloc(size); + _totalRead += size; + return ReadStream_FALSE(inSeqStream, data, size); +} + + +STDMETHODIMP 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() + _auxItems.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 >= _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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + for (i = 0;; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + + if (i == numItems) + break; + + CMyComPtr outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + + 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 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 +} + + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + *stream = NULL; + if (index >= _items.Size()) + return S_FALSE; + return GetStream_Node(_refs[_items[index].Node], stream); +} + + +API_FUNC_static_IsArc IsArc_Ext(const Byte *p, size_t size) +{ + if (size < kHeaderSize) + return k_IsArc_Res_NEED_MORE; + CHeader h; + if (!h.Parse(p + kHeaderDataOffset)) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} +} + +static const Byte k_Signature[] = { 0x53, 0xEF }; + +REGISTER_ARC_I( + "Ext", "ext ext2 ext3 ext4 img", 0, 0xC7, + k_Signature, + 0x438, + 0, + IsArc_Ext) + +}} diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp index eccf1aa15..bf6053e0d 100644 --- a/CPP/7zip/Archive/FatHandler.cpp +++ b/CPP/7zip/Archive/FatHandler.cpp @@ -1,1063 +1,1063 @@ -// FatHandler.cpp - -#include "StdAfx.h" - -// #include - -#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_static_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; - } - { - { - UInt32 val32 = Get16(p + 11); - int s = GetLog(val32); - if (s < 9 || s > 12) - return false; - SectorSizeLog = (Byte)s; - } - { - UInt32 val32 = p[13]; - 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. - bool isOkOffset = (codeOffset == 0) - || (codeOffset == (p[0] == 0xEB ? 2 : 3)); - - 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; - UInt32 mask = (1 << (SectorSizeLog - 5)) - 1; - if ((numRootDirEntries & mask) != 0) - return false; - NumRootDirSectors = (numRootDirEntries + mask) >> (SectorSizeLog - 5); - } - - NumSectors = Get16(p + 19); - if (NumSectors == 0) - NumSectors = Get32(p + 32); - else if (IsFat32()) - return false; - - MediaType = p[21]; - NumFatSectors = Get16(p + 22); - SectorsPerTrack = Get16(p + 24); - NumHeads = Get16(p + 26); - NumHiddenSectors = Get32(p + 28); - - // memcpy(OemName, p + 3, 5); - - 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; - UInt32 numDataSectors = NumSectors - DataSector; - UInt32 numClusters = numDataSectors >> SectorsPerClusterLog; - - BadCluster = 0x0FFFFFF7; - if (numClusters < 0xFFF5) - { - if (NumFatBits == 32) - return false; - NumFatBits = (Byte)(numClusters < 0xFF5 ? 12 : 16); - BadCluster &= ((1 << NumFatBits) - 1); - } - else if (NumFatBits != 32) - return false; - - FatSize = numClusters + 2; - if (FatSize > BadCluster || CalcFatSizeInSectors() > NumFatSectors) - return false; - return true; -} - -struct CItem -{ - UString UName; - char DosName[11]; - Byte CTime2; - UInt32 CTime; - UInt32 MTime; - UInt16 ADate; - Byte Attrib; - Byte Flags; - UInt32 Size; - UInt32 Cluster; - Int32 Parent; - - // NT uses Flags to store Low Case status - bool NameIsLow() const { return (Flags & 0x8) != 0; } - bool ExtIsLow() const { return (Flags & 0x10) != 0; } - bool IsDir() const { return (Attrib & 0x10) != 0; } - UString GetShortName() const; - UString GetName() const; - UString GetVolName() const; -}; - -static 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 Items; - UInt32 *Fat; - CMyComPtr InStream; - IArchiveOpenCallback *OpenCallback; - - UInt32 NumFreeClusters; - bool VolItemDefined; - CItem VolItem; - UInt32 NumDirClusters; - CByteBuffer ByteBuf; - UInt64 NumCurUsedBytes; - - UInt64 PhySize; - - CDatabase(): Fat(0) {} - ~CDatabase() { ClearAndClose(); } - - void Clear(); - void ClearAndClose(); - HRESULT OpenProgressFat(bool changeTotal = true); - HRESULT OpenProgress(); - - UString GetItemPath(Int32 index) const; - HRESULT Open(); - HRESULT ReadDir(Int32 parent, UInt32 cluster, 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->Seek((UInt64)sector << Header.SectorSizeLog, STREAM_SEEK_SET, NULL); -} - -void CDatabase::Clear() -{ - PhySize = 0; - VolItemDefined = false; - NumDirClusters = 0; - NumCurUsedBytes = 0; - - Items.Clear(); - delete []Fat; - Fat = 0; -} - -void CDatabase::ClearAndClose() -{ - Clear(); - InStream.Release(); -} - -HRESULT CDatabase::OpenProgressFat(bool changeTotal) -{ - if (!OpenCallback) - return S_OK; - if (changeTotal) - { - UInt64 numTotalBytes = (Header.CalcFatSizeInSectors() << Header.SectorSizeLog) + - ((UInt64)(Header.FatSize - NumFreeClusters) << Header.ClusterSizeLog); - RINOK(OpenCallback->SetTotal(NULL, &numTotalBytes)); - } - return OpenCallback->SetCompleted(NULL, &NumCurUsedBytes); -} - -HRESULT CDatabase::OpenProgress() -{ - if (!OpenCallback) - return S_OK; - UInt64 numItems = Items.Size(); - return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes); -} - -UString CDatabase::GetItemPath(Int32 index) const -{ - const CItem *item = &Items[index]; - UString name = item->GetName(); - for (;;) - { - index = item->Parent; - if (index < 0) - return name; - item = &Items[index]; - name.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(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->Seek(0, STREAM_SEEK_END, &fileSize)); - - /* we comment that check to support truncated images */ - /* - if (fileSize < Header.GetPhySize()) - return S_FALSE; - */ - - if (Header.IsFat32()) - { - SeekToSector(Header.FsInfoSector); - RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)); - if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA) - return S_FALSE; - if (Get32(buf) == 0x41615252 && Get32(buf + 484) == 0x61417272) - { - NumFreeClusters = Get32(buf + 488); - numFreeClustersDefined = (NumFreeClusters <= Header.FatSize); - } - } - } - - // numFreeClustersDefined = false; // to recalculate NumFreeClusters - if (!numFreeClustersDefined) - NumFreeClusters = 0; - - CByteBuffer byteBuf; - Fat = new UInt32[Header.FatSize]; - - RINOK(OpenProgressFat()); - RINOK(SeekToSector(Header.GetFatSector())); - if (Header.NumFatBits == 32) - { - const UInt32 kBufSize = (1 << 15); - byteBuf.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 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; -} - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp, - CDatabase -{ -public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); -}; - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - *stream = 0; - const CItem &item = Items[index]; - CClusterInStream *streamSpec = new CClusterInStream; - CMyComPtr 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::DosTimeToFileTime(dosTime, localFileTime)) - if (LocalFileTimeToFileTime(&localFileTime, &utc)) - { - UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime; - t64 += ms10 * 100000; - utc.dwLowDateTime = (DWORD)t64; - utc.dwHighDateTime = (DWORD)(t64 >> 32); - prop = utc; - } -} - -/* -static void StringToProp(const Byte *src, 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) -*/ - -STDMETHODIMP 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) FatTimeToProp(VolItem.MTime, 0, prop); 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 -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem &item = Items[index]; - switch (propID) - { - case kpidPath: prop = GetItemPath(index); break; - case kpidShortName: prop = item.GetShortName(); break; - case kpidIsDir: prop = item.IsDir(); break; - case kpidMTime: FatTimeToProp(item.MTime, 0, prop); break; - case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break; - case kpidATime: FatTimeToProp(((UInt32)item.ADate << 16), 0, prop); break; - case kpidAttrib: prop = (UInt32)item.Attrib; break; - case kpidSize: if (!item.IsDir()) prop = item.Size; break; - case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) -{ - COM_TRY_BEGIN - { - OpenCallback = callback; - InStream = stream; - HRESULT res; - try - { - res = CDatabase::Open(); - if (res == S_OK) - return S_OK; - } - catch(...) - { - Close(); - throw; - } - Close(); - return res; - } - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - ClearAndClose(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CDummyOutStream *outStreamSpec = new CDummyOutStream; - CMyComPtr outStream(outStreamSpec); - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - CMyComPtr realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; - const CItem &item = Items[index]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - - if (item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - - totalPackSize += Header.GetFilePackSize(item.Size); - totalSize += item.Size; - - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - - outStreamSpec->SetStream(realOutStream); - realOutStream.Release(); - outStreamSpec->Init(); - - int res = NExtract::NOperationResult::kDataError; - CMyComPtr inStream; - HRESULT hres = GetStream(index, &inStream); - if (hres != S_FALSE) - { - RINOK(hres); - if (inStream) - { - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); - if (copyCoderSpec->TotalSize == item.Size) - res = NExtract::NOperationResult::kOK; - } - } - outStreamSpec->ReleaseStream(); - RINOK(extractCallback->SetOperationResult(res)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = Items.Size(); - return S_OK; -} - -static const Byte k_Signature[] = { 0x55, 0xAA }; - -REGISTER_ARC_I( - "FAT", "fat img", 0, 0xDA, - k_Signature, - 0x1FE, - 0, - IsArc_Fat) - -}} +// FatHandler.cpp + +#include "StdAfx.h" + +// #include + +#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_static_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; + } + { + { + UInt32 val32 = Get16(p + 11); + int s = GetLog(val32); + if (s < 9 || s > 12) + return false; + SectorSizeLog = (Byte)s; + } + { + UInt32 val32 = p[13]; + 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. + bool isOkOffset = (codeOffset == 0) + || (codeOffset == (p[0] == 0xEB ? 2 : 3)); + + 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; + UInt32 mask = (1 << (SectorSizeLog - 5)) - 1; + if ((numRootDirEntries & mask) != 0) + return false; + NumRootDirSectors = (numRootDirEntries + mask) >> (SectorSizeLog - 5); + } + + NumSectors = Get16(p + 19); + if (NumSectors == 0) + NumSectors = Get32(p + 32); + else if (IsFat32()) + return false; + + MediaType = p[21]; + NumFatSectors = Get16(p + 22); + SectorsPerTrack = Get16(p + 24); + NumHeads = Get16(p + 26); + NumHiddenSectors = Get32(p + 28); + + // memcpy(OemName, p + 3, 5); + + 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; + UInt32 numDataSectors = NumSectors - DataSector; + UInt32 numClusters = numDataSectors >> SectorsPerClusterLog; + + BadCluster = 0x0FFFFFF7; + if (numClusters < 0xFFF5) + { + if (NumFatBits == 32) + return false; + NumFatBits = (Byte)(numClusters < 0xFF5 ? 12 : 16); + BadCluster &= ((1 << NumFatBits) - 1); + } + else if (NumFatBits != 32) + return false; + + FatSize = numClusters + 2; + if (FatSize > BadCluster || CalcFatSizeInSectors() > NumFatSectors) + return false; + return true; +} + +struct CItem +{ + UString UName; + char DosName[11]; + Byte CTime2; + UInt32 CTime; + UInt32 MTime; + UInt16 ADate; + Byte Attrib; + Byte Flags; + UInt32 Size; + UInt32 Cluster; + Int32 Parent; + + // NT uses Flags to store Low Case status + bool NameIsLow() const { return (Flags & 0x8) != 0; } + bool ExtIsLow() const { return (Flags & 0x10) != 0; } + bool IsDir() const { return (Attrib & 0x10) != 0; } + UString GetShortName() const; + UString GetName() const; + UString GetVolName() const; +}; + +static 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 Items; + UInt32 *Fat; + CMyComPtr InStream; + IArchiveOpenCallback *OpenCallback; + + UInt32 NumFreeClusters; + bool VolItemDefined; + CItem VolItem; + UInt32 NumDirClusters; + CByteBuffer ByteBuf; + UInt64 NumCurUsedBytes; + + UInt64 PhySize; + + CDatabase(): Fat(0) {} + ~CDatabase() { ClearAndClose(); } + + void Clear(); + void ClearAndClose(); + HRESULT OpenProgressFat(bool changeTotal = true); + HRESULT OpenProgress(); + + UString GetItemPath(Int32 index) const; + HRESULT Open(); + HRESULT ReadDir(Int32 parent, UInt32 cluster, 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->Seek((UInt64)sector << Header.SectorSizeLog, STREAM_SEEK_SET, NULL); +} + +void CDatabase::Clear() +{ + PhySize = 0; + VolItemDefined = false; + NumDirClusters = 0; + NumCurUsedBytes = 0; + + Items.Clear(); + delete []Fat; + Fat = 0; +} + +void CDatabase::ClearAndClose() +{ + Clear(); + InStream.Release(); +} + +HRESULT CDatabase::OpenProgressFat(bool changeTotal) +{ + if (!OpenCallback) + return S_OK; + if (changeTotal) + { + UInt64 numTotalBytes = (Header.CalcFatSizeInSectors() << Header.SectorSizeLog) + + ((UInt64)(Header.FatSize - NumFreeClusters) << Header.ClusterSizeLog); + RINOK(OpenCallback->SetTotal(NULL, &numTotalBytes)); + } + return OpenCallback->SetCompleted(NULL, &NumCurUsedBytes); +} + +HRESULT CDatabase::OpenProgress() +{ + if (!OpenCallback) + return S_OK; + UInt64 numItems = Items.Size(); + return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes); +} + +UString CDatabase::GetItemPath(Int32 index) const +{ + const CItem *item = &Items[index]; + UString name = item->GetName(); + for (;;) + { + index = item->Parent; + if (index < 0) + return name; + item = &Items[index]; + name.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(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->Seek(0, STREAM_SEEK_END, &fileSize)); + + /* we comment that check to support truncated images */ + /* + if (fileSize < Header.GetPhySize()) + return S_FALSE; + */ + + if (Header.IsFat32()) + { + SeekToSector(Header.FsInfoSector); + RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)); + if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA) + return S_FALSE; + if (Get32(buf) == 0x41615252 && Get32(buf + 484) == 0x61417272) + { + NumFreeClusters = Get32(buf + 488); + numFreeClustersDefined = (NumFreeClusters <= Header.FatSize); + } + } + } + + // numFreeClustersDefined = false; // to recalculate NumFreeClusters + if (!numFreeClustersDefined) + NumFreeClusters = 0; + + CByteBuffer byteBuf; + Fat = new UInt32[Header.FatSize]; + + RINOK(OpenProgressFat()); + RINOK(SeekToSector(Header.GetFatSector())); + if (Header.NumFatBits == 32) + { + const UInt32 kBufSize = (1 << 15); + byteBuf.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 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; +} + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp, + CDatabase +{ +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = 0; + const CItem &item = Items[index]; + CClusterInStream *streamSpec = new CClusterInStream; + CMyComPtr 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::DosTimeToFileTime(dosTime, localFileTime)) + if (LocalFileTimeToFileTime(&localFileTime, &utc)) + { + UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime; + t64 += ms10 * 100000; + utc.dwLowDateTime = (DWORD)t64; + utc.dwHighDateTime = (DWORD)(t64 >> 32); + prop = utc; + } +} + +/* +static void StringToProp(const Byte *src, 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) +*/ + +STDMETHODIMP 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) FatTimeToProp(VolItem.MTime, 0, prop); 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 +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem &item = Items[index]; + switch (propID) + { + case kpidPath: prop = GetItemPath(index); break; + case kpidShortName: prop = item.GetShortName(); break; + case kpidIsDir: prop = item.IsDir(); break; + case kpidMTime: FatTimeToProp(item.MTime, 0, prop); break; + case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break; + case kpidATime: FatTimeToProp(((UInt32)item.ADate << 16), 0, prop); break; + case kpidAttrib: prop = (UInt32)item.Attrib; break; + case kpidSize: if (!item.IsDir()) prop = item.Size; break; + case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + { + OpenCallback = callback; + InStream = stream; + HRESULT res; + try + { + res = CDatabase::Open(); + if (res == S_OK) + return S_OK; + } + catch(...) + { + Close(); + throw; + } + Close(); + return res; + } + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + ClearAndClose(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr outStream(outStreamSpec); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + const CItem &item = Items[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + if (item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + + totalPackSize += Header.GetFilePackSize(item.Size); + totalSize += item.Size; + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + + outStreamSpec->SetStream(realOutStream); + realOutStream.Release(); + outStreamSpec->Init(); + + int res = NExtract::NOperationResult::kDataError; + CMyComPtr inStream; + HRESULT hres = GetStream(index, &inStream); + if (hres != S_FALSE) + { + RINOK(hres); + if (inStream) + { + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize == item.Size) + res = NExtract::NOperationResult::kOK; + } + } + outStreamSpec->ReleaseStream(); + RINOK(extractCallback->SetOperationResult(res)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = Items.Size(); + return S_OK; +} + +static const Byte k_Signature[] = { 0x55, 0xAA }; + +REGISTER_ARC_I( + "FAT", "fat img", 0, 0xDA, + k_Signature, + 0x1FE, + 0, + IsArc_Fat) + +}} diff --git a/CPP/7zip/Archive/FlvHandler.cpp b/CPP/7zip/Archive/FlvHandler.cpp index e6bee3a1e..1f52f60be 100644 --- a/CPP/7zip/Archive/FlvHandler.cpp +++ b/CPP/7zip/Archive/FlvHandler.cpp @@ -1,526 +1,526 @@ -// FlvHandler.cpp - -#include "StdAfx.h" - -// #include - -#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 RefBuf; - - bool IsAudio() const { return Type == kType_Audio; } -}; - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - CMyComPtr _stream; - CObjectVector _items2; - CByteBuffer _metadata; - bool _isRaw; - UInt64 _phySize; - - HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); - // AString GetComment(); -public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); -}; - -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" -}; - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - NWindows::NCOM::CPropVariant prop; - const CItem2 &item = _items2[index]; - switch (propID) - { - case kpidExtension: - prop = _isRaw ? - (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) : - (item.IsAudio() ? "audio.flv" : "video.flv"); - break; - case kpidSize: - case kpidPackSize: - prop = (UInt64)item.Size; - break; - case kpidNumBlocks: prop = (UInt32)item.NumChunks; break; - case kpidComment: - { - char sz[64]; - 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; -} -*/ - -STDMETHODIMP 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 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] = _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; -} - -STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback) -{ - COM_TRY_BEGIN - Close(); - HRESULT res; - try - { - res = Open2(inStream, callback); - if (res == S_OK) - _stream = inStream; - } - catch(...) { res = S_FALSE; } - if (res != S_OK) - { - Close(); - return S_FALSE; - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _phySize = 0; - _stream.Release(); - _items2.Clear(); - // _metadata.SetCapacity(0); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items2.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(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 progress = lps; - lps->Init(extractCallback, false); - - for (i = 0; i < numItems; i++) - { - lps->InSize = lps->OutSize = totalSize; - RINOK(lps->SetCur()); - CMyComPtr outStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - UInt32 index = allFilesMode ? i : indices[i]; - const CItem2 &item = _items2[index]; - RINOK(extractCallback->GetStream(index, &outStream, askMode)); - totalSize += item.Size; - if (!testMode && !outStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - if (outStream) - { - RINOK(WriteStream(outStream, item.BufSpec->Buf, item.BufSpec->Buf.Size())); - } - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - *stream = 0; - CBufInStream *streamSpec = new CBufInStream; - CMyComPtr 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", 0, 0xD6, - k_Signature, - 0, - 0, - NULL) - -}} +// FlvHandler.cpp + +#include "StdAfx.h" + +// #include + +#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 RefBuf; + + bool IsAudio() const { return Type == kType_Audio; } +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CMyComPtr _stream; + CObjectVector _items2; + CByteBuffer _metadata; + bool _isRaw; + UInt64 _phySize; + + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); + // AString GetComment(); +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +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" +}; + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + NWindows::NCOM::CPropVariant prop; + const CItem2 &item = _items2[index]; + switch (propID) + { + case kpidExtension: + prop = _isRaw ? + (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) : + (item.IsAudio() ? "audio.flv" : "video.flv"); + break; + case kpidSize: + case kpidPackSize: + prop = (UInt64)item.Size; + break; + case kpidNumBlocks: prop = (UInt32)item.NumChunks; break; + case kpidComment: + { + char sz[64]; + 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; +} +*/ + +STDMETHODIMP 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 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] = _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; +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + Close(); + HRESULT res; + try + { + res = Open2(inStream, callback); + if (res == S_OK) + _stream = inStream; + } + catch(...) { res = S_FALSE; } + if (res != S_OK) + { + Close(); + return S_FALSE; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _phySize = 0; + _stream.Release(); + _items2.Clear(); + // _metadata.SetCapacity(0); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items2.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(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 progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++) + { + lps->InSize = lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + const CItem2 &item = _items2[index]; + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + totalSize += item.Size; + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + if (outStream) + { + RINOK(WriteStream(outStream, item.BufSpec->Buf, item.BufSpec->Buf.Size())); + } + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = 0; + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr 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", 0, 0xD6, + k_Signature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/GptHandler.cpp b/CPP/7zip/Archive/GptHandler.cpp index 881e0d904..a86ad37cb 100644 --- a/CPP/7zip/Archive/GptHandler.cpp +++ b/CPP/7zip/Archive/GptHandler.cpp @@ -1,403 +1,403 @@ -// 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 NGpt { - -#define SIGNATURE { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 } - -static const unsigned k_SignatureSize = 12; -static const Byte k_Signature[k_SignatureSize] = SIGNATURE; - -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; - 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); - } -}; - - -struct CPartType -{ - UInt32 Id; - const char *Ext; - const char *Type; -}; - -static const CPartType kPartTypes[] = -{ - // { 0x0, 0, "Unused" }, - - { 0x21686148, 0, "BIOS Boot" }, - - { 0xC12A7328, 0, "EFI System" }, - { 0x024DEE41, 0, "MBR" }, - - { 0xE3C9E316, 0, "Windows MSR" }, - { 0xEBD0A0A2, 0, "Windows BDP" }, - { 0x5808C8AA, 0, "Windows LDM Metadata" }, - { 0xAF9B60A0, 0, "Windows LDM Data" }, - { 0xDE94BBA4, 0, "Windows Recovery" }, - // { 0x37AFFC90, 0, "IBM GPFS" }, - // { 0xE75CAF8F, 0, "Windows Storage Spaces" }, - - { 0x0FC63DAF, 0, "Linux Data" }, - { 0x0657FD6D, 0, "Linux Swap" }, - - { 0x83BD6B9D, 0, "FreeBSD Boot" }, - { 0x516E7CB4, 0, "FreeBSD Data" }, - { 0x516E7CB5, 0, "FreeBSD Swap" }, - { 0x516E7CB6, "ufs", "FreeBSD UFS" }, - { 0x516E7CB8, 0, "FreeBSD Vinum" }, - { 0x516E7CB8, "zfs", "FreeBSD ZFS" }, - - { 0x48465300, "hfsx", "HFS+" }, -}; - -static int FindPartType(const Byte *guid) -{ - UInt32 val = Get32(guid); - for (unsigned i = 0; i < ARRAY_SIZE(kPartTypes); i++) - if (kPartTypes[i].Id == val) - return i; - return -1; -} - - -static void RawLeGuidToString_Upper(const Byte *g, char *s) -{ - RawLeGuidToString(g, s); - // MyStringUpper_Ascii(s); -} - - -class CHandler: public CHandlerCont -{ - CRecordVector _items; - UInt64 _totalSize; - Byte Guid[16]; - - CByteBuffer _buffer; - - HRESULT Open2(IInStream *stream); - - virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const - { - const CPartition &item = _items[index]; - pos = item.GetPos(); - size = item.GetSize(); - return NExtract::NOperationResult::kOK; - } - -public: - INTERFACE_IInArchive_Cont(;) -}; - - -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); - UInt64 curLba = Get64(buf + 0x18); - if (curLba != 1) - return S_FALSE; - UInt64 backupLba = Get64(buf + 0x20); - // UInt64 firstUsableLba = Get64(buf + 0x28); - // UInt64 lastUsableLba = Get64(buf + 0x30); - memcpy(Guid, buf + 0x38, 16); - UInt64 tableLba = Get64(buf + 0x48); - if (tableLba < 2) - return S_FALSE; - UInt32 numEntries = Get32(buf + 0x50); - UInt32 entrySize = Get32(buf + 0x54); // = 128 usually - UInt32 entriesCrc = Get32(buf + 0x58); - - if (entrySize < 128 - || entrySize > (1 << 12) - || numEntries > (1 << 16) - || tableLba < 2 - || tableLba >= ((UInt64)1 << (64 - 10))) - return S_FALSE; - - UInt32 tableSize = entrySize * numEntries; - UInt32 tableSizeAligned = (tableSize + kSectorSize - 1) & ~(kSectorSize - 1); - _buffer.Alloc(tableSizeAligned); - UInt64 tableOffset = tableLba * kSectorSize; - RINOK(stream->Seek(tableOffset, STREAM_SEEK_SET, NULL)); - 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(stream->Seek(0, STREAM_SEEK_END, &fileEnd)); - - if (_totalSize < fileEnd) - { - const UInt64 rem = fileEnd - _totalSize; - const UInt64 kRemMax = 1 << 22; - if (rem <= kRemMax) - { - RINOK(stream->Seek(_totalSize, STREAM_SEEK_SET, NULL)); - bool areThereNonZeros = false; - UInt64 numZeros = 0; - if (ReadZeroTail(stream, areThereNonZeros, numZeros, kRemMax) == S_OK) - if (!areThereNonZeros) - _totalSize += numZeros; - } - } - } - - return S_OK; -} - -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) -{ - COM_TRY_BEGIN - Close(); - RINOK(Open2(stream)); - _stream = stream; - return S_OK; - COM_TRY_END -} - -STDMETHODIMP 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 - -STDMETHODIMP 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 -} - -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 CPartition &item = _items[index]; - - switch (propID) - { - case kpidPath: - { - UString s; - for (unsigned i = 0; i < kNameLen; i++) - { - wchar_t c = (wchar_t)Get16(item.Name + i * 2); - if (c == 0) - break; - s += c; - } - if (s.IsEmpty()) - s.Add_UInt32(index); - { - s += '.'; - const char *ext = NULL; - int typeIndex = FindPartType(item.Type); - if (typeIndex >= 0) - ext = kPartTypes[(unsigned)typeIndex].Ext; - if (!ext) - ext = "img"; - s += ext; - } - 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; - 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) - -}} +// 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 NGpt { + +#define SIGNATURE { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 } + +static const unsigned k_SignatureSize = 12; +static const Byte k_Signature[k_SignatureSize] = SIGNATURE; + +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; + 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); + } +}; + + +struct CPartType +{ + UInt32 Id; + const char *Ext; + const char *Type; +}; + +static const CPartType kPartTypes[] = +{ + // { 0x0, 0, "Unused" }, + + { 0x21686148, 0, "BIOS Boot" }, + + { 0xC12A7328, 0, "EFI System" }, + { 0x024DEE41, 0, "MBR" }, + + { 0xE3C9E316, 0, "Windows MSR" }, + { 0xEBD0A0A2, 0, "Windows BDP" }, + { 0x5808C8AA, 0, "Windows LDM Metadata" }, + { 0xAF9B60A0, 0, "Windows LDM Data" }, + { 0xDE94BBA4, 0, "Windows Recovery" }, + // { 0x37AFFC90, 0, "IBM GPFS" }, + // { 0xE75CAF8F, 0, "Windows Storage Spaces" }, + + { 0x0FC63DAF, 0, "Linux Data" }, + { 0x0657FD6D, 0, "Linux Swap" }, + + { 0x83BD6B9D, 0, "FreeBSD Boot" }, + { 0x516E7CB4, 0, "FreeBSD Data" }, + { 0x516E7CB5, 0, "FreeBSD Swap" }, + { 0x516E7CB6, "ufs", "FreeBSD UFS" }, + { 0x516E7CB8, 0, "FreeBSD Vinum" }, + { 0x516E7CB8, "zfs", "FreeBSD ZFS" }, + + { 0x48465300, "hfsx", "HFS+" }, +}; + +static int FindPartType(const Byte *guid) +{ + UInt32 val = Get32(guid); + for (unsigned i = 0; i < ARRAY_SIZE(kPartTypes); i++) + if (kPartTypes[i].Id == val) + return i; + return -1; +} + + +static void RawLeGuidToString_Upper(const Byte *g, char *s) +{ + RawLeGuidToString(g, s); + // MyStringUpper_Ascii(s); +} + + +class CHandler: public CHandlerCont +{ + CRecordVector _items; + UInt64 _totalSize; + Byte Guid[16]; + + CByteBuffer _buffer; + + HRESULT Open2(IInStream *stream); + + virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const + { + const CPartition &item = _items[index]; + pos = item.GetPos(); + size = item.GetSize(); + return NExtract::NOperationResult::kOK; + } + +public: + INTERFACE_IInArchive_Cont(;) +}; + + +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); + UInt64 curLba = Get64(buf + 0x18); + if (curLba != 1) + return S_FALSE; + UInt64 backupLba = Get64(buf + 0x20); + // UInt64 firstUsableLba = Get64(buf + 0x28); + // UInt64 lastUsableLba = Get64(buf + 0x30); + memcpy(Guid, buf + 0x38, 16); + UInt64 tableLba = Get64(buf + 0x48); + if (tableLba < 2) + return S_FALSE; + UInt32 numEntries = Get32(buf + 0x50); + UInt32 entrySize = Get32(buf + 0x54); // = 128 usually + UInt32 entriesCrc = Get32(buf + 0x58); + + if (entrySize < 128 + || entrySize > (1 << 12) + || numEntries > (1 << 16) + || tableLba < 2 + || tableLba >= ((UInt64)1 << (64 - 10))) + return S_FALSE; + + UInt32 tableSize = entrySize * numEntries; + UInt32 tableSizeAligned = (tableSize + kSectorSize - 1) & ~(kSectorSize - 1); + _buffer.Alloc(tableSizeAligned); + UInt64 tableOffset = tableLba * kSectorSize; + RINOK(stream->Seek(tableOffset, STREAM_SEEK_SET, NULL)); + 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(stream->Seek(0, STREAM_SEEK_END, &fileEnd)); + + if (_totalSize < fileEnd) + { + const UInt64 rem = fileEnd - _totalSize; + const UInt64 kRemMax = 1 << 22; + if (rem <= kRemMax) + { + RINOK(stream->Seek(_totalSize, STREAM_SEEK_SET, NULL)); + bool areThereNonZeros = false; + UInt64 numZeros = 0; + if (ReadZeroTail(stream, areThereNonZeros, numZeros, kRemMax) == S_OK) + if (!areThereNonZeros) + _totalSize += numZeros; + } + } + } + + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(stream)); + _stream = stream; + return S_OK; + COM_TRY_END +} + +STDMETHODIMP 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 + +STDMETHODIMP 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 +} + +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 CPartition &item = _items[index]; + + switch (propID) + { + case kpidPath: + { + UString s; + for (unsigned i = 0; i < kNameLen; i++) + { + wchar_t c = (wchar_t)Get16(item.Name + i * 2); + if (c == 0) + break; + s += c; + } + if (s.IsEmpty()) + s.Add_UInt32(index); + { + s += '.'; + const char *ext = NULL; + int typeIndex = FindPartType(item.Type); + if (typeIndex >= 0) + ext = kPartTypes[(unsigned)typeIndex].Ext; + if (!ext) + ext = "img"; + s += ext; + } + 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; + 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 index 3310f4d7b..130f8b35a 100644 --- a/CPP/7zip/Archive/GzHandler.cpp +++ b/CPP/7zip/Archive/GzHandler.cpp @@ -1,1043 +1,1043 @@ -// GzHandler.cpp - -#include "StdAfx.h" - -// #include - -#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; - if (GetUi16(p) != (UInt16)~GetUi16(p + 2)) - 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 unsigned kNameMaxLen = 1 << 12; -static 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); -} - -class CHandler: - public IInArchive, - public IArchiveOpenSeq, - public IOutArchive, - public ISetProperties, - public CMyUnknownImp -{ - 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 _stream; - CMyComPtr _decoder; - NDecoder::CCOMCoder *_decoderSpec; - - CSingleMethodProps _props; - -public: - MY_UNKNOWN_IMP4( - IInArchive, - IArchiveOpenSeq, - IOutArchive, - ISetProperties) - INTERFACE_IInArchive(;) - INTERFACE_IOutArchive(;) - STDMETHOD(OpenSeq)(ISequentialInStream *stream); - STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); - - CHandler() - { - _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 - -STDMETHODIMP 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 -} - - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = 1; - return S_OK; -} - -STDMETHODIMP 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: - if (_item.Time != 0) - { - FILETIME utc; - NTime::UnixTimeToFileTime(_item.Time, utc); - prop = utc; - } - 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 -} - -class CCompressProgressInfoImp: - public ICompressProgressInfo, - public CMyUnknownImp -{ - CMyComPtr 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) - { - UInt64 files = 0; - UInt64 value = Offset + *inSize; - return Callback->SetCompleted(&files, &value); - } - return S_OK; -} - -/* -*/ - -STDMETHODIMP 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 -} - -STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) -{ - COM_TRY_BEGIN - try - { - Close(); - _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 -} - -STDMETHODIMP 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(); - _decoderSpec->ReleaseInStream(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - if (_packSize_Defined) - extractCallback->SetTotal(_packSize); - // UInt64 currentTotalPacked = 0; - // RINOK(extractCallback->SetCompleted(¤tTotalPacked)); - CMyComPtr realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); - if (!testMode && !realOutStream) - return S_OK; - - extractCallback->PrepareOperation(askMode); - - COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; - CMyComPtr outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(); - realOutStream.Release(); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, true); - - bool needReadFirstItem = _needSeekToStart; - - if (_needSeekToStart) - { - if (!_stream) - return E_FAIL; - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - _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 UpdateArchive( - ISequentialOutStream *outStream, - UInt64 unpackSize, - CItem &item, - const CSingleMethodProps &props, - IArchiveUpdateCallback *updateCallback) -{ - UInt64 complexity = 0; - RINOK(updateCallback->SetTotal(unpackSize)); - RINOK(updateCallback->SetCompleted(&complexity)); - - CMyComPtr fileInStream; - - RINOK(updateCallback->GetStream(0, &fileInStream)); - - CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC; - CMyComPtr crcStream(inStreamSpec); - inStreamSpec->SetStream(fileInStream); - inStreamSpec->Init(); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr 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 deflateEncoder = deflateEncoderSpec; - RINOK(props.SetCoderProps(deflateEncoderSpec, NULL)); - RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress)); - - item.Crc = inStreamSpec->GetCRC(); - item.Size32 = (UInt32)inStreamSpec->GetSize(); - RINOK(item.WriteFooter(outStream)); - return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK); -} - -STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) -{ - *timeType = NFileTimeType::kUnix; - return S_OK; -} - -STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *updateCallback) -{ - COM_TRY_BEGIN - - if (numItems != 1) - return E_INVALIDARG; - - Int32 newData, newProps; - UInt32 indexInArchive; - if (!updateCallback) - return E_FAIL; - RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); - - CItem newItem; - - if (!IntToBool(newProps)) - { - newItem.CopyMetaPropsFrom(_item); - } - else - { - newItem.HostOS = kHostOS; - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidMTime, &prop)); - if (prop.vt == VT_FILETIME) - NTime::FileTimeToUnixTime(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(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, updateCallback); - } - - if (indexInArchive != 0) - return E_INVALIDARG; - - if (!_stream) - return E_NOTIMPL; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(updateCallback, true); - - CMyComPtr opCallback; - updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); - 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(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); - - return NCompress::CopyStream(_stream, outStream, progress); - - COM_TRY_END -} - -STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) -{ - return _props.SetProperties(names, values, numProps); -} - -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, - IsArc_Gz) - -}} +// GzHandler.cpp + +#include "StdAfx.h" + +// #include + +#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; + if (GetUi16(p) != (UInt16)~GetUi16(p + 2)) + 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 unsigned kNameMaxLen = 1 << 12; +static 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); +} + +class CHandler: + public IInArchive, + public IArchiveOpenSeq, + public IOutArchive, + public ISetProperties, + public CMyUnknownImp +{ + 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 _stream; + CMyComPtr _decoder; + NDecoder::CCOMCoder *_decoderSpec; + + CSingleMethodProps _props; + +public: + MY_UNKNOWN_IMP4( + IInArchive, + IArchiveOpenSeq, + IOutArchive, + ISetProperties) + INTERFACE_IInArchive(;) + INTERFACE_IOutArchive(;) + STDMETHOD(OpenSeq)(ISequentialInStream *stream); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); + + CHandler() + { + _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 + +STDMETHODIMP 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 +} + + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1; + return S_OK; +} + +STDMETHODIMP 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: + if (_item.Time != 0) + { + FILETIME utc; + NTime::UnixTimeToFileTime(_item.Time, utc); + prop = utc; + } + 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 +} + +class CCompressProgressInfoImp: + public ICompressProgressInfo, + public CMyUnknownImp +{ + CMyComPtr 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) + { + UInt64 files = 0; + UInt64 value = Offset + *inSize; + return Callback->SetCompleted(&files, &value); + } + return S_OK; +} + +/* +*/ + +STDMETHODIMP 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 +} + +STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) +{ + COM_TRY_BEGIN + try + { + Close(); + _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 +} + +STDMETHODIMP 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(); + _decoderSpec->ReleaseInStream(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + if (_packSize_Defined) + extractCallback->SetTotal(_packSize); + // UInt64 currentTotalPacked = 0; + // RINOK(extractCallback->SetCompleted(¤tTotalPacked)); + CMyComPtr realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); + if (!testMode && !realOutStream) + return S_OK; + + extractCallback->PrepareOperation(askMode); + + COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; + CMyComPtr outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + realOutStream.Release(); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, true); + + bool needReadFirstItem = _needSeekToStart; + + if (_needSeekToStart) + { + if (!_stream) + return E_FAIL; + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); + _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 UpdateArchive( + ISequentialOutStream *outStream, + UInt64 unpackSize, + CItem &item, + const CSingleMethodProps &props, + IArchiveUpdateCallback *updateCallback) +{ + UInt64 complexity = 0; + RINOK(updateCallback->SetTotal(unpackSize)); + RINOK(updateCallback->SetCompleted(&complexity)); + + CMyComPtr fileInStream; + + RINOK(updateCallback->GetStream(0, &fileInStream)); + + CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC; + CMyComPtr crcStream(inStreamSpec); + inStreamSpec->SetStream(fileInStream); + inStreamSpec->Init(); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr 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 deflateEncoder = deflateEncoderSpec; + RINOK(props.SetCoderProps(deflateEncoderSpec, NULL)); + RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress)); + + item.Crc = inStreamSpec->GetCRC(); + item.Size32 = (UInt32)inStreamSpec->GetSize(); + RINOK(item.WriteFooter(outStream)); + return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK); +} + +STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) +{ + *timeType = NFileTimeType::kUnix; + return S_OK; +} + +STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback) +{ + COM_TRY_BEGIN + + if (numItems != 1) + return E_INVALIDARG; + + Int32 newData, newProps; + UInt32 indexInArchive; + if (!updateCallback) + return E_FAIL; + RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); + + CItem newItem; + + if (!IntToBool(newProps)) + { + newItem.CopyMetaPropsFrom(_item); + } + else + { + newItem.HostOS = kHostOS; + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidMTime, &prop)); + if (prop.vt == VT_FILETIME) + NTime::FileTimeToUnixTime(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(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, updateCallback); + } + + if (indexInArchive != 0) + return E_INVALIDARG; + + if (!_stream) + return E_NOTIMPL; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(updateCallback, true); + + CMyComPtr opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + 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(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); + + return NCompress::CopyStream(_stream, outStream, progress); + + COM_TRY_END +} + +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) +{ + return _props.SetProperties(names, values, numProps); +} + +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, + IsArc_Gz) + +}} diff --git a/CPP/7zip/Archive/HandlerCont.cpp b/CPP/7zip/Archive/HandlerCont.cpp index 8c74de8dd..c2d5c70cf 100644 --- a/CPP/7zip/Archive/HandlerCont.cpp +++ b/CPP/7zip/Archive/HandlerCont.cpp @@ -1,288 +1,288 @@ -// 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 { - -STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - 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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_stream); - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - CMyComPtr outStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - Int32 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(_stream->Seek(pos, STREAM_SEEK_SET, NULL)); - 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 -} - -STDMETHODIMP 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(): - _imgExt(NULL) -{ - ClearStreamVars(); -} - -STDMETHODIMP 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) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _virtPos = offset; - if (newPosition) - *newPosition = offset; - return S_OK; -} - -static const Byte k_GDP_Signature[] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' }; - -static const char *GetImgExt(ISequentialInStream *stream) -{ - const size_t kHeaderSize = 1 << 10; - 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"; - } - } - return NULL; -} - -void CHandlerImg::CloseAtError() -{ - Stream.Release(); -} - -STDMETHODIMP 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 inStream; - HRESULT res2 = GetStream(0, &inStream); - if (res2 == S_OK && inStream) - _imgExt = GetImgExt(inStream); - return S_OK; - } - } - catch(...) - { - CloseAtError(); - throw; - } - CloseAtError(); - return res; - } - COM_TRY_END -} - -STDMETHODIMP CHandlerImg::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = 1; - return S_OK; -} - -STDMETHODIMP 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 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)); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - int opRes = NExtract::NOperationResult::kDataError; - - ClearStreamVars(); - - CMyComPtr inStream; - HRESULT hres = GetStream(0, &inStream); - if (hres == S_FALSE) - hres = E_NOTIMPL; - - if (hres == S_OK && inStream) - { - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr 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; - HRESULT(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; - } -} - -} +// 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 { + +STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + 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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(_stream); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 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(_stream->Seek(pos, STREAM_SEEK_SET, NULL)); + 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 +} + +STDMETHODIMP 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(): + _imgExt(NULL) +{ + ClearStreamVars(); +} + +STDMETHODIMP 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) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = offset; + if (newPosition) + *newPosition = offset; + return S_OK; +} + +static const Byte k_GDP_Signature[] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' }; + +static const char *GetImgExt(ISequentialInStream *stream) +{ + const size_t kHeaderSize = 1 << 10; + 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"; + } + } + return NULL; +} + +void CHandlerImg::CloseAtError() +{ + Stream.Release(); +} + +STDMETHODIMP 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 inStream; + HRESULT res2 = GetStream(0, &inStream); + if (res2 == S_OK && inStream) + _imgExt = GetImgExt(inStream); + return S_OK; + } + } + catch(...) + { + CloseAtError(); + throw; + } + CloseAtError(); + return res; + } + COM_TRY_END +} + +STDMETHODIMP CHandlerImg::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1; + return S_OK; +} + +STDMETHODIMP 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 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)); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + int opRes = NExtract::NOperationResult::kDataError; + + ClearStreamVars(); + + CMyComPtr inStream; + HRESULT hres = GetStream(0, &inStream); + if (hres == S_FALSE) + hres = E_NOTIMPL; + + if (hres == S_OK && inStream) + { + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr 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; + HRESULT(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 index 4a32a7959..50a72895e 100644 --- a/CPP/7zip/Archive/HandlerCont.h +++ b/CPP/7zip/Archive/HandlerCont.h @@ -1,116 +1,116 @@ -// HandlerCont.h - -#ifndef __HANDLER_CONT_H -#define __HANDLER_CONT_H - -#include "../../Common/MyCom.h" - -#include "IArchive.h" - -namespace NArchive { - -#define INTERFACE_IInArchive_Cont(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; \ - - -class CHandlerCont: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ -protected: - CMyComPtr _stream; - - virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const = 0; - -public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive_Cont(PURE) - - STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY; - - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - - // destructor must be virtual for this class - virtual ~CHandlerCont() {} -}; - - - -#define INTERFACE_IInArchive_Img(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; \ - - -class CHandlerImg: - public IInStream, - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ -protected: - UInt64 _virtPos; - UInt64 _posInArc; - UInt64 _size; - CMyComPtr Stream; - const char *_imgExt; - - bool _stream_unavailData; - bool _stream_unsupportedMethod; - bool _stream_dataError; - // bool _stream_UsePackSize; - // UInt64 _stream_PackSize; - - void ClearStreamVars() - { - _stream_unavailData = false; - _stream_unsupportedMethod = false; - _stream_dataError = false; - // _stream_UsePackSize = false; - // _stream_PackSize = 0; - } - - - virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0; - virtual void CloseAtError(); -public: - MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream) - INTERFACE_IInArchive_Img(PURE) - - STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback); - STDMETHOD(GetNumberOfItems)(UInt32 *numItems); - STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback); - - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) = 0; - - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) = 0; - STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); - - CHandlerImg(); - // destructor must be virtual for this class - virtual ~CHandlerImg() {} -}; - - -HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize); - -} - -#endif +// HandlerCont.h + +#ifndef __HANDLER_CONT_H +#define __HANDLER_CONT_H + +#include "../../Common/MyCom.h" + +#include "IArchive.h" + +namespace NArchive { + +#define INTERFACE_IInArchive_Cont(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; \ + + +class CHandlerCont: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ +protected: + CMyComPtr _stream; + + virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const = 0; + +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive_Cont(PURE) + + STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY; + + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + + // destructor must be virtual for this class + virtual ~CHandlerCont() {} +}; + + + +#define INTERFACE_IInArchive_Img(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; \ + + +class CHandlerImg: + public IInStream, + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ +protected: + UInt64 _virtPos; + UInt64 _posInArc; + UInt64 _size; + CMyComPtr Stream; + const char *_imgExt; + + bool _stream_unavailData; + bool _stream_unsupportedMethod; + bool _stream_dataError; + // bool _stream_UsePackSize; + // UInt64 _stream_PackSize; + + void ClearStreamVars() + { + _stream_unavailData = false; + _stream_unsupportedMethod = false; + _stream_dataError = false; + // _stream_UsePackSize = false; + // _stream_PackSize = 0; + } + + + virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0; + virtual void CloseAtError(); +public: + MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream) + INTERFACE_IInArchive_Img(PURE) + + STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback); + STDMETHOD(GetNumberOfItems)(UInt32 *numItems); + STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback); + + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) = 0; + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) = 0; + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); + + 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 index 5ccbae63f..ca1d7bda4 100644 --- a/CPP/7zip/Archive/HfsHandler.cpp +++ b/CPP/7zip/Archive/HfsHandler.cpp @@ -1,1980 +1,1980 @@ -// HfsHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyString.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/ZlibDecoder.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 Extents; -}; - -struct CFork -{ - UInt64 Size; - UInt32 NumBlocks; - // UInt32 ClumpSize; - CRecordVector 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 &items, UInt32 id); - bool UpgradeAndTest(const CObjectVector &items, UInt32 id, unsigned blockSizeLog) - { - if (!Upgrade(items, id)) - return false; - return IsOk(blockSizeLog); - } -}; - -static const unsigned 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; - int Index; - - int Compare(const CIdIndexPair &a) const; -}; - -#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } - -int CIdIndexPair::Compare(const CIdIndexPair &a) const -{ - RINOZ(MyCompare(ID, a.ID)); - return MyCompare(Index, a.Index); -} - -static int FindItemIndex(const CRecordVector &items, UInt32 id) -{ - unsigned left = 0, right = items.Size(); - while (left != right) - { - unsigned mid = (left + right) / 2; - UInt32 midVal = items[mid].ID; - if (id == midVal) - return items[mid].Index; - if (id < midVal) - right = mid; - else - left = mid + 1; - } - return -1; -} - -static int Find_in_IdExtents(const CObjectVector &items, UInt32 id) -{ - unsigned left = 0, right = items.Size(); - while (left != right) - { - unsigned mid = (left + right) / 2; - UInt32 midVal = items[mid].ID; - if (id == midVal) - return mid; - if (id < midVal) - right = mid; - else - left = mid + 1; - } - return -1; -} - -bool CFork::Upgrade(const CObjectVector &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 -}; - -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 - UInt64 UnpackSize; - size_t DataPos; - UInt32 PackSize; - unsigned Method; - bool UseAttr; - bool UseInlineData; - - CItem(): UseAttr(false), UseInlineData(false) {} - bool IsDir() const { return Type == RECORD_TYPE_FOLDER; } - const CFork &GetFork(bool isResource) const { return (CFork & )*(isResource ? &ResourceFork: &DataFork ); } -}; - -struct CAttr -{ - UInt32 ID; - UInt32 Size; - size_t Pos; - UString Name; -}; - -struct CRef -{ - unsigned ItemIndex; - int AttrIndex; - int Parent; - bool IsResource; - - bool IsAltStream() const { return IsResource || AttrIndex >= 0; } - CRef(): AttrIndex(-1), Parent(-1), IsResource(false) {} -}; - -class CDatabase -{ - HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream); - HRESULT LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector *overflowExtentsArray); - HRESULT LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress); - HRESULT LoadCatalog(const CFork &fork, const CObjectVector *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress); - bool Parse_decmpgfs(const CAttr &attr, CItem &item, bool &skip); -public: - CRecordVector Refs; - CObjectVector Items; - CObjectVector Attrs; - - CByteBuffer AttrBuf; - - CVolHeader Header; - bool HeadersError; - bool ThereAreAltStreams; - // bool CaseSensetive; - UString ResFileName; - - UInt64 SpecOffset; - UInt64 PhySize; - UInt64 PhySize2; - - void Clear() - { - SpecOffset = 0; - PhySize = 0; - PhySize2 = 0; - HeadersError = 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].Size; - const CItem &item = Items[ref.ItemIndex]; - if (item.IsDir()) - return 0; - if (item.UseAttr) - return item.UnpackSize; - return item.GetFork(ref.IsResource).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); - int 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 = ref.Parent; - if (cur < 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 = 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; - 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->Seek(SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog), STREAM_SEEK_SET, NULL)); - 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 CheckNumRecords(unsigned nodeSizeLog) - { - return (kNodeDescriptor_Size + ((UInt32)NumRecords + 1) * 2 <= ((UInt32)1 << nodeSizeLog)); - } - void Parse(const Byte *p); -}; - -void CNodeDescriptor::Parse(const Byte *p) -{ - fLink = Get32(p); - // bLink = Get32(p + 4); - Kind = p[8]; - // Height = p[9]; - NumRecords = Get16(p + 10); -} - -struct CHeaderRec -{ - // UInt16 TreeDepth; - // UInt32 RootNode; - // UInt32 LeafRecords; - UInt32 FirstLeafNode; - // UInt32 LastLeafNode; - 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 *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; - - CByteBuffer usedBuf(hr.TotalNodes); - memset(usedBuf, 0, hr.TotalNodes); - - while (node != 0) - { - if (node >= hr.TotalNodes || usedBuf[node] != 0) - return S_FALSE; - usedBuf[node] = 1; - - size_t nodeOffset = (size_t)node << hr.NodeSizeLog; - CNodeDescriptor desc; - desc.Parse(p + nodeOffset); - if (!desc.CheckNumRecords(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 UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2); - const UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2); - if (offs > nodeSize || offsNext > nodeSize) - return S_FALSE; - UInt32 recSize = offsNext - offs; - const unsigned kKeyLen = 10; - - if (recSize != 2 + kKeyLen + kNumFixedExtents * 8) - return S_FALSE; - - const Byte *r = p + nodeOffset + offs; - if (Get16(r) != kKeyLen) - return S_FALSE; - - Byte forkType = r[2]; - unsigned forkTypeIndex; - if (forkType == kExtentForkType_Data) - forkTypeIndex = 0; - else if (forkType == kExtentForkType_Resource) - forkTypeIndex = 1; - else - continue; - CObjectVector &overflowExtents = overflowExtentsArray[forkTypeIndex]; - - UInt32 id = Get32(r + 4); - 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++) - { - 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++) - { - 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; - - 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; - - CByteBuffer 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; - - size_t nodeOffset = (size_t)node << hr.NodeSizeLog; - CNodeDescriptor desc; - desc.Parse(p + nodeOffset); - if (!desc.CheckNumRecords(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 UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2); - const UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2); - UInt32 recSize = offsNext - offs; - if (offs >= nodeSize - || offsNext > nodeSize - || offsNext < offs) - return S_FALSE; - - const unsigned kHeadSize = 14; - if (recSize < kHeadSize) - return S_FALSE; - - const Byte *r = p + nodeOffset + offs; - UInt32 keyLen = Get16(r); - - // UInt16 pad = Get16(r + 2); - UInt32 fileID = Get32(r + 4); - unsigned startBlock = Get32(r + 8); - if (startBlock != 0) - { - // that case is still unsupported - HeadersError = true; - continue; - } - 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; - - UInt32 recordType = Get32(r); - if (recordType != kAttrRecordType_Inline) - { - // Probably only kAttrRecordType_Inline now is used in real HFS files - HeadersError = true; - continue; - } - - const UInt32 kRecordHeaderSize = 16; - if (recSize < kRecordHeaderSize) - return S_FALSE; - UInt32 dataSize = Get32(r + 12); - - r += kRecordHeaderSize; - recSize -= kRecordHeaderSize; - - if (recSize < dataSize) - return S_FALSE; - - CAttr &attr = Attrs.AddNew(); - attr.ID = fileID; - attr.Pos = nodeOffset + offs + 2 + keyLen + kRecordHeaderSize; - attr.Size = dataSize; - LoadName(name, nameLen, attr.Name); - - if (progress && (i & 0xFFF) == 0) - { - UInt64 numFiles = 0; - RINOK(progress->SetCompleted(&numFiles, NULL)); - } - } - - node = desc.fLink; - } - return S_OK; -} - -static const UInt32 kMethod_Attr = 3; // data stored in attribute file -static const UInt32 kMethod_Resource = 4; // data stored in resource fork - -bool CDatabase::Parse_decmpgfs(const CAttr &attr, CItem &item, bool &skip) -{ - skip = false; - if (!attr.Name.IsEqualTo("com.apple.decmpfs")) - return true; - if (item.UseAttr || !item.DataFork.IsEmpty()) - return false; - - const UInt32 k_decmpfs_headerSize = 16; - UInt32 dataSize = attr.Size; - if (dataSize < k_decmpfs_headerSize) - return false; - const Byte *r = AttrBuf + attr.Pos; - if (GetUi32(r) != 0x636D7066) // magic == "fpmc" - return false; - item.Method = GetUi32(r + 4); - item.UnpackSize = GetUi64(r + 8); - dataSize -= k_decmpfs_headerSize; - r += k_decmpfs_headerSize; - if (item.Method == kMethod_Resource) - { - if (dataSize != 0) - return false; - item.UseAttr = true; - } - else if (item.Method == kMethod_Attr) - { - if (dataSize == 0) - return false; - Byte b = r[0]; - if ((b & 0xF) == 0xF) - { - dataSize--; - if (item.UnpackSize > dataSize) - return false; - item.DataPos = attr.Pos + k_decmpfs_headerSize + 1; - item.PackSize = dataSize; - item.UseAttr = true; - item.UseInlineData = true; - } - else - { - item.DataPos = attr.Pos + k_decmpfs_headerSize; - item.PackSize = dataSize; - item.UseAttr = true; - } - } - else - return false; - skip = true; - return true; -} - -HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress) -{ - unsigned reserveSize = (unsigned)(Header.NumFolders + 1 + Header.NumFiles); - Items.ClearAndReserve(reserveSize); - Refs.ClearAndReserve(reserveSize); - - CRecordVector IdToIndexMap; - IdToIndexMap.ClearAndReserve(reserveSize); - - CByteBuffer buf; - RINOK(ReadFile(fork, buf, inStream)); - const Byte *p = (const Byte *)buf; - - // CNodeDescriptor nodeDesc; - // nodeDesc.Parse(p); - CHeaderRec hr; - RINOK(hr.Parse2(buf)); - - // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC); - - CByteBuffer usedBuf(hr.TotalNodes); - 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; - desc.Parse(p + nodeOffset); - if (!desc.CheckNumRecords(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 UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2); - const UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2); - UInt32 recSize = offsNext - offs; - if (offs >= nodeSize - || offsNext > nodeSize - || offsNext < offs - || recSize < 6) - return S_FALSE; - - const Byte *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; - - const unsigned kBasicRecSize = 0x58; - 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++; - const unsigned kForkRecSize = 16 + kNumFixedExtents * 8; - 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) - { - 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]; - - int itemIndex = FindItemIndex(IdToIndexMap, attr.ID); - if (itemIndex < 0) - { - HeadersError = true; - continue; - } - if (!Parse_decmpgfs(attr, 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.UseAttr && item.Method == kMethod_Resource) - continue; - CRef resRef; - resRef.ItemIndex = i; - resRef.IsResource = true; - resRef.Parent = Refs.Size() - 1; - Refs.Add(resRef); - - #endif - } - } - - IdToIndexMap.Sort2(); - - { - FOR_VECTOR (i, Refs) - { - CRef &ref = Refs[i]; - if (ref.IsResource) - continue; - 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]; - - int refIndex = FindItemIndex(IdToIndexMap, attr.ID); - if (refIndex < 0) - { - HeadersError = true; - continue; - } - - CRef ref; - ref.AttrIndex = 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->Seek(SpecOffset, STREAM_SEEK_SET, NULL)); - 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; - if (progress) - { - 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); - */ - - /* - UInt64 endPos; - RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); - if ((endPos >> h.BlockSizeLog) < h.NumBlocks) - return S_FALSE; - */ - - 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 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; -} - - - -class CHandler: - public IInArchive, - public IArchiveGetRawProps, - public IInArchiveGetStream, - public CMyUnknownImp, - public CDatabase -{ - CMyComPtr _stream; - - HRESULT GetForkStream(const CFork &fork, ISequentialInStream **stream); - - HRESULT ExtractZlibFile( - ISequentialOutStream *realOutStream, - const CItem &item, - NCompress::NZlib::CDecoder *_zlibDecoderSpec, - CByteBuffer &buf, - UInt64 progressStart, - IArchiveExtractCallback *extractCallback); -public: - MY_UNKNOWN_IMP3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream) - INTERFACE_IInArchive(;) - INTERFACE_IArchiveGetRawProps(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidCTime, - kpidMTime, - kpidATime, - kpidPosixAttrib -}; - -static const Byte kArcProps[] = -{ - kpidMethod, - kpidClusterSize, - kpidFreeSpace, - kpidCTime, - kpidMTime -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop) -{ - FILETIME ft; - HfsTimeToFileTime(hfsTime, ft); - prop = ft; -} - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidExtension: prop = Header.IsHfsX() ? "hfsx" : "hfs"; break; - case kpidMethod: prop = Header.IsHfsX() ? "HFSX" : "HFS+"; 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: - { - FILETIME localFt, ft; - HfsTimeToFileTime(Header.CTime, localFt); - if (LocalFileTimeToFileTime(&localFt, &ft)) - prop = ft; - break; - } - case kpidIsTree: prop = true; break; - case kpidErrorFlags: - { - UInt32 flags = 0; - if (HeadersError) flags |= kpv_ErrorFlags_HeadersError; - if (flags != 0) - prop = flags; - break; - } - case kpidIsAltStream: prop = ThereAreAltStreams; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) -{ - *numProps = 0; - return S_OK; -} - -STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) -{ - *name = NULL; - *propID = 0; - return S_OK; -} - -STDMETHODIMP 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; -} - -STDMETHODIMP 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) * sizeof(wchar_t); - *propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE; - return S_OK; - } - #endif - return S_OK; -} - -STDMETHODIMP 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].Size; - else if (item.IsDir()) - break; - else if (item.UseAttr) - { - if (item.Method == kMethod_Resource) - size = item.ResourceFork.NumBlocks << Header.BlockSizeLog; - else - size = item.PackSize; - } - else - size = item.GetFork(ref.IsResource).NumBlocks << Header.BlockSizeLog; - prop = size; - break; - } - case kpidSize: - { - UInt64 size; - if (ref.AttrIndex >= 0) - size = Attrs[ref.AttrIndex].Size; - else if (item.IsDir()) - break; - else if (item.UseAttr) - size = item.UnpackSize; - else - size = item.GetFork(ref.IsResource).Size; - prop = size; - break; - } - case kpidIsDir: prop = 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 kpidPosixAttrib: if (ref.AttrIndex < 0) prop = (UInt32)item.FileMode; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP 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 -} - -STDMETHODIMP CHandler::Close() -{ - _stream.Release(); - Clear(); - return S_OK; -} - -static const UInt32 kCompressionBlockSize = 1 << 16; - -HRESULT CHandler::ExtractZlibFile( - ISequentialOutStream *outStream, - const CItem &item, - NCompress::NZlib::CDecoder *_zlibDecoderSpec, - CByteBuffer &buf, - UInt64 progressStart, - IArchiveExtractCallback *extractCallback) -{ - CMyComPtr inStream; - const CFork &fork = item.ResourceFork; - RINOK(GetForkStream(fork, &inStream)); - const unsigned kHeaderSize = 0x100 + 8; - RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)); - UInt32 dataPos = Get32(buf); - UInt32 mapPos = Get32(buf + 4); - UInt32 dataSize = Get32(buf + 8); - UInt32 mapSize = Get32(buf + 12); - - const UInt32 kResMapSize = 50; - - if (mapSize != kResMapSize - || dataPos + dataSize != mapPos - || mapPos + mapSize != fork.Size) - return S_FALSE; - - UInt32 dataSize2 = Get32(buf + 0x100); - if (4 + dataSize2 != dataSize || dataSize2 < 8) - return S_FALSE; - - UInt32 numBlocks = GetUi32(buf + 0x100 + 4); - if (((dataSize2 - 4) >> 3) < numBlocks) - return S_FALSE; - if (item.UnpackSize > (UInt64)numBlocks * kCompressionBlockSize) - return S_FALSE; - - if (item.UnpackSize + kCompressionBlockSize < (UInt64)numBlocks * kCompressionBlockSize) - return S_FALSE; - - UInt32 tableSize = (numBlocks << 3); - - CByteBuffer tableBuf(tableSize); - - RINOK(ReadStream_FALSE(inStream, tableBuf, tableSize)); - - UInt32 prev = 4 + tableSize; - - UInt32 i; - for (i = 0; i < numBlocks; i++) - { - UInt32 offset = GetUi32(tableBuf + i * 8); - UInt32 size = GetUi32(tableBuf + i * 8 + 4); - if (size == 0) - return S_FALSE; - if (prev != offset) - return S_FALSE; - if (offset > dataSize2 || - size > dataSize2 - offset) - return S_FALSE; - prev = offset + size; - } - - if (prev != dataSize2) - return S_FALSE; - - CBufInStream *bufInStreamSpec = new CBufInStream; - CMyComPtr bufInStream = bufInStreamSpec; - - UInt64 outPos = 0; - for (i = 0; i < numBlocks; i++) - { - UInt64 rem = item.UnpackSize - outPos; - if (rem == 0) - return S_FALSE; - UInt32 blockSize = kCompressionBlockSize; - if (rem < kCompressionBlockSize) - blockSize = (UInt32)rem; - - UInt32 size = GetUi32(tableBuf + i * 8 + 4); - - if (size > buf.Size() || size > kCompressionBlockSize + 1) - return S_FALSE; - - RINOK(ReadStream_FALSE(inStream, buf, size)); - - if ((buf[0] & 0xF) == 0xF) - { - // that code was not tested. Are there HFS archives with uncompressed block - if (size - 1 != blockSize) - return S_FALSE; - - if (outStream) - { - RINOK(WriteStream(outStream, buf, blockSize)); - } - } - else - { - UInt64 blockSize64 = blockSize; - bufInStreamSpec->Init(buf, size); - RINOK(_zlibDecoderSpec->Code(bufInStream, outStream, NULL, &blockSize64, NULL)); - if (_zlibDecoderSpec->GetOutputProcessedSize() != blockSize || - _zlibDecoderSpec->GetInputProcessedSize() != size) - return S_FALSE; - } - - outPos += blockSize; - UInt64 progressPos = progressStart + outPos; - RINOK(extractCallback->SetCompleted(&progressPos)); - } - - if (outPos != item.UnpackSize) - return S_FALSE; - - /* We check Resource Map - Are there HFS files with another values in Resource Map ??? */ - - RINOK(ReadStream_FALSE(inStream, buf, mapSize)); - UInt32 types = Get16(buf + 24); - UInt32 names = Get16(buf + 26); - UInt32 numTypes = Get16(buf + 28); - if (numTypes != 0 || types != 28 || names != kResMapSize) - return S_FALSE; - UInt32 resType = Get32(buf + 30); - UInt32 numResources = Get16(buf + 34); - UInt32 resListOffset = Get16(buf + 36); - if (resType != 0x636D7066) // cmpf - return S_FALSE; - if (numResources != 0 || resListOffset != 10) - return S_FALSE; - - UInt32 entryId = Get16(buf + 38); - UInt32 nameOffset = Get16(buf + 40); - // Byte attrib = buf[42]; - UInt32 resourceOffset = Get32(buf + 42) & 0xFFFFFF; - if (entryId != 1 || nameOffset != 0xFFFF || resourceOffset != 0) - return S_FALSE; - - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - 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 - - NCompress::NZlib::CDecoder *_zlibDecoderSpec = NULL; - CMyComPtr _zlibDecoder; - - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) - { - RINOK(extractCallback->SetCompleted(¤tTotalSize)); - UInt32 index = allFilesMode ? i : indices[i]; - const CRef &ref = Refs[index]; - const CItem &item = Items[ref.ItemIndex]; - currentItemSize = Get_UnpackSize_of_Ref(ref); - - CMyComPtr realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - - if (ref.AttrIndex < 0 && item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - UInt64 pos = 0; - int res = NExtract::NOperationResult::kDataError; - if (ref.AttrIndex >= 0) - { - res = NExtract::NOperationResult::kOK; - if (realOutStream) - { - const CAttr &attr = Attrs[ref.AttrIndex]; - RINOK(WriteStream(realOutStream, AttrBuf + attr.Pos, attr.Size)); - } - } - else if (item.UseAttr) - { - if (item.UseInlineData) - { - res = NExtract::NOperationResult::kOK; - if (realOutStream) - { - RINOK(WriteStream(realOutStream, AttrBuf + item.DataPos, (size_t)item.UnpackSize)); - } - } - else - { - if (!_zlibDecoder) - { - _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); - _zlibDecoder = _zlibDecoderSpec; - } - - if (item.Method == kMethod_Attr) - { - CBufInStream *bufInStreamSpec = new CBufInStream; - CMyComPtr bufInStream = bufInStreamSpec; - bufInStreamSpec->Init(AttrBuf + item.DataPos, item.PackSize); - - HRESULT hres = _zlibDecoder->Code(bufInStream, realOutStream, NULL, &item.UnpackSize, NULL); - if (hres != S_FALSE) - { - if (hres != S_OK) - return hres; - if (_zlibDecoderSpec->GetOutputProcessedSize() == item.UnpackSize && - _zlibDecoderSpec->GetInputProcessedSize() == item.PackSize) - res = NExtract::NOperationResult::kOK; - } - } - else - { - HRESULT hres = ExtractZlibFile(realOutStream, item, _zlibDecoderSpec, buf, - currentTotalSize, extractCallback); - if (hres != S_FALSE) - { - if (hres != S_OK) - return hres; - res = NExtract::NOperationResult::kOK; - } - } - } - } - else - { - const CFork &fork = item.GetFork(ref.IsResource); - if (fork.IsOk(Header.BlockSizeLog)) - { - res = NExtract::NOperationResult::kOK; - unsigned extentIndex; - for (extentIndex = 0; extentIndex < fork.Extents.Size(); extentIndex++) - { - if (res != NExtract::NOperationResult::kOK) - break; - if (fork.Size == pos) - break; - const CExtent &e = fork.Extents[extentIndex]; - RINOK(_stream->Seek(SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog), STREAM_SEEK_SET, NULL)); - UInt64 extentRem = (UInt64)e.NumBlocks << Header.BlockSizeLog; - while (extentRem != 0) - { - 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)) - res = 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) - { - res = NExtract::NOperationResult::kDataError; - break; - } - if (realOutStream) - { - RINOK(WriteStream(realOutStream, buf, cur)); - } - pos += cur; - extentRem -= cur; - UInt64 processed = currentTotalSize + pos; - RINOK(extractCallback->SetCompleted(&processed)); - } - } - if (extentIndex != fork.Extents.Size() || fork.Size != pos) - res = NExtract::NOperationResult::kDataError; - } - } - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(res)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = Refs.Size(); - return S_OK; -} - -HRESULT CHandler::GetForkStream(const CFork &fork, ISequentialInStream **stream) -{ - *stream = 0; - - if (!fork.IsOk(Header.BlockSizeLog)) - return S_FALSE; - - CExtentsStream *extentStreamSpec = new CExtentsStream(); - CMyComPtr 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; -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - *stream = 0; - - const CRef &ref = Refs[index]; - if (ref.AttrIndex >= 0) - return S_FALSE; - const CItem &item = Items[ref.ItemIndex]; - if (item.IsDir() || item.UseAttr) - return S_FALSE; - - return GetForkStream(item.GetFork(ref.IsResource), stream); -} - -static const Byte k_Signature[] = { - 2, 'B', 'D', - 4, 'H', '+', 0, 4, - 4, 'H', 'X', 0, 5 }; - -REGISTER_ARC_I( - "HFS", "hfs hfsx", 0, 0xE3, - k_Signature, - kHeaderPadSize, - NArcInfoFlags::kMultiSignature, - IsArc_HFS) - -}} +// HfsHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyString.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/ZlibDecoder.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 Extents; +}; + +struct CFork +{ + UInt64 Size; + UInt32 NumBlocks; + // UInt32 ClumpSize; + CRecordVector 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 &items, UInt32 id); + bool UpgradeAndTest(const CObjectVector &items, UInt32 id, unsigned blockSizeLog) + { + if (!Upgrade(items, id)) + return false; + return IsOk(blockSizeLog); + } +}; + +static const unsigned 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; + int Index; + + int Compare(const CIdIndexPair &a) const; +}; + +#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } + +int CIdIndexPair::Compare(const CIdIndexPair &a) const +{ + RINOZ(MyCompare(ID, a.ID)); + return MyCompare(Index, a.Index); +} + +static int FindItemIndex(const CRecordVector &items, UInt32 id) +{ + unsigned left = 0, right = items.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + UInt32 midVal = items[mid].ID; + if (id == midVal) + return items[mid].Index; + if (id < midVal) + right = mid; + else + left = mid + 1; + } + return -1; +} + +static int Find_in_IdExtents(const CObjectVector &items, UInt32 id) +{ + unsigned left = 0, right = items.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + UInt32 midVal = items[mid].ID; + if (id == midVal) + return mid; + if (id < midVal) + right = mid; + else + left = mid + 1; + } + return -1; +} + +bool CFork::Upgrade(const CObjectVector &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 +}; + +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 + UInt64 UnpackSize; + size_t DataPos; + UInt32 PackSize; + unsigned Method; + bool UseAttr; + bool UseInlineData; + + CItem(): UseAttr(false), UseInlineData(false) {} + bool IsDir() const { return Type == RECORD_TYPE_FOLDER; } + const CFork &GetFork(bool isResource) const { return (CFork & )*(isResource ? &ResourceFork: &DataFork ); } +}; + +struct CAttr +{ + UInt32 ID; + UInt32 Size; + size_t Pos; + UString Name; +}; + +struct CRef +{ + unsigned ItemIndex; + int AttrIndex; + int Parent; + bool IsResource; + + bool IsAltStream() const { return IsResource || AttrIndex >= 0; } + CRef(): AttrIndex(-1), Parent(-1), IsResource(false) {} +}; + +class CDatabase +{ + HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream); + HRESULT LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector *overflowExtentsArray); + HRESULT LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress); + HRESULT LoadCatalog(const CFork &fork, const CObjectVector *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress); + bool Parse_decmpgfs(const CAttr &attr, CItem &item, bool &skip); +public: + CRecordVector Refs; + CObjectVector Items; + CObjectVector Attrs; + + CByteBuffer AttrBuf; + + CVolHeader Header; + bool HeadersError; + bool ThereAreAltStreams; + // bool CaseSensetive; + UString ResFileName; + + UInt64 SpecOffset; + UInt64 PhySize; + UInt64 PhySize2; + + void Clear() + { + SpecOffset = 0; + PhySize = 0; + PhySize2 = 0; + HeadersError = 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].Size; + const CItem &item = Items[ref.ItemIndex]; + if (item.IsDir()) + return 0; + if (item.UseAttr) + return item.UnpackSize; + return item.GetFork(ref.IsResource).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); + int 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 = ref.Parent; + if (cur < 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 = 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; + 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->Seek(SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog), STREAM_SEEK_SET, NULL)); + 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 CheckNumRecords(unsigned nodeSizeLog) + { + return (kNodeDescriptor_Size + ((UInt32)NumRecords + 1) * 2 <= ((UInt32)1 << nodeSizeLog)); + } + void Parse(const Byte *p); +}; + +void CNodeDescriptor::Parse(const Byte *p) +{ + fLink = Get32(p); + // bLink = Get32(p + 4); + Kind = p[8]; + // Height = p[9]; + NumRecords = Get16(p + 10); +} + +struct CHeaderRec +{ + // UInt16 TreeDepth; + // UInt32 RootNode; + // UInt32 LeafRecords; + UInt32 FirstLeafNode; + // UInt32 LastLeafNode; + 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 *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; + + CByteBuffer usedBuf(hr.TotalNodes); + memset(usedBuf, 0, hr.TotalNodes); + + while (node != 0) + { + if (node >= hr.TotalNodes || usedBuf[node] != 0) + return S_FALSE; + usedBuf[node] = 1; + + size_t nodeOffset = (size_t)node << hr.NodeSizeLog; + CNodeDescriptor desc; + desc.Parse(p + nodeOffset); + if (!desc.CheckNumRecords(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 UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2); + const UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2); + if (offs > nodeSize || offsNext > nodeSize) + return S_FALSE; + UInt32 recSize = offsNext - offs; + const unsigned kKeyLen = 10; + + if (recSize != 2 + kKeyLen + kNumFixedExtents * 8) + return S_FALSE; + + const Byte *r = p + nodeOffset + offs; + if (Get16(r) != kKeyLen) + return S_FALSE; + + Byte forkType = r[2]; + unsigned forkTypeIndex; + if (forkType == kExtentForkType_Data) + forkTypeIndex = 0; + else if (forkType == kExtentForkType_Resource) + forkTypeIndex = 1; + else + continue; + CObjectVector &overflowExtents = overflowExtentsArray[forkTypeIndex]; + + UInt32 id = Get32(r + 4); + 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++) + { + 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++) + { + 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; + + 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; + + CByteBuffer 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; + + size_t nodeOffset = (size_t)node << hr.NodeSizeLog; + CNodeDescriptor desc; + desc.Parse(p + nodeOffset); + if (!desc.CheckNumRecords(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 UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2); + const UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2); + UInt32 recSize = offsNext - offs; + if (offs >= nodeSize + || offsNext > nodeSize + || offsNext < offs) + return S_FALSE; + + const unsigned kHeadSize = 14; + if (recSize < kHeadSize) + return S_FALSE; + + const Byte *r = p + nodeOffset + offs; + UInt32 keyLen = Get16(r); + + // UInt16 pad = Get16(r + 2); + UInt32 fileID = Get32(r + 4); + unsigned startBlock = Get32(r + 8); + if (startBlock != 0) + { + // that case is still unsupported + HeadersError = true; + continue; + } + 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; + + UInt32 recordType = Get32(r); + if (recordType != kAttrRecordType_Inline) + { + // Probably only kAttrRecordType_Inline now is used in real HFS files + HeadersError = true; + continue; + } + + const UInt32 kRecordHeaderSize = 16; + if (recSize < kRecordHeaderSize) + return S_FALSE; + UInt32 dataSize = Get32(r + 12); + + r += kRecordHeaderSize; + recSize -= kRecordHeaderSize; + + if (recSize < dataSize) + return S_FALSE; + + CAttr &attr = Attrs.AddNew(); + attr.ID = fileID; + attr.Pos = nodeOffset + offs + 2 + keyLen + kRecordHeaderSize; + attr.Size = dataSize; + LoadName(name, nameLen, attr.Name); + + if (progress && (i & 0xFFF) == 0) + { + UInt64 numFiles = 0; + RINOK(progress->SetCompleted(&numFiles, NULL)); + } + } + + node = desc.fLink; + } + return S_OK; +} + +static const UInt32 kMethod_Attr = 3; // data stored in attribute file +static const UInt32 kMethod_Resource = 4; // data stored in resource fork + +bool CDatabase::Parse_decmpgfs(const CAttr &attr, CItem &item, bool &skip) +{ + skip = false; + if (!attr.Name.IsEqualTo("com.apple.decmpfs")) + return true; + if (item.UseAttr || !item.DataFork.IsEmpty()) + return false; + + const UInt32 k_decmpfs_headerSize = 16; + UInt32 dataSize = attr.Size; + if (dataSize < k_decmpfs_headerSize) + return false; + const Byte *r = AttrBuf + attr.Pos; + if (GetUi32(r) != 0x636D7066) // magic == "fpmc" + return false; + item.Method = GetUi32(r + 4); + item.UnpackSize = GetUi64(r + 8); + dataSize -= k_decmpfs_headerSize; + r += k_decmpfs_headerSize; + if (item.Method == kMethod_Resource) + { + if (dataSize != 0) + return false; + item.UseAttr = true; + } + else if (item.Method == kMethod_Attr) + { + if (dataSize == 0) + return false; + Byte b = r[0]; + if ((b & 0xF) == 0xF) + { + dataSize--; + if (item.UnpackSize > dataSize) + return false; + item.DataPos = attr.Pos + k_decmpfs_headerSize + 1; + item.PackSize = dataSize; + item.UseAttr = true; + item.UseInlineData = true; + } + else + { + item.DataPos = attr.Pos + k_decmpfs_headerSize; + item.PackSize = dataSize; + item.UseAttr = true; + } + } + else + return false; + skip = true; + return true; +} + +HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress) +{ + unsigned reserveSize = (unsigned)(Header.NumFolders + 1 + Header.NumFiles); + Items.ClearAndReserve(reserveSize); + Refs.ClearAndReserve(reserveSize); + + CRecordVector IdToIndexMap; + IdToIndexMap.ClearAndReserve(reserveSize); + + CByteBuffer buf; + RINOK(ReadFile(fork, buf, inStream)); + const Byte *p = (const Byte *)buf; + + // CNodeDescriptor nodeDesc; + // nodeDesc.Parse(p); + CHeaderRec hr; + RINOK(hr.Parse2(buf)); + + // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC); + + CByteBuffer usedBuf(hr.TotalNodes); + 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; + desc.Parse(p + nodeOffset); + if (!desc.CheckNumRecords(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 UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2); + const UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2); + UInt32 recSize = offsNext - offs; + if (offs >= nodeSize + || offsNext > nodeSize + || offsNext < offs + || recSize < 6) + return S_FALSE; + + const Byte *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; + + const unsigned kBasicRecSize = 0x58; + 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++; + const unsigned kForkRecSize = 16 + kNumFixedExtents * 8; + 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) + { + 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]; + + int itemIndex = FindItemIndex(IdToIndexMap, attr.ID); + if (itemIndex < 0) + { + HeadersError = true; + continue; + } + if (!Parse_decmpgfs(attr, 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.UseAttr && item.Method == kMethod_Resource) + continue; + CRef resRef; + resRef.ItemIndex = i; + resRef.IsResource = true; + resRef.Parent = Refs.Size() - 1; + Refs.Add(resRef); + + #endif + } + } + + IdToIndexMap.Sort2(); + + { + FOR_VECTOR (i, Refs) + { + CRef &ref = Refs[i]; + if (ref.IsResource) + continue; + 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]; + + int refIndex = FindItemIndex(IdToIndexMap, attr.ID); + if (refIndex < 0) + { + HeadersError = true; + continue; + } + + CRef ref; + ref.AttrIndex = 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->Seek(SpecOffset, STREAM_SEEK_SET, NULL)); + 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; + if (progress) + { + 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); + */ + + /* + UInt64 endPos; + RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); + if ((endPos >> h.BlockSizeLog) < h.NumBlocks) + return S_FALSE; + */ + + 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 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; +} + + + +class CHandler: + public IInArchive, + public IArchiveGetRawProps, + public IInArchiveGetStream, + public CMyUnknownImp, + public CDatabase +{ + CMyComPtr _stream; + + HRESULT GetForkStream(const CFork &fork, ISequentialInStream **stream); + + HRESULT ExtractZlibFile( + ISequentialOutStream *realOutStream, + const CItem &item, + NCompress::NZlib::CDecoder *_zlibDecoderSpec, + CByteBuffer &buf, + UInt64 progressStart, + IArchiveExtractCallback *extractCallback); +public: + MY_UNKNOWN_IMP3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream) + INTERFACE_IInArchive(;) + INTERFACE_IArchiveGetRawProps(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidCTime, + kpidMTime, + kpidATime, + kpidPosixAttrib +}; + +static const Byte kArcProps[] = +{ + kpidMethod, + kpidClusterSize, + kpidFreeSpace, + kpidCTime, + kpidMTime +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop) +{ + FILETIME ft; + HfsTimeToFileTime(hfsTime, ft); + prop = ft; +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidExtension: prop = Header.IsHfsX() ? "hfsx" : "hfs"; break; + case kpidMethod: prop = Header.IsHfsX() ? "HFSX" : "HFS+"; 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: + { + FILETIME localFt, ft; + HfsTimeToFileTime(Header.CTime, localFt); + if (LocalFileTimeToFileTime(&localFt, &ft)) + prop = ft; + break; + } + case kpidIsTree: prop = true; break; + case kpidErrorFlags: + { + UInt32 flags = 0; + if (HeadersError) flags |= kpv_ErrorFlags_HeadersError; + if (flags != 0) + prop = flags; + break; + } + case kpidIsAltStream: prop = ThereAreAltStreams; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) +{ + *numProps = 0; + return S_OK; +} + +STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) +{ + *name = NULL; + *propID = 0; + return S_OK; +} + +STDMETHODIMP 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; +} + +STDMETHODIMP 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) * sizeof(wchar_t); + *propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE; + return S_OK; + } + #endif + return S_OK; +} + +STDMETHODIMP 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].Size; + else if (item.IsDir()) + break; + else if (item.UseAttr) + { + if (item.Method == kMethod_Resource) + size = item.ResourceFork.NumBlocks << Header.BlockSizeLog; + else + size = item.PackSize; + } + else + size = item.GetFork(ref.IsResource).NumBlocks << Header.BlockSizeLog; + prop = size; + break; + } + case kpidSize: + { + UInt64 size; + if (ref.AttrIndex >= 0) + size = Attrs[ref.AttrIndex].Size; + else if (item.IsDir()) + break; + else if (item.UseAttr) + size = item.UnpackSize; + else + size = item.GetFork(ref.IsResource).Size; + prop = size; + break; + } + case kpidIsDir: prop = 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 kpidPosixAttrib: if (ref.AttrIndex < 0) prop = (UInt32)item.FileMode; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP 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 +} + +STDMETHODIMP CHandler::Close() +{ + _stream.Release(); + Clear(); + return S_OK; +} + +static const UInt32 kCompressionBlockSize = 1 << 16; + +HRESULT CHandler::ExtractZlibFile( + ISequentialOutStream *outStream, + const CItem &item, + NCompress::NZlib::CDecoder *_zlibDecoderSpec, + CByteBuffer &buf, + UInt64 progressStart, + IArchiveExtractCallback *extractCallback) +{ + CMyComPtr inStream; + const CFork &fork = item.ResourceFork; + RINOK(GetForkStream(fork, &inStream)); + const unsigned kHeaderSize = 0x100 + 8; + RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)); + UInt32 dataPos = Get32(buf); + UInt32 mapPos = Get32(buf + 4); + UInt32 dataSize = Get32(buf + 8); + UInt32 mapSize = Get32(buf + 12); + + const UInt32 kResMapSize = 50; + + if (mapSize != kResMapSize + || dataPos + dataSize != mapPos + || mapPos + mapSize != fork.Size) + return S_FALSE; + + UInt32 dataSize2 = Get32(buf + 0x100); + if (4 + dataSize2 != dataSize || dataSize2 < 8) + return S_FALSE; + + UInt32 numBlocks = GetUi32(buf + 0x100 + 4); + if (((dataSize2 - 4) >> 3) < numBlocks) + return S_FALSE; + if (item.UnpackSize > (UInt64)numBlocks * kCompressionBlockSize) + return S_FALSE; + + if (item.UnpackSize + kCompressionBlockSize < (UInt64)numBlocks * kCompressionBlockSize) + return S_FALSE; + + UInt32 tableSize = (numBlocks << 3); + + CByteBuffer tableBuf(tableSize); + + RINOK(ReadStream_FALSE(inStream, tableBuf, tableSize)); + + UInt32 prev = 4 + tableSize; + + UInt32 i; + for (i = 0; i < numBlocks; i++) + { + UInt32 offset = GetUi32(tableBuf + i * 8); + UInt32 size = GetUi32(tableBuf + i * 8 + 4); + if (size == 0) + return S_FALSE; + if (prev != offset) + return S_FALSE; + if (offset > dataSize2 || + size > dataSize2 - offset) + return S_FALSE; + prev = offset + size; + } + + if (prev != dataSize2) + return S_FALSE; + + CBufInStream *bufInStreamSpec = new CBufInStream; + CMyComPtr bufInStream = bufInStreamSpec; + + UInt64 outPos = 0; + for (i = 0; i < numBlocks; i++) + { + UInt64 rem = item.UnpackSize - outPos; + if (rem == 0) + return S_FALSE; + UInt32 blockSize = kCompressionBlockSize; + if (rem < kCompressionBlockSize) + blockSize = (UInt32)rem; + + UInt32 size = GetUi32(tableBuf + i * 8 + 4); + + if (size > buf.Size() || size > kCompressionBlockSize + 1) + return S_FALSE; + + RINOK(ReadStream_FALSE(inStream, buf, size)); + + if ((buf[0] & 0xF) == 0xF) + { + // that code was not tested. Are there HFS archives with uncompressed block + if (size - 1 != blockSize) + return S_FALSE; + + if (outStream) + { + RINOK(WriteStream(outStream, buf, blockSize)); + } + } + else + { + UInt64 blockSize64 = blockSize; + bufInStreamSpec->Init(buf, size); + RINOK(_zlibDecoderSpec->Code(bufInStream, outStream, NULL, &blockSize64, NULL)); + if (_zlibDecoderSpec->GetOutputProcessedSize() != blockSize || + _zlibDecoderSpec->GetInputProcessedSize() != size) + return S_FALSE; + } + + outPos += blockSize; + UInt64 progressPos = progressStart + outPos; + RINOK(extractCallback->SetCompleted(&progressPos)); + } + + if (outPos != item.UnpackSize) + return S_FALSE; + + /* We check Resource Map + Are there HFS files with another values in Resource Map ??? */ + + RINOK(ReadStream_FALSE(inStream, buf, mapSize)); + UInt32 types = Get16(buf + 24); + UInt32 names = Get16(buf + 26); + UInt32 numTypes = Get16(buf + 28); + if (numTypes != 0 || types != 28 || names != kResMapSize) + return S_FALSE; + UInt32 resType = Get32(buf + 30); + UInt32 numResources = Get16(buf + 34); + UInt32 resListOffset = Get16(buf + 36); + if (resType != 0x636D7066) // cmpf + return S_FALSE; + if (numResources != 0 || resListOffset != 10) + return S_FALSE; + + UInt32 entryId = Get16(buf + 38); + UInt32 nameOffset = Get16(buf + 40); + // Byte attrib = buf[42]; + UInt32 resourceOffset = Get32(buf + 42) & 0xFFFFFF; + if (entryId != 1 || nameOffset != 0xFFFF || resourceOffset != 0) + return S_FALSE; + + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + 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 + + NCompress::NZlib::CDecoder *_zlibDecoderSpec = NULL; + CMyComPtr _zlibDecoder; + + for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + { + RINOK(extractCallback->SetCompleted(¤tTotalSize)); + UInt32 index = allFilesMode ? i : indices[i]; + const CRef &ref = Refs[index]; + const CItem &item = Items[ref.ItemIndex]; + currentItemSize = Get_UnpackSize_of_Ref(ref); + + CMyComPtr realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + if (ref.AttrIndex < 0 && item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + UInt64 pos = 0; + int res = NExtract::NOperationResult::kDataError; + if (ref.AttrIndex >= 0) + { + res = NExtract::NOperationResult::kOK; + if (realOutStream) + { + const CAttr &attr = Attrs[ref.AttrIndex]; + RINOK(WriteStream(realOutStream, AttrBuf + attr.Pos, attr.Size)); + } + } + else if (item.UseAttr) + { + if (item.UseInlineData) + { + res = NExtract::NOperationResult::kOK; + if (realOutStream) + { + RINOK(WriteStream(realOutStream, AttrBuf + item.DataPos, (size_t)item.UnpackSize)); + } + } + else + { + if (!_zlibDecoder) + { + _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); + _zlibDecoder = _zlibDecoderSpec; + } + + if (item.Method == kMethod_Attr) + { + CBufInStream *bufInStreamSpec = new CBufInStream; + CMyComPtr bufInStream = bufInStreamSpec; + bufInStreamSpec->Init(AttrBuf + item.DataPos, item.PackSize); + + HRESULT hres = _zlibDecoder->Code(bufInStream, realOutStream, NULL, &item.UnpackSize, NULL); + if (hres != S_FALSE) + { + if (hres != S_OK) + return hres; + if (_zlibDecoderSpec->GetOutputProcessedSize() == item.UnpackSize && + _zlibDecoderSpec->GetInputProcessedSize() == item.PackSize) + res = NExtract::NOperationResult::kOK; + } + } + else + { + HRESULT hres = ExtractZlibFile(realOutStream, item, _zlibDecoderSpec, buf, + currentTotalSize, extractCallback); + if (hres != S_FALSE) + { + if (hres != S_OK) + return hres; + res = NExtract::NOperationResult::kOK; + } + } + } + } + else + { + const CFork &fork = item.GetFork(ref.IsResource); + if (fork.IsOk(Header.BlockSizeLog)) + { + res = NExtract::NOperationResult::kOK; + unsigned extentIndex; + for (extentIndex = 0; extentIndex < fork.Extents.Size(); extentIndex++) + { + if (res != NExtract::NOperationResult::kOK) + break; + if (fork.Size == pos) + break; + const CExtent &e = fork.Extents[extentIndex]; + RINOK(_stream->Seek(SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog), STREAM_SEEK_SET, NULL)); + UInt64 extentRem = (UInt64)e.NumBlocks << Header.BlockSizeLog; + while (extentRem != 0) + { + 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)) + res = 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) + { + res = NExtract::NOperationResult::kDataError; + break; + } + if (realOutStream) + { + RINOK(WriteStream(realOutStream, buf, cur)); + } + pos += cur; + extentRem -= cur; + UInt64 processed = currentTotalSize + pos; + RINOK(extractCallback->SetCompleted(&processed)); + } + } + if (extentIndex != fork.Extents.Size() || fork.Size != pos) + res = NExtract::NOperationResult::kDataError; + } + } + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(res)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = Refs.Size(); + return S_OK; +} + +HRESULT CHandler::GetForkStream(const CFork &fork, ISequentialInStream **stream) +{ + *stream = 0; + + if (!fork.IsOk(Header.BlockSizeLog)) + return S_FALSE; + + CExtentsStream *extentStreamSpec = new CExtentsStream(); + CMyComPtr 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; +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + *stream = 0; + + const CRef &ref = Refs[index]; + if (ref.AttrIndex >= 0) + return S_FALSE; + const CItem &item = Items[ref.ItemIndex]; + if (item.IsDir() || item.UseAttr) + return S_FALSE; + + return GetForkStream(item.GetFork(ref.IsResource), stream); +} + +static const Byte k_Signature[] = { + 2, 'B', 'D', + 4, 'H', '+', 0, 4, + 4, 'H', 'X', 0, 5 }; + +REGISTER_ARC_I( + "HFS", "hfs hfsx", 0, 0xE3, + k_Signature, + kHeaderPadSize, + NArcInfoFlags::kMultiSignature, + IsArc_HFS) + +}} diff --git a/CPP/7zip/Archive/IArchive.h b/CPP/7zip/Archive/IArchive.h index 0c35349a6..d85bb2170 100644 --- a/CPP/7zip/Archive/IArchive.h +++ b/CPP/7zip/Archive/IArchive.h @@ -1,608 +1,608 @@ -// 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, lz, 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 __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, lz, 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 diff --git a/CPP/7zip/Archive/IhexHandler.cpp b/CPP/7zip/Archive/IhexHandler.cpp index a30680eb5..00ff80a77 100644 --- a/CPP/7zip/Archive/IhexHandler.cpp +++ b/CPP/7zip/Archive/IhexHandler.cpp @@ -1,497 +1,497 @@ -// 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; -}; - -class CHandler: - public IInArchive, - public CMyUnknownImp -{ - bool _isArc; - bool _needMoreInput; - bool _dataError; - - UInt64 _phySize; - - CObjectVector _blocks; -public: - MY_UNKNOWN_IMP1(IInArchive) - INTERFACE_IInArchive(;) -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidVa -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _blocks.Size(); - return S_OK; -} - -STDMETHODIMP 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; -} - -STDMETHODIMP 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 c - '0'; - if (c >= 'A' && c <= 'F') return c - 'A' + 10; - if (c >= 'a' && c <= 'f') return c - 'a' + 10; - return -1; -} - -static int Parse(const Byte *p) -{ - int c1 = HexToByte(p[0]); if (c1 < 0) return -1; - 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; - char b = *p++; - size--; - if (IS_LINE_DELIMITER(b)) - continue; - if (b == ':') - break; - return k_IsArc_Res_NO; - } - } - - return k_IsArc_Res_YES; -} -} - -STDMETHODIMP 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(stream->Seek(0, STREAM_SEEK_SET, NULL)); - 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; - } - 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 = num; - for (size_t i = 0; i < numPairs; i++) - { - int a = Parse(temp + i * 2); - if (a < 0) - { - _dataError = true; - return S_FALSE; - } - temp[i] = (Byte)a; - sum += 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 -} - -STDMETHODIMP CHandler::Close() -{ - _phySize = 0; - - _isArc = false; - _needMoreInput = false; - _dataError = false; - - _blocks.Clear(); - return S_OK; -} - - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - 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 progress = lps; - lps->Init(extractCallback, false); - - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) - { - currentItemSize = 0; - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()); - - UInt32 index = allFilesMode ? i : indices[i]; - const CByteDynamicBuffer &data = _blocks[index].Data; - currentItemSize = data.GetPos(); - - CMyComPtr realOutStream; - 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", 0, 0xCD, - 0, - NArcInfoFlags::kStartOpen, - IsArc_Ihex) - -}} +// 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; +}; + +class CHandler: + public IInArchive, + public CMyUnknownImp +{ + bool _isArc; + bool _needMoreInput; + bool _dataError; + + UInt64 _phySize; + + CObjectVector _blocks; +public: + MY_UNKNOWN_IMP1(IInArchive) + INTERFACE_IInArchive(;) +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidVa +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _blocks.Size(); + return S_OK; +} + +STDMETHODIMP 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; +} + +STDMETHODIMP 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 c - '0'; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + return -1; +} + +static int Parse(const Byte *p) +{ + int c1 = HexToByte(p[0]); if (c1 < 0) return -1; + 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; + char b = *p++; + size--; + if (IS_LINE_DELIMITER(b)) + continue; + if (b == ':') + break; + return k_IsArc_Res_NO; + } + } + + return k_IsArc_Res_YES; +} +} + +STDMETHODIMP 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(stream->Seek(0, STREAM_SEEK_SET, NULL)); + 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; + } + 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 = num; + for (size_t i = 0; i < numPairs; i++) + { + int a = Parse(temp + i * 2); + if (a < 0) + { + _dataError = true; + return S_FALSE; + } + temp[i] = (Byte)a; + sum += 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 +} + +STDMETHODIMP CHandler::Close() +{ + _phySize = 0; + + _isArc = false; + _needMoreInput = false; + _dataError = false; + + _blocks.Clear(); + return S_OK; +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + 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 progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + { + currentItemSize = 0; + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + + UInt32 index = allFilesMode ? i : indices[i]; + const CByteDynamicBuffer &data = _blocks[index].Data; + currentItemSize = data.GetPos(); + + CMyComPtr realOutStream; + 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", 0, 0xCD, + 0, + NArcInfoFlags::kStartOpen, + IsArc_Ihex) + +}} diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp index 8365e1a09..2230cd23b 100644 --- a/CPP/7zip/Archive/Iso/IsoHandler.cpp +++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp @@ -1,489 +1,489 @@ -// IsoHandler.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/TimeUtils.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/ProgressUtils.h" - -#include "../../Compress/CopyCoder.h" - -#include "../Common/ItemNameUtils.h" - -#include "IsoHandler.h" - -using namespace NWindows; -using namespace NTime; - -namespace NArchive { -namespace NIso { - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - // kpidCTime, - // kpidATime, - kpidPosixAttrib, - // kpidUser, - // kpidGroup, - // kpidLinks, - kpidSymLink -}; - -static const Byte kArcProps[] = -{ - kpidComment, - kpidCTime, - kpidMTime, - // kpidHeadersSize -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP 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 -} - -STDMETHODIMP CHandler::Close() -{ - _archive.Clear(); - _stream.Release(); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _archive.Refs.Size() + _archive.BootEntries.Size(); - return S_OK; -} - -static void AddString(AString &s, const char *name, const Byte *p, 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; -} - -STDMETHODIMP 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: { FILETIME utc; if (vol.CTime.GetFileTime(utc)) prop = utc; break; } - case kpidMTime: { FILETIME utc; if (vol.MTime.GetFileTime(utc)) prop = utc; 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 -} - -STDMETHODIMP 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 += '-'; - } - 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) - { - UString s; - UInt32 mode; - if (item.GetPx(_archive.SuspSkipSize, k_Px_Mode, mode)) - { - if (((mode >> 12) & 0xF) == 10) - { - AString s8; - if (item.GetSymLink(_archive.SuspSkipSize, s8)) - { - s = MultiByteToUnicodeString(s8, CP_OEMCP); - prop = s; - } - } - } - } - break; - - - case kpidPosixAttrib: - /* - case kpidLinks: - case kpidUser: - case kpidGroup: - */ - { - if (_archive.IsSusp) - { - UInt32 t = 0; - switch (propID) - { - case kpidPosixAttrib: t = k_Px_Mode; break; - /* - case kpidLinks: t = k_Px_Links; break; - case kpidUser: t = k_Px_User; break; - case kpidGroup: 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: - { - FILETIME utc; - if (/* propID == kpidMTime && */ item.DateTime.GetFileTime(utc)) - prop = utc; - /* - 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 -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - 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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_stream); - - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()); - currentItemSize = 0; - CMyComPtr realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - UInt32 index = allFilesMode ? i : indices[i]; - - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - - UInt64 blockIndex; - if (index < (UInt32)_archive.Refs.Size()) - { - const CRef &ref = _archive.Refs[index]; - const CDir &item = ref.Dir->_subItems[ref.Index]; - if (item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - currentItemSize = 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(_stream->Seek((UInt64)item2.ExtentLocation * kBlockSize, STREAM_SEEK_SET, NULL)); - 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(_stream->Seek((UInt64)blockIndex * kBlockSize, STREAM_SEEK_SET, NULL)); - 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 -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - *stream = 0; - 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 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 -} - -}} +// IsoHandler.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" + +#include "../../Compress/CopyCoder.h" + +#include "../Common/ItemNameUtils.h" + +#include "IsoHandler.h" + +using namespace NWindows; +using namespace NTime; + +namespace NArchive { +namespace NIso { + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + // kpidCTime, + // kpidATime, + kpidPosixAttrib, + // kpidUser, + // kpidGroup, + // kpidLinks, + kpidSymLink +}; + +static const Byte kArcProps[] = +{ + kpidComment, + kpidCTime, + kpidMTime, + // kpidHeadersSize +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP 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 +} + +STDMETHODIMP CHandler::Close() +{ + _archive.Clear(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _archive.Refs.Size() + _archive.BootEntries.Size(); + return S_OK; +} + +static void AddString(AString &s, const char *name, const Byte *p, 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; +} + +STDMETHODIMP 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: { FILETIME utc; if (vol.CTime.GetFileTime(utc)) prop = utc; break; } + case kpidMTime: { FILETIME utc; if (vol.MTime.GetFileTime(utc)) prop = utc; 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 +} + +STDMETHODIMP 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 += '-'; + } + 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) + { + UString s; + UInt32 mode; + if (item.GetPx(_archive.SuspSkipSize, k_Px_Mode, mode)) + { + if (((mode >> 12) & 0xF) == 10) + { + AString s8; + if (item.GetSymLink(_archive.SuspSkipSize, s8)) + { + s = MultiByteToUnicodeString(s8, CP_OEMCP); + prop = s; + } + } + } + } + break; + + + case kpidPosixAttrib: + /* + case kpidLinks: + case kpidUser: + case kpidGroup: + */ + { + if (_archive.IsSusp) + { + UInt32 t = 0; + switch (propID) + { + case kpidPosixAttrib: t = k_Px_Mode; break; + /* + case kpidLinks: t = k_Px_Links; break; + case kpidUser: t = k_Px_User; break; + case kpidGroup: 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: + { + FILETIME utc; + if (/* propID == kpidMTime && */ item.DateTime.GetFileTime(utc)) + prop = utc; + /* + 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 +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + 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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(_stream); + + for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + currentItemSize = 0; + CMyComPtr realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + UInt64 blockIndex; + if (index < (UInt32)_archive.Refs.Size()) + { + const CRef &ref = _archive.Refs[index]; + const CDir &item = ref.Dir->_subItems[ref.Index]; + if (item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + currentItemSize = 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(_stream->Seek((UInt64)item2.ExtentLocation * kBlockSize, STREAM_SEEK_SET, NULL)); + 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(_stream->Seek((UInt64)blockIndex * kBlockSize, STREAM_SEEK_SET, NULL)); + 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 +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = 0; + 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 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 index f322d64f5..1923784d9 100644 --- a/CPP/7zip/Archive/Iso/IsoHandler.h +++ b/CPP/7zip/Archive/Iso/IsoHandler.h @@ -1,31 +1,31 @@ -// IsoHandler.h - -#ifndef __ISO_HANDLER_H -#define __ISO_HANDLER_H - -#include "../../../Common/MyCom.h" - -#include "../IArchive.h" - -#include "IsoIn.h" -#include "IsoItem.h" - -namespace NArchive { -namespace NIso { - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - CMyComPtr _stream; - CInArchive _archive; -public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); -}; - -}} - -#endif +// IsoHandler.h + +#ifndef __ISO_HANDLER_H +#define __ISO_HANDLER_H + +#include "../../../Common/MyCom.h" + +#include "../IArchive.h" + +#include "IsoIn.h" +#include "IsoItem.h" + +namespace NArchive { +namespace NIso { + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CMyComPtr _stream; + CInArchive _archive; +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Iso/IsoHeader.cpp b/CPP/7zip/Archive/Iso/IsoHeader.cpp index f3baf3700..3b59060a1 100644 --- a/CPP/7zip/Archive/Iso/IsoHeader.cpp +++ b/CPP/7zip/Archive/Iso/IsoHeader.cpp @@ -1,12 +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"; - -}} +// 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 index 7ab507361..e6a4d3272 100644 --- a/CPP/7zip/Archive/Iso/IsoHeader.h +++ b/CPP/7zip/Archive/Iso/IsoHeader.h @@ -1,64 +1,64 @@ -// Archive/IsoHeader.h - -#ifndef __ARCHIVE_ISO_HEADER_H -#define __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 +// Archive/IsoHeader.h + +#ifndef __ARCHIVE_ISO_HEADER_H +#define __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 index 699c7a1a8..b0bfb1643 100644 --- a/CPP/7zip/Archive/Iso/IsoIn.cpp +++ b/CPP/7zip/Archive/Iso/IsoIn.cpp @@ -1,669 +1,669 @@ -// 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 += '-'; - - if (BootMediaType < 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 += '-'; - for (i = 1; i < sizeof(VendorSpec); i++) - { - char c = 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 |= ((UInt16)(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) -{ - HRESULT res = _stream->Seek((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(_stream->Seek(0, STREAM_SEEK_END, &_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 = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--) - if (VolDescs[MainVolDescIndex].IsJoliet()) - break; - // MainVolDescIndex = 0; // to read primary volume - const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex]; - if (vd.LogicalBlockSize != kBlockSize) - return S_FALSE; - - 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(_stream->Seek(PhySize, STREAM_SEEK_SET, NULL)); - 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; -} - -}} +// 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 += '-'; + + if (BootMediaType < 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 += '-'; + for (i = 1; i < sizeof(VendorSpec); i++) + { + char c = 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 |= ((UInt16)(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) +{ + HRESULT res = _stream->Seek((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(_stream->Seek(0, STREAM_SEEK_END, &_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 = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--) + if (VolDescs[MainVolDescIndex].IsJoliet()) + break; + // MainVolDescIndex = 0; // to read primary volume + const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex]; + if (vd.LogicalBlockSize != kBlockSize) + return S_FALSE; + + 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(_stream->Seek(PhySize, STREAM_SEEK_SET, NULL)); + 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; +} + +}} diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h index 0081674ef..347f9e9b7 100644 --- a/CPP/7zip/Archive/Iso/IsoIn.h +++ b/CPP/7zip/Archive/Iso/IsoIn.h @@ -1,332 +1,332 @@ -// Archive/IsoIn.h - -#ifndef __ARCHIVE_ISO_IN_H -#define __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 _subItems; - - void Clear() - { - Parent = 0; - _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(FILETIME &ft) const - { - UInt64 value; - bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, value); - if (res) - { - value -= (Int64)((Int32)GmtOffset * 15 * 60); - value *= 10000000; - } - ft.dwLowDateTime = (DWORD)value; - ft.dwHighDateTime = (DWORD)(value >> 32); - return res; - } -}; - -struct CBootRecordDescriptor -{ - Byte BootSystemId[32]; // a-characters - Byte BootId[32]; // a-characters - Byte BootSystemUse[1977]; -}; - -struct CBootValidationEntry -{ - Byte PlatformId; - Byte Id[24]; // to identify the manufacturer/developer of the CD-ROM. -}; - -struct CBootInitialEntry -{ - bool Bootable; - Byte BootMediaType; - UInt16 LoadSegment; - /* This is the load segment for the initial boot image. If this - value is 0 the system will use the traditional segment of 7C0. If this value - is non-zero the system will use the specified segment. This applies to x86 - architectures only. For "flat" model architectures (such as Motorola) this - is the address divided by 10. */ - Byte SystemType; // This must be a copy of byte 5 (System Type) from the - // Partition Table found in the boot image. - UInt16 SectorCount; // This is the number of virtual/emulated sectors the system - // will store at Load Segment during the initial boot procedure. - UInt32 LoadRBA; // This is the start address of the virtual disk. 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; - - CDir _rootDir; - bool _bootIsDefined; - CBootRecordDescriptor _bootDesc; - - void Skip(size_t size); - void SkipZeros(size_t size); - Byte ReadByte(); - void ReadBytes(Byte *data, UInt32 size); - UInt16 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 Refs; - CObjectVector VolDescs; - int MainVolDescIndex; - // UInt32 BlockSize; - CObjectVector BootEntries; - - bool IsArc; - bool UnexpectedEnd; - bool HeadersError; - bool IncorrectBigEndian; - bool TooDeepDirs; - bool SelfLinkedDirs; - CRecordVector UniqStartLocations; - - Byte m_Buffer[kBlockSize]; - - void UpdatePhySize(UInt32 blockIndex, 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(int index) const - { - const CBootInitialEntry &be = BootEntries[index]; - UInt64 size = be.GetSize(); - if (be.BootMediaType == NBootMediaType::k1d2Floppy) - size = (1200 << 10); - else if (be.BootMediaType == NBootMediaType::k1d44Floppy) - size = (1440 << 10); - else if (be.BootMediaType == NBootMediaType::k2d88Floppy) - size = (2880 << 10); - UInt64 startPos = (UInt64)be.LoadRBA * kBlockSize; - if (startPos < _fileSize) - { - if (_fileSize - startPos < size) - size = _fileSize - startPos; - } - return size; - } - - bool IsSusp; - unsigned SuspSkipSize; -}; - -}} - -#endif +// Archive/IsoIn.h + +#ifndef __ARCHIVE_ISO_IN_H +#define __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 _subItems; + + void Clear() + { + Parent = 0; + _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(FILETIME &ft) const + { + UInt64 value; + bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, value); + if (res) + { + value -= (Int64)((Int32)GmtOffset * 15 * 60); + value *= 10000000; + } + ft.dwLowDateTime = (DWORD)value; + ft.dwHighDateTime = (DWORD)(value >> 32); + return res; + } +}; + +struct CBootRecordDescriptor +{ + Byte BootSystemId[32]; // a-characters + Byte BootId[32]; // a-characters + Byte BootSystemUse[1977]; +}; + +struct CBootValidationEntry +{ + Byte PlatformId; + Byte Id[24]; // to identify the manufacturer/developer of the CD-ROM. +}; + +struct CBootInitialEntry +{ + bool Bootable; + Byte BootMediaType; + UInt16 LoadSegment; + /* This is the load segment for the initial boot image. If this + value is 0 the system will use the traditional segment of 7C0. If this value + is non-zero the system will use the specified segment. This applies to x86 + architectures only. For "flat" model architectures (such as Motorola) this + is the address divided by 10. */ + Byte SystemType; // This must be a copy of byte 5 (System Type) from the + // Partition Table found in the boot image. + UInt16 SectorCount; // This is the number of virtual/emulated sectors the system + // will store at Load Segment during the initial boot procedure. + UInt32 LoadRBA; // This is the start address of the virtual disk. 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; + + CDir _rootDir; + bool _bootIsDefined; + CBootRecordDescriptor _bootDesc; + + void Skip(size_t size); + void SkipZeros(size_t size); + Byte ReadByte(); + void ReadBytes(Byte *data, UInt32 size); + UInt16 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 Refs; + CObjectVector VolDescs; + int MainVolDescIndex; + // UInt32 BlockSize; + CObjectVector BootEntries; + + bool IsArc; + bool UnexpectedEnd; + bool HeadersError; + bool IncorrectBigEndian; + bool TooDeepDirs; + bool SelfLinkedDirs; + CRecordVector UniqStartLocations; + + Byte m_Buffer[kBlockSize]; + + void UpdatePhySize(UInt32 blockIndex, 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(int index) const + { + const CBootInitialEntry &be = BootEntries[index]; + UInt64 size = be.GetSize(); + if (be.BootMediaType == NBootMediaType::k1d2Floppy) + size = (1200 << 10); + else if (be.BootMediaType == NBootMediaType::k1d44Floppy) + size = (1440 << 10); + else if (be.BootMediaType == NBootMediaType::k2d88Floppy) + size = (2880 << 10); + UInt64 startPos = (UInt64)be.LoadRBA * kBlockSize; + if (startPos < _fileSize) + { + if (_fileSize - startPos < size) + size = _fileSize - startPos; + } + return size; + } + + bool IsSusp; + unsigned SuspSkipSize; +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Iso/IsoItem.h b/CPP/7zip/Archive/Iso/IsoItem.h index c435bc803..5ae13a60c 100644 --- a/CPP/7zip/Archive/Iso/IsoItem.h +++ b/CPP/7zip/Archive/Iso/IsoItem.h @@ -1,321 +1,321 @@ -// Archive/IsoItem.h - -#ifndef __ARCHIVE_ISO_ITEM_H -#define __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(FILETIME &ft) const - { - UInt64 value; - bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, value); - if (res) - { - value -= (Int64)((Int32)GmtOffset * 15 * 60); - value *= 10000000; - } - ft.dwLowDateTime = (DWORD)value; - ft.dwHighDateTime = (DWORD)(value >> 32); - 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 0; - 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 0; - if (p[0] == id0 && p[1] == id1 && p[3] == 1) - { - if (len < 4) - return 0; // Check it - lenRes = len - 4; - return p + 4; - } - p += len; - rem -= len; - } - return 0; - } - - - const Byte* GetNameCur(bool checkSusp, int 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; - } - - - const bool GetSymLink(int 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++) - { - char c = p[i]; - if (c == 0) - { - break; - // return false; - } - link += c; - } - - p += cl; - len -= cl; - - if (len == 0) - break; - - if (needSlash) - link += '/'; - } - - return true; - } - - static const 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; - } - - - const bool GetPx(int 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 < ((unsigned)pxType + 1) * 8) - return false; - - return GetLe32Be32(p + pxType * 8, val); - } - - /* - const 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; - unsigned len = (int)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 +// Archive/IsoItem.h + +#ifndef __ARCHIVE_ISO_ITEM_H +#define __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(FILETIME &ft) const + { + UInt64 value; + bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, value); + if (res) + { + value -= (Int64)((Int32)GmtOffset * 15 * 60); + value *= 10000000; + } + ft.dwLowDateTime = (DWORD)value; + ft.dwHighDateTime = (DWORD)(value >> 32); + 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 0; + 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 0; + if (p[0] == id0 && p[1] == id1 && p[3] == 1) + { + if (len < 4) + return 0; // Check it + lenRes = len - 4; + return p + 4; + } + p += len; + rem -= len; + } + return 0; + } + + + const Byte* GetNameCur(bool checkSusp, int 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; + } + + + const bool GetSymLink(int 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++) + { + char c = p[i]; + if (c == 0) + { + break; + // return false; + } + link += c; + } + + p += cl; + len -= cl; + + if (len == 0) + break; + + if (needSlash) + link += '/'; + } + + return true; + } + + static const 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; + } + + + const bool GetPx(int 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 < ((unsigned)pxType + 1) * 8) + return false; + + return GetLe32Be32(p + pxType * 8, val); + } + + /* + const 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; + unsigned len = (int)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 index 4aa2cc90e..0205238d2 100644 --- a/CPP/7zip/Archive/Iso/IsoRegister.cpp +++ b/CPP/7zip/Archive/Iso/IsoRegister.cpp @@ -1,21 +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", 0, 0xE7, - k_Signature, - NArchive::NIso::kStartPos + 1, - 0, - NULL) - -}} +// 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", 0, 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 index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Archive/Iso/StdAfx.h +++ b/CPP/7zip/Archive/Iso/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/LizardHandler.cpp b/CPP/7zip/Archive/LizardHandler.cpp index 3ffa01796..707960f37 100644 --- a/CPP/7zip/Archive/LizardHandler.cpp +++ b/CPP/7zip/Archive/LizardHandler.cpp @@ -1,366 +1,366 @@ -// LizardHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" -#include "../../Common/ComTry.h" -#include "../../Common/Defs.h" - -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/LizardDecoder.h" -#include "../Compress/LizardEncoder.h" -#include "../Compress/CopyCoder.h" - -#include "Common/DummyOutStream.h" -#include "Common/HandlerOut.h" - -using namespace NWindows; - -namespace NArchive { -namespace NLIZARD { - -class CHandler: - public IInArchive, - public IArchiveOpenSeq, - public IOutArchive, - public ISetProperties, - public CMyUnknownImp -{ - CMyComPtr _stream; - CMyComPtr _seqStream; - - bool _isArc; - bool _dataAfterEnd; - bool _needMoreInput; - - bool _packSize_Defined; - bool _unpackSize_Defined; - - UInt64 _packSize; - UInt64 _unpackSize; - UInt64 _numStreams; - UInt64 _numBlocks; - - CSingleMethodProps _props; - -public: - MY_UNKNOWN_IMP4( - IInArchive, - IArchiveOpenSeq, - IOutArchive, - ISetProperties) - INTERFACE_IInArchive(;) - INTERFACE_IOutArchive(;) - STDMETHOD(OpenSeq)(ISequentialInStream *stream); - STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); - - CHandler() { } -}; - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize -}; - -static const Byte kArcProps[] = -{ - kpidNumStreams, - kpidNumBlocks -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID /*propID*/, PROPVARIANT * /*value*/) -{ - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = 1; - return S_OK; -} - -STDMETHODIMP 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 = 4; - -API_FUNC_static_IsArc IsArc_lizard(const Byte *p, size_t size) -{ - if (size < 4) - return k_IsArc_Res_NEED_MORE; - - UInt32 magic = GetUi32(p); - - // skippable frames - if (magic >= 0x184D2A50 && magic <= 0x184D2A5F) { - if (size < 16) - return k_IsArc_Res_NEED_MORE; - magic = GetUi32(p+12); - } - - // Lizard Magic - if (magic == 0x184D2206) - return k_IsArc_Res_YES; - - return k_IsArc_Res_NO; -} -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) -{ - COM_TRY_BEGIN - Close(); - { - Byte buf[kSignatureCheckSize]; - RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize)); - if (IsArc_lizard(buf, kSignatureCheckSize) == k_IsArc_Res_NO) - return S_FALSE; - _isArc = true; - _stream = stream; - _seqStream = stream; - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) -{ - Close(); - _isArc = true; - _seqStream = stream; - return S_OK; -} - -STDMETHODIMP CHandler::Close() -{ - _isArc = false; - _dataAfterEnd = false; - _needMoreInput = false; - - _packSize_Defined = false; - _unpackSize_Defined = false; - - _packSize = 0; - - _seqStream.Release(); - _stream.Release(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - if (_packSize_Defined) - extractCallback->SetTotal(_packSize); - - CMyComPtr 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); - - Int32 opRes; - - { - - NCompress::NLIZARD::CDecoder *decoderSpec = new NCompress::NLIZARD::CDecoder; - CMyComPtr decoder = decoderSpec; - decoderSpec->SetInStream(_seqStream); - - CDummyOutStream *outStreamSpec = new CDummyOutStream; - CMyComPtr outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(); - - realOutStream.Release(); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, true); - - UInt64 packSize = 0; - UInt64 unpackedSize = 0; - - HRESULT result = S_OK; - - for (;;) - { - lps->InSize = packSize; - lps->OutSize = unpackedSize; - - RINOK(lps->SetCur()); - result = decoderSpec->CodeResume(outStream, &unpackedSize, progress); - UInt64 streamSize = decoderSpec->GetInputProcessedSize(); - - if (result != S_FALSE && result != S_OK) - return result; - - if (unpackedSize == 0) - break; - - if (streamSize == packSize) - { - // no new bytes in input stream, So it's good end of archive. - result = S_OK; - break; - } - - if (packSize > streamSize) - return E_FAIL; - - if (result != S_OK) - break; - } - - decoderSpec->ReleaseInStream(); - outStream.Release(); - - if (!_isArc) - opRes = NExtract::NOperationResult::kIsNotArc; - else if (_needMoreInput) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - else if (_dataAfterEnd) - opRes = NExtract::NOperationResult::kDataAfterEnd; - else if (result == S_FALSE) - opRes = NExtract::NOperationResult::kDataError; - else if (result == S_OK) - opRes = NExtract::NOperationResult::kOK; - else - return result; - - } - - return extractCallback->SetOperationResult(opRes); - - COM_TRY_END -} - -static HRESULT UpdateArchive( - UInt64 unpackSize, - ISequentialOutStream *outStream, - const CProps &props, - IArchiveUpdateCallback *updateCallback) -{ - RINOK(updateCallback->SetTotal(unpackSize)); - CMyComPtr fileInStream; - RINOK(updateCallback->GetStream(0, &fileInStream)); - CLocalProgress *localProgressSpec = new CLocalProgress; - CMyComPtr localProgress = localProgressSpec; - localProgressSpec->Init(updateCallback, true); - NCompress::NLIZARD::CEncoder *encoderSpec = new NCompress::NLIZARD::CEncoder; - CMyComPtr encoder = encoderSpec; - RINOK(props.SetCoderProps(encoderSpec, NULL)); - RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); - return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); -} - -STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) -{ - *type = NFileTimeType::kUnix; - return S_OK; -} - -STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *updateCallback) -{ - COM_TRY_BEGIN - - if (numItems != 1) - return E_INVALIDARG; - - Int32 newData, newProps; - UInt32 indexInArchive; - if (!updateCallback) - return E_FAIL; - RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); - - if ((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 ((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(size, outStream, _props, updateCallback); - } - - if (indexInArchive != 0) - return E_INVALIDARG; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(updateCallback, true); - - CMyComPtr opCallback; - updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kInArcIndex, 0, - NUpdateNotifyOp::kReplicate)) - } - - if (_stream) - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - - return NCompress::CopyStream(_stream, outStream, progress); - - COM_TRY_END -} - -STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) -{ - return _props.SetProperties(names, values, numProps); -} - -static const Byte k_Signature[] = "0x184D2206"; - -REGISTER_ARC_IO( - "lizard", "liz tliz", "* .tar", 0x11, - k_Signature, - 0, - NArcInfoFlags::kKeepName, - IsArc_lizard) - -}} +// LizardHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" +#include "../../Common/ComTry.h" +#include "../../Common/Defs.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/LizardDecoder.h" +#include "../Compress/LizardEncoder.h" +#include "../Compress/CopyCoder.h" + +#include "Common/DummyOutStream.h" +#include "Common/HandlerOut.h" + +using namespace NWindows; + +namespace NArchive { +namespace NLIZARD { + +class CHandler: + public IInArchive, + public IArchiveOpenSeq, + public IOutArchive, + public ISetProperties, + public CMyUnknownImp +{ + CMyComPtr _stream; + CMyComPtr _seqStream; + + bool _isArc; + bool _dataAfterEnd; + bool _needMoreInput; + + bool _packSize_Defined; + bool _unpackSize_Defined; + + UInt64 _packSize; + UInt64 _unpackSize; + UInt64 _numStreams; + UInt64 _numBlocks; + + CSingleMethodProps _props; + +public: + MY_UNKNOWN_IMP4( + IInArchive, + IArchiveOpenSeq, + IOutArchive, + ISetProperties) + INTERFACE_IInArchive(;) + INTERFACE_IOutArchive(;) + STDMETHOD(OpenSeq)(ISequentialInStream *stream); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); + + CHandler() { } +}; + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidNumStreams, + kpidNumBlocks +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID /*propID*/, PROPVARIANT * /*value*/) +{ + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1; + return S_OK; +} + +STDMETHODIMP 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 = 4; + +API_FUNC_static_IsArc IsArc_lizard(const Byte *p, size_t size) +{ + if (size < 4) + return k_IsArc_Res_NEED_MORE; + + UInt32 magic = GetUi32(p); + + // skippable frames + if (magic >= 0x184D2A50 && magic <= 0x184D2A5F) { + if (size < 16) + return k_IsArc_Res_NEED_MORE; + magic = GetUi32(p+12); + } + + // Lizard Magic + if (magic == 0x184D2206) + return k_IsArc_Res_YES; + + return k_IsArc_Res_NO; +} +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) +{ + COM_TRY_BEGIN + Close(); + { + Byte buf[kSignatureCheckSize]; + RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize)); + if (IsArc_lizard(buf, kSignatureCheckSize) == k_IsArc_Res_NO) + return S_FALSE; + _isArc = true; + _stream = stream; + _seqStream = stream; + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) +{ + Close(); + _isArc = true; + _seqStream = stream; + return S_OK; +} + +STDMETHODIMP CHandler::Close() +{ + _isArc = false; + _dataAfterEnd = false; + _needMoreInput = false; + + _packSize_Defined = false; + _unpackSize_Defined = false; + + _packSize = 0; + + _seqStream.Release(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + if (_packSize_Defined) + extractCallback->SetTotal(_packSize); + + CMyComPtr 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); + + Int32 opRes; + + { + + NCompress::NLIZARD::CDecoder *decoderSpec = new NCompress::NLIZARD::CDecoder; + CMyComPtr decoder = decoderSpec; + decoderSpec->SetInStream(_seqStream); + + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + + realOutStream.Release(); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, true); + + UInt64 packSize = 0; + UInt64 unpackedSize = 0; + + HRESULT result = S_OK; + + for (;;) + { + lps->InSize = packSize; + lps->OutSize = unpackedSize; + + RINOK(lps->SetCur()); + result = decoderSpec->CodeResume(outStream, &unpackedSize, progress); + UInt64 streamSize = decoderSpec->GetInputProcessedSize(); + + if (result != S_FALSE && result != S_OK) + return result; + + if (unpackedSize == 0) + break; + + if (streamSize == packSize) + { + // no new bytes in input stream, So it's good end of archive. + result = S_OK; + break; + } + + if (packSize > streamSize) + return E_FAIL; + + if (result != S_OK) + break; + } + + decoderSpec->ReleaseInStream(); + outStream.Release(); + + if (!_isArc) + opRes = NExtract::NOperationResult::kIsNotArc; + else if (_needMoreInput) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + else if (_dataAfterEnd) + opRes = NExtract::NOperationResult::kDataAfterEnd; + else if (result == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else if (result == S_OK) + opRes = NExtract::NOperationResult::kOK; + else + return result; + + } + + return extractCallback->SetOperationResult(opRes); + + COM_TRY_END +} + +static HRESULT UpdateArchive( + UInt64 unpackSize, + ISequentialOutStream *outStream, + const CProps &props, + IArchiveUpdateCallback *updateCallback) +{ + RINOK(updateCallback->SetTotal(unpackSize)); + CMyComPtr fileInStream; + RINOK(updateCallback->GetStream(0, &fileInStream)); + CLocalProgress *localProgressSpec = new CLocalProgress; + CMyComPtr localProgress = localProgressSpec; + localProgressSpec->Init(updateCallback, true); + NCompress::NLIZARD::CEncoder *encoderSpec = new NCompress::NLIZARD::CEncoder; + CMyComPtr encoder = encoderSpec; + RINOK(props.SetCoderProps(encoderSpec, NULL)); + RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); + return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); +} + +STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) +{ + *type = NFileTimeType::kUnix; + return S_OK; +} + +STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback) +{ + COM_TRY_BEGIN + + if (numItems != 1) + return E_INVALIDARG; + + Int32 newData, newProps; + UInt32 indexInArchive; + if (!updateCallback) + return E_FAIL; + RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); + + if ((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 ((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(size, outStream, _props, updateCallback); + } + + if (indexInArchive != 0) + return E_INVALIDARG; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(updateCallback, true); + + CMyComPtr opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, 0, + NUpdateNotifyOp::kReplicate)) + } + + if (_stream) + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); + + return NCompress::CopyStream(_stream, outStream, progress); + + COM_TRY_END +} + +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) +{ + return _props.SetProperties(names, values, numProps); +} + +static const Byte k_Signature[] = "0x184D2206"; + +REGISTER_ARC_IO( + "lizard", "liz tliz", "* .tar", 0x11, + k_Signature, + 0, + NArcInfoFlags::kKeepName, + IsArc_lizard) + +}} diff --git a/CPP/7zip/Archive/Lz4Handler.cpp b/CPP/7zip/Archive/Lz4Handler.cpp index 1c71867aa..907dfd524 100644 --- a/CPP/7zip/Archive/Lz4Handler.cpp +++ b/CPP/7zip/Archive/Lz4Handler.cpp @@ -1,366 +1,366 @@ -// Lz4Handler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" -#include "../../Common/ComTry.h" -#include "../../Common/Defs.h" - -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/Lz4Decoder.h" -#include "../Compress/Lz4Encoder.h" -#include "../Compress/CopyCoder.h" - -#include "Common/DummyOutStream.h" -#include "Common/HandlerOut.h" - -using namespace NWindows; - -namespace NArchive { -namespace NLZ4 { - -class CHandler: - public IInArchive, - public IArchiveOpenSeq, - public IOutArchive, - public ISetProperties, - public CMyUnknownImp -{ - CMyComPtr _stream; - CMyComPtr _seqStream; - - bool _isArc; - bool _dataAfterEnd; - bool _needMoreInput; - - bool _packSize_Defined; - bool _unpackSize_Defined; - - UInt64 _packSize; - UInt64 _unpackSize; - UInt64 _numStreams; - UInt64 _numBlocks; - - CSingleMethodProps _props; - -public: - MY_UNKNOWN_IMP4( - IInArchive, - IArchiveOpenSeq, - IOutArchive, - ISetProperties) - INTERFACE_IInArchive(;) - INTERFACE_IOutArchive(;) - STDMETHOD(OpenSeq)(ISequentialInStream *stream); - STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); - - CHandler() { } -}; - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize -}; - -static const Byte kArcProps[] = -{ - kpidNumStreams, - kpidNumBlocks -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID /*propID*/, PROPVARIANT * /*value*/) -{ - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = 1; - return S_OK; -} - -STDMETHODIMP 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 = 4; - -API_FUNC_static_IsArc IsArc_lz4(const Byte *p, size_t size) -{ - if (size < 4) - return k_IsArc_Res_NEED_MORE; - - UInt32 magic = GetUi32(p); - - // skippable frames - if (magic >= 0x184D2A50 && magic <= 0x184D2A5F) { - if (size < 16) - return k_IsArc_Res_NEED_MORE; - magic = GetUi32(p+12); - } - - // lz4 magic - if (magic == 0x184D2204) - return k_IsArc_Res_YES; - - return k_IsArc_Res_NO; -} -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) -{ - COM_TRY_BEGIN - Close(); - { - Byte buf[kSignatureCheckSize]; - RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize)); - if (IsArc_lz4(buf, kSignatureCheckSize) == k_IsArc_Res_NO) - return S_FALSE; - _isArc = true; - _stream = stream; - _seqStream = stream; - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) -{ - Close(); - _isArc = true; - _seqStream = stream; - return S_OK; -} - -STDMETHODIMP CHandler::Close() -{ - _isArc = false; - _dataAfterEnd = false; - _needMoreInput = false; - - _packSize_Defined = false; - _unpackSize_Defined = false; - - _packSize = 0; - - _seqStream.Release(); - _stream.Release(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - if (_packSize_Defined) - extractCallback->SetTotal(_packSize); - - CMyComPtr 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); - - Int32 opRes; - - { - - NCompress::NLZ4::CDecoder *decoderSpec = new NCompress::NLZ4::CDecoder; - CMyComPtr decoder = decoderSpec; - decoderSpec->SetInStream(_seqStream); - - CDummyOutStream *outStreamSpec = new CDummyOutStream; - CMyComPtr outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(); - - realOutStream.Release(); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, true); - - UInt64 packSize = 0; - UInt64 unpackedSize = 0; - - HRESULT result = S_OK; - - for (;;) - { - lps->InSize = packSize; - lps->OutSize = unpackedSize; - - RINOK(lps->SetCur()); - result = decoderSpec->CodeResume(outStream, &unpackedSize, progress); - UInt64 streamSize = decoderSpec->GetInputProcessedSize(); - - if (result != S_FALSE && result != S_OK) - return result; - - if (unpackedSize == 0) - break; - - if (streamSize == packSize) - { - // no new bytes in input stream, So it's good end of archive. - result = S_OK; - break; - } - - if (packSize > streamSize) - return E_FAIL; - - if (result != S_OK) - break; - } - - decoderSpec->ReleaseInStream(); - outStream.Release(); - - if (!_isArc) - opRes = NExtract::NOperationResult::kIsNotArc; - else if (_needMoreInput) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - else if (_dataAfterEnd) - opRes = NExtract::NOperationResult::kDataAfterEnd; - else if (result == S_FALSE) - opRes = NExtract::NOperationResult::kDataError; - else if (result == S_OK) - opRes = NExtract::NOperationResult::kOK; - else - return result; - - } - - return extractCallback->SetOperationResult(opRes); - - COM_TRY_END -} - -static HRESULT UpdateArchive( - UInt64 unpackSize, - ISequentialOutStream *outStream, - const CProps &props, - IArchiveUpdateCallback *updateCallback) -{ - RINOK(updateCallback->SetTotal(unpackSize)); - CMyComPtr fileInStream; - RINOK(updateCallback->GetStream(0, &fileInStream)); - CLocalProgress *localProgressSpec = new CLocalProgress; - CMyComPtr localProgress = localProgressSpec; - localProgressSpec->Init(updateCallback, true); - NCompress::NLZ4::CEncoder *encoderSpec = new NCompress::NLZ4::CEncoder; - CMyComPtr encoder = encoderSpec; - RINOK(props.SetCoderProps(encoderSpec, NULL)); - RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); - return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); -} - -STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) -{ - *type = NFileTimeType::kUnix; - return S_OK; -} - -STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *updateCallback) -{ - COM_TRY_BEGIN - - if (numItems != 1) - return E_INVALIDARG; - - Int32 newData, newProps; - UInt32 indexInArchive; - if (!updateCallback) - return E_FAIL; - RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); - - if ((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 ((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(size, outStream, _props, updateCallback); - } - - if (indexInArchive != 0) - return E_INVALIDARG; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(updateCallback, true); - - CMyComPtr opCallback; - updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kInArcIndex, 0, - NUpdateNotifyOp::kReplicate)) - } - - if (_stream) - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - - return NCompress::CopyStream(_stream, outStream, progress); - - COM_TRY_END -} - -STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) -{ - return _props.SetProperties(names, values, numProps); -} - -static const Byte k_Signature[] = "0x184D2204"; - -REGISTER_ARC_IO( - "lz4", "lz4 tlz4", "* .tar", 0x0f, - k_Signature, - 0, - NArcInfoFlags::kKeepName, - IsArc_lz4) - -}} +// Lz4Handler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" +#include "../../Common/ComTry.h" +#include "../../Common/Defs.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/Lz4Decoder.h" +#include "../Compress/Lz4Encoder.h" +#include "../Compress/CopyCoder.h" + +#include "Common/DummyOutStream.h" +#include "Common/HandlerOut.h" + +using namespace NWindows; + +namespace NArchive { +namespace NLZ4 { + +class CHandler: + public IInArchive, + public IArchiveOpenSeq, + public IOutArchive, + public ISetProperties, + public CMyUnknownImp +{ + CMyComPtr _stream; + CMyComPtr _seqStream; + + bool _isArc; + bool _dataAfterEnd; + bool _needMoreInput; + + bool _packSize_Defined; + bool _unpackSize_Defined; + + UInt64 _packSize; + UInt64 _unpackSize; + UInt64 _numStreams; + UInt64 _numBlocks; + + CSingleMethodProps _props; + +public: + MY_UNKNOWN_IMP4( + IInArchive, + IArchiveOpenSeq, + IOutArchive, + ISetProperties) + INTERFACE_IInArchive(;) + INTERFACE_IOutArchive(;) + STDMETHOD(OpenSeq)(ISequentialInStream *stream); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); + + CHandler() { } +}; + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidNumStreams, + kpidNumBlocks +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID /*propID*/, PROPVARIANT * /*value*/) +{ + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1; + return S_OK; +} + +STDMETHODIMP 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 = 4; + +API_FUNC_static_IsArc IsArc_lz4(const Byte *p, size_t size) +{ + if (size < 4) + return k_IsArc_Res_NEED_MORE; + + UInt32 magic = GetUi32(p); + + // skippable frames + if (magic >= 0x184D2A50 && magic <= 0x184D2A5F) { + if (size < 16) + return k_IsArc_Res_NEED_MORE; + magic = GetUi32(p+12); + } + + // lz4 magic + if (magic == 0x184D2204) + return k_IsArc_Res_YES; + + return k_IsArc_Res_NO; +} +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) +{ + COM_TRY_BEGIN + Close(); + { + Byte buf[kSignatureCheckSize]; + RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize)); + if (IsArc_lz4(buf, kSignatureCheckSize) == k_IsArc_Res_NO) + return S_FALSE; + _isArc = true; + _stream = stream; + _seqStream = stream; + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) +{ + Close(); + _isArc = true; + _seqStream = stream; + return S_OK; +} + +STDMETHODIMP CHandler::Close() +{ + _isArc = false; + _dataAfterEnd = false; + _needMoreInput = false; + + _packSize_Defined = false; + _unpackSize_Defined = false; + + _packSize = 0; + + _seqStream.Release(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + if (_packSize_Defined) + extractCallback->SetTotal(_packSize); + + CMyComPtr 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); + + Int32 opRes; + + { + + NCompress::NLZ4::CDecoder *decoderSpec = new NCompress::NLZ4::CDecoder; + CMyComPtr decoder = decoderSpec; + decoderSpec->SetInStream(_seqStream); + + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + + realOutStream.Release(); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, true); + + UInt64 packSize = 0; + UInt64 unpackedSize = 0; + + HRESULT result = S_OK; + + for (;;) + { + lps->InSize = packSize; + lps->OutSize = unpackedSize; + + RINOK(lps->SetCur()); + result = decoderSpec->CodeResume(outStream, &unpackedSize, progress); + UInt64 streamSize = decoderSpec->GetInputProcessedSize(); + + if (result != S_FALSE && result != S_OK) + return result; + + if (unpackedSize == 0) + break; + + if (streamSize == packSize) + { + // no new bytes in input stream, So it's good end of archive. + result = S_OK; + break; + } + + if (packSize > streamSize) + return E_FAIL; + + if (result != S_OK) + break; + } + + decoderSpec->ReleaseInStream(); + outStream.Release(); + + if (!_isArc) + opRes = NExtract::NOperationResult::kIsNotArc; + else if (_needMoreInput) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + else if (_dataAfterEnd) + opRes = NExtract::NOperationResult::kDataAfterEnd; + else if (result == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else if (result == S_OK) + opRes = NExtract::NOperationResult::kOK; + else + return result; + + } + + return extractCallback->SetOperationResult(opRes); + + COM_TRY_END +} + +static HRESULT UpdateArchive( + UInt64 unpackSize, + ISequentialOutStream *outStream, + const CProps &props, + IArchiveUpdateCallback *updateCallback) +{ + RINOK(updateCallback->SetTotal(unpackSize)); + CMyComPtr fileInStream; + RINOK(updateCallback->GetStream(0, &fileInStream)); + CLocalProgress *localProgressSpec = new CLocalProgress; + CMyComPtr localProgress = localProgressSpec; + localProgressSpec->Init(updateCallback, true); + NCompress::NLZ4::CEncoder *encoderSpec = new NCompress::NLZ4::CEncoder; + CMyComPtr encoder = encoderSpec; + RINOK(props.SetCoderProps(encoderSpec, NULL)); + RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); + return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); +} + +STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) +{ + *type = NFileTimeType::kUnix; + return S_OK; +} + +STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback) +{ + COM_TRY_BEGIN + + if (numItems != 1) + return E_INVALIDARG; + + Int32 newData, newProps; + UInt32 indexInArchive; + if (!updateCallback) + return E_FAIL; + RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); + + if ((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 ((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(size, outStream, _props, updateCallback); + } + + if (indexInArchive != 0) + return E_INVALIDARG; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(updateCallback, true); + + CMyComPtr opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, 0, + NUpdateNotifyOp::kReplicate)) + } + + if (_stream) + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); + + return NCompress::CopyStream(_stream, outStream, progress); + + COM_TRY_END +} + +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) +{ + return _props.SetProperties(names, values, numProps); +} + +static const Byte k_Signature[] = "0x184D2204"; + +REGISTER_ARC_IO( + "lz4", "lz4 tlz4", "* .tar", 0x0f, + k_Signature, + 0, + NArcInfoFlags::kKeepName, + IsArc_lz4) + +}} diff --git a/CPP/7zip/Archive/Lz5Handler.cpp b/CPP/7zip/Archive/Lz5Handler.cpp index cf55239d9..d1fd2c1bd 100644 --- a/CPP/7zip/Archive/Lz5Handler.cpp +++ b/CPP/7zip/Archive/Lz5Handler.cpp @@ -1,366 +1,366 @@ -// Lz5Handler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" -#include "../../Common/ComTry.h" -#include "../../Common/Defs.h" - -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/Lz5Decoder.h" -#include "../Compress/Lz5Encoder.h" -#include "../Compress/CopyCoder.h" - -#include "Common/DummyOutStream.h" -#include "Common/HandlerOut.h" - -using namespace NWindows; - -namespace NArchive { -namespace NLZ5 { - -class CHandler: - public IInArchive, - public IArchiveOpenSeq, - public IOutArchive, - public ISetProperties, - public CMyUnknownImp -{ - CMyComPtr _stream; - CMyComPtr _seqStream; - - bool _isArc; - bool _dataAfterEnd; - bool _needMoreInput; - - bool _packSize_Defined; - bool _unpackSize_Defined; - - UInt64 _packSize; - UInt64 _unpackSize; - UInt64 _numStreams; - UInt64 _numBlocks; - - CSingleMethodProps _props; - -public: - MY_UNKNOWN_IMP4( - IInArchive, - IArchiveOpenSeq, - IOutArchive, - ISetProperties) - INTERFACE_IInArchive(;) - INTERFACE_IOutArchive(;) - STDMETHOD(OpenSeq)(ISequentialInStream *stream); - STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); - - CHandler() { } -}; - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize -}; - -static const Byte kArcProps[] = -{ - kpidNumStreams, - kpidNumBlocks -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID /*propID*/, PROPVARIANT * /*value*/) -{ - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = 1; - return S_OK; -} - -STDMETHODIMP 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 = 4; - -API_FUNC_static_IsArc IsArc_lz5(const Byte *p, size_t size) -{ - if (size < 4) - return k_IsArc_Res_NEED_MORE; - - UInt32 magic = GetUi32(p); - - // skippable frames - if (magic >= 0x184D2A50 && magic <= 0x184D2A5F) { - if (size < 16) - return k_IsArc_Res_NEED_MORE; - magic = GetUi32(p+12); - } - - // Lz5 Magic - if (magic == 0x184D2205) - return k_IsArc_Res_YES; - - return k_IsArc_Res_NO; -} -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) -{ - COM_TRY_BEGIN - Close(); - { - Byte buf[kSignatureCheckSize]; - RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize)); - if (IsArc_lz5(buf, kSignatureCheckSize) == k_IsArc_Res_NO) - return S_FALSE; - _isArc = true; - _stream = stream; - _seqStream = stream; - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) -{ - Close(); - _isArc = true; - _seqStream = stream; - return S_OK; -} - -STDMETHODIMP CHandler::Close() -{ - _isArc = false; - _dataAfterEnd = false; - _needMoreInput = false; - - _packSize_Defined = false; - _unpackSize_Defined = false; - - _packSize = 0; - - _seqStream.Release(); - _stream.Release(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - if (_packSize_Defined) - extractCallback->SetTotal(_packSize); - - CMyComPtr 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); - - Int32 opRes; - - { - - NCompress::NLZ5::CDecoder *decoderSpec = new NCompress::NLZ5::CDecoder; - CMyComPtr decoder = decoderSpec; - decoderSpec->SetInStream(_seqStream); - - CDummyOutStream *outStreamSpec = new CDummyOutStream; - CMyComPtr outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(); - - realOutStream.Release(); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, true); - - UInt64 packSize = 0; - UInt64 unpackedSize = 0; - - HRESULT result = S_OK; - - for (;;) - { - lps->InSize = packSize; - lps->OutSize = unpackedSize; - - RINOK(lps->SetCur()); - result = decoderSpec->CodeResume(outStream, &unpackedSize, progress); - UInt64 streamSize = decoderSpec->GetInputProcessedSize(); - - if (result != S_FALSE && result != S_OK) - return result; - - if (unpackedSize == 0) - break; - - if (streamSize == packSize) - { - // no new bytes in input stream, So it's good end of archive. - result = S_OK; - break; - } - - if (packSize > streamSize) - return E_FAIL; - - if (result != S_OK) - break; - } - - decoderSpec->ReleaseInStream(); - outStream.Release(); - - if (!_isArc) - opRes = NExtract::NOperationResult::kIsNotArc; - else if (_needMoreInput) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - else if (_dataAfterEnd) - opRes = NExtract::NOperationResult::kDataAfterEnd; - else if (result == S_FALSE) - opRes = NExtract::NOperationResult::kDataError; - else if (result == S_OK) - opRes = NExtract::NOperationResult::kOK; - else - return result; - - } - - return extractCallback->SetOperationResult(opRes); - - COM_TRY_END -} - -static HRESULT UpdateArchive( - UInt64 unpackSize, - ISequentialOutStream *outStream, - const CProps &props, - IArchiveUpdateCallback *updateCallback) -{ - RINOK(updateCallback->SetTotal(unpackSize)); - CMyComPtr fileInStream; - RINOK(updateCallback->GetStream(0, &fileInStream)); - CLocalProgress *localProgressSpec = new CLocalProgress; - CMyComPtr localProgress = localProgressSpec; - localProgressSpec->Init(updateCallback, true); - NCompress::NLZ5::CEncoder *encoderSpec = new NCompress::NLZ5::CEncoder; - CMyComPtr encoder = encoderSpec; - RINOK(props.SetCoderProps(encoderSpec, NULL)); - RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); - return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); -} - -STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) -{ - *type = NFileTimeType::kUnix; - return S_OK; -} - -STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *updateCallback) -{ - COM_TRY_BEGIN - - if (numItems != 1) - return E_INVALIDARG; - - Int32 newData, newProps; - UInt32 indexInArchive; - if (!updateCallback) - return E_FAIL; - RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); - - if ((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 ((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(size, outStream, _props, updateCallback); - } - - if (indexInArchive != 0) - return E_INVALIDARG; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(updateCallback, true); - - CMyComPtr opCallback; - updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kInArcIndex, 0, - NUpdateNotifyOp::kReplicate)) - } - - if (_stream) - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - - return NCompress::CopyStream(_stream, outStream, progress); - - COM_TRY_END -} - -STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) -{ - return _props.SetProperties(names, values, numProps); -} - -static const Byte k_Signature[] = "0x184D2205"; - -REGISTER_ARC_IO( - "lz5", "lz5 tlz5", "* .tar", 0x10, - k_Signature, - 0, - NArcInfoFlags::kKeepName, - IsArc_lz5) - -}} +// Lz5Handler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" +#include "../../Common/ComTry.h" +#include "../../Common/Defs.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/Lz5Decoder.h" +#include "../Compress/Lz5Encoder.h" +#include "../Compress/CopyCoder.h" + +#include "Common/DummyOutStream.h" +#include "Common/HandlerOut.h" + +using namespace NWindows; + +namespace NArchive { +namespace NLZ5 { + +class CHandler: + public IInArchive, + public IArchiveOpenSeq, + public IOutArchive, + public ISetProperties, + public CMyUnknownImp +{ + CMyComPtr _stream; + CMyComPtr _seqStream; + + bool _isArc; + bool _dataAfterEnd; + bool _needMoreInput; + + bool _packSize_Defined; + bool _unpackSize_Defined; + + UInt64 _packSize; + UInt64 _unpackSize; + UInt64 _numStreams; + UInt64 _numBlocks; + + CSingleMethodProps _props; + +public: + MY_UNKNOWN_IMP4( + IInArchive, + IArchiveOpenSeq, + IOutArchive, + ISetProperties) + INTERFACE_IInArchive(;) + INTERFACE_IOutArchive(;) + STDMETHOD(OpenSeq)(ISequentialInStream *stream); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); + + CHandler() { } +}; + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidNumStreams, + kpidNumBlocks +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID /*propID*/, PROPVARIANT * /*value*/) +{ + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1; + return S_OK; +} + +STDMETHODIMP 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 = 4; + +API_FUNC_static_IsArc IsArc_lz5(const Byte *p, size_t size) +{ + if (size < 4) + return k_IsArc_Res_NEED_MORE; + + UInt32 magic = GetUi32(p); + + // skippable frames + if (magic >= 0x184D2A50 && magic <= 0x184D2A5F) { + if (size < 16) + return k_IsArc_Res_NEED_MORE; + magic = GetUi32(p+12); + } + + // Lz5 Magic + if (magic == 0x184D2205) + return k_IsArc_Res_YES; + + return k_IsArc_Res_NO; +} +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) +{ + COM_TRY_BEGIN + Close(); + { + Byte buf[kSignatureCheckSize]; + RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize)); + if (IsArc_lz5(buf, kSignatureCheckSize) == k_IsArc_Res_NO) + return S_FALSE; + _isArc = true; + _stream = stream; + _seqStream = stream; + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) +{ + Close(); + _isArc = true; + _seqStream = stream; + return S_OK; +} + +STDMETHODIMP CHandler::Close() +{ + _isArc = false; + _dataAfterEnd = false; + _needMoreInput = false; + + _packSize_Defined = false; + _unpackSize_Defined = false; + + _packSize = 0; + + _seqStream.Release(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + if (_packSize_Defined) + extractCallback->SetTotal(_packSize); + + CMyComPtr 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); + + Int32 opRes; + + { + + NCompress::NLZ5::CDecoder *decoderSpec = new NCompress::NLZ5::CDecoder; + CMyComPtr decoder = decoderSpec; + decoderSpec->SetInStream(_seqStream); + + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + + realOutStream.Release(); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, true); + + UInt64 packSize = 0; + UInt64 unpackedSize = 0; + + HRESULT result = S_OK; + + for (;;) + { + lps->InSize = packSize; + lps->OutSize = unpackedSize; + + RINOK(lps->SetCur()); + result = decoderSpec->CodeResume(outStream, &unpackedSize, progress); + UInt64 streamSize = decoderSpec->GetInputProcessedSize(); + + if (result != S_FALSE && result != S_OK) + return result; + + if (unpackedSize == 0) + break; + + if (streamSize == packSize) + { + // no new bytes in input stream, So it's good end of archive. + result = S_OK; + break; + } + + if (packSize > streamSize) + return E_FAIL; + + if (result != S_OK) + break; + } + + decoderSpec->ReleaseInStream(); + outStream.Release(); + + if (!_isArc) + opRes = NExtract::NOperationResult::kIsNotArc; + else if (_needMoreInput) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + else if (_dataAfterEnd) + opRes = NExtract::NOperationResult::kDataAfterEnd; + else if (result == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else if (result == S_OK) + opRes = NExtract::NOperationResult::kOK; + else + return result; + + } + + return extractCallback->SetOperationResult(opRes); + + COM_TRY_END +} + +static HRESULT UpdateArchive( + UInt64 unpackSize, + ISequentialOutStream *outStream, + const CProps &props, + IArchiveUpdateCallback *updateCallback) +{ + RINOK(updateCallback->SetTotal(unpackSize)); + CMyComPtr fileInStream; + RINOK(updateCallback->GetStream(0, &fileInStream)); + CLocalProgress *localProgressSpec = new CLocalProgress; + CMyComPtr localProgress = localProgressSpec; + localProgressSpec->Init(updateCallback, true); + NCompress::NLZ5::CEncoder *encoderSpec = new NCompress::NLZ5::CEncoder; + CMyComPtr encoder = encoderSpec; + RINOK(props.SetCoderProps(encoderSpec, NULL)); + RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); + return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); +} + +STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) +{ + *type = NFileTimeType::kUnix; + return S_OK; +} + +STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback) +{ + COM_TRY_BEGIN + + if (numItems != 1) + return E_INVALIDARG; + + Int32 newData, newProps; + UInt32 indexInArchive; + if (!updateCallback) + return E_FAIL; + RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); + + if ((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 ((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(size, outStream, _props, updateCallback); + } + + if (indexInArchive != 0) + return E_INVALIDARG; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(updateCallback, true); + + CMyComPtr opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, 0, + NUpdateNotifyOp::kReplicate)) + } + + if (_stream) + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); + + return NCompress::CopyStream(_stream, outStream, progress); + + COM_TRY_END +} + +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) +{ + return _props.SetProperties(names, values, numProps); +} + +static const Byte k_Signature[] = "0x184D2205"; + +REGISTER_ARC_IO( + "lz5", "lz5 tlz5", "* .tar", 0x10, + k_Signature, + 0, + NArcInfoFlags::kKeepName, + IsArc_lz5) + +}} diff --git a/CPP/7zip/Archive/LzhHandler.cpp b/CPP/7zip/Archive/LzhHandler.cpp index 39da04a17..53d69db72 100644 --- a/CPP/7zip/Archive/LzhHandler.cpp +++ b/CPP/7zip/Archive/LzhHandler.cpp @@ -1,758 +1,758 @@ -// 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) -{ - const Byte *p = (const Byte *)data; - const Byte *pEnd = p + size; - for (; p != pEnd; p++) - crc = CRC16_UPDATE_BYTE(crc, *p); - return crc; -} - -static class CLzhCrc16TableInit -{ -public: - 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; - for (size_t i = 0; i < Data.Size(); i++) - { - char c = (char)Data[i]; - if (c == 0) - break; - s += c; - } - 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 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 i; - return -1; - } - bool GetUnixTime(UInt32 &value) const - { - value = 0; - int index = FindExt(kExtIdUnixTime); - if (index < 0) - { - if (Level == 2) - { - value = ModifiedTime; - return true; - } - return false; - } - const Byte *data = (const Byte *)(Extensions[index].Data); - value = GetUi32(data); - return true; - } - - AString GetDirName() const - { - int index = FindExt(kExtIdDirName); - if (index < 0) - return AString(); - return Extensions[index].GetString(); - } - - AString GetFileName() const - { - int index = FindExt(kExtIdFileName); - if (index < 0) - return Name; - return Extensions[index].GetString(); - } - - AString GetName() const - { - AString dirName (GetDirName()); - const char kDirSeparator = '\\'; - // check kDirSeparator in Linux - dirName.Replace((char)(unsigned char)0xFF, kDirSeparator); - if (!dirName.IsEmpty() && dirName.Back() != kDirSeparator) - dirName += kDirSeparator; - return dirName + GetFileName(); - } -}; - -static const Byte *ReadUInt16(const Byte *p, UInt16 &v) -{ - v = Get16(p); - return p + 2; -} - -static const Byte *ReadString(const Byte *p, size_t size, AString &s) -{ - s.Empty(); - for (size_t i = 0; i < size; i++) - { - char c = p[i]; - if (c == 0) - break; - s += c; - } - return p + size; -} - -static Byte CalcSum(const Byte *data, size_t size) -{ - Byte sum = 0; - for (size_t i = 0; i < size; i++) - sum = (Byte)(sum + data[i]); - return sum; -} - -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; - size_t nameLength = *p++; - if ((p - header) + nameLength + 2 > headerSize) - return S_FALSE; - p = ReadString(p, nameLength, item.Name); - } - else - headerSize = startHeader[0] | ((UInt32)startHeader[1] << 8); - p = ReadUInt16(p, item.CRC); - if (item.Level != 0) - { - if (item.Level == 2) - { - RINOK(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 -= 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 -}; - - -class COutStreamWithCRC: - public ISequentialOutStream, - public CMyUnknownImp -{ -public: - MY_UNKNOWN_IMP - - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); -private: - UInt32 _crc; - CMyComPtr _stream; -public: - void Init(ISequentialOutStream *stream) - { - _stream = stream; - _crc = 0; - } - void ReleaseStream() { _stream.Release(); } - UInt32 GetCRC() const { return _crc; } -}; - -STDMETHODIMP 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; -}; - - -class CHandler: - public IInArchive, - public CMyUnknownImp -{ - CObjectVector _items; - CMyComPtr _stream; - UInt64 _phySize; - UInt32 _errorFlags; - bool _isArc; -public: - MY_UNKNOWN_IMP1(IInArchive) - INTERFACE_IInArchive(;) - CHandler(); -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table - -CHandler::CHandler() {} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: prop = _phySize; break; - - case kpidErrorFlags: - UInt32 v = _errorFlags; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - prop = v; - break; - } - prop.Detach(value); - return S_OK; -} - -STDMETHODIMP 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: - { - FILETIME utc; - UInt32 unixTime; - if (item.GetUnixTime(unixTime)) - NTime::UnixTimeToFileTime(unixTime, utc); - else - { - FILETIME localFileTime; - if (DosTimeToFileTime(item.ModifiedTime, localFileTime)) - { - if (!LocalFileTimeToFileTime(&localFileTime, &utc)) - utc.dwHighDateTime = utc.dwLowDateTime = 0; - } - else - utc.dwHighDateTime = utc.dwLowDateTime = 0; - } - prop = utc; - break; - } - // case kpidAttrib: prop = (UInt32)item.Attributes; break; - case kpidMethod: - { - char method2[kMethodIdSize + 1]; - method2[kMethodIdSize] = 0; - memcpy(method2, item.Method, kMethodIdSize); - prop = method2; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback) -{ - COM_TRY_BEGIN - Close(); - try - { - _items.Clear(); - - UInt64 endPos = 0; - bool needSetTotal = true; - - RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); - RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); - - for (;;) - { - CItemEx item; - bool filled; - HRESULT res = GetNextItem(stream, filled, item); - RINOK(stream->Seek(0, STREAM_SEEK_CUR, &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; -} - -STDMETHODIMP CHandler::Close() -{ - _isArc = false; - _phySize = 0; - _errorFlags = 0; - _items.Clear(); - _stream.Release(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testModeSpec, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool testMode = (testModeSpec != 0); - UInt64 totalUnPacked = 0, totalPacked = 0; - bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (numItems == 0) - return S_OK; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const CItemEx &item = _items[allFilesMode ? i : indices[i]]; - totalUnPacked += item.Size; - totalPacked += item.PackSize; - } - RINOK(extractCallback->SetTotal(totalUnPacked)); - - UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0; - UInt64 currentItemUnPacked, currentItemPacked; - - NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = 0; - CMyComPtr lzhDecoder; - // CMyComPtr lzh1Decoder; - // CMyComPtr arj2Decoder; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_stream); - - for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked, - currentTotalPacked += currentItemPacked) - { - currentItemUnPacked = 0; - currentItemPacked = 0; - - lps->InSize = currentTotalPacked; - lps->OutSize = currentTotalUnPacked; - RINOK(lps->SetCur()); - - CMyComPtr realOutStream; - Int32 askMode; - askMode = testMode ? NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; - const CItemEx &item = _items[index]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - - if (item.IsDir()) - { - // if (!testMode) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - } - continue; - } - - if (!testMode && !realOutStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)); - currentItemUnPacked = item.Size; - currentItemPacked = item.PackSize; - - { - COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; - CMyComPtr outStream(outStreamSpec); - outStreamSpec->Init(realOutStream); - realOutStream.Release(); - - UInt64 pos; - _stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos); - - 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, ¤tItemUnPacked, 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, ¤tItemUnPacked, 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", 0, 6, - k_Signature, - 2, - 0, - IsArc_Lzh) - -}} +// 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) +{ + const Byte *p = (const Byte *)data; + const Byte *pEnd = p + size; + for (; p != pEnd; p++) + crc = CRC16_UPDATE_BYTE(crc, *p); + return crc; +} + +static class CLzhCrc16TableInit +{ +public: + 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; + for (size_t i = 0; i < Data.Size(); i++) + { + char c = (char)Data[i]; + if (c == 0) + break; + s += c; + } + 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 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 i; + return -1; + } + bool GetUnixTime(UInt32 &value) const + { + value = 0; + int index = FindExt(kExtIdUnixTime); + if (index < 0) + { + if (Level == 2) + { + value = ModifiedTime; + return true; + } + return false; + } + const Byte *data = (const Byte *)(Extensions[index].Data); + value = GetUi32(data); + return true; + } + + AString GetDirName() const + { + int index = FindExt(kExtIdDirName); + if (index < 0) + return AString(); + return Extensions[index].GetString(); + } + + AString GetFileName() const + { + int index = FindExt(kExtIdFileName); + if (index < 0) + return Name; + return Extensions[index].GetString(); + } + + AString GetName() const + { + AString dirName (GetDirName()); + const char kDirSeparator = '\\'; + // check kDirSeparator in Linux + dirName.Replace((char)(unsigned char)0xFF, kDirSeparator); + if (!dirName.IsEmpty() && dirName.Back() != kDirSeparator) + dirName += kDirSeparator; + return dirName + GetFileName(); + } +}; + +static const Byte *ReadUInt16(const Byte *p, UInt16 &v) +{ + v = Get16(p); + return p + 2; +} + +static const Byte *ReadString(const Byte *p, size_t size, AString &s) +{ + s.Empty(); + for (size_t i = 0; i < size; i++) + { + char c = p[i]; + if (c == 0) + break; + s += c; + } + return p + size; +} + +static Byte CalcSum(const Byte *data, size_t size) +{ + Byte sum = 0; + for (size_t i = 0; i < size; i++) + sum = (Byte)(sum + data[i]); + return sum; +} + +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; + size_t nameLength = *p++; + if ((p - header) + nameLength + 2 > headerSize) + return S_FALSE; + p = ReadString(p, nameLength, item.Name); + } + else + headerSize = startHeader[0] | ((UInt32)startHeader[1] << 8); + p = ReadUInt16(p, item.CRC); + if (item.Level != 0) + { + if (item.Level == 2) + { + RINOK(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 -= 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 +}; + + +class COutStreamWithCRC: + public ISequentialOutStream, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +private: + UInt32 _crc; + CMyComPtr _stream; +public: + void Init(ISequentialOutStream *stream) + { + _stream = stream; + _crc = 0; + } + void ReleaseStream() { _stream.Release(); } + UInt32 GetCRC() const { return _crc; } +}; + +STDMETHODIMP 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; +}; + + +class CHandler: + public IInArchive, + public CMyUnknownImp +{ + CObjectVector _items; + CMyComPtr _stream; + UInt64 _phySize; + UInt32 _errorFlags; + bool _isArc; +public: + MY_UNKNOWN_IMP1(IInArchive) + INTERFACE_IInArchive(;) + CHandler(); +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +CHandler::CHandler() {} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: prop = _phySize; break; + + case kpidErrorFlags: + UInt32 v = _errorFlags; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + prop = v; + break; + } + prop.Detach(value); + return S_OK; +} + +STDMETHODIMP 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: + { + FILETIME utc; + UInt32 unixTime; + if (item.GetUnixTime(unixTime)) + NTime::UnixTimeToFileTime(unixTime, utc); + else + { + FILETIME localFileTime; + if (DosTimeToFileTime(item.ModifiedTime, localFileTime)) + { + if (!LocalFileTimeToFileTime(&localFileTime, &utc)) + utc.dwHighDateTime = utc.dwLowDateTime = 0; + } + else + utc.dwHighDateTime = utc.dwLowDateTime = 0; + } + prop = utc; + break; + } + // case kpidAttrib: prop = (UInt32)item.Attributes; break; + case kpidMethod: + { + char method2[kMethodIdSize + 1]; + method2[kMethodIdSize] = 0; + memcpy(method2, item.Method, kMethodIdSize); + prop = method2; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + Close(); + try + { + _items.Clear(); + + UInt64 endPos = 0; + bool needSetTotal = true; + + RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + + for (;;) + { + CItemEx item; + bool filled; + HRESULT res = GetNextItem(stream, filled, item); + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &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; +} + +STDMETHODIMP CHandler::Close() +{ + _isArc = false; + _phySize = 0; + _errorFlags = 0; + _items.Clear(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testModeSpec, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool testMode = (testModeSpec != 0); + UInt64 totalUnPacked = 0, totalPacked = 0; + bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const CItemEx &item = _items[allFilesMode ? i : indices[i]]; + totalUnPacked += item.Size; + totalPacked += item.PackSize; + } + RINOK(extractCallback->SetTotal(totalUnPacked)); + + UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0; + UInt64 currentItemUnPacked, currentItemPacked; + + NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = 0; + CMyComPtr lzhDecoder; + // CMyComPtr lzh1Decoder; + // CMyComPtr arj2Decoder; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(_stream); + + for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked, + currentTotalPacked += currentItemPacked) + { + currentItemUnPacked = 0; + currentItemPacked = 0; + + lps->InSize = currentTotalPacked; + lps->OutSize = currentTotalUnPacked; + RINOK(lps->SetCur()); + + CMyComPtr realOutStream; + Int32 askMode; + askMode = testMode ? NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + const CItemEx &item = _items[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + if (item.IsDir()) + { + // if (!testMode) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + } + continue; + } + + if (!testMode && !realOutStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)); + currentItemUnPacked = item.Size; + currentItemPacked = item.PackSize; + + { + COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; + CMyComPtr outStream(outStreamSpec); + outStreamSpec->Init(realOutStream); + realOutStream.Release(); + + UInt64 pos; + _stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos); + + 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, ¤tItemUnPacked, 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, ¤tItemUnPacked, 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", 0, 6, + k_Signature, + 2, + 0, + IsArc_Lzh) + +}} diff --git a/CPP/7zip/Archive/LzmaHandler.cpp b/CPP/7zip/Archive/LzmaHandler.cpp index f13fca7ab..9eac3ca12 100644 --- a/CPP/7zip/Archive/LzmaHandler.cpp +++ b/CPP/7zip/Archive/LzmaHandler.cpp @@ -1,629 +1,629 @@ -// 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 _bcjStream; - CFilterCoder *_filterCoder; - CMyComPtr _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 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 _stream; - CMyComPtr _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 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 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 outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(); - realOutStream.Release(); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr 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 +{ + CMyComPtr _bcjStream; + CFilterCoder *_filterCoder; + CMyComPtr _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 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 _stream; + CMyComPtr _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 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 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 outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + realOutStream.Release(); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr 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) + +} + +}} diff --git a/CPP/7zip/Archive/MachoHandler.cpp b/CPP/7zip/Archive/MachoHandler.cpp index 31e7d1705..1f65574d4 100644 --- a/CPP/7zip/Archive/MachoHandler.cpp +++ b/CPP/7zip/Archive/MachoHandler.cpp @@ -1,668 +1,668 @@ -// 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 (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" -}; - -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_Flags[] = -{ - { 31, "PURE_INSTRUCTIONS" }, - { 30, "NO_TOC" }, - { 29, "STRIP_STATIC_SYMS" }, - { 28, "NO_DEAD_STRIP" }, - { 27, "LIVE_SUPPORT" }, - { 26, "SELF_MODIFYING_CODE" }, - { 25, "DEBUG" }, - { 10, "SOME_INSTRUCTIONS" }, - { 9, "EXT_RELOC" }, - { 8, "LOC_RELOC" } -}; - -static const unsigned kNameSize = 16; - -struct CSegment -{ - char Name[kNameSize]; -}; - -struct CSection -{ - char Name[kNameSize]; - char SegName[kNameSize]; - UInt64 Va; - UInt64 Pa; - UInt64 VSize; - UInt64 PSize; - - UInt32 Flags; - int SegmentIndex; - - bool IsDummy; - - CSection(): IsDummy(false) {} - // UInt64 GetPackSize() const { return Flags == SECT_ATTR_ZEROFILL ? 0 : Size; } - UInt64 GetPackSize() const { return PSize; } -}; - - -class CHandler: - public IInArchive, - public IArchiveAllowTail, - public CMyUnknownImp -{ - CMyComPtr _inStream; - CObjectVector _segments; - CObjectVector _sections; - bool _allowTail; - bool _mode64; - bool _be; - UInt32 _cpuType; - UInt32 _cpuSubType; - UInt32 _type; - UInt32 _flags; - UInt32 _headersSize; - UInt64 _totalSize; - - HRESULT Open2(ISequentialInStream *stream); -public: - MY_UNKNOWN_IMP2(IInArchive, IArchiveAllowTail) - INTERFACE_IInArchive(;) - STDMETHOD(AllowTail)(Int32 allowTail); - CHandler(): _allowTail(false) {} -}; - -static const Byte kArcProps[] = -{ - kpidCpu, - kpidBit64, - kpidBigEndian, - kpidCharacts, - kpidHeadersSize -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidPackSize, - kpidCharacts, - kpidOffset, - kpidVa -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - CPropVariant prop; - switch (propID) - { - case kpidShortComment: - case kpidCpu: - { - AString s; - char temp[16]; - UInt32 cpu = _cpuType & ~(UInt32)CPU_ARCH_ABI64; - UInt32 flag64 = _cpuType & (UInt32)CPU_ARCH_ABI64; - { - const char *n = NULL; - for (unsigned i = 0; i < ARRAY_SIZE(g_CpuPairs); i++) - { - const CUInt32PCharPair &pair = g_CpuPairs[i]; - if (pair.Value == cpu || pair.Value == _cpuType) - { - if (pair.Value == _cpuType) - flag64 = 0; - n = pair.Name; - break; - } - } - if (!n) - { - ConvertUInt32ToString(cpu, temp); - n = temp; - } - s = n; - - if (flag64 != 0) - s += " 64-bit"; - else if ((_cpuSubType & CPU_SUBTYPE_LIB64) && _cpuType != CPU_TYPE_AMD64) - s += " 64-bit-lib"; - } - 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 < ARRAY_SIZE(k_PowerPc_SubTypes)) - n = k_PowerPc_SubTypes[t]; - } - if (!n) - { - ConvertUInt32ToString(t, temp); - n = temp; - } - s.Add_Space(); - s += n; - } - prop = s; - break; - } - case kpidCharacts: - { - // TYPE_TO_PROP(g_FileTypes, _type, prop); break; - AString res (TypeToString(g_FileTypes, ARRAY_SIZE(g_FileTypes), _type)); - AString s (FlagsToString(g_ArcFlags, 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 AString GetName(const char *name) -{ - char res[kNameSize + 1]; - memcpy(res, name, kNameSize); - res[kNameSize] = 0; - return (AString)res; -} - - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - CPropVariant prop; - const CSection &item = _sections[index]; - switch (propID) - { - case kpidPath: - { - AString s (GetName(_segments[item.SegmentIndex].Name)); - if (!item.IsDummy) - s += GetName(item.Name); - prop = MultiByteToUnicodeString(s); - break; - } - case kpidSize: /* prop = (UInt64)item.VSize; break; */ - case kpidPackSize: prop = (UInt64)item.GetPackSize(); break; - case kpidCharacts: - if (!item.IsDummy) - { - AString res (TypeToString(g_SectTypes, ARRAY_SIZE(g_SectTypes), item.Flags & SECT_TYPE_MASK)); - AString s (FlagsToString(g_Flags, ARRAY_SIZE(g_Flags), item.Flags & SECT_ATTR_MASK)); - if (!s.IsEmpty()) - { - res.Add_Space(); - res += s; - } - prop = res; - } - break; - case kpidOffset: prop = item.Pa; break; - case kpidVa: prop = item.Va; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -HRESULT CHandler::Open2(ISequentialInStream *stream) -{ - const UInt32 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; - - UInt32 numCommands = Get32(header + 0x10, be); - 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; - 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 § = _sections.AddNew(); - sect.IsDummy = true; - sect.SegmentIndex = _segments.Size() - 1; - sect.Va = vmAddr; - sect.PSize = phSize; - sect.VSize = vmSize; - sect.Pa = phAddr; - sect.Flags = 0; - } - else do - { - UInt32 headSize = (cmd == CMD_SEGMENT_64) ? 0x50 : 0x44; - const Byte *p = buf + offs; - if (cmdSize - offs < headSize) - break; - CSection § = _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.Flags = Get32(p + f32Offset + 10, be); - if (sect.Flags == 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; -} - -STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) -{ - COM_TRY_BEGIN - Close(); - RINOK(Open2(inStream)); - if (!_allowTail) - { - UInt64 fileSize; - RINOK(inStream->Seek(0, STREAM_SEEK_END, &fileSize)); - if (fileSize > _totalSize) - return S_FALSE; - } - _inStream = inStream; - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _totalSize = 0; - _inStream.Release(); - _sections.Clear(); - _segments.Clear(); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _sections.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_inStream); - - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()); - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - UInt32 index = allFilesMode ? i : indices[i]; - const CSection &item = _sections[index]; - currentItemSize = item.GetPackSize(); - - CMyComPtr outStream; - RINOK(extractCallback->GetStream(index, &outStream, askMode)); - if (!testMode && !outStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(_inStream->Seek(item.Pa, STREAM_SEEK_SET, NULL)); - streamSpec->Init(currentItemSize); - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); - outStream.Release(); - RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP 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", 0, 0xDF, - k_Signature, - 0, - NArcInfoFlags::kMultiSignature | - NArcInfoFlags::kPreArc, - NULL) - -}} +// 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 (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" +}; + +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_Flags[] = +{ + { 31, "PURE_INSTRUCTIONS" }, + { 30, "NO_TOC" }, + { 29, "STRIP_STATIC_SYMS" }, + { 28, "NO_DEAD_STRIP" }, + { 27, "LIVE_SUPPORT" }, + { 26, "SELF_MODIFYING_CODE" }, + { 25, "DEBUG" }, + { 10, "SOME_INSTRUCTIONS" }, + { 9, "EXT_RELOC" }, + { 8, "LOC_RELOC" } +}; + +static const unsigned kNameSize = 16; + +struct CSegment +{ + char Name[kNameSize]; +}; + +struct CSection +{ + char Name[kNameSize]; + char SegName[kNameSize]; + UInt64 Va; + UInt64 Pa; + UInt64 VSize; + UInt64 PSize; + + UInt32 Flags; + int SegmentIndex; + + bool IsDummy; + + CSection(): IsDummy(false) {} + // UInt64 GetPackSize() const { return Flags == SECT_ATTR_ZEROFILL ? 0 : Size; } + UInt64 GetPackSize() const { return PSize; } +}; + + +class CHandler: + public IInArchive, + public IArchiveAllowTail, + public CMyUnknownImp +{ + CMyComPtr _inStream; + CObjectVector _segments; + CObjectVector _sections; + bool _allowTail; + bool _mode64; + bool _be; + UInt32 _cpuType; + UInt32 _cpuSubType; + UInt32 _type; + UInt32 _flags; + UInt32 _headersSize; + UInt64 _totalSize; + + HRESULT Open2(ISequentialInStream *stream); +public: + MY_UNKNOWN_IMP2(IInArchive, IArchiveAllowTail) + INTERFACE_IInArchive(;) + STDMETHOD(AllowTail)(Int32 allowTail); + CHandler(): _allowTail(false) {} +}; + +static const Byte kArcProps[] = +{ + kpidCpu, + kpidBit64, + kpidBigEndian, + kpidCharacts, + kpidHeadersSize +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidCharacts, + kpidOffset, + kpidVa +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + CPropVariant prop; + switch (propID) + { + case kpidShortComment: + case kpidCpu: + { + AString s; + char temp[16]; + UInt32 cpu = _cpuType & ~(UInt32)CPU_ARCH_ABI64; + UInt32 flag64 = _cpuType & (UInt32)CPU_ARCH_ABI64; + { + const char *n = NULL; + for (unsigned i = 0; i < ARRAY_SIZE(g_CpuPairs); i++) + { + const CUInt32PCharPair &pair = g_CpuPairs[i]; + if (pair.Value == cpu || pair.Value == _cpuType) + { + if (pair.Value == _cpuType) + flag64 = 0; + n = pair.Name; + break; + } + } + if (!n) + { + ConvertUInt32ToString(cpu, temp); + n = temp; + } + s = n; + + if (flag64 != 0) + s += " 64-bit"; + else if ((_cpuSubType & CPU_SUBTYPE_LIB64) && _cpuType != CPU_TYPE_AMD64) + s += " 64-bit-lib"; + } + 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 < ARRAY_SIZE(k_PowerPc_SubTypes)) + n = k_PowerPc_SubTypes[t]; + } + if (!n) + { + ConvertUInt32ToString(t, temp); + n = temp; + } + s.Add_Space(); + s += n; + } + prop = s; + break; + } + case kpidCharacts: + { + // TYPE_TO_PROP(g_FileTypes, _type, prop); break; + AString res (TypeToString(g_FileTypes, ARRAY_SIZE(g_FileTypes), _type)); + AString s (FlagsToString(g_ArcFlags, 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 AString GetName(const char *name) +{ + char res[kNameSize + 1]; + memcpy(res, name, kNameSize); + res[kNameSize] = 0; + return (AString)res; +} + + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + CPropVariant prop; + const CSection &item = _sections[index]; + switch (propID) + { + case kpidPath: + { + AString s (GetName(_segments[item.SegmentIndex].Name)); + if (!item.IsDummy) + s += GetName(item.Name); + prop = MultiByteToUnicodeString(s); + break; + } + case kpidSize: /* prop = (UInt64)item.VSize; break; */ + case kpidPackSize: prop = (UInt64)item.GetPackSize(); break; + case kpidCharacts: + if (!item.IsDummy) + { + AString res (TypeToString(g_SectTypes, ARRAY_SIZE(g_SectTypes), item.Flags & SECT_TYPE_MASK)); + AString s (FlagsToString(g_Flags, ARRAY_SIZE(g_Flags), item.Flags & SECT_ATTR_MASK)); + if (!s.IsEmpty()) + { + res.Add_Space(); + res += s; + } + prop = res; + } + break; + case kpidOffset: prop = item.Pa; break; + case kpidVa: prop = item.Va; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +HRESULT CHandler::Open2(ISequentialInStream *stream) +{ + const UInt32 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; + + UInt32 numCommands = Get32(header + 0x10, be); + 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; + 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 § = _sections.AddNew(); + sect.IsDummy = true; + sect.SegmentIndex = _segments.Size() - 1; + sect.Va = vmAddr; + sect.PSize = phSize; + sect.VSize = vmSize; + sect.Pa = phAddr; + sect.Flags = 0; + } + else do + { + UInt32 headSize = (cmd == CMD_SEGMENT_64) ? 0x50 : 0x44; + const Byte *p = buf + offs; + if (cmdSize - offs < headSize) + break; + CSection § = _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.Flags = Get32(p + f32Offset + 10, be); + if (sect.Flags == 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; +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(inStream)); + if (!_allowTail) + { + UInt64 fileSize; + RINOK(inStream->Seek(0, STREAM_SEEK_END, &fileSize)); + if (fileSize > _totalSize) + return S_FALSE; + } + _inStream = inStream; + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _totalSize = 0; + _inStream.Release(); + _sections.Clear(); + _segments.Clear(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _sections.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(_inStream); + + for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + const CSection &item = _sections[index]; + currentItemSize = item.GetPackSize(); + + CMyComPtr outStream; + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + if (!testMode && !outStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(_inStream->Seek(item.Pa, STREAM_SEEK_SET, NULL)); + streamSpec->Init(currentItemSize); + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + outStream.Release(); + RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP 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", 0, 0xDF, + k_Signature, + 0, + NArcInfoFlags::kMultiSignature | + NArcInfoFlags::kPreArc, + NULL) + +}} diff --git a/CPP/7zip/Archive/MbrHandler.cpp b/CPP/7zip/Archive/MbrHandler.cpp index 150070675..14a1224cd 100644 --- a/CPP/7zip/Archive/MbrHandler.cpp +++ b/CPP/7zip/Archive/MbrHandler.cpp @@ -1,445 +1,445 @@ -// MbrHandler.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#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; } -}; - -#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } - -// Chs in some MBRs contains only low bits of "Cyl number". So we disable check. -/* -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 += '-'; - s.Add_UInt32(Head); - s += '-'; - 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" - -static const CPartType kPartTypes[] = -{ - { 0x01, kFat, "FAT12" }, - { 0x04, kFat, "FAT16 DOS 3.0+" }, - { 0x05, 0, "Extended" }, - { 0x06, kFat, "FAT16 DOS 3.31+" }, - { 0x07, "ntfs", "NTFS" }, - { 0x0B, kFat, "FAT32" }, - { 0x0C, kFat, "FAT32-LBA" }, - { 0x0E, kFat, "FAT16-LBA" }, - { 0x0F, 0, "Extended-LBA" }, - { 0x11, kFat, "FAT12-Hidden" }, - { 0x14, kFat, "FAT16-Hidden < 32 MB" }, - { 0x16, kFat, "FAT16-Hidden >= 32 MB" }, - { 0x1B, kFat, "FAT32-Hidden" }, - { 0x1C, kFat, "FAT32-LBA-Hidden" }, - { 0x1E, kFat, "FAT16-LBA-WIN95-Hidden" }, - { 0x27, "ntfs", "NTFS-WinRE" }, - { 0x82, 0, "Solaris x86 / Linux swap" }, - { 0x83, 0, "Linux" }, - { 0x8E, "lvm", "Linux LVM" }, - { 0xA5, 0, "BSD slice" }, - { 0xBE, 0, "Solaris 8 boot" }, - { 0xBF, 0, "New Solaris x86" }, - { 0xC2, 0, "Linux-Hidden" }, - { 0xC3, 0, "Linux swap-Hidden" }, - { 0xEE, 0, "GPT" }, - { 0xEE, 0, "EFI" } -}; - -static int FindPartType(UInt32 type) -{ - for (unsigned i = 0; i < ARRAY_SIZE(kPartTypes); i++) - if (kPartTypes[i].Id == type) - return i; - return -1; -} - -struct CItem -{ - bool IsReal; - bool IsPrim; - UInt64 Size; - CPartition Part; -}; - -class CHandler: public CHandlerCont -{ - CObjectVector _items; - UInt64 _totalSize; - CByteBuffer _buffer; - - virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const - { - 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); -public: - INTERFACE_IInArchive_Cont(;) -}; - -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(stream->Seek(newPos, STREAM_SEEK_SET, NULL)); - 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; -} - -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) -{ - COM_TRY_BEGIN - Close(); - RINOK(stream->Seek(0, STREAM_SEEK_END, &_totalSize)); - RINOK(ReadTables(stream, 0, 0, 0)); - if (_items.IsEmpty()) - return S_FALSE; - UInt32 lbaLimit = _items.Back().Part.GetLimit(); - UInt64 lim = (UInt64)lbaLimit << 9; - if (lim < _totalSize) - { - CItem n; - n.Part.Lba = lbaLimit; - n.Size = _totalSize - lim; - n.IsReal = false; - _items.Add(n); - } - _stream = stream; - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _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 - -STDMETHODIMP 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 = i; - } - if (mainIndex >= 0) - prop = (UInt32)mainIndex; - break; - } - case kpidPhySize: prop = _totalSize; break; - } - prop.Detach(value); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - const CItem &item = _items[index]; - const CPartition &part = item.Part; - switch (propID) - { - case kpidPath: - { - AString s; - s.Add_UInt32(index); - if (item.IsReal) - { - s += '.'; - const char *ext = NULL; - 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; - 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", 0, 0xDB, - 0, - NArcInfoFlags::kPureStartOpen, - NULL) - -}} +// MbrHandler.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#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; } +}; + +#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } + +// Chs in some MBRs contains only low bits of "Cyl number". So we disable check. +/* +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 += '-'; + s.Add_UInt32(Head); + s += '-'; + 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" + +static const CPartType kPartTypes[] = +{ + { 0x01, kFat, "FAT12" }, + { 0x04, kFat, "FAT16 DOS 3.0+" }, + { 0x05, 0, "Extended" }, + { 0x06, kFat, "FAT16 DOS 3.31+" }, + { 0x07, "ntfs", "NTFS" }, + { 0x0B, kFat, "FAT32" }, + { 0x0C, kFat, "FAT32-LBA" }, + { 0x0E, kFat, "FAT16-LBA" }, + { 0x0F, 0, "Extended-LBA" }, + { 0x11, kFat, "FAT12-Hidden" }, + { 0x14, kFat, "FAT16-Hidden < 32 MB" }, + { 0x16, kFat, "FAT16-Hidden >= 32 MB" }, + { 0x1B, kFat, "FAT32-Hidden" }, + { 0x1C, kFat, "FAT32-LBA-Hidden" }, + { 0x1E, kFat, "FAT16-LBA-WIN95-Hidden" }, + { 0x27, "ntfs", "NTFS-WinRE" }, + { 0x82, 0, "Solaris x86 / Linux swap" }, + { 0x83, 0, "Linux" }, + { 0x8E, "lvm", "Linux LVM" }, + { 0xA5, 0, "BSD slice" }, + { 0xBE, 0, "Solaris 8 boot" }, + { 0xBF, 0, "New Solaris x86" }, + { 0xC2, 0, "Linux-Hidden" }, + { 0xC3, 0, "Linux swap-Hidden" }, + { 0xEE, 0, "GPT" }, + { 0xEE, 0, "EFI" } +}; + +static int FindPartType(UInt32 type) +{ + for (unsigned i = 0; i < ARRAY_SIZE(kPartTypes); i++) + if (kPartTypes[i].Id == type) + return i; + return -1; +} + +struct CItem +{ + bool IsReal; + bool IsPrim; + UInt64 Size; + CPartition Part; +}; + +class CHandler: public CHandlerCont +{ + CObjectVector _items; + UInt64 _totalSize; + CByteBuffer _buffer; + + virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const + { + 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); +public: + INTERFACE_IInArchive_Cont(;) +}; + +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(stream->Seek(newPos, STREAM_SEEK_SET, NULL)); + 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; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + RINOK(stream->Seek(0, STREAM_SEEK_END, &_totalSize)); + RINOK(ReadTables(stream, 0, 0, 0)); + if (_items.IsEmpty()) + return S_FALSE; + UInt32 lbaLimit = _items.Back().Part.GetLimit(); + UInt64 lim = (UInt64)lbaLimit << 9; + if (lim < _totalSize) + { + CItem n; + n.Part.Lba = lbaLimit; + n.Size = _totalSize - lim; + n.IsReal = false; + _items.Add(n); + } + _stream = stream; + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _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 + +STDMETHODIMP 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 = i; + } + if (mainIndex >= 0) + prop = (UInt32)mainIndex; + break; + } + case kpidPhySize: prop = _totalSize; break; + } + prop.Detach(value); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CItem &item = _items[index]; + const CPartition &part = item.Part; + switch (propID) + { + case kpidPath: + { + AString s; + s.Add_UInt32(index); + if (item.IsReal) + { + s += '.'; + const char *ext = NULL; + 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; + 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", 0, 0xDB, + 0, + NArcInfoFlags::kPureStartOpen, + NULL) + +}} diff --git a/CPP/7zip/Archive/MslzHandler.cpp b/CPP/7zip/Archive/MslzHandler.cpp index 5e3d515e2..6f9057a65 100644 --- a/CPP/7zip/Archive/MslzHandler.cpp +++ b/CPP/7zip/Archive/MslzHandler.cpp @@ -1,397 +1,397 @@ -// 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; - -class CHandler: - public IInArchive, - public IArchiveOpenSeq, - public CMyUnknownImp -{ - CMyComPtr _inStream; - CMyComPtr _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); -public: - MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq) - INTERFACE_IInArchive(;) - STDMETHOD(OpenSeq)(ISequentialInStream *stream); -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidPackSize, -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = 1; - return S_OK; -} - -STDMETHODIMP 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 -} - - -STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidPath: if (!_name.IsEmpty()) prop = _name; break; - case kpidSize: 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; - CMyComPtr volumeCallback; - callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback); - 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 < 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 = ext[2]; - break; - } - } - } - - if (replaceByte >= 0x20 && replaceByte < 0x80) - _name += (char)replaceByte; -} - -STDMETHODIMP 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(stream->Seek(0, STREAM_SEEK_END, &_originalFileSize)); - _packSize = _originalFileSize; - - ParseName(buffer[kSignatureSize], callback); - - _isArc = true; - _unpackSize_Defined = true; - _inStream = stream; - _seqStream = stream; - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP 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; -} - -STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) -{ - COM_TRY_BEGIN - Close(); - _isArc = true; - _seqStream = stream; - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - // extractCallback->SetTotal(_unpackSize); - - CMyComPtr 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 outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(); - realOutStream.Release(); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - if (_needSeekToStart) - { - if (!_inStream) - return E_FAIL; - RINOK(_inStream->Seek(0, STREAM_SEEK_SET, NULL)); - } - 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", 0, 0xD5, - kSignature, - 0, - 0, - NULL) - -}} +// 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; + +class CHandler: + public IInArchive, + public IArchiveOpenSeq, + public CMyUnknownImp +{ + CMyComPtr _inStream; + CMyComPtr _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); +public: + MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq) + INTERFACE_IInArchive(;) + STDMETHOD(OpenSeq)(ISequentialInStream *stream); +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1; + return S_OK; +} + +STDMETHODIMP 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 +} + + +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidPath: if (!_name.IsEmpty()) prop = _name; break; + case kpidSize: 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; + CMyComPtr volumeCallback; + callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback); + 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 < 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 = ext[2]; + break; + } + } + } + + if (replaceByte >= 0x20 && replaceByte < 0x80) + _name += (char)replaceByte; +} + +STDMETHODIMP 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(stream->Seek(0, STREAM_SEEK_END, &_originalFileSize)); + _packSize = _originalFileSize; + + ParseName(buffer[kSignatureSize], callback); + + _isArc = true; + _unpackSize_Defined = true; + _inStream = stream; + _seqStream = stream; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP 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; +} + +STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) +{ + COM_TRY_BEGIN + Close(); + _isArc = true; + _seqStream = stream; + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + // extractCallback->SetTotal(_unpackSize); + + CMyComPtr 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 outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + realOutStream.Release(); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + if (_needSeekToStart) + { + if (!_inStream) + return E_FAIL; + RINOK(_inStream->Seek(0, STREAM_SEEK_SET, NULL)); + } + 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", 0, 0xD5, + kSignature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/MubHandler.cpp b/CPP/7zip/Archive/MubHandler.cpp index 347d3e2c9..6d0543567 100644 --- a/CPP/7zip/Archive/MubHandler.cpp +++ b/CPP/7zip/Archive/MubHandler.cpp @@ -1,246 +1,246 @@ -// MubHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyString.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "HandlerCont.h" - -static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); } - -using namespace NWindows; -using namespace NCOM; - -namespace NArchive { -namespace NMub { - -#define MACH_CPU_ARCH_ABI64 (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 (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 = 10; - -class CHandler: public CHandlerCont -{ - // 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 - { - const CItem &item = _items[index]; - pos = item.Offset; - size = item.Size; - return NExtract::NOperationResult::kOK; - } - -public: - INTERFACE_IInArchive_Cont(;) -}; - -static const Byte kArcProps[] = -{ - kpidBigEndian -}; - -static const Byte kProps[] = -{ - kpidSize -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP 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; -} - -STDMETHODIMP 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 = 0; - 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'; - ConvertUInt32ToString(item.Type & ~MACH_CPU_ARCH_ABI64, temp + 3); - if (item.Type & MACH_CPU_ARCH_ABI64) - MyStringCopy(temp + MyStringLen(temp), "_64"); - break; - } - if (ext) - strcpy(temp, ext); - if (item.SubType != 0 && ( - 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; - } - return S_OK; -} - -HRESULT CHandler::Open2(IInStream *stream) -{ - // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPos)); - - const UInt32 kHeaderSize = 8; - const UInt32 kRecordSize = 5 * 4; - const UInt32 kBufSize = kHeaderSize + kNumFilesMax * kRecordSize; - Byte buf[kBufSize]; - size_t processed = kBufSize; - RINOK(ReadStream(stream, buf, &processed)); - if (processed < kHeaderSize) - return S_FALSE; - - bool be; - switch (GetBe32(buf)) - { - case 0xCAFEBABE: be = true; break; - case 0xB9FAF10E: be = false; break; - default: return S_FALSE; - } - _bigEndian = be; - UInt32 num = Get32(buf + 4, be); - 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 Byte *p = buf + kHeaderSize + i * kRecordSize; - CItem &sb = _items[i]; - sb.Type = Get32(p, be); - sb.SubType = Get32(p + 4, be); - sb.Offset = Get32(p + 8, be); - sb.Size = Get32(p + 12, be); - UInt32 align = Get32(p + 16, be); - 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; - - UInt64 endPos = (UInt64)sb.Offset + sb.Size; - if (endPosMax < endPos) - endPosMax = endPos; - } - _numItems = num; - _phySize = endPosMax; - return S_OK; -} - -STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) -{ - COM_TRY_BEGIN - Close(); - try - { - if (Open2(inStream) != S_OK) - return S_FALSE; - _stream = inStream; - } - catch(...) { return S_FALSE; } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _stream.Release(); - _numItems = 0; - _phySize = 0; - return S_OK; -} - -STDMETHODIMP 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", 0, 0xE2, - k_Signature, - 0, - NArcInfoFlags::kMultiSignature, - NULL) - -} - -}} +// MubHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyString.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); } + +using namespace NWindows; +using namespace NCOM; + +namespace NArchive { +namespace NMub { + +#define MACH_CPU_ARCH_ABI64 (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 (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 = 10; + +class CHandler: public CHandlerCont +{ + // 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 + { + const CItem &item = _items[index]; + pos = item.Offset; + size = item.Size; + return NExtract::NOperationResult::kOK; + } + +public: + INTERFACE_IInArchive_Cont(;) +}; + +static const Byte kArcProps[] = +{ + kpidBigEndian +}; + +static const Byte kProps[] = +{ + kpidSize +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP 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; +} + +STDMETHODIMP 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 = 0; + 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'; + ConvertUInt32ToString(item.Type & ~MACH_CPU_ARCH_ABI64, temp + 3); + if (item.Type & MACH_CPU_ARCH_ABI64) + MyStringCopy(temp + MyStringLen(temp), "_64"); + break; + } + if (ext) + strcpy(temp, ext); + if (item.SubType != 0 && ( + 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; + } + return S_OK; +} + +HRESULT CHandler::Open2(IInStream *stream) +{ + // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPos)); + + const UInt32 kHeaderSize = 8; + const UInt32 kRecordSize = 5 * 4; + const UInt32 kBufSize = kHeaderSize + kNumFilesMax * kRecordSize; + Byte buf[kBufSize]; + size_t processed = kBufSize; + RINOK(ReadStream(stream, buf, &processed)); + if (processed < kHeaderSize) + return S_FALSE; + + bool be; + switch (GetBe32(buf)) + { + case 0xCAFEBABE: be = true; break; + case 0xB9FAF10E: be = false; break; + default: return S_FALSE; + } + _bigEndian = be; + UInt32 num = Get32(buf + 4, be); + 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 Byte *p = buf + kHeaderSize + i * kRecordSize; + CItem &sb = _items[i]; + sb.Type = Get32(p, be); + sb.SubType = Get32(p + 4, be); + sb.Offset = Get32(p + 8, be); + sb.Size = Get32(p + 12, be); + UInt32 align = Get32(p + 16, be); + 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; + + UInt64 endPos = (UInt64)sb.Offset + sb.Size; + if (endPosMax < endPos) + endPosMax = endPos; + } + _numItems = num; + _phySize = endPosMax; + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + try + { + if (Open2(inStream) != S_OK) + return S_FALSE; + _stream = inStream; + } + catch(...) { return S_FALSE; } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _stream.Release(); + _numItems = 0; + _phySize = 0; + return S_OK; +} + +STDMETHODIMP 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", 0, 0xE2, + k_Signature, + 0, + NArcInfoFlags::kMultiSignature, + NULL) + +} + +}} diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.cpp b/CPP/7zip/Archive/Nsis/NsisDecode.cpp index 37cc04462..e2822184e 100644 --- a/CPP/7zip/Archive/Nsis/NsisDecode.cpp +++ b/CPP/7zip/Archive/Nsis/NsisDecode.cpp @@ -1,295 +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 (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::CCoder(false); - } - 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 setInStream; - _codecInStream.QueryInterface(IID_ICompressSetInStream, &setInStream); - if (!setInStream) - return E_NOTIMPL; - RINOK(setInStream->SetInStream(inStream)); - } - - { - CMyComPtr 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 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; -} - -}} +// 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 (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::CCoder(false); + } + 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 setInStream; + _codecInStream.QueryInterface(IID_ICompressSetInStream, &setInStream); + if (!setInStream) + return E_NOTIMPL; + RINOK(setInStream->SetInStream(inStream)); + } + + { + CMyComPtr 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 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 index 4b66f0a66..2153d785b 100644 --- a/CPP/7zip/Archive/Nsis/NsisDecode.h +++ b/CPP/7zip/Archive/Nsis/NsisDecode.h @@ -1,97 +1,97 @@ -// NsisDecode.h - -#ifndef __NSIS_DECODE_H -#define __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 _filterInStream; - CMyComPtr _codecInStream; - CMyComPtr _decoderInStream; - - NCompress::NBZip2::CNsisDecoder *_bzDecoder; - NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoder; - NCompress::NLzma::CDecoder *_lzmaDecoder; - -public: - CMyComPtr 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 +// NsisDecode.h + +#ifndef __NSIS_DECODE_H +#define __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 _filterInStream; + CMyComPtr _codecInStream; + CMyComPtr _decoderInStream; + + NCompress::NBZip2::CNsisDecoder *_bzDecoder; + NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoder; + NCompress::NLzma::CDecoder *_lzmaDecoder; + +public: + CMyComPtr 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 index e5cf24bd4..095105fe5 100644 --- a/CPP/7zip/Archive/Nsis/NsisHandler.cpp +++ b/CPP/7zip/Archive/Nsis/NsisHandler.cpp @@ -1,686 +1,686 @@ -// 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, - kpidHeadersSize, - kpidEmbeddedStubSize, - kpidSubType - // kpidCodePage -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - - -static AString UInt32ToString(UInt32 val) -{ - char s[16]; - ConvertUInt32ToString(val, s); - return (AString)s; -} - -static AString GetStringForSizeValue(UInt32 val) -{ - for (int i = 31; i >= 0; i--) - if (((UInt32)1 << i) == val) - return UInt32ToString(i); - char c = 'b'; - if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } - else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } - return UInt32ToString(val) + c; -} - -static AString GetMethod(bool useFilter, NMethodType::EEnum method, UInt32 dict) -{ - AString s; - if (useFilter) - { - s += kBcjMethod; - s.Add_Space(); - } - s += ((unsigned)method < ARRAY_SIZE(kMethods)) ? kMethods[(unsigned)method] : kUnknownMethod; - if (method == NMethodType::kLZMA) - { - s += ':'; - s += GetStringForSizeValue(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 < ARRAY_SIZE(kMethods)) ? kMethods[method] : kUnknownMethod; - if (method == NMethodType::kLZMA) - { - s += ':'; - s += GetStringForSizeValue(_archive.IsSolid ? _archive.DictionarySize: dictionary); - } - return s; -} -*/ - -STDMETHODIMP 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 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 += '.'; - 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 -} - - -STDMETHODIMP 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 -} - -STDMETHODIMP CHandler::Close() -{ - _archive.Clear(); - _archive.Release(); - return S_OK; -} - -STDMETHODIMP 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 - 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; -} - - -STDMETHODIMP 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, CByteBuffer &dest) -{ - for (;;) - { - if (size < 4) - return false; - UInt32 len = Get32(p); - if (len == 0) - return size == 4; - if (size < 8) - return false; - UInt32 offs = Get32(p + 4); - p += 8; - size -= 8; - if (size < len || offs > dest.Size() || len > dest.Size() - offs) - return false; - memcpy(dest + offs, p, len); - p += len; - size -= len; - } -} - - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - 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++) - { - 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 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(¤tTotalSize)); - CMyComPtr realOutStream; - 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 = !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) - { - UInt32 next = allFilesMode ? i + 1 : indices[i + 1]; - if (next < _archive.Items.Size()) - { - UInt64 nextPos = _archive.GetPosOfSolidItem(next); - if (nextPos == pos) - { - writeToTemp = true; - tempPos = pos; - } - } - } - } - prevPos = pos; - } - - if (!dataError) - { - // UInt32 unpackSize = 0; - // bool unpackSize_Defined = false; - bool writeToTemp1 = writeToTemp; - if (item.IsUninstaller) - { - // 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 && !item.IsUninstaller) - RINOK(WriteStream(realOutStream, tempBuf, tempBuf.Size())); - } - else - { - UInt32 curUnpacked32 = 0; - HRESULT res = _archive.Decoder.Decode( - writeToTemp1 ? &tempBuf : NULL, - item.IsUninstaller, item.PatchSize, - item.IsUninstaller ? 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 && item.IsUninstaller) - { - if (_archive.ExeStub.Size() != 0) - { - CByteBuffer destBuf = _archive.ExeStub; - dataError = !UninstallerPatch(tempBuf, tempBuf.Size(), destBuf); - - 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 )); - } - - 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 -} - -}} +// 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, + kpidHeadersSize, + kpidEmbeddedStubSize, + kpidSubType + // kpidCodePage +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + + +static AString UInt32ToString(UInt32 val) +{ + char s[16]; + ConvertUInt32ToString(val, s); + return (AString)s; +} + +static AString GetStringForSizeValue(UInt32 val) +{ + for (int i = 31; i >= 0; i--) + if (((UInt32)1 << i) == val) + return UInt32ToString(i); + char c = 'b'; + if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } + else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } + return UInt32ToString(val) + c; +} + +static AString GetMethod(bool useFilter, NMethodType::EEnum method, UInt32 dict) +{ + AString s; + if (useFilter) + { + s += kBcjMethod; + s.Add_Space(); + } + s += ((unsigned)method < ARRAY_SIZE(kMethods)) ? kMethods[(unsigned)method] : kUnknownMethod; + if (method == NMethodType::kLZMA) + { + s += ':'; + s += GetStringForSizeValue(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 < ARRAY_SIZE(kMethods)) ? kMethods[method] : kUnknownMethod; + if (method == NMethodType::kLZMA) + { + s += ':'; + s += GetStringForSizeValue(_archive.IsSolid ? _archive.DictionarySize: dictionary); + } + return s; +} +*/ + +STDMETHODIMP 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 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 += '.'; + 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 +} + + +STDMETHODIMP 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 +} + +STDMETHODIMP CHandler::Close() +{ + _archive.Clear(); + _archive.Release(); + return S_OK; +} + +STDMETHODIMP 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 + 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; +} + + +STDMETHODIMP 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, CByteBuffer &dest) +{ + for (;;) + { + if (size < 4) + return false; + UInt32 len = Get32(p); + if (len == 0) + return size == 4; + if (size < 8) + return false; + UInt32 offs = Get32(p + 4); + p += 8; + size -= 8; + if (size < len || offs > dest.Size() || len > dest.Size() - offs) + return false; + memcpy(dest + offs, p, len); + p += len; + size -= len; + } +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + 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++) + { + 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 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(¤tTotalSize)); + CMyComPtr realOutStream; + 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 = !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) + { + UInt32 next = allFilesMode ? i + 1 : indices[i + 1]; + if (next < _archive.Items.Size()) + { + UInt64 nextPos = _archive.GetPosOfSolidItem(next); + if (nextPos == pos) + { + writeToTemp = true; + tempPos = pos; + } + } + } + } + prevPos = pos; + } + + if (!dataError) + { + // UInt32 unpackSize = 0; + // bool unpackSize_Defined = false; + bool writeToTemp1 = writeToTemp; + if (item.IsUninstaller) + { + // 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 && !item.IsUninstaller) + RINOK(WriteStream(realOutStream, tempBuf, tempBuf.Size())); + } + else + { + UInt32 curUnpacked32 = 0; + HRESULT res = _archive.Decoder.Decode( + writeToTemp1 ? &tempBuf : NULL, + item.IsUninstaller, item.PatchSize, + item.IsUninstaller ? 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 && item.IsUninstaller) + { + if (_archive.ExeStub.Size() != 0) + { + CByteBuffer destBuf = _archive.ExeStub; + dataError = !UninstallerPatch(tempBuf, tempBuf.Size(), destBuf); + + 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 )); + } + + 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 index c3afd73d8..1eb8b731a 100644 --- a/CPP/7zip/Archive/Nsis/NsisHandler.h +++ b/CPP/7zip/Archive/Nsis/NsisHandler.h @@ -1,36 +1,36 @@ -// NSisHandler.h - -#ifndef __NSIS_HANDLER_H -#define __NSIS_HANDLER_H - -#include "../../../Common/MyCom.h" - -#include "../../Common/CreateCoder.h" - -#include "../IArchive.h" - -#include "NsisIn.h" - -namespace NArchive { -namespace NNsis { - -class CHandler: - public IInArchive, - public CMyUnknownImp -{ - 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; -public: - MY_UNKNOWN_IMP1(IInArchive) - - INTERFACE_IInArchive(;) -}; - -}} - -#endif +// NSisHandler.h + +#ifndef __NSIS_HANDLER_H +#define __NSIS_HANDLER_H + +#include "../../../Common/MyCom.h" + +#include "../../Common/CreateCoder.h" + +#include "../IArchive.h" + +#include "NsisIn.h" + +namespace NArchive { +namespace NNsis { + +class CHandler: + public IInArchive, + public CMyUnknownImp +{ + 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; +public: + MY_UNKNOWN_IMP1(IInArchive) + + INTERFACE_IInArchive(;) +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Nsis/NsisIn.cpp b/CPP/7zip/Archive/Nsis/NsisIn.cpp index 62eb22647..f4f9ab04e 100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.cpp +++ b/CPP/7zip/Archive/Nsis/NsisIn.cpp @@ -1,5916 +1,5916 @@ -// NsisIn.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringToInt.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/StreamUtils.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 - EW_PUSHPOP, // Push/Pop/Exchange - EW_FINDWINDOW, // FindWindow - EW_SENDMESSAGE, // SendMessage - EW_ISWINDOW, // IsWindow - EW_GETDLGITEM, // GetDlgItem - EW_SETCTLCOLORS, // SetCtlColors - EW_SETBRANDINGIMAGE, // SetBrandingImage - 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 - - // instructions not actually implemented in exehead, but used in compiler. - EW_GETLABELADDR, // both of these get converted to EW_ASSIGNVAR - EW_GETFUNCTIONADDR, - - EW_LOCKWINDOW, // LockWindow - - // 2 unicode commands available only in Unicode archive - EW_FPUTWS, // FileWriteUTF16LE, FileWriteWord - EW_FGETWS, // FileReadUTF16LE, FileReadWord - - // 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 -}; - -static const unsigned kNumAdditionalParkCmds = 3; - -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" }, - { 3 }, // "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" }, - { 3 }, // "SetBrandingImage" }, - { 5 }, // "CreateFont" }, - { 4 }, // ShowWindow, EnableWindow, HideWindow - { 6 }, // "ExecShell" }, - { 3 }, // "Exec" }, // Exec, ExecWait - { 3 }, // "GetFileTime" }, - { 3 }, // "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" }, - { 2 }, // "GetFunctionAddress" }, - { 1 }, // "LockWindow" }, - { 3 }, // "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 - , "IntCmp" - , "IntOp" - , "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 - , "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; - - UInt32 start = _stringsPos + (IsUnicode ? param * 2 : param); - 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, langID); - } - else if (++_numRootLicenses > 1) - { - fileName += '-'; - UIntToString(fileName, _numRootLicenses); - } - const Byte *sz = (_data + start); - unsigned marker = IsUnicode ? Get16(sz) : *sz; - 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; - 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 - - -#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 -#define kVar_HWNDPARENT 29 - -// #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 + 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) (((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 < ARRAY_SIZE(kShellStrings)) - { - const char *sz = kShellStrings[index1]; - if (sz) - { - s += sz; - return; - } - } - if (index2 < 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, -((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, -((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); // _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(-((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 MY__MB_ABORTRETRYIGNORE 2 -#define MY__MB_RETRYCANCEL 5 - -static const char * const k_MB_Buttons[] = -{ - "OK" - , "OKCANCEL" - , "ABORTRETRYIGNORE" - , "YESNOCANCEL" - , "YESNO" - , "RETRYCANCEL" - , "CANCELTRYCONTINUE" -}; - -#define MY__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 MY__IDCANCEL 2 -#define MY__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 < 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_CtlColors_Size = 24; - -struct CNsis_CtlColors -{ - UInt32 text; // COLORREF - UInt32 bkc; // COLORREF - UInt32 lbStyle; - UInt32 bkb; // HBRUSH - Int32 bkmode; - Int32 flags; - - void Parse(const Byte *p); -}; - -void CNsis_CtlColors::Parse(const Byte *p) -{ - text = Get32(p); - bkc = Get32(p + 4); - lbStyle = Get32(p + 8); - bkb = Get32(p + 12); - bkmode = (Int32)Get32(p + 16); - flags = (Int32)Get32(p + 20); -} - -// Win32 constants -#define MY__TRANSPARENT 1 -#define MY__OPAQUE 2 - -#define MY__GENERIC_READ (1 << 31) -#define MY__GENERIC_WRITE (1 << 30) -#define MY__GENERIC_EXECUTE (1 << 29) -#define MY__GENERIC_ALL (1 << 28) - -#define MY__CREATE_NEW 1 -#define MY__CREATE_ALWAYS 2 -#define MY__OPEN_EXISTING 3 -#define MY__OPEN_ALWAYS 4 -#define MY__TRUNCATE_EXISTING 5 - -// 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 MY__SW_HIDE 0 -#define MY__SW_SHOWNORMAL 1 - -#define MY__SW_SHOWMINIMIZED 2 -#define MY__SW_SHOWMINNOACTIVE 7 -#define MY__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 < ARRAY_SIZE(kShowWindow_Commands)) - { - s += "SW_"; - s += kShowWindow_Commands[cmd]; - } - else - UIntToString(s, cmd); -} - -void CInArchive::Add_ShowWindow_Cmd(UInt32 cmd) -{ - if (cmd < 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, 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 §, 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 (int 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 < 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 < ARRAY_SIZE(k_MB_Icons) && k_MB_Icons[icon] != 0) - 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 < 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; -} - -#endif - -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 - - -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 (LogCmdIsEnabled) - AddString(s, "log"); - if (BadCmd >= 0) - { - AddString(s, "BadCmd="); - UIntToString(s, BadCmd); - } - return s; -} - -#ifdef NSIS_SCRIPT - -unsigned CInArchive::GetNumSupportedCommands() const -{ - unsigned numCmds = IsPark() ? kNumCmds : 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) - { - UInt32 id = GetCmd(Get32(p)); - if (id >= kNumCmds) - continue; - if (BadCmd >= 0 && id >= (unsigned)BadCmd) - continue; - unsigned i; - if (id == EW_GETLABELADDR || - id == EW_GETFUNCTIONADDR) - { - BadCmd = id; - continue; - } - for (i = 6; i != 0; i--) - { - UInt32 param = Get32(p + i * 4); - if (param != 0) - break; - } - if (id == EW_FINDPROC && i == 0) - { - BadCmd = id; - continue; - } - if (k_Commands[id].NumParams < i) - BadCmd = 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; - - unsigned c0 = p[1]; - if (c0 == 0) - return -1; - unsigned c1 = p[2]; - if (c1 == 0) - return -1; - return 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 -bool IsDrivePath(const wchar_t *s) { return IS_LETTER_CHAR(s[0]) && s[1] == ':' /* && s[2] == '\\' */ ; } -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); - bool isAbs = IsAbsolutePathVar(strPos); - if (IsUnicode) - { - item.NameU = Raw_UString; - if (!isAbs && !IsAbsolutePath(Raw_UString)) - item.Prefix = UPrefixes.Size() - 1; - } - else - { - item.NameA = Raw_AString; - if (!isAbs && !IsAbsolutePath(Raw_AString)) - item.Prefix = APrefixes.Size() - 1; - } -} - -HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) -{ - #ifdef NSIS_SCRIPT - CDynLimBuf &s = Script; - - CObjArray 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 < 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 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 §ion = 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 >= ARRAY_SIZE(k_InitPluginDir_Commands) - && CompareCommands(p, k_InitPluginDir_Commands, ARRAY_SIZE(k_InitPluginDir_Commands))) - { - InitPluginsDir_Start = kkk; - InitPluginsDir_End = kkk + 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 § = 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 < 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) - { - 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 == (MY__MB_ABORTRETRYIGNORE | MY__MB_ICONSTOP) && (b1 == MY__IDIGNORE || b2 == MY__IDIGNORE)) - asf = -1; - else if (mb == (MY__MB_RETRYCANCEL | MY__MB_ICONSTOP) && (b1 == MY__IDCANCEL || b2 == MY__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, 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 */ - - bool pathOk = (params[0] > 0) && IsGoodString(params[0]); - - if (!pathOk) - { - #ifdef NSIS_SCRIPT - AddError("bad path"); - #endif - break; - } - - bool altPathOk = true; - - UInt32 altParam = params[3]; - if (altParam != 0) - { - altPathOk = false; - UInt32 additional = 0; - if (GetVarIndexFinished(altParam, '\\', additional) == kVar_INSTDIR) - altPathOk = AreTwoParamStringsEqual(altParam + additional, params[0]); - } - - - #ifdef NSIS_SCRIPT - - AddParam(params[0]); - - /* - for (int i = 1; i < 3; i++) - AddParam_UInt(params[i]); - */ - - if (params[3] != 0) - { - SmallSpaceComment(); - AddParam(params[3]); - } - - #endif - - if (!altPathOk) - { - #ifdef NSIS_SCRIPT - AddError("alt path error"); - #endif - } - - if (BadCmd >= 0 && BadCmd <= EW_WRITEUNINSTALLER) - { - /* We don't 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; - - /* - // 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 § = 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 *pCmd = p + kCmdSize * (j - kkk); - AddParam(GET_CMD_PARAM(pCmd, 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(-((Int32)params[0] + 1)); - else if (params[0] == 0) - s += '0'; - else - { - 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] == MY__SW_SHOWNA && params[1] == MY__SW_HIDE) s += " show"; - else if (params[1] == MY__SW_SHOWNA && params[0] == MY__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(¶ms[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"; - } - if (s2) - { - s += ' '; - s += s2; - break; - } - } - SpaceQuStr(temp); - break; - } - - case EW_IFFLAG: - { - Add_ExecFlags(params[2]); - Add_GotoVars2(¶ms[0]); - /* - static 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(¶ms[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: - { - if (params[5] != 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 - UInt32 opIndex = params[3]; - char c = (opIndex < 13) ? kOps[opIndex] : '?'; - char c2 = (opIndex < 8 || opIndex == 10) ? (char)0 : c; - 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 (c2 != 0) - s += c2; - AddParam(params[2]); - } - break; - } - - case EW_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(¶ms[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 < k_CtlColors_Size) - { - AddError("bad offset"); - break; - } - - const Byte *p2 = _data + bhCtlColors.Offset + offset; - CNsis_CtlColors colors; - colors.Parse(p2); - - if ((colors.flags & kColorsFlags_BK_SYS) != 0 || - (colors.flags & kColorsFlags_TEXT_SYS) != 0) - s += " /BRANDING"; - - AString bk; - bool bkc = false; - if (colors.bkmode == MY__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_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 < 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] != MY__SW_SHOWNORMAL) - { - AddParam(params[2]); - if (params[3] != MY__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: - { - 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; - for (numParams = 6; numParams > 2; numParams--) - if (params[numParams - 1] != 0) - break; - - UInt32 spec = params[4]; - if (spec & 0x8000) // NSIS 3.0b0 - s += " /NoWorkingDir"; - - AddParams(params, numParams > 4 ? 4 : numParams); - if (numParams <= 4) - break; - - UInt32 icon = (spec & 0xFF); - Space(); - if (icon != 0) - Add_UInt(icon); - else - AddQuotes(); - - if ((spec >> 8) == 0 && numParams < 6) - break; - UInt32 sw = (spec >> 8) & 0x7F; - Space(); - // NSIS encoder replaces these names: - if (sw == MY__SW_SHOWMINNOACTIVE) - sw = MY__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|"; - - static 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"; - } - AddRegRoot(params[1]); - AddParam(params[2]); - AddOptionalParam(params[3]); - break; - } - - case EW_WRITEREG: - { - const char *s2 = 0; - 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 (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; - } - - case EW_FOPEN: - { - AddParam_Var(params[0]); - AddParam(params[3]); - UInt32 acc = params[1]; // dwDesiredAccess - UInt32 creat = params[2]; // dwCreationDisposition - if (acc == 0 && creat == 0) - break; - char cc = 0; - if (acc == MY__GENERIC_READ && creat == OPEN_EXISTING) - cc = 'r'; - else if (creat == CREATE_ALWAYS && acc == MY__GENERIC_WRITE) - cc = 'w'; - else if (creat == OPEN_ALWAYS && (acc == (MY__GENERIC_WRITE | MY__GENERIC_READ))) - cc = 'a'; - // cc = 0; - if (cc != 0) - { - Space(); - s += cc; - break; - } - - if (acc & MY__GENERIC_READ) s += " GENERIC_READ"; - if (acc & MY__GENERIC_WRITE) s += " GENERIC_WRITE"; - if (acc & MY__GENERIC_EXECUTE) s += " GENERIC_EXECUTE"; - if (acc & MY__GENERIC_ALL) s += " GENERIC_ALL"; - - const char *s2 = NULL; - switch (creat) - { - case MY__CREATE_NEW: s2 = "CREATE_NEW"; break; - case MY__CREATE_ALWAYS: s2 = "CREATE_ALWAYS"; break; - case MY__OPEN_EXISTING: s2 = "OPEN_EXISTING"; break; - case MY__OPEN_ALWAYS: s2 = "OPEN_ALWAYS"; break; - case MY__TRUNCATE_EXISTING: s2 = "TRUNCATE_EXISTING"; break; - } - Space(); - if (s2) - s += s2; - else - Add_UInt(creat); - break; - } - - case EW_FPUTS: - case EW_FPUTWS: - { - if (commandId == EW_FPUTWS) - s += (params[2] == 0) ? "UTF16LE" : "Word"; - else if (params[2] != 0) - s += "Byte"; - 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]); - } - } - - case EW_SECTIONSET: - { - if ((Int32)params[2] >= 0) - { - s += "Get"; - Add_SectOp(params[2]); - AddParam(params[0]); - AddParam_Var(params[1]); - } - else - { - s += "Set"; - UInt32 t = -(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: - { - int 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_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 § = Sections[curSectionIndex]; - if (sect.StartCmdIndex + sect.NumCommands + 1 == kkk) - { - PrintSectionEnd(); - sectionIsOpen = false; - // lastSectionEndCmd = kkk; - curSectionIndex++; - } - } - } - - while (curSectionIndex < bhSections.Num) - { - const CSection § = Sections[curSectionIndex]; - if (sectionIsOpen) - { - if (sect.StartCmdIndex + sect.NumCommands != kkk) - AddErrorLF("SECTION ERROR"); - PrintSectionEnd(); - sectionIsOpen = false; - curSectionIndex++; - } - else - { - if (curSectionIndex == 49) - curSectionIndex = curSectionIndex; - - 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 = **(CItem **)p1; - const CItem &i2 = **(CItem **)p2; - RINOZ(MyCompare(i1.Pos, i2.Pos)); - 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]; - 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]; - UInt32 curPos = item.Pos + 4; - for (unsigned nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++) - { - UInt32 nextPos = Items[nextIndex].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]; - 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; -} - -// 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 -}; - -HRESULT CInArchive::Parse() -{ - // UInt32 offset = ReadUInt32(); - // ???? offset == FirstHeader.HeaderSize - const Byte *p = _data; - - if (_size < 4 + 8 * 8) - return S_FALSE; - - CBlockHeader bhEntries, bhStrings, bhLangTables; - bhEntries.Parse(p + 4 + 8 * 2); - bhStrings.Parse(p + 4 + 8 * 3); - bhLangTables.Parse(p + 4 + 8 * 4); - - #ifdef NSIS_SCRIPT - - CBlockHeader bhFont; - bhPages.Parse(p + 4 + 8 * 0); - bhSections.Parse(p + 4 + 8 * 1); - bhCtlColors.Parse(p + 4 + 8 * 5); - bhFont.Parse(p + 4 + 8 * 6); - bhData.Parse(p + 4 + 8 * 7); - - #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 (IsUnicode) - AddStringLF("Unicode true"); - - if (Method != NMethodType::kCopy) - { - const char *m = NULL; - switch (Method) - { - case NMethodType::kDeflate: m = "zlib"; break; - case NMethodType::kBZip2: m = "bzip2"; break; - case NMethodType::kLZMA: m = "lzma"; 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(p); - 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 = 4 + 8 * 8; - if (bhPages.Offset == 276) - paramsOffset -= 8; - - const Byte *p2 = p + 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 != -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(); - } - - UInt32 langtable_size = Get32(p2 + 32); - if (bhLangTables.Num > 0) - { - if (langtable_size == (UInt32)(Int32)-1) - return E_NOTIMPL; // maybe it's old NSIS archive() - - UInt32 numStrings = (langtable_size - 10) / 4; - _numLangStrings = numStrings; - AddLF(); - Separator(); - PrintNumComment("LANG TABLES", bhLangTables.Num); - PrintNumComment("LANG STRINGS", numStrings); - AddLF(); - - if (licenseLangIndex >= 0) - { - for (UInt32 i = 0; i < bhLangTables.Num; i++) - { - const Byte *p = _data + bhLangTables.Offset + langtable_size * i; - LANGID langID = Get16(p); - UInt32 val = Get32(p + 10 + (UInt32)licenseLangIndex * 4); - if (val != 0) - { - Script += "LicenseLangString "; - Add_LangStr_Simple(licenseLangIndex); - AddParam_UInt(langID); - AddLicense(val, langID); - noParseStringIndexes.AddToUniqueSorted(val); - NewLine(); - } - } - AddLF(); - } - - UInt32 brandingText = 0; - UInt32 caption = 0; - UInt32 name = 0; - UInt32 i; - for (i = 0; i < bhLangTables.Num; i++) - { - const Byte *p = _data + bhLangTables.Offset + langtable_size * i; - LANGID langID = Get16(p); - if (i == 0 || langID == 1033) - _mainLang = p + 10; - { - UInt32 v = Get32(p + 10 + 0 * 4); - if (v != 0 && (langID == 1033 || brandingText == 0)) - brandingText = v; - } - { - UInt32 v = Get32(p + 10 + 1 * 4); - if (v != 0 && (langID == 1033 || caption == 0)) - caption = v; - } - { - UInt32 v = Get32(p + 10 + 2 * 4); - if (v != 0 && (langID == 1033 || name == 0)) - name = v; - } - } - - if (name != 0) - { - Script += "Name"; - AddParam(name); - NewLine(); - - ReadString2(Name, name); - } - - /* - if (caption != 0) - { - Script += "Caption"; - AddParam(caption); - NewLine(); - } - */ - - if (brandingText != 0) - { - Script += "BrandingText"; - AddParam(brandingText); - NewLine(); - - ReadString2(BrandingText, brandingText); - } - - for (i = 0; i < bhLangTables.Num; i++) - { - const Byte *p = _data + bhLangTables.Offset + langtable_size * i; - LANGID 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 = 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->Seek(0, STREAM_SEEK_CUR, &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->Seek(posCur, STREAM_SEEK_SET, NULL)); - 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->Seek(pos, STREAM_SEEK_SET, NULL)); - 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 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; - - RINOK(inStream->Seek(0, STREAM_SEEK_END, &_fileSize)); - - IsArc = true; - - if (peSize != 0) - { - ExeStub.Alloc(peSize); - RINOK(inStream->Seek(pePos, STREAM_SEEK_SET, NULL)); - 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; - - #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(); -} - -}} +// NsisIn.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringToInt.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/StreamUtils.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 + EW_PUSHPOP, // Push/Pop/Exchange + EW_FINDWINDOW, // FindWindow + EW_SENDMESSAGE, // SendMessage + EW_ISWINDOW, // IsWindow + EW_GETDLGITEM, // GetDlgItem + EW_SETCTLCOLORS, // SetCtlColors + EW_SETBRANDINGIMAGE, // SetBrandingImage + 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 + + // instructions not actually implemented in exehead, but used in compiler. + EW_GETLABELADDR, // both of these get converted to EW_ASSIGNVAR + EW_GETFUNCTIONADDR, + + EW_LOCKWINDOW, // LockWindow + + // 2 unicode commands available only in Unicode archive + EW_FPUTWS, // FileWriteUTF16LE, FileWriteWord + EW_FGETWS, // FileReadUTF16LE, FileReadWord + + // 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 +}; + +static const unsigned kNumAdditionalParkCmds = 3; + +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" }, + { 3 }, // "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" }, + { 3 }, // "SetBrandingImage" }, + { 5 }, // "CreateFont" }, + { 4 }, // ShowWindow, EnableWindow, HideWindow + { 6 }, // "ExecShell" }, + { 3 }, // "Exec" }, // Exec, ExecWait + { 3 }, // "GetFileTime" }, + { 3 }, // "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" }, + { 2 }, // "GetFunctionAddress" }, + { 1 }, // "LockWindow" }, + { 3 }, // "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 + , "IntCmp" + , "IntOp" + , "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 + , "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; + + UInt32 start = _stringsPos + (IsUnicode ? param * 2 : param); + 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, langID); + } + else if (++_numRootLicenses > 1) + { + fileName += '-'; + UIntToString(fileName, _numRootLicenses); + } + const Byte *sz = (_data + start); + unsigned marker = IsUnicode ? Get16(sz) : *sz; + 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; + 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 + + +#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 +#define kVar_HWNDPARENT 29 + +// #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 + 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) (((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 < ARRAY_SIZE(kShellStrings)) + { + const char *sz = kShellStrings[index1]; + if (sz) + { + s += sz; + return; + } + } + if (index2 < 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, -((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, -((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); // _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(-((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 MY__MB_ABORTRETRYIGNORE 2 +#define MY__MB_RETRYCANCEL 5 + +static const char * const k_MB_Buttons[] = +{ + "OK" + , "OKCANCEL" + , "ABORTRETRYIGNORE" + , "YESNOCANCEL" + , "YESNO" + , "RETRYCANCEL" + , "CANCELTRYCONTINUE" +}; + +#define MY__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 MY__IDCANCEL 2 +#define MY__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 < 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_CtlColors_Size = 24; + +struct CNsis_CtlColors +{ + UInt32 text; // COLORREF + UInt32 bkc; // COLORREF + UInt32 lbStyle; + UInt32 bkb; // HBRUSH + Int32 bkmode; + Int32 flags; + + void Parse(const Byte *p); +}; + +void CNsis_CtlColors::Parse(const Byte *p) +{ + text = Get32(p); + bkc = Get32(p + 4); + lbStyle = Get32(p + 8); + bkb = Get32(p + 12); + bkmode = (Int32)Get32(p + 16); + flags = (Int32)Get32(p + 20); +} + +// Win32 constants +#define MY__TRANSPARENT 1 +#define MY__OPAQUE 2 + +#define MY__GENERIC_READ (1 << 31) +#define MY__GENERIC_WRITE (1 << 30) +#define MY__GENERIC_EXECUTE (1 << 29) +#define MY__GENERIC_ALL (1 << 28) + +#define MY__CREATE_NEW 1 +#define MY__CREATE_ALWAYS 2 +#define MY__OPEN_EXISTING 3 +#define MY__OPEN_ALWAYS 4 +#define MY__TRUNCATE_EXISTING 5 + +// 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 MY__SW_HIDE 0 +#define MY__SW_SHOWNORMAL 1 + +#define MY__SW_SHOWMINIMIZED 2 +#define MY__SW_SHOWMINNOACTIVE 7 +#define MY__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 < ARRAY_SIZE(kShowWindow_Commands)) + { + s += "SW_"; + s += kShowWindow_Commands[cmd]; + } + else + UIntToString(s, cmd); +} + +void CInArchive::Add_ShowWindow_Cmd(UInt32 cmd) +{ + if (cmd < 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, 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 §, 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 (int 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 < 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 < ARRAY_SIZE(k_MB_Icons) && k_MB_Icons[icon] != 0) + 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 < 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; +} + +#endif + +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 + + +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 (LogCmdIsEnabled) + AddString(s, "log"); + if (BadCmd >= 0) + { + AddString(s, "BadCmd="); + UIntToString(s, BadCmd); + } + return s; +} + +#ifdef NSIS_SCRIPT + +unsigned CInArchive::GetNumSupportedCommands() const +{ + unsigned numCmds = IsPark() ? kNumCmds : 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) + { + UInt32 id = GetCmd(Get32(p)); + if (id >= kNumCmds) + continue; + if (BadCmd >= 0 && id >= (unsigned)BadCmd) + continue; + unsigned i; + if (id == EW_GETLABELADDR || + id == EW_GETFUNCTIONADDR) + { + BadCmd = id; + continue; + } + for (i = 6; i != 0; i--) + { + UInt32 param = Get32(p + i * 4); + if (param != 0) + break; + } + if (id == EW_FINDPROC && i == 0) + { + BadCmd = id; + continue; + } + if (k_Commands[id].NumParams < i) + BadCmd = 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; + + unsigned c0 = p[1]; + if (c0 == 0) + return -1; + unsigned c1 = p[2]; + if (c1 == 0) + return -1; + return 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 +bool IsDrivePath(const wchar_t *s) { return IS_LETTER_CHAR(s[0]) && s[1] == ':' /* && s[2] == '\\' */ ; } +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); + bool isAbs = IsAbsolutePathVar(strPos); + if (IsUnicode) + { + item.NameU = Raw_UString; + if (!isAbs && !IsAbsolutePath(Raw_UString)) + item.Prefix = UPrefixes.Size() - 1; + } + else + { + item.NameA = Raw_AString; + if (!isAbs && !IsAbsolutePath(Raw_AString)) + item.Prefix = APrefixes.Size() - 1; + } +} + +HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) +{ + #ifdef NSIS_SCRIPT + CDynLimBuf &s = Script; + + CObjArray 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 < 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 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 §ion = 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 >= ARRAY_SIZE(k_InitPluginDir_Commands) + && CompareCommands(p, k_InitPluginDir_Commands, ARRAY_SIZE(k_InitPluginDir_Commands))) + { + InitPluginsDir_Start = kkk; + InitPluginsDir_End = kkk + 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 § = 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 < 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) + { + 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 == (MY__MB_ABORTRETRYIGNORE | MY__MB_ICONSTOP) && (b1 == MY__IDIGNORE || b2 == MY__IDIGNORE)) + asf = -1; + else if (mb == (MY__MB_RETRYCANCEL | MY__MB_ICONSTOP) && (b1 == MY__IDCANCEL || b2 == MY__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, 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 */ + + bool pathOk = (params[0] > 0) && IsGoodString(params[0]); + + if (!pathOk) + { + #ifdef NSIS_SCRIPT + AddError("bad path"); + #endif + break; + } + + bool altPathOk = true; + + UInt32 altParam = params[3]; + if (altParam != 0) + { + altPathOk = false; + UInt32 additional = 0; + if (GetVarIndexFinished(altParam, '\\', additional) == kVar_INSTDIR) + altPathOk = AreTwoParamStringsEqual(altParam + additional, params[0]); + } + + + #ifdef NSIS_SCRIPT + + AddParam(params[0]); + + /* + for (int i = 1; i < 3; i++) + AddParam_UInt(params[i]); + */ + + if (params[3] != 0) + { + SmallSpaceComment(); + AddParam(params[3]); + } + + #endif + + if (!altPathOk) + { + #ifdef NSIS_SCRIPT + AddError("alt path error"); + #endif + } + + if (BadCmd >= 0 && BadCmd <= EW_WRITEUNINSTALLER) + { + /* We don't 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; + + /* + // 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 § = 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 *pCmd = p + kCmdSize * (j - kkk); + AddParam(GET_CMD_PARAM(pCmd, 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(-((Int32)params[0] + 1)); + else if (params[0] == 0) + s += '0'; + else + { + 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] == MY__SW_SHOWNA && params[1] == MY__SW_HIDE) s += " show"; + else if (params[1] == MY__SW_SHOWNA && params[0] == MY__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(¶ms[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"; + } + if (s2) + { + s += ' '; + s += s2; + break; + } + } + SpaceQuStr(temp); + break; + } + + case EW_IFFLAG: + { + Add_ExecFlags(params[2]); + Add_GotoVars2(¶ms[0]); + /* + static 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(¶ms[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: + { + if (params[5] != 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 + UInt32 opIndex = params[3]; + char c = (opIndex < 13) ? kOps[opIndex] : '?'; + char c2 = (opIndex < 8 || opIndex == 10) ? (char)0 : c; + 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 (c2 != 0) + s += c2; + AddParam(params[2]); + } + break; + } + + case EW_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(¶ms[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 < k_CtlColors_Size) + { + AddError("bad offset"); + break; + } + + const Byte *p2 = _data + bhCtlColors.Offset + offset; + CNsis_CtlColors colors; + colors.Parse(p2); + + if ((colors.flags & kColorsFlags_BK_SYS) != 0 || + (colors.flags & kColorsFlags_TEXT_SYS) != 0) + s += " /BRANDING"; + + AString bk; + bool bkc = false; + if (colors.bkmode == MY__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_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 < 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] != MY__SW_SHOWNORMAL) + { + AddParam(params[2]); + if (params[3] != MY__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: + { + 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; + for (numParams = 6; numParams > 2; numParams--) + if (params[numParams - 1] != 0) + break; + + UInt32 spec = params[4]; + if (spec & 0x8000) // NSIS 3.0b0 + s += " /NoWorkingDir"; + + AddParams(params, numParams > 4 ? 4 : numParams); + if (numParams <= 4) + break; + + UInt32 icon = (spec & 0xFF); + Space(); + if (icon != 0) + Add_UInt(icon); + else + AddQuotes(); + + if ((spec >> 8) == 0 && numParams < 6) + break; + UInt32 sw = (spec >> 8) & 0x7F; + Space(); + // NSIS encoder replaces these names: + if (sw == MY__SW_SHOWMINNOACTIVE) + sw = MY__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|"; + + static 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"; + } + AddRegRoot(params[1]); + AddParam(params[2]); + AddOptionalParam(params[3]); + break; + } + + case EW_WRITEREG: + { + const char *s2 = 0; + 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 (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; + } + + case EW_FOPEN: + { + AddParam_Var(params[0]); + AddParam(params[3]); + UInt32 acc = params[1]; // dwDesiredAccess + UInt32 creat = params[2]; // dwCreationDisposition + if (acc == 0 && creat == 0) + break; + char cc = 0; + if (acc == MY__GENERIC_READ && creat == OPEN_EXISTING) + cc = 'r'; + else if (creat == CREATE_ALWAYS && acc == MY__GENERIC_WRITE) + cc = 'w'; + else if (creat == OPEN_ALWAYS && (acc == (MY__GENERIC_WRITE | MY__GENERIC_READ))) + cc = 'a'; + // cc = 0; + if (cc != 0) + { + Space(); + s += cc; + break; + } + + if (acc & MY__GENERIC_READ) s += " GENERIC_READ"; + if (acc & MY__GENERIC_WRITE) s += " GENERIC_WRITE"; + if (acc & MY__GENERIC_EXECUTE) s += " GENERIC_EXECUTE"; + if (acc & MY__GENERIC_ALL) s += " GENERIC_ALL"; + + const char *s2 = NULL; + switch (creat) + { + case MY__CREATE_NEW: s2 = "CREATE_NEW"; break; + case MY__CREATE_ALWAYS: s2 = "CREATE_ALWAYS"; break; + case MY__OPEN_EXISTING: s2 = "OPEN_EXISTING"; break; + case MY__OPEN_ALWAYS: s2 = "OPEN_ALWAYS"; break; + case MY__TRUNCATE_EXISTING: s2 = "TRUNCATE_EXISTING"; break; + } + Space(); + if (s2) + s += s2; + else + Add_UInt(creat); + break; + } + + case EW_FPUTS: + case EW_FPUTWS: + { + if (commandId == EW_FPUTWS) + s += (params[2] == 0) ? "UTF16LE" : "Word"; + else if (params[2] != 0) + s += "Byte"; + 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]); + } + } + + case EW_SECTIONSET: + { + if ((Int32)params[2] >= 0) + { + s += "Get"; + Add_SectOp(params[2]); + AddParam(params[0]); + AddParam_Var(params[1]); + } + else + { + s += "Set"; + UInt32 t = -(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: + { + int 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_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 § = Sections[curSectionIndex]; + if (sect.StartCmdIndex + sect.NumCommands + 1 == kkk) + { + PrintSectionEnd(); + sectionIsOpen = false; + // lastSectionEndCmd = kkk; + curSectionIndex++; + } + } + } + + while (curSectionIndex < bhSections.Num) + { + const CSection § = Sections[curSectionIndex]; + if (sectionIsOpen) + { + if (sect.StartCmdIndex + sect.NumCommands != kkk) + AddErrorLF("SECTION ERROR"); + PrintSectionEnd(); + sectionIsOpen = false; + curSectionIndex++; + } + else + { + if (curSectionIndex == 49) + curSectionIndex = curSectionIndex; + + 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 = **(CItem **)p1; + const CItem &i2 = **(CItem **)p2; + RINOZ(MyCompare(i1.Pos, i2.Pos)); + 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]; + 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]; + UInt32 curPos = item.Pos + 4; + for (unsigned nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++) + { + UInt32 nextPos = Items[nextIndex].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]; + 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; +} + +// 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 +}; + +HRESULT CInArchive::Parse() +{ + // UInt32 offset = ReadUInt32(); + // ???? offset == FirstHeader.HeaderSize + const Byte *p = _data; + + if (_size < 4 + 8 * 8) + return S_FALSE; + + CBlockHeader bhEntries, bhStrings, bhLangTables; + bhEntries.Parse(p + 4 + 8 * 2); + bhStrings.Parse(p + 4 + 8 * 3); + bhLangTables.Parse(p + 4 + 8 * 4); + + #ifdef NSIS_SCRIPT + + CBlockHeader bhFont; + bhPages.Parse(p + 4 + 8 * 0); + bhSections.Parse(p + 4 + 8 * 1); + bhCtlColors.Parse(p + 4 + 8 * 5); + bhFont.Parse(p + 4 + 8 * 6); + bhData.Parse(p + 4 + 8 * 7); + + #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 (IsUnicode) + AddStringLF("Unicode true"); + + if (Method != NMethodType::kCopy) + { + const char *m = NULL; + switch (Method) + { + case NMethodType::kDeflate: m = "zlib"; break; + case NMethodType::kBZip2: m = "bzip2"; break; + case NMethodType::kLZMA: m = "lzma"; 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(p); + 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 = 4 + 8 * 8; + if (bhPages.Offset == 276) + paramsOffset -= 8; + + const Byte *p2 = p + 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 != -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(); + } + + UInt32 langtable_size = Get32(p2 + 32); + if (bhLangTables.Num > 0) + { + if (langtable_size == (UInt32)(Int32)-1) + return E_NOTIMPL; // maybe it's old NSIS archive() + + UInt32 numStrings = (langtable_size - 10) / 4; + _numLangStrings = numStrings; + AddLF(); + Separator(); + PrintNumComment("LANG TABLES", bhLangTables.Num); + PrintNumComment("LANG STRINGS", numStrings); + AddLF(); + + if (licenseLangIndex >= 0) + { + for (UInt32 i = 0; i < bhLangTables.Num; i++) + { + const Byte *p = _data + bhLangTables.Offset + langtable_size * i; + LANGID langID = Get16(p); + UInt32 val = Get32(p + 10 + (UInt32)licenseLangIndex * 4); + if (val != 0) + { + Script += "LicenseLangString "; + Add_LangStr_Simple(licenseLangIndex); + AddParam_UInt(langID); + AddLicense(val, langID); + noParseStringIndexes.AddToUniqueSorted(val); + NewLine(); + } + } + AddLF(); + } + + UInt32 brandingText = 0; + UInt32 caption = 0; + UInt32 name = 0; + UInt32 i; + for (i = 0; i < bhLangTables.Num; i++) + { + const Byte *p = _data + bhLangTables.Offset + langtable_size * i; + LANGID langID = Get16(p); + if (i == 0 || langID == 1033) + _mainLang = p + 10; + { + UInt32 v = Get32(p + 10 + 0 * 4); + if (v != 0 && (langID == 1033 || brandingText == 0)) + brandingText = v; + } + { + UInt32 v = Get32(p + 10 + 1 * 4); + if (v != 0 && (langID == 1033 || caption == 0)) + caption = v; + } + { + UInt32 v = Get32(p + 10 + 2 * 4); + if (v != 0 && (langID == 1033 || name == 0)) + name = v; + } + } + + if (name != 0) + { + Script += "Name"; + AddParam(name); + NewLine(); + + ReadString2(Name, name); + } + + /* + if (caption != 0) + { + Script += "Caption"; + AddParam(caption); + NewLine(); + } + */ + + if (brandingText != 0) + { + Script += "BrandingText"; + AddParam(brandingText); + NewLine(); + + ReadString2(BrandingText, brandingText); + } + + for (i = 0; i < bhLangTables.Num; i++) + { + const Byte *p = _data + bhLangTables.Offset + langtable_size * i; + LANGID 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 = 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->Seek(0, STREAM_SEEK_CUR, &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->Seek(posCur, STREAM_SEEK_SET, NULL)); + 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->Seek(pos, STREAM_SEEK_SET, NULL)); + 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 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; + + RINOK(inStream->Seek(0, STREAM_SEEK_END, &_fileSize)); + + IsArc = true; + + if (peSize != 0) + { + ExeStub.Alloc(peSize); + RINOK(inStream->Seek(pePos, STREAM_SEEK_SET, NULL)); + 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; + + #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 index a3a0edb3e..028e4a5db 100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.h +++ b/CPP/7zip/Archive/Nsis/NsisIn.h @@ -1,450 +1,450 @@ -// NsisIn.h - -#ifndef __ARCHIVE_NSIS_IN_H -#define __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 "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; -} - -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) - { - Offset = GetUi32(p); - Num = GetUi32(p + 4); - } -}; - -struct CItem -{ - bool IsCompressed; - bool Size_Defined; - bool CompressedSize_Defined; - bool EstimatedSize_Defined; - bool Attrib_Defined; - bool IsUninstaller; - // bool UseFilter; - - UInt32 Attrib; - UInt32 Pos; - 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; - - CItem(): - 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 Items; - bool IsUnicode; -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; } - - 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 langStrIDs; - UInt32 numOnFunc; - UInt32 onFuncOffset; - // CRecordVector OnFuncs; - unsigned _numRootLicenses; - CRecordVector noParseStringIndexes; - AString _tempString_for_GetVar; - AString _tempString_for_AddFuncName; - AString _tempString; - - #endif - - -public: - CMyComPtr _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 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 §, 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 _stream->Seek(pos, STREAM_SEEK_SET, NULL); - } - - 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.IsUninstaller && ExeStub.Size() == 0) - s += ".nsis"; - return s; - } - - UString ConvertToUnicode(const AString &s) const; - - CInArchive() - #ifdef NSIS_SCRIPT - : Script(kScriptSizeLimit) - #endif - {} -}; - -}} - -#endif +// NsisIn.h + +#ifndef __ARCHIVE_NSIS_IN_H +#define __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 "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; +} + +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) + { + Offset = GetUi32(p); + Num = GetUi32(p + 4); + } +}; + +struct CItem +{ + bool IsCompressed; + bool Size_Defined; + bool CompressedSize_Defined; + bool EstimatedSize_Defined; + bool Attrib_Defined; + bool IsUninstaller; + // bool UseFilter; + + UInt32 Attrib; + UInt32 Pos; + 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; + + CItem(): + 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 Items; + bool IsUnicode; +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; } + + 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 langStrIDs; + UInt32 numOnFunc; + UInt32 onFuncOffset; + // CRecordVector OnFuncs; + unsigned _numRootLicenses; + CRecordVector noParseStringIndexes; + AString _tempString_for_GetVar; + AString _tempString_for_AddFuncName; + AString _tempString; + + #endif + + +public: + CMyComPtr _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 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 §, 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 _stream->Seek(pos, STREAM_SEEK_SET, NULL); + } + + 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.IsUninstaller && 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 index 411b5e68f..7230c3c26 100644 --- a/CPP/7zip/Archive/Nsis/NsisRegister.cpp +++ b/CPP/7zip/Archive/Nsis/NsisRegister.cpp @@ -1,20 +1,20 @@ -// NsisRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "NsisHandler.h" - -namespace NArchive { -namespace NNsis { - -REGISTER_ARC_I( - "Nsis", "nsis", 0, 0x9, - kSignature, - 4, - NArcInfoFlags::kFindSignature | - NArcInfoFlags::kUseGlobalOffset, - NULL) - -}} +// NsisRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "NsisHandler.h" + +namespace NArchive { +namespace NNsis { + +REGISTER_ARC_I( + "Nsis", "nsis", 0, 0x9, + kSignature, + 4, + NArcInfoFlags::kFindSignature | + NArcInfoFlags::kUseGlobalOffset, + NULL) + +}} diff --git a/CPP/7zip/Archive/Nsis/StdAfx.h b/CPP/7zip/Archive/Nsis/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Archive/Nsis/StdAfx.h +++ b/CPP/7zip/Archive/Nsis/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp index 3e037b134..21372033e 100644 --- a/CPP/7zip/Archive/NtfsHandler.cpp +++ b/CPP/7zip/Archive/NtfsHandler.cpp @@ -1,2807 +1,2807 @@ -// NtfsHandler.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO -// #define SHOW_DEBUG_INFO2 - -#if defined(SHOW_DEBUG_INFO) || defined(SHOW_DEBUG_INFO2) -#include -#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 = t; - t = GetLog(p[13]); - if (t < 0) - return false; - sectorsPerClusterLog = 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; } -}; - -#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); -}; - -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); -}; - -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 &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 **)elem1)); - const CAttr &a2 = *(*((const CAttr **)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 &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 += 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; - -class CInStream: - public IInStream, - public CMyUnknownImp -{ - UInt64 _virtPos; - UInt64 _physPos; - UInt64 _curRem; - bool _sparseMode; - - - unsigned _chunkSizeLog; - UInt64 _tags[kNumCacheChunks]; - CByteBuffer _inBuf; - CByteBuffer _outBuf; -public: - UInt64 Size; - UInt64 InitializedSize; - unsigned BlockSizeLog; - unsigned CompressionUnit; - CRecordVector Extents; - bool InUse; - CMyComPtr Stream; - - HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); } - - UInt32 GetCuSize() const { return (UInt32)1 << (BlockSizeLog + CompressionUnit); } - 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(); - } - - MY_UNKNOWN_IMP1(IInStream) - - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); -}; - -static size_t Lznt1Dec(Byte *dest, size_t outBufLim, size_t destLen, const Byte *src, size_t srcLen) -{ - size_t destSize = 0; - while (destSize < destLen) - { - if (srcLen < 2 || (destSize & 0xFFF) != 0) - break; - UInt32 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; - Int32 offs = -1 - dist; - Byte *p = dest + destSize; - for (UInt32 t = 0; t < len; t++) - p[t] = p[t + offs]; - destSize += len; - sbOffset += len; - } - } - } - while (comprSize > 0); - src += pos; - } - } - return destSize; -} - -STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) -{ - if (processedSize) - *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; - UInt64 newPos = (e.Phy + (curVirt - e.Virt)) << BlockSizeLog; - if (newPos != _physPos) - { - _physPos = newPos; - RINOK(SeekToPhys()); - } - UInt64 numChunks = Extents[i + 1].Virt - curVirt; - if (curVirt + numChunks > virtBlock2End) - numChunks = virtBlock2End - curVirt; - size_t compressed = (size_t)numChunks << BlockSizeLog; - RINOK(ReadStream_FALSE(Stream, _inBuf + offs, compressed)); - curVirt += numChunks; - _physPos += compressed; - offs += compressed; - } - - size_t destLenMax = GetCuSize(); - size_t destLen = destLenMax; - const UInt64 rem = Size - (virtBlock2 << BlockSizeLog); - if (destLen > rem) - destLen = (size_t)rem; - - Byte *dest = _outBuf + (cacheIndex << _chunkSizeLog); - size_t destSizeRes = Lznt1Dec(dest, destLenMax, destLen, _inBuf, offs); - _tags[cacheIndex] = cacheTag; - - // some files in Vista have destSize > destLen - if (destSizeRes < destLen) - { - memset(dest, 0, destLenMax); - if (InUse) - return S_FALSE; - } - } - - if (size > _curRem) - size = (UInt32)_curRem; - HRESULT res = S_OK; - if (_sparseMode) - memset(data, 0, size); - else - { - res = Stream->Read(data, size, &size); - _physPos += size; - } - if (processedSize) - *processedSize = size; - _virtPos += size; - _curRem -= size; - return res; -} - -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; - if (_virtPos != (UInt64)offset) - { - _curRem = 0; - _virtPos = offset; - } - if (newPosition) - *newPosition = offset; - return S_OK; -} - -static HRESULT DataParseExtents(unsigned clusterSizeLog, const CObjectVector &attrs, - unsigned attrIndex, unsigned attrIndexLim, UInt64 numPhysClusters, CRecordVector &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; - -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 DataAttrs; - CObjectVector FileNames; - CRecordVector 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 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 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 *attrs); - - bool IsEmpty() const { return (Magic <= 2); } - bool IsFILE() const { return (Magic == kMagic_FILE); } - bool IsBAAD() const { return (Magic == kMagic_BAAD); } - - bool InUse() const { return (Flags & 1) != 0; } - bool IsDir() const { return (Flags & 2) != 0; } - - void ParseDataNames(); - HRESULT GetStream(IInStream *mainStream, int dataIndex, - 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(): MyNumNameLinks(0), MyItemIndex(-1) {} -}; - -void CMftRec::ParseDataNames() -{ - DataRefs.Clear(); - DataAttrs.Sort(CompareAttr, 0); - - 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 = 0; - CBufferInStream *streamSpec = new CBufferInStream; - CMyComPtr 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 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 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 *attrs) -{ - G32(p, Magic); - if (!IsFILE()) - return IsEmpty() || IsBAAD(); - - - { - 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 Items; - CObjectVector Recs; - CMyComPtr InStream; - CHeader Header; - unsigned RecSizeLog; - UInt64 PhySize; - - IArchiveOpenCallback *OpenCallback; - - CByteBuffer ByteBuf; - - CObjectVector VolAttrs; - - CByteBuffer SecurData; - CRecordVector SecurOffsets; - - bool _showSystemFiles; - bool _showDeletedFiles; - CObjectVector 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->Seek(cluster << Header.ClusterSizeLog, STREAM_SEEK_SET, NULL); -} - -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. - */ - - { - static const UInt32 kHeaderSize = 512; - Byte buf[kHeaderSize]; - RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)); - if (!Header.Parse(buf)) - return S_FALSE; - - UInt64 fileSize; - RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize)); - PhySize = Header.GetPhySize_Clusters(); - if (fileSize < PhySize) - return S_FALSE; - - UInt64 phySizeMax = Header.GetPhySize_Max(); - if (fileSize >= phySizeMax) - { - RINOK(InStream->Seek(Header.NumSectors << Header.SectorSizeLog, STREAM_SEEK_SET, NULL)); - 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 mftStream; - { - UInt32 blockSize = 1 << 12; - ByteBuf.Alloc(blockSize); - RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize)); - - { - UInt32 allocSize = Get32(ByteBuf + 0x1C); - int t = GetLog(allocSize); - if (t < (int)Header.SectorSizeLog) - return S_FALSE; - RecSizeLog = 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.IsFILE()) - return S_FALSE; - mftRec.ParseDataNames(); - if (mftRec.DataRefs.IsEmpty()) - return S_FALSE; - RINOK(mftRec.GetStream(InStream, 0, Header.ClusterSizeLog, Header.NumClusters, &mftStream)); - if (!mftStream) - return S_FALSE; - } - - // CObjectVector 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 & 0x3FF) == 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 *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.BaseMftRef.IsBaseItself()) - { - UInt64 refIndex = rec.BaseMftRef.GetIndex(); - if (refIndex > (UInt32)Recs.Size()) - return S_FALSE; - CMftRec &refRec = Recs[(unsigned)refIndex]; - bool moveAttrs = (refRec.SeqNumber == rec.BaseMftRef.GetNumber() && refRec.BaseMftRef.IsBaseItself()); - if (rec.InUse() && refRec.InUse()) - { - if (!moveAttrs) - return S_FALSE; - } - else if (rec.InUse() || refRec.InUse()) - moveAttrs = false; - if (moveAttrs) - refRec.MoveAttrsFrom(rec); - } - } - - for (i = 0; i < Recs.Size(); i++) - Recs[i].ParseDataNames(); - - for (i = 0; i < Recs.Size(); i++) - { - CMftRec &rec = Recs[i]; - if (!rec.IsFILE() || !rec.BaseMftRef.IsBaseItself()) - continue; - 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 = 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 = Items.Size(); - item.ParentHost = 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 = 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 sdsStream; - RINOK(rec.GetStream(InStream, di, Header.ClusterSizeLog, Header.NumClusters, &sdsStream)); - if (sdsStream) - { - 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; - 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 = virtIndex++; - VirtFolderNames.Add(kVirtualFolder_System); - } - if (thereAreUnknownFolders_Normal) - { - _lostFolderIndex_Normal = virtIndex++; - VirtFolderNames.Add(kVirtualFolder_Lost_Normal); - } - if (thereAreUnknownFolders_Deleted) - { - _lostFolderIndex_Deleted = virtIndex++; - VirtFolderNames.Add(kVirtualFolder_Lost_Deleted); - } - - return S_OK; -} - -class CHandler: - public IInArchive, - public IArchiveGetRawProps, - public IInArchiveGetStream, - public ISetProperties, - public CMyUnknownImp, - CDatabase -{ -public: - MY_UNKNOWN_IMP4( - IInArchive, - IArchiveGetRawProps, - IInArchiveGetStream, - ISetProperties) - INTERFACE_IInArchive(;) - INTERFACE_IArchiveGetRawProps(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); -}; - -STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) -{ - *numProps = 2; - return S_OK; -} - -STDMETHODIMP CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) -{ - *name = NULL; - *propID = index == 0 ? kpidNtReparse : kpidNtSecure; - return S_OK; -} - -STDMETHODIMP 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; -} - -STDMETHODIMP 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) * 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; -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - *stream = 0; - 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, - 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; -} - -STDMETHODIMP 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 += '.'; - 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 -} - -STDMETHODIMP 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 = 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 kpidRecMTime: if (fn) 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 = 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 -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) -{ - COM_TRY_BEGIN - { - OpenCallback = callback; - InStream = stream; - HRESULT res; - try - { - res = CDatabase::Open(); - if (res == S_OK) - return S_OK; - } - catch(...) - { - Close(); - throw; - } - Close(); - return res; - } - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - ClearAndClose(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = Items.Size(); - if (numItems == 0) - return S_OK; - UInt32 i; - UInt64 totalSize = 0; - for (i = 0; i < numItems; i++) - { - UInt32 index = allFilesMode ? i : indices[i]; - if (index >= (UInt32)Items.Size()) - continue; - const CItem &item = Items[allFilesMode ? i : indices[i]]; - const CMftRec &rec = Recs[item.RecIndex]; - if (item.DataIndex >= 0) - totalSize += rec.GetSize(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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CDummyOutStream *outStreamSpec = new CDummyOutStream; - CMyComPtr outStream(outStreamSpec); - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - CMyComPtr realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - 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 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 -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = Items.Size() + VirtFolderNames.Size(); - return S_OK; -} - -STDMETHODIMP 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", 0, 0xD9, - k_Signature, - 3, - 0, - NULL) - -}} +// NtfsHandler.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO +// #define SHOW_DEBUG_INFO2 + +#if defined(SHOW_DEBUG_INFO) || defined(SHOW_DEBUG_INFO2) +#include +#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 = t; + t = GetLog(p[13]); + if (t < 0) + return false; + sectorsPerClusterLog = 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; } +}; + +#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); +}; + +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); +}; + +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 &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 **)elem1)); + const CAttr &a2 = *(*((const CAttr **)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 &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 += 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; + +class CInStream: + public IInStream, + public CMyUnknownImp +{ + UInt64 _virtPos; + UInt64 _physPos; + UInt64 _curRem; + bool _sparseMode; + + + unsigned _chunkSizeLog; + UInt64 _tags[kNumCacheChunks]; + CByteBuffer _inBuf; + CByteBuffer _outBuf; +public: + UInt64 Size; + UInt64 InitializedSize; + unsigned BlockSizeLog; + unsigned CompressionUnit; + CRecordVector Extents; + bool InUse; + CMyComPtr Stream; + + HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); } + + UInt32 GetCuSize() const { return (UInt32)1 << (BlockSizeLog + CompressionUnit); } + 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(); + } + + MY_UNKNOWN_IMP1(IInStream) + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); +}; + +static size_t Lznt1Dec(Byte *dest, size_t outBufLim, size_t destLen, const Byte *src, size_t srcLen) +{ + size_t destSize = 0; + while (destSize < destLen) + { + if (srcLen < 2 || (destSize & 0xFFF) != 0) + break; + UInt32 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; + Int32 offs = -1 - dist; + Byte *p = dest + destSize; + for (UInt32 t = 0; t < len; t++) + p[t] = p[t + offs]; + destSize += len; + sbOffset += len; + } + } + } + while (comprSize > 0); + src += pos; + } + } + return destSize; +} + +STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *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; + UInt64 newPos = (e.Phy + (curVirt - e.Virt)) << BlockSizeLog; + if (newPos != _physPos) + { + _physPos = newPos; + RINOK(SeekToPhys()); + } + UInt64 numChunks = Extents[i + 1].Virt - curVirt; + if (curVirt + numChunks > virtBlock2End) + numChunks = virtBlock2End - curVirt; + size_t compressed = (size_t)numChunks << BlockSizeLog; + RINOK(ReadStream_FALSE(Stream, _inBuf + offs, compressed)); + curVirt += numChunks; + _physPos += compressed; + offs += compressed; + } + + size_t destLenMax = GetCuSize(); + size_t destLen = destLenMax; + const UInt64 rem = Size - (virtBlock2 << BlockSizeLog); + if (destLen > rem) + destLen = (size_t)rem; + + Byte *dest = _outBuf + (cacheIndex << _chunkSizeLog); + size_t destSizeRes = Lznt1Dec(dest, destLenMax, destLen, _inBuf, offs); + _tags[cacheIndex] = cacheTag; + + // some files in Vista have destSize > destLen + if (destSizeRes < destLen) + { + memset(dest, 0, destLenMax); + if (InUse) + return S_FALSE; + } + } + + if (size > _curRem) + size = (UInt32)_curRem; + HRESULT res = S_OK; + if (_sparseMode) + memset(data, 0, size); + else + { + res = Stream->Read(data, size, &size); + _physPos += size; + } + if (processedSize) + *processedSize = size; + _virtPos += size; + _curRem -= size; + return res; +} + +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; + if (_virtPos != (UInt64)offset) + { + _curRem = 0; + _virtPos = offset; + } + if (newPosition) + *newPosition = offset; + return S_OK; +} + +static HRESULT DataParseExtents(unsigned clusterSizeLog, const CObjectVector &attrs, + unsigned attrIndex, unsigned attrIndexLim, UInt64 numPhysClusters, CRecordVector &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; + +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 DataAttrs; + CObjectVector FileNames; + CRecordVector 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 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 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 *attrs); + + bool IsEmpty() const { return (Magic <= 2); } + bool IsFILE() const { return (Magic == kMagic_FILE); } + bool IsBAAD() const { return (Magic == kMagic_BAAD); } + + bool InUse() const { return (Flags & 1) != 0; } + bool IsDir() const { return (Flags & 2) != 0; } + + void ParseDataNames(); + HRESULT GetStream(IInStream *mainStream, int dataIndex, + 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(): MyNumNameLinks(0), MyItemIndex(-1) {} +}; + +void CMftRec::ParseDataNames() +{ + DataRefs.Clear(); + DataAttrs.Sort(CompareAttr, 0); + + 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 = 0; + CBufferInStream *streamSpec = new CBufferInStream; + CMyComPtr 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 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 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 *attrs) +{ + G32(p, Magic); + if (!IsFILE()) + return IsEmpty() || IsBAAD(); + + + { + 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 Items; + CObjectVector Recs; + CMyComPtr InStream; + CHeader Header; + unsigned RecSizeLog; + UInt64 PhySize; + + IArchiveOpenCallback *OpenCallback; + + CByteBuffer ByteBuf; + + CObjectVector VolAttrs; + + CByteBuffer SecurData; + CRecordVector SecurOffsets; + + bool _showSystemFiles; + bool _showDeletedFiles; + CObjectVector 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->Seek(cluster << Header.ClusterSizeLog, STREAM_SEEK_SET, NULL); +} + +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. + */ + + { + static const UInt32 kHeaderSize = 512; + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)); + if (!Header.Parse(buf)) + return S_FALSE; + + UInt64 fileSize; + RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize)); + PhySize = Header.GetPhySize_Clusters(); + if (fileSize < PhySize) + return S_FALSE; + + UInt64 phySizeMax = Header.GetPhySize_Max(); + if (fileSize >= phySizeMax) + { + RINOK(InStream->Seek(Header.NumSectors << Header.SectorSizeLog, STREAM_SEEK_SET, NULL)); + 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 mftStream; + { + UInt32 blockSize = 1 << 12; + ByteBuf.Alloc(blockSize); + RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize)); + + { + UInt32 allocSize = Get32(ByteBuf + 0x1C); + int t = GetLog(allocSize); + if (t < (int)Header.SectorSizeLog) + return S_FALSE; + RecSizeLog = 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.IsFILE()) + return S_FALSE; + mftRec.ParseDataNames(); + if (mftRec.DataRefs.IsEmpty()) + return S_FALSE; + RINOK(mftRec.GetStream(InStream, 0, Header.ClusterSizeLog, Header.NumClusters, &mftStream)); + if (!mftStream) + return S_FALSE; + } + + // CObjectVector 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 & 0x3FF) == 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 *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.BaseMftRef.IsBaseItself()) + { + UInt64 refIndex = rec.BaseMftRef.GetIndex(); + if (refIndex > (UInt32)Recs.Size()) + return S_FALSE; + CMftRec &refRec = Recs[(unsigned)refIndex]; + bool moveAttrs = (refRec.SeqNumber == rec.BaseMftRef.GetNumber() && refRec.BaseMftRef.IsBaseItself()); + if (rec.InUse() && refRec.InUse()) + { + if (!moveAttrs) + return S_FALSE; + } + else if (rec.InUse() || refRec.InUse()) + moveAttrs = false; + if (moveAttrs) + refRec.MoveAttrsFrom(rec); + } + } + + for (i = 0; i < Recs.Size(); i++) + Recs[i].ParseDataNames(); + + for (i = 0; i < Recs.Size(); i++) + { + CMftRec &rec = Recs[i]; + if (!rec.IsFILE() || !rec.BaseMftRef.IsBaseItself()) + continue; + 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 = 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 = Items.Size(); + item.ParentHost = 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 = 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 sdsStream; + RINOK(rec.GetStream(InStream, di, Header.ClusterSizeLog, Header.NumClusters, &sdsStream)); + if (sdsStream) + { + 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; + 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 = virtIndex++; + VirtFolderNames.Add(kVirtualFolder_System); + } + if (thereAreUnknownFolders_Normal) + { + _lostFolderIndex_Normal = virtIndex++; + VirtFolderNames.Add(kVirtualFolder_Lost_Normal); + } + if (thereAreUnknownFolders_Deleted) + { + _lostFolderIndex_Deleted = virtIndex++; + VirtFolderNames.Add(kVirtualFolder_Lost_Deleted); + } + + return S_OK; +} + +class CHandler: + public IInArchive, + public IArchiveGetRawProps, + public IInArchiveGetStream, + public ISetProperties, + public CMyUnknownImp, + CDatabase +{ +public: + MY_UNKNOWN_IMP4( + IInArchive, + IArchiveGetRawProps, + IInArchiveGetStream, + ISetProperties) + INTERFACE_IInArchive(;) + INTERFACE_IArchiveGetRawProps(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); +}; + +STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) +{ + *numProps = 2; + return S_OK; +} + +STDMETHODIMP CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) +{ + *name = NULL; + *propID = index == 0 ? kpidNtReparse : kpidNtSecure; + return S_OK; +} + +STDMETHODIMP 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; +} + +STDMETHODIMP 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) * 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; +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = 0; + 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, + 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; +} + +STDMETHODIMP 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 += '.'; + 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 +} + +STDMETHODIMP 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 = 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 kpidRecMTime: if (fn) 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 = 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 +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + { + OpenCallback = callback; + InStream = stream; + HRESULT res; + try + { + res = CDatabase::Open(); + if (res == S_OK) + return S_OK; + } + catch(...) + { + Close(); + throw; + } + Close(); + return res; + } + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + ClearAndClose(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = Items.Size(); + if (numItems == 0) + return S_OK; + UInt32 i; + UInt64 totalSize = 0; + for (i = 0; i < numItems; i++) + { + UInt32 index = allFilesMode ? i : indices[i]; + if (index >= (UInt32)Items.Size()) + continue; + const CItem &item = Items[allFilesMode ? i : indices[i]]; + const CMftRec &rec = Recs[item.RecIndex]; + if (item.DataIndex >= 0) + totalSize += rec.GetSize(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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr outStream(outStreamSpec); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + 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 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 +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = Items.Size() + VirtFolderNames.Size(); + return S_OK; +} + +STDMETHODIMP 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", 0, 0xD9, + k_Signature, + 3, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp index ca833cf87..675293ba3 100644 --- a/CPP/7zip/Archive/PeHandler.cpp +++ b/CPP/7zip/Archive/PeHandler.cpp @@ -1,3238 +1,3238 @@ -// PeHandler.cpp - -#include "StdAfx.h" - -// #include - -#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 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 <= 31; i++) - if (((UInt32)1 << i) == FileAlign) - return 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; - 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) {} - - const UInt32 GetSizeExtract() const { return PSize; } - const 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(Byte 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(Byte c) -{ - Byte *p = Buf.GetCurPtrAndGrow(2); - p[0] = 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; -}; - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public IArchiveAllowTail, - public CMyUnknownImp -{ - CMyComPtr _stream; - CObjectVector _sections; - CHeader _header; - UInt32 _totalSize; - Int32 _mainSubfile; - - CRecordVector _mixItems; - CRecordVector _items; - CObjectVector _strings; - CObjectVector _versionFiles; - UString _versionFullString; - UString _versionShortString; - UString _originalFilename; - CObjectVector _versionKeys; - - CByteBuffer _buf; - bool _oneLang; - UString _resourcesPrefix; - CUsedBitmap _usedRes; - bool _parseResources; - bool _checksumError; - - bool IsOpt() const { return _header.OptHeaderSize != 0; } - - COptHeader _optHeader; - - bool _allowTail; - bool _coffMode; - - 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 &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 §, 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) - {} - - MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IArchiveAllowTail) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - STDMETHOD(AllowTail)(Int32 allowTail); -}; - - -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) - { - FILETIME ft; - NTime::UnixTimeToFileTime(unixTime, ft); - prop = ft; - } -} - -STDMETHODIMP 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 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(); - } -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - const CMixItem &mixItem = _mixItems[index]; - if (mixItem.StringIndex >= 0) - { - const CStringItem &item = _strings[mixItem.StringIndex]; - switch (propID) - { - case kpidPath: - { - 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 < 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: prop = MultiByteToUnicodeString(item.Name); 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, 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 § = _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(stream->Seek(pa, STREAM_SEEK_SET, NULL)); - 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 § = _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 &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( 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.Planes != 1 || h.BitCount > 32) - return 0; - if (h.SizeImage == 0) - { - if (h.Compression != 0) // BI_RGB - return 0; - h.SizeImage = GetImageSize(h.XSize, h.YSize, h.BitCount); - } - UInt32 totalSize = kBmpHeaderSize + size; - UInt32 offBits = totalSize - h.SizeImage; - // BITMAPFILEHEADER - SetUi16(dest, 0x4D42); - SetUi32(dest + 2, totalSize); - SetUi32(dest + 6, 0); - SetUi32(dest + 10, offBits); - return kBmpHeaderSize; -} - -static UInt32 SetIconHeader(Byte *dest, const Byte *src, UInt32 size) -{ - CBitmapInfoHeader h; - if (!h.Parse(src, size)) - return 0; - if (h.YSize < 0) - h.YSize = -h.YSize; - if (h.XSize > (1 << 26) || h.YSize > (1 << 26) || h.Planes != 1 || - h.Compression != 0) // BI_RGB - return 0; - - UInt32 numBitCount = h.BitCount; - if (numBitCount != 1 && - numBitCount != 4 && - numBitCount != 8 && - numBitCount != 24 && - numBitCount != 32) - return 0; - - if ((h.YSize & 1) != 0) - return 0; - h.YSize /= 2; - if (h.XSize > 0x100 || h.YSize > 0x100) - return 0; - - UInt32 imageSize; - // imageSize is not correct if AND mask array contains zeros - // in this case it is equal image1Size - - // UInt32 imageSize = h.SizeImage; - // if (imageSize == 0) - // { - UInt32 image1Size = GetImageSize(h.XSize, h.YSize, h.BitCount); - UInt32 image2Size = GetImageSize(h.XSize, h.YSize, 1); - imageSize = image1Size + image2Size; - // } - UInt32 numColors = 0; - if (numBitCount < 16) - numColors = 1 << numBitCount; - - SetUi16(dest, 0); // Reserved - SetUi16(dest + 2, 1); // RES_ICON - SetUi16(dest + 4, 1); // ResCount - - dest[6] = (Byte)h.XSize; // Width - dest[7] = (Byte)h.YSize; // Height - dest[8] = (Byte)numColors; // ColorCount - dest[9] = 0; // Reserved - - SetUi32(dest + 10, 0); // Reserved1 / Reserved2 - - UInt32 numQuadsBytes = numColors * 4; - UInt32 BytesInRes = kBitmapInfoHeader_Size + numQuadsBytes + imageSize; - SetUi32(dest + 14, BytesInRes); - SetUi32(dest + 18, kIconHeaderSize); - - /* - Description = DWORDToString(xSize) + - kDelimiterChar + DWORDToString(ySize) + - kDelimiterChar + DWORDToString(numBitCount); - */ - return kIconHeaderSize; -} - -bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size) -{ - if ((size & 1) != 0) - return false; - - 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 &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 += '.'; - PrintUInt32(s, LOWORD(ms)); s += '.'; - PrintUInt32(s, HIWORD(ls)); s += '.'; - 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 &v, const char *key) -{ - FOR_VECTOR (i, v) - if (v[i].Key.IsEqualTo(key)) - return i; - return -1; -} - -static void AddToUniqueUStringVector(CObjectVector &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 &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 < 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 << 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 < 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 == ARRAY_SIZE(k_VS_FileOS)) - { - UInt32 high = OS >> 16; - if (high < 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 < ARRAY_SIZE(k_VS_FileOS_Low)) - f.AddString(k_VS_FileOS_Low[low]); - else - PrintHex(f, low); - } - } - f.NewLine(); - - f.AddString("FILETYPE "); - if (Type < 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 < 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 < 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 (;;) - { - Byte c = *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 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; - int t = Get_Utf16Str_Len_InBytes(p + k_ResoureBlockHeader_Size, TotalLen - k_ResoureBlockHeader_Size); - if (t < 0) - return false; - StrSize = 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 &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); - 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 += 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 § = _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(stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL)); - - _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 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 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 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 = _versionFiles.Size(); - mixItem.SectionIndex = 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 = i; - mixItem.SectionIndex = 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 < 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(stream->Seek(_peOffset, STREAM_SEEK_SET, NULL)); - 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)); - - 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 § = _sections.AddNew(); - sect.Parse(buffer + pos); - sect.IsRealSect = true; - - /* PE pre-file in .hxs file has errors: - PSize of resource is larger tnan real size. - So it overlaps next ".its" section. - We correct it. */ - - if (i > 0) - { - CSection &prev = _sections[i - 1]; - if (prev.Pa < sect.Pa && - prev.Pa + prev.PSize > sect.Pa && - sect.PSize > 0) - { - // printf("\n !!!! Section correction: %s\n ", prev.Name); - // fflush(stdout); - prev.PSize = sect.Pa - prev.Pa; - } - } - /* last ".its" section in hxs file has incorrect sect.PSize. - So we reduce it 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 § = _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(stream->Seek(_totalSize, STREAM_SEEK_SET, NULL)); - 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(stream->Seek((UInt64)_header.PointerToSymbolTable + size, STREAM_SEEK_SET, NULL)); - Byte buf[4]; - RINOK(ReadStream_FALSE(stream, buf, 4)); - UInt32 size2 = Get32(buf); - if (size2 >= (1 << 28)) - return S_FALSE; - size += size2; - - CSection § = _sections.AddNew(); - sect.Name = "COFF_SYMBOLS"; - sect.Va = 0; - sect.Pa = _header.PointerToSymbolTable; - sect.PSize = sect.VSize = size; - sect.UpdateTotalSize(_totalSize); - } - - { - CObjectVector 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(stream->Seek(0, STREAM_SEEK_SET, NULL)); - UInt32 checkSum = 0; - RINOK(CalcCheckSum(stream, _totalSize, optStart + k_CheckSum_Field_Offset, checkSum)); - _checksumError = (checkSum != _optHeader.CheckSum); - } - - - if (!_allowTail) - { - UInt64 fileSize; - RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); - if (fileSize > _totalSize) - return S_FALSE; - } - - _parseResources = true; - // _parseResources = false; - - UInt64 mainSize = 0, mainSize2 = 0; - - for (i = 0; i < _sections.Size(); i++) - { - const CSection § = _sections[i]; - CMixItem mixItem; - mixItem.SectionIndex = i; - if (IsOpt()) - if (_parseResources && sect.Name == ".rsrc" && _items.IsEmpty()) - { - 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) - { - mixItem.ResourceIndex = j; - if (item.IsRcDataOrUnknown()) - { - if (item.Size >= mainSize) - { - mainSize2 = mainSize; - mainSize = item.Size; - _mainSubfile = _mixItems.Size(); - } - else if (item.Size >= mainSize2) - mainSize2 = item.Size; - } - _mixItems.Add(mixItem); - } - } - // 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 §2 = _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 = _mixItems.Size(); - } - else if (sect.PSize >= mainSize2) - mainSize2 = sect.PSize; - } - _mixItems.Add(mixItem); - } - - if (mainSize2 >= (1 << 20) && mainSize < mainSize2 * 2) - _mainSubfile = -1; - - for (i = 0; i < _mixItems.Size(); i++) - { - const CMixItem &mixItem = _mixItems[i]; - if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name == "_winzip_") - { - _mainSubfile = i; - break; - } - } - - 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; -} - -STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback) -{ - COM_TRY_BEGIN - Close(); - RINOK(Open2(inStream, callback)); - _stream = inStream; - return S_OK; - COM_TRY_END -} - -void CHandler::CloseResources() -{ - _usedRes.Free(); - _items.Clear(); - _strings.Clear(); - _versionFiles.Clear(); - _buf.Free(); - _versionFullString.Empty(); - _versionShortString.Empty(); - _originalFilename.Empty(); - _versionKeys.Clear(); -} - -STDMETHODIMP CHandler::Close() -{ - _totalSize = 0; - _checksumError = false; - _mainSubfile = -1; - - _stream.Release(); - _sections.Clear(); - _mixItems.Clear(); - CloseResources(); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _mixItems.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_stream); - - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()); - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - UInt32 index = allFilesMode ? i : indices[i]; - - CMyComPtr outStream; - RINOK(extractCallback->GetStream(index, &outStream, askMode)); - const CMixItem &mixItem = _mixItems[index]; - - const CSection § = _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(_stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL)); - 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 -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - *stream = 0; - - const CMixItem &mixItem = _mixItems[index]; - const CSection § = _sections[mixItem.SectionIndex]; - if (mixItem.IsSectionItem()) - return CreateLimitedInStream(_stream, sect.Pa, sect.PSize, stream); - - CBufInStream *inStreamSpec = new CBufInStream; - CMyComPtr streamTemp = inStreamSpec; - CReferenceBuf *referenceBuf = new CReferenceBuf; - CMyComPtr 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 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 -} - -STDMETHODIMP CHandler::AllowTail(Int32 allowTail) -{ - _allowTail = IntToBool(allowTail); - return S_OK; -} - -static const Byte k_Signature[] = { 'M', 'Z' }; - -REGISTER_ARC_I( - "PE", "exe dll sys", 0, 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", 0, 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, ARRAY_SIZE(pairs), val) -#define MY_FIND_VALUE_2(strings, val) (val < 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; - } -}; - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public IArchiveAllowTail, - public CMyUnknownImp -{ - CRecordVector _items; - CMyComPtr _stream; - UInt32 _totalSize; - bool _allowTail; - CHeader _h; - - HRESULT Open2(IInStream *stream); -public: - MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IArchiveAllowTail) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - STDMETHOD(AllowTail)(Int32 allowTail); - 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 - -STDMETHODIMP 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 -} - -STDMETHODIMP 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(stream->Seek(0, STREAM_SEEK_END, &fileSize)); - if (fileSize > _totalSize) - return S_FALSE; - } - - return S_OK; -} - -STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) -{ - COM_TRY_BEGIN - Close(); - try - { - if (Open2(inStream) != S_OK) - return S_FALSE; - _stream = inStream; - } - catch(...) { return S_FALSE; } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _totalSize = 0; - _stream.Release(); - _items.Clear(); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items.Size(); - return S_OK; -} - -STDMETHODIMP 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 (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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_stream); - - for (i = 0; i < numItems; i++) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()); - CMyComPtr realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - 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(_stream->Seek(item.Pa, STREAM_SEEK_SET, NULL)); - 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 -} - -STDMETHODIMP 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 -} - -STDMETHODIMP CHandler::AllowTail(Int32 allowTail) -{ - _allowTail = IntToBool(allowTail); - return S_OK; -} - -static const Byte k_Signature[] = { 'V', 'Z' }; - -REGISTER_ARC_I( - "TE", "te", 0, 0xCF, - k_Signature, - 0, - NArcInfoFlags::kPreArc, - IsArc_Te) - -} -} +// PeHandler.cpp + +#include "StdAfx.h" + +// #include + +#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 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 <= 31; i++) + if (((UInt32)1 << i) == FileAlign) + return 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; + 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) {} + + const UInt32 GetSizeExtract() const { return PSize; } + const 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(Byte 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(Byte c) +{ + Byte *p = Buf.GetCurPtrAndGrow(2); + p[0] = 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; +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public IArchiveAllowTail, + public CMyUnknownImp +{ + CMyComPtr _stream; + CObjectVector _sections; + CHeader _header; + UInt32 _totalSize; + Int32 _mainSubfile; + + CRecordVector _mixItems; + CRecordVector _items; + CObjectVector _strings; + CObjectVector _versionFiles; + UString _versionFullString; + UString _versionShortString; + UString _originalFilename; + CObjectVector _versionKeys; + + CByteBuffer _buf; + bool _oneLang; + UString _resourcesPrefix; + CUsedBitmap _usedRes; + bool _parseResources; + bool _checksumError; + + bool IsOpt() const { return _header.OptHeaderSize != 0; } + + COptHeader _optHeader; + + bool _allowTail; + bool _coffMode; + + 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 &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 §, 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) + {} + + MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IArchiveAllowTail) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(AllowTail)(Int32 allowTail); +}; + + +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) + { + FILETIME ft; + NTime::UnixTimeToFileTime(unixTime, ft); + prop = ft; + } +} + +STDMETHODIMP 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 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(); + } +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + const CMixItem &mixItem = _mixItems[index]; + if (mixItem.StringIndex >= 0) + { + const CStringItem &item = _strings[mixItem.StringIndex]; + switch (propID) + { + case kpidPath: + { + 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 < 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: prop = MultiByteToUnicodeString(item.Name); 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, 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 § = _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(stream->Seek(pa, STREAM_SEEK_SET, NULL)); + 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 § = _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 &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( 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.Planes != 1 || h.BitCount > 32) + return 0; + if (h.SizeImage == 0) + { + if (h.Compression != 0) // BI_RGB + return 0; + h.SizeImage = GetImageSize(h.XSize, h.YSize, h.BitCount); + } + UInt32 totalSize = kBmpHeaderSize + size; + UInt32 offBits = totalSize - h.SizeImage; + // BITMAPFILEHEADER + SetUi16(dest, 0x4D42); + SetUi32(dest + 2, totalSize); + SetUi32(dest + 6, 0); + SetUi32(dest + 10, offBits); + return kBmpHeaderSize; +} + +static UInt32 SetIconHeader(Byte *dest, const Byte *src, UInt32 size) +{ + CBitmapInfoHeader h; + if (!h.Parse(src, size)) + return 0; + if (h.YSize < 0) + h.YSize = -h.YSize; + if (h.XSize > (1 << 26) || h.YSize > (1 << 26) || h.Planes != 1 || + h.Compression != 0) // BI_RGB + return 0; + + UInt32 numBitCount = h.BitCount; + if (numBitCount != 1 && + numBitCount != 4 && + numBitCount != 8 && + numBitCount != 24 && + numBitCount != 32) + return 0; + + if ((h.YSize & 1) != 0) + return 0; + h.YSize /= 2; + if (h.XSize > 0x100 || h.YSize > 0x100) + return 0; + + UInt32 imageSize; + // imageSize is not correct if AND mask array contains zeros + // in this case it is equal image1Size + + // UInt32 imageSize = h.SizeImage; + // if (imageSize == 0) + // { + UInt32 image1Size = GetImageSize(h.XSize, h.YSize, h.BitCount); + UInt32 image2Size = GetImageSize(h.XSize, h.YSize, 1); + imageSize = image1Size + image2Size; + // } + UInt32 numColors = 0; + if (numBitCount < 16) + numColors = 1 << numBitCount; + + SetUi16(dest, 0); // Reserved + SetUi16(dest + 2, 1); // RES_ICON + SetUi16(dest + 4, 1); // ResCount + + dest[6] = (Byte)h.XSize; // Width + dest[7] = (Byte)h.YSize; // Height + dest[8] = (Byte)numColors; // ColorCount + dest[9] = 0; // Reserved + + SetUi32(dest + 10, 0); // Reserved1 / Reserved2 + + UInt32 numQuadsBytes = numColors * 4; + UInt32 BytesInRes = kBitmapInfoHeader_Size + numQuadsBytes + imageSize; + SetUi32(dest + 14, BytesInRes); + SetUi32(dest + 18, kIconHeaderSize); + + /* + Description = DWORDToString(xSize) + + kDelimiterChar + DWORDToString(ySize) + + kDelimiterChar + DWORDToString(numBitCount); + */ + return kIconHeaderSize; +} + +bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size) +{ + if ((size & 1) != 0) + return false; + + 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 &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 += '.'; + PrintUInt32(s, LOWORD(ms)); s += '.'; + PrintUInt32(s, HIWORD(ls)); s += '.'; + 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 &v, const char *key) +{ + FOR_VECTOR (i, v) + if (v[i].Key.IsEqualTo(key)) + return i; + return -1; +} + +static void AddToUniqueUStringVector(CObjectVector &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 &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 < 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 << 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 < 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 == ARRAY_SIZE(k_VS_FileOS)) + { + UInt32 high = OS >> 16; + if (high < 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 < ARRAY_SIZE(k_VS_FileOS_Low)) + f.AddString(k_VS_FileOS_Low[low]); + else + PrintHex(f, low); + } + } + f.NewLine(); + + f.AddString("FILETYPE "); + if (Type < 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 < 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 < 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 (;;) + { + Byte c = *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 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; + int t = Get_Utf16Str_Len_InBytes(p + k_ResoureBlockHeader_Size, TotalLen - k_ResoureBlockHeader_Size); + if (t < 0) + return false; + StrSize = 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 &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); + 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 += 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 § = _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(stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL)); + + _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 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 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 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 = _versionFiles.Size(); + mixItem.SectionIndex = 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 = i; + mixItem.SectionIndex = 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 < 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(stream->Seek(_peOffset, STREAM_SEEK_SET, NULL)); + 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)); + + 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 § = _sections.AddNew(); + sect.Parse(buffer + pos); + sect.IsRealSect = true; + + /* PE pre-file in .hxs file has errors: + PSize of resource is larger tnan real size. + So it overlaps next ".its" section. + We correct it. */ + + if (i > 0) + { + CSection &prev = _sections[i - 1]; + if (prev.Pa < sect.Pa && + prev.Pa + prev.PSize > sect.Pa && + sect.PSize > 0) + { + // printf("\n !!!! Section correction: %s\n ", prev.Name); + // fflush(stdout); + prev.PSize = sect.Pa - prev.Pa; + } + } + /* last ".its" section in hxs file has incorrect sect.PSize. + So we reduce it 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 § = _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(stream->Seek(_totalSize, STREAM_SEEK_SET, NULL)); + 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(stream->Seek((UInt64)_header.PointerToSymbolTable + size, STREAM_SEEK_SET, NULL)); + Byte buf[4]; + RINOK(ReadStream_FALSE(stream, buf, 4)); + UInt32 size2 = Get32(buf); + if (size2 >= (1 << 28)) + return S_FALSE; + size += size2; + + CSection § = _sections.AddNew(); + sect.Name = "COFF_SYMBOLS"; + sect.Va = 0; + sect.Pa = _header.PointerToSymbolTable; + sect.PSize = sect.VSize = size; + sect.UpdateTotalSize(_totalSize); + } + + { + CObjectVector 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(stream->Seek(0, STREAM_SEEK_SET, NULL)); + UInt32 checkSum = 0; + RINOK(CalcCheckSum(stream, _totalSize, optStart + k_CheckSum_Field_Offset, checkSum)); + _checksumError = (checkSum != _optHeader.CheckSum); + } + + + if (!_allowTail) + { + UInt64 fileSize; + RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); + if (fileSize > _totalSize) + return S_FALSE; + } + + _parseResources = true; + // _parseResources = false; + + UInt64 mainSize = 0, mainSize2 = 0; + + for (i = 0; i < _sections.Size(); i++) + { + const CSection § = _sections[i]; + CMixItem mixItem; + mixItem.SectionIndex = i; + if (IsOpt()) + if (_parseResources && sect.Name == ".rsrc" && _items.IsEmpty()) + { + 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) + { + mixItem.ResourceIndex = j; + if (item.IsRcDataOrUnknown()) + { + if (item.Size >= mainSize) + { + mainSize2 = mainSize; + mainSize = item.Size; + _mainSubfile = _mixItems.Size(); + } + else if (item.Size >= mainSize2) + mainSize2 = item.Size; + } + _mixItems.Add(mixItem); + } + } + // 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 §2 = _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 = _mixItems.Size(); + } + else if (sect.PSize >= mainSize2) + mainSize2 = sect.PSize; + } + _mixItems.Add(mixItem); + } + + if (mainSize2 >= (1 << 20) && mainSize < mainSize2 * 2) + _mainSubfile = -1; + + for (i = 0; i < _mixItems.Size(); i++) + { + const CMixItem &mixItem = _mixItems[i]; + if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name == "_winzip_") + { + _mainSubfile = i; + break; + } + } + + 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; +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(inStream, callback)); + _stream = inStream; + return S_OK; + COM_TRY_END +} + +void CHandler::CloseResources() +{ + _usedRes.Free(); + _items.Clear(); + _strings.Clear(); + _versionFiles.Clear(); + _buf.Free(); + _versionFullString.Empty(); + _versionShortString.Empty(); + _originalFilename.Empty(); + _versionKeys.Clear(); +} + +STDMETHODIMP CHandler::Close() +{ + _totalSize = 0; + _checksumError = false; + _mainSubfile = -1; + + _stream.Release(); + _sections.Clear(); + _mixItems.Clear(); + CloseResources(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _mixItems.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(_stream); + + for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + + CMyComPtr outStream; + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + const CMixItem &mixItem = _mixItems[index]; + + const CSection § = _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(_stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL)); + 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 +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = 0; + + const CMixItem &mixItem = _mixItems[index]; + const CSection § = _sections[mixItem.SectionIndex]; + if (mixItem.IsSectionItem()) + return CreateLimitedInStream(_stream, sect.Pa, sect.PSize, stream); + + CBufInStream *inStreamSpec = new CBufInStream; + CMyComPtr streamTemp = inStreamSpec; + CReferenceBuf *referenceBuf = new CReferenceBuf; + CMyComPtr 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 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 +} + +STDMETHODIMP CHandler::AllowTail(Int32 allowTail) +{ + _allowTail = IntToBool(allowTail); + return S_OK; +} + +static const Byte k_Signature[] = { 'M', 'Z' }; + +REGISTER_ARC_I( + "PE", "exe dll sys", 0, 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", 0, 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, ARRAY_SIZE(pairs), val) +#define MY_FIND_VALUE_2(strings, val) (val < 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; + } +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public IArchiveAllowTail, + public CMyUnknownImp +{ + CRecordVector _items; + CMyComPtr _stream; + UInt32 _totalSize; + bool _allowTail; + CHeader _h; + + HRESULT Open2(IInStream *stream); +public: + MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IArchiveAllowTail) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(AllowTail)(Int32 allowTail); + 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 + +STDMETHODIMP 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 +} + +STDMETHODIMP 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(stream->Seek(0, STREAM_SEEK_END, &fileSize)); + if (fileSize > _totalSize) + return S_FALSE; + } + + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + try + { + if (Open2(inStream) != S_OK) + return S_FALSE; + _stream = inStream; + } + catch(...) { return S_FALSE; } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _totalSize = 0; + _stream.Release(); + _items.Clear(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP 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 (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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(_stream); + + for (i = 0; i < numItems; i++) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + CMyComPtr realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + 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(_stream->Seek(item.Pa, STREAM_SEEK_SET, NULL)); + 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 +} + +STDMETHODIMP 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 +} + +STDMETHODIMP CHandler::AllowTail(Int32 allowTail) +{ + _allowTail = IntToBool(allowTail); + return S_OK; +} + +static const Byte k_Signature[] = { 'V', 'Z' }; + +REGISTER_ARC_I( + "TE", "te", 0, 0xCF, + k_Signature, + 0, + NArcInfoFlags::kPreArc, + IsArc_Te) + +} +} diff --git a/CPP/7zip/Archive/PpmdHandler.cpp b/CPP/7zip/Archive/PpmdHandler.cpp index 29274aa75..c80400bcb 100644 --- a/CPP/7zip/Archive/PpmdHandler.cpp +++ b/CPP/7zip/Archive/PpmdHandler.cpp @@ -1,479 +1,479 @@ -/* PpmdHandler.cpp -- PPMd format handler -2015-11-30 : 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(0) {} - ~CBuf() { ::MidFree(Buf); } - bool Alloc() - { - if (!Buf) - Buf = (Byte *)::MidAlloc(kBufSize); - return (Buf != 0); - } -}; - -static const UInt32 kHeaderSize = 16; -static const UInt32 kSignature = 0x84ACAF8F; -static const unsigned kNewHeaderVer = 8; - -struct CItem -{ - UInt32 Attrib; - UInt32 Time; - AString Name; - - unsigned Order; - unsigned MemInMB; - unsigned Ver; - unsigned Restor; - - HRESULT ReadHeader(ISequentialInStream *s, UInt32 &headerSize); - bool IsSupported() const { return Ver == 7 || (Ver == 8 && Restor <= 1); } -}; - -HRESULT CItem::ReadHeader(ISequentialInStream *s, UInt32 &headerSize) -{ - Byte h[kHeaderSize]; - RINOK(ReadStream_FALSE(s, h, kHeaderSize)); - if (GetUi32(h) != kSignature) - return S_FALSE; - Attrib = GetUi32(h + 4); - Time = GetUi32(h + 12); - unsigned info = GetUi16(h + 8); - Order = (info & 0xF) + 1; - MemInMB = ((info >> 4) & 0xFF) + 1; - Ver = info >> 12; - - 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; -} - -class CHandler: - public IInArchive, - public IArchiveOpenSeq, - public CMyUnknownImp -{ - CItem _item; - UInt32 _headerSize; - bool _packSize_Defined; - UInt64 _packSize; - CMyComPtr _stream; - - void GetVersion(NCOM::CPropVariant &prop); - -public: - MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq) - INTERFACE_IInArchive(;) - STDMETHOD(OpenSeq)(ISequentialInStream *stream); -}; - -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; -} - -STDMETHODIMP 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; -} - - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = 1; - return S_OK; -} - -STDMETHODIMP 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::DosTimeToFileTime(_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 -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) -{ - return OpenSeq(stream); -} - -STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) -{ - COM_TRY_BEGIN - HRESULT res; - try - { - Close(); - res = _item.ReadHeader(stream, _headerSize); - } - catch(...) { res = S_FALSE; } - if (res == S_OK) - _stream = stream; - else - Close(); - return res; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _packSize = 0; - _packSize_Defined = false; - _stream.Release(); - return S_OK; -} - -static const UInt32 kTopValue = (1 << 24); -static const UInt32 kBot = (1 << 15); - -struct CRangeDecoder -{ - IPpmd7_RangeDec vt; - UInt32 Range; - UInt32 Code; - UInt32 Low; - CByteInBufWrap *Stream; - -public: - bool Init() - { - Code = 0; - Low = 0; - Range = 0xFFFFFFFF; - for (int i = 0; i < 4; i++) - Code = (Code << 8) | Stream->ReadByte(); - return Code < 0xFFFFFFFF; - } - - void Normalize() - { - while ((Low ^ (Low + Range)) < kTopValue || - Range < kBot && ((Range = (0 - Low) & (kBot - 1)), 1)) - { - Code = (Code << 8) | Stream->ReadByte(); - Range <<= 8; - Low <<= 8; - } - } - - CRangeDecoder(); -}; - - -extern "C" { - -#define GET_RangeDecoder CRangeDecoder *p = CONTAINER_FROM_VTBL(pp, CRangeDecoder, vt); - -static UInt32 Range_GetThreshold(const IPpmd7_RangeDec *pp, UInt32 total) -{ - GET_RangeDecoder - return p->Code / (p->Range /= total); -} - -static void Range_Decode(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size) -{ - GET_RangeDecoder - start *= p->Range; - p->Low += start; - p->Code -= start; - p->Range *= size; - p->Normalize(); -} - -static UInt32 Range_DecodeBit(const IPpmd7_RangeDec *pp, UInt32 size0) -{ - GET_RangeDecoder - if (p->Code / (p->Range >>= 14) < size0) - { - Range_Decode(&p->vt, 0, size0); - return 0; - } - else - { - Range_Decode(&p->vt, size0, (1 << 14) - size0); - return 1; - } -} - -} - -CRangeDecoder::CRangeDecoder() -{ - vt.GetThreshold = Range_GetThreshold; - vt.Decode = Range_Decode; - vt.DecodeBit = Range_DecodeBit; -} - -struct CPpmdCpp -{ - unsigned Ver; - CRangeDecoder _rc; - CPpmd7 _ppmd7; - CPpmd8 _ppmd8; - - CPpmdCpp(unsigned version) - { - Ver = version; - Ppmd7_Construct(&_ppmd7); - Ppmd8_Construct(&_ppmd8); - } - - ~CPpmdCpp() - { - Ppmd7_Free(&_ppmd7, &g_BigAlloc); - Ppmd8_Free(&_ppmd8, &g_BigAlloc); - } - - bool Alloc(UInt32 memInMB) - { - memInMB <<= 20; - if (Ver == 7) - return Ppmd7_Alloc(&_ppmd7, memInMB, &g_BigAlloc) != 0; - return Ppmd8_Alloc(&_ppmd8, memInMB, &g_BigAlloc) != 0; - } - - void Init(unsigned order, unsigned restor) - { - if (Ver == 7) - Ppmd7_Init(&_ppmd7, order); - else - Ppmd8_Init(&_ppmd8, order, restor);; - } - - bool InitRc(CByteInBufWrap *inStream) - { - if (Ver == 7) - { - _rc.Stream = inStream; - return _rc.Init(); - } - else - { - _ppmd8.Stream.In = &inStream->vt; - return Ppmd8_RangeDec_Init(&_ppmd8) != 0; - } - } - - bool IsFinishedOK() - { - if (Ver == 7) - return Ppmd7z_RangeDec_IsFinishedOK(&_rc); - return Ppmd8_RangeDec_IsFinishedOK(&_ppmd8); - } -}; - - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - // extractCallback->SetTotal(_packSize); - UInt64 currentTotalPacked = 0; - RINOK(extractCallback->SetCompleted(¤tTotalPacked)); - CMyComPtr realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); - if (!testMode && !realOutStream) - return S_OK; - - extractCallback->PrepareOperation(askMode); - - CByteInBufWrap inBuf; - if (!inBuf.Alloc(1 << 20)) - return E_OUTOFMEMORY; - inBuf.Stream = _stream; - - CBuf outBuf; - if (!outBuf.Alloc()) - return E_OUTOFMEMORY; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, true); - - CPpmdCpp ppmd(_item.Ver); - if (!ppmd.Alloc(_item.MemInMB)) - return E_OUTOFMEMORY; - - Int32 opRes = NExtract::NOperationResult::kUnsupportedMethod; - - if (_item.IsSupported()) - { - opRes = NExtract::NOperationResult::kDataError; - - ppmd.Init(_item.Order, _item.Restor); - inBuf.Init(); - UInt64 outSize = 0; - - if (ppmd.InitRc(&inBuf) && !inBuf.Extra && inBuf.Res == S_OK) - for (;;) - { - lps->InSize = _packSize = inBuf.GetProcessed(); - lps->OutSize = outSize; - RINOK(lps->SetCur()); - - size_t i; - int sym = 0; - - if (ppmd.Ver == 7) - { - for (i = 0; i < kBufSize; i++) - { - sym = Ppmd7_DecodeSymbol(&ppmd._ppmd7, &ppmd._rc.vt); - if (inBuf.Extra || sym < 0) - break; - outBuf.Buf[i] = (Byte)sym; - } - } - else - { - for (i = 0; i < kBufSize; i++) - { - sym = Ppmd8_DecodeSymbol(&ppmd._ppmd8); - if (inBuf.Extra || sym < 0) - break; - outBuf.Buf[i] = (Byte)sym; - } - } - - outSize += i; - _packSize = _headerSize + inBuf.GetProcessed(); - _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", 0, 0xD, - k_Signature, - 0, - 0, - NULL) - -}} +/* PpmdHandler.cpp -- PPMd format handler +2015-11-30 : 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(0) {} + ~CBuf() { ::MidFree(Buf); } + bool Alloc() + { + if (!Buf) + Buf = (Byte *)::MidAlloc(kBufSize); + return (Buf != 0); + } +}; + +static const UInt32 kHeaderSize = 16; +static const UInt32 kSignature = 0x84ACAF8F; +static const unsigned kNewHeaderVer = 8; + +struct CItem +{ + UInt32 Attrib; + UInt32 Time; + AString Name; + + unsigned Order; + unsigned MemInMB; + unsigned Ver; + unsigned Restor; + + HRESULT ReadHeader(ISequentialInStream *s, UInt32 &headerSize); + bool IsSupported() const { return Ver == 7 || (Ver == 8 && Restor <= 1); } +}; + +HRESULT CItem::ReadHeader(ISequentialInStream *s, UInt32 &headerSize) +{ + Byte h[kHeaderSize]; + RINOK(ReadStream_FALSE(s, h, kHeaderSize)); + if (GetUi32(h) != kSignature) + return S_FALSE; + Attrib = GetUi32(h + 4); + Time = GetUi32(h + 12); + unsigned info = GetUi16(h + 8); + Order = (info & 0xF) + 1; + MemInMB = ((info >> 4) & 0xFF) + 1; + Ver = info >> 12; + + 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; +} + +class CHandler: + public IInArchive, + public IArchiveOpenSeq, + public CMyUnknownImp +{ + CItem _item; + UInt32 _headerSize; + bool _packSize_Defined; + UInt64 _packSize; + CMyComPtr _stream; + + void GetVersion(NCOM::CPropVariant &prop); + +public: + MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq) + INTERFACE_IInArchive(;) + STDMETHOD(OpenSeq)(ISequentialInStream *stream); +}; + +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; +} + +STDMETHODIMP 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; +} + + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1; + return S_OK; +} + +STDMETHODIMP 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::DosTimeToFileTime(_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 +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) +{ + return OpenSeq(stream); +} + +STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) +{ + COM_TRY_BEGIN + HRESULT res; + try + { + Close(); + res = _item.ReadHeader(stream, _headerSize); + } + catch(...) { res = S_FALSE; } + if (res == S_OK) + _stream = stream; + else + Close(); + return res; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _packSize = 0; + _packSize_Defined = false; + _stream.Release(); + return S_OK; +} + +static const UInt32 kTopValue = (1 << 24); +static const UInt32 kBot = (1 << 15); + +struct CRangeDecoder +{ + IPpmd7_RangeDec vt; + UInt32 Range; + UInt32 Code; + UInt32 Low; + CByteInBufWrap *Stream; + +public: + bool Init() + { + Code = 0; + Low = 0; + Range = 0xFFFFFFFF; + for (int i = 0; i < 4; i++) + Code = (Code << 8) | Stream->ReadByte(); + return Code < 0xFFFFFFFF; + } + + void Normalize() + { + while ((Low ^ (Low + Range)) < kTopValue || + Range < kBot && ((Range = (0 - Low) & (kBot - 1)), 1)) + { + Code = (Code << 8) | Stream->ReadByte(); + Range <<= 8; + Low <<= 8; + } + } + + CRangeDecoder(); +}; + + +extern "C" { + +#define GET_RangeDecoder CRangeDecoder *p = CONTAINER_FROM_VTBL(pp, CRangeDecoder, vt); + +static UInt32 Range_GetThreshold(const IPpmd7_RangeDec *pp, UInt32 total) +{ + GET_RangeDecoder + return p->Code / (p->Range /= total); +} + +static void Range_Decode(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size) +{ + GET_RangeDecoder + start *= p->Range; + p->Low += start; + p->Code -= start; + p->Range *= size; + p->Normalize(); +} + +static UInt32 Range_DecodeBit(const IPpmd7_RangeDec *pp, UInt32 size0) +{ + GET_RangeDecoder + if (p->Code / (p->Range >>= 14) < size0) + { + Range_Decode(&p->vt, 0, size0); + return 0; + } + else + { + Range_Decode(&p->vt, size0, (1 << 14) - size0); + return 1; + } +} + +} + +CRangeDecoder::CRangeDecoder() +{ + vt.GetThreshold = Range_GetThreshold; + vt.Decode = Range_Decode; + vt.DecodeBit = Range_DecodeBit; +} + +struct CPpmdCpp +{ + unsigned Ver; + CRangeDecoder _rc; + CPpmd7 _ppmd7; + CPpmd8 _ppmd8; + + CPpmdCpp(unsigned version) + { + Ver = version; + Ppmd7_Construct(&_ppmd7); + Ppmd8_Construct(&_ppmd8); + } + + ~CPpmdCpp() + { + Ppmd7_Free(&_ppmd7, &g_BigAlloc); + Ppmd8_Free(&_ppmd8, &g_BigAlloc); + } + + bool Alloc(UInt32 memInMB) + { + memInMB <<= 20; + if (Ver == 7) + return Ppmd7_Alloc(&_ppmd7, memInMB, &g_BigAlloc) != 0; + return Ppmd8_Alloc(&_ppmd8, memInMB, &g_BigAlloc) != 0; + } + + void Init(unsigned order, unsigned restor) + { + if (Ver == 7) + Ppmd7_Init(&_ppmd7, order); + else + Ppmd8_Init(&_ppmd8, order, restor);; + } + + bool InitRc(CByteInBufWrap *inStream) + { + if (Ver == 7) + { + _rc.Stream = inStream; + return _rc.Init(); + } + else + { + _ppmd8.Stream.In = &inStream->vt; + return Ppmd8_RangeDec_Init(&_ppmd8) != 0; + } + } + + bool IsFinishedOK() + { + if (Ver == 7) + return Ppmd7z_RangeDec_IsFinishedOK(&_rc); + return Ppmd8_RangeDec_IsFinishedOK(&_ppmd8); + } +}; + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + // extractCallback->SetTotal(_packSize); + UInt64 currentTotalPacked = 0; + RINOK(extractCallback->SetCompleted(¤tTotalPacked)); + CMyComPtr realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); + if (!testMode && !realOutStream) + return S_OK; + + extractCallback->PrepareOperation(askMode); + + CByteInBufWrap inBuf; + if (!inBuf.Alloc(1 << 20)) + return E_OUTOFMEMORY; + inBuf.Stream = _stream; + + CBuf outBuf; + if (!outBuf.Alloc()) + return E_OUTOFMEMORY; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, true); + + CPpmdCpp ppmd(_item.Ver); + if (!ppmd.Alloc(_item.MemInMB)) + return E_OUTOFMEMORY; + + Int32 opRes = NExtract::NOperationResult::kUnsupportedMethod; + + if (_item.IsSupported()) + { + opRes = NExtract::NOperationResult::kDataError; + + ppmd.Init(_item.Order, _item.Restor); + inBuf.Init(); + UInt64 outSize = 0; + + if (ppmd.InitRc(&inBuf) && !inBuf.Extra && inBuf.Res == S_OK) + for (;;) + { + lps->InSize = _packSize = inBuf.GetProcessed(); + lps->OutSize = outSize; + RINOK(lps->SetCur()); + + size_t i; + int sym = 0; + + if (ppmd.Ver == 7) + { + for (i = 0; i < kBufSize; i++) + { + sym = Ppmd7_DecodeSymbol(&ppmd._ppmd7, &ppmd._rc.vt); + if (inBuf.Extra || sym < 0) + break; + outBuf.Buf[i] = (Byte)sym; + } + } + else + { + for (i = 0; i < kBufSize; i++) + { + sym = Ppmd8_DecodeSymbol(&ppmd._ppmd8); + if (inBuf.Extra || sym < 0) + break; + outBuf.Buf[i] = (Byte)sym; + } + } + + outSize += i; + _packSize = _headerSize + inBuf.GetProcessed(); + _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", 0, 0xD, + k_Signature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/QcowHandler.cpp b/CPP/7zip/Archive/QcowHandler.cpp index 293679fd5..065f59b3c 100644 --- a/CPP/7zip/Archive/QcowHandler.cpp +++ b/CPP/7zip/Archive/QcowHandler.cpp @@ -1,611 +1,611 @@ -// QcowHandler.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.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 { - -#define SIGNATURE { 'Q', 'F', 'I', 0xFB, 0, 0, 0 } - -static const Byte k_Signature[] = SIGNATURE; - -class CHandler: public CHandlerImg -{ - unsigned _clusterBits; - unsigned _numMidBits; - UInt64 _compressedFlag; - - CObjectVector _tables; - UInt64 _cacheCluster; - CByteBuffer _cache; - CByteBuffer _cacheCompressed; - - UInt64 _comprPos; - size_t _comprSize; - - UInt64 _phySize; - - CBufInStream *_bufInStreamSpec; - CMyComPtr _bufInStream; - - CBufPtrSeqOutStream *_bufOutStreamSpec; - CMyComPtr _bufOutStream; - - NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoderSpec; - CMyComPtr _deflateDecoder; - - bool _needDeflate; - bool _isArc; - bool _unsupported; - - UInt32 _version; - UInt32 _cryptMethod; - - HRESULT Seek(UInt64 offset) - { - _posInArc = offset; - return Stream->Seek(offset, STREAM_SEEK_SET, NULL); - } - - HRESULT InitAndSeek() - { - _virtPos = 0; - return Seek(0); - } - - HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback); - -public: - INTERFACE_IInArchive_Img(;) - - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); -}; - - -STDMETHODIMP 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; - } - - for (;;) - { - UInt64 cluster = _virtPos >> _clusterBits; - size_t clusterSize = (size_t)1 << _clusterBits; - 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); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; - } - - UInt64 high = cluster >> _numMidBits; - - if (high < _tables.Size()) - { - const CByteBuffer &buffer = _tables[(unsigned)high]; - - if (buffer.Size() != 0) - { - 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; - unsigned numOffsetBits = (62 - (_clusterBits - 8)); - UInt64 offset = v & (((UInt64)1 << 62) - 1); - const size_t dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; - offset &= ((UInt64)1 << numOffsetBits) - 1; - UInt64 sectorOffset = offset >> 9 << 9; - UInt64 offset2inCache = sectorOffset - _comprPos; - - if (sectorOffset >= _comprPos && offset2inCache < _comprSize) - { - if (offset2inCache != 0) - { - _comprSize -= (size_t)offset2inCache; - memmove(_cacheCompressed, _cacheCompressed + offset2inCache, _comprSize); - _comprPos = sectorOffset; - } - sectorOffset += _comprSize; - } - else - { - _comprPos = sectorOffset; - _comprSize = 0; - } - - // printf("\nDeflate"); - if (sectorOffset != _posInArc) - { - // printf("\nDeflate %12I64x %12I64x\n", sectorOffset, sectorOffset - _posInArc); - RINOK(Seek(sectorOffset)); - } - - if (_cacheCompressed.Size() < dataSize) - return E_FAIL; - size_t dataSize3 = dataSize - _comprSize; - size_t dataSize2 = dataSize3; - RINOK(ReadStream(Stream, _cacheCompressed + _comprSize, &dataSize2)); - _posInArc += dataSize2; - if (dataSize2 != dataSize3) - return E_FAIL; - _comprSize += dataSize2; - - const size_t kSectorMask = (1 << 9) - 1; - 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? - UInt64 blockSize64 = clusterSize; - HRESULT res = _deflateDecoderSpec->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); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; - */ - } - - // 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(Seek(v)); - } - 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[] = -{ - kpidClusterSize, - kpidUnpackVer, - kpidMethod -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP 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 -} - - -STDMETHODIMP 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 = 0; - UInt32 l1Size = 0; - - 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; - unsigned numBits2 = (_clusterBits + _numMidBits); - 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 - - UInt64 refOffset = Get64(buf + 0x30); // must be aligned for cluster - 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) - { - size_t numBytes = refClusters << _clusterBits; - /* - CByteBuffer refs; - refs.Alloc(numBytes); - RINOK(stream->Seek(refOffset, STREAM_SEEK_SET, NULL)); - RINOK(ReadStream_FALSE(stream, refs, numBytes)); - */ - 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; - { - size_t t1SizeBytes = (size_t)l1Size << 3; - if ((t1SizeBytes >> 3) != l1Size) - return S_FALSE; - table.Alloc(t1SizeBytes); - RINOK(stream->Seek(l1Offset, STREAM_SEEK_SET, NULL)); - 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; - } - } - - if (openCallback) - { - UInt64 totalBytes = (UInt64)l1Size << (_numMidBits + 3); - RINOK(openCallback->SetTotal(NULL, &totalBytes)); - } - - _compressedFlag = (_version <= 1) ? ((UInt64)1 << 63) : ((UInt64)1 << 62); - const UInt64 offsetMask = _compressedFlag - 1; - - for (UInt32 i = 0; i < l1Size; i++) - { - if (openCallback) - { - UInt64 numBytes = (UInt64)i << (_numMidBits + 3); - RINOK(openCallback->SetCompleted(NULL, &numBytes)); - } - - CByteBuffer &buf2 = _tables.AddNew(); - - { - UInt64 v = Get64((const Byte *)table + (size_t)i * 8); - v &= offsetMask; - if (v == 0) - continue; - - buf2.Alloc((size_t)1 << (_numMidBits + 3)); - RINOK(stream->Seek(v, STREAM_SEEK_SET, NULL)); - RINOK(ReadStream_FALSE(stream, buf2, clusterSize)); - - const UInt64 end = v + clusterSize; - if (_phySize < end) - _phySize = end; - } - - for (size_t k = 0; k < clusterSize; 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; - } - } - } - - UInt64 end = offset + dataSize; - if (_phySize < end) - _phySize = end; - } - } - - if (_cryptMethod != 0) - _unsupported = true; - - if (_needDeflate && _version <= 1) // that case was not implemented - _unsupported = true; - - Stream = stream; - return S_OK; -} - - -STDMETHODIMP CHandler::Close() -{ - _tables.Clear(); - _phySize = 0; - _size = 0; - - _cacheCluster = (UInt64)(Int64)-1; - _comprPos = 0; - _comprSize = 0; - _needDeflate = false; - - _isArc = false; - _unsupported = false; - - _imgExt = NULL; - Stream.Release(); - return S_OK; -} - - -STDMETHODIMP 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); - } - - size_t clusterSize = (size_t)1 << _clusterBits; - _cache.AllocAtLeast(clusterSize); - _cacheCompressed.AllocAtLeast(clusterSize * 2); - } - - CMyComPtr 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) - -}} +// QcowHandler.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.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 { + +#define SIGNATURE { 'Q', 'F', 'I', 0xFB, 0, 0, 0 } + +static const Byte k_Signature[] = SIGNATURE; + +class CHandler: public CHandlerImg +{ + unsigned _clusterBits; + unsigned _numMidBits; + UInt64 _compressedFlag; + + CObjectVector _tables; + UInt64 _cacheCluster; + CByteBuffer _cache; + CByteBuffer _cacheCompressed; + + UInt64 _comprPos; + size_t _comprSize; + + UInt64 _phySize; + + CBufInStream *_bufInStreamSpec; + CMyComPtr _bufInStream; + + CBufPtrSeqOutStream *_bufOutStreamSpec; + CMyComPtr _bufOutStream; + + NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoderSpec; + CMyComPtr _deflateDecoder; + + bool _needDeflate; + bool _isArc; + bool _unsupported; + + UInt32 _version; + UInt32 _cryptMethod; + + HRESULT Seek(UInt64 offset) + { + _posInArc = offset; + return Stream->Seek(offset, STREAM_SEEK_SET, NULL); + } + + HRESULT InitAndSeek() + { + _virtPos = 0; + return Seek(0); + } + + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback); + +public: + INTERFACE_IInArchive_Img(;) + + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + + +STDMETHODIMP 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; + } + + for (;;) + { + UInt64 cluster = _virtPos >> _clusterBits; + size_t clusterSize = (size_t)1 << _clusterBits; + 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); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + } + + UInt64 high = cluster >> _numMidBits; + + if (high < _tables.Size()) + { + const CByteBuffer &buffer = _tables[(unsigned)high]; + + if (buffer.Size() != 0) + { + 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; + unsigned numOffsetBits = (62 - (_clusterBits - 8)); + UInt64 offset = v & (((UInt64)1 << 62) - 1); + const size_t dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; + offset &= ((UInt64)1 << numOffsetBits) - 1; + UInt64 sectorOffset = offset >> 9 << 9; + UInt64 offset2inCache = sectorOffset - _comprPos; + + if (sectorOffset >= _comprPos && offset2inCache < _comprSize) + { + if (offset2inCache != 0) + { + _comprSize -= (size_t)offset2inCache; + memmove(_cacheCompressed, _cacheCompressed + offset2inCache, _comprSize); + _comprPos = sectorOffset; + } + sectorOffset += _comprSize; + } + else + { + _comprPos = sectorOffset; + _comprSize = 0; + } + + // printf("\nDeflate"); + if (sectorOffset != _posInArc) + { + // printf("\nDeflate %12I64x %12I64x\n", sectorOffset, sectorOffset - _posInArc); + RINOK(Seek(sectorOffset)); + } + + if (_cacheCompressed.Size() < dataSize) + return E_FAIL; + size_t dataSize3 = dataSize - _comprSize; + size_t dataSize2 = dataSize3; + RINOK(ReadStream(Stream, _cacheCompressed + _comprSize, &dataSize2)); + _posInArc += dataSize2; + if (dataSize2 != dataSize3) + return E_FAIL; + _comprSize += dataSize2; + + const size_t kSectorMask = (1 << 9) - 1; + 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? + UInt64 blockSize64 = clusterSize; + HRESULT res = _deflateDecoderSpec->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); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + */ + } + + // 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(Seek(v)); + } + 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[] = +{ + kpidClusterSize, + kpidUnpackVer, + kpidMethod +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP 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 +} + + +STDMETHODIMP 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 = 0; + UInt32 l1Size = 0; + + 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; + unsigned numBits2 = (_clusterBits + _numMidBits); + 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 + + UInt64 refOffset = Get64(buf + 0x30); // must be aligned for cluster + 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) + { + size_t numBytes = refClusters << _clusterBits; + /* + CByteBuffer refs; + refs.Alloc(numBytes); + RINOK(stream->Seek(refOffset, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(stream, refs, numBytes)); + */ + 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; + { + size_t t1SizeBytes = (size_t)l1Size << 3; + if ((t1SizeBytes >> 3) != l1Size) + return S_FALSE; + table.Alloc(t1SizeBytes); + RINOK(stream->Seek(l1Offset, STREAM_SEEK_SET, NULL)); + 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; + } + } + + if (openCallback) + { + UInt64 totalBytes = (UInt64)l1Size << (_numMidBits + 3); + RINOK(openCallback->SetTotal(NULL, &totalBytes)); + } + + _compressedFlag = (_version <= 1) ? ((UInt64)1 << 63) : ((UInt64)1 << 62); + const UInt64 offsetMask = _compressedFlag - 1; + + for (UInt32 i = 0; i < l1Size; i++) + { + if (openCallback) + { + UInt64 numBytes = (UInt64)i << (_numMidBits + 3); + RINOK(openCallback->SetCompleted(NULL, &numBytes)); + } + + CByteBuffer &buf2 = _tables.AddNew(); + + { + UInt64 v = Get64((const Byte *)table + (size_t)i * 8); + v &= offsetMask; + if (v == 0) + continue; + + buf2.Alloc((size_t)1 << (_numMidBits + 3)); + RINOK(stream->Seek(v, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(stream, buf2, clusterSize)); + + const UInt64 end = v + clusterSize; + if (_phySize < end) + _phySize = end; + } + + for (size_t k = 0; k < clusterSize; 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; + } + } + } + + UInt64 end = offset + dataSize; + if (_phySize < end) + _phySize = end; + } + } + + if (_cryptMethod != 0) + _unsupported = true; + + if (_needDeflate && _version <= 1) // that case was not implemented + _unsupported = true; + + Stream = stream; + return S_OK; +} + + +STDMETHODIMP CHandler::Close() +{ + _tables.Clear(); + _phySize = 0; + _size = 0; + + _cacheCluster = (UInt64)(Int64)-1; + _comprPos = 0; + _comprSize = 0; + _needDeflate = false; + + _isArc = false; + _unsupported = false; + + _imgExt = NULL; + Stream.Release(); + return S_OK; +} + + +STDMETHODIMP 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); + } + + size_t clusterSize = (size_t)1 << _clusterBits; + _cache.AllocAtLeast(clusterSize); + _cacheCompressed.AllocAtLeast(clusterSize * 2); + } + + CMyComPtr 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 index 962382393..320771d5b 100644 --- a/CPP/7zip/Archive/Rar/Rar5Handler.cpp +++ b/CPP/7zip/Archive/Rar/Rar5Handler.cpp @@ -1,3020 +1,3020 @@ -// 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; - -#define SIGNATURE { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0 } - -static const Byte kMarker[kMarkerSize] = SIGNATURE; - -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 = 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; - - UInt64 len; - 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, 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 < ARRAY_SIZE(g_ExtraTimeFlags); i++) - if ((flags & ((UInt64)1 << i)) != 0) - s += g_ExtraTimeFlags[i]; - flags &= ~(((UInt64)1 << 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, 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; - int offset = FindExtra(NExtraID::kLink, size); - if (offset < 0) - return false; - if (!link.Parse(Extra + (unsigned)offset, size)) - return false; - link.NameOffset += 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; - if (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; -} - - -class COutStreamWithHash: - public ISequentialOutStream, - public CMyUnknownImp -{ - ISequentialOutStream *_stream; - UInt64 _pos; - UInt64 _size; - bool _size_Defined; - Byte *_destBuf; -public: - CHash _hash; - - COutStreamWithHash(): _destBuf(NULL) {} - - MY_UNKNOWN_IMP - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); - 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; } -}; - - -STDMETHODIMP 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 m_CryptoDecoder; - - 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 password; - RINOK(getTextPassword->CryptoGetTextPassword(&password)); - AString utf8; - const unsigned kPasswordLen_MAX = 127; - UString unicode = (LPCOLESTR)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_CryptoDecoderSpec->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_CryptoDecoderSpec->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(stream->Seek(StreamStartPosition, STREAM_SEEK_SET, NULL)); - RINOK(FindSignatureInStream(stream, kMarker, kMarkerSize, - searchHeaderSizeLimit, arcStartPos)); - arcStartPos += StreamStartPosition; - Position = arcStartPos + kMarkerSize; - RINOK(stream->Seek(Position, STREAM_SEEK_SET, NULL)); - } - } - - 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 copyCoder; - - CMyComPtr LzCoders[2]; - bool SolidAllowed; - - CFilterCoder *filterStreamSpec; - CMyComPtr filterStream; - - NCrypto::NRar5::CDecoder *cryptoDecoderSpec; - CMyComPtr cryptoDecoder; - - CMyComPtr getTextPassword; - - COutStreamWithHash *outStreamSpec; - CMyComPtr 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 &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 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 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 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 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 = item.NextItem; - } -} - - -STDMETHODIMP 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; - if (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 -} - - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _refs.Size(); - return S_OK; -} - - -static const Byte kRawProps[] = -{ - kpidChecksum, - kpidNtSecure -}; - - -STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) -{ - *numProps = ARRAY_SIZE(kRawProps); - return S_OK; -} - -STDMETHODIMP CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) -{ - *propID = kRawProps[index]; - *name = 0; - return S_OK; -} - -STDMETHODIMP 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; -} - - -STDMETHODIMP 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; - int offset = item.FindExtra(NExtraID::kTime, size); - if (offset < 0) - return; - - const Byte *p = item.Extra + (unsigned)offset; - UInt64 flags; - { - 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; - unsigned i; - for (i = 0; i < 3; i++) - if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0) - { - if (i == stampIndex) - curStamp = numStamps; - numStamps++; - } - - FILETIME ft; - - if ((flags & NTimeRecord::NFlags::kUnixTime) != 0) - { - curStamp *= 4; - if (curStamp + 4 > size) - return; - const Byte *p2 = p + curStamp; - UInt64 val = NTime::UnixTimeToFileTime64(Get32(p2)); - numStamps *= 4; - if ((flags & NTimeRecord::NFlags::kUnixNs) != 0 && numStamps * 2 <= size) - { - const UInt32 ns = Get32(p2 + numStamps) & 0x3FFFFFFF; - if (ns < 1000000000) - val += ns / 100; - } - ft.dwLowDateTime = (DWORD)val; - ft.dwHighDateTime = (DWORD)(val >> 32); - } - else - { - curStamp *= 8; - if (curStamp + 8 > size) - return; - const Byte *p2 = p + curStamp; - ft.dwLowDateTime = Get32(p2); - ft.dwHighDateTime = Get32(p2 + 4); - } - - prop = ft; -} - - -STDMETHODIMP 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) - { - CItem &mainItem = _items[_refs[ref.Parent].Item]; - s = mainItem.Name; - } - - AString name; - item.GetAltStreamName(name); - if (name[0] != ':') - s += ':'; - s += name; - if (!ConvertUTF8ToUnicode(s, unicodeName)) - break; - } - else - { - if (!ConvertUTF8ToUnicode(item.Name, unicodeName)) - break; - 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()) - { - FILETIME ft; - NWindows::NTime::UnixTimeToFileTime(item.UnixMTime, ft); - prop = ft; - } - 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()) - { - FILETIME ft; - NWindows::NTime::UnixTimeToFileTime(baseItem.UnixMTime, ft); - prop = ft; - } - } - 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; - if (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, 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 < 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) - { - unsigned refIndex = sorted[left - 1]; - if (CompareItemsPaths(handler, index, refIndex, &s) == 0) - return refIndex; - } - if (right < sorted.Size()) - { - unsigned refIndex = sorted[right]; - if (CompareItemsPaths(handler, index, refIndex, &s) == 0) - return refIndex; - } - return -1; - } - - unsigned mid = (left + right) / 2; - unsigned refIndex = sorted[mid]; - int compare = CompareItemsPaths2(handler, index, refIndex, &s); - if (compare == 0) - return 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 openVolumeCallback; - CMyComPtr 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 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->Seek(0, STREAM_SEEK_CUR, &arch.StreamStartPosition)); - RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); - RINOK(inStream->Seek(arch.StreamStartPosition, STREAM_SEEK_SET, NULL)); - - 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->Seek(arch.Position, STREAM_SEEK_SET, NULL)); - - { - 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->Seek(arcInfo.EndPos, STREAM_SEEK_SET, NULL)); - 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 = _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 = ref2.Last; - needAdd = false; - } - } - } - } - - if (needAdd) - { - if (item.IsSplitAfter()) - prevSplitFile = _refs.Size(); - if (!item.IsService()) - prevMainFile = _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; -} - - -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *openCallback) -{ - COM_TRY_BEGIN - Close(); - return Open2(stream, maxCheckStartPosition, openCallback); - COM_TRY_END -} - -STDMETHODIMP 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 -} - - -class CVolsInStream: - public ISequentialInStream, - public CMyUnknownImp -{ - UInt64 _rem; - ISequentialInStream *_stream; - const CObjectVector *_arcs; - const CObjectVector *_items; - int _itemIndex; -public: - bool CrcIsOK; -private: - CHash _hash; -public: - MY_UNKNOWN_IMP - void Init(const CObjectVector *arcs, - const CObjectVector *items, - unsigned itemIndex) - { - _arcs = arcs; - _items = items; - _itemIndex = itemIndex; - _stream = NULL; - CrcIsOK = true; - } - - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); -}; - -STDMETHODIMP 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(s->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL)); - _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 &linkFiles, unsigned index) -{ - unsigned left = 0, right = linkFiles.Size(); - for (;;) - { - if (left == right) - return -1; - unsigned mid = (left + right) / 2; - unsigned linkIndex = linkFiles[mid].Index; - if (index == linkIndex) - return 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; -} - - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - - 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 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; - int bufIndex = FindLinkBuf(linkFiles, 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 volsInStream = volsInStreamSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr 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 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(index2); - } - else - { - if ((unsigned)index2 < index) - bufIndex = FindLinkBuf(linkFiles, 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", 0, 0xCC, - kMarker, - 0, - NArcInfoFlags::kFindSignature, - NULL) - -}} - - -class CBlake2spHasher: - public IHasher, - public CMyUnknownImp -{ - CBlake2sp _blake; - Byte mtDummy[1 << 7]; - -public: - CBlake2spHasher() { Init(); } - - MY_UNKNOWN_IMP - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CBlake2spHasher::Init() throw() -{ - Blake2sp_Init(&_blake); -} - -STDMETHODIMP_(void) CBlake2spHasher::Update(const void *data, UInt32 size) throw() -{ - Blake2sp_Update(&_blake, (const Byte *)data, size); -} - -STDMETHODIMP_(void) CBlake2spHasher::Final(Byte *digest) throw() -{ - Blake2sp_Final(&_blake, digest); -} - -REGISTER_HASHER(CBlake2spHasher, 0x202, "BLAKE2sp", BLAKE2S_DIGEST_SIZE) +// 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; + +#define SIGNATURE { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0 } + +static const Byte kMarker[kMarkerSize] = SIGNATURE; + +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 = 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; + + UInt64 len; + 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, 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 < ARRAY_SIZE(g_ExtraTimeFlags); i++) + if ((flags & ((UInt64)1 << i)) != 0) + s += g_ExtraTimeFlags[i]; + flags &= ~(((UInt64)1 << 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, 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; + int offset = FindExtra(NExtraID::kLink, size); + if (offset < 0) + return false; + if (!link.Parse(Extra + (unsigned)offset, size)) + return false; + link.NameOffset += 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; + if (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; +} + + +class COutStreamWithHash: + public ISequentialOutStream, + public CMyUnknownImp +{ + ISequentialOutStream *_stream; + UInt64 _pos; + UInt64 _size; + bool _size_Defined; + Byte *_destBuf; +public: + CHash _hash; + + COutStreamWithHash(): _destBuf(NULL) {} + + MY_UNKNOWN_IMP + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + 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; } +}; + + +STDMETHODIMP 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 m_CryptoDecoder; + + 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 password; + RINOK(getTextPassword->CryptoGetTextPassword(&password)); + AString utf8; + const unsigned kPasswordLen_MAX = 127; + UString unicode = (LPCOLESTR)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_CryptoDecoderSpec->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_CryptoDecoderSpec->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(stream->Seek(StreamStartPosition, STREAM_SEEK_SET, NULL)); + RINOK(FindSignatureInStream(stream, kMarker, kMarkerSize, + searchHeaderSizeLimit, arcStartPos)); + arcStartPos += StreamStartPosition; + Position = arcStartPos + kMarkerSize; + RINOK(stream->Seek(Position, STREAM_SEEK_SET, NULL)); + } + } + + 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 copyCoder; + + CMyComPtr LzCoders[2]; + bool SolidAllowed; + + CFilterCoder *filterStreamSpec; + CMyComPtr filterStream; + + NCrypto::NRar5::CDecoder *cryptoDecoderSpec; + CMyComPtr cryptoDecoder; + + CMyComPtr getTextPassword; + + COutStreamWithHash *outStreamSpec; + CMyComPtr 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 &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 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 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 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 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 = item.NextItem; + } +} + + +STDMETHODIMP 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; + if (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 +} + + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _refs.Size(); + return S_OK; +} + + +static const Byte kRawProps[] = +{ + kpidChecksum, + kpidNtSecure +}; + + +STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) +{ + *numProps = ARRAY_SIZE(kRawProps); + return S_OK; +} + +STDMETHODIMP CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) +{ + *propID = kRawProps[index]; + *name = 0; + return S_OK; +} + +STDMETHODIMP 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; +} + + +STDMETHODIMP 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; + int offset = item.FindExtra(NExtraID::kTime, size); + if (offset < 0) + return; + + const Byte *p = item.Extra + (unsigned)offset; + UInt64 flags; + { + 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; + unsigned i; + for (i = 0; i < 3; i++) + if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0) + { + if (i == stampIndex) + curStamp = numStamps; + numStamps++; + } + + FILETIME ft; + + if ((flags & NTimeRecord::NFlags::kUnixTime) != 0) + { + curStamp *= 4; + if (curStamp + 4 > size) + return; + const Byte *p2 = p + curStamp; + UInt64 val = NTime::UnixTimeToFileTime64(Get32(p2)); + numStamps *= 4; + if ((flags & NTimeRecord::NFlags::kUnixNs) != 0 && numStamps * 2 <= size) + { + const UInt32 ns = Get32(p2 + numStamps) & 0x3FFFFFFF; + if (ns < 1000000000) + val += ns / 100; + } + ft.dwLowDateTime = (DWORD)val; + ft.dwHighDateTime = (DWORD)(val >> 32); + } + else + { + curStamp *= 8; + if (curStamp + 8 > size) + return; + const Byte *p2 = p + curStamp; + ft.dwLowDateTime = Get32(p2); + ft.dwHighDateTime = Get32(p2 + 4); + } + + prop = ft; +} + + +STDMETHODIMP 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) + { + CItem &mainItem = _items[_refs[ref.Parent].Item]; + s = mainItem.Name; + } + + AString name; + item.GetAltStreamName(name); + if (name[0] != ':') + s += ':'; + s += name; + if (!ConvertUTF8ToUnicode(s, unicodeName)) + break; + } + else + { + if (!ConvertUTF8ToUnicode(item.Name, unicodeName)) + break; + 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()) + { + FILETIME ft; + NWindows::NTime::UnixTimeToFileTime(item.UnixMTime, ft); + prop = ft; + } + 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()) + { + FILETIME ft; + NWindows::NTime::UnixTimeToFileTime(baseItem.UnixMTime, ft); + prop = ft; + } + } + 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; + if (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, 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 < 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) + { + unsigned refIndex = sorted[left - 1]; + if (CompareItemsPaths(handler, index, refIndex, &s) == 0) + return refIndex; + } + if (right < sorted.Size()) + { + unsigned refIndex = sorted[right]; + if (CompareItemsPaths(handler, index, refIndex, &s) == 0) + return refIndex; + } + return -1; + } + + unsigned mid = (left + right) / 2; + unsigned refIndex = sorted[mid]; + int compare = CompareItemsPaths2(handler, index, refIndex, &s); + if (compare == 0) + return 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 openVolumeCallback; + CMyComPtr 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 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->Seek(0, STREAM_SEEK_CUR, &arch.StreamStartPosition)); + RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(inStream->Seek(arch.StreamStartPosition, STREAM_SEEK_SET, NULL)); + + 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->Seek(arch.Position, STREAM_SEEK_SET, NULL)); + + { + 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->Seek(arcInfo.EndPos, STREAM_SEEK_SET, NULL)); + 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 = _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 = ref2.Last; + needAdd = false; + } + } + } + } + + if (needAdd) + { + if (item.IsSplitAfter()) + prevSplitFile = _refs.Size(); + if (!item.IsService()) + prevMainFile = _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; +} + + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback) +{ + COM_TRY_BEGIN + Close(); + return Open2(stream, maxCheckStartPosition, openCallback); + COM_TRY_END +} + +STDMETHODIMP 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 +} + + +class CVolsInStream: + public ISequentialInStream, + public CMyUnknownImp +{ + UInt64 _rem; + ISequentialInStream *_stream; + const CObjectVector *_arcs; + const CObjectVector *_items; + int _itemIndex; +public: + bool CrcIsOK; +private: + CHash _hash; +public: + MY_UNKNOWN_IMP + void Init(const CObjectVector *arcs, + const CObjectVector *items, + unsigned itemIndex) + { + _arcs = arcs; + _items = items; + _itemIndex = itemIndex; + _stream = NULL; + CrcIsOK = true; + } + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP 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(s->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL)); + _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 &linkFiles, unsigned index) +{ + unsigned left = 0, right = linkFiles.Size(); + for (;;) + { + if (left == right) + return -1; + unsigned mid = (left + right) / 2; + unsigned linkIndex = linkFiles[mid].Index; + if (index == linkIndex) + return 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; +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + + 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 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; + int bufIndex = FindLinkBuf(linkFiles, 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 volsInStream = volsInStreamSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr 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 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(index2); + } + else + { + if ((unsigned)index2 < index) + bufIndex = FindLinkBuf(linkFiles, 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", 0, 0xCC, + kMarker, + 0, + NArcInfoFlags::kFindSignature, + NULL) + +}} + + +class CBlake2spHasher: + public IHasher, + public CMyUnknownImp +{ + CBlake2sp _blake; + Byte mtDummy[1 << 7]; + +public: + CBlake2spHasher() { Init(); } + + MY_UNKNOWN_IMP + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CBlake2spHasher::Init() throw() +{ + Blake2sp_Init(&_blake); +} + +STDMETHODIMP_(void) CBlake2spHasher::Update(const void *data, UInt32 size) throw() +{ + Blake2sp_Update(&_blake, (const Byte *)data, size); +} + +STDMETHODIMP_(void) CBlake2spHasher::Final(Byte *digest) throw() +{ + 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 index c93e8fba6..3b3b940a6 100644 --- a/CPP/7zip/Archive/Rar/Rar5Handler.h +++ b/CPP/7zip/Archive/Rar/Rar5Handler.h @@ -1,421 +1,421 @@ -// Rar5Handler.h - -#ifndef __RAR5_HANDLER_H -#define __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 Stream; - CInArcInfo Info; -}; - - -class CHandler: - public IInArchive, - public IArchiveGetRawProps, - PUBLIC_ISetCompressCodecsInfo - public CMyUnknownImp -{ -public: - CRecordVector _refs; - CObjectVector _items; -private: - CObjectVector _arcs; - CObjectVector _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); - -public: - MY_QUERYINTERFACE_BEGIN2(IInArchive) - MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps) - QUERY_ENTRY_ISetCompressCodecsInfo - MY_QUERYINTERFACE_END - MY_ADDREF_RELEASE - - INTERFACE_IInArchive(;) - INTERFACE_IArchiveGetRawProps(;) - - DECL_ISetCompressCodecsInfo -}; - -}} - -#endif +// Rar5Handler.h + +#ifndef __RAR5_HANDLER_H +#define __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 Stream; + CInArcInfo Info; +}; + + +class CHandler: + public IInArchive, + public IArchiveGetRawProps, + PUBLIC_ISetCompressCodecsInfo + public CMyUnknownImp +{ +public: + CRecordVector _refs; + CObjectVector _items; +private: + CObjectVector _arcs; + CObjectVector _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); + +public: + MY_QUERYINTERFACE_BEGIN2(IInArchive) + MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps) + QUERY_ENTRY_ISetCompressCodecsInfo + MY_QUERYINTERFACE_END + MY_ADDREF_RELEASE + + INTERFACE_IInArchive(;) + INTERFACE_IArchiveGetRawProps(;) + + DECL_ISetCompressCodecsInfo +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp index 70ea58faf..dd78e3126 100644 --- a/CPP/7zip/Archive/Rar/RarHandler.cpp +++ b/CPP/7zip/Archive/Rar/RarHandler.cpp @@ -1,1781 +1,1781 @@ -// 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 { - -#define SIGNATURE { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 } - -static const Byte kMarker[NHeader::kMarkerSize] = SIGNATURE; - -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 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(stream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition)); - RINOK(stream->Seek(0, STREAM_SEEK_END, &ArcInfo.FileSize)); - RINOK(stream->Seek(m_StreamStartPosition, STREAM_SEEK_SET, NULL)); - 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(stream->Seek(m_StreamStartPosition, STREAM_SEEK_SET, NULL)); - RINOK(FindSignatureInStream(stream, kMarker, NHeader::kMarkerSize, - searchHeaderSizeLimit, arcStartPos)); - m_Position = arcStartPos + NHeader::kMarkerSize; - RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); - } - } - Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1]; - - RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize)); - AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize); - - - UInt32 blockSize = Get16(buf + 5); - - 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); - 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 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 -= 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 (;;) - { - m_Stream->Seek(m_Position, STREAM_SEEK_SET, NULL); - ArcInfo.EndPos = m_Position; - if (!m_CryptoMode && (ArcInfo.Flags & - NHeader::NArchive::kBlockHeadersAreEncrypted) != 0) - { - m_CryptoMode = false; - if (getTextPassword == 0) - { - 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 password; - RINOK(getTextPassword->CryptoGetTextPassword(&password)) - unsigned len = 0; - if (password) - len = MyStringLen(password); - if (len > kPasswordLen_MAX) - len = kPasswordLen_MAX; - - CByteArr 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; - m_Stream->Seek(m_Position, STREAM_SEEK_SET, NULL); - 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(); -} - -STDMETHODIMP 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, 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 -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _refItems.Size(); - return S_OK; -} - -static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result) -{ - if (!NTime::DosTimeToFileTime(rarTime.DosTime, result)) - return false; - UInt64 value = (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime; - value += (UInt64)rarTime.LowSecond * 10000000; - value += ((UInt64)rarTime.SubTime[2] << 16) + - ((UInt64)rarTime.SubTime[1] << 8) + - ((UInt64)rarTime.SubTime[0]); - result.dwLowDateTime = (DWORD)value; - result.dwHighDateTime = DWORD(value >> 32); - return true; -} - -static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop) -{ - FILETIME localFileTime, utcFileTime; - if (RarTimeToFileTime(rarTime, localFileTime)) - { - if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime)) - utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; - } - else - utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; - prop = utcFileTime; -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - 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 openVolumeCallback; - CMyComPtr 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 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 = 0; - RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); - RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); - 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->Seek(archive.ArcInfo.EndPos, STREAM_SEEK_SET, NULL)); - 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; -} - -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *openCallback) -{ - COM_TRY_BEGIN - Close(); - // try - { - HRESULT res = Open2(stream, maxCheckStartPosition, openCallback); - /* - if (res != S_OK) - Close(); - */ - - return res; - } - // catch(const CInArchiveException &) { Close(); return S_FALSE; } - // catch(...) { Close(); throw; } - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - COM_TRY_BEGIN - // _errorMessage.Empty(); - _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 Coder; -}; - - -class CVolsInStream: - public ISequentialInStream, - public CMyUnknownImp -{ - UInt64 _rem; - ISequentialInStream *_stream; - const CObjectVector *_arcs; - const CObjectVector *_items; - CRefItem _refItem; - unsigned _curIndex; - UInt32 _crc; - bool _calcCrc; - -public: - MY_UNKNOWN_IMP - - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - - void Init(const CObjectVector *arcs, - const CObjectVector *items, - const CRefItem &refItem) - { - _arcs = arcs; - _items = items; - _refItem = refItem; - _curIndex = 0; - _stream = NULL; - CrcIsOK = true; - } - - bool CrcIsOK; -}; - - -STDMETHODIMP 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(s->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL)); - _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; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - CMyComPtr getTextPassword; - UInt64 censoredTotalUnPacked = 0, - // censoredTotalPacked = 0, - importantTotalUnPacked = 0; - // importantTotalPacked = 0; - bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _refItems.Size(); - if (numItems == 0) - return S_OK; - unsigned lastIndex = 0; - CRecordVector importantIndexes; - CRecordVector 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 methodItems; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; - CMyComPtr copyCoder = copyCoderSpec; - - CFilterCoder *filterStreamSpec = new CFilterCoder(false); - CMyComPtr filterStream = filterStreamSpec; - - NCrypto::NRar2::CDecoder *rar20CryptoDecoderSpec = NULL; - CMyComPtr rar20CryptoDecoder; - NCrypto::NRar3::CDecoder *rar3CryptoDecoderSpec = NULL; - CMyComPtr rar3CryptoDecoder; - - CVolsInStream *volsInStreamSpec = NULL; - CMyComPtr volsInStream; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr 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 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 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 inStream; - - if (item.IsEncrypted()) - { - // CMyComPtr cryptoSetPassword; - - if (item.UnPackVersion >= 29) - { - if (!rar3CryptoDecoder) - { - rar3CryptoDecoderSpec = new NCrypto::NRar3::CDecoder; - rar3CryptoDecoder = rar3CryptoDecoderSpec; - } - // rar3CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36); - /* - CMyComPtr 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 password; - RINOK(getTextPassword->CryptoGetTextPassword(&password)); - - if (item.UnPackVersion >= 29) - { - unsigned len = 0; - if (password) - len = MyStringLen(password); - if (len > kPasswordLen_MAX) - len = kPasswordLen_MAX; - CByteArr 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 oemPassword; - if (password) - { - UString unicode = (LPCOLESTR)password; - if (unicode.Len() > kPasswordLen_MAX) - unicode.DeleteFrom(kPasswordLen_MAX); - oemPassword = UnicodeStringToMultiByte(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 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 == 0) - { - outStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)); - continue; - } - - m = methodItems.Add(mi); - } - CMyComPtr decoder = methodItems[m].Coder; - - CMyComPtr 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", 0, 3, - kMarker, - 0, - NArcInfoFlags::kFindSignature, - NULL) - -}} +// 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 { + +#define SIGNATURE { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 } + +static const Byte kMarker[NHeader::kMarkerSize] = SIGNATURE; + +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 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(stream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition)); + RINOK(stream->Seek(0, STREAM_SEEK_END, &ArcInfo.FileSize)); + RINOK(stream->Seek(m_StreamStartPosition, STREAM_SEEK_SET, NULL)); + 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(stream->Seek(m_StreamStartPosition, STREAM_SEEK_SET, NULL)); + RINOK(FindSignatureInStream(stream, kMarker, NHeader::kMarkerSize, + searchHeaderSizeLimit, arcStartPos)); + m_Position = arcStartPos + NHeader::kMarkerSize; + RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); + } + } + Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1]; + + RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize)); + AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize); + + + UInt32 blockSize = Get16(buf + 5); + + 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); + 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 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 -= 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 (;;) + { + m_Stream->Seek(m_Position, STREAM_SEEK_SET, NULL); + ArcInfo.EndPos = m_Position; + if (!m_CryptoMode && (ArcInfo.Flags & + NHeader::NArchive::kBlockHeadersAreEncrypted) != 0) + { + m_CryptoMode = false; + if (getTextPassword == 0) + { + 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 password; + RINOK(getTextPassword->CryptoGetTextPassword(&password)) + unsigned len = 0; + if (password) + len = MyStringLen(password); + if (len > kPasswordLen_MAX) + len = kPasswordLen_MAX; + + CByteArr 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; + m_Stream->Seek(m_Position, STREAM_SEEK_SET, NULL); + 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(); +} + +STDMETHODIMP 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, 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 +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _refItems.Size(); + return S_OK; +} + +static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result) +{ + if (!NTime::DosTimeToFileTime(rarTime.DosTime, result)) + return false; + UInt64 value = (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime; + value += (UInt64)rarTime.LowSecond * 10000000; + value += ((UInt64)rarTime.SubTime[2] << 16) + + ((UInt64)rarTime.SubTime[1] << 8) + + ((UInt64)rarTime.SubTime[0]); + result.dwLowDateTime = (DWORD)value; + result.dwHighDateTime = DWORD(value >> 32); + return true; +} + +static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop) +{ + FILETIME localFileTime, utcFileTime; + if (RarTimeToFileTime(rarTime, localFileTime)) + { + if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime)) + utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; + } + else + utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; + prop = utcFileTime; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + 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 openVolumeCallback; + CMyComPtr 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 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 = 0; + RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); + 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->Seek(archive.ArcInfo.EndPos, STREAM_SEEK_SET, NULL)); + 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; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback) +{ + COM_TRY_BEGIN + Close(); + // try + { + HRESULT res = Open2(stream, maxCheckStartPosition, openCallback); + /* + if (res != S_OK) + Close(); + */ + + return res; + } + // catch(const CInArchiveException &) { Close(); return S_FALSE; } + // catch(...) { Close(); throw; } + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + COM_TRY_BEGIN + // _errorMessage.Empty(); + _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 Coder; +}; + + +class CVolsInStream: + public ISequentialInStream, + public CMyUnknownImp +{ + UInt64 _rem; + ISequentialInStream *_stream; + const CObjectVector *_arcs; + const CObjectVector *_items; + CRefItem _refItem; + unsigned _curIndex; + UInt32 _crc; + bool _calcCrc; + +public: + MY_UNKNOWN_IMP + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + + void Init(const CObjectVector *arcs, + const CObjectVector *items, + const CRefItem &refItem) + { + _arcs = arcs; + _items = items; + _refItem = refItem; + _curIndex = 0; + _stream = NULL; + CrcIsOK = true; + } + + bool CrcIsOK; +}; + + +STDMETHODIMP 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(s->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL)); + _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; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + CMyComPtr getTextPassword; + UInt64 censoredTotalUnPacked = 0, + // censoredTotalPacked = 0, + importantTotalUnPacked = 0; + // importantTotalPacked = 0; + bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _refItems.Size(); + if (numItems == 0) + return S_OK; + unsigned lastIndex = 0; + CRecordVector importantIndexes; + CRecordVector 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 methodItems; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; + CMyComPtr copyCoder = copyCoderSpec; + + CFilterCoder *filterStreamSpec = new CFilterCoder(false); + CMyComPtr filterStream = filterStreamSpec; + + NCrypto::NRar2::CDecoder *rar20CryptoDecoderSpec = NULL; + CMyComPtr rar20CryptoDecoder; + NCrypto::NRar3::CDecoder *rar3CryptoDecoderSpec = NULL; + CMyComPtr rar3CryptoDecoder; + + CVolsInStream *volsInStreamSpec = NULL; + CMyComPtr volsInStream; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr 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 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 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 inStream; + + if (item.IsEncrypted()) + { + // CMyComPtr cryptoSetPassword; + + if (item.UnPackVersion >= 29) + { + if (!rar3CryptoDecoder) + { + rar3CryptoDecoderSpec = new NCrypto::NRar3::CDecoder; + rar3CryptoDecoder = rar3CryptoDecoderSpec; + } + // rar3CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36); + /* + CMyComPtr 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 password; + RINOK(getTextPassword->CryptoGetTextPassword(&password)); + + if (item.UnPackVersion >= 29) + { + unsigned len = 0; + if (password) + len = MyStringLen(password); + if (len > kPasswordLen_MAX) + len = kPasswordLen_MAX; + CByteArr 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 oemPassword; + if (password) + { + UString unicode = (LPCOLESTR)password; + if (unicode.Len() > kPasswordLen_MAX) + unicode.DeleteFrom(kPasswordLen_MAX); + oemPassword = UnicodeStringToMultiByte(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 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 == 0) + { + outStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)); + continue; + } + + m = methodItems.Add(mi); + } + CMyComPtr decoder = methodItems[m].Coder; + + CMyComPtr 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", 0, 3, + kMarker, + 0, + NArcInfoFlags::kFindSignature, + NULL) + +}} diff --git a/CPP/7zip/Archive/Rar/RarHandler.h b/CPP/7zip/Archive/Rar/RarHandler.h index f93848661..e444bd77d 100644 --- a/CPP/7zip/Archive/Rar/RarHandler.h +++ b/CPP/7zip/Archive/Rar/RarHandler.h @@ -1,116 +1,116 @@ -// RarHandler.h - -#ifndef __RAR_HANDLER_H -#define __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), EndOfArchive_was_Read(false), VolNumber(0) {} - - 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 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: - public IInArchive, - PUBLIC_ISetCompressCodecsInfo - public CMyUnknownImp -{ - CRecordVector _refItems; - CObjectVector _items; - CObjectVector _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); - -public: - MY_QUERYINTERFACE_BEGIN2(IInArchive) - QUERY_ENTRY_ISetCompressCodecsInfo - MY_QUERYINTERFACE_END - MY_ADDREF_RELEASE - - INTERFACE_IInArchive(;) - - DECL_ISetCompressCodecsInfo -}; - -}} - -#endif +// RarHandler.h + +#ifndef __RAR_HANDLER_H +#define __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), EndOfArchive_was_Read(false), VolNumber(0) {} + + 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 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: + public IInArchive, + PUBLIC_ISetCompressCodecsInfo + public CMyUnknownImp +{ + CRecordVector _refItems; + CObjectVector _items; + CObjectVector _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); + +public: + MY_QUERYINTERFACE_BEGIN2(IInArchive) + QUERY_ENTRY_ISetCompressCodecsInfo + MY_QUERYINTERFACE_END + MY_ADDREF_RELEASE + + INTERFACE_IInArchive(;) + + DECL_ISetCompressCodecsInfo +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Rar/RarHeader.h b/CPP/7zip/Archive/Rar/RarHeader.h index ba0751bbc..30c53ec97 100644 --- a/CPP/7zip/Archive/Rar/RarHeader.h +++ b/CPP/7zip/Archive/Rar/RarHeader.h @@ -1,209 +1,209 @@ -// Archive/RarHeader.h - -#ifndef __ARCHIVE_RAR_HEADER_H -#define __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 +// Archive/RarHeader.h + +#ifndef __ARCHIVE_RAR_HEADER_H +#define __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 index bdde8259b..10e21c57c 100644 --- a/CPP/7zip/Archive/Rar/RarItem.h +++ b/CPP/7zip/Archive/Rar/RarItem.h @@ -1,97 +1,97 @@ -// RarItem.h - -#ifndef __ARCHIVE_RAR_ITEM_H -#define __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 +// RarItem.h + +#ifndef __ARCHIVE_RAR_ITEM_H +#define __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 index 7e765e67c..310369d4b 100644 --- a/CPP/7zip/Archive/Rar/RarVol.h +++ b/CPP/7zip/Archive/Rar/RarVol.h @@ -1,129 +1,129 @@ -// RarVol.h - -#ifndef __ARCHIVE_RAR_VOL_H -#define __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; - 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 = name.Left(dotPos + 1); - return true; - } - } - } - - if (newStyle) - { - unsigned i = base.Len(); - - for (; i != 0; i--) - if (!IsDigit(base[i - 1])) - break; - - if (i != base.Len()) - { - _before = base.Left(i); - _changed = base.Ptr(i); - return true; - } - } - - _after.Empty(); - _before = base; - _before += '.'; - _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 +// RarVol.h + +#ifndef __ARCHIVE_RAR_VOL_H +#define __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; + 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 = name.Left(dotPos + 1); + return true; + } + } + } + + if (newStyle) + { + unsigned i = base.Len(); + + for (; i != 0; i--) + if (!IsDigit(base[i - 1])) + break; + + if (i != base.Len()) + { + _before = base.Left(i); + _changed = base.Ptr(i); + return true; + } + } + + _after.Empty(); + _before = base; + _before += '.'; + _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 index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Archive/Rar/StdAfx.cpp +++ b/CPP/7zip/Archive/Rar/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Archive/Rar/StdAfx.h b/CPP/7zip/Archive/Rar/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Archive/Rar/StdAfx.h +++ b/CPP/7zip/Archive/Rar/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp index 6f1213a73..e0ec28ce1 100644 --- a/CPP/7zip/Archive/RpmHandler.cpp +++ b/CPP/7zip/Archive/RpmHandler.cpp @@ -1,774 +1,774 @@ -// 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 _SHOW_RPM_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 _SHOW_RPM_METADATA -struct CMetaFile -{ - UInt32 Tag; - UInt32 Offset; - UInt32 Size; -}; -#endif - -class CHandler: public CHandlerCont -{ - 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 _SHOW_RPM_METADATA - AString _metadata; - CRecordVector _metaFiles; - #endif - - void SetTime(NCOM::CPropVariant &prop) const - { - if (_time_Defined && _buildTime != 0) - { - FILETIME ft; - NTime::UnixTimeToFileTime(_buildTime, ft); - prop = ft; - } - } - - 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 - { - pos = _headersSize; - size = _size; - return NExtract::NOperationResult::kOK; - } - -public: - INTERFACE_IInArchive_Cont(;) -}; - -static const Byte kArcProps[] = -{ - kpidHeadersSize, - kpidCpu, - kpidHostOS, - kpidCTime - #ifdef _SHOW_RPM_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 < 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 += '-'; - s += _version; - } - if (!_release.IsEmpty()) - { - s += '-'; - s += _release; - } - } - else - s.SetFrom_CalcLen(_lead.Name, kNameSize); - - s += '.'; - 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 += '.'; - - 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; -} - -STDMETHODIMP 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 _SHOW_RPM_METADATA - // case kpidComment: SetStringProp(_metadata, prop); break; - #endif - - case kpidName: - { - SetStringProp(GetBaseName() + ".rpm", prop); - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -STDMETHODIMP 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 += '.'; - AddSubFileExtension(s); - SetStringProp(s, prop); - break; - } - - /* - case kpidExtension: - { - prop = GetSubFileExtension(); - break; - } - */ - } - #ifdef _SHOW_RPM_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 _SHOW_RPM_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 _SHOW_RPM_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 _SHOW_RPM_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 _SHOW_RPM_METADATA - for (UInt32 t = 0; t < entry.Count; t++) - { - if (t != 0) - _metadata.Add_Space(); - _metadata.Add_UInt32(Get32(p + t * 4)); - } - #endif - } - - #ifdef _SHOW_RPM_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 _SHOW_RPM_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); -} - - -STDMETHODIMP 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->Seek(0, STREAM_SEEK_END, &endPos)); - _size = endPos - _headersSize; - } - _stream = inStream; - return S_OK; - } - COM_TRY_END -} - -STDMETHODIMP 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 _SHOW_RPM_METADATA - _metadata.Empty(); - _metaFiles.Size(); - #endif - - _stream.Release(); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = 1 - #ifdef _SHOW_RPM_METADATA - + _metaFiles.Size() - #endif - ; - - return S_OK; -} - -static const Byte k_Signature[] = { 0xED, 0xAB, 0xEE, 0xDB}; - -REGISTER_ARC_I( - "Rpm", "rpm", 0, 0xEB, - k_Signature, - 0, - 0, - NULL) - -}} +// 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 _SHOW_RPM_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 _SHOW_RPM_METADATA +struct CMetaFile +{ + UInt32 Tag; + UInt32 Offset; + UInt32 Size; +}; +#endif + +class CHandler: public CHandlerCont +{ + 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 _SHOW_RPM_METADATA + AString _metadata; + CRecordVector _metaFiles; + #endif + + void SetTime(NCOM::CPropVariant &prop) const + { + if (_time_Defined && _buildTime != 0) + { + FILETIME ft; + NTime::UnixTimeToFileTime(_buildTime, ft); + prop = ft; + } + } + + 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 + { + pos = _headersSize; + size = _size; + return NExtract::NOperationResult::kOK; + } + +public: + INTERFACE_IInArchive_Cont(;) +}; + +static const Byte kArcProps[] = +{ + kpidHeadersSize, + kpidCpu, + kpidHostOS, + kpidCTime + #ifdef _SHOW_RPM_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 < 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 += '-'; + s += _version; + } + if (!_release.IsEmpty()) + { + s += '-'; + s += _release; + } + } + else + s.SetFrom_CalcLen(_lead.Name, kNameSize); + + s += '.'; + 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 += '.'; + + 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; +} + +STDMETHODIMP 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 _SHOW_RPM_METADATA + // case kpidComment: SetStringProp(_metadata, prop); break; + #endif + + case kpidName: + { + SetStringProp(GetBaseName() + ".rpm", prop); + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP 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 += '.'; + AddSubFileExtension(s); + SetStringProp(s, prop); + break; + } + + /* + case kpidExtension: + { + prop = GetSubFileExtension(); + break; + } + */ + } + #ifdef _SHOW_RPM_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 _SHOW_RPM_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 _SHOW_RPM_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 _SHOW_RPM_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 _SHOW_RPM_METADATA + for (UInt32 t = 0; t < entry.Count; t++) + { + if (t != 0) + _metadata.Add_Space(); + _metadata.Add_UInt32(Get32(p + t * 4)); + } + #endif + } + + #ifdef _SHOW_RPM_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 _SHOW_RPM_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); +} + + +STDMETHODIMP 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->Seek(0, STREAM_SEEK_END, &endPos)); + _size = endPos - _headersSize; + } + _stream = inStream; + return S_OK; + } + COM_TRY_END +} + +STDMETHODIMP 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 _SHOW_RPM_METADATA + _metadata.Empty(); + _metaFiles.Size(); + #endif + + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1 + #ifdef _SHOW_RPM_METADATA + + _metaFiles.Size() + #endif + ; + + return S_OK; +} + +static const Byte k_Signature[] = { 0xED, 0xAB, 0xEE, 0xDB}; + +REGISTER_ARC_I( + "Rpm", "rpm", 0, 0xEB, + k_Signature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/SplitHandler.cpp b/CPP/7zip/Archive/SplitHandler.cpp index ffb0e3343..f4a10b1df 100644 --- a/CPP/7zip/Archive/SplitHandler.cpp +++ b/CPP/7zip/Archive/SplitHandler.cpp @@ -1,359 +1,359 @@ -// 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 > _streams; - CRecordVector _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 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 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 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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr 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 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 "../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 > _streams; + CRecordVector _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 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 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 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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr 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 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) + +}} diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp index 85009f014..0689af202 100644 --- a/CPP/7zip/Archive/SquashfsHandler.cpp +++ b/CPP/7zip/Archive/SquashfsHandler.cpp @@ -1,2357 +1,2357 @@ -// SquashfsHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" -#include "../../../C/CpuArch.h" -#include "../../../C/LzmaDec.h" -#include "../../../C/Xz.h" -#include "../../../C/lz4/lz4.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" -#include "../Compress/ZstdDecoder.h" - -namespace NArchive { -namespace NSquashfs { - -static const UInt32 kNumFilesMax = (1 << 28); -static const unsigned kNumDirLevelsMax = (1 << 10); - -// Layout: Header, Data, inodes, Directories, Fragments, UIDs, GIDs - -/* -#define Get16(p) (be ? GetBe16(p) : GetUi16(p)) -#define Get32(p) (be ? GetBe32(p) : GetUi32(p)) -#define Get64(p) (be ? GetBe64(p) : GetUi64(p)) -*/ - -UInt16 Get16b(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); } -UInt32 Get32b(const Byte *p, bool be) { return be ? GetBe32(p) : GetUi32(p); } -UInt64 Get64b(const Byte *p, bool be) { return be ? GetBe64(p) : GetUi64(p); } - -#define Get16(p) Get16b(p, be) -#define Get32(p) Get32b(p, be) -#define Get64(p) Get64b(p, be) - -#define LE_16(offs, dest) dest = GetUi16(p + (offs)); -#define LE_32(offs, dest) dest = GetUi32(p + (offs)); -#define LE_64(offs, dest) dest = GetUi64(p + (offs)); - -#define GET_16(offs, dest) dest = Get16(p + (offs)); -#define GET_32(offs, dest) dest = Get32(p + (offs)); -#define GET_64(offs, dest) dest = Get64(p + (offs)); - -static const UInt32 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 -#define kMethod_LZ4 5 -#define kMethod_ZSTD 6 - -static const char * const k_Methods[] = -{ - "0" - , "ZLIB" - , "LZMA" - , "LZO" - , "XZ" - , "LZ4" - , "ZSTD" -}; - -static const UInt32 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" -}; - -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) -{ - 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) -{ - 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 PackPos; - CRecordVector UnpackPos; // additional item at the end contains TotalUnpackSize - - UInt32 GetNumBlocks() const { return PackPos.Size(); } - void Clear() - { - Data.Free(); - PackPos.Clear(); - UnpackPos.Clear(); - } -}; - -struct CFrag -{ - UInt64 StartBlock; - UInt32 Size; -}; - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - CRecordVector _items; - CRecordVector _nodes; - CRecordVector _nodesPos; - CRecordVector _blockToNode; - CData _inodesData; - CData _dirs; - CRecordVector _frags; - // CByteBuffer _uids; - // CByteBuffer _gids; - CHeader _h; - bool _noPropsLZMA; - bool _needCheckLzma; - - UInt32 _openCodePage; - - CMyComPtr _stream; - UInt64 _sizeCalculated; - - IArchiveOpenCallback *_openCallback; - - int _nodeIndex; - CRecordVector _blockCompressed; - CRecordVector _blockOffsets; - - CByteBuffer _cachedBlock; - UInt64 _cachedBlockStartPos; - UInt32 _cachedPackBlockSize; - UInt32 _cachedUnpackBlockSize; - - CLimitedSequentialInStream *_limitedInStreamSpec; - CMyComPtr _limitedInStream; - - CBufPtrSeqOutStream *_outStreamSpec; - CMyComPtr _outStream; - - // NCompress::NLzma::CDecoder *_lzmaDecoderSpec; - // CMyComPtr _lzmaDecoder; - - NCompress::NZlib::CDecoder *_zlibDecoderSpec; - CMyComPtr _zlibDecoder; - - NCompress::NZSTD::CDecoder *_zstdDecoderSpec; - CMyComPtr _zstdDecoder; - - CXzUnpacker _xz; - - CByteBuffer _inputBuffer; - - CDynBufSeqOutStream *_dynOutStreamSpec; - CMyComPtr _dynOutStream; - - void ClearCache() - { - _cachedBlockStartPos = 0; - _cachedPackBlockSize = 0; - _cachedUnpackBlockSize = 0; - } - - HRESULT Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize, - UInt32 inSize, UInt32 outSizeMax); - HRESULT ReadMetadataBlock(UInt32 &packSize); - HRESULT ReadData(CData &data, UInt64 start, UInt64 end); - - HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex); - HRESULT ScanInodes(UInt64 ptr); - // HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids); - HRESULT Open2(IInStream *inStream); - AString GetPath(int index) const; - bool GetPackSize(int index, UInt64 &res, bool fillOffsets); - -public: - CHandler(); - ~CHandler() - { - XzUnpacker_Free(&_xz); - } - - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - - 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 - // kpidUser, - // kpidGroup, - // 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) + (*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 = dest - destStart; - *srcLen = 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++; - } - } -} - -static HRESULT Lz4Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen) -{ - const char *Src = (const char *)src; - char *Dst = (char *)dest; - int compressedSize = (int)*srcLen; - int dstCapacity = (int)*destLen; - // int LZ4_decompress_safe (const char* src, char* dst, int compressedSize, int dstCapacity); - int rv = LZ4_decompress_safe(Src, Dst, compressedSize, dstCapacity); - if (rv == 0) - return S_FALSE; - - *destLen = rv; - return S_OK; -} - -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_ZSTD) - { - if (!_zstdDecoder) - { - _zstdDecoderSpec = new NCompress::NZSTD::CDecoder(); - _zstdDecoder = _zstdDecoderSpec; - } - RINOK(_zstdDecoder->Code(_limitedInStream, outStream, NULL, NULL, NULL)); - if (inSize != _zstdDecoderSpec->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_LZ4) - { - RINOK(Lz4Decode(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) - 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]; - unsigned offset = _h.NeedCheckData() ? 3 : 2; - if (offset > packSize) - return S_FALSE; - RINOK(ReadStream_FALSE(_stream, temp, offset)); - // if (NeedCheckData && Major < 4) checkByte must be = 0xFF - bool be = _h.be; - UInt32 size = Get16(temp); - bool isCompressed = ((size & kNotCompressedBit16) == 0); - if (size != kNotCompressedBit16) - size &= ~kNotCompressedBit16; - - if (size > kMetadataBlockSize || offset + size > packSize) - return S_FALSE; - packSize = offset + size; - if (isCompressed) - { - _limitedInStreamSpec->Init(size); - RINOK(Decompress(_dynOutStream, NULL, NULL, NULL, size, kMetadataBlockSize)); - } - else - { - // size != 0 here - Byte *buf = _dynOutStreamSpec->GetBufPtrForWriting(size); - if (!buf) - return E_OUTOFMEMORY; - RINOK(ReadStream_FALSE(_stream, buf, size)); - _dynOutStreamSpec->UpdateSize(size); - } - return S_OK; -} - -HRESULT CHandler::ReadData(CData &data, UInt64 start, UInt64 end) -{ - if (end < start || end - start >= ((UInt64)1 << 32)) - return S_FALSE; - UInt32 size = (UInt32)(end - start); - RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL)); - _dynOutStreamSpec->Init(); - UInt32 packPos = 0; - while (packPos != size) - { - data.PackPos.Add(packPos); - data.UnpackPos.Add((UInt32)_dynOutStreamSpec->GetSize()); - if (packPos > size) - return S_FALSE; - UInt32 packSize = size - packPos; - RINOK(ReadMetadataBlock(packSize)); - if (_dynOutStreamSpec->GetSize() >= ((UInt64)1 << 32)) - return S_FALSE; - packPos += packSize; - } - data.UnpackPos.Add((UInt32)_dynOutStreamSpec->GetSize()); - _dynOutStreamSpec->CopyToBuffer(data.Data); - return S_OK; -} - -struct CTempItem -{ - UInt32 StartBlock; - // UInt32 iNodeNumber1; - UInt32 Offset; - // UInt16 iNodeNumber2; - UInt16 Type; -}; - -HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex) -{ - if (level > kNumDirLevelsMax) - return S_FALSE; - - int blockIndex = _inodesData.PackPos.FindInSorted(startBlock); - if (blockIndex < 0) - return S_FALSE; - UInt32 unpackPos = _inodesData.UnpackPos[blockIndex] + offset; - if (unpackPos < offset) - return S_FALSE; - - nodeIndex = _nodesPos.FindInSorted(unpackPos, _blockToNode[blockIndex], _blockToNode[blockIndex + 1]); - // nodeIndex = _nodesPos.FindInSorted(unpackPos); - if (nodeIndex < 0) - return S_FALSE; - - const CNode &n = _nodes[nodeIndex]; - if (!n.IsDir()) - return S_OK; - blockIndex = _dirs.PackPos.FindInSorted((UInt32)n.StartBlock); - if (blockIndex < 0) - return S_FALSE; - unpackPos = _dirs.UnpackPos[blockIndex] + n.Offset; - if (unpackPos < n.Offset || unpackPos > _dirs.Data.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 tempItems; - while (rem != 0) - { - bool be = _h.be; - UInt32 count; - CTempItem tempItem; - if (_h.Major <= 2) - { - if (rem < 4) - return S_FALSE; - count = p[0]; - tempItem.StartBlock = Get32(p); - if (be) - tempItem.StartBlock &= 0xFFFFFF; - else - tempItem.StartBlock >>= 8; - p += 4; - rem -= 4; - } - else - { - if (_h.Major == 3) - { - if (rem < 9) - return S_FALSE; - count = p[0]; - p += 1; - rem -= 1; - } - else - { - if (rem < 12) - return S_FALSE; - count = GetUi32(p); - p += 4; - rem -= 4; - } - GET_32 (0, tempItem.StartBlock); - // GET_32 (4, tempItem.iNodeNumber1); - p += 8; - rem -= 8; - } - count++; - - for (UInt32 i = 0; i < count; i++) - { - if (rem == 0) - return S_FALSE; - - UInt32 nameOffset = _h.GetFileNameOffset(); - if (rem < nameOffset) - return S_FALSE; - - if ((UInt32)_items.Size() >= kNumFilesMax) - return S_FALSE; - if (_openCallback) - { - UInt64 numFiles = _items.Size(); - if ((numFiles & 0xFFFF) == 0) - { - RINOK(_openCallback->SetCompleted(&numFiles, NULL)); - } - } - - CItem item; - item.Ptr = (UInt32)(p - (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(tempString)) - _openCodePage = CP_OEMCP; - } - - p += size; - rem -= size; - item.Parent = parent; - _items.Add(item); - tempItems.Add(tempItem); - } - } - - int startItemIndex = _items.Size() - tempItems.Size(); - FOR_VECTOR (i, tempItems) - { - const CTempItem &tempItem = tempItems[i]; - int index = startItemIndex + i; - CItem &item = _items[index]; - RINOK(OpenDir(index, tempItem.StartBlock, tempItem.Offset, level + 1, item.Node)); - } - - return S_OK; -} - -/* -HRESULT CHandler::ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids) -{ - size_t size = num * 4; - ids.SetCapacity(size); - RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL)); - return ReadStream_FALSE(_stream, ids, size); -} -*/ - -HRESULT CHandler::Open2(IInStream *inStream) -{ - { - Byte buf[kHeaderSize3]; - RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize3)); - if (!_h.Parse(buf)) - return S_FALSE; - if (!_h.IsSupported()) - return E_NOTIMPL; - - _noPropsLZMA = false; - _needCheckLzma = false; - switch (_h.Method) - { - case kMethod_ZLIB: _needCheckLzma = true; break; - case kMethod_LZMA: - case kMethod_LZO: - case kMethod_XZ: - case kMethod_LZ4: - case kMethod_ZSTD: - break; - default: - return E_NOTIMPL; - } - } - - _stream = inStream; - - if (_h.NumFrags != 0) - { - if (_h.NumFrags > kNumFilesMax) - return S_FALSE; - _frags.ClearAndReserve(_h.NumFrags); - unsigned bigFrag = (_h.Major > 2); - - unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag); - UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog; - size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag); - CByteBuffer data(numBlocksBytes); - RINOK(inStream->Seek(_h.FragTable, STREAM_SEEK_SET, NULL)); - RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)); - bool be = _h.be; - - for (UInt32 i = 0; i < numBlocks; i++) - { - UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4); - RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); - _dynOutStreamSpec->Init(); - UInt32 packSize = kMetadataBlockSize + 3; - RINOK(ReadMetadataBlock(packSize)); - UInt32 unpackSize = (UInt32)_dynOutStreamSpec->GetSize(); - if (unpackSize != kMetadataBlockSize) - if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1))) - return S_FALSE; - const Byte *buf = _dynOutStreamSpec->GetBuffer(); - for (UInt32 j = 0; j < kMetadataBlockSize && j < unpackSize;) - { - CFrag frag; - if (bigFrag) - { - frag.StartBlock = Get64(buf + j); - frag.Size = Get32(buf + j + 8); - // some archives contain nonzero in unused (buf + j + 12) - j += 16; - } - else - { - frag.StartBlock = Get32(buf + j); - frag.Size = Get32(buf + j + 4); - j += 8; - } - _frags.Add(frag); - } - } - if ((UInt32)_frags.Size() != _h.NumFrags) - return S_FALSE; - } - - // RINOK(inStream->Seek(_h.InodeTable, STREAM_SEEK_SET, NULL)); - - RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable)); - RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable)); - - UInt64 absOffset = _h.RootInode >> 16; - if (absOffset >= ((UInt64)1 << 32)) - return S_FALSE; - { - UInt32 pos = 0; - UInt32 totalSize = (UInt32)_inodesData.Data.Size(); - _nodesPos.ClearAndReserve(_h.NumInodes); - _nodes.ClearAndReserve(_h.NumInodes); - // we use _blockToNode for binary search seed optimizations - _blockToNode.ClearAndReserve(_inodesData.GetNumBlocks() + 1); - int curBlock = 0; - for (UInt32 i = 0; i < _h.NumInodes; i++) - { - CNode n; - const Byte *p = _inodesData.Data + pos; - UInt32 size = totalSize - pos; - - switch (_h.Major) - { - case 1: size = n.Parse1(p, size, _h); break; - case 2: size = n.Parse2(p, size, _h); break; - case 3: size = n.Parse3(p, size, _h); break; - default: size = n.Parse4(p, size, _h); break; - } - if (size == 0) - return S_FALSE; - while (pos >= _inodesData.UnpackPos[curBlock]) - { - _blockToNode.Add(_nodesPos.Size()); - curBlock++; - } - _nodesPos.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 - { - UInt32 size = _h.NumIDs * 4; - _uids.SetCapacity(size); - - UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize; - UInt32 numBlocksBytes = numBlocks << 3; - CByteBuffer data; - data.SetCapacity(numBlocksBytes); - RINOK(inStream->Seek(_h.UidTable, STREAM_SEEK_SET, NULL)); - RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)); - - for (UInt32 i = 0; i < numBlocks; i++) - { - UInt64 offset = GetUi64(data + i * 8); - UInt32 unpackSize, packSize; - RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); - RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize)); - if (unpackSize != kMetadataBlockSize) - if (i != numBlocks - 1 || unpackSize != (size & (kMetadataBlockSize - 1))) - return S_FALSE; - } - } - */ - - { - const UInt32 alignSize = 1 << 12; - Byte buf[alignSize]; - RINOK(inStream->Seek(_h.Size, STREAM_SEEK_SET, NULL)); - UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1); - _sizeCalculated = _h.Size; - if (rem != 0) - { - if (ReadStream_FALSE(_stream, buf, rem) == S_OK) - { - size_t i; - for (i = 0; i < rem && buf[i] == 0; i++); - if (i == rem) - _sizeCalculated = _h.Size + rem; - } - } - } - return S_OK; -} - -AString CHandler::GetPath(int index) const -{ - unsigned len = 0; - int indexMem = index; - bool be = _h.be; - do - { - const CItem &item = _items[index]; - index = item.Parent; - const Byte *p = _dirs.Data + item.Ptr; - unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1; - p += _h.GetFileNameOffset(); - unsigned i; - for (i = 0; i < size && p[i]; i++); - len += i + 1; - } - while (index >= 0); - len--; - - AString path; - char *dest = path.GetBuf_SetEnd(len) + len; - index = indexMem; - for (;;) - { - const CItem &item = _items[index]; - index = item.Parent; - const Byte *p = _dirs.Data + item.Ptr; - unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1; - p += _h.GetFileNameOffset(); - unsigned i; - for (i = 0; i < size && p[i]; i++); - dest -= i; - memcpy(dest, p, i); - if (index < 0) - break; - *(--dest) = CHAR_PATH_SEPARATOR; - } - return path; -} - -STDMETHODIMP 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 -} - -STDMETHODIMP 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(int index, UInt64 &totalPack, bool fillOffsets) -{ - totalPack = 0; - const CItem &item = _items[index]; - const CNode &node = _nodes[item.Node]; - UInt32 ptr = _nodesPos[item.Node]; - const Byte *p = _inodesData.Data + ptr; - bool be = _h.be; - - UInt32 type = node.Type; - UInt32 offset; - if (node.IsLink() || node.FileSize == 0) - { - totalPack = node.FileSize; - return true; - } - - UInt32 numBlocks = (UInt32)node.GetNumBlocks(_h); - - if (fillOffsets) - { - _blockOffsets.Clear(); - _blockCompressed.Clear(); - _blockOffsets.Add(totalPack); - } - - if (_h.Major <= 1) - { - offset = 15; - p += offset; - - for (UInt32 i = 0; i < numBlocks; i++) - { - UInt32 t = Get16(p + i * 2); - if (fillOffsets) - _blockCompressed.Add((t & kNotCompressedBit16) == 0); - if (t != kNotCompressedBit16) - t &= ~kNotCompressedBit16; - totalPack += t; - if (fillOffsets) - _blockOffsets.Add(totalPack); - } - } - else - { - if (_h.Major <= 2) - offset = 24; - else if (type == kType_FILE) - offset = 32; - else if (type == kType_FILE + 7) - offset = (_h.Major <= 3 ? 40 : 56); - else - return false; - - p += offset; - - for (UInt64 i = 0; i < numBlocks; i++) - { - UInt32 t = Get32(p + i * 4); - if (fillOffsets) - _blockCompressed.Add(IS_COMPRESSED_BLOCK(t)); - UInt32 size = GET_COMPRESSED_BLOCK_SIZE(t); - if (size > _h.BlockSize) - return false; - totalPack += size; - if (fillOffsets) - _blockOffsets.Add(totalPack); - } - - if (node.ThereAreFrags()) - { - if (node.Frag >= (UInt32)_frags.Size()) - return false; - const CFrag &frag = _frags[node.Frag]; - if (node.Offset == 0) - { - UInt32 size = GET_COMPRESSED_BLOCK_SIZE(frag.Size); - if (size > _h.BlockSize) - return false; - totalPack += size; - } - } - } - return true; -} - - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidMethod: - { - char sz[16]; - const char *s; - if (_noPropsLZMA) - s = "LZMA Spec"; - else if (_h.SeveralMethods) - s = "LZMA ZLIB"; - else - { - s = NULL; - if (_h.Method < 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 += '.'; - 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) - { - FILETIME ft; - NWindows::NTime::UnixTimeToFileTime(_h.CTime, ft); - prop = ft; - } - break; - case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break; - // case kpidNumBlocks: prop = _h.NumFrags; break; - case kpidPhySize: prop = _sizeCalculated; break; - case kpidHeadersSize: - if (_sizeCalculated >= _h.InodeTable) - prop = _sizeCalculated - _h.InodeTable; - break; - - 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 -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem &item = _items[index]; - const CNode &node = _nodes[item.Node]; - bool isDir = node.IsDir(); - bool be = _h.be; - - switch (propID) - { - case kpidPath: - { - 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; - FILETIME ft; - NWindows::NTime::UnixTimeToFileTime(Get32(p), ft); - prop = ft; - } - break; - } - case kpidPosixAttrib: - { - if (node.Type != 0 && node.Type < ARRAY_SIZE(k_TypeToMode)) - prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type]; - break; - } - /* - case kpidUser: - { - UInt32 offset = node.Uid * 4; - if (offset < _uids.Size()) - prop = (UInt32)Get32(_uids + offset); - break; - } - case kpidGroup: - { - if (_h.Major == 4 || node.Gid == _h.GetSpecGuidIndex()) - { - UInt32 offset = node.Uid * 4; - if (offset < _uids.Size()) - prop = (UInt32)Get32(_uids + offset); - } - else - { - UInt32 offset = node.Gid * 4; - if (offset < _gids.Size()) - prop = (UInt32)Get32(_gids + offset); - } - break; - } - */ - /* - case kpidLinks: - if (_h.Major >= 3 && node.Type != kType_FILE) - prop = node.NumLinks; - break; - */ - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -class CSquashfsInStream: public CCachedInStream -{ - HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); -public: - CHandler *Handler; -}; - -HRESULT CSquashfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) -{ - return Handler->ReadBlock(blockIndex, dest, blockSize); -} - -HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) -{ - const CNode &node = _nodes[_nodeIndex]; - UInt64 blockOffset; - UInt32 packBlockSize; - UInt32 offsetInBlock = 0; - bool compressed; - if (blockIndex < _blockCompressed.Size()) - { - compressed = _blockCompressed[(int)blockIndex]; - blockOffset = _blockOffsets[(int)blockIndex]; - packBlockSize = (UInt32)(_blockOffsets[(int)blockIndex + 1] - blockOffset); - blockOffset += node.StartBlock; - } - else - { - if (!node.ThereAreFrags()) - return S_FALSE; - const CFrag &frag = _frags[node.Frag]; - offsetInBlock = node.Offset; - blockOffset = frag.StartBlock; - packBlockSize = GET_COMPRESSED_BLOCK_SIZE(frag.Size); - compressed = IS_COMPRESSED_BLOCK(frag.Size); - } - - if (packBlockSize == 0) - { - // sparse file ??? - memset(dest, 0, blockSize); - return S_OK; - } - - if (blockOffset != _cachedBlockStartPos || - packBlockSize != _cachedPackBlockSize) - { - ClearCache(); - RINOK(_stream->Seek(blockOffset, STREAM_SEEK_SET, NULL)); - _limitedInStreamSpec->Init(packBlockSize); - - if (compressed) - { - _outStreamSpec->Init((Byte *)_cachedBlock, _h.BlockSize); - bool outBufWasWritten; - UInt32 outBufWasWrittenSize; - HRESULT res = Decompress(_outStream, _cachedBlock, &outBufWasWritten, &outBufWasWrittenSize, packBlockSize, _h.BlockSize); - if (outBufWasWritten) - _cachedUnpackBlockSize = outBufWasWrittenSize; - else - _cachedUnpackBlockSize = (UInt32)_outStreamSpec->GetPos(); - RINOK(res); - } - else - { - RINOK(ReadStream_FALSE(_limitedInStream, _cachedBlock, packBlockSize)); - _cachedUnpackBlockSize = packBlockSize; - } - _cachedBlockStartPos = blockOffset; - _cachedPackBlockSize = packBlockSize; - } - if (offsetInBlock + blockSize > _cachedUnpackBlockSize) - return S_FALSE; - if (blockSize != 0) - memcpy(dest, _cachedBlock + offsetInBlock, blockSize); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - CMyComPtr outStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - UInt32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - const CNode &node = _nodes[item.Node]; - RINOK(extractCallback->GetStream(index, &outStream, askMode)); - // const Byte *p = _data + item.Offset; - - if (node.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - UInt64 unpackSize = node.GetSize(); - totalSize += unpackSize; - UInt64 packSize; - if (GetPackSize(index, packSize, false)) - totalPackSize += packSize; - - if (!testMode && !outStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - - int res = NExtract::NOperationResult::kDataError; - { - CMyComPtr 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 -} - - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - - const CItem &item = _items[index]; - const CNode &node = _nodes[item.Node]; - - if (node.IsDir()) - return E_FAIL; - - const Byte *p = _inodesData.Data + _nodesPos[item.Node]; - - if (node.FileSize == 0 || node.IsLink()) - { - CBufInStream *streamSpec = new CBufInStream; - CMyComPtr 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 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", 0, 0xD2, - k_Signature, - 0, - NArcInfoFlags::kMultiSignature, - NULL) - -}} +// SquashfsHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" +#include "../../../C/CpuArch.h" +#include "../../../C/LzmaDec.h" +#include "../../../C/Xz.h" +#include "../../../C/lz4/lz4.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" +#include "../Compress/ZstdDecoder.h" + +namespace NArchive { +namespace NSquashfs { + +static const UInt32 kNumFilesMax = (1 << 28); +static const unsigned kNumDirLevelsMax = (1 << 10); + +// Layout: Header, Data, inodes, Directories, Fragments, UIDs, GIDs + +/* +#define Get16(p) (be ? GetBe16(p) : GetUi16(p)) +#define Get32(p) (be ? GetBe32(p) : GetUi32(p)) +#define Get64(p) (be ? GetBe64(p) : GetUi64(p)) +*/ + +UInt16 Get16b(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); } +UInt32 Get32b(const Byte *p, bool be) { return be ? GetBe32(p) : GetUi32(p); } +UInt64 Get64b(const Byte *p, bool be) { return be ? GetBe64(p) : GetUi64(p); } + +#define Get16(p) Get16b(p, be) +#define Get32(p) Get32b(p, be) +#define Get64(p) Get64b(p, be) + +#define LE_16(offs, dest) dest = GetUi16(p + (offs)); +#define LE_32(offs, dest) dest = GetUi32(p + (offs)); +#define LE_64(offs, dest) dest = GetUi64(p + (offs)); + +#define GET_16(offs, dest) dest = Get16(p + (offs)); +#define GET_32(offs, dest) dest = Get32(p + (offs)); +#define GET_64(offs, dest) dest = Get64(p + (offs)); + +static const UInt32 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 +#define kMethod_LZ4 5 +#define kMethod_ZSTD 6 + +static const char * const k_Methods[] = +{ + "0" + , "ZLIB" + , "LZMA" + , "LZO" + , "XZ" + , "LZ4" + , "ZSTD" +}; + +static const UInt32 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" +}; + +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) +{ + 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) +{ + 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 PackPos; + CRecordVector UnpackPos; // additional item at the end contains TotalUnpackSize + + UInt32 GetNumBlocks() const { return PackPos.Size(); } + void Clear() + { + Data.Free(); + PackPos.Clear(); + UnpackPos.Clear(); + } +}; + +struct CFrag +{ + UInt64 StartBlock; + UInt32 Size; +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CRecordVector _items; + CRecordVector _nodes; + CRecordVector _nodesPos; + CRecordVector _blockToNode; + CData _inodesData; + CData _dirs; + CRecordVector _frags; + // CByteBuffer _uids; + // CByteBuffer _gids; + CHeader _h; + bool _noPropsLZMA; + bool _needCheckLzma; + + UInt32 _openCodePage; + + CMyComPtr _stream; + UInt64 _sizeCalculated; + + IArchiveOpenCallback *_openCallback; + + int _nodeIndex; + CRecordVector _blockCompressed; + CRecordVector _blockOffsets; + + CByteBuffer _cachedBlock; + UInt64 _cachedBlockStartPos; + UInt32 _cachedPackBlockSize; + UInt32 _cachedUnpackBlockSize; + + CLimitedSequentialInStream *_limitedInStreamSpec; + CMyComPtr _limitedInStream; + + CBufPtrSeqOutStream *_outStreamSpec; + CMyComPtr _outStream; + + // NCompress::NLzma::CDecoder *_lzmaDecoderSpec; + // CMyComPtr _lzmaDecoder; + + NCompress::NZlib::CDecoder *_zlibDecoderSpec; + CMyComPtr _zlibDecoder; + + NCompress::NZSTD::CDecoder *_zstdDecoderSpec; + CMyComPtr _zstdDecoder; + + CXzUnpacker _xz; + + CByteBuffer _inputBuffer; + + CDynBufSeqOutStream *_dynOutStreamSpec; + CMyComPtr _dynOutStream; + + void ClearCache() + { + _cachedBlockStartPos = 0; + _cachedPackBlockSize = 0; + _cachedUnpackBlockSize = 0; + } + + HRESULT Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize, + UInt32 inSize, UInt32 outSizeMax); + HRESULT ReadMetadataBlock(UInt32 &packSize); + HRESULT ReadData(CData &data, UInt64 start, UInt64 end); + + HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex); + HRESULT ScanInodes(UInt64 ptr); + // HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids); + HRESULT Open2(IInStream *inStream); + AString GetPath(int index) const; + bool GetPackSize(int index, UInt64 &res, bool fillOffsets); + +public: + CHandler(); + ~CHandler() + { + XzUnpacker_Free(&_xz); + } + + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + + 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 + // kpidUser, + // kpidGroup, + // 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) + (*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 = dest - destStart; + *srcLen = 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++; + } + } +} + +static HRESULT Lz4Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen) +{ + const char *Src = (const char *)src; + char *Dst = (char *)dest; + int compressedSize = (int)*srcLen; + int dstCapacity = (int)*destLen; + // int LZ4_decompress_safe (const char* src, char* dst, int compressedSize, int dstCapacity); + int rv = LZ4_decompress_safe(Src, Dst, compressedSize, dstCapacity); + if (rv == 0) + return S_FALSE; + + *destLen = rv; + return S_OK; +} + +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_ZSTD) + { + if (!_zstdDecoder) + { + _zstdDecoderSpec = new NCompress::NZSTD::CDecoder(); + _zstdDecoder = _zstdDecoderSpec; + } + RINOK(_zstdDecoder->Code(_limitedInStream, outStream, NULL, NULL, NULL)); + if (inSize != _zstdDecoderSpec->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_LZ4) + { + RINOK(Lz4Decode(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) + 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]; + unsigned offset = _h.NeedCheckData() ? 3 : 2; + if (offset > packSize) + return S_FALSE; + RINOK(ReadStream_FALSE(_stream, temp, offset)); + // if (NeedCheckData && Major < 4) checkByte must be = 0xFF + bool be = _h.be; + UInt32 size = Get16(temp); + bool isCompressed = ((size & kNotCompressedBit16) == 0); + if (size != kNotCompressedBit16) + size &= ~kNotCompressedBit16; + + if (size > kMetadataBlockSize || offset + size > packSize) + return S_FALSE; + packSize = offset + size; + if (isCompressed) + { + _limitedInStreamSpec->Init(size); + RINOK(Decompress(_dynOutStream, NULL, NULL, NULL, size, kMetadataBlockSize)); + } + else + { + // size != 0 here + Byte *buf = _dynOutStreamSpec->GetBufPtrForWriting(size); + if (!buf) + return E_OUTOFMEMORY; + RINOK(ReadStream_FALSE(_stream, buf, size)); + _dynOutStreamSpec->UpdateSize(size); + } + return S_OK; +} + +HRESULT CHandler::ReadData(CData &data, UInt64 start, UInt64 end) +{ + if (end < start || end - start >= ((UInt64)1 << 32)) + return S_FALSE; + UInt32 size = (UInt32)(end - start); + RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL)); + _dynOutStreamSpec->Init(); + UInt32 packPos = 0; + while (packPos != size) + { + data.PackPos.Add(packPos); + data.UnpackPos.Add((UInt32)_dynOutStreamSpec->GetSize()); + if (packPos > size) + return S_FALSE; + UInt32 packSize = size - packPos; + RINOK(ReadMetadataBlock(packSize)); + if (_dynOutStreamSpec->GetSize() >= ((UInt64)1 << 32)) + return S_FALSE; + packPos += packSize; + } + data.UnpackPos.Add((UInt32)_dynOutStreamSpec->GetSize()); + _dynOutStreamSpec->CopyToBuffer(data.Data); + return S_OK; +} + +struct CTempItem +{ + UInt32 StartBlock; + // UInt32 iNodeNumber1; + UInt32 Offset; + // UInt16 iNodeNumber2; + UInt16 Type; +}; + +HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex) +{ + if (level > kNumDirLevelsMax) + return S_FALSE; + + int blockIndex = _inodesData.PackPos.FindInSorted(startBlock); + if (blockIndex < 0) + return S_FALSE; + UInt32 unpackPos = _inodesData.UnpackPos[blockIndex] + offset; + if (unpackPos < offset) + return S_FALSE; + + nodeIndex = _nodesPos.FindInSorted(unpackPos, _blockToNode[blockIndex], _blockToNode[blockIndex + 1]); + // nodeIndex = _nodesPos.FindInSorted(unpackPos); + if (nodeIndex < 0) + return S_FALSE; + + const CNode &n = _nodes[nodeIndex]; + if (!n.IsDir()) + return S_OK; + blockIndex = _dirs.PackPos.FindInSorted((UInt32)n.StartBlock); + if (blockIndex < 0) + return S_FALSE; + unpackPos = _dirs.UnpackPos[blockIndex] + n.Offset; + if (unpackPos < n.Offset || unpackPos > _dirs.Data.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 tempItems; + while (rem != 0) + { + bool be = _h.be; + UInt32 count; + CTempItem tempItem; + if (_h.Major <= 2) + { + if (rem < 4) + return S_FALSE; + count = p[0]; + tempItem.StartBlock = Get32(p); + if (be) + tempItem.StartBlock &= 0xFFFFFF; + else + tempItem.StartBlock >>= 8; + p += 4; + rem -= 4; + } + else + { + if (_h.Major == 3) + { + if (rem < 9) + return S_FALSE; + count = p[0]; + p += 1; + rem -= 1; + } + else + { + if (rem < 12) + return S_FALSE; + count = GetUi32(p); + p += 4; + rem -= 4; + } + GET_32 (0, tempItem.StartBlock); + // GET_32 (4, tempItem.iNodeNumber1); + p += 8; + rem -= 8; + } + count++; + + for (UInt32 i = 0; i < count; i++) + { + if (rem == 0) + return S_FALSE; + + UInt32 nameOffset = _h.GetFileNameOffset(); + if (rem < nameOffset) + return S_FALSE; + + if ((UInt32)_items.Size() >= kNumFilesMax) + return S_FALSE; + if (_openCallback) + { + UInt64 numFiles = _items.Size(); + if ((numFiles & 0xFFFF) == 0) + { + RINOK(_openCallback->SetCompleted(&numFiles, NULL)); + } + } + + CItem item; + item.Ptr = (UInt32)(p - (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(tempString)) + _openCodePage = CP_OEMCP; + } + + p += size; + rem -= size; + item.Parent = parent; + _items.Add(item); + tempItems.Add(tempItem); + } + } + + int startItemIndex = _items.Size() - tempItems.Size(); + FOR_VECTOR (i, tempItems) + { + const CTempItem &tempItem = tempItems[i]; + int index = startItemIndex + i; + CItem &item = _items[index]; + RINOK(OpenDir(index, tempItem.StartBlock, tempItem.Offset, level + 1, item.Node)); + } + + return S_OK; +} + +/* +HRESULT CHandler::ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids) +{ + size_t size = num * 4; + ids.SetCapacity(size); + RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL)); + return ReadStream_FALSE(_stream, ids, size); +} +*/ + +HRESULT CHandler::Open2(IInStream *inStream) +{ + { + Byte buf[kHeaderSize3]; + RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize3)); + if (!_h.Parse(buf)) + return S_FALSE; + if (!_h.IsSupported()) + return E_NOTIMPL; + + _noPropsLZMA = false; + _needCheckLzma = false; + switch (_h.Method) + { + case kMethod_ZLIB: _needCheckLzma = true; break; + case kMethod_LZMA: + case kMethod_LZO: + case kMethod_XZ: + case kMethod_LZ4: + case kMethod_ZSTD: + break; + default: + return E_NOTIMPL; + } + } + + _stream = inStream; + + if (_h.NumFrags != 0) + { + if (_h.NumFrags > kNumFilesMax) + return S_FALSE; + _frags.ClearAndReserve(_h.NumFrags); + unsigned bigFrag = (_h.Major > 2); + + unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag); + UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog; + size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag); + CByteBuffer data(numBlocksBytes); + RINOK(inStream->Seek(_h.FragTable, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)); + bool be = _h.be; + + for (UInt32 i = 0; i < numBlocks; i++) + { + UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4); + RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); + _dynOutStreamSpec->Init(); + UInt32 packSize = kMetadataBlockSize + 3; + RINOK(ReadMetadataBlock(packSize)); + UInt32 unpackSize = (UInt32)_dynOutStreamSpec->GetSize(); + if (unpackSize != kMetadataBlockSize) + if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1))) + return S_FALSE; + const Byte *buf = _dynOutStreamSpec->GetBuffer(); + for (UInt32 j = 0; j < kMetadataBlockSize && j < unpackSize;) + { + CFrag frag; + if (bigFrag) + { + frag.StartBlock = Get64(buf + j); + frag.Size = Get32(buf + j + 8); + // some archives contain nonzero in unused (buf + j + 12) + j += 16; + } + else + { + frag.StartBlock = Get32(buf + j); + frag.Size = Get32(buf + j + 4); + j += 8; + } + _frags.Add(frag); + } + } + if ((UInt32)_frags.Size() != _h.NumFrags) + return S_FALSE; + } + + // RINOK(inStream->Seek(_h.InodeTable, STREAM_SEEK_SET, NULL)); + + RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable)); + RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable)); + + UInt64 absOffset = _h.RootInode >> 16; + if (absOffset >= ((UInt64)1 << 32)) + return S_FALSE; + { + UInt32 pos = 0; + UInt32 totalSize = (UInt32)_inodesData.Data.Size(); + _nodesPos.ClearAndReserve(_h.NumInodes); + _nodes.ClearAndReserve(_h.NumInodes); + // we use _blockToNode for binary search seed optimizations + _blockToNode.ClearAndReserve(_inodesData.GetNumBlocks() + 1); + int curBlock = 0; + for (UInt32 i = 0; i < _h.NumInodes; i++) + { + CNode n; + const Byte *p = _inodesData.Data + pos; + UInt32 size = totalSize - pos; + + switch (_h.Major) + { + case 1: size = n.Parse1(p, size, _h); break; + case 2: size = n.Parse2(p, size, _h); break; + case 3: size = n.Parse3(p, size, _h); break; + default: size = n.Parse4(p, size, _h); break; + } + if (size == 0) + return S_FALSE; + while (pos >= _inodesData.UnpackPos[curBlock]) + { + _blockToNode.Add(_nodesPos.Size()); + curBlock++; + } + _nodesPos.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 + { + UInt32 size = _h.NumIDs * 4; + _uids.SetCapacity(size); + + UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize; + UInt32 numBlocksBytes = numBlocks << 3; + CByteBuffer data; + data.SetCapacity(numBlocksBytes); + RINOK(inStream->Seek(_h.UidTable, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)); + + for (UInt32 i = 0; i < numBlocks; i++) + { + UInt64 offset = GetUi64(data + i * 8); + UInt32 unpackSize, packSize; + RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); + RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize)); + if (unpackSize != kMetadataBlockSize) + if (i != numBlocks - 1 || unpackSize != (size & (kMetadataBlockSize - 1))) + return S_FALSE; + } + } + */ + + { + const UInt32 alignSize = 1 << 12; + Byte buf[alignSize]; + RINOK(inStream->Seek(_h.Size, STREAM_SEEK_SET, NULL)); + UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1); + _sizeCalculated = _h.Size; + if (rem != 0) + { + if (ReadStream_FALSE(_stream, buf, rem) == S_OK) + { + size_t i; + for (i = 0; i < rem && buf[i] == 0; i++); + if (i == rem) + _sizeCalculated = _h.Size + rem; + } + } + } + return S_OK; +} + +AString CHandler::GetPath(int index) const +{ + unsigned len = 0; + int indexMem = index; + bool be = _h.be; + do + { + const CItem &item = _items[index]; + index = item.Parent; + const Byte *p = _dirs.Data + item.Ptr; + unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1; + p += _h.GetFileNameOffset(); + unsigned i; + for (i = 0; i < size && p[i]; i++); + len += i + 1; + } + while (index >= 0); + len--; + + AString path; + char *dest = path.GetBuf_SetEnd(len) + len; + index = indexMem; + for (;;) + { + const CItem &item = _items[index]; + index = item.Parent; + const Byte *p = _dirs.Data + item.Ptr; + unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1; + p += _h.GetFileNameOffset(); + unsigned i; + for (i = 0; i < size && p[i]; i++); + dest -= i; + memcpy(dest, p, i); + if (index < 0) + break; + *(--dest) = CHAR_PATH_SEPARATOR; + } + return path; +} + +STDMETHODIMP 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 +} + +STDMETHODIMP 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(int index, UInt64 &totalPack, bool fillOffsets) +{ + totalPack = 0; + const CItem &item = _items[index]; + const CNode &node = _nodes[item.Node]; + UInt32 ptr = _nodesPos[item.Node]; + const Byte *p = _inodesData.Data + ptr; + bool be = _h.be; + + UInt32 type = node.Type; + UInt32 offset; + if (node.IsLink() || node.FileSize == 0) + { + totalPack = node.FileSize; + return true; + } + + UInt32 numBlocks = (UInt32)node.GetNumBlocks(_h); + + if (fillOffsets) + { + _blockOffsets.Clear(); + _blockCompressed.Clear(); + _blockOffsets.Add(totalPack); + } + + if (_h.Major <= 1) + { + offset = 15; + p += offset; + + for (UInt32 i = 0; i < numBlocks; i++) + { + UInt32 t = Get16(p + i * 2); + if (fillOffsets) + _blockCompressed.Add((t & kNotCompressedBit16) == 0); + if (t != kNotCompressedBit16) + t &= ~kNotCompressedBit16; + totalPack += t; + if (fillOffsets) + _blockOffsets.Add(totalPack); + } + } + else + { + if (_h.Major <= 2) + offset = 24; + else if (type == kType_FILE) + offset = 32; + else if (type == kType_FILE + 7) + offset = (_h.Major <= 3 ? 40 : 56); + else + return false; + + p += offset; + + for (UInt64 i = 0; i < numBlocks; i++) + { + UInt32 t = Get32(p + i * 4); + if (fillOffsets) + _blockCompressed.Add(IS_COMPRESSED_BLOCK(t)); + UInt32 size = GET_COMPRESSED_BLOCK_SIZE(t); + if (size > _h.BlockSize) + return false; + totalPack += size; + if (fillOffsets) + _blockOffsets.Add(totalPack); + } + + if (node.ThereAreFrags()) + { + if (node.Frag >= (UInt32)_frags.Size()) + return false; + const CFrag &frag = _frags[node.Frag]; + if (node.Offset == 0) + { + UInt32 size = GET_COMPRESSED_BLOCK_SIZE(frag.Size); + if (size > _h.BlockSize) + return false; + totalPack += size; + } + } + } + return true; +} + + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidMethod: + { + char sz[16]; + const char *s; + if (_noPropsLZMA) + s = "LZMA Spec"; + else if (_h.SeveralMethods) + s = "LZMA ZLIB"; + else + { + s = NULL; + if (_h.Method < 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 += '.'; + 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) + { + FILETIME ft; + NWindows::NTime::UnixTimeToFileTime(_h.CTime, ft); + prop = ft; + } + break; + case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break; + // case kpidNumBlocks: prop = _h.NumFrags; break; + case kpidPhySize: prop = _sizeCalculated; break; + case kpidHeadersSize: + if (_sizeCalculated >= _h.InodeTable) + prop = _sizeCalculated - _h.InodeTable; + break; + + 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 +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem &item = _items[index]; + const CNode &node = _nodes[item.Node]; + bool isDir = node.IsDir(); + bool be = _h.be; + + switch (propID) + { + case kpidPath: + { + 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; + FILETIME ft; + NWindows::NTime::UnixTimeToFileTime(Get32(p), ft); + prop = ft; + } + break; + } + case kpidPosixAttrib: + { + if (node.Type != 0 && node.Type < ARRAY_SIZE(k_TypeToMode)) + prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type]; + break; + } + /* + case kpidUser: + { + UInt32 offset = node.Uid * 4; + if (offset < _uids.Size()) + prop = (UInt32)Get32(_uids + offset); + break; + } + case kpidGroup: + { + if (_h.Major == 4 || node.Gid == _h.GetSpecGuidIndex()) + { + UInt32 offset = node.Uid * 4; + if (offset < _uids.Size()) + prop = (UInt32)Get32(_uids + offset); + } + else + { + UInt32 offset = node.Gid * 4; + if (offset < _gids.Size()) + prop = (UInt32)Get32(_gids + offset); + } + break; + } + */ + /* + case kpidLinks: + if (_h.Major >= 3 && node.Type != kType_FILE) + prop = node.NumLinks; + break; + */ + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +class CSquashfsInStream: public CCachedInStream +{ + HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); +public: + CHandler *Handler; +}; + +HRESULT CSquashfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) +{ + return Handler->ReadBlock(blockIndex, dest, blockSize); +} + +HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) +{ + const CNode &node = _nodes[_nodeIndex]; + UInt64 blockOffset; + UInt32 packBlockSize; + UInt32 offsetInBlock = 0; + bool compressed; + if (blockIndex < _blockCompressed.Size()) + { + compressed = _blockCompressed[(int)blockIndex]; + blockOffset = _blockOffsets[(int)blockIndex]; + packBlockSize = (UInt32)(_blockOffsets[(int)blockIndex + 1] - blockOffset); + blockOffset += node.StartBlock; + } + else + { + if (!node.ThereAreFrags()) + return S_FALSE; + const CFrag &frag = _frags[node.Frag]; + offsetInBlock = node.Offset; + blockOffset = frag.StartBlock; + packBlockSize = GET_COMPRESSED_BLOCK_SIZE(frag.Size); + compressed = IS_COMPRESSED_BLOCK(frag.Size); + } + + if (packBlockSize == 0) + { + // sparse file ??? + memset(dest, 0, blockSize); + return S_OK; + } + + if (blockOffset != _cachedBlockStartPos || + packBlockSize != _cachedPackBlockSize) + { + ClearCache(); + RINOK(_stream->Seek(blockOffset, STREAM_SEEK_SET, NULL)); + _limitedInStreamSpec->Init(packBlockSize); + + if (compressed) + { + _outStreamSpec->Init((Byte *)_cachedBlock, _h.BlockSize); + bool outBufWasWritten; + UInt32 outBufWasWrittenSize; + HRESULT res = Decompress(_outStream, _cachedBlock, &outBufWasWritten, &outBufWasWrittenSize, packBlockSize, _h.BlockSize); + if (outBufWasWritten) + _cachedUnpackBlockSize = outBufWasWrittenSize; + else + _cachedUnpackBlockSize = (UInt32)_outStreamSpec->GetPos(); + RINOK(res); + } + else + { + RINOK(ReadStream_FALSE(_limitedInStream, _cachedBlock, packBlockSize)); + _cachedUnpackBlockSize = packBlockSize; + } + _cachedBlockStartPos = blockOffset; + _cachedPackBlockSize = packBlockSize; + } + if (offsetInBlock + blockSize > _cachedUnpackBlockSize) + return S_FALSE; + if (blockSize != 0) + memcpy(dest, _cachedBlock + offsetInBlock, blockSize); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + const CNode &node = _nodes[item.Node]; + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + // const Byte *p = _data + item.Offset; + + if (node.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + UInt64 unpackSize = node.GetSize(); + totalSize += unpackSize; + UInt64 packSize; + if (GetPackSize(index, packSize, false)) + totalPackSize += packSize; + + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + + int res = NExtract::NOperationResult::kDataError; + { + CMyComPtr 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 +} + + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + + const CItem &item = _items[index]; + const CNode &node = _nodes[item.Node]; + + if (node.IsDir()) + return E_FAIL; + + const Byte *p = _inodesData.Data + _nodesPos[item.Node]; + + if (node.FileSize == 0 || node.IsLink()) + { + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr 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 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", 0, 0xD2, + k_Signature, + 0, + NArcInfoFlags::kMultiSignature, + NULL) + +}} diff --git a/CPP/7zip/Archive/StdAfx.h b/CPP/7zip/Archive/StdAfx.h index 42a088f12..1cbd7feae 100644 --- a/CPP/7zip/Archive/StdAfx.h +++ b/CPP/7zip/Archive/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/SwfHandler.cpp b/CPP/7zip/Archive/SwfHandler.cpp index 224ab1527..ebb6acfdd 100644 --- a/CPP/7zip/Archive/SwfHandler.cpp +++ b/CPP/7zip/Archive/SwfHandler.cpp @@ -1,980 +1,980 @@ -// 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/LzmaEncoder.h" -#include "../Compress/ZlibDecoder.h" -#include "../Compress/ZlibEncoder.h" - -#include "Common/DummyOutStream.h" -#include "Common/HandlerOut.h" - -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); - } -}; - -class CHandler: - public IInArchive, - public IArchiveOpenSeq, - public IOutArchive, - public ISetProperties, - public CMyUnknownImp -{ - CItem _item; - UInt64 _packSize; - bool _packSizeDefined; - CMyComPtr _seqStream; - CMyComPtr _stream; - - CSingleMethodProps _props; - bool _lzmaMode; - -public: - CHandler(): _lzmaMode(false) {} - MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties) - INTERFACE_IInArchive(;) - INTERFACE_IOutArchive(;) - STDMETHOD(OpenSeq)(ISequentialInStream *stream); - STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); -}; - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize, - kpidMethod -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: if (_packSizeDefined) prop = _item.HeaderSize + _packSize; break; - case kpidIsNotArcType: prop = true; break; - } - prop.Detach(value); - return S_OK; -} - -STDMETHODIMP 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 <= 31; 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; -} - -STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) -{ - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidSize: prop = (UInt64)_item.GetSize(); break; - case kpidPackSize: if (_packSizeDefined) prop = _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; -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) -{ - RINOK(OpenSeq(stream)); - _stream = stream; - return S_OK; -} - -STDMETHODIMP 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; -} - -STDMETHODIMP CHandler::Close() -{ - _packSize = 0; - _packSizeDefined = false; - _seqStream.Release(); - _stream.Release(); - return S_OK; -} - -class CCompressProgressInfoImp: - public ICompressProgressInfo, - public CMyUnknownImp -{ - CMyComPtr 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) - { - UInt64 files = 0; - UInt64 value = Offset + *inSize; - return Callback->SetCompleted(&files, &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; - - extractCallback->SetTotal(_item.GetSize()); - CMyComPtr 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 outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(); - realOutStream.Release(); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr 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(_stream->Seek(_item.HeaderSize, STREAM_SEEK_SET, NULL)); - NCompress::NZlib::CDecoder *_decoderZlibSpec = NULL; - NCompress::NLzma::CDecoder *_decoderLzmaSpec = NULL; - CMyComPtr _decoder; - - CMyComPtr 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 -} - -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 fileInStream; - RINOK(updateCallback->GetStream(0, &fileInStream)); - - /* - CDummyOutStream *outStreamSpec = new CDummyOutStream; - CMyComPtr outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(); - realOutStream.Release(); - */ - - CItem item; - 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 encoder; - CMyComPtr 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 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 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)); - UInt64 packSize = curPos - kHeaderLzmaSize; - if (packSize > (UInt32)0xFFFFFFFF) - return E_INVALIDARG; - item.MakeLzma((UInt32)packSize); - RINOK(outSeekStream->Seek(0, STREAM_SEEK_SET, NULL)); - item.WriteHeader(outStream); - inputProcessed = encoderLzmaSpec->GetInputProcessedSize(); - } - else - { - inputProcessed = encoderZlibSpec->GetInputProcessedSize(); - } - if (inputProcessed + kHeaderBaseSize != size) - return E_INVALIDARG; - return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK); -} - -STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) -{ - *timeType = NFileTimeType::kUnix; - return S_OK; -} - -STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *updateCallback) -{ - if (numItems != 1) - return E_INVALIDARG; - - Int32 newData, newProps; - UInt32 indexInArchive; - if (!updateCallback) - return E_FAIL; - RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); - - if (IntToBool(newProps)) - { - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)); - if (prop.vt == VT_BOOL) - { - if (prop.boolVal != VARIANT_FALSE) - return E_INVALIDARG; - } - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - } - - if (IntToBool(newData)) - { - UInt64 size; - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidSize, &prop)); - if (prop.vt != VT_UI8) - return E_INVALIDARG; - size = prop.uhVal.QuadPart; - } - return UpdateArchive(outStream, size, _lzmaMode, _props, updateCallback); - } - - if (indexInArchive != 0) - return E_INVALIDARG; - - if (!_seqStream) - return E_NOTIMPL; - - if (_stream) - { - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - } - else - _item.WriteHeader(outStream); - return NCompress::CopyStream(_seqStream, outStream, NULL); -} - -STDMETHODIMP CHandler::SetProperties(const wchar_t * 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; -} - -static const Byte k_Signature[] = { - 3, 'C', 'W', 'S', - 3, 'Z', 'W', 'S' }; - -REGISTER_ARC_IO( - "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; -}; - -class CHandler: - public IInArchive, - public IArchiveOpenSeq, - public CMyUnknownImp -{ - CObjectVector _tags; - NSwfc::CItem _item; - UInt64 _phySize; - - HRESULT OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback); - HRESULT OpenSeq2(ISequentialInStream *stream, IArchiveOpenCallback *callback); -public: - MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq) - INTERFACE_IInArchive(;) - - STDMETHOD(OpenSeq)(ISequentialInStream *stream); -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidComment, -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table - -STDMETHODIMP 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; -} - - -STDMETHODIMP 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" -}; - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - NWindows::NCOM::CPropVariant prop; - const CTag &tag = _tags[index]; - switch (propID) - { - case kpidPath: - { - char s[32]; - ConvertUInt32ToString(index, s); - size_t i = strlen(s); - s[i++] = '.'; - ConvertUInt32ToString(tag.Type, s + i); - prop = s; - break; - } - case kpidSize: - case kpidPackSize: - prop = (UInt64)tag.Buf.Size(); break; - case kpidComment: - TYPE_TO_PROP(g_TagDesc, tag.Type, prop); - break; - } - prop.Detach(value); - return S_OK; -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) -{ - return OpenSeq2(stream, callback); -} - -static UInt16 Read16(CInBuffer &stream) -{ - UInt16 res = 0; - for (int i = 0; i < 2; i++) - { - Byte b; - if (!stream.ReadByte(b)) - throw 1; - res |= (UInt16)b << (i * 8); - } - return res; -} - -static UInt32 Read32(CInBuffer &stream) -{ - UInt32 res = 0; - for (int i = 0; i < 4; i++) - { - Byte b; - if (!stream.ReadByte(b)) - throw 1; - res |= (UInt32)b << (i * 8); - } - return res; -} - -struct CBitReader -{ - CInBuffer *stream; - unsigned NumBits; - Byte Val; - - CBitReader(): NumBits(0), Val(0) {} - - UInt32 ReadBits(unsigned numBits); -}; - -UInt32 CBitReader::ReadBits(unsigned numBits) -{ - UInt32 res = 0; - while (numBits > 0) - { - if (NumBits == 0) - { - Val = stream->ReadByte(); - NumBits = 8; - } - if (numBits <= NumBits) - { - res <<= numBits; - NumBits -= numBits; - res |= (Val >> NumBits); - Val &= (1 << NumBits) - 1; - break; - } - else - { - res <<= NumBits; - res |= Val; - numBits -= NumBits; - NumBits = 0; - } - } - return res; -} - -HRESULT CHandler::OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback) -{ - RINOK(_item.ReadHeader(stream)) - if (!_item.IsSwf() || !_item.IsUncompressed()) - return S_FALSE; - 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; - unsigned numBits = br.ReadBits(5); - /* UInt32 xMin = */ br.ReadBits(numBits); - /* UInt32 xMax = */ br.ReadBits(numBits); - /* UInt32 yMin = */ br.ReadBits(numBits); - /* UInt32 yMax = */ br.ReadBits(numBits); - } - /* UInt32 frameDelay = */ Read16(s); - /* UInt32 numFrames = */ Read16(s); - - _tags.Clear(); - UInt64 offsetPrev = 0; - for (;;) - { - UInt32 pair = Read16(s); - UInt32 type = pair >> 6; - UInt32 length = pair & 0x3F; - if (length == 0x3F) - length = Read32(s); - if (type == 0) - break; - UInt64 offset = s.GetProcessedSize() + NSwfc::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)) - { - 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; -} - -STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) -{ - return OpenSeq2(stream, NULL); -} - -STDMETHODIMP CHandler::Close() -{ - _phySize = 0; - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - 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(); - extractCallback->SetTotal(totalSize); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - totalSize = 0; - - for (i = 0; i < numItems; i++) - { - lps->InSize = lps->OutSize = totalSize; - RINOK(lps->SetCur()); - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - UInt32 index = allFilesMode ? i : indices[i]; - const CByteBuffer &buf = _tags[index].Buf; - totalSize += buf.Size(); - - CMyComPtr 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", 0, 0xD7, - k_Signature, - 0, - NArcInfoFlags::kKeepName, - NSwfc::IsArc_Swf) - -}} +// 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/LzmaEncoder.h" +#include "../Compress/ZlibDecoder.h" +#include "../Compress/ZlibEncoder.h" + +#include "Common/DummyOutStream.h" +#include "Common/HandlerOut.h" + +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); + } +}; + +class CHandler: + public IInArchive, + public IArchiveOpenSeq, + public IOutArchive, + public ISetProperties, + public CMyUnknownImp +{ + CItem _item; + UInt64 _packSize; + bool _packSizeDefined; + CMyComPtr _seqStream; + CMyComPtr _stream; + + CSingleMethodProps _props; + bool _lzmaMode; + +public: + CHandler(): _lzmaMode(false) {} + MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties) + INTERFACE_IInArchive(;) + INTERFACE_IOutArchive(;) + STDMETHOD(OpenSeq)(ISequentialInStream *stream); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); +}; + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize, + kpidMethod +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: if (_packSizeDefined) prop = _item.HeaderSize + _packSize; break; + case kpidIsNotArcType: prop = true; break; + } + prop.Detach(value); + return S_OK; +} + +STDMETHODIMP 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 <= 31; 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; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +{ + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidSize: prop = (UInt64)_item.GetSize(); break; + case kpidPackSize: if (_packSizeDefined) prop = _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; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) +{ + RINOK(OpenSeq(stream)); + _stream = stream; + return S_OK; +} + +STDMETHODIMP 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; +} + +STDMETHODIMP CHandler::Close() +{ + _packSize = 0; + _packSizeDefined = false; + _seqStream.Release(); + _stream.Release(); + return S_OK; +} + +class CCompressProgressInfoImp: + public ICompressProgressInfo, + public CMyUnknownImp +{ + CMyComPtr 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) + { + UInt64 files = 0; + UInt64 value = Offset + *inSize; + return Callback->SetCompleted(&files, &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; + + extractCallback->SetTotal(_item.GetSize()); + CMyComPtr 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 outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + realOutStream.Release(); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr 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(_stream->Seek(_item.HeaderSize, STREAM_SEEK_SET, NULL)); + NCompress::NZlib::CDecoder *_decoderZlibSpec = NULL; + NCompress::NLzma::CDecoder *_decoderLzmaSpec = NULL; + CMyComPtr _decoder; + + CMyComPtr 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 +} + +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 fileInStream; + RINOK(updateCallback->GetStream(0, &fileInStream)); + + /* + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + realOutStream.Release(); + */ + + CItem item; + 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 encoder; + CMyComPtr 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 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 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)); + UInt64 packSize = curPos - kHeaderLzmaSize; + if (packSize > (UInt32)0xFFFFFFFF) + return E_INVALIDARG; + item.MakeLzma((UInt32)packSize); + RINOK(outSeekStream->Seek(0, STREAM_SEEK_SET, NULL)); + item.WriteHeader(outStream); + inputProcessed = encoderLzmaSpec->GetInputProcessedSize(); + } + else + { + inputProcessed = encoderZlibSpec->GetInputProcessedSize(); + } + if (inputProcessed + kHeaderBaseSize != size) + return E_INVALIDARG; + return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK); +} + +STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) +{ + *timeType = NFileTimeType::kUnix; + return S_OK; +} + +STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback) +{ + if (numItems != 1) + return E_INVALIDARG; + + Int32 newData, newProps; + UInt32 indexInArchive; + if (!updateCallback) + return E_FAIL; + RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); + + if (IntToBool(newProps)) + { + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)); + if (prop.vt == VT_BOOL) + { + if (prop.boolVal != VARIANT_FALSE) + return E_INVALIDARG; + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + } + + if (IntToBool(newData)) + { + UInt64 size; + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidSize, &prop)); + if (prop.vt != VT_UI8) + return E_INVALIDARG; + size = prop.uhVal.QuadPart; + } + return UpdateArchive(outStream, size, _lzmaMode, _props, updateCallback); + } + + if (indexInArchive != 0) + return E_INVALIDARG; + + if (!_seqStream) + return E_NOTIMPL; + + if (_stream) + { + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); + } + else + _item.WriteHeader(outStream); + return NCompress::CopyStream(_seqStream, outStream, NULL); +} + +STDMETHODIMP CHandler::SetProperties(const wchar_t * 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; +} + +static const Byte k_Signature[] = { + 3, 'C', 'W', 'S', + 3, 'Z', 'W', 'S' }; + +REGISTER_ARC_IO( + "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; +}; + +class CHandler: + public IInArchive, + public IArchiveOpenSeq, + public CMyUnknownImp +{ + CObjectVector _tags; + NSwfc::CItem _item; + UInt64 _phySize; + + HRESULT OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback); + HRESULT OpenSeq2(ISequentialInStream *stream, IArchiveOpenCallback *callback); +public: + MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq) + INTERFACE_IInArchive(;) + + STDMETHOD(OpenSeq)(ISequentialInStream *stream); +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidComment, +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +STDMETHODIMP 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; +} + + +STDMETHODIMP 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" +}; + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + NWindows::NCOM::CPropVariant prop; + const CTag &tag = _tags[index]; + switch (propID) + { + case kpidPath: + { + char s[32]; + ConvertUInt32ToString(index, s); + size_t i = strlen(s); + s[i++] = '.'; + ConvertUInt32ToString(tag.Type, s + i); + prop = s; + break; + } + case kpidSize: + case kpidPackSize: + prop = (UInt64)tag.Buf.Size(); break; + case kpidComment: + TYPE_TO_PROP(g_TagDesc, tag.Type, prop); + break; + } + prop.Detach(value); + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) +{ + return OpenSeq2(stream, callback); +} + +static UInt16 Read16(CInBuffer &stream) +{ + UInt16 res = 0; + for (int i = 0; i < 2; i++) + { + Byte b; + if (!stream.ReadByte(b)) + throw 1; + res |= (UInt16)b << (i * 8); + } + return res; +} + +static UInt32 Read32(CInBuffer &stream) +{ + UInt32 res = 0; + for (int i = 0; i < 4; i++) + { + Byte b; + if (!stream.ReadByte(b)) + throw 1; + res |= (UInt32)b << (i * 8); + } + return res; +} + +struct CBitReader +{ + CInBuffer *stream; + unsigned NumBits; + Byte Val; + + CBitReader(): NumBits(0), Val(0) {} + + UInt32 ReadBits(unsigned numBits); +}; + +UInt32 CBitReader::ReadBits(unsigned numBits) +{ + UInt32 res = 0; + while (numBits > 0) + { + if (NumBits == 0) + { + Val = stream->ReadByte(); + NumBits = 8; + } + if (numBits <= NumBits) + { + res <<= numBits; + NumBits -= numBits; + res |= (Val >> NumBits); + Val &= (1 << NumBits) - 1; + break; + } + else + { + res <<= NumBits; + res |= Val; + numBits -= NumBits; + NumBits = 0; + } + } + return res; +} + +HRESULT CHandler::OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback) +{ + RINOK(_item.ReadHeader(stream)) + if (!_item.IsSwf() || !_item.IsUncompressed()) + return S_FALSE; + 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; + unsigned numBits = br.ReadBits(5); + /* UInt32 xMin = */ br.ReadBits(numBits); + /* UInt32 xMax = */ br.ReadBits(numBits); + /* UInt32 yMin = */ br.ReadBits(numBits); + /* UInt32 yMax = */ br.ReadBits(numBits); + } + /* UInt32 frameDelay = */ Read16(s); + /* UInt32 numFrames = */ Read16(s); + + _tags.Clear(); + UInt64 offsetPrev = 0; + for (;;) + { + UInt32 pair = Read16(s); + UInt32 type = pair >> 6; + UInt32 length = pair & 0x3F; + if (length == 0x3F) + length = Read32(s); + if (type == 0) + break; + UInt64 offset = s.GetProcessedSize() + NSwfc::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)) + { + 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; +} + +STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) +{ + return OpenSeq2(stream, NULL); +} + +STDMETHODIMP CHandler::Close() +{ + _phySize = 0; + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + 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(); + extractCallback->SetTotal(totalSize); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + totalSize = 0; + + for (i = 0; i < numItems; i++) + { + lps->InSize = lps->OutSize = totalSize; + RINOK(lps->SetCur()); + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + const CByteBuffer &buf = _tags[index].Buf; + totalSize += buf.Size(); + + CMyComPtr 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", 0, 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 index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Archive/Tar/StdAfx.h +++ b/CPP/7zip/Archive/Tar/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp index f68e43ebc..72fbf74e9 100644 --- a/CPP/7zip/Archive/Tar/TarHandler.cpp +++ b/CPP/7zip/Archive/Tar/TarHandler.cpp @@ -1,690 +1,690 @@ -// 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 { - -static const UINT k_DefaultCodePage = CP_OEMCP; // it uses it if UTF8 check in names shows error - - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - kpidPosixAttrib, - kpidUser, - kpidGroup, - kpidSymLink, - kpidHardLink, - // kpidLinkType -}; - -static const Byte kArcProps[] = -{ - kpidHeadersSize, - kpidCodePage -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: if (_phySizeDefined) prop = _phySize; break; - case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break; - case kpidErrorFlags: - { - UInt32 flags = 0; - if (!_isArc) - flags |= kpv_ErrorFlags_IsNotArc; - else switch (_error) - { - case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break; - case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break; - } - prop = flags; - break; - } - - case kpidWarningFlags: - { - if (_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; - } - } - prop.Detach(value); - return S_OK; -} - -HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item) -{ - item.HeaderPos = _phySize; - EErrorType error; - HRESULT res = ReadItem(stream, filled, item, error); - if (error == k_ErrorType_Warning) - _warning = true; - else if (error != k_ErrorType_OK) - _error = error; - RINOK(res); - if (filled) - { - /* - if (item.IsSparse()) - _isSparse = true; - */ - if (item.IsPaxExtendedHeader()) - _thereIsPaxExtendedHeader = true; - } - _phySize += item.HeaderSize; - _headersSize += item.HeaderSize; - return S_OK; -} - -HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) -{ - UInt64 endPos = 0; - { - RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); - RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); - } - - _phySizeDefined = true; - - bool utf8_OK = true; - if (!_forceCodePage) - { - if (!utf8_OK) - _curCodePage = k_DefaultCodePage; - } - - for (;;) - { - CItemEx item; - bool filled; - RINOK(ReadItem2(stream, filled, item)); - if (!filled) - break; - - _isArc = true; - _items.Add(item); - - 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); - } - - RINOK(stream->Seek(item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize)); - if (_phySize > endPos) - { - _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) - { - UInt64 numFiles = _items.Size(); - RINOK(callback->SetCompleted(&numFiles, &_phySize)); - } - } - } - - if (!_forceCodePage) - { - if (!utf8_OK) - _curCodePage = k_DefaultCodePage; - } - _openCodePage = _curCodePage; - - if (_items.Size() == 0) - { - if (_error != k_ErrorType_OK) - { - _isArc = false; - return S_FALSE; - } - CMyComPtr openVolumeCallback; - if (!callback) - return S_FALSE; - callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); - if (!openVolumeCallback) - return S_FALSE; - NCOM::CPropVariant prop; - if (openVolumeCallback->GetProperty(kpidName, &prop) != S_OK) - return S_FALSE; - if (prop.vt != VT_BSTR) - return S_FALSE; - unsigned len = MyStringLen(prop.bstrVal); - if (len < 4 || MyStringCompareNoCase(prop.bstrVal + len - 4, L".tar") != 0) - return S_FALSE; - } - - _isArc = true; - return S_OK; -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback) -{ - COM_TRY_BEGIN - { - Close(); - RINOK(Open2(stream, openArchiveCallback)); - _stream = stream; - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) -{ - Close(); - _seqStream = stream; - _isArc = true; - return S_OK; -} - -STDMETHODIMP CHandler::Close() -{ - _isArc = false; - _warning = false; - _error = k_ErrorType_OK; - - _phySizeDefined = false; - _phySize = 0; - _headersSize = 0; - _curIndex = 0; - _latestIsRead = false; - // _isSparse = false; - _thereIsPaxExtendedHeader = false; - _items.Clear(); - _seqStream.Release(); - _stream.Release(); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = (_stream ? _items.Size() : (UInt32)(Int32)-1); - return S_OK; -} - -CHandler::CHandler() -{ - copyCoderSpec = new NCompress::CCopyCoder(); - copyCoder = copyCoderSpec; - _openCodePage = CP_UTF8; - Init(); -} - -HRESULT CHandler::SkipTo(UInt32 index) -{ - while (_curIndex < index || !_latestIsRead) - { - if (_latestIsRead) - { - UInt64 packSize = _latestItem.GetPackSizeAligned(); - RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL)); - _phySize += copyCoderSpec->TotalSize; - if (copyCoderSpec->TotalSize != packSize) - { - _error = k_ErrorType_UnexpectedEnd; - return S_FALSE; - } - _latestIsRead = false; - _curIndex++; - } - else - { - bool filled; - RINOK(ReadItem2(_seqStream, filled, _latestItem)); - if (!filled) - { - _phySizeDefined = true; - return E_INVALIDARG; - } - _latestIsRead = true; - } - } - return S_OK; -} - -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); - prop = dest; -} - -STDMETHODIMP 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->GetUnpackSize(); break; - case kpidPackSize: prop = item->GetPackSizeAligned(); break; - case kpidMTime: - if (item->MTime != 0) - { - FILETIME ft; - if (NTime::UnixTime64ToFileTime(item->MTime, ft)) - prop = ft; - } - break; - case kpidPosixAttrib: prop = item->Get_Combined_Mode(); break; - case kpidUser: TarStringToUnicode(item->User, prop); break; - case kpidGroup: TarStringToUnicode(item->Group, prop); break; - case kpidSymLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kSymLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break; - case kpidHardLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kHardLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break; - // case kpidLinkType: prop = (int)item->LinkFlag; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - ISequentialInStream *stream = _seqStream; - bool seqMode = (_stream == NULL); - if (!seqMode) - stream = _stream; - - bool allFilesMode = (numItems == (UInt32)(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]].GetUnpackSize(); - extractCallback->SetTotal(totalSize); - - UInt64 totalPackSize; - totalSize = totalPackSize = 0; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(stream); - - CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; - CMyComPtr outStream(outStreamSpec); - - for (i = 0; i < numItems || seqMode; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - CMyComPtr realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; - const CItemEx *item; - if (seqMode) - { - HRESULT res = SkipTo(index); - if (res == E_INVALIDARG) - break; - RINOK(res); - item = &_latestItem; - } - else - item = &_items[index]; - - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - UInt64 unpackSize = item->GetUnpackSize(); - totalSize += unpackSize; - totalPackSize += item->GetPackSizeAligned(); - 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 inStream2; - if (!item->IsSparse()) - inStream2 = inStream; - else - { - GetStream(index, &inStream2); - if (!inStream2) - return E_FAIL; - } - - { - if (item->IsSymLink()) - { - RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len())); - } - else - { - if (!seqMode) - { - RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL)); - } - streamSpec->Init(item->GetPackSizeAligned()); - 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 -} - -class CSparseStream: - public IInStream, - public CMyUnknownImp -{ - UInt64 _phyPos; - UInt64 _virtPos; - bool _needStartSeek; - -public: - CHandler *Handler; - CMyComPtr HandlerRef; - unsigned ItemIndex; - CRecordVector PhyOffsets; - - MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); - - void Init() - { - _virtPos = 0; - _phyPos = 0; - _needStartSeek = true; - } -}; - - -STDMETHODIMP 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 (;;) - { - unsigned mid = (left + 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(Handler->_stream->Seek(item.GetDataPosition() + phyPos, STREAM_SEEK_SET, NULL)); - _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; -} - -STDMETHODIMP 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 = offset; - if (newPosition) - *newPosition = _virtPos; - return S_OK; -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - - const CItemEx &item = _items[index]; - - if (item.IsSparse()) - { - CSparseStream *streamSpec = new CSparseStream; - CMyComPtr 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.IsSymLink()) - { - Create_BufInStream_WithReference((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this, stream); - return S_OK; - } - - return CreateLimitedInStream(_stream, item.GetDataPosition(), item.PackSize, stream); - - COM_TRY_END -} - -void CHandler::Init() -{ - _forceCodePage = false; - // _codePage = CP_OEMCP; - _curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP; - _thereIsPaxExtendedHeader = false; -} - -STDMETHODIMP 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 - return E_INVALIDARG; - } - return S_OK; -} - -}} +// 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 { + +static const UINT k_DefaultCodePage = CP_OEMCP; // it uses it if UTF8 check in names shows error + + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidPosixAttrib, + kpidUser, + kpidGroup, + kpidSymLink, + kpidHardLink, + // kpidLinkType +}; + +static const Byte kArcProps[] = +{ + kpidHeadersSize, + kpidCodePage +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: if (_phySizeDefined) prop = _phySize; break; + case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break; + case kpidErrorFlags: + { + UInt32 flags = 0; + if (!_isArc) + flags |= kpv_ErrorFlags_IsNotArc; + else switch (_error) + { + case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break; + case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break; + } + prop = flags; + break; + } + + case kpidWarningFlags: + { + if (_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; + } + } + prop.Detach(value); + return S_OK; +} + +HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item) +{ + item.HeaderPos = _phySize; + EErrorType error; + HRESULT res = ReadItem(stream, filled, item, error); + if (error == k_ErrorType_Warning) + _warning = true; + else if (error != k_ErrorType_OK) + _error = error; + RINOK(res); + if (filled) + { + /* + if (item.IsSparse()) + _isSparse = true; + */ + if (item.IsPaxExtendedHeader()) + _thereIsPaxExtendedHeader = true; + } + _phySize += item.HeaderSize; + _headersSize += item.HeaderSize; + return S_OK; +} + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) +{ + UInt64 endPos = 0; + { + RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + } + + _phySizeDefined = true; + + bool utf8_OK = true; + if (!_forceCodePage) + { + if (!utf8_OK) + _curCodePage = k_DefaultCodePage; + } + + for (;;) + { + CItemEx item; + bool filled; + RINOK(ReadItem2(stream, filled, item)); + if (!filled) + break; + + _isArc = true; + _items.Add(item); + + 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); + } + + RINOK(stream->Seek(item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize)); + if (_phySize > endPos) + { + _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) + { + UInt64 numFiles = _items.Size(); + RINOK(callback->SetCompleted(&numFiles, &_phySize)); + } + } + } + + if (!_forceCodePage) + { + if (!utf8_OK) + _curCodePage = k_DefaultCodePage; + } + _openCodePage = _curCodePage; + + if (_items.Size() == 0) + { + if (_error != k_ErrorType_OK) + { + _isArc = false; + return S_FALSE; + } + CMyComPtr openVolumeCallback; + if (!callback) + return S_FALSE; + callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); + if (!openVolumeCallback) + return S_FALSE; + NCOM::CPropVariant prop; + if (openVolumeCallback->GetProperty(kpidName, &prop) != S_OK) + return S_FALSE; + if (prop.vt != VT_BSTR) + return S_FALSE; + unsigned len = MyStringLen(prop.bstrVal); + if (len < 4 || MyStringCompareNoCase(prop.bstrVal + len - 4, L".tar") != 0) + return S_FALSE; + } + + _isArc = true; + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback) +{ + COM_TRY_BEGIN + { + Close(); + RINOK(Open2(stream, openArchiveCallback)); + _stream = stream; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) +{ + Close(); + _seqStream = stream; + _isArc = true; + return S_OK; +} + +STDMETHODIMP CHandler::Close() +{ + _isArc = false; + _warning = false; + _error = k_ErrorType_OK; + + _phySizeDefined = false; + _phySize = 0; + _headersSize = 0; + _curIndex = 0; + _latestIsRead = false; + // _isSparse = false; + _thereIsPaxExtendedHeader = false; + _items.Clear(); + _seqStream.Release(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = (_stream ? _items.Size() : (UInt32)(Int32)-1); + return S_OK; +} + +CHandler::CHandler() +{ + copyCoderSpec = new NCompress::CCopyCoder(); + copyCoder = copyCoderSpec; + _openCodePage = CP_UTF8; + Init(); +} + +HRESULT CHandler::SkipTo(UInt32 index) +{ + while (_curIndex < index || !_latestIsRead) + { + if (_latestIsRead) + { + UInt64 packSize = _latestItem.GetPackSizeAligned(); + RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL)); + _phySize += copyCoderSpec->TotalSize; + if (copyCoderSpec->TotalSize != packSize) + { + _error = k_ErrorType_UnexpectedEnd; + return S_FALSE; + } + _latestIsRead = false; + _curIndex++; + } + else + { + bool filled; + RINOK(ReadItem2(_seqStream, filled, _latestItem)); + if (!filled) + { + _phySizeDefined = true; + return E_INVALIDARG; + } + _latestIsRead = true; + } + } + return S_OK; +} + +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); + prop = dest; +} + +STDMETHODIMP 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->GetUnpackSize(); break; + case kpidPackSize: prop = item->GetPackSizeAligned(); break; + case kpidMTime: + if (item->MTime != 0) + { + FILETIME ft; + if (NTime::UnixTime64ToFileTime(item->MTime, ft)) + prop = ft; + } + break; + case kpidPosixAttrib: prop = item->Get_Combined_Mode(); break; + case kpidUser: TarStringToUnicode(item->User, prop); break; + case kpidGroup: TarStringToUnicode(item->Group, prop); break; + case kpidSymLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kSymLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break; + case kpidHardLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kHardLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break; + // case kpidLinkType: prop = (int)item->LinkFlag; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + ISequentialInStream *stream = _seqStream; + bool seqMode = (_stream == NULL); + if (!seqMode) + stream = _stream; + + bool allFilesMode = (numItems == (UInt32)(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]].GetUnpackSize(); + extractCallback->SetTotal(totalSize); + + UInt64 totalPackSize; + totalSize = totalPackSize = 0; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(stream); + + CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; + CMyComPtr outStream(outStreamSpec); + + for (i = 0; i < numItems || seqMode; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + const CItemEx *item; + if (seqMode) + { + HRESULT res = SkipTo(index); + if (res == E_INVALIDARG) + break; + RINOK(res); + item = &_latestItem; + } + else + item = &_items[index]; + + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + UInt64 unpackSize = item->GetUnpackSize(); + totalSize += unpackSize; + totalPackSize += item->GetPackSizeAligned(); + 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 inStream2; + if (!item->IsSparse()) + inStream2 = inStream; + else + { + GetStream(index, &inStream2); + if (!inStream2) + return E_FAIL; + } + + { + if (item->IsSymLink()) + { + RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len())); + } + else + { + if (!seqMode) + { + RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL)); + } + streamSpec->Init(item->GetPackSizeAligned()); + 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 +} + +class CSparseStream: + public IInStream, + public CMyUnknownImp +{ + UInt64 _phyPos; + UInt64 _virtPos; + bool _needStartSeek; + +public: + CHandler *Handler; + CMyComPtr HandlerRef; + unsigned ItemIndex; + CRecordVector PhyOffsets; + + MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); + + void Init() + { + _virtPos = 0; + _phyPos = 0; + _needStartSeek = true; + } +}; + + +STDMETHODIMP 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 (;;) + { + unsigned mid = (left + 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(Handler->_stream->Seek(item.GetDataPosition() + phyPos, STREAM_SEEK_SET, NULL)); + _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; +} + +STDMETHODIMP 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 = offset; + if (newPosition) + *newPosition = _virtPos; + return S_OK; +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + + const CItemEx &item = _items[index]; + + if (item.IsSparse()) + { + CSparseStream *streamSpec = new CSparseStream; + CMyComPtr 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.IsSymLink()) + { + Create_BufInStream_WithReference((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this, stream); + return S_OK; + } + + return CreateLimitedInStream(_stream, item.GetDataPosition(), item.PackSize, stream); + + COM_TRY_END +} + +void CHandler::Init() +{ + _forceCodePage = false; + // _codePage = CP_OEMCP; + _curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP; + _thereIsPaxExtendedHeader = false; +} + +STDMETHODIMP 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 + return E_INVALIDARG; + } + return S_OK; +} + +}} diff --git a/CPP/7zip/Archive/Tar/TarHandler.h b/CPP/7zip/Archive/Tar/TarHandler.h index 39ee597b3..eb9c049ef 100644 --- a/CPP/7zip/Archive/Tar/TarHandler.h +++ b/CPP/7zip/Archive/Tar/TarHandler.h @@ -1,79 +1,79 @@ -// TarHandler.h - -#ifndef __TAR_HANDLER_H -#define __TAR_HANDLER_H - -#include "../../../Common/MyCom.h" - -#include "../../../Windows/PropVariant.h" - -#include "../../Compress/CopyCoder.h" - -#include "../IArchive.h" - -#include "TarIn.h" - -namespace NArchive { -namespace NTar { - -class CHandler: - public IInArchive, - public IArchiveOpenSeq, - public IInArchiveGetStream, - public ISetProperties, - public IOutArchive, - public CMyUnknownImp -{ -public: - CObjectVector _items; - CMyComPtr _stream; - CMyComPtr _seqStream; -private: - UInt32 _curIndex; - bool _latestIsRead; - CItemEx _latestItem; - - UInt64 _phySize; - UInt64 _headersSize; - bool _phySizeDefined; - EErrorType _error; - bool _warning; - bool _isArc; - - // bool _isSparse; - bool _thereIsPaxExtendedHeader; - - bool _forceCodePage; - UInt32 _specifiedCodePage; - UInt32 _curCodePage; - UInt32 _openCodePage; - - NCompress::CCopyCoder *copyCoderSpec; - CMyComPtr copyCoder; - - HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo); - HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); - HRESULT SkipTo(UInt32 index); - void TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs = false) const; -public: - MY_UNKNOWN_IMP5( - IInArchive, - IArchiveOpenSeq, - IInArchiveGetStream, - ISetProperties, - IOutArchive - ) - - INTERFACE_IInArchive(;) - INTERFACE_IOutArchive(;) - STDMETHOD(OpenSeq)(ISequentialInStream *stream); - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); - - void Init(); - CHandler(); -}; - -}} - -#endif +// TarHandler.h + +#ifndef __TAR_HANDLER_H +#define __TAR_HANDLER_H + +#include "../../../Common/MyCom.h" + +#include "../../../Windows/PropVariant.h" + +#include "../../Compress/CopyCoder.h" + +#include "../IArchive.h" + +#include "TarIn.h" + +namespace NArchive { +namespace NTar { + +class CHandler: + public IInArchive, + public IArchiveOpenSeq, + public IInArchiveGetStream, + public ISetProperties, + public IOutArchive, + public CMyUnknownImp +{ +public: + CObjectVector _items; + CMyComPtr _stream; + CMyComPtr _seqStream; +private: + UInt32 _curIndex; + bool _latestIsRead; + CItemEx _latestItem; + + UInt64 _phySize; + UInt64 _headersSize; + bool _phySizeDefined; + EErrorType _error; + bool _warning; + bool _isArc; + + // bool _isSparse; + bool _thereIsPaxExtendedHeader; + + bool _forceCodePage; + UInt32 _specifiedCodePage; + UInt32 _curCodePage; + UInt32 _openCodePage; + + NCompress::CCopyCoder *copyCoderSpec; + CMyComPtr copyCoder; + + HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo); + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); + HRESULT SkipTo(UInt32 index); + void TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs = false) const; +public: + MY_UNKNOWN_IMP5( + IInArchive, + IArchiveOpenSeq, + IInArchiveGetStream, + ISetProperties, + IOutArchive + ) + + INTERFACE_IInArchive(;) + INTERFACE_IOutArchive(;) + STDMETHOD(OpenSeq)(ISequentialInStream *stream); + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); + + void Init(); + CHandler(); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp index 5f808f016..419343399 100644 --- a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp +++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp @@ -1,176 +1,176 @@ -// TarHandlerOut.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/Defs.h" -#include "../../../Common/MyLinux.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/UTFConvert.h" - -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/TimeUtils.h" - -#include "TarHandler.h" -#include "TarUpdate.h" - -using namespace NWindows; - -namespace NArchive { -namespace NTar { - -STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) -{ - *type = NFileTimeType::kUnix; - return S_OK; -} - -HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, - AString &res, UINT codePage, bool convertSlash = false) -{ - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(index, propId, &prop)); - - if (prop.vt == VT_BSTR) - { - UString s = prop.bstrVal; - if (convertSlash) - NItemName::ReplaceSlashes_OsToUnix(s); - - if (codePage == CP_UTF8) - { - ConvertUnicodeToUTF8(s, res); - // if (!ConvertUnicodeToUTF8(s, res)) // return E_INVALIDARG; - } - else - UnicodeStringToMultiByte2(res, s, codePage); - } - 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 **)p1)); - const CUpdateItem &u2 = *(*((const CUpdateItem **)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); -} - - -STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *callback) -{ - COM_TRY_BEGIN - - if ((_stream && (_error != k_ErrorType_OK || _warning /* || _isSparse */)) || _seqStream) - return E_NOTIMPL; - CObjectVector updateItems; - UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage); - - 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 = 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; - // FIXME : we can clear high file type bits to be more compatible with tars created by GNU TAR. - // ui.Mode &= ~(UInt32)MY_LIN_S_IFMT; - } - - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidMTime, &prop)); - if (prop.vt == VT_EMPTY) - ui.MTime = 0; - else if (prop.vt != VT_FILETIME) - return E_INVALIDARG; - else - ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime); - } - - RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, true)); - if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/') - ui.Name += '/'; - RINOK(GetPropString(callback, i, kpidUser, ui.User, codePage)); - RINOK(GetPropString(callback, i, kpidGroup, ui.Group, codePage)); - } - - 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 (_thereIsPaxExtendedHeader) - { - // we restore original order of files, if there is pax header block - updateItems.Sort(CompareUpdateItems, NULL); - } - - return UpdateArchive(_stream, outStream, _items, updateItems, codePage, callback); - - COM_TRY_END -} - -}} +// TarHandlerOut.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/Defs.h" +#include "../../../Common/MyLinux.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" + +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" + +#include "TarHandler.h" +#include "TarUpdate.h" + +using namespace NWindows; + +namespace NArchive { +namespace NTar { + +STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) +{ + *type = NFileTimeType::kUnix; + return S_OK; +} + +HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, + AString &res, UINT codePage, bool convertSlash = false) +{ + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(index, propId, &prop)); + + if (prop.vt == VT_BSTR) + { + UString s = prop.bstrVal; + if (convertSlash) + NItemName::ReplaceSlashes_OsToUnix(s); + + if (codePage == CP_UTF8) + { + ConvertUnicodeToUTF8(s, res); + // if (!ConvertUnicodeToUTF8(s, res)) // return E_INVALIDARG; + } + else + UnicodeStringToMultiByte2(res, s, codePage); + } + 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 **)p1)); + const CUpdateItem &u2 = *(*((const CUpdateItem **)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); +} + + +STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *callback) +{ + COM_TRY_BEGIN + + if ((_stream && (_error != k_ErrorType_OK || _warning /* || _isSparse */)) || _seqStream) + return E_NOTIMPL; + CObjectVector updateItems; + UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage); + + 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 = 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; + // FIXME : we can clear high file type bits to be more compatible with tars created by GNU TAR. + // ui.Mode &= ~(UInt32)MY_LIN_S_IFMT; + } + + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidMTime, &prop)); + if (prop.vt == VT_EMPTY) + ui.MTime = 0; + else if (prop.vt != VT_FILETIME) + return E_INVALIDARG; + else + ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime); + } + + RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, true)); + if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/') + ui.Name += '/'; + RINOK(GetPropString(callback, i, kpidUser, ui.User, codePage)); + RINOK(GetPropString(callback, i, kpidGroup, ui.Group, codePage)); + } + + 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 (_thereIsPaxExtendedHeader) + { + // we restore original order of files, if there is pax header block + updateItems.Sort(CompareUpdateItems, NULL); + } + + return UpdateArchive(_stream, outStream, _items, updateItems, codePage, callback); + + COM_TRY_END +} + +}} diff --git a/CPP/7zip/Archive/Tar/TarHeader.cpp b/CPP/7zip/Archive/Tar/TarHeader.cpp index 549b80aaf..a22f36bd1 100644 --- a/CPP/7zip/Archive/Tar/TarHeader.cpp +++ b/CPP/7zip/Archive/Tar/TarHeader.cpp @@ -1,23 +1,23 @@ -// 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"; - const char kUsTar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ; - } - -}}} +// 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"; + const char kUsTar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ; + } + +}}} diff --git a/CPP/7zip/Archive/Tar/TarHeader.h b/CPP/7zip/Archive/Tar/TarHeader.h index 89dbafb66..47971b587 100644 --- a/CPP/7zip/Archive/Tar/TarHeader.h +++ b/CPP/7zip/Archive/Tar/TarHeader.h @@ -1,84 +1,84 @@ -// Archive/TarHeader.h - -#ifndef __ARCHIVE_TAR_HEADER_H -#define __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 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. */ - } - - 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 kUsTar_00[8]; - } -} - -}} - -#endif +// Archive/TarHeader.h + +#ifndef __ARCHIVE_TAR_HEADER_H +#define __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 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. */ + } + + 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 kUsTar_00[8]; + } +} + +}} + +#endif diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp index 3ef2ff8cc..327616585 100644 --- a/CPP/7zip/Archive/Tar/TarIn.cpp +++ b/CPP/7zip/Archive/Tar/TarIn.cpp @@ -1,502 +1,502 @@ -// TarIn.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/StringToInt.h" - -#include "../../Common/StreamUtils.h" - -#include "../IArchive.h" - -#include "TarIn.h" - -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, unsigned size, UInt32 &res, bool allowEmpty = false) -{ - UInt64 res64; - if (!OctalToNumber(srcString, size, res64, allowEmpty)) - return false; - res = (UInt32)res64; - return (res64 <= 0xFFFFFFFF); -} - -#define RIF(x) { if (!(x)) return S_OK; } - -/* -static bool IsEmptyData(const char *buf, size_t size) -{ - for (unsigned i = 0; i < size; i++) - if (buf[i] != 0) - return false; - return true; -} -*/ - -static bool IsRecordLast(const char *buf) -{ - for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) - if (buf[i] != 0) - return false; - return true; -} - -static void ReadString(const char *s, unsigned size, AString &result) -{ - char temp[NFileHeader::kRecordSize + 1]; - MyStrNCpy(temp, s, size); - temp[size] = '\0'; - result = temp; -} - -static bool ParseInt64(const char *p, Int64 &val) -{ - UInt32 h = GetBe32(p); - val = GetBe64(p + 4); - if (h == (UInt32)1 << 31) - return ((val >> 63) & 1) == 0; - if (h == (UInt32)(Int32)-1) - return ((val >> 63) & 1) != 0; - UInt64 uv; - bool res = OctalToNumber(p, 12, uv); - val = uv; - return res; -} - -static bool ParseInt64_MTime(const char *p, Int64 &val) -{ - // rare case tar : ZEROs in Docker-Windows TARs - // rare case tar : spaces - if (GetUi32(p) != 0) - for (unsigned i = 0; i < 12; i++) - if (p[i] != ' ') - return ParseInt64(p, val); - val = 0; - return true; -} - -static bool ParseSize(const char *p, UInt64 &val) -{ - if (GetBe32(p) == (UInt32)1 << 31) - { - // GNU extension - val = GetBe64(p + 4); - return ((val >> 63) & 1) == 0; - } - return OctalToNumber(p, 12, val); -} - -#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, 8, mode, true)); p += 8; - - // if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; - p += 8; - // if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; - p += 8; - - UInt64 packSize; - Int64 time; - UInt32 checkSum; - CHECK(ParseSize(p, packSize)); p += 12; - CHECK(ParseInt64_MTime(p, time)); p += 12; - CHECK(OctalToNumber32(p, 8, checkSum)); - return k_IsArc_Res_YES; -} - -static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error) -{ - char buf[NFileHeader::kRecordSize]; - char *p = buf; - - error = k_ErrorType_OK; - filled = false; - - bool thereAreEmptyRecords = false; - for (;;) - { - size_t processedSize = NFileHeader::kRecordSize; - RINOK(ReadStream(stream, 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 (!IsRecordLast(buf)) - break; - item.HeaderSize += NFileHeader::kRecordSize; - thereAreEmptyRecords = true; - } - if (thereAreEmptyRecords) - { - // error = "There are data after end of archive"; - return S_OK; - } - - error = k_ErrorType_Corrupted; - ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize; - item.NameCouldBeReduced = - (item.Name.Len() == NFileHeader::kNameSize || - item.Name.Len() == NFileHeader::kNameSize - 1); - - // we allow empty Mode value for LongName prefix items - RIF(OctalToNumber32(p, 8, item.Mode, true)); p += 8; - - if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; p += 8; - if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; p += 8; - - RIF(ParseSize(p, item.PackSize)); - item.Size = item.PackSize; - p += 12; - RIF(ParseInt64_MTime(p, item.MTime)); p += 12; - - UInt32 checkSum; - RIF(OctalToNumber32(p, 8, checkSum)); - memset(p, ' ', 8); p += 8; - - item.LinkFlag = *p++; - - ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize; - item.LinkNameCouldBeReduced = - (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.DeviceMajorDefined = (p[0] != 0); if (item.DeviceMajorDefined) { RIF(OctalToNumber32(p, 8, item.DeviceMajor)); } p += 8; - item.DeviceMinorDefined = (p[0] != 0); if (item.DeviceMinorDefined) { RIF(OctalToNumber32(p, 8, item.DeviceMinor)); } p += 8; - - if (p[0] != 0) - { - AString prefix; - ReadString(p, NFileHeader::kPrefixSize, prefix); - if (!prefix.IsEmpty() - && item.IsUstarMagic() - && (item.LinkFlag != 'L' /* || prefix != "00000000000" */ )) - item.Name = prefix + '/' + item.Name; - } - - p += NFileHeader::kPrefixSize; - - if (item.LinkFlag == NFileHeader::NLinkFlag::kHardLink) - { - item.PackSize = 0; - item.Size = 0; - } - /* - TAR standard requires sum of unsigned byte values. - But some TAR programs use sum of signed byte values. - So we check both values. - */ - UInt32 checkSumReal = 0; - Int32 checkSumReal_Signed = 0; - for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) - { - char c = buf[i]; - checkSumReal_Signed += (signed char)c; - checkSumReal += (Byte)buf[i]; - } - - if (checkSumReal != checkSum) - { - if ((UInt32)checkSumReal_Signed != checkSum) - return S_OK; - } - - item.HeaderSize += NFileHeader::kRecordSize; - - if (item.LinkFlag == NFileHeader::NLinkFlag::kSparse) - { - Byte isExtended = buf[482]; - if (isExtended != 0 && isExtended != 1) - return S_OK; - RIF(ParseSize(buf + 483, item.Size)); - 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(stream, buf, &processedSize)); - if (processedSize != NFileHeader::kRecordSize) - { - error = k_ErrorType_UnexpectedEnd; - return S_OK; - } - - item.HeaderSize += NFileHeader::kRecordSize; - isExtended = 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; - } - - filled = true; - error = k_ErrorType_OK; - return S_OK; -} - - -static HRESULT ReadDataToString(ISequentialInStream *stream, CItemEx &item, AString &s, EErrorType &error) -{ - const unsigned packSize = (unsigned)item.GetPackSizeAligned(); - size_t processedSize = packSize; - HRESULT res = ReadStream(stream, s.GetBuf(packSize), &processedSize); - item.HeaderSize += (unsigned)processedSize; - s.ReleaseBuf_CalcLen((unsigned)item.PackSize); - RINOK(res); - if (processedSize != packSize) - error = k_ErrorType_UnexpectedEnd; - return S_OK; -} - -static bool ParsePaxLongName(const AString &src, AString &dest) -{ - dest.Empty(); - for (unsigned pos = 0;;) - { - if (pos >= src.Len()) - return false; - const char *start = src.Ptr(pos); - const char *end; - const UInt32 lineLen = ConvertStringToUInt32(start, &end); - if (end == start) - return false; - if (*end != ' ') - return false; - if (lineLen > src.Len() - pos) - return false; - unsigned offset = (unsigned)(end - start) + 1; - if (lineLen < offset) - return false; - if (IsString1PrefixedByString2(src.Ptr(pos + offset), "path=")) - { - offset += 5; // "path=" - dest = src.Mid(pos + offset, lineLen - offset); - if (dest.IsEmpty()) - return false; - if (dest.Back() != '\n') - return false; - dest.DeleteBack(); - return true; - } - pos += lineLen; - } -} - -HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error) -{ - item.HeaderSize = 0; - - bool flagL = false; - bool flagK = false; - AString nameL; - AString nameK; - AString pax; - - for (;;) - { - RINOK(GetNextItemReal(stream, filled, item, error)); - if (!filled) - { - if (error == k_ErrorType_OK && (flagL || flagK)) - error = k_ErrorType_Corrupted; - return S_OK; - } - - if (error != k_ErrorType_OK) - return S_OK; - - if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName || // file contains a long name - item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongLink) // file contains a long linkname - { - AString *name; - if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName) - { if (flagL) return S_OK; flagL = true; name = &nameL; } - else - { if (flagK) return S_OK; flagK = true; name = &nameK; } - - if (item.Name != NFileHeader::kLongLink && - item.Name != NFileHeader::kLongLink2) - return S_OK; - if (item.PackSize > (1 << 14)) - return S_OK; - - RINOK(ReadDataToString(stream, item, *name, error)); - if (error != k_ErrorType_OK) - return S_OK; - - continue; - } - - switch (item.LinkFlag) - { - case 'g': - case 'x': - case 'X': - { - // pax Extended Header - if (item.Name.IsPrefixedBy("PaxHeader/") - || item.Name.Find("PaxHeaders.4467/") >= 0) - { - RINOK(ReadDataToString(stream, item, pax, error)); - if (error != k_ErrorType_OK) - return S_OK; - continue; - } - break; - } - case NFileHeader::NLinkFlag::kDumpDir: - { - break; - // GNU Extensions to the Archive Format - } - case NFileHeader::NLinkFlag::kSparse: - { - break; - // GNU Extensions to the Archive Format - } - default: - if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0)) - return S_OK; - } - - if (flagL) - { - item.Name = nameL; - item.NameCouldBeReduced = false; - } - - if (flagK) - { - item.LinkName = nameK; - item.LinkNameCouldBeReduced = false; - } - - error = k_ErrorType_OK; - - if (!pax.IsEmpty()) - { - AString name; - if (ParsePaxLongName(pax, name)) - item.Name = name; - else - { - // no "path" property is allowed in pax4467 - // error = k_ErrorType_Warning; - } - pax.Empty(); - } - - return S_OK; - } -} - -}} +// TarIn.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/StringToInt.h" + +#include "../../Common/StreamUtils.h" + +#include "../IArchive.h" + +#include "TarIn.h" + +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, unsigned size, UInt32 &res, bool allowEmpty = false) +{ + UInt64 res64; + if (!OctalToNumber(srcString, size, res64, allowEmpty)) + return false; + res = (UInt32)res64; + return (res64 <= 0xFFFFFFFF); +} + +#define RIF(x) { if (!(x)) return S_OK; } + +/* +static bool IsEmptyData(const char *buf, size_t size) +{ + for (unsigned i = 0; i < size; i++) + if (buf[i] != 0) + return false; + return true; +} +*/ + +static bool IsRecordLast(const char *buf) +{ + for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) + if (buf[i] != 0) + return false; + return true; +} + +static void ReadString(const char *s, unsigned size, AString &result) +{ + char temp[NFileHeader::kRecordSize + 1]; + MyStrNCpy(temp, s, size); + temp[size] = '\0'; + result = temp; +} + +static bool ParseInt64(const char *p, Int64 &val) +{ + UInt32 h = GetBe32(p); + val = GetBe64(p + 4); + if (h == (UInt32)1 << 31) + return ((val >> 63) & 1) == 0; + if (h == (UInt32)(Int32)-1) + return ((val >> 63) & 1) != 0; + UInt64 uv; + bool res = OctalToNumber(p, 12, uv); + val = uv; + return res; +} + +static bool ParseInt64_MTime(const char *p, Int64 &val) +{ + // rare case tar : ZEROs in Docker-Windows TARs + // rare case tar : spaces + if (GetUi32(p) != 0) + for (unsigned i = 0; i < 12; i++) + if (p[i] != ' ') + return ParseInt64(p, val); + val = 0; + return true; +} + +static bool ParseSize(const char *p, UInt64 &val) +{ + if (GetBe32(p) == (UInt32)1 << 31) + { + // GNU extension + val = GetBe64(p + 4); + return ((val >> 63) & 1) == 0; + } + return OctalToNumber(p, 12, val); +} + +#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, 8, mode, true)); p += 8; + + // if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; + p += 8; + // if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; + p += 8; + + UInt64 packSize; + Int64 time; + UInt32 checkSum; + CHECK(ParseSize(p, packSize)); p += 12; + CHECK(ParseInt64_MTime(p, time)); p += 12; + CHECK(OctalToNumber32(p, 8, checkSum)); + return k_IsArc_Res_YES; +} + +static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error) +{ + char buf[NFileHeader::kRecordSize]; + char *p = buf; + + error = k_ErrorType_OK; + filled = false; + + bool thereAreEmptyRecords = false; + for (;;) + { + size_t processedSize = NFileHeader::kRecordSize; + RINOK(ReadStream(stream, 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 (!IsRecordLast(buf)) + break; + item.HeaderSize += NFileHeader::kRecordSize; + thereAreEmptyRecords = true; + } + if (thereAreEmptyRecords) + { + // error = "There are data after end of archive"; + return S_OK; + } + + error = k_ErrorType_Corrupted; + ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize; + item.NameCouldBeReduced = + (item.Name.Len() == NFileHeader::kNameSize || + item.Name.Len() == NFileHeader::kNameSize - 1); + + // we allow empty Mode value for LongName prefix items + RIF(OctalToNumber32(p, 8, item.Mode, true)); p += 8; + + if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; p += 8; + if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; p += 8; + + RIF(ParseSize(p, item.PackSize)); + item.Size = item.PackSize; + p += 12; + RIF(ParseInt64_MTime(p, item.MTime)); p += 12; + + UInt32 checkSum; + RIF(OctalToNumber32(p, 8, checkSum)); + memset(p, ' ', 8); p += 8; + + item.LinkFlag = *p++; + + ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize; + item.LinkNameCouldBeReduced = + (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.DeviceMajorDefined = (p[0] != 0); if (item.DeviceMajorDefined) { RIF(OctalToNumber32(p, 8, item.DeviceMajor)); } p += 8; + item.DeviceMinorDefined = (p[0] != 0); if (item.DeviceMinorDefined) { RIF(OctalToNumber32(p, 8, item.DeviceMinor)); } p += 8; + + if (p[0] != 0) + { + AString prefix; + ReadString(p, NFileHeader::kPrefixSize, prefix); + if (!prefix.IsEmpty() + && item.IsUstarMagic() + && (item.LinkFlag != 'L' /* || prefix != "00000000000" */ )) + item.Name = prefix + '/' + item.Name; + } + + p += NFileHeader::kPrefixSize; + + if (item.LinkFlag == NFileHeader::NLinkFlag::kHardLink) + { + item.PackSize = 0; + item.Size = 0; + } + /* + TAR standard requires sum of unsigned byte values. + But some TAR programs use sum of signed byte values. + So we check both values. + */ + UInt32 checkSumReal = 0; + Int32 checkSumReal_Signed = 0; + for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) + { + char c = buf[i]; + checkSumReal_Signed += (signed char)c; + checkSumReal += (Byte)buf[i]; + } + + if (checkSumReal != checkSum) + { + if ((UInt32)checkSumReal_Signed != checkSum) + return S_OK; + } + + item.HeaderSize += NFileHeader::kRecordSize; + + if (item.LinkFlag == NFileHeader::NLinkFlag::kSparse) + { + Byte isExtended = buf[482]; + if (isExtended != 0 && isExtended != 1) + return S_OK; + RIF(ParseSize(buf + 483, item.Size)); + 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(stream, buf, &processedSize)); + if (processedSize != NFileHeader::kRecordSize) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + + item.HeaderSize += NFileHeader::kRecordSize; + isExtended = 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; + } + + filled = true; + error = k_ErrorType_OK; + return S_OK; +} + + +static HRESULT ReadDataToString(ISequentialInStream *stream, CItemEx &item, AString &s, EErrorType &error) +{ + const unsigned packSize = (unsigned)item.GetPackSizeAligned(); + size_t processedSize = packSize; + HRESULT res = ReadStream(stream, s.GetBuf(packSize), &processedSize); + item.HeaderSize += (unsigned)processedSize; + s.ReleaseBuf_CalcLen((unsigned)item.PackSize); + RINOK(res); + if (processedSize != packSize) + error = k_ErrorType_UnexpectedEnd; + return S_OK; +} + +static bool ParsePaxLongName(const AString &src, AString &dest) +{ + dest.Empty(); + for (unsigned pos = 0;;) + { + if (pos >= src.Len()) + return false; + const char *start = src.Ptr(pos); + const char *end; + const UInt32 lineLen = ConvertStringToUInt32(start, &end); + if (end == start) + return false; + if (*end != ' ') + return false; + if (lineLen > src.Len() - pos) + return false; + unsigned offset = (unsigned)(end - start) + 1; + if (lineLen < offset) + return false; + if (IsString1PrefixedByString2(src.Ptr(pos + offset), "path=")) + { + offset += 5; // "path=" + dest = src.Mid(pos + offset, lineLen - offset); + if (dest.IsEmpty()) + return false; + if (dest.Back() != '\n') + return false; + dest.DeleteBack(); + return true; + } + pos += lineLen; + } +} + +HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error) +{ + item.HeaderSize = 0; + + bool flagL = false; + bool flagK = false; + AString nameL; + AString nameK; + AString pax; + + for (;;) + { + RINOK(GetNextItemReal(stream, filled, item, error)); + if (!filled) + { + if (error == k_ErrorType_OK && (flagL || flagK)) + error = k_ErrorType_Corrupted; + return S_OK; + } + + if (error != k_ErrorType_OK) + return S_OK; + + if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName || // file contains a long name + item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongLink) // file contains a long linkname + { + AString *name; + if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName) + { if (flagL) return S_OK; flagL = true; name = &nameL; } + else + { if (flagK) return S_OK; flagK = true; name = &nameK; } + + if (item.Name != NFileHeader::kLongLink && + item.Name != NFileHeader::kLongLink2) + return S_OK; + if (item.PackSize > (1 << 14)) + return S_OK; + + RINOK(ReadDataToString(stream, item, *name, error)); + if (error != k_ErrorType_OK) + return S_OK; + + continue; + } + + switch (item.LinkFlag) + { + case 'g': + case 'x': + case 'X': + { + // pax Extended Header + if (item.Name.IsPrefixedBy("PaxHeader/") + || item.Name.Find("PaxHeaders.4467/") >= 0) + { + RINOK(ReadDataToString(stream, item, pax, error)); + if (error != k_ErrorType_OK) + return S_OK; + continue; + } + break; + } + case NFileHeader::NLinkFlag::kDumpDir: + { + break; + // GNU Extensions to the Archive Format + } + case NFileHeader::NLinkFlag::kSparse: + { + break; + // GNU Extensions to the Archive Format + } + default: + if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0)) + return S_OK; + } + + if (flagL) + { + item.Name = nameL; + item.NameCouldBeReduced = false; + } + + if (flagK) + { + item.LinkName = nameK; + item.LinkNameCouldBeReduced = false; + } + + error = k_ErrorType_OK; + + if (!pax.IsEmpty()) + { + AString name; + if (ParsePaxLongName(pax, name)) + item.Name = name; + else + { + // no "path" property is allowed in pax4467 + // error = k_ErrorType_Warning; + } + pax.Empty(); + } + + return S_OK; + } +} + +}} diff --git a/CPP/7zip/Archive/Tar/TarIn.h b/CPP/7zip/Archive/Tar/TarIn.h index bc650f579..1c508bcce 100644 --- a/CPP/7zip/Archive/Tar/TarIn.h +++ b/CPP/7zip/Archive/Tar/TarIn.h @@ -1,27 +1,27 @@ -// TarIn.h - -#ifndef __ARCHIVE_TAR_IN_H -#define __ARCHIVE_TAR_IN_H - -#include "../../IStream.h" - -#include "TarItem.h" - -namespace NArchive { -namespace NTar { - -enum EErrorType -{ - k_ErrorType_OK, - k_ErrorType_Corrupted, - k_ErrorType_UnexpectedEnd, - k_ErrorType_Warning -}; - -HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, EErrorType &error); - -API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size); - -}} - -#endif +// TarIn.h + +#ifndef __ARCHIVE_TAR_IN_H +#define __ARCHIVE_TAR_IN_H + +#include "../../IStream.h" + +#include "TarItem.h" + +namespace NArchive { +namespace NTar { + +enum EErrorType +{ + k_ErrorType_OK, + k_ErrorType_Corrupted, + k_ErrorType_UnexpectedEnd, + k_ErrorType_Warning +}; + +HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, EErrorType &error); + +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 index 26966a3d6..bc3b40847 100644 --- a/CPP/7zip/Archive/Tar/TarItem.h +++ b/CPP/7zip/Archive/Tar/TarItem.h @@ -1,126 +1,126 @@ -// TarItem.h - -#ifndef __ARCHIVE_TAR_ITEM_H -#define __ARCHIVE_TAR_ITEM_H - -#include "../../../Common/MyLinux.h" - -#include "../Common/ItemNameUtils.h" - -#include "TarHeader.h" - -namespace NArchive { -namespace NTar { - -struct CSparseBlock -{ - UInt64 Offset; - UInt64 Size; -}; - -struct CItem -{ - AString Name; - UInt64 PackSize; - UInt64 Size; - Int64 MTime; - - UInt32 Mode; - UInt32 UID; - UInt32 GID; - UInt32 DeviceMajor; - UInt32 DeviceMinor; - - AString LinkName; - AString User; - AString Group; - - char Magic[8]; - char LinkFlag; - bool DeviceMajorDefined; - bool DeviceMinorDefined; - - CRecordVector SparseBlocks; - - bool IsSymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); } - bool IsHardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; } - bool IsSparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; } - UInt64 GetUnpackSize() const { return IsSymLink() ? LinkName.Len() : Size; } - bool IsPaxExtendedHeader() const - { - switch (LinkFlag) - { - case 'g': - case 'x': - case 'X': // Check it - return true; - } - return false; - } - - UInt32 Get_Combined_Mode() const - { - return (Mode & ~(UInt32)MY_LIN_S_IFMT) | Get_FileTypeMode_from_LinkFlag(); - } - - 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: - return NItemName::HasTailSlash(Name, CP_OEMCP); - } - return false; - } - - bool IsUstarMagic() const - { - for (int i = 0; i < 5; i++) - if (Magic[i] != NFileHeader::NMagic::kUsTar_00[i]) - return false; - return true; - } - - UInt64 GetPackSizeAligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); } -}; - -struct CItemEx: public CItem -{ - UInt64 HeaderPos; - unsigned HeaderSize; - bool NameCouldBeReduced; - bool LinkNameCouldBeReduced; - - UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; } - UInt64 GetFullSize() const { return HeaderSize + PackSize; } -}; - -}} - -#endif +// TarItem.h + +#ifndef __ARCHIVE_TAR_ITEM_H +#define __ARCHIVE_TAR_ITEM_H + +#include "../../../Common/MyLinux.h" + +#include "../Common/ItemNameUtils.h" + +#include "TarHeader.h" + +namespace NArchive { +namespace NTar { + +struct CSparseBlock +{ + UInt64 Offset; + UInt64 Size; +}; + +struct CItem +{ + AString Name; + UInt64 PackSize; + UInt64 Size; + Int64 MTime; + + UInt32 Mode; + UInt32 UID; + UInt32 GID; + UInt32 DeviceMajor; + UInt32 DeviceMinor; + + AString LinkName; + AString User; + AString Group; + + char Magic[8]; + char LinkFlag; + bool DeviceMajorDefined; + bool DeviceMinorDefined; + + CRecordVector SparseBlocks; + + bool IsSymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); } + bool IsHardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; } + bool IsSparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; } + UInt64 GetUnpackSize() const { return IsSymLink() ? LinkName.Len() : Size; } + bool IsPaxExtendedHeader() const + { + switch (LinkFlag) + { + case 'g': + case 'x': + case 'X': // Check it + return true; + } + return false; + } + + UInt32 Get_Combined_Mode() const + { + return (Mode & ~(UInt32)MY_LIN_S_IFMT) | Get_FileTypeMode_from_LinkFlag(); + } + + 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: + return NItemName::HasTailSlash(Name, CP_OEMCP); + } + return false; + } + + bool IsUstarMagic() const + { + for (int i = 0; i < 5; i++) + if (Magic[i] != NFileHeader::NMagic::kUsTar_00[i]) + return false; + return true; + } + + UInt64 GetPackSizeAligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); } +}; + +struct CItemEx: public CItem +{ + UInt64 HeaderPos; + unsigned HeaderSize; + bool NameCouldBeReduced; + bool LinkNameCouldBeReduced; + + UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; } + UInt64 GetFullSize() const { return HeaderSize + PackSize; } +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Tar/TarOut.cpp b/CPP/7zip/Archive/Tar/TarOut.cpp index bbce17449..51081e8b8 100644 --- a/CPP/7zip/Archive/Tar/TarOut.cpp +++ b/CPP/7zip/Archive/Tar/TarOut.cpp @@ -1,245 +1,245 @@ -// TarOut.cpp - -#include "StdAfx.h" - -#include "../../Common/StreamUtils.h" - -#include "TarOut.h" - -namespace NArchive { -namespace NTar { - -HRESULT COutArchive::WriteBytes(const void *data, unsigned size) -{ - Pos += size; - return WriteStream(m_Stream, data, size); -} - -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 WriteOctal_8(char *s, UInt32 val) -{ - const unsigned kNumDigits = 8 - 1; - if (val >= ((UInt32)1 << (kNumDigits * 3))) - return false; - for (unsigned i = 0; i < kNumDigits; i++) - { - s[kNumDigits - 1 - i] = (char)('0' + (val & 7)); - val >>= 3; - } - return true; -} - -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; - for (unsigned i = 0; i < 8; i++, val <<= 8) - s[4 + i] = (char)(val >> 56); - 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, Int64 val) -{ - if (val >= 0) - { - WriteOctal_12(s, val); - return; - } - s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF; - for (unsigned i = 0; i < 8; i++, val <<= 8) - s[4 + i] = (char)(val >> 56); -} - -static bool CopyString(char *dest, const AString &src, unsigned maxSize) -{ - if (src.Len() >= maxSize) - return false; - MyStringCopy(dest, (const char *)src); - return true; -} - -#define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_FAIL; } - -HRESULT COutArchive::WriteHeaderReal(const CItem &item) -{ - char record[NFileHeader::kRecordSize]; - memset(record, 0, NFileHeader::kRecordSize); - char *cur = record; - - if (item.Name.Len() > NFileHeader::kNameSize) - return E_FAIL; - MyStrNCpy(cur, item.Name, NFileHeader::kNameSize); - cur += NFileHeader::kNameSize; - - RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.Mode)); cur += 8; - RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.UID)); cur += 8; - RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.GID)); cur += 8; - - WriteOctal_12(cur, item.PackSize); cur += 12; - WriteOctal_12_Signed(cur, item.MTime); cur += 12; - - memset(cur, ' ', 8); - cur += 8; - - *cur++ = item.LinkFlag; - - RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize)); - cur += NFileHeader::kNameSize; - - memcpy(cur, item.Magic, 8); - cur += 8; - - RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize)); - cur += NFileHeader::kUserNameSize; - RETURN_IF_NOT_TRUE(CopyString(cur, item.Group, NFileHeader::kGroupNameSize)); - cur += NFileHeader::kGroupNameSize; - - - if (item.DeviceMajorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMajor)); cur += 8; - if (item.DeviceMinorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMinor)); cur += 8; - - if (item.IsSparse()) - { - 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 checkSum = 0; - { - for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) - checkSum += (Byte)record[i]; - } - /* we use GNU TAR scheme: - checksum field is formatted differently from the - other fields: it has [6] digits, a null, then a space. */ - // RETURN_IF_NOT_TRUE(WriteOctal_8(record + 148, checkSum)); - const unsigned kNumDigits = 6; - for (unsigned i = 0; i < kNumDigits; i++) - { - record[148 + kNumDigits - 1 - i] = (char)('0' + (checkSum & 7)); - checkSum >>= 3; - } - record[148 + 6] = 0; - } - - RINOK(WriteBytes(record, NFileHeader::kRecordSize)); - - if (item.IsSparse()) - { - for (unsigned i = 4; i < item.SparseBlocks.Size();) - { - memset(record, 0, NFileHeader::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(WriteBytes(record, NFileHeader::kRecordSize)); - } - } - - return S_OK; -} - -HRESULT COutArchive::WriteHeader(const CItem &item) -{ - unsigned nameSize = item.Name.Len(); - unsigned linkSize = item.LinkName.Len(); - - /* There two versions of GNU tar: - OLDGNU_FORMAT: it writes short name and zero at the end - GNU_FORMAT: it writes only short name without zero at the end - we write it as OLDGNU_FORMAT with zero at the end */ - - if (nameSize < NFileHeader::kNameSize && - linkSize < NFileHeader::kNameSize) - return WriteHeaderReal(item); - - CItem mi = item; - mi.Name = NFileHeader::kLongLink; - mi.LinkName.Empty(); - for (int 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 = NFileHeader::NLinkFlag::kGnu_LongLink; - name = &item.LinkName; - } - else - { - mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName; - name = &item.Name; - } - if (name->Len() < NFileHeader::kNameSize) - continue; - unsigned nameStreamSize = name->Len() + 1; - mi.PackSize = nameStreamSize; - RINOK(WriteHeaderReal(mi)); - RINOK(WriteBytes((const char *)*name, nameStreamSize)); - RINOK(FillDataResidual(nameStreamSize)); - } - - mi = item; - if (mi.Name.Len() >= NFileHeader::kNameSize) - mi.Name.SetFrom(item.Name, NFileHeader::kNameSize - 1); - if (mi.LinkName.Len() >= NFileHeader::kNameSize) - mi.LinkName.SetFrom(item.LinkName, NFileHeader::kNameSize - 1); - return WriteHeaderReal(mi); -} - -HRESULT COutArchive::FillDataResidual(UInt64 dataSize) -{ - unsigned lastRecordSize = ((unsigned)dataSize & (NFileHeader::kRecordSize - 1)); - if (lastRecordSize == 0) - return S_OK; - unsigned rem = NFileHeader::kRecordSize - lastRecordSize; - Byte buf[NFileHeader::kRecordSize]; - memset(buf, 0, rem); - return WriteBytes(buf, rem); -} - -HRESULT COutArchive::WriteFinishHeader() -{ - Byte record[NFileHeader::kRecordSize]; - memset(record, 0, NFileHeader::kRecordSize); - for (unsigned i = 0; i < 2; i++) - { - RINOK(WriteBytes(record, NFileHeader::kRecordSize)); - } - return S_OK; -} - -}} +// TarOut.cpp + +#include "StdAfx.h" + +#include "../../Common/StreamUtils.h" + +#include "TarOut.h" + +namespace NArchive { +namespace NTar { + +HRESULT COutArchive::WriteBytes(const void *data, unsigned size) +{ + Pos += size; + return WriteStream(m_Stream, data, size); +} + +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 WriteOctal_8(char *s, UInt32 val) +{ + const unsigned kNumDigits = 8 - 1; + if (val >= ((UInt32)1 << (kNumDigits * 3))) + return false; + for (unsigned i = 0; i < kNumDigits; i++) + { + s[kNumDigits - 1 - i] = (char)('0' + (val & 7)); + val >>= 3; + } + return true; +} + +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; + for (unsigned i = 0; i < 8; i++, val <<= 8) + s[4 + i] = (char)(val >> 56); + 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, Int64 val) +{ + if (val >= 0) + { + WriteOctal_12(s, val); + return; + } + s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF; + for (unsigned i = 0; i < 8; i++, val <<= 8) + s[4 + i] = (char)(val >> 56); +} + +static bool CopyString(char *dest, const AString &src, unsigned maxSize) +{ + if (src.Len() >= maxSize) + return false; + MyStringCopy(dest, (const char *)src); + return true; +} + +#define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_FAIL; } + +HRESULT COutArchive::WriteHeaderReal(const CItem &item) +{ + char record[NFileHeader::kRecordSize]; + memset(record, 0, NFileHeader::kRecordSize); + char *cur = record; + + if (item.Name.Len() > NFileHeader::kNameSize) + return E_FAIL; + MyStrNCpy(cur, item.Name, NFileHeader::kNameSize); + cur += NFileHeader::kNameSize; + + RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.Mode)); cur += 8; + RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.UID)); cur += 8; + RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.GID)); cur += 8; + + WriteOctal_12(cur, item.PackSize); cur += 12; + WriteOctal_12_Signed(cur, item.MTime); cur += 12; + + memset(cur, ' ', 8); + cur += 8; + + *cur++ = item.LinkFlag; + + RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize)); + cur += NFileHeader::kNameSize; + + memcpy(cur, item.Magic, 8); + cur += 8; + + RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize)); + cur += NFileHeader::kUserNameSize; + RETURN_IF_NOT_TRUE(CopyString(cur, item.Group, NFileHeader::kGroupNameSize)); + cur += NFileHeader::kGroupNameSize; + + + if (item.DeviceMajorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMajor)); cur += 8; + if (item.DeviceMinorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMinor)); cur += 8; + + if (item.IsSparse()) + { + 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 checkSum = 0; + { + for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) + checkSum += (Byte)record[i]; + } + /* we use GNU TAR scheme: + checksum field is formatted differently from the + other fields: it has [6] digits, a null, then a space. */ + // RETURN_IF_NOT_TRUE(WriteOctal_8(record + 148, checkSum)); + const unsigned kNumDigits = 6; + for (unsigned i = 0; i < kNumDigits; i++) + { + record[148 + kNumDigits - 1 - i] = (char)('0' + (checkSum & 7)); + checkSum >>= 3; + } + record[148 + 6] = 0; + } + + RINOK(WriteBytes(record, NFileHeader::kRecordSize)); + + if (item.IsSparse()) + { + for (unsigned i = 4; i < item.SparseBlocks.Size();) + { + memset(record, 0, NFileHeader::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(WriteBytes(record, NFileHeader::kRecordSize)); + } + } + + return S_OK; +} + +HRESULT COutArchive::WriteHeader(const CItem &item) +{ + unsigned nameSize = item.Name.Len(); + unsigned linkSize = item.LinkName.Len(); + + /* There two versions of GNU tar: + OLDGNU_FORMAT: it writes short name and zero at the end + GNU_FORMAT: it writes only short name without zero at the end + we write it as OLDGNU_FORMAT with zero at the end */ + + if (nameSize < NFileHeader::kNameSize && + linkSize < NFileHeader::kNameSize) + return WriteHeaderReal(item); + + CItem mi = item; + mi.Name = NFileHeader::kLongLink; + mi.LinkName.Empty(); + for (int 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 = NFileHeader::NLinkFlag::kGnu_LongLink; + name = &item.LinkName; + } + else + { + mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName; + name = &item.Name; + } + if (name->Len() < NFileHeader::kNameSize) + continue; + unsigned nameStreamSize = name->Len() + 1; + mi.PackSize = nameStreamSize; + RINOK(WriteHeaderReal(mi)); + RINOK(WriteBytes((const char *)*name, nameStreamSize)); + RINOK(FillDataResidual(nameStreamSize)); + } + + mi = item; + if (mi.Name.Len() >= NFileHeader::kNameSize) + mi.Name.SetFrom(item.Name, NFileHeader::kNameSize - 1); + if (mi.LinkName.Len() >= NFileHeader::kNameSize) + mi.LinkName.SetFrom(item.LinkName, NFileHeader::kNameSize - 1); + return WriteHeaderReal(mi); +} + +HRESULT COutArchive::FillDataResidual(UInt64 dataSize) +{ + unsigned lastRecordSize = ((unsigned)dataSize & (NFileHeader::kRecordSize - 1)); + if (lastRecordSize == 0) + return S_OK; + unsigned rem = NFileHeader::kRecordSize - lastRecordSize; + Byte buf[NFileHeader::kRecordSize]; + memset(buf, 0, rem); + return WriteBytes(buf, rem); +} + +HRESULT COutArchive::WriteFinishHeader() +{ + Byte record[NFileHeader::kRecordSize]; + memset(record, 0, NFileHeader::kRecordSize); + for (unsigned i = 0; i < 2; i++) + { + RINOK(WriteBytes(record, NFileHeader::kRecordSize)); + } + return S_OK; +} + +}} diff --git a/CPP/7zip/Archive/Tar/TarOut.h b/CPP/7zip/Archive/Tar/TarOut.h index d9b8e03af..ee9b965ed 100644 --- a/CPP/7zip/Archive/Tar/TarOut.h +++ b/CPP/7zip/Archive/Tar/TarOut.h @@ -1,36 +1,36 @@ -// Archive/TarOut.h - -#ifndef __ARCHIVE_TAR_OUT_H -#define __ARCHIVE_TAR_OUT_H - -#include "../../../Common/MyCom.h" - -#include "../../IStream.h" - -#include "TarItem.h" - -namespace NArchive { -namespace NTar { - -class COutArchive -{ - CMyComPtr m_Stream; - - HRESULT WriteBytes(const void *data, unsigned size); - HRESULT WriteHeaderReal(const CItem &item); -public: - UInt64 Pos; - - void Create(ISequentialOutStream *outStream) - { - m_Stream = outStream; - } - - HRESULT WriteHeader(const CItem &item); - HRESULT FillDataResidual(UInt64 dataSize); - HRESULT WriteFinishHeader(); -}; - -}} - -#endif +// Archive/TarOut.h + +#ifndef __ARCHIVE_TAR_OUT_H +#define __ARCHIVE_TAR_OUT_H + +#include "../../../Common/MyCom.h" + +#include "../../IStream.h" + +#include "TarItem.h" + +namespace NArchive { +namespace NTar { + +class COutArchive +{ + CMyComPtr m_Stream; + + HRESULT WriteBytes(const void *data, unsigned size); + HRESULT WriteHeaderReal(const CItem &item); +public: + UInt64 Pos; + + void Create(ISequentialOutStream *outStream) + { + m_Stream = outStream; + } + + HRESULT WriteHeader(const CItem &item); + HRESULT FillDataResidual(UInt64 dataSize); + HRESULT WriteFinishHeader(); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Tar/TarRegister.cpp b/CPP/7zip/Archive/Tar/TarRegister.cpp index 8558b86c0..5014f04df 100644 --- a/CPP/7zip/Archive/Tar/TarRegister.cpp +++ b/CPP/7zip/Archive/Tar/TarRegister.cpp @@ -1,23 +1,23 @@ -// 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", 0, 0xEE, - k_Signature, - NFileHeader::kUstarMagic_Offset, - NArcInfoFlags::kStartOpen | - NArcInfoFlags::kSymLinks | - NArcInfoFlags::kHardLinks, - IsArc_Tar) - -}} +// 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", 0, 0xEE, + k_Signature, + NFileHeader::kUstarMagic_Offset, + NArcInfoFlags::kStartOpen | + NArcInfoFlags::kSymLinks | + NArcInfoFlags::kHardLinks, + IsArc_Tar) + +}} diff --git a/CPP/7zip/Archive/Tar/TarUpdate.cpp b/CPP/7zip/Archive/Tar/TarUpdate.cpp index 011aded2b..0cdb30d16 100644 --- a/CPP/7zip/Archive/Tar/TarUpdate.cpp +++ b/CPP/7zip/Archive/Tar/TarUpdate.cpp @@ -1,266 +1,266 @@ -// TarUpdate.cpp - -#include "StdAfx.h" - -#include "../../../Windows/TimeUtils.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/ProgressUtils.h" - -#include "../../Compress/CopyCoder.h" - -#include "TarOut.h" -#include "TarUpdate.h" - -namespace NArchive { -namespace NTar { - -HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, - AString &res, UINT codePage, bool convertSlash = false); - -HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, - const CObjectVector &inputItems, - const CObjectVector &updateItems, - UINT codePage, - IArchiveUpdateCallback *updateCallback) -{ - COutArchive outArchive; - outArchive.Create(outStream); - outArchive.Pos = 0; - - CMyComPtr outSeekStream; - outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream); - - CMyComPtr opCallback; - updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); - - 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[ui.IndexInArc].GetFullSize(); - } - - RINOK(updateCallback->SetTotal(complexity)); - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(updateCallback, true); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStreamLimited(streamSpec); - streamSpec->SetStream(inStream); - - complexity = 0; - - for (i = 0; i < updateItems.Size(); i++) - { - lps->InSize = lps->OutSize = complexity; - RINOK(lps->SetCur()); - - const CUpdateItem &ui = updateItems[i]; - CItem item; - - if (ui.NewProps) - { - item.Mode = ui.Mode; - item.Name = ui.Name; - item.User = ui.User; - item.Group = ui.Group; - - if (ui.IsDir) - { - item.LinkFlag = NFileHeader::NLinkFlag::kDirectory; - item.PackSize = 0; - } - else - { - item.LinkFlag = NFileHeader::NLinkFlag::kNormal; - item.PackSize = ui.Size; - } - - item.MTime = ui.MTime; - item.DeviceMajorDefined = false; - item.DeviceMinorDefined = false; - item.UID = 0; - item.GID = 0; - memcpy(item.Magic, NFileHeader::NMagic::kUsTar_00, 8); - } - else - item = inputItems[ui.IndexInArc]; - - AString symLink; - if (ui.NewData || ui.NewProps) - { - RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink, codePage, 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 fileInStream; - - bool needWrite = true; - - if (!symLink.IsEmpty()) - { - item.PackSize = 0; - item.Size = 0; - } - else - { - HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); - - if (res == S_FALSE) - needWrite = false; - else - { - RINOK(res); - - if (fileInStream) - { - CMyComPtr getProps; - fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); - if (getProps) - { - FILETIME mTime; - UInt64 size2; - if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK) - { - item.PackSize = size2; - item.Size = size2; - item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);; - } - } - } - else - { - item.PackSize = 0; - item.Size = 0; - } - - { - AString hardLink; - RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, codePage, true)); - if (!hardLink.IsEmpty()) - { - item.LinkFlag = NFileHeader::NLinkFlag::kHardLink; - item.LinkName = hardLink; - item.PackSize = 0; - item.Size = 0; - fileInStream.Release(); - } - } - } - } - - if (needWrite) - { - UInt64 fileHeaderStartPos = outArchive.Pos; - RINOK(outArchive.WriteHeader(item)); - if (fileInStream) - { - RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress)); - outArchive.Pos += copyCoderSpec->TotalSize; - if (copyCoderSpec->TotalSize != item.PackSize) - { - if (!outSeekStream) - return E_FAIL; - UInt64 backOffset = outArchive.Pos - fileHeaderStartPos; - RINOK(outSeekStream->Seek(-(Int64)backOffset, STREAM_SEEK_CUR, NULL)); - outArchive.Pos = fileHeaderStartPos; - item.PackSize = copyCoderSpec->TotalSize; - RINOK(outArchive.WriteHeader(item)); - RINOK(outSeekStream->Seek(item.PackSize, STREAM_SEEK_CUR, NULL)); - outArchive.Pos += item.PackSize; - } - RINOK(outArchive.FillDataResidual(item.PackSize)); - } - } - - complexity += item.PackSize; - RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); - } - else - { - const CItemEx &existItem = inputItems[ui.IndexInArc]; - UInt64 size; - - 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.DeviceMajorDefined = existItem.DeviceMajorDefined; - item.DeviceMinorDefined = existItem.DeviceMinorDefined; - item.DeviceMajor = existItem.DeviceMajor; - item.DeviceMinor = existItem.DeviceMinor; - item.UID = existItem.UID; - item.GID = existItem.GID; - - RINOK(outArchive.WriteHeader(item)); - RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL)); - size = existItem.PackSize; - } - else - { - RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL)); - size = existItem.GetFullSize(); - } - - streamSpec->Init(size); - - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc, - NUpdateNotifyOp::kReplicate)) - } - - RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); - if (copyCoderSpec->TotalSize != size) - return E_FAIL; - outArchive.Pos += size; - RINOK(outArchive.FillDataResidual(existItem.PackSize)); - complexity += size; - } - } - - lps->InSize = lps->OutSize = complexity; - RINOK(lps->SetCur()); - return outArchive.WriteFinishHeader(); -} - -}} +// TarUpdate.cpp + +#include "StdAfx.h" + +#include "../../../Windows/TimeUtils.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" + +#include "../../Compress/CopyCoder.h" + +#include "TarOut.h" +#include "TarUpdate.h" + +namespace NArchive { +namespace NTar { + +HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, + AString &res, UINT codePage, bool convertSlash = false); + +HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, + const CObjectVector &inputItems, + const CObjectVector &updateItems, + UINT codePage, + IArchiveUpdateCallback *updateCallback) +{ + COutArchive outArchive; + outArchive.Create(outStream); + outArchive.Pos = 0; + + CMyComPtr outSeekStream; + outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream); + + CMyComPtr opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + + 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[ui.IndexInArc].GetFullSize(); + } + + RINOK(updateCallback->SetTotal(complexity)); + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; + CMyComPtr copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(updateCallback, true); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStreamLimited(streamSpec); + streamSpec->SetStream(inStream); + + complexity = 0; + + for (i = 0; i < updateItems.Size(); i++) + { + lps->InSize = lps->OutSize = complexity; + RINOK(lps->SetCur()); + + const CUpdateItem &ui = updateItems[i]; + CItem item; + + if (ui.NewProps) + { + item.Mode = ui.Mode; + item.Name = ui.Name; + item.User = ui.User; + item.Group = ui.Group; + + if (ui.IsDir) + { + item.LinkFlag = NFileHeader::NLinkFlag::kDirectory; + item.PackSize = 0; + } + else + { + item.LinkFlag = NFileHeader::NLinkFlag::kNormal; + item.PackSize = ui.Size; + } + + item.MTime = ui.MTime; + item.DeviceMajorDefined = false; + item.DeviceMinorDefined = false; + item.UID = 0; + item.GID = 0; + memcpy(item.Magic, NFileHeader::NMagic::kUsTar_00, 8); + } + else + item = inputItems[ui.IndexInArc]; + + AString symLink; + if (ui.NewData || ui.NewProps) + { + RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink, codePage, 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 fileInStream; + + bool needWrite = true; + + if (!symLink.IsEmpty()) + { + item.PackSize = 0; + item.Size = 0; + } + else + { + HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); + + if (res == S_FALSE) + needWrite = false; + else + { + RINOK(res); + + if (fileInStream) + { + CMyComPtr getProps; + fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); + if (getProps) + { + FILETIME mTime; + UInt64 size2; + if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK) + { + item.PackSize = size2; + item.Size = size2; + item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);; + } + } + } + else + { + item.PackSize = 0; + item.Size = 0; + } + + { + AString hardLink; + RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, codePage, true)); + if (!hardLink.IsEmpty()) + { + item.LinkFlag = NFileHeader::NLinkFlag::kHardLink; + item.LinkName = hardLink; + item.PackSize = 0; + item.Size = 0; + fileInStream.Release(); + } + } + } + } + + if (needWrite) + { + UInt64 fileHeaderStartPos = outArchive.Pos; + RINOK(outArchive.WriteHeader(item)); + if (fileInStream) + { + RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress)); + outArchive.Pos += copyCoderSpec->TotalSize; + if (copyCoderSpec->TotalSize != item.PackSize) + { + if (!outSeekStream) + return E_FAIL; + UInt64 backOffset = outArchive.Pos - fileHeaderStartPos; + RINOK(outSeekStream->Seek(-(Int64)backOffset, STREAM_SEEK_CUR, NULL)); + outArchive.Pos = fileHeaderStartPos; + item.PackSize = copyCoderSpec->TotalSize; + RINOK(outArchive.WriteHeader(item)); + RINOK(outSeekStream->Seek(item.PackSize, STREAM_SEEK_CUR, NULL)); + outArchive.Pos += item.PackSize; + } + RINOK(outArchive.FillDataResidual(item.PackSize)); + } + } + + complexity += item.PackSize; + RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); + } + else + { + const CItemEx &existItem = inputItems[ui.IndexInArc]; + UInt64 size; + + 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.DeviceMajorDefined = existItem.DeviceMajorDefined; + item.DeviceMinorDefined = existItem.DeviceMinorDefined; + item.DeviceMajor = existItem.DeviceMajor; + item.DeviceMinor = existItem.DeviceMinor; + item.UID = existItem.UID; + item.GID = existItem.GID; + + RINOK(outArchive.WriteHeader(item)); + RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL)); + size = existItem.PackSize; + } + else + { + RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL)); + size = existItem.GetFullSize(); + } + + streamSpec->Init(size); + + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc, + NUpdateNotifyOp::kReplicate)) + } + + RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize != size) + return E_FAIL; + outArchive.Pos += size; + RINOK(outArchive.FillDataResidual(existItem.PackSize)); + complexity += size; + } + } + + lps->InSize = lps->OutSize = complexity; + RINOK(lps->SetCur()); + return outArchive.WriteFinishHeader(); +} + +}} diff --git a/CPP/7zip/Archive/Tar/TarUpdate.h b/CPP/7zip/Archive/Tar/TarUpdate.h index d197aff7e..b758635f1 100644 --- a/CPP/7zip/Archive/Tar/TarUpdate.h +++ b/CPP/7zip/Archive/Tar/TarUpdate.h @@ -1,38 +1,38 @@ -// TarUpdate.h - -#ifndef __TAR_UPDATE_H -#define __TAR_UPDATE_H - -#include "../IArchive.h" - -#include "TarItem.h" - -namespace NArchive { -namespace NTar { - -struct CUpdateItem -{ - int IndexInArc; - int IndexInClient; - UInt64 Size; - Int64 MTime; - UInt32 Mode; - bool NewData; - bool NewProps; - bool IsDir; - AString Name; - AString User; - AString Group; - - CUpdateItem(): Size(0), IsDir(false) {} -}; - -HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, - const CObjectVector &inputItems, - const CObjectVector &updateItems, - UINT codePage, - IArchiveUpdateCallback *updateCallback); - -}} - -#endif +// TarUpdate.h + +#ifndef __TAR_UPDATE_H +#define __TAR_UPDATE_H + +#include "../IArchive.h" + +#include "TarItem.h" + +namespace NArchive { +namespace NTar { + +struct CUpdateItem +{ + int IndexInArc; + int IndexInClient; + UInt64 Size; + Int64 MTime; + UInt32 Mode; + bool NewData; + bool NewProps; + bool IsDir; + AString Name; + AString User; + AString Group; + + CUpdateItem(): Size(0), IsDir(false) {} +}; + +HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, + const CObjectVector &inputItems, + const CObjectVector &updateItems, + UINT codePage, + IArchiveUpdateCallback *updateCallback); + +}} + +#endif diff --git a/CPP/7zip/Archive/Udf/StdAfx.h b/CPP/7zip/Archive/Udf/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Archive/Udf/StdAfx.h +++ b/CPP/7zip/Archive/Udf/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/Udf/UdfHandler.cpp b/CPP/7zip/Archive/Udf/UdfHandler.cpp index 60cfe4ace..74ec0beb4 100644 --- a/CPP/7zip/Archive/Udf/UdfHandler.cpp +++ b/CPP/7zip/Archive/Udf/UdfHandler.cpp @@ -1,376 +1,376 @@ -// 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 -= (Int64)((Int32)t.GetMinutesOffset() * 60); - FILETIME ft; - UInt64 v = (((numSecs * 100 + d[9]) * 100 + d[10]) * 100 + d[11]) * 10; - ft.dwLowDateTime = (UInt32)v; - ft.dwHighDateTime = (UInt32)(v >> 32); - prop = ft; -} - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - kpidATime -}; - -static const Byte kArcProps[] = -{ - kpidComment, - kpidClusterSize, - kpidCTime -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: prop = _archive.PhySize; 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 kpidCTime: - if (_archive.LogVols.Size() == 1) - { - const CLogVol &vol = _archive.LogVols[0]; - if (vol.FileSets.Size() >= 1) - UdfTimeToFileTime(vol.FileSets[0].RecodringTime, 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: public CProgressVirt -{ - CMyComPtr _callback; - UInt64 _numFiles; - UInt64 _numBytes; -public: - HRESULT SetTotal(UInt64 numBytes); - HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes); - HRESULT SetCompleted(); - CProgressImp(IArchiveOpenCallback *callback): _callback(callback), _numFiles(0), _numBytes(0) {} -}; - -HRESULT CProgressImp::SetTotal(UInt64 numBytes) -{ - if (_callback) - return _callback->SetTotal(NULL, &numBytes); - return S_OK; -} - -HRESULT CProgressImp::SetCompleted(UInt64 numFiles, UInt64 numBytes) -{ - _numFiles = numFiles; - _numBytes = numBytes; - return SetCompleted(); -} - -HRESULT CProgressImp::SetCompleted() -{ - if (_callback) - return _callback->SetCompleted(&_numFiles, &_numBytes); - return S_OK; -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, 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); - 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 -} - -STDMETHODIMP CHandler::Close() -{ - _inStream.Release(); - _archive.Clear(); - _refs2.Clear(); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _refs2.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - { - const CRef2 &ref2 = _refs2[index]; - const CLogVol &vol = _archive.LogVols[ref2.Vol]; - const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref]; - const CFile &file = _archive.Files[ref.FileIndex]; - const CItem &item = _archive.Items[file.ItemIndex]; - switch (propID) - { - case kpidPath: prop = _archive.GetItemPath(ref2.Vol, ref2.Fs, ref2.Ref, - _archive.LogVols.Size() > 1, vol.FileSets.Size() > 1); break; - case kpidIsDir: prop = item.IsDir(); break; - case kpidSize: if (!item.IsDir()) prop = (UInt64)item.Size; break; - case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break; - case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break; - case kpidATime: UdfTimeToFileTime(item.ATime, prop); break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - *stream = 0; - - const CRef2 &ref2 = _refs2[index]; - const CLogVol &vol = _archive.LogVols[ref2.Vol]; - const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref]; - const CFile &file = _archive.Files[ref.FileIndex]; - const CItem &item = _archive.Items[file.ItemIndex]; - UInt64 size = item.Size; - - if (!item.IsRecAndAlloc() || !item.CheckChunkSizes() || ! _archive.CheckItemExtents(ref2.Vol, item)) - return E_NOTIMPL; - - if (item.IsInline) - { - Create_BufInStream_WithNewBuffer(item.InlineData, stream); - return S_OK; - } - - CExtentsStream *extentStreamSpec = new CExtentsStream(); - CMyComPtr 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; - - int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; - UInt32 logBlockNumber = extent.Pos; - const CPartition &partition = _archive.Partitions[partitionIndex]; - UInt64 offset = ((UInt64)partition.Pos << _archive.SecLogSize) + - (UInt64)logBlockNumber * vol.BlockSize; - - CSeekExtent se; - se.Phy = offset; - se.Virt = virtOffset; - virtOffset += len; - extentStreamSpec->Extents.Add(se); - - size -= len; - } - if (size != 0) - return S_FALSE; - CSeekExtent se; - se.Phy = 0; - se.Virt = virtOffset; - extentStreamSpec->Extents.Add(se); - extentStreamSpec->Init(); - *stream = extentStream.Detach(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; - CMyComPtr outStream(outStreamSpec); - - for (i = 0; i < numItems; i++) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()); - CMyComPtr realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - UInt32 index = allFilesMode ? i : indices[i]; - - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - - const CRef2 &ref2 = _refs2[index]; - const CRef &ref = _archive.LogVols[ref2.Vol].FileSets[ref2.Fs].Refs[ref2.Ref]; - const CFile &file = _archive.Files[ref.FileIndex]; - const CItem &item = _archive.Items[file.ItemIndex]; - - if (item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - currentTotalSize += item.Size; - - if (!testMode && !realOutStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)); - outStreamSpec->SetStream(realOutStream); - realOutStream.Release(); - outStreamSpec->Init(item.Size); - Int32 opRes; - CMyComPtr 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[] = { 1, 'C', 'D', '0', '0', '1' }; - -REGISTER_ARC_I( - "Udf", "udf iso img", 0, 0xE0, - k_Signature, - kIsoStartPos, - NArcInfoFlags::kStartOpen, - IsArc_Udf) - -}} +// 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 -= (Int64)((Int32)t.GetMinutesOffset() * 60); + FILETIME ft; + UInt64 v = (((numSecs * 100 + d[9]) * 100 + d[10]) * 100 + d[11]) * 10; + ft.dwLowDateTime = (UInt32)v; + ft.dwHighDateTime = (UInt32)(v >> 32); + prop = ft; +} + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidATime +}; + +static const Byte kArcProps[] = +{ + kpidComment, + kpidClusterSize, + kpidCTime +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: prop = _archive.PhySize; 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 kpidCTime: + if (_archive.LogVols.Size() == 1) + { + const CLogVol &vol = _archive.LogVols[0]; + if (vol.FileSets.Size() >= 1) + UdfTimeToFileTime(vol.FileSets[0].RecodringTime, 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: public CProgressVirt +{ + CMyComPtr _callback; + UInt64 _numFiles; + UInt64 _numBytes; +public: + HRESULT SetTotal(UInt64 numBytes); + HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes); + HRESULT SetCompleted(); + CProgressImp(IArchiveOpenCallback *callback): _callback(callback), _numFiles(0), _numBytes(0) {} +}; + +HRESULT CProgressImp::SetTotal(UInt64 numBytes) +{ + if (_callback) + return _callback->SetTotal(NULL, &numBytes); + return S_OK; +} + +HRESULT CProgressImp::SetCompleted(UInt64 numFiles, UInt64 numBytes) +{ + _numFiles = numFiles; + _numBytes = numBytes; + return SetCompleted(); +} + +HRESULT CProgressImp::SetCompleted() +{ + if (_callback) + return _callback->SetCompleted(&_numFiles, &_numBytes); + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, 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); + 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 +} + +STDMETHODIMP CHandler::Close() +{ + _inStream.Release(); + _archive.Clear(); + _refs2.Clear(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _refs2.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + { + const CRef2 &ref2 = _refs2[index]; + const CLogVol &vol = _archive.LogVols[ref2.Vol]; + const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref]; + const CFile &file = _archive.Files[ref.FileIndex]; + const CItem &item = _archive.Items[file.ItemIndex]; + switch (propID) + { + case kpidPath: prop = _archive.GetItemPath(ref2.Vol, ref2.Fs, ref2.Ref, + _archive.LogVols.Size() > 1, vol.FileSets.Size() > 1); break; + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: if (!item.IsDir()) prop = (UInt64)item.Size; break; + case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break; + case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break; + case kpidATime: UdfTimeToFileTime(item.ATime, prop); break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + *stream = 0; + + const CRef2 &ref2 = _refs2[index]; + const CLogVol &vol = _archive.LogVols[ref2.Vol]; + const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref]; + const CFile &file = _archive.Files[ref.FileIndex]; + const CItem &item = _archive.Items[file.ItemIndex]; + UInt64 size = item.Size; + + if (!item.IsRecAndAlloc() || !item.CheckChunkSizes() || ! _archive.CheckItemExtents(ref2.Vol, item)) + return E_NOTIMPL; + + if (item.IsInline) + { + Create_BufInStream_WithNewBuffer(item.InlineData, stream); + return S_OK; + } + + CExtentsStream *extentStreamSpec = new CExtentsStream(); + CMyComPtr 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; + + int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; + UInt32 logBlockNumber = extent.Pos; + const CPartition &partition = _archive.Partitions[partitionIndex]; + UInt64 offset = ((UInt64)partition.Pos << _archive.SecLogSize) + + (UInt64)logBlockNumber * vol.BlockSize; + + CSeekExtent se; + se.Phy = offset; + se.Virt = virtOffset; + virtOffset += len; + extentStreamSpec->Extents.Add(se); + + size -= len; + } + if (size != 0) + return S_FALSE; + CSeekExtent se; + se.Phy = 0; + se.Virt = virtOffset; + extentStreamSpec->Extents.Add(se); + extentStreamSpec->Init(); + *stream = extentStream.Detach(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; + CMyComPtr outStream(outStreamSpec); + + for (i = 0; i < numItems; i++) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + CMyComPtr realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + const CRef2 &ref2 = _refs2[index]; + const CRef &ref = _archive.LogVols[ref2.Vol].FileSets[ref2.Fs].Refs[ref2.Ref]; + const CFile &file = _archive.Files[ref.FileIndex]; + const CItem &item = _archive.Items[file.ItemIndex]; + + if (item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + currentTotalSize += item.Size; + + if (!testMode && !realOutStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)); + outStreamSpec->SetStream(realOutStream); + realOutStream.Release(); + outStreamSpec->Init(item.Size); + Int32 opRes; + CMyComPtr 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[] = { 1, 'C', 'D', '0', '0', '1' }; + +REGISTER_ARC_I( + "Udf", "udf iso img", 0, 0xE0, + k_Signature, + kIsoStartPos, + NArcInfoFlags::kStartOpen, + IsArc_Udf) + +}} diff --git a/CPP/7zip/Archive/Udf/UdfHandler.h b/CPP/7zip/Archive/Udf/UdfHandler.h index a8b4e9922..da44b232f 100644 --- a/CPP/7zip/Archive/Udf/UdfHandler.h +++ b/CPP/7zip/Archive/Udf/UdfHandler.h @@ -1,38 +1,38 @@ -// UdfHandler.h - -#ifndef __UDF_HANDLER_H -#define __UDF_HANDLER_H - -#include "../../../Common/MyCom.h" - -#include "../IArchive.h" - -#include "UdfIn.h" - -namespace NArchive { -namespace NUdf { - -struct CRef2 -{ - unsigned Vol; - unsigned Fs; - unsigned Ref; -}; - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - CMyComPtr _inStream; - CInArchive _archive; - CRecordVector _refs2; -public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); -}; - -}} - -#endif +// UdfHandler.h + +#ifndef __UDF_HANDLER_H +#define __UDF_HANDLER_H + +#include "../../../Common/MyCom.h" + +#include "../IArchive.h" + +#include "UdfIn.h" + +namespace NArchive { +namespace NUdf { + +struct CRef2 +{ + unsigned Vol; + unsigned Fs; + unsigned Ref; +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CMyComPtr _inStream; + CInArchive _archive; + CRecordVector _refs2; +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp index 01ac87864..cfe6c5adb 100644 --- a/CPP/7zip/Archive/Udf/UdfIn.cpp +++ b/CPP/7zip/Archive/Udf/UdfIn.cpp @@ -1,1131 +1,1131 @@ -// Archive/UdfIn.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#endif - -#include "../../../../C/CpuArch.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) - -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_GET_DIGEST(crc) (crc) -#define CRC16_UPDATE_BYTE(crc, b) ((UInt16)(g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8))) - -#define kCrc16Poly 0x1021 -static UInt16 g_Crc16Table[256]; - -void MY_FAST_CALL 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; - } -} - -UInt32 MY_FAST_CALL Crc16_Update(UInt32 v, const void *data, size_t size) -{ - const Byte *p = (const Byte *)data; - for (; size > 0 ; size--, p++) - v = CRC16_UPDATE_BYTE(v, *p); - return v; -} - -UInt32 MY_FAST_CALL Crc16Calc(const void *data, size_t size) -{ - return Crc16_Update(CRC16_INIT_VAL, data, size); -} - -static struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit; - - - -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; - Byte type = data[0]; - if (type == 8) - { - p = res.GetBuf(size); - for (unsigned i = 1; i < size; i++) - { - wchar_t c = data[i]; - if (c == 0) - break; - *p++ = c; - } - } - else if (type == 16) - { - p = res.GetBuf(size / 2); - for (unsigned i = 1; i + 2 <= size; i += 2) - { - wchar_t c = GetBe16(data + i); - if (c == 0) - break; - *p++ = c; - } - } - else - return UString("[unknow]"); - *p = 0; - res.ReleaseBuf_SetLen((unsigned)(p - (const wchar_t *)res)); - } - return res; -} - -UString CDString128::GetString() 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 *buf) { memcpy(Data, buf, sizeof(Data)); } - -/* -void CRegId::Parse(const Byte *buf) -{ - Flags = buf[0]; - memcpy(Id, buf + 1, sizeof(Id)); - memcpy(Suffix, buf + 24, sizeof(Suffix)); -} -*/ - -// ECMA 3/7.1 - -struct CExtent -{ - UInt32 Len; - UInt32 Pos; - - void Parse(const Byte *buf); -}; - -void CExtent::Parse(const Byte *buf) -{ - Len = Get32(buf); - Pos = Get32(buf + 4); -} - -// ECMA 3/7.2 - -struct CTag -{ - UInt16 Id; - UInt16 Version; - // Byte Checksum; - // UInt16 SerialNumber; - // UInt16 Crc; - // UInt16 CrcLen; - // UInt32 TagLocation; - - HRESULT Parse(const Byte *buf, size_t size); -}; - -HRESULT CTag::Parse(const Byte *buf, size_t size) -{ - if (size < 16) - return S_FALSE; - Byte sum = 0; - int i; - for (i = 0; i < 4; i++) sum = (Byte)(sum + buf[i]); - for (i = 5; i < 16; i++) sum = (Byte)(sum + buf[i]); - if (sum != buf[4] || buf[5] != 0) return S_FALSE; - - Id = Get16(buf); - Version = Get16(buf + 2); - // SerialNumber = Get16(buf + 6); - UInt32 crc = Get16(buf + 8); - UInt32 crcLen = Get16(buf + 10); - // TagLocation = Get32(buf + 12); - - if (size >= 16 + crcLen) - if (crc == Crc16Calc(buf + 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_UnallocatedSpace = 263, - DESC_TYPE_SpaceBitmap = 264, - DESC_TYPE_PartitionIntegrity = 265, - DESC_TYPE_ExtendedFile = 266 -}; - - -void CLogBlockAddr::Parse(const Byte *buf) -{ - Pos = Get32(buf); - PartitionRef = Get16(buf + 4); -} - -void CShortAllocDesc::Parse(const Byte *buf) -{ - Len = Get32(buf); - Pos = Get32(buf + 4); -} - -/* -void CADImpUse::Parse(const Byte *buf) -{ - Flags = Get16(buf); - UdfUniqueId = Get32(buf + 2); -} -*/ - -void CLongAllocDesc::Parse(const Byte *buf) -{ - Len = Get32(buf); - Location.Parse(buf + 4); - // memcpy(ImplUse, buf + 10, sizeof(ImplUse)); - // adImpUse.Parse(ImplUse); -} - -bool CInArchive::CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const -{ - const CLogVol &vol = LogVols[volIndex]; - if (partitionRef >= (int)vol.PartitionMaps.Size()) - return false; - const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; - UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize; - return (offset + len) <= (((UInt64)partition.Pos + partition.Len) << SecLogSize); -} - -bool CInArchive::CheckItemExtents(int volIndex, const CItem &item) const -{ - FOR_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(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf) -{ - if (!CheckExtent(volIndex, partitionRef, blockPos, len)) - return S_FALSE; - const CLogVol &vol = LogVols[volIndex]; - const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; - UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize; - RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); - HRESULT res = ReadStream_FALSE(_stream, buf, len); - if (res == S_FALSE && offset + len > FileSize) - UnexpectedEnd = true; - RINOK(res); - UpdatePhySize(offset + len); - return S_OK; -} - -HRESULT CInArchive::Read(int volIndex, const CLongAllocDesc &lad, Byte *buf) -{ - return Read(volIndex, lad.Location.PartitionRef, lad.Location.Pos, lad.GetLen(), (Byte *)buf); -} - -HRESULT CInArchive::ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf) -{ - if (item.Size >= (UInt32)1 << 30) - return S_FALSE; - if (item.IsInline) - { - buf = item.InlineData; - return S_OK; - } - buf.Alloc((size_t)item.Size); - size_t pos = 0; - FOR_VECTOR (i, item.Extents) - { - const CMyExtent &e = item.Extents[i]; - UInt32 len = e.GetLen(); - RINOK(Read(volIndex, e.PartitionRef, e.Pos, len, (Byte *)buf + pos)); - pos += len; - } - return S_OK; -} - - -void CIcbTag::Parse(const Byte *p) -{ - // PriorDirectNum = Get32(p); - // StrategyType = Get16(p + 4); - // StrategyParam = Get16(p + 6); - // MaxNumOfEntries = Get16(p + 8); - FileType = p[11]; - // ParentIcb.Parse(p + 12); - Flags = Get16(p + 18); -} - -void CItem::Parse(const Byte *p) -{ - // Uid = Get32(p + 36); - // Gid = Get32(p + 40); - // Permissions = Get32(p + 44); - // FileLinkCount = Get16(p + 48); - // RecordFormat = p[50]; - // RecordDisplayAttr = p[51]; - // RecordLen = Get32(p + 52); - Size = Get64(p + 56); - NumLogBlockRecorded = Get64(p + 64); - ATime.Parse(p + 72); - MTime.Parse(p + 84); - // AttrtTime.Parse(p + 96); - // CheckPoint = Get32(p + 108); - // ExtendedAttrIcb.Parse(p + 112); - // ImplId.Parse(p + 128); - // UniqueId = Get64(p + 160); -} - -// 4/14.4 -struct CFileId -{ - // UInt16 FileVersion; - Byte FileCharacteristics; - // CByteBuffer ImplUse; - CDString Id; - CLongAllocDesc Icb; - - bool IsItLinkParent() const { return (FileCharacteristics & FILEID_CHARACS_Parent) != 0; } - HRESULT Parse(const Byte *p, size_t size, size_t &processed); -}; - -HRESULT CFileId::Parse(const Byte *p, size_t size, size_t &processed) -{ - processed = 0; - if (size < 38) - return S_FALSE; - CTag tag; - RINOK(tag.Parse(p, size)); - if (tag.Id != DESC_TYPE_FileId) - return S_FALSE; - // FileVersion = Get16(p + 16); - FileCharacteristics = p[18]; - unsigned idLen = p[19]; - Icb.Parse(p + 20); - unsigned impLen = Get16(p + 36); - if (size < 38 + idLen + impLen) - return S_FALSE; - // ImplUse.SetCapacity(impLen); - processed = 38; - // memcpy(ImplUse, p + processed, impLen); - processed += impLen; - Id.Parse(p + processed, idLen); - processed += idLen; - for (;(processed & 3) != 0; processed++) - if (p[processed] != 0) - return S_FALSE; - return (processed <= size) ? S_OK : S_FALSE; -} - -HRESULT CInArchive::ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) -{ - if (Files.Size() % 100 == 0) - RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes)); - if (numRecurseAllowed-- == 0) - return S_FALSE; - CFile &file = Files.Back(); - const CLogVol &vol = LogVols[volIndex]; - unsigned partitionRef = lad.Location.PartitionRef; - if (partitionRef >= vol.PartitionMaps.Size()) - return S_FALSE; - CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; - - UInt32 key = lad.Location.Pos; - UInt32 value; - const UInt32 kRecursedErrorValue = (UInt32)(Int32)-1; - if (partition.Map.Find(key, value)) - { - if (value == kRecursedErrorValue) - return S_FALSE; - file.ItemIndex = value; - } - else - { - value = Items.Size(); - file.ItemIndex = (int)value; - if (partition.Map.Set(key, kRecursedErrorValue)) - return S_FALSE; - RINOK(ReadItem(volIndex, fsIndex, lad, numRecurseAllowed)); - if (!partition.Map.Set(key, value)) - return S_FALSE; - } - return S_OK; -} - -HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) -{ - if (Items.Size() > kNumItemsMax) - return S_FALSE; - Items.Add(CItem()); - CItem &item = Items.Back(); - - const CLogVol &vol = LogVols[volIndex]; - - if (lad.GetLen() != vol.BlockSize) - return S_FALSE; - - const size_t size = lad.GetLen(); - CByteBuffer buf(size); - RINOK(Read(volIndex, lad, buf)); - - CTag tag; - const Byte *p = buf; - RINOK(tag.Parse(p, size)); - if (size < 176) - return S_FALSE; - if (tag.Id != DESC_TYPE_File) - return S_FALSE; - - item.IcbTag.Parse(p + 16); - if (item.IcbTag.FileType != ICB_FILE_TYPE_DIR && - item.IcbTag.FileType != ICB_FILE_TYPE_FILE) - return S_FALSE; - - item.Parse(p); - - _processedProgressBytes += (UInt64)item.NumLogBlockRecorded * vol.BlockSize + size; - - UInt32 extendedAttrLen = Get32(p + 168); - UInt32 allocDescriptorsLen = Get32(p + 172); - - if ((extendedAttrLen & 3) != 0) - return S_FALSE; - size_t pos = 176; - if (extendedAttrLen > size - pos) - return S_FALSE; - /* - if (extendedAttrLen != 16) - { - if (extendedAttrLen < 24) - return S_FALSE; - CTag attrTag; - RINOK(attrTag.Parse(p + pos, size)); - if (attrTag.Id != DESC_TYPE_ExtendedAttrHeader) - return S_FALSE; - // UInt32 implAttrLocation = Get32(p + pos + 16); - // UInt32 applicationlAttrLocation = Get32(p + pos + 20); - } - */ - pos += extendedAttrLen; - - int desctType = item.IcbTag.GetDescriptorType(); - if (allocDescriptorsLen > size - pos) - return S_FALSE; - if (desctType == ICB_DESC_TYPE_INLINE) - { - item.IsInline = true; - item.InlineData.CopyFrom(p + pos, allocDescriptorsLen); - } - else - { - item.IsInline = false; - if (desctType != ICB_DESC_TYPE_SHORT && desctType != ICB_DESC_TYPE_LONG) - return S_FALSE; - for (UInt32 i = 0; i < allocDescriptorsLen;) - { - CMyExtent e; - if (desctType == ICB_DESC_TYPE_SHORT) - { - if (i + 8 > allocDescriptorsLen) - return S_FALSE; - CShortAllocDesc sad; - sad.Parse(p + pos + i); - e.Pos = sad.Pos; - e.Len = sad.Len; - e.PartitionRef = lad.Location.PartitionRef; - i += 8; - } - else - { - if (i + 16 > allocDescriptorsLen) - return S_FALSE; - CLongAllocDesc ladNew; - ladNew.Parse(p + pos + i); - e.Pos = ladNew.Location.Pos; - e.PartitionRef = ladNew.Location.PartitionRef; - e.Len = ladNew.Len; - i += 16; - } - item.Extents.Add(e); - } - } - - if (item.IcbTag.IsDir()) - { - if (!item.CheckChunkSizes() || !CheckItemExtents(volIndex, item)) - return S_FALSE; - CByteBuffer buf2; - RINOK(ReadFromFile(volIndex, item, buf2)); - item.Size = 0; - item.Extents.ClearAndFree(); - item.InlineData.Free(); - - const Byte *p2 = buf2; - const size_t size2 = buf2.Size(); - size_t processedTotal = 0; - for (; processedTotal < size2;) - { - size_t processedCur; - CFileId fileId; - RINOK(fileId.Parse(p2 + processedTotal, size2 - processedTotal, processedCur)); - if (!fileId.IsItLinkParent()) - { - CFile file; - // file.FileVersion = fileId.FileVersion; - // file.FileCharacteristics = fileId.FileCharacteristics; - // file.ImplUse = fileId.ImplUse; - file.Id = fileId.Id; - - _fileNameLengthTotal += file.Id.Data.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, fsIndex, fileId.Icb, numRecurseAllowed)); - } - processedTotal += processedCur; - } - } - 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 = 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 -= 3) - { - if (SecLogSize < 8) - 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) - return k_IsArc_Res_YES; - } - } -} - - -HRESULT CInArchive::Open2() -{ - Clear(); - UInt64 fileSize; - RINOK(_stream->Seek(0, STREAM_SEEK_END, &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(_stream->Seek(fileSize - readSize, STREAM_SEEK_SET, NULL)); - 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); - */ - - const size_t kBufSize = 1 << 11; - Byte buf[kBufSize]; - - for (SecLogSize = 11;; SecLogSize -= 3) - { - if (SecLogSize < 8) - return S_FALSE; - UInt32 offset = (UInt32)256 << SecLogSize; - if (offset >= fileSize) - continue; - RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); - 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) - break; - } - } - - PhySize = (UInt32)(256 + 1) << SecLogSize; - IsArc = true; - - CExtent extentVDS; - extentVDS.Parse(buf + 16); - { - CExtent extentVDS2; - extentVDS2.Parse(buf + 24); - UpdatePhySize(((UInt64)extentVDS.Pos << SecLogSize) + extentVDS.Len); - UpdatePhySize(((UInt64)extentVDS2.Pos << SecLogSize) + extentVDS2.Len); - } - - for (UInt32 location = 0; ; location++) - { - const size_t bufSize = (size_t)1 << SecLogSize; - if (((UInt64)(location + 1) << SecLogSize) > extentVDS.Len) - return S_FALSE; - - UInt64 offs = (UInt64)(extentVDS.Pos + location) << SecLogSize; - RINOK(_stream->Seek(offs, STREAM_SEEK_SET, NULL)); - HRESULT res = ReadStream_FALSE(_stream, buf, bufSize); - if (res == S_FALSE && offs + bufSize > FileSize) - UnexpectedEnd = true; - RINOK(res); - - - CTag tag; - { - const size_t pos = 0; - RINOK(tag.Parse(buf + pos, bufSize - pos)); - } - if (tag.Id == DESC_TYPE_Terminating) - break; - - if (tag.Id == DESC_TYPE_Partition) - { - // Partition Descriptor - // ECMA 167 3/10.5 - // UDF / 2.2.14 - - if (Partitions.Size() >= kNumPartitionsMax) - return S_FALSE; - CPartition partition; - // UInt32 volDescSeqNumer = Get32(buf + 16); - // partition.Flags = Get16(buf + 20); - partition.Number = Get16(buf + 22); - // partition.ContentsId.Parse(buf + 24); - - // memcpy(partition.ContentsUse, buf + 56, sizeof(partition.ContentsUse)); - // ContentsUse is Partition Header Description. - - // partition.AccessType = Get32(buf + 184); - partition.Pos = Get32(buf + 188); - partition.Len = Get32(buf + 192); - // partition.ImplId.Parse(buf + 196); - // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse)); - - PRF(printf("\nPartition number = %2d pos = %d len = %d", partition.Number, partition.Pos, partition.Len)); - Partitions.Add(partition); - } - else 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; - vol.Id.Parse(buf + 84); - vol.BlockSize = Get32(buf + 212); - // vol.DomainId.Parse(buf + 216); - - if (vol.BlockSize < 512 || vol.BlockSize > ((UInt32)1 << 30)) - return S_FALSE; - - // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse)); - vol.FileSetLocation.Parse(buf + 248); - /* the extent in which the first File Set Descriptor Sequence - of the logical volume is recorded */ - - // UInt32 mapTableLength = Get32(buf + 264); - UInt32 numPartitionMaps = Get32(buf + 268); - if (numPartitionMaps > kNumPartitionsMax) - return S_FALSE; - // vol.ImplId.Parse(buf + 272); - // memcpy(vol.ImplUse, buf + 128, sizeof(vol.ImplUse)); - - PRF(printf("\nLogicalVol numPartitionMaps = %2d", numPartitionMaps)); - size_t pos = 440; - for (UInt32 i = 0; i < numPartitionMaps; i++) - { - if (pos + 2 > bufSize) - return S_FALSE; - CPartitionMap pm; - pm.Type = buf[pos]; - // pm.Length = buf[pos + 1]; - Byte len = buf[pos + 1]; - - if (pos + len > bufSize) - return S_FALSE; - - // memcpy(pm.Data, buf + pos + 2, pm.Length - 2); - if (pm.Type == 1) - { - if (len != 6) // < 6 - return S_FALSE; - // pm.VolSeqNumber = 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.6 - 2.2.8 Virtual Partition Map - This is an extension of ECMA 167 to expand its scope to include - sequentially written media (eg. CD-R). This extension is for a - Partition Map entry to describe a virtual space. */ - - // It's not implemented still. - if (Get16(buf + pos + 2) != 0) - return S_FALSE; - // pm.VolSeqNumber = Get16(buf + pos + 36); - pm.PartitionNumber = Get16(buf + pos + 38); - PRF(printf("\nPartitionMap type 2 PartitionNumber = %2d", pm.PartitionNumber)); - // Unsupported = true; - return S_FALSE; - } - else - return S_FALSE; - pos += len; - vol.PartitionMaps.Add(pm); - } - LogVols.Add(vol); - } - } - - 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]; - unsigned i; - for (i = 0; i < Partitions.Size(); i++) - { - CPartition &part = Partitions[i]; - if (part.Number == pm.PartitionNumber) - { - if (part.VolIndex >= 0) - { - // it's for 2.60. Fix it - if (part.VolIndex != (int)volIndex) - return S_FALSE; - // return S_FALSE; - } - pm.PartitionIndex = i; - part.VolIndex = volIndex; - - totalSize += (UInt64)part.Len << SecLogSize; - break; - } - } - if (i == Partitions.Size()) - return S_FALSE; - } - } - - RINOK(_progress->SetTotal(totalSize)); - - 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(Read(volIndex, nextExtent, buf2)); - const Byte *p = buf2; - size_t size = nextExtent.GetLen(); - - CTag tag; - RINOK(tag.Parse(p, size)); - - 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.RecodringTime.Parse(p + 16); - // fs.InterchangeLevel = Get16(p + 18); - // fs.MaxInterchangeLevel = Get16(p + 20); - // fs.FileSetNumber = Get32(p + 40); - // fs.FileSetDescNumber = Get32(p + 44); - - // fs.Id.Parse(p + 304); - // fs.CopyrightId.Parse(p + 336); - // fs.AbstractId.Parse(p + 368); - - fs.RootDirICB.Parse(p + 400); - // fs.DomainId.Parse(p + 416); - - // fs.SystemStreamDirICB.Parse(p + 464); - - vol.FileSets.Add(fs); - - // nextExtent.Parse(p + 448); - } - - FOR_VECTOR (fsIndex, vol.FileSets) - { - CFileSet &fs = vol.FileSets[fsIndex]; - unsigned fileIndex = Files.Size(); - Files.AddNew(); - RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, 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]; - UInt32 len = extent.GetLen(); - if (len == 0) - continue; - if (size < len) - break; - - int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; - UInt32 logBlockNumber = extent.Pos; - const CPartition &partition = Partitions[partitionIndex]; - 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(_stream->Seek(PhySize, STREAM_SEEK_SET, NULL)); - - // 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; - - if (readSize == secSize && NoEndAnchor) - { - CTag tag; - if (tag.Parse(buf, readSize) == S_OK && - tag.Id == DESC_TYPE_AnchorVolPtr) - { - 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(); - Items.Clear(); - Files.Clear(); - _fileNameLengthTotal = 0; - _numRefs = 0; - _numExtents = 0; - _inlineExtentsSize = 0; - _processedProgressBytes = 0; -} - -UString CInArchive::GetComment() const -{ - UString res; - FOR_VECTOR (i, LogVols) - { - if (i != 0) - res.Add_Space(); - res += LogVols[i].GetName(); - } - return res; -} - -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(int volIndex, int fsIndex, int refIndex, - bool showVolName, bool showFsName) const -{ - // showVolName = true; - const CLogVol &vol = LogVols[volIndex]; - const CFileSet &fs = vol.FileSets[fsIndex]; - - UString name; - - for (;;) - { - const CRef &ref = fs.Refs[refIndex]; - refIndex = ref.Parent; - if (refIndex < 0) - break; - UpdateWithName(name, GetSpecName(Files[ref.FileIndex].GetName())); - } - - if (showFsName) - { - 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; -} - -}} +// Archive/UdfIn.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include "../../../../C/CpuArch.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) + +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_GET_DIGEST(crc) (crc) +#define CRC16_UPDATE_BYTE(crc, b) ((UInt16)(g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8))) + +#define kCrc16Poly 0x1021 +static UInt16 g_Crc16Table[256]; + +void MY_FAST_CALL 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; + } +} + +UInt32 MY_FAST_CALL Crc16_Update(UInt32 v, const void *data, size_t size) +{ + const Byte *p = (const Byte *)data; + for (; size > 0 ; size--, p++) + v = CRC16_UPDATE_BYTE(v, *p); + return v; +} + +UInt32 MY_FAST_CALL Crc16Calc(const void *data, size_t size) +{ + return Crc16_Update(CRC16_INIT_VAL, data, size); +} + +static struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit; + + + +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; + Byte type = data[0]; + if (type == 8) + { + p = res.GetBuf(size); + for (unsigned i = 1; i < size; i++) + { + wchar_t c = data[i]; + if (c == 0) + break; + *p++ = c; + } + } + else if (type == 16) + { + p = res.GetBuf(size / 2); + for (unsigned i = 1; i + 2 <= size; i += 2) + { + wchar_t c = GetBe16(data + i); + if (c == 0) + break; + *p++ = c; + } + } + else + return UString("[unknow]"); + *p = 0; + res.ReleaseBuf_SetLen((unsigned)(p - (const wchar_t *)res)); + } + return res; +} + +UString CDString128::GetString() 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 *buf) { memcpy(Data, buf, sizeof(Data)); } + +/* +void CRegId::Parse(const Byte *buf) +{ + Flags = buf[0]; + memcpy(Id, buf + 1, sizeof(Id)); + memcpy(Suffix, buf + 24, sizeof(Suffix)); +} +*/ + +// ECMA 3/7.1 + +struct CExtent +{ + UInt32 Len; + UInt32 Pos; + + void Parse(const Byte *buf); +}; + +void CExtent::Parse(const Byte *buf) +{ + Len = Get32(buf); + Pos = Get32(buf + 4); +} + +// ECMA 3/7.2 + +struct CTag +{ + UInt16 Id; + UInt16 Version; + // Byte Checksum; + // UInt16 SerialNumber; + // UInt16 Crc; + // UInt16 CrcLen; + // UInt32 TagLocation; + + HRESULT Parse(const Byte *buf, size_t size); +}; + +HRESULT CTag::Parse(const Byte *buf, size_t size) +{ + if (size < 16) + return S_FALSE; + Byte sum = 0; + int i; + for (i = 0; i < 4; i++) sum = (Byte)(sum + buf[i]); + for (i = 5; i < 16; i++) sum = (Byte)(sum + buf[i]); + if (sum != buf[4] || buf[5] != 0) return S_FALSE; + + Id = Get16(buf); + Version = Get16(buf + 2); + // SerialNumber = Get16(buf + 6); + UInt32 crc = Get16(buf + 8); + UInt32 crcLen = Get16(buf + 10); + // TagLocation = Get32(buf + 12); + + if (size >= 16 + crcLen) + if (crc == Crc16Calc(buf + 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_UnallocatedSpace = 263, + DESC_TYPE_SpaceBitmap = 264, + DESC_TYPE_PartitionIntegrity = 265, + DESC_TYPE_ExtendedFile = 266 +}; + + +void CLogBlockAddr::Parse(const Byte *buf) +{ + Pos = Get32(buf); + PartitionRef = Get16(buf + 4); +} + +void CShortAllocDesc::Parse(const Byte *buf) +{ + Len = Get32(buf); + Pos = Get32(buf + 4); +} + +/* +void CADImpUse::Parse(const Byte *buf) +{ + Flags = Get16(buf); + UdfUniqueId = Get32(buf + 2); +} +*/ + +void CLongAllocDesc::Parse(const Byte *buf) +{ + Len = Get32(buf); + Location.Parse(buf + 4); + // memcpy(ImplUse, buf + 10, sizeof(ImplUse)); + // adImpUse.Parse(ImplUse); +} + +bool CInArchive::CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const +{ + const CLogVol &vol = LogVols[volIndex]; + if (partitionRef >= (int)vol.PartitionMaps.Size()) + return false; + const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; + UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize; + return (offset + len) <= (((UInt64)partition.Pos + partition.Len) << SecLogSize); +} + +bool CInArchive::CheckItemExtents(int volIndex, const CItem &item) const +{ + FOR_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(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf) +{ + if (!CheckExtent(volIndex, partitionRef, blockPos, len)) + return S_FALSE; + const CLogVol &vol = LogVols[volIndex]; + const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; + UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize; + RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); + HRESULT res = ReadStream_FALSE(_stream, buf, len); + if (res == S_FALSE && offset + len > FileSize) + UnexpectedEnd = true; + RINOK(res); + UpdatePhySize(offset + len); + return S_OK; +} + +HRESULT CInArchive::Read(int volIndex, const CLongAllocDesc &lad, Byte *buf) +{ + return Read(volIndex, lad.Location.PartitionRef, lad.Location.Pos, lad.GetLen(), (Byte *)buf); +} + +HRESULT CInArchive::ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf) +{ + if (item.Size >= (UInt32)1 << 30) + return S_FALSE; + if (item.IsInline) + { + buf = item.InlineData; + return S_OK; + } + buf.Alloc((size_t)item.Size); + size_t pos = 0; + FOR_VECTOR (i, item.Extents) + { + const CMyExtent &e = item.Extents[i]; + UInt32 len = e.GetLen(); + RINOK(Read(volIndex, e.PartitionRef, e.Pos, len, (Byte *)buf + pos)); + pos += len; + } + return S_OK; +} + + +void CIcbTag::Parse(const Byte *p) +{ + // PriorDirectNum = Get32(p); + // StrategyType = Get16(p + 4); + // StrategyParam = Get16(p + 6); + // MaxNumOfEntries = Get16(p + 8); + FileType = p[11]; + // ParentIcb.Parse(p + 12); + Flags = Get16(p + 18); +} + +void CItem::Parse(const Byte *p) +{ + // Uid = Get32(p + 36); + // Gid = Get32(p + 40); + // Permissions = Get32(p + 44); + // FileLinkCount = Get16(p + 48); + // RecordFormat = p[50]; + // RecordDisplayAttr = p[51]; + // RecordLen = Get32(p + 52); + Size = Get64(p + 56); + NumLogBlockRecorded = Get64(p + 64); + ATime.Parse(p + 72); + MTime.Parse(p + 84); + // AttrtTime.Parse(p + 96); + // CheckPoint = Get32(p + 108); + // ExtendedAttrIcb.Parse(p + 112); + // ImplId.Parse(p + 128); + // UniqueId = Get64(p + 160); +} + +// 4/14.4 +struct CFileId +{ + // UInt16 FileVersion; + Byte FileCharacteristics; + // CByteBuffer ImplUse; + CDString Id; + CLongAllocDesc Icb; + + bool IsItLinkParent() const { return (FileCharacteristics & FILEID_CHARACS_Parent) != 0; } + HRESULT Parse(const Byte *p, size_t size, size_t &processed); +}; + +HRESULT CFileId::Parse(const Byte *p, size_t size, size_t &processed) +{ + processed = 0; + if (size < 38) + return S_FALSE; + CTag tag; + RINOK(tag.Parse(p, size)); + if (tag.Id != DESC_TYPE_FileId) + return S_FALSE; + // FileVersion = Get16(p + 16); + FileCharacteristics = p[18]; + unsigned idLen = p[19]; + Icb.Parse(p + 20); + unsigned impLen = Get16(p + 36); + if (size < 38 + idLen + impLen) + return S_FALSE; + // ImplUse.SetCapacity(impLen); + processed = 38; + // memcpy(ImplUse, p + processed, impLen); + processed += impLen; + Id.Parse(p + processed, idLen); + processed += idLen; + for (;(processed & 3) != 0; processed++) + if (p[processed] != 0) + return S_FALSE; + return (processed <= size) ? S_OK : S_FALSE; +} + +HRESULT CInArchive::ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) +{ + if (Files.Size() % 100 == 0) + RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes)); + if (numRecurseAllowed-- == 0) + return S_FALSE; + CFile &file = Files.Back(); + const CLogVol &vol = LogVols[volIndex]; + unsigned partitionRef = lad.Location.PartitionRef; + if (partitionRef >= vol.PartitionMaps.Size()) + return S_FALSE; + CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; + + UInt32 key = lad.Location.Pos; + UInt32 value; + const UInt32 kRecursedErrorValue = (UInt32)(Int32)-1; + if (partition.Map.Find(key, value)) + { + if (value == kRecursedErrorValue) + return S_FALSE; + file.ItemIndex = value; + } + else + { + value = Items.Size(); + file.ItemIndex = (int)value; + if (partition.Map.Set(key, kRecursedErrorValue)) + return S_FALSE; + RINOK(ReadItem(volIndex, fsIndex, lad, numRecurseAllowed)); + if (!partition.Map.Set(key, value)) + return S_FALSE; + } + return S_OK; +} + +HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) +{ + if (Items.Size() > kNumItemsMax) + return S_FALSE; + Items.Add(CItem()); + CItem &item = Items.Back(); + + const CLogVol &vol = LogVols[volIndex]; + + if (lad.GetLen() != vol.BlockSize) + return S_FALSE; + + const size_t size = lad.GetLen(); + CByteBuffer buf(size); + RINOK(Read(volIndex, lad, buf)); + + CTag tag; + const Byte *p = buf; + RINOK(tag.Parse(p, size)); + if (size < 176) + return S_FALSE; + if (tag.Id != DESC_TYPE_File) + return S_FALSE; + + item.IcbTag.Parse(p + 16); + if (item.IcbTag.FileType != ICB_FILE_TYPE_DIR && + item.IcbTag.FileType != ICB_FILE_TYPE_FILE) + return S_FALSE; + + item.Parse(p); + + _processedProgressBytes += (UInt64)item.NumLogBlockRecorded * vol.BlockSize + size; + + UInt32 extendedAttrLen = Get32(p + 168); + UInt32 allocDescriptorsLen = Get32(p + 172); + + if ((extendedAttrLen & 3) != 0) + return S_FALSE; + size_t pos = 176; + if (extendedAttrLen > size - pos) + return S_FALSE; + /* + if (extendedAttrLen != 16) + { + if (extendedAttrLen < 24) + return S_FALSE; + CTag attrTag; + RINOK(attrTag.Parse(p + pos, size)); + if (attrTag.Id != DESC_TYPE_ExtendedAttrHeader) + return S_FALSE; + // UInt32 implAttrLocation = Get32(p + pos + 16); + // UInt32 applicationlAttrLocation = Get32(p + pos + 20); + } + */ + pos += extendedAttrLen; + + int desctType = item.IcbTag.GetDescriptorType(); + if (allocDescriptorsLen > size - pos) + return S_FALSE; + if (desctType == ICB_DESC_TYPE_INLINE) + { + item.IsInline = true; + item.InlineData.CopyFrom(p + pos, allocDescriptorsLen); + } + else + { + item.IsInline = false; + if (desctType != ICB_DESC_TYPE_SHORT && desctType != ICB_DESC_TYPE_LONG) + return S_FALSE; + for (UInt32 i = 0; i < allocDescriptorsLen;) + { + CMyExtent e; + if (desctType == ICB_DESC_TYPE_SHORT) + { + if (i + 8 > allocDescriptorsLen) + return S_FALSE; + CShortAllocDesc sad; + sad.Parse(p + pos + i); + e.Pos = sad.Pos; + e.Len = sad.Len; + e.PartitionRef = lad.Location.PartitionRef; + i += 8; + } + else + { + if (i + 16 > allocDescriptorsLen) + return S_FALSE; + CLongAllocDesc ladNew; + ladNew.Parse(p + pos + i); + e.Pos = ladNew.Location.Pos; + e.PartitionRef = ladNew.Location.PartitionRef; + e.Len = ladNew.Len; + i += 16; + } + item.Extents.Add(e); + } + } + + if (item.IcbTag.IsDir()) + { + if (!item.CheckChunkSizes() || !CheckItemExtents(volIndex, item)) + return S_FALSE; + CByteBuffer buf2; + RINOK(ReadFromFile(volIndex, item, buf2)); + item.Size = 0; + item.Extents.ClearAndFree(); + item.InlineData.Free(); + + const Byte *p2 = buf2; + const size_t size2 = buf2.Size(); + size_t processedTotal = 0; + for (; processedTotal < size2;) + { + size_t processedCur; + CFileId fileId; + RINOK(fileId.Parse(p2 + processedTotal, size2 - processedTotal, processedCur)); + if (!fileId.IsItLinkParent()) + { + CFile file; + // file.FileVersion = fileId.FileVersion; + // file.FileCharacteristics = fileId.FileCharacteristics; + // file.ImplUse = fileId.ImplUse; + file.Id = fileId.Id; + + _fileNameLengthTotal += file.Id.Data.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, fsIndex, fileId.Icb, numRecurseAllowed)); + } + processedTotal += processedCur; + } + } + 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 = 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 -= 3) + { + if (SecLogSize < 8) + 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) + return k_IsArc_Res_YES; + } + } +} + + +HRESULT CInArchive::Open2() +{ + Clear(); + UInt64 fileSize; + RINOK(_stream->Seek(0, STREAM_SEEK_END, &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(_stream->Seek(fileSize - readSize, STREAM_SEEK_SET, NULL)); + 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); + */ + + const size_t kBufSize = 1 << 11; + Byte buf[kBufSize]; + + for (SecLogSize = 11;; SecLogSize -= 3) + { + if (SecLogSize < 8) + return S_FALSE; + UInt32 offset = (UInt32)256 << SecLogSize; + if (offset >= fileSize) + continue; + RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); + 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) + break; + } + } + + PhySize = (UInt32)(256 + 1) << SecLogSize; + IsArc = true; + + CExtent extentVDS; + extentVDS.Parse(buf + 16); + { + CExtent extentVDS2; + extentVDS2.Parse(buf + 24); + UpdatePhySize(((UInt64)extentVDS.Pos << SecLogSize) + extentVDS.Len); + UpdatePhySize(((UInt64)extentVDS2.Pos << SecLogSize) + extentVDS2.Len); + } + + for (UInt32 location = 0; ; location++) + { + const size_t bufSize = (size_t)1 << SecLogSize; + if (((UInt64)(location + 1) << SecLogSize) > extentVDS.Len) + return S_FALSE; + + UInt64 offs = (UInt64)(extentVDS.Pos + location) << SecLogSize; + RINOK(_stream->Seek(offs, STREAM_SEEK_SET, NULL)); + HRESULT res = ReadStream_FALSE(_stream, buf, bufSize); + if (res == S_FALSE && offs + bufSize > FileSize) + UnexpectedEnd = true; + RINOK(res); + + + CTag tag; + { + const size_t pos = 0; + RINOK(tag.Parse(buf + pos, bufSize - pos)); + } + if (tag.Id == DESC_TYPE_Terminating) + break; + + if (tag.Id == DESC_TYPE_Partition) + { + // Partition Descriptor + // ECMA 167 3/10.5 + // UDF / 2.2.14 + + if (Partitions.Size() >= kNumPartitionsMax) + return S_FALSE; + CPartition partition; + // UInt32 volDescSeqNumer = Get32(buf + 16); + // partition.Flags = Get16(buf + 20); + partition.Number = Get16(buf + 22); + // partition.ContentsId.Parse(buf + 24); + + // memcpy(partition.ContentsUse, buf + 56, sizeof(partition.ContentsUse)); + // ContentsUse is Partition Header Description. + + // partition.AccessType = Get32(buf + 184); + partition.Pos = Get32(buf + 188); + partition.Len = Get32(buf + 192); + // partition.ImplId.Parse(buf + 196); + // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse)); + + PRF(printf("\nPartition number = %2d pos = %d len = %d", partition.Number, partition.Pos, partition.Len)); + Partitions.Add(partition); + } + else 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; + vol.Id.Parse(buf + 84); + vol.BlockSize = Get32(buf + 212); + // vol.DomainId.Parse(buf + 216); + + if (vol.BlockSize < 512 || vol.BlockSize > ((UInt32)1 << 30)) + return S_FALSE; + + // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse)); + vol.FileSetLocation.Parse(buf + 248); + /* the extent in which the first File Set Descriptor Sequence + of the logical volume is recorded */ + + // UInt32 mapTableLength = Get32(buf + 264); + UInt32 numPartitionMaps = Get32(buf + 268); + if (numPartitionMaps > kNumPartitionsMax) + return S_FALSE; + // vol.ImplId.Parse(buf + 272); + // memcpy(vol.ImplUse, buf + 128, sizeof(vol.ImplUse)); + + PRF(printf("\nLogicalVol numPartitionMaps = %2d", numPartitionMaps)); + size_t pos = 440; + for (UInt32 i = 0; i < numPartitionMaps; i++) + { + if (pos + 2 > bufSize) + return S_FALSE; + CPartitionMap pm; + pm.Type = buf[pos]; + // pm.Length = buf[pos + 1]; + Byte len = buf[pos + 1]; + + if (pos + len > bufSize) + return S_FALSE; + + // memcpy(pm.Data, buf + pos + 2, pm.Length - 2); + if (pm.Type == 1) + { + if (len != 6) // < 6 + return S_FALSE; + // pm.VolSeqNumber = 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.6 + 2.2.8 Virtual Partition Map + This is an extension of ECMA 167 to expand its scope to include + sequentially written media (eg. CD-R). This extension is for a + Partition Map entry to describe a virtual space. */ + + // It's not implemented still. + if (Get16(buf + pos + 2) != 0) + return S_FALSE; + // pm.VolSeqNumber = Get16(buf + pos + 36); + pm.PartitionNumber = Get16(buf + pos + 38); + PRF(printf("\nPartitionMap type 2 PartitionNumber = %2d", pm.PartitionNumber)); + // Unsupported = true; + return S_FALSE; + } + else + return S_FALSE; + pos += len; + vol.PartitionMaps.Add(pm); + } + LogVols.Add(vol); + } + } + + 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]; + unsigned i; + for (i = 0; i < Partitions.Size(); i++) + { + CPartition &part = Partitions[i]; + if (part.Number == pm.PartitionNumber) + { + if (part.VolIndex >= 0) + { + // it's for 2.60. Fix it + if (part.VolIndex != (int)volIndex) + return S_FALSE; + // return S_FALSE; + } + pm.PartitionIndex = i; + part.VolIndex = volIndex; + + totalSize += (UInt64)part.Len << SecLogSize; + break; + } + } + if (i == Partitions.Size()) + return S_FALSE; + } + } + + RINOK(_progress->SetTotal(totalSize)); + + 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(Read(volIndex, nextExtent, buf2)); + const Byte *p = buf2; + size_t size = nextExtent.GetLen(); + + CTag tag; + RINOK(tag.Parse(p, size)); + + 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.RecodringTime.Parse(p + 16); + // fs.InterchangeLevel = Get16(p + 18); + // fs.MaxInterchangeLevel = Get16(p + 20); + // fs.FileSetNumber = Get32(p + 40); + // fs.FileSetDescNumber = Get32(p + 44); + + // fs.Id.Parse(p + 304); + // fs.CopyrightId.Parse(p + 336); + // fs.AbstractId.Parse(p + 368); + + fs.RootDirICB.Parse(p + 400); + // fs.DomainId.Parse(p + 416); + + // fs.SystemStreamDirICB.Parse(p + 464); + + vol.FileSets.Add(fs); + + // nextExtent.Parse(p + 448); + } + + FOR_VECTOR (fsIndex, vol.FileSets) + { + CFileSet &fs = vol.FileSets[fsIndex]; + unsigned fileIndex = Files.Size(); + Files.AddNew(); + RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, 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]; + UInt32 len = extent.GetLen(); + if (len == 0) + continue; + if (size < len) + break; + + int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; + UInt32 logBlockNumber = extent.Pos; + const CPartition &partition = Partitions[partitionIndex]; + 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(_stream->Seek(PhySize, STREAM_SEEK_SET, NULL)); + + // 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; + + if (readSize == secSize && NoEndAnchor) + { + CTag tag; + if (tag.Parse(buf, readSize) == S_OK && + tag.Id == DESC_TYPE_AnchorVolPtr) + { + 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(); + Items.Clear(); + Files.Clear(); + _fileNameLengthTotal = 0; + _numRefs = 0; + _numExtents = 0; + _inlineExtentsSize = 0; + _processedProgressBytes = 0; +} + +UString CInArchive::GetComment() const +{ + UString res; + FOR_VECTOR (i, LogVols) + { + if (i != 0) + res.Add_Space(); + res += LogVols[i].GetName(); + } + return res; +} + +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(int volIndex, int fsIndex, int refIndex, + bool showVolName, bool showFsName) const +{ + // showVolName = true; + const CLogVol &vol = LogVols[volIndex]; + const CFileSet &fs = vol.FileSets[fsIndex]; + + UString name; + + for (;;) + { + const CRef &ref = fs.Refs[refIndex]; + refIndex = ref.Parent; + if (refIndex < 0) + break; + UpdateWithName(name, GetSpecName(Files[ref.FileIndex].GetName())); + } + + if (showFsName) + { + 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 index f592084cb..f73794015 100644 --- a/CPP/7zip/Archive/Udf/UdfIn.h +++ b/CPP/7zip/Archive/Udf/UdfIn.h @@ -1,394 +1,394 @@ -// Archive/UdfIn.h -- UDF / ECMA-167 - -#ifndef __ARCHIVE_UDF_IN_H -#define __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 - -/* -struct CDString32 -{ - Byte Data[32]; - - void Parse(const Byte *buf); - // 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 - -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 - -/* -struct CRegId -{ - Byte Flags; - char Id[23]; - char Suffix[8]; - - void Parse(const Byte *buf); -}; -*/ - -// ---------- ECMA Part 3: Volume Structure ---------- - -// ECMA 3/10.5 - -struct CPartition -{ - // UInt16 Flags; - UInt16 Number; - // CRegId ContentsId; - // Byte ContentsUse[128]; - // UInt32 AccessType; - - UInt32 Pos; - UInt32 Len; - - // CRegId ImplId; - // Byte ImplUse[128]; - - int VolIndex; - CMap32 Map; - - CPartition(): VolIndex(-1) {} - - // bool IsNsr() const { return (strncmp(ContentsId.Id, "+NSR0", 5) == 0); } - // bool IsAllocated() const { return ((Flags & 1) != 0); } -}; - -struct CLogBlockAddr -{ - UInt32 Pos; - UInt16 PartitionRef; - - void Parse(const Byte *buf); -}; - -enum EShortAllocDescType -{ - SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated = 0, - SHORT_ALLOC_DESC_TYPE_NotRecordedButAllocated = 1, - SHORT_ALLOC_DESC_TYPE_NotRecordedAndNotAllocated = 2, - SHORT_ALLOC_DESC_TYPE_NextExtent = 3 -}; - -struct CShortAllocDesc -{ - UInt32 Len; - UInt32 Pos; - - // 4/14.14.1 - // UInt32 GetLen() const { return Len & 0x3FFFFFFF; } - // UInt32 GetType() const { return Len >> 30; } - // bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } - void Parse(const Byte *buf); -}; - -/* -struct CADImpUse -{ - UInt16 Flags; - UInt32 UdfUniqueId; - void Parse(const Byte *buf); -}; -*/ - -struct CLongAllocDesc -{ - UInt32 Len; - CLogBlockAddr Location; - - // Byte ImplUse[6]; - // CADImpUse adImpUse; // UDF - - UInt32 GetLen() const { return Len & 0x3FFFFFFF; } - UInt32 GetType() const { return Len >> 30; } - bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } - void Parse(const Byte *buf); -}; - -struct CPartitionMap -{ - Byte Type; - // Byte Len; - - // Type - 1 - // UInt16 VolSeqNumber; - UInt16 PartitionNumber; - - // Byte Data[256]; - - int PartitionIndex; -}; - -// ECMA 4/14.6 - -enum EIcbFileType -{ - ICB_FILE_TYPE_DIR = 4, - ICB_FILE_TYPE_FILE = 5 -}; - -enum EIcbDescriptorType -{ - ICB_DESC_TYPE_SHORT = 0, - ICB_DESC_TYPE_LONG = 1, - ICB_DESC_TYPE_EXTENDED = 2, - ICB_DESC_TYPE_INLINE = 3 -}; - -struct CIcbTag -{ - // UInt32 PriorDirectNum; - // UInt16 StrategyType; - // UInt16 StrategyParam; - // UInt16 MaxNumOfEntries; - Byte FileType; - // CLogBlockAddr ParentIcb; - UInt16 Flags; - - bool IsDir() const { return FileType == ICB_FILE_TYPE_DIR; } - int GetDescriptorType() const { return Flags & 3; } - void Parse(const Byte *p); -}; - -// const Byte FILEID_CHARACS_Existance = (1 << 0); -const Byte FILEID_CHARACS_Parent = (1 << 3); - -struct CFile -{ - // UInt16 FileVersion; - // Byte FileCharacteristics; - // CByteBuffer ImplUse; - CDString Id; - - int ItemIndex; - - CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {} - UString GetName() const { return Id.GetString(); } -}; - -struct CMyExtent -{ - UInt32 Pos; - UInt32 Len; - unsigned PartitionRef; - - UInt32 GetLen() const { return Len & 0x3FFFFFFF; } - UInt32 GetType() const { return Len >> 30; } - bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } -}; - -struct CItem -{ - CIcbTag IcbTag; - - // UInt32 Uid; - // UInt32 Gid; - // UInt32 Permissions; - // UInt16 FileLinkCount; - // Byte RecordFormat; - // Byte RecordDisplayAttr; - // UInt32 RecordLen; - UInt64 Size; - UInt64 NumLogBlockRecorded; - CTime ATime; - CTime MTime; - // CTime AttrtTime; - // UInt32 CheckPoint; - // CLongAllocDesc ExtendedAttrIcb; - // CRegId ImplId; - // UInt64 UniqueId; - - bool IsInline; - CByteBuffer InlineData; - CRecordVector Extents; - CUIntVector SubFiles; - - void Parse(const Byte *buf); - - 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 -{ - int Parent; - unsigned FileIndex; -}; - - -// ECMA 4 / 14.1 -struct CFileSet -{ - CTime RecodringTime; - // UInt16 InterchangeLevel; - // UInt16 MaxInterchangeLevel; - // UInt32 FileSetNumber; - // UInt32 FileSetDescNumber; - // CDString32 Id; - // CDString32 CopyrightId; - // CDString32 AbstractId; - - CLongAllocDesc RootDirICB; - // CRegId DomainId; - // CLongAllocDesc SystemStreamDirICB; - - CRecordVector Refs; -}; - - -// ECMA 3/10.6 - -struct CLogVol -{ - CDString128 Id; - UInt32 BlockSize; - // CRegId DomainId; - - // Byte ContentsUse[16]; - CLongAllocDesc FileSetLocation; // UDF - - // CRegId ImplId; - // Byte ImplUse[128]; - - CObjectVector PartitionMaps; - CObjectVector FileSets; - - UString GetName() const { return Id.GetString(); } -}; - -struct CProgressVirt -{ - virtual HRESULT SetTotal(UInt64 numBytes) PURE; - virtual HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes) PURE; - virtual HRESULT SetCompleted() PURE; -}; - -class CInArchive -{ - IInStream *_stream; - CProgressVirt *_progress; - - HRESULT Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf); - HRESULT Read(int volIndex, const CLongAllocDesc &lad, Byte *buf); - HRESULT ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf); - - HRESULT ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed); - HRESULT ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed); - - HRESULT Open2(); - HRESULT FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed); - - UInt64 _processedProgressBytes; - - UInt64 _fileNameLengthTotal; - int _numRefs; - UInt32 _numExtents; - UInt64 _inlineExtentsSize; - bool CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const; - -public: - CObjectVector Partitions; - CObjectVector LogVols; - - CObjectVector Items; - CObjectVector Files; - - unsigned SecLogSize; - UInt64 PhySize; - UInt64 FileSize; - - bool IsArc; - bool Unsupported; - bool UnexpectedEnd; - bool NoEndAnchor; - - void UpdatePhySize(UInt64 val) - { - if (PhySize < val) - PhySize = val; - } - HRESULT Open(IInStream *inStream, CProgressVirt *progress); - void Clear(); - - UString GetComment() const; - UString GetItemPath(int volIndex, int fsIndex, int refIndex, - bool showVolName, bool showFsName) const; - - bool CheckItemExtents(int volIndex, const CItem &item) const; -}; - -API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size); - -}} - -#endif +// Archive/UdfIn.h -- UDF / ECMA-167 + +#ifndef __ARCHIVE_UDF_IN_H +#define __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 + +/* +struct CDString32 +{ + Byte Data[32]; + + void Parse(const Byte *buf); + // 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 + +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 + +/* +struct CRegId +{ + Byte Flags; + char Id[23]; + char Suffix[8]; + + void Parse(const Byte *buf); +}; +*/ + +// ---------- ECMA Part 3: Volume Structure ---------- + +// ECMA 3/10.5 + +struct CPartition +{ + // UInt16 Flags; + UInt16 Number; + // CRegId ContentsId; + // Byte ContentsUse[128]; + // UInt32 AccessType; + + UInt32 Pos; + UInt32 Len; + + // CRegId ImplId; + // Byte ImplUse[128]; + + int VolIndex; + CMap32 Map; + + CPartition(): VolIndex(-1) {} + + // bool IsNsr() const { return (strncmp(ContentsId.Id, "+NSR0", 5) == 0); } + // bool IsAllocated() const { return ((Flags & 1) != 0); } +}; + +struct CLogBlockAddr +{ + UInt32 Pos; + UInt16 PartitionRef; + + void Parse(const Byte *buf); +}; + +enum EShortAllocDescType +{ + SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated = 0, + SHORT_ALLOC_DESC_TYPE_NotRecordedButAllocated = 1, + SHORT_ALLOC_DESC_TYPE_NotRecordedAndNotAllocated = 2, + SHORT_ALLOC_DESC_TYPE_NextExtent = 3 +}; + +struct CShortAllocDesc +{ + UInt32 Len; + UInt32 Pos; + + // 4/14.14.1 + // UInt32 GetLen() const { return Len & 0x3FFFFFFF; } + // UInt32 GetType() const { return Len >> 30; } + // bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } + void Parse(const Byte *buf); +}; + +/* +struct CADImpUse +{ + UInt16 Flags; + UInt32 UdfUniqueId; + void Parse(const Byte *buf); +}; +*/ + +struct CLongAllocDesc +{ + UInt32 Len; + CLogBlockAddr Location; + + // Byte ImplUse[6]; + // CADImpUse adImpUse; // UDF + + UInt32 GetLen() const { return Len & 0x3FFFFFFF; } + UInt32 GetType() const { return Len >> 30; } + bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } + void Parse(const Byte *buf); +}; + +struct CPartitionMap +{ + Byte Type; + // Byte Len; + + // Type - 1 + // UInt16 VolSeqNumber; + UInt16 PartitionNumber; + + // Byte Data[256]; + + int PartitionIndex; +}; + +// ECMA 4/14.6 + +enum EIcbFileType +{ + ICB_FILE_TYPE_DIR = 4, + ICB_FILE_TYPE_FILE = 5 +}; + +enum EIcbDescriptorType +{ + ICB_DESC_TYPE_SHORT = 0, + ICB_DESC_TYPE_LONG = 1, + ICB_DESC_TYPE_EXTENDED = 2, + ICB_DESC_TYPE_INLINE = 3 +}; + +struct CIcbTag +{ + // UInt32 PriorDirectNum; + // UInt16 StrategyType; + // UInt16 StrategyParam; + // UInt16 MaxNumOfEntries; + Byte FileType; + // CLogBlockAddr ParentIcb; + UInt16 Flags; + + bool IsDir() const { return FileType == ICB_FILE_TYPE_DIR; } + int GetDescriptorType() const { return Flags & 3; } + void Parse(const Byte *p); +}; + +// const Byte FILEID_CHARACS_Existance = (1 << 0); +const Byte FILEID_CHARACS_Parent = (1 << 3); + +struct CFile +{ + // UInt16 FileVersion; + // Byte FileCharacteristics; + // CByteBuffer ImplUse; + CDString Id; + + int ItemIndex; + + CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {} + UString GetName() const { return Id.GetString(); } +}; + +struct CMyExtent +{ + UInt32 Pos; + UInt32 Len; + unsigned PartitionRef; + + UInt32 GetLen() const { return Len & 0x3FFFFFFF; } + UInt32 GetType() const { return Len >> 30; } + bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } +}; + +struct CItem +{ + CIcbTag IcbTag; + + // UInt32 Uid; + // UInt32 Gid; + // UInt32 Permissions; + // UInt16 FileLinkCount; + // Byte RecordFormat; + // Byte RecordDisplayAttr; + // UInt32 RecordLen; + UInt64 Size; + UInt64 NumLogBlockRecorded; + CTime ATime; + CTime MTime; + // CTime AttrtTime; + // UInt32 CheckPoint; + // CLongAllocDesc ExtendedAttrIcb; + // CRegId ImplId; + // UInt64 UniqueId; + + bool IsInline; + CByteBuffer InlineData; + CRecordVector Extents; + CUIntVector SubFiles; + + void Parse(const Byte *buf); + + 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 +{ + int Parent; + unsigned FileIndex; +}; + + +// ECMA 4 / 14.1 +struct CFileSet +{ + CTime RecodringTime; + // UInt16 InterchangeLevel; + // UInt16 MaxInterchangeLevel; + // UInt32 FileSetNumber; + // UInt32 FileSetDescNumber; + // CDString32 Id; + // CDString32 CopyrightId; + // CDString32 AbstractId; + + CLongAllocDesc RootDirICB; + // CRegId DomainId; + // CLongAllocDesc SystemStreamDirICB; + + CRecordVector Refs; +}; + + +// ECMA 3/10.6 + +struct CLogVol +{ + CDString128 Id; + UInt32 BlockSize; + // CRegId DomainId; + + // Byte ContentsUse[16]; + CLongAllocDesc FileSetLocation; // UDF + + // CRegId ImplId; + // Byte ImplUse[128]; + + CObjectVector PartitionMaps; + CObjectVector FileSets; + + UString GetName() const { return Id.GetString(); } +}; + +struct CProgressVirt +{ + virtual HRESULT SetTotal(UInt64 numBytes) PURE; + virtual HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes) PURE; + virtual HRESULT SetCompleted() PURE; +}; + +class CInArchive +{ + IInStream *_stream; + CProgressVirt *_progress; + + HRESULT Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf); + HRESULT Read(int volIndex, const CLongAllocDesc &lad, Byte *buf); + HRESULT ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf); + + HRESULT ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed); + HRESULT ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed); + + HRESULT Open2(); + HRESULT FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed); + + UInt64 _processedProgressBytes; + + UInt64 _fileNameLengthTotal; + int _numRefs; + UInt32 _numExtents; + UInt64 _inlineExtentsSize; + bool CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const; + +public: + CObjectVector Partitions; + CObjectVector LogVols; + + CObjectVector Items; + CObjectVector Files; + + unsigned SecLogSize; + UInt64 PhySize; + UInt64 FileSize; + + bool IsArc; + bool Unsupported; + bool UnexpectedEnd; + bool NoEndAnchor; + + void UpdatePhySize(UInt64 val) + { + if (PhySize < val) + PhySize = val; + } + HRESULT Open(IInStream *inStream, CProgressVirt *progress); + void Clear(); + + UString GetComment() const; + UString GetItemPath(int volIndex, int fsIndex, int refIndex, + bool showVolName, bool showFsName) const; + + bool CheckItemExtents(int volIndex, const CItem &item) const; +}; + +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 index e67c9465c..5892d5684 100644 --- a/CPP/7zip/Archive/UefiHandler.cpp +++ b/CPP/7zip/Archive/UefiHandler.cpp @@ -1,1892 +1,1892 @@ -// UefiHandler.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#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 -}; - -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 < 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 == 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 < ARRAY_SIZE(kGuids); i++) - if (AreGuidsEq(p, kGuids[i])) - return i; - return -1; -} - -static bool IsFfs(const Byte *p) -{ - if (Get32(p + 0x28) != kFvSignature) - return false; - for (unsigned i = 0; i < 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 > 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, ARRAY_SIZE(pairs), value) -#define TYPE_TO_STRING(table, value) TypeToString(table, ARRAY_SIZE(table), value) -#define TYPE_PAIR_TO_STRING(table, value) TypePairToString(table, 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) - { - int 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; - int NumChilds; - bool IsDir; - bool Skip; - bool ThereAreSubDirs; - bool ThereIsUniqueName; - bool KeepName; - - int 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(NameIndex, sz); - ConvertUInt32ToString(numChildsInParent - 1, sz2); - int numZeros = (int)strlen(sz2) - (int)strlen(sz); - AString res; - for (int i = 0; i < numZeros; i++) - res += '0'; - res += sz; - res += '.'; - res += Name; - return res; -} - -struct CItem2 -{ - AString Name; - AString Characts; - int MainIndex; - int Parent; - - CItem2(): Parent(-1) {} -}; - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - CObjectVector _items; - CObjectVector _items2; - CObjectVector _bufs; - UString _comment; - UInt32 _methodsMask; - bool _capsuleMode; - bool _headersError; - - size_t _totalBufsSize; - CCapsuleHeader _h; - UInt64 _phySize; - - void AddCommentString(const char *name, UInt32 pos); - int AddItem(const CItem &item); - int AddFileItemWithIndex(CItem &item); - int AddDirItem(CItem &item); - unsigned AddBuf(size_t size); - - HRESULT DecodeLzma(const Byte *data, size_t inputSize); - - HRESULT ParseSections(int bufIndex, UInt32 pos, UInt32 size, int parent, int method, unsigned level, bool &error); - - HRESULT ParseIntelMe(int bufIndex, UInt32 posBase, - UInt32 exactSize, UInt32 limitSize, - int parent, int method, int level); - - HRESULT ParseVolume(int bufIndex, UInt32 posBase, - UInt32 exactSize, UInt32 limitSize, - int parent, int method, int 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) {} - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - // kpidOffset, - kpidMethod, - kpidCharacts -}; - -static const Byte kArcProps[] = -{ - kpidComment, - kpidMethod, - kpidCharacts -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP 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; -} - -STDMETHODIMP 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(int level) -{ - PRF(printf("\n")); - for (int i = 0; i < level; i++) - PRF(printf(" ")); -} -static void MyPrint(UInt32 posBase, UInt32 size, int 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 - - - -int CHandler::AddItem(const CItem &item) -{ - if (_items.Size() >= kNumFilesMax) - throw 2; - return _items.Add(item); -} - -int CHandler::AddFileItemWithIndex(CItem &item) -{ - int nameIndex = _items.Size(); - if (item.Parent >= 0) - nameIndex = _items[item.Parent].NumChilds++; - item.NameIndex = nameIndex; - return AddItem(item); -} - -int 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(int 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 = 0; - CMyComPtr 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 inStream = inStreamSpec; - - CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; - CMyComPtr 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); - UInt32 dataOffset = Get16(p + 4 + kGuidSize); - 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; - 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 = AddDirItem(item); - bool error2; - RINOK(ParseSections(newBufIndex, newOffset, newSectSize, newParent, newMethod, level, error2)); - } - else if (type == SECTION_FIRMWARE_VOLUME_IMAGE) - { - item.KeepName = false; - int newParent = 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"; - int newParent = AddDirItem(item); - RINOK(ParseVolume(bufIndex, posBase + pos + 4 + kInsydeOffset, - sectDataSize - kInsydeOffset, - sectDataSize - kInsydeOffset, - 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( - int bufIndex, UInt32 posBase, - UInt32 exactSize, UInt32 limitSize, - int parent, int method, int 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 guidsVector; - - for (;;) - { - UInt32 rem = (UInt32)ffsHeader.VolSize - pos; - if (rem < kFileHeaderSize) - break; - pos = (pos + 7) & ~7; - 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) - { - int newParent = AddDirItem(item); - 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, 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 - */ - { - int newParent = AddDirItem(item); - bool error2; - RINOK(ParseSections(bufIndex, offset, sectSize, 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( - int bufIndex, UInt32 posBase, - UInt32 exactSize, UInt32 limitSize, - int parent, int method, int 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(stream->Seek(0, STREAM_SEEK_SET, NULL)); - 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)); - } - - unsigned num = _items.Size(); - CIntArr numChilds(num); - - unsigned i; - - for (i = 0; i < num; i++) - numChilds[i] = 0; - - for (i = 0; i < num; i++) - { - int parent = _items[i].Parent; - if (parent >= 0) - numChilds[(unsigned)parent]++; - } - - for (i = 0; i < num; i++) - { - const CItem &item = _items[i]; - 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 = 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; -} - -STDMETHODIMP 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 -} - -STDMETHODIMP CHandler::Close() -{ - _phySize = 0; - _totalBufsSize = 0; - _methodsMask = 0; - _items.Clear(); - _items2.Clear(); - _bufs.Clear(); - _comment.Empty(); - _headersError = false; - _h.Clear(); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items2.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - for (i = 0; i < numItems; i++) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()); - CMyComPtr realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - 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 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 -} - -STDMETHODIMP 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 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", 0, 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", 0, 0xD1, - k_FFS_Signatures, - kFfsGuidOffset, - NArcInfoFlags::kMultiSignature | - NArcInfoFlags::kFindSignature, - NULL) - -} - -}} +// UefiHandler.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#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 +}; + +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 < 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 == 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 < ARRAY_SIZE(kGuids); i++) + if (AreGuidsEq(p, kGuids[i])) + return i; + return -1; +} + +static bool IsFfs(const Byte *p) +{ + if (Get32(p + 0x28) != kFvSignature) + return false; + for (unsigned i = 0; i < 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 > 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, ARRAY_SIZE(pairs), value) +#define TYPE_TO_STRING(table, value) TypeToString(table, ARRAY_SIZE(table), value) +#define TYPE_PAIR_TO_STRING(table, value) TypePairToString(table, 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) + { + int 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; + int NumChilds; + bool IsDir; + bool Skip; + bool ThereAreSubDirs; + bool ThereIsUniqueName; + bool KeepName; + + int 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(NameIndex, sz); + ConvertUInt32ToString(numChildsInParent - 1, sz2); + int numZeros = (int)strlen(sz2) - (int)strlen(sz); + AString res; + for (int i = 0; i < numZeros; i++) + res += '0'; + res += sz; + res += '.'; + res += Name; + return res; +} + +struct CItem2 +{ + AString Name; + AString Characts; + int MainIndex; + int Parent; + + CItem2(): Parent(-1) {} +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CObjectVector _items; + CObjectVector _items2; + CObjectVector _bufs; + UString _comment; + UInt32 _methodsMask; + bool _capsuleMode; + bool _headersError; + + size_t _totalBufsSize; + CCapsuleHeader _h; + UInt64 _phySize; + + void AddCommentString(const char *name, UInt32 pos); + int AddItem(const CItem &item); + int AddFileItemWithIndex(CItem &item); + int AddDirItem(CItem &item); + unsigned AddBuf(size_t size); + + HRESULT DecodeLzma(const Byte *data, size_t inputSize); + + HRESULT ParseSections(int bufIndex, UInt32 pos, UInt32 size, int parent, int method, unsigned level, bool &error); + + HRESULT ParseIntelMe(int bufIndex, UInt32 posBase, + UInt32 exactSize, UInt32 limitSize, + int parent, int method, int level); + + HRESULT ParseVolume(int bufIndex, UInt32 posBase, + UInt32 exactSize, UInt32 limitSize, + int parent, int method, int 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) {} + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + // kpidOffset, + kpidMethod, + kpidCharacts +}; + +static const Byte kArcProps[] = +{ + kpidComment, + kpidMethod, + kpidCharacts +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP 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; +} + +STDMETHODIMP 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(int level) +{ + PRF(printf("\n")); + for (int i = 0; i < level; i++) + PRF(printf(" ")); +} +static void MyPrint(UInt32 posBase, UInt32 size, int 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 + + + +int CHandler::AddItem(const CItem &item) +{ + if (_items.Size() >= kNumFilesMax) + throw 2; + return _items.Add(item); +} + +int CHandler::AddFileItemWithIndex(CItem &item) +{ + int nameIndex = _items.Size(); + if (item.Parent >= 0) + nameIndex = _items[item.Parent].NumChilds++; + item.NameIndex = nameIndex; + return AddItem(item); +} + +int 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(int 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 = 0; + CMyComPtr 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 inStream = inStreamSpec; + + CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; + CMyComPtr 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); + UInt32 dataOffset = Get16(p + 4 + kGuidSize); + 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; + 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 = AddDirItem(item); + bool error2; + RINOK(ParseSections(newBufIndex, newOffset, newSectSize, newParent, newMethod, level, error2)); + } + else if (type == SECTION_FIRMWARE_VOLUME_IMAGE) + { + item.KeepName = false; + int newParent = 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"; + int newParent = AddDirItem(item); + RINOK(ParseVolume(bufIndex, posBase + pos + 4 + kInsydeOffset, + sectDataSize - kInsydeOffset, + sectDataSize - kInsydeOffset, + 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( + int bufIndex, UInt32 posBase, + UInt32 exactSize, UInt32 limitSize, + int parent, int method, int 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 guidsVector; + + for (;;) + { + UInt32 rem = (UInt32)ffsHeader.VolSize - pos; + if (rem < kFileHeaderSize) + break; + pos = (pos + 7) & ~7; + 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) + { + int newParent = AddDirItem(item); + 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, 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 + */ + { + int newParent = AddDirItem(item); + bool error2; + RINOK(ParseSections(bufIndex, offset, sectSize, 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( + int bufIndex, UInt32 posBase, + UInt32 exactSize, UInt32 limitSize, + int parent, int method, int 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(stream->Seek(0, STREAM_SEEK_SET, NULL)); + 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)); + } + + unsigned num = _items.Size(); + CIntArr numChilds(num); + + unsigned i; + + for (i = 0; i < num; i++) + numChilds[i] = 0; + + for (i = 0; i < num; i++) + { + int parent = _items[i].Parent; + if (parent >= 0) + numChilds[(unsigned)parent]++; + } + + for (i = 0; i < num; i++) + { + const CItem &item = _items[i]; + 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 = 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; +} + +STDMETHODIMP 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 +} + +STDMETHODIMP CHandler::Close() +{ + _phySize = 0; + _totalBufsSize = 0; + _methodsMask = 0; + _items.Clear(); + _items2.Clear(); + _bufs.Clear(); + _comment.Empty(); + _headersError = false; + _h.Clear(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items2.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + CMyComPtr realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + 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 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 +} + +STDMETHODIMP 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 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", 0, 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", 0, 0xD1, + k_FFS_Signatures, + kFfsGuidOffset, + NArcInfoFlags::kMultiSignature | + NArcInfoFlags::kFindSignature, + NULL) + +} + +}} diff --git a/CPP/7zip/Archive/VdiHandler.cpp b/CPP/7zip/Archive/VdiHandler.cpp index 32d5e57e5..b8ef35bb2 100644 --- a/CPP/7zip/Archive/VdiHandler.cpp +++ b/CPP/7zip/Archive/VdiHandler.cpp @@ -1,431 +1,431 @@ -// VdiHandler.cpp - -#include "StdAfx.h" - -// #include - -#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 Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -using namespace NWindows; - -namespace NArchive { -namespace NVdi { - -#define SIGNATURE { 0x7F, 0x10, 0xDA, 0xBE } - -static const Byte k_Signature[] = SIGNATURE; - -static const unsigned k_ClusterBits = 20; -static const UInt32 k_ClusterSize = (UInt32)1 << k_ClusterBits; -static const UInt32 k_UnusedCluster = 0xFFFFFFFF; - - -// 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; -} - - - -class CHandler: public CHandlerImg -{ - UInt32 _dataOffset; - CByteBuffer _table; - UInt64 _phySize; - UInt32 _imageType; - bool _isArc; - bool _unsupported; - - Byte Guids[kNumGuids][16]; - - HRESULT Seek(UInt64 offset) - { - _posInArc = offset; - return Stream->Seek(offset, STREAM_SEEK_SET, NULL); - } - - HRESULT InitAndSeek() - { - _virtPos = 0; - return Seek(0); - } - - HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback); - -public: - INTERFACE_IInArchive_Img(;) - - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); -}; - - -STDMETHODIMP 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; - UInt32 v = Get32(p); - if (v != k_UnusedCluster) - { - UInt64 offset = _dataOffset + ((UInt64)v << k_ClusterBits); - offset += lowBits; - if (offset != _posInArc) - { - RINOK(Seek(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 - -STDMETHODIMP 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); - strcat(temp, ".vdi"); - prop = temp; - } - break; - } - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - 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(stream->Seek(tableOffset, STREAM_SEEK_SET, NULL)); - RINOK(ReadStream_FALSE(stream, _table, numBytes)); - - const Byte *data = _table; - for (UInt32 i = 0; i < totalBlocks; i++) - { - UInt32 v = Get32(data + (size_t)i * 4); - if (v == k_UnusedCluster) - continue; - if (v >= numAllocatedBlocks) - { - _unsupported = true; - return S_FALSE; - } - } - - Stream = stream; - return S_OK; -} - - -STDMETHODIMP CHandler::Close() -{ - _table.Free(); - _phySize = 0; - _size = 0; - _isArc = false; - _unsupported = false; - - for (unsigned i = 0; i < kNumGuids; i++) - memset(Guids[i], 0, 16); - - _imgExt = NULL; - Stream.Release(); - return S_OK; -} - - -STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - *stream = NULL; - if (_unsupported) - return S_FALSE; - CMyComPtr 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) - -}} +// VdiHandler.cpp + +#include "StdAfx.h" + +// #include + +#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 Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +using namespace NWindows; + +namespace NArchive { +namespace NVdi { + +#define SIGNATURE { 0x7F, 0x10, 0xDA, 0xBE } + +static const Byte k_Signature[] = SIGNATURE; + +static const unsigned k_ClusterBits = 20; +static const UInt32 k_ClusterSize = (UInt32)1 << k_ClusterBits; +static const UInt32 k_UnusedCluster = 0xFFFFFFFF; + + +// 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; +} + + + +class CHandler: public CHandlerImg +{ + UInt32 _dataOffset; + CByteBuffer _table; + UInt64 _phySize; + UInt32 _imageType; + bool _isArc; + bool _unsupported; + + Byte Guids[kNumGuids][16]; + + HRESULT Seek(UInt64 offset) + { + _posInArc = offset; + return Stream->Seek(offset, STREAM_SEEK_SET, NULL); + } + + HRESULT InitAndSeek() + { + _virtPos = 0; + return Seek(0); + } + + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback); + +public: + INTERFACE_IInArchive_Img(;) + + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + + +STDMETHODIMP 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; + UInt32 v = Get32(p); + if (v != k_UnusedCluster) + { + UInt64 offset = _dataOffset + ((UInt64)v << k_ClusterBits); + offset += lowBits; + if (offset != _posInArc) + { + RINOK(Seek(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 + +STDMETHODIMP 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); + strcat(temp, ".vdi"); + prop = temp; + } + break; + } + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + 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(stream->Seek(tableOffset, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(stream, _table, numBytes)); + + const Byte *data = _table; + for (UInt32 i = 0; i < totalBlocks; i++) + { + UInt32 v = Get32(data + (size_t)i * 4); + if (v == k_UnusedCluster) + continue; + if (v >= numAllocatedBlocks) + { + _unsupported = true; + return S_FALSE; + } + } + + Stream = stream; + return S_OK; +} + + +STDMETHODIMP CHandler::Close() +{ + _table.Free(); + _phySize = 0; + _size = 0; + _isArc = false; + _unsupported = false; + + for (unsigned i = 0; i < kNumGuids; i++) + memset(Guids[i], 0, 16); + + _imgExt = NULL; + Stream.Release(); + return S_OK; +} + + +STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = NULL; + if (_unsupported) + return S_FALSE; + CMyComPtr 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 index c29482df2..d79ae907a 100644 --- a/CPP/7zip/Archive/VhdHandler.cpp +++ b/CPP/7zip/Archive/VhdHandler.cpp @@ -1,921 +1,921 @@ -// 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 { - -#define SIGNATURE { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x', 0, 0 } - -static const unsigned kSignatureSize = 10; -static const Byte kSignature[kSignatureSize] = SIGNATURE; - -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 < 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); -} - -class CHandler: public CHandlerImg -{ - UInt64 _posInArcLimit; - UInt64 _startOffset; - UInt64 _phySize; - - CFooter Footer; - CDynHeader Dyn; - CRecordVector Bat; - CByteBuffer BitMap; - UInt32 BitMapTag; - UInt32 NumUsedBlocks; - // CMyComPtr Stream; - CMyComPtr ParentStream; - CHandler *Parent; - 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; - } - - void Reset_PosInArc() { _posInArc = (UInt64)0 - 1; } - HRESULT Seek(UInt64 offset); - HRESULT InitAndSeek(); - HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size); - - bool NeedParent() const { return Footer.Type == kDiskType_Diff; } - UInt64 GetPackSize() const - { return Footer.ThereIsDynamic() ? ((UInt64)NumUsedBlocks << Dyn.BlockSizeLog) : Footer.CurrentSize; } - - UString 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) - { - return Open2(stream, NULL, openArchiveCallback, 0); - } - void CloseAtError(); - -public: - INTERFACE_IInArchive_Img(;) - - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); -}; - -HRESULT CHandler::Seek(UInt64 offset) { return Stream->Seek(_startOffset + offset, STREAM_SEEK_SET, NULL); } - -HRESULT CHandler::InitAndSeek() -{ - if (ParentStream) - { - RINOK(Parent->InitAndSeek()); - } - _virtPos = _posInArc = 0; - BitMapTag = kUnusedBlock; - BitMap.Alloc(Dyn.NumBitMapSectors() << kSectorSize_Log); - return Seek(0); -} - -HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size) -{ - if (offset + size > _posInArcLimit) - return S_FALSE; - if (offset != _posInArc) - { - _posInArc = offset; - RINOK(Seek(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(Stream->Seek(0, STREAM_SEEK_CUR, &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(Stream->Seek(0, STREAM_SEEK_END, &fileSize)); - if (fileSize < kHeaderSize) - return S_FALSE; - - const UInt32 kDynSize = 1024; - Byte buf[kDynSize]; - - RINOK(Stream->Seek(fileSize - kHeaderSize, STREAM_SEEK_SET, NULL)); - 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. - _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; -} - -STDMETHODIMP 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; - UInt32 blockIndex = (UInt32)(_virtPos >> Dyn.BlockSizeLog); - UInt32 blockSectIndex = Bat[blockIndex]; - UInt32 blockSize = (UInt32)1 << Dyn.BlockSizeLog; - UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); - size = MyMin(blockSize - offsetInBlock, size); - - HRESULT res = S_OK; - if (blockSectIndex == kUnusedBlock) - { - if (ParentStream) - { - RINOK(ParentStream->Seek(_virtPos, STREAM_SEEK_SET, NULL)); - res = ParentStream->Read(data, size, &size); - } - else - memset(data, 0, size); - } - else - { - UInt64 newPos = (UInt64)blockSectIndex << 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); - UInt32 bmi = offsetInBlock >> kSectorSize_Log; - if (((BitMap[bmi >> 3] >> (7 - (bmi & 7))) & 1) == 0) - { - if (ParentStream) - { - RINOK(ParentStream->Seek(_virtPos + cur, STREAM_SEEK_SET, NULL)); - RINOK(ReadStream_FALSE(ParentStream, (Byte *)data + cur, rem)); - } - else - { - const Byte *p = (const Byte *)data + cur; - for (UInt32 i = 0; i < rem; i++) - if (p[i] != 0) - return S_FALSE; - } - } - offsetInBlock += rem; - cur += rem; - } - } - if (processedSize) - *processedSize = size; - _virtPos += size; - return res; -} - - -enum -{ - kpidParent = kpidUserDefined, - kpidSavedState -}; - -static const CStatProp kArcProps[] = -{ - { NULL, kpidSize, VT_UI8}, - { NULL, kpidOffset, VT_UI8}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidClusterSize, VT_UI8}, - { NULL, kpidMethod, VT_BSTR}, - { "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) - { - Byte b = (Byte)((val >> i) & 0xFF); - if (b < 0x20 || b > 0x7F) - break; - *dest++ = b; - } - *dest = 0; -} - -static void ConvertByteToHex(unsigned value, char *s) -{ - for (int i = 0; i < 2; i++) - { - unsigned t = value & 0xF; - value >>= 4; - s[1 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); - } -} - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidMainSubfile: prop = (UInt32)0; break; - case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break; - case kpidClusterSize: if (Footer.ThereIsDynamic()) prop = (UInt32)1 << Dyn.BlockSizeLog; break; - case 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 += '.'; - 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 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()); - - 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; - - CMyComPtr openVolumeCallback; - openArchiveCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); - - if (openVolumeCallback) - { - CMyComPtr 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 - } - } - } - { - 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() -{ - _phySize = 0; - Bat.Clear(); - NumUsedBlocks = 0; - Parent = NULL; - Stream.Release(); - ParentStream.Release(); - Dyn.Clear(); - _errorMessage.Empty(); - // _unexpectedEnd = false; - _imgExt = NULL; -} - -STDMETHODIMP CHandler::Close() -{ - CloseAtError(); - return S_OK; -} - -STDMETHODIMP 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 -} - - -STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - *stream = 0; - if (Footer.IsFixed()) - { - CLimitedInStream *streamSpec = new CLimitedInStream; - CMyComPtr streamTemp = streamSpec; - streamSpec->SetStream(Stream); - streamSpec->InitAndSeek(0, Footer.CurrentSize); - RINOK(streamSpec->SeekToStart()); - *stream = streamTemp.Detach(); - return S_OK; - } - if (!Footer.ThereIsDynamic() || !AreParentsOK()) - return S_FALSE; - CMyComPtr 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) - -}} +// 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 { + +#define SIGNATURE { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x', 0, 0 } + +static const unsigned kSignatureSize = 10; +static const Byte kSignature[kSignatureSize] = SIGNATURE; + +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 < 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); +} + +class CHandler: public CHandlerImg +{ + UInt64 _posInArcLimit; + UInt64 _startOffset; + UInt64 _phySize; + + CFooter Footer; + CDynHeader Dyn; + CRecordVector Bat; + CByteBuffer BitMap; + UInt32 BitMapTag; + UInt32 NumUsedBlocks; + // CMyComPtr Stream; + CMyComPtr ParentStream; + CHandler *Parent; + 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; + } + + void Reset_PosInArc() { _posInArc = (UInt64)0 - 1; } + HRESULT Seek(UInt64 offset); + HRESULT InitAndSeek(); + HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size); + + bool NeedParent() const { return Footer.Type == kDiskType_Diff; } + UInt64 GetPackSize() const + { return Footer.ThereIsDynamic() ? ((UInt64)NumUsedBlocks << Dyn.BlockSizeLog) : Footer.CurrentSize; } + + UString 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) + { + return Open2(stream, NULL, openArchiveCallback, 0); + } + void CloseAtError(); + +public: + INTERFACE_IInArchive_Img(;) + + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +HRESULT CHandler::Seek(UInt64 offset) { return Stream->Seek(_startOffset + offset, STREAM_SEEK_SET, NULL); } + +HRESULT CHandler::InitAndSeek() +{ + if (ParentStream) + { + RINOK(Parent->InitAndSeek()); + } + _virtPos = _posInArc = 0; + BitMapTag = kUnusedBlock; + BitMap.Alloc(Dyn.NumBitMapSectors() << kSectorSize_Log); + return Seek(0); +} + +HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size) +{ + if (offset + size > _posInArcLimit) + return S_FALSE; + if (offset != _posInArc) + { + _posInArc = offset; + RINOK(Seek(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(Stream->Seek(0, STREAM_SEEK_CUR, &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(Stream->Seek(0, STREAM_SEEK_END, &fileSize)); + if (fileSize < kHeaderSize) + return S_FALSE; + + const UInt32 kDynSize = 1024; + Byte buf[kDynSize]; + + RINOK(Stream->Seek(fileSize - kHeaderSize, STREAM_SEEK_SET, NULL)); + 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. + _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; +} + +STDMETHODIMP 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; + UInt32 blockIndex = (UInt32)(_virtPos >> Dyn.BlockSizeLog); + UInt32 blockSectIndex = Bat[blockIndex]; + UInt32 blockSize = (UInt32)1 << Dyn.BlockSizeLog; + UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); + size = MyMin(blockSize - offsetInBlock, size); + + HRESULT res = S_OK; + if (blockSectIndex == kUnusedBlock) + { + if (ParentStream) + { + RINOK(ParentStream->Seek(_virtPos, STREAM_SEEK_SET, NULL)); + res = ParentStream->Read(data, size, &size); + } + else + memset(data, 0, size); + } + else + { + UInt64 newPos = (UInt64)blockSectIndex << 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); + UInt32 bmi = offsetInBlock >> kSectorSize_Log; + if (((BitMap[bmi >> 3] >> (7 - (bmi & 7))) & 1) == 0) + { + if (ParentStream) + { + RINOK(ParentStream->Seek(_virtPos + cur, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(ParentStream, (Byte *)data + cur, rem)); + } + else + { + const Byte *p = (const Byte *)data + cur; + for (UInt32 i = 0; i < rem; i++) + if (p[i] != 0) + return S_FALSE; + } + } + offsetInBlock += rem; + cur += rem; + } + } + if (processedSize) + *processedSize = size; + _virtPos += size; + return res; +} + + +enum +{ + kpidParent = kpidUserDefined, + kpidSavedState +}; + +static const CStatProp kArcProps[] = +{ + { NULL, kpidSize, VT_UI8}, + { NULL, kpidOffset, VT_UI8}, + { NULL, kpidCTime, VT_FILETIME}, + { NULL, kpidClusterSize, VT_UI8}, + { NULL, kpidMethod, VT_BSTR}, + { "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) + { + Byte b = (Byte)((val >> i) & 0xFF); + if (b < 0x20 || b > 0x7F) + break; + *dest++ = b; + } + *dest = 0; +} + +static void ConvertByteToHex(unsigned value, char *s) +{ + for (int i = 0; i < 2; i++) + { + unsigned t = value & 0xF; + value >>= 4; + s[1 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); + } +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break; + case kpidClusterSize: if (Footer.ThereIsDynamic()) prop = (UInt32)1 << Dyn.BlockSizeLog; break; + case 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 += '.'; + 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 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()); + + 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; + + CMyComPtr openVolumeCallback; + openArchiveCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); + + if (openVolumeCallback) + { + CMyComPtr 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 + } + } + } + { + 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() +{ + _phySize = 0; + Bat.Clear(); + NumUsedBlocks = 0; + Parent = NULL; + Stream.Release(); + ParentStream.Release(); + Dyn.Clear(); + _errorMessage.Empty(); + // _unexpectedEnd = false; + _imgExt = NULL; +} + +STDMETHODIMP CHandler::Close() +{ + CloseAtError(); + return S_OK; +} + +STDMETHODIMP 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 +} + + +STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = 0; + if (Footer.IsFixed()) + { + CLimitedInStream *streamSpec = new CLimitedInStream; + CMyComPtr streamTemp = streamSpec; + streamSpec->SetStream(Stream); + streamSpec->InitAndSeek(0, Footer.CurrentSize); + RINOK(streamSpec->SeekToStart()); + *stream = streamTemp.Detach(); + return S_OK; + } + if (!Footer.ThereIsDynamic() || !AreParentsOK()) + return S_FALSE; + CMyComPtr 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/VmdkHandler.cpp b/CPP/7zip/Archive/VmdkHandler.cpp index 13c197718..942bd792c 100644 --- a/CPP/7zip/Archive/VmdkHandler.cpp +++ b/CPP/7zip/Archive/VmdkHandler.cpp @@ -1,1514 +1,1514 @@ -// VmdkHandler.cpp - -#include "StdAfx.h" - -// #include - -#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)); - - -#define SIGNATURE { 'K', 'D', 'M', 'V' } - -static const Byte k_Signature[] = SIGNATURE; - -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 = s.Left(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 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 (;;) - { - char 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 Tables; - - CMyComPtr 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 Stream->Seek(offset, STREAM_SEEK_SET, NULL); - } - - 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; - } -}; - - -class CHandler: 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 _extents; - - CBufInStream *_bufInStreamSpec; - CMyComPtr _bufInStream; - - CBufPtrSeqOutStream *_bufOutStreamSpec; - CMyComPtr _bufOutStream; - - NCompress::NZlib::CDecoder *_zlibDecoderSpec; - CMyComPtr _zlibDecoder; - - CByteBuffer _descriptorBuf; - CDescriptor _descriptor; - - UString _missingVolName; - - void InitAndSeekMain() - { - _virtPos = 0; - } - - virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback); - virtual void CloseAtError(); -public: - INTERFACE_IInArchive_Img(;) - - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); -}; - - -STDMETHODIMP 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? - UInt64 blockSize64 = clusterSize; - HRESULT res = _zlibDecoderSpec->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, - kpidMethod, - kpidClusterSize, - kpidHeadersSize, - kpidId, - kpidName, - kpidComment -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - - -STDMETHODIMP 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 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 -} - - -STDMETHODIMP 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(stream->Seek(sector, STREAM_SEEK_SET, NULL)); - 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 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(stream->Seek(0, STREAM_SEEK_END, &endPos)); - if (endPos > (1 << 20)) - return S_FALSE; - const size_t numBytes = (size_t)endPos; - _descriptorBuf.Alloc(numBytes); - RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); - 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 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(stream->Seek(0, STREAM_SEEK_END, &endPos)); - if ((endPos & 511) != 0) - return S_FALSE; - - const size_t kEndSize = 512 * 3; - Byte buf2[kEndSize]; - if (endPos < kEndSize) - return S_FALSE; - RINOK(stream->Seek(endPos - kEndSize, STREAM_SEEK_SET, NULL)); - 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; - } - - 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 + 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; - } - - { - UInt64 overHeadBytes = h.overHead << 9; - if (PhySize < overHeadBytes) - PhySize = overHeadBytes; - } - - ZeroSector = 0; - if (h.Is_ZeroGrain()) - ZeroSector = 1; - - const UInt64 numSectorsPerGde = (UInt64)1 << (grainSize_Log + k_NumMidBits); - const UInt64 numGdeEntries = (h.capacity + numSectorsPerGde - 1) >> (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; -} - - -STDMETHODIMP CHandler::Close() -{ - _phySize = 0; - _size = 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(); - - _imgExt = NULL; - Stream.Release(); // Stream vriable is unused - _extents.Clear(); - return S_OK; -} - - -STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - *stream = 0; - - 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 streamTemp = this; - InitAndSeekMain(); - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - - -REGISTER_ARC_I( - "VMDK", "vmdk", NULL, 0xC8, - k_Signature, - 0, - 0, - NULL) - -}} +// VmdkHandler.cpp + +#include "StdAfx.h" + +// #include + +#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)); + + +#define SIGNATURE { 'K', 'D', 'M', 'V' } + +static const Byte k_Signature[] = SIGNATURE; + +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 = s.Left(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 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 (;;) + { + char 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 Tables; + + CMyComPtr 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 Stream->Seek(offset, STREAM_SEEK_SET, NULL); + } + + 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; + } +}; + + +class CHandler: 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 _extents; + + CBufInStream *_bufInStreamSpec; + CMyComPtr _bufInStream; + + CBufPtrSeqOutStream *_bufOutStreamSpec; + CMyComPtr _bufOutStream; + + NCompress::NZlib::CDecoder *_zlibDecoderSpec; + CMyComPtr _zlibDecoder; + + CByteBuffer _descriptorBuf; + CDescriptor _descriptor; + + UString _missingVolName; + + void InitAndSeekMain() + { + _virtPos = 0; + } + + virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback); + virtual void CloseAtError(); +public: + INTERFACE_IInArchive_Img(;) + + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + + +STDMETHODIMP 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? + UInt64 blockSize64 = clusterSize; + HRESULT res = _zlibDecoderSpec->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, + kpidMethod, + kpidClusterSize, + kpidHeadersSize, + kpidId, + kpidName, + kpidComment +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + + +STDMETHODIMP 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 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 +} + + +STDMETHODIMP 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(stream->Seek(sector, STREAM_SEEK_SET, NULL)); + 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 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(stream->Seek(0, STREAM_SEEK_END, &endPos)); + if (endPos > (1 << 20)) + return S_FALSE; + const size_t numBytes = (size_t)endPos; + _descriptorBuf.Alloc(numBytes); + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + 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 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(stream->Seek(0, STREAM_SEEK_END, &endPos)); + if ((endPos & 511) != 0) + return S_FALSE; + + const size_t kEndSize = 512 * 3; + Byte buf2[kEndSize]; + if (endPos < kEndSize) + return S_FALSE; + RINOK(stream->Seek(endPos - kEndSize, STREAM_SEEK_SET, NULL)); + 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; + } + + 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 + 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; + } + + { + UInt64 overHeadBytes = h.overHead << 9; + if (PhySize < overHeadBytes) + PhySize = overHeadBytes; + } + + ZeroSector = 0; + if (h.Is_ZeroGrain()) + ZeroSector = 1; + + const UInt64 numSectorsPerGde = (UInt64)1 << (grainSize_Log + k_NumMidBits); + const UInt64 numGdeEntries = (h.capacity + numSectorsPerGde - 1) >> (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; +} + + +STDMETHODIMP CHandler::Close() +{ + _phySize = 0; + _size = 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(); + + _imgExt = NULL; + Stream.Release(); // Stream vriable is unused + _extents.Clear(); + return S_OK; +} + + +STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = 0; + + 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 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 index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Archive/Wim/StdAfx.h +++ b/CPP/7zip/Archive/Wim/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp index bb44228b4..927a0b386 100644 --- a/CPP/7zip/Archive/Wim/WimHandler.cpp +++ b/CPP/7zip/Archive/Wim/WimHandler.cpp @@ -1,1222 +1,1222 @@ -// 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; -} - - -STDMETHODIMP 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 = 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 = 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 += '.'; - res.Add_UInt32(ver2); - if (ver3 != 0) - { - res += '.'; - 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 += '.'; - } - 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 < 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 < 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 -} - -void GetFileTime(const Byte *p, NCOM::CPropVariant &prop) -{ - prop.vt = VT_FILETIME; - prop.filetime.dwLowDateTime = Get32(p); - prop.filetime.dwHighDateTime = Get32(p + 4); -} - - -static void MethodToProp(int method, int chunksSizeBits, NCOM::CPropVariant &prop) -{ - if (method >= 0) - { - char temp[32]; - - if ((unsigned)method < ARRAY_SIZE(k_Methods)) - strcpy(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; - } -} - - -STDMETHODIMP 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(item.StreamIndex); - prop = s; - } - break; - - case kpidName: - if (item.ImageIndex >= 0) - _db.GetItemName(realIndex, prop); - else - { - char sz[16]; - ConvertUInt32ToString(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, ss.ChunkSizeBits, prop); - } - } - else - { - int method = 0; - int chunkSizeBits = -1; - if (r.IsCompressed()) - { - method = vol->Header.GetMethod(); - chunkSizeBits = 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 -} - -STDMETHODIMP 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; -} - -STDMETHODIMP CHandler::GetRootRawProp(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) -{ - *data = 0; - *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 -}; - - -STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) -{ - *numProps = ARRAY_SIZE(kRawProps); - return S_OK; -} - -STDMETHODIMP CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) -{ - *propID = kRawProps[index]; - *name = 0; - return S_OK; -} - -STDMETHODIMP 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 = _db.Items[item.Parent].IndexInSorted; - } - else - { - CImage &image = _db.Images[item.ImageIndex]; - if (image.VirtualRootIndex >= 0) - *parent = _db.SortedItems.Size() + _numXmlItems + image.VirtualRootIndex; - } - } - else - *parent = _db.SortedItems.Size() + _numXmlItems + _db.VirtualRoots.Size(); - return S_OK; -} - -STDMETHODIMP 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 = name.Len(); - _before = name.Left(dotPos); - _after = name.Ptr(dotPos); - } - - UString GetNextName(UInt32 index) const - { - UString s = _before; - s.Add_UInt32(index); - s += _after; - return s; - } -}; - -STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback) -{ - COM_TRY_BEGIN - - Close(); - { - CMyComPtr openVolumeCallback; - - CVolumeName seqName; - if (callback) - callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); - - UInt32 numVolumes = 1; - - for (UInt32 i = 1; i <= numVolumes; i++) - { - CMyComPtr curStream; - - if (i == 1) - curStream = inStream; - else - { - UString fullName = seqName.GetNextName(i); - HRESULT result = openVolumeCallback->GetStream(fullName, &curStream); - if (result == S_FALSE) - continue; - if (result != S_OK) - return result; - if (!curStream) - break; - } - - 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 -} - - -STDMETHODIMP 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; -} - - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - 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 < (UInt32)_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 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]; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - - CMyComPtr 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 < (UInt32)_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 -} - - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _db.SortedItems.Size() + - _numXmlItems + - _db.VirtualRoots.Size() + - _numIgnoreItems; - return S_OK; -} - -CHandler::CHandler() -{ - _keepMode_ShowImageNumber = false; - InitDefaults(); - _xmlError = false; -} - -STDMETHODIMP 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 = image; - } - else - return E_INVALIDARG; - } - return S_OK; -} - -STDMETHODIMP CHandler::KeepModeForNextOpen() -{ - _keepMode_ShowImageNumber = _showImageNumber; - return S_OK; -} - -}} +// 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; +} + + +STDMETHODIMP 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 = 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 = 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 += '.'; + res.Add_UInt32(ver2); + if (ver3 != 0) + { + res += '.'; + 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 += '.'; + } + 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 < 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 < 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 +} + +void GetFileTime(const Byte *p, NCOM::CPropVariant &prop) +{ + prop.vt = VT_FILETIME; + prop.filetime.dwLowDateTime = Get32(p); + prop.filetime.dwHighDateTime = Get32(p + 4); +} + + +static void MethodToProp(int method, int chunksSizeBits, NCOM::CPropVariant &prop) +{ + if (method >= 0) + { + char temp[32]; + + if ((unsigned)method < ARRAY_SIZE(k_Methods)) + strcpy(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; + } +} + + +STDMETHODIMP 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(item.StreamIndex); + prop = s; + } + break; + + case kpidName: + if (item.ImageIndex >= 0) + _db.GetItemName(realIndex, prop); + else + { + char sz[16]; + ConvertUInt32ToString(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, ss.ChunkSizeBits, prop); + } + } + else + { + int method = 0; + int chunkSizeBits = -1; + if (r.IsCompressed()) + { + method = vol->Header.GetMethod(); + chunkSizeBits = 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 +} + +STDMETHODIMP 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; +} + +STDMETHODIMP CHandler::GetRootRawProp(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) +{ + *data = 0; + *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 +}; + + +STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) +{ + *numProps = ARRAY_SIZE(kRawProps); + return S_OK; +} + +STDMETHODIMP CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) +{ + *propID = kRawProps[index]; + *name = 0; + return S_OK; +} + +STDMETHODIMP 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 = _db.Items[item.Parent].IndexInSorted; + } + else + { + CImage &image = _db.Images[item.ImageIndex]; + if (image.VirtualRootIndex >= 0) + *parent = _db.SortedItems.Size() + _numXmlItems + image.VirtualRootIndex; + } + } + else + *parent = _db.SortedItems.Size() + _numXmlItems + _db.VirtualRoots.Size(); + return S_OK; +} + +STDMETHODIMP 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 = name.Len(); + _before = name.Left(dotPos); + _after = name.Ptr(dotPos); + } + + UString GetNextName(UInt32 index) const + { + UString s = _before; + s.Add_UInt32(index); + s += _after; + return s; + } +}; + +STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + + Close(); + { + CMyComPtr openVolumeCallback; + + CVolumeName seqName; + if (callback) + callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); + + UInt32 numVolumes = 1; + + for (UInt32 i = 1; i <= numVolumes; i++) + { + CMyComPtr curStream; + + if (i == 1) + curStream = inStream; + else + { + UString fullName = seqName.GetNextName(i); + HRESULT result = openVolumeCallback->GetStream(fullName, &curStream); + if (result == S_FALSE) + continue; + if (result != S_OK) + return result; + if (!curStream) + break; + } + + 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 +} + + +STDMETHODIMP 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; +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + 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 < (UInt32)_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 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]; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + + CMyComPtr 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 < (UInt32)_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 +} + + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _db.SortedItems.Size() + + _numXmlItems + + _db.VirtualRoots.Size() + + _numIgnoreItems; + return S_OK; +} + +CHandler::CHandler() +{ + _keepMode_ShowImageNumber = false; + InitDefaults(); + _xmlError = false; +} + +STDMETHODIMP 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 = image; + } + else + return E_INVALIDARG; + } + return S_OK; +} + +STDMETHODIMP CHandler::KeepModeForNextOpen() +{ + _keepMode_ShowImageNumber = _showImageNumber; + return S_OK; +} + +}} diff --git a/CPP/7zip/Archive/Wim/WimHandler.h b/CPP/7zip/Archive/Wim/WimHandler.h index 0cdc23741..3ba88d2bd 100644 --- a/CPP/7zip/Archive/Wim/WimHandler.h +++ b/CPP/7zip/Archive/Wim/WimHandler.h @@ -1,103 +1,103 @@ -// WimHandler.h - -#ifndef __ARCHIVE_WIM_HANDLER_H -#define __ARCHIVE_WIM_HANDLER_H - -#include "../../../Common/MyCom.h" - -#include "WimIn.h" - -namespace NArchive { -namespace NWim { - -static const Int32 kNumImagesMaxUpdate = (1 << 10); - -class CHandler: - public IInArchive, - public IArchiveGetRawProps, - public IArchiveGetRootProps, - public IArchiveKeepModeForNextOpen, - public ISetProperties, - public IOutArchive, - public CMyUnknownImp -{ - CDatabase _db; - UInt32 _version; - bool _isOldVersion; - UInt32 _bootIndex; - - CObjectVector _volumes; - CObjectVector _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; - - void InitDefaults() - { - _set_use_ShowImageNumber = false; - _set_showImageNumber = false; - _defaultImageNumber = -1; - } - - 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(); - MY_UNKNOWN_IMP6( - IInArchive, - IArchiveGetRawProps, - IArchiveGetRootProps, - IArchiveKeepModeForNextOpen, - ISetProperties, - IOutArchive) - INTERFACE_IInArchive(;) - INTERFACE_IArchiveGetRawProps(;) - INTERFACE_IArchiveGetRootProps(;) - STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); - STDMETHOD(KeepModeForNextOpen)(); - INTERFACE_IOutArchive(;) -}; - -}} - -#endif +// WimHandler.h + +#ifndef __ARCHIVE_WIM_HANDLER_H +#define __ARCHIVE_WIM_HANDLER_H + +#include "../../../Common/MyCom.h" + +#include "WimIn.h" + +namespace NArchive { +namespace NWim { + +static const Int32 kNumImagesMaxUpdate = (1 << 10); + +class CHandler: + public IInArchive, + public IArchiveGetRawProps, + public IArchiveGetRootProps, + public IArchiveKeepModeForNextOpen, + public ISetProperties, + public IOutArchive, + public CMyUnknownImp +{ + CDatabase _db; + UInt32 _version; + bool _isOldVersion; + UInt32 _bootIndex; + + CObjectVector _volumes; + CObjectVector _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; + + void InitDefaults() + { + _set_use_ShowImageNumber = false; + _set_showImageNumber = false; + _defaultImageNumber = -1; + } + + 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(); + MY_UNKNOWN_IMP6( + IInArchive, + IArchiveGetRawProps, + IArchiveGetRootProps, + IArchiveKeepModeForNextOpen, + ISetProperties, + IOutArchive) + INTERFACE_IInArchive(;) + INTERFACE_IArchiveGetRawProps(;) + INTERFACE_IArchiveGetRootProps(;) + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); + STDMETHOD(KeepModeForNextOpen)(); + INTERFACE_IOutArchive(;) +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp index 874b6c7fe..18740c703 100644 --- a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp +++ b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp @@ -1,1902 +1,1902 @@ -// WimHandlerOut.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.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 int AddUniqHash(const CStreamInfo *streams, CUIntVector &sorted, const Byte *h, int streamIndexForInsert) -{ - unsigned left = 0, right = sorted.Size(); - while (left != right) - { - unsigned mid = (left + right) / 2; - 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 index; - - if (h[i] < hash2[i]) - right = mid; - else - left = mid + 1; - } - - if (streamIndexForInsert >= 0) - sorted.Insert(left, 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; - UInt32 Attrib; - UInt64 FileID; - UInt64 VolID; - - UString Name; - UString ShortName; - - int SecurityId; // -1: means no secutity ID - bool IsDir; - bool Skip; - unsigned NumSkipAltStreams; - CObjectVector AltStreams; - - CByteBuffer Reparse; - - unsigned GetNumAltStreams() const { return AltStreams.Size() - NumSkipAltStreams; } - CMetaItem(): UpdateIndex(-1), HashIndex(-1), SecurityId(-1), - FileID(0), VolID(0), - Skip(false), NumSkipAltStreams(0) {} -}; - - -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 &metaItems, unsigned indexOfItem, CUIntVector &indexes) -{ - const CMetaItem &mi = metaItems[indexOfItem]; - unsigned left = 0, right = indexes.Size(); - while (left != right) - { - unsigned mid = (left + right) / 2; - unsigned index = indexes[mid]; - int comp = Compare_HardLink_MetaItems(mi, metaItems[index]); - if (comp == 0) - return 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 Dirs; - CUIntVector Files; // indexes in MetaItems[] - - CDir(): MetaIndex(-1) {} - unsigned GetNumDirs() const; - unsigned GetNumFiles() const; - UInt64 GetTotalSize(const CObjectVector &metaItems) const; - bool FindDir(const CObjectVector &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 &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 &items, const UString &name, unsigned &index) -{ - unsigned left = 0, right = Dirs.Size(); - while (left != right) - { - unsigned mid = (left + right) / 2; - 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; -} - - -STDMETHODIMP 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 >= 0) - return GetProperty(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); -} - - -class CInStreamWithSha1: - public ISequentialInStream, - public CMyUnknownImp -{ - CMyComPtr _stream; - UInt64 _size; - NCrypto::NSha1::CContext _sha; -public: - MY_UNKNOWN_IMP1(IInStream) - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - - void SetStream(ISequentialInStream *stream) { _stream = stream; } - void Init() - { - _size = 0; - _sha.Init(); - } - void ReleaseStream() { _stream.Release(); } - UInt64 GetSize() const { return _size; } - void Final(Byte *digest) { _sha.Final(digest); } -}; - -STDMETHODIMP CInStreamWithSha1::Read(void *data, UInt32 size, UInt32 *processedSize) -{ - UInt32 realProcessedSize; - HRESULT result = _stream->Read(data, size, &realProcessedSize); - _size += realProcessedSize; - _sha.Update((const Byte *)data, realProcessedSize); - if (processedSize) - *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); - - unsigned shortNameLen = item.ShortName.Len() * 2; - unsigned shortNameLen2 = (shortNameLen == 0 ? 2 : shortNameLen + 4); - - size_t totalLen = ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7); - if (item.GetNumAltStreams() != 0) - { - if (!item.IsDir) - { - UInt32 curLen = (((0x26 + 0) + 6) & ~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); - UInt32 curLen = (((0x26 + fileNameLen2) + 6) & ~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) & ~7); - - memset(p, 0, totalLen); - Set64(p, totalLen); - Set64(p + 8, item.Attrib); - Set32(p + 0xC, (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, item.Name[i]); - for (i = 0; i * 2 < shortNameLen; i++) - Set16(p + kDirRecordSize + fileNameLen2 + i * 2, 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) - { - UInt32 curLen = (((0x26 + 0) + 6) & ~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) & ~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, ss.Name[i]); - totalLen += curLen; - p += curLen; - } - } - - return totalLen; -} - - -struct CDb -{ - CMetaItem DefaultDirItem; - const CStreamInfo *Hashes; - CObjectVector MetaItems; - CRecordVector 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(mi.UpdateIndex); - FOR_VECTOR (si, mi.AltStreams) - UpdateIndexes.Add(mi.AltStreams[si].UpdateIndex); - } - - unsigned i; - for (i = 0; i < tree.Files.Size(); i++) - { - const CMetaItem &mi = MetaItems[tree.Files[i]]; - UpdateIndexes.Add(mi.UpdateIndex); - FOR_VECTOR (si, mi.AltStreams) - UpdateIndexes.Add(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 &trees, CObjectVector &metaItems, const CMetaItem &ri, int curTreeIndex) -{ - while (curTreeIndex >= (int)trees.Size()) - trees.AddNew().Dirs.AddNew().MetaIndex = metaItems.Add(ri); -} - - -#define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') - - - -STDMETHODIMP 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 outStream; - RINOK(outSeqStream->QueryInterface(IID_IOutStream, (void **)&outStream)); - if (!outStream) - return E_NOTIMPL; - if (!callback) - return E_FAIL; - - CDb db; - CObjectVector 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 getRawProps; - callback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps); - - CMyComPtr getRootProps; - callback->QueryInterface(IID_IArchiveGetRootProps, (void **)&getRootProps); - - CObjectVector 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 = secUniqBlocks.AddUniq((const Byte *)data, dataSize); - } - } - - IArchiveGetRootProps *thisGetRoot = isUpdate ? this : NULL; - - RINOK(GetRootTime(getRootProps, thisGetRoot, kpidCTime, rootItem.CTime)); - RINOK(GetRootTime(getRootProps, thisGetRoot, kpidATime, rootItem.ATime)); - 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 = indexInArchive; - } - - // we set arcIndex only if we must use old props - Int32 arcIndex = (newProps ? -1 : 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 = db.UpdateItems.Size(); - ui.AltStreamIndex = 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 = db.MetaItems.Add(ri); - db.MetaItems.Back().Name = fileName; - } - curItem = &curItem->Dirs[indexOfDir]; - fileName.Empty(); - } - else - 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(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--) - { - int metaIndex = curItem->Files[j]; - const CMetaItem &mi = db.MetaItems[metaIndex]; - if (CompareFileNames(mainName, mi.Name) == 0) - { - ui.MetaIndex = metaIndex; - break; - } - } - } - - if (ui.MetaIndex >= 0) - { - CAltStream ss; - ss.Size = size; - ss.Name = fileName.Ptr(colonPos + 1); - ss.UpdateIndex = db.UpdateItems.Size(); - ui.AltStreamIndex = db.MetaItems[ui.MetaIndex].AltStreams.Add(ss); - } - } - } - - - if (ui.MetaIndex < 0 || isRootImageDir) - { - if (!isRootImageDir) - { - ui.MetaIndex = db.MetaItems.Size(); - db.MetaItems.AddNew(); - } - - CMetaItem &mi = db.MetaItems[ui.MetaIndex]; - mi.Size = size; - mi.IsDir = isDir; - mi.Name = fileName; - mi.UpdateIndex = 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; - } - RINOK(GetTime(callback, i, arcIndex, kpidCTime, mi.CTime)); - RINOK(GetTime(callback, i, arcIndex, kpidATime, mi.ATime)); - 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(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 = secUniqBlocks.AddUniq((const Byte *)data, dataSize); - } - - data = NULL; - dataSize = 0; - propType = 0; - - if (arcIndex >= 0) - { - GetRawProp(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(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, 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 copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr 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; - } - - { - Byte buf[kHeaderSizeMax]; - header.WriteTo(buf); - RINOK(WriteStream(outStream, buf, kHeaderSizeMax)); - } - - UInt64 curPos = kHeaderSizeMax; - - CInStreamWithSha1 *inShaStreamSpec = new CInStreamWithSha1; - CMyComPtr inShaStream = inShaStreamSpec; - - CLimitedSequentialInStream *inStreamLimitedSpec = NULL; - CMyComPtr inStreamLimited; - if (_volumes.Size() == 2) - { - inStreamLimitedSpec = new CLimitedSequentialInStream; - inStreamLimited = inStreamLimitedSpec; - inStreamLimitedSpec->SetStream(_volumes[1].Stream); - } - - - CRecordVector streams; - CUIntVector 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; - - 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()); - - int 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()) - { - int find = AddUniqHash(&streams.Front(), sortedHashes, siOld.Hash, streamIndex); - if (find >= 0) - return E_FAIL; // two streams with same SHA-1 - } - - if (!rs.IsSolid() || rs.IsSolidBig()) - { - RINOK(_volumes[siOld.PartNumber].Stream->Seek(rs.Offset, STREAM_SEEK_SET, NULL)); - 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]; - - int index = AddUniqHash(&streams.Front(), sortedHashes, siOld.Hash, -1); - // we must have written that stream already - if (index < 0) - return E_FAIL; - - if (ui.AltStreamIndex < 0) - mi.HashIndex = index; - else - mi.AltStreams[ui.AltStreamIndex].HashIndex = index; - - continue; - } - - CMyComPtr 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 getProps2; - fileInStream->QueryInterface(IID_IStreamGetProps2, (void **)&getProps2); - if (getProps2) - { - CStreamFileProps props; - if (getProps2->GetProps2(&props) == S_OK) - { - mi.Attrib = props.Attrib; - mi.CTime = props.CTime; - mi.ATime = props.ATime; - 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, ui.MetaIndex, hlIndexes); - - if (props.Size != size && props.Size != (UInt64)(Int64)-1) - { - Int64 delta = (Int64)props.Size - (Int64)size; - Int64 newComplexity = totalComplexity + delta; - if (newComplexity > 0) - { - totalComplexity = 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(); - 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, streams.Size()); - - if (index >= 0) - streams[index].RefCount++; - else - { - index = 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); - 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; - } - } - */ - - RINOK(copyCoder->Code(inShaStream, outStream, NULL, NULL, progress)); - size = copyCoderSpec->TotalSize; - - if (size != 0) - { - Byte hash[kHashSize]; - UInt64 packSize = offsetBlockSize + size; - inShaStreamSpec->Final(hash); - - int index = AddUniqHash(&streams.Front(), sortedHashes, hash, streams.Size()); - - if (index >= 0) - { - streams[index].RefCount++; - outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos); - outStream->SetSize(curPos); - } - else - { - index = 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); - } - - if (ui.AltStreamIndex < 0) - mi.HashIndex = index; - else - mi.AltStreams[ui.AltStreamIndex].HashIndex = index; - } - } - } - 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(_volumes[1].Stream->Seek(s.Resource.Offset, STREAM_SEEK_SET, NULL)); - 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 &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 (""); - AddTagUInt64_ToString(xml, "TOTALBYTES", curPos); - for (i = 0; i < trees.Size(); i++) - { - CDir &tree = trees[i]; - - CXmlItem item; - if (_xmls.Size() == 1) - { - const CWimXml &_oldXml = _xmls[0]; - if ((int)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 += ""; - - size_t xmlSize; - { - UString utf16; - if (!ConvertUTF8ToUnicode(xml, utf16)) - return S_FALSE; - xmlSize = (utf16.Len() + 1) * 2; - - CByteArr xmlBuf(xmlSize); - Set16((Byte *)xmlBuf, 0xFEFF); - for (i = 0; i < (unsigned)utf16.Len(); i++) - Set16((Byte *)xmlBuf + 2 + i * 2, 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); - return WriteStream(outStream, buf, kHeaderSizeMax); - } - - COM_TRY_END -} - -}} +// WimHandlerOut.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.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 int AddUniqHash(const CStreamInfo *streams, CUIntVector &sorted, const Byte *h, int streamIndexForInsert) +{ + unsigned left = 0, right = sorted.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + 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 index; + + if (h[i] < hash2[i]) + right = mid; + else + left = mid + 1; + } + + if (streamIndexForInsert >= 0) + sorted.Insert(left, 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; + UInt32 Attrib; + UInt64 FileID; + UInt64 VolID; + + UString Name; + UString ShortName; + + int SecurityId; // -1: means no secutity ID + bool IsDir; + bool Skip; + unsigned NumSkipAltStreams; + CObjectVector AltStreams; + + CByteBuffer Reparse; + + unsigned GetNumAltStreams() const { return AltStreams.Size() - NumSkipAltStreams; } + CMetaItem(): UpdateIndex(-1), HashIndex(-1), SecurityId(-1), + FileID(0), VolID(0), + Skip(false), NumSkipAltStreams(0) {} +}; + + +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 &metaItems, unsigned indexOfItem, CUIntVector &indexes) +{ + const CMetaItem &mi = metaItems[indexOfItem]; + unsigned left = 0, right = indexes.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + unsigned index = indexes[mid]; + int comp = Compare_HardLink_MetaItems(mi, metaItems[index]); + if (comp == 0) + return 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 Dirs; + CUIntVector Files; // indexes in MetaItems[] + + CDir(): MetaIndex(-1) {} + unsigned GetNumDirs() const; + unsigned GetNumFiles() const; + UInt64 GetTotalSize(const CObjectVector &metaItems) const; + bool FindDir(const CObjectVector &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 &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 &items, const UString &name, unsigned &index) +{ + unsigned left = 0, right = Dirs.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + 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; +} + + +STDMETHODIMP 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 >= 0) + return GetProperty(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); +} + + +class CInStreamWithSha1: + public ISequentialInStream, + public CMyUnknownImp +{ + CMyComPtr _stream; + UInt64 _size; + NCrypto::NSha1::CContext _sha; +public: + MY_UNKNOWN_IMP1(IInStream) + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + + void SetStream(ISequentialInStream *stream) { _stream = stream; } + void Init() + { + _size = 0; + _sha.Init(); + } + void ReleaseStream() { _stream.Release(); } + UInt64 GetSize() const { return _size; } + void Final(Byte *digest) { _sha.Final(digest); } +}; + +STDMETHODIMP CInStreamWithSha1::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 realProcessedSize; + HRESULT result = _stream->Read(data, size, &realProcessedSize); + _size += realProcessedSize; + _sha.Update((const Byte *)data, realProcessedSize); + if (processedSize) + *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); + + unsigned shortNameLen = item.ShortName.Len() * 2; + unsigned shortNameLen2 = (shortNameLen == 0 ? 2 : shortNameLen + 4); + + size_t totalLen = ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7); + if (item.GetNumAltStreams() != 0) + { + if (!item.IsDir) + { + UInt32 curLen = (((0x26 + 0) + 6) & ~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); + UInt32 curLen = (((0x26 + fileNameLen2) + 6) & ~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) & ~7); + + memset(p, 0, totalLen); + Set64(p, totalLen); + Set64(p + 8, item.Attrib); + Set32(p + 0xC, (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, item.Name[i]); + for (i = 0; i * 2 < shortNameLen; i++) + Set16(p + kDirRecordSize + fileNameLen2 + i * 2, 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) + { + UInt32 curLen = (((0x26 + 0) + 6) & ~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) & ~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, ss.Name[i]); + totalLen += curLen; + p += curLen; + } + } + + return totalLen; +} + + +struct CDb +{ + CMetaItem DefaultDirItem; + const CStreamInfo *Hashes; + CObjectVector MetaItems; + CRecordVector 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(mi.UpdateIndex); + FOR_VECTOR (si, mi.AltStreams) + UpdateIndexes.Add(mi.AltStreams[si].UpdateIndex); + } + + unsigned i; + for (i = 0; i < tree.Files.Size(); i++) + { + const CMetaItem &mi = MetaItems[tree.Files[i]]; + UpdateIndexes.Add(mi.UpdateIndex); + FOR_VECTOR (si, mi.AltStreams) + UpdateIndexes.Add(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 &trees, CObjectVector &metaItems, const CMetaItem &ri, int curTreeIndex) +{ + while (curTreeIndex >= (int)trees.Size()) + trees.AddNew().Dirs.AddNew().MetaIndex = metaItems.Add(ri); +} + + +#define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') + + + +STDMETHODIMP 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 outStream; + RINOK(outSeqStream->QueryInterface(IID_IOutStream, (void **)&outStream)); + if (!outStream) + return E_NOTIMPL; + if (!callback) + return E_FAIL; + + CDb db; + CObjectVector 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 getRawProps; + callback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps); + + CMyComPtr getRootProps; + callback->QueryInterface(IID_IArchiveGetRootProps, (void **)&getRootProps); + + CObjectVector 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 = secUniqBlocks.AddUniq((const Byte *)data, dataSize); + } + } + + IArchiveGetRootProps *thisGetRoot = isUpdate ? this : NULL; + + RINOK(GetRootTime(getRootProps, thisGetRoot, kpidCTime, rootItem.CTime)); + RINOK(GetRootTime(getRootProps, thisGetRoot, kpidATime, rootItem.ATime)); + 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 = indexInArchive; + } + + // we set arcIndex only if we must use old props + Int32 arcIndex = (newProps ? -1 : 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 = db.UpdateItems.Size(); + ui.AltStreamIndex = 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 = db.MetaItems.Add(ri); + db.MetaItems.Back().Name = fileName; + } + curItem = &curItem->Dirs[indexOfDir]; + fileName.Empty(); + } + else + 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(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--) + { + int metaIndex = curItem->Files[j]; + const CMetaItem &mi = db.MetaItems[metaIndex]; + if (CompareFileNames(mainName, mi.Name) == 0) + { + ui.MetaIndex = metaIndex; + break; + } + } + } + + if (ui.MetaIndex >= 0) + { + CAltStream ss; + ss.Size = size; + ss.Name = fileName.Ptr(colonPos + 1); + ss.UpdateIndex = db.UpdateItems.Size(); + ui.AltStreamIndex = db.MetaItems[ui.MetaIndex].AltStreams.Add(ss); + } + } + } + + + if (ui.MetaIndex < 0 || isRootImageDir) + { + if (!isRootImageDir) + { + ui.MetaIndex = db.MetaItems.Size(); + db.MetaItems.AddNew(); + } + + CMetaItem &mi = db.MetaItems[ui.MetaIndex]; + mi.Size = size; + mi.IsDir = isDir; + mi.Name = fileName; + mi.UpdateIndex = 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; + } + RINOK(GetTime(callback, i, arcIndex, kpidCTime, mi.CTime)); + RINOK(GetTime(callback, i, arcIndex, kpidATime, mi.ATime)); + 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(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 = secUniqBlocks.AddUniq((const Byte *)data, dataSize); + } + + data = NULL; + dataSize = 0; + propType = 0; + + if (arcIndex >= 0) + { + GetRawProp(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(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, 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 copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr 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; + } + + { + Byte buf[kHeaderSizeMax]; + header.WriteTo(buf); + RINOK(WriteStream(outStream, buf, kHeaderSizeMax)); + } + + UInt64 curPos = kHeaderSizeMax; + + CInStreamWithSha1 *inShaStreamSpec = new CInStreamWithSha1; + CMyComPtr inShaStream = inShaStreamSpec; + + CLimitedSequentialInStream *inStreamLimitedSpec = NULL; + CMyComPtr inStreamLimited; + if (_volumes.Size() == 2) + { + inStreamLimitedSpec = new CLimitedSequentialInStream; + inStreamLimited = inStreamLimitedSpec; + inStreamLimitedSpec->SetStream(_volumes[1].Stream); + } + + + CRecordVector streams; + CUIntVector 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; + + 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()); + + int 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()) + { + int find = AddUniqHash(&streams.Front(), sortedHashes, siOld.Hash, streamIndex); + if (find >= 0) + return E_FAIL; // two streams with same SHA-1 + } + + if (!rs.IsSolid() || rs.IsSolidBig()) + { + RINOK(_volumes[siOld.PartNumber].Stream->Seek(rs.Offset, STREAM_SEEK_SET, NULL)); + 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]; + + int index = AddUniqHash(&streams.Front(), sortedHashes, siOld.Hash, -1); + // we must have written that stream already + if (index < 0) + return E_FAIL; + + if (ui.AltStreamIndex < 0) + mi.HashIndex = index; + else + mi.AltStreams[ui.AltStreamIndex].HashIndex = index; + + continue; + } + + CMyComPtr 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 getProps2; + fileInStream->QueryInterface(IID_IStreamGetProps2, (void **)&getProps2); + if (getProps2) + { + CStreamFileProps props; + if (getProps2->GetProps2(&props) == S_OK) + { + mi.Attrib = props.Attrib; + mi.CTime = props.CTime; + mi.ATime = props.ATime; + 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, ui.MetaIndex, hlIndexes); + + if (props.Size != size && props.Size != (UInt64)(Int64)-1) + { + Int64 delta = (Int64)props.Size - (Int64)size; + Int64 newComplexity = totalComplexity + delta; + if (newComplexity > 0) + { + totalComplexity = 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(); + 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, streams.Size()); + + if (index >= 0) + streams[index].RefCount++; + else + { + index = 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); + 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; + } + } + */ + + RINOK(copyCoder->Code(inShaStream, outStream, NULL, NULL, progress)); + size = copyCoderSpec->TotalSize; + + if (size != 0) + { + Byte hash[kHashSize]; + UInt64 packSize = offsetBlockSize + size; + inShaStreamSpec->Final(hash); + + int index = AddUniqHash(&streams.Front(), sortedHashes, hash, streams.Size()); + + if (index >= 0) + { + streams[index].RefCount++; + outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos); + outStream->SetSize(curPos); + } + else + { + index = 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); + } + + if (ui.AltStreamIndex < 0) + mi.HashIndex = index; + else + mi.AltStreams[ui.AltStreamIndex].HashIndex = index; + } + } + } + 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(_volumes[1].Stream->Seek(s.Resource.Offset, STREAM_SEEK_SET, NULL)); + 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 &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 (""); + AddTagUInt64_ToString(xml, "TOTALBYTES", curPos); + for (i = 0; i < trees.Size(); i++) + { + CDir &tree = trees[i]; + + CXmlItem item; + if (_xmls.Size() == 1) + { + const CWimXml &_oldXml = _xmls[0]; + if ((int)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 += ""; + + size_t xmlSize; + { + UString utf16; + if (!ConvertUTF8ToUnicode(xml, utf16)) + return S_FALSE; + xmlSize = (utf16.Len() + 1) * 2; + + CByteArr xmlBuf(xmlSize); + Set16((Byte *)xmlBuf, 0xFEFF); + for (i = 0; i < (unsigned)utf16.Len(); i++) + Set16((Byte *)xmlBuf + 2 + i * 2, 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); + return WriteStream(outStream, buf, kHeaderSizeMax); + } + + COM_TRY_END +} + +}} diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp index 179481599..3c7120844 100644 --- a/CPP/7zip/Archive/Wim/WimIn.cpp +++ b/CPP/7zip/Archive/Wim/WimIn.cpp @@ -1,1873 +1,1873 @@ -// Archive/WimIn.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#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 limitedStream = limitedStreamSpec; - limitedStreamSpec->SetStream(inStream); - - RINOK(inStream->Seek(resource.Offset, STREAM_SEEK_SET, NULL)); - 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; - - UInt64 offset = ss.Chunks[chunkIndex]; - UInt64 packSize = ss.GetChunkPackSize(chunkIndex); - const CResource &rs = db->DataStreams[ss.StreamIndex].Resource; - RINOK(inStream->Seek(rs.Offset + ss.HeadersSize + offset, STREAM_SEEK_SET, NULL)); - - size_t cur = chunkSize; - UInt64 unpackRem = ss.UnpackSize - ((UInt64)chunkIndex << chunkSizeBits); - if (cur > unpackRem) - cur = (size_t)unpackRem; - - _solidIndex = -1; - _unpackedChunkIndex = 0; - - HRESULT res = UnpackChunk(inStream, 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; - { - UInt64 numChunks64 = (unpackSize + (((UInt32)1 << chunkSizeBits) - 1)) >> chunkSizeBits; - UInt64 sizesBufSize64 = (numChunks64 - 1) << entrySizeShifts; - if (sizesBufSize64 > resource.PackSize) - return S_FALSE; - packDataSize = resource.PackSize - sizesBufSize64; - size_t sizesBufSize = (size_t)sizesBufSize64; - if (sizesBufSize != sizesBufSize64) - return E_OUTOFMEMORY; - sizesBuf.AllocAtLeast(sizesBufSize); - RINOK(inStream->Seek(baseOffset, STREAM_SEEK_SET, NULL)); - 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->Seek(baseOffset + offset, STREAM_SEEK_SET, NULL)); - - 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 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 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 = index1; - 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 = 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); - // 18.06 - if (c == CHAR_PATH_SEPARATOR || c == '/') - c = '_'; - 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 *)(p + fileNameLen) != 0) - return S_FALSE; - for (UInt32 j = 0; j < fileNameLen; j += 2) - if (*(const UInt16 *)(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 *)(p2 + shortNameLen) != 0) - return S_FALSE; - for (UInt32 j = 0; j < shortNameLen; j += 2) - if (*(const UInt16 *)(p2 + j) == 0) - return S_FALSE; - } - - item.Offset = pos; - item.Parent = parent; - item.ImageIndex = 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 < (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 *)(p3 + fileNameLen111) != 0) - return S_FALSE; - for (UInt32 j = 0; j < fileNameLen111; j += 2) - if (*(const UInt16 *)(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 = prevIndex; - item2.ImageIndex = 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, 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) - { - int log = GetLog(ChunkSize); - if (log < 12) - return S_FALSE; - ChunkSizeBits = 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 int 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) - { - unsigned mid = (left + right) / 2; - unsigned streamIndex = sorted[mid]; - UInt32 id2 = streams[streamIndex].Id; - if (id == id2) - return streamIndex; - if (id < id2) - right = mid; - else - left = mid + 1; - } - return -1; -} - -static int FindHash(const CStreamInfo *streams, const CUIntVector &sorted, const Byte *hash) -{ - unsigned left = 0, right = sorted.Size(); - while (left != right) - { - unsigned mid = (left + right) / 2; - 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 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 &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 &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 = 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->Seek(r.Offset, STREAM_SEEK_SET, NULL)); - 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); - int log = GetLog(solidChunkSize); - if (log < 8 || log > 31) - return S_FALSE; - ss.ChunkSizeBits = log; - ss.Method = 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; - UInt64 relat = r.Offset - ss.SolidOffset; - if (relat > ss.UnpackSize) - return S_FALSE; - if (r.PackSize > ss.UnpackSize - relat) - return S_FALSE; - r.SolidIndex = solidIndex; - if (ss.FirstSmallStream < 0) - ss.FirstSmallStream = 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 = 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 = 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 = i; - - if (showImageNumber) - for (i = 0; i < Images.Size(); i++) - { - CImage &image = Images[i]; - if (image.NumEmptyRootItems != 0) - continue; - image.VirtualRootIndex = 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 &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] = 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 = 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 = 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; -} - -}} +// Archive/WimIn.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#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 limitedStream = limitedStreamSpec; + limitedStreamSpec->SetStream(inStream); + + RINOK(inStream->Seek(resource.Offset, STREAM_SEEK_SET, NULL)); + 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; + + UInt64 offset = ss.Chunks[chunkIndex]; + UInt64 packSize = ss.GetChunkPackSize(chunkIndex); + const CResource &rs = db->DataStreams[ss.StreamIndex].Resource; + RINOK(inStream->Seek(rs.Offset + ss.HeadersSize + offset, STREAM_SEEK_SET, NULL)); + + size_t cur = chunkSize; + UInt64 unpackRem = ss.UnpackSize - ((UInt64)chunkIndex << chunkSizeBits); + if (cur > unpackRem) + cur = (size_t)unpackRem; + + _solidIndex = -1; + _unpackedChunkIndex = 0; + + HRESULT res = UnpackChunk(inStream, 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; + { + UInt64 numChunks64 = (unpackSize + (((UInt32)1 << chunkSizeBits) - 1)) >> chunkSizeBits; + UInt64 sizesBufSize64 = (numChunks64 - 1) << entrySizeShifts; + if (sizesBufSize64 > resource.PackSize) + return S_FALSE; + packDataSize = resource.PackSize - sizesBufSize64; + size_t sizesBufSize = (size_t)sizesBufSize64; + if (sizesBufSize != sizesBufSize64) + return E_OUTOFMEMORY; + sizesBuf.AllocAtLeast(sizesBufSize); + RINOK(inStream->Seek(baseOffset, STREAM_SEEK_SET, NULL)); + 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->Seek(baseOffset + offset, STREAM_SEEK_SET, NULL)); + + 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 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 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 = index1; + 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 = 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); + // 18.06 + if (c == CHAR_PATH_SEPARATOR || c == '/') + c = '_'; + 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 *)(p + fileNameLen) != 0) + return S_FALSE; + for (UInt32 j = 0; j < fileNameLen; j += 2) + if (*(const UInt16 *)(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 *)(p2 + shortNameLen) != 0) + return S_FALSE; + for (UInt32 j = 0; j < shortNameLen; j += 2) + if (*(const UInt16 *)(p2 + j) == 0) + return S_FALSE; + } + + item.Offset = pos; + item.Parent = parent; + item.ImageIndex = 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 < (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 *)(p3 + fileNameLen111) != 0) + return S_FALSE; + for (UInt32 j = 0; j < fileNameLen111; j += 2) + if (*(const UInt16 *)(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 = prevIndex; + item2.ImageIndex = 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, 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) + { + int log = GetLog(ChunkSize); + if (log < 12) + return S_FALSE; + ChunkSizeBits = 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 int 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) + { + unsigned mid = (left + right) / 2; + unsigned streamIndex = sorted[mid]; + UInt32 id2 = streams[streamIndex].Id; + if (id == id2) + return streamIndex; + if (id < id2) + right = mid; + else + left = mid + 1; + } + return -1; +} + +static int FindHash(const CStreamInfo *streams, const CUIntVector &sorted, const Byte *hash) +{ + unsigned left = 0, right = sorted.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + 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 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 &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 &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 = 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->Seek(r.Offset, STREAM_SEEK_SET, NULL)); + 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); + int log = GetLog(solidChunkSize); + if (log < 8 || log > 31) + return S_FALSE; + ss.ChunkSizeBits = log; + ss.Method = 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; + UInt64 relat = r.Offset - ss.SolidOffset; + if (relat > ss.UnpackSize) + return S_FALSE; + if (r.PackSize > ss.UnpackSize - relat) + return S_FALSE; + r.SolidIndex = solidIndex; + if (ss.FirstSmallStream < 0) + ss.FirstSmallStream = 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 = 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 = 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 = i; + + if (showImageNumber) + for (i = 0; i < Images.Size(); i++) + { + CImage &image = Images[i]; + if (image.NumEmptyRootItems != 0) + continue; + image.VirtualRootIndex = 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 &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] = 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 = 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 = 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 index e4157df57..9e835b01f 100644 --- a/CPP/7zip/Archive/Wim/WimIn.h +++ b/CPP/7zip/Archive/Wim/WimIn.h @@ -1,659 +1,659 @@ -// Archive/WimIn.h - -#ifndef __ARCHIVE_WIM_IN_H -#define __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; - int ChunkSizeBits; - - UInt64 HeadersSize; - // size_t NumChunks; - CObjArray 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 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 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 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 DataStreams; - CRecordVector MetaStreams; - - CObjectVector Solids; - - CRecordVector Items; - CObjectVector ReparseItems; - CIntVector ItemToReparse; // from index_in_Items to index_in_ReparseItems - // -1 means no reparse; - - CObjectVector Images; - - bool IsOldVersion9; - bool IsOldVersion; - bool ThereAreDeletedStreams; - bool ThereAreAltStreams; - bool RefCountError; - bool HeadersError; - - bool 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 &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 &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 copyCoder; - - NCompress::NLzx::CDecoder *lzxDecoderSpec; - CMyComPtr 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 +// Archive/WimIn.h + +#ifndef __ARCHIVE_WIM_IN_H +#define __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; + int ChunkSizeBits; + + UInt64 HeadersSize; + // size_t NumChunks; + CObjArray 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 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 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 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 DataStreams; + CRecordVector MetaStreams; + + CObjectVector Solids; + + CRecordVector Items; + CObjectVector ReparseItems; + CIntVector ItemToReparse; // from index_in_Items to index_in_ReparseItems + // -1 means no reparse; + + CObjectVector Images; + + bool IsOldVersion9; + bool IsOldVersion; + bool ThereAreDeletedStreams; + bool ThereAreAltStreams; + bool RefCountError; + bool HeadersError; + + bool 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 &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 &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 copyCoder; + + NCompress::NLzx::CDecoder *lzxDecoderSpec; + CMyComPtr 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 index 19093b6ca..ecebe8d94 100644 --- a/CPP/7zip/Archive/Wim/WimRegister.cpp +++ b/CPP/7zip/Archive/Wim/WimRegister.cpp @@ -1,22 +1,22 @@ -// WimRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "WimHandler.h" - -namespace NArchive { -namespace NWim { - -REGISTER_ARC_IO( - "wim", "wim swm esd ppkg", 0, 0xE6, - kSignature, - 0, - NArcInfoFlags::kAltStreams | - NArcInfoFlags::kNtSecure | - NArcInfoFlags::kSymLinks | - NArcInfoFlags::kHardLinks - , NULL) - -}} +// WimRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "WimHandler.h" + +namespace NArchive { +namespace NWim { + +REGISTER_ARC_IO( + "wim", "wim swm esd ppkg", 0, 0xE6, + kSignature, + 0, + NArcInfoFlags::kAltStreams | + NArcInfoFlags::kNtSecure | + NArcInfoFlags::kSymLinks | + NArcInfoFlags::kHardLinks + , NULL) + +}} diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp index 9f760261f..f20b1eb9f 100644 --- a/CPP/7zip/Archive/XarHandler.cpp +++ b/CPP/7zip/Archive/XarHandler.cpp @@ -1,732 +1,732 @@ -// 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(): IsDir(false), HasData(false), ModeDefined(false), Sha1IsDefined(false), - /* packSha1IsDefined(false), */ - Parent(-1), - Size(0), PackSize(0), Offset(0), - CTime(0), MTime(0), ATime(0), Mode(0) {} - - bool IsCopyMethod() const - { - return Method.IsEmpty() || Method == "octet-stream"; - } - - void UpdateTotalPackSize(UInt64 &totalSize) const - { - UInt64 t = Offset + PackSize; - if (totalSize < t) - totalSize = t; - } -}; - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - UInt64 _dataStartPos; - CMyComPtr _inStream; - CByteArr _xml; - size_t _xmlLen; - CObjectVector _files; - // UInt32 _checkSumAlgo; - UInt64 _phySize; - Int32 _mainSubfile; - bool _is_pkg; - - HRESULT Open2(IInStream *stream); - HRESULT Extract(IInStream *stream); -public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **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(unsigned 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) -{ - 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) - { - int b0 = HexToByte(s[i]); - 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 &files, int parent) -{ - if (!item.IsTag) - return true; - if (item.Name == "file") - { - CFile file; - file.Parent = parent; - parent = files.Size(); - file.Name = item.GetSubStringForTag("name"); - 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 zlibCoder = zlibCoderSpec; - - CLimitedSequentialInStream *inStreamLimSpec = new CLimitedSequentialInStream; - CMyComPtr inStreamLim(inStreamLimSpec); - inStreamLimSpec->SetStream(stream); - inStreamLimSpec->Init(packSize); - - CBufPtrSeqOutStream *outStreamLimSpec = new CBufPtrSeqOutStream; - CMyComPtr 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 = i; - numMainFiles++; - } - else if (file.Name == "PackageInfo") - _is_pkg = true; - } - - if (numMainFiles > 1) - _mainSubfile = -1; - - _phySize = _dataStartPos + totalPackSize; - - return S_OK; -} - -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) -{ - COM_TRY_BEGIN - { - Close(); - if (Open2(stream) != S_OK) - return S_FALSE; - _inStream = stream; - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _phySize = 0; - _inStream.Release(); - _files.Clear(); - _xmlLen = 0; - _xml.Free(); - _mainSubfile = -1; - _is_pkg = false; - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _files.Size() - #ifdef XAR_SHOW_RAW - + 1 - #endif - ; - return S_OK; -} - -static void TimeToProp(UInt64 t, 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; - if (ConvertUTF8ToUnicode(s, us)) - prop = us; - } -} - -STDMETHODIMP 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 -} - -STDMETHODIMP 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; - int cur = index; - do - { - 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 = item2.Parent; - } - while (cur >= 0); - - 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 -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - 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 copyCoder = copyCoderSpec; - - NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder(); - CMyComPtr zlibCoder = zlibCoderSpec; - - NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder(); - CMyComPtr bzip2Coder = bzip2CoderSpec; - - NCompress::NDeflate::NDecoder::CCOMCoder *deflateCoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder(); - CMyComPtr deflateCoder = deflateCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(inStreamSpec); - inStreamSpec->SetStream(_inStream); - - - CLimitedSequentialOutStream *outStreamLimSpec = new CLimitedSequentialOutStream; - CMyComPtr outStream(outStreamLimSpec); - - COutStreamWithSha1 *outStreamSha1Spec = new COutStreamWithSha1; - { - CMyComPtr 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 realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - 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->Seek(_dataStartPos + item.Offset, STREAM_SEEK_SET, NULL)); - inStreamSpec->Init(item.PackSize); - outStreamSha1Spec->Init(item.Sha1IsDefined); - outStreamLimSpec->Init(item.Size); - HRESULT res = S_OK; - - ICompressCoder *coder = NULL; - if (item.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 -} - -STDMETHODIMP 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", 0, 0xE1, - k_Signature, - 0, - 0, - NULL) - -}} +// 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(): IsDir(false), HasData(false), ModeDefined(false), Sha1IsDefined(false), + /* packSha1IsDefined(false), */ + Parent(-1), + Size(0), PackSize(0), Offset(0), + CTime(0), MTime(0), ATime(0), Mode(0) {} + + bool IsCopyMethod() const + { + return Method.IsEmpty() || Method == "octet-stream"; + } + + void UpdateTotalPackSize(UInt64 &totalSize) const + { + UInt64 t = Offset + PackSize; + if (totalSize < t) + totalSize = t; + } +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + UInt64 _dataStartPos; + CMyComPtr _inStream; + CByteArr _xml; + size_t _xmlLen; + CObjectVector _files; + // UInt32 _checkSumAlgo; + UInt64 _phySize; + Int32 _mainSubfile; + bool _is_pkg; + + HRESULT Open2(IInStream *stream); + HRESULT Extract(IInStream *stream); +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **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(unsigned 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) +{ + 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) + { + int b0 = HexToByte(s[i]); + 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 &files, int parent) +{ + if (!item.IsTag) + return true; + if (item.Name == "file") + { + CFile file; + file.Parent = parent; + parent = files.Size(); + file.Name = item.GetSubStringForTag("name"); + 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 zlibCoder = zlibCoderSpec; + + CLimitedSequentialInStream *inStreamLimSpec = new CLimitedSequentialInStream; + CMyComPtr inStreamLim(inStreamLimSpec); + inStreamLimSpec->SetStream(stream); + inStreamLimSpec->Init(packSize); + + CBufPtrSeqOutStream *outStreamLimSpec = new CBufPtrSeqOutStream; + CMyComPtr 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 = i; + numMainFiles++; + } + else if (file.Name == "PackageInfo") + _is_pkg = true; + } + + if (numMainFiles > 1) + _mainSubfile = -1; + + _phySize = _dataStartPos + totalPackSize; + + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + { + Close(); + if (Open2(stream) != S_OK) + return S_FALSE; + _inStream = stream; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _phySize = 0; + _inStream.Release(); + _files.Clear(); + _xmlLen = 0; + _xml.Free(); + _mainSubfile = -1; + _is_pkg = false; + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _files.Size() + #ifdef XAR_SHOW_RAW + + 1 + #endif + ; + return S_OK; +} + +static void TimeToProp(UInt64 t, 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; + if (ConvertUTF8ToUnicode(s, us)) + prop = us; + } +} + +STDMETHODIMP 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 +} + +STDMETHODIMP 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; + int cur = index; + do + { + 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 = item2.Parent; + } + while (cur >= 0); + + 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 +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + 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 copyCoder = copyCoderSpec; + + NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder(); + CMyComPtr zlibCoder = zlibCoderSpec; + + NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder(); + CMyComPtr bzip2Coder = bzip2CoderSpec; + + NCompress::NDeflate::NDecoder::CCOMCoder *deflateCoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder(); + CMyComPtr deflateCoder = deflateCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(inStreamSpec); + inStreamSpec->SetStream(_inStream); + + + CLimitedSequentialOutStream *outStreamLimSpec = new CLimitedSequentialOutStream; + CMyComPtr outStream(outStreamLimSpec); + + COutStreamWithSha1 *outStreamSha1Spec = new COutStreamWithSha1; + { + CMyComPtr 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 realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + 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->Seek(_dataStartPos + item.Offset, STREAM_SEEK_SET, NULL)); + inStreamSpec->Init(item.PackSize); + outStreamSha1Spec->Init(item.Sha1IsDefined); + outStreamLimSpec->Init(item.Size); + HRESULT res = S_OK; + + ICompressCoder *coder = NULL; + if (item.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 +} + +STDMETHODIMP 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", 0, 0xE1, + k_Signature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp index 743271a36..801619fba 100644 --- a/CPP/7zip/Archive/XzHandler.cpp +++ b/CPP/7zip/Archive/XzHandler.cpp @@ -1,1308 +1,1308 @@ -// 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 _stream; - CMyComPtr _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 _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 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(¤tTotalPacked)); - CMyComPtr 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 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 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 fileInStream; - RINOK(updateCallback->GetStream(0, &fileInStream)); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(updateCallback, true); - - return encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress); - } - - if (indexInArchive != 0) - return E_INVALIDARG; - - CMyComPtr 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 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; +}; + + +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 _stream; + CMyComPtr _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 _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 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(¤tTotalPacked)); + CMyComPtr 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 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 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 fileInStream; + RINOK(updateCallback->GetStream(0, &fileInStream)); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(updateCallback, true); + + return encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress); + } + + if (indexInArchive != 0) + return E_INVALIDARG; + + CMyComPtr 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 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) + +}} diff --git a/CPP/7zip/Archive/XzHandler.h b/CPP/7zip/Archive/XzHandler.h index 18633fbc9..24e8eeb4a 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 __XZ_HANDLER_H +#define __XZ_HANDLER_H + +namespace NArchive { +namespace NXz { + +}} + +#endif diff --git a/CPP/7zip/Archive/ZHandler.cpp b/CPP/7zip/Archive/ZHandler.cpp index 8c9a42dda..299343678 100644 --- a/CPP/7zip/Archive/ZHandler.cpp +++ b/CPP/7zip/Archive/ZHandler.cpp @@ -1,236 +1,236 @@ -// ZHandler.cpp - -#include "StdAfx.h" - -#include "../../Common/ComTry.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/ZDecoder.h" - -#include "Common/DummyOutStream.h" - -namespace NArchive { -namespace NZ { - -class CHandler: - public IInArchive, - public CMyUnknownImp -{ - CMyComPtr _stream; - UInt64 _packSize; - // UInt64 _unpackSize; - // bool _unpackSize_Defined; -public: - MY_UNKNOWN_IMP1(IInArchive) - INTERFACE_IInArchive(;) -}; - -static const Byte kProps[] = -{ - kpidPackSize -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = 1; - return S_OK; -} - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySizeCantBeDetected: prop = true; break; - } - prop.Detach(value); - return S_OK; -} - -STDMETHODIMP 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; -} - -/* -class CCompressProgressInfoImp: - public ICompressProgressInfo, - public CMyUnknownImp -{ - CMyComPtr Callback; -public: - 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) - { - 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; -} -} - -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openCallback */) -{ - COM_TRY_BEGIN - { - // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_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(stream->Seek(0, STREAM_SEEK_END, &endPos)); - _packSize = endPos; - - /* - bool fullCheck = false; - if (fullCheck) - { - CCompressProgressInfoImp *compressProgressSpec = new CCompressProgressInfoImp; - CMyComPtr compressProgress = compressProgressSpec; - compressProgressSpec->Init(openCallback); - - NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder; - CMyComPtr decoder = decoderSpec; - - CDummyOutStream *outStreamSpec = new CDummyOutStream; - CMyComPtr outStream(outStreamSpec); - outStreamSpec->SetStream(NULL); - outStreamSpec->Init(); - decoderSpec->SetProp(_prop); - if (openCallback) - { - UInt64 files = 1; - RINOK(openCallback->SetTotal(&files, &endPos)); - } - RINOK(stream->Seek(_streamStartPosition + kSignatureSize, STREAM_SEEK_SET, NULL)); - 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 -} - -STDMETHODIMP CHandler::Close() -{ - _packSize = 0; - // _unpackSize_Defined = false; - _stream.Release(); - return S_OK; -} - - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - extractCallback->SetTotal(_packSize); - - UInt64 currentTotalPacked = 0; - - RINOK(extractCallback->SetCompleted(¤tTotalPacked)); - - CMyComPtr 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 outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(); - realOutStream.Release(); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, true); - - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - - NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder; - CMyComPtr 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) - -}} +// ZHandler.cpp + +#include "StdAfx.h" + +#include "../../Common/ComTry.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/ZDecoder.h" + +#include "Common/DummyOutStream.h" + +namespace NArchive { +namespace NZ { + +class CHandler: + public IInArchive, + public CMyUnknownImp +{ + CMyComPtr _stream; + UInt64 _packSize; + // UInt64 _unpackSize; + // bool _unpackSize_Defined; +public: + MY_UNKNOWN_IMP1(IInArchive) + INTERFACE_IInArchive(;) +}; + +static const Byte kProps[] = +{ + kpidPackSize +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1; + return S_OK; +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySizeCantBeDetected: prop = true; break; + } + prop.Detach(value); + return S_OK; +} + +STDMETHODIMP 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; +} + +/* +class CCompressProgressInfoImp: + public ICompressProgressInfo, + public CMyUnknownImp +{ + CMyComPtr Callback; +public: + 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) + { + 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; +} +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openCallback */) +{ + COM_TRY_BEGIN + { + // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_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(stream->Seek(0, STREAM_SEEK_END, &endPos)); + _packSize = endPos; + + /* + bool fullCheck = false; + if (fullCheck) + { + CCompressProgressInfoImp *compressProgressSpec = new CCompressProgressInfoImp; + CMyComPtr compressProgress = compressProgressSpec; + compressProgressSpec->Init(openCallback); + + NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder; + CMyComPtr decoder = decoderSpec; + + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr outStream(outStreamSpec); + outStreamSpec->SetStream(NULL); + outStreamSpec->Init(); + decoderSpec->SetProp(_prop); + if (openCallback) + { + UInt64 files = 1; + RINOK(openCallback->SetTotal(&files, &endPos)); + } + RINOK(stream->Seek(_streamStartPosition + kSignatureSize, STREAM_SEEK_SET, NULL)); + 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 +} + +STDMETHODIMP CHandler::Close() +{ + _packSize = 0; + // _unpackSize_Defined = false; + _stream.Release(); + return S_OK; +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + extractCallback->SetTotal(_packSize); + + UInt64 currentTotalPacked = 0; + + RINOK(extractCallback->SetCompleted(¤tTotalPacked)); + + CMyComPtr 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 outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + realOutStream.Release(); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, true); + + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); + + NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder; + CMyComPtr 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 index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Archive/Zip/StdAfx.h +++ b/CPP/7zip/Archive/Zip/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp index a8365db67..1ee7e22f9 100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp @@ -1,478 +1,478 @@ -// 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 UInt32 kLzmaPropsSize = 5; -static const UInt32 kLzmaHeaderSize = 4 + kLzmaPropsSize; - -class CLzmaEncoder: - public ICompressCoder, - public ICompressSetCoderProperties, - public ICompressSetCoderPropertiesOpt, - public CMyUnknownImp -{ -public: - NCompress::NLzma::CEncoder *EncoderSpec; - CMyComPtr Encoder; - Byte Header[kLzmaHeaderSize]; - - 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); - - MY_UNKNOWN_IMP2( - ICompressSetCoderProperties, - ICompressSetCoderPropertiesOpt) -}; - -STDMETHODIMP CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) -{ - if (!Encoder) - { - EncoderSpec = new NCompress::NLzma::CEncoder; - Encoder = EncoderSpec; - } - CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; - CMyComPtr 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; -} - -STDMETHODIMP CLzmaEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) -{ - return EncoderSpec->SetCoderPropertiesOpt(propIDs, props, numProps); -} - -STDMETHODIMP CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - RINOK(WriteStream(outStream, Header, kLzmaHeaderSize)); - return Encoder->Code(inStream, outStream, inSize, outSize, progress); -} - - -CAddCommon::CAddCommon(const CCompressionMethodMode &options): - _options(options), - _copyCoderSpec(NULL), - _cryptoStreamSpec(NULL), - _buf(NULL), - _isLzmaEos(false) - {} - -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; - - Byte method = _options.MethodSequence[0]; - - if (method == NCompressionMethod::kStore && !_options.PasswordIsDefined) - opRes.PackSize = unpackSize; - - opRes.CRC = 0; - - opRes.LzmaEos = false; - - opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; - opRes.DescriptorMode = outSeqMode; - - if (_options.PasswordIsDefined) - { - 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, - 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 inCrcStream = inSecCrcStreamSpec; - - CMyComPtr 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->Init(); - - unsigned numTestMethods = _options.MethodSequence.Size(); - - bool descriptorMode = outSeqMode; - if (!outSeqMode) - if (inSeqMode && _options.PasswordIsDefined && !_options.IsAesMode) - descriptorMode = true; - opRes.DescriptorMode = descriptorMode; - - if (numTestMethods > 1) - if (inSeqMode || outSeqMode || !inStream2) - numTestMethods = 1; - - UInt32 crc = 0; - bool crc_IsCalculated = false; - - Byte method = 0; - CFilterCoder::C_OutStream_Releaser outStreamReleaser; - opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; - - for (unsigned i = 0; i < numTestMethods; i++) - { - opRes.LzmaEos = false; - opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; - - if (i != 0) - { - if (inStream2) - { - inSecCrcStreamSpec->Init(); - RINOK(inStream2->Seek(0, STREAM_SEEK_SET, NULL)); - } - - RINOK(outStream->SetSize(0)); - RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL)); - } - - if (_options.PasswordIsDefined) - { - 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(inStream2->Seek(0, STREAM_SEEK_SET, NULL)); - inSecCrcStreamSpec->Init(); - } - check = (crc >> 16); - } - - RINOK(_filterSpec->WriteHeader_Check16(outStream, (UInt16)check)); - } - - RINOK(_cryptoStreamSpec->SetOutStream(outStream)); - RINOK(_cryptoStreamSpec->InitEncoder()); - outStreamReleaser.FilterCoder = _cryptoStreamSpec; - } - - method = _options.MethodSequence[i]; - - switch (method) - { - case NCompressionMethod::kStore: - { - if (descriptorMode) - { - // we still can create descriptor_mode archives with "Store" method, but they are not good for 100% - return E_NOTIMPL; - } - - if (!_copyCoderSpec) - { - _copyCoderSpec = new NCompress::CCopyCoder; - _copyCoder = _copyCoderSpec; - } - CMyComPtr outStreamNew; - if (_options.PasswordIsDefined) - 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 setCoderProps; - _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProps); - if (setCoderProps) - { - if (!_options._methods.IsEmpty()) - { - COneMethodInfo *oneMethodMain = &_options._methods[0]; - - RINOK(oneMethodMain->SetCoderProps(setCoderProps, - _options._dataSizeReduceDefined ? &_options._dataSizeReduce : NULL)); - } - } - } - if (method == NCompressionMethod::kLZMA) - _isLzmaEos = _lzmaEncoder->EncoderSpec->IsWriteEndMark(); - } - - if (method == NCompressionMethod::kLZMA) - opRes.LzmaEos = _isLzmaEos; - - CMyComPtr outStreamNew; - if (_options.PasswordIsDefined) - outStreamNew = _cryptoStream; - else - outStreamNew = outStream; - if (_compressExtractVersion > opRes.ExtractVersion) - opRes.ExtractVersion = _compressExtractVersion; - - { - CMyComPtr optProps; - _compressEncoder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps); - if (optProps) - { - PROPID propID = NCoderPropID::kExpectedDataSize; - NWindows::NCOM::CPropVariant prop = (UInt64)expectedDataSize; - RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1)); - } - } - - RINOK(_compressEncoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress)); - break; - } - } - - if (_options.PasswordIsDefined) - { - RINOK(_cryptoStreamSpec->OutStreamFinish()); - - if (_options.IsAesMode) - { - RINOK(_filterAesSpec->WriteFooter(outStream)); - } - } - - RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize)); - - { - opRes.CRC = inSecCrcStreamSpec->GetCRC(); - opRes.UnpackSize = inSecCrcStreamSpec->GetSize(); - } - - if (_options.PasswordIsDefined) - { - if (opRes.PackSize < opRes.UnpackSize + - (_options.IsAesMode ? _filterAesSpec->GetAddPackSize() : NCrypto::NZip::kHeaderSize)) - break; - } - else if (opRes.PackSize < opRes.UnpackSize) - break; - } - - - opRes.Method = method; - return S_OK; -} - -}} +// 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 UInt32 kLzmaPropsSize = 5; +static const UInt32 kLzmaHeaderSize = 4 + kLzmaPropsSize; + +class CLzmaEncoder: + public ICompressCoder, + public ICompressSetCoderProperties, + public ICompressSetCoderPropertiesOpt, + public CMyUnknownImp +{ +public: + NCompress::NLzma::CEncoder *EncoderSpec; + CMyComPtr Encoder; + Byte Header[kLzmaHeaderSize]; + + 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); + + MY_UNKNOWN_IMP2( + ICompressSetCoderProperties, + ICompressSetCoderPropertiesOpt) +}; + +STDMETHODIMP CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) +{ + if (!Encoder) + { + EncoderSpec = new NCompress::NLzma::CEncoder; + Encoder = EncoderSpec; + } + CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; + CMyComPtr 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; +} + +STDMETHODIMP CLzmaEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) +{ + return EncoderSpec->SetCoderPropertiesOpt(propIDs, props, numProps); +} + +STDMETHODIMP CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + RINOK(WriteStream(outStream, Header, kLzmaHeaderSize)); + return Encoder->Code(inStream, outStream, inSize, outSize, progress); +} + + +CAddCommon::CAddCommon(const CCompressionMethodMode &options): + _options(options), + _copyCoderSpec(NULL), + _cryptoStreamSpec(NULL), + _buf(NULL), + _isLzmaEos(false) + {} + +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; + + Byte method = _options.MethodSequence[0]; + + if (method == NCompressionMethod::kStore && !_options.PasswordIsDefined) + opRes.PackSize = unpackSize; + + opRes.CRC = 0; + + opRes.LzmaEos = false; + + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; + opRes.DescriptorMode = outSeqMode; + + if (_options.PasswordIsDefined) + { + 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, + 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 inCrcStream = inSecCrcStreamSpec; + + CMyComPtr 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->Init(); + + unsigned numTestMethods = _options.MethodSequence.Size(); + + bool descriptorMode = outSeqMode; + if (!outSeqMode) + if (inSeqMode && _options.PasswordIsDefined && !_options.IsAesMode) + descriptorMode = true; + opRes.DescriptorMode = descriptorMode; + + if (numTestMethods > 1) + if (inSeqMode || outSeqMode || !inStream2) + numTestMethods = 1; + + UInt32 crc = 0; + bool crc_IsCalculated = false; + + Byte method = 0; + CFilterCoder::C_OutStream_Releaser outStreamReleaser; + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; + + for (unsigned i = 0; i < numTestMethods; i++) + { + opRes.LzmaEos = false; + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; + + if (i != 0) + { + if (inStream2) + { + inSecCrcStreamSpec->Init(); + RINOK(inStream2->Seek(0, STREAM_SEEK_SET, NULL)); + } + + RINOK(outStream->SetSize(0)); + RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL)); + } + + if (_options.PasswordIsDefined) + { + 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(inStream2->Seek(0, STREAM_SEEK_SET, NULL)); + inSecCrcStreamSpec->Init(); + } + check = (crc >> 16); + } + + RINOK(_filterSpec->WriteHeader_Check16(outStream, (UInt16)check)); + } + + RINOK(_cryptoStreamSpec->SetOutStream(outStream)); + RINOK(_cryptoStreamSpec->InitEncoder()); + outStreamReleaser.FilterCoder = _cryptoStreamSpec; + } + + method = _options.MethodSequence[i]; + + switch (method) + { + case NCompressionMethod::kStore: + { + if (descriptorMode) + { + // we still can create descriptor_mode archives with "Store" method, but they are not good for 100% + return E_NOTIMPL; + } + + if (!_copyCoderSpec) + { + _copyCoderSpec = new NCompress::CCopyCoder; + _copyCoder = _copyCoderSpec; + } + CMyComPtr outStreamNew; + if (_options.PasswordIsDefined) + 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 setCoderProps; + _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProps); + if (setCoderProps) + { + if (!_options._methods.IsEmpty()) + { + COneMethodInfo *oneMethodMain = &_options._methods[0]; + + RINOK(oneMethodMain->SetCoderProps(setCoderProps, + _options._dataSizeReduceDefined ? &_options._dataSizeReduce : NULL)); + } + } + } + if (method == NCompressionMethod::kLZMA) + _isLzmaEos = _lzmaEncoder->EncoderSpec->IsWriteEndMark(); + } + + if (method == NCompressionMethod::kLZMA) + opRes.LzmaEos = _isLzmaEos; + + CMyComPtr outStreamNew; + if (_options.PasswordIsDefined) + outStreamNew = _cryptoStream; + else + outStreamNew = outStream; + if (_compressExtractVersion > opRes.ExtractVersion) + opRes.ExtractVersion = _compressExtractVersion; + + { + CMyComPtr optProps; + _compressEncoder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps); + if (optProps) + { + PROPID propID = NCoderPropID::kExpectedDataSize; + NWindows::NCOM::CPropVariant prop = (UInt64)expectedDataSize; + RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1)); + } + } + + RINOK(_compressEncoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress)); + break; + } + } + + if (_options.PasswordIsDefined) + { + RINOK(_cryptoStreamSpec->OutStreamFinish()); + + if (_options.IsAesMode) + { + RINOK(_filterAesSpec->WriteFooter(outStream)); + } + } + + RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize)); + + { + opRes.CRC = inSecCrcStreamSpec->GetCRC(); + opRes.UnpackSize = inSecCrcStreamSpec->GetSize(); + } + + if (_options.PasswordIsDefined) + { + if (opRes.PackSize < opRes.UnpackSize + + (_options.IsAesMode ? _filterAesSpec->GetAddPackSize() : NCrypto::NZip::kHeaderSize)) + break; + } + else if (opRes.PackSize < opRes.UnpackSize) + break; + } + + + opRes.Method = method; + return S_OK; +} + +}} diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.h b/CPP/7zip/Archive/Zip/ZipAddCommon.h index 6f3b0f652..ff3251db2 100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.h +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.h @@ -1,69 +1,69 @@ -// ZipAddCommon.h - -#ifndef __ZIP_ADD_COMMON_H -#define __ZIP_ADD_COMMON_H - -#include "../../ICoder.h" -#include "../../IProgress.h" - -#include "../../Common/CreateCoder.h" -#include "../../Common/FilterCoder.h" - -#include "../../Compress/CopyCoder.h" - -#include "../../Crypto/ZipCrypto.h" -#include "../../Crypto/WzAes.h" - -#include "ZipCompressionMode.h" - -namespace NArchive { -namespace NZip { - -struct CCompressingResult -{ - UInt64 UnpackSize; - UInt64 PackSize; - UInt32 CRC; - UInt16 Method; - Byte ExtractVersion; - bool DescriptorMode; - bool LzmaEos; -}; - -class CAddCommon -{ - CCompressionMethodMode _options; - NCompress::CCopyCoder *_copyCoderSpec; - CMyComPtr _copyCoder; - - CMyComPtr _compressEncoder; - Byte _compressExtractVersion; - bool _isLzmaEos; - - CFilterCoder *_cryptoStreamSpec; - CMyComPtr _cryptoStream; - - NCrypto::NZip::CEncoder *_filterSpec; - NCrypto::NWzAes::CEncoder *_filterAesSpec; - - Byte *_buf; - - HRESULT CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC); -public: - CAddCommon(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, - ICompressProgressInfo *progress, CCompressingResult &opRes); -}; - -}} - -#endif +// ZipAddCommon.h + +#ifndef __ZIP_ADD_COMMON_H +#define __ZIP_ADD_COMMON_H + +#include "../../ICoder.h" +#include "../../IProgress.h" + +#include "../../Common/CreateCoder.h" +#include "../../Common/FilterCoder.h" + +#include "../../Compress/CopyCoder.h" + +#include "../../Crypto/ZipCrypto.h" +#include "../../Crypto/WzAes.h" + +#include "ZipCompressionMode.h" + +namespace NArchive { +namespace NZip { + +struct CCompressingResult +{ + UInt64 UnpackSize; + UInt64 PackSize; + UInt32 CRC; + UInt16 Method; + Byte ExtractVersion; + bool DescriptorMode; + bool LzmaEos; +}; + +class CAddCommon +{ + CCompressionMethodMode _options; + NCompress::CCopyCoder *_copyCoderSpec; + CMyComPtr _copyCoder; + + CMyComPtr _compressEncoder; + Byte _compressExtractVersion; + bool _isLzmaEos; + + CFilterCoder *_cryptoStreamSpec; + CMyComPtr _cryptoStream; + + NCrypto::NZip::CEncoder *_filterSpec; + NCrypto::NWzAes::CEncoder *_filterAesSpec; + + Byte *_buf; + + HRESULT CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC); +public: + CAddCommon(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, + ICompressProgressInfo *progress, CCompressingResult &opRes); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Zip/ZipCompressionMode.h b/CPP/7zip/Archive/Zip/ZipCompressionMode.h index 9679dce4a..1125f6ed9 100644 --- a/CPP/7zip/Archive/Zip/ZipCompressionMode.h +++ b/CPP/7zip/Archive/Zip/ZipCompressionMode.h @@ -1,54 +1,54 @@ -// CompressionMode.h - -#ifndef __ZIP_COMPRESSION_MODE_H -#define __ZIP_COMPRESSION_MODE_H - -#include "../../../Common/MyString.h" - -#ifndef _7ZIP_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 MethodSequence; - bool PasswordIsDefined; - AString Password; - - UInt64 _dataSizeReduce; - bool _dataSizeReduceDefined; - - bool IsRealAesMode() const { return PasswordIsDefined && IsAesMode; } - - CCompressionMethodMode(): PasswordIsDefined(false) - { - _dataSizeReduceDefined = false; - _dataSizeReduce = 0; - } -}; - -}} - -#endif +// CompressionMode.h + +#ifndef __ZIP_COMPRESSION_MODE_H +#define __ZIP_COMPRESSION_MODE_H + +#include "../../../Common/MyString.h" + +#ifndef _7ZIP_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 MethodSequence; + bool PasswordIsDefined; + AString Password; + + UInt64 _dataSizeReduce; + bool _dataSizeReduceDefined; + + bool IsRealAesMode() const { return PasswordIsDefined && IsAesMode; } + + CCompressionMethodMode(): PasswordIsDefined(false) + { + _dataSizeReduceDefined = false; + _dataSizeReduce = 0; + } +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp index cea766d71..a4794f512 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp @@ -1,1470 +1,1470 @@ -// 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" -#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" -}; - - -const char * const kMethodNames2[kNumMethodNames2] = -{ - "xz" - , "Jpeg" - , "WavPack" - , "PPMd" - , "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" }, - // { 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 -}; - -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 - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break; - case kpidComment: 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.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; - } - prop.Detach(value); - COM_TRY_END - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = m_Items.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItemEx &item = m_Items[index]; - const CExtraBlock &extra = item.GetMainExtra(); - - switch (propID) - { - case kpidPath: - { - UString res; - item.GetUnicodeString(res, item.Name, false, _forceCodePage, _specifiedCodePage); - NItemName::ReplaceToOsSlashes_Remove_TailSlash(res); - /* - 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.FromCentral || !item.FromLocal || !item.HasDescriptor() || item.DescriptorWasRead) - prop = item.Size; - break; - } - - case kpidPackSize: prop = item.PackSize; break; - - case kpidTimeType: - { - FILETIME ft; - UInt32 unixTime; - UInt32 type; - if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft)) - type = NFileTimeType::kWindows; - else if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) - type = NFileTimeType::kUnix; - else - type = NFileTimeType::kDOS; - prop = type; - break; - } - - case kpidCTime: - { - FILETIME utc; - bool defined = true; - if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, utc)) - { - UInt32 unixTime = 0; - if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kCTime, unixTime)) - NTime::UnixTimeToFileTime(unixTime, utc); - else - defined = false; - } - if (defined) - prop = utc; - break; - } - - case kpidATime: - { - FILETIME utc; - bool defined = true; - if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, utc)) - { - UInt32 unixTime = 0; - if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kATime, unixTime)) - NTime::UnixTimeToFileTime(unixTime, utc); - else - defined = false; - } - if (defined) - prop = utc; - - break; - } - - case kpidMTime: - { - FILETIME utc; - bool defined = true; - if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc)) - { - UInt32 unixTime = 0; - if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) - NTime::UnixTimeToFileTime(unixTime, utc); - else - { - FILETIME localFileTime; - if (item.Time == 0) - defined = false; - else if (!NTime::DosTimeToFileTime(item.Time, localFileTime) || - !LocalFileTimeToFileTime(&localFileTime, &utc)) - utc.dwHighDateTime = utc.dwLowDateTime = 0; - } - } - if (defined) - prop = utc; - 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: - { - unsigned id = item.Method; - AString m; - - if (item.IsEncrypted()) - { - if (id == NFileHeader::NCompressionMethod::kWzAES) - { - m += kMethod_AES; - CWzAesExtra aesField; - if (extra.GetWzAes(aesField)) - { - m += '-'; - m.Add_UInt32(((unsigned)aesField.Strength + 1) * 64); - id = aesField.Method; - } - } - else if (item.IsStrongEncrypted()) - { - CStrongCryptoExtra f; - f.AlgId = 0; - if (extra.GetStrongCrypto(f)) - { - const char *s = FindNameForId(k_StrongCryptoPairs, 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 += ' '; - } - - { - const char *s = NULL; - if (id < kNumMethodNames1) - s = kMethodNames1[id]; - else - { - int id2 = (int)id - (int)kMethodNames2Start; - if (id2 >= 0 && 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 &= ~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 &= ~(6); // we don't need compression related bits here. - - if (flags != 0) - { - AString s2 = FlagsToString(g_HeaderCharacts, ARRAY_SIZE(g_HeaderCharacts), flags); - if (!s2.IsEmpty()) - { - if (!s.IsEmpty()) - s.Add_OptSpaced(":"); - s.Add_OptSpaced(s2); - } - } - - if (!item.FromCentral && item.FromLocal && item.HasDescriptor() && !item.DescriptorWasRead) - 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; - */ - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - - -/* -STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) -{ - *numProps = 0; - return S_OK; -} - -STDMETHODIMP CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) -{ - UNUSED_VAR(index); - *propID = 0; - *name = 0; - return S_OK; -} - -STDMETHODIMP 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; -} - -STDMETHODIMP 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 &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(); - } - } -} -*/ - -STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) -{ - COM_TRY_BEGIN - try - { - Close(); - 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 -} - -STDMETHODIMP CHandler::Close() -{ - m_Items.Clear(); - m_Archive.Close(); - return S_OK; -} - - -class CLzmaDecoder: - public ICompressCoder, - public ICompressSetFinishMode, - public ICompressGetInStreamProcessedSize, - public CMyUnknownImp -{ -public: - NCompress::NLzma::CDecoder *DecoderSpec; - CMyComPtr Decoder; - - MY_UNKNOWN_IMP2( - ICompressSetFinishMode, - ICompressGetInStreamProcessedSize) - - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - STDMETHOD(SetFinishMode)(UInt32 finishMode); - STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); - - CLzmaDecoder(); -}; - -CLzmaDecoder::CLzmaDecoder() -{ - DecoderSpec = new NCompress::NLzma::CDecoder; - Decoder = DecoderSpec; -} - -static const unsigned kZipLzmaPropsSize = 4 + LZMA_PROPS_SIZE; - -HRESULT 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); -} - -STDMETHODIMP CLzmaDecoder::SetFinishMode(UInt32 finishMode) -{ - DecoderSpec->FinishStream = (finishMode != 0); - return S_OK; -} - -STDMETHODIMP CLzmaDecoder::GetInStreamProcessedSize(UInt64 *value) -{ - *value = DecoderSpec->GetInputProcessedSize() + kZipLzmaPropsSize; - return S_OK; -} - - - - - - - -struct CMethodItem -{ - unsigned ZipMethod; - CMyComPtr Coder; -}; - - - -class CZipDecoder -{ - NCrypto::NZip::CDecoder *_zipCryptoDecoderSpec; - NCrypto::NZipStrong::CDecoder *_pkAesDecoderSpec; - NCrypto::NWzAes::CDecoder *_wzAesDecoderSpec; - - CMyComPtr _zipCryptoDecoder; - CMyComPtr _pkAesDecoder; - CMyComPtr _wzAesDecoder; - - CFilterCoder *filterStreamSpec; - CMyComPtr filterStream; - CMyComPtr getTextPassword; - CObjectVector methodItems; - - CLzmaDecoder *lzmaDecoderSpec; -public: - CZipDecoder(): - _zipCryptoDecoderSpec(0), - _pkAesDecoderSpec(0), - _wzAesDecoderSpec(0), - filterStreamSpec(0), - lzmaDecoderSpec(0) - {} - - HRESULT Decode( - DECL_EXTERNAL_CODECS_LOC_VARS - CInArchive &archive, const CItemEx &item, - ISequentialOutStream *realOutStream, - IArchiveExtractCallback *extractCallback, - ICompressProgressInfo *compressProgress, - #ifndef _7ZIP_ST - UInt32 numThreads, UInt64 memUsage, - #endif - Int32 &res); -}; - - -static HRESULT SkipStreamData(ISequentialInStream *stream, bool &thereAreData) -{ - thereAreData = false; - const size_t kBufSize = 1 << 12; - Byte buf[kBufSize]; - for (;;) - { - size_t size = kBufSize; - RINOK(ReadStream(stream, buf, &size)); - if (size == 0) - return S_OK; - thereAreData = true; - } -} - - -HRESULT CZipDecoder::Decode( - DECL_EXTERNAL_CODECS_LOC_VARS - CInArchive &archive, const CItemEx &item, - ISequentialOutStream *realOutStream, - IArchiveExtractCallback *extractCallback, - ICompressProgressInfo *compressProgress, - #ifndef _7ZIP_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; - - unsigned id = item.Method; - - if (item.IsEncrypted()) - { - if (item.IsStrongEncrypted()) - { - CStrongCryptoExtra f; - if (!item.CentralExtra.GetStrongCrypto(f)) - { - res = NExtract::NOperationResult::kUnsupportedMethod; - return S_OK; - } - pkAesMode = true; - } - else if (id == NFileHeader::NCompressionMethod::kWzAES) - { - CWzAesExtra aesField; - if (!item.GetMainExtra().GetWzAes(aesField)) - return S_OK; - wzAesMode = true; - needCRC = aesField.NeedCrc(); - } - } - - COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; - CMyComPtr outStream = outStreamSpec; - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(needCRC); - - CMyComPtr packStream; - - CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream; - CMyComPtr 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 cryptoFilter; - - if (item.IsEncrypted()) - { - if (wzAesMode) - { - CWzAesExtra aesField; - if (!item.GetMainExtra().GetWzAes(aesField)) - return S_OK; - 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 cryptoSetPassword; - RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword)); - if (!cryptoSetPassword) - return E_FAIL; - - if (!getTextPassword) - extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword); - - if (getTextPassword) - { - CMyComBSTR password; - RINOK(getTextPassword->CryptoGetTextPassword(&password)); - AString charPassword; - if (password) - { - UnicodeStringToMultiByte2(charPassword, (const wchar_t *)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); - 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); - } - - ICompressCoder *coder = methodItems[m].Coder; - - - #ifndef _7ZIP_ST - { - CMyComPtr setCoderMt; - coder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt); - if (setCoderMt) - { - RINOK(setCoderMt->SetNumberOfThreads(numThreads)); - } - } - // if (memUsage != 0) - { - CMyComPtr setMemLimit; - coder->QueryInterface(IID_ICompressSetMemLimit, (void **)&setMemLimit); - if (setMemLimit) - { - RINOK(setMemLimit->SetMemLimit(memUsage)); - } - } - #endif - - { - CMyComPtr setDecoderProperties; - coder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties); - if (setDecoderProperties) - { - Byte properties = (Byte)item.Flags; - RINOK(setDecoderProperties->SetDecoderProperties2(&properties, 1)); - } - } - - - CMyComPtr inStreamNew; - - bool isFullStreamExpected = (!item.HasDescriptor() || item.PackSize != 0); - bool needReminderCheck = false; - - bool dataAfterEnd = false; - bool truncatedError = false; - bool lzmaEosError = false; - - { - 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) - { - 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)); - - inStreamNew = filterStream; - } - } - else - inStreamNew = inStream; - - if (result == S_OK) - { - CMyComPtr setFinishMode; - coder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode); - if (setFinishMode) - { - RINOK(setFinishMode->SetFinishMode(BoolToInt(true))); - } - - const UInt64 coderPackSize = limitedStreamSpec->GetRem(); - - bool useUnpackLimit = (id == 0 - || !item.HasDescriptor() - || item.Size >= ((UInt64)1 << 32) - || item.LocalExtra.IsZip64 - || item.CentralExtra.IsZip64 - ); - - result = coder->Code(inStreamNew, outStream, - isFullStreamExpected ? &coderPackSize : NULL, - // NULL, - useUnpackLimit ? &item.Size : NULL, - compressProgress); - - if (result == S_OK) - { - CMyComPtr 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; - // also here we can check PKCS7 padding data from reminder (it can be inside stream buffer in coder). - } - } - else - { - if (processed < coderPackSize) - { - if (isFullStreamExpected) - dataAfterEnd = true; - } - else if (processed > coderPackSize) - 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 (wzAesMode) - { - bool thereAreData = false; - if (SkipStreamData(inStreamNew, thereAreData) != S_OK) - authOk = false; - - if (needReminderCheck && thereAreData) - dataAfterEnd = true; - - 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 (truncatedError) - res = NExtract::NOperationResult::kUnexpectedEnd; - else if (lzmaEosError) - res = NExtract::NOperationResult::kHeadersError; - - // 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; -} - - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - CZipDecoder myDecoder; - UInt64 totalUnPacked = 0, totalPacked = 0; - bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = m_Items.Size(); - if (numItems == 0) - return S_OK; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const CItemEx &item = m_Items[allFilesMode ? i : indices[i]]; - totalUnPacked += item.Size; - totalPacked += item.PackSize; - } - RINOK(extractCallback->SetTotal(totalUnPacked)); - - UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0; - UInt64 currentItemUnPacked, currentItemPacked; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - for (i = 0; i < numItems; i++, - currentTotalUnPacked += currentItemUnPacked, - currentTotalPacked += currentItemPacked) - { - currentItemUnPacked = 0; - currentItemPacked = 0; - - lps->InSize = currentTotalPacked; - lps->OutSize = currentTotalUnPacked; - RINOK(lps->SetCur()); - - CMyComPtr realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - UInt32 index = allFilesMode ? i : indices[i]; - - CItemEx item = m_Items[index]; - bool isLocalOffsetOK = m_Archive.IsLocalOffsetOK(item); - bool skip = !isLocalOffsetOK && !item.IsDir(); - if (skip) - askMode = NExtract::NAskMode::kSkip; - - currentItemUnPacked = item.Size; - currentItemPacked = item.PackSize; - - 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; - HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item, isAvail, headersError); - if (res == 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(res); - } - - 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; - HRESULT hres = myDecoder.Decode( - EXTERNAL_CODECS_VARS - m_Archive, item, realOutStream, extractCallback, - progress, - #ifndef _7ZIP_ST - _props._numThreads, _props._memUsage, - #endif - res); - - RINOK(hres); - realOutStream.Release(); - - if (res == NExtract::NOperationResult::kOK && headersError) - res = NExtract::NOperationResult::kHeadersError; - - RINOK(extractCallback->SetOperationResult(res)) - } - - lps->InSize = currentTotalPacked; - lps->OutSize = currentTotalUnPacked; - return lps->SetCur(); - COM_TRY_END -} - -IMPL_ISetCompressCodecsInfo - -}} +// 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" +#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" +}; + + +const char * const kMethodNames2[kNumMethodNames2] = +{ + "xz" + , "Jpeg" + , "WavPack" + , "PPMd" + , "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" }, + // { 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 +}; + +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 + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break; + case kpidComment: 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.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; + } + prop.Detach(value); + COM_TRY_END + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = m_Items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItemEx &item = m_Items[index]; + const CExtraBlock &extra = item.GetMainExtra(); + + switch (propID) + { + case kpidPath: + { + UString res; + item.GetUnicodeString(res, item.Name, false, _forceCodePage, _specifiedCodePage); + NItemName::ReplaceToOsSlashes_Remove_TailSlash(res); + /* + 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.FromCentral || !item.FromLocal || !item.HasDescriptor() || item.DescriptorWasRead) + prop = item.Size; + break; + } + + case kpidPackSize: prop = item.PackSize; break; + + case kpidTimeType: + { + FILETIME ft; + UInt32 unixTime; + UInt32 type; + if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft)) + type = NFileTimeType::kWindows; + else if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) + type = NFileTimeType::kUnix; + else + type = NFileTimeType::kDOS; + prop = type; + break; + } + + case kpidCTime: + { + FILETIME utc; + bool defined = true; + if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, utc)) + { + UInt32 unixTime = 0; + if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kCTime, unixTime)) + NTime::UnixTimeToFileTime(unixTime, utc); + else + defined = false; + } + if (defined) + prop = utc; + break; + } + + case kpidATime: + { + FILETIME utc; + bool defined = true; + if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, utc)) + { + UInt32 unixTime = 0; + if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kATime, unixTime)) + NTime::UnixTimeToFileTime(unixTime, utc); + else + defined = false; + } + if (defined) + prop = utc; + + break; + } + + case kpidMTime: + { + FILETIME utc; + bool defined = true; + if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc)) + { + UInt32 unixTime = 0; + if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) + NTime::UnixTimeToFileTime(unixTime, utc); + else + { + FILETIME localFileTime; + if (item.Time == 0) + defined = false; + else if (!NTime::DosTimeToFileTime(item.Time, localFileTime) || + !LocalFileTimeToFileTime(&localFileTime, &utc)) + utc.dwHighDateTime = utc.dwLowDateTime = 0; + } + } + if (defined) + prop = utc; + 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: + { + unsigned id = item.Method; + AString m; + + if (item.IsEncrypted()) + { + if (id == NFileHeader::NCompressionMethod::kWzAES) + { + m += kMethod_AES; + CWzAesExtra aesField; + if (extra.GetWzAes(aesField)) + { + m += '-'; + m.Add_UInt32(((unsigned)aesField.Strength + 1) * 64); + id = aesField.Method; + } + } + else if (item.IsStrongEncrypted()) + { + CStrongCryptoExtra f; + f.AlgId = 0; + if (extra.GetStrongCrypto(f)) + { + const char *s = FindNameForId(k_StrongCryptoPairs, 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 += ' '; + } + + { + const char *s = NULL; + if (id < kNumMethodNames1) + s = kMethodNames1[id]; + else + { + int id2 = (int)id - (int)kMethodNames2Start; + if (id2 >= 0 && 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 &= ~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 &= ~(6); // we don't need compression related bits here. + + if (flags != 0) + { + AString s2 = FlagsToString(g_HeaderCharacts, ARRAY_SIZE(g_HeaderCharacts), flags); + if (!s2.IsEmpty()) + { + if (!s.IsEmpty()) + s.Add_OptSpaced(":"); + s.Add_OptSpaced(s2); + } + } + + if (!item.FromCentral && item.FromLocal && item.HasDescriptor() && !item.DescriptorWasRead) + 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; + */ + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + + +/* +STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) +{ + *numProps = 0; + return S_OK; +} + +STDMETHODIMP CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) +{ + UNUSED_VAR(index); + *propID = 0; + *name = 0; + return S_OK; +} + +STDMETHODIMP 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; +} + +STDMETHODIMP 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 &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(); + } + } +} +*/ + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + try + { + Close(); + 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 +} + +STDMETHODIMP CHandler::Close() +{ + m_Items.Clear(); + m_Archive.Close(); + return S_OK; +} + + +class CLzmaDecoder: + public ICompressCoder, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize, + public CMyUnknownImp +{ +public: + NCompress::NLzma::CDecoder *DecoderSpec; + CMyComPtr Decoder; + + MY_UNKNOWN_IMP2( + ICompressSetFinishMode, + ICompressGetInStreamProcessedSize) + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + STDMETHOD(SetFinishMode)(UInt32 finishMode); + STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); + + CLzmaDecoder(); +}; + +CLzmaDecoder::CLzmaDecoder() +{ + DecoderSpec = new NCompress::NLzma::CDecoder; + Decoder = DecoderSpec; +} + +static const unsigned kZipLzmaPropsSize = 4 + LZMA_PROPS_SIZE; + +HRESULT 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); +} + +STDMETHODIMP CLzmaDecoder::SetFinishMode(UInt32 finishMode) +{ + DecoderSpec->FinishStream = (finishMode != 0); + return S_OK; +} + +STDMETHODIMP CLzmaDecoder::GetInStreamProcessedSize(UInt64 *value) +{ + *value = DecoderSpec->GetInputProcessedSize() + kZipLzmaPropsSize; + return S_OK; +} + + + + + + + +struct CMethodItem +{ + unsigned ZipMethod; + CMyComPtr Coder; +}; + + + +class CZipDecoder +{ + NCrypto::NZip::CDecoder *_zipCryptoDecoderSpec; + NCrypto::NZipStrong::CDecoder *_pkAesDecoderSpec; + NCrypto::NWzAes::CDecoder *_wzAesDecoderSpec; + + CMyComPtr _zipCryptoDecoder; + CMyComPtr _pkAesDecoder; + CMyComPtr _wzAesDecoder; + + CFilterCoder *filterStreamSpec; + CMyComPtr filterStream; + CMyComPtr getTextPassword; + CObjectVector methodItems; + + CLzmaDecoder *lzmaDecoderSpec; +public: + CZipDecoder(): + _zipCryptoDecoderSpec(0), + _pkAesDecoderSpec(0), + _wzAesDecoderSpec(0), + filterStreamSpec(0), + lzmaDecoderSpec(0) + {} + + HRESULT Decode( + DECL_EXTERNAL_CODECS_LOC_VARS + CInArchive &archive, const CItemEx &item, + ISequentialOutStream *realOutStream, + IArchiveExtractCallback *extractCallback, + ICompressProgressInfo *compressProgress, + #ifndef _7ZIP_ST + UInt32 numThreads, UInt64 memUsage, + #endif + Int32 &res); +}; + + +static HRESULT SkipStreamData(ISequentialInStream *stream, bool &thereAreData) +{ + thereAreData = false; + const size_t kBufSize = 1 << 12; + Byte buf[kBufSize]; + for (;;) + { + size_t size = kBufSize; + RINOK(ReadStream(stream, buf, &size)); + if (size == 0) + return S_OK; + thereAreData = true; + } +} + + +HRESULT CZipDecoder::Decode( + DECL_EXTERNAL_CODECS_LOC_VARS + CInArchive &archive, const CItemEx &item, + ISequentialOutStream *realOutStream, + IArchiveExtractCallback *extractCallback, + ICompressProgressInfo *compressProgress, + #ifndef _7ZIP_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; + + unsigned id = item.Method; + + if (item.IsEncrypted()) + { + if (item.IsStrongEncrypted()) + { + CStrongCryptoExtra f; + if (!item.CentralExtra.GetStrongCrypto(f)) + { + res = NExtract::NOperationResult::kUnsupportedMethod; + return S_OK; + } + pkAesMode = true; + } + else if (id == NFileHeader::NCompressionMethod::kWzAES) + { + CWzAesExtra aesField; + if (!item.GetMainExtra().GetWzAes(aesField)) + return S_OK; + wzAesMode = true; + needCRC = aesField.NeedCrc(); + } + } + + COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; + CMyComPtr outStream = outStreamSpec; + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(needCRC); + + CMyComPtr packStream; + + CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream; + CMyComPtr 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 cryptoFilter; + + if (item.IsEncrypted()) + { + if (wzAesMode) + { + CWzAesExtra aesField; + if (!item.GetMainExtra().GetWzAes(aesField)) + return S_OK; + 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 cryptoSetPassword; + RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword)); + if (!cryptoSetPassword) + return E_FAIL; + + if (!getTextPassword) + extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword); + + if (getTextPassword) + { + CMyComBSTR password; + RINOK(getTextPassword->CryptoGetTextPassword(&password)); + AString charPassword; + if (password) + { + UnicodeStringToMultiByte2(charPassword, (const wchar_t *)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); + 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); + } + + ICompressCoder *coder = methodItems[m].Coder; + + + #ifndef _7ZIP_ST + { + CMyComPtr setCoderMt; + coder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt); + if (setCoderMt) + { + RINOK(setCoderMt->SetNumberOfThreads(numThreads)); + } + } + // if (memUsage != 0) + { + CMyComPtr setMemLimit; + coder->QueryInterface(IID_ICompressSetMemLimit, (void **)&setMemLimit); + if (setMemLimit) + { + RINOK(setMemLimit->SetMemLimit(memUsage)); + } + } + #endif + + { + CMyComPtr setDecoderProperties; + coder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties); + if (setDecoderProperties) + { + Byte properties = (Byte)item.Flags; + RINOK(setDecoderProperties->SetDecoderProperties2(&properties, 1)); + } + } + + + CMyComPtr inStreamNew; + + bool isFullStreamExpected = (!item.HasDescriptor() || item.PackSize != 0); + bool needReminderCheck = false; + + bool dataAfterEnd = false; + bool truncatedError = false; + bool lzmaEosError = false; + + { + 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) + { + 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)); + + inStreamNew = filterStream; + } + } + else + inStreamNew = inStream; + + if (result == S_OK) + { + CMyComPtr setFinishMode; + coder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode); + if (setFinishMode) + { + RINOK(setFinishMode->SetFinishMode(BoolToInt(true))); + } + + const UInt64 coderPackSize = limitedStreamSpec->GetRem(); + + bool useUnpackLimit = (id == 0 + || !item.HasDescriptor() + || item.Size >= ((UInt64)1 << 32) + || item.LocalExtra.IsZip64 + || item.CentralExtra.IsZip64 + ); + + result = coder->Code(inStreamNew, outStream, + isFullStreamExpected ? &coderPackSize : NULL, + // NULL, + useUnpackLimit ? &item.Size : NULL, + compressProgress); + + if (result == S_OK) + { + CMyComPtr 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; + // also here we can check PKCS7 padding data from reminder (it can be inside stream buffer in coder). + } + } + else + { + if (processed < coderPackSize) + { + if (isFullStreamExpected) + dataAfterEnd = true; + } + else if (processed > coderPackSize) + 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 (wzAesMode) + { + bool thereAreData = false; + if (SkipStreamData(inStreamNew, thereAreData) != S_OK) + authOk = false; + + if (needReminderCheck && thereAreData) + dataAfterEnd = true; + + 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 (truncatedError) + res = NExtract::NOperationResult::kUnexpectedEnd; + else if (lzmaEosError) + res = NExtract::NOperationResult::kHeadersError; + + // 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; +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + CZipDecoder myDecoder; + UInt64 totalUnPacked = 0, totalPacked = 0; + bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = m_Items.Size(); + if (numItems == 0) + return S_OK; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const CItemEx &item = m_Items[allFilesMode ? i : indices[i]]; + totalUnPacked += item.Size; + totalPacked += item.PackSize; + } + RINOK(extractCallback->SetTotal(totalUnPacked)); + + UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0; + UInt64 currentItemUnPacked, currentItemPacked; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++, + currentTotalUnPacked += currentItemUnPacked, + currentTotalPacked += currentItemPacked) + { + currentItemUnPacked = 0; + currentItemPacked = 0; + + lps->InSize = currentTotalPacked; + lps->OutSize = currentTotalUnPacked; + RINOK(lps->SetCur()); + + CMyComPtr realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + + CItemEx item = m_Items[index]; + bool isLocalOffsetOK = m_Archive.IsLocalOffsetOK(item); + bool skip = !isLocalOffsetOK && !item.IsDir(); + if (skip) + askMode = NExtract::NAskMode::kSkip; + + currentItemUnPacked = item.Size; + currentItemPacked = item.PackSize; + + 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; + HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item, isAvail, headersError); + if (res == 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(res); + } + + 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; + HRESULT hres = myDecoder.Decode( + EXTERNAL_CODECS_VARS + m_Archive, item, realOutStream, extractCallback, + progress, + #ifndef _7ZIP_ST + _props._numThreads, _props._memUsage, + #endif + res); + + RINOK(hres); + realOutStream.Release(); + + if (res == NExtract::NOperationResult::kOK && headersError) + res = NExtract::NOperationResult::kHeadersError; + + RINOK(extractCallback->SetOperationResult(res)) + } + + lps->InSize = currentTotalPacked; + lps->OutSize = currentTotalUnPacked; + return lps->SetCur(); + COM_TRY_END +} + +IMPL_ISetCompressCodecsInfo + +}} diff --git a/CPP/7zip/Archive/Zip/ZipHandler.h b/CPP/7zip/Archive/Zip/ZipHandler.h index 404ecc9a7..bee57c00d 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.h +++ b/CPP/7zip/Archive/Zip/ZipHandler.h @@ -1,89 +1,89 @@ -// Zip/Handler.h - -#ifndef __ZIP_HANDLER_H -#define __ZIP_HANDLER_H - -#include "../../../Common/DynamicBuffer.h" -#include "../../ICoder.h" -#include "../IArchive.h" - -#include "../../Common/CreateCoder.h" - -#include "ZipCompressionMode.h" -#include "ZipIn.h" - -namespace NArchive { -namespace NZip { - -const unsigned kNumMethodNames1 = NFileHeader::NCompressionMethod::kLZMA + 1; -const unsigned kMethodNames2Start = NFileHeader::NCompressionMethod::kXz; -const unsigned kNumMethodNames2 = NFileHeader::NCompressionMethod::kWzAES + 1 - kMethodNames2Start; - -extern const char * const kMethodNames1[kNumMethodNames1]; -extern const char * const kMethodNames2[kNumMethodNames2]; - - -class CHandler: - public IInArchive, - // public IArchiveGetRawProps, - public IOutArchive, - public ISetProperties, - PUBLIC_ISetCompressCodecsInfo - public CMyUnknownImp -{ -public: - MY_QUERYINTERFACE_BEGIN2(IInArchive) - // MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps) - MY_QUERYINTERFACE_ENTRY(IOutArchive) - MY_QUERYINTERFACE_ENTRY(ISetProperties) - QUERY_ENTRY_ISetCompressCodecsInfo - MY_QUERYINTERFACE_END - MY_ADDREF_RELEASE - - INTERFACE_IInArchive(;) - // INTERFACE_IArchiveGetRawProps(;) - INTERFACE_IOutArchive(;) - - STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); - - DECL_ISetCompressCodecsInfo - - CHandler(); -private: - CObjectVector m_Items; - CInArchive m_Archive; - - CBaseProps _props; - - int m_MainMethod; - bool m_ForceAesMode; - bool m_WriteNtfsTimeExtra; - bool _removeSfxBlock; - bool m_ForceLocal; - bool m_ForceUtf8; - bool _forceCodePage; - UInt32 _specifiedCodePage; - - DECL_EXTERNAL_CODECS_VARS - - void InitMethodProps() - { - _props.Init(); - m_MainMethod = -1; - m_ForceAesMode = false; - m_WriteNtfsTimeExtra = true; - _removeSfxBlock = false; - m_ForceLocal = false; - m_ForceUtf8 = false; - _forceCodePage = false; - _specifiedCodePage = CP_OEMCP; - } - - // void MarkAltStreams(CObjectVector &items); - - HRESULT GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value); -}; - -}} - -#endif +// Zip/Handler.h + +#ifndef __ZIP_HANDLER_H +#define __ZIP_HANDLER_H + +#include "../../../Common/DynamicBuffer.h" +#include "../../ICoder.h" +#include "../IArchive.h" + +#include "../../Common/CreateCoder.h" + +#include "ZipCompressionMode.h" +#include "ZipIn.h" + +namespace NArchive { +namespace NZip { + +const unsigned kNumMethodNames1 = NFileHeader::NCompressionMethod::kLZMA + 1; +const unsigned kMethodNames2Start = NFileHeader::NCompressionMethod::kXz; +const unsigned kNumMethodNames2 = NFileHeader::NCompressionMethod::kWzAES + 1 - kMethodNames2Start; + +extern const char * const kMethodNames1[kNumMethodNames1]; +extern const char * const kMethodNames2[kNumMethodNames2]; + + +class CHandler: + public IInArchive, + // public IArchiveGetRawProps, + public IOutArchive, + public ISetProperties, + PUBLIC_ISetCompressCodecsInfo + public CMyUnknownImp +{ +public: + MY_QUERYINTERFACE_BEGIN2(IInArchive) + // MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps) + MY_QUERYINTERFACE_ENTRY(IOutArchive) + MY_QUERYINTERFACE_ENTRY(ISetProperties) + QUERY_ENTRY_ISetCompressCodecsInfo + MY_QUERYINTERFACE_END + MY_ADDREF_RELEASE + + INTERFACE_IInArchive(;) + // INTERFACE_IArchiveGetRawProps(;) + INTERFACE_IOutArchive(;) + + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); + + DECL_ISetCompressCodecsInfo + + CHandler(); +private: + CObjectVector m_Items; + CInArchive m_Archive; + + CBaseProps _props; + + int m_MainMethod; + bool m_ForceAesMode; + bool m_WriteNtfsTimeExtra; + bool _removeSfxBlock; + bool m_ForceLocal; + bool m_ForceUtf8; + bool _forceCodePage; + UInt32 _specifiedCodePage; + + DECL_EXTERNAL_CODECS_VARS + + void InitMethodProps() + { + _props.Init(); + m_MainMethod = -1; + m_ForceAesMode = false; + m_WriteNtfsTimeExtra = true; + _removeSfxBlock = false; + m_ForceLocal = false; + m_ForceUtf8 = false; + _forceCodePage = false; + _specifiedCodePage = CP_OEMCP; + } + + // void MarkAltStreams(CObjectVector &items); + + HRESULT GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp index aec751053..c21b5605a 100644 --- a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp @@ -1,530 +1,530 @@ -// 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 { - -STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) -{ - *timeType = NFileTimeType::kDOS; - 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 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 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, int index, PROPID propID, FILETIME &filetime) -{ - filetime.dwHighDateTime = filetime.dwLowDateTime = 0; - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(index, propID, &prop)); - if (prop.vt == VT_FILETIME) - filetime = prop.filetime; - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - return S_OK; -} - - -STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *callback) -{ - COM_TRY_BEGIN2 - - if (m_Archive.IsOpen()) - { - if (!m_Archive.CanUpdate()) - return E_NOTIMPL; - } - - CObjectVector updateItems; - updateItems.ClearAndReserve(numItems); - - bool thereAreAesUpdates = false; - UInt64 largestSize = 0; - bool largestSizeDefined = false; - - 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 = 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; - } - } - } - */ - - { - CPropVariant prop; - RINOK(callback->GetProperty(i, kpidTimeType, &prop)); - if (prop.vt == VT_UI4) - ui.NtfsTimeIsDefined = (prop.ulVal == NFileTimeType::kWindows); - else - ui.NtfsTimeIsDefined = m_WriteNtfsTimeExtra; - } - RINOK(GetTime(callback, i, kpidMTime, ui.Ntfs_MTime)); - RINOK(GetTime(callback, i, kpidATime, ui.Ntfs_ATime)); - RINOK(GetTime(callback, i, kpidCTime, ui.Ntfs_CTime)); - - { - FILETIME localFileTime = { 0, 0 }; - if (ui.Ntfs_MTime.dwHighDateTime != 0 || - ui.Ntfs_MTime.dwLowDateTime != 0) - if (!FileTimeToLocalFileTime(&ui.Ntfs_MTime, &localFileTime)) - return E_INVALIDARG; - FileTimeToDosTime(localFileTime, 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; - - UINT codePage = _forceCodePage ? _specifiedCodePage : CP_OEMCP; - - bool tryUtf8 = true; - if ((m_ForceLocal || !m_ForceUtf8) && codePage != CP_UTF8) - { - bool defaultCharWasUsed; - ui.Name = UnicodeStringToMultiByte(name, codePage, '_', defaultCharWasUsed); - tryUtf8 = (!m_ForceLocal && (defaultCharWasUsed || - MultiByteToUnicodeString(ui.Name, codePage) != name)); - } - - if (tryUtf8) - { - ui.IsUtf8 = !name.IsAscii(); - ConvertUnicodeToUTF8(name, ui.Name); - } - - if (ui.Name.Len() >= (1 << 16)) - 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 getTextPassword; - { - CMyComPtr udateCallBack2(callback); - udateCallBack2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword); - } - CCompressionMethodMode options; - (CBaseProps &)options = _props; - options._dataSizeReduce = largestSize; - options._dataSizeReduceDefined = largestSizeDefined; - - options.PasswordIsDefined = false; - options.Password.Empty(); - if (getTextPassword) - { - CMyComBSTR password; - Int32 passwordIsDefined; - RINOK(getTextPassword->CryptoGetTextPassword2(&passwordIsDefined, &password)); - options.PasswordIsDefined = IntToBool(passwordIsDefined); - if (options.PasswordIsDefined) - { - if (!m_ForceAesMode) - options.IsAesMode = thereAreAesUpdates; - - if (!IsSimpleAsciiString(password)) - return E_INVALIDARG; - if (password) - options.Password = UnicodeStringToMultiByte((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; - if (FindMethod_Index(EXTERNAL_CODECS_VARS methodName, true, - methodId, numStreams) < 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); - - return Update( - EXTERNAL_CODECS_VARS - m_Items, updateItems, outStream, - m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock, - options, callback); - - COM_TRY_END2 -} - - - -STDMETHODIMP 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("tc")) - { - RINOK(PROPVARIANT_to_bool(prop, m_WriteNtfsTimeExtra)); - } - 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_Ascii_NoCase("m") && prop.vt == VT_UI4) - { - UInt32 id = prop.ulVal; - if (id > 0xFF) - return E_INVALIDARG; - m_MainMethod = id; - } - else - { - 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 = id; - else if (methodName.IsEqualTo_Ascii_NoCase("Copy")) // it's alias for "Store" - m_MainMethod = 0; - } - } - - return S_OK; -} - -}} +// 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 { + +STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) +{ + *timeType = NFileTimeType::kDOS; + 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 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 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, int index, PROPID propID, FILETIME &filetime) +{ + filetime.dwHighDateTime = filetime.dwLowDateTime = 0; + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(index, propID, &prop)); + if (prop.vt == VT_FILETIME) + filetime = prop.filetime; + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + return S_OK; +} + + +STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *callback) +{ + COM_TRY_BEGIN2 + + if (m_Archive.IsOpen()) + { + if (!m_Archive.CanUpdate()) + return E_NOTIMPL; + } + + CObjectVector updateItems; + updateItems.ClearAndReserve(numItems); + + bool thereAreAesUpdates = false; + UInt64 largestSize = 0; + bool largestSizeDefined = false; + + 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 = 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; + } + } + } + */ + + { + CPropVariant prop; + RINOK(callback->GetProperty(i, kpidTimeType, &prop)); + if (prop.vt == VT_UI4) + ui.NtfsTimeIsDefined = (prop.ulVal == NFileTimeType::kWindows); + else + ui.NtfsTimeIsDefined = m_WriteNtfsTimeExtra; + } + RINOK(GetTime(callback, i, kpidMTime, ui.Ntfs_MTime)); + RINOK(GetTime(callback, i, kpidATime, ui.Ntfs_ATime)); + RINOK(GetTime(callback, i, kpidCTime, ui.Ntfs_CTime)); + + { + FILETIME localFileTime = { 0, 0 }; + if (ui.Ntfs_MTime.dwHighDateTime != 0 || + ui.Ntfs_MTime.dwLowDateTime != 0) + if (!FileTimeToLocalFileTime(&ui.Ntfs_MTime, &localFileTime)) + return E_INVALIDARG; + FileTimeToDosTime(localFileTime, 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; + + UINT codePage = _forceCodePage ? _specifiedCodePage : CP_OEMCP; + + bool tryUtf8 = true; + if ((m_ForceLocal || !m_ForceUtf8) && codePage != CP_UTF8) + { + bool defaultCharWasUsed; + ui.Name = UnicodeStringToMultiByte(name, codePage, '_', defaultCharWasUsed); + tryUtf8 = (!m_ForceLocal && (defaultCharWasUsed || + MultiByteToUnicodeString(ui.Name, codePage) != name)); + } + + if (tryUtf8) + { + ui.IsUtf8 = !name.IsAscii(); + ConvertUnicodeToUTF8(name, ui.Name); + } + + if (ui.Name.Len() >= (1 << 16)) + 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 getTextPassword; + { + CMyComPtr udateCallBack2(callback); + udateCallBack2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword); + } + CCompressionMethodMode options; + (CBaseProps &)options = _props; + options._dataSizeReduce = largestSize; + options._dataSizeReduceDefined = largestSizeDefined; + + options.PasswordIsDefined = false; + options.Password.Empty(); + if (getTextPassword) + { + CMyComBSTR password; + Int32 passwordIsDefined; + RINOK(getTextPassword->CryptoGetTextPassword2(&passwordIsDefined, &password)); + options.PasswordIsDefined = IntToBool(passwordIsDefined); + if (options.PasswordIsDefined) + { + if (!m_ForceAesMode) + options.IsAesMode = thereAreAesUpdates; + + if (!IsSimpleAsciiString(password)) + return E_INVALIDARG; + if (password) + options.Password = UnicodeStringToMultiByte((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; + if (FindMethod_Index(EXTERNAL_CODECS_VARS methodName, true, + methodId, numStreams) < 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); + + return Update( + EXTERNAL_CODECS_VARS + m_Items, updateItems, outStream, + m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock, + options, callback); + + COM_TRY_END2 +} + + + +STDMETHODIMP 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("tc")) + { + RINOK(PROPVARIANT_to_bool(prop, m_WriteNtfsTimeExtra)); + } + 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_Ascii_NoCase("m") && prop.vt == VT_UI4) + { + UInt32 id = prop.ulVal; + if (id > 0xFF) + return E_INVALIDARG; + m_MainMethod = id; + } + else + { + 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 = 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 index f99ae5987..5e6f00e4e 100644 --- a/CPP/7zip/Archive/Zip/ZipHeader.h +++ b/CPP/7zip/Archive/Zip/ZipHeader.h @@ -1,193 +1,193 @@ -// ZipHeader.h - -#ifndef __ARCHIVE_ZIP_HEADER_H -#define __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, - - 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, - kStrongEncrypt = 0x17, - kUnixTime = 0x5455, - kUnixExtra = 0x5855, - kIzUnicodeComment = 0x6375, - kIzUnicodeName = 0x7075, - kWzAES = 0x9901 - }; - } - - 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 +// ZipHeader.h + +#ifndef __ARCHIVE_ZIP_HEADER_H +#define __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, + + 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, + kStrongEncrypt = 0x17, + kUnixTime = 0x5455, + kUnixExtra = 0x5855, + kIzUnicodeComment = 0x6375, + kIzUnicodeName = 0x7075, + kWzAES = 0x9901 + }; + } + + 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 index 047d3d2e8..509753c23 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -1,3231 +1,3231 @@ -// Archive/ZipIn.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../Common/DynamicBuffer.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/MyException.h" -#include "../../../Common/StringToInt.h" - -#include "../../../Windows/PropVariant.h" - -#include "../../Common/StreamUtils.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 { - -// (kBufferSize >= kDataDescriptorSize64 + 4) - -static const size_t kSeqBufferSize = (size_t)1 << 14; - -/* - 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; - - 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(offset, STREAM_SEEK_SET, &_streamPos); -} - -HRESULT CInArchive::SeekToVol(int volIndex, UInt64 offset) -{ - if (volIndex != Vols.StreamIndex) - { - InitBuf(); - if (IsMultiVol && volIndex >= 0) - { - if ((unsigned)volIndex >= Vols.Streams.Size()) - return S_FALSE; - if (!Vols.Streams[volIndex].Stream) - return S_FALSE; - Stream = Vols.Streams[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); -} - - -// ---------- 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 - { - UInt32 cur = 0; - result = Stream->Read(data, size, &cur); - data += cur; - size -= cur; - processed += 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[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; -} - - -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; - 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 WsAES 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; -} - - - -MY_NO_INLINE -static const Byte *FindPK(const Byte *p, const Byte *limit) -{ - for (;;) - { - for (;;) - { - Byte b0 = p[0]; - if (p >= limit) - return p; - p++; - if (b0 == 0x50) - break; - } - if (p[0] == 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]; - unsigned processed; - RINOK(ReadFromCache(startBuf, kMarkerSize, processed)); - if (processed != kMarkerSize) - return S_FALSE; - - UInt32 marker = Get32(startBuf); - _signature = marker; - - if ( marker == NSignature::kNoSpan - || marker == NSignature::kSpan) - { - RINOK(ReadFromCache(startBuf, kMarkerSize, processed)); - if (processed != kMarkerSize) - return S_FALSE; - _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; - } - - const size_t kCheckSize = (size_t)1 << 16; // must be smaller than kBufSize - const size_t kBufSize = (size_t)1 << 17; // must be larger than kCheckSize - - if (Buffer.Size() < kBufSize) - { - InitBuf(); - Buffer.AllocAtLeast(kBufSize); - if (!Buffer.IsAllocated()) - return E_OUTOFMEMORY; - } - - _inBufMode = true; - - UInt64 progressPrev = 0; - - for (;;) - { - RINOK(LookAhead(kBufSize)); - - const size_t avail = GetAvail(); - - size_t limitPos; - 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[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(p, limit); - if (p >= limit) - break; - const size_t rem = pStart + avail - p; - UInt32 res = IsArc_Zip_2(p, rem, isFinished); - if (res != k_IsArc_Res_NO) - { - if (rem < kMarkerSize) - return S_FALSE; - _signature = Get32(p); - SkipLookahed(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(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; - } - - if (!IsMultiVol) - { - _cnt += offset; - return Stream->Seek(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[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(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[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[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(unsigned extraSize, CExtraBlock &extra, - UInt64 &unpackSize, UInt64 &packSize, UInt64 &localOffset, UInt32 &disk) -{ - extra.Clear(); - - while (extraSize >= 4) - { - CExtraSubBlock subBlock; - const UInt32 pair = ReadUInt32(); - subBlock.ID = (pair & 0xFFFF); - unsigned size = (unsigned)(pair >> 16); - - 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 (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 (isOK && ZIP64_IS_32_MAX(localOffset)) - if (size < 8) isOK = false; else { size -= 8; localOffset = ReadUInt64(); } - - if (isOK && ZIP64_IS_16_MAX(disk)) - if (size < 4) isOK = false; else { size -= 4; disk = ReadUInt32(); } - - 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 (extraSize != 0) - { - ExtraMinorError = true; - extra.MinorError = true; - // 7-Zip before 9.31 created incorrect WsAES 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 = 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) - { - UInt64 localOffset = 0; - UInt32 disk = 0; - if (!ReadExtra(extraSize, item.LocalExtra, item.Size, item.PackSize, localOffset, disk)) - { - /* 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); -} - - -static bool FlagsAreSame(const CItem &i1, const CItem &i2) -{ - if (i1.Method != i2.Method) - return false; - if (i1.Flags == i2.Flags) - return true; - UInt32 mask = 0xFFFF; - 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 - if ((i1.Flags ^ i2.Flags) & NFileHeader::NFlags::kUtf8) - if (i1.Name.IsAscii() && i2.Name.IsAscii()) - mask &= ~NFileHeader::NFlags::kUtf8; - - return ((i1.Flags & mask) == (i2.Flags & mask)); -} - - -// #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(cdItem, localItem)) - 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::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail, bool &headersError) -{ - InitBuf(); - _inBufMode = false; - - 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 = 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 += ArcInfo.Base; - if (ArcInfo.Base < 0 && (Int64)offset < 0) - { - isAvail = false; - return S_FALSE; - } - } - - RINOK(Seek_SavePos(offset)); - - /* - // we can check buf mode - InitBuf(); - _inBufMode = true; - Buffer.AllocAtLeast(1 << 10); - */ - - 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; - } - 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; - 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(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 + (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 = (p - pStart) + descriptorSize4 - kNextSignatureSize; - - SkipLookahed(skip); - - return S_OK; - } - - const size_t skip = (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::ReadLocalItemAfterCdItemFull(CItemEx &item) -{ - if (item.FromLocal) - return S_OK; - try - { - bool isAvail = true; - bool headersError = false; - RINOK(ReadLocalItemAfterCdItem(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(extraSize, item.CentralExtra, item.Size, item.PackSize, item.LocalHeaderPos, item.Disk); - - // May be these strings must be deleted - /* - if (item.IsDir()) - item.Size = 0; - */ - - ReadBuffer(item.Comment, commentSize); - return S_OK; -} - - -HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo) -{ - if (offset >= ((UInt64)1 << 63)) - return S_FALSE; - Byte buf[kEcd64_FullSize]; - - RINOK(SeekToVol(Vols.StreamIndex, offset)); - unsigned processed = 0; - ReadFromCache(buf, kEcd64_FullSize, processed); - - if (processed != kEcd64_FullSize) - return S_FALSE; - - 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; -} - - -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(Stream->Seek(0, STREAM_SEEK_END, &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); - - if (Buffer.Size() < kBufSizeMax) - { - // InitBuf(); - Buffer.AllocAtLeast(kBufSizeMax); - if (!Buffer.IsAllocated()) - return E_OUTOFMEMORY; - } - - 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); - if ((cdInfo.ThisDisk == locator.NumDisks - 1 || ZIP64_IS_16_MAX(cdInfo.ThisDisk)) - && locator.Ecd64Disk < locator.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 = 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 = 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 = absEcdPos - cdEnd; - } - return S_OK; - } - } -} - - -HRESULT CInArchive::TryReadCd(CObjectVector &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize) -{ - items.Clear(); - - // _startLocalFromCd_Disk = (UInt32)(Int32)-1; - // _startLocalFromCd_Offset = (UInt64)(Int64)-1; - - RINOK(SeekToVol(IsMultiVol ? 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; - } - */ - - 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; -} - - -HRESULT CInArchive::ReadCd(CObjectVector &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize) -{ - bool checkOffsetMode = true; - - if (IsMultiVol) - { - if (Vols.EndVolIndex == -1) - return S_FALSE; - Stream = Vols.Streams[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 : 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 = ArcInfo.MarkerPos; - } - - return res; -} - - -static int FindItem(const CObjectVector &items, const CItemEx &item) -{ - unsigned left = 0, right = items.Size(); - for (;;) - { - if (left >= right) - return -1; - unsigned index = (left + 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 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 &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 -= 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; - } - - int dotPos = name.ReverseFind_Dot(); - if (dotPos < 0) - return S_OK; - const UString ext = name.Ptr(dotPos + 1); - name.DeleteFrom(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 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 = 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 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 size; - UInt64 pos; - RINOK(stream->Seek(0, STREAM_SEEK_CUR, &pos)); - RINOK(stream->Seek(0, STREAM_SEEK_END, &size)); - RINOK(stream->Seek(pos, STREAM_SEEK_SET, NULL)); - - 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 = Vols.Streams.Size() - 1; - break; - } - } - - return S_OK; -} - - -HRESULT CInArchive::ReadVols() -{ - CMyComPtr 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 = 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 = ecd.CdDisk; - if (Vols.StartVolIndex < 0) - Vols.StartVolIndex = 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, 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[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, 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, 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[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; - } -} - -STDMETHODIMP 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 &items) -{ - if (Buffer.Size() < kSeqBufferSize) - { - InitBuf(); - Buffer.AllocAtLeast(kSeqBufferSize); - if (!Buffer.IsAllocated()) - return E_OUTOFMEMORY; - } - - _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 (!MarkerIsFound || !MarkerIsSafe) - { - IsArc = true; - res = ReadCd(items, cdDisk, cdRelatOffset, cdSize); - if (res == S_OK) - ReadSignature(); - else if (res != S_FALSE) - return res; - } - else - { - - // _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 = 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 = ArcInfo.MarkerPos2 - ArcInfo.Base; - int index = FindItem(items, firstItem); - if (index == -1) - res = S_FALSE; - else if (!AreItemsEqual(firstItem, items[index])) - res = S_FALSE; - else - { - ArcInfo.CdWasRead = true; - ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos; - - // ArcInfo.FirstItemRelatOffset = _startLocalFromCd_Offset; - } - } - } - } - } - - - - CObjectVector 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 - - _inBufMode = false; - // _inBufMode = true; - - InitBuf(); - - ArcInfo.Base = 0; - - 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 = 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; - NoCentralDir = true; - HeadersError = true; - return S_OK; - } - - _inBufMode = true; - - cdAbsOffset = GetVirtStreamPos() - 4; - cdDisk = 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 = 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); - } - - 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 != (int)cdInfo.CdDisk) - HeadersError = true; - } - else if (needSetBase && cdOK) - { - const UInt64 oldBase = ArcInfo.Base; - // localsWereRead == true - // ArcInfo.Base == ArcInfo.MarkerPos2 - // cdRelatOffset == (cdAbsOffset - ArcInfo.Base) - - if (isZip64) - { - if (ecd64Disk == Vols.StartVolIndex) - { - const Int64 newBase = (Int64)ecd64AbsOffset - locator.Ecd64Offset; - if (newBase <= (Int64)ecd64AbsOffset) - { - if (!localsWereRead || newBase <= (Int64)ArcInfo.MarkerPos2) - { - ArcInfo.Base = newBase; - cdRelatOffset = 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 - 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 = 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 != ArcInfo.Base + 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 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[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[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; - } - - 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 &items) -{ - items.Clear(); - - Close(); - - UInt64 startPos; - RINOK(stream->Seek(0, STREAM_SEEK_CUR, &startPos)); - RINOK(stream->Seek(0, STREAM_SEEK_END, &ArcInfo.FileEndPos)); - _streamPos = ArcInfo.FileEndPos; - - StartStream = stream; - Stream = stream; - Callback = callback; - - DisableBufMode(); - - bool volWasRequested = false; - - 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 (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[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 copuld be already tested with another call with (startPos == 0). - // so we don't want to try to open CD again in that ase. - 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[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[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 &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 += ArcInfo.Base; - RINOK(StreamRef->Seek(pos, STREAM_SEEK_SET, NULL)); - 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(str2->Seek(pos, STREAM_SEEK_SET, NULL)); - - Vols.NeedSeek = false; - Vols.StreamIndex = item.Disk; - - CVolStream *volsStreamSpec = new CVolStream; - volsStreamSpec->Vols = &Vols; - stream = volsStreamSpec; - - return S_OK; -} - -}} +// Archive/ZipIn.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../Common/DynamicBuffer.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/MyException.h" +#include "../../../Common/StringToInt.h" + +#include "../../../Windows/PropVariant.h" + +#include "../../Common/StreamUtils.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 { + +// (kBufferSize >= kDataDescriptorSize64 + 4) + +static const size_t kSeqBufferSize = (size_t)1 << 14; + +/* + 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; + + 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(offset, STREAM_SEEK_SET, &_streamPos); +} + +HRESULT CInArchive::SeekToVol(int volIndex, UInt64 offset) +{ + if (volIndex != Vols.StreamIndex) + { + InitBuf(); + if (IsMultiVol && volIndex >= 0) + { + if ((unsigned)volIndex >= Vols.Streams.Size()) + return S_FALSE; + if (!Vols.Streams[volIndex].Stream) + return S_FALSE; + Stream = Vols.Streams[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); +} + + +// ---------- 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 + { + UInt32 cur = 0; + result = Stream->Read(data, size, &cur); + data += cur; + size -= cur; + processed += 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[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; +} + + +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; + 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 WsAES 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; +} + + + +MY_NO_INLINE +static const Byte *FindPK(const Byte *p, const Byte *limit) +{ + for (;;) + { + for (;;) + { + Byte b0 = p[0]; + if (p >= limit) + return p; + p++; + if (b0 == 0x50) + break; + } + if (p[0] == 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]; + unsigned processed; + RINOK(ReadFromCache(startBuf, kMarkerSize, processed)); + if (processed != kMarkerSize) + return S_FALSE; + + UInt32 marker = Get32(startBuf); + _signature = marker; + + if ( marker == NSignature::kNoSpan + || marker == NSignature::kSpan) + { + RINOK(ReadFromCache(startBuf, kMarkerSize, processed)); + if (processed != kMarkerSize) + return S_FALSE; + _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; + } + + const size_t kCheckSize = (size_t)1 << 16; // must be smaller than kBufSize + const size_t kBufSize = (size_t)1 << 17; // must be larger than kCheckSize + + if (Buffer.Size() < kBufSize) + { + InitBuf(); + Buffer.AllocAtLeast(kBufSize); + if (!Buffer.IsAllocated()) + return E_OUTOFMEMORY; + } + + _inBufMode = true; + + UInt64 progressPrev = 0; + + for (;;) + { + RINOK(LookAhead(kBufSize)); + + const size_t avail = GetAvail(); + + size_t limitPos; + 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[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(p, limit); + if (p >= limit) + break; + const size_t rem = pStart + avail - p; + UInt32 res = IsArc_Zip_2(p, rem, isFinished); + if (res != k_IsArc_Res_NO) + { + if (rem < kMarkerSize) + return S_FALSE; + _signature = Get32(p); + SkipLookahed(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(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; + } + + if (!IsMultiVol) + { + _cnt += offset; + return Stream->Seek(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[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(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[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[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(unsigned extraSize, CExtraBlock &extra, + UInt64 &unpackSize, UInt64 &packSize, UInt64 &localOffset, UInt32 &disk) +{ + extra.Clear(); + + while (extraSize >= 4) + { + CExtraSubBlock subBlock; + const UInt32 pair = ReadUInt32(); + subBlock.ID = (pair & 0xFFFF); + unsigned size = (unsigned)(pair >> 16); + + 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 (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 (isOK && ZIP64_IS_32_MAX(localOffset)) + if (size < 8) isOK = false; else { size -= 8; localOffset = ReadUInt64(); } + + if (isOK && ZIP64_IS_16_MAX(disk)) + if (size < 4) isOK = false; else { size -= 4; disk = ReadUInt32(); } + + 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 (extraSize != 0) + { + ExtraMinorError = true; + extra.MinorError = true; + // 7-Zip before 9.31 created incorrect WsAES 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 = 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) + { + UInt64 localOffset = 0; + UInt32 disk = 0; + if (!ReadExtra(extraSize, item.LocalExtra, item.Size, item.PackSize, localOffset, disk)) + { + /* 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); +} + + +static bool FlagsAreSame(const CItem &i1, const CItem &i2) +{ + if (i1.Method != i2.Method) + return false; + if (i1.Flags == i2.Flags) + return true; + UInt32 mask = 0xFFFF; + 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 + if ((i1.Flags ^ i2.Flags) & NFileHeader::NFlags::kUtf8) + if (i1.Name.IsAscii() && i2.Name.IsAscii()) + mask &= ~NFileHeader::NFlags::kUtf8; + + return ((i1.Flags & mask) == (i2.Flags & mask)); +} + + +// #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(cdItem, localItem)) + 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::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail, bool &headersError) +{ + InitBuf(); + _inBufMode = false; + + 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 = 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 += ArcInfo.Base; + if (ArcInfo.Base < 0 && (Int64)offset < 0) + { + isAvail = false; + return S_FALSE; + } + } + + RINOK(Seek_SavePos(offset)); + + /* + // we can check buf mode + InitBuf(); + _inBufMode = true; + Buffer.AllocAtLeast(1 << 10); + */ + + 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; + } + 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; + 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(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 + (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 = (p - pStart) + descriptorSize4 - kNextSignatureSize; + + SkipLookahed(skip); + + return S_OK; + } + + const size_t skip = (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::ReadLocalItemAfterCdItemFull(CItemEx &item) +{ + if (item.FromLocal) + return S_OK; + try + { + bool isAvail = true; + bool headersError = false; + RINOK(ReadLocalItemAfterCdItem(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(extraSize, item.CentralExtra, item.Size, item.PackSize, item.LocalHeaderPos, item.Disk); + + // May be these strings must be deleted + /* + if (item.IsDir()) + item.Size = 0; + */ + + ReadBuffer(item.Comment, commentSize); + return S_OK; +} + + +HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo) +{ + if (offset >= ((UInt64)1 << 63)) + return S_FALSE; + Byte buf[kEcd64_FullSize]; + + RINOK(SeekToVol(Vols.StreamIndex, offset)); + unsigned processed = 0; + ReadFromCache(buf, kEcd64_FullSize, processed); + + if (processed != kEcd64_FullSize) + return S_FALSE; + + 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; +} + + +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(Stream->Seek(0, STREAM_SEEK_END, &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); + + if (Buffer.Size() < kBufSizeMax) + { + // InitBuf(); + Buffer.AllocAtLeast(kBufSizeMax); + if (!Buffer.IsAllocated()) + return E_OUTOFMEMORY; + } + + 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); + if ((cdInfo.ThisDisk == locator.NumDisks - 1 || ZIP64_IS_16_MAX(cdInfo.ThisDisk)) + && locator.Ecd64Disk < locator.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 = 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 = 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 = absEcdPos - cdEnd; + } + return S_OK; + } + } +} + + +HRESULT CInArchive::TryReadCd(CObjectVector &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize) +{ + items.Clear(); + + // _startLocalFromCd_Disk = (UInt32)(Int32)-1; + // _startLocalFromCd_Offset = (UInt64)(Int64)-1; + + RINOK(SeekToVol(IsMultiVol ? 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; + } + */ + + 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; +} + + +HRESULT CInArchive::ReadCd(CObjectVector &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize) +{ + bool checkOffsetMode = true; + + if (IsMultiVol) + { + if (Vols.EndVolIndex == -1) + return S_FALSE; + Stream = Vols.Streams[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 : 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 = ArcInfo.MarkerPos; + } + + return res; +} + + +static int FindItem(const CObjectVector &items, const CItemEx &item) +{ + unsigned left = 0, right = items.Size(); + for (;;) + { + if (left >= right) + return -1; + unsigned index = (left + 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 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 &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 -= 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; + } + + int dotPos = name.ReverseFind_Dot(); + if (dotPos < 0) + return S_OK; + const UString ext = name.Ptr(dotPos + 1); + name.DeleteFrom(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 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 = 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 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 size; + UInt64 pos; + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &pos)); + RINOK(stream->Seek(0, STREAM_SEEK_END, &size)); + RINOK(stream->Seek(pos, STREAM_SEEK_SET, NULL)); + + 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 = Vols.Streams.Size() - 1; + break; + } + } + + return S_OK; +} + + +HRESULT CInArchive::ReadVols() +{ + CMyComPtr 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 = 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 = ecd.CdDisk; + if (Vols.StartVolIndex < 0) + Vols.StartVolIndex = 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, 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[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, 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, 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[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; + } +} + +STDMETHODIMP 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 &items) +{ + if (Buffer.Size() < kSeqBufferSize) + { + InitBuf(); + Buffer.AllocAtLeast(kSeqBufferSize); + if (!Buffer.IsAllocated()) + return E_OUTOFMEMORY; + } + + _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 (!MarkerIsFound || !MarkerIsSafe) + { + IsArc = true; + res = ReadCd(items, cdDisk, cdRelatOffset, cdSize); + if (res == S_OK) + ReadSignature(); + else if (res != S_FALSE) + return res; + } + else + { + + // _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 = 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 = ArcInfo.MarkerPos2 - ArcInfo.Base; + int index = FindItem(items, firstItem); + if (index == -1) + res = S_FALSE; + else if (!AreItemsEqual(firstItem, items[index])) + res = S_FALSE; + else + { + ArcInfo.CdWasRead = true; + ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos; + + // ArcInfo.FirstItemRelatOffset = _startLocalFromCd_Offset; + } + } + } + } + } + + + + CObjectVector 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 + + _inBufMode = false; + // _inBufMode = true; + + InitBuf(); + + ArcInfo.Base = 0; + + 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 = 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; + NoCentralDir = true; + HeadersError = true; + return S_OK; + } + + _inBufMode = true; + + cdAbsOffset = GetVirtStreamPos() - 4; + cdDisk = 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 = 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); + } + + 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 != (int)cdInfo.CdDisk) + HeadersError = true; + } + else if (needSetBase && cdOK) + { + const UInt64 oldBase = ArcInfo.Base; + // localsWereRead == true + // ArcInfo.Base == ArcInfo.MarkerPos2 + // cdRelatOffset == (cdAbsOffset - ArcInfo.Base) + + if (isZip64) + { + if (ecd64Disk == Vols.StartVolIndex) + { + const Int64 newBase = (Int64)ecd64AbsOffset - locator.Ecd64Offset; + if (newBase <= (Int64)ecd64AbsOffset) + { + if (!localsWereRead || newBase <= (Int64)ArcInfo.MarkerPos2) + { + ArcInfo.Base = newBase; + cdRelatOffset = 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 - 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 = 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 != ArcInfo.Base + 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 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[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[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; + } + + 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 &items) +{ + items.Clear(); + + Close(); + + UInt64 startPos; + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &startPos)); + RINOK(stream->Seek(0, STREAM_SEEK_END, &ArcInfo.FileEndPos)); + _streamPos = ArcInfo.FileEndPos; + + StartStream = stream; + Stream = stream; + Callback = callback; + + DisableBufMode(); + + bool volWasRequested = false; + + 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 (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[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 copuld be already tested with another call with (startPos == 0). + // so we don't want to try to open CD again in that ase. + 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[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[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 &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 += ArcInfo.Base; + RINOK(StreamRef->Seek(pos, STREAM_SEEK_SET, NULL)); + 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(str2->Seek(pos, STREAM_SEEK_SET, NULL)); + + Vols.NeedSeek = false; + Vols.StreamIndex = 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 index 61f680d86..f46f1f07a 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.h +++ b/CPP/7zip/Archive/Zip/ZipIn.h @@ -1,427 +1,427 @@ -// Archive/ZipIn.h - -#ifndef __ZIP_IN_H -#define __ZIP_IN_H - -#include "../../../Common/MyBuffer2.h" -#include "../../../Common/MyCom.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; } -}; - - -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 Stream; - UInt64 Size; - - HRESULT SeekToStart() const { return Stream->Seek(0, STREAM_SEEK_SET, NULL); } - - CSubStreamInfo(): Size(0) {} - }; - - CObjectVector 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 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); -}; - - -class CVolStream: - public ISequentialInStream, - public CMyUnknownImp -{ -public: - CVols *Vols; - - MY_UNKNOWN_IMP1(ISequentialInStream) - - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); -}; - - -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; - } - - UInt64 GetVirtStreamPos() { return _streamPos - _bufCached + _bufPos; } - - bool _inBufMode; - - bool IsArcOpen; - bool CanStartNewVol; - - UInt32 _signature; - - CMyComPtr 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 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(unsigned extraSize, CExtraBlock &extra, - UInt64 &unpackSize, UInt64 &packSize, UInt64 &localOffset, UInt32 &disk); - 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 &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize); - HRESULT ReadCd(CObjectVector &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize); - HRESULT ReadLocals(CObjectVector &localItems); - - HRESULT ReadHeaders(CObjectVector &items); - - HRESULT GetVolStream(unsigned vol, UInt64 pos, CMyComPtr &stream); - -public: - CInArchiveInfo ArcInfo; - - bool IsArc; - bool IsZip64; - - 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; - - CInArchive(): Stream(NULL), StartStream(NULL), Callback(NULL), IsArcOpen(false) {} - - UInt64 GetPhySize() const - { - if (IsMultiVol) - return ArcInfo.FinishPos; - else - return ArcInfo.FinishPos - ArcInfo.Base; - } - - UInt64 GetOffset() const - { - if (IsMultiVol) - return 0; - else - return ArcInfo.Base; - } - - - void ClearRefs(); - void Close(); - HRESULT Open(IInStream *stream, const UInt64 *searchLimit, IArchiveOpenCallback *callback, CObjectVector &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 ArcInfo.MarkerPos2 - ArcInfo.Base; - } - - - HRESULT CheckDescriptor(const CItemEx &item); - HRESULT ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail, bool &headersError); - HRESULT ReadLocalItemAfterCdItemFull(CItemEx &item); - - HRESULT GetItemStream(const CItemEx &item, bool seekPackData, CMyComPtr &stream); - - IInStream *GetBaseStream() { return StreamRef; } - - bool CanUpdate() const - { - if (AreThereErrors() - || IsMultiVol - || ArcInfo.Base < 0 - || (Int64)ArcInfo.MarkerPos2 < ArcInfo.Base - || ArcInfo.ThereIsTail - || GetEmbeddedStubSize() != 0) - return false; - - // 7-zip probably can update archives with embedded stubs. - // we just disable that feature for more safety. - - return true; - } -}; - -}} - -#endif +// Archive/ZipIn.h + +#ifndef __ZIP_IN_H +#define __ZIP_IN_H + +#include "../../../Common/MyBuffer2.h" +#include "../../../Common/MyCom.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; } +}; + + +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 Stream; + UInt64 Size; + + HRESULT SeekToStart() const { return Stream->Seek(0, STREAM_SEEK_SET, NULL); } + + CSubStreamInfo(): Size(0) {} + }; + + CObjectVector 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 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); +}; + + +class CVolStream: + public ISequentialInStream, + public CMyUnknownImp +{ +public: + CVols *Vols; + + MY_UNKNOWN_IMP1(ISequentialInStream) + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + + +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; + } + + UInt64 GetVirtStreamPos() { return _streamPos - _bufCached + _bufPos; } + + bool _inBufMode; + + bool IsArcOpen; + bool CanStartNewVol; + + UInt32 _signature; + + CMyComPtr 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 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(unsigned extraSize, CExtraBlock &extra, + UInt64 &unpackSize, UInt64 &packSize, UInt64 &localOffset, UInt32 &disk); + 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 &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize); + HRESULT ReadCd(CObjectVector &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize); + HRESULT ReadLocals(CObjectVector &localItems); + + HRESULT ReadHeaders(CObjectVector &items); + + HRESULT GetVolStream(unsigned vol, UInt64 pos, CMyComPtr &stream); + +public: + CInArchiveInfo ArcInfo; + + bool IsArc; + bool IsZip64; + + 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; + + CInArchive(): Stream(NULL), StartStream(NULL), Callback(NULL), IsArcOpen(false) {} + + UInt64 GetPhySize() const + { + if (IsMultiVol) + return ArcInfo.FinishPos; + else + return ArcInfo.FinishPos - ArcInfo.Base; + } + + UInt64 GetOffset() const + { + if (IsMultiVol) + return 0; + else + return ArcInfo.Base; + } + + + void ClearRefs(); + void Close(); + HRESULT Open(IInStream *stream, const UInt64 *searchLimit, IArchiveOpenCallback *callback, CObjectVector &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 ArcInfo.MarkerPos2 - ArcInfo.Base; + } + + + HRESULT CheckDescriptor(const CItemEx &item); + HRESULT ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail, bool &headersError); + HRESULT ReadLocalItemAfterCdItemFull(CItemEx &item); + + HRESULT GetItemStream(const CItemEx &item, bool seekPackData, CMyComPtr &stream); + + IInStream *GetBaseStream() { return StreamRef; } + + bool CanUpdate() const + { + if (AreThereErrors() + || IsMultiVol + || ArcInfo.Base < 0 + || (Int64)ArcInfo.MarkerPos2 < ArcInfo.Base + || ArcInfo.ThereIsTail + || GetEmbeddedStubSize() != 0) + 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 index 888f940e8..5cff1735c 100644 --- a/CPP/7zip/Archive/Zip/ZipItem.cpp +++ b/CPP/7zip/Archive/Zip/ZipItem.cpp @@ -1,367 +1,367 @@ -// 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::kStrongEncrypt, "StrongCrypto" }, - { NExtraID::kUnixTime, "UT" }, - { NExtraID::kUnixExtra, "UX" }, - { NExtraID::kIzUnicodeComment, "uc" }, - { NExtraID::kIzUnicodeName, "up" }, - { NExtraID::kWzAES, "WzAES" } -}; - -void CExtraSubBlock::PrintInfo(AString &s) const -{ - for (unsigned i = 0; i < ARRAY_SIZE(g_ExtraTypes); i++) - { - const CUInt32PCharPair &pair = g_ExtraTypes[i]; - if (pair.Value == ID) - { - s += pair.Name; - 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::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const -{ - res = 0; - UInt32 size = (UInt32)Data.Size(); - if (ID != NExtraID::kUnixTime || size < 5) - return false; - const Byte *p = (const Byte *)Data; - 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; -} - - -bool CExtraSubBlock::ExtractUnixExtraTime(unsigned index, UInt32 &res) const -{ - res = 0; - const size_t size = Data.Size(); - unsigned offset = index * 4; - if (ID != NExtraID::kUnixExtra || size < offset + 4) - 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.ExtractUnixTime(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::kUnixExtra) - return sb.ExtractUnixExtraTime(index, res); - } - } - return false; -} - - -bool CLocalItem::IsDir() const -{ - return NItemName::HasTailSlash(Name, GetCodePage()); -} - -bool CItem::IsDir() const -{ - 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; -} - -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 &subBlocks = GetMainExtra().SubBlocks; - - FOR_VECTOR (i, subBlocks) - { - const CExtraSubBlock &sb = subBlocks[i]; - if (sb.ID == id) - { - AString utf; - if (sb.ExtractIzUnicode(CrcCalc(s, s.Len()), utf)) - if (ConvertUTF8ToUnicode(utf, 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; - ignore_Utf8_Errors = false; - } - #endif - } - - - if (isUtf8) - if (ConvertUTF8ToUnicode(s, res) || ignore_Utf8_Errors) - return; - - MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage()); -} - -}} +// 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::kStrongEncrypt, "StrongCrypto" }, + { NExtraID::kUnixTime, "UT" }, + { NExtraID::kUnixExtra, "UX" }, + { NExtraID::kIzUnicodeComment, "uc" }, + { NExtraID::kIzUnicodeName, "up" }, + { NExtraID::kWzAES, "WzAES" } +}; + +void CExtraSubBlock::PrintInfo(AString &s) const +{ + for (unsigned i = 0; i < ARRAY_SIZE(g_ExtraTypes); i++) + { + const CUInt32PCharPair &pair = g_ExtraTypes[i]; + if (pair.Value == ID) + { + s += pair.Name; + 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::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const +{ + res = 0; + UInt32 size = (UInt32)Data.Size(); + if (ID != NExtraID::kUnixTime || size < 5) + return false; + const Byte *p = (const Byte *)Data; + 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; +} + + +bool CExtraSubBlock::ExtractUnixExtraTime(unsigned index, UInt32 &res) const +{ + res = 0; + const size_t size = Data.Size(); + unsigned offset = index * 4; + if (ID != NExtraID::kUnixExtra || size < offset + 4) + 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.ExtractUnixTime(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::kUnixExtra) + return sb.ExtractUnixExtraTime(index, res); + } + } + return false; +} + + +bool CLocalItem::IsDir() const +{ + return NItemName::HasTailSlash(Name, GetCodePage()); +} + +bool CItem::IsDir() const +{ + 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; +} + +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 &subBlocks = GetMainExtra().SubBlocks; + + FOR_VECTOR (i, subBlocks) + { + const CExtraSubBlock &sb = subBlocks[i]; + if (sb.ID == id) + { + AString utf; + if (sb.ExtractIzUnicode(CrcCalc(s, s.Len()), utf)) + if (ConvertUTF8ToUnicode(utf, 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; + ignore_Utf8_Errors = false; + } + #endif + } + + + if (isUtf8) + if (ConvertUTF8ToUnicode(s, res) || ignore_Utf8_Errors) + return; + + MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage()); +} + +}} diff --git a/CPP/7zip/Archive/Zip/ZipItem.h b/CPP/7zip/Archive/Zip/ZipItem.h index e9c6392aa..e5769711d 100644 --- a/CPP/7zip/Archive/Zip/ZipItem.h +++ b/CPP/7zip/Archive/Zip/ZipItem.h @@ -1,350 +1,350 @@ -// Archive/ZipItem.h - -#ifndef __ARCHIVE_ZIP_ITEM_H -#define __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 ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const; - bool ExtractUnixExtraTime(unsigned index, UInt32 &res) const; - - bool ExtractIzUnicode(UInt32 crc, AString &name) const - { - unsigned size = (unsigned)Data.Size(); - if (size < 1 + 4) - return false; - const Byte *p = (const Byte *)Data; - if (p[0] > 1) - return false; - if (crc != GetUi32(p + 1)) - return false; - size -= 5; - name.SetFrom_CalcLen((const char *)p + 5, size); - if (size != name.Len()) - return false; - return CheckUTF8(name, false); - } - - 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 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--; - if (SubBlocks[i].ID != NFileHeader::NExtraID::kWzAES) - 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 |= bitMask; - else - 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 { 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()); - } - - UINT GetCodePage() const - { - // 18.06: now we use HostOS only from Central::MadeByVersion - 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 +// Archive/ZipItem.h + +#ifndef __ARCHIVE_ZIP_ITEM_H +#define __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 ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const; + bool ExtractUnixExtraTime(unsigned index, UInt32 &res) const; + + bool ExtractIzUnicode(UInt32 crc, AString &name) const + { + unsigned size = (unsigned)Data.Size(); + if (size < 1 + 4) + return false; + const Byte *p = (const Byte *)Data; + if (p[0] > 1) + return false; + if (crc != GetUi32(p + 1)) + return false; + size -= 5; + name.SetFrom_CalcLen((const char *)p + 5, size); + if (size != name.Len()) + return false; + return CheckUTF8(name, false); + } + + 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 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--; + if (SubBlocks[i].ID != NFileHeader::NExtraID::kWzAES) + 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 |= bitMask; + else + 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 { 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()); + } + + UINT GetCodePage() const + { + // 18.06: now we use HostOS only from Central::MadeByVersion + 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 index f0573576a..945bd020f 100644 --- a/CPP/7zip/Archive/Zip/ZipOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipOut.cpp @@ -1,348 +1,348 @@ -// ZipOut.cpp - -#include "StdAfx.h" - -#include "../../Common/OffsetStream.h" - -#include "ZipOut.h" - -namespace NArchive { -namespace NZip { - -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(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::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; - - const UInt32 localExtraSize = (UInt32)((isZip64 ? (4 + 8 + 8): 0) + 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); - } - - WriteExtra(item.LocalExtra); - - // Why don't we write NTFS timestamps to local header? - // Probably we want to reduce size of archive? - - 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) -{ - bool isUnPack64 = DOES_NEED_ZIP64(item.Size); - bool isPack64 = DOES_NEED_ZIP64(item.PackSize); - bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos); - 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()); - - UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0)); - const UInt16 kNtfsExtraSize = 4 + 2 + 2 + (3 * 8); - const UInt16 centralExtraSize = (UInt16)( - (isZip64 ? 4 + zip64ExtraSize : 0) + - (item.NtfsTimeIsDefined ? 4 + kNtfsExtraSize : 0) + - item.CentralExtra.GetSize()); - - Write16(centralExtraSize); // test it; - - 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); - } - - if (item.NtfsTimeIsDefined) - { - Write16(NFileHeader::NExtraID::kNTFS); - Write16(kNtfsExtraSize); - Write32(0); // reserved - Write16(NFileHeader::NNtfsExtra::kTagTime); - Write16(8 * 3); - WriteNtfsTime(item.Ntfs_MTime); - WriteNtfsTime(item.Ntfs_ATime); - WriteNtfsTime(item.Ntfs_CTime); - } - - WriteExtra(item.CentralExtra); - if (commentSize != 0) - WriteBytes(item.Comment, commentSize); -} - -void COutArchive::WriteCentralDir(const CObjectVector &items, const CByteBuffer *comment) -{ - UInt64 cdOffset = GetCurPos(); - FOR_VECTOR (i, items) - WriteCentralHeader(items[i]); - UInt64 cd64EndOffset = GetCurPos(); - UInt64 cdSize = cd64EndOffset - cdOffset; - bool cdOffset64 = DOES_NEED_ZIP64(cdOffset); - bool cdSize64 = DOES_NEED_ZIP64(cdSize); - bool items64 = items.Size() >= 0xFFFF; - 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 = 0; - 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 = 0; - 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(); -} - -void COutArchive::CreateStreamForCompressing(CMyComPtr &outStream) -{ - COffsetOutStream *streamSpec = new COffsetOutStream; - outStream = streamSpec; - streamSpec->Init(m_Stream, m_Base + m_CurPos); -} - -void COutArchive::CreateStreamForCopying(CMyComPtr &outStream) -{ - outStream = m_Stream; -} - -}} +// ZipOut.cpp + +#include "StdAfx.h" + +#include "../../Common/OffsetStream.h" + +#include "ZipOut.h" + +namespace NArchive { +namespace NZip { + +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(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::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; + + const UInt32 localExtraSize = (UInt32)((isZip64 ? (4 + 8 + 8): 0) + 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); + } + + WriteExtra(item.LocalExtra); + + // Why don't we write NTFS timestamps to local header? + // Probably we want to reduce size of archive? + + 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) +{ + bool isUnPack64 = DOES_NEED_ZIP64(item.Size); + bool isPack64 = DOES_NEED_ZIP64(item.PackSize); + bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos); + 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()); + + UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0)); + const UInt16 kNtfsExtraSize = 4 + 2 + 2 + (3 * 8); + const UInt16 centralExtraSize = (UInt16)( + (isZip64 ? 4 + zip64ExtraSize : 0) + + (item.NtfsTimeIsDefined ? 4 + kNtfsExtraSize : 0) + + item.CentralExtra.GetSize()); + + Write16(centralExtraSize); // test it; + + 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); + } + + if (item.NtfsTimeIsDefined) + { + Write16(NFileHeader::NExtraID::kNTFS); + Write16(kNtfsExtraSize); + Write32(0); // reserved + Write16(NFileHeader::NNtfsExtra::kTagTime); + Write16(8 * 3); + WriteNtfsTime(item.Ntfs_MTime); + WriteNtfsTime(item.Ntfs_ATime); + WriteNtfsTime(item.Ntfs_CTime); + } + + WriteExtra(item.CentralExtra); + if (commentSize != 0) + WriteBytes(item.Comment, commentSize); +} + +void COutArchive::WriteCentralDir(const CObjectVector &items, const CByteBuffer *comment) +{ + UInt64 cdOffset = GetCurPos(); + FOR_VECTOR (i, items) + WriteCentralHeader(items[i]); + UInt64 cd64EndOffset = GetCurPos(); + UInt64 cdSize = cd64EndOffset - cdOffset; + bool cdOffset64 = DOES_NEED_ZIP64(cdOffset); + bool cdSize64 = DOES_NEED_ZIP64(cdSize); + bool items64 = items.Size() >= 0xFFFF; + 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 = 0; + 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 = 0; + 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(); +} + +void COutArchive::CreateStreamForCompressing(CMyComPtr &outStream) +{ + COffsetOutStream *streamSpec = new COffsetOutStream; + outStream = streamSpec; + streamSpec->Init(m_Stream, m_Base + m_CurPos); +} + +void COutArchive::CreateStreamForCopying(CMyComPtr &outStream) +{ + outStream = m_Stream; +} + +}} diff --git a/CPP/7zip/Archive/Zip/ZipOut.h b/CPP/7zip/Archive/Zip/ZipOut.h index b9c77a8d1..0a0ac0c8f 100644 --- a/CPP/7zip/Archive/Zip/ZipOut.h +++ b/CPP/7zip/Archive/Zip/ZipOut.h @@ -1,83 +1,83 @@ -// ZipOut.h - -#ifndef __ZIP_OUT_H -#define __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 NtfsTimeIsDefined; - - // It's possible that NtfsTime is not defined, but there is NtfsTime in Extra. - - CItemOut(): NtfsTimeIsDefined(false) {} -}; - - -// COutArchive can throw CSystemException and COutBufferException - -class COutArchive -{ - COutBuffer m_OutBuffer; - CMyComPtr 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 WriteExtra(const CExtraBlock &extra); - void WriteCommonItemInfo(const CLocalItem &item, bool isZip64); - void WriteCentralHeader(const CItemOut &item); - - void SeekToCurPos(); -public: - 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); - - void WriteCentralDir(const CObjectVector &items, const CByteBuffer *comment); - - void CreateStreamForCompressing(CMyComPtr &outStream); - void CreateStreamForCopying(CMyComPtr &outStream); -}; - -}} - -#endif +// ZipOut.h + +#ifndef __ZIP_OUT_H +#define __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 NtfsTimeIsDefined; + + // It's possible that NtfsTime is not defined, but there is NtfsTime in Extra. + + CItemOut(): NtfsTimeIsDefined(false) {} +}; + + +// COutArchive can throw CSystemException and COutBufferException + +class COutArchive +{ + COutBuffer m_OutBuffer; + CMyComPtr 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 WriteExtra(const CExtraBlock &extra); + void WriteCommonItemInfo(const CLocalItem &item, bool isZip64); + void WriteCentralHeader(const CItemOut &item); + + void SeekToCurPos(); +public: + 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); + + void WriteCentralDir(const CObjectVector &items, const CByteBuffer *comment); + + void CreateStreamForCompressing(CMyComPtr &outStream); + void CreateStreamForCopying(CMyComPtr &outStream); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Zip/ZipRegister.cpp b/CPP/7zip/Archive/Zip/ZipRegister.cpp index 125b0a0b5..e6929f1b0 100644 --- a/CPP/7zip/Archive/Zip/ZipRegister.cpp +++ b/CPP/7zip/Archive/Zip/ZipRegister.cpp @@ -1,28 +1,28 @@ -// 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", 0, 1, - k_Signature, - 0, - NArcInfoFlags::kFindSignature | - NArcInfoFlags::kMultiSignature | - NArcInfoFlags::kUseGlobalOffset, - IsArc_Zip) - -}} +// 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", 0, 1, + k_Signature, + 0, + NArcInfoFlags::kFindSignature | + NArcInfoFlags::kMultiSignature | + NArcInfoFlags::kUseGlobalOffset, + IsArc_Zip) + +}} diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index 5b7d5928e..e65c2b8bf 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -1,1430 +1,1430 @@ -// ZipUpdate.cpp - -#include "StdAfx.h" - -#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 _7ZIP_ST -#include "../../Common/ProgressMt.h" -#endif -#include "../../Common/StreamUtils.h" - -#include "../../Compress/CopyCoder.h" - -#include "ZipAddCommon.h" -#include "ZipOut.h" -#include "ZipUpdate.h" - -using namespace NWindows; -using namespace NSynchronization; - -namespace NArchive { -namespace NZip { - -static const Byte kHostOS = - #ifdef _WIN32 - NFileHeader::NHostOS::kFAT; - #else - NFileHeader::NHostOS::kUnix; - #endif - -static const Byte kMadeByHostOS = kHostOS; - -// 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 SetFileHeader( - const CCompressionMethodMode &options, - const CUpdateItem &ui, - bool useDescriptor, - CItemOut &item) -{ - item.Size = ui.Size; - bool isDir = ui.IsDir; - - item.ClearFlags(); - - if (ui.NewProps) - { - item.Name = ui.Name; - 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.NtfsTimeIsDefined = ui.NtfsTimeIsDefined; - } - /* - 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.PasswordIsDefined); - 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 _7ZIP_ST - -static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo); - -struct CThreadInfo -{ - DECL_EXTERNAL_CODECS_LOC_VARS2; - - NWindows::CThread Thread; - NWindows::NSynchronization::CAutoResetEvent CompressEvent; - NWindows::NSynchronization::CAutoResetEvent CompressionCompletedEvent; - bool ExitThread; - - CMtCompressProgress *ProgressSpec; - CMyComPtr Progress; - - COutMemStream *OutStreamSpec; - CMyComPtr OutStream; - CMyComPtr InStream; - - CAddCommon Coder; - HRESULT Result; - CCompressingResult CompressingResult; - - bool InSeqMode; - bool OutSeqMode; - bool IsFree; - UInt32 UpdateIndex; - UInt32 FileTime; - UInt64 ExpectedDataSize; - - CThreadInfo(const CCompressionMethodMode &options): - ExitThread(false), - ProgressSpec(0), - OutStreamSpec(0), - Coder(options), - InSeqMode(false), - OutSeqMode(false), - FileTime(0), - ExpectedDataSize((UInt64)(Int64)-1) - {} - - HRESULT CreateEvents() - { - RINOK(CompressEvent.CreateIfNotCreated()); - return CompressionCompletedEvent.CreateIfNotCreated(); - } - HRes CreateThread() { return Thread.Create(CoderThread, this); } - - void WaitAndCode(); - void StopWaitClose() - { - ExitThread = true; - if (OutStreamSpec != 0) - OutStreamSpec->StopWriting(E_ABORT); - if (CompressEvent.IsCreated()) - CompressEvent.Set(); - Thread.Wait(); - Thread.Close(); - } -}; - -void CThreadInfo::WaitAndCode() -{ - for (;;) - { - CompressEvent.Lock(); - if (ExitThread) - return; - - Result = Coder.Compress( - EXTERNAL_CODECS_LOC_VARS - InStream, OutStream, - InSeqMode, OutSeqMode, FileTime, ExpectedDataSize, - Progress, CompressingResult); - - if (Result == S_OK && Progress) - Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize); - CompressionCompletedEvent.Set(); - } -} - -static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo) -{ - ((CThreadInfo *)threadCoderInfo)->WaitAndCode(); - return 0; -} - -class CThreads -{ -public: - CObjectVector Threads; - ~CThreads() - { - FOR_VECTOR (i, Threads) - Threads[i].StopWaitClose(); - } -}; - -struct CMemBlocks2: public CMemLockBlocks -{ - bool Skip; - bool InSeqMode; - bool PreDescriptorMode; - bool Finished; - CCompressingResult CompressingResult; - - CMemBlocks2(): Skip(false), InSeqMode(false), PreDescriptorMode(false), Finished(false) {} -}; - -class CMemRefs -{ -public: - CMemBlockManagerMt *Manager; - CObjectVector Refs; - CMemRefs(CMemBlockManagerMt *manager): Manager(manager) {} ; - ~CMemRefs() - { - FOR_VECTOR (i, Refs) - Refs[i].FreeOpt(Manager); - } -}; - -class CMtProgressMixer2: - public ICompressProgressInfo, - public CMyUnknownImp -{ - UInt64 ProgressOffset; - UInt64 InSizes[2]; - UInt64 OutSizes[2]; - CMyComPtr Progress; - CMyComPtr RatioProgress; - bool _inSizeIsMain; -public: - NWindows::NSynchronization::CCriticalSection CriticalSection; - MY_UNKNOWN_IMP - 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); - STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); -}; - -void CMtProgressMixer2::Create(IProgress *progress, bool inSizeIsMain) -{ - Progress = progress; - Progress.QueryInterface(IID_ICompressProgressInfo, &RatioProgress); - _inSizeIsMain = inSizeIsMain; - ProgressOffset = InSizes[0] = InSizes[1] = OutSizes[0] = OutSizes[1] = 0; -} - -void CMtProgressMixer2::SetProgressOffset_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); -} - -STDMETHODIMP CMtProgressMixer2::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) -{ - return SetRatioInfo(0, inSize, outSize); -} - -class CMtProgressMixer: - public ICompressProgressInfo, - public CMyUnknownImp -{ -public: - CMtProgressMixer2 *Mixer2; - CMyComPtr RatioProgress; - void Create(IProgress *progress, bool inSizeIsMain); - MY_UNKNOWN_IMP - STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); -}; - -void CMtProgressMixer::Create(IProgress *progress, bool inSizeIsMain) -{ - Mixer2 = new CMtProgressMixer2; - RatioProgress = Mixer2; - Mixer2->Create(progress, inSizeIsMain); -} - -STDMETHODIMP CMtProgressMixer::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) -{ - return Mixer2->SetRatioInfo(1, inSize, outSize); -} - - -#endif - - -static HRESULT UpdateItemOldData( - COutArchive &archive, - 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; - - if (ui.NewProps) - { - if (item.HasDescriptor()) - return E_NOTIMPL; - - // use old name size. - - // 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 - item.Comment = ui.Comment; - item.Name = ui.Name; - item.SetUtf8(ui.IsUtf8); - // item.SetFlag_AltStream(ui.IsAltStream); - item.Time = ui.Time; - item.Ntfs_MTime = ui.Ntfs_MTime; - item.Ntfs_ATime = ui.Ntfs_ATime; - item.Ntfs_CTime = ui.Ntfs_CTime; - item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined; - - item.CentralExtra.RemoveUnknownSubBlocks(); - item.LocalExtra.RemoveUnknownSubBlocks(); - - archive.WriteLocalHeader(item); - rangeSize = item.GetPackSizeWithDescriptor(); - } - else - { - item.LocalHeaderPos = archive.GetCurPos(); - rangeSize = itemEx.GetLocalFullSize(); - } - - CMyComPtr packStream; - - RINOK(inArchive->GetItemStream(itemEx, ui.NewProps, packStream)); - if (!packStream) - return E_NOTIMPL; - - complexity += rangeSize; - - CMyComPtr outStream; - archive.CreateStreamForCopying(outStream); - HRESULT res = NCompress::CopyStream_ExactSize(packStream, outStream, rangeSize, progress); - archive.MoveCurPos(rangeSize); - return res; -} - - -static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options, - const CUpdateItem &ui, CItemOut &item) -{ - SetFileHeader(*options, ui, false, item); - archive.WriteLocalHeader(item); -} - - -static inline bool IsZero_FILETIME(const FILETIME &ft) -{ - return (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0); -} - -static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileInStream, - IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity) -{ - CMyComPtr getProps; - fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); - if (!getProps) - return; - - FILETIME cTime, aTime, mTime; - UInt64 size; - // UInt32 attrib; - if (getProps->GetProps(&size, &cTime, &aTime, &mTime, NULL) != S_OK) - return; - - if (size != item.Size && size != (UInt64)(Int64)-1) - { - Int64 newComplexity = totalComplexity + ((Int64)size - (Int64)item.Size); - if (newComplexity > 0) - { - totalComplexity = newComplexity; - updateCallback->SetTotal(totalComplexity); - } - item.Size = size; - } - - if (!IsZero_FILETIME(mTime)) - { - item.Ntfs_MTime = mTime; - FILETIME loc = { 0, 0 }; - if (FileTimeToLocalFileTime(&mTime, &loc)) - { - item.Time = 0; - NTime::FileTimeToDosTime(loc, item.Time); - } - } - - if (!IsZero_FILETIME(cTime)) item.Ntfs_CTime = cTime; - if (!IsZero_FILETIME(aTime)) item.Ntfs_ATime = aTime; - - // item.Attrib = attrib; -} - - -static HRESULT Update2St( - DECL_EXTERNAL_CODECS_LOC_VARS - COutArchive &archive, - CInArchive *inArchive, - const CObjectVector &inputItems, - CObjectVector &updateItems, - const CCompressionMethodMode *options, bool outSeqMode, - const CByteBuffer *comment, - IArchiveUpdateCallback *updateCallback, - UInt64 &totalComplexity, - IArchiveUpdateCallbackFile *opCallback) -{ - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(updateCallback, true); - - CAddCommon compressor(*options); - - CObjectVector 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[ui.IndexInArc]; - if (inArchive->ReadLocalItemAfterCdItemFull(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) - { - WriteDirHeader(archive, options, ui, item); - } - else - { - CMyComPtr 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 inStream2; - fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2); - inSeqMode = (inStream2 == NULL); - } - // seqMode = true; // to test seqMode - - UpdatePropsFromStream(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); - - archive.WriteLocalHeader(item); - - CMyComPtr outStream; - archive.CreateStreamForCompressing(outStream); - - RINOK(compressor.Compress( - EXTERNAL_CODECS_LOC_VARS - fileInStream, outStream, - inSeqMode, outSeqMode, - ui.Time, ui.Size, - progress, compressingResult)); - - if (item.HasDescriptor() != compressingResult.DescriptorMode) - return E_FAIL; - - SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); - - archive.WriteLocalHeader_Replace(item); - - 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()); - - archive.WriteCentralDir(items, comment); - - lps->ProgressOffset += kCentralHeaderSize * updateItems.Size() + 1; - return lps->SetCur(); -} - - -static HRESULT Update2( - DECL_EXTERNAL_CODECS_LOC_VARS - COutArchive &archive, - CInArchive *inArchive, - const CObjectVector &inputItems, - CObjectVector &updateItems, - const CCompressionMethodMode &options, bool outSeqMode, - const CByteBuffer *comment, - IArchiveUpdateCallback *updateCallback) -{ - CMyComPtr opCallback; - updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); - - bool unknownComplexity = false; - UInt64 complexity = 0; - UInt64 numFilesToCompress = 0; - UInt64 numBytesToCompress = 0; - - 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; - numBytesToCompress += ui.Size; - numFilesToCompress++; - /* - if (ui.Commented) - complexity += ui.CommentRange.Size; - */ - } - else - { - CItemEx inputItem = inputItems[ui.IndexInArc]; - if (inArchive->ReadLocalItemAfterCdItemFull(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(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 _7ZIP_ST - - UInt32 numThreads = options._numThreads; - - const UInt32 kNumMaxThreads = 64; - if (numThreads > kNumMaxThreads) - numThreads = kNumMaxThreads; - if (numThreads > MAXIMUM_WAIT_OBJECTS) // is 64 in Windows (is it 64 in all versions?) - numThreads = MAXIMUM_WAIT_OBJECTS; - if (numThreads < 1) - numThreads = 1; - - const size_t kMemPerThread = (1 << 25); - const size_t kBlockSize = 1 << 16; - - bool mtMode = (numThreads > 1); - - if (numFilesToCompress <= 1) - mtMode = false; - - if (!mtMode) - { - FOR_VECTOR (mi, options2._methods) - { - COneMethodInfo &onem = options2._methods[mi]; - - if (onem.FindProp(NCoderPropID::kNumThreads) < 0) - { - // fixed for 9.31. bzip2 default is just one thread. - onem.AddProp_NumThreads(numThreads); - } - } - } - else - { - if (method == NFileHeader::NCompressionMethod::kStore && !options.PasswordIsDefined) - 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) - { - 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 = t; - } - numThreads /= (unsigned)numXzThreads; - } - else if (method == NFileHeader::NCompressionMethod::kLZMA) - { - // we suppose that default LZMA is 2 thread. So we don't change it - UInt32 numLZMAThreads = oneMethodMain->Get_Lzma_NumThreads(); - numThreads /= numLZMAThreads; - } - } - - if (numThreads > numFilesToCompress) - numThreads = (UInt32)numFilesToCompress; - if (numThreads <= 1) - mtMode = false; - } - - // mtMode = true; // to test mtMode for seqMode - - if (!mtMode) - #endif - return Update2St( - EXTERNAL_CODECS_LOC_VARS - archive, inArchive, - inputItems, updateItems, &options2, outSeqMode, comment, updateCallback, totalComplexity, opCallback); - - - #ifndef _7ZIP_ST - - CObjectVector items; - - CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer; - CMyComPtr progress = mtProgressMixerSpec; - mtProgressMixerSpec->Create(updateCallback, true); - - CMtCompressProgressMixer mtCompressProgressMixer; - mtCompressProgressMixer.Init(numThreads, mtProgressMixerSpec->RatioProgress); - - CMemBlockManagerMt memManager(kBlockSize); - CMemRefs refs(&memManager); - - CThreads threads; - CRecordVector compressingCompletedEvents; - 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.Add(CThreadInfo(options2)); - - for (i = 0; i < numThreads; i++) - { - CThreadInfo &threadInfo = threads.Threads[i]; - #ifdef EXTERNAL_CODECS - threadInfo.__externalCodecs = __externalCodecs; - #endif - RINOK(threadInfo.CreateEvents()); - threadInfo.OutStreamSpec = new COutMemStream(&memManager); - RINOK(threadInfo.OutStreamSpec->CreateEvents()); - threadInfo.OutStream = threadInfo.OutStreamSpec; - threadInfo.IsFree = true; - threadInfo.ProgressSpec = new CMtCompressProgress(); - threadInfo.Progress = threadInfo.ProgressSpec; - threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, (int)i); - threadInfo.InSeqMode = false; - threadInfo.OutSeqMode = false; - threadInfo.FileTime = 0; - threadInfo.ExpectedDataSize = (UInt64)(Int64)-1; - 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[ui.IndexInArc]; - if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK) - return E_NOTIMPL; - (CItem &)item = itemEx; - if (item.IsDir() != ui.IsDir) - return E_NOTIMPL; - if (ui.IsDir) - continue; - } - - CMyComPtr 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(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 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.CompressEvent.Set(); - - compressingCompletedEvents.Add(threadInfo.CompressionCompletedEvent); - 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[ui.IndexInArc]; - if (inArchive->ReadLocalItemAfterCdItemFull(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) - { - WriteDirHeader(archive, &options, ui, item); - } - else - { - CMemBlocks2 &memRef = refs.Refs[itemIndex]; - - if (memRef.Finished) - { - if (lastRealStreamItemIndex < (int)itemIndex) - lastRealStreamItemIndex = 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); - archive.WriteLocalHeader(item); - // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); - CMyComPtr outStream; - archive.CreateStreamForCopying(outStream); - memRef.WriteToStream(memManager.GetBlockSize(), outStream); - archive.MoveCurPos(item.PackSize); - memRef.FreeOpt(&memManager); - } - else - { - // current file was not finished - - if (lastRealStreamItemIndex < (int)itemIndex) - { - // LocalHeader was not written for current itemIndex still - - lastRealStreamItemIndex = 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 !!! - archive.WriteLocalHeader(item); - } - - { - CThreadInfo &thread = threads.Threads[threadIndices.Front()]; - if (!thread.OutStreamSpec->WasUnlockEventSent()) - { - CMyComPtr outStream; - archive.CreateStreamForCompressing(outStream); - thread.OutStreamSpec->SetOutStream(outStream); - thread.OutStreamSpec->SetRealStreamMode(); - } - } - - DWORD result = ::WaitForMultipleObjects(compressingCompletedEvents.Size(), - &compressingCompletedEvents.Front(), FALSE, INFINITE); - if (result == WAIT_FAILED) - { - DWORD lastError = GetLastError(); - return lastError != 0 ? lastError : E_FAIL; - } - - unsigned t = (unsigned)(result - WAIT_OBJECT_0); - if (t >= compressingCompletedEvents.Size()) - return E_FAIL; - - CThreadInfo &threadInfo = threads.Threads[threadIndices[t]]; - threadInfo.InStream.Release(); - threadInfo.IsFree = true; - RINOK(threadInfo.Result); - threadIndices.Delete(t); - compressingCompletedEvents.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); - } - 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)); - - archive.WriteCentralDir(items, comment); - - complexity += kCentralHeaderSize * updateItems.Size() + 1; - mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); - return mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL); - - #endif -} - - -static const size_t kCacheBlockSize = (1 << 20); -static const size_t kCacheSize = (kCacheBlockSize << 2); -static const size_t kCacheMask = (kCacheSize - 1); - -class CCacheOutStream: - public IOutStream, - public CMyUnknownImp -{ - CMyComPtr _stream; - CMyComPtr _seqStream; - Byte *_cache; - UInt64 _virtPos; - UInt64 _virtSize; - UInt64 _phyPos; - UInt64 _phySize; // <= _virtSize - UInt64 _cachedPos; // (_cachedPos + _cachedSize) <= _virtSize - size_t _cachedSize; - - HRESULT MyWrite(size_t size); - HRESULT MyWriteBlock() - { - return MyWrite(kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1))); - } - HRESULT FlushCache(); -public: - CCacheOutStream(): _cache(NULL) {} - ~CCacheOutStream(); - bool Allocate(); - HRESULT Init(ISequentialOutStream *seqStream, IOutStream *stream); - - MY_UNKNOWN_IMP - - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); - STDMETHOD(SetSize)(UInt64 newSize); -}; - -bool CCacheOutStream::Allocate() -{ - if (!_cache) - _cache = (Byte *)::MidAlloc(kCacheSize); - return (_cache != NULL); -} - -HRESULT CCacheOutStream::Init(ISequentialOutStream *seqStream, IOutStream *stream) -{ - _virtPos = 0; - _phyPos = 0; - _virtSize = 0; - _seqStream = seqStream; - _stream = stream; - if (_stream) - { - RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos)); - RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize)); - RINOK(_stream->Seek(_virtPos, STREAM_SEEK_SET, &_virtPos)); - } - _phyPos = _virtPos; - _phySize = _virtSize; - _cachedPos = 0; - _cachedSize = 0; - return S_OK; -} - -HRESULT CCacheOutStream::MyWrite(size_t size) -{ - while (size != 0 && _cachedSize != 0) - { - if (_phyPos != _cachedPos) - { - if (!_stream) - return E_FAIL; - RINOK(_stream->Seek(_cachedPos, STREAM_SEEK_SET, &_phyPos)); - } - size_t pos = (size_t)_cachedPos & kCacheMask; - size_t curSize = MyMin(kCacheSize - pos, _cachedSize); - curSize = MyMin(curSize, size); - RINOK(WriteStream(_seqStream, _cache + pos, curSize)); - _phyPos += curSize; - if (_phySize < _phyPos) - _phySize = _phyPos; - _cachedPos += curSize; - _cachedSize -= curSize; - size -= curSize; - } - return S_OK; -} - -HRESULT CCacheOutStream::FlushCache() -{ - return MyWrite(_cachedSize); -} - -CCacheOutStream::~CCacheOutStream() -{ - FlushCache(); - if (_stream) - { - if (_virtSize != _phySize) - _stream->SetSize(_virtSize); - if (_virtPos != _phyPos) - _stream->Seek(_virtPos, STREAM_SEEK_SET, NULL); - } - ::MidFree(_cache); -} - -STDMETHODIMP CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) -{ - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - - UInt64 zerosStart = _virtPos; - if (_cachedSize != 0) - { - if (_virtPos < _cachedPos) - { - RINOK(FlushCache()); - } - else - { - UInt64 cachedEnd = _cachedPos + _cachedSize; - if (cachedEnd < _virtPos) - { - if (cachedEnd < _phySize) - { - RINOK(FlushCache()); - } - else - zerosStart = cachedEnd; - } - } - } - - if (_cachedSize == 0 && _phySize < _virtPos) - _cachedPos = zerosStart = _phySize; - - if (zerosStart != _virtPos) - { - // write zeros to [cachedEnd ... _virtPos) - - for (;;) - { - UInt64 cachedEnd = _cachedPos + _cachedSize; - size_t endPos = (size_t)cachedEnd & kCacheMask; - size_t curSize = kCacheSize - endPos; - if (curSize > _virtPos - cachedEnd) - curSize = (size_t)(_virtPos - cachedEnd); - if (curSize == 0) - break; - while (curSize > (kCacheSize - _cachedSize)) - { - RINOK(MyWriteBlock()); - } - memset(_cache + endPos, 0, curSize); - _cachedSize += curSize; - } - } - - if (_cachedSize == 0) - _cachedPos = _virtPos; - - size_t pos = (size_t)_virtPos & kCacheMask; - size = (UInt32)MyMin((size_t)size, kCacheSize - pos); - UInt64 cachedEnd = _cachedPos + _cachedSize; - if (_virtPos != cachedEnd) // _virtPos < cachedEnd - size = (UInt32)MyMin((size_t)size, (size_t)(cachedEnd - _virtPos)); - else - { - // _virtPos == cachedEnd - if (_cachedSize == kCacheSize) - { - RINOK(MyWriteBlock()); - } - size_t startPos = (size_t)_cachedPos & kCacheMask; - if (startPos > pos) - size = (UInt32)MyMin((size_t)size, (size_t)(startPos - pos)); - _cachedSize += size; - } - memcpy(_cache + pos, data, size); - if (processedSize) - *processedSize = size; - _virtPos += size; - if (_virtSize < _virtPos) - _virtSize = _virtPos; - return S_OK; -} - -STDMETHODIMP CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: 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 = offset; - return S_OK; -} - -STDMETHODIMP CCacheOutStream::SetSize(UInt64 newSize) -{ - _virtSize = newSize; - if (newSize < _phySize) - { - if (!_stream) - return E_NOTIMPL; - RINOK(_stream->SetSize(newSize)); - _phySize = newSize; - } - if (newSize <= _cachedPos) - { - _cachedSize = 0; - _cachedPos = newSize; - } - if (newSize < _cachedPos + _cachedSize) - _cachedSize = (size_t)(newSize - _cachedPos); - return S_OK; -} - - -HRESULT Update( - DECL_EXTERNAL_CODECS_LOC_VARS - const CObjectVector &inputItems, - CObjectVector &updateItems, - ISequentialOutStream *seqOutStream, - CInArchive *inArchive, bool removeSfx, - const CCompressionMethodMode &compressionMethodMode, - IArchiveUpdateCallback *updateCallback) -{ - if (inArchive) - { - if (!inArchive->CanUpdate()) - return E_NOTIMPL; - } - - - CMyComPtr outStream; - bool outSeqMode; - { - CMyComPtr outStreamReal; - 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(baseStream->Seek(0, STREAM_SEEK_SET, NULL)); - RINOK(NCompress::CopyStream_ExactSize(baseStream, seqOutStream, inArchive->ArcInfo.Base, NULL)); - } - } - - CCacheOutStream *cacheStream = new CCacheOutStream(); - outStream = cacheStream; - if (!cacheStream->Allocate()) - return E_OUTOFMEMORY; - RINOK(cacheStream->Init(seqOutStream, outStreamReal)); - outSeqMode = (outStreamReal == NULL); - } - - COutArchive outArchive; - RINOK(outArchive.Create(outStream)); - - if (inArchive) - { - if (!inArchive->IsMultiVol && (Int64)inArchive->ArcInfo.MarkerPos2 > inArchive->ArcInfo.Base) - { - IInStream *baseStream = inArchive->GetBaseStream(); - RINOK(baseStream->Seek(inArchive->ArcInfo.Base, STREAM_SEEK_SET, NULL)); - UInt64 embStubSize = inArchive->ArcInfo.MarkerPos2 - inArchive->ArcInfo.Base; - RINOK(NCompress::CopyStream_ExactSize(baseStream, outStream, embStubSize, NULL)); - outArchive.MoveCurPos(embStubSize); - } - } - - return Update2( - EXTERNAL_CODECS_LOC_VARS - outArchive, inArchive, - inputItems, updateItems, - compressionMethodMode, outSeqMode, - inArchive ? &inArchive->ArcInfo.Comment : NULL, - updateCallback); -} - -}} +// ZipUpdate.cpp + +#include "StdAfx.h" + +#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 _7ZIP_ST +#include "../../Common/ProgressMt.h" +#endif +#include "../../Common/StreamUtils.h" + +#include "../../Compress/CopyCoder.h" + +#include "ZipAddCommon.h" +#include "ZipOut.h" +#include "ZipUpdate.h" + +using namespace NWindows; +using namespace NSynchronization; + +namespace NArchive { +namespace NZip { + +static const Byte kHostOS = + #ifdef _WIN32 + NFileHeader::NHostOS::kFAT; + #else + NFileHeader::NHostOS::kUnix; + #endif + +static const Byte kMadeByHostOS = kHostOS; + +// 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 SetFileHeader( + const CCompressionMethodMode &options, + const CUpdateItem &ui, + bool useDescriptor, + CItemOut &item) +{ + item.Size = ui.Size; + bool isDir = ui.IsDir; + + item.ClearFlags(); + + if (ui.NewProps) + { + item.Name = ui.Name; + 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.NtfsTimeIsDefined = ui.NtfsTimeIsDefined; + } + /* + 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.PasswordIsDefined); + 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 _7ZIP_ST + +static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo); + +struct CThreadInfo +{ + DECL_EXTERNAL_CODECS_LOC_VARS2; + + NWindows::CThread Thread; + NWindows::NSynchronization::CAutoResetEvent CompressEvent; + NWindows::NSynchronization::CAutoResetEvent CompressionCompletedEvent; + bool ExitThread; + + CMtCompressProgress *ProgressSpec; + CMyComPtr Progress; + + COutMemStream *OutStreamSpec; + CMyComPtr OutStream; + CMyComPtr InStream; + + CAddCommon Coder; + HRESULT Result; + CCompressingResult CompressingResult; + + bool InSeqMode; + bool OutSeqMode; + bool IsFree; + UInt32 UpdateIndex; + UInt32 FileTime; + UInt64 ExpectedDataSize; + + CThreadInfo(const CCompressionMethodMode &options): + ExitThread(false), + ProgressSpec(0), + OutStreamSpec(0), + Coder(options), + InSeqMode(false), + OutSeqMode(false), + FileTime(0), + ExpectedDataSize((UInt64)(Int64)-1) + {} + + HRESULT CreateEvents() + { + RINOK(CompressEvent.CreateIfNotCreated()); + return CompressionCompletedEvent.CreateIfNotCreated(); + } + HRes CreateThread() { return Thread.Create(CoderThread, this); } + + void WaitAndCode(); + void StopWaitClose() + { + ExitThread = true; + if (OutStreamSpec != 0) + OutStreamSpec->StopWriting(E_ABORT); + if (CompressEvent.IsCreated()) + CompressEvent.Set(); + Thread.Wait(); + Thread.Close(); + } +}; + +void CThreadInfo::WaitAndCode() +{ + for (;;) + { + CompressEvent.Lock(); + if (ExitThread) + return; + + Result = Coder.Compress( + EXTERNAL_CODECS_LOC_VARS + InStream, OutStream, + InSeqMode, OutSeqMode, FileTime, ExpectedDataSize, + Progress, CompressingResult); + + if (Result == S_OK && Progress) + Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize); + CompressionCompletedEvent.Set(); + } +} + +static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo) +{ + ((CThreadInfo *)threadCoderInfo)->WaitAndCode(); + return 0; +} + +class CThreads +{ +public: + CObjectVector Threads; + ~CThreads() + { + FOR_VECTOR (i, Threads) + Threads[i].StopWaitClose(); + } +}; + +struct CMemBlocks2: public CMemLockBlocks +{ + bool Skip; + bool InSeqMode; + bool PreDescriptorMode; + bool Finished; + CCompressingResult CompressingResult; + + CMemBlocks2(): Skip(false), InSeqMode(false), PreDescriptorMode(false), Finished(false) {} +}; + +class CMemRefs +{ +public: + CMemBlockManagerMt *Manager; + CObjectVector Refs; + CMemRefs(CMemBlockManagerMt *manager): Manager(manager) {} ; + ~CMemRefs() + { + FOR_VECTOR (i, Refs) + Refs[i].FreeOpt(Manager); + } +}; + +class CMtProgressMixer2: + public ICompressProgressInfo, + public CMyUnknownImp +{ + UInt64 ProgressOffset; + UInt64 InSizes[2]; + UInt64 OutSizes[2]; + CMyComPtr Progress; + CMyComPtr RatioProgress; + bool _inSizeIsMain; +public: + NWindows::NSynchronization::CCriticalSection CriticalSection; + MY_UNKNOWN_IMP + 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); + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); +}; + +void CMtProgressMixer2::Create(IProgress *progress, bool inSizeIsMain) +{ + Progress = progress; + Progress.QueryInterface(IID_ICompressProgressInfo, &RatioProgress); + _inSizeIsMain = inSizeIsMain; + ProgressOffset = InSizes[0] = InSizes[1] = OutSizes[0] = OutSizes[1] = 0; +} + +void CMtProgressMixer2::SetProgressOffset_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); +} + +STDMETHODIMP CMtProgressMixer2::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + return SetRatioInfo(0, inSize, outSize); +} + +class CMtProgressMixer: + public ICompressProgressInfo, + public CMyUnknownImp +{ +public: + CMtProgressMixer2 *Mixer2; + CMyComPtr RatioProgress; + void Create(IProgress *progress, bool inSizeIsMain); + MY_UNKNOWN_IMP + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); +}; + +void CMtProgressMixer::Create(IProgress *progress, bool inSizeIsMain) +{ + Mixer2 = new CMtProgressMixer2; + RatioProgress = Mixer2; + Mixer2->Create(progress, inSizeIsMain); +} + +STDMETHODIMP CMtProgressMixer::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + return Mixer2->SetRatioInfo(1, inSize, outSize); +} + + +#endif + + +static HRESULT UpdateItemOldData( + COutArchive &archive, + 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; + + if (ui.NewProps) + { + if (item.HasDescriptor()) + return E_NOTIMPL; + + // use old name size. + + // 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 + item.Comment = ui.Comment; + item.Name = ui.Name; + item.SetUtf8(ui.IsUtf8); + // item.SetFlag_AltStream(ui.IsAltStream); + item.Time = ui.Time; + item.Ntfs_MTime = ui.Ntfs_MTime; + item.Ntfs_ATime = ui.Ntfs_ATime; + item.Ntfs_CTime = ui.Ntfs_CTime; + item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined; + + item.CentralExtra.RemoveUnknownSubBlocks(); + item.LocalExtra.RemoveUnknownSubBlocks(); + + archive.WriteLocalHeader(item); + rangeSize = item.GetPackSizeWithDescriptor(); + } + else + { + item.LocalHeaderPos = archive.GetCurPos(); + rangeSize = itemEx.GetLocalFullSize(); + } + + CMyComPtr packStream; + + RINOK(inArchive->GetItemStream(itemEx, ui.NewProps, packStream)); + if (!packStream) + return E_NOTIMPL; + + complexity += rangeSize; + + CMyComPtr outStream; + archive.CreateStreamForCopying(outStream); + HRESULT res = NCompress::CopyStream_ExactSize(packStream, outStream, rangeSize, progress); + archive.MoveCurPos(rangeSize); + return res; +} + + +static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options, + const CUpdateItem &ui, CItemOut &item) +{ + SetFileHeader(*options, ui, false, item); + archive.WriteLocalHeader(item); +} + + +static inline bool IsZero_FILETIME(const FILETIME &ft) +{ + return (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0); +} + +static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileInStream, + IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity) +{ + CMyComPtr getProps; + fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); + if (!getProps) + return; + + FILETIME cTime, aTime, mTime; + UInt64 size; + // UInt32 attrib; + if (getProps->GetProps(&size, &cTime, &aTime, &mTime, NULL) != S_OK) + return; + + if (size != item.Size && size != (UInt64)(Int64)-1) + { + Int64 newComplexity = totalComplexity + ((Int64)size - (Int64)item.Size); + if (newComplexity > 0) + { + totalComplexity = newComplexity; + updateCallback->SetTotal(totalComplexity); + } + item.Size = size; + } + + if (!IsZero_FILETIME(mTime)) + { + item.Ntfs_MTime = mTime; + FILETIME loc = { 0, 0 }; + if (FileTimeToLocalFileTime(&mTime, &loc)) + { + item.Time = 0; + NTime::FileTimeToDosTime(loc, item.Time); + } + } + + if (!IsZero_FILETIME(cTime)) item.Ntfs_CTime = cTime; + if (!IsZero_FILETIME(aTime)) item.Ntfs_ATime = aTime; + + // item.Attrib = attrib; +} + + +static HRESULT Update2St( + DECL_EXTERNAL_CODECS_LOC_VARS + COutArchive &archive, + CInArchive *inArchive, + const CObjectVector &inputItems, + CObjectVector &updateItems, + const CCompressionMethodMode *options, bool outSeqMode, + const CByteBuffer *comment, + IArchiveUpdateCallback *updateCallback, + UInt64 &totalComplexity, + IArchiveUpdateCallbackFile *opCallback) +{ + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(updateCallback, true); + + CAddCommon compressor(*options); + + CObjectVector 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[ui.IndexInArc]; + if (inArchive->ReadLocalItemAfterCdItemFull(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) + { + WriteDirHeader(archive, options, ui, item); + } + else + { + CMyComPtr 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 inStream2; + fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2); + inSeqMode = (inStream2 == NULL); + } + // seqMode = true; // to test seqMode + + UpdatePropsFromStream(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); + + archive.WriteLocalHeader(item); + + CMyComPtr outStream; + archive.CreateStreamForCompressing(outStream); + + RINOK(compressor.Compress( + EXTERNAL_CODECS_LOC_VARS + fileInStream, outStream, + inSeqMode, outSeqMode, + ui.Time, ui.Size, + progress, compressingResult)); + + if (item.HasDescriptor() != compressingResult.DescriptorMode) + return E_FAIL; + + SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); + + archive.WriteLocalHeader_Replace(item); + + 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()); + + archive.WriteCentralDir(items, comment); + + lps->ProgressOffset += kCentralHeaderSize * updateItems.Size() + 1; + return lps->SetCur(); +} + + +static HRESULT Update2( + DECL_EXTERNAL_CODECS_LOC_VARS + COutArchive &archive, + CInArchive *inArchive, + const CObjectVector &inputItems, + CObjectVector &updateItems, + const CCompressionMethodMode &options, bool outSeqMode, + const CByteBuffer *comment, + IArchiveUpdateCallback *updateCallback) +{ + CMyComPtr opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + + bool unknownComplexity = false; + UInt64 complexity = 0; + UInt64 numFilesToCompress = 0; + UInt64 numBytesToCompress = 0; + + 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; + numBytesToCompress += ui.Size; + numFilesToCompress++; + /* + if (ui.Commented) + complexity += ui.CommentRange.Size; + */ + } + else + { + CItemEx inputItem = inputItems[ui.IndexInArc]; + if (inArchive->ReadLocalItemAfterCdItemFull(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(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 _7ZIP_ST + + UInt32 numThreads = options._numThreads; + + const UInt32 kNumMaxThreads = 64; + if (numThreads > kNumMaxThreads) + numThreads = kNumMaxThreads; + if (numThreads > MAXIMUM_WAIT_OBJECTS) // is 64 in Windows (is it 64 in all versions?) + numThreads = MAXIMUM_WAIT_OBJECTS; + if (numThreads < 1) + numThreads = 1; + + const size_t kMemPerThread = (1 << 25); + const size_t kBlockSize = 1 << 16; + + bool mtMode = (numThreads > 1); + + if (numFilesToCompress <= 1) + mtMode = false; + + if (!mtMode) + { + FOR_VECTOR (mi, options2._methods) + { + COneMethodInfo &onem = options2._methods[mi]; + + if (onem.FindProp(NCoderPropID::kNumThreads) < 0) + { + // fixed for 9.31. bzip2 default is just one thread. + onem.AddProp_NumThreads(numThreads); + } + } + } + else + { + if (method == NFileHeader::NCompressionMethod::kStore && !options.PasswordIsDefined) + 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) + { + 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 = t; + } + numThreads /= (unsigned)numXzThreads; + } + else if (method == NFileHeader::NCompressionMethod::kLZMA) + { + // we suppose that default LZMA is 2 thread. So we don't change it + UInt32 numLZMAThreads = oneMethodMain->Get_Lzma_NumThreads(); + numThreads /= numLZMAThreads; + } + } + + if (numThreads > numFilesToCompress) + numThreads = (UInt32)numFilesToCompress; + if (numThreads <= 1) + mtMode = false; + } + + // mtMode = true; // to test mtMode for seqMode + + if (!mtMode) + #endif + return Update2St( + EXTERNAL_CODECS_LOC_VARS + archive, inArchive, + inputItems, updateItems, &options2, outSeqMode, comment, updateCallback, totalComplexity, opCallback); + + + #ifndef _7ZIP_ST + + CObjectVector items; + + CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer; + CMyComPtr progress = mtProgressMixerSpec; + mtProgressMixerSpec->Create(updateCallback, true); + + CMtCompressProgressMixer mtCompressProgressMixer; + mtCompressProgressMixer.Init(numThreads, mtProgressMixerSpec->RatioProgress); + + CMemBlockManagerMt memManager(kBlockSize); + CMemRefs refs(&memManager); + + CThreads threads; + CRecordVector compressingCompletedEvents; + 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.Add(CThreadInfo(options2)); + + for (i = 0; i < numThreads; i++) + { + CThreadInfo &threadInfo = threads.Threads[i]; + #ifdef EXTERNAL_CODECS + threadInfo.__externalCodecs = __externalCodecs; + #endif + RINOK(threadInfo.CreateEvents()); + threadInfo.OutStreamSpec = new COutMemStream(&memManager); + RINOK(threadInfo.OutStreamSpec->CreateEvents()); + threadInfo.OutStream = threadInfo.OutStreamSpec; + threadInfo.IsFree = true; + threadInfo.ProgressSpec = new CMtCompressProgress(); + threadInfo.Progress = threadInfo.ProgressSpec; + threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, (int)i); + threadInfo.InSeqMode = false; + threadInfo.OutSeqMode = false; + threadInfo.FileTime = 0; + threadInfo.ExpectedDataSize = (UInt64)(Int64)-1; + 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[ui.IndexInArc]; + if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK) + return E_NOTIMPL; + (CItem &)item = itemEx; + if (item.IsDir() != ui.IsDir) + return E_NOTIMPL; + if (ui.IsDir) + continue; + } + + CMyComPtr 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(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 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.CompressEvent.Set(); + + compressingCompletedEvents.Add(threadInfo.CompressionCompletedEvent); + 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[ui.IndexInArc]; + if (inArchive->ReadLocalItemAfterCdItemFull(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) + { + WriteDirHeader(archive, &options, ui, item); + } + else + { + CMemBlocks2 &memRef = refs.Refs[itemIndex]; + + if (memRef.Finished) + { + if (lastRealStreamItemIndex < (int)itemIndex) + lastRealStreamItemIndex = 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); + archive.WriteLocalHeader(item); + // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); + CMyComPtr outStream; + archive.CreateStreamForCopying(outStream); + memRef.WriteToStream(memManager.GetBlockSize(), outStream); + archive.MoveCurPos(item.PackSize); + memRef.FreeOpt(&memManager); + } + else + { + // current file was not finished + + if (lastRealStreamItemIndex < (int)itemIndex) + { + // LocalHeader was not written for current itemIndex still + + lastRealStreamItemIndex = 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 !!! + archive.WriteLocalHeader(item); + } + + { + CThreadInfo &thread = threads.Threads[threadIndices.Front()]; + if (!thread.OutStreamSpec->WasUnlockEventSent()) + { + CMyComPtr outStream; + archive.CreateStreamForCompressing(outStream); + thread.OutStreamSpec->SetOutStream(outStream); + thread.OutStreamSpec->SetRealStreamMode(); + } + } + + DWORD result = ::WaitForMultipleObjects(compressingCompletedEvents.Size(), + &compressingCompletedEvents.Front(), FALSE, INFINITE); + if (result == WAIT_FAILED) + { + DWORD lastError = GetLastError(); + return lastError != 0 ? lastError : E_FAIL; + } + + unsigned t = (unsigned)(result - WAIT_OBJECT_0); + if (t >= compressingCompletedEvents.Size()) + return E_FAIL; + + CThreadInfo &threadInfo = threads.Threads[threadIndices[t]]; + threadInfo.InStream.Release(); + threadInfo.IsFree = true; + RINOK(threadInfo.Result); + threadIndices.Delete(t); + compressingCompletedEvents.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); + } + 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)); + + archive.WriteCentralDir(items, comment); + + complexity += kCentralHeaderSize * updateItems.Size() + 1; + mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); + return mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL); + + #endif +} + + +static const size_t kCacheBlockSize = (1 << 20); +static const size_t kCacheSize = (kCacheBlockSize << 2); +static const size_t kCacheMask = (kCacheSize - 1); + +class CCacheOutStream: + public IOutStream, + public CMyUnknownImp +{ + CMyComPtr _stream; + CMyComPtr _seqStream; + Byte *_cache; + UInt64 _virtPos; + UInt64 _virtSize; + UInt64 _phyPos; + UInt64 _phySize; // <= _virtSize + UInt64 _cachedPos; // (_cachedPos + _cachedSize) <= _virtSize + size_t _cachedSize; + + HRESULT MyWrite(size_t size); + HRESULT MyWriteBlock() + { + return MyWrite(kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1))); + } + HRESULT FlushCache(); +public: + CCacheOutStream(): _cache(NULL) {} + ~CCacheOutStream(); + bool Allocate(); + HRESULT Init(ISequentialOutStream *seqStream, IOutStream *stream); + + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); + STDMETHOD(SetSize)(UInt64 newSize); +}; + +bool CCacheOutStream::Allocate() +{ + if (!_cache) + _cache = (Byte *)::MidAlloc(kCacheSize); + return (_cache != NULL); +} + +HRESULT CCacheOutStream::Init(ISequentialOutStream *seqStream, IOutStream *stream) +{ + _virtPos = 0; + _phyPos = 0; + _virtSize = 0; + _seqStream = seqStream; + _stream = stream; + if (_stream) + { + RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos)); + RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize)); + RINOK(_stream->Seek(_virtPos, STREAM_SEEK_SET, &_virtPos)); + } + _phyPos = _virtPos; + _phySize = _virtSize; + _cachedPos = 0; + _cachedSize = 0; + return S_OK; +} + +HRESULT CCacheOutStream::MyWrite(size_t size) +{ + while (size != 0 && _cachedSize != 0) + { + if (_phyPos != _cachedPos) + { + if (!_stream) + return E_FAIL; + RINOK(_stream->Seek(_cachedPos, STREAM_SEEK_SET, &_phyPos)); + } + size_t pos = (size_t)_cachedPos & kCacheMask; + size_t curSize = MyMin(kCacheSize - pos, _cachedSize); + curSize = MyMin(curSize, size); + RINOK(WriteStream(_seqStream, _cache + pos, curSize)); + _phyPos += curSize; + if (_phySize < _phyPos) + _phySize = _phyPos; + _cachedPos += curSize; + _cachedSize -= curSize; + size -= curSize; + } + return S_OK; +} + +HRESULT CCacheOutStream::FlushCache() +{ + return MyWrite(_cachedSize); +} + +CCacheOutStream::~CCacheOutStream() +{ + FlushCache(); + if (_stream) + { + if (_virtSize != _phySize) + _stream->SetSize(_virtSize); + if (_virtPos != _phyPos) + _stream->Seek(_virtPos, STREAM_SEEK_SET, NULL); + } + ::MidFree(_cache); +} + +STDMETHODIMP CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + + UInt64 zerosStart = _virtPos; + if (_cachedSize != 0) + { + if (_virtPos < _cachedPos) + { + RINOK(FlushCache()); + } + else + { + UInt64 cachedEnd = _cachedPos + _cachedSize; + if (cachedEnd < _virtPos) + { + if (cachedEnd < _phySize) + { + RINOK(FlushCache()); + } + else + zerosStart = cachedEnd; + } + } + } + + if (_cachedSize == 0 && _phySize < _virtPos) + _cachedPos = zerosStart = _phySize; + + if (zerosStart != _virtPos) + { + // write zeros to [cachedEnd ... _virtPos) + + for (;;) + { + UInt64 cachedEnd = _cachedPos + _cachedSize; + size_t endPos = (size_t)cachedEnd & kCacheMask; + size_t curSize = kCacheSize - endPos; + if (curSize > _virtPos - cachedEnd) + curSize = (size_t)(_virtPos - cachedEnd); + if (curSize == 0) + break; + while (curSize > (kCacheSize - _cachedSize)) + { + RINOK(MyWriteBlock()); + } + memset(_cache + endPos, 0, curSize); + _cachedSize += curSize; + } + } + + if (_cachedSize == 0) + _cachedPos = _virtPos; + + size_t pos = (size_t)_virtPos & kCacheMask; + size = (UInt32)MyMin((size_t)size, kCacheSize - pos); + UInt64 cachedEnd = _cachedPos + _cachedSize; + if (_virtPos != cachedEnd) // _virtPos < cachedEnd + size = (UInt32)MyMin((size_t)size, (size_t)(cachedEnd - _virtPos)); + else + { + // _virtPos == cachedEnd + if (_cachedSize == kCacheSize) + { + RINOK(MyWriteBlock()); + } + size_t startPos = (size_t)_cachedPos & kCacheMask; + if (startPos > pos) + size = (UInt32)MyMin((size_t)size, (size_t)(startPos - pos)); + _cachedSize += size; + } + memcpy(_cache + pos, data, size); + if (processedSize) + *processedSize = size; + _virtPos += size; + if (_virtSize < _virtPos) + _virtSize = _virtPos; + return S_OK; +} + +STDMETHODIMP CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: 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 = offset; + return S_OK; +} + +STDMETHODIMP CCacheOutStream::SetSize(UInt64 newSize) +{ + _virtSize = newSize; + if (newSize < _phySize) + { + if (!_stream) + return E_NOTIMPL; + RINOK(_stream->SetSize(newSize)); + _phySize = newSize; + } + if (newSize <= _cachedPos) + { + _cachedSize = 0; + _cachedPos = newSize; + } + if (newSize < _cachedPos + _cachedSize) + _cachedSize = (size_t)(newSize - _cachedPos); + return S_OK; +} + + +HRESULT Update( + DECL_EXTERNAL_CODECS_LOC_VARS + const CObjectVector &inputItems, + CObjectVector &updateItems, + ISequentialOutStream *seqOutStream, + CInArchive *inArchive, bool removeSfx, + const CCompressionMethodMode &compressionMethodMode, + IArchiveUpdateCallback *updateCallback) +{ + if (inArchive) + { + if (!inArchive->CanUpdate()) + return E_NOTIMPL; + } + + + CMyComPtr outStream; + bool outSeqMode; + { + CMyComPtr outStreamReal; + 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(baseStream->Seek(0, STREAM_SEEK_SET, NULL)); + RINOK(NCompress::CopyStream_ExactSize(baseStream, seqOutStream, inArchive->ArcInfo.Base, NULL)); + } + } + + CCacheOutStream *cacheStream = new CCacheOutStream(); + outStream = cacheStream; + if (!cacheStream->Allocate()) + return E_OUTOFMEMORY; + RINOK(cacheStream->Init(seqOutStream, outStreamReal)); + outSeqMode = (outStreamReal == NULL); + } + + COutArchive outArchive; + RINOK(outArchive.Create(outStream)); + + if (inArchive) + { + if (!inArchive->IsMultiVol && (Int64)inArchive->ArcInfo.MarkerPos2 > inArchive->ArcInfo.Base) + { + IInStream *baseStream = inArchive->GetBaseStream(); + RINOK(baseStream->Seek(inArchive->ArcInfo.Base, STREAM_SEEK_SET, NULL)); + UInt64 embStubSize = inArchive->ArcInfo.MarkerPos2 - inArchive->ArcInfo.Base; + RINOK(NCompress::CopyStream_ExactSize(baseStream, outStream, embStubSize, NULL)); + outArchive.MoveCurPos(embStubSize); + } + } + + return Update2( + EXTERNAL_CODECS_LOC_VARS + outArchive, inArchive, + inputItems, updateItems, + compressionMethodMode, outSeqMode, + inArchive ? &inArchive->ArcInfo.Comment : NULL, + updateCallback); +} + +}} diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.h b/CPP/7zip/Archive/Zip/ZipUpdate.h index 7abb60848..8785ae608 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.h +++ b/CPP/7zip/Archive/Zip/ZipUpdate.h @@ -1,80 +1,80 @@ -// ZipUpdate.h - -#ifndef __ZIP_UPDATE_H -#define __ZIP_UPDATE_H - -#include "../../ICoder.h" -#include "../IArchive.h" - -#include "../../Common/CreateCoder.h" - -#include "ZipCompressionMode.h" -#include "ZipIn.h" - -namespace NArchive { -namespace NZip { - -/* -struct CUpdateRange -{ - UInt64 Position; - UInt64 Size; - - // CUpdateRange() {}; - CUpdateRange(UInt64 position, UInt64 size): Position(position), Size(size) {}; -}; -*/ - -struct CUpdateItem -{ - bool NewData; - bool NewProps; - bool IsDir; - bool NtfsTimeIsDefined; - bool IsUtf8; - // bool IsAltStream; - int IndexInArc; - int IndexInClient; - UInt32 Attrib; - UInt32 Time; - UInt64 Size; - AString Name; - CByteBuffer Comment; - // bool Commented; - // CUpdateRange CommentRange; - FILETIME Ntfs_MTime; - FILETIME Ntfs_ATime; - FILETIME Ntfs_CTime; - - void Clear() - { - IsDir = false; - NtfsTimeIsDefined = false; - IsUtf8 = false; - // IsAltStream = false; - Size = 0; - Name.Empty(); - Comment.Free(); - } - - CUpdateItem(): - IsDir(false), - NtfsTimeIsDefined(false), - IsUtf8(false), - // IsAltStream(false), - Size(0) - {} -}; - -HRESULT Update( - DECL_EXTERNAL_CODECS_LOC_VARS - const CObjectVector &inputItems, - CObjectVector &updateItems, - ISequentialOutStream *seqOutStream, - CInArchive *inArchive, bool removeSfx, - const CCompressionMethodMode &compressionMethodMode, - IArchiveUpdateCallback *updateCallback); - -}} - -#endif +// ZipUpdate.h + +#ifndef __ZIP_UPDATE_H +#define __ZIP_UPDATE_H + +#include "../../ICoder.h" +#include "../IArchive.h" + +#include "../../Common/CreateCoder.h" + +#include "ZipCompressionMode.h" +#include "ZipIn.h" + +namespace NArchive { +namespace NZip { + +/* +struct CUpdateRange +{ + UInt64 Position; + UInt64 Size; + + // CUpdateRange() {}; + CUpdateRange(UInt64 position, UInt64 size): Position(position), Size(size) {}; +}; +*/ + +struct CUpdateItem +{ + bool NewData; + bool NewProps; + bool IsDir; + bool NtfsTimeIsDefined; + bool IsUtf8; + // bool IsAltStream; + int IndexInArc; + int IndexInClient; + UInt32 Attrib; + UInt32 Time; + UInt64 Size; + AString Name; + CByteBuffer Comment; + // bool Commented; + // CUpdateRange CommentRange; + FILETIME Ntfs_MTime; + FILETIME Ntfs_ATime; + FILETIME Ntfs_CTime; + + void Clear() + { + IsDir = false; + NtfsTimeIsDefined = false; + IsUtf8 = false; + // IsAltStream = false; + Size = 0; + Name.Empty(); + Comment.Free(); + } + + CUpdateItem(): + IsDir(false), + NtfsTimeIsDefined(false), + IsUtf8(false), + // IsAltStream(false), + Size(0) + {} +}; + +HRESULT Update( + DECL_EXTERNAL_CODECS_LOC_VARS + const CObjectVector &inputItems, + CObjectVector &updateItems, + ISequentialOutStream *seqOutStream, + CInArchive *inArchive, bool removeSfx, + const CCompressionMethodMode &compressionMethodMode, + IArchiveUpdateCallback *updateCallback); + +}} + +#endif diff --git a/CPP/7zip/Archive/ZstdHandler.cpp b/CPP/7zip/Archive/ZstdHandler.cpp index 066bb8dd1..135c05545 100644 --- a/CPP/7zip/Archive/ZstdHandler.cpp +++ b/CPP/7zip/Archive/ZstdHandler.cpp @@ -1,377 +1,377 @@ -// ZstdHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" -#include "../../Common/ComTry.h" -#include "../../Common/Defs.h" - -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/ZstdDecoder.h" -#include "../Compress/ZstdEncoder.h" -#include "../Compress/CopyCoder.h" - -#include "Common/DummyOutStream.h" -#include "Common/HandlerOut.h" - -using namespace NWindows; - -namespace NArchive { -namespace NZSTD { - -class CHandler: - public IInArchive, - public IArchiveOpenSeq, - public IOutArchive, - public ISetProperties, - public CMyUnknownImp -{ - CMyComPtr _stream; - CMyComPtr _seqStream; - - bool _isArc; - bool _dataAfterEnd; - bool _needMoreInput; - - bool _packSize_Defined; - bool _unpackSize_Defined; - - UInt64 _packSize; - UInt64 _unpackSize; - UInt64 _numStreams; - UInt64 _numBlocks; - - CSingleMethodProps _props; - -public: - MY_UNKNOWN_IMP4( - IInArchive, - IArchiveOpenSeq, - IOutArchive, - ISetProperties) - INTERFACE_IInArchive(;) - INTERFACE_IOutArchive(;) - STDMETHOD(OpenSeq)(ISequentialInStream *stream); - STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); - - CHandler() { } -}; - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize -}; - -static const Byte kArcProps[] = -{ - kpidNumStreams, - kpidNumBlocks -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID /*propID*/, PROPVARIANT * /*value*/) -{ - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = 1; - return S_OK; -} - -STDMETHODIMP 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 = 4; - -API_FUNC_static_IsArc IsArc_zstd(const Byte *p, size_t size) -{ - if (size < 4) - return k_IsArc_Res_NEED_MORE; - - UInt32 magic = GetUi32(p); - - // skippable frames - if (magic >= 0x184D2A50 && magic <= 0x184D2A5F) { - if (size < 16) - return k_IsArc_Res_NEED_MORE; - magic = GetUi32(p+12); - } - -#ifdef ZSTD_LEGACY_SUPPORT - // zstd 0.1 - if (magic == 0xFD2FB51E) - return k_IsArc_Res_YES; - - // zstd magic's for 0.2 .. 0.8 (aka 1.x) - if (magic >= 0xFD2FB522 && magic <= 0xFD2FB528) - return k_IsArc_Res_YES; -#else - /* only version 1.x */ - if (magic == 0xFD2FB528) - return k_IsArc_Res_YES; -#endif - - return k_IsArc_Res_NO; -} -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) -{ - COM_TRY_BEGIN - Close(); - { - Byte buf[kSignatureCheckSize]; - RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize)); - if (IsArc_zstd(buf, kSignatureCheckSize) == k_IsArc_Res_NO) - return S_FALSE; - _isArc = true; - _stream = stream; - _seqStream = stream; - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - } - return S_OK; - COM_TRY_END -} - - -STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) -{ - Close(); - _isArc = true; - _seqStream = stream; - return S_OK; -} - -STDMETHODIMP CHandler::Close() -{ - _isArc = false; - _dataAfterEnd = false; - _needMoreInput = false; - - _packSize_Defined = false; - _unpackSize_Defined = false; - - _packSize = 0; - - _seqStream.Release(); - _stream.Release(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - if (_packSize_Defined) - extractCallback->SetTotal(_packSize); - - CMyComPtr 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); - - Int32 opRes; - - { - - NCompress::NZSTD::CDecoder *decoderSpec = new NCompress::NZSTD::CDecoder; - CMyComPtr decoder = decoderSpec; - decoderSpec->SetInStream(_seqStream); - - CDummyOutStream *outStreamSpec = new CDummyOutStream; - CMyComPtr outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(); - - realOutStream.Release(); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, true); - - UInt64 packSize = 0; - UInt64 unpackedSize = 0; - - HRESULT result = S_OK; - - for (;;) - { - lps->InSize = packSize; - lps->OutSize = unpackedSize; - - RINOK(lps->SetCur()); - result = decoderSpec->CodeResume(outStream, &unpackedSize, progress); - UInt64 streamSize = decoderSpec->GetInputProcessedSize(); - - if (result != S_FALSE && result != S_OK) - return result; - - if (unpackedSize == 0) - break; - - if (streamSize == packSize) - { - // no new bytes in input stream, So it's good end of archive. - result = S_OK; - break; - } - - if (packSize > streamSize) - return E_FAIL; - - if (result != S_OK) - break; - } - - decoderSpec->ReleaseInStream(); - outStream.Release(); - - if (!_isArc) - opRes = NExtract::NOperationResult::kIsNotArc; - else if (_needMoreInput) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - else if (_dataAfterEnd) - opRes = NExtract::NOperationResult::kDataAfterEnd; - else if (result == S_FALSE) - opRes = NExtract::NOperationResult::kDataError; - else if (result == S_OK) - opRes = NExtract::NOperationResult::kOK; - else - return result; - - } - - return extractCallback->SetOperationResult(opRes); - - COM_TRY_END -} - -static HRESULT UpdateArchive( - UInt64 unpackSize, - ISequentialOutStream *outStream, - const CProps &props, - IArchiveUpdateCallback *updateCallback) -{ - RINOK(updateCallback->SetTotal(unpackSize)); - CMyComPtr fileInStream; - RINOK(updateCallback->GetStream(0, &fileInStream)); - CLocalProgress *localProgressSpec = new CLocalProgress; - CMyComPtr localProgress = localProgressSpec; - localProgressSpec->Init(updateCallback, true); - NCompress::NZSTD::CEncoder *encoderSpec = new NCompress::NZSTD::CEncoder; - CMyComPtr encoder = encoderSpec; - RINOK(props.SetCoderProps(encoderSpec, NULL)); - RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); - return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); -} - -STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) -{ - *type = NFileTimeType::kUnix; - return S_OK; -} - -STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *updateCallback) -{ - COM_TRY_BEGIN - - if (numItems != 1) - return E_INVALIDARG; - - Int32 newData, newProps; - UInt32 indexInArchive; - if (!updateCallback) - return E_FAIL; - RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); - - if ((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 ((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(size, outStream, _props, updateCallback); - } - - if (indexInArchive != 0) - return E_INVALIDARG; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(updateCallback, true); - - CMyComPtr opCallback; - updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kInArcIndex, 0, - NUpdateNotifyOp::kReplicate)) - } - - if (_stream) - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - - return NCompress::CopyStream(_stream, outStream, progress); - - COM_TRY_END -} - -STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) -{ - return _props.SetProperties(names, values, numProps); -} - -static const Byte k_Signature[] = "0xFD2FB522..28"; - -REGISTER_ARC_IO( - "zstd", "zst tzstd", "* .tar", 0x0e, - k_Signature, - 0, - NArcInfoFlags::kKeepName, - IsArc_zstd) - -}} +// ZstdHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" +#include "../../Common/ComTry.h" +#include "../../Common/Defs.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/ZstdDecoder.h" +#include "../Compress/ZstdEncoder.h" +#include "../Compress/CopyCoder.h" + +#include "Common/DummyOutStream.h" +#include "Common/HandlerOut.h" + +using namespace NWindows; + +namespace NArchive { +namespace NZSTD { + +class CHandler: + public IInArchive, + public IArchiveOpenSeq, + public IOutArchive, + public ISetProperties, + public CMyUnknownImp +{ + CMyComPtr _stream; + CMyComPtr _seqStream; + + bool _isArc; + bool _dataAfterEnd; + bool _needMoreInput; + + bool _packSize_Defined; + bool _unpackSize_Defined; + + UInt64 _packSize; + UInt64 _unpackSize; + UInt64 _numStreams; + UInt64 _numBlocks; + + CSingleMethodProps _props; + +public: + MY_UNKNOWN_IMP4( + IInArchive, + IArchiveOpenSeq, + IOutArchive, + ISetProperties) + INTERFACE_IInArchive(;) + INTERFACE_IOutArchive(;) + STDMETHOD(OpenSeq)(ISequentialInStream *stream); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); + + CHandler() { } +}; + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidNumStreams, + kpidNumBlocks +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID /*propID*/, PROPVARIANT * /*value*/) +{ + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1; + return S_OK; +} + +STDMETHODIMP 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 = 4; + +API_FUNC_static_IsArc IsArc_zstd(const Byte *p, size_t size) +{ + if (size < 4) + return k_IsArc_Res_NEED_MORE; + + UInt32 magic = GetUi32(p); + + // skippable frames + if (magic >= 0x184D2A50 && magic <= 0x184D2A5F) { + if (size < 16) + return k_IsArc_Res_NEED_MORE; + magic = GetUi32(p+12); + } + +#ifdef ZSTD_LEGACY_SUPPORT + // zstd 0.1 + if (magic == 0xFD2FB51E) + return k_IsArc_Res_YES; + + // zstd magic's for 0.2 .. 0.8 (aka 1.x) + if (magic >= 0xFD2FB522 && magic <= 0xFD2FB528) + return k_IsArc_Res_YES; +#else + /* only version 1.x */ + if (magic == 0xFD2FB528) + return k_IsArc_Res_YES; +#endif + + return k_IsArc_Res_NO; +} +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) +{ + COM_TRY_BEGIN + Close(); + { + Byte buf[kSignatureCheckSize]; + RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize)); + if (IsArc_zstd(buf, kSignatureCheckSize) == k_IsArc_Res_NO) + return S_FALSE; + _isArc = true; + _stream = stream; + _seqStream = stream; + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); + } + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) +{ + Close(); + _isArc = true; + _seqStream = stream; + return S_OK; +} + +STDMETHODIMP CHandler::Close() +{ + _isArc = false; + _dataAfterEnd = false; + _needMoreInput = false; + + _packSize_Defined = false; + _unpackSize_Defined = false; + + _packSize = 0; + + _seqStream.Release(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + if (_packSize_Defined) + extractCallback->SetTotal(_packSize); + + CMyComPtr 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); + + Int32 opRes; + + { + + NCompress::NZSTD::CDecoder *decoderSpec = new NCompress::NZSTD::CDecoder; + CMyComPtr decoder = decoderSpec; + decoderSpec->SetInStream(_seqStream); + + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + + realOutStream.Release(); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, true); + + UInt64 packSize = 0; + UInt64 unpackedSize = 0; + + HRESULT result = S_OK; + + for (;;) + { + lps->InSize = packSize; + lps->OutSize = unpackedSize; + + RINOK(lps->SetCur()); + result = decoderSpec->CodeResume(outStream, &unpackedSize, progress); + UInt64 streamSize = decoderSpec->GetInputProcessedSize(); + + if (result != S_FALSE && result != S_OK) + return result; + + if (unpackedSize == 0) + break; + + if (streamSize == packSize) + { + // no new bytes in input stream, So it's good end of archive. + result = S_OK; + break; + } + + if (packSize > streamSize) + return E_FAIL; + + if (result != S_OK) + break; + } + + decoderSpec->ReleaseInStream(); + outStream.Release(); + + if (!_isArc) + opRes = NExtract::NOperationResult::kIsNotArc; + else if (_needMoreInput) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + else if (_dataAfterEnd) + opRes = NExtract::NOperationResult::kDataAfterEnd; + else if (result == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else if (result == S_OK) + opRes = NExtract::NOperationResult::kOK; + else + return result; + + } + + return extractCallback->SetOperationResult(opRes); + + COM_TRY_END +} + +static HRESULT UpdateArchive( + UInt64 unpackSize, + ISequentialOutStream *outStream, + const CProps &props, + IArchiveUpdateCallback *updateCallback) +{ + RINOK(updateCallback->SetTotal(unpackSize)); + CMyComPtr fileInStream; + RINOK(updateCallback->GetStream(0, &fileInStream)); + CLocalProgress *localProgressSpec = new CLocalProgress; + CMyComPtr localProgress = localProgressSpec; + localProgressSpec->Init(updateCallback, true); + NCompress::NZSTD::CEncoder *encoderSpec = new NCompress::NZSTD::CEncoder; + CMyComPtr encoder = encoderSpec; + RINOK(props.SetCoderProps(encoderSpec, NULL)); + RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); + return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); +} + +STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) +{ + *type = NFileTimeType::kUnix; + return S_OK; +} + +STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback) +{ + COM_TRY_BEGIN + + if (numItems != 1) + return E_INVALIDARG; + + Int32 newData, newProps; + UInt32 indexInArchive; + if (!updateCallback) + return E_FAIL; + RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); + + if ((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 ((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(size, outStream, _props, updateCallback); + } + + if (indexInArchive != 0) + return E_INVALIDARG; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(updateCallback, true); + + CMyComPtr opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, 0, + NUpdateNotifyOp::kReplicate)) + } + + if (_stream) + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); + + return NCompress::CopyStream(_stream, outStream, progress); + + COM_TRY_END +} + +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) +{ + return _props.SetProperties(names, values, numProps); +} + +static const Byte k_Signature[] = "0xFD2FB522..28"; + +REGISTER_ARC_IO( + "zstd", "zst tzstd", "* .tar", 0x0e, + k_Signature, + 0, + NArcInfoFlags::kKeepName, + IsArc_zstd) + +}} diff --git a/CPP/7zip/Archive/makefile b/CPP/7zip/Archive/makefile index 96d8d782d..7512ad568 100644 --- a/CPP/7zip/Archive/makefile +++ b/CPP/7zip/Archive/makefile @@ -1,23 +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" +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 3ad238a8e..c4073e890 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 index 6b0df241e..1a3a8739f 100644 --- a/CPP/7zip/Bundles/Alone/Alone.dsp +++ b/CPP/7zip/Bundles/Alone/Alone.dsp @@ -1,3076 +1,3076 @@ -# 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 /Gz /MT /W4 /WX /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "_MBCS" /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 -# 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 "_7ZIP_LARGE_PAGES" /D "SUPPORT_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" /D "EXCLUDE_COM" /D "NO_REGISTRY" /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 "_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\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 "EXCLUDE_COM" /D "NO_REGISTRY" /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 "_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\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\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\Sha1Reg.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\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\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 "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\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 "Compress" - -# PROP Default_Filter "" -# Begin Group "BZip2" - -# PROP Default_Filter "" -# 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\DeflateExtConst.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\PpmdContext.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdDecode.h -# End Source File -# 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\PpmdEncode.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\PpmdSubAlloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdType.h -# 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\ZipItemEx.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\LzHandler.cpp -# 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\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\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=..\..\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\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\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\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\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\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\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\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 -# Begin Source File - -SOURCE=..\..\..\..\C\Types.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 /Gz /MT /W4 /WX /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "_MBCS" /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 +# 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 "_7ZIP_LARGE_PAGES" /D "SUPPORT_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" /D "EXCLUDE_COM" /D "NO_REGISTRY" /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 "_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\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 "EXCLUDE_COM" /D "NO_REGISTRY" /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 "_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\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\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\Sha1Reg.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\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\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 "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\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 "Compress" + +# PROP Default_Filter "" +# Begin Group "BZip2" + +# PROP Default_Filter "" +# 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\DeflateExtConst.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\PpmdContext.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdDecode.h +# End Source File +# 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\PpmdEncode.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\PpmdSubAlloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdType.h +# 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\ZipItemEx.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\LzHandler.cpp +# 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\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\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=..\..\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\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\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\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\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\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\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\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 +# Begin Source File + +SOURCE=..\..\..\..\C\Types.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 index 036aab454..65eca43f6 100644 --- a/CPP/7zip/Bundles/Alone/Alone.dsw +++ b/CPP/7zip/Bundles/Alone/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/Alone/StdAfx.cpp b/CPP/7zip/Bundles/Alone/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Alone/StdAfx.cpp +++ b/CPP/7zip/Bundles/Alone/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Alone/StdAfx.h b/CPP/7zip/Bundles/Alone/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Bundles/Alone/StdAfx.h +++ b/CPP/7zip/Bundles/Alone/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Alone/afxres.h b/CPP/7zip/Bundles/Alone/afxres.h index f646cce4f..c2fadd4a5 100644 --- a/CPP/7zip/Bundles/Alone/afxres.h +++ b/CPP/7zip/Bundles/Alone/afxres.h @@ -1 +1 @@ -#include +#include diff --git a/CPP/7zip/Bundles/Alone/makefile b/CPP/7zip/Bundles/Alone/makefile index be894f354..33ce6b7d1 100644 --- a/CPP/7zip/Bundles/Alone/makefile +++ b/CPP/7zip/Bundles/Alone/makefile @@ -1,348 +1,348 @@ -PROG = 7za.exe -MY_CONSOLE = 1 -CFLAGS = $(CFLAGS) -DZSTD_MULTITHREAD - -!IFNDEF UNDER_CE -CFLAGS = $(CFLAGS) -DWIN_LONG_PATH -D_7ZIP_LARGE_PAGES -DSUPPORT_DEVICE_FILE -!ENDIF - -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\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\Synchronization.obj \ - $O\System.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\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\LzHandler.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\Sha1.obj \ - $O\Sha256.obj \ - $O\Sort.obj \ - $O\Threads.obj \ - $O\Xz.obj \ - $O\XzDec.obj \ - $O\XzEnc.obj \ - $O\XzIn.obj \ - -COMPRESS_OBJS = $(COMPRESS_OBJS) \ - $O\BrotliDecoder.obj \ - $O\BrotliEncoder.obj \ - $O\BrotliRegister.obj \ - $O\Lz4Decoder.obj \ - $O\Lz4Encoder.obj \ - $O\Lz4Register.obj \ - $O\LizardDecoder.obj \ - $O\LizardEncoder.obj \ - $O\LizardRegister.obj \ - $O\Lz5Decoder.obj \ - $O\Lz5Encoder.obj \ - $O\Lz5Register.obj \ - $O\ZstdDecoder.obj \ - $O\ZstdEncoder.obj \ - $O\ZstdRegister.obj \ - $O\FastLzma2Register.obj \ - -BROTLI_OBJS = \ - $O/br_backward_references.obj \ - $O/br_backward_references_hq.obj \ - $O/br_bit_cost.obj \ - $O/br_bit_reader.obj \ - $O/br_block_splitter.obj \ - $O/br_brotli_bit_stream.obj \ - $O/br_cluster.obj \ - $O/br_compress_fragment.obj \ - $O/br_compress_fragment_two_pass.obj \ - $O/br_decode.obj \ - $O/br_dictionary.obj \ - $O/br_dictionary_hash.obj \ - $O/br_encode.obj \ - $O/br_encoder_dict.obj \ - $O/br_entropy_encode.obj \ - $O/br_histogram.obj \ - $O/br_huffman.obj \ - $O/br_literal_cost.obj \ - $O/br_memory.obj \ - $O/br_metablock.obj \ - $O/br_state.obj \ - $O/br_static_dict.obj \ - $O/br_transform.obj \ - $O/br_utf8_util.obj \ - -LIZARD_OBJS = \ - $O/lizard_compress.obj \ - $O/lizard_decompress.obj \ - $O/lizard_frame.obj \ - -LZ4_OBJS = \ - $O\lz4.obj \ - $O\lz4frame.obj \ - $O\lz4hc.obj \ - -LZ5_OBJS = \ - $O\lz5.obj \ - $O\lz5frame.obj \ - $O\lz5hc.obj \ - -ZSTD_OBJS = \ - $O\debug.obj \ - $O\entropy_common.obj \ - $O\error_private.obj \ - $O\fse_compress.obj \ - $O\fse_decompress.obj \ - $O\hist.obj \ - $O\huf_compress.obj \ - $O\huf_decompress.obj \ - $O\pool.obj \ - $O\threading.obj \ - $O\xxhash.obj \ - $O\zstd_common.obj \ - $O\zstd_compress.obj \ - $O\zstd_compress_literals.obj \ - $O\zstd_compress_sequences.obj \ - $O\zstd_compress_superblock.obj \ - $O\zstd_ddict.obj \ - $O\zstd_decompress_block.obj \ - $O\zstd_decompress.obj \ - $O\zstd_double_fast.obj \ - $O\zstd_fast.obj \ - $O\zstd_lazy.obj \ - $O\zstd_ldm.obj \ - $O\zstdmt_compress.obj \ - $O\zstd_opt.obj \ - $O\zstd_v01.obj \ - $O\zstd_v02.obj \ - $O\zstd_v03.obj \ - $O\zstd_v04.obj \ - $O\zstd_v05.obj \ - $O\zstd_v06.obj \ - $O\zstd_v07.obj \ - -ZSTDMT_OBJS = \ - $O\brotli-mt_common.obj \ - $O\brotli-mt_compress.obj \ - $O\brotli-mt_decompress.obj \ - $O\lizard-mt_common.obj \ - $O\lizard-mt_compress.obj \ - $O\lizard-mt_decompress.obj \ - $O\lz4-mt_common.obj \ - $O\lz4-mt_compress.obj \ - $O\lz4-mt_decompress.obj \ - $O\lz5-mt_common.obj \ - $O\lz5-mt_compress.obj \ - $O\lz5-mt_decompress.obj \ - $O\zstd-mt_threading.obj \ - -FASTLZMA2_OBJS = \ - $O\dict_buffer.obj \ - $O\fl2_common.obj \ - $O\fl2_compress.obj \ - $O\fl2_pool.obj \ - $O\fl2_threading.obj \ - $O\lzma2_enc.obj \ - $O\radix_bitpack.obj \ - $O\radix_mf.obj \ - $O\radix_struct.obj \ - $O\range_enc.obj \ - $O\util.obj \ - -!include "../../UI/Console/Console.mak" - -!include "../../Aes.mak" -!include "../../Crc.mak" -!include "../../Crc64.mak" -!include "../../LzmaDec.mak" - -!include "../../7zip.mak" +PROG = 7za.exe +MY_CONSOLE = 1 +CFLAGS = $(CFLAGS) -DZSTD_MULTITHREAD + +!IFNDEF UNDER_CE +CFLAGS = $(CFLAGS) -DWIN_LONG_PATH -D_7ZIP_LARGE_PAGES -DSUPPORT_DEVICE_FILE +!ENDIF + +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\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\Synchronization.obj \ + $O\System.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\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\LzHandler.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\Sha1.obj \ + $O\Sha256.obj \ + $O\Sort.obj \ + $O\Threads.obj \ + $O\Xz.obj \ + $O\XzDec.obj \ + $O\XzEnc.obj \ + $O\XzIn.obj \ + +COMPRESS_OBJS = $(COMPRESS_OBJS) \ + $O\BrotliDecoder.obj \ + $O\BrotliEncoder.obj \ + $O\BrotliRegister.obj \ + $O\Lz4Decoder.obj \ + $O\Lz4Encoder.obj \ + $O\Lz4Register.obj \ + $O\LizardDecoder.obj \ + $O\LizardEncoder.obj \ + $O\LizardRegister.obj \ + $O\Lz5Decoder.obj \ + $O\Lz5Encoder.obj \ + $O\Lz5Register.obj \ + $O\ZstdDecoder.obj \ + $O\ZstdEncoder.obj \ + $O\ZstdRegister.obj \ + $O\FastLzma2Register.obj \ + +BROTLI_OBJS = \ + $O/br_backward_references.obj \ + $O/br_backward_references_hq.obj \ + $O/br_bit_cost.obj \ + $O/br_bit_reader.obj \ + $O/br_block_splitter.obj \ + $O/br_brotli_bit_stream.obj \ + $O/br_cluster.obj \ + $O/br_compress_fragment.obj \ + $O/br_compress_fragment_two_pass.obj \ + $O/br_decode.obj \ + $O/br_dictionary.obj \ + $O/br_dictionary_hash.obj \ + $O/br_encode.obj \ + $O/br_encoder_dict.obj \ + $O/br_entropy_encode.obj \ + $O/br_histogram.obj \ + $O/br_huffman.obj \ + $O/br_literal_cost.obj \ + $O/br_memory.obj \ + $O/br_metablock.obj \ + $O/br_state.obj \ + $O/br_static_dict.obj \ + $O/br_transform.obj \ + $O/br_utf8_util.obj \ + +LIZARD_OBJS = \ + $O/lizard_compress.obj \ + $O/lizard_decompress.obj \ + $O/lizard_frame.obj \ + +LZ4_OBJS = \ + $O\lz4.obj \ + $O\lz4frame.obj \ + $O\lz4hc.obj \ + +LZ5_OBJS = \ + $O\lz5.obj \ + $O\lz5frame.obj \ + $O\lz5hc.obj \ + +ZSTD_OBJS = \ + $O\debug.obj \ + $O\entropy_common.obj \ + $O\error_private.obj \ + $O\fse_compress.obj \ + $O\fse_decompress.obj \ + $O\hist.obj \ + $O\huf_compress.obj \ + $O\huf_decompress.obj \ + $O\pool.obj \ + $O\threading.obj \ + $O\xxhash.obj \ + $O\zstd_common.obj \ + $O\zstd_compress.obj \ + $O\zstd_compress_literals.obj \ + $O\zstd_compress_sequences.obj \ + $O\zstd_compress_superblock.obj \ + $O\zstd_ddict.obj \ + $O\zstd_decompress_block.obj \ + $O\zstd_decompress.obj \ + $O\zstd_double_fast.obj \ + $O\zstd_fast.obj \ + $O\zstd_lazy.obj \ + $O\zstd_ldm.obj \ + $O\zstdmt_compress.obj \ + $O\zstd_opt.obj \ + $O\zstd_v01.obj \ + $O\zstd_v02.obj \ + $O\zstd_v03.obj \ + $O\zstd_v04.obj \ + $O\zstd_v05.obj \ + $O\zstd_v06.obj \ + $O\zstd_v07.obj \ + +ZSTDMT_OBJS = \ + $O\brotli-mt_common.obj \ + $O\brotli-mt_compress.obj \ + $O\brotli-mt_decompress.obj \ + $O\lizard-mt_common.obj \ + $O\lizard-mt_compress.obj \ + $O\lizard-mt_decompress.obj \ + $O\lz4-mt_common.obj \ + $O\lz4-mt_compress.obj \ + $O\lz4-mt_decompress.obj \ + $O\lz5-mt_common.obj \ + $O\lz5-mt_compress.obj \ + $O\lz5-mt_decompress.obj \ + $O\zstd-mt_threading.obj \ + +FASTLZMA2_OBJS = \ + $O\dict_buffer.obj \ + $O\fl2_common.obj \ + $O\fl2_compress.obj \ + $O\fl2_pool.obj \ + $O\fl2_threading.obj \ + $O\lzma2_enc.obj \ + $O\radix_bitpack.obj \ + $O\radix_mf.obj \ + $O\radix_struct.obj \ + $O\range_enc.obj \ + $O\util.obj \ + +!include "../../UI/Console/Console.mak" + +!include "../../Aes.mak" +!include "../../Crc.mak" +!include "../../Crc64.mak" +!include "../../LzmaDec.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Alone/resource.rc b/CPP/7zip/Bundles/Alone/resource.rc index 9b6a30847..c85acaa9c 100644 --- a/CPP/7zip/Bundles/Alone/resource.rc +++ b/CPP/7zip/Bundles/Alone/resource.rc @@ -1,7 +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 +#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/Alone7z/Alone.dsp b/CPP/7zip/Bundles/Alone7z/Alone.dsp index e12207db3..bb7ca4c9c 100644 --- a/CPP/7zip/Bundles/Alone7z/Alone.dsp +++ b/CPP/7zip/Bundles/Alone7z/Alone.dsp @@ -1,1910 +1,1910 @@ -# 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 /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 diff --git a/CPP/7zip/Bundles/Alone7z/Alone.dsw b/CPP/7zip/Bundles/Alone7z/Alone.dsw index 036aab454..65eca43f6 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 c6d3b1fa6..d0feea85c 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 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Bundles/Alone7z/StdAfx.h +++ b/CPP/7zip/Bundles/Alone7z/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Alone7z/makefile b/CPP/7zip/Bundles/Alone7z/makefile index 4f23c10c1..10be3cfba 100644 --- a/CPP/7zip/Bundles/Alone7z/makefile +++ b/CPP/7zip/Bundles/Alone7z/makefile @@ -1,154 +1,154 @@ -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 +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" diff --git a/CPP/7zip/Bundles/Alone7z/resource.rc b/CPP/7zip/Bundles/Alone7z/resource.rc index 36d70e7d9..593785007 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/Codec_brotli/StdAfx.cpp b/CPP/7zip/Bundles/Codec_brotli/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Codec_brotli/StdAfx.cpp +++ b/CPP/7zip/Bundles/Codec_brotli/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Codec_brotli/StdAfx.h b/CPP/7zip/Bundles/Codec_brotli/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Bundles/Codec_brotli/StdAfx.h +++ b/CPP/7zip/Bundles/Codec_brotli/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Codec_brotli/makefile b/CPP/7zip/Bundles/Codec_brotli/makefile index f319fe15a..a456bb21a 100644 --- a/CPP/7zip/Bundles/Codec_brotli/makefile +++ b/CPP/7zip/Bundles/Codec_brotli/makefile @@ -1,56 +1,56 @@ -PROG = brotli.dll -DEF_FILE = ../../Compress/Codec.def -CFLAGS = $(CFLAGS) - -7ZIP_COMMON_OBJS = \ - $O\StreamUtils.obj \ - -WIN_OBJS = \ - $O\System.obj \ - -COMPRESS_OBJS = \ - $O\CodecExports.obj \ - $O\DllExportsCompress.obj \ - -C_OBJS = \ - $O\Alloc.obj \ - $O\Threads.obj \ - -COMPRESS_OBJS = $(COMPRESS_OBJS) \ - $O\BrotliDecoder.obj \ - $O\BrotliEncoder.obj \ - $O\BrotliRegister.obj \ - -BROTLI_OBJS = \ - $O/br_backward_references.obj \ - $O/br_backward_references_hq.obj \ - $O/br_bit_cost.obj \ - $O/br_bit_reader.obj \ - $O/br_block_splitter.obj \ - $O/br_brotli_bit_stream.obj \ - $O/br_cluster.obj \ - $O/br_compress_fragment.obj \ - $O/br_compress_fragment_two_pass.obj \ - $O/br_decode.obj \ - $O/br_dictionary.obj \ - $O/br_dictionary_hash.obj \ - $O/br_encode.obj \ - $O/br_encoder_dict.obj \ - $O/br_entropy_encode.obj \ - $O/br_histogram.obj \ - $O/br_huffman.obj \ - $O/br_literal_cost.obj \ - $O/br_memory.obj \ - $O/br_metablock.obj \ - $O/br_state.obj \ - $O/br_static_dict.obj \ - $O/br_transform.obj \ - $O/br_utf8_util.obj \ - -ZSTDMT_OBJS = \ - $O\brotli-mt_common.obj \ - $O\brotli-mt_compress.obj \ - $O\brotli-mt_decompress.obj \ - $O\zstd-mt_threading.obj \ - -!include "../../7zip.mak" +PROG = brotli.dll +DEF_FILE = ../../Compress/Codec.def +CFLAGS = $(CFLAGS) + +7ZIP_COMMON_OBJS = \ + $O\StreamUtils.obj \ + +WIN_OBJS = \ + $O\System.obj \ + +COMPRESS_OBJS = \ + $O\CodecExports.obj \ + $O\DllExportsCompress.obj \ + +C_OBJS = \ + $O\Alloc.obj \ + $O\Threads.obj \ + +COMPRESS_OBJS = $(COMPRESS_OBJS) \ + $O\BrotliDecoder.obj \ + $O\BrotliEncoder.obj \ + $O\BrotliRegister.obj \ + +BROTLI_OBJS = \ + $O/br_backward_references.obj \ + $O/br_backward_references_hq.obj \ + $O/br_bit_cost.obj \ + $O/br_bit_reader.obj \ + $O/br_block_splitter.obj \ + $O/br_brotli_bit_stream.obj \ + $O/br_cluster.obj \ + $O/br_compress_fragment.obj \ + $O/br_compress_fragment_two_pass.obj \ + $O/br_decode.obj \ + $O/br_dictionary.obj \ + $O/br_dictionary_hash.obj \ + $O/br_encode.obj \ + $O/br_encoder_dict.obj \ + $O/br_entropy_encode.obj \ + $O/br_histogram.obj \ + $O/br_huffman.obj \ + $O/br_literal_cost.obj \ + $O/br_memory.obj \ + $O/br_metablock.obj \ + $O/br_state.obj \ + $O/br_static_dict.obj \ + $O/br_transform.obj \ + $O/br_utf8_util.obj \ + +ZSTDMT_OBJS = \ + $O\brotli-mt_common.obj \ + $O\brotli-mt_compress.obj \ + $O\brotli-mt_decompress.obj \ + $O\zstd-mt_threading.obj \ + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Codec_brotli/resource.rc b/CPP/7zip/Bundles/Codec_brotli/resource.rc index a29be04ec..49aa0cb56 100644 --- a/CPP/7zip/Bundles/Codec_brotli/resource.rc +++ b/CPP/7zip/Bundles/Codec_brotli/resource.rc @@ -1,6 +1,6 @@ -#include "../../../../C/7zVersionTr.h" -#include "../../../../C/7zVersion.rc" - -MY_VERSION_INFO_DLL("7-Zip Brotli Plugin v1.0.7", "Brotli") - -101 ICON "../../Archive/Icons/7z.ico" +#include "../../../../C/7zVersionTr.h" +#include "../../../../C/7zVersion.rc" + +MY_VERSION_INFO_DLL("7-Zip Brotli Plugin v1.0.7", "Brotli") + +101 ICON "../../Archive/Icons/7z.ico" diff --git a/CPP/7zip/Bundles/Codec_lizard/StdAfx.cpp b/CPP/7zip/Bundles/Codec_lizard/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Codec_lizard/StdAfx.cpp +++ b/CPP/7zip/Bundles/Codec_lizard/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Codec_lizard/StdAfx.h b/CPP/7zip/Bundles/Codec_lizard/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Bundles/Codec_lizard/StdAfx.h +++ b/CPP/7zip/Bundles/Codec_lizard/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Codec_lizard/makefile b/CPP/7zip/Bundles/Codec_lizard/makefile index 093fb3ae1..657880b9b 100644 --- a/CPP/7zip/Bundles/Codec_lizard/makefile +++ b/CPP/7zip/Bundles/Codec_lizard/makefile @@ -1,46 +1,46 @@ -PROG = lizard.dll -DEF_FILE = ../../Compress/Codec.def -CFLAGS = $(CFLAGS) - -7ZIP_COMMON_OBJS = \ - $O\StreamUtils.obj \ - -WIN_OBJS = \ - $O\System.obj \ - -COMPRESS_OBJS = \ - $O\CodecExports.obj \ - $O\DllExportsCompress.obj \ - -C_OBJS = \ - $O\Alloc.obj \ - $O\Threads.obj \ - -COMPRESS_OBJS = $(COMPRESS_OBJS) \ - $O\LizardDecoder.obj \ - $O\LizardEncoder.obj \ - $O\LizardRegister.obj \ - -LIZARD_OBJS = \ - $O/lizard_compress.obj \ - $O/lizard_decompress.obj \ - $O/lizard_frame.obj \ - -ZSTD_OBJS = \ - $O\debug.obj \ - $O\entropy_common.obj \ - $O\error_private.obj \ - $O\fse_compress.obj \ - $O\fse_decompress.obj \ - $O\hist.obj \ - $O\huf_compress.obj \ - $O\huf_decompress.obj \ - $O\xxhash.obj \ - -ZSTDMT_OBJS = \ - $O\lizard-mt_common.obj \ - $O\lizard-mt_compress.obj \ - $O\lizard-mt_decompress.obj \ - $O\zstd-mt_threading.obj \ - -!include "../../7zip.mak" +PROG = lizard.dll +DEF_FILE = ../../Compress/Codec.def +CFLAGS = $(CFLAGS) + +7ZIP_COMMON_OBJS = \ + $O\StreamUtils.obj \ + +WIN_OBJS = \ + $O\System.obj \ + +COMPRESS_OBJS = \ + $O\CodecExports.obj \ + $O\DllExportsCompress.obj \ + +C_OBJS = \ + $O\Alloc.obj \ + $O\Threads.obj \ + +COMPRESS_OBJS = $(COMPRESS_OBJS) \ + $O\LizardDecoder.obj \ + $O\LizardEncoder.obj \ + $O\LizardRegister.obj \ + +LIZARD_OBJS = \ + $O/lizard_compress.obj \ + $O/lizard_decompress.obj \ + $O/lizard_frame.obj \ + +ZSTD_OBJS = \ + $O\debug.obj \ + $O\entropy_common.obj \ + $O\error_private.obj \ + $O\fse_compress.obj \ + $O\fse_decompress.obj \ + $O\hist.obj \ + $O\huf_compress.obj \ + $O\huf_decompress.obj \ + $O\xxhash.obj \ + +ZSTDMT_OBJS = \ + $O\lizard-mt_common.obj \ + $O\lizard-mt_compress.obj \ + $O\lizard-mt_decompress.obj \ + $O\zstd-mt_threading.obj \ + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Codec_lizard/resource.rc b/CPP/7zip/Bundles/Codec_lizard/resource.rc index 79afb0bf0..0d98cc682 100644 --- a/CPP/7zip/Bundles/Codec_lizard/resource.rc +++ b/CPP/7zip/Bundles/Codec_lizard/resource.rc @@ -1,6 +1,6 @@ -#include "../../../../C/7zVersionTr.h" -#include "../../../../C/7zVersion.rc" - -MY_VERSION_INFO_DLL("7-Zip Lizard Plugin v1.0", "Lizard") - -101 ICON "../../Archive/Icons/liz.ico" +#include "../../../../C/7zVersionTr.h" +#include "../../../../C/7zVersion.rc" + +MY_VERSION_INFO_DLL("7-Zip Lizard Plugin v1.0", "Lizard") + +101 ICON "../../Archive/Icons/liz.ico" diff --git a/CPP/7zip/Bundles/Codec_lz4/StdAfx.cpp b/CPP/7zip/Bundles/Codec_lz4/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Codec_lz4/StdAfx.cpp +++ b/CPP/7zip/Bundles/Codec_lz4/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Codec_lz4/StdAfx.h b/CPP/7zip/Bundles/Codec_lz4/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Bundles/Codec_lz4/StdAfx.h +++ b/CPP/7zip/Bundles/Codec_lz4/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Codec_lz4/makefile b/CPP/7zip/Bundles/Codec_lz4/makefile index 1f339bec0..983447403 100644 --- a/CPP/7zip/Bundles/Codec_lz4/makefile +++ b/CPP/7zip/Bundles/Codec_lz4/makefile @@ -1,38 +1,38 @@ -PROG = lz4.dll -DEF_FILE = ../../Compress/Codec.def -CFLAGS = $(CFLAGS) - -7ZIP_COMMON_OBJS = \ - $O\StreamUtils.obj \ - -WIN_OBJS = \ - $O\System.obj \ - -COMPRESS_OBJS = \ - $O\CodecExports.obj \ - $O\DllExportsCompress.obj \ - -C_OBJS = \ - $O\Alloc.obj \ - $O\Threads.obj \ - -COMPRESS_OBJS = $(COMPRESS_OBJS) \ - $O\Lz4Decoder.obj \ - $O\Lz4Encoder.obj \ - $O\Lz4Register.obj \ - -LZ4_OBJS = \ - $O\lz4.obj \ - $O\lz4frame.obj \ - $O\lz4hc.obj \ - -ZSTD_OBJS = \ - $O\xxhash.obj \ - -ZSTDMT_OBJS = \ - $O\lz4-mt_common.obj \ - $O\lz4-mt_compress.obj \ - $O\lz4-mt_decompress.obj \ - $O\zstd-mt_threading.obj \ - -!include "../../7zip.mak" +PROG = lz4.dll +DEF_FILE = ../../Compress/Codec.def +CFLAGS = $(CFLAGS) + +7ZIP_COMMON_OBJS = \ + $O\StreamUtils.obj \ + +WIN_OBJS = \ + $O\System.obj \ + +COMPRESS_OBJS = \ + $O\CodecExports.obj \ + $O\DllExportsCompress.obj \ + +C_OBJS = \ + $O\Alloc.obj \ + $O\Threads.obj \ + +COMPRESS_OBJS = $(COMPRESS_OBJS) \ + $O\Lz4Decoder.obj \ + $O\Lz4Encoder.obj \ + $O\Lz4Register.obj \ + +LZ4_OBJS = \ + $O\lz4.obj \ + $O\lz4frame.obj \ + $O\lz4hc.obj \ + +ZSTD_OBJS = \ + $O\xxhash.obj \ + +ZSTDMT_OBJS = \ + $O\lz4-mt_common.obj \ + $O\lz4-mt_compress.obj \ + $O\lz4-mt_decompress.obj \ + $O\zstd-mt_threading.obj \ + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Codec_lz4/resource.rc b/CPP/7zip/Bundles/Codec_lz4/resource.rc index ae53b483d..02dd1dc60 100644 --- a/CPP/7zip/Bundles/Codec_lz4/resource.rc +++ b/CPP/7zip/Bundles/Codec_lz4/resource.rc @@ -1,6 +1,6 @@ -#include "../../../../C/7zVersionTr.h" -#include "../../../../C/7zVersion.rc" - -MY_VERSION_INFO_DLL("7-Zip LZ4 Plugin v1.9.2", "Lz4") - -101 ICON "../../Archive/Icons/lz4.ico" +#include "../../../../C/7zVersionTr.h" +#include "../../../../C/7zVersion.rc" + +MY_VERSION_INFO_DLL("7-Zip LZ4 Plugin v1.9.2", "Lz4") + +101 ICON "../../Archive/Icons/lz4.ico" diff --git a/CPP/7zip/Bundles/Codec_lz5/StdAfx.cpp b/CPP/7zip/Bundles/Codec_lz5/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Codec_lz5/StdAfx.cpp +++ b/CPP/7zip/Bundles/Codec_lz5/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Codec_lz5/StdAfx.h b/CPP/7zip/Bundles/Codec_lz5/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Bundles/Codec_lz5/StdAfx.h +++ b/CPP/7zip/Bundles/Codec_lz5/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Codec_lz5/makefile b/CPP/7zip/Bundles/Codec_lz5/makefile index 68450a85c..ad1b97f3d 100644 --- a/CPP/7zip/Bundles/Codec_lz5/makefile +++ b/CPP/7zip/Bundles/Codec_lz5/makefile @@ -1,38 +1,38 @@ -PROG = lz5.dll -DEF_FILE = ../../Compress/Codec.def -CFLAGS = $(CFLAGS) - -7ZIP_COMMON_OBJS = \ - $O\StreamUtils.obj \ - -WIN_OBJS = \ - $O\System.obj \ - -COMPRESS_OBJS = \ - $O\CodecExports.obj \ - $O\DllExportsCompress.obj \ - -C_OBJS = \ - $O\Alloc.obj \ - $O\Threads.obj \ - -COMPRESS_OBJS = $(COMPRESS_OBJS) \ - $O\Lz5Decoder.obj \ - $O\Lz5Encoder.obj \ - $O\Lz5Register.obj \ - -LZ5_OBJS = \ - $O\lz5.obj \ - $O\lz5frame.obj \ - $O\lz5hc.obj \ - -ZSTD_OBJS = \ - $O\xxhash.obj \ - -ZSTDMT_OBJS = \ - $O\lz5-mt_common.obj \ - $O\lz5-mt_compress.obj \ - $O\lz5-mt_decompress.obj \ - $O\zstd-mt_threading.obj \ - -!include "../../7zip.mak" +PROG = lz5.dll +DEF_FILE = ../../Compress/Codec.def +CFLAGS = $(CFLAGS) + +7ZIP_COMMON_OBJS = \ + $O\StreamUtils.obj \ + +WIN_OBJS = \ + $O\System.obj \ + +COMPRESS_OBJS = \ + $O\CodecExports.obj \ + $O\DllExportsCompress.obj \ + +C_OBJS = \ + $O\Alloc.obj \ + $O\Threads.obj \ + +COMPRESS_OBJS = $(COMPRESS_OBJS) \ + $O\Lz5Decoder.obj \ + $O\Lz5Encoder.obj \ + $O\Lz5Register.obj \ + +LZ5_OBJS = \ + $O\lz5.obj \ + $O\lz5frame.obj \ + $O\lz5hc.obj \ + +ZSTD_OBJS = \ + $O\xxhash.obj \ + +ZSTDMT_OBJS = \ + $O\lz5-mt_common.obj \ + $O\lz5-mt_compress.obj \ + $O\lz5-mt_decompress.obj \ + $O\zstd-mt_threading.obj \ + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Codec_lz5/resource.rc b/CPP/7zip/Bundles/Codec_lz5/resource.rc index 27467f1ee..7310d728f 100644 --- a/CPP/7zip/Bundles/Codec_lz5/resource.rc +++ b/CPP/7zip/Bundles/Codec_lz5/resource.rc @@ -1,6 +1,6 @@ -#include "../../../../C/7zVersionTr.h" -#include "../../../../C/7zVersion.rc" - -MY_VERSION_INFO_DLL("7-Zip LZ5 Plugin v1.5", "Lz5") - -101 ICON "../../Archive/Icons/lz5.ico" +#include "../../../../C/7zVersionTr.h" +#include "../../../../C/7zVersion.rc" + +MY_VERSION_INFO_DLL("7-Zip LZ5 Plugin v1.5", "Lz5") + +101 ICON "../../Archive/Icons/lz5.ico" diff --git a/CPP/7zip/Bundles/Codec_zstd/StdAfx.cpp b/CPP/7zip/Bundles/Codec_zstd/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Codec_zstd/StdAfx.cpp +++ b/CPP/7zip/Bundles/Codec_zstd/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Codec_zstd/StdAfx.h b/CPP/7zip/Bundles/Codec_zstd/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Bundles/Codec_zstd/StdAfx.h +++ b/CPP/7zip/Bundles/Codec_zstd/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Codec_zstd/makefile b/CPP/7zip/Bundles/Codec_zstd/makefile index dc54eaa60..1345fd6e2 100644 --- a/CPP/7zip/Bundles/Codec_zstd/makefile +++ b/CPP/7zip/Bundles/Codec_zstd/makefile @@ -1,61 +1,61 @@ -PROG = zstd.dll -DEF_FILE = ../../Compress/Codec.def -CFLAGS = $(CFLAGS) -DZSTD_LEGACY_SUPPORT -DZSTD_MULTITHREAD - -7ZIP_COMMON_OBJS = \ - $O\StreamUtils.obj \ - -WIN_OBJS = \ - $O\System.obj \ - -COMPRESS_OBJS = \ - $O\CodecExports.obj \ - $O\DllExportsCompress.obj \ - -C_OBJS = \ - $O\Alloc.obj \ - $O\Threads.obj \ - -COMPRESS_OBJS = $(COMPRESS_OBJS) \ - $O\ZstdDecoder.obj \ - $O\ZstdEncoder.obj \ - $O\ZstdRegister.obj \ - -ZSTD_OBJS = \ - $O\debug.obj \ - $O\entropy_common.obj \ - $O\error_private.obj \ - $O\fse_compress.obj \ - $O\fse_decompress.obj \ - $O\hist.obj \ - $O\huf_compress.obj \ - $O\huf_decompress.obj \ - $O\pool.obj \ - $O\threading.obj \ - $O\xxhash.obj \ - $O\zstd_common.obj \ - $O\zstd_compress.obj \ - $O\zstd_compress_literals.obj \ - $O\zstd_compress_sequences.obj \ - $O\zstd_compress_superblock.obj \ - $O\zstd_ddict.obj \ - $O\zstd_decompress_block.obj \ - $O\zstd_decompress.obj \ - $O\zstd_double_fast.obj \ - $O\zstd_fast.obj \ - $O\zstd_lazy.obj \ - $O\zstd_ldm.obj \ - $O\zstdmt_compress.obj \ - $O\zstd_opt.obj \ - $O\zstd_v01.obj \ - $O\zstd_v02.obj \ - $O\zstd_v03.obj \ - $O\zstd_v04.obj \ - $O\zstd_v05.obj \ - $O\zstd_v06.obj \ - $O\zstd_v07.obj \ - -ZSTDMT_OBJS = \ - $O\zstd-mt_threading.obj \ - -!include "../../7zip.mak" +PROG = zstd.dll +DEF_FILE = ../../Compress/Codec.def +CFLAGS = $(CFLAGS) -DZSTD_LEGACY_SUPPORT -DZSTD_MULTITHREAD + +7ZIP_COMMON_OBJS = \ + $O\StreamUtils.obj \ + +WIN_OBJS = \ + $O\System.obj \ + +COMPRESS_OBJS = \ + $O\CodecExports.obj \ + $O\DllExportsCompress.obj \ + +C_OBJS = \ + $O\Alloc.obj \ + $O\Threads.obj \ + +COMPRESS_OBJS = $(COMPRESS_OBJS) \ + $O\ZstdDecoder.obj \ + $O\ZstdEncoder.obj \ + $O\ZstdRegister.obj \ + +ZSTD_OBJS = \ + $O\debug.obj \ + $O\entropy_common.obj \ + $O\error_private.obj \ + $O\fse_compress.obj \ + $O\fse_decompress.obj \ + $O\hist.obj \ + $O\huf_compress.obj \ + $O\huf_decompress.obj \ + $O\pool.obj \ + $O\threading.obj \ + $O\xxhash.obj \ + $O\zstd_common.obj \ + $O\zstd_compress.obj \ + $O\zstd_compress_literals.obj \ + $O\zstd_compress_sequences.obj \ + $O\zstd_compress_superblock.obj \ + $O\zstd_ddict.obj \ + $O\zstd_decompress_block.obj \ + $O\zstd_decompress.obj \ + $O\zstd_double_fast.obj \ + $O\zstd_fast.obj \ + $O\zstd_lazy.obj \ + $O\zstd_ldm.obj \ + $O\zstdmt_compress.obj \ + $O\zstd_opt.obj \ + $O\zstd_v01.obj \ + $O\zstd_v02.obj \ + $O\zstd_v03.obj \ + $O\zstd_v04.obj \ + $O\zstd_v05.obj \ + $O\zstd_v06.obj \ + $O\zstd_v07.obj \ + +ZSTDMT_OBJS = \ + $O\zstd-mt_threading.obj \ + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Codec_zstd/resource.rc b/CPP/7zip/Bundles/Codec_zstd/resource.rc index 26383b9b7..45c950191 100644 --- a/CPP/7zip/Bundles/Codec_zstd/resource.rc +++ b/CPP/7zip/Bundles/Codec_zstd/resource.rc @@ -1,6 +1,6 @@ -#include "../../../../C/7zVersionTr.h" -#include "../../../../C/7zVersion.rc" - -MY_VERSION_INFO_DLL("7-Zip ZS Plugin v1.4.5", "zstd") - -101 ICON "../../Archive/Icons/zst.ico" +#include "../../../../C/7zVersionTr.h" +#include "../../../../C/7zVersion.rc" + +MY_VERSION_INFO_DLL("7-Zip ZS Plugin v1.4.5", "zstd") + +101 ICON "../../Archive/Icons/zst.ico" diff --git a/CPP/7zip/Bundles/Fm/FM.dsp b/CPP/7zip/Bundles/Fm/FM.dsp index ff6208f99..03fbb50ef 100644 --- a/CPP/7zip/Bundles/Fm/FM.dsp +++ b/CPP/7zip/Bundles/Fm/FM.dsp @@ -1,2152 +1,2152 @@ -# 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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS_2" /D "SUPPORT_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:\Program Files\7-ZIP\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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS_2" /D "SUPPORT_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:\Program Files\7-ZIP\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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS_2" /D "SUPPORT_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:\Program Files\7-ZIP\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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS_2" /D "SUPPORT_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:\Program Files\7-ZIP\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 -# 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\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\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\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\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\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\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\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\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\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\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\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 -# 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 +# 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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS_2" /D "SUPPORT_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:\Program Files\7-ZIP\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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS_2" /D "SUPPORT_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:\Program Files\7-ZIP\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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS_2" /D "SUPPORT_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:\Program Files\7-ZIP\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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS_2" /D "SUPPORT_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:\Program Files\7-ZIP\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 +# 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\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\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\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\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\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\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\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\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\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\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\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 +# 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 index 38f65d224..1c955d956 100644 --- a/CPP/7zip/Bundles/Fm/FM.dsw +++ b/CPP/7zip/Bundles/Fm/FM.dsw @@ -1,29 +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> -{{{ -}}} - -############################################################################### - +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 index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Fm/StdAfx.cpp +++ b/CPP/7zip/Bundles/Fm/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Fm/StdAfx.h b/CPP/7zip/Bundles/Fm/StdAfx.h index 5815991f7..d2301e48e 100644 --- a/CPP/7zip/Bundles/Fm/StdAfx.h +++ b/CPP/7zip/Bundles/Fm/StdAfx.h @@ -1,16 +1,16 @@ -// stdafx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -// #define _WIN32_WINNT 0x0400 -#define _WIN32_WINNT 0x0500 -#define WINVER _WIN32_WINNT - -#include "../../../Common/Common.h" - -#include -#include -#include - -#endif +// stdafx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +// #define _WIN32_WINNT 0x0400 +#define _WIN32_WINNT 0x0500 +#define WINVER _WIN32_WINNT + +#include "../../../Common/Common.h" + +#include +#include +#include + +#endif diff --git a/CPP/7zip/Bundles/Fm/makefile b/CPP/7zip/Bundles/Fm/makefile index b89d2f8fa..8da34edb8 100644 --- a/CPP/7zip/Bundles/Fm/makefile +++ b/CPP/7zip/Bundles/Fm/makefile @@ -1,81 +1,81 @@ -PROG = 7zFM.exe - -!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\PropVariantConv.obj \ - $O\Registry.obj \ - $O\ResourceString.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 \ - -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" +PROG = 7zFM.exe + +!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\PropVariantConv.obj \ + $O\Registry.obj \ + $O\ResourceString.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 \ + +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 index eddbb6f85..60b465cc2 100644 --- a/CPP/7zip/Bundles/Fm/resource.rc +++ b/CPP/7zip/Bundles/Fm/resource.rc @@ -1,7 +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 lz tlz lz4 tlz4 lz5 tlz5 lzh lha rpm deb arj vhd wim swm fat ntfs dmg hfs xar squashfs zst" -END +#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 lz tlz lz4 tlz4 lz5 tlz5 lzh lha rpm deb arj vhd wim swm fat ntfs dmg hfs xar squashfs zst" +END diff --git a/CPP/7zip/Bundles/Format7z/StdAfx.cpp b/CPP/7zip/Bundles/Format7z/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Format7z/StdAfx.cpp +++ b/CPP/7zip/Bundles/Format7z/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Format7z/StdAfx.h b/CPP/7zip/Bundles/Format7z/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Bundles/Format7z/StdAfx.h +++ b/CPP/7zip/Bundles/Format7z/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Format7z/makefile b/CPP/7zip/Bundles/Format7z/makefile index 380f0a8dc..4b9eb2b10 100644 --- a/CPP/7zip/Bundles/Format7z/makefile +++ b/CPP/7zip/Bundles/Format7z/makefile @@ -1,266 +1,266 @@ -PROG = 7za.dll -DEF_FILE = ../../Archive/Archive2.def -CFLAGS = $(CFLAGS) -DZSTD_LEGACY_SUPPORT -DZSTD_MULTITHREAD - -COMMON_OBJS = \ - $O\CRC.obj \ - $O\CrcReg.obj \ - $O\IntToString.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\BZip2Encoder.obj \ - $O\BZip2Register.obj \ - $O\CopyCoder.obj \ - $O\CopyRegister.obj \ - $O\DeflateDecoder.obj \ - $O\DeflateEncoder.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\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\Sha256.obj \ - $O\Sort.obj \ - $O\Threads.obj \ - -!include "../../Aes.mak" -!include "../../Crc.mak" -!include "../../LzmaDec.mak" - -COMPRESS_OBJS = $(COMPRESS_OBJS) \ - $O\BrotliDecoder.obj \ - $O\BrotliEncoder.obj \ - $O\BrotliRegister.obj \ - $O\Lz4Decoder.obj \ - $O\Lz4Encoder.obj \ - $O\Lz4Register.obj \ - $O\LizardDecoder.obj \ - $O\LizardEncoder.obj \ - $O\LizardRegister.obj \ - $O\Lz5Decoder.obj \ - $O\Lz5Encoder.obj \ - $O\Lz5Register.obj \ - $O\ZstdDecoder.obj \ - $O\ZstdEncoder.obj \ - $O\ZstdRegister.obj \ - $O\FastLzma2Register.obj \ - -BROTLI_OBJS = \ - $O/br_backward_references.obj \ - $O/br_backward_references_hq.obj \ - $O/br_bit_cost.obj \ - $O/br_bit_reader.obj \ - $O/br_block_splitter.obj \ - $O/br_brotli_bit_stream.obj \ - $O/br_cluster.obj \ - $O/br_compress_fragment.obj \ - $O/br_compress_fragment_two_pass.obj \ - $O/br_decode.obj \ - $O/br_dictionary.obj \ - $O/br_dictionary_hash.obj \ - $O/br_encode.obj \ - $O/br_encoder_dict.obj \ - $O/br_entropy_encode.obj \ - $O/br_histogram.obj \ - $O/br_huffman.obj \ - $O/br_literal_cost.obj \ - $O/br_memory.obj \ - $O/br_metablock.obj \ - $O/br_state.obj \ - $O/br_static_dict.obj \ - $O/br_transform.obj \ - $O/br_utf8_util.obj \ - -LIZARD_OBJS = \ - $O/lizard_compress.obj \ - $O/lizard_decompress.obj \ - $O/lizard_frame.obj \ - -LZ4_OBJS = \ - $O\lz4.obj \ - $O\lz4frame.obj \ - $O\lz4hc.obj \ - -LZ5_OBJS = \ - $O\lz5.obj \ - $O\lz5frame.obj \ - $O\lz5hc.obj \ - -ZSTD_OBJS = \ - $O\debug.obj \ - $O\entropy_common.obj \ - $O\error_private.obj \ - $O\fse_compress.obj \ - $O\fse_decompress.obj \ - $O\hist.obj \ - $O\huf_compress.obj \ - $O\huf_decompress.obj \ - $O\pool.obj \ - $O\threading.obj \ - $O\xxhash.obj \ - $O\zstd_common.obj \ - $O\zstd_compress.obj \ - $O\zstd_compress_literals.obj \ - $O\zstd_compress_sequences.obj \ - $O\zstd_compress_superblock.obj \ - $O\zstd_ddict.obj \ - $O\zstd_decompress_block.obj \ - $O\zstd_decompress.obj \ - $O\zstd_double_fast.obj \ - $O\zstd_fast.obj \ - $O\zstd_lazy.obj \ - $O\zstd_ldm.obj \ - $O\zstdmt_compress.obj \ - $O\zstd_opt.obj \ - $O\zstd_v01.obj \ - $O\zstd_v02.obj \ - $O\zstd_v03.obj \ - $O\zstd_v04.obj \ - $O\zstd_v05.obj \ - $O\zstd_v06.obj \ - $O\zstd_v07.obj \ - -ZSTDMT_OBJS = \ - $O\brotli-mt_common.obj \ - $O\brotli-mt_compress.obj \ - $O\brotli-mt_decompress.obj \ - $O\lizard-mt_common.obj \ - $O\lizard-mt_compress.obj \ - $O\lizard-mt_decompress.obj \ - $O\lz4-mt_common.obj \ - $O\lz4-mt_compress.obj \ - $O\lz4-mt_decompress.obj \ - $O\lz5-mt_common.obj \ - $O\lz5-mt_compress.obj \ - $O\lz5-mt_decompress.obj \ - $O\zstd-mt_threading.obj \ - -FASTLZMA2_OBJS = \ - $O\dict_buffer.obj \ - $O\fl2_common.obj \ - $O\fl2_compress.obj \ - $O\fl2_pool.obj \ - $O\fl2_threading.obj \ - $O\lzma2_enc.obj \ - $O\radix_bitpack.obj \ - $O\radix_mf.obj \ - $O\radix_struct.obj \ - $O\range_enc.obj \ - $O\util.obj \ - - - -!include "../../7zip.mak" +PROG = 7za.dll +DEF_FILE = ../../Archive/Archive2.def +CFLAGS = $(CFLAGS) -DZSTD_LEGACY_SUPPORT -DZSTD_MULTITHREAD + +COMMON_OBJS = \ + $O\CRC.obj \ + $O\CrcReg.obj \ + $O\IntToString.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\BZip2Encoder.obj \ + $O\BZip2Register.obj \ + $O\CopyCoder.obj \ + $O\CopyRegister.obj \ + $O\DeflateDecoder.obj \ + $O\DeflateEncoder.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\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\Sha256.obj \ + $O\Sort.obj \ + $O\Threads.obj \ + +!include "../../Aes.mak" +!include "../../Crc.mak" +!include "../../LzmaDec.mak" + +COMPRESS_OBJS = $(COMPRESS_OBJS) \ + $O\BrotliDecoder.obj \ + $O\BrotliEncoder.obj \ + $O\BrotliRegister.obj \ + $O\Lz4Decoder.obj \ + $O\Lz4Encoder.obj \ + $O\Lz4Register.obj \ + $O\LizardDecoder.obj \ + $O\LizardEncoder.obj \ + $O\LizardRegister.obj \ + $O\Lz5Decoder.obj \ + $O\Lz5Encoder.obj \ + $O\Lz5Register.obj \ + $O\ZstdDecoder.obj \ + $O\ZstdEncoder.obj \ + $O\ZstdRegister.obj \ + $O\FastLzma2Register.obj \ + +BROTLI_OBJS = \ + $O/br_backward_references.obj \ + $O/br_backward_references_hq.obj \ + $O/br_bit_cost.obj \ + $O/br_bit_reader.obj \ + $O/br_block_splitter.obj \ + $O/br_brotli_bit_stream.obj \ + $O/br_cluster.obj \ + $O/br_compress_fragment.obj \ + $O/br_compress_fragment_two_pass.obj \ + $O/br_decode.obj \ + $O/br_dictionary.obj \ + $O/br_dictionary_hash.obj \ + $O/br_encode.obj \ + $O/br_encoder_dict.obj \ + $O/br_entropy_encode.obj \ + $O/br_histogram.obj \ + $O/br_huffman.obj \ + $O/br_literal_cost.obj \ + $O/br_memory.obj \ + $O/br_metablock.obj \ + $O/br_state.obj \ + $O/br_static_dict.obj \ + $O/br_transform.obj \ + $O/br_utf8_util.obj \ + +LIZARD_OBJS = \ + $O/lizard_compress.obj \ + $O/lizard_decompress.obj \ + $O/lizard_frame.obj \ + +LZ4_OBJS = \ + $O\lz4.obj \ + $O\lz4frame.obj \ + $O\lz4hc.obj \ + +LZ5_OBJS = \ + $O\lz5.obj \ + $O\lz5frame.obj \ + $O\lz5hc.obj \ + +ZSTD_OBJS = \ + $O\debug.obj \ + $O\entropy_common.obj \ + $O\error_private.obj \ + $O\fse_compress.obj \ + $O\fse_decompress.obj \ + $O\hist.obj \ + $O\huf_compress.obj \ + $O\huf_decompress.obj \ + $O\pool.obj \ + $O\threading.obj \ + $O\xxhash.obj \ + $O\zstd_common.obj \ + $O\zstd_compress.obj \ + $O\zstd_compress_literals.obj \ + $O\zstd_compress_sequences.obj \ + $O\zstd_compress_superblock.obj \ + $O\zstd_ddict.obj \ + $O\zstd_decompress_block.obj \ + $O\zstd_decompress.obj \ + $O\zstd_double_fast.obj \ + $O\zstd_fast.obj \ + $O\zstd_lazy.obj \ + $O\zstd_ldm.obj \ + $O\zstdmt_compress.obj \ + $O\zstd_opt.obj \ + $O\zstd_v01.obj \ + $O\zstd_v02.obj \ + $O\zstd_v03.obj \ + $O\zstd_v04.obj \ + $O\zstd_v05.obj \ + $O\zstd_v06.obj \ + $O\zstd_v07.obj \ + +ZSTDMT_OBJS = \ + $O\brotli-mt_common.obj \ + $O\brotli-mt_compress.obj \ + $O\brotli-mt_decompress.obj \ + $O\lizard-mt_common.obj \ + $O\lizard-mt_compress.obj \ + $O\lizard-mt_decompress.obj \ + $O\lz4-mt_common.obj \ + $O\lz4-mt_compress.obj \ + $O\lz4-mt_decompress.obj \ + $O\lz5-mt_common.obj \ + $O\lz5-mt_compress.obj \ + $O\lz5-mt_decompress.obj \ + $O\zstd-mt_threading.obj \ + +FASTLZMA2_OBJS = \ + $O\dict_buffer.obj \ + $O\fl2_common.obj \ + $O\fl2_compress.obj \ + $O\fl2_pool.obj \ + $O\fl2_threading.obj \ + $O\lzma2_enc.obj \ + $O\radix_bitpack.obj \ + $O\radix_mf.obj \ + $O\radix_struct.obj \ + $O\range_enc.obj \ + $O\util.obj \ + + + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Format7z/resource.rc b/CPP/7zip/Bundles/Format7z/resource.rc index 53d6be065..2f2b42aee 100644 --- a/CPP/7zip/Bundles/Format7z/resource.rc +++ b/CPP/7zip/Bundles/Format7z/resource.rc @@ -1,5 +1,5 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_DLL("7z Standalone Plugin", "7za") - -101 ICON "../../Archive/Icons/7z.ico" +#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 index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Format7zExtract/StdAfx.cpp +++ b/CPP/7zip/Bundles/Format7zExtract/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Format7zExtract/StdAfx.h b/CPP/7zip/Bundles/Format7zExtract/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Bundles/Format7zExtract/StdAfx.h +++ b/CPP/7zip/Bundles/Format7zExtract/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Format7zExtract/makefile b/CPP/7zip/Bundles/Format7zExtract/makefile index 2cccc1453..549604757 100644 --- a/CPP/7zip/Bundles/Format7zExtract/makefile +++ b/CPP/7zip/Bundles/Format7zExtract/makefile @@ -1,211 +1,211 @@ -PROG = 7zxa.dll -DEF_FILE = ../../Archive/Archive2.def -CFLAGS = $(CFLAGS) -DEXTRACT_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\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\Sha256.obj \ - $O\Threads.obj \ - -COMPRESS_OBJS = $(COMPRESS_OBJS) \ - $O\BrotliDecoder.obj \ - $O\BrotliRegister.obj \ - $O\Lz4Decoder.obj \ - $O\Lz4Register.obj \ - $O\LizardDecoder.obj \ - $O\LizardRegister.obj \ - $O\Lz5Decoder.obj \ - $O\Lz5Register.obj \ - $O\ZstdDecoder.obj \ - $O\ZstdRegister.obj \ - -BROTLI_OBJS = \ - $O/br_backward_references.obj \ - $O/br_backward_references_hq.obj \ - $O/br_bit_cost.obj \ - $O/br_bit_reader.obj \ - $O/br_block_splitter.obj \ - $O/br_brotli_bit_stream.obj \ - $O/br_cluster.obj \ - $O/br_compress_fragment.obj \ - $O/br_compress_fragment_two_pass.obj \ - $O/br_decode.obj \ - $O/br_dictionary.obj \ - $O/br_dictionary_hash.obj \ - $O/br_encode.obj \ - $O/br_encoder_dict.obj \ - $O/br_entropy_encode.obj \ - $O/br_histogram.obj \ - $O/br_huffman.obj \ - $O/br_literal_cost.obj \ - $O/br_memory.obj \ - $O/br_metablock.obj \ - $O/br_state.obj \ - $O/br_static_dict.obj \ - $O/br_transform.obj \ - $O/br_utf8_util.obj \ - -LIZARD_OBJS = \ - $O/lizard_compress.obj \ - $O/lizard_decompress.obj \ - $O/lizard_frame.obj \ - -LZ4_OBJS = \ - $O\lz4.obj \ - $O\lz4frame.obj \ - $O\lz4hc.obj \ - -LZ5_OBJS = \ - $O\lz5.obj \ - $O\lz5frame.obj \ - $O\lz5hc.obj \ - -ZSTD_OBJS = \ - $O\debug.obj \ - $O\entropy_common.obj \ - $O\error_private.obj \ - $O\fse_compress.obj \ - $O\fse_decompress.obj \ - $O\hist.obj \ - $O\huf_compress.obj \ - $O\huf_decompress.obj \ - $O\pool.obj \ - $O\threading.obj \ - $O\xxhash.obj \ - $O\zstd_common.obj \ - $O\zstd_compress.obj \ - $O\zstd_compress_literals.obj \ - $O\zstd_compress_sequences.obj \ - $O\zstd_compress_superblock.obj \ - $O\zstd_ddict.obj \ - $O\zstd_decompress_block.obj \ - $O\zstd_decompress.obj \ - $O\zstd_double_fast.obj \ - $O\zstd_fast.obj \ - $O\zstd_lazy.obj \ - $O\zstd_ldm.obj \ - $O\zstdmt_compress.obj \ - $O\zstd_opt.obj \ - $O\zstd_v01.obj \ - $O\zstd_v02.obj \ - $O\zstd_v03.obj \ - $O\zstd_v04.obj \ - $O\zstd_v05.obj \ - $O\zstd_v06.obj \ - $O\zstd_v07.obj \ - -ZSTDMT_OBJS = \ - $O\brotli-mt_common.obj \ - $O\brotli-mt_decompress.obj \ - $O\lizard-mt_common.obj \ - $O\lizard-mt_decompress.obj \ - $O\lz4-mt_common.obj \ - $O\lz4-mt_decompress.obj \ - $O\lz5-mt_common.obj \ - $O\lz5-mt_decompress.obj \ - $O\zstd-mt_threading.obj \ - -!include "../../Aes.mak" -!include "../../Crc.mak" -!include "../../LzmaDec.mak" - -!include "../../7zip.mak" +PROG = 7zxa.dll +DEF_FILE = ../../Archive/Archive2.def +CFLAGS = $(CFLAGS) -DEXTRACT_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\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\Sha256.obj \ + $O\Threads.obj \ + +COMPRESS_OBJS = $(COMPRESS_OBJS) \ + $O\BrotliDecoder.obj \ + $O\BrotliRegister.obj \ + $O\Lz4Decoder.obj \ + $O\Lz4Register.obj \ + $O\LizardDecoder.obj \ + $O\LizardRegister.obj \ + $O\Lz5Decoder.obj \ + $O\Lz5Register.obj \ + $O\ZstdDecoder.obj \ + $O\ZstdRegister.obj \ + +BROTLI_OBJS = \ + $O/br_backward_references.obj \ + $O/br_backward_references_hq.obj \ + $O/br_bit_cost.obj \ + $O/br_bit_reader.obj \ + $O/br_block_splitter.obj \ + $O/br_brotli_bit_stream.obj \ + $O/br_cluster.obj \ + $O/br_compress_fragment.obj \ + $O/br_compress_fragment_two_pass.obj \ + $O/br_decode.obj \ + $O/br_dictionary.obj \ + $O/br_dictionary_hash.obj \ + $O/br_encode.obj \ + $O/br_encoder_dict.obj \ + $O/br_entropy_encode.obj \ + $O/br_histogram.obj \ + $O/br_huffman.obj \ + $O/br_literal_cost.obj \ + $O/br_memory.obj \ + $O/br_metablock.obj \ + $O/br_state.obj \ + $O/br_static_dict.obj \ + $O/br_transform.obj \ + $O/br_utf8_util.obj \ + +LIZARD_OBJS = \ + $O/lizard_compress.obj \ + $O/lizard_decompress.obj \ + $O/lizard_frame.obj \ + +LZ4_OBJS = \ + $O\lz4.obj \ + $O\lz4frame.obj \ + $O\lz4hc.obj \ + +LZ5_OBJS = \ + $O\lz5.obj \ + $O\lz5frame.obj \ + $O\lz5hc.obj \ + +ZSTD_OBJS = \ + $O\debug.obj \ + $O\entropy_common.obj \ + $O\error_private.obj \ + $O\fse_compress.obj \ + $O\fse_decompress.obj \ + $O\hist.obj \ + $O\huf_compress.obj \ + $O\huf_decompress.obj \ + $O\pool.obj \ + $O\threading.obj \ + $O\xxhash.obj \ + $O\zstd_common.obj \ + $O\zstd_compress.obj \ + $O\zstd_compress_literals.obj \ + $O\zstd_compress_sequences.obj \ + $O\zstd_compress_superblock.obj \ + $O\zstd_ddict.obj \ + $O\zstd_decompress_block.obj \ + $O\zstd_decompress.obj \ + $O\zstd_double_fast.obj \ + $O\zstd_fast.obj \ + $O\zstd_lazy.obj \ + $O\zstd_ldm.obj \ + $O\zstdmt_compress.obj \ + $O\zstd_opt.obj \ + $O\zstd_v01.obj \ + $O\zstd_v02.obj \ + $O\zstd_v03.obj \ + $O\zstd_v04.obj \ + $O\zstd_v05.obj \ + $O\zstd_v06.obj \ + $O\zstd_v07.obj \ + +ZSTDMT_OBJS = \ + $O\brotli-mt_common.obj \ + $O\brotli-mt_decompress.obj \ + $O\lizard-mt_common.obj \ + $O\lizard-mt_decompress.obj \ + $O\lz4-mt_common.obj \ + $O\lz4-mt_decompress.obj \ + $O\lz5-mt_common.obj \ + $O\lz5-mt_decompress.obj \ + $O\zstd-mt_threading.obj \ + +!include "../../Aes.mak" +!include "../../Crc.mak" +!include "../../LzmaDec.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Format7zExtract/resource.rc b/CPP/7zip/Bundles/Format7zExtract/resource.rc index e85e7e95e..6a654615c 100644 --- a/CPP/7zip/Bundles/Format7zExtract/resource.rc +++ b/CPP/7zip/Bundles/Format7zExtract/resource.rc @@ -1,5 +1,5 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_DLL("7z Standalone Extracting Plugin", "7zxa") - -101 ICON "../../Archive/Icons/7z.ico" +#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 c6d3b1fa6..d0feea85c 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 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h +++ b/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Format7zExtractR/makefile b/CPP/7zip/Bundles/Format7zExtractR/makefile index 3a7f98169..756c8ae69 100644 --- a/CPP/7zip/Bundles/Format7zExtractR/makefile +++ b/CPP/7zip/Bundles/Format7zExtractR/makefile @@ -1,96 +1,96 @@ -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) \ + -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" diff --git a/CPP/7zip/Bundles/Format7zExtractR/resource.rc b/CPP/7zip/Bundles/Format7zExtractR/resource.rc index dac02a676..149f58c48 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 index 9b9ae22a1..a44689a08 100644 --- a/CPP/7zip/Bundles/Format7zF/Arc.mak +++ b/CPP/7zip/Bundles/Format7zF/Arc.mak @@ -1,306 +1,306 @@ -COMMON_OBJS = \ - $O\CRC.obj \ - $O\CrcReg.obj \ - $O\DynLimBuf.obj \ - $O\IntToString.obj \ - $O\Md2Reg.obj \ - $O\Md4Reg.obj \ - $O\Md5Reg.obj \ - $O\MyMap.obj \ - $O\MyString.obj \ - $O\MyVector.obj \ - $O\MyXml.obj \ - $O\NewHandler.obj \ - $O\Sha1Reg.obj \ - $O\Sha256Reg.obj \ - $O\Sha384Reg.obj \ - $O\Sha512Reg.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\UTFConvert.obj \ - $O\Wildcard.obj \ - $O\XXH32Reg.obj \ - $O\XXH64Reg.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\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\ApmHandler.obj \ - $O\ArHandler.obj \ - $O\ArjHandler.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\LzHandler.obj \ - $O\Lz4Handler.obj \ - $O\Lz5Handler.obj \ - $O\LizardHandler.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\SplitHandler.obj \ - $O\SquashfsHandler.obj \ - $O\SwfHandler.obj \ - $O\UefiHandler.obj \ - $O\VdiHandler.obj \ - $O\VhdHandler.obj \ - $O\VmdkHandler.obj \ - $O\XarHandler.obj \ - $O\XzHandler.obj \ - $O\ZHandler.obj \ - $O\ZstdHandler.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 \ - -HASHES_OBJS = \ - $O\md2.obj \ - $O\md4.obj \ - $O\md5.obj \ - $O\sha512.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\Ppmd7Enc.obj \ - $O\Ppmd8.obj \ - $O\Ppmd8Dec.obj \ - $O\Ppmd8Enc.obj \ - $O\Sha1.obj \ - $O\Sha256.obj \ - $O\Sort.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 "../../LzmaDec.mak" +COMMON_OBJS = \ + $O\CRC.obj \ + $O\CrcReg.obj \ + $O\DynLimBuf.obj \ + $O\IntToString.obj \ + $O\Md2Reg.obj \ + $O\Md4Reg.obj \ + $O\Md5Reg.obj \ + $O\MyMap.obj \ + $O\MyString.obj \ + $O\MyVector.obj \ + $O\MyXml.obj \ + $O\NewHandler.obj \ + $O\Sha1Reg.obj \ + $O\Sha256Reg.obj \ + $O\Sha384Reg.obj \ + $O\Sha512Reg.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\UTFConvert.obj \ + $O\Wildcard.obj \ + $O\XXH32Reg.obj \ + $O\XXH64Reg.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\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\ApmHandler.obj \ + $O\ArHandler.obj \ + $O\ArjHandler.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\LzHandler.obj \ + $O\Lz4Handler.obj \ + $O\Lz5Handler.obj \ + $O\LizardHandler.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\SplitHandler.obj \ + $O\SquashfsHandler.obj \ + $O\SwfHandler.obj \ + $O\UefiHandler.obj \ + $O\VdiHandler.obj \ + $O\VhdHandler.obj \ + $O\VmdkHandler.obj \ + $O\XarHandler.obj \ + $O\XzHandler.obj \ + $O\ZHandler.obj \ + $O\ZstdHandler.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 \ + +HASHES_OBJS = \ + $O\md2.obj \ + $O\md4.obj \ + $O\md5.obj \ + $O\sha512.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\Ppmd7Enc.obj \ + $O\Ppmd8.obj \ + $O\Ppmd8Dec.obj \ + $O\Ppmd8Enc.obj \ + $O\Sha1.obj \ + $O\Sha256.obj \ + $O\Sort.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 "../../LzmaDec.mak" diff --git a/CPP/7zip/Bundles/Format7zF/Format7z.dsp b/CPP/7zip/Bundles/Format7zF/Format7z.dsp index 39ff535b7..3e202fe72 100644 --- a/CPP/7zip/Bundles/Format7zF/Format7z.dsp +++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsp @@ -1,3008 +1,3008 @@ -# 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 /MT /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "NO_REGISTRY" /D "EXTERNAL_CODECS" /D "_7ZIP_LARGE_PAGES" /D "_7ZIP_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:\Program Files\7-Zip\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 "NO_REGISTRY" /D "EXTERNAL_CODECS" /D "_7ZIP_LARGE_PAGES" /D "_7ZIP_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:\Program Files\7-Zip\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\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\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\Sha1Reg.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 -# 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)" == "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 -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\HmacSha256.h -# 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\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 -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\Rar5Aes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\RarAes.cpp -# 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 -# 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\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\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\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\StdAfx.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\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\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\IArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\IhexHandler.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\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\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=..\..\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\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.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 -# End Group -# 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) 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 /MT /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "NO_REGISTRY" /D "EXTERNAL_CODECS" /D "_7ZIP_LARGE_PAGES" /D "_7ZIP_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:\Program Files\7-Zip\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 "NO_REGISTRY" /D "EXTERNAL_CODECS" /D "_7ZIP_LARGE_PAGES" /D "_7ZIP_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:\Program Files\7-Zip\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\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\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\Sha1Reg.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 +# 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)" == "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 +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\HmacSha256.h +# 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\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 +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\Rar5Aes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\RarAes.cpp +# 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 +# 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\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\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\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\StdAfx.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\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\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\IArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\IhexHandler.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\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\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=..\..\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\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.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 +# End Group +# End Target +# End Project diff --git a/CPP/7zip/Bundles/Format7zF/Format7z.dsw b/CPP/7zip/Bundles/Format7zF/Format7z.dsw index bb68d2596..324dab1ff 100644 --- a/CPP/7zip/Bundles/Format7zF/Format7z.dsw +++ b/CPP/7zip/Bundles/Format7zF/Format7z.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"=.\Format7z.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"=.\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 index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Format7zF/StdAfx.cpp +++ b/CPP/7zip/Bundles/Format7zF/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Format7zF/StdAfx.h b/CPP/7zip/Bundles/Format7zF/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Bundles/Format7zF/StdAfx.h +++ b/CPP/7zip/Bundles/Format7zF/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Format7zF/makefile b/CPP/7zip/Bundles/Format7zF/makefile index b5c18907a..327aa12ad 100644 --- a/CPP/7zip/Bundles/Format7zF/makefile +++ b/CPP/7zip/Bundles/Format7zF/makefile @@ -1,139 +1,139 @@ -PROG = 7z.dll -DEF_FILE = ../../Archive/Archive2.def -CFLAGS = $(CFLAGS) -DEXTERNAL_CODECS -DZSTD_LEGACY_SUPPORT -DZSTD_MULTITHREAD - -!IFNDEF UNDER_CE -CFLAGS = $(CFLAGS) -D_7ZIP_LARGE_PAGES -!ENDIF - -!include "Arc.mak" - -COMPRESS_OBJS = $(COMPRESS_OBJS) \ - $O\CodecExports.obj \ - -AR_OBJS = $(AR_OBJS) \ - $O\ArchiveExports.obj \ - $O\DllExports2.obj \ - -COMPRESS_OBJS = $(COMPRESS_OBJS) \ - $O\BrotliDecoder.obj \ - $O\BrotliEncoder.obj \ - $O\BrotliRegister.obj \ - $O\Lz4Decoder.obj \ - $O\Lz4Encoder.obj \ - $O\Lz4Register.obj \ - $O\LizardDecoder.obj \ - $O\LizardEncoder.obj \ - $O\LizardRegister.obj \ - $O\Lz5Decoder.obj \ - $O\Lz5Encoder.obj \ - $O\Lz5Register.obj \ - $O\ZstdDecoder.obj \ - $O\ZstdEncoder.obj \ - $O\ZstdRegister.obj \ - $O\FastLzma2Register.obj \ - -BROTLI_OBJS = \ - $O/br_backward_references.obj \ - $O/br_backward_references_hq.obj \ - $O/br_bit_cost.obj \ - $O/br_bit_reader.obj \ - $O/br_block_splitter.obj \ - $O/br_brotli_bit_stream.obj \ - $O/br_cluster.obj \ - $O/br_compress_fragment.obj \ - $O/br_compress_fragment_two_pass.obj \ - $O/br_decode.obj \ - $O/br_dictionary.obj \ - $O/br_dictionary_hash.obj \ - $O/br_encode.obj \ - $O/br_encoder_dict.obj \ - $O/br_entropy_encode.obj \ - $O/br_histogram.obj \ - $O/br_huffman.obj \ - $O/br_literal_cost.obj \ - $O/br_memory.obj \ - $O/br_metablock.obj \ - $O/br_state.obj \ - $O/br_static_dict.obj \ - $O/br_transform.obj \ - $O/br_utf8_util.obj \ - -LIZARD_OBJS = \ - $O/lizard_compress.obj \ - $O/lizard_decompress.obj \ - $O/lizard_frame.obj \ - -LZ4_OBJS = \ - $O\lz4.obj \ - $O\lz4frame.obj \ - $O\lz4hc.obj \ - -LZ5_OBJS = \ - $O\lz5.obj \ - $O\lz5frame.obj \ - $O\lz5hc.obj \ - -ZSTD_OBJS = \ - $O\debug.obj \ - $O\entropy_common.obj \ - $O\error_private.obj \ - $O\fse_compress.obj \ - $O\fse_decompress.obj \ - $O\hist.obj \ - $O\huf_compress.obj \ - $O\huf_decompress.obj \ - $O\pool.obj \ - $O\threading.obj \ - $O\xxhash.obj \ - $O\zstd_common.obj \ - $O\zstd_compress.obj \ - $O\zstd_compress_literals.obj \ - $O\zstd_compress_sequences.obj \ - $O\zstd_compress_superblock.obj \ - $O\zstd_ddict.obj \ - $O\zstd_decompress_block.obj \ - $O\zstd_decompress.obj \ - $O\zstd_double_fast.obj \ - $O\zstd_fast.obj \ - $O\zstd_lazy.obj \ - $O\zstd_ldm.obj \ - $O\zstdmt_compress.obj \ - $O\zstd_opt.obj \ - $O\zstd_v01.obj \ - $O\zstd_v02.obj \ - $O\zstd_v03.obj \ - $O\zstd_v04.obj \ - $O\zstd_v05.obj \ - $O\zstd_v06.obj \ - $O\zstd_v07.obj \ - -ZSTDMT_OBJS = \ - $O\brotli-mt_common.obj \ - $O\brotli-mt_compress.obj \ - $O\brotli-mt_decompress.obj \ - $O\lizard-mt_common.obj \ - $O\lizard-mt_compress.obj \ - $O\lizard-mt_decompress.obj \ - $O\lz4-mt_common.obj \ - $O\lz4-mt_compress.obj \ - $O\lz4-mt_decompress.obj \ - $O\lz5-mt_common.obj \ - $O\lz5-mt_compress.obj \ - $O\lz5-mt_decompress.obj \ - $O\zstd-mt_threading.obj \ - -FASTLZMA2_OBJS = \ - $O\dict_buffer.obj \ - $O\fl2_common.obj \ - $O\fl2_compress.obj \ - $O\fl2_pool.obj \ - $O\fl2_threading.obj \ - $O\lzma2_enc.obj \ - $O\radix_bitpack.obj \ - $O\radix_mf.obj \ - $O\radix_struct.obj \ - $O\range_enc.obj \ - $O\util.obj \ - -!include "../../7zip.mak" +PROG = 7z.dll +DEF_FILE = ../../Archive/Archive2.def +CFLAGS = $(CFLAGS) -DEXTERNAL_CODECS -DZSTD_LEGACY_SUPPORT -DZSTD_MULTITHREAD + +!IFNDEF UNDER_CE +CFLAGS = $(CFLAGS) -D_7ZIP_LARGE_PAGES +!ENDIF + +!include "Arc.mak" + +COMPRESS_OBJS = $(COMPRESS_OBJS) \ + $O\CodecExports.obj \ + +AR_OBJS = $(AR_OBJS) \ + $O\ArchiveExports.obj \ + $O\DllExports2.obj \ + +COMPRESS_OBJS = $(COMPRESS_OBJS) \ + $O\BrotliDecoder.obj \ + $O\BrotliEncoder.obj \ + $O\BrotliRegister.obj \ + $O\Lz4Decoder.obj \ + $O\Lz4Encoder.obj \ + $O\Lz4Register.obj \ + $O\LizardDecoder.obj \ + $O\LizardEncoder.obj \ + $O\LizardRegister.obj \ + $O\Lz5Decoder.obj \ + $O\Lz5Encoder.obj \ + $O\Lz5Register.obj \ + $O\ZstdDecoder.obj \ + $O\ZstdEncoder.obj \ + $O\ZstdRegister.obj \ + $O\FastLzma2Register.obj \ + +BROTLI_OBJS = \ + $O/br_backward_references.obj \ + $O/br_backward_references_hq.obj \ + $O/br_bit_cost.obj \ + $O/br_bit_reader.obj \ + $O/br_block_splitter.obj \ + $O/br_brotli_bit_stream.obj \ + $O/br_cluster.obj \ + $O/br_compress_fragment.obj \ + $O/br_compress_fragment_two_pass.obj \ + $O/br_decode.obj \ + $O/br_dictionary.obj \ + $O/br_dictionary_hash.obj \ + $O/br_encode.obj \ + $O/br_encoder_dict.obj \ + $O/br_entropy_encode.obj \ + $O/br_histogram.obj \ + $O/br_huffman.obj \ + $O/br_literal_cost.obj \ + $O/br_memory.obj \ + $O/br_metablock.obj \ + $O/br_state.obj \ + $O/br_static_dict.obj \ + $O/br_transform.obj \ + $O/br_utf8_util.obj \ + +LIZARD_OBJS = \ + $O/lizard_compress.obj \ + $O/lizard_decompress.obj \ + $O/lizard_frame.obj \ + +LZ4_OBJS = \ + $O\lz4.obj \ + $O\lz4frame.obj \ + $O\lz4hc.obj \ + +LZ5_OBJS = \ + $O\lz5.obj \ + $O\lz5frame.obj \ + $O\lz5hc.obj \ + +ZSTD_OBJS = \ + $O\debug.obj \ + $O\entropy_common.obj \ + $O\error_private.obj \ + $O\fse_compress.obj \ + $O\fse_decompress.obj \ + $O\hist.obj \ + $O\huf_compress.obj \ + $O\huf_decompress.obj \ + $O\pool.obj \ + $O\threading.obj \ + $O\xxhash.obj \ + $O\zstd_common.obj \ + $O\zstd_compress.obj \ + $O\zstd_compress_literals.obj \ + $O\zstd_compress_sequences.obj \ + $O\zstd_compress_superblock.obj \ + $O\zstd_ddict.obj \ + $O\zstd_decompress_block.obj \ + $O\zstd_decompress.obj \ + $O\zstd_double_fast.obj \ + $O\zstd_fast.obj \ + $O\zstd_lazy.obj \ + $O\zstd_ldm.obj \ + $O\zstdmt_compress.obj \ + $O\zstd_opt.obj \ + $O\zstd_v01.obj \ + $O\zstd_v02.obj \ + $O\zstd_v03.obj \ + $O\zstd_v04.obj \ + $O\zstd_v05.obj \ + $O\zstd_v06.obj \ + $O\zstd_v07.obj \ + +ZSTDMT_OBJS = \ + $O\brotli-mt_common.obj \ + $O\brotli-mt_compress.obj \ + $O\brotli-mt_decompress.obj \ + $O\lizard-mt_common.obj \ + $O\lizard-mt_compress.obj \ + $O\lizard-mt_decompress.obj \ + $O\lz4-mt_common.obj \ + $O\lz4-mt_compress.obj \ + $O\lz4-mt_decompress.obj \ + $O\lz5-mt_common.obj \ + $O\lz5-mt_compress.obj \ + $O\lz5-mt_decompress.obj \ + $O\zstd-mt_threading.obj \ + +FASTLZMA2_OBJS = \ + $O\dict_buffer.obj \ + $O\fl2_common.obj \ + $O\fl2_compress.obj \ + $O\fl2_pool.obj \ + $O\fl2_threading.obj \ + $O\lzma2_enc.obj \ + $O\radix_bitpack.obj \ + $O\radix_mf.obj \ + $O\radix_struct.obj \ + $O\range_enc.obj \ + $O\util.obj \ + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Format7zF/resource.rc b/CPP/7zip/Bundles/Format7zF/resource.rc index e7c4d1b29..3bf485d5a 100644 --- a/CPP/7zip/Bundles/Format7zF/resource.rc +++ b/CPP/7zip/Bundles/Format7zF/resource.rc @@ -1,40 +1,40 @@ -#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/zst.ico" -26 ICON "../../Archive/Icons/lz4.ico" -27 ICON "../../Archive/Icons/lz5.ico" -28 ICON "../../Archive/Icons/liz.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 lz:16 tlz:16 liz:28 lz4:26 lz5:27 lzh:6 lha:6 rpm:10 deb:11 arj:4 vhd:20 wim:15 swm:15 fat:21 ntfs:22 dmg:17 hfs:18 xar:19 squashfs:24 zst:25" -END +#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/zst.ico" +26 ICON "../../Archive/Icons/lz4.ico" +27 ICON "../../Archive/Icons/lz5.ico" +28 ICON "../../Archive/Icons/liz.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 lz:16 tlz:16 liz:28 lz4:26 lz5:27 lzh:6 lha:6 rpm:10 deb:11 arj:4 vhd:20 wim:15 swm:15 fat:21 ntfs:22 dmg:17 hfs:18 xar:19 squashfs:24 zst:25" +END diff --git a/CPP/7zip/Bundles/Format7zR/StdAfx.cpp b/CPP/7zip/Bundles/Format7zR/StdAfx.cpp index c6d3b1fa6..d0feea85c 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 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Bundles/Format7zR/StdAfx.h +++ b/CPP/7zip/Bundles/Format7zR/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Format7zR/makefile b/CPP/7zip/Bundles/Format7zR/makefile index 6a9dfb919..5c05abd17 100644 --- a/CPP/7zip/Bundles/Format7zR/makefile +++ b/CPP/7zip/Bundles/Format7zR/makefile @@ -1,116 +1,116 @@ -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) \ + -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" diff --git a/CPP/7zip/Bundles/Format7zR/resource.rc b/CPP/7zip/Bundles/Format7zR/resource.rc index 262125c12..a8baa596a 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 f27333741..62d3a84cb 100644 --- a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp +++ b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp @@ -1,799 +1,799 @@ -// LzmaAlone.cpp - -#include "StdAfx.h" - -#include - -#include "../../../../C/CpuArch.h" - -#if (defined(_WIN32) || defined(OS2) || defined(MSDOS)) && !defined(UNDER_CE) -#include -#include -#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 [inputFile] [outputFile] [...]\n" - "\n" - "\n" - " e : Encode file\n" - " d : Decode file\n" - " b : Benchmark\n" - "\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 &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 ¶ms = parser.NonSwitchStrings; - - unsigned paramIndex = 0; - if (paramIndex >= params.Size()) - IncorrectCommand(); - const UString &command = params[paramIndex++]; - - CObjectVector 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 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 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 progress; - - if (!stdOutMode) - { - progressSpec = new CProgressPrint; - progress = progressSpec; - } - - if (encodeMode) - { - NCompress::NLzma::CEncoder *encoderSpec = new NCompress::NLzma::CEncoder; - CMyComPtr 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((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 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 + +#include "../../../../C/CpuArch.h" + +#if (defined(_WIN32) || defined(OS2) || defined(MSDOS)) && !defined(UNDER_CE) +#include +#include +#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 [inputFile] [outputFile] [...]\n" + "\n" + "\n" + " e : Encode file\n" + " d : Decode file\n" + " b : Benchmark\n" + "\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 &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 ¶ms = parser.NonSwitchStrings; + + unsigned paramIndex = 0; + if (paramIndex >= params.Size()) + IncorrectCommand(); + const UString &command = params[paramIndex++]; + + CObjectVector 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 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 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 progress; + + if (!stdOutMode) + { + progressSpec = new CProgressPrint; + progress = progressSpec; + } + + if (encodeMode) + { + NCompress::NLzma::CEncoder *encoderSpec = new NCompress::NLzma::CEncoder; + CMyComPtr 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((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 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; + } +} diff --git a/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp b/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp index bdc0c3e39..f8267a11f 100644 --- a/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp +++ b/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp @@ -1,477 +1,477 @@ -# 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\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 diff --git a/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw b/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw index c6a666276..e62c9d2f1 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 c6d3b1fa6..d0feea85c 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 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Bundles/LzmaCon/StdAfx.h +++ b/CPP/7zip/Bundles/LzmaCon/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/LzmaCon/makefile b/CPP/7zip/Bundles/LzmaCon/makefile index 5a50808f3..000ca4469 100644 --- a/CPP/7zip/Bundles/LzmaCon/makefile +++ b/CPP/7zip/Bundles/LzmaCon/makefile @@ -1,59 +1,59 @@ -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 + +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" diff --git a/CPP/7zip/Bundles/LzmaCon/makefile.gcc b/CPP/7zip/Bundles/LzmaCon/makefile.gcc index 3fb5ec208..97fe45084 100644 --- a/CPP/7zip/Bundles/LzmaCon/makefile.gcc +++ b/CPP/7zip/Bundles/LzmaCon/makefile.gcc @@ -1,195 +1,195 @@ -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 +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) diff --git a/CPP/7zip/Bundles/LzmaCon/resource.rc b/CPP/7zip/Bundles/LzmaCon/resource.rc index 9b54fa80a..43b50738e 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/SFXCon/SFXCon.dsp b/CPP/7zip/Bundles/SFXCon/SFXCon.dsp index 87753191f..0f032d81a 100644 --- a/CPP/7zip/Bundles/SFXCon/SFXCon.dsp +++ b/CPP/7zip/Bundles/SFXCon/SFXCon.dsp @@ -1,912 +1,912 @@ -# 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 /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 diff --git a/CPP/7zip/Bundles/SFXCon/SFXCon.dsw b/CPP/7zip/Bundles/SFXCon/SFXCon.dsw index bfbc2b7f0..27bf7e6d1 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 9b34a0819..3209a01c6 100644 --- a/CPP/7zip/Bundles/SFXCon/SfxCon.cpp +++ b/CPP/7zip/Bundles/SFXCon/SfxCon.cpp @@ -1,482 +1,482 @@ -// 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 <@|!>ame must be -static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!>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 [] [...] [...]\n" - "\n" - "\n" - // " l: List contents of archive\n" - " t: Test integrity of archive\n" - " x: eXtract files with full pathname (default)\n" - "\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 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(), 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(), 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 "../../../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 <@|!>ame must be +static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!>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 [] [...] [...]\n" + "\n" + "\n" + // " l: List contents of archive\n" + " t: Test integrity of archive\n" + " x: eXtract files with full pathname (default)\n" + "\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 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(), 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(), 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; +} diff --git a/CPP/7zip/Bundles/SFXCon/StdAfx.cpp b/CPP/7zip/Bundles/SFXCon/StdAfx.cpp index c6d3b1fa6..d0feea85c 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 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/Bundles/SFXCon/StdAfx.h +++ b/CPP/7zip/Bundles/SFXCon/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/SFXCon/makefile b/CPP/7zip/Bundles/SFXCon/makefile index c785ceb99..05b7a6293 100644 --- a/CPP/7zip/Bundles/SFXCon/makefile +++ b/CPP/7zip/Bundles/SFXCon/makefile @@ -1,152 +1,152 @@ -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" - -COMPRESS_OBJS = $(COMPRESS_OBJS) \ - $O\ZstdDecoder.obj \ - $O\ZstdRegister.obj \ - -ZSTD_OBJS = \ - $O\debug.obj \ - $O\entropy_common.obj \ - $O\error_private.obj \ - $O\fse_decompress.obj \ - $O\huf_decompress.obj \ - $O\pool.obj \ - $O\threading.obj \ - $O\xxhash.obj \ - $O\zstd_common.obj \ - $O\zstd_ddict.obj \ - $O\zstd_decompress_block.obj \ - $O\zstd_decompress.obj \ - -!include "../../7zip.mak" +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" + +COMPRESS_OBJS = $(COMPRESS_OBJS) \ + $O\ZstdDecoder.obj \ + $O\ZstdRegister.obj \ + +ZSTD_OBJS = \ + $O\debug.obj \ + $O\entropy_common.obj \ + $O\error_private.obj \ + $O\fse_decompress.obj \ + $O\huf_decompress.obj \ + $O\pool.obj \ + $O\threading.obj \ + $O\xxhash.obj \ + $O\zstd_common.obj \ + $O\zstd_ddict.obj \ + $O\zstd_decompress_block.obj \ + $O\zstd_decompress.obj \ + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/SFXCon/resource.rc b/CPP/7zip/Bundles/SFXCon/resource.rc index 97882cd3c..58331b81f 100644 --- a/CPP/7zip/Bundles/SFXCon/resource.rc +++ b/CPP/7zip/Bundles/SFXCon/resource.rc @@ -1,5 +1,5 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_APP("7z Console SFX", "7z.sfx") - +#include "../../MyVersionInfo.rc" + +MY_VERSION_INFO_APP("7z Console SFX", "7z.sfx") + 101 ICON "7z.ico" \ No newline at end of file diff --git a/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.cpp b/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.cpp index d35a24fec..00e3ba53a 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 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 = "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 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; +} diff --git a/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h b/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h index b7f04e0ec..cfbc5c07a 100644 --- a/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h +++ b/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h @@ -1,86 +1,86 @@ -// 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 _archiveHandler; - FString _directoryPath; - UString _filePath; - FString _diskFilePath; - - bool _extractMode; - struct CProcessedFileInfo - { - FILETIME MTime; - bool IsDir; - UInt32 Attributes; - } _processedFileInfo; - - COutFileStream *_outFileStreamSpec; - CMyComPtr _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 __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 _archiveHandler; + FString _directoryPath; + UString _filePath; + FString _diskFilePath; + + bool _extractMode; + struct CProcessedFileInfo + { + FILETIME MTime; + bool IsDir; + UInt32 Attributes; + } _processedFileInfo; + + COutFileStream *_outFileStreamSpec; + CMyComPtr _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 diff --git a/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp b/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp index 194e37614..e510e5c81 100644 --- a/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp +++ b/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp @@ -1,137 +1,137 @@ -// 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 ExtractCallback; - - CArchiveLink ArchiveLink; - HRESULT Result; - UString ErrorMessage; - - void Process2() - { - NFind::CFileInfo fi; - if (!fi.Find(FileName)) - { - ErrorMessage = kCantFindArchive; - Result = E_FAIL; - return; - } - - CObjectVector incl; - CIntVector excl; - COpenOptions options; - options.codecs = Codecs; - options.types = &incl; - options.excludedFormats = ! - 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 = "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 ExtractCallback; + + CArchiveLink ArchiveLink; + HRESULT Result; + UString ErrorMessage; + + void Process2() + { + NFind::CFileInfo fi; + if (!fi.Find(FileName)) + { + ErrorMessage = kCantFindArchive; + Result = E_FAIL; + return; + } + + CObjectVector incl; + CIntVector excl; + COpenOptions options; + options.codecs = Codecs; + options.types = &incl; + options.excludedFormats = ! + 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; +} diff --git a/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h b/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h index 8aa9724e2..295d77b99 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 __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 diff --git a/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp b/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp index b1d740e67..754cc0e0c 100644 --- a/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp +++ b/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp @@ -1,803 +1,803 @@ -# 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 "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 diff --git a/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw b/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw index 297037014..f563b21f2 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 1705a8de1..0c302332d 100644 --- a/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp +++ b/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp @@ -1,364 +1,364 @@ -// 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 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 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 "../../../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 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 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; +} diff --git a/CPP/7zip/Bundles/SFXSetup/StdAfx.cpp b/CPP/7zip/Bundles/SFXSetup/StdAfx.cpp index c6d3b1fa6..d0feea85c 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 72410eecd..37bbd0c33 100644 --- a/CPP/7zip/Bundles/SFXSetup/StdAfx.h +++ b/CPP/7zip/Bundles/SFXSetup/StdAfx.h @@ -1,13 +1,13 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#include - -// #define printf(x) NO_PRINTF_(x) -// #define sprintf(x) NO_SPRINTF_(x) - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#include + +// #define printf(x) NO_PRINTF_(x) +// #define sprintf(x) NO_SPRINTF_(x) + +#endif diff --git a/CPP/7zip/Bundles/SFXSetup/resource.h b/CPP/7zip/Bundles/SFXSetup/resource.h index 533197e91..d5f440bb8 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 9e88fd4d0..47e1b7620 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 83ec93115..14492ca18 100644 --- a/CPP/7zip/Bundles/SFXWin/SFXWin.dsp +++ b/CPP/7zip/Bundles/SFXWin/SFXWin.dsp @@ -1,988 +1,988 @@ -# 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 "_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 diff --git a/CPP/7zip/Bundles/SFXWin/SFXWin.dsw b/CPP/7zip/Bundles/SFXWin/SFXWin.dsw index 66958036b..a9926c719 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 5eade1abd..3c77356e4 100644 --- a/CPP/7zip/Bundles/SFXWin/SfxWin.cpp +++ b/CPP/7zip/Bundles/SFXWin/SfxWin.cpp @@ -1,241 +1,241 @@ -// Main.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#include - -#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 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 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(), 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" + +#include + +#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 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 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(), 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; + } +} diff --git a/CPP/7zip/Bundles/SFXWin/StdAfx.cpp b/CPP/7zip/Bundles/SFXWin/StdAfx.cpp index c6d3b1fa6..d0feea85c 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 f263ecb77..975a17e8b 100644 --- a/CPP/7zip/Bundles/SFXWin/StdAfx.h +++ b/CPP/7zip/Bundles/SFXWin/StdAfx.h @@ -1,14 +1,14 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#include -#include - -// #define printf(x) NO_PRINTF_(x) -// #define sprintf(x) NO_SPRINTF_(x) - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#include +#include + +// #define printf(x) NO_PRINTF_(x) +// #define sprintf(x) NO_SPRINTF_(x) + +#endif diff --git a/CPP/7zip/Bundles/SFXWin/makefile b/CPP/7zip/Bundles/SFXWin/makefile index 8a2145bf3..50a06b2b3 100644 --- a/CPP/7zip/Bundles/SFXWin/makefile +++ b/CPP/7zip/Bundles/SFXWin/makefile @@ -1,172 +1,172 @@ -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\System.obj \ - $O\Synchronization.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" - -COMPRESS_OBJS = $(COMPRESS_OBJS) \ - $O\ZstdDecoder.obj \ - $O\ZstdRegister.obj \ - -ZSTD_OBJS = \ - $O\debug.obj \ - $O\entropy_common.obj \ - $O\error_private.obj \ - $O\fse_decompress.obj \ - $O\huf_decompress.obj \ - $O\pool.obj \ - $O\threading.obj \ - $O\xxhash.obj \ - $O\zstd_common.obj \ - $O\zstd_ddict.obj \ - $O\zstd_decompress_block.obj \ - $O\zstd_decompress.obj \ - - -!include "../../7zip.mak" +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\System.obj \ + $O\Synchronization.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" + +COMPRESS_OBJS = $(COMPRESS_OBJS) \ + $O\ZstdDecoder.obj \ + $O\ZstdRegister.obj \ + +ZSTD_OBJS = \ + $O\debug.obj \ + $O\entropy_common.obj \ + $O\error_private.obj \ + $O\fse_decompress.obj \ + $O\huf_decompress.obj \ + $O\pool.obj \ + $O\threading.obj \ + $O\xxhash.obj \ + $O\zstd_common.obj \ + $O\zstd_ddict.obj \ + $O\zstd_decompress_block.obj \ + $O\zstd_decompress.obj \ + + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/SFXWin/resource.h b/CPP/7zip/Bundles/SFXWin/resource.h index d9fae1ba6..30fe2030e 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 3b69b357e..91292b2f1 100644 --- a/CPP/7zip/Bundles/SFXWin/resource.rc +++ b/CPP/7zip/Bundles/SFXWin/resource.rc @@ -1,50 +1,50 @@ -#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 diff --git a/CPP/7zip/Bundles/makefile b/CPP/7zip/Bundles/makefile index e869ee45c..e3b4b88f0 100644 --- a/CPP/7zip/Bundles/makefile +++ b/CPP/7zip/Bundles/makefile @@ -1,18 +1,18 @@ -DIRS = \ - Alone\~ \ - Alone7z\~ \ - Fm\~ \ - Format7z\~ \ - Format7zF\~ \ - Format7zR\~ \ - Format7zExtract\~ \ - Format7zExtractR\~ \ - LzmaCon\~ \ - SFXCon\~ \ - SFXSetup\~ \ - SFXWin\~ \ - -all: $(DIRS) - -$(DIRS): -!include "../SubBuild.mak" +DIRS = \ + Alone\~ \ + 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 e726dadc2..d6b04206b 100644 --- a/CPP/7zip/Common/CWrappers.cpp +++ b/CPP/7zip/Common/CWrappers.cpp @@ -1,250 +1,250 @@ -// 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.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; +} diff --git a/CPP/7zip/Common/CWrappers.h b/CPP/7zip/Common/CWrappers.h index f93c98adc..e5c890d82 100644 --- a/CPP/7zip/Common/CWrappers.h +++ b/CPP/7zip/Common/CWrappers.h @@ -1,120 +1,120 @@ -// 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 __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 diff --git a/CPP/7zip/Common/CreateCoder.cpp b/CPP/7zip/Common/CreateCoder.cpp index 504076573..bf525dc8c 100644 --- a/CPP/7zip/Common/CreateCoder.cpp +++ b/CPP/7zip/Common/CreateCoder.cpp @@ -1,536 +1,536 @@ -// 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 &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 &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 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 &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 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 &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 &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 &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; +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 &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 &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 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 &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 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 &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 &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 &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; +} diff --git a/CPP/7zip/Common/CreateCoder.h b/CPP/7zip/Common/CreateCoder.h index 2105818fb..20d0ef338 100644 --- a/CPP/7zip/Common/CreateCoder.h +++ b/CPP/7zip/Common/CreateCoder.h @@ -1,192 +1,192 @@ -// 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 GetCodecs; - CMyComPtr GetHashers; - - CObjectVector Codecs; - CObjectVector 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 &methods); - - -struct CCreatedCoder -{ - CMyComPtr Coder; - CMyComPtr 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 &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 &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 &coder); - -HRESULT CreateFilter( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, bool encode, - CMyComPtr &filter); - -HRESULT CreateHasher( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, - AString &name, - CMyComPtr &hasher); - -#endif +// 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 GetCodecs; + CMyComPtr GetHashers; + + CObjectVector Codecs; + CObjectVector 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 &methods); + + +struct CCreatedCoder +{ + CMyComPtr Coder; + CMyComPtr 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 &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 &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 &coder); + +HRESULT CreateFilter( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, bool encode, + CMyComPtr &filter); + +HRESULT CreateHasher( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, + AString &name, + CMyComPtr &hasher); + +#endif diff --git a/CPP/7zip/Common/FilePathAutoRename.cpp b/CPP/7zip/Common/FilePathAutoRename.cpp index 84c9e2bce..0904e6969 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(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); +} diff --git a/CPP/7zip/Common/FilePathAutoRename.h b/CPP/7zip/Common/FilePathAutoRename.h index cb2d71b40..7b576591c 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 __FILE_PATH_AUTO_RENAME_H +#define __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 11c14d219..f3a322fc9 100644 --- a/CPP/7zip/Common/FileStreams.cpp +++ b/CPP/7zip/Common/FileStreams.cpp @@ -1,475 +1,475 @@ -// FileStreams.cpp - -#include "StdAfx.h" - -#ifndef _WIN32 -#include -#include -#include -#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" + +#ifndef _WIN32 +#include +#include +#include +#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 diff --git a/CPP/7zip/Common/FileStreams.h b/CPP/7zip/Common/FileStreams.h index a0996f80a..ef2986fdd 100644 --- a/CPP/7zip/Common/FileStreams.h +++ b/CPP/7zip/Common/FileStreams.h @@ -1,166 +1,166 @@ -// 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 __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 diff --git a/CPP/7zip/Common/FilterCoder.cpp b/CPP/7zip/Common/FilterCoder.cpp index d5c7ff0e5..f4c00273c 100644 --- a/CPP/7zip/Common/FilterCoder.cpp +++ b/CPP/7zip/Common/FilterCoder.cpp @@ -1,435 +1,435 @@ -// 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 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 "../../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 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); } diff --git a/CPP/7zip/Common/FilterCoder.h b/CPP/7zip/Common/FilterCoder.h index bde0e2bb4..6668fdb31 100644 --- a/CPP/7zip/Common/FilterCoder.h +++ b/CPP/7zip/Common/FilterCoder.h @@ -1,205 +1,205 @@ -// 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 _inStream; - CMyComPtr _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 _SetPassword; - CMyComPtr _CryptoProperties; - #endif - - #ifndef EXTRACT_ONLY - CMyComPtr _SetCoderProperties; - CMyComPtr _WriteCoderProperties; - // CMyComPtr _CryptoResetSalt; - CMyComPtr _CryptoResetInitVector; - #endif - - CMyComPtr _SetDecoderProperties2; - -public: - CMyComPtr 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 __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 _inStream; + CMyComPtr _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 _SetPassword; + CMyComPtr _CryptoProperties; + #endif + + #ifndef EXTRACT_ONLY + CMyComPtr _SetCoderProperties; + CMyComPtr _WriteCoderProperties; + // CMyComPtr _CryptoResetSalt; + CMyComPtr _CryptoResetInitVector; + #endif + + CMyComPtr _SetDecoderProperties2; + +public: + CMyComPtr 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 diff --git a/CPP/7zip/Common/InBuffer.cpp b/CPP/7zip/Common/InBuffer.cpp index 826e98b19..d1bc9b9a0 100644 --- a/CPP/7zip/Common/InBuffer.cpp +++ b/CPP/7zip/Common/InBuffer.cpp @@ -1,163 +1,163 @@ -// 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(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; + } +} diff --git a/CPP/7zip/Common/InBuffer.h b/CPP/7zip/Common/InBuffer.h index 76e359a00..4b9c2c32c 100644 --- a/CPP/7zip/Common/InBuffer.h +++ b/CPP/7zip/Common/InBuffer.h @@ -1,92 +1,92 @@ -// 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 __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 diff --git a/CPP/7zip/Common/InOutTempBuffer.cpp b/CPP/7zip/Common/InOutTempBuffer.cpp index d83d67467..7523f3a39 100644 --- a/CPP/7zip/Common/InOutTempBuffer.cpp +++ b/CPP/7zip/Common/InOutTempBuffer.cpp @@ -1,127 +1,127 @@ -// 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/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; +} +*/ diff --git a/CPP/7zip/Common/InOutTempBuffer.h b/CPP/7zip/Common/InOutTempBuffer.h index 4140d2830..204a105f1 100644 --- a/CPP/7zip/Common/InOutTempBuffer.h +++ b/CPP/7zip/Common/InOutTempBuffer.h @@ -1,48 +1,48 @@ -// InOutTempBuffer.h - -#ifndef __IN_OUT_TEMP_BUFFER_H -#define __IN_OUT_TEMP_BUFFER_H - -#include "../../Common/MyCom.h" -#include "../../Windows/FileDir.h" - -#include "../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 __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 diff --git a/CPP/7zip/Common/LimitedStreams.cpp b/CPP/7zip/Common/LimitedStreams.cpp index fc7e794cf..8e0325616 100644 --- a/CPP/7zip/Common/LimitedStreams.cpp +++ b/CPP/7zip/Common/LimitedStreams.cpp @@ -1,367 +1,367 @@ -// LimitedStreams.cpp - -#include "StdAfx.h" - -#include - -#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 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 + +#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 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); +} diff --git a/CPP/7zip/Common/LimitedStreams.h b/CPP/7zip/Common/LimitedStreams.h index 2e55aa0b6..fb1ac3cd6 100644 --- a/CPP/7zip/Common/LimitedStreams.h +++ b/CPP/7zip/Common/LimitedStreams.h @@ -1,252 +1,252 @@ -// 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 _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 _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 Stream; - CRecordVector 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 Stream; - CRecordVector 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 _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 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 _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 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 __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 _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 _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 Stream; + CRecordVector 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 Stream; + CRecordVector 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 _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 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 _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 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 diff --git a/CPP/7zip/Common/LockedStream.cpp b/CPP/7zip/Common/LockedStream.cpp index 1223efe85..ca39fb455 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 5bf5c85a4..efebf1975 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 __LOCKED_STREAM_H +#define __LOCKED_STREAM_H + +#endif diff --git a/CPP/7zip/Common/MemBlocks.cpp b/CPP/7zip/Common/MemBlocks.cpp index 7a4ee7e7f..5aba046bf 100644 --- a/CPP/7zip/Common/MemBlocks.cpp +++ b/CPP/7zip/Common/MemBlocks.cpp @@ -1,183 +1,183 @@ -// MemBlocks.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "MemBlocks.h" -#include "StreamUtils.h" - -bool CMemBlockManager::AllocateSpace(size_t numBlocks) -{ - FreeSpace(); - if (_blockSize < sizeof(void *) || numBlocks < 1) - return false; - size_t totalSize = numBlocks * _blockSize; - if (totalSize / _blockSize != numBlocks) - return false; - _data = ::MidAlloc(totalSize); - if (_data == 0) - return false; - Byte *p = (Byte *)_data; - for (size_t i = 0; i + 1 < numBlocks; i++, p += _blockSize) - *(Byte **)p = (p + _blockSize); - *(Byte **)p = 0; - _headFree = _data; - return true; -} - -void CMemBlockManager::FreeSpace() -{ - ::MidFree(_data); - _data = 0; - _headFree= 0; -} - -void *CMemBlockManager::AllocateBlock() -{ - if (_headFree == 0) - return 0; - void *p = _headFree; - _headFree = *(void **)_headFree; - return p; -} - -void CMemBlockManager::FreeBlock(void *p) -{ - if (p == 0) - return; - *(void **)p = _headFree; - _headFree = p; -} - - -HRes CMemBlockManagerMt::AllocateSpace(size_t numBlocks, size_t numNoLockBlocks) -{ - if (numNoLockBlocks > numBlocks) - return E_INVALIDARG; - if (!CMemBlockManager::AllocateSpace(numBlocks)) - return E_OUTOFMEMORY; - size_t numLockBlocks = numBlocks - numNoLockBlocks; - Semaphore.Close(); - return Semaphore.Create((LONG)numLockBlocks, (LONG)numLockBlocks); -} - -HRes CMemBlockManagerMt::AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks) -{ - if (numNoLockBlocks > desiredNumberOfBlocks) - return E_INVALIDARG; - for (;;) - { - if (AllocateSpace(desiredNumberOfBlocks, numNoLockBlocks) == 0) - return 0; - if (desiredNumberOfBlocks == numNoLockBlocks) - return E_OUTOFMEMORY; - desiredNumberOfBlocks = numNoLockBlocks + ((desiredNumberOfBlocks - numNoLockBlocks) >> 1); - } -} - -void CMemBlockManagerMt::FreeSpace() -{ - Semaphore.Close(); - CMemBlockManager::FreeSpace(); -} - -void *CMemBlockManagerMt::AllocateBlock() -{ - // Semaphore.Lock(); - NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); - return CMemBlockManager::AllocateBlock(); -} - -void CMemBlockManagerMt::FreeBlock(void *p, bool lockMode) -{ - if (p == 0) - return; - { - NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); - CMemBlockManager::FreeBlock(p); - } - if (lockMode) - Semaphore.Release(); -} - -void CMemBlocks::Free(CMemBlockManagerMt *manager) -{ - while (Blocks.Size() > 0) - { - manager->FreeBlock(Blocks.Back()); - Blocks.DeleteBack(); - } - TotalSize = 0; -} - -void CMemBlocks::FreeOpt(CMemBlockManagerMt *manager) -{ - Free(manager); - Blocks.ClearAndFree(); -} - -HRESULT CMemBlocks::WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const -{ - UInt64 totalSize = TotalSize; - for (unsigned blockIndex = 0; totalSize > 0; blockIndex++) - { - UInt32 curSize = (UInt32)blockSize; - if (totalSize < curSize) - curSize = (UInt32)totalSize; - if (blockIndex >= Blocks.Size()) - return E_FAIL; - RINOK(WriteStream(outStream, Blocks[blockIndex], curSize)); - totalSize -= curSize; - } - return S_OK; -} - - -void CMemLockBlocks::FreeBlock(int index, CMemBlockManagerMt *memManager) -{ - memManager->FreeBlock(Blocks[index], LockMode); - Blocks[index] = 0; -} - -void CMemLockBlocks::Free(CMemBlockManagerMt *memManager) -{ - while (Blocks.Size() > 0) - { - FreeBlock(Blocks.Size() - 1, memManager); - Blocks.DeleteBack(); - } - TotalSize = 0; -} - -HRes CMemLockBlocks::SwitchToNoLockMode(CMemBlockManagerMt *memManager) -{ - if (LockMode) - { - if (Blocks.Size() > 0) - { - RINOK(memManager->ReleaseLockedBlocks(Blocks.Size())); - } - LockMode = false; - } - return 0; -} - -void CMemLockBlocks::Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager) -{ - blocks.Free(memManager); - blocks.LockMode = LockMode; - UInt64 totalSize = 0; - size_t blockSize = memManager->GetBlockSize(); - FOR_VECTOR (i, Blocks) - { - if (totalSize < TotalSize) - blocks.Blocks.Add(Blocks[i]); - else - FreeBlock(i, memManager); - Blocks[i] = 0; - totalSize += blockSize; - } - blocks.TotalSize = TotalSize; - Free(memManager); -} +// MemBlocks.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "MemBlocks.h" +#include "StreamUtils.h" + +bool CMemBlockManager::AllocateSpace(size_t numBlocks) +{ + FreeSpace(); + if (_blockSize < sizeof(void *) || numBlocks < 1) + return false; + size_t totalSize = numBlocks * _blockSize; + if (totalSize / _blockSize != numBlocks) + return false; + _data = ::MidAlloc(totalSize); + if (_data == 0) + return false; + Byte *p = (Byte *)_data; + for (size_t i = 0; i + 1 < numBlocks; i++, p += _blockSize) + *(Byte **)p = (p + _blockSize); + *(Byte **)p = 0; + _headFree = _data; + return true; +} + +void CMemBlockManager::FreeSpace() +{ + ::MidFree(_data); + _data = 0; + _headFree= 0; +} + +void *CMemBlockManager::AllocateBlock() +{ + if (_headFree == 0) + return 0; + void *p = _headFree; + _headFree = *(void **)_headFree; + return p; +} + +void CMemBlockManager::FreeBlock(void *p) +{ + if (p == 0) + return; + *(void **)p = _headFree; + _headFree = p; +} + + +HRes CMemBlockManagerMt::AllocateSpace(size_t numBlocks, size_t numNoLockBlocks) +{ + if (numNoLockBlocks > numBlocks) + return E_INVALIDARG; + if (!CMemBlockManager::AllocateSpace(numBlocks)) + return E_OUTOFMEMORY; + size_t numLockBlocks = numBlocks - numNoLockBlocks; + Semaphore.Close(); + return Semaphore.Create((LONG)numLockBlocks, (LONG)numLockBlocks); +} + +HRes CMemBlockManagerMt::AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks) +{ + if (numNoLockBlocks > desiredNumberOfBlocks) + return E_INVALIDARG; + for (;;) + { + if (AllocateSpace(desiredNumberOfBlocks, numNoLockBlocks) == 0) + return 0; + if (desiredNumberOfBlocks == numNoLockBlocks) + return E_OUTOFMEMORY; + desiredNumberOfBlocks = numNoLockBlocks + ((desiredNumberOfBlocks - numNoLockBlocks) >> 1); + } +} + +void CMemBlockManagerMt::FreeSpace() +{ + Semaphore.Close(); + CMemBlockManager::FreeSpace(); +} + +void *CMemBlockManagerMt::AllocateBlock() +{ + // Semaphore.Lock(); + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + return CMemBlockManager::AllocateBlock(); +} + +void CMemBlockManagerMt::FreeBlock(void *p, bool lockMode) +{ + if (p == 0) + return; + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + CMemBlockManager::FreeBlock(p); + } + if (lockMode) + Semaphore.Release(); +} + +void CMemBlocks::Free(CMemBlockManagerMt *manager) +{ + while (Blocks.Size() > 0) + { + manager->FreeBlock(Blocks.Back()); + Blocks.DeleteBack(); + } + TotalSize = 0; +} + +void CMemBlocks::FreeOpt(CMemBlockManagerMt *manager) +{ + Free(manager); + Blocks.ClearAndFree(); +} + +HRESULT CMemBlocks::WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const +{ + UInt64 totalSize = TotalSize; + for (unsigned blockIndex = 0; totalSize > 0; blockIndex++) + { + UInt32 curSize = (UInt32)blockSize; + if (totalSize < curSize) + curSize = (UInt32)totalSize; + if (blockIndex >= Blocks.Size()) + return E_FAIL; + RINOK(WriteStream(outStream, Blocks[blockIndex], curSize)); + totalSize -= curSize; + } + return S_OK; +} + + +void CMemLockBlocks::FreeBlock(int index, CMemBlockManagerMt *memManager) +{ + memManager->FreeBlock(Blocks[index], LockMode); + Blocks[index] = 0; +} + +void CMemLockBlocks::Free(CMemBlockManagerMt *memManager) +{ + while (Blocks.Size() > 0) + { + FreeBlock(Blocks.Size() - 1, memManager); + Blocks.DeleteBack(); + } + TotalSize = 0; +} + +HRes CMemLockBlocks::SwitchToNoLockMode(CMemBlockManagerMt *memManager) +{ + if (LockMode) + { + if (Blocks.Size() > 0) + { + RINOK(memManager->ReleaseLockedBlocks(Blocks.Size())); + } + LockMode = false; + } + return 0; +} + +void CMemLockBlocks::Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager) +{ + blocks.Free(memManager); + blocks.LockMode = LockMode; + UInt64 totalSize = 0; + size_t blockSize = memManager->GetBlockSize(); + FOR_VECTOR (i, Blocks) + { + if (totalSize < TotalSize) + blocks.Blocks.Add(Blocks[i]); + else + FreeBlock(i, memManager); + Blocks[i] = 0; + totalSize += blockSize; + } + blocks.TotalSize = TotalSize; + Free(memManager); +} diff --git a/CPP/7zip/Common/MemBlocks.h b/CPP/7zip/Common/MemBlocks.h index 1602a2da6..ec56c14db 100644 --- a/CPP/7zip/Common/MemBlocks.h +++ b/CPP/7zip/Common/MemBlocks.h @@ -1,71 +1,71 @@ -// MemBlocks.h - -#ifndef __MEM_BLOCKS_H -#define __MEM_BLOCKS_H - -#include "../../Common/MyVector.h" - -#include "../../Windows/Synchronization.h" - -#include "../IStream.h" - -class CMemBlockManager -{ - void *_data; - size_t _blockSize; - void *_headFree; -public: - CMemBlockManager(size_t blockSize = (1 << 20)): _data(0), _blockSize(blockSize), _headFree(0) {} - ~CMemBlockManager() { FreeSpace(); } - - bool AllocateSpace(size_t numBlocks); - void FreeSpace(); - size_t GetBlockSize() const { return _blockSize; } - void *AllocateBlock(); - void FreeBlock(void *p); -}; - - -class CMemBlockManagerMt: public CMemBlockManager -{ - NWindows::NSynchronization::CCriticalSection _criticalSection; -public: - NWindows::NSynchronization::CSemaphore Semaphore; - - CMemBlockManagerMt(size_t blockSize = (1 << 20)): CMemBlockManager(blockSize) {} - ~CMemBlockManagerMt() { FreeSpace(); } - - HRes AllocateSpace(size_t numBlocks, size_t numNoLockBlocks = 0); - HRes AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks = 0); - void FreeSpace(); - void *AllocateBlock(); - void FreeBlock(void *p, bool lockMode = true); - HRes ReleaseLockedBlocks(int number) { return Semaphore.Release(number); } -}; - - -class CMemBlocks -{ - void Free(CMemBlockManagerMt *manager); -public: - CRecordVector Blocks; - UInt64 TotalSize; - - CMemBlocks(): TotalSize(0) {} - - void FreeOpt(CMemBlockManagerMt *manager); - HRESULT WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const; -}; - -struct CMemLockBlocks: public CMemBlocks -{ - bool LockMode; - - CMemLockBlocks(): LockMode(true) {}; - void Free(CMemBlockManagerMt *memManager); - void FreeBlock(int index, CMemBlockManagerMt *memManager); - HRes SwitchToNoLockMode(CMemBlockManagerMt *memManager); - void Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager); -}; - -#endif +// MemBlocks.h + +#ifndef __MEM_BLOCKS_H +#define __MEM_BLOCKS_H + +#include "../../Common/MyVector.h" + +#include "../../Windows/Synchronization.h" + +#include "../IStream.h" + +class CMemBlockManager +{ + void *_data; + size_t _blockSize; + void *_headFree; +public: + CMemBlockManager(size_t blockSize = (1 << 20)): _data(0), _blockSize(blockSize), _headFree(0) {} + ~CMemBlockManager() { FreeSpace(); } + + bool AllocateSpace(size_t numBlocks); + void FreeSpace(); + size_t GetBlockSize() const { return _blockSize; } + void *AllocateBlock(); + void FreeBlock(void *p); +}; + + +class CMemBlockManagerMt: public CMemBlockManager +{ + NWindows::NSynchronization::CCriticalSection _criticalSection; +public: + NWindows::NSynchronization::CSemaphore Semaphore; + + CMemBlockManagerMt(size_t blockSize = (1 << 20)): CMemBlockManager(blockSize) {} + ~CMemBlockManagerMt() { FreeSpace(); } + + HRes AllocateSpace(size_t numBlocks, size_t numNoLockBlocks = 0); + HRes AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks = 0); + void FreeSpace(); + void *AllocateBlock(); + void FreeBlock(void *p, bool lockMode = true); + HRes ReleaseLockedBlocks(int number) { return Semaphore.Release(number); } +}; + + +class CMemBlocks +{ + void Free(CMemBlockManagerMt *manager); +public: + CRecordVector Blocks; + UInt64 TotalSize; + + CMemBlocks(): TotalSize(0) {} + + void FreeOpt(CMemBlockManagerMt *manager); + HRESULT WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const; +}; + +struct CMemLockBlocks: public CMemBlocks +{ + bool LockMode; + + CMemLockBlocks(): LockMode(true) {}; + void Free(CMemBlockManagerMt *memManager); + void FreeBlock(int index, CMemBlockManagerMt *memManager); + HRes SwitchToNoLockMode(CMemBlockManagerMt *memManager); + void Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager); +}; + +#endif diff --git a/CPP/7zip/Common/MethodId.cpp b/CPP/7zip/Common/MethodId.cpp index 9a07e4c9a..1566c97c1 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 1ba9f49af..28b615fcd 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 __7Z_METHOD_ID_H +#define __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 2935e6daa..b00d0e822 100644 --- a/CPP/7zip/Common/MethodProps.cpp +++ b/CPP/7zip/Common/MethodProps.cpp @@ -1,523 +1,523 @@ -// 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" }, - { VT_UI4, "strat" }, - { VT_UI4, "fast" }, - { VT_UI4, "long" }, - { VT_UI4, "wlog" }, - { VT_UI4, "hlog" }, - { VT_UI4, "clog" }, - { VT_UI4, "slog" }, - { VT_UI4, "slen" }, - { VT_UI4, "tlen" }, - { VT_UI4, "ovlog" }, - { VT_UI4, "ldmhlog" }, - { VT_UI4, "ldmslen" }, - { VT_UI4, "ldmblog" }, - { VT_UI4, "ldmhevery" } -}; - -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 ¶m, 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 ¶m = 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; + +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" }, + { VT_UI4, "strat" }, + { VT_UI4, "fast" }, + { VT_UI4, "long" }, + { VT_UI4, "wlog" }, + { VT_UI4, "hlog" }, + { VT_UI4, "clog" }, + { VT_UI4, "slog" }, + { VT_UI4, "slen" }, + { VT_UI4, "tlen" }, + { VT_UI4, "ovlog" }, + { VT_UI4, "ldmhlog" }, + { VT_UI4, "ldmslen" }, + { VT_UI4, "ldmblog" }, + { VT_UI4, "ldmhevery" } +}; + +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 ¶m, 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 ¶m = 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); +} diff --git a/CPP/7zip/Common/MethodProps.h b/CPP/7zip/Common/MethodProps.h index c8a3d0dc3..395808812 100644 --- a/CPP/7zip/Common/MethodProps.h +++ b/CPP/7zip/Common/MethodProps.h @@ -1,264 +1,264 @@ -// 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 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 __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 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 diff --git a/CPP/7zip/Common/OffsetStream.cpp b/CPP/7zip/Common/OffsetStream.cpp index 3b01c7f65..368d39b65 100644 --- a/CPP/7zip/Common/OffsetStream.cpp +++ b/CPP/7zip/Common/OffsetStream.cpp @@ -1,39 +1,39 @@ -// 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 "../../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); +} diff --git a/CPP/7zip/Common/OffsetStream.h b/CPP/7zip/Common/OffsetStream.h index ad835f2df..9074a24e0 100644 --- a/CPP/7zip/Common/OffsetStream.h +++ b/CPP/7zip/Common/OffsetStream.h @@ -1,26 +1,26 @@ -// 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 _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 __OFFSET_STREAM_H +#define __OFFSET_STREAM_H + +#include "../../Common/MyCom.h" + +#include "../IStream.h" + +class COffsetOutStream: + public IOutStream, + public CMyUnknownImp +{ + UInt64 _offset; + CMyComPtr _stream; +public: + HRESULT Init(IOutStream *stream, UInt64 offset); + + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); + STDMETHOD(SetSize)(UInt64 newSize); +}; + +#endif diff --git a/CPP/7zip/Common/OutBuffer.cpp b/CPP/7zip/Common/OutBuffer.cpp index fb8dc8d16..4ba34a053 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 != 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 +} diff --git a/CPP/7zip/Common/OutBuffer.h b/CPP/7zip/Common/OutBuffer.h index 2ffb5cd32..d7ca9f6a2 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 __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 diff --git a/CPP/7zip/Common/OutMemStream.cpp b/CPP/7zip/Common/OutMemStream.cpp index 32bd3f665..768c2d45f 100644 --- a/CPP/7zip/Common/OutMemStream.cpp +++ b/CPP/7zip/Common/OutMemStream.cpp @@ -1,142 +1,142 @@ -// OutMemStream.cpp - -#include "StdAfx.h" - -#include "OutMemStream.h" - -void COutMemStream::Free() -{ - Blocks.Free(_memManager); - Blocks.LockMode = true; -} - -void COutMemStream::Init() -{ - WriteToRealStreamEvent.Reset(); - _unlockEventWasSent = false; - _realStreamMode = false; - Free(); - _curBlockPos = 0; - _curBlockIndex = 0; -} - -void COutMemStream::DetachData(CMemLockBlocks &blocks) -{ - Blocks.Detach(blocks, _memManager); - Free(); -} - - -HRESULT COutMemStream::WriteToRealStream() -{ - RINOK(Blocks.WriteToStream(_memManager->GetBlockSize(), OutSeqStream)); - Blocks.Free(_memManager); - return S_OK; -} - -STDMETHODIMP COutMemStream::Write(const void *data, UInt32 size, UInt32 *processedSize) -{ - if (_realStreamMode) - return OutSeqStream->Write(data, size, processedSize); - if (processedSize != 0) - *processedSize = 0; - while (size != 0) - { - if (_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 != 0) - *processedSize += (UInt32)curSize; - data = (const void *)((const Byte *)data + curSize); - size -= (UInt32)curSize; - _curBlockPos += curSize; - - UInt64 pos64 = GetPos(); - if (pos64 > Blocks.TotalSize) - Blocks.TotalSize = pos64; - if (_curBlockPos == _memManager->GetBlockSize()) - { - _curBlockIndex++; - _curBlockPos = 0; - } - continue; - } - HANDLE events[3] = { StopWritingEvent, WriteToRealStreamEvent, /* NoLockEvent, */ _memManager->Semaphore }; - DWORD waitResult = ::WaitForMultipleObjects((Blocks.LockMode ? 3 : 2), events, FALSE, INFINITE); - switch (waitResult) - { - case (WAIT_OBJECT_0 + 0): - return StopWriteResult; - case (WAIT_OBJECT_0 + 1): - { - _realStreamMode = true; - RINOK(WriteToRealStream()); - UInt32 processedSize2; - HRESULT res = OutSeqStream->Write(data, size, &processedSize2); - if (processedSize != 0) - *processedSize += processedSize2; - return res; - } - /* - case (WAIT_OBJECT_0 + 2): - { - // it has bug: no write. - if (!Blocks.SwitchToNoLockMode(_memManager)) - return E_FAIL; - break; - } - */ - case (WAIT_OBJECT_0 + 2): - break; - default: - return E_FAIL; - } - Blocks.Blocks.Add(_memManager->AllocateBlock()); - if (Blocks.Blocks.Back() == 0) - return E_FAIL; - } - return S_OK; -} - -STDMETHODIMP COutMemStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) -{ - if (_realStreamMode) - { - if (!OutStream) - return E_FAIL; - return OutStream->Seek(offset, seekOrigin, newPosition); - } - if (seekOrigin == STREAM_SEEK_CUR) - { - if (offset != 0) - return E_NOTIMPL; - } - else if (seekOrigin == STREAM_SEEK_SET) - { - if (offset != 0) - return E_NOTIMPL; - _curBlockIndex = 0; - _curBlockPos = 0; - } - else - return E_NOTIMPL; - if (newPosition) - *newPosition = GetPos(); - return S_OK; -} - -STDMETHODIMP COutMemStream::SetSize(UInt64 newSize) -{ - if (_realStreamMode) - { - if (!OutStream) - return E_FAIL; - return OutStream->SetSize(newSize); - } - Blocks.TotalSize = newSize; - return S_OK; -} +// OutMemStream.cpp + +#include "StdAfx.h" + +#include "OutMemStream.h" + +void COutMemStream::Free() +{ + Blocks.Free(_memManager); + Blocks.LockMode = true; +} + +void COutMemStream::Init() +{ + WriteToRealStreamEvent.Reset(); + _unlockEventWasSent = false; + _realStreamMode = false; + Free(); + _curBlockPos = 0; + _curBlockIndex = 0; +} + +void COutMemStream::DetachData(CMemLockBlocks &blocks) +{ + Blocks.Detach(blocks, _memManager); + Free(); +} + + +HRESULT COutMemStream::WriteToRealStream() +{ + RINOK(Blocks.WriteToStream(_memManager->GetBlockSize(), OutSeqStream)); + Blocks.Free(_memManager); + return S_OK; +} + +STDMETHODIMP COutMemStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + if (_realStreamMode) + return OutSeqStream->Write(data, size, processedSize); + if (processedSize != 0) + *processedSize = 0; + while (size != 0) + { + if (_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 != 0) + *processedSize += (UInt32)curSize; + data = (const void *)((const Byte *)data + curSize); + size -= (UInt32)curSize; + _curBlockPos += curSize; + + UInt64 pos64 = GetPos(); + if (pos64 > Blocks.TotalSize) + Blocks.TotalSize = pos64; + if (_curBlockPos == _memManager->GetBlockSize()) + { + _curBlockIndex++; + _curBlockPos = 0; + } + continue; + } + HANDLE events[3] = { StopWritingEvent, WriteToRealStreamEvent, /* NoLockEvent, */ _memManager->Semaphore }; + DWORD waitResult = ::WaitForMultipleObjects((Blocks.LockMode ? 3 : 2), events, FALSE, INFINITE); + switch (waitResult) + { + case (WAIT_OBJECT_0 + 0): + return StopWriteResult; + case (WAIT_OBJECT_0 + 1): + { + _realStreamMode = true; + RINOK(WriteToRealStream()); + UInt32 processedSize2; + HRESULT res = OutSeqStream->Write(data, size, &processedSize2); + if (processedSize != 0) + *processedSize += processedSize2; + return res; + } + /* + case (WAIT_OBJECT_0 + 2): + { + // it has bug: no write. + if (!Blocks.SwitchToNoLockMode(_memManager)) + return E_FAIL; + break; + } + */ + case (WAIT_OBJECT_0 + 2): + break; + default: + return E_FAIL; + } + Blocks.Blocks.Add(_memManager->AllocateBlock()); + if (Blocks.Blocks.Back() == 0) + return E_FAIL; + } + return S_OK; +} + +STDMETHODIMP COutMemStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) +{ + if (_realStreamMode) + { + if (!OutStream) + return E_FAIL; + return OutStream->Seek(offset, seekOrigin, newPosition); + } + if (seekOrigin == STREAM_SEEK_CUR) + { + if (offset != 0) + return E_NOTIMPL; + } + else if (seekOrigin == STREAM_SEEK_SET) + { + if (offset != 0) + return E_NOTIMPL; + _curBlockIndex = 0; + _curBlockPos = 0; + } + else + return E_NOTIMPL; + if (newPosition) + *newPosition = GetPos(); + return S_OK; +} + +STDMETHODIMP COutMemStream::SetSize(UInt64 newSize) +{ + if (_realStreamMode) + { + if (!OutStream) + return E_FAIL; + return OutStream->SetSize(newSize); + } + Blocks.TotalSize = newSize; + return S_OK; +} diff --git a/CPP/7zip/Common/OutMemStream.h b/CPP/7zip/Common/OutMemStream.h index 88fdf4dcc..0a892c522 100644 --- a/CPP/7zip/Common/OutMemStream.h +++ b/CPP/7zip/Common/OutMemStream.h @@ -1,97 +1,97 @@ -// OutMemStream.h - -#ifndef __OUT_MEM_STREAM_H -#define __OUT_MEM_STREAM_H - -#include "../../Common/MyCom.h" - -#include "MemBlocks.h" - -class COutMemStream: - public IOutStream, - public CMyUnknownImp -{ - CMemBlockManagerMt *_memManager; - unsigned _curBlockIndex; - size_t _curBlockPos; - bool _realStreamMode; - - bool _unlockEventWasSent; - NWindows::NSynchronization::CAutoResetEvent StopWritingEvent; - NWindows::NSynchronization::CAutoResetEvent WriteToRealStreamEvent; - // NWindows::NSynchronization::CAutoResetEvent NoLockEvent; - - HRESULT StopWriteResult; - CMemLockBlocks Blocks; - - UInt64 GetPos() const { return (UInt64)_curBlockIndex * _memManager->GetBlockSize() + _curBlockPos; } - - CMyComPtr OutSeqStream; - CMyComPtr OutStream; - -public: - - HRes CreateEvents() - { - RINOK(StopWritingEvent.CreateIfNotCreated()); - return WriteToRealStreamEvent.CreateIfNotCreated(); - } - - void SetOutStream(IOutStream *outStream) - { - OutStream = outStream; - OutSeqStream = outStream; - } - - void SetSeqOutStream(ISequentialOutStream *outStream) - { - OutStream = NULL; - OutSeqStream = outStream; - } - - void ReleaseOutStream() - { - OutStream.Release(); - OutSeqStream.Release(); - } - - COutMemStream(CMemBlockManagerMt *memManager): _memManager(memManager) { } - - ~COutMemStream() { Free(); } - void Free(); - - void Init(); - HRESULT WriteToRealStream(); - - void DetachData(CMemLockBlocks &blocks); - - bool WasUnlockEventSent() const { return _unlockEventWasSent; } - - void SetRealStreamMode() - { - _unlockEventWasSent = true; - WriteToRealStreamEvent.Set(); - } - - /* - void SetNoLockMode() - { - _unlockEventWasSent = true; - NoLockEvent.Set(); - } - */ - - void StopWriting(HRESULT res) - { - StopWriteResult = res; - StopWritingEvent.Set(); - } - - MY_UNKNOWN_IMP - - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); - STDMETHOD(SetSize)(UInt64 newSize); -}; - -#endif +// OutMemStream.h + +#ifndef __OUT_MEM_STREAM_H +#define __OUT_MEM_STREAM_H + +#include "../../Common/MyCom.h" + +#include "MemBlocks.h" + +class COutMemStream: + public IOutStream, + public CMyUnknownImp +{ + CMemBlockManagerMt *_memManager; + unsigned _curBlockIndex; + size_t _curBlockPos; + bool _realStreamMode; + + bool _unlockEventWasSent; + NWindows::NSynchronization::CAutoResetEvent StopWritingEvent; + NWindows::NSynchronization::CAutoResetEvent WriteToRealStreamEvent; + // NWindows::NSynchronization::CAutoResetEvent NoLockEvent; + + HRESULT StopWriteResult; + CMemLockBlocks Blocks; + + UInt64 GetPos() const { return (UInt64)_curBlockIndex * _memManager->GetBlockSize() + _curBlockPos; } + + CMyComPtr OutSeqStream; + CMyComPtr OutStream; + +public: + + HRes CreateEvents() + { + RINOK(StopWritingEvent.CreateIfNotCreated()); + return WriteToRealStreamEvent.CreateIfNotCreated(); + } + + void SetOutStream(IOutStream *outStream) + { + OutStream = outStream; + OutSeqStream = outStream; + } + + void SetSeqOutStream(ISequentialOutStream *outStream) + { + OutStream = NULL; + OutSeqStream = outStream; + } + + void ReleaseOutStream() + { + OutStream.Release(); + OutSeqStream.Release(); + } + + COutMemStream(CMemBlockManagerMt *memManager): _memManager(memManager) { } + + ~COutMemStream() { Free(); } + void Free(); + + void Init(); + HRESULT WriteToRealStream(); + + void DetachData(CMemLockBlocks &blocks); + + bool WasUnlockEventSent() const { return _unlockEventWasSent; } + + void SetRealStreamMode() + { + _unlockEventWasSent = true; + WriteToRealStreamEvent.Set(); + } + + /* + void SetNoLockMode() + { + _unlockEventWasSent = true; + NoLockEvent.Set(); + } + */ + + void StopWriting(HRESULT res) + { + StopWriteResult = res; + StopWritingEvent.Set(); + } + + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); + STDMETHOD(SetSize)(UInt64 newSize); +}; + +#endif diff --git a/CPP/7zip/Common/ProgressMt.cpp b/CPP/7zip/Common/ProgressMt.cpp index e1e7f38e0..319bd241b 100644 --- a/CPP/7zip/Common/ProgressMt.cpp +++ b/CPP/7zip/Common/ProgressMt.cpp @@ -1,53 +1,53 @@ -// ProgressMt.h - -#include "StdAfx.h" - -#include "ProgressMt.h" - -void CMtCompressProgressMixer::Init(int numItems, ICompressProgressInfo *progress) -{ - NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); - InSizes.Clear(); - OutSizes.Clear(); - for (int i = 0; i < numItems; i++) - { - InSizes.Add(0); - OutSizes.Add(0); - } - TotalInSize = 0; - TotalOutSize = 0; - _progress = progress; -} - -void CMtCompressProgressMixer::Reinit(int index) -{ - NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); - InSizes[index] = 0; - OutSizes[index] = 0; -} - -HRESULT CMtCompressProgressMixer::SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize) -{ - NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); - if (inSize != 0) - { - UInt64 diff = *inSize - InSizes[index]; - InSizes[index] = *inSize; - TotalInSize += diff; - } - if (outSize != 0) - { - UInt64 diff = *outSize - OutSizes[index]; - OutSizes[index] = *outSize; - TotalOutSize += diff; - } - if (_progress) - return _progress->SetRatioInfo(&TotalInSize, &TotalOutSize); - return S_OK; -} - - -STDMETHODIMP CMtCompressProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) -{ - return _progress->SetRatioInfo(_index, inSize, outSize); -} +// ProgressMt.h + +#include "StdAfx.h" + +#include "ProgressMt.h" + +void CMtCompressProgressMixer::Init(int numItems, ICompressProgressInfo *progress) +{ + NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); + InSizes.Clear(); + OutSizes.Clear(); + for (int i = 0; i < numItems; i++) + { + InSizes.Add(0); + OutSizes.Add(0); + } + TotalInSize = 0; + TotalOutSize = 0; + _progress = progress; +} + +void CMtCompressProgressMixer::Reinit(int index) +{ + NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); + InSizes[index] = 0; + OutSizes[index] = 0; +} + +HRESULT CMtCompressProgressMixer::SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize) +{ + NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); + if (inSize != 0) + { + UInt64 diff = *inSize - InSizes[index]; + InSizes[index] = *inSize; + TotalInSize += diff; + } + if (outSize != 0) + { + UInt64 diff = *outSize - OutSizes[index]; + OutSizes[index] = *outSize; + TotalOutSize += diff; + } + if (_progress) + return _progress->SetRatioInfo(&TotalInSize, &TotalOutSize); + return S_OK; +} + + +STDMETHODIMP CMtCompressProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + return _progress->SetRatioInfo(_index, inSize, outSize); +} diff --git a/CPP/7zip/Common/ProgressMt.h b/CPP/7zip/Common/ProgressMt.h index 4eeb02aa0..26079d4e9 100644 --- a/CPP/7zip/Common/ProgressMt.h +++ b/CPP/7zip/Common/ProgressMt.h @@ -1,46 +1,46 @@ -// ProgressMt.h - -#ifndef __PROGRESSMT_H -#define __PROGRESSMT_H - -#include "../../Common/MyCom.h" -#include "../../Common/MyVector.h" -#include "../../Windows/Synchronization.h" - -#include "../ICoder.h" -#include "../IProgress.h" - -class CMtCompressProgressMixer -{ - CMyComPtr _progress; - CRecordVector InSizes; - CRecordVector OutSizes; - UInt64 TotalInSize; - UInt64 TotalOutSize; -public: - NWindows::NSynchronization::CCriticalSection CriticalSection; - void Init(int numItems, ICompressProgressInfo *progress); - void Reinit(int index); - HRESULT SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize); -}; - -class CMtCompressProgress: - public ICompressProgressInfo, - public CMyUnknownImp -{ - CMtCompressProgressMixer *_progress; - int _index; -public: - void Init(CMtCompressProgressMixer *progress, int index) - { - _progress = progress; - _index = index; - } - void Reinit() { _progress->Reinit(_index); } - - MY_UNKNOWN_IMP - - STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); -}; - -#endif +// ProgressMt.h + +#ifndef __PROGRESSMT_H +#define __PROGRESSMT_H + +#include "../../Common/MyCom.h" +#include "../../Common/MyVector.h" +#include "../../Windows/Synchronization.h" + +#include "../ICoder.h" +#include "../IProgress.h" + +class CMtCompressProgressMixer +{ + CMyComPtr _progress; + CRecordVector InSizes; + CRecordVector OutSizes; + UInt64 TotalInSize; + UInt64 TotalOutSize; +public: + NWindows::NSynchronization::CCriticalSection CriticalSection; + void Init(int numItems, ICompressProgressInfo *progress); + void Reinit(int index); + HRESULT SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize); +}; + +class CMtCompressProgress: + public ICompressProgressInfo, + public CMyUnknownImp +{ + CMtCompressProgressMixer *_progress; + int _index; +public: + void Init(CMtCompressProgressMixer *progress, int index) + { + _progress = progress; + _index = index; + } + void Reinit() { _progress->Reinit(_index); } + + MY_UNKNOWN_IMP + + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); +}; + +#endif diff --git a/CPP/7zip/Common/ProgressUtils.cpp b/CPP/7zip/Common/ProgressUtils.cpp index 86f1e7826..41385ccb1 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(): + 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); +} diff --git a/CPP/7zip/Common/ProgressUtils.h b/CPP/7zip/Common/ProgressUtils.h index 176e8bb43..e94265ba7 100644 --- a/CPP/7zip/Common/ProgressUtils.h +++ b/CPP/7zip/Common/ProgressUtils.h @@ -1,35 +1,35 @@ -// 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 _progress; - CMyComPtr _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 __PROGRESS_UTILS_H +#define __PROGRESS_UTILS_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" +#include "../IProgress.h" + +class CLocalProgress: + public ICompressProgressInfo, + public CMyUnknownImp +{ + CMyComPtr _progress; + CMyComPtr _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 diff --git a/CPP/7zip/Common/PropId.cpp b/CPP/7zip/Common/PropId.cpp index 96f8f0564..11d20d557 100644 --- a/CPP/7zip/Common/PropId.cpp +++ b/CPP/7zip/Common/PropId.cpp @@ -1,108 +1,108 @@ -// 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 +}; diff --git a/CPP/7zip/Common/RegisterArc.h b/CPP/7zip/Common/RegisterArc.h index 08aa2d478..3421ba1b1 100644 --- a/CPP/7zip/Common/RegisterArc.h +++ b/CPP/7zip/Common/RegisterArc.h @@ -1,78 +1,78 @@ -// 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 __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 diff --git a/CPP/7zip/Common/RegisterCodec.h b/CPP/7zip/Common/RegisterCodec.h index 7b52b9272..7ddb7604b 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 __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 diff --git a/CPP/7zip/Common/StdAfx.h b/CPP/7zip/Common/StdAfx.h index 42a088f12..1cbd7feae 100644 --- a/CPP/7zip/Common/StdAfx.h +++ b/CPP/7zip/Common/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Common/StreamBinder.cpp b/CPP/7zip/Common/StreamBinder.cpp index a6627db21..435440c66 100644 --- a/CPP/7zip/Common/StreamBinder.cpp +++ b/CPP/7zip/Common/StreamBinder.cpp @@ -1,156 +1,156 @@ -// 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 inStreamLoc(inStreamSpec); - *inStream = inStreamLoc.Detach(); - - CBinderOutStream *outStreamSpec = new CBinderOutStream(this); - CMyComPtr 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" + +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 inStreamLoc(inStreamSpec); + *inStream = inStreamLoc.Detach(); + + CBinderOutStream *outStreamSpec = new CBinderOutStream(this); + CMyComPtr 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; +} diff --git a/CPP/7zip/Common/StreamBinder.h b/CPP/7zip/Common/StreamBinder.h index f4d4f3b42..12088a945 100644 --- a/CPP/7zip/Common/StreamBinder.h +++ b/CPP/7zip/Common/StreamBinder.h @@ -1,60 +1,60 @@ -// 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 __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 diff --git a/CPP/7zip/Common/StreamObjects.cpp b/CPP/7zip/Common/StreamObjects.cpp index 4cd9cc65b..8136716d6 100644 --- a/CPP/7zip/Common/StreamObjects.cpp +++ b/CPP/7zip/Common/StreamObjects.cpp @@ -1,285 +1,285 @@ -// StreamObjects.cpp - -#include "StdAfx.h" - -#include - -#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 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 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 + +#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 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 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; +} diff --git a/CPP/7zip/Common/StreamObjects.h b/CPP/7zip/Common/StreamObjects.h index c3e083747..e20e9bd80 100644 --- a/CPP/7zip/Common/StreamObjects.h +++ b/CPP/7zip/Common/StreamObjects.h @@ -1,157 +1,157 @@ -// 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 _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 _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 __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 _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 _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 diff --git a/CPP/7zip/Common/StreamUtils.cpp b/CPP/7zip/Common/StreamUtils.cpp index a79de2352..1402f4205 100644 --- a/CPP/7zip/Common/StreamUtils.cpp +++ b/CPP/7zip/Common/StreamUtils.cpp @@ -1,56 +1,56 @@ -// StreamUtils.cpp - -#include "StdAfx.h" - -#include "StreamUtils.h" - -static const UInt32 kBlockSize = ((UInt32)1 << 31); - -HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *processedSize) 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 "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; +} diff --git a/CPP/7zip/Common/StreamUtils.h b/CPP/7zip/Common/StreamUtils.h index 799a8b9db..ae914c004 100644 --- a/CPP/7zip/Common/StreamUtils.h +++ b/CPP/7zip/Common/StreamUtils.h @@ -1,13 +1,13 @@ -// 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 __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 diff --git a/CPP/7zip/Common/UniqBlocks.cpp b/CPP/7zip/Common/UniqBlocks.cpp index 5baf1a495..8f754e177 100644 --- a/CPP/7zip/Common/UniqBlocks.cpp +++ b/CPP/7zip/Common/UniqBlocks.cpp @@ -1,57 +1,57 @@ -// UniqBlocks.cpp - -#include "StdAfx.h" - -#include - -#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 + +#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; +} diff --git a/CPP/7zip/Common/UniqBlocks.h b/CPP/7zip/Common/UniqBlocks.h index d9ec17da1..a376024e3 100644 --- a/CPP/7zip/Common/UniqBlocks.h +++ b/CPP/7zip/Common/UniqBlocks.h @@ -1,26 +1,26 @@ -// 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 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 __UNIQ_BLOCKS_H +#define __UNIQ_BLOCKS_H + +#include "../../Common/MyTypes.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/MyVector.h" + +struct CUniqBlocks +{ + CObjectVector 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 3cf9acd3e..77e3c1acf 100644 --- a/CPP/7zip/Common/VirtThread.cpp +++ b/CPP/7zip/Common/VirtThread.cpp @@ -1,48 +1,48 @@ -// 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 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(); + } +} diff --git a/CPP/7zip/Common/VirtThread.h b/CPP/7zip/Common/VirtThread.h index a2711036a..ebee158ca 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 __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 diff --git a/CPP/7zip/Compress/BZip2Const.h b/CPP/7zip/Compress/BZip2Const.h index b8bfd62a7..0efecba3b 100644 --- a/CPP/7zip/Compress/BZip2Const.h +++ b/CPP/7zip/Compress/BZip2Const.h @@ -1,66 +1,66 @@ -// Compress/BZip2Const.h - -#ifndef __COMPRESS_BZIP2_CONST_H -#define __COMPRESS_BZIP2_CONST_H - -namespace NCompress { -namespace NBZip2 { - -const Byte kArSig0 = 'B'; -const Byte kArSig1 = 'Z'; -const Byte kArSig2 = 'h'; -const Byte kArSig3 = '0'; - -const Byte kFinSig0 = 0x17; -const Byte kFinSig1 = 0x72; -const Byte kFinSig2 = 0x45; -const Byte kFinSig3 = 0x38; -const Byte kFinSig4 = 0x50; -const Byte kFinSig5 = 0x90; - -const Byte kBlockSig0 = 0x31; -const Byte kBlockSig1 = 0x41; -const Byte kBlockSig2 = 0x59; -const Byte kBlockSig3 = 0x26; -const Byte kBlockSig4 = 0x53; -const Byte kBlockSig5 = 0x59; - -const 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) - 7-Zip decoder doesn't support it. - bzip2 1.0.6 decoder can overflow selector[18002] arrays. But there are another - arrays after selector arrays. So the compiled code works. - lbzip2 2.5 encoder can write up to (18001 + 7) selectors. -*/ - -}} - -#endif +// Compress/BZip2Const.h + +#ifndef __COMPRESS_BZIP2_CONST_H +#define __COMPRESS_BZIP2_CONST_H + +namespace NCompress { +namespace NBZip2 { + +const Byte kArSig0 = 'B'; +const Byte kArSig1 = 'Z'; +const Byte kArSig2 = 'h'; +const Byte kArSig3 = '0'; + +const Byte kFinSig0 = 0x17; +const Byte kFinSig1 = 0x72; +const Byte kFinSig2 = 0x45; +const Byte kFinSig3 = 0x38; +const Byte kFinSig4 = 0x50; +const Byte kFinSig5 = 0x90; + +const Byte kBlockSig0 = 0x31; +const Byte kBlockSig1 = 0x41; +const Byte kBlockSig2 = 0x59; +const Byte kBlockSig3 = 0x26; +const Byte kBlockSig4 = 0x53; +const Byte kBlockSig5 = 0x59; + +const 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) + 7-Zip decoder doesn't support it. + bzip2 1.0.6 decoder can overflow selector[18002] arrays. But there are another + arrays after selector arrays. So the compiled code works. + lbzip2 2.5 encoder can write up to (18001 + 7) selectors. +*/ + +}} + +#endif diff --git a/CPP/7zip/Compress/BZip2Crc.cpp b/CPP/7zip/Compress/BZip2Crc.cpp index 9822153ef..bf8e540f6 100644 --- a/CPP/7zip/Compress/BZip2Crc.cpp +++ b/CPP/7zip/Compress/BZip2Crc.cpp @@ -1,26 +1,26 @@ -// BZip2Crc.cpp - -#include "StdAfx.h" - -#include "BZip2Crc.h" - -UInt32 CBZip2Crc::Table[256]; - -static const UInt32 kBZip2CrcPoly = 0x04c11db7; /* AUTODIN II, Ethernet, & FDDI */ - -void CBZip2Crc::InitTable() -{ - for (UInt32 i = 0; i < 256; i++) - { - UInt32 r = (i << 24); - for (unsigned j = 0; j < 8; j++) - r = (r << 1) ^ (kBZip2CrcPoly & ((UInt32)0 - (r >> 31))); - Table[i] = r; - } -} - -class CBZip2CrcTableInit -{ -public: - CBZip2CrcTableInit() { CBZip2Crc::InitTable(); } -} g_BZip2CrcTableInit; +// 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; + } +} + +class CBZip2CrcTableInit +{ +public: + CBZip2CrcTableInit() { CBZip2Crc::InitTable(); } +} g_BZip2CrcTableInit; diff --git a/CPP/7zip/Compress/BZip2Crc.h b/CPP/7zip/Compress/BZip2Crc.h index 635a0e01a..1b5755b5d 100644 --- a/CPP/7zip/Compress/BZip2Crc.h +++ b/CPP/7zip/Compress/BZip2Crc.h @@ -1,31 +1,31 @@ -// BZip2Crc.h - -#ifndef __BZIP2_CRC_H -#define __BZIP2_CRC_H - -#include "../../Common/MyTypes.h" - -class CBZip2Crc -{ - UInt32 _value; - static UInt32 Table[256]; -public: - static void InitTable(); - CBZip2Crc(): _value(0xFFFFFFFF) {}; - void Init() { _value = 0xFFFFFFFF; } - void UpdateByte(Byte b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); } - void UpdateByte(unsigned int b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); } - UInt32 GetDigest() const { return _value ^ 0xFFFFFFFF; } -}; - -class CBZip2CombinedCrc -{ - UInt32 _value; -public: - CBZip2CombinedCrc(): _value(0){}; - void Init() { _value = 0; } - void Update(UInt32 v) { _value = ((_value << 1) | (_value >> 31)) ^ v; } - UInt32 GetDigest() const { return _value ; } -}; - -#endif +// BZip2Crc.h + +#ifndef __BZIP2_CRC_H +#define __BZIP2_CRC_H + +#include "../../Common/MyTypes.h" + +class CBZip2Crc +{ + UInt32 _value; + static UInt32 Table[256]; +public: + static void InitTable(); + CBZip2Crc(): _value(0xFFFFFFFF) {}; + void Init() { _value = 0xFFFFFFFF; } + void UpdateByte(Byte b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); } + void UpdateByte(unsigned int b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); } + UInt32 GetDigest() const { return _value ^ 0xFFFFFFFF; } +}; + +class CBZip2CombinedCrc +{ + UInt32 _value; +public: + CBZip2CombinedCrc(): _value(0){}; + void Init() { _value = 0; } + void Update(UInt32 v) { _value = ((_value << 1) | (_value >> 31)) ^ v; } + UInt32 GetDigest() const { return _value ; } +}; + +#endif diff --git a/CPP/7zip/Compress/BZip2Decoder.cpp b/CPP/7zip/Compress/BZip2Decoder.cpp index 9f8f8b0ee..b414d088c 100644 --- a/CPP/7zip/Compress/BZip2Decoder.cpp +++ b/CPP/7zip/Compress/BZip2Decoder.cpp @@ -1,1745 +1,1745 @@ -// BZip2Decoder.cpp - -#include "StdAfx.h" - -// #include "CopyCoder.h" - -/* -#include -#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) - -#define PRIN_MT(s) PRIN(" " s) - -#include "../../../C/Alloc.h" - -#include "../Common/StreamUtils.h" - -#include "BZip2Decoder.h" - - -namespace NCompress { -namespace NBZip2 { - -// #undef NO_INLINE -#define NO_INLINE MY_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; - if (numSelectors == 0 || numSelectors > kNumSelectorsMax) - 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; - selectors[state3] = (Byte)tmp; - } - while (++state3 < numSelectors); - - 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; - } - - // 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++); - /* - 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 >> MTF_MOVS; - const unsigned pos = (sym & 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 >> (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 = 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 = 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 = 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(): - _inBuf(NULL), - _outBuf(NULL), - _counters(NULL), - FinishMode(false), - _outSizeDefined(false) -{ - #ifndef _7ZIP_ST - MtMode = false; - NeedWaitScout = false; - // ScoutRes = S_OK; - #endif -} - - -CDecoder::~CDecoder() -{ - PRIN("\n~CDecoder()"); - - #ifndef _7ZIP_ST - - if (Thread.IsCreated()) - { - WaitScout(); - - _block.StopScout = true; - - PRIN("\nScoutEvent.Set()"); - ScoutEvent.Set(); - - PRIN("\nThread.Wait()()"); - Thread.Wait(); - PRIN("\n after Thread.Wait()()"); - Thread.Close(); - - // 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 += (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 _7ZIP_ST - _block.StopScout = false; - #endif - } - - RINOK(StartRead()); - - UInt64 inPrev = 0; - UInt64 outPrev = 0; - - { - #ifndef _7ZIP_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 _7ZIP_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 _7ZIP_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 _7ZIP_ST - if (useMt) - { - PRIN("DecoderEvent.Lock()"); - RINOK(DecoderEvent.Lock()); - 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 _7ZIP_ST - if (useMt && !wasFinished) - { - /* - if (props.blockSize == 0) - { - // this codes switches back to single-threadMode - useMt = false; - PRIN("=== ST_MODE"); - continue; - } - */ - - PRIN("ScoutEvent.Set()"); - RINOK(ScoutEvent.Set()); - 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; - } - if (!_counters) - { - _counters = (UInt32 *)::BigAlloc((256 + kBlockSizeMax) * sizeof(UInt32) - #ifdef BZIP2_BYTE_MODE - + kBlockSizeMax - #endif - + 256); - 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(); -} - - -STDMETHODIMP 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(); - } - */ - - InitOutSize(outSize); - - _inputFinished = false; - _inputRes = S_OK; - _writeRes = S_OK; - - try { - - 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; -} - - -STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode) -{ - FinishMode = (finishMode != 0); - return S_OK; -} - - -STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) -{ - *value = GetInputProcessedSize(); - return S_OK; -} - - -#ifndef _7ZIP_ST - -#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() -{ - RINOK_THREAD(DecoderEvent.CreateIfNotCreated()); - RINOK_THREAD(ScoutEvent.CreateIfNotCreated()); - RINOK_THREAD(Thread.Create(RunScout2, this)); - return S_OK; -} - -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; - } - } -} - - -STDMETHODIMP CDecoder::SetNumberOfThreads(UInt32 numThreads) -{ - MtMode = (numThreads > 1); - - #ifndef BZIP2_BYTE_MODE - MtMode = false; - #endif - - // MtMode = false; - return S_OK; -} - -#endif - - - -#ifndef NO_READ_FROM_CODER - - -STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) -{ - Base.InStreamRef = inStream; - Base.InStream = inStream; - return S_OK; -} - - -STDMETHODIMP CDecoder::ReleaseInStream() -{ - Base.InStreamRef.Release(); - Base.InStream = NULL; - return S_OK; -} - - - -STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize) -{ - InitOutSize(outSize); - - if (!CreateInputBufer()) - return E_OUTOFMEMORY; - - InitInputBuffer(); - - StartNewStream(); - - _blockFinished = true; - - ErrorResult = S_OK; - - _inputFinished = false; - _inputRes = S_OK; - - return S_OK; -} - - - -STDMETHODIMP 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 ---------- - -STDMETHODIMP 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 - -}} +// BZip2Decoder.cpp + +#include "StdAfx.h" + +// #include "CopyCoder.h" + +/* +#include +#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) + +#define PRIN_MT(s) PRIN(" " s) + +#include "../../../C/Alloc.h" + +#include "../Common/StreamUtils.h" + +#include "BZip2Decoder.h" + + +namespace NCompress { +namespace NBZip2 { + +// #undef NO_INLINE +#define NO_INLINE MY_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; + if (numSelectors == 0 || numSelectors > kNumSelectorsMax) + 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; + selectors[state3] = (Byte)tmp; + } + while (++state3 < numSelectors); + + 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; + } + + // 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++); + /* + 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 >> MTF_MOVS; + const unsigned pos = (sym & 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 >> (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 = 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 = 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 = 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(): + _inBuf(NULL), + _outBuf(NULL), + _counters(NULL), + FinishMode(false), + _outSizeDefined(false) +{ + #ifndef _7ZIP_ST + MtMode = false; + NeedWaitScout = false; + // ScoutRes = S_OK; + #endif +} + + +CDecoder::~CDecoder() +{ + PRIN("\n~CDecoder()"); + + #ifndef _7ZIP_ST + + if (Thread.IsCreated()) + { + WaitScout(); + + _block.StopScout = true; + + PRIN("\nScoutEvent.Set()"); + ScoutEvent.Set(); + + PRIN("\nThread.Wait()()"); + Thread.Wait(); + PRIN("\n after Thread.Wait()()"); + Thread.Close(); + + // 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 += (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 _7ZIP_ST + _block.StopScout = false; + #endif + } + + RINOK(StartRead()); + + UInt64 inPrev = 0; + UInt64 outPrev = 0; + + { + #ifndef _7ZIP_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 _7ZIP_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 _7ZIP_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 _7ZIP_ST + if (useMt) + { + PRIN("DecoderEvent.Lock()"); + RINOK(DecoderEvent.Lock()); + 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 _7ZIP_ST + if (useMt && !wasFinished) + { + /* + if (props.blockSize == 0) + { + // this codes switches back to single-threadMode + useMt = false; + PRIN("=== ST_MODE"); + continue; + } + */ + + PRIN("ScoutEvent.Set()"); + RINOK(ScoutEvent.Set()); + 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; + } + if (!_counters) + { + _counters = (UInt32 *)::BigAlloc((256 + kBlockSizeMax) * sizeof(UInt32) + #ifdef BZIP2_BYTE_MODE + + kBlockSizeMax + #endif + + 256); + 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(); +} + + +STDMETHODIMP 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(); + } + */ + + InitOutSize(outSize); + + _inputFinished = false; + _inputRes = S_OK; + _writeRes = S_OK; + + try { + + 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; +} + + +STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode) +{ + FinishMode = (finishMode != 0); + return S_OK; +} + + +STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) +{ + *value = GetInputProcessedSize(); + return S_OK; +} + + +#ifndef _7ZIP_ST + +#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() +{ + RINOK_THREAD(DecoderEvent.CreateIfNotCreated()); + RINOK_THREAD(ScoutEvent.CreateIfNotCreated()); + RINOK_THREAD(Thread.Create(RunScout2, this)); + return S_OK; +} + +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; + } + } +} + + +STDMETHODIMP CDecoder::SetNumberOfThreads(UInt32 numThreads) +{ + MtMode = (numThreads > 1); + + #ifndef BZIP2_BYTE_MODE + MtMode = false; + #endif + + // MtMode = false; + return S_OK; +} + +#endif + + + +#ifndef NO_READ_FROM_CODER + + +STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) +{ + Base.InStreamRef = inStream; + Base.InStream = inStream; + return S_OK; +} + + +STDMETHODIMP CDecoder::ReleaseInStream() +{ + Base.InStreamRef.Release(); + Base.InStream = NULL; + return S_OK; +} + + + +STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize) +{ + InitOutSize(outSize); + + if (!CreateInputBufer()) + return E_OUTOFMEMORY; + + InitInputBuffer(); + + StartNewStream(); + + _blockFinished = true; + + ErrorResult = S_OK; + + _inputFinished = false; + _inputRes = S_OK; + + return S_OK; +} + + + +STDMETHODIMP 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 ---------- + +STDMETHODIMP 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 index 3430a5b81..68aa7094b 100644 --- a/CPP/7zip/Compress/BZip2Decoder.h +++ b/CPP/7zip/Compress/BZip2Decoder.h @@ -1,382 +1,382 @@ -// Compress/BZip2Decoder.h - -#ifndef __COMPRESS_BZIP2_DECODER_H -#define __COMPRESS_BZIP2_DECODER_H - -#include "../../Common/MyCom.h" - -// #define NO_READ_FROM_CODER -// #define _7ZIP_ST - -#ifndef _7ZIP_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 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); -}; - - -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]; - 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 NO_READ_FROM_CODER - CMyComPtr 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, - - #ifndef NO_READ_FROM_CODER - public ICompressSetInStream, - public ICompressSetOutStreamSize, - public ISequentialInStream, - #endif - - #ifndef _7ZIP_ST - public ICompressSetCoderMt, - #endif - - public CMyUnknownImp -{ - 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 _7ZIP_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() - { - _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 + (Base._buf - _inBuf); - } - - 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); - - MY_QUERYINTERFACE_BEGIN2(ICompressCoder) - 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 - - #ifndef _7ZIP_ST - MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt) - #endif - - MY_QUERYINTERFACE_END - MY_ADDREF_RELEASE - - - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - - STDMETHOD(SetFinishMode)(UInt32 finishMode); - STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); - - UInt64 GetNumStreams() const { return Base.NumStreams; } - UInt64 GetNumBlocks() const { return Base.NumBlocks; } - - #ifndef NO_READ_FROM_CODER - - STDMETHOD(SetInStream)(ISequentialInStream *inStream); - STDMETHOD(ReleaseInStream)(); - STDMETHOD(SetOutStreamSize)(const UInt64 *outSize); - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - - #endif - - #ifndef _7ZIP_ST - STDMETHOD(SetNumberOfThreads)(UInt32 numThreads); - #endif - - CDecoder(); - ~CDecoder(); -}; - - - -#ifndef NO_READ_FROM_CODER - -class CNsisDecoder : public CDecoder -{ -public: - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); -}; - -#endif - -}} - -#endif +// Compress/BZip2Decoder.h + +#ifndef __COMPRESS_BZIP2_DECODER_H +#define __COMPRESS_BZIP2_DECODER_H + +#include "../../Common/MyCom.h" + +// #define NO_READ_FROM_CODER +// #define _7ZIP_ST + +#ifndef _7ZIP_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 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); +}; + + +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]; + 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 NO_READ_FROM_CODER + CMyComPtr 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, + + #ifndef NO_READ_FROM_CODER + public ICompressSetInStream, + public ICompressSetOutStreamSize, + public ISequentialInStream, + #endif + + #ifndef _7ZIP_ST + public ICompressSetCoderMt, + #endif + + public CMyUnknownImp +{ + 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 _7ZIP_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() + { + _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 + (Base._buf - _inBuf); + } + + 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); + + MY_QUERYINTERFACE_BEGIN2(ICompressCoder) + 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 + + #ifndef _7ZIP_ST + MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt) + #endif + + MY_QUERYINTERFACE_END + MY_ADDREF_RELEASE + + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + STDMETHOD(SetFinishMode)(UInt32 finishMode); + STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); + + UInt64 GetNumStreams() const { return Base.NumStreams; } + UInt64 GetNumBlocks() const { return Base.NumBlocks; } + + #ifndef NO_READ_FROM_CODER + + STDMETHOD(SetInStream)(ISequentialInStream *inStream); + STDMETHOD(ReleaseInStream)(); + STDMETHOD(SetOutStreamSize)(const UInt64 *outSize); + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + + #endif + + #ifndef _7ZIP_ST + STDMETHOD(SetNumberOfThreads)(UInt32 numThreads); + #endif + + CDecoder(); + ~CDecoder(); +}; + + + +#ifndef NO_READ_FROM_CODER + +class CNsisDecoder : public CDecoder +{ +public: + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +#endif + +}} + +#endif diff --git a/CPP/7zip/Compress/BZip2Encoder.cpp b/CPP/7zip/Compress/BZip2Encoder.cpp index a1839e7d1..c9f9c6646 100644 --- a/CPP/7zip/Compress/BZip2Encoder.cpp +++ b/CPP/7zip/Compress/BZip2Encoder.cpp @@ -1,893 +1,893 @@ -// 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 == 0) - { - m_BlockSorterIndex = (UInt32 *)::BigAlloc(BLOCK_SORT_BUF_SIZE(kBlockSizeMax) * sizeof(UInt32)); - if (m_BlockSorterIndex == 0) - return false; - } - - if (m_Block == 0) - { - m_Block = (Byte *)::MidAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10)); - if (m_Block == 0) - return false; - m_MtfArray = m_Block + kBlockSizeMax; - m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2; - } - return true; -} - -void CThreadInfo::Free() -{ - ::BigFree(m_BlockSorterIndex); - m_BlockSorterIndex = 0; - ::MidFree(m_Block); - m_Block = 0; -} - -#ifndef _7ZIP_ST - -static THREAD_FUNC_DECL MFThread(void *threadCoderInfo) -{ - return ((CThreadInfo *)threadCoderInfo)->ThreadFunc(); -} - -#define RINOK_THREAD(x) { WRes __result_ = (x); if (__result_ != 0) return __result_; } - -HRESULT CThreadInfo::Create() -{ - RINOK_THREAD(StreamWasFinishedEvent.Create()); - RINOK_THREAD(WaitingWasStartedEvent.Create()); - RINOK_THREAD(CanWriteEvent.Create()); - RINOK_THREAD(Thread.Create(MFThread, this)); - return S_OK; -} - -void CThreadInfo::FinishStream(bool needLeave) -{ - Encoder->StreamWasFinished = true; - StreamWasFinishedEvent.Set(); - if (needLeave) - Encoder->CS.Leave(); - Encoder->CanStartWaitingEvent.Lock(); - WaitingWasStartedEvent.Set(); -} - -DWORD CThreadInfo::ThreadFunc() -{ - for (;;) - { - Encoder->CanProcessEvent.Lock(); - Encoder->CS.Enter(); - if (Encoder->CloseThreads) - { - Encoder->CS.Leave(); - return 0; - } - if (Encoder->StreamWasFinished) - { - FinishStream(true); - continue; - } - HRESULT res = S_OK; - bool needLeave = true; - try - { - UInt32 blockSize = Encoder->ReadRleBlock(m_Block); - m_PackSize = Encoder->m_InStream.GetProcessedSize(); - m_BlockIndex = Encoder->NextBlockIndex; - if (++Encoder->NextBlockIndex == Encoder->NumThreads) - Encoder->NextBlockIndex = 0; - if (blockSize == 0) - { - FinishStream(true); - continue; - } - Encoder->CS.Leave(); - needLeave = false; - res = EncodeBlock3(blockSize); - } - catch(const CInBufferException &e) { res = e.ErrorCode; } - catch(const COutBufferException &e) { res = e.ErrorCode; } - catch(...) { res = E_FAIL; } - if (res != S_OK) - { - Encoder->Result = res; - FinishStream(needLeave); - continue; - } - } -} - -#endif - -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 ? level * 2 - 1: 1)); - if (BlockSizeMult < kBlockSizeMultMin) BlockSizeMult = kBlockSizeMultMin; - if (BlockSizeMult > kBlockSizeMultMax) BlockSizeMult = kBlockSizeMultMax; -} - -CEncoder::CEncoder() -{ - _props.Normalize(-1); - - #ifndef _7ZIP_ST - ThreadsInfo = 0; - m_NumThreadsPrev = 0; - NumThreads = 1; - #endif -} - -#ifndef _7ZIP_ST -CEncoder::~CEncoder() -{ - Free(); -} - -HRESULT CEncoder::Create() -{ - RINOK_THREAD(CanProcessEvent.CreateIfNotCreated()); - RINOK_THREAD(CanStartWaitingEvent.CreateIfNotCreated()); - if (ThreadsInfo != 0 && m_NumThreadsPrev == NumThreads) - return S_OK; - try - { - Free(); - MtMode = (NumThreads > 1); - m_NumThreadsPrev = NumThreads; - ThreadsInfo = new CThreadInfo[NumThreads]; - if (ThreadsInfo == 0) - return E_OUTOFMEMORY; - } - catch(...) { return E_OUTOFMEMORY; } - for (UInt32 t = 0; t < NumThreads; t++) - { - CThreadInfo &ti = ThreadsInfo[t]; - ti.Encoder = this; - if (MtMode) - { - HRESULT res = ti.Create(); - if (res != S_OK) - { - NumThreads = t; - Free(); - return res; - } - } - } - return S_OK; -} - -void CEncoder::Free() -{ - if (!ThreadsInfo) - return; - CloseThreads = true; - CanProcessEvent.Set(); - for (UInt32 t = 0; t < NumThreads; t++) - { - CThreadInfo &ti = ThreadsInfo[t]; - if (MtMode) - ti.Thread.Wait(); - ti.Free(); - } - delete []ThreadsInfo; - ThreadsInfo = 0; -} -#endif - -UInt32 CEncoder::ReadRleBlock(Byte *buffer) -{ - UInt32 i = 0; - Byte prevByte; - if (m_InStream.ReadByte(prevByte)) - { - UInt32 blockSize = _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 = 0; - const UInt32 *codes = 0; - 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 _7ZIP_ST - if (Encoder->MtMode) - Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock(); - #endif - for (UInt32 i = 0; i < m_NumCrcs; i++) - Encoder->CombinedCrc.Update(m_CRCs[i]); - Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte()); - HRESULT res = S_OK; - #ifndef _7ZIP_ST - if (Encoder->MtMode) - { - UInt32 blockIndex = m_BlockIndex + 1; - if (blockIndex == Encoder->NumThreads) - blockIndex = 0; - - if (Encoder->Progress) - { - UInt64 unpackSize = Encoder->m_OutStream.GetProcessedSize(); - res = Encoder->Progress->SetRatioInfo(&m_PackSize, &unpackSize); - } - - Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set(); - } - #endif - return res; -} - -void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte) -{ - UInt32 bytesSize = (sizeInBits >> 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) -{ - #ifndef _7ZIP_ST - Progress = progress; - RINOK(Create()); - for (UInt32 t = 0; t < NumThreads; t++) - #endif - { - #ifndef _7ZIP_ST - CThreadInfo &ti = ThreadsInfo[t]; - if (MtMode) - { - RINOK(ti.StreamWasFinishedEvent.Reset()); - RINOK(ti.WaitingWasStartedEvent.Reset()); - RINOK(ti.CanWriteEvent.Reset()); - } - #else - CThreadInfo &ti = ThreadsInfo; - ti.Encoder = this; - #endif - - ti.m_OptimizeNumTables = _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 _7ZIP_ST - NextBlockIndex = 0; - StreamWasFinished = false; - CloseThreads = false; - CanStartWaitingEvent.Reset(); - #endif - - WriteByte(kArSig0); - WriteByte(kArSig1); - WriteByte(kArSig2); - WriteByte((Byte)(kArSig3 + _props.BlockSizeMult)); - - #ifndef _7ZIP_ST - - if (MtMode) - { - ThreadsInfo[0].CanWriteEvent.Set(); - Result = S_OK; - CanProcessEvent.Set(); - UInt32 t; - for (t = 0; t < NumThreads; t++) - ThreadsInfo[t].StreamWasFinishedEvent.Lock(); - CanProcessEvent.Reset(); - CanStartWaitingEvent.Set(); - for (t = 0; t < NumThreads; t++) - ThreadsInfo[t].WaitingWasStartedEvent.Lock(); - CanStartWaitingEvent.Reset(); - RINOK(Result); - } - else - #endif - { - for (;;) - { - CThreadInfo &ti = - #ifndef _7ZIP_ST - ThreadsInfo[0]; - #else - ThreadsInfo; - #endif - UInt32 blockSize = ReadRleBlock(ti.m_Block); - if (blockSize == 0) - break; - RINOK(ti.EncodeBlock3(blockSize)); - if (progress) - { - UInt64 packSize = m_InStream.GetProcessedSize(); - UInt64 unpackSize = m_OutStream.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&packSize, &unpackSize)); - } - } - } - WriteByte(kFinSig0); - WriteByte(kFinSig1); - WriteByte(kFinSig2); - WriteByte(kFinSig3); - WriteByte(kFinSig4); - WriteByte(kFinSig5); - - WriteCrc(CombinedCrc.GetDigest()); - return Flush(); -} - -STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const COutBufferException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - -HRESULT CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *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 (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 = v; break; - case NCoderPropID::kNumThreads: - { - #ifndef _7ZIP_ST - SetNumberOfThreads(v); - #endif - break; - } - default: return E_INVALIDARG; - } - } - props.Normalize(level); - _props = props; - return S_OK; -} - -#ifndef _7ZIP_ST -STDMETHODIMP CEncoder::SetNumberOfThreads(UInt32 numThreads) -{ - const UInt32 kNumThreadsMax = 64; - if (numThreads < 1) numThreads = 1; - if (numThreads > kNumThreadsMax) numThreads = kNumThreadsMax; - NumThreads = numThreads; - return S_OK; -} -#endif - -}} +// 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 == 0) + { + m_BlockSorterIndex = (UInt32 *)::BigAlloc(BLOCK_SORT_BUF_SIZE(kBlockSizeMax) * sizeof(UInt32)); + if (m_BlockSorterIndex == 0) + return false; + } + + if (m_Block == 0) + { + m_Block = (Byte *)::MidAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10)); + if (m_Block == 0) + return false; + m_MtfArray = m_Block + kBlockSizeMax; + m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2; + } + return true; +} + +void CThreadInfo::Free() +{ + ::BigFree(m_BlockSorterIndex); + m_BlockSorterIndex = 0; + ::MidFree(m_Block); + m_Block = 0; +} + +#ifndef _7ZIP_ST + +static THREAD_FUNC_DECL MFThread(void *threadCoderInfo) +{ + return ((CThreadInfo *)threadCoderInfo)->ThreadFunc(); +} + +#define RINOK_THREAD(x) { WRes __result_ = (x); if (__result_ != 0) return __result_; } + +HRESULT CThreadInfo::Create() +{ + RINOK_THREAD(StreamWasFinishedEvent.Create()); + RINOK_THREAD(WaitingWasStartedEvent.Create()); + RINOK_THREAD(CanWriteEvent.Create()); + RINOK_THREAD(Thread.Create(MFThread, this)); + return S_OK; +} + +void CThreadInfo::FinishStream(bool needLeave) +{ + Encoder->StreamWasFinished = true; + StreamWasFinishedEvent.Set(); + if (needLeave) + Encoder->CS.Leave(); + Encoder->CanStartWaitingEvent.Lock(); + WaitingWasStartedEvent.Set(); +} + +DWORD CThreadInfo::ThreadFunc() +{ + for (;;) + { + Encoder->CanProcessEvent.Lock(); + Encoder->CS.Enter(); + if (Encoder->CloseThreads) + { + Encoder->CS.Leave(); + return 0; + } + if (Encoder->StreamWasFinished) + { + FinishStream(true); + continue; + } + HRESULT res = S_OK; + bool needLeave = true; + try + { + UInt32 blockSize = Encoder->ReadRleBlock(m_Block); + m_PackSize = Encoder->m_InStream.GetProcessedSize(); + m_BlockIndex = Encoder->NextBlockIndex; + if (++Encoder->NextBlockIndex == Encoder->NumThreads) + Encoder->NextBlockIndex = 0; + if (blockSize == 0) + { + FinishStream(true); + continue; + } + Encoder->CS.Leave(); + needLeave = false; + res = EncodeBlock3(blockSize); + } + catch(const CInBufferException &e) { res = e.ErrorCode; } + catch(const COutBufferException &e) { res = e.ErrorCode; } + catch(...) { res = E_FAIL; } + if (res != S_OK) + { + Encoder->Result = res; + FinishStream(needLeave); + continue; + } + } +} + +#endif + +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 ? level * 2 - 1: 1)); + if (BlockSizeMult < kBlockSizeMultMin) BlockSizeMult = kBlockSizeMultMin; + if (BlockSizeMult > kBlockSizeMultMax) BlockSizeMult = kBlockSizeMultMax; +} + +CEncoder::CEncoder() +{ + _props.Normalize(-1); + + #ifndef _7ZIP_ST + ThreadsInfo = 0; + m_NumThreadsPrev = 0; + NumThreads = 1; + #endif +} + +#ifndef _7ZIP_ST +CEncoder::~CEncoder() +{ + Free(); +} + +HRESULT CEncoder::Create() +{ + RINOK_THREAD(CanProcessEvent.CreateIfNotCreated()); + RINOK_THREAD(CanStartWaitingEvent.CreateIfNotCreated()); + if (ThreadsInfo != 0 && m_NumThreadsPrev == NumThreads) + return S_OK; + try + { + Free(); + MtMode = (NumThreads > 1); + m_NumThreadsPrev = NumThreads; + ThreadsInfo = new CThreadInfo[NumThreads]; + if (ThreadsInfo == 0) + return E_OUTOFMEMORY; + } + catch(...) { return E_OUTOFMEMORY; } + for (UInt32 t = 0; t < NumThreads; t++) + { + CThreadInfo &ti = ThreadsInfo[t]; + ti.Encoder = this; + if (MtMode) + { + HRESULT res = ti.Create(); + if (res != S_OK) + { + NumThreads = t; + Free(); + return res; + } + } + } + return S_OK; +} + +void CEncoder::Free() +{ + if (!ThreadsInfo) + return; + CloseThreads = true; + CanProcessEvent.Set(); + for (UInt32 t = 0; t < NumThreads; t++) + { + CThreadInfo &ti = ThreadsInfo[t]; + if (MtMode) + ti.Thread.Wait(); + ti.Free(); + } + delete []ThreadsInfo; + ThreadsInfo = 0; +} +#endif + +UInt32 CEncoder::ReadRleBlock(Byte *buffer) +{ + UInt32 i = 0; + Byte prevByte; + if (m_InStream.ReadByte(prevByte)) + { + UInt32 blockSize = _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 = 0; + const UInt32 *codes = 0; + 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 _7ZIP_ST + if (Encoder->MtMode) + Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock(); + #endif + for (UInt32 i = 0; i < m_NumCrcs; i++) + Encoder->CombinedCrc.Update(m_CRCs[i]); + Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte()); + HRESULT res = S_OK; + #ifndef _7ZIP_ST + if (Encoder->MtMode) + { + UInt32 blockIndex = m_BlockIndex + 1; + if (blockIndex == Encoder->NumThreads) + blockIndex = 0; + + if (Encoder->Progress) + { + UInt64 unpackSize = Encoder->m_OutStream.GetProcessedSize(); + res = Encoder->Progress->SetRatioInfo(&m_PackSize, &unpackSize); + } + + Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set(); + } + #endif + return res; +} + +void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte) +{ + UInt32 bytesSize = (sizeInBits >> 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) +{ + #ifndef _7ZIP_ST + Progress = progress; + RINOK(Create()); + for (UInt32 t = 0; t < NumThreads; t++) + #endif + { + #ifndef _7ZIP_ST + CThreadInfo &ti = ThreadsInfo[t]; + if (MtMode) + { + RINOK(ti.StreamWasFinishedEvent.Reset()); + RINOK(ti.WaitingWasStartedEvent.Reset()); + RINOK(ti.CanWriteEvent.Reset()); + } + #else + CThreadInfo &ti = ThreadsInfo; + ti.Encoder = this; + #endif + + ti.m_OptimizeNumTables = _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 _7ZIP_ST + NextBlockIndex = 0; + StreamWasFinished = false; + CloseThreads = false; + CanStartWaitingEvent.Reset(); + #endif + + WriteByte(kArSig0); + WriteByte(kArSig1); + WriteByte(kArSig2); + WriteByte((Byte)(kArSig3 + _props.BlockSizeMult)); + + #ifndef _7ZIP_ST + + if (MtMode) + { + ThreadsInfo[0].CanWriteEvent.Set(); + Result = S_OK; + CanProcessEvent.Set(); + UInt32 t; + for (t = 0; t < NumThreads; t++) + ThreadsInfo[t].StreamWasFinishedEvent.Lock(); + CanProcessEvent.Reset(); + CanStartWaitingEvent.Set(); + for (t = 0; t < NumThreads; t++) + ThreadsInfo[t].WaitingWasStartedEvent.Lock(); + CanStartWaitingEvent.Reset(); + RINOK(Result); + } + else + #endif + { + for (;;) + { + CThreadInfo &ti = + #ifndef _7ZIP_ST + ThreadsInfo[0]; + #else + ThreadsInfo; + #endif + UInt32 blockSize = ReadRleBlock(ti.m_Block); + if (blockSize == 0) + break; + RINOK(ti.EncodeBlock3(blockSize)); + if (progress) + { + UInt64 packSize = m_InStream.GetProcessedSize(); + UInt64 unpackSize = m_OutStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &unpackSize)); + } + } + } + WriteByte(kFinSig0); + WriteByte(kFinSig1); + WriteByte(kFinSig2); + WriteByte(kFinSig3); + WriteByte(kFinSig4); + WriteByte(kFinSig5); + + WriteCrc(CombinedCrc.GetDigest()); + return Flush(); +} + +STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const COutBufferException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +HRESULT CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *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 (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 = v; break; + case NCoderPropID::kNumThreads: + { + #ifndef _7ZIP_ST + SetNumberOfThreads(v); + #endif + break; + } + default: return E_INVALIDARG; + } + } + props.Normalize(level); + _props = props; + return S_OK; +} + +#ifndef _7ZIP_ST +STDMETHODIMP 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 index 8f60243f3..05d6fa16c 100644 --- a/CPP/7zip/Compress/BZip2Encoder.h +++ b/CPP/7zip/Compress/BZip2Encoder.h @@ -1,239 +1,239 @@ -// BZip2Encoder.h - -#ifndef __COMPRESS_BZIP2_ENCODER_H -#define __COMPRESS_BZIP2_ENCODER_H - -#include "../../Common/Defs.h" -#include "../../Common/MyCom.h" - -#ifndef _7ZIP_ST -#include "../../Windows/Synchronization.h" -#include "../../Windows/Thread.h" -#endif - -#include "../ICoder.h" - -#include "../Common/InBuffer.h" -#include "../Common/OutBuffer.h" - -#include "BitmEncoder.h" -#include "BZip2Const.h" -#include "BZip2Crc.h" - -namespace NCompress { -namespace NBZip2 { - -class CMsbfEncoderTemp -{ - UInt32 _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 <<= 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; - - UInt32 m_BlockIndex; - - 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 _7ZIP_ST - NWindows::CThread Thread; - - NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent; - NWindows::NSynchronization::CAutoResetEvent WaitingWasStartedEvent; - - // it's not member of this thread. We just need one event per thread - NWindows::NSynchronization::CAutoResetEvent CanWriteEvent; - - UInt64 m_PackSize; - - Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. - HRESULT Create(); - void FinishStream(bool needLeave); - DWORD ThreadFunc(); - #endif - - CThreadInfo(): m_BlockSorterIndex(0), m_Block(0) {} - ~CThreadInfo() { Free(); } - bool Alloc(); - void Free(); - - HRESULT EncodeBlock3(UInt32 blockSize); -}; - -struct CEncProps -{ - UInt32 BlockSizeMult; - UInt32 NumPasses; - - CEncProps() - { - BlockSizeMult = (UInt32)(Int32)-1; - NumPasses = (UInt32)(Int32)-1; - } - void Normalize(int level); - bool DoOptimizeNumTables() const { return NumPasses > 1; } -}; - -class CEncoder : - public ICompressCoder, - public ICompressSetCoderProperties, - #ifndef _7ZIP_ST - public ICompressSetCoderMt, - #endif - public CMyUnknownImp -{ - UInt32 m_NumThreadsPrev; -public: - CInBuffer m_InStream; - Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. - CBitmEncoder m_OutStream; - CEncProps _props; - CBZip2CombinedCrc CombinedCrc; - - #ifndef _7ZIP_ST - CThreadInfo *ThreadsInfo; - NWindows::NSynchronization::CManualResetEvent CanProcessEvent; - NWindows::NSynchronization::CCriticalSection CS; - UInt32 NumThreads; - bool MtMode; - UInt32 NextBlockIndex; - - bool CloseThreads; - bool StreamWasFinished; - NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent; - - HRESULT Result; - ICompressProgressInfo *Progress; - #else - CThreadInfo ThreadsInfo; - #endif - - UInt32 ReadRleBlock(Byte *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 _7ZIP_ST - HRESULT Create(); - void Free(); - #endif - -public: - CEncoder(); - #ifndef _7ZIP_ST - ~CEncoder(); - #endif - - HRESULT Flush() { return m_OutStream.Flush(); } - - MY_QUERYINTERFACE_BEGIN2(ICompressCoder) - #ifndef _7ZIP_ST - MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt) - #endif - MY_QUERYINTERFACE_ENTRY(ICompressSetCoderProperties) - MY_QUERYINTERFACE_END - MY_ADDREF_RELEASE - - HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); - - #ifndef _7ZIP_ST - STDMETHOD(SetNumberOfThreads)(UInt32 numThreads); - #endif -}; - -}} - -#endif +// BZip2Encoder.h + +#ifndef __COMPRESS_BZIP2_ENCODER_H +#define __COMPRESS_BZIP2_ENCODER_H + +#include "../../Common/Defs.h" +#include "../../Common/MyCom.h" + +#ifndef _7ZIP_ST +#include "../../Windows/Synchronization.h" +#include "../../Windows/Thread.h" +#endif + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" +#include "../Common/OutBuffer.h" + +#include "BitmEncoder.h" +#include "BZip2Const.h" +#include "BZip2Crc.h" + +namespace NCompress { +namespace NBZip2 { + +class CMsbfEncoderTemp +{ + UInt32 _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 <<= 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; + + UInt32 m_BlockIndex; + + 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 _7ZIP_ST + NWindows::CThread Thread; + + NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent; + NWindows::NSynchronization::CAutoResetEvent WaitingWasStartedEvent; + + // it's not member of this thread. We just need one event per thread + NWindows::NSynchronization::CAutoResetEvent CanWriteEvent; + + UInt64 m_PackSize; + + Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. + HRESULT Create(); + void FinishStream(bool needLeave); + DWORD ThreadFunc(); + #endif + + CThreadInfo(): m_BlockSorterIndex(0), m_Block(0) {} + ~CThreadInfo() { Free(); } + bool Alloc(); + void Free(); + + HRESULT EncodeBlock3(UInt32 blockSize); +}; + +struct CEncProps +{ + UInt32 BlockSizeMult; + UInt32 NumPasses; + + CEncProps() + { + BlockSizeMult = (UInt32)(Int32)-1; + NumPasses = (UInt32)(Int32)-1; + } + void Normalize(int level); + bool DoOptimizeNumTables() const { return NumPasses > 1; } +}; + +class CEncoder : + public ICompressCoder, + public ICompressSetCoderProperties, + #ifndef _7ZIP_ST + public ICompressSetCoderMt, + #endif + public CMyUnknownImp +{ + UInt32 m_NumThreadsPrev; +public: + CInBuffer m_InStream; + Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. + CBitmEncoder m_OutStream; + CEncProps _props; + CBZip2CombinedCrc CombinedCrc; + + #ifndef _7ZIP_ST + CThreadInfo *ThreadsInfo; + NWindows::NSynchronization::CManualResetEvent CanProcessEvent; + NWindows::NSynchronization::CCriticalSection CS; + UInt32 NumThreads; + bool MtMode; + UInt32 NextBlockIndex; + + bool CloseThreads; + bool StreamWasFinished; + NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent; + + HRESULT Result; + ICompressProgressInfo *Progress; + #else + CThreadInfo ThreadsInfo; + #endif + + UInt32 ReadRleBlock(Byte *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 _7ZIP_ST + HRESULT Create(); + void Free(); + #endif + +public: + CEncoder(); + #ifndef _7ZIP_ST + ~CEncoder(); + #endif + + HRESULT Flush() { return m_OutStream.Flush(); } + + MY_QUERYINTERFACE_BEGIN2(ICompressCoder) + #ifndef _7ZIP_ST + MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt) + #endif + MY_QUERYINTERFACE_ENTRY(ICompressSetCoderProperties) + MY_QUERYINTERFACE_END + MY_ADDREF_RELEASE + + HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); + + #ifndef _7ZIP_ST + STDMETHOD(SetNumberOfThreads)(UInt32 numThreads); + #endif +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/BZip2Register.cpp b/CPP/7zip/Compress/BZip2Register.cpp index 456104834..6e960366f 100644 --- a/CPP/7zip/Compress/BZip2Register.cpp +++ b/CPP/7zip/Compress/BZip2Register.cpp @@ -1,25 +1,25 @@ -// BZip2Register.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "BZip2Decoder.h" -#if !defined(EXTRACT_ONLY) && !defined(BZIP2_EXTRACT_ONLY) -#include "BZip2Encoder.h" -#endif - -namespace NCompress { -namespace NBZip2 { - -REGISTER_CODEC_CREATE(CreateDec, CDecoder) - -#if !defined(EXTRACT_ONLY) && !defined(BZIP2_EXTRACT_ONLY) -REGISTER_CODEC_CREATE(CreateEnc, CEncoder) -#else -#define CreateEnc NULL -#endif - -REGISTER_CODEC_2(BZip2, CreateDec, CreateEnc, 0x40202, "BZip2") - -}} +// BZip2Register.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "BZip2Decoder.h" +#if !defined(EXTRACT_ONLY) && !defined(BZIP2_EXTRACT_ONLY) +#include "BZip2Encoder.h" +#endif + +namespace NCompress { +namespace NBZip2 { + +REGISTER_CODEC_CREATE(CreateDec, CDecoder) + +#if !defined(EXTRACT_ONLY) && !defined(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 4e083bf19..4906e78c0 100644 --- a/CPP/7zip/Compress/Bcj2Coder.cpp +++ b/CPP/7zip/Compress/Bcj2Coder.cpp @@ -1,666 +1,666 @@ -// 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 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(¤tInPos, &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 "../../../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 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(¤tInPos, &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; +} + +}} diff --git a/CPP/7zip/Compress/Bcj2Coder.h b/CPP/7zip/Compress/Bcj2Coder.h index 666bf8c4c..ca6a1e4ed 100644 --- a/CPP/7zip/Compress/Bcj2Coder.h +++ b/CPP/7zip/Compress/Bcj2Coder.h @@ -1,120 +1,120 @@ -// 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 _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 __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 _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 diff --git a/CPP/7zip/Compress/Bcj2Register.cpp b/CPP/7zip/Compress/Bcj2Register.cpp index bce617892..7a48f91cf 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 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) + +}} diff --git a/CPP/7zip/Compress/BcjCoder.cpp b/CPP/7zip/Compress/BcjCoder.cpp index a50360c19..32aa1762c 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 { + +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; +} + +}} diff --git a/CPP/7zip/Compress/BcjCoder.h b/CPP/7zip/Compress/BcjCoder.h index 475dfe55a..7883906e4 100644 --- a/CPP/7zip/Compress/BcjCoder.h +++ b/CPP/7zip/Compress/BcjCoder.h @@ -1,31 +1,31 @@ -// 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 __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 diff --git a/CPP/7zip/Compress/BcjRegister.cpp b/CPP/7zip/Compress/BcjRegister.cpp index 48cc057fa..f06dcfe9f 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, + CCoder(false), + CCoder(true), + 0x3030103, "BCJ") + +}} diff --git a/CPP/7zip/Compress/BitlDecoder.cpp b/CPP/7zip/Compress/BitlDecoder.cpp index 183506b41..516b09328 100644 --- a/CPP/7zip/Compress/BitlDecoder.cpp +++ b/CPP/7zip/Compress/BitlDecoder.cpp @@ -1,24 +1,24 @@ -// BitlDecoder.cpp - -#include "StdAfx.h" - -#include "BitlDecoder.h" - -namespace NBitl { - -Byte kInvertTable[256]; - -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; - -} +// BitlDecoder.cpp + +#include "StdAfx.h" + +#include "BitlDecoder.h" + +namespace NBitl { + +Byte kInvertTable[256]; + +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 index f1f7959ec..f3b8248fd 100644 --- a/CPP/7zip/Compress/BitlDecoder.h +++ b/CPP/7zip/Compress/BitlDecoder.h @@ -1,146 +1,146 @@ -// BitlDecoder.h -- the Least Significant Bit of byte is First - -#ifndef __BITL_DECODER_H -#define __BITL_DECODER_H - -#include "../IStream.h" - -namespace NBitl { - -const unsigned kNumBigValueBits = 8 * 4; -const unsigned kNumValueBytes = 3; -const unsigned kNumValueBits = 8 * kNumValueBytes; - -const UInt32 kMask = (1 << kNumValueBits) - 1; - -extern Byte kInvertTable[256]; - -/* 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 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; - } - - UInt64 GetStreamSize() const { return _stream.GetStreamSize(); } - UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); } - - bool ThereAreDataInBitsBuffer() const { return this->_bitPos != kNumBigValueBits; } - - MY_FORCE_INLINE - void Normalize() - { - for (; _bitPos >= 8; _bitPos -= 8) - _value = ((UInt32)_stream.ReadByte() << (kNumBigValueBits - _bitPos)) | _value; - } - - MY_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 CDecoder: public CBaseDecoder -{ - UInt32 _normalValue; - -public: - void Init() - { - CBaseDecoder::Init(); - _normalValue = 0; - } - - MY_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]; - } - } - - MY_FORCE_INLINE - UInt32 GetValue(unsigned numBits) - { - Normalize(); - return ((this->_value >> (8 - this->_bitPos)) & kMask) >> (kNumValueBits - numBits); - } - - MY_FORCE_INLINE - void MovePos(unsigned numBits) - { - this->_bitPos += numBits; - _normalValue >>= numBits; - } - - MY_FORCE_INLINE - UInt32 ReadBits(unsigned numBits) - { - Normalize(); - UInt32 res = _normalValue & ((1 << numBits) - 1); - MovePos(numBits); - return res; - } - - void AlignToByte() { MovePos((32 - this->_bitPos) & 7); } - - MY_FORCE_INLINE - Byte ReadDirectByte() { return this->_stream.ReadByte(); } - - MY_FORCE_INLINE - Byte ReadAlignedByte() - { - if (this->_bitPos == kNumBigValueBits) - return this->_stream.ReadByte(); - Byte b = (Byte)(_normalValue & 0xFF); - MovePos(8); - return b; - } -}; - -} - -#endif +// BitlDecoder.h -- the Least Significant Bit of byte is First + +#ifndef __BITL_DECODER_H +#define __BITL_DECODER_H + +#include "../IStream.h" + +namespace NBitl { + +const unsigned kNumBigValueBits = 8 * 4; +const unsigned kNumValueBytes = 3; +const unsigned kNumValueBits = 8 * kNumValueBytes; + +const UInt32 kMask = (1 << kNumValueBits) - 1; + +extern Byte kInvertTable[256]; + +/* 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 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; + } + + UInt64 GetStreamSize() const { return _stream.GetStreamSize(); } + UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); } + + bool ThereAreDataInBitsBuffer() const { return this->_bitPos != kNumBigValueBits; } + + MY_FORCE_INLINE + void Normalize() + { + for (; _bitPos >= 8; _bitPos -= 8) + _value = ((UInt32)_stream.ReadByte() << (kNumBigValueBits - _bitPos)) | _value; + } + + MY_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 CDecoder: public CBaseDecoder +{ + UInt32 _normalValue; + +public: + void Init() + { + CBaseDecoder::Init(); + _normalValue = 0; + } + + MY_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]; + } + } + + MY_FORCE_INLINE + UInt32 GetValue(unsigned numBits) + { + Normalize(); + return ((this->_value >> (8 - this->_bitPos)) & kMask) >> (kNumValueBits - numBits); + } + + MY_FORCE_INLINE + void MovePos(unsigned numBits) + { + this->_bitPos += numBits; + _normalValue >>= numBits; + } + + MY_FORCE_INLINE + UInt32 ReadBits(unsigned numBits) + { + Normalize(); + UInt32 res = _normalValue & ((1 << numBits) - 1); + MovePos(numBits); + return res; + } + + void AlignToByte() { MovePos((32 - this->_bitPos) & 7); } + + MY_FORCE_INLINE + Byte ReadDirectByte() { return this->_stream.ReadByte(); } + + MY_FORCE_INLINE + Byte ReadAlignedByte() + { + if (this->_bitPos == kNumBigValueBits) + return this->_stream.ReadByte(); + Byte b = (Byte)(_normalValue & 0xFF); + MovePos(8); + return b; + } +}; + +} + +#endif diff --git a/CPP/7zip/Compress/BitlEncoder.h b/CPP/7zip/Compress/BitlEncoder.h index fc585a8ae..22b835452 100644 --- a/CPP/7zip/Compress/BitlEncoder.h +++ b/CPP/7zip/Compress/BitlEncoder.h @@ -1,56 +1,56 @@ -// BitlEncoder.h -- the Least Significant Bit of byte is First - -#ifndef __BITL_ENCODER_H -#define __BITL_ENCODER_H - -#include "../Common/OutBuffer.h" - -class CBitlEncoder -{ - COutBuffer _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 |= (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 +// BitlEncoder.h -- the Least Significant Bit of byte is First + +#ifndef __BITL_ENCODER_H +#define __BITL_ENCODER_H + +#include "../Common/OutBuffer.h" + +class CBitlEncoder +{ + COutBuffer _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 |= (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 index 62109f361..9ce41bd1b 100644 --- a/CPP/7zip/Compress/BitmDecoder.h +++ b/CPP/7zip/Compress/BitmDecoder.h @@ -1,100 +1,100 @@ -// BitmDecoder.h -- the Most Significant Bit of byte is First - -#ifndef __BITM_DECODER_H -#define __BITM_DECODER_H - -#include "../IStream.h" - -namespace NBitm { - -const unsigned kNumBigValueBits = 8 * 4; -const unsigned kNumValueBytes = 3; -const unsigned kNumValueBits = 8 * kNumValueBytes; - -const UInt32 kMask = (1 << kNumValueBits) - 1; - -// _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 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); - } - - MY_FORCE_INLINE - void Normalize() - { - for (; _bitPos >= 8; _bitPos -= 8) - _value = (_value << 8) | _stream.ReadByte(); - } - - MY_FORCE_INLINE - UInt32 GetValue(unsigned numBits) const - { - // return (_value << _bitPos) >> (kNumBigValueBits - numBits); - return ((_value >> (8 - _bitPos)) & kMask) >> (kNumValueBits - numBits); - } - - MY_FORCE_INLINE - void MovePos(unsigned numBits) - { - _bitPos += numBits; - Normalize(); - } - - MY_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); } - - MY_FORCE_INLINE - UInt32 ReadAlignBits() { return ReadBits((kNumBigValueBits - _bitPos) & 7); } -}; - -} - -#endif +// BitmDecoder.h -- the Most Significant Bit of byte is First + +#ifndef __BITM_DECODER_H +#define __BITM_DECODER_H + +#include "../IStream.h" + +namespace NBitm { + +const unsigned kNumBigValueBits = 8 * 4; +const unsigned kNumValueBytes = 3; +const unsigned kNumValueBits = 8 * kNumValueBytes; + +const UInt32 kMask = (1 << kNumValueBits) - 1; + +// _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 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); + } + + MY_FORCE_INLINE + void Normalize() + { + for (; _bitPos >= 8; _bitPos -= 8) + _value = (_value << 8) | _stream.ReadByte(); + } + + MY_FORCE_INLINE + UInt32 GetValue(unsigned numBits) const + { + // return (_value << _bitPos) >> (kNumBigValueBits - numBits); + return ((_value >> (8 - _bitPos)) & kMask) >> (kNumValueBits - numBits); + } + + MY_FORCE_INLINE + void MovePos(unsigned numBits) + { + _bitPos += numBits; + Normalize(); + } + + MY_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); } + + MY_FORCE_INLINE + UInt32 ReadAlignBits() { return ReadBits((kNumBigValueBits - _bitPos) & 7); } +}; + +} + +#endif diff --git a/CPP/7zip/Compress/BitmEncoder.h b/CPP/7zip/Compress/BitmEncoder.h index 458576b16..05079ace0 100644 --- a/CPP/7zip/Compress/BitmEncoder.h +++ b/CPP/7zip/Compress/BitmEncoder.h @@ -1,49 +1,49 @@ -// BitmEncoder.h -- the Most Significant Bit of byte is First - -#ifndef __BITM_ENCODER_H -#define __BITM_ENCODER_H - -#include "../IStream.h" - -template -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)value << (_bitPos -= numBits)); - return; - } - numBits -= _bitPos; - UInt32 newBits = (value >> numBits); - value -= (newBits << numBits); - _stream.WriteByte((Byte)(_curByte | newBits)); - _bitPos = 8; - _curByte = 0; - } - } -}; - -#endif +// BitmEncoder.h -- the Most Significant Bit of byte is First + +#ifndef __BITM_ENCODER_H +#define __BITM_ENCODER_H + +#include "../IStream.h" + +template +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)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 d5a90f179..d0e75e83b 100644 --- a/CPP/7zip/Compress/BranchMisc.cpp +++ b/CPP/7zip/Compress/BranchMisc.cpp @@ -1,23 +1,23 @@ -// 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 "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; +} + +}} diff --git a/CPP/7zip/Compress/BranchMisc.h b/CPP/7zip/Compress/BranchMisc.h index 02a56c390..66fc23d2c 100644 --- a/CPP/7zip/Compress/BranchMisc.h +++ b/CPP/7zip/Compress/BranchMisc.h @@ -1,35 +1,35 @@ -// 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 __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 diff --git a/CPP/7zip/Compress/BranchRegister.cpp b/CPP/7zip/Compress/BranchRegister.cpp index b83c6bcbd..6331c1b9e 100644 --- a/CPP/7zip/Compress/BranchRegister.cpp +++ b/CPP/7zip/Compress/BranchRegister.cpp @@ -1,41 +1,41 @@ -// 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 "../../../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) + +}} diff --git a/CPP/7zip/Compress/ByteSwap.cpp b/CPP/7zip/Compress/ByteSwap.cpp index ee103afe7..4c11806eb 100644 --- a/CPP/7zip/Compress/ByteSwap.cpp +++ b/CPP/7zip/Compress/ByteSwap.cpp @@ -1,92 +1,92 @@ -// 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 "../../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) + +}} diff --git a/CPP/7zip/Compress/Codec.def b/CPP/7zip/Compress/Codec.def index a13bfe9e4..f55b2d57c 100644 --- a/CPP/7zip/Compress/Codec.def +++ b/CPP/7zip/Compress/Codec.def @@ -1,6 +1,6 @@ -EXPORTS - CreateObject PRIVATE - GetNumberOfMethods PRIVATE - GetMethodProperty PRIVATE - CreateDecoder PRIVATE - CreateEncoder PRIVATE +EXPORTS + CreateObject PRIVATE + GetNumberOfMethods PRIVATE + GetMethodProperty PRIVATE + CreateDecoder PRIVATE + CreateEncoder PRIVATE diff --git a/CPP/7zip/Compress/CodecExports.cpp b/CPP/7zip/Compress/CodecExports.cpp index 7be496c24..99085040d 100644 --- a/CPP/7zip/Compress/CodecExports.cpp +++ b/CPP/7zip/Compress/CodecExports.cpp @@ -1,344 +1,344 @@ -// 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 "../../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); +} diff --git a/CPP/7zip/Compress/CopyCoder.cpp b/CPP/7zip/Compress/CopyCoder.cpp index 89b523765..d8487ad54 100644 --- a/CPP/7zip/Compress/CopyCoder.cpp +++ b/CPP/7zip/Compress/CopyCoder.cpp @@ -1,120 +1,120 @@ -// 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 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 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); +} + +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 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 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 b2fa491e0..a9d0b6db2 100644 --- a/CPP/7zip/Compress/CopyCoder.h +++ b/CPP/7zip/Compress/CopyCoder.h @@ -1,49 +1,49 @@ -// 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 _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 __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 _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 diff --git a/CPP/7zip/Compress/CopyRegister.cpp b/CPP/7zip/Compress/CopyRegister.cpp index 1c59fe0c0..7141ab580 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 index 8258f7ac8..14d20bb30 100644 --- a/CPP/7zip/Compress/Deflate64Register.cpp +++ b/CPP/7zip/Compress/Deflate64Register.cpp @@ -1,26 +1,26 @@ -// Deflate64Register.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "DeflateDecoder.h" - -#if !defined(EXTRACT_ONLY) && !defined(DEFLATE_EXTRACT_ONLY) -#include "DeflateEncoder.h" -#endif - -namespace NCompress { -namespace NDeflate { - -REGISTER_CODEC_CREATE(CreateDec, NDecoder::CCOMCoder64()) - -#if !defined(EXTRACT_ONLY) && !defined(DEFLATE_EXTRACT_ONLY) -REGISTER_CODEC_CREATE(CreateEnc, NEncoder::CCOMCoder64()) -#else -#define CreateEnc NULL -#endif - -REGISTER_CODEC_2(Deflate64, CreateDec, CreateEnc, 0x40109, "Deflate64") - -}} +// Deflate64Register.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "DeflateDecoder.h" + +#if !defined(EXTRACT_ONLY) && !defined(DEFLATE_EXTRACT_ONLY) +#include "DeflateEncoder.h" +#endif + +namespace NCompress { +namespace NDeflate { + +REGISTER_CODEC_CREATE(CreateDec, NDecoder::CCOMCoder64()) + +#if !defined(EXTRACT_ONLY) && !defined(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 index d98b32439..cfbbf8865 100644 --- a/CPP/7zip/Compress/DeflateConst.h +++ b/CPP/7zip/Compress/DeflateConst.h @@ -1,131 +1,131 @@ -// DeflateConst.h - -#ifndef __DEFLATE_CONST_H -#define __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 +// DeflateConst.h + +#ifndef __DEFLATE_CONST_H +#define __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 index d77fd2b2e..fceef8570 100644 --- a/CPP/7zip/Compress/DeflateDecoder.cpp +++ b/CPP/7zip/Compress/DeflateDecoder.cpp @@ -1,517 +1,517 @@ -// DeflateDecoder.cpp - -#include "StdAfx.h" - -#include "DeflateDecoder.h" - -namespace NCompress { -namespace NDeflate { -namespace NDecoder { - -CCoder::CCoder(bool deflate64Mode): - _deflate64Mode(deflate64Mode), - _deflateNSIS(false), - _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; - 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 - { - unsigned numLitLenLevels = ReadBits(kNumLenCodesFieldSize) + kNumLitLenCodesMin; - _numDistLevels = ReadBits(kNumDistCodesFieldSize) + kNumDistCodesMin; - unsigned numLevelCodes = ReadBits(kNumLevelCodesFieldSize) + kNumLevelCodesMin; - - if (!_deflate64Mode) - if (_numDistLevels > kDistTableSize32) - return false; - - Byte levelLevels[kLevelTableSize]; - for (unsigned i = 0; i < kLevelTableSize; i++) - { - 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--; - 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; - UInt32 distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]); - if (!m_OutWindowStream.CopyBlock(distance, locLen)) - return S_FALSE; - curSize -= locLen; - len -= locLen; - if (len != 0) - { - _remainLen = (Int32)len; - _rep0 = distance; - break; - } - } - else - return S_FALSE; - } - - 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 _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; -} - - -HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - SetInStream(inStream); - SetOutStreamSize(outSize); - HRESULT res = CodeReal(outStream, progress); - ReleaseInStream(); - /* - if (res == S_OK) - if (_needFinishInput && inSize && *inSize != m_InBitStream.GetProcessedSize()) - res = S_FALSE; - */ - return res; -} - - -STDMETHODIMP CCoder::SetFinishMode(UInt32 finishMode) -{ - Set_NeedFinishInput(finishMode != 0); - return S_OK; -} - - -STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value) -{ - if (!value) - return E_INVALIDARG; - *value = m_InBitStream.GetProcessedSize(); - return S_OK; -} - - -STDMETHODIMP CCoder::SetInStream(ISequentialInStream *inStream) -{ - m_InStreamRef = inStream; - m_InBitStream.SetStream(inStream); - return S_OK; -} - - -STDMETHODIMP 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; -} - - -STDMETHODIMP 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 NO_READ_FROM_CODER - -STDMETHODIMP 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) - - { - 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); -} - -}}} +// DeflateDecoder.cpp + +#include "StdAfx.h" + +#include "DeflateDecoder.h" + +namespace NCompress { +namespace NDeflate { +namespace NDecoder { + +CCoder::CCoder(bool deflate64Mode): + _deflate64Mode(deflate64Mode), + _deflateNSIS(false), + _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; + 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 + { + unsigned numLitLenLevels = ReadBits(kNumLenCodesFieldSize) + kNumLitLenCodesMin; + _numDistLevels = ReadBits(kNumDistCodesFieldSize) + kNumDistCodesMin; + unsigned numLevelCodes = ReadBits(kNumLevelCodesFieldSize) + kNumLevelCodesMin; + + if (!_deflate64Mode) + if (_numDistLevels > kDistTableSize32) + return false; + + Byte levelLevels[kLevelTableSize]; + for (unsigned i = 0; i < kLevelTableSize; i++) + { + 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--; + 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; + UInt32 distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]); + if (!m_OutWindowStream.CopyBlock(distance, locLen)) + return S_FALSE; + curSize -= locLen; + len -= locLen; + if (len != 0) + { + _remainLen = (Int32)len; + _rep0 = distance; + break; + } + } + else + return S_FALSE; + } + + 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 _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; +} + + +HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + SetInStream(inStream); + SetOutStreamSize(outSize); + HRESULT res = CodeReal(outStream, progress); + ReleaseInStream(); + /* + if (res == S_OK) + if (_needFinishInput && inSize && *inSize != m_InBitStream.GetProcessedSize()) + res = S_FALSE; + */ + return res; +} + + +STDMETHODIMP CCoder::SetFinishMode(UInt32 finishMode) +{ + Set_NeedFinishInput(finishMode != 0); + return S_OK; +} + + +STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value) +{ + if (!value) + return E_INVALIDARG; + *value = m_InBitStream.GetProcessedSize(); + return S_OK; +} + + +STDMETHODIMP CCoder::SetInStream(ISequentialInStream *inStream) +{ + m_InStreamRef = inStream; + m_InBitStream.SetStream(inStream); + return S_OK; +} + + +STDMETHODIMP 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; +} + + +STDMETHODIMP 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 NO_READ_FROM_CODER + +STDMETHODIMP 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) + + { + 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 index e6ec51903..0a7242475 100644 --- a/CPP/7zip/Compress/DeflateDecoder.h +++ b/CPP/7zip/Compress/DeflateDecoder.h @@ -1,153 +1,153 @@ -// DeflateDecoder.h - -#ifndef __DEFLATE_DECODER_H -#define __DEFLATE_DECODER_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/InBuffer.h" - -#include "BitlDecoder.h" -#include "DeflateConst.h" -#include "HuffmanDecoder.h" -#include "LzOutWindow.h" - -namespace NCompress { -namespace NDeflate { -namespace NDecoder { - -const int kLenIdFinished = -1; -const int kLenIdNeedInit = -2; - -class CCoder: - public ICompressCoder, - public ICompressSetFinishMode, - public ICompressGetInStreamProcessedSize, - #ifndef NO_READ_FROM_CODER - public ICompressSetInStream, - public ICompressSetOutStreamSize, - public ISequentialInStream, - #endif - public CMyUnknownImp -{ - CLzOutWindow m_OutWindowStream; - CMyComPtr m_InStreamRef; - NBitl::CDecoder m_InBitStream; - NCompress::NHuffman::CDecoder m_MainDecoder; - NCompress::NHuffman::CDecoder m_DistDecoder; - NCompress::NHuffman::CDecoder7b 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); - - MY_QUERYINTERFACE_BEGIN2(ICompressCoder) - 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(SetFinishMode)(UInt32 finishMode); - STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); - - STDMETHOD(SetInStream)(ISequentialInStream *inStream); - STDMETHOD(ReleaseInStream)(); - STDMETHOD(SetOutStreamSize)(const UInt64 *outSize); - - #ifndef NO_READ_FROM_CODER - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - #endif - - 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(); } - - UInt64 GetStreamSize() const { return m_InBitStream.GetStreamSize(); } - UInt64 GetInputProcessedSize() const { return m_InBitStream.GetProcessedSize(); } -}; - -class CCOMCoder : public CCoder { public: CCOMCoder(): CCoder(false) {} }; -class CCOMCoder64 : public CCoder { public: CCOMCoder64(): CCoder(true) {} }; - -}}} - -#endif +// DeflateDecoder.h + +#ifndef __DEFLATE_DECODER_H +#define __DEFLATE_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "BitlDecoder.h" +#include "DeflateConst.h" +#include "HuffmanDecoder.h" +#include "LzOutWindow.h" + +namespace NCompress { +namespace NDeflate { +namespace NDecoder { + +const int kLenIdFinished = -1; +const int kLenIdNeedInit = -2; + +class CCoder: + public ICompressCoder, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize, + #ifndef NO_READ_FROM_CODER + public ICompressSetInStream, + public ICompressSetOutStreamSize, + public ISequentialInStream, + #endif + public CMyUnknownImp +{ + CLzOutWindow m_OutWindowStream; + CMyComPtr m_InStreamRef; + NBitl::CDecoder m_InBitStream; + NCompress::NHuffman::CDecoder m_MainDecoder; + NCompress::NHuffman::CDecoder m_DistDecoder; + NCompress::NHuffman::CDecoder7b 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); + + MY_QUERYINTERFACE_BEGIN2(ICompressCoder) + 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(SetFinishMode)(UInt32 finishMode); + STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); + + STDMETHOD(SetInStream)(ISequentialInStream *inStream); + STDMETHOD(ReleaseInStream)(); + STDMETHOD(SetOutStreamSize)(const UInt64 *outSize); + + #ifndef NO_READ_FROM_CODER + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + #endif + + 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(); } + + UInt64 GetStreamSize() const { return m_InBitStream.GetStreamSize(); } + 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 index 009322e49..233edb5f7 100644 --- a/CPP/7zip/Compress/DeflateEncoder.cpp +++ b/CPP/7zip/Compress/DeflateEncoder.cpp @@ -1,1003 +1,1003 @@ -// 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 MY_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]; -static Byte g_FastPos[1 << 9]; - -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 = 18; - 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; -} - -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 + (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 = 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_Deflate64Mode(deflate64Mode), - m_OnePosMatchesMemory(0), - m_DistanceMemory(0), - m_Created(false), - m_Values(0), - m_Tables(0) -{ - 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 == 0) - { - m_Values = (CCodeValue *)MyAlloc((kMaxUncompressedBlockSize) * sizeof(CCodeValue)); - if (m_Values == 0) - return E_OUTOFMEMORY; - } - if (m_Tables == 0) - { - m_Tables = (CTables *)MyAlloc((kNumTables) * sizeof(CTables)); - if (m_Tables == 0) - return E_OUTOFMEMORY; - } - - if (m_IsMultiPass) - { - if (m_OnePosMatchesMemory == 0) - { - m_OnePosMatchesMemory = (UInt16 *)::MidAlloc(kMatchArraySize * sizeof(UInt16)); - if (m_OnePosMatchesMemory == 0) - return E_OUTOFMEMORY; - } - } - else - { - if (m_DistanceMemory == 0) - { - m_DistanceMemory = (UInt16 *)MyAlloc((kMatchMaxLen + 2) * 2 * sizeof(UInt16)); - if (m_DistanceMemory == 0) - return E_OUTOFMEMORY; - m_MatchDistances = m_DistanceMemory; - } - } - - if (!m_Created) - { - _lzInWindow.btMode = (Byte)(_btMode ? 1 : 0); - _lzInWindow.numHashBytes = 3; - if (!MatchFinder_Create(&_lzInWindow, - m_Deflate64Mode ? kHistorySize64 : kHistorySize32, - kNumOpts + kMaxUncompressedBlockSize, - m_NumFastBytes, m_MatchMaxLen - m_NumFastBytes, &g_Alloc)) - return E_OUTOFMEMORY; - if (!m_OutStream.Create(1 << 20)) - return E_OUTOFMEMORY; - } - if (m_MatchFinderCycles != 0) - _lzInWindow.cutValue = m_MatchFinderCycles; - m_Created = true; - return S_OK; - // COM_TRY_END -} - -HRESULT CCoder::BaseSetEncoderProperties2(const PROPID *propIDs, const PROPVARIANT *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 = v; break; - case NCoderPropID::kMatchFinderCycles: props.mc = v; break; - case NCoderPropID::kAlgorithm: props.algo = v; break; - case NCoderPropID::kLevel: props.Level = v; break; - case NCoderPropID::kNumThreads: break; - default: return E_INVALIDARG; - } - } - SetProps(&props); - return S_OK; -} - -void CCoder::Free() -{ - ::MidFree(m_OnePosMatchesMemory); m_OnePosMatchesMemory = 0; - ::MyFree(m_DistanceMemory); m_DistanceMemory = 0; - ::MyFree(m_Values); m_Values = 0; - ::MyFree(m_Tables); m_Tables = 0; -} - -CCoder::~CCoder() -{ - Free(); - MatchFinder_Free(&_lzInWindow, &g_Alloc); -} - -NO_INLINE void CCoder::GetMatches() -{ - if (m_IsMultiPass) - { - m_MatchDistances = m_OnePosMatchesMemory + m_Pos; - if (m_SecondPass) - { - m_Pos += *m_MatchDistances + 1; - return; - } - } - - UInt32 distanceTmp[kMatchMaxLen * 2 + 3]; - - UInt32 numPairs = (_btMode) ? - Bt3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp): - Hc3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp); - - *m_MatchDistances = (UInt16)numPairs; - - if (numPairs > 0) - { - UInt32 i; - for (i = 0; i < numPairs; i += 2) - { - m_MatchDistances[(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); -} - -NO_INLINE UInt32 Huffman_GetPrice(const UInt32 *freqs, const Byte *lens, UInt32 num) -{ - UInt32 price = 0; - UInt32 i; - for (i = 0; i < num; i++) - price += lens[i] * freqs[i]; - return price; -} - -NO_INLINE UInt32 Huffman_GetPrice_Spec(const UInt32 *freqs, const Byte *lens, UInt32 num, const Byte *extraBits, UInt32 extraBase) -{ - return Huffman_GetPrice(freqs, lens, num) + - Huffman_GetPrice(freqs + extraBase, extraBits, num - extraBase); -} - -NO_INLINE UInt32 CCoder::GetLzBlockPrice() const -{ - return - Huffman_GetPrice_Spec(mainFreqs, m_NewLevels.litLenLevels, kFixedMainTableSize, m_LenDirectBits, kSymbolMatch) + - Huffman_GetPrice_Spec(distFreqs, m_NewLevels.distLevels, kDistTableSize64, kDistDirectBits, 0); -} - -NO_INLINE void CCoder::TryBlock() -{ - memset(mainFreqs, 0, sizeof(mainFreqs)); - memset(distFreqs, 0, sizeof(distFreqs)); - - m_ValueIndex = 0; - UInt32 blockSize = BlockSizeRes; - BlockSizeRes = 0; - for (;;) - { - if (m_OptimumCurrentIndex == m_OptimumEndIndex) - { - if (m_Pos >= kMatchArrayLimit || BlockSizeRes >= blockSize || !m_SecondPass && - ((Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) == 0) || m_ValueIndex >= m_ValueBlockSize)) - break; - } - UInt32 pos; - UInt32 len; - if (_fastMode) - len = GetOptimalFast(pos); - else - len = GetOptimal(pos); - CCodeValue &codeValue = m_Values[m_ValueIndex++]; - if (len >= kMatchMinLen) - { - UInt32 newLen = len - kMatchMinLen; - codeValue.Len = (UInt16)newLen; - mainFreqs[kSymbolMatch + (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]); - } -} - -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)); - - RINOK(Create()); - - m_ValueBlockSize = (7 << 10) + (1 << 12) * m_NumDivPasses; - - UInt64 nowPos = 0; - - CSeqInStreamWrap _seqInStream; - - _seqInStream.Init(inStream); - - _lzInWindow.stream = &_seqInStream.vt; - - 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; } -} - -STDMETHODIMP CCOMCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) - { return BaseCode(inStream, outStream, inSize, outSize, progress); } - -STDMETHODIMP CCOMCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) - { return BaseSetEncoderProperties2(propIDs, props, numProps); } - -STDMETHODIMP CCOMCoder64::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) - { return BaseCode(inStream, outStream, inSize, outSize, progress); } - -STDMETHODIMP CCOMCoder64::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) - { return BaseSetEncoderProperties2(propIDs, props, numProps); } - -}}} +// 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 MY_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]; +static Byte g_FastPos[1 << 9]; + +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 = 18; + 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; +} + +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 + (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 = 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_Deflate64Mode(deflate64Mode), + m_OnePosMatchesMemory(0), + m_DistanceMemory(0), + m_Created(false), + m_Values(0), + m_Tables(0) +{ + 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 == 0) + { + m_Values = (CCodeValue *)MyAlloc((kMaxUncompressedBlockSize) * sizeof(CCodeValue)); + if (m_Values == 0) + return E_OUTOFMEMORY; + } + if (m_Tables == 0) + { + m_Tables = (CTables *)MyAlloc((kNumTables) * sizeof(CTables)); + if (m_Tables == 0) + return E_OUTOFMEMORY; + } + + if (m_IsMultiPass) + { + if (m_OnePosMatchesMemory == 0) + { + m_OnePosMatchesMemory = (UInt16 *)::MidAlloc(kMatchArraySize * sizeof(UInt16)); + if (m_OnePosMatchesMemory == 0) + return E_OUTOFMEMORY; + } + } + else + { + if (m_DistanceMemory == 0) + { + m_DistanceMemory = (UInt16 *)MyAlloc((kMatchMaxLen + 2) * 2 * sizeof(UInt16)); + if (m_DistanceMemory == 0) + return E_OUTOFMEMORY; + m_MatchDistances = m_DistanceMemory; + } + } + + if (!m_Created) + { + _lzInWindow.btMode = (Byte)(_btMode ? 1 : 0); + _lzInWindow.numHashBytes = 3; + if (!MatchFinder_Create(&_lzInWindow, + m_Deflate64Mode ? kHistorySize64 : kHistorySize32, + kNumOpts + kMaxUncompressedBlockSize, + m_NumFastBytes, m_MatchMaxLen - m_NumFastBytes, &g_Alloc)) + return E_OUTOFMEMORY; + if (!m_OutStream.Create(1 << 20)) + return E_OUTOFMEMORY; + } + if (m_MatchFinderCycles != 0) + _lzInWindow.cutValue = m_MatchFinderCycles; + m_Created = true; + return S_OK; + // COM_TRY_END +} + +HRESULT CCoder::BaseSetEncoderProperties2(const PROPID *propIDs, const PROPVARIANT *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 = v; break; + case NCoderPropID::kMatchFinderCycles: props.mc = v; break; + case NCoderPropID::kAlgorithm: props.algo = v; break; + case NCoderPropID::kLevel: props.Level = v; break; + case NCoderPropID::kNumThreads: break; + default: return E_INVALIDARG; + } + } + SetProps(&props); + return S_OK; +} + +void CCoder::Free() +{ + ::MidFree(m_OnePosMatchesMemory); m_OnePosMatchesMemory = 0; + ::MyFree(m_DistanceMemory); m_DistanceMemory = 0; + ::MyFree(m_Values); m_Values = 0; + ::MyFree(m_Tables); m_Tables = 0; +} + +CCoder::~CCoder() +{ + Free(); + MatchFinder_Free(&_lzInWindow, &g_Alloc); +} + +NO_INLINE void CCoder::GetMatches() +{ + if (m_IsMultiPass) + { + m_MatchDistances = m_OnePosMatchesMemory + m_Pos; + if (m_SecondPass) + { + m_Pos += *m_MatchDistances + 1; + return; + } + } + + UInt32 distanceTmp[kMatchMaxLen * 2 + 3]; + + UInt32 numPairs = (_btMode) ? + Bt3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp): + Hc3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp); + + *m_MatchDistances = (UInt16)numPairs; + + if (numPairs > 0) + { + UInt32 i; + for (i = 0; i < numPairs; i += 2) + { + m_MatchDistances[(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); +} + +NO_INLINE UInt32 Huffman_GetPrice(const UInt32 *freqs, const Byte *lens, UInt32 num) +{ + UInt32 price = 0; + UInt32 i; + for (i = 0; i < num; i++) + price += lens[i] * freqs[i]; + return price; +} + +NO_INLINE UInt32 Huffman_GetPrice_Spec(const UInt32 *freqs, const Byte *lens, UInt32 num, const Byte *extraBits, UInt32 extraBase) +{ + return Huffman_GetPrice(freqs, lens, num) + + Huffman_GetPrice(freqs + extraBase, extraBits, num - extraBase); +} + +NO_INLINE UInt32 CCoder::GetLzBlockPrice() const +{ + return + Huffman_GetPrice_Spec(mainFreqs, m_NewLevels.litLenLevels, kFixedMainTableSize, m_LenDirectBits, kSymbolMatch) + + Huffman_GetPrice_Spec(distFreqs, m_NewLevels.distLevels, kDistTableSize64, kDistDirectBits, 0); +} + +NO_INLINE void CCoder::TryBlock() +{ + memset(mainFreqs, 0, sizeof(mainFreqs)); + memset(distFreqs, 0, sizeof(distFreqs)); + + m_ValueIndex = 0; + UInt32 blockSize = BlockSizeRes; + BlockSizeRes = 0; + for (;;) + { + if (m_OptimumCurrentIndex == m_OptimumEndIndex) + { + if (m_Pos >= kMatchArrayLimit || BlockSizeRes >= blockSize || !m_SecondPass && + ((Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) == 0) || m_ValueIndex >= m_ValueBlockSize)) + break; + } + UInt32 pos; + UInt32 len; + if (_fastMode) + len = GetOptimalFast(pos); + else + len = GetOptimal(pos); + CCodeValue &codeValue = m_Values[m_ValueIndex++]; + if (len >= kMatchMinLen) + { + UInt32 newLen = len - kMatchMinLen; + codeValue.Len = (UInt16)newLen; + mainFreqs[kSymbolMatch + (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]); + } +} + +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)); + + RINOK(Create()); + + m_ValueBlockSize = (7 << 10) + (1 << 12) * m_NumDivPasses; + + UInt64 nowPos = 0; + + CSeqInStreamWrap _seqInStream; + + _seqInStream.Init(inStream); + + _lzInWindow.stream = &_seqInStream.vt; + + 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; } +} + +STDMETHODIMP CCOMCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) + { return BaseCode(inStream, outStream, inSize, outSize, progress); } + +STDMETHODIMP CCOMCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) + { return BaseSetEncoderProperties2(propIDs, props, numProps); } + +STDMETHODIMP CCOMCoder64::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) + { return BaseCode(inStream, outStream, inSize, outSize, progress); } + +STDMETHODIMP CCOMCoder64::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) + { return BaseSetEncoderProperties2(propIDs, props, numProps); } + +}}} diff --git a/CPP/7zip/Compress/DeflateEncoder.h b/CPP/7zip/Compress/DeflateEncoder.h index 733e90c8d..94d250ec6 100644 --- a/CPP/7zip/Compress/DeflateEncoder.h +++ b/CPP/7zip/Compress/DeflateEncoder.h @@ -1,209 +1,209 @@ -// DeflateEncoder.h - -#ifndef __DEFLATE_ENCODER_H -#define __DEFLATE_ENCODER_H - -#include "../../../C/LzFind.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "BitlEncoder.h" -#include "DeflateConst.h" - -namespace NCompress { -namespace NDeflate { -namespace NEncoder { - -struct CCodeValue -{ - UInt16 Len; - UInt16 Pos; - void SetAsLiteral() { Len = (1 << 15); } - bool IsLiteral() const { return (Len >= (1 << 15)); } -}; - -struct COptimal -{ - UInt32 Price; - UInt16 PosPrev; - UInt16 BackPrev; -}; - -const UInt32 kNumOptsBase = 1 << 12; -const UInt32 kNumOpts = kNumOptsBase + kMatchMaxLen; - -class CCoder; - -struct CTables: public CLevels -{ - bool UseSubBlocks; - bool StoreMode; - bool StaticMode; - UInt32 BlockSizeRes; - UInt32 m_Pos; - void InitStructures(); -}; - - -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 : - public ICompressCoder, - public ICompressSetCoderProperties, - public CMyUnknownImp, - public CCoder -{ -public: - MY_UNKNOWN_IMP2(ICompressCoder, ICompressSetCoderProperties) - CCOMCoder(): CCoder(false) {}; - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); -}; - -class CCOMCoder64 : - public ICompressCoder, - public ICompressSetCoderProperties, - public CMyUnknownImp, - public CCoder -{ -public: - MY_UNKNOWN_IMP2(ICompressCoder, ICompressSetCoderProperties) - CCOMCoder64(): CCoder(true) {}; - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); -}; - -}}} - -#endif +// DeflateEncoder.h + +#ifndef __DEFLATE_ENCODER_H +#define __DEFLATE_ENCODER_H + +#include "../../../C/LzFind.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "BitlEncoder.h" +#include "DeflateConst.h" + +namespace NCompress { +namespace NDeflate { +namespace NEncoder { + +struct CCodeValue +{ + UInt16 Len; + UInt16 Pos; + void SetAsLiteral() { Len = (1 << 15); } + bool IsLiteral() const { return (Len >= (1 << 15)); } +}; + +struct COptimal +{ + UInt32 Price; + UInt16 PosPrev; + UInt16 BackPrev; +}; + +const UInt32 kNumOptsBase = 1 << 12; +const UInt32 kNumOpts = kNumOptsBase + kMatchMaxLen; + +class CCoder; + +struct CTables: public CLevels +{ + bool UseSubBlocks; + bool StoreMode; + bool StaticMode; + UInt32 BlockSizeRes; + UInt32 m_Pos; + void InitStructures(); +}; + + +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 : + public ICompressCoder, + public ICompressSetCoderProperties, + public CMyUnknownImp, + public CCoder +{ +public: + MY_UNKNOWN_IMP2(ICompressCoder, ICompressSetCoderProperties) + CCOMCoder(): CCoder(false) {}; + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); +}; + +class CCOMCoder64 : + public ICompressCoder, + public ICompressSetCoderProperties, + public CMyUnknownImp, + public CCoder +{ +public: + MY_UNKNOWN_IMP2(ICompressCoder, ICompressSetCoderProperties) + CCOMCoder64(): CCoder(true) {}; + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); +}; + +}}} + +#endif diff --git a/CPP/7zip/Compress/DeflateRegister.cpp b/CPP/7zip/Compress/DeflateRegister.cpp index 9546f6269..387be6ed5 100644 --- a/CPP/7zip/Compress/DeflateRegister.cpp +++ b/CPP/7zip/Compress/DeflateRegister.cpp @@ -1,25 +1,25 @@ -// DeflateRegister.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "DeflateDecoder.h" -#if !defined(EXTRACT_ONLY) && !defined(DEFLATE_EXTRACT_ONLY) -#include "DeflateEncoder.h" -#endif - -namespace NCompress { -namespace NDeflate { - -REGISTER_CODEC_CREATE(CreateDec, NDecoder::CCOMCoder) - -#if !defined(EXTRACT_ONLY) && !defined(DEFLATE_EXTRACT_ONLY) -REGISTER_CODEC_CREATE(CreateEnc, NEncoder::CCOMCoder) -#else -#define CreateEnc NULL -#endif - -REGISTER_CODEC_2(Deflate, CreateDec, CreateEnc, 0x40108, "Deflate") - -}} +// DeflateRegister.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "DeflateDecoder.h" +#if !defined(EXTRACT_ONLY) && !defined(DEFLATE_EXTRACT_ONLY) +#include "DeflateEncoder.h" +#endif + +namespace NCompress { +namespace NDeflate { + +REGISTER_CODEC_CREATE(CreateDec, NDecoder::CCOMCoder) + +#if !defined(EXTRACT_ONLY) && !defined(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 cdbd33d4c..3986ae4fd 100644 --- a/CPP/7zip/Compress/DeltaFilter.cpp +++ b/CPP/7zip/Compress/DeltaFilter.cpp @@ -1,128 +1,128 @@ -// 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 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") + +}} diff --git a/CPP/7zip/Compress/DllExports2Compress.cpp b/CPP/7zip/Compress/DllExports2Compress.cpp index 66c43466a..a6ff69057 100644 --- a/CPP/7zip/Compress/DllExports2Compress.cpp +++ b/CPP/7zip/Compress/DllExports2Compress.cpp @@ -1,28 +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); -} +// 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 index a3b09b12e..c58d2d5e0 100644 --- a/CPP/7zip/Compress/DllExportsCompress.cpp +++ b/CPP/7zip/Compress/DllExportsCompress.cpp @@ -1,48 +1,48 @@ -// 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*/) -{ - return TRUE; -} -#endif - -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); -} +// 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*/) +{ + return TRUE; +} +#endif + +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/HuffmanDecoder.h b/CPP/7zip/Compress/HuffmanDecoder.h index 957bd4d0d..f05298762 100644 --- a/CPP/7zip/Compress/HuffmanDecoder.h +++ b/CPP/7zip/Compress/HuffmanDecoder.h @@ -1,278 +1,278 @@ -// Compress/HuffmanDecoder.h - -#ifndef __COMPRESS_HUFFMAN_DECODER_H -#define __COMPRESS_HUFFMAN_DECODER_H - -#include "../../Common/MyTypes.h" - -namespace NCompress { -namespace NHuffman { - -const unsigned kNumPairLenBits = 4; -const unsigned kPairLenMask = (1 << kNumPairLenBits) - 1; - -template -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 - MY_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 - MY_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 -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 - UInt32 Decode(TBitDecoder *bitStream) const - { - UInt32 val = bitStream->GetValue(7); - UInt32 pair = _lens[val]; - bitStream->MovePos((unsigned)(pair & 0x7)); - return pair >> 3; - } -}; - -}} - -#endif +// Compress/HuffmanDecoder.h + +#ifndef __COMPRESS_HUFFMAN_DECODER_H +#define __COMPRESS_HUFFMAN_DECODER_H + +#include "../../Common/MyTypes.h" + +namespace NCompress { +namespace NHuffman { + +const unsigned kNumPairLenBits = 4; +const unsigned kPairLenMask = (1 << kNumPairLenBits) - 1; + +template +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 + MY_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 + MY_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 +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 + 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 index 0d43d5119..736c832ec 100644 --- a/CPP/7zip/Compress/ImplodeDecoder.cpp +++ b/CPP/7zip/Compress/ImplodeDecoder.cpp @@ -1,258 +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++) - { - unsigned len = lens[sym]; - if (len != 0) - _symbols[--counts[len]] = (Byte)sym; - } - - return true; -} - - -UInt32 CHuffmanDecoder::Decode(CInBit *inStream) const throw() -{ - UInt32 val = inStream->GetValue(kNumHuffmanBits); - unsigned numBits; - for (numBits = 1; val < _limits[numBits]; numBits++); - 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(): - _fullStreamMode(false), - _flags(0) -{} - - -bool CCoder::BuildHuff(CHuffmanDecoder &decoder, unsigned numSymbols) -{ - Byte levels[kMaxHuffTableSize]; - unsigned numRecords = (unsigned)_inBitStream.ReadAlignedByte() + 1; - unsigned index = 0; - do - { - unsigned b = (unsigned)_inBitStream.ReadAlignedByte(); - Byte level = (Byte)((b & 0xF) + 1); - 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) - { - UInt32 sym = _litDecoder.Decode(&_inBitStream); - // if (sym >= kLitTableSize) break; - b = (Byte)sym; - } - else - b = (Byte)_inBitStream.ReadBits(8); - _outWindowStream.PutByte(b); - pos++; - } - else - { - 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; -} - - -STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - // catch(const CInBufferException &e) { return e.ErrorCode; } - // catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(const CSystemException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - - -STDMETHODIMP CCoder::SetDecoderProperties2(const Byte *data, UInt32 size) -{ - if (size == 0) - return E_NOTIMPL; - _flags = data[0]; - return S_OK; -} - - -STDMETHODIMP CCoder::SetFinishMode(UInt32 finishMode) -{ - _fullStreamMode = (finishMode != 0); - return S_OK; -} - - -STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value) -{ - *value = _inBitStream.GetProcessedSize(); - return S_OK; -} - -}}} +// 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++) + { + unsigned len = lens[sym]; + if (len != 0) + _symbols[--counts[len]] = (Byte)sym; + } + + return true; +} + + +UInt32 CHuffmanDecoder::Decode(CInBit *inStream) const throw() +{ + UInt32 val = inStream->GetValue(kNumHuffmanBits); + unsigned numBits; + for (numBits = 1; val < _limits[numBits]; numBits++); + 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(): + _fullStreamMode(false), + _flags(0) +{} + + +bool CCoder::BuildHuff(CHuffmanDecoder &decoder, unsigned numSymbols) +{ + Byte levels[kMaxHuffTableSize]; + unsigned numRecords = (unsigned)_inBitStream.ReadAlignedByte() + 1; + unsigned index = 0; + do + { + unsigned b = (unsigned)_inBitStream.ReadAlignedByte(); + Byte level = (Byte)((b & 0xF) + 1); + 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) + { + UInt32 sym = _litDecoder.Decode(&_inBitStream); + // if (sym >= kLitTableSize) break; + b = (Byte)sym; + } + else + b = (Byte)_inBitStream.ReadBits(8); + _outWindowStream.PutByte(b); + pos++; + } + else + { + 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; +} + + +STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + // catch(const CInBufferException &e) { return e.ErrorCode; } + // catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(const CSystemException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + + +STDMETHODIMP CCoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + if (size == 0) + return E_NOTIMPL; + _flags = data[0]; + return S_OK; +} + + +STDMETHODIMP CCoder::SetFinishMode(UInt32 finishMode) +{ + _fullStreamMode = (finishMode != 0); + return S_OK; +} + + +STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value) +{ + *value = _inBitStream.GetProcessedSize(); + return S_OK; +} + +}}} diff --git a/CPP/7zip/Compress/ImplodeDecoder.h b/CPP/7zip/Compress/ImplodeDecoder.h index 3a3b80b11..a73c143c9 100644 --- a/CPP/7zip/Compress/ImplodeDecoder.h +++ b/CPP/7zip/Compress/ImplodeDecoder.h @@ -1,73 +1,73 @@ -// ImplodeDecoder.h - -#ifndef __COMPRESS_IMPLODE_DECODER_H -#define __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 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(); -}; - - -class CCoder: - public ICompressCoder, - public ICompressSetDecoderProperties2, - public ICompressSetFinishMode, - public ICompressGetInStreamProcessedSize, - public CMyUnknownImp -{ - 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: - MY_UNKNOWN_IMP3( - ICompressSetDecoderProperties2, - ICompressSetFinishMode, - ICompressGetInStreamProcessedSize) - - 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); - - CCoder(); -}; - -}}} - -#endif +// ImplodeDecoder.h + +#ifndef __COMPRESS_IMPLODE_DECODER_H +#define __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 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(); +}; + + +class CCoder: + public ICompressCoder, + public ICompressSetDecoderProperties2, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize, + public CMyUnknownImp +{ + 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: + MY_UNKNOWN_IMP3( + ICompressSetDecoderProperties2, + ICompressSetFinishMode, + ICompressGetInStreamProcessedSize) + + 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); + + CCoder(); +}; + +}}} + +#endif diff --git a/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp b/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp index c0af85f7a..7d31bb941 100644 --- a/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp +++ b/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp @@ -1,3 +1,3 @@ -// ImplodeHuffmanDecoder.cpp - -#include "StdAfx.h" +// ImplodeHuffmanDecoder.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Compress/ImplodeHuffmanDecoder.h b/CPP/7zip/Compress/ImplodeHuffmanDecoder.h index 7c3f78dd0..ea25211af 100644 --- a/CPP/7zip/Compress/ImplodeHuffmanDecoder.h +++ b/CPP/7zip/Compress/ImplodeHuffmanDecoder.h @@ -1,6 +1,6 @@ -// ImplodeHuffmanDecoder.h - -#ifndef __IMPLODE_HUFFMAN_DECODER_H -#define __IMPLODE_HUFFMAN_DECODER_H - -#endif +// ImplodeHuffmanDecoder.h + +#ifndef __IMPLODE_HUFFMAN_DECODER_H +#define __IMPLODE_HUFFMAN_DECODER_H + +#endif diff --git a/CPP/7zip/Compress/LzOutWindow.cpp b/CPP/7zip/Compress/LzOutWindow.cpp index dca039897..eb3464074 100644 --- a/CPP/7zip/Compress/LzOutWindow.cpp +++ b/CPP/7zip/Compress/LzOutWindow.cpp @@ -1,14 +1,14 @@ -// LzOutWindow.cpp - -#include "StdAfx.h" - -#include "LzOutWindow.h" - -void CLzOutWindow::Init(bool solid) throw() -{ - if (!solid) - COutBuffer::Init(); - #ifdef _NO_EXCEPTIONS - ErrorCode = S_OK; - #endif -} +// LzOutWindow.cpp + +#include "StdAfx.h" + +#include "LzOutWindow.h" + +void CLzOutWindow::Init(bool solid) throw() +{ + if (!solid) + COutBuffer::Init(); + #ifdef _NO_EXCEPTIONS + ErrorCode = S_OK; + #endif +} diff --git a/CPP/7zip/Compress/LzOutWindow.h b/CPP/7zip/Compress/LzOutWindow.h index eac963ba2..30ac334fd 100644 --- a/CPP/7zip/Compress/LzOutWindow.h +++ b/CPP/7zip/Compress/LzOutWindow.h @@ -1,102 +1,102 @@ -// LzOutWindow.h - -#ifndef __LZ_OUT_WINDOW_H -#define __LZ_OUT_WINDOW_H - -#include "../Common/OutBuffer.h" - -#ifndef _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 +// LzOutWindow.h + +#ifndef __LZ_OUT_WINDOW_H +#define __LZ_OUT_WINDOW_H + +#include "../Common/OutBuffer.h" + +#ifndef _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 index 548ca9956..41c7445a6 100644 --- a/CPP/7zip/Compress/LzfseDecoder.cpp +++ b/CPP/7zip/Compress/LzfseDecoder.cpp @@ -1,925 +1,925 @@ -// 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 -#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; - RINOK(GetUInt32(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 - small L - 1110LLLL - - 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 - 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 - 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 - // small - LLMMMDDD DDDDDDDD - 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 MY_FORCE_INLINE unsigned CountZeroBits(UInt32 val, UInt32 mask) -{ - for (unsigned i = 0;;) - { - if (val & mask) - return i; - i++; - mask >>= 1; - } -} - - -static MY_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) - 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 MY_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 = 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 \ - { unsigned nbits = (31 - in.numBits) & -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 MY_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 MY_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_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(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(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 ((buf - buf_start) * 8 + in.numBits != 64) - return S_FALSE; - if (GetUi64(buf_start) != 0) - return S_FALSE; - - return S_OK; -} - - -STDMETHODIMP 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; - - 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; - } - - const UInt64 rem = *outSize - 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 (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' - res = DecodeLzvn(cur); - 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 != m_InStream.GetProcessedSize() - || *outSize != m_OutWindowStream.GetProcessedSize()) - res = S_FALSE; - return res; -} - - -STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(...) { return E_OUTOFMEMORY; } - // catch(...) { return S_FALSE; } -} - -}} +// 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 +#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; + RINOK(GetUInt32(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 + small L - 1110LLLL + + 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 + 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 + 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 + // small - LLMMMDDD DDDDDDDD + 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 MY_FORCE_INLINE unsigned CountZeroBits(UInt32 val, UInt32 mask) +{ + for (unsigned i = 0;;) + { + if (val & mask) + return i; + i++; + mask >>= 1; + } +} + + +static MY_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) - 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 MY_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 = 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 \ + { unsigned nbits = (31 - in.numBits) & -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 MY_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 MY_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_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(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(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 ((buf - buf_start) * 8 + in.numBits != 64) + return S_FALSE; + if (GetUi64(buf_start) != 0) + return S_FALSE; + + return S_OK; +} + + +STDMETHODIMP 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; + + 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; + } + + const UInt64 rem = *outSize - 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 (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' + res = DecodeLzvn(cur); + 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 != m_InStream.GetProcessedSize() + || *outSize != m_OutWindowStream.GetProcessedSize()) + res = S_FALSE; + return res; +} + + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(...) { return E_OUTOFMEMORY; } + // catch(...) { return S_FALSE; } +} + +}} diff --git a/CPP/7zip/Compress/LzfseDecoder.h b/CPP/7zip/Compress/LzfseDecoder.h index 9d2b354f8..0156a0874 100644 --- a/CPP/7zip/Compress/LzfseDecoder.h +++ b/CPP/7zip/Compress/LzfseDecoder.h @@ -1,58 +1,58 @@ -// LzfseDecoder.h - -#ifndef __LZFSE_DECODER_H -#define __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 { - -class CDecoder: - public ICompressCoder, - public CMyUnknownImp -{ - 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); - HRESULT DecodeLzfse(UInt32 unpackSize, Byte version); - - STDMETHOD(CodeReal)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); -public: - MY_UNKNOWN_IMP - - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, - const UInt64 *outSize, ICompressProgressInfo *progress); -}; - -}} - -#endif +// LzfseDecoder.h + +#ifndef __LZFSE_DECODER_H +#define __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 { + +class CDecoder: + public ICompressCoder, + public CMyUnknownImp +{ + 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); + HRESULT DecodeLzfse(UInt32 unpackSize, Byte version); + + STDMETHOD(CodeReal)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); +public: + MY_UNKNOWN_IMP + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, + const UInt64 *outSize, ICompressProgressInfo *progress); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/LzhDecoder.cpp b/CPP/7zip/Compress/LzhDecoder.cpp index bd7a01b16..b0aa75363 100644 --- a/CPP/7zip/Compress/LzhDecoder.cpp +++ b/CPP/7zip/Compress/LzhDecoder.cpp @@ -1,250 +1,250 @@ -// 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++) - { - 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; - - UInt32 n = _inBitStream.ReadBits(numBits); - if (n == 0) - { - _symbolT = _inBitStream.ReadBits(numBits); - return ((unsigned)_symbolT < num); - } - - if (n > num) - return false; - - { - Byte lens[NPT]; - unsigned i; - for (i = 0; i < NPT; i++) - lens[i] = 0; - - i = 0; - - do - { - 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) - { - _symbolC = _inBitStream.ReadBits(NUM_C_BITS); - return ((unsigned)_symbolC < 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) -{ - unsigned pbit = (DictSize <= (1 << 14) ? 4 : 5); - - UInt32 blockSize = 0; - - while (rem != 0) - { - if (blockSize == 0) - { - if (_inBitStream.ExtraBitsWereRead()) - return S_FALSE; - - if (progress) - { - UInt64 packSize = _inBitStream.GetProcessedSize(); - 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; -} - - -STDMETHODIMP 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; } -} - -}}} +// 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++) + { + 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; + + UInt32 n = _inBitStream.ReadBits(numBits); + if (n == 0) + { + _symbolT = _inBitStream.ReadBits(numBits); + return ((unsigned)_symbolT < num); + } + + if (n > num) + return false; + + { + Byte lens[NPT]; + unsigned i; + for (i = 0; i < NPT; i++) + lens[i] = 0; + + i = 0; + + do + { + 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) + { + _symbolC = _inBitStream.ReadBits(NUM_C_BITS); + return ((unsigned)_symbolC < 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) +{ + unsigned pbit = (DictSize <= (1 << 14) ? 4 : 5); + + UInt32 blockSize = 0; + + while (rem != 0) + { + if (blockSize == 0) + { + if (_inBitStream.ExtraBitsWereRead()) + return S_FALSE; + + if (progress) + { + UInt64 packSize = _inBitStream.GetProcessedSize(); + 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; +} + + +STDMETHODIMP 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 index d6bbb37ab..5e13d8236 100644 --- a/CPP/7zip/Compress/LzhDecoder.h +++ b/CPP/7zip/Compress/LzhDecoder.h @@ -1,74 +1,74 @@ -// LzhDecoder.h - -#ifndef __COMPRESS_LZH_DECODER_H -#define __COMPRESS_LZH_DECODER_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/InBuffer.h" - -#include "BitmDecoder.h" -#include "HuffmanDecoder.h" -#include "LzOutWindow.h" - -namespace NCompress { -namespace NLzh { -namespace NDecoder { - -const 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) - -class CCoder: - public ICompressCoder, - public CMyUnknownImp -{ - CLzOutWindow _outWindow; - NBitm::CDecoder _inBitStream; - - int _symbolT; - int _symbolC; - - NHuffman::CDecoder _decoderT; - NHuffman::CDecoder _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: - MY_UNKNOWN_IMP - - UInt32 DictSize; - bool FinishMode; - - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - - void SetDictSize(unsigned dictSize) { DictSize = dictSize; } - - CCoder(): DictSize(1 << 16), FinishMode(false) {} - - UInt64 GetInputProcessedSize() const { return _inBitStream.GetProcessedSize(); } -}; - -}}} - -#endif +// LzhDecoder.h + +#ifndef __COMPRESS_LZH_DECODER_H +#define __COMPRESS_LZH_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "BitmDecoder.h" +#include "HuffmanDecoder.h" +#include "LzOutWindow.h" + +namespace NCompress { +namespace NLzh { +namespace NDecoder { + +const 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) + +class CCoder: + public ICompressCoder, + public CMyUnknownImp +{ + CLzOutWindow _outWindow; + NBitm::CDecoder _inBitStream; + + int _symbolT; + int _symbolC; + + NHuffman::CDecoder _decoderT; + NHuffman::CDecoder _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: + MY_UNKNOWN_IMP + + UInt32 DictSize; + bool FinishMode; + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + 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 bb631c5c5..653fe2de0 100644 --- a/CPP/7zip/Compress/Lzma2Decoder.cpp +++ b/CPP/7zip/Compress/Lzma2Decoder.cpp @@ -1,265 +1,265 @@ -// Lzma2Decoder.cpp - -#include "StdAfx.h" - -// #include - -#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 + +#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 + +}} diff --git a/CPP/7zip/Compress/Lzma2Decoder.h b/CPP/7zip/Compress/Lzma2Decoder.h index b56488e0d..e14148848 100644 --- a/CPP/7zip/Compress/Lzma2Decoder.h +++ b/CPP/7zip/Compress/Lzma2Decoder.h @@ -1,96 +1,96 @@ -// 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 _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 __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 _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 diff --git a/CPP/7zip/Compress/Lzma2Encoder.cpp b/CPP/7zip/Compress/Lzma2Encoder.cpp index 4f5b00b18..d2fc7b10b 100644 --- a/CPP/7zip/Compress/Lzma2Encoder.cpp +++ b/CPP/7zip/Compress/Lzma2Encoder.cpp @@ -1,389 +1,389 @@ -// Lzma2Encoder.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "../../../C/fast-lzma2/fl2_errors.h" - -#include "../Common/CWrappers.h" -#include "../Common/StreamUtils.h" - -#include "Lzma2Encoder.h" -#pragma warning(disable : 4127) - -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); -} - - -// Fast LZMA2 encoder - - -static HRESULT TranslateError(size_t res) -{ - if (FL2_getErrorCode(res) == FL2_error_memory_allocation) - return E_OUTOFMEMORY; - return S_FALSE; -} - -#define CHECK_S(f_) do { \ - size_t r_ = f_; \ - if (FL2_isError(r_)) \ - return TranslateError(r_); \ -} while (false) - -#define CHECK_H(f_) do { \ - HRESULT r_ = f_; \ - if (r_ != S_OK) \ - return r_; \ -} while (false) - -#define CHECK_P(f) if (FL2_isError(f)) return E_INVALIDARG; /* check and convert error code */ - -#define MIN_BLOCK_SIZE (1U << 20) -#define MAX_BLOCK_SIZE (1U << 28) - -CFastEncoder::FastLzma2::FastLzma2() - : fcs(NULL), - dict_pos(0) -{ -} - -CFastEncoder::FastLzma2::~FastLzma2() -{ - FL2_freeCCtx(fcs); -} - -HRESULT CFastEncoder::FastLzma2::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)); - } - if (fcs == NULL) { - fcs = FL2_createCStreamMt(lzma2Props.numTotalThreads, 1); - if (fcs == NULL) - return E_OUTOFMEMORY; - } - if (lzma2Props.lzmaProps.algo > 2) { - if (lzma2Props.lzmaProps.algo > 3) - return E_INVALIDARG; - lzma2Props.lzmaProps.algo = 2; - FL2_CCtx_setParameter(fcs, FL2_p_highCompression, 1); - FL2_CCtx_setParameter(fcs, FL2_p_compressionLevel, lzma2Props.lzmaProps.level); - } - else { - FL2_CCtx_setParameter(fcs, FL2_p_compressionLevel, lzma2Props.lzmaProps.level); - } - size_t dictSize = lzma2Props.lzmaProps.dictSize; - if (!dictSize) { - dictSize = (UInt32)FL2_CCtx_getParameter(fcs, FL2_p_dictionarySize); - } - UInt64 reduceSize = lzma2Props.lzmaProps.reduceSize; - reduceSize += (reduceSize < (UInt64)-1); /* prevent extra buffer shift after read */ - dictSize = (UInt32)min(dictSize, reduceSize); - dictSize = max(dictSize, FL2_DICTSIZE_MIN); - CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_dictionarySize, dictSize)); - if (lzma2Props.lzmaProps.algo >= 0) { - CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_strategy, (unsigned)lzma2Props.lzmaProps.algo)); - } - if (lzma2Props.lzmaProps.fb > 0) - CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_fastLength, lzma2Props.lzmaProps.fb)); - if (lzma2Props.lzmaProps.mc > 0) - CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_hybridCycles, lzma2Props.lzmaProps.mc)); - if (lzma2Props.lzmaProps.lc >= 0) - CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_literalCtxBits, lzma2Props.lzmaProps.lc)); - if (lzma2Props.lzmaProps.lp >= 0) - CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_literalPosBits, lzma2Props.lzmaProps.lp)); - if (lzma2Props.lzmaProps.pb >= 0) - CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_posBits, lzma2Props.lzmaProps.pb)); - if (lzma2Props.blockSize == 0) - lzma2Props.blockSize = min(max(MIN_BLOCK_SIZE, dictSize * 4U), MAX_BLOCK_SIZE); - else if (lzma2Props.blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) - lzma2Props.blockSize = 0; - unsigned r = 0; - if (lzma2Props.blockSize != 0) { - r = 1; - // Do not exceed the block size. TODO: the lib should support setting a value instead of a multiplier. - while (r < FL2_RESET_INTERVAL_MAX && (r + 1) * (UInt64)dictSize <= lzma2Props.blockSize) - ++r; - } - CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_resetInterval, r)); - FL2_CCtx_setParameter(fcs, FL2_p_omitProperties, 1); - FL2_setCStreamTimeout(fcs, 500); - return S_OK; -} - -size_t CFastEncoder::FastLzma2::GetDictSize() const -{ - return FL2_CCtx_getParameter(fcs, FL2_p_dictionarySize); -} - -HRESULT CFastEncoder::FastLzma2::Begin() -{ - CHECK_S(FL2_initCStream(fcs, 0)); - CHECK_S(FL2_getDictionaryBuffer(fcs, &dict)); - dict_pos = 0; - return S_OK; -} - -BYTE* CFastEncoder::FastLzma2::GetAvailableBuffer(unsigned long& size) -{ - size = static_cast(dict.size - dict_pos); - return reinterpret_cast(dict.dst) + dict_pos; -} - -HRESULT CFastEncoder::FastLzma2::WaitAndReport(size_t& res, ICompressProgressInfo *progress) -{ - while (FL2_isTimedOut(res)) { - if (!UpdateProgress(progress)) - return S_FALSE; - res = FL2_waitCStream(fcs); - } - CHECK_S(res); - return S_OK; -} - -HRESULT CFastEncoder::FastLzma2::AddByteCount(size_t count, ISequentialOutStream *outStream, ICompressProgressInfo *progress) -{ - dict_pos += count; - if (dict_pos == dict.size) { - size_t res = FL2_updateDictionary(fcs, dict_pos); - CHECK_H(WaitAndReport(res, progress)); - if (res != 0) - CHECK_H(WriteBuffers(outStream)); - res = FL2_getDictionaryBuffer(fcs, &dict); - while (FL2_isTimedOut(res)) { - if (!UpdateProgress(progress)) - return S_FALSE; - res = FL2_getDictionaryBuffer(fcs, &dict); - } - CHECK_S(res); - dict_pos = 0; - } - if (!UpdateProgress(progress)) - return S_FALSE; - return S_OK; -} - -bool CFastEncoder::FastLzma2::UpdateProgress(ICompressProgressInfo *progress) -{ - if (progress) { - UInt64 outProcessed; - UInt64 inProcessed = FL2_getCStreamProgress(fcs, &outProcessed); - HRESULT err = progress->SetRatioInfo(&inProcessed, &outProcessed); - if (err != S_OK) { - FL2_cancelCStream(fcs); - return false; - } - } - return true; -} - -HRESULT CFastEncoder::FastLzma2::WriteBuffers(ISequentialOutStream *outStream) -{ - size_t csize; - for (;;) { - FL2_cBuffer cbuf; - do { - csize = FL2_getNextCompressedBuffer(fcs, &cbuf); - } while (FL2_isTimedOut(csize)); - CHECK_S(csize); - if (csize == 0) - break; - HRESULT err = WriteStream(outStream, cbuf.src, cbuf.size); - if (err != S_OK) - return err; - } - return S_OK; -} - -HRESULT CFastEncoder::FastLzma2::End(ISequentialOutStream *outStream, ICompressProgressInfo *progress) -{ - if (dict_pos) { - size_t res = FL2_updateDictionary(fcs, dict_pos); - CHECK_H(WaitAndReport(res, progress)); - } - - size_t res = FL2_endStream(fcs, nullptr); - CHECK_H(WaitAndReport(res, progress)); - while (res) { - CHECK_H(WriteBuffers(outStream)); - res = FL2_endStream(fcs, nullptr); - CHECK_H(WaitAndReport(res, progress)); - } - return S_OK; -} - -void CFastEncoder::FastLzma2::Cancel() -{ - FL2_cancelCStream(fcs); -} - -CFastEncoder::CFastEncoder() -{ -} - -CFastEncoder::~CFastEncoder() -{ -} - - -STDMETHODIMP CFastEncoder::SetCoderProperties(const PROPID *propIDs, - const PROPVARIANT *coderProps, UInt32 numProps) -{ - return _encoder.SetCoderProperties(propIDs, coderProps, numProps); -} - - -#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) - -STDMETHODIMP CFastEncoder::WriteCoderProperties(ISequentialOutStream *outStream) -{ - Byte prop; - unsigned i; - size_t dictSize = _encoder.GetDictSize(); - for (i = 0; i < 40; i++) - if (dictSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) - break; - prop = (Byte)i; - return WriteStream(outStream, &prop, 1); -} - - -STDMETHODIMP CFastEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) -{ - CHECK_H(_encoder.Begin()); - size_t inSize; - unsigned long dSize; - do - { - BYTE* dict = _encoder.GetAvailableBuffer(dSize); - - inSize = dSize; - HRESULT err = ReadStream(inStream, dict, &inSize); - if (err != S_OK) { - _encoder.Cancel(); - return err; - } - CHECK_H(_encoder.AddByteCount(inSize, outStream, progress)); - - } while (inSize == dSize); - - CHECK_H(_encoder.End(outStream, progress)); - - return S_OK; -} - -}} +// Lzma2Encoder.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "../../../C/fast-lzma2/fl2_errors.h" + +#include "../Common/CWrappers.h" +#include "../Common/StreamUtils.h" + +#include "Lzma2Encoder.h" +#pragma warning(disable : 4127) + +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); +} + + +// Fast LZMA2 encoder + + +static HRESULT TranslateError(size_t res) +{ + if (FL2_getErrorCode(res) == FL2_error_memory_allocation) + return E_OUTOFMEMORY; + return S_FALSE; +} + +#define CHECK_S(f_) do { \ + size_t r_ = f_; \ + if (FL2_isError(r_)) \ + return TranslateError(r_); \ +} while (false) + +#define CHECK_H(f_) do { \ + HRESULT r_ = f_; \ + if (r_ != S_OK) \ + return r_; \ +} while (false) + +#define CHECK_P(f) if (FL2_isError(f)) return E_INVALIDARG; /* check and convert error code */ + +#define MIN_BLOCK_SIZE (1U << 20) +#define MAX_BLOCK_SIZE (1U << 28) + +CFastEncoder::FastLzma2::FastLzma2() + : fcs(NULL), + dict_pos(0) +{ +} + +CFastEncoder::FastLzma2::~FastLzma2() +{ + FL2_freeCCtx(fcs); +} + +HRESULT CFastEncoder::FastLzma2::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)); + } + if (fcs == NULL) { + fcs = FL2_createCStreamMt(lzma2Props.numTotalThreads, 1); + if (fcs == NULL) + return E_OUTOFMEMORY; + } + if (lzma2Props.lzmaProps.algo > 2) { + if (lzma2Props.lzmaProps.algo > 3) + return E_INVALIDARG; + lzma2Props.lzmaProps.algo = 2; + FL2_CCtx_setParameter(fcs, FL2_p_highCompression, 1); + FL2_CCtx_setParameter(fcs, FL2_p_compressionLevel, lzma2Props.lzmaProps.level); + } + else { + FL2_CCtx_setParameter(fcs, FL2_p_compressionLevel, lzma2Props.lzmaProps.level); + } + size_t dictSize = lzma2Props.lzmaProps.dictSize; + if (!dictSize) { + dictSize = (UInt32)FL2_CCtx_getParameter(fcs, FL2_p_dictionarySize); + } + UInt64 reduceSize = lzma2Props.lzmaProps.reduceSize; + reduceSize += (reduceSize < (UInt64)-1); /* prevent extra buffer shift after read */ + dictSize = (UInt32)min(dictSize, reduceSize); + dictSize = max(dictSize, FL2_DICTSIZE_MIN); + CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_dictionarySize, dictSize)); + if (lzma2Props.lzmaProps.algo >= 0) { + CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_strategy, (unsigned)lzma2Props.lzmaProps.algo)); + } + if (lzma2Props.lzmaProps.fb > 0) + CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_fastLength, lzma2Props.lzmaProps.fb)); + if (lzma2Props.lzmaProps.mc > 0) + CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_hybridCycles, lzma2Props.lzmaProps.mc)); + if (lzma2Props.lzmaProps.lc >= 0) + CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_literalCtxBits, lzma2Props.lzmaProps.lc)); + if (lzma2Props.lzmaProps.lp >= 0) + CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_literalPosBits, lzma2Props.lzmaProps.lp)); + if (lzma2Props.lzmaProps.pb >= 0) + CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_posBits, lzma2Props.lzmaProps.pb)); + if (lzma2Props.blockSize == 0) + lzma2Props.blockSize = min(max(MIN_BLOCK_SIZE, dictSize * 4U), MAX_BLOCK_SIZE); + else if (lzma2Props.blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) + lzma2Props.blockSize = 0; + unsigned r = 0; + if (lzma2Props.blockSize != 0) { + r = 1; + // Do not exceed the block size. TODO: the lib should support setting a value instead of a multiplier. + while (r < FL2_RESET_INTERVAL_MAX && (r + 1) * (UInt64)dictSize <= lzma2Props.blockSize) + ++r; + } + CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_resetInterval, r)); + FL2_CCtx_setParameter(fcs, FL2_p_omitProperties, 1); + FL2_setCStreamTimeout(fcs, 500); + return S_OK; +} + +size_t CFastEncoder::FastLzma2::GetDictSize() const +{ + return FL2_CCtx_getParameter(fcs, FL2_p_dictionarySize); +} + +HRESULT CFastEncoder::FastLzma2::Begin() +{ + CHECK_S(FL2_initCStream(fcs, 0)); + CHECK_S(FL2_getDictionaryBuffer(fcs, &dict)); + dict_pos = 0; + return S_OK; +} + +BYTE* CFastEncoder::FastLzma2::GetAvailableBuffer(unsigned long& size) +{ + size = static_cast(dict.size - dict_pos); + return reinterpret_cast(dict.dst) + dict_pos; +} + +HRESULT CFastEncoder::FastLzma2::WaitAndReport(size_t& res, ICompressProgressInfo *progress) +{ + while (FL2_isTimedOut(res)) { + if (!UpdateProgress(progress)) + return S_FALSE; + res = FL2_waitCStream(fcs); + } + CHECK_S(res); + return S_OK; +} + +HRESULT CFastEncoder::FastLzma2::AddByteCount(size_t count, ISequentialOutStream *outStream, ICompressProgressInfo *progress) +{ + dict_pos += count; + if (dict_pos == dict.size) { + size_t res = FL2_updateDictionary(fcs, dict_pos); + CHECK_H(WaitAndReport(res, progress)); + if (res != 0) + CHECK_H(WriteBuffers(outStream)); + res = FL2_getDictionaryBuffer(fcs, &dict); + while (FL2_isTimedOut(res)) { + if (!UpdateProgress(progress)) + return S_FALSE; + res = FL2_getDictionaryBuffer(fcs, &dict); + } + CHECK_S(res); + dict_pos = 0; + } + if (!UpdateProgress(progress)) + return S_FALSE; + return S_OK; +} + +bool CFastEncoder::FastLzma2::UpdateProgress(ICompressProgressInfo *progress) +{ + if (progress) { + UInt64 outProcessed; + UInt64 inProcessed = FL2_getCStreamProgress(fcs, &outProcessed); + HRESULT err = progress->SetRatioInfo(&inProcessed, &outProcessed); + if (err != S_OK) { + FL2_cancelCStream(fcs); + return false; + } + } + return true; +} + +HRESULT CFastEncoder::FastLzma2::WriteBuffers(ISequentialOutStream *outStream) +{ + size_t csize; + for (;;) { + FL2_cBuffer cbuf; + do { + csize = FL2_getNextCompressedBuffer(fcs, &cbuf); + } while (FL2_isTimedOut(csize)); + CHECK_S(csize); + if (csize == 0) + break; + HRESULT err = WriteStream(outStream, cbuf.src, cbuf.size); + if (err != S_OK) + return err; + } + return S_OK; +} + +HRESULT CFastEncoder::FastLzma2::End(ISequentialOutStream *outStream, ICompressProgressInfo *progress) +{ + if (dict_pos) { + size_t res = FL2_updateDictionary(fcs, dict_pos); + CHECK_H(WaitAndReport(res, progress)); + } + + size_t res = FL2_endStream(fcs, nullptr); + CHECK_H(WaitAndReport(res, progress)); + while (res) { + CHECK_H(WriteBuffers(outStream)); + res = FL2_endStream(fcs, nullptr); + CHECK_H(WaitAndReport(res, progress)); + } + return S_OK; +} + +void CFastEncoder::FastLzma2::Cancel() +{ + FL2_cancelCStream(fcs); +} + +CFastEncoder::CFastEncoder() +{ +} + +CFastEncoder::~CFastEncoder() +{ +} + + +STDMETHODIMP CFastEncoder::SetCoderProperties(const PROPID *propIDs, + const PROPVARIANT *coderProps, UInt32 numProps) +{ + return _encoder.SetCoderProperties(propIDs, coderProps, numProps); +} + + +#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) + +STDMETHODIMP CFastEncoder::WriteCoderProperties(ISequentialOutStream *outStream) +{ + Byte prop; + unsigned i; + size_t dictSize = _encoder.GetDictSize(); + for (i = 0; i < 40; i++) + if (dictSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) + break; + prop = (Byte)i; + return WriteStream(outStream, &prop, 1); +} + + +STDMETHODIMP CFastEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) +{ + CHECK_H(_encoder.Begin()); + size_t inSize; + unsigned long dSize; + do + { + BYTE* dict = _encoder.GetAvailableBuffer(dSize); + + inSize = dSize; + HRESULT err = ReadStream(inStream, dict, &inSize); + if (err != S_OK) { + _encoder.Cancel(); + return err; + } + CHECK_H(_encoder.AddByteCount(inSize, outStream, progress)); + + } while (inSize == dSize); + + CHECK_H(_encoder.End(outStream, progress)); + + return S_OK; +} + +}} diff --git a/CPP/7zip/Compress/Lzma2Encoder.h b/CPP/7zip/Compress/Lzma2Encoder.h index 734c697ba..3211a1d62 100644 --- a/CPP/7zip/Compress/Lzma2Encoder.h +++ b/CPP/7zip/Compress/Lzma2Encoder.h @@ -1,93 +1,93 @@ -// Lzma2Encoder.h - -#ifndef __LZMA2_ENCODER_H -#define __LZMA2_ENCODER_H - -#include "../../../C/Lzma2Enc.h" -#include "../../../C/fast-lzma2/fast-lzma2.h" - -#include "../../Common/MyCom.h" -#include "../../Common/MyBuffer.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(); -}; - -class CFastEncoder : - public ICompressCoder, - public ICompressSetCoderProperties, - public ICompressWriteCoderProperties, - public CMyUnknownImp -{ - class FastLzma2 - { - public: - FastLzma2(); - ~FastLzma2(); - HRESULT SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); - size_t GetDictSize() const; - HRESULT Begin(); - BYTE* GetAvailableBuffer(unsigned long& size); - HRESULT AddByteCount(size_t count, ISequentialOutStream *outStream, ICompressProgressInfo *progress); - HRESULT End(ISequentialOutStream *outStream, ICompressProgressInfo *progress); - void Cancel(); - - private: - bool UpdateProgress(ICompressProgressInfo *progress); - HRESULT WaitAndReport(size_t& res, ICompressProgressInfo *progress); - HRESULT WriteBuffers(ISequentialOutStream *outStream); - - FL2_CStream* fcs; - FL2_dictBuffer dict; - size_t dict_pos; - - FastLzma2(const FastLzma2&) = delete; - FastLzma2& operator=(const FastLzma2&) = delete; - }; - - FastLzma2 _encoder; - -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); - - CFastEncoder(); - virtual ~CFastEncoder(); -}; - -}} - -#endif +// Lzma2Encoder.h + +#ifndef __LZMA2_ENCODER_H +#define __LZMA2_ENCODER_H + +#include "../../../C/Lzma2Enc.h" +#include "../../../C/fast-lzma2/fast-lzma2.h" + +#include "../../Common/MyCom.h" +#include "../../Common/MyBuffer.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(); +}; + +class CFastEncoder : + public ICompressCoder, + public ICompressSetCoderProperties, + public ICompressWriteCoderProperties, + public CMyUnknownImp +{ + class FastLzma2 + { + public: + FastLzma2(); + ~FastLzma2(); + HRESULT SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); + size_t GetDictSize() const; + HRESULT Begin(); + BYTE* GetAvailableBuffer(unsigned long& size); + HRESULT AddByteCount(size_t count, ISequentialOutStream *outStream, ICompressProgressInfo *progress); + HRESULT End(ISequentialOutStream *outStream, ICompressProgressInfo *progress); + void Cancel(); + + private: + bool UpdateProgress(ICompressProgressInfo *progress); + HRESULT WaitAndReport(size_t& res, ICompressProgressInfo *progress); + HRESULT WriteBuffers(ISequentialOutStream *outStream); + + FL2_CStream* fcs; + FL2_dictBuffer dict; + size_t dict_pos; + + FastLzma2(const FastLzma2&) = delete; + FastLzma2& operator=(const FastLzma2&) = delete; + }; + + FastLzma2 _encoder; + +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); + + CFastEncoder(); + virtual ~CFastEncoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Lzma2Register.cpp b/CPP/7zip/Compress/Lzma2Register.cpp index 436710563..8f279ebf1 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 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 b6a8d3fbd..83c24f1c1 100644 --- a/CPP/7zip/Compress/LzmaDecoder.cpp +++ b/CPP/7zip/Compress/LzmaDecoder.cpp @@ -1,343 +1,343 @@ -// 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(): + _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 + +}} diff --git a/CPP/7zip/Compress/LzmaDecoder.h b/CPP/7zip/Compress/LzmaDecoder.h index 08b7c1bc3..37dec0258 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 _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 __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 _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 diff --git a/CPP/7zip/Compress/LzmaEncoder.cpp b/CPP/7zip/Compress/LzmaEncoder.cpp index 3151c3d21..e47f776b6 100644 --- a/CPP/7zip/Compress/LzmaEncoder.cpp +++ b/CPP/7zip/Compress/LzmaEncoder.cpp @@ -1,182 +1,182 @@ -// 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" + +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); +} + +}} diff --git a/CPP/7zip/Compress/LzmaEncoder.h b/CPP/7zip/Compress/LzmaEncoder.h index 7b31c66d8..7d706ad70 100644 --- a/CPP/7zip/Compress/LzmaEncoder.h +++ b/CPP/7zip/Compress/LzmaEncoder.h @@ -1,46 +1,46 @@ -// 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 __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 diff --git a/CPP/7zip/Compress/LzmaRegister.cpp b/CPP/7zip/Compress/LzmaRegister.cpp index 439759508..c802a99fa 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 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 index f67548b37..5189ce16d 100644 --- a/CPP/7zip/Compress/LzmsDecoder.cpp +++ b/CPP/7zip/Compress/LzmsDecoder.cpp @@ -1,576 +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 (;;) - { - 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 (;;) - { - const 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; - - 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; - { - const Byte *p2 = p + codeLen; - UInt32 n = GetUi32(p2); - if (i - last_x86_pos <= maxTransOffset) - { - n -= i; - SetUi32(p2, n); - } - target = history + (((UInt32)i + n) & 0xFFFF); - } - - i += 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 - - 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]; - { - 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 - - 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); - } - - 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; -} - -}} +// 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 (;;) + { + 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 (;;) + { + const 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; + + 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; + { + const Byte *p2 = p + codeLen; + UInt32 n = GetUi32(p2); + if (i - last_x86_pos <= maxTransOffset) + { + n -= i; + SetUi32(p2, n); + } + target = history + (((UInt32)i + n) & 0xFFFF); + } + + i += 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 + + 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]; + { + 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 + + 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); + } + + 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 index b9f49e9a4..510d33897 100644 --- a/CPP/7zip/Compress/LzmsDecoder.h +++ b/CPP/7zip/Compress/LzmsDecoder.h @@ -1,271 +1,271 @@ -// LzmsDecoder.h -// The code is based on LZMS description from wimlib code - -#ifndef __LZMS_DECODER_H -#define __LZMS_DECODER_H - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#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 -class CHuffDecoder: public NCompress::NHuffman::CDecoder -{ -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 += (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 m_LitDecoder; - CHuffDecoder m_PosDecoder; - CHuffDecoder m_LenDecoder; - CHuffDecoder m_PowerDecoder; - CHuffDecoder 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); - const size_t GetUnpackSize() const { return _pos; } -}; - -}} - -#endif +// LzmsDecoder.h +// The code is based on LZMS description from wimlib code + +#ifndef __LZMS_DECODER_H +#define __LZMS_DECODER_H + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#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 +class CHuffDecoder: public NCompress::NHuffman::CDecoder +{ +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 += (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 m_LitDecoder; + CHuffDecoder m_PosDecoder; + CHuffDecoder m_LenDecoder; + CHuffDecoder m_PowerDecoder; + CHuffDecoder 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); + const size_t GetUnpackSize() const { return _pos; } +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Lzx.h b/CPP/7zip/Compress/Lzx.h index 41d2e11dc..29ca4cacc 100644 --- a/CPP/7zip/Compress/Lzx.h +++ b/CPP/7zip/Compress/Lzx.h @@ -1,57 +1,57 @@ -// Lzx.h - -#ifndef __COMPRESS_LZX_H -#define __COMPRESS_LZX_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 +// Lzx.h + +#ifndef __COMPRESS_LZX_H +#define __COMPRESS_LZX_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 index 524849d0e..a7bba903d 100644 --- a/CPP/7zip/Compress/LzxDecoder.cpp +++ b/CPP/7zip/Compress/LzxDecoder.cpp @@ -1,529 +1,529 @@ -// LzxDecoder.cpp - -#include "StdAfx.h" - -#include - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#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; - - Byte save = data[(size_t)size + 4]; - data[(size_t)size + 4] = 0xE8; - - for (UInt32 i = 0;;) - { - const 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 = GetUi32(p); - Int32 pos = (Int32)((Int32)1 - (Int32)(processedSize + i)); - i += 4; - if (v >= pos && v < (Int32)translationSize) - { - v += (v >= 0 ? pos : translationSize); - SetUi32(p, v); - } - } - } - - data[(size_t)size + 4] = save; -} - - -CDecoder::CDecoder(bool wimMode): - _win(NULL), - _keepHistory(false), - _skipByte(false), - _wimMode(wimMode), - _numDictBits(15), - _unpackBlockSize(0), - _x86_buf(NULL), - _x86_translationSize(0), - KeepHistoryForNext(true), - NeedAlloc(true), - _unpackedData(NULL) -{ -} - -CDecoder::~CDecoder() -{ - if (NeedAlloc) - ::MidFree(_win); - ::MidFree(_x86_buf); -} - -HRESULT CDecoder::Flush() -{ - if (_x86_translationSize != 0) - { - Byte *destData = _win + _writePos; - 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; - - 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(); - - 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++) - { - 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) - { - 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; - UInt32 posSlot = sym / kNumLenSlots; - 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); - 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 - { - 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); - - HRESULT res = CodeSpec(outSize); - 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; - 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)); - - 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; -} - -}} +// LzxDecoder.cpp + +#include "StdAfx.h" + +#include + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#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; + + Byte save = data[(size_t)size + 4]; + data[(size_t)size + 4] = 0xE8; + + for (UInt32 i = 0;;) + { + const 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 = GetUi32(p); + Int32 pos = (Int32)((Int32)1 - (Int32)(processedSize + i)); + i += 4; + if (v >= pos && v < (Int32)translationSize) + { + v += (v >= 0 ? pos : translationSize); + SetUi32(p, v); + } + } + } + + data[(size_t)size + 4] = save; +} + + +CDecoder::CDecoder(bool wimMode): + _win(NULL), + _keepHistory(false), + _skipByte(false), + _wimMode(wimMode), + _numDictBits(15), + _unpackBlockSize(0), + _x86_buf(NULL), + _x86_translationSize(0), + KeepHistoryForNext(true), + NeedAlloc(true), + _unpackedData(NULL) +{ +} + +CDecoder::~CDecoder() +{ + if (NeedAlloc) + ::MidFree(_win); + ::MidFree(_x86_buf); +} + +HRESULT CDecoder::Flush() +{ + if (_x86_translationSize != 0) + { + Byte *destData = _win + _writePos; + 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; + + 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(); + + 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++) + { + 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) + { + 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; + UInt32 posSlot = sym / kNumLenSlots; + 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); + 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 + { + 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); + + HRESULT res = CodeSpec(outSize); + 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; + 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)); + + 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 index 70a4f1cf1..a5c6f12cf 100644 --- a/CPP/7zip/Compress/LzxDecoder.h +++ b/CPP/7zip/Compress/LzxDecoder.h @@ -1,246 +1,246 @@ -// LzxDecoder.h - -#ifndef __LZX_DECODER_H -#define __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 _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++; - } -}; - - -class CDecoder: - public IUnknown, - public CMyUnknownImp -{ - 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 _mainDecoder; - NHuffman::CDecoder _lenDecoder; - NHuffman::CDecoder7b _alignDecoder; - NHuffman::CDecoder _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(); - - MY_UNKNOWN_IMP - - 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; } - const UInt32 GetUnpackSize() const { return _pos - _writePos; } -}; - -}} - -#endif +// LzxDecoder.h + +#ifndef __LZX_DECODER_H +#define __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 _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++; + } +}; + + +class CDecoder: + public IUnknown, + public CMyUnknownImp +{ + 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 _mainDecoder; + NHuffman::CDecoder _lenDecoder; + NHuffman::CDecoder7b _alignDecoder; + NHuffman::CDecoder _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(); + + MY_UNKNOWN_IMP + + 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; } + const UInt32 GetUnpackSize() const { return _pos - _writePos; } +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Mtf8.h b/CPP/7zip/Compress/Mtf8.h index 12cb01048..50a84cee9 100644 --- a/CPP/7zip/Compress/Mtf8.h +++ b/CPP/7zip/Compress/Mtf8.h @@ -1,212 +1,212 @@ -// Mtf8.h - -#ifndef __COMPRESS_MTF8_H -#define __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++); - 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 MTF_MOVS 3 -#else - typedef UInt32 CMtfVar; - #define MTF_MOVS 2 -#endif - -#define MTF_MASK ((1 << MTF_MOVS) - 1) - - -struct CMtf8Decoder -{ - CMtfVar Buf[256 >> MTF_MOVS]; - - void StartInit() { memset(Buf, 0, sizeof(Buf)); } - void Add(unsigned pos, Byte val) { Buf[pos >> MTF_MOVS] |= ((CMtfVar)val << ((pos & MTF_MASK) << 3)); } - Byte GetHead() const { return (Byte)Buf[0]; } - - MY_FORCE_INLINE - Byte GetAndMove(unsigned pos) throw() - { - UInt32 lim = ((UInt32)pos >> MTF_MOVS); - pos = (pos & MTF_MASK) << 3; - CMtfVar prev = (Buf[lim] >> pos) & 0xFF; - - UInt32 i = 0; - - - /* - if ((lim & 1) != 0) - { - CMtfVar next = Buf[0]; - Buf[0] = (next << 8) | prev; - prev = (next >> (MTF_MASK << 3)); - i = 1; - lim -= 1; - } - for (; i < lim; i += 2) - { - CMtfVar n0 = Buf[i]; - CMtfVar n1 = Buf[i + 1]; - Buf[i ] = (n0 << 8) | prev; - Buf[i + 1] = (n1 << 8) | (n0 >> (MTF_MASK << 3)); - prev = (n1 >> (MTF_MASK << 3)); - } - */ - - for (; i < lim; i++) - { - CMtfVar n0 = Buf[i]; - Buf[i ] = (n0 << 8) | prev; - prev = (n0 >> (MTF_MASK << 3)); - } - - - CMtfVar next = Buf[i]; - CMtfVar mask = (((CMtfVar)0x100 << pos) - 1); - Buf[i] = (next & ~mask) | (((next << 8) | prev) & mask); - return (Byte)Buf[0]; - } -}; - -/* -const int kSmallSize = 64; -class CMtf8Decoder -{ - Byte SmallBuffer[kSmallSize]; - int SmallSize; - 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 +// Mtf8.h + +#ifndef __COMPRESS_MTF8_H +#define __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++); + 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 MTF_MOVS 3 +#else + typedef UInt32 CMtfVar; + #define MTF_MOVS 2 +#endif + +#define MTF_MASK ((1 << MTF_MOVS) - 1) + + +struct CMtf8Decoder +{ + CMtfVar Buf[256 >> MTF_MOVS]; + + void StartInit() { memset(Buf, 0, sizeof(Buf)); } + void Add(unsigned pos, Byte val) { Buf[pos >> MTF_MOVS] |= ((CMtfVar)val << ((pos & MTF_MASK) << 3)); } + Byte GetHead() const { return (Byte)Buf[0]; } + + MY_FORCE_INLINE + Byte GetAndMove(unsigned pos) throw() + { + UInt32 lim = ((UInt32)pos >> MTF_MOVS); + pos = (pos & MTF_MASK) << 3; + CMtfVar prev = (Buf[lim] >> pos) & 0xFF; + + UInt32 i = 0; + + + /* + if ((lim & 1) != 0) + { + CMtfVar next = Buf[0]; + Buf[0] = (next << 8) | prev; + prev = (next >> (MTF_MASK << 3)); + i = 1; + lim -= 1; + } + for (; i < lim; i += 2) + { + CMtfVar n0 = Buf[i]; + CMtfVar n1 = Buf[i + 1]; + Buf[i ] = (n0 << 8) | prev; + Buf[i + 1] = (n1 << 8) | (n0 >> (MTF_MASK << 3)); + prev = (n1 >> (MTF_MASK << 3)); + } + */ + + for (; i < lim; i++) + { + CMtfVar n0 = Buf[i]; + Buf[i ] = (n0 << 8) | prev; + prev = (n0 >> (MTF_MASK << 3)); + } + + + CMtfVar next = Buf[i]; + CMtfVar mask = (((CMtfVar)0x100 << pos) - 1); + Buf[i] = (next & ~mask) | (((next << 8) | prev) & mask); + return (Byte)Buf[0]; + } +}; + +/* +const int kSmallSize = 64; +class CMtf8Decoder +{ + Byte SmallBuffer[kSmallSize]; + int SmallSize; + 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 4820c0a7c..ed0e9e294 100644 --- a/CPP/7zip/Compress/PpmdDecoder.cpp +++ b/CPP/7zip/Compress/PpmdDecoder.cpp @@ -1,170 +1,170 @@ -// 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 +// 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 + +}} diff --git a/CPP/7zip/Compress/PpmdDecoder.h b/CPP/7zip/Compress/PpmdDecoder.h index 3c2f49349..2b6213c0e 100644 --- a/CPP/7zip/Compress/PpmdDecoder.h +++ b/CPP/7zip/Compress/PpmdDecoder.h @@ -1,86 +1,86 @@ -// 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 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 +// 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 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 diff --git a/CPP/7zip/Compress/PpmdEncoder.cpp b/CPP/7zip/Compress/PpmdEncoder.cpp index 0aef701d0..34e6d361e 100644 --- a/CPP/7zip/Compress/PpmdEncoder.cpp +++ b/CPP/7zip/Compress/PpmdEncoder.cpp @@ -1,152 +1,152 @@ -// 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 "../../../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)); + } + } +} + +}} diff --git a/CPP/7zip/Compress/PpmdEncoder.h b/CPP/7zip/Compress/PpmdEncoder.h index cdb0352b7..671a5353e 100644 --- a/CPP/7zip/Compress/PpmdEncoder.h +++ b/CPP/7zip/Compress/PpmdEncoder.h @@ -1,58 +1,58 @@ -// 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 __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 diff --git a/CPP/7zip/Compress/PpmdRegister.cpp b/CPP/7zip/Compress/PpmdRegister.cpp index c7486966c..a3ebb5f3d 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 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 index 441cd83b2..d9ce218ae 100644 --- a/CPP/7zip/Compress/PpmdZip.cpp +++ b/CPP/7zip/Compress/PpmdZip.cpp @@ -1,287 +1,287 @@ -// 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) -{ - _ppmd.Stream.In = &_inStream.vt; - Ppmd8_Construct(&_ppmd); -} - -CDecoder::~CDecoder() -{ - Ppmd8_Free(&_ppmd, &g_BigAlloc); -} - -STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - if (!_outStream.Alloc()) - return E_OUTOFMEMORY; - if (!_inStream.Alloc(1 << 20)) - return E_OUTOFMEMORY; - - _inStream.Stream = inStream; - _inStream.Init(); - - { - Byte buf[2]; - for (int i = 0; i < 2; i++) - buf[i] = _inStream.ReadByte(); - if (_inStream.Extra) - return S_FALSE; - - UInt32 val = GetUi16(buf); - UInt32 order = (val & 0xF) + 1; - UInt32 mem = ((val >> 4) & 0xFF) + 1; - UInt32 restor = (val >> 12); - if (order < 2 || restor > 2) - return S_FALSE; - - #ifndef PPMD8_FREEZE_SUPPORT - if (restor == 2) - return E_NOTIMPL; - #endif - - if (!Ppmd8_Alloc(&_ppmd, mem << 20, &g_BigAlloc)) - return E_OUTOFMEMORY; - - if (!Ppmd8_RangeDec_Init(&_ppmd)) - return S_FALSE; - Ppmd8_Init(&_ppmd, order, restor); - } - - bool wasFinished = false; - UInt64 processedSize = 0; - - for (;;) - { - size_t size = kBufSize; - if (outSize) - { - const UInt64 rem = *outSize - processedSize; - if (size > rem) - { - size = (size_t)rem; - if (size == 0) - break; - } - } - - Byte *data = _outStream.Buf; - size_t i = 0; - int sym = 0; - do - { - sym = Ppmd8_DecodeSymbol(&_ppmd); - if (_inStream.Extra || sym < 0) - break; - data[i] = (Byte)sym; - } - while (++i != size); - - processedSize += i; - - RINOK(WriteStream(outStream, _outStream.Buf, i)); - - RINOK(_inStream.Res); - if (_inStream.Extra) - return S_FALSE; - - if (sym < 0) - { - if (sym != -1) - return S_FALSE; - wasFinished = true; - break; - } - - if (progress) - { - const UInt64 inProccessed = _inStream.GetProcessed(); - RINOK(progress->SetRatioInfo(&inProccessed, &processedSize)); - } - } - - RINOK(_inStream.Res); - - if (_fullFileMode) - { - if (!wasFinished) - { - int res = Ppmd8_DecodeSymbol(&_ppmd); - RINOK(_inStream.Res); - if (_inStream.Extra || res != -1) - return S_FALSE; - } - if (!Ppmd8_RangeDec_IsFinishedOK(&_ppmd)) - return S_FALSE; - - if (inSize && *inSize != _inStream.GetProcessed()) - return S_FALSE; - } - - return S_OK; -} - - -STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode) -{ - _fullFileMode = (finishMode != 0); - return S_OK; -} - -STDMETHODIMP 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 > 8 ? 8 : level) - 1)); - const unsigned kMult = 16; - if ((MemSizeMB << 20) / kMult > ReduceSize) - { - for (UInt32 m = (1 << 20); m <= (1 << 28); m <<= 1) - { - if (ReduceSize <= m / kMult) - { - m >>= 20; - if (MemSizeMB > m) - 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); -} - -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 << 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 > 1) - return E_INVALIDARG; - props.Restor = 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); -} - -STDMETHODIMP 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_RangeEnc_Init(&_ppmd); - Ppmd8_Init(&_ppmd, _props.Order, _props.Restor); - - UInt32 val = (UInt32)((_props.Order - 1) + ((_props.MemSizeMB - 1) << 4) + (_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_RangeEnc_FlushData(&_ppmd); - return _outStream.Flush(); - } - for (UInt32 i = 0; i < size; i++) - { - Ppmd8_EncodeSymbol(&_ppmd, _inStream.Buf[i]); - RINOK(_outStream.Res); - } - processed += size; - if (progress) - { - const UInt64 outProccessed = _outStream.GetProcessed(); - RINOK(progress->SetRatioInfo(&processed, &outProccessed)); - } - } -} - -}} +// 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) +{ + _ppmd.Stream.In = &_inStream.vt; + Ppmd8_Construct(&_ppmd); +} + +CDecoder::~CDecoder() +{ + Ppmd8_Free(&_ppmd, &g_BigAlloc); +} + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + if (!_outStream.Alloc()) + return E_OUTOFMEMORY; + if (!_inStream.Alloc(1 << 20)) + return E_OUTOFMEMORY; + + _inStream.Stream = inStream; + _inStream.Init(); + + { + Byte buf[2]; + for (int i = 0; i < 2; i++) + buf[i] = _inStream.ReadByte(); + if (_inStream.Extra) + return S_FALSE; + + UInt32 val = GetUi16(buf); + UInt32 order = (val & 0xF) + 1; + UInt32 mem = ((val >> 4) & 0xFF) + 1; + UInt32 restor = (val >> 12); + if (order < 2 || restor > 2) + return S_FALSE; + + #ifndef PPMD8_FREEZE_SUPPORT + if (restor == 2) + return E_NOTIMPL; + #endif + + if (!Ppmd8_Alloc(&_ppmd, mem << 20, &g_BigAlloc)) + return E_OUTOFMEMORY; + + if (!Ppmd8_RangeDec_Init(&_ppmd)) + return S_FALSE; + Ppmd8_Init(&_ppmd, order, restor); + } + + bool wasFinished = false; + UInt64 processedSize = 0; + + for (;;) + { + size_t size = kBufSize; + if (outSize) + { + const UInt64 rem = *outSize - processedSize; + if (size > rem) + { + size = (size_t)rem; + if (size == 0) + break; + } + } + + Byte *data = _outStream.Buf; + size_t i = 0; + int sym = 0; + do + { + sym = Ppmd8_DecodeSymbol(&_ppmd); + if (_inStream.Extra || sym < 0) + break; + data[i] = (Byte)sym; + } + while (++i != size); + + processedSize += i; + + RINOK(WriteStream(outStream, _outStream.Buf, i)); + + RINOK(_inStream.Res); + if (_inStream.Extra) + return S_FALSE; + + if (sym < 0) + { + if (sym != -1) + return S_FALSE; + wasFinished = true; + break; + } + + if (progress) + { + const UInt64 inProccessed = _inStream.GetProcessed(); + RINOK(progress->SetRatioInfo(&inProccessed, &processedSize)); + } + } + + RINOK(_inStream.Res); + + if (_fullFileMode) + { + if (!wasFinished) + { + int res = Ppmd8_DecodeSymbol(&_ppmd); + RINOK(_inStream.Res); + if (_inStream.Extra || res != -1) + return S_FALSE; + } + if (!Ppmd8_RangeDec_IsFinishedOK(&_ppmd)) + return S_FALSE; + + if (inSize && *inSize != _inStream.GetProcessed()) + return S_FALSE; + } + + return S_OK; +} + + +STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode) +{ + _fullFileMode = (finishMode != 0); + return S_OK; +} + +STDMETHODIMP 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 > 8 ? 8 : level) - 1)); + const unsigned kMult = 16; + if ((MemSizeMB << 20) / kMult > ReduceSize) + { + for (UInt32 m = (1 << 20); m <= (1 << 28); m <<= 1) + { + if (ReduceSize <= m / kMult) + { + m >>= 20; + if (MemSizeMB > m) + 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); +} + +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 << 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 > 1) + return E_INVALIDARG; + props.Restor = 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); +} + +STDMETHODIMP 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_RangeEnc_Init(&_ppmd); + Ppmd8_Init(&_ppmd, _props.Order, _props.Restor); + + UInt32 val = (UInt32)((_props.Order - 1) + ((_props.MemSizeMB - 1) << 4) + (_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_RangeEnc_FlushData(&_ppmd); + return _outStream.Flush(); + } + for (UInt32 i = 0; i < size; i++) + { + Ppmd8_EncodeSymbol(&_ppmd, _inStream.Buf[i]); + RINOK(_outStream.Res); + } + processed += size; + if (progress) + { + const UInt64 outProccessed = _outStream.GetProcessed(); + RINOK(progress->SetRatioInfo(&processed, &outProccessed)); + } + } +} + +}} diff --git a/CPP/7zip/Compress/PpmdZip.h b/CPP/7zip/Compress/PpmdZip.h index 6c9638c70..b8c7aae0a 100644 --- a/CPP/7zip/Compress/PpmdZip.h +++ b/CPP/7zip/Compress/PpmdZip.h @@ -1,97 +1,97 @@ -// PpmdZip.h - -#ifndef __COMPRESS_PPMD_ZIP_H -#define __COMPRESS_PPMD_ZIP_H - -#include "../../../C/Alloc.h" -#include "../../../C/Ppmd8.h" - -#include "../../Common/MyCom.h" - -#include "../Common/CWrappers.h" - -#include "../ICoder.h" - -namespace NCompress { -namespace NPpmdZip { - -static const UInt32 kBufSize = (1 << 20); - -struct CBuf -{ - Byte *Buf; - - CBuf(): Buf(0) {} - ~CBuf() { ::MidFree(Buf); } - bool Alloc() - { - if (!Buf) - Buf = (Byte *)::MidAlloc(kBufSize); - return (Buf != 0); - } -}; - - -class CDecoder : - public ICompressCoder, - public ICompressSetFinishMode, - public ICompressGetInStreamProcessedSize, - public CMyUnknownImp -{ - CByteInBufWrap _inStream; - CBuf _outStream; - CPpmd8 _ppmd; - bool _fullFileMode; -public: - MY_UNKNOWN_IMP2( - ICompressSetFinishMode, - ICompressGetInStreamProcessedSize) - - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - STDMETHOD(SetFinishMode)(UInt32 finishMode); - STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); - - CDecoder(bool fullFileMode); - ~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); -}; - -class CEncoder : - public ICompressCoder, - public ICompressSetCoderProperties, - public CMyUnknownImp -{ - CByteOutBufWrap _outStream; - CBuf _inStream; - CPpmd8 _ppmd; - CEncProps _props; -public: - MY_UNKNOWN_IMP1(ICompressSetCoderProperties) - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); - CEncoder(); - ~CEncoder(); -}; - -}} - -#endif +// PpmdZip.h + +#ifndef __COMPRESS_PPMD_ZIP_H +#define __COMPRESS_PPMD_ZIP_H + +#include "../../../C/Alloc.h" +#include "../../../C/Ppmd8.h" + +#include "../../Common/MyCom.h" + +#include "../Common/CWrappers.h" + +#include "../ICoder.h" + +namespace NCompress { +namespace NPpmdZip { + +static const UInt32 kBufSize = (1 << 20); + +struct CBuf +{ + Byte *Buf; + + CBuf(): Buf(0) {} + ~CBuf() { ::MidFree(Buf); } + bool Alloc() + { + if (!Buf) + Buf = (Byte *)::MidAlloc(kBufSize); + return (Buf != 0); + } +}; + + +class CDecoder : + public ICompressCoder, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize, + public CMyUnknownImp +{ + CByteInBufWrap _inStream; + CBuf _outStream; + CPpmd8 _ppmd; + bool _fullFileMode; +public: + MY_UNKNOWN_IMP2( + ICompressSetFinishMode, + ICompressGetInStreamProcessedSize) + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + STDMETHOD(SetFinishMode)(UInt32 finishMode); + STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); + + CDecoder(bool fullFileMode); + ~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); +}; + +class CEncoder : + public ICompressCoder, + public ICompressSetCoderProperties, + public CMyUnknownImp +{ + CByteOutBufWrap _outStream; + CBuf _inStream; + CPpmd8 _ppmd; + CEncProps _props; +public: + MY_UNKNOWN_IMP1(ICompressSetCoderProperties) + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); + CEncoder(); + ~CEncoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/QuantumDecoder.cpp b/CPP/7zip/Compress/QuantumDecoder.cpp index d68fbe32a..64e35bf2f 100644 --- a/CPP/7zip/Compress/QuantumDecoder.cpp +++ b/CPP/7zip/Compress/QuantumDecoder.cpp @@ -1,195 +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) -{ - 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]); - unsigned res = Vals[--i]; - - do - 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]) - { - UInt16 tmpFreq = Freqs[i]; - 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] >>= 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); - 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) - { - 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; - 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(); - - HRESULT res = CodeSpec(inData, inSize, outSize); - 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; -} - -}} +// 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) +{ + 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]); + unsigned res = Vals[--i]; + + do + 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]) + { + UInt16 tmpFreq = Freqs[i]; + 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] >>= 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); + 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) + { + 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; + 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(); + + HRESULT res = CodeSpec(inData, inSize, outSize); + 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 index 968587ea3..afeba7088 100644 --- a/CPP/7zip/Compress/QuantumDecoder.h +++ b/CPP/7zip/Compress/QuantumDecoder.h @@ -1,175 +1,175 @@ -// QuantumDecoder.h - -#ifndef __COMPRESS_QUANTUM_DECODER_H -#define __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); -}; - - -class CDecoder: - public IUnknown, - public CMyUnknownImp -{ - 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: - - MY_UNKNOWN_IMP - - HRESULT Code(const Byte *inData, size_t inSize, - ISequentialOutStream *outStream, UInt32 outSize, - bool keepHistory); - - HRESULT SetParams(unsigned numDictBits); - - CDecoder(): _numDictBits(0) {} - virtual ~CDecoder() {} -}; - -}} - -#endif +// QuantumDecoder.h + +#ifndef __COMPRESS_QUANTUM_DECODER_H +#define __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); +}; + + +class CDecoder: + public IUnknown, + public CMyUnknownImp +{ + 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: + + MY_UNKNOWN_IMP + + HRESULT Code(const Byte *inData, size_t inSize, + ISequentialOutStream *outStream, UInt32 outSize, + bool keepHistory); + + HRESULT SetParams(unsigned numDictBits); + + CDecoder(): _numDictBits(0) {} + virtual ~CDecoder() {} +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Rar1Decoder.cpp b/CPP/7zip/Compress/Rar1Decoder.cpp index 02de07040..6b55705b6 100644 --- a/CPP/7zip/Compress/Rar1Decoder.cpp +++ b/CPP/7zip/Compress/Rar1Decoder.cpp @@ -1,516 +1,516 @@ -// 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 (;;) - { - UInt32 num = numTab[i]; - 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); - } - - 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; - UInt32 flagsPlace = DecodeNum(PosHf2); // [0, 256] - - if (flagsPlace >= 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 (int j = 0; j < 32; j++, CharSet++) - *CharSet = (*CharSet & ~0xff) | i; - memset(NumToPlace, 0, sizeof(NToPl)); - for (i = 6; i >= 0; i--) - NumToPlace[i] = (7 - i) * 32; -} - - - -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 (int 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(); -} - - -STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - -STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) -{ - if (size < 1) - return E_INVALIDARG; - _isSolid = ((data[0] & 1) != 0); - return S_OK; -} - -}} +// 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 (;;) + { + UInt32 num = numTab[i]; + 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); + } + + 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; + UInt32 flagsPlace = DecodeNum(PosHf2); // [0, 256] + + if (flagsPlace >= 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 (int j = 0; j < 32; j++, CharSet++) + *CharSet = (*CharSet & ~0xff) | i; + memset(NumToPlace, 0, sizeof(NToPl)); + for (i = 6; i >= 0; i--) + NumToPlace[i] = (7 - i) * 32; +} + + + +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 (int 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(); +} + + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + if (size < 1) + return E_INVALIDARG; + _isSolid = ((data[0] & 1) != 0); + return S_OK; +} + +}} diff --git a/CPP/7zip/Compress/Rar1Decoder.h b/CPP/7zip/Compress/Rar1Decoder.h index b5dc1eb43..52907e5c4 100644 --- a/CPP/7zip/Compress/Rar1Decoder.h +++ b/CPP/7zip/Compress/Rar1Decoder.h @@ -1,79 +1,79 @@ -// Rar1Decoder.h -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -#ifndef __COMPRESS_RAR1_DECODER_H -#define __COMPRESS_RAR1_DECODER_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/InBuffer.h" - -#include "BitmDecoder.h" -#include "HuffmanDecoder.h" -#include "LzOutWindow.h" - -namespace NCompress { -namespace NRar1 { - -const UInt32 kNumRepDists = 4; - -class CDecoder : - public ICompressCoder, - public ICompressSetDecoderProperties2, - public CMyUnknownImp -{ - CLzOutWindow m_OutWindowStream; - NBitm::CDecoder 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(); - - MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) - - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - - STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); - -}; - -}} - -#endif +// Rar1Decoder.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#ifndef __COMPRESS_RAR1_DECODER_H +#define __COMPRESS_RAR1_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "BitmDecoder.h" +#include "HuffmanDecoder.h" +#include "LzOutWindow.h" + +namespace NCompress { +namespace NRar1 { + +const UInt32 kNumRepDists = 4; + +class CDecoder : + public ICompressCoder, + public ICompressSetDecoderProperties2, + public CMyUnknownImp +{ + CLzOutWindow m_OutWindowStream; + NBitm::CDecoder 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(); + + MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); + +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Rar2Decoder.cpp b/CPP/7zip/Compress/Rar2Decoder.cpp index dd27e369e..fe458c851 100644 --- a/CPP/7zip/Compress/Rar2Decoder.cpp +++ b/CPP/7zip/Compress/Rar2Decoder.cpp @@ -1,435 +1,435 @@ -// Rar2Decoder.cpp -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -#include "StdAfx.h" - -#include "Rar2Decoder.h" - -namespace NCompress { -namespace NRar2 { - -namespace NMultimedia { - -Byte CFilter::Decode(int &channelDelta, Byte deltaByte) -{ - D4 = D3; - D3 = D2; - D2 = LastDelta - D1; - D1 = LastDelta; - int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3); - - Byte realValue = (Byte)(predictedValue - deltaByte); - - { - int i = ((int)(signed char)deltaByte) << 3; - - Dif[0] += abs(i); - Dif[1] += abs(i - D1); - Dif[2] += abs(i + D1); - Dif[3] += abs(i - D2); - Dif[4] += abs(i + D2); - Dif[5] += abs(i - D3); - Dif[6] += abs(i + D3); - Dif[7] += abs(i - D4); - Dif[8] += abs(i + D4); - Dif[9] += abs(i - channelDelta); - Dif[10] += abs(i + channelDelta); - } - - channelDelta = LastDelta = (signed char)(realValue - LastChar); - LastChar = realValue; - - if (((++ByteCount) & 0x1F) == 0) - { - UInt32 minDif = Dif[0]; - UInt32 numMinDif = 0; - Dif[0] = 0; - - for (unsigned i = 1; i < 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 - { - 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 - } - 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) - { - UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream); - if (symbol == 256) - return ReadTables(); - if (symbol >= kMMTableSize) - return false; - } - else - { - 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) - { - 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); - */ - 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; - - 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; - - 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(); -} - -STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - -STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) -{ - if (size < 1) - return E_INVALIDARG; - _isSolid = ((data[0] & 1) != 0); - return S_OK; -} - -}} +// Rar2Decoder.cpp +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#include "StdAfx.h" + +#include "Rar2Decoder.h" + +namespace NCompress { +namespace NRar2 { + +namespace NMultimedia { + +Byte CFilter::Decode(int &channelDelta, Byte deltaByte) +{ + D4 = D3; + D3 = D2; + D2 = LastDelta - D1; + D1 = LastDelta; + int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3); + + Byte realValue = (Byte)(predictedValue - deltaByte); + + { + int i = ((int)(signed char)deltaByte) << 3; + + Dif[0] += abs(i); + Dif[1] += abs(i - D1); + Dif[2] += abs(i + D1); + Dif[3] += abs(i - D2); + Dif[4] += abs(i + D2); + Dif[5] += abs(i - D3); + Dif[6] += abs(i + D3); + Dif[7] += abs(i - D4); + Dif[8] += abs(i + D4); + Dif[9] += abs(i - channelDelta); + Dif[10] += abs(i + channelDelta); + } + + channelDelta = LastDelta = (signed char)(realValue - LastChar); + LastChar = realValue; + + if (((++ByteCount) & 0x1F) == 0) + { + UInt32 minDif = Dif[0]; + UInt32 numMinDif = 0; + Dif[0] = 0; + + for (unsigned i = 1; i < 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 + { + 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 + } + 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) + { + UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream); + if (symbol == 256) + return ReadTables(); + if (symbol >= kMMTableSize) + return false; + } + else + { + 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) + { + 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); + */ + 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; + + 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; + + 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(); +} + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + if (size < 1) + return E_INVALIDARG; + _isSolid = ((data[0] & 1) != 0); + return S_OK; +} + +}} diff --git a/CPP/7zip/Compress/Rar2Decoder.h b/CPP/7zip/Compress/Rar2Decoder.h index a8a531d85..f42f228d4 100644 --- a/CPP/7zip/Compress/Rar2Decoder.h +++ b/CPP/7zip/Compress/Rar2Decoder.h @@ -1,172 +1,172 @@ -// Rar2Decoder.h -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -#ifndef __COMPRESS_RAR2_DECODER_H -#define __COMPRESS_RAR2_DECODER_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/InBuffer.h" - -#include "BitmDecoder.h" -#include "HuffmanDecoder.h" -#include "LzOutWindow.h" - -namespace NCompress { -namespace NRar2 { - -const 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 CBitDecoder; - -const unsigned kNumHuffmanBits = 15; - -class CDecoder : - public ICompressCoder, - public ICompressSetDecoderProperties2, - public CMyUnknownImp -{ - 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 m_MainDecoder; - NHuffman::CDecoder m_DistDecoder; - NHuffman::CDecoder m_LenDecoder; - NHuffman::CDecoder m_MMDecoders[NMultimedia::kNumChanelsMax]; - NHuffman::CDecoder 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(); - - MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) - - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - - STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); - -}; - -}} - -#endif +// Rar2Decoder.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#ifndef __COMPRESS_RAR2_DECODER_H +#define __COMPRESS_RAR2_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "BitmDecoder.h" +#include "HuffmanDecoder.h" +#include "LzOutWindow.h" + +namespace NCompress { +namespace NRar2 { + +const 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 CBitDecoder; + +const unsigned kNumHuffmanBits = 15; + +class CDecoder : + public ICompressCoder, + public ICompressSetDecoderProperties2, + public CMyUnknownImp +{ + 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 m_MainDecoder; + NHuffman::CDecoder m_DistDecoder; + NHuffman::CDecoder m_LenDecoder; + NHuffman::CDecoder m_MMDecoders[NMultimedia::kNumChanelsMax]; + NHuffman::CDecoder 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(); + + MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); + +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Rar3Decoder.cpp b/CPP/7zip/Compress/Rar3Decoder.cpp index 7b1b31fba..4456ba631 100644 --- a/CPP/7zip/Compress/Rar3Decoder.cpp +++ b/CPP/7zip/Compress/Rar3Decoder.cpp @@ -1,960 +1,960 @@ -// 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 UInt32 kSymbolLen2 = kSymbolRep + kNumReps; - -static const Byte kLenStart [kLenTableSize] = {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224}; -static const Byte kLenDirectBits[kLenTableSize] = {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5}; - -static const Byte kDistDirectBits[kDistTableSize] = - {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 18,18,18,18,18,18,18,18,18,18,18,18}; - -static const Byte kLevelDirectBits[kLevelTableSize] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -static const Byte kLen2DistStarts[kNumLen2Symbols]={0,4,8,16,32,64,128,192}; -static const Byte kLen2DistDirectBits[kNumLen2Symbols]={2,2,3, 4, 5, 6, 6, 6}; - -static const UInt32 kDistLimit3 = 0x2000 - 2; -static const UInt32 kDistLimit4 = 0x40000 - 2; - -static const UInt32 kNormalMatchMinLen = 3; - -static const UInt32 kVmDataSizeMax = 1 << 16; -static const UInt32 kVmCodeSizeMax = 1 << 16; - -extern "C" { - -#define GET_RangeDecoder CRangeDecoder *p = CONTAINER_FROM_VTBL_CLS(pp, CRangeDecoder, vt); - -static UInt32 Range_GetThreshold(const IPpmd7_RangeDec *pp, UInt32 total) -{ - GET_RangeDecoder; - return p->Code / (p->Range /= total); -} - -static void Range_Decode(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size) -{ - GET_RangeDecoder; - start *= p->Range; - p->Low += start; - p->Code -= start; - p->Range *= size; - p->Normalize(); -} - -static UInt32 Range_DecodeBit(const IPpmd7_RangeDec *pp, UInt32 size0) -{ - GET_RangeDecoder; - if (p->Code / (p->Range >>= 14) < size0) - { - Range_Decode(&p->vt, 0, size0); - return 0; - } - else - { - Range_Decode(&p->vt, size0, (1 << 14) - size0); - return 1; - } -} - -} - -CRangeDecoder::CRangeDecoder() throw() -{ - vt.GetThreshold = Range_GetThreshold; - vt.Decode = Range_Decode; - vt.DecodeBit = Range_DecodeBit; -} - -CDecoder::CDecoder(): - _window(0), - _winPos(0), - _wrPtr(0), - _lzSize(0), - _writtenFileSize(0), - _vmData(0), - _vmCode(0), - _isSolid(false), - _solidAllowed(false) -{ - Ppmd7_Construct(&_ppmd); -} - -CDecoder::~CDecoder() -{ - InitFilters(); - ::MidFree(_vmData); - ::MidFree(_window); - Ppmd7_Free(&_ppmd, &g_BigAlloc); -} - -HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size) -{ - return WriteStream(_outStream, data, size); -} - -HRESULT CDecoder::WriteData(const Byte *data, UInt32 size) -{ - HRESULT res = S_OK; - if (_writtenFileSize < _unpackSize) - { - UInt32 curSize = size; - UInt64 remain = _unpackSize - _writtenFileSize; - if (remain < curSize) - curSize = (UInt32)remain; - res = WriteDataToStream(data, curSize); - } - _writtenFileSize += size; - return res; -} - -HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr) -{ - if (startPtr <= endPtr) - return WriteData(_window + startPtr, endPtr - startPtr); - RINOK(WriteData(_window + startPtr, kWindowSize - startPtr)); - return WriteData(_window, endPtr); -} - -void CDecoder::ExecuteFilter(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 &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 length = (firstByte & 7) + 1; - if (length == 7) - length = ReadBits(8) + 7; - else if (length == 8) - length = ReadBits(16); - if (length > kVmDataSizeMax) - return false; - for (UInt32 i = 0; i < length; i++) - _vmData[i] = (Byte)ReadBits(8); - return AddVmCode(firstByte, length); -} - -bool CDecoder::ReadVmCodePPM() -{ - int firstByte = DecodePpmSymbol(); - if (firstByte < 0) - return false; - UInt32 length = (firstByte & 7) + 1; - if (length == 7) - { - int b1 = DecodePpmSymbol(); - if (b1 < 0) - return false; - length = b1 + 7; - } - else if (length == 8) - { - int b1 = DecodePpmSymbol(); - if (b1 < 0) - return false; - int b2 = DecodePpmSymbol(); - if (b2 < 0) - return false; - length = b1 * 256 + b2; - } - if (length > kVmDataSizeMax) - return false; - if (InputEofError_Fast()) - return false; - for (UInt32 i = 0; i < length; i++) - { - int b = DecodePpmSymbol(); - if (b < 0) - return false; - _vmData[i] = (Byte)b; - } - return AddVmCode(firstByte, length); -} - -#define RIF(x) { if (!(x)) return S_FALSE; } - -UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.BitDecoder.ReadBits(numBits); } - -// ---------- PPM ---------- - -HRESULT CDecoder::InitPPM() -{ - unsigned maxOrder = (unsigned)ReadBits(7); - - bool reset = ((maxOrder & 0x20) != 0); - UInt32 maxMB = 0; - if (reset) - maxMB = (Byte)ReadBits(8); - else - { - if (PpmError || !Ppmd7_WasAllocated(&_ppmd)) - return S_FALSE; - } - if (maxOrder & 0x40) - PpmEscChar = (Byte)ReadBits(8); - m_InBitStream.InitRangeCoder(); - /* - if (m_InBitStream.m_BitPos != 0) - return S_FALSE; - */ - if (reset) - { - PpmError = true; - maxOrder = (maxOrder & 0x1F) + 1; - if (maxOrder > 16) - maxOrder = 16 + (maxOrder - 16) * 3; - if (maxOrder == 1) - { - Ppmd7_Free(&_ppmd, &g_BigAlloc); - return S_FALSE; - } - if (!Ppmd7_Alloc(&_ppmd, (maxMB + 1) << 20, &g_BigAlloc)) - return E_OUTOFMEMORY; - Ppmd7_Init(&_ppmd, maxOrder); - PpmError = false; - } - return S_OK; -} - -int CDecoder::DecodePpmSymbol() { return Ppmd7_DecodeSymbol(&_ppmd, &m_InBitStream.vt); } - -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; - int c = DecodePpmSymbol(); - if (c < 0) - { - PpmError = true; - return S_FALSE; - } - if (c == PpmEscChar) - { - int nextCh = DecodePpmSymbol(); - if (nextCh < 0) - { - PpmError = true; - return S_FALSE; - } - if (nextCh == 0) - return ReadTables(keepDecompressing); - if (nextCh == 2 || nextCh == -1) - return S_OK; - if (nextCh == 3) - { - if (!ReadVmCodePPM()) - { - PpmError = true; - return S_FALSE; - } - continue; - } - if (nextCh == 4 || nextCh == 5) - { - UInt32 distance = 0; - UInt32 length = 4; - if (nextCh == 4) - { - for (int i = 0; i < 3; i++) - { - int c2 = DecodePpmSymbol(); - if (c2 < 0) - { - PpmError = true; - return S_FALSE; - } - distance = (distance << 8) + (Byte)c2; - } - distance++; - length += 28; - } - int c2 = DecodePpmSymbol(); - if (c2 < 0) - { - PpmError = true; - return S_FALSE; - } - length += c2; - if (distance >= _lzSize) - return S_FALSE; - CopyBlock(distance, length); - num -= (Int32)length; - continue; - } - } - PutByte((Byte)c); - num--; - } - while (num >= 0); - keepDecompressing = true; - return S_OK; -} - -// ---------- LZ ---------- - -HRESULT CDecoder::ReadTables(bool &keepDecompressing) -{ - keepDecompressing = true; - 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++) - { - UInt32 length = ReadBits(4); - if (length == 15) - { - UInt32 zeroCount = ReadBits(4); - if (zeroCount != 0) - { - zeroCount += 2; - while (zeroCount-- > 0 && i < kLevelTableSize) - levelLevels[i++]=0; - i--; - continue; - } - } - levelLevels[i] = (Byte)length; - } - - RIF(m_LevelDecoder.Build(levelLevels)); - - i = 0; - - do - { - 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); -} - -UInt32 kDistStart[kDistTableSize]; - -class CDistInit -{ -public: - CDistInit() { Init(); } - void Init() - { - UInt32 start = 0; - for (UInt32 i = 0; i < kDistTableSize; i++) - { - kDistStart[i] = start; - start += (1 << kDistDirectBits[i]); - } - } -} g_DistInit; - -HRESULT CDecoder::DecodeLZ(bool &keepDecompressing) -{ - UInt32 rep0 = _reps[0]; - UInt32 rep1 = _reps[1]; - UInt32 rep2 = _reps[2]; - UInt32 rep3 = _reps[3]; - UInt32 length = _lastLength; - for (;;) - { - if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos) - { - RINOK(WriteBuf()); - if (_writtenFileSize > _unpackSize) - { - keepDecompressing = false; - return S_OK; - } - } - - 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 (length == 0) - return S_FALSE; - } - else if (sym < kSymbolRep + 4) - { - if (sym != kSymbolRep) - { - UInt32 distance; - if (sym == kSymbolRep + 1) - distance = rep1; - else - { - if (sym == kSymbolRep + 2) - distance = rep2; - else - { - distance = rep3; - rep3 = rep2; - } - rep2 = rep1; - } - rep1 = rep0; - rep0 = distance; - } - - const UInt32 sym2 = m_LenDecoder.Decode(&m_InBitStream.BitDecoder); - if (sym2 >= kLenTableSize) - return S_FALSE; - length = 2 + kLenStart[sym2] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[sym2]); - } - else - { - rep3 = rep2; - rep2 = rep1; - rep1 = rep0; - if (sym < 271) - { - sym -= 263; - rep0 = kLen2DistStarts[sym] + m_InBitStream.BitDecoder.ReadBits(kLen2DistDirectBits[sym]); - length = 2; - } - else if (sym < 299) - { - sym -= 271; - length = kNormalMatchMinLen + (UInt32)kLenStart[sym] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[sym]); - 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(numBits); - length += ((kDistLimit4 - rep0) >> 31) + ((kDistLimit3 - rep0) >> 31); - } - else - return S_FALSE; - } - if (rep0 >= _lzSize) - return S_FALSE; - CopyBlock(rep0, length); - } - _reps[0] = rep0; - _reps[1] = rep1; - _reps[2] = rep2; - _reps[3] = rep3; - _lastLength = length; - - return S_OK; -} - - -HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress) -{ - _writtenFileSize = 0; - _unsupportedFilter = false; - - if (!_isSolid) - { - _lzSize = 0; - _winPos = 0; - _wrPtr = 0; - for (int i = 0; i < kNumReps; i++) - _reps[i] = 0; - _lastLength = 0; - memset(m_LastLevels, 0, kTablesSizesSum); - TablesRead = false; - PpmEscChar = 2; - PpmError = true; - InitFilters(); - // _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; - - UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize)); - if (!keepDecompressing) - break; - } - - _solidAllowed = true; - - RINOK(WriteBuf()); - 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; -} - -STDMETHODIMP 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. -} - -STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) -{ - if (size < 1) - return E_INVALIDARG; - _isSolid = ((data[0] & 1) != 0); - return S_OK; -} - -}} +// 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 UInt32 kSymbolLen2 = kSymbolRep + kNumReps; + +static const Byte kLenStart [kLenTableSize] = {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224}; +static const Byte kLenDirectBits[kLenTableSize] = {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5}; + +static const Byte kDistDirectBits[kDistTableSize] = + {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 18,18,18,18,18,18,18,18,18,18,18,18}; + +static const Byte kLevelDirectBits[kLevelTableSize] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +static const Byte kLen2DistStarts[kNumLen2Symbols]={0,4,8,16,32,64,128,192}; +static const Byte kLen2DistDirectBits[kNumLen2Symbols]={2,2,3, 4, 5, 6, 6, 6}; + +static const UInt32 kDistLimit3 = 0x2000 - 2; +static const UInt32 kDistLimit4 = 0x40000 - 2; + +static const UInt32 kNormalMatchMinLen = 3; + +static const UInt32 kVmDataSizeMax = 1 << 16; +static const UInt32 kVmCodeSizeMax = 1 << 16; + +extern "C" { + +#define GET_RangeDecoder CRangeDecoder *p = CONTAINER_FROM_VTBL_CLS(pp, CRangeDecoder, vt); + +static UInt32 Range_GetThreshold(const IPpmd7_RangeDec *pp, UInt32 total) +{ + GET_RangeDecoder; + return p->Code / (p->Range /= total); +} + +static void Range_Decode(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size) +{ + GET_RangeDecoder; + start *= p->Range; + p->Low += start; + p->Code -= start; + p->Range *= size; + p->Normalize(); +} + +static UInt32 Range_DecodeBit(const IPpmd7_RangeDec *pp, UInt32 size0) +{ + GET_RangeDecoder; + if (p->Code / (p->Range >>= 14) < size0) + { + Range_Decode(&p->vt, 0, size0); + return 0; + } + else + { + Range_Decode(&p->vt, size0, (1 << 14) - size0); + return 1; + } +} + +} + +CRangeDecoder::CRangeDecoder() throw() +{ + vt.GetThreshold = Range_GetThreshold; + vt.Decode = Range_Decode; + vt.DecodeBit = Range_DecodeBit; +} + +CDecoder::CDecoder(): + _window(0), + _winPos(0), + _wrPtr(0), + _lzSize(0), + _writtenFileSize(0), + _vmData(0), + _vmCode(0), + _isSolid(false), + _solidAllowed(false) +{ + Ppmd7_Construct(&_ppmd); +} + +CDecoder::~CDecoder() +{ + InitFilters(); + ::MidFree(_vmData); + ::MidFree(_window); + Ppmd7_Free(&_ppmd, &g_BigAlloc); +} + +HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size) +{ + return WriteStream(_outStream, data, size); +} + +HRESULT CDecoder::WriteData(const Byte *data, UInt32 size) +{ + HRESULT res = S_OK; + if (_writtenFileSize < _unpackSize) + { + UInt32 curSize = size; + UInt64 remain = _unpackSize - _writtenFileSize; + if (remain < curSize) + curSize = (UInt32)remain; + res = WriteDataToStream(data, curSize); + } + _writtenFileSize += size; + return res; +} + +HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr) +{ + if (startPtr <= endPtr) + return WriteData(_window + startPtr, endPtr - startPtr); + RINOK(WriteData(_window + startPtr, kWindowSize - startPtr)); + return WriteData(_window, endPtr); +} + +void CDecoder::ExecuteFilter(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 &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 length = (firstByte & 7) + 1; + if (length == 7) + length = ReadBits(8) + 7; + else if (length == 8) + length = ReadBits(16); + if (length > kVmDataSizeMax) + return false; + for (UInt32 i = 0; i < length; i++) + _vmData[i] = (Byte)ReadBits(8); + return AddVmCode(firstByte, length); +} + +bool CDecoder::ReadVmCodePPM() +{ + int firstByte = DecodePpmSymbol(); + if (firstByte < 0) + return false; + UInt32 length = (firstByte & 7) + 1; + if (length == 7) + { + int b1 = DecodePpmSymbol(); + if (b1 < 0) + return false; + length = b1 + 7; + } + else if (length == 8) + { + int b1 = DecodePpmSymbol(); + if (b1 < 0) + return false; + int b2 = DecodePpmSymbol(); + if (b2 < 0) + return false; + length = b1 * 256 + b2; + } + if (length > kVmDataSizeMax) + return false; + if (InputEofError_Fast()) + return false; + for (UInt32 i = 0; i < length; i++) + { + int b = DecodePpmSymbol(); + if (b < 0) + return false; + _vmData[i] = (Byte)b; + } + return AddVmCode(firstByte, length); +} + +#define RIF(x) { if (!(x)) return S_FALSE; } + +UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.BitDecoder.ReadBits(numBits); } + +// ---------- PPM ---------- + +HRESULT CDecoder::InitPPM() +{ + unsigned maxOrder = (unsigned)ReadBits(7); + + bool reset = ((maxOrder & 0x20) != 0); + UInt32 maxMB = 0; + if (reset) + maxMB = (Byte)ReadBits(8); + else + { + if (PpmError || !Ppmd7_WasAllocated(&_ppmd)) + return S_FALSE; + } + if (maxOrder & 0x40) + PpmEscChar = (Byte)ReadBits(8); + m_InBitStream.InitRangeCoder(); + /* + if (m_InBitStream.m_BitPos != 0) + return S_FALSE; + */ + if (reset) + { + PpmError = true; + maxOrder = (maxOrder & 0x1F) + 1; + if (maxOrder > 16) + maxOrder = 16 + (maxOrder - 16) * 3; + if (maxOrder == 1) + { + Ppmd7_Free(&_ppmd, &g_BigAlloc); + return S_FALSE; + } + if (!Ppmd7_Alloc(&_ppmd, (maxMB + 1) << 20, &g_BigAlloc)) + return E_OUTOFMEMORY; + Ppmd7_Init(&_ppmd, maxOrder); + PpmError = false; + } + return S_OK; +} + +int CDecoder::DecodePpmSymbol() { return Ppmd7_DecodeSymbol(&_ppmd, &m_InBitStream.vt); } + +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; + int c = DecodePpmSymbol(); + if (c < 0) + { + PpmError = true; + return S_FALSE; + } + if (c == PpmEscChar) + { + int nextCh = DecodePpmSymbol(); + if (nextCh < 0) + { + PpmError = true; + return S_FALSE; + } + if (nextCh == 0) + return ReadTables(keepDecompressing); + if (nextCh == 2 || nextCh == -1) + return S_OK; + if (nextCh == 3) + { + if (!ReadVmCodePPM()) + { + PpmError = true; + return S_FALSE; + } + continue; + } + if (nextCh == 4 || nextCh == 5) + { + UInt32 distance = 0; + UInt32 length = 4; + if (nextCh == 4) + { + for (int i = 0; i < 3; i++) + { + int c2 = DecodePpmSymbol(); + if (c2 < 0) + { + PpmError = true; + return S_FALSE; + } + distance = (distance << 8) + (Byte)c2; + } + distance++; + length += 28; + } + int c2 = DecodePpmSymbol(); + if (c2 < 0) + { + PpmError = true; + return S_FALSE; + } + length += c2; + if (distance >= _lzSize) + return S_FALSE; + CopyBlock(distance, length); + num -= (Int32)length; + continue; + } + } + PutByte((Byte)c); + num--; + } + while (num >= 0); + keepDecompressing = true; + return S_OK; +} + +// ---------- LZ ---------- + +HRESULT CDecoder::ReadTables(bool &keepDecompressing) +{ + keepDecompressing = true; + 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++) + { + UInt32 length = ReadBits(4); + if (length == 15) + { + UInt32 zeroCount = ReadBits(4); + if (zeroCount != 0) + { + zeroCount += 2; + while (zeroCount-- > 0 && i < kLevelTableSize) + levelLevels[i++]=0; + i--; + continue; + } + } + levelLevels[i] = (Byte)length; + } + + RIF(m_LevelDecoder.Build(levelLevels)); + + i = 0; + + do + { + 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); +} + +UInt32 kDistStart[kDistTableSize]; + +class CDistInit +{ +public: + CDistInit() { Init(); } + void Init() + { + UInt32 start = 0; + for (UInt32 i = 0; i < kDistTableSize; i++) + { + kDistStart[i] = start; + start += (1 << kDistDirectBits[i]); + } + } +} g_DistInit; + +HRESULT CDecoder::DecodeLZ(bool &keepDecompressing) +{ + UInt32 rep0 = _reps[0]; + UInt32 rep1 = _reps[1]; + UInt32 rep2 = _reps[2]; + UInt32 rep3 = _reps[3]; + UInt32 length = _lastLength; + for (;;) + { + if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos) + { + RINOK(WriteBuf()); + if (_writtenFileSize > _unpackSize) + { + keepDecompressing = false; + return S_OK; + } + } + + 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 (length == 0) + return S_FALSE; + } + else if (sym < kSymbolRep + 4) + { + if (sym != kSymbolRep) + { + UInt32 distance; + if (sym == kSymbolRep + 1) + distance = rep1; + else + { + if (sym == kSymbolRep + 2) + distance = rep2; + else + { + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + + const UInt32 sym2 = m_LenDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym2 >= kLenTableSize) + return S_FALSE; + length = 2 + kLenStart[sym2] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[sym2]); + } + else + { + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + if (sym < 271) + { + sym -= 263; + rep0 = kLen2DistStarts[sym] + m_InBitStream.BitDecoder.ReadBits(kLen2DistDirectBits[sym]); + length = 2; + } + else if (sym < 299) + { + sym -= 271; + length = kNormalMatchMinLen + (UInt32)kLenStart[sym] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[sym]); + 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(numBits); + length += ((kDistLimit4 - rep0) >> 31) + ((kDistLimit3 - rep0) >> 31); + } + else + return S_FALSE; + } + if (rep0 >= _lzSize) + return S_FALSE; + CopyBlock(rep0, length); + } + _reps[0] = rep0; + _reps[1] = rep1; + _reps[2] = rep2; + _reps[3] = rep3; + _lastLength = length; + + return S_OK; +} + + +HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress) +{ + _writtenFileSize = 0; + _unsupportedFilter = false; + + if (!_isSolid) + { + _lzSize = 0; + _winPos = 0; + _wrPtr = 0; + for (int i = 0; i < kNumReps; i++) + _reps[i] = 0; + _lastLength = 0; + memset(m_LastLevels, 0, kTablesSizesSum); + TablesRead = false; + PpmEscChar = 2; + PpmError = true; + InitFilters(); + // _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; + + UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize)); + if (!keepDecompressing) + break; + } + + _solidAllowed = true; + + RINOK(WriteBuf()); + 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; +} + +STDMETHODIMP 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. +} + +STDMETHODIMP 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 index 68d79dbda..3d319deda 100644 --- a/CPP/7zip/Compress/Rar3Decoder.h +++ b/CPP/7zip/Compress/Rar3Decoder.h @@ -1,286 +1,286 @@ -// Rar3Decoder.h -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ - -#ifndef __COMPRESS_RAR3_DECODER_H -#define __COMPRESS_RAR3_DECODER_H - -#include "../../../C/Ppmd7.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/InBuffer.h" - -#include "BitmDecoder.h" -#include "HuffmanDecoder.h" -#include "Rar3Vm.h" - -namespace NCompress { -namespace NRar3 { - -const UInt32 kWindowSize = 1 << 22; -const UInt32 kWindowMask = (kWindowSize - 1); - -const UInt32 kNumReps = 4; -const UInt32 kNumLen2Symbols = 8; -const UInt32 kLenTableSize = 28; -const UInt32 kMainTableSize = 256 + 1 + 1 + 1 + kNumReps + kNumLen2Symbols + kLenTableSize; -const UInt32 kDistTableSize = 60; - -const 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; - } -}; - -const UInt32 kTopValue = (1 << 24); -const UInt32 kBot = (1 << 15); - -struct CRangeDecoder -{ - IPpmd7_RangeDec vt; - UInt32 Range; - UInt32 Code; - UInt32 Low; - CBitDecoder BitDecoder; - SRes Res; - -public: - void InitRangeCoder() - { - Code = 0; - Low = 0; - Range = 0xFFFFFFFF; - for (int i = 0; i < 4; i++) - Code = (Code << 8) | BitDecoder.ReadBits(8); - } - - void Normalize() - { - while ((Low ^ (Low + Range)) < kTopValue || - Range < kBot && ((Range = (0 - Low) & (kBot - 1)), 1)) - { - Code = (Code << 8) | BitDecoder.Stream.ReadByte(); - Range <<= 8; - Low <<= 8; - } - } - - CRangeDecoder() throw(); -}; - -struct CFilter: public NVm::CProgram -{ - CRecordVector 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; - -class CDecoder: - public ICompressCoder, - public ICompressSetDecoderProperties2, - public CMyUnknownImp -{ - CRangeDecoder m_InBitStream; - Byte *_window; - UInt32 _winPos; - UInt32 _wrPtr; - UInt64 _lzSize; - UInt64 _unpackSize; - UInt64 _writtenFileSize; // if it's > _unpackSize, then _unpackSize only written - ISequentialOutStream *_outStream; - NHuffman::CDecoder m_MainDecoder; - NHuffman::CDecoder m_DistDecoder; - NHuffman::CDecoder m_AlignDecoder; - NHuffman::CDecoder m_LenDecoder; - NHuffman::CDecoder m_LevelDecoder; - - UInt32 _reps[kNumReps]; - UInt32 _lastLength; - - Byte m_LastLevels[kTablesSizesSum]; - - Byte *_vmData; - Byte *_vmCode; - NVm::CVm _vm; - CRecordVector _filters; - CRecordVector _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); } - -public: - CDecoder(); - ~CDecoder(); - - MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) - - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - - STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); - - void CopyBlock(UInt32 distance, UInt32 len) - { - _lzSize += len; - UInt32 pos = (_winPos - distance - 1) & kWindowMask; - Byte *window = _window; - UInt32 winPos = _winPos; - if (kWindowSize - winPos > len && kWindowSize - pos > len) - { - const Byte *src = window + pos; - Byte *dest = window + winPos; - _winPos += len; - do - *dest++ = *src++; - while (--len != 0); - return; - } - do - { - window[winPos] = window[pos]; - winPos = (winPos + 1) & kWindowMask; - pos = (pos + 1) & kWindowMask; - } - while (--len != 0); - _winPos = winPos; - } - - void PutByte(Byte b) - { - _window[_winPos] = b; - _winPos = (_winPos + 1) & kWindowMask; - _lzSize++; - } - - -}; - -}} - -#endif +// Rar3Decoder.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#ifndef __COMPRESS_RAR3_DECODER_H +#define __COMPRESS_RAR3_DECODER_H + +#include "../../../C/Ppmd7.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "BitmDecoder.h" +#include "HuffmanDecoder.h" +#include "Rar3Vm.h" + +namespace NCompress { +namespace NRar3 { + +const UInt32 kWindowSize = 1 << 22; +const UInt32 kWindowMask = (kWindowSize - 1); + +const UInt32 kNumReps = 4; +const UInt32 kNumLen2Symbols = 8; +const UInt32 kLenTableSize = 28; +const UInt32 kMainTableSize = 256 + 1 + 1 + 1 + kNumReps + kNumLen2Symbols + kLenTableSize; +const UInt32 kDistTableSize = 60; + +const 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; + } +}; + +const UInt32 kTopValue = (1 << 24); +const UInt32 kBot = (1 << 15); + +struct CRangeDecoder +{ + IPpmd7_RangeDec vt; + UInt32 Range; + UInt32 Code; + UInt32 Low; + CBitDecoder BitDecoder; + SRes Res; + +public: + void InitRangeCoder() + { + Code = 0; + Low = 0; + Range = 0xFFFFFFFF; + for (int i = 0; i < 4; i++) + Code = (Code << 8) | BitDecoder.ReadBits(8); + } + + void Normalize() + { + while ((Low ^ (Low + Range)) < kTopValue || + Range < kBot && ((Range = (0 - Low) & (kBot - 1)), 1)) + { + Code = (Code << 8) | BitDecoder.Stream.ReadByte(); + Range <<= 8; + Low <<= 8; + } + } + + CRangeDecoder() throw(); +}; + +struct CFilter: public NVm::CProgram +{ + CRecordVector 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; + +class CDecoder: + public ICompressCoder, + public ICompressSetDecoderProperties2, + public CMyUnknownImp +{ + CRangeDecoder m_InBitStream; + Byte *_window; + UInt32 _winPos; + UInt32 _wrPtr; + UInt64 _lzSize; + UInt64 _unpackSize; + UInt64 _writtenFileSize; // if it's > _unpackSize, then _unpackSize only written + ISequentialOutStream *_outStream; + NHuffman::CDecoder m_MainDecoder; + NHuffman::CDecoder m_DistDecoder; + NHuffman::CDecoder m_AlignDecoder; + NHuffman::CDecoder m_LenDecoder; + NHuffman::CDecoder m_LevelDecoder; + + UInt32 _reps[kNumReps]; + UInt32 _lastLength; + + Byte m_LastLevels[kTablesSizesSum]; + + Byte *_vmData; + Byte *_vmCode; + NVm::CVm _vm; + CRecordVector _filters; + CRecordVector _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); } + +public: + CDecoder(); + ~CDecoder(); + + MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); + + void CopyBlock(UInt32 distance, UInt32 len) + { + _lzSize += len; + UInt32 pos = (_winPos - distance - 1) & kWindowMask; + Byte *window = _window; + UInt32 winPos = _winPos; + if (kWindowSize - winPos > len && kWindowSize - pos > len) + { + const Byte *src = window + pos; + Byte *dest = window + winPos; + _winPos += len; + do + *dest++ = *src++; + while (--len != 0); + return; + } + do + { + window[winPos] = window[pos]; + winPos = (winPos + 1) & kWindowMask; + pos = (pos + 1) & kWindowMask; + } + while (--len != 0); + _winPos = winPos; + } + + void PutByte(Byte b) + { + _window[_winPos] = b; + _winPos = (_winPos + 1) & kWindowMask; + _lzSize++; + } + + +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Rar3Vm.cpp b/CPP/7zip/Compress/Rar3Vm.cpp index 0695a7891..61cf657c2 100644 --- a/CPP/7zip/Compress/Rar3Vm.cpp +++ b/CPP/7zip/Compress/Rar3Vm.cpp @@ -1,1139 +1,1139 @@ -// 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 - -#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 (;;) - { - unsigned b = _bitPos < _bitSize ? (unsigned)_data[_bitPos >> 3] : 0; - 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() -{ - unsigned v = (unsigned)ReadBits(2); - UInt32 res = ReadBits(4 << v); - if (v == 1 && res < 16) - res = 0xFFFFFF00 | (res << 4) | ReadBits(4); - return res; -} - -namespace NVm { - -static const UInt32 kStackRegIndex = kNumRegs - 1; - -#ifdef RARVM_VM_ENABLE - -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 &outGlobalData) -{ - memcpy(R, initState->InitR, sizeof(initState->InitR)); - R[kStackRegIndex] = kSpaceSize; - R[kNumRegs] = 0; - Flags = 0; - - UInt32 globalSize = MyMin((UInt32)initState->GlobalData.Size(), kGlobalSize); - if (globalSize != 0) - memcpy(Mem + kGlobalOffset, &initState->GlobalData[0], globalSize); - UInt32 staticSize = MyMin((UInt32)prg->StaticData.Size(), kGlobalSize - globalSize); - if (staticSize != 0) - memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize); - - bool res = true; - - #ifdef RARVM_STANDARD_FILTERS - if (prg->StandardFilterIndex >= 0) - res = ExecuteStandardFilter(prg->StandardFilterIndex); - else - #endif - { - #ifdef 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 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 { UInt32 val = GetOperand32(&cmd->Op1); SET_IP(val); } -#define FLAGS_UPDATE_SZ Flags = res == 0 ? FLAG_Z : res & FLAG_S -#define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res) - -UInt32 CVm::GetOperand32(const COperand *op) const -{ - switch (op->Type) - { - case OP_TYPE_REG: return R[op->Data]; - case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]); - default: return op->Data; - } -} - -void CVm::SetOperand32(const COperand *op, UInt32 val) -{ - switch (op->Type) - { - case OP_TYPE_REG: R[op->Data] = val; return; - case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return; - } -} - -Byte CVm::GetOperand8(const COperand *op) const -{ - switch (op->Type) - { - case OP_TYPE_REG: return (Byte)R[op->Data]; - case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask];; - default: return (Byte)op->Data; - } -} - -void CVm::SetOperand8(const COperand *op, Byte val) -{ - switch (op->Type) - { - case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return; - case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return; - } -} - -UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const -{ - if (byteMode) - return GetOperand8(op); - return GetOperand32(op); -} - -void CVm::SetOperand(bool byteMode, const COperand *op, UInt32 val) -{ - if (byteMode) - SetOperand8(op, (Byte)(val & 0xFF)); - else - SetOperand32(op, val); -} - -bool CVm::ExecuteCode(const CProgram *prg) -{ - Int32 maxOpCount = 25000000; - const CCommand *commands = &prg->Commands[0]; - const CCommand *cmd = commands; - UInt32 numCommands = prg->Commands.Size(); - 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: - { - UInt32 v1 = GetOperand32(&cmd->Op1); - UInt32 res = v1 - GetOperand32(&cmd->Op2); - Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); - } - break; - case CMD_CMPB: - { - Byte v1 = GetOperand8(&cmd->Op1); - Byte res = (Byte)((v1 - GetOperand8(&cmd->Op2)) & 0xFF); - Flags = res == 0 ? FLAG_Z : (res > v1) | GET_FLAG_S_B(res); - } - break; - case CMD_ADD: - { - UInt32 v1 = GetOperand32(&cmd->Op1); - UInt32 res = v1 + GetOperand32(&cmd->Op2); - SetOperand32(&cmd->Op1, res); - Flags = (res < v1) | (res == 0 ? FLAG_Z : (res & FLAG_S)); - } - break; - case CMD_ADDB: - { - Byte v1 = GetOperand8(&cmd->Op1); - Byte res = (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: - { - UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); - UInt32 FC = (Flags & FLAG_C); - UInt32 res = v1 + GetOperand(cmd->ByteMode, &cmd->Op2) + FC; - if (cmd->ByteMode) - res &= 0xFF; - SetOperand(cmd->ByteMode, &cmd->Op1, res); - Flags = (res < v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S)); - } - break; - case CMD_SUB: - { - UInt32 v1 = GetOperand32(&cmd->Op1); - UInt32 res = v1 - GetOperand32(&cmd->Op2); - SetOperand32(&cmd->Op1, res); - Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); - } - break; - case CMD_SUBB: - { - UInt32 v1 = GetOperand8(&cmd->Op1); - UInt32 res = v1 - GetOperand8(&cmd->Op2); - SetOperand8(&cmd->Op1, (Byte)res); - Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); - } - break; - case CMD_SBB: - { - UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); - UInt32 FC = (Flags & FLAG_C); - UInt32 res = v1 - GetOperand(cmd->ByteMode, &cmd->Op2) - FC; - // Flags = res == 0 ? FLAG_Z : (res > v1 || res == v1 && FC) | (res & FLAG_S); - if (cmd->ByteMode) - res &= 0xFF; - SetOperand(cmd->ByteMode, &cmd->Op1, res); - Flags = (res > v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S)); - } - break; - case CMD_INC: - { - UInt32 res = GetOperand32(&cmd->Op1) + 1; - SetOperand32(&cmd->Op1, res); - FLAGS_UPDATE_SZ; - } - break; - case CMD_INCB: - { - Byte res = (Byte)(GetOperand8(&cmd->Op1) + 1); - SetOperand8(&cmd->Op1, res);; - FLAGS_UPDATE_SZ_B; - } - break; - case CMD_DEC: - { - UInt32 res = GetOperand32(&cmd->Op1) - 1; - SetOperand32(&cmd->Op1, res); - FLAGS_UPDATE_SZ; - } - break; - case CMD_DECB: - { - Byte res = (Byte)(GetOperand8(&cmd->Op1) - 1); - SetOperand8(&cmd->Op1, res);; - FLAGS_UPDATE_SZ_B; - } - break; - case CMD_XOR: - { - UInt32 res = GetOperand32(&cmd->Op1) ^ GetOperand32(&cmd->Op2); - SetOperand32(&cmd->Op1, res); - FLAGS_UPDATE_SZ; - } - break; - case CMD_XORB: - { - Byte res = (Byte)(GetOperand8(&cmd->Op1) ^ GetOperand8(&cmd->Op2)); - SetOperand8(&cmd->Op1, res); - FLAGS_UPDATE_SZ_B; - } - break; - case CMD_AND: - { - UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2); - SetOperand32(&cmd->Op1, res); - FLAGS_UPDATE_SZ; - } - break; - case CMD_ANDB: - { - Byte res = (Byte)(GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2)); - SetOperand8(&cmd->Op1, res); - FLAGS_UPDATE_SZ_B; - } - break; - case CMD_OR: - { - UInt32 res = GetOperand32(&cmd->Op1) | GetOperand32(&cmd->Op2); - SetOperand32(&cmd->Op1, res); - FLAGS_UPDATE_SZ; - } - break; - case CMD_ORB: - { - Byte res = (Byte)(GetOperand8(&cmd->Op1) | GetOperand8(&cmd->Op2)); - SetOperand8(&cmd->Op1, res); - FLAGS_UPDATE_SZ_B; - } - break; - case CMD_TEST: - { - UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2); - FLAGS_UPDATE_SZ; - } - break; - case CMD_TESTB: - { - Byte res = (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: - { - UInt32 res = 0 - GetOperand32(&cmd->Op1); - SetOperand32(&cmd->Op1, res); - Flags = res == 0 ? FLAG_Z : FLAG_C | (res & FLAG_S); - } - break; - case CMD_NEGB: - { - Byte res = (Byte)(0 - GetOperand8(&cmd->Op1)); - SetOperand8(&cmd->Op1, res); - Flags = res == 0 ? FLAG_Z : FLAG_C | GET_FLAG_S_B(res); - } - break; - - case CMD_SHL: - { - UInt32 v1 = GetOperand32(&cmd->Op1); - int v2 = (int)GetOperand32(&cmd->Op2); - UInt32 res = v1 << v2; - SetOperand32(&cmd->Op1, res); - Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 << (v2 - 1)) & 0x80000000 ? FLAG_C : 0); - } - break; - case CMD_SHLB: - { - Byte v1 = GetOperand8(&cmd->Op1); - int v2 = (int)GetOperand8(&cmd->Op2); - Byte res = (Byte)(v1 << v2); - SetOperand8(&cmd->Op1, res); - Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 << (v2 - 1)) & 0x80 ? FLAG_C : 0); - } - break; - case CMD_SHR: - { - UInt32 v1 = GetOperand32(&cmd->Op1); - int v2 = (int)GetOperand32(&cmd->Op2); - UInt32 res = v1 >> v2; - SetOperand32(&cmd->Op1, res); - Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C); - } - break; - case CMD_SHRB: - { - Byte v1 = GetOperand8(&cmd->Op1); - int v2 = (int)GetOperand8(&cmd->Op2); - Byte res = (Byte)(v1 >> v2); - SetOperand8(&cmd->Op1, res); - Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C); - } - break; - case CMD_SAR: - { - UInt32 v1 = GetOperand32(&cmd->Op1); - int v2 = (int)GetOperand32(&cmd->Op2); - UInt32 res = UInt32(((Int32)v1) >> v2); - SetOperand32(&cmd->Op1, res); - Flags= (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C); - } - break; - case CMD_SARB: - { - Byte v1 = GetOperand8(&cmd->Op1); - int v2 = (int)GetOperand8(&cmd->Op2); - Byte res = (Byte)(((signed char)v1) >> v2); - SetOperand8(&cmd->Op1, res); - Flags= (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C); - } - break; - - case CMD_JMP: - SET_IP_OP1; - continue; - case CMD_JZ: - if ((Flags & FLAG_Z) != 0) - { - SET_IP_OP1; - continue; - } - break; - case CMD_JNZ: - if ((Flags & FLAG_Z) == 0) - { - SET_IP_OP1; - continue; - } - break; - case CMD_JS: - if ((Flags & FLAG_S) != 0) - { - SET_IP_OP1; - continue; - } - break; - case CMD_JNS: - if ((Flags & FLAG_S) == 0) - { - SET_IP_OP1; - continue; - } - break; - case CMD_JB: - if ((Flags & FLAG_C) != 0) - { - SET_IP_OP1; - continue; - } - break; - case CMD_JBE: - if ((Flags & (FLAG_C | FLAG_Z)) != 0) - { - SET_IP_OP1; - continue; - } - break; - case CMD_JA: - if ((Flags & (FLAG_C | FLAG_Z)) == 0) - { - SET_IP_OP1; - continue; - } - break; - case CMD_JAE: - if ((Flags & FLAG_C) == 0) - { - SET_IP_OP1; - continue; - } - break; - - case CMD_PUSH: - R[kStackRegIndex] -= 4; - SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], GetOperand32(&cmd->Op1)); - break; - case CMD_POP: - SetOperand32(&cmd->Op1, GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask])); - R[kStackRegIndex] += 4; - break; - case CMD_CALL: - R[kStackRegIndex] -= 4; - SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], (UInt32)(cmd - commands + 1)); - SET_IP_OP1; - continue; - - case CMD_PUSHA: - { - for (UInt32 i = 0, SP = R[kStackRegIndex] - 4; i < kNumRegs; i++, SP -= 4) - SetValue32(&Mem[SP & kSpaceMask], R[i]); - R[kStackRegIndex] -= kNumRegs * 4; - } - break; - case CMD_POPA: - { - for (UInt32 i = 0, SP = R[kStackRegIndex]; i < kNumRegs; i++, SP += 4) - R[kStackRegIndex - i] = GetValue32(&Mem[SP & kSpaceMask]); - } - break; - case CMD_PUSHF: - R[kStackRegIndex] -= 4; - SetValue32(&Mem[R[kStackRegIndex]&kSpaceMask], Flags); - break; - case CMD_POPF: - Flags = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]); - R[kStackRegIndex] += 4; - break; - - case CMD_MOVZX: - SetOperand32(&cmd->Op1, GetOperand8(&cmd->Op2)); - break; - case CMD_MOVSX: - SetOperand32(&cmd->Op1, (UInt32)(Int32)(signed char)GetOperand8(&cmd->Op2)); - break; - case CMD_XCHG: - { - UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); - SetOperand(cmd->ByteMode, &cmd->Op1, GetOperand(cmd->ByteMode, &cmd->Op2)); - SetOperand(cmd->ByteMode, &cmd->Op2, v1); - } - break; - case CMD_MUL: - { - UInt32 res = GetOperand32(&cmd->Op1) * GetOperand32(&cmd->Op2); - SetOperand32(&cmd->Op1, res); - } - break; - case CMD_MULB: - { - Byte res = (Byte)(GetOperand8(&cmd->Op1) * GetOperand8(&cmd->Op2)); - SetOperand8(&cmd->Op1, res); - } - break; - case CMD_DIV: - { - UInt32 divider = GetOperand(cmd->ByteMode, &cmd->Op2); - if (divider != 0) - { - UInt32 res = GetOperand(cmd->ByteMode, &cmd->Op1) / divider; - SetOperand(cmd->ByteMode, &cmd->Op1, res); - } - } - break; - - case CMD_RET: - { - if (R[kStackRegIndex] >= kSpaceSize) - return true; - UInt32 ip = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]); - SET_IP(ip); - R[kStackRegIndex] += 4; - continue; - } - case CMD_PRINT: - break; - } - cmd++; - --maxOpCount; - } -} - -////////////////////////////////////////////////////// -// Read program - -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()) - { - 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(); - - if (inp.ReadBit() == 0) - cmd->OpCode = (ECommand)inp.ReadBits(3); - else - cmd->OpCode = (ECommand)(8 + inp.ReadBits(5)); - - if (kCmdFlags[(unsigned)cmd->OpCode] & CF_BYTEMODE) - cmd->ByteMode = (inp.ReadBit()) ? true : false; - else - cmd->ByteMode = 0; - - int opNum = (kCmdFlags[(unsigned)cmd->OpCode] & CF_OPMASK); - - if (opNum > 0) - { - DecodeArg(inp, cmd->Op1, cmd->ByteMode); - if (opNum == 2) - DecodeArg(inp, cmd->Op2, cmd->ByteMode); - else - { - if (cmd->Op1.Type == OP_TYPE_INT && (kCmdFlags[(unsigned)cmd->OpCode] & (CF_JUMP | CF_PROC))) - { - int dist = 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 = 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; - } - } - } -} - -#endif - - -#ifdef 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) -{ - UInt32 crc = CrcCalc(code, codeSize); - for (unsigned i = 0; i < ARRAY_SIZE(kStdFilters); i++) - { - const CStandardFilterSignature &sfs = kStdFilters[i]; - if (sfs.CRC == crc && sfs.Length == codeSize) - return i; - } - return -1; -} - -#endif - - -bool CProgram::PrepareProgram(const Byte *code, UInt32 codeSize) -{ - IsSupported = false; - - #ifdef RARVM_VM_ENABLE - Commands.Clear(); - #endif - - #ifdef 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 RARVM_STANDARD_FILTERS - StandardFilterIndex = FindStandardFilter(code, codeSize); - if (StandardFilterIndex >= 0) - return true; - #endif - - #ifdef RARVM_VM_ENABLE - ReadProgram(code + 1, codeSize - 1); - #else - IsSupported = false; - #endif - } - - #ifdef 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 RARVM_STANDARD_FILTERS - -static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9) -{ - if (dataSize <= 4) - return; - dataSize -= 4; - const UInt32 kFileSize = 0x1000000; - Byte 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 - { - unsigned int upperLeftByte = destData[i - width]; - unsigned int upperByte = destData[i - width + 3]; - predicted = prevByte + upperByte - upperLeftByte; - int pa = abs((int)(predicted - prevByte)); - int pb = abs((int)(predicted - upperByte)); - int pc = abs((int)(predicted - upperLeftByte)); - if (pa <= pb && pa <= pc) - predicted = prevByte; - else - if (pb <= pc) - predicted = upperByte; - else - predicted = upperLeftByte; - } - destData[i] = prevByte = (Byte)(predicted - *(srcData++)); - } - } - if (dataSize < 3) - return; - const UInt32 border = dataSize - 2; - for (UInt32 i = posR; i < border; i += 3) - { - Byte g = destData[i + 1]; - destData[i ] = (Byte)(destData[i ] + g); - destData[i + 2] = (Byte)(destData[i + 2] + g); - } -} - -static void AudioDecode(Byte *srcData, UInt32 dataSize, UInt32 numChannels) -{ - Byte *destData = srcData + dataSize; - for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++) - { - UInt32 prevByte = 0, prevDelta = 0, dif[7]; - Int32 D1 = 0, D2 = 0, D3; - Int32 K1 = 0, K2 = 0, K3 = 0; - memset(dif, 0, sizeof(dif)); - - for (UInt32 i = curChannel, byteCount = 0; i < dataSize; i += numChannels, byteCount++) - { - D3 = D2; - D2 = prevDelta - D1; - D1 = prevDelta; - - UInt32 predicted = 8 * prevByte + K1 * D1 + K2 * D2 + K3 * D3; - predicted = (predicted >> 3) & 0xFF; - - UInt32 curByte = *(srcData++); - - predicted -= curByte; - destData[i] = (Byte)predicted; - prevDelta = (UInt32)(Int32)(signed char)(predicted - prevByte); - prevByte = predicted; - - Int32 D = ((Int32)(signed char)curByte) << 3; - - dif[0] += abs(D); - dif[1] += abs(D - D1); - dif[2] += abs(D + D1); - dif[3] += abs(D - D2); - dif[4] += abs(D + D2); - dif[5] += abs(D - D3); - dif[6] += abs(D + D3); - - if ((byteCount & 0x1F) == 0) - { - UInt32 minDif = dif[0], numMinDif = 0; - dif[0] = 0; - for (unsigned j = 1; j < 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) -{ - 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; - 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; - UInt32 width = R[0]; - 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; - 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 - -}}} +// 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 + +#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 (;;) + { + unsigned b = _bitPos < _bitSize ? (unsigned)_data[_bitPos >> 3] : 0; + 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() +{ + unsigned v = (unsigned)ReadBits(2); + UInt32 res = ReadBits(4 << v); + if (v == 1 && res < 16) + res = 0xFFFFFF00 | (res << 4) | ReadBits(4); + return res; +} + +namespace NVm { + +static const UInt32 kStackRegIndex = kNumRegs - 1; + +#ifdef RARVM_VM_ENABLE + +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 &outGlobalData) +{ + memcpy(R, initState->InitR, sizeof(initState->InitR)); + R[kStackRegIndex] = kSpaceSize; + R[kNumRegs] = 0; + Flags = 0; + + UInt32 globalSize = MyMin((UInt32)initState->GlobalData.Size(), kGlobalSize); + if (globalSize != 0) + memcpy(Mem + kGlobalOffset, &initState->GlobalData[0], globalSize); + UInt32 staticSize = MyMin((UInt32)prg->StaticData.Size(), kGlobalSize - globalSize); + if (staticSize != 0) + memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize); + + bool res = true; + + #ifdef RARVM_STANDARD_FILTERS + if (prg->StandardFilterIndex >= 0) + res = ExecuteStandardFilter(prg->StandardFilterIndex); + else + #endif + { + #ifdef 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 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 { UInt32 val = GetOperand32(&cmd->Op1); SET_IP(val); } +#define FLAGS_UPDATE_SZ Flags = res == 0 ? FLAG_Z : res & FLAG_S +#define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res) + +UInt32 CVm::GetOperand32(const COperand *op) const +{ + switch (op->Type) + { + case OP_TYPE_REG: return R[op->Data]; + case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]); + default: return op->Data; + } +} + +void CVm::SetOperand32(const COperand *op, UInt32 val) +{ + switch (op->Type) + { + case OP_TYPE_REG: R[op->Data] = val; return; + case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return; + } +} + +Byte CVm::GetOperand8(const COperand *op) const +{ + switch (op->Type) + { + case OP_TYPE_REG: return (Byte)R[op->Data]; + case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask];; + default: return (Byte)op->Data; + } +} + +void CVm::SetOperand8(const COperand *op, Byte val) +{ + switch (op->Type) + { + case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return; + case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return; + } +} + +UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const +{ + if (byteMode) + return GetOperand8(op); + return GetOperand32(op); +} + +void CVm::SetOperand(bool byteMode, const COperand *op, UInt32 val) +{ + if (byteMode) + SetOperand8(op, (Byte)(val & 0xFF)); + else + SetOperand32(op, val); +} + +bool CVm::ExecuteCode(const CProgram *prg) +{ + Int32 maxOpCount = 25000000; + const CCommand *commands = &prg->Commands[0]; + const CCommand *cmd = commands; + UInt32 numCommands = prg->Commands.Size(); + 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: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + UInt32 res = v1 - GetOperand32(&cmd->Op2); + Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); + } + break; + case CMD_CMPB: + { + Byte v1 = GetOperand8(&cmd->Op1); + Byte res = (Byte)((v1 - GetOperand8(&cmd->Op2)) & 0xFF); + Flags = res == 0 ? FLAG_Z : (res > v1) | GET_FLAG_S_B(res); + } + break; + case CMD_ADD: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + UInt32 res = v1 + GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + Flags = (res < v1) | (res == 0 ? FLAG_Z : (res & FLAG_S)); + } + break; + case CMD_ADDB: + { + Byte v1 = GetOperand8(&cmd->Op1); + Byte res = (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: + { + UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); + UInt32 FC = (Flags & FLAG_C); + UInt32 res = v1 + GetOperand(cmd->ByteMode, &cmd->Op2) + FC; + if (cmd->ByteMode) + res &= 0xFF; + SetOperand(cmd->ByteMode, &cmd->Op1, res); + Flags = (res < v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S)); + } + break; + case CMD_SUB: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + UInt32 res = v1 - GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); + } + break; + case CMD_SUBB: + { + UInt32 v1 = GetOperand8(&cmd->Op1); + UInt32 res = v1 - GetOperand8(&cmd->Op2); + SetOperand8(&cmd->Op1, (Byte)res); + Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); + } + break; + case CMD_SBB: + { + UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); + UInt32 FC = (Flags & FLAG_C); + UInt32 res = v1 - GetOperand(cmd->ByteMode, &cmd->Op2) - FC; + // Flags = res == 0 ? FLAG_Z : (res > v1 || res == v1 && FC) | (res & FLAG_S); + if (cmd->ByteMode) + res &= 0xFF; + SetOperand(cmd->ByteMode, &cmd->Op1, res); + Flags = (res > v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S)); + } + break; + case CMD_INC: + { + UInt32 res = GetOperand32(&cmd->Op1) + 1; + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_INCB: + { + Byte res = (Byte)(GetOperand8(&cmd->Op1) + 1); + SetOperand8(&cmd->Op1, res);; + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_DEC: + { + UInt32 res = GetOperand32(&cmd->Op1) - 1; + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_DECB: + { + Byte res = (Byte)(GetOperand8(&cmd->Op1) - 1); + SetOperand8(&cmd->Op1, res);; + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_XOR: + { + UInt32 res = GetOperand32(&cmd->Op1) ^ GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_XORB: + { + Byte res = (Byte)(GetOperand8(&cmd->Op1) ^ GetOperand8(&cmd->Op2)); + SetOperand8(&cmd->Op1, res); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_AND: + { + UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_ANDB: + { + Byte res = (Byte)(GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2)); + SetOperand8(&cmd->Op1, res); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_OR: + { + UInt32 res = GetOperand32(&cmd->Op1) | GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_ORB: + { + Byte res = (Byte)(GetOperand8(&cmd->Op1) | GetOperand8(&cmd->Op2)); + SetOperand8(&cmd->Op1, res); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_TEST: + { + UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2); + FLAGS_UPDATE_SZ; + } + break; + case CMD_TESTB: + { + Byte res = (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: + { + UInt32 res = 0 - GetOperand32(&cmd->Op1); + SetOperand32(&cmd->Op1, res); + Flags = res == 0 ? FLAG_Z : FLAG_C | (res & FLAG_S); + } + break; + case CMD_NEGB: + { + Byte res = (Byte)(0 - GetOperand8(&cmd->Op1)); + SetOperand8(&cmd->Op1, res); + Flags = res == 0 ? FLAG_Z : FLAG_C | GET_FLAG_S_B(res); + } + break; + + case CMD_SHL: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + int v2 = (int)GetOperand32(&cmd->Op2); + UInt32 res = v1 << v2; + SetOperand32(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 << (v2 - 1)) & 0x80000000 ? FLAG_C : 0); + } + break; + case CMD_SHLB: + { + Byte v1 = GetOperand8(&cmd->Op1); + int v2 = (int)GetOperand8(&cmd->Op2); + Byte res = (Byte)(v1 << v2); + SetOperand8(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 << (v2 - 1)) & 0x80 ? FLAG_C : 0); + } + break; + case CMD_SHR: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + int v2 = (int)GetOperand32(&cmd->Op2); + UInt32 res = v1 >> v2; + SetOperand32(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + case CMD_SHRB: + { + Byte v1 = GetOperand8(&cmd->Op1); + int v2 = (int)GetOperand8(&cmd->Op2); + Byte res = (Byte)(v1 >> v2); + SetOperand8(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + case CMD_SAR: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + int v2 = (int)GetOperand32(&cmd->Op2); + UInt32 res = UInt32(((Int32)v1) >> v2); + SetOperand32(&cmd->Op1, res); + Flags= (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + case CMD_SARB: + { + Byte v1 = GetOperand8(&cmd->Op1); + int v2 = (int)GetOperand8(&cmd->Op2); + Byte res = (Byte)(((signed char)v1) >> v2); + SetOperand8(&cmd->Op1, res); + Flags= (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + + case CMD_JMP: + SET_IP_OP1; + continue; + case CMD_JZ: + if ((Flags & FLAG_Z) != 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JNZ: + if ((Flags & FLAG_Z) == 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JS: + if ((Flags & FLAG_S) != 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JNS: + if ((Flags & FLAG_S) == 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JB: + if ((Flags & FLAG_C) != 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JBE: + if ((Flags & (FLAG_C | FLAG_Z)) != 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JA: + if ((Flags & (FLAG_C | FLAG_Z)) == 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JAE: + if ((Flags & FLAG_C) == 0) + { + SET_IP_OP1; + continue; + } + break; + + case CMD_PUSH: + R[kStackRegIndex] -= 4; + SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], GetOperand32(&cmd->Op1)); + break; + case CMD_POP: + SetOperand32(&cmd->Op1, GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask])); + R[kStackRegIndex] += 4; + break; + case CMD_CALL: + R[kStackRegIndex] -= 4; + SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], (UInt32)(cmd - commands + 1)); + SET_IP_OP1; + continue; + + case CMD_PUSHA: + { + for (UInt32 i = 0, SP = R[kStackRegIndex] - 4; i < kNumRegs; i++, SP -= 4) + SetValue32(&Mem[SP & kSpaceMask], R[i]); + R[kStackRegIndex] -= kNumRegs * 4; + } + break; + case CMD_POPA: + { + for (UInt32 i = 0, SP = R[kStackRegIndex]; i < kNumRegs; i++, SP += 4) + R[kStackRegIndex - i] = GetValue32(&Mem[SP & kSpaceMask]); + } + break; + case CMD_PUSHF: + R[kStackRegIndex] -= 4; + SetValue32(&Mem[R[kStackRegIndex]&kSpaceMask], Flags); + break; + case CMD_POPF: + Flags = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]); + R[kStackRegIndex] += 4; + break; + + case CMD_MOVZX: + SetOperand32(&cmd->Op1, GetOperand8(&cmd->Op2)); + break; + case CMD_MOVSX: + SetOperand32(&cmd->Op1, (UInt32)(Int32)(signed char)GetOperand8(&cmd->Op2)); + break; + case CMD_XCHG: + { + UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); + SetOperand(cmd->ByteMode, &cmd->Op1, GetOperand(cmd->ByteMode, &cmd->Op2)); + SetOperand(cmd->ByteMode, &cmd->Op2, v1); + } + break; + case CMD_MUL: + { + UInt32 res = GetOperand32(&cmd->Op1) * GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + } + break; + case CMD_MULB: + { + Byte res = (Byte)(GetOperand8(&cmd->Op1) * GetOperand8(&cmd->Op2)); + SetOperand8(&cmd->Op1, res); + } + break; + case CMD_DIV: + { + UInt32 divider = GetOperand(cmd->ByteMode, &cmd->Op2); + if (divider != 0) + { + UInt32 res = GetOperand(cmd->ByteMode, &cmd->Op1) / divider; + SetOperand(cmd->ByteMode, &cmd->Op1, res); + } + } + break; + + case CMD_RET: + { + if (R[kStackRegIndex] >= kSpaceSize) + return true; + UInt32 ip = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]); + SET_IP(ip); + R[kStackRegIndex] += 4; + continue; + } + case CMD_PRINT: + break; + } + cmd++; + --maxOpCount; + } +} + +////////////////////////////////////////////////////// +// Read program + +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()) + { + 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(); + + if (inp.ReadBit() == 0) + cmd->OpCode = (ECommand)inp.ReadBits(3); + else + cmd->OpCode = (ECommand)(8 + inp.ReadBits(5)); + + if (kCmdFlags[(unsigned)cmd->OpCode] & CF_BYTEMODE) + cmd->ByteMode = (inp.ReadBit()) ? true : false; + else + cmd->ByteMode = 0; + + int opNum = (kCmdFlags[(unsigned)cmd->OpCode] & CF_OPMASK); + + if (opNum > 0) + { + DecodeArg(inp, cmd->Op1, cmd->ByteMode); + if (opNum == 2) + DecodeArg(inp, cmd->Op2, cmd->ByteMode); + else + { + if (cmd->Op1.Type == OP_TYPE_INT && (kCmdFlags[(unsigned)cmd->OpCode] & (CF_JUMP | CF_PROC))) + { + int dist = 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 = 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; + } + } + } +} + +#endif + + +#ifdef 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) +{ + UInt32 crc = CrcCalc(code, codeSize); + for (unsigned i = 0; i < ARRAY_SIZE(kStdFilters); i++) + { + const CStandardFilterSignature &sfs = kStdFilters[i]; + if (sfs.CRC == crc && sfs.Length == codeSize) + return i; + } + return -1; +} + +#endif + + +bool CProgram::PrepareProgram(const Byte *code, UInt32 codeSize) +{ + IsSupported = false; + + #ifdef RARVM_VM_ENABLE + Commands.Clear(); + #endif + + #ifdef 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 RARVM_STANDARD_FILTERS + StandardFilterIndex = FindStandardFilter(code, codeSize); + if (StandardFilterIndex >= 0) + return true; + #endif + + #ifdef RARVM_VM_ENABLE + ReadProgram(code + 1, codeSize - 1); + #else + IsSupported = false; + #endif + } + + #ifdef 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 RARVM_STANDARD_FILTERS + +static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9) +{ + if (dataSize <= 4) + return; + dataSize -= 4; + const UInt32 kFileSize = 0x1000000; + Byte 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 + { + unsigned int upperLeftByte = destData[i - width]; + unsigned int upperByte = destData[i - width + 3]; + predicted = prevByte + upperByte - upperLeftByte; + int pa = abs((int)(predicted - prevByte)); + int pb = abs((int)(predicted - upperByte)); + int pc = abs((int)(predicted - upperLeftByte)); + if (pa <= pb && pa <= pc) + predicted = prevByte; + else + if (pb <= pc) + predicted = upperByte; + else + predicted = upperLeftByte; + } + destData[i] = prevByte = (Byte)(predicted - *(srcData++)); + } + } + if (dataSize < 3) + return; + const UInt32 border = dataSize - 2; + for (UInt32 i = posR; i < border; i += 3) + { + Byte g = destData[i + 1]; + destData[i ] = (Byte)(destData[i ] + g); + destData[i + 2] = (Byte)(destData[i + 2] + g); + } +} + +static void AudioDecode(Byte *srcData, UInt32 dataSize, UInt32 numChannels) +{ + Byte *destData = srcData + dataSize; + for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++) + { + UInt32 prevByte = 0, prevDelta = 0, dif[7]; + Int32 D1 = 0, D2 = 0, D3; + Int32 K1 = 0, K2 = 0, K3 = 0; + memset(dif, 0, sizeof(dif)); + + for (UInt32 i = curChannel, byteCount = 0; i < dataSize; i += numChannels, byteCount++) + { + D3 = D2; + D2 = prevDelta - D1; + D1 = prevDelta; + + UInt32 predicted = 8 * prevByte + K1 * D1 + K2 * D2 + K3 * D3; + predicted = (predicted >> 3) & 0xFF; + + UInt32 curByte = *(srcData++); + + predicted -= curByte; + destData[i] = (Byte)predicted; + prevDelta = (UInt32)(Int32)(signed char)(predicted - prevByte); + prevByte = predicted; + + Int32 D = ((Int32)(signed char)curByte) << 3; + + dif[0] += abs(D); + dif[1] += abs(D - D1); + dif[2] += abs(D + D1); + dif[3] += abs(D - D2); + dif[4] += abs(D + D2); + dif[5] += abs(D - D3); + dif[6] += abs(D + D3); + + if ((byteCount & 0x1F) == 0) + { + UInt32 minDif = dif[0], numMinDif = 0; + dif[0] = 0; + for (unsigned j = 1; j < 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) +{ + 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; + 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; + UInt32 width = R[0]; + 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; + 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 index ec115c5fa..3fc515102 100644 --- a/CPP/7zip/Compress/Rar3Vm.h +++ b/CPP/7zip/Compress/Rar3Vm.h @@ -1,195 +1,195 @@ -// Rar3Vm.h -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -#ifndef __COMPRESS_RAR3_VM_H -#define __COMPRESS_RAR3_VM_H - -#include "../../../C/CpuArch.h" - -#include "../../Common/MyVector.h" - -#define RARVM_STANDARD_FILTERS -// #define 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 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 RARVM_VM_ENABLE - void ReadProgram(const Byte *code, UInt32 codeSize); -public: - CRecordVector Commands; - #endif - -public: - #ifdef RARVM_STANDARD_FILTERS - int StandardFilterIndex; - #endif - - bool IsSupported; - CRecordVector StaticData; - - bool PrepareProgram(const Byte *code, UInt32 codeSize); -}; - - -struct CProgramInitState -{ - UInt32 InitR[kNumGpRegs]; - CRecordVector 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 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 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 &outGlobalData); - const Byte *GetDataPointer(UInt32 offset) const { return Mem + offset; } -}; - -#endif - -}}} +// Rar3Vm.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#ifndef __COMPRESS_RAR3_VM_H +#define __COMPRESS_RAR3_VM_H + +#include "../../../C/CpuArch.h" + +#include "../../Common/MyVector.h" + +#define RARVM_STANDARD_FILTERS +// #define 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 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 RARVM_VM_ENABLE + void ReadProgram(const Byte *code, UInt32 codeSize); +public: + CRecordVector Commands; + #endif + +public: + #ifdef RARVM_STANDARD_FILTERS + int StandardFilterIndex; + #endif + + bool IsSupported; + CRecordVector StaticData; + + bool PrepareProgram(const Byte *code, UInt32 codeSize); +}; + + +struct CProgramInitState +{ + UInt32 InitR[kNumGpRegs]; + CRecordVector 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 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 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 &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 index 7c963b109..d7c68e218 100644 --- a/CPP/7zip/Compress/Rar5Decoder.cpp +++ b/CPP/7zip/Compress/Rar5Decoder.cpp @@ -1,980 +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 - -#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 = _bufLim - _buf; - if (rem != 0) - memmove(_bufBase, _buf, rem); - - _bufLim = _bufBase + rem; - _processedSize += (_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 = _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(): - _window(NULL), - _winPos(0), - _winSizeAllocated(0), - _lzSize(0), - _lzEnd(0), - _writtenFileSize(0), - _dictSizeLog(0), - _isSolid(false), - _solidAllowed(false), - _wasInit(false), - _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) - { - 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; - UInt32 fileOffset = (UInt32)(f.Start - _lzFileStart); - - const UInt32 kFileSize = (UInt32)1 << 24; - Byte cmpMask = (Byte)(f.Type == FILTER_E8 ? 0xFF : 0xFE); - - for (UInt32 curPos = 0; curPos < dataSize;) - { - curPos++; - if (((*data++) & cmpMask) == 0xE8) - { - UInt32 offset = (curPos + fileOffset) & (kFileSize - 1); - 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; - 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; - 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]; - - UInt64 blockStart = f.Start; - - size_t lzAvail = (size_t)(_lzSize - _lzWritten); - if (lzAvail == 0) - break; - - if (blockStart > _lzWritten) - { - 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; - } - - UInt32 blockSize = f.Size; - size_t offset = (size_t)(_lzWritten - blockStart); - if (offset == 0) - { - _filterSrc.AllocAtLeast(blockSize); - if (!_filterSrc.IsAllocated()) - return E_OUTOFMEMORY; - } - - 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; - - size_t lzAvail = (size_t)(_lzSize - _lzWritten); - RINOK(WriteData(_window + _winPos - lzAvail, lzAvail)); - _lzWritten += lzAvail; - return S_OK; -} - - -static UInt32 ReadUInt32(CBitDecoder &bi) -{ - 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; - 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(); - - { - unsigned flags = _bitStream.ReadByteInAligned(); - unsigned checkSum = _bitStream.ReadByteInAligned(); - checkSum ^= flags; - 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(); - 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; - } - - 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; - 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; - 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(); - - UInt64 processed = _bitStream.GetProcessedSize_Round(); - if (processed >= _bitStream._blockEnd) - { - if (processed > _bitStream._blockEnd) - break; // return S_FALSE; - { - 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; - } - - 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; - 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); - 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; - { - 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; - -STDMETHODIMP 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 - { - 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; - size_t oldSize = _winSize; - size_t newMask = newSize - 1; - size_t oldMask = _winSize - 1; - 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; - - 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. -} - -STDMETHODIMP 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; -} - -}} +// Rar5Decoder.cpp +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#include "StdAfx.h" + +// #include + +#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 = _bufLim - _buf; + if (rem != 0) + memmove(_bufBase, _buf, rem); + + _bufLim = _bufBase + rem; + _processedSize += (_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 = _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(): + _window(NULL), + _winPos(0), + _winSizeAllocated(0), + _lzSize(0), + _lzEnd(0), + _writtenFileSize(0), + _dictSizeLog(0), + _isSolid(false), + _solidAllowed(false), + _wasInit(false), + _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) + { + 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; + UInt32 fileOffset = (UInt32)(f.Start - _lzFileStart); + + const UInt32 kFileSize = (UInt32)1 << 24; + Byte cmpMask = (Byte)(f.Type == FILTER_E8 ? 0xFF : 0xFE); + + for (UInt32 curPos = 0; curPos < dataSize;) + { + curPos++; + if (((*data++) & cmpMask) == 0xE8) + { + UInt32 offset = (curPos + fileOffset) & (kFileSize - 1); + 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; + 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; + 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]; + + UInt64 blockStart = f.Start; + + size_t lzAvail = (size_t)(_lzSize - _lzWritten); + if (lzAvail == 0) + break; + + if (blockStart > _lzWritten) + { + 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; + } + + UInt32 blockSize = f.Size; + size_t offset = (size_t)(_lzWritten - blockStart); + if (offset == 0) + { + _filterSrc.AllocAtLeast(blockSize); + if (!_filterSrc.IsAllocated()) + return E_OUTOFMEMORY; + } + + 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; + + size_t lzAvail = (size_t)(_lzSize - _lzWritten); + RINOK(WriteData(_window + _winPos - lzAvail, lzAvail)); + _lzWritten += lzAvail; + return S_OK; +} + + +static UInt32 ReadUInt32(CBitDecoder &bi) +{ + 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; + 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(); + + { + unsigned flags = _bitStream.ReadByteInAligned(); + unsigned checkSum = _bitStream.ReadByteInAligned(); + checkSum ^= flags; + 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(); + 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; + } + + 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; + 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; + 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(); + + UInt64 processed = _bitStream.GetProcessedSize_Round(); + if (processed >= _bitStream._blockEnd) + { + if (processed > _bitStream._blockEnd) + break; // return S_FALSE; + { + 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; + } + + 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; + 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); + 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; + { + 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; + +STDMETHODIMP 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 + { + 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; + size_t oldSize = _winSize; + size_t newMask = newSize - 1; + size_t oldMask = _winSize - 1; + 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; + + 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. +} + +STDMETHODIMP 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 index 9039b481e..8174c4af7 100644 --- a/CPP/7zip/Compress/Rar5Decoder.h +++ b/CPP/7zip/Compress/Rar5Decoder.h @@ -1,307 +1,307 @@ -// Rar5Decoder.h -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -#ifndef __COMPRESS_RAR5_DECODER_H -#define __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 - { - UInt64 delta = _blockEnd - processed; - if ((size_t)(_bufCheck - _buf) > delta) - _bufCheck2 = _buf + (size_t)delta; - } - } - } - - bool IsBlockOverRead() 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 + (_buf - _bufBase); } - UInt64 GetProcessedSize() const { return _processedSize + (_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]; - UInt32 mask = ((1 << numBits) - 1); - numBits += _bitPos; - v >>= (16 - numBits); - _buf = buf + (numBits >> 3); - _bitPos = numBits & 7; - return v & mask; - } - - UInt32 ReadBits32(unsigned numBits) - { - 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; - -class CDecoder: - public ICompressCoder, - public ICompressSetDecoderProperties2, - public CMyUnknownImp -{ - 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 _filters; - - ISequentialInStream *_inStream; - ISequentialOutStream *_outStream; - ICompressProgressInfo *_progress; - Byte *_inputBuf; - - NHuffman::CDecoder m_MainDecoder; - NHuffman::CDecoder m_DistDecoder; - NHuffman::CDecoder m_AlignDecoder; - NHuffman::CDecoder m_LenDecoder; - NHuffman::CDecoder 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(); - - MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) - - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - - STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); -}; - -}} - -#endif +// Rar5Decoder.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#ifndef __COMPRESS_RAR5_DECODER_H +#define __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 + { + UInt64 delta = _blockEnd - processed; + if ((size_t)(_bufCheck - _buf) > delta) + _bufCheck2 = _buf + (size_t)delta; + } + } + } + + bool IsBlockOverRead() 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 + (_buf - _bufBase); } + UInt64 GetProcessedSize() const { return _processedSize + (_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]; + UInt32 mask = ((1 << numBits) - 1); + numBits += _bitPos; + v >>= (16 - numBits); + _buf = buf + (numBits >> 3); + _bitPos = numBits & 7; + return v & mask; + } + + UInt32 ReadBits32(unsigned numBits) + { + 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; + +class CDecoder: + public ICompressCoder, + public ICompressSetDecoderProperties2, + public CMyUnknownImp +{ + 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 _filters; + + ISequentialInStream *_inStream; + ISequentialOutStream *_outStream; + ICompressProgressInfo *_progress; + Byte *_inputBuf; + + NHuffman::CDecoder m_MainDecoder; + NHuffman::CDecoder m_DistDecoder; + NHuffman::CDecoder m_AlignDecoder; + NHuffman::CDecoder m_LenDecoder; + NHuffman::CDecoder 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(); + + MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/RarCodecsRegister.cpp b/CPP/7zip/Compress/RarCodecsRegister.cpp index 9679b6e5e..e1bc3d9b3 100644 --- a/CPP/7zip/Compress/RarCodecsRegister.cpp +++ b/CPP/7zip/Compress/RarCodecsRegister.cpp @@ -1,33 +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) - -} +// 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 index 3f3a42a33..41f0e3521 100644 --- a/CPP/7zip/Compress/ShrinkDecoder.cpp +++ b/CPP/7zip/Compress/ShrinkDecoder.cpp @@ -1,244 +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 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 = 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; -} - - -STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - // catch(const CInBufferException &e) { return e.ErrorCode; } - // catch(const COutBufferException &e) { return e.ErrorCode; } - catch(const CSystemException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - - -STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode) -{ - _fullStreamMode = (finishMode != 0); - return S_OK; -} - - -STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) -{ - *value = _inProcessed; - return S_OK; -} - - -}} +// 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 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 = 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; +} + + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + // catch(const CInBufferException &e) { return e.ErrorCode; } + // catch(const COutBufferException &e) { return e.ErrorCode; } + catch(const CSystemException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + + +STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode) +{ + _fullStreamMode = (finishMode != 0); + return S_OK; +} + + +STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) +{ + *value = _inProcessed; + return S_OK; +} + + +}} diff --git a/CPP/7zip/Compress/ShrinkDecoder.h b/CPP/7zip/Compress/ShrinkDecoder.h index ed3f2ddce..b095b5f46 100644 --- a/CPP/7zip/Compress/ShrinkDecoder.h +++ b/CPP/7zip/Compress/ShrinkDecoder.h @@ -1,45 +1,45 @@ -// ShrinkDecoder.h - -#ifndef __COMPRESS_SHRINK_DECODER_H -#define __COMPRESS_SHRINK_DECODER_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -namespace NCompress { -namespace NShrink { - -const unsigned kNumMaxBits = 13; -const unsigned kNumItems = 1 << kNumMaxBits; - -class CDecoder : - public ICompressCoder, - public ICompressSetFinishMode, - public ICompressGetInStreamProcessedSize, - public CMyUnknownImp -{ - 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); - -public: - MY_UNKNOWN_IMP2( - ICompressSetFinishMode, - ICompressGetInStreamProcessedSize) - - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - STDMETHOD(SetFinishMode)(UInt32 finishMode); - STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); -}; - -}} - -#endif +// ShrinkDecoder.h + +#ifndef __COMPRESS_SHRINK_DECODER_H +#define __COMPRESS_SHRINK_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +namespace NCompress { +namespace NShrink { + +const unsigned kNumMaxBits = 13; +const unsigned kNumItems = 1 << kNumMaxBits; + +class CDecoder : + public ICompressCoder, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize, + public CMyUnknownImp +{ + 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); + +public: + MY_UNKNOWN_IMP2( + ICompressSetFinishMode, + ICompressGetInStreamProcessedSize) + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + STDMETHOD(SetFinishMode)(UInt32 finishMode); + STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/StdAfx.h b/CPP/7zip/Compress/StdAfx.h index 42a088f12..1cbd7feae 100644 --- a/CPP/7zip/Compress/StdAfx.h +++ b/CPP/7zip/Compress/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Compress/XpressDecoder.cpp b/CPP/7zip/Compress/XpressDecoder.cpp index c143ccf36..864c6f8fe 100644 --- a/CPP/7zip/Compress/XpressDecoder.cpp +++ b/CPP/7zip/Compress/XpressDecoder.cpp @@ -1,130 +1,130 @@ -// XpressDecoder.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/CpuArch.h" - -#include "HuffmanDecoder.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 huff; - - if (inSize < kNumSyms / 2 + 4) - return S_FALSE; - { - Byte levels[kNumSyms]; - for (unsigned i = 0; i < kNumSyms / 2; i++) - { - 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 = (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); - } - } -} - -}} +// XpressDecoder.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/CpuArch.h" + +#include "HuffmanDecoder.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 huff; + + if (inSize < kNumSyms / 2 + 4) + return S_FALSE; + { + Byte levels[kNumSyms]; + for (unsigned i = 0; i < kNumSyms / 2; i++) + { + 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 = (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 index d18f6b44b..cada85bf9 100644 --- a/CPP/7zip/Compress/XpressDecoder.h +++ b/CPP/7zip/Compress/XpressDecoder.h @@ -1,13 +1,13 @@ -// XpressDecoder.h - -#ifndef __XPRESS_DECODER_H -#define __XPRESS_DECODER_H - -namespace NCompress { -namespace NXpress { - -HRESULT Decode(const Byte *in, size_t inSize, Byte *out, size_t outSize); - -}} - -#endif +// XpressDecoder.h + +#ifndef __XPRESS_DECODER_H +#define __XPRESS_DECODER_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 4fcd09fe8..7a9743118 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 = 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 + +}} diff --git a/CPP/7zip/Compress/XzDecoder.h b/CPP/7zip/Compress/XzDecoder.h index 76694eec0..b65b46b8f 100644 --- a/CPP/7zip/Compress/XzDecoder.h +++ b/CPP/7zip/Compress/XzDecoder.h @@ -1,92 +1,92 @@ -// 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 __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 diff --git a/CPP/7zip/Compress/XzEncoder.cpp b/CPP/7zip/Compress/XzEncoder.cpp index 458a928c9..7dd4d8606 100644 --- a/CPP/7zip/Compress/XzEncoder.cpp +++ b/CPP/7zip/Compress/XzEncoder.cpp @@ -1,245 +1,245 @@ -// 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 < 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); +} + +}} diff --git a/CPP/7zip/Compress/XzEncoder.h b/CPP/7zip/Compress/XzEncoder.h index 79d81f793..ea5190ee6 100644 --- a/CPP/7zip/Compress/XzEncoder.h +++ b/CPP/7zip/Compress/XzEncoder.h @@ -1,46 +1,46 @@ -// 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 __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 diff --git a/CPP/7zip/Compress/ZDecoder.cpp b/CPP/7zip/Compress/ZDecoder.cpp index f724d5b03..06eab00ef 100644 --- a/CPP/7zip/Compress/ZDecoder.cpp +++ b/CPP/7zip/Compress/ZDecoder.cpp @@ -1,237 +1,237 @@ -// ZDecoder.cpp - -#include "StdAfx.h" - -// #include - -#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 = 0; - MyFree(_suffixes); _suffixes = 0; - MyFree(_stack); _stack = 0; -} - -CDecoder::~CDecoder() { Free(); } - -HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) -{ - CInBuffer inBuffer; - COutBuffer outBuffer; - - 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; - unsigned maxbits = prop & kNumBitsMask; - if (maxbits < kNumMinBits || maxbits > kNumMaxBits) - return S_FALSE; - UInt32 numItems = 1 << maxbits; - // Speed optimization: blockSymbol can contain unused velue. - - if (maxbits != _numMaxBits || _parents == 0 || _suffixes == 0 || _stack == 0) - { - Free(); - _parents = (UInt16 *)MyAlloc(numItems * sizeof(UInt16)); if (_parents == 0) return E_OUTOFMEMORY; - _suffixes = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (_suffixes == 0) return E_OUTOFMEMORY; - _stack = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (_stack == 0) return E_OUTOFMEMORY; - _numMaxBits = maxbits; - } - - UInt64 prevPos = 0; - 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; - UInt64 nowPos = outBuffer.GetProcessedSize(); - if (progress && nowPos - prevPos >= (1 << 13)) - { - prevPos = nowPos; - UInt64 packSize = inBuffer.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&packSize, &nowPos)); - } - } - 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(); - HRESULT res2 = outBuffer.Flush(); - return (res == S_OK) ? res2 : res; -} - -STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const COutBufferException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - -bool CheckStream(const Byte *data, size_t size) -{ - if (size < 3) - return false; - if (data[0] != 0x1F || data[1] != 0x9D) - return false; - Byte prop = data[2]; - if ((prop & 0x60) != 0) - return false; - unsigned maxbits = prop & kNumBitsMask; - if (maxbits < kNumMinBits || maxbits > kNumMaxBits) - return false; - UInt32 numItems = 1 << maxbits; - 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) - { - unsigned num = (numBits < size) ? numBits : (unsigned)size; - memcpy(buf, data, num); - data += num; - size -= num; - numBufBits = num * 8; - bitPos = 0; - } - 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++; - } - } - } - } -} - -}} +// ZDecoder.cpp + +#include "StdAfx.h" + +// #include + +#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 = 0; + MyFree(_suffixes); _suffixes = 0; + MyFree(_stack); _stack = 0; +} + +CDecoder::~CDecoder() { Free(); } + +HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) +{ + CInBuffer inBuffer; + COutBuffer outBuffer; + + 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; + unsigned maxbits = prop & kNumBitsMask; + if (maxbits < kNumMinBits || maxbits > kNumMaxBits) + return S_FALSE; + UInt32 numItems = 1 << maxbits; + // Speed optimization: blockSymbol can contain unused velue. + + if (maxbits != _numMaxBits || _parents == 0 || _suffixes == 0 || _stack == 0) + { + Free(); + _parents = (UInt16 *)MyAlloc(numItems * sizeof(UInt16)); if (_parents == 0) return E_OUTOFMEMORY; + _suffixes = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (_suffixes == 0) return E_OUTOFMEMORY; + _stack = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (_stack == 0) return E_OUTOFMEMORY; + _numMaxBits = maxbits; + } + + UInt64 prevPos = 0; + 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; + UInt64 nowPos = outBuffer.GetProcessedSize(); + if (progress && nowPos - prevPos >= (1 << 13)) + { + prevPos = nowPos; + UInt64 packSize = inBuffer.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &nowPos)); + } + } + 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(); + HRESULT res2 = outBuffer.Flush(); + return (res == S_OK) ? res2 : res; +} + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const COutBufferException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +bool CheckStream(const Byte *data, size_t size) +{ + if (size < 3) + return false; + if (data[0] != 0x1F || data[1] != 0x9D) + return false; + Byte prop = data[2]; + if ((prop & 0x60) != 0) + return false; + unsigned maxbits = prop & kNumBitsMask; + if (maxbits < kNumMinBits || maxbits > kNumMaxBits) + return false; + UInt32 numItems = 1 << maxbits; + 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) + { + unsigned num = (numBits < size) ? numBits : (unsigned)size; + memcpy(buf, data, num); + data += num; + size -= num; + numBufBits = num * 8; + bitPos = 0; + } + 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 index ed29d88a9..19acd4985 100644 --- a/CPP/7zip/Compress/ZDecoder.h +++ b/CPP/7zip/Compress/ZDecoder.h @@ -1,54 +1,54 @@ -// ZDecoder.h - -#ifndef __COMPRESS_Z_DECODER_H -#define __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. - -class CDecoder: - public ICompressCoder, - public CMyUnknownImp -{ - UInt16 *_parents; - Byte *_suffixes; - Byte *_stack; - unsigned _numMaxBits; - -public: - CDecoder(): _parents(0), _suffixes(0), _stack(0), /* _prop(0), */ _numMaxBits(0) {}; - ~CDecoder(); - void Free(); - UInt64 PackSize; - - MY_UNKNOWN_IMP1(ICompressCoder) - - HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); -}; - -/* - 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 +// ZDecoder.h + +#ifndef __COMPRESS_Z_DECODER_H +#define __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. + +class CDecoder: + public ICompressCoder, + public CMyUnknownImp +{ + UInt16 *_parents; + Byte *_suffixes; + Byte *_stack; + unsigned _numMaxBits; + +public: + CDecoder(): _parents(0), _suffixes(0), _stack(0), /* _prop(0), */ _numMaxBits(0) {}; + ~CDecoder(); + void Free(); + UInt64 PackSize; + + MY_UNKNOWN_IMP1(ICompressCoder) + + HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); +}; + +/* + 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 index 293a77cb2..8f3a63cb7 100644 --- a/CPP/7zip/Compress/ZlibDecoder.cpp +++ b/CPP/7zip/Compress/ZlibDecoder.cpp @@ -1,92 +1,92 @@ -// ZlibDecoder.cpp - -#include "StdAfx.h" - -#include "../Common/StreamUtils.h" - -#include "ZlibDecoder.h" - -namespace NCompress { -namespace NZlib { - -#define DEFLATE_TRY_BEGIN try { -#define DEFLATE_TRY_END } catch(...) { return S_FALSE; } - -#define ADLER_MOD 65521 -#define ADLER_LOOP_MAX 5550 - -UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size) -{ - UInt32 a = adler & 0xFFFF; - UInt32 b = (adler >> 16) & 0xFFFF; - while (size > 0) - { - unsigned curSize = (size > ADLER_LOOP_MAX) ? ADLER_LOOP_MAX : (unsigned )size; - unsigned i; - for (i = 0; i < curSize; i++) - { - a += buf[i]; - b += a; - } - buf += curSize; - size -= curSize; - a %= ADLER_MOD; - b %= ADLER_MOD; - } - return (b << 16) + a; -} - -STDMETHODIMP COutStreamWithAdler::Write(const void *data, UInt32 size, UInt32 *processedSize) -{ - HRESULT result = 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; -} - -STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - DEFLATE_TRY_BEGIN - if (!AdlerStream) - AdlerStream = AdlerSpec = new COutStreamWithAdler; - if (!DeflateDecoder) - { - DeflateDecoderSpec = new NDeflate::NDecoder::CCOMCoder; - DeflateDecoderSpec->ZlibMode = true; - DeflateDecoder = DeflateDecoderSpec; - } - - 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; - - HRESULT res = DeflateDecoder->Code(inStream, AdlerStream, inSize ? &inSize2 : NULL, outSize, progress); - AdlerSpec->ReleaseStream(); - - if (res == S_OK) - { - const Byte *p = DeflateDecoderSpec->ZlibFooter; - UInt32 adler = ((UInt32)p[0] << 24) | ((UInt32)p[1] << 16) | ((UInt32)p[2] << 8) | p[3]; - if (adler != AdlerSpec->GetAdler()) - return S_FALSE; - } - return res; - DEFLATE_TRY_END -} - -}} +// ZlibDecoder.cpp + +#include "StdAfx.h" + +#include "../Common/StreamUtils.h" + +#include "ZlibDecoder.h" + +namespace NCompress { +namespace NZlib { + +#define DEFLATE_TRY_BEGIN try { +#define DEFLATE_TRY_END } catch(...) { return S_FALSE; } + +#define ADLER_MOD 65521 +#define ADLER_LOOP_MAX 5550 + +UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size) +{ + UInt32 a = adler & 0xFFFF; + UInt32 b = (adler >> 16) & 0xFFFF; + while (size > 0) + { + unsigned curSize = (size > ADLER_LOOP_MAX) ? ADLER_LOOP_MAX : (unsigned )size; + unsigned i; + for (i = 0; i < curSize; i++) + { + a += buf[i]; + b += a; + } + buf += curSize; + size -= curSize; + a %= ADLER_MOD; + b %= ADLER_MOD; + } + return (b << 16) + a; +} + +STDMETHODIMP COutStreamWithAdler::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + HRESULT result = 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; +} + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + DEFLATE_TRY_BEGIN + if (!AdlerStream) + AdlerStream = AdlerSpec = new COutStreamWithAdler; + if (!DeflateDecoder) + { + DeflateDecoderSpec = new NDeflate::NDecoder::CCOMCoder; + DeflateDecoderSpec->ZlibMode = true; + DeflateDecoder = DeflateDecoderSpec; + } + + 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; + + HRESULT res = DeflateDecoder->Code(inStream, AdlerStream, inSize ? &inSize2 : NULL, outSize, progress); + AdlerSpec->ReleaseStream(); + + if (res == S_OK) + { + const Byte *p = DeflateDecoderSpec->ZlibFooter; + UInt32 adler = ((UInt32)p[0] << 24) | ((UInt32)p[1] << 16) | ((UInt32)p[2] << 8) | p[3]; + if (adler != AdlerSpec->GetAdler()) + return S_FALSE; + } + return res; + DEFLATE_TRY_END +} + +}} diff --git a/CPP/7zip/Compress/ZlibDecoder.h b/CPP/7zip/Compress/ZlibDecoder.h index 17be887dc..8c5e73b05 100644 --- a/CPP/7zip/Compress/ZlibDecoder.h +++ b/CPP/7zip/Compress/ZlibDecoder.h @@ -1,79 +1,79 @@ -// ZlibDecoder.h - -#ifndef __ZLIB_DECODER_H -#define __ZLIB_DECODER_H - -#include "DeflateDecoder.h" - -namespace NCompress { -namespace NZlib { - -const UInt32 ADLER_INIT_VAL = 1; - -class COutStreamWithAdler: - public ISequentialOutStream, - public CMyUnknownImp -{ - CMyComPtr _stream; - UInt32 _adler; - UInt64 _size; -public: - MY_UNKNOWN_IMP - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - void Init() { _adler = ADLER_INIT_VAL; _size = 0; } - UInt32 GetAdler() const { return _adler; } - UInt64 GetSize() const { return _size; } -}; - -class CDecoder: - public ICompressCoder, - public CMyUnknownImp -{ - COutStreamWithAdler *AdlerSpec; - CMyComPtr AdlerStream; - - NCompress::NDeflate::NDecoder::CCOMCoder *DeflateDecoderSpec; - CMyComPtr DeflateDecoder; -public: - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - - UInt64 GetInputProcessedSize() const { return DeflateDecoderSpec->GetInputProcessedSize() + 2; } - UInt64 GetOutputProcessedSize() const { return AdlerSpec->GetSize(); } - - MY_UNKNOWN_IMP -}; - -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; - unsigned val = p[2]; - 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 +// ZlibDecoder.h + +#ifndef __ZLIB_DECODER_H +#define __ZLIB_DECODER_H + +#include "DeflateDecoder.h" + +namespace NCompress { +namespace NZlib { + +const UInt32 ADLER_INIT_VAL = 1; + +class COutStreamWithAdler: + public ISequentialOutStream, + public CMyUnknownImp +{ + CMyComPtr _stream; + UInt32 _adler; + UInt64 _size; +public: + MY_UNKNOWN_IMP + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init() { _adler = ADLER_INIT_VAL; _size = 0; } + UInt32 GetAdler() const { return _adler; } + UInt64 GetSize() const { return _size; } +}; + +class CDecoder: + public ICompressCoder, + public CMyUnknownImp +{ + COutStreamWithAdler *AdlerSpec; + CMyComPtr AdlerStream; + + NCompress::NDeflate::NDecoder::CCOMCoder *DeflateDecoderSpec; + CMyComPtr DeflateDecoder; +public: + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + UInt64 GetInputProcessedSize() const { return DeflateDecoderSpec->GetInputProcessedSize() + 2; } + UInt64 GetOutputProcessedSize() const { return AdlerSpec->GetSize(); } + + MY_UNKNOWN_IMP +}; + +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; + unsigned val = p[2]; + 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 index e023b746d..09235c337 100644 --- a/CPP/7zip/Compress/ZlibEncoder.cpp +++ b/CPP/7zip/Compress/ZlibEncoder.cpp @@ -1,61 +1,61 @@ -// ZlibEncoder.cpp - -#include "StdAfx.h" - -#include "../Common/StreamUtils.h" - -#include "ZlibEncoder.h" - -namespace NCompress { -namespace NZlib { - -#define DEFLATE_TRY_BEGIN try { -#define DEFLATE_TRY_END } catch(...) { return S_FALSE; } - -UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size); - -STDMETHODIMP CInStreamWithAdler::Read(void *data, UInt32 size, UInt32 *processedSize) -{ - HRESULT result = _stream->Read(data, size, &size); - _adler = Adler32_Update(_adler, (const Byte *)data, size); - _size += size; - if (processedSize != NULL) - *processedSize = size; - return result; -} - -void CEncoder::Create() -{ - if (!DeflateEncoder) - DeflateEncoder = DeflateEncoderSpec = new NDeflate::NEncoder::CCOMCoder; -} - -STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 * /* outSize */, ICompressProgressInfo *progress) -{ - DEFLATE_TRY_BEGIN - if (!AdlerStream) - AdlerStream = AdlerSpec = new CInStreamWithAdler; - Create(); - - { - Byte buf[2] = { 0x78, 0xDA }; - RINOK(WriteStream(outStream, buf, 2)); - } - - AdlerSpec->SetStream(inStream); - AdlerSpec->Init(); - HRESULT res = DeflateEncoder->Code(AdlerStream, outStream, inSize, NULL, progress); - AdlerSpec->ReleaseStream(); - - RINOK(res); - - { - UInt32 a = AdlerSpec->GetAdler(); - Byte buf[4] = { (Byte)(a >> 24), (Byte)(a >> 16), (Byte)(a >> 8), (Byte)(a) }; - return WriteStream(outStream, buf, 4); - } - DEFLATE_TRY_END -} - -}} +// ZlibEncoder.cpp + +#include "StdAfx.h" + +#include "../Common/StreamUtils.h" + +#include "ZlibEncoder.h" + +namespace NCompress { +namespace NZlib { + +#define DEFLATE_TRY_BEGIN try { +#define DEFLATE_TRY_END } catch(...) { return S_FALSE; } + +UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size); + +STDMETHODIMP CInStreamWithAdler::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + HRESULT result = _stream->Read(data, size, &size); + _adler = Adler32_Update(_adler, (const Byte *)data, size); + _size += size; + if (processedSize != NULL) + *processedSize = size; + return result; +} + +void CEncoder::Create() +{ + if (!DeflateEncoder) + DeflateEncoder = DeflateEncoderSpec = new NDeflate::NEncoder::CCOMCoder; +} + +STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 * /* outSize */, ICompressProgressInfo *progress) +{ + DEFLATE_TRY_BEGIN + if (!AdlerStream) + AdlerStream = AdlerSpec = new CInStreamWithAdler; + Create(); + + { + Byte buf[2] = { 0x78, 0xDA }; + RINOK(WriteStream(outStream, buf, 2)); + } + + AdlerSpec->SetStream(inStream); + AdlerSpec->Init(); + HRESULT res = DeflateEncoder->Code(AdlerStream, outStream, inSize, NULL, progress); + AdlerSpec->ReleaseStream(); + + RINOK(res); + + { + UInt32 a = AdlerSpec->GetAdler(); + Byte buf[4] = { (Byte)(a >> 24), (Byte)(a >> 16), (Byte)(a >> 8), (Byte)(a) }; + return WriteStream(outStream, buf, 4); + } + DEFLATE_TRY_END +} + +}} diff --git a/CPP/7zip/Compress/ZlibEncoder.h b/CPP/7zip/Compress/ZlibEncoder.h index 3cac95046..621cc1d08 100644 --- a/CPP/7zip/Compress/ZlibEncoder.h +++ b/CPP/7zip/Compress/ZlibEncoder.h @@ -1,48 +1,48 @@ -// ZlibEncoder.h - -#ifndef __ZLIB_ENCODER_H -#define __ZLIB_ENCODER_H - -#include "DeflateEncoder.h" - -namespace NCompress { -namespace NZlib { - -class CInStreamWithAdler: - public ISequentialInStream, - public CMyUnknownImp -{ - CMyComPtr _stream; - UInt32 _adler; - UInt64 _size; -public: - MY_UNKNOWN_IMP - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - void SetStream(ISequentialInStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - void Init() { _adler = 1; _size = 0; } // ADLER_INIT_VAL - UInt32 GetAdler() const { return _adler; } - UInt64 GetSize() const { return _size; } -}; - -class CEncoder: - public ICompressCoder, - public CMyUnknownImp -{ - CInStreamWithAdler *AdlerSpec; - CMyComPtr AdlerStream; - CMyComPtr DeflateEncoder; -public: - NCompress::NDeflate::NEncoder::CCOMCoder *DeflateEncoderSpec; - - void Create(); - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - UInt64 GetInputProcessedSize() const { return AdlerSpec->GetSize(); } - - MY_UNKNOWN_IMP -}; - -}} - -#endif +// ZlibEncoder.h + +#ifndef __ZLIB_ENCODER_H +#define __ZLIB_ENCODER_H + +#include "DeflateEncoder.h" + +namespace NCompress { +namespace NZlib { + +class CInStreamWithAdler: + public ISequentialInStream, + public CMyUnknownImp +{ + CMyComPtr _stream; + UInt32 _adler; + UInt64 _size; +public: + MY_UNKNOWN_IMP + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + void SetStream(ISequentialInStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init() { _adler = 1; _size = 0; } // ADLER_INIT_VAL + UInt32 GetAdler() const { return _adler; } + UInt64 GetSize() const { return _size; } +}; + +class CEncoder: + public ICompressCoder, + public CMyUnknownImp +{ + CInStreamWithAdler *AdlerSpec; + CMyComPtr AdlerStream; + CMyComPtr DeflateEncoder; +public: + NCompress::NDeflate::NEncoder::CCOMCoder *DeflateEncoderSpec; + + void Create(); + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + UInt64 GetInputProcessedSize() const { return AdlerSpec->GetSize(); } + + MY_UNKNOWN_IMP +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/makefile b/CPP/7zip/Compress/makefile index 9be1878f0..e981319dd 100644 --- a/CPP/7zip/Compress/makefile +++ b/CPP/7zip/Compress/makefile @@ -1,7 +1,7 @@ -DIRS = \ - LZMA_Alone\~ \ - -all: $(DIRS) - -$(DIRS): -!include "../SubBuild.mak" +DIRS = \ + LZMA_Alone\~ \ + +all: $(DIRS) + +$(DIRS): +!include "../SubBuild.mak" diff --git a/CPP/7zip/Crc.mak b/CPP/7zip/Crc.mak index 66b35c1e4..815142db8 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 6df9b4064..d58a48326 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 55e40f385..2ed69badc 100644 --- a/CPP/7zip/Crypto/7zAes.cpp +++ b/CPP/7zip/Crypto/7zAes.cpp @@ -1,280 +1,280 @@ -// 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 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 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/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 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 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); +} + +}} diff --git a/CPP/7zip/Crypto/7zAes.h b/CPP/7zip/Crypto/7zAes.h index 5a0943607..84e07ac96 100644 --- a/CPP/7zip/Crypto/7zAes.h +++ b/CPP/7zip/Crypto/7zAes.h @@ -1,118 +1,118 @@ -// 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 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 _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 __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 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 _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 diff --git a/CPP/7zip/Crypto/7zAesRegister.cpp b/CPP/7zip/Crypto/7zAesRegister.cpp index c0b206093..f9d59699b 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(7zAES, + CDecoder(), + CEncoder(), + 0x6F10701, "7zAES") + +}} diff --git a/CPP/7zip/Crypto/Codec.def b/CPP/7zip/Crypto/Codec.def index aab87ef8e..ebf73a3b8 100644 --- a/CPP/7zip/Crypto/Codec.def +++ b/CPP/7zip/Crypto/Codec.def @@ -1,4 +1,4 @@ -EXPORTS - CreateObject PRIVATE - GetNumberOfMethods PRIVATE - GetMethodProperty PRIVATE +EXPORTS + CreateObject PRIVATE + GetNumberOfMethods PRIVATE + GetMethodProperty PRIVATE diff --git a/CPP/7zip/Crypto/HmacSha1.cpp b/CPP/7zip/Crypto/HmacSha1.cpp index b74020a6d..359b65bc0 100644 --- a/CPP/7zip/Crypto/HmacSha1.cpp +++ b/CPP/7zip/Crypto/HmacSha1.cpp @@ -1,120 +1,120 @@ -// HmacSha1.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "HmacSha1.h" - -namespace NCrypto { -namespace NSha1 { - -void CHmac::SetKey(const Byte *key, size_t keySize) -{ - Byte keyTemp[kBlockSize]; - size_t i; - - for (i = 0; i < kBlockSize; i++) - keyTemp[i] = 0; - - if (keySize > kBlockSize) - { - _sha.Init(); - _sha.Update(key, keySize); - _sha.Final(keyTemp); - } - else - for (i = 0; i < keySize; i++) - keyTemp[i] = key[i]; - - for (i = 0; i < kBlockSize; i++) - keyTemp[i] ^= 0x36; - - _sha.Init(); - _sha.Update(keyTemp, kBlockSize); - - for (i = 0; i < kBlockSize; i++) - keyTemp[i] ^= 0x36 ^ 0x5C; - - _sha2.Init(); - _sha2.Update(keyTemp, kBlockSize); -} - -void CHmac::Final(Byte *mac, size_t macSize) -{ - Byte digest[kDigestSize]; - _sha.Final(digest); - _sha2.Update(digest, kDigestSize); - _sha2.Final(digest); - for (size_t i = 0; i < macSize; i++) - mac[i] = digest[i]; -} - - -void CHmac32::SetKey(const Byte *key, size_t keySize) -{ - UInt32 keyTemp[kNumBlockWords]; - size_t i; - - for (i = 0; i < kNumBlockWords; i++) - keyTemp[i] = 0; - - if (keySize > kBlockSize) - { - CContext sha; - sha.Init(); - sha.Update(key, keySize); - Byte digest[kDigestSize]; - sha.Final(digest); - - for (i = 0 ; i < kNumDigestWords; i++) - keyTemp[i] = GetBe32(digest + i * 4 + 0); - } - else - for (i = 0; i < keySize; i++) - keyTemp[i / 4] |= (key[i] << (24 - 8 * (i & 3))); - - for (i = 0; i < kNumBlockWords; i++) - keyTemp[i] ^= 0x36363636; - - _sha.Init(); - _sha.Update(keyTemp, kNumBlockWords); - - for (i = 0; i < kNumBlockWords; i++) - keyTemp[i] ^= 0x36363636 ^ 0x5C5C5C5C; - - _sha2.Init(); - _sha2.Update(keyTemp, kNumBlockWords); -} - -void CHmac32::Final(UInt32 *mac, size_t macSize) -{ - UInt32 digest[kNumDigestWords]; - _sha.Final(digest); - _sha2.Update(digest, kNumDigestWords); - _sha2.Final(digest); - for (size_t i = 0; i < macSize; i++) - mac[i] = digest[i]; -} - -void CHmac32::GetLoopXorDigest(UInt32 *mac, UInt32 numIteration) -{ - UInt32 block[kNumBlockWords]; - UInt32 block2[kNumBlockWords]; - - _sha.PrepareBlock(block, kNumDigestWords); - _sha2.PrepareBlock(block2, kNumDigestWords); - - for (unsigned s = 0; s < kNumDigestWords; s++) - block[s] = mac[s]; - - for (UInt32 i = 0; i < numIteration; i++) - { - _sha.GetBlockDigest(block, block2); - _sha2.GetBlockDigest(block2, block); - for (unsigned s = 0; s < kNumDigestWords; s++) - mac[s] ^= block[s]; - } -} - -}} +// HmacSha1.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "HmacSha1.h" + +namespace NCrypto { +namespace NSha1 { + +void CHmac::SetKey(const Byte *key, size_t keySize) +{ + Byte keyTemp[kBlockSize]; + size_t i; + + for (i = 0; i < kBlockSize; i++) + keyTemp[i] = 0; + + if (keySize > kBlockSize) + { + _sha.Init(); + _sha.Update(key, keySize); + _sha.Final(keyTemp); + } + else + for (i = 0; i < keySize; i++) + keyTemp[i] = key[i]; + + for (i = 0; i < kBlockSize; i++) + keyTemp[i] ^= 0x36; + + _sha.Init(); + _sha.Update(keyTemp, kBlockSize); + + for (i = 0; i < kBlockSize; i++) + keyTemp[i] ^= 0x36 ^ 0x5C; + + _sha2.Init(); + _sha2.Update(keyTemp, kBlockSize); +} + +void CHmac::Final(Byte *mac, size_t macSize) +{ + Byte digest[kDigestSize]; + _sha.Final(digest); + _sha2.Update(digest, kDigestSize); + _sha2.Final(digest); + for (size_t i = 0; i < macSize; i++) + mac[i] = digest[i]; +} + + +void CHmac32::SetKey(const Byte *key, size_t keySize) +{ + UInt32 keyTemp[kNumBlockWords]; + size_t i; + + for (i = 0; i < kNumBlockWords; i++) + keyTemp[i] = 0; + + if (keySize > kBlockSize) + { + CContext sha; + sha.Init(); + sha.Update(key, keySize); + Byte digest[kDigestSize]; + sha.Final(digest); + + for (i = 0 ; i < kNumDigestWords; i++) + keyTemp[i] = GetBe32(digest + i * 4 + 0); + } + else + for (i = 0; i < keySize; i++) + keyTemp[i / 4] |= (key[i] << (24 - 8 * (i & 3))); + + for (i = 0; i < kNumBlockWords; i++) + keyTemp[i] ^= 0x36363636; + + _sha.Init(); + _sha.Update(keyTemp, kNumBlockWords); + + for (i = 0; i < kNumBlockWords; i++) + keyTemp[i] ^= 0x36363636 ^ 0x5C5C5C5C; + + _sha2.Init(); + _sha2.Update(keyTemp, kNumBlockWords); +} + +void CHmac32::Final(UInt32 *mac, size_t macSize) +{ + UInt32 digest[kNumDigestWords]; + _sha.Final(digest); + _sha2.Update(digest, kNumDigestWords); + _sha2.Final(digest); + for (size_t i = 0; i < macSize; i++) + mac[i] = digest[i]; +} + +void CHmac32::GetLoopXorDigest(UInt32 *mac, UInt32 numIteration) +{ + UInt32 block[kNumBlockWords]; + UInt32 block2[kNumBlockWords]; + + _sha.PrepareBlock(block, kNumDigestWords); + _sha2.PrepareBlock(block2, kNumDigestWords); + + for (unsigned s = 0; s < kNumDigestWords; s++) + block[s] = mac[s]; + + for (UInt32 i = 0; i < numIteration; i++) + { + _sha.GetBlockDigest(block, block2); + _sha2.GetBlockDigest(block2, block); + for (unsigned s = 0; s < kNumDigestWords; s++) + mac[s] ^= block[s]; + } +} + +}} diff --git a/CPP/7zip/Crypto/HmacSha1.h b/CPP/7zip/Crypto/HmacSha1.h index b107913e9..6ba015e84 100644 --- a/CPP/7zip/Crypto/HmacSha1.h +++ b/CPP/7zip/Crypto/HmacSha1.h @@ -1,39 +1,39 @@ -// HmacSha1.h -// Implements HMAC-SHA-1 (RFC2104, FIPS-198) - -#ifndef __CRYPTO_HMAC_SHA1_H -#define __CRYPTO_HMAC_SHA1_H - -#include "Sha1Cls.h" - -namespace NCrypto { -namespace NSha1 { - -// Use: SetKey(key, keySize); for () Update(data, size); Final(mac, macSize); - -class CHmac -{ - CContext _sha; - CContext _sha2; -public: - void SetKey(const Byte *key, size_t keySize); - void Update(const Byte *data, size_t dataSize) { _sha.Update(data, dataSize); } - void Final(Byte *mac, size_t macSize = kDigestSize); -}; - -class CHmac32 -{ - CContext32 _sha; - CContext32 _sha2; -public: - void SetKey(const Byte *key, size_t keySize); - void Update(const UInt32 *data, size_t dataSize) { _sha.Update(data, dataSize); } - void Final(UInt32 *mac, size_t macSize = kNumDigestWords); - - // It'sa for hmac function. in,out: mac[kNumDigestWords]. - void GetLoopXorDigest(UInt32 *mac, UInt32 numIteration); -}; - -}} - -#endif +// HmacSha1.h +// Implements HMAC-SHA-1 (RFC2104, FIPS-198) + +#ifndef __CRYPTO_HMAC_SHA1_H +#define __CRYPTO_HMAC_SHA1_H + +#include "Sha1Cls.h" + +namespace NCrypto { +namespace NSha1 { + +// Use: SetKey(key, keySize); for () Update(data, size); Final(mac, macSize); + +class CHmac +{ + CContext _sha; + CContext _sha2; +public: + void SetKey(const Byte *key, size_t keySize); + void Update(const Byte *data, size_t dataSize) { _sha.Update(data, dataSize); } + void Final(Byte *mac, size_t macSize = kDigestSize); +}; + +class CHmac32 +{ + CContext32 _sha; + CContext32 _sha2; +public: + void SetKey(const Byte *key, size_t keySize); + void Update(const UInt32 *data, size_t dataSize) { _sha.Update(data, dataSize); } + void Final(UInt32 *mac, size_t macSize = kNumDigestWords); + + // It'sa for hmac function. in,out: mac[kNumDigestWords]. + void GetLoopXorDigest(UInt32 *mac, UInt32 numIteration); +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/HmacSha256.cpp b/CPP/7zip/Crypto/HmacSha256.cpp index 332340689..2e1efb48a 100644 --- a/CPP/7zip/Crypto/HmacSha256.cpp +++ b/CPP/7zip/Crypto/HmacSha256.cpp @@ -1,62 +1,62 @@ -// HmacSha256.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "HmacSha256.h" - -namespace NCrypto { -namespace NSha256 { - -static const unsigned kBlockSize = 64; - -void CHmac::SetKey(const Byte *key, size_t keySize) -{ - Byte temp[kBlockSize]; - size_t i; - - for (i = 0; i < kBlockSize; i++) - temp[i] = 0; - - if (keySize > kBlockSize) - { - Sha256_Init(&_sha); - Sha256_Update(&_sha, key, keySize); - Sha256_Final(&_sha, temp); - } - else - for (i = 0; i < keySize; i++) - temp[i] = key[i]; - - for (i = 0; i < kBlockSize; i++) - temp[i] ^= 0x36; - - Sha256_Init(&_sha); - Sha256_Update(&_sha, temp, kBlockSize); - - for (i = 0; i < kBlockSize; i++) - temp[i] ^= 0x36 ^ 0x5C; - - Sha256_Init(&_sha2); - Sha256_Update(&_sha2, temp, kBlockSize); -} - -void CHmac::Final(Byte *mac) -{ - Sha256_Final(&_sha, mac); - Sha256_Update(&_sha2, mac, SHA256_DIGEST_SIZE); - Sha256_Final(&_sha2, mac); -} - -/* -void CHmac::Final(Byte *mac, size_t macSize) -{ - Byte digest[SHA256_DIGEST_SIZE]; - Final(digest); - for (size_t i = 0; i < macSize; i++) - mac[i] = digest[i]; -} -*/ - -}} +// HmacSha256.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "HmacSha256.h" + +namespace NCrypto { +namespace NSha256 { + +static const unsigned kBlockSize = 64; + +void CHmac::SetKey(const Byte *key, size_t keySize) +{ + Byte temp[kBlockSize]; + size_t i; + + for (i = 0; i < kBlockSize; i++) + temp[i] = 0; + + if (keySize > kBlockSize) + { + Sha256_Init(&_sha); + Sha256_Update(&_sha, key, keySize); + Sha256_Final(&_sha, temp); + } + else + for (i = 0; i < keySize; i++) + temp[i] = key[i]; + + for (i = 0; i < kBlockSize; i++) + temp[i] ^= 0x36; + + Sha256_Init(&_sha); + Sha256_Update(&_sha, temp, kBlockSize); + + for (i = 0; i < kBlockSize; i++) + temp[i] ^= 0x36 ^ 0x5C; + + Sha256_Init(&_sha2); + Sha256_Update(&_sha2, temp, kBlockSize); +} + +void CHmac::Final(Byte *mac) +{ + Sha256_Final(&_sha, mac); + Sha256_Update(&_sha2, mac, SHA256_DIGEST_SIZE); + Sha256_Final(&_sha2, mac); +} + +/* +void CHmac::Final(Byte *mac, size_t macSize) +{ + Byte digest[SHA256_DIGEST_SIZE]; + Final(digest); + for (size_t i = 0; i < macSize; i++) + mac[i] = digest[i]; +} +*/ + +}} diff --git a/CPP/7zip/Crypto/HmacSha256.h b/CPP/7zip/Crypto/HmacSha256.h index 6db2e0a00..233424a04 100644 --- a/CPP/7zip/Crypto/HmacSha256.h +++ b/CPP/7zip/Crypto/HmacSha256.h @@ -1,27 +1,27 @@ -// HmacSha256.h -// Implements HMAC-SHA-256 (RFC2104, FIPS-198) - -#ifndef __CRYPTO_HMAC_SHA256_H -#define __CRYPTO_HMAC_SHA256_H - -#include "../../../C/Sha256.h" - -namespace NCrypto { -namespace NSha256 { - -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); - // void Final(Byte *mac, size_t macSize); -}; - -}} - -#endif +// HmacSha256.h +// Implements HMAC-SHA-256 (RFC2104, FIPS-198) + +#ifndef __CRYPTO_HMAC_SHA256_H +#define __CRYPTO_HMAC_SHA256_H + +#include "../../../C/Sha256.h" + +namespace NCrypto { +namespace NSha256 { + +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); + // void Final(Byte *mac, size_t macSize); +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/MyAes.cpp b/CPP/7zip/Crypto/MyAes.cpp index 1d399d707..52eaab7ae 100644 --- a/CPP/7zip/Crypto/MyAes.cpp +++ b/CPP/7zip/Crypto/MyAes.cpp @@ -1,112 +1,112 @@ -// 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; + +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; +} + +} diff --git a/CPP/7zip/Crypto/MyAes.h b/CPP/7zip/Crypto/MyAes.h index 8d5ed98c3..182411db4 100644 --- a/CPP/7zip/Crypto/MyAes.h +++ b/CPP/7zip/Crypto/MyAes.h @@ -1,57 +1,57 @@ -// 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 __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 diff --git a/CPP/7zip/Crypto/MyAesReg.cpp b/CPP/7zip/Crypto/MyAesReg.cpp index 3427ad625..280068355 100644 --- a/CPP/7zip/Crypto/MyAesReg.cpp +++ b/CPP/7zip/Crypto/MyAesReg.cpp @@ -1,16 +1,16 @@ -// 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 { + +REGISTER_FILTER_E(AES256CBC, + CAesCbcDecoder(32), + CAesCbcEncoder(32), + 0x6F00181, "AES256CBC") + +} diff --git a/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp b/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp index dc5151ed7..a7fcb728b 100644 --- a/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp +++ b/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp @@ -1,97 +1,97 @@ -// Pbkdf2HmacSha1.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "HmacSha1.h" - -namespace NCrypto { -namespace NSha1 { - -void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize, - const Byte *salt, size_t saltSize, - UInt32 numIterations, - Byte *key, size_t keySize) -{ - CHmac baseCtx; - baseCtx.SetKey(pwd, pwdSize); - - for (UInt32 i = 1; keySize != 0; i++) - { - CHmac ctx = baseCtx; - ctx.Update(salt, saltSize); - - Byte u[kDigestSize]; - SetBe32(u, i); - - ctx.Update(u, 4); - ctx.Final(u, kDigestSize); - - const unsigned curSize = (keySize < kDigestSize) ? (unsigned)keySize : kDigestSize; - unsigned s; - for (s = 0; s < curSize; s++) - key[s] = u[s]; - - for (UInt32 j = numIterations; j > 1; j--) - { - ctx = baseCtx; - ctx.Update(u, kDigestSize); - ctx.Final(u, kDigestSize); - for (s = 0; s < curSize; s++) - key[s] ^= u[s]; - } - - key += curSize; - keySize -= curSize; - } -} - -void Pbkdf2Hmac32(const Byte *pwd, size_t pwdSize, - const UInt32 *salt, size_t saltSize, - UInt32 numIterations, - UInt32 *key, size_t keySize) -{ - CHmac32 baseCtx; - baseCtx.SetKey(pwd, pwdSize); - - for (UInt32 i = 1; keySize != 0; i++) - { - CHmac32 ctx = baseCtx; - ctx.Update(salt, saltSize); - - UInt32 u[kNumDigestWords]; - u[0] = i; - - ctx.Update(u, 1); - ctx.Final(u, kNumDigestWords); - - // Speed-optimized code start - ctx = baseCtx; - ctx.GetLoopXorDigest(u, numIterations - 1); - // Speed-optimized code end - - const unsigned curSize = (keySize < kNumDigestWords) ? (unsigned)keySize : kNumDigestWords; - unsigned s; - for (s = 0; s < curSize; s++) - key[s] = u[s]; - - /* - // Default code start - for (UInt32 j = numIterations; j > 1; j--) - { - ctx = baseCtx; - ctx.Update(u, kNumDigestWords); - ctx.Final(u, kNumDigestWords); - for (s = 0; s < curSize; s++) - key[s] ^= u[s]; - } - // Default code end - */ - - key += curSize; - keySize -= curSize; - } -} - -}} +// Pbkdf2HmacSha1.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "HmacSha1.h" + +namespace NCrypto { +namespace NSha1 { + +void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize, + const Byte *salt, size_t saltSize, + UInt32 numIterations, + Byte *key, size_t keySize) +{ + CHmac baseCtx; + baseCtx.SetKey(pwd, pwdSize); + + for (UInt32 i = 1; keySize != 0; i++) + { + CHmac ctx = baseCtx; + ctx.Update(salt, saltSize); + + Byte u[kDigestSize]; + SetBe32(u, i); + + ctx.Update(u, 4); + ctx.Final(u, kDigestSize); + + const unsigned curSize = (keySize < kDigestSize) ? (unsigned)keySize : kDigestSize; + unsigned s; + for (s = 0; s < curSize; s++) + key[s] = u[s]; + + for (UInt32 j = numIterations; j > 1; j--) + { + ctx = baseCtx; + ctx.Update(u, kDigestSize); + ctx.Final(u, kDigestSize); + for (s = 0; s < curSize; s++) + key[s] ^= u[s]; + } + + key += curSize; + keySize -= curSize; + } +} + +void Pbkdf2Hmac32(const Byte *pwd, size_t pwdSize, + const UInt32 *salt, size_t saltSize, + UInt32 numIterations, + UInt32 *key, size_t keySize) +{ + CHmac32 baseCtx; + baseCtx.SetKey(pwd, pwdSize); + + for (UInt32 i = 1; keySize != 0; i++) + { + CHmac32 ctx = baseCtx; + ctx.Update(salt, saltSize); + + UInt32 u[kNumDigestWords]; + u[0] = i; + + ctx.Update(u, 1); + ctx.Final(u, kNumDigestWords); + + // Speed-optimized code start + ctx = baseCtx; + ctx.GetLoopXorDigest(u, numIterations - 1); + // Speed-optimized code end + + const unsigned curSize = (keySize < kNumDigestWords) ? (unsigned)keySize : kNumDigestWords; + unsigned s; + for (s = 0; s < curSize; s++) + key[s] = u[s]; + + /* + // Default code start + for (UInt32 j = numIterations; j > 1; j--) + { + ctx = baseCtx; + ctx.Update(u, kNumDigestWords); + ctx.Final(u, kNumDigestWords); + for (s = 0; s < curSize; s++) + key[s] ^= u[s]; + } + // Default code end + */ + + key += curSize; + keySize -= curSize; + } +} + +}} diff --git a/CPP/7zip/Crypto/Pbkdf2HmacSha1.h b/CPP/7zip/Crypto/Pbkdf2HmacSha1.h index 6303e3c3d..6560b8d15 100644 --- a/CPP/7zip/Crypto/Pbkdf2HmacSha1.h +++ b/CPP/7zip/Crypto/Pbkdf2HmacSha1.h @@ -1,22 +1,22 @@ -// Pbkdf2HmacSha1.h -// Password-Based Key Derivation Function (RFC 2898, PKCS #5) based on HMAC-SHA-1 - -#ifndef __CRYPTO_PBKDF2_HMAC_SHA1_H -#define __CRYPTO_PBKDF2_HMAC_SHA1_H - -#include - -#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); - -void Pbkdf2Hmac32(const Byte *pwd, size_t pwdSize, const UInt32 *salt, size_t saltSize, - UInt32 numIterations, UInt32 *key, size_t keySize); - -}} - -#endif +// Pbkdf2HmacSha1.h +// Password-Based Key Derivation Function (RFC 2898, PKCS #5) based on HMAC-SHA-1 + +#ifndef __CRYPTO_PBKDF2_HMAC_SHA1_H +#define __CRYPTO_PBKDF2_HMAC_SHA1_H + +#include + +#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); + +void Pbkdf2Hmac32(const Byte *pwd, size_t pwdSize, const UInt32 *salt, size_t saltSize, + UInt32 numIterations, UInt32 *key, size_t keySize); + +}} + +#endif diff --git a/CPP/7zip/Crypto/RandGen.cpp b/CPP/7zip/Crypto/RandGen.cpp index 791275f9c..f98878f5b 100644 --- a/CPP/7zip/Crypto/RandGen.cpp +++ b/CPP/7zip/Crypto/RandGen.cpp @@ -1,233 +1,233 @@ -// 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 - -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 -#include -#include -#include -#define USE_POSIX_TIME -#define USE_POSIX_TIME2 -#endif - -#ifdef USE_POSIX_TIME -#include -#ifdef USE_POSIX_TIME2 -#include -#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 _7ZIP_ST +#include "../../Windows/Synchronization.h" +#endif + + +#ifdef _WIN32 + +#ifdef _WIN64 +#define USE_STATIC_RtlGenRandom +#endif + +#ifdef USE_STATIC_RtlGenRandom + +#include + +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 +#include +#include +#include +#define USE_POSIX_TIME +#define USE_POSIX_TIME2 +#endif + +#ifdef USE_POSIX_TIME +#include +#ifdef USE_POSIX_TIME2 +#include +#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 diff --git a/CPP/7zip/Crypto/RandGen.h b/CPP/7zip/Crypto/RandGen.h index dc5a3386d..5122ec4b4 100644 --- a/CPP/7zip/Crypto/RandGen.h +++ b/CPP/7zip/Crypto/RandGen.h @@ -1,40 +1,40 @@ -// 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 -#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 __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 +#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 diff --git a/CPP/7zip/Crypto/Rar20Crypto.cpp b/CPP/7zip/Crypto/Rar20Crypto.cpp index a39075805..878dfc5ce 100644 --- a/CPP/7zip/Crypto/Rar20Crypto.cpp +++ b/CPP/7zip/Crypto/Rar20Crypto.cpp @@ -1,130 +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]; - memset(psw, 0, sizeof(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); -} - -STDMETHODIMP CDecoder::Init() -{ - return S_OK; -} - -static const UInt32 kBlockSize = 16; - -STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size) -{ - if (size == 0) - return 0; - if (size < kBlockSize) - return kBlockSize; - size -= kBlockSize; - UInt32 i; - for (i = 0; i <= size; i += kBlockSize) - DecryptBlock(data + i); - return i; -} - -}} +// 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]; + memset(psw, 0, sizeof(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); +} + +STDMETHODIMP CDecoder::Init() +{ + return S_OK; +} + +static const UInt32 kBlockSize = 16; + +STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size) +{ + if (size == 0) + return 0; + if (size < kBlockSize) + return kBlockSize; + 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 index 2f1d9f3ac..6d1d0f5d8 100644 --- a/CPP/7zip/Crypto/Rar20Crypto.h +++ b/CPP/7zip/Crypto/Rar20Crypto.h @@ -1,48 +1,48 @@ -// Crypto/Rar20Crypto.h - -#ifndef __CRYPTO_RAR20_CRYPTO_H -#define __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: - void EncryptBlock(Byte *buf) { CryptBlock(buf, true); } - void DecryptBlock(Byte *buf) { CryptBlock(buf, false); } - void SetPassword(const Byte *password, unsigned passwordLen); -}; - -class CDecoder: - public ICompressFilter, - public CMyUnknownImp, - public CData -{ -public: - MY_UNKNOWN_IMP - INTERFACE_ICompressFilter(;) -}; - -}} - -#endif +// Crypto/Rar20Crypto.h + +#ifndef __CRYPTO_RAR20_CRYPTO_H +#define __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: + void EncryptBlock(Byte *buf) { CryptBlock(buf, true); } + void DecryptBlock(Byte *buf) { CryptBlock(buf, false); } + void SetPassword(const Byte *password, unsigned passwordLen); +}; + +class CDecoder: + public ICompressFilter, + public CMyUnknownImp, + public CData +{ +public: + MY_UNKNOWN_IMP + INTERFACE_ICompressFilter(;) +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/Rar5Aes.cpp b/CPP/7zip/Crypto/Rar5Aes.cpp index c33845845..005fa6bcb 100644 --- a/CPP/7zip/Crypto/Rar5Aes.cpp +++ b/CPP/7zip/Crypto/Rar5Aes.cpp @@ -1,257 +1,257 @@ -// Crypto/Rar5Aes.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#ifndef _7ZIP_ST -#include "../../Windows/Synchronization.h" -#endif - -#include "Rar5Aes.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.CopyFrom(data, size); - } -} - - -STDMETHODIMP CDecoder::Init() -{ - CalcKey_and_CheckPassword(); - RINOK(SetKey(_key, kAesKeySize)); - RINOK(SetInitVector(_iv, AES_BLOCK_SIZE)); - return CAesCbcCoder::Init(); -} - - -UInt32 CDecoder::Hmac_Convert_Crc32(UInt32 crc) const -{ - NSha256::CHmac ctx; - ctx.SetKey(_hashKey, NSha256::kDigestSize); - Byte v[4]; - SetUi32(v, crc); - ctx.Update(v, 4); - Byte h[NSha256::kDigestSize]; - ctx.Final(h); - crc = 0; - for (unsigned i = 0; i < NSha256::kDigestSize; i++) - crc ^= (UInt32)h[i] << ((i & 3) * 8); - return crc; -}; - - -void CDecoder::Hmac_Convert_32Bytes(Byte *data) const -{ - NSha256::CHmac ctx; - ctx.SetKey(_hashKey, NSha256::kDigestSize); - ctx.Update(data, NSha256::kDigestSize); - ctx.Final(data); -}; - - -static CKey g_Key; - -#ifndef _7ZIP_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 - - NSha256::CHmac baseCtx; - baseCtx.SetKey(_password, _password.Size()); - - NSha256::CHmac ctx = baseCtx; - ctx.Update(_salt, sizeof(_salt)); - - Byte u[NSha256::kDigestSize]; - 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; -} - -}} +// Crypto/Rar5Aes.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#ifndef _7ZIP_ST +#include "../../Windows/Synchronization.h" +#endif + +#include "Rar5Aes.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.CopyFrom(data, size); + } +} + + +STDMETHODIMP CDecoder::Init() +{ + CalcKey_and_CheckPassword(); + RINOK(SetKey(_key, kAesKeySize)); + RINOK(SetInitVector(_iv, AES_BLOCK_SIZE)); + return CAesCbcCoder::Init(); +} + + +UInt32 CDecoder::Hmac_Convert_Crc32(UInt32 crc) const +{ + NSha256::CHmac ctx; + ctx.SetKey(_hashKey, NSha256::kDigestSize); + Byte v[4]; + SetUi32(v, crc); + ctx.Update(v, 4); + Byte h[NSha256::kDigestSize]; + ctx.Final(h); + crc = 0; + for (unsigned i = 0; i < NSha256::kDigestSize; i++) + crc ^= (UInt32)h[i] << ((i & 3) * 8); + return crc; +}; + + +void CDecoder::Hmac_Convert_32Bytes(Byte *data) const +{ + NSha256::CHmac ctx; + ctx.SetKey(_hashKey, NSha256::kDigestSize); + ctx.Update(data, NSha256::kDigestSize); + ctx.Final(data); +}; + + +static CKey g_Key; + +#ifndef _7ZIP_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 + + NSha256::CHmac baseCtx; + baseCtx.SetKey(_password, _password.Size()); + + NSha256::CHmac ctx = baseCtx; + ctx.Update(_salt, sizeof(_salt)); + + Byte u[NSha256::kDigestSize]; + 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 index 01ab833d8..c69b24e48 100644 --- a/CPP/7zip/Crypto/Rar5Aes.h +++ b/CPP/7zip/Crypto/Rar5Aes.h @@ -1,84 +1,84 @@ -// Crypto/Rar5Aes.h - -#ifndef __CRYPTO_RAR5_AES_H -#define __CRYPTO_RAR5_AES_H - -#include "../../../C/Aes.h" - -#include "../../Common/MyBuffer.h" - -#include "HmacSha256.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(); -}; - - -class CDecoder: - 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(); - - STDMETHOD(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 +// Crypto/Rar5Aes.h + +#ifndef __CRYPTO_RAR5_AES_H +#define __CRYPTO_RAR5_AES_H + +#include "../../../C/Aes.h" + +#include "../../Common/MyBuffer.h" + +#include "HmacSha256.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(); +}; + + +class CDecoder: + 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(); + + STDMETHOD(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 index bbf138573..98e9f62de 100644 --- a/CPP/7zip/Crypto/RarAes.cpp +++ b/CPP/7zip/Crypto/RarAes.cpp @@ -1,133 +1,133 @@ -// Crypto/RarAes.cpp - -#include "StdAfx.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.CopyFrom(data, (size_t)size); -} - -STDMETHODIMP CDecoder::Init() -{ - CalcKey(); - RINOK(SetKey(_key, kAesKeySize)); - RINOK(SetInitVector(_iv, AES_BLOCK_SIZE)); - return CAesCbcCoder::Init(); -} - -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; - } - - NSha1::CContext sha; - sha.Init(); - - Byte digest[NSha1::kDigestSize]; - // rar reverts hash for sha. - const UInt32 kNumRounds = ((UInt32)1 << 18); - UInt32 i; - for (i = 0; i < kNumRounds; i++) - { - sha.UpdateRar(buf, rawSize /* , _rar350Mode */); - Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) }; - sha.UpdateRar(pswNum, 3 /* , _rar350Mode */); - if (i % (kNumRounds / 16) == 0) - { - NSha1::CContext shaTemp = sha; - 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; -} - -}} +// Crypto/RarAes.cpp + +#include "StdAfx.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.CopyFrom(data, (size_t)size); +} + +STDMETHODIMP CDecoder::Init() +{ + CalcKey(); + RINOK(SetKey(_key, kAesKeySize)); + RINOK(SetInitVector(_iv, AES_BLOCK_SIZE)); + return CAesCbcCoder::Init(); +} + +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; + } + + NSha1::CContext sha; + sha.Init(); + + Byte digest[NSha1::kDigestSize]; + // rar reverts hash for sha. + const UInt32 kNumRounds = ((UInt32)1 << 18); + UInt32 i; + for (i = 0; i < kNumRounds; i++) + { + sha.UpdateRar(buf, rawSize /* , _rar350Mode */); + Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) }; + sha.UpdateRar(pswNum, 3 /* , _rar350Mode */); + if (i % (kNumRounds / 16) == 0) + { + NSha1::CContext shaTemp = sha; + 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 index 0f5bd4194..645da1af2 100644 --- a/CPP/7zip/Crypto/RarAes.h +++ b/CPP/7zip/Crypto/RarAes.h @@ -1,52 +1,52 @@ -// Crypto/RarAes.h - -#ifndef __CRYPTO_RAR_AES_H -#define __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: - public CAesCbcDecoder - // public ICompressSetDecoderProperties2, - // public ICryptoSetPassword -{ - Byte _salt[8]; - bool _thereIsSalt; - bool _needCalc; - // bool _rar350Mode; - - CByteBuffer _password; - - Byte _key[kAesKeySize]; - Byte _iv[AES_BLOCK_SIZE]; - - void CalcKey(); -public: - /* - MY_UNKNOWN_IMP1( - ICryptoSetPassword - // ICompressSetDecoderProperties2 - */ - STDMETHOD(Init)(); - - void SetPassword(const Byte *data, unsigned size); - HRESULT SetDecoderProperties2(const Byte *data, UInt32 size); - - CDecoder(); - // void SetRar350Mode(bool rar350Mode) { _rar350Mode = rar350Mode; } -}; - -}} - -#endif +// Crypto/RarAes.h + +#ifndef __CRYPTO_RAR_AES_H +#define __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: + public CAesCbcDecoder + // public ICompressSetDecoderProperties2, + // public ICryptoSetPassword +{ + Byte _salt[8]; + bool _thereIsSalt; + bool _needCalc; + // bool _rar350Mode; + + CByteBuffer _password; + + Byte _key[kAesKeySize]; + Byte _iv[AES_BLOCK_SIZE]; + + void CalcKey(); +public: + /* + MY_UNKNOWN_IMP1( + ICryptoSetPassword + // ICompressSetDecoderProperties2 + */ + STDMETHOD(Init)(); + + void SetPassword(const Byte *data, unsigned size); + HRESULT SetDecoderProperties2(const Byte *data, UInt32 size); + + CDecoder(); + // void SetRar350Mode(bool rar350Mode) { _rar350Mode = rar350Mode; } +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/Sha1Cls.h b/CPP/7zip/Crypto/Sha1Cls.h index 5a8df8fd3..71acbdec5 100644 --- a/CPP/7zip/Crypto/Sha1Cls.h +++ b/CPP/7zip/Crypto/Sha1Cls.h @@ -1,51 +1,51 @@ -// Crypto/Sha1.h - -#ifndef __CRYPTO_SHA1_H -#define __CRYPTO_SHA1_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 CContextBase -{ -protected: - CSha1 _s; - -public: - void Init() throw() { Sha1_Init(&_s); } - void GetBlockDigest(const UInt32 *blockData, UInt32 *destDigest) throw() { Sha1_GetBlockDigest(&_s, blockData, destDigest); } -}; - -class CContext: public CContextBase -{ -public: - void Update(const Byte *data, size_t size) throw() { Sha1_Update(&_s, data, size); } - void UpdateRar(Byte *data, size_t size /* , bool rar350Mode */) throw() { Sha1_Update_Rar(&_s, data, size /* , rar350Mode ? 1 : 0 */); } - void Final(Byte *digest) throw() { Sha1_Final(&_s, digest); } -}; - -class CContext32: public CContextBase -{ -public: - void Update(const UInt32 *data, size_t size) throw() { Sha1_32_Update(&_s, data, size); } - void Final(UInt32 *digest) throw() { Sha1_32_Final(&_s, digest); } - - /* PrepareBlock can be used only when size <= 13. size in Words - _buffer must be empty (_count & 0xF) == 0) */ - void PrepareBlock(UInt32 *block, unsigned size) const throw() - { - Sha1_32_PrepareBlock(&_s, block, size); - } -}; - -}} - -#endif +// Crypto/Sha1.h + +#ifndef __CRYPTO_SHA1_H +#define __CRYPTO_SHA1_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 CContextBase +{ +protected: + CSha1 _s; + +public: + void Init() throw() { Sha1_Init(&_s); } + void GetBlockDigest(const UInt32 *blockData, UInt32 *destDigest) throw() { Sha1_GetBlockDigest(&_s, blockData, destDigest); } +}; + +class CContext: public CContextBase +{ +public: + void Update(const Byte *data, size_t size) throw() { Sha1_Update(&_s, data, size); } + void UpdateRar(Byte *data, size_t size /* , bool rar350Mode */) throw() { Sha1_Update_Rar(&_s, data, size /* , rar350Mode ? 1 : 0 */); } + void Final(Byte *digest) throw() { Sha1_Final(&_s, digest); } +}; + +class CContext32: public CContextBase +{ +public: + void Update(const UInt32 *data, size_t size) throw() { Sha1_32_Update(&_s, data, size); } + void Final(UInt32 *digest) throw() { Sha1_32_Final(&_s, digest); } + + /* PrepareBlock can be used only when size <= 13. size in Words + _buffer must be empty (_count & 0xF) == 0) */ + void PrepareBlock(UInt32 *block, unsigned size) const throw() + { + Sha1_32_PrepareBlock(&_s, block, size); + } +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/StdAfx.h b/CPP/7zip/Crypto/StdAfx.h index 42a088f12..1cbd7feae 100644 --- a/CPP/7zip/Crypto/StdAfx.h +++ b/CPP/7zip/Crypto/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Crypto/WzAes.cpp b/CPP/7zip/Crypto/WzAes.cpp index 1c7919574..d415ab846 100644 --- a/CPP/7zip/Crypto/WzAes.cpp +++ b/CPP/7zip/Crypto/WzAes.cpp @@ -1,235 +1,235 @@ -// 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" - -// define it if you don't want to use speed-optimized version of NSha1::Pbkdf2Hmac -// #define _NO_WZAES_OPTIMIZATIONS - -namespace NCrypto { -namespace NWzAes { - -const unsigned kAesKeySizeMax = 32; - -static const UInt32 kNumKeyGenIterations = 1000; - -STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size) -{ - if (size > kPasswordSizeMax) - return E_INVALIDARG; - _key.Password.CopyFrom(data, (size_t)size); - return S_OK; -} - -void CBaseCoder::Init2() -{ - const unsigned dkSizeMax32 = (2 * kAesKeySizeMax + kPwdVerifSize + 3) / 4; - Byte dk[dkSizeMax32 * 4]; - - const unsigned keySize = _key.GetKeySize(); - const unsigned dkSize = 2 * keySize + kPwdVerifSize; - - // for (unsigned ii = 0; ii < 1000; ii++) - { - #ifdef _NO_WZAES_OPTIMIZATIONS - - NSha1::Pbkdf2Hmac( - _key.Password, _key.Password.Size(), - _key.Salt, _key.GetSaltSize(), - kNumKeyGenIterations, - dk, dkSize); - - #else - - UInt32 dk32[dkSizeMax32]; - const unsigned dkSize32 = (dkSize + 3) / 4; - UInt32 salt[kSaltSizeMax / 4]; - unsigned numSaltWords = _key.GetNumSaltWords(); - - for (unsigned i = 0; i < numSaltWords; i++) - { - const Byte *src = _key.Salt + i * 4; - salt[i] = GetBe32(src); - } - - NSha1::Pbkdf2Hmac32( - _key.Password, _key.Password.Size(), - salt, numSaltWords, - kNumKeyGenIterations, - dk32, dkSize32); - - /* - for (unsigned j = 0; j < dkSize; j++) - dk[j] = (Byte)(dk32[j / 4] >> (24 - 8 * (j & 3))); - */ - for (unsigned j = 0; j < dkSize32; j++) - SetBe32(dk + j * 4, dk32[j]); - - #endif - } - - _hmac.SetKey(dk + keySize, keySize); - memcpy(_key.PwdVerifComputed, dk + 2 * keySize, kPwdVerifSize); - - Aes_SetKey_Enc(_aes.aes + _aes.offset + 8, dk, keySize); - AesCtr2_Init(&_aes); -} - -STDMETHODIMP 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) -{ - Byte mac[kMacSize]; - _hmac.Final(mac, kMacSize); - return WriteStream(outStream, mac, kMacSize); -} - -/* -STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) -{ - if (size != 1) - return E_INVALIDARG; - _key.Init(); - return SetKeyMode(data[0]) ? S_OK : E_INVALIDARG; -} -*/ - -HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream) -{ - unsigned saltSize = _key.GetSaltSize(); - 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; - Byte mac1[kMacSize]; - RINOK(ReadStream_FAIL(inStream, mac1, kMacSize)); - Byte mac2[kMacSize]; - _hmac.Final(mac2, kMacSize); - isOK = CompareArrays(mac1, mac2, kMacSize); - return S_OK; -} - -CAesCtr2::CAesCtr2() -{ - offset = ((0 - (unsigned)(ptrdiff_t)aes) & 0xF) / sizeof(UInt32); -} - -void AesCtr2_Init(CAesCtr2 *p) -{ - UInt32 *ctr = p->aes + p->offset + 4; - unsigned i; - for (i = 0; i < 4; i++) - ctr[i] = 0; - p->pos = AES_BLOCK_SIZE; -} - -/* (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 + p->offset; - if (size == 0) - return; - - if (pos != AES_BLOCK_SIZE) - { - const Byte *buf = (const Byte *)buf32; - do - *data++ ^= buf[pos++]; - while (--size != 0 && pos != AES_BLOCK_SIZE); - } - - if (size >= 16) - { - SizeT size2 = size >> 4; - g_AesCtr_Code(buf32 + 4, data, size2); - size2 <<= 4; - data += size2; - size -= size2; - pos = AES_BLOCK_SIZE; - } - - if (size != 0) - { - unsigned j; - const Byte *buf; - for (j = 0; j < 4; j++) - buf32[j] = 0; - g_AesCtr_Code(buf32 + 4, (Byte *)buf32, 1); - buf = (const Byte *)buf32; - pos = 0; - do - *data++ ^= buf[pos++]; - while (--size != 0); - } - - p->pos = pos; -} - -/* (size != 16 * N) is allowed only for last Filter() call */ - -STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size) -{ - AesCtr2_Code(&_aes, data, size); - _hmac.Update(data, size); - return size; -} - -STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size) -{ - _hmac.Update(data, size); - AesCtr2_Code(&_aes, data, size); - return size; -} - -}} +// 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" + +// define it if you don't want to use speed-optimized version of NSha1::Pbkdf2Hmac +// #define _NO_WZAES_OPTIMIZATIONS + +namespace NCrypto { +namespace NWzAes { + +const unsigned kAesKeySizeMax = 32; + +static const UInt32 kNumKeyGenIterations = 1000; + +STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size) +{ + if (size > kPasswordSizeMax) + return E_INVALIDARG; + _key.Password.CopyFrom(data, (size_t)size); + return S_OK; +} + +void CBaseCoder::Init2() +{ + const unsigned dkSizeMax32 = (2 * kAesKeySizeMax + kPwdVerifSize + 3) / 4; + Byte dk[dkSizeMax32 * 4]; + + const unsigned keySize = _key.GetKeySize(); + const unsigned dkSize = 2 * keySize + kPwdVerifSize; + + // for (unsigned ii = 0; ii < 1000; ii++) + { + #ifdef _NO_WZAES_OPTIMIZATIONS + + NSha1::Pbkdf2Hmac( + _key.Password, _key.Password.Size(), + _key.Salt, _key.GetSaltSize(), + kNumKeyGenIterations, + dk, dkSize); + + #else + + UInt32 dk32[dkSizeMax32]; + const unsigned dkSize32 = (dkSize + 3) / 4; + UInt32 salt[kSaltSizeMax / 4]; + unsigned numSaltWords = _key.GetNumSaltWords(); + + for (unsigned i = 0; i < numSaltWords; i++) + { + const Byte *src = _key.Salt + i * 4; + salt[i] = GetBe32(src); + } + + NSha1::Pbkdf2Hmac32( + _key.Password, _key.Password.Size(), + salt, numSaltWords, + kNumKeyGenIterations, + dk32, dkSize32); + + /* + for (unsigned j = 0; j < dkSize; j++) + dk[j] = (Byte)(dk32[j / 4] >> (24 - 8 * (j & 3))); + */ + for (unsigned j = 0; j < dkSize32; j++) + SetBe32(dk + j * 4, dk32[j]); + + #endif + } + + _hmac.SetKey(dk + keySize, keySize); + memcpy(_key.PwdVerifComputed, dk + 2 * keySize, kPwdVerifSize); + + Aes_SetKey_Enc(_aes.aes + _aes.offset + 8, dk, keySize); + AesCtr2_Init(&_aes); +} + +STDMETHODIMP 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) +{ + Byte mac[kMacSize]; + _hmac.Final(mac, kMacSize); + return WriteStream(outStream, mac, kMacSize); +} + +/* +STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + if (size != 1) + return E_INVALIDARG; + _key.Init(); + return SetKeyMode(data[0]) ? S_OK : E_INVALIDARG; +} +*/ + +HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream) +{ + unsigned saltSize = _key.GetSaltSize(); + 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; + Byte mac1[kMacSize]; + RINOK(ReadStream_FAIL(inStream, mac1, kMacSize)); + Byte mac2[kMacSize]; + _hmac.Final(mac2, kMacSize); + isOK = CompareArrays(mac1, mac2, kMacSize); + return S_OK; +} + +CAesCtr2::CAesCtr2() +{ + offset = ((0 - (unsigned)(ptrdiff_t)aes) & 0xF) / sizeof(UInt32); +} + +void AesCtr2_Init(CAesCtr2 *p) +{ + UInt32 *ctr = p->aes + p->offset + 4; + unsigned i; + for (i = 0; i < 4; i++) + ctr[i] = 0; + p->pos = AES_BLOCK_SIZE; +} + +/* (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 + p->offset; + if (size == 0) + return; + + if (pos != AES_BLOCK_SIZE) + { + const Byte *buf = (const Byte *)buf32; + do + *data++ ^= buf[pos++]; + while (--size != 0 && pos != AES_BLOCK_SIZE); + } + + if (size >= 16) + { + SizeT size2 = size >> 4; + g_AesCtr_Code(buf32 + 4, data, size2); + size2 <<= 4; + data += size2; + size -= size2; + pos = AES_BLOCK_SIZE; + } + + if (size != 0) + { + unsigned j; + const Byte *buf; + for (j = 0; j < 4; j++) + buf32[j] = 0; + g_AesCtr_Code(buf32 + 4, (Byte *)buf32, 1); + buf = (const Byte *)buf32; + pos = 0; + do + *data++ ^= buf[pos++]; + while (--size != 0); + } + + p->pos = pos; +} + +/* (size != 16 * N) is allowed only for last Filter() call */ + +STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size) +{ + AesCtr2_Code(&_aes, data, size); + _hmac.Update(data, size); + return size; +} + +STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size) +{ + _hmac.Update(data, size); + AesCtr2_Code(&_aes, data, size); + return size; +} + +}} diff --git a/CPP/7zip/Crypto/WzAes.h b/CPP/7zip/Crypto/WzAes.h index d1bbfa5db..3b22bc167 100644 --- a/CPP/7zip/Crypto/WzAes.h +++ b/CPP/7zip/Crypto/WzAes.h @@ -1,137 +1,137 @@ -// 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 __CRYPTO_WZ_AES_H -#define __CRYPTO_WZ_AES_H - -#include "../../../C/Aes.h" - -#include "../../Common/MyBuffer.h" -#include "../../Common/MyCom.h" - -#include "../ICoder.h" -#include "../IPassword.h" - -#include "HmacSha1.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) {} -}; - -struct CAesCtr2 -{ - unsigned pos; - unsigned offset; - UInt32 aes[4 + AES_NUM_IVMRK_WORDS + 3]; - CAesCtr2(); -}; - -void AesCtr2_Init(CAesCtr2 *p); -void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size); - -class CBaseCoder: - public ICompressFilter, - public ICryptoSetPassword, - public CMyUnknownImp -{ -protected: - CKeyInfo _key; - NSha1::CHmac _hmac; - CAesCtr2 _aes; - - void Init2(); -public: - MY_UNKNOWN_IMP1(ICryptoSetPassword) - - STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size); - - STDMETHOD(Init)(); - - 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: - public CBaseCoder -{ -public: - STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); - HRESULT WriteHeader(ISequentialOutStream *outStream); - HRESULT WriteFooter(ISequentialOutStream *outStream); -}; - -class CDecoder: - public CBaseCoder - // public ICompressSetDecoderProperties2 -{ - Byte _pwdVerifFromArchive[kPwdVerifSize]; -public: - // ICompressSetDecoderProperties2 - // STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); - STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); - HRESULT ReadHeader(ISequentialInStream *inStream); - bool Init_and_CheckPassword(); - HRESULT CheckMac(ISequentialInStream *inStream, bool &isOK); -}; - -}} - -#endif +// 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 __CRYPTO_WZ_AES_H +#define __CRYPTO_WZ_AES_H + +#include "../../../C/Aes.h" + +#include "../../Common/MyBuffer.h" +#include "../../Common/MyCom.h" + +#include "../ICoder.h" +#include "../IPassword.h" + +#include "HmacSha1.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) {} +}; + +struct CAesCtr2 +{ + unsigned pos; + unsigned offset; + UInt32 aes[4 + AES_NUM_IVMRK_WORDS + 3]; + CAesCtr2(); +}; + +void AesCtr2_Init(CAesCtr2 *p); +void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size); + +class CBaseCoder: + public ICompressFilter, + public ICryptoSetPassword, + public CMyUnknownImp +{ +protected: + CKeyInfo _key; + NSha1::CHmac _hmac; + CAesCtr2 _aes; + + void Init2(); +public: + MY_UNKNOWN_IMP1(ICryptoSetPassword) + + STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size); + + STDMETHOD(Init)(); + + 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: + public CBaseCoder +{ +public: + STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); + HRESULT WriteHeader(ISequentialOutStream *outStream); + HRESULT WriteFooter(ISequentialOutStream *outStream); +}; + +class CDecoder: + public CBaseCoder + // public ICompressSetDecoderProperties2 +{ + Byte _pwdVerifFromArchive[kPwdVerifSize]; +public: + // ICompressSetDecoderProperties2 + // STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); + STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); + 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 index 6f7677135..8610297a6 100644 --- a/CPP/7zip/Crypto/ZipCrypto.cpp +++ b/CPP/7zip/Crypto/ZipCrypto.cpp @@ -1,114 +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)) - -STDMETHODIMP 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; -} - -STDMETHODIMP 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); -} - -STDMETHODIMP_(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); -} - -STDMETHODIMP_(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; -} - -}} +// 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)) + +STDMETHODIMP 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; +} + +STDMETHODIMP 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); +} + +STDMETHODIMP_(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); +} + +STDMETHODIMP_(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 index ddc17d254..acc0b0310 100644 --- a/CPP/7zip/Crypto/ZipCrypto.h +++ b/CPP/7zip/Crypto/ZipCrypto.h @@ -1,75 +1,75 @@ -// Crypto/ZipCrypto.h - -#ifndef __CRYPTO_ZIP_CRYPTO_H -#define __CRYPTO_ZIP_CRYPTO_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" -#include "../IPassword.h" - -namespace NCrypto { -namespace NZip { - -const unsigned kHeaderSize = 12; - -/* 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 -{ -protected: - UInt32 Key0; - UInt32 Key1; - UInt32 Key2; - - UInt32 KeyMem0; - UInt32 KeyMem1; - UInt32 KeyMem2; - - void RestoreKeys() - { - Key0 = KeyMem0; - Key1 = KeyMem1; - Key2 = KeyMem2; - } - -public: - MY_UNKNOWN_IMP1(ICryptoSetPassword) - STDMETHOD(Init)(); - STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size); - - virtual ~CCipher() {} -}; - -class CEncoder: public CCipher -{ -public: - STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); - HRESULT WriteHeader_Check16(ISequentialOutStream *outStream, UInt16 crc); -}; - -class CDecoder: public CCipher -{ -public: - Byte _header[kHeaderSize]; - STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); - HRESULT ReadHeader(ISequentialInStream *inStream); - void Init_BeforeDecode(); -}; - -}} - -#endif +// Crypto/ZipCrypto.h + +#ifndef __CRYPTO_ZIP_CRYPTO_H +#define __CRYPTO_ZIP_CRYPTO_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" +#include "../IPassword.h" + +namespace NCrypto { +namespace NZip { + +const unsigned kHeaderSize = 12; + +/* 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 +{ +protected: + UInt32 Key0; + UInt32 Key1; + UInt32 Key2; + + UInt32 KeyMem0; + UInt32 KeyMem1; + UInt32 KeyMem2; + + void RestoreKeys() + { + Key0 = KeyMem0; + Key1 = KeyMem1; + Key2 = KeyMem2; + } + +public: + MY_UNKNOWN_IMP1(ICryptoSetPassword) + STDMETHOD(Init)(); + STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size); + + virtual ~CCipher() {} +}; + +class CEncoder: public CCipher +{ +public: + STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); + HRESULT WriteHeader_Check16(ISequentialOutStream *outStream, UInt16 crc); +}; + +class CDecoder: public CCipher +{ +public: + Byte _header[kHeaderSize]; + STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); + HRESULT ReadHeader(ISequentialInStream *inStream); + void Init_BeforeDecode(); +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/ZipStrong.cpp b/CPP/7zip/Crypto/ZipStrong.cpp index 7bfb07412..22a905cb9 100644 --- a/CPP/7zip/Crypto/ZipStrong.cpp +++ b/CPP/7zip/Crypto/ZipStrong.cpp @@ -1,240 +1,240 @@ -// 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) -{ - Byte buf[64]; - memset(buf, c, 64); - for (unsigned i = 0; i < NSha1::kDigestSize; i++) - buf[i] ^= digest[i]; - NSha1::CContext sha; - sha.Init(); - sha.Update(buf, 64); - sha.Final(dest); -} - -static void DeriveKey(NSha1::CContext &sha, Byte *key) -{ - Byte digest[NSha1::kDigestSize]; - sha.Final(digest); - Byte temp[NSha1::kDigestSize * 2]; - DeriveKey2(digest, 0x36, temp); - DeriveKey2(digest, 0x5C, temp + NSha1::kDigestSize); - memcpy(key, temp, 32); -} - -void CKeyInfo::SetPassword(const Byte *data, UInt32 size) -{ - NSha1::CContext sha; - sha.Init(); - sha.Update(data, size); - DeriveKey(sha, MasterKey); -} - -STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size) -{ - _key.SetPassword(data, size); - return S_OK; -} - -STDMETHODIMP CBaseCoder::Init() -{ - return S_OK; -} - -HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize) -{ - Byte temp[4]; - RINOK(ReadStream_FALSE(inStream, temp, 2)); - _ivSize = GetUi16(temp); - if (_ivSize == 0) - { - 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; - UInt16 format = GetUi16(p); - if (format != 3) - return E_NOTIMPL; - UInt16 algId = GetUi16(p + 2); - if (algId < kAES128) - return E_NOTIMPL; - algId -= kAES128; - if (algId > 2) - return E_NOTIMPL; - UInt16 bitLen = GetUi16(p + 4); - UInt16 flags = GetUi16(p + 6); - if (algId * 64 + 128 != bitLen) - return E_NOTIMPL; - _key.KeySize = 16 + algId * 8; - 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 = p2 - p; - if ((validSize & 0xF) != 0 || validOffset + validSize != _remSize) - return E_NOTIMPL; - - { - RINOK(SetKey(_key.MasterKey, _key.KeySize)); - RINOK(SetInitVector(_iv, 16)); - RINOK(Init()); - Filter(p, rdSize); - - rdSize -= kPadSize; - for (unsigned i = 0; i < kPadSize; i++) - if (p[(size_t)rdSize + i] != kPadSize) - return S_OK; // passwOK = false; - } - - Byte fileKey[32]; - NSha1::CContext sha; - sha.Init(); - sha.Update(_iv, _ivSize); - sha.Update(p, rdSize); - DeriveKey(sha, fileKey); - - RINOK(SetKey(fileKey, _key.KeySize)); - RINOK(SetInitVector(_iv, 16)); - Init(); - - 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; -} - -}} +// 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) +{ + Byte buf[64]; + memset(buf, c, 64); + for (unsigned i = 0; i < NSha1::kDigestSize; i++) + buf[i] ^= digest[i]; + NSha1::CContext sha; + sha.Init(); + sha.Update(buf, 64); + sha.Final(dest); +} + +static void DeriveKey(NSha1::CContext &sha, Byte *key) +{ + Byte digest[NSha1::kDigestSize]; + sha.Final(digest); + Byte temp[NSha1::kDigestSize * 2]; + DeriveKey2(digest, 0x36, temp); + DeriveKey2(digest, 0x5C, temp + NSha1::kDigestSize); + memcpy(key, temp, 32); +} + +void CKeyInfo::SetPassword(const Byte *data, UInt32 size) +{ + NSha1::CContext sha; + sha.Init(); + sha.Update(data, size); + DeriveKey(sha, MasterKey); +} + +STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size) +{ + _key.SetPassword(data, size); + return S_OK; +} + +STDMETHODIMP CBaseCoder::Init() +{ + return S_OK; +} + +HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize) +{ + Byte temp[4]; + RINOK(ReadStream_FALSE(inStream, temp, 2)); + _ivSize = GetUi16(temp); + if (_ivSize == 0) + { + 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; + UInt16 format = GetUi16(p); + if (format != 3) + return E_NOTIMPL; + UInt16 algId = GetUi16(p + 2); + if (algId < kAES128) + return E_NOTIMPL; + algId -= kAES128; + if (algId > 2) + return E_NOTIMPL; + UInt16 bitLen = GetUi16(p + 4); + UInt16 flags = GetUi16(p + 6); + if (algId * 64 + 128 != bitLen) + return E_NOTIMPL; + _key.KeySize = 16 + algId * 8; + 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 = p2 - p; + if ((validSize & 0xF) != 0 || validOffset + validSize != _remSize) + return E_NOTIMPL; + + { + RINOK(SetKey(_key.MasterKey, _key.KeySize)); + RINOK(SetInitVector(_iv, 16)); + RINOK(Init()); + Filter(p, rdSize); + + rdSize -= kPadSize; + for (unsigned i = 0; i < kPadSize; i++) + if (p[(size_t)rdSize + i] != kPadSize) + return S_OK; // passwOK = false; + } + + Byte fileKey[32]; + NSha1::CContext sha; + sha.Init(); + sha.Update(_iv, _ivSize); + sha.Update(p, rdSize); + DeriveKey(sha, fileKey); + + RINOK(SetKey(fileKey, _key.KeySize)); + RINOK(SetInitVector(_iv, 16)); + Init(); + + 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 index 39c18b1a5..03a0f2c7d 100644 --- a/CPP/7zip/Crypto/ZipStrong.h +++ b/CPP/7zip/Crypto/ZipStrong.h @@ -1,65 +1,65 @@ -// Crypto/ZipStrong.h - -#ifndef __CRYPTO_ZIP_STRONG_H -#define __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); -}; - -class CBaseCoder: - public CAesCbcDecoder, - public ICryptoSetPassword -{ -protected: - CKeyInfo _key; - CAlignedBuffer _bufAligned; -public: - STDMETHOD(Init)(); - STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size); -}; - -const unsigned kAesPadAllign = AES_BLOCK_SIZE; - -class CDecoder: public CBaseCoder -{ - UInt32 _ivSize; - Byte _iv[16]; - UInt32 _remSize; -public: - MY_UNKNOWN_IMP1(ICryptoSetPassword) - HRESULT ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize); - HRESULT 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)); - } -}; - -}} - -#endif +// Crypto/ZipStrong.h + +#ifndef __CRYPTO_ZIP_STRONG_H +#define __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); +}; + +class CBaseCoder: + public CAesCbcDecoder, + public ICryptoSetPassword +{ +protected: + CKeyInfo _key; + CAlignedBuffer _bufAligned; +public: + STDMETHOD(Init)(); + STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size); +}; + +const unsigned kAesPadAllign = AES_BLOCK_SIZE; + +class CDecoder: public CBaseCoder +{ + UInt32 _ivSize; + Byte _iv[16]; + UInt32 _remSize; +public: + MY_UNKNOWN_IMP1(ICryptoSetPassword) + HRESULT ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize); + HRESULT 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)); + } +}; + +}} + +#endif diff --git a/CPP/7zip/GuiCommon.rc b/CPP/7zip/GuiCommon.rc index 565ee702e..b67409b92 100644 --- a/CPP/7zip/GuiCommon.rc +++ b/CPP/7zip/GuiCommon.rc @@ -1,84 +1,84 @@ -#include - -// #include -// #include - -// for Windows CE: -#include - - -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 + +// #include +// #include + +// for Windows CE: +#include + + +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 f95349423..b703ac780 100644 --- a/CPP/7zip/Guid.txt +++ b/CPP/7zip/Guid.txt @@ -1,225 +1,225 @@ -{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 - 0E zstd - 0F lz4 - 10 lz5 - 11 liz - - C5 Lzip - 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 + + 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 + 0E zstd + 0F lz4 + 10 lz5 + 11 liz + + C5 Lzip + 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 b2775eada..1138dbca6 100644 --- a/CPP/7zip/ICoder.h +++ b/CPP/7zip/ICoder.h @@ -1,415 +1,415 @@ -// 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 - - /* zstd props */ - kStrategy, // VT_UI4 1=ZSTD_fast, 2=ZSTD_dfast, 3=ZSTD_greedy, 4=ZSTD_lazy, 5=ZSTD_lazy2, 6=ZSTD_btlazy2, 7=ZSTD_btopt, 8=ZSTD_btultra - kFast, // VT_UI4 The minimum fast is 1 and the maximum is 64 (default: unused) - kLong, // VT_UI4 The minimum long is 10 (1KiB) and the maximum is 30 (1GiB) on x32 and 31 (2GiB) on x64 - kWindowLog, // VT_UI4 The minimum long is 10 (1KiB) and the maximum is 30 (1GiB) on x32 and 31 (2GiB) on x64 - kHashLog, // VT_UI4 The minimum hlog is 6 (64 B) and the maximum is 26 (128 MiB). - kChainLog, // VT_UI4 The minimum clog is 6 (64 B) and the maximum is 28 (256 MiB) - kSearchLog, // VT_UI4 The minimum slog is 1 and the maximum is 26 - kMinMatch, // VT_UI4 The minimum slen is 3 and the maximum is 7. - kTargetLen, // VT_UI4 The minimum tlen is 0 and the maximum is 999. - kOverlapLog, // VT_UI4 The minimum ovlog is 0 and the maximum is 9. (default: 6) - kLdmHashLog, // VT_UI4 The minimum ldmhlog is 6 and the maximum is 26 (default: 20). - kLdmSearchLength, // 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. - }; -} - -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 __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 + + /* zstd props */ + kStrategy, // VT_UI4 1=ZSTD_fast, 2=ZSTD_dfast, 3=ZSTD_greedy, 4=ZSTD_lazy, 5=ZSTD_lazy2, 6=ZSTD_btlazy2, 7=ZSTD_btopt, 8=ZSTD_btultra + kFast, // VT_UI4 The minimum fast is 1 and the maximum is 64 (default: unused) + kLong, // VT_UI4 The minimum long is 10 (1KiB) and the maximum is 30 (1GiB) on x32 and 31 (2GiB) on x64 + kWindowLog, // VT_UI4 The minimum long is 10 (1KiB) and the maximum is 30 (1GiB) on x32 and 31 (2GiB) on x64 + kHashLog, // VT_UI4 The minimum hlog is 6 (64 B) and the maximum is 26 (128 MiB). + kChainLog, // VT_UI4 The minimum clog is 6 (64 B) and the maximum is 28 (256 MiB) + kSearchLog, // VT_UI4 The minimum slog is 1 and the maximum is 26 + kMinMatch, // VT_UI4 The minimum slen is 3 and the maximum is 7. + kTargetLen, // VT_UI4 The minimum tlen is 0 and the maximum is 999. + kOverlapLog, // VT_UI4 The minimum ovlog is 0 and the maximum is 9. (default: 6) + kLdmHashLog, // VT_UI4 The minimum ldmhlog is 6 and the maximum is 26 (default: 20). + kLdmSearchLength, // 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. + }; +} + +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 diff --git a/CPP/7zip/IDecl.h b/CPP/7zip/IDecl.h index 2715d24d4..f2202e9bf 100644 --- a/CPP/7zip/IDecl.h +++ b/CPP/7zip/IDecl.h @@ -1,28 +1,28 @@ -// 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_Data2_ZS 0x20BB - -#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 __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_Data2_ZS 0x20BB + +#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 diff --git a/CPP/7zip/IPassword.h b/CPP/7zip/IPassword.h index e36600704..7ea45537e 100644 --- a/CPP/7zip/IPassword.h +++ b/CPP/7zip/IPassword.h @@ -1,23 +1,23 @@ -// 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 __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 diff --git a/CPP/7zip/IProgress.h b/CPP/7zip/IProgress.h index d54529ca8..fac951eca 100644 --- a/CPP/7zip/IProgress.h +++ b/CPP/7zip/IProgress.h @@ -1,19 +1,19 @@ -// 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 __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 diff --git a/CPP/7zip/IStream.h b/CPP/7zip/IStream.h index 436e91987..9a0bcbf3d 100644 --- a/CPP/7zip/IStream.h +++ b/CPP/7zip/IStream.h @@ -1,127 +1,127 @@ -// 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 __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 diff --git a/CPP/7zip/LzmaDec.mak b/CPP/7zip/LzmaDec.mak index 08dac72d7..1e07e2781 100644 --- a/CPP/7zip/LzmaDec.mak +++ b/CPP/7zip/LzmaDec.mak @@ -1,5 +1,5 @@ -!IF "$(PLATFORM)" == "x64" -CFLAGS = $(CFLAGS) -D_LZMA_DEC_OPT -ASM_OBJS = $(ASM_OBJS) \ - $O\LzmaDecOpt.obj -!ENDIF +!IF "$(PLATFORM)" == "x64" +CFLAGS = $(CFLAGS) -D_LZMA_DEC_OPT +ASM_OBJS = $(ASM_OBJS) \ + $O\LzmaDecOpt.obj +!ENDIF diff --git a/CPP/7zip/MyVersion.h b/CPP/7zip/MyVersion.h index 0d50f9426..8f52a1261 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 eddf8935c..fab66860a 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 126af6785..1822f402b 100644 --- a/CPP/7zip/PropID.h +++ b/CPP/7zip/PropID.h @@ -1,127 +1,127 @@ -// 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 __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 diff --git a/CPP/7zip/SubBuild.mak b/CPP/7zip/SubBuild.mak index 0c49d3b71..f86ce4361 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 index 730a9087e..1c2e33975 100644 --- a/CPP/7zip/UI/Agent/Agent.cpp +++ b/CPP/7zip/UI/Agent/Agent.cpp @@ -1,1885 +1,1885 @@ -// Agent.cpp - -#include "StdAfx.h" - -#include - -#include "../../../../C/Sort.h" - -#include "../../../Common/ComTry.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariantConv.h" - -#ifndef _7ZIP_ST -#include "../../../Windows/Synchronization.h" -#endif - -#include "../Common/ArchiveExtractCallback.h" -#include "../FileManager/RegistryUtils.h" - -#include "Agent.h" - -using namespace NWindows; - -CCodecs *g_CodecsObj; - -#ifdef EXTERNAL_CODECS - CExternalCodecs g_ExternalCodecs; - CCodecs::CReleaser g_CodecsReleaser; -#else - CMyComPtr g_CodecsRef; -#endif - -#ifndef _7ZIP_ST -static NSynchronization::CCriticalSection g_CriticalSection; -#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); -#else -#define MT_LOCK -#endif - -void FreeGlobalCodecs() -{ - MT_LOCK - - #ifdef EXTERNAL_CODECS - if (g_CodecsObj) - { - g_CodecsObj->CloseLibs(); - } - g_CodecsReleaser.Set(NULL); - g_CodecsObj = NULL; - g_ExternalCodecs.ClearAndRelease(); - #else - g_CodecsRef.Release(); - #endif -} - -HRESULT LoadGlobalCodecs() -{ - MT_LOCK - - if (g_CodecsObj) - return S_OK; - - g_CodecsObj = new CCodecs; - - #ifdef 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; - } - - #ifdef EXTERNAL_CODECS - RINOK(g_ExternalCodecs.Load()); - #endif - - return S_OK; -} - -STDMETHODIMP 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 >= 0) - LoadFolder(file.DirIndex); - if (_loadAltStreams && file.AltDirIndex >= 0) - LoadFolder(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); - } -} - -STDMETHODIMP 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; -} - -STDMETHODIMP 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[_proxy2->Dirs[proxyIndex].ArcIndex]; - len += file.NameLen + 1; - proxyIndex = (file.Parent < 0) ? 0 : _proxy2->Files[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[_proxy2->Dirs[proxyIndex].ArcIndex]; - p--; - *p = WCHAR_PATH_SEPARATOR; - p -= file.NameLen; - wmemcpy(p, file.Name, file.NameLen); - proxyIndex = (file.Parent < 0) ? 0 : _proxy2->Files[file.Parent].GetDirIndex(file.IsAltStream); - } - } - else - { - unsigned len = 0; - while (proxyIndex != _proxyDirIndex) - { - const CProxyDir *dir = &_proxy->Dirs[proxyIndex]; - len += dir->NameLen + 1; - proxyIndex = 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 = dir->ParentDir; - } - } -} - -UString CAgentFolder::GetFullPrefix(UInt32 index) const -{ - int foldIndex = _proxyDirIndex; - - if (_flatMode) - foldIndex = _items[index].DirIndex; - - if (_proxy2) - return _proxy2->Dirs[foldIndex].PathPrefix; - else - return _proxy->GetDirPath_as_Prefix(foldIndex); -} - -STDMETHODIMP_(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 = 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; -} - -STDMETHODIMP 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 >= 0) - 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(item.ArcIndex, propID, value)); - } - if (item.CrcIsDefined && value->vt == VT_EMPTY) - prop = item.Crc; - break; - } - default: - if (item.IsLeaf()) - return _agentSpec->GetArchive()->GetProperty(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; -} - -STDMETHODIMP 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; - } - } -} - -STDMETHODIMP CAgentFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len) -{ - *name = 0; - *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, int arcIndex1, int arcIndex2, PROPID propID) -{ - // if (propID == kpidSha1) - if (rawProps) - { - const void *p1, *p2; - UInt32 size1, size2; - UInt32 propType1, propType2; - HRESULT res1 = rawProps->GetRawProp(arcIndex1, propID, &p1, &size1, &propType1); - 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++) - { - Byte b1 = ((const Byte *)p1)[i]; - 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); -} - - -STDMETHODIMP_(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 = proxFolder1->ArcIndex; - } - else - arcIndex1 = dir1->SubFiles[realIndex1 - dir1->SubDirs.Size()]; - - if (realIndex2 < dir2->SubDirs.Size()) - { - proxFolder2 = &_proxy->Dirs[dir2->SubDirs[realIndex2]]; - arcIndex2 = 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 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 agentFolder = folderSpec; - folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec); - *resultFolder = agentFolder.Detach(); - return S_OK; -} - -STDMETHODIMP CAgentFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder) -{ - COM_TRY_BEGIN - if (_proxy2) - { - SET_realIndex_AND_dir_2 - unsigned arcIndex = dir->Items[realIndex]; - const CProxyFile2 &item = _proxy2->Files[arcIndex]; - if (!item.IsDir()) - return E_INVALIDARG; - return BindToFolder_Internal(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 -} - -STDMETHODIMP CAgentFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder) -{ - COM_TRY_BEGIN - if (_proxy2) - { - int index = _proxy2->FindItem(_proxyDirIndex, name, true); - if (index < 0) - return E_INVALIDARG; - return BindToFolder_Internal(_proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]].DirIndex, resultFolder); - } - int index = _proxy->FindSubDir(_proxyDirIndex, name); - if (index < 0) - return E_INVALIDARG; - return BindToFolder_Internal(index, resultFolder); - COM_TRY_END -} - - - -// ---------- IFolderAltStreams ---------- - -HRESULT CAgentFolder::BindToAltStreams_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder) -{ - *resultFolder = NULL; - if (!_proxy2) - return S_OK; - - /* - CMyComPtr 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 agentFolder = folderSpec; - folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec); - *resultFolder = agentFolder.Detach(); - return S_OK; -} - -STDMETHODIMP 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 - { - unsigned arcIndex = _proxy2->Dirs[_proxyDirIndex].ArcIndex; - const CProxyFile2 &item = _proxy2->Files[arcIndex]; - if (item.AltDirIndex < 0) - return S_OK; - altDirIndex = item.AltDirIndex; - // parentFolder = _parentFolder; - } - - CAgentFolder *folderSpec = new CAgentFolder; - CMyComPtr agentFolder = folderSpec; - folderSpec->Init(_proxy, _proxy2, altDirIndex, /* parentFolder, */ _agentSpec); - *resultFolder = agentFolder.Detach(); - return S_OK; - } - - SET_realIndex_AND_dir_2 - unsigned arcIndex = dir->Items[realIndex]; - const CProxyFile2 &item = _proxy2->Files[arcIndex]; - if (item.AltDirIndex < 0) - return S_OK; - return BindToAltStreams_Internal(item.AltDirIndex, resultFolder); - } - - COM_TRY_END -} - -STDMETHODIMP 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 >= 0) - if (CompareFileNames(file.Name, name) == 0) - return BindToAltStreams_Internal(file.AltDirIndex, resultFolder); - } - return E_INVALIDARG; - } - COM_TRY_END -} - -STDMETHODIMP 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 = _proxy2->Dirs[_proxyDirIndex].ArcIndex; - } - else - { - SET_realIndex_AND_dir_2 - arcIndex = dir->Items[realIndex]; - } - - if (_proxy2->Files[arcIndex].AltDirIndex >= 0) - *isSupported = BoolToInt(true); - return S_OK; -} - - -STDMETHODIMP CAgentFolder::BindToParentFolder(IFolderFolder **resultFolder) -{ - COM_TRY_BEGIN - /* - CMyComPtr 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[fold.ArcIndex]; - int parentIndex = file.Parent; - if (parentIndex < 0) - proxyDirIndex = k_Proxy2_RootDirIndex; - else - proxyDirIndex = _proxy2->Files[parentIndex].DirIndex; - } - } - else - { - int parent = _proxy->Dirs[_proxyDirIndex].ParentDir; - if (parent < 0) - return S_OK; - proxyDirIndex = parent; - } - - CAgentFolder *folderSpec = new CAgentFolder; - CMyComPtr agentFolder = folderSpec; - folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec); - *resultFolder = agentFolder.Detach(); - - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CAgentFolder::GetStream(UInt32 index, ISequentialInStream **stream) -{ - CMyComPtr getStream; - _agentSpec->GetArchive()->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream); - 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 = 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; -}; - -STDMETHODIMP CAgentFolder::GetNumberOfProperties(UInt32 *numProps) -{ - COM_TRY_BEGIN - RINOK(_agentSpec->GetArchive()->GetNumberOfProperties(numProps)); - *numProps += 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 -} - -STDMETHODIMP 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 = 0; - 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 = 0; - } - return S_OK; - COM_TRY_END -} - -static const PROPID kFolderProps[] = -{ - kpidSize, - kpidPackSize, - kpidNumSubDirs, - kpidNumSubFiles, - kpidCRC -}; - -STDMETHODIMP 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->IsThereReadOnlyArc(); - } - else if (_proxy2) - { - const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex]; - if (propID == kpidName) - { - if (dir.ArcIndex >= 0) - prop = _proxy2->Files[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 -} - -STDMETHODIMP CAgentFolder::GetNumberOfFolderProperties(UInt32 *numProps) -{ - *numProps = ARRAY_SIZE(kFolderProps); - return S_OK; -} - -STDMETHODIMP CAgentFolder::GetFolderPropertyInfo IMP_IFolderFolder_GetProp(kFolderProps) - -STDMETHODIMP CAgentFolder::GetParent(UInt32 /* index */, UInt32 * /* parent */, UInt32 * /* parentType */) -{ - return E_FAIL; -} - - -STDMETHODIMP CAgentFolder::GetNumRawProps(UInt32 *numProps) -{ - IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps(); - if (rawProps) - return rawProps->GetNumRawProps(numProps); - *numProps = 0; - return S_OK; -} - -STDMETHODIMP CAgentFolder::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) -{ - IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps(); - if (rawProps) - return rawProps->GetRawPropInfo(index, name, propID); - return E_FAIL; -} - -STDMETHODIMP 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 = 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; -} - -STDMETHODIMP CAgentFolder::GetFolderArcProps(IFolderArcProps **object) -{ - CMyComPtr temp = _agentSpec; - *object = temp.Detach(); - return S_OK; -} - -#ifdef NEW_FOLDER_INTERFACE - -STDMETHODIMP CAgentFolder::SetFlatMode(Int32 flatMode) -{ - _flatMode = IntToBool(flatMode); - return S_OK; -} - -#endif - -int CAgentFolder::GetRealIndex(unsigned index) const -{ - if (!_flatMode) - { - if (_proxy2) - return _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 dir->Items[item.Index]; - } - else - { - const CProxyDir *dir = &_proxy->Dirs[item.DirIndex]; - 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 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 = f.ArcIndex; - } - else - arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()]; - } - realIndices.Add(arcIndex); - } - - HeapSort(&realIndices.Front(), realIndices.Size()); -} - -STDMETHODIMP 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 - CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; - CMyComPtr 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, - true // keepEmptyDirPrefixes - ); - - if (extractCallback2) - extractCallback2->SetTotal(_agentSpec->GetArc().GetEstmatedPhySize()); - - FString pathU; - if (path) - { - pathU = us2fs(path); - if (!pathU.IsEmpty()) - { - 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->Init( - extractNtOptions, - NULL, &_agentSpec->GetArc(), - extractCallback2, - false, // stdOutMode - IntToBool(testMode), - pathU, - pathParts, isAltStreamFolder, - (UInt64)(Int64)-1); - - if (_proxy2) - extractCallbackSpec->SetBaseParentFolderIndex(_proxy2->Dirs[_proxyDirIndex].ArcIndex); - - 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), - _isDeviceFile(false), - _updatePathPrefix_is_AltFolder(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; -} - -STDMETHODIMP CAgent::Open( - IInStream *inStream, - const wchar_t *filePath, - const wchar_t *arcFormat, - BSTR *archiveType, - IArchiveOpenCallback *openArchiveCallback) -{ - COM_TRY_BEGIN - _archiveFilePath = filePath; - _attrib = 0; - NFile::NFind::CFileInfo fi; - _isDeviceFile = false; - if (!inStream) - { - if (!fi.Find(us2fs(_archiveFilePath))) - return ::GetLastError(); - if (fi.IsDir()) - return E_FAIL; - _attrib = fi.Attrib; - _isDeviceFile = fi.IsDevice; - } - CArcInfoEx archiverInfo0, archiverInfo1; - - RINOK(LoadGlobalCodecs()); - - CObjectVector types; - if (!ParseOpenTypes(*g_CodecsObj, arcFormat, types)) - return S_FALSE; - - /* - CObjectVector 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; - - RINOK(_archiveLink.Open(options)); - - CArc &arc = _archiveLink.Arcs.Back(); - if (!inStream) - { - arc.MTimeDefined = !fi.IsDevice; - arc.MTime = fi.MTime; - } - - ArchiveType = GetTypeOfArc(arc); - if (archiveType) - { - RINOK(StringToBstr(ArchiveType, archiveType)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CAgent::ReOpen(IArchiveOpenCallback *openArchiveCallback) -{ - COM_TRY_BEGIN - if (_proxy2) - { - delete _proxy2; - _proxy2 = NULL; - } - if (_proxy) - { - delete _proxy; - _proxy = NULL; - } - - CObjectVector 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 -} - -STDMETHODIMP CAgent::Close() -{ - COM_TRY_BEGIN - return _archiveLink.Close(); - COM_TRY_END -} - -/* -STDMETHODIMP 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); -} - -STDMETHODIMP CAgent::BindToRootFolder(IFolderFolder **resultFolder) -{ - COM_TRY_BEGIN - RINOK(ReadItems()); - CAgentFolder *folderSpec = new CAgentFolder; - CMyComPtr rootFolder = folderSpec; - folderSpec->Init(_proxy, _proxy2, k_Proxy_RootDirIndex, /* NULL, */ this); - *resultFolder = rootFolder.Detach(); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CAgent::Extract( - NExtract::NPathMode::EEnum pathMode, - NExtract::NOverwriteMode::EEnum overwriteMode, - const wchar_t *path, - Int32 testMode, - IFolderArchiveExtractCallback *extractCallback2) -{ - COM_TRY_BEGIN - CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; - CMyComPtr extractCallback = extractCallbackSpec; - extractCallbackSpec->InitForMulti( - false, // multiArchives - pathMode, - overwriteMode, - true // 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); - - #ifdef SUPPORT_LINKS - - if (!testMode) - { - RINOK(extractCallbackSpec->PrepareHardLinks(NULL)); // NULL means all items - } - - #endif - - return GetArchive()->Extract(0, (UInt32)(Int32)-1, testMode, extractCallback); - COM_TRY_END -} - -STDMETHODIMP CAgent::GetNumberOfProperties(UInt32 *numProps) -{ - COM_TRY_BEGIN - return GetArchive()->GetNumberOfProperties(numProps); - COM_TRY_END -} - -STDMETHODIMP 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 -} - -STDMETHODIMP CAgent::GetArcNumLevels(UInt32 *numLevels) -{ - *numLevels = _archiveLink.Arcs.Size(); - return S_OK; -} - -STDMETHODIMP 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; - } - } - 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: - { - UInt32 flags = arc.ErrorInfo.GetErrorFlags(); - if (flags != 0) - prop = flags; - break; - } - case kpidWarningFlags: - { - UInt32 flags = arc.ErrorInfo.GetWarningFlags(); - if (flags != 0) - prop = flags; - break; - } - case kpidOffset: - { - Int64 v = arc.GetGlobalOffset(); - if (v != 0) - prop = 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 -} - -STDMETHODIMP CAgent::GetArcNumProps(UInt32 level, UInt32 *numProps) -{ - return _archiveLink.Arcs[level].Archive->GetNumberOfArchiveProperties(numProps); -} - -STDMETHODIMP CAgent::GetArcPropInfo(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) -{ - return _archiveLink.Arcs[level].Archive->GetArchivePropertyInfo(index, name, propID, varType); -} - -// MainItemProperty -STDMETHODIMP CAgent::GetArcProp2(UInt32 level, PROPID propID, PROPVARIANT *value) -{ - return _archiveLink.Arcs[level - 1].Archive->GetProperty(_archiveLink.Arcs[level].SubfileIndex, propID, value); -} - -STDMETHODIMP CAgent::GetArcNumProps2(UInt32 level, UInt32 *numProps) -{ - return _archiveLink.Arcs[level - 1].Archive->GetNumberOfProperties(numProps); -} - -STDMETHODIMP CAgent::GetArcPropInfo2(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) -{ - return _archiveLink.Arcs[level - 1].Archive->GetPropertyInfo(index, name, propID, varType); -} +// Agent.cpp + +#include "StdAfx.h" + +#include + +#include "../../../../C/Sort.h" + +#include "../../../Common/ComTry.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariantConv.h" + +#ifndef _7ZIP_ST +#include "../../../Windows/Synchronization.h" +#endif + +#include "../Common/ArchiveExtractCallback.h" +#include "../FileManager/RegistryUtils.h" + +#include "Agent.h" + +using namespace NWindows; + +CCodecs *g_CodecsObj; + +#ifdef EXTERNAL_CODECS + CExternalCodecs g_ExternalCodecs; + CCodecs::CReleaser g_CodecsReleaser; +#else + CMyComPtr g_CodecsRef; +#endif + +#ifndef _7ZIP_ST +static NSynchronization::CCriticalSection g_CriticalSection; +#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); +#else +#define MT_LOCK +#endif + +void FreeGlobalCodecs() +{ + MT_LOCK + + #ifdef EXTERNAL_CODECS + if (g_CodecsObj) + { + g_CodecsObj->CloseLibs(); + } + g_CodecsReleaser.Set(NULL); + g_CodecsObj = NULL; + g_ExternalCodecs.ClearAndRelease(); + #else + g_CodecsRef.Release(); + #endif +} + +HRESULT LoadGlobalCodecs() +{ + MT_LOCK + + if (g_CodecsObj) + return S_OK; + + g_CodecsObj = new CCodecs; + + #ifdef 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; + } + + #ifdef EXTERNAL_CODECS + RINOK(g_ExternalCodecs.Load()); + #endif + + return S_OK; +} + +STDMETHODIMP 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 >= 0) + LoadFolder(file.DirIndex); + if (_loadAltStreams && file.AltDirIndex >= 0) + LoadFolder(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); + } +} + +STDMETHODIMP 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; +} + +STDMETHODIMP 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[_proxy2->Dirs[proxyIndex].ArcIndex]; + len += file.NameLen + 1; + proxyIndex = (file.Parent < 0) ? 0 : _proxy2->Files[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[_proxy2->Dirs[proxyIndex].ArcIndex]; + p--; + *p = WCHAR_PATH_SEPARATOR; + p -= file.NameLen; + wmemcpy(p, file.Name, file.NameLen); + proxyIndex = (file.Parent < 0) ? 0 : _proxy2->Files[file.Parent].GetDirIndex(file.IsAltStream); + } + } + else + { + unsigned len = 0; + while (proxyIndex != _proxyDirIndex) + { + const CProxyDir *dir = &_proxy->Dirs[proxyIndex]; + len += dir->NameLen + 1; + proxyIndex = 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 = dir->ParentDir; + } + } +} + +UString CAgentFolder::GetFullPrefix(UInt32 index) const +{ + int foldIndex = _proxyDirIndex; + + if (_flatMode) + foldIndex = _items[index].DirIndex; + + if (_proxy2) + return _proxy2->Dirs[foldIndex].PathPrefix; + else + return _proxy->GetDirPath_as_Prefix(foldIndex); +} + +STDMETHODIMP_(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 = 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; +} + +STDMETHODIMP 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 >= 0) + 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(item.ArcIndex, propID, value)); + } + if (item.CrcIsDefined && value->vt == VT_EMPTY) + prop = item.Crc; + break; + } + default: + if (item.IsLeaf()) + return _agentSpec->GetArchive()->GetProperty(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; +} + +STDMETHODIMP 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; + } + } +} + +STDMETHODIMP CAgentFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len) +{ + *name = 0; + *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, int arcIndex1, int arcIndex2, PROPID propID) +{ + // if (propID == kpidSha1) + if (rawProps) + { + const void *p1, *p2; + UInt32 size1, size2; + UInt32 propType1, propType2; + HRESULT res1 = rawProps->GetRawProp(arcIndex1, propID, &p1, &size1, &propType1); + 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++) + { + Byte b1 = ((const Byte *)p1)[i]; + 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); +} + + +STDMETHODIMP_(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 = proxFolder1->ArcIndex; + } + else + arcIndex1 = dir1->SubFiles[realIndex1 - dir1->SubDirs.Size()]; + + if (realIndex2 < dir2->SubDirs.Size()) + { + proxFolder2 = &_proxy->Dirs[dir2->SubDirs[realIndex2]]; + arcIndex2 = 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 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 agentFolder = folderSpec; + folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec); + *resultFolder = agentFolder.Detach(); + return S_OK; +} + +STDMETHODIMP CAgentFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder) +{ + COM_TRY_BEGIN + if (_proxy2) + { + SET_realIndex_AND_dir_2 + unsigned arcIndex = dir->Items[realIndex]; + const CProxyFile2 &item = _proxy2->Files[arcIndex]; + if (!item.IsDir()) + return E_INVALIDARG; + return BindToFolder_Internal(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 +} + +STDMETHODIMP CAgentFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder) +{ + COM_TRY_BEGIN + if (_proxy2) + { + int index = _proxy2->FindItem(_proxyDirIndex, name, true); + if (index < 0) + return E_INVALIDARG; + return BindToFolder_Internal(_proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]].DirIndex, resultFolder); + } + int index = _proxy->FindSubDir(_proxyDirIndex, name); + if (index < 0) + return E_INVALIDARG; + return BindToFolder_Internal(index, resultFolder); + COM_TRY_END +} + + + +// ---------- IFolderAltStreams ---------- + +HRESULT CAgentFolder::BindToAltStreams_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder) +{ + *resultFolder = NULL; + if (!_proxy2) + return S_OK; + + /* + CMyComPtr 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 agentFolder = folderSpec; + folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec); + *resultFolder = agentFolder.Detach(); + return S_OK; +} + +STDMETHODIMP 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 + { + unsigned arcIndex = _proxy2->Dirs[_proxyDirIndex].ArcIndex; + const CProxyFile2 &item = _proxy2->Files[arcIndex]; + if (item.AltDirIndex < 0) + return S_OK; + altDirIndex = item.AltDirIndex; + // parentFolder = _parentFolder; + } + + CAgentFolder *folderSpec = new CAgentFolder; + CMyComPtr agentFolder = folderSpec; + folderSpec->Init(_proxy, _proxy2, altDirIndex, /* parentFolder, */ _agentSpec); + *resultFolder = agentFolder.Detach(); + return S_OK; + } + + SET_realIndex_AND_dir_2 + unsigned arcIndex = dir->Items[realIndex]; + const CProxyFile2 &item = _proxy2->Files[arcIndex]; + if (item.AltDirIndex < 0) + return S_OK; + return BindToAltStreams_Internal(item.AltDirIndex, resultFolder); + } + + COM_TRY_END +} + +STDMETHODIMP 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 >= 0) + if (CompareFileNames(file.Name, name) == 0) + return BindToAltStreams_Internal(file.AltDirIndex, resultFolder); + } + return E_INVALIDARG; + } + COM_TRY_END +} + +STDMETHODIMP 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 = _proxy2->Dirs[_proxyDirIndex].ArcIndex; + } + else + { + SET_realIndex_AND_dir_2 + arcIndex = dir->Items[realIndex]; + } + + if (_proxy2->Files[arcIndex].AltDirIndex >= 0) + *isSupported = BoolToInt(true); + return S_OK; +} + + +STDMETHODIMP CAgentFolder::BindToParentFolder(IFolderFolder **resultFolder) +{ + COM_TRY_BEGIN + /* + CMyComPtr 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[fold.ArcIndex]; + int parentIndex = file.Parent; + if (parentIndex < 0) + proxyDirIndex = k_Proxy2_RootDirIndex; + else + proxyDirIndex = _proxy2->Files[parentIndex].DirIndex; + } + } + else + { + int parent = _proxy->Dirs[_proxyDirIndex].ParentDir; + if (parent < 0) + return S_OK; + proxyDirIndex = parent; + } + + CAgentFolder *folderSpec = new CAgentFolder; + CMyComPtr agentFolder = folderSpec; + folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec); + *resultFolder = agentFolder.Detach(); + + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CAgentFolder::GetStream(UInt32 index, ISequentialInStream **stream) +{ + CMyComPtr getStream; + _agentSpec->GetArchive()->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream); + 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 = 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; +}; + +STDMETHODIMP CAgentFolder::GetNumberOfProperties(UInt32 *numProps) +{ + COM_TRY_BEGIN + RINOK(_agentSpec->GetArchive()->GetNumberOfProperties(numProps)); + *numProps += 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 +} + +STDMETHODIMP 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 = 0; + 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 = 0; + } + return S_OK; + COM_TRY_END +} + +static const PROPID kFolderProps[] = +{ + kpidSize, + kpidPackSize, + kpidNumSubDirs, + kpidNumSubFiles, + kpidCRC +}; + +STDMETHODIMP 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->IsThereReadOnlyArc(); + } + else if (_proxy2) + { + const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex]; + if (propID == kpidName) + { + if (dir.ArcIndex >= 0) + prop = _proxy2->Files[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 +} + +STDMETHODIMP CAgentFolder::GetNumberOfFolderProperties(UInt32 *numProps) +{ + *numProps = ARRAY_SIZE(kFolderProps); + return S_OK; +} + +STDMETHODIMP CAgentFolder::GetFolderPropertyInfo IMP_IFolderFolder_GetProp(kFolderProps) + +STDMETHODIMP CAgentFolder::GetParent(UInt32 /* index */, UInt32 * /* parent */, UInt32 * /* parentType */) +{ + return E_FAIL; +} + + +STDMETHODIMP CAgentFolder::GetNumRawProps(UInt32 *numProps) +{ + IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps(); + if (rawProps) + return rawProps->GetNumRawProps(numProps); + *numProps = 0; + return S_OK; +} + +STDMETHODIMP CAgentFolder::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) +{ + IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps(); + if (rawProps) + return rawProps->GetRawPropInfo(index, name, propID); + return E_FAIL; +} + +STDMETHODIMP 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 = 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; +} + +STDMETHODIMP CAgentFolder::GetFolderArcProps(IFolderArcProps **object) +{ + CMyComPtr temp = _agentSpec; + *object = temp.Detach(); + return S_OK; +} + +#ifdef NEW_FOLDER_INTERFACE + +STDMETHODIMP CAgentFolder::SetFlatMode(Int32 flatMode) +{ + _flatMode = IntToBool(flatMode); + return S_OK; +} + +#endif + +int CAgentFolder::GetRealIndex(unsigned index) const +{ + if (!_flatMode) + { + if (_proxy2) + return _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 dir->Items[item.Index]; + } + else + { + const CProxyDir *dir = &_proxy->Dirs[item.DirIndex]; + 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 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 = f.ArcIndex; + } + else + arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()]; + } + realIndices.Add(arcIndex); + } + + HeapSort(&realIndices.Front(), realIndices.Size()); +} + +STDMETHODIMP 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 + CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; + CMyComPtr 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, + true // keepEmptyDirPrefixes + ); + + if (extractCallback2) + extractCallback2->SetTotal(_agentSpec->GetArc().GetEstmatedPhySize()); + + FString pathU; + if (path) + { + pathU = us2fs(path); + if (!pathU.IsEmpty()) + { + 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->Init( + extractNtOptions, + NULL, &_agentSpec->GetArc(), + extractCallback2, + false, // stdOutMode + IntToBool(testMode), + pathU, + pathParts, isAltStreamFolder, + (UInt64)(Int64)-1); + + if (_proxy2) + extractCallbackSpec->SetBaseParentFolderIndex(_proxy2->Dirs[_proxyDirIndex].ArcIndex); + + 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), + _isDeviceFile(false), + _updatePathPrefix_is_AltFolder(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; +} + +STDMETHODIMP CAgent::Open( + IInStream *inStream, + const wchar_t *filePath, + const wchar_t *arcFormat, + BSTR *archiveType, + IArchiveOpenCallback *openArchiveCallback) +{ + COM_TRY_BEGIN + _archiveFilePath = filePath; + _attrib = 0; + NFile::NFind::CFileInfo fi; + _isDeviceFile = false; + if (!inStream) + { + if (!fi.Find(us2fs(_archiveFilePath))) + return ::GetLastError(); + if (fi.IsDir()) + return E_FAIL; + _attrib = fi.Attrib; + _isDeviceFile = fi.IsDevice; + } + CArcInfoEx archiverInfo0, archiverInfo1; + + RINOK(LoadGlobalCodecs()); + + CObjectVector types; + if (!ParseOpenTypes(*g_CodecsObj, arcFormat, types)) + return S_FALSE; + + /* + CObjectVector 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; + + RINOK(_archiveLink.Open(options)); + + CArc &arc = _archiveLink.Arcs.Back(); + if (!inStream) + { + arc.MTimeDefined = !fi.IsDevice; + arc.MTime = fi.MTime; + } + + ArchiveType = GetTypeOfArc(arc); + if (archiveType) + { + RINOK(StringToBstr(ArchiveType, archiveType)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CAgent::ReOpen(IArchiveOpenCallback *openArchiveCallback) +{ + COM_TRY_BEGIN + if (_proxy2) + { + delete _proxy2; + _proxy2 = NULL; + } + if (_proxy) + { + delete _proxy; + _proxy = NULL; + } + + CObjectVector 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 +} + +STDMETHODIMP CAgent::Close() +{ + COM_TRY_BEGIN + return _archiveLink.Close(); + COM_TRY_END +} + +/* +STDMETHODIMP 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); +} + +STDMETHODIMP CAgent::BindToRootFolder(IFolderFolder **resultFolder) +{ + COM_TRY_BEGIN + RINOK(ReadItems()); + CAgentFolder *folderSpec = new CAgentFolder; + CMyComPtr rootFolder = folderSpec; + folderSpec->Init(_proxy, _proxy2, k_Proxy_RootDirIndex, /* NULL, */ this); + *resultFolder = rootFolder.Detach(); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CAgent::Extract( + NExtract::NPathMode::EEnum pathMode, + NExtract::NOverwriteMode::EEnum overwriteMode, + const wchar_t *path, + Int32 testMode, + IFolderArchiveExtractCallback *extractCallback2) +{ + COM_TRY_BEGIN + CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; + CMyComPtr extractCallback = extractCallbackSpec; + extractCallbackSpec->InitForMulti( + false, // multiArchives + pathMode, + overwriteMode, + true // 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); + + #ifdef SUPPORT_LINKS + + if (!testMode) + { + RINOK(extractCallbackSpec->PrepareHardLinks(NULL)); // NULL means all items + } + + #endif + + return GetArchive()->Extract(0, (UInt32)(Int32)-1, testMode, extractCallback); + COM_TRY_END +} + +STDMETHODIMP CAgent::GetNumberOfProperties(UInt32 *numProps) +{ + COM_TRY_BEGIN + return GetArchive()->GetNumberOfProperties(numProps); + COM_TRY_END +} + +STDMETHODIMP 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 +} + +STDMETHODIMP CAgent::GetArcNumLevels(UInt32 *numLevels) +{ + *numLevels = _archiveLink.Arcs.Size(); + return S_OK; +} + +STDMETHODIMP 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; + } + } + 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: + { + UInt32 flags = arc.ErrorInfo.GetErrorFlags(); + if (flags != 0) + prop = flags; + break; + } + case kpidWarningFlags: + { + UInt32 flags = arc.ErrorInfo.GetWarningFlags(); + if (flags != 0) + prop = flags; + break; + } + case kpidOffset: + { + Int64 v = arc.GetGlobalOffset(); + if (v != 0) + prop = 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 +} + +STDMETHODIMP CAgent::GetArcNumProps(UInt32 level, UInt32 *numProps) +{ + return _archiveLink.Arcs[level].Archive->GetNumberOfArchiveProperties(numProps); +} + +STDMETHODIMP CAgent::GetArcPropInfo(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) +{ + return _archiveLink.Arcs[level].Archive->GetArchivePropertyInfo(index, name, propID, varType); +} + +// MainItemProperty +STDMETHODIMP CAgent::GetArcProp2(UInt32 level, PROPID propID, PROPVARIANT *value) +{ + return _archiveLink.Arcs[level - 1].Archive->GetProperty(_archiveLink.Arcs[level].SubfileIndex, propID, value); +} + +STDMETHODIMP CAgent::GetArcNumProps2(UInt32 level, UInt32 *numProps) +{ + return _archiveLink.Arcs[level - 1].Archive->GetNumberOfProperties(numProps); +} + +STDMETHODIMP 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 index 2d5a239b9..f7d7b5e4f 100644 --- a/CPP/7zip/UI/Agent/Agent.h +++ b/CPP/7zip/UI/Agent/Agent.h @@ -1,344 +1,344 @@ -// Agent/Agent.h - -#ifndef __AGENT_AGENT_H -#define __AGENT_AGENT_H - -#include "../../../Common/MyCom.h" - -#include "../../../Windows/PropVariant.h" - -#include "../Common/OpenArchive.h" -#include "../Common/UpdateAction.h" - -#ifdef NEW_FOLDER_INTERFACE -#include "../FileManager/IFolder.h" -#include "../Common/LoadCodecs.h" -#endif - -#include "AgentProxy.h" -#include "IFolderArchive.h" - -extern CCodecs *g_CodecsObj; -HRESULT LoadGlobalCodecs(); -void FreeGlobalCodecs(); - -class CAgentFolder; - -DECL_INTERFACE(IArchiveFolderInternal, 0x01, 0xC) -{ - STDMETHOD(GetAgentFolder)(CAgentFolder **agentFolder) PURE; -}; - -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: - public IFolderFolder, - public IFolderAltStreams, - public IFolderProperties, - public IArchiveGetRawProps, - public IGetFolderArcProps, - public IFolderCompare, - public IFolderGetItemName, - public IArchiveFolder, - public IArchiveFolderInternal, - public IInArchiveGetStream, - // public IFolderSetReplaceAltStreamCharsMode, -#ifdef NEW_FOLDER_INTERFACE - public IFolderOperations, - public IFolderSetFlatMode, -#endif - public CMyUnknownImp -{ - void LoadFolder(unsigned proxyDirIndex); -public: - - MY_QUERYINTERFACE_BEGIN2(IFolderFolder) - MY_QUERYINTERFACE_ENTRY(IFolderAltStreams) - MY_QUERYINTERFACE_ENTRY(IFolderProperties) - MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps) - MY_QUERYINTERFACE_ENTRY(IGetFolderArcProps) - MY_QUERYINTERFACE_ENTRY(IFolderCompare) - MY_QUERYINTERFACE_ENTRY(IFolderGetItemName) - MY_QUERYINTERFACE_ENTRY(IArchiveFolder) - MY_QUERYINTERFACE_ENTRY(IArchiveFolderInternal) - MY_QUERYINTERFACE_ENTRY(IInArchiveGetStream) - // MY_QUERYINTERFACE_ENTRY(IFolderSetReplaceAltStreamCharsMode) - #ifdef NEW_FOLDER_INTERFACE - MY_QUERYINTERFACE_ENTRY(IFolderOperations) - MY_QUERYINTERFACE_ENTRY(IFolderSetFlatMode) - #endif - MY_QUERYINTERFACE_END - MY_ADDREF_RELEASE - - 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; - - // INTERFACE_FolderSetReplaceAltStreamCharsMode(;) - - INTERFACE_FolderFolder(;) - INTERFACE_FolderAltStreams(;) - INTERFACE_FolderProperties(;) - INTERFACE_IArchiveGetRawProps(;) - INTERFACE_IFolderGetItemName(;) - - STDMETHOD(GetFolderArcProps)(IFolderArcProps **object); - STDMETHOD_(Int32, CompareItems)(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw); - int CompareItems3(UInt32 index1, UInt32 index2, PROPID propID); - int CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw); - - // IArchiveFolder - INTERFACE_IArchiveFolder(;) - - STDMETHOD(GetAgentFolder)(CAgentFolder **agentFolder); - - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - - #ifdef NEW_FOLDER_INTERFACE - INTERFACE_FolderOperations(;) - - STDMETHOD(SetFlatMode)(Int32 flatMode); - #endif - - CAgentFolder(): - _proxyDirIndex(0), - _isAltStreamFolder(false), - _flatMode(false), - _loadAltStreams(false) // _loadAltStreams alt streams works in flat mode, but we don't use it now - /* , _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 _parentFolder; - CMyComPtr _agent; - CAgent *_agentSpec; - - CRecordVector _items; - bool _flatMode; - bool _loadAltStreams; // in Flat mode - // Int32 _replaceAltStreamCharsMode; -}; - -class CAgent: - public IInFolderArchive, - public IFolderArcProps, - #ifndef EXTRACT_ONLY - public IOutFolderArchive, - public ISetProperties, - #endif - public CMyUnknownImp -{ -public: - - MY_QUERYINTERFACE_BEGIN2(IInFolderArchive) - MY_QUERYINTERFACE_ENTRY(IFolderArcProps) - #ifndef EXTRACT_ONLY - MY_QUERYINTERFACE_ENTRY(IOutFolderArchive) - MY_QUERYINTERFACE_ENTRY(ISetProperties) - #endif - MY_QUERYINTERFACE_END - MY_ADDREF_RELEASE - - INTERFACE_IInFolderArchive(;) - INTERFACE_IFolderArcProps(;) - - #ifndef EXTRACT_ONLY - INTERFACE_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); - - // ISetProperties - STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); - #endif - - CAgent(); - ~CAgent(); -private: - HRESULT ReadItems(); -public: - CProxyArc *_proxy; - CProxyArc2 *_proxy2; - CArchiveLink _archiveLink; - - bool ThereIsPathProp; - // bool ThereIsAltStreamProp; - - UString ArchiveType; - - FStringVector _names; - FString _folderPrefix; - - bool _updatePathPrefix_is_AltFolder; - UString _updatePathPrefix; - CAgentFolder *_agentFolder; - - UString _archiveFilePath; - DWORD _attrib; - bool _isDeviceFile; - - #ifndef EXTRACT_ONLY - CObjectVector m_PropNames; - CObjectVector m_PropValues; - #endif - - const CArc &GetArc() const { return _archiveLink.Arcs.Back(); } - IInArchive *GetArchive() const { if ( _archiveLink.Arcs.IsEmpty()) return 0; return GetArc().Archive; } - bool CanUpdate() const; - - bool Is_Attrib_ReadOnly() const - { - return _attrib != INVALID_FILE_ATTRIBUTES && (_attrib & FILE_ATTRIBUTE_READONLY); - } - - bool IsThereReadOnlyArc() 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 = _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 += "Can not 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 - -class CArchiveFolderManager: - public IFolderManager, - public CMyUnknownImp -{ - void LoadFormats(); - int FindFormat(const UString &type); -public: - MY_UNKNOWN_IMP1(IFolderManager) - INTERFACE_IFolderManager(;) -}; - -#endif - -#endif +// Agent/Agent.h + +#ifndef __AGENT_AGENT_H +#define __AGENT_AGENT_H + +#include "../../../Common/MyCom.h" + +#include "../../../Windows/PropVariant.h" + +#include "../Common/OpenArchive.h" +#include "../Common/UpdateAction.h" + +#ifdef NEW_FOLDER_INTERFACE +#include "../FileManager/IFolder.h" +#include "../Common/LoadCodecs.h" +#endif + +#include "AgentProxy.h" +#include "IFolderArchive.h" + +extern CCodecs *g_CodecsObj; +HRESULT LoadGlobalCodecs(); +void FreeGlobalCodecs(); + +class CAgentFolder; + +DECL_INTERFACE(IArchiveFolderInternal, 0x01, 0xC) +{ + STDMETHOD(GetAgentFolder)(CAgentFolder **agentFolder) PURE; +}; + +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: + public IFolderFolder, + public IFolderAltStreams, + public IFolderProperties, + public IArchiveGetRawProps, + public IGetFolderArcProps, + public IFolderCompare, + public IFolderGetItemName, + public IArchiveFolder, + public IArchiveFolderInternal, + public IInArchiveGetStream, + // public IFolderSetReplaceAltStreamCharsMode, +#ifdef NEW_FOLDER_INTERFACE + public IFolderOperations, + public IFolderSetFlatMode, +#endif + public CMyUnknownImp +{ + void LoadFolder(unsigned proxyDirIndex); +public: + + MY_QUERYINTERFACE_BEGIN2(IFolderFolder) + MY_QUERYINTERFACE_ENTRY(IFolderAltStreams) + MY_QUERYINTERFACE_ENTRY(IFolderProperties) + MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps) + MY_QUERYINTERFACE_ENTRY(IGetFolderArcProps) + MY_QUERYINTERFACE_ENTRY(IFolderCompare) + MY_QUERYINTERFACE_ENTRY(IFolderGetItemName) + MY_QUERYINTERFACE_ENTRY(IArchiveFolder) + MY_QUERYINTERFACE_ENTRY(IArchiveFolderInternal) + MY_QUERYINTERFACE_ENTRY(IInArchiveGetStream) + // MY_QUERYINTERFACE_ENTRY(IFolderSetReplaceAltStreamCharsMode) + #ifdef NEW_FOLDER_INTERFACE + MY_QUERYINTERFACE_ENTRY(IFolderOperations) + MY_QUERYINTERFACE_ENTRY(IFolderSetFlatMode) + #endif + MY_QUERYINTERFACE_END + MY_ADDREF_RELEASE + + 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; + + // INTERFACE_FolderSetReplaceAltStreamCharsMode(;) + + INTERFACE_FolderFolder(;) + INTERFACE_FolderAltStreams(;) + INTERFACE_FolderProperties(;) + INTERFACE_IArchiveGetRawProps(;) + INTERFACE_IFolderGetItemName(;) + + STDMETHOD(GetFolderArcProps)(IFolderArcProps **object); + STDMETHOD_(Int32, CompareItems)(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw); + int CompareItems3(UInt32 index1, UInt32 index2, PROPID propID); + int CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw); + + // IArchiveFolder + INTERFACE_IArchiveFolder(;) + + STDMETHOD(GetAgentFolder)(CAgentFolder **agentFolder); + + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + + #ifdef NEW_FOLDER_INTERFACE + INTERFACE_FolderOperations(;) + + STDMETHOD(SetFlatMode)(Int32 flatMode); + #endif + + CAgentFolder(): + _proxyDirIndex(0), + _isAltStreamFolder(false), + _flatMode(false), + _loadAltStreams(false) // _loadAltStreams alt streams works in flat mode, but we don't use it now + /* , _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 _parentFolder; + CMyComPtr _agent; + CAgent *_agentSpec; + + CRecordVector _items; + bool _flatMode; + bool _loadAltStreams; // in Flat mode + // Int32 _replaceAltStreamCharsMode; +}; + +class CAgent: + public IInFolderArchive, + public IFolderArcProps, + #ifndef EXTRACT_ONLY + public IOutFolderArchive, + public ISetProperties, + #endif + public CMyUnknownImp +{ +public: + + MY_QUERYINTERFACE_BEGIN2(IInFolderArchive) + MY_QUERYINTERFACE_ENTRY(IFolderArcProps) + #ifndef EXTRACT_ONLY + MY_QUERYINTERFACE_ENTRY(IOutFolderArchive) + MY_QUERYINTERFACE_ENTRY(ISetProperties) + #endif + MY_QUERYINTERFACE_END + MY_ADDREF_RELEASE + + INTERFACE_IInFolderArchive(;) + INTERFACE_IFolderArcProps(;) + + #ifndef EXTRACT_ONLY + INTERFACE_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); + + // ISetProperties + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); + #endif + + CAgent(); + ~CAgent(); +private: + HRESULT ReadItems(); +public: + CProxyArc *_proxy; + CProxyArc2 *_proxy2; + CArchiveLink _archiveLink; + + bool ThereIsPathProp; + // bool ThereIsAltStreamProp; + + UString ArchiveType; + + FStringVector _names; + FString _folderPrefix; + + bool _updatePathPrefix_is_AltFolder; + UString _updatePathPrefix; + CAgentFolder *_agentFolder; + + UString _archiveFilePath; + DWORD _attrib; + bool _isDeviceFile; + + #ifndef EXTRACT_ONLY + CObjectVector m_PropNames; + CObjectVector m_PropValues; + #endif + + const CArc &GetArc() const { return _archiveLink.Arcs.Back(); } + IInArchive *GetArchive() const { if ( _archiveLink.Arcs.IsEmpty()) return 0; return GetArc().Archive; } + bool CanUpdate() const; + + bool Is_Attrib_ReadOnly() const + { + return _attrib != INVALID_FILE_ATTRIBUTES && (_attrib & FILE_ATTRIBUTE_READONLY); + } + + bool IsThereReadOnlyArc() 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 = _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 += "Can not 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 + +class CArchiveFolderManager: + public IFolderManager, + public CMyUnknownImp +{ + void LoadFormats(); + int FindFormat(const UString &type); +public: + MY_UNKNOWN_IMP1(IFolderManager) + INTERFACE_IFolderManager(;) +}; + +#endif + +#endif diff --git a/CPP/7zip/UI/Agent/AgentOut.cpp b/CPP/7zip/UI/Agent/AgentOut.cpp index 6215fe385..40876d764 100644 --- a/CPP/7zip/UI/Agent/AgentOut.cpp +++ b/CPP/7zip/UI/Agent/AgentOut.cpp @@ -1,709 +1,709 @@ -// 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 "Agent.h" -#include "UpdateCallbackAgent.h" - -using namespace NWindows; -using namespace NCOM; - -STDMETHODIMP CAgent::SetFolder(IFolderFolder *folder) -{ - _updatePathPrefix.Empty(); - _updatePathPrefix_is_AltFolder = false; - _agentFolder = NULL; - - if (!folder) - return S_OK; - - { - CMyComPtr afi; - RINOK(folder->QueryInterface(IID_IArchiveFolderInternal, (void **)&afi)); - 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; -} - -STDMETHODIMP 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 &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().GetItemMTime(arcIndex, ai.MTime, ai.MTimeDefined)); - RINOK(agent->GetArc().GetItemSize(arcIndex, ai.Size, ai.SizeDefined)); - 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().GetItemMTime(dirItem.ArcIndex, ai.MTime, ai.MTimeDefined)); - ai.IsDir = true; - ai.SizeDefined = false; - ai.Name = fullName; - ai.Censored = true; // test it - ai.IndexInServer = 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 &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().GetItemMTime(arcIndex, ai.MTime, ai.MTimeDefined)); - ai.IsDir = file.IsDir(); - ai.SizeDefined = false; - ai.IsAltStream = file.IsAltStream; - if (!ai.IsDir) - { - RINOK(agent->GetArc().GetItemSize(arcIndex, ai.Size, ai.SizeDefined)); - ai.IsDir = false; - } - arcItems.Add(ai); - - if (file.AltDirIndex >= 0) - { - RINOK(EnumerateArchiveItems2(agent, file.AltDirIndex, ai.Name + L':', arcItems)); - } - - if (ai.IsDir) - { - RINOK(EnumerateArchiveItems2(agent, file.DirIndex, ai.Name + WCHAR_PATH_SEPARATOR, arcItems)); - } - } - return S_OK; -} - -struct CAgUpCallbackImp: public IUpdateProduceCallback -{ - const CObjectVector *_arcItems; - IFolderArchiveUpdateCallback *_callback; - - CAgUpCallbackImp(const CObjectVector *a, - IFolderArchiveUpdateCallback *callback): _arcItems(a), _callback(callback) {} - HRESULT ShowDeleteFile(unsigned arcIndex); -}; - -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; -} - -struct CDirItemsCallback_AgentOut: public IDirItemsCallback -{ - CMyComPtr FolderScanProgress; - IFolderArchiveUpdateCallback *FolderArchiveUpdateCallback; - HRESULT ErrorCode; - - CDirItemsCallback_AgentOut(): ErrorCode(S_OK), FolderArchiveUpdateCallback(NULL) {} - - HRESULT ScanError(const FString &name, DWORD systemError) - { - 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) - { - 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; - } -}; - -STDMETHODIMP 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; - 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 outArchive; - - if (GetArchive()) - { - RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive)); - } - else - { - if (formatIndex < 0) - return E_FAIL; - RINOK(codecs->CreateOutArchive(formatIndex, outArchive)); - - #ifdef EXTERNAL_CODECS - { - CMyComPtr setCompressCodecsInfo; - outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); - if (setCompressCodecsInfo) - { - RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)); - } - } - #endif - } - - NFileTimeType::EEnum fileTimeType; - UInt32 value; - RINOK(outArchive->GetFileTimeType(&value)); - - switch (value) - { - case NFileTimeType::kWindows: - case NFileTimeType::kDOS: - case NFileTimeType::kUnix: - fileTimeType = NFileTimeType::EEnum(value); - break; - default: - return E_FAIL; - } - - - CObjectVector 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 updatePairs2; - - { - CRecordVector 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 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; - } - - CMyComPtr setProperties; - if (outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties) == S_OK) - { - if (m_PropNames.Size() == 0) - { - RINOK(setProperties->SetProperties(0, 0, 0)); - } - else - { - CRecordVector 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 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 >= 0 && up.NewData) - { - const CDirItem &di = dirItems.Items[up.DirIndex]; - if (!di.IsDir() && di.Size == 0) - processedItems[up.DirIndex] = 1; - } - } - } - - FOR_VECTOR (i, dirItems.Items) - if (processedItems[i] != 0) - processedPaths->Add(dirItems.GetPhyPath(i)); - } - return res; -} - -STDMETHODIMP 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 outArchive; - RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive)); - return outArchive->UpdateItems(outArchiveStream, numUpdateItems, updateCallback); -} - -STDMETHODIMP CAgent::DeleteItems(ISequentialOutStream *outArchiveStream, - const UInt32 *indices, UInt32 numItems, - IFolderArchiveUpdateCallback *updateCallback100) -{ - if (!CanUpdate()) - return E_NOTIMPL; - CRecordVector updatePairs; - CUpdateCallbackAgent updateCallbackAgent; - updateCallbackAgent.SetCallback(updateCallback100); - CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; - CMyComPtr 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().GetItemPath2(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 updatePairs; - CDirItems dirItems; - CUpdateCallbackAgent updateCallbackAgent; - updateCallbackAgent.SetCallback(updateCallback100); - CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; - CMyComPtr 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 updatePairs; - CUpdateCallbackAgent updateCallbackAgent; - updateCallbackAgent.SetCallback(updateCallback100); - CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; - CMyComPtr updateCallback(updateCallbackSpec); - - CUIntVector realIndices; - _agentFolder->GetRealIndices(indices, numItems, - true, // includeAltStreams - true, // includeFolderSubItemsInFlatMode - realIndices); - - int mainRealIndex = _agentFolder->GetRealIndex(indices[0]); - - UString fullPrefix = _agentFolder->GetFullPrefix(indices[0]); - UString oldItemPath = fullPrefix + _agentFolder->GetName(indices[0]); - 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().IsItemAnti(i, up2.IsAnti)); // it must work without that line too. - - UString oldFullPath; - RINOK(GetArc().GetItemPath2(i, oldFullPath)); - - if (!IsPath1PrefixedByPath2(oldFullPath, oldItemPath)) - return E_INVALIDARG; - - up2.NewNameIndex = 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 updatePairs; - CUpdateCallbackAgent updateCallbackAgent; - updateCallbackAgent.SetCallback(updateCallback100); - CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; - CMyComPtr 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 updatePairs; - CDirItems dirItems; - CUpdateCallbackAgent updateCallbackAgent; - updateCallbackAgent.SetCallback(updateCallback100); - CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; - CMyComPtr 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); -} - -STDMETHODIMP 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; -} +// 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 "Agent.h" +#include "UpdateCallbackAgent.h" + +using namespace NWindows; +using namespace NCOM; + +STDMETHODIMP CAgent::SetFolder(IFolderFolder *folder) +{ + _updatePathPrefix.Empty(); + _updatePathPrefix_is_AltFolder = false; + _agentFolder = NULL; + + if (!folder) + return S_OK; + + { + CMyComPtr afi; + RINOK(folder->QueryInterface(IID_IArchiveFolderInternal, (void **)&afi)); + 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; +} + +STDMETHODIMP 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 &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().GetItemMTime(arcIndex, ai.MTime, ai.MTimeDefined)); + RINOK(agent->GetArc().GetItemSize(arcIndex, ai.Size, ai.SizeDefined)); + 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().GetItemMTime(dirItem.ArcIndex, ai.MTime, ai.MTimeDefined)); + ai.IsDir = true; + ai.SizeDefined = false; + ai.Name = fullName; + ai.Censored = true; // test it + ai.IndexInServer = 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 &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().GetItemMTime(arcIndex, ai.MTime, ai.MTimeDefined)); + ai.IsDir = file.IsDir(); + ai.SizeDefined = false; + ai.IsAltStream = file.IsAltStream; + if (!ai.IsDir) + { + RINOK(agent->GetArc().GetItemSize(arcIndex, ai.Size, ai.SizeDefined)); + ai.IsDir = false; + } + arcItems.Add(ai); + + if (file.AltDirIndex >= 0) + { + RINOK(EnumerateArchiveItems2(agent, file.AltDirIndex, ai.Name + L':', arcItems)); + } + + if (ai.IsDir) + { + RINOK(EnumerateArchiveItems2(agent, file.DirIndex, ai.Name + WCHAR_PATH_SEPARATOR, arcItems)); + } + } + return S_OK; +} + +struct CAgUpCallbackImp: public IUpdateProduceCallback +{ + const CObjectVector *_arcItems; + IFolderArchiveUpdateCallback *_callback; + + CAgUpCallbackImp(const CObjectVector *a, + IFolderArchiveUpdateCallback *callback): _arcItems(a), _callback(callback) {} + HRESULT ShowDeleteFile(unsigned arcIndex); +}; + +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; +} + +struct CDirItemsCallback_AgentOut: public IDirItemsCallback +{ + CMyComPtr FolderScanProgress; + IFolderArchiveUpdateCallback *FolderArchiveUpdateCallback; + HRESULT ErrorCode; + + CDirItemsCallback_AgentOut(): ErrorCode(S_OK), FolderArchiveUpdateCallback(NULL) {} + + HRESULT ScanError(const FString &name, DWORD systemError) + { + 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) + { + 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; + } +}; + +STDMETHODIMP 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; + 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 outArchive; + + if (GetArchive()) + { + RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive)); + } + else + { + if (formatIndex < 0) + return E_FAIL; + RINOK(codecs->CreateOutArchive(formatIndex, outArchive)); + + #ifdef EXTERNAL_CODECS + { + CMyComPtr setCompressCodecsInfo; + outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); + if (setCompressCodecsInfo) + { + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)); + } + } + #endif + } + + NFileTimeType::EEnum fileTimeType; + UInt32 value; + RINOK(outArchive->GetFileTimeType(&value)); + + switch (value) + { + case NFileTimeType::kWindows: + case NFileTimeType::kDOS: + case NFileTimeType::kUnix: + fileTimeType = NFileTimeType::EEnum(value); + break; + default: + return E_FAIL; + } + + + CObjectVector 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 updatePairs2; + + { + CRecordVector 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 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; + } + + CMyComPtr setProperties; + if (outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties) == S_OK) + { + if (m_PropNames.Size() == 0) + { + RINOK(setProperties->SetProperties(0, 0, 0)); + } + else + { + CRecordVector 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 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 >= 0 && up.NewData) + { + const CDirItem &di = dirItems.Items[up.DirIndex]; + if (!di.IsDir() && di.Size == 0) + processedItems[up.DirIndex] = 1; + } + } + } + + FOR_VECTOR (i, dirItems.Items) + if (processedItems[i] != 0) + processedPaths->Add(dirItems.GetPhyPath(i)); + } + return res; +} + +STDMETHODIMP 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 outArchive; + RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive)); + return outArchive->UpdateItems(outArchiveStream, numUpdateItems, updateCallback); +} + +STDMETHODIMP CAgent::DeleteItems(ISequentialOutStream *outArchiveStream, + const UInt32 *indices, UInt32 numItems, + IFolderArchiveUpdateCallback *updateCallback100) +{ + if (!CanUpdate()) + return E_NOTIMPL; + CRecordVector updatePairs; + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.SetCallback(updateCallback100); + CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; + CMyComPtr 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().GetItemPath2(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 updatePairs; + CDirItems dirItems; + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.SetCallback(updateCallback100); + CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; + CMyComPtr 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 updatePairs; + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.SetCallback(updateCallback100); + CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; + CMyComPtr updateCallback(updateCallbackSpec); + + CUIntVector realIndices; + _agentFolder->GetRealIndices(indices, numItems, + true, // includeAltStreams + true, // includeFolderSubItemsInFlatMode + realIndices); + + int mainRealIndex = _agentFolder->GetRealIndex(indices[0]); + + UString fullPrefix = _agentFolder->GetFullPrefix(indices[0]); + UString oldItemPath = fullPrefix + _agentFolder->GetName(indices[0]); + 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().IsItemAnti(i, up2.IsAnti)); // it must work without that line too. + + UString oldFullPath; + RINOK(GetArc().GetItemPath2(i, oldFullPath)); + + if (!IsPath1PrefixedByPath2(oldFullPath, oldItemPath)) + return E_INVALIDARG; + + up2.NewNameIndex = 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 updatePairs; + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.SetCallback(updateCallback100); + CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; + CMyComPtr 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 updatePairs; + CDirItems dirItems; + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.SetCallback(updateCallback100); + CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; + CMyComPtr 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); +} + +STDMETHODIMP 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 index 5bc7ff593..7f550f757 100644 --- a/CPP/7zip/UI/Agent/AgentProxy.cpp +++ b/CPP/7zip/UI/Agent/AgentProxy.cpp @@ -1,717 +1,717 @@ -// AgentProxy.cpp - -#include "StdAfx.h" - -// #include -#ifdef _WIN32 -#include -#else -#include -#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 "AgentProxy.h" - -using namespace NWindows; - -int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const -{ - const CRecordVector &subDirs = Dirs[dirIndex].SubDirs; - unsigned left = 0, right = subDirs.Size(); - for (;;) - { - if (left == right) - { - insertPos = left; - return -1; - } - unsigned mid = (left + right) / 2; - unsigned dirIndex2 = subDirs[mid]; - int compare = CompareFileNames(name, Dirs[dirIndex2].Name); - if (compare == 0) - return dirIndex2; - if (compare < 0) - right = mid; - else - left = mid + 1; - } -} - -int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name) const -{ - unsigned insertPos; - return FindSubDir(dirIndex, name, insertPos); -} - -unsigned CProxyArc::AddDir(unsigned dirIndex, int arcIndex, const UString &name) -{ - unsigned insertPos; - int subDirIndex = FindSubDir(dirIndex, name, insertPos); - if (subDirIndex >= 0) - { - if (arcIndex >= 0) - { - CProxyDir &item = Dirs[subDirIndex]; - if (item.ArcIndex < 0) - item.ArcIndex = arcIndex; - } - return subDirIndex; - } - subDirIndex = Dirs.Size(); - Dirs[dirIndex].SubDirs.Insert(insertPos, subDirIndex); - CProxyDir &item = Dirs.AddNew(); - - item.NameLen = name.Len(); - item.Name = new wchar_t[item.NameLen + 1]; - MyStringCopy((wchar_t *)item.Name, name); - - item.ArcIndex = arcIndex; - item.ParentDir = dirIndex; - return subDirIndex; -} - -void CProxyDir::Clear() -{ - SubDirs.Clear(); - SubFiles.Clear(); -} - -void CProxyArc::GetDirPathParts(int dirIndex, UStringVector &pathParts) const -{ - pathParts.Clear(); - while (dirIndex >= 0) - { - const CProxyDir &dir = Dirs[dirIndex]; - dirIndex = dir.ParentDir; - if (dirIndex < 0) - break; - pathParts.Insert(0, dir.Name); - } -} - -UString CProxyArc::GetDirPath_as_Prefix(int dirIndex) const -{ - UString s; - while (dirIndex >= 0) - { - const CProxyDir &dir = Dirs[dirIndex]; - dirIndex = dir.ParentDir; - if (dirIndex < 0) - break; - s.InsertAtFront(WCHAR_PATH_SEPARATOR); - s.Insert(0, dir.Name); - } - return s; -} - -void CProxyArc::AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const -{ - const CProxyDir &dir = Dirs[dirIndex]; - if (dir.IsLeaf()) - realIndices.Add(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 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) - { - UInt64 currentItemIndex = i; - RINOK(progress->SetCompleted(¤tItemIndex)); - } - - const wchar_t *s = NULL; - unsigned len = 0; - bool isPtrName = false; - - #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 (!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.GetDefaultItemPath(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++) - { - wchar_t c = s[j]; - if (c == WCHAR_PATH_SEPARATOR || c == L'/') - { - const unsigned kLevelLimit = 1 << 10; - if (numLevels <= kLevelLimit) - { - if (numLevels == kLevelLimit) - name = "[LONG_PATH]"; - else - name.SetFrom(s + namePos, j - namePos); - 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 = new wchar_t[f.NameLen + 1]; - f.NeedDeleteName = true; - MyStringCopy((wchar_t *)f.Name, s); - } - - if (isDir) - { - name = s; - 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(int 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[dir.ArcIndex]; - if (pathParts.IsEmpty() && dirIndex == file.AltDirIndex) - isAltStreamDir = true; - pathParts.Insert(0, file.Name); - int par = file.Parent; - if (par < 0) - break; - dirIndex = Files[par].DirIndex; - } -} - -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[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[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 >= 0) - AddRealIndices_of_Dir(file.DirIndex, includeAltStreams, realIndices); - if (includeAltStreams && file.AltDirIndex >= 0) - AddRealIndices_of_Dir(file.AltDirIndex, includeAltStreams, realIndices); -} - -void CProxyArc2::AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const -{ - const CRecordVector &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 < 0) - { - dir.NumSubFiles++; - } - else - { - dir.NumSubDirs++; - CProxyDir2 &f = Dirs[subFile.DirIndex]; - f.PathPrefix = dir.PathPrefix + subFile.Name + WCHAR_PATH_SEPARATOR; - CalculateSizes(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 < 0) - { - // dir.NumSubFiles++; - } - else - { - // dir.NumSubDirs++; - CProxyDir2 &f = Dirs[subFile.AltDirIndex]; - f.PathPrefix = dir.PathPrefix + subFile.Name + L':'; - CalculateSizes(subFile.AltDirIndex, archive); - } - } -} - - -bool CProxyArc2::IsThere_SubDir(unsigned dirIndex, const UString &name) const -{ - const CRecordVector &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(¤tItemIndex)); - } - - 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 = new wchar_t[file.NameLen + 1]; - file.NeedDeleteName = true; - wmemcpy((wchar_t *)file.Name, tempUString.Ptr(), file.NameLen + 1); - } - 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 = new wchar_t[file.NameLen + 1]; - file.NeedDeleteName = true; - wmemcpy((wchar_t *)file.Name, s, file.NameLen + 1); - } - - 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 = Dirs.Size(); - CProxyDir2 &dir = Dirs.AddNew(); - dir.ArcIndex = 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 < 0) - dirIndex = k_Proxy2_AltRootDirIndex; - else - { - int &folderIndex2 = Files[file.Parent].AltDirIndex; - if (folderIndex2 < 0) - { - folderIndex2 = Dirs.Size(); - CProxyDir2 &dir = Dirs.AddNew(); - dir.ArcIndex = file.Parent; - } - dirIndex = folderIndex2; - } - } - else - { - if (file.Parent < 0) - dirIndex = k_Proxy2_RootDirIndex; - else - { - dirIndex = Files[file.Parent].DirIndex; - if (dirIndex < 0) - 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 < 0) - continue; - if (CompareFileNames(file.Name, name) == 0) - return i; - } - return -1; -} +// AgentProxy.cpp + +#include "StdAfx.h" + +// #include +#ifdef _WIN32 +#include +#else +#include +#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 "AgentProxy.h" + +using namespace NWindows; + +int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const +{ + const CRecordVector &subDirs = Dirs[dirIndex].SubDirs; + unsigned left = 0, right = subDirs.Size(); + for (;;) + { + if (left == right) + { + insertPos = left; + return -1; + } + unsigned mid = (left + right) / 2; + unsigned dirIndex2 = subDirs[mid]; + int compare = CompareFileNames(name, Dirs[dirIndex2].Name); + if (compare == 0) + return dirIndex2; + if (compare < 0) + right = mid; + else + left = mid + 1; + } +} + +int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name) const +{ + unsigned insertPos; + return FindSubDir(dirIndex, name, insertPos); +} + +unsigned CProxyArc::AddDir(unsigned dirIndex, int arcIndex, const UString &name) +{ + unsigned insertPos; + int subDirIndex = FindSubDir(dirIndex, name, insertPos); + if (subDirIndex >= 0) + { + if (arcIndex >= 0) + { + CProxyDir &item = Dirs[subDirIndex]; + if (item.ArcIndex < 0) + item.ArcIndex = arcIndex; + } + return subDirIndex; + } + subDirIndex = Dirs.Size(); + Dirs[dirIndex].SubDirs.Insert(insertPos, subDirIndex); + CProxyDir &item = Dirs.AddNew(); + + item.NameLen = name.Len(); + item.Name = new wchar_t[item.NameLen + 1]; + MyStringCopy((wchar_t *)item.Name, name); + + item.ArcIndex = arcIndex; + item.ParentDir = dirIndex; + return subDirIndex; +} + +void CProxyDir::Clear() +{ + SubDirs.Clear(); + SubFiles.Clear(); +} + +void CProxyArc::GetDirPathParts(int dirIndex, UStringVector &pathParts) const +{ + pathParts.Clear(); + while (dirIndex >= 0) + { + const CProxyDir &dir = Dirs[dirIndex]; + dirIndex = dir.ParentDir; + if (dirIndex < 0) + break; + pathParts.Insert(0, dir.Name); + } +} + +UString CProxyArc::GetDirPath_as_Prefix(int dirIndex) const +{ + UString s; + while (dirIndex >= 0) + { + const CProxyDir &dir = Dirs[dirIndex]; + dirIndex = dir.ParentDir; + if (dirIndex < 0) + break; + s.InsertAtFront(WCHAR_PATH_SEPARATOR); + s.Insert(0, dir.Name); + } + return s; +} + +void CProxyArc::AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const +{ + const CProxyDir &dir = Dirs[dirIndex]; + if (dir.IsLeaf()) + realIndices.Add(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 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) + { + UInt64 currentItemIndex = i; + RINOK(progress->SetCompleted(¤tItemIndex)); + } + + const wchar_t *s = NULL; + unsigned len = 0; + bool isPtrName = false; + + #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 (!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.GetDefaultItemPath(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++) + { + wchar_t c = s[j]; + if (c == WCHAR_PATH_SEPARATOR || c == L'/') + { + const unsigned kLevelLimit = 1 << 10; + if (numLevels <= kLevelLimit) + { + if (numLevels == kLevelLimit) + name = "[LONG_PATH]"; + else + name.SetFrom(s + namePos, j - namePos); + 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 = new wchar_t[f.NameLen + 1]; + f.NeedDeleteName = true; + MyStringCopy((wchar_t *)f.Name, s); + } + + if (isDir) + { + name = s; + 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(int 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[dir.ArcIndex]; + if (pathParts.IsEmpty() && dirIndex == file.AltDirIndex) + isAltStreamDir = true; + pathParts.Insert(0, file.Name); + int par = file.Parent; + if (par < 0) + break; + dirIndex = Files[par].DirIndex; + } +} + +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[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[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 >= 0) + AddRealIndices_of_Dir(file.DirIndex, includeAltStreams, realIndices); + if (includeAltStreams && file.AltDirIndex >= 0) + AddRealIndices_of_Dir(file.AltDirIndex, includeAltStreams, realIndices); +} + +void CProxyArc2::AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const +{ + const CRecordVector &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 < 0) + { + dir.NumSubFiles++; + } + else + { + dir.NumSubDirs++; + CProxyDir2 &f = Dirs[subFile.DirIndex]; + f.PathPrefix = dir.PathPrefix + subFile.Name + WCHAR_PATH_SEPARATOR; + CalculateSizes(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 < 0) + { + // dir.NumSubFiles++; + } + else + { + // dir.NumSubDirs++; + CProxyDir2 &f = Dirs[subFile.AltDirIndex]; + f.PathPrefix = dir.PathPrefix + subFile.Name + L':'; + CalculateSizes(subFile.AltDirIndex, archive); + } + } +} + + +bool CProxyArc2::IsThere_SubDir(unsigned dirIndex, const UString &name) const +{ + const CRecordVector &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(¤tItemIndex)); + } + + 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 = new wchar_t[file.NameLen + 1]; + file.NeedDeleteName = true; + wmemcpy((wchar_t *)file.Name, tempUString.Ptr(), file.NameLen + 1); + } + 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 = new wchar_t[file.NameLen + 1]; + file.NeedDeleteName = true; + wmemcpy((wchar_t *)file.Name, s, file.NameLen + 1); + } + + 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 = Dirs.Size(); + CProxyDir2 &dir = Dirs.AddNew(); + dir.ArcIndex = 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 < 0) + dirIndex = k_Proxy2_AltRootDirIndex; + else + { + int &folderIndex2 = Files[file.Parent].AltDirIndex; + if (folderIndex2 < 0) + { + folderIndex2 = Dirs.Size(); + CProxyDir2 &dir = Dirs.AddNew(); + dir.ArcIndex = file.Parent; + } + dirIndex = folderIndex2; + } + } + else + { + if (file.Parent < 0) + dirIndex = k_Proxy2_RootDirIndex; + else + { + dirIndex = Files[file.Parent].DirIndex; + if (dirIndex < 0) + 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 < 0) + continue; + if (CompareFileNames(file.Name, name) == 0) + return i; + } + return -1; +} diff --git a/CPP/7zip/UI/Agent/AgentProxy.h b/CPP/7zip/UI/Agent/AgentProxy.h index 8bb256991..490126769 100644 --- a/CPP/7zip/UI/Agent/AgentProxy.h +++ b/CPP/7zip/UI/Agent/AgentProxy.h @@ -1,162 +1,162 @@ -// AgentProxy.h - -#ifndef __AGENT_PROXY_H -#define __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 *)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 SubDirs; - CRecordVector SubFiles; - - UInt64 Size; - UInt64 PackSize; - UInt32 Crc; - UInt32 NumSubDirs; - UInt32 NumSubFiles; - bool CrcIsDefined; - - CProxyDir(): Name(NULL), NameLen(0), ParentDir(-1) {}; - ~CProxyDir() { delete [](wchar_t *)Name; } - - void Clear(); - bool IsLeaf() const { return ArcIndex >= 0; } -}; - -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 Dirs; // Dirs[0] - root - CObjArray 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(int dirIndex, UStringVector &pathParts) const; - // returns full path of Dirs[dirIndex], including back slash - UString GetDirPath_as_Prefix(int 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 >= 0; } - CProxyFile2(): - DirIndex(-1), AltDirIndex(-1), Parent(-1), - Name(NULL), NameLen(0), - NeedDeleteName(false), - Ignore(false), - IsAltStream(false) - {} - ~CProxyFile2() - { - if (NeedDeleteName) - delete [](wchar_t *)Name; - } -}; - -struct CProxyDir2 -{ - int ArcIndex; // = -1 for root folders, index in proxy->Files[] - CRecordVector 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 Dirs; // Dirs[0] - root folder - // Dirs[1] - for alt streams of root dir - CObjArray Files; // all items from archive in same order - - bool IsThere_SubDir(unsigned dirIndex, const UString &name) const; - - void GetDirPathParts(int 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 < 0) - 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 +// AgentProxy.h + +#ifndef __AGENT_PROXY_H +#define __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 *)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 SubDirs; + CRecordVector SubFiles; + + UInt64 Size; + UInt64 PackSize; + UInt32 Crc; + UInt32 NumSubDirs; + UInt32 NumSubFiles; + bool CrcIsDefined; + + CProxyDir(): Name(NULL), NameLen(0), ParentDir(-1) {}; + ~CProxyDir() { delete [](wchar_t *)Name; } + + void Clear(); + bool IsLeaf() const { return ArcIndex >= 0; } +}; + +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 Dirs; // Dirs[0] - root + CObjArray 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(int dirIndex, UStringVector &pathParts) const; + // returns full path of Dirs[dirIndex], including back slash + UString GetDirPath_as_Prefix(int 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 >= 0; } + CProxyFile2(): + DirIndex(-1), AltDirIndex(-1), Parent(-1), + Name(NULL), NameLen(0), + NeedDeleteName(false), + Ignore(false), + IsAltStream(false) + {} + ~CProxyFile2() + { + if (NeedDeleteName) + delete [](wchar_t *)Name; + } +}; + +struct CProxyDir2 +{ + int ArcIndex; // = -1 for root folders, index in proxy->Files[] + CRecordVector 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 Dirs; // Dirs[0] - root folder + // Dirs[1] - for alt streams of root dir + CObjArray Files; // all items from archive in same order + + bool IsThere_SubDir(unsigned dirIndex, const UString &name) const; + + void GetDirPathParts(int 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 < 0) + 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 index f13d24428..a20b4f240 100644 --- a/CPP/7zip/UI/Agent/ArchiveFolder.cpp +++ b/CPP/7zip/UI/Agent/ArchiveFolder.cpp @@ -1,44 +1,44 @@ -// Agent/ArchiveFolder.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" - -#include "../Common/ArchiveExtractCallback.h" - -#include "Agent.h" - -/* -STDMETHODIMP CAgentFolder::SetReplaceAltStreamCharsMode(Int32 replaceAltStreamCharsMode) -{ - _replaceAltStreamCharsMode = replaceAltStreamCharsMode; - return S_OK; -} -*/ - -STDMETHODIMP 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 extractCallback2; - { - CMyComPtr 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 -} +// Agent/ArchiveFolder.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" + +#include "../Common/ArchiveExtractCallback.h" + +#include "Agent.h" + +/* +STDMETHODIMP CAgentFolder::SetReplaceAltStreamCharsMode(Int32 replaceAltStreamCharsMode) +{ + _replaceAltStreamCharsMode = replaceAltStreamCharsMode; + return S_OK; +} +*/ + +STDMETHODIMP 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 extractCallback2; + { + CMyComPtr 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 index ac05a3b86..62d5b1f86 100644 --- a/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp +++ b/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp @@ -1,141 +1,141 @@ -// Agent/ArchiveFolderOpen.cpp - -#include "StdAfx.h" - -#include "../../../Windows/DLL.h" - -#include "Agent.h" - -void CArchiveFolderManager::LoadFormats() -{ - LoadGlobalCodecs(); -} - -int CArchiveFolderManager::FindFormat(const UString &type) -{ - FOR_VECTOR (i, g_CodecsObj->Formats) - if (type.IsEqualTo_NoCase(g_CodecsObj->Formats[i].Name)) - return i; - return -1; -} - -STDMETHODIMP CArchiveFolderManager::OpenFolderFile(IInStream *inStream, - const wchar_t *filePath, const wchar_t *arcFormat, - IFolderFolder **resultFolder, IProgress *progress) -{ - CMyComPtr openArchiveCallback; - if (progress) - { - CMyComPtr progressWrapper = progress; - progressWrapper.QueryInterface(IID_IArchiveOpenCallback, &openArchiveCallback); - } - CAgent *agent = new CAgent(); - CMyComPtr archive = agent; - RINOK(agent->Open(inStream, filePath, arcFormat, NULL, openArchiveCallback)); - return agent->BindToRootFolder(resultFolder); -} - -/* -HRESULT CAgent::FolderReOpen( - IArchiveOpenCallback *openArchiveCallback) -{ - return ReOpenArchive(_archive, _archiveFilePath); -} -*/ - - -/* -STDMETHODIMP 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; - } -} - -STDMETHODIMP CArchiveFolderManager::GetExtensions(BSTR *extensions) -{ - LoadFormats(); - *extensions = 0; - UString res; - - #ifdef EXTERNAL_CODECS - - FOR_VECTOR (i, g_CodecsObj->Libs) - AddIconExt(g_CodecsObj->Libs[i], res); - - #endif - - AddIconExt(g_CodecsObj->InternalIcons, res); - return StringToBstr(res, extensions); -} - -STDMETHODIMP CArchiveFolderManager::GetIconPath(const wchar_t *ext, BSTR *iconPath, Int32 *iconIndex) -{ - *iconPath = 0; - *iconIndex = 0; - - LoadFormats(); - - #ifdef EXTERNAL_CODECS - - FOR_VECTOR (i, g_CodecsObj->Libs) - { - const CCodecLib &lib = g_CodecsObj->Libs[i]; - int ii; - if (lib.FindIconIndex(ext, ii)) - { - *iconIndex = ii; - return StringToBstr(fs2us(lib.Path), iconPath); - } - } - - #endif - - int ii; - if (g_CodecsObj->InternalIcons.FindIconIndex(ext, ii)) - { - FString path; - if (NWindows::NDLL::MyGetModuleFileName(path)) - { - *iconIndex = ii; - return StringToBstr(fs2us(path), iconPath); - } - } - return S_OK; -} - -/* -STDMETHODIMP 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); -} -STDMETHODIMP CArchiveFolderManager::CreateFolderFile(const wchar_t * type, - const wchar_t * filePath, IProgress progress) -{ - return E_NOTIMPL; -} -*/ +// Agent/ArchiveFolderOpen.cpp + +#include "StdAfx.h" + +#include "../../../Windows/DLL.h" + +#include "Agent.h" + +void CArchiveFolderManager::LoadFormats() +{ + LoadGlobalCodecs(); +} + +int CArchiveFolderManager::FindFormat(const UString &type) +{ + FOR_VECTOR (i, g_CodecsObj->Formats) + if (type.IsEqualTo_NoCase(g_CodecsObj->Formats[i].Name)) + return i; + return -1; +} + +STDMETHODIMP CArchiveFolderManager::OpenFolderFile(IInStream *inStream, + const wchar_t *filePath, const wchar_t *arcFormat, + IFolderFolder **resultFolder, IProgress *progress) +{ + CMyComPtr openArchiveCallback; + if (progress) + { + CMyComPtr progressWrapper = progress; + progressWrapper.QueryInterface(IID_IArchiveOpenCallback, &openArchiveCallback); + } + CAgent *agent = new CAgent(); + CMyComPtr archive = agent; + RINOK(agent->Open(inStream, filePath, arcFormat, NULL, openArchiveCallback)); + return agent->BindToRootFolder(resultFolder); +} + +/* +HRESULT CAgent::FolderReOpen( + IArchiveOpenCallback *openArchiveCallback) +{ + return ReOpenArchive(_archive, _archiveFilePath); +} +*/ + + +/* +STDMETHODIMP 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; + } +} + +STDMETHODIMP CArchiveFolderManager::GetExtensions(BSTR *extensions) +{ + LoadFormats(); + *extensions = 0; + UString res; + + #ifdef EXTERNAL_CODECS + + FOR_VECTOR (i, g_CodecsObj->Libs) + AddIconExt(g_CodecsObj->Libs[i], res); + + #endif + + AddIconExt(g_CodecsObj->InternalIcons, res); + return StringToBstr(res, extensions); +} + +STDMETHODIMP CArchiveFolderManager::GetIconPath(const wchar_t *ext, BSTR *iconPath, Int32 *iconIndex) +{ + *iconPath = 0; + *iconIndex = 0; + + LoadFormats(); + + #ifdef EXTERNAL_CODECS + + FOR_VECTOR (i, g_CodecsObj->Libs) + { + const CCodecLib &lib = g_CodecsObj->Libs[i]; + int ii; + if (lib.FindIconIndex(ext, ii)) + { + *iconIndex = ii; + return StringToBstr(fs2us(lib.Path), iconPath); + } + } + + #endif + + int ii; + if (g_CodecsObj->InternalIcons.FindIconIndex(ext, ii)) + { + FString path; + if (NWindows::NDLL::MyGetModuleFileName(path)) + { + *iconIndex = ii; + return StringToBstr(fs2us(path), iconPath); + } + } + return S_OK; +} + +/* +STDMETHODIMP 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); +} +STDMETHODIMP CArchiveFolderManager::CreateFolderFile(const wchar_t * type, + const wchar_t * filePath, IProgress progress) +{ + return E_NOTIMPL; +} +*/ diff --git a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp index 9af33f5b6..ecbfe58b3 100644 --- a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp +++ b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp @@ -1,373 +1,373 @@ -// 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 DeleteEmptyFolderAndEmptySubFolders(const FString &path) -{ - NFind::CFileInfo fileInfo; - FString pathPrefix = path; - pathPrefix.Add_PathSepar(); - { - 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 readonly for folders - 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 (!_agentSpec->CanUpdate()) - return E_NOTIMPL; - - CMyComPtr 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 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 (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 (int 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(); - _agentSpec->Close(); - - // before 9.26: if there was error for MoveToOriginal archive was closed. - // now: we reopen archive after close - - // m_FolderItem = NULL; - - 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)) - DeleteEmptyFolderAndEmptySubFolders(fs); - } - } - } - - { - CMyComPtr openCallback; - if (updateCallback100) - updateCallback100->QueryInterface(IID_IArchiveOpenCallback, (void **)&openCallback); - RINOK(_agentSpec->ReOpen(openCallback)); - } - - // CAgent::ReOpen() deletes _proxy and _proxy2 - _items.Clear(); - _proxy = NULL; - _proxy2 = NULL; - _proxyDirIndex = k_Proxy_RootDirIndex; - _isAltStreamFolder = false; - - - // ---------- Restore FolderItem ---------- - - CMyComPtr archiveFolder; - RINOK(_agentSpec->BindToRootFolder(&archiveFolder)); - - // CAgent::BindToRootFolder() changes _proxy and _proxy2 - _proxy = _agentSpec->_proxy; - _proxy2 = _agentSpec->_proxy2; - - if (_proxy) - { - FOR_VECTOR (i, pathParts) - { - int next = _proxy->FindSubDir(_proxyDirIndex, pathParts[i]); - if (next < 0) - break; - _proxyDirIndex = next; - } - } - - if (_proxy2) - { - if (pathParts.IsEmpty() && isAltStreamFolder) - { - _proxyDirIndex = k_Proxy2_AltRootDirIndex; - } - else FOR_VECTOR (i, pathParts) - { - bool dirOnly = (i + 1 < pathParts.Size() || !isAltStreamFolder); - int index = _proxy2->FindItem(_proxyDirIndex, pathParts[i], dirOnly); - if (index < 0) - break; - - const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]]; - - if (dirOnly) - _proxyDirIndex = file.DirIndex; - else - { - if (file.AltDirIndex >= 0) - _proxyDirIndex = file.AltDirIndex; - break; - } - } - } - - /* - if (pathParts.IsEmpty() && isAltStreamFolder) - { - CMyComPtr folderAltStreams; - archiveFolder.QueryInterface(IID_IFolderAltStreams, &folderAltStreams); - if (folderAltStreams) - { - CMyComPtr newFolder; - folderAltStreams->BindToAltStreams((UInt32)(Int32)-1, &newFolder); - if (newFolder) - archiveFolder = newFolder; - } - } - - FOR_VECTOR (i, pathParts) - { - CMyComPtr newFolder; - - if (isAltStreamFolder && i == pathParts.Size() - 1) - { - CMyComPtr 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 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; - } -} - - - -STDMETHODIMP 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 -} - -STDMETHODIMP 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 -} - -STDMETHODIMP 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 -} - -STDMETHODIMP 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) >= 0) - return ERROR_ALREADY_EXISTS; - } - - return CommonUpdateOperation(AGENT_OP_CreateFolder, false, name, NULL, NULL, 0, progress); - COM_TRY_END -} - -STDMETHODIMP 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 -} - -STDMETHODIMP CAgentFolder::CreateFile(const wchar_t * /* name */, IProgress * /* progress */) -{ - return E_NOTIMPL; -} - -STDMETHODIMP 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 -} +// 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 DeleteEmptyFolderAndEmptySubFolders(const FString &path) +{ + NFind::CFileInfo fileInfo; + FString pathPrefix = path; + pathPrefix.Add_PathSepar(); + { + 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 readonly for folders + 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 (!_agentSpec->CanUpdate()) + return E_NOTIMPL; + + CMyComPtr 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 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 (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 (int 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(); + _agentSpec->Close(); + + // before 9.26: if there was error for MoveToOriginal archive was closed. + // now: we reopen archive after close + + // m_FolderItem = NULL; + + 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)) + DeleteEmptyFolderAndEmptySubFolders(fs); + } + } + } + + { + CMyComPtr openCallback; + if (updateCallback100) + updateCallback100->QueryInterface(IID_IArchiveOpenCallback, (void **)&openCallback); + RINOK(_agentSpec->ReOpen(openCallback)); + } + + // CAgent::ReOpen() deletes _proxy and _proxy2 + _items.Clear(); + _proxy = NULL; + _proxy2 = NULL; + _proxyDirIndex = k_Proxy_RootDirIndex; + _isAltStreamFolder = false; + + + // ---------- Restore FolderItem ---------- + + CMyComPtr archiveFolder; + RINOK(_agentSpec->BindToRootFolder(&archiveFolder)); + + // CAgent::BindToRootFolder() changes _proxy and _proxy2 + _proxy = _agentSpec->_proxy; + _proxy2 = _agentSpec->_proxy2; + + if (_proxy) + { + FOR_VECTOR (i, pathParts) + { + int next = _proxy->FindSubDir(_proxyDirIndex, pathParts[i]); + if (next < 0) + break; + _proxyDirIndex = next; + } + } + + if (_proxy2) + { + if (pathParts.IsEmpty() && isAltStreamFolder) + { + _proxyDirIndex = k_Proxy2_AltRootDirIndex; + } + else FOR_VECTOR (i, pathParts) + { + bool dirOnly = (i + 1 < pathParts.Size() || !isAltStreamFolder); + int index = _proxy2->FindItem(_proxyDirIndex, pathParts[i], dirOnly); + if (index < 0) + break; + + const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]]; + + if (dirOnly) + _proxyDirIndex = file.DirIndex; + else + { + if (file.AltDirIndex >= 0) + _proxyDirIndex = file.AltDirIndex; + break; + } + } + } + + /* + if (pathParts.IsEmpty() && isAltStreamFolder) + { + CMyComPtr folderAltStreams; + archiveFolder.QueryInterface(IID_IFolderAltStreams, &folderAltStreams); + if (folderAltStreams) + { + CMyComPtr newFolder; + folderAltStreams->BindToAltStreams((UInt32)(Int32)-1, &newFolder); + if (newFolder) + archiveFolder = newFolder; + } + } + + FOR_VECTOR (i, pathParts) + { + CMyComPtr newFolder; + + if (isAltStreamFolder && i == pathParts.Size() - 1) + { + CMyComPtr 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 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; + } +} + + + +STDMETHODIMP 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 +} + +STDMETHODIMP 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 +} + +STDMETHODIMP 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 +} + +STDMETHODIMP 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) >= 0) + return ERROR_ALREADY_EXISTS; + } + + return CommonUpdateOperation(AGENT_OP_CreateFolder, false, name, NULL, NULL, 0, progress); + COM_TRY_END +} + +STDMETHODIMP 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 +} + +STDMETHODIMP CAgentFolder::CreateFile(const wchar_t * /* name */, IProgress * /* progress */) +{ + return E_NOTIMPL; +} + +STDMETHODIMP 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 index 625463a41..565e37b00 100644 --- a/CPP/7zip/UI/Agent/IFolderArchive.h +++ b/CPP/7zip/UI/Agent/IFolderArchive.h @@ -1,119 +1,119 @@ -// IFolderArchive.h - -#ifndef __IFOLDER_ARCHIVE_H -#define __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" - -#define FOLDER_ARCHIVE_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 0x01, x) -#define FOLDER_ARCHIVE_INTERFACE(i, x) FOLDER_ARCHIVE_INTERFACE_SUB(i, IUnknown, x) - -/* ---------- 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 INTERFACE_IArchiveFolder(x) \ - STDMETHOD(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) x; \ - -FOLDER_ARCHIVE_INTERFACE(IArchiveFolder, 0x0D) -{ - INTERFACE_IArchiveFolder(PURE) -}; - - -/* ---------- IInFolderArchive ---------- -IInFolderArchive is implemented by CAgent (Agent/Agent.h) -IInFolderArchive Is used by FAR/Plugin -*/ - -#define INTERFACE_IInFolderArchive(x) \ - STDMETHOD(Open)(IInStream *inStream, const wchar_t *filePath, const wchar_t *arcFormat, BSTR *archiveTypeRes, IArchiveOpenCallback *openArchiveCallback) x; \ - STDMETHOD(ReOpen)(IArchiveOpenCallback *openArchiveCallback) x; \ - STDMETHOD(Close)() x; \ - STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties) x; \ - STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \ - STDMETHOD(BindToRootFolder)(IFolderFolder **resultFolder) x; \ - STDMETHOD(Extract)(NExtract::NPathMode::EEnum pathMode, \ - NExtract::NOverwriteMode::EEnum overwriteMode, const wchar_t *path, \ - Int32 testMode, IFolderArchiveExtractCallback *extractCallback2) x; \ - -FOLDER_ARCHIVE_INTERFACE(IInFolderArchive, 0x0E) -{ - INTERFACE_IInFolderArchive(PURE) -}; - -#define INTERFACE_IFolderArchiveUpdateCallback(x) \ - STDMETHOD(CompressOperation)(const wchar_t *name) x; \ - STDMETHOD(DeleteOperation)(const wchar_t *name) x; \ - STDMETHOD(OperationResult)(Int32 opRes) x; \ - STDMETHOD(UpdateErrorMessage)(const wchar_t *message) x; \ - STDMETHOD(SetNumFiles)(UInt64 numFiles) x; \ - -FOLDER_ARCHIVE_INTERFACE_SUB(IFolderArchiveUpdateCallback, IProgress, 0x0B) -{ - INTERFACE_IFolderArchiveUpdateCallback(PURE) -}; - -#define INTERFACE_IOutFolderArchive(x) \ - STDMETHOD(SetFolder)(IFolderFolder *folder) x; \ - STDMETHOD(SetFiles)(const wchar_t *folderPrefix, const wchar_t * const *names, UInt32 numNames) x; \ - STDMETHOD(DeleteItems)(ISequentialOutStream *outArchiveStream, \ - const UInt32 *indices, UInt32 numItems, IFolderArchiveUpdateCallback *updateCallback) x; \ - STDMETHOD(DoOperation)( \ - FStringVector *requestedPaths, \ - FStringVector *processedPaths, \ - CCodecs *codecs, int index, \ - ISequentialOutStream *outArchiveStream, const Byte *stateActions, const wchar_t *sfxModule, \ - IFolderArchiveUpdateCallback *updateCallback) x; \ - STDMETHOD(DoOperation2)( \ - FStringVector *requestedPaths, \ - FStringVector *processedPaths, \ - ISequentialOutStream *outArchiveStream, const Byte *stateActions, const wchar_t *sfxModule, \ - IFolderArchiveUpdateCallback *updateCallback) x; \ - -FOLDER_ARCHIVE_INTERFACE(IOutFolderArchive, 0x0F) -{ - INTERFACE_IOutFolderArchive(PURE) -}; - - -#define INTERFACE_IFolderArchiveUpdateCallback2(x) \ - STDMETHOD(OpenFileError)(const wchar_t *path, HRESULT errorCode) x; \ - STDMETHOD(ReadingFileError)(const wchar_t *path, HRESULT errorCode) x; \ - STDMETHOD(ReportExtractResult)(Int32 opRes, Int32 isEncrypted, const wchar_t *path) x; \ - STDMETHOD(ReportUpdateOperation)(UInt32 notifyOp, const wchar_t *path, Int32 isDir) x; \ - -FOLDER_ARCHIVE_INTERFACE(IFolderArchiveUpdateCallback2, 0x10) -{ - INTERFACE_IFolderArchiveUpdateCallback2(PURE) -}; - - -#define INTERFACE_IFolderScanProgress(x) \ - STDMETHOD(ScanError)(const wchar_t *path, HRESULT errorCode) x; \ - STDMETHOD(ScanProgress)(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 isDir) x; \ - -FOLDER_ARCHIVE_INTERFACE(IFolderScanProgress, 0x11) -{ - INTERFACE_IFolderScanProgress(PURE) -}; - -#endif +// IFolderArchive.h + +#ifndef __IFOLDER_ARCHIVE_H +#define __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" + +#define FOLDER_ARCHIVE_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 0x01, x) +#define FOLDER_ARCHIVE_INTERFACE(i, x) FOLDER_ARCHIVE_INTERFACE_SUB(i, IUnknown, x) + +/* ---------- 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 INTERFACE_IArchiveFolder(x) \ + STDMETHOD(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) x; \ + +FOLDER_ARCHIVE_INTERFACE(IArchiveFolder, 0x0D) +{ + INTERFACE_IArchiveFolder(PURE) +}; + + +/* ---------- IInFolderArchive ---------- +IInFolderArchive is implemented by CAgent (Agent/Agent.h) +IInFolderArchive Is used by FAR/Plugin +*/ + +#define INTERFACE_IInFolderArchive(x) \ + STDMETHOD(Open)(IInStream *inStream, const wchar_t *filePath, const wchar_t *arcFormat, BSTR *archiveTypeRes, IArchiveOpenCallback *openArchiveCallback) x; \ + STDMETHOD(ReOpen)(IArchiveOpenCallback *openArchiveCallback) x; \ + STDMETHOD(Close)() x; \ + STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties) x; \ + STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \ + STDMETHOD(BindToRootFolder)(IFolderFolder **resultFolder) x; \ + STDMETHOD(Extract)(NExtract::NPathMode::EEnum pathMode, \ + NExtract::NOverwriteMode::EEnum overwriteMode, const wchar_t *path, \ + Int32 testMode, IFolderArchiveExtractCallback *extractCallback2) x; \ + +FOLDER_ARCHIVE_INTERFACE(IInFolderArchive, 0x0E) +{ + INTERFACE_IInFolderArchive(PURE) +}; + +#define INTERFACE_IFolderArchiveUpdateCallback(x) \ + STDMETHOD(CompressOperation)(const wchar_t *name) x; \ + STDMETHOD(DeleteOperation)(const wchar_t *name) x; \ + STDMETHOD(OperationResult)(Int32 opRes) x; \ + STDMETHOD(UpdateErrorMessage)(const wchar_t *message) x; \ + STDMETHOD(SetNumFiles)(UInt64 numFiles) x; \ + +FOLDER_ARCHIVE_INTERFACE_SUB(IFolderArchiveUpdateCallback, IProgress, 0x0B) +{ + INTERFACE_IFolderArchiveUpdateCallback(PURE) +}; + +#define INTERFACE_IOutFolderArchive(x) \ + STDMETHOD(SetFolder)(IFolderFolder *folder) x; \ + STDMETHOD(SetFiles)(const wchar_t *folderPrefix, const wchar_t * const *names, UInt32 numNames) x; \ + STDMETHOD(DeleteItems)(ISequentialOutStream *outArchiveStream, \ + const UInt32 *indices, UInt32 numItems, IFolderArchiveUpdateCallback *updateCallback) x; \ + STDMETHOD(DoOperation)( \ + FStringVector *requestedPaths, \ + FStringVector *processedPaths, \ + CCodecs *codecs, int index, \ + ISequentialOutStream *outArchiveStream, const Byte *stateActions, const wchar_t *sfxModule, \ + IFolderArchiveUpdateCallback *updateCallback) x; \ + STDMETHOD(DoOperation2)( \ + FStringVector *requestedPaths, \ + FStringVector *processedPaths, \ + ISequentialOutStream *outArchiveStream, const Byte *stateActions, const wchar_t *sfxModule, \ + IFolderArchiveUpdateCallback *updateCallback) x; \ + +FOLDER_ARCHIVE_INTERFACE(IOutFolderArchive, 0x0F) +{ + INTERFACE_IOutFolderArchive(PURE) +}; + + +#define INTERFACE_IFolderArchiveUpdateCallback2(x) \ + STDMETHOD(OpenFileError)(const wchar_t *path, HRESULT errorCode) x; \ + STDMETHOD(ReadingFileError)(const wchar_t *path, HRESULT errorCode) x; \ + STDMETHOD(ReportExtractResult)(Int32 opRes, Int32 isEncrypted, const wchar_t *path) x; \ + STDMETHOD(ReportUpdateOperation)(UInt32 notifyOp, const wchar_t *path, Int32 isDir) x; \ + +FOLDER_ARCHIVE_INTERFACE(IFolderArchiveUpdateCallback2, 0x10) +{ + INTERFACE_IFolderArchiveUpdateCallback2(PURE) +}; + + +#define INTERFACE_IFolderScanProgress(x) \ + STDMETHOD(ScanError)(const wchar_t *path, HRESULT errorCode) x; \ + STDMETHOD(ScanProgress)(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 isDir) x; \ + +FOLDER_ARCHIVE_INTERFACE(IFolderScanProgress, 0x11) +{ + INTERFACE_IFolderScanProgress(PURE) +}; + +#endif diff --git a/CPP/7zip/UI/Agent/StdAfx.h b/CPP/7zip/UI/Agent/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/UI/Agent/StdAfx.h +++ b/CPP/7zip/UI/Agent/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp b/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp index cb4ec18ae..d450eefec 100644 --- a/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp +++ b/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp @@ -1,208 +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) -{ - 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) -{ - 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::ReportUpdateOpeartion(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 _NO_CRYPTO - password - #endif - ) -{ - #ifndef _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 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); -} +// 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) +{ + 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) +{ + 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::ReportUpdateOpeartion(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 _NO_CRYPTO + password + #endif + ) +{ + #ifndef _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 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 index 3390ebcb6..4da7693c5 100644 --- a/CPP/7zip/UI/Agent/UpdateCallbackAgent.h +++ b/CPP/7zip/UI/Agent/UpdateCallbackAgent.h @@ -1,22 +1,22 @@ -// UpdateCallbackAgent.h - -#ifndef __UPDATE_CALLBACK_AGENT_H -#define __UPDATE_CALLBACK_AGENT_H - -#include "../Common/UpdateCallback.h" - -#include "IFolderArchive.h" - -class CUpdateCallbackAgent: public IUpdateCallbackUI -{ - INTERFACE_IUpdateCallbackUI(;) - - CMyComPtr _cryptoGetTextPassword; - CMyComPtr Callback; - CMyComPtr Callback2; - CMyComPtr _compressProgress; -public: - void SetCallback(IFolderArchiveUpdateCallback *callback); -}; - -#endif +// UpdateCallbackAgent.h + +#ifndef __UPDATE_CALLBACK_AGENT_H +#define __UPDATE_CALLBACK_AGENT_H + +#include "../Common/UpdateCallback.h" + +#include "IFolderArchive.h" + +class CUpdateCallbackAgent: public IUpdateCallbackUI +{ + INTERFACE_IUpdateCallbackUI(;) + + CMyComPtr _cryptoGetTextPassword; + CMyComPtr Callback; + CMyComPtr Callback2; + CMyComPtr _compressProgress; +public: + void SetCallback(IFolderArchiveUpdateCallback *callback); +}; + +#endif diff --git a/CPP/7zip/UI/Client7z/Client7z.cpp b/CPP/7zip/UI/Client7z/Client7z.cpp index 9a06cdc1d..4ebfb2dcd 100644 --- a/CPP/7zip/UI/Client7z/Client7z.cpp +++ b/CPP/7zip/UI/Client7z/Client7z.cpp @@ -1,993 +1,993 @@ -// Client7z.cpp - -#include "StdAfx.h" - -#include - -#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 _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 _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 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 VolumesSizes; - UString VolName; - UString VolExt; - - FString DirPrefix; - const CObjectVector *DirItems; - - bool PasswordIsDefined; - UString Password; - bool AskPassword; - - bool m_NeedBeClosed; - - FStringVector FailedFiles; - CRecordVector FailedCodes; - - CArchiveUpdateCallback(): PasswordIsDefined(false), AskPassword(false), DirItems(0) {}; - - ~CArchiveUpdateCallback() { Finilize(); } - HRESULT Finilize(); - - void Init(const CObjectVector *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 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 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 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 outFileStream = outFileStreamSpec; - if (!outFileStreamSpec->Create(archiveName, false)) - { - PrintError("can't create archive file"); - return 1; - } - - CMyComPtr outArchive; - if (createObjectFunc(&CLSID_Format, &IID_IOutArchive, (void **)&outArchive) != S_OK) - { - PrintError("Can not get class object"); - return 1; - } - - CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; - CMyComPtr 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 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 archive; - if (createObjectFunc(&CLSID_Format, &IID_IInArchive, (void **)&archive) != S_OK) - { - PrintError("Can not get class object"); - return 1; - } - - CInFileStream *fileSpec = new CInFileStream; - CMyComPtr file = fileSpec; - - if (!fileSpec->Open(archiveName)) - { - PrintError("Can not open archive file", archiveName); - return 1; - } - - { - CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback; - CMyComPtr 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 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 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 + +#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 _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 _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 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 VolumesSizes; + UString VolName; + UString VolExt; + + FString DirPrefix; + const CObjectVector *DirItems; + + bool PasswordIsDefined; + UString Password; + bool AskPassword; + + bool m_NeedBeClosed; + + FStringVector FailedFiles; + CRecordVector FailedCodes; + + CArchiveUpdateCallback(): PasswordIsDefined(false), AskPassword(false), DirItems(0) {}; + + ~CArchiveUpdateCallback() { Finilize(); } + HRESULT Finilize(); + + void Init(const CObjectVector *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 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 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 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 outFileStream = outFileStreamSpec; + if (!outFileStreamSpec->Create(archiveName, false)) + { + PrintError("can't create archive file"); + return 1; + } + + CMyComPtr outArchive; + if (createObjectFunc(&CLSID_Format, &IID_IOutArchive, (void **)&outArchive) != S_OK) + { + PrintError("Can not get class object"); + return 1; + } + + CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; + CMyComPtr 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 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 archive; + if (createObjectFunc(&CLSID_Format, &IID_IInArchive, (void **)&archive) != S_OK) + { + PrintError("Can not get class object"); + return 1; + } + + CInFileStream *fileSpec = new CInFileStream; + CMyComPtr file = fileSpec; + + if (!fileSpec->Open(archiveName)) + { + PrintError("Can not open archive file", archiveName); + return 1; + } + + { + CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback; + CMyComPtr 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 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 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; +} diff --git a/CPP/7zip/UI/Client7z/Client7z.dsp b/CPP/7zip/UI/Client7z/Client7z.dsp index d9ec4caf6..b412c8e9a 100644 --- a/CPP/7zip/UI/Client7z/Client7z.dsp +++ b/CPP/7zip/UI/Client7z/Client7z.dsp @@ -1,235 +1,235 @@ -# 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\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 diff --git a/CPP/7zip/UI/Client7z/Client7z.dsw b/CPP/7zip/UI/Client7z/Client7z.dsw index 4c2685118..598a6d3fb 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 c6d3b1fa6..d0feea85c 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 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/UI/Client7z/StdAfx.h +++ b/CPP/7zip/UI/Client7z/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/UI/Client7z/makefile b/CPP/7zip/UI/Client7z/makefile index 9f68f1672..99a6d4947 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\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" diff --git a/CPP/7zip/UI/Client7z/resource.rc b/CPP/7zip/UI/Client7z/resource.rc index 701a783e0..462df6fa7 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 8d23ff21a..0cc524b1a 100644 --- a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp +++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp @@ -1,1295 +1,1295 @@ -// ArchiveCommandLine.cpp - -#include "StdAfx.h" -#undef printf -#undef sprintf - -#ifdef _WIN32 -#ifndef UNDER_CE -#include -#endif -#else -// for isatty() -#include -#endif - -#include - -#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 <@|!>ame must be -static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!>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 *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 *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 *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 ZS", 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 &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 +#endif +#else +// for isatty() +#include +#endif + +#include + +#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 <@|!>ame must be +static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!>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 *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 *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 *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 ZS", 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 &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; +} diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.h b/CPP/7zip/UI/Common/ArchiveCommandLine.h index bba3c98aa..9ed0825fa 100644 --- a/CPP/7zip/UI/Common/ArchiveCommandLine.h +++ b/CPP/7zip/UI/Common/ArchiveCommandLine.h @@ -1,136 +1,136 @@ -// 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 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 __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 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 diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp index aae08ada9..de2f2e007 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp @@ -1,1715 +1,1715 @@ -// ArchiveExtractCallback.cpp - -#include "StdAfx.h" - -#undef sprintf -#undef printf - -// #include -// #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 *realIndices) -{ - _hardLinks.Clear(); - - if (!_arc->Ask_INode) - return S_OK; - - IInArchive *archive = _arc->Archive; - CRecordVector &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 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 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 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 +// #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 *realIndices) +{ + _hardLinks.Clear(); + + if (!_arc->Ask_INode) + return S_OK; + + IInArchive *archive = _arc->Archive; + CRecordVector &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 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 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 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; +} diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/CPP/7zip/UI/Common/ArchiveExtractCallback.h index af38f13c3..dd5c98c07 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h @@ -1,403 +1,403 @@ -// 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 _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 IDs; - CObjectVector 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 _extractCallback2; - CMyComPtr _compressProgress; - CMyComPtr _cryptoGetTextPassword; - CMyComPtr _callbackMessage; - CMyComPtr _folderArchiveExtractCallback2; - - FString _dirPathPrefix; - FString _dirPathPrefix_Full; - NExtract::NPathMode::EEnum _pathMode; - NExtract::NOverwriteMode::EEnum _overwriteMode; - bool _keepAndReplaceEmptyDirPrefixes; // replace them to "_"; - - #ifndef _SFX - - CMyComPtr ExtractToStreamCallback; - CGetProp *GetProp_Spec; - CMyComPtr 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 _outFileStream; - - #ifndef _SFX - - COutStreamWithHash *_hashStreamSpec; - CMyComPtr _hashStream; - bool _hashStreamWasUsed; - - #endif - - bool _removePartsForAltStreams; - UStringVector _removePathParts; - - #ifndef _SFX - bool _use_baseParentFolder_mode; - UInt32 _baseParentFolder; - #endif - - bool _stdOutMode; - bool _testMode; - bool _multiArchives; - - CMyComPtr _localProgress; - UInt64 _packTotal; - - UInt64 _progressTotal; - bool _progressTotal_Defined; - - CObjectVector _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 *realIndices); // NULL means all items - - #endif - - - #ifdef SUPPORT_ALT_STREAMS - CObjectVector _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 __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 _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 IDs; + CObjectVector 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 _extractCallback2; + CMyComPtr _compressProgress; + CMyComPtr _cryptoGetTextPassword; + CMyComPtr _callbackMessage; + CMyComPtr _folderArchiveExtractCallback2; + + FString _dirPathPrefix; + FString _dirPathPrefix_Full; + NExtract::NPathMode::EEnum _pathMode; + NExtract::NOverwriteMode::EEnum _overwriteMode; + bool _keepAndReplaceEmptyDirPrefixes; // replace them to "_"; + + #ifndef _SFX + + CMyComPtr ExtractToStreamCallback; + CGetProp *GetProp_Spec; + CMyComPtr 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 _outFileStream; + + #ifndef _SFX + + COutStreamWithHash *_hashStreamSpec; + CMyComPtr _hashStream; + bool _hashStreamWasUsed; + + #endif + + bool _removePartsForAltStreams; + UStringVector _removePathParts; + + #ifndef _SFX + bool _use_baseParentFolder_mode; + UInt32 _baseParentFolder; + #endif + + bool _stdOutMode; + bool _testMode; + bool _multiArchives; + + CMyComPtr _localProgress; + UInt64 _packTotal; + + UInt64 _progressTotal; + bool _progressTotal_Defined; + + CObjectVector _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 *realIndices); // NULL means all items + + #endif + + + #ifdef SUPPORT_ALT_STREAMS + CObjectVector _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 diff --git a/CPP/7zip/UI/Common/ArchiveName.cpp b/CPP/7zip/UI/Common/ArchiveName.cpp index b07d46c06..9048edcef 100644 --- a/CPP/7zip/UI/Common/ArchiveName.cpp +++ b/CPP/7zip/UI/Common/ArchiveName.cpp @@ -1,155 +1,155 @@ -// 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 "../../../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; +} diff --git a/CPP/7zip/UI/Common/ArchiveName.h b/CPP/7zip/UI/Common/ArchiveName.h index ce2d19232..0d32645f4 100644 --- a/CPP/7zip/UI/Common/ArchiveName.h +++ b/CPP/7zip/UI/Common/ArchiveName.h @@ -1,10 +1,10 @@ -// 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 __ARCHIVE_NAME_H +#define __ARCHIVE_NAME_H + +#include "../../../Windows/FileFind.h" + +UString CreateArchiveName(const UStringVector &paths, const NWindows::NFile::NFind::CFileInfo *fi = NULL); + +#endif diff --git a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp index fd8f9f804..4d9d9e148 100644 --- a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp +++ b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp @@ -1,161 +1,161 @@ -// 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 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 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 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 "../../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 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 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 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 diff --git a/CPP/7zip/UI/Common/ArchiveOpenCallback.h b/CPP/7zip/UI/Common/ArchiveOpenCallback.h index 7f7548f9c..e9575f561 100644 --- a/CPP/7zip/UI/Common/ArchiveOpenCallback.h +++ b/CPP/7zip/UI/Common/ArchiveOpenCallback.h @@ -1,112 +1,112 @@ -// 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 FileSizes; - - bool PasswordWasAsked; - - IOpenCallbackUI *Callback; - CMyComPtr 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 __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 FileSizes; + + bool PasswordWasAsked; + + IOpenCallbackUI *Callback; + CMyComPtr 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 diff --git a/CPP/7zip/UI/Common/Bench.cpp b/CPP/7zip/UI/Common/Bench.cpp index 3fb0758c5..f849a8770 100644 --- a/CPP/7zip/UI/Common/Bench.cpp +++ b/CPP/7zip/UI/Common/Bench.cpp @@ -1,3618 +1,3618 @@ -// Bench.cpp - -#include "StdAfx.h" - -#include - -#ifndef _WIN32 -#define USE_POSIX_TIME -#define USE_POSIX_TIME2 -#endif - -#ifdef USE_POSIX_TIME -#include -#ifdef USE_POSIX_TIME2 -#include -#endif -#endif - -#ifdef _WIN32 -#define USE_ALLOCA -#endif - -#ifdef USE_ALLOCA -#ifdef _WIN32 -#include -#else -#include -#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 _encoder; - CMyComPtr _encoderFilter; - CBenchProgressInfo *progressInfoSpec[2]; - CMyComPtr 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 _decoders[2]; - CMyComPtr _decoderFilter; - - HRESULT Results[2]; - CBenchmarkOutStream *outStreamSpec; - CMyComPtr 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 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 coder; - if (_encoderFilter) - coder = _encoderFilter; - else - coder = _encoder; - { - CMyComPtr scp; - coder.QueryInterface(IID_ICompressSetCoderProperties, &scp); - if (scp) - { - UInt64 reduceSize = kBufferSize; - RINOK(method.SetCoderProps(scp, &reduceSize)); - } - else - { - if (method.AreThereNonOptionalProps()) - return E_INVALIDARG; - } - - CMyComPtr writeCoderProps; - coder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProps); - if (writeCoderProps) - { - RINOK(writeCoderProps->WriteCoderProperties(propStream)); - } - - { - CMyComPtr 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 inStream = inStreamSpec; - inStreamSpec->Init(temp, sizeof(temp)); - - CCrcOutStream *crcStreamSpec = new CCrcOutStream; - CMyComPtr 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 cp; - CMyComPtr coder; - if (_encoderFilter) - coder = _encoderFilter; - else - coder = _encoder; - coder.QueryInterface(IID_ICryptoProperties, &cp); - CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; - CMyComPtr 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 inStream = inStreamSpec; - CMyComPtr &decoder = _decoders[decoderIndex]; - CMyComPtr coder; - if (_decoderFilter) - { - if (decoderIndex != 0) - return E_FAIL; - coder = _decoderFilter; - } - else - coder = decoder; - - CMyComPtr setDecProps; - coder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecProps); - if (!setDecProps && propStreamSpec->Pos != 0) - return E_FAIL; - - CCrcOutStream *crcOutStreamSpec = new CCrcOutStream; - CMyComPtr crcOutStream = crcOutStreamSpec; - - CBenchProgressInfo *pi = progressInfoSpec[decoderIndex]; - pi->BenchInfo.UnpackSize = 0; - pi->BenchInfo.PackSize = 0; - - #ifndef _7ZIP_ST - { - CMyComPtr setCoderMt; - coder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); - if (setCoderMt) - { - RINOK(setCoderMt->SetNumberOfThreads(NumDecoderSubThreads)); - } - } - #endif - - CMyComPtr scp; - coder.QueryInterface(IID_ICompressSetCoderProperties, &scp); - if (scp) - { - UInt64 reduceSize = _uncompressedDataSize; - RINOK(_method.SetCoderProps(scp, &reduceSize)); - } - - CMyComPtr cp; - coder.QueryInterface(IID_ICryptoProperties, &cp); - - if (setDecProps) - { - RINOK(setDecProps->SetDecoderProperties2((const Byte *)*propStreamSpec, (UInt32)propStreamSpec->Pos)); - } - - { - CMyComPtr 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 &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 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 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 hasher; - AString name; - RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, hasher)); - if (!hasher) - return E_NOTIMPL; - CMyComPtr 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 &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 + +#ifndef _WIN32 +#define USE_POSIX_TIME +#define USE_POSIX_TIME2 +#endif + +#ifdef USE_POSIX_TIME +#include +#ifdef USE_POSIX_TIME2 +#include +#endif +#endif + +#ifdef _WIN32 +#define USE_ALLOCA +#endif + +#ifdef USE_ALLOCA +#ifdef _WIN32 +#include +#else +#include +#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 _encoder; + CMyComPtr _encoderFilter; + CBenchProgressInfo *progressInfoSpec[2]; + CMyComPtr 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 _decoders[2]; + CMyComPtr _decoderFilter; + + HRESULT Results[2]; + CBenchmarkOutStream *outStreamSpec; + CMyComPtr 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 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 coder; + if (_encoderFilter) + coder = _encoderFilter; + else + coder = _encoder; + { + CMyComPtr scp; + coder.QueryInterface(IID_ICompressSetCoderProperties, &scp); + if (scp) + { + UInt64 reduceSize = kBufferSize; + RINOK(method.SetCoderProps(scp, &reduceSize)); + } + else + { + if (method.AreThereNonOptionalProps()) + return E_INVALIDARG; + } + + CMyComPtr writeCoderProps; + coder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProps); + if (writeCoderProps) + { + RINOK(writeCoderProps->WriteCoderProperties(propStream)); + } + + { + CMyComPtr 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 inStream = inStreamSpec; + inStreamSpec->Init(temp, sizeof(temp)); + + CCrcOutStream *crcStreamSpec = new CCrcOutStream; + CMyComPtr 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 cp; + CMyComPtr coder; + if (_encoderFilter) + coder = _encoderFilter; + else + coder = _encoder; + coder.QueryInterface(IID_ICryptoProperties, &cp); + CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; + CMyComPtr 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 inStream = inStreamSpec; + CMyComPtr &decoder = _decoders[decoderIndex]; + CMyComPtr coder; + if (_decoderFilter) + { + if (decoderIndex != 0) + return E_FAIL; + coder = _decoderFilter; + } + else + coder = decoder; + + CMyComPtr setDecProps; + coder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecProps); + if (!setDecProps && propStreamSpec->Pos != 0) + return E_FAIL; + + CCrcOutStream *crcOutStreamSpec = new CCrcOutStream; + CMyComPtr crcOutStream = crcOutStreamSpec; + + CBenchProgressInfo *pi = progressInfoSpec[decoderIndex]; + pi->BenchInfo.UnpackSize = 0; + pi->BenchInfo.PackSize = 0; + + #ifndef _7ZIP_ST + { + CMyComPtr setCoderMt; + coder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); + if (setCoderMt) + { + RINOK(setCoderMt->SetNumberOfThreads(NumDecoderSubThreads)); + } + } + #endif + + CMyComPtr scp; + coder.QueryInterface(IID_ICompressSetCoderProperties, &scp); + if (scp) + { + UInt64 reduceSize = _uncompressedDataSize; + RINOK(_method.SetCoderProps(scp, &reduceSize)); + } + + CMyComPtr cp; + coder.QueryInterface(IID_ICryptoProperties, &cp); + + if (setDecProps) + { + RINOK(setDecProps->SetDecoderProperties2((const Byte *)*propStreamSpec, (UInt32)propStreamSpec->Pos)); + } + + { + CMyComPtr 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 &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 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 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 hasher; + AString name; + RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, hasher)); + if (!hasher) + return E_NOTIMPL; + CMyComPtr 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 &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; +} diff --git a/CPP/7zip/UI/Common/Bench.h b/CPP/7zip/UI/Common/Bench.h index 1d052aac6..18a40a844 100644 --- a/CPP/7zip/UI/Common/Bench.h +++ b/CPP/7zip/UI/Common/Bench.h @@ -1,77 +1,77 @@ -// 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 &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 __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 &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 diff --git a/CPP/7zip/UI/Common/CompressCall.cpp b/CPP/7zip/UI/Common/CompressCall.cpp index e05b8ef1f..0f8753650 100644 --- a/CPP/7zip/UI/Common/CompressCall.cpp +++ b/CPP/7zip/UI/Common/CompressCall.cpp @@ -1,382 +1,382 @@ -// CompressCall.cpp - -#include "StdAfx.h" - -#include - -#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/StringUtils.h" -#include "../FileManager/RegistryUtils.h" - -#include "ZipRegistry.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" - -#define kShowDialogSwitch " -ad" -#define kEmailSwitch " -seml." -#define kIncludeSwitch " -i" -#define kArchiveTypeSwitch " -t" -#define kArcIncludeSwitches " -an -ai" -#define kHashIncludeSwitches " -i" -#define kStopSwitchParsing " --" - -static NCompression::CInfo m_RegistryInfo; -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 ZS", 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 ¶ms, - // LPCWSTR curDir, - bool waitFinish, - NSynchronization::CBaseEvent *event) -{ - UString imageName = fs2us(NWindows::NDLL::GetModuleDirPrefix()); - imageName += k7zGui; - - CProcess process; - WRes res = process.Create(imageName, params, NULL); // curDir); - if (res != 0) - { - ErrorMessageHRESULT(res, imageName); - return res; - } - if (waitFinish) - process.Wait(); - else if (event != NULL) - { - HANDLE handles[] = { process, *event }; - ::WaitForMultipleObjects(ARRAY_SIZE(handles), handles, FALSE, INFINITE); - } - return S_OK; -} - -static void AddLagePagesSwitch(UString ¶ms) -{ - 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 ¶ms) -{ - 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"); - - WRes res = fileMapping.Create(PAGE_READWRITE, totalSize, GetSystemString(mappingName)); - if (fileMapping.IsCreated() && res == 0) - break; - if (res != ERROR_ALREADY_EXISTS) - return res; - fileMapping.Close(); - } - - UString eventName; - for (;;) - { - random.GenerateName(eventName, "7zEvent"); - WRes res = event.CreateWithName(false, GetSystemString(eventName)); - if (event.IsCreated() && res == 0) - break; - if (res != ERROR_ALREADY_EXISTS) - return res; - 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]; - unsigned len = s.Len() + 1; - wmemcpy(cur, (const wchar_t *)s, len); - cur += len; - } - } - return S_OK; -} - -int 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 i; - } - return -1; -} - -int FindRegistryFormatAlways(const UString &name) -{ - int index = FindRegistryFormat(name); - if (index < 0) - { - NCompression::CFormatOptions fo; - fo.FormatID = GetSystemString(name); - index = m_RegistryInfo.Formats.Add(fo); - } - return index; -} - -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() && arcType == L"7z") - { - int index; - params += kArchiveTypeSwitch; - params += arcType; - m_RegistryInfo.Load(); - index = FindRegistryFormatAlways(arcType); - if (index >= 0) - { - char temp[64]; - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - - if (!fo.Method.IsEmpty()) - { - params += " -m0="; - params += fo.Method; - } - - if (fo.Level) - { - params += " -mx="; - ConvertUInt32ToString(fo.Level, temp); - params += temp; - } - - if (fo.Dictionary) - { - params += " -md="; - ConvertUInt32ToString(fo.Dictionary, temp); - params += temp; - params += "b"; - } - - if (fo.BlockLogSize) - { - params += " -ms="; - ConvertUInt32ToString(1 << fo.BlockLogSize, temp); - params += temp; - params += "b"; - } - - if (fo.NumThreads) - { - params += " -mmt="; - ConvertUInt32ToString(fo.NumThreads, temp); - params += temp; - } - - if (!fo.Options.IsEmpty()) - { - UStringVector strings; - SplitString(fo.Options, strings); - FOR_VECTOR (i, strings) - { - params += " -m"; - params += strings[i]; - } - } - } - } - - 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); - } - - // ErrorMessage(params); - return Call7zGui(params, - // (arcPathPrefix.IsEmpty()? 0: (LPCWSTR)arcPathPrefix), - waitFinish, &event); - MY_TRY_FINISH -} - -static void ExtractGroupCommand(const UStringVector &arcPaths, UString ¶ms, 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) -{ - MY_TRY_BEGIN - UString params ('x'); - if (!outFolder.IsEmpty()) - { - params += " -o"; - params += GetQuotedString(outFolder); - } - if (elimDup) - params += " -spe"; - if (showDialog) - params += kShowDialogSwitch; - ExtractGroupCommand(arcPaths, params, false); - MY_TRY_FINISH_VOID -} - -void TestArchives(const UStringVector &arcPaths) -{ - MY_TRY_BEGIN - UString params ('t'); - ExtractGroupCommand(arcPaths, params, false); - MY_TRY_FINISH_VOID -} - -void CalcChecksum(const UStringVector &paths, const UString &methodName) -{ - MY_TRY_BEGIN - UString params ('h'); - if (!methodName.IsEmpty()) - { - params += " -scrc"; - params += methodName; - } - ExtractGroupCommand(paths, params, true); - MY_TRY_FINISH_VOID -} - -void Benchmark(bool totalMode) -{ - MY_TRY_BEGIN - UString params ('b'); - if (totalMode) - params += " -mm=*"; - AddLagePagesSwitch(params); - HRESULT result = Call7zGui(params, false, NULL); - if (result != S_OK) - ErrorMessageHRESULT(result); - MY_TRY_FINISH_VOID -} +// CompressCall.cpp + +#include "StdAfx.h" + +#include + +#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/StringUtils.h" +#include "../FileManager/RegistryUtils.h" + +#include "ZipRegistry.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" + +#define kShowDialogSwitch " -ad" +#define kEmailSwitch " -seml." +#define kIncludeSwitch " -i" +#define kArchiveTypeSwitch " -t" +#define kArcIncludeSwitches " -an -ai" +#define kHashIncludeSwitches " -i" +#define kStopSwitchParsing " --" + +static NCompression::CInfo m_RegistryInfo; +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 ZS", 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 ¶ms, + // LPCWSTR curDir, + bool waitFinish, + NSynchronization::CBaseEvent *event) +{ + UString imageName = fs2us(NWindows::NDLL::GetModuleDirPrefix()); + imageName += k7zGui; + + CProcess process; + WRes res = process.Create(imageName, params, NULL); // curDir); + if (res != 0) + { + ErrorMessageHRESULT(res, imageName); + return res; + } + if (waitFinish) + process.Wait(); + else if (event != NULL) + { + HANDLE handles[] = { process, *event }; + ::WaitForMultipleObjects(ARRAY_SIZE(handles), handles, FALSE, INFINITE); + } + return S_OK; +} + +static void AddLagePagesSwitch(UString ¶ms) +{ + 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 ¶ms) +{ + 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"); + + WRes res = fileMapping.Create(PAGE_READWRITE, totalSize, GetSystemString(mappingName)); + if (fileMapping.IsCreated() && res == 0) + break; + if (res != ERROR_ALREADY_EXISTS) + return res; + fileMapping.Close(); + } + + UString eventName; + for (;;) + { + random.GenerateName(eventName, "7zEvent"); + WRes res = event.CreateWithName(false, GetSystemString(eventName)); + if (event.IsCreated() && res == 0) + break; + if (res != ERROR_ALREADY_EXISTS) + return res; + 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]; + unsigned len = s.Len() + 1; + wmemcpy(cur, (const wchar_t *)s, len); + cur += len; + } + } + return S_OK; +} + +int 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 i; + } + return -1; +} + +int FindRegistryFormatAlways(const UString &name) +{ + int index = FindRegistryFormat(name); + if (index < 0) + { + NCompression::CFormatOptions fo; + fo.FormatID = GetSystemString(name); + index = m_RegistryInfo.Formats.Add(fo); + } + return index; +} + +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() && arcType == L"7z") + { + int index; + params += kArchiveTypeSwitch; + params += arcType; + m_RegistryInfo.Load(); + index = FindRegistryFormatAlways(arcType); + if (index >= 0) + { + char temp[64]; + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + + if (!fo.Method.IsEmpty()) + { + params += " -m0="; + params += fo.Method; + } + + if (fo.Level) + { + params += " -mx="; + ConvertUInt32ToString(fo.Level, temp); + params += temp; + } + + if (fo.Dictionary) + { + params += " -md="; + ConvertUInt32ToString(fo.Dictionary, temp); + params += temp; + params += "b"; + } + + if (fo.BlockLogSize) + { + params += " -ms="; + ConvertUInt32ToString(1 << fo.BlockLogSize, temp); + params += temp; + params += "b"; + } + + if (fo.NumThreads) + { + params += " -mmt="; + ConvertUInt32ToString(fo.NumThreads, temp); + params += temp; + } + + if (!fo.Options.IsEmpty()) + { + UStringVector strings; + SplitString(fo.Options, strings); + FOR_VECTOR (i, strings) + { + params += " -m"; + params += strings[i]; + } + } + } + } + + 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); + } + + // ErrorMessage(params); + return Call7zGui(params, + // (arcPathPrefix.IsEmpty()? 0: (LPCWSTR)arcPathPrefix), + waitFinish, &event); + MY_TRY_FINISH +} + +static void ExtractGroupCommand(const UStringVector &arcPaths, UString ¶ms, 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) +{ + MY_TRY_BEGIN + UString params ('x'); + if (!outFolder.IsEmpty()) + { + params += " -o"; + params += GetQuotedString(outFolder); + } + if (elimDup) + params += " -spe"; + if (showDialog) + params += kShowDialogSwitch; + ExtractGroupCommand(arcPaths, params, false); + MY_TRY_FINISH_VOID +} + +void TestArchives(const UStringVector &arcPaths) +{ + MY_TRY_BEGIN + UString params ('t'); + ExtractGroupCommand(arcPaths, params, false); + MY_TRY_FINISH_VOID +} + +void CalcChecksum(const UStringVector &paths, const UString &methodName) +{ + MY_TRY_BEGIN + UString params ('h'); + if (!methodName.IsEmpty()) + { + params += " -scrc"; + params += methodName; + } + ExtractGroupCommand(paths, params, true); + MY_TRY_FINISH_VOID +} + +void Benchmark(bool totalMode) +{ + MY_TRY_BEGIN + UString params ('b'); + if (totalMode) + params += " -mm=*"; + AddLagePagesSwitch(params); + 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 index 4c39a43fc..c71c21f73 100644 --- a/CPP/7zip/UI/Common/CompressCall.h +++ b/CPP/7zip/UI/Common/CompressCall.h @@ -1,23 +1,23 @@ -// CompressCall.h - -#ifndef __COMPRESS_CALL_H -#define __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); -void TestArchives(const UStringVector &arcPaths); -void CalcChecksum(const UStringVector &paths, const UString &methodName); -void Benchmark(bool totalMode); - -#endif +// CompressCall.h + +#ifndef __COMPRESS_CALL_H +#define __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); +void TestArchives(const UStringVector &arcPaths); +void CalcChecksum(const UStringVector &paths, const UString &methodName); +void Benchmark(bool totalMode); + +#endif diff --git a/CPP/7zip/UI/Common/CompressCall2.cpp b/CPP/7zip/UI/Common/CompressCall2.cpp index df940fda4..d3c585426 100644 --- a/CPP/7zip/UI/Common/CompressCall2.cpp +++ b/CPP/7zip/UI/Common/CompressCall2.cpp @@ -1,276 +1,276 @@ -// CompressCall2.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyException.h" - -#include "../../UI/Common/EnumDirItems.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 EXTERNAL_CODECS - -#define CREATE_CODECS \ - CCodecs *codecs = new CCodecs; \ - CMyComPtr compressCodecsInfo = codecs; \ - ThrowException_if_Error(codecs->Load()); - -#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 compressCodecsInfo = codecs; \ - ThrowException_if_Error(codecs->Load()); - -#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 ZS", 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 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(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, const UString &outFolder, bool testMode, bool elimDup = false) -{ - MY_TRY_BEGIN - - CREATE_CODECS - - CExtractOptions eo; - eo.OutputDir = us2fs(outFolder); - eo.TestMode = testMode; - eo.ElimDup.Val = elimDup; - eo.ElimDup.Def = elimDup; - - CExtractCallbackImp *ecs = new CExtractCallbackImp; - CMyComPtr extractCallback = ecs; - - ecs->Init(); - - // eo.CalcCrc = options.CalcCrc; - - UStringVector arcPathsSorted; - UStringVector arcFullPathsSorted; - { - NWildcard::CCensor arcCensor; - FOR_VECTOR (i, arcPaths) - { - arcCensor.AddPreItem(arcPaths[i]); - } - arcCensor.AddPathsToCensor(NWildcard::k_RelatPath); - CDirItemsStat st; - EnumerateDirItemsAndSort(arcCensor, NWildcard::k_RelatPath, UString(), - arcPathsSorted, arcFullPathsSorted, - st, - NULL // &scan: change it!!!! - ); - } - - CObjectVector formatIndices; - - 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) -{ - ExtractGroupCommand(arcPaths, showDialog, outFolder, false, elimDup); -} - -void TestArchives(const UStringVector &arcPaths) -{ - ExtractGroupCommand(arcPaths, true, UString(), true); -} - -void CalcChecksum(const UStringVector &paths, const UString &methodName) -{ - MY_TRY_BEGIN - - CREATE_CODECS - LOAD_EXTERNAL_CODECS - - NWildcard::CCensor censor; - FOR_VECTOR (i, paths) - { - censor.AddPreItem(paths[i]); - } - - censor.AddPathsToCensor(NWildcard::k_RelatPath); - bool messageWasDisplayed = false; - - CHashOptions options; - options.Methods.Add(methodName); - - 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 props; - if (totalMode) - { - CProperty prop; - prop.Name = "m"; - prop.Value = "*"; - props.Add(prop); - } - result = Benchmark(EXTERNAL_CODECS_VARS_L props, g_HWND); - - MY_TRY_FINISH -} +// CompressCall2.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyException.h" + +#include "../../UI/Common/EnumDirItems.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 EXTERNAL_CODECS + +#define CREATE_CODECS \ + CCodecs *codecs = new CCodecs; \ + CMyComPtr compressCodecsInfo = codecs; \ + ThrowException_if_Error(codecs->Load()); + +#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 compressCodecsInfo = codecs; \ + ThrowException_if_Error(codecs->Load()); + +#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 ZS", 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 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(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, const UString &outFolder, bool testMode, bool elimDup = false) +{ + MY_TRY_BEGIN + + CREATE_CODECS + + CExtractOptions eo; + eo.OutputDir = us2fs(outFolder); + eo.TestMode = testMode; + eo.ElimDup.Val = elimDup; + eo.ElimDup.Def = elimDup; + + CExtractCallbackImp *ecs = new CExtractCallbackImp; + CMyComPtr extractCallback = ecs; + + ecs->Init(); + + // eo.CalcCrc = options.CalcCrc; + + UStringVector arcPathsSorted; + UStringVector arcFullPathsSorted; + { + NWildcard::CCensor arcCensor; + FOR_VECTOR (i, arcPaths) + { + arcCensor.AddPreItem(arcPaths[i]); + } + arcCensor.AddPathsToCensor(NWildcard::k_RelatPath); + CDirItemsStat st; + EnumerateDirItemsAndSort(arcCensor, NWildcard::k_RelatPath, UString(), + arcPathsSorted, arcFullPathsSorted, + st, + NULL // &scan: change it!!!! + ); + } + + CObjectVector formatIndices; + + 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) +{ + ExtractGroupCommand(arcPaths, showDialog, outFolder, false, elimDup); +} + +void TestArchives(const UStringVector &arcPaths) +{ + ExtractGroupCommand(arcPaths, true, UString(), true); +} + +void CalcChecksum(const UStringVector &paths, const UString &methodName) +{ + MY_TRY_BEGIN + + CREATE_CODECS + LOAD_EXTERNAL_CODECS + + NWildcard::CCensor censor; + FOR_VECTOR (i, paths) + { + censor.AddPreItem(paths[i]); + } + + censor.AddPathsToCensor(NWildcard::k_RelatPath); + bool messageWasDisplayed = false; + + CHashOptions options; + options.Methods.Add(methodName); + + 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 props; + if (totalMode) + { + CProperty prop; + prop.Name = "m"; + prop.Value = "*"; + props.Add(prop); + } + result = Benchmark(EXTERNAL_CODECS_VARS_L props, g_HWND); + + MY_TRY_FINISH +} diff --git a/CPP/7zip/UI/Common/DefaultName.cpp b/CPP/7zip/UI/Common/DefaultName.cpp index 0c13e9ebc..02f611c3d 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(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 4484c3b5b..df1645602 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 __DEFAULT_NAME_H +#define __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 47485bec3..839371035 100644 --- a/CPP/7zip/UI/Common/DirItem.h +++ b/CPP/7zip/UI/Common/DirItem.h @@ -1,190 +1,190 @@ -// 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 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 __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 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 diff --git a/CPP/7zip/UI/Common/EnumDirItems.cpp b/CPP/7zip/UI/Common/EnumDirItems.cpp index 2c941e12b..088f07772 100644 --- a/CPP/7zip/UI/Common/EnumDirItems.cpp +++ b/CPP/7zip/UI/Common/EnumDirItems.cpp @@ -1,1096 +1,1096 @@ -// EnumDirItems.cpp - -#include "StdAfx.h" - -#include - -#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 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 &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 + +#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 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 &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 ae1d22694..6490bd509 100644 --- a/CPP/7zip/UI/Common/EnumDirItems.h +++ b/CPP/7zip/UI/Common/EnumDirItems.h @@ -1,42 +1,42 @@ -// 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 &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 __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 &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 diff --git a/CPP/7zip/UI/Common/ExitCode.h b/CPP/7zip/UI/Common/ExitCode.h index d03ec6d79..b6d7d4dfc 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 __EXIT_CODE_H +#define __EXIT_CODE_H + +namespace NExitCode { + +enum EEnum { + + kSuccess = 0, // Successful operation + kWarning = 1, // Non fatal error(s) occurred + kFatalError = 2, // A fatal error occurred + // kCRCError = 3, // A CRC error occurred when unpacking + // kLockedArchive = 4, // Attempt to modify an archive previously locked + // kWriteError = 5, // Write to disk error + // kOpenError = 6, // Open file error + kUserError = 7, // Command line option error + kMemoryError = 8, // Not enough memory for operation + // kCreateFileError = 9, // Create file error + + kUserBreak = 255 // User stopped the process + +}; + +} + +#endif diff --git a/CPP/7zip/UI/Common/Extract.cpp b/CPP/7zip/UI/Common/Extract.cpp index 2cb2c9b92..c49daa1d5 100644 --- a/CPP/7zip/UI/Common/Extract.cpp +++ b/CPP/7zip/UI/Common/Extract.cpp @@ -1,482 +1,482 @@ -// 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 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 &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 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 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 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/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 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 &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 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 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 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; +} diff --git a/CPP/7zip/UI/Common/Extract.h b/CPP/7zip/UI/Common/Extract.h index 9c806bee7..03ac74b2d 100644 --- a/CPP/7zip/UI/Common/Extract.h +++ b/CPP/7zip/UI/Common/Extract.h @@ -1,94 +1,94 @@ -// 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 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 &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 __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 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 &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 diff --git a/CPP/7zip/UI/Common/ExtractMode.h b/CPP/7zip/UI/Common/ExtractMode.h index c28b7ccfa..3b2b9a02e 100644 --- a/CPP/7zip/UI/Common/ExtractMode.h +++ b/CPP/7zip/UI/Common/ExtractMode.h @@ -1,34 +1,34 @@ -// 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 __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 diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/CPP/7zip/UI/Common/ExtractingFilePath.cpp index 13665de57..535530e45 100644 --- a/CPP/7zip/UI/Common/ExtractingFilePath.cpp +++ b/CPP/7zip/UI/Common/ExtractingFilePath.cpp @@ -1,280 +1,280 @@ -// 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" + +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; +} diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.h b/CPP/7zip/UI/Common/ExtractingFilePath.h index 12eb0bad7..81cb8267c 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 __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 diff --git a/CPP/7zip/UI/Common/HashCalc.cpp b/CPP/7zip/UI/Common/HashCalc.cpp index 822018d6c..c340ac7f0 100644 --- a/CPP/7zip/UI/Common/HashCalc.cpp +++ b/CPP/7zip/UI/Common/HashCalc.cpp @@ -1,347 +1,347 @@ -// 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 ids; - CObjectVector 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 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 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 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 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 "../../../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 ids; + CObjectVector 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 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 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 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 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; + } +} diff --git a/CPP/7zip/UI/Common/HashCalc.h b/CPP/7zip/UI/Common/HashCalc.h index 524bd3bd6..db5b39aa7 100644 --- a/CPP/7zip/UI/Common/HashCalc.h +++ b/CPP/7zip/UI/Common/HashCalc.h @@ -1,110 +1,110 @@ -// 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 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 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 __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 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 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 diff --git a/CPP/7zip/UI/Common/IFileExtractCallback.h b/CPP/7zip/UI/Common/IFileExtractCallback.h index 3f554ef31..c456c8627 100644 --- a/CPP/7zip/UI/Common/IFileExtractCallback.h +++ b/CPP/7zip/UI/Common/IFileExtractCallback.h @@ -1,114 +1,114 @@ -// 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 __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 diff --git a/CPP/7zip/UI/Common/LoadCodecs.cpp b/CPP/7zip/UI/Common/LoadCodecs.cpp index d31e05f19..f1334613d 100644 --- a/CPP/7zip/UI/Common/LoadCodecs.cpp +++ b/CPP/7zip/UI/Common/LoadCodecs.cpp @@ -1,1074 +1,1074 @@ -// 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 &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 + +/* +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 &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 diff --git a/CPP/7zip/UI/Common/LoadCodecs.h b/CPP/7zip/UI/Common/LoadCodecs.h index 9ba36d3e9..ac9eeac71 100644 --- a/CPP/7zip/UI/Common/LoadCodecs.h +++ b/CPP/7zip/UI/Common/LoadCodecs.h @@ -1,424 +1,424 @@ -// 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 Exts; - - #ifndef _SFX - Func_CreateOutArchive CreateOutArchive; - bool UpdateEnabled; - bool NewInterface; - // UInt32 Version; - UInt32 SignatureOffset; - CObjectVector 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 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 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 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 Formats; - - #ifdef EXTERNAL_CODECS - CRecordVector Codecs; - CRecordVector 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 &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 &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 __codecsRef = codecs; -#endif - -#endif +// 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 Exts; + + #ifndef _SFX + Func_CreateOutArchive CreateOutArchive; + bool UpdateEnabled; + bool NewInterface; + // UInt32 Version; + UInt32 SignatureOffset; + CObjectVector 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 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 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 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 Formats; + + #ifdef EXTERNAL_CODECS + CRecordVector Codecs; + CRecordVector 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 &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 &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 __codecsRef = codecs; +#endif + +#endif diff --git a/CPP/7zip/UI/Common/OpenArchive.cpp b/CPP/7zip/UI/Common/OpenArchive.cpp index e35c0e7de..877260f2f 100644 --- a/CPP/7zip/UI/Common/OpenArchive.cpp +++ b/CPP/7zip/UI/Common/OpenArchive.cpp @@ -1,3554 +1,3554 @@ -// OpenArchive.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#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 _items; - UInt64 _maxEndOffset; - CMyComPtr _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 progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_stream); - - CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; - CMyComPtr outStream(outStreamSpec); - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - CMyComPtr 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 &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" - , "lzip" - , "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 Callback; - CMyComPtr OpenVolumeCallback; - UInt64 Files; - UInt64 Offset; - - #ifndef _NO_CRYPTO - CMyComPtr 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 &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 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 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 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 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 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 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 handler = handlerSpec; - - CExtractCallback_To_OpenCallback *extractCallback_To_OpenCallback_Spec = new CExtractCallback_To_OpenCallback; - CMyComPtr 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 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 &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 limitedStream = limitedStreamSpec; - limitedStreamSpec->SetStream(op.stream); - - CArchiveOpenCallback_Offset *openCallback_Offset_Spec = NULL; - CMyComPtr 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 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 fileStream; - CMyComPtr 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 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 getStream; - if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream) - break; - - CMyComPtr subSeqStream; - if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream) - break; - - CMyComPtr 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 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 = ! - 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 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 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 inc; - CIntVector excl; - - op.types = &inc; - op.excludedFormats = ! - op.stdInMode = false; - op.stream = NULL; - if (Arcs.Size() == 0) // ??? - return Open2(op, NULL); - - COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; - CMyComPtr 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 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 &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 +#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 _items; + UInt64 _maxEndOffset; + CMyComPtr _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 progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(_stream); + + CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; + CMyComPtr outStream(outStreamSpec); + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr 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 &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" + , "lzip" + , "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 Callback; + CMyComPtr OpenVolumeCallback; + UInt64 Files; + UInt64 Offset; + + #ifndef _NO_CRYPTO + CMyComPtr 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 &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 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 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 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 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 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 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 handler = handlerSpec; + + CExtractCallback_To_OpenCallback *extractCallback_To_OpenCallback_Spec = new CExtractCallback_To_OpenCallback; + CMyComPtr 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 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 &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 limitedStream = limitedStreamSpec; + limitedStreamSpec->SetStream(op.stream); + + CArchiveOpenCallback_Offset *openCallback_Offset_Spec = NULL; + CMyComPtr 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 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 fileStream; + CMyComPtr 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 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 getStream; + if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream) + break; + + CMyComPtr subSeqStream; + if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream) + break; + + CMyComPtr 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 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 = ! + 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 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 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 inc; + CIntVector excl; + + op.types = &inc; + op.excludedFormats = ! + op.stdInMode = false; + op.stream = NULL; + if (Arcs.Size() == 0) // ??? + return Open2(op, NULL); + + COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; + CMyComPtr 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 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 &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 diff --git a/CPP/7zip/UI/Common/OpenArchive.h b/CPP/7zip/UI/Common/OpenArchive.h index 033cb960f..6eb0d3953 100644 --- a/CPP/7zip/UI/Common/OpenArchive.h +++ b/CPP/7zip/UI/Common/OpenArchive.h @@ -1,436 +1,436 @@ -// 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 Props; -}; -*/ - -#ifdef _SFX -#define OPEN_PROPS_DECL -#else -#define OPEN_PROPS_DECL const CObjectVector *props; -// #define OPEN_PROPS_DECL , const CObjectVector *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 *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 &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 Archive; - CMyComPtr InStream; - // we use InStream in 2 cases (ArcStreamOffset != 0): - // 1) if we use additional cache stream - // 2) we reopen sfx archive with CTailInStream - - CMyComPtr GetRawProps; - CMyComPtr 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 &stream); -}; - -struct CArchiveLink -{ - CObjectVector 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 &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 __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 Props; +}; +*/ + +#ifdef _SFX +#define OPEN_PROPS_DECL +#else +#define OPEN_PROPS_DECL const CObjectVector *props; +// #define OPEN_PROPS_DECL , const CObjectVector *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 *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 &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 Archive; + CMyComPtr InStream; + // we use InStream in 2 cases (ArcStreamOffset != 0): + // 1) if we use additional cache stream + // 2) we reopen sfx archive with CTailInStream + + CMyComPtr GetRawProps; + CMyComPtr 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 &stream); +}; + +struct CArchiveLink +{ + CObjectVector 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 &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 bb9c89f2d..7702e222d 100644 --- a/CPP/7zip/UI/Common/PropIDUtils.cpp +++ b/CPP/7zip/UI/Common/PropIDUtils.cpp @@ -1,668 +1,668 @@ -// 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" + +#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 diff --git a/CPP/7zip/UI/Common/PropIDUtils.h b/CPP/7zip/UI/Common/PropIDUtils.h index e94e6d798..915bfc28e 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 __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 diff --git a/CPP/7zip/UI/Common/Property.h b/CPP/7zip/UI/Common/Property.h index 31234ad3c..8b57a2a64 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 __7Z_PROPERTY_H +#define __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 3cd4d5718..c3de5d5a3 100644 --- a/CPP/7zip/UI/Common/SetProperties.cpp +++ b/CPP/7zip/UI/Common/SetProperties.cpp @@ -1,80 +1,80 @@ -// 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 &properties) -{ - if (properties.IsEmpty()) - return S_OK; - CMyComPtr 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 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; + 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 &properties) +{ + if (properties.IsEmpty()) + return S_OK; + CMyComPtr 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 names; + for (i = 0; i < realNames.Size(); i++) + names.Add((const wchar_t *)realNames[i]); + + RINOK(setProperties->SetProperties(&names.Front(), values, names.Size())); + } + catch(...) + { + delete []values; + throw; + } + delete []values; + return S_OK; +} diff --git a/CPP/7zip/UI/Common/SetProperties.h b/CPP/7zip/UI/Common/SetProperties.h index 64c947cf8..892f1a210 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 &properties); - -#endif +// SetProperties.h + +#ifndef __SETPROPERTIES_H +#define __SETPROPERTIES_H + +#include "Property.h" + +HRESULT SetProperties(IUnknown *unknown, const CObjectVector &properties); + +#endif diff --git a/CPP/7zip/UI/Common/SortUtils.cpp b/CPP/7zip/UI/Common/SortUtils.cpp index f73ece86e..5f29249bd 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 82d5e4cb2..8e42e0682 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 __SORT_UTLS_H +#define __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 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/UI/Common/StdAfx.h +++ b/CPP/7zip/UI/Common/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/UI/Common/TempFiles.cpp b/CPP/7zip/UI/Common/TempFiles.cpp index 56bba9a1f..2f868381f 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 f62192dd5..4099e6558 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 __TEMP_FILES_H +#define __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 2f1b36563..8c7ae45f6 100644 --- a/CPP/7zip/UI/Common/Update.cpp +++ b/CPP/7zip/UI/Common/Update.cpp @@ -1,1704 +1,1704 @@ -// 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 Stream; - FString Name; - UInt64 Pos; - UInt64 RealSize; - }; - CObjectVector Streams; -public: - // CMyComPtr VolumeCallback; - CRecordVector 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 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 &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 *_arcItems; - IUpdateCallbackUI *_callback; - CDirItemsStat *_stat; - - CUpdateProduceCallbackImp( - const CObjectVector *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 &arcItems, - Byte *processedItemsStatuses, - const CDirItems &dirItems, - const CDirItem *parentDirItem, - CTempFiles &tempFiles, - CUpdateErrorInfo &errorInfo, - IUpdateCallbackUI *callback, - CFinishArchiveStat &st) -{ - CMyComPtr outArchive; - int formatIndex = options.MethodMode.Type.FormatIndex; - - if (arc) - { - formatIndex = arc->FormatIndex; - if (formatIndex < 0) - return E_NOTIMPL; - CMyComPtr 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 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 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 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 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 outSeekStream; - CMyComPtr 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 sfxStream(sfxStreamSpec); - if (!sfxStreamSpec->Open(options.SfxModule)) - return errorInfo.SetFromLastError("cannot open SFX module", options.SfxModule); - - CMyComPtr 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 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 &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 - -#endif - -HRESULT UpdateArchive( - CCodecs *codecs, - const CObjectVector &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 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 = ! - 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 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 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 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 "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 Stream; + FString Name; + UInt64 Pos; + UInt64 RealSize; + }; + CObjectVector Streams; +public: + // CMyComPtr VolumeCallback; + CRecordVector 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 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 &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 *_arcItems; + IUpdateCallbackUI *_callback; + CDirItemsStat *_stat; + + CUpdateProduceCallbackImp( + const CObjectVector *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 &arcItems, + Byte *processedItemsStatuses, + const CDirItems &dirItems, + const CDirItem *parentDirItem, + CTempFiles &tempFiles, + CUpdateErrorInfo &errorInfo, + IUpdateCallbackUI *callback, + CFinishArchiveStat &st) +{ + CMyComPtr outArchive; + int formatIndex = options.MethodMode.Type.FormatIndex; + + if (arc) + { + formatIndex = arc->FormatIndex; + if (formatIndex < 0) + return E_NOTIMPL; + CMyComPtr 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 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 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 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 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 outSeekStream; + CMyComPtr 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 sfxStream(sfxStreamSpec); + if (!sfxStreamSpec->Open(options.SfxModule)) + return errorInfo.SetFromLastError("cannot open SFX module", options.SfxModule); + + CMyComPtr 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 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 &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 + +#endif + +HRESULT UpdateArchive( + CCodecs *codecs, + const CObjectVector &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 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 = ! + 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 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 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 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; +} diff --git a/CPP/7zip/UI/Common/Update.h b/CPP/7zip/UI/Common/Update.h index 45b02d740..dc9ff5d3c 100644 --- a/CPP/7zip/UI/Common/Update.h +++ b/CPP/7zip/UI/Common/Update.h @@ -1,200 +1,200 @@ -// 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 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 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 RenamePairs; - - bool InitFormatIndex(const CCodecs *codecs, const CObjectVector &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 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 &types, - const UString &cmdArcPath2, - NWildcard::CCensor &censor, - CUpdateOptions &options, - CUpdateErrorInfo &errorInfo, - IOpenCallbackUI *openCallback, - IUpdateCallbackUI2 *callback, - bool needSetPath); - -#endif +// 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 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 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 RenamePairs; + + bool InitFormatIndex(const CCodecs *codecs, const CObjectVector &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 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 &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 ba138d201..a80db7212 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 8d6002f0b..bc53fcdbb 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 __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 diff --git a/CPP/7zip/UI/Common/UpdateCallback.cpp b/CPP/7zip/UI/Common/UpdateCallback.cpp index 9c165fe93..fd46dda85 100644 --- a/CPP/7zip/UI/Common/UpdateCallback.cpp +++ b/CPP/7zip/UI/Common/UpdateCallback.cpp @@ -1,771 +1,771 @@ -// 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 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 inStreamLoc(inStreamSpec); - *inStream = inStreamLoc.Detach(); - } - else - { - CInFileStream *inStreamSpec = new CInFileStream; - CMyComPtr 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 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" + +#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 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 inStreamLoc(inStreamSpec); + *inStream = inStreamLoc.Detach(); + } + else + { + CInFileStream *inStreamSpec = new CInFileStream; + CMyComPtr 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 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; +} diff --git a/CPP/7zip/UI/Common/UpdateCallback.h b/CPP/7zip/UI/Common/UpdateCallback.h index 1b5d1eee8..9e6925f60 100644 --- a/CPP/7zip/UI/Common/UpdateCallback.h +++ b/CPP/7zip/UI/Common/UpdateCallback.h @@ -1,162 +1,162 @@ -// 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 _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 _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 VolumesSizes; - FString VolName; - FString VolExt; - - IUpdateCallbackUI *Callback; - - const CDirItems *DirItems; - const CDirItem *ParentDirItem; - - const CArc *Arc; - CMyComPtr Archive; - const CObjectVector *ArcItems; - const CRecordVector *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 __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 _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 _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 VolumesSizes; + FString VolName; + FString VolExt; + + IUpdateCallbackUI *Callback; + + const CDirItems *DirItems; + const CDirItem *ParentDirItem; + + const CArc *Arc; + CMyComPtr Archive; + const CObjectVector *ArcItems; + const CRecordVector *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 diff --git a/CPP/7zip/UI/Common/UpdatePair.cpp b/CPP/7zip/UI/Common/UpdatePair.cpp index 5153671a7..82876c1d6 100644 --- a/CPP/7zip/UI/Common/UpdatePair.cpp +++ b/CPP/7zip/UI/Common/UpdatePair.cpp @@ -1,233 +1,233 @@ -// UpdatePair.cpp - -#include "StdAfx.h" - -#include - -#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 &arcItems = *(const CObjectVector *)param; - int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]); - if (res != 0) - return res; - return MyCompare(i1, i2); -} - -void GetUpdatePairInfoList( - const CDirItems &dirItems, - const CObjectVector &arcItems, - NFileTimeType::EEnum fileTimeType, - CRecordVector &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 + +#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 &arcItems = *(const CObjectVector *)param; + int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]); + if (res != 0) + return res; + return MyCompare(i1, i2); +} + +void GetUpdatePairInfoList( + const CDirItems &dirItems, + const CObjectVector &arcItems, + NFileTimeType::EEnum fileTimeType, + CRecordVector &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(); +} diff --git a/CPP/7zip/UI/Common/UpdatePair.h b/CPP/7zip/UI/Common/UpdatePair.h index 36da24342..296d3b097 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 &arcItems, - NFileTimeType::EEnum fileTimeType, - CRecordVector &updatePairs); - -#endif +// 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 &arcItems, + NFileTimeType::EEnum fileTimeType, + CRecordVector &updatePairs); + +#endif diff --git a/CPP/7zip/UI/Common/UpdateProduce.cpp b/CPP/7zip/UI/Common/UpdateProduce.cpp index c025ac468..d5052f136 100644 --- a/CPP/7zip/UI/Common/UpdateProduce.cpp +++ b/CPP/7zip/UI/Common/UpdateProduce.cpp @@ -1,70 +1,70 @@ -// 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 &updatePairs, - const CActionSet &actionSet, - CRecordVector &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 &updatePairs, + const CActionSet &actionSet, + CRecordVector &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(); +} diff --git a/CPP/7zip/UI/Common/UpdateProduce.h b/CPP/7zip/UI/Common/UpdateProduce.h index 846754383..64c58cc57 100644 --- a/CPP/7zip/UI/Common/UpdateProduce.h +++ b/CPP/7zip/UI/Common/UpdateProduce.h @@ -1,55 +1,55 @@ -// 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 &updatePairs, - const NUpdateArchive::CActionSet &actionSet, - CRecordVector &operationChain, - IUpdateProduceCallback *callback); - -#endif +// 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 &updatePairs, + const NUpdateArchive::CActionSet &actionSet, + CRecordVector &operationChain, + IUpdateProduceCallback *callback); + +#endif diff --git a/CPP/7zip/UI/Common/WorkDir.cpp b/CPP/7zip/UI/Common/WorkDir.cpp index 03d6eed10..284eaa16a 100644 --- a/CPP/7zip/UI/Common/WorkDir.cpp +++ b/CPP/7zip/UI/Common/WorkDir.cpp @@ -1,94 +1,94 @@ -// 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 "../../../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; +} diff --git a/CPP/7zip/UI/Common/WorkDir.h b/CPP/7zip/UI/Common/WorkDir.h index 13d4ed9fe..75850a92b 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 OutStream; - - HRESULT CreateTempFile(const FString &originalPath); - HRESULT MoveToOriginal(bool deleteOriginal); -}; - -#endif +// 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 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 index 7ad46aa81..d7e856933 100644 --- a/CPP/7zip/UI/Common/ZipRegistry.cpp +++ b/CPP/7zip/UI/Common/ZipRegistry.cpp @@ -1,413 +1,413 @@ -// ZipRegistry.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/Registry.h" -#include "../../../Windows/Synchronization.h" - -#include "../FileManager/RegistryUtils.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-Zstandard") 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_BoolPair(CKey &key, LPCTSTR name, const CBoolPair &b) -{ - if (b.Def) - key.SetValue(name, b.Val); -} - -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); - UStringVector Empty; - - 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); - if (WantPathHistory()) - key.SetValue_Strings(kPathHistory, Paths); - else - key.SetValue_Strings(kPathHistory, Empty); -} - -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 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 kSplitVolume = L"SplitVolume"; -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 void SetRegString(CKey &key, LPCWSTR name, const UString &value) -{ - if (value.IsEmpty()) - key.DeleteValue(name); - else - key.SetValue(name, value); -} - -static void SetRegUInt32(CKey &key, LPCTSTR name, UInt32 value) -{ - if (value == (UInt32)(Int32)-1) - 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 void GetRegUInt32(CKey &key, LPCTSTR name, UInt32 &value) -{ - if (key.QueryValue(name, value) != ERROR_SUCCESS) - value = (UInt32)(Int32)-1; -} - -void CInfo::Save() const -{ - UStringVector Empty; - CS_LOCK - - CKey key; - CreateMainKey(key, kKeyName); - - Key_Set_BoolPair(key, kNtSecur, NtSecurity); - Key_Set_BoolPair(key, kAltStreams, AltStreams); - Key_Set_BoolPair(key, kHardLinks, HardLinks); - Key_Set_BoolPair(key, kSymLinks, SymLinks); - - key.SetValue(kShowPassword, ShowPassword); - key.SetValue(kLevel, (UInt32)Level); - key.SetValue(kArchiver, ArcType); - key.SetValue(kShowPassword, ShowPassword); - key.SetValue(kEncryptHeaders, EncryptHeaders); - key.RecurseDeleteKey(kArcHistory); - - if (WantArcHistory()) - key.SetValue_Strings(kArcHistory, ArcPaths); - else - key.SetValue_Strings(kArcHistory, Empty); - - 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); - - SetRegUInt32(fk, kLevel, fo.Level); - SetRegUInt32(fk, kDictionary, fo.Dictionary); - SetRegUInt32(fk, kOrder, fo.Order); - SetRegUInt32(fk, kBlockSize, fo.BlockLogSize); - SetRegUInt32(fk, kNumThreads, fo.NumThreads); - - SetRegString(fk, kMethod, fo.Method); - SetRegString(fk, kOptions, fo.Options); - SetRegString(fk, kSplitVolume, fo.SplitVolume); - SetRegString(fk, kEncryptionMethod, fo.EncryptionMethod); - } - } -} - -void CInfo::Load() -{ - ArcPaths.Clear(); - Formats.Clear(); - - Level = 5; - ArcType = L"7z"; - ShowPassword = false; - EncryptHeaders = false; - - CS_LOCK - CKey key; - - if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS) - return; - - Key_Get_BoolPair(key, kNtSecur, NtSecurity); - Key_Get_BoolPair(key, kAltStreams, AltStreams); - Key_Get_BoolPair(key, kHardLinks, HardLinks); - Key_Get_BoolPair(key, kSymLinks, SymLinks); - - 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, kSplitVolume, fo.SplitVolume); - GetRegString(fk, kEncryptionMethod, fo.EncryptionMethod); - - GetRegUInt32(fk, kLevel, fo.Level); - GetRegUInt32(fk, kDictionary, fo.Dictionary); - GetRegUInt32(fk, kOrder, fo.Order); - GetRegUInt32(fk, kBlockSize, fo.BlockLogSize); - GetRegUInt32(fk, kNumThreads, fo.NumThreads); - - Formats.Add(fo); - } - } - } - } - - UString a; - if (key.QueryValue(kArchiver, a) == ERROR_SUCCESS) - ArcType = a; - key.GetValue_IfOk(kLevel, Level); - key.GetValue_IfOk(kShowPassword, ShowPassword); - key.GetValue_IfOk(kEncryptHeaders, EncryptHeaders); -} - -} - -static 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"); - -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); - - 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; - - Flags = (UInt32)(Int32)-1; - 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); - - Flags_Def = (key.GetValue_IfOk(kContextMenu, Flags) == ERROR_SUCCESS); -} +// ZipRegistry.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/Registry.h" +#include "../../../Windows/Synchronization.h" + +#include "../FileManager/RegistryUtils.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-Zstandard") 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_BoolPair(CKey &key, LPCTSTR name, const CBoolPair &b) +{ + if (b.Def) + key.SetValue(name, b.Val); +} + +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); + UStringVector Empty; + + 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); + if (WantPathHistory()) + key.SetValue_Strings(kPathHistory, Paths); + else + key.SetValue_Strings(kPathHistory, Empty); +} + +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 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 kSplitVolume = L"SplitVolume"; +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 void SetRegString(CKey &key, LPCWSTR name, const UString &value) +{ + if (value.IsEmpty()) + key.DeleteValue(name); + else + key.SetValue(name, value); +} + +static void SetRegUInt32(CKey &key, LPCTSTR name, UInt32 value) +{ + if (value == (UInt32)(Int32)-1) + 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 void GetRegUInt32(CKey &key, LPCTSTR name, UInt32 &value) +{ + if (key.QueryValue(name, value) != ERROR_SUCCESS) + value = (UInt32)(Int32)-1; +} + +void CInfo::Save() const +{ + UStringVector Empty; + CS_LOCK + + CKey key; + CreateMainKey(key, kKeyName); + + Key_Set_BoolPair(key, kNtSecur, NtSecurity); + Key_Set_BoolPair(key, kAltStreams, AltStreams); + Key_Set_BoolPair(key, kHardLinks, HardLinks); + Key_Set_BoolPair(key, kSymLinks, SymLinks); + + key.SetValue(kShowPassword, ShowPassword); + key.SetValue(kLevel, (UInt32)Level); + key.SetValue(kArchiver, ArcType); + key.SetValue(kShowPassword, ShowPassword); + key.SetValue(kEncryptHeaders, EncryptHeaders); + key.RecurseDeleteKey(kArcHistory); + + if (WantArcHistory()) + key.SetValue_Strings(kArcHistory, ArcPaths); + else + key.SetValue_Strings(kArcHistory, Empty); + + 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); + + SetRegUInt32(fk, kLevel, fo.Level); + SetRegUInt32(fk, kDictionary, fo.Dictionary); + SetRegUInt32(fk, kOrder, fo.Order); + SetRegUInt32(fk, kBlockSize, fo.BlockLogSize); + SetRegUInt32(fk, kNumThreads, fo.NumThreads); + + SetRegString(fk, kMethod, fo.Method); + SetRegString(fk, kOptions, fo.Options); + SetRegString(fk, kSplitVolume, fo.SplitVolume); + SetRegString(fk, kEncryptionMethod, fo.EncryptionMethod); + } + } +} + +void CInfo::Load() +{ + ArcPaths.Clear(); + Formats.Clear(); + + Level = 5; + ArcType = L"7z"; + ShowPassword = false; + EncryptHeaders = false; + + CS_LOCK + CKey key; + + if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS) + return; + + Key_Get_BoolPair(key, kNtSecur, NtSecurity); + Key_Get_BoolPair(key, kAltStreams, AltStreams); + Key_Get_BoolPair(key, kHardLinks, HardLinks); + Key_Get_BoolPair(key, kSymLinks, SymLinks); + + 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, kSplitVolume, fo.SplitVolume); + GetRegString(fk, kEncryptionMethod, fo.EncryptionMethod); + + GetRegUInt32(fk, kLevel, fo.Level); + GetRegUInt32(fk, kDictionary, fo.Dictionary); + GetRegUInt32(fk, kOrder, fo.Order); + GetRegUInt32(fk, kBlockSize, fo.BlockLogSize); + GetRegUInt32(fk, kNumThreads, fo.NumThreads); + + Formats.Add(fo); + } + } + } + } + + UString a; + if (key.QueryValue(kArchiver, a) == ERROR_SUCCESS) + ArcType = a; + key.GetValue_IfOk(kLevel, Level); + key.GetValue_IfOk(kShowPassword, ShowPassword); + key.GetValue_IfOk(kEncryptHeaders, EncryptHeaders); +} + +} + +static 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"); + +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); + + 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; + + Flags = (UInt32)(Int32)-1; + 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); + + 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 8fe857ac1..31416c714 100644 --- a/CPP/7zip/UI/Common/ZipRegistry.h +++ b/CPP/7zip/UI/Common/ZipRegistry.h @@ -1,131 +1,131 @@ -// 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 SplitVolume; - 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 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 __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 SplitVolume; + 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 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 diff --git a/CPP/7zip/UI/Console/BenchCon.cpp b/CPP/7zip/UI/Console/BenchCon.cpp index 9cf8dd6dc..a7c9e6762 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 &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: 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 &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 ef235eea3..c9da1de39 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 - -#include "../../Common/CreateCoder.h" -#include "../../UI/Common/Property.h" - -HRESULT BenchCon(DECL_EXTERNAL_CODECS_LOC_VARS - const CObjectVector &props, UInt32 numIterations, FILE *f); - -#endif +// BenchCon.h + +#ifndef __BENCH_CON_H +#define __BENCH_CON_H + +#include + +#include "../../Common/CreateCoder.h" +#include "../../UI/Common/Property.h" + +HRESULT BenchCon(DECL_EXTERNAL_CODECS_LOC_VARS + const CObjectVector &props, UInt32 numIterations, FILE *f); + +#endif diff --git a/CPP/7zip/UI/Console/Console.dsp b/CPP/7zip/UI/Console/Console.dsp index 3da9da50c..34918e38e 100644 --- a/CPP/7zip/UI/Console/Console.dsp +++ b/CPP/7zip/UI/Console/Console.dsp @@ -1,984 +1,984 @@ -# 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 "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /D "_7ZIP_LARGE_PAGES" /D "SUPPORT_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 "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /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\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 "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /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\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 "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /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\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\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 "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\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\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\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\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\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\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\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 +# 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 "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /D "_7ZIP_LARGE_PAGES" /D "SUPPORT_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 "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /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\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 "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /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\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 "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /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\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\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 "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\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\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\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\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\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\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\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 index 6e37f110a..0d93da2f6 100644 --- a/CPP/7zip/UI/Console/Console.dsw +++ b/CPP/7zip/UI/Console/Console.dsw @@ -1,29 +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> -{{{ -}}} - -############################################################################### - +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 d4268c54d..bd4c1da4f 100644 --- a/CPP/7zip/UI/Console/Console.mak +++ b/CPP/7zip/UI/Console/Console.mak @@ -1,43 +1,43 @@ -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) -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 \ diff --git a/CPP/7zip/UI/Console/Console.manifest b/CPP/7zip/UI/Console/Console.manifest index 77ecaad72..58b68ced8 100644 --- a/CPP/7zip/UI/Console/Console.manifest +++ b/CPP/7zip/UI/Console/Console.manifest @@ -1,13 +1,13 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/CPP/7zip/UI/Console/ConsoleClose.cpp b/CPP/7zip/UI/Console/ConsoleClose.cpp index a6f17af93..703f82139 100644 --- a/CPP/7zip/UI/Console/ConsoleClose.cpp +++ b/CPP/7zip/UI/Console/ConsoleClose.cpp @@ -1,69 +1,69 @@ -// 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" + +#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 +} + +} diff --git a/CPP/7zip/UI/Console/ConsoleClose.h b/CPP/7zip/UI/Console/ConsoleClose.h index 0a0bbf0e0..11c1631ca 100644 --- a/CPP/7zip/UI/Console/ConsoleClose.h +++ b/CPP/7zip/UI/Console/ConsoleClose.h @@ -1,33 +1,33 @@ -// 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 __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 diff --git a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp index bdf954998..21c2f0712 100644 --- a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp +++ b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp @@ -1,825 +1,825 @@ -// 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 _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(); +} diff --git a/CPP/7zip/UI/Console/ExtractCallbackConsole.h b/CPP/7zip/UI/Console/ExtractCallbackConsole.h index 5de6c5b2a..dc659521e 100644 --- a/CPP/7zip/UI/Console/ExtractCallbackConsole.h +++ b/CPP/7zip/UI/Console/ExtractCallbackConsole.h @@ -1,164 +1,164 @@ -// 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 __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 diff --git a/CPP/7zip/UI/Console/HashCon.cpp b/CPP/7zip/UI/Console/HashCon.cpp index 3ade0fda8..762b21bb5 100644 --- a/CPP/7zip/UI/Console/HashCon.cpp +++ b/CPP/7zip/UI/Console/HashCon.cpp @@ -1,367 +1,367 @@ -// 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 &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 &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 "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 &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 &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; +} diff --git a/CPP/7zip/UI/Console/HashCon.h b/CPP/7zip/UI/Console/HashCon.h index 9c12869eb..5b30b69a0 100644 --- a/CPP/7zip/UI/Console/HashCon.h +++ b/CPP/7zip/UI/Console/HashCon.h @@ -1,48 +1,48 @@ -// 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 &hashers); - void PrintResultLine(UInt64 fileSize, - const CObjectVector &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 __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 &hashers); + void PrintResultLine(UInt64 fileSize, + const CObjectVector &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 diff --git a/CPP/7zip/UI/Console/List.cpp b/CPP/7zip/UI/Console/List.cpp index c56e2e218..416ef2c92 100644 --- a/CPP/7zip/UI/Console/List.cpp +++ b/CPP/7zip/UI/Console/List.cpp @@ -1,1359 +1,1359 @@ -// 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 _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 &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 *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 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" +}; + +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 _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 &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 *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 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; +} diff --git a/CPP/7zip/UI/Console/List.h b/CPP/7zip/UI/Console/List.h index dabbc2a60..462c47103 100644 --- a/CPP/7zip/UI/Console/List.h +++ b/CPP/7zip/UI/Console/List.h @@ -1,27 +1,27 @@ -// List.h - -#ifndef __LIST_H -#define __LIST_H - -#include "../../../Common/Wildcard.h" - -#include "../Common/LoadCodecs.h" - -HRESULT ListArchives(CCodecs *codecs, - const CObjectVector &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 *props, - #endif - UInt64 &errors, - UInt64 &numWarnings); - -#endif +// List.h + +#ifndef __LIST_H +#define __LIST_H + +#include "../../../Common/Wildcard.h" + +#include "../Common/LoadCodecs.h" + +HRESULT ListArchives(CCodecs *codecs, + const CObjectVector &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 *props, + #endif + UInt64 &errors, + UInt64 &numWarnings); + +#endif diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp index 4d7aac900..333223bd0 100644 --- a/CPP/7zip/UI/Console/Main.cpp +++ b/CPP/7zip/UI/Console/Main.cpp @@ -1,1154 +1,1154 @@ -// Main.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#ifdef _WIN32 -#include -#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 - " [...] [...] [@listfile]\n" - "\n" - "\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" - "\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 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 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 +#include +#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 + " [...] [...] [@listfile]\n" + "\n" + "\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" + "\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 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 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; +} diff --git a/CPP/7zip/UI/Console/MainAr.cpp b/CPP/7zip/UI/Console/MainAr.cpp index 1d6c5a42f..87bf57e85 100644 --- a/CPP/7zip/UI/Console/MainAr.cpp +++ b/CPP/7zip/UI/Console/MainAr.cpp @@ -1,175 +1,175 @@ -// 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 "../../../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; +} diff --git a/CPP/7zip/UI/Console/OpenCallbackConsole.cpp b/CPP/7zip/UI/Console/OpenCallbackConsole.cpp index 6e58c1f96..a074fa1fb 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 _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 b9270f8e2..64c1dad39 100644 --- a/CPP/7zip/UI/Console/OpenCallbackConsole.h +++ b/CPP/7zip/UI/Console/OpenCallbackConsole.h @@ -1,66 +1,66 @@ -// 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 __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 diff --git a/CPP/7zip/UI/Console/PercentPrinter.cpp b/CPP/7zip/UI/Console/PercentPrinter.cpp index 20249ed03..b2426878e 100644 --- a/CPP/7zip/UI/Console/PercentPrinter.cpp +++ b/CPP/7zip/UI/Console/PercentPrinter.cpp @@ -1,183 +1,183 @@ -// 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) + { + 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; +} diff --git a/CPP/7zip/UI/Console/PercentPrinter.h b/CPP/7zip/UI/Console/PercentPrinter.h index 90b4083ed..95290b37e 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 __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 diff --git a/CPP/7zip/UI/Console/StdAfx.cpp b/CPP/7zip/UI/Console/StdAfx.cpp index c6d3b1fa6..d0feea85c 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 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/UI/Console/StdAfx.h +++ b/CPP/7zip/UI/Console/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp index 46ffaba02..cd232fff7 100644 --- a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp +++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp @@ -1,702 +1,702 @@ -// 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" + +#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; +} diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.h b/CPP/7zip/UI/Console/UpdateCallbackConsole.h index 6765db677..ba8614eba 100644 --- a/CPP/7zip/UI/Console/UpdateCallbackConsole.h +++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.h @@ -1,124 +1,124 @@ -// 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 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 __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 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 diff --git a/CPP/7zip/UI/Console/UserInputUtils.cpp b/CPP/7zip/UI/Console/UserInputUtils.cpp index 7bdafdae5..0e2d7ac17 100644 --- a/CPP/7zip/UI/Console/UserInputUtils.cpp +++ b/CPP/7zip/UI/Console/UserInputUtils.cpp @@ -1,110 +1,110 @@ -// 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 + + 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; +} diff --git a/CPP/7zip/UI/Console/UserInputUtils.h b/CPP/7zip/UI/Console/UserInputUtils.h index ebe09c1eb..256feafef 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 __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 diff --git a/CPP/7zip/UI/Console/makefile b/CPP/7zip/UI/Console/makefile index 2210e0b8c..541b7681a 100644 --- a/CPP/7zip/UI/Console/makefile +++ b/CPP/7zip/UI/Console/makefile @@ -1,64 +1,64 @@ -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) \ + -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" diff --git a/CPP/7zip/UI/Console/resource.rc b/CPP/7zip/UI/Console/resource.rc index 8d721f509..414427fb2 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 index 9276dfb8d..cba1c5df4 100644 --- a/CPP/7zip/UI/Explorer/7-zip.dll.manifest +++ b/CPP/7zip/UI/Explorer/7-zip.dll.manifest @@ -1 +1 @@ -7-Zip Extension. +7-Zip Extension. diff --git a/CPP/7zip/UI/Explorer/ContextMenu.cpp b/CPP/7zip/UI/Explorer/ContextMenu.cpp index ea3b231cb..9feaf216e 100644 --- a/CPP/7zip/UI/Explorer/ContextMenu.cpp +++ b/CPP/7zip/UI/Explorer/ContextMenu.cpp @@ -1,1036 +1,1036 @@ -// ContextMenu.cpp - -#include "StdAfx.h" - -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/COM.h" -#include "../../../Windows/DLL.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/MemoryGlobal.h" -#include "../../../Windows/Menu.h" -#include "../../../Windows/ProcessUtils.h" -#include "../../../Windows/Shell.h" - -#include "../Common/ArchiveName.h" -#include "../Common/CompressCall.h" -#include "../Common/ExtractingFilePath.h" -#include "../Common/ZipRegistry.h" - -#include "../FileManager/FormatUtils.h" - -#ifdef LANG -#include "../FileManager/LangUtils.h" -#endif - -#include "ContextMenu.h" -#include "ContextMenuFlags.h" -#include "MyMessages.h" - -#include "resource.h" - -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 - -CZipContextMenu::CZipContextMenu(): - _isMenuForFM(false), - _bitmap(NULL) -{ - InterlockedIncrement(&g_DllRefCount); - _bitmap = ::LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_MENU_LOGO)); -} - -CZipContextMenu::~CZipContextMenu() -{ - if (_bitmap != NULL) - DeleteObject(_bitmap); - InterlockedDecrement(&g_DllRefCount); -} - -HRESULT CZipContextMenu::GetFileNames(LPDATAOBJECT dataObject, UStringVector &fileNames) -{ - fileNames.Clear(); - if (dataObject == NULL) - return E_FAIL; - - #ifndef UNDER_CE - - FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; - NCOM::CStgMedium stgMedium; - HRESULT result = dataObject->GetData(&fmte, &stgMedium); - if (result != S_OK) - return result; - stgMedium._mustBeReleased = true; - - NShell::CDrop drop(false); - NMemory::CGlobalLock globalLock(stgMedium->hGlobal); - drop.Attach((HDROP)globalLock.GetPointer()); - drop.QueryFileNames(fileNames); - - #endif - - return S_OK; -} - -// IShellExtInit - -STDMETHODIMP CZipContextMenu::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT dataObject, HKEY /* hkeyProgID */) -{ - // OutputDebugString(TEXT("::Initialize\r\n")); - _dropMode = false; - _dropPath.Empty(); - if (pidlFolder != 0) - { - #ifndef UNDER_CE - if (NShell::GetPathFromIDList(pidlFolder, _dropPath)) - { - // OutputDebugString(path); - // OutputDebugString(TEXT("\r\n")); - NName::NormalizeDirPathPrefix(_dropPath); - _dropMode = !_dropPath.IsEmpty(); - } - else - #endif - _dropPath.Empty(); - } - - /* - m_IsFolder = false; - if (pidlFolder == 0) - */ - // pidlFolder is NULL :( - return GetFileNames(dataObject, _fileNames); -} - -HRESULT CZipContextMenu::InitContextMenu(const wchar_t * /* folder */, const wchar_t * const *names, unsigned numFiles) -{ - _isMenuForFM = true; - _fileNames.Clear(); - for (UInt32 i = 0; i < numFiles; i++) - { - // MessageBoxW(0, names[i], NULL, 0); - // OutputDebugStringW(names[i]); - _fileNames.Add(names[i]); - } - _dropMode = false; - return S_OK; -} - - -///////////////////////////// -// IContextMenu - -static LPCSTR const kMainVerb = "SevenZipZS"; -static LPCSTR const kOpenCascadedVerb = "SevenZipZS.OpenWithType."; -static LPCSTR const kCheckSumCascadedVerb = "SevenZipZS.Checksum"; - - -struct CContextMenuCommand -{ - UInt32 flag; - CZipContextMenu::ECommandInternalID CommandInternalID; - LPCSTR Verb; - UINT ResourceID; -}; - -static const CContextMenuCommand g_Commands[] = -{ - { - NContextMenuFlags::kOpen, - CZipContextMenu::kOpen, - "Open", - IDS_CONTEXT_OPEN - }, - { - NContextMenuFlags::kExtract, - CZipContextMenu::kExtract, - "Extract", - IDS_CONTEXT_EXTRACT - }, - { - NContextMenuFlags::kExtractHere, - CZipContextMenu::kExtractHere, - "ExtractHere", - IDS_CONTEXT_EXTRACT_HERE - }, - { - NContextMenuFlags::kExtractTo, - CZipContextMenu::kExtractTo, - "ExtractTo", - IDS_CONTEXT_EXTRACT_TO - }, - { - NContextMenuFlags::kTest, - CZipContextMenu::kTest, - "Test", - IDS_CONTEXT_TEST - }, - { - NContextMenuFlags::kCompress, - CZipContextMenu::kCompress, - "Compress", - IDS_CONTEXT_COMPRESS - }, - { - NContextMenuFlags::kCompressEmail, - CZipContextMenu::kCompressEmail, - "CompressEmail", - IDS_CONTEXT_COMPRESS_EMAIL - }, - { - NContextMenuFlags::kCompressTo7z, - CZipContextMenu::kCompressTo7z, - "CompressTo7z", - IDS_CONTEXT_COMPRESS_TO - }, - { - NContextMenuFlags::kCompressTo7zEmail, - CZipContextMenu::kCompressTo7zEmail, - "CompressTo7zEmail", - IDS_CONTEXT_COMPRESS_TO_EMAIL - }, - { - NContextMenuFlags::kCompressToZip, - CZipContextMenu::kCompressToZip, - "CompressToZip", - IDS_CONTEXT_COMPRESS_TO - }, - { - NContextMenuFlags::kCompressToZipEmail, - CZipContextMenu::kCompressToZipEmail, - "CompressToZipEmail", - IDS_CONTEXT_COMPRESS_TO_EMAIL - } -}; - -struct CHashCommand -{ - CZipContextMenu::ECommandInternalID CommandInternalID; - LPCSTR UserName; - LPCSTR MethodName; -}; - -static const CHashCommand g_HashCommands[] = -{ - { CZipContextMenu::kHash_CRC32, "CRC-32", "CRC32" }, - { CZipContextMenu::kHash_CRC64, "CRC-64", "CRC64" }, - { CZipContextMenu::kHash_XXH32, "XXH-32", "XXH32" }, - { CZipContextMenu::kHash_XXH64, "XXH-64", "XXH64" }, - { CZipContextMenu::kHash_MD2, "MD2", "MD2" }, - { CZipContextMenu::kHash_MD4, "MD4", "MD4" }, - { CZipContextMenu::kHash_MD5, "MD5", "MD5" }, - { CZipContextMenu::kHash_SHA1, "SHA-1", "SHA1" }, - { CZipContextMenu::kHash_SHA256, "SHA-256", "SHA256" }, - { CZipContextMenu::kHash_SHA384, "SHA-384", "SHA384" }, - { CZipContextMenu::kHash_SHA512, "SHA-512", "SHA512" }, - { CZipContextMenu::kHash_BLAKE2sp, "BLAKE2sp", "BLAKE2sp" }, - { CZipContextMenu::kHash_All, "*", "*" } -}; - -static int FindCommand(CZipContextMenu::ECommandInternalID &id) -{ - for (unsigned i = 0; i < ARRAY_SIZE(g_Commands); i++) - if (g_Commands[i].CommandInternalID == id) - return i; - return -1; -} - -bool CZipContextMenu::FillCommand(ECommandInternalID id, UString &mainString, CCommandMapItem &commandMapItem) -{ - mainString.Empty(); - int i = FindCommand(id); - if (i < 0) - return false; - const CContextMenuCommand &command = g_Commands[i]; - commandMapItem.CommandInternalID = command.CommandInternalID; - commandMapItem.Verb = kMainVerb; - commandMapItem.Verb += command.Verb; - // LangString(command.ResourceHelpID, command.LangID + 1, commandMapItem.HelpString); - LangString(command.ResourceID, mainString); - return true; -} - -static bool MyInsertMenu(CMenu &menu, int pos, UINT id, const UString &s, HBITMAP bitmap) -{ - 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 ??? - return menu.InsertItem(pos, true, mi); - - // SetMenuItemBitmaps also works - // ::SetMenuItemBitmaps(menu, pos, MF_BYPOSITION, bitmap, NULL); -} - -static const char * const kArcExts[] = -{ - "7z" - , "bz2" - , "gz" - , "lz" - , "liz" - , "lz4" - , "lz5" - , "rar" - , "zip" - , "zst" -}; - -static bool IsItArcExt(const UString &ext) -{ - for (unsigned i = 0; i < ARRAY_SIZE(kArcExts); i++) - if (ext.IsEqualTo_Ascii_NoCase(kArcExts[i])) - return true; - return false; -} - -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 kExtractExludeExtensions = - " 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" -}; - -static bool FindExt(const char *p, const FString &name) -{ - int dotPos = name.ReverseFind_Dot(); - if (dotPos < 0 || dotPos == (int)name.Len() - 1) - return false; - - AString s; - - for (unsigned pos = dotPos + 1;; pos++) - { - 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 bool DoNeedExtract(const FString &name) -{ - return !FindExt(kExtractExludeExtensions, name); -} - -// we must use diferent Verbs for Popup subMenu. -void CZipContextMenu::AddMapItem_ForSubMenu(const char *verb) -{ - CCommandMapItem commandMapItem; - commandMapItem.CommandInternalID = kCommandNULL; - commandMapItem.Verb = verb; - _commandMap.Add(commandMapItem); -} - - -STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, - UINT commandIDFirst, UINT commandIDLast, UINT flags) -{ - // OutputDebugStringA("QueryContextMenu"); - - /* - for (UInt32 i = 0; i < _fileNames.Size(); i++) - { - OutputDebugStringW(_fileNames[i]); - } - */ - - LoadLangOneTime(); - if (_fileNames.Size() == 0) - return E_FAIL; - UINT currentCommandID = commandIDFirst; - if ((flags & 0x000F) != CMF_NORMAL && - (flags & CMF_VERBSONLY) == 0 && - (flags & CMF_EXPLORE) == 0) - return MAKE_HRESULT(SEVERITY_SUCCESS, 0, currentCommandID); - - _commandMap.Clear(); - - CMenu popupMenu; - CMenuDestroyer menuDestroyer; - - CContextMenuInfo ci; - ci.Load(); - - _elimDup = ci.ElimDup; - - HBITMAP bitmap = NULL; - if (ci.MenuIcons.Val) - bitmap = _bitmap; - - UINT subIndex = indexMenu; - - if (ci.Cascaded.Val) - { - if (!popupMenu.CreatePopup()) - return E_FAIL; - 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; - popupMenu.InsertItem(subIndex++, true, mi); - } - - 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)); // change it 4 - must be constant - folderPrefix = - #ifdef UNDER_CE - "\\"; - #else - "C:\\"; - #endif - } - else - #endif - { - if (!fi0.Find(us2fs(fileName))) - return E_FAIL; - GetOnlyDirPrefix(us2fs(fileName), folderPrefix); - } - } - - UString mainString; - - if (_fileNames.Size() == 1 && currentCommandID + 14 <= commandIDLast) - { - if (!fi0.IsDir() && DoNeedExtract(fi0.Name)) - { - // Open - bool thereIsMainOpenItem = ((contextMenuFlags & NContextMenuFlags::kOpen) != 0); - if (thereIsMainOpenItem) - { - CCommandMapItem commandMapItem; - FillCommand(kOpen, mainString, commandMapItem); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); - _commandMap.Add(commandMapItem); - } - if ((contextMenuFlags & NContextMenuFlags::kOpenAs) != 0 - // && (!thereIsMainOpenItem || !FindExt(kNoOpenAsExtensions, fi0.Name)) - ) - { - CMenu subMenu; - if (subMenu.CreatePopup()) - { - CMenuItem mi; - mi.fType = MFT_STRING; - mi.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID; - if (bitmap) - mi.fMask |= MIIM_CHECKMARKS; - mi.wID = currentCommandID++; - mi.hSubMenu = subMenu; - mi.hbmpUnchecked = bitmap; - - LangString(IDS_CONTEXT_OPEN, mi.StringValue); - popupMenu.InsertItem(subIndex++, true, mi); - AddMapItem_ForSubMenu(kOpenCascadedVerb); - - UINT subIndex2 = 0; - for (unsigned i = (thereIsMainOpenItem ? 1 : 0); i < ARRAY_SIZE(kOpenTypes); i++) - { - CCommandMapItem commandMapItem; - if (i == 0) - FillCommand(kOpen, mainString, commandMapItem); - else - { - mainString = kOpenTypes[i]; - commandMapItem.CommandInternalID = kOpen; - commandMapItem.Verb = kMainVerb; - commandMapItem.Verb += ".Open."; - commandMapItem.Verb += mainString; - commandMapItem.HelpString = mainString; - commandMapItem.ArcType = mainString; - } - MyInsertMenu(subMenu, subIndex2++, currentCommandID++, mainString, bitmap); - _commandMap.Add(commandMapItem); - } - - subMenu.Detach(); - } - } - } - } - - if (_fileNames.Size() > 0 && currentCommandID + 10 <= commandIDLast) - { - bool needExtract = (!fi0.IsDir() && DoNeedExtract(fi0.Name)); - - if (!needExtract) - { - for (unsigned i = 1; i < _fileNames.Size(); i++) - { - NFind::CFileInfo fi; - if (!fi.Find(us2fs(_fileNames[i]))) - return E_FAIL; - if (!fi.IsDir() && DoNeedExtract(fi.Name)) - { - needExtract = true; - break; - } - } - } - - // const UString &fileName = _fileNames.Front(); - - 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 commandMapItem; - FillCommand(kExtract, mainString, commandMapItem); - commandMapItem.Folder = baseFolder + specFolder; - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); - _commandMap.Add(commandMapItem); - } - - if ((contextMenuFlags & NContextMenuFlags::kExtractHere) != 0) - { - // Extract Here - CCommandMapItem commandMapItem; - FillCommand(kExtractHere, mainString, commandMapItem); - commandMapItem.Folder = baseFolder; - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); - _commandMap.Add(commandMapItem); - } - - if ((contextMenuFlags & NContextMenuFlags::kExtractTo) != 0) - { - // Extract To - CCommandMapItem commandMapItem; - UString s; - FillCommand(kExtractTo, s, commandMapItem); - commandMapItem.Folder = baseFolder + specFolder; - MyFormatNew_ReducedName(s, specFolder); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); - _commandMap.Add(commandMapItem); - } - } - - if ((contextMenuFlags & NContextMenuFlags::kTest) != 0) - { - // Test - CCommandMapItem commandMapItem; - FillCommand(kTest, mainString, commandMapItem); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); - _commandMap.Add(commandMapItem); - } - } - - const UString arcName = CreateArchiveName(_fileNames, _fileNames.Size() == 1 ? &fi0 : NULL); - - UString arcName7z = arcName; - arcName7z += ".7z"; - UString arcNameZip = arcName; - arcNameZip += ".zip"; - - // Compress - if ((contextMenuFlags & NContextMenuFlags::kCompress) != 0) - { - CCommandMapItem commandMapItem; - if (_dropMode) - commandMapItem.Folder = _dropPath; - else - commandMapItem.Folder = fs2us(folderPrefix); - commandMapItem.ArcName = arcName; - FillCommand(kCompress, mainString, commandMapItem); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); - _commandMap.Add(commandMapItem); - } - - #ifdef EMAIL_SUPPORT - // CompressEmail - if ((contextMenuFlags & NContextMenuFlags::kCompressEmail) != 0 && !_dropMode) - { - CCommandMapItem commandMapItem; - commandMapItem.ArcName = arcName; - FillCommand(kCompressEmail, mainString, commandMapItem); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); - _commandMap.Add(commandMapItem); - } - #endif - - // CompressTo7z - if (contextMenuFlags & NContextMenuFlags::kCompressTo7z && - !arcName7z.IsEqualTo_NoCase(fs2us(fi0.Name))) - { - CCommandMapItem commandMapItem; - UString s; - FillCommand(kCompressTo7z, s, commandMapItem); - if (_dropMode) - commandMapItem.Folder = _dropPath; - else - commandMapItem.Folder = fs2us(folderPrefix); - commandMapItem.ArcName = arcName7z; - commandMapItem.ArcType = "7z"; - MyFormatNew_ReducedName(s, arcName7z); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); - _commandMap.Add(commandMapItem); - } - - #ifdef EMAIL_SUPPORT - // CompressTo7zEmail - if ((contextMenuFlags & NContextMenuFlags::kCompressTo7zEmail) != 0 && !_dropMode) - { - CCommandMapItem commandMapItem; - UString s; - FillCommand(kCompressTo7zEmail, s, commandMapItem); - commandMapItem.ArcName = arcName7z; - commandMapItem.ArcType = "7z"; - MyFormatNew_ReducedName(s, arcName7z); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); - _commandMap.Add(commandMapItem); - } - #endif - - // CompressToZip - if (contextMenuFlags & NContextMenuFlags::kCompressToZip && - !arcNameZip.IsEqualTo_NoCase(fs2us(fi0.Name))) - { - CCommandMapItem commandMapItem; - UString s; - FillCommand(kCompressToZip, s, commandMapItem); - if (_dropMode) - commandMapItem.Folder = _dropPath; - else - commandMapItem.Folder = fs2us(folderPrefix); - commandMapItem.ArcName = arcNameZip; - commandMapItem.ArcType = "zip"; - MyFormatNew_ReducedName(s, arcNameZip); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); - _commandMap.Add(commandMapItem); - } - - #ifdef EMAIL_SUPPORT - // CompressToZipEmail - if ((contextMenuFlags & NContextMenuFlags::kCompressToZipEmail) != 0 && !_dropMode) - { - CCommandMapItem commandMapItem; - UString s; - FillCommand(kCompressToZipEmail, s, commandMapItem); - commandMapItem.ArcName = arcNameZip; - commandMapItem.ArcType = "zip"; - MyFormatNew_ReducedName(s, arcNameZip); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); - _commandMap.Add(commandMapItem); - } - #endif - } - - - // 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) - { - CMenuItem mi; - mi.fType = MFT_STRING; - mi.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID; - if (bitmap) - mi.fMask |= MIIM_CHECKMARKS; - mi.wID = currentCommandID++; - mi.hSubMenu = popupMenu.Detach(); - mi.StringValue = "7-Zip ZS"; // LangString(IDS_CONTEXT_POPUP_CAPTION); - mi.hbmpUnchecked = bitmap; - - CMenu menu; - menu.Attach(hMenu); - menuDestroyer.Disable(); - menu.InsertItem(indexMenu++, true, mi); - - AddMapItem_ForSubMenu(kMainVerb); - } - else - { - popupMenu.Detach(); - indexMenu = subIndex; - } - - - if (!_isMenuForFM && - ((contextMenuFlags & NContextMenuFlags::kCRC) != 0 - && currentCommandID + 6 <= commandIDLast)) - { - CMenu subMenu; - // CMenuDestroyer menuDestroyer_CRC; - - UINT subIndex_CRC = 0; - - if (subMenu.CreatePopup()) - { - // menuDestroyer_CRC.Attach(subMenu); - CMenuItem mi; - mi.fType = MFT_STRING; - mi.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID; - if (bitmap) - mi.fMask |= MIIM_CHECKMARKS; - mi.wID = currentCommandID++; - mi.hSubMenu = subMenu; - mi.StringValue = "7-Zip ZS Hash"; - mi.hbmpUnchecked = bitmap; - - CMenu menu; - menu.Attach(hMenu); - // menuDestroyer_CRC.Disable(); - menu.InsertItem(indexMenu++, true, mi); - - AddMapItem_ForSubMenu(kCheckSumCascadedVerb); - - for (unsigned i = 0; i < ARRAY_SIZE(g_HashCommands); i++) - { - const CHashCommand &hc = g_HashCommands[i]; - CCommandMapItem commandMapItem; - commandMapItem.CommandInternalID = hc.CommandInternalID; - commandMapItem.Verb = kCheckSumCascadedVerb; - commandMapItem.Verb += hc.MethodName; - // commandMapItem.HelpString = hc.Name; - MyInsertMenu(subMenu, subIndex_CRC++, currentCommandID++, (UString)hc.UserName, bitmap); - _commandMap.Add(commandMapItem); - } - - subMenu.Detach(); - } - } - - return MAKE_HRESULT(SEVERITY_SUCCESS, 0, currentCommandID - commandIDFirst); -} - - -int CZipContextMenu::FindVerb(const UString &verb) -{ - FOR_VECTOR (i, _commandMap) - if (_commandMap[i].Verb == verb) - return i; - return -1; -} - -static UString Get7zFmPath() -{ - return fs2us(NWindows::NDLL::GetModuleDirPrefix()) + L"7zFM.exe"; -} - -STDMETHODIMP CZipContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO commandInfo) -{ - // ::OutputDebugStringA("1"); - int commandOffset; - - // It's fix for bug: crashing in XP. See example in MSDN: "Creating Context Menu Handlers". - - #if !defined(UNDER_CE) && defined(_MSC_VER) - if (commandInfo->cbSize == sizeof(CMINVOKECOMMANDINFOEX) && - (commandInfo->fMask & CMIC_MASK_UNICODE) != 0) - { - LPCMINVOKECOMMANDINFOEX commandInfoEx = (LPCMINVOKECOMMANDINFOEX)commandInfo; - if (HIWORD(commandInfoEx->lpVerbW) == 0) - commandOffset = LOWORD(commandInfo->lpVerb); - else - commandOffset = FindVerb(commandInfoEx->lpVerbW); - } - else - #endif - if (HIWORD(commandInfo->lpVerb) == 0) - commandOffset = LOWORD(commandInfo->lpVerb); - else - commandOffset = FindVerb(GetUnicodeString(commandInfo->lpVerb)); - - if (commandOffset < 0 || (unsigned)commandOffset >= _commandMap.Size()) - return E_FAIL; - - const CCommandMapItem commandMapItem = _commandMap[commandOffset]; - ECommandInternalID cmdID = commandMapItem.CommandInternalID; - - try - { - switch (cmdID) - { - case kOpen: - { - UString params; - params = GetQuotedString(_fileNames[0]); - if (!commandMapItem.ArcType.IsEmpty()) - { - params += " -t"; - params += commandMapItem.ArcType; - } - MyCreateProcess(Get7zFmPath(), params); - break; - } - case kExtract: - case kExtractHere: - case kExtractTo: - { - ExtractArchives(_fileNames, commandMapItem.Folder, - (cmdID == kExtract), // showDialog - (cmdID == kExtractTo) && _elimDup.Val // elimDup - ); - break; - } - case kTest: - { - TestArchives(_fileNames); - break; - } - case kCompress: - case kCompressEmail: - case kCompressTo7z: - case kCompressTo7zEmail: - case kCompressToZip: - case kCompressToZipEmail: - { - bool email = - (cmdID == kCompressEmail) || - (cmdID == kCompressTo7zEmail) || - (cmdID == kCompressToZipEmail); - bool showDialog = - (cmdID == kCompress) || - (cmdID == kCompressEmail); - bool addExtension = (cmdID == kCompress || cmdID == kCompressEmail); - CompressFiles(commandMapItem.Folder, - commandMapItem.ArcName, commandMapItem.ArcType, - addExtension, - _fileNames, email, showDialog, false); - break; - } - - case kHash_CRC32: - case kHash_CRC64: - case kHash_XXH32: - case kHash_XXH64: - case kHash_MD2: - case kHash_MD4: - case kHash_MD5: - case kHash_SHA1: - case kHash_SHA256: - case kHash_SHA384: - case kHash_SHA512: - case kHash_BLAKE2sp: - case kHash_All: - { - for (unsigned i = 0; i < ARRAY_SIZE(g_HashCommands); i++) - { - const CHashCommand &hc = g_HashCommands[i]; - if (hc.CommandInternalID == cmdID) - { - CalcChecksum(_fileNames, (UString)hc.MethodName); - break; - } - } - break; - } - } - } - catch(...) - { - ::MessageBoxW(0, L"Error", L"7-Zip", MB_ICONERROR); - } - return S_OK; -} - -static void MyCopyString(void *dest, const wchar_t *src, bool writeInUnicode) -{ - if (writeInUnicode) - { - MyStringCopy((wchar_t *)dest, src); - } - else - MyStringCopy((char *)dest, (const char *)GetAnsiString(src)); -} - -STDMETHODIMP CZipContextMenu::GetCommandString(UINT_PTR commandOffset, UINT uType, - UINT * /* pwReserved */ , LPSTR pszName, UINT /* cchMax */) -{ - int cmdOffset = (int)commandOffset; - switch (uType) - { - #ifdef UNDER_CE - case GCS_VALIDATE: - #else - case GCS_VALIDATEA: - case GCS_VALIDATEW: - #endif - if (cmdOffset < 0 || (unsigned)cmdOffset >= _commandMap.Size()) - return S_FALSE; - else - return S_OK; - } - if (cmdOffset < 0 || (unsigned)cmdOffset >= _commandMap.Size()) - return E_FAIL; - #ifdef UNDER_CE - if (uType == GCS_HELPTEXT) - #else - if (uType == GCS_HELPTEXTA || uType == GCS_HELPTEXTW) - #endif - { - MyCopyString(pszName, _commandMap[cmdOffset].HelpString, - #ifdef UNDER_CE - true - #else - uType == GCS_HELPTEXTW - #endif - ); - return NO_ERROR; - } - #ifdef UNDER_CE - if (uType == GCS_VERB) - #else - if (uType == GCS_VERBA || uType == GCS_VERBW) - #endif - { - MyCopyString(pszName, _commandMap[cmdOffset].Verb, - #ifdef UNDER_CE - true - #else - uType == GCS_VERBW - #endif - ); - return NO_ERROR; - } - return E_FAIL; -} +// ContextMenu.cpp + +#include "StdAfx.h" + +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/COM.h" +#include "../../../Windows/DLL.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/MemoryGlobal.h" +#include "../../../Windows/Menu.h" +#include "../../../Windows/ProcessUtils.h" +#include "../../../Windows/Shell.h" + +#include "../Common/ArchiveName.h" +#include "../Common/CompressCall.h" +#include "../Common/ExtractingFilePath.h" +#include "../Common/ZipRegistry.h" + +#include "../FileManager/FormatUtils.h" + +#ifdef LANG +#include "../FileManager/LangUtils.h" +#endif + +#include "ContextMenu.h" +#include "ContextMenuFlags.h" +#include "MyMessages.h" + +#include "resource.h" + +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 + +CZipContextMenu::CZipContextMenu(): + _isMenuForFM(false), + _bitmap(NULL) +{ + InterlockedIncrement(&g_DllRefCount); + _bitmap = ::LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_MENU_LOGO)); +} + +CZipContextMenu::~CZipContextMenu() +{ + if (_bitmap != NULL) + DeleteObject(_bitmap); + InterlockedDecrement(&g_DllRefCount); +} + +HRESULT CZipContextMenu::GetFileNames(LPDATAOBJECT dataObject, UStringVector &fileNames) +{ + fileNames.Clear(); + if (dataObject == NULL) + return E_FAIL; + + #ifndef UNDER_CE + + FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; + NCOM::CStgMedium stgMedium; + HRESULT result = dataObject->GetData(&fmte, &stgMedium); + if (result != S_OK) + return result; + stgMedium._mustBeReleased = true; + + NShell::CDrop drop(false); + NMemory::CGlobalLock globalLock(stgMedium->hGlobal); + drop.Attach((HDROP)globalLock.GetPointer()); + drop.QueryFileNames(fileNames); + + #endif + + return S_OK; +} + +// IShellExtInit + +STDMETHODIMP CZipContextMenu::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT dataObject, HKEY /* hkeyProgID */) +{ + // OutputDebugString(TEXT("::Initialize\r\n")); + _dropMode = false; + _dropPath.Empty(); + if (pidlFolder != 0) + { + #ifndef UNDER_CE + if (NShell::GetPathFromIDList(pidlFolder, _dropPath)) + { + // OutputDebugString(path); + // OutputDebugString(TEXT("\r\n")); + NName::NormalizeDirPathPrefix(_dropPath); + _dropMode = !_dropPath.IsEmpty(); + } + else + #endif + _dropPath.Empty(); + } + + /* + m_IsFolder = false; + if (pidlFolder == 0) + */ + // pidlFolder is NULL :( + return GetFileNames(dataObject, _fileNames); +} + +HRESULT CZipContextMenu::InitContextMenu(const wchar_t * /* folder */, const wchar_t * const *names, unsigned numFiles) +{ + _isMenuForFM = true; + _fileNames.Clear(); + for (UInt32 i = 0; i < numFiles; i++) + { + // MessageBoxW(0, names[i], NULL, 0); + // OutputDebugStringW(names[i]); + _fileNames.Add(names[i]); + } + _dropMode = false; + return S_OK; +} + + +///////////////////////////// +// IContextMenu + +static LPCSTR const kMainVerb = "SevenZipZS"; +static LPCSTR const kOpenCascadedVerb = "SevenZipZS.OpenWithType."; +static LPCSTR const kCheckSumCascadedVerb = "SevenZipZS.Checksum"; + + +struct CContextMenuCommand +{ + UInt32 flag; + CZipContextMenu::ECommandInternalID CommandInternalID; + LPCSTR Verb; + UINT ResourceID; +}; + +static const CContextMenuCommand g_Commands[] = +{ + { + NContextMenuFlags::kOpen, + CZipContextMenu::kOpen, + "Open", + IDS_CONTEXT_OPEN + }, + { + NContextMenuFlags::kExtract, + CZipContextMenu::kExtract, + "Extract", + IDS_CONTEXT_EXTRACT + }, + { + NContextMenuFlags::kExtractHere, + CZipContextMenu::kExtractHere, + "ExtractHere", + IDS_CONTEXT_EXTRACT_HERE + }, + { + NContextMenuFlags::kExtractTo, + CZipContextMenu::kExtractTo, + "ExtractTo", + IDS_CONTEXT_EXTRACT_TO + }, + { + NContextMenuFlags::kTest, + CZipContextMenu::kTest, + "Test", + IDS_CONTEXT_TEST + }, + { + NContextMenuFlags::kCompress, + CZipContextMenu::kCompress, + "Compress", + IDS_CONTEXT_COMPRESS + }, + { + NContextMenuFlags::kCompressEmail, + CZipContextMenu::kCompressEmail, + "CompressEmail", + IDS_CONTEXT_COMPRESS_EMAIL + }, + { + NContextMenuFlags::kCompressTo7z, + CZipContextMenu::kCompressTo7z, + "CompressTo7z", + IDS_CONTEXT_COMPRESS_TO + }, + { + NContextMenuFlags::kCompressTo7zEmail, + CZipContextMenu::kCompressTo7zEmail, + "CompressTo7zEmail", + IDS_CONTEXT_COMPRESS_TO_EMAIL + }, + { + NContextMenuFlags::kCompressToZip, + CZipContextMenu::kCompressToZip, + "CompressToZip", + IDS_CONTEXT_COMPRESS_TO + }, + { + NContextMenuFlags::kCompressToZipEmail, + CZipContextMenu::kCompressToZipEmail, + "CompressToZipEmail", + IDS_CONTEXT_COMPRESS_TO_EMAIL + } +}; + +struct CHashCommand +{ + CZipContextMenu::ECommandInternalID CommandInternalID; + LPCSTR UserName; + LPCSTR MethodName; +}; + +static const CHashCommand g_HashCommands[] = +{ + { CZipContextMenu::kHash_CRC32, "CRC-32", "CRC32" }, + { CZipContextMenu::kHash_CRC64, "CRC-64", "CRC64" }, + { CZipContextMenu::kHash_XXH32, "XXH-32", "XXH32" }, + { CZipContextMenu::kHash_XXH64, "XXH-64", "XXH64" }, + { CZipContextMenu::kHash_MD2, "MD2", "MD2" }, + { CZipContextMenu::kHash_MD4, "MD4", "MD4" }, + { CZipContextMenu::kHash_MD5, "MD5", "MD5" }, + { CZipContextMenu::kHash_SHA1, "SHA-1", "SHA1" }, + { CZipContextMenu::kHash_SHA256, "SHA-256", "SHA256" }, + { CZipContextMenu::kHash_SHA384, "SHA-384", "SHA384" }, + { CZipContextMenu::kHash_SHA512, "SHA-512", "SHA512" }, + { CZipContextMenu::kHash_BLAKE2sp, "BLAKE2sp", "BLAKE2sp" }, + { CZipContextMenu::kHash_All, "*", "*" } +}; + +static int FindCommand(CZipContextMenu::ECommandInternalID &id) +{ + for (unsigned i = 0; i < ARRAY_SIZE(g_Commands); i++) + if (g_Commands[i].CommandInternalID == id) + return i; + return -1; +} + +bool CZipContextMenu::FillCommand(ECommandInternalID id, UString &mainString, CCommandMapItem &commandMapItem) +{ + mainString.Empty(); + int i = FindCommand(id); + if (i < 0) + return false; + const CContextMenuCommand &command = g_Commands[i]; + commandMapItem.CommandInternalID = command.CommandInternalID; + commandMapItem.Verb = kMainVerb; + commandMapItem.Verb += command.Verb; + // LangString(command.ResourceHelpID, command.LangID + 1, commandMapItem.HelpString); + LangString(command.ResourceID, mainString); + return true; +} + +static bool MyInsertMenu(CMenu &menu, int pos, UINT id, const UString &s, HBITMAP bitmap) +{ + 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 ??? + return menu.InsertItem(pos, true, mi); + + // SetMenuItemBitmaps also works + // ::SetMenuItemBitmaps(menu, pos, MF_BYPOSITION, bitmap, NULL); +} + +static const char * const kArcExts[] = +{ + "7z" + , "bz2" + , "gz" + , "lz" + , "liz" + , "lz4" + , "lz5" + , "rar" + , "zip" + , "zst" +}; + +static bool IsItArcExt(const UString &ext) +{ + for (unsigned i = 0; i < ARRAY_SIZE(kArcExts); i++) + if (ext.IsEqualTo_Ascii_NoCase(kArcExts[i])) + return true; + return false; +} + +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 kExtractExludeExtensions = + " 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" +}; + +static bool FindExt(const char *p, const FString &name) +{ + int dotPos = name.ReverseFind_Dot(); + if (dotPos < 0 || dotPos == (int)name.Len() - 1) + return false; + + AString s; + + for (unsigned pos = dotPos + 1;; pos++) + { + 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 bool DoNeedExtract(const FString &name) +{ + return !FindExt(kExtractExludeExtensions, name); +} + +// we must use diferent Verbs for Popup subMenu. +void CZipContextMenu::AddMapItem_ForSubMenu(const char *verb) +{ + CCommandMapItem commandMapItem; + commandMapItem.CommandInternalID = kCommandNULL; + commandMapItem.Verb = verb; + _commandMap.Add(commandMapItem); +} + + +STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, + UINT commandIDFirst, UINT commandIDLast, UINT flags) +{ + // OutputDebugStringA("QueryContextMenu"); + + /* + for (UInt32 i = 0; i < _fileNames.Size(); i++) + { + OutputDebugStringW(_fileNames[i]); + } + */ + + LoadLangOneTime(); + if (_fileNames.Size() == 0) + return E_FAIL; + UINT currentCommandID = commandIDFirst; + if ((flags & 0x000F) != CMF_NORMAL && + (flags & CMF_VERBSONLY) == 0 && + (flags & CMF_EXPLORE) == 0) + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, currentCommandID); + + _commandMap.Clear(); + + CMenu popupMenu; + CMenuDestroyer menuDestroyer; + + CContextMenuInfo ci; + ci.Load(); + + _elimDup = ci.ElimDup; + + HBITMAP bitmap = NULL; + if (ci.MenuIcons.Val) + bitmap = _bitmap; + + UINT subIndex = indexMenu; + + if (ci.Cascaded.Val) + { + if (!popupMenu.CreatePopup()) + return E_FAIL; + 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; + popupMenu.InsertItem(subIndex++, true, mi); + } + + 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)); // change it 4 - must be constant + folderPrefix = + #ifdef UNDER_CE + "\\"; + #else + "C:\\"; + #endif + } + else + #endif + { + if (!fi0.Find(us2fs(fileName))) + return E_FAIL; + GetOnlyDirPrefix(us2fs(fileName), folderPrefix); + } + } + + UString mainString; + + if (_fileNames.Size() == 1 && currentCommandID + 14 <= commandIDLast) + { + if (!fi0.IsDir() && DoNeedExtract(fi0.Name)) + { + // Open + bool thereIsMainOpenItem = ((contextMenuFlags & NContextMenuFlags::kOpen) != 0); + if (thereIsMainOpenItem) + { + CCommandMapItem commandMapItem; + FillCommand(kOpen, mainString, commandMapItem); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); + _commandMap.Add(commandMapItem); + } + if ((contextMenuFlags & NContextMenuFlags::kOpenAs) != 0 + // && (!thereIsMainOpenItem || !FindExt(kNoOpenAsExtensions, fi0.Name)) + ) + { + CMenu subMenu; + if (subMenu.CreatePopup()) + { + CMenuItem mi; + mi.fType = MFT_STRING; + mi.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID; + if (bitmap) + mi.fMask |= MIIM_CHECKMARKS; + mi.wID = currentCommandID++; + mi.hSubMenu = subMenu; + mi.hbmpUnchecked = bitmap; + + LangString(IDS_CONTEXT_OPEN, mi.StringValue); + popupMenu.InsertItem(subIndex++, true, mi); + AddMapItem_ForSubMenu(kOpenCascadedVerb); + + UINT subIndex2 = 0; + for (unsigned i = (thereIsMainOpenItem ? 1 : 0); i < ARRAY_SIZE(kOpenTypes); i++) + { + CCommandMapItem commandMapItem; + if (i == 0) + FillCommand(kOpen, mainString, commandMapItem); + else + { + mainString = kOpenTypes[i]; + commandMapItem.CommandInternalID = kOpen; + commandMapItem.Verb = kMainVerb; + commandMapItem.Verb += ".Open."; + commandMapItem.Verb += mainString; + commandMapItem.HelpString = mainString; + commandMapItem.ArcType = mainString; + } + MyInsertMenu(subMenu, subIndex2++, currentCommandID++, mainString, bitmap); + _commandMap.Add(commandMapItem); + } + + subMenu.Detach(); + } + } + } + } + + if (_fileNames.Size() > 0 && currentCommandID + 10 <= commandIDLast) + { + bool needExtract = (!fi0.IsDir() && DoNeedExtract(fi0.Name)); + + if (!needExtract) + { + for (unsigned i = 1; i < _fileNames.Size(); i++) + { + NFind::CFileInfo fi; + if (!fi.Find(us2fs(_fileNames[i]))) + return E_FAIL; + if (!fi.IsDir() && DoNeedExtract(fi.Name)) + { + needExtract = true; + break; + } + } + } + + // const UString &fileName = _fileNames.Front(); + + 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 commandMapItem; + FillCommand(kExtract, mainString, commandMapItem); + commandMapItem.Folder = baseFolder + specFolder; + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); + _commandMap.Add(commandMapItem); + } + + if ((contextMenuFlags & NContextMenuFlags::kExtractHere) != 0) + { + // Extract Here + CCommandMapItem commandMapItem; + FillCommand(kExtractHere, mainString, commandMapItem); + commandMapItem.Folder = baseFolder; + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); + _commandMap.Add(commandMapItem); + } + + if ((contextMenuFlags & NContextMenuFlags::kExtractTo) != 0) + { + // Extract To + CCommandMapItem commandMapItem; + UString s; + FillCommand(kExtractTo, s, commandMapItem); + commandMapItem.Folder = baseFolder + specFolder; + MyFormatNew_ReducedName(s, specFolder); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); + _commandMap.Add(commandMapItem); + } + } + + if ((contextMenuFlags & NContextMenuFlags::kTest) != 0) + { + // Test + CCommandMapItem commandMapItem; + FillCommand(kTest, mainString, commandMapItem); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); + _commandMap.Add(commandMapItem); + } + } + + const UString arcName = CreateArchiveName(_fileNames, _fileNames.Size() == 1 ? &fi0 : NULL); + + UString arcName7z = arcName; + arcName7z += ".7z"; + UString arcNameZip = arcName; + arcNameZip += ".zip"; + + // Compress + if ((contextMenuFlags & NContextMenuFlags::kCompress) != 0) + { + CCommandMapItem commandMapItem; + if (_dropMode) + commandMapItem.Folder = _dropPath; + else + commandMapItem.Folder = fs2us(folderPrefix); + commandMapItem.ArcName = arcName; + FillCommand(kCompress, mainString, commandMapItem); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); + _commandMap.Add(commandMapItem); + } + + #ifdef EMAIL_SUPPORT + // CompressEmail + if ((contextMenuFlags & NContextMenuFlags::kCompressEmail) != 0 && !_dropMode) + { + CCommandMapItem commandMapItem; + commandMapItem.ArcName = arcName; + FillCommand(kCompressEmail, mainString, commandMapItem); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); + _commandMap.Add(commandMapItem); + } + #endif + + // CompressTo7z + if (contextMenuFlags & NContextMenuFlags::kCompressTo7z && + !arcName7z.IsEqualTo_NoCase(fs2us(fi0.Name))) + { + CCommandMapItem commandMapItem; + UString s; + FillCommand(kCompressTo7z, s, commandMapItem); + if (_dropMode) + commandMapItem.Folder = _dropPath; + else + commandMapItem.Folder = fs2us(folderPrefix); + commandMapItem.ArcName = arcName7z; + commandMapItem.ArcType = "7z"; + MyFormatNew_ReducedName(s, arcName7z); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); + _commandMap.Add(commandMapItem); + } + + #ifdef EMAIL_SUPPORT + // CompressTo7zEmail + if ((contextMenuFlags & NContextMenuFlags::kCompressTo7zEmail) != 0 && !_dropMode) + { + CCommandMapItem commandMapItem; + UString s; + FillCommand(kCompressTo7zEmail, s, commandMapItem); + commandMapItem.ArcName = arcName7z; + commandMapItem.ArcType = "7z"; + MyFormatNew_ReducedName(s, arcName7z); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); + _commandMap.Add(commandMapItem); + } + #endif + + // CompressToZip + if (contextMenuFlags & NContextMenuFlags::kCompressToZip && + !arcNameZip.IsEqualTo_NoCase(fs2us(fi0.Name))) + { + CCommandMapItem commandMapItem; + UString s; + FillCommand(kCompressToZip, s, commandMapItem); + if (_dropMode) + commandMapItem.Folder = _dropPath; + else + commandMapItem.Folder = fs2us(folderPrefix); + commandMapItem.ArcName = arcNameZip; + commandMapItem.ArcType = "zip"; + MyFormatNew_ReducedName(s, arcNameZip); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); + _commandMap.Add(commandMapItem); + } + + #ifdef EMAIL_SUPPORT + // CompressToZipEmail + if ((contextMenuFlags & NContextMenuFlags::kCompressToZipEmail) != 0 && !_dropMode) + { + CCommandMapItem commandMapItem; + UString s; + FillCommand(kCompressToZipEmail, s, commandMapItem); + commandMapItem.ArcName = arcNameZip; + commandMapItem.ArcType = "zip"; + MyFormatNew_ReducedName(s, arcNameZip); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); + _commandMap.Add(commandMapItem); + } + #endif + } + + + // 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) + { + CMenuItem mi; + mi.fType = MFT_STRING; + mi.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID; + if (bitmap) + mi.fMask |= MIIM_CHECKMARKS; + mi.wID = currentCommandID++; + mi.hSubMenu = popupMenu.Detach(); + mi.StringValue = "7-Zip ZS"; // LangString(IDS_CONTEXT_POPUP_CAPTION); + mi.hbmpUnchecked = bitmap; + + CMenu menu; + menu.Attach(hMenu); + menuDestroyer.Disable(); + menu.InsertItem(indexMenu++, true, mi); + + AddMapItem_ForSubMenu(kMainVerb); + } + else + { + popupMenu.Detach(); + indexMenu = subIndex; + } + + + if (!_isMenuForFM && + ((contextMenuFlags & NContextMenuFlags::kCRC) != 0 + && currentCommandID + 6 <= commandIDLast)) + { + CMenu subMenu; + // CMenuDestroyer menuDestroyer_CRC; + + UINT subIndex_CRC = 0; + + if (subMenu.CreatePopup()) + { + // menuDestroyer_CRC.Attach(subMenu); + CMenuItem mi; + mi.fType = MFT_STRING; + mi.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID; + if (bitmap) + mi.fMask |= MIIM_CHECKMARKS; + mi.wID = currentCommandID++; + mi.hSubMenu = subMenu; + mi.StringValue = "7-Zip ZS Hash"; + mi.hbmpUnchecked = bitmap; + + CMenu menu; + menu.Attach(hMenu); + // menuDestroyer_CRC.Disable(); + menu.InsertItem(indexMenu++, true, mi); + + AddMapItem_ForSubMenu(kCheckSumCascadedVerb); + + for (unsigned i = 0; i < ARRAY_SIZE(g_HashCommands); i++) + { + const CHashCommand &hc = g_HashCommands[i]; + CCommandMapItem commandMapItem; + commandMapItem.CommandInternalID = hc.CommandInternalID; + commandMapItem.Verb = kCheckSumCascadedVerb; + commandMapItem.Verb += hc.MethodName; + // commandMapItem.HelpString = hc.Name; + MyInsertMenu(subMenu, subIndex_CRC++, currentCommandID++, (UString)hc.UserName, bitmap); + _commandMap.Add(commandMapItem); + } + + subMenu.Detach(); + } + } + + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, currentCommandID - commandIDFirst); +} + + +int CZipContextMenu::FindVerb(const UString &verb) +{ + FOR_VECTOR (i, _commandMap) + if (_commandMap[i].Verb == verb) + return i; + return -1; +} + +static UString Get7zFmPath() +{ + return fs2us(NWindows::NDLL::GetModuleDirPrefix()) + L"7zFM.exe"; +} + +STDMETHODIMP CZipContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO commandInfo) +{ + // ::OutputDebugStringA("1"); + int commandOffset; + + // It's fix for bug: crashing in XP. See example in MSDN: "Creating Context Menu Handlers". + + #if !defined(UNDER_CE) && defined(_MSC_VER) + if (commandInfo->cbSize == sizeof(CMINVOKECOMMANDINFOEX) && + (commandInfo->fMask & CMIC_MASK_UNICODE) != 0) + { + LPCMINVOKECOMMANDINFOEX commandInfoEx = (LPCMINVOKECOMMANDINFOEX)commandInfo; + if (HIWORD(commandInfoEx->lpVerbW) == 0) + commandOffset = LOWORD(commandInfo->lpVerb); + else + commandOffset = FindVerb(commandInfoEx->lpVerbW); + } + else + #endif + if (HIWORD(commandInfo->lpVerb) == 0) + commandOffset = LOWORD(commandInfo->lpVerb); + else + commandOffset = FindVerb(GetUnicodeString(commandInfo->lpVerb)); + + if (commandOffset < 0 || (unsigned)commandOffset >= _commandMap.Size()) + return E_FAIL; + + const CCommandMapItem commandMapItem = _commandMap[commandOffset]; + ECommandInternalID cmdID = commandMapItem.CommandInternalID; + + try + { + switch (cmdID) + { + case kOpen: + { + UString params; + params = GetQuotedString(_fileNames[0]); + if (!commandMapItem.ArcType.IsEmpty()) + { + params += " -t"; + params += commandMapItem.ArcType; + } + MyCreateProcess(Get7zFmPath(), params); + break; + } + case kExtract: + case kExtractHere: + case kExtractTo: + { + ExtractArchives(_fileNames, commandMapItem.Folder, + (cmdID == kExtract), // showDialog + (cmdID == kExtractTo) && _elimDup.Val // elimDup + ); + break; + } + case kTest: + { + TestArchives(_fileNames); + break; + } + case kCompress: + case kCompressEmail: + case kCompressTo7z: + case kCompressTo7zEmail: + case kCompressToZip: + case kCompressToZipEmail: + { + bool email = + (cmdID == kCompressEmail) || + (cmdID == kCompressTo7zEmail) || + (cmdID == kCompressToZipEmail); + bool showDialog = + (cmdID == kCompress) || + (cmdID == kCompressEmail); + bool addExtension = (cmdID == kCompress || cmdID == kCompressEmail); + CompressFiles(commandMapItem.Folder, + commandMapItem.ArcName, commandMapItem.ArcType, + addExtension, + _fileNames, email, showDialog, false); + break; + } + + case kHash_CRC32: + case kHash_CRC64: + case kHash_XXH32: + case kHash_XXH64: + case kHash_MD2: + case kHash_MD4: + case kHash_MD5: + case kHash_SHA1: + case kHash_SHA256: + case kHash_SHA384: + case kHash_SHA512: + case kHash_BLAKE2sp: + case kHash_All: + { + for (unsigned i = 0; i < ARRAY_SIZE(g_HashCommands); i++) + { + const CHashCommand &hc = g_HashCommands[i]; + if (hc.CommandInternalID == cmdID) + { + CalcChecksum(_fileNames, (UString)hc.MethodName); + break; + } + } + break; + } + } + } + catch(...) + { + ::MessageBoxW(0, L"Error", L"7-Zip", MB_ICONERROR); + } + return S_OK; +} + +static void MyCopyString(void *dest, const wchar_t *src, bool writeInUnicode) +{ + if (writeInUnicode) + { + MyStringCopy((wchar_t *)dest, src); + } + else + MyStringCopy((char *)dest, (const char *)GetAnsiString(src)); +} + +STDMETHODIMP CZipContextMenu::GetCommandString(UINT_PTR commandOffset, UINT uType, + UINT * /* pwReserved */ , LPSTR pszName, UINT /* cchMax */) +{ + int cmdOffset = (int)commandOffset; + switch (uType) + { + #ifdef UNDER_CE + case GCS_VALIDATE: + #else + case GCS_VALIDATEA: + case GCS_VALIDATEW: + #endif + if (cmdOffset < 0 || (unsigned)cmdOffset >= _commandMap.Size()) + return S_FALSE; + else + return S_OK; + } + if (cmdOffset < 0 || (unsigned)cmdOffset >= _commandMap.Size()) + return E_FAIL; + #ifdef UNDER_CE + if (uType == GCS_HELPTEXT) + #else + if (uType == GCS_HELPTEXTA || uType == GCS_HELPTEXTW) + #endif + { + MyCopyString(pszName, _commandMap[cmdOffset].HelpString, + #ifdef UNDER_CE + true + #else + uType == GCS_HELPTEXTW + #endif + ); + return NO_ERROR; + } + #ifdef UNDER_CE + if (uType == GCS_VERB) + #else + if (uType == GCS_VERBA || uType == GCS_VERBW) + #endif + { + MyCopyString(pszName, _commandMap[cmdOffset].Verb, + #ifdef UNDER_CE + true + #else + uType == GCS_VERBW + #endif + ); + return NO_ERROR; + } + return E_FAIL; +} diff --git a/CPP/7zip/UI/Explorer/ContextMenu.h b/CPP/7zip/UI/Explorer/ContextMenu.h index ec0489d5f..a9936964b 100644 --- a/CPP/7zip/UI/Explorer/ContextMenu.h +++ b/CPP/7zip/UI/Explorer/ContextMenu.h @@ -1,93 +1,93 @@ -// ContextMenu.h - -#ifndef __CONTEXT_MENU_H -#define __CONTEXT_MENU_H - -#include "../../../Common/MyWindows.h" - -#include - -#include "../../../Common/MyString.h" - -#include "../FileManager/MyCom2.h" - -class CZipContextMenu: - public IContextMenu, - public IShellExtInit, - public CMyUnknownImp -{ -public: - - enum ECommandInternalID - { - kCommandNULL, - kOpen, - kExtract, - kExtractHere, - kExtractTo, - kTest, - kCompress, - kCompressEmail, - kCompressTo7z, - kCompressTo7zEmail, - kCompressToZip, - kCompressToZipEmail, - kHash_CRC32, - kHash_CRC64, - kHash_XXH32, - kHash_XXH64, - kHash_MD2, - kHash_MD4, - kHash_MD5, - kHash_SHA1, - kHash_SHA256, - kHash_SHA384, - kHash_SHA512, - kHash_BLAKE2sp, - kHash_All - }; - - MY_UNKNOWN_IMP2_MT(IContextMenu, IShellExtInit) - - // IShellExtInit - STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder, LPDATAOBJECT dataObject, HKEY hkeyProgID); - - // IContextMenu - STDMETHOD(QueryContextMenu)(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); - STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO lpici); - STDMETHOD(GetCommandString)(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax); - - HRESULT InitContextMenu(const wchar_t *folder, const wchar_t * const *names, unsigned numFiles); - - CZipContextMenu(); - ~CZipContextMenu(); - -private: - - struct CCommandMapItem - { - ECommandInternalID CommandInternalID; - UString Verb; - UString HelpString; - UString Folder; - UString ArcName; - UString ArcType; - }; - - bool _isMenuForFM; - UStringVector _fileNames; - bool _dropMode; - UString _dropPath; - CObjectVector _commandMap; - - HBITMAP _bitmap; - - CBoolPair _elimDup; - - HRESULT GetFileNames(LPDATAOBJECT dataObject, UStringVector &fileNames); - int FindVerb(const UString &verb); - bool FillCommand(ECommandInternalID id, UString &mainString, CCommandMapItem &commandMapItem); - void AddMapItem_ForSubMenu(const char *ver); -}; - -#endif +// ContextMenu.h + +#ifndef __CONTEXT_MENU_H +#define __CONTEXT_MENU_H + +#include "../../../Common/MyWindows.h" + +#include + +#include "../../../Common/MyString.h" + +#include "../FileManager/MyCom2.h" + +class CZipContextMenu: + public IContextMenu, + public IShellExtInit, + public CMyUnknownImp +{ +public: + + enum ECommandInternalID + { + kCommandNULL, + kOpen, + kExtract, + kExtractHere, + kExtractTo, + kTest, + kCompress, + kCompressEmail, + kCompressTo7z, + kCompressTo7zEmail, + kCompressToZip, + kCompressToZipEmail, + kHash_CRC32, + kHash_CRC64, + kHash_XXH32, + kHash_XXH64, + kHash_MD2, + kHash_MD4, + kHash_MD5, + kHash_SHA1, + kHash_SHA256, + kHash_SHA384, + kHash_SHA512, + kHash_BLAKE2sp, + kHash_All + }; + + MY_UNKNOWN_IMP2_MT(IContextMenu, IShellExtInit) + + // IShellExtInit + STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder, LPDATAOBJECT dataObject, HKEY hkeyProgID); + + // IContextMenu + STDMETHOD(QueryContextMenu)(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); + STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO lpici); + STDMETHOD(GetCommandString)(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax); + + HRESULT InitContextMenu(const wchar_t *folder, const wchar_t * const *names, unsigned numFiles); + + CZipContextMenu(); + ~CZipContextMenu(); + +private: + + struct CCommandMapItem + { + ECommandInternalID CommandInternalID; + UString Verb; + UString HelpString; + UString Folder; + UString ArcName; + UString ArcType; + }; + + bool _isMenuForFM; + UStringVector _fileNames; + bool _dropMode; + UString _dropPath; + CObjectVector _commandMap; + + HBITMAP _bitmap; + + CBoolPair _elimDup; + + HRESULT GetFileNames(LPDATAOBJECT dataObject, UStringVector &fileNames); + int FindVerb(const UString &verb); + bool FillCommand(ECommandInternalID id, UString &mainString, CCommandMapItem &commandMapItem); + void AddMapItem_ForSubMenu(const char *ver); +}; + +#endif diff --git a/CPP/7zip/UI/Explorer/ContextMenuFlags.h b/CPP/7zip/UI/Explorer/ContextMenuFlags.h index aa6dee84c..f739cdc6c 100644 --- a/CPP/7zip/UI/Explorer/ContextMenuFlags.h +++ b/CPP/7zip/UI/Explorer/ContextMenuFlags.h @@ -1,26 +1,26 @@ -// ContextMenuFlags.h - -#ifndef __CONTEXT_MENU_FLAGS_H -#define __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 = (UInt32)1 << 31; -} - -#endif +// ContextMenuFlags.h + +#ifndef __CONTEXT_MENU_FLAGS_H +#define __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 = (UInt32)1 << 31; +} + +#endif diff --git a/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp b/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp index 9fc246597..34a581e73 100644 --- a/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp +++ b/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp @@ -1,216 +1,216 @@ -// DLLExports.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" - -#include - -#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 ZS 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-20BB-278A-1000-000100020000}"); - -DEFINE_GUID(CLSID_CZipContextMenu, - k_7zip_GUID_Data1, - k_7zip_GUID_Data2_ZS, - k_7zip_GUID_Data3_Common, - 0x10, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00); - -using namespace NWindows; - -HINSTANCE g_hInstance = 0; -HWND g_HWND = 0; - -LONG g_DllRefCount = 0; // Reference count of this DLL. - - -// #define ODS(sz) OutputDebugString(L#sz) - -class CShellExtClassFactory: - public IClassFactory, - public CMyUnknownImp -{ -public: - CShellExtClassFactory() { InterlockedIncrement(&g_DllRefCount); } - ~CShellExtClassFactory() { InterlockedDecrement(&g_DllRefCount); } - - MY_UNKNOWN_IMP1_MT(IClassFactory) - - STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, void**); - STDMETHODIMP LockServer(BOOL); -}; - -STDMETHODIMP CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, - REFIID riid, void **ppvObj) -{ - // ODS("CShellExtClassFactory::CreateInstance()\r\n"); - *ppvObj = NULL; - if (pUnkOuter) - return CLASS_E_NOAGGREGATION; - - CZipContextMenu *shellExt; - try - { - shellExt = new CZipContextMenu(); - } - catch(...) { return E_OUTOFMEMORY; } - if (!shellExt) - return E_OUTOFMEMORY; - - HRESULT res = shellExt->QueryInterface(riid, ppvObj); - if (res != S_OK) - delete shellExt; - return res; -} - - -STDMETHODIMP CShellExtClassFactory::LockServer(BOOL /* fLock */) -{ - return S_OK; // Check it -} - - -#define NT_CHECK_FAIL_ACTION return FALSE; - -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"); - 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; - HRESULT res = cf->QueryInterface(riid, ppv); - if (res != S_OK) - delete cf; - return res; - } - return CLASS_E_CLASSNOTAVAILABLE; - // return _Module.GetClassObject(rclsid, riid, ppv); -} - - -static BOOL RegisterServer() -{ - 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); - } - - 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; -} +// DLLExports.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" + +#include + +#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 ZS 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-20BB-278A-1000-000100020000}"); + +DEFINE_GUID(CLSID_CZipContextMenu, + k_7zip_GUID_Data1, + k_7zip_GUID_Data2_ZS, + k_7zip_GUID_Data3_Common, + 0x10, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00); + +using namespace NWindows; + +HINSTANCE g_hInstance = 0; +HWND g_HWND = 0; + +LONG g_DllRefCount = 0; // Reference count of this DLL. + + +// #define ODS(sz) OutputDebugString(L#sz) + +class CShellExtClassFactory: + public IClassFactory, + public CMyUnknownImp +{ +public: + CShellExtClassFactory() { InterlockedIncrement(&g_DllRefCount); } + ~CShellExtClassFactory() { InterlockedDecrement(&g_DllRefCount); } + + MY_UNKNOWN_IMP1_MT(IClassFactory) + + STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, void**); + STDMETHODIMP LockServer(BOOL); +}; + +STDMETHODIMP CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, + REFIID riid, void **ppvObj) +{ + // ODS("CShellExtClassFactory::CreateInstance()\r\n"); + *ppvObj = NULL; + if (pUnkOuter) + return CLASS_E_NOAGGREGATION; + + CZipContextMenu *shellExt; + try + { + shellExt = new CZipContextMenu(); + } + catch(...) { return E_OUTOFMEMORY; } + if (!shellExt) + return E_OUTOFMEMORY; + + HRESULT res = shellExt->QueryInterface(riid, ppvObj); + if (res != S_OK) + delete shellExt; + return res; +} + + +STDMETHODIMP CShellExtClassFactory::LockServer(BOOL /* fLock */) +{ + return S_OK; // Check it +} + + +#define NT_CHECK_FAIL_ACTION return FALSE; + +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"); + 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; + HRESULT res = cf->QueryInterface(riid, ppv); + if (res != S_OK) + delete cf; + return res; + } + return CLASS_E_CLASSNOTAVAILABLE; + // return _Module.GetClassObject(rclsid, riid, ppv); +} + + +static BOOL RegisterServer() +{ + 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); + } + + 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 index 5374c3739..034a269d7 100644 --- a/CPP/7zip/UI/Explorer/Explorer.def +++ b/CPP/7zip/UI/Explorer/Explorer.def @@ -1,9 +1,9 @@ -; 7-zip.def - -LIBRARY "7-zip" - -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +; 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 index 9ce94b76d..bd91e5466 100644 --- a/CPP/7zip/UI/Explorer/Explorer.dsp +++ b/CPP/7zip/UI/Explorer/Explorer.dsp @@ -1,559 +1,559 @@ -# 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 "LANG" /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:\Program Files\7-ZIP\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 "LANG" /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:\Program Files\7-ZIP\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 "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 "LANG" /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:\Program Files\7-ZIP\7-Zipn.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 "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 "LANG" /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:\Program Files\7-ZIP\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=.\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\ProgramLocation.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\ProgramLocation.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\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\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\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\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\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 -# End Target -# End Project +# 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 "LANG" /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:\Program Files\7-ZIP\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 "LANG" /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:\Program Files\7-ZIP\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 "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 "LANG" /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:\Program Files\7-ZIP\7-Zipn.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 "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 "LANG" /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:\Program Files\7-ZIP\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=.\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\ProgramLocation.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\ProgramLocation.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\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\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\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\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\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 +# End Target +# End Project diff --git a/CPP/7zip/UI/Explorer/Explorer.dsw b/CPP/7zip/UI/Explorer/Explorer.dsw index 38275b184..beb8df7bc 100644 --- a/CPP/7zip/UI/Explorer/Explorer.dsw +++ b/CPP/7zip/UI/Explorer/Explorer.dsw @@ -1,29 +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> -{{{ -}}} - -############################################################################### - +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/MyMessages.cpp b/CPP/7zip/UI/Explorer/MyMessages.cpp index 1024024b2..509237eec 100644 --- a/CPP/7zip/UI/Explorer/MyMessages.cpp +++ b/CPP/7zip/UI/Explorer/MyMessages.cpp @@ -1,37 +1,37 @@ -// 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-Zstandard", 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-Zstandard", 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()); +} diff --git a/CPP/7zip/UI/Explorer/MyMessages.h b/CPP/7zip/UI/Explorer/MyMessages.h index c175e8a17..d5822f45f 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 __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 diff --git a/CPP/7zip/UI/Explorer/RegistryContextMenu.cpp b/CPP/7zip/UI/Explorer/RegistryContextMenu.cpp index 763a437f1..b0cf0fb08 100644 --- a/CPP/7zip/UI/Explorer/RegistryContextMenu.cpp +++ b/CPP/7zip/UI/Explorer/RegistryContextMenu.cpp @@ -1,224 +1,224 @@ -// 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-20BB-278A-1000-000100020000}" - -static LPCTSTR const k_Clsid = TEXT(k_Clsid_A); -static LPCTSTR const k_ShellExtName = TEXT("7-Zip ZS 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-Zstandard"; -static LPCSTR const k_KeyPostfix_DragDrop = "\\shellex\\DragDropHandlers\\7-Zip-Zstandard"; - -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 = (Func_RegDeleteKeyExW) - GetProcAddress(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 < 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 +// 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-20BB-278A-1000-000100020000}" + +static LPCTSTR const k_Clsid = TEXT(k_Clsid_A); +static LPCTSTR const k_ShellExtName = TEXT("7-Zip ZS 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-Zstandard"; +static LPCSTR const k_KeyPostfix_DragDrop = "\\shellex\\DragDropHandlers\\7-Zip-Zstandard"; + +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 = (Func_RegDeleteKeyExW) + GetProcAddress(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 < 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 index 80e6d3b27..8c2acc421 100644 --- a/CPP/7zip/UI/Explorer/RegistryContextMenu.h +++ b/CPP/7zip/UI/Explorer/RegistryContextMenu.h @@ -1,13 +1,13 @@ -// RegistryContextMenu.h - -#ifndef __REGISTRY_CONTEXT_MENU_H -#define __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 +// RegistryContextMenu.h + +#ifndef __REGISTRY_CONTEXT_MENU_H +#define __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 index 2b852f23d..2550270cf 100644 --- a/CPP/7zip/UI/Explorer/StdAfx.cpp +++ b/CPP/7zip/UI/Explorer/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "stdafx.h" +// StdAfx.cpp + +#include "stdafx.h" diff --git a/CPP/7zip/UI/Explorer/StdAfx.h b/CPP/7zip/UI/Explorer/StdAfx.h index 35e8b337d..5e4dc640d 100644 --- a/CPP/7zip/UI/Explorer/StdAfx.h +++ b/CPP/7zip/UI/Explorer/StdAfx.h @@ -1,14 +1,14 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -// #define _WIN32_WINNT 0x0400 -#define _WIN32_WINNT 0x0500 -#define WINVER _WIN32_WINNT - -#include "../../../Common/Common.h" - -#include - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +// #define _WIN32_WINNT 0x0400 +#define _WIN32_WINNT 0x0500 +#define WINVER _WIN32_WINNT + +#include "../../../Common/Common.h" + +#include + +#endif diff --git a/CPP/7zip/UI/Explorer/makefile b/CPP/7zip/UI/Explorer/makefile index 667b244d1..c539853b4 100644 --- a/CPP/7zip/UI/Explorer/makefile +++ b/CPP/7zip/UI/Explorer/makefile @@ -1,75 +1,75 @@ -PROG = 7-zip.dll -DEF_FILE = Explorer.def -CFLAGS = $(CFLAGS) \ - -DLANG \ - -!IFDEF UNDER_CE -LIBS = $(LIBS) Commctrl.lib -!ELSE -LIBS = $(LIBS) htmlhelp.lib comdlg32.lib Mpr.lib Gdi32.lib -CFLAGS = $(CFLAGS) -DWIN_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\RegistryUtils.obj \ - $O\StringUtils.obj \ - -C_OBJS = \ - $O\CpuArch.obj \ - $O\Threads.obj \ - -!include "../../7zip.mak" +PROG = 7-zip.dll +DEF_FILE = Explorer.def +CFLAGS = $(CFLAGS) \ + -DLANG \ + +!IFDEF UNDER_CE +LIBS = $(LIBS) Commctrl.lib +!ELSE +LIBS = $(LIBS) htmlhelp.lib comdlg32.lib Mpr.lib Gdi32.lib +CFLAGS = $(CFLAGS) -DWIN_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\RegistryUtils.obj \ + $O\StringUtils.obj \ + +C_OBJS = \ + $O\CpuArch.obj \ + $O\Threads.obj \ + +!include "../../7zip.mak" diff --git a/CPP/7zip/UI/Explorer/resource.h b/CPP/7zip/UI/Explorer/resource.h index c4dd4eb39..8bb821087 100644 --- a/CPP/7zip/UI/Explorer/resource.h +++ b/CPP/7zip/UI/Explorer/resource.h @@ -1,13 +1,13 @@ -#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 IDB_MENU_LOGO 190 +#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 IDB_MENU_LOGO 190 diff --git a/CPP/7zip/UI/Explorer/resource.rc b/CPP/7zip/UI/Explorer/resource.rc index 684eb6efb..80018b45b 100644 --- a/CPP/7zip/UI/Explorer/resource.rc +++ b/CPP/7zip/UI/Explorer/resource.rc @@ -1,8 +1,8 @@ -#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 +#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 diff --git a/CPP/7zip/UI/Explorer/resource2.rc b/CPP/7zip/UI/Explorer/resource2.rc index 3453658c0..c07148fd8 100644 --- a/CPP/7zip/UI/Explorer/resource2.rc +++ b/CPP/7zip/UI/Explorer/resource2.rc @@ -1,18 +1,18 @@ -#include "resource.h" - -STRINGTABLE -BEGIN - IDS_CONTEXT_FOLDER "" - IDS_CONTEXT_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" -END - -IDB_MENU_LOGO BITMAP "../../UI/Explorer/MenuLogo.bmp" +#include "resource.h" + +STRINGTABLE +BEGIN + IDS_CONTEXT_FOLDER "" + IDS_CONTEXT_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" +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 index 20da02574..3567c0481 100644 --- a/CPP/7zip/UI/Far/ExtractEngine.cpp +++ b/CPP/7zip/UI/Far/ExtractEngine.cpp @@ -1,275 +1,275 @@ -// ExtractEngine.h - -#include "StdAfx.h" - -#ifndef _7ZIP_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 _7ZIP_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); - -CExtractCallbackImp::~CExtractCallbackImp() -{ -} - -void CExtractCallbackImp::Init( - UINT codePage, - CProgressBox *progressBox, - bool passwordIsDefined, - const UString &password) -{ - m_PasswordIsDefined = passwordIsDefined; - m_Password = password; - m_CodePage = codePage; - _percent = progressBox; -} - -STDMETHODIMP CExtractCallbackImp::SetTotal(UInt64 size) -{ - MT_LOCK - - if (_percent) - { - _percent->Total = size; - _percent->Print(); - } - return CheckBreak2(); -} - -STDMETHODIMP CExtractCallbackImp::SetCompleted(const UInt64 *completeValue) -{ - MT_LOCK - - if (_percent) - { - if (completeValue) - _percent->Completed = *completeValue; - _percent->Print(); - } - return CheckBreak2(); -} - -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) -{ - MT_LOCK - - NOverwriteDialog::CFileInfo oldFileInfo, newFileInfo; - oldFileInfo.TimeIsDefined = (existTime != 0); - if (oldFileInfo.TimeIsDefined) - oldFileInfo.Time = *existTime; - oldFileInfo.SizeIsDefined = (existSize != NULL); - if (oldFileInfo.SizeIsDefined) - oldFileInfo.Size = *existSize; - oldFileInfo.Name = existName; - - newFileInfo.TimeIsDefined = (newTime != 0); - 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 (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"; - -STDMETHODIMP 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; - default: s = "???"; // return E_FAIL; - }; - - if (_percent) - { - _percent->Command = s; - _percent->FileName = name; - _percent->Print(); - } - - return CheckBreak2(); -} - -STDMETHODIMP 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) -{ - 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(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(opRes); - } - } - } -} - -STDMETHODIMP 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(); -} - - -STDMETHODIMP 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); - -STDMETHODIMP CExtractCallbackImp::CryptoGetTextPassword(BSTR *password) -{ - MT_LOCK - - if (!m_PasswordIsDefined) - { - RINOK(GetPassword(m_Password)); - m_PasswordIsDefined = true; - } - return StringToBstr(m_Password, password); -} +// ExtractEngine.h + +#include "StdAfx.h" + +#ifndef _7ZIP_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 _7ZIP_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); + +CExtractCallbackImp::~CExtractCallbackImp() +{ +} + +void CExtractCallbackImp::Init( + UINT codePage, + CProgressBox *progressBox, + bool passwordIsDefined, + const UString &password) +{ + m_PasswordIsDefined = passwordIsDefined; + m_Password = password; + m_CodePage = codePage; + _percent = progressBox; +} + +STDMETHODIMP CExtractCallbackImp::SetTotal(UInt64 size) +{ + MT_LOCK + + if (_percent) + { + _percent->Total = size; + _percent->Print(); + } + return CheckBreak2(); +} + +STDMETHODIMP CExtractCallbackImp::SetCompleted(const UInt64 *completeValue) +{ + MT_LOCK + + if (_percent) + { + if (completeValue) + _percent->Completed = *completeValue; + _percent->Print(); + } + return CheckBreak2(); +} + +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) +{ + MT_LOCK + + NOverwriteDialog::CFileInfo oldFileInfo, newFileInfo; + oldFileInfo.TimeIsDefined = (existTime != 0); + if (oldFileInfo.TimeIsDefined) + oldFileInfo.Time = *existTime; + oldFileInfo.SizeIsDefined = (existSize != NULL); + if (oldFileInfo.SizeIsDefined) + oldFileInfo.Size = *existSize; + oldFileInfo.Name = existName; + + newFileInfo.TimeIsDefined = (newTime != 0); + 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 (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"; + +STDMETHODIMP 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; + default: s = "???"; // return E_FAIL; + }; + + if (_percent) + { + _percent->Command = s; + _percent->FileName = name; + _percent->Print(); + } + + return CheckBreak2(); +} + +STDMETHODIMP 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) +{ + 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(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(opRes); + } + } + } +} + +STDMETHODIMP 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(); +} + + +STDMETHODIMP 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); + +STDMETHODIMP 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 index 0b928225c..5861d92c9 100644 --- a/CPP/7zip/UI/Far/ExtractEngine.h +++ b/CPP/7zip/UI/Far/ExtractEngine.h @@ -1,57 +1,57 @@ -// ExtractEngine.h - -#ifndef __EXTRACT_ENGINE_H -#define __EXTRACT_ENGINE_H - -#include "../../../Common/MyCom.h" -#include "../../../Common/MyString.h" - -#include "../../IPassword.h" -#include "../Agent/IFolderArchive.h" - -#include "ProgressBox.h" - -class CExtractCallbackImp: - public IFolderArchiveExtractCallback, - public IFolderArchiveExtractCallback2, - public ICryptoGetTextPassword, - public CMyUnknownImp -{ -public: - MY_UNKNOWN_IMP2(ICryptoGetTextPassword, IFolderArchiveExtractCallback2) - - // IProgress - STDMETHOD(SetTotal)(UInt64 size); - STDMETHOD(SetCompleted)(const UInt64 *completeValue); - - INTERFACE_IFolderArchiveExtractCallback(;) - INTERFACE_IFolderArchiveExtractCallback2(;) - - // ICryptoGetTextPassword - STDMETHOD(CryptoGetTextPassword)(BSTR *password); - -private: - 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: - // CExtractCallbackImp() {} - ~CExtractCallbackImp(); - void Init(UINT codePage, - CProgressBox *progressBox, - bool passwordIsDefined, const UString &password); -}; - -#endif +// ExtractEngine.h + +#ifndef __EXTRACT_ENGINE_H +#define __EXTRACT_ENGINE_H + +#include "../../../Common/MyCom.h" +#include "../../../Common/MyString.h" + +#include "../../IPassword.h" +#include "../Agent/IFolderArchive.h" + +#include "ProgressBox.h" + +class CExtractCallbackImp: + public IFolderArchiveExtractCallback, + public IFolderArchiveExtractCallback2, + public ICryptoGetTextPassword, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP2(ICryptoGetTextPassword, IFolderArchiveExtractCallback2) + + // IProgress + STDMETHOD(SetTotal)(UInt64 size); + STDMETHOD(SetCompleted)(const UInt64 *completeValue); + + INTERFACE_IFolderArchiveExtractCallback(;) + INTERFACE_IFolderArchiveExtractCallback2(;) + + // ICryptoGetTextPassword + STDMETHOD(CryptoGetTextPassword)(BSTR *password); + +private: + 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: + // CExtractCallbackImp() {} + ~CExtractCallbackImp(); + 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 index f4959cd40..5d92bc406 100644 --- a/CPP/7zip/UI/Far/Far.cpp +++ b/CPP/7zip/UI/Far/Far.cpp @@ -1,634 +1,634 @@ -// 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; - -HINSTANCE g_hInstance; - -namespace NFar { - -const char *g_PluginName_for_Error = "7-Zip"; - -} - -#define NT_CHECK_FAIL_ACTION return FALSE; - -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"); -} - -class COpenArchiveCallback: - public IArchiveOpenCallback, - public IArchiveOpenVolumeCallback, - public IArchiveOpenSetSubArchiveName, - public IProgress, - public ICryptoGetTextPassword, - public CMyUnknownImp -{ - DWORD m_StartTickValue; - bool m_MessageBoxIsShown; - - CProgressBox _progressBox; - - bool _numFilesTotalDefined; - bool _numBytesTotalDefined; - - NFind::CFileInfo _fileInfo; - bool _subArchiveMode; - UString _subArchiveName; -public: - bool PasswordIsDefined; - UString Password; - - FString _folderPrefix; - -public: - MY_UNKNOWN_IMP4( - IArchiveOpenVolumeCallback, - IArchiveOpenSetSubArchiveName, - IProgress, - ICryptoGetTextPassword - ) - - // IProgress - STDMETHOD(SetTotal)(UInt64 total); - STDMETHOD(SetCompleted)(const UInt64 *aCompleteValue); - - // IArchiveOpenCallback - STDMETHOD(SetTotal)(const UInt64 *numFiles, const UInt64 *numBytes); - STDMETHOD(SetCompleted)(const UInt64 *numFiles, const UInt64 *numBytes); - - // IArchiveOpenVolumeCallback - STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value); - STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream); - - STDMETHOD(SetSubArchiveName(const wchar_t *name)) - { - _subArchiveMode = true; - _subArchiveName = name; - return S_OK; - } - - // ICryptoGetTextPassword - STDMETHOD(CryptoGetTextPassword)(BSTR *password); - - COpenArchiveCallback(): _subArchiveMode(false) {} - - void Init() - { - PasswordIsDefined = false; - - _subArchiveMode = false; - - _numFilesTotalDefined = false; - _numBytesTotalDefined = false; - - m_MessageBoxIsShown = false; - - _progressBox.Init( - // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), - g_StartupInfo.GetMsgString(NMessageID::kReading)); - } - void ShowMessage(); - - void LoadFileInfo(const FString &folderPrefix, const FString &fileName) - { - _folderPrefix = folderPrefix; - if (!_fileInfo.Find(_folderPrefix + fileName)) - throw 1; - } -}; - -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(); -} - -STDMETHODIMP 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(); -} - -STDMETHODIMP COpenArchiveCallback::SetCompleted(const UInt64 *numFiles, const UInt64 *numBytes) -{ - if (numFiles) - _progressBox.Files = *numFiles; - - if (numBytes) - _progressBox.Completed = *numBytes; - - ShowMessage(); - return CheckBreak2(); -} - - -STDMETHODIMP COpenArchiveCallback::SetTotal(const UInt64 /* total */) -{ - return CheckBreak2(); -} - -STDMETHODIMP COpenArchiveCallback::SetCompleted(const UInt64 * /* completed */) -{ - ShowMessage(); - return CheckBreak2(); -} - -STDMETHODIMP COpenArchiveCallback::GetStream(const wchar_t *name, IInStream **inStream) -{ - if (WasEscPressed()) - return E_ABORT; - if (_subArchiveMode) - return S_FALSE; - *inStream = NULL; - FString fullPath = _folderPrefix + us2fs(name); - if (!_fileInfo.Find(fullPath)) - return S_FALSE; - if (_fileInfo.IsDir()) - return S_FALSE; - CInFileStream *inFile = new CInFileStream; - CMyComPtr inStreamTemp = inFile; - if (!inFile->Open(fullPath)) - return ::GetLastError(); - *inStream = inStreamTemp.Detach(); - return S_OK; -} - - -STDMETHODIMP COpenArchiveCallback::GetProperty(PROPID propID, PROPVARIANT *value) -{ - NCOM::CPropVariant prop; - if (_subArchiveMode) - { - switch (propID) - { - case kpidName: prop = _subArchiveName; break; - } - } - else - switch (propID) - { - case kpidName: prop = GetUnicodeString(_fileInfo.Name, CP_OEMCP); 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; -} - -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 = 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; -} - -STDMETHODIMP 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 archiveHandler; - - // CArchiverInfo archiverInfoResult; - // ::OutputDebugStringA("before OpenArchive\n"); - - CScreenRestorer screenRestorer; - { - screenRestorer.Save(); - } - - COpenArchiveCallback *openArchiveCallbackSpec = new COpenArchiveCallback; - CMyComPtr openArchiveCallback = openArchiveCallbackSpec; - - // if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) - openArchiveCallbackSpec->Init(); - { - FString dirPrefix, fileName; - GetFullPathAndSplit(fullName, dirPrefix, fileName); - openArchiveCallbackSpec->LoadFileInfo(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, openArchiveCallback); - /* - 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; - 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, 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 const char *pluginMenuStrings[2]; - pluginMenuStrings[0] = g_StartupInfo.GetMsgString(NMessageID::kOpenArchiveMenuString); - pluginMenuStrings[1] = g_StartupInfo.GetMsgString(NMessageID::kCreateArchiveMenuString); - info->PluginMenuStrings = (char **)pluginMenuStrings; - info->PluginMenuStringsNumber = 2; - static const char *pluginCfgStrings[1]; - pluginCfgStrings[0] = g_StartupInfo.GetMsgString(NMessageID::kOpenArchiveMenuString); - info->PluginConfigStrings = (char **)pluginCfgStrings; - info->PluginConfigStringsNumber = ARRAY_SIZE(pluginCfgStrings); - info->CommandPrefix = (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 = 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, 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, itemsNumber, opMode)); - MY_TRY_END2("DeleteFiles", FALSE); -} - -EXTERN_C int WINAPI ProcessKey(HANDLE plugin, int key, unsigned int controlState) -{ - MY_TRY_BEGIN; - return (((CPlugin *)plugin)->ProcessKey(key, controlState)); - MY_TRY_END2("ProcessKey", FALSE); -} +// 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; + +HINSTANCE g_hInstance; + +namespace NFar { + +const char *g_PluginName_for_Error = "7-Zip"; + +} + +#define NT_CHECK_FAIL_ACTION return FALSE; + +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"); +} + +class COpenArchiveCallback: + public IArchiveOpenCallback, + public IArchiveOpenVolumeCallback, + public IArchiveOpenSetSubArchiveName, + public IProgress, + public ICryptoGetTextPassword, + public CMyUnknownImp +{ + DWORD m_StartTickValue; + bool m_MessageBoxIsShown; + + CProgressBox _progressBox; + + bool _numFilesTotalDefined; + bool _numBytesTotalDefined; + + NFind::CFileInfo _fileInfo; + bool _subArchiveMode; + UString _subArchiveName; +public: + bool PasswordIsDefined; + UString Password; + + FString _folderPrefix; + +public: + MY_UNKNOWN_IMP4( + IArchiveOpenVolumeCallback, + IArchiveOpenSetSubArchiveName, + IProgress, + ICryptoGetTextPassword + ) + + // IProgress + STDMETHOD(SetTotal)(UInt64 total); + STDMETHOD(SetCompleted)(const UInt64 *aCompleteValue); + + // IArchiveOpenCallback + STDMETHOD(SetTotal)(const UInt64 *numFiles, const UInt64 *numBytes); + STDMETHOD(SetCompleted)(const UInt64 *numFiles, const UInt64 *numBytes); + + // IArchiveOpenVolumeCallback + STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value); + STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream); + + STDMETHOD(SetSubArchiveName(const wchar_t *name)) + { + _subArchiveMode = true; + _subArchiveName = name; + return S_OK; + } + + // ICryptoGetTextPassword + STDMETHOD(CryptoGetTextPassword)(BSTR *password); + + COpenArchiveCallback(): _subArchiveMode(false) {} + + void Init() + { + PasswordIsDefined = false; + + _subArchiveMode = false; + + _numFilesTotalDefined = false; + _numBytesTotalDefined = false; + + m_MessageBoxIsShown = false; + + _progressBox.Init( + // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), + g_StartupInfo.GetMsgString(NMessageID::kReading)); + } + void ShowMessage(); + + void LoadFileInfo(const FString &folderPrefix, const FString &fileName) + { + _folderPrefix = folderPrefix; + if (!_fileInfo.Find(_folderPrefix + fileName)) + throw 1; + } +}; + +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(); +} + +STDMETHODIMP 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(); +} + +STDMETHODIMP COpenArchiveCallback::SetCompleted(const UInt64 *numFiles, const UInt64 *numBytes) +{ + if (numFiles) + _progressBox.Files = *numFiles; + + if (numBytes) + _progressBox.Completed = *numBytes; + + ShowMessage(); + return CheckBreak2(); +} + + +STDMETHODIMP COpenArchiveCallback::SetTotal(const UInt64 /* total */) +{ + return CheckBreak2(); +} + +STDMETHODIMP COpenArchiveCallback::SetCompleted(const UInt64 * /* completed */) +{ + ShowMessage(); + return CheckBreak2(); +} + +STDMETHODIMP COpenArchiveCallback::GetStream(const wchar_t *name, IInStream **inStream) +{ + if (WasEscPressed()) + return E_ABORT; + if (_subArchiveMode) + return S_FALSE; + *inStream = NULL; + FString fullPath = _folderPrefix + us2fs(name); + if (!_fileInfo.Find(fullPath)) + return S_FALSE; + if (_fileInfo.IsDir()) + return S_FALSE; + CInFileStream *inFile = new CInFileStream; + CMyComPtr inStreamTemp = inFile; + if (!inFile->Open(fullPath)) + return ::GetLastError(); + *inStream = inStreamTemp.Detach(); + return S_OK; +} + + +STDMETHODIMP COpenArchiveCallback::GetProperty(PROPID propID, PROPVARIANT *value) +{ + NCOM::CPropVariant prop; + if (_subArchiveMode) + { + switch (propID) + { + case kpidName: prop = _subArchiveName; break; + } + } + else + switch (propID) + { + case kpidName: prop = GetUnicodeString(_fileInfo.Name, CP_OEMCP); 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; +} + +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 = 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; +} + +STDMETHODIMP 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 archiveHandler; + + // CArchiverInfo archiverInfoResult; + // ::OutputDebugStringA("before OpenArchive\n"); + + CScreenRestorer screenRestorer; + { + screenRestorer.Save(); + } + + COpenArchiveCallback *openArchiveCallbackSpec = new COpenArchiveCallback; + CMyComPtr openArchiveCallback = openArchiveCallbackSpec; + + // if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) + openArchiveCallbackSpec->Init(); + { + FString dirPrefix, fileName; + GetFullPathAndSplit(fullName, dirPrefix, fileName); + openArchiveCallbackSpec->LoadFileInfo(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, openArchiveCallback); + /* + 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; + 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, 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 const char *pluginMenuStrings[2]; + pluginMenuStrings[0] = g_StartupInfo.GetMsgString(NMessageID::kOpenArchiveMenuString); + pluginMenuStrings[1] = g_StartupInfo.GetMsgString(NMessageID::kCreateArchiveMenuString); + info->PluginMenuStrings = (char **)pluginMenuStrings; + info->PluginMenuStringsNumber = 2; + static const char *pluginCfgStrings[1]; + pluginCfgStrings[0] = g_StartupInfo.GetMsgString(NMessageID::kOpenArchiveMenuString); + info->PluginConfigStrings = (char **)pluginCfgStrings; + info->PluginConfigStringsNumber = ARRAY_SIZE(pluginCfgStrings); + info->CommandPrefix = (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 = 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, 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, itemsNumber, opMode)); + MY_TRY_END2("DeleteFiles", FALSE); +} + +EXTERN_C int WINAPI ProcessKey(HANDLE plugin, int key, unsigned int controlState) +{ + MY_TRY_BEGIN; + return (((CPlugin *)plugin)->ProcessKey(key, controlState)); + MY_TRY_END2("ProcessKey", FALSE); +} diff --git a/CPP/7zip/UI/Far/Far.def b/CPP/7zip/UI/Far/Far.def index 1b345d243..1de9acdf7 100644 --- a/CPP/7zip/UI/Far/Far.def +++ b/CPP/7zip/UI/Far/Far.def @@ -1,35 +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 +; 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 index ced05fe5a..2433b2520 100644 --- a/CPP/7zip/UI/Far/Far.dsp +++ b/CPP/7zip/UI/Far/Far.dsp @@ -1,759 +1,759 @@ -# 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 "EXTERNAL_CODECS" /D "NEW_FOLDER_INTERFACE" /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:\Program Files\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 "EXTERNAL_CODECS" /D "NEW_FOLDER_INTERFACE" /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:\Program Files\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\CRC.cpp -# 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\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\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\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\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\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 "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\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\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\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\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 +# 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 "EXTERNAL_CODECS" /D "NEW_FOLDER_INTERFACE" /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:\Program Files\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 "EXTERNAL_CODECS" /D "NEW_FOLDER_INTERFACE" /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:\Program Files\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\CRC.cpp +# 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\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\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\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\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\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 "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\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\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\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\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 index ed5200341..f4ef08019 100644 --- a/CPP/7zip/UI/Far/Far.dsw +++ b/CPP/7zip/UI/Far/Far.dsw @@ -1,29 +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> -{{{ -}}} - -############################################################################### - +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 index 73b4a878d..859d319fd 100644 --- a/CPP/7zip/UI/Far/FarPlugin.h +++ b/CPP/7zip/UI/Far/FarPlugin.h @@ -1,529 +1,529 @@ -// 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 __FAR_PLUGIN_H -#define __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 -*/ - -#endif +// 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 __FAR_PLUGIN_H +#define __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 +*/ + +#endif diff --git a/CPP/7zip/UI/Far/FarUtils.cpp b/CPP/7zip/UI/Far/FarUtils.cpp index 5f7d38dce..ddca3cab7 100644 --- a/CPP/7zip/UI/Far/FarUtils.cpp +++ b/CPP/7zip/UI/Far/FarUtils.cpp @@ -1,521 +1,521 @@ -// 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, int numItems, int numButtons) -{ - return m_Data.Message(m_Data.ModuleNumber, flags, helpTopic, - items, numItems, numButtons); -} - -namespace NMessageID -{ - enum - { - kOk, - kCancel, - kWarning, - kError - }; -} - -int CStartupInfo::ShowWarningWithOk(const char **items, int 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, 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, 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, int numItems) -{ - return m_Data.Dialog(m_Data.ModuleNumber, X1, Y1, X2, Y2, (char *)helpTopic, - items, numItems); -} - -int CStartupInfo::ShowDialog(int sizeX, int sizeY, - const char *helpTopic, struct FarDialogItem *items, int 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, int numItems) -{ - for (int 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 &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 &= ~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, - int numItems) -{ - return m_Data.Menu(m_Data.ModuleNumber, x, y, maxHeight, flags, (char *)title, - (char *)aBottom, (char *)helpTopic, breakKeys, breakCode, items, numItems); -} - -int CStartupInfo::Menu( - unsigned int flags, - const char *title, - const char *helpTopic, - struct FarMenuItem *items, - int 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 farMenuItems; - FOR_VECTOR (i, items) - { - FarMenuItem item; - item.Checked = 0; - item.Separator = 0; - item.Selected = ((int)i == selectedItem); - const AString reducedString (items[i].Left(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) -{ - 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 -} - -} +// 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, int numItems, int numButtons) +{ + return m_Data.Message(m_Data.ModuleNumber, flags, helpTopic, + items, numItems, numButtons); +} + +namespace NMessageID +{ + enum + { + kOk, + kCancel, + kWarning, + kError + }; +} + +int CStartupInfo::ShowWarningWithOk(const char **items, int 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, 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, 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, int numItems) +{ + return m_Data.Dialog(m_Data.ModuleNumber, X1, Y1, X2, Y2, (char *)helpTopic, + items, numItems); +} + +int CStartupInfo::ShowDialog(int sizeX, int sizeY, + const char *helpTopic, struct FarDialogItem *items, int 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, int numItems) +{ + for (int 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 &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 &= ~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, + int numItems) +{ + return m_Data.Menu(m_Data.ModuleNumber, x, y, maxHeight, flags, (char *)title, + (char *)aBottom, (char *)helpTopic, breakKeys, breakCode, items, numItems); +} + +int CStartupInfo::Menu( + unsigned int flags, + const char *title, + const char *helpTopic, + struct FarMenuItem *items, + int 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 farMenuItems; + FOR_VECTOR (i, items) + { + FarMenuItem item; + item.Checked = 0; + item.Separator = 0; + item.Selected = ((int)i == selectedItem); + const AString reducedString (items[i].Left(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) +{ + 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 index 92c36e451..38f64f988 100644 --- a/CPP/7zip/UI/Far/FarUtils.h +++ b/CPP/7zip/UI/Far/FarUtils.h @@ -1,197 +1,197 @@ -// FarUtils.h - -#ifndef __FAR_UTILS_H -#define __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, int numItems, int numButtons); - int ShowWarningWithOk(const char **items, int 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, int numItems); - int ShowDialog(int sizeX, int sizeY, - const char *helpTopic, struct FarDialogItem *items, int numItems); - - void InitDialogItems(const CInitDialogItem *srcItems, - FarDialogItem *destItems, int 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 &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, - int numItems); - int Menu( - unsigned int flags, - const char *title, - const char *helpTopic, - FarMenuItem *items, - int 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((char *)fileName, (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((char *)fileName, (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(); - -bool WasEscPressed(); - -void ReduceString(UString &s, unsigned size); - -} - -#endif +// FarUtils.h + +#ifndef __FAR_UTILS_H +#define __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, int numItems, int numButtons); + int ShowWarningWithOk(const char **items, int 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, int numItems); + int ShowDialog(int sizeX, int sizeY, + const char *helpTopic, struct FarDialogItem *items, int numItems); + + void InitDialogItems(const CInitDialogItem *srcItems, + FarDialogItem *destItems, int 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 &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, + int numItems); + int Menu( + unsigned int flags, + const char *title, + const char *helpTopic, + FarMenuItem *items, + int 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((char *)fileName, (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((char *)fileName, (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(); + +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 index 4863d2296..4e5ed8d54 100644 --- a/CPP/7zip/UI/Far/Messages.h +++ b/CPP/7zip/UI/Far/Messages.h @@ -1,136 +1,136 @@ -// Far/Messages.h - -#ifndef __7ZIP_FAR_MESSAGES_H -#define __7ZIP_FAR_MESSAGES_H - -#include "../../PropID.h" - -namespace NMessageID { - -const unsigned k_Last_PropId_supported_by_plugin = kpidCopyLink; - -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 +// Far/Messages.h + +#ifndef __7ZIP_FAR_MESSAGES_H +#define __7ZIP_FAR_MESSAGES_H + +#include "../../PropID.h" + +namespace NMessageID { + +const unsigned k_Last_PropId_supported_by_plugin = kpidCopyLink; + +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 index 792f21a78..1171453e3 100644 --- a/CPP/7zip/UI/Far/OverwriteDialogFar.cpp +++ b/CPP/7zip/UI/Far/OverwriteDialogFar.cpp @@ -1,145 +1,145 @@ -// OverwriteDialogFar.cpp - -#include "StdAfx.h" - -#include - -#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; -}; - -void SetFileInfoStrings(const CFileInfo &fileInfo, - CFileInfoStrings &fileInfoStrings) -{ - char buffer[256]; - - if (fileInfo.SizeIsDefined) - { - ConvertUInt64ToString(fileInfo.Size, buffer); - fileInfoStrings.Size = buffer; - fileInfoStrings.Size += ' '; - 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 += ' '; - 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); - } - - AString pref1A (UnicodeStringToMultiByte(pref1, CP_OEMCP)); - AString pref2A (UnicodeStringToMultiByte(pref2, CP_OEMCP)); - AString name1A (UnicodeStringToMultiByte(name1, CP_OEMCP)); - AString name2A (UnicodeStringToMultiByte(name2, CP_OEMCP)); - - 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 = ARRAY_SIZE(initItems); - FarDialogItem aDialogItems[kNumDialogItems]; - g_StartupInfo.InitDialogItems(initItems, aDialogItems, kNumDialogItems); - 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; -} - -} +// OverwriteDialogFar.cpp + +#include "StdAfx.h" + +#include + +#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; +}; + +void SetFileInfoStrings(const CFileInfo &fileInfo, + CFileInfoStrings &fileInfoStrings) +{ + char buffer[256]; + + if (fileInfo.SizeIsDefined) + { + ConvertUInt64ToString(fileInfo.Size, buffer); + fileInfoStrings.Size = buffer; + fileInfoStrings.Size += ' '; + 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 += ' '; + 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); + } + + AString pref1A (UnicodeStringToMultiByte(pref1, CP_OEMCP)); + AString pref2A (UnicodeStringToMultiByte(pref2, CP_OEMCP)); + AString name1A (UnicodeStringToMultiByte(name1, CP_OEMCP)); + AString name2A (UnicodeStringToMultiByte(name2, CP_OEMCP)); + + 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 = ARRAY_SIZE(initItems); + FarDialogItem aDialogItems[kNumDialogItems]; + g_StartupInfo.InitDialogItems(initItems, aDialogItems, kNumDialogItems); + 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 index e5de1c368..34947436e 100644 --- a/CPP/7zip/UI/Far/OverwriteDialogFar.h +++ b/CPP/7zip/UI/Far/OverwriteDialogFar.h @@ -1,37 +1,37 @@ -// OverwriteDialogFar.h - -#ifndef __OVERWRITE_DIALOG_FAR_H -#define __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 +// OverwriteDialogFar.h + +#ifndef __OVERWRITE_DIALOG_FAR_H +#define __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 index 0d08ab511..72f81ac98 100644 --- a/CPP/7zip/UI/Far/Plugin.cpp +++ b/CPP/7zip/UI/Far/Plugin.cpp @@ -1,922 +1,922 @@ -// 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 unused -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, 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, 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 = 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 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 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 folderItem = _folder; - for (;;) - { - CMyComPtr 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 + 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 = 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 = 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, int &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, int &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)); - - int numItems = 2; - - { - CMyComPtr 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 getFolderArcProps; - _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); - if (getFolderArcProps) - { - CMyComPtr 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, 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, 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 = 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(Byte value) -{ - return (char)((value < 10) ? ('0' + value) : ('A' + (value - 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; - int itemIndex = (int)pluginPanelItem.UserData; - - CObjectVector 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 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]; - - int startY = kStartY + 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 _folderRawProps; - _folder.QueryInterface(IID_IArchiveGetRawProps, &_folderRawProps); - - CObjectVector 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 - { - for (UInt32 k = 0; k < dataSize; k++) - { - Byte b = ((const Byte *)data)[k]; - s += GetHex((Byte)((b >> 4) & 0xF)); - s += GetHex((Byte)(b & 0xF)); - } - } - } - - int startY = kStartY + 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); - } - } - } - } - - unsigned numLines = values.Size(); - for (i = 0; i < numLines; i++) - { - CInitDialogItem &idi = initDialogItems[1 + i * 2 + 1]; - idi.DataString = values[i]; - } - - unsigned numDialogItems = initDialogItems.Size(); - - CObjArray 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]; - unsigned len = (int)strlen(dialogItem.Data); - if (len > maxLen2) - maxLen2 = len; - dialogItem.X1 = maxLen + kSpace; - } - - size = numLines + 6; - xSize = 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, - 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; -} +// 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 unused +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, 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, 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 = 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 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 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 folderItem = _folder; + for (;;) + { + CMyComPtr 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 + 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 = 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 = 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, int &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, int &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)); + + int numItems = 2; + + { + CMyComPtr 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 getFolderArcProps; + _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); + if (getFolderArcProps) + { + CMyComPtr 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, 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, 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 = 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(Byte value) +{ + return (char)((value < 10) ? ('0' + value) : ('A' + (value - 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; + int itemIndex = (int)pluginPanelItem.UserData; + + CObjectVector 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 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]; + + int startY = kStartY + 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 _folderRawProps; + _folder.QueryInterface(IID_IArchiveGetRawProps, &_folderRawProps); + + CObjectVector 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 + { + for (UInt32 k = 0; k < dataSize; k++) + { + Byte b = ((const Byte *)data)[k]; + s += GetHex((Byte)((b >> 4) & 0xF)); + s += GetHex((Byte)(b & 0xF)); + } + } + } + + int startY = kStartY + 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); + } + } + } + } + + unsigned numLines = values.Size(); + for (i = 0; i < numLines; i++) + { + CInitDialogItem &idi = initDialogItems[1 + i * 2 + 1]; + idi.DataString = values[i]; + } + + unsigned numDialogItems = initDialogItems.Size(); + + CObjArray 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]; + unsigned len = (int)strlen(dialogItem.Data); + if (len > maxLen2) + maxLen2 = len; + dialogItem.X1 = maxLen + kSpace; + } + + size = numLines + 6; + xSize = 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, + 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 index 88e7b854f..1fe190e42 100644 --- a/CPP/7zip/UI/Far/Plugin.h +++ b/CPP/7zip/UI/Far/Plugin.h @@ -1,94 +1,94 @@ -// 7zip/Far/Plugin.h - -#ifndef __7ZIP_FAR_PLUGIN_H -#define __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 m_ArchiveHandler; - CMyComPtr _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, int 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, int itemsNumber, - int move, char *destPath, int opMode); - - NFar::NFileOperationReturnCode::EEnum GetFilesReal(struct PluginPanelItem *panelItems, - int itemsNumber, int move, const char *_aDestPath, int opMode, bool showBox); - - NFar::NFileOperationReturnCode::EEnum PutFiles(struct PluginPanelItem *panelItems, int itemsNumber, - int move, int opMode); - HRESULT CreateFolder(); - - HRESULT ShowAttributesWindow(); - - int ProcessKey(int key, unsigned int controlState); -}; - -HRESULT CompressFiles(const CObjectVector &pluginPanelItems); - -#endif +// 7zip/Far/Plugin.h + +#ifndef __7ZIP_FAR_PLUGIN_H +#define __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 m_ArchiveHandler; + CMyComPtr _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, int 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, int itemsNumber, + int move, char *destPath, int opMode); + + NFar::NFileOperationReturnCode::EEnum GetFilesReal(struct PluginPanelItem *panelItems, + int itemsNumber, int move, const char *_aDestPath, int opMode, bool showBox); + + NFar::NFileOperationReturnCode::EEnum PutFiles(struct PluginPanelItem *panelItems, int itemsNumber, + int move, int opMode); + HRESULT CreateFolder(); + + HRESULT ShowAttributesWindow(); + + int ProcessKey(int key, unsigned int controlState); +}; + +HRESULT CompressFiles(const CObjectVector &pluginPanelItems); + +#endif diff --git a/CPP/7zip/UI/Far/PluginCommon.cpp b/CPP/7zip/UI/Far/PluginCommon.cpp index d50b2e03a..e1d445827 100644 --- a/CPP/7zip/UI/Far/PluginCommon.cpp +++ b/CPP/7zip/UI/Far/PluginCommon.cpp @@ -1,50 +1,50 @@ -// SevenZip/Plugin.cpp - -#include "StdAfx.h" - -#include "Plugin.h" - -/* -void CPlugin::AddRealIndexOfFile(const CArchiveFolderItem &aFolder, - int anIndexInVector, vector &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 &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 &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()); -} - -*/ +// SevenZip/Plugin.cpp + +#include "StdAfx.h" + +#include "Plugin.h" + +/* +void CPlugin::AddRealIndexOfFile(const CArchiveFolderItem &aFolder, + int anIndexInVector, vector &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 &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 &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 index 49acfc45b..955843416 100644 --- a/CPP/7zip/UI/Far/PluginDelete.cpp +++ b/CPP/7zip/UI/Far/PluginDelete.cpp @@ -1,120 +1,120 @@ -// PluginDelete.cpp - -#include "StdAfx.h" - -#include - -#include "Messages.h" -#include "Plugin.h" -#include "UpdateCallbackFar.h" - -using namespace NFar; - -int CPlugin::DeleteFiles(PluginPanelItem *panelItems, int numItems, int opMode) -{ - if (numItems == 0) - return FALSE; - if (_agent->IsThereReadOnlyArc()) - { - 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]; - if (numItems == 1) - { - sprintf(msg, g_StartupInfo.GetMsgString(NMessageID::kDeleteFile), panelItems[0].FindData.cFileName); - msgItems[1] = msg; - } - else if (numItems > 1) - { - sprintf(msg, g_StartupInfo.GetMsgString(NMessageID::kDeleteNumberOfFiles), numItems); - msgItems[1] = msg; - } - if (g_StartupInfo.ShowMessage(FMSG_WARNING, NULL, msgItems, 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 indices(numItems); - int i; - for (i = 0; i < numItems; i++) - indices[i] = (UInt32)panelItems[i].UserData; - - /* - UStringVector pathVector; - GetPathParts(pathVector); - - CMyComPtr 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 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 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; -} +// PluginDelete.cpp + +#include "StdAfx.h" + +#include + +#include "Messages.h" +#include "Plugin.h" +#include "UpdateCallbackFar.h" + +using namespace NFar; + +int CPlugin::DeleteFiles(PluginPanelItem *panelItems, int numItems, int opMode) +{ + if (numItems == 0) + return FALSE; + if (_agent->IsThereReadOnlyArc()) + { + 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]; + if (numItems == 1) + { + sprintf(msg, g_StartupInfo.GetMsgString(NMessageID::kDeleteFile), panelItems[0].FindData.cFileName); + msgItems[1] = msg; + } + else if (numItems > 1) + { + sprintf(msg, g_StartupInfo.GetMsgString(NMessageID::kDeleteNumberOfFiles), numItems); + msgItems[1] = msg; + } + if (g_StartupInfo.ShowMessage(FMSG_WARNING, NULL, msgItems, 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 indices(numItems); + int i; + for (i = 0; i < numItems; i++) + indices[i] = (UInt32)panelItems[i].UserData; + + /* + UStringVector pathVector; + GetPathParts(pathVector); + + CMyComPtr 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 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 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 index 31f8475d2..9df4a09f9 100644 --- a/CPP/7zip/UI/Far/PluginRead.cpp +++ b/CPP/7zip/UI/Far/PluginRead.cpp @@ -1,295 +1,295 @@ -// 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) -{ - 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 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 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, - int 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, - int 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; - - 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 int kNumDialogItems = ARRAY_SIZE(initItems); - const int kOkButtonIndex = kNumDialogItems - 2; - const int 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 realIndices; - if (!decompressAllItems) - GetRealIndexes(panelItems, itemsNumber, realIndices); - */ - CObjArray indices(itemsNumber); - for (int i = 0; i < itemsNumber; i++) - indices[i] = (UInt32)panelItems[i].UserData; - - 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; -} +// 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) +{ + 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 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 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, + int 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, + int 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; + + 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 int kNumDialogItems = ARRAY_SIZE(initItems); + const int kOkButtonIndex = kNumDialogItems - 2; + const int 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 realIndices; + if (!decompressAllItems) + GetRealIndexes(panelItems, itemsNumber, realIndices); + */ + CObjArray indices(itemsNumber); + for (int i = 0; i < itemsNumber; i++) + indices[i] = (UInt32)panelItems[i].UserData; + + 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 index e26a32bdd..ec0f119b8 100644 --- a/CPP/7zip/UI/Far/PluginWrite.cpp +++ b/CPP/7zip/UI/Far/PluginWrite.cpp @@ -1,827 +1,827 @@ -// PluginWrite.cpp - -#include "StdAfx.h" - -#include - -#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 setProperties; - if (outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties) == S_OK) - { - /* - UStringVector realNames; - realNames.Add(UString("x")); - NCOM::CPropVariant value = (UInt32)method; - CRecordVector 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 newFolder; - _folder->BindToFolder(pathVector[i], &newFolder); - if (!newFolder) - break; - _folder = newFolder; - } - return S_OK; -} -*/ - -NFileOperationReturnCode::EEnum CPlugin::PutFiles( - struct PluginPanelItem *panelItems, int numItems, - int moveMode, int opMode) -{ - /* - if (moveMode != 0) - { - g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported); - return NFileOperationReturnCode::kError; - } - */ - - if (numItems == 0) - return NFileOperationReturnCode::kError; - - if (_agent->IsThereReadOnlyArc()) - { - g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); - return NFileOperationReturnCode::kError; - } - - const int kYSize = 14; - const int kXMid = 38; - - NCompression::CInfo compressionInfo; - compressionInfo.Load(); - - int methodIndex = 0; - int i; - for (i = ARRAY_SIZE(g_MethodMap) - 1; 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 = ARRAY_SIZE(initItems); - const int kOkButtonIndex = kNumDialogItems - 2; - FarDialogItem dialogItems[kNumDialogItems]; - g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems); - 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 < 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 < numItems; i++) - fileNames.AddInReserved(MultiByteToUnicodeString(panelItems[i].FindData.cFileName, CP_OEMCP)); - CObjArray fileNamePointers(numItems); - for (i = 0; i < numItems; i++) - fileNamePointers[i] = fileNames[i]; - - CMyComPtr 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 updateCallback(updateCallbackSpec ); - - updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer); - updateCallbackSpec->PasswordIsDefined = PasswordIsDefined; - updateCallbackSpec->Password = Password; - - 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 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 = 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 += '.'; - arcName += arcInfo.GetMainExt(); -} - -HRESULT CompressFiles(const CObjectVector &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 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 = i; - if (MyStringCompareNoCase(arcInfo.Name, compressionInfo.ArcType) == 0) - archiverIndex = 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]; - { - const CArcInfoEx &arcInfo = codecs->Formats[archiverIndex]; - const AString s (UnicodeStringToMultiByte(arcInfo.Name, CP_OEMCP)); - sprintf(updateAddToArchiveString, - g_StartupInfo.GetMsgString(NMessageID::kUpdateAddToArchive), (const char *)s); - } - - int methodIndex = 0; - int i; - for (i = ARRAY_SIZE(g_MethodMap) - 1; 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, updateAddToArchiveString, 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 = 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 < 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) - { - CIntVector 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)); - } - } - - 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) - { - int pos = arcName.Len() - prevExtensionLen; - if (pos > 2) - { - if (arcName[pos - 1] == '.') - arcName.DeleteFrom(pos - 1); - } - } - } - - archiverIndex = 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 outArchive; - - CMyComPtr 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(agentSpec->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"; - 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 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 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->IsThereReadOnlyArc()) - { - 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 = 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 updateCallback(updateCallbackSpec); - - updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer); - updateCallbackSpec->PasswordIsDefined = PasswordIsDefined; - updateCallbackSpec->Password = Password; - - HRESULT result; - { - CMyComPtr 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; -} +// PluginWrite.cpp + +#include "StdAfx.h" + +#include + +#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 setProperties; + if (outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties) == S_OK) + { + /* + UStringVector realNames; + realNames.Add(UString("x")); + NCOM::CPropVariant value = (UInt32)method; + CRecordVector 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 newFolder; + _folder->BindToFolder(pathVector[i], &newFolder); + if (!newFolder) + break; + _folder = newFolder; + } + return S_OK; +} +*/ + +NFileOperationReturnCode::EEnum CPlugin::PutFiles( + struct PluginPanelItem *panelItems, int numItems, + int moveMode, int opMode) +{ + /* + if (moveMode != 0) + { + g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported); + return NFileOperationReturnCode::kError; + } + */ + + if (numItems == 0) + return NFileOperationReturnCode::kError; + + if (_agent->IsThereReadOnlyArc()) + { + g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); + return NFileOperationReturnCode::kError; + } + + const int kYSize = 14; + const int kXMid = 38; + + NCompression::CInfo compressionInfo; + compressionInfo.Load(); + + int methodIndex = 0; + int i; + for (i = ARRAY_SIZE(g_MethodMap) - 1; 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 = ARRAY_SIZE(initItems); + const int kOkButtonIndex = kNumDialogItems - 2; + FarDialogItem dialogItems[kNumDialogItems]; + g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems); + 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 < 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 < numItems; i++) + fileNames.AddInReserved(MultiByteToUnicodeString(panelItems[i].FindData.cFileName, CP_OEMCP)); + CObjArray fileNamePointers(numItems); + for (i = 0; i < numItems; i++) + fileNamePointers[i] = fileNames[i]; + + CMyComPtr 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 updateCallback(updateCallbackSpec ); + + updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer); + updateCallbackSpec->PasswordIsDefined = PasswordIsDefined; + updateCallbackSpec->Password = Password; + + 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 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 = 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 += '.'; + arcName += arcInfo.GetMainExt(); +} + +HRESULT CompressFiles(const CObjectVector &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 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 = i; + if (MyStringCompareNoCase(arcInfo.Name, compressionInfo.ArcType) == 0) + archiverIndex = 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]; + { + const CArcInfoEx &arcInfo = codecs->Formats[archiverIndex]; + const AString s (UnicodeStringToMultiByte(arcInfo.Name, CP_OEMCP)); + sprintf(updateAddToArchiveString, + g_StartupInfo.GetMsgString(NMessageID::kUpdateAddToArchive), (const char *)s); + } + + int methodIndex = 0; + int i; + for (i = ARRAY_SIZE(g_MethodMap) - 1; 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, updateAddToArchiveString, 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 = 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 < 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) + { + CIntVector 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)); + } + } + + 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) + { + int pos = arcName.Len() - prevExtensionLen; + if (pos > 2) + { + if (arcName[pos - 1] == '.') + arcName.DeleteFrom(pos - 1); + } + } + } + + archiverIndex = 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 outArchive; + + CMyComPtr 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(agentSpec->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"; + 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 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 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->IsThereReadOnlyArc()) + { + 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 = 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 updateCallback(updateCallbackSpec); + + updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer); + updateCallbackSpec->PasswordIsDefined = PasswordIsDefined; + updateCallbackSpec->Password = Password; + + HRESULT result; + { + CMyComPtr 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 index 88ac77ebb..6efb132a9 100644 --- a/CPP/7zip/UI/Far/ProgressBox.cpp +++ b/CPP/7zip/UI/Far/ProgressBox.cpp @@ -1,305 +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) -{ - 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; -} - -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 - */ - { - int slashPos = FileName.ReverseFind_PathSepar(); - if (slashPos >= 0) - { - _name1U.SetFrom(FileName, 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, ARRAY_SIZE(strings), 0); - } - - _wasPrinted = true; - _printedState = *this; - _prevTick = tick; - _prevElapsedSec = elapsedSec; -} +// 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) +{ + 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; +} + +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 + */ + { + int slashPos = FileName.ReverseFind_PathSepar(); + if (slashPos >= 0) + { + _name1U.SetFrom(FileName, 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, 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 index 1011353a9..54bdb4f11 100644 --- a/CPP/7zip/UI/Far/ProgressBox.h +++ b/CPP/7zip/UI/Far/ProgressBox.h @@ -1,83 +1,83 @@ -// ProgressBox.h - -#ifndef __PROGRESS_BOX_H -#define __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 +// ProgressBox.h + +#ifndef __PROGRESS_BOX_H +#define __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 index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/UI/Far/StdAfx.cpp +++ b/CPP/7zip/UI/Far/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/UI/Far/StdAfx.h b/CPP/7zip/UI/Far/StdAfx.h index 59d9ac15b..2854ff3e9 100644 --- a/CPP/7zip/UI/Far/StdAfx.h +++ b/CPP/7zip/UI/Far/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/UI/Far/UpdateCallbackFar.cpp b/CPP/7zip/UI/Far/UpdateCallbackFar.cpp index e5993e973..3f0f206b4 100644 --- a/CPP/7zip/UI/Far/UpdateCallbackFar.cpp +++ b/CPP/7zip/UI/Far/UpdateCallbackFar.cpp @@ -1,237 +1,237 @@ -// UpdateCallbackFar.cpp - -#include "StdAfx.h" - -#ifndef _7ZIP_ST -#include "../../../Windows/Synchronization.h" -#endif - -#include "../../../Common/StringConvert.h" - -#include "FarUtils.h" -#include "UpdateCallbackFar.h" - -using namespace NWindows; -using namespace NFar; - -#ifndef _7ZIP_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; -} - - -STDMETHODIMP 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(); -} - -STDMETHODIMP CUpdateCallback100Imp::ScanError(const wchar_t *path, HRESULT errorCode) -{ - if (ShowSysErrorMessage(errorCode, path) == -1) - return E_ABORT; - return CheckBreak2(); -} - -STDMETHODIMP CUpdateCallback100Imp::SetNumFiles(UInt64 numFiles) -{ - MT_LOCK - - if (_percent) - { - _percent->FilesTotal = numFiles; - _percent->Print(); - } - return CheckBreak2(); -} - - -STDMETHODIMP CUpdateCallback100Imp::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */) -{ - return S_OK; -} - -STDMETHODIMP CUpdateCallback100Imp::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */) -{ - MT_LOCK - return CheckBreak2(); -} - - - -STDMETHODIMP CUpdateCallback100Imp::SetTotal(UInt64 size) -{ - MT_LOCK - - if (_percent) - { - _percent->Total = size; - _percent->Print(); - } - return CheckBreak2(); -} - -STDMETHODIMP CUpdateCallback100Imp::SetCompleted(const UInt64 *completeValue) -{ - MT_LOCK - - if (_percent) - { - if (completeValue) - _percent->Completed = *completeValue; - _percent->Print(); - } - return CheckBreak2(); -} - -STDMETHODIMP CUpdateCallback100Imp::CompressOperation(const wchar_t *name) -{ - MT_LOCK - - if (_percent) - { - _percent->Command = "Adding"; - _percent->FileName = name; - _percent->Print(); - } - return CheckBreak2();; -} - -STDMETHODIMP CUpdateCallback100Imp::DeleteOperation(const wchar_t *name) -{ - MT_LOCK - - if (_percent) - { - _percent->Command = "Deleting"; - _percent->FileName = name; - _percent->Print(); - } - return CheckBreak2();; -} - -STDMETHODIMP CUpdateCallback100Imp::OperationResult(Int32 /* opRes */) -{ - MT_LOCK - - if (_percent) - { - _percent->Files++; - } - return CheckBreak2(); -} - -STDMETHODIMP CUpdateCallback100Imp::UpdateErrorMessage(const wchar_t *message) -{ - MT_LOCK - - if (g_StartupInfo.ShowErrorMessage(UnicodeStringToMultiByte(message, CP_OEMCP)) == -1) - return E_ABORT; - return CheckBreak2(); -} - -HRESULT CUpdateCallback100Imp::OpenFileError(const wchar_t *path, HRESULT errorCode) -{ - if (ShowSysErrorMessage(errorCode, path) == -1) - return E_ABORT; - return CheckBreak2(); -} - -STDMETHODIMP 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); - -STDMETHODIMP 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(); -} - - -STDMETHODIMP 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); - -STDMETHODIMP CUpdateCallback100Imp::CryptoGetTextPassword(BSTR *password) -{ - MT_LOCK - - *password = NULL; - if (!PasswordIsDefined) - { - RINOK(GetPassword(Password)); - PasswordIsDefined = true; - } - return StringToBstr(Password, password); -} - -STDMETHODIMP CUpdateCallback100Imp::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) -{ - MT_LOCK - - *password = NULL; - *passwordIsDefined = BoolToInt(PasswordIsDefined); - if (!PasswordIsDefined) - return S_OK; - return StringToBstr(Password, password); -} +// UpdateCallbackFar.cpp + +#include "StdAfx.h" + +#ifndef _7ZIP_ST +#include "../../../Windows/Synchronization.h" +#endif + +#include "../../../Common/StringConvert.h" + +#include "FarUtils.h" +#include "UpdateCallbackFar.h" + +using namespace NWindows; +using namespace NFar; + +#ifndef _7ZIP_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; +} + + +STDMETHODIMP 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(); +} + +STDMETHODIMP CUpdateCallback100Imp::ScanError(const wchar_t *path, HRESULT errorCode) +{ + if (ShowSysErrorMessage(errorCode, path) == -1) + return E_ABORT; + return CheckBreak2(); +} + +STDMETHODIMP CUpdateCallback100Imp::SetNumFiles(UInt64 numFiles) +{ + MT_LOCK + + if (_percent) + { + _percent->FilesTotal = numFiles; + _percent->Print(); + } + return CheckBreak2(); +} + + +STDMETHODIMP CUpdateCallback100Imp::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */) +{ + return S_OK; +} + +STDMETHODIMP CUpdateCallback100Imp::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */) +{ + MT_LOCK + return CheckBreak2(); +} + + + +STDMETHODIMP CUpdateCallback100Imp::SetTotal(UInt64 size) +{ + MT_LOCK + + if (_percent) + { + _percent->Total = size; + _percent->Print(); + } + return CheckBreak2(); +} + +STDMETHODIMP CUpdateCallback100Imp::SetCompleted(const UInt64 *completeValue) +{ + MT_LOCK + + if (_percent) + { + if (completeValue) + _percent->Completed = *completeValue; + _percent->Print(); + } + return CheckBreak2(); +} + +STDMETHODIMP CUpdateCallback100Imp::CompressOperation(const wchar_t *name) +{ + MT_LOCK + + if (_percent) + { + _percent->Command = "Adding"; + _percent->FileName = name; + _percent->Print(); + } + return CheckBreak2();; +} + +STDMETHODIMP CUpdateCallback100Imp::DeleteOperation(const wchar_t *name) +{ + MT_LOCK + + if (_percent) + { + _percent->Command = "Deleting"; + _percent->FileName = name; + _percent->Print(); + } + return CheckBreak2();; +} + +STDMETHODIMP CUpdateCallback100Imp::OperationResult(Int32 /* opRes */) +{ + MT_LOCK + + if (_percent) + { + _percent->Files++; + } + return CheckBreak2(); +} + +STDMETHODIMP CUpdateCallback100Imp::UpdateErrorMessage(const wchar_t *message) +{ + MT_LOCK + + if (g_StartupInfo.ShowErrorMessage(UnicodeStringToMultiByte(message, CP_OEMCP)) == -1) + return E_ABORT; + return CheckBreak2(); +} + +HRESULT CUpdateCallback100Imp::OpenFileError(const wchar_t *path, HRESULT errorCode) +{ + if (ShowSysErrorMessage(errorCode, path) == -1) + return E_ABORT; + return CheckBreak2(); +} + +STDMETHODIMP 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); + +STDMETHODIMP 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(); +} + + +STDMETHODIMP 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); + +STDMETHODIMP CUpdateCallback100Imp::CryptoGetTextPassword(BSTR *password) +{ + MT_LOCK + + *password = NULL; + if (!PasswordIsDefined) + { + RINOK(GetPassword(Password)); + PasswordIsDefined = true; + } + return StringToBstr(Password, password); +} + +STDMETHODIMP 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 index 63c8d46f3..d2c2c8ed2 100644 --- a/CPP/7zip/UI/Far/UpdateCallbackFar.h +++ b/CPP/7zip/UI/Far/UpdateCallbackFar.h @@ -1,60 +1,60 @@ -// UpdateCallbackFar.h - -#ifndef __UPDATE_CALLBACK_FAR_H -#define __UPDATE_CALLBACK_FAR_H - -#include "../../../Common/MyCom.h" - -#include "../../IPassword.h" - -#include "../Agent/IFolderArchive.h" - -#include "ProgressBox.h" - -class CUpdateCallback100Imp: - public IFolderArchiveUpdateCallback, - public IFolderArchiveUpdateCallback2, - public IFolderScanProgress, - public ICryptoGetTextPassword2, - public ICryptoGetTextPassword, - public IArchiveOpenCallback, - public CMyUnknownImp -{ - // CMyComPtr _archiveHandler; - CProgressBox *_percent; - UInt64 _total; - -public: - - bool PasswordIsDefined; - UString Password; - - MY_UNKNOWN_IMP6( - IFolderArchiveUpdateCallback, - IFolderArchiveUpdateCallback2, - IFolderScanProgress, - ICryptoGetTextPassword2, - ICryptoGetTextPassword, - IArchiveOpenCallback - ) - - INTERFACE_IProgress(;) - INTERFACE_IFolderArchiveUpdateCallback(;) - INTERFACE_IFolderArchiveUpdateCallback2(;) - INTERFACE_IFolderScanProgress(;) - INTERFACE_IArchiveOpenCallback(;) - - STDMETHOD(CryptoGetTextPassword)(BSTR *password); - STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password); - - CUpdateCallback100Imp(): _total(0) {} - void Init(/* IInFolderArchive *archiveHandler, */ CProgressBox *progressBox) - { - // _archiveHandler = archiveHandler; - _percent = progressBox; - PasswordIsDefined = false; - Password.Empty(); - } -}; - -#endif +// UpdateCallbackFar.h + +#ifndef __UPDATE_CALLBACK_FAR_H +#define __UPDATE_CALLBACK_FAR_H + +#include "../../../Common/MyCom.h" + +#include "../../IPassword.h" + +#include "../Agent/IFolderArchive.h" + +#include "ProgressBox.h" + +class CUpdateCallback100Imp: + public IFolderArchiveUpdateCallback, + public IFolderArchiveUpdateCallback2, + public IFolderScanProgress, + public ICryptoGetTextPassword2, + public ICryptoGetTextPassword, + public IArchiveOpenCallback, + public CMyUnknownImp +{ + // CMyComPtr _archiveHandler; + CProgressBox *_percent; + UInt64 _total; + +public: + + bool PasswordIsDefined; + UString Password; + + MY_UNKNOWN_IMP6( + IFolderArchiveUpdateCallback, + IFolderArchiveUpdateCallback2, + IFolderScanProgress, + ICryptoGetTextPassword2, + ICryptoGetTextPassword, + IArchiveOpenCallback + ) + + INTERFACE_IProgress(;) + INTERFACE_IFolderArchiveUpdateCallback(;) + INTERFACE_IFolderArchiveUpdateCallback2(;) + INTERFACE_IFolderScanProgress(;) + INTERFACE_IArchiveOpenCallback(;) + + STDMETHOD(CryptoGetTextPassword)(BSTR *password); + STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *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 index 1606bb82c..621c8d9e2 100644 --- a/CPP/7zip/UI/Far/makefile +++ b/CPP/7zip/UI/Far/makefile @@ -1,102 +1,102 @@ -PROG = 7-ZipFar.dll -DEF_FILE = Far.def -CFLAGS = $(CFLAGS) \ - -DEXTERNAL_CODECS \ - -DNEW_FOLDER_INTERFACE - -!IFNDEF UNDER_CE -CFLAGS = $(CFLAGS) -DWIN_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 \ - $O\UTFConvert.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\ErrorMsg.obj \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileLink.obj \ - $O\FileName.obj \ - $O\PropVariant.obj \ - $O\PropVariantConv.obj \ - $O\Registry.obj \ - $O\ResourceString.obj \ - $O\Synchronization.obj \ - $O\TimeUtils.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\FilePathAutoRename.obj \ - $O\FileStreams.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.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\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\OutStreamWithCRC.obj \ - -AGENT_OBJS = \ - $O\Agent.obj \ - $O\AgentOut.obj \ - $O\AgentProxy.obj \ - $O\ArchiveFolder.obj \ - $O\ArchiveFolderOpen.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" +PROG = 7-ZipFar.dll +DEF_FILE = Far.def +CFLAGS = $(CFLAGS) \ + -DEXTERNAL_CODECS \ + -DNEW_FOLDER_INTERFACE + +!IFNDEF UNDER_CE +CFLAGS = $(CFLAGS) -DWIN_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 \ + $O\UTFConvert.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\ErrorMsg.obj \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileLink.obj \ + $O\FileName.obj \ + $O\PropVariant.obj \ + $O\PropVariantConv.obj \ + $O\Registry.obj \ + $O\ResourceString.obj \ + $O\Synchronization.obj \ + $O\TimeUtils.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\FilePathAutoRename.obj \ + $O\FileStreams.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.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\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\OutStreamWithCRC.obj \ + +AGENT_OBJS = \ + $O\Agent.obj \ + $O\AgentOut.obj \ + $O\AgentProxy.obj \ + $O\ArchiveFolder.obj \ + $O\ArchiveFolderOpen.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 index 7d04d2d0a..a5c2e2f31 100644 --- a/CPP/7zip/UI/Far/resource.rc +++ b/CPP/7zip/UI/Far/resource.rc @@ -1,3 +1,3 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_DLL("7-Zip Plugin for FAR Manager", "7-ZipFar") +#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 index 304ba7dd6..6a13c9231 100644 --- a/CPP/7zip/UI/FileManager/7zFM.exe.manifest +++ b/CPP/7zip/UI/FileManager/7zFM.exe.manifest @@ -1,20 +1,20 @@ - - - - 7-Zip File Manager. - - - - - - - - - - - - - true - - - + + + + 7-Zip File Manager. + + + + + + + + + + + + + true + + + diff --git a/CPP/7zip/UI/FileManager/AboutDialog.cpp b/CPP/7zip/UI/FileManager/AboutDialog.cpp index 5fb237533..d954dbe66 100644 --- a/CPP/7zip/UI/FileManager/AboutDialog.cpp +++ b/CPP/7zip/UI/FileManager/AboutDialog.cpp @@ -1,61 +1,61 @@ -// AboutDialog.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../MyVersion.h" - -#include "AboutDialog.h" -#include "PropertyNameRes.h" - -#include "HelpUtils.h" -#include "LangUtils.h" - -static const UInt32 kLangIDs[] = -{ - IDT_ABOUT_INFO -}; - -#define kHomePageURL TEXT("http://www.7-zip.org/") -#define kHomePageURL2 TEXT("http://github.com/mcmilk/7-Zip-zstd/") -#define kHelpTopic "start.htm" - -#define LLL_(quote) L##quote -#define LLL(quote) LLL_(quote) - -bool CAboutDialog::OnInit() -{ - LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); - SetItemText(IDT_ABOUT_VERSION, UString("7-Zip " MY_VERSION_CPU)); - SetItemText(IDT_ABOUT_DATE, LLL(MY_DATE)); - - LangSetWindowText(*this, IDD_ABOUT); - NormalizePosition(); - return CModalDialog::OnInit(); -} - -void CAboutDialog::OnHelp() -{ - ShowHelpWindow(kHelpTopic); -} - -bool CAboutDialog::OnButtonClicked(int buttonID, HWND buttonHWND) -{ - LPCTSTR url; - switch (buttonID) - { - case IDB_ABOUT_HOMEPAGE: url = kHomePageURL; break; - case IDB_ABOUT_HOMEPAGE2: url = kHomePageURL2; break; - default: - return CModalDialog::OnButtonClicked(buttonID, buttonHWND); - } - - SHELLEXECUTEINFO s; - memset(&s, 0, sizeof(s)); - s.cbSize = sizeof(s); - s.lpFile = url; - ::ShellExecuteEx(&s); - - return true; -} +// AboutDialog.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../MyVersion.h" + +#include "AboutDialog.h" +#include "PropertyNameRes.h" + +#include "HelpUtils.h" +#include "LangUtils.h" + +static const UInt32 kLangIDs[] = +{ + IDT_ABOUT_INFO +}; + +#define kHomePageURL TEXT("http://www.7-zip.org/") +#define kHomePageURL2 TEXT("http://github.com/mcmilk/7-Zip-zstd/") +#define kHelpTopic "start.htm" + +#define LLL_(quote) L##quote +#define LLL(quote) LLL_(quote) + +bool CAboutDialog::OnInit() +{ + LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); + SetItemText(IDT_ABOUT_VERSION, UString("7-Zip " MY_VERSION_CPU)); + SetItemText(IDT_ABOUT_DATE, LLL(MY_DATE)); + + LangSetWindowText(*this, IDD_ABOUT); + NormalizePosition(); + return CModalDialog::OnInit(); +} + +void CAboutDialog::OnHelp() +{ + ShowHelpWindow(kHelpTopic); +} + +bool CAboutDialog::OnButtonClicked(int buttonID, HWND buttonHWND) +{ + LPCTSTR url; + switch (buttonID) + { + case IDB_ABOUT_HOMEPAGE: url = kHomePageURL; break; + case IDB_ABOUT_HOMEPAGE2: url = kHomePageURL2; break; + default: + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); + } + + SHELLEXECUTEINFO s; + memset(&s, 0, sizeof(s)); + s.cbSize = sizeof(s); + s.lpFile = url; + ::ShellExecuteEx(&s); + + return true; +} diff --git a/CPP/7zip/UI/FileManager/AboutDialog.h b/CPP/7zip/UI/FileManager/AboutDialog.h index 6fc517633..39fd3ba77 100644 --- a/CPP/7zip/UI/FileManager/AboutDialog.h +++ b/CPP/7zip/UI/FileManager/AboutDialog.h @@ -1,19 +1,19 @@ -// AboutDialog.h - -#ifndef __ABOUT_DIALOG_H -#define __ABOUT_DIALOG_H - -#include "../../../Windows/Control/Dialog.h" - -#include "AboutDialogRes.h" - -class CAboutDialog: public NWindows::NControl::CModalDialog -{ -public: - virtual bool OnInit(); - virtual void OnHelp(); - virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); - INT_PTR Create(HWND wndParent = 0) { return CModalDialog::Create(IDD_ABOUT, wndParent); } -}; - -#endif +// AboutDialog.h + +#ifndef __ABOUT_DIALOG_H +#define __ABOUT_DIALOG_H + +#include "../../../Windows/Control/Dialog.h" + +#include "AboutDialogRes.h" + +class CAboutDialog: public NWindows::NControl::CModalDialog +{ +public: + virtual bool OnInit(); + virtual void OnHelp(); + virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); + INT_PTR Create(HWND wndParent = 0) { return CModalDialog::Create(IDD_ABOUT, wndParent); } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/AboutDialog.rc b/CPP/7zip/UI/FileManager/AboutDialog.rc index a5cf4b8bc..92dd0c725 100644 --- a/CPP/7zip/UI/FileManager/AboutDialog.rc +++ b/CPP/7zip/UI/FileManager/AboutDialog.rc @@ -1,27 +1,27 @@ -#include "AboutDialogRes.h" -#include "../../GuiCommon.rc" -#include "../../MyVersion.h" - -#define xc 216 -#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, bx3-10, by, bxs, bys - PUSHBUTTON "www.7-zip.org", IDB_ABOUT_HOMEPAGE, bx2-10, by, bxs, bys - PUSHBUTTON "7-Zip ZS Hompeage", IDB_ABOUT_HOMEPAGE2, bx1-10, by, bxs+10, 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_CR, -1, m, 80, xc, 8 - LTEXT "7-Zip is free software", IDT_ABOUT_INFO, m, y, xc, (by - y - 1) -} +#include "AboutDialogRes.h" +#include "../../GuiCommon.rc" +#include "../../MyVersion.h" + +#define xc 216 +#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, bx3-10, by, bxs, bys + PUSHBUTTON "www.7-zip.org", IDB_ABOUT_HOMEPAGE, bx2-10, by, bxs, bys + PUSHBUTTON "7-Zip ZS Hompeage", IDB_ABOUT_HOMEPAGE2, bx1-10, by, bxs+10, 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_CR, -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 index 1ed9cb172..cba490a4a 100644 --- a/CPP/7zip/UI/FileManager/AboutDialogRes.h +++ b/CPP/7zip/UI/FileManager/AboutDialogRes.h @@ -1,9 +1,9 @@ -#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 -#define IDB_ABOUT_HOMEPAGE2 111 +#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 +#define IDB_ABOUT_HOMEPAGE2 111 diff --git a/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp b/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp index 50118b477..7069e1aa8 100644 --- a/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp +++ b/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp @@ -1,839 +1,839 @@ -// AltStreamsFolder.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/Wildcard.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; - 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 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(); - } - - 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; -} - -STDMETHODIMP 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; -} - -STDMETHODIMP CAltStreamsFolder::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = Streams.Size(); - return S_OK; -} - -#ifdef USE_UNICODE_FSTRING - -STDMETHODIMP CAltStreamsFolder::GetItemPrefix(UInt32 /* index */, const wchar_t **name, unsigned *len) -{ - *name = 0; - *len = 0; - return S_OK; -} - -STDMETHODIMP CAltStreamsFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len) -{ - *name = 0; - *len = 0; - { - const CAltStream &ss = Streams[index]; - *name = ss.Name; - *len = ss.Name.Len(); - } - return S_OK; -} - -STDMETHODIMP_(UInt64) CAltStreamsFolder::GetItemSize(UInt32 index) -{ - return Streams[index].Size; -} - -#endif - - -STDMETHODIMP 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) -{ - int dotPos = name.ReverseFind_Dot(); - return name.Ptr((dotPos < 0) ? name.Len() : dotPos); -} - -STDMETHODIMP_(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; -} - -STDMETHODIMP CAltStreamsFolder::BindToFolder(UInt32 /* index */, IFolderFolder **resultFolder) -{ - *resultFolder = 0; - return E_INVALIDARG; -} - -STDMETHODIMP CAltStreamsFolder::BindToFolder(const wchar_t * /* name */, IFolderFolder **resultFolder) -{ - *resultFolder = 0; - return E_INVALIDARG; -} - -// static CFSTR const kSuperPrefix = FTEXT("\\\\?\\"); - -STDMETHODIMP CAltStreamsFolder::BindToParentFolder(IFolderFolder **resultFolder) -{ - *resultFolder = 0; - /* - if (_parentFolder) - { - CMyComPtr parentFolder = _parentFolder; - *resultFolder = parentFolder.Detach(); - return S_OK; - } - */ - - if (IsDriveRootPath_SuperAllowed(_pathBaseFile)) - { - CFSDrives *drivesFolderSpec = new CFSDrives; - CMyComPtr 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 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 netFolder = netFolderSpec; - netFolderSpec->Init(fs2us(parentPath)); - *resultFolder = netFolder.Detach(); - return S_OK; - } - #endif - - CFSFolder *parentFolderSpec = new CFSFolder; - CMyComPtr parentFolder = parentFolderSpec; - RINOK(parentFolderSpec->Init(parentPath, 0)); - *resultFolder = parentFolder.Detach(); - */ - - return S_OK; -} - -STDMETHODIMP CAltStreamsFolder::GetNumberOfProperties(UInt32 *numProperties) -{ - *numProperties = ARRAY_SIZE(kProps); - return S_OK; -} - -STDMETHODIMP CAltStreamsFolder::GetPropertyInfo IMP_IFolderFolder_GetProp(kProps) - -STDMETHODIMP 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 -} - -STDMETHODIMP 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; -} - -STDMETHODIMP CAltStreamsFolder::Clone(IFolderFolder **resultFolder) -{ - CAltStreamsFolder *folderSpec = new CAltStreamsFolder; - CMyComPtr 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); -} -*/ - -STDMETHODIMP CAltStreamsFolder::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CAltStreamsFolder::CreateFile(const wchar_t *name, IProgress * /* progress */) -{ - FString absPath; - GetAbsPath(name, absPath); - NIO::COutFile outFile; - if (!outFile.Create(absPath, false)) - return ::GetLastError(); - return S_OK; -} - -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()); -} - -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; -} - -STDMETHODIMP CAltStreamsFolder::Rename(UInt32 index, const wchar_t *newName, IProgress *progress) -{ - CMyComPtr callback; - if (progress) - { - RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&callback)); - } - - FString destPath = _pathPrefix + us2fs(newName); - - const CAltStream &ss = Streams[index]; - - if (callback) - { - RINOK(callback->SetNumFiles(1)); - RINOK(callback->SetTotal(ss.Size)); - } - - NFsFolder::CCopyStateIO state; - state.Progress = progress; - state.TotalSize = 0; - state.DeleteSrcFile = true; - - return UpdateFile(state, _pathPrefix + us2fs(ss.Name), destPath, callback); -} - -STDMETHODIMP 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); - bool result = DeleteFileAlways(fullPath); - if (!result) - return Return_LastError_or_FAIL(); - UInt64 completed = i; - RINOK(progress->SetCompleted(&completed)); - } - return S_OK; -} - -STDMETHODIMP CAltStreamsFolder::SetProperty(UInt32 /* index */, PROPID /* propID */, - const PROPVARIANT * /* value */, IProgress * /* progress */) -{ - return E_NOTIMPL; -} - -STDMETHODIMP 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 Return_LastError_or_FAIL(); -} - -/* -class CGetProp: - public IGetProp, - public CMyUnknownImp -{ -public: - // const CArc *Arc; - // UInt32 IndexInArc; - UString Name; // relative path - UInt64 Size; - - MY_UNKNOWN_IMP1(IGetProp) - INTERFACE_IGetProp(;) -}; - -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 - } - 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, "can not 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; -} - -STDMETHODIMP 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; - - /* - CMyComPtr ExtractToStreamCallback; - RINOK(callback->QueryInterface(IID_IFolderExtractToStreamCallback, (void **)&ExtractToStreamCallback)); - 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 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 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; - - bool isAltDest = NName::IsAltPathPrefix(destPath);; - bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back())); - - if (isDirectPath) - { - if (numItems > 1) - return E_INVALIDARG; - } - - CFileInfo fi; - if (!fi.Find(_pathBaseFile)) - return GetLastError(); - - NFsFolder::CCopyStateIO state; - state.Progress = callback; - state.DeleteSrcFile = IntToBool(moveMode); - state.TotalSize = totalSize; - - for (UInt32 i = 0; i < numItems; i++) - { - 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; -} - -STDMETHODIMP CAltStreamsFolder::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */, - const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */) -{ - /* - if (numItems == 0) - return S_OK; - - CMyComPtr callback; - if (progress) - { - RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&callback)); - } - - if (CompareFileNames(fromFolderPath, fs2us(_pathPrefix)) == 0) - { - RINOK(SendMessageError(callback, "can not 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; -} - -STDMETHODIMP CAltStreamsFolder::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */) -{ - return E_NOTIMPL; -} - -} +// AltStreamsFolder.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.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; + 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 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(); + } + + 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; +} + +STDMETHODIMP 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; +} + +STDMETHODIMP CAltStreamsFolder::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = Streams.Size(); + return S_OK; +} + +#ifdef USE_UNICODE_FSTRING + +STDMETHODIMP CAltStreamsFolder::GetItemPrefix(UInt32 /* index */, const wchar_t **name, unsigned *len) +{ + *name = 0; + *len = 0; + return S_OK; +} + +STDMETHODIMP CAltStreamsFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len) +{ + *name = 0; + *len = 0; + { + const CAltStream &ss = Streams[index]; + *name = ss.Name; + *len = ss.Name.Len(); + } + return S_OK; +} + +STDMETHODIMP_(UInt64) CAltStreamsFolder::GetItemSize(UInt32 index) +{ + return Streams[index].Size; +} + +#endif + + +STDMETHODIMP 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) +{ + int dotPos = name.ReverseFind_Dot(); + return name.Ptr((dotPos < 0) ? name.Len() : dotPos); +} + +STDMETHODIMP_(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; +} + +STDMETHODIMP CAltStreamsFolder::BindToFolder(UInt32 /* index */, IFolderFolder **resultFolder) +{ + *resultFolder = 0; + return E_INVALIDARG; +} + +STDMETHODIMP CAltStreamsFolder::BindToFolder(const wchar_t * /* name */, IFolderFolder **resultFolder) +{ + *resultFolder = 0; + return E_INVALIDARG; +} + +// static CFSTR const kSuperPrefix = FTEXT("\\\\?\\"); + +STDMETHODIMP CAltStreamsFolder::BindToParentFolder(IFolderFolder **resultFolder) +{ + *resultFolder = 0; + /* + if (_parentFolder) + { + CMyComPtr parentFolder = _parentFolder; + *resultFolder = parentFolder.Detach(); + return S_OK; + } + */ + + if (IsDriveRootPath_SuperAllowed(_pathBaseFile)) + { + CFSDrives *drivesFolderSpec = new CFSDrives; + CMyComPtr 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 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 netFolder = netFolderSpec; + netFolderSpec->Init(fs2us(parentPath)); + *resultFolder = netFolder.Detach(); + return S_OK; + } + #endif + + CFSFolder *parentFolderSpec = new CFSFolder; + CMyComPtr parentFolder = parentFolderSpec; + RINOK(parentFolderSpec->Init(parentPath, 0)); + *resultFolder = parentFolder.Detach(); + */ + + return S_OK; +} + +STDMETHODIMP CAltStreamsFolder::GetNumberOfProperties(UInt32 *numProperties) +{ + *numProperties = ARRAY_SIZE(kProps); + return S_OK; +} + +STDMETHODIMP CAltStreamsFolder::GetPropertyInfo IMP_IFolderFolder_GetProp(kProps) + +STDMETHODIMP 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 +} + +STDMETHODIMP 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; +} + +STDMETHODIMP CAltStreamsFolder::Clone(IFolderFolder **resultFolder) +{ + CAltStreamsFolder *folderSpec = new CAltStreamsFolder; + CMyComPtr 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); +} +*/ + +STDMETHODIMP CAltStreamsFolder::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CAltStreamsFolder::CreateFile(const wchar_t *name, IProgress * /* progress */) +{ + FString absPath; + GetAbsPath(name, absPath); + NIO::COutFile outFile; + if (!outFile.Create(absPath, false)) + return ::GetLastError(); + return S_OK; +} + +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()); +} + +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; +} + +STDMETHODIMP CAltStreamsFolder::Rename(UInt32 index, const wchar_t *newName, IProgress *progress) +{ + CMyComPtr callback; + if (progress) + { + RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&callback)); + } + + FString destPath = _pathPrefix + us2fs(newName); + + const CAltStream &ss = Streams[index]; + + if (callback) + { + RINOK(callback->SetNumFiles(1)); + RINOK(callback->SetTotal(ss.Size)); + } + + NFsFolder::CCopyStateIO state; + state.Progress = progress; + state.TotalSize = 0; + state.DeleteSrcFile = true; + + return UpdateFile(state, _pathPrefix + us2fs(ss.Name), destPath, callback); +} + +STDMETHODIMP 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); + bool result = DeleteFileAlways(fullPath); + if (!result) + return Return_LastError_or_FAIL(); + UInt64 completed = i; + RINOK(progress->SetCompleted(&completed)); + } + return S_OK; +} + +STDMETHODIMP CAltStreamsFolder::SetProperty(UInt32 /* index */, PROPID /* propID */, + const PROPVARIANT * /* value */, IProgress * /* progress */) +{ + return E_NOTIMPL; +} + +STDMETHODIMP 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 Return_LastError_or_FAIL(); +} + +/* +class CGetProp: + public IGetProp, + public CMyUnknownImp +{ +public: + // const CArc *Arc; + // UInt32 IndexInArc; + UString Name; // relative path + UInt64 Size; + + MY_UNKNOWN_IMP1(IGetProp) + INTERFACE_IGetProp(;) +}; + +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 + } + 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, "can not 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; +} + +STDMETHODIMP 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; + + /* + CMyComPtr ExtractToStreamCallback; + RINOK(callback->QueryInterface(IID_IFolderExtractToStreamCallback, (void **)&ExtractToStreamCallback)); + 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 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 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; + + bool isAltDest = NName::IsAltPathPrefix(destPath);; + bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back())); + + if (isDirectPath) + { + if (numItems > 1) + return E_INVALIDARG; + } + + CFileInfo fi; + if (!fi.Find(_pathBaseFile)) + return GetLastError(); + + NFsFolder::CCopyStateIO state; + state.Progress = callback; + state.DeleteSrcFile = IntToBool(moveMode); + state.TotalSize = totalSize; + + for (UInt32 i = 0; i < numItems; i++) + { + 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; +} + +STDMETHODIMP CAltStreamsFolder::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */, + const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */) +{ + /* + if (numItems == 0) + return S_OK; + + CMyComPtr callback; + if (progress) + { + RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&callback)); + } + + if (CompareFileNames(fromFolderPath, fs2us(_pathPrefix)) == 0) + { + RINOK(SendMessageError(callback, "can not 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; +} + +STDMETHODIMP 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 index 808a83337..ccd0a58f5 100644 --- a/CPP/7zip/UI/FileManager/AltStreamsFolder.h +++ b/CPP/7zip/UI/FileManager/AltStreamsFolder.h @@ -1,100 +1,100 @@ -// AltStreamsFolder.h - -#ifndef __ALT_STREAMS_FOLDER_H -#define __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: - public IFolderFolder, - public IFolderCompare, - #ifdef USE_UNICODE_FSTRING - public IFolderGetItemName, - #endif - public IFolderWasChanged, - public IFolderOperations, - // public IFolderOperationsDeleteToRecycleBin, - public IFolderClone, - public IFolderGetSystemIconIndex, - public CMyUnknownImp -{ -public: - MY_QUERYINTERFACE_BEGIN2(IFolderFolder) - MY_QUERYINTERFACE_ENTRY(IFolderCompare) - #ifdef USE_UNICODE_FSTRING - MY_QUERYINTERFACE_ENTRY(IFolderGetItemName) - #endif - MY_QUERYINTERFACE_ENTRY(IFolderWasChanged) - // MY_QUERYINTERFACE_ENTRY(IFolderOperationsDeleteToRecycleBin) - MY_QUERYINTERFACE_ENTRY(IFolderOperations) - MY_QUERYINTERFACE_ENTRY(IFolderClone) - MY_QUERYINTERFACE_ENTRY(IFolderGetSystemIconIndex) - MY_QUERYINTERFACE_END - MY_ADDREF_RELEASE - - - INTERFACE_FolderFolder(;) - INTERFACE_FolderOperations(;) - - STDMETHOD_(Int32, CompareItems)(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw); - - #ifdef USE_UNICODE_FSTRING - INTERFACE_IFolderGetItemName(;) - #endif - STDMETHOD(WasChanged)(Int32 *wasChanged); - STDMETHOD(Clone)(IFolderFolder **resultFolder); - - STDMETHOD(GetSystemIconIndex)(UInt32 index, Int32 *iconIndex); - -private: - FString _pathBaseFile; // folder - FString _pathPrefix; // folder: - - CObjectVector Streams; - // CMyComPtr _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 */); - - CAltStreamsFolder() {} - - void GetFullPath(const CAltStream &item, FString &path) const - { - path = _pathPrefix; - path += us2fs(item.Name); - } - - void Clear() - { - Streams.Clear(); - } -}; - -} - -#endif +// AltStreamsFolder.h + +#ifndef __ALT_STREAMS_FOLDER_H +#define __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: + public IFolderFolder, + public IFolderCompare, + #ifdef USE_UNICODE_FSTRING + public IFolderGetItemName, + #endif + public IFolderWasChanged, + public IFolderOperations, + // public IFolderOperationsDeleteToRecycleBin, + public IFolderClone, + public IFolderGetSystemIconIndex, + public CMyUnknownImp +{ +public: + MY_QUERYINTERFACE_BEGIN2(IFolderFolder) + MY_QUERYINTERFACE_ENTRY(IFolderCompare) + #ifdef USE_UNICODE_FSTRING + MY_QUERYINTERFACE_ENTRY(IFolderGetItemName) + #endif + MY_QUERYINTERFACE_ENTRY(IFolderWasChanged) + // MY_QUERYINTERFACE_ENTRY(IFolderOperationsDeleteToRecycleBin) + MY_QUERYINTERFACE_ENTRY(IFolderOperations) + MY_QUERYINTERFACE_ENTRY(IFolderClone) + MY_QUERYINTERFACE_ENTRY(IFolderGetSystemIconIndex) + MY_QUERYINTERFACE_END + MY_ADDREF_RELEASE + + + INTERFACE_FolderFolder(;) + INTERFACE_FolderOperations(;) + + STDMETHOD_(Int32, CompareItems)(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw); + + #ifdef USE_UNICODE_FSTRING + INTERFACE_IFolderGetItemName(;) + #endif + STDMETHOD(WasChanged)(Int32 *wasChanged); + STDMETHOD(Clone)(IFolderFolder **resultFolder); + + STDMETHOD(GetSystemIconIndex)(UInt32 index, Int32 *iconIndex); + +private: + FString _pathBaseFile; // folder + FString _pathPrefix; // folder: + + CObjectVector Streams; + // CMyComPtr _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 */); + + CAltStreamsFolder() {} + + 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 index aeae20cb2..4c1ea5486 100644 --- a/CPP/7zip/UI/FileManager/App.cpp +++ b/CPP/7zip/UI/FileManager/App.cpp @@ -1,997 +1,997 @@ -// 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) -{ - int 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::ReloadLang() -{ - 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; - - DWORD style = (DWORD)panel._listView.GetStyle(); - if (st.AlternativeSelection) - style |= LVS_SINGLESEL; - else - style &= ~LVS_SINGLESEL; - panel._listView.SetStyle(style); - panel.SetExtendedStyle(); - } -} - -#ifndef ILC_COLOR32 -#define ILC_COLOR32 0x0020 -#endif - -HRESULT CApp::CreateOnePanel(int panelIndex, const UString &mainPath, const UString &arcFormat, - bool needOpenArc, - bool &archiveIsOpened, bool &encrypted) -{ - 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; - - int id = 1000 + 100 * panelIndex; - - return Panels[panelIndex].Create(_window, _window, - id, path, arcFormat, &m_PanelCallbackImp[panelIndex], &AppState, - needOpenArc, - archiveIsOpened, encrypted); -} - - -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, ARRAY_SIZE(g_StandardButtons), s)) - return; - SetButtonText(commandID, g_ArchiveButtons, 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 != 0) - { - 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 < ARRAY_SIZE(g_ArchiveButtons); i++) - AddButton(_buttonsImageList, _toolBar, g_ArchiveButtons[i], ShowButtonsLables, LargeButtons); - if (ShowStandardToolbar) - for (i = 0; i < 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, bool &archiveIsOpened, bool &encrypted) -{ - _window.Attach(hwnd); - - #ifdef UNDER_CE - _commandBar.Create(g_hInstance, hwnd, 1); - #endif - - MyLoadMenu(); - - #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]; - bool archiveIsOpened2 = false; - bool encrypted2 = false; - UString path; - if (isMainPanel) - path = mainPath; - - RINOK(CreateOnePanel(panelIndex, path, arcFormat, - isMainPanel && needOpenArc, - archiveIsOpened2, encrypted2)); - - if (isMainPanel) - { - archiveIsOpened = archiveIsOpened2; - encrypted = encrypted2; - if (needOpenArc && !archiveIsOpened2) - return S_OK; - } - } - } - - SetFocusedPanel(LastFocusedPanel); - Panels[LastFocusedPanel].SetFocusToList(); - return S_OK; -} - - -HRESULT CApp::SwitchOnOffOnePanel() -{ - if (NumPanels == 1) - { - NumPanels++; - bool archiveIsOpened, encrypted; - RINOK(CreateOnePanel(1 - LastFocusedPanel, UString(), UString(), - false, // needOpenArc - archiveIsOpened, encrypted)); - 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 ReducePathToRealFileSystemPath(UString &path) -{ - unsigned prefixSize = GetRootPrefixSize(path); - - while (!path.IsEmpty()) - { - if (NFind::DoesDirExist(us2fs(path))) - { - NName::NormalizeDirPathPrefix(path); - break; - } - int pos = path.ReverseFind_PathSepar(); - if (pos < 0) - { - path.Empty(); - break; - } - path.DeleteFrom(pos + 1); - if ((unsigned)pos + 1 == prefixSize) - break; - path.DeleteFrom(pos); - } -} - -// returns: true, if such dir exists or is root -/* -static bool CheckFolderPath(const UString &path) -{ - UString pathReduced = path; - ReducePathToRealFileSystemPath(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) -{ - 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, int 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 &indices) -{ - UString info; - UInt64 numDirs, numFiles, filesSize, foldersSize; - numDirs = numFiles = filesSize = foldersSize = 0; - - unsigned i; - for (i = 0; i < indices.Size(); i++) - { - int 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 += " "; - int 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, int srcPanelIndex) -{ - 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 indices; - UString destPath; - bool useDestPanel = false; - - { - if (copyToSame) - { - int focusedItem = srcPanel._listView.GetFocusedItem(); - if (focusedItem < 0) - return; - int realIndex = srcPanel.GetRealItemIndex(focusedItem); - if (realIndex == kParentIndex) - return; - indices.Add(realIndex); - destPath = srcPanel.GetItemName(realIndex); - } - else - { - srcPanel.GetOperatedIndicesSmart(indices); - if (indices.Size() == 0) - return; - destPath = destPanel.GetFsPath(); - if (NumPanels == 1) - ReducePathToRealFileSystemPath(destPath); - } - } - - UStringVector copyFolders; - ReadCopyHistory(copyFolders); - - 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"Can not 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))) - { - DWORD lastError = ::GetLastError(); - srcPanel.MessageBox_Error_2Lines_Message_HRESULT(prefix, lastError); - return; - } - } - // bool isFolder = srcPanael.IsItem_Folder(indices[0]); - } - else - { - NName::NormalizeDirPathPrefix(destPath); - if (!CreateComplexDir(us2fs(destPath))) - { - DWORD lastError = ::GetLastError(); - 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, 0); - } - - 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(int srcPanelIndex) -{ - if (NumPanels <= 1) - return; - const CPanel &srcPanel = Panels[srcPanelIndex]; - CPanel &destPanel = Panels[1 - srcPanelIndex]; - destPanel.BindToPathAndRefresh(srcPanel._currentFolderPrefix); -} - -void CApp::OnSetSubFolder(int srcPanelIndex) -{ - if (NumPanels <= 1) - return; - const CPanel &srcPanel = Panels[srcPanelIndex]; - CPanel &destPanel = Panels[1 - srcPanelIndex]; - - int focusedItem = srcPanel._listView.GetFocusedItem(); - if (focusedItem < 0) - return; - int realIndex = srcPanel.GetRealItemIndex(focusedItem); - if (!srcPanel.IsItem_Folder(realIndex)) - return; - - // destPanel.BindToFolder(srcPanel._currentFolderPrefix + srcPanel.GetItemName(realIndex) + WCHAR_PATH_SEPARATOR); - - CMyComPtr newFolder; - if (realIndex == kParentIndex) - { - if (srcPanel._folder->BindToParentFolder(&newFolder) != S_OK) - return; - if (!newFolder) - { - const UString parentPrefix = srcPanel.GetParentDirPrefix(); - bool archiveIsOpened, encrypted; - destPanel.BindToPath(parentPrefix, UString(), archiveIsOpened, encrypted); - 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 = 0; - g_ToolTipBuffer.Empty(); - SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer); - g_ToolTipBufferSys = GetSystemString(g_ToolTipBuffer); - info->lpszText = (LPTSTR)(LPCTSTR)g_ToolTipBufferSys; - return; - } - #ifndef _UNICODE - if (pnmh->code == TTN_GETDISPINFOW) - { - LPNMTTDISPINFOW info = (LPNMTTDISPINFOW)pnmh; - info->hinst = 0; - g_ToolTipBuffer.Empty(); - SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer); - info->lpszText = (LPWSTR)(LPCWSTR)g_ToolTipBuffer; - 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); -} - -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(); -} +// 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) +{ + int 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::ReloadLang() +{ + 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; + + DWORD style = (DWORD)panel._listView.GetStyle(); + if (st.AlternativeSelection) + style |= LVS_SINGLESEL; + else + style &= ~LVS_SINGLESEL; + panel._listView.SetStyle(style); + panel.SetExtendedStyle(); + } +} + +#ifndef ILC_COLOR32 +#define ILC_COLOR32 0x0020 +#endif + +HRESULT CApp::CreateOnePanel(int panelIndex, const UString &mainPath, const UString &arcFormat, + bool needOpenArc, + bool &archiveIsOpened, bool &encrypted) +{ + 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; + + int id = 1000 + 100 * panelIndex; + + return Panels[panelIndex].Create(_window, _window, + id, path, arcFormat, &m_PanelCallbackImp[panelIndex], &AppState, + needOpenArc, + archiveIsOpened, encrypted); +} + + +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, ARRAY_SIZE(g_StandardButtons), s)) + return; + SetButtonText(commandID, g_ArchiveButtons, 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 != 0) + { + 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 < ARRAY_SIZE(g_ArchiveButtons); i++) + AddButton(_buttonsImageList, _toolBar, g_ArchiveButtons[i], ShowButtonsLables, LargeButtons); + if (ShowStandardToolbar) + for (i = 0; i < 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, bool &archiveIsOpened, bool &encrypted) +{ + _window.Attach(hwnd); + + #ifdef UNDER_CE + _commandBar.Create(g_hInstance, hwnd, 1); + #endif + + MyLoadMenu(); + + #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]; + bool archiveIsOpened2 = false; + bool encrypted2 = false; + UString path; + if (isMainPanel) + path = mainPath; + + RINOK(CreateOnePanel(panelIndex, path, arcFormat, + isMainPanel && needOpenArc, + archiveIsOpened2, encrypted2)); + + if (isMainPanel) + { + archiveIsOpened = archiveIsOpened2; + encrypted = encrypted2; + if (needOpenArc && !archiveIsOpened2) + return S_OK; + } + } + } + + SetFocusedPanel(LastFocusedPanel); + Panels[LastFocusedPanel].SetFocusToList(); + return S_OK; +} + + +HRESULT CApp::SwitchOnOffOnePanel() +{ + if (NumPanels == 1) + { + NumPanels++; + bool archiveIsOpened, encrypted; + RINOK(CreateOnePanel(1 - LastFocusedPanel, UString(), UString(), + false, // needOpenArc + archiveIsOpened, encrypted)); + 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 ReducePathToRealFileSystemPath(UString &path) +{ + unsigned prefixSize = GetRootPrefixSize(path); + + while (!path.IsEmpty()) + { + if (NFind::DoesDirExist(us2fs(path))) + { + NName::NormalizeDirPathPrefix(path); + break; + } + int pos = path.ReverseFind_PathSepar(); + if (pos < 0) + { + path.Empty(); + break; + } + path.DeleteFrom(pos + 1); + if ((unsigned)pos + 1 == prefixSize) + break; + path.DeleteFrom(pos); + } +} + +// returns: true, if such dir exists or is root +/* +static bool CheckFolderPath(const UString &path) +{ + UString pathReduced = path; + ReducePathToRealFileSystemPath(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) +{ + 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, int 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 &indices) +{ + UString info; + UInt64 numDirs, numFiles, filesSize, foldersSize; + numDirs = numFiles = filesSize = foldersSize = 0; + + unsigned i; + for (i = 0; i < indices.Size(); i++) + { + int 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 += " "; + int 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, int srcPanelIndex) +{ + 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 indices; + UString destPath; + bool useDestPanel = false; + + { + if (copyToSame) + { + int focusedItem = srcPanel._listView.GetFocusedItem(); + if (focusedItem < 0) + return; + int realIndex = srcPanel.GetRealItemIndex(focusedItem); + if (realIndex == kParentIndex) + return; + indices.Add(realIndex); + destPath = srcPanel.GetItemName(realIndex); + } + else + { + srcPanel.GetOperatedIndicesSmart(indices); + if (indices.Size() == 0) + return; + destPath = destPanel.GetFsPath(); + if (NumPanels == 1) + ReducePathToRealFileSystemPath(destPath); + } + } + + UStringVector copyFolders; + ReadCopyHistory(copyFolders); + + 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"Can not 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))) + { + DWORD lastError = ::GetLastError(); + srcPanel.MessageBox_Error_2Lines_Message_HRESULT(prefix, lastError); + return; + } + } + // bool isFolder = srcPanael.IsItem_Folder(indices[0]); + } + else + { + NName::NormalizeDirPathPrefix(destPath); + if (!CreateComplexDir(us2fs(destPath))) + { + DWORD lastError = ::GetLastError(); + 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, 0); + } + + 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(int srcPanelIndex) +{ + if (NumPanels <= 1) + return; + const CPanel &srcPanel = Panels[srcPanelIndex]; + CPanel &destPanel = Panels[1 - srcPanelIndex]; + destPanel.BindToPathAndRefresh(srcPanel._currentFolderPrefix); +} + +void CApp::OnSetSubFolder(int srcPanelIndex) +{ + if (NumPanels <= 1) + return; + const CPanel &srcPanel = Panels[srcPanelIndex]; + CPanel &destPanel = Panels[1 - srcPanelIndex]; + + int focusedItem = srcPanel._listView.GetFocusedItem(); + if (focusedItem < 0) + return; + int realIndex = srcPanel.GetRealItemIndex(focusedItem); + if (!srcPanel.IsItem_Folder(realIndex)) + return; + + // destPanel.BindToFolder(srcPanel._currentFolderPrefix + srcPanel.GetItemName(realIndex) + WCHAR_PATH_SEPARATOR); + + CMyComPtr newFolder; + if (realIndex == kParentIndex) + { + if (srcPanel._folder->BindToParentFolder(&newFolder) != S_OK) + return; + if (!newFolder) + { + const UString parentPrefix = srcPanel.GetParentDirPrefix(); + bool archiveIsOpened, encrypted; + destPanel.BindToPath(parentPrefix, UString(), archiveIsOpened, encrypted); + 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 = 0; + g_ToolTipBuffer.Empty(); + SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer); + g_ToolTipBufferSys = GetSystemString(g_ToolTipBuffer); + info->lpszText = (LPTSTR)(LPCTSTR)g_ToolTipBufferSys; + return; + } + #ifndef _UNICODE + if (pnmh->code == TTN_GETDISPINFOW) + { + LPNMTTDISPINFOW info = (LPNMTTDISPINFOW)pnmh; + info->hinst = 0; + g_ToolTipBuffer.Empty(); + SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer); + info->lpszText = (LPWSTR)(LPCWSTR)g_ToolTipBuffer; + 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); +} + +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 index 09d4e6372..fa8eeaa7d 100644 --- a/CPP/7zip/UI/FileManager/App.h +++ b/CPP/7zip/UI/FileManager/App.h @@ -1,370 +1,370 @@ -// App.h - -#ifndef __APP_H -#define __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; - -const int kMenuCmdID_Plugin_Start = 1000; // must be large them context menu IDs -const int kMenuCmdID_Toolbar_Start = 1500; - -enum -{ - kMenuCmdID_Toolbar_Add = kMenuCmdID_Toolbar_Start, - kMenuCmdID_Toolbar_Extract, - kMenuCmdID_Toolbar_Test, - kMenuCmdID_Toolbar_End -}; - -class CPanelCallbackImp: public CPanelCallback -{ - CApp *_app; - unsigned _index; -public: - void Init(CApp *app, unsigned index) - { - _app = app; - _index = index; - } - virtual void OnTab(); - virtual void SetFocusToPath(unsigned index); - virtual void OnCopy(bool move, bool copyToSame); - virtual void OnSetSameFolder(); - virtual void OnSetSubFolder(); - virtual void PanelWasFocused(); - virtual void DragBegin(); - virtual void DragEnd(); - virtual void RefreshTitle(bool always); -}; - -class CApp; - -class CDropTarget: - public IDropTarget, - public CMyUnknownImp -{ - CMyComPtr m_DataObject; - UStringVector m_SourcePaths; - int m_SelectionIndex; - bool m_DropIsAllowed; // = true, if data contain fillist - bool m_PanelDropIsAllowed; // = false, if current target_panel is source_panel. - // check it only if m_DropIsAllowed == true - int m_SubFolderIndex; - UString m_SubFolderName; - - CPanel *m_Panel; - bool m_IsAppTarget; // true, if we want to drop to app window (not to panel). - - bool m_SetPathIsOK; - - bool IsItSameDrive() const; - - void QueryGetData(IDataObject *dataObject); - bool IsFsFolderPath() const; - DWORD GetEffect(DWORD keyState, POINTL pt, DWORD allowedEffect); - void RemoveSelection(); - void PositionCursor(POINTL ptl); - UString GetTargetPath() const; - bool SetPath(bool enablePath) const; - bool SetPath(); - -public: - MY_UNKNOWN_IMP1_MT(IDropTarget) - STDMETHOD(DragEnter)(IDataObject * dataObject, DWORD keyState, POINTL pt, DWORD *effect); - STDMETHOD(DragOver)(DWORD keyState, POINTL pt, DWORD * effect); - STDMETHOD(DragLeave)(); - STDMETHOD(Drop)(IDataObject * dataObject, DWORD keyState, POINTL pt, DWORD *effect); - - CDropTarget(): - TargetPanelIndex(-1), - SrcPanelIndex(-1), - m_IsAppTarget(false), - m_Panel(0), - App(0), - m_PanelDropIsAllowed(false), - m_DropIsAllowed(false), - m_SelectionIndex(-1), - m_SubFolderIndex(-1), - m_SetPathIsOK(false) {} - - CApp *App; - int SrcPanelIndex; // index of D&D source_panel - int TargetPanelIndex; // what panel to use as target_panel of Application -}; - -class CApp -{ -public: - NWindows::CWindow _window; - bool ShowSystemMenu; - // 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 _dropTarget; - - UString LangString_N_SELECTED_ITEMS; - - void ReloadLang(); - - CApp(): _window(0), NumPanels(2), LastFocusedPanel(0), - AutoRefresh_Mode(true) - { - SetPanels_AutoRefresh_Mode(); - } - - void CreateDragTarget() - { - _dropTargetSpec = new CDropTarget(); - _dropTarget = _dropTargetSpec; - _dropTargetSpec->App = (this); - } - - void SetFocusedPanel(unsigned index) - { - LastFocusedPanel = index; - _dropTargetSpec->TargetPanelIndex = LastFocusedPanel; - } - - void DragBegin(unsigned panelIndex) - { - _dropTargetSpec->TargetPanelIndex = (NumPanels > 1) ? 1 - panelIndex : panelIndex; - _dropTargetSpec->SrcPanelIndex = panelIndex; - } - - void DragEnd() - { - _dropTargetSpec->TargetPanelIndex = LastFocusedPanel; - _dropTargetSpec->SrcPanelIndex = -1; - } - - - void OnCopy(bool move, bool copyToSame, int srcPanelIndex); - void OnSetSameFolder(int srcPanelIndex); - void OnSetSubFolder(int srcPanelIndex); - - HRESULT CreateOnePanel(int panelIndex, const UString &mainPath, const UString &arcFormat, bool needOpenArc, bool &archiveIsOpened, bool &encrypted); - HRESULT Create(HWND hwnd, const UString &mainPath, const UString &arcFormat, int xSizes[2], bool needOpenArc, bool &archiveIsOpened, bool &encrypted); - 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(); - 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 AutoRefresh_Mode; - 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(int index) { GetFocusedPanel().OpenBookmark(index); } - void SetBookmark(int index) { GetFocusedPanel().SetBookmark(index); } - - void ReloadToolbars(); - void ReadToolbar() - { - 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 +// App.h + +#ifndef __APP_H +#define __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; + +const int kMenuCmdID_Plugin_Start = 1000; // must be large them context menu IDs +const int kMenuCmdID_Toolbar_Start = 1500; + +enum +{ + kMenuCmdID_Toolbar_Add = kMenuCmdID_Toolbar_Start, + kMenuCmdID_Toolbar_Extract, + kMenuCmdID_Toolbar_Test, + kMenuCmdID_Toolbar_End +}; + +class CPanelCallbackImp: public CPanelCallback +{ + CApp *_app; + unsigned _index; +public: + void Init(CApp *app, unsigned index) + { + _app = app; + _index = index; + } + virtual void OnTab(); + virtual void SetFocusToPath(unsigned index); + virtual void OnCopy(bool move, bool copyToSame); + virtual void OnSetSameFolder(); + virtual void OnSetSubFolder(); + virtual void PanelWasFocused(); + virtual void DragBegin(); + virtual void DragEnd(); + virtual void RefreshTitle(bool always); +}; + +class CApp; + +class CDropTarget: + public IDropTarget, + public CMyUnknownImp +{ + CMyComPtr m_DataObject; + UStringVector m_SourcePaths; + int m_SelectionIndex; + bool m_DropIsAllowed; // = true, if data contain fillist + bool m_PanelDropIsAllowed; // = false, if current target_panel is source_panel. + // check it only if m_DropIsAllowed == true + int m_SubFolderIndex; + UString m_SubFolderName; + + CPanel *m_Panel; + bool m_IsAppTarget; // true, if we want to drop to app window (not to panel). + + bool m_SetPathIsOK; + + bool IsItSameDrive() const; + + void QueryGetData(IDataObject *dataObject); + bool IsFsFolderPath() const; + DWORD GetEffect(DWORD keyState, POINTL pt, DWORD allowedEffect); + void RemoveSelection(); + void PositionCursor(POINTL ptl); + UString GetTargetPath() const; + bool SetPath(bool enablePath) const; + bool SetPath(); + +public: + MY_UNKNOWN_IMP1_MT(IDropTarget) + STDMETHOD(DragEnter)(IDataObject * dataObject, DWORD keyState, POINTL pt, DWORD *effect); + STDMETHOD(DragOver)(DWORD keyState, POINTL pt, DWORD * effect); + STDMETHOD(DragLeave)(); + STDMETHOD(Drop)(IDataObject * dataObject, DWORD keyState, POINTL pt, DWORD *effect); + + CDropTarget(): + TargetPanelIndex(-1), + SrcPanelIndex(-1), + m_IsAppTarget(false), + m_Panel(0), + App(0), + m_PanelDropIsAllowed(false), + m_DropIsAllowed(false), + m_SelectionIndex(-1), + m_SubFolderIndex(-1), + m_SetPathIsOK(false) {} + + CApp *App; + int SrcPanelIndex; // index of D&D source_panel + int TargetPanelIndex; // what panel to use as target_panel of Application +}; + +class CApp +{ +public: + NWindows::CWindow _window; + bool ShowSystemMenu; + // 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 _dropTarget; + + UString LangString_N_SELECTED_ITEMS; + + void ReloadLang(); + + CApp(): _window(0), NumPanels(2), LastFocusedPanel(0), + AutoRefresh_Mode(true) + { + SetPanels_AutoRefresh_Mode(); + } + + void CreateDragTarget() + { + _dropTargetSpec = new CDropTarget(); + _dropTarget = _dropTargetSpec; + _dropTargetSpec->App = (this); + } + + void SetFocusedPanel(unsigned index) + { + LastFocusedPanel = index; + _dropTargetSpec->TargetPanelIndex = LastFocusedPanel; + } + + void DragBegin(unsigned panelIndex) + { + _dropTargetSpec->TargetPanelIndex = (NumPanels > 1) ? 1 - panelIndex : panelIndex; + _dropTargetSpec->SrcPanelIndex = panelIndex; + } + + void DragEnd() + { + _dropTargetSpec->TargetPanelIndex = LastFocusedPanel; + _dropTargetSpec->SrcPanelIndex = -1; + } + + + void OnCopy(bool move, bool copyToSame, int srcPanelIndex); + void OnSetSameFolder(int srcPanelIndex); + void OnSetSubFolder(int srcPanelIndex); + + HRESULT CreateOnePanel(int panelIndex, const UString &mainPath, const UString &arcFormat, bool needOpenArc, bool &archiveIsOpened, bool &encrypted); + HRESULT Create(HWND hwnd, const UString &mainPath, const UString &arcFormat, int xSizes[2], bool needOpenArc, bool &archiveIsOpened, bool &encrypted); + 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(); + 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 AutoRefresh_Mode; + 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(int index) { GetFocusedPanel().OpenBookmark(index); } + void SetBookmark(int index) { GetFocusedPanel().SetBookmark(index); } + + void ReloadToolbars(); + void ReadToolbar() + { + 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 index b020f91d1..cc8871505 100644 --- a/CPP/7zip/UI/FileManager/AppState.h +++ b/CPP/7zip/UI/FileManager/AppState.h @@ -1,95 +1,95 @@ -// AppState.h - -#ifndef __APP_STATE_H -#define __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 +// AppState.h + +#ifndef __APP_STATE_H +#define __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 d5c981c54..d8f9ebe80 100644 --- a/CPP/7zip/UI/FileManager/BrowseDialog.cpp +++ b/CPP/7zip/UI/FileManager/BrowseDialog.cpp @@ -1,1025 +1,1025 @@ -// BrowseDialog.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#include - -#ifndef UNDER_CE -#include "../../../Windows/CommonDialog.h" -#include "../../../Windows/Shell.h" -#endif - -#include "../../../Windows/FileName.h" -#include "../../../Windows/FileFind.h" - -#ifdef UNDER_CE -#include -#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 _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 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 + +#ifndef UNDER_CE +#include "../../../Windows/CommonDialog.h" +#include "../../../Windows/Shell.h" +#endif + +#include "../../../Windows/FileName.h" +#include "../../../Windows/FileFind.h" + +#ifdef UNDER_CE +#include +#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 _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 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; +} diff --git a/CPP/7zip/UI/FileManager/BrowseDialog.h b/CPP/7zip/UI/FileManager/BrowseDialog.h index be51085bf..957af2e25 100644 --- a/CPP/7zip/UI/FileManager/BrowseDialog.h +++ b/CPP/7zip/UI/FileManager/BrowseDialog.h @@ -1,21 +1,21 @@ -// 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 __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 diff --git a/CPP/7zip/UI/FileManager/BrowseDialog.rc b/CPP/7zip/UI/FileManager/BrowseDialog.rc index 66f46f32d..04a6ad617 100644 --- a/CPP/7zip/UI/FileManager/BrowseDialog.rc +++ b/CPP/7zip/UI/FileManager/BrowseDialog.rc @@ -1,25 +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 -} +#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 f211b7374..aff84ec9a 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 index daf9fe5e7..33197fc3b 100644 --- a/CPP/7zip/UI/FileManager/ClassDefs.cpp +++ b/CPP/7zip/UI/FileManager/ClassDefs.cpp @@ -1,11 +1,11 @@ -// ClassDefs.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#include "../../../Common/MyInitGuid.h" - -#include "../Agent/Agent.h" - -#include "MyWindowsNew.h" +// ClassDefs.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#include "../../../Common/MyInitGuid.h" + +#include "../Agent/Agent.h" + +#include "MyWindowsNew.h" diff --git a/CPP/7zip/UI/FileManager/ComboDialog.cpp b/CPP/7zip/UI/FileManager/ComboDialog.cpp index e846c5613..729743e87 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 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(); +} diff --git a/CPP/7zip/UI/FileManager/ComboDialog.h b/CPP/7zip/UI/FileManager/ComboDialog.h index 6869cff70..29b28b5b4 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 __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 diff --git a/CPP/7zip/UI/FileManager/ComboDialog.rc b/CPP/7zip/UI/FileManager/ComboDialog.rc index 1706ffe0f..fddb7484a 100644 --- a/CPP/7zip/UI/FileManager/ComboDialog.rc +++ b/CPP/7zip/UI/FileManager/ComboDialog.rc @@ -1,16 +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 +#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 98938b63b..a044797e4 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/CopyDialog.cpp b/CPP/7zip/UI/FileManager/CopyDialog.cpp index 83ad73f79..4b17110db 100644 --- a/CPP/7zip/UI/FileManager/CopyDialog.cpp +++ b/CPP/7zip/UI/FileManager/CopyDialog.cpp @@ -1,106 +1,106 @@ -// CopyDialog.cpp - -#include "StdAfx.h" - -#include "../../../Windows/FileName.h" - -#include "../../../Windows/Control/Static.h" - -#include "BrowseDialog.h" -#include "CopyDialog.h" - -#ifdef LANG -#include "LangUtils.h" -#endif - -using namespace NWindows; - -bool CCopyDialog::OnInit() -{ - #ifdef 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); - int y = ySize - my - by; - int x = xSize - mx - bx1; - - InvalidateRect(NULL); - - { - RECT r; - GetClientRectOfItem(IDB_COPY_SET_PATH, r); - 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)); - 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(int 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(); -} +// CopyDialog.cpp + +#include "StdAfx.h" + +#include "../../../Windows/FileName.h" + +#include "../../../Windows/Control/Static.h" + +#include "BrowseDialog.h" +#include "CopyDialog.h" + +#ifdef LANG +#include "LangUtils.h" +#endif + +using namespace NWindows; + +bool CCopyDialog::OnInit() +{ + #ifdef 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); + int y = ySize - my - by; + int x = xSize - mx - bx1; + + InvalidateRect(NULL); + + { + RECT r; + GetClientRectOfItem(IDB_COPY_SET_PATH, r); + 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)); + 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(int 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 index 67ddd50f2..30fde71f1 100644 --- a/CPP/7zip/UI/FileManager/CopyDialog.h +++ b/CPP/7zip/UI/FileManager/CopyDialog.h @@ -1,31 +1,31 @@ -// CopyDialog.h - -#ifndef __COPY_DIALOG_H -#define __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(); - virtual bool OnInit(); - virtual bool OnSize(WPARAM wParam, int xSize, int ySize); - void OnButtonSetPath(); - bool OnButtonClicked(int buttonID, HWND buttonHWND); -public: - UString Title; - UString Static; - UString Value; - UString Info; - UStringVector Strings; - - INT_PTR Create(HWND parentWindow = 0) { return CModalDialog::Create(IDD_COPY, parentWindow); } -}; - -#endif +// CopyDialog.h + +#ifndef __COPY_DIALOG_H +#define __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(); + virtual bool OnInit(); + virtual bool OnSize(WPARAM wParam, int xSize, int ySize); + void OnButtonSetPath(); + bool OnButtonClicked(int buttonID, HWND buttonHWND); +public: + UString Title; + UString Static; + UString Value; + UString Info; + UStringVector Strings; + + INT_PTR Create(HWND parentWindow = 0) { return CModalDialog::Create(IDD_COPY, parentWindow); } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/CopyDialog.rc b/CPP/7zip/UI/FileManager/CopyDialog.rc index 378761f0d..73d3ea80d 100644 --- a/CPP/7zip/UI/FileManager/CopyDialog.rc +++ b/CPP/7zip/UI/FileManager/CopyDialog.rc @@ -1,20 +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 +#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 index c2e4da9de..85f5a39a4 100644 --- a/CPP/7zip/UI/FileManager/CopyDialogRes.h +++ b/CPP/7zip/UI/FileManager/CopyDialogRes.h @@ -1,8 +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 +#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/DialogSize.h b/CPP/7zip/UI/FileManager/DialogSize.h index bbce15982..504541bdf 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 __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 diff --git a/CPP/7zip/UI/FileManager/EditDialog.cpp b/CPP/7zip/UI/FileManager/EditDialog.cpp index 965c7b177..7f596722c 100644 --- a/CPP/7zip/UI/FileManager/EditDialog.cpp +++ b/CPP/7zip/UI/FileManager/EditDialog.cpp @@ -1,57 +1,57 @@ -// EditDialog.cpp - -#include "StdAfx.h" - -#include "EditDialog.h" - -#ifdef LANG -#include "LangUtils.h" -#endif - -bool CEditDialog::OnInit() -{ - #ifdef 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); - - int y = ySize - my - by; - 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; -} +// EditDialog.cpp + +#include "StdAfx.h" + +#include "EditDialog.h" + +#ifdef LANG +#include "LangUtils.h" +#endif + +bool CEditDialog::OnInit() +{ + #ifdef 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); + + int y = ySize - my - by; + 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 index b9cf08d65..d820516a5 100644 --- a/CPP/7zip/UI/FileManager/EditDialog.h +++ b/CPP/7zip/UI/FileManager/EditDialog.h @@ -1,25 +1,25 @@ -// EditDialog.h - -#ifndef __EDIT_DIALOG_H -#define __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(); - virtual bool OnSize(WPARAM wParam, int xSize, int ySize); -public: - UString Title; - UString Text; - - INT_PTR Create(HWND wndParent = 0) { return CModalDialog::Create(IDD_EDIT_DLG, wndParent); } - - CEditDialog() {} -}; - -#endif +// EditDialog.h + +#ifndef __EDIT_DIALOG_H +#define __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(); + virtual bool OnSize(WPARAM wParam, int xSize, int ySize); +public: + UString Title; + UString Text; + + INT_PTR Create(HWND wndParent = 0) { 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 index 40d19966d..cdb0b4450 100644 --- a/CPP/7zip/UI/FileManager/EditDialog.rc +++ b/CPP/7zip/UI/FileManager/EditDialog.rc @@ -1,15 +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 -} +#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 index 1bbcf916c..58c5ca911 100644 --- a/CPP/7zip/UI/FileManager/EditDialogRes.h +++ b/CPP/7zip/UI/FileManager/EditDialogRes.h @@ -1,2 +1,2 @@ -#define IDD_EDIT_DLG 94 -#define IDE_EDIT 100 +#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 index 87f394e47..0108904d6 100644 --- a/CPP/7zip/UI/FileManager/EditPage.cpp +++ b/CPP/7zip/UI/FileManager/EditPage.cpp @@ -1,147 +1,147 @@ -// 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; - -static const UInt32 kLangIDs[] = -{ - IDT_EDIT_EDITOR, - IDT_EDIT_DIFF -}; - -static const UInt32 kLangIDs_Colon[] = -{ - IDT_EDIT_VIEWER -}; - -#define kEditTopic "FM/options.htm#editor" - -bool CEditPage::OnInit() -{ - _initMode = true; - - LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); - LangSetDlgItems_Colon(*this, kLangIDs_Colon, ARRAY_SIZE(kLangIDs_Colon)); - - _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 ¶ms); - -static void Edit_BrowseForFile(NWindows::NControl::CEdit &edit, HWND hwnd) -{ - UString cmd; - edit.GetText(cmd); - - UString param; - UString prg; - - SplitCmdLineSmart(cmd, prg, param); - - UString resPath; - - if (MyBrowseForFile(hwnd, 0, prg, NULL, L"*.exe", resPath)) - { - resPath.Trim(); - cmd = resPath; - /* - if (!param.IsEmpty() && !resPath.IsEmpty()) - { - cmd.InsertAtFront(L'\"'); - cmd += L'\"'; - cmd.Add_Space(); - cmd += param; - } - */ - - edit.SetText(cmd); - // Changed(); - } -} - -bool CEditPage::OnButtonClicked(int 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(int code, int 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); -} +// 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; + +static const UInt32 kLangIDs[] = +{ + IDT_EDIT_EDITOR, + IDT_EDIT_DIFF +}; + +static const UInt32 kLangIDs_Colon[] = +{ + IDT_EDIT_VIEWER +}; + +#define kEditTopic "FM/options.htm#editor" + +bool CEditPage::OnInit() +{ + _initMode = true; + + LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); + LangSetDlgItems_Colon(*this, kLangIDs_Colon, ARRAY_SIZE(kLangIDs_Colon)); + + _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 ¶ms); + +static void Edit_BrowseForFile(NWindows::NControl::CEdit &edit, HWND hwnd) +{ + UString cmd; + edit.GetText(cmd); + + UString param; + UString prg; + + SplitCmdLineSmart(cmd, prg, param); + + UString resPath; + + if (MyBrowseForFile(hwnd, 0, prg, NULL, L"*.exe", resPath)) + { + resPath.Trim(); + cmd = resPath; + /* + if (!param.IsEmpty() && !resPath.IsEmpty()) + { + cmd.InsertAtFront(L'\"'); + cmd += L'\"'; + cmd.Add_Space(); + cmd += param; + } + */ + + edit.SetText(cmd); + // Changed(); + } +} + +bool CEditPage::OnButtonClicked(int 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(int code, int 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 index c94a1f7ed..208edd8de 100644 --- a/CPP/7zip/UI/FileManager/EditPage.h +++ b/CPP/7zip/UI/FileManager/EditPage.h @@ -1,30 +1,30 @@ -// EditPage.h - -#ifndef __EDIT_PAGE_H -#define __EDIT_PAGE_H - -#include "../../../Windows/Control/PropertyPage.h" -#include "../../../Windows/Control/Edit.h" - -struct CEditPageCtrl -{ - NWindows::NControl::CEdit Edit; - bool WasChanged; - int Ctrl; - int Button; -}; - -class CEditPage: public NWindows::NControl::CPropertyPage -{ - CEditPageCtrl _ctrls[3]; - - bool _initMode; -public: - virtual bool OnInit(); - virtual void OnNotifyHelp(); - virtual bool OnCommand(int code, int itemID, LPARAM param); - virtual LONG OnApply(); - virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); -}; - -#endif +// EditPage.h + +#ifndef __EDIT_PAGE_H +#define __EDIT_PAGE_H + +#include "../../../Windows/Control/PropertyPage.h" +#include "../../../Windows/Control/Edit.h" + +struct CEditPageCtrl +{ + NWindows::NControl::CEdit Edit; + bool WasChanged; + int Ctrl; + int Button; +}; + +class CEditPage: public NWindows::NControl::CPropertyPage +{ + CEditPageCtrl _ctrls[3]; + + bool _initMode; +public: + virtual bool OnInit(); + virtual void OnNotifyHelp(); + virtual bool OnCommand(int code, int itemID, LPARAM param); + virtual LONG OnApply(); + virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/EditPage.rc b/CPP/7zip/UI/FileManager/EditPage.rc index 9b05fab83..38f74ea18 100644 --- a/CPP/7zip/UI/FileManager/EditPage.rc +++ b/CPP/7zip/UI/FileManager/EditPage.rc @@ -1,19 +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 +#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 index 1c175fadb..2d6554fbb 100644 --- a/CPP/7zip/UI/FileManager/EditPage2.rc +++ b/CPP/7zip/UI/FileManager/EditPage2.rc @@ -1,14 +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 -} +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 index 4baf6801f..017d7024f 100644 --- a/CPP/7zip/UI/FileManager/EditPageRes.h +++ b/CPP/7zip/UI/FileManager/EditPageRes.h @@ -1,15 +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 +#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 index 240198f74..cba9aa21a 100644 --- a/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp +++ b/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp @@ -1,108 +1,108 @@ -// EnumFormatEtc.cpp - -#include "StdAfx.h" - -#include "EnumFormatEtc.h" -#include "MyCom2.h" - -class CEnumFormatEtc : -public IEnumFORMATETC, -public CMyUnknownImp -{ -public: - MY_UNKNOWN_IMP1_MT(IEnumFORMATETC) - - STDMETHOD(Next)(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched); - STDMETHOD(Skip)(ULONG celt); - STDMETHOD(Reset)(void); - STDMETHOD(Clone)(IEnumFORMATETC **ppEnumFormatEtc); - - CEnumFormatEtc(const FORMATETC *pFormatEtc, ULONG numFormats); - ~CEnumFormatEtc(); - -private: - LONG m_RefCount; - ULONG m_NumFormats; - FORMATETC *m_Formats; - ULONG m_Index; -}; - -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; - } -} - -STDMETHODIMP CEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG *pceltFetched) -{ - ULONG copied = 0; - if (celt == 0 || pFormatEtc == 0) - return E_INVALIDARG; - while (m_Index < m_NumFormats && copied < celt) - { - DeepCopyFormatEtc(&pFormatEtc[copied], &m_Formats[m_Index]); - copied++; - m_Index++; - } - if (pceltFetched != 0) - *pceltFetched = copied; - return (copied == celt) ? S_OK : S_FALSE; -} - -STDMETHODIMP CEnumFormatEtc::Skip(ULONG celt) -{ - m_Index += celt; - return (m_Index <= m_NumFormats) ? S_OK : S_FALSE; -} - -STDMETHODIMP CEnumFormatEtc::Reset(void) -{ - m_Index = 0; - return S_OK; -} - -STDMETHODIMP 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 == 0 || enumFormat == 0) - return E_INVALIDARG; - *enumFormat = new CEnumFormatEtc(formats, numFormats); - return (*enumFormat) ? S_OK : E_OUTOFMEMORY; -} +// EnumFormatEtc.cpp + +#include "StdAfx.h" + +#include "EnumFormatEtc.h" +#include "MyCom2.h" + +class CEnumFormatEtc : +public IEnumFORMATETC, +public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP1_MT(IEnumFORMATETC) + + STDMETHOD(Next)(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched); + STDMETHOD(Skip)(ULONG celt); + STDMETHOD(Reset)(void); + STDMETHOD(Clone)(IEnumFORMATETC **ppEnumFormatEtc); + + CEnumFormatEtc(const FORMATETC *pFormatEtc, ULONG numFormats); + ~CEnumFormatEtc(); + +private: + LONG m_RefCount; + ULONG m_NumFormats; + FORMATETC *m_Formats; + ULONG m_Index; +}; + +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; + } +} + +STDMETHODIMP CEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG *pceltFetched) +{ + ULONG copied = 0; + if (celt == 0 || pFormatEtc == 0) + return E_INVALIDARG; + while (m_Index < m_NumFormats && copied < celt) + { + DeepCopyFormatEtc(&pFormatEtc[copied], &m_Formats[m_Index]); + copied++; + m_Index++; + } + if (pceltFetched != 0) + *pceltFetched = copied; + return (copied == celt) ? S_OK : S_FALSE; +} + +STDMETHODIMP CEnumFormatEtc::Skip(ULONG celt) +{ + m_Index += celt; + return (m_Index <= m_NumFormats) ? S_OK : S_FALSE; +} + +STDMETHODIMP CEnumFormatEtc::Reset(void) +{ + m_Index = 0; + return S_OK; +} + +STDMETHODIMP 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 == 0 || enumFormat == 0) + 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 index f1aed4973..6c476f1ae 100644 --- a/CPP/7zip/UI/FileManager/EnumFormatEtc.h +++ b/CPP/7zip/UI/FileManager/EnumFormatEtc.h @@ -1,10 +1,10 @@ -// EnumFormatEtc.h - -#ifndef __ENUMFORMATETC_H -#define __ENUMFORMATETC_H - -#include - -HRESULT CreateEnumFormatEtc(UINT numFormats, const FORMATETC *formats, IEnumFORMATETC **enumFormat); - -#endif +// EnumFormatEtc.h + +#ifndef __ENUMFORMATETC_H +#define __ENUMFORMATETC_H + +#include + +HRESULT CreateEnumFormatEtc(UINT numFormats, const FORMATETC *formats, IEnumFORMATETC **enumFormat); + +#endif diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.cpp b/CPP/7zip/UI/FileManager/ExtractCallback.cpp index f2305944d..1bc96ae37 100644 --- a/CPP/7zip/UI/FileManager/ExtractCallback.cpp +++ b/CPP/7zip/UI/FileManager/ExtractCallback.cpp @@ -1,1037 +1,1037 @@ -// 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 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 _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 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 diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.h b/CPP/7zip/UI/FileManager/ExtractCallback.h index a6d5ae3a4..6cd8d0aa8 100644 --- a/CPP/7zip/UI/FileManager/ExtractCallback.h +++ b/CPP/7zip/UI/FileManager/ExtractCallback.h @@ -1,328 +1,328 @@ -// 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 _outFileStream; -public: - CObjectVector 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 _hashStream; - IHashCalc *_hashCalc; // it's for stat in Test operation - #endif - -public: - - #ifndef _SFX - CVirtFileSystem *VirtFileSystemSpec; - CMyComPtr 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 __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 _outFileStream; +public: + CObjectVector 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 _hashStream; + IHashCalc *_hashCalc; // it's for stat in Test operation + #endif + +public: + + #ifndef _SFX + CVirtFileSystem *VirtFileSystemSpec; + CMyComPtr 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 diff --git a/CPP/7zip/UI/FileManager/FM.cpp b/CPP/7zip/UI/FileManager/FM.cpp index c89e9e784..3e7f104d7 100644 --- a/CPP/7zip/UI/FileManager/FM.cpp +++ b/CPP/7zip/UI/FileManager/FM.cpp @@ -1,1076 +1,1076 @@ -// FM.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#include - -#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 - -#define MENU_HEIGHT 26 - -bool g_RAM_Size_Defined; -bool g_LargePagesMode = false; -bool g_OpenArchive = false; - -static bool g_Maximized = false; - -UInt64 g_RAM_Size; - -#ifdef _WIN32 -HINSTANCE g_hInstance; -#endif - -HWND g_HWND; - -static UString g_MainPath; -static UString g_ArcFormat; - -// HRESULT LoadGlobalCodecs(); -void FreeGlobalCodecs(); - -#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_IsSmallScreen = false; - -bool g_LVN_ITEMACTIVATE_Support = true; -// LVN_ITEMACTIVATE replaces both NM_DBLCLK & NM_RETURN -// Windows 2000 -// NT/98 + IE 3 (g_ComCtl32Version >= 4.70) - - -const int kNumDefaultPanels = 1; - -const int kSplitterWidth = 4; -int kSplitterRateMax = 1 << 16; -int kPanelSizeMin = 120; - -// bool OnMenuCommand(HWND hWnd, int id); - -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"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(0, 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; - - MyRegisterClass(&wc); - - // 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 = 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) - -bool g_Is_Wow64; - -typedef BOOL (WINAPI *Func_IsWow64Process)(HANDLE, PBOOL); - -static void Set_Wow64() -{ - g_Is_Wow64 = false; - Func_IsWow64Process fnIsWow64Process = (Func_IsWow64Process)GetProcAddress( - GetModuleHandleA("kernel32.dll"), "IsWow64Process"); - if (fnIsWow64Process) - { - BOOL isWow; - if (fnIsWow64Process(GetCurrentProcess(), &isWow)) - g_Is_Wow64 = (isWow != FALSE); - } -} - -#endif - - -bool IsLargePageSupported() -{ - #ifdef _WIN64 - return true; - #else - OSVERSIONINFO vi; - vi.dwOSVersionInfoSize = sizeof(vi); - if (!::GetVersionEx(&vi)) - return false; - if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) - return false; - if (vi.dwMajorVersion < 5) return false; - if (vi.dwMajorVersion > 5) return true; - if (vi.dwMinorVersion < 1) return false; - if (vi.dwMinorVersion > 1) return true; - // return g_Is_Wow64; - return false; - #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(); - } -} - -bool g_SymLink_Supported = false; - -static void Set_SymLink_Supported() -{ - g_SymLink_Supported = false; - OSVERSIONINFO vi; - vi.dwOSVersionInfoSize = sizeof(vi); - if (!::GetVersionEx(&vi)) - return; - if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT || vi.dwMajorVersion < 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(0, s, L"7-Zip", MB_ICONERROR); -} - -static void ErrorMessage(const char *s) -{ - ErrorMessage(GetUnicodeString(s)); -} - - -#define NT_CHECK_FAIL_ACTION ErrorMessage("Unsupported Windows version"); return 1; - -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 - SetLargePageSize(); - - #endif - - LoadLangOneTime(); - - 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(0, 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(0, 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.ReloadLang(); - - 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 = 0; - #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(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 = 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) -{ - int wmId, wmEvent; - switch (message) - { - case WM_COMMAND: - wmId = LOWORD(wParam); - 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, ARRAY_SIZE(tbb), - 0, 0, 100, 30, sizeof (TBBUTTON))); - */ - // HCURSOR cursor = ::LoadCursor(0, IDC_SIZEWE); - // ::SetCursor(cursor); - - if (g_PanelsInfoDefined) - g_Splitter.SetPos(hWnd, g_SplitterPos); - else - { - g_Splitter.SetRatio(hWnd, kSplitterRateMax / 2); - g_SplitterPos = g_Splitter.GetPos(); - } - - RECT rect; - ::GetClientRect(hWnd, &rect); - 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(); - - bool archiveIsOpened; - bool encrypted; - bool needOpenFile = 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(us2fs(fullPath))) - needOpenFile = true; - } - - HRESULT res = g_App.Create(hWnd, fullPath, g_ArcFormat, xSizes, - needOpenFile, - archiveIsOpened, encrypted); - - if (res == E_ABORT) - return -1; - - if (needOpenFile && !archiveIsOpened || res != S_OK) - { - UString m ("Error"); - if (res == S_FALSE || res == S_OK) - { - m = MyFormatNew(encrypted ? - IDS_CANT_OPEN_ENCRYPTED_ARCHIVE : - IDS_CANT_OPEN_ARCHIVE, - fullPath); - } - else if (res != S_OK) - m = HResultToMessage(res); - 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, 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 == 0) - 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); - } -} +// FM.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#include + +#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 + +#define MENU_HEIGHT 26 + +bool g_RAM_Size_Defined; +bool g_LargePagesMode = false; +bool g_OpenArchive = false; + +static bool g_Maximized = false; + +UInt64 g_RAM_Size; + +#ifdef _WIN32 +HINSTANCE g_hInstance; +#endif + +HWND g_HWND; + +static UString g_MainPath; +static UString g_ArcFormat; + +// HRESULT LoadGlobalCodecs(); +void FreeGlobalCodecs(); + +#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_IsSmallScreen = false; + +bool g_LVN_ITEMACTIVATE_Support = true; +// LVN_ITEMACTIVATE replaces both NM_DBLCLK & NM_RETURN +// Windows 2000 +// NT/98 + IE 3 (g_ComCtl32Version >= 4.70) + + +const int kNumDefaultPanels = 1; + +const int kSplitterWidth = 4; +int kSplitterRateMax = 1 << 16; +int kPanelSizeMin = 120; + +// bool OnMenuCommand(HWND hWnd, int id); + +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"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(0, 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; + + MyRegisterClass(&wc); + + // 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 = 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) + +bool g_Is_Wow64; + +typedef BOOL (WINAPI *Func_IsWow64Process)(HANDLE, PBOOL); + +static void Set_Wow64() +{ + g_Is_Wow64 = false; + Func_IsWow64Process fnIsWow64Process = (Func_IsWow64Process)GetProcAddress( + GetModuleHandleA("kernel32.dll"), "IsWow64Process"); + if (fnIsWow64Process) + { + BOOL isWow; + if (fnIsWow64Process(GetCurrentProcess(), &isWow)) + g_Is_Wow64 = (isWow != FALSE); + } +} + +#endif + + +bool IsLargePageSupported() +{ + #ifdef _WIN64 + return true; + #else + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + if (!::GetVersionEx(&vi)) + return false; + if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) + return false; + if (vi.dwMajorVersion < 5) return false; + if (vi.dwMajorVersion > 5) return true; + if (vi.dwMinorVersion < 1) return false; + if (vi.dwMinorVersion > 1) return true; + // return g_Is_Wow64; + return false; + #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(); + } +} + +bool g_SymLink_Supported = false; + +static void Set_SymLink_Supported() +{ + g_SymLink_Supported = false; + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + if (!::GetVersionEx(&vi)) + return; + if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT || vi.dwMajorVersion < 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(0, s, L"7-Zip", MB_ICONERROR); +} + +static void ErrorMessage(const char *s) +{ + ErrorMessage(GetUnicodeString(s)); +} + + +#define NT_CHECK_FAIL_ACTION ErrorMessage("Unsupported Windows version"); return 1; + +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 + SetLargePageSize(); + + #endif + + LoadLangOneTime(); + + 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(0, 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(0, 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.ReloadLang(); + + 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 = 0; + #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(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 = 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) +{ + int wmId, wmEvent; + switch (message) + { + case WM_COMMAND: + wmId = LOWORD(wParam); + 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, ARRAY_SIZE(tbb), + 0, 0, 100, 30, sizeof (TBBUTTON))); + */ + // HCURSOR cursor = ::LoadCursor(0, IDC_SIZEWE); + // ::SetCursor(cursor); + + if (g_PanelsInfoDefined) + g_Splitter.SetPos(hWnd, g_SplitterPos); + else + { + g_Splitter.SetRatio(hWnd, kSplitterRateMax / 2); + g_SplitterPos = g_Splitter.GetPos(); + } + + RECT rect; + ::GetClientRect(hWnd, &rect); + 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(); + + bool archiveIsOpened; + bool encrypted; + bool needOpenFile = 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(us2fs(fullPath))) + needOpenFile = true; + } + + HRESULT res = g_App.Create(hWnd, fullPath, g_ArcFormat, xSizes, + needOpenFile, + archiveIsOpened, encrypted); + + if (res == E_ABORT) + return -1; + + if (needOpenFile && !archiveIsOpened || res != S_OK) + { + UString m ("Error"); + if (res == S_FALSE || res == S_OK) + { + m = MyFormatNew(encrypted ? + IDS_CANT_OPEN_ENCRYPTED_ARCHIVE : + IDS_CANT_OPEN_ARCHIVE, + fullPath); + } + else if (res != S_OK) + m = HResultToMessage(res); + 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, 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 == 0) + 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 index 3c51f6a5b..69d285cb6 100644 --- a/CPP/7zip/UI/FileManager/FM.dsp +++ b/CPP/7zip/UI/FileManager/FM.dsp @@ -1,1615 +1,1615 @@ -# 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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS" /D "SUPPORT_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:\Program Files\7-ZIP\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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS" /D "SUPPORT_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:\Program Files\7-ZIP\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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS" /D "SUPPORT_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:\Program Files\7-ZIP\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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS" /D "SUPPORT_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:\Program Files\7-ZIP\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 -# 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\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\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\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\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\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\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 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 +# 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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS" /D "SUPPORT_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:\Program Files\7-ZIP\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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS" /D "SUPPORT_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:\Program Files\7-ZIP\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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS" /D "SUPPORT_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:\Program Files\7-ZIP\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 "LANG" /D "WIN_LONG_PATH" /D "NEW_FOLDER_INTERFACE" /D "EXTERNAL_CODECS" /D "SUPPORT_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:\Program Files\7-ZIP\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 +# 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\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\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\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\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\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\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 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 index 38f65d224..1c955d956 100644 --- a/CPP/7zip/UI/FileManager/FM.dsw +++ b/CPP/7zip/UI/FileManager/FM.dsw @@ -1,29 +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> -{{{ -}}} - -############################################################################### - +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.mak b/CPP/7zip/UI/FileManager/FM.mak index 493b4bbd4..654da627c 100644 --- a/CPP/7zip/UI/FileManager/FM.mak +++ b/CPP/7zip/UI/FileManager/FM.mak @@ -1,99 +1,99 @@ -CFLAGS = $(CFLAGS) \ - -DLANG \ - -DNEW_FOLDER_INTERFACE \ - -!IFDEF UNDER_CE -LIBS = $(LIBS) ceshell.lib Commctrl.lib -!ELSE -LIBS = $(LIBS) comctl32.lib htmlhelp.lib comdlg32.lib Mpr.lib Gdi32.lib -CFLAGS = $(CFLAGS) -DWIN_LONG_PATH -DSUPPORT_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\RegistryPlugins.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 \ - -!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 \ +CFLAGS = $(CFLAGS) \ + -DLANG \ + -DNEW_FOLDER_INTERFACE \ + +!IFDEF UNDER_CE +LIBS = $(LIBS) ceshell.lib Commctrl.lib +!ELSE +LIBS = $(LIBS) comctl32.lib htmlhelp.lib comdlg32.lib Mpr.lib Gdi32.lib +CFLAGS = $(CFLAGS) -DWIN_LONG_PATH -DSUPPORT_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\RegistryPlugins.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 \ + +!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 \ diff --git a/CPP/7zip/UI/FileManager/FSDrives.cpp b/CPP/7zip/UI/FileManager/FSDrives.cpp index 91b8ba90e..208cea4e6 100644 --- a/CPP/7zip/UI/FileManager/FSDrives.cpp +++ b/CPP/7zip/UI/FileManager/FSDrives.cpp @@ -1,494 +1,494 @@ -// 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(0) {} - ~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(); - if (fileSize == (UInt64)(Int64)-1) - { - if (!inFile.GetLength(fileSize)) - ::GetLastError(); - } - - NIO::COutFile outFile; - if (writeToDisk) - { - if (!outFile.Open(toPath, FILE_SHARE_WRITE, OPEN_EXISTING, 0)) - return GetLastError(); - } - else - if (!outFile.Create(toPath, true)) - return GetLastError(); - - 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(); - 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(); - 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" -}; - -STDMETHODIMP 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; -} - -STDMETHODIMP CFSDrives::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _drives.Size(); - return S_OK; -} - -STDMETHODIMP 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 = di.Name; break; - case kpidOutName: - if (!di.Name.IsEmpty() && di.Name.Back() == ':') - { - FString s = di.Name; - s.DeleteBack(); - AddExt(s, itemIndex); - prop = 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 < 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 = 0; - if (_volumeMode) - return S_OK; - NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder; - CMyComPtr subFolder = fsFolderSpec; - FString path; - if (_superMode) - path = kSuperPrefix; - path += name; - RINOK(fsFolderSpec->Init(path)); - *resultFolder = subFolder.Detach(); - return S_OK; -} - -STDMETHODIMP CFSDrives::BindToFolder(UInt32 index, IFolderFolder **resultFolder) -{ - *resultFolder = 0; - if (index >= (UInt32)_drives.Size()) - return E_INVALIDARG; - const CDriveInfo &di = _drives[index]; - /* - if (_volumeMode) - { - *resultFolder = 0; - CPhysDriveFolder *folderSpec = new CPhysDriveFolder; - CMyComPtr subFolder = folderSpec; - RINOK(folderSpec->Init(di.Name)); - *resultFolder = subFolder.Detach(); - return S_OK; - } - */ - return BindToFolderSpec(di.FullSystemName, resultFolder); -} - -STDMETHODIMP CFSDrives::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder) -{ - return BindToFolderSpec(us2fs(name), resultFolder); -} - -STDMETHODIMP CFSDrives::BindToParentFolder(IFolderFolder **resultFolder) -{ - *resultFolder = 0; - return S_OK; -} - -IMP_IFolderFolder_Props(CFSDrives) - -STDMETHODIMP 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 -} - - -STDMETHODIMP 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(); -} - -void CFSDrives::AddExt(FString &s, unsigned index) const -{ - s += '.'; - const CDriveInfo &di = _drives[index]; - const char *ext; - if (di.DriveType == DRIVE_CDROM) - ext = "iso"; - else if (di.FileSystemName.IsPrefixedBy_Ascii_NoCase("NTFS")) - ext = "ntfs"; - else if (di.FileSystemName.IsPrefixedBy_Ascii_NoCase("FAT")) - ext = "fat"; - else - ext = "img"; - s += ext; -} - -HRESULT CFSDrives::GetFileSize(unsigned index, UInt64 &fileSize) const -{ - NIO::CInFile inFile; - if (!inFile.Open(_drives[index].GetDeviceFileIoName())) - return GetLastError(); - if (!inFile.SizeDefined) - return E_FAIL; - fileSize = inFile.Size; - return S_OK; -} - -STDMETHODIMP 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))); - - static const UInt32 kBufferSize = (4 << 20); - 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; -} - -STDMETHODIMP CFSDrives::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */, - const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CFSDrives::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CFSDrives::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CFSDrives::CreateFile(const wchar_t * /* name */, IProgress * /* progress */) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CFSDrives::Rename(UInt32 /* index */, const wchar_t * /* newName */, IProgress * /* progress */) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CFSDrives::Delete(const UInt32 * /* indices */, UInt32 /* numItems */, IProgress * /* progress */) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CFSDrives::SetProperty(UInt32 /* index */, PROPID /* propID */, - const PROPVARIANT * /* value */, IProgress * /* progress */) -{ - return E_NOTIMPL; -} +// 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(0) {} + ~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(); + if (fileSize == (UInt64)(Int64)-1) + { + if (!inFile.GetLength(fileSize)) + ::GetLastError(); + } + + NIO::COutFile outFile; + if (writeToDisk) + { + if (!outFile.Open(toPath, FILE_SHARE_WRITE, OPEN_EXISTING, 0)) + return GetLastError(); + } + else + if (!outFile.Create(toPath, true)) + return GetLastError(); + + 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(); + 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(); + 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" +}; + +STDMETHODIMP 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; +} + +STDMETHODIMP CFSDrives::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _drives.Size(); + return S_OK; +} + +STDMETHODIMP 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 = di.Name; break; + case kpidOutName: + if (!di.Name.IsEmpty() && di.Name.Back() == ':') + { + FString s = di.Name; + s.DeleteBack(); + AddExt(s, itemIndex); + prop = 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 < 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 = 0; + if (_volumeMode) + return S_OK; + NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder; + CMyComPtr subFolder = fsFolderSpec; + FString path; + if (_superMode) + path = kSuperPrefix; + path += name; + RINOK(fsFolderSpec->Init(path)); + *resultFolder = subFolder.Detach(); + return S_OK; +} + +STDMETHODIMP CFSDrives::BindToFolder(UInt32 index, IFolderFolder **resultFolder) +{ + *resultFolder = 0; + if (index >= (UInt32)_drives.Size()) + return E_INVALIDARG; + const CDriveInfo &di = _drives[index]; + /* + if (_volumeMode) + { + *resultFolder = 0; + CPhysDriveFolder *folderSpec = new CPhysDriveFolder; + CMyComPtr subFolder = folderSpec; + RINOK(folderSpec->Init(di.Name)); + *resultFolder = subFolder.Detach(); + return S_OK; + } + */ + return BindToFolderSpec(di.FullSystemName, resultFolder); +} + +STDMETHODIMP CFSDrives::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder) +{ + return BindToFolderSpec(us2fs(name), resultFolder); +} + +STDMETHODIMP CFSDrives::BindToParentFolder(IFolderFolder **resultFolder) +{ + *resultFolder = 0; + return S_OK; +} + +IMP_IFolderFolder_Props(CFSDrives) + +STDMETHODIMP 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 +} + + +STDMETHODIMP 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(); +} + +void CFSDrives::AddExt(FString &s, unsigned index) const +{ + s += '.'; + const CDriveInfo &di = _drives[index]; + const char *ext; + if (di.DriveType == DRIVE_CDROM) + ext = "iso"; + else if (di.FileSystemName.IsPrefixedBy_Ascii_NoCase("NTFS")) + ext = "ntfs"; + else if (di.FileSystemName.IsPrefixedBy_Ascii_NoCase("FAT")) + ext = "fat"; + else + ext = "img"; + s += ext; +} + +HRESULT CFSDrives::GetFileSize(unsigned index, UInt64 &fileSize) const +{ + NIO::CInFile inFile; + if (!inFile.Open(_drives[index].GetDeviceFileIoName())) + return GetLastError(); + if (!inFile.SizeDefined) + return E_FAIL; + fileSize = inFile.Size; + return S_OK; +} + +STDMETHODIMP 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))); + + static const UInt32 kBufferSize = (4 << 20); + 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; +} + +STDMETHODIMP CFSDrives::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */, + const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CFSDrives::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CFSDrives::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CFSDrives::CreateFile(const wchar_t * /* name */, IProgress * /* progress */) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CFSDrives::Rename(UInt32 /* index */, const wchar_t * /* newName */, IProgress * /* progress */) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CFSDrives::Delete(const UInt32 * /* indices */, UInt32 /* numItems */, IProgress * /* progress */) +{ + return E_NOTIMPL; +} + +STDMETHODIMP 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 index 67f15e15a..f12e4da8e 100644 --- a/CPP/7zip/UI/FileManager/FSDrives.h +++ b/CPP/7zip/UI/FileManager/FSDrives.h @@ -1,59 +1,59 @@ -// FSDrives.h - -#ifndef __FS_DRIVES_H -#define __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) {} -}; - -class CFSDrives: - public IFolderFolder, - public IFolderOperations, - public IFolderGetSystemIconIndex, - public CMyUnknownImp -{ - CObjectVector _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: - MY_UNKNOWN_IMP2(IFolderGetSystemIconIndex, IFolderOperations) - - INTERFACE_FolderFolder(;) - INTERFACE_FolderOperations(;) - - STDMETHOD(GetSystemIconIndex)(UInt32 index, Int32 *iconIndex); - - void Init(bool volMode = false, bool superMode = false) - { - _volumeMode = volMode; - _superMode = superMode; - } -}; - -#endif +// FSDrives.h + +#ifndef __FS_DRIVES_H +#define __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) {} +}; + +class CFSDrives: + public IFolderFolder, + public IFolderOperations, + public IFolderGetSystemIconIndex, + public CMyUnknownImp +{ + CObjectVector _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: + MY_UNKNOWN_IMP2(IFolderGetSystemIconIndex, IFolderOperations) + + INTERFACE_FolderFolder(;) + INTERFACE_FolderOperations(;) + + STDMETHOD(GetSystemIconIndex)(UInt32 index, Int32 *iconIndex); + + 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 index 4fcec45fc..9e7202148 100644 --- a/CPP/7zip/UI/FileManager/FSFolder.cpp +++ b/CPP/7zip/UI/FileManager/FSFolder.cpp @@ -1,1105 +1,1105 @@ -// FSFolder.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/Defs.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/UTFConvert.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, - 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()) - { - DWORD lastError = GetLastError(); - 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); - CFileInfo fi; - while (enumerator.Next(fi)) - { - if (fi.IsDir()) - { - Path.DeleteFrom(len); - Path += fi.Name; - RINOK(Enumerate()); - NumFolders++; - } - else - { - NumFiles++; - Size += fi.Size; - } - } - return S_OK; -} - -#ifndef UNDER_CE - -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 WIN_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) -{ - 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; - #endif - - fi.PackSize = fi.Size; - 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 - - /* 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; - - unsigned endIndex = Folders.Size(); - for (unsigned i = startIndex; i < endIndex; i++) - LoadSubItems(i, Folders[i]); - return S_OK; -} - -STDMETHODIMP 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); - UInt32 processedSize; - file.Read(p, (UInt32)len, processedSize); - 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; -} - -STDMETHODIMP CFSFolder::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = Files.Size() /* + Streams.Size() */; - return S_OK; -} - -#ifdef USE_UNICODE_FSTRING - -STDMETHODIMP CFSFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len) -{ - *name = 0; - *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; -} - -STDMETHODIMP CFSFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len) -{ - *name = 0; - *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; -} - -STDMETHODIMP_(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; -} -#endif - -STDMETHODIMP 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; - - #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(pos); - prop = comment; - } - break; - } - case kpidPrefix: - if (fi.Parent >= 0) - prop = 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 ---------- - - -STDMETHODIMP CFSFolder::GetNumRawProps(UInt32 *numProps) -{ - *numProps = 1; - return S_OK; -} - -STDMETHODIMP CFSFolder::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) -{ - *name = NULL; - *propID = kpidNtReparse; - return S_OK; -} - -STDMETHODIMP CFSFolder::GetParent(UInt32 /* index */, UInt32 * /* parent */, UInt32 * /* parentType */) -{ - return E_FAIL; -} - -STDMETHODIMP CFSFolder::GetRawProp(UInt32 - #ifndef UNDER_CE - index - #endif - , PROPID - #ifndef UNDER_CE - propID - #endif - , const void **data, UInt32 *dataSize, UInt32 *propType) -{ - *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) -{ - int dotPos = name.ReverseFind_Dot(); - return name.Ptr((dotPos < 0) ? name.Len() : dotPos); -} - -STDMETHODIMP_(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: - { - 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 = 0; - CFSFolder *folderSpec = new CFSFolder; - CMyComPtr 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; -} - -STDMETHODIMP CFSFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder) -{ - *resultFolder = 0; - const CDirItem &fi = Files[index]; - if (!fi.IsDir()) - return E_INVALIDARG; - return BindToFolderSpec(GetRelPath(fi), resultFolder); -} - -STDMETHODIMP CFSFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder) -{ - return BindToFolderSpec(us2fs(name), resultFolder); -} - -STDMETHODIMP CFSFolder::BindToParentFolder(IFolderFolder **resultFolder) -{ - *resultFolder = 0; - /* - if (_parentFolder) - { - CMyComPtr 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 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(pos + 1); - - if (NName::IsDrivePath_SuperAllowed(parentPath)) - { - CFSFolder *parentFolderSpec = new CFSFolder; - CMyComPtr 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 netFolder = netFolderSpec; - netFolderSpec->Init(fs2us(parentPath)); - *resultFolder = netFolder.Detach(); - return S_OK; - } - */ - - #endif - - return S_OK; -} - -STDMETHODIMP CFSFolder::GetNumberOfProperties(UInt32 *numProperties) -{ - *numProperties = ARRAY_SIZE(kProps); - if (!_flatMode) - (*numProperties)--; - return S_OK; -} - -STDMETHODIMP CFSFolder::GetPropertyInfo IMP_IFolderFolder_GetProp(kProps) - -STDMETHODIMP 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 -} - -STDMETHODIMP 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; -} - -STDMETHODIMP CFSFolder::Clone(IFolderFolder **resultFolder) -{ - CFSFolder *fsFolderSpec = new CFSFolder; - CMyComPtr folderNew = fsFolderSpec; - fsFolderSpec->Init(_path); - *resultFolder = folderNew.Detach(); - return S_OK; -} - -HRESULT CFSFolder::GetItemsFullSize(const UInt32 *indices, UInt32 numItems, CFsFolderStat &stat) -{ - for (UInt32 i = 0; i < numItems; i++) - { - UInt32 index = indices[i]; - /* - if (index >= Files.Size()) - { - size += Streams[index - Files.Size()].Size; - // numFiles++; - continue; - } - */ - const CDirItem &fi = Files[index]; - if (fi.IsDir()) - { - stat.Path = _path; - stat.Path += GetRelPath(fi); - RINOK(stat.Enumerate()); - stat.NumFolders++; - } - else - { - stat.NumFiles++; - stat.Size += fi.Size; - } - } - 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; -} - -STDMETHODIMP 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; -} -*/ - -STDMETHODIMP 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); -} - -STDMETHODIMP CFSFolder::CreateFolder(const wchar_t *name, IProgress * /* progress */) -{ - FString absPath; - GetAbsPath(name, absPath); - if (CreateDir(absPath)) - return S_OK; - if (::GetLastError() == ERROR_ALREADY_EXISTS) - return ::GetLastError(); - if (!CreateComplexDir(absPath)) - return ::GetLastError(); - return S_OK; -} - -STDMETHODIMP CFSFolder::CreateFile(const wchar_t *name, IProgress * /* progress */) -{ - FString absPath; - GetAbsPath(name, absPath); - NIO::COutFile outFile; - if (!outFile.Create(absPath, false)) - return ::GetLastError(); - return S_OK; -} - -STDMETHODIMP 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(); - return S_OK; -} - -STDMETHODIMP 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(); - UInt64 completed = i; - RINOK(progress->SetCompleted(&completed)); - } - return S_OK; -} - -STDMETHODIMP 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; -} - -STDMETHODIMP 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(); -} - -STDMETHODIMP CFSFolder::SetFlatMode(Int32 flatMode) -{ - _flatMode = IntToBool(flatMode); - return S_OK; -} - -/* -STDMETHODIMP CFSFolder::SetShowNtfsStreamsMode(Int32 showStreamsMode) -{ - _scanAltStreams = IntToBool(showStreamsMode); - return S_OK; -} -*/ - -} +// FSFolder.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/Defs.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.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, + 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()) + { + DWORD lastError = GetLastError(); + 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); + CFileInfo fi; + while (enumerator.Next(fi)) + { + if (fi.IsDir()) + { + Path.DeleteFrom(len); + Path += fi.Name; + RINOK(Enumerate()); + NumFolders++; + } + else + { + NumFiles++; + Size += fi.Size; + } + } + return S_OK; +} + +#ifndef UNDER_CE + +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 WIN_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) +{ + 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; + #endif + + fi.PackSize = fi.Size; + 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 + + /* 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; + + unsigned endIndex = Folders.Size(); + for (unsigned i = startIndex; i < endIndex; i++) + LoadSubItems(i, Folders[i]); + return S_OK; +} + +STDMETHODIMP 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); + UInt32 processedSize; + file.Read(p, (UInt32)len, processedSize); + 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; +} + +STDMETHODIMP CFSFolder::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = Files.Size() /* + Streams.Size() */; + return S_OK; +} + +#ifdef USE_UNICODE_FSTRING + +STDMETHODIMP CFSFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len) +{ + *name = 0; + *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; +} + +STDMETHODIMP CFSFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len) +{ + *name = 0; + *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; +} + +STDMETHODIMP_(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; +} +#endif + +STDMETHODIMP 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; + + #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(pos); + prop = comment; + } + break; + } + case kpidPrefix: + if (fi.Parent >= 0) + prop = 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 ---------- + + +STDMETHODIMP CFSFolder::GetNumRawProps(UInt32 *numProps) +{ + *numProps = 1; + return S_OK; +} + +STDMETHODIMP CFSFolder::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) +{ + *name = NULL; + *propID = kpidNtReparse; + return S_OK; +} + +STDMETHODIMP CFSFolder::GetParent(UInt32 /* index */, UInt32 * /* parent */, UInt32 * /* parentType */) +{ + return E_FAIL; +} + +STDMETHODIMP CFSFolder::GetRawProp(UInt32 + #ifndef UNDER_CE + index + #endif + , PROPID + #ifndef UNDER_CE + propID + #endif + , const void **data, UInt32 *dataSize, UInt32 *propType) +{ + *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) +{ + int dotPos = name.ReverseFind_Dot(); + return name.Ptr((dotPos < 0) ? name.Len() : dotPos); +} + +STDMETHODIMP_(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: + { + 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 = 0; + CFSFolder *folderSpec = new CFSFolder; + CMyComPtr 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; +} + +STDMETHODIMP CFSFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder) +{ + *resultFolder = 0; + const CDirItem &fi = Files[index]; + if (!fi.IsDir()) + return E_INVALIDARG; + return BindToFolderSpec(GetRelPath(fi), resultFolder); +} + +STDMETHODIMP CFSFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder) +{ + return BindToFolderSpec(us2fs(name), resultFolder); +} + +STDMETHODIMP CFSFolder::BindToParentFolder(IFolderFolder **resultFolder) +{ + *resultFolder = 0; + /* + if (_parentFolder) + { + CMyComPtr 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 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(pos + 1); + + if (NName::IsDrivePath_SuperAllowed(parentPath)) + { + CFSFolder *parentFolderSpec = new CFSFolder; + CMyComPtr 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 netFolder = netFolderSpec; + netFolderSpec->Init(fs2us(parentPath)); + *resultFolder = netFolder.Detach(); + return S_OK; + } + */ + + #endif + + return S_OK; +} + +STDMETHODIMP CFSFolder::GetNumberOfProperties(UInt32 *numProperties) +{ + *numProperties = ARRAY_SIZE(kProps); + if (!_flatMode) + (*numProperties)--; + return S_OK; +} + +STDMETHODIMP CFSFolder::GetPropertyInfo IMP_IFolderFolder_GetProp(kProps) + +STDMETHODIMP 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 +} + +STDMETHODIMP 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; +} + +STDMETHODIMP CFSFolder::Clone(IFolderFolder **resultFolder) +{ + CFSFolder *fsFolderSpec = new CFSFolder; + CMyComPtr folderNew = fsFolderSpec; + fsFolderSpec->Init(_path); + *resultFolder = folderNew.Detach(); + return S_OK; +} + +HRESULT CFSFolder::GetItemsFullSize(const UInt32 *indices, UInt32 numItems, CFsFolderStat &stat) +{ + for (UInt32 i = 0; i < numItems; i++) + { + UInt32 index = indices[i]; + /* + if (index >= Files.Size()) + { + size += Streams[index - Files.Size()].Size; + // numFiles++; + continue; + } + */ + const CDirItem &fi = Files[index]; + if (fi.IsDir()) + { + stat.Path = _path; + stat.Path += GetRelPath(fi); + RINOK(stat.Enumerate()); + stat.NumFolders++; + } + else + { + stat.NumFiles++; + stat.Size += fi.Size; + } + } + 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; +} + +STDMETHODIMP 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; +} +*/ + +STDMETHODIMP 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); +} + +STDMETHODIMP CFSFolder::CreateFolder(const wchar_t *name, IProgress * /* progress */) +{ + FString absPath; + GetAbsPath(name, absPath); + if (CreateDir(absPath)) + return S_OK; + if (::GetLastError() == ERROR_ALREADY_EXISTS) + return ::GetLastError(); + if (!CreateComplexDir(absPath)) + return ::GetLastError(); + return S_OK; +} + +STDMETHODIMP CFSFolder::CreateFile(const wchar_t *name, IProgress * /* progress */) +{ + FString absPath; + GetAbsPath(name, absPath); + NIO::COutFile outFile; + if (!outFile.Create(absPath, false)) + return ::GetLastError(); + return S_OK; +} + +STDMETHODIMP 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(); + return S_OK; +} + +STDMETHODIMP 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(); + UInt64 completed = i; + RINOK(progress->SetCompleted(&completed)); + } + return S_OK; +} + +STDMETHODIMP 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; +} + +STDMETHODIMP 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(); +} + +STDMETHODIMP CFSFolder::SetFlatMode(Int32 flatMode) +{ + _flatMode = IntToBool(flatMode); + return S_OK; +} + +/* +STDMETHODIMP 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 index 9c3fafaf4..a7d78993c 100644 --- a/CPP/7zip/UI/FileManager/FSFolder.h +++ b/CPP/7zip/UI/FileManager/FSFolder.h @@ -1,215 +1,215 @@ -// FSFolder.h - -#ifndef __FS_FOLDER_H -#define __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 - -struct CDirItem: public NWindows::NFile::NFind::CFileInfo -{ - #ifndef UNDER_CE - UInt64 PackSize; - #endif - - #ifdef FS_SHOW_LINKS_INFO - UInt64 FileIndex; - UInt32 NumLinks; - bool FileInfo_Defined; - bool FileInfo_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: - 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 -{ -public: - MY_QUERYINTERFACE_BEGIN2(IFolderFolder) - MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps) - MY_QUERYINTERFACE_ENTRY(IFolderCompare) - #ifdef USE_UNICODE_FSTRING - MY_QUERYINTERFACE_ENTRY(IFolderGetItemName) - #endif - MY_QUERYINTERFACE_ENTRY(IFolderWasChanged) - // MY_QUERYINTERFACE_ENTRY(IFolderOperationsDeleteToRecycleBin) - MY_QUERYINTERFACE_ENTRY(IFolderOperations) - MY_QUERYINTERFACE_ENTRY(IFolderCalcItemFullSize) - MY_QUERYINTERFACE_ENTRY(IFolderClone) - MY_QUERYINTERFACE_ENTRY(IFolderGetSystemIconIndex) - MY_QUERYINTERFACE_ENTRY(IFolderSetFlatMode) - // MY_QUERYINTERFACE_ENTRY(IFolderSetShowNtfsStreamsMode) - MY_QUERYINTERFACE_END - MY_ADDREF_RELEASE - - - INTERFACE_FolderFolder(;) - INTERFACE_IArchiveGetRawProps(;) - INTERFACE_FolderOperations(;) - - STDMETHOD_(Int32, CompareItems)(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw); - - #ifdef USE_UNICODE_FSTRING - INTERFACE_IFolderGetItemName(;) - #endif - STDMETHOD(WasChanged)(Int32 *wasChanged); - STDMETHOD(Clone)(IFolderFolder **resultFolder); - STDMETHOD(CalcItemFullSize)(UInt32 index, IProgress *progress); - - STDMETHOD(SetFlatMode)(Int32 flatMode); - // STDMETHOD(SetShowNtfsStreamsMode)(Int32 showStreamsMode); - - STDMETHOD(GetSystemIconIndex)(UInt32 index, Int32 *iconIndex); - -private: - FString _path; - - CObjectVector Files; - FStringVector Folders; - // CObjectVector Streams; - // CMyComPtr _parentFolder; - - bool _commentsAreLoaded; - CPairsStorage _comments; - - // bool _scanAltStreams; - bool _flatMode; - - #ifdef _WIN32 - NWindows::NFile::NFind::CFindChangeNotification _findChangeNotification; - #endif - - HRESULT GetItemsFullSize(const UInt32 *indices, UInt32 numItems, CFsFolderStat &stat); - - 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); - #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(): DeleteSrcFile(false), TotalSize(0), StartPos(0) {} - - HRESULT MyCopyFile(CFSTR inPath, CFSTR outPath, DWORD attrib = INVALID_FILE_ATTRIBUTES); -}; - -HRESULT SendLastErrorMessage(IFolderOperationsExtractCallback *callback, const FString &fileName); - -} - -#endif +// FSFolder.h + +#ifndef __FS_FOLDER_H +#define __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 + +struct CDirItem: public NWindows::NFile::NFind::CFileInfo +{ + #ifndef UNDER_CE + UInt64 PackSize; + #endif + + #ifdef FS_SHOW_LINKS_INFO + UInt64 FileIndex; + UInt32 NumLinks; + bool FileInfo_Defined; + bool FileInfo_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: + 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 +{ +public: + MY_QUERYINTERFACE_BEGIN2(IFolderFolder) + MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps) + MY_QUERYINTERFACE_ENTRY(IFolderCompare) + #ifdef USE_UNICODE_FSTRING + MY_QUERYINTERFACE_ENTRY(IFolderGetItemName) + #endif + MY_QUERYINTERFACE_ENTRY(IFolderWasChanged) + // MY_QUERYINTERFACE_ENTRY(IFolderOperationsDeleteToRecycleBin) + MY_QUERYINTERFACE_ENTRY(IFolderOperations) + MY_QUERYINTERFACE_ENTRY(IFolderCalcItemFullSize) + MY_QUERYINTERFACE_ENTRY(IFolderClone) + MY_QUERYINTERFACE_ENTRY(IFolderGetSystemIconIndex) + MY_QUERYINTERFACE_ENTRY(IFolderSetFlatMode) + // MY_QUERYINTERFACE_ENTRY(IFolderSetShowNtfsStreamsMode) + MY_QUERYINTERFACE_END + MY_ADDREF_RELEASE + + + INTERFACE_FolderFolder(;) + INTERFACE_IArchiveGetRawProps(;) + INTERFACE_FolderOperations(;) + + STDMETHOD_(Int32, CompareItems)(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw); + + #ifdef USE_UNICODE_FSTRING + INTERFACE_IFolderGetItemName(;) + #endif + STDMETHOD(WasChanged)(Int32 *wasChanged); + STDMETHOD(Clone)(IFolderFolder **resultFolder); + STDMETHOD(CalcItemFullSize)(UInt32 index, IProgress *progress); + + STDMETHOD(SetFlatMode)(Int32 flatMode); + // STDMETHOD(SetShowNtfsStreamsMode)(Int32 showStreamsMode); + + STDMETHOD(GetSystemIconIndex)(UInt32 index, Int32 *iconIndex); + +private: + FString _path; + + CObjectVector Files; + FStringVector Folders; + // CObjectVector Streams; + // CMyComPtr _parentFolder; + + bool _commentsAreLoaded; + CPairsStorage _comments; + + // bool _scanAltStreams; + bool _flatMode; + + #ifdef _WIN32 + NWindows::NFile::NFind::CFindChangeNotification _findChangeNotification; + #endif + + HRESULT GetItemsFullSize(const UInt32 *indices, UInt32 numItems, CFsFolderStat &stat); + + 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); + #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(): DeleteSrcFile(false), TotalSize(0), StartPos(0) {} + + HRESULT MyCopyFile(CFSTR inPath, CFSTR outPath, DWORD attrib = INVALID_FILE_ATTRIBUTES); +}; + +HRESULT SendLastErrorMessage(IFolderOperationsExtractCallback *callback, const FString &fileName); + +} + +#endif diff --git a/CPP/7zip/UI/FileManager/FSFolderCopy.cpp b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp index 5be17faae..7f95b1d20 100644 --- a/CPP/7zip/UI/FileManager/FSFolderCopy.cpp +++ b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp @@ -1,670 +1,670 @@ -// FSFolderCopy.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#include - -#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 { - -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)); - } - } - } - - 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); - } - UInt64 completed = pi.StartPos + 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; - - 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 = (Func_CopyFileExA)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "CopyFileExA"); - } - else - #endif - { - HMODULE module = ::GetModuleHandleW( - #ifdef UNDER_CE - L"coredll.dll" - #else - L"kernel32.dll" - #endif - ); - my_CopyFileExW = (Func_CopyFileExW)My_GetProcAddress(module, "CopyFileExW"); - #ifndef UNDER_CE - my_MoveFileWithProgressW = (Func_MoveFileWithProgressW)My_GetProcAddress(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 WIN_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 WIN_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 ? - "can not move file onto itself" : - "can not 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, 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) -{ - return folderPath + FCHAR_PATH_SEPARATOR + fileName; -} - -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 ? - "can not copy folder onto itself" : - "can not 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, "can not 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, "can not remove folder", srcPath)); - return E_ABORT; - } - } - - return S_OK; -} - -STDMETHODIMP 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; - - 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; - } - - CFsFolderStat stat; - stat.Progress = callback; - RINOK(GetItemsFullSize(indices, numItems, stat)); - - 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.UseReadWriteMode = isAltDest; - state.Prepare(); - - for (UInt32 i = 0; i < numItems; i++) - { - 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()) - { - RINOK(CopyFolder(state, srcPath, destPath2)); - } - else - { - RINOK(CopyFile_Ask(state, srcPath, fi, destPath2)); - } - } - return S_OK; -} - -STDMETHODIMP CFSFolder::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */, - const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */) -{ - /* - UInt64 numFolders, numFiles, totalSize; - numFiles = numFolders = totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - UString path = (UString)fromFolderPath + itemsPaths[i]; - - CFileInfo fi; - if (!FindFile(path, fi)) - return ::GetLastError(); - if (fi.IsDir()) - { - UInt64 subFolders, subFiles, subSize; - RINOK(GetFolderSize(CombinePath(path, fi.Name), subFolders, subFiles, subSize, progress)); - numFolders += subFolders; - numFolders++; - numFiles += subFiles; - totalSize += subSize; - } - else - { - numFiles++; - totalSize += fi.Size; - } - } - RINOK(progress->SetTotal(totalSize)); - RINOK(callback->SetNumFiles(numFiles)); - for (i = 0; i < numItems; i++) - { - UString path = (UString)fromFolderPath + itemsPaths[i]; - } - return S_OK; - */ - return E_NOTIMPL; -} - -STDMETHODIMP CFSFolder::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */) -{ - return E_NOTIMPL; -} - -} +// FSFolderCopy.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#include + +#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 { + +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)); + } + } + } + + 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); + } + UInt64 completed = pi.StartPos + 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; + + 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 = (Func_CopyFileExA)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "CopyFileExA"); + } + else + #endif + { + HMODULE module = ::GetModuleHandleW( + #ifdef UNDER_CE + L"coredll.dll" + #else + L"kernel32.dll" + #endif + ); + my_CopyFileExW = (Func_CopyFileExW)My_GetProcAddress(module, "CopyFileExW"); + #ifndef UNDER_CE + my_MoveFileWithProgressW = (Func_MoveFileWithProgressW)My_GetProcAddress(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 WIN_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 WIN_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 ? + "can not move file onto itself" : + "can not 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, 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) +{ + return folderPath + FCHAR_PATH_SEPARATOR + fileName; +} + +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 ? + "can not copy folder onto itself" : + "can not 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, "can not 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, "can not remove folder", srcPath)); + return E_ABORT; + } + } + + return S_OK; +} + +STDMETHODIMP 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; + + 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; + } + + CFsFolderStat stat; + stat.Progress = callback; + RINOK(GetItemsFullSize(indices, numItems, stat)); + + 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.UseReadWriteMode = isAltDest; + state.Prepare(); + + for (UInt32 i = 0; i < numItems; i++) + { + 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()) + { + RINOK(CopyFolder(state, srcPath, destPath2)); + } + else + { + RINOK(CopyFile_Ask(state, srcPath, fi, destPath2)); + } + } + return S_OK; +} + +STDMETHODIMP CFSFolder::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */, + const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */) +{ + /* + UInt64 numFolders, numFiles, totalSize; + numFiles = numFolders = totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + UString path = (UString)fromFolderPath + itemsPaths[i]; + + CFileInfo fi; + if (!FindFile(path, fi)) + return ::GetLastError(); + if (fi.IsDir()) + { + UInt64 subFolders, subFiles, subSize; + RINOK(GetFolderSize(CombinePath(path, fi.Name), subFolders, subFiles, subSize, progress)); + numFolders += subFolders; + numFolders++; + numFiles += subFiles; + totalSize += subSize; + } + else + { + numFiles++; + totalSize += fi.Size; + } + } + RINOK(progress->SetTotal(totalSize)); + RINOK(callback->SetNumFiles(numFiles)); + for (i = 0; i < numItems; i++) + { + UString path = (UString)fromFolderPath + itemsPaths[i]; + } + return S_OK; + */ + return E_NOTIMPL; +} + +STDMETHODIMP 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 index 4cd444c6e..4e9646284 100644 --- a/CPP/7zip/UI/FileManager/FileFolderPluginOpen.cpp +++ b/CPP/7zip/UI/FileManager/FileFolderPluginOpen.cpp @@ -1,183 +1,183 @@ -// FileFolderPluginOpen.cpp - -#include "StdAfx.h" - -#include "resource.h" - -#include "../../../Windows/FileName.h" -#include "../../../Windows/Thread.h" - -#include "../Agent/Agent.h" - -#include "LangUtils.h" -#include "OpenCallback.h" -#include "PluginLoader.h" -#include "RegistryPlugins.h" - -using namespace NWindows; - -struct CThreadArchiveOpen -{ - UString Path; - UString ArcFormat; - CMyComPtr InStream; - CMyComPtr FolderManager; - CMyComPtr OpenCallback; - COpenArchiveCallback *OpenCallbackSpec; - - CMyComPtr Folder; - HRESULT Result; - - void Process() - { - try - { - CProgressCloser closer(OpenCallbackSpec->ProgressDialog); - Result = FolderManager->OpenFolderFile(InStream, Path, ArcFormat, &Folder, OpenCallback); - } - catch(...) { Result = E_FAIL; } - } - - static THREAD_FUNC_DECL MyThreadFunction(void *param) - { - ((CThreadArchiveOpen *)param)->Process(); - return 0; - } -}; - -/* -static int FindPlugin(const CObjectVector &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) -{ - int index = fullName.ReverseFind_Dot(); - if (index < 0) - { - pureName = fullName; - extensionDelimiter.Empty(); - extension.Empty(); - } - else - { - pureName.SetFrom(fullName, index); - extensionDelimiter = '.'; - extension = fullName.Ptr(index + 1); - } -} - -HRESULT OpenFileFolderPlugin( - IInStream *inStream, - const FString &path, - const UString &arcFormat, - HMODULE *module, - IFolderFolder **resultFolder, - HWND parentWindow, - bool &encrypted, UString &password) -{ - CObjectVector plugins; - ReadFileFolderPluginInfoList(plugins); - - FString extension, name, pureName, dot; - - int slashPos = path.ReverseFind_PathSepar(); - FString dirPrefix; - FString fileName; - if (slashPos >= 0) - { - dirPrefix.SetFrom(path, slashPos + 1); - fileName = path.Ptr(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); - } - } - } - } - */ - - FOR_VECTOR (i, plugins) - { - const CPluginInfo &plugin = plugins[i]; - if (!plugin.ClassIDDefined) - 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; - - t.OpenCallbackSpec = new COpenArchiveCallback; - t.OpenCallback = t.OpenCallbackSpec; - t.OpenCallbackSpec->PasswordIsDefined = encrypted; - t.OpenCallbackSpec->Password = password; - t.OpenCallbackSpec->ParentWindow = parentWindow; - - if (inStream) - t.OpenCallbackSpec->SetSubArchiveName(fs2us(fileName)); - else - t.OpenCallbackSpec->LoadFileInfo(dirPrefix, fileName); - - t.InStream = inStream; - t.Path = fs2us(path); - t.ArcFormat = arcFormat; - - UString progressTitle = LangString(IDS_OPENNING); - t.OpenCallbackSpec->ProgressDialog.MainWindow = parentWindow; - t.OpenCallbackSpec->ProgressDialog.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE); - t.OpenCallbackSpec->ProgressDialog.MainAddTitle = progressTitle + L' '; - t.OpenCallbackSpec->ProgressDialog.WaitMode = true; - - { - NWindows::CThread thread; - RINOK(thread.Create(CThreadArchiveOpen::MyThreadFunction, &t)); - t.OpenCallbackSpec->StartProgressDialog(progressTitle, thread); - } - - if (t.Result == E_ABORT) - return t.Result; - - encrypted = t.OpenCallbackSpec->PasswordIsDefined; - if (t.Result == S_OK) - { - // if (openCallbackSpec->PasswordWasAsked) - { - password = t.OpenCallbackSpec->Password; - } - *module = library.Detach(); - *resultFolder = t.Folder.Detach(); - return S_OK; - } - - if (t.Result != S_FALSE) - return t.Result; - } - return S_FALSE; -} +// FileFolderPluginOpen.cpp + +#include "StdAfx.h" + +#include "resource.h" + +#include "../../../Windows/FileName.h" +#include "../../../Windows/Thread.h" + +#include "../Agent/Agent.h" + +#include "LangUtils.h" +#include "OpenCallback.h" +#include "PluginLoader.h" +#include "RegistryPlugins.h" + +using namespace NWindows; + +struct CThreadArchiveOpen +{ + UString Path; + UString ArcFormat; + CMyComPtr InStream; + CMyComPtr FolderManager; + CMyComPtr OpenCallback; + COpenArchiveCallback *OpenCallbackSpec; + + CMyComPtr Folder; + HRESULT Result; + + void Process() + { + try + { + CProgressCloser closer(OpenCallbackSpec->ProgressDialog); + Result = FolderManager->OpenFolderFile(InStream, Path, ArcFormat, &Folder, OpenCallback); + } + catch(...) { Result = E_FAIL; } + } + + static THREAD_FUNC_DECL MyThreadFunction(void *param) + { + ((CThreadArchiveOpen *)param)->Process(); + return 0; + } +}; + +/* +static int FindPlugin(const CObjectVector &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) +{ + int index = fullName.ReverseFind_Dot(); + if (index < 0) + { + pureName = fullName; + extensionDelimiter.Empty(); + extension.Empty(); + } + else + { + pureName.SetFrom(fullName, index); + extensionDelimiter = '.'; + extension = fullName.Ptr(index + 1); + } +} + +HRESULT OpenFileFolderPlugin( + IInStream *inStream, + const FString &path, + const UString &arcFormat, + HMODULE *module, + IFolderFolder **resultFolder, + HWND parentWindow, + bool &encrypted, UString &password) +{ + CObjectVector plugins; + ReadFileFolderPluginInfoList(plugins); + + FString extension, name, pureName, dot; + + int slashPos = path.ReverseFind_PathSepar(); + FString dirPrefix; + FString fileName; + if (slashPos >= 0) + { + dirPrefix.SetFrom(path, slashPos + 1); + fileName = path.Ptr(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); + } + } + } + } + */ + + FOR_VECTOR (i, plugins) + { + const CPluginInfo &plugin = plugins[i]; + if (!plugin.ClassIDDefined) + 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; + + t.OpenCallbackSpec = new COpenArchiveCallback; + t.OpenCallback = t.OpenCallbackSpec; + t.OpenCallbackSpec->PasswordIsDefined = encrypted; + t.OpenCallbackSpec->Password = password; + t.OpenCallbackSpec->ParentWindow = parentWindow; + + if (inStream) + t.OpenCallbackSpec->SetSubArchiveName(fs2us(fileName)); + else + t.OpenCallbackSpec->LoadFileInfo(dirPrefix, fileName); + + t.InStream = inStream; + t.Path = fs2us(path); + t.ArcFormat = arcFormat; + + UString progressTitle = LangString(IDS_OPENNING); + t.OpenCallbackSpec->ProgressDialog.MainWindow = parentWindow; + t.OpenCallbackSpec->ProgressDialog.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE); + t.OpenCallbackSpec->ProgressDialog.MainAddTitle = progressTitle + L' '; + t.OpenCallbackSpec->ProgressDialog.WaitMode = true; + + { + NWindows::CThread thread; + RINOK(thread.Create(CThreadArchiveOpen::MyThreadFunction, &t)); + t.OpenCallbackSpec->StartProgressDialog(progressTitle, thread); + } + + if (t.Result == E_ABORT) + return t.Result; + + encrypted = t.OpenCallbackSpec->PasswordIsDefined; + if (t.Result == S_OK) + { + // if (openCallbackSpec->PasswordWasAsked) + { + password = t.OpenCallbackSpec->Password; + } + *module = library.Detach(); + *resultFolder = t.Folder.Detach(); + return S_OK; + } + + if (t.Result != S_FALSE) + return t.Result; + } + return S_FALSE; +} diff --git a/CPP/7zip/UI/FileManager/FileFolderPluginOpen.h b/CPP/7zip/UI/FileManager/FileFolderPluginOpen.h index 0d4ec39e2..593880e91 100644 --- a/CPP/7zip/UI/FileManager/FileFolderPluginOpen.h +++ b/CPP/7zip/UI/FileManager/FileFolderPluginOpen.h @@ -1,9 +1,9 @@ -// FileFolderPluginOpen.h - -#ifndef __FILE_FOLDER_PLUGIN_OPEN_H -#define __FILE_FOLDER_PLUGIN_OPEN_H - -HRESULT OpenFileFolderPlugin(IInStream *inStream, const FString &path, const UString &arcFormat, - HMODULE *module, IFolderFolder **resultFolder, HWND parentWindow, bool &encrypted, UString &password); - -#endif +// FileFolderPluginOpen.h + +#ifndef __FILE_FOLDER_PLUGIN_OPEN_H +#define __FILE_FOLDER_PLUGIN_OPEN_H + +HRESULT OpenFileFolderPlugin(IInStream *inStream, const FString &path, const UString &arcFormat, + HMODULE *module, IFolderFolder **resultFolder, HWND parentWindow, bool &encrypted, UString &password); + +#endif diff --git a/CPP/7zip/UI/FileManager/FilePlugins.cpp b/CPP/7zip/UI/FileManager/FilePlugins.cpp index 5d6ce1fb7..460003016 100644 --- a/CPP/7zip/UI/FileManager/FilePlugins.cpp +++ b/CPP/7zip/UI/FileManager/FilePlugins.cpp @@ -1,69 +1,69 @@ -// FilePlugins.cpp - -#include "StdAfx.h" - -#include "../Agent/Agent.h" - -#include "FilePlugins.h" -#include "PluginLoader.h" -#include "StringUtils.h" - -int CExtDatabase::FindExt(const UString &ext) -{ - FOR_VECTOR (i, Exts) - if (Exts[i].Ext.IsEqualTo_NoCase(ext)) - return i; - return -1; -} - -void CExtDatabase::Read() -{ - ReadFileFolderPluginInfoList(Plugins); - FOR_VECTOR (pluginIndex, Plugins) - { - const CPluginInfo &plugin = Plugins[pluginIndex]; - - CPluginLibrary pluginLib; - CMyComPtr folderManager; - - if (plugin.FilePath.IsEmpty()) - folderManager = new CArchiveFolderManager; - else 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 != 0) - { - plugPair.IconPath = (const wchar_t *)iconPath; - plugPair.IconIndex = iconIndex; - } - - 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); - } - } - } -} +// FilePlugins.cpp + +#include "StdAfx.h" + +#include "../Agent/Agent.h" + +#include "FilePlugins.h" +#include "PluginLoader.h" +#include "StringUtils.h" + +int CExtDatabase::FindExt(const UString &ext) +{ + FOR_VECTOR (i, Exts) + if (Exts[i].Ext.IsEqualTo_NoCase(ext)) + return i; + return -1; +} + +void CExtDatabase::Read() +{ + ReadFileFolderPluginInfoList(Plugins); + FOR_VECTOR (pluginIndex, Plugins) + { + const CPluginInfo &plugin = Plugins[pluginIndex]; + + CPluginLibrary pluginLib; + CMyComPtr folderManager; + + if (plugin.FilePath.IsEmpty()) + folderManager = new CArchiveFolderManager; + else 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 != 0) + { + plugPair.IconPath = (const wchar_t *)iconPath; + plugPair.IconIndex = iconIndex; + } + + 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 index 231d00eed..43b05f925 100644 --- a/CPP/7zip/UI/FileManager/FilePlugins.h +++ b/CPP/7zip/UI/FileManager/FilePlugins.h @@ -1,33 +1,33 @@ -// FilePlugins.h - -#ifndef __FILE_PLUGINS_H -#define __FILE_PLUGINS_H - -#include "RegistryPlugins.h" - -struct CPluginToIcon -{ - int PluginIndex; - UString IconPath; - int IconIndex; - - CPluginToIcon(): IconIndex(-1) {} -}; - -struct CExtPlugins -{ - UString Ext; - CObjectVector Plugins; -}; - -class CExtDatabase -{ - int FindExt(const UString &ext); -public: - CObjectVector Exts; - CObjectVector Plugins; - - void Read(); -}; - -#endif +// FilePlugins.h + +#ifndef __FILE_PLUGINS_H +#define __FILE_PLUGINS_H + +#include "RegistryPlugins.h" + +struct CPluginToIcon +{ + int PluginIndex; + UString IconPath; + int IconIndex; + + CPluginToIcon(): IconIndex(-1) {} +}; + +struct CExtPlugins +{ + UString Ext; + CObjectVector Plugins; +}; + +class CExtDatabase +{ + int FindExt(const UString &ext); +public: + CObjectVector Exts; + CObjectVector Plugins; + + void Read(); +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/FoldersPage.cpp b/CPP/7zip/UI/FileManager/FoldersPage.cpp index 8016cea35..d019bab8b 100644 --- a/CPP/7zip/UI/FileManager/FoldersPage.cpp +++ b/CPP/7zip/UI/FileManager/FoldersPage.cpp @@ -1,166 +1,166 @@ -// 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; - -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 -}; - -static const int kWorkModeButtons[] = -{ - IDR_FOLDERS_WORK_SYSTEM, - IDR_FOLDERS_WORK_CURRENT, - IDR_FOLDERS_WORK_SPECIFIED -}; - -#define kFoldersTopic "fm/options.htm#folders" - -static const unsigned kNumWorkModeButtons = ARRAY_SIZE(kWorkModeButtons); - -bool CFoldersPage::OnInit() -{ - _initMode = true; - _needSave = false; - - LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); - 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 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(int 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(int code, int 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); -} +// 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; + +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 +}; + +static const int kWorkModeButtons[] = +{ + IDR_FOLDERS_WORK_SYSTEM, + IDR_FOLDERS_WORK_CURRENT, + IDR_FOLDERS_WORK_SPECIFIED +}; + +#define kFoldersTopic "fm/options.htm#folders" + +static const unsigned kNumWorkModeButtons = ARRAY_SIZE(kWorkModeButtons); + +bool CFoldersPage::OnInit() +{ + _initMode = true; + _needSave = false; + + LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); + 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 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(int 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(int code, int 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 index fe2e64910..71c7bfce9 100644 --- a/CPP/7zip/UI/FileManager/FoldersPage.h +++ b/CPP/7zip/UI/FileManager/FoldersPage.h @@ -1,32 +1,32 @@ -// FoldersPage.h - -#ifndef __FOLDERS_PAGE_H -#define __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(); - virtual bool OnCommand(int code, int itemID, LPARAM lParam); - virtual void OnNotifyHelp(); - virtual LONG OnApply(); - virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); -}; - -#endif +// FoldersPage.h + +#ifndef __FOLDERS_PAGE_H +#define __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(); + virtual bool OnCommand(int code, int itemID, LPARAM lParam); + virtual void OnNotifyHelp(); + virtual LONG OnApply(); + virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/FoldersPage.rc b/CPP/7zip/UI/FileManager/FoldersPage.rc index 3b99bda41..cb345ea68 100644 --- a/CPP/7zip/UI/FileManager/FoldersPage.rc +++ b/CPP/7zip/UI/FileManager/FoldersPage.rc @@ -1,23 +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 +#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 index f4463af05..9b9276ef2 100644 --- a/CPP/7zip/UI/FileManager/FoldersPage2.rc +++ b/CPP/7zip/UI/FileManager/FoldersPage2.rc @@ -1,16 +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 +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 index 8049ec2fe..ba9ab73ef 100644 --- a/CPP/7zip/UI/FileManager/FoldersPageRes.h +++ b/CPP/7zip/UI/FileManager/FoldersPageRes.h @@ -1,12 +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 +#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 4f7ef74e5..2143c3f1b 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 f221cd233..993e80339 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 __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 diff --git a/CPP/7zip/UI/FileManager/HelpUtils.cpp b/CPP/7zip/UI/FileManager/HelpUtils.cpp index 917386fab..c0f579907 100644 --- a/CPP/7zip/UI/FileManager/HelpUtils.cpp +++ b/CPP/7zip/UI/FileManager/HelpUtils.cpp @@ -1,32 +1,32 @@ -// HelpUtils.cpp - -#include "StdAfx.h" - -#include "HelpUtils.h" - -#if defined(UNDER_CE) || !defined(_WIN32) - -void ShowHelpWindow(LPCSTR) -{ -} - -#else - -#include - -#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; - // HWND hwnd = NULL; - HtmlHelp(NULL, GetSystemString(fs2us(path)), HH_DISPLAY_TOPIC, 0); -} - -#endif +// HelpUtils.cpp + +#include "StdAfx.h" + +#include "HelpUtils.h" + +#if defined(UNDER_CE) || !defined(_WIN32) + +void ShowHelpWindow(LPCSTR) +{ +} + +#else + +#include + +#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; + // HWND hwnd = NULL; + HtmlHelp(NULL, GetSystemString(fs2us(path)), HH_DISPLAY_TOPIC, 0); +} + +#endif diff --git a/CPP/7zip/UI/FileManager/HelpUtils.h b/CPP/7zip/UI/FileManager/HelpUtils.h index 9945f44b4..90c5f7d10 100644 --- a/CPP/7zip/UI/FileManager/HelpUtils.h +++ b/CPP/7zip/UI/FileManager/HelpUtils.h @@ -1,10 +1,10 @@ -// HelpUtils.h - -#ifndef __HELP_UTILS_H -#define __HELP_UTILS_H - -#include "../../../Common/MyString.h" - -void ShowHelpWindow(LPCSTR topicFile); - -#endif +// HelpUtils.h + +#ifndef __HELP_UTILS_H +#define __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 index bb0c9fcb7..c5cff06ed 100644 --- a/CPP/7zip/UI/FileManager/IFolder.h +++ b/CPP/7zip/UI/FileManager/IFolder.h @@ -1,218 +1,218 @@ -// IFolder.h - -#ifndef __IFOLDER_H -#define __IFOLDER_H - -#include "../../IProgress.h" -#include "../../IStream.h" - -#define FOLDER_INTERFACE_SUB(i, b, x) DECL_INTERFACE_SUB(i, b, 8, x) -#define FOLDER_INTERFACE(i, x) FOLDER_INTERFACE_SUB(i, IUnknown, x) - -namespace NPlugin -{ - enum - { - kName = 0, - kType, - kClassID, - kOptionsClassID - }; -} - -#define INTERFACE_FolderFolder(x) \ - STDMETHOD(LoadItems)() x; \ - STDMETHOD(GetNumberOfItems)(UInt32 *numItems) x; \ - STDMETHOD(GetProperty)(UInt32 itemIndex, PROPID propID, PROPVARIANT *value) x; \ - STDMETHOD(BindToFolder)(UInt32 index, IFolderFolder **resultFolder) x; \ - STDMETHOD(BindToFolder)(const wchar_t *name, IFolderFolder **resultFolder) x; \ - STDMETHOD(BindToParentFolder)(IFolderFolder **resultFolder) x; \ - STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties) x; \ - STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \ - STDMETHOD(GetFolderProperty)(PROPID propID, PROPVARIANT *value) x; \ - -FOLDER_INTERFACE(IFolderFolder, 0x00) -{ - INTERFACE_FolderFolder(PURE) -}; - -/* - IFolderAltStreams:: - BindToAltStreams((UInt32)(Int32)-1, ... ) means alt streams of that folder -*/ - -#define INTERFACE_FolderAltStreams(x) \ - STDMETHOD(BindToAltStreams)(UInt32 index, IFolderFolder **resultFolder) x; \ - STDMETHOD(BindToAltStreams)(const wchar_t *name, IFolderFolder **resultFolder) x; \ - STDMETHOD(AreAltStreamsSupported)(UInt32 index, Int32 *isSupported) x; \ - -FOLDER_INTERFACE(IFolderAltStreams, 0x17) -{ - INTERFACE_FolderAltStreams(PURE) -}; - -FOLDER_INTERFACE(IFolderWasChanged, 0x04) -{ - STDMETHOD(WasChanged)(Int32 *wasChanged) PURE; -}; - -FOLDER_INTERFACE_SUB(IFolderOperationsExtractCallback, IProgress, 0x0B) -{ - // STDMETHOD(SetTotalFiles)(UInt64 total) PURE; - // STDMETHOD(SetCompletedFiles)(const UInt64 *completedValue) PURE; - STDMETHOD(AskWrite)( - const wchar_t *srcPath, - Int32 srcIsFolder, - const FILETIME *srcTime, - const UInt64 *srcSize, - const wchar_t *destPathRequest, - BSTR *destPathResult, - Int32 *writeAnswer) PURE; - STDMETHOD(ShowMessage)(const wchar_t *message) PURE; - STDMETHOD(SetCurrentFilePath)(const wchar_t *filePath) PURE; - STDMETHOD(SetNumFiles)(UInt64 numFiles) PURE; -}; - -#define INTERFACE_FolderOperations(x) \ - STDMETHOD(CreateFolder)(const wchar_t *name, IProgress *progress) x; \ - STDMETHOD(CreateFile)(const wchar_t *name, IProgress *progress) x; \ - STDMETHOD(Rename)(UInt32 index, const wchar_t *newName, IProgress *progress) x; \ - STDMETHOD(Delete)(const UInt32 *indices, UInt32 numItems, IProgress *progress) x; \ - STDMETHOD(CopyTo)(Int32 moveMode, const UInt32 *indices, UInt32 numItems, \ - Int32 includeAltStreams, Int32 replaceAltStreamCharsMode, \ - const wchar_t *path, IFolderOperationsExtractCallback *callback) x; \ - STDMETHOD(CopyFrom)(Int32 moveMode, const wchar_t *fromFolderPath, \ - const wchar_t * const *itemsPaths, UInt32 numItems, IProgress *progress) x; \ - STDMETHOD(SetProperty)(UInt32 index, PROPID propID, const PROPVARIANT *value, IProgress *progress) x; \ - STDMETHOD(CopyFromFile)(UInt32 index, const wchar_t *fullFilePath, IProgress *progress) x; \ - -FOLDER_INTERFACE(IFolderOperations, 0x13) -{ - INTERFACE_FolderOperations(PURE) -}; - -/* -FOLDER_INTERFACE2(IFolderOperationsDeleteToRecycleBin, 0x06, 0x03) -{ - STDMETHOD(DeleteToRecycleBin)(const UInt32 *indices, UInt32 numItems, IProgress *progress) PURE; -}; -*/ - -FOLDER_INTERFACE(IFolderGetSystemIconIndex, 0x07) -{ - STDMETHOD(GetSystemIconIndex)(UInt32 index, Int32 *iconIndex) PURE; -}; - -FOLDER_INTERFACE(IFolderGetItemFullSize, 0x08) -{ - STDMETHOD(GetItemFullSize)(UInt32 index, PROPVARIANT *value, IProgress *progress) PURE; -}; - -FOLDER_INTERFACE(IFolderCalcItemFullSize, 0x14) -{ - STDMETHOD(CalcItemFullSize)(UInt32 index, IProgress *progress) PURE; -}; - -FOLDER_INTERFACE(IFolderClone, 0x09) -{ - STDMETHOD(Clone)(IFolderFolder **resultFolder) PURE; -}; - -FOLDER_INTERFACE(IFolderSetFlatMode, 0x0A) -{ - STDMETHOD(SetFlatMode)(Int32 flatMode) PURE; -}; - -/* -FOLDER_INTERFACE(IFolderSetShowNtfsStreamsMode, 0xFA) -{ - STDMETHOD(SetShowNtfsStreamsMode)(Int32 showStreamsMode) PURE; -}; -*/ - -#define INTERFACE_FolderProperties(x) \ - STDMETHOD(GetNumberOfFolderProperties)(UInt32 *numProperties) x; \ - STDMETHOD(GetFolderPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \ - -FOLDER_INTERFACE(IFolderProperties, 0x0E) -{ - INTERFACE_FolderProperties(PURE) -}; - -#define INTERFACE_IFolderArcProps(x) \ - STDMETHOD(GetArcNumLevels)(UInt32 *numLevels) x; \ - STDMETHOD(GetArcProp)(UInt32 level, PROPID propID, PROPVARIANT *value) x; \ - STDMETHOD(GetArcNumProps)(UInt32 level, UInt32 *numProps) x; \ - STDMETHOD(GetArcPropInfo)(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \ - STDMETHOD(GetArcProp2)(UInt32 level, PROPID propID, PROPVARIANT *value) x; \ - STDMETHOD(GetArcNumProps2)(UInt32 level, UInt32 *numProps) x; \ - STDMETHOD(GetArcPropInfo2)(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \ - -FOLDER_INTERFACE(IFolderArcProps, 0x10) -{ - INTERFACE_IFolderArcProps(PURE) -}; - -FOLDER_INTERFACE(IGetFolderArcProps, 0x11) -{ - STDMETHOD(GetFolderArcProps)(IFolderArcProps **object) PURE; -}; - -FOLDER_INTERFACE(IFolderCompare, 0x15) -{ - STDMETHOD_(Int32, CompareItems)(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw) PURE; -}; - -#define INTERFACE_IFolderGetItemName(x) \ - STDMETHOD(GetItemName)(UInt32 index, const wchar_t **name, unsigned *len) x; \ - STDMETHOD(GetItemPrefix)(UInt32 index, const wchar_t **name, unsigned *len) x; \ - STDMETHOD_(UInt64, GetItemSize)(UInt32 index) x; \ - -FOLDER_INTERFACE(IFolderGetItemName, 0x16) -{ - INTERFACE_IFolderGetItemName(PURE) -}; - -#define FOLDER_MANAGER_INTERFACE(i, x) DECL_INTERFACE(i, 9, x) - -#define INTERFACE_IFolderManager(x) \ - STDMETHOD(OpenFolderFile)(IInStream *inStream, const wchar_t *filePath, const wchar_t *arcFormat, IFolderFolder **resultFolder, IProgress *progress) x; \ - STDMETHOD(GetExtensions)(BSTR *extensions) x; \ - STDMETHOD(GetIconPath)(const wchar_t *ext, BSTR *iconPath, Int32 *iconIndex) x; \ - - // STDMETHOD(GetTypes)(BSTR *types) PURE; - // STDMETHOD(CreateFolderFile)(const wchar_t *type, const wchar_t *filePath, IProgress *progress) PURE; - -FOLDER_MANAGER_INTERFACE(IFolderManager, 0x05) -{ - INTERFACE_IFolderManager(PURE); -}; - -/* -#define IMP_IFolderFolder_GetProp(k) \ - (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \ - { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \ - const CMy_STATPROPSTG_2 &srcItem = k[index]; \ - *propID = srcItem.propid; *varType = srcItem.vt; *name = 0; return S_OK; } \ - -#define IMP_IFolderFolder_Props(c) \ - STDMETHODIMP c::GetNumberOfProperties(UInt32 *numProperties) \ - { *numProperties = ARRAY_SIZE(kProps); return S_OK; } \ - STDMETHODIMP c::GetPropertyInfo IMP_IFolderFolder_GetProp(kProps) -*/ - -#define IMP_IFolderFolder_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; } \ - -#define IMP_IFolderFolder_Props(c) \ - STDMETHODIMP c::GetNumberOfProperties(UInt32 *numProperties) \ - { *numProperties = ARRAY_SIZE(kProps); return S_OK; } \ - STDMETHODIMP c::GetPropertyInfo IMP_IFolderFolder_GetProp(kProps) - - -int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2); -// int CompareFileNames_ForFolderList(const FChar *s1, const FChar *s2); - -#endif +// IFolder.h + +#ifndef __IFOLDER_H +#define __IFOLDER_H + +#include "../../IProgress.h" +#include "../../IStream.h" + +#define FOLDER_INTERFACE_SUB(i, b, x) DECL_INTERFACE_SUB(i, b, 8, x) +#define FOLDER_INTERFACE(i, x) FOLDER_INTERFACE_SUB(i, IUnknown, x) + +namespace NPlugin +{ + enum + { + kName = 0, + kType, + kClassID, + kOptionsClassID + }; +} + +#define INTERFACE_FolderFolder(x) \ + STDMETHOD(LoadItems)() x; \ + STDMETHOD(GetNumberOfItems)(UInt32 *numItems) x; \ + STDMETHOD(GetProperty)(UInt32 itemIndex, PROPID propID, PROPVARIANT *value) x; \ + STDMETHOD(BindToFolder)(UInt32 index, IFolderFolder **resultFolder) x; \ + STDMETHOD(BindToFolder)(const wchar_t *name, IFolderFolder **resultFolder) x; \ + STDMETHOD(BindToParentFolder)(IFolderFolder **resultFolder) x; \ + STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties) x; \ + STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \ + STDMETHOD(GetFolderProperty)(PROPID propID, PROPVARIANT *value) x; \ + +FOLDER_INTERFACE(IFolderFolder, 0x00) +{ + INTERFACE_FolderFolder(PURE) +}; + +/* + IFolderAltStreams:: + BindToAltStreams((UInt32)(Int32)-1, ... ) means alt streams of that folder +*/ + +#define INTERFACE_FolderAltStreams(x) \ + STDMETHOD(BindToAltStreams)(UInt32 index, IFolderFolder **resultFolder) x; \ + STDMETHOD(BindToAltStreams)(const wchar_t *name, IFolderFolder **resultFolder) x; \ + STDMETHOD(AreAltStreamsSupported)(UInt32 index, Int32 *isSupported) x; \ + +FOLDER_INTERFACE(IFolderAltStreams, 0x17) +{ + INTERFACE_FolderAltStreams(PURE) +}; + +FOLDER_INTERFACE(IFolderWasChanged, 0x04) +{ + STDMETHOD(WasChanged)(Int32 *wasChanged) PURE; +}; + +FOLDER_INTERFACE_SUB(IFolderOperationsExtractCallback, IProgress, 0x0B) +{ + // STDMETHOD(SetTotalFiles)(UInt64 total) PURE; + // STDMETHOD(SetCompletedFiles)(const UInt64 *completedValue) PURE; + STDMETHOD(AskWrite)( + const wchar_t *srcPath, + Int32 srcIsFolder, + const FILETIME *srcTime, + const UInt64 *srcSize, + const wchar_t *destPathRequest, + BSTR *destPathResult, + Int32 *writeAnswer) PURE; + STDMETHOD(ShowMessage)(const wchar_t *message) PURE; + STDMETHOD(SetCurrentFilePath)(const wchar_t *filePath) PURE; + STDMETHOD(SetNumFiles)(UInt64 numFiles) PURE; +}; + +#define INTERFACE_FolderOperations(x) \ + STDMETHOD(CreateFolder)(const wchar_t *name, IProgress *progress) x; \ + STDMETHOD(CreateFile)(const wchar_t *name, IProgress *progress) x; \ + STDMETHOD(Rename)(UInt32 index, const wchar_t *newName, IProgress *progress) x; \ + STDMETHOD(Delete)(const UInt32 *indices, UInt32 numItems, IProgress *progress) x; \ + STDMETHOD(CopyTo)(Int32 moveMode, const UInt32 *indices, UInt32 numItems, \ + Int32 includeAltStreams, Int32 replaceAltStreamCharsMode, \ + const wchar_t *path, IFolderOperationsExtractCallback *callback) x; \ + STDMETHOD(CopyFrom)(Int32 moveMode, const wchar_t *fromFolderPath, \ + const wchar_t * const *itemsPaths, UInt32 numItems, IProgress *progress) x; \ + STDMETHOD(SetProperty)(UInt32 index, PROPID propID, const PROPVARIANT *value, IProgress *progress) x; \ + STDMETHOD(CopyFromFile)(UInt32 index, const wchar_t *fullFilePath, IProgress *progress) x; \ + +FOLDER_INTERFACE(IFolderOperations, 0x13) +{ + INTERFACE_FolderOperations(PURE) +}; + +/* +FOLDER_INTERFACE2(IFolderOperationsDeleteToRecycleBin, 0x06, 0x03) +{ + STDMETHOD(DeleteToRecycleBin)(const UInt32 *indices, UInt32 numItems, IProgress *progress) PURE; +}; +*/ + +FOLDER_INTERFACE(IFolderGetSystemIconIndex, 0x07) +{ + STDMETHOD(GetSystemIconIndex)(UInt32 index, Int32 *iconIndex) PURE; +}; + +FOLDER_INTERFACE(IFolderGetItemFullSize, 0x08) +{ + STDMETHOD(GetItemFullSize)(UInt32 index, PROPVARIANT *value, IProgress *progress) PURE; +}; + +FOLDER_INTERFACE(IFolderCalcItemFullSize, 0x14) +{ + STDMETHOD(CalcItemFullSize)(UInt32 index, IProgress *progress) PURE; +}; + +FOLDER_INTERFACE(IFolderClone, 0x09) +{ + STDMETHOD(Clone)(IFolderFolder **resultFolder) PURE; +}; + +FOLDER_INTERFACE(IFolderSetFlatMode, 0x0A) +{ + STDMETHOD(SetFlatMode)(Int32 flatMode) PURE; +}; + +/* +FOLDER_INTERFACE(IFolderSetShowNtfsStreamsMode, 0xFA) +{ + STDMETHOD(SetShowNtfsStreamsMode)(Int32 showStreamsMode) PURE; +}; +*/ + +#define INTERFACE_FolderProperties(x) \ + STDMETHOD(GetNumberOfFolderProperties)(UInt32 *numProperties) x; \ + STDMETHOD(GetFolderPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \ + +FOLDER_INTERFACE(IFolderProperties, 0x0E) +{ + INTERFACE_FolderProperties(PURE) +}; + +#define INTERFACE_IFolderArcProps(x) \ + STDMETHOD(GetArcNumLevels)(UInt32 *numLevels) x; \ + STDMETHOD(GetArcProp)(UInt32 level, PROPID propID, PROPVARIANT *value) x; \ + STDMETHOD(GetArcNumProps)(UInt32 level, UInt32 *numProps) x; \ + STDMETHOD(GetArcPropInfo)(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \ + STDMETHOD(GetArcProp2)(UInt32 level, PROPID propID, PROPVARIANT *value) x; \ + STDMETHOD(GetArcNumProps2)(UInt32 level, UInt32 *numProps) x; \ + STDMETHOD(GetArcPropInfo2)(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \ + +FOLDER_INTERFACE(IFolderArcProps, 0x10) +{ + INTERFACE_IFolderArcProps(PURE) +}; + +FOLDER_INTERFACE(IGetFolderArcProps, 0x11) +{ + STDMETHOD(GetFolderArcProps)(IFolderArcProps **object) PURE; +}; + +FOLDER_INTERFACE(IFolderCompare, 0x15) +{ + STDMETHOD_(Int32, CompareItems)(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw) PURE; +}; + +#define INTERFACE_IFolderGetItemName(x) \ + STDMETHOD(GetItemName)(UInt32 index, const wchar_t **name, unsigned *len) x; \ + STDMETHOD(GetItemPrefix)(UInt32 index, const wchar_t **name, unsigned *len) x; \ + STDMETHOD_(UInt64, GetItemSize)(UInt32 index) x; \ + +FOLDER_INTERFACE(IFolderGetItemName, 0x16) +{ + INTERFACE_IFolderGetItemName(PURE) +}; + +#define FOLDER_MANAGER_INTERFACE(i, x) DECL_INTERFACE(i, 9, x) + +#define INTERFACE_IFolderManager(x) \ + STDMETHOD(OpenFolderFile)(IInStream *inStream, const wchar_t *filePath, const wchar_t *arcFormat, IFolderFolder **resultFolder, IProgress *progress) x; \ + STDMETHOD(GetExtensions)(BSTR *extensions) x; \ + STDMETHOD(GetIconPath)(const wchar_t *ext, BSTR *iconPath, Int32 *iconIndex) x; \ + + // STDMETHOD(GetTypes)(BSTR *types) PURE; + // STDMETHOD(CreateFolderFile)(const wchar_t *type, const wchar_t *filePath, IProgress *progress) PURE; + +FOLDER_MANAGER_INTERFACE(IFolderManager, 0x05) +{ + INTERFACE_IFolderManager(PURE); +}; + +/* +#define IMP_IFolderFolder_GetProp(k) \ + (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \ + { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \ + const CMy_STATPROPSTG_2 &srcItem = k[index]; \ + *propID = srcItem.propid; *varType = srcItem.vt; *name = 0; return S_OK; } \ + +#define IMP_IFolderFolder_Props(c) \ + STDMETHODIMP c::GetNumberOfProperties(UInt32 *numProperties) \ + { *numProperties = ARRAY_SIZE(kProps); return S_OK; } \ + STDMETHODIMP c::GetPropertyInfo IMP_IFolderFolder_GetProp(kProps) +*/ + +#define IMP_IFolderFolder_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; } \ + +#define IMP_IFolderFolder_Props(c) \ + STDMETHODIMP c::GetNumberOfProperties(UInt32 *numProperties) \ + { *numProperties = ARRAY_SIZE(kProps); return S_OK; } \ + STDMETHODIMP c::GetPropertyInfo IMP_IFolderFolder_GetProp(kProps) + + +int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2); +// int CompareFileNames_ForFolderList(const FChar *s1, const FChar *s2); + +#endif diff --git a/CPP/7zip/UI/FileManager/LangPage.cpp b/CPP/7zip/UI/FileManager/LangPage.cpp index df8fff9b8..47e7894cc 100644 --- a/CPP/7zip/UI/FileManager/LangPage.cpp +++ b/CPP/7zip/UI/FileManager/LangPage.cpp @@ -1,120 +1,120 @@ -// 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 UInt32 kLangIDs[] = -{ - IDT_LANG_LANG -}; - -#define kLangTopic "fm/options.htm#language" - -static void NativeLangString(UString &dest, const wchar_t *s) -{ - dest += " ("; - dest += s; - dest += ')'; -} - -bool LangOpen(CLang &lang, CFSTR fileName); - -bool CLangPage::OnInit() -{ - LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); - - _langCombo.Attach(GetItem(IDC_LANG_LANG)); - - UString temp = MyLoadString(IDS_LANG_ENGLISH); - NativeLangString(temp, MyLoadString(IDS_LANG_NATIVE)); - int index = (int)_langCombo.AddString(temp); - _langCombo.SetItemData(index, _paths.Size()); - _paths.Add(L"-"); - _langCombo.SetCurSel(0); - - const FString dirPrefix = GetLangDirPrefix(); - NFile::NFind::CEnumerator enumerator; - enumerator.SetDirPrefix(dirPrefix); - NFile::NFind::CFileInfo fi; - CLang lang; - UString error; - - 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)); - 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); - index = (int)_langCombo.AddString(s); - _langCombo.SetItemData(index, _paths.Size()); - _paths.Add(shortName); - if (g_LangID.IsEqualTo_NoCase(shortName)) - _langCombo.SetCurSel(index); - } - - if (!error.IsEmpty()) - MessageBoxW(0, error, L"Error in Lang file", MB_ICONERROR); - return CPropertyPage::OnInit(); -} - -LONG CLangPage::OnApply() -{ - int pathIndex = (int)_langCombo.GetItemData_of_CurSel(); - if (_needSave) - SaveRegLang(_paths[pathIndex]); - _needSave = false; - ReloadLang(); - LangWasChanged = true; - return PSNRET_NOERROR; -} - -void CLangPage::OnNotifyHelp() -{ - ShowHelpWindow(kLangTopic); -} - -bool CLangPage::OnCommand(int code, int itemID, LPARAM param) -{ - if (code == CBN_SELCHANGE && itemID == IDC_LANG_LANG) - { - _needSave = true; - Changed(); - return true; - } - return CPropertyPage::OnCommand(code, itemID, param); -} +// 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 UInt32 kLangIDs[] = +{ + IDT_LANG_LANG +}; + +#define kLangTopic "fm/options.htm#language" + +static void NativeLangString(UString &dest, const wchar_t *s) +{ + dest += " ("; + dest += s; + dest += ')'; +} + +bool LangOpen(CLang &lang, CFSTR fileName); + +bool CLangPage::OnInit() +{ + LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); + + _langCombo.Attach(GetItem(IDC_LANG_LANG)); + + UString temp = MyLoadString(IDS_LANG_ENGLISH); + NativeLangString(temp, MyLoadString(IDS_LANG_NATIVE)); + int index = (int)_langCombo.AddString(temp); + _langCombo.SetItemData(index, _paths.Size()); + _paths.Add(L"-"); + _langCombo.SetCurSel(0); + + const FString dirPrefix = GetLangDirPrefix(); + NFile::NFind::CEnumerator enumerator; + enumerator.SetDirPrefix(dirPrefix); + NFile::NFind::CFileInfo fi; + CLang lang; + UString error; + + 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)); + 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); + index = (int)_langCombo.AddString(s); + _langCombo.SetItemData(index, _paths.Size()); + _paths.Add(shortName); + if (g_LangID.IsEqualTo_NoCase(shortName)) + _langCombo.SetCurSel(index); + } + + if (!error.IsEmpty()) + MessageBoxW(0, error, L"Error in Lang file", MB_ICONERROR); + return CPropertyPage::OnInit(); +} + +LONG CLangPage::OnApply() +{ + int pathIndex = (int)_langCombo.GetItemData_of_CurSel(); + if (_needSave) + SaveRegLang(_paths[pathIndex]); + _needSave = false; + ReloadLang(); + LangWasChanged = true; + return PSNRET_NOERROR; +} + +void CLangPage::OnNotifyHelp() +{ + ShowHelpWindow(kLangTopic); +} + +bool CLangPage::OnCommand(int code, int itemID, LPARAM param) +{ + if (code == CBN_SELCHANGE && itemID == IDC_LANG_LANG) + { + _needSave = true; + Changed(); + return true; + } + return CPropertyPage::OnCommand(code, itemID, param); +} diff --git a/CPP/7zip/UI/FileManager/LangPage.h b/CPP/7zip/UI/FileManager/LangPage.h index 56226bd4f..b80625733 100644 --- a/CPP/7zip/UI/FileManager/LangPage.h +++ b/CPP/7zip/UI/FileManager/LangPage.h @@ -1,25 +1,25 @@ -// LangPage.h - -#ifndef __LANG_PAGE_H -#define __LANG_PAGE_H - -#include "../../../Windows/Control/PropertyPage.h" -#include "../../../Windows/Control/ComboBox.h" - -class CLangPage: public NWindows::NControl::CPropertyPage -{ - NWindows::NControl::CComboBox _langCombo; - UStringVector _paths; - - bool _needSave; -public: - bool LangWasChanged; - - CLangPage(): _needSave(false), LangWasChanged(false) {} - virtual bool OnInit(); - virtual void OnNotifyHelp(); - virtual bool OnCommand(int code, int itemID, LPARAM param); - virtual LONG OnApply(); -}; - -#endif +// LangPage.h + +#ifndef __LANG_PAGE_H +#define __LANG_PAGE_H + +#include "../../../Windows/Control/PropertyPage.h" +#include "../../../Windows/Control/ComboBox.h" + +class CLangPage: public NWindows::NControl::CPropertyPage +{ + NWindows::NControl::CComboBox _langCombo; + UStringVector _paths; + + bool _needSave; +public: + bool LangWasChanged; + + CLangPage(): _needSave(false), LangWasChanged(false) {} + virtual bool OnInit(); + virtual void OnNotifyHelp(); + virtual bool OnCommand(int code, int itemID, LPARAM param); + virtual LONG OnApply(); +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/LangPage.rc b/CPP/7zip/UI/FileManager/LangPage.rc index 479cf39ef..164e2d30b 100644 --- a/CPP/7zip/UI/FileManager/LangPage.rc +++ b/CPP/7zip/UI/FileManager/LangPage.rc @@ -1,37 +1,37 @@ -#include "LangPageRes.h" -#include "../../GuiCommon.rc" - -#define xc 160 -#define yc 100 - -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, xc, yc - 20, MY_COMBO_SORTED -} - - -#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_SORTED -} - -#endif - - -STRINGTABLE -BEGIN - IDS_LANG_ENGLISH "English" - IDS_LANG_NATIVE "English" -END +#include "LangPageRes.h" +#include "../../GuiCommon.rc" + +#define xc 160 +#define yc 100 + +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, xc, yc - 20, MY_COMBO_SORTED +} + + +#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_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 index d93b43a8c..d7a39d752 100644 --- a/CPP/7zip/UI/FileManager/LangPageRes.h +++ b/CPP/7zip/UI/FileManager/LangPageRes.h @@ -1,8 +1,8 @@ -#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 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 diff --git a/CPP/7zip/UI/FileManager/LangUtils.cpp b/CPP/7zip/UI/FileManager/LangUtils.cpp index 324dc3629..bcaa5f1eb 100644 --- a/CPP/7zip/UI/FileManager/LangUtils.cpp +++ b/CPP/7zip/UI/FileManager/LangUtils.cpp @@ -1,292 +1,292 @@ -// 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) -{ - return lang.Open(fileName, "7-Zip"); -} - -FString GetLangDirPrefix() -{ - return NDLL::GetModuleDirPrefix() + FTEXT("Lang") FSTRING_PATH_SEPARATOR; -} - -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, 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 < ARRAY_SIZE(kLangPairs); i++) - { - const CIDLangPair &pair = kLangPairs[i]; - CWindow window(GetDlgItem(dialog, pair.ControlID)); - if (window) - { - const wchar_t *s = g_Lang.Get(pair.LangID); - if (s) - window.SetText(s); - } - } - - for (i = 0; i < numItems; i++) - { - 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++) - { - UInt32 id = ids[i]; - const wchar_t *s = g_Lang.Get(id); - if (s) - { - CWindow window(GetDlgItem(dialog, id)); - UString s2 = s; - s2 += ':'; - 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.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)(); - -static void OpenDefaultLang() -{ - LANGID sysLang = GetSystemDefaultLangID(); // "Language for non-Unicode programs" in XP64 - LANGID userLang = GetUserDefaultLangID(); // "Standards and formats" language in XP64 - - if (sysLang != userLang) - return; - LANGID langID = userLang; - - /* - 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(); - */ - - WORD primLang = (WORD)(PRIMARYLANGID(langID)); - WORD subLang = (WORD)(SUBLANGID(langID)); - { - AStringVector names; - FindShortNames(primLang, names); - const FString dirPrefix (GetLangDirPrefix()); - for (unsigned i = 0; i < 2; i++) - { - 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.Find(FCHAR_PATH_SEPARATOR) < 0) - { - if (s.Find(FTEXT('.')) < 0) - s += ".txt"; - s.Insert(0, GetLangDirPrefix()); - } - LangOpen(g_Lang, s); - } -} +// 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) +{ + return lang.Open(fileName, "7-Zip"); +} + +FString GetLangDirPrefix() +{ + return NDLL::GetModuleDirPrefix() + FTEXT("Lang") FSTRING_PATH_SEPARATOR; +} + +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, 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 < ARRAY_SIZE(kLangPairs); i++) + { + const CIDLangPair &pair = kLangPairs[i]; + CWindow window(GetDlgItem(dialog, pair.ControlID)); + if (window) + { + const wchar_t *s = g_Lang.Get(pair.LangID); + if (s) + window.SetText(s); + } + } + + for (i = 0; i < numItems; i++) + { + 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++) + { + UInt32 id = ids[i]; + const wchar_t *s = g_Lang.Get(id); + if (s) + { + CWindow window(GetDlgItem(dialog, id)); + UString s2 = s; + s2 += ':'; + 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.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)(); + +static void OpenDefaultLang() +{ + LANGID sysLang = GetSystemDefaultLangID(); // "Language for non-Unicode programs" in XP64 + LANGID userLang = GetUserDefaultLangID(); // "Standards and formats" language in XP64 + + if (sysLang != userLang) + return; + LANGID langID = userLang; + + /* + 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(); + */ + + WORD primLang = (WORD)(PRIMARYLANGID(langID)); + WORD subLang = (WORD)(SUBLANGID(langID)); + { + AStringVector names; + FindShortNames(primLang, names); + const FString dirPrefix (GetLangDirPrefix()); + for (unsigned i = 0; i < 2; i++) + { + 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.Find(FCHAR_PATH_SEPARATOR) < 0) + { + if (s.Find(FTEXT('.')) < 0) + s += ".txt"; + s.Insert(0, GetLangDirPrefix()); + } + LangOpen(g_Lang, s); + } +} diff --git a/CPP/7zip/UI/FileManager/LangUtils.h b/CPP/7zip/UI/FileManager/LangUtils.h index c69442390..d63a443c6 100644 --- a/CPP/7zip/UI/FileManager/LangUtils.h +++ b/CPP/7zip/UI/FileManager/LangUtils.h @@ -1,40 +1,40 @@ -// 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 __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 diff --git a/CPP/7zip/UI/FileManager/LinkDialog.cpp b/CPP/7zip/UI/FileManager/LinkDialog.cpp index a87bf622c..ddef365c2 100644 --- a/CPP/7zip/UI/FileManager/LinkDialog.cpp +++ b/CPP/7zip/UI/FileManager/LinkDialog.cpp @@ -1,354 +1,354 @@ -// 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" - -#ifdef LANG -#include "LangUtils.h" -#endif - -#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 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 -}; -#endif - -static bool GetSymLink(CFSTR path, CReparseAttr &attr) -{ - NIO::CInFile file; - if (!file.Open(path, - FILE_SHARE_READ, - OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS)) - return false; - - 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; - - DWORD errorCode = 0; - if (!attr.Parse(buf, returnedSize, errorCode)) - return false; - - CByteBuffer data2; - if (!FillLinkData(data2, attr.GetPath(), attr.IsSymLink())) - return false; - - if (data2.Size() != returnedSize || - memcmp(data2, buf, returnedSize) != 0) - return false; - - return true; -} - -static const int k_LinkType_Buttons[] = -{ - IDR_LINK_TYPE_HARD, - IDR_LINK_TYPE_SYM_FILE, - IDR_LINK_TYPE_SYM_DIR, - IDR_LINK_TYPE_JUNCTION -}; - -void CLinkDialog::Set_LinkType_Radio(int idb) -{ - CheckRadioButton(k_LinkType_Buttons[0], k_LinkType_Buttons[ARRAY_SIZE(k_LinkType_Buttons) - 1], idb); -} - -bool CLinkDialog::OnInit() -{ - #ifdef LANG - LangSetWindowText(*this, IDD_LINK); - LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); - #endif - - _pathFromCombo.Attach(GetItem(IDC_LINK_PATH_FROM)); - _pathToCombo.Attach(GetItem(IDC_LINK_PATH_TO)); - - if (!FilePath.IsEmpty()) - { - NFind::CFileInfo fi; - int linkType = 0; - if (!fi.Find(us2fs(FilePath))) - linkType = IDR_LINK_TYPE_SYM_FILE; - else - { - if (fi.HasReparsePoint()) - { - CReparseAttr attr; - bool res = GetSymLink(us2fs(FilePath), attr); - - UString s = attr.PrintName; - if (!attr.IsOkNamePair()) - { - s += " : "; - s += attr.SubsName; - } - if (!res) - s.Insert(0, L"ERROR: "); - - SetItemText(IDT_LINK_PATH_TO_CUR, s); - - UString destPath = attr.GetPath(); - _pathFromCombo.SetText(FilePath); - _pathToCombo.SetText(destPath); - - if (res) - { - if (attr.IsMountPoint()) - linkType = IDR_LINK_TYPE_JUNCTION; - if (attr.IsSymLink()) - { - 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 - { - _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(int 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"; - 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); - - int idb = -1; - for (unsigned i = 0;; i++) - { - if (i >= ARRAY_SIZE(k_LinkType_Buttons)) - return; - idb = k_LinkType_Buttons[i]; - if (IsButtonCheckedBool(idb)) - break; - } - - NFind::CFileInfo info1, info2; - bool finded1 = info1.Find(us2fs(from)); - bool finded2 = info2.Find(us2fs(to)); - - bool isDirLink = ( - idb == IDR_LINK_TYPE_SYM_DIR || - idb == IDR_LINK_TYPE_JUNCTION); - - 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 - { - bool isSymLink = (idb != IDR_LINK_TYPE_JUNCTION); - - CByteBuffer data; - if (!FillLinkData(data, to, isSymLink)) - { - ShowError(L"Incorrect link"); - return; - } - - CReparseAttr attr; - DWORD errorCode = 0; - if (!attr.Parse(data, data.Size(), errorCode)) - { - ShowError(L"Internal conversion error"); - return; - } - - - if (!NIO::SetReparseData(us2fs(from), isDirLink, data, (DWORD)data.Size())) - { - ShowLastErrorMessage(); - return; - } - } - - End(IDOK); -} - -void CApp::Link() -{ - unsigned srcPanelIndex = GetFocusedPanelIndex(); - CPanel &srcPanel = Panels[srcPanelIndex]; - if (!srcPanel.IsFSFolder()) - { - srcPanel.MessageBox_Error_UnsupportOperation(); - return; - } - CRecordVector indices; - srcPanel.GetOperatedItemIndices(indices); - if (indices.IsEmpty()) - return; - if (indices.Size() != 1) - { - srcPanel.MessageBox_Error_LangID(IDS_SELECT_ONE_FILE); - return; - } - int index = indices[0]; - const UString itemName = srcPanel.GetItemName(index); - - const UString fsPrefix = srcPanel.GetFsPath(); - const UString srcPath = fsPrefix + 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(); - } - - CLinkDialog dlg; - dlg.CurDirPrefix = fsPrefix; - dlg.FilePath = srcPath + itemName; - dlg.AnotherPath = path; - - if (dlg.Create(srcPanel.GetParent()) != IDOK) - return; - - RefreshTitleAlways(); -} +// 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" + +#ifdef LANG +#include "LangUtils.h" +#endif + +#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 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 +}; +#endif + +static bool GetSymLink(CFSTR path, CReparseAttr &attr) +{ + NIO::CInFile file; + if (!file.Open(path, + FILE_SHARE_READ, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS)) + return false; + + 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; + + DWORD errorCode = 0; + if (!attr.Parse(buf, returnedSize, errorCode)) + return false; + + CByteBuffer data2; + if (!FillLinkData(data2, attr.GetPath(), attr.IsSymLink())) + return false; + + if (data2.Size() != returnedSize || + memcmp(data2, buf, returnedSize) != 0) + return false; + + return true; +} + +static const int k_LinkType_Buttons[] = +{ + IDR_LINK_TYPE_HARD, + IDR_LINK_TYPE_SYM_FILE, + IDR_LINK_TYPE_SYM_DIR, + IDR_LINK_TYPE_JUNCTION +}; + +void CLinkDialog::Set_LinkType_Radio(int idb) +{ + CheckRadioButton(k_LinkType_Buttons[0], k_LinkType_Buttons[ARRAY_SIZE(k_LinkType_Buttons) - 1], idb); +} + +bool CLinkDialog::OnInit() +{ + #ifdef LANG + LangSetWindowText(*this, IDD_LINK); + LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); + #endif + + _pathFromCombo.Attach(GetItem(IDC_LINK_PATH_FROM)); + _pathToCombo.Attach(GetItem(IDC_LINK_PATH_TO)); + + if (!FilePath.IsEmpty()) + { + NFind::CFileInfo fi; + int linkType = 0; + if (!fi.Find(us2fs(FilePath))) + linkType = IDR_LINK_TYPE_SYM_FILE; + else + { + if (fi.HasReparsePoint()) + { + CReparseAttr attr; + bool res = GetSymLink(us2fs(FilePath), attr); + + UString s = attr.PrintName; + if (!attr.IsOkNamePair()) + { + s += " : "; + s += attr.SubsName; + } + if (!res) + s.Insert(0, L"ERROR: "); + + SetItemText(IDT_LINK_PATH_TO_CUR, s); + + UString destPath = attr.GetPath(); + _pathFromCombo.SetText(FilePath); + _pathToCombo.SetText(destPath); + + if (res) + { + if (attr.IsMountPoint()) + linkType = IDR_LINK_TYPE_JUNCTION; + if (attr.IsSymLink()) + { + 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 + { + _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(int 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"; + 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); + + int idb = -1; + for (unsigned i = 0;; i++) + { + if (i >= ARRAY_SIZE(k_LinkType_Buttons)) + return; + idb = k_LinkType_Buttons[i]; + if (IsButtonCheckedBool(idb)) + break; + } + + NFind::CFileInfo info1, info2; + bool finded1 = info1.Find(us2fs(from)); + bool finded2 = info2.Find(us2fs(to)); + + bool isDirLink = ( + idb == IDR_LINK_TYPE_SYM_DIR || + idb == IDR_LINK_TYPE_JUNCTION); + + 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 + { + bool isSymLink = (idb != IDR_LINK_TYPE_JUNCTION); + + CByteBuffer data; + if (!FillLinkData(data, to, isSymLink)) + { + ShowError(L"Incorrect link"); + return; + } + + CReparseAttr attr; + DWORD errorCode = 0; + if (!attr.Parse(data, data.Size(), errorCode)) + { + ShowError(L"Internal conversion error"); + return; + } + + + if (!NIO::SetReparseData(us2fs(from), isDirLink, data, (DWORD)data.Size())) + { + ShowLastErrorMessage(); + return; + } + } + + End(IDOK); +} + +void CApp::Link() +{ + unsigned srcPanelIndex = GetFocusedPanelIndex(); + CPanel &srcPanel = Panels[srcPanelIndex]; + if (!srcPanel.IsFSFolder()) + { + srcPanel.MessageBox_Error_UnsupportOperation(); + return; + } + CRecordVector indices; + srcPanel.GetOperatedItemIndices(indices); + if (indices.IsEmpty()) + return; + if (indices.Size() != 1) + { + srcPanel.MessageBox_Error_LangID(IDS_SELECT_ONE_FILE); + return; + } + int index = indices[0]; + const UString itemName = srcPanel.GetItemName(index); + + const UString fsPrefix = srcPanel.GetFsPath(); + const UString srcPath = fsPrefix + 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(); + } + + CLinkDialog dlg; + dlg.CurDirPrefix = fsPrefix; + dlg.FilePath = srcPath + itemName; + dlg.AnotherPath = path; + + if (dlg.Create(srcPanel.GetParent()) != IDOK) + return; + + RefreshTitleAlways(); +} diff --git a/CPP/7zip/UI/FileManager/LinkDialog.h b/CPP/7zip/UI/FileManager/LinkDialog.h index c271205bf..56deec9db 100644 --- a/CPP/7zip/UI/FileManager/LinkDialog.h +++ b/CPP/7zip/UI/FileManager/LinkDialog.h @@ -1,34 +1,34 @@ -// LinkDialog.h - -#ifndef __LINK_DIALOG_H -#define __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(); - virtual bool OnSize(WPARAM wParam, int xSize, int ySize); - virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); - void OnButton_SetPath(bool to); - void OnButton_Link(); - - void ShowLastErrorMessage(); - void ShowError(const wchar_t *s); - void Set_LinkType_Radio(int idb); -public: - UString CurDirPrefix; - UString FilePath; - UString AnotherPath; - - INT_PTR Create(HWND parentWindow = 0) - { return CModalDialog::Create(IDD_LINK, parentWindow); } -}; - -#endif +// LinkDialog.h + +#ifndef __LINK_DIALOG_H +#define __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(); + virtual bool OnSize(WPARAM wParam, int xSize, int ySize); + virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); + void OnButton_SetPath(bool to); + void OnButton_Link(); + + void ShowLastErrorMessage(); + void ShowError(const wchar_t *s); + void Set_LinkType_Radio(int idb); +public: + UString CurDirPrefix; + UString FilePath; + UString AnotherPath; + + INT_PTR Create(HWND parentWindow = 0) + { return CModalDialog::Create(IDD_LINK, parentWindow); } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/LinkDialog.rc b/CPP/7zip/UI/FileManager/LinkDialog.rc index b0478b272..3d481d4d7 100644 --- a/CPP/7zip/UI/FileManager/LinkDialog.rc +++ b/CPP/7zip/UI/FileManager/LinkDialog.rc @@ -1,36 +1,36 @@ -#include "LinkDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 288 -#define yc 200 - -#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, 76 - - 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 - - DEFPUSHBUTTON "Link", IDB_LINK_LINK, bx2, by, bxs, bys - PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys -END +#include "LinkDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 288 +#define yc 200 + +#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, 76 + + 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 + + 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 index 4f4f7d421..47b891923 100644 --- a/CPP/7zip/UI/FileManager/LinkDialogRes.h +++ b/CPP/7zip/UI/FileManager/LinkDialogRes.h @@ -1,21 +1,21 @@ -#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 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 +#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 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 index c5b0d4388..a42e790b7 100644 --- a/CPP/7zip/UI/FileManager/ListViewDialog.cpp +++ b/CPP/7zip/UI/FileManager/ListViewDialog.cpp @@ -1,321 +1,321 @@ -// ListViewDialog.cpp - -#include "StdAfx.h" - -#include "../../../Windows/Clipboard.h" - -#include "EditDialog.h" -#include "ListViewDialog.h" -#include "RegistryUtils.h" - -#ifdef 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(index); - } -} - - -bool CListViewDialog::OnInit() -{ - #ifdef 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 (;;) - { - int index = _listView.GetNextSelectedItem(-1); - if (index < 0) - break; - StringsWereChanged = true; - _listView.DeleteItem(index); - if ((unsigned)index < Strings.Size()) - Strings.Delete(index); - if ((unsigned)index < Values.Size()) - Values.Delete(index); - } - 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(); -} +// ListViewDialog.cpp + +#include "StdAfx.h" + +#include "../../../Windows/Clipboard.h" + +#include "EditDialog.h" +#include "ListViewDialog.h" +#include "RegistryUtils.h" + +#ifdef 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(index); + } +} + + +bool CListViewDialog::OnInit() +{ + #ifdef 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 (;;) + { + int index = _listView.GetNextSelectedItem(-1); + if (index < 0) + break; + StringsWereChanged = true; + _listView.DeleteItem(index); + if ((unsigned)index < Strings.Size()) + Strings.Delete(index); + if ((unsigned)index < Values.Size()) + Values.Delete(index); + } + 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 index d18dae39a..00206afd2 100644 --- a/CPP/7zip/UI/FileManager/ListViewDialog.h +++ b/CPP/7zip/UI/FileManager/ListViewDialog.h @@ -1,46 +1,46 @@ -// ListViewDialog.h - -#ifndef __LISTVIEW_DIALOG_H -#define __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(); - virtual bool OnInit(); - virtual bool OnSize(WPARAM wParam, int xSize, int ySize); - virtual bool OnNotify(UINT controlID, LPNMHDR header); - 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 = 0) { return CModalDialog::Create(IDD_LISTVIEW, wndParent); } - - CListViewDialog(): - SelectFirst(false), - DeleteIsAllowed(false), - StringsWereChanged(false), - FocusedItemIndex(-1), - NumColumns(1) - {} -}; - -#endif +// ListViewDialog.h + +#ifndef __LISTVIEW_DIALOG_H +#define __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(); + virtual bool OnInit(); + virtual bool OnSize(WPARAM wParam, int xSize, int ySize); + virtual bool OnNotify(UINT controlID, LPNMHDR header); + 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 = 0) { 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 index 0846c73a8..961d224a9 100644 --- a/CPP/7zip/UI/FileManager/ListViewDialog.rc +++ b/CPP/7zip/UI/FileManager/ListViewDialog.rc @@ -1,14 +1,14 @@ -#include "ListViewDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 440 -#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 -} +#include "ListViewDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 440 +#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 index 1143be8cb..9abdb9d2e 100644 --- a/CPP/7zip/UI/FileManager/ListViewDialogRes.h +++ b/CPP/7zip/UI/FileManager/ListViewDialogRes.h @@ -1,2 +1,2 @@ -#define IDD_LISTVIEW 99 -#define IDL_LISTVIEW 100 +#define IDD_LISTVIEW 99 +#define IDL_LISTVIEW 100 diff --git a/CPP/7zip/UI/FileManager/MenuPage.cpp b/CPP/7zip/UI/FileManager/MenuPage.cpp index 57ec4a444..a642a7a3b 100644 --- a/CPP/7zip/UI/FileManager/MenuPage.cpp +++ b/CPP/7zip/UI/FileManager/MenuPage.cpp @@ -1,358 +1,358 @@ -// 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; - -static const UInt32 kLangIDs[] = -{ - IDX_SYSTEM_INTEGRATE_TO_MENU, - IDX_SYSTEM_CASCADED_MENU, - IDX_SYSTEM_ICON_IN_MENU, - IDX_EXTRACT_ELIM_DUP, - IDT_SYSTEM_CONTEXT_MENU_ITEMS -}; - -#define kMenuTopic "fm/options.htm#sevenZip" - -struct CContextMenuItem -{ - int 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 } -}; - - -#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 - -bool CMenuPage::OnInit() -{ - _initMode = true; - - Clear_MenuChanged(); - - LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); - - #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(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)); - - const UInt32 newFlags = LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT; - _listView.SetExtendedListViewStyle(newFlags, newFlags); - - _listView.InsertColumn(0, L"", 200); - - for (unsigned i = 0; i < ARRAY_SIZE(kMenuItems); i++) - { - const CContextMenuItem &menuItem = kMenuItems[i]; - - UString s = LangString(menuItem.ControlID); - if (menuItem.Flag == kCRC) - s = "HASH"; - if (menuItem.Flag == kOpenAs || - menuItem.Flag == kCRC) - 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; - } - } - - int itemIndex = _listView.InsertItem(i, s); - _listView.SetCheckState(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 ZS", 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()) - { - bool newVal = IsButtonCheckedBool(dll.ctrl); - 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 || _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; - - ci.Flags = 0; - - for (unsigned i = 0; i < 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(int 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; - - default: - return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); - } - - Changed(); - return true; -} - -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; -} +// 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; + +static const UInt32 kLangIDs[] = +{ + IDX_SYSTEM_INTEGRATE_TO_MENU, + IDX_SYSTEM_CASCADED_MENU, + IDX_SYSTEM_ICON_IN_MENU, + IDX_EXTRACT_ELIM_DUP, + IDT_SYSTEM_CONTEXT_MENU_ITEMS +}; + +#define kMenuTopic "fm/options.htm#sevenZip" + +struct CContextMenuItem +{ + int 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 } +}; + + +#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 + +bool CMenuPage::OnInit() +{ + _initMode = true; + + Clear_MenuChanged(); + + LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); + + #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(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)); + + const UInt32 newFlags = LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT; + _listView.SetExtendedListViewStyle(newFlags, newFlags); + + _listView.InsertColumn(0, L"", 200); + + for (unsigned i = 0; i < ARRAY_SIZE(kMenuItems); i++) + { + const CContextMenuItem &menuItem = kMenuItems[i]; + + UString s = LangString(menuItem.ControlID); + if (menuItem.Flag == kCRC) + s = "HASH"; + if (menuItem.Flag == kOpenAs || + menuItem.Flag == kCRC) + 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; + } + } + + int itemIndex = _listView.InsertItem(i, s); + _listView.SetCheckState(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 ZS", 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()) + { + bool newVal = IsButtonCheckedBool(dll.ctrl); + 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 || _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; + + ci.Flags = 0; + + for (unsigned i = 0; i < 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(int 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; + + default: + return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); + } + + Changed(); + return true; +} + +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 index 3dbbfc530..3807d9dd3 100644 --- a/CPP/7zip/UI/FileManager/MenuPage.h +++ b/CPP/7zip/UI/FileManager/MenuPage.h @@ -1,52 +1,52 @@ -// MenuPage.h - -#ifndef __MENU_PAGE_H -#define __MENU_PAGE_H - -#include "../../../Windows/Control/PropertyPage.h" -#include "../../../Windows/Control/ListView.h" - -struct CShellDll -{ - FString Path; - bool wasChanged; - bool prevValue; - int 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 _flags_Changed; - - void Clear_MenuChanged() - { - _cascaded_Changed = false; - _menuIcons_Changed = false; - _elimDup_Changed = false; - _flags_Changed = false; - } - - #ifndef UNDER_CE - CShellDll _dlls[2]; - #endif - - NWindows::NControl::CListView _listView; - - virtual bool OnInit(); - virtual void OnNotifyHelp(); - virtual bool OnNotify(UINT controlID, LPNMHDR lParam); - virtual bool OnItemChanged(const NMLISTVIEW *info); - virtual LONG OnApply(); - virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); -public: -}; - -#endif +// MenuPage.h + +#ifndef __MENU_PAGE_H +#define __MENU_PAGE_H + +#include "../../../Windows/Control/PropertyPage.h" +#include "../../../Windows/Control/ListView.h" + +struct CShellDll +{ + FString Path; + bool wasChanged; + bool prevValue; + int 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 _flags_Changed; + + void Clear_MenuChanged() + { + _cascaded_Changed = false; + _menuIcons_Changed = false; + _elimDup_Changed = false; + _flags_Changed = false; + } + + #ifndef UNDER_CE + CShellDll _dlls[2]; + #endif + + NWindows::NControl::CListView _listView; + + virtual bool OnInit(); + virtual void OnNotifyHelp(); + virtual bool OnNotify(UINT controlID, LPNMHDR lParam); + virtual bool OnItemChanged(const NMLISTVIEW *info); + virtual LONG OnApply(); + virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); +public: +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/MenuPage.rc b/CPP/7zip/UI/FileManager/MenuPage.rc index 7159fd4d0..dd32898ff 100644 --- a/CPP/7zip/UI/FileManager/MenuPage.rc +++ b/CPP/7zip/UI/FileManager/MenuPage.rc @@ -1,24 +1,24 @@ -#include "MenuPageRes.h" -#include "../../GuiCommon.rc" - -#define xc 240 -#define yc 224 - -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 +#include "MenuPageRes.h" +#include "../../GuiCommon.rc" + +#define xc 240 +#define yc 224 + +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 index 574d80806..af0cc3c5b 100644 --- a/CPP/7zip/UI/FileManager/MenuPage2.rc +++ b/CPP/7zip/UI/FileManager/MenuPage2.rc @@ -1,17 +1,17 @@ -#include "../GUI/ExtractDialogRes.h" - -#define y 82 - -CAPTION "7-Zip ZS" -BEGIN - CONTROL "Integrate 7-Zip ZS 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 "Context menu items:", IDT_SYSTEM_CONTEXT_MENU_ITEMS, m, m + 70, 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 +#include "../GUI/ExtractDialogRes.h" + +#define y 82 + +CAPTION "7-Zip ZS" +BEGIN + CONTROL "Integrate 7-Zip ZS 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 "Context menu items:", IDT_SYSTEM_CONTEXT_MENU_ITEMS, m, m + 70, 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 diff --git a/CPP/7zip/UI/FileManager/MenuPageRes.h b/CPP/7zip/UI/FileManager/MenuPageRes.h index b9bd13f70..ae0bf66d2 100644 --- a/CPP/7zip/UI/FileManager/MenuPageRes.h +++ b/CPP/7zip/UI/FileManager/MenuPageRes.h @@ -1,11 +1,11 @@ -#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 IDL_SYSTEM_OPTIONS 100 +#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 IDL_SYSTEM_OPTIONS 100 diff --git a/CPP/7zip/UI/FileManager/MessagesDialog.cpp b/CPP/7zip/UI/FileManager/MessagesDialog.cpp index dffb4c6bc..412482773 100644 --- a/CPP/7zip/UI/FileManager/MessagesDialog.cpp +++ b/CPP/7zip/UI/FileManager/MessagesDialog.cpp @@ -1,76 +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) -{ - int i = _messageList.GetItemCount(); - wchar_t sz[16]; - ConvertUInt32ToString((UInt32)i, sz); - _messageList.InsertItem(i, sz); - _messageList.SetSubItem(i, 1, message); -} - -void CMessagesDialog::AddMessage(LPCWSTR message) -{ - UString s = message; - while (!s.IsEmpty()) - { - int pos = s.Find(L'\n'); - if (pos < 0) - break; - AddMessageDirect(s.Left(pos)); - s.DeleteFrontal(pos + 1); - } - AddMessageDirect(s); -} - -bool CMessagesDialog::OnInit() -{ - #ifdef 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; -} +// 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) +{ + int i = _messageList.GetItemCount(); + wchar_t sz[16]; + ConvertUInt32ToString((UInt32)i, sz); + _messageList.InsertItem(i, sz); + _messageList.SetSubItem(i, 1, message); +} + +void CMessagesDialog::AddMessage(LPCWSTR message) +{ + UString s = message; + while (!s.IsEmpty()) + { + int pos = s.Find(L'\n'); + if (pos < 0) + break; + AddMessageDirect(s.Left(pos)); + s.DeleteFrontal(pos + 1); + } + AddMessageDirect(s); +} + +bool CMessagesDialog::OnInit() +{ + #ifdef 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 index a65f5907a..5c017eb48 100644 --- a/CPP/7zip/UI/FileManager/MessagesDialog.h +++ b/CPP/7zip/UI/FileManager/MessagesDialog.h @@ -1,25 +1,25 @@ -// MessagesDialog.h - -#ifndef __MESSAGES_DIALOG_H -#define __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(); - virtual bool OnSize(WPARAM wParam, int xSize, int ySize); -public: - const UStringVector *Messages; - - INT_PTR Create(HWND parent = 0) { return CModalDialog::Create(IDD_MESSAGES, parent); } -}; - -#endif +// MessagesDialog.h + +#ifndef __MESSAGES_DIALOG_H +#define __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(); + virtual bool OnSize(WPARAM wParam, int xSize, int ySize); +public: + const UStringVector *Messages; + + INT_PTR Create(HWND parent = 0) { return CModalDialog::Create(IDD_MESSAGES, parent); } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/MessagesDialog.rc b/CPP/7zip/UI/FileManager/MessagesDialog.rc index d7d404319..49b73e843 100644 --- a/CPP/7zip/UI/FileManager/MessagesDialog.rc +++ b/CPP/7zip/UI/FileManager/MessagesDialog.rc @@ -1,14 +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 -} +#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 index 5bd8184e0..c8fffff6e 100644 --- a/CPP/7zip/UI/FileManager/MessagesDialogRes.h +++ b/CPP/7zip/UI/FileManager/MessagesDialogRes.h @@ -1,3 +1,3 @@ -#define IDD_MESSAGES 6602 -#define IDS_MESSAGE 6603 -#define IDL_MESSAGE 100 +#define IDD_MESSAGES 6602 +#define IDS_MESSAGE 6603 +#define IDL_MESSAGE 100 diff --git a/CPP/7zip/UI/FileManager/MyCom2.h b/CPP/7zip/UI/FileManager/MyCom2.h index a6af900ed..224a838df 100644 --- a/CPP/7zip/UI/FileManager/MyCom2.h +++ b/CPP/7zip/UI/FileManager/MyCom2.h @@ -1,39 +1,39 @@ -// MyCom2.h - -#ifndef __MYCOM2_H -#define __MYCOM2_H - -#include "../../../Common/MyCom.h" - -#define MY_ADDREF_RELEASE_MT \ -STDMETHOD_(ULONG, AddRef)() { InterlockedIncrement((LONG *)&__m_RefCount); return __m_RefCount; } \ -STDMETHOD_(ULONG, Release)() { InterlockedDecrement((LONG *)&__m_RefCount); if (__m_RefCount != 0) \ - return __m_RefCount; delete this; return 0; } - -#define MY_UNKNOWN_IMP_SPEC_MT2(i1, i) \ - MY_QUERYINTERFACE_BEGIN \ - MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ - i \ - MY_QUERYINTERFACE_END \ - MY_ADDREF_RELEASE_MT - - -#define MY_UNKNOWN_IMP1_MT(i) MY_UNKNOWN_IMP_SPEC_MT2( \ - i, \ - MY_QUERYINTERFACE_ENTRY(i) \ - ) - -#define MY_UNKNOWN_IMP2_MT(i1, i2) MY_UNKNOWN_IMP_SPEC_MT2( \ - i1, \ - MY_QUERYINTERFACE_ENTRY(i1) \ - MY_QUERYINTERFACE_ENTRY(i2) \ - ) - -#define MY_UNKNOWN_IMP3_MT(i1, i2, i3) MY_UNKNOWN_IMP_SPEC_MT2( \ - i1, \ - MY_QUERYINTERFACE_ENTRY(i1) \ - MY_QUERYINTERFACE_ENTRY(i2) \ - MY_QUERYINTERFACE_ENTRY(i3) \ - ) - -#endif +// MyCom2.h + +#ifndef __MYCOM2_H +#define __MYCOM2_H + +#include "../../../Common/MyCom.h" + +#define MY_ADDREF_RELEASE_MT \ +STDMETHOD_(ULONG, AddRef)() { InterlockedIncrement((LONG *)&__m_RefCount); return __m_RefCount; } \ +STDMETHOD_(ULONG, Release)() { InterlockedDecrement((LONG *)&__m_RefCount); if (__m_RefCount != 0) \ + return __m_RefCount; delete this; return 0; } + +#define MY_UNKNOWN_IMP_SPEC_MT2(i1, i) \ + MY_QUERYINTERFACE_BEGIN \ + MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ + i \ + MY_QUERYINTERFACE_END \ + MY_ADDREF_RELEASE_MT + + +#define MY_UNKNOWN_IMP1_MT(i) MY_UNKNOWN_IMP_SPEC_MT2( \ + i, \ + MY_QUERYINTERFACE_ENTRY(i) \ + ) + +#define MY_UNKNOWN_IMP2_MT(i1, i2) MY_UNKNOWN_IMP_SPEC_MT2( \ + i1, \ + MY_QUERYINTERFACE_ENTRY(i1) \ + MY_QUERYINTERFACE_ENTRY(i2) \ + ) + +#define MY_UNKNOWN_IMP3_MT(i1, i2, i3) MY_UNKNOWN_IMP_SPEC_MT2( \ + i1, \ + MY_QUERYINTERFACE_ENTRY(i1) \ + MY_QUERYINTERFACE_ENTRY(i2) \ + MY_QUERYINTERFACE_ENTRY(i3) \ + ) + +#endif diff --git a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp index b5c8c41c7..a60cec4ce 100644 --- a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp +++ b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp @@ -1,757 +1,757 @@ -// 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 "resource.h" - -using namespace NWindows; - -static const UINT kOpenBookmarkMenuID = 830; -static const UINT kSetBookmarkMenuID = 810; -static const UINT kMenuID_Time_Parent = 760; -static const UINT kMenuID_Time = 761; - -extern HINSTANCE g_hInstance; - -#define kFMHelpTopic "FM/index.htm" - -extern void OptionsDialog(HWND hwndOwner, HINSTANCE hInstance); - -enum -{ - kMenuIndex_File = 0, - kMenuIndex_Edit, - kMenuIndex_View, - kMenuIndex_Bookmarks -}; - -static const UInt32 kTopMenuLangIDs[] = { 500, 501, 502, 503, 504, 505 }; - -static const UInt32 kAddToFavoritesLangID = 800; -static const UInt32 kToolbarsLangID = 733; - -static const CIDLangPair kIDLangPairs[] = -{ - { IDCLOSE, 557 }, - { IDM_VIEW_ARANGE_BY_NAME, 1004 }, - { IDM_VIEW_ARANGE_BY_TYPE, 1020 }, - { IDM_VIEW_ARANGE_BY_DATE, 1012 }, - { IDM_VIEW_ARANGE_BY_SIZE, 1007 } -}; - -static int FindLangItem(unsigned controlID) -{ - for (unsigned i = 0; i < ARRAY_SIZE(kIDLangPairs); i++) - if (kIDLangPairs[i].ControlID == controlID) - return i; - return -1; -} - -static int 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 -1; -} - -/* -static bool g_IsNew_fMask = true; - -class CInit_fMask -{ -public: - CInit_fMask() - { - g_IsNew_fMask = false; - OSVERSIONINFO vi; - vi.dwOSVersionInfoSize = sizeof(vi); - if (::GetVersionEx(&vi)) - { - g_IsNew_fMask = (vi.dwMajorVersion > 4 || - (vi.dwMajorVersion == 4 && vi.dwMinorVersion > 0)); - } - g_IsNew_fMask = false; - } -} g_Init_fMask; - -// it's hack for supporting Windows NT -// constants are from WinUser.h - -#if (WINVER < 0x0500) -#define MIIM_STRING 0x00000040 -#define MIIM_BITMAP 0x00000080 -#define MIIM_FTYPE 0x00000100 -#endif - -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; -} -*/ - -static inline UINT Get_fMask_for_String() { return MIIM_TYPE; } -static inline UINT Get_fMask_for_FType_and_String() { return MIIM_TYPE; } - - -static void MyChangeMenu(HMENU menuLoc, int level, int menuIndex) -{ - CMenu menu; - menu.Attach(menuLoc); - - for (int 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; - { - UString newString; - if (item.hSubMenu) - { - UInt32 langID = 0; - if (level == 1 && menuIndex == kMenuIndex_Bookmarks) - langID = kAddToFavoritesLangID; - else - { - MyChangeMenu(item.hSubMenu, level + 1, i); - if (level == 1 && menuIndex == kMenuIndex_View) - { - if (item.wID == kMenuID_Time_Parent || item.StringValue.IsPrefixedBy_Ascii_NoCase("20")) - continue; - else - langID = kToolbarsLangID; - } - else if (level == 0 && i < ARRAY_SIZE(kTopMenuLangIDs)) - langID = kTopMenuLangIDs[i]; - else - continue; - } - - LangString_OnlyFromLangFile(langID, newString); - - if (newString.IsEmpty()) - continue; - } - else - { - if (item.IsSeparator()) - continue; - int langPos = FindLangItem(item.wID); - - // we don't need lang change for CRC items!!! - - UInt32 langID = langPos >= 0 ? kIDLangPairs[langPos].LangID : item.wID; - - 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""); - 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""); - int tabPos = newString.Find(L"\t"); - if (tabPos >= 0) - newString.DeleteFrom(tabPos); - newString += " 2"; - } - else - LangString_OnlyFromLangFile(langID, newString); - - if (newString.IsEmpty()) - continue; - - int tabPos = item.StringValue.ReverseFind(L'\t'); - if (tabPos >= 0) - newString += item.StringValue.Ptr(tabPos); - } - - { - item.StringValue = newString; - item.fMask = Get_fMask_for_String(); - item.fType = MFT_STRING; - menu.SetItem(i, true, item); - } - } - } -} - -static CMenu g_FileMenu; - -struct CFileMenuDestroyer -{ - ~CFileMenuDestroyer() { if ((HMENU)g_FileMenu != 0) g_FileMenu.Destroy(); } -} g_FileMenuDestroyer; - - -static void CopyMenu(HMENU srcMenuSpec, HMENU destMenuSpec); - -static void CopyPopMenu_IfRequired(CMenuItem &item) -{ - if (item.hSubMenu) - { - CMenu popup; - popup.CreatePopup(); - CopyMenu(item.hSubMenu, popup); - item.hSubMenu = popup; - } -} - -static void CopyMenu(HMENU srcMenuSpec, HMENU destMenuSpec) -{ - CMenu srcMenu; - srcMenu.Attach(srcMenuSpec); - CMenu destMenu; - destMenu.Attach(destMenuSpec); - int startPos = 0; - for (int i = 0;; i++) - { - CMenuItem item; - item.fMask = MIIM_SUBMENU | MIIM_STATE | MIIM_ID | Get_fMask_for_FType_and_String(); - item.fType = MFT_STRING; - - if (!srcMenu.GetItem(i, true, item)) - break; - - CopyPopMenu_IfRequired(item); - if (destMenu.InsertItem(startPos, true, item)) - startPos++; - } -} - -void MyLoadMenu() -{ - HMENU baseMenu; - - #ifdef UNDER_CE - - HMENU oldMenu = g_App._commandBar.GetMenu(0); - if (oldMenu) - ::DestroyMenu(oldMenu); - /* BOOL b = */ g_App._commandBar.InsertMenubar(g_hInstance, IDM_MENU, 0); - baseMenu = g_App._commandBar.GetMenu(0); - // if (startInit) - // SetIdsForSubMenes(baseMenu, 0, 0); - if (!g_LangID.IsEmpty()) - MyChangeMenu(baseMenu, 0, 0); - g_App._commandBar.DrawMenuBar(0); - - #else - - HWND hWnd = g_HWND; - HMENU oldMenu = ::GetMenu(hWnd); - ::SetMenu(hWnd, ::LoadMenu(g_hInstance, MAKEINTRESOURCE(IDM_MENU))); - ::DestroyMenu(oldMenu); - baseMenu = ::GetMenu(hWnd); - // if (startInit) - // SetIdsForSubMenes(baseMenu, 0, 0); - if (!g_LangID.IsEmpty()) - MyChangeMenu(baseMenu, 0, 0); - ::DrawMenuBar(hWnd); - - #endif - - if ((HMENU)g_FileMenu != 0) - g_FileMenu.Destroy(); - g_FileMenu.CreatePopup(); - CopyMenu(::GetSubMenu(baseMenu, 0), 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 == kMenuIndex_File) - { - CMenu menu; - menu.Attach(hMenu); - menu.RemoveAllItems(); - g_App.GetFocusedPanel().CreateFileMenu(hMenu); - } - else if (position == kMenuIndex_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 == kMenuIndex_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 (int 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 && (item.wID == kMenuID_Time_Parent - || item.StringValue.IsPrefixedBy_Ascii_NoCase("20") - )) - { - 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 = kMenuID_Time_Parent; - menu.SetItem(i, true, item); - - CMenu subMenu; - subMenu.Attach(menu.GetSubMenu(i)); - subMenu.RemoveAllItems(); - - const int k_TimeLevels[] = - { - kTimestampPrintLevel_DAY, - kTimestampPrintLevel_MIN, - kTimestampPrintLevel_SEC, - // 1,2,3,4,5,6, - kTimestampPrintLevel_NTFS - }; - - unsigned last = kMenuID_Time; - unsigned selectedCommand = 0; - g_App._timestampLevels.Clear(); - unsigned id = kMenuID_Time; - - for (unsigned k = 0; k < ARRAY_SIZE(k_TimeLevels); k++) - { - wchar_t s[64]; - s[0] = 0; - 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(kMenuID_Time, last, selectedCommand, MF_BYCOMMAND); - } - } - } - else if (position == kMenuIndex_Bookmarks) - { - CMenu menu; - menu.Attach(hMenu); - - CMenu subMenu; - subMenu.Attach(menu.GetSubMenu(0)); - subMenu.RemoveAllItems(); - int i; - - for (i = 0; i < 10; i++) - { - UString s = LangString(IDS_BOOKMARK); - s.Add_Space(); - char c = (char)(L'0' + i); - s += c; - s += "\tAlt+Shift+"; - s += c; - subMenu.AppendItem(MF_STRING, kSetBookmarkMenuID + 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, kOpenBookmarkMenuID + i, s); - } - } -} - -/* -It doesn't help -void OnMenuUnActivating(HWND hWnd, HMENU hMenu, int id) -{ - if (::GetSubMenu(::GetMenu(g_HWND), 0) != hMenu) - return; -} -*/ - -void CFileMenu::Load(HMENU hMenu, unsigned startPos) -{ - CMenu destMenu; - destMenu.Attach(hMenu); - - UString diffPath; - ReadRegDiff(diffPath); - - unsigned numRealItems = startPos; - - 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 (item.wID == IDM_LINK && numItems != 1) - disable = true; - - if (item.wID == IDM_ALT_STREAMS) - disable = !isAltStreamsSupported; - - bool isBigScreen = NControl::IsDialogSizeOK(40, 200); - - 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; - } - } - - destMenu.RemoveAllItemsFrom(numRealItems); -} - -bool ExecuteFileCommand(int 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_XXH32: g_App.CalculateCrc("XXH32"); break; - case IDM_XXH64: g_App.CalculateCrc("XXH64"); break; - case IDM_MD2: g_App.CalculateCrc("MD2"); break; - case IDM_MD4: g_App.CalculateCrc("MD4"); break; - case IDM_MD5: g_App.CalculateCrc("MD5"); break; - case IDM_SHA1: g_App.CalculateCrc("SHA1"); break; - case IDM_SHA256: g_App.CalculateCrc("SHA256"); break; - case IDM_SHA384: g_App.CalculateCrc("SHA384"); break; - case IDM_SHA512: g_App.CalculateCrc("SHA512"); break; - case IDM_BLAKE2sp: g_App.CalculateCrc("BLAKE2sp"); break; - - case IDM_DIFF: g_App.DiffFiles(); 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, int 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), kMenuIndex_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 >= kOpenBookmarkMenuID && id <= kOpenBookmarkMenuID + 9) - { - g_App.OpenBookmark(id - kOpenBookmarkMenuID); - return true; - } - else if (id >= kSetBookmarkMenuID && id <= kSetBookmarkMenuID + 9) - { - g_App.SetBookmark(id - kSetBookmarkMenuID); - return true; - } - else if (id >= kMenuID_Time && (unsigned)id <= kMenuID_Time + g_App._timestampLevels.Size()) - { - unsigned index = id - kMenuID_Time; - g_App.SetTimestampLevel(g_App._timestampLevels[index]); - return true; - } - return false; - } - } - return true; -} +// 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 "resource.h" + +using namespace NWindows; + +static const UINT kOpenBookmarkMenuID = 830; +static const UINT kSetBookmarkMenuID = 810; +static const UINT kMenuID_Time_Parent = 760; +static const UINT kMenuID_Time = 761; + +extern HINSTANCE g_hInstance; + +#define kFMHelpTopic "FM/index.htm" + +extern void OptionsDialog(HWND hwndOwner, HINSTANCE hInstance); + +enum +{ + kMenuIndex_File = 0, + kMenuIndex_Edit, + kMenuIndex_View, + kMenuIndex_Bookmarks +}; + +static const UInt32 kTopMenuLangIDs[] = { 500, 501, 502, 503, 504, 505 }; + +static const UInt32 kAddToFavoritesLangID = 800; +static const UInt32 kToolbarsLangID = 733; + +static const CIDLangPair kIDLangPairs[] = +{ + { IDCLOSE, 557 }, + { IDM_VIEW_ARANGE_BY_NAME, 1004 }, + { IDM_VIEW_ARANGE_BY_TYPE, 1020 }, + { IDM_VIEW_ARANGE_BY_DATE, 1012 }, + { IDM_VIEW_ARANGE_BY_SIZE, 1007 } +}; + +static int FindLangItem(unsigned controlID) +{ + for (unsigned i = 0; i < ARRAY_SIZE(kIDLangPairs); i++) + if (kIDLangPairs[i].ControlID == controlID) + return i; + return -1; +} + +static int 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 -1; +} + +/* +static bool g_IsNew_fMask = true; + +class CInit_fMask +{ +public: + CInit_fMask() + { + g_IsNew_fMask = false; + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + if (::GetVersionEx(&vi)) + { + g_IsNew_fMask = (vi.dwMajorVersion > 4 || + (vi.dwMajorVersion == 4 && vi.dwMinorVersion > 0)); + } + g_IsNew_fMask = false; + } +} g_Init_fMask; + +// it's hack for supporting Windows NT +// constants are from WinUser.h + +#if (WINVER < 0x0500) +#define MIIM_STRING 0x00000040 +#define MIIM_BITMAP 0x00000080 +#define MIIM_FTYPE 0x00000100 +#endif + +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; +} +*/ + +static inline UINT Get_fMask_for_String() { return MIIM_TYPE; } +static inline UINT Get_fMask_for_FType_and_String() { return MIIM_TYPE; } + + +static void MyChangeMenu(HMENU menuLoc, int level, int menuIndex) +{ + CMenu menu; + menu.Attach(menuLoc); + + for (int 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; + { + UString newString; + if (item.hSubMenu) + { + UInt32 langID = 0; + if (level == 1 && menuIndex == kMenuIndex_Bookmarks) + langID = kAddToFavoritesLangID; + else + { + MyChangeMenu(item.hSubMenu, level + 1, i); + if (level == 1 && menuIndex == kMenuIndex_View) + { + if (item.wID == kMenuID_Time_Parent || item.StringValue.IsPrefixedBy_Ascii_NoCase("20")) + continue; + else + langID = kToolbarsLangID; + } + else if (level == 0 && i < ARRAY_SIZE(kTopMenuLangIDs)) + langID = kTopMenuLangIDs[i]; + else + continue; + } + + LangString_OnlyFromLangFile(langID, newString); + + if (newString.IsEmpty()) + continue; + } + else + { + if (item.IsSeparator()) + continue; + int langPos = FindLangItem(item.wID); + + // we don't need lang change for CRC items!!! + + UInt32 langID = langPos >= 0 ? kIDLangPairs[langPos].LangID : item.wID; + + 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""); + 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""); + int tabPos = newString.Find(L"\t"); + if (tabPos >= 0) + newString.DeleteFrom(tabPos); + newString += " 2"; + } + else + LangString_OnlyFromLangFile(langID, newString); + + if (newString.IsEmpty()) + continue; + + int tabPos = item.StringValue.ReverseFind(L'\t'); + if (tabPos >= 0) + newString += item.StringValue.Ptr(tabPos); + } + + { + item.StringValue = newString; + item.fMask = Get_fMask_for_String(); + item.fType = MFT_STRING; + menu.SetItem(i, true, item); + } + } + } +} + +static CMenu g_FileMenu; + +struct CFileMenuDestroyer +{ + ~CFileMenuDestroyer() { if ((HMENU)g_FileMenu != 0) g_FileMenu.Destroy(); } +} g_FileMenuDestroyer; + + +static void CopyMenu(HMENU srcMenuSpec, HMENU destMenuSpec); + +static void CopyPopMenu_IfRequired(CMenuItem &item) +{ + if (item.hSubMenu) + { + CMenu popup; + popup.CreatePopup(); + CopyMenu(item.hSubMenu, popup); + item.hSubMenu = popup; + } +} + +static void CopyMenu(HMENU srcMenuSpec, HMENU destMenuSpec) +{ + CMenu srcMenu; + srcMenu.Attach(srcMenuSpec); + CMenu destMenu; + destMenu.Attach(destMenuSpec); + int startPos = 0; + for (int i = 0;; i++) + { + CMenuItem item; + item.fMask = MIIM_SUBMENU | MIIM_STATE | MIIM_ID | Get_fMask_for_FType_and_String(); + item.fType = MFT_STRING; + + if (!srcMenu.GetItem(i, true, item)) + break; + + CopyPopMenu_IfRequired(item); + if (destMenu.InsertItem(startPos, true, item)) + startPos++; + } +} + +void MyLoadMenu() +{ + HMENU baseMenu; + + #ifdef UNDER_CE + + HMENU oldMenu = g_App._commandBar.GetMenu(0); + if (oldMenu) + ::DestroyMenu(oldMenu); + /* BOOL b = */ g_App._commandBar.InsertMenubar(g_hInstance, IDM_MENU, 0); + baseMenu = g_App._commandBar.GetMenu(0); + // if (startInit) + // SetIdsForSubMenes(baseMenu, 0, 0); + if (!g_LangID.IsEmpty()) + MyChangeMenu(baseMenu, 0, 0); + g_App._commandBar.DrawMenuBar(0); + + #else + + HWND hWnd = g_HWND; + HMENU oldMenu = ::GetMenu(hWnd); + ::SetMenu(hWnd, ::LoadMenu(g_hInstance, MAKEINTRESOURCE(IDM_MENU))); + ::DestroyMenu(oldMenu); + baseMenu = ::GetMenu(hWnd); + // if (startInit) + // SetIdsForSubMenes(baseMenu, 0, 0); + if (!g_LangID.IsEmpty()) + MyChangeMenu(baseMenu, 0, 0); + ::DrawMenuBar(hWnd); + + #endif + + if ((HMENU)g_FileMenu != 0) + g_FileMenu.Destroy(); + g_FileMenu.CreatePopup(); + CopyMenu(::GetSubMenu(baseMenu, 0), 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 == kMenuIndex_File) + { + CMenu menu; + menu.Attach(hMenu); + menu.RemoveAllItems(); + g_App.GetFocusedPanel().CreateFileMenu(hMenu); + } + else if (position == kMenuIndex_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 == kMenuIndex_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 (int 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 && (item.wID == kMenuID_Time_Parent + || item.StringValue.IsPrefixedBy_Ascii_NoCase("20") + )) + { + 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 = kMenuID_Time_Parent; + menu.SetItem(i, true, item); + + CMenu subMenu; + subMenu.Attach(menu.GetSubMenu(i)); + subMenu.RemoveAllItems(); + + const int k_TimeLevels[] = + { + kTimestampPrintLevel_DAY, + kTimestampPrintLevel_MIN, + kTimestampPrintLevel_SEC, + // 1,2,3,4,5,6, + kTimestampPrintLevel_NTFS + }; + + unsigned last = kMenuID_Time; + unsigned selectedCommand = 0; + g_App._timestampLevels.Clear(); + unsigned id = kMenuID_Time; + + for (unsigned k = 0; k < ARRAY_SIZE(k_TimeLevels); k++) + { + wchar_t s[64]; + s[0] = 0; + 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(kMenuID_Time, last, selectedCommand, MF_BYCOMMAND); + } + } + } + else if (position == kMenuIndex_Bookmarks) + { + CMenu menu; + menu.Attach(hMenu); + + CMenu subMenu; + subMenu.Attach(menu.GetSubMenu(0)); + subMenu.RemoveAllItems(); + int i; + + for (i = 0; i < 10; i++) + { + UString s = LangString(IDS_BOOKMARK); + s.Add_Space(); + char c = (char)(L'0' + i); + s += c; + s += "\tAlt+Shift+"; + s += c; + subMenu.AppendItem(MF_STRING, kSetBookmarkMenuID + 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, kOpenBookmarkMenuID + i, s); + } + } +} + +/* +It doesn't help +void OnMenuUnActivating(HWND hWnd, HMENU hMenu, int id) +{ + if (::GetSubMenu(::GetMenu(g_HWND), 0) != hMenu) + return; +} +*/ + +void CFileMenu::Load(HMENU hMenu, unsigned startPos) +{ + CMenu destMenu; + destMenu.Attach(hMenu); + + UString diffPath; + ReadRegDiff(diffPath); + + unsigned numRealItems = startPos; + + 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 (item.wID == IDM_LINK && numItems != 1) + disable = true; + + if (item.wID == IDM_ALT_STREAMS) + disable = !isAltStreamsSupported; + + bool isBigScreen = NControl::IsDialogSizeOK(40, 200); + + 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; + } + } + + destMenu.RemoveAllItemsFrom(numRealItems); +} + +bool ExecuteFileCommand(int 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_XXH32: g_App.CalculateCrc("XXH32"); break; + case IDM_XXH64: g_App.CalculateCrc("XXH64"); break; + case IDM_MD2: g_App.CalculateCrc("MD2"); break; + case IDM_MD4: g_App.CalculateCrc("MD4"); break; + case IDM_MD5: g_App.CalculateCrc("MD5"); break; + case IDM_SHA1: g_App.CalculateCrc("SHA1"); break; + case IDM_SHA256: g_App.CalculateCrc("SHA256"); break; + case IDM_SHA384: g_App.CalculateCrc("SHA384"); break; + case IDM_SHA512: g_App.CalculateCrc("SHA512"); break; + case IDM_BLAKE2sp: g_App.CalculateCrc("BLAKE2sp"); break; + + case IDM_DIFF: g_App.DiffFiles(); 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, int 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), kMenuIndex_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 >= kOpenBookmarkMenuID && id <= kOpenBookmarkMenuID + 9) + { + g_App.OpenBookmark(id - kOpenBookmarkMenuID); + return true; + } + else if (id >= kSetBookmarkMenuID && id <= kSetBookmarkMenuID + 9) + { + g_App.SetBookmark(id - kSetBookmarkMenuID); + return true; + } + else if (id >= kMenuID_Time && (unsigned)id <= kMenuID_Time + g_App._timestampLevels.Size()) + { + unsigned index = id - kMenuID_Time; + g_App.SetTimestampLevel(g_App._timestampLevels[index]); + return true; + } + return false; + } + } + return true; +} diff --git a/CPP/7zip/UI/FileManager/MyLoadMenu.h b/CPP/7zip/UI/FileManager/MyLoadMenu.h index 2482d5887..02569e524 100644 --- a/CPP/7zip/UI/FileManager/MyLoadMenu.h +++ b/CPP/7zip/UI/FileManager/MyLoadMenu.h @@ -1,36 +1,36 @@ -// MyLoadMenu.h - -#ifndef __MY_LOAD_MENU_H -#define __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, int id); -void MyLoadMenu(); - -struct CFileMenu -{ - bool programMenu; - bool readOnly; - bool isFsFolder; - bool allAreFiles; - bool isAltStreamsSupported; - int numItems; - - CFileMenu(): - programMenu(false), - readOnly(false), - isFsFolder(false), - allAreFiles(false), - isAltStreamsSupported(true), - numItems(0) - {} - - void Load(HMENU hMenu, unsigned startPos); -}; - -bool ExecuteFileCommand(int id); - -#endif +// MyLoadMenu.h + +#ifndef __MY_LOAD_MENU_H +#define __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, int id); +void MyLoadMenu(); + +struct CFileMenu +{ + bool programMenu; + bool readOnly; + bool isFsFolder; + bool allAreFiles; + bool isAltStreamsSupported; + int numItems; + + CFileMenu(): + programMenu(false), + readOnly(false), + isFsFolder(false), + allAreFiles(false), + isAltStreamsSupported(true), + numItems(0) + {} + + void Load(HMENU hMenu, unsigned startPos); +}; + +bool ExecuteFileCommand(int id); + +#endif diff --git a/CPP/7zip/UI/FileManager/MyWindowsNew.h b/CPP/7zip/UI/FileManager/MyWindowsNew.h index c0fe8439b..48a95359e 100644 --- a/CPP/7zip/UI/FileManager/MyWindowsNew.h +++ b/CPP/7zip/UI/FileManager/MyWindowsNew.h @@ -1,76 +1,76 @@ -// MyWindowsNew.h - -#ifndef __MY_WINDOWS_NEW_H -#define __MY_WINDOWS_NEW_H - -#ifdef _MSC_VER - -#include - -#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 - -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 __MY_WINDOWS_NEW_H +#define __MY_WINDOWS_NEW_H + +#ifdef _MSC_VER + +#include + +#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 + +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 diff --git a/CPP/7zip/UI/FileManager/NetFolder.cpp b/CPP/7zip/UI/FileManager/NetFolder.cpp index 48d81d51f..a941e73d0 100644 --- a/CPP/7zip/UI/FileManager/NetFolder.cpp +++ b/CPP/7zip/UI/FileManager/NetFolder.cpp @@ -1,281 +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, 0, path); - else - Init(0, 0 , L""); - return; -} - -void CNetFolder::Init(const NWindows::NNet::CResourceW *netResource, - IFolderFolder *parentFolder, const UString &path) -{ - _path = path; - if (netResource == 0) - _netResourcePointer = 0; - 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; -} - -STDMETHODIMP 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 result; - if (_netResourcePointer != 0) - result = AddConnection2(_netResource, - 0, 0, CONNECT_INTERACTIVE); - if (result != NO_ERROR) - return result; - } - - for (;;) - { - CResourceEx resource; - 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; - int pos = resource.Name.ReverseFind_PathSepar(); - if (pos >= 0) - { - // _path = resource.Name.Left(pos + 1); - resource.Name.DeleteFrontal(pos + 1); - } - _items.Add(resource); - } - else if (result == ERROR_NO_MORE_ITEMS) - break; - else - return 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; -} - - -STDMETHODIMP CNetFolder::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items.Size(); - return S_OK; -} - -STDMETHODIMP 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; -} - -STDMETHODIMP CNetFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder) -{ - *resultFolder = 0; - const CResourceEx &resource = _items[index]; - if (resource.Usage == RESOURCEUSAGE_CONNECTABLE || - resource.DisplayType == RESOURCEDISPLAYTYPE_SHARE) - { - NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder; - CMyComPtr subFolder = fsFolderSpec; - RINOK(fsFolderSpec->Init(us2fs(resource.RemoteName + WCHAR_PATH_SEPARATOR))); // , this - *resultFolder = subFolder.Detach(); - } - else - { - CNetFolder *netFolder = new CNetFolder; - CMyComPtr subFolder = netFolder; - netFolder->Init(&resource, this, resource.Name + WCHAR_PATH_SEPARATOR); - *resultFolder = subFolder.Detach(); - } - return S_OK; -} - -STDMETHODIMP CNetFolder::BindToFolder(const wchar_t * /* name */, IFolderFolder ** /* resultFolder */) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CNetFolder::BindToParentFolder(IFolderFolder **resultFolder) -{ - *resultFolder = 0; - if (_parentFolder) - { - CMyComPtr parentFolder = _parentFolder; - *resultFolder = parentFolder.Detach(); - return S_OK; - } - if (_netResourcePointer != 0) - { - CResourceW resourceParent; - DWORD result = GetResourceParent(_netResource, resourceParent); - if (result != NO_ERROR) - return result; - if (!_netResource.RemoteNameIsDefined) - return S_OK; - - CNetFolder *netFolder = new CNetFolder; - CMyComPtr subFolder = netFolder; - netFolder->Init(&resourceParent, 0, WSTRING_PATH_SEPARATOR); - *resultFolder = subFolder.Detach(); - } - return S_OK; -} - -IMP_IFolderFolder_Props(CNetFolder) - -STDMETHODIMP 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; -} - -STDMETHODIMP 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(); -} +// 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, 0, path); + else + Init(0, 0 , L""); + return; +} + +void CNetFolder::Init(const NWindows::NNet::CResourceW *netResource, + IFolderFolder *parentFolder, const UString &path) +{ + _path = path; + if (netResource == 0) + _netResourcePointer = 0; + 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; +} + +STDMETHODIMP 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 result; + if (_netResourcePointer != 0) + result = AddConnection2(_netResource, + 0, 0, CONNECT_INTERACTIVE); + if (result != NO_ERROR) + return result; + } + + for (;;) + { + CResourceEx resource; + 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; + int pos = resource.Name.ReverseFind_PathSepar(); + if (pos >= 0) + { + // _path = resource.Name.Left(pos + 1); + resource.Name.DeleteFrontal(pos + 1); + } + _items.Add(resource); + } + else if (result == ERROR_NO_MORE_ITEMS) + break; + else + return 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; +} + + +STDMETHODIMP CNetFolder::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP 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; +} + +STDMETHODIMP CNetFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder) +{ + *resultFolder = 0; + const CResourceEx &resource = _items[index]; + if (resource.Usage == RESOURCEUSAGE_CONNECTABLE || + resource.DisplayType == RESOURCEDISPLAYTYPE_SHARE) + { + NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder; + CMyComPtr subFolder = fsFolderSpec; + RINOK(fsFolderSpec->Init(us2fs(resource.RemoteName + WCHAR_PATH_SEPARATOR))); // , this + *resultFolder = subFolder.Detach(); + } + else + { + CNetFolder *netFolder = new CNetFolder; + CMyComPtr subFolder = netFolder; + netFolder->Init(&resource, this, resource.Name + WCHAR_PATH_SEPARATOR); + *resultFolder = subFolder.Detach(); + } + return S_OK; +} + +STDMETHODIMP CNetFolder::BindToFolder(const wchar_t * /* name */, IFolderFolder ** /* resultFolder */) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CNetFolder::BindToParentFolder(IFolderFolder **resultFolder) +{ + *resultFolder = 0; + if (_parentFolder) + { + CMyComPtr parentFolder = _parentFolder; + *resultFolder = parentFolder.Detach(); + return S_OK; + } + if (_netResourcePointer != 0) + { + CResourceW resourceParent; + DWORD result = GetResourceParent(_netResource, resourceParent); + if (result != NO_ERROR) + return result; + if (!_netResource.RemoteNameIsDefined) + return S_OK; + + CNetFolder *netFolder = new CNetFolder; + CMyComPtr subFolder = netFolder; + netFolder->Init(&resourceParent, 0, WSTRING_PATH_SEPARATOR); + *resultFolder = subFolder.Detach(); + } + return S_OK; +} + +IMP_IFolderFolder_Props(CNetFolder) + +STDMETHODIMP 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; +} + +STDMETHODIMP 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(); +} diff --git a/CPP/7zip/UI/FileManager/NetFolder.h b/CPP/7zip/UI/FileManager/NetFolder.h index 02b07a1cc..151dd096c 100644 --- a/CPP/7zip/UI/FileManager/NetFolder.h +++ b/CPP/7zip/UI/FileManager/NetFolder.h @@ -1,40 +1,40 @@ -// NetFolder.h - -#ifndef __NET_FOLDER_H -#define __NET_FOLDER_H - -#include "../../../Common/MyCom.h" - -#include "../../../Windows/Net.h" - -#include "IFolder.h" - -struct CResourceEx: public NWindows::NNet::CResourceW -{ - UString Name; -}; - -class CNetFolder: - public IFolderFolder, - public IFolderGetSystemIconIndex, - public CMyUnknownImp -{ - NWindows::NNet::CResourceW _netResource; - NWindows::NNet::CResourceW *_netResourcePointer; - - CObjectVector _items; - - CMyComPtr _parentFolder; - UString _path; -public: - MY_UNKNOWN_IMP1(IFolderGetSystemIconIndex) - INTERFACE_FolderFolder(;) - STDMETHOD(GetSystemIconIndex)(UInt32 index, Int32 *iconIndex); - - CNetFolder(): _netResourcePointer(0) {} - void Init(const UString &path); - void Init(const NWindows::NNet::CResourceW *netResource, - IFolderFolder *parentFolder, const UString &path); -}; - -#endif +// NetFolder.h + +#ifndef __NET_FOLDER_H +#define __NET_FOLDER_H + +#include "../../../Common/MyCom.h" + +#include "../../../Windows/Net.h" + +#include "IFolder.h" + +struct CResourceEx: public NWindows::NNet::CResourceW +{ + UString Name; +}; + +class CNetFolder: + public IFolderFolder, + public IFolderGetSystemIconIndex, + public CMyUnknownImp +{ + NWindows::NNet::CResourceW _netResource; + NWindows::NNet::CResourceW *_netResourcePointer; + + CObjectVector _items; + + CMyComPtr _parentFolder; + UString _path; +public: + MY_UNKNOWN_IMP1(IFolderGetSystemIconIndex) + INTERFACE_FolderFolder(;) + STDMETHOD(GetSystemIconIndex)(UInt32 index, Int32 *iconIndex); + + CNetFolder(): _netResourcePointer(0) {} + 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 index 638ce88b5..bf7abfb7f 100644 --- a/CPP/7zip/UI/FileManager/OpenCallback.cpp +++ b/CPP/7zip/UI/FileManager/OpenCallback.cpp @@ -1,129 +1,129 @@ -// 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; - -STDMETHODIMP COpenArchiveCallback::SetTotal(const UInt64 *numFiles, const UInt64 *numBytes) -{ - 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; -} - -STDMETHODIMP COpenArchiveCallback::SetCompleted(const UInt64 *numFiles, const UInt64 *numBytes) -{ - // NSynchronization::CCriticalSectionLock lock(_criticalSection); - if (numFiles) - ProgressDialog.Sync.Set_NumFilesCur(*numFiles); - if (numBytes) - ProgressDialog.Sync.Set_NumBytesCur(*numBytes); - return ProgressDialog.Sync.CheckStop(); -} - -STDMETHODIMP COpenArchiveCallback::SetTotal(const UInt64 total) -{ - RINOK(ProgressDialog.Sync.CheckStop()); - ProgressDialog.Sync.Set_NumBytesTotal(total); - return S_OK; -} - -STDMETHODIMP COpenArchiveCallback::SetCompleted(const UInt64 *completed) -{ - return ProgressDialog.Sync.Set_NumBytesCur(completed); -} - -STDMETHODIMP COpenArchiveCallback::GetProperty(PROPID propID, PROPVARIANT *value) -{ - NCOM::CPropVariant prop; - if (_subArchiveMode) - { - switch (propID) - { - case kpidName: prop = _subArchiveName; break; - } - } - else - { - switch (propID) - { - case kpidName: prop = _fileInfo.Name; break; - case kpidIsDir: prop = _fileInfo.IsDir(); break; - case kpidSize: prop = _fileInfo.Size; break; - case kpidAttrib: prop = (UInt32)_fileInfo.Attrib; break; - case kpidCTime: prop = _fileInfo.CTime; break; - case kpidATime: prop = _fileInfo.ATime; break; - case kpidMTime: prop = _fileInfo.MTime; break; - } - } - prop.Detach(value); - return S_OK; -} - -STDMETHODIMP COpenArchiveCallback::GetStream(const wchar_t *name, IInStream **inStream) -{ - COM_TRY_BEGIN - *inStream = NULL; - if (_subArchiveMode) - return S_FALSE; - - FString fullPath; - if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name), fullPath)) - return S_FALSE; - if (!_fileInfo.Find(fullPath)) - return S_FALSE; - if (_fileInfo.IsDir()) - return S_FALSE; - CInFileStream *inFile = new CInFileStream; - CMyComPtr inStreamTemp = inFile; - if (!inFile->Open(fullPath)) - return ::GetLastError(); - *inStream = inStreamTemp.Detach(); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP 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 -} +// 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; + +STDMETHODIMP COpenArchiveCallback::SetTotal(const UInt64 *numFiles, const UInt64 *numBytes) +{ + 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; +} + +STDMETHODIMP COpenArchiveCallback::SetCompleted(const UInt64 *numFiles, const UInt64 *numBytes) +{ + // NSynchronization::CCriticalSectionLock lock(_criticalSection); + if (numFiles) + ProgressDialog.Sync.Set_NumFilesCur(*numFiles); + if (numBytes) + ProgressDialog.Sync.Set_NumBytesCur(*numBytes); + return ProgressDialog.Sync.CheckStop(); +} + +STDMETHODIMP COpenArchiveCallback::SetTotal(const UInt64 total) +{ + RINOK(ProgressDialog.Sync.CheckStop()); + ProgressDialog.Sync.Set_NumBytesTotal(total); + return S_OK; +} + +STDMETHODIMP COpenArchiveCallback::SetCompleted(const UInt64 *completed) +{ + return ProgressDialog.Sync.Set_NumBytesCur(completed); +} + +STDMETHODIMP COpenArchiveCallback::GetProperty(PROPID propID, PROPVARIANT *value) +{ + NCOM::CPropVariant prop; + if (_subArchiveMode) + { + switch (propID) + { + case kpidName: prop = _subArchiveName; break; + } + } + else + { + switch (propID) + { + case kpidName: prop = _fileInfo.Name; break; + case kpidIsDir: prop = _fileInfo.IsDir(); break; + case kpidSize: prop = _fileInfo.Size; break; + case kpidAttrib: prop = (UInt32)_fileInfo.Attrib; break; + case kpidCTime: prop = _fileInfo.CTime; break; + case kpidATime: prop = _fileInfo.ATime; break; + case kpidMTime: prop = _fileInfo.MTime; break; + } + } + prop.Detach(value); + return S_OK; +} + +STDMETHODIMP COpenArchiveCallback::GetStream(const wchar_t *name, IInStream **inStream) +{ + COM_TRY_BEGIN + *inStream = NULL; + if (_subArchiveMode) + return S_FALSE; + + FString fullPath; + if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name), fullPath)) + return S_FALSE; + if (!_fileInfo.Find(fullPath)) + return S_FALSE; + if (_fileInfo.IsDir()) + return S_FALSE; + CInFileStream *inFile = new CInFileStream; + CMyComPtr inStreamTemp = inFile; + if (!inFile->Open(fullPath)) + return ::GetLastError(); + *inStream = inStreamTemp.Detach(); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP 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 +} diff --git a/CPP/7zip/UI/FileManager/OpenCallback.h b/CPP/7zip/UI/FileManager/OpenCallback.h index 5cc91d535..c952d7b01 100644 --- a/CPP/7zip/UI/FileManager/OpenCallback.h +++ b/CPP/7zip/UI/FileManager/OpenCallback.h @@ -1,91 +1,91 @@ -// OpenCallback.h - -#ifndef __OPEN_CALLBACK_H -#define __OPEN_CALLBACK_H - -#include "../../../Common/MyCom.h" - -#include "../../../Windows/FileFind.h" - -#include "../../IPassword.h" - -#include "../../Archive/IArchive.h" - -#ifdef _SFX -#include "ProgressDialog.h" -#else -#include "ProgressDialog2.h" -#endif - - -class COpenArchiveCallback: - public IArchiveOpenCallback, - public IArchiveOpenVolumeCallback, - public IArchiveOpenSetSubArchiveName, - public IProgress, - public ICryptoGetTextPassword, - public CMyUnknownImp -{ - FString _folderPrefix; - NWindows::NFile::NFind::CFileInfo _fileInfo; - // NWindows::NSynchronization::CCriticalSection _criticalSection; - bool _subArchiveMode; - UString _subArchiveName; - -public: - bool PasswordIsDefined; - bool PasswordWasAsked; - UString Password; - HWND ParentWindow; - CProgressDialog ProgressDialog; - - MY_UNKNOWN_IMP5( - IArchiveOpenCallback, - IArchiveOpenVolumeCallback, - IArchiveOpenSetSubArchiveName, - IProgress, - ICryptoGetTextPassword) - - INTERFACE_IProgress(;) - INTERFACE_IArchiveOpenCallback(;) - INTERFACE_IArchiveOpenVolumeCallback(;) - - // ICryptoGetTextPassword - STDMETHOD(CryptoGetTextPassword)(BSTR *password); - - STDMETHOD(SetSubArchiveName(const wchar_t *name)) - { - _subArchiveMode = true; - _subArchiveName = name; - return S_OK; - } - - COpenArchiveCallback(): - ParentWindow(0) - { - _subArchiveMode = false; - PasswordIsDefined = false; - PasswordWasAsked = false; - } - /* - void Init() - { - PasswordIsDefined = false; - _subArchiveMode = false; - } - */ - void LoadFileInfo(const FString &folderPrefix, const FString &fileName) - { - _folderPrefix = folderPrefix; - if (!_fileInfo.Find(_folderPrefix + fileName)) - throw 1; - } - void ShowMessage(const UInt64 *completed); - - INT_PTR StartProgressDialog(const UString &title, NWindows::CThread &thread) - { - return ProgressDialog.Create(title, thread, ParentWindow); - } -}; - -#endif +// OpenCallback.h + +#ifndef __OPEN_CALLBACK_H +#define __OPEN_CALLBACK_H + +#include "../../../Common/MyCom.h" + +#include "../../../Windows/FileFind.h" + +#include "../../IPassword.h" + +#include "../../Archive/IArchive.h" + +#ifdef _SFX +#include "ProgressDialog.h" +#else +#include "ProgressDialog2.h" +#endif + + +class COpenArchiveCallback: + public IArchiveOpenCallback, + public IArchiveOpenVolumeCallback, + public IArchiveOpenSetSubArchiveName, + public IProgress, + public ICryptoGetTextPassword, + public CMyUnknownImp +{ + FString _folderPrefix; + NWindows::NFile::NFind::CFileInfo _fileInfo; + // NWindows::NSynchronization::CCriticalSection _criticalSection; + bool _subArchiveMode; + UString _subArchiveName; + +public: + bool PasswordIsDefined; + bool PasswordWasAsked; + UString Password; + HWND ParentWindow; + CProgressDialog ProgressDialog; + + MY_UNKNOWN_IMP5( + IArchiveOpenCallback, + IArchiveOpenVolumeCallback, + IArchiveOpenSetSubArchiveName, + IProgress, + ICryptoGetTextPassword) + + INTERFACE_IProgress(;) + INTERFACE_IArchiveOpenCallback(;) + INTERFACE_IArchiveOpenVolumeCallback(;) + + // ICryptoGetTextPassword + STDMETHOD(CryptoGetTextPassword)(BSTR *password); + + STDMETHOD(SetSubArchiveName(const wchar_t *name)) + { + _subArchiveMode = true; + _subArchiveName = name; + return S_OK; + } + + COpenArchiveCallback(): + ParentWindow(0) + { + _subArchiveMode = false; + PasswordIsDefined = false; + PasswordWasAsked = false; + } + /* + void Init() + { + PasswordIsDefined = false; + _subArchiveMode = false; + } + */ + void LoadFileInfo(const FString &folderPrefix, const FString &fileName) + { + _folderPrefix = folderPrefix; + if (!_fileInfo.Find(_folderPrefix + fileName)) + throw 1; + } + void ShowMessage(const UInt64 *completed); + + 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 index 269f205fd..66e6f3c44 100644 --- a/CPP/7zip/UI/FileManager/OptionsDialog.cpp +++ b/CPP/7zip/UI/FileManager/OptionsDialog.cpp @@ -1,86 +1,86 @@ -// 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 */) -{ - CSystemPage systemPage; - CMenuPage menuPage; - CFoldersPage foldersPage; - CEditPage editPage; - CSettingsPage settingsPage; - CLangPage langPage; - - CObjectVector 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 < ARRAY_SIZE(pageIDs); i++) - { - NControl::CPageInfo &page = pages.AddNew(); - page.ID = pageIDs[i]; - LangString_OnlyFromLangFile(page.ID, page.Title); - page.Page = pagePointers[i]; - } - - 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(); - g_App.ReloadToolbars(); - g_App.MoveSubWindows(); // we need it to change list window aafter _toolBar.AutoSize(); - g_App.ReloadLang(); - } - - /* - 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); - } -} +// 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 */) +{ + CSystemPage systemPage; + CMenuPage menuPage; + CFoldersPage foldersPage; + CEditPage editPage; + CSettingsPage settingsPage; + CLangPage langPage; + + CObjectVector 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 < ARRAY_SIZE(pageIDs); i++) + { + NControl::CPageInfo &page = pages.AddNew(); + page.ID = pageIDs[i]; + LangString_OnlyFromLangFile(page.ID, page.Title); + page.Page = pagePointers[i]; + } + + 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(); + g_App.ReloadToolbars(); + g_App.MoveSubWindows(); // we need it to change list window aafter _toolBar.AutoSize(); + g_App.ReloadLang(); + } + + /* + 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 3f0180dec..1c0291324 100644 --- a/CPP/7zip/UI/FileManager/OverwriteDialog.cpp +++ b/CPP/7zip/UI/FileManager/OverwriteDialog.cpp @@ -1,122 +1,122 @@ -// 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 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); +} diff --git a/CPP/7zip/UI/FileManager/OverwriteDialog.h b/CPP/7zip/UI/FileManager/OverwriteDialog.h index 4564a472d..da7fa55ff 100644 --- a/CPP/7zip/UI/FileManager/OverwriteDialog.h +++ b/CPP/7zip/UI/FileManager/OverwriteDialog.h @@ -1,69 +1,69 @@ -// 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 __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 diff --git a/CPP/7zip/UI/FileManager/OverwriteDialog.rc b/CPP/7zip/UI/FileManager/OverwriteDialog.rc index 80f48b007..29f99122b 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 28bc0d0aa..b480ba163 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 index 8f1c8e50d..afb5649a1 100644 --- a/CPP/7zip/UI/FileManager/Panel.cpp +++ b/CPP/7zip/UI/FileManager/Panel.cpp @@ -1,1097 +1,1097 @@ -// Panel.cpp - -#include "StdAfx.h" - -#include -// #include - -#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 "../Agent/IFolderArchive.h" - -#include "App.h" -#include "ExtractCallback.h" -#include "FSFolder.h" -#include "FormatUtils.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() -{ - HWND h = CWindow2::GetParent(); - return (h == 0) ? _mainWindow : h; -} - -#define kClassName L"7-Zip::Panel" - - -HRESULT CPanel::Create(HWND mainWindow, HWND parentWindow, UINT id, - const UString ¤tFolderPrefix, - const UString &arcFormat, - CPanelCallback *panelCallback, CAppState *appState, - bool needOpenArc, - bool &archiveIsOpened, bool &encrypted) -{ - _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, archiveIsOpened, encrypted)); - - if (needOpenArc && !archiveIsOpened) - return S_OK; - - if (!CreateEx(0, kClassName, 0, WS_CHILD | WS_VISIBLE, - 0, 0, _xSize, 260, - parentWindow, (HMENU)(UINT_PTR)id, g_hInstance)) - return E_FAIL; - PanelCreated = true; - - return S_OK; -} - -LRESULT CPanel::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - 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; - } - } - 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); -} - -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 = 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); - - 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, 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, 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 == 0) ? (HWND)*this : _headerToolBar), - (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; - rbBand.cbSize = sizeof(REBARBANDINFO); // Required - rbBand.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE; - rbBand.fStyle = RBBS_NOGRIPPER; - rbBand.cxMinChild = size.cx; - rbBand.cyMinChild = size.cy; - rbBand.cyChild = size.cy; - rbBand.cx = size.cx; - rbBand.hwndChild = _headerToolBar; - _headerReBar.InsertBand(-1, &rbBand); - - RECT rc; - ::GetWindowRect(_headerComboBox, &rc); - rbBand.cxMinChild = 30; - rbBand.cyMinChild = 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 == 0) - 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 == 0) - 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 && - header->code == NM_RCLICK) - return OnRightClick((MY_NMLISTVIEW_NMITEMACTIVATE *)header, result); - return false; -} - -bool CPanel::OnCommand(int code, int 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(), 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"); -} - -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; - DWORD oldStyle = (DWORD)_listView.GetStyle(); - DWORD newStyle = kStyles[index]; - - // DWORD tickCount1 = GetTickCount(); - if ((oldStyle & LVS_TYPEMASK) != newStyle) - _listView.SetStyle((oldStyle & ~LVS_TYPEMASK) | 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() -{ - CRecordVector indices; - GetOperatedItemIndices(indices); - if (!Is_IO_FS_Folder()) - { - MessageBox_Error_UnsupportOperation(); - return; - } - if (indices.Size() == 0) - { - MessageBox_Error_LangID(IDS_SELECT_FILES); - return; - } - UStringVector names; - - const UString curPrefix = GetFsPath(); - UString destCurDirPrefix = curPrefix; - if (IsFSDrivesFolder()) - destCurDirPrefix = ROOT_FS_FOLDER; - - FOR_VECTOR (i, indices) - names.Add(curPrefix + GetItemRelPath2(indices[i])); - - const UString arcName = CreateArchiveName(names); - - HRESULT res = CompressFiles(destCurDirPrefix, arcName, L"", - true, // addExtension - names, false, true, false); - 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(slashPos + 1); - name = arcPath.Ptr(slashPos + 1); - } - s += GetSubFolderNameForExtract(name); - return s; -} - -void CPanel::GetFilePaths(const CRecordVector &indices, UStringVector &paths, bool allowFolders) -{ - const UString prefix = GetFsPath(); - FOR_VECTOR (i, indices) - { - int index = indices[i]; - if (!allowFolders && IsItem_Folder(index)) - { - paths.Clear(); - break; - } - paths.Add(prefix + GetItemRelPath2(index)); - } - if (paths.Size() == 0) - { - MessageBox_Error_LangID(IDS_SELECT_FILES); - return; - } -} - -void CPanel::ExtractArchives() -{ - if (_parentFolders.Size() > 0) - { - _panelCallback->OnCopy(false, false); - return; - } - CRecordVector indices; - GetOperatedItemIndices(indices); - UStringVector paths; - GetFilePaths(indices, paths); - if (paths.IsEmpty()) - return; - - UString outFolder = GetFsPath(); - if (indices.Size() == 1) - outFolder += GetSubFolderNameForExtract2(GetItemRelPath(indices[0])); - else - outFolder += '*'; - outFolder.Add_PathSepar(); - - ::ExtractArchives(paths, outFolder - , true // showDialog - , false // elimDup - ); -} - -/* -static void AddValuePair(UINT resourceID, UInt64 value, UString &s) -{ - AddLangString(s, resourceID); - char sz[32]; - s += ": "; - ConvertUInt64ToString(value, sz); - s += sz; - s.Add_LF(); -} -*/ - -class CThreadTest: public CProgressThreadVirt -{ - HRESULT ProcessVirt(); -public: - CRecordVector Indices; - CExtractCallbackImp *ExtractCallbackSpec; - CMyComPtr ExtractCallback; - CMyComPtr ArchiveFolder; -}; - -// actually now we don't need CThreadTest, since now we call CopyTo for "test command - -/* -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 indices; - GetOperatedIndicesSmart(indices); - CMyComPtr 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; - - 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, true); - if (paths.IsEmpty()) - return; - ::TestArchives(paths); -} +// Panel.cpp + +#include "StdAfx.h" + +#include +// #include + +#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 "../Agent/IFolderArchive.h" + +#include "App.h" +#include "ExtractCallback.h" +#include "FSFolder.h" +#include "FormatUtils.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() +{ + HWND h = CWindow2::GetParent(); + return (h == 0) ? _mainWindow : h; +} + +#define kClassName L"7-Zip::Panel" + + +HRESULT CPanel::Create(HWND mainWindow, HWND parentWindow, UINT id, + const UString ¤tFolderPrefix, + const UString &arcFormat, + CPanelCallback *panelCallback, CAppState *appState, + bool needOpenArc, + bool &archiveIsOpened, bool &encrypted) +{ + _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, archiveIsOpened, encrypted)); + + if (needOpenArc && !archiveIsOpened) + return S_OK; + + if (!CreateEx(0, kClassName, 0, WS_CHILD | WS_VISIBLE, + 0, 0, _xSize, 260, + parentWindow, (HMENU)(UINT_PTR)id, g_hInstance)) + return E_FAIL; + PanelCreated = true; + + return S_OK; +} + +LRESULT CPanel::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + 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; + } + } + 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); +} + +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 = 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); + + 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, 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, 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 == 0) ? (HWND)*this : _headerToolBar), + (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; + rbBand.cbSize = sizeof(REBARBANDINFO); // Required + rbBand.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE; + rbBand.fStyle = RBBS_NOGRIPPER; + rbBand.cxMinChild = size.cx; + rbBand.cyMinChild = size.cy; + rbBand.cyChild = size.cy; + rbBand.cx = size.cx; + rbBand.hwndChild = _headerToolBar; + _headerReBar.InsertBand(-1, &rbBand); + + RECT rc; + ::GetWindowRect(_headerComboBox, &rc); + rbBand.cxMinChild = 30; + rbBand.cyMinChild = 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 == 0) + 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 == 0) + 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 && + header->code == NM_RCLICK) + return OnRightClick((MY_NMLISTVIEW_NMITEMACTIVATE *)header, result); + return false; +} + +bool CPanel::OnCommand(int code, int 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(), 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"); +} + +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; + DWORD oldStyle = (DWORD)_listView.GetStyle(); + DWORD newStyle = kStyles[index]; + + // DWORD tickCount1 = GetTickCount(); + if ((oldStyle & LVS_TYPEMASK) != newStyle) + _listView.SetStyle((oldStyle & ~LVS_TYPEMASK) | 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() +{ + CRecordVector indices; + GetOperatedItemIndices(indices); + if (!Is_IO_FS_Folder()) + { + MessageBox_Error_UnsupportOperation(); + return; + } + if (indices.Size() == 0) + { + MessageBox_Error_LangID(IDS_SELECT_FILES); + return; + } + UStringVector names; + + const UString curPrefix = GetFsPath(); + UString destCurDirPrefix = curPrefix; + if (IsFSDrivesFolder()) + destCurDirPrefix = ROOT_FS_FOLDER; + + FOR_VECTOR (i, indices) + names.Add(curPrefix + GetItemRelPath2(indices[i])); + + const UString arcName = CreateArchiveName(names); + + HRESULT res = CompressFiles(destCurDirPrefix, arcName, L"", + true, // addExtension + names, false, true, false); + 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(slashPos + 1); + name = arcPath.Ptr(slashPos + 1); + } + s += GetSubFolderNameForExtract(name); + return s; +} + +void CPanel::GetFilePaths(const CRecordVector &indices, UStringVector &paths, bool allowFolders) +{ + const UString prefix = GetFsPath(); + FOR_VECTOR (i, indices) + { + int index = indices[i]; + if (!allowFolders && IsItem_Folder(index)) + { + paths.Clear(); + break; + } + paths.Add(prefix + GetItemRelPath2(index)); + } + if (paths.Size() == 0) + { + MessageBox_Error_LangID(IDS_SELECT_FILES); + return; + } +} + +void CPanel::ExtractArchives() +{ + if (_parentFolders.Size() > 0) + { + _panelCallback->OnCopy(false, false); + return; + } + CRecordVector indices; + GetOperatedItemIndices(indices); + UStringVector paths; + GetFilePaths(indices, paths); + if (paths.IsEmpty()) + return; + + UString outFolder = GetFsPath(); + if (indices.Size() == 1) + outFolder += GetSubFolderNameForExtract2(GetItemRelPath(indices[0])); + else + outFolder += '*'; + outFolder.Add_PathSepar(); + + ::ExtractArchives(paths, outFolder + , true // showDialog + , false // elimDup + ); +} + +/* +static void AddValuePair(UINT resourceID, UInt64 value, UString &s) +{ + AddLangString(s, resourceID); + char sz[32]; + s += ": "; + ConvertUInt64ToString(value, sz); + s += sz; + s.Add_LF(); +} +*/ + +class CThreadTest: public CProgressThreadVirt +{ + HRESULT ProcessVirt(); +public: + CRecordVector Indices; + CExtractCallbackImp *ExtractCallbackSpec; + CMyComPtr ExtractCallback; + CMyComPtr ArchiveFolder; +}; + +// actually now we don't need CThreadTest, since now we call CopyTo for "test command + +/* +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 indices; + GetOperatedIndicesSmart(indices); + CMyComPtr 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; + + 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, true); + if (paths.IsEmpty()) + return; + ::TestArchives(paths); +} diff --git a/CPP/7zip/UI/FileManager/Panel.h b/CPP/7zip/UI/FileManager/Panel.h index dd217ec38..03882344e 100644 --- a/CPP/7zip/UI/FileManager/Panel.h +++ b/CPP/7zip/UI/FileManager/Panel.h @@ -1,902 +1,902 @@ -// Panel.h - -#ifndef __PANEL_H -#define __PANEL_H - -#include "../../../Common/MyWindows.h" - -#include - -#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 int kParentIndex = -1; - -#if !defined(_WIN32) || defined(UNDER_CE) -#define ROOT_FS_FOLDER L"\\" -#else -#define ROOT_FS_FOLDER L"C:\\" -#endif - -struct 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; -}; - -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 -{ -public: - int FindItem_for_PropID(PROPID id) const - { - FOR_VECTOR (i, (*this)) - if ((*this)[i].ID == id) - return 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 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: public NWindows::NControl::CListView2 -{ -public: - CPanel *_panel; - LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); -}; - -/* -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; - UString FocusedName; - UStringVector SelectedNames; - - CSelectedState(): FocusedItem(-1), FocusedName_Defined(false), SelectFocused(true) {} -}; - -#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; - - UString folder; - - UStringVector hashMethods; - - CVirtFileSystem *VirtFileSystemSpec; - ISequentialOutStream *VirtFileSystem; - - CCopyToOptions(): - streamMode(false), - moveMode(false), - testMode(false), - includeAltStreams(true), - replaceAltStreamChars(false), - showErrorMessages(false), - VirtFileSystemSpec(NULL), - VirtFileSystem(NULL) - {} -}; - - -class CPanel: public NWindows::NControl::CWindow2 -{ - CExtToIconMap _extToIconMap; - UINT _baseID; - int _comboBoxID; - UINT _statusBarID; - - CAppState *_appState; - - bool OnCommand(int code, int itemID, LPARAM lParam, LRESULT &result); - LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); - virtual bool OnCreate(CREATESTRUCT *createStruct); - virtual bool OnSize(WPARAM wParam, int xSize, int ySize); - virtual void OnDestroy(); - virtual bool OnNotify(UINT controlID, LPNMHDR lParam, LRESULT &result); - - 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 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 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(); - - UInt32 GetRealIndex(const LVITEMW &item) const - { - /* - if (_virtualMode) - return _realIndices[item.iItem]; - */ - return (UInt32)item.lParam; - } - - int GetRealItemIndex(int indexInListView) const - { - /* - if (_virtualMode) - return indexInListView; - */ - LPARAM param; - if (!_listView.GetItemParam(indexInListView, param)) - throw 1; - return (int)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 _parentFolders; - NWindows::NDLL::CLibrary _library; - - CMyComPtr _folder; - CMyComPtr _folderCompare; - CMyComPtr _folderGetItemName; - CMyComPtr _folderRawProps; - CMyComPtr _folderAltStreams; - CMyComPtr _folderOperations; - - void ReleaseFolder(); - void SetNewFolder(IFolderFolder *newFolder); - - // CMyComPtr _folderGetSystemIconIndex; - - UStringVector _fastFolders; - - void GetSelectedNames(UStringVector &selectedNames); - void SaveSelectedState(CSelectedState &s); - HRESULT RefreshListCtrl(const CSelectedState &s); - HRESULT RefreshListCtrl_SaveFocused(); - - bool GetItem_BoolProp(UInt32 itemIndex, PROPID propID) const; - bool IsItem_Deleted(int itemIndex) const; - bool IsItem_Folder(int itemIndex) const; - bool IsItem_AltStream(int itemIndex) const; - - UString GetItemName(int itemIndex) const; - UString GetItemName_for_Copy(int itemIndex) const; - void GetItemName(int itemIndex, UString &s) const; - UString GetItemPrefix(int itemIndex) const; - UString GetItemRelPath(int itemIndex) const; - UString GetItemRelPath2(int itemIndex) const; - UString GetItemFullPath(int itemIndex) const; - UInt64 GetItem_UInt64Prop(int itemIndex, PROPID propID) const; - UInt64 GetItemSize(int itemIndex) const; - - //////////////////////// - // PanelFolderChange.cpp - - void SetToRootFolder(); - HRESULT BindToPath(const UString &fullPath, const UString &arcFormat, bool &archiveIsOpened, bool &encrypted); // 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 ¤tFolderPrefix, - const UString &arcFormat, - CPanelCallback *panelCallback, - CAppState *appState, - bool needOpenArc, - bool &archiveIsOpened, bool &encrypted); - void SetFocusToList(); - void SetFocusToLastRememberedItem(); - - - void SaveListViewInfo(); - - CPanel() : - // _virtualMode(flase), - _exStyle(0), - _showDots(false), - _showRealFileIcons(false), - _needSaveInfo(false), - _startGroupSelect(0), - _selectionIsDefined(false), - _ListViewMode(3), - _flatMode(false), - _flatModeForDisk(false), - _flatModeForArc(false), - PanelCreated(false), - _thereAre_ListView_Items(false), - - // _showNtfsStrems_Mode(false), - // _showNtfsStrems_ModeForDisk(false), - // _showNtfsStrems_ModeForArc(false), - - _xSize(300), - _mySelectMode(false), - _thereAreDeletedItems(false), - _markDeletedItems(true), - _enableItemChangeNotify(true), - _dontShowMode(false), - - _timestampLevel(kTimestampPrintLevel_MIN) - {} - - void SetExtendedStyle() - { - if (_listView != 0) - _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(); - 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 OnContextMenu(HANDLE windowHandle, int xPos, int yPos); - - CMyComPtr _sevenZipContextMenu; - CMyComPtr _systemContextMenu; - HRESULT CreateShellContextMenu( - const CRecordVector &operatedIndices, - CMyComPtr &systemContextMenu); - void CreateSystemMenu(HMENU menu, - const CRecordVector &operatedIndices, - CMyComPtr &systemContextMenu); - void CreateSevenZipMenu(HMENU menu, - const CRecordVector &operatedIndices, - CMyComPtr &sevenZipContextMenu); - void CreateFileMenu(HMENU menu, - CMyComPtr &sevenZipContextMenu, - CMyComPtr &systemContextMenu, - bool programMenu); - void CreateFileMenu(HMENU menu); - bool InvokePluginCommand(int id); - bool InvokePluginCommand(int 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 GetSelectedItemsIndices(CRecordVector &indices) const; - void GetOperatedItemIndices(CRecordVector &indices) const; - void GetAllItemIndices(CRecordVector &indices) const; - void GetOperatedIndicesSmart(CRecordVector &indices) const; - // void GetOperatedListViewIndices(CRecordVector &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; - - /* - 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 - { - 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 CDisableNotify - { - 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; - } - }; - - // bool _passwordIsDefined; - // UString _password; - - 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(int index); - - void OpenFolder(int index); - HRESULT OpenParentArchiveFolder(); - - HRESULT OpenAsArc(IInStream *inStream, - const CTempFileInfo &tempFileInfo, - const UString &virtualFilePath, - const UString &arcFormat, - bool &encrypted); - - HRESULT OpenAsArc_Msg(IInStream *inStream, - const CTempFileInfo &tempFileInfo, - const UString &virtualFilePath, - const UString &arcFormat, - bool &encrypted, - bool showErrorMessage); - - HRESULT OpenAsArc_Name(const UString &relPath, const UString &arcFormat, bool &encrypted, bool showErrorMessage); - HRESULT OpenAsArc_Index(int index, const wchar_t *type /* = NULL */, bool showErrorMessage); - - void OpenItemInArchive(int 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(int index, bool tryInternal, bool tryExternal, const wchar_t *type = NULL); - void EditItem(bool useEditor); - void EditItem(int 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(); - - void GetFilePaths(const CRecordVector &indices, UStringVector &paths, bool allowFolders = false); - void ExtractArchives(); - void TestArchives(); - - HRESULT CopyTo(CCopyToOptions &options, - const CRecordVector &indices, - UStringVector *messages, - bool &usePassword, UString &password); - - HRESULT CopyTo(CCopyToOptions &options, const CRecordVector &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 CopyFrom(bool moveMode, const UString &folderPrefix, const UStringVector &filePaths, - bool showErrorMessages, UStringVector *messages); - - void CopyFromNoAsk(const UStringVector &filePaths); - void CopyFromAsk(const UStringVector &filePaths); - - // empty folderPath means create new Archive to path of first fileName. - void DropObject(IDataObject * dataObject, const UString &folderPath); - - // empty folderPath means create new Archive to path of first fileName. - void CompressDropFiles(const UStringVector &fileNames, const UString &folderPath); - - void RefreshTitle(bool always = false) { _panelCallback->RefreshTitle(always); } - void RefreshTitleAlways() { RefreshTitle(true); } - - UString GetItemsInfoString(const CRecordVector &indices); -}; - -class CMyBuffer -{ - void *_data; -public: - CMyBuffer(): _data(0) {} - operator void *() { return _data; } - bool Allocate(size_t size) - { - if (_data != 0) - return false; - _data = ::MidAlloc(size); - return _data != 0; - } - ~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 +// Panel.h + +#ifndef __PANEL_H +#define __PANEL_H + +#include "../../../Common/MyWindows.h" + +#include + +#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 int kParentIndex = -1; + +#if !defined(_WIN32) || defined(UNDER_CE) +#define ROOT_FS_FOLDER L"\\" +#else +#define ROOT_FS_FOLDER L"C:\\" +#endif + +struct 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; +}; + +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 +{ +public: + int FindItem_for_PropID(PROPID id) const + { + FOR_VECTOR (i, (*this)) + if ((*this)[i].ID == id) + return 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 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: public NWindows::NControl::CListView2 +{ +public: + CPanel *_panel; + LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); +}; + +/* +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; + UString FocusedName; + UStringVector SelectedNames; + + CSelectedState(): FocusedItem(-1), FocusedName_Defined(false), SelectFocused(true) {} +}; + +#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; + + UString folder; + + UStringVector hashMethods; + + CVirtFileSystem *VirtFileSystemSpec; + ISequentialOutStream *VirtFileSystem; + + CCopyToOptions(): + streamMode(false), + moveMode(false), + testMode(false), + includeAltStreams(true), + replaceAltStreamChars(false), + showErrorMessages(false), + VirtFileSystemSpec(NULL), + VirtFileSystem(NULL) + {} +}; + + +class CPanel: public NWindows::NControl::CWindow2 +{ + CExtToIconMap _extToIconMap; + UINT _baseID; + int _comboBoxID; + UINT _statusBarID; + + CAppState *_appState; + + bool OnCommand(int code, int itemID, LPARAM lParam, LRESULT &result); + LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); + virtual bool OnCreate(CREATESTRUCT *createStruct); + virtual bool OnSize(WPARAM wParam, int xSize, int ySize); + virtual void OnDestroy(); + virtual bool OnNotify(UINT controlID, LPNMHDR lParam, LRESULT &result); + + 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 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 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(); + + UInt32 GetRealIndex(const LVITEMW &item) const + { + /* + if (_virtualMode) + return _realIndices[item.iItem]; + */ + return (UInt32)item.lParam; + } + + int GetRealItemIndex(int indexInListView) const + { + /* + if (_virtualMode) + return indexInListView; + */ + LPARAM param; + if (!_listView.GetItemParam(indexInListView, param)) + throw 1; + return (int)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 _parentFolders; + NWindows::NDLL::CLibrary _library; + + CMyComPtr _folder; + CMyComPtr _folderCompare; + CMyComPtr _folderGetItemName; + CMyComPtr _folderRawProps; + CMyComPtr _folderAltStreams; + CMyComPtr _folderOperations; + + void ReleaseFolder(); + void SetNewFolder(IFolderFolder *newFolder); + + // CMyComPtr _folderGetSystemIconIndex; + + UStringVector _fastFolders; + + void GetSelectedNames(UStringVector &selectedNames); + void SaveSelectedState(CSelectedState &s); + HRESULT RefreshListCtrl(const CSelectedState &s); + HRESULT RefreshListCtrl_SaveFocused(); + + bool GetItem_BoolProp(UInt32 itemIndex, PROPID propID) const; + bool IsItem_Deleted(int itemIndex) const; + bool IsItem_Folder(int itemIndex) const; + bool IsItem_AltStream(int itemIndex) const; + + UString GetItemName(int itemIndex) const; + UString GetItemName_for_Copy(int itemIndex) const; + void GetItemName(int itemIndex, UString &s) const; + UString GetItemPrefix(int itemIndex) const; + UString GetItemRelPath(int itemIndex) const; + UString GetItemRelPath2(int itemIndex) const; + UString GetItemFullPath(int itemIndex) const; + UInt64 GetItem_UInt64Prop(int itemIndex, PROPID propID) const; + UInt64 GetItemSize(int itemIndex) const; + + //////////////////////// + // PanelFolderChange.cpp + + void SetToRootFolder(); + HRESULT BindToPath(const UString &fullPath, const UString &arcFormat, bool &archiveIsOpened, bool &encrypted); // 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 ¤tFolderPrefix, + const UString &arcFormat, + CPanelCallback *panelCallback, + CAppState *appState, + bool needOpenArc, + bool &archiveIsOpened, bool &encrypted); + void SetFocusToList(); + void SetFocusToLastRememberedItem(); + + + void SaveListViewInfo(); + + CPanel() : + // _virtualMode(flase), + _exStyle(0), + _showDots(false), + _showRealFileIcons(false), + _needSaveInfo(false), + _startGroupSelect(0), + _selectionIsDefined(false), + _ListViewMode(3), + _flatMode(false), + _flatModeForDisk(false), + _flatModeForArc(false), + PanelCreated(false), + _thereAre_ListView_Items(false), + + // _showNtfsStrems_Mode(false), + // _showNtfsStrems_ModeForDisk(false), + // _showNtfsStrems_ModeForArc(false), + + _xSize(300), + _mySelectMode(false), + _thereAreDeletedItems(false), + _markDeletedItems(true), + _enableItemChangeNotify(true), + _dontShowMode(false), + + _timestampLevel(kTimestampPrintLevel_MIN) + {} + + void SetExtendedStyle() + { + if (_listView != 0) + _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(); + 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 OnContextMenu(HANDLE windowHandle, int xPos, int yPos); + + CMyComPtr _sevenZipContextMenu; + CMyComPtr _systemContextMenu; + HRESULT CreateShellContextMenu( + const CRecordVector &operatedIndices, + CMyComPtr &systemContextMenu); + void CreateSystemMenu(HMENU menu, + const CRecordVector &operatedIndices, + CMyComPtr &systemContextMenu); + void CreateSevenZipMenu(HMENU menu, + const CRecordVector &operatedIndices, + CMyComPtr &sevenZipContextMenu); + void CreateFileMenu(HMENU menu, + CMyComPtr &sevenZipContextMenu, + CMyComPtr &systemContextMenu, + bool programMenu); + void CreateFileMenu(HMENU menu); + bool InvokePluginCommand(int id); + bool InvokePluginCommand(int 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 GetSelectedItemsIndices(CRecordVector &indices) const; + void GetOperatedItemIndices(CRecordVector &indices) const; + void GetAllItemIndices(CRecordVector &indices) const; + void GetOperatedIndicesSmart(CRecordVector &indices) const; + // void GetOperatedListViewIndices(CRecordVector &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; + + /* + 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 + { + 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 CDisableNotify + { + 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; + } + }; + + // bool _passwordIsDefined; + // UString _password; + + 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(int index); + + void OpenFolder(int index); + HRESULT OpenParentArchiveFolder(); + + HRESULT OpenAsArc(IInStream *inStream, + const CTempFileInfo &tempFileInfo, + const UString &virtualFilePath, + const UString &arcFormat, + bool &encrypted); + + HRESULT OpenAsArc_Msg(IInStream *inStream, + const CTempFileInfo &tempFileInfo, + const UString &virtualFilePath, + const UString &arcFormat, + bool &encrypted, + bool showErrorMessage); + + HRESULT OpenAsArc_Name(const UString &relPath, const UString &arcFormat, bool &encrypted, bool showErrorMessage); + HRESULT OpenAsArc_Index(int index, const wchar_t *type /* = NULL */, bool showErrorMessage); + + void OpenItemInArchive(int 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(int index, bool tryInternal, bool tryExternal, const wchar_t *type = NULL); + void EditItem(bool useEditor); + void EditItem(int 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(); + + void GetFilePaths(const CRecordVector &indices, UStringVector &paths, bool allowFolders = false); + void ExtractArchives(); + void TestArchives(); + + HRESULT CopyTo(CCopyToOptions &options, + const CRecordVector &indices, + UStringVector *messages, + bool &usePassword, UString &password); + + HRESULT CopyTo(CCopyToOptions &options, const CRecordVector &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 CopyFrom(bool moveMode, const UString &folderPrefix, const UStringVector &filePaths, + bool showErrorMessages, UStringVector *messages); + + void CopyFromNoAsk(const UStringVector &filePaths); + void CopyFromAsk(const UStringVector &filePaths); + + // empty folderPath means create new Archive to path of first fileName. + void DropObject(IDataObject * dataObject, const UString &folderPath); + + // empty folderPath means create new Archive to path of first fileName. + void CompressDropFiles(const UStringVector &fileNames, const UString &folderPath); + + void RefreshTitle(bool always = false) { _panelCallback->RefreshTitle(always); } + void RefreshTitleAlways() { RefreshTitle(true); } + + UString GetItemsInfoString(const CRecordVector &indices); +}; + +class CMyBuffer +{ + void *_data; +public: + CMyBuffer(): _data(0) {} + operator void *() { return _data; } + bool Allocate(size_t size) + { + if (_data != 0) + return false; + _data = ::MidAlloc(size); + return _data != 0; + } + ~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 index e0640eff6..c3416cc7d 100644 --- a/CPP/7zip/UI/FileManager/PanelCopy.cpp +++ b/CPP/7zip/UI/FileManager/PanelCopy.cpp @@ -1,393 +1,393 @@ -/// PanelCopy.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyException.h" - -#include "../GUI/HashGUI.h" - -#include "ExtractCallback.h" -#include "LangUtils.h" -#include "Panel.h" -#include "resource.h" -#include "UpdateCallback100.h" - -using namespace NWindows; - -class CPanelCopyThread: public CProgressThreadVirt -{ - bool ResultsWereShown; - bool NeedShowRes; - - HRESULT ProcessVirt(); - virtual void ProcessWasFinished_GuiVirt(); -public: - const CCopyToOptions *options; - CMyComPtr FolderOperations; - CRecordVector Indices; - CExtractCallbackImp *ExtractCallbackSpec; - CMyComPtr ExtractCallback; - - CHashBundle Hash; - // UString FirstFilePath; - - HRESULT Result; - - void ShowFinalResults(HWND hwnd); - - CPanelCopyThread(): - Result(E_FAIL), - ResultsWereShown(false), - NeedShowRes(false) - {} -}; - -void CPanelCopyThread::ShowFinalResults(HWND hwnd) -{ - if (NeedShowRes) - if (!ResultsWereShown) - { - ResultsWereShown = true; - ShowHashResults(Hash, hwnd); - } -} - -void CPanelCopyThread::ProcessWasFinished_GuiVirt() -{ - ShowFinalResults(*this); -} - -HRESULT CPanelCopyThread::ProcessVirt() -{ - /* - CMyComPtr iReplace; - FolderOperations.QueryInterface(IID_IFolderSetReplaceAltStreamCharsMode, &iReplace); - if (iReplace) - { - RINOK(iReplace->SetReplaceAltStreamCharsMode(ReplaceAltStreamChars ? 1 : 0)); - } - */ - - if (options->testMode) - { - CMyComPtr archiveFolder; - FolderOperations.QueryInterface(IID_IArchiveFolder, &archiveFolder); - if (!archiveFolder) - return E_NOTIMPL; - CMyComPtr extractCallback2; - RINOK(ExtractCallback.QueryInterface(IID_IFolderArchiveExtractCallback, &extractCallback2)); - NExtract::NPathMode::EEnum pathMode = - NExtract::NPathMode::kCurPaths; - // NExtract::NPathMode::kFullPathnames; - Result = archiveFolder->Extract(&Indices.Front(), Indices.Size(), - BoolToInt(options->includeAltStreams), - BoolToInt(options->replaceAltStreamChars), - pathMode, NExtract::NOverwriteMode::kAsk, - options->folder, BoolToInt(true), extractCallback2); - } - else - Result = FolderOperations->CopyTo( - BoolToInt(options->moveMode), - &Indices.Front(), Indices.Size(), - BoolToInt(options->includeAltStreams), - BoolToInt(options->replaceAltStreamChars), - options->folder, ExtractCallback); - - if (Result == 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 Result; -} - - -/* -#ifdef EXTERNAL_CODECS - -static void ThrowException_if_Error(HRESULT res) -{ - if (res != S_OK) - throw CSystemException(res); -} - -#endif -*/ - -HRESULT CPanel::CopyTo(CCopyToOptions &options, const CRecordVector &indices, - UStringVector *messages, - bool &usePassword, UString &password) -{ - if (!_folderOperations) - { - 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 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 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); - } - - 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.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.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 FolderOperations; - UString FolderPrefix; - UStringVector FileNames; - CRecordVector FileNamePointers; - CProgressDialog ProgressDialog; - CMyComPtr 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) -{ - // 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; - - UString title = LangString(IDS_COPYING); - 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; - RINOK(thread.Create(CThreadUpdate::MyThreadFunction, &updater)); - updater.ProgressDialog.Create(title, thread, GetParent()); - - if (messages) - *messages = updater.ProgressDialog.Sync.Messages; - - res = updater.Result; - } - - if (res == E_NOINTERFACE) - { - 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(const UStringVector &filePaths) -{ - CDisableTimerProcessing disableTimerProcessing(*this); - - CSelectedState srcSelState; - SaveSelectedState(srcSelState); - - CDisableNotify disableNotify(*this); - - HRESULT result = CopyFrom(false, L"", filePaths, true, 0); - - if (result != S_OK) - { - disableNotify.Restore(); - // For Password: - SetFocusToList(); - if (result != E_ABORT) - MessageBox_Error_HRESULT(result); - return; - } - - RefreshListCtrl(srcSelState); - - disableNotify.Restore(); - SetFocusToList(); -} - -void CPanel::CopyFromAsk(const UStringVector &filePaths) -{ - UString title = LangString(IDS_CONFIRM_FILE_COPY); - UString message = LangString(IDS_WANT_TO_COPY_FILES); - message += "\n\'"; - message += _currentFolderPrefix; - message += "\' ?"; - int res = ::MessageBoxW(*(this), message, title, MB_YESNOCANCEL | MB_ICONQUESTION); - if (res != IDYES) - return; - - CopyFromNoAsk(filePaths); -} +/// PanelCopy.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyException.h" + +#include "../GUI/HashGUI.h" + +#include "ExtractCallback.h" +#include "LangUtils.h" +#include "Panel.h" +#include "resource.h" +#include "UpdateCallback100.h" + +using namespace NWindows; + +class CPanelCopyThread: public CProgressThreadVirt +{ + bool ResultsWereShown; + bool NeedShowRes; + + HRESULT ProcessVirt(); + virtual void ProcessWasFinished_GuiVirt(); +public: + const CCopyToOptions *options; + CMyComPtr FolderOperations; + CRecordVector Indices; + CExtractCallbackImp *ExtractCallbackSpec; + CMyComPtr ExtractCallback; + + CHashBundle Hash; + // UString FirstFilePath; + + HRESULT Result; + + void ShowFinalResults(HWND hwnd); + + CPanelCopyThread(): + Result(E_FAIL), + ResultsWereShown(false), + NeedShowRes(false) + {} +}; + +void CPanelCopyThread::ShowFinalResults(HWND hwnd) +{ + if (NeedShowRes) + if (!ResultsWereShown) + { + ResultsWereShown = true; + ShowHashResults(Hash, hwnd); + } +} + +void CPanelCopyThread::ProcessWasFinished_GuiVirt() +{ + ShowFinalResults(*this); +} + +HRESULT CPanelCopyThread::ProcessVirt() +{ + /* + CMyComPtr iReplace; + FolderOperations.QueryInterface(IID_IFolderSetReplaceAltStreamCharsMode, &iReplace); + if (iReplace) + { + RINOK(iReplace->SetReplaceAltStreamCharsMode(ReplaceAltStreamChars ? 1 : 0)); + } + */ + + if (options->testMode) + { + CMyComPtr archiveFolder; + FolderOperations.QueryInterface(IID_IArchiveFolder, &archiveFolder); + if (!archiveFolder) + return E_NOTIMPL; + CMyComPtr extractCallback2; + RINOK(ExtractCallback.QueryInterface(IID_IFolderArchiveExtractCallback, &extractCallback2)); + NExtract::NPathMode::EEnum pathMode = + NExtract::NPathMode::kCurPaths; + // NExtract::NPathMode::kFullPathnames; + Result = archiveFolder->Extract(&Indices.Front(), Indices.Size(), + BoolToInt(options->includeAltStreams), + BoolToInt(options->replaceAltStreamChars), + pathMode, NExtract::NOverwriteMode::kAsk, + options->folder, BoolToInt(true), extractCallback2); + } + else + Result = FolderOperations->CopyTo( + BoolToInt(options->moveMode), + &Indices.Front(), Indices.Size(), + BoolToInt(options->includeAltStreams), + BoolToInt(options->replaceAltStreamChars), + options->folder, ExtractCallback); + + if (Result == 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 Result; +} + + +/* +#ifdef EXTERNAL_CODECS + +static void ThrowException_if_Error(HRESULT res) +{ + if (res != S_OK) + throw CSystemException(res); +} + +#endif +*/ + +HRESULT CPanel::CopyTo(CCopyToOptions &options, const CRecordVector &indices, + UStringVector *messages, + bool &usePassword, UString &password) +{ + if (!_folderOperations) + { + 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 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 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); + } + + 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.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.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 FolderOperations; + UString FolderPrefix; + UStringVector FileNames; + CRecordVector FileNamePointers; + CProgressDialog ProgressDialog; + CMyComPtr 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) +{ + // 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; + + UString title = LangString(IDS_COPYING); + 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; + RINOK(thread.Create(CThreadUpdate::MyThreadFunction, &updater)); + updater.ProgressDialog.Create(title, thread, GetParent()); + + if (messages) + *messages = updater.ProgressDialog.Sync.Messages; + + res = updater.Result; + } + + if (res == E_NOINTERFACE) + { + 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(const UStringVector &filePaths) +{ + CDisableTimerProcessing disableTimerProcessing(*this); + + CSelectedState srcSelState; + SaveSelectedState(srcSelState); + + CDisableNotify disableNotify(*this); + + HRESULT result = CopyFrom(false, L"", filePaths, true, 0); + + if (result != S_OK) + { + disableNotify.Restore(); + // For Password: + SetFocusToList(); + if (result != E_ABORT) + MessageBox_Error_HRESULT(result); + return; + } + + RefreshListCtrl(srcSelState); + + disableNotify.Restore(); + SetFocusToList(); +} + +void CPanel::CopyFromAsk(const UStringVector &filePaths) +{ + UString title = LangString(IDS_CONFIRM_FILE_COPY); + UString message = LangString(IDS_WANT_TO_COPY_FILES); + message += "\n\'"; + message += _currentFolderPrefix; + message += "\' ?"; + int res = ::MessageBoxW(*(this), message, title, MB_YESNOCANCEL | MB_ICONQUESTION); + if (res != IDYES) + return; + + CopyFromNoAsk(filePaths); +} diff --git a/CPP/7zip/UI/FileManager/PanelCrc.cpp b/CPP/7zip/UI/FileManager/PanelCrc.cpp index 94c41e973..1cfbfe5d5 100644 --- a/CPP/7zip/UI/FileManager/PanelCrc.cpp +++ b/CPP/7zip/UI/FileManager/PanelCrc.cpp @@ -1,421 +1,421 @@ -// 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 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 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() -{ - DWORD error = GetLastError(); - return (error == 0) ? 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++]; - int pos = path.ReverseFind_PathSepar(); - if (pos >= 0) - resPath.SetFrom(path, 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)) - { - DWORD error = GetNormalizedError(); - resPath = path; - return error; - } - - break; - } - - bool found; - - if (Enumerators.Back().Next(fi, found)) - { - if (found) - { - resPath = Prefixes.Back(); - break; - } - } - else - { - 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(); - virtual void ProcessWasFinished_GuiVirt(); -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(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; - 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 = 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 indices; - srcPanel.GetOperatedIndicesSmart(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); - - UStringVector messages; - return srcPanel.CopyTo(options, indices, &messages); - } - - #ifdef 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 = t.Enumerator.FilePaths[0]; - - UString basePrefix = srcPanel.GetFsPath(); - UString basePrefix2 = basePrefix; - if (basePrefix2.Back() == ':') - { - int pos = basePrefix2.ReverseFind_PathSepar(); - if (pos >= 0) - basePrefix2.DeleteFrom(pos + 1); - } - - t.Enumerator.BasePrefix = us2fs(basePrefix); - t.Enumerator.BasePrefix_for_Open = us2fs(basePrefix2); - - t.Enumerator.EnterToDirs = !GetFlatMode(); - - t.ShowCompressionInfo = false; - - 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); - } -} +// 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 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 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() +{ + DWORD error = GetLastError(); + return (error == 0) ? 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++]; + int pos = path.ReverseFind_PathSepar(); + if (pos >= 0) + resPath.SetFrom(path, 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)) + { + DWORD error = GetNormalizedError(); + resPath = path; + return error; + } + + break; + } + + bool found; + + if (Enumerators.Back().Next(fi, found)) + { + if (found) + { + resPath = Prefixes.Back(); + break; + } + } + else + { + 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(); + virtual void ProcessWasFinished_GuiVirt(); +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(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; + 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 = 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 indices; + srcPanel.GetOperatedIndicesSmart(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); + + UStringVector messages; + return srcPanel.CopyTo(options, indices, &messages); + } + + #ifdef 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 = t.Enumerator.FilePaths[0]; + + UString basePrefix = srcPanel.GetFsPath(); + UString basePrefix2 = basePrefix; + if (basePrefix2.Back() == ':') + { + int pos = basePrefix2.ReverseFind_PathSepar(); + if (pos >= 0) + basePrefix2.DeleteFrom(pos + 1); + } + + t.Enumerator.BasePrefix = us2fs(basePrefix); + t.Enumerator.BasePrefix_for_Open = us2fs(basePrefix2); + + t.Enumerator.EnterToDirs = !GetFlatMode(); + + t.ShowCompressionInfo = false; + + 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 index ee4a9f6f9..6a781e225 100644 --- a/CPP/7zip/UI/FileManager/PanelDrag.cpp +++ b/CPP/7zip/UI/FileManager/PanelDrag.cpp @@ -1,956 +1,956 @@ -// PanelDrag.cpp - -#include "StdAfx.h" - -#ifdef UNDER_CE -#include -#endif - -#include "../../../Common/StringConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/MemoryGlobal.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" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -#define kTempDirPrefix FTEXT("7zE") - -static LPCTSTR const kSvenZipSetFolderFormat = TEXT("7-Zip::SetTargetFolder"); - -//////////////////////////////////////////////////////// - -class CDataObject: - public IDataObject, - public CMyUnknownImp -{ -private: - FORMATETC m_Etc; - UINT m_SetFolderFormat; - -public: - MY_UNKNOWN_IMP1_MT(IDataObject) - - STDMETHODIMP GetData(LPFORMATETC pformatetcIn, LPSTGMEDIUM medium); - STDMETHODIMP GetDataHere(LPFORMATETC pformatetc, LPSTGMEDIUM medium); - STDMETHODIMP QueryGetData(LPFORMATETC pformatetc ); - - STDMETHODIMP GetCanonicalFormatEtc ( LPFORMATETC /* pformatetc */, LPFORMATETC pformatetcOut) - { pformatetcOut->ptd = NULL; return ResultFromScode(E_NOTIMPL); } - - STDMETHODIMP SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL release); - STDMETHODIMP EnumFormatEtc(DWORD drection, LPENUMFORMATETC *enumFormatEtc); - - STDMETHODIMP DAdvise(FORMATETC * /* etc */, DWORD /* advf */, LPADVISESINK /* pAdvSink */, DWORD * /* pdwConnection */) - { return OLE_E_ADVISENOTSUPPORTED; } - STDMETHODIMP DUnadvise(DWORD /* dwConnection */) { return OLE_E_ADVISENOTSUPPORTED; } - STDMETHODIMP EnumDAdvise( LPENUMSTATDATA * /* ppenumAdvise */) { return OLE_E_ADVISENOTSUPPORTED; } - - CDataObject(); - - NMemory::CGlobal hGlobal; - UString Path; -}; - -CDataObject::CDataObject() -{ - m_SetFolderFormat = RegisterClipboardFormat(kSvenZipSetFolderFormat); - m_Etc.cfFormat = CF_HDROP; - m_Etc.ptd = NULL; - m_Etc.dwAspect = DVASPECT_CONTENT; - m_Etc.lindex = -1; - m_Etc.tymed = TYMED_HGLOBAL; -} - -STDMETHODIMP CDataObject::SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL /* release */) -{ - if (etc->cfFormat == m_SetFolderFormat - && etc->tymed == TYMED_HGLOBAL - && etc->dwAspect == DVASPECT_CONTENT - && medium->tymed == TYMED_HGLOBAL) - { - Path.Empty(); - if (!medium->hGlobal) - return S_OK; - size_t size = GlobalSize(medium->hGlobal) / sizeof(wchar_t); - const wchar_t *src = (const wchar_t *)GlobalLock(medium->hGlobal); - if (src) - { - for (size_t i = 0; i < size; i++) - { - wchar_t c = src[i]; - if (c == 0) - break; - Path += c; - } - GlobalUnlock(medium->hGlobal); - return S_OK; - } - } - return E_NOTIMPL; -} - -static HGLOBAL DuplicateGlobalMem(HGLOBAL srcGlobal) -{ - SIZE_T size = GlobalSize(srcGlobal); - const void *src = GlobalLock(srcGlobal); - if (!src) - return 0; - HGLOBAL destGlobal = GlobalAlloc(GHND | GMEM_SHARE, size); - if (destGlobal) - { - void *dest = GlobalLock(destGlobal); - if (!dest) - { - GlobalFree(destGlobal); - destGlobal = 0; - } - else - { - memcpy(dest, src, size); - GlobalUnlock(destGlobal); - } - } - GlobalUnlock(srcGlobal); - return destGlobal; -} - -STDMETHODIMP CDataObject::GetData(LPFORMATETC etc, LPSTGMEDIUM medium) -{ - RINOK(QueryGetData(etc)); - medium->tymed = m_Etc.tymed; - medium->pUnkForRelease = 0; - medium->hGlobal = DuplicateGlobalMem(hGlobal); - if (!medium->hGlobal) - return E_OUTOFMEMORY; - return S_OK; -} - -STDMETHODIMP CDataObject::GetDataHere(LPFORMATETC /* etc */, LPSTGMEDIUM /* medium */) -{ - // Seems Windows doesn't call it, so we will not implement it. - return E_UNEXPECTED; -} - - -STDMETHODIMP CDataObject::QueryGetData(LPFORMATETC etc) -{ - if ((m_Etc.tymed & etc->tymed) && - m_Etc.cfFormat == etc->cfFormat && - m_Etc.dwAspect == etc->dwAspect) - return S_OK; - return DV_E_FORMATETC; -} - -STDMETHODIMP CDataObject::EnumFormatEtc(DWORD direction, LPENUMFORMATETC FAR* enumFormatEtc) -{ - if (direction != DATADIR_GET) - return E_NOTIMPL; - return CreateEnumFormatEtc(1, &m_Etc, enumFormatEtc); -} - -//////////////////////////////////////////////////////// - -class CDropSource: - public IDropSource, - public CMyUnknownImp -{ - DWORD m_Effect; -public: - MY_UNKNOWN_IMP1_MT(IDropSource) - STDMETHOD(QueryContinueDrag)(BOOL escapePressed, DWORD keyState); - STDMETHOD(GiveFeedback)(DWORD effect); - - - bool NeedExtract; - CPanel *Panel; - CRecordVector Indices; - UString Folder; - CDataObject *DataObjectSpec; - CMyComPtr DataObject; - - bool NeedPostCopy; - HRESULT Result; - UStringVector Messages; - - CDropSource(): NeedPostCopy(false), Panel(0), Result(S_OK), m_Effect(DROPEFFECT_NONE) {} -}; - -STDMETHODIMP CDropSource::QueryContinueDrag(BOOL escapePressed, DWORD keyState) -{ - if (escapePressed == TRUE) - return DRAGDROP_S_CANCEL; - if ((keyState & MK_LBUTTON) == 0) - { - if (m_Effect == DROPEFFECT_NONE) - return DRAGDROP_S_CANCEL; - Result = S_OK; - bool needExtract = NeedExtract; - // MoveMode = (((keyState & MK_SHIFT) != 0) && MoveIsAllowed); - if (!DataObjectSpec->Path.IsEmpty()) - { - needExtract = false; - NeedPostCopy = true; - } - if (needExtract) - { - CCopyToOptions options; - options.folder = Folder; - - // 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); - - Result = Panel->CopyTo(options, Indices, &Messages); - - // do we need to restore capture? - // ReleaseCapture(); - // oldHwnd = SetCapture(oldHwnd); - - if (Result != S_OK || !Messages.IsEmpty()) - return DRAGDROP_S_CANCEL; - } - return DRAGDROP_S_DROP; - } - return S_OK; -} - -STDMETHODIMP CDropSource::GiveFeedback(DWORD effect) -{ - m_Effect = effect; - return DRAGDROP_S_USEDEFAULTCURSORS; -} - -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 < names.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 *)((BYTE *)dropFiles + sizeof(DROPFILES)); - for (i = 0; i < names.Size(); i++) - { - const AString &s = namesA[i]; - 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; - dropFiles->fNC = FALSE; - dropFiles->pt.x = 0; - dropFiles->pt.y = 0; - dropFiles->pFiles = sizeof(DROPFILES); - dropFiles->fWide = TRUE; - WCHAR *p = (WCHAR *)((BYTE *)dropFiles + sizeof(DROPFILES)); - for (i = 0; i < names.Size(); i++) - { - const UString &s = names[i]; - unsigned fullLen = s.Len() + 1; - MyStringCopy(p, (const WCHAR *)s); - p += fullLen; - totalLen -= fullLen; - } - *p = 0; - } - return true; -} - -void CPanel::OnDrag(LPNMLISTVIEW /* nmListView */) -{ - if (!DoesItSupportOperations()) - return; - - CDisableTimerProcessing disableTimerProcessing2(*this); - - CRecordVector indices; - GetOperatedItemIndices(indices); - if (indices.Size() == 0) - return; - - // CSelectedState selState; - // SaveSelectedState(selState); - - // FString dirPrefix2; - FString dirPrefix; - CTempDir tempDirectory; - - bool isFSFolder = IsFSFolder(); - if (isFSFolder) - dirPrefix = us2fs(GetFsPath()); - else - { - if (!tempDirectory.Create(kTempDirPrefix)) - { - MessageBox_Error(L"Can't create temp folder"); - return; - } - dirPrefix = tempDirectory.GetPath(); - // dirPrefix2 = dirPrefix; - NFile::NName::NormalizeDirPathPrefix(dirPrefix); - } - - CDataObject *dataObjectSpec = new CDataObject; - CMyComPtr dataObject = dataObjectSpec; - - { - 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) - { - 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(fs2us(dirPrefix) + s); - } - if (!CopyNamesToHGlobal(dataObjectSpec->hGlobal, names)) - return; - } - - CDropSource *dropSourceSpec = new CDropSource; - CMyComPtr dropSource = dropSourceSpec; - dropSourceSpec->NeedExtract = !isFSFolder; - dropSourceSpec->Panel = this; - dropSourceSpec->Indices = indices; - dropSourceSpec->Folder = fs2us(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 preserved 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 Path in IDataObject. - and - IDropSource::QueryContinueDrag() sets NeedPostCopy, if Path is not epmty. - 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. - */ - - bool moveIsAllowed = isFSFolder; - /* - DWORD effectsOK = DROPEFFECT_COPY; - if (moveIsAllowed) - effectsOK |= DROPEFFECT_MOVE; - */ - - // 18.04: was changed - DWORD effectsOK = DROPEFFECT_MOVE | DROPEFFECT_COPY; - - DWORD effect; - _panelCallback->DragBegin(); - - HRESULT res = DoDragDrop(dataObject, dropSource, effectsOK, &effect); - - _panelCallback->DragEnd(); - bool canceled = (res == DRAGDROP_S_CANCEL); - - CDisableNotify disableNotify(*this); - - if (res == DRAGDROP_S_DROP) - { - res = dropSourceSpec->Result; - if (dropSourceSpec->NeedPostCopy) - if (!dataObjectSpec->Path.IsEmpty()) - { - NFile::NName::NormalizeDirPathPrefix(dataObjectSpec->Path); - CCopyToOptions options; - options.folder = dataObjectSpec->Path; - // if MOVE is not allowed, we just use COPY operation - options.moveMode = (effect == DROPEFFECT_MOVE && moveIsAllowed); - res = CopyTo(options, indices, &dropSourceSpec->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 = dropSourceSpec->Result; - } - - if (!dropSourceSpec->Messages.IsEmpty()) - { - CMessagesDialog messagesDialog; - messagesDialog.Messages = &dropSourceSpec->Messages; - messagesDialog.Create((*this)); - } - - if (res != S_OK && res != E_ABORT) - { - // we restore Notify before MessageBox_Error_HRESULT. So we will se files selection - disableNotify.Restore(); - // SetFocusToList(); - MessageBox_Error_HRESULT(res); - } - if (res == S_OK && dropSourceSpec->Messages.IsEmpty() && !canceled) - KillSelection(); -} - -void CDropTarget::QueryGetData(IDataObject *dataObject) -{ - FORMATETC etc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - m_DropIsAllowed = (dataObject->QueryGetData(&etc) == S_OK); - -} - -static void MySetDropHighlighted(HWND hWnd, int index, bool enable) -{ - LVITEM item; - item.mask = LVIF_STATE; - item.iItem = index; - item.iSubItem = 0; - item.state = enable ? LVIS_DROPHILITED : 0; - item.stateMask = LVIS_DROPHILITED; - item.pszText = 0; - ListView_SetItem(hWnd, &item); -} - -void CDropTarget::RemoveSelection() -{ - if (m_SelectionIndex >= 0 && m_Panel) - MySetDropHighlighted(m_Panel->_listView, m_SelectionIndex, false); - m_SelectionIndex = -1; -} - -#ifdef UNDER_CE -#define ChildWindowFromPointEx(hwndParent, pt, uFlags) ChildWindowFromPoint(hwndParent, pt) -#endif - -void CDropTarget::PositionCursor(POINTL ptl) -{ - m_SubFolderIndex = -1; - POINT pt; - pt.x = ptl.x; - pt.y = ptl.y; - - RemoveSelection(); - m_IsAppTarget = true; - m_Panel = NULL; - - m_PanelDropIsAllowed = true; - if (!m_DropIsAllowed) - return; - { - POINT pt2 = pt; - App->_window.ScreenToClient(&pt2); - for (unsigned i = 0; i < kNumPanelsMax; i++) - if (App->IsPanelVisible(i)) - if (App->Panels[i].IsEnabled()) - if (ChildWindowFromPointEx(App->_window, pt2, - CWP_SKIPINVISIBLE | CWP_SKIPDISABLED) == (HWND)App->Panels[i]) - { - m_Panel = &App->Panels[i]; - m_IsAppTarget = false; - if ((int)i == SrcPanelIndex) - { - m_PanelDropIsAllowed = false; - return; - } - break; - } - if (m_IsAppTarget) - { - if (TargetPanelIndex >= 0) - m_Panel = &App->Panels[TargetPanelIndex]; - return; - } - } - - /* - m_PanelDropIsAllowed = m_Panel->DoesItSupportOperations(); - if (!m_PanelDropIsAllowed) - return; - */ - - if (!m_Panel->IsFsOrPureDrivesFolder()) - return; - - if (WindowFromPoint(pt) != (HWND)m_Panel->_listView) - return; - - LVHITTESTINFO info; - m_Panel->_listView.ScreenToClient(&pt); - info.pt = pt; - int index = ListView_HitTest(m_Panel->_listView, &info); - if (index < 0) - return; - int realIndex = m_Panel->GetRealItemIndex(index); - if (realIndex == kParentIndex) - return; - if (!m_Panel->IsItem_Folder(realIndex)) - return; - m_SubFolderIndex = realIndex; - m_SubFolderName = m_Panel->GetItemName(m_SubFolderIndex); - MySetDropHighlighted(m_Panel->_listView, index, true); - m_SelectionIndex = index; -} - -bool CDropTarget::IsFsFolderPath() const -{ - if (!m_IsAppTarget && m_Panel) - return (m_Panel->IsFSFolder() || (m_Panel->IsFSDrivesFolder() && m_SelectionIndex >= 0)); - return false; -} - -static void ReadUnicodeStrings(const wchar_t *p, size_t size, UStringVector &names) -{ - names.Clear(); - UString name; - for (;size > 0; size--) - { - wchar_t c = *p++; - if (c == 0) - { - if (name.IsEmpty()) - break; - names.Add(name); - name.Empty(); - } - else - name += c; - } -} - -static void ReadAnsiStrings(const char *p, size_t size, UStringVector &names) -{ - names.Clear(); - AString name; - for (;size > 0; size--) - { - char c = *p++; - if (c == 0) - { - if (name.IsEmpty()) - break; - names.Add(GetUnicodeString(name)); - name.Empty(); - } - else - name += c; - } -} - -static void GetNamesFromDataObject(IDataObject *dataObject, UStringVector &names) -{ - names.Clear(); - FORMATETC etc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - STGMEDIUM medium; - HRESULT res = dataObject->GetData(&etc, &medium); - if (res != S_OK) - return; - if (medium.tymed != TYMED_HGLOBAL) - return; - { - NMemory::CGlobal global; - global.Attach(medium.hGlobal); - size_t blockSize = GlobalSize(medium.hGlobal); - NMemory::CGlobalLock dropLock(medium.hGlobal); - const DROPFILES* dropFiles = (DROPFILES*)dropLock.GetPointer(); - if (!dropFiles) - return; - if (blockSize < dropFiles->pFiles) - return; - size_t size = blockSize - dropFiles->pFiles; - const void *namesData = (const Byte *)dropFiles + dropFiles->pFiles; - if (dropFiles->fWide) - ReadUnicodeStrings((const wchar_t *)namesData, size / sizeof(wchar_t), names); - else - ReadAnsiStrings((const char *)namesData, size, names); - } -} - -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_SelectionIndex >= 0) - { - drive = m_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) Drag from any external program except of Explorer to "7-Zip" FS folder. - We want to create new archive for that operation. - 2) all another operation 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. -*/ - -DWORD CDropTarget::GetEffect(DWORD keyState, POINTL /* pt */, DWORD allowedEffect) -{ - if (!m_DropIsAllowed || !m_PanelDropIsAllowed) - return DROPEFFECT_NONE; - - if (!IsFsFolderPath() || !m_SetPathIsOK) - allowedEffect &= ~DROPEFFECT_MOVE; - - DWORD effect = 0; - - if (keyState & MK_CONTROL) - effect = allowedEffect & DROPEFFECT_COPY; - else if (keyState & MK_SHIFT) - effect = allowedEffect & DROPEFFECT_MOVE; - - if (effect == 0) - { - if (allowedEffect & DROPEFFECT_COPY) - effect = DROPEFFECT_COPY; - if (allowedEffect & DROPEFFECT_MOVE) - { - if (IsItSameDrive()) - effect = DROPEFFECT_MOVE; - } - } - if (effect == 0) - return DROPEFFECT_NONE; - return effect; -} - -UString CDropTarget::GetTargetPath() const -{ - if (!IsFsFolderPath()) - return UString(); - UString path = m_Panel->GetFsPath(); - if (m_SubFolderIndex >= 0 && !m_SubFolderName.IsEmpty()) - { - path += m_SubFolderName; - path.Add_PathSepar(); - } - return path; -} - -bool CDropTarget::SetPath(bool enablePath) const -{ - UINT setFolderFormat = RegisterClipboardFormat(kSvenZipSetFolderFormat); - - FORMATETC etc = { (CLIPFORMAT)setFolderFormat, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - STGMEDIUM medium; - medium.tymed = etc.tymed; - medium.pUnkForRelease = 0; - UString path; - if (enablePath) - path = GetTargetPath(); - size_t size = path.Len() + 1; - medium.hGlobal = GlobalAlloc(GHND | GMEM_SHARE, size * sizeof(wchar_t)); - if (!medium.hGlobal) - return false; - wchar_t *dest = (wchar_t *)GlobalLock(medium.hGlobal); - if (!dest) - { - GlobalUnlock(medium.hGlobal); - return false; - } - MyStringCopy(dest, (const wchar_t *)path); - GlobalUnlock(medium.hGlobal); - bool res = m_DataObject->SetData(&etc, &medium, FALSE) == S_OK; - GlobalFree(medium.hGlobal); - return res; -} - -bool CDropTarget::SetPath() -{ - m_SetPathIsOK = SetPath(m_DropIsAllowed && m_PanelDropIsAllowed && IsFsFolderPath()); - return m_SetPathIsOK; -} - -STDMETHODIMP CDropTarget::DragEnter(IDataObject * dataObject, DWORD keyState, - POINTL pt, DWORD *effect) -{ - GetNamesFromDataObject(dataObject, m_SourcePaths); - QueryGetData(dataObject); - m_DataObject = dataObject; - return DragOver(keyState, pt, effect); -} - - -STDMETHODIMP CDropTarget::DragOver(DWORD keyState, POINTL pt, DWORD *effect) -{ - PositionCursor(pt); - SetPath(); - *effect = GetEffect(keyState, pt, *effect); - return S_OK; -} - - -STDMETHODIMP CDropTarget::DragLeave() -{ - RemoveSelection(); - SetPath(false); - m_DataObject.Release(); - return S_OK; -} - -// We suppose that there was ::DragOver for same POINTL_pt before ::Drop -// So SetPath() is same as in Drop. - -STDMETHODIMP CDropTarget::Drop(IDataObject *dataObject, DWORD keyState, - POINTL pt, DWORD * effect) -{ - QueryGetData(dataObject); - PositionCursor(pt); - m_DataObject = dataObject; - bool needDrop = true; - if (m_DropIsAllowed && m_PanelDropIsAllowed) - if (IsFsFolderPath()) - needDrop = !SetPath(); - *effect = GetEffect(keyState, pt, *effect); - if (m_DropIsAllowed && m_PanelDropIsAllowed) - { - if (needDrop) - { - UString path = GetTargetPath(); - if (m_IsAppTarget && m_Panel) - if (m_Panel->IsFSFolder()) - path = m_Panel->GetFsPath(); - m_Panel->DropObject(dataObject, path); - } - } - RemoveSelection(); - m_DataObject.Release(); - return S_OK; -} - -void CPanel::DropObject(IDataObject *dataObject, const UString &folderPath) -{ - UStringVector names; - GetNamesFromDataObject(dataObject, names); - CompressDropFiles(names, folderPath); -} - -/* -void CPanel::CompressDropFiles(HDROP dr) -{ - UStringVector fileNames; - { - NShell::CDrop drop(true); - drop.Attach(dr); - drop.QueryFileNames(fileNames); - } - CompressDropFiles(fileNamesUnicode); -} -*/ - -static bool IsFolderInTemp(const FString &path) -{ - FString tempPath; - if (!MyGetTempPath(tempPath)) - return false; - if (tempPath.IsEmpty()) - return false; - unsigned len = tempPath.Len(); - if (path.Len() < len) - return false; - return CompareFileNames(path.Left(len), tempPath) == 0; -} - -static bool AreThereNamesFromTemp(const UStringVector &fileNames) -{ - FString tempPathF; - if (!MyGetTempPath(tempPathF)) - return false; - UString tempPath = fs2us(tempPathF); - if (tempPath.IsEmpty()) - return false; - FOR_VECTOR (i, fileNames) - if (fileNames[i].IsPrefixedBy_NoCase(tempPath)) - return true; - return false; -} - -void CPanel::CompressDropFiles(const UStringVector &fileNames, const UString &folderPath) -{ - if (fileNames.Size() == 0) - return; - bool createNewArchive = true; - if (!IsFSFolder()) - createNewArchive = !DoesItSupportOperations(); - - if (createNewArchive) - { - UString folderPath2 = folderPath; - if (folderPath2.IsEmpty()) - { - FString folderPath2F; - GetOnlyDirPrefix(us2fs(fileNames.Front()), folderPath2F); - folderPath2 = fs2us(folderPath2F); - if (IsFolderInTemp(folderPath2F)) - folderPath2 = ROOT_FS_FOLDER; - } - - const UString arcName = CreateArchiveName(fileNames); - - CompressFiles(folderPath2, arcName, L"", - true, // addExtension - fileNames, - false, // email - true, // showDialog - AreThereNamesFromTemp(fileNames) // waitFinish - ); - } - else - CopyFromAsk(fileNames); -} +// PanelDrag.cpp + +#include "StdAfx.h" + +#ifdef UNDER_CE +#include +#endif + +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/MemoryGlobal.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" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +#define kTempDirPrefix FTEXT("7zE") + +static LPCTSTR const kSvenZipSetFolderFormat = TEXT("7-Zip::SetTargetFolder"); + +//////////////////////////////////////////////////////// + +class CDataObject: + public IDataObject, + public CMyUnknownImp +{ +private: + FORMATETC m_Etc; + UINT m_SetFolderFormat; + +public: + MY_UNKNOWN_IMP1_MT(IDataObject) + + STDMETHODIMP GetData(LPFORMATETC pformatetcIn, LPSTGMEDIUM medium); + STDMETHODIMP GetDataHere(LPFORMATETC pformatetc, LPSTGMEDIUM medium); + STDMETHODIMP QueryGetData(LPFORMATETC pformatetc ); + + STDMETHODIMP GetCanonicalFormatEtc ( LPFORMATETC /* pformatetc */, LPFORMATETC pformatetcOut) + { pformatetcOut->ptd = NULL; return ResultFromScode(E_NOTIMPL); } + + STDMETHODIMP SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL release); + STDMETHODIMP EnumFormatEtc(DWORD drection, LPENUMFORMATETC *enumFormatEtc); + + STDMETHODIMP DAdvise(FORMATETC * /* etc */, DWORD /* advf */, LPADVISESINK /* pAdvSink */, DWORD * /* pdwConnection */) + { return OLE_E_ADVISENOTSUPPORTED; } + STDMETHODIMP DUnadvise(DWORD /* dwConnection */) { return OLE_E_ADVISENOTSUPPORTED; } + STDMETHODIMP EnumDAdvise( LPENUMSTATDATA * /* ppenumAdvise */) { return OLE_E_ADVISENOTSUPPORTED; } + + CDataObject(); + + NMemory::CGlobal hGlobal; + UString Path; +}; + +CDataObject::CDataObject() +{ + m_SetFolderFormat = RegisterClipboardFormat(kSvenZipSetFolderFormat); + m_Etc.cfFormat = CF_HDROP; + m_Etc.ptd = NULL; + m_Etc.dwAspect = DVASPECT_CONTENT; + m_Etc.lindex = -1; + m_Etc.tymed = TYMED_HGLOBAL; +} + +STDMETHODIMP CDataObject::SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL /* release */) +{ + if (etc->cfFormat == m_SetFolderFormat + && etc->tymed == TYMED_HGLOBAL + && etc->dwAspect == DVASPECT_CONTENT + && medium->tymed == TYMED_HGLOBAL) + { + Path.Empty(); + if (!medium->hGlobal) + return S_OK; + size_t size = GlobalSize(medium->hGlobal) / sizeof(wchar_t); + const wchar_t *src = (const wchar_t *)GlobalLock(medium->hGlobal); + if (src) + { + for (size_t i = 0; i < size; i++) + { + wchar_t c = src[i]; + if (c == 0) + break; + Path += c; + } + GlobalUnlock(medium->hGlobal); + return S_OK; + } + } + return E_NOTIMPL; +} + +static HGLOBAL DuplicateGlobalMem(HGLOBAL srcGlobal) +{ + SIZE_T size = GlobalSize(srcGlobal); + const void *src = GlobalLock(srcGlobal); + if (!src) + return 0; + HGLOBAL destGlobal = GlobalAlloc(GHND | GMEM_SHARE, size); + if (destGlobal) + { + void *dest = GlobalLock(destGlobal); + if (!dest) + { + GlobalFree(destGlobal); + destGlobal = 0; + } + else + { + memcpy(dest, src, size); + GlobalUnlock(destGlobal); + } + } + GlobalUnlock(srcGlobal); + return destGlobal; +} + +STDMETHODIMP CDataObject::GetData(LPFORMATETC etc, LPSTGMEDIUM medium) +{ + RINOK(QueryGetData(etc)); + medium->tymed = m_Etc.tymed; + medium->pUnkForRelease = 0; + medium->hGlobal = DuplicateGlobalMem(hGlobal); + if (!medium->hGlobal) + return E_OUTOFMEMORY; + return S_OK; +} + +STDMETHODIMP CDataObject::GetDataHere(LPFORMATETC /* etc */, LPSTGMEDIUM /* medium */) +{ + // Seems Windows doesn't call it, so we will not implement it. + return E_UNEXPECTED; +} + + +STDMETHODIMP CDataObject::QueryGetData(LPFORMATETC etc) +{ + if ((m_Etc.tymed & etc->tymed) && + m_Etc.cfFormat == etc->cfFormat && + m_Etc.dwAspect == etc->dwAspect) + return S_OK; + return DV_E_FORMATETC; +} + +STDMETHODIMP CDataObject::EnumFormatEtc(DWORD direction, LPENUMFORMATETC FAR* enumFormatEtc) +{ + if (direction != DATADIR_GET) + return E_NOTIMPL; + return CreateEnumFormatEtc(1, &m_Etc, enumFormatEtc); +} + +//////////////////////////////////////////////////////// + +class CDropSource: + public IDropSource, + public CMyUnknownImp +{ + DWORD m_Effect; +public: + MY_UNKNOWN_IMP1_MT(IDropSource) + STDMETHOD(QueryContinueDrag)(BOOL escapePressed, DWORD keyState); + STDMETHOD(GiveFeedback)(DWORD effect); + + + bool NeedExtract; + CPanel *Panel; + CRecordVector Indices; + UString Folder; + CDataObject *DataObjectSpec; + CMyComPtr DataObject; + + bool NeedPostCopy; + HRESULT Result; + UStringVector Messages; + + CDropSource(): NeedPostCopy(false), Panel(0), Result(S_OK), m_Effect(DROPEFFECT_NONE) {} +}; + +STDMETHODIMP CDropSource::QueryContinueDrag(BOOL escapePressed, DWORD keyState) +{ + if (escapePressed == TRUE) + return DRAGDROP_S_CANCEL; + if ((keyState & MK_LBUTTON) == 0) + { + if (m_Effect == DROPEFFECT_NONE) + return DRAGDROP_S_CANCEL; + Result = S_OK; + bool needExtract = NeedExtract; + // MoveMode = (((keyState & MK_SHIFT) != 0) && MoveIsAllowed); + if (!DataObjectSpec->Path.IsEmpty()) + { + needExtract = false; + NeedPostCopy = true; + } + if (needExtract) + { + CCopyToOptions options; + options.folder = Folder; + + // 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); + + Result = Panel->CopyTo(options, Indices, &Messages); + + // do we need to restore capture? + // ReleaseCapture(); + // oldHwnd = SetCapture(oldHwnd); + + if (Result != S_OK || !Messages.IsEmpty()) + return DRAGDROP_S_CANCEL; + } + return DRAGDROP_S_DROP; + } + return S_OK; +} + +STDMETHODIMP CDropSource::GiveFeedback(DWORD effect) +{ + m_Effect = effect; + return DRAGDROP_S_USEDEFAULTCURSORS; +} + +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 < names.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 *)((BYTE *)dropFiles + sizeof(DROPFILES)); + for (i = 0; i < names.Size(); i++) + { + const AString &s = namesA[i]; + 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; + dropFiles->fNC = FALSE; + dropFiles->pt.x = 0; + dropFiles->pt.y = 0; + dropFiles->pFiles = sizeof(DROPFILES); + dropFiles->fWide = TRUE; + WCHAR *p = (WCHAR *)((BYTE *)dropFiles + sizeof(DROPFILES)); + for (i = 0; i < names.Size(); i++) + { + const UString &s = names[i]; + unsigned fullLen = s.Len() + 1; + MyStringCopy(p, (const WCHAR *)s); + p += fullLen; + totalLen -= fullLen; + } + *p = 0; + } + return true; +} + +void CPanel::OnDrag(LPNMLISTVIEW /* nmListView */) +{ + if (!DoesItSupportOperations()) + return; + + CDisableTimerProcessing disableTimerProcessing2(*this); + + CRecordVector indices; + GetOperatedItemIndices(indices); + if (indices.Size() == 0) + return; + + // CSelectedState selState; + // SaveSelectedState(selState); + + // FString dirPrefix2; + FString dirPrefix; + CTempDir tempDirectory; + + bool isFSFolder = IsFSFolder(); + if (isFSFolder) + dirPrefix = us2fs(GetFsPath()); + else + { + if (!tempDirectory.Create(kTempDirPrefix)) + { + MessageBox_Error(L"Can't create temp folder"); + return; + } + dirPrefix = tempDirectory.GetPath(); + // dirPrefix2 = dirPrefix; + NFile::NName::NormalizeDirPathPrefix(dirPrefix); + } + + CDataObject *dataObjectSpec = new CDataObject; + CMyComPtr dataObject = dataObjectSpec; + + { + 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) + { + 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(fs2us(dirPrefix) + s); + } + if (!CopyNamesToHGlobal(dataObjectSpec->hGlobal, names)) + return; + } + + CDropSource *dropSourceSpec = new CDropSource; + CMyComPtr dropSource = dropSourceSpec; + dropSourceSpec->NeedExtract = !isFSFolder; + dropSourceSpec->Panel = this; + dropSourceSpec->Indices = indices; + dropSourceSpec->Folder = fs2us(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 preserved 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 Path in IDataObject. + and + IDropSource::QueryContinueDrag() sets NeedPostCopy, if Path is not epmty. + 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. + */ + + bool moveIsAllowed = isFSFolder; + /* + DWORD effectsOK = DROPEFFECT_COPY; + if (moveIsAllowed) + effectsOK |= DROPEFFECT_MOVE; + */ + + // 18.04: was changed + DWORD effectsOK = DROPEFFECT_MOVE | DROPEFFECT_COPY; + + DWORD effect; + _panelCallback->DragBegin(); + + HRESULT res = DoDragDrop(dataObject, dropSource, effectsOK, &effect); + + _panelCallback->DragEnd(); + bool canceled = (res == DRAGDROP_S_CANCEL); + + CDisableNotify disableNotify(*this); + + if (res == DRAGDROP_S_DROP) + { + res = dropSourceSpec->Result; + if (dropSourceSpec->NeedPostCopy) + if (!dataObjectSpec->Path.IsEmpty()) + { + NFile::NName::NormalizeDirPathPrefix(dataObjectSpec->Path); + CCopyToOptions options; + options.folder = dataObjectSpec->Path; + // if MOVE is not allowed, we just use COPY operation + options.moveMode = (effect == DROPEFFECT_MOVE && moveIsAllowed); + res = CopyTo(options, indices, &dropSourceSpec->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 = dropSourceSpec->Result; + } + + if (!dropSourceSpec->Messages.IsEmpty()) + { + CMessagesDialog messagesDialog; + messagesDialog.Messages = &dropSourceSpec->Messages; + messagesDialog.Create((*this)); + } + + if (res != S_OK && res != E_ABORT) + { + // we restore Notify before MessageBox_Error_HRESULT. So we will se files selection + disableNotify.Restore(); + // SetFocusToList(); + MessageBox_Error_HRESULT(res); + } + if (res == S_OK && dropSourceSpec->Messages.IsEmpty() && !canceled) + KillSelection(); +} + +void CDropTarget::QueryGetData(IDataObject *dataObject) +{ + FORMATETC etc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + m_DropIsAllowed = (dataObject->QueryGetData(&etc) == S_OK); + +} + +static void MySetDropHighlighted(HWND hWnd, int index, bool enable) +{ + LVITEM item; + item.mask = LVIF_STATE; + item.iItem = index; + item.iSubItem = 0; + item.state = enable ? LVIS_DROPHILITED : 0; + item.stateMask = LVIS_DROPHILITED; + item.pszText = 0; + ListView_SetItem(hWnd, &item); +} + +void CDropTarget::RemoveSelection() +{ + if (m_SelectionIndex >= 0 && m_Panel) + MySetDropHighlighted(m_Panel->_listView, m_SelectionIndex, false); + m_SelectionIndex = -1; +} + +#ifdef UNDER_CE +#define ChildWindowFromPointEx(hwndParent, pt, uFlags) ChildWindowFromPoint(hwndParent, pt) +#endif + +void CDropTarget::PositionCursor(POINTL ptl) +{ + m_SubFolderIndex = -1; + POINT pt; + pt.x = ptl.x; + pt.y = ptl.y; + + RemoveSelection(); + m_IsAppTarget = true; + m_Panel = NULL; + + m_PanelDropIsAllowed = true; + if (!m_DropIsAllowed) + return; + { + POINT pt2 = pt; + App->_window.ScreenToClient(&pt2); + for (unsigned i = 0; i < kNumPanelsMax; i++) + if (App->IsPanelVisible(i)) + if (App->Panels[i].IsEnabled()) + if (ChildWindowFromPointEx(App->_window, pt2, + CWP_SKIPINVISIBLE | CWP_SKIPDISABLED) == (HWND)App->Panels[i]) + { + m_Panel = &App->Panels[i]; + m_IsAppTarget = false; + if ((int)i == SrcPanelIndex) + { + m_PanelDropIsAllowed = false; + return; + } + break; + } + if (m_IsAppTarget) + { + if (TargetPanelIndex >= 0) + m_Panel = &App->Panels[TargetPanelIndex]; + return; + } + } + + /* + m_PanelDropIsAllowed = m_Panel->DoesItSupportOperations(); + if (!m_PanelDropIsAllowed) + return; + */ + + if (!m_Panel->IsFsOrPureDrivesFolder()) + return; + + if (WindowFromPoint(pt) != (HWND)m_Panel->_listView) + return; + + LVHITTESTINFO info; + m_Panel->_listView.ScreenToClient(&pt); + info.pt = pt; + int index = ListView_HitTest(m_Panel->_listView, &info); + if (index < 0) + return; + int realIndex = m_Panel->GetRealItemIndex(index); + if (realIndex == kParentIndex) + return; + if (!m_Panel->IsItem_Folder(realIndex)) + return; + m_SubFolderIndex = realIndex; + m_SubFolderName = m_Panel->GetItemName(m_SubFolderIndex); + MySetDropHighlighted(m_Panel->_listView, index, true); + m_SelectionIndex = index; +} + +bool CDropTarget::IsFsFolderPath() const +{ + if (!m_IsAppTarget && m_Panel) + return (m_Panel->IsFSFolder() || (m_Panel->IsFSDrivesFolder() && m_SelectionIndex >= 0)); + return false; +} + +static void ReadUnicodeStrings(const wchar_t *p, size_t size, UStringVector &names) +{ + names.Clear(); + UString name; + for (;size > 0; size--) + { + wchar_t c = *p++; + if (c == 0) + { + if (name.IsEmpty()) + break; + names.Add(name); + name.Empty(); + } + else + name += c; + } +} + +static void ReadAnsiStrings(const char *p, size_t size, UStringVector &names) +{ + names.Clear(); + AString name; + for (;size > 0; size--) + { + char c = *p++; + if (c == 0) + { + if (name.IsEmpty()) + break; + names.Add(GetUnicodeString(name)); + name.Empty(); + } + else + name += c; + } +} + +static void GetNamesFromDataObject(IDataObject *dataObject, UStringVector &names) +{ + names.Clear(); + FORMATETC etc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM medium; + HRESULT res = dataObject->GetData(&etc, &medium); + if (res != S_OK) + return; + if (medium.tymed != TYMED_HGLOBAL) + return; + { + NMemory::CGlobal global; + global.Attach(medium.hGlobal); + size_t blockSize = GlobalSize(medium.hGlobal); + NMemory::CGlobalLock dropLock(medium.hGlobal); + const DROPFILES* dropFiles = (DROPFILES*)dropLock.GetPointer(); + if (!dropFiles) + return; + if (blockSize < dropFiles->pFiles) + return; + size_t size = blockSize - dropFiles->pFiles; + const void *namesData = (const Byte *)dropFiles + dropFiles->pFiles; + if (dropFiles->fWide) + ReadUnicodeStrings((const wchar_t *)namesData, size / sizeof(wchar_t), names); + else + ReadAnsiStrings((const char *)namesData, size, names); + } +} + +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_SelectionIndex >= 0) + { + drive = m_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) Drag from any external program except of Explorer to "7-Zip" FS folder. + We want to create new archive for that operation. + 2) all another operation 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. +*/ + +DWORD CDropTarget::GetEffect(DWORD keyState, POINTL /* pt */, DWORD allowedEffect) +{ + if (!m_DropIsAllowed || !m_PanelDropIsAllowed) + return DROPEFFECT_NONE; + + if (!IsFsFolderPath() || !m_SetPathIsOK) + allowedEffect &= ~DROPEFFECT_MOVE; + + DWORD effect = 0; + + if (keyState & MK_CONTROL) + effect = allowedEffect & DROPEFFECT_COPY; + else if (keyState & MK_SHIFT) + effect = allowedEffect & DROPEFFECT_MOVE; + + if (effect == 0) + { + if (allowedEffect & DROPEFFECT_COPY) + effect = DROPEFFECT_COPY; + if (allowedEffect & DROPEFFECT_MOVE) + { + if (IsItSameDrive()) + effect = DROPEFFECT_MOVE; + } + } + if (effect == 0) + return DROPEFFECT_NONE; + return effect; +} + +UString CDropTarget::GetTargetPath() const +{ + if (!IsFsFolderPath()) + return UString(); + UString path = m_Panel->GetFsPath(); + if (m_SubFolderIndex >= 0 && !m_SubFolderName.IsEmpty()) + { + path += m_SubFolderName; + path.Add_PathSepar(); + } + return path; +} + +bool CDropTarget::SetPath(bool enablePath) const +{ + UINT setFolderFormat = RegisterClipboardFormat(kSvenZipSetFolderFormat); + + FORMATETC etc = { (CLIPFORMAT)setFolderFormat, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM medium; + medium.tymed = etc.tymed; + medium.pUnkForRelease = 0; + UString path; + if (enablePath) + path = GetTargetPath(); + size_t size = path.Len() + 1; + medium.hGlobal = GlobalAlloc(GHND | GMEM_SHARE, size * sizeof(wchar_t)); + if (!medium.hGlobal) + return false; + wchar_t *dest = (wchar_t *)GlobalLock(medium.hGlobal); + if (!dest) + { + GlobalUnlock(medium.hGlobal); + return false; + } + MyStringCopy(dest, (const wchar_t *)path); + GlobalUnlock(medium.hGlobal); + bool res = m_DataObject->SetData(&etc, &medium, FALSE) == S_OK; + GlobalFree(medium.hGlobal); + return res; +} + +bool CDropTarget::SetPath() +{ + m_SetPathIsOK = SetPath(m_DropIsAllowed && m_PanelDropIsAllowed && IsFsFolderPath()); + return m_SetPathIsOK; +} + +STDMETHODIMP CDropTarget::DragEnter(IDataObject * dataObject, DWORD keyState, + POINTL pt, DWORD *effect) +{ + GetNamesFromDataObject(dataObject, m_SourcePaths); + QueryGetData(dataObject); + m_DataObject = dataObject; + return DragOver(keyState, pt, effect); +} + + +STDMETHODIMP CDropTarget::DragOver(DWORD keyState, POINTL pt, DWORD *effect) +{ + PositionCursor(pt); + SetPath(); + *effect = GetEffect(keyState, pt, *effect); + return S_OK; +} + + +STDMETHODIMP CDropTarget::DragLeave() +{ + RemoveSelection(); + SetPath(false); + m_DataObject.Release(); + return S_OK; +} + +// We suppose that there was ::DragOver for same POINTL_pt before ::Drop +// So SetPath() is same as in Drop. + +STDMETHODIMP CDropTarget::Drop(IDataObject *dataObject, DWORD keyState, + POINTL pt, DWORD * effect) +{ + QueryGetData(dataObject); + PositionCursor(pt); + m_DataObject = dataObject; + bool needDrop = true; + if (m_DropIsAllowed && m_PanelDropIsAllowed) + if (IsFsFolderPath()) + needDrop = !SetPath(); + *effect = GetEffect(keyState, pt, *effect); + if (m_DropIsAllowed && m_PanelDropIsAllowed) + { + if (needDrop) + { + UString path = GetTargetPath(); + if (m_IsAppTarget && m_Panel) + if (m_Panel->IsFSFolder()) + path = m_Panel->GetFsPath(); + m_Panel->DropObject(dataObject, path); + } + } + RemoveSelection(); + m_DataObject.Release(); + return S_OK; +} + +void CPanel::DropObject(IDataObject *dataObject, const UString &folderPath) +{ + UStringVector names; + GetNamesFromDataObject(dataObject, names); + CompressDropFiles(names, folderPath); +} + +/* +void CPanel::CompressDropFiles(HDROP dr) +{ + UStringVector fileNames; + { + NShell::CDrop drop(true); + drop.Attach(dr); + drop.QueryFileNames(fileNames); + } + CompressDropFiles(fileNamesUnicode); +} +*/ + +static bool IsFolderInTemp(const FString &path) +{ + FString tempPath; + if (!MyGetTempPath(tempPath)) + return false; + if (tempPath.IsEmpty()) + return false; + unsigned len = tempPath.Len(); + if (path.Len() < len) + return false; + return CompareFileNames(path.Left(len), tempPath) == 0; +} + +static bool AreThereNamesFromTemp(const UStringVector &fileNames) +{ + FString tempPathF; + if (!MyGetTempPath(tempPathF)) + return false; + UString tempPath = fs2us(tempPathF); + if (tempPath.IsEmpty()) + return false; + FOR_VECTOR (i, fileNames) + if (fileNames[i].IsPrefixedBy_NoCase(tempPath)) + return true; + return false; +} + +void CPanel::CompressDropFiles(const UStringVector &fileNames, const UString &folderPath) +{ + if (fileNames.Size() == 0) + return; + bool createNewArchive = true; + if (!IsFSFolder()) + createNewArchive = !DoesItSupportOperations(); + + if (createNewArchive) + { + UString folderPath2 = folderPath; + if (folderPath2.IsEmpty()) + { + FString folderPath2F; + GetOnlyDirPrefix(us2fs(fileNames.Front()), folderPath2F); + folderPath2 = fs2us(folderPath2F); + if (IsFolderInTemp(folderPath2F)) + folderPath2 = ROOT_FS_FOLDER; + } + + const UString arcName = CreateArchiveName(fileNames); + + CompressFiles(folderPath2, arcName, L"", + true, // addExtension + fileNames, + false, // email + true, // showDialog + AreThereNamesFromTemp(fileNames) // waitFinish + ); + } + else + CopyFromAsk(fileNames); +} diff --git a/CPP/7zip/UI/FileManager/PanelFolderChange.cpp b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp index 76f1f46fa..38b83124d 100644 --- a/CPP/7zip/UI/FileManager/PanelFolderChange.cpp +++ b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp @@ -1,876 +1,876 @@ -// 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, bool &archiveIsOpened, bool &encrypted) -{ - UString path = fullPath; - #ifdef _WIN32 - path.Replace(L'/', WCHAR_PATH_SEPARATOR); - #endif - - archiveIsOpened = false; - 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 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; - - 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))) - { - UString baseFile = sysPath; - baseFile.DeleteBack(); - if (NFind::DoesFileOrDirExist(us2fs(baseFile))) - sysPath.Empty(); - } - #endif - - CFileInfo fileInfo; - - while (!sysPath.IsEmpty()) - { - if (fileInfo.Find(us2fs(sysPath))) - break; - int pos = sysPath.ReverseFind_PathSepar(); - if (pos < 0) - sysPath.Empty(); - else - { - /* - if (reducedParts.Size() > 0 || pos < (int)sysPath.Len() - 1) - reducedParts.Add(sysPath.Ptr(pos + 1)); - */ - #if defined(_WIN32) && !defined(UNDER_CE) - if (pos == 2 && NName::IsDrivePath2(sysPath) && sysPath.Len() > 3) - pos++; - #endif - - sysPath.DeleteFrom(pos); - } - } - - SetToRootFolder(); - - CMyComPtr 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, encrypted); - } - - if (res == S_FALSE) - _folder->BindToFolder(fs2us(dirPrefix), &newFolder); - else - { - RINOK(res); - 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); - int slashPos = NName::FindSepar(s); - unsigned skipLen = s.Len(); - if (slashPos >= 0) - { - s.DeleteFrom(slashPos); - skipLen = slashPos + 1; - } - - CMyComPtr newFolder; - _folder->BindToFolder(s, &newFolder); - if (newFolder) - curPos += skipLen; - else if (_folderAltStreams) - { - int pos = s.Find(L':'); - if (pos >= 0) - { - UString baseName = s; - baseName.DeleteFrom(pos); - if (_folderAltStreams->BindToAltStreams(baseName, &newFolder) == S_OK && newFolder) - curPos += pos + 1; - } - } - - if (!newFolder) - break; - - SetNewFolder(newFolder); - } - } - - return S_OK; -} - -HRESULT CPanel::BindToPathAndRefresh(const UString &path) -{ - CDisableTimerProcessing disableTimerProcessing(*this); - CDisableNotify disableNotify(*this); - bool archiveIsOpened, encrypted; - UString s = path; - - #ifdef _WIN32 - if (!s.IsEmpty() && s[0] == '\"' && s.Back() == '\"') - { - s.DeleteBack(); - s.Delete(0); - } - #endif - - HRESULT res = BindToPath(s, UString(), archiveIsOpened, encrypted); - 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 = (LPWSTR)(LPCWSTR)name; - _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++) - { - 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), i, false); - 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: - { - code = code; - 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 = 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(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"\\\\?") - { - int pos = focusedName.ReverseFind_PathSepar(); - if (pos >= 0) - { - parentFolderPrefix = focusedName; - parentFolderPrefix.DeleteFrom(pos + 1); - focusedName.DeleteFrontal(pos + 1); - } - } - } - } - - CDisableTimerProcessing disableTimerProcessing(*this); - CDisableNotify disableNotify(*this); - - CMyComPtr 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) - { - { - bool archiveIsOpened; - bool encrypted; - BindToPath(parentFolderPrefix, UString(), archiveIsOpened, encrypted); - } - } - } - - 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(int index) -{ - if (index == kParentIndex) - { - OpenParentFolder(); - return; - } - CMyComPtr newFolder; - _folder->BindToFolder(index, &newFolder); - 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 indices; - GetOperatedItemIndices(indices); - Int32 realIndex = -1; - if (indices.Size() > 1) - return; - if (indices.Size() == 1) - realIndex = indices[0]; - - if (_folderAltStreams) - { - CMyComPtr newFolder; - _folderAltStreams->BindToAltStreams(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(realIndex); - else - { - path = GetFsPath(); - if (!NName::IsDriveRootPath_SuperAllowed(us2fs(path))) - if (!path.IsEmpty() && IS_PATH_SEPAR(path.Back())) - path.DeleteBack(); - } - - path += ':'; - BindToPathAndRefresh(path); - #endif -} +// 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, bool &archiveIsOpened, bool &encrypted) +{ + UString path = fullPath; + #ifdef _WIN32 + path.Replace(L'/', WCHAR_PATH_SEPARATOR); + #endif + + archiveIsOpened = false; + 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 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; + + 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))) + { + UString baseFile = sysPath; + baseFile.DeleteBack(); + if (NFind::DoesFileOrDirExist(us2fs(baseFile))) + sysPath.Empty(); + } + #endif + + CFileInfo fileInfo; + + while (!sysPath.IsEmpty()) + { + if (fileInfo.Find(us2fs(sysPath))) + break; + int pos = sysPath.ReverseFind_PathSepar(); + if (pos < 0) + sysPath.Empty(); + else + { + /* + if (reducedParts.Size() > 0 || pos < (int)sysPath.Len() - 1) + reducedParts.Add(sysPath.Ptr(pos + 1)); + */ + #if defined(_WIN32) && !defined(UNDER_CE) + if (pos == 2 && NName::IsDrivePath2(sysPath) && sysPath.Len() > 3) + pos++; + #endif + + sysPath.DeleteFrom(pos); + } + } + + SetToRootFolder(); + + CMyComPtr 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, encrypted); + } + + if (res == S_FALSE) + _folder->BindToFolder(fs2us(dirPrefix), &newFolder); + else + { + RINOK(res); + 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); + int slashPos = NName::FindSepar(s); + unsigned skipLen = s.Len(); + if (slashPos >= 0) + { + s.DeleteFrom(slashPos); + skipLen = slashPos + 1; + } + + CMyComPtr newFolder; + _folder->BindToFolder(s, &newFolder); + if (newFolder) + curPos += skipLen; + else if (_folderAltStreams) + { + int pos = s.Find(L':'); + if (pos >= 0) + { + UString baseName = s; + baseName.DeleteFrom(pos); + if (_folderAltStreams->BindToAltStreams(baseName, &newFolder) == S_OK && newFolder) + curPos += pos + 1; + } + } + + if (!newFolder) + break; + + SetNewFolder(newFolder); + } + } + + return S_OK; +} + +HRESULT CPanel::BindToPathAndRefresh(const UString &path) +{ + CDisableTimerProcessing disableTimerProcessing(*this); + CDisableNotify disableNotify(*this); + bool archiveIsOpened, encrypted; + UString s = path; + + #ifdef _WIN32 + if (!s.IsEmpty() && s[0] == '\"' && s.Back() == '\"') + { + s.DeleteBack(); + s.Delete(0); + } + #endif + + HRESULT res = BindToPath(s, UString(), archiveIsOpened, encrypted); + 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 = (LPWSTR)(LPCWSTR)name; + _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++) + { + 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), i, false); + 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: + { + code = code; + 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 = 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(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"\\\\?") + { + int pos = focusedName.ReverseFind_PathSepar(); + if (pos >= 0) + { + parentFolderPrefix = focusedName; + parentFolderPrefix.DeleteFrom(pos + 1); + focusedName.DeleteFrontal(pos + 1); + } + } + } + } + + CDisableTimerProcessing disableTimerProcessing(*this); + CDisableNotify disableNotify(*this); + + CMyComPtr 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) + { + { + bool archiveIsOpened; + bool encrypted; + BindToPath(parentFolderPrefix, UString(), archiveIsOpened, encrypted); + } + } + } + + 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(int index) +{ + if (index == kParentIndex) + { + OpenParentFolder(); + return; + } + CMyComPtr newFolder; + _folder->BindToFolder(index, &newFolder); + 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 indices; + GetOperatedItemIndices(indices); + Int32 realIndex = -1; + if (indices.Size() > 1) + return; + if (indices.Size() == 1) + realIndex = indices[0]; + + if (_folderAltStreams) + { + CMyComPtr newFolder; + _folderAltStreams->BindToAltStreams(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(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 index 1ff888817..89f49bf69 100644 --- a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp +++ b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp @@ -1,1890 +1,1890 @@ -// PanelItemOpen.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#include - -#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 < 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 = (Func_GetProcessImageFileNameW) - ::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_GetProcessImageFileNameW)::GetProcAddress(g_Psapi_dll_module, func_name); - } - - if (my_func) - { - // DWORD num = GetProcessImageFileNameW(hProcess, temp, maxPath); - DWORD num = my_func(hProcess, temp, maxPath); - if (num != 0) - path = temp; - } - // FreeLibrary(lib); -} - -struct CSnapshotProcess -{ - DWORD Id; - DWORD ParentId; - UString Name; -}; - -static void GetSnapshot(CObjectVector &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 _ids; - #endif - -public: - // bool ProgsWereUsed; - CRecordVector Handles; - CRecordVector 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 - - Func_GetProcessId func = (Func_GetProcessId)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "GetProcessId"); - if (func) - { - 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 sps; - GetSnapshot(sps); - - const int separ = Path.ReverseFind_PathSepar(); - const UString mainName = Path.Ptr(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(); - } -}; - - -HRESULT CPanel::OpenAsArc(IInStream *inStream, - const CTempFileInfo &tempFileInfo, - const UString &virtualFilePath, - const UString &arcFormat, - bool &encrypted) -{ - encrypted = false; - CFolderLink folderLink; - (CTempFileInfo &)folderLink = tempFileInfo; - - if (inStream) - folderLink.IsVirtual = true; - else - { - if (!folderLink.FileInfo.Find(folderLink.FilePath)) - return ::GetLastError(); - if (folderLink.FileInfo.IsDir()) - return S_FALSE; - folderLink.IsVirtual = false; - } - - folderLink.VirtualPath = virtualFilePath; - - CMyComPtr newFolder; - - // _passwordIsDefined = false; - // _password.Empty(); - - NDLL::CLibrary library; - - UString password; - RINOK(OpenFileFolderPlugin(inStream, - folderLink.FilePath.IsEmpty() ? us2fs(virtualFilePath) : folderLink.FilePath, - arcFormat, - &library, &newFolder, GetParent(), encrypted, password)); - - folderLink.Password = password; - folderLink.UsePassword = 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(newFolder); - _library.Attach(library.Detach()); - - _flatMode = _flatModeForArc; - - CMyComPtr getFolderArcProps; - _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); - _thereAreDeletedItems = false; - - if (getFolderArcProps) - { - CMyComPtr arcProps; - getFolderArcProps->GetFolderArcProps(&arcProps); - if (arcProps) - { - /* - UString s; - UInt32 numLevels; - if (arcProps->GetArcNumLevels(&numLevels) != S_OK) - numLevels = 0; - for (UInt32 level2 = 0; level2 <= numLevels; level2++) - { - UInt32 level = numLevels - level2; - PROPID propIDs[] = { kpidError, kpidPath, kpidType, kpidErrorType } ; - UString values[4]; - 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) - values[i] = (prop.vt == VT_BSTR) ? prop.bstrVal : L"?"; - } - UString s2; - if (!values[3].IsEmpty()) - { - s2 = "Can not open the file as [" + values[3] + "] archive"; - if (level2 != 0) - s2 += "\nThe file is open as [" + values[2] + "] archive"; - } - if (!values[0].IsEmpty()) - { - if (!s2.IsEmpty()) - s2.Add_LF(); - s2 += "["; - s2 += values[2]; - s2 += "] Error: "; - s2 += values[0]; - } - if (!s2.IsEmpty()) - { - if (!s.IsEmpty()) - s += "--------------------\n"; - s += values[1]; - s.Add_LF(); - s += s2; - } - } - */ - /* - if (!s.IsEmpty()) - MessageBox_Warning(s); - else - */ - // 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) -{ - HRESULT res = OpenAsArc(inStream, tempFileInfo, virtualFilePath, arcFormat, encrypted); - - if (res == S_OK) - return res; - if (res == E_ABORT) - return res; - - if (showErrorMessage) - if (encrypted || res != S_FALSE) // 17.01 : we show message also for (res != S_FALSE) - { - UString message; - if (res == S_FALSE) - { - message = MyFormatNew( - 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(int index, const wchar_t *type, bool showErrorMessage) -{ - CDisableTimerProcessing disableTimerProcessing1(*this); - CDisableNotify disableNotify(*this); - bool encrypted; - 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 xsn" - " mpp" - " msg" - " dwf" - - " flv swf" - - " odt ods" - " wb3" - " pdf" - " "; - -static bool FindExt(const char *p, const UString &name) -{ - int dotPos = name.ReverseFind_Dot(); - if (dotPos < 0 || dotPos == (int)name.Len() - 1) - return false; - - AString s; - for (unsigned pos = dotPos + 1;; pos++) - { - 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 bool DoItemAlwaysStart(const UString &name) -{ - return FindExt(kStartExtensions, name); -} - -UString GetQuotedString(const UString &s); - - -void SplitCmdLineSmart(const UString &cmd, UString &prg, UString ¶ms) -{ - 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(pos + 1); - params.Trim(); - prg.DeleteFrom(pos); - prg.DeleteFrontal(1); - } - } - } -} - - -static WRes StartAppWithParams(const UString &cmd, const UStringVector ¶mVector, 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); - - HRESULT res = StartAppWithParams(command, params, process); - if (res != SZ_OK) - ::MessageBoxW(window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP); - return res; -} - - -void CApp::DiffFiles() -{ - const CPanel &panel = GetFocusedPanel(); - - if (!panel.Is_IO_FS_Folder()) - { - panel.MessageBox_Error_UnsupportOperation(); - return; - } - - CRecordVector indices; - panel.GetSelectedItemsIndices(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 indices2; - destPanel.GetSelectedItemsIndices(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; - - UString command; - ReadRegDiff(command); - if (command.IsEmpty()) - return; - - UStringVector params; - params.Add(path1); - params.Add(path2); - - HRESULT res; - { - CProcess process; - res = StartAppWithParams(command, params, process); - } - if (res == SZ_OK) - return; - ::MessageBoxW(_window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP); -} - - -#ifndef _UNICODE -typedef BOOL (WINAPI * ShellExecuteExWP)(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 += '.'; - } - #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 = 0; - ShellExecuteExWP shellExecuteExW = (ShellExecuteExWP) - ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "ShellExecuteExW"); - if (!shellExecuteExW) - return 0; - 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 = 0; - ::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(int 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(int 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(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()) - { - UString name3 = name2; - name3.DeleteFrom(i); - if (FindExt(kExeExtensions, name3)) - isVirus = true; - } - } - #endif - - if (!isVirus) - return false; - - UString s = LangString(IDS_VIRUS); - - if (!isSpaceError) - { - int pos1 = s.Find(L'('); - if (pos1 >= 0) - { - int pos2 = s.Find(L')', pos1 + 1); - if (pos2 >= 0) - { - s.Delete(pos1, pos2 + 1 - 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(int index, bool tryInternal, bool tryExternal, const wchar_t *type) -{ - CDisableTimerProcessing disableTimerProcessing(*this); - 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(); -public: - UString FullPath; - UInt32 ItemIndex; - - CMyComPtr FolderOperations; - CMyComPtr 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 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 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 = ::WaitForMultipleObjects(handles.Size(), &handles.Front(), FALSE, INFINITE); - - 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) - { - 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[waitResult]); - } - - firstPass = false; - - // Sleep(300); - #ifndef UNDER_CE - processes.Update(needFindProcessByPath /* , progs */); - #endif - } - - - 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); - UInt32 processed; - if (file.Read(buf, (UInt32)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 - -/* -class CBufSeqOutStream_WithFile: - public ISequentialOutStream, - public CMyUnknownImp -{ - 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 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; } - - MY_UNKNOWN_IMP - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); -}; - -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(int index, bool tryInternal, bool tryExternal, bool editMode, bool useEditor, const wchar_t *type) -{ - 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 getStream; - _folder.QueryInterface(IID_IInArchiveGetStream, &getStream); - if (getStream) - { - CMyComPtr subSeqStream; - getStream->GetStream(index, &subSeqStream); - if (subSeqStream) - { - CMyComPtr subStream; - subSeqStream.QueryInterface(IID_IInStream, &subStream); - if (subStream) - { - bool encrypted; - HRESULT res = OpenAsArc_Msg(subStream, tempFileInfo, fullVirtPath, type ? type : L"", encrypted, true); - if (res == S_OK) - { - tempDirectory.DisableDeleting(); - RefreshListCtrl(); - return; - } - if (res == E_ABORT || res != S_FALSE) - return; - if (!tryExternal) - return; - tryAsArchive = false; - } - } - } - } - - - CRecordVector 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 virtFileSystem; - - bool isAltStream = IsItem_AltStream(index); - - CCopyToOptions options; - options.includeAltStreams = true; - options.replaceAltStreamChars = isAltStream; - - 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; - - 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 bufInStream = bufInStreamSpec; - bufInStreamSpec->Init(file.Data, streamSize, virtFileSystem); - bool encrypted; - - HRESULT res = OpenAsArc_Msg(bufInStream, tempFileInfo, fullVirtPath, type ? type : L"", encrypted, true); - 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(tempFilePath)) - { - WriteZoneFile(tempFilePath + k_ZoneId_StreamName, zoneBuf); - } - } - #endif - - - if (tryAsArchive) - { - bool encrypted; - HRESULT res = OpenAsArc_Msg(NULL, tempFileInfo, fullVirtPath, type ? type : L"", encrypted, true); - if (res == S_OK) - { - tempDirectory.DisableDeleting(); - RefreshListCtrl(); - return; - } - if (res == E_ABORT || res != S_FALSE) - return; - } - - if (!tryExternal) - return; - - CMyAutoPtr 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 (!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 != SZ_OK) - return; - } - - tpi->Window = (HWND)(*this); - tpi->FullPathFolderPrefix = _currentFolderPrefix; - tpi->FileIndex = index; - tpi->RelPath = relPath; - - if ((HANDLE)process != 0) - 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); - } -} -*/ +// PanelItemOpen.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#include + +#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 < 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 = (Func_GetProcessImageFileNameW) + ::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_GetProcessImageFileNameW)::GetProcAddress(g_Psapi_dll_module, func_name); + } + + if (my_func) + { + // DWORD num = GetProcessImageFileNameW(hProcess, temp, maxPath); + DWORD num = my_func(hProcess, temp, maxPath); + if (num != 0) + path = temp; + } + // FreeLibrary(lib); +} + +struct CSnapshotProcess +{ + DWORD Id; + DWORD ParentId; + UString Name; +}; + +static void GetSnapshot(CObjectVector &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 _ids; + #endif + +public: + // bool ProgsWereUsed; + CRecordVector Handles; + CRecordVector 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 + + Func_GetProcessId func = (Func_GetProcessId)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "GetProcessId"); + if (func) + { + 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 sps; + GetSnapshot(sps); + + const int separ = Path.ReverseFind_PathSepar(); + const UString mainName = Path.Ptr(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(); + } +}; + + +HRESULT CPanel::OpenAsArc(IInStream *inStream, + const CTempFileInfo &tempFileInfo, + const UString &virtualFilePath, + const UString &arcFormat, + bool &encrypted) +{ + encrypted = false; + CFolderLink folderLink; + (CTempFileInfo &)folderLink = tempFileInfo; + + if (inStream) + folderLink.IsVirtual = true; + else + { + if (!folderLink.FileInfo.Find(folderLink.FilePath)) + return ::GetLastError(); + if (folderLink.FileInfo.IsDir()) + return S_FALSE; + folderLink.IsVirtual = false; + } + + folderLink.VirtualPath = virtualFilePath; + + CMyComPtr newFolder; + + // _passwordIsDefined = false; + // _password.Empty(); + + NDLL::CLibrary library; + + UString password; + RINOK(OpenFileFolderPlugin(inStream, + folderLink.FilePath.IsEmpty() ? us2fs(virtualFilePath) : folderLink.FilePath, + arcFormat, + &library, &newFolder, GetParent(), encrypted, password)); + + folderLink.Password = password; + folderLink.UsePassword = 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(newFolder); + _library.Attach(library.Detach()); + + _flatMode = _flatModeForArc; + + CMyComPtr getFolderArcProps; + _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); + _thereAreDeletedItems = false; + + if (getFolderArcProps) + { + CMyComPtr arcProps; + getFolderArcProps->GetFolderArcProps(&arcProps); + if (arcProps) + { + /* + UString s; + UInt32 numLevels; + if (arcProps->GetArcNumLevels(&numLevels) != S_OK) + numLevels = 0; + for (UInt32 level2 = 0; level2 <= numLevels; level2++) + { + UInt32 level = numLevels - level2; + PROPID propIDs[] = { kpidError, kpidPath, kpidType, kpidErrorType } ; + UString values[4]; + 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) + values[i] = (prop.vt == VT_BSTR) ? prop.bstrVal : L"?"; + } + UString s2; + if (!values[3].IsEmpty()) + { + s2 = "Can not open the file as [" + values[3] + "] archive"; + if (level2 != 0) + s2 += "\nThe file is open as [" + values[2] + "] archive"; + } + if (!values[0].IsEmpty()) + { + if (!s2.IsEmpty()) + s2.Add_LF(); + s2 += "["; + s2 += values[2]; + s2 += "] Error: "; + s2 += values[0]; + } + if (!s2.IsEmpty()) + { + if (!s.IsEmpty()) + s += "--------------------\n"; + s += values[1]; + s.Add_LF(); + s += s2; + } + } + */ + /* + if (!s.IsEmpty()) + MessageBox_Warning(s); + else + */ + // 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) +{ + HRESULT res = OpenAsArc(inStream, tempFileInfo, virtualFilePath, arcFormat, encrypted); + + if (res == S_OK) + return res; + if (res == E_ABORT) + return res; + + if (showErrorMessage) + if (encrypted || res != S_FALSE) // 17.01 : we show message also for (res != S_FALSE) + { + UString message; + if (res == S_FALSE) + { + message = MyFormatNew( + 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(int index, const wchar_t *type, bool showErrorMessage) +{ + CDisableTimerProcessing disableTimerProcessing1(*this); + CDisableNotify disableNotify(*this); + bool encrypted; + 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 xsn" + " mpp" + " msg" + " dwf" + + " flv swf" + + " odt ods" + " wb3" + " pdf" + " "; + +static bool FindExt(const char *p, const UString &name) +{ + int dotPos = name.ReverseFind_Dot(); + if (dotPos < 0 || dotPos == (int)name.Len() - 1) + return false; + + AString s; + for (unsigned pos = dotPos + 1;; pos++) + { + 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 bool DoItemAlwaysStart(const UString &name) +{ + return FindExt(kStartExtensions, name); +} + +UString GetQuotedString(const UString &s); + + +void SplitCmdLineSmart(const UString &cmd, UString &prg, UString ¶ms) +{ + 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(pos + 1); + params.Trim(); + prg.DeleteFrom(pos); + prg.DeleteFrontal(1); + } + } + } +} + + +static WRes StartAppWithParams(const UString &cmd, const UStringVector ¶mVector, 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); + + HRESULT res = StartAppWithParams(command, params, process); + if (res != SZ_OK) + ::MessageBoxW(window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP); + return res; +} + + +void CApp::DiffFiles() +{ + const CPanel &panel = GetFocusedPanel(); + + if (!panel.Is_IO_FS_Folder()) + { + panel.MessageBox_Error_UnsupportOperation(); + return; + } + + CRecordVector indices; + panel.GetSelectedItemsIndices(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 indices2; + destPanel.GetSelectedItemsIndices(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; + + UString command; + ReadRegDiff(command); + if (command.IsEmpty()) + return; + + UStringVector params; + params.Add(path1); + params.Add(path2); + + HRESULT res; + { + CProcess process; + res = StartAppWithParams(command, params, process); + } + if (res == SZ_OK) + return; + ::MessageBoxW(_window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP); +} + + +#ifndef _UNICODE +typedef BOOL (WINAPI * ShellExecuteExWP)(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 += '.'; + } + #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 = 0; + ShellExecuteExWP shellExecuteExW = (ShellExecuteExWP) + ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "ShellExecuteExW"); + if (!shellExecuteExW) + return 0; + 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 = 0; + ::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(int 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(int 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(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()) + { + UString name3 = name2; + name3.DeleteFrom(i); + if (FindExt(kExeExtensions, name3)) + isVirus = true; + } + } + #endif + + if (!isVirus) + return false; + + UString s = LangString(IDS_VIRUS); + + if (!isSpaceError) + { + int pos1 = s.Find(L'('); + if (pos1 >= 0) + { + int pos2 = s.Find(L')', pos1 + 1); + if (pos2 >= 0) + { + s.Delete(pos1, pos2 + 1 - 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(int index, bool tryInternal, bool tryExternal, const wchar_t *type) +{ + CDisableTimerProcessing disableTimerProcessing(*this); + 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(); +public: + UString FullPath; + UInt32 ItemIndex; + + CMyComPtr FolderOperations; + CMyComPtr 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 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 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 = ::WaitForMultipleObjects(handles.Size(), &handles.Front(), FALSE, INFINITE); + + 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) + { + 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[waitResult]); + } + + firstPass = false; + + // Sleep(300); + #ifndef UNDER_CE + processes.Update(needFindProcessByPath /* , progs */); + #endif + } + + + 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); + UInt32 processed; + if (file.Read(buf, (UInt32)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 + +/* +class CBufSeqOutStream_WithFile: + public ISequentialOutStream, + public CMyUnknownImp +{ + 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 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; } + + MY_UNKNOWN_IMP + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; + +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(int index, bool tryInternal, bool tryExternal, bool editMode, bool useEditor, const wchar_t *type) +{ + 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 getStream; + _folder.QueryInterface(IID_IInArchiveGetStream, &getStream); + if (getStream) + { + CMyComPtr subSeqStream; + getStream->GetStream(index, &subSeqStream); + if (subSeqStream) + { + CMyComPtr subStream; + subSeqStream.QueryInterface(IID_IInStream, &subStream); + if (subStream) + { + bool encrypted; + HRESULT res = OpenAsArc_Msg(subStream, tempFileInfo, fullVirtPath, type ? type : L"", encrypted, true); + if (res == S_OK) + { + tempDirectory.DisableDeleting(); + RefreshListCtrl(); + return; + } + if (res == E_ABORT || res != S_FALSE) + return; + if (!tryExternal) + return; + tryAsArchive = false; + } + } + } + } + + + CRecordVector 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 virtFileSystem; + + bool isAltStream = IsItem_AltStream(index); + + CCopyToOptions options; + options.includeAltStreams = true; + options.replaceAltStreamChars = isAltStream; + + 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; + + 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 bufInStream = bufInStreamSpec; + bufInStreamSpec->Init(file.Data, streamSize, virtFileSystem); + bool encrypted; + + HRESULT res = OpenAsArc_Msg(bufInStream, tempFileInfo, fullVirtPath, type ? type : L"", encrypted, true); + 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(tempFilePath)) + { + WriteZoneFile(tempFilePath + k_ZoneId_StreamName, zoneBuf); + } + } + #endif + + + if (tryAsArchive) + { + bool encrypted; + HRESULT res = OpenAsArc_Msg(NULL, tempFileInfo, fullVirtPath, type ? type : L"", encrypted, true); + if (res == S_OK) + { + tempDirectory.DisableDeleting(); + RefreshListCtrl(); + return; + } + if (res == E_ABORT || res != S_FALSE) + return; + } + + if (!tryExternal) + return; + + CMyAutoPtr 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 (!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 != SZ_OK) + return; + } + + tpi->Window = (HWND)(*this); + tpi->FullPathFolderPrefix = _currentFolderPrefix; + tpi->FileIndex = index; + tpi->RelPath = relPath; + + if ((HANDLE)process != 0) + 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 index 7fce2321f..178df7c7f 100644 --- a/CPP/7zip/UI/FileManager/PanelItems.cpp +++ b/CPP/7zip/UI/FileManager/PanelItems.cpp @@ -1,1269 +1,1269 @@ -// 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 kpidAttrib: - case kpidPackSize: - case kpidINode: - case kpidLinks: - case kpidNtReparse: - return false; - } - } - return true; -} - -static int 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: - 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 **)a1))).Compare_NameFirst(*(*((const CPropColumn **)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); - } - } - - 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]; - 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 = order++; - continue; - } - } - - for (i = 0; i < _columns.Size(); i++) - { - CPropColumn &item = _columns[i]; - if (item.IsVisible && item.Order < 0) - item.Order = order++; - } - - for (i = 0; i < _columns.Size(); i++) - { - CPropColumn &item = _columns[i]; - if (item.Order < 0) - item.Order = 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 can not 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] = i; - else - orderError = true; - } - - for (;;) - { - 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 int index = _visibleColumns.Size(); - - LV_COLUMNW column; - column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER; - column.cx = prop.Width; - column.fmt = GetColumnAlign(prop.ID, prop.Type); - column.iOrder = index; // must be <= _listView.ItemCount - column.iSubItem = index; // must be <= _listView.ItemCount - column.pszText = const_cast((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 indices; - GetSelectedItemsIndices(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; - int 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) - { - int 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() -{ - CSelectedState state; - SaveSelectedState(state); - 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) - { - int 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 - - -HRESULT CPanel::RefreshListCtrl(const CSelectedState &state) -{ - if (!_folder) - return S_OK; - - _dontShowMode = false; - 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 folderSetFlatMode; - _folder.QueryInterface(IID_IFolderSetFlatMode, &folderSetFlatMode); - if (folderSetFlatMode) - folderSetFlatMode->SetFlatMode(BoolToInt(_flatMode)); - } - - /* - { - CMyComPtr setShow; - _folder.QueryInterface(IID_IFolderSetShowNtfsStreamsMode, &setShow); - if (setShow) - setShow->SetShowNtfsStreamsMode(BoolToInt(_showNtfsStrems_Mode)); - } - */ - - // DWORD tickCount1 = GetTickCount(); - RINOK(_folder->LoadItems()); - // DWORD tickCount2 = GetTickCount(); - RINOK(InitColumns()); - - // OutputDebugString(TEXT("Start Dir\n")); - UInt32 numItems; - _folder->GetNumberOfItems(&numItems); - - bool showDots = _showDots && !IsRootFolder(); - - _listView.SetItemCount(numItems + (showDots ? 1 : 0)); - - _selectedStatusVector.ClearAndReserve(numItems); - int cursorIndex = -1; - - CMyComPtr folderGetSystemIconIndex; - if (!Is_Slow_Icon_Folder() || _showRealFileIcons) - _folder.QueryInterface(IID_IFolderGetSystemIconIndex, &folderGetSystemIconIndex); - - if (!IsFSFolder()) - { - CMyComPtr getFolderArcProps; - _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); - _thereAreDeletedItems = false; - if (getFolderArcProps) - { - CMyComPtr 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"); - - if (showDots) - { - 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 = kParentIndex; - // item.pszText = const_cast((const wchar_t *)itemName); - item.pszText = LPSTR_TEXTCALLBACKW; - 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); - // change it (_flatMode) - if (i != kParentIndex && _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) >= 0) - 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 = 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((const wchar_t *)correctedName); - } - else - */ - { - // item.pszText = const_cast((const wchar_t *)name); - item.pszText = LPSTR_TEXTCALLBACKW; - /* 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::GetSelectedItemsIndices(CRecordVector &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(); - unsigned size = _selectedStatusVector.Size(); - for (unsigned i = 0; i < size; i++) - if (v[i]) - indices.Add(i); -} - - -void CPanel::GetOperatedItemIndices(CRecordVector &indices) const -{ - GetSelectedItemsIndices(indices); - if (!indices.IsEmpty()) - return; - if (_listView.GetSelectedCount() == 0) - return; - int focusedItem = _listView.GetFocusedItem(); - if (focusedItem >= 0) - { - if (_listView.IsItemSelected(focusedItem)) - { - int realIndex = GetRealItemIndex(focusedItem); - if (realIndex != kParentIndex) - indices.Add(realIndex); - } - } -} - -void CPanel::GetAllItemIndices(CRecordVector &indices) const -{ - indices.Clear(); - UInt32 numItems; - if (_folder->GetNumberOfItems(&numItems) == S_OK) - for (UInt32 i = 0; i < numItems; i++) - indices.Add(i); -} - -void CPanel::GetOperatedIndicesSmart(CRecordVector &indices) const -{ - GetOperatedItemIndices(indices); - if (indices.IsEmpty() || (indices.Size() == 1 && indices[0] == (UInt32)(Int32)-1)) - GetAllItemIndices(indices); -} - -/* -void CPanel::GetOperatedListViewIndices(CRecordVector &indices) const -{ - indices.Clear(); - int numItems = _listView.GetItemCount(); - for (int i = 0; i < numItems; i++) - { - int realIndex = GetRealItemIndex(i); - if (realIndex >= 0) - if (_selectedStatusVector[realIndex]) - indices.Add(i); - } - if (indices.IsEmpty()) - { - int focusedItem = _listView.GetFocusedItem(); - if (focusedItem >= 0) - indices.Add(focusedItem); - } -} -*/ - -void CPanel::EditItem(bool useEditor) -{ - if (!useEditor) - { - CMyComPtr calcItemFullSize; - _folder.QueryInterface(IID_IFolderCalcItemFullSize, &calcItemFullSize); - if (calcItemFullSize) - { - bool needRefresh = false; - CRecordVector indices; - GetOperatedItemIndices(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; - } - } - } - - - int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - int realIndex = GetRealItemIndex(focusedItem); - if (realIndex == kParentIndex) - return; - if (!IsItem_Folder(realIndex)) - EditItem(realIndex, useEditor); -} - -void CPanel::OpenFocusedItemAsInternal(const wchar_t *type) -{ - int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - int realIndex = GetRealItemIndex(focusedItem); - if (IsItem_Folder(realIndex)) - OpenFolder(realIndex); - else - OpenItem(realIndex, true, false, type); -} - -void CPanel::OpenSelectedItems(bool tryInternal) -{ - CRecordVector indices; - GetOperatedItemIndices(indices); - if (indices.Size() > 20) - { - MessageBox_Error_LangID(IDS_TOO_MANY_ITEMS); - return; - } - - int focusedItem = _listView.GetFocusedItem(); - if (focusedItem >= 0) - { - int 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(int 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(int 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(int 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(int 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(int itemIndex) const -{ - return GetItemPrefix(itemIndex) + GetItemName(itemIndex); -} - -UString CPanel::GetItemRelPath2(int 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; -} - -UString CPanel::GetItemFullPath(int 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(int itemIndex) const -{ - if (itemIndex == kParentIndex) - return false; - return GetItem_BoolProp(itemIndex, kpidIsDeleted); -} - -bool CPanel::IsItem_Folder(int itemIndex) const -{ - if (itemIndex == kParentIndex) - return true; - return GetItem_BoolProp(itemIndex, kpidIsDir); -} - -bool CPanel::IsItem_AltStream(int itemIndex) const -{ - if (itemIndex == kParentIndex) - return false; - return GetItem_BoolProp(itemIndex, kpidIsAltStream); -} - -UInt64 CPanel::GetItem_UInt64Prop(int 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(int 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 = 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); - } - - int menuResult = menu.Track(TPM_LEFTALIGN | TPM_RETURNCMD | TPM_NONOTIFY, x, y, _listView); - - if (menuResult >= kCommandStart && menuResult <= kCommandStart + (int)_columns.Size()) - { - int index = menuResult - kCommandStart; - CPropColumn &prop = _columns[index]; - prop.IsVisible = !prop.IsVisible; - - if (prop.IsVisible) - { - prop.Order = _visibleColumns.Size(); - AddColumn(prop); - } - else - { - 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(visibleIndex); - } - } - } -} - -void CPanel::OnReload() -{ - HRESULT res = RefreshListCtrl_SaveFocused(); - if (res != S_OK) - MessageBox_Error_HRESULT(res); -} - -void CPanel::OnTimer() -{ - if (!_processTimer) - return; - if (!AutoRefresh_Mode) - return; - CMyComPtr folderWasChanged; - if (_folder.QueryInterface(IID_IFolderWasChanged, &folderWasChanged) != S_OK) - return; - Int32 wasChanged; - if (folderWasChanged->WasChanged(&wasChanged) != S_OK) - return; - if (wasChanged == 0) - return; - OnReload(); -} +// 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 kpidAttrib: + case kpidPackSize: + case kpidINode: + case kpidLinks: + case kpidNtReparse: + return false; + } + } + return true; +} + +static int 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: + 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 **)a1))).Compare_NameFirst(*(*((const CPropColumn **)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); + } + } + + 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]; + 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 = order++; + continue; + } + } + + for (i = 0; i < _columns.Size(); i++) + { + CPropColumn &item = _columns[i]; + if (item.IsVisible && item.Order < 0) + item.Order = order++; + } + + for (i = 0; i < _columns.Size(); i++) + { + CPropColumn &item = _columns[i]; + if (item.Order < 0) + item.Order = 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 can not 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] = i; + else + orderError = true; + } + + for (;;) + { + 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 int index = _visibleColumns.Size(); + + LV_COLUMNW column; + column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER; + column.cx = prop.Width; + column.fmt = GetColumnAlign(prop.ID, prop.Type); + column.iOrder = index; // must be <= _listView.ItemCount + column.iSubItem = index; // must be <= _listView.ItemCount + column.pszText = const_cast((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 indices; + GetSelectedItemsIndices(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; + int 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) + { + int 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() +{ + CSelectedState state; + SaveSelectedState(state); + 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) + { + int 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 + + +HRESULT CPanel::RefreshListCtrl(const CSelectedState &state) +{ + if (!_folder) + return S_OK; + + _dontShowMode = false; + 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 folderSetFlatMode; + _folder.QueryInterface(IID_IFolderSetFlatMode, &folderSetFlatMode); + if (folderSetFlatMode) + folderSetFlatMode->SetFlatMode(BoolToInt(_flatMode)); + } + + /* + { + CMyComPtr setShow; + _folder.QueryInterface(IID_IFolderSetShowNtfsStreamsMode, &setShow); + if (setShow) + setShow->SetShowNtfsStreamsMode(BoolToInt(_showNtfsStrems_Mode)); + } + */ + + // DWORD tickCount1 = GetTickCount(); + RINOK(_folder->LoadItems()); + // DWORD tickCount2 = GetTickCount(); + RINOK(InitColumns()); + + // OutputDebugString(TEXT("Start Dir\n")); + UInt32 numItems; + _folder->GetNumberOfItems(&numItems); + + bool showDots = _showDots && !IsRootFolder(); + + _listView.SetItemCount(numItems + (showDots ? 1 : 0)); + + _selectedStatusVector.ClearAndReserve(numItems); + int cursorIndex = -1; + + CMyComPtr folderGetSystemIconIndex; + if (!Is_Slow_Icon_Folder() || _showRealFileIcons) + _folder.QueryInterface(IID_IFolderGetSystemIconIndex, &folderGetSystemIconIndex); + + if (!IsFSFolder()) + { + CMyComPtr getFolderArcProps; + _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); + _thereAreDeletedItems = false; + if (getFolderArcProps) + { + CMyComPtr 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"); + + if (showDots) + { + 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 = kParentIndex; + // item.pszText = const_cast((const wchar_t *)itemName); + item.pszText = LPSTR_TEXTCALLBACKW; + 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); + // change it (_flatMode) + if (i != kParentIndex && _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) >= 0) + 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 = 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((const wchar_t *)correctedName); + } + else + */ + { + // item.pszText = const_cast((const wchar_t *)name); + item.pszText = LPSTR_TEXTCALLBACKW; + /* 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::GetSelectedItemsIndices(CRecordVector &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(); + unsigned size = _selectedStatusVector.Size(); + for (unsigned i = 0; i < size; i++) + if (v[i]) + indices.Add(i); +} + + +void CPanel::GetOperatedItemIndices(CRecordVector &indices) const +{ + GetSelectedItemsIndices(indices); + if (!indices.IsEmpty()) + return; + if (_listView.GetSelectedCount() == 0) + return; + int focusedItem = _listView.GetFocusedItem(); + if (focusedItem >= 0) + { + if (_listView.IsItemSelected(focusedItem)) + { + int realIndex = GetRealItemIndex(focusedItem); + if (realIndex != kParentIndex) + indices.Add(realIndex); + } + } +} + +void CPanel::GetAllItemIndices(CRecordVector &indices) const +{ + indices.Clear(); + UInt32 numItems; + if (_folder->GetNumberOfItems(&numItems) == S_OK) + for (UInt32 i = 0; i < numItems; i++) + indices.Add(i); +} + +void CPanel::GetOperatedIndicesSmart(CRecordVector &indices) const +{ + GetOperatedItemIndices(indices); + if (indices.IsEmpty() || (indices.Size() == 1 && indices[0] == (UInt32)(Int32)-1)) + GetAllItemIndices(indices); +} + +/* +void CPanel::GetOperatedListViewIndices(CRecordVector &indices) const +{ + indices.Clear(); + int numItems = _listView.GetItemCount(); + for (int i = 0; i < numItems; i++) + { + int realIndex = GetRealItemIndex(i); + if (realIndex >= 0) + if (_selectedStatusVector[realIndex]) + indices.Add(i); + } + if (indices.IsEmpty()) + { + int focusedItem = _listView.GetFocusedItem(); + if (focusedItem >= 0) + indices.Add(focusedItem); + } +} +*/ + +void CPanel::EditItem(bool useEditor) +{ + if (!useEditor) + { + CMyComPtr calcItemFullSize; + _folder.QueryInterface(IID_IFolderCalcItemFullSize, &calcItemFullSize); + if (calcItemFullSize) + { + bool needRefresh = false; + CRecordVector indices; + GetOperatedItemIndices(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; + } + } + } + + + int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + int realIndex = GetRealItemIndex(focusedItem); + if (realIndex == kParentIndex) + return; + if (!IsItem_Folder(realIndex)) + EditItem(realIndex, useEditor); +} + +void CPanel::OpenFocusedItemAsInternal(const wchar_t *type) +{ + int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + int realIndex = GetRealItemIndex(focusedItem); + if (IsItem_Folder(realIndex)) + OpenFolder(realIndex); + else + OpenItem(realIndex, true, false, type); +} + +void CPanel::OpenSelectedItems(bool tryInternal) +{ + CRecordVector indices; + GetOperatedItemIndices(indices); + if (indices.Size() > 20) + { + MessageBox_Error_LangID(IDS_TOO_MANY_ITEMS); + return; + } + + int focusedItem = _listView.GetFocusedItem(); + if (focusedItem >= 0) + { + int 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(int 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(int 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(int 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(int 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(int itemIndex) const +{ + return GetItemPrefix(itemIndex) + GetItemName(itemIndex); +} + +UString CPanel::GetItemRelPath2(int 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; +} + +UString CPanel::GetItemFullPath(int 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(int itemIndex) const +{ + if (itemIndex == kParentIndex) + return false; + return GetItem_BoolProp(itemIndex, kpidIsDeleted); +} + +bool CPanel::IsItem_Folder(int itemIndex) const +{ + if (itemIndex == kParentIndex) + return true; + return GetItem_BoolProp(itemIndex, kpidIsDir); +} + +bool CPanel::IsItem_AltStream(int itemIndex) const +{ + if (itemIndex == kParentIndex) + return false; + return GetItem_BoolProp(itemIndex, kpidIsAltStream); +} + +UInt64 CPanel::GetItem_UInt64Prop(int 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(int 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 = 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); + } + + int menuResult = menu.Track(TPM_LEFTALIGN | TPM_RETURNCMD | TPM_NONOTIFY, x, y, _listView); + + if (menuResult >= kCommandStart && menuResult <= kCommandStart + (int)_columns.Size()) + { + int index = menuResult - kCommandStart; + CPropColumn &prop = _columns[index]; + prop.IsVisible = !prop.IsVisible; + + if (prop.IsVisible) + { + prop.Order = _visibleColumns.Size(); + AddColumn(prop); + } + else + { + 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(visibleIndex); + } + } + } +} + +void CPanel::OnReload() +{ + HRESULT res = RefreshListCtrl_SaveFocused(); + if (res != S_OK) + MessageBox_Error_HRESULT(res); +} + +void CPanel::OnTimer() +{ + if (!_processTimer) + return; + if (!AutoRefresh_Mode) + return; + CMyComPtr folderWasChanged; + if (_folder.QueryInterface(IID_IFolderWasChanged, &folderWasChanged) != S_OK) + return; + Int32 wasChanged; + if (folderWasChanged->WasChanged(&wasChanged) != S_OK) + return; + if (wasChanged == 0) + return; + OnReload(); +} diff --git a/CPP/7zip/UI/FileManager/PanelKey.cpp b/CPP/7zip/UI/FileManager/PanelKey.cpp index 113f38042..5603251f8 100644 --- a/CPP/7zip/UI/FileManager/PanelKey.cpp +++ b/CPP/7zip/UI/FileManager/PanelKey.cpp @@ -1,347 +1,347 @@ -// 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 (int i = 0; i < ARRAY_SIZE(g_VKeyPropIDPairs); i++) - if (g_VKeyPropIDPairs[i].VKey == vKey) - return i; - return -1; -} - - -bool CPanel::OnKeyDown(LPNMLVKEYDOWN keyDownInfo, LRESULT &result) -{ - if (keyDownInfo->wVKey == VK_TAB && keyDownInfo->hdr.hwndFrom == _listView) - { - _panelCallback->OnTab(); - return false; - } - bool alt = IsKeyDown(VK_MENU); - bool ctrl = IsKeyDown(VK_CONTROL); - // bool leftCtrl = IsKeyDown(VK_LCONTROL); - bool rightCtrl = IsKeyDown(VK_RCONTROL); - bool shift = IsKeyDown(VK_SHIFT); - result = 0; - - if (keyDownInfo->wVKey >= '0' && keyDownInfo->wVKey <= '9' && - (rightCtrl || alt)) - { - int index = 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) - { - 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 'Z': - if (ctrl) - { - ChangeComment(); - return true; - } - return false; - case '1': - case '2': - case '3': - case '4': - if (ctrl) - { - int styleIndex = 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; -} +// 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 (int i = 0; i < ARRAY_SIZE(g_VKeyPropIDPairs); i++) + if (g_VKeyPropIDPairs[i].VKey == vKey) + return i; + return -1; +} + + +bool CPanel::OnKeyDown(LPNMLVKEYDOWN keyDownInfo, LRESULT &result) +{ + if (keyDownInfo->wVKey == VK_TAB && keyDownInfo->hdr.hwndFrom == _listView) + { + _panelCallback->OnTab(); + return false; + } + bool alt = IsKeyDown(VK_MENU); + bool ctrl = IsKeyDown(VK_CONTROL); + // bool leftCtrl = IsKeyDown(VK_LCONTROL); + bool rightCtrl = IsKeyDown(VK_RCONTROL); + bool shift = IsKeyDown(VK_SHIFT); + result = 0; + + if (keyDownInfo->wVKey >= '0' && keyDownInfo->wVKey <= '9' && + (rightCtrl || alt)) + { + int index = 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) + { + 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 'Z': + if (ctrl) + { + ChangeComment(); + return true; + } + return false; + case '1': + case '2': + case '3': + case '4': + if (ctrl) + { + int styleIndex = 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 index f6306de7a..9061e585e 100644 --- a/CPP/7zip/UI/FileManager/PanelListNotify.cpp +++ b/CPP/7zip/UI/FileManager/PanelListNotify.cpp @@ -1,765 +1,765 @@ -// 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) -{ - wchar_t s[32]; - ConvertSizeToString(value, s); - return s; -} - -static inline unsigned GetHex(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() -{ - 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; -} - -LRESULT CPanel::SetItemText(LVITEMW &item) -{ - if (_dontShowMode) - return 0; - UInt32 realIndex = GetRealIndex(item); - - /* - if ((item.mask & LVIF_IMAGE) != 0) - { - bool defined = false; - CComPtr 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) - { - if (propID == kpidName) - { - if (item.cchTextMax > 2) - { - text[0] = '.'; - text[1] = '.'; - text[2] = 0; - } - } - return 0; - } - - - if (property.IsRawProp) - { - const void *data; - UInt32 dataSize; - UInt32 propType; - RINOK(_folderRawProps->GetRawProp(realIndex, propID, &data, &dataSize, &propType)); - unsigned limit = 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; - for (UInt32 i = 0; i < dataSize; i++) - { - unsigned b = ((const Byte *)data)[i]; - dest[0] = (WCHAR)GetHex((b >> 4) & 0xF); - dest[1] = (WCHAR)GetHex(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 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; - unsigned limit = item.cchTextMax - 1; - - for (unsigned i = 0; dest < limit;) - { - 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; - unsigned limit = item.cchTextMax - 1; - for (unsigned i = 0; dest < limit;) - { - wchar_t c = name[i++]; - if (c == 0) - break; - text[dest++] = c; - } - text[dest] = 0; - return 0; - } - } - } - - 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) - { - unsigned limit = 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; - unsigned limit = item.cchTextMax - 1; - for (i = 0; i < limit; i++) - { - 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) -{ - int index = (int)item->lParam; - if (index == kParentIndex) - return; - bool oldSelected = (item->uOldState & LVIS_SELECTED) != 0; - 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); - 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); - 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); - */ - int realIndex = (int)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 indices; - GetOperatedItemIndices(indices); - - wchar_t temp[32]; - ConvertUInt32ToString(indices.Size(), temp); - wcscat(temp, L" / "); - ConvertUInt32ToString(_selectedStatusVector.Size(), temp + wcslen(temp)); - - // 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, temp)); - // _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); - - int focusedItem = _listView.GetFocusedItem(); - wchar_t sizeString[32]; - sizeString[0] = 0; - wchar_t dateString[32]; - dateString[0] = 0; - if (focusedItem >= 0 && _listView.GetSelectedCount() > 0) - { - int 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); - */ -} +// 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) +{ + wchar_t s[32]; + ConvertSizeToString(value, s); + return s; +} + +static inline unsigned GetHex(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() +{ + 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; +} + +LRESULT CPanel::SetItemText(LVITEMW &item) +{ + if (_dontShowMode) + return 0; + UInt32 realIndex = GetRealIndex(item); + + /* + if ((item.mask & LVIF_IMAGE) != 0) + { + bool defined = false; + CComPtr 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) + { + if (propID == kpidName) + { + if (item.cchTextMax > 2) + { + text[0] = '.'; + text[1] = '.'; + text[2] = 0; + } + } + return 0; + } + + + if (property.IsRawProp) + { + const void *data; + UInt32 dataSize; + UInt32 propType; + RINOK(_folderRawProps->GetRawProp(realIndex, propID, &data, &dataSize, &propType)); + unsigned limit = 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; + for (UInt32 i = 0; i < dataSize; i++) + { + unsigned b = ((const Byte *)data)[i]; + dest[0] = (WCHAR)GetHex((b >> 4) & 0xF); + dest[1] = (WCHAR)GetHex(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 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; + unsigned limit = item.cchTextMax - 1; + + for (unsigned i = 0; dest < limit;) + { + 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; + unsigned limit = item.cchTextMax - 1; + for (unsigned i = 0; dest < limit;) + { + wchar_t c = name[i++]; + if (c == 0) + break; + text[dest++] = c; + } + text[dest] = 0; + return 0; + } + } + } + + 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) + { + unsigned limit = 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; + unsigned limit = item.cchTextMax - 1; + for (i = 0; i < limit; i++) + { + 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) +{ + int index = (int)item->lParam; + if (index == kParentIndex) + return; + bool oldSelected = (item->uOldState & LVIS_SELECTED) != 0; + 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); + 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); + 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); + */ + int realIndex = (int)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 indices; + GetOperatedItemIndices(indices); + + wchar_t temp[32]; + ConvertUInt32ToString(indices.Size(), temp); + wcscat(temp, L" / "); + ConvertUInt32ToString(_selectedStatusVector.Size(), temp + wcslen(temp)); + + // 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, temp)); + // _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); + + int focusedItem = _listView.GetFocusedItem(); + wchar_t sizeString[32]; + sizeString[0] = 0; + wchar_t dateString[32]; + dateString[0] = 0; + if (focusedItem >= 0 && _listView.GetSelectedCount() > 0) + { + int 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 index d11617044..11c6d7c1a 100644 --- a/CPP/7zip/UI/FileManager/PanelMenu.cpp +++ b/CPP/7zip/UI/FileManager/PanelMenu.cpp @@ -1,968 +1,968 @@ -#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 "resource.h" -#include "PropertyNameRes.h" - -using namespace NWindows; - -LONG g_DllRefCount = 0; - -static const UINT kSevenZipStartMenuID = kMenuCmdID_Plugin_Start; -static const UINT kSystemStartMenuID = kMenuCmdID_Plugin_Start + 100; - -void CPanel::InvokeSystemCommand(const char *command) -{ - NCOM::CComInitializer comInitializer; - if (!IsFsOrPureDrivesFolder()) - return; - CRecordVector operatedIndices; - GetOperatedItemIndices(operatedIndices); - if (operatedIndices.IsEmpty()) - return; - CMyComPtr 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); - - if (!val.IsEmpty()) - { - 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 char GetHex(Byte value) -{ - return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); -} - -static const Byte kSpecProps[] = -{ - kpidPath, - kpidType, - kpidErrorType, - kpidError, - kpidErrorFlags, - kpidWarning, - kpidWarningFlags, - kpidOffset, - kpidPhySize, - kpidTailSize -}; - -void CPanel::Properties() -{ - CMyComPtr getFolderArcProps; - _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); - if (!getFolderArcProps) - { - InvokeSystemCommand("properties"); - return; - } - - { - CListViewDialog message; - // message.DeleteIsAllowed = false; - // message.SelectFirst = false; - - CRecordVector operatedIndices; - GetOperatedItemIndices(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 - { - for (UInt32 k = 0; k < dataSize; k++) - { - Byte b = ((const Byte *)data)[k]; - s += GetHex((Byte)((b >> 4) & 0xF)); - s += GetHex((Byte)(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 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 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 = 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, 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) - { - UInt32 level = numLevels - 1 - level2; - UInt32 numProps; - if (getProps->GetArcNumProps2(level, &numProps) == S_OK) - { - AddSeparatorSmall(message); - for (Int32 i = 0; i < (Int32)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); - } - } - } - } - } - } - - message.Title = LangString(IDS_PROPERTIES); - message.NumColumns = 2; - message.Create(GetParent()); - } -} - - - -void CPanel::EditCut() -{ - // InvokeSystemCommand("cut"); -} - -void CPanel::EditCopy() -{ - /* - CMyComPtr getFolderArcProps; - _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); - if (!getFolderArcProps) - { - InvokeSystemCommand("copy"); - return; - } - */ - UString s; - CRecordVector indices; - GetSelectedItemsIndices(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 items; - - CFolderPidls(): parent(NULL) {} - ~CFolderPidls() - { - FOR_VECTOR (i, items) - CoTaskMemFree(items[i]); - CoTaskMemFree(parent); - } -}; - - -HRESULT CPanel::CreateShellContextMenu( - const CRecordVector &operatedIndices, - CMyComPtr &systemContextMenu) -{ - systemContextMenu.Release(); - const UString folderPath = GetFsPath(); - - CMyComPtr desktopFolder; - RINOK(::SHGetDesktopFolder(&desktopFolder)); - if (!desktopFolder) - { - // ShowMessage("Failed to get Desktop folder"); - return E_FAIL; - } - - CFolderPidls pidls; - DWORD eaten; - - // if (folderPath.IsEmpty()), then ParseDisplayName returns pidls of "My Computer" - RINOK(desktopFolder->ParseDisplayName( - GetParent(), NULL, (wchar_t *)(const wchar_t *)folderPath, - &eaten, &pidls.parent, NULL)); - - /* - STRRET pName; - res = desktopFolder->GetDisplayNameOf(pidls.parent, SHGDN_NORMAL, &pName); - WCHAR dir[MAX_PATH]; - if (!SHGetPathFromIDListW(pidls.parent, dir)) - dir[0] = 0; - */ - - if (!pidls.parent) - return E_FAIL; - - 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 parentFolder; - RINOK(desktopFolder->BindToObject(pidls.parent, - NULL, IID_IShellFolder, (void**)&parentFolder)); - if (!parentFolder) - { - // ShowMessage("Invalid file name"); - return E_FAIL; - } - - pidls.items.ClearAndReserve(operatedIndices.Size()); - FOR_VECTOR (i, operatedIndices) - { - LPITEMIDLIST pidl; - const UString fileName = GetItemRelPath2(operatedIndices[i]); - RINOK(parentFolder->ParseDisplayName(GetParent(), 0, - (wchar_t *)(const wchar_t *)fileName, &eaten, &pidl, 0)); - pidls.items.AddInReserved(pidl); - } - - // Get IContextMenu for items - - RINOK(parentFolder->GetUIObjectOf(GetParent(), pidls.items.Size(), - (LPCITEMIDLIST *)&pidls.items.Front(), IID_IContextMenu, 0, (void**)&systemContextMenu)); - - if (!systemContextMenu) - { - // ShowMessage("Unable to get context menu interface"); - return E_FAIL; - } - return S_OK; -} - - -void CPanel::CreateSystemMenu(HMENU menuSpec, - const CRecordVector &operatedIndices, - CMyComPtr &systemContextMenu) -{ - systemContextMenu.Release(); - - CreateShellContextMenu(operatedIndices, systemContextMenu); - - if (systemContextMenu == 0) - 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; - - HMENU hMenu = popupMenu; - - DWORD Flags = CMF_EXPLORE; - // Optionally the shell will show the extended - // context menu on some operating systems when - // the shift key is held down at the time the - // context menu is invoked. The following is - // commented out but you can uncommnent this - // line to show the extended context menu. - // Flags |= 0x00000080; - systemContextMenu->QueryContextMenu(hMenu, 0, kSystemStartMenuID, 0x7FFF, Flags); - - - { - 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); -} - -void CPanel::CreateSevenZipMenu(HMENU menuSpec, - const CRecordVector &operatedIndices, - CMyComPtr &sevenZipContextMenu) -{ - sevenZipContextMenu.Release(); - - CMenu menu; - menu.Attach(menuSpec); - // CMenuDestroyer menuDestroyer(menu); - // menu.CreatePopup(); - - bool sevenZipMenuCreated = false; - - CZipContextMenu *contextMenuSpec = new CZipContextMenu; - CMyComPtr contextMenu = contextMenuSpec; - // if (contextMenu.CoCreateInstance(CLSID_CZipContextMenu, IID_IContextMenu) == S_OK) - { - /* - CMyComPtr initContextMenu; - if (contextMenu.QueryInterface(IID_IInitContextMenu, &initContextMenu) != S_OK) - return; - */ - UString currentFolderUnicode = GetFsPath(); - UStringVector names; - unsigned i; - for (i = 0; i < operatedIndices.Size(); i++) - names.Add(currentFolderUnicode + GetItemRelPath2(operatedIndices[i])); - CRecordVector namePointers; - for (i = 0; i < operatedIndices.Size(); i++) - namePointers.Add(names[i]); - - // NFile::NDirectory::MySetCurrentDirectory(currentFolderUnicode); - if (contextMenuSpec->InitContextMenu(currentFolderUnicode, &namePointers.Front(), - operatedIndices.Size()) == S_OK) - { - HRESULT res = contextMenu->QueryContextMenu(menu, 0, kSevenZipStartMenuID, - kSystemStartMenuID - 1, 0); - sevenZipMenuCreated = (HRESULT_SEVERITY(res) == SEVERITY_SUCCESS); - if (sevenZipMenuCreated) - sevenZipContextMenu = contextMenu; - // 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 &sevenZipContextMenu, - CMyComPtr &systemContextMenu, - bool programMenu) -{ - sevenZipContextMenu.Release(); - systemContextMenu.Release(); - - CRecordVector operatedIndices; - GetOperatedItemIndices(operatedIndices); - - CMenu menu; - menu.Attach(menuSpec); - - if (!IsArcFolder()) - { - CreateSevenZipMenu(menu, operatedIndices, 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, operatedIndices, systemContextMenu); - } - - /* - if (menu.GetItemCount() > 0) - menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)0); - */ - - unsigned i; - for (i = 0; i < operatedIndices.Size(); i++) - if (IsItem_Folder(operatedIndices[i])) - break; - bool allAreFiles = (i == operatedIndices.Size()); - - CFileMenu fm; - - fm.readOnly = IsThereReadOnlyFolder(); - fm.isFsFolder = Is_IO_FS_Folder(); - fm.programMenu = programMenu; - fm.allAreFiles = allAreFiles; - fm.numItems = operatedIndices.Size(); - - fm.isAltStreamsSupported = false; - - if (_folderAltStreams) - { - if (operatedIndices.Size() <= 1) - { - Int32 realIndex = -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, menu.GetItemCount()); -} - -bool CPanel::InvokePluginCommand(int id) -{ - return InvokePluginCommand(id, _sevenZipContextMenu, _systemContextMenu); -} - -#if defined(_MSC_VER) && !defined(UNDER_CE) -#define use_CMINVOKECOMMANDINFOEX -#endif - -bool CPanel::InvokePluginCommand(int id, - IContextMenu *sevenZipContextMenu, IContextMenu *systemContextMenu) -{ - UInt32 offset; - bool isSystemMenu = (id >= kSystemStartMenuID); - if (isSystemMenu) - offset = id - kSystemStartMenuID; - else - 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; - const CSysString currentFolderSys (GetSystemString(_currentFolderPrefix)); - commandInfo.lpDirectory = (LPCSTR)(LPCTSTR)(currentFolderSys); - commandInfo.nShow = SW_SHOW; - - #ifdef use_CMINVOKECOMMANDINFOEX - - commandInfo.lpParametersW = NULL; - commandInfo.lpTitle = ""; - commandInfo.lpVerbW = (LPCWSTR)(MAKEINTRESOURCEW(offset)); - 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; - } - 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 operatedIndices; - GetOperatedItemIndices(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 sevenZipContextMenu; - CMyComPtr systemContextMenu; - CreateFileMenu(menu, sevenZipContextMenu, systemContextMenu, false); - - int result = menu.Track(TPM_LEFTALIGN - #ifndef UNDER_CE - | TPM_RIGHTBUTTON - #endif - | TPM_RETURNCMD | TPM_NONOTIFY, - xPos, yPos, _listView); - - if (result == 0) - return true; - - if (result >= kMenuCmdID_Plugin_Start) - { - InvokePluginCommand(result, sevenZipContextMenu, systemContextMenu); - return true; - } - if (ExecuteFileCommand(result)) - return true; - return true; -} +#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 "resource.h" +#include "PropertyNameRes.h" + +using namespace NWindows; + +LONG g_DllRefCount = 0; + +static const UINT kSevenZipStartMenuID = kMenuCmdID_Plugin_Start; +static const UINT kSystemStartMenuID = kMenuCmdID_Plugin_Start + 100; + +void CPanel::InvokeSystemCommand(const char *command) +{ + NCOM::CComInitializer comInitializer; + if (!IsFsOrPureDrivesFolder()) + return; + CRecordVector operatedIndices; + GetOperatedItemIndices(operatedIndices); + if (operatedIndices.IsEmpty()) + return; + CMyComPtr 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); + + if (!val.IsEmpty()) + { + 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 char GetHex(Byte value) +{ + return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); +} + +static const Byte kSpecProps[] = +{ + kpidPath, + kpidType, + kpidErrorType, + kpidError, + kpidErrorFlags, + kpidWarning, + kpidWarningFlags, + kpidOffset, + kpidPhySize, + kpidTailSize +}; + +void CPanel::Properties() +{ + CMyComPtr getFolderArcProps; + _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); + if (!getFolderArcProps) + { + InvokeSystemCommand("properties"); + return; + } + + { + CListViewDialog message; + // message.DeleteIsAllowed = false; + // message.SelectFirst = false; + + CRecordVector operatedIndices; + GetOperatedItemIndices(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 + { + for (UInt32 k = 0; k < dataSize; k++) + { + Byte b = ((const Byte *)data)[k]; + s += GetHex((Byte)((b >> 4) & 0xF)); + s += GetHex((Byte)(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 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 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 = 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, 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) + { + UInt32 level = numLevels - 1 - level2; + UInt32 numProps; + if (getProps->GetArcNumProps2(level, &numProps) == S_OK) + { + AddSeparatorSmall(message); + for (Int32 i = 0; i < (Int32)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); + } + } + } + } + } + } + + message.Title = LangString(IDS_PROPERTIES); + message.NumColumns = 2; + message.Create(GetParent()); + } +} + + + +void CPanel::EditCut() +{ + // InvokeSystemCommand("cut"); +} + +void CPanel::EditCopy() +{ + /* + CMyComPtr getFolderArcProps; + _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); + if (!getFolderArcProps) + { + InvokeSystemCommand("copy"); + return; + } + */ + UString s; + CRecordVector indices; + GetSelectedItemsIndices(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 items; + + CFolderPidls(): parent(NULL) {} + ~CFolderPidls() + { + FOR_VECTOR (i, items) + CoTaskMemFree(items[i]); + CoTaskMemFree(parent); + } +}; + + +HRESULT CPanel::CreateShellContextMenu( + const CRecordVector &operatedIndices, + CMyComPtr &systemContextMenu) +{ + systemContextMenu.Release(); + const UString folderPath = GetFsPath(); + + CMyComPtr desktopFolder; + RINOK(::SHGetDesktopFolder(&desktopFolder)); + if (!desktopFolder) + { + // ShowMessage("Failed to get Desktop folder"); + return E_FAIL; + } + + CFolderPidls pidls; + DWORD eaten; + + // if (folderPath.IsEmpty()), then ParseDisplayName returns pidls of "My Computer" + RINOK(desktopFolder->ParseDisplayName( + GetParent(), NULL, (wchar_t *)(const wchar_t *)folderPath, + &eaten, &pidls.parent, NULL)); + + /* + STRRET pName; + res = desktopFolder->GetDisplayNameOf(pidls.parent, SHGDN_NORMAL, &pName); + WCHAR dir[MAX_PATH]; + if (!SHGetPathFromIDListW(pidls.parent, dir)) + dir[0] = 0; + */ + + if (!pidls.parent) + return E_FAIL; + + 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 parentFolder; + RINOK(desktopFolder->BindToObject(pidls.parent, + NULL, IID_IShellFolder, (void**)&parentFolder)); + if (!parentFolder) + { + // ShowMessage("Invalid file name"); + return E_FAIL; + } + + pidls.items.ClearAndReserve(operatedIndices.Size()); + FOR_VECTOR (i, operatedIndices) + { + LPITEMIDLIST pidl; + const UString fileName = GetItemRelPath2(operatedIndices[i]); + RINOK(parentFolder->ParseDisplayName(GetParent(), 0, + (wchar_t *)(const wchar_t *)fileName, &eaten, &pidl, 0)); + pidls.items.AddInReserved(pidl); + } + + // Get IContextMenu for items + + RINOK(parentFolder->GetUIObjectOf(GetParent(), pidls.items.Size(), + (LPCITEMIDLIST *)&pidls.items.Front(), IID_IContextMenu, 0, (void**)&systemContextMenu)); + + if (!systemContextMenu) + { + // ShowMessage("Unable to get context menu interface"); + return E_FAIL; + } + return S_OK; +} + + +void CPanel::CreateSystemMenu(HMENU menuSpec, + const CRecordVector &operatedIndices, + CMyComPtr &systemContextMenu) +{ + systemContextMenu.Release(); + + CreateShellContextMenu(operatedIndices, systemContextMenu); + + if (systemContextMenu == 0) + 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; + + HMENU hMenu = popupMenu; + + DWORD Flags = CMF_EXPLORE; + // Optionally the shell will show the extended + // context menu on some operating systems when + // the shift key is held down at the time the + // context menu is invoked. The following is + // commented out but you can uncommnent this + // line to show the extended context menu. + // Flags |= 0x00000080; + systemContextMenu->QueryContextMenu(hMenu, 0, kSystemStartMenuID, 0x7FFF, Flags); + + + { + 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); +} + +void CPanel::CreateSevenZipMenu(HMENU menuSpec, + const CRecordVector &operatedIndices, + CMyComPtr &sevenZipContextMenu) +{ + sevenZipContextMenu.Release(); + + CMenu menu; + menu.Attach(menuSpec); + // CMenuDestroyer menuDestroyer(menu); + // menu.CreatePopup(); + + bool sevenZipMenuCreated = false; + + CZipContextMenu *contextMenuSpec = new CZipContextMenu; + CMyComPtr contextMenu = contextMenuSpec; + // if (contextMenu.CoCreateInstance(CLSID_CZipContextMenu, IID_IContextMenu) == S_OK) + { + /* + CMyComPtr initContextMenu; + if (contextMenu.QueryInterface(IID_IInitContextMenu, &initContextMenu) != S_OK) + return; + */ + UString currentFolderUnicode = GetFsPath(); + UStringVector names; + unsigned i; + for (i = 0; i < operatedIndices.Size(); i++) + names.Add(currentFolderUnicode + GetItemRelPath2(operatedIndices[i])); + CRecordVector namePointers; + for (i = 0; i < operatedIndices.Size(); i++) + namePointers.Add(names[i]); + + // NFile::NDirectory::MySetCurrentDirectory(currentFolderUnicode); + if (contextMenuSpec->InitContextMenu(currentFolderUnicode, &namePointers.Front(), + operatedIndices.Size()) == S_OK) + { + HRESULT res = contextMenu->QueryContextMenu(menu, 0, kSevenZipStartMenuID, + kSystemStartMenuID - 1, 0); + sevenZipMenuCreated = (HRESULT_SEVERITY(res) == SEVERITY_SUCCESS); + if (sevenZipMenuCreated) + sevenZipContextMenu = contextMenu; + // 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 &sevenZipContextMenu, + CMyComPtr &systemContextMenu, + bool programMenu) +{ + sevenZipContextMenu.Release(); + systemContextMenu.Release(); + + CRecordVector operatedIndices; + GetOperatedItemIndices(operatedIndices); + + CMenu menu; + menu.Attach(menuSpec); + + if (!IsArcFolder()) + { + CreateSevenZipMenu(menu, operatedIndices, 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, operatedIndices, systemContextMenu); + } + + /* + if (menu.GetItemCount() > 0) + menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)0); + */ + + unsigned i; + for (i = 0; i < operatedIndices.Size(); i++) + if (IsItem_Folder(operatedIndices[i])) + break; + bool allAreFiles = (i == operatedIndices.Size()); + + CFileMenu fm; + + fm.readOnly = IsThereReadOnlyFolder(); + fm.isFsFolder = Is_IO_FS_Folder(); + fm.programMenu = programMenu; + fm.allAreFiles = allAreFiles; + fm.numItems = operatedIndices.Size(); + + fm.isAltStreamsSupported = false; + + if (_folderAltStreams) + { + if (operatedIndices.Size() <= 1) + { + Int32 realIndex = -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, menu.GetItemCount()); +} + +bool CPanel::InvokePluginCommand(int id) +{ + return InvokePluginCommand(id, _sevenZipContextMenu, _systemContextMenu); +} + +#if defined(_MSC_VER) && !defined(UNDER_CE) +#define use_CMINVOKECOMMANDINFOEX +#endif + +bool CPanel::InvokePluginCommand(int id, + IContextMenu *sevenZipContextMenu, IContextMenu *systemContextMenu) +{ + UInt32 offset; + bool isSystemMenu = (id >= kSystemStartMenuID); + if (isSystemMenu) + offset = id - kSystemStartMenuID; + else + 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; + const CSysString currentFolderSys (GetSystemString(_currentFolderPrefix)); + commandInfo.lpDirectory = (LPCSTR)(LPCTSTR)(currentFolderSys); + commandInfo.nShow = SW_SHOW; + + #ifdef use_CMINVOKECOMMANDINFOEX + + commandInfo.lpParametersW = NULL; + commandInfo.lpTitle = ""; + commandInfo.lpVerbW = (LPCWSTR)(MAKEINTRESOURCEW(offset)); + 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; + } + 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 operatedIndices; + GetOperatedItemIndices(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 sevenZipContextMenu; + CMyComPtr systemContextMenu; + CreateFileMenu(menu, sevenZipContextMenu, systemContextMenu, false); + + int result = menu.Track(TPM_LEFTALIGN + #ifndef UNDER_CE + | TPM_RIGHTBUTTON + #endif + | TPM_RETURNCMD | TPM_NONOTIFY, + xPos, yPos, _listView); + + if (result == 0) + return true; + + if (result >= kMenuCmdID_Plugin_Start) + { + InvokePluginCommand(result, sevenZipContextMenu, systemContextMenu); + return true; + } + if (ExecuteFileCommand(result)) + return true; + return true; +} diff --git a/CPP/7zip/UI/FileManager/PanelOperations.cpp b/CPP/7zip/UI/FileManager/PanelOperations.cpp index e61c57ddd..00bda1a98 100644 --- a/CPP/7zip/UI/FileManager/PanelOperations.cpp +++ b/CPP/7zip/UI/FileManager/PanelOperations.cpp @@ -1,526 +1,526 @@ -// 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(); -public: - EFolderOpType OpType; - UString Name; - UInt32 Index; - CRecordVector Indices; - - CMyComPtr FolderOperations; - CMyComPtr UpdateCallback; - CUpdateCallback100Imp *UpdateCallbackSpec; - - HRESULT Result; - - CThreadFolderOperations(EFolderOpType opType): OpType(opType), Result(E_FAIL) {} - HRESULT DoOperation(CPanel &panel, const UString &progressTitle, const UString &titleError); -}; - -HRESULT CThreadFolderOperations::ProcessVirt() -{ - NCOM::CComInitializer comInitializer; - switch (OpType) - { - case FOLDER_TYPE_CREATE_FOLDER: - Result = FolderOperations->CreateFolder(Name, UpdateCallback); - break; - case FOLDER_TYPE_DELETE: - Result = FolderOperations->Delete(&Indices.Front(), Indices.Size(), UpdateCallback); - break; - case FOLDER_TYPE_RENAME: - Result = FolderOperations->Rename(Index, Name, UpdateCallback); - break; - default: - Result = E_FAIL; - } - return Result; -} - - -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; - Result = S_OK; - - 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 * SHFileOperationWP)(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 indices; - GetOperatedItemIndices(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 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 = 0; - 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 = 0; - fo.lpszProgressTitle = 0; - /* int res = */ ::SHFileOperationA(&fo); - } - else - #endif - { - CDynamicBuffer 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 = 0; - fo.fFlags = 0; - if (toRecycleBin) - fo.fFlags |= FOF_ALLOWUNDO; - fo.fAnyOperationsAborted = FALSE; - fo.hNameMappings = 0; - fo.lpszProgressTitle = 0; - // int res; - #ifdef _UNICODE - /* res = */ ::SHFileOperationW(&fo); - #else - SHFileOperationWP shFileOperationW = (SHFileOperationWP) - ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHFileOperationW"); - if (shFileOperationW == 0) - return; - /* res = */ 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) - { - int 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) -{ - int realIndex = GetRealIndex(lpnmh->item); - if (realIndex == kParentIndex) - return TRUE; - if (IsThereReadOnlyFolder()) - return TRUE; - return FALSE; -} - -bool IsCorrectFsName(const UString &name) -{ - const UString lastPart = name.Ptr(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); - - int 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 (!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(pos); - if (!_mySelectMode) - state.SelectedNames.Clear(); - state.FocusedName = newName; - state.FocusedName_Defined = true; - state.SelectFocused = true; - } - RefreshTitleAlways(); - RefreshListCtrl(state); -} - -void CPanel::CreateFile() -{ - 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; - } - - HRESULT result = _folderOperations->CreateFile(newName, 0); - if (result != S_OK) - { - MessageBox_Error_HRESULT_Caption(result, LangString(IDS_CREATE_FILE_ERROR)); - // MessageBoxErrorForUpdate(result, IDS_CREATE_FILE_ERROR); - return; - } - int pos = newName.Find(WCHAR_PATH_SEPARATOR); - if (pos >= 0) - newName.DeleteFrom(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 (!CheckBeforeUpdate(IDS_COMMENT)) - return; - CDisableTimerProcessing disableTimerProcessing2(*this); - int index = _listView.GetFocusedItem(); - if (index < 0) - return; - int 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; - } - 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.Ptr(); - - CDisableNotify disableNotify(*this); - 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); -} +// 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(); +public: + EFolderOpType OpType; + UString Name; + UInt32 Index; + CRecordVector Indices; + + CMyComPtr FolderOperations; + CMyComPtr UpdateCallback; + CUpdateCallback100Imp *UpdateCallbackSpec; + + HRESULT Result; + + CThreadFolderOperations(EFolderOpType opType): OpType(opType), Result(E_FAIL) {} + HRESULT DoOperation(CPanel &panel, const UString &progressTitle, const UString &titleError); +}; + +HRESULT CThreadFolderOperations::ProcessVirt() +{ + NCOM::CComInitializer comInitializer; + switch (OpType) + { + case FOLDER_TYPE_CREATE_FOLDER: + Result = FolderOperations->CreateFolder(Name, UpdateCallback); + break; + case FOLDER_TYPE_DELETE: + Result = FolderOperations->Delete(&Indices.Front(), Indices.Size(), UpdateCallback); + break; + case FOLDER_TYPE_RENAME: + Result = FolderOperations->Rename(Index, Name, UpdateCallback); + break; + default: + Result = E_FAIL; + } + return Result; +} + + +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; + Result = S_OK; + + 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 * SHFileOperationWP)(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 indices; + GetOperatedItemIndices(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 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 = 0; + 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 = 0; + fo.lpszProgressTitle = 0; + /* int res = */ ::SHFileOperationA(&fo); + } + else + #endif + { + CDynamicBuffer 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 = 0; + fo.fFlags = 0; + if (toRecycleBin) + fo.fFlags |= FOF_ALLOWUNDO; + fo.fAnyOperationsAborted = FALSE; + fo.hNameMappings = 0; + fo.lpszProgressTitle = 0; + // int res; + #ifdef _UNICODE + /* res = */ ::SHFileOperationW(&fo); + #else + SHFileOperationWP shFileOperationW = (SHFileOperationWP) + ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHFileOperationW"); + if (shFileOperationW == 0) + return; + /* res = */ 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) + { + int 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) +{ + int realIndex = GetRealIndex(lpnmh->item); + if (realIndex == kParentIndex) + return TRUE; + if (IsThereReadOnlyFolder()) + return TRUE; + return FALSE; +} + +bool IsCorrectFsName(const UString &name) +{ + const UString lastPart = name.Ptr(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); + + int 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 (!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(pos); + if (!_mySelectMode) + state.SelectedNames.Clear(); + state.FocusedName = newName; + state.FocusedName_Defined = true; + state.SelectFocused = true; + } + RefreshTitleAlways(); + RefreshListCtrl(state); +} + +void CPanel::CreateFile() +{ + 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; + } + + HRESULT result = _folderOperations->CreateFile(newName, 0); + if (result != S_OK) + { + MessageBox_Error_HRESULT_Caption(result, LangString(IDS_CREATE_FILE_ERROR)); + // MessageBoxErrorForUpdate(result, IDS_CREATE_FILE_ERROR); + return; + } + int pos = newName.Find(WCHAR_PATH_SEPARATOR); + if (pos >= 0) + newName.DeleteFrom(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 (!CheckBeforeUpdate(IDS_COMMENT)) + return; + CDisableTimerProcessing disableTimerProcessing2(*this); + int index = _listView.GetFocusedItem(); + if (index < 0) + return; + int 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; + } + 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.Ptr(); + + CDisableNotify disableNotify(*this); + 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 index 022eeb676..8cfb23f44 100644 --- a/CPP/7zip/UI/FileManager/PanelSelect.cpp +++ b/CPP/7zip/UI/FileManager/PanelSelect.cpp @@ -1,311 +1,311 @@ -// 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; - 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++) - { - int 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; - int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - int 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); - */ - - int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - - int 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() -{ - int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - int index = GetRealItemIndex(focusedItem); - if (index == kParentIndex) - return; - _selectedStatusVector[index] = !_selectedStatusVector[index]; - _listView.RedrawItem(index); -} - -void CPanel::OnDownWithShift() -{ - int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - 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++) - { - int 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) -{ - int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - int 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(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) - { - int 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); - 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. - int 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(); - int focusedIndex = _startGroupSelect; - if (focusedIndex < 0) - return; - int startItem = MyMin(focusedIndex, indexInList); - int finishItem = MyMax(focusedIndex, indexInList); - - int numItems = _listView.GetItemCount(); - for (int i = 0; i < numItems; i++) - { - int realIndex = GetRealItemIndex(i); - if (realIndex == kParentIndex) - continue; - 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) - { - int realIndex = GetRealItemIndex(indexInList); - if (realIndex != kParentIndex) - { - _selectedStatusVector[realIndex] = !_selectedStatusVector[realIndex]; - _listView.RedrawItem(indexInList); - } - } - #endif - } - - return; -} +// 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; + 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++) + { + int 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; + int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + int 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); + */ + + int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + + int 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() +{ + int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + int index = GetRealItemIndex(focusedItem); + if (index == kParentIndex) + return; + _selectedStatusVector[index] = !_selectedStatusVector[index]; + _listView.RedrawItem(index); +} + +void CPanel::OnDownWithShift() +{ + int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + 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++) + { + int 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) +{ + int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + int 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(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) + { + int 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); + 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. + int 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(); + int focusedIndex = _startGroupSelect; + if (focusedIndex < 0) + return; + int startItem = MyMin(focusedIndex, indexInList); + int finishItem = MyMax(focusedIndex, indexInList); + + int numItems = _listView.GetItemCount(); + for (int i = 0; i < numItems; i++) + { + int realIndex = GetRealItemIndex(i); + if (realIndex == kParentIndex) + continue; + 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) + { + int 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 index 7edc04510..4adfc39fd 100644 --- a/CPP/7zip/UI/FileManager/PanelSort.cpp +++ b/CPP/7zip/UI/FileManager/PanelSort.cpp @@ -1,269 +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 &= ~1; - size2 &= ~1; - 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) -{ - int dotPos = name.ReverseFind_Dot(); - return name.Ptr((dotPos < 0) ? name.Len() : 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; - } - } -} - - -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((int)lParam1); - const UString name2 = panel->GetItemName((int)lParam2); - 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((int)lParam1); - const UString name2 = panel->GetItemName((int)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) -{ - if (lpData == 0) return 0; - if (lParam1 == kParentIndex) return -1; - if (lParam2 == kParentIndex) return 1; - - CPanel *panel = (CPanel*)lpData; - - bool isDir1 = panel->IsItem_Folder((int)lParam1); - bool isDir2 = panel->IsItem_Folder((int)lParam2); - - if (isDir1 && !isDir2) return -1; - if (isDir2 && !isDir1) return 1; - - 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); -} +// 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 &= ~1; + size2 &= ~1; + 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) +{ + int dotPos = name.ReverseFind_Dot(); + return name.Ptr((dotPos < 0) ? name.Len() : 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; + } + } +} + + +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((int)lParam1); + const UString name2 = panel->GetItemName((int)lParam2); + 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((int)lParam1); + const UString name2 = panel->GetItemName((int)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) +{ + if (lpData == 0) return 0; + if (lParam1 == kParentIndex) return -1; + if (lParam2 == kParentIndex) return 1; + + CPanel *panel = (CPanel*)lpData; + + bool isDir1 = panel->IsItem_Folder((int)lParam1); + bool isDir2 = panel->IsItem_Folder((int)lParam2); + + if (isDir1 && !isDir2) return -1; + if (isDir2 && !isDir1) return 1; + + 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 index f5f9aa2d3..7c633323e 100644 --- a/CPP/7zip/UI/FileManager/PanelSplitFile.cpp +++ b/CPP/7zip/UI/FileManager/PanelSplitFile.cpp @@ -1,562 +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--) - { - wchar_t c = ChangedPart[i]; - if (c != L'9') - { - ChangedPart.ReplaceOneCharAtPos(i, (wchar_t)(c + 1)); - break; - } - ChangedPart.ReplaceOneCharAtPos(i, L'0'); - if (i == 0) - ChangedPart.InsertAtFront(L'1'); - } - return UnchangedPart + ChangedPart; -} - -class CThreadSplit: public CProgressThreadVirt -{ - HRESULT ProcessVirt(); -public: - FString FilePath; - FString VolBasePath; - UInt64 NumVolumes; - CRecordVector 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(); - - CPreAllocOutFile outFile; - - CMyBuffer buffer; - if (!buffer.Allocate(kBufSize)) - return E_OUTOFMEMORY; - - CVolSeqName seqName; - seqName.SetNumDigits(NumVolumes); - - UInt64 length; - if (!inFile.GetLength(length)) - return GetLastError(); - - 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(); - if (processedSize == 0) - return S_OK; - needSize = processedSize; - - if (outFile.Written == 0) - { - FString name = VolBasePath; - name += '.'; - name += us2fs(seqName.GetNextName()); - sync.Set_FilePath(fs2us(name)); - if (!outFile.File.Create(name, false)) - { - HRESULT res = GetLastError(); - 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(); - 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() -{ - int srcPanelIndex = GetFocusedPanelIndex(); - CPanel &srcPanel = Panels[srcPanelIndex]; - if (!srcPanel.Is_IO_FS_Folder()) - { - srcPanel.MessageBox_Error_UnsupportOperation(); - return; - } - CRecordVector indices; - srcPanel.GetOperatedItemIndices(indices); - if (indices.IsEmpty()) - return; - if (indices.Size() != 1) - { - srcPanel.MessageBox_Error_LangID(IDS_SELECT_ONE_FILE); - return; - } - int index = indices[0]; - if (srcPanel.IsItem_Folder(index)) - { - srcPanel.MessageBox_Error_LangID(IDS_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(); - 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"Can not 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))) - { - DWORD lastError = ::GetLastError(); - srcPanel.MessageBox_Error_2Lines_Message_HRESULT(MyFormatNew(IDS_CANNOT_CREATE_FOLDER, path), lastError); - return; - } - - { - CThreadSplit spliter; - spliter.NumVolumes = numVolumes; - - CProgressDialog &progressDialog = spliter; - - UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE, 0x03000000); - 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(); -public: - FString InputDirPrefix; - FStringVector Names; - FString OutputPath; - UInt64 TotalSize; -}; - -HRESULT CThreadCombine::ProcessVirt() -{ - NIO::COutFile outFile; - if (!outFile.Create(OutputPath, false)) - { - HRESULT res = GetLastError(); - 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)) - { - HRESULT res = GetLastError(); - AddErrorPath(nextName); - return res; - } - sync.Set_FilePath(fs2us(nextName)); - for (;;) - { - UInt32 processedSize; - if (!inFile.Read(buffer, kBufSize, processedSize)) - { - HRESULT res = GetLastError(); - AddErrorPath(nextName); - return res; - } - if (processedSize == 0) - break; - UInt32 needSize = processedSize; - if (!outFile.Write(buffer, needSize, processedSize)) - { - HRESULT res = GetLastError(); - 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() -{ - int srcPanelIndex = GetFocusedPanelIndex(); - CPanel &srcPanel = Panels[srcPanelIndex]; - if (!srcPanel.IsFSFolder()) - { - srcPanel.MessageBox_Error_LangID(IDS_OPERATION_IS_NOT_SUPPORTED); - return; - } - CRecordVector indices; - srcPanel.GetOperatedItemIndices(indices); - if (indices.IsEmpty()) - return; - int 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))) - { - DWORD lastError = ::GetLastError(); - 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; - - UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE, 0x03000000); - 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(); -} +// 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--) + { + wchar_t c = ChangedPart[i]; + if (c != L'9') + { + ChangedPart.ReplaceOneCharAtPos(i, (wchar_t)(c + 1)); + break; + } + ChangedPart.ReplaceOneCharAtPos(i, L'0'); + if (i == 0) + ChangedPart.InsertAtFront(L'1'); + } + return UnchangedPart + ChangedPart; +} + +class CThreadSplit: public CProgressThreadVirt +{ + HRESULT ProcessVirt(); +public: + FString FilePath; + FString VolBasePath; + UInt64 NumVolumes; + CRecordVector 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(); + + CPreAllocOutFile outFile; + + CMyBuffer buffer; + if (!buffer.Allocate(kBufSize)) + return E_OUTOFMEMORY; + + CVolSeqName seqName; + seqName.SetNumDigits(NumVolumes); + + UInt64 length; + if (!inFile.GetLength(length)) + return GetLastError(); + + 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(); + if (processedSize == 0) + return S_OK; + needSize = processedSize; + + if (outFile.Written == 0) + { + FString name = VolBasePath; + name += '.'; + name += us2fs(seqName.GetNextName()); + sync.Set_FilePath(fs2us(name)); + if (!outFile.File.Create(name, false)) + { + HRESULT res = GetLastError(); + 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(); + 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() +{ + int srcPanelIndex = GetFocusedPanelIndex(); + CPanel &srcPanel = Panels[srcPanelIndex]; + if (!srcPanel.Is_IO_FS_Folder()) + { + srcPanel.MessageBox_Error_UnsupportOperation(); + return; + } + CRecordVector indices; + srcPanel.GetOperatedItemIndices(indices); + if (indices.IsEmpty()) + return; + if (indices.Size() != 1) + { + srcPanel.MessageBox_Error_LangID(IDS_SELECT_ONE_FILE); + return; + } + int index = indices[0]; + if (srcPanel.IsItem_Folder(index)) + { + srcPanel.MessageBox_Error_LangID(IDS_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(); + 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"Can not 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))) + { + DWORD lastError = ::GetLastError(); + srcPanel.MessageBox_Error_2Lines_Message_HRESULT(MyFormatNew(IDS_CANNOT_CREATE_FOLDER, path), lastError); + return; + } + + { + CThreadSplit spliter; + spliter.NumVolumes = numVolumes; + + CProgressDialog &progressDialog = spliter; + + UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE, 0x03000000); + 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(); +public: + FString InputDirPrefix; + FStringVector Names; + FString OutputPath; + UInt64 TotalSize; +}; + +HRESULT CThreadCombine::ProcessVirt() +{ + NIO::COutFile outFile; + if (!outFile.Create(OutputPath, false)) + { + HRESULT res = GetLastError(); + 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)) + { + HRESULT res = GetLastError(); + AddErrorPath(nextName); + return res; + } + sync.Set_FilePath(fs2us(nextName)); + for (;;) + { + UInt32 processedSize; + if (!inFile.Read(buffer, kBufSize, processedSize)) + { + HRESULT res = GetLastError(); + AddErrorPath(nextName); + return res; + } + if (processedSize == 0) + break; + UInt32 needSize = processedSize; + if (!outFile.Write(buffer, needSize, processedSize)) + { + HRESULT res = GetLastError(); + 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() +{ + int srcPanelIndex = GetFocusedPanelIndex(); + CPanel &srcPanel = Panels[srcPanelIndex]; + if (!srcPanel.IsFSFolder()) + { + srcPanel.MessageBox_Error_LangID(IDS_OPERATION_IS_NOT_SUPPORTED); + return; + } + CRecordVector indices; + srcPanel.GetOperatedItemIndices(indices); + if (indices.IsEmpty()) + return; + int 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))) + { + DWORD lastError = ::GetLastError(); + 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; + + UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE, 0x03000000); + 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 95e83fe45..6ead39c37 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 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(); +} diff --git a/CPP/7zip/UI/FileManager/PasswordDialog.h b/CPP/7zip/UI/FileManager/PasswordDialog.h index b756a1c4d..339ebdaf0 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 __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 diff --git a/CPP/7zip/UI/FileManager/PasswordDialog.rc b/CPP/7zip/UI/FileManager/PasswordDialog.rc index 51dd5bc47..90c57efa6 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 f9300d6bc..1fe32e10a 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 index b83432f41..37654a036 100644 --- a/CPP/7zip/UI/FileManager/PluginInterface.h +++ b/CPP/7zip/UI/FileManager/PluginInterface.h @@ -1,31 +1,31 @@ -// PluginInterface.h - -#ifndef __PLUGIN_INTERFACE_H -#define __PLUGIN_INTERFACE_H - -/* -#include "../../../Common/Types.h" -#include "../../IDecl.h" - -#define PLUGIN_INTERFACE(i, x) DECL_INTERFACE(i, 0x0A, x) - -PLUGIN_INTERFACE(IInitContextMenu, 0x00) -{ - STDMETHOD(InitContextMenu)(const wchar_t *folder, const wchar_t * const *names, UInt32 numFiles) PURE; -}; - -PLUGIN_INTERFACE(IPluginOptionsCallback, 0x01) -{ - STDMETHOD(GetProgramFolderPath)(BSTR *value) PURE; - STDMETHOD(GetProgramPath)(BSTR *value) PURE; - STDMETHOD(GetRegistryCUPath)(BSTR *value) PURE; -}; - -PLUGIN_INTERFACE(IPluginOptions, 0x02) -{ - STDMETHOD(PluginOptions)(HWND hWnd, IPluginOptionsCallback *callback) PURE; - // STDMETHOD(GetFileExtensions)(BSTR *extensions) PURE; -}; -*/ - -#endif +// PluginInterface.h + +#ifndef __PLUGIN_INTERFACE_H +#define __PLUGIN_INTERFACE_H + +/* +#include "../../../Common/Types.h" +#include "../../IDecl.h" + +#define PLUGIN_INTERFACE(i, x) DECL_INTERFACE(i, 0x0A, x) + +PLUGIN_INTERFACE(IInitContextMenu, 0x00) +{ + STDMETHOD(InitContextMenu)(const wchar_t *folder, const wchar_t * const *names, UInt32 numFiles) PURE; +}; + +PLUGIN_INTERFACE(IPluginOptionsCallback, 0x01) +{ + STDMETHOD(GetProgramFolderPath)(BSTR *value) PURE; + STDMETHOD(GetProgramPath)(BSTR *value) PURE; + STDMETHOD(GetRegistryCUPath)(BSTR *value) PURE; +}; + +PLUGIN_INTERFACE(IPluginOptions, 0x02) +{ + STDMETHOD(PluginOptions)(HWND hWnd, IPluginOptionsCallback *callback) PURE; + // STDMETHOD(GetFileExtensions)(BSTR *extensions) PURE; +}; +*/ + +#endif diff --git a/CPP/7zip/UI/FileManager/PluginLoader.h b/CPP/7zip/UI/FileManager/PluginLoader.h index bca380778..fed38d651 100644 --- a/CPP/7zip/UI/FileManager/PluginLoader.h +++ b/CPP/7zip/UI/FileManager/PluginLoader.h @@ -1,28 +1,28 @@ -// PluginLoader.h - -#ifndef __PLUGIN_LOADER_H -#define __PLUGIN_LOADER_H - -#include "../../../Windows/DLL.h" - -#include "IFolder.h" - -class CPluginLibrary: public NWindows::NDLL::CLibrary -{ -public: - HRESULT CreateManager(REFGUID clsID, IFolderManager **manager) - { - Func_CreateObject createObject = (Func_CreateObject)GetProc("CreateObject"); - if (!createObject) - return GetLastError(); - return createObject(&clsID, &IID_IFolderManager, (void **)manager); - } - HRESULT LoadAndCreateManager(CFSTR filePath, REFGUID clsID, IFolderManager **manager) - { - if (!Load(filePath)) - return GetLastError(); - return CreateManager(clsID, manager); - } -}; - -#endif +// PluginLoader.h + +#ifndef __PLUGIN_LOADER_H +#define __PLUGIN_LOADER_H + +#include "../../../Windows/DLL.h" + +#include "IFolder.h" + +class CPluginLibrary: public NWindows::NDLL::CLibrary +{ +public: + HRESULT CreateManager(REFGUID clsID, IFolderManager **manager) + { + Func_CreateObject createObject = (Func_CreateObject)GetProc("CreateObject"); + if (!createObject) + return GetLastError(); + return createObject(&clsID, &IID_IFolderManager, (void **)manager); + } + HRESULT LoadAndCreateManager(CFSTR filePath, REFGUID clsID, IFolderManager **manager) + { + if (!Load(filePath)) + return GetLastError(); + return CreateManager(clsID, manager); + } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/ProgramLocation.cpp b/CPP/7zip/UI/FileManager/ProgramLocation.cpp index ea6cd8da0..50ca5ca5e 100644 --- a/CPP/7zip/UI/FileManager/ProgramLocation.cpp +++ b/CPP/7zip/UI/FileManager/ProgramLocation.cpp @@ -1,3 +1,3 @@ -// ProgramLocation.cpp - -#include "StdAfx.h" +// ProgramLocation.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/UI/FileManager/ProgramLocation.h b/CPP/7zip/UI/FileManager/ProgramLocation.h index 65c8c54bc..6bfb711e4 100644 --- a/CPP/7zip/UI/FileManager/ProgramLocation.h +++ b/CPP/7zip/UI/FileManager/ProgramLocation.h @@ -1,6 +1,6 @@ -// ProgramLocation.h - -#ifndef __PROGRAM_LOCATION_H -#define __PROGRAM_LOCATION_H - -#endif +// ProgramLocation.h + +#ifndef __PROGRAM_LOCATION_H +#define __PROGRAM_LOCATION_H + +#endif diff --git a/CPP/7zip/UI/FileManager/ProgressDialog.cpp b/CPP/7zip/UI/FileManager/ProgressDialog.cpp index 27d42b2c3..1bf115ad2 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog.cpp +++ b/CPP/7zip/UI/FileManager/ProgressDialog.cpp @@ -1,196 +1,196 @@ -// 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 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; +} diff --git a/CPP/7zip/UI/FileManager/ProgressDialog.h b/CPP/7zip/UI/FileManager/ProgressDialog.h index 2a9d26d11..0f41b57ae 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog.h +++ b/CPP/7zip/UI/FileManager/ProgressDialog.h @@ -1,170 +1,170 @@ -// 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 __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 diff --git a/CPP/7zip/UI/FileManager/ProgressDialog.rc b/CPP/7zip/UI/FileManager/ProgressDialog.rc index 5af370f74..55d99233b 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 bdb2be3f1..28e3eae73 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog2.cpp +++ b/CPP/7zip/UI/FileManager/ProgressDialog2.cpp @@ -1,1337 +1,1337 @@ -// 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" + +#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); +} diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.h b/CPP/7zip/UI/FileManager/ProgressDialog2.h index 5e916e6f9..6c4213ac9 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog2.h +++ b/CPP/7zip/UI/FileManager/ProgressDialog2.h @@ -1,351 +1,351 @@ -// 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 _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 __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 _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 diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.rc b/CPP/7zip/UI/FileManager/ProgressDialog2.rc index 535a00817..4d0e0c7bf 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 54f02f030..b45d7b495 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog2Res.h +++ b/CPP/7zip/UI/FileManager/ProgressDialog2Res.h @@ -1,48 +1,48 @@ -#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_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 diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2a.rc b/CPP/7zip/UI/FileManager/ProgressDialog2a.rc index f1daec70a..e9713930b 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog2a.rc +++ b/CPP/7zip/UI/FileManager/ProgressDialog2a.rc @@ -1,80 +1,80 @@ -#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 "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 +} diff --git a/CPP/7zip/UI/FileManager/ProgressDialogRes.h b/CPP/7zip/UI/FileManager/ProgressDialogRes.h index a2814188a..cbf3beb21 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 a9552415f..838b6e3f6 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 a1061b74f..4f0d6dc11 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 __PROPERTY_NAME_H +#define __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 index eb427921f..5de5aeec4 100644 --- a/CPP/7zip/UI/FileManager/PropertyName.rc +++ b/CPP/7zip/UI/FileManager/PropertyName.rc @@ -1,100 +1,100 @@ -#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" -END +#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" +END diff --git a/CPP/7zip/UI/FileManager/PropertyNameRes.h b/CPP/7zip/UI/FileManager/PropertyNameRes.h index 1315b8995..67f339028 100644 --- a/CPP/7zip/UI/FileManager/PropertyNameRes.h +++ b/CPP/7zip/UI/FileManager/PropertyNameRes.h @@ -1,95 +1,95 @@ - - -#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 diff --git a/CPP/7zip/UI/FileManager/RegistryAssociations.cpp b/CPP/7zip/UI/FileManager/RegistryAssociations.cpp index af5b38b64..340a11db5 100644 --- a/CPP/7zip/UI/FileManager/RegistryAssociations.cpp +++ b/CPP/7zip/UI/FileManager/RegistryAssociations.cpp @@ -1,167 +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-Zstandard."; - -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) - { - int pos = value.ReverseFind(L','); - IconPath = value; - if (pos >= 0) - { - const wchar_t *end; - 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, 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; -} - -} +// 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-Zstandard."; + +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) + { + int pos = value.ReverseFind(L','); + IconPath = value; + if (pos >= 0) + { + const wchar_t *end; + 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, 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 index f38554216..975c9d5f0 100644 --- a/CPP/7zip/UI/FileManager/RegistryAssociations.h +++ b/CPP/7zip/UI/FileManager/RegistryAssociations.h @@ -1,31 +1,31 @@ -// RegistryAssociations.h - -#ifndef __REGISTRY_ASSOCIATIONS_H -#define __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 +// RegistryAssociations.h + +#ifndef __REGISTRY_ASSOCIATIONS_H +#define __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 index 5eab8f2a7..a0753ca6a 100644 --- a/CPP/7zip/UI/FileManager/RegistryPlugins.cpp +++ b/CPP/7zip/UI/FileManager/RegistryPlugins.cpp @@ -1,139 +1,139 @@ -// 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; - -/* -static LPCTSTR const kLMBasePath = TEXT("Software\\7-Zip\\FM"); - -static LPCTSTR const kPluginsKeyName = TEXT("Plugins"); -static LPCTSTR const kPluginsOpenClassIDValue = TEXT("CLSID"); -static LPCTSTR const kPluginsOptionsClassIDValue = TEXT("Options"); -static LPCTSTR const kPluginsTypeValue = TEXT("Type"); - -static CSysString GetFileFolderPluginsKeyName() -{ - return CSysString(kLMBasePath) + CSysString(TEXT('\\')) + - CSysString(kPluginsKeyName); -} - -*/ - -typedef UINT32 (WINAPI * GetPluginPropertyFunc)(PROPID propID, PROPVARIANT *value); - -static bool ReadPluginInfo(CPluginInfo &pluginInfo, bool needCheckDll) -{ - if (needCheckDll) - { - NDLL::CLibrary lib; - if (!lib.LoadEx(pluginInfo.FilePath, LOAD_LIBRARY_AS_DATAFILE)) - return false; - } - NDLL::CLibrary lib; - if (!lib.Load(pluginInfo.FilePath)) - return false; - GetPluginPropertyFunc getPluginProperty = (GetPluginPropertyFunc)lib.GetProc("GetPluginProperty"); - if (getPluginProperty == NULL) - return false; - - NCOM::CPropVariant prop; - if (getPluginProperty(NPlugin::kName, &prop) != S_OK) - return false; - if (prop.vt != VT_BSTR) - return false; - pluginInfo.Name = prop.bstrVal; - prop.Clear(); - - if (getPluginProperty(NPlugin::kClassID, &prop) != S_OK) - return false; - if (prop.vt == VT_EMPTY) - pluginInfo.ClassIDDefined = false; - else if (prop.vt != VT_BSTR) - return false; - else - { - pluginInfo.ClassIDDefined = true; - pluginInfo.ClassID = *(const GUID *)prop.bstrVal; - } - prop.Clear(); - - if (getPluginProperty(NPlugin::kOptionsClassID, &prop) != S_OK) - return false; - if (prop.vt == VT_EMPTY) - pluginInfo.OptionsClassIDDefined = false; - else if (prop.vt != VT_BSTR) - return false; - else - { - pluginInfo.OptionsClassIDDefined = true; - pluginInfo.OptionsClassID = *(const GUID *)prop.bstrVal; - } - prop.Clear(); - - if (getPluginProperty(NPlugin::kType, &prop) != S_OK) - return false; - if (prop.vt == VT_EMPTY) - pluginInfo.Type = kPluginTypeFF; - else if (prop.vt == VT_UI4) - pluginInfo.Type = (EPluginType)prop.ulVal; - else - return false; - return true; -} - -void ReadPluginInfoList(CObjectVector &plugins) -{ - plugins.Clear(); - - FString baseFolderPrefix = NDLL::GetModuleDirPrefix(); - { - CPluginInfo pluginInfo; - pluginInfo.FilePath = baseFolderPrefix + FTEXT("7-zip.dll"); - if (::ReadPluginInfo(pluginInfo, false)) - plugins.Add(pluginInfo); - } - FString folderPath = baseFolderPrefix; - folderPath += "Plugins" STRING_PATH_SEPARATOR; - NFind::CEnumerator enumerator; - enumerator.SetDirPrefix(folderPath); - NFind::CFileInfo fileInfo; - while (enumerator.Next(fileInfo)) - { - if (fileInfo.IsDir()) - continue; - CPluginInfo pluginInfo; - pluginInfo.FilePath = folderPath + fileInfo.Name; - if (::ReadPluginInfo(pluginInfo, true)) - plugins.Add(pluginInfo); - } -} - -void ReadFileFolderPluginInfoList(CObjectVector &plugins) -{ - ReadPluginInfoList(plugins); - for (unsigned i = 0; i < plugins.Size();) - if (plugins[i].Type != kPluginTypeFF) - plugins.Delete(i); - else - i++; - { - CPluginInfo p; - // p.FilePath.Empty(); - p.Type = kPluginTypeFF; - p.Name = "7-Zip"; - // p.ClassID = CLSID_CAgentArchiveHandler; - p.ClassIDDefined = true; - // p.OptionsClassID; - p.OptionsClassIDDefined = false; - plugins.Add(p); - } -} +// 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; + +/* +static LPCTSTR const kLMBasePath = TEXT("Software\\7-Zip\\FM"); + +static LPCTSTR const kPluginsKeyName = TEXT("Plugins"); +static LPCTSTR const kPluginsOpenClassIDValue = TEXT("CLSID"); +static LPCTSTR const kPluginsOptionsClassIDValue = TEXT("Options"); +static LPCTSTR const kPluginsTypeValue = TEXT("Type"); + +static CSysString GetFileFolderPluginsKeyName() +{ + return CSysString(kLMBasePath) + CSysString(TEXT('\\')) + + CSysString(kPluginsKeyName); +} + +*/ + +typedef UINT32 (WINAPI * GetPluginPropertyFunc)(PROPID propID, PROPVARIANT *value); + +static bool ReadPluginInfo(CPluginInfo &pluginInfo, bool needCheckDll) +{ + if (needCheckDll) + { + NDLL::CLibrary lib; + if (!lib.LoadEx(pluginInfo.FilePath, LOAD_LIBRARY_AS_DATAFILE)) + return false; + } + NDLL::CLibrary lib; + if (!lib.Load(pluginInfo.FilePath)) + return false; + GetPluginPropertyFunc getPluginProperty = (GetPluginPropertyFunc)lib.GetProc("GetPluginProperty"); + if (getPluginProperty == NULL) + return false; + + NCOM::CPropVariant prop; + if (getPluginProperty(NPlugin::kName, &prop) != S_OK) + return false; + if (prop.vt != VT_BSTR) + return false; + pluginInfo.Name = prop.bstrVal; + prop.Clear(); + + if (getPluginProperty(NPlugin::kClassID, &prop) != S_OK) + return false; + if (prop.vt == VT_EMPTY) + pluginInfo.ClassIDDefined = false; + else if (prop.vt != VT_BSTR) + return false; + else + { + pluginInfo.ClassIDDefined = true; + pluginInfo.ClassID = *(const GUID *)prop.bstrVal; + } + prop.Clear(); + + if (getPluginProperty(NPlugin::kOptionsClassID, &prop) != S_OK) + return false; + if (prop.vt == VT_EMPTY) + pluginInfo.OptionsClassIDDefined = false; + else if (prop.vt != VT_BSTR) + return false; + else + { + pluginInfo.OptionsClassIDDefined = true; + pluginInfo.OptionsClassID = *(const GUID *)prop.bstrVal; + } + prop.Clear(); + + if (getPluginProperty(NPlugin::kType, &prop) != S_OK) + return false; + if (prop.vt == VT_EMPTY) + pluginInfo.Type = kPluginTypeFF; + else if (prop.vt == VT_UI4) + pluginInfo.Type = (EPluginType)prop.ulVal; + else + return false; + return true; +} + +void ReadPluginInfoList(CObjectVector &plugins) +{ + plugins.Clear(); + + FString baseFolderPrefix = NDLL::GetModuleDirPrefix(); + { + CPluginInfo pluginInfo; + pluginInfo.FilePath = baseFolderPrefix + FTEXT("7-zip.dll"); + if (::ReadPluginInfo(pluginInfo, false)) + plugins.Add(pluginInfo); + } + FString folderPath = baseFolderPrefix; + folderPath += "Plugins" STRING_PATH_SEPARATOR; + NFind::CEnumerator enumerator; + enumerator.SetDirPrefix(folderPath); + NFind::CFileInfo fileInfo; + while (enumerator.Next(fileInfo)) + { + if (fileInfo.IsDir()) + continue; + CPluginInfo pluginInfo; + pluginInfo.FilePath = folderPath + fileInfo.Name; + if (::ReadPluginInfo(pluginInfo, true)) + plugins.Add(pluginInfo); + } +} + +void ReadFileFolderPluginInfoList(CObjectVector &plugins) +{ + ReadPluginInfoList(plugins); + for (unsigned i = 0; i < plugins.Size();) + if (plugins[i].Type != kPluginTypeFF) + plugins.Delete(i); + else + i++; + { + CPluginInfo p; + // p.FilePath.Empty(); + p.Type = kPluginTypeFF; + p.Name = "7-Zip"; + // p.ClassID = CLSID_CAgentArchiveHandler; + p.ClassIDDefined = true; + // p.OptionsClassID; + p.OptionsClassIDDefined = false; + plugins.Add(p); + } +} diff --git a/CPP/7zip/UI/FileManager/RegistryPlugins.h b/CPP/7zip/UI/FileManager/RegistryPlugins.h index b0daae73b..dfa6de54d 100644 --- a/CPP/7zip/UI/FileManager/RegistryPlugins.h +++ b/CPP/7zip/UI/FileManager/RegistryPlugins.h @@ -1,32 +1,32 @@ -// RegistryPlugins.h - -#ifndef __REGISTRY_PLUGINS_H -#define __REGISTRY_PLUGINS_H - -#include "../../../Common/MyString.h" - -enum EPluginType -{ - kPluginTypeFF = 0 -}; - -struct CPluginInfo -{ - FString FilePath; - EPluginType Type; - UString Name; - CLSID ClassID; - CLSID OptionsClassID; - bool ClassIDDefined; - bool OptionsClassIDDefined; - - // CSysString Extension; - // CSysString AddExtension; - // bool UpdateEnabled; - // bool KeepName; -}; - -void ReadPluginInfoList(CObjectVector &plugins); -void ReadFileFolderPluginInfoList(CObjectVector &plugins); - -#endif +// RegistryPlugins.h + +#ifndef __REGISTRY_PLUGINS_H +#define __REGISTRY_PLUGINS_H + +#include "../../../Common/MyString.h" + +enum EPluginType +{ + kPluginTypeFF = 0 +}; + +struct CPluginInfo +{ + FString FilePath; + EPluginType Type; + UString Name; + CLSID ClassID; + CLSID OptionsClassID; + bool ClassIDDefined; + bool OptionsClassIDDefined; + + // CSysString Extension; + // CSysString AddExtension; + // bool UpdateEnabled; + // bool KeepName; +}; + +void ReadPluginInfoList(CObjectVector &plugins); +void ReadFileFolderPluginInfoList(CObjectVector &plugins); + +#endif diff --git a/CPP/7zip/UI/FileManager/RegistryUtils.cpp b/CPP/7zip/UI/FileManager/RegistryUtils.cpp index 896dfae7f..a3f13b680 100644 --- a/CPP/7zip/UI/FileManager/RegistryUtils.cpp +++ b/CPP/7zip/UI/FileManager/RegistryUtils.cpp @@ -1,223 +1,223 @@ -// 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-Zstandard") - -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 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"); - -// they default to off (0) in 7-Zip ZS /TR -static LPCTSTR const kArcHistory = TEXT("WantArcHistory"); -static LPCTSTR const kPathHistory = TEXT("WantPathHistory"); -static LPCTSTR const kCopyHistory = TEXT("WantCopyHistory"); -static LPCTSTR const kFolderHistory = TEXT("WantFolderHistory"); - -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); } - -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 bool ReadFMOption(LPCTSTR value) -{ - CKey key; - bool enabled = false; - if (key.Open(HKEY_CURRENT_USER, kCU_FMPath, KEY_READ) == ERROR_SUCCESS) - { - if (key.QueryValue(value, enabled) == ERROR_SUCCESS) - return enabled; - } - return enabled; -} - -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(kArcHistory, ArcHistory); - SaveOption(kPathHistory, PathHistory); - SaveOption(kCopyHistory, CopyHistory); - SaveOption(kFolderHistory, FolderHistory); - // SaveOption(kUnderline, Underline); - - SaveOption(kShowSystemMenu, ShowSystemMenu); -} - -void CFmSettings::Load() -{ - ShowDots = false; - ShowRealFileIcons = false; - FullRow = false; - ShowGrid = false; - SingleClick = false; - AlternativeSelection = false; - ArcHistory = false; - PathHistory = false; - CopyHistory = false; - FolderHistory = 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, kArcHistory, ArcHistory); - ReadOption(key, kPathHistory, PathHistory); - ReadOption(key, kCopyHistory, CopyHistory); - ReadOption(key, kFolderHistory, FolderHistory); - // 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); } - -bool WantArcHistory() { return ReadFMOption(kArcHistory); } -bool WantPathHistory() { return ReadFMOption(kPathHistory); } -bool WantCopyHistory() { return ReadFMOption(kCopyHistory); } -bool WantFolderHistory() { return ReadFMOption(kFolderHistory); } - -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); } -*/ +// 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-Zstandard") + +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 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"); + +// they default to off (0) in 7-Zip ZS /TR +static LPCTSTR const kArcHistory = TEXT("WantArcHistory"); +static LPCTSTR const kPathHistory = TEXT("WantPathHistory"); +static LPCTSTR const kCopyHistory = TEXT("WantCopyHistory"); +static LPCTSTR const kFolderHistory = TEXT("WantFolderHistory"); + +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); } + +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 bool ReadFMOption(LPCTSTR value) +{ + CKey key; + bool enabled = false; + if (key.Open(HKEY_CURRENT_USER, kCU_FMPath, KEY_READ) == ERROR_SUCCESS) + { + if (key.QueryValue(value, enabled) == ERROR_SUCCESS) + return enabled; + } + return enabled; +} + +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(kArcHistory, ArcHistory); + SaveOption(kPathHistory, PathHistory); + SaveOption(kCopyHistory, CopyHistory); + SaveOption(kFolderHistory, FolderHistory); + // SaveOption(kUnderline, Underline); + + SaveOption(kShowSystemMenu, ShowSystemMenu); +} + +void CFmSettings::Load() +{ + ShowDots = false; + ShowRealFileIcons = false; + FullRow = false; + ShowGrid = false; + SingleClick = false; + AlternativeSelection = false; + ArcHistory = false; + PathHistory = false; + CopyHistory = false; + FolderHistory = 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, kArcHistory, ArcHistory); + ReadOption(key, kPathHistory, PathHistory); + ReadOption(key, kCopyHistory, CopyHistory); + ReadOption(key, kFolderHistory, FolderHistory); + // 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); } + +bool WantArcHistory() { return ReadFMOption(kArcHistory); } +bool WantPathHistory() { return ReadFMOption(kPathHistory); } +bool WantCopyHistory() { return ReadFMOption(kCopyHistory); } +bool WantFolderHistory() { return ReadFMOption(kFolderHistory); } + +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 index 4d131f14f..95764aeac 100644 --- a/CPP/7zip/UI/FileManager/RegistryUtils.h +++ b/CPP/7zip/UI/FileManager/RegistryUtils.h @@ -1,57 +1,57 @@ -// RegistryUtils.h - -#ifndef __REGISTRY_UTILS_H -#define __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); - -struct CFmSettings -{ - bool ShowDots; - bool ShowRealFileIcons; - bool FullRow; - bool ShowGrid; - bool SingleClick; - bool AlternativeSelection; - bool ArcHistory; - bool PathHistory; - bool CopyHistory; - bool FolderHistory; - // bool Underline; - - bool ShowSystemMenu; - - void Save() const; - void Load(); -}; - -// void SaveLockMemoryAdd(bool enable); -// bool ReadLockMemoryAdd(); - -bool ReadLockMemoryEnable(); -void SaveLockMemoryEnable(bool enable); - -bool WantArcHistory(); -bool WantPathHistory(); -bool WantCopyHistory(); -bool WantFolderHistory(); - -void SaveFlatView(UInt32 panelIndex, bool enable); -bool ReadFlatView(UInt32 panelIndex); - -/* -void Save_ShowDeleted(bool enable); -bool Read_ShowDeleted(); -*/ - -#endif +// RegistryUtils.h + +#ifndef __REGISTRY_UTILS_H +#define __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); + +struct CFmSettings +{ + bool ShowDots; + bool ShowRealFileIcons; + bool FullRow; + bool ShowGrid; + bool SingleClick; + bool AlternativeSelection; + bool ArcHistory; + bool PathHistory; + bool CopyHistory; + bool FolderHistory; + // bool Underline; + + bool ShowSystemMenu; + + void Save() const; + void Load(); +}; + +// void SaveLockMemoryAdd(bool enable); +// bool ReadLockMemoryAdd(); + +bool ReadLockMemoryEnable(); +void SaveLockMemoryEnable(bool enable); + +bool WantArcHistory(); +bool WantPathHistory(); +bool WantCopyHistory(); +bool WantFolderHistory(); + +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 index a642017b0..643f10660 100644 --- a/CPP/7zip/UI/FileManager/RootFolder.cpp +++ b/CPP/7zip/UI/FileManager/RootFolder.cpp @@ -1,315 +1,315 @@ -// RootFolder.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#include - -#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) -{ - #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) -{ - iconIndex = GetIconIndexForCSIDL(CSIDL_NETWORK); - return LangString(IDS_NETWORK); -} - -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 -} - -STDMETHODIMP CRootFolder::LoadItems() -{ - Init(); - return S_OK; -} - -STDMETHODIMP CRootFolder::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = kNumRootFolderItems; - return S_OK; -} - -STDMETHODIMP 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 *SHGetSpecialFolderPathWp)(HWND hwnd, LPWSTR pszPath, int csidl, BOOL fCreate); -typedef BOOL (WINAPI *SHGetSpecialFolderPathAp)(HWND hwnd, LPSTR pszPath, int csidl, BOOL fCreate); - -UString GetMyDocsPath() -{ - UString us; - WCHAR s[MAX_PATH + 1]; - SHGetSpecialFolderPathWp getW = (SHGetSpecialFolderPathWp) - #ifdef UNDER_CE - My_GetProcAddress(GetModuleHandle(TEXT("coredll.dll")), "SHGetSpecialFolderPath"); - #else - My_GetProcAddress(GetModuleHandle(TEXT("shell32.dll")), "SHGetSpecialFolderPathW"); - #endif - if (getW && getW(0, s, CSIDL_PERSONAL, FALSE)) - us = s; - #ifndef _UNICODE - else - { - SHGetSpecialFolderPathAp getA = (SHGetSpecialFolderPathAp) - ::GetProcAddress(::GetModuleHandleA("shell32.dll"), "SHGetSpecialFolderPathA"); - CHAR s2[MAX_PATH + 1]; - if (getA && getA(0, s2, CSIDL_PERSONAL, FALSE)) - us = GetUnicodeString(s2); - } - #endif - NFile::NName::NormalizeDirPathPrefix(us); - return us; -} - -STDMETHODIMP CRootFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder) -{ - *resultFolder = NULL; - CMyComPtr 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(0, 0, _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); -} - -STDMETHODIMP CRootFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder) -{ - *resultFolder = 0; - UString name2 = name; - name2.Trim(); - - if (name2.IsEmpty()) - { - CRootFolder *rootFolderSpec = new CRootFolder; - CMyComPtr 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 subFolder = this; - *resultFolder = subFolder.Detach(); - return S_OK; - } - - if (name2.Len() < 2) - return E_INVALIDARG; - - CMyComPtr 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() == ':') - { - 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; -} - -STDMETHODIMP CRootFolder::BindToParentFolder(IFolderFolder **resultFolder) -{ - *resultFolder = 0; - return S_OK; -} - -IMP_IFolderFolder_Props(CRootFolder) - -STDMETHODIMP 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; -} - -STDMETHODIMP CRootFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex) -{ - *iconIndex = _iconIndices[index]; - return S_OK; -} +// RootFolder.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#include + +#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) +{ + #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) +{ + iconIndex = GetIconIndexForCSIDL(CSIDL_NETWORK); + return LangString(IDS_NETWORK); +} + +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 +} + +STDMETHODIMP CRootFolder::LoadItems() +{ + Init(); + return S_OK; +} + +STDMETHODIMP CRootFolder::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = kNumRootFolderItems; + return S_OK; +} + +STDMETHODIMP 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 *SHGetSpecialFolderPathWp)(HWND hwnd, LPWSTR pszPath, int csidl, BOOL fCreate); +typedef BOOL (WINAPI *SHGetSpecialFolderPathAp)(HWND hwnd, LPSTR pszPath, int csidl, BOOL fCreate); + +UString GetMyDocsPath() +{ + UString us; + WCHAR s[MAX_PATH + 1]; + SHGetSpecialFolderPathWp getW = (SHGetSpecialFolderPathWp) + #ifdef UNDER_CE + My_GetProcAddress(GetModuleHandle(TEXT("coredll.dll")), "SHGetSpecialFolderPath"); + #else + My_GetProcAddress(GetModuleHandle(TEXT("shell32.dll")), "SHGetSpecialFolderPathW"); + #endif + if (getW && getW(0, s, CSIDL_PERSONAL, FALSE)) + us = s; + #ifndef _UNICODE + else + { + SHGetSpecialFolderPathAp getA = (SHGetSpecialFolderPathAp) + ::GetProcAddress(::GetModuleHandleA("shell32.dll"), "SHGetSpecialFolderPathA"); + CHAR s2[MAX_PATH + 1]; + if (getA && getA(0, s2, CSIDL_PERSONAL, FALSE)) + us = GetUnicodeString(s2); + } + #endif + NFile::NName::NormalizeDirPathPrefix(us); + return us; +} + +STDMETHODIMP CRootFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder) +{ + *resultFolder = NULL; + CMyComPtr 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(0, 0, _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); +} + +STDMETHODIMP CRootFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder) +{ + *resultFolder = 0; + UString name2 = name; + name2.Trim(); + + if (name2.IsEmpty()) + { + CRootFolder *rootFolderSpec = new CRootFolder; + CMyComPtr 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 subFolder = this; + *resultFolder = subFolder.Detach(); + return S_OK; + } + + if (name2.Len() < 2) + return E_INVALIDARG; + + CMyComPtr 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() == ':') + { + 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; +} + +STDMETHODIMP CRootFolder::BindToParentFolder(IFolderFolder **resultFolder) +{ + *resultFolder = 0; + return S_OK; +} + +IMP_IFolderFolder_Props(CRootFolder) + +STDMETHODIMP 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; +} + +STDMETHODIMP 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 index bc5fd7147..e25378370 100644 --- a/CPP/7zip/UI/FileManager/RootFolder.h +++ b/CPP/7zip/UI/FileManager/RootFolder.h @@ -1,27 +1,27 @@ -// RootFolder.h - -#ifndef __ROOT_FOLDER_H -#define __ROOT_FOLDER_H - -#include "../../../Common/MyString.h" - -#include "IFolder.h" - -const unsigned kNumRootFolderItems_Max = 4; - -class CRootFolder: - public IFolderFolder, - public IFolderGetSystemIconIndex, - public CMyUnknownImp -{ - UString _names[kNumRootFolderItems_Max]; - int _iconIndices[kNumRootFolderItems_Max]; - -public: - MY_UNKNOWN_IMP1(IFolderGetSystemIconIndex) - INTERFACE_FolderFolder(;) - STDMETHOD(GetSystemIconIndex)(UInt32 index, Int32 *iconIndex); - void Init(); -}; - -#endif +// RootFolder.h + +#ifndef __ROOT_FOLDER_H +#define __ROOT_FOLDER_H + +#include "../../../Common/MyString.h" + +#include "IFolder.h" + +const unsigned kNumRootFolderItems_Max = 4; + +class CRootFolder: + public IFolderFolder, + public IFolderGetSystemIconIndex, + public CMyUnknownImp +{ + UString _names[kNumRootFolderItems_Max]; + int _iconIndices[kNumRootFolderItems_Max]; + +public: + MY_UNKNOWN_IMP1(IFolderGetSystemIconIndex) + INTERFACE_FolderFolder(;) + STDMETHOD(GetSystemIconIndex)(UInt32 index, Int32 *iconIndex); + void Init(); +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/SettingsPage.cpp b/CPP/7zip/UI/FileManager/SettingsPage.cpp index efdad026e..8e663e161 100644 --- a/CPP/7zip/UI/FileManager/SettingsPage.cpp +++ b/CPP/7zip/UI/FileManager/SettingsPage.cpp @@ -1,158 +1,158 @@ -// SettingsPage.cpp - -#include "StdAfx.h" - -#include "../../../Common/StringConvert.h" - -#ifndef UNDER_CE -#include "../../../Windows/MemoryLock.h" -#endif - -#include "HelpUtils.h" -#include "LangUtils.h" -#include "RegistryUtils.h" -#include "SettingsPage.h" - -#include "SettingsPageRes.h" - -using namespace NWindows; - -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, - IDX_SETTINGS_WANT_ARC_HISTORY, - IDX_SETTINGS_WANT_PATH_HISTORY, - IDX_SETTINGS_WANT_COPY_HISTORY, - IDX_SETTINGS_WANT_FOLDER_HISTORY -}; - -#define kSettingsTopic "FM/options.htm#settings" - -extern bool IsLargePageSupported(); - -bool CSettingsPage::OnInit() -{ - _wasChanged = false; - _largePages_wasChanged = false; - - LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); - - 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); - - CheckButton(IDX_SETTINGS_WANT_ARC_HISTORY, st.ArcHistory); - CheckButton(IDX_SETTINGS_WANT_PATH_HISTORY, st.PathHistory); - CheckButton(IDX_SETTINGS_WANT_COPY_HISTORY, st.CopyHistory); - CheckButton(IDX_SETTINGS_WANT_FOLDER_HISTORY, st.FolderHistory); - // EnableSubItems(); - - return CPropertyPage::OnInit(); -} - -/* -void CSettingsPage::EnableSubItems() -{ - EnableItem(IDX_SETTINGS_UNDERLINE, IsButtonCheckedBool(IDX_SETTINGS_SINGLE_CLICK)); -} -*/ - -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.ArcHistory = IsButtonCheckedBool(IDX_SETTINGS_WANT_ARC_HISTORY); - st.PathHistory = IsButtonCheckedBool(IDX_SETTINGS_WANT_PATH_HISTORY); - st.CopyHistory = IsButtonCheckedBool(IDX_SETTINGS_WANT_COPY_HISTORY); - st.FolderHistory = IsButtonCheckedBool(IDX_SETTINGS_WANT_FOLDER_HISTORY); - // 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()) - { - bool enable = IsButtonCheckedBool(IDX_SETTINGS_LARGE_PAGES); - NSecurity::EnablePrivilege_LockMemory(enable); - SaveLockMemoryEnable(enable); - } - _largePages_wasChanged = false; - } - #endif - - return PSNRET_NOERROR; -} - -void CSettingsPage::OnNotifyHelp() -{ - ShowHelpWindow(kSettingsTopic); -} - -bool CSettingsPage::OnButtonClicked(int 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: - case IDX_SETTINGS_WANT_ARC_HISTORY: - case IDX_SETTINGS_WANT_PATH_HISTORY: - case IDX_SETTINGS_WANT_COPY_HISTORY: - case IDX_SETTINGS_WANT_FOLDER_HISTORY: - _wasChanged = true; - break; - - case IDX_SETTINGS_LARGE_PAGES: - _largePages_wasChanged = true; - break; - - default: - return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); - } - - Changed(); - return true; -} +// SettingsPage.cpp + +#include "StdAfx.h" + +#include "../../../Common/StringConvert.h" + +#ifndef UNDER_CE +#include "../../../Windows/MemoryLock.h" +#endif + +#include "HelpUtils.h" +#include "LangUtils.h" +#include "RegistryUtils.h" +#include "SettingsPage.h" + +#include "SettingsPageRes.h" + +using namespace NWindows; + +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, + IDX_SETTINGS_WANT_ARC_HISTORY, + IDX_SETTINGS_WANT_PATH_HISTORY, + IDX_SETTINGS_WANT_COPY_HISTORY, + IDX_SETTINGS_WANT_FOLDER_HISTORY +}; + +#define kSettingsTopic "FM/options.htm#settings" + +extern bool IsLargePageSupported(); + +bool CSettingsPage::OnInit() +{ + _wasChanged = false; + _largePages_wasChanged = false; + + LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); + + 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); + + CheckButton(IDX_SETTINGS_WANT_ARC_HISTORY, st.ArcHistory); + CheckButton(IDX_SETTINGS_WANT_PATH_HISTORY, st.PathHistory); + CheckButton(IDX_SETTINGS_WANT_COPY_HISTORY, st.CopyHistory); + CheckButton(IDX_SETTINGS_WANT_FOLDER_HISTORY, st.FolderHistory); + // EnableSubItems(); + + return CPropertyPage::OnInit(); +} + +/* +void CSettingsPage::EnableSubItems() +{ + EnableItem(IDX_SETTINGS_UNDERLINE, IsButtonCheckedBool(IDX_SETTINGS_SINGLE_CLICK)); +} +*/ + +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.ArcHistory = IsButtonCheckedBool(IDX_SETTINGS_WANT_ARC_HISTORY); + st.PathHistory = IsButtonCheckedBool(IDX_SETTINGS_WANT_PATH_HISTORY); + st.CopyHistory = IsButtonCheckedBool(IDX_SETTINGS_WANT_COPY_HISTORY); + st.FolderHistory = IsButtonCheckedBool(IDX_SETTINGS_WANT_FOLDER_HISTORY); + // 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()) + { + bool enable = IsButtonCheckedBool(IDX_SETTINGS_LARGE_PAGES); + NSecurity::EnablePrivilege_LockMemory(enable); + SaveLockMemoryEnable(enable); + } + _largePages_wasChanged = false; + } + #endif + + return PSNRET_NOERROR; +} + +void CSettingsPage::OnNotifyHelp() +{ + ShowHelpWindow(kSettingsTopic); +} + +bool CSettingsPage::OnButtonClicked(int 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: + case IDX_SETTINGS_WANT_ARC_HISTORY: + case IDX_SETTINGS_WANT_PATH_HISTORY: + case IDX_SETTINGS_WANT_COPY_HISTORY: + case IDX_SETTINGS_WANT_FOLDER_HISTORY: + _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 index c893f077f..08dda0f01 100644 --- a/CPP/7zip/UI/FileManager/SettingsPage.h +++ b/CPP/7zip/UI/FileManager/SettingsPage.h @@ -1,22 +1,22 @@ -// SettingsPage.h - -#ifndef __SETTINGS_PAGE_H -#define __SETTINGS_PAGE_H - -#include "../../../Windows/Control/PropertyPage.h" -#include "../../../Windows/Control/Edit.h" - -class CSettingsPage: public NWindows::NControl::CPropertyPage -{ - bool _wasChanged; - bool _largePages_wasChanged; - - // void EnableSubItems(); - bool OnButtonClicked(int buttonID, HWND buttonHWND); -public: - virtual bool OnInit(); - virtual void OnNotifyHelp(); - virtual LONG OnApply(); -}; - -#endif +// SettingsPage.h + +#ifndef __SETTINGS_PAGE_H +#define __SETTINGS_PAGE_H + +#include "../../../Windows/Control/PropertyPage.h" +#include "../../../Windows/Control/Edit.h" + +class CSettingsPage: public NWindows::NControl::CPropertyPage +{ + bool _wasChanged; + bool _largePages_wasChanged; + + // void EnableSubItems(); + bool OnButtonClicked(int buttonID, HWND buttonHWND); +public: + virtual bool OnInit(); + virtual void OnNotifyHelp(); + virtual LONG OnApply(); +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/SettingsPage.rc b/CPP/7zip/UI/FileManager/SettingsPage.rc index a74d5c073..c724fcb71 100644 --- a/CPP/7zip/UI/FileManager/SettingsPage.rc +++ b/CPP/7zip/UI/FileManager/SettingsPage.rc @@ -1,22 +1,22 @@ -#include "SettingsPageRes.h" -#include "../../GuiCommon.rc" - -#define xc 240 -#define yc 120 - -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 +#include "SettingsPageRes.h" +#include "../../GuiCommon.rc" + +#define xc 240 +#define yc 120 + +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 index fc4ce2278..2d634dde3 100644 --- a/CPP/7zip/UI/FileManager/SettingsPage2.rc +++ b/CPP/7zip/UI/FileManager/SettingsPage2.rc @@ -1,17 +1,17 @@ -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 +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, 80, xc, 10 - CONTROL "Show system &menu", IDX_SETTINGS_SHOW_SYSTEM_MENU, MY_CHECKBOX, m, 96, xc, 10 + CONTROL "&Alternative selection mode", IDX_SETTINGS_ALTERNATIVE_SELECTION, MY_CHECKBOX, m, 80, xc, 10 + CONTROL "Show system &menu", IDX_SETTINGS_SHOW_SYSTEM_MENU, MY_CHECKBOX, m, 96, xc, 10 CONTROL "Use &large memory pages", IDX_SETTINGS_LARGE_PAGES, MY_CHECKBOX, m, 112, xc, 10 - CONTROL "Want ArcHistory", IDX_SETTINGS_WANT_ARC_HISTORY, MY_CHECKBOX, m, 130, xc, 10 - CONTROL "Want PathHistory", IDX_SETTINGS_WANT_PATH_HISTORY, MY_CHECKBOX, m, 144, xc, 10 - CONTROL "Want CopyHistory", IDX_SETTINGS_WANT_COPY_HISTORY, MY_CHECKBOX, m, 158, xc, 10 - CONTROL "Want FolderHistory", IDX_SETTINGS_WANT_FOLDER_HISTORY, MY_CHECKBOX, m, 172, xc, 10 -END + CONTROL "Want ArcHistory", IDX_SETTINGS_WANT_ARC_HISTORY, MY_CHECKBOX, m, 130, xc, 10 + CONTROL "Want PathHistory", IDX_SETTINGS_WANT_PATH_HISTORY, MY_CHECKBOX, m, 144, xc, 10 + CONTROL "Want CopyHistory", IDX_SETTINGS_WANT_COPY_HISTORY, MY_CHECKBOX, m, 158, xc, 10 + CONTROL "Want FolderHistory", IDX_SETTINGS_WANT_FOLDER_HISTORY, MY_CHECKBOX, m, 172, xc, 10 +END diff --git a/CPP/7zip/UI/FileManager/SettingsPageRes.h b/CPP/7zip/UI/FileManager/SettingsPageRes.h index fdd5fc84c..a8899455b 100644 --- a/CPP/7zip/UI/FileManager/SettingsPageRes.h +++ b/CPP/7zip/UI/FileManager/SettingsPageRes.h @@ -1,15 +1,15 @@ -#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 IDX_SETTINGS_WANT_ARC_HISTORY 2509 -#define IDX_SETTINGS_WANT_PATH_HISTORY 2510 -#define IDX_SETTINGS_WANT_COPY_HISTORY 2511 -#define IDX_SETTINGS_WANT_FOLDER_HISTORY 2512 +#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 IDX_SETTINGS_WANT_ARC_HISTORY 2509 +#define IDX_SETTINGS_WANT_PATH_HISTORY 2510 +#define IDX_SETTINGS_WANT_COPY_HISTORY 2511 +#define IDX_SETTINGS_WANT_FOLDER_HISTORY 2512 diff --git a/CPP/7zip/UI/FileManager/SplitDialog.cpp b/CPP/7zip/UI/FileManager/SplitDialog.cpp index e20e997f2..0c9fdd17d 100644 --- a/CPP/7zip/UI/FileManager/SplitDialog.cpp +++ b/CPP/7zip/UI/FileManager/SplitDialog.cpp @@ -1,116 +1,116 @@ -// SplitDialog.cpp - -#include "StdAfx.h" - -#include "../../../Windows/FileName.h" - -#ifdef LANG -#include "LangUtils.h" -#endif - -#include "BrowseDialog.h" -#include "CopyDialogRes.h" -#include "SplitDialog.h" -#include "SplitUtils.h" -#include "resourceGui.h" - -using namespace NWindows; - -#ifdef LANG -static const UInt32 kLangIDs[] = -{ - IDT_SPLIT_PATH, - IDT_SPLIT_VOLUME -}; -#endif - - -bool CSplitDialog::OnInit() -{ - #ifdef LANG - LangSetWindowText(*this, IDD_SPLIT); - LangSetDlgItems(*this, kLangIDs, 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(int 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"; - 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(); -} +// SplitDialog.cpp + +#include "StdAfx.h" + +#include "../../../Windows/FileName.h" + +#ifdef LANG +#include "LangUtils.h" +#endif + +#include "BrowseDialog.h" +#include "CopyDialogRes.h" +#include "SplitDialog.h" +#include "SplitUtils.h" +#include "resourceGui.h" + +using namespace NWindows; + +#ifdef LANG +static const UInt32 kLangIDs[] = +{ + IDT_SPLIT_PATH, + IDT_SPLIT_VOLUME +}; +#endif + + +bool CSplitDialog::OnInit() +{ + #ifdef LANG + LangSetWindowText(*this, IDD_SPLIT); + LangSetDlgItems(*this, kLangIDs, 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(int 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"; + 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 index 52e236891..00aae6589 100644 --- a/CPP/7zip/UI/FileManager/SplitDialog.h +++ b/CPP/7zip/UI/FileManager/SplitDialog.h @@ -1,28 +1,28 @@ -// SplitDialog.h - -#ifndef __SPLIT_DIALOG_H -#define __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(); - virtual bool OnInit(); - virtual bool OnSize(WPARAM wParam, int xSize, int ySize); - virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); - void OnButtonSetPath(); -public: - UString FilePath; - UString Path; - CRecordVector VolumeSizes; - INT_PTR Create(HWND parentWindow = 0) - { return CModalDialog::Create(IDD_SPLIT, parentWindow); } -}; - -#endif +// SplitDialog.h + +#ifndef __SPLIT_DIALOG_H +#define __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(); + virtual bool OnInit(); + virtual bool OnSize(WPARAM wParam, int xSize, int ySize); + virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); + void OnButtonSetPath(); +public: + UString FilePath; + UString Path; + CRecordVector VolumeSizes; + INT_PTR Create(HWND parentWindow = 0) + { return CModalDialog::Create(IDD_SPLIT, parentWindow); } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/SplitDialog.rc b/CPP/7zip/UI/FileManager/SplitDialog.rc index cee8b650f..5a026e8ab 100644 --- a/CPP/7zip/UI/FileManager/SplitDialog.rc +++ b/CPP/7zip/UI/FileManager/SplitDialog.rc @@ -1,16 +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 +#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 index f9747da9f..50584a147 100644 --- a/CPP/7zip/UI/FileManager/SplitDialogRes.h +++ b/CPP/7zip/UI/FileManager/SplitDialogRes.h @@ -1,8 +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 +#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 index 0e6b131e4..4b6235b31 100644 --- a/CPP/7zip/UI/FileManager/SplitUtils.cpp +++ b/CPP/7zip/UI/FileManager/SplitUtils.cpp @@ -1,96 +1,96 @@ -// SplitUtils.cpp - -#include "StdAfx.h" - -#include "../../../Common/StringToInt.h" - -#include "SplitUtils.h" - -bool ParseVolumeSizes(const UString &s, CRecordVector &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 < ARRAY_SIZE(k_Sizes); i++) - combo.AddString(CSysString(k_Sizes[i])); -} - -UInt64 GetNumberOfVolumes(UInt64 size, const CRecordVector &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; -} +// SplitUtils.cpp + +#include "StdAfx.h" + +#include "../../../Common/StringToInt.h" + +#include "SplitUtils.h" + +bool ParseVolumeSizes(const UString &s, CRecordVector &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 < ARRAY_SIZE(k_Sizes); i++) + combo.AddString(CSysString(k_Sizes[i])); +} + +UInt64 GetNumberOfVolumes(UInt64 size, const CRecordVector &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 index c324032ff..641dfe6b7 100644 --- a/CPP/7zip/UI/FileManager/SplitUtils.h +++ b/CPP/7zip/UI/FileManager/SplitUtils.h @@ -1,15 +1,15 @@ -// SplitUtils.h - -#ifndef __SPLIT_UTILS_H -#define __SPLIT_UTILS_H - -#include "../../../Common/MyTypes.h" -#include "../../../Common/MyString.h" - -#include "../../../Windows/Control/ComboBox.h" - -bool ParseVolumeSizes(const UString &s, CRecordVector &values); -void AddVolumeItems(NWindows::NControl::CComboBox &volumeCombo); -UInt64 GetNumberOfVolumes(UInt64 size, const CRecordVector &volSizes); - -#endif +// SplitUtils.h + +#ifndef __SPLIT_UTILS_H +#define __SPLIT_UTILS_H + +#include "../../../Common/MyTypes.h" +#include "../../../Common/MyString.h" + +#include "../../../Windows/Control/ComboBox.h" + +bool ParseVolumeSizes(const UString &s, CRecordVector &values); +void AddVolumeItems(NWindows::NControl::CComboBox &volumeCombo); +UInt64 GetNumberOfVolumes(UInt64 size, const CRecordVector &volSizes); + +#endif diff --git a/CPP/7zip/UI/FileManager/StdAfx.cpp b/CPP/7zip/UI/FileManager/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/UI/FileManager/StdAfx.cpp +++ b/CPP/7zip/UI/FileManager/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/UI/FileManager/StdAfx.h b/CPP/7zip/UI/FileManager/StdAfx.h index ad67d8168..e6d960411 100644 --- a/CPP/7zip/UI/FileManager/StdAfx.h +++ b/CPP/7zip/UI/FileManager/StdAfx.h @@ -1,21 +1,21 @@ -// stdafx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -/* we used 0x0400 for Windows NT supporting (MENUITEMINFOW) - But now menu problem is fixed. So it's OK to use 0x0500 (Windows 2000) */ - -// #define _WIN32_WINNT 0x0400 -#define _WIN32_WINNT 0x0500 -#define WINVER _WIN32_WINNT - -#include "../../../Common/Common.h" - -// #include "../../../Common/MyWindows.h" - -// #include -// #include -// #include - -#endif +// stdafx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +/* we used 0x0400 for Windows NT supporting (MENUITEMINFOW) + But now menu problem is fixed. So it's OK to use 0x0500 (Windows 2000) */ + +// #define _WIN32_WINNT 0x0400 +#define _WIN32_WINNT 0x0500 +#define WINVER _WIN32_WINNT + +#include "../../../Common/Common.h" + +// #include "../../../Common/MyWindows.h" + +// #include +// #include +// #include + +#endif diff --git a/CPP/7zip/UI/FileManager/StringUtils.cpp b/CPP/7zip/UI/FileManager/StringUtils.cpp index 2b5957e3e..04783992d 100644 --- a/CPP/7zip/UI/FileManager/StringUtils.cpp +++ b/CPP/7zip/UI/FileManager/StringUtils.cpp @@ -1,65 +1,65 @@ -// 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; - } -} - -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++) - { - wchar_t c = srcString[i]; - if (c == ' ') - { - if (!s.IsEmpty()) - { - destStrings.Add(s); - s.Empty(); - } - } - else - s += c; - } - if (!s.IsEmpty()) - destStrings.Add(s); -} - -/* -UString JoinStrings(const UStringVector &srcStrings) -{ - - UString s; - FOR_VECTOR (i, srcStrings) - { - if (i != 0) - s.Add_Space(); - s += srcStrings[i]; - } - return s; -} -*/ +// 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; + } +} + +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++) + { + wchar_t c = srcString[i]; + if (c == ' ') + { + if (!s.IsEmpty()) + { + destStrings.Add(s); + s.Empty(); + } + } + else + s += c; + } + if (!s.IsEmpty()) + destStrings.Add(s); +} + +/* +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 index 7e4ffb437..fc070de18 100644 --- a/CPP/7zip/UI/FileManager/StringUtils.h +++ b/CPP/7zip/UI/FileManager/StringUtils.h @@ -1,13 +1,13 @@ -// StringUtils.h - -#ifndef __STRING_UTILS_H -#define __STRING_UTILS_H - -#include "../../../Common/MyString.h" - -void SplitStringToTwoStrings(const UString &src, UString &dest1, UString &dest2); - -void SplitString(const UString &srcString, UStringVector &destStrings); -UString JoinStrings(const UStringVector &srcStrings); - -#endif +// StringUtils.h + +#ifndef __STRING_UTILS_H +#define __STRING_UTILS_H + +#include "../../../Common/MyString.h" + +void SplitStringToTwoStrings(const UString &src, UString &dest1, UString &dest2); + +void SplitString(const UString &srcString, UStringVector &destStrings); +UString JoinStrings(const UStringVector &srcStrings); + +#endif diff --git a/CPP/7zip/UI/FileManager/SysIconUtils.cpp b/CPP/7zip/UI/FileManager/SysIconUtils.cpp index 2100e8294..c8ea8b95a 100644 --- a/CPP/7zip/UI/FileManager/SysIconUtils.cpp +++ b/CPP/7zip/UI/FileManager/SysIconUtils.cpp @@ -1,255 +1,255 @@ -// SysIconUtils.cpp - -#include "StdAfx.h" - -#ifndef _UNICODE -#include "../../../Common/StringConvert.h" -#endif - -#include "../../../Windows/FileDir.h" - -#include "SysIconUtils.h" - -#include - -#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 &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 &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" + +#include + +#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 &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 &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); +} +*/ diff --git a/CPP/7zip/UI/FileManager/SysIconUtils.h b/CPP/7zip/UI/FileManager/SysIconUtils.h index 2eedc4be4..f1b27fa15 100644 --- a/CPP/7zip/UI/FileManager/SysIconUtils.h +++ b/CPP/7zip/UI/FileManager/SysIconUtils.h @@ -1,62 +1,62 @@ -// SysIconUtils.h - -#ifndef __SYS_ICON_UTILS_H -#define __SYS_ICON_UTILS_H - -#include "../../../Common/MyWindows.h" - -#include - -#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 _attribMap; - CObjectVector _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 __SYS_ICON_UTILS_H +#define __SYS_ICON_UTILS_H + +#include "../../../Common/MyWindows.h" + +#include + +#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 _attribMap; + CObjectVector _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 diff --git a/CPP/7zip/UI/FileManager/SystemPage.cpp b/CPP/7zip/UI/FileManager/SystemPage.cpp index 3af62c7f0..a9ce454ad 100644 --- a/CPP/7zip/UI/FileManager/SystemPage.cpp +++ b/CPP/7zip/UI/FileManager/SystemPage.cpp @@ -1,461 +1,461 @@ -// SystemPage.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#include - -#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 - -static const UInt32 kLangIDs[] = -{ - IDT_SYSTEM_ASSOCIATE -}; - -#define kSystemTopic "FM/options.htm#system" - -CSysString CModifiedExtInfo::GetString() const -{ - if (State == kExtState_7Zip) - return TEXT("7-Zip ZS"); - if (State == kExtState_Clear) - return TEXT(""); - if (Other7Zip) - return TEXT("[7-Zip ZS]"); - return ProgramKey; -}; - - -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; - DWORD size = MAX_PATH + 10; - DWORD needLen = ::ExpandEnvironmentStringsW(iconPath, path.GetBuf(size + 2), size); - path.ReleaseBuf_CalcLen(size); - if (needLen == 0 || needLen >= size) - path = iconPath; - int num = ExtractIconExW(path, iconIndex, NULL, &hicon, 1); - if (num != 1 || !hicon) - #endif - return -1; - - _imageList.AddIcon(hicon); - DestroyIcon(hicon); - return _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 = 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; - - LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); - - _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 = (WCHAR *)(const WCHAR *)s; - ci.iSubItem = 1; - _listView.InsertColumn(1, &ci); - - #if NUM_EXT_GROUPS > 1 - { - LangString(IDS_SYSTEM_ALL_USERS, s); - ci.pszText = (WCHAR *)(const WCHAR *)s; - 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 = i; - item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; - item.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 = (wchar_t *)(const wchar_t *)(LPCWSTR)extInfo.Ext; - - 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(); - int itemIndex = _listView.InsertItem(&item); - for (g = 0; g < NUM_EXT_GROUPS; g++) - _listView.SetSubItem(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 ZS", MB_ICONERROR); - - return PSNRET_NOERROR; -} - - -void CSystemPage::OnNotifyHelp() -{ - ShowHelpWindow(kSystemTopic); -} - - -bool CSystemPage::OnButtonClicked(int 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(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(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; -} +// SystemPage.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#include + +#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 + +static const UInt32 kLangIDs[] = +{ + IDT_SYSTEM_ASSOCIATE +}; + +#define kSystemTopic "FM/options.htm#system" + +CSysString CModifiedExtInfo::GetString() const +{ + if (State == kExtState_7Zip) + return TEXT("7-Zip ZS"); + if (State == kExtState_Clear) + return TEXT(""); + if (Other7Zip) + return TEXT("[7-Zip ZS]"); + return ProgramKey; +}; + + +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; + DWORD size = MAX_PATH + 10; + DWORD needLen = ::ExpandEnvironmentStringsW(iconPath, path.GetBuf(size + 2), size); + path.ReleaseBuf_CalcLen(size); + if (needLen == 0 || needLen >= size) + path = iconPath; + int num = ExtractIconExW(path, iconIndex, NULL, &hicon, 1); + if (num != 1 || !hicon) + #endif + return -1; + + _imageList.AddIcon(hicon); + DestroyIcon(hicon); + return _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 = 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; + + LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); + + _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 = (WCHAR *)(const WCHAR *)s; + ci.iSubItem = 1; + _listView.InsertColumn(1, &ci); + + #if NUM_EXT_GROUPS > 1 + { + LangString(IDS_SYSTEM_ALL_USERS, s); + ci.pszText = (WCHAR *)(const WCHAR *)s; + 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 = i; + item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; + item.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 = (wchar_t *)(const wchar_t *)(LPCWSTR)extInfo.Ext; + + 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(); + int itemIndex = _listView.InsertItem(&item); + for (g = 0; g < NUM_EXT_GROUPS; g++) + _listView.SetSubItem(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 ZS", MB_ICONERROR); + + return PSNRET_NOERROR; +} + + +void CSystemPage::OnNotifyHelp() +{ + ShowHelpWindow(kSystemTopic); +} + + +bool CSystemPage::OnButtonClicked(int 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(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(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 index c81eb3a75..761a49aca 100644 --- a/CPP/7zip/UI/FileManager/SystemPage.h +++ b/CPP/7zip/UI/FileManager/SystemPage.h @@ -1,126 +1,126 @@ -// SystemPage.h - -#ifndef __SYSTEM_PAGE_H -#define __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 _items; - - unsigned _numIcons; - NWindows::NControl::CImageList _imageList; - NWindows::NControl::CListView _listView; - - bool _needSave; - - const 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(); - virtual void OnNotifyHelp(); - virtual bool OnNotify(UINT controlID, LPNMHDR lParam); - virtual LONG OnApply(); - virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); -}; - -#endif +// SystemPage.h + +#ifndef __SYSTEM_PAGE_H +#define __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 _items; + + unsigned _numIcons; + NWindows::NControl::CImageList _imageList; + NWindows::NControl::CListView _listView; + + bool _needSave; + + const 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(); + virtual void OnNotifyHelp(); + virtual bool OnNotify(UINT controlID, LPNMHDR lParam); + virtual LONG OnApply(); + virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/SystemPage.rc b/CPP/7zip/UI/FileManager/SystemPage.rc index da0c1ff9b..617512111 100644 --- a/CPP/7zip/UI/FileManager/SystemPage.rc +++ b/CPP/7zip/UI/FileManager/SystemPage.rc @@ -1,43 +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 ZS 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 ZS 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 +#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 ZS 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 ZS 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 index 13f6cd708..c89444825 100644 --- a/CPP/7zip/UI/FileManager/SystemPageRes.h +++ b/CPP/7zip/UI/FileManager/SystemPageRes.h @@ -1,9 +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 +#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/TextPairs.cpp b/CPP/7zip/UI/FileManager/TextPairs.cpp index b6d7560b2..d4002b452 100644 --- a/CPP/7zip/UI/FileManager/TextPairs.cpp +++ b/CPP/7zip/UI/FileManager/TextPairs.cpp @@ -1,190 +1,190 @@ -// 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 &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 **)a1, **(const CTextPair **)a2); } - -void CPairsStorage::Sort() { Pairs.Sort(ComparePairItems, 0); } - -int CPairsStorage::FindID(const UString &id, int &insertPos) const -{ - int left = 0, right = Pairs.Size(); - while (left != right) - { - int mid = (left + right) / 2; - int compResult = ComparePairIDs(id, Pairs[mid].ID); - if (compResult == 0) - return mid; - if (compResult < 0) - right = mid; - else - left = mid + 1; - } - insertPos = left; - return -1; -} - -int CPairsStorage::FindID(const UString &id) const -{ - int pos; - return FindID(id, pos); -} - -void CPairsStorage::AddPair(const CTextPair &pair) -{ - int insertPos; - int pos = FindID(pair.ID, insertPos); - if (pos >= 0) - Pairs[pos] = pair; - else - Pairs.Insert(insertPos, pair); -} - -void CPairsStorage::DeletePair(const UString &id) -{ - int pos = FindID(id); - if (pos >= 0) - Pairs.Delete(pos); -} - -bool CPairsStorage::GetValue(const UString &id, UString &value) const -{ - value.Empty(); - int pos = FindID(id); - if (pos < 0) - return false; - value = Pairs[pos].Value; - return true; -} - -UString CPairsStorage::GetValue(const UString &id) 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 += ' '; - text += pair.Value; - text += '\x0D'; - text.Add_LF(); - } -} +// 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 &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 **)a1, **(const CTextPair **)a2); } + +void CPairsStorage::Sort() { Pairs.Sort(ComparePairItems, 0); } + +int CPairsStorage::FindID(const UString &id, int &insertPos) const +{ + int left = 0, right = Pairs.Size(); + while (left != right) + { + int mid = (left + right) / 2; + int compResult = ComparePairIDs(id, Pairs[mid].ID); + if (compResult == 0) + return mid; + if (compResult < 0) + right = mid; + else + left = mid + 1; + } + insertPos = left; + return -1; +} + +int CPairsStorage::FindID(const UString &id) const +{ + int pos; + return FindID(id, pos); +} + +void CPairsStorage::AddPair(const CTextPair &pair) +{ + int insertPos; + int pos = FindID(pair.ID, insertPos); + if (pos >= 0) + Pairs[pos] = pair; + else + Pairs.Insert(insertPos, pair); +} + +void CPairsStorage::DeletePair(const UString &id) +{ + int pos = FindID(id); + if (pos >= 0) + Pairs.Delete(pos); +} + +bool CPairsStorage::GetValue(const UString &id, UString &value) const +{ + value.Empty(); + int pos = FindID(id); + if (pos < 0) + return false; + value = Pairs[pos].Value; + return true; +} + +UString CPairsStorage::GetValue(const UString &id) 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 += ' '; + text += pair.Value; + text += '\x0D'; + text.Add_LF(); + } +} diff --git a/CPP/7zip/UI/FileManager/TextPairs.h b/CPP/7zip/UI/FileManager/TextPairs.h index 6bc126f2d..0a71d044e 100644 --- a/CPP/7zip/UI/FileManager/TextPairs.h +++ b/CPP/7zip/UI/FileManager/TextPairs.h @@ -1,32 +1,32 @@ -// TextPairs.h - -#ifndef __FM_TEXT_PAIRS_H -#define __FM_TEXT_PAIRS_H - -#include "../../../Common/MyString.h" - -struct CTextPair -{ - UString ID; - UString Value; -}; - -class CPairsStorage -{ - CObjectVector Pairs; - - int FindID(const UString &id, int &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 +// TextPairs.h + +#ifndef __FM_TEXT_PAIRS_H +#define __FM_TEXT_PAIRS_H + +#include "../../../Common/MyString.h" + +struct CTextPair +{ + UString ID; + UString Value; +}; + +class CPairsStorage +{ + CObjectVector Pairs; + + int FindID(const UString &id, int &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 index 112689da8..67e70fb75 100644 --- a/CPP/7zip/UI/FileManager/UpdateCallback100.cpp +++ b/CPP/7zip/UI/FileManager/UpdateCallback100.cpp @@ -1,124 +1,124 @@ -// UpdateCallback100.cpp - -#include "StdAfx.h" - -#include "../../../Windows/ErrorMsg.h" - -#include "../GUI/resource3.h" - -#include "LangUtils.h" -#include "UpdateCallback100.h" - -STDMETHODIMP CUpdateCallback100Imp::ScanProgress(UInt64 /* numFolders */, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 /* isDir */) -{ - return ProgressDialog->Sync.ScanProgress(numFiles, totalSize, us2fs(path)); -} - -STDMETHODIMP CUpdateCallback100Imp::ScanError(const wchar_t *path, HRESULT errorCode) -{ - ProgressDialog->Sync.AddError_Code_Name(errorCode, path); - return S_OK; -} - -STDMETHODIMP CUpdateCallback100Imp::SetNumFiles(UInt64 numFiles) -{ - return ProgressDialog->Sync.Set_NumFilesTotal(numFiles); -} - -STDMETHODIMP CUpdateCallback100Imp::SetTotal(UInt64 size) -{ - ProgressDialog->Sync.Set_NumBytesTotal(size); - return S_OK; -} - -STDMETHODIMP CUpdateCallback100Imp::SetCompleted(const UInt64 *completed) -{ - return ProgressDialog->Sync.Set_NumBytesCur(completed); -} - -STDMETHODIMP CUpdateCallback100Imp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) -{ - ProgressDialog->Sync.Set_Ratio(inSize, outSize); - return S_OK; -} - -STDMETHODIMP CUpdateCallback100Imp::CompressOperation(const wchar_t *name) -{ - return SetOperation_Base(NUpdateNotifyOp::kAdd, name, false); -} - -STDMETHODIMP CUpdateCallback100Imp::DeleteOperation(const wchar_t *name) -{ - return SetOperation_Base(NUpdateNotifyOp::kDelete, name, false); -} - -STDMETHODIMP CUpdateCallback100Imp::OperationResult(Int32 /* operationResult */) -{ - ProgressDialog->Sync.Set_NumFilesCur(++NumFiles); - return S_OK; -} - -void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s); - -HRESULT 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; -} - -HRESULT CUpdateCallback100Imp::ReportUpdateOperation(UInt32 notifyOp, const wchar_t *name, Int32 isDir) -{ - return SetOperation_Base(notifyOp, name, IntToBool(isDir)); -} - -STDMETHODIMP CUpdateCallback100Imp::UpdateErrorMessage(const wchar_t *message) -{ - ProgressDialog->Sync.AddError_Message(message); - return S_OK; -} - -HRESULT CUpdateCallback100Imp::OpenFileError(const wchar_t *path, HRESULT errorCode) -{ - ProgressDialog->Sync.AddError_Code_Name(errorCode, path); - return S_OK; -} - -STDMETHODIMP CUpdateCallback100Imp::ReadingFileError(const wchar_t *path, HRESULT errorCode) -{ - ProgressDialog->Sync.AddError_Code_Name(errorCode, path); - return S_OK; -} - -STDMETHODIMP CUpdateCallback100Imp::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) -{ - *password = NULL; - *passwordIsDefined = BoolToInt(PasswordIsDefined); - if (!PasswordIsDefined) - return S_OK; - return StringToBstr(Password, password); -} - -STDMETHODIMP CUpdateCallback100Imp::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */) -{ - return S_OK; -} - -STDMETHODIMP CUpdateCallback100Imp::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */) -{ - return ProgressDialog->Sync.CheckStop(); -} - -STDMETHODIMP CUpdateCallback100Imp::CryptoGetTextPassword(BSTR *password) -{ - *password = NULL; - if (!PasswordIsDefined) - { - RINOK(ShowAskPasswordDialog()) - } - return StringToBstr(Password, password); -} +// UpdateCallback100.cpp + +#include "StdAfx.h" + +#include "../../../Windows/ErrorMsg.h" + +#include "../GUI/resource3.h" + +#include "LangUtils.h" +#include "UpdateCallback100.h" + +STDMETHODIMP CUpdateCallback100Imp::ScanProgress(UInt64 /* numFolders */, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 /* isDir */) +{ + return ProgressDialog->Sync.ScanProgress(numFiles, totalSize, us2fs(path)); +} + +STDMETHODIMP CUpdateCallback100Imp::ScanError(const wchar_t *path, HRESULT errorCode) +{ + ProgressDialog->Sync.AddError_Code_Name(errorCode, path); + return S_OK; +} + +STDMETHODIMP CUpdateCallback100Imp::SetNumFiles(UInt64 numFiles) +{ + return ProgressDialog->Sync.Set_NumFilesTotal(numFiles); +} + +STDMETHODIMP CUpdateCallback100Imp::SetTotal(UInt64 size) +{ + ProgressDialog->Sync.Set_NumBytesTotal(size); + return S_OK; +} + +STDMETHODIMP CUpdateCallback100Imp::SetCompleted(const UInt64 *completed) +{ + return ProgressDialog->Sync.Set_NumBytesCur(completed); +} + +STDMETHODIMP CUpdateCallback100Imp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + ProgressDialog->Sync.Set_Ratio(inSize, outSize); + return S_OK; +} + +STDMETHODIMP CUpdateCallback100Imp::CompressOperation(const wchar_t *name) +{ + return SetOperation_Base(NUpdateNotifyOp::kAdd, name, false); +} + +STDMETHODIMP CUpdateCallback100Imp::DeleteOperation(const wchar_t *name) +{ + return SetOperation_Base(NUpdateNotifyOp::kDelete, name, false); +} + +STDMETHODIMP CUpdateCallback100Imp::OperationResult(Int32 /* operationResult */) +{ + ProgressDialog->Sync.Set_NumFilesCur(++NumFiles); + return S_OK; +} + +void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s); + +HRESULT 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; +} + +HRESULT CUpdateCallback100Imp::ReportUpdateOperation(UInt32 notifyOp, const wchar_t *name, Int32 isDir) +{ + return SetOperation_Base(notifyOp, name, IntToBool(isDir)); +} + +STDMETHODIMP CUpdateCallback100Imp::UpdateErrorMessage(const wchar_t *message) +{ + ProgressDialog->Sync.AddError_Message(message); + return S_OK; +} + +HRESULT CUpdateCallback100Imp::OpenFileError(const wchar_t *path, HRESULT errorCode) +{ + ProgressDialog->Sync.AddError_Code_Name(errorCode, path); + return S_OK; +} + +STDMETHODIMP CUpdateCallback100Imp::ReadingFileError(const wchar_t *path, HRESULT errorCode) +{ + ProgressDialog->Sync.AddError_Code_Name(errorCode, path); + return S_OK; +} + +STDMETHODIMP CUpdateCallback100Imp::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) +{ + *password = NULL; + *passwordIsDefined = BoolToInt(PasswordIsDefined); + if (!PasswordIsDefined) + return S_OK; + return StringToBstr(Password, password); +} + +STDMETHODIMP CUpdateCallback100Imp::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */) +{ + return S_OK; +} + +STDMETHODIMP CUpdateCallback100Imp::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */) +{ + return ProgressDialog->Sync.CheckStop(); +} + +STDMETHODIMP 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 index 4b501b3f6..7cbc11e3a 100644 --- a/CPP/7zip/UI/FileManager/UpdateCallback100.h +++ b/CPP/7zip/UI/FileManager/UpdateCallback100.h @@ -1,52 +1,52 @@ -// UpdateCallback100.h - -#ifndef __UPDATE_CALLBACK100_H -#define __UPDATE_CALLBACK100_H - -#include "../../../Common/MyCom.h" - -#include "../../IPassword.h" - -#include "../Agent/IFolderArchive.h" - -#include "../GUI/UpdateCallbackGUI2.h" - -#include "ProgressDialog2.h" - -class CUpdateCallback100Imp: - public IFolderArchiveUpdateCallback, - public IFolderArchiveUpdateCallback2, - public IFolderScanProgress, - public ICryptoGetTextPassword2, - public ICryptoGetTextPassword, - public IArchiveOpenCallback, - public ICompressProgressInfo, - public CUpdateCallbackGUI2, - public CMyUnknownImp -{ -public: - - // CUpdateCallback100Imp() {} - - MY_UNKNOWN_IMP7( - IFolderArchiveUpdateCallback, - IFolderArchiveUpdateCallback2, - IFolderScanProgress, - ICryptoGetTextPassword2, - ICryptoGetTextPassword, - IArchiveOpenCallback, - ICompressProgressInfo) - - INTERFACE_IProgress(;) - INTERFACE_IArchiveOpenCallback(;) - INTERFACE_IFolderArchiveUpdateCallback(;) - INTERFACE_IFolderArchiveUpdateCallback2(;) - INTERFACE_IFolderScanProgress(;) - - STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); - - STDMETHOD(CryptoGetTextPassword)(BSTR *password); - STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password); -}; - -#endif +// UpdateCallback100.h + +#ifndef __UPDATE_CALLBACK100_H +#define __UPDATE_CALLBACK100_H + +#include "../../../Common/MyCom.h" + +#include "../../IPassword.h" + +#include "../Agent/IFolderArchive.h" + +#include "../GUI/UpdateCallbackGUI2.h" + +#include "ProgressDialog2.h" + +class CUpdateCallback100Imp: + public IFolderArchiveUpdateCallback, + public IFolderArchiveUpdateCallback2, + public IFolderScanProgress, + public ICryptoGetTextPassword2, + public ICryptoGetTextPassword, + public IArchiveOpenCallback, + public ICompressProgressInfo, + public CUpdateCallbackGUI2, + public CMyUnknownImp +{ +public: + + // CUpdateCallback100Imp() {} + + MY_UNKNOWN_IMP7( + IFolderArchiveUpdateCallback, + IFolderArchiveUpdateCallback2, + IFolderScanProgress, + ICryptoGetTextPassword2, + ICryptoGetTextPassword, + IArchiveOpenCallback, + ICompressProgressInfo) + + INTERFACE_IProgress(;) + INTERFACE_IArchiveOpenCallback(;) + INTERFACE_IFolderArchiveUpdateCallback(;) + INTERFACE_IFolderArchiveUpdateCallback2(;) + INTERFACE_IFolderScanProgress(;) + + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); + + STDMETHOD(CryptoGetTextPassword)(BSTR *password); + STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password); +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/ViewSettings.cpp b/CPP/7zip/UI/FileManager/ViewSettings.cpp index 335fdc097..11388bbdc 100644 --- a/CPP/7zip/UI/FileManager/ViewSettings.cpp +++ b/CPP/7zip/UI/FileManager/ViewSettings.cpp @@ -1,330 +1,330 @@ -// 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 "RegistryUtils.h" -#include "ViewSettings.h" - -using namespace NWindows; -using namespace NRegistry; - -#define REG_PATH_FM TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip-Zstandard") 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 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, rect.left); - Set32(buf + 4, rect.top); - Set32(buf + 8, rect.right); - Set32(buf + 12, 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(buf, rect.left); - Get32(buf + 4, rect.top); - Get32(buf + 8, rect.right); - Get32(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; -} - - -void SaveUi32Val(const TCHAR *name, UInt32 value) -{ - CKey key; - key.Create(HKEY_CURRENT_USER, kCUBasePath); - key.SetValue(name, value); -} - -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) -{ - if (WantFolderHistory()) - SaveStringList(kFolderHistoryValueName, folders); - else { - UStringVector Empty; - SaveStringList(kFolderHistoryValueName, Empty); - } -} - -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) -{ - if (WantCopyHistory()) - SaveStringList(kCopyHistoryValueName, folders); - else { - UStringVector Empty; - SaveStringList(kCopyHistoryValueName, Empty); - } -} - -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); -} +// 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 "RegistryUtils.h" +#include "ViewSettings.h" + +using namespace NWindows; +using namespace NRegistry; + +#define REG_PATH_FM TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip-Zstandard") 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 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, rect.left); + Set32(buf + 4, rect.top); + Set32(buf + 8, rect.right); + Set32(buf + 12, 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(buf, rect.left); + Get32(buf + 4, rect.top); + Get32(buf + 8, rect.right); + Get32(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; +} + + +void SaveUi32Val(const TCHAR *name, UInt32 value) +{ + CKey key; + key.Create(HKEY_CURRENT_USER, kCUBasePath); + key.SetValue(name, value); +} + +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) +{ + if (WantFolderHistory()) + SaveStringList(kFolderHistoryValueName, folders); + else { + UStringVector Empty; + SaveStringList(kFolderHistoryValueName, Empty); + } +} + +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) +{ + if (WantCopyHistory()) + SaveStringList(kCopyHistoryValueName, folders); + else { + UStringVector Empty; + SaveStringList(kCopyHistoryValueName, Empty); + } +} + +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 index c224d6af3..aeb689791 100644 --- a/CPP/7zip/UI/FileManager/ViewSettings.h +++ b/CPP/7zip/UI/FileManager/ViewSettings.h @@ -1,115 +1,115 @@ -// ViewSettings.h - -#ifndef __VIEW_SETTINGS_H -#define __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 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 +// ViewSettings.h + +#ifndef __VIEW_SETTINGS_H +#define __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 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 index 27dce9fd6..4525d8462 100644 --- a/CPP/7zip/UI/FileManager/makefile +++ b/CPP/7zip/UI/FileManager/makefile @@ -1,102 +1,102 @@ -PROG = 7zFM.exe -CFLAGS = $(CFLAGS) \ - -DEXTERNAL_CODECS \ - -!include "FM.mak" - -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 = $(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\RegistryContextMenu.obj \ - -GUI_OBJS = \ - $O\HashGUI.obj \ - $O\UpdateCallbackGUI2.obj \ - -COMPRESS_OBJS = \ - $O\CopyCoder.obj \ - -C_OBJS = $(C_OBJS) \ - $O\Alloc.obj \ - $O\CpuArch.obj \ - $O\Sort.obj \ - $O\Threads.obj \ - -!include "../../7zip.mak" +PROG = 7zFM.exe +CFLAGS = $(CFLAGS) \ + -DEXTERNAL_CODECS \ + +!include "FM.mak" + +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 = $(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\RegistryContextMenu.obj \ + +GUI_OBJS = \ + $O\HashGUI.obj \ + $O\UpdateCallbackGUI2.obj \ + +COMPRESS_OBJS = \ + $O\CopyCoder.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 302889ce1..0a3b92f9b 100644 --- a/CPP/7zip/UI/FileManager/resource.h +++ b/CPP/7zip/UI/FileManager/resource.h @@ -1,185 +1,185 @@ -#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_XXH32 104 -#define IDM_XXH64 105 -#define IDM_MD2 106 -#define IDM_MD4 107 -#define IDM_MD5 108 -#define IDM_SHA1 109 -#define IDM_SHA256 110 -#define IDM_SHA384 111 -#define IDM_SHA512 112 -#define IDM_BLAKE2sp 113 - -#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_XXH32 104 +#define IDM_XXH64 105 +#define IDM_MD2 106 +#define IDM_MD4 107 +#define IDM_MD5 108 +#define IDM_SHA1 109 +#define IDM_SHA256 110 +#define IDM_SHA384 111 +#define IDM_SHA512 112 +#define IDM_BLAKE2sp 113 + +#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 diff --git a/CPP/7zip/UI/FileManager/resource.rc b/CPP/7zip/UI/FileManager/resource.rc index 45c927e61..a6024ec2d 100644 --- a/CPP/7zip/UI/FileManager/resource.rc +++ b/CPP/7zip/UI/FileManager/resource.rc @@ -1,276 +1,276 @@ -#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 - - -IDM_MENU MENU -BEGIN - POPUP "&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 - 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 - MENUITEM SEPARATOR - MENUITEM "&Split file...", IDM_SPLIT - MENUITEM "Com&bine files...", IDM_COMBINE - MENUITEM SEPARATOR - MENUITEM "P&roperties\tAlt+Enter", IDM_PROPERTIES - MENUITEM "Comme&nt...\tCtrl+Z", IDM_COMMENT - // MENUITEM "Calculate checksum", IDM_CRC - POPUP "CRC" - BEGIN - MENUITEM "CRC-32", IDM_CRC32 - MENUITEM "CRC-64", IDM_CRC64 - MENUITEM "xxHash-32", IDM_XXH32 - MENUITEM "xxHash-64", IDM_XXH64 - MENUITEM "MD2", IDM_MD2 - MENUITEM "MD4", IDM_MD4 - MENUITEM "MD5", IDM_MD5 - MENUITEM "SHA-1", IDM_SHA1 - MENUITEM "SHA-256", IDM_SHA256 - MENUITEM "SHA-384", IDM_SHA384 - MENUITEM "SHA-512", IDM_SHA512 - MENUITEM "Blake2sp", IDM_BLAKE2sp - MENUITEM "*", IDM_HASH_ALL - END - MENUITEM "Di&ff", IDM_DIFF - MENUITEM SEPARATOR - MENUITEM "Create Folder\tF7", IDM_CREATE_FOLDER - MENUITEM "Create File\tCtrl+N", IDM_CREATE_FILE - MENUITEM SEPARATOR - MENUITEM "&Link...", IDM_LINK - MENUITEM "&Alternate streams", IDM_ALT_STREAMS - MENUITEM SEPARATOR - MENUITEM "E&xit\tAlt+F4", IDCLOSE - END - POPUP "&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 - // 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 "Select by Type\tAlt+[Grey+]", IDM_SELECT_BY_TYPE - MENUITEM "Deselect by Type\tAlt+[Grey -]", IDM_DESELECT_BY_TYPE - END - POPUP "&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, CHECKED - 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 - MENUITEM SEPARATOR - MENUITEM "Flat View", IDM_VIEW_FLAT_VIEW - MENUITEM "&2 Panels\tF9", IDM_VIEW_TWO_PANELS - - POPUP "2017" - BEGIN - MENUITEM "Time", IDM_VIEW_TIME - END - - POPUP "Toolbars" - BEGIN - MENUITEM "Archive Toolbar", IDM_VIEW_ARCHIVE_TOOLBAR - MENUITEM "Standard Toolbar", IDM_VIEW_STANDARD_TOOLBAR - 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" - BEGIN - POPUP "&Add folder to Favorites as" - BEGIN - MENUITEM SEPARATOR - END - MENUITEM SEPARATOR - END - POPUP "&Tools" - BEGIN - MENUITEM "&Options...", IDM_OPTIONS - MENUITEM SEPARATOR - MENUITEM "&Benchmark", IDM_BENCHMARK - #ifdef UNDER_CE - MENUITEM "Benchmark 2", IDM_BENCHMARK2 - #endif - #ifndef UNDER_CE - END - POPUP "&Help" - BEGIN - MENUITEM "&Contents...\tF1", IDM_HELP_CONTENTS - #endif - 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 "Can not 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 "Can not detect file as split file" - IDS_COMBINE_CANT_FIND_MORE_THAN_ONE_PART "Can not 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" +#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 + + +IDM_MENU MENU +BEGIN + POPUP "&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 + 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 + MENUITEM SEPARATOR + MENUITEM "&Split file...", IDM_SPLIT + MENUITEM "Com&bine files...", IDM_COMBINE + MENUITEM SEPARATOR + MENUITEM "P&roperties\tAlt+Enter", IDM_PROPERTIES + MENUITEM "Comme&nt...\tCtrl+Z", IDM_COMMENT + // MENUITEM "Calculate checksum", IDM_CRC + POPUP "CRC" + BEGIN + MENUITEM "CRC-32", IDM_CRC32 + MENUITEM "CRC-64", IDM_CRC64 + MENUITEM "xxHash-32", IDM_XXH32 + MENUITEM "xxHash-64", IDM_XXH64 + MENUITEM "MD2", IDM_MD2 + MENUITEM "MD4", IDM_MD4 + MENUITEM "MD5", IDM_MD5 + MENUITEM "SHA-1", IDM_SHA1 + MENUITEM "SHA-256", IDM_SHA256 + MENUITEM "SHA-384", IDM_SHA384 + MENUITEM "SHA-512", IDM_SHA512 + MENUITEM "Blake2sp", IDM_BLAKE2sp + MENUITEM "*", IDM_HASH_ALL + END + MENUITEM "Di&ff", IDM_DIFF + MENUITEM SEPARATOR + MENUITEM "Create Folder\tF7", IDM_CREATE_FOLDER + MENUITEM "Create File\tCtrl+N", IDM_CREATE_FILE + MENUITEM SEPARATOR + MENUITEM "&Link...", IDM_LINK + MENUITEM "&Alternate streams", IDM_ALT_STREAMS + MENUITEM SEPARATOR + MENUITEM "E&xit\tAlt+F4", IDCLOSE + END + POPUP "&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 + // 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 "Select by Type\tAlt+[Grey+]", IDM_SELECT_BY_TYPE + MENUITEM "Deselect by Type\tAlt+[Grey -]", IDM_DESELECT_BY_TYPE + END + POPUP "&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, CHECKED + 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 + MENUITEM SEPARATOR + MENUITEM "Flat View", IDM_VIEW_FLAT_VIEW + MENUITEM "&2 Panels\tF9", IDM_VIEW_TWO_PANELS + + POPUP "2017" + BEGIN + MENUITEM "Time", IDM_VIEW_TIME + END + + POPUP "Toolbars" + BEGIN + MENUITEM "Archive Toolbar", IDM_VIEW_ARCHIVE_TOOLBAR + MENUITEM "Standard Toolbar", IDM_VIEW_STANDARD_TOOLBAR + 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" + BEGIN + POPUP "&Add folder to Favorites as" + BEGIN + MENUITEM SEPARATOR + END + MENUITEM SEPARATOR + END + POPUP "&Tools" + BEGIN + MENUITEM "&Options...", IDM_OPTIONS + MENUITEM SEPARATOR + MENUITEM "&Benchmark", IDM_BENCHMARK + #ifdef UNDER_CE + MENUITEM "Benchmark 2", IDM_BENCHMARK2 + #endif + #ifndef UNDER_CE + END + POPUP "&Help" + BEGIN + MENUITEM "&Contents...\tF1", IDM_HELP_CONTENTS + #endif + 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 "Can not 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 "Can not detect file as split file" + IDS_COMBINE_CANT_FIND_MORE_THAN_ONE_PART "Can not 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 025f316ec..7c1b40e43 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 index 735f7067d..f748e0bd0 100644 --- a/CPP/7zip/UI/FileManager/resourceGui.rc +++ b/CPP/7zip/UI/FileManager/resourceGui.rc @@ -1,19 +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 +#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 index 3982748d4..39f516cd4 100644 --- a/CPP/7zip/UI/GUI/7zG.exe.manifest +++ b/CPP/7zip/UI/GUI/7zG.exe.manifest @@ -1,20 +1,20 @@ - - - - 7-Zip GUI. - - - - - - - - - - - - - true - - - + + + + 7-Zip GUI. + + + + + + + + + + + + + true + + + diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp index f8af962a1..e6dc57ba6 100644 --- a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp +++ b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp @@ -1,939 +1,939 @@ -// 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/System.h" -#include "../../../Windows/Thread.h" - -#include "../../Common/MethodProps.h" - -#include "../FileManager/HelpUtils.h" - -#include "../../MyVersion.h" - -#include "BenchmarkDialog.h" - -using namespace NWindows; - -#define kHelpTopic "fm/benchmark.htm" - -static const UINT_PTR kTimerID = 4; -static const UINT kTimerElapse = 1000; - -#ifdef LANG -#include "../FileManager/LangUtils.h" -#endif - -using namespace NWindows; - -UString HResultToMessage(HRESULT errorCode); - -#ifdef LANG -static const UInt32 kLangIDs[] = -{ - IDT_BENCH_DICTIONARY, - IDT_BENCH_MEMORY, - IDT_BENCH_NUM_THREADS, - IDT_BENCH_SPEED, - 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_Colon[] = -{ - IDT_BENCH_SIZE -}; - -#endif - -static LPCTSTR const kProcessingString = TEXT("..."); -static LPCTSTR const kMB = TEXT(" MB"); -static LPCTSTR const kMIPS = TEXT(" MIPS"); -static LPCTSTR const kKBs = TEXT(" KB/s"); - -static const unsigned kMinDicLogSize = - #ifdef UNDER_CE - 20; - #else - 21; - #endif - -static const UInt32 kMinDicSize = (1 << kMinDicLogSize); -static const UInt32 kMaxDicSize = - #ifdef MY_CPU_64BIT - (1 << 30); - #else - (1 << 27); - #endif - -bool CBenchmarkDialog::OnInit() -{ - #ifdef LANG - LangSetWindowText(*this, IDD_BENCH); - LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); - LangSetDlgItems_Colon(*this, kLangIDs_Colon, ARRAY_SIZE(kLangIDs_Colon)); - LangSetDlgItemText(*this, IDT_BENCH_CURRENT2, IDT_BENCH_CURRENT); - LangSetDlgItemText(*this, IDT_BENCH_RESULTING2, IDT_BENCH_RESULTING); - #endif - - Sync.Init(); - - 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; - - { - UString s ("/ "); - - NSystem::CProcessAffinity threadsInfo; - threadsInfo.InitST(); - - #ifndef _7ZIP_ST - - if (threadsInfo.Get() && threadsInfo.processAffinityMask != 0) - numCPUs = threadsInfo.GetNumProcessThreads(); - else - numCPUs = NSystem::GetNumberOfProcessors(); - - #endif - - s.Add_UInt32(numCPUs); - s += GetProcessThreadsInfo(threadsInfo); - SetItemText(IDT_BENCH_HARDWARE_THREADS, s); - } - - { - UString s; - { - AString s1, s2; - GetSysInfo(s1, s2); - s = s1; - SetItemText(IDT_BENCH_SYS1, s); - if (s1 != s2 && !s2.IsEmpty()) - { - s = s2; - SetItemText(IDT_BENCH_SYS2, s); - } - } - /* - { - GetVersionString(s); - SetItemText(IDT_BENCH_SYSTEM, s); - } - */ - { - AString s2; - GetCpuName(s2); - s = s2; - SetItemText(IDT_BENCH_CPU, s); - } - /* - { - AString s2; - GetCpuFeatures(s2); - s = s2; - SetItemText(IDT_BENCH_CPU_FEATURE, s); - } - */ - - s = "7-Zip " MY_VERSION_CPU; - SetItemText(IDT_BENCH_VER, s); - } - - - if (numCPUs < 1) - numCPUs = 1; - numCPUs = MyMin(numCPUs, (UInt32)(1 << 8)); - - if (Sync.NumThreads == (UInt32)(Int32)-1) - { - Sync.NumThreads = numCPUs; - if (Sync.NumThreads > 1) - Sync.NumThreads &= ~1; - } - m_NumThreads.Attach(GetItem(IDC_BENCH_NUM_THREADS)); - int cur = 0; - for (UInt32 num = 1; num <= numCPUs * 2;) - { - TCHAR s[16]; - ConvertUInt32ToString(num, s); - int index = (int)m_NumThreads.AddString(s); - m_NumThreads.SetItemData(index, num); - if (num <= Sync.NumThreads) - cur = index; - if (num > 1) - num++; - num++; - } - m_NumThreads.SetCurSel(cur); - Sync.NumThreads = GetNumberOfThreads(); - - m_Dictionary.Attach(GetItem(IDC_BENCH_DICTIONARY)); - cur = 0; - - 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 - - if (Sync.DictionarySize == (UInt32)(Int32)-1) - { - unsigned dicSizeLog = 25; - - #ifdef UNDER_CE - dicSizeLog = 20; - #endif - - if (ramSize_Defined) - for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--) - if (GetBenchMemoryUsage(Sync.NumThreads, ((UInt32)1 << dicSizeLog)) + (8 << 20) <= ramSize) - break; - Sync.DictionarySize = (1 << dicSizeLog); - } - - if (Sync.DictionarySize < kMinDicSize) Sync.DictionarySize = kMinDicSize; - if (Sync.DictionarySize > kMaxDicSize) Sync.DictionarySize = kMaxDicSize; - - for (unsigned i = kMinDicLogSize; i <= 30; i++) - for (unsigned j = 0; j < 2; j++) - { - UInt32 dict = ((UInt32)1 << i) + ((UInt32)j << (i - 1)); - if (dict > kMaxDicSize) - continue; - TCHAR s[32]; - ConvertUInt32ToString((dict >> 20), s); - lstrcat(s, kMB); - int index = (int)m_Dictionary.AddString(s); - m_Dictionary.SetItemData(index, dict); - if (dict <= Sync.DictionarySize) - cur = index; - } - m_Dictionary.SetCurSel(cur); - - OnChangeSettings(); - - Sync._startEvent.Set(); - _timer = SetTimer(kTimerID, kTimerElapse); - - if (TotalMode) - NormalizeSize(true); - else - NormalizePosition(); - return CModalDialog::OnInit(); -} - -bool CBenchmarkDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) -{ - if (!TotalMode) - return false; - int mx, my; - GetMargins(8, mx, my); - 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(); -} - - -void CBenchmarkDialog::SetItemText_Number(int itemID, UInt64 val, LPCTSTR post) -{ - TCHAR s[64]; - ConvertUInt64ToString(val, s); - if (post) - lstrcat(s, post); - SetItemText(itemID, s); -} - -static void PrintSize_MB(UString &s, UInt64 size) -{ - char temp[32]; - ConvertUInt64ToString((size + (1 << 20) - 1) >> 20, temp); - s += temp; - s += kMB; -} - - -UInt32 CBenchmarkDialog::OnChangeDictionary() -{ - const UInt32 dict = (UInt32)m_Dictionary.GetItemData_of_CurSel(); - const UInt64 memUsage = GetBenchMemoryUsage(GetNumberOfThreads(), dict); - - UString s; - PrintSize_MB(s, memUsage); - if (ramSize_Defined) - { - s += " / "; - PrintSize_MB(s, ramSize); - } - - #ifdef _7ZIP_LARGE_PAGES - { - AString s2; - Add_LargePages_String(s2); - s += s2; - } - #endif - - SetItemText(IDT_BENCH_MEMORY_VAL, s); - - return dict; -} - -static const UInt32 g_IDs[] = -{ - 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_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 - - // IDT_BENCH_FREQ_CUR, - // IDT_BENCH_FREQ_RES -}; - -void CBenchmarkDialog::OnChangeSettings() -{ - EnableItem(IDB_STOP, true); - UInt32 dict = OnChangeDictionary(); - - for (int i = 0; i < ARRAY_SIZE(g_IDs); i++) - SetItemText(g_IDs[i], kProcessingString); - _startTime = GetTickCount(); - PrintTime(); - NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS); - Sync.Init(); - Sync.DictionarySize = dict; - Sync.Changed = true; - Sync.NumThreads = GetNumberOfThreads(); -} - -void CBenchmarkDialog::OnRestartButton() -{ - OnChangeSettings(); -} - -void CBenchmarkDialog::OnStopButton() -{ - EnableItem(IDB_STOP, false); - Sync.Pause(); -} - -void CBenchmarkDialog::OnHelp() -{ - ShowHelpWindow(kHelpTopic); -} - -void CBenchmarkDialog::OnCancel() -{ - Sync.Stop(); - KillTimer(_timer); - CModalDialog::OnCancel(); -} - -void GetTimeString(UInt64 timeValue, wchar_t *s); - -void CBenchmarkDialog::PrintTime() -{ - UInt32 curTime = ::GetTickCount(); - UInt32 elapsedTime = (curTime - _startTime); - UInt32 elapsedSec = elapsedTime / 1000; - if (elapsedSec != 0 && Sync.WasPaused()) - return; - WCHAR s[40]; - GetTimeString(elapsedSec, s); - SetItemText(IDT_BENCH_ELAPSED_VAL, s); -} - -void CBenchmarkDialog::PrintRating(UInt64 rating, UINT controlID) -{ - SetItemText_Number(controlID, rating / 1000000, kMIPS); -} - -void CBenchmarkDialog::PrintUsage(UInt64 usage, UINT controlID) -{ - SetItemText_Number(controlID, (usage + 5000) / 10000, TEXT("%")); -} - -void CBenchmarkDialog::PrintResults( - UInt32 dictionarySize, - const CBenchInfo2 &info, - UINT usageID, UINT speedID, UINT rpuID, UINT ratingID, - bool decompressMode) -{ - if (info.GlobalTime == 0) - return; - - { - const UInt64 speed = info.UnpackSize * info.NumIterations * info.GlobalFreq / info.GlobalTime; - SetItemText_Number(speedID, speed >> 10, kKBs); - } - UInt64 rating; - if (decompressMode) - rating = info.GetDecompressRating(); - else - rating = info.GetCompressRating(dictionarySize); - - PrintRating(rating, ratingID); - PrintRating(info.GetRatingPerUsage(rating), rpuID); - PrintUsage(info.GetUsage(), usageID); -} - -bool CBenchmarkDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */) -{ - bool printTime = true; - if (TotalMode) - { - if (Sync.WasStopped()) - printTime = false; - } - if (printTime) - 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 true; - } - - SetItemText_Number(IDT_BENCH_SIZE_VAL, (Sync.ProcessedSize >> 20), kMB); - - SetItemText_Number(IDT_BENCH_PASSES_VAL, Sync.NumPasses); - - /* - if (Sync.FirstPath) - SetItemText_Number(IDT_BENCH_FREQ_CUR, Sync.Freq, TEXT(" MHz")); - else - SetItemText_Number(IDT_BENCH_FREQ_RES, Sync.Freq, TEXT(" MHz")); - */ - - /* - if (Sync.FreqWasChanged) - { - SetItemText(IDT_BENCH_FREQ, Sync.Freq); - Sync.FreqWasChanged = false; - } - */ - - { - UInt32 dicSizeTemp = (UInt32)MyMax(Sync.ProcessedSize, UInt64(1) << 20); - dicSizeTemp = MyMin(dicSizeTemp, Sync.DictionarySize), - PrintResults(dicSizeTemp, - Sync.CompressingInfoTemp, - IDT_BENCH_COMPRESS_USAGE1, - IDT_BENCH_COMPRESS_SPEED1, - IDT_BENCH_COMPRESS_RPU1, - IDT_BENCH_COMPRESS_RATING1); - } - - { - PrintResults( - Sync.DictionarySize, - Sync.CompressingInfo, - IDT_BENCH_COMPRESS_USAGE2, - IDT_BENCH_COMPRESS_SPEED2, - IDT_BENCH_COMPRESS_RPU2, - IDT_BENCH_COMPRESS_RATING2); - } - - { - PrintResults( - Sync.DictionarySize, - Sync.DecompressingInfoTemp, - IDT_BENCH_DECOMPR_USAGE1, - IDT_BENCH_DECOMPR_SPEED1, - IDT_BENCH_DECOMPR_RPU1, - IDT_BENCH_DECOMPR_RATING1, - true); - } - { - PrintResults( - Sync.DictionarySize, - Sync.DecompressingInfo, - IDT_BENCH_DECOMPR_USAGE2, - IDT_BENCH_DECOMPR_SPEED2, - IDT_BENCH_DECOMPR_RPU2, - IDT_BENCH_DECOMPR_RATING2, - true); - if (Sync.DecompressingInfo.GlobalTime > 0 && - Sync.CompressingInfo.GlobalTime > 0) - { - UInt64 comprRating = Sync.CompressingInfo.GetCompressRating(Sync.DictionarySize); - UInt64 decomprRating = Sync.DecompressingInfo.GetDecompressRating(); - PrintRating((comprRating + decomprRating) / 2, IDT_BENCH_TOTAL_RATING_VAL); - PrintRating(( - Sync.CompressingInfo.GetRatingPerUsage(comprRating) + - Sync.DecompressingInfo.GetRatingPerUsage(decomprRating)) / 2, IDT_BENCH_TOTAL_RPU_VAL); - PrintUsage( - (Sync.CompressingInfo.GetUsage() + - Sync.DecompressingInfo.GetUsage()) / 2, IDT_BENCH_TOTAL_USAGE_VAL); - } - } - return true; -} - -bool CBenchmarkDialog::OnCommand(int code, int itemID, LPARAM lParam) -{ - if (code == CBN_SELCHANGE && - (itemID == IDC_BENCH_DICTIONARY || - itemID == IDC_BENCH_NUM_THREADS)) - { - OnChangeSettings(); - return true; - } - return CModalDialog::OnCommand(code, itemID, lParam); -} - -bool CBenchmarkDialog::OnButtonClicked(int buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - case IDB_RESTART: - OnRestartButton(); - return true; - case IDB_STOP: - OnStopButton(); - return true; - } - return CModalDialog::OnButtonClicked(buttonID, buttonHWND); -} - -struct CThreadBenchmark -{ - CBenchmarkDialog *BenchmarkDialog; - DECL_EXTERNAL_CODECS_LOC_VARS2; - // UInt32 dictionarySize; - // UInt32 numThreads; - - HRESULT Process(); - HRESULT Result; - static THREAD_FUNC_DECL MyThreadFunction(void *param) - { - ((CThreadBenchmark *)param)->Result = ((CThreadBenchmark *)param)->Process(); - return 0; - } -}; - -struct CBenchCallback: public IBenchCallback -{ - UInt32 dictionarySize; - CBenchProgressSync *Sync; - - // void AddCpuFreq(UInt64 cpuFreq); - HRESULT SetFreq(bool showFreq, UInt64 cpuFreq); - HRESULT SetEncodeResult(const CBenchInfo &info, bool final); - HRESULT SetDecodeResult(const CBenchInfo &info, bool final); -}; - -/* -void CBenchCallback::AddCpuFreq(UInt64 cpuFreq) -{ - NSynchronization::CCriticalSectionLock lock(Sync->CS); - { - wchar_t s[32]; - ConvertUInt64ToString(cpuFreq, s); - Sync->Freq.Add_Space_if_NotEmpty(); - Sync->Freq += s; - Sync->FreqWasChanged = true; - } -} -*/ - -HRESULT CBenchCallback::SetFreq(bool /* showFreq */, UInt64 /* cpuFreq */) -{ - return S_OK; -} - -HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final) -{ - NSynchronization::CCriticalSectionLock lock(Sync->CS); - if (Sync->Changed || Sync->Paused || Sync->Stopped) - return E_ABORT; - Sync->ProcessedSize = info.UnpackSize * info.NumIterations; - if (final && Sync->CompressingInfo.GlobalTime == 0) - { - (CBenchInfo&)Sync->CompressingInfo = info; - if (Sync->CompressingInfo.GlobalTime == 0) - Sync->CompressingInfo.GlobalTime = 1; - } - else - (CBenchInfo&)Sync->CompressingInfoTemp = info; - - return S_OK; -} - -HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final) -{ - NSynchronization::CCriticalSectionLock lock(Sync->CS); - if (Sync->Changed || Sync->Paused || Sync->Stopped) - return E_ABORT; - CBenchInfo info2 = info; - if (final && Sync->DecompressingInfo.GlobalTime == 0) - { - (CBenchInfo&)Sync->DecompressingInfo = info2; - if (Sync->DecompressingInfo.GlobalTime == 0) - Sync->DecompressingInfo.GlobalTime = 1; - } - else - (CBenchInfo&)Sync->DecompressingInfoTemp = info2; - return S_OK; -} - -struct CBenchCallback2: public IBenchPrintCallback -{ - CBenchProgressSync *Sync; - bool TotalMode; - - void Print(const char *s); - void NewLine(); - HRESULT CheckBreak(); -}; - -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->Changed || Sync->Paused || Sync->Stopped) - return E_ABORT; - return S_OK; -} - - - -/* -struct CFreqCallback: public IBenchFreqCallback -{ - CBenchProgressSync *Sync; - - virtual void AddCpuFreq(UInt64 freq); -}; - -void CFreqCallback::AddCpuFreq(UInt64 freq) -{ - NSynchronization::CCriticalSectionLock lock(Sync->CS); - Sync->Freq = freq; -} -*/ - - - -HRESULT CThreadBenchmark::Process() -{ - CBenchProgressSync &sync = BenchmarkDialog->Sync; - sync.WaitCreating(); - try - { - for (;;) - { - if (sync.WasStopped()) - return 0; - if (sync.WasPaused()) - { - Sleep(200); - continue; - } - UInt32 dictionarySize; - UInt32 numThreads; - { - NSynchronization::CCriticalSectionLock lock(sync.CS); - if (sync.Stopped || sync.Paused) - continue; - if (sync.Changed) - sync.Init(); - dictionarySize = sync.DictionarySize; - numThreads = sync.NumThreads; - /* - if (sync.CompressingInfo.GlobalTime != 0) - sync.FirstPath = false; - */ - } - - CBenchCallback callback; - callback.dictionarySize = dictionarySize; - callback.Sync = &sync; - CBenchCallback2 callback2; - callback2.TotalMode = BenchmarkDialog->TotalMode; - callback2.Sync = &sync; - // CFreqCallback freqCallback; - // freqCallback.Sync = &sync; - HRESULT result; - - try - { - CObjectVector 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(dictionarySize); - prop.Name += 'b'; - props.Add(prop); - } - } - - result = Bench(EXTERNAL_CODECS_LOC_VARS - BenchmarkDialog->TotalMode ? &callback2 : NULL, - BenchmarkDialog->TotalMode ? NULL : &callback, - // &freqCallback, - props, 1, false); - - if (BenchmarkDialog->TotalMode) - { - sync.Stop(); - } - } - catch(...) - { - result = E_FAIL; - } - - if (result != S_OK) - { - if (result != E_ABORT) - { - { - NSynchronization::CCriticalSectionLock lock(sync.CS); - sync.Pause(); - } - UString message; - if (result == S_FALSE) - message = "Decoding error"; - else if (result == CLASS_E_CLASSNOTAVAILABLE) - message = "Can't find 7z.dll"; - else - message = HResultToMessage(result); - BenchmarkDialog->MessageBoxError(message); - } - } - else - { - NSynchronization::CCriticalSectionLock lock(sync.CS); - sync.NumPasses++; - } - } - // return S_OK; - } - catch(CSystemException &e) - { - BenchmarkDialog->MessageBoxError(HResultToMessage(e.ErrorCode)); - return E_FAIL; - } - catch(...) - { - BenchmarkDialog->MessageBoxError(HResultToMessage(E_FAIL)); - return E_FAIL; - } -} - -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 &props, HWND hwndParent) -{ - CThreadBenchmark benchmarker; - #ifdef EXTERNAL_CODECS - benchmarker.__externalCodecs = __externalCodecs; - #endif - - CBenchmarkDialog bd; - bd.Props = props; - bd.TotalMode = false; - bd.Sync.DictionarySize = (UInt32)(Int32)-1; - bd.Sync.NumThreads = (UInt32)(Int32)-1; - - COneMethodInfo method; - - UInt32 numCPUs = 1; - #ifndef _7ZIP_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 _7ZIP_ST - RINOK(ParseMtProp(name.Ptr(2), propVariant, numCPUs, numThreads)); - if (numThreads != numCPUs) - bd.Sync.NumThreads = numThreads; - #endif - continue; - } - if (name.IsEqualTo("testtime")) - { - // UInt32 testTime = 4; - // RINOK(ParsePropToUInt32(L"", propVariant, testTime)); - continue; - } - RINOK(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(); - } - - { - UInt32 dict; - if (method.Get_DicSize(dict)) - bd.Sync.DictionarySize = dict; - } - - benchmarker.BenchmarkDialog = &bd; - - NWindows::CThread thread; - RINOK(thread.Create(CThreadBenchmark::MyThreadFunction, &benchmarker)); - bd.Create(hwndParent); - return thread.Wait(); -} +// 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/System.h" +#include "../../../Windows/Thread.h" + +#include "../../Common/MethodProps.h" + +#include "../FileManager/HelpUtils.h" + +#include "../../MyVersion.h" + +#include "BenchmarkDialog.h" + +using namespace NWindows; + +#define kHelpTopic "fm/benchmark.htm" + +static const UINT_PTR kTimerID = 4; +static const UINT kTimerElapse = 1000; + +#ifdef LANG +#include "../FileManager/LangUtils.h" +#endif + +using namespace NWindows; + +UString HResultToMessage(HRESULT errorCode); + +#ifdef LANG +static const UInt32 kLangIDs[] = +{ + IDT_BENCH_DICTIONARY, + IDT_BENCH_MEMORY, + IDT_BENCH_NUM_THREADS, + IDT_BENCH_SPEED, + 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_Colon[] = +{ + IDT_BENCH_SIZE +}; + +#endif + +static LPCTSTR const kProcessingString = TEXT("..."); +static LPCTSTR const kMB = TEXT(" MB"); +static LPCTSTR const kMIPS = TEXT(" MIPS"); +static LPCTSTR const kKBs = TEXT(" KB/s"); + +static const unsigned kMinDicLogSize = + #ifdef UNDER_CE + 20; + #else + 21; + #endif + +static const UInt32 kMinDicSize = (1 << kMinDicLogSize); +static const UInt32 kMaxDicSize = + #ifdef MY_CPU_64BIT + (1 << 30); + #else + (1 << 27); + #endif + +bool CBenchmarkDialog::OnInit() +{ + #ifdef LANG + LangSetWindowText(*this, IDD_BENCH); + LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); + LangSetDlgItems_Colon(*this, kLangIDs_Colon, ARRAY_SIZE(kLangIDs_Colon)); + LangSetDlgItemText(*this, IDT_BENCH_CURRENT2, IDT_BENCH_CURRENT); + LangSetDlgItemText(*this, IDT_BENCH_RESULTING2, IDT_BENCH_RESULTING); + #endif + + Sync.Init(); + + 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; + + { + UString s ("/ "); + + NSystem::CProcessAffinity threadsInfo; + threadsInfo.InitST(); + + #ifndef _7ZIP_ST + + if (threadsInfo.Get() && threadsInfo.processAffinityMask != 0) + numCPUs = threadsInfo.GetNumProcessThreads(); + else + numCPUs = NSystem::GetNumberOfProcessors(); + + #endif + + s.Add_UInt32(numCPUs); + s += GetProcessThreadsInfo(threadsInfo); + SetItemText(IDT_BENCH_HARDWARE_THREADS, s); + } + + { + UString s; + { + AString s1, s2; + GetSysInfo(s1, s2); + s = s1; + SetItemText(IDT_BENCH_SYS1, s); + if (s1 != s2 && !s2.IsEmpty()) + { + s = s2; + SetItemText(IDT_BENCH_SYS2, s); + } + } + /* + { + GetVersionString(s); + SetItemText(IDT_BENCH_SYSTEM, s); + } + */ + { + AString s2; + GetCpuName(s2); + s = s2; + SetItemText(IDT_BENCH_CPU, s); + } + /* + { + AString s2; + GetCpuFeatures(s2); + s = s2; + SetItemText(IDT_BENCH_CPU_FEATURE, s); + } + */ + + s = "7-Zip " MY_VERSION_CPU; + SetItemText(IDT_BENCH_VER, s); + } + + + if (numCPUs < 1) + numCPUs = 1; + numCPUs = MyMin(numCPUs, (UInt32)(1 << 8)); + + if (Sync.NumThreads == (UInt32)(Int32)-1) + { + Sync.NumThreads = numCPUs; + if (Sync.NumThreads > 1) + Sync.NumThreads &= ~1; + } + m_NumThreads.Attach(GetItem(IDC_BENCH_NUM_THREADS)); + int cur = 0; + for (UInt32 num = 1; num <= numCPUs * 2;) + { + TCHAR s[16]; + ConvertUInt32ToString(num, s); + int index = (int)m_NumThreads.AddString(s); + m_NumThreads.SetItemData(index, num); + if (num <= Sync.NumThreads) + cur = index; + if (num > 1) + num++; + num++; + } + m_NumThreads.SetCurSel(cur); + Sync.NumThreads = GetNumberOfThreads(); + + m_Dictionary.Attach(GetItem(IDC_BENCH_DICTIONARY)); + cur = 0; + + 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 + + if (Sync.DictionarySize == (UInt32)(Int32)-1) + { + unsigned dicSizeLog = 25; + + #ifdef UNDER_CE + dicSizeLog = 20; + #endif + + if (ramSize_Defined) + for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--) + if (GetBenchMemoryUsage(Sync.NumThreads, ((UInt32)1 << dicSizeLog)) + (8 << 20) <= ramSize) + break; + Sync.DictionarySize = (1 << dicSizeLog); + } + + if (Sync.DictionarySize < kMinDicSize) Sync.DictionarySize = kMinDicSize; + if (Sync.DictionarySize > kMaxDicSize) Sync.DictionarySize = kMaxDicSize; + + for (unsigned i = kMinDicLogSize; i <= 30; i++) + for (unsigned j = 0; j < 2; j++) + { + UInt32 dict = ((UInt32)1 << i) + ((UInt32)j << (i - 1)); + if (dict > kMaxDicSize) + continue; + TCHAR s[32]; + ConvertUInt32ToString((dict >> 20), s); + lstrcat(s, kMB); + int index = (int)m_Dictionary.AddString(s); + m_Dictionary.SetItemData(index, dict); + if (dict <= Sync.DictionarySize) + cur = index; + } + m_Dictionary.SetCurSel(cur); + + OnChangeSettings(); + + Sync._startEvent.Set(); + _timer = SetTimer(kTimerID, kTimerElapse); + + if (TotalMode) + NormalizeSize(true); + else + NormalizePosition(); + return CModalDialog::OnInit(); +} + +bool CBenchmarkDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) +{ + if (!TotalMode) + return false; + int mx, my; + GetMargins(8, mx, my); + 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(); +} + + +void CBenchmarkDialog::SetItemText_Number(int itemID, UInt64 val, LPCTSTR post) +{ + TCHAR s[64]; + ConvertUInt64ToString(val, s); + if (post) + lstrcat(s, post); + SetItemText(itemID, s); +} + +static void PrintSize_MB(UString &s, UInt64 size) +{ + char temp[32]; + ConvertUInt64ToString((size + (1 << 20) - 1) >> 20, temp); + s += temp; + s += kMB; +} + + +UInt32 CBenchmarkDialog::OnChangeDictionary() +{ + const UInt32 dict = (UInt32)m_Dictionary.GetItemData_of_CurSel(); + const UInt64 memUsage = GetBenchMemoryUsage(GetNumberOfThreads(), dict); + + UString s; + PrintSize_MB(s, memUsage); + if (ramSize_Defined) + { + s += " / "; + PrintSize_MB(s, ramSize); + } + + #ifdef _7ZIP_LARGE_PAGES + { + AString s2; + Add_LargePages_String(s2); + s += s2; + } + #endif + + SetItemText(IDT_BENCH_MEMORY_VAL, s); + + return dict; +} + +static const UInt32 g_IDs[] = +{ + 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_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 + + // IDT_BENCH_FREQ_CUR, + // IDT_BENCH_FREQ_RES +}; + +void CBenchmarkDialog::OnChangeSettings() +{ + EnableItem(IDB_STOP, true); + UInt32 dict = OnChangeDictionary(); + + for (int i = 0; i < ARRAY_SIZE(g_IDs); i++) + SetItemText(g_IDs[i], kProcessingString); + _startTime = GetTickCount(); + PrintTime(); + NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS); + Sync.Init(); + Sync.DictionarySize = dict; + Sync.Changed = true; + Sync.NumThreads = GetNumberOfThreads(); +} + +void CBenchmarkDialog::OnRestartButton() +{ + OnChangeSettings(); +} + +void CBenchmarkDialog::OnStopButton() +{ + EnableItem(IDB_STOP, false); + Sync.Pause(); +} + +void CBenchmarkDialog::OnHelp() +{ + ShowHelpWindow(kHelpTopic); +} + +void CBenchmarkDialog::OnCancel() +{ + Sync.Stop(); + KillTimer(_timer); + CModalDialog::OnCancel(); +} + +void GetTimeString(UInt64 timeValue, wchar_t *s); + +void CBenchmarkDialog::PrintTime() +{ + UInt32 curTime = ::GetTickCount(); + UInt32 elapsedTime = (curTime - _startTime); + UInt32 elapsedSec = elapsedTime / 1000; + if (elapsedSec != 0 && Sync.WasPaused()) + return; + WCHAR s[40]; + GetTimeString(elapsedSec, s); + SetItemText(IDT_BENCH_ELAPSED_VAL, s); +} + +void CBenchmarkDialog::PrintRating(UInt64 rating, UINT controlID) +{ + SetItemText_Number(controlID, rating / 1000000, kMIPS); +} + +void CBenchmarkDialog::PrintUsage(UInt64 usage, UINT controlID) +{ + SetItemText_Number(controlID, (usage + 5000) / 10000, TEXT("%")); +} + +void CBenchmarkDialog::PrintResults( + UInt32 dictionarySize, + const CBenchInfo2 &info, + UINT usageID, UINT speedID, UINT rpuID, UINT ratingID, + bool decompressMode) +{ + if (info.GlobalTime == 0) + return; + + { + const UInt64 speed = info.UnpackSize * info.NumIterations * info.GlobalFreq / info.GlobalTime; + SetItemText_Number(speedID, speed >> 10, kKBs); + } + UInt64 rating; + if (decompressMode) + rating = info.GetDecompressRating(); + else + rating = info.GetCompressRating(dictionarySize); + + PrintRating(rating, ratingID); + PrintRating(info.GetRatingPerUsage(rating), rpuID); + PrintUsage(info.GetUsage(), usageID); +} + +bool CBenchmarkDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */) +{ + bool printTime = true; + if (TotalMode) + { + if (Sync.WasStopped()) + printTime = false; + } + if (printTime) + 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 true; + } + + SetItemText_Number(IDT_BENCH_SIZE_VAL, (Sync.ProcessedSize >> 20), kMB); + + SetItemText_Number(IDT_BENCH_PASSES_VAL, Sync.NumPasses); + + /* + if (Sync.FirstPath) + SetItemText_Number(IDT_BENCH_FREQ_CUR, Sync.Freq, TEXT(" MHz")); + else + SetItemText_Number(IDT_BENCH_FREQ_RES, Sync.Freq, TEXT(" MHz")); + */ + + /* + if (Sync.FreqWasChanged) + { + SetItemText(IDT_BENCH_FREQ, Sync.Freq); + Sync.FreqWasChanged = false; + } + */ + + { + UInt32 dicSizeTemp = (UInt32)MyMax(Sync.ProcessedSize, UInt64(1) << 20); + dicSizeTemp = MyMin(dicSizeTemp, Sync.DictionarySize), + PrintResults(dicSizeTemp, + Sync.CompressingInfoTemp, + IDT_BENCH_COMPRESS_USAGE1, + IDT_BENCH_COMPRESS_SPEED1, + IDT_BENCH_COMPRESS_RPU1, + IDT_BENCH_COMPRESS_RATING1); + } + + { + PrintResults( + Sync.DictionarySize, + Sync.CompressingInfo, + IDT_BENCH_COMPRESS_USAGE2, + IDT_BENCH_COMPRESS_SPEED2, + IDT_BENCH_COMPRESS_RPU2, + IDT_BENCH_COMPRESS_RATING2); + } + + { + PrintResults( + Sync.DictionarySize, + Sync.DecompressingInfoTemp, + IDT_BENCH_DECOMPR_USAGE1, + IDT_BENCH_DECOMPR_SPEED1, + IDT_BENCH_DECOMPR_RPU1, + IDT_BENCH_DECOMPR_RATING1, + true); + } + { + PrintResults( + Sync.DictionarySize, + Sync.DecompressingInfo, + IDT_BENCH_DECOMPR_USAGE2, + IDT_BENCH_DECOMPR_SPEED2, + IDT_BENCH_DECOMPR_RPU2, + IDT_BENCH_DECOMPR_RATING2, + true); + if (Sync.DecompressingInfo.GlobalTime > 0 && + Sync.CompressingInfo.GlobalTime > 0) + { + UInt64 comprRating = Sync.CompressingInfo.GetCompressRating(Sync.DictionarySize); + UInt64 decomprRating = Sync.DecompressingInfo.GetDecompressRating(); + PrintRating((comprRating + decomprRating) / 2, IDT_BENCH_TOTAL_RATING_VAL); + PrintRating(( + Sync.CompressingInfo.GetRatingPerUsage(comprRating) + + Sync.DecompressingInfo.GetRatingPerUsage(decomprRating)) / 2, IDT_BENCH_TOTAL_RPU_VAL); + PrintUsage( + (Sync.CompressingInfo.GetUsage() + + Sync.DecompressingInfo.GetUsage()) / 2, IDT_BENCH_TOTAL_USAGE_VAL); + } + } + return true; +} + +bool CBenchmarkDialog::OnCommand(int code, int itemID, LPARAM lParam) +{ + if (code == CBN_SELCHANGE && + (itemID == IDC_BENCH_DICTIONARY || + itemID == IDC_BENCH_NUM_THREADS)) + { + OnChangeSettings(); + return true; + } + return CModalDialog::OnCommand(code, itemID, lParam); +} + +bool CBenchmarkDialog::OnButtonClicked(int buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDB_RESTART: + OnRestartButton(); + return true; + case IDB_STOP: + OnStopButton(); + return true; + } + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); +} + +struct CThreadBenchmark +{ + CBenchmarkDialog *BenchmarkDialog; + DECL_EXTERNAL_CODECS_LOC_VARS2; + // UInt32 dictionarySize; + // UInt32 numThreads; + + HRESULT Process(); + HRESULT Result; + static THREAD_FUNC_DECL MyThreadFunction(void *param) + { + ((CThreadBenchmark *)param)->Result = ((CThreadBenchmark *)param)->Process(); + return 0; + } +}; + +struct CBenchCallback: public IBenchCallback +{ + UInt32 dictionarySize; + CBenchProgressSync *Sync; + + // void AddCpuFreq(UInt64 cpuFreq); + HRESULT SetFreq(bool showFreq, UInt64 cpuFreq); + HRESULT SetEncodeResult(const CBenchInfo &info, bool final); + HRESULT SetDecodeResult(const CBenchInfo &info, bool final); +}; + +/* +void CBenchCallback::AddCpuFreq(UInt64 cpuFreq) +{ + NSynchronization::CCriticalSectionLock lock(Sync->CS); + { + wchar_t s[32]; + ConvertUInt64ToString(cpuFreq, s); + Sync->Freq.Add_Space_if_NotEmpty(); + Sync->Freq += s; + Sync->FreqWasChanged = true; + } +} +*/ + +HRESULT CBenchCallback::SetFreq(bool /* showFreq */, UInt64 /* cpuFreq */) +{ + return S_OK; +} + +HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final) +{ + NSynchronization::CCriticalSectionLock lock(Sync->CS); + if (Sync->Changed || Sync->Paused || Sync->Stopped) + return E_ABORT; + Sync->ProcessedSize = info.UnpackSize * info.NumIterations; + if (final && Sync->CompressingInfo.GlobalTime == 0) + { + (CBenchInfo&)Sync->CompressingInfo = info; + if (Sync->CompressingInfo.GlobalTime == 0) + Sync->CompressingInfo.GlobalTime = 1; + } + else + (CBenchInfo&)Sync->CompressingInfoTemp = info; + + return S_OK; +} + +HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final) +{ + NSynchronization::CCriticalSectionLock lock(Sync->CS); + if (Sync->Changed || Sync->Paused || Sync->Stopped) + return E_ABORT; + CBenchInfo info2 = info; + if (final && Sync->DecompressingInfo.GlobalTime == 0) + { + (CBenchInfo&)Sync->DecompressingInfo = info2; + if (Sync->DecompressingInfo.GlobalTime == 0) + Sync->DecompressingInfo.GlobalTime = 1; + } + else + (CBenchInfo&)Sync->DecompressingInfoTemp = info2; + return S_OK; +} + +struct CBenchCallback2: public IBenchPrintCallback +{ + CBenchProgressSync *Sync; + bool TotalMode; + + void Print(const char *s); + void NewLine(); + HRESULT CheckBreak(); +}; + +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->Changed || Sync->Paused || Sync->Stopped) + return E_ABORT; + return S_OK; +} + + + +/* +struct CFreqCallback: public IBenchFreqCallback +{ + CBenchProgressSync *Sync; + + virtual void AddCpuFreq(UInt64 freq); +}; + +void CFreqCallback::AddCpuFreq(UInt64 freq) +{ + NSynchronization::CCriticalSectionLock lock(Sync->CS); + Sync->Freq = freq; +} +*/ + + + +HRESULT CThreadBenchmark::Process() +{ + CBenchProgressSync &sync = BenchmarkDialog->Sync; + sync.WaitCreating(); + try + { + for (;;) + { + if (sync.WasStopped()) + return 0; + if (sync.WasPaused()) + { + Sleep(200); + continue; + } + UInt32 dictionarySize; + UInt32 numThreads; + { + NSynchronization::CCriticalSectionLock lock(sync.CS); + if (sync.Stopped || sync.Paused) + continue; + if (sync.Changed) + sync.Init(); + dictionarySize = sync.DictionarySize; + numThreads = sync.NumThreads; + /* + if (sync.CompressingInfo.GlobalTime != 0) + sync.FirstPath = false; + */ + } + + CBenchCallback callback; + callback.dictionarySize = dictionarySize; + callback.Sync = &sync; + CBenchCallback2 callback2; + callback2.TotalMode = BenchmarkDialog->TotalMode; + callback2.Sync = &sync; + // CFreqCallback freqCallback; + // freqCallback.Sync = &sync; + HRESULT result; + + try + { + CObjectVector 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(dictionarySize); + prop.Name += 'b'; + props.Add(prop); + } + } + + result = Bench(EXTERNAL_CODECS_LOC_VARS + BenchmarkDialog->TotalMode ? &callback2 : NULL, + BenchmarkDialog->TotalMode ? NULL : &callback, + // &freqCallback, + props, 1, false); + + if (BenchmarkDialog->TotalMode) + { + sync.Stop(); + } + } + catch(...) + { + result = E_FAIL; + } + + if (result != S_OK) + { + if (result != E_ABORT) + { + { + NSynchronization::CCriticalSectionLock lock(sync.CS); + sync.Pause(); + } + UString message; + if (result == S_FALSE) + message = "Decoding error"; + else if (result == CLASS_E_CLASSNOTAVAILABLE) + message = "Can't find 7z.dll"; + else + message = HResultToMessage(result); + BenchmarkDialog->MessageBoxError(message); + } + } + else + { + NSynchronization::CCriticalSectionLock lock(sync.CS); + sync.NumPasses++; + } + } + // return S_OK; + } + catch(CSystemException &e) + { + BenchmarkDialog->MessageBoxError(HResultToMessage(e.ErrorCode)); + return E_FAIL; + } + catch(...) + { + BenchmarkDialog->MessageBoxError(HResultToMessage(E_FAIL)); + return E_FAIL; + } +} + +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 &props, HWND hwndParent) +{ + CThreadBenchmark benchmarker; + #ifdef EXTERNAL_CODECS + benchmarker.__externalCodecs = __externalCodecs; + #endif + + CBenchmarkDialog bd; + bd.Props = props; + bd.TotalMode = false; + bd.Sync.DictionarySize = (UInt32)(Int32)-1; + bd.Sync.NumThreads = (UInt32)(Int32)-1; + + COneMethodInfo method; + + UInt32 numCPUs = 1; + #ifndef _7ZIP_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 _7ZIP_ST + RINOK(ParseMtProp(name.Ptr(2), propVariant, numCPUs, numThreads)); + if (numThreads != numCPUs) + bd.Sync.NumThreads = numThreads; + #endif + continue; + } + if (name.IsEqualTo("testtime")) + { + // UInt32 testTime = 4; + // RINOK(ParsePropToUInt32(L"", propVariant, testTime)); + continue; + } + RINOK(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(); + } + + { + UInt32 dict; + if (method.Get_DicSize(dict)) + bd.Sync.DictionarySize = dict; + } + + benchmarker.BenchmarkDialog = &bd; + + NWindows::CThread thread; + RINOK(thread.Create(CThreadBenchmark::MyThreadFunction, &benchmarker)); + bd.Create(hwndParent); + return thread.Wait(); +} diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.h b/CPP/7zip/UI/GUI/BenchmarkDialog.h index 3f79b1ad3..7312a1daf 100644 --- a/CPP/7zip/UI/GUI/BenchmarkDialog.h +++ b/CPP/7zip/UI/GUI/BenchmarkDialog.h @@ -1,192 +1,192 @@ -// BenchmarkDialog.h - -#ifndef __BENCHMARK_DIALOG_H -#define __BENCHMARK_DIALOG_H - -#include "../../../Windows/Synchronization.h" - -#include "../../../Windows/Control/ComboBox.h" -#include "../../../Windows/Control/Edit.h" - -#include "../Common/Bench.h" - -#include "../FileManager/DialogSize.h" - -#include "BenchmarkDialogRes.h" - -struct CBenchInfo2 : public CBenchInfo -{ - void Init() { GlobalTime = UserTime = 0; } - - UInt64 GetCompressRating(UInt32 dictSize) const - { - return ::GetCompressRating(dictSize, GlobalTime, GlobalFreq, UnpackSize * NumIterations); - } - - UInt64 GetDecompressRating() const - { - return ::GetDecompressRating(GlobalTime, GlobalFreq, UnpackSize, PackSize, NumIterations); - } -}; - -class CBenchProgressSync -{ -public: - bool Stopped; - bool Paused; - bool Changed; - UInt32 DictionarySize; - UInt32 NumThreads; - UInt64 NumPasses; - NWindows::NSynchronization::CManualResetEvent _startEvent; - NWindows::NSynchronization::CCriticalSection CS; - - CBenchInfo2 CompressingInfoTemp; - CBenchInfo2 CompressingInfo; - UInt64 ProcessedSize; - - CBenchInfo2 DecompressingInfoTemp; - CBenchInfo2 DecompressingInfo; - - AString Text; - bool TextWasChanged; - - // bool FirstPath; - // UInt64 Freq; - // UString Freq; - // bool FreqWasChanged; - - CBenchProgressSync() - { - if (_startEvent.Create() != S_OK) - throw 3986437; - } - - void Init() - { - Changed = false; - Stopped = false; - Paused = false; - CompressingInfoTemp.Init(); - CompressingInfo.Init(); - ProcessedSize = 0; - - DecompressingInfoTemp.Init(); - DecompressingInfo.Init(); - - NumPasses = 0; - - // FirstPath = true; - // Freq = 0; - // Freq.SetFromAscii("MHz: "); - // FreqWasChanged = true; - - Text.Empty(); - TextWasChanged = true; - } - - void Stop() - { - NWindows::NSynchronization::CCriticalSectionLock lock(CS); - Stopped = true; - } - bool WasStopped() - { - NWindows::NSynchronization::CCriticalSectionLock lock(CS); - return Stopped; - } - void Pause() - { - NWindows::NSynchronization::CCriticalSectionLock lock(CS); - Paused = true; - } - void Start() - { - NWindows::NSynchronization::CCriticalSectionLock lock(CS); - Paused = false; - } - bool WasPaused() - { - NWindows::NSynchronization::CCriticalSectionLock lock(CS); - return Paused; - } - void WaitCreating() { _startEvent.Lock(); } -}; - -struct CMyFont -{ - HFONT _font; - CMyFont(): _font(NULL) {} - ~CMyFont() - { - if (_font) - DeleteObject(_font); - } - void Create(const LOGFONT *lplf) - { - _font = CreateFontIndirect(lplf); - } -}; - - -class CBenchmarkDialog: - public NWindows::NControl::CModalDialog -{ - NWindows::NControl::CComboBox m_Dictionary; - NWindows::NControl::CComboBox m_NumThreads; - NWindows::NControl::CEdit _consoleEdit; - UINT_PTR _timer; - UInt32 _startTime; - CMyFont _font; - - UInt64 ramSize; - bool ramSize_Defined; - - bool OnSize(WPARAM /* wParam */, int xSize, int ySize); - bool OnTimer(WPARAM timerID, LPARAM callback); - virtual bool OnInit(); - void OnRestartButton(); - void OnStopButton(); - void OnHelp(); - virtual void OnCancel(); - bool OnButtonClicked(int buttonID, HWND buttonHWND); - bool OnCommand(int code, int itemID, LPARAM lParam); - - void PrintTime(); - void PrintRating(UInt64 rating, UINT controlID); - void PrintUsage(UInt64 usage, UINT controlID); - void PrintResults( - UInt32 dictionarySize, - const CBenchInfo2 &info, UINT usageID, UINT speedID, UINT rpuID, UINT ratingID, - bool decompressMode = false); - - UInt32 GetNumberOfThreads(); - UInt32 OnChangeDictionary(); - void OnChangeSettings(); - - void SetItemText_Number(int itemID, UInt64 val, LPCTSTR post = NULL); - -public: - CBenchProgressSync Sync; - bool TotalMode; - CObjectVector Props; - - CSysString Bench2Text; - - CBenchmarkDialog(): _timer(0), TotalMode(false) {} - INT_PTR Create(HWND wndParent = 0) - { - 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 ZS", MB_ICONERROR); - } -}; - -HRESULT Benchmark( - DECL_EXTERNAL_CODECS_LOC_VARS - const CObjectVector &props, HWND hwndParent = NULL); - -#endif +// BenchmarkDialog.h + +#ifndef __BENCHMARK_DIALOG_H +#define __BENCHMARK_DIALOG_H + +#include "../../../Windows/Synchronization.h" + +#include "../../../Windows/Control/ComboBox.h" +#include "../../../Windows/Control/Edit.h" + +#include "../Common/Bench.h" + +#include "../FileManager/DialogSize.h" + +#include "BenchmarkDialogRes.h" + +struct CBenchInfo2 : public CBenchInfo +{ + void Init() { GlobalTime = UserTime = 0; } + + UInt64 GetCompressRating(UInt32 dictSize) const + { + return ::GetCompressRating(dictSize, GlobalTime, GlobalFreq, UnpackSize * NumIterations); + } + + UInt64 GetDecompressRating() const + { + return ::GetDecompressRating(GlobalTime, GlobalFreq, UnpackSize, PackSize, NumIterations); + } +}; + +class CBenchProgressSync +{ +public: + bool Stopped; + bool Paused; + bool Changed; + UInt32 DictionarySize; + UInt32 NumThreads; + UInt64 NumPasses; + NWindows::NSynchronization::CManualResetEvent _startEvent; + NWindows::NSynchronization::CCriticalSection CS; + + CBenchInfo2 CompressingInfoTemp; + CBenchInfo2 CompressingInfo; + UInt64 ProcessedSize; + + CBenchInfo2 DecompressingInfoTemp; + CBenchInfo2 DecompressingInfo; + + AString Text; + bool TextWasChanged; + + // bool FirstPath; + // UInt64 Freq; + // UString Freq; + // bool FreqWasChanged; + + CBenchProgressSync() + { + if (_startEvent.Create() != S_OK) + throw 3986437; + } + + void Init() + { + Changed = false; + Stopped = false; + Paused = false; + CompressingInfoTemp.Init(); + CompressingInfo.Init(); + ProcessedSize = 0; + + DecompressingInfoTemp.Init(); + DecompressingInfo.Init(); + + NumPasses = 0; + + // FirstPath = true; + // Freq = 0; + // Freq.SetFromAscii("MHz: "); + // FreqWasChanged = true; + + Text.Empty(); + TextWasChanged = true; + } + + void Stop() + { + NWindows::NSynchronization::CCriticalSectionLock lock(CS); + Stopped = true; + } + bool WasStopped() + { + NWindows::NSynchronization::CCriticalSectionLock lock(CS); + return Stopped; + } + void Pause() + { + NWindows::NSynchronization::CCriticalSectionLock lock(CS); + Paused = true; + } + void Start() + { + NWindows::NSynchronization::CCriticalSectionLock lock(CS); + Paused = false; + } + bool WasPaused() + { + NWindows::NSynchronization::CCriticalSectionLock lock(CS); + return Paused; + } + void WaitCreating() { _startEvent.Lock(); } +}; + +struct CMyFont +{ + HFONT _font; + CMyFont(): _font(NULL) {} + ~CMyFont() + { + if (_font) + DeleteObject(_font); + } + void Create(const LOGFONT *lplf) + { + _font = CreateFontIndirect(lplf); + } +}; + + +class CBenchmarkDialog: + public NWindows::NControl::CModalDialog +{ + NWindows::NControl::CComboBox m_Dictionary; + NWindows::NControl::CComboBox m_NumThreads; + NWindows::NControl::CEdit _consoleEdit; + UINT_PTR _timer; + UInt32 _startTime; + CMyFont _font; + + UInt64 ramSize; + bool ramSize_Defined; + + bool OnSize(WPARAM /* wParam */, int xSize, int ySize); + bool OnTimer(WPARAM timerID, LPARAM callback); + virtual bool OnInit(); + void OnRestartButton(); + void OnStopButton(); + void OnHelp(); + virtual void OnCancel(); + bool OnButtonClicked(int buttonID, HWND buttonHWND); + bool OnCommand(int code, int itemID, LPARAM lParam); + + void PrintTime(); + void PrintRating(UInt64 rating, UINT controlID); + void PrintUsage(UInt64 usage, UINT controlID); + void PrintResults( + UInt32 dictionarySize, + const CBenchInfo2 &info, UINT usageID, UINT speedID, UINT rpuID, UINT ratingID, + bool decompressMode = false); + + UInt32 GetNumberOfThreads(); + UInt32 OnChangeDictionary(); + void OnChangeSettings(); + + void SetItemText_Number(int itemID, UInt64 val, LPCTSTR post = NULL); + +public: + CBenchProgressSync Sync; + bool TotalMode; + CObjectVector Props; + + CSysString Bench2Text; + + CBenchmarkDialog(): _timer(0), TotalMode(false) {} + INT_PTR Create(HWND wndParent = 0) + { + 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 ZS", MB_ICONERROR); + } +}; + +HRESULT Benchmark( + DECL_EXTERNAL_CODECS_LOC_VARS + const CObjectVector &props, HWND hwndParent = NULL); + +#endif diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.rc b/CPP/7zip/UI/GUI/BenchmarkDialog.rc index e179ee39e..f1d37cab3 100644 --- a/CPP/7zip/UI/GUI/BenchmarkDialog.rc +++ b/CPP/7zip/UI/GUI/BenchmarkDialog.rc @@ -1,273 +1,273 @@ -#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 60 -#define sSpeed 60 -#define sUsage 60 -#define sRpu 60 -#define sFreq 34 - -#define xRating (xs - m - m - sRating) -#define xRpu (xRating - sRpu) -#define xUsage (xRpu - sUsage) -#define xSpeed (xUsage - sSpeed) - -#define xFreq (xUsage - sFreq) - -#define sLabel (xUsage - g4x) -#define sTotalRating (sUsage + sRpu + sRating + m + m) -#define xTotalRating (xs - m - sTotalRating) - -#define g2xs 58 -#define g3xs 36 -#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 - -IDD_BENCH 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 + 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, 8 - - 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, 32, g7xs, 8 - - RTEXT "CPU Usage", IDT_BENCH_USAGE_LABEL, xUsage, 54, sUsage, 8 - RTEXT "Speed", IDT_BENCH_SPEED, xSpeed, 54, sSpeed, 8 - RTEXT "Rating / Usage", IDT_BENCH_RPU_LABEL, xRpu, 54, sRpu, 8 - RTEXT "Rating", IDT_BENCH_RATING_LABEL, xRating, 54, sRating, 8 - - GROUPBOX "Compressing", IDG_BENCH_COMPRESSING, m, 64, xc, GROUP_Y_SIZE - - LTEXT "Current", IDT_BENCH_CURRENT, g4x, 76, sLabel, 8 - RTEXT "", IDT_BENCH_COMPRESS_USAGE1, xUsage, 76, sUsage, 8 - RTEXT "", IDT_BENCH_COMPRESS_SPEED1, xSpeed, 76, sSpeed, 8 - RTEXT "", IDT_BENCH_COMPRESS_RPU1, xRpu, 76, sRpu, 8 - RTEXT "", IDT_BENCH_COMPRESS_RATING1, xRating, 76, sRating, 8 - - LTEXT "Resulting", IDT_BENCH_RESULTING, g4x, 89, sLabel, 8 - RTEXT "", IDT_BENCH_COMPRESS_USAGE2, xUsage, 89, sUsage, 8 - RTEXT "", IDT_BENCH_COMPRESS_SPEED2, xSpeed, 89, sSpeed, 8 - RTEXT "", IDT_BENCH_COMPRESS_RPU2, xRpu, 89, sRpu, 8 - RTEXT "", IDT_BENCH_COMPRESS_RATING2, xRating, 89, sRating, 8 - - GROUPBOX "Decompressing", IDG_BENCH_DECOMPRESSING, m, 111, xc, GROUP_Y_SIZE - - LTEXT "Current", IDT_BENCH_CURRENT2, g4x, 123, sLabel, 8 - RTEXT "", IDT_BENCH_DECOMPR_USAGE1, xUsage, 123, sUsage, 8 - RTEXT "", IDT_BENCH_DECOMPR_SPEED1, xSpeed, 123, sSpeed, 8 - RTEXT "", IDT_BENCH_DECOMPR_RPU1, xRpu, 123, sRpu, 8 - RTEXT "", IDT_BENCH_DECOMPR_RATING1, xRating, 123, sRating, 8 - - LTEXT "Resulting", IDT_BENCH_RESULTING2, g4x, 136, sLabel, 8 - RTEXT "", IDT_BENCH_DECOMPR_USAGE2, xUsage, 136, sUsage, 8 - RTEXT "", IDT_BENCH_DECOMPR_SPEED2, xSpeed, 136, sSpeed, 8 - RTEXT "", IDT_BENCH_DECOMPR_RPU2, xRpu, 136, sRpu, 8 - RTEXT "", IDT_BENCH_DECOMPR_RATING2, xRating, 136, sRating, 8 - - GROUPBOX "Total Rating", IDG_BENCH_TOTAL_RATING, xTotalRating, 163, sTotalRating, GROUP_Y2_SIZE - - RTEXT "", IDT_BENCH_TOTAL_USAGE_VAL, xUsage, 176, sUsage, 8 - RTEXT "", IDT_BENCH_TOTAL_RPU_VAL, xRpu, 176, sRpu, 8 - RTEXT "", IDT_BENCH_TOTAL_RATING_VAL, xRating, 176, sRating, 8 - - RTEXT "", IDT_BENCH_CPU, m, 202, xc, 8 - - RTEXT "", IDT_BENCH_VER, m + xc - 80, 216, 80, 8 - - LTEXT "", IDT_BENCH_CPU_FEATURE, m, 212, xc - 80, 26 - LTEXT "", IDT_BENCH_SYS1, m, 238, xc - 140, 8 - LTEXT "", IDT_BENCH_SYS2, m, 248, xc - 140, 8 - - // LTEXT "", IDT_BENCH_SYSTEM, m, 232, xc - 80, 8 - // LTEXT "", IDT_BENCH_FREQ_RES, m, 242, 80, 8 - - - - 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, 189, g2xs, 8 - - RTEXT "", IDT_BENCH_ELAPSED_VAL, g3x, 163, g3xs, 8 - RTEXT "", IDT_BENCH_SIZE_VAL, g3x, 176, g3xs, 8 - RTEXT "", IDT_BENCH_PASSES_VAL, g3x, 189, g3xs, 8 -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 -} +#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 60 +#define sSpeed 60 +#define sUsage 60 +#define sRpu 60 +#define sFreq 34 + +#define xRating (xs - m - m - sRating) +#define xRpu (xRating - sRpu) +#define xUsage (xRpu - sUsage) +#define xSpeed (xUsage - sSpeed) + +#define xFreq (xUsage - sFreq) + +#define sLabel (xUsage - g4x) +#define sTotalRating (sUsage + sRpu + sRating + m + m) +#define xTotalRating (xs - m - sTotalRating) + +#define g2xs 58 +#define g3xs 36 +#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 + +IDD_BENCH 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 + 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, 8 + + 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, 32, g7xs, 8 + + RTEXT "CPU Usage", IDT_BENCH_USAGE_LABEL, xUsage, 54, sUsage, 8 + RTEXT "Speed", IDT_BENCH_SPEED, xSpeed, 54, sSpeed, 8 + RTEXT "Rating / Usage", IDT_BENCH_RPU_LABEL, xRpu, 54, sRpu, 8 + RTEXT "Rating", IDT_BENCH_RATING_LABEL, xRating, 54, sRating, 8 + + GROUPBOX "Compressing", IDG_BENCH_COMPRESSING, m, 64, xc, GROUP_Y_SIZE + + LTEXT "Current", IDT_BENCH_CURRENT, g4x, 76, sLabel, 8 + RTEXT "", IDT_BENCH_COMPRESS_USAGE1, xUsage, 76, sUsage, 8 + RTEXT "", IDT_BENCH_COMPRESS_SPEED1, xSpeed, 76, sSpeed, 8 + RTEXT "", IDT_BENCH_COMPRESS_RPU1, xRpu, 76, sRpu, 8 + RTEXT "", IDT_BENCH_COMPRESS_RATING1, xRating, 76, sRating, 8 + + LTEXT "Resulting", IDT_BENCH_RESULTING, g4x, 89, sLabel, 8 + RTEXT "", IDT_BENCH_COMPRESS_USAGE2, xUsage, 89, sUsage, 8 + RTEXT "", IDT_BENCH_COMPRESS_SPEED2, xSpeed, 89, sSpeed, 8 + RTEXT "", IDT_BENCH_COMPRESS_RPU2, xRpu, 89, sRpu, 8 + RTEXT "", IDT_BENCH_COMPRESS_RATING2, xRating, 89, sRating, 8 + + GROUPBOX "Decompressing", IDG_BENCH_DECOMPRESSING, m, 111, xc, GROUP_Y_SIZE + + LTEXT "Current", IDT_BENCH_CURRENT2, g4x, 123, sLabel, 8 + RTEXT "", IDT_BENCH_DECOMPR_USAGE1, xUsage, 123, sUsage, 8 + RTEXT "", IDT_BENCH_DECOMPR_SPEED1, xSpeed, 123, sSpeed, 8 + RTEXT "", IDT_BENCH_DECOMPR_RPU1, xRpu, 123, sRpu, 8 + RTEXT "", IDT_BENCH_DECOMPR_RATING1, xRating, 123, sRating, 8 + + LTEXT "Resulting", IDT_BENCH_RESULTING2, g4x, 136, sLabel, 8 + RTEXT "", IDT_BENCH_DECOMPR_USAGE2, xUsage, 136, sUsage, 8 + RTEXT "", IDT_BENCH_DECOMPR_SPEED2, xSpeed, 136, sSpeed, 8 + RTEXT "", IDT_BENCH_DECOMPR_RPU2, xRpu, 136, sRpu, 8 + RTEXT "", IDT_BENCH_DECOMPR_RATING2, xRating, 136, sRating, 8 + + GROUPBOX "Total Rating", IDG_BENCH_TOTAL_RATING, xTotalRating, 163, sTotalRating, GROUP_Y2_SIZE + + RTEXT "", IDT_BENCH_TOTAL_USAGE_VAL, xUsage, 176, sUsage, 8 + RTEXT "", IDT_BENCH_TOTAL_RPU_VAL, xRpu, 176, sRpu, 8 + RTEXT "", IDT_BENCH_TOTAL_RATING_VAL, xRating, 176, sRating, 8 + + RTEXT "", IDT_BENCH_CPU, m, 202, xc, 8 + + RTEXT "", IDT_BENCH_VER, m + xc - 80, 216, 80, 8 + + LTEXT "", IDT_BENCH_CPU_FEATURE, m, 212, xc - 80, 26 + LTEXT "", IDT_BENCH_SYS1, m, 238, xc - 140, 8 + LTEXT "", IDT_BENCH_SYS2, m, 248, xc - 140, 8 + + // LTEXT "", IDT_BENCH_SYSTEM, m, 232, xc - 80, 8 + // LTEXT "", IDT_BENCH_FREQ_RES, m, 242, 80, 8 + + + + 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, 189, g2xs, 8 + + RTEXT "", IDT_BENCH_ELAPSED_VAL, g3x, 163, g3xs, 8 + RTEXT "", IDT_BENCH_SIZE_VAL, g3x, 176, g3xs, 8 + RTEXT "", IDT_BENCH_PASSES_VAL, g3x, 189, g3xs, 8 +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 index f857179a5..8ee4f681b 100644 --- a/CPP/7zip/UI/GUI/BenchmarkDialogRes.h +++ b/CPP/7zip/UI/GUI/BenchmarkDialogRes.h @@ -1,71 +1,71 @@ -#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 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) +#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 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 index 1cc2c0073..cc5a89d79 100644 --- a/CPP/7zip/UI/GUI/CompressDialog.cpp +++ b/CPP/7zip/UI/GUI/CompressDialog.cpp @@ -1,2118 +1,2118 @@ -// 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 "../FileManager/BrowseDialog.h" -#include "../FileManager/FormatUtils.h" -#include "../FileManager/HelpUtils.h" -#include "../FileManager/SplitUtils.h" - -#include "../Explorer/MyMessages.h" - -#include "../Common/ZipRegistry.h" - -#include "CompressDialog.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -#ifdef LANG -#include "../FileManager/LangUtils.h" -#endif - -#include "CompressDialogRes.h" -#include "ExtractRes.h" - -#ifdef LANG -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, - - IDG_COMPRESS_OPTIONS, - IDX_COMPRESS_SFX, - IDX_COMPRESS_SHARED, - IDX_COMPRESS_DEL, - - IDT_COMPRESS_MEMORY, - IDT_COMPRESS_MEMORY_DE, - - IDX_COMPRESS_NT_SYM_LINKS, - IDX_COMPRESS_NT_HARD_LINKS, - IDX_COMPRESS_NT_ALT_STREAMS, - IDX_COMPRESS_NT_SECUR, - - 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 kNoSolidBlockSize = 0; -static const UInt32 kSolidBlockSize = 64; - -static LPCSTR const kExeExt = ".exe"; - -#define k7zFormat "7z" - -static const UInt32 g_Levels[] = -{ - IDS_METHOD_STORE, - IDS_METHOD_FASTEST, - IDS_METHOD_FAST, - IDS_METHOD_NORMAL, - IDS_METHOD_MAXIMUM, - IDS_METHOD_ULTRA -}; - -enum EMethodID -{ - kCopy, - kZSTD, - kBROTLI, - kLZ4, - kLZ5, - kLIZARD_M1, - kLIZARD_M2, - kLIZARD_M3, - kLIZARD_M4, - kLZMA, - kLZMA2, - kFLZMA2, - kPPMd, - kBZip2, - kDeflate, - kDeflate64, - kPPMdZip -}; - -static LPCSTR const kMethodsLongnames[] = -{ - "Copy [std]" - , "Zstandard" - , "Brotli" - , "LZ4" - , "LZ5" - , "Lizard, FastLZ4" - , "Lizard, LIZv1" - , "Lizard, FastLZ4 + Huffman" - , "Lizard, LIZv1 + Huffman" - , "LZMA [std]" - , "LZMA2 [std]" - , "LZMA2, Fast [std]" - , "PPMd [std]" - , "BZip2 [std]" - , "Deflate [std]" - , "Deflate64 [std]" - , "PPMd [std]" -}; - -static LPCSTR const kMethodsNames[] = -{ - "Copy" - , "zstd" - , "Brotli" - , "LZ4" - , "LZ5" - , "Lizard" - , "Lizard" - , "Lizard" - , "Lizard" - , "LZMA" - , "LZMA2" - , "FLZMA2" - , "PPMd" - , "BZip2" - , "Deflate" - , "Deflate64" - , "PPMd" -}; - -static const EMethodID g_ZstdMethods[] = -{ - kZSTD -}; - -static const EMethodID g_BrotliMethods[] = -{ - kBROTLI -}; - -static const EMethodID g_LizardMethods[] = -{ - kLIZARD_M1, - kLIZARD_M2, - kLIZARD_M3, - kLIZARD_M4 -}; - -static const EMethodID g_Lz4Methods[] = -{ - kLZ4 -}; - -static const EMethodID g_Lz5Methods[] = -{ - kLZ5 -}; - -static const EMethodID g_7zMethods[] = -{ - kZSTD, - kBROTLI, - kLZ4, - kLZ5, - kLIZARD_M1, - kLIZARD_M2, - kLIZARD_M3, - kLIZARD_M4, - kFLZMA2, - kLZMA2, - kLZMA, - kPPMd, - kDeflate, - kDeflate64, - kBZip2 -}; - -static const EMethodID g_7zSfxMethods[] = -{ - kCopy, - kZSTD, - kLZMA, - kLZMA2, - kFLZMA2, - kPPMd -}; - -static const EMethodID g_ZipMethods[] = -{ - kDeflate, - kDeflate64, - kBZip2, - kLZMA, - kPPMdZip -}; - -static const EMethodID g_GZipMethods[] = -{ - kDeflate -}; - -static const EMethodID g_BZip2Methods[] = -{ - kBZip2 -}; - -static const EMethodID g_XzMethods[] = -{ - kLZMA2 -}; - -static const EMethodID g_SwfcMethods[] = -{ - kDeflate - // kLZMA -}; - -struct CFormatInfo -{ - LPCSTR Name; - UInt32 LevelsMask; - unsigned NumMethods; - const EMethodID *MathodIDs; - bool Filter; - bool Solid; - bool MultiThread; - bool SFX; - - bool Encrypt; - bool EncryptFileNames; -}; - -#if 0 -void ShowInfo(LPCWSTR str, ...) -{ - wchar_t buf[4000]; - va_list args; - va_start(args, str); - wvsprintf(buf, str, args); - va_end(args); - ShowErrorMessage(NULL, buf); -} -#endif - -#define METHODS_PAIR(x) ARRAY_SIZE(x), x - -static const CFormatInfo g_Formats[] = -{ - { - "", /* 0 */ - (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), - 0, 0, - false, false, false, false, false, false - }, - { - k7zFormat, /* 1 */ - (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), - METHODS_PAIR(g_7zMethods), - true, true, true, true, true, true - }, - { - "Zip", /* 2 */ - (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), - METHODS_PAIR(g_ZipMethods), - false, false, true, false, true, false - }, - { - "GZip", /* 3 */ - (1 << 1) | (1 << 5) | (1 << 7) | (1 << 9), - METHODS_PAIR(g_GZipMethods), - false, false, false, false, false, false - }, - { - "BZip2", /* 4 */ - (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), - METHODS_PAIR(g_BZip2Methods), - false, false, true, false, false, false - }, - { - "xz", /* 5 */ - (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), - METHODS_PAIR(g_XzMethods), - false, true, true, false, false, false - }, - { - "zstd", /* 6 */ - (1 << 0) | (1 << 1) | (1 << 5) | (1 << 11) | (1 << 17) | (1 << 22), - METHODS_PAIR(g_ZstdMethods), - false, false, true, false, false, false - }, - { - "Brotli", /* 7 */ - (1 << 0) | (1 << 1) | (1 << 3) | (1 << 6) | (1 << 9) | (1 << 11), - METHODS_PAIR(g_BrotliMethods), - false, false, true, false, false, false - }, - { - "Lizard", /* 8 */ - (1 << 10) | (1 << 11) | (1 << 13) | (1 << 15) | (1 << 17) | (1 << 19), - METHODS_PAIR(g_LizardMethods), - false, false, true, false, false, false - }, - { - "LZ4", /* 9 */ - (1 << 0) | (1 << 1) | (1 << 3) | (1 << 6) | (1 << 9) | (1 << 12), - METHODS_PAIR(g_Lz4Methods), - false, false, true, false, false, false - }, - { - "LZ5", /* 10 */ - (1 << 0) | (1 << 1) | (1 << 3) | (1 << 7) | (1 << 11) | (1 << 15), - METHODS_PAIR(g_Lz5Methods), - false, false, true, false, false, false - }, - { - "Swfc", /* 11 */ - (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), - METHODS_PAIR(g_SwfcMethods), - false, false, true, false, false, false - }, - { - "Tar", /* 12 */ - (1 << 0), - 0, 0, - false, false, false, false, false, false - }, - { - "wim", /* 13 */ - (1 << 0), - 0, 0, - false, false, false, false, false, false - } -}; - -static bool IsMethodSupportedBySfx(int methodID) -{ - for (int i = 0; i < ARRAY_SIZE(g_7zSfxMethods); i++) - if (methodID == g_7zSfxMethods[i]) - return true; - return false; -} - -static bool GetMaxRamSizeForProgram(UInt64 &physSize) -{ - physSize = (UInt64)(sizeof(size_t)) << 29; - bool ramSize_Defined = NSystem::GetRamSize(physSize); - const UInt64 kMinSysSize = (1 << 24); - if (physSize <= kMinSysSize) - physSize = 0; - else - physSize -= kMinSysSize; - const UInt64 kMinUseSize = (1 << 24); - if (physSize < kMinUseSize) - physSize = kMinUseSize; - return ramSize_Defined; -} - - -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); -bool GetBoolsVal(const CBoolPair &b1, const CBoolPair &b2); - -void CCompressDialog::CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2) -{ - CheckButton(id, GetBoolsVal(b1, b2)); -} - -void CCompressDialog::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; -} - - -bool CCompressDialog::OnInit() -{ - #ifdef LANG - LangSetWindowText(*this, IDD_COMPRESS); - LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); - #endif - - _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)); - - m_ArchivePath.Attach(GetItem(IDC_COMPRESS_ARCHIVE)); - m_Format.Attach(GetItem(IDC_COMPRESS_FORMAT)); - m_Method.Attach(GetItem(IDC_COMPRESS_METHOD)); - m_Level.Attach(GetItem(IDC_COMPRESS_LEVEL)); - m_Dictionary.Attach(GetItem(IDC_COMPRESS_DICTIONARY)); - - m_Order.Attach(GetItem(IDC_COMPRESS_ORDER)); - m_Solid.Attach(GetItem(IDC_COMPRESS_SOLID)); - m_NumThreads.Attach(GetItem(IDC_COMPRESS_THREADS)); - - 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); - - CheckButton_TwoBools(IDX_COMPRESS_NT_SYM_LINKS, Info.SymLinks, m_RegistryInfo.SymLinks); - CheckButton_TwoBools(IDX_COMPRESS_NT_HARD_LINKS, Info.HardLinks, m_RegistryInfo.HardLinks); - CheckButton_TwoBools(IDX_COMPRESS_NT_ALT_STREAMS, Info.AltStreams, m_RegistryInfo.AltStreams); - CheckButton_TwoBools(IDX_COMPRESS_NT_SECUR, Info.NtSecurity, m_RegistryInfo.NtSecurity); - - UpdatePasswordControl(); - - { - bool needSetMain = (Info.FormatIndex < 0); - FOR_VECTOR(i, ArcIndices) - { - unsigned arcIndex = ArcIndices[i]; - const CArcInfoEx &ai = (*ArcFormats)[arcIndex]; - int index = (int)m_Format.AddString(ai.Name); - m_Format.SetItemData(index, 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 = arcIndex; - } - } - } - - CheckButton(IDX_COMPRESS_SFX, Info.SFXMode); - - { - UString fileName; - SetArcPathFields(Info.ArcPath, fileName, true); - StartDirPrefix = DirPrefix; - SetArchiveName(fileName); - } - - SetMethod(); - SetLevel(); - SetParams(); - - 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, ARRAY_SIZE(k_UpdateMode_IDs), - k_UpdateMode_Vals, Info.UpdateMode); - - AddComboItems(m_PathMode, k_PathMode_IDs, ARRAY_SIZE(k_PathMode_IDs), - k_PathMode_Vals, Info.PathMode); - - SetSolidBlockSize(); - SetNumThreads(); - - TCHAR s[40] = { 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); - - CheckControlsEnable(); - - SetEncryptionMethod(); - SetMemoryUsage(); - - NormalizePosition(); - - return CModalDialog::OnInit(); -} - -void CCompressDialog::UpdatePasswordControl() -{ - bool showPassword = IsShowPasswordChecked(); - TCHAR c = showPassword ? (TCHAR)0: TEXT('*'); - _password1Control.SetPasswordChar(c); - _password2Control.SetPasswordChar(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(int 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; - } - } - return CModalDialog::OnButtonClicked(buttonID, buttonHWND); -} - -void CCompressDialog::CheckSFXControlsEnable() -{ - const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - bool enable = fi.SFX; - if (enable) - { - int methodID = GetMethodID(); - enable = (methodID == -1 || IsMethodSupportedBySfx(methodID)); - } - if (!enable) - CheckButton(IDX_COMPRESS_SFX, false); - EnableItem(IDX_COMPRESS_SFX, enable); -} - -void CCompressDialog::CheckControlsEnable() -{ - const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - Info.SolidIsSpecified = fi.Solid; - bool multiThreadEnable = fi.MultiThread; - Info.MultiThreadIsAllowed = multiThreadEnable; - Info.EncryptHeadersIsAllowed = fi.EncryptFileNames; - - EnableItem(IDC_COMPRESS_SOLID, fi.Solid); - EnableItem(IDC_COMPRESS_THREADS, multiThreadEnable); - - CheckSFXControlsEnable(); - - { - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - - ShowItem_Bool(IDX_COMPRESS_NT_SYM_LINKS, ai.Flags_SymLinks()); - ShowItem_Bool(IDX_COMPRESS_NT_HARD_LINKS, ai.Flags_HardLinks()); - ShowItem_Bool(IDX_COMPRESS_NT_ALT_STREAMS, ai.Flags_AltStreams()); - ShowItem_Bool(IDX_COMPRESS_NT_SECUR, ai.Flags_NtSecure()); - - ShowItem_Bool(IDG_COMPRESS_NTFS, - ai.Flags_SymLinks() - || ai.Flags_HardLinks() - || ai.Flags_AltStreams() - || ai.Flags_NtSecure()); - } - - EnableItem(IDG_COMPRESS_ENCRYPTION, fi.Encrypt); - - EnableItem(IDT_PASSWORD_ENTER, fi.Encrypt); - EnableItem(IDT_PASSWORD_REENTER, fi.Encrypt); - EnableItem(IDE_COMPRESS_PASSWORD1, fi.Encrypt); - EnableItem(IDE_COMPRESS_PASSWORD2, fi.Encrypt); - EnableItem(IDX_PASSWORD_SHOW, fi.Encrypt); - - EnableItem(IDT_COMPRESS_ENCRYPTION_METHOD, fi.Encrypt); - EnableItem(IDC_COMPRESS_ENCRYPTION_METHOD, fi.Encrypt); - EnableItem(IDX_COMPRESS_ENCRYPT_FILE_NAMES, fi.EncryptFileNames); - - ShowItem_Bool(IDX_COMPRESS_ENCRYPT_FILE_NAMES, fi.EncryptFileNames); -} - -bool CCompressDialog::IsSFX() -{ - CWindow sfxButton = GetItem(IDX_COMPRESS_SFX); - return sfxButton.IsEnabled() && IsButtonCheckedBool(IDX_COMPRESS_SFX); -} - -static int GetExtDotPos(const UString &s) -{ - int dotPos = s.ReverseFind_Dot(); - if (dotPos > s.ReverseFind_PathSepar() + 1) - return dotPos; - return -1; -} - -void CCompressDialog::OnButtonSFX() -{ - UString fileName; - m_ArchivePath.GetText(fileName); - int dotPos = GetExtDotPos(fileName); - if (IsSFX()) - { - if (dotPos >= 0) - fileName.DeleteFrom(dotPos); - fileName += kExeExt; - m_ArchivePath.SetText(fileName); - } - else - { - if (dotPos >= 0) - { - UString ext = fileName.Ptr(dotPos); - if (ext.IsEqualTo_Ascii_NoCase(kExeExt)) - { - fileName.DeleteFrom(dotPos); - m_ArchivePath.SetText(fileName); - } - } - SetArchiveName2(false); // it's for OnInit - } -} - -bool CCompressDialog::GetFinalPath_Smart(UString &resPath) -{ - UString name; - m_ArchivePath.GetText(name); - name.Trim(); - UString tempPath = name; - if (!IsAbsolutePath(name)) - { - UString newDirPrefix = DirPrefix; - if (newDirPrefix.IsEmpty()) - newDirPrefix = StartDirPrefix; - FString resultF; - if (!MyGetFullPathName(us2fs(newDirPrefix + name), resultF)) - return false; - tempPath = fs2us(resultF); - } - if (!SetArcPathFields(tempPath, name, false)) - return false; - FString resultF; - if (!MyGetFullPathName(us2fs(DirPrefix + name), resultF)) - return false; - resPath = fs2us(resultF); - return true; -} - -bool CCompressDialog::SetArcPathFields(const UString &path, UString &name, bool always) -{ - FString resDirPrefix; - FString resFileName; - 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"; - -void CCompressDialog::OnButtonSetArchive() -{ - UString path; - if (!GetFinalPath_Smart(path)) - { - ShowErrorMessage(*this, k_IncorrectPathMessage); - return; - } - - UString title = LangString(IDS_COMPRESS_SET_ARCHIVE_BROWSE); - UString filterDescription = LangString(IDS_OPEN_TYPE_ALL_FILES); - filterDescription += " (*.*)"; - UString resPath; - CurrentDirWasChanged = true; - if (!MyBrowseForFile(*this, title, - // DirPrefix.IsEmpty() ? NULL : (const wchar_t *)DirPrefix, - // NULL, - path, - filterDescription, - NULL, // L"*.*", - resPath)) - return; - UString dummyName; - SetArcPathFields(resPath, dummyName, true); -} - -// 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++) - { - wchar_t c = s[i]; - if (c < 0x20 || c > 0x7F) - return false; - } - return true; -} - -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; - } - } - - SaveOptionsInMem(); - { - UString s; - if (!GetFinalPath_Smart(s)) - { - ShowErrorMessage(*this, k_IncorrectPathMessage); - return; - } - - m_RegistryInfo.ArcPaths.Clear(); - AddUniqueString(m_RegistryInfo.ArcPaths, s); - Info.ArcPath = 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.Dictionary = GetDictionarySpec(); - Info.Order = GetOrderSpec(); - Info.OrderMode = GetOrderMode(); - Info.NumThreads = GetNumThreadsSpec(); - - { - 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 = 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); - - GetButton_Bools(IDX_COMPRESS_NT_SYM_LINKS, Info.SymLinks, m_RegistryInfo.SymLinks); - GetButton_Bools(IDX_COMPRESS_NT_HARD_LINKS, Info.HardLinks, m_RegistryInfo.HardLinks); - GetButton_Bools(IDX_COMPRESS_NT_ALT_STREAMS, Info.AltStreams, m_RegistryInfo.AltStreams); - GetButton_Bools(IDX_COMPRESS_NT_SECUR, Info.NtSecurity, m_RegistryInfo.NtSecurity); - - { - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - if (!ai.Flags_SymLinks()) Info.SymLinks.Val = false; - if (!ai.Flags_HardLinks()) Info.HardLinks.Val = false; - if (!ai.Flags_AltStreams()) Info.AltStreams.Val = false; - if (!ai.Flags_NtSecure()) Info.NtSecurity.Val = false; - } - - m_Params.GetText(Info.Options); - m_Volume.GetText(Info.SplitVolume); - Info.SplitVolume.Trim(); - Info.VolumeSizes.Clear(); - - if (!Info.SplitVolume.IsEmpty()) - { - if (!ParseVolumeSizes(Info.SplitVolume, 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 ZS", MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES) - return; - } - } - } - - for (int i = 0; i < m_ArchivePath.GetCount(); i++) - { - UString sTemp; - m_ArchivePath.GetLBText(i, sTemp); - sTemp.Trim(); - AddUniqueString(m_RegistryInfo.ArcPaths, sTemp); - } - - if (m_RegistryInfo.ArcPaths.Size() > kHistorySize) - m_RegistryInfo.ArcPaths.DeleteBack(); - - if (Info.FormatIndex >= 0) - m_RegistryInfo.ArcType = (*ArcFormats)[Info.FormatIndex].Name; - m_RegistryInfo.ShowPassword = IsShowPasswordChecked(); - - m_RegistryInfo.Save(); - - CModalDialog::OnOK(); -} - -#define kHelpTopic "fm/plugins/7-zip/add.htm" - -void CCompressDialog::OnHelp() -{ - ShowHelpWindow(kHelpTopic); -} - -bool CCompressDialog::OnCommand(int code, int itemID, LPARAM lParam) -{ - if (code == CBN_SELCHANGE) - { - switch (itemID) - { - case IDC_COMPRESS_ARCHIVE: - { - // we can 't change m_ArchivePath in that handler ! - DirPrefix.Empty(); - SetItemText(IDT_COMPRESS_ARCHIVE_FOLDER, DirPrefix); - return true; - } - - case IDC_COMPRESS_FORMAT: - { - bool isSFX = IsSFX(); - SaveOptionsInMem(); - m_Solid.ResetContent(); - SetMethod(GetMethodID()); - SetLevel(); - SetSolidBlockSize(); - SetNumThreads(); - SetParams(); - CheckControlsEnable(); - SetArchiveName2(isSFX); - SetEncryptionMethod(); - SetMemoryUsage(); - SetMethod(GetMethodID()); - return true; - } - - case IDC_COMPRESS_LEVEL: - { - { - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - int index = FindRegistryFormatAlways(ai.Name); - NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - fo.ResetForLevelChange(); - } - - SetSolidBlockSize(); - SetNumThreads(); - CheckSFXNameChange(); - SetMemoryUsage(); - return true; - } - - case IDC_COMPRESS_METHOD: - { - SetMethod(GetMethodID()); - SetDictionary(); - SetOrder(); - SetSolidBlockSize(); - SetNumThreads(); - CheckSFXNameChange(); - SetMemoryUsage(); - return true; - } - - case IDC_COMPRESS_DICTIONARY: - { - UInt32 blockSizeLog = GetBlockSizeSpec(); - if (blockSizeLog != (UInt32)(Int32)-1 - && blockSizeLog != kNoSolidBlockSize - && blockSizeLog != kSolidBlockSize) - { - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - int index = FindRegistryFormatAlways(ai.Name); - NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - fo.Reset_BlockLogSize(); - SetSolidBlockSize(true); - } - - SetMemoryUsage(); - return true; - } - - case IDC_COMPRESS_ORDER: - return true; - - case IDC_COMPRESS_SOLID: - { - SetMemoryUsage(); - return true; - } - - case IDC_COMPRESS_THREADS: - { - SetMemoryUsage(); - return true; - } - } - } - return CModalDialog::OnCommand(code, itemID, lParam); -} - -void CCompressDialog::CheckSFXNameChange() -{ - 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 += '.'; - 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 = 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 += '.'; - fileName += ai.GetMainExt(); - } - 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 i; - } - return -1; -} - -int CCompressDialog::FindRegistryFormatAlways(const UString &name) -{ - int index = FindRegistryFormat(name); - if (index < 0) - { - NCompression::CFormatOptions fo; - fo.FormatID = GetSystemString(name); - index = m_RegistryInfo.Formats.Add(fo); - } - return index; -} - -int CCompressDialog::GetStaticFormatIndex() -{ - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - for (unsigned i = 0; i < 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::SetLevel() -{ - UInt32 level = GetLevel2(); - UInt32 LevelsMask; - UInt32 LevelsStart = 0; - UInt32 LevelsEnd = 22; - UInt32 langID = 0; - unsigned i, ir; - - if (GetMethodID() == kZSTD) - LevelsMask = g_Formats[6].LevelsMask; - else if (GetMethodID() == kBROTLI) - LevelsMask = g_Formats[7].LevelsMask; - else if (GetMethodID() == kLIZARD_M1) { - LevelsMask = g_Formats[8].LevelsMask; - LevelsStart = 10; - LevelsEnd = 19; - } else if (GetMethodID() == kLIZARD_M2) { - LevelsMask = g_Formats[8].LevelsMask; - LevelsStart = 20; - LevelsEnd = 29; - } else if (GetMethodID() == kLIZARD_M3) { - LevelsMask = g_Formats[8].LevelsMask; - LevelsStart = 30; - LevelsEnd = 39; - } else if (GetMethodID() == kLIZARD_M4) { - LevelsMask = g_Formats[8].LevelsMask; - LevelsStart = 40; - LevelsEnd = 49; - } else if (GetMethodID() == kLZ4) - LevelsMask = g_Formats[9].LevelsMask; - else if (GetMethodID() == kLZ5) - LevelsMask = g_Formats[10].LevelsMask; - else - LevelsMask = g_Formats[GetStaticFormatIndex()].LevelsMask; - - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - { - int index = FindRegistryFormat(ai.Name); - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - if (fo.Level <= 49) - level = fo.Level; - else - level = 5; - } - } - - m_Level.ResetContent(); - for (i = LevelsStart; i <= LevelsEnd; i++) - { - TCHAR s[40]; - TCHAR t[50] = { TEXT('L'), TEXT('e'), TEXT('v'), TEXT('e'), TEXT('l'), TEXT(' '), 0 }; - - // lizard needs extra handling - if (GetMethodID() >= kLIZARD_M1 && GetMethodID() <= kLIZARD_M4) { - ir = i; - if (ir % 10 == 0) langID = 0; - while (ir > 19) { ir -= 10; } - } else { - ir = i; - } - - // max reached - if (LevelsMask < (UInt32)(1 << ir)) - break; - - if ((LevelsMask & (1 << ir)) != 0) - { - ConvertUInt32ToString(i, s); - lstrcat(t, s); - lstrcat(t, TEXT(" (")); - lstrcat(t, LangString(g_Levels[langID])); - lstrcat(t, TEXT(")")); - int index = (int)m_Level.AddString(t); - m_Level.SetItemData(index, i); - langID++; - } else { - ConvertUInt32ToString(i, s); - lstrcat(t, s); - int index = (int)m_Level.AddString(t); - m_Level.SetItemData(index, i); - } - } - - // ShowInfo(L"SetLevel() methodID=%d level=%d start=%d end=%d", GetMethodID(), level, LevelsStart, LevelsEnd); - SetNearestSelectComboBox(m_Level, level); - - return; -} - -static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s) -{ - return cb.AddString((CSysString)s); -} - - -void CCompressDialog::SetMethod(int keepMethodId) -{ - UInt32 level = GetLevel2(); - int mID = GetMethodID(); - static int mID_old = 0; - - if (mID != mID_old) { - mID_old = mID; - SetLevel(); - } - - if (level == 0) - { - SetDictionary(); - SetOrder(); - return; - } - const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - int index = FindRegistryFormat(ai.Name); - UString defaultMethod; - int defaultLevel = 5; - if (index >= 0) { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - defaultMethod = fo.Method; - defaultLevel = fo.Level; - } - - bool isSfx = IsSFX(); - bool weUseSameMethod = false; - - m_Method.ResetContent(); - for (unsigned m = 0; m < fi.NumMethods; m++) - { - EMethodID methodID = fi.MathodIDs[m]; - if (isSfx) - if (!IsMethodSupportedBySfx(methodID)) - continue; - - const char *methodLong = kMethodsLongnames[methodID]; - const char *method = kMethodsNames[methodID]; - int itemIndex = (int)ComboBox_AddStringAscii(m_Method, methodLong); - m_Method.SetItemData(itemIndex, methodID); - - if (keepMethodId == methodID) { - weUseSameMethod = true; - m_Method.SetCurSel(itemIndex); - continue; - } - - // Lizard :/ - if (defaultMethod.IsEqualTo_Ascii_NoCase("lizard") && keepMethodId == -1) { - if (defaultLevel >= 10 && defaultLevel <= 19) m_Method.SetCurSel(kLIZARD_M1 - 1); - if (defaultLevel >= 20 && defaultLevel <= 29) m_Method.SetCurSel(kLIZARD_M2 - 1); - if (defaultLevel >= 30 && defaultLevel <= 39) m_Method.SetCurSel(kLIZARD_M3 - 1); - if (defaultLevel >= 40 && defaultLevel <= 49) m_Method.SetCurSel(kLIZARD_M4 - 1); - } - - if ((defaultMethod.IsEqualTo_Ascii_NoCase(method) || m == 0) && !weUseSameMethod) { - m_Method.SetCurSel(itemIndex); - } - } - - if (!weUseSameMethod) { - SetDictionary(); - SetOrder(); - } -} - -bool CCompressDialog::IsZipFormat() -{ - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - return ai.Name.IsEqualTo_Ascii_NoCase("zip"); -} - -bool CCompressDialog::IsXzFormat() -{ - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - return ai.Name.IsEqualTo_Ascii_NoCase("xz"); -} - -void CCompressDialog::SetEncryptionMethod() -{ - _encryptionMethod.ResetContent(); - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - if (ai.Name.IsEqualTo_Ascii_NoCase("7z")) - { - ComboBox_AddStringAscii(_encryptionMethod, "AES-256"); - _encryptionMethod.SetCurSel(0); - } - else if (ai.Name.IsEqualTo_Ascii_NoCase("zip")) - { - int index = FindRegistryFormat(ai.Name); - UString encryptionMethod; - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - encryptionMethod = fo.EncryptionMethod; - } - ComboBox_AddStringAscii(_encryptionMethod, "ZipCrypto"); - ComboBox_AddStringAscii(_encryptionMethod, "AES-256"); - _encryptionMethod.SetCurSel(encryptionMethod.IsPrefixedBy_Ascii_NoCase("aes") ? 1 : 0); - } -} - -int CCompressDialog::GetMethodID() -{ - if (m_Method.GetCount() <= 0) - return -1; - return (int)(UInt32)m_Method.GetItemData_of_CurSel(); -} - -UString CCompressDialog::GetMethodSpec() -{ - UString s; - if (m_Method.GetCount() > 1) - s = kMethodsNames[GetMethodID()]; - return s; -} - -UString CCompressDialog::GetEncryptionMethodSpec() -{ - UString s; - if (_encryptionMethod.GetCount() > 1 - && _encryptionMethod.GetCurSel() > 0) - { - _encryptionMethod.GetText(s); - s.RemoveChar(L'-'); - } - return s; -} - -void CCompressDialog::AddDictionarySize(UInt32 size) -{ - Byte c = 0; - unsigned moveBits = 0; - if ((size & 0xFFFFF) == 0) { moveBits = 20; c = 'M'; } - else if ((size & 0x3FF) == 0) { moveBits = 10; c = 'K'; } - TCHAR s[40]; - ConvertUInt32ToString(size >> moveBits, s); - unsigned pos = MyStringLen(s); - s[pos++] = ' '; - if (moveBits != 0) - s[pos++] = c; - s[pos++] = 'B'; - s[pos++] = 0; - int index = (int)m_Dictionary.AddString(s); - m_Dictionary.SetItemData(index, size); -} - -typedef enum { - FL2_fast, - FL2_opt, - FL2_ultra -} FL2_strategy; - -typedef struct { - UInt32 dictionarySize; /* largest match distance : larger == more compression, more memory needed during decompression; > 64Mb == more memory per byte, slower */ - unsigned overlapFraction; /* overlap between consecutive blocks in 1/16 units: larger == more compression, slower */ - unsigned chainLog; /* HC3 sliding window : larger == more compression, slower; hybrid mode only (ultra) */ - unsigned cyclesLog; /* nb of searches : larger == more compression, slower; hybrid mode only (ultra) */ - unsigned searchDepth; /* maximum depth for resolving string matches : larger == more compression, slower */ - unsigned fastLength; /* acceptable match size for parser : larger == more compression, slower; fast bytes parameter from 7-Zip */ - unsigned divideAndConquer; /* split long chains of 2-byte matches into shorter chains with a small overlap : faster, somewhat less compression; enabled by default */ - FL2_strategy strategy; /* encoder strategy : fast, optimized or ultra (hybrid) */ -} FL2_compressionParameters; - -#define FL2_MAX_7Z_CLEVEL 9 -#define MATCH_BUFFER_SHIFT 8; -#define MATCH_BUFFER_ELBOW_BITS 17 -#define MATCH_BUFFER_ELBOW (1UL << MATCH_BUFFER_ELBOW_BITS) - -#define MB *(1U<<20) - -static const FL2_compressionParameters FL2_7zCParameters[FL2_MAX_7Z_CLEVEL + 1] = { - { 0,0,0,0,0,0,0,FL2_fast }, - { 1 MB, 1, 7, 0, 6, 32, 1, FL2_fast }, /* 1 */ - { 2 MB, 2, 7, 0, 10, 32, 1, FL2_fast }, /* 2 */ - { 2 MB, 2, 7, 0, 10, 32, 1, FL2_opt }, /* 3 */ - { 4 MB, 2, 7, 0, 14, 32, 1, FL2_opt }, /* 4 */ - { 16 MB, 2, 9, 0, 42, 48, 1, FL2_ultra }, /* 5 */ - { 32 MB, 2, 10, 0, 50, 64, 1, FL2_ultra }, /* 6 */ - { 64 MB, 2, 11, 1, 62, 96, 1, FL2_ultra }, /* 7 */ - { 64 MB, 4, 12, 2, 90, 273, 1, FL2_ultra }, /* 8 */ - { 128 MB, 2, 14, 3, 254, 273, 0, FL2_ultra } /* 9 */ -}; - -#undef MB - -#define RMF_BUILDER_SIZE (8 * 0x40100U) - -void CCompressDialog::SetDictionary() -{ - m_Dictionary.ResetContent(); - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - int index = FindRegistryFormat(ai.Name); - UInt32 defaultDict = (UInt32)(Int32)-1; - - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - if (fo.Method.IsEqualTo_NoCase(GetMethodSpec())) - defaultDict = fo.Dictionary; - } - - int methodID = GetMethodID(); - UInt32 level = GetLevel2(); - if (methodID < 0) - return; - UInt64 maxRamSize; - bool maxRamSize_Defined = GetMaxRamSizeForProgram(maxRamSize); - - switch (methodID) - { - case kLZMA: - case kLZMA2: - { - static const UInt32 kMinDicSize = (1 << 16); - if (defaultDict == (UInt32)(Int32)-1) - { - if (level >= 9) defaultDict = (1 << 26); - else if (level >= 7) defaultDict = (1 << 25); - else if (level >= 5) defaultDict = (1 << 24); - else if (level >= 3) defaultDict = (1 << 20); - else defaultDict = (kMinDicSize); - } - - AddDictionarySize(kMinDicSize); - m_Dictionary.SetCurSel(0); - - for (unsigned i = 20; i <= 31; i++) - for (unsigned j = 0; j < 2; j++) - { - if (i == 20 && j > 0) - continue; - UInt32 dict = ((UInt32)(2 + j) << (i - 1)); - - if (dict > - #ifdef MY_CPU_64BIT - (3 << 29) - #else - (1 << 26) - #endif - ) - continue; - - AddDictionarySize(dict); - UInt64 decomprSize; - UInt64 requiredComprSize = GetMemoryUsage(dict, decomprSize); - if (dict <= defaultDict && (!maxRamSize_Defined || requiredComprSize <= maxRamSize)) - m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1); - } - - // SetNearestSelectComboBox(m_Dictionary, defaultDict); - break; - } - - case kFLZMA2: - { - static const UInt32 kMinDicSize = (1 << 20); - level += !level; - if (level > FL2_MAX_7Z_CLEVEL) - level = FL2_MAX_7Z_CLEVEL; - if (defaultDict == (UInt32)(Int32)-1) - defaultDict = FL2_7zCParameters[level].dictionarySize; - - m_Dictionary.SetCurSel(0); - - for (unsigned i = 20; i <= 31; i++) { - UInt32 dict = (UInt32)1 << i; - - if (dict > - #ifdef MY_CPU_64BIT - (1 << 30) - #else - (1 << 27) - #endif - ) - continue; - - AddDictionarySize(dict); - UInt64 decomprSize; - UInt64 requiredComprSize = GetMemoryUsage(dict, decomprSize); - if (dict <= defaultDict && (!maxRamSize_Defined || requiredComprSize <= maxRamSize)) - m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1); - } - - break; - } - - case kPPMd: - { - if (defaultDict == (UInt32)(Int32)-1) - { - if (level >= 9) defaultDict = (192 << 20); - else if (level >= 7) defaultDict = ( 64 << 20); - else if (level >= 5) defaultDict = ( 16 << 20); - else defaultDict = ( 4 << 20); - } - - for (unsigned i = 20; i < 31; i++) - for (unsigned j = 0; j < 2; j++) - { - if (i == 20 && j > 0) - continue; - UInt32 dict = ((UInt32)(2 + j) << (i - 1)); - if (dict > - #ifdef MY_CPU_64BIT - (1 << 30) - #else - (1 << 29) - #endif - ) - continue; - AddDictionarySize(dict); - UInt64 decomprSize; - UInt64 requiredComprSize = GetMemoryUsage(dict, decomprSize); - if ((dict <= defaultDict && (!maxRamSize_Defined || requiredComprSize <= maxRamSize)) - || m_Dictionary.GetCount() == 1) - m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1); - } - - // SetNearestSelectComboBox(m_Dictionary, defaultDict); - break; - } - - case kDeflate: - { - AddDictionarySize(32 << 10); - m_Dictionary.SetCurSel(0); - break; - } - - case kDeflate64: - { - AddDictionarySize(64 << 10); - m_Dictionary.SetCurSel(0); - break; - } - - case kBZip2: - { - if (defaultDict == (UInt32)(Int32)-1) - { - if (level >= 5) defaultDict = (900 << 10); - else if (level >= 3) defaultDict = (500 << 10); - else defaultDict = (100 << 10); - } - - for (unsigned i = 1; i <= 9; i++) - { - UInt32 dict = ((UInt32)i * 100) << 10; - AddDictionarySize(dict); - if (dict <= defaultDict || m_Dictionary.GetCount() == 0) - m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1); - } - - break; - } - - case kPPMdZip: - { - if (defaultDict == (UInt32)(Int32)-1) - defaultDict = (1 << (19 + (level > 8 ? 8 : level))); - - for (unsigned i = 20; i <= 28; i++) - { - UInt32 dict = (1 << i); - AddDictionarySize(dict); - UInt64 decomprSize; - UInt64 requiredComprSize = GetMemoryUsage(dict, decomprSize); - if ((dict <= defaultDict && (!maxRamSize_Defined || requiredComprSize <= maxRamSize)) - || m_Dictionary.GetCount() == 1) - m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1); - } - - // SetNearestSelectComboBox(m_Dictionary, defaultDict); - break; - } - - } -} - -UInt32 CCompressDialog::GetComboValue(NWindows::NControl::CComboBox &c, int defMax) -{ - if (c.GetCount() <= defMax) - return (UInt32)(Int32)-1; - return (UInt32)c.GetItemData_of_CurSel(); -} - -UInt32 CCompressDialog::GetLevel2() -{ - UInt32 level = GetLevel(); - if (level == (UInt32)(Int32)-1) - level = 5; - return level; -} - -int CCompressDialog::AddOrder(UInt32 size) -{ - TCHAR s[40]; - ConvertUInt32ToString(size, s); - int index = (int)m_Order.AddString(s); - m_Order.SetItemData(index, size); - return index; -} - -void CCompressDialog::SetOrder() -{ - m_Order.ResetContent(); - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - int index = FindRegistryFormat(ai.Name); - UInt32 defaultOrder = (UInt32)(Int32)-1; - - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - if (fo.Method.IsEqualTo_NoCase(GetMethodSpec())) - defaultOrder = fo.Order; - } - - int methodID = GetMethodID(); - UInt32 level = GetLevel2(); - if (methodID < 0) - return; - - switch (methodID) - { - case kLZMA: - case kLZMA2: - case kFLZMA2: - { - if (defaultOrder == (UInt32)(Int32)-1) { - if (methodID == kFLZMA2) - defaultOrder = FL2_7zCParameters[level].fastLength; - else - defaultOrder = (level >= 7) ? 64 : 32; - } - for (unsigned i = 3; i <= 8; i++) - for (unsigned j = 0; j < 2; j++) - { - UInt32 order = ((UInt32)(2 + j) << (i - 1)); - if (order <= 256) - AddOrder(order); - } - AddOrder(273); - SetNearestSelectComboBox(m_Order, defaultOrder); - break; - } - - case kPPMd: - { - if (defaultOrder == (UInt32)(Int32)-1) - { - if (level >= 9) defaultOrder = 32; - else if (level >= 7) defaultOrder = 16; - else if (level >= 5) defaultOrder = 6; - else defaultOrder = 4; - } - - AddOrder(2); - AddOrder(3); - - for (unsigned i = 2; i < 8; i++) - for (unsigned j = 0; j < 4; j++) - { - UInt32 order = (4 + j) << (i - 2); - if (order < 32) - AddOrder(order); - } - - AddOrder(32); - SetNearestSelectComboBox(m_Order, defaultOrder); - break; - } - - case kDeflate: - case kDeflate64: - { - if (defaultOrder == (UInt32)(Int32)-1) - { - if (level >= 9) defaultOrder = 128; - else if (level >= 7) defaultOrder = 64; - else defaultOrder = 32; - } - - for (unsigned i = 3; i <= 8; i++) - for (unsigned j = 0; j < 2; j++) - { - UInt32 order = ((UInt32)(2 + j) << (i - 1));; - if (order <= 256) - AddOrder(order); - } - - AddOrder(methodID == kDeflate64 ? 257 : 258); - SetNearestSelectComboBox(m_Order, defaultOrder); - break; - } - - case kBZip2: - break; - - case kPPMdZip: - { - if (defaultOrder == (UInt32)(Int32)-1) - defaultOrder = level + 3; - for (unsigned i = 2; i <= 16; i++) - AddOrder(i); - SetNearestSelectComboBox(m_Order, defaultOrder); - break; - } - } -} - -bool CCompressDialog::GetOrderMode() -{ - switch (GetMethodID()) - { - case kPPMd: - case kPPMdZip: - return true; - } - return false; -} - - -void CCompressDialog::SetSolidBlockSize(bool useDictionary) -{ - m_Solid.ResetContent(); - const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - if (!fi.Solid) - return; - - UInt32 level = GetLevel2(); - if (level == 0) - return; - - UInt32 dict = GetDictionarySpec(); - if (dict == (UInt32)(Int32)-1) - dict = 1; - - UInt32 defaultBlockSize = (UInt32)(Int32)-1; - - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - - if (useDictionary) - defaultBlockSize = GetBlockSizeSpec(); - else - { - int index = FindRegistryFormat(ai.Name); - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - if (fo.Method.IsEqualTo_NoCase(GetMethodSpec())) - defaultBlockSize = fo.BlockLogSize; - } - } - - bool is7z = ai.Name.IsEqualTo_Ascii_NoCase("7z"); - - { - UString s ('-'); - if (is7z) - LangString(IDS_COMPRESS_NON_SOLID, s); - int index = (int)m_Solid.AddString(s); - m_Solid.SetItemData(index, (UInt32)kNoSolidBlockSize); - if (defaultBlockSize == kNoSolidBlockSize) - m_Solid.SetCurSel(0); - } - - UInt64 blockSize; - - if (is7z) - { - blockSize = (UInt64)dict << 7; - const UInt32 kMinSize = (UInt32)1 << 24; - const UInt64 kMaxSize = (UInt64)1 << 32; - if (blockSize < kMinSize) blockSize = kMinSize; - if (blockSize > kMaxSize) blockSize = kMaxSize; - } - else - { - blockSize = (UInt64)dict << 2; - const UInt32 kMinSize = (UInt32)1 << 20; - const UInt32 kMaxSize = (UInt32)1 << 28; - if (blockSize < kMinSize) blockSize = kMinSize; - if (blockSize > kMaxSize) blockSize = kMaxSize; - if (blockSize < dict) blockSize = dict; - } - - for (unsigned i = 20; i <= 36; i++) - { - if (defaultBlockSize == (UInt32)(Int32)-1 && ((UInt64)1 << i) >= blockSize) - defaultBlockSize = i; - - TCHAR s[40]; - char post; - ConvertUInt32ToString(1 << (i % 10), s); - if (i < 20) post = 'K'; - else if (i < 30) post = 'M'; - else post = 'G'; - unsigned pos = (unsigned)lstrlen(s); - s[pos++] = ' '; - s[pos++] = post; - s[pos++] = 'B'; - s[pos] = 0; - int index = (int)m_Solid.AddString(s); - m_Solid.SetItemData(index, (UInt32)i); - } - - { - int index = (int)m_Solid.AddString(LangString(IDS_COMPRESS_SOLID)); - m_Solid.SetItemData(index, kSolidBlockSize); - } - - if (defaultBlockSize == (UInt32)(Int32)-1) - defaultBlockSize = kSolidBlockSize; - if (defaultBlockSize != kNoSolidBlockSize) - SetNearestSelectComboBox(m_Solid, defaultBlockSize); -} - -void CCompressDialog::SetNumThreads() -{ - m_NumThreads.ResetContent(); - - const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - if (!fi.MultiThread) - return; - - UInt32 numHardwareThreads = NSystem::GetNumberOfProcessors(); - UInt32 defaultValue = numHardwareThreads; - - { - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - int index = FindRegistryFormat(ai.Name); - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - if (fo.Method.IsEqualTo_NoCase(GetMethodSpec()) && fo.NumThreads != (UInt32)(Int32)-1) - defaultValue = fo.NumThreads; - } - } - - UInt32 numAlgoThreadsMax = 1; - int methodID = GetMethodID(); - switch (methodID) - { - case kZSTD: numAlgoThreadsMax = 128; break; - case kBROTLI: numAlgoThreadsMax = 128; break; - case kLZ4: numAlgoThreadsMax = 128; break; - case kLZ5: numAlgoThreadsMax = 128; break; - case kLIZARD_M1: numAlgoThreadsMax = 128; break; - case kLIZARD_M2: numAlgoThreadsMax = 128; break; - case kLIZARD_M3: numAlgoThreadsMax = 128; break; - case kLIZARD_M4: numAlgoThreadsMax = 128; break; - case kLZMA: numAlgoThreadsMax = 2; break; - case kLZMA2: numAlgoThreadsMax = 32; break; - case kFLZMA2: numAlgoThreadsMax = 128; break; - case kBZip2: numAlgoThreadsMax = 32; break; - } - if (IsZipFormat()) - numAlgoThreadsMax = 128; - for (UInt32 i = 1; i <= numHardwareThreads * 2 && i <= numAlgoThreadsMax; i++) - { - TCHAR s[40]; - ConvertUInt32ToString(i, s); - int index = (int)m_NumThreads.AddString(s); - m_NumThreads.SetItemData(index, (UInt32)i); - } - SetNearestSelectComboBox(m_NumThreads, defaultValue); -} - -UInt64 CCompressDialog::GetMemoryUsage(UInt32 dict, UInt64 &decompressMemory) -{ - decompressMemory = UInt64(Int64(-1)); - UInt32 level = GetLevel2(); - if (level == 0) - { - 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(); - - if (IsZipFormat()) - { - UInt32 numSubThreads = 1; - if (GetMethodID() == kLZMA && numThreads > 1 && level >= 5) - numSubThreads = 2; - UInt32 numMainThreads = numThreads / numSubThreads; - if (numMainThreads > 1) - size += (UInt64)numMainThreads << 25; - } - - int methidId = GetMethodID(); - - switch (methidId) - { - case kLZMA: - case kLZMA2: - { - UInt32 hs = 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++; - 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; - - if (methidId != kLZMA && numBlockThreads != 1) - { - chunkSize = (UInt64)dict << 2; - chunkSize = MyMax(chunkSize, (UInt64)(1 << 20)); - chunkSize = MyMin(chunkSize, (UInt64)(1 << 28)); - chunkSize = MyMax(chunkSize, (UInt64)dict); - - if (IsXzFormat()) - { - UInt32 blockSizeLog = GetBlockSizeSpec(); - if (blockSizeLog != (UInt32)(Int32)-1) - { - if (blockSizeLog == kSolidBlockSize) - { - numBlockThreads = 1; - chunkSize = 0; - } - else if (blockSizeLog != kNoSolidBlockSize) - chunkSize = (UInt64)1 << blockSizeLog; - } - } - } - - if (chunkSize == 0) - size += numBlockThreads * (size1 + (UInt64)dict * 3 / 2); - else - { - size += numBlockThreads * (size1 + chunkSize); - UInt64 numPackChunks = numBlockThreads + (numBlockThreads / 4) + 2; - size += numPackChunks * chunkSize; - } - - decompressMemory = dict + (2 << 20); - return size; - } - - case kFLZMA2: - { - if (level > FL2_MAX_7Z_CLEVEL) - level = FL2_MAX_7Z_CLEVEL; - /* dual buffer is enabled in Lzma2Encoder.cpp so size is dict * 6 */ - size += dict * 6 + (1UL << 18) * numThreads; - UInt32 bufSize = dict >> MATCH_BUFFER_SHIFT; - if (bufSize > MATCH_BUFFER_ELBOW) { - UInt32 extra = 0; - unsigned n = MATCH_BUFFER_ELBOW_BITS - 1; - for (; (4UL << n) <= bufSize; ++n) - extra += MATCH_BUFFER_ELBOW >> 4; - if ((3UL << n) <= bufSize) - extra += MATCH_BUFFER_ELBOW >> 5; - bufSize = MATCH_BUFFER_ELBOW + extra; - } - size += (bufSize * 12 + RMF_BUILDER_SIZE) * numThreads; - if (dict > (UInt32(1) << 26)) - size += dict; - if (FL2_7zCParameters[level].strategy == FL2_ultra) - size += (UInt32(4) << 14) + (UInt32(4) << FL2_7zCParameters[level].chainLog); - decompressMemory = dict + (2 << 20); - return size; - } - - case kPPMd: - { - decompressMemory = dict + (2 << 20); - return size + decompressMemory; - } - - case kDeflate: - case kDeflate64: - { - /* - UInt32 order = GetOrder(); - if (order == (UInt32)(Int32)-1) - order = 32; - */ - if (level >= 7) - size += (1 << 20); - size += 3 << 20; - decompressMemory = (2 << 20); - return size; - } - - case kBZip2: - { - decompressMemory = (7 << 20); - UInt64 memForOneThread = (10 << 20); - return size + memForOneThread * numThreads; - } - - case kPPMdZip: - { - decompressMemory = dict + (2 << 20); - return size + (UInt64)decompressMemory * numThreads; - } - } - - return (UInt64)(Int64)-1; -} - -UInt64 CCompressDialog::GetMemoryUsage(UInt64 &decompressMemory) -{ - return GetMemoryUsage(GetDictionary(), decompressMemory); -} - -void CCompressDialog::PrintMemUsage(UINT res, UInt64 value) -{ - if (value == (UInt64)(Int64)-1) - { - SetItemText(res, TEXT("?")); - return; - } - value = (value + (1 << 20) - 1) >> 20; - TCHAR s[40]; - ConvertUInt64ToString(value, s); - lstrcat(s, TEXT(" MB")); - SetItemText(res, s); -} - -void CCompressDialog::SetMemoryUsage() -{ - UInt64 decompressMem; - UInt64 memUsage = GetMemoryUsage(decompressMem); - PrintMemUsage(IDT_COMPRESS_MEMORY_VALUE, memUsage); - PrintMemUsage(IDT_COMPRESS_MEMORY_DE_VALUE, decompressMem); -} - -void CCompressDialog::SetParams() -{ - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - m_Params.SetText(TEXT("")); - int index = FindRegistryFormat(ai.Name); - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - m_Params.SetText(fo.Options); - m_Volume.SetText(fo.SplitVolume); - } -} - -void CCompressDialog::SaveOptionsInMem() -{ - const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex]; - int index = FindRegistryFormatAlways(ai.Name); - m_Params.GetText(Info.Options); - m_Volume.GetText(Info.SplitVolume); - Info.Options.Trim(); - Info.SplitVolume.Trim(); - NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - fo.Options = Info.Options; - fo.SplitVolume = Info.SplitVolume; - fo.Level = GetLevelSpec(); - fo.Dictionary = GetDictionarySpec(); - fo.Order = GetOrderSpec(); - fo.Method = GetMethodSpec(); - fo.EncryptionMethod = GetEncryptionMethodSpec(); - fo.NumThreads = GetNumThreadsSpec(); - fo.BlockLogSize = GetBlockSizeSpec(); -} - -unsigned CCompressDialog::GetFormatIndex() -{ - return (unsigned)m_Format.GetItemData_of_CurSel(); -} +// 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 "../FileManager/BrowseDialog.h" +#include "../FileManager/FormatUtils.h" +#include "../FileManager/HelpUtils.h" +#include "../FileManager/SplitUtils.h" + +#include "../Explorer/MyMessages.h" + +#include "../Common/ZipRegistry.h" + +#include "CompressDialog.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +#ifdef LANG +#include "../FileManager/LangUtils.h" +#endif + +#include "CompressDialogRes.h" +#include "ExtractRes.h" + +#ifdef LANG +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, + + IDG_COMPRESS_OPTIONS, + IDX_COMPRESS_SFX, + IDX_COMPRESS_SHARED, + IDX_COMPRESS_DEL, + + IDT_COMPRESS_MEMORY, + IDT_COMPRESS_MEMORY_DE, + + IDX_COMPRESS_NT_SYM_LINKS, + IDX_COMPRESS_NT_HARD_LINKS, + IDX_COMPRESS_NT_ALT_STREAMS, + IDX_COMPRESS_NT_SECUR, + + 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 kNoSolidBlockSize = 0; +static const UInt32 kSolidBlockSize = 64; + +static LPCSTR const kExeExt = ".exe"; + +#define k7zFormat "7z" + +static const UInt32 g_Levels[] = +{ + IDS_METHOD_STORE, + IDS_METHOD_FASTEST, + IDS_METHOD_FAST, + IDS_METHOD_NORMAL, + IDS_METHOD_MAXIMUM, + IDS_METHOD_ULTRA +}; + +enum EMethodID +{ + kCopy, + kZSTD, + kBROTLI, + kLZ4, + kLZ5, + kLIZARD_M1, + kLIZARD_M2, + kLIZARD_M3, + kLIZARD_M4, + kLZMA, + kLZMA2, + kFLZMA2, + kPPMd, + kBZip2, + kDeflate, + kDeflate64, + kPPMdZip +}; + +static LPCSTR const kMethodsLongnames[] = +{ + "Copy [std]" + , "Zstandard" + , "Brotli" + , "LZ4" + , "LZ5" + , "Lizard, FastLZ4" + , "Lizard, LIZv1" + , "Lizard, FastLZ4 + Huffman" + , "Lizard, LIZv1 + Huffman" + , "LZMA [std]" + , "LZMA2 [std]" + , "LZMA2, Fast [std]" + , "PPMd [std]" + , "BZip2 [std]" + , "Deflate [std]" + , "Deflate64 [std]" + , "PPMd [std]" +}; + +static LPCSTR const kMethodsNames[] = +{ + "Copy" + , "zstd" + , "Brotli" + , "LZ4" + , "LZ5" + , "Lizard" + , "Lizard" + , "Lizard" + , "Lizard" + , "LZMA" + , "LZMA2" + , "FLZMA2" + , "PPMd" + , "BZip2" + , "Deflate" + , "Deflate64" + , "PPMd" +}; + +static const EMethodID g_ZstdMethods[] = +{ + kZSTD +}; + +static const EMethodID g_BrotliMethods[] = +{ + kBROTLI +}; + +static const EMethodID g_LizardMethods[] = +{ + kLIZARD_M1, + kLIZARD_M2, + kLIZARD_M3, + kLIZARD_M4 +}; + +static const EMethodID g_Lz4Methods[] = +{ + kLZ4 +}; + +static const EMethodID g_Lz5Methods[] = +{ + kLZ5 +}; + +static const EMethodID g_7zMethods[] = +{ + kZSTD, + kBROTLI, + kLZ4, + kLZ5, + kLIZARD_M1, + kLIZARD_M2, + kLIZARD_M3, + kLIZARD_M4, + kFLZMA2, + kLZMA2, + kLZMA, + kPPMd, + kDeflate, + kDeflate64, + kBZip2 +}; + +static const EMethodID g_7zSfxMethods[] = +{ + kCopy, + kZSTD, + kLZMA, + kLZMA2, + kFLZMA2, + kPPMd +}; + +static const EMethodID g_ZipMethods[] = +{ + kDeflate, + kDeflate64, + kBZip2, + kLZMA, + kPPMdZip +}; + +static const EMethodID g_GZipMethods[] = +{ + kDeflate +}; + +static const EMethodID g_BZip2Methods[] = +{ + kBZip2 +}; + +static const EMethodID g_XzMethods[] = +{ + kLZMA2 +}; + +static const EMethodID g_SwfcMethods[] = +{ + kDeflate + // kLZMA +}; + +struct CFormatInfo +{ + LPCSTR Name; + UInt32 LevelsMask; + unsigned NumMethods; + const EMethodID *MathodIDs; + bool Filter; + bool Solid; + bool MultiThread; + bool SFX; + + bool Encrypt; + bool EncryptFileNames; +}; + +#if 0 +void ShowInfo(LPCWSTR str, ...) +{ + wchar_t buf[4000]; + va_list args; + va_start(args, str); + wvsprintf(buf, str, args); + va_end(args); + ShowErrorMessage(NULL, buf); +} +#endif + +#define METHODS_PAIR(x) ARRAY_SIZE(x), x + +static const CFormatInfo g_Formats[] = +{ + { + "", /* 0 */ + (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), + 0, 0, + false, false, false, false, false, false + }, + { + k7zFormat, /* 1 */ + (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), + METHODS_PAIR(g_7zMethods), + true, true, true, true, true, true + }, + { + "Zip", /* 2 */ + (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), + METHODS_PAIR(g_ZipMethods), + false, false, true, false, true, false + }, + { + "GZip", /* 3 */ + (1 << 1) | (1 << 5) | (1 << 7) | (1 << 9), + METHODS_PAIR(g_GZipMethods), + false, false, false, false, false, false + }, + { + "BZip2", /* 4 */ + (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), + METHODS_PAIR(g_BZip2Methods), + false, false, true, false, false, false + }, + { + "xz", /* 5 */ + (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), + METHODS_PAIR(g_XzMethods), + false, true, true, false, false, false + }, + { + "zstd", /* 6 */ + (1 << 0) | (1 << 1) | (1 << 5) | (1 << 11) | (1 << 17) | (1 << 22), + METHODS_PAIR(g_ZstdMethods), + false, false, true, false, false, false + }, + { + "Brotli", /* 7 */ + (1 << 0) | (1 << 1) | (1 << 3) | (1 << 6) | (1 << 9) | (1 << 11), + METHODS_PAIR(g_BrotliMethods), + false, false, true, false, false, false + }, + { + "Lizard", /* 8 */ + (1 << 10) | (1 << 11) | (1 << 13) | (1 << 15) | (1 << 17) | (1 << 19), + METHODS_PAIR(g_LizardMethods), + false, false, true, false, false, false + }, + { + "LZ4", /* 9 */ + (1 << 0) | (1 << 1) | (1 << 3) | (1 << 6) | (1 << 9) | (1 << 12), + METHODS_PAIR(g_Lz4Methods), + false, false, true, false, false, false + }, + { + "LZ5", /* 10 */ + (1 << 0) | (1 << 1) | (1 << 3) | (1 << 7) | (1 << 11) | (1 << 15), + METHODS_PAIR(g_Lz5Methods), + false, false, true, false, false, false + }, + { + "Swfc", /* 11 */ + (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), + METHODS_PAIR(g_SwfcMethods), + false, false, true, false, false, false + }, + { + "Tar", /* 12 */ + (1 << 0), + 0, 0, + false, false, false, false, false, false + }, + { + "wim", /* 13 */ + (1 << 0), + 0, 0, + false, false, false, false, false, false + } +}; + +static bool IsMethodSupportedBySfx(int methodID) +{ + for (int i = 0; i < ARRAY_SIZE(g_7zSfxMethods); i++) + if (methodID == g_7zSfxMethods[i]) + return true; + return false; +} + +static bool GetMaxRamSizeForProgram(UInt64 &physSize) +{ + physSize = (UInt64)(sizeof(size_t)) << 29; + bool ramSize_Defined = NSystem::GetRamSize(physSize); + const UInt64 kMinSysSize = (1 << 24); + if (physSize <= kMinSysSize) + physSize = 0; + else + physSize -= kMinSysSize; + const UInt64 kMinUseSize = (1 << 24); + if (physSize < kMinUseSize) + physSize = kMinUseSize; + return ramSize_Defined; +} + + +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); +bool GetBoolsVal(const CBoolPair &b1, const CBoolPair &b2); + +void CCompressDialog::CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2) +{ + CheckButton(id, GetBoolsVal(b1, b2)); +} + +void CCompressDialog::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; +} + + +bool CCompressDialog::OnInit() +{ + #ifdef LANG + LangSetWindowText(*this, IDD_COMPRESS); + LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); + #endif + + _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)); + + m_ArchivePath.Attach(GetItem(IDC_COMPRESS_ARCHIVE)); + m_Format.Attach(GetItem(IDC_COMPRESS_FORMAT)); + m_Method.Attach(GetItem(IDC_COMPRESS_METHOD)); + m_Level.Attach(GetItem(IDC_COMPRESS_LEVEL)); + m_Dictionary.Attach(GetItem(IDC_COMPRESS_DICTIONARY)); + + m_Order.Attach(GetItem(IDC_COMPRESS_ORDER)); + m_Solid.Attach(GetItem(IDC_COMPRESS_SOLID)); + m_NumThreads.Attach(GetItem(IDC_COMPRESS_THREADS)); + + 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); + + CheckButton_TwoBools(IDX_COMPRESS_NT_SYM_LINKS, Info.SymLinks, m_RegistryInfo.SymLinks); + CheckButton_TwoBools(IDX_COMPRESS_NT_HARD_LINKS, Info.HardLinks, m_RegistryInfo.HardLinks); + CheckButton_TwoBools(IDX_COMPRESS_NT_ALT_STREAMS, Info.AltStreams, m_RegistryInfo.AltStreams); + CheckButton_TwoBools(IDX_COMPRESS_NT_SECUR, Info.NtSecurity, m_RegistryInfo.NtSecurity); + + UpdatePasswordControl(); + + { + bool needSetMain = (Info.FormatIndex < 0); + FOR_VECTOR(i, ArcIndices) + { + unsigned arcIndex = ArcIndices[i]; + const CArcInfoEx &ai = (*ArcFormats)[arcIndex]; + int index = (int)m_Format.AddString(ai.Name); + m_Format.SetItemData(index, 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 = arcIndex; + } + } + } + + CheckButton(IDX_COMPRESS_SFX, Info.SFXMode); + + { + UString fileName; + SetArcPathFields(Info.ArcPath, fileName, true); + StartDirPrefix = DirPrefix; + SetArchiveName(fileName); + } + + SetMethod(); + SetLevel(); + SetParams(); + + 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, ARRAY_SIZE(k_UpdateMode_IDs), + k_UpdateMode_Vals, Info.UpdateMode); + + AddComboItems(m_PathMode, k_PathMode_IDs, ARRAY_SIZE(k_PathMode_IDs), + k_PathMode_Vals, Info.PathMode); + + SetSolidBlockSize(); + SetNumThreads(); + + TCHAR s[40] = { 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); + + CheckControlsEnable(); + + SetEncryptionMethod(); + SetMemoryUsage(); + + NormalizePosition(); + + return CModalDialog::OnInit(); +} + +void CCompressDialog::UpdatePasswordControl() +{ + bool showPassword = IsShowPasswordChecked(); + TCHAR c = showPassword ? (TCHAR)0: TEXT('*'); + _password1Control.SetPasswordChar(c); + _password2Control.SetPasswordChar(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(int 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; + } + } + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); +} + +void CCompressDialog::CheckSFXControlsEnable() +{ + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; + bool enable = fi.SFX; + if (enable) + { + int methodID = GetMethodID(); + enable = (methodID == -1 || IsMethodSupportedBySfx(methodID)); + } + if (!enable) + CheckButton(IDX_COMPRESS_SFX, false); + EnableItem(IDX_COMPRESS_SFX, enable); +} + +void CCompressDialog::CheckControlsEnable() +{ + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; + Info.SolidIsSpecified = fi.Solid; + bool multiThreadEnable = fi.MultiThread; + Info.MultiThreadIsAllowed = multiThreadEnable; + Info.EncryptHeadersIsAllowed = fi.EncryptFileNames; + + EnableItem(IDC_COMPRESS_SOLID, fi.Solid); + EnableItem(IDC_COMPRESS_THREADS, multiThreadEnable); + + CheckSFXControlsEnable(); + + { + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + + ShowItem_Bool(IDX_COMPRESS_NT_SYM_LINKS, ai.Flags_SymLinks()); + ShowItem_Bool(IDX_COMPRESS_NT_HARD_LINKS, ai.Flags_HardLinks()); + ShowItem_Bool(IDX_COMPRESS_NT_ALT_STREAMS, ai.Flags_AltStreams()); + ShowItem_Bool(IDX_COMPRESS_NT_SECUR, ai.Flags_NtSecure()); + + ShowItem_Bool(IDG_COMPRESS_NTFS, + ai.Flags_SymLinks() + || ai.Flags_HardLinks() + || ai.Flags_AltStreams() + || ai.Flags_NtSecure()); + } + + EnableItem(IDG_COMPRESS_ENCRYPTION, fi.Encrypt); + + EnableItem(IDT_PASSWORD_ENTER, fi.Encrypt); + EnableItem(IDT_PASSWORD_REENTER, fi.Encrypt); + EnableItem(IDE_COMPRESS_PASSWORD1, fi.Encrypt); + EnableItem(IDE_COMPRESS_PASSWORD2, fi.Encrypt); + EnableItem(IDX_PASSWORD_SHOW, fi.Encrypt); + + EnableItem(IDT_COMPRESS_ENCRYPTION_METHOD, fi.Encrypt); + EnableItem(IDC_COMPRESS_ENCRYPTION_METHOD, fi.Encrypt); + EnableItem(IDX_COMPRESS_ENCRYPT_FILE_NAMES, fi.EncryptFileNames); + + ShowItem_Bool(IDX_COMPRESS_ENCRYPT_FILE_NAMES, fi.EncryptFileNames); +} + +bool CCompressDialog::IsSFX() +{ + CWindow sfxButton = GetItem(IDX_COMPRESS_SFX); + return sfxButton.IsEnabled() && IsButtonCheckedBool(IDX_COMPRESS_SFX); +} + +static int GetExtDotPos(const UString &s) +{ + int dotPos = s.ReverseFind_Dot(); + if (dotPos > s.ReverseFind_PathSepar() + 1) + return dotPos; + return -1; +} + +void CCompressDialog::OnButtonSFX() +{ + UString fileName; + m_ArchivePath.GetText(fileName); + int dotPos = GetExtDotPos(fileName); + if (IsSFX()) + { + if (dotPos >= 0) + fileName.DeleteFrom(dotPos); + fileName += kExeExt; + m_ArchivePath.SetText(fileName); + } + else + { + if (dotPos >= 0) + { + UString ext = fileName.Ptr(dotPos); + if (ext.IsEqualTo_Ascii_NoCase(kExeExt)) + { + fileName.DeleteFrom(dotPos); + m_ArchivePath.SetText(fileName); + } + } + SetArchiveName2(false); // it's for OnInit + } +} + +bool CCompressDialog::GetFinalPath_Smart(UString &resPath) +{ + UString name; + m_ArchivePath.GetText(name); + name.Trim(); + UString tempPath = name; + if (!IsAbsolutePath(name)) + { + UString newDirPrefix = DirPrefix; + if (newDirPrefix.IsEmpty()) + newDirPrefix = StartDirPrefix; + FString resultF; + if (!MyGetFullPathName(us2fs(newDirPrefix + name), resultF)) + return false; + tempPath = fs2us(resultF); + } + if (!SetArcPathFields(tempPath, name, false)) + return false; + FString resultF; + if (!MyGetFullPathName(us2fs(DirPrefix + name), resultF)) + return false; + resPath = fs2us(resultF); + return true; +} + +bool CCompressDialog::SetArcPathFields(const UString &path, UString &name, bool always) +{ + FString resDirPrefix; + FString resFileName; + 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"; + +void CCompressDialog::OnButtonSetArchive() +{ + UString path; + if (!GetFinalPath_Smart(path)) + { + ShowErrorMessage(*this, k_IncorrectPathMessage); + return; + } + + UString title = LangString(IDS_COMPRESS_SET_ARCHIVE_BROWSE); + UString filterDescription = LangString(IDS_OPEN_TYPE_ALL_FILES); + filterDescription += " (*.*)"; + UString resPath; + CurrentDirWasChanged = true; + if (!MyBrowseForFile(*this, title, + // DirPrefix.IsEmpty() ? NULL : (const wchar_t *)DirPrefix, + // NULL, + path, + filterDescription, + NULL, // L"*.*", + resPath)) + return; + UString dummyName; + SetArcPathFields(resPath, dummyName, true); +} + +// 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++) + { + wchar_t c = s[i]; + if (c < 0x20 || c > 0x7F) + return false; + } + return true; +} + +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; + } + } + + SaveOptionsInMem(); + { + UString s; + if (!GetFinalPath_Smart(s)) + { + ShowErrorMessage(*this, k_IncorrectPathMessage); + return; + } + + m_RegistryInfo.ArcPaths.Clear(); + AddUniqueString(m_RegistryInfo.ArcPaths, s); + Info.ArcPath = 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.Dictionary = GetDictionarySpec(); + Info.Order = GetOrderSpec(); + Info.OrderMode = GetOrderMode(); + Info.NumThreads = GetNumThreadsSpec(); + + { + 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 = 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); + + GetButton_Bools(IDX_COMPRESS_NT_SYM_LINKS, Info.SymLinks, m_RegistryInfo.SymLinks); + GetButton_Bools(IDX_COMPRESS_NT_HARD_LINKS, Info.HardLinks, m_RegistryInfo.HardLinks); + GetButton_Bools(IDX_COMPRESS_NT_ALT_STREAMS, Info.AltStreams, m_RegistryInfo.AltStreams); + GetButton_Bools(IDX_COMPRESS_NT_SECUR, Info.NtSecurity, m_RegistryInfo.NtSecurity); + + { + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + if (!ai.Flags_SymLinks()) Info.SymLinks.Val = false; + if (!ai.Flags_HardLinks()) Info.HardLinks.Val = false; + if (!ai.Flags_AltStreams()) Info.AltStreams.Val = false; + if (!ai.Flags_NtSecure()) Info.NtSecurity.Val = false; + } + + m_Params.GetText(Info.Options); + m_Volume.GetText(Info.SplitVolume); + Info.SplitVolume.Trim(); + Info.VolumeSizes.Clear(); + + if (!Info.SplitVolume.IsEmpty()) + { + if (!ParseVolumeSizes(Info.SplitVolume, 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 ZS", MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES) + return; + } + } + } + + for (int i = 0; i < m_ArchivePath.GetCount(); i++) + { + UString sTemp; + m_ArchivePath.GetLBText(i, sTemp); + sTemp.Trim(); + AddUniqueString(m_RegistryInfo.ArcPaths, sTemp); + } + + if (m_RegistryInfo.ArcPaths.Size() > kHistorySize) + m_RegistryInfo.ArcPaths.DeleteBack(); + + if (Info.FormatIndex >= 0) + m_RegistryInfo.ArcType = (*ArcFormats)[Info.FormatIndex].Name; + m_RegistryInfo.ShowPassword = IsShowPasswordChecked(); + + m_RegistryInfo.Save(); + + CModalDialog::OnOK(); +} + +#define kHelpTopic "fm/plugins/7-zip/add.htm" + +void CCompressDialog::OnHelp() +{ + ShowHelpWindow(kHelpTopic); +} + +bool CCompressDialog::OnCommand(int code, int itemID, LPARAM lParam) +{ + if (code == CBN_SELCHANGE) + { + switch (itemID) + { + case IDC_COMPRESS_ARCHIVE: + { + // we can 't change m_ArchivePath in that handler ! + DirPrefix.Empty(); + SetItemText(IDT_COMPRESS_ARCHIVE_FOLDER, DirPrefix); + return true; + } + + case IDC_COMPRESS_FORMAT: + { + bool isSFX = IsSFX(); + SaveOptionsInMem(); + m_Solid.ResetContent(); + SetMethod(GetMethodID()); + SetLevel(); + SetSolidBlockSize(); + SetNumThreads(); + SetParams(); + CheckControlsEnable(); + SetArchiveName2(isSFX); + SetEncryptionMethod(); + SetMemoryUsage(); + SetMethod(GetMethodID()); + return true; + } + + case IDC_COMPRESS_LEVEL: + { + { + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + int index = FindRegistryFormatAlways(ai.Name); + NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + fo.ResetForLevelChange(); + } + + SetSolidBlockSize(); + SetNumThreads(); + CheckSFXNameChange(); + SetMemoryUsage(); + return true; + } + + case IDC_COMPRESS_METHOD: + { + SetMethod(GetMethodID()); + SetDictionary(); + SetOrder(); + SetSolidBlockSize(); + SetNumThreads(); + CheckSFXNameChange(); + SetMemoryUsage(); + return true; + } + + case IDC_COMPRESS_DICTIONARY: + { + UInt32 blockSizeLog = GetBlockSizeSpec(); + if (blockSizeLog != (UInt32)(Int32)-1 + && blockSizeLog != kNoSolidBlockSize + && blockSizeLog != kSolidBlockSize) + { + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + int index = FindRegistryFormatAlways(ai.Name); + NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + fo.Reset_BlockLogSize(); + SetSolidBlockSize(true); + } + + SetMemoryUsage(); + return true; + } + + case IDC_COMPRESS_ORDER: + return true; + + case IDC_COMPRESS_SOLID: + { + SetMemoryUsage(); + return true; + } + + case IDC_COMPRESS_THREADS: + { + SetMemoryUsage(); + return true; + } + } + } + return CModalDialog::OnCommand(code, itemID, lParam); +} + +void CCompressDialog::CheckSFXNameChange() +{ + 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 += '.'; + 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 = 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 += '.'; + fileName += ai.GetMainExt(); + } + 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 i; + } + return -1; +} + +int CCompressDialog::FindRegistryFormatAlways(const UString &name) +{ + int index = FindRegistryFormat(name); + if (index < 0) + { + NCompression::CFormatOptions fo; + fo.FormatID = GetSystemString(name); + index = m_RegistryInfo.Formats.Add(fo); + } + return index; +} + +int CCompressDialog::GetStaticFormatIndex() +{ + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + for (unsigned i = 0; i < 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::SetLevel() +{ + UInt32 level = GetLevel2(); + UInt32 LevelsMask; + UInt32 LevelsStart = 0; + UInt32 LevelsEnd = 22; + UInt32 langID = 0; + unsigned i, ir; + + if (GetMethodID() == kZSTD) + LevelsMask = g_Formats[6].LevelsMask; + else if (GetMethodID() == kBROTLI) + LevelsMask = g_Formats[7].LevelsMask; + else if (GetMethodID() == kLIZARD_M1) { + LevelsMask = g_Formats[8].LevelsMask; + LevelsStart = 10; + LevelsEnd = 19; + } else if (GetMethodID() == kLIZARD_M2) { + LevelsMask = g_Formats[8].LevelsMask; + LevelsStart = 20; + LevelsEnd = 29; + } else if (GetMethodID() == kLIZARD_M3) { + LevelsMask = g_Formats[8].LevelsMask; + LevelsStart = 30; + LevelsEnd = 39; + } else if (GetMethodID() == kLIZARD_M4) { + LevelsMask = g_Formats[8].LevelsMask; + LevelsStart = 40; + LevelsEnd = 49; + } else if (GetMethodID() == kLZ4) + LevelsMask = g_Formats[9].LevelsMask; + else if (GetMethodID() == kLZ5) + LevelsMask = g_Formats[10].LevelsMask; + else + LevelsMask = g_Formats[GetStaticFormatIndex()].LevelsMask; + + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + { + int index = FindRegistryFormat(ai.Name); + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + if (fo.Level <= 49) + level = fo.Level; + else + level = 5; + } + } + + m_Level.ResetContent(); + for (i = LevelsStart; i <= LevelsEnd; i++) + { + TCHAR s[40]; + TCHAR t[50] = { TEXT('L'), TEXT('e'), TEXT('v'), TEXT('e'), TEXT('l'), TEXT(' '), 0 }; + + // lizard needs extra handling + if (GetMethodID() >= kLIZARD_M1 && GetMethodID() <= kLIZARD_M4) { + ir = i; + if (ir % 10 == 0) langID = 0; + while (ir > 19) { ir -= 10; } + } else { + ir = i; + } + + // max reached + if (LevelsMask < (UInt32)(1 << ir)) + break; + + if ((LevelsMask & (1 << ir)) != 0) + { + ConvertUInt32ToString(i, s); + lstrcat(t, s); + lstrcat(t, TEXT(" (")); + lstrcat(t, LangString(g_Levels[langID])); + lstrcat(t, TEXT(")")); + int index = (int)m_Level.AddString(t); + m_Level.SetItemData(index, i); + langID++; + } else { + ConvertUInt32ToString(i, s); + lstrcat(t, s); + int index = (int)m_Level.AddString(t); + m_Level.SetItemData(index, i); + } + } + + // ShowInfo(L"SetLevel() methodID=%d level=%d start=%d end=%d", GetMethodID(), level, LevelsStart, LevelsEnd); + SetNearestSelectComboBox(m_Level, level); + + return; +} + +static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s) +{ + return cb.AddString((CSysString)s); +} + + +void CCompressDialog::SetMethod(int keepMethodId) +{ + UInt32 level = GetLevel2(); + int mID = GetMethodID(); + static int mID_old = 0; + + if (mID != mID_old) { + mID_old = mID; + SetLevel(); + } + + if (level == 0) + { + SetDictionary(); + SetOrder(); + return; + } + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + int index = FindRegistryFormat(ai.Name); + UString defaultMethod; + int defaultLevel = 5; + if (index >= 0) { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + defaultMethod = fo.Method; + defaultLevel = fo.Level; + } + + bool isSfx = IsSFX(); + bool weUseSameMethod = false; + + m_Method.ResetContent(); + for (unsigned m = 0; m < fi.NumMethods; m++) + { + EMethodID methodID = fi.MathodIDs[m]; + if (isSfx) + if (!IsMethodSupportedBySfx(methodID)) + continue; + + const char *methodLong = kMethodsLongnames[methodID]; + const char *method = kMethodsNames[methodID]; + int itemIndex = (int)ComboBox_AddStringAscii(m_Method, methodLong); + m_Method.SetItemData(itemIndex, methodID); + + if (keepMethodId == methodID) { + weUseSameMethod = true; + m_Method.SetCurSel(itemIndex); + continue; + } + + // Lizard :/ + if (defaultMethod.IsEqualTo_Ascii_NoCase("lizard") && keepMethodId == -1) { + if (defaultLevel >= 10 && defaultLevel <= 19) m_Method.SetCurSel(kLIZARD_M1 - 1); + if (defaultLevel >= 20 && defaultLevel <= 29) m_Method.SetCurSel(kLIZARD_M2 - 1); + if (defaultLevel >= 30 && defaultLevel <= 39) m_Method.SetCurSel(kLIZARD_M3 - 1); + if (defaultLevel >= 40 && defaultLevel <= 49) m_Method.SetCurSel(kLIZARD_M4 - 1); + } + + if ((defaultMethod.IsEqualTo_Ascii_NoCase(method) || m == 0) && !weUseSameMethod) { + m_Method.SetCurSel(itemIndex); + } + } + + if (!weUseSameMethod) { + SetDictionary(); + SetOrder(); + } +} + +bool CCompressDialog::IsZipFormat() +{ + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + return ai.Name.IsEqualTo_Ascii_NoCase("zip"); +} + +bool CCompressDialog::IsXzFormat() +{ + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + return ai.Name.IsEqualTo_Ascii_NoCase("xz"); +} + +void CCompressDialog::SetEncryptionMethod() +{ + _encryptionMethod.ResetContent(); + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + if (ai.Name.IsEqualTo_Ascii_NoCase("7z")) + { + ComboBox_AddStringAscii(_encryptionMethod, "AES-256"); + _encryptionMethod.SetCurSel(0); + } + else if (ai.Name.IsEqualTo_Ascii_NoCase("zip")) + { + int index = FindRegistryFormat(ai.Name); + UString encryptionMethod; + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + encryptionMethod = fo.EncryptionMethod; + } + ComboBox_AddStringAscii(_encryptionMethod, "ZipCrypto"); + ComboBox_AddStringAscii(_encryptionMethod, "AES-256"); + _encryptionMethod.SetCurSel(encryptionMethod.IsPrefixedBy_Ascii_NoCase("aes") ? 1 : 0); + } +} + +int CCompressDialog::GetMethodID() +{ + if (m_Method.GetCount() <= 0) + return -1; + return (int)(UInt32)m_Method.GetItemData_of_CurSel(); +} + +UString CCompressDialog::GetMethodSpec() +{ + UString s; + if (m_Method.GetCount() > 1) + s = kMethodsNames[GetMethodID()]; + return s; +} + +UString CCompressDialog::GetEncryptionMethodSpec() +{ + UString s; + if (_encryptionMethod.GetCount() > 1 + && _encryptionMethod.GetCurSel() > 0) + { + _encryptionMethod.GetText(s); + s.RemoveChar(L'-'); + } + return s; +} + +void CCompressDialog::AddDictionarySize(UInt32 size) +{ + Byte c = 0; + unsigned moveBits = 0; + if ((size & 0xFFFFF) == 0) { moveBits = 20; c = 'M'; } + else if ((size & 0x3FF) == 0) { moveBits = 10; c = 'K'; } + TCHAR s[40]; + ConvertUInt32ToString(size >> moveBits, s); + unsigned pos = MyStringLen(s); + s[pos++] = ' '; + if (moveBits != 0) + s[pos++] = c; + s[pos++] = 'B'; + s[pos++] = 0; + int index = (int)m_Dictionary.AddString(s); + m_Dictionary.SetItemData(index, size); +} + +typedef enum { + FL2_fast, + FL2_opt, + FL2_ultra +} FL2_strategy; + +typedef struct { + UInt32 dictionarySize; /* largest match distance : larger == more compression, more memory needed during decompression; > 64Mb == more memory per byte, slower */ + unsigned overlapFraction; /* overlap between consecutive blocks in 1/16 units: larger == more compression, slower */ + unsigned chainLog; /* HC3 sliding window : larger == more compression, slower; hybrid mode only (ultra) */ + unsigned cyclesLog; /* nb of searches : larger == more compression, slower; hybrid mode only (ultra) */ + unsigned searchDepth; /* maximum depth for resolving string matches : larger == more compression, slower */ + unsigned fastLength; /* acceptable match size for parser : larger == more compression, slower; fast bytes parameter from 7-Zip */ + unsigned divideAndConquer; /* split long chains of 2-byte matches into shorter chains with a small overlap : faster, somewhat less compression; enabled by default */ + FL2_strategy strategy; /* encoder strategy : fast, optimized or ultra (hybrid) */ +} FL2_compressionParameters; + +#define FL2_MAX_7Z_CLEVEL 9 +#define MATCH_BUFFER_SHIFT 8; +#define MATCH_BUFFER_ELBOW_BITS 17 +#define MATCH_BUFFER_ELBOW (1UL << MATCH_BUFFER_ELBOW_BITS) + +#define MB *(1U<<20) + +static const FL2_compressionParameters FL2_7zCParameters[FL2_MAX_7Z_CLEVEL + 1] = { + { 0,0,0,0,0,0,0,FL2_fast }, + { 1 MB, 1, 7, 0, 6, 32, 1, FL2_fast }, /* 1 */ + { 2 MB, 2, 7, 0, 10, 32, 1, FL2_fast }, /* 2 */ + { 2 MB, 2, 7, 0, 10, 32, 1, FL2_opt }, /* 3 */ + { 4 MB, 2, 7, 0, 14, 32, 1, FL2_opt }, /* 4 */ + { 16 MB, 2, 9, 0, 42, 48, 1, FL2_ultra }, /* 5 */ + { 32 MB, 2, 10, 0, 50, 64, 1, FL2_ultra }, /* 6 */ + { 64 MB, 2, 11, 1, 62, 96, 1, FL2_ultra }, /* 7 */ + { 64 MB, 4, 12, 2, 90, 273, 1, FL2_ultra }, /* 8 */ + { 128 MB, 2, 14, 3, 254, 273, 0, FL2_ultra } /* 9 */ +}; + +#undef MB + +#define RMF_BUILDER_SIZE (8 * 0x40100U) + +void CCompressDialog::SetDictionary() +{ + m_Dictionary.ResetContent(); + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + int index = FindRegistryFormat(ai.Name); + UInt32 defaultDict = (UInt32)(Int32)-1; + + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + if (fo.Method.IsEqualTo_NoCase(GetMethodSpec())) + defaultDict = fo.Dictionary; + } + + int methodID = GetMethodID(); + UInt32 level = GetLevel2(); + if (methodID < 0) + return; + UInt64 maxRamSize; + bool maxRamSize_Defined = GetMaxRamSizeForProgram(maxRamSize); + + switch (methodID) + { + case kLZMA: + case kLZMA2: + { + static const UInt32 kMinDicSize = (1 << 16); + if (defaultDict == (UInt32)(Int32)-1) + { + if (level >= 9) defaultDict = (1 << 26); + else if (level >= 7) defaultDict = (1 << 25); + else if (level >= 5) defaultDict = (1 << 24); + else if (level >= 3) defaultDict = (1 << 20); + else defaultDict = (kMinDicSize); + } + + AddDictionarySize(kMinDicSize); + m_Dictionary.SetCurSel(0); + + for (unsigned i = 20; i <= 31; i++) + for (unsigned j = 0; j < 2; j++) + { + if (i == 20 && j > 0) + continue; + UInt32 dict = ((UInt32)(2 + j) << (i - 1)); + + if (dict > + #ifdef MY_CPU_64BIT + (3 << 29) + #else + (1 << 26) + #endif + ) + continue; + + AddDictionarySize(dict); + UInt64 decomprSize; + UInt64 requiredComprSize = GetMemoryUsage(dict, decomprSize); + if (dict <= defaultDict && (!maxRamSize_Defined || requiredComprSize <= maxRamSize)) + m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1); + } + + // SetNearestSelectComboBox(m_Dictionary, defaultDict); + break; + } + + case kFLZMA2: + { + static const UInt32 kMinDicSize = (1 << 20); + level += !level; + if (level > FL2_MAX_7Z_CLEVEL) + level = FL2_MAX_7Z_CLEVEL; + if (defaultDict == (UInt32)(Int32)-1) + defaultDict = FL2_7zCParameters[level].dictionarySize; + + m_Dictionary.SetCurSel(0); + + for (unsigned i = 20; i <= 31; i++) { + UInt32 dict = (UInt32)1 << i; + + if (dict > + #ifdef MY_CPU_64BIT + (1 << 30) + #else + (1 << 27) + #endif + ) + continue; + + AddDictionarySize(dict); + UInt64 decomprSize; + UInt64 requiredComprSize = GetMemoryUsage(dict, decomprSize); + if (dict <= defaultDict && (!maxRamSize_Defined || requiredComprSize <= maxRamSize)) + m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1); + } + + break; + } + + case kPPMd: + { + if (defaultDict == (UInt32)(Int32)-1) + { + if (level >= 9) defaultDict = (192 << 20); + else if (level >= 7) defaultDict = ( 64 << 20); + else if (level >= 5) defaultDict = ( 16 << 20); + else defaultDict = ( 4 << 20); + } + + for (unsigned i = 20; i < 31; i++) + for (unsigned j = 0; j < 2; j++) + { + if (i == 20 && j > 0) + continue; + UInt32 dict = ((UInt32)(2 + j) << (i - 1)); + if (dict > + #ifdef MY_CPU_64BIT + (1 << 30) + #else + (1 << 29) + #endif + ) + continue; + AddDictionarySize(dict); + UInt64 decomprSize; + UInt64 requiredComprSize = GetMemoryUsage(dict, decomprSize); + if ((dict <= defaultDict && (!maxRamSize_Defined || requiredComprSize <= maxRamSize)) + || m_Dictionary.GetCount() == 1) + m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1); + } + + // SetNearestSelectComboBox(m_Dictionary, defaultDict); + break; + } + + case kDeflate: + { + AddDictionarySize(32 << 10); + m_Dictionary.SetCurSel(0); + break; + } + + case kDeflate64: + { + AddDictionarySize(64 << 10); + m_Dictionary.SetCurSel(0); + break; + } + + case kBZip2: + { + if (defaultDict == (UInt32)(Int32)-1) + { + if (level >= 5) defaultDict = (900 << 10); + else if (level >= 3) defaultDict = (500 << 10); + else defaultDict = (100 << 10); + } + + for (unsigned i = 1; i <= 9; i++) + { + UInt32 dict = ((UInt32)i * 100) << 10; + AddDictionarySize(dict); + if (dict <= defaultDict || m_Dictionary.GetCount() == 0) + m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1); + } + + break; + } + + case kPPMdZip: + { + if (defaultDict == (UInt32)(Int32)-1) + defaultDict = (1 << (19 + (level > 8 ? 8 : level))); + + for (unsigned i = 20; i <= 28; i++) + { + UInt32 dict = (1 << i); + AddDictionarySize(dict); + UInt64 decomprSize; + UInt64 requiredComprSize = GetMemoryUsage(dict, decomprSize); + if ((dict <= defaultDict && (!maxRamSize_Defined || requiredComprSize <= maxRamSize)) + || m_Dictionary.GetCount() == 1) + m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1); + } + + // SetNearestSelectComboBox(m_Dictionary, defaultDict); + break; + } + + } +} + +UInt32 CCompressDialog::GetComboValue(NWindows::NControl::CComboBox &c, int defMax) +{ + if (c.GetCount() <= defMax) + return (UInt32)(Int32)-1; + return (UInt32)c.GetItemData_of_CurSel(); +} + +UInt32 CCompressDialog::GetLevel2() +{ + UInt32 level = GetLevel(); + if (level == (UInt32)(Int32)-1) + level = 5; + return level; +} + +int CCompressDialog::AddOrder(UInt32 size) +{ + TCHAR s[40]; + ConvertUInt32ToString(size, s); + int index = (int)m_Order.AddString(s); + m_Order.SetItemData(index, size); + return index; +} + +void CCompressDialog::SetOrder() +{ + m_Order.ResetContent(); + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + int index = FindRegistryFormat(ai.Name); + UInt32 defaultOrder = (UInt32)(Int32)-1; + + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + if (fo.Method.IsEqualTo_NoCase(GetMethodSpec())) + defaultOrder = fo.Order; + } + + int methodID = GetMethodID(); + UInt32 level = GetLevel2(); + if (methodID < 0) + return; + + switch (methodID) + { + case kLZMA: + case kLZMA2: + case kFLZMA2: + { + if (defaultOrder == (UInt32)(Int32)-1) { + if (methodID == kFLZMA2) + defaultOrder = FL2_7zCParameters[level].fastLength; + else + defaultOrder = (level >= 7) ? 64 : 32; + } + for (unsigned i = 3; i <= 8; i++) + for (unsigned j = 0; j < 2; j++) + { + UInt32 order = ((UInt32)(2 + j) << (i - 1)); + if (order <= 256) + AddOrder(order); + } + AddOrder(273); + SetNearestSelectComboBox(m_Order, defaultOrder); + break; + } + + case kPPMd: + { + if (defaultOrder == (UInt32)(Int32)-1) + { + if (level >= 9) defaultOrder = 32; + else if (level >= 7) defaultOrder = 16; + else if (level >= 5) defaultOrder = 6; + else defaultOrder = 4; + } + + AddOrder(2); + AddOrder(3); + + for (unsigned i = 2; i < 8; i++) + for (unsigned j = 0; j < 4; j++) + { + UInt32 order = (4 + j) << (i - 2); + if (order < 32) + AddOrder(order); + } + + AddOrder(32); + SetNearestSelectComboBox(m_Order, defaultOrder); + break; + } + + case kDeflate: + case kDeflate64: + { + if (defaultOrder == (UInt32)(Int32)-1) + { + if (level >= 9) defaultOrder = 128; + else if (level >= 7) defaultOrder = 64; + else defaultOrder = 32; + } + + for (unsigned i = 3; i <= 8; i++) + for (unsigned j = 0; j < 2; j++) + { + UInt32 order = ((UInt32)(2 + j) << (i - 1));; + if (order <= 256) + AddOrder(order); + } + + AddOrder(methodID == kDeflate64 ? 257 : 258); + SetNearestSelectComboBox(m_Order, defaultOrder); + break; + } + + case kBZip2: + break; + + case kPPMdZip: + { + if (defaultOrder == (UInt32)(Int32)-1) + defaultOrder = level + 3; + for (unsigned i = 2; i <= 16; i++) + AddOrder(i); + SetNearestSelectComboBox(m_Order, defaultOrder); + break; + } + } +} + +bool CCompressDialog::GetOrderMode() +{ + switch (GetMethodID()) + { + case kPPMd: + case kPPMdZip: + return true; + } + return false; +} + + +void CCompressDialog::SetSolidBlockSize(bool useDictionary) +{ + m_Solid.ResetContent(); + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; + if (!fi.Solid) + return; + + UInt32 level = GetLevel2(); + if (level == 0) + return; + + UInt32 dict = GetDictionarySpec(); + if (dict == (UInt32)(Int32)-1) + dict = 1; + + UInt32 defaultBlockSize = (UInt32)(Int32)-1; + + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + + if (useDictionary) + defaultBlockSize = GetBlockSizeSpec(); + else + { + int index = FindRegistryFormat(ai.Name); + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + if (fo.Method.IsEqualTo_NoCase(GetMethodSpec())) + defaultBlockSize = fo.BlockLogSize; + } + } + + bool is7z = ai.Name.IsEqualTo_Ascii_NoCase("7z"); + + { + UString s ('-'); + if (is7z) + LangString(IDS_COMPRESS_NON_SOLID, s); + int index = (int)m_Solid.AddString(s); + m_Solid.SetItemData(index, (UInt32)kNoSolidBlockSize); + if (defaultBlockSize == kNoSolidBlockSize) + m_Solid.SetCurSel(0); + } + + UInt64 blockSize; + + if (is7z) + { + blockSize = (UInt64)dict << 7; + const UInt32 kMinSize = (UInt32)1 << 24; + const UInt64 kMaxSize = (UInt64)1 << 32; + if (blockSize < kMinSize) blockSize = kMinSize; + if (blockSize > kMaxSize) blockSize = kMaxSize; + } + else + { + blockSize = (UInt64)dict << 2; + const UInt32 kMinSize = (UInt32)1 << 20; + const UInt32 kMaxSize = (UInt32)1 << 28; + if (blockSize < kMinSize) blockSize = kMinSize; + if (blockSize > kMaxSize) blockSize = kMaxSize; + if (blockSize < dict) blockSize = dict; + } + + for (unsigned i = 20; i <= 36; i++) + { + if (defaultBlockSize == (UInt32)(Int32)-1 && ((UInt64)1 << i) >= blockSize) + defaultBlockSize = i; + + TCHAR s[40]; + char post; + ConvertUInt32ToString(1 << (i % 10), s); + if (i < 20) post = 'K'; + else if (i < 30) post = 'M'; + else post = 'G'; + unsigned pos = (unsigned)lstrlen(s); + s[pos++] = ' '; + s[pos++] = post; + s[pos++] = 'B'; + s[pos] = 0; + int index = (int)m_Solid.AddString(s); + m_Solid.SetItemData(index, (UInt32)i); + } + + { + int index = (int)m_Solid.AddString(LangString(IDS_COMPRESS_SOLID)); + m_Solid.SetItemData(index, kSolidBlockSize); + } + + if (defaultBlockSize == (UInt32)(Int32)-1) + defaultBlockSize = kSolidBlockSize; + if (defaultBlockSize != kNoSolidBlockSize) + SetNearestSelectComboBox(m_Solid, defaultBlockSize); +} + +void CCompressDialog::SetNumThreads() +{ + m_NumThreads.ResetContent(); + + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; + if (!fi.MultiThread) + return; + + UInt32 numHardwareThreads = NSystem::GetNumberOfProcessors(); + UInt32 defaultValue = numHardwareThreads; + + { + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + int index = FindRegistryFormat(ai.Name); + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + if (fo.Method.IsEqualTo_NoCase(GetMethodSpec()) && fo.NumThreads != (UInt32)(Int32)-1) + defaultValue = fo.NumThreads; + } + } + + UInt32 numAlgoThreadsMax = 1; + int methodID = GetMethodID(); + switch (methodID) + { + case kZSTD: numAlgoThreadsMax = 128; break; + case kBROTLI: numAlgoThreadsMax = 128; break; + case kLZ4: numAlgoThreadsMax = 128; break; + case kLZ5: numAlgoThreadsMax = 128; break; + case kLIZARD_M1: numAlgoThreadsMax = 128; break; + case kLIZARD_M2: numAlgoThreadsMax = 128; break; + case kLIZARD_M3: numAlgoThreadsMax = 128; break; + case kLIZARD_M4: numAlgoThreadsMax = 128; break; + case kLZMA: numAlgoThreadsMax = 2; break; + case kLZMA2: numAlgoThreadsMax = 32; break; + case kFLZMA2: numAlgoThreadsMax = 128; break; + case kBZip2: numAlgoThreadsMax = 32; break; + } + if (IsZipFormat()) + numAlgoThreadsMax = 128; + for (UInt32 i = 1; i <= numHardwareThreads * 2 && i <= numAlgoThreadsMax; i++) + { + TCHAR s[40]; + ConvertUInt32ToString(i, s); + int index = (int)m_NumThreads.AddString(s); + m_NumThreads.SetItemData(index, (UInt32)i); + } + SetNearestSelectComboBox(m_NumThreads, defaultValue); +} + +UInt64 CCompressDialog::GetMemoryUsage(UInt32 dict, UInt64 &decompressMemory) +{ + decompressMemory = UInt64(Int64(-1)); + UInt32 level = GetLevel2(); + if (level == 0) + { + 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(); + + if (IsZipFormat()) + { + UInt32 numSubThreads = 1; + if (GetMethodID() == kLZMA && numThreads > 1 && level >= 5) + numSubThreads = 2; + UInt32 numMainThreads = numThreads / numSubThreads; + if (numMainThreads > 1) + size += (UInt64)numMainThreads << 25; + } + + int methidId = GetMethodID(); + + switch (methidId) + { + case kLZMA: + case kLZMA2: + { + UInt32 hs = 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++; + 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; + + if (methidId != kLZMA && numBlockThreads != 1) + { + chunkSize = (UInt64)dict << 2; + chunkSize = MyMax(chunkSize, (UInt64)(1 << 20)); + chunkSize = MyMin(chunkSize, (UInt64)(1 << 28)); + chunkSize = MyMax(chunkSize, (UInt64)dict); + + if (IsXzFormat()) + { + UInt32 blockSizeLog = GetBlockSizeSpec(); + if (blockSizeLog != (UInt32)(Int32)-1) + { + if (blockSizeLog == kSolidBlockSize) + { + numBlockThreads = 1; + chunkSize = 0; + } + else if (blockSizeLog != kNoSolidBlockSize) + chunkSize = (UInt64)1 << blockSizeLog; + } + } + } + + if (chunkSize == 0) + size += numBlockThreads * (size1 + (UInt64)dict * 3 / 2); + else + { + size += numBlockThreads * (size1 + chunkSize); + UInt64 numPackChunks = numBlockThreads + (numBlockThreads / 4) + 2; + size += numPackChunks * chunkSize; + } + + decompressMemory = dict + (2 << 20); + return size; + } + + case kFLZMA2: + { + if (level > FL2_MAX_7Z_CLEVEL) + level = FL2_MAX_7Z_CLEVEL; + /* dual buffer is enabled in Lzma2Encoder.cpp so size is dict * 6 */ + size += dict * 6 + (1UL << 18) * numThreads; + UInt32 bufSize = dict >> MATCH_BUFFER_SHIFT; + if (bufSize > MATCH_BUFFER_ELBOW) { + UInt32 extra = 0; + unsigned n = MATCH_BUFFER_ELBOW_BITS - 1; + for (; (4UL << n) <= bufSize; ++n) + extra += MATCH_BUFFER_ELBOW >> 4; + if ((3UL << n) <= bufSize) + extra += MATCH_BUFFER_ELBOW >> 5; + bufSize = MATCH_BUFFER_ELBOW + extra; + } + size += (bufSize * 12 + RMF_BUILDER_SIZE) * numThreads; + if (dict > (UInt32(1) << 26)) + size += dict; + if (FL2_7zCParameters[level].strategy == FL2_ultra) + size += (UInt32(4) << 14) + (UInt32(4) << FL2_7zCParameters[level].chainLog); + decompressMemory = dict + (2 << 20); + return size; + } + + case kPPMd: + { + decompressMemory = dict + (2 << 20); + return size + decompressMemory; + } + + case kDeflate: + case kDeflate64: + { + /* + UInt32 order = GetOrder(); + if (order == (UInt32)(Int32)-1) + order = 32; + */ + if (level >= 7) + size += (1 << 20); + size += 3 << 20; + decompressMemory = (2 << 20); + return size; + } + + case kBZip2: + { + decompressMemory = (7 << 20); + UInt64 memForOneThread = (10 << 20); + return size + memForOneThread * numThreads; + } + + case kPPMdZip: + { + decompressMemory = dict + (2 << 20); + return size + (UInt64)decompressMemory * numThreads; + } + } + + return (UInt64)(Int64)-1; +} + +UInt64 CCompressDialog::GetMemoryUsage(UInt64 &decompressMemory) +{ + return GetMemoryUsage(GetDictionary(), decompressMemory); +} + +void CCompressDialog::PrintMemUsage(UINT res, UInt64 value) +{ + if (value == (UInt64)(Int64)-1) + { + SetItemText(res, TEXT("?")); + return; + } + value = (value + (1 << 20) - 1) >> 20; + TCHAR s[40]; + ConvertUInt64ToString(value, s); + lstrcat(s, TEXT(" MB")); + SetItemText(res, s); +} + +void CCompressDialog::SetMemoryUsage() +{ + UInt64 decompressMem; + UInt64 memUsage = GetMemoryUsage(decompressMem); + PrintMemUsage(IDT_COMPRESS_MEMORY_VALUE, memUsage); + PrintMemUsage(IDT_COMPRESS_MEMORY_DE_VALUE, decompressMem); +} + +void CCompressDialog::SetParams() +{ + const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + m_Params.SetText(TEXT("")); + int index = FindRegistryFormat(ai.Name); + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + m_Params.SetText(fo.Options); + m_Volume.SetText(fo.SplitVolume); + } +} + +void CCompressDialog::SaveOptionsInMem() +{ + const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex]; + int index = FindRegistryFormatAlways(ai.Name); + m_Params.GetText(Info.Options); + m_Volume.GetText(Info.SplitVolume); + Info.Options.Trim(); + Info.SplitVolume.Trim(); + NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + fo.Options = Info.Options; + fo.SplitVolume = Info.SplitVolume; + fo.Level = GetLevelSpec(); + fo.Dictionary = GetDictionarySpec(); + fo.Order = GetOrderSpec(); + fo.Method = GetMethodSpec(); + fo.EncryptionMethod = GetEncryptionMethodSpec(); + fo.NumThreads = GetNumThreadsSpec(); + fo.BlockLogSize = GetBlockSizeSpec(); +} + +unsigned CCompressDialog::GetFormatIndex() +{ + return (unsigned)m_Format.GetItemData_of_CurSel(); +} diff --git a/CPP/7zip/UI/GUI/CompressDialog.h b/CPP/7zip/UI/GUI/CompressDialog.h index a171d7d19..3f8209735 100644 --- a/CPP/7zip/UI/GUI/CompressDialog.h +++ b/CPP/7zip/UI/GUI/CompressDialog.h @@ -1,218 +1,218 @@ -// CompressDialog.h - -#ifndef __COMPRESS_DIALOG_H -#define __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; - - CRecordVector VolumeSizes; - - UInt32 Level; - UString Method; - UInt32 Dictionary; - bool OrderMode; - UInt32 Order; - UString Options; - UString SplitVolume; - - UString EncryptionMethod; - - bool SFXMode; - bool OpenShareForWrite; - bool DeleteAfterCompressing; - - CBoolPair SymLinks; - CBoolPair HardLinks; - CBoolPair AltStreams; - CBoolPair NtSecurity; - - 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 = Dictionary = Order = UInt32(-1); - OrderMode = false; - Method.Empty(); - Options.Empty(); - SplitVolume.Empty(); - EncryptionMethod.Empty(); - } - }; -} - -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_Order; - NWindows::NControl::CComboBox m_Solid; - NWindows::NControl::CComboBox m_NumThreads; - - NWindows::NControl::CComboBox m_UpdateMode; - NWindows::NControl::CComboBox m_PathMode; - - NWindows::NControl::CComboBox m_Volume; - NWindows::NControl::CDialogChildControl m_Params; - - NWindows::NControl::CEdit _password1Control; - NWindows::NControl::CEdit _password2Control; - NWindows::NControl::CComboBox _encryptionMethod; - - NCompression::CInfo m_RegistryInfo; - - int m_PrevFormat; - UString DirPrefix; - UString StartDirPrefix; - - void CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2); - void GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2); - - void SetArchiveName(const UString &name); - int FindRegistryFormat(const UString &name); - int FindRegistryFormatAlways(const UString &name); - - void CheckSFXNameChange(); - void SetArchiveName2(bool prevWasSFX); - - int GetStaticFormatIndex(); - - void SetNearestSelectComboBox(NWindows::NControl::CComboBox &comboBox, UInt32 value); - - void SetLevel(); - - void SetMethod(int keepMethodId = -1); - int GetMethodID(); - UString GetMethodSpec(); - UString GetEncryptionMethodSpec(); - - bool IsZipFormat(); - bool IsXzFormat(); - - void SetEncryptionMethod(); - - void AddDictionarySize(UInt32 size); - - void SetDictionary(); - - UInt32 GetComboValue(NWindows::NControl::CComboBox &c, int defMax = 0); - - UInt32 GetLevel() { return GetComboValue(m_Level); } - UInt32 GetLevelSpec() { return GetComboValue(m_Level, 1); } - UInt32 GetLevel2(); - UInt32 GetDictionary() { return GetComboValue(m_Dictionary); } - UInt32 GetDictionarySpec() { return GetComboValue(m_Dictionary, 1); } - 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(-1)) num = 1; return num; } - UInt32 GetBlockSizeSpec() { return GetComboValue(m_Solid, 1); } - - int AddOrder(UInt32 size); - void SetOrder(); - bool GetOrderMode(); - - void SetSolidBlockSize(bool useDictionary = false); - void SetNumThreads(); - - UInt64 GetMemoryUsage(UInt32 dict, UInt64 &decompressMemory); - UInt64 GetMemoryUsage(UInt64 &decompressMemory); - void PrintMemUsage(UINT res, UInt64 value); - void SetMemoryUsage(); - 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 GetFinalPath_Smart(UString &resPath); - -public: - CObjectVector *ArcFormats; - CUIntVector ArcIndices; // can not be empty, must contain Info.FormatIndex, if Info.FormatIndex >= 0 - - NCompressDialog::CInfo Info; - UString OriginalFileName; // for bzip2, gzip2 - bool CurrentDirWasChanged; - - INT_PTR Create(HWND wndParent = 0) - { - BIG_DIALOG_SIZE(400, 304); - return CModalDialog::Create(SIZED_DIALOG(IDD_COMPRESS), wndParent); - } - - CCompressDialog(): CurrentDirWasChanged(false) {}; - -protected: - - void CheckSFXControlsEnable(); - // void CheckVolumeEnable(); - void CheckControlsEnable(); - - void OnButtonSetArchive(); - bool IsSFX(); - void OnButtonSFX(); - - virtual bool OnInit(); - virtual bool OnCommand(int code, int itemID, LPARAM lParam); - virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); - virtual void OnOK(); - virtual void OnHelp(); - -}; - -#endif +// CompressDialog.h + +#ifndef __COMPRESS_DIALOG_H +#define __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; + + CRecordVector VolumeSizes; + + UInt32 Level; + UString Method; + UInt32 Dictionary; + bool OrderMode; + UInt32 Order; + UString Options; + UString SplitVolume; + + UString EncryptionMethod; + + bool SFXMode; + bool OpenShareForWrite; + bool DeleteAfterCompressing; + + CBoolPair SymLinks; + CBoolPair HardLinks; + CBoolPair AltStreams; + CBoolPair NtSecurity; + + 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 = Dictionary = Order = UInt32(-1); + OrderMode = false; + Method.Empty(); + Options.Empty(); + SplitVolume.Empty(); + EncryptionMethod.Empty(); + } + }; +} + +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_Order; + NWindows::NControl::CComboBox m_Solid; + NWindows::NControl::CComboBox m_NumThreads; + + NWindows::NControl::CComboBox m_UpdateMode; + NWindows::NControl::CComboBox m_PathMode; + + NWindows::NControl::CComboBox m_Volume; + NWindows::NControl::CDialogChildControl m_Params; + + NWindows::NControl::CEdit _password1Control; + NWindows::NControl::CEdit _password2Control; + NWindows::NControl::CComboBox _encryptionMethod; + + NCompression::CInfo m_RegistryInfo; + + int m_PrevFormat; + UString DirPrefix; + UString StartDirPrefix; + + void CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2); + void GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2); + + void SetArchiveName(const UString &name); + int FindRegistryFormat(const UString &name); + int FindRegistryFormatAlways(const UString &name); + + void CheckSFXNameChange(); + void SetArchiveName2(bool prevWasSFX); + + int GetStaticFormatIndex(); + + void SetNearestSelectComboBox(NWindows::NControl::CComboBox &comboBox, UInt32 value); + + void SetLevel(); + + void SetMethod(int keepMethodId = -1); + int GetMethodID(); + UString GetMethodSpec(); + UString GetEncryptionMethodSpec(); + + bool IsZipFormat(); + bool IsXzFormat(); + + void SetEncryptionMethod(); + + void AddDictionarySize(UInt32 size); + + void SetDictionary(); + + UInt32 GetComboValue(NWindows::NControl::CComboBox &c, int defMax = 0); + + UInt32 GetLevel() { return GetComboValue(m_Level); } + UInt32 GetLevelSpec() { return GetComboValue(m_Level, 1); } + UInt32 GetLevel2(); + UInt32 GetDictionary() { return GetComboValue(m_Dictionary); } + UInt32 GetDictionarySpec() { return GetComboValue(m_Dictionary, 1); } + 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(-1)) num = 1; return num; } + UInt32 GetBlockSizeSpec() { return GetComboValue(m_Solid, 1); } + + int AddOrder(UInt32 size); + void SetOrder(); + bool GetOrderMode(); + + void SetSolidBlockSize(bool useDictionary = false); + void SetNumThreads(); + + UInt64 GetMemoryUsage(UInt32 dict, UInt64 &decompressMemory); + UInt64 GetMemoryUsage(UInt64 &decompressMemory); + void PrintMemUsage(UINT res, UInt64 value); + void SetMemoryUsage(); + 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 GetFinalPath_Smart(UString &resPath); + +public: + CObjectVector *ArcFormats; + CUIntVector ArcIndices; // can not be empty, must contain Info.FormatIndex, if Info.FormatIndex >= 0 + + NCompressDialog::CInfo Info; + UString OriginalFileName; // for bzip2, gzip2 + bool CurrentDirWasChanged; + + INT_PTR Create(HWND wndParent = 0) + { + BIG_DIALOG_SIZE(400, 304); + return CModalDialog::Create(SIZED_DIALOG(IDD_COMPRESS), wndParent); + } + + CCompressDialog(): CurrentDirWasChanged(false) {}; + +protected: + + void CheckSFXControlsEnable(); + // void CheckVolumeEnable(); + void CheckControlsEnable(); + + void OnButtonSetArchive(); + bool IsSFX(); + void OnButtonSFX(); + + virtual bool OnInit(); + virtual bool OnCommand(int code, int itemID, LPARAM lParam); + virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); + virtual void OnOK(); + virtual void OnHelp(); + +}; + +#endif diff --git a/CPP/7zip/UI/GUI/CompressDialog.rc b/CPP/7zip/UI/GUI/CompressDialog.rc index 2ef39af9f..ccb2a5a6a 100644 --- a/CPP/7zip/UI/GUI/CompressDialog.rc +++ b/CPP/7zip/UI/GUI/CompressDialog.rc @@ -1,225 +1,225 @@ -#include "CompressDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 400 -#define yc 354 - -#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 ntSize2 168 -#define ntSizeX (ntSize2 - m - m) -#define ntPosX m + m -#define ntPosY 292 - -#define g1xs 88 -#define g0xs (gSize - g1xs) -#define g1x (m + g0xs) - -#define g3xs 40 -#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 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 &method:", IDT_COMPRESS_METHOD, m, 62, g0xs, 8 - COMBOBOX IDC_COMPRESS_METHOD, g1x, 60, g1xs, 80, MY_COMBO - - LTEXT "Compression &level:", IDT_COMPRESS_LEVEL, m, 83, g0xs, 8 - COMBOBOX IDC_COMPRESS_LEVEL, 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 "&Word size:", IDT_COMPRESS_ORDER, m, 125, g0xs, 8 - COMBOBOX IDC_COMPRESS_ORDER, g1x, 123, g1xs, 141, 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, 8 - - LTEXT "Memory usage for Compressing:", IDT_COMPRESS_MEMORY, m, 190, g2xs, 8 - RTEXT "", IDT_COMPRESS_MEMORY_VALUE, g3x, 190, g3xs, 8 - - LTEXT "Memory usage for Decompressing:", IDT_COMPRESS_MEMORY_DE, m, 206, g2xs, 8 - RTEXT "", IDT_COMPRESS_MEMORY_DE_VALUE, g3x, 206, g3xs, 8 - - 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 - - - GROUPBOX "NTFS", IDG_COMPRESS_NTFS, m, ntPosY, ntSize2, 68 - - 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 "&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?" -END +#include "CompressDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 400 +#define yc 354 + +#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 ntSize2 168 +#define ntSizeX (ntSize2 - m - m) +#define ntPosX m + m +#define ntPosY 292 + +#define g1xs 88 +#define g0xs (gSize - g1xs) +#define g1x (m + g0xs) + +#define g3xs 40 +#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 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 &method:", IDT_COMPRESS_METHOD, m, 62, g0xs, 8 + COMBOBOX IDC_COMPRESS_METHOD, g1x, 60, g1xs, 80, MY_COMBO + + LTEXT "Compression &level:", IDT_COMPRESS_LEVEL, m, 83, g0xs, 8 + COMBOBOX IDC_COMPRESS_LEVEL, 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 "&Word size:", IDT_COMPRESS_ORDER, m, 125, g0xs, 8 + COMBOBOX IDC_COMPRESS_ORDER, g1x, 123, g1xs, 141, 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, 8 + + LTEXT "Memory usage for Compressing:", IDT_COMPRESS_MEMORY, m, 190, g2xs, 8 + RTEXT "", IDT_COMPRESS_MEMORY_VALUE, g3x, 190, g3xs, 8 + + LTEXT "Memory usage for Decompressing:", IDT_COMPRESS_MEMORY_DE, m, 206, g2xs, 8 + RTEXT "", IDT_COMPRESS_MEMORY_DE_VALUE, g3x, 206, g3xs, 8 + + 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 + + + GROUPBOX "NTFS", IDG_COMPRESS_NTFS, m, ntPosY, ntSize2, 68 + + 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 "&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?" +END diff --git a/CPP/7zip/UI/GUI/CompressDialogRes.h b/CPP/7zip/UI/GUI/CompressDialogRes.h index 39bb6bfb6..ff99fa94c 100644 --- a/CPP/7zip/UI/GUI/CompressDialogRes.h +++ b/CPP/7zip/UI/GUI/CompressDialogRes.h @@ -1,87 +1,87 @@ -#define IDD_COMPRESS 4000 -#define IDD_COMPRESS_2 14000 - -#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 IDE_COMPRESS_PASSWORD1 120 -#define IDE_COMPRESS_PASSWORD2 121 -#define IDC_COMPRESS_ENCRYPTION_METHOD 122 - -#define IDT_COMPRESS_ARCHIVE_FOLDER 130 - -#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 +#define IDD_COMPRESS 4000 +#define IDD_COMPRESS_2 14000 + +#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 IDE_COMPRESS_PASSWORD1 120 +#define IDE_COMPRESS_PASSWORD2 121 +#define IDC_COMPRESS_ENCRYPTION_METHOD 122 + +#define IDT_COMPRESS_ARCHIVE_FOLDER 130 + +#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 diff --git a/CPP/7zip/UI/GUI/Extract.rc b/CPP/7zip/UI/GUI/Extract.rc index 6bda89e39..f75b2e6fc 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 "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 diff --git a/CPP/7zip/UI/GUI/ExtractDialog.cpp b/CPP/7zip/UI/GUI/ExtractDialog.cpp index 71c2a3b61..b36a49438 100644 --- a/CPP/7zip/UI/GUI/ExtractDialog.cpp +++ b/CPP/7zip/UI/GUI/ExtractDialog.cpp @@ -1,418 +1,418 @@ -// 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 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 diff --git a/CPP/7zip/UI/GUI/ExtractDialog.h b/CPP/7zip/UI/GUI/ExtractDialog.h index 308c78676..33349ffc6 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 __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 diff --git a/CPP/7zip/UI/GUI/ExtractDialog.rc b/CPP/7zip/UI/GUI/ExtractDialog.rc index f5d65281c..3728b96d2 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 e198796aa..ed12bfb31 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 99db743d7..1e37efb83 100644 --- a/CPP/7zip/UI/GUI/ExtractGUI.cpp +++ b/CPP/7zip/UI/GUI/ExtractGUI.cpp @@ -1,280 +1,280 @@ -// 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 *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 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 &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 _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 *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 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 &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; +} diff --git a/CPP/7zip/UI/GUI/ExtractGUI.h b/CPP/7zip/UI/GUI/ExtractGUI.h index 466e524e0..d55b30de1 100644 --- a/CPP/7zip/UI/GUI/ExtractGUI.h +++ b/CPP/7zip/UI/GUI/ExtractGUI.h @@ -1,38 +1,38 @@ -// 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 &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 __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 &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 diff --git a/CPP/7zip/UI/GUI/ExtractRes.h b/CPP/7zip/UI/GUI/ExtractRes.h index 6437d953f..634ba6b5f 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/GUI.cpp b/CPP/7zip/UI/GUI/GUI.cpp index b58e4bd28..772ab0b30 100644 --- a/CPP/7zip/UI/GUI/GUI.cpp +++ b/CPP/7zip/UI/GUI/GUI.cpp @@ -1,432 +1,432 @@ -// GUI.cpp - -#include "StdAfx.h" - -#ifdef _WIN32 -#include "../../../../C/DllSecur.h" -#endif - -#include "../../../Common/MyWindows.h" - -#include - -#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/MyWindowsNew.h" - -#include "BenchmarkDialog.h" -#include "ExtractGUI.h" -#include "HashGUI.h" -#include "UpdateGUI.h" - -#include "ExtractRes.h" - -using namespace NWindows; - -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 void ErrorMessage(LPCWSTR message) -{ - MessageBoxW(NULL, message, L"7-Zip ZS", 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(DWORD 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(0, L"Specify command", L"7-Zip ZS", 0); - return 0; - } - - CArcCmdLineOptions options; - CArcCmdLineParser parser; - - parser.Parse1(commandStrings, options); - parser.Parse2(options); - - 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.IsFromUpdateGroup())) - { - #ifdef 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 formatIndices; - if (!ParseOpenTypes(*codecs, options.ArcType, formatIndices)) - { - ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE); - return NExitCode::kFatalError; - } - - CIntVector excludedFormatIndices; - 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; - } - excludedFormatIndices.AddToUniqueSorted(tempIndices[0]); - // excludedFormatIndices.Sort(); - } - - #ifdef EXTERNAL_CODECS - if (isExtractGroupCommand - || 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); - /* - 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 extractCallback = ecs; - - #ifndef _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 _SFX - eo.Properties = options.Properties; - #endif - - bool messageWasDisplayed = false; - - #ifndef _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(codecs, - formatIndices, excludedFormatIndices, - ArchivePathsSorted, - ArchivePathsFullSorted, - options.Censor.Pairs.Front().Head, - eo, - #ifndef _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 _NO_CRYPTO - bool passwordIsDefined = options.PasswordEnabled && !options.Password.IsEmpty(); - #endif - - CUpdateCallbackGUI callback; - // callback.EnablePercents = options.EnablePercents; - - #ifndef _NO_CRYPTO - callback.PasswordIsDefined = passwordIsDefined; - callback.AskPassword = options.PasswordEnabled && options.Password.IsEmpty(); - callback.Password = options.Password; - #endif - - // callback.StdOutMode = 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; -} - -#define NT_CHECK_FAIL_ACTION ErrorMessage("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; - - #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 - - LoadLangOneTime(); - - // 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(v); - ErrorMessage(e); - return NExitCode::kFatalError; - } - catch(...) - { - ErrorMessage("Unknown error"); - return NExitCode::kFatalError; - } -} +// GUI.cpp + +#include "StdAfx.h" + +#ifdef _WIN32 +#include "../../../../C/DllSecur.h" +#endif + +#include "../../../Common/MyWindows.h" + +#include + +#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/MyWindowsNew.h" + +#include "BenchmarkDialog.h" +#include "ExtractGUI.h" +#include "HashGUI.h" +#include "UpdateGUI.h" + +#include "ExtractRes.h" + +using namespace NWindows; + +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 void ErrorMessage(LPCWSTR message) +{ + MessageBoxW(NULL, message, L"7-Zip ZS", 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(DWORD 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(0, L"Specify command", L"7-Zip ZS", 0); + return 0; + } + + CArcCmdLineOptions options; + CArcCmdLineParser parser; + + parser.Parse1(commandStrings, options); + parser.Parse2(options); + + 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.IsFromUpdateGroup())) + { + #ifdef 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 formatIndices; + if (!ParseOpenTypes(*codecs, options.ArcType, formatIndices)) + { + ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE); + return NExitCode::kFatalError; + } + + CIntVector excludedFormatIndices; + 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; + } + excludedFormatIndices.AddToUniqueSorted(tempIndices[0]); + // excludedFormatIndices.Sort(); + } + + #ifdef EXTERNAL_CODECS + if (isExtractGroupCommand + || 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); + /* + 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 extractCallback = ecs; + + #ifndef _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 _SFX + eo.Properties = options.Properties; + #endif + + bool messageWasDisplayed = false; + + #ifndef _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(codecs, + formatIndices, excludedFormatIndices, + ArchivePathsSorted, + ArchivePathsFullSorted, + options.Censor.Pairs.Front().Head, + eo, + #ifndef _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 _NO_CRYPTO + bool passwordIsDefined = options.PasswordEnabled && !options.Password.IsEmpty(); + #endif + + CUpdateCallbackGUI callback; + // callback.EnablePercents = options.EnablePercents; + + #ifndef _NO_CRYPTO + callback.PasswordIsDefined = passwordIsDefined; + callback.AskPassword = options.PasswordEnabled && options.Password.IsEmpty(); + callback.Password = options.Password; + #endif + + // callback.StdOutMode = 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; +} + +#define NT_CHECK_FAIL_ACTION ErrorMessage("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; + + #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 + + LoadLangOneTime(); + + // 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(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 index 70448ff23..b70e28480 100644 --- a/CPP/7zip/UI/GUI/GUI.dsp +++ b/CPP/7zip/UI/GUI/GUI.dsp @@ -1,1187 +1,1187 @@ -# 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 "LANG" /D "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /D "SUPPORT_DEVICE_FILE" /D "_7ZIP_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:\Program Files\7-Zip\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 "LANG" /D "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /D "SUPPORT_DEVICE_FILE" /D "_7ZIP_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:\Program Files\7-Zip\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 "LANG" /D "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /D "SUPPORT_DEVICE_FILE" /D "_7ZIP_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:\Program Files\7-Zip\7zgn.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 "LANG" /D "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /D "SUPPORT_DEVICE_FILE" /D "_7ZIP_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:\Program Files\7-Zip\7zgn.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\FolderInterface.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\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\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\CRC.cpp -# 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\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\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\OutStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.h -# End Source File -# End Group -# End Target -# End Project +# 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 "LANG" /D "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /D "SUPPORT_DEVICE_FILE" /D "_7ZIP_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:\Program Files\7-Zip\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 "LANG" /D "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /D "SUPPORT_DEVICE_FILE" /D "_7ZIP_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:\Program Files\7-Zip\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 "LANG" /D "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /D "SUPPORT_DEVICE_FILE" /D "_7ZIP_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:\Program Files\7-Zip\7zgn.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 "LANG" /D "WIN_LONG_PATH" /D "EXTERNAL_CODECS" /D "SUPPORT_DEVICE_FILE" /D "_7ZIP_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:\Program Files\7-Zip\7zgn.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\FolderInterface.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\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\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\CRC.cpp +# 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\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\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\OutStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.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 index 465622e44..85d33484b 100644 --- a/CPP/7zip/UI/GUI/GUI.dsw +++ b/CPP/7zip/UI/GUI/GUI.dsw @@ -1,29 +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> -{{{ -}}} - -############################################################################### - +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 index 7c0b3f285..f0d5a1516 100644 --- a/CPP/7zip/UI/GUI/HashGUI.cpp +++ b/CPP/7zip/UI/GUI/HashGUI.cpp @@ -1,358 +1,358 @@ -// 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: public CProgressThreadVirt, public IHashCallbackUI -{ - UInt64 NumFiles; - bool _curIsFolder; - UString FirstFileName; - // UString MainPath; - - CPropNameValPairs PropNameValPairs; - - HRESULT ProcessVirt(); - virtual void ProcessWasFinished_GuiVirt(); - -public: - const NWildcard::CCensor *censor; - const CHashOptions *options; - - DECL_EXTERNAL_CODECS_LOC_VARS2; - - CHashCallbackGUI() {} - ~CHashCallbackGUI() { } - - INTERFACE_IHashCallbackUI(;) - - void AddErrorMessage(DWORD 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'; } - char sz[32]; - ConvertUInt64ToString(value, sz); - s += " ("; - s += sz; - s += " "; - 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(systemError, fs2us(path)); - return CheckBreak(); -} - -HRESULT CHashCallbackGUI::FinishScanning(const CDirItemsStat &st) -{ - return ScanProgress(st, FString(), false); -} - -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(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 void AddHashString(CProperty &s, const CHasherState &h, unsigned digestIndex) -{ - char temp[k_HashCalc_DigestSize_Max * 2 + 4]; - AddHashHexToString(temp, h.Digests[digestIndex], h.DigestSize); - 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 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 ZS"; // 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() -{ - ShowHashResults(PropNameValPairs, *this); -} +// 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: public CProgressThreadVirt, public IHashCallbackUI +{ + UInt64 NumFiles; + bool _curIsFolder; + UString FirstFileName; + // UString MainPath; + + CPropNameValPairs PropNameValPairs; + + HRESULT ProcessVirt(); + virtual void ProcessWasFinished_GuiVirt(); + +public: + const NWildcard::CCensor *censor; + const CHashOptions *options; + + DECL_EXTERNAL_CODECS_LOC_VARS2; + + CHashCallbackGUI() {} + ~CHashCallbackGUI() { } + + INTERFACE_IHashCallbackUI(;) + + void AddErrorMessage(DWORD 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'; } + char sz[32]; + ConvertUInt64ToString(value, sz); + s += " ("; + s += sz; + s += " "; + 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(systemError, fs2us(path)); + return CheckBreak(); +} + +HRESULT CHashCallbackGUI::FinishScanning(const CDirItemsStat &st) +{ + return ScanProgress(st, FString(), false); +} + +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(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 void AddHashString(CProperty &s, const CHasherState &h, unsigned digestIndex) +{ + char temp[k_HashCalc_DigestSize_Max * 2 + 4]; + AddHashHexToString(temp, h.Digests[digestIndex], h.DigestSize); + 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 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 ZS"; // 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() +{ + ShowHashResults(PropNameValPairs, *this); +} diff --git a/CPP/7zip/UI/GUI/HashGUI.h b/CPP/7zip/UI/GUI/HashGUI.h index b62682323..826445352 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 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 __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 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 index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/UI/GUI/StdAfx.cpp +++ b/CPP/7zip/UI/GUI/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/UI/GUI/StdAfx.h b/CPP/7zip/UI/GUI/StdAfx.h index da8cde196..64290769a 100644 --- a/CPP/7zip/UI/GUI/StdAfx.h +++ b/CPP/7zip/UI/GUI/StdAfx.h @@ -1,21 +1,21 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -// #define _WIN32_WINNT 0x0400 -#define _WIN32_WINNT 0x0500 -#define WINVER _WIN32_WINNT - -#include "../../../Common/Common.h" - -// #include "../../../Common/MyWindows.h" - -// #include -// #include -// #include - -// #define printf(x) NO_PRINTF_(x) -// #define sprintf(x) NO_SPRINTF_(x) - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +// #define _WIN32_WINNT 0x0400 +#define _WIN32_WINNT 0x0500 +#define WINVER _WIN32_WINNT + +#include "../../../Common/Common.h" + +// #include "../../../Common/MyWindows.h" + +// #include +// #include +// #include + +// #define printf(x) NO_PRINTF_(x) +// #define sprintf(x) NO_SPRINTF_(x) + +#endif diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp b/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp index 335bbf930..33852e3b1 100644 --- a/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp +++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp @@ -1,280 +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(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(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::ReportUpdateOpeartion(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 _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(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 +// 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(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(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::ReportUpdateOpeartion(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 _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(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 index 1ad745668..2e0c111bf 100644 --- a/CPP/7zip/UI/GUI/UpdateCallbackGUI.h +++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI.h @@ -1,34 +1,34 @@ -// UpdateCallbackGUI.h - -#ifndef __UPDATE_CALLBACK_GUI_H -#define __UPDATE_CALLBACK_GUI_H - -#include "../Common/Update.h" -#include "../Common/ArchiveOpenCallback.h" - -#include "UpdateCallbackGUI2.h" - -class CUpdateCallbackGUI: - public IOpenCallbackUI, - public IUpdateCallbackUI2, - public CUpdateCallbackGUI2 -{ -public: - // CUpdateCallbackGUI(); - // ~CUpdateCallbackGUI(); - - bool AskPassword; - - void Init(); - - CUpdateCallbackGUI(): - AskPassword(false) - {} - - INTERFACE_IUpdateCallbackUI2(;) - INTERFACE_IOpenCallbackUI(;) - - FStringVector FailedFiles; -}; - -#endif +// UpdateCallbackGUI.h + +#ifndef __UPDATE_CALLBACK_GUI_H +#define __UPDATE_CALLBACK_GUI_H + +#include "../Common/Update.h" +#include "../Common/ArchiveOpenCallback.h" + +#include "UpdateCallbackGUI2.h" + +class CUpdateCallbackGUI: + public IOpenCallbackUI, + public IUpdateCallbackUI2, + public CUpdateCallbackGUI2 +{ +public: + // CUpdateCallbackGUI(); + // ~CUpdateCallbackGUI(); + + bool AskPassword; + + void Init(); + + CUpdateCallbackGUI(): + AskPassword(false) + {} + + INTERFACE_IUpdateCallbackUI2(;) + INTERFACE_IOpenCallbackUI(;) + + FStringVector FailedFiles; +}; + +#endif diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp index 60c7e2d81..4eeead7d1 100644 --- a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp +++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp @@ -1,59 +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 < 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; -} +// 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 < 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 index 017e1c0bd..2b30ad217 100644 --- a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h +++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h @@ -1,35 +1,35 @@ -// UpdateCallbackGUI2.h - -#ifndef __UPDATE_CALLBACK_GUI2_H -#define __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) - {} - - // ~CUpdateCallbackGUI2(); - void Init(); - - CProgressDialog *ProgressDialog; - - HRESULT SetOperation_Base(UInt32 notifyOp, const wchar_t *name, bool isDir); - HRESULT ShowAskPasswordDialog(); -}; - -#endif +// UpdateCallbackGUI2.h + +#ifndef __UPDATE_CALLBACK_GUI2_H +#define __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) + {} + + // ~CUpdateCallbackGUI2(); + 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 index 280ed78af..2e738d3a9 100644 --- a/CPP/7zip/UI/GUI/UpdateGUI.cpp +++ b/CPP/7zip/UI/GUI/UpdateGUI.cpp @@ -1,485 +1,485 @@ -// 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(); -public: - CCodecs *codecs; - const CObjectVector *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 (ei.SystemError != S_OK && ei.SystemError != E_FAIL && ei.SystemError != E_ABORT) - return ei.SystemError; - return res; -} - -static void AddProp(CObjectVector &properties, const char *name, const UString &value) -{ - CProperty prop; - prop.Name = name; - prop.Value = value; - properties.Add(prop); -} - -static void AddProp(CObjectVector &properties, const char *name, UInt32 value) -{ - char tmp[32]; - ConvertUInt64ToString(value, tmp); - AddProp(properties, name, UString(tmp)); -} - -static void AddProp(CObjectVector &properties, const char *name, bool value) -{ - AddProp(properties, name, UString(value ? "on": "off")); -} - -static bool IsThereMethodOverride(bool is7z, const UString &propertiesString) -{ - UStringVector strings; - SplitString(propertiesString, 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 &properties, - const UString &propertiesString) -{ - UStringVector strings; - SplitString(propertiesString, strings); - FOR_VECTOR (i, strings) - { - const UString &s = strings[i]; - CProperty property; - int index = s.Find(L'='); - if (index < 0) - property.Name = s; - else - { - property.Name.SetFrom(s, index); - property.Value = s.Ptr(index + 1); - } - properties.Add(property); - } -} - -static UString GetNumInBytesString(UInt64 v) -{ - char s[32]; - ConvertUInt64ToString(v, s); - size_t len = MyStringLen(s); - s[len++] = 'B'; - s[len] = '\0'; - return UString(s); -} - -static void SetOutProperties( - CObjectVector &properties, - bool is7z, - UInt32 level, - bool setMethod, - const UString &method, - UInt32 dictionary, - bool orderMode, - UInt32 order, - bool solidIsSpecified, UInt64 solidBlockSize, - bool multiThreadIsAllowed, UInt32 numThreads, - const UString &encryptionMethod, - bool encryptHeadersIsAllowed, bool encryptHeaders, - bool /* sfxMode */) -{ - if (level != (UInt32)(Int32)-1) - AddProp(properties, "x", (UInt32)level); - if (setMethod) - { - if (!method.IsEmpty()) - AddProp(properties, is7z ? "0": "m", method); - if (dictionary != (UInt32)(Int32)-1) - { - AString name; - if (is7z) - name = "0"; - name += (orderMode ? "mem" : "d"); - AddProp(properties, name, GetNumInBytesString(dictionary)); - } - if (order != (UInt32)(Int32)-1) - { - AString name; - if (is7z) - name = "0"; - name += (orderMode ? "o" : "fb"); - AddProp(properties, name, (UInt32)order); - } - } - - if (!encryptionMethod.IsEmpty()) - AddProp(properties, "em", encryptionMethod); - - if (encryptHeadersIsAllowed) - AddProp(properties, "he", encryptHeaders); - if (solidIsSpecified) - AddProp(properties, "s", GetNumInBytesString(solidBlockSize)); - if (multiThreadIsAllowed) - AddProp(properties, "mt", numThreads); -} - -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 < ARRAY_SIZE(g_UpdateMode_Pairs); i++) - if (actionSet.IsEqualTo(*g_UpdateMode_Pairs[i].ActionSet)) - return i; - return -1; -} - -static int FindUpdateMode(NCompressDialog::NUpdateMode::EEnum mode) -{ - for (unsigned i = 0; i < ARRAY_SIZE(g_UpdateMode_Pairs); i++) - if (mode == g_UpdateMode_Pairs[i].UpdateMode) - return i; - return -1; -} - - -static HRESULT ShowDialog( - CCodecs *codecs, - const CObjectVector &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(); - } - } - } - } - - - #if defined(_WIN32) && !defined(UNDER_CE) - CCurrentDirRestorer curDirRestorer; - #endif - CCompressDialog dialog; - NCompressDialog::CInfo &di = dialog.Info; - dialog.ArcFormats = &codecs->Formats; - - 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.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 (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; - } - - 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; - - #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; - - options.MethodMode.Properties.Clear(); - - bool is7z = archiverInfo.Name.IsEqualTo_Ascii_NoCase("7z"); - bool methodOverride = IsThereMethodOverride(is7z, di.Options); - - SetOutProperties( - options.MethodMode.Properties, - is7z, - di.Level, - !methodOverride, - di.Method, - di.Dictionary, - di.OrderMode, di.Order, - di.SolidIsSpecified, di.SolidBlockSize, - di.MultiThreadIsAllowed, di.NumThreads, - di.EncryptionMethod, - di.EncryptHeadersIsAllowed, di.EncryptHeaders, - di.SFXMode); - - options.OpenShareForWrite = di.OpenShareForWrite; - ParseAndAddPropertires(options.MethodMode.Properties, di.Options); - - 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 &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 (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; -} +// 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(); +public: + CCodecs *codecs; + const CObjectVector *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 (ei.SystemError != S_OK && ei.SystemError != E_FAIL && ei.SystemError != E_ABORT) + return ei.SystemError; + return res; +} + +static void AddProp(CObjectVector &properties, const char *name, const UString &value) +{ + CProperty prop; + prop.Name = name; + prop.Value = value; + properties.Add(prop); +} + +static void AddProp(CObjectVector &properties, const char *name, UInt32 value) +{ + char tmp[32]; + ConvertUInt64ToString(value, tmp); + AddProp(properties, name, UString(tmp)); +} + +static void AddProp(CObjectVector &properties, const char *name, bool value) +{ + AddProp(properties, name, UString(value ? "on": "off")); +} + +static bool IsThereMethodOverride(bool is7z, const UString &propertiesString) +{ + UStringVector strings; + SplitString(propertiesString, 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 &properties, + const UString &propertiesString) +{ + UStringVector strings; + SplitString(propertiesString, strings); + FOR_VECTOR (i, strings) + { + const UString &s = strings[i]; + CProperty property; + int index = s.Find(L'='); + if (index < 0) + property.Name = s; + else + { + property.Name.SetFrom(s, index); + property.Value = s.Ptr(index + 1); + } + properties.Add(property); + } +} + +static UString GetNumInBytesString(UInt64 v) +{ + char s[32]; + ConvertUInt64ToString(v, s); + size_t len = MyStringLen(s); + s[len++] = 'B'; + s[len] = '\0'; + return UString(s); +} + +static void SetOutProperties( + CObjectVector &properties, + bool is7z, + UInt32 level, + bool setMethod, + const UString &method, + UInt32 dictionary, + bool orderMode, + UInt32 order, + bool solidIsSpecified, UInt64 solidBlockSize, + bool multiThreadIsAllowed, UInt32 numThreads, + const UString &encryptionMethod, + bool encryptHeadersIsAllowed, bool encryptHeaders, + bool /* sfxMode */) +{ + if (level != (UInt32)(Int32)-1) + AddProp(properties, "x", (UInt32)level); + if (setMethod) + { + if (!method.IsEmpty()) + AddProp(properties, is7z ? "0": "m", method); + if (dictionary != (UInt32)(Int32)-1) + { + AString name; + if (is7z) + name = "0"; + name += (orderMode ? "mem" : "d"); + AddProp(properties, name, GetNumInBytesString(dictionary)); + } + if (order != (UInt32)(Int32)-1) + { + AString name; + if (is7z) + name = "0"; + name += (orderMode ? "o" : "fb"); + AddProp(properties, name, (UInt32)order); + } + } + + if (!encryptionMethod.IsEmpty()) + AddProp(properties, "em", encryptionMethod); + + if (encryptHeadersIsAllowed) + AddProp(properties, "he", encryptHeaders); + if (solidIsSpecified) + AddProp(properties, "s", GetNumInBytesString(solidBlockSize)); + if (multiThreadIsAllowed) + AddProp(properties, "mt", numThreads); +} + +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 < ARRAY_SIZE(g_UpdateMode_Pairs); i++) + if (actionSet.IsEqualTo(*g_UpdateMode_Pairs[i].ActionSet)) + return i; + return -1; +} + +static int FindUpdateMode(NCompressDialog::NUpdateMode::EEnum mode) +{ + for (unsigned i = 0; i < ARRAY_SIZE(g_UpdateMode_Pairs); i++) + if (mode == g_UpdateMode_Pairs[i].UpdateMode) + return i; + return -1; +} + + +static HRESULT ShowDialog( + CCodecs *codecs, + const CObjectVector &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(); + } + } + } + } + + + #if defined(_WIN32) && !defined(UNDER_CE) + CCurrentDirRestorer curDirRestorer; + #endif + CCompressDialog dialog; + NCompressDialog::CInfo &di = dialog.Info; + dialog.ArcFormats = &codecs->Formats; + + 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.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 (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; + } + + 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; + + #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; + + options.MethodMode.Properties.Clear(); + + bool is7z = archiverInfo.Name.IsEqualTo_Ascii_NoCase("7z"); + bool methodOverride = IsThereMethodOverride(is7z, di.Options); + + SetOutProperties( + options.MethodMode.Properties, + is7z, + di.Level, + !methodOverride, + di.Method, + di.Dictionary, + di.OrderMode, di.Order, + di.SolidIsSpecified, di.SolidBlockSize, + di.MultiThreadIsAllowed, di.NumThreads, + di.EncryptionMethod, + di.EncryptHeadersIsAllowed, di.EncryptHeaders, + di.SFXMode); + + options.OpenShareForWrite = di.OpenShareForWrite; + ParseAndAddPropertires(options.MethodMode.Properties, di.Options); + + 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 &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 (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 index f2e8085de..d1880de0a 100644 --- a/CPP/7zip/UI/GUI/UpdateGUI.h +++ b/CPP/7zip/UI/GUI/UpdateGUI.h @@ -1,33 +1,33 @@ -// GUI/UpdateGUI.h - -#ifndef __UPDATE_GUI_H -#define __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 &formatIndices, - const UString &cmdArcPath2, - NWildcard::CCensor &censor, - CUpdateOptions &options, - bool showDialog, - bool &messageWasDisplayed, - CUpdateCallbackGUI *callback, - HWND hwndParent = NULL); - -#endif +// GUI/UpdateGUI.h + +#ifndef __UPDATE_GUI_H +#define __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 &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 index c608acdc4..f8416022c 100644 --- a/CPP/7zip/UI/GUI/makefile +++ b/CPP/7zip/UI/GUI/makefile @@ -1,144 +1,144 @@ -PROG = 7zG.exe -CFLAGS = $(CFLAGS) \ - -DLANG \ - -DEXTERNAL_CODECS \ - -!IFDEF UNDER_CE -LIBS = $(LIBS) ceshell.lib Commctrl.lib -!ELSE -LIBS = $(LIBS) comctl32.lib htmlhelp.lib comdlg32.lib gdi32.lib -CFLAGS = $(CFLAGS) -DWIN_LONG_PATH -DSUPPORT_DEVICE_FILE -D_7ZIP_LARGE_PAGES -!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\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\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\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\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" +PROG = 7zG.exe +CFLAGS = $(CFLAGS) \ + -DLANG \ + -DEXTERNAL_CODECS \ + +!IFDEF UNDER_CE +LIBS = $(LIBS) ceshell.lib Commctrl.lib +!ELSE +LIBS = $(LIBS) comctl32.lib htmlhelp.lib comdlg32.lib gdi32.lib +CFLAGS = $(CFLAGS) -DWIN_LONG_PATH -DSUPPORT_DEVICE_FILE -D_7ZIP_LARGE_PAGES +!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\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\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\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\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 index 03a9f4199..04af8157c 100644 --- a/CPP/7zip/UI/GUI/resource.rc +++ b/CPP/7zip/UI/GUI/resource.rc @@ -1,25 +1,25 @@ -#include "../../MyVersionInfo.rc" -// #include - -#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" +#include "../../MyVersionInfo.rc" +// #include + +#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 152e71f8a..cd8829245 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 index 042154e62..49534f504 100644 --- a/CPP/7zip/UI/GUI/resource2.rc +++ b/CPP/7zip/UI/GUI/resource2.rc @@ -1,10 +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 +#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 index 4c33bb92b..c25737fa1 100644 --- a/CPP/7zip/UI/GUI/resource3.h +++ b/CPP/7zip/UI/GUI/resource3.h @@ -1,10 +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 +#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 index 9f533be72..cfc8bc35e 100644 --- a/CPP/7zip/UI/GUI/resource3.rc +++ b/CPP/7zip/UI/GUI/resource3.rc @@ -1,15 +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 +#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 index 9d51814f3..1b0cdbe18 100644 --- a/CPP/7zip/UI/makefile +++ b/CPP/7zip/UI/makefile @@ -1,12 +1,12 @@ -DIRS = \ - Client7z\~ \ - Console\~ \ - Explorer\~ \ - Far\~ \ - FileManager\~ \ - GUI\~ \ - -all: $(DIRS) - -$(DIRS): -!include "../SubBuild.mak" +DIRS = \ + Client7z\~ \ + Console\~ \ + Explorer\~ \ + Far\~ \ + FileManager\~ \ + GUI\~ \ + +all: $(DIRS) + +$(DIRS): +!include "../SubBuild.mak" diff --git a/CPP/7zip/makefile b/CPP/7zip/makefile index 422d2d25c..9d31e6bdc 100644 --- a/CPP/7zip/makefile +++ b/CPP/7zip/makefile @@ -1,10 +1,10 @@ -DIRS = \ - UI\~ \ - Bundles\~ \ - -all: $(DIRS) - -$(DIRS): - cd $(@D) - $(MAKE) -nologo - cd .. +DIRS = \ + UI\~ \ + Bundles\~ \ + +all: $(DIRS) + +$(DIRS): + cd $(@D) + $(MAKE) -nologo + cd .. diff --git a/CPP/Build.mak b/CPP/Build.mak index 0025656af..135183749 100644 --- a/CPP/Build.mak +++ b/CPP/Build.mak @@ -1,79 +1,79 @@ - -!IFNDEF MY_NO_UNICODE -CFLAGS = $(CFLAGS) -DUNICODE -D_UNICODE -!ENDIF - -!IFNDEF O -!IFDEF PLATFORM -O=$(PLATFORM) -!ELSE -O=o -!ENDIF -!ENDIF - -LIBS = $(LIBS) oleaut32.lib ole32.lib user32.lib advapi32.lib shell32.lib - -CFLAGS = $(CFLAGS) -c /nologo /Fo$O/ /W4 /WX /EHsc /MT /MP /GR- /GL /Gw /Gy - -!IFDEF MY_CONSOLE -CFLAGS = $(CFLAGS) -D_CONSOLE -!ENDIF - -CFLAGS_O1 = $(CFLAGS) /O1 -CFLAGS_O2 = $(CFLAGS) /O2 /Ob3 - -LFLAGS = $(LFLAGS) /nologo /LTCG /LARGEADDRESSAWARE - -!IFDEF DEF_FILE -LFLAGS = $(LFLAGS) /DLL /DEF:$(DEF_FILE) -!ENDIF - -PROGPATH = $O\$(PROG) - -!IF "$(PLATFORM)" == "x64" -MY_ML = ml64 /Dx64 /WX -!ELSEIF "$(PLATFORM)" == "arm" -MY_ML = armasm /WX -!ELSE -MY_ML = ml /WX -!ENDIF - -!IF "$(PLATFORM)" == "arm" -COMPL_ASM = $(MY_ML) /nologo $** $O/$(*B).obj -!ELSE -COMPL_ASM = $(MY_ML) /nologo -c /Fo$O/ $** -!ENDIF - -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) $< - -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) /nologo /fo$@ $** -!ENDIF -$O\StdAfx.obj: $(*B).cpp - $(COMPL_PCH) + +!IFNDEF MY_NO_UNICODE +CFLAGS = $(CFLAGS) -DUNICODE -D_UNICODE +!ENDIF + +!IFNDEF O +!IFDEF PLATFORM +O=$(PLATFORM) +!ELSE +O=o +!ENDIF +!ENDIF + +LIBS = $(LIBS) oleaut32.lib ole32.lib user32.lib advapi32.lib shell32.lib + +CFLAGS = $(CFLAGS) -c /nologo /Fo$O/ /W4 /WX /EHsc /MT /MP /GR- /GL /Gw /Gy + +!IFDEF MY_CONSOLE +CFLAGS = $(CFLAGS) -D_CONSOLE +!ENDIF + +CFLAGS_O1 = $(CFLAGS) /O1 +CFLAGS_O2 = $(CFLAGS) /O2 /Ob3 + +LFLAGS = $(LFLAGS) /nologo /LTCG /LARGEADDRESSAWARE + +!IFDEF DEF_FILE +LFLAGS = $(LFLAGS) /DLL /DEF:$(DEF_FILE) +!ENDIF + +PROGPATH = $O\$(PROG) + +!IF "$(PLATFORM)" == "x64" +MY_ML = ml64 /Dx64 /WX +!ELSEIF "$(PLATFORM)" == "arm" +MY_ML = armasm /WX +!ELSE +MY_ML = ml /WX +!ENDIF + +!IF "$(PLATFORM)" == "arm" +COMPL_ASM = $(MY_ML) /nologo $** $O/$(*B).obj +!ELSE +COMPL_ASM = $(MY_ML) /nologo -c /Fo$O/ $** +!ENDIF + +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) $< + +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) /nologo /fo$@ $** +!ENDIF +$O\StdAfx.obj: $(*B).cpp + $(COMPL_PCH) diff --git a/CPP/Common/AutoPtr.h b/CPP/Common/AutoPtr.h index e53fb7f5d..006d31551 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 CMyAutoPtr -{ - T *_p; -public: - CMyAutoPtr(T *p = 0) : _p(p) {} - CMyAutoPtr(CMyAutoPtr& p): _p(p.release()) {} - CMyAutoPtr& operator=(CMyAutoPtr& 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 __COMMON_AUTOPTR_H +#define __COMMON_AUTOPTR_H + +template class CMyAutoPtr +{ + T *_p; +public: + CMyAutoPtr(T *p = 0) : _p(p) {} + CMyAutoPtr(CMyAutoPtr& p): _p(p.release()) {} + CMyAutoPtr& operator=(CMyAutoPtr& p) + { + reset(p.release()); + return (*this); + } + ~CMyAutoPtr() { delete _p; } + T& operator*() const { return *_p; } + // T* operator->() const { return (&**this); } + T* get() const { return _p; } + T* release() + { + T *tmp = _p; + _p = 0; + return tmp; + } + void reset(T* p = 0) + { + if (p != _p) + delete _p; + _p = p; + } +}; + +#endif diff --git a/CPP/Common/CRC.cpp b/CPP/Common/CRC.cpp index 6ac52c4c1..9a9f81fb7 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" + +struct CCRCTableInit { CCRCTableInit() { CrcGenerateTable(); } } g_CRCTableInit; diff --git a/CPP/Common/C_FileIO.cpp b/CPP/Common/C_FileIO.cpp index d68a42779..7c6293902 100644 --- a/CPP/Common/C_FileIO.cpp +++ b/CPP/Common/C_FileIO.cpp @@ -1,92 +1,92 @@ -// Common/C_FileIO.cpp - -#include "C_FileIO.h" - -#include -#ifdef _WIN32 -#include -#else -#include -#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 "C_FileIO.h" + +#include +#ifdef _WIN32 +#include +#else +#include +#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); +} + +}}} diff --git a/CPP/Common/C_FileIO.h b/CPP/Common/C_FileIO.h index 4c400b41f..ff4ec162c 100644 --- a/CPP/Common/C_FileIO.h +++ b/CPP/Common/C_FileIO.h @@ -1,53 +1,53 @@ -// Common/C_FileIO.h - -#ifndef __COMMON_C_FILEIO_H -#define __COMMON_C_FILEIO_H - -#include -#include - -#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 __COMMON_C_FILEIO_H +#define __COMMON_C_FILEIO_H + +#include +#include + +#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 diff --git a/CPP/Common/ComTry.h b/CPP/Common/ComTry.h index e6b514d44..297c407ba 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 __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 diff --git a/CPP/Common/CommandLineParser.cpp b/CPP/Common/CommandLineParser.cpp index 94aabce6d..145f3435a 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 = 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; +} + +} diff --git a/CPP/Common/CommandLineParser.h b/CPP/Common/CommandLineParser.h index ec6336c81..1dbdd4ea7 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 __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 diff --git a/CPP/Common/Common.h b/CPP/Common/Common.h index c1ecc7ed4..5430a92d4 100644 --- a/CPP/Common/Common.h +++ b/CPP/Common/Common.h @@ -1,43 +1,43 @@ -// 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 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 + +#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 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 diff --git a/CPP/Common/CrcReg.cpp b/CPP/Common/CrcReg.cpp index 1d9d00903..4b662f522 100644 --- a/CPP/Common/CrcReg.cpp +++ b/CPP/Common/CrcReg.cpp @@ -1,98 +1,98 @@ -// 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 + +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) diff --git a/CPP/Common/Defs.h b/CPP/Common/Defs.h index 941609813..1fbd78bda 100644 --- a/CPP/Common/Defs.h +++ b/CPP/Common/Defs.h @@ -1,15 +1,15 @@ -// Common/Defs.h - -#ifndef __COMMON_DEFS_H -#define __COMMON_DEFS_H - -template inline T MyMin(T a, T b) { return a < b ? a : b; } -template inline T MyMax(T a, T b) { return a > b ? a : b; } - -template 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 __COMMON_DEFS_H +#define __COMMON_DEFS_H + +template inline T MyMin(T a, T b) { return a < b ? a : b; } +template inline T MyMax(T a, T b) { return a > b ? a : b; } + +template 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 diff --git a/CPP/Common/DynLimBuf.cpp b/CPP/Common/DynLimBuf.cpp index 6e5227156..1d1d99dc2 100644 --- a/CPP/Common/DynLimBuf.cpp +++ b/CPP/Common/DynLimBuf.cpp @@ -1,93 +1,93 @@ -// Common/DynLimBuf.cpp - -#include "StdAfx.h" - -#include "DynLimBuf.h" -#include "MyString.h" - -CDynLimBuf::CDynLimBuf(size_t limit) throw() -{ - _chars = 0; - _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++] = 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; -} +// Common/DynLimBuf.cpp + +#include "StdAfx.h" + +#include "DynLimBuf.h" +#include "MyString.h" + +CDynLimBuf::CDynLimBuf(size_t limit) throw() +{ + _chars = 0; + _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++] = 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 index a47da9103..e80a7e7c5 100644 --- a/CPP/Common/DynLimBuf.h +++ b/CPP/Common/DynLimBuf.h @@ -1,41 +1,41 @@ -// Common/DynLimBuf.h - -#ifndef __COMMON_DYN_LIM_BUF_H -#define __COMMON_DYN_LIM_BUF_H - -#include - -#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 +// Common/DynLimBuf.h + +#ifndef __COMMON_DYN_LIM_BUF_H +#define __COMMON_DYN_LIM_BUF_H + +#include + +#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 16c925010..44e3df7fd 100644 --- a/CPP/Common/DynamicBuffer.h +++ b/CPP/Common/DynamicBuffer.h @@ -1,64 +1,64 @@ -// Common/DynamicBuffer.h - -#ifndef __COMMON_DYNAMIC_BUFFER_H -#define __COMMON_DYNAMIC_BUFFER_H - -template 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 CByteDynamicBuffer; - -#endif +// Common/DynamicBuffer.h + +#ifndef __COMMON_DYNAMIC_BUFFER_H +#define __COMMON_DYNAMIC_BUFFER_H + +template 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 CByteDynamicBuffer; + +#endif diff --git a/CPP/Common/HashesReg.cpp b/CPP/Common/HashesReg.cpp index f3d9479fd..7b0ccbd9c 100644 --- a/CPP/Common/HashesReg.cpp +++ b/CPP/Common/HashesReg.cpp @@ -1,237 +1,237 @@ -// XXH32Reg.cpp - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" - -#define XXH_STATIC_LINKING_ONLY -#include "../../C/zstd/xxhash.h" -#include "../../C/hashes/md2.h" -#include "../../C/hashes/md4.h" -#include "../../C/hashes/md5.h" -#include "../../C/hashes/sha.h" - -#include "../Common/MyCom.h" -#include "../7zip/Common/RegisterCodec.h" - -// XXH32 -class CXXH32Hasher: - public IHasher, - public CMyUnknownImp -{ - XXH32_state_t *_ctx; - Byte mtDummy[1 << 7]; - -public: - CXXH32Hasher() { _ctx = XXH32_createState(); } - ~CXXH32Hasher() { XXH32_freeState(_ctx); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CXXH32Hasher::Init() throw() -{ - XXH32_reset(_ctx, 0); -} - -STDMETHODIMP_(void) CXXH32Hasher::Update(const void *data, UInt32 size) throw() -{ - XXH32_update(_ctx, data, size); -} - -STDMETHODIMP_(void) CXXH32Hasher::Final(Byte *digest) throw() -{ - UInt32 val = XXH32_digest(_ctx); - SetUi32(digest, val); -} - -REGISTER_HASHER(CXXH32Hasher, 0x203, "XXH32", 4) - -// XXH64 -class CXXH64Hasher: - public IHasher, - public CMyUnknownImp -{ - XXH64_state_t *_ctx; - Byte mtDummy[1 << 7]; - -public: - CXXH64Hasher() { _ctx = XXH64_createState(); } - ~CXXH64Hasher() { XXH64_freeState(_ctx); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CXXH64Hasher::Init() throw() -{ - XXH64_reset(_ctx, 0); -} - -STDMETHODIMP_(void) CXXH64Hasher::Update(const void *data, UInt32 size) throw() -{ - XXH64_update(_ctx, data, size); -} - -STDMETHODIMP_(void) CXXH64Hasher::Final(Byte *digest) throw() -{ - UInt64 val = XXH64_digest(_ctx); - SetUi64(digest, val); -} -REGISTER_HASHER(CXXH64Hasher, 0x204, "XXH64", 8) - -// MD2 -class CMD2Hasher: - public IHasher, - public CMyUnknownImp -{ - MD2_CTX _ctx; - Byte mtDummy[1 << 7]; - -public: - CMD2Hasher() { MD2_Init(&_ctx); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CMD2Hasher::Init() throw() -{ - MD2_Init(&_ctx); -} - -STDMETHODIMP_(void) CMD2Hasher::Update(const void *data, UInt32 size) throw() -{ - MD2_Update(&_ctx, (const Byte *)data, size); -} - -STDMETHODIMP_(void) CMD2Hasher::Final(Byte *digest) throw() -{ - MD2_Final(digest, &_ctx); -} -REGISTER_HASHER(CMD2Hasher, 0x205, "MD2", MD2_DIGEST_LENGTH) - -// MD4 -class CMD4Hasher: - public IHasher, - public CMyUnknownImp -{ - MD4_CTX _ctx; - Byte mtDummy[1 << 7]; - -public: - CMD4Hasher() { MD4_Init(&_ctx); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CMD4Hasher::Init() throw() -{ - MD4_Init(&_ctx); -} - -STDMETHODIMP_(void) CMD4Hasher::Update(const void *data, UInt32 size) throw() -{ - MD4_Update(&_ctx, (const Byte *)data, size); -} - -STDMETHODIMP_(void) CMD4Hasher::Final(Byte *digest) throw() -{ - MD4_Final(digest, &_ctx); -} -REGISTER_HASHER(CMD4Hasher, 0x206, "MD4", MD4_DIGEST_LENGTH) - -// MD5 -class CMD5Hasher: - public IHasher, - public CMyUnknownImp -{ - MD5_CTX _ctx; - Byte mtDummy[1 << 7]; - -public: - CMD5Hasher() { MD5_Init(&_ctx); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CMD5Hasher::Init() throw() -{ - MD5_Init(&_ctx); -} - -STDMETHODIMP_(void) CMD5Hasher::Update(const void *data, UInt32 size) throw() -{ - MD5_Update(&_ctx, (const Byte *)data, size); -} - -STDMETHODIMP_(void) CMD5Hasher::Final(Byte *digest) throw() -{ - MD5_Final(digest, &_ctx); -} -REGISTER_HASHER(CMD5Hasher, 0x207, "MD5", MD5_DIGEST_LENGTH) - -// SHA384 -class CSHA384Hasher: - public IHasher, - public CMyUnknownImp -{ - SHA384_CTX _ctx; - Byte mtDummy[1 << 7]; - -public: - CSHA384Hasher() { SHA384_Init(&_ctx); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CSHA384Hasher::Init() throw() -{ - SHA384_Init(&_ctx); -} - -STDMETHODIMP_(void) CSHA384Hasher::Update(const void *data, UInt32 size) throw() -{ - SHA384_Update(&_ctx, (const Byte *)data, size); -} - -STDMETHODIMP_(void) CSHA384Hasher::Final(Byte *digest) throw() -{ - SHA384_Final(digest, &_ctx); -} -REGISTER_HASHER(CSHA384Hasher, 0x208, "SHA384", SHA384_DIGEST_LENGTH) - -// SHA512 -class CSHA512Hasher: - public IHasher, - public CMyUnknownImp -{ - SHA512_CTX _ctx; - Byte mtDummy[1 << 7]; - -public: - CSHA512Hasher() { SHA512_Init(&_ctx); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CSHA512Hasher::Init() throw() -{ - SHA512_Init(&_ctx); -} - -STDMETHODIMP_(void) CSHA512Hasher::Update(const void *data, UInt32 size) throw() -{ - SHA512_Update(&_ctx, (const Byte *)data, size); -} - -STDMETHODIMP_(void) CSHA512Hasher::Final(Byte *digest) throw() -{ - SHA512_Final(digest, &_ctx); -} -REGISTER_HASHER(CSHA512Hasher, 0x209, "SHA512", SHA512_DIGEST_LENGTH) +// XXH32Reg.cpp + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +#define XXH_STATIC_LINKING_ONLY +#include "../../C/zstd/xxhash.h" +#include "../../C/hashes/md2.h" +#include "../../C/hashes/md4.h" +#include "../../C/hashes/md5.h" +#include "../../C/hashes/sha.h" + +#include "../Common/MyCom.h" +#include "../7zip/Common/RegisterCodec.h" + +// XXH32 +class CXXH32Hasher: + public IHasher, + public CMyUnknownImp +{ + XXH32_state_t *_ctx; + Byte mtDummy[1 << 7]; + +public: + CXXH32Hasher() { _ctx = XXH32_createState(); } + ~CXXH32Hasher() { XXH32_freeState(_ctx); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CXXH32Hasher::Init() throw() +{ + XXH32_reset(_ctx, 0); +} + +STDMETHODIMP_(void) CXXH32Hasher::Update(const void *data, UInt32 size) throw() +{ + XXH32_update(_ctx, data, size); +} + +STDMETHODIMP_(void) CXXH32Hasher::Final(Byte *digest) throw() +{ + UInt32 val = XXH32_digest(_ctx); + SetUi32(digest, val); +} + +REGISTER_HASHER(CXXH32Hasher, 0x203, "XXH32", 4) + +// XXH64 +class CXXH64Hasher: + public IHasher, + public CMyUnknownImp +{ + XXH64_state_t *_ctx; + Byte mtDummy[1 << 7]; + +public: + CXXH64Hasher() { _ctx = XXH64_createState(); } + ~CXXH64Hasher() { XXH64_freeState(_ctx); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CXXH64Hasher::Init() throw() +{ + XXH64_reset(_ctx, 0); +} + +STDMETHODIMP_(void) CXXH64Hasher::Update(const void *data, UInt32 size) throw() +{ + XXH64_update(_ctx, data, size); +} + +STDMETHODIMP_(void) CXXH64Hasher::Final(Byte *digest) throw() +{ + UInt64 val = XXH64_digest(_ctx); + SetUi64(digest, val); +} +REGISTER_HASHER(CXXH64Hasher, 0x204, "XXH64", 8) + +// MD2 +class CMD2Hasher: + public IHasher, + public CMyUnknownImp +{ + MD2_CTX _ctx; + Byte mtDummy[1 << 7]; + +public: + CMD2Hasher() { MD2_Init(&_ctx); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CMD2Hasher::Init() throw() +{ + MD2_Init(&_ctx); +} + +STDMETHODIMP_(void) CMD2Hasher::Update(const void *data, UInt32 size) throw() +{ + MD2_Update(&_ctx, (const Byte *)data, size); +} + +STDMETHODIMP_(void) CMD2Hasher::Final(Byte *digest) throw() +{ + MD2_Final(digest, &_ctx); +} +REGISTER_HASHER(CMD2Hasher, 0x205, "MD2", MD2_DIGEST_LENGTH) + +// MD4 +class CMD4Hasher: + public IHasher, + public CMyUnknownImp +{ + MD4_CTX _ctx; + Byte mtDummy[1 << 7]; + +public: + CMD4Hasher() { MD4_Init(&_ctx); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CMD4Hasher::Init() throw() +{ + MD4_Init(&_ctx); +} + +STDMETHODIMP_(void) CMD4Hasher::Update(const void *data, UInt32 size) throw() +{ + MD4_Update(&_ctx, (const Byte *)data, size); +} + +STDMETHODIMP_(void) CMD4Hasher::Final(Byte *digest) throw() +{ + MD4_Final(digest, &_ctx); +} +REGISTER_HASHER(CMD4Hasher, 0x206, "MD4", MD4_DIGEST_LENGTH) + +// MD5 +class CMD5Hasher: + public IHasher, + public CMyUnknownImp +{ + MD5_CTX _ctx; + Byte mtDummy[1 << 7]; + +public: + CMD5Hasher() { MD5_Init(&_ctx); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CMD5Hasher::Init() throw() +{ + MD5_Init(&_ctx); +} + +STDMETHODIMP_(void) CMD5Hasher::Update(const void *data, UInt32 size) throw() +{ + MD5_Update(&_ctx, (const Byte *)data, size); +} + +STDMETHODIMP_(void) CMD5Hasher::Final(Byte *digest) throw() +{ + MD5_Final(digest, &_ctx); +} +REGISTER_HASHER(CMD5Hasher, 0x207, "MD5", MD5_DIGEST_LENGTH) + +// SHA384 +class CSHA384Hasher: + public IHasher, + public CMyUnknownImp +{ + SHA384_CTX _ctx; + Byte mtDummy[1 << 7]; + +public: + CSHA384Hasher() { SHA384_Init(&_ctx); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CSHA384Hasher::Init() throw() +{ + SHA384_Init(&_ctx); +} + +STDMETHODIMP_(void) CSHA384Hasher::Update(const void *data, UInt32 size) throw() +{ + SHA384_Update(&_ctx, (const Byte *)data, size); +} + +STDMETHODIMP_(void) CSHA384Hasher::Final(Byte *digest) throw() +{ + SHA384_Final(digest, &_ctx); +} +REGISTER_HASHER(CSHA384Hasher, 0x208, "SHA384", SHA384_DIGEST_LENGTH) + +// SHA512 +class CSHA512Hasher: + public IHasher, + public CMyUnknownImp +{ + SHA512_CTX _ctx; + Byte mtDummy[1 << 7]; + +public: + CSHA512Hasher() { SHA512_Init(&_ctx); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CSHA512Hasher::Init() throw() +{ + SHA512_Init(&_ctx); +} + +STDMETHODIMP_(void) CSHA512Hasher::Update(const void *data, UInt32 size) throw() +{ + SHA512_Update(&_ctx, (const Byte *)data, size); +} + +STDMETHODIMP_(void) CSHA512Hasher::Final(Byte *digest) throw() +{ + SHA512_Final(digest, &_ctx); +} +REGISTER_HASHER(CSHA512Hasher, 0x209, "SHA512", SHA512_DIGEST_LENGTH) diff --git a/CPP/Common/IntToString.cpp b/CPP/Common/IntToString.cpp index da627caef..05b1c148f 100644 --- a/CPP/Common/IntToString.cpp +++ b/CPP/Common/IntToString.cpp @@ -1,193 +1,193 @@ -// 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++ = 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; +} diff --git a/CPP/Common/IntToString.h b/CPP/Common/IntToString.h index 07b67c31f..d4110d1de 100644 --- a/CPP/Common/IntToString.h +++ b/CPP/Common/IntToString.h @@ -1,28 +1,28 @@ -// 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 __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 diff --git a/CPP/Common/Lang.cpp b/CPP/Common/Lang.cpp index b5468b4f2..e959ba48f 100644 --- a/CPP/Common/Lang.cpp +++ b/CPP/Common/Lang.cpp @@ -1,163 +1,163 @@ -// 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(); - delete []_text; - _text = 0; -} - -static const char * const kLangSignature = ";!@Lang2@!UTF-8!"; - -bool CLang::OpenFromString(const AString &s2) -{ - UString s; - if (!ConvertUTF8ToUnicode(s2, s)) - return false; - unsigned i = 0; - if (s.IsEmpty()) - return false; - if (s[0] == 0xFEFF) - i++; - - for (const char *p = kLangSignature;; i++) - { - Byte c = *p++; - if (c == 0) - break; - if (s[i] != c) - return false; - } - - _text = new wchar_t[s.Len() - i + 1]; - wchar_t *text = _text; - - Int32 id = -100; - UInt32 pos = 0; - - while (i < s.Len()) - { - unsigned start = pos; - do - { - wchar_t c = s[i++]; - if (c == '\n') - break; - if (c == '\\') - { - if (i == s.Len()) - return false; - c = s[i++]; - 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 (i < s.Len()); - - { - unsigned j = start; - for (; j < pos; j++) - if (text[j] != ' ') - break; - if (j == pos) - { - id++; - continue; - } - } - if (text[start] == ';') - { - pos = start; - id++; - continue; - } - - text[pos++] = 0; - const wchar_t *end; - 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; - unsigned len = (unsigned)length; - char *p = s.GetBuf(len); - UInt32 processed; - if (!file.Read(p, len, processed)) - return false; - file.Close(); - if (len != processed) - return false; - - char *p2 = p; - for (unsigned i = 0; i < len; i++) - { - 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() -{ - int index = _ids.FindInSorted(id); - if (index < 0) - return NULL; - return _text + (size_t)_offsets[index]; -} +// 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(); + delete []_text; + _text = 0; +} + +static const char * const kLangSignature = ";!@Lang2@!UTF-8!"; + +bool CLang::OpenFromString(const AString &s2) +{ + UString s; + if (!ConvertUTF8ToUnicode(s2, s)) + return false; + unsigned i = 0; + if (s.IsEmpty()) + return false; + if (s[0] == 0xFEFF) + i++; + + for (const char *p = kLangSignature;; i++) + { + Byte c = *p++; + if (c == 0) + break; + if (s[i] != c) + return false; + } + + _text = new wchar_t[s.Len() - i + 1]; + wchar_t *text = _text; + + Int32 id = -100; + UInt32 pos = 0; + + while (i < s.Len()) + { + unsigned start = pos; + do + { + wchar_t c = s[i++]; + if (c == '\n') + break; + if (c == '\\') + { + if (i == s.Len()) + return false; + c = s[i++]; + 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 (i < s.Len()); + + { + unsigned j = start; + for (; j < pos; j++) + if (text[j] != ' ') + break; + if (j == pos) + { + id++; + continue; + } + } + if (text[start] == ';') + { + pos = start; + id++; + continue; + } + + text[pos++] = 0; + const wchar_t *end; + 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; + unsigned len = (unsigned)length; + char *p = s.GetBuf(len); + UInt32 processed; + if (!file.Read(p, len, processed)) + return false; + file.Close(); + if (len != processed) + return false; + + char *p2 = p; + for (unsigned i = 0; i < len; i++) + { + 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() +{ + int index = _ids.FindInSorted(id); + if (index < 0) + return NULL; + return _text + (size_t)_offsets[index]; +} diff --git a/CPP/Common/Lang.h b/CPP/Common/Lang.h index e95de6859..cc66677d4 100644 --- a/CPP/Common/Lang.h +++ b/CPP/Common/Lang.h @@ -1,23 +1,23 @@ -// Common/Lang.h - -#ifndef __COMMON_LANG_H -#define __COMMON_LANG_H - -#include "MyString.h" - -class CLang -{ - wchar_t *_text; - CRecordVector _ids; - CRecordVector _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 __COMMON_LANG_H +#define __COMMON_LANG_H + +#include "MyString.h" + +class CLang +{ + wchar_t *_text; + CRecordVector _ids; + CRecordVector _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 diff --git a/CPP/Common/ListFileUtils.cpp b/CPP/Common/ListFileUtils.cpp index 2fdde6dd0..edd37eb13 100644 --- a/CPP/Common/ListFileUtils.cpp +++ b/CPP/Common/ListFileUtils.cpp @@ -1,132 +1,132 @@ -// 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 "../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; +} diff --git a/CPP/Common/ListFileUtils.h b/CPP/Common/ListFileUtils.h index a4f0d167f..a91e4b112 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 __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 diff --git a/CPP/Common/Md2Reg.cpp b/CPP/Common/Md2Reg.cpp index 7fea37934..1c19b5d2c 100644 --- a/CPP/Common/Md2Reg.cpp +++ b/CPP/Common/Md2Reg.cpp @@ -1,43 +1,43 @@ -// Md2Reg.cpp /TR 2018-11-02 - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" - -EXTERN_C_BEGIN -#include "../../C/hashes/md2.h" -EXTERN_C_END - -#include "../Common/MyCom.h" -#include "../7zip/Common/RegisterCodec.h" - -// MD2 -class CMD2Hasher: - public IHasher, - public CMyUnknownImp -{ - MD2_CTX _ctx; - Byte mtDummy[1 << 7]; - -public: - CMD2Hasher() { MD2_Init(&_ctx); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CMD2Hasher::Init() throw() -{ - MD2_Init(&_ctx); -} - -STDMETHODIMP_(void) CMD2Hasher::Update(const void *data, UInt32 size) throw() -{ - MD2_Update(&_ctx, (const Byte *)data, size); -} - -STDMETHODIMP_(void) CMD2Hasher::Final(Byte *digest) throw() -{ - MD2_Final(digest, &_ctx); -} -REGISTER_HASHER(CMD2Hasher, 0x205, "MD2", MD2_DIGEST_LENGTH) +// Md2Reg.cpp /TR 2018-11-02 + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +EXTERN_C_BEGIN +#include "../../C/hashes/md2.h" +EXTERN_C_END + +#include "../Common/MyCom.h" +#include "../7zip/Common/RegisterCodec.h" + +// MD2 +class CMD2Hasher: + public IHasher, + public CMyUnknownImp +{ + MD2_CTX _ctx; + Byte mtDummy[1 << 7]; + +public: + CMD2Hasher() { MD2_Init(&_ctx); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CMD2Hasher::Init() throw() +{ + MD2_Init(&_ctx); +} + +STDMETHODIMP_(void) CMD2Hasher::Update(const void *data, UInt32 size) throw() +{ + MD2_Update(&_ctx, (const Byte *)data, size); +} + +STDMETHODIMP_(void) CMD2Hasher::Final(Byte *digest) throw() +{ + MD2_Final(digest, &_ctx); +} +REGISTER_HASHER(CMD2Hasher, 0x205, "MD2", MD2_DIGEST_LENGTH) diff --git a/CPP/Common/Md4Reg.cpp b/CPP/Common/Md4Reg.cpp index 2b83f7d87..26c4d0b03 100644 --- a/CPP/Common/Md4Reg.cpp +++ b/CPP/Common/Md4Reg.cpp @@ -1,43 +1,43 @@ -// Md4Reg.cpp /TR 2018-11-02 - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" - -EXTERN_C_BEGIN -#include "../../C/hashes/md4.h" -EXTERN_C_END - -#include "../Common/MyCom.h" -#include "../7zip/Common/RegisterCodec.h" - -// MD4 -class CMD4Hasher: - public IHasher, - public CMyUnknownImp -{ - MD4_CTX _ctx; - Byte mtDummy[1 << 7]; - -public: - CMD4Hasher() { MD4_Init(&_ctx); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CMD4Hasher::Init() throw() -{ - MD4_Init(&_ctx); -} - -STDMETHODIMP_(void) CMD4Hasher::Update(const void *data, UInt32 size) throw() -{ - MD4_Update(&_ctx, (const Byte *)data, size); -} - -STDMETHODIMP_(void) CMD4Hasher::Final(Byte *digest) throw() -{ - MD4_Final(digest, &_ctx); -} -REGISTER_HASHER(CMD4Hasher, 0x206, "MD4", MD4_DIGEST_LENGTH) +// Md4Reg.cpp /TR 2018-11-02 + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +EXTERN_C_BEGIN +#include "../../C/hashes/md4.h" +EXTERN_C_END + +#include "../Common/MyCom.h" +#include "../7zip/Common/RegisterCodec.h" + +// MD4 +class CMD4Hasher: + public IHasher, + public CMyUnknownImp +{ + MD4_CTX _ctx; + Byte mtDummy[1 << 7]; + +public: + CMD4Hasher() { MD4_Init(&_ctx); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CMD4Hasher::Init() throw() +{ + MD4_Init(&_ctx); +} + +STDMETHODIMP_(void) CMD4Hasher::Update(const void *data, UInt32 size) throw() +{ + MD4_Update(&_ctx, (const Byte *)data, size); +} + +STDMETHODIMP_(void) CMD4Hasher::Final(Byte *digest) throw() +{ + MD4_Final(digest, &_ctx); +} +REGISTER_HASHER(CMD4Hasher, 0x206, "MD4", MD4_DIGEST_LENGTH) diff --git a/CPP/Common/Md5Reg.cpp b/CPP/Common/Md5Reg.cpp index 853c78d99..c13bd1e9d 100644 --- a/CPP/Common/Md5Reg.cpp +++ b/CPP/Common/Md5Reg.cpp @@ -1,43 +1,43 @@ -// Md5Reg.cpp /TR 2018-11-02 - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" - -EXTERN_C_BEGIN -#include "../../C/hashes/md5.h" -EXTERN_C_END - -#include "../Common/MyCom.h" -#include "../7zip/Common/RegisterCodec.h" - -// MD5 -class CMD5Hasher: - public IHasher, - public CMyUnknownImp -{ - MD5_CTX _ctx; - Byte mtDummy[1 << 7]; - -public: - CMD5Hasher() { MD5_Init(&_ctx); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CMD5Hasher::Init() throw() -{ - MD5_Init(&_ctx); -} - -STDMETHODIMP_(void) CMD5Hasher::Update(const void *data, UInt32 size) throw() -{ - MD5_Update(&_ctx, (const Byte *)data, size); -} - -STDMETHODIMP_(void) CMD5Hasher::Final(Byte *digest) throw() -{ - MD5_Final(digest, &_ctx); -} -REGISTER_HASHER(CMD5Hasher, 0x207, "MD5", MD5_DIGEST_LENGTH) +// Md5Reg.cpp /TR 2018-11-02 + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +EXTERN_C_BEGIN +#include "../../C/hashes/md5.h" +EXTERN_C_END + +#include "../Common/MyCom.h" +#include "../7zip/Common/RegisterCodec.h" + +// MD5 +class CMD5Hasher: + public IHasher, + public CMyUnknownImp +{ + MD5_CTX _ctx; + Byte mtDummy[1 << 7]; + +public: + CMD5Hasher() { MD5_Init(&_ctx); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CMD5Hasher::Init() throw() +{ + MD5_Init(&_ctx); +} + +STDMETHODIMP_(void) CMD5Hasher::Update(const void *data, UInt32 size) throw() +{ + MD5_Update(&_ctx, (const Byte *)data, size); +} + +STDMETHODIMP_(void) CMD5Hasher::Final(Byte *digest) throw() +{ + MD5_Final(digest, &_ctx); +} +REGISTER_HASHER(CMD5Hasher, 0x207, "MD5", MD5_DIGEST_LENGTH) diff --git a/CPP/Common/MyBuffer.h b/CPP/Common/MyBuffer.h index ae320eefe..5d4e34759 100644 --- a/CPP/Common/MyBuffer.h +++ b/CPP/Common/MyBuffer.h @@ -1,259 +1,259 @@ -// 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 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 -bool operator==(const CBuffer& b1, const CBuffer& 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 -bool operator!=(const CBuffer& b1, const CBuffer& 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 CCharBuffer; -// typedef CBuffer CWCharBuffer; -typedef CBuffer CByteBuffer; - - -template 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 CByteArr; -typedef CObjArray CBoolArr; -typedef CObjArray CIntArr; -typedef CObjArray CUIntArr; - - -template 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 __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 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 +bool operator==(const CBuffer& b1, const CBuffer& 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 +bool operator!=(const CBuffer& b1, const CBuffer& 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 CCharBuffer; +// typedef CBuffer CWCharBuffer; +typedef CBuffer CByteBuffer; + + +template 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 CByteArr; +typedef CObjArray CBoolArr; +typedef CObjArray CIntArr; +typedef CObjArray CUIntArr; + + +template 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 diff --git a/CPP/Common/MyBuffer2.h b/CPP/Common/MyBuffer2.h index 10edcb1c7..d61a72ef1 100644 --- a/CPP/Common/MyBuffer2.h +++ b/CPP/Common/MyBuffer2.h @@ -1,100 +1,100 @@ -// 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 __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 diff --git a/CPP/Common/MyCom.h b/CPP/Common/MyCom.h index ca49ead99..031921d3d 100644 --- a/CPP/Common/MyCom.h +++ b/CPP/Common/MyCom.h @@ -1,277 +1,277 @@ -// 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 CMyComPtr -{ - T* _p; -public: - CMyComPtr(): _p(NULL) {} - CMyComPtr(T* p) throw() { if ((_p = p) != NULL) p->AddRef(); } - CMyComPtr(const CMyComPtr& 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& 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 - 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 __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 CMyComPtr +{ + T* _p; +public: + CMyComPtr(): _p(NULL) {} + CMyComPtr(T* p) throw() { if ((_p = p) != NULL) p->AddRef(); } + CMyComPtr(const CMyComPtr& 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& 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 + 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 diff --git a/CPP/Common/MyException.h b/CPP/Common/MyException.h index cd9fe6948..f0ad11158 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 __COMMON_EXCEPTION_H +#define __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 e0359e203..68745870e 100644 --- a/CPP/Common/MyGuidDef.h +++ b/CPP/Common/MyGuidDef.h @@ -1,54 +1,54 @@ -// 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 + +#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 diff --git a/CPP/Common/MyInitGuid.h b/CPP/Common/MyInitGuid.h index 79fea19ab..279fba5d6 100644 --- a/CPP/Common/MyInitGuid.h +++ b/CPP/Common/MyInitGuid.h @@ -1,45 +1,45 @@ -// 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 -#endif - -#include - -#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 __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 +#endif + +#include + +#ifdef UNDER_CE +DEFINE_GUID(IID_IUnknown, +0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); +#endif + +#else + +#define INITGUID +#include "MyGuidDef.h" +DEFINE_GUID(IID_IUnknown, +0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); + +#endif + + +#endif diff --git a/CPP/Common/MyLinux.h b/CPP/Common/MyLinux.h index b4e760522..1a9189935 100644 --- a/CPP/Common/MyLinux.h +++ b/CPP/Common/MyLinux.h @@ -1,42 +1,42 @@ -// 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 __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 diff --git a/CPP/Common/MyMap.cpp b/CPP/Common/MyMap.cpp index fddbccba5..923846ae6 100644 --- a/CPP/Common/MyMap.cpp +++ b/CPP/Common/MyMap.cpp @@ -1,140 +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)); - 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 = n.Len - 1; - for (; GetSubBit(key, bitPos + i) == GetSubBit(n.Key, bitPos + i); i--); - - CNode e2(n); - e2.Len = (UInt16)i; - - n.Len = (UInt16)(n.Len - (1 + i)); - unsigned newBit = GetSubBit(key, bitPos + i); - n.Values[newBit] = value; - n.IsLeaf[newBit] = 1; - n.IsLeaf[1 - newBit] = 0; - n.Keys[newBit] = key; - n.Keys[1 - newBit] = Nodes.Size(); - Nodes.Add(e2); - return false; - } - unsigned bit = GetSubBit(key, --bitPos); - - if (n.IsLeaf[bit]) - { - if (key == n.Keys[bit]) - { - n.Values[bit] = value; - return true; - } - unsigned i = bitPos - 1; - for (; GetSubBit(key, i) == GetSubBit(n.Keys[bit], i); i--); - - CNode e2; - - unsigned newBit = GetSubBit(key, i); - e2.Values[newBit] = value; - e2.Values[1 - newBit] = n.Values[bit]; - e2.IsLeaf[newBit] = e2.IsLeaf[1 - newBit] = 1; - e2.Keys[newBit] = key; - e2.Keys[1 - newBit] = e2.Key = n.Keys[bit]; - e2.Len = (UInt16)(bitPos - (1 + i)); - - n.IsLeaf[bit] = 0; - n.Keys[bit] = Nodes.Size(); - - Nodes.Add(e2); - return false; - } - cur = (unsigned)n.Keys[bit]; - } -} +// 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)); + 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 = n.Len - 1; + for (; GetSubBit(key, bitPos + i) == GetSubBit(n.Key, bitPos + i); i--); + + CNode e2(n); + e2.Len = (UInt16)i; + + n.Len = (UInt16)(n.Len - (1 + i)); + unsigned newBit = GetSubBit(key, bitPos + i); + n.Values[newBit] = value; + n.IsLeaf[newBit] = 1; + n.IsLeaf[1 - newBit] = 0; + n.Keys[newBit] = key; + n.Keys[1 - newBit] = Nodes.Size(); + Nodes.Add(e2); + return false; + } + unsigned bit = GetSubBit(key, --bitPos); + + if (n.IsLeaf[bit]) + { + if (key == n.Keys[bit]) + { + n.Values[bit] = value; + return true; + } + unsigned i = bitPos - 1; + for (; GetSubBit(key, i) == GetSubBit(n.Keys[bit], i); i--); + + CNode e2; + + unsigned newBit = GetSubBit(key, i); + e2.Values[newBit] = value; + e2.Values[1 - newBit] = n.Values[bit]; + e2.IsLeaf[newBit] = e2.IsLeaf[1 - newBit] = 1; + e2.Keys[newBit] = key; + e2.Keys[1 - newBit] = e2.Key = n.Keys[bit]; + e2.Len = (UInt16)(bitPos - (1 + i)); + + n.IsLeaf[bit] = 0; + n.Keys[bit] = Nodes.Size(); + + Nodes.Add(e2); + return false; + } + cur = (unsigned)n.Keys[bit]; + } +} diff --git a/CPP/Common/MyMap.h b/CPP/Common/MyMap.h index bfe93d54d..cbcbadd6f 100644 --- a/CPP/Common/MyMap.h +++ b/CPP/Common/MyMap.h @@ -1,28 +1,28 @@ -// MyMap.h - -#ifndef __COMMON_MYMAP_H -#define __COMMON_MYMAP_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 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 +// MyMap.h + +#ifndef __COMMON_MYMAP_H +#define __COMMON_MYMAP_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 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 bf62303df..e2ec8a68d 100644 --- a/CPP/Common/MyString.cpp +++ b/CPP/Common/MyString.cpp @@ -1,1659 +1,1659 @@ -// Common/MyString.cpp - -#include "StdAfx.h" - -#ifdef _WIN32 -#include -#else -#include -#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 +#else +#include +#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 diff --git a/CPP/Common/MyString.h b/CPP/Common/MyString.h index 45cea98b2..40de52cd7 100644 --- a/CPP/Common/MyString.h +++ b/CPP/Common/MyString.h @@ -1,868 +1,868 @@ -// Common/String.h - -#ifndef __COMMON_STRING_H -#define __COMMON_STRING_H - -#include - -#ifndef _WIN32 -#include -#include -#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 AStringVector; -typedef CObjectVector UStringVector; - -#ifdef _UNICODE - typedef UString CSysString; -#else - typedef AString CSysString; -#endif - -typedef CObjectVector 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 FStringVector; - -#endif +// Common/String.h + +#ifndef __COMMON_STRING_H +#define __COMMON_STRING_H + +#include + +#ifndef _WIN32 +#include +#include +#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 AStringVector; +typedef CObjectVector UStringVector; + +#ifdef _UNICODE + typedef UString CSysString; +#else + typedef AString CSysString; +#endif + +typedef CObjectVector 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 FStringVector; + +#endif diff --git a/CPP/Common/MyTypes.h b/CPP/Common/MyTypes.h index 6e73aca31..75806f37d 100644 --- a/CPP/Common/MyTypes.h +++ b/CPP/Common/MyTypes.h @@ -1,35 +1,35 @@ -// 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 __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 diff --git a/CPP/Common/MyUnknown.h b/CPP/Common/MyUnknown.h index b1d476ffb..ff025cb53 100644 --- a/CPP/Common/MyUnknown.h +++ b/CPP/Common/MyUnknown.h @@ -1,17 +1,17 @@ -// MyUnknown.h - -#ifndef __MY_UNKNOWN_H -#define __MY_UNKNOWN_H - -#include "MyWindows.h" - -/* -#ifdef _WIN32 -#include -#include -#else -#include "MyWindows.h" -#endif -*/ - -#endif +// MyUnknown.h + +#ifndef __MY_UNKNOWN_H +#define __MY_UNKNOWN_H + +#include "MyWindows.h" + +/* +#ifdef _WIN32 +#include +#include +#else +#include "MyWindows.h" +#endif +*/ + +#endif diff --git a/CPP/Common/MyVector.cpp b/CPP/Common/MyVector.cpp index 9a6d1d5ae..0b1baf45c 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 21125fa7d..61dabbd1a 100644 --- a/CPP/Common/MyVector.h +++ b/CPP/Common/MyVector.h @@ -1,634 +1,634 @@ -// Common/MyVector.h - -#ifndef __COMMON_MY_VECTOR_H -#define __COMMON_MY_VECTOR_H - -#include - -template -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 CIntVector; -typedef CRecordVector CUIntVector; -typedef CRecordVector CBoolVector; -typedef CRecordVector CByteVector; -typedef CRecordVector CPointerVector; - -template -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 __COMMON_MY_VECTOR_H +#define __COMMON_MY_VECTOR_H + +#include + +template +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 CIntVector; +typedef CRecordVector CUIntVector; +typedef CRecordVector CBoolVector; +typedef CRecordVector CByteVector; +typedef CRecordVector CPointerVector; + +template +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 diff --git a/CPP/Common/MyWindows.cpp b/CPP/Common/MyWindows.cpp index bc9f7be3f..463c77c4a 100644 --- a/CPP/Common/MyWindows.cpp +++ b/CPP/Common/MyWindows.cpp @@ -1,145 +1,145 @@ -// MyWindows.cpp - -#include "StdAfx.h" - -#ifndef _WIN32 - -#include - -#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 + +#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 diff --git a/CPP/Common/MyWindows.h b/CPP/Common/MyWindows.h index cc7847815..db3f35d82 100644 --- a/CPP/Common/MyWindows.h +++ b/CPP/Common/MyWindows.h @@ -1,231 +1,231 @@ -// MyWindows.h - -#ifndef __MY_WINDOWS_H -#define __MY_WINDOWS_H - -#ifdef _WIN32 - -#include - -#ifdef UNDER_CE - #undef VARIANT_TRUE - #define VARIANT_TRUE ((VARIANT_BOOL)-1) -#endif - -#else - -#include // for wchar_t -#include -// #include // 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 + +#ifndef __MY_WINDOWS_H +#define __MY_WINDOWS_H + +#ifdef _WIN32 + +#include + +#ifdef UNDER_CE + #undef VARIANT_TRUE + #define VARIANT_TRUE ((VARIANT_BOOL)-1) +#endif + +#else + +#include // for wchar_t +#include +// #include // 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 diff --git a/CPP/Common/MyXml.cpp b/CPP/Common/MyXml.cpp index 0b3fb024e..f34a745e0 100644 --- a/CPP/Common/MyXml.cpp +++ b/CPP/Common/MyXml.cpp @@ -1,260 +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 i; - return -1; -} - -AString CXmlItem::GetPropVal(const char *propName) const -{ - int index = FindProp(propName); - if (index >= 0) - return Props[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 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[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 += ' '; - 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 += ' '; - item.AppendTo(s); - } - if (IsTag) - { - s += '<'; - s += '/'; - s += Name; - s += '>'; - } -} - -bool CXml::Parse(const char *s) -{ - s = SkipHeader(s, ""); if (!s) return false; - s = SkipHeader(s, ""); 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); -} -*/ +// 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 i; + return -1; +} + +AString CXmlItem::GetPropVal(const char *propName) const +{ + int index = FindProp(propName); + if (index >= 0) + return Props[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 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[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 += ' '; + 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 += ' '; + item.AppendTo(s); + } + if (IsTag) + { + s += '<'; + s += '/'; + s += Name; + s += '>'; + } +} + +bool CXml::Parse(const char *s) +{ + s = SkipHeader(s, ""); if (!s) return false; + s = SkipHeader(s, ""); 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 index de519e523..00b7113ad 100644 --- a/CPP/Common/MyXml.h +++ b/CPP/Common/MyXml.h @@ -1,43 +1,43 @@ -// MyXml.h - -#ifndef __MY_XML_H -#define __MY_XML_H - -#include "MyString.h" - -struct CXmlProp -{ - AString Name; - AString Value; -}; - -class CXmlItem -{ -public: - AString Name; - bool IsTag; - CObjectVector Props; - CObjectVector 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 +// MyXml.h + +#ifndef __MY_XML_H +#define __MY_XML_H + +#include "MyString.h" + +struct CXmlProp +{ + AString Name; + AString Value; +}; + +class CXmlItem +{ +public: + AString Name; + bool IsTag; + CObjectVector Props; + CObjectVector 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 18d2d1865..7e5b1d451 100644 --- a/CPP/Common/NewHandler.cpp +++ b/CPP/Common/NewHandler.cpp @@ -1,163 +1,163 @@ -// NewHandler.cpp - -#include "StdAfx.h" - -#include - -#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 - -// #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 + +#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 + +// #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); +} +*/ diff --git a/CPP/Common/NewHandler.h b/CPP/Common/NewHandler.h index 9d20ee134..aedeca64e 100644 --- a/CPP/Common/NewHandler.h +++ b/CPP/Common/NewHandler.h @@ -1,88 +1,88 @@ -// 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 - -#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 - -#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 __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 + +#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 + +#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 index 674147340..fbdb8c975 100644 --- a/CPP/Common/Random.cpp +++ b/CPP/Common/Random.cpp @@ -1,28 +1,28 @@ -// Common/Random.cpp - -#include "StdAfx.h" - -#include - -#ifndef _WIN32 -#include -#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(); } +// Common/Random.cpp + +#include "StdAfx.h" + +#include + +#ifndef _WIN32 +#include +#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 index 20a666b3f..e784e9848 100644 --- a/CPP/Common/Random.h +++ b/CPP/Common/Random.h @@ -1,14 +1,14 @@ -// Common/Random.h - -#ifndef __COMMON_RANDOM_H -#define __COMMON_RANDOM_H - -class CRandom -{ -public: - void Init(); - void Init(unsigned int seed); - int Generate() const; -}; - -#endif +// Common/Random.h + +#ifndef __COMMON_RANDOM_H +#define __COMMON_RANDOM_H + +class CRandom +{ +public: + void Init(); + void Init(unsigned int seed); + int Generate() const; +}; + +#endif diff --git a/CPP/Common/Sha1Reg.cpp b/CPP/Common/Sha1Reg.cpp index 85e934013..1400c989a 100644 --- a/CPP/Common/Sha1Reg.cpp +++ b/CPP/Common/Sha1Reg.cpp @@ -1,40 +1,40 @@ -// Sha1Reg.cpp - -#include "StdAfx.h" - -#include "../../C/Sha1.h" - -#include "../Common/MyCom.h" - -#include "../7zip/Common/RegisterCodec.h" - -class CSha1Hasher: - public IHasher, - public CMyUnknownImp -{ - CSha1 _sha; - Byte mtDummy[1 << 7]; - -public: - CSha1Hasher() { Sha1_Init(&_sha); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CSha1Hasher::Init() throw() -{ - Sha1_Init(&_sha); -} - -STDMETHODIMP_(void) CSha1Hasher::Update(const void *data, UInt32 size) throw() -{ - Sha1_Update(&_sha, (const Byte *)data, size); -} - -STDMETHODIMP_(void) CSha1Hasher::Final(Byte *digest) throw() -{ - Sha1_Final(&_sha, digest); -} - -REGISTER_HASHER(CSha1Hasher, 0x201, "SHA1", SHA1_DIGEST_SIZE) +// Sha1Reg.cpp + +#include "StdAfx.h" + +#include "../../C/Sha1.h" + +#include "../Common/MyCom.h" + +#include "../7zip/Common/RegisterCodec.h" + +class CSha1Hasher: + public IHasher, + public CMyUnknownImp +{ + CSha1 _sha; + Byte mtDummy[1 << 7]; + +public: + CSha1Hasher() { Sha1_Init(&_sha); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CSha1Hasher::Init() throw() +{ + Sha1_Init(&_sha); +} + +STDMETHODIMP_(void) CSha1Hasher::Update(const void *data, UInt32 size) throw() +{ + Sha1_Update(&_sha, (const Byte *)data, size); +} + +STDMETHODIMP_(void) CSha1Hasher::Final(Byte *digest) throw() +{ + Sha1_Final(&_sha, digest); +} + +REGISTER_HASHER(CSha1Hasher, 0x201, "SHA1", SHA1_DIGEST_SIZE) diff --git a/CPP/Common/Sha256Reg.cpp b/CPP/Common/Sha256Reg.cpp index 14a365237..66941699e 100644 --- a/CPP/Common/Sha256Reg.cpp +++ b/CPP/Common/Sha256Reg.cpp @@ -1,40 +1,40 @@ -// 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/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) diff --git a/CPP/Common/Sha384Reg.cpp b/CPP/Common/Sha384Reg.cpp index adc35e22c..82592baaf 100644 --- a/CPP/Common/Sha384Reg.cpp +++ b/CPP/Common/Sha384Reg.cpp @@ -1,43 +1,43 @@ -// Sha384Reg.cpp /TR 2018-11-02 - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" - -EXTERN_C_BEGIN -#include "../../C/hashes/sha.h" -EXTERN_C_END - -#include "../Common/MyCom.h" -#include "../7zip/Common/RegisterCodec.h" - -// SHA384 -class CSHA384Hasher: - public IHasher, - public CMyUnknownImp -{ - SHA384_CTX _ctx; - Byte mtDummy[1 << 7]; - -public: - CSHA384Hasher() { SHA384_Init(&_ctx); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CSHA384Hasher::Init() throw() -{ - SHA384_Init(&_ctx); -} - -STDMETHODIMP_(void) CSHA384Hasher::Update(const void *data, UInt32 size) throw() -{ - SHA384_Update(&_ctx, (const Byte *)data, size); -} - -STDMETHODIMP_(void) CSHA384Hasher::Final(Byte *digest) throw() -{ - SHA384_Final(digest, &_ctx); -} -REGISTER_HASHER(CSHA384Hasher, 0x208, "SHA384", SHA384_DIGEST_LENGTH) +// Sha384Reg.cpp /TR 2018-11-02 + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +EXTERN_C_BEGIN +#include "../../C/hashes/sha.h" +EXTERN_C_END + +#include "../Common/MyCom.h" +#include "../7zip/Common/RegisterCodec.h" + +// SHA384 +class CSHA384Hasher: + public IHasher, + public CMyUnknownImp +{ + SHA384_CTX _ctx; + Byte mtDummy[1 << 7]; + +public: + CSHA384Hasher() { SHA384_Init(&_ctx); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CSHA384Hasher::Init() throw() +{ + SHA384_Init(&_ctx); +} + +STDMETHODIMP_(void) CSHA384Hasher::Update(const void *data, UInt32 size) throw() +{ + SHA384_Update(&_ctx, (const Byte *)data, size); +} + +STDMETHODIMP_(void) CSHA384Hasher::Final(Byte *digest) throw() +{ + SHA384_Final(digest, &_ctx); +} +REGISTER_HASHER(CSHA384Hasher, 0x208, "SHA384", SHA384_DIGEST_LENGTH) diff --git a/CPP/Common/Sha512Reg.cpp b/CPP/Common/Sha512Reg.cpp index 9634e4c93..5c6d71d77 100644 --- a/CPP/Common/Sha512Reg.cpp +++ b/CPP/Common/Sha512Reg.cpp @@ -1,43 +1,43 @@ -// Sha512Reg.cpp /TR 2018-11-02 - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" - -EXTERN_C_BEGIN -#include "../../C/hashes/sha.h" -EXTERN_C_END - -#include "../Common/MyCom.h" -#include "../7zip/Common/RegisterCodec.h" - -// SHA512 -class CSHA512Hasher: - public IHasher, - public CMyUnknownImp -{ - SHA512_CTX _ctx; - Byte mtDummy[1 << 7]; - -public: - CSHA512Hasher() { SHA512_Init(&_ctx); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CSHA512Hasher::Init() throw() -{ - SHA512_Init(&_ctx); -} - -STDMETHODIMP_(void) CSHA512Hasher::Update(const void *data, UInt32 size) throw() -{ - SHA512_Update(&_ctx, (const Byte *)data, size); -} - -STDMETHODIMP_(void) CSHA512Hasher::Final(Byte *digest) throw() -{ - SHA512_Final(digest, &_ctx); -} -REGISTER_HASHER(CSHA512Hasher, 0x209, "SHA512", SHA512_DIGEST_LENGTH) +// Sha512Reg.cpp /TR 2018-11-02 + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +EXTERN_C_BEGIN +#include "../../C/hashes/sha.h" +EXTERN_C_END + +#include "../Common/MyCom.h" +#include "../7zip/Common/RegisterCodec.h" + +// SHA512 +class CSHA512Hasher: + public IHasher, + public CMyUnknownImp +{ + SHA512_CTX _ctx; + Byte mtDummy[1 << 7]; + +public: + CSHA512Hasher() { SHA512_Init(&_ctx); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CSHA512Hasher::Init() throw() +{ + SHA512_Init(&_ctx); +} + +STDMETHODIMP_(void) CSHA512Hasher::Update(const void *data, UInt32 size) throw() +{ + SHA512_Update(&_ctx, (const Byte *)data, size); +} + +STDMETHODIMP_(void) CSHA512Hasher::Final(Byte *digest) throw() +{ + SHA512_Final(digest, &_ctx); +} +REGISTER_HASHER(CSHA512Hasher, 0x209, "SHA512", SHA512_DIGEST_LENGTH) diff --git a/CPP/Common/StdAfx.h b/CPP/Common/StdAfx.h index 3f1890a27..420f5c326 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 __STDAFX_H +#define __STDAFX_H + +#include "Common.h" + +#endif diff --git a/CPP/Common/StdInStream.cpp b/CPP/Common/StdInStream.cpp index f547b54fb..422a96e5e 100644 --- a/CPP/Common/StdInStream.cpp +++ b/CPP/Common/StdInStream.cpp @@ -1,89 +1,89 @@ -// Common/StdInStream.cpp - -#include "StdAfx.h" - -#include - -#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" + +#include + +#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? +} diff --git a/CPP/Common/StdInStream.h b/CPP/Common/StdInStream.h index 20f9ce343..698ebec1a 100644 --- a/CPP/Common/StdInStream.h +++ b/CPP/Common/StdInStream.h @@ -1,38 +1,38 @@ -// Common/StdInStream.h - -#ifndef __COMMON_STD_IN_STREAM_H -#define __COMMON_STD_IN_STREAM_H - -#include - -#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 __COMMON_STD_IN_STREAM_H +#define __COMMON_STD_IN_STREAM_H + +#include + +#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 diff --git a/CPP/Common/StdOutStream.cpp b/CPP/Common/StdOutStream.cpp index dc6d4bd4a..8236072d3 100644 --- a/CPP/Common/StdOutStream.cpp +++ b/CPP/Common/StdOutStream.cpp @@ -1,163 +1,163 @@ -// Common/StdOutStream.cpp - -#include "StdAfx.h" - -#include - -#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" + +#include + +#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); +} diff --git a/CPP/Common/StdOutStream.h b/CPP/Common/StdOutStream.h index 475954c06..2e637e8fe 100644 --- a/CPP/Common/StdOutStream.h +++ b/CPP/Common/StdOutStream.h @@ -1,71 +1,71 @@ -// Common/StdOutStream.h - -#ifndef __COMMON_STD_OUT_STREAM_H -#define __COMMON_STD_OUT_STREAM_H - -#include - -#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 __COMMON_STD_OUT_STREAM_H +#define __COMMON_STD_OUT_STREAM_H + +#include + +#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 diff --git a/CPP/Common/StringConvert.cpp b/CPP/Common/StringConvert.cpp index b8f33cd63..2a73d688e 100644 --- a/CPP/Common/StringConvert.cpp +++ b/CPP/Common/StringConvert.cpp @@ -1,319 +1,319 @@ -// Common/StringConvert.cpp - -#include "StdAfx.h" - -#include "StringConvert.h" - -#ifndef _WIN32 -#include -#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 +#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; +} diff --git a/CPP/Common/StringConvert.h b/CPP/Common/StringConvert.h index 05a21556d..25fe503f3 100644 --- a/CPP/Common/StringConvert.h +++ b/CPP/Common/StringConvert.h @@ -1,88 +1,88 @@ -// 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 __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 diff --git a/CPP/Common/StringToInt.cpp b/CPP/Common/StringToInt.cpp index 295816e16..dfa5cc3bf 100644 --- a/CPP/Common/StringToInt.cpp +++ b/CPP/Common/StringToInt.cpp @@ -1,144 +1,144 @@ -// 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 = (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; + } +} diff --git a/CPP/Common/StringToInt.h b/CPP/Common/StringToInt.h index 140d1ee2d..5c5d7d7fe 100644 --- a/CPP/Common/StringToInt.h +++ b/CPP/Common/StringToInt.h @@ -1,21 +1,21 @@ -// 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 __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 diff --git a/CPP/Common/TextConfig.cpp b/CPP/Common/TextConfig.cpp index f54aa3f6d..1428aab5c 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 &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 &pairs, const char *id) throw() -{ - FOR_VECTOR (i, pairs) - if (pairs[i].ID.IsEqualTo(id)) - return i; - return -1; -} - -UString GetTextConfigValue(const CObjectVector &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++) + { + 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 &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 &pairs, const char *id) throw() +{ + FOR_VECTOR (i, pairs) + if (pairs[i].ID.IsEqualTo(id)) + return i; + return -1; +} + +UString GetTextConfigValue(const CObjectVector &pairs, const char *id) +{ + 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 c39e3634f..cc7ce4127 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 &pairs); - -int FindTextConfigItem(const CObjectVector &pairs, const char *id) throw(); -UString GetTextConfigValue(const CObjectVector &pairs, const char *id); - -#endif +// 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 &pairs); + +int FindTextConfigItem(const CObjectVector &pairs, const char *id) throw(); +UString GetTextConfigValue(const CObjectVector &pairs, const char *id); + +#endif diff --git a/CPP/Common/UTFConvert.cpp b/CPP/Common/UTFConvert.cpp index b09bbcdb3..b772164aa 100644 --- a/CPP/Common/UTFConvert.cpp +++ b/CPP/Common/UTFConvert.cpp @@ -1,288 +1,288 @@ -// 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 "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); +} diff --git a/CPP/Common/UTFConvert.h b/CPP/Common/UTFConvert.h index 11831700c..827f3dcfe 100644 --- a/CPP/Common/UTFConvert.h +++ b/CPP/Common/UTFConvert.h @@ -1,12 +1,12 @@ -// 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 __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 diff --git a/CPP/Common/Wildcard.cpp b/CPP/Common/Wildcard.cpp index 43e4baa17..a7199170c 100644 --- a/CPP/Common/Wildcard.cpp +++ b/CPP/Common/Wildcard.cpp @@ -1,676 +1,676 @@ -// 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 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 &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" + +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 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 &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; +} + +} diff --git a/CPP/Common/Wildcard.h b/CPP/Common/Wildcard.h index 6e5f01341..93f53c0fa 100644 --- a/CPP/Common/Wildcard.h +++ b/CPP/Common/Wildcard.h @@ -1,149 +1,149 @@ -// 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 SubNodes; - CObjectVector IncludeItems; - CObjectVector 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 Pairs; - - CObjectVector 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 __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 SubNodes; + CObjectVector IncludeItems; + CObjectVector 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 Pairs; + + CObjectVector 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 diff --git a/CPP/Common/XXH32Reg.cpp b/CPP/Common/XXH32Reg.cpp index fdf8fd7b8..59a2de8e0 100644 --- a/CPP/Common/XXH32Reg.cpp +++ b/CPP/Common/XXH32Reg.cpp @@ -1,45 +1,45 @@ -// XXH32Reg.cpp /TR 2018-11-02 - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" - -#define XXH_STATIC_LINKING_ONLY -#include "../../C/zstd/xxhash.h" - -#include "../Common/MyCom.h" -#include "../7zip/Common/RegisterCodec.h" - -// XXH32 -class CXXH32Hasher: - public IHasher, - public CMyUnknownImp -{ - XXH32_state_t *_ctx; - Byte mtDummy[1 << 7]; - -public: - CXXH32Hasher() { _ctx = XXH32_createState(); } - ~CXXH32Hasher() { XXH32_freeState(_ctx); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CXXH32Hasher::Init() throw() -{ - XXH32_reset(_ctx, 0); -} - -STDMETHODIMP_(void) CXXH32Hasher::Update(const void *data, UInt32 size) throw() -{ - XXH32_update(_ctx, data, size); -} - -STDMETHODIMP_(void) CXXH32Hasher::Final(Byte *digest) throw() -{ - UInt32 val = XXH32_digest(_ctx); - SetUi32(digest, val); -} - -REGISTER_HASHER(CXXH32Hasher, 0x203, "XXH32", 4) +// XXH32Reg.cpp /TR 2018-11-02 + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +#define XXH_STATIC_LINKING_ONLY +#include "../../C/zstd/xxhash.h" + +#include "../Common/MyCom.h" +#include "../7zip/Common/RegisterCodec.h" + +// XXH32 +class CXXH32Hasher: + public IHasher, + public CMyUnknownImp +{ + XXH32_state_t *_ctx; + Byte mtDummy[1 << 7]; + +public: + CXXH32Hasher() { _ctx = XXH32_createState(); } + ~CXXH32Hasher() { XXH32_freeState(_ctx); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CXXH32Hasher::Init() throw() +{ + XXH32_reset(_ctx, 0); +} + +STDMETHODIMP_(void) CXXH32Hasher::Update(const void *data, UInt32 size) throw() +{ + XXH32_update(_ctx, data, size); +} + +STDMETHODIMP_(void) CXXH32Hasher::Final(Byte *digest) throw() +{ + UInt32 val = XXH32_digest(_ctx); + SetUi32(digest, val); +} + +REGISTER_HASHER(CXXH32Hasher, 0x203, "XXH32", 4) diff --git a/CPP/Common/XXH64Reg.cpp b/CPP/Common/XXH64Reg.cpp index b1d9b0643..a0d7bf04e 100644 --- a/CPP/Common/XXH64Reg.cpp +++ b/CPP/Common/XXH64Reg.cpp @@ -1,44 +1,44 @@ -// XXH64Reg.cpp /TR 2018-11-02 - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" - -#define XXH_STATIC_LINKING_ONLY -#include "../../C/zstd/xxhash.h" - -#include "../Common/MyCom.h" -#include "../7zip/Common/RegisterCodec.h" - -// XXH64 -class CXXH64Hasher: - public IHasher, - public CMyUnknownImp -{ - XXH64_state_t *_ctx; - Byte mtDummy[1 << 7]; - -public: - CXXH64Hasher() { _ctx = XXH64_createState(); } - ~CXXH64Hasher() { XXH64_freeState(_ctx); } - - MY_UNKNOWN_IMP1(IHasher) - INTERFACE_IHasher(;) -}; - -STDMETHODIMP_(void) CXXH64Hasher::Init() throw() -{ - XXH64_reset(_ctx, 0); -} - -STDMETHODIMP_(void) CXXH64Hasher::Update(const void *data, UInt32 size) throw() -{ - XXH64_update(_ctx, data, size); -} - -STDMETHODIMP_(void) CXXH64Hasher::Final(Byte *digest) throw() -{ - UInt64 val = XXH64_digest(_ctx); - SetUi64(digest, val); -} -REGISTER_HASHER(CXXH64Hasher, 0x204, "XXH64", 8) +// XXH64Reg.cpp /TR 2018-11-02 + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +#define XXH_STATIC_LINKING_ONLY +#include "../../C/zstd/xxhash.h" + +#include "../Common/MyCom.h" +#include "../7zip/Common/RegisterCodec.h" + +// XXH64 +class CXXH64Hasher: + public IHasher, + public CMyUnknownImp +{ + XXH64_state_t *_ctx; + Byte mtDummy[1 << 7]; + +public: + CXXH64Hasher() { _ctx = XXH64_createState(); } + ~CXXH64Hasher() { XXH64_freeState(_ctx); } + + MY_UNKNOWN_IMP1(IHasher) + INTERFACE_IHasher(;) +}; + +STDMETHODIMP_(void) CXXH64Hasher::Init() throw() +{ + XXH64_reset(_ctx, 0); +} + +STDMETHODIMP_(void) CXXH64Hasher::Update(const void *data, UInt32 size) throw() +{ + XXH64_update(_ctx, data, size); +} + +STDMETHODIMP_(void) CXXH64Hasher::Final(Byte *digest) throw() +{ + UInt64 val = XXH64_digest(_ctx); + SetUi64(digest, val); +} +REGISTER_HASHER(CXXH64Hasher, 0x204, "XXH64", 8) diff --git a/CPP/Common/XzCrc64Init.cpp b/CPP/Common/XzCrc64Init.cpp index 1eae72ad9..5cb8e6744 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 92fce0a1a..33b524932 100644 --- a/CPP/Common/XzCrc64Reg.cpp +++ b/CPP/Common/XzCrc64Reg.cpp @@ -1,42 +1,42 @@ -// 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" + +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) diff --git a/CPP/Windows/COM.cpp b/CPP/Windows/COM.cpp index b859326c1..d0cb32113 100644 --- a/CPP/Windows/COM.cpp +++ b/CPP/Windows/COM.cpp @@ -1,41 +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); -} - -}} - -*/ +// 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 e2cb002bf..cee7f702d 100644 --- a/CPP/Windows/COM.h +++ b/CPP/Windows/COM.h @@ -1,70 +1,70 @@ -// 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 __WINDOWS_COM_H +#define __WINDOWS_COM_H + +#include "../Common/MyString.h" + +namespace NWindows { +namespace NCOM { + +#ifdef _WIN32 + +class CComInitializer +{ +public: + CComInitializer() + { + #ifdef UNDER_CE + CoInitializeEx(NULL, COINIT_MULTITHREADED); + #else + // it's single thread. Do we need multithread? + CoInitialize(NULL); + #endif + }; + ~CComInitializer() { CoUninitialize(); } +}; + +class CStgMedium +{ + STGMEDIUM _object; +public: + bool _mustBeReleased; + CStgMedium(): _mustBeReleased(false) {} + ~CStgMedium() { Free(); } + void Free() + { + if (_mustBeReleased) + ReleaseStgMedium(&_object); + _mustBeReleased = false; + } + const STGMEDIUM* operator->() const { return &_object;} + STGMEDIUM* operator->() { return &_object;} + STGMEDIUM* operator&() { return &_object; } +}; + +#endif + +/* +////////////////////////////////// +// GUID <--> String Conversions +UString GUIDToStringW(REFGUID guid); +AString GUIDToStringA(REFGUID guid); +#ifdef UNICODE + #define GUIDToString GUIDToStringW +#else + #define GUIDToString GUIDToStringA +#endif + +HRESULT StringToGUIDW(const wchar_t *string, GUID &classID); +HRESULT StringToGUIDA(const char *string, GUID &classID); +#ifdef UNICODE + #define StringToGUID StringToGUIDW +#else + #define StringToGUID StringToGUIDA +#endif +*/ + +}} + +#endif diff --git a/CPP/Windows/Clipboard.cpp b/CPP/Windows/Clipboard.cpp index 90c486430..bc7e201dd 100644 --- a/CPP/Windows/Clipboard.cpp +++ b/CPP/Windows/Clipboard.cpp @@ -1,130 +1,130 @@ -// Windows/Clipboard.cpp - -#include "StdAfx.h" - -#ifdef UNDER_CE -#include -#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; -} - -} +// Windows/Clipboard.cpp + +#include "StdAfx.h" + +#ifdef UNDER_CE +#include +#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 index 09a90b682..60fedc13b 100644 --- a/CPP/Windows/Clipboard.h +++ b/CPP/Windows/Clipboard.h @@ -1,28 +1,28 @@ -// Windows/Clipboard.h - -#ifndef __CLIPBOARD_H -#define __CLIPBOARD_H - -#include "../Common/MyString.h" - -namespace NWindows { - -class CClipboard -{ - bool m_Open; -public: - CClipboard(): m_Open(false) {}; - ~CClipboard() { 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 +// Windows/Clipboard.h + +#ifndef __CLIPBOARD_H +#define __CLIPBOARD_H + +#include "../Common/MyString.h" + +namespace NWindows { + +class CClipboard +{ + bool m_Open; +public: + CClipboard(): m_Open(false) {}; + ~CClipboard() { 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 8b3828cf7..8f4f56d39 100644 --- a/CPP/Windows/CommonDialog.cpp +++ b/CPP/Windows/CommonDialog.cpp @@ -1,185 +1,185 @@ -// Windows/CommonDialog.cpp - -#include "StdAfx.h" - -#include "../Common/MyWindows.h" - -#ifdef UNDER_CE -#include -#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/MyWindows.h" + +#ifdef UNDER_CE +#include +#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; + } +} + +} diff --git a/CPP/Windows/CommonDialog.h b/CPP/Windows/CommonDialog.h index 2bfec28d9..aaf17ac57 100644 --- a/CPP/Windows/CommonDialog.h +++ b/CPP/Windows/CommonDialog.h @@ -1,23 +1,23 @@ -// 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 __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 diff --git a/CPP/Windows/Console.cpp b/CPP/Windows/Console.cpp index cb0c5d9c3..28ba1c47a 100644 --- a/CPP/Windows/Console.cpp +++ b/CPP/Windows/Console.cpp @@ -1,10 +1,10 @@ -// Windows/Console.cpp - -#include "StdAfx.h" - -#include "Console.h" - -namespace NWindows{ -namespace NConsole{ - -}} +// 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 index d6cb25f75..43e02fa62 100644 --- a/CPP/Windows/Console.h +++ b/CPP/Windows/Console.h @@ -1,52 +1,52 @@ -// Windows/Console.h - -#ifndef __WINDOWS_CONSOLE_H -#define __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 +// Windows/Console.h + +#ifndef __WINDOWS_CONSOLE_H +#define __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 6ab471712..febc61ef9 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, 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 + +}} diff --git a/CPP/Windows/Control/ComboBox.h b/CPP/Windows/Control/ComboBox.h index 3439655fe..1d5a48213 100644 --- a/CPP/Windows/Control/ComboBox.h +++ b/CPP/Windows/Control/ComboBox.h @@ -1,65 +1,65 @@ -// Windows/Control/ComboBox.h - -#ifndef __WINDOWS_CONTROL_COMBOBOX_H -#define __WINDOWS_CONTROL_COMBOBOX_H - -#include "../../Common/MyWindows.h" - -#include - -#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 __WINDOWS_CONTROL_COMBOBOX_H +#define __WINDOWS_CONTROL_COMBOBOX_H + +#include "../../Common/MyWindows.h" + +#include + +#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 diff --git a/CPP/Windows/Control/CommandBar.h b/CPP/Windows/Control/CommandBar.h index c4355680a..a6197447a 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 - -#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 __WINDOWS_CONTROL_COMMANDBAR_H +#define __WINDOWS_CONTROL_COMMANDBAR_H + +#ifdef UNDER_CE + +#include "../../Common/MyWindows.h" + +#include + +#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 diff --git a/CPP/Windows/Control/Dialog.cpp b/CPP/Windows/Control/Dialog.cpp index 8e61a2b2c..020694a6a 100644 --- a/CPP/Windows/Control/Dialog.cpp +++ b/CPP/Windows/Control/Dialog.cpp @@ -1,251 +1,251 @@ -// 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" + +#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 + +}} diff --git a/CPP/Windows/Control/Dialog.h b/CPP/Windows/Control/Dialog.h index f9c3442fd..33caa5b27 100644 --- a/CPP/Windows/Control/Dialog.h +++ b/CPP/Windows/Control/Dialog.h @@ -1,170 +1,170 @@ -// 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 __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 diff --git a/CPP/Windows/Control/Edit.h b/CPP/Windows/Control/Edit.h index 4f503aa7a..51a22c537 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 __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 diff --git a/CPP/Windows/Control/ImageList.cpp b/CPP/Windows/Control/ImageList.cpp index d201c8fd7..3e22b956e 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 f72ea0d19..0d9c93131 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 - -#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 __WINDOWS_CONTROL_IMAGE_LIST_H +#define __WINDOWS_CONTROL_IMAGE_LIST_H + +#include + +#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 diff --git a/CPP/Windows/Control/ListView.cpp b/CPP/Windows/Control/ListView.cpp index fb22f95c1..6d916591a 100644 --- a/CPP/Windows/Control/ListView.cpp +++ b/CPP/Windows/Control/ListView.cpp @@ -1,155 +1,155 @@ -// 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 ¶m) 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); +} + +bool CListView::GetItemParam(int index, LPARAM ¶m) 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; +} +*/ + +}} diff --git a/CPP/Windows/Control/ListView.h b/CPP/Windows/Control/ListView.h index 1ed496d7e..9a3abe70f 100644 --- a/CPP/Windows/Control/ListView.h +++ b/CPP/Windows/Control/ListView.h @@ -1,146 +1,146 @@ -// Windows/Control/ListView.h - -#ifndef __WINDOWS_CONTROL_LISTVIEW_H -#define __WINDOWS_CONTROL_LISTVIEW_H - -#include "../../Common/MyWindows.h" - -#include - -#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 ¶m) 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 __WINDOWS_CONTROL_LISTVIEW_H +#define __WINDOWS_CONTROL_LISTVIEW_H + +#include "../../Common/MyWindows.h" + +#include + +#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 ¶m) 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 diff --git a/CPP/Windows/Control/ProgressBar.h b/CPP/Windows/Control/ProgressBar.h index f18d89c14..38ebcb613 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 - -#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 __WINDOWS_CONTROL_PROGRESSBAR_H +#define __WINDOWS_CONTROL_PROGRESSBAR_H + +#include "../../Common/MyWindows.h" + +#include + +#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 diff --git a/CPP/Windows/Control/PropertyPage.cpp b/CPP/Windows/Control/PropertyPage.cpp index 48947c018..ce8696d40 100644 --- a/CPP/Windows/Control/PropertyPage.cpp +++ b/CPP/Windows/Control/PropertyPage.cpp @@ -1,143 +1,143 @@ -// 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 &pagesInfo, HWND hwndParent, const UString &title) -{ - #ifndef _UNICODE - AStringVector titles; - #endif - #ifndef _UNICODE - CRecordVector pagesA; - #endif - CRecordVector 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 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 &pagesInfo, HWND hwndParent, const UString &title) +{ + #ifndef _UNICODE + AStringVector titles; + #endif + #ifndef _UNICODE + CRecordVector pagesA; + #endif + CRecordVector 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); + } +} + +}} diff --git a/CPP/Windows/Control/PropertyPage.h b/CPP/Windows/Control/PropertyPage.h index 551c95994..4c4ddad91 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 - -#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 &pagesInfo, HWND hwndParent, const UString &title); - -}} - -#endif +// Windows/Control/PropertyPage.h + +#ifndef __WINDOWS_CONTROL_PROPERTYPAGE_H +#define __WINDOWS_CONTROL_PROPERTYPAGE_H + +#include "../../Common/MyWindows.h" + +#include + +#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 &pagesInfo, HWND hwndParent, const UString &title); + +}} + +#endif diff --git a/CPP/Windows/Control/ReBar.h b/CPP/Windows/Control/ReBar.h index 26fa31105..c2d58dbe8 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 __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 diff --git a/CPP/Windows/Control/Static.h b/CPP/Windows/Control/Static.h index 936dd3c88..5523b2e63 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 __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 diff --git a/CPP/Windows/Control/StatusBar.h b/CPP/Windows/Control/StatusBar.h index 7f7d66b0b..988b84700 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 __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 diff --git a/CPP/Windows/Control/StdAfx.h b/CPP/Windows/Control/StdAfx.h index 42a088f12..1cbd7feae 100644 --- a/CPP/Windows/Control/StdAfx.h +++ b/CPP/Windows/Control/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../Common/Common.h" + +#endif diff --git a/CPP/Windows/Control/ToolBar.h b/CPP/Windows/Control/ToolBar.h index 02ed9a142..7bc93a241 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 __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 diff --git a/CPP/Windows/Control/Trackbar.h b/CPP/Windows/Control/Trackbar.h index afc9bf25c..313e0c851 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 __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 diff --git a/CPP/Windows/Control/Window2.cpp b/CPP/Windows/Control/Window2.cpp index b6e6d67da..994d96e08 100644 --- a/CPP/Windows/Control/Window2.cpp +++ b/CPP/Windows/Control/Window2.cpp @@ -1,200 +1,200 @@ -// 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 != 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; +} + +*/ + +}} diff --git a/CPP/Windows/Control/Window2.h b/CPP/Windows/Control/Window2.h index d632b86fe..7ac580cb0 100644 --- a/CPP/Windows/Control/Window2.h +++ b/CPP/Windows/Control/Window2.h @@ -1,51 +1,51 @@ -// 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 __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 diff --git a/CPP/Windows/DLL.cpp b/CPP/Windows/DLL.cpp index efee379b7..d7f383755 100644 --- a/CPP/Windows/DLL.cpp +++ b/CPP/Windows/DLL.cpp @@ -1,109 +1,109 @@ -// 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" + +#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 + +}} diff --git a/CPP/Windows/DLL.h b/CPP/Windows/DLL.h index 58bcf1954..984a1d33b 100644 --- a/CPP/Windows/DLL.h +++ b/CPP/Windows/DLL.h @@ -1,58 +1,58 @@ -// 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 __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 diff --git a/CPP/Windows/Defs.h b/CPP/Windows/Defs.h index f3d692f3d..281c40c33 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 __WINDOWS_DEFS_H +#define __WINDOWS_DEFS_H + +#include "../Common/MyWindows.h" + +#ifdef _WIN32 +inline bool LRESULTToBool(LRESULT v) { return (v != FALSE); } +inline bool BOOLToBool(BOOL v) { return (v != FALSE); } +inline BOOL BoolToBOOL(bool v) { return (v ? TRUE: FALSE); } +#endif + +inline VARIANT_BOOL BoolToVARIANT_BOOL(bool v) { return (v ? VARIANT_TRUE: VARIANT_FALSE); } +inline bool VARIANT_BOOLToBool(VARIANT_BOOL v) { return (v != VARIANT_FALSE); } + +#endif diff --git a/CPP/Windows/ErrorMsg.cpp b/CPP/Windows/ErrorMsg.cpp index 6434ec2f7..b86c0b392 100644 --- a/CPP/Windows/ErrorMsg.cpp +++ b/CPP/Windows/ErrorMsg.cpp @@ -1,66 +1,66 @@ -// 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" + +#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; +} + +}} diff --git a/CPP/Windows/ErrorMsg.h b/CPP/Windows/ErrorMsg.h index e05e95043..0957c696a 100644 --- a/CPP/Windows/ErrorMsg.h +++ b/CPP/Windows/ErrorMsg.h @@ -1,15 +1,15 @@ -// 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 __WINDOWS_ERROR_MSG_H +#define __WINDOWS_ERROR_MSG_H + +#include "../Common/MyString.h" + +namespace NWindows { +namespace NError { + +UString MyFormatMessage(DWORD errorCode); + +}} + +#endif diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp index 124569e3f..62b11c103 100644 --- a/CPP/Windows/FileDir.cpp +++ b/CPP/Windows/FileDir.cpp @@ -1,714 +1,714 @@ -// 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 _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; +} + +}}} diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h index 8d2b56a6a..154ed9738 100644 --- a/CPP/Windows/FileDir.h +++ b/CPP/Windows/FileDir.h @@ -1,117 +1,117 @@ -// 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 __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 diff --git a/CPP/Windows/FileFind.cpp b/CPP/Windows/FileFind.cpp index 8c6255bda..b9692b817 100644 --- a/CPP/Windows/FileFind.cpp +++ b/CPP/Windows/FileFind.cpp @@ -1,749 +1,749 @@ -// 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 &driveStrings) -{ - driveStrings.Clear(); - #ifndef _UNICODE - if (!g_IsNT) - { - driveStrings.Clear(); - UINT32 size = GetLogicalDriveStrings(0, NULL); - if (size == 0) - return false; - CObjArray 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 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" + +#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 &driveStrings) +{ + driveStrings.Clear(); + #ifndef _UNICODE + if (!g_IsNT) + { + driveStrings.Clear(); + UINT32 size = GetLogicalDriveStrings(0, NULL); + if (size == 0) + return false; + CObjArray 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 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 + +}}} diff --git a/CPP/Windows/FileFind.h b/CPP/Windows/FileFind.h index 77d8dc35c..bfb29206e 100644 --- a/CPP/Windows/FileFind.h +++ b/CPP/Windows/FileFind.h @@ -1,161 +1,161 @@ -// 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 &driveStrings); -#endif - -}}} - -#endif +// 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 &driveStrings); +#endif + +}}} + +#endif diff --git a/CPP/Windows/FileIO.cpp b/CPP/Windows/FileIO.cpp index a1d52c0fe..56e6ca457 100644 --- a/CPP/Windows/FileIO.cpp +++ b/CPP/Windows/FileIO.cpp @@ -1,432 +1,432 @@ -// 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 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(); +} + +}}} diff --git a/CPP/Windows/FileIO.h b/CPP/Windows/FileIO.h index e31bc20cc..5ca5448bc 100644 --- a/CPP/Windows/FileIO.h +++ b/CPP/Windows/FileIO.h @@ -1,212 +1,212 @@ -// Windows/FileIO.h - -#ifndef __WINDOWS_FILE_IO_H -#define __WINDOWS_FILE_IO_H - -#include "../Common/MyWindows.h" - -#if defined(_WIN32) && !defined(UNDER_CE) -#include -#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 __WINDOWS_FILE_IO_H +#define __WINDOWS_FILE_IO_H + +#include "../Common/MyWindows.h" + +#if defined(_WIN32) && !defined(UNDER_CE) +#include +#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 diff --git a/CPP/Windows/FileLink.cpp b/CPP/Windows/FileLink.cpp index b5e47e73c..3e2f64310 100644 --- a/CPP/Windows/FileLink.cpp +++ b/CPP/Windows/FileLink.cpp @@ -1,440 +1,440 @@ -// 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" + +#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 + +}} diff --git a/CPP/Windows/FileMapping.cpp b/CPP/Windows/FileMapping.cpp index 01c4a943d..1933f7c8b 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 27d076b83..f90c429f1 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 __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 diff --git a/CPP/Windows/FileName.cpp b/CPP/Windows/FileName.cpp index 2a227dc60..2d0b50d5b 100644 --- a/CPP/Windows/FileName.cpp +++ b/CPP/Windows/FileName.cpp @@ -1,839 +1,839 @@ -// 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" + +#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); +} + +}}} diff --git a/CPP/Windows/FileName.h b/CPP/Windows/FileName.h index 1e4709863..2c9c56db3 100644 --- a/CPP/Windows/FileName.h +++ b/CPP/Windows/FileName.h @@ -1,115 +1,115 @@ -// 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 __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 diff --git a/CPP/Windows/FileSystem.cpp b/CPP/Windows/FileSystem.cpp index 986106280..6c1f48a20 100644 --- a/CPP/Windows/FileSystem.cpp +++ b/CPP/Windows/FileSystem.cpp @@ -1,131 +1,131 @@ -// 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 { + +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 diff --git a/CPP/Windows/FileSystem.h b/CPP/Windows/FileSystem.h index b0149de42..9076ea13f 100644 --- a/CPP/Windows/FileSystem.h +++ b/CPP/Windows/FileSystem.h @@ -1,27 +1,27 @@ -// 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 __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 diff --git a/CPP/Windows/Handle.h b/CPP/Windows/Handle.h index 755eeb8c5..bb7cb705d 100644 --- a/CPP/Windows/Handle.h +++ b/CPP/Windows/Handle.h @@ -1,37 +1,37 @@ -// Windows/Handle.h - -#ifndef __WINDOWS_HANDLE_H -#define __WINDOWS_HANDLE_H - -namespace NWindows { - -class CHandle -{ -protected: - HANDLE _handle; -public: - operator HANDLE() { return _handle; } - CHandle(): _handle(NULL) {} - ~CHandle() { Close(); } - bool IsCreated() const { return (_handle != NULL); } - bool Close() - { - if (_handle == NULL) - return true; - if (!::CloseHandle(_handle)) - return false; - _handle = NULL; - return true; - } - void Attach(HANDLE handle) { _handle = handle; } - HANDLE Detach() - { - HANDLE handle = _handle; - _handle = NULL; - return handle; - } -}; - -} - -#endif +// Windows/Handle.h + +#ifndef __WINDOWS_HANDLE_H +#define __WINDOWS_HANDLE_H + +namespace NWindows { + +class CHandle +{ +protected: + HANDLE _handle; +public: + operator HANDLE() { return _handle; } + CHandle(): _handle(NULL) {} + ~CHandle() { Close(); } + bool IsCreated() const { return (_handle != NULL); } + bool Close() + { + if (_handle == NULL) + return true; + if (!::CloseHandle(_handle)) + return false; + _handle = NULL; + return true; + } + void Attach(HANDLE handle) { _handle = handle; } + HANDLE Detach() + { + HANDLE handle = _handle; + _handle = NULL; + return handle; + } +}; + +} + +#endif diff --git a/CPP/Windows/MemoryGlobal.cpp b/CPP/Windows/MemoryGlobal.cpp index 7e2d3de3a..2a22394b3 100644 --- a/CPP/Windows/MemoryGlobal.cpp +++ b/CPP/Windows/MemoryGlobal.cpp @@ -1,36 +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; -} - -}} +// 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 index 601335b4b..c217510e5 100644 --- a/CPP/Windows/MemoryGlobal.h +++ b/CPP/Windows/MemoryGlobal.h @@ -1,55 +1,55 @@ -// Windows/MemoryGlobal.h - -#ifndef __WINDOWS_MEMORY_GLOBAL_H -#define __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() - { - 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 != NULL) - GlobalUnlock(_global); - } -}; - -}} - -#endif +// Windows/MemoryGlobal.h + +#ifndef __WINDOWS_MEMORY_GLOBAL_H +#define __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() + { + 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 != NULL) + GlobalUnlock(_global); + } +}; + +}} + +#endif diff --git a/CPP/Windows/MemoryLock.cpp b/CPP/Windows/MemoryLock.cpp index d1b3bcc32..f9d08a6e6 100644 --- a/CPP/Windows/MemoryLock.cpp +++ b/CPP/Windows/MemoryLock.cpp @@ -1,112 +1,112 @@ -// 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) 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 + +}} diff --git a/CPP/Windows/MemoryLock.h b/CPP/Windows/MemoryLock.h index d82910feb..dcaf182e9 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 __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 diff --git a/CPP/Windows/Menu.cpp b/CPP/Windows/Menu.cpp index 8841c847a..3834881a8 100644 --- a/CPP/Windows/Menu.cpp +++ b/CPP/Windows/Menu.cpp @@ -1,212 +1,212 @@ -// 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 NT 4.0, if cbSize is set as sizeof(MENUITEMINFO*). -So we use size of old version of structure. */ - -#if defined(UNDER_CE) || defined(_WIN64) || (WINVER < 0x0500) - #define my_compatib_MENUITEMINFOA_size sizeof(MENUITEMINFOA) - #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)) - #define my_compatib_MENUITEMINFOA_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOA, hbmpItem) - #define my_compatib_MENUITEMINFOW_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOW, hbmpItem) -#endif - -static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOW &si) -{ - ZeroMemory(&si, sizeof(si)); - si.cbSize = my_compatib_MENUITEMINFOW_size; // sizeof(si); - si.fMask = item.fMask; - si.fType = item.fType; - si.fState = item.fState; - si.wID = item.wID; - si.hSubMenu = item.hSubMenu; - si.hbmpChecked = item.hbmpChecked; - si.hbmpUnchecked = item.hbmpUnchecked; - si.dwItemData = item.dwItemData; -} - -#ifndef _UNICODE -static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOA &si) -{ - ZeroMemory(&si, sizeof(si)); - si.cbSize = my_compatib_MENUITEMINFOA_size; // sizeof(si); - si.fMask = item.fMask; - si.fType = item.fType; - si.fState = item.fState; - si.wID = item.wID; - si.hSubMenu = item.hSubMenu; - si.hbmpChecked = item.hbmpChecked; - si.hbmpUnchecked = item.hbmpUnchecked; - si.dwItemData = item.dwItemData; -} -#endif - -static void ConvertItemToMyForm(const MENUITEMINFOW &si, CMenuItem &item) -{ - item.fMask = si.fMask; - item.fType = si.fType; - item.fState = si.fState; - item.wID = si.wID; - item.hSubMenu = si.hSubMenu; - item.hbmpChecked = si.hbmpChecked; - item.hbmpUnchecked = si.hbmpUnchecked; - item.dwItemData = si.dwItemData; -} - -#ifndef _UNICODE -static void ConvertItemToMyForm(const MENUITEMINFOA &si, CMenuItem &item) -{ - item.fMask = si.fMask; - item.fType = si.fType; - item.fState = si.fState; - item.wID = si.wID; - item.hSubMenu = si.hSubMenu; - item.hbmpChecked = si.hbmpChecked; - item.hbmpUnchecked = si.hbmpUnchecked; - item.dwItemData = si.dwItemData; -} -#endif - -bool CMenu::GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) -{ - const UINT kMaxSize = 512; - #ifndef _UNICODE - if (!g_IsNT) - { - CHAR s[kMaxSize + 1]; - MENUITEMINFOA si; - ConvertItemToSysForm(item, si); - if (item.IsString()) - { - si.cch = kMaxSize; - si.dwTypeData = s; - } - if (GetItemInfo(itemIndex, byPosition, &si)) - { - ConvertItemToMyForm(si, item); - if (item.IsString()) - item.StringValue = GetUnicodeString(s); - return true; - } - } - else - #endif - { - wchar_t s[kMaxSize + 1]; - MENUITEMINFOW si; - ConvertItemToSysForm(item, si); - if (item.IsString()) - { - si.cch = kMaxSize; - si.dwTypeData = s; - } - if (GetItemInfo(itemIndex, byPosition, &si)) - { - ConvertItemToMyForm(si, item); - if (item.IsString()) - item.StringValue = s; - return true; - } - } - return false; -} - -bool CMenu::SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - MENUITEMINFOA si; - ConvertItemToSysForm(item, si); - AString s; - if (item.IsString()) - { - s = GetSystemString(item.StringValue); - si.dwTypeData = (LPTSTR)(LPCTSTR)s; - } - return SetItemInfo(itemIndex, byPosition, &si); - } - else - #endif - { - MENUITEMINFOW si; - ConvertItemToSysForm(item, si); - if (item.IsString()) - si.dwTypeData = (LPWSTR)(LPCWSTR)item.StringValue; - return SetItemInfo(itemIndex, byPosition, &si); - } -} - -bool CMenu::InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - MENUITEMINFOA si; - ConvertItemToSysForm(item, si); - AString s; - if (item.IsString()) - { - s = GetSystemString(item.StringValue); - si.dwTypeData = (LPTSTR)(LPCTSTR)s; - } - return InsertItem(itemIndex, byPosition, &si); - } - else - #endif - { - MENUITEMINFOW si; - ConvertItemToSysForm(item, si); - if (item.IsString()) - si.dwTypeData = (LPWSTR)(LPCWSTR)item.StringValue; - #ifdef UNDER_CE - UINT flags = (item.fType & MFT_SEPARATOR) ? MF_SEPARATOR : MF_STRING; - UINT id = item.wID; - if ((item.fMask & MIIM_SUBMENU) != 0) - { - flags |= MF_POPUP; - id = (UINT)item.hSubMenu; - } - if (!Insert(itemIndex, flags | (byPosition ? MF_BYPOSITION : MF_BYCOMMAND), id, item.StringValue)) - return false; - return SetItemInfo(itemIndex, byPosition, &si); - #else - return InsertItem(itemIndex, byPosition, &si); - #endif - } -} - -#ifndef _UNICODE -bool CMenu::AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem) -{ - if (g_IsNT) - return BOOLToBool(::AppendMenuW(_menu, flags, newItemID, newItem)); - else - return AppendItem(flags, newItemID, GetSystemString(newItem)); -} -#endif - -} +// 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 NT 4.0, if cbSize is set as sizeof(MENUITEMINFO*). +So we use size of old version of structure. */ + +#if defined(UNDER_CE) || defined(_WIN64) || (WINVER < 0x0500) + #define my_compatib_MENUITEMINFOA_size sizeof(MENUITEMINFOA) + #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)) + #define my_compatib_MENUITEMINFOA_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOA, hbmpItem) + #define my_compatib_MENUITEMINFOW_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOW, hbmpItem) +#endif + +static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOW &si) +{ + ZeroMemory(&si, sizeof(si)); + si.cbSize = my_compatib_MENUITEMINFOW_size; // sizeof(si); + si.fMask = item.fMask; + si.fType = item.fType; + si.fState = item.fState; + si.wID = item.wID; + si.hSubMenu = item.hSubMenu; + si.hbmpChecked = item.hbmpChecked; + si.hbmpUnchecked = item.hbmpUnchecked; + si.dwItemData = item.dwItemData; +} + +#ifndef _UNICODE +static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOA &si) +{ + ZeroMemory(&si, sizeof(si)); + si.cbSize = my_compatib_MENUITEMINFOA_size; // sizeof(si); + si.fMask = item.fMask; + si.fType = item.fType; + si.fState = item.fState; + si.wID = item.wID; + si.hSubMenu = item.hSubMenu; + si.hbmpChecked = item.hbmpChecked; + si.hbmpUnchecked = item.hbmpUnchecked; + si.dwItemData = item.dwItemData; +} +#endif + +static void ConvertItemToMyForm(const MENUITEMINFOW &si, CMenuItem &item) +{ + item.fMask = si.fMask; + item.fType = si.fType; + item.fState = si.fState; + item.wID = si.wID; + item.hSubMenu = si.hSubMenu; + item.hbmpChecked = si.hbmpChecked; + item.hbmpUnchecked = si.hbmpUnchecked; + item.dwItemData = si.dwItemData; +} + +#ifndef _UNICODE +static void ConvertItemToMyForm(const MENUITEMINFOA &si, CMenuItem &item) +{ + item.fMask = si.fMask; + item.fType = si.fType; + item.fState = si.fState; + item.wID = si.wID; + item.hSubMenu = si.hSubMenu; + item.hbmpChecked = si.hbmpChecked; + item.hbmpUnchecked = si.hbmpUnchecked; + item.dwItemData = si.dwItemData; +} +#endif + +bool CMenu::GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) +{ + const UINT kMaxSize = 512; + #ifndef _UNICODE + if (!g_IsNT) + { + CHAR s[kMaxSize + 1]; + MENUITEMINFOA si; + ConvertItemToSysForm(item, si); + if (item.IsString()) + { + si.cch = kMaxSize; + si.dwTypeData = s; + } + if (GetItemInfo(itemIndex, byPosition, &si)) + { + ConvertItemToMyForm(si, item); + if (item.IsString()) + item.StringValue = GetUnicodeString(s); + return true; + } + } + else + #endif + { + wchar_t s[kMaxSize + 1]; + MENUITEMINFOW si; + ConvertItemToSysForm(item, si); + if (item.IsString()) + { + si.cch = kMaxSize; + si.dwTypeData = s; + } + if (GetItemInfo(itemIndex, byPosition, &si)) + { + ConvertItemToMyForm(si, item); + if (item.IsString()) + item.StringValue = s; + return true; + } + } + return false; +} + +bool CMenu::SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + MENUITEMINFOA si; + ConvertItemToSysForm(item, si); + AString s; + if (item.IsString()) + { + s = GetSystemString(item.StringValue); + si.dwTypeData = (LPTSTR)(LPCTSTR)s; + } + return SetItemInfo(itemIndex, byPosition, &si); + } + else + #endif + { + MENUITEMINFOW si; + ConvertItemToSysForm(item, si); + if (item.IsString()) + si.dwTypeData = (LPWSTR)(LPCWSTR)item.StringValue; + return SetItemInfo(itemIndex, byPosition, &si); + } +} + +bool CMenu::InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + MENUITEMINFOA si; + ConvertItemToSysForm(item, si); + AString s; + if (item.IsString()) + { + s = GetSystemString(item.StringValue); + si.dwTypeData = (LPTSTR)(LPCTSTR)s; + } + return InsertItem(itemIndex, byPosition, &si); + } + else + #endif + { + MENUITEMINFOW si; + ConvertItemToSysForm(item, si); + if (item.IsString()) + si.dwTypeData = (LPWSTR)(LPCWSTR)item.StringValue; + #ifdef UNDER_CE + UINT flags = (item.fType & MFT_SEPARATOR) ? MF_SEPARATOR : MF_STRING; + UINT id = item.wID; + if ((item.fMask & MIIM_SUBMENU) != 0) + { + flags |= MF_POPUP; + id = (UINT)item.hSubMenu; + } + if (!Insert(itemIndex, flags | (byPosition ? MF_BYPOSITION : MF_BYCOMMAND), id, item.StringValue)) + return false; + return SetItemInfo(itemIndex, byPosition, &si); + #else + return InsertItem(itemIndex, byPosition, &si); + #endif + } +} + +#ifndef _UNICODE +bool CMenu::AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem) +{ + if (g_IsNT) + return BOOLToBool(::AppendMenuW(_menu, flags, newItemID, newItem)); + else + return AppendItem(flags, newItemID, GetSystemString(newItem)); +} +#endif + +} diff --git a/CPP/Windows/Menu.h b/CPP/Windows/Menu.h index 8020d49a8..aacdc7c32 100644 --- a/CPP/Windows/Menu.h +++ b/CPP/Windows/Menu.h @@ -1,158 +1,158 @@ -// Windows/Menu.h - -#ifndef __WINDOWS_MENU_H -#define __WINDOWS_MENU_H - -#include "../Common/MyString.h" - -#include "Defs.h" - -namespace NWindows { - -struct CMenuItem -{ - UString StringValue; - UINT fMask; - UINT fType; - UINT fState; - UINT wID; - HMENU hSubMenu; - HBITMAP hbmpChecked; - HBITMAP hbmpUnchecked; - ULONG_PTR dwItemData; - // LPTSTR dwTypeData; - // UINT cch; - // HBITMAP hbmpItem; - bool IsString() const // change it MIIM_STRING - { return ((fMask & MIIM_TYPE) != 0 && (fType == MFT_STRING)); } - bool IsSeparator() const { return (fType == MFT_SEPARATOR); } - CMenuItem(): fMask(0), fType(0), fState(0), wID(0), hSubMenu(0), hbmpChecked(0), - hbmpUnchecked(0), dwItemData(0) {} -}; - -class CMenu -{ - HMENU _menu; -public: - CMenu(): _menu(NULL) {}; - operator HMENU() const { return _menu; } - void Attach(HMENU menu) { _menu = menu; } - - HMENU Detach() - { - HMENU menu = _menu; - _menu = NULL; - return menu; - } - - bool Create() - { - _menu = ::CreateMenu(); - return (_menu != NULL); - } - - bool CreatePopup() - { - _menu = ::CreatePopupMenu(); - return (_menu != NULL); - } - - bool Destroy() - { - if (_menu == NULL) - return false; - return BOOLToBool(::DestroyMenu(Detach())); - } - - int GetItemCount() - { - #ifdef UNDER_CE - for (int i = 0;; i++) - { - CMenuItem item; - item.fMask = MIIM_STATE; - if (!GetItem(i, true, item)) - return i; - } - #else - return GetMenuItemCount(_menu); - #endif - } - - HMENU GetSubMenu(int pos) { return ::GetSubMenu(_menu, pos); } - #ifndef UNDER_CE - /* - bool GetItemString(UINT idItem, UINT flag, CSysString &result) - { - result.Empty(); - int len = ::GetMenuString(_menu, idItem, 0, 0, flag); - 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) { return ::GetMenuItemID(_menu, pos); } - UINT GetItemState(UINT id, UINT flags) { return ::GetMenuState(_menu, id, flags); } - #endif - - bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo) - { return BOOLToBool(::GetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } - bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo) - { return BOOLToBool(::SetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } - - bool AppendItem(UINT flags, UINT_PTR newItemID, LPCTSTR newItem) - { return BOOLToBool(::AppendMenu(_menu, flags, newItemID, newItem)); } - - bool Insert(UINT position, UINT flags, UINT_PTR idNewItem, LPCTSTR newItem) - { return BOOLToBool(::InsertMenu(_menu, position, flags, idNewItem, newItem)); } - - #ifndef UNDER_CE - bool InsertItem(UINT itemIndex, bool byPosition, LPCMENUITEMINFO itemInfo) - { return BOOLToBool(::InsertMenuItem(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } - #endif - - bool RemoveItem(UINT item, UINT flags) { return BOOLToBool(::RemoveMenu(_menu, item, flags)); } - void RemoveAllItemsFrom(UINT index) { while (RemoveItem(index, MF_BYPOSITION)); } - void RemoveAllItems() { RemoveAllItemsFrom(0); } - - #ifndef _UNICODE - bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) - { return BOOLToBool(::GetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } - bool InsertItem(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) - { return BOOLToBool(::InsertMenuItemW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } - bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) - { return BOOLToBool(::SetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } - bool AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem); - #endif - - bool GetItem(UINT itemIndex, bool byPosition, CMenuItem &item); - bool SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item); - bool InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item); - - int Track(UINT flags, int x, int y, HWND hWnd) { return ::TrackPopupMenuEx(_menu, flags, x, y, hWnd, NULL); } - - bool CheckRadioItem(UINT idFirst, UINT idLast, UINT idCheck, UINT flags) - { return BOOLToBool(::CheckMenuRadioItem(_menu, idFirst, idLast, idCheck, flags)); } - - DWORD CheckItem(UINT id, UINT uCheck) { return ::CheckMenuItem(_menu, id, uCheck); } - DWORD CheckItemByID(UINT id, bool check) { return CheckItem(id, MF_BYCOMMAND | (check ? MF_CHECKED : MF_UNCHECKED)); } - - BOOL EnableItem(UINT uIDEnableItem, UINT uEnable) { return EnableMenuItem(_menu, uIDEnableItem, uEnable); } -}; - -class CMenuDestroyer -{ - CMenu *_menu; -public: - CMenuDestroyer(CMenu &menu): _menu(&menu) {} - CMenuDestroyer(): _menu(0) {} - ~CMenuDestroyer() { if (_menu) _menu->Destroy(); } - void Attach(CMenu &menu) { _menu = &menu; } - void Disable() { _menu = 0; } -}; - -} - -#endif +// Windows/Menu.h + +#ifndef __WINDOWS_MENU_H +#define __WINDOWS_MENU_H + +#include "../Common/MyString.h" + +#include "Defs.h" + +namespace NWindows { + +struct CMenuItem +{ + UString StringValue; + UINT fMask; + UINT fType; + UINT fState; + UINT wID; + HMENU hSubMenu; + HBITMAP hbmpChecked; + HBITMAP hbmpUnchecked; + ULONG_PTR dwItemData; + // LPTSTR dwTypeData; + // UINT cch; + // HBITMAP hbmpItem; + bool IsString() const // change it MIIM_STRING + { return ((fMask & MIIM_TYPE) != 0 && (fType == MFT_STRING)); } + bool IsSeparator() const { return (fType == MFT_SEPARATOR); } + CMenuItem(): fMask(0), fType(0), fState(0), wID(0), hSubMenu(0), hbmpChecked(0), + hbmpUnchecked(0), dwItemData(0) {} +}; + +class CMenu +{ + HMENU _menu; +public: + CMenu(): _menu(NULL) {}; + operator HMENU() const { return _menu; } + void Attach(HMENU menu) { _menu = menu; } + + HMENU Detach() + { + HMENU menu = _menu; + _menu = NULL; + return menu; + } + + bool Create() + { + _menu = ::CreateMenu(); + return (_menu != NULL); + } + + bool CreatePopup() + { + _menu = ::CreatePopupMenu(); + return (_menu != NULL); + } + + bool Destroy() + { + if (_menu == NULL) + return false; + return BOOLToBool(::DestroyMenu(Detach())); + } + + int GetItemCount() + { + #ifdef UNDER_CE + for (int i = 0;; i++) + { + CMenuItem item; + item.fMask = MIIM_STATE; + if (!GetItem(i, true, item)) + return i; + } + #else + return GetMenuItemCount(_menu); + #endif + } + + HMENU GetSubMenu(int pos) { return ::GetSubMenu(_menu, pos); } + #ifndef UNDER_CE + /* + bool GetItemString(UINT idItem, UINT flag, CSysString &result) + { + result.Empty(); + int len = ::GetMenuString(_menu, idItem, 0, 0, flag); + 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) { return ::GetMenuItemID(_menu, pos); } + UINT GetItemState(UINT id, UINT flags) { return ::GetMenuState(_menu, id, flags); } + #endif + + bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo) + { return BOOLToBool(::GetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } + bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo) + { return BOOLToBool(::SetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } + + bool AppendItem(UINT flags, UINT_PTR newItemID, LPCTSTR newItem) + { return BOOLToBool(::AppendMenu(_menu, flags, newItemID, newItem)); } + + bool Insert(UINT position, UINT flags, UINT_PTR idNewItem, LPCTSTR newItem) + { return BOOLToBool(::InsertMenu(_menu, position, flags, idNewItem, newItem)); } + + #ifndef UNDER_CE + bool InsertItem(UINT itemIndex, bool byPosition, LPCMENUITEMINFO itemInfo) + { return BOOLToBool(::InsertMenuItem(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } + #endif + + bool RemoveItem(UINT item, UINT flags) { return BOOLToBool(::RemoveMenu(_menu, item, flags)); } + void RemoveAllItemsFrom(UINT index) { while (RemoveItem(index, MF_BYPOSITION)); } + void RemoveAllItems() { RemoveAllItemsFrom(0); } + + #ifndef _UNICODE + bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) + { return BOOLToBool(::GetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } + bool InsertItem(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) + { return BOOLToBool(::InsertMenuItemW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } + bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) + { return BOOLToBool(::SetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } + bool AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem); + #endif + + bool GetItem(UINT itemIndex, bool byPosition, CMenuItem &item); + bool SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item); + bool InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item); + + int Track(UINT flags, int x, int y, HWND hWnd) { return ::TrackPopupMenuEx(_menu, flags, x, y, hWnd, NULL); } + + bool CheckRadioItem(UINT idFirst, UINT idLast, UINT idCheck, UINT flags) + { return BOOLToBool(::CheckMenuRadioItem(_menu, idFirst, idLast, idCheck, flags)); } + + DWORD CheckItem(UINT id, UINT uCheck) { return ::CheckMenuItem(_menu, id, uCheck); } + DWORD CheckItemByID(UINT id, bool check) { return CheckItem(id, MF_BYCOMMAND | (check ? MF_CHECKED : MF_UNCHECKED)); } + + BOOL EnableItem(UINT uIDEnableItem, UINT uEnable) { return EnableMenuItem(_menu, uIDEnableItem, uEnable); } +}; + +class CMenuDestroyer +{ + CMenu *_menu; +public: + CMenuDestroyer(CMenu &menu): _menu(&menu) {} + CMenuDestroyer(): _menu(0) {} + ~CMenuDestroyer() { if (_menu) _menu->Destroy(); } + void Attach(CMenu &menu) { _menu = &menu; } + void Disable() { _menu = 0; } +}; + +} + +#endif diff --git a/CPP/Windows/NationalTime.cpp b/CPP/Windows/NationalTime.cpp index 41a95e985..0dcd31e05 100644 --- a/CPP/Windows/NationalTime.cpp +++ b/CPP/Windows/NationalTime.cpp @@ -1,37 +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(numChars), numChars + 1); - resultString.ReleaseBuf_CalcLen(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(numChars), numChars + 1); - resultString.ReleaseBuf_CalcLen(numChars); - return (numChars != 0); -} - -}}} +// 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(numChars), numChars + 1); + resultString.ReleaseBuf_CalcLen(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(numChars), numChars + 1); + resultString.ReleaseBuf_CalcLen(numChars); + return (numChars != 0); +} + +}}} diff --git a/CPP/Windows/NationalTime.h b/CPP/Windows/NationalTime.h index a49f1c3bd..49b0e5e82 100644 --- a/CPP/Windows/NationalTime.h +++ b/CPP/Windows/NationalTime.h @@ -1,20 +1,20 @@ -// Windows/NationalTime.h - -#ifndef __WINDOWS_NATIONAL_TIME_H -#define __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 +// Windows/NationalTime.h + +#ifndef __WINDOWS_NATIONAL_TIME_H +#define __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 index e3e276b5c..14d06d6e8 100644 --- a/CPP/Windows/Net.cpp +++ b/CPP/Windows/Net.cpp @@ -1,376 +1,376 @@ -// 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 - -namespace NWindows { -namespace NNet { - -DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource) -{ - Close(); - DWORD result = ::WNetOpenEnum(scope, type, usage, netResource, &_handle); - _handleAllocated = (result == NO_ERROR); - return result; -} - -#ifndef _UNICODE -DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource) -{ - Close(); - DWORD result = ::WNetOpenEnumW(scope, type, usage, netResource, &_handle); - _handleAllocated = (result == NO_ERROR); - return result; -} -#endif - -static void SetComplexString(bool &defined, CSysString &destString, LPCTSTR srsString) -{ - defined = (srsString != 0); - if (defined) - destString = srsString; - else - destString.Empty(); -} - -static void ConvertNETRESOURCEToCResource(const NETRESOURCE &netResource, CResource &resource) -{ - resource.Scope = netResource.dwScope; - resource.Type = netResource.dwType; - resource.DisplayType = netResource.dwDisplayType; - resource.Usage = netResource.dwUsage; - SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName); - SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName); - SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment); - SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider); -} - -static void SetComplexString2(LPTSTR *destString, bool defined, const CSysString &srcString) -{ - if (defined) - *destString = (TCHAR *)(const TCHAR *)srcString; - else - *destString = 0; -} - -static void ConvertCResourceToNETRESOURCE(const CResource &resource, NETRESOURCE &netResource) -{ - netResource.dwScope = resource.Scope; - netResource.dwType = resource.Type; - netResource.dwDisplayType = resource.DisplayType; - netResource.dwUsage = resource.Usage; - SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName); - SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName); - SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment); - SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider); -} - -#ifndef _UNICODE - -static void SetComplexString(bool &defined, UString &destString, LPCWSTR srsString) -{ - defined = (srsString != 0); - if (defined) - destString = srsString; - else - destString.Empty(); -} - -static void ConvertNETRESOURCEToCResource(const NETRESOURCEW &netResource, CResourceW &resource) -{ - resource.Scope = netResource.dwScope; - resource.Type = netResource.dwType; - resource.DisplayType = netResource.dwDisplayType; - resource.Usage = netResource.dwUsage; - SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName); - SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName); - SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment); - SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider); -} - -static void SetComplexString2(LPWSTR *destString, bool defined, const UString &srcString) -{ - if (defined) - *destString = (WCHAR *)(const WCHAR *)srcString; - else - *destString = 0; -} - -static void ConvertCResourceToNETRESOURCE(const CResourceW &resource, NETRESOURCEW &netResource) -{ - netResource.dwScope = resource.Scope; - netResource.dwType = resource.Type; - netResource.dwDisplayType = resource.DisplayType; - netResource.dwUsage = resource.Usage; - SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName); - SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName); - SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment); - SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider); -} - -static void ConvertResourceWToResource(const CResourceW &resourceW, CResource &resource) -{ - *(CResourceBase *)&resource = *(CResourceBase *)&resourceW; - resource.LocalName = GetSystemString(resourceW.LocalName); - resource.RemoteName = GetSystemString(resourceW.RemoteName); - resource.Comment = GetSystemString(resourceW.Comment); - resource.Provider = GetSystemString(resourceW.Provider); -} - -static void ConvertResourceToResourceW(const CResource &resource, CResourceW &resourceW) -{ - *(CResourceBase *)&resourceW = *(CResourceBase *)&resource; - resourceW.LocalName = GetUnicodeString(resource.LocalName); - resourceW.RemoteName = GetUnicodeString(resource.RemoteName); - resourceW.Comment = GetUnicodeString(resource.Comment); - resourceW.Provider = GetUnicodeString(resource.Provider); -} -#endif - -DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource) -{ - NETRESOURCE netResource; - LPNETRESOURCE pointer; - if (resource == 0) - pointer = 0; - else - { - ConvertCResourceToNETRESOURCE(*resource, netResource); - pointer = &netResource; - } - return Open(scope, type, usage, pointer); -} - -#ifndef _UNICODE -DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource) -{ - if (g_IsNT) - { - NETRESOURCEW netResource; - LPNETRESOURCEW pointer; - if (resource == 0) - pointer = 0; - else - { - ConvertCResourceToNETRESOURCE(*resource, netResource); - pointer = &netResource; - } - return Open(scope, type, usage, pointer); - } - CResource *pointer; - CResource resourceA; - if (resource == 0) - pointer = 0; - else - { - ConvertResourceWToResource(*resource, resourceA); - pointer = &resourceA; - } - return Open(scope, type, usage, pointer); -} -#endif - -DWORD CEnum::Close() -{ - if (!_handleAllocated) - return NO_ERROR; - DWORD result = ::WNetCloseEnum(_handle); - _handleAllocated = (result != NO_ERROR); - return result; -} - -DWORD CEnum::Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) -{ - return ::WNetEnumResource(_handle, lpcCount, lpBuffer, lpBufferSize); -} - -#ifndef _UNICODE -DWORD CEnum::NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) -{ - return ::WNetEnumResourceW(_handle, lpcCount, lpBuffer, lpBufferSize); -} -#endif - -DWORD CEnum::Next(CResource &resource) -{ - const DWORD kBufferSize = 16384; - CByteArr byteBuffer(kBufferSize); - LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (BYTE *)(byteBuffer); - ZeroMemory(lpnrLocal, kBufferSize); - DWORD bufferSize = kBufferSize; - DWORD numEntries = 1; - DWORD result = Next(&numEntries, lpnrLocal, &bufferSize); - if (result != NO_ERROR) - return result; - if (numEntries != 1) - return (DWORD)E_FAIL; - ConvertNETRESOURCEToCResource(lpnrLocal[0], resource); - return result; -} - -#ifndef _UNICODE -DWORD CEnum::Next(CResourceW &resource) -{ - if (g_IsNT) - { - const DWORD kBufferSize = 16384; - CByteArr byteBuffer(kBufferSize); - LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (BYTE *)(byteBuffer); - ZeroMemory(lpnrLocal, kBufferSize); - DWORD bufferSize = kBufferSize; - DWORD numEntries = 1; - DWORD result = NextW(&numEntries, lpnrLocal, &bufferSize); - if (result != NO_ERROR) - return result; - if (numEntries != 1) - return (DWORD)E_FAIL; - ConvertNETRESOURCEToCResource(lpnrLocal[0], resource); - return result; - } - CResource resourceA; - DWORD result = Next(resourceA); - ConvertResourceToResourceW(resourceA, resource); - return result; -} -#endif - - -DWORD GetResourceParent(const CResource &resource, CResource &parentResource) -{ - const DWORD kBufferSize = 16384; - CByteArr byteBuffer(kBufferSize); - LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (BYTE *)(byteBuffer); - ZeroMemory(lpnrLocal, kBufferSize); - DWORD bufferSize = kBufferSize; - NETRESOURCE netResource; - ConvertCResourceToNETRESOURCE(resource, netResource); - DWORD result = ::WNetGetResourceParent(&netResource, lpnrLocal, &bufferSize); - if (result != NO_ERROR) - return result; - ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource); - return result; -} - -#ifndef _UNICODE -DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource) -{ - if (g_IsNT) - { - const DWORD kBufferSize = 16384; - CByteArr byteBuffer(kBufferSize); - LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (BYTE *)(byteBuffer); - ZeroMemory(lpnrLocal, kBufferSize); - DWORD bufferSize = kBufferSize; - NETRESOURCEW netResource; - ConvertCResourceToNETRESOURCE(resource, netResource); - DWORD result = ::WNetGetResourceParentW(&netResource, lpnrLocal, &bufferSize); - if (result != NO_ERROR) - return result; - ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource); - return result; - } - CResource resourceA, parentResourceA; - ConvertResourceWToResource(resource, resourceA); - DWORD result = GetResourceParent(resourceA, parentResourceA); - ConvertResourceToResourceW(parentResourceA, parentResource); - return result; -} -#endif - -DWORD GetResourceInformation(const CResource &resource, - CResource &destResource, CSysString &systemPathPart) -{ - const DWORD kBufferSize = 16384; - CByteArr byteBuffer(kBufferSize); - LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (BYTE *)(byteBuffer); - ZeroMemory(lpnrLocal, kBufferSize); - DWORD bufferSize = kBufferSize; - NETRESOURCE netResource; - ConvertCResourceToNETRESOURCE(resource, netResource); - LPTSTR lplpSystem; - DWORD result = ::WNetGetResourceInformation(&netResource, - lpnrLocal, &bufferSize, &lplpSystem); - if (result != NO_ERROR) - return result; - if (lplpSystem != 0) - systemPathPart = lplpSystem; - ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource); - return result; -} - -#ifndef _UNICODE -DWORD GetResourceInformation(const CResourceW &resource, - CResourceW &destResource, UString &systemPathPart) -{ - if (g_IsNT) - { - const DWORD kBufferSize = 16384; - CByteArr byteBuffer(kBufferSize); - LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (BYTE *)(byteBuffer); - ZeroMemory(lpnrLocal, kBufferSize); - DWORD bufferSize = kBufferSize; - NETRESOURCEW netResource; - ConvertCResourceToNETRESOURCE(resource, netResource); - LPWSTR lplpSystem; - DWORD result = ::WNetGetResourceInformationW(&netResource, - lpnrLocal, &bufferSize, &lplpSystem); - if (result != NO_ERROR) - return result; - if (lplpSystem != 0) - systemPathPart = lplpSystem; - ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource); - return result; - } - CResource resourceA, destResourceA; - ConvertResourceWToResource(resource, resourceA); - AString systemPathPartA; - DWORD result = GetResourceInformation(resourceA, destResourceA, systemPathPartA); - ConvertResourceToResourceW(destResourceA, destResource); - systemPathPart = GetUnicodeString(systemPathPartA); - return result; -} -#endif - -DWORD AddConnection2(const CResource &resource, - LPCTSTR password, LPCTSTR userName, DWORD flags) -{ - NETRESOURCE netResource; - ConvertCResourceToNETRESOURCE(resource, netResource); - return ::WNetAddConnection2(&netResource, - password, userName, flags); -} - -DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags); - -#ifndef _UNICODE -DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags) -{ - if (g_IsNT) - { - NETRESOURCEW netResource; - ConvertCResourceToNETRESOURCE(resource, netResource); - return ::WNetAddConnection2W(&netResource,password, userName, flags); - } - CResource resourceA; - ConvertResourceWToResource(resource, resourceA); - const CSysString passwordA (GetSystemString(password)); - const CSysString userNameA (GetSystemString(userName)); - return AddConnection2(resourceA, - password ? (LPCTSTR)passwordA: 0, - userName ? (LPCTSTR)userNameA: 0, - flags); -} -#endif - -}} +// 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 + +namespace NWindows { +namespace NNet { + +DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource) +{ + Close(); + DWORD result = ::WNetOpenEnum(scope, type, usage, netResource, &_handle); + _handleAllocated = (result == NO_ERROR); + return result; +} + +#ifndef _UNICODE +DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource) +{ + Close(); + DWORD result = ::WNetOpenEnumW(scope, type, usage, netResource, &_handle); + _handleAllocated = (result == NO_ERROR); + return result; +} +#endif + +static void SetComplexString(bool &defined, CSysString &destString, LPCTSTR srsString) +{ + defined = (srsString != 0); + if (defined) + destString = srsString; + else + destString.Empty(); +} + +static void ConvertNETRESOURCEToCResource(const NETRESOURCE &netResource, CResource &resource) +{ + resource.Scope = netResource.dwScope; + resource.Type = netResource.dwType; + resource.DisplayType = netResource.dwDisplayType; + resource.Usage = netResource.dwUsage; + SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName); + SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName); + SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment); + SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider); +} + +static void SetComplexString2(LPTSTR *destString, bool defined, const CSysString &srcString) +{ + if (defined) + *destString = (TCHAR *)(const TCHAR *)srcString; + else + *destString = 0; +} + +static void ConvertCResourceToNETRESOURCE(const CResource &resource, NETRESOURCE &netResource) +{ + netResource.dwScope = resource.Scope; + netResource.dwType = resource.Type; + netResource.dwDisplayType = resource.DisplayType; + netResource.dwUsage = resource.Usage; + SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName); + SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName); + SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment); + SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider); +} + +#ifndef _UNICODE + +static void SetComplexString(bool &defined, UString &destString, LPCWSTR srsString) +{ + defined = (srsString != 0); + if (defined) + destString = srsString; + else + destString.Empty(); +} + +static void ConvertNETRESOURCEToCResource(const NETRESOURCEW &netResource, CResourceW &resource) +{ + resource.Scope = netResource.dwScope; + resource.Type = netResource.dwType; + resource.DisplayType = netResource.dwDisplayType; + resource.Usage = netResource.dwUsage; + SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName); + SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName); + SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment); + SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider); +} + +static void SetComplexString2(LPWSTR *destString, bool defined, const UString &srcString) +{ + if (defined) + *destString = (WCHAR *)(const WCHAR *)srcString; + else + *destString = 0; +} + +static void ConvertCResourceToNETRESOURCE(const CResourceW &resource, NETRESOURCEW &netResource) +{ + netResource.dwScope = resource.Scope; + netResource.dwType = resource.Type; + netResource.dwDisplayType = resource.DisplayType; + netResource.dwUsage = resource.Usage; + SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName); + SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName); + SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment); + SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider); +} + +static void ConvertResourceWToResource(const CResourceW &resourceW, CResource &resource) +{ + *(CResourceBase *)&resource = *(CResourceBase *)&resourceW; + resource.LocalName = GetSystemString(resourceW.LocalName); + resource.RemoteName = GetSystemString(resourceW.RemoteName); + resource.Comment = GetSystemString(resourceW.Comment); + resource.Provider = GetSystemString(resourceW.Provider); +} + +static void ConvertResourceToResourceW(const CResource &resource, CResourceW &resourceW) +{ + *(CResourceBase *)&resourceW = *(CResourceBase *)&resource; + resourceW.LocalName = GetUnicodeString(resource.LocalName); + resourceW.RemoteName = GetUnicodeString(resource.RemoteName); + resourceW.Comment = GetUnicodeString(resource.Comment); + resourceW.Provider = GetUnicodeString(resource.Provider); +} +#endif + +DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource) +{ + NETRESOURCE netResource; + LPNETRESOURCE pointer; + if (resource == 0) + pointer = 0; + else + { + ConvertCResourceToNETRESOURCE(*resource, netResource); + pointer = &netResource; + } + return Open(scope, type, usage, pointer); +} + +#ifndef _UNICODE +DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource) +{ + if (g_IsNT) + { + NETRESOURCEW netResource; + LPNETRESOURCEW pointer; + if (resource == 0) + pointer = 0; + else + { + ConvertCResourceToNETRESOURCE(*resource, netResource); + pointer = &netResource; + } + return Open(scope, type, usage, pointer); + } + CResource *pointer; + CResource resourceA; + if (resource == 0) + pointer = 0; + else + { + ConvertResourceWToResource(*resource, resourceA); + pointer = &resourceA; + } + return Open(scope, type, usage, pointer); +} +#endif + +DWORD CEnum::Close() +{ + if (!_handleAllocated) + return NO_ERROR; + DWORD result = ::WNetCloseEnum(_handle); + _handleAllocated = (result != NO_ERROR); + return result; +} + +DWORD CEnum::Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + return ::WNetEnumResource(_handle, lpcCount, lpBuffer, lpBufferSize); +} + +#ifndef _UNICODE +DWORD CEnum::NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + return ::WNetEnumResourceW(_handle, lpcCount, lpBuffer, lpBufferSize); +} +#endif + +DWORD CEnum::Next(CResource &resource) +{ + const DWORD kBufferSize = 16384; + CByteArr byteBuffer(kBufferSize); + LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (BYTE *)(byteBuffer); + ZeroMemory(lpnrLocal, kBufferSize); + DWORD bufferSize = kBufferSize; + DWORD numEntries = 1; + DWORD result = Next(&numEntries, lpnrLocal, &bufferSize); + if (result != NO_ERROR) + return result; + if (numEntries != 1) + return (DWORD)E_FAIL; + ConvertNETRESOURCEToCResource(lpnrLocal[0], resource); + return result; +} + +#ifndef _UNICODE +DWORD CEnum::Next(CResourceW &resource) +{ + if (g_IsNT) + { + const DWORD kBufferSize = 16384; + CByteArr byteBuffer(kBufferSize); + LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (BYTE *)(byteBuffer); + ZeroMemory(lpnrLocal, kBufferSize); + DWORD bufferSize = kBufferSize; + DWORD numEntries = 1; + DWORD result = NextW(&numEntries, lpnrLocal, &bufferSize); + if (result != NO_ERROR) + return result; + if (numEntries != 1) + return (DWORD)E_FAIL; + ConvertNETRESOURCEToCResource(lpnrLocal[0], resource); + return result; + } + CResource resourceA; + DWORD result = Next(resourceA); + ConvertResourceToResourceW(resourceA, resource); + return result; +} +#endif + + +DWORD GetResourceParent(const CResource &resource, CResource &parentResource) +{ + const DWORD kBufferSize = 16384; + CByteArr byteBuffer(kBufferSize); + LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (BYTE *)(byteBuffer); + ZeroMemory(lpnrLocal, kBufferSize); + DWORD bufferSize = kBufferSize; + NETRESOURCE netResource; + ConvertCResourceToNETRESOURCE(resource, netResource); + DWORD result = ::WNetGetResourceParent(&netResource, lpnrLocal, &bufferSize); + if (result != NO_ERROR) + return result; + ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource); + return result; +} + +#ifndef _UNICODE +DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource) +{ + if (g_IsNT) + { + const DWORD kBufferSize = 16384; + CByteArr byteBuffer(kBufferSize); + LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (BYTE *)(byteBuffer); + ZeroMemory(lpnrLocal, kBufferSize); + DWORD bufferSize = kBufferSize; + NETRESOURCEW netResource; + ConvertCResourceToNETRESOURCE(resource, netResource); + DWORD result = ::WNetGetResourceParentW(&netResource, lpnrLocal, &bufferSize); + if (result != NO_ERROR) + return result; + ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource); + return result; + } + CResource resourceA, parentResourceA; + ConvertResourceWToResource(resource, resourceA); + DWORD result = GetResourceParent(resourceA, parentResourceA); + ConvertResourceToResourceW(parentResourceA, parentResource); + return result; +} +#endif + +DWORD GetResourceInformation(const CResource &resource, + CResource &destResource, CSysString &systemPathPart) +{ + const DWORD kBufferSize = 16384; + CByteArr byteBuffer(kBufferSize); + LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (BYTE *)(byteBuffer); + ZeroMemory(lpnrLocal, kBufferSize); + DWORD bufferSize = kBufferSize; + NETRESOURCE netResource; + ConvertCResourceToNETRESOURCE(resource, netResource); + LPTSTR lplpSystem; + DWORD result = ::WNetGetResourceInformation(&netResource, + lpnrLocal, &bufferSize, &lplpSystem); + if (result != NO_ERROR) + return result; + if (lplpSystem != 0) + systemPathPart = lplpSystem; + ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource); + return result; +} + +#ifndef _UNICODE +DWORD GetResourceInformation(const CResourceW &resource, + CResourceW &destResource, UString &systemPathPart) +{ + if (g_IsNT) + { + const DWORD kBufferSize = 16384; + CByteArr byteBuffer(kBufferSize); + LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (BYTE *)(byteBuffer); + ZeroMemory(lpnrLocal, kBufferSize); + DWORD bufferSize = kBufferSize; + NETRESOURCEW netResource; + ConvertCResourceToNETRESOURCE(resource, netResource); + LPWSTR lplpSystem; + DWORD result = ::WNetGetResourceInformationW(&netResource, + lpnrLocal, &bufferSize, &lplpSystem); + if (result != NO_ERROR) + return result; + if (lplpSystem != 0) + systemPathPart = lplpSystem; + ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource); + return result; + } + CResource resourceA, destResourceA; + ConvertResourceWToResource(resource, resourceA); + AString systemPathPartA; + DWORD result = GetResourceInformation(resourceA, destResourceA, systemPathPartA); + ConvertResourceToResourceW(destResourceA, destResource); + systemPathPart = GetUnicodeString(systemPathPartA); + return result; +} +#endif + +DWORD AddConnection2(const CResource &resource, + LPCTSTR password, LPCTSTR userName, DWORD flags) +{ + NETRESOURCE netResource; + ConvertCResourceToNETRESOURCE(resource, netResource); + return ::WNetAddConnection2(&netResource, + password, userName, flags); +} + +DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags); + +#ifndef _UNICODE +DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags) +{ + if (g_IsNT) + { + NETRESOURCEW netResource; + ConvertCResourceToNETRESOURCE(resource, netResource); + return ::WNetAddConnection2W(&netResource,password, userName, flags); + } + CResource resourceA; + ConvertResourceWToResource(resource, resourceA); + 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 index d77cb7b03..7b60b1b43 100644 --- a/CPP/Windows/Net.h +++ b/CPP/Windows/Net.h @@ -1,86 +1,86 @@ -// Windows/Net.h - -#ifndef __WINDOWS_NET_H -#define __WINDOWS_NET_H - -#include "../Common/MyString.h" - -namespace NWindows { -namespace NNet { - -struct CResourceBase -{ - DWORD Scope; - DWORD Type; - DWORD DisplayType; - DWORD Usage; - bool LocalNameIsDefined; - bool RemoteNameIsDefined; - bool CommentIsDefined; - bool ProviderIsDefined; -}; - -struct CResource: public CResourceBase -{ - CSysString LocalName; - CSysString RemoteName; - CSysString Comment; - CSysString Provider; -}; - -#ifdef _UNICODE -typedef CResource CResourceW; -#else -struct CResourceW: public CResourceBase -{ - UString LocalName; - UString RemoteName; - UString Comment; - UString Provider; -}; -#endif - -class CEnum -{ - HANDLE _handle; - bool _handleAllocated; - DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource); - DWORD Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize); - #ifndef _UNICODE - DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource); - DWORD NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize); - #endif -protected: - bool IsHandleAllocated() const { return _handleAllocated; } -public: - CEnum(): _handleAllocated(false) {} - ~CEnum() { Close(); } - DWORD Close(); - DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource); - DWORD Next(CResource &resource); - #ifndef _UNICODE - DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource); - DWORD Next(CResourceW &resource); - #endif -}; - -DWORD GetResourceParent(const CResource &resource, CResource &parentResource); -#ifndef _UNICODE -DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource); -#endif - -DWORD GetResourceInformation(const CResource &resource, - CResource &destResource, CSysString &systemPathPart); -#ifndef _UNICODE -DWORD GetResourceInformation(const CResourceW &resource, - CResourceW &destResource, UString &systemPathPart); -#endif - -DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags); -#ifndef _UNICODE -DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags); -#endif - -}} - -#endif +// Windows/Net.h + +#ifndef __WINDOWS_NET_H +#define __WINDOWS_NET_H + +#include "../Common/MyString.h" + +namespace NWindows { +namespace NNet { + +struct CResourceBase +{ + DWORD Scope; + DWORD Type; + DWORD DisplayType; + DWORD Usage; + bool LocalNameIsDefined; + bool RemoteNameIsDefined; + bool CommentIsDefined; + bool ProviderIsDefined; +}; + +struct CResource: public CResourceBase +{ + CSysString LocalName; + CSysString RemoteName; + CSysString Comment; + CSysString Provider; +}; + +#ifdef _UNICODE +typedef CResource CResourceW; +#else +struct CResourceW: public CResourceBase +{ + UString LocalName; + UString RemoteName; + UString Comment; + UString Provider; +}; +#endif + +class CEnum +{ + HANDLE _handle; + bool _handleAllocated; + DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource); + DWORD Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize); + #ifndef _UNICODE + DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource); + DWORD NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize); + #endif +protected: + bool IsHandleAllocated() const { return _handleAllocated; } +public: + CEnum(): _handleAllocated(false) {} + ~CEnum() { Close(); } + DWORD Close(); + DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource); + DWORD Next(CResource &resource); + #ifndef _UNICODE + DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource); + DWORD Next(CResourceW &resource); + #endif +}; + +DWORD GetResourceParent(const CResource &resource, CResource &parentResource); +#ifndef _UNICODE +DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource); +#endif + +DWORD GetResourceInformation(const CResource &resource, + CResource &destResource, CSysString &systemPathPart); +#ifndef _UNICODE +DWORD GetResourceInformation(const CResourceW &resource, + CResourceW &destResource, UString &systemPathPart); +#endif + +DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags); +#ifndef _UNICODE +DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags); +#endif + +}} + +#endif diff --git a/CPP/Windows/NtCheck.h b/CPP/Windows/NtCheck.h index 401e239e0..a1b89ef2d 100644 --- a/CPP/Windows/NtCheck.h +++ b/CPP/Windows/NtCheck.h @@ -1,46 +1,46 @@ -// 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 __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 diff --git a/CPP/Windows/ProcessMessages.cpp b/CPP/Windows/ProcessMessages.cpp index 439d3fdbb..0f48aee25 100644 --- a/CPP/Windows/ProcessMessages.cpp +++ b/CPP/Windows/ProcessMessages.cpp @@ -1,22 +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); - } - } -} - -} +// 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 index de65d283b..b2558a017 100644 --- a/CPP/Windows/ProcessMessages.h +++ b/CPP/Windows/ProcessMessages.h @@ -1,12 +1,12 @@ -// Windows/ProcessMessages.h - -#ifndef __WINDOWS_PROCESSMESSAGES_H -#define __WINDOWS_PROCESSMESSAGES_H - -namespace NWindows { - -void ProcessMessages(HWND window); - -} - -#endif +// Windows/ProcessMessages.h + +#ifndef __WINDOWS_PROCESSMESSAGES_H +#define __WINDOWS_PROCESSMESSAGES_H + +namespace NWindows { + +void ProcessMessages(HWND window); + +} + +#endif diff --git a/CPP/Windows/ProcessUtils.cpp b/CPP/Windows/ProcessUtils.cpp index fc129e196..f7878d51f 100644 --- a/CPP/Windows/ProcessUtils.cpp +++ b/CPP/Windows/ProcessUtils.cpp @@ -1,86 +1,86 @@ -// 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 ¶ms, LPCWSTR curDir) -{ - Close(); - const UString params2 = - #ifndef UNDER_CE - GetQuotedString(imageName) + L' ' + - #endif - params; - #ifdef UNDER_CE - curDir = 0; - #else - imageName = 0; - #endif - PROCESS_INFORMATION pi; - BOOL result; - #ifndef _UNICODE - if (!g_IsNT) - { - STARTUPINFOA si; - si.cb = sizeof(si); - si.lpReserved = 0; - si.lpDesktop = 0; - si.lpTitle = 0; - si.dwFlags = 0; - si.cbReserved2 = 0; - si.lpReserved2 = 0; - - CSysString curDirA; - if (curDir != 0) - curDirA = GetSystemString(curDir); - result = ::CreateProcessA(NULL, (LPSTR)(LPCSTR)GetSystemString(params2), - NULL, NULL, FALSE, 0, NULL, ((curDir != 0) ? (LPCSTR)curDirA: 0), &si, &pi); - } - else - #endif - { - STARTUPINFOW si; - si.cb = sizeof(si); - si.lpReserved = 0; - si.lpDesktop = 0; - si.lpTitle = 0; - si.dwFlags = 0; - si.cbReserved2 = 0; - si.lpReserved2 = 0; - - result = CreateProcessW(imageName, (LPWSTR)(LPCWSTR)params2, - NULL, NULL, FALSE, 0, NULL, (LPWSTR)curDir, &si, &pi); - } - if (result == 0) - return ::GetLastError(); - ::CloseHandle(pi.hThread); - _handle = pi.hProcess; - return 0; -} - -WRes MyCreateProcess(LPCWSTR imageName, const UString ¶ms) -{ - CProcess process; - return process.Create(imageName, params, 0); -} - -} +// 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 ¶ms, LPCWSTR curDir) +{ + Close(); + const UString params2 = + #ifndef UNDER_CE + GetQuotedString(imageName) + L' ' + + #endif + params; + #ifdef UNDER_CE + curDir = 0; + #else + imageName = 0; + #endif + PROCESS_INFORMATION pi; + BOOL result; + #ifndef _UNICODE + if (!g_IsNT) + { + STARTUPINFOA si; + si.cb = sizeof(si); + si.lpReserved = 0; + si.lpDesktop = 0; + si.lpTitle = 0; + si.dwFlags = 0; + si.cbReserved2 = 0; + si.lpReserved2 = 0; + + CSysString curDirA; + if (curDir != 0) + curDirA = GetSystemString(curDir); + result = ::CreateProcessA(NULL, (LPSTR)(LPCSTR)GetSystemString(params2), + NULL, NULL, FALSE, 0, NULL, ((curDir != 0) ? (LPCSTR)curDirA: 0), &si, &pi); + } + else + #endif + { + STARTUPINFOW si; + si.cb = sizeof(si); + si.lpReserved = 0; + si.lpDesktop = 0; + si.lpTitle = 0; + si.dwFlags = 0; + si.cbReserved2 = 0; + si.lpReserved2 = 0; + + result = CreateProcessW(imageName, (LPWSTR)(LPCWSTR)params2, + NULL, NULL, FALSE, 0, NULL, (LPWSTR)curDir, &si, &pi); + } + if (result == 0) + return ::GetLastError(); + ::CloseHandle(pi.hThread); + _handle = pi.hProcess; + return 0; +} + +WRes MyCreateProcess(LPCWSTR imageName, const UString ¶ms) +{ + CProcess process; + return process.Create(imageName, params, 0); +} + +} diff --git a/CPP/Windows/ProcessUtils.h b/CPP/Windows/ProcessUtils.h index de46c6f52..a50bb5fca 100644 --- a/CPP/Windows/ProcessUtils.h +++ b/CPP/Windows/ProcessUtils.h @@ -1,100 +1,100 @@ -// Windows/ProcessUtils.h - -#ifndef __WINDOWS_PROCESS_UTILS_H -#define __WINDOWS_PROCESS_UTILS_H - -#include - -#include "../Common/MyString.h" - -#include "Defs.h" -#include "Handle.h" - -namespace NWindows { - -class CProcess: public CHandle -{ -public: - bool Open(DWORD desiredAccess, bool inheritHandle, DWORD processId) - { - _handle = ::OpenProcess(desiredAccess, inheritHandle, processId); - return (_handle != 0); - } - - #ifndef UNDER_CE - - bool GetExitCodeProcess(LPDWORD lpExitCode) { return BOOLToBool(::GetExitCodeProcess(_handle, lpExitCode)); } - bool Terminate(UINT exitCode) { return BOOLToBool(::TerminateProcess(_handle, exitCode)); } - #if (WINVER >= 0x0500) - DWORD GetGuiResources (DWORD uiFlags) { return ::GetGuiResources(_handle, uiFlags); } - #endif - bool SetPriorityClass(DWORD dwPriorityClass) { return BOOLToBool(::SetPriorityClass(_handle, dwPriorityClass)); } - DWORD GetPriorityClass() { return ::GetPriorityClass(_handle); } - // bool GetIoCounters(PIO_COUNTERS lpIoCounters ) { return BOOLToBool(::GetProcessIoCounters(_handle, lpIoCounters )); } - - bool GetTimes(LPFILETIME creationTime, LPFILETIME exitTime, LPFILETIME kernelTime, LPFILETIME userTime) - { return BOOLToBool(::GetProcessTimes(_handle, creationTime, exitTime, kernelTime, userTime)); } - - DWORD WaitForInputIdle(DWORD milliseconds) { return ::WaitForInputIdle(_handle, milliseconds); } - - // Debug - - bool ReadMemory(LPCVOID baseAddress, LPVOID buffer, SIZE_T size, SIZE_T* numberOfBytesRead) - { return BOOLToBool(::ReadProcessMemory(_handle, baseAddress, buffer, size, numberOfBytesRead)); } - - bool WriteMemory(LPVOID baseAddress, LPCVOID buffer, SIZE_T size, SIZE_T* numberOfBytesWritten) - { return BOOLToBool(::WriteProcessMemory(_handle, baseAddress, buffer, size, numberOfBytesWritten)); } - - bool FlushInstructionCache(LPCVOID baseAddress = 0, SIZE_T size = 0) - { return BOOLToBool(::FlushInstructionCache(_handle, baseAddress, size)); } - - LPVOID VirtualAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect) - { return VirtualAllocEx(_handle, address, size, allocationType, protect); } - - bool VirtualFree(LPVOID address, SIZE_T size, DWORD freeType) - { return BOOLToBool(::VirtualFreeEx(_handle, address, size, freeType)); } - - // Process Status API (PSAPI) - - bool EmptyWorkingSet() - { return BOOLToBool(::EmptyWorkingSet(_handle)); } - bool EnumModules(HMODULE *hModules, DWORD arraySizeInBytes, LPDWORD receivedBytes) - { return BOOLToBool(::EnumProcessModules(_handle, hModules, arraySizeInBytes, receivedBytes)); } - - DWORD MyGetModuleBaseName(HMODULE hModule, LPTSTR baseName, DWORD size) - { return ::GetModuleBaseName(_handle, hModule, baseName, size); } - bool MyGetModuleBaseName(HMODULE hModule, CSysString &name) - { - const unsigned len = MAX_PATH + 100; - 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; - 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 ¶ms, LPCWSTR curDir); - - DWORD Wait() { return ::WaitForSingleObject(_handle, INFINITE); } -}; - -WRes MyCreateProcess(LPCWSTR imageName, const UString ¶ms); - -} - -#endif +// Windows/ProcessUtils.h + +#ifndef __WINDOWS_PROCESS_UTILS_H +#define __WINDOWS_PROCESS_UTILS_H + +#include + +#include "../Common/MyString.h" + +#include "Defs.h" +#include "Handle.h" + +namespace NWindows { + +class CProcess: public CHandle +{ +public: + bool Open(DWORD desiredAccess, bool inheritHandle, DWORD processId) + { + _handle = ::OpenProcess(desiredAccess, inheritHandle, processId); + return (_handle != 0); + } + + #ifndef UNDER_CE + + bool GetExitCodeProcess(LPDWORD lpExitCode) { return BOOLToBool(::GetExitCodeProcess(_handle, lpExitCode)); } + bool Terminate(UINT exitCode) { return BOOLToBool(::TerminateProcess(_handle, exitCode)); } + #if (WINVER >= 0x0500) + DWORD GetGuiResources (DWORD uiFlags) { return ::GetGuiResources(_handle, uiFlags); } + #endif + bool SetPriorityClass(DWORD dwPriorityClass) { return BOOLToBool(::SetPriorityClass(_handle, dwPriorityClass)); } + DWORD GetPriorityClass() { return ::GetPriorityClass(_handle); } + // bool GetIoCounters(PIO_COUNTERS lpIoCounters ) { return BOOLToBool(::GetProcessIoCounters(_handle, lpIoCounters )); } + + bool GetTimes(LPFILETIME creationTime, LPFILETIME exitTime, LPFILETIME kernelTime, LPFILETIME userTime) + { return BOOLToBool(::GetProcessTimes(_handle, creationTime, exitTime, kernelTime, userTime)); } + + DWORD WaitForInputIdle(DWORD milliseconds) { return ::WaitForInputIdle(_handle, milliseconds); } + + // Debug + + bool ReadMemory(LPCVOID baseAddress, LPVOID buffer, SIZE_T size, SIZE_T* numberOfBytesRead) + { return BOOLToBool(::ReadProcessMemory(_handle, baseAddress, buffer, size, numberOfBytesRead)); } + + bool WriteMemory(LPVOID baseAddress, LPCVOID buffer, SIZE_T size, SIZE_T* numberOfBytesWritten) + { return BOOLToBool(::WriteProcessMemory(_handle, baseAddress, buffer, size, numberOfBytesWritten)); } + + bool FlushInstructionCache(LPCVOID baseAddress = 0, SIZE_T size = 0) + { return BOOLToBool(::FlushInstructionCache(_handle, baseAddress, size)); } + + LPVOID VirtualAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect) + { return VirtualAllocEx(_handle, address, size, allocationType, protect); } + + bool VirtualFree(LPVOID address, SIZE_T size, DWORD freeType) + { return BOOLToBool(::VirtualFreeEx(_handle, address, size, freeType)); } + + // Process Status API (PSAPI) + + bool EmptyWorkingSet() + { return BOOLToBool(::EmptyWorkingSet(_handle)); } + bool EnumModules(HMODULE *hModules, DWORD arraySizeInBytes, LPDWORD receivedBytes) + { return BOOLToBool(::EnumProcessModules(_handle, hModules, arraySizeInBytes, receivedBytes)); } + + DWORD MyGetModuleBaseName(HMODULE hModule, LPTSTR baseName, DWORD size) + { return ::GetModuleBaseName(_handle, hModule, baseName, size); } + bool MyGetModuleBaseName(HMODULE hModule, CSysString &name) + { + const unsigned len = MAX_PATH + 100; + 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; + 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 ¶ms, LPCWSTR curDir); + + DWORD Wait() { return ::WaitForSingleObject(_handle, INFINITE); } +}; + +WRes MyCreateProcess(LPCWSTR imageName, const UString ¶ms); + +} + +#endif diff --git a/CPP/Windows/PropVariant.cpp b/CPP/Windows/PropVariant.cpp index 6d9fb48ed..c4ad3acbf 100644 --- a/CPP/Windows/PropVariant.cpp +++ b/CPP/Windows/PropVariant.cpp @@ -1,347 +1,347 @@ -// 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(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_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(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; + } +} + +}} diff --git a/CPP/Windows/PropVariant.h b/CPP/Windows/PropVariant.h index f2eaba2fd..58e8a0c6c 100644 --- a/CPP/Windows/PropVariant.h +++ b/CPP/Windows/PropVariant.h @@ -1,114 +1,114 @@ -// 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 __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 diff --git a/CPP/Windows/PropVariantConv.cpp b/CPP/Windows/PropVariantConv.cpp index c5ac21260..65aa9f7e2 100644 --- a/CPP/Windows/PropVariantConv.cpp +++ b/CPP/Windows/PropVariantConv.cpp @@ -1,138 +1,138 @@ -// 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); - } -} +// 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); + } +} diff --git a/CPP/Windows/PropVariantConv.h b/CPP/Windows/PropVariantConv.h index 3e2456926..390e0b89c 100644 --- a/CPP/Windows/PropVariantConv.h +++ b/CPP/Windows/PropVariantConv.h @@ -1,37 +1,37 @@ -// 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 __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 diff --git a/CPP/Windows/PropVariantUtils.cpp b/CPP/Windows/PropVariantUtils.cpp index cb02fb032..fab556a50 100644 --- a/CPP/Windows/PropVariantUtils.cpp +++ b/CPP/Windows/PropVariantUtils.cpp @@ -1,161 +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); -} - - -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); -} +// 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); +} + + +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 index d8b3a5b74..3dd8295f0 100644 --- a/CPP/Windows/PropVariantUtils.h +++ b/CPP/Windows/PropVariantUtils.h @@ -1,34 +1,34 @@ -// Windows/PropVariantUtils.h - -#ifndef __PROP_VARIANT_UTILS_H -#define __PROP_VARIANT_UTILS_H - -#include "../Common/MyString.h" - -#include "PropVariant.h" - -struct CUInt32PCharPair -{ - UInt32 Value; - const char *Name; -}; - -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, ARRAY_SIZE(pairs), value, prop) -#define FLAGS_TO_PROP(pairs, value, prop) FlagsToProp(pairs, ARRAY_SIZE(pairs), value, prop) -#define TYPE_TO_PROP(table, value, prop) TypeToProp(table, 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, ARRAY_SIZE(pairs), value, prop) - -#endif +// Windows/PropVariantUtils.h + +#ifndef __PROP_VARIANT_UTILS_H +#define __PROP_VARIANT_UTILS_H + +#include "../Common/MyString.h" + +#include "PropVariant.h" + +struct CUInt32PCharPair +{ + UInt32 Value; + const char *Name; +}; + +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, ARRAY_SIZE(pairs), value, prop) +#define FLAGS_TO_PROP(pairs, value, prop) FlagsToProp(pairs, ARRAY_SIZE(pairs), value, prop) +#define TYPE_TO_PROP(table, value, prop) TypeToProp(table, 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, ARRAY_SIZE(pairs), value, prop) + +#endif diff --git a/CPP/Windows/Registry.cpp b/CPP/Windows/Registry.cpp index 014662140..a2893131a 100644 --- a/CPP/Windows/Registry.cpp +++ b/CPP/Windows/Registry.cpp @@ -1,390 +1,390 @@ -// Windows/Registry.cpp - -#include "StdAfx.h" - -#include - -#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 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 + +#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 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; +} + +}} diff --git a/CPP/Windows/Registry.h b/CPP/Windows/Registry.h index 0a312304b..ca79dfe3c 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 __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 diff --git a/CPP/Windows/ResourceString.cpp b/CPP/Windows/ResourceString.cpp index c28e60e07..cc8b964a2 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(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); +} + +} diff --git a/CPP/Windows/ResourceString.h b/CPP/Windows/ResourceString.h index cbaef4bfb..f0bdabf47 100644 --- a/CPP/Windows/ResourceString.h +++ b/CPP/Windows/ResourceString.h @@ -1,16 +1,16 @@ -// 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 __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 diff --git a/CPP/Windows/SecurityUtils.cpp b/CPP/Windows/SecurityUtils.cpp index 8646cc984..67a9d7fdc 100644 --- a/CPP/Windows/SecurityUtils.cpp +++ b/CPP/Windows/SecurityUtils.cpp @@ -1,181 +1,181 @@ -// 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 "../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; +} + +}} diff --git a/CPP/Windows/SecurityUtils.h b/CPP/Windows/SecurityUtils.h index 16b6606e6..8966dfd3b 100644 --- a/CPP/Windows/SecurityUtils.h +++ b/CPP/Windows/SecurityUtils.h @@ -1,167 +1,167 @@ -// Windows/SecurityUtils.h - -#ifndef __WINDOWS_SECURITY_UTILS_H -#define __WINDOWS_SECURITY_UTILS_H - -#include - -#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 __WINDOWS_SECURITY_UTILS_H +#define __WINDOWS_SECURITY_UTILS_H + +#include + +#include "Defs.h" + +namespace NWindows { +namespace NSecurity { + +class CAccessToken +{ + HANDLE _handle; +public: + CAccessToken(): _handle(NULL) {}; + ~CAccessToken() { Close(); } + bool Close() + { + if (_handle == NULL) + return true; + bool res = BOOLToBool(::CloseHandle(_handle)); + if (res) + _handle = NULL; + return res; + } + + bool OpenProcessToken(HANDLE processHandle, DWORD desiredAccess) + { + Close(); + return BOOLToBool(::OpenProcessToken(processHandle, desiredAccess, &_handle)); + } + + /* + bool OpenThreadToken(HANDLE threadHandle, DWORD desiredAccess, bool openAsSelf) + { + Close(); + return BOOLToBool(::OpenTreadToken(threadHandle, desiredAccess, BoolToBOOL(anOpenAsSelf), &_handle)); + } + */ + + bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState, + DWORD bufferLength, PTOKEN_PRIVILEGES previousState, PDWORD returnLength) + { return BOOLToBool(::AdjustTokenPrivileges(_handle, BoolToBOOL(disableAllPrivileges), + newState, bufferLength, previousState, returnLength)); } + + bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState) + { return AdjustPrivileges(disableAllPrivileges, newState, 0, NULL, NULL); } + + bool AdjustPrivileges(PTOKEN_PRIVILEGES newState) + { return AdjustPrivileges(false, newState); } + +}; + +#ifndef _UNICODE +typedef NTSTATUS (NTAPI *LsaOpenPolicyP)(PLSA_UNICODE_STRING SystemName, + PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle); +typedef NTSTATUS (NTAPI *LsaCloseP)(LSA_HANDLE ObjectHandle); +typedef NTSTATUS (NTAPI *LsaAddAccountRightsP)(LSA_HANDLE PolicyHandle, + PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights ); +#define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L) +#endif + +struct CPolicy +{ +protected: + LSA_HANDLE _handle; + #ifndef _UNICODE + HMODULE hModule; + #endif +public: + operator LSA_HANDLE() const { return _handle; } + CPolicy(): _handle(NULL) + { + #ifndef _UNICODE + hModule = GetModuleHandle(TEXT("Advapi32.dll")); + #endif + }; + ~CPolicy() { Close(); } + + NTSTATUS Open(PLSA_UNICODE_STRING systemName, PLSA_OBJECT_ATTRIBUTES objectAttributes, + ACCESS_MASK desiredAccess) + { + #ifndef _UNICODE + if (hModule == NULL) + return MY_STATUS_NOT_IMPLEMENTED; + LsaOpenPolicyP lsaOpenPolicy = (LsaOpenPolicyP)GetProcAddress(hModule, "LsaOpenPolicy"); + if (lsaOpenPolicy == NULL) + return MY_STATUS_NOT_IMPLEMENTED; + #endif + + Close(); + return + #ifdef _UNICODE + ::LsaOpenPolicy + #else + lsaOpenPolicy + #endif + (systemName, objectAttributes, desiredAccess, &_handle); + } + + NTSTATUS Close() + { + if (_handle == NULL) + return 0; + + #ifndef _UNICODE + if (hModule == NULL) + return MY_STATUS_NOT_IMPLEMENTED; + LsaCloseP lsaClose = (LsaCloseP)GetProcAddress(hModule, "LsaClose"); + if (lsaClose == NULL) + return MY_STATUS_NOT_IMPLEMENTED; + #endif + + NTSTATUS res = + #ifdef _UNICODE + ::LsaClose + #else + lsaClose + #endif + (_handle); + _handle = NULL; + return res; + } + + NTSTATUS EnumerateAccountsWithUserRight(PLSA_UNICODE_STRING userRights, + PLSA_ENUMERATION_INFORMATION *enumerationBuffer, PULONG countReturned) + { return LsaEnumerateAccountsWithUserRight(_handle, userRights, (void **)enumerationBuffer, countReturned); } + + NTSTATUS EnumerateAccountRights(PSID sid, PLSA_UNICODE_STRING* userRights, PULONG countOfRights) + { return ::LsaEnumerateAccountRights(_handle, sid, userRights, countOfRights); } + + NTSTATUS LookupSids(ULONG count, PSID* sids, + PLSA_REFERENCED_DOMAIN_LIST* referencedDomains, PLSA_TRANSLATED_NAME* names) + { return LsaLookupSids(_handle, count, sids, referencedDomains, names); } + + NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights, ULONG countOfRights) + { + #ifndef _UNICODE + if (hModule == NULL) + return MY_STATUS_NOT_IMPLEMENTED; + LsaAddAccountRightsP lsaAddAccountRights = (LsaAddAccountRightsP)GetProcAddress(hModule, "LsaAddAccountRights"); + if (lsaAddAccountRights == NULL) + return MY_STATUS_NOT_IMPLEMENTED; + #endif + + return + #ifdef _UNICODE + ::LsaAddAccountRights + #else + lsaAddAccountRights + #endif + (_handle, accountSid, userRights, countOfRights); + } + NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights) + { return AddAccountRights(accountSid, userRights, 1); } + + NTSTATUS RemoveAccountRights(PSID accountSid, bool allRights, PLSA_UNICODE_STRING userRights, ULONG countOfRights) + { return LsaRemoveAccountRights(_handle, accountSid, (BOOLEAN)(allRights ? TRUE : FALSE), userRights, countOfRights); } +}; + +bool AddLockMemoryPrivilege(); + +}} + +#endif diff --git a/CPP/Windows/Shell.cpp b/CPP/Windows/Shell.cpp index 7ba82d425..b424e67ca 100644 --- a/CPP/Windows/Shell.cpp +++ b/CPP/Windows/Shell.cpp @@ -1,358 +1,358 @@ -// Windows/Shell.cpp - -#include "StdAfx.h" - -/* -#include -#include -*/ - -#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 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 +#include +*/ + +#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 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 + +}} diff --git a/CPP/Windows/Shell.h b/CPP/Windows/Shell.h index 906804098..4bff18cf9 100644 --- a/CPP/Windows/Shell.h +++ b/CPP/Windows/Shell.h @@ -1,94 +1,94 @@ -// Windows/Shell.h - -#ifndef __WINDOWS_SHELL_H -#define __WINDOWS_SHELL_H - -#include -#include - -#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 __WINDOWS_SHELL_H +#define __WINDOWS_SHELL_H + +#include +#include + +#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 diff --git a/CPP/Windows/StdAfx.h b/CPP/Windows/StdAfx.h index 47a489527..1766dfa86 100644 --- a/CPP/Windows/StdAfx.h +++ b/CPP/Windows/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef __STDAFX_H -#define __STDAFX_H - -#include "../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../Common/Common.h" + +#endif diff --git a/CPP/Windows/Synchronization.cpp b/CPP/Windows/Synchronization.cpp index 01f1ad90f..5f86d1eb1 100644 --- a/CPP/Windows/Synchronization.cpp +++ b/CPP/Windows/Synchronization.cpp @@ -1,10 +1,10 @@ -// Windows/Synchronization.cpp - -#include "StdAfx.h" - -#include "Synchronization.h" - -namespace NWindows { -namespace NSynchronization { - -}} +// Windows/Synchronization.cpp + +#include "StdAfx.h" + +#include "Synchronization.h" + +namespace NWindows { +namespace NSynchronization { + +}} diff --git a/CPP/Windows/Synchronization.h b/CPP/Windows/Synchronization.h index 786da00c6..dc695f6f3 100644 --- a/CPP/Windows/Synchronization.h +++ b/CPP/Windows/Synchronization.h @@ -1,164 +1,164 @@ -// Windows/Synchronization.h - -#ifndef __WINDOWS_SYNCHRONIZATION_H -#define __WINDOWS_SYNCHRONIZATION_H - -#include "../../C/Threads.h" - -#include "Defs.h" - -#ifdef _WIN32 -#include "Handle.h" -#endif - -namespace NWindows { -namespace NSynchronization { - -class CBaseEvent -{ -protected: - ::CEvent _object; -public: - bool IsCreated() { return Event_IsCreated(&_object) != 0; } - operator HANDLE() { return _object; } - CBaseEvent() { Event_Construct(&_object); } - ~CBaseEvent() { Close(); } - WRes Close() { return Event_Close(&_object); } - #ifdef _WIN32 - WRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL) - { - _object = ::CreateEvent(sa, BoolToBOOL(manualReset), BoolToBOOL(initiallyOwn), name); - if (name == NULL && _object != 0) - return 0; - return ::GetLastError(); - } - WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) - { - _object = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name); - if (_object != 0) - return 0; - return ::GetLastError(); - } - #endif - - WRes Set() { return Event_Set(&_object); } - // bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); } - WRes Reset() { return Event_Reset(&_object); } - WRes Lock() { return Event_Wait(&_object); } -}; - -class CManualResetEvent: public CBaseEvent -{ -public: - WRes Create(bool initiallyOwn = false) - { - return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0); - } - WRes CreateIfNotCreated() - { - if (IsCreated()) - return 0; - return ManualResetEvent_CreateNotSignaled(&_object); - } - #ifdef _WIN32 - WRes CreateWithName(bool initiallyOwn, LPCTSTR name) - { - return CBaseEvent::Create(true, initiallyOwn, name); - } - #endif -}; - -class CAutoResetEvent: public CBaseEvent -{ -public: - WRes Create() - { - return AutoResetEvent_CreateNotSignaled(&_object); - } - WRes CreateIfNotCreated() - { - if (IsCreated()) - return 0; - return AutoResetEvent_CreateNotSignaled(&_object); - } -}; - -#ifdef _WIN32 -class CObject: public CHandle -{ -public: - WRes Lock(DWORD timeoutInterval = INFINITE) - { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); } -}; -class CMutex: public CObject -{ -public: - WRes Create(bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL) - { - _handle = ::CreateMutex(sa, BoolToBOOL(initiallyOwn), name); - if (name == NULL && _handle != 0) - return 0; - return ::GetLastError(); - } - #ifndef UNDER_CE - WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) - { - _handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name); - if (_handle != 0) - return 0; - return ::GetLastError(); - } - #endif - WRes Release() - { - return ::ReleaseMutex(_handle) ? 0 : ::GetLastError(); - } -}; -class CMutexLock -{ - CMutex *_object; -public: - CMutexLock(CMutex &object): _object(&object) { _object->Lock(); } - ~CMutexLock() { _object->Release(); } -}; -#endif - -class CSemaphore -{ - ::CSemaphore _object; -public: - CSemaphore() { Semaphore_Construct(&_object); } - ~CSemaphore() { Close(); } - WRes Close() { return Semaphore_Close(&_object); } - operator HANDLE() { return _object; } - WRes Create(UInt32 initiallyCount, UInt32 maxCount) - { - return Semaphore_Create(&_object, initiallyCount, maxCount); - } - WRes Release() { return Semaphore_Release1(&_object); } - WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); } - WRes Lock() { return Semaphore_Wait(&_object); } -}; - -class CCriticalSection -{ - ::CCriticalSection _object; -public: - CCriticalSection() { CriticalSection_Init(&_object); } - ~CCriticalSection() { CriticalSection_Delete(&_object); } - void Enter() { CriticalSection_Enter(&_object); } - void Leave() { CriticalSection_Leave(&_object); } -}; - -class CCriticalSectionLock -{ - CCriticalSection *_object; - void Unlock() { _object->Leave(); } -public: - CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); } - ~CCriticalSectionLock() { Unlock(); } -}; - -}} - -#endif +// Windows/Synchronization.h + +#ifndef __WINDOWS_SYNCHRONIZATION_H +#define __WINDOWS_SYNCHRONIZATION_H + +#include "../../C/Threads.h" + +#include "Defs.h" + +#ifdef _WIN32 +#include "Handle.h" +#endif + +namespace NWindows { +namespace NSynchronization { + +class CBaseEvent +{ +protected: + ::CEvent _object; +public: + bool IsCreated() { return Event_IsCreated(&_object) != 0; } + operator HANDLE() { return _object; } + CBaseEvent() { Event_Construct(&_object); } + ~CBaseEvent() { Close(); } + WRes Close() { return Event_Close(&_object); } + #ifdef _WIN32 + WRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL) + { + _object = ::CreateEvent(sa, BoolToBOOL(manualReset), BoolToBOOL(initiallyOwn), name); + if (name == NULL && _object != 0) + return 0; + return ::GetLastError(); + } + WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) + { + _object = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name); + if (_object != 0) + return 0; + return ::GetLastError(); + } + #endif + + WRes Set() { return Event_Set(&_object); } + // bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); } + WRes Reset() { return Event_Reset(&_object); } + WRes Lock() { return Event_Wait(&_object); } +}; + +class CManualResetEvent: public CBaseEvent +{ +public: + WRes Create(bool initiallyOwn = false) + { + return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0); + } + WRes CreateIfNotCreated() + { + if (IsCreated()) + return 0; + return ManualResetEvent_CreateNotSignaled(&_object); + } + #ifdef _WIN32 + WRes CreateWithName(bool initiallyOwn, LPCTSTR name) + { + return CBaseEvent::Create(true, initiallyOwn, name); + } + #endif +}; + +class CAutoResetEvent: public CBaseEvent +{ +public: + WRes Create() + { + return AutoResetEvent_CreateNotSignaled(&_object); + } + WRes CreateIfNotCreated() + { + if (IsCreated()) + return 0; + return AutoResetEvent_CreateNotSignaled(&_object); + } +}; + +#ifdef _WIN32 +class CObject: public CHandle +{ +public: + WRes Lock(DWORD timeoutInterval = INFINITE) + { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); } +}; +class CMutex: public CObject +{ +public: + WRes Create(bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL) + { + _handle = ::CreateMutex(sa, BoolToBOOL(initiallyOwn), name); + if (name == NULL && _handle != 0) + return 0; + return ::GetLastError(); + } + #ifndef UNDER_CE + WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) + { + _handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name); + if (_handle != 0) + return 0; + return ::GetLastError(); + } + #endif + WRes Release() + { + return ::ReleaseMutex(_handle) ? 0 : ::GetLastError(); + } +}; +class CMutexLock +{ + CMutex *_object; +public: + CMutexLock(CMutex &object): _object(&object) { _object->Lock(); } + ~CMutexLock() { _object->Release(); } +}; +#endif + +class CSemaphore +{ + ::CSemaphore _object; +public: + CSemaphore() { Semaphore_Construct(&_object); } + ~CSemaphore() { Close(); } + WRes Close() { return Semaphore_Close(&_object); } + operator HANDLE() { return _object; } + WRes Create(UInt32 initiallyCount, UInt32 maxCount) + { + return Semaphore_Create(&_object, initiallyCount, maxCount); + } + WRes Release() { return Semaphore_Release1(&_object); } + WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); } + WRes Lock() { return Semaphore_Wait(&_object); } +}; + +class CCriticalSection +{ + ::CCriticalSection _object; +public: + CCriticalSection() { CriticalSection_Init(&_object); } + ~CCriticalSection() { CriticalSection_Delete(&_object); } + void Enter() { CriticalSection_Enter(&_object); } + void Leave() { CriticalSection_Leave(&_object); } +}; + +class CCriticalSectionLock +{ + CCriticalSection *_object; + void Unlock() { _object->Leave(); } +public: + CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); } + ~CCriticalSectionLock() { Unlock(); } +}; + +}} + +#endif diff --git a/CPP/Windows/System.cpp b/CPP/Windows/System.cpp index c6f827588..cc33169a7 100644 --- a/CPP/Windows/System.cpp +++ b/CPP/Windows/System.cpp @@ -1,142 +1,142 @@ -// 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" + +#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 +} + +}} diff --git a/CPP/Windows/System.h b/CPP/Windows/System.h index bc28f4780..519e0444a 100644 --- a/CPP/Windows/System.h +++ b/CPP/Windows/System.h @@ -1,40 +1,40 @@ -// 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 __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 diff --git a/CPP/Windows/Thread.h b/CPP/Windows/Thread.h index 1b5863ce4..16a509d47 100644 --- a/CPP/Windows/Thread.h +++ b/CPP/Windows/Thread.h @@ -1,38 +1,38 @@ -// Windows/Thread.h - -#ifndef __WINDOWS_THREAD_H -#define __WINDOWS_THREAD_H - -#include "../../C/Threads.h" - -#include "Defs.h" - -namespace NWindows { - -class CThread -{ - ::CThread thread; -public: - CThread() { Thread_Construct(&thread); } - ~CThread() { Close(); } - bool IsCreated() { return Thread_WasCreated(&thread) != 0; } - WRes Close() { return Thread_Close(&thread); } - WRes Create(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter) - { return Thread_Create(&thread, startAddress, parameter); } - WRes Wait() { return Thread_Wait(&thread); } - - #ifdef _WIN32 - operator HANDLE() { return thread; } - void Attach(HANDLE handle) { thread = handle; } - HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; } - DWORD Resume() { return ::ResumeThread(thread); } - DWORD Suspend() { return ::SuspendThread(thread); } - bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); } - int GetPriority() { return ::GetThreadPriority(thread); } - bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); } - #endif -}; - -} - -#endif +// Windows/Thread.h + +#ifndef __WINDOWS_THREAD_H +#define __WINDOWS_THREAD_H + +#include "../../C/Threads.h" + +#include "Defs.h" + +namespace NWindows { + +class CThread +{ + ::CThread thread; +public: + CThread() { Thread_Construct(&thread); } + ~CThread() { Close(); } + bool IsCreated() { return Thread_WasCreated(&thread) != 0; } + WRes Close() { return Thread_Close(&thread); } + WRes Create(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter) + { return Thread_Create(&thread, startAddress, parameter); } + WRes Wait() { return Thread_Wait(&thread); } + + #ifdef _WIN32 + operator HANDLE() { return thread; } + void Attach(HANDLE handle) { thread = handle; } + HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; } + DWORD Resume() { return ::ResumeThread(thread); } + DWORD Suspend() { return ::SuspendThread(thread); } + bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); } + int GetPriority() { return ::GetThreadPriority(thread); } + bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); } + #endif +}; + +} + +#endif diff --git a/CPP/Windows/TimeUtils.cpp b/CPP/Windows/TimeUtils.cpp index 3fc02bc86..d288f1216 100644 --- a/CPP/Windows/TimeUtils.cpp +++ b/CPP/Windows/TimeUtils.cpp @@ -1,213 +1,213 @@ -// 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" + +#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 +} + +}} diff --git a/CPP/Windows/TimeUtils.h b/CPP/Windows/TimeUtils.h index b0092f870..d1d8c150b 100644 --- a/CPP/Windows/TimeUtils.h +++ b/CPP/Windows/TimeUtils.h @@ -1,32 +1,32 @@ -// 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 __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 diff --git a/CPP/Windows/Window.cpp b/CPP/Windows/Window.cpp index 0c7422240..365850223 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) +{ + 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; +} +*/ + +} diff --git a/CPP/Windows/Window.h b/CPP/Windows/Window.h index 4c80a5b4f..3bda6795d 100644 --- a/CPP/Windows/Window.h +++ b/CPP/Windows/Window.h @@ -1,284 +1,284 @@ -// 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 __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 diff --git a/CPP/appveyor.cmd b/CPP/appveyor.cmd index 97e234f5e..bcb4eee04 100644 --- a/CPP/appveyor.cmd +++ b/CPP/appveyor.cmd @@ -1,44 +1,44 @@ -@echo off - -REM Microsoft Windows SDK 7.1 (VC=sdk71) -> can compile for IA64, but who needs that? -REM Microsoft Visual Studio 2010 (VC=10.0) -> for win2k, but who needs that? -REM Microsoft Visual Studio 2012 (VC=11.0) -REM Microsoft Visual Studio 2013 (VC=12.0) -REM Microsoft Visual Studio 2015 (VC=14.0) -REM Microsoft Visual Studio 2017 (VC=15.0) -REM Microsoft Visual Studio 2019 (VC=16.0) - -REM to many vcvarsall.cmd calls will blow it up! -set OPATH=%PATH% -set ERRFILE=%APPVEYOR_BUILD_FOLDER%\error.txt -cd %APPVEYOR_BUILD_FOLDER%\CPP - -goto build_vs2019 - -:build_vs2019 -set VC=16.0 -set PATH=%OPATH% -set SUBSYS="5.01" -call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 -call build-it.cmd - -set PATH=%OPATH% -set SUBSYS="5.02" -call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 -call build-it.cmd - -set PATH=%OPATH% -set SUBSYS="6.02" -call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64_arm -call build-it.cmd - -set PATH=%OPATH% -set SUBSYS="6.02" -call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64_arm64 -call build-it.cmd - -goto end - -:end -cd %APPVEYOR_BUILD_FOLDER% -7z a %APPVEYOR_PROJECT_NAME%-%APPVEYOR_BUILD_VERSION%.7z bin-* *.txt +@echo off + +REM Microsoft Windows SDK 7.1 (VC=sdk71) -> can compile for IA64, but who needs that? +REM Microsoft Visual Studio 2010 (VC=10.0) -> for win2k, but who needs that? +REM Microsoft Visual Studio 2012 (VC=11.0) +REM Microsoft Visual Studio 2013 (VC=12.0) +REM Microsoft Visual Studio 2015 (VC=14.0) +REM Microsoft Visual Studio 2017 (VC=15.0) +REM Microsoft Visual Studio 2019 (VC=16.0) + +REM to many vcvarsall.cmd calls will blow it up! +set OPATH=%PATH% +set ERRFILE=%APPVEYOR_BUILD_FOLDER%\error.txt +cd %APPVEYOR_BUILD_FOLDER%\CPP + +goto build_vs2019 + +:build_vs2019 +set VC=16.0 +set PATH=%OPATH% +set SUBSYS="5.01" +call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 +call build-it.cmd + +set PATH=%OPATH% +set SUBSYS="5.02" +call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 +call build-it.cmd + +set PATH=%OPATH% +set SUBSYS="6.02" +call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64_arm +call build-it.cmd + +set PATH=%OPATH% +set SUBSYS="6.02" +call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64_arm64 +call build-it.cmd + +goto end + +:end +cd %APPVEYOR_BUILD_FOLDER% +7z a %APPVEYOR_PROJECT_NAME%-%APPVEYOR_BUILD_VERSION%.7z bin-* *.txt diff --git a/CPP/build-it.cmd b/CPP/build-it.cmd index 660c4a5f2..be82ef13d 100644 --- a/CPP/build-it.cmd +++ b/CPP/build-it.cmd @@ -1,103 +1,103 @@ -@echo off - -set ROOT=%cd%\7zip -set OUTDIR=%APPVEYOR_BUILD_FOLDER%\bin-%VC%-%PLATFORM% -set ERRFILE=%APPVEYOR_BUILD_FOLDER%\bin-%VC%-%PLATFORM%.log -set LFLAGS=/SUBSYSTEM:WINDOWS,%SUBSYS% -set > %APPVEYOR_BUILD_FOLDER%\env-%VC%-%PLATFORM%.txt -mkdir %OUTDIR% - -cd %ROOT%\Bundles\Format7zExtract -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ 7zxa.dll" >> %ERRFILE% -copy %PLATFORM%\7zxa.dll %OUTDIR%\7zxa.dll - -cd %ROOT%\Bundles\Format7z -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ 7za.dll" >> %ERRFILE% -copy %PLATFORM%\7za.dll %OUTDIR%\7za.dll - -cd %ROOT%\Bundles\Format7zF -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ 7z.dll" >> %ERRFILE% -copy %PLATFORM%\7z.dll %OUTDIR%\7z.dll - -cd %ROOT%\UI\FileManager -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ 7zFM.exe" >> %ERRFILE% -copy %PLATFORM%\7zFM.exe %OUTDIR%\7zFM.exe - -cd %ROOT%\UI\GUI -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ 7zG.exe" >> %ERRFILE% -copy %PLATFORM%\7zG.exe %OUTDIR%\7zG.exe - -cd %ROOT%\UI\Explorer -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ 7-zip.dll" >> %ERRFILE% -copy %PLATFORM%\7-zip.dll %OUTDIR%\7-zip.dll - -cd %ROOT%\Bundles\SFXWin -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ 7z.sfx" >> %ERRFILE% -copy %PLATFORM%\7z.sfx %OUTDIR%\7z.sfx - -cd %ROOT%\Bundles\Codec_brotli -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ brotli.dll" >> %ERRFILE% -copy %PLATFORM%\brotli.dll %OUTDIR%\brotli.dll - -cd %ROOT%\Bundles\Codec_lizard -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ lizard.dll" >> %ERRFILE% -copy %PLATFORM%\lizard.dll %OUTDIR%\lizard.dll - -cd %ROOT%\Bundles\Codec_lz4 -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ lz4.dll" >> %ERRFILE% -copy %PLATFORM%\lz4.dll %OUTDIR%\lz4.dll - -cd %ROOT%\Bundles\Codec_lz5 -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ lz5.dll" >> %ERRFILE% -copy %PLATFORM%\lz5.dll %OUTDIR%\lz5.dll - -cd %ROOT%\Bundles\Codec_zstd -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ zstd.dll" >> %ERRFILE% -copy %PLATFORM%\zstd.dll %OUTDIR%\zstd.dll - -cd %ROOT%\Bundles\Codec_flzma2 -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ flzma2.dll" >> %ERRFILE% -copy %PLATFORM%\flzma2.dll %OUTDIR%\flzma2.dll - -cd %ROOT%\..\..\C\Util\7zipInstall -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ Install.exe" >> %ERRFILE% -copy %PLATFORM%\7zipInstall.exe %OUTDIR%\Install.exe - -cd %ROOT%\..\..\C\Util\7zipUninstall -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ Uninstall.exe" >> %ERRFILE% -copy %PLATFORM%\7zipUninstall.exe %OUTDIR%\Uninstall.exe - -set LFLAGS=/SUBSYSTEM:CONSOLE,%SUBSYS% -cd %ROOT%\UI\Console -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ 7z.exe" >> %ERRFILE% -copy %PLATFORM%\7z.exe %OUTDIR%\7z.exe - -cd %ROOT%\Bundles\SFXCon -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ 7zCon.sfx" >> %ERRFILE% -copy %PLATFORM%\7zCon.sfx %OUTDIR%\7zCon.sfx - -cd %ROOT%\Bundles\Alone -nmake %OPTS% -IF %errorlevel% NEQ 0 echo "Error @ 7za.exe" >> %ERRFILE% -copy %PLATFORM%\7za.exe %OUTDIR%\7za.exe - -:ende -cd %ROOT%\.. - +@echo off + +set ROOT=%cd%\7zip +set OUTDIR=%APPVEYOR_BUILD_FOLDER%\bin-%VC%-%PLATFORM% +set ERRFILE=%APPVEYOR_BUILD_FOLDER%\bin-%VC%-%PLATFORM%.log +set LFLAGS=/SUBSYSTEM:WINDOWS,%SUBSYS% +set > %APPVEYOR_BUILD_FOLDER%\env-%VC%-%PLATFORM%.txt +mkdir %OUTDIR% + +cd %ROOT%\Bundles\Format7zExtract +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ 7zxa.dll" >> %ERRFILE% +copy %PLATFORM%\7zxa.dll %OUTDIR%\7zxa.dll + +cd %ROOT%\Bundles\Format7z +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ 7za.dll" >> %ERRFILE% +copy %PLATFORM%\7za.dll %OUTDIR%\7za.dll + +cd %ROOT%\Bundles\Format7zF +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ 7z.dll" >> %ERRFILE% +copy %PLATFORM%\7z.dll %OUTDIR%\7z.dll + +cd %ROOT%\UI\FileManager +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ 7zFM.exe" >> %ERRFILE% +copy %PLATFORM%\7zFM.exe %OUTDIR%\7zFM.exe + +cd %ROOT%\UI\GUI +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ 7zG.exe" >> %ERRFILE% +copy %PLATFORM%\7zG.exe %OUTDIR%\7zG.exe + +cd %ROOT%\UI\Explorer +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ 7-zip.dll" >> %ERRFILE% +copy %PLATFORM%\7-zip.dll %OUTDIR%\7-zip.dll + +cd %ROOT%\Bundles\SFXWin +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ 7z.sfx" >> %ERRFILE% +copy %PLATFORM%\7z.sfx %OUTDIR%\7z.sfx + +cd %ROOT%\Bundles\Codec_brotli +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ brotli.dll" >> %ERRFILE% +copy %PLATFORM%\brotli.dll %OUTDIR%\brotli.dll + +cd %ROOT%\Bundles\Codec_lizard +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ lizard.dll" >> %ERRFILE% +copy %PLATFORM%\lizard.dll %OUTDIR%\lizard.dll + +cd %ROOT%\Bundles\Codec_lz4 +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ lz4.dll" >> %ERRFILE% +copy %PLATFORM%\lz4.dll %OUTDIR%\lz4.dll + +cd %ROOT%\Bundles\Codec_lz5 +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ lz5.dll" >> %ERRFILE% +copy %PLATFORM%\lz5.dll %OUTDIR%\lz5.dll + +cd %ROOT%\Bundles\Codec_zstd +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ zstd.dll" >> %ERRFILE% +copy %PLATFORM%\zstd.dll %OUTDIR%\zstd.dll + +cd %ROOT%\Bundles\Codec_flzma2 +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ flzma2.dll" >> %ERRFILE% +copy %PLATFORM%\flzma2.dll %OUTDIR%\flzma2.dll + +cd %ROOT%\..\..\C\Util\7zipInstall +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ Install.exe" >> %ERRFILE% +copy %PLATFORM%\7zipInstall.exe %OUTDIR%\Install.exe + +cd %ROOT%\..\..\C\Util\7zipUninstall +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ Uninstall.exe" >> %ERRFILE% +copy %PLATFORM%\7zipUninstall.exe %OUTDIR%\Uninstall.exe + +set LFLAGS=/SUBSYSTEM:CONSOLE,%SUBSYS% +cd %ROOT%\UI\Console +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ 7z.exe" >> %ERRFILE% +copy %PLATFORM%\7z.exe %OUTDIR%\7z.exe + +cd %ROOT%\Bundles\SFXCon +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ 7zCon.sfx" >> %ERRFILE% +copy %PLATFORM%\7zCon.sfx %OUTDIR%\7zCon.sfx + +cd %ROOT%\Bundles\Alone +nmake %OPTS% +IF %errorlevel% NEQ 0 echo "Error @ 7za.exe" >> %ERRFILE% +copy %PLATFORM%\7za.exe %OUTDIR%\7za.exe + +:ende +cd %ROOT%\.. + diff --git a/DOC/7zC.txt b/DOC/7zC.txt index 49276787f..939b720f9 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 - -: - 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 + +: + 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 9239e9355..74cdfa418 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 index 2102faf83..8b865bddb 100644 --- a/DOC/7zip.hhp +++ b/DOC/7zip.hhp @@ -1,82 +1,82 @@ -[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\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] - +[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\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.inf b/DOC/7zip.inf index ce07d9318..b4e18e839 100644 --- a/DOC/7zip.inf +++ b/DOC/7zip.inf @@ -1,55 +1,55 @@ -[CODE] - -[Version] -Signature = "$Windows NT$" -Provider = "7-zip.org" -CESignature = "$Windows CE$" - -[CEStrings] -AppName = "7-Zip" -InstallDir = %CE1%\%AppName% - -[Strings] -AppVer = "19.00" -AppDate = "2019-01-21" - -[CEDevice] -; ProcessorType = 2577 ; ARM -VersionMin = 3.0 -BuildMin = 0.0 -VersionMax = 1000.0 -BuildMax = 0xE0000000 - -[DefaultInstall] -CopyFiles = CopyFilesSection,CopyFilesSection.Lang -AddReg = RegSettings -CEShortcuts = Shortcuts - -[SourceDisksNames] -1 = ,"Common files",,"." -2 = ,"Lang files",,"Lang" - -[SourceDisksFiles] -7zFM.exe = 1 -7z.sfx = 1 -7zS2.sfx = 1 -ru.txt = 2 - -[DestinationDirs] -DefaultDestDir = ,%InstallDir% -CopyFilesSection = ,%InstallDir% -CopyFilesSection.Lang = ,"%InstallDir%\Lang" -Shortcuts = ,%CE11% - -[CopyFilesSection] -7zFM.exe -7z.sfx -7zS2.sfx - -[CopyFilesSection.Lang] -ru.txt - -[RegSettings] - -[Shortcuts] -7-Zip,0,7zFM.exe +[CODE] + +[Version] +Signature = "$Windows NT$" +Provider = "7-zip.org" +CESignature = "$Windows CE$" + +[CEStrings] +AppName = "7-Zip" +InstallDir = %CE1%\%AppName% + +[Strings] +AppVer = "19.00" +AppDate = "2019-01-21" + +[CEDevice] +; ProcessorType = 2577 ; ARM +VersionMin = 3.0 +BuildMin = 0.0 +VersionMax = 1000.0 +BuildMax = 0xE0000000 + +[DefaultInstall] +CopyFiles = CopyFilesSection,CopyFilesSection.Lang +AddReg = RegSettings +CEShortcuts = Shortcuts + +[SourceDisksNames] +1 = ,"Common files",,"." +2 = ,"Lang files",,"Lang" + +[SourceDisksFiles] +7zFM.exe = 1 +7z.sfx = 1 +7zS2.sfx = 1 +ru.txt = 2 + +[DestinationDirs] +DefaultDestDir = ,%InstallDir% +CopyFilesSection = ,%InstallDir% +CopyFilesSection.Lang = ,"%InstallDir%\Lang" +Shortcuts = ,%CE11% + +[CopyFilesSection] +7zFM.exe +7z.sfx +7zS2.sfx + +[CopyFilesSection.Lang] +ru.txt + +[RegSettings] + +[Shortcuts] +7-Zip,0,7zFM.exe diff --git a/DOC/7zip.nsi b/DOC/7zip.nsi index fef7403d9..118203c37 100644 --- a/DOC/7zip.nsi +++ b/DOC/7zip.nsi @@ -1,559 +1,559 @@ -;-------------------------------- -;Defines - -!define VERSION_MAJOR 19 -!define VERSION_MINOR 00 -!define VERSION_POSTFIX_FULL " ZS" -!ifdef WIN64 -!ifdef IA64 -!define VERSION_SYS_POSTFIX_FULL " for Windows IA-64" -!else -!define VERSION_SYS_POSTFIX_FULL " for Windows x64" -!endif -!else -!define VERSION_SYS_POSTFIX_FULL "" -!endif -!define NAME_FULL "7-Zip ${VERSION_MAJOR}.${VERSION_MINOR}${VERSION_POSTFIX_FULL}${VERSION_SYS_POSTFIX_FULL}" -!define VERSION_POSTFIX "" -!ifdef WIN64 -!ifdef IA64 -!define VERSION_SYS_POSTFIX "-ia64" -!else -!define VERSION_SYS_POSTFIX "-x64" -!endif -!else -!define VERSION_SYS_POSTFIX "" -!endif - - - -!define FM_LINK "7-Zip File Manager.lnk" -!define HELP_LINK "7-Zip Help.lnk" - -!define CLSID_CONTEXT_MENU {23170F69-40C1-278A-1000-000100020000} - -#!define NO_COMPRESSION - - !include "Library.nsh" - !include "MUI.nsh" - -;-------------------------------- -;Configuration - - ;General - Name "${NAME_FULL}" - BrandingText "www.7-zip.org" - OutFile "..\7z${VERSION_MAJOR}${VERSION_MINOR}${VERSION_POSTFIX}${VERSION_SYS_POSTFIX}.exe" - - ;Folder selection page - InstallDir "$PROGRAMFILES\7-Zip" - - ;Get install folder from registry if available - InstallDirRegKey HKCU "Software\7-Zip" "Path32" - - ;Compressor -!ifndef NO_COMPRESSION - SetCompressor /solid lzma - ; SetCompressorFilter 1 -!ifdef IA64 - SetCompressorDictSize 8 -!else - SetCompressorDictSize 4 -!endif -!else - SetCompress off -!endif - - -;-------------------------------- -;Variables - -;-------------------------------- -;Interface Settings - - !define MUI_ABORTWARNING - -;-------------------------------- -;Pages - - #!insertmacro MUI_PAGE_LICENSE "License.txt" - !insertmacro MUI_PAGE_DIRECTORY - !insertmacro MUI_PAGE_INSTFILES - !insertmacro MUI_PAGE_FINISH - - !insertmacro MUI_UNPAGE_CONFIRM - !insertmacro MUI_UNPAGE_INSTFILES - !insertmacro MUI_UNPAGE_FINISH - -;-------------------------------- -;Languages - - !insertmacro MUI_LANGUAGE "English" - -;-------------------------------- -;Reserve Files - - ;These files should be inserted before other files in the data block - ;Keep these lines before any File command - ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA) - - !insertmacro MUI_RESERVEFILE_LANGDLL - -;-------------------------------- -;Installer Sections - -Section - !ifndef WIN64 - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\App Paths\7zFMn.exe" - !endif - - # delete old unwanted files - - Delete $INSTDIR\7zFMn.exe - Delete $INSTDIR\7zgn.exe - Delete $INSTDIR\7zn.exe - Delete $INSTDIR\7zan.exe - Delete $INSTDIR\7zC.sfx - Delete $INSTDIR\7-zipn.dll - Delete $INSTDIR\7zipDoc.txt - Delete $INSTDIR\file_id.diz - Delete $INSTDIR\7zip_pad.xml - Delete $INSTDIR\copying.txt - - Delete $INSTDIR\Codecs\7zAES.dll - Delete $INSTDIR\Codecs\AES.dll - Delete $INSTDIR\Codecs\Branch.dll - Delete $INSTDIR\Codecs\BZip2.dll - Delete $INSTDIR\Codecs\Copy.dll - Delete $INSTDIR\Codecs\Deflate.dll - Delete $INSTDIR\Codecs\Implode.dll - Delete $INSTDIR\Codecs\LZMA.dll - Delete $INSTDIR\Codecs\PPMD.dll - Delete $INSTDIR\Codecs\Rar29.dll - Delete $INSTDIR\Codecs\Swap.dll - - RMDir $INSTDIR\Codecs - - Delete $INSTDIR\Formats\7z.dll - Delete $INSTDIR\Formats\arj.dll - Delete $INSTDIR\Formats\bz2.dll - Delete $INSTDIR\Formats\cab.dll - Delete $INSTDIR\Formats\chm.dll - Delete $INSTDIR\Formats\cpio.dll - Delete $INSTDIR\Formats\deb.dll - Delete $INSTDIR\Formats\gz.dll - Delete $INSTDIR\Formats\iso.dll - Delete $INSTDIR\Formats\lzh.dll - Delete $INSTDIR\Formats\nsis.dll - Delete $INSTDIR\Formats\rar.dll - Delete $INSTDIR\Formats\rpm.dll - Delete $INSTDIR\Formats\split.dll - Delete $INSTDIR\Formats\tar.dll - Delete $INSTDIR\Formats\z.dll - Delete $INSTDIR\Formats\zip.dll - - RMDir $INSTDIR\Formats - - Delete $INSTDIR\Lang\no.txt - - # install files - - SetOutPath $INSTDIR - - File descript.ion - File History.txt - File License.txt - File readme.txt - File 7-zip.chm - - # File 7-zip.dll - - File 7z.dll - File 7zFM.exe - File 7zG.exe - File 7z.exe - File 7z.sfx - File 7zCon.sfx - - SetOutPath $INSTDIR\Lang - - File en.ttt - File af.txt - File an.txt - File ar.txt - File ast.txt - File az.txt - File ba.txt - File be.txt - File bg.txt - File bn.txt - File br.txt - File ca.txt - File co.txt - File cs.txt - File cy.txt - File da.txt - File de.txt - File el.txt - File eo.txt - File es.txt - File et.txt - File eu.txt - File ext.txt - File fa.txt - File fi.txt - File fr.txt - File fur.txt - File fy.txt - File ga.txt - File gl.txt - File gu.txt - File he.txt - File hi.txt - File hr.txt - File hu.txt - File hy.txt - File id.txt - File io.txt - File is.txt - File it.txt - File ja.txt - File ka.txt - File kaa.txt - File kab.txt - File kk.txt - File ko.txt - File ku.txt - File ku-ckb.txt - File ky.txt - File lij.txt - File lt.txt - File lv.txt - File mk.txt - File mn.txt - File mng.txt - File mng2.txt - File mr.txt - File ms.txt - File ne.txt - File nl.txt - File nb.txt - File nn.txt - File pa-in.txt - File pl.txt - File ps.txt - File pt.txt - File pt-br.txt - File ro.txt - File ru.txt - File sa.txt - File si.txt - File sk.txt - File sl.txt - File sq.txt - File sr-spc.txt - File sr-spl.txt - File sv.txt - File ta.txt - File th.txt - File tr.txt - File tt.txt - File ug.txt - File uk.txt - File uz.txt - File va.txt - File vi.txt - File yo.txt - File zh-cn.txt - File zh-tw.txt - - SetOutPath $INSTDIR - - # delete "current user" menu items - - Delete "$SMPROGRAMS\7-Zip\${FM_LINK}" - Delete "$SMPROGRAMS\7-Zip\${HELP_LINK}" - RMDir $SMPROGRAMS\7-Zip - - # set "all users" mode - - SetShellVarContext all - - !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED 7-zip.dll $INSTDIR\7-zip.dll $INSTDIR - - ClearErrors - - # create start menu icons - - SetOutPath $INSTDIR - - CreateDirectory $SMPROGRAMS\7-Zip - CreateShortCut "$SMPROGRAMS\7-Zip\${FM_LINK}" $INSTDIR\7zFM.exe - CreateShortCut "$SMPROGRAMS\7-Zip\${HELP_LINK}" $INSTDIR\7-zip.chm - - IfErrors 0 noScErrors - - SetShellVarContext current - - CreateDirectory $SMPROGRAMS\7-Zip - CreateShortCut "$SMPROGRAMS\7-Zip\${FM_LINK}" $INSTDIR\7zFM.exe - CreateShortCut "$SMPROGRAMS\7-Zip\${HELP_LINK}" $INSTDIR\7-zip.chm - -noScErrors: - - # store install folder - - WriteRegStr HKLM Software\7-Zip Path32 $INSTDIR - WriteRegStr HKLM Software\7-Zip Path $INSTDIR - WriteRegStr HKCU Software\7-Zip Path32 $INSTDIR - WriteRegStr HKCU Software\7-Zip Path $INSTDIR - - # write reg entries - - WriteRegStr HKCR "CLSID\${CLSID_CONTEXT_MENU}" "" "7-Zip Shell Extension" - WriteRegStr HKCR "CLSID\${CLSID_CONTEXT_MENU}\InprocServer32" "" $INSTDIR\7-zip.dll - WriteRegStr HKCR "CLSID\${CLSID_CONTEXT_MENU}\InprocServer32" ThreadingModel Apartment - DeleteRegValue HKCR "CLSID\${CLSID_CONTEXT_MENU}\InprocServer32" "InprocServer32" - - WriteRegStr HKCR "*\shellex\ContextMenuHandlers\7-Zip" "" "${CLSID_CONTEXT_MENU}" - WriteRegStr HKCR "Directory\shellex\ContextMenuHandlers\7-Zip" "" "${CLSID_CONTEXT_MENU}" - WriteRegStr HKCR "Folder\shellex\ContextMenuHandlers\7-Zip" "" "${CLSID_CONTEXT_MENU}" - - WriteRegStr HKCR "Directory\shellex\DragDropHandlers\7-Zip" "" "${CLSID_CONTEXT_MENU}" - WriteRegStr HKCR "Drive\shellex\DragDropHandlers\7-Zip" "" "${CLSID_CONTEXT_MENU}" - - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved" "${CLSID_CONTEXT_MENU}" "7-Zip Shell Extension" - - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\App Paths\7zFM.exe" "" $INSTDIR\7zFM.exe - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\App Paths\7zFM.exe" Path $INSTDIR - - # create uninstaller - - WriteRegStr HKLM Software\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip DisplayName "${NAME_FULL}" - WriteRegStr HKLM Software\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip UninstallString '"$INSTDIR\Uninstall.exe"' - WriteRegDWORD HKLM Software\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip NoModify 1 - WriteRegDWORD HKLM Software\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip NoRepair 1 - - WriteUninstaller $INSTDIR\Uninstall.exe - - !ifdef WIN64 - ExecWait 'regsvr32 /s "$INSTDIR\7-zip.dll"' - !endif - -SectionEnd - - -;-------------------------------- -;Installer Functions - -/* -Function .onInit - - !insertmacro MUI_LANGDLL_DISPLAY - -FunctionEnd -*/ - - - - -;-------------------------------- -;Uninstaller Section - -Section Uninstall - - ExecWait 'regsvr32 /u /s "$INSTDIR\7-zip.dll"' - - # delete files - - Delete $INSTDIR\descript.ion - Delete $INSTDIR\History.txt - Delete $INSTDIR\License.txt - Delete $INSTDIR\readme.txt - Delete $INSTDIR\7-zip.chm - - Delete $INSTDIR\7z.dll - Delete $INSTDIR\7zFM.exe - Delete $INSTDIR\7zG.exe - Delete $INSTDIR\7z.exe - Delete $INSTDIR\7z.sfx - Delete $INSTDIR\7zCon.sfx - - Delete $INSTDIR\Lang\en.ttt - Delete $INSTDIR\Lang\af.txt - Delete $INSTDIR\Lang\an.txt - Delete $INSTDIR\Lang\ar.txt - Delete $INSTDIR\Lang\ast.txt - Delete $INSTDIR\Lang\az.txt - Delete $INSTDIR\Lang\ba.txt - Delete $INSTDIR\Lang\be.txt - Delete $INSTDIR\Lang\bg.txt - Delete $INSTDIR\Lang\bn.txt - Delete $INSTDIR\Lang\br.txt - Delete $INSTDIR\Lang\ca.txt - Delete $INSTDIR\Lang\co.txt - Delete $INSTDIR\Lang\cs.txt - Delete $INSTDIR\Lang\cy.txt - Delete $INSTDIR\Lang\da.txt - Delete $INSTDIR\Lang\de.txt - Delete $INSTDIR\Lang\el.txt - Delete $INSTDIR\Lang\eo.txt - Delete $INSTDIR\Lang\es.txt - Delete $INSTDIR\Lang\et.txt - Delete $INSTDIR\Lang\eu.txt - Delete $INSTDIR\Lang\ext.txt - Delete $INSTDIR\Lang\fa.txt - Delete $INSTDIR\Lang\fi.txt - Delete $INSTDIR\Lang\fr.txt - Delete $INSTDIR\Lang\fur.txt - Delete $INSTDIR\Lang\fy.txt - Delete $INSTDIR\Lang\ga.txt - Delete $INSTDIR\Lang\gl.txt - Delete $INSTDIR\Lang\gu.txt - Delete $INSTDIR\Lang\he.txt - Delete $INSTDIR\Lang\hi.txt - Delete $INSTDIR\Lang\hr.txt - Delete $INSTDIR\Lang\hu.txt - Delete $INSTDIR\Lang\hy.txt - Delete $INSTDIR\Lang\id.txt - Delete $INSTDIR\Lang\io.txt - Delete $INSTDIR\Lang\is.txt - Delete $INSTDIR\Lang\it.txt - Delete $INSTDIR\Lang\ja.txt - Delete $INSTDIR\Lang\ka.txt - Delete $INSTDIR\Lang\kaa.txt - Delete $INSTDIR\Lang\kab.txt - Delete $INSTDIR\Lang\kk.txt - Delete $INSTDIR\Lang\ko.txt - Delete $INSTDIR\Lang\ku.txt - Delete $INSTDIR\Lang\ku-ckb.txt - Delete $INSTDIR\Lang\ky.txt - Delete $INSTDIR\Lang\lij.txt - Delete $INSTDIR\Lang\lt.txt - Delete $INSTDIR\Lang\lv.txt - Delete $INSTDIR\Lang\mk.txt - Delete $INSTDIR\Lang\mn.txt - Delete $INSTDIR\Lang\mng.txt - Delete $INSTDIR\Lang\mng2.txt - Delete $INSTDIR\Lang\mr.txt - Delete $INSTDIR\Lang\ms.txt - Delete $INSTDIR\Lang\ne.txt - Delete $INSTDIR\Lang\nl.txt - Delete $INSTDIR\Lang\nb.txt - Delete $INSTDIR\Lang\nn.txt - Delete $INSTDIR\Lang\pa-in.txt - Delete $INSTDIR\Lang\pl.txt - Delete $INSTDIR\Lang\ps.txt - Delete $INSTDIR\Lang\pt.txt - Delete $INSTDIR\Lang\pt-br.txt - Delete $INSTDIR\Lang\ro.txt - Delete $INSTDIR\Lang\ru.txt - Delete $INSTDIR\Lang\sa.txt - Delete $INSTDIR\Lang\si.txt - Delete $INSTDIR\Lang\sk.txt - Delete $INSTDIR\Lang\sl.txt - Delete $INSTDIR\Lang\sq.txt - Delete $INSTDIR\Lang\sr.txt - Delete $INSTDIR\Lang\sr-spc.txt - Delete $INSTDIR\Lang\sr-spl.txt - Delete $INSTDIR\Lang\sv.txt - Delete $INSTDIR\Lang\ta.txt - Delete $INSTDIR\Lang\th.txt - Delete $INSTDIR\Lang\tr.txt - Delete $INSTDIR\Lang\tt.txt - Delete $INSTDIR\Lang\ug.txt - Delete $INSTDIR\Lang\uk.txt - Delete $INSTDIR\Lang\uz.txt - Delete $INSTDIR\Lang\va.txt - Delete $INSTDIR\Lang\vi.txt - Delete $INSTDIR\Lang\vr.txt - Delete $INSTDIR\Lang\yo.txt - Delete $INSTDIR\Lang\zh-cn.txt - Delete $INSTDIR\Lang\zh-tw.txt - - RMDir $INSTDIR\Lang - - Delete /REBOOTOK $INSTDIR\7-zip.dll - Delete $INSTDIR\Uninstall.exe - - RMDir $INSTDIR - - # delete start menu entires - - SetShellVarContext all - - # ClearErrors - - Delete "$SMPROGRAMS\7-Zip\${FM_LINK}" - Delete "$SMPROGRAMS\7-Zip\${HELP_LINK}" - RMDir $SMPROGRAMS\7-Zip - - # IfErrors 0 noScErrors - - SetShellVarContext current - - Delete "$SMPROGRAMS\7-Zip\${FM_LINK}" - Delete "$SMPROGRAMS\7-Zip\${HELP_LINK}" - RMDir $SMPROGRAMS\7-Zip - - # noScErrors: - - - # delete registry entries - - DeleteRegKey HKLM Software\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\App Paths\7zFM.exe" - - DeleteRegKey HKLM Software\7-Zip - DeleteRegKey HKCU Software\7-Zip - - DeleteRegKey HKCR CLSID\${CLSID_CONTEXT_MENU} - - DeleteRegKey HKCR *\shellex\ContextMenuHandlers\7-Zip - DeleteRegKey HKCR Directory\shellex\ContextMenuHandlers\7-Zip - DeleteRegKey HKCR Folder\shellex\ContextMenuHandlers\7-Zip - - DeleteRegKey HKCR Drive\shellex\DragDropHandlers\7-Zip - DeleteRegKey HKCR Directory\shellex\DragDropHandlers\7-Zip - DeleteRegKey HKCR Folder\shellex\DragDropHandlers\7-Zip - - DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved" "${CLSID_CONTEXT_MENU}" - - DeleteRegKey HKCR 7-Zip.001 - DeleteRegKey HKCR 7-Zip.7z - DeleteRegKey HKCR 7-Zip.arj - DeleteRegKey HKCR 7-Zip.bz2 - DeleteRegKey HKCR 7-Zip.bzip2 - DeleteRegKey HKCR 7-Zip.tbz - DeleteRegKey HKCR 7-Zip.tbz2 - DeleteRegKey HKCR 7-Zip.cab - DeleteRegKey HKCR 7-Zip.cpio - DeleteRegKey HKCR 7-Zip.deb - DeleteRegKey HKCR 7-Zip.dmg - DeleteRegKey HKCR 7-Zip.fat - DeleteRegKey HKCR 7-Zip.gz - DeleteRegKey HKCR 7-Zip.gzip - DeleteRegKey HKCR 7-Zip.hfs - DeleteRegKey HKCR 7-Zip.iso - DeleteRegKey HKCR 7-Zip.lha - DeleteRegKey HKCR 7-Zip.lzh - DeleteRegKey HKCR 7-Zip.lzma - DeleteRegKey HKCR 7-Zip.ntfs - DeleteRegKey HKCR 7-Zip.rar - DeleteRegKey HKCR 7-Zip.rpm - DeleteRegKey HKCR 7-Zip.split - DeleteRegKey HKCR 7-Zip.squashfs - DeleteRegKey HKCR 7-Zip.swm - DeleteRegKey HKCR 7-Zip.tar - DeleteRegKey HKCR 7-Zip.taz - DeleteRegKey HKCR 7-Zip.tgz - DeleteRegKey HKCR 7-Zip.tpz - DeleteRegKey HKCR 7-Zip.txz - DeleteRegKey HKCR 7-Zip.vhd - DeleteRegKey HKCR 7-Zip.wim - DeleteRegKey HKCR 7-Zip.xar - DeleteRegKey HKCR 7-Zip.xz - DeleteRegKey HKCR 7-Zip.z - DeleteRegKey HKCR 7-Zip.zip - -SectionEnd +;-------------------------------- +;Defines + +!define VERSION_MAJOR 19 +!define VERSION_MINOR 00 +!define VERSION_POSTFIX_FULL " ZS" +!ifdef WIN64 +!ifdef IA64 +!define VERSION_SYS_POSTFIX_FULL " for Windows IA-64" +!else +!define VERSION_SYS_POSTFIX_FULL " for Windows x64" +!endif +!else +!define VERSION_SYS_POSTFIX_FULL "" +!endif +!define NAME_FULL "7-Zip ${VERSION_MAJOR}.${VERSION_MINOR}${VERSION_POSTFIX_FULL}${VERSION_SYS_POSTFIX_FULL}" +!define VERSION_POSTFIX "" +!ifdef WIN64 +!ifdef IA64 +!define VERSION_SYS_POSTFIX "-ia64" +!else +!define VERSION_SYS_POSTFIX "-x64" +!endif +!else +!define VERSION_SYS_POSTFIX "" +!endif + + + +!define FM_LINK "7-Zip File Manager.lnk" +!define HELP_LINK "7-Zip Help.lnk" + +!define CLSID_CONTEXT_MENU {23170F69-40C1-278A-1000-000100020000} + +#!define NO_COMPRESSION + + !include "Library.nsh" + !include "MUI.nsh" + +;-------------------------------- +;Configuration + + ;General + Name "${NAME_FULL}" + BrandingText "www.7-zip.org" + OutFile "..\7z${VERSION_MAJOR}${VERSION_MINOR}${VERSION_POSTFIX}${VERSION_SYS_POSTFIX}.exe" + + ;Folder selection page + InstallDir "$PROGRAMFILES\7-Zip" + + ;Get install folder from registry if available + InstallDirRegKey HKCU "Software\7-Zip" "Path32" + + ;Compressor +!ifndef NO_COMPRESSION + SetCompressor /solid lzma + ; SetCompressorFilter 1 +!ifdef IA64 + SetCompressorDictSize 8 +!else + SetCompressorDictSize 4 +!endif +!else + SetCompress off +!endif + + +;-------------------------------- +;Variables + +;-------------------------------- +;Interface Settings + + !define MUI_ABORTWARNING + +;-------------------------------- +;Pages + + #!insertmacro MUI_PAGE_LICENSE "License.txt" + !insertmacro MUI_PAGE_DIRECTORY + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_PAGE_FINISH + + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_INSTFILES + !insertmacro MUI_UNPAGE_FINISH + +;-------------------------------- +;Languages + + !insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +;Reserve Files + + ;These files should be inserted before other files in the data block + ;Keep these lines before any File command + ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA) + + !insertmacro MUI_RESERVEFILE_LANGDLL + +;-------------------------------- +;Installer Sections + +Section + !ifndef WIN64 + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\App Paths\7zFMn.exe" + !endif + + # delete old unwanted files + + Delete $INSTDIR\7zFMn.exe + Delete $INSTDIR\7zgn.exe + Delete $INSTDIR\7zn.exe + Delete $INSTDIR\7zan.exe + Delete $INSTDIR\7zC.sfx + Delete $INSTDIR\7-zipn.dll + Delete $INSTDIR\7zipDoc.txt + Delete $INSTDIR\file_id.diz + Delete $INSTDIR\7zip_pad.xml + Delete $INSTDIR\copying.txt + + Delete $INSTDIR\Codecs\7zAES.dll + Delete $INSTDIR\Codecs\AES.dll + Delete $INSTDIR\Codecs\Branch.dll + Delete $INSTDIR\Codecs\BZip2.dll + Delete $INSTDIR\Codecs\Copy.dll + Delete $INSTDIR\Codecs\Deflate.dll + Delete $INSTDIR\Codecs\Implode.dll + Delete $INSTDIR\Codecs\LZMA.dll + Delete $INSTDIR\Codecs\PPMD.dll + Delete $INSTDIR\Codecs\Rar29.dll + Delete $INSTDIR\Codecs\Swap.dll + + RMDir $INSTDIR\Codecs + + Delete $INSTDIR\Formats\7z.dll + Delete $INSTDIR\Formats\arj.dll + Delete $INSTDIR\Formats\bz2.dll + Delete $INSTDIR\Formats\cab.dll + Delete $INSTDIR\Formats\chm.dll + Delete $INSTDIR\Formats\cpio.dll + Delete $INSTDIR\Formats\deb.dll + Delete $INSTDIR\Formats\gz.dll + Delete $INSTDIR\Formats\iso.dll + Delete $INSTDIR\Formats\lzh.dll + Delete $INSTDIR\Formats\nsis.dll + Delete $INSTDIR\Formats\rar.dll + Delete $INSTDIR\Formats\rpm.dll + Delete $INSTDIR\Formats\split.dll + Delete $INSTDIR\Formats\tar.dll + Delete $INSTDIR\Formats\z.dll + Delete $INSTDIR\Formats\zip.dll + + RMDir $INSTDIR\Formats + + Delete $INSTDIR\Lang\no.txt + + # install files + + SetOutPath $INSTDIR + + File descript.ion + File History.txt + File License.txt + File readme.txt + File 7-zip.chm + + # File 7-zip.dll + + File 7z.dll + File 7zFM.exe + File 7zG.exe + File 7z.exe + File 7z.sfx + File 7zCon.sfx + + SetOutPath $INSTDIR\Lang + + File en.ttt + File af.txt + File an.txt + File ar.txt + File ast.txt + File az.txt + File ba.txt + File be.txt + File bg.txt + File bn.txt + File br.txt + File ca.txt + File co.txt + File cs.txt + File cy.txt + File da.txt + File de.txt + File el.txt + File eo.txt + File es.txt + File et.txt + File eu.txt + File ext.txt + File fa.txt + File fi.txt + File fr.txt + File fur.txt + File fy.txt + File ga.txt + File gl.txt + File gu.txt + File he.txt + File hi.txt + File hr.txt + File hu.txt + File hy.txt + File id.txt + File io.txt + File is.txt + File it.txt + File ja.txt + File ka.txt + File kaa.txt + File kab.txt + File kk.txt + File ko.txt + File ku.txt + File ku-ckb.txt + File ky.txt + File lij.txt + File lt.txt + File lv.txt + File mk.txt + File mn.txt + File mng.txt + File mng2.txt + File mr.txt + File ms.txt + File ne.txt + File nl.txt + File nb.txt + File nn.txt + File pa-in.txt + File pl.txt + File ps.txt + File pt.txt + File pt-br.txt + File ro.txt + File ru.txt + File sa.txt + File si.txt + File sk.txt + File sl.txt + File sq.txt + File sr-spc.txt + File sr-spl.txt + File sv.txt + File ta.txt + File th.txt + File tr.txt + File tt.txt + File ug.txt + File uk.txt + File uz.txt + File va.txt + File vi.txt + File yo.txt + File zh-cn.txt + File zh-tw.txt + + SetOutPath $INSTDIR + + # delete "current user" menu items + + Delete "$SMPROGRAMS\7-Zip\${FM_LINK}" + Delete "$SMPROGRAMS\7-Zip\${HELP_LINK}" + RMDir $SMPROGRAMS\7-Zip + + # set "all users" mode + + SetShellVarContext all + + !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED 7-zip.dll $INSTDIR\7-zip.dll $INSTDIR + + ClearErrors + + # create start menu icons + + SetOutPath $INSTDIR + + CreateDirectory $SMPROGRAMS\7-Zip + CreateShortCut "$SMPROGRAMS\7-Zip\${FM_LINK}" $INSTDIR\7zFM.exe + CreateShortCut "$SMPROGRAMS\7-Zip\${HELP_LINK}" $INSTDIR\7-zip.chm + + IfErrors 0 noScErrors + + SetShellVarContext current + + CreateDirectory $SMPROGRAMS\7-Zip + CreateShortCut "$SMPROGRAMS\7-Zip\${FM_LINK}" $INSTDIR\7zFM.exe + CreateShortCut "$SMPROGRAMS\7-Zip\${HELP_LINK}" $INSTDIR\7-zip.chm + +noScErrors: + + # store install folder + + WriteRegStr HKLM Software\7-Zip Path32 $INSTDIR + WriteRegStr HKLM Software\7-Zip Path $INSTDIR + WriteRegStr HKCU Software\7-Zip Path32 $INSTDIR + WriteRegStr HKCU Software\7-Zip Path $INSTDIR + + # write reg entries + + WriteRegStr HKCR "CLSID\${CLSID_CONTEXT_MENU}" "" "7-Zip Shell Extension" + WriteRegStr HKCR "CLSID\${CLSID_CONTEXT_MENU}\InprocServer32" "" $INSTDIR\7-zip.dll + WriteRegStr HKCR "CLSID\${CLSID_CONTEXT_MENU}\InprocServer32" ThreadingModel Apartment + DeleteRegValue HKCR "CLSID\${CLSID_CONTEXT_MENU}\InprocServer32" "InprocServer32" + + WriteRegStr HKCR "*\shellex\ContextMenuHandlers\7-Zip" "" "${CLSID_CONTEXT_MENU}" + WriteRegStr HKCR "Directory\shellex\ContextMenuHandlers\7-Zip" "" "${CLSID_CONTEXT_MENU}" + WriteRegStr HKCR "Folder\shellex\ContextMenuHandlers\7-Zip" "" "${CLSID_CONTEXT_MENU}" + + WriteRegStr HKCR "Directory\shellex\DragDropHandlers\7-Zip" "" "${CLSID_CONTEXT_MENU}" + WriteRegStr HKCR "Drive\shellex\DragDropHandlers\7-Zip" "" "${CLSID_CONTEXT_MENU}" + + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved" "${CLSID_CONTEXT_MENU}" "7-Zip Shell Extension" + + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\App Paths\7zFM.exe" "" $INSTDIR\7zFM.exe + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\App Paths\7zFM.exe" Path $INSTDIR + + # create uninstaller + + WriteRegStr HKLM Software\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip DisplayName "${NAME_FULL}" + WriteRegStr HKLM Software\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip UninstallString '"$INSTDIR\Uninstall.exe"' + WriteRegDWORD HKLM Software\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip NoModify 1 + WriteRegDWORD HKLM Software\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip NoRepair 1 + + WriteUninstaller $INSTDIR\Uninstall.exe + + !ifdef WIN64 + ExecWait 'regsvr32 /s "$INSTDIR\7-zip.dll"' + !endif + +SectionEnd + + +;-------------------------------- +;Installer Functions + +/* +Function .onInit + + !insertmacro MUI_LANGDLL_DISPLAY + +FunctionEnd +*/ + + + + +;-------------------------------- +;Uninstaller Section + +Section Uninstall + + ExecWait 'regsvr32 /u /s "$INSTDIR\7-zip.dll"' + + # delete files + + Delete $INSTDIR\descript.ion + Delete $INSTDIR\History.txt + Delete $INSTDIR\License.txt + Delete $INSTDIR\readme.txt + Delete $INSTDIR\7-zip.chm + + Delete $INSTDIR\7z.dll + Delete $INSTDIR\7zFM.exe + Delete $INSTDIR\7zG.exe + Delete $INSTDIR\7z.exe + Delete $INSTDIR\7z.sfx + Delete $INSTDIR\7zCon.sfx + + Delete $INSTDIR\Lang\en.ttt + Delete $INSTDIR\Lang\af.txt + Delete $INSTDIR\Lang\an.txt + Delete $INSTDIR\Lang\ar.txt + Delete $INSTDIR\Lang\ast.txt + Delete $INSTDIR\Lang\az.txt + Delete $INSTDIR\Lang\ba.txt + Delete $INSTDIR\Lang\be.txt + Delete $INSTDIR\Lang\bg.txt + Delete $INSTDIR\Lang\bn.txt + Delete $INSTDIR\Lang\br.txt + Delete $INSTDIR\Lang\ca.txt + Delete $INSTDIR\Lang\co.txt + Delete $INSTDIR\Lang\cs.txt + Delete $INSTDIR\Lang\cy.txt + Delete $INSTDIR\Lang\da.txt + Delete $INSTDIR\Lang\de.txt + Delete $INSTDIR\Lang\el.txt + Delete $INSTDIR\Lang\eo.txt + Delete $INSTDIR\Lang\es.txt + Delete $INSTDIR\Lang\et.txt + Delete $INSTDIR\Lang\eu.txt + Delete $INSTDIR\Lang\ext.txt + Delete $INSTDIR\Lang\fa.txt + Delete $INSTDIR\Lang\fi.txt + Delete $INSTDIR\Lang\fr.txt + Delete $INSTDIR\Lang\fur.txt + Delete $INSTDIR\Lang\fy.txt + Delete $INSTDIR\Lang\ga.txt + Delete $INSTDIR\Lang\gl.txt + Delete $INSTDIR\Lang\gu.txt + Delete $INSTDIR\Lang\he.txt + Delete $INSTDIR\Lang\hi.txt + Delete $INSTDIR\Lang\hr.txt + Delete $INSTDIR\Lang\hu.txt + Delete $INSTDIR\Lang\hy.txt + Delete $INSTDIR\Lang\id.txt + Delete $INSTDIR\Lang\io.txt + Delete $INSTDIR\Lang\is.txt + Delete $INSTDIR\Lang\it.txt + Delete $INSTDIR\Lang\ja.txt + Delete $INSTDIR\Lang\ka.txt + Delete $INSTDIR\Lang\kaa.txt + Delete $INSTDIR\Lang\kab.txt + Delete $INSTDIR\Lang\kk.txt + Delete $INSTDIR\Lang\ko.txt + Delete $INSTDIR\Lang\ku.txt + Delete $INSTDIR\Lang\ku-ckb.txt + Delete $INSTDIR\Lang\ky.txt + Delete $INSTDIR\Lang\lij.txt + Delete $INSTDIR\Lang\lt.txt + Delete $INSTDIR\Lang\lv.txt + Delete $INSTDIR\Lang\mk.txt + Delete $INSTDIR\Lang\mn.txt + Delete $INSTDIR\Lang\mng.txt + Delete $INSTDIR\Lang\mng2.txt + Delete $INSTDIR\Lang\mr.txt + Delete $INSTDIR\Lang\ms.txt + Delete $INSTDIR\Lang\ne.txt + Delete $INSTDIR\Lang\nl.txt + Delete $INSTDIR\Lang\nb.txt + Delete $INSTDIR\Lang\nn.txt + Delete $INSTDIR\Lang\pa-in.txt + Delete $INSTDIR\Lang\pl.txt + Delete $INSTDIR\Lang\ps.txt + Delete $INSTDIR\Lang\pt.txt + Delete $INSTDIR\Lang\pt-br.txt + Delete $INSTDIR\Lang\ro.txt + Delete $INSTDIR\Lang\ru.txt + Delete $INSTDIR\Lang\sa.txt + Delete $INSTDIR\Lang\si.txt + Delete $INSTDIR\Lang\sk.txt + Delete $INSTDIR\Lang\sl.txt + Delete $INSTDIR\Lang\sq.txt + Delete $INSTDIR\Lang\sr.txt + Delete $INSTDIR\Lang\sr-spc.txt + Delete $INSTDIR\Lang\sr-spl.txt + Delete $INSTDIR\Lang\sv.txt + Delete $INSTDIR\Lang\ta.txt + Delete $INSTDIR\Lang\th.txt + Delete $INSTDIR\Lang\tr.txt + Delete $INSTDIR\Lang\tt.txt + Delete $INSTDIR\Lang\ug.txt + Delete $INSTDIR\Lang\uk.txt + Delete $INSTDIR\Lang\uz.txt + Delete $INSTDIR\Lang\va.txt + Delete $INSTDIR\Lang\vi.txt + Delete $INSTDIR\Lang\vr.txt + Delete $INSTDIR\Lang\yo.txt + Delete $INSTDIR\Lang\zh-cn.txt + Delete $INSTDIR\Lang\zh-tw.txt + + RMDir $INSTDIR\Lang + + Delete /REBOOTOK $INSTDIR\7-zip.dll + Delete $INSTDIR\Uninstall.exe + + RMDir $INSTDIR + + # delete start menu entires + + SetShellVarContext all + + # ClearErrors + + Delete "$SMPROGRAMS\7-Zip\${FM_LINK}" + Delete "$SMPROGRAMS\7-Zip\${HELP_LINK}" + RMDir $SMPROGRAMS\7-Zip + + # IfErrors 0 noScErrors + + SetShellVarContext current + + Delete "$SMPROGRAMS\7-Zip\${FM_LINK}" + Delete "$SMPROGRAMS\7-Zip\${HELP_LINK}" + RMDir $SMPROGRAMS\7-Zip + + # noScErrors: + + + # delete registry entries + + DeleteRegKey HKLM Software\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\App Paths\7zFM.exe" + + DeleteRegKey HKLM Software\7-Zip + DeleteRegKey HKCU Software\7-Zip + + DeleteRegKey HKCR CLSID\${CLSID_CONTEXT_MENU} + + DeleteRegKey HKCR *\shellex\ContextMenuHandlers\7-Zip + DeleteRegKey HKCR Directory\shellex\ContextMenuHandlers\7-Zip + DeleteRegKey HKCR Folder\shellex\ContextMenuHandlers\7-Zip + + DeleteRegKey HKCR Drive\shellex\DragDropHandlers\7-Zip + DeleteRegKey HKCR Directory\shellex\DragDropHandlers\7-Zip + DeleteRegKey HKCR Folder\shellex\DragDropHandlers\7-Zip + + DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved" "${CLSID_CONTEXT_MENU}" + + DeleteRegKey HKCR 7-Zip.001 + DeleteRegKey HKCR 7-Zip.7z + DeleteRegKey HKCR 7-Zip.arj + DeleteRegKey HKCR 7-Zip.bz2 + DeleteRegKey HKCR 7-Zip.bzip2 + DeleteRegKey HKCR 7-Zip.tbz + DeleteRegKey HKCR 7-Zip.tbz2 + DeleteRegKey HKCR 7-Zip.cab + DeleteRegKey HKCR 7-Zip.cpio + DeleteRegKey HKCR 7-Zip.deb + DeleteRegKey HKCR 7-Zip.dmg + DeleteRegKey HKCR 7-Zip.fat + DeleteRegKey HKCR 7-Zip.gz + DeleteRegKey HKCR 7-Zip.gzip + DeleteRegKey HKCR 7-Zip.hfs + DeleteRegKey HKCR 7-Zip.iso + DeleteRegKey HKCR 7-Zip.lha + DeleteRegKey HKCR 7-Zip.lzh + DeleteRegKey HKCR 7-Zip.lzma + DeleteRegKey HKCR 7-Zip.ntfs + DeleteRegKey HKCR 7-Zip.rar + DeleteRegKey HKCR 7-Zip.rpm + DeleteRegKey HKCR 7-Zip.split + DeleteRegKey HKCR 7-Zip.squashfs + DeleteRegKey HKCR 7-Zip.swm + DeleteRegKey HKCR 7-Zip.tar + DeleteRegKey HKCR 7-Zip.taz + DeleteRegKey HKCR 7-Zip.tgz + DeleteRegKey HKCR 7-Zip.tpz + DeleteRegKey HKCR 7-Zip.txz + DeleteRegKey HKCR 7-Zip.vhd + DeleteRegKey HKCR 7-Zip.wim + DeleteRegKey HKCR 7-Zip.xar + DeleteRegKey HKCR 7-Zip.xz + DeleteRegKey HKCR 7-Zip.z + DeleteRegKey HKCR 7-Zip.zip + +SectionEnd diff --git a/DOC/7zip.wxs b/DOC/7zip.wxs index 93f05f960..338d58290 100644 --- a/DOC/7zip.wxs +++ b/DOC/7zip.wxs @@ -1,399 +1,399 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 - - 1 - - - - - - - - - - - - - - - - Privileged - - - - - - - - - - - - - - - - - - - - - - - - - - - Privileged - - - - - - Privileged - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + + 1 + + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + Privileged + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DOC/License.txt b/DOC/License.txt index e9113842c..d6b672bb0 100644 --- a/DOC/License.txt +++ b/DOC/License.txt @@ -1,90 +1,90 @@ - 7-Zip source code - ~~~~~~~~~~~~~~~~~ - License for use and distribution - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - 7-Zip Copyright (C) 1999-2019 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 + 7-Zip source code + ~~~~~~~~~~~~~~~~~ + License for use and distribution + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 7-Zip Copyright (C) 1999-2019 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 6d0641bae..d4a1b1dd4 100644 --- a/DOC/Methods.txt +++ b/DOC/Methods.txt @@ -1,173 +1,173 @@ -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: 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 diff --git a/DOC/copying.txt b/DOC/copying.txt index 3394995ab..4362b4915 100644 --- a/DOC/copying.txt +++ b/DOC/copying.txt @@ -1,502 +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. - - - Copyright (C) - - 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. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! + 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. + + + Copyright (C) + + 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/DOC/lzma.txt b/DOC/lzma.txt index 1f92142ea..a65988fe0 100644 --- a/DOC/lzma.txt +++ b/DOC/lzma.txt @@ -1,328 +1,328 @@ -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: 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 diff --git a/DOC/readme.txt b/DOC/readme.txt index 9dd6e0849..0d1aebf7b 100644 --- a/DOC/readme.txt +++ b/DOC/readme.txt @@ -1,180 +1,180 @@ -7-Zip 19.00 Sources -------------------- - -7-Zip is a file archiver for Windows. - -7-Zip Copyright (C) 1999-2019 Igor Pavlov. - - -License Info ------------- - -7-Zip is free software distributed under the GNU LGPL -(except for unRar code). -read License.txt for more infomation about license. - -Notes about unRAR license: - -Please check main restriction from unRar license: - - 2. The unRAR sources may be used in any software to handle RAR - archives without limitations free of charge, but cannot be used - to re-create the RAR compression algorithm, which is proprietary. - Distribution of modified unRAR sources in separate form or as a - part of other software is permitted, provided that it is clearly - stated in the documentation and source comments that the code may - not be used to develop a RAR (WinRAR) compatible archiver. - -In brief it means: -1) You can compile and use compiled files under GNU LGPL rules, since - unRAR license almost has no restrictions for compiled files. - You can link these compiled files to LGPL programs. -2) You can fix bugs in source code and use compiled fixed version. -3) You can not use unRAR sources to re-create the RAR compression algorithm. - - -LZMA SDK --------- - -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 --------------- - -To compile the sources to Windows binaries you need Visual Studio compiler and/or Windows SDK. -You can use latest Windows Studio 2017 to compile binaries for x86, x64 and arm64 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 - arm64 : Windows Studio 2017 - arm : Windows Studio 2017 - 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. -The 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 under Unix/Linux --------------------------- -Check this site for Posix/Linux version: -http://sourceforge.net/projects/p7zip/ - - -Notes: ------- -7-Zip consists of COM modules (DLL files). -But 7-Zip doesn't use standard COM interfaces for creating objects. -Look at -7zip\UI\Client7z folder for example of using DLL files of 7-Zip. -Some DLL files can use other DLL files from 7-Zip. -If you don't like it, you must use standalone version of DLL. -To compile standalone version of DLL you must include all used parts -to project and define some defs. -For example, 7zip\Bundles\Format7z is a standalone version of 7z.dll -that works with 7z format. So you can use such DLL in your project -without additional DLL files. - - -Description of 7-Zip sources package -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -DOC Documentation ---- - 7zFormat.txt - 7z format description - copying.txt - GNU LGPL license - unRarLicense.txt - License for unRAR part of source code - src-history.txt - Sources history - Methods.txt - Compression method IDs - readme.txt - Readme file - lzma.txt - LZMA compression description - 7zip.nsi - installer script for NSIS - 7zip.wix - installer script for WIX - - -Asm - Source code in Assembler (optimized code for CRC calculation and Intel-AES encryption) - -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. - 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 / decompression - - 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 +7-Zip 19.00 Sources +------------------- + +7-Zip is a file archiver for Windows. + +7-Zip Copyright (C) 1999-2019 Igor Pavlov. + + +License Info +------------ + +7-Zip is free software distributed under the GNU LGPL +(except for unRar code). +read License.txt for more infomation about license. + +Notes about unRAR license: + +Please check main restriction from unRar license: + + 2. The unRAR sources may be used in any software to handle RAR + archives without limitations free of charge, but cannot be used + to re-create the RAR compression algorithm, which is proprietary. + Distribution of modified unRAR sources in separate form or as a + part of other software is permitted, provided that it is clearly + stated in the documentation and source comments that the code may + not be used to develop a RAR (WinRAR) compatible archiver. + +In brief it means: +1) You can compile and use compiled files under GNU LGPL rules, since + unRAR license almost has no restrictions for compiled files. + You can link these compiled files to LGPL programs. +2) You can fix bugs in source code and use compiled fixed version. +3) You can not use unRAR sources to re-create the RAR compression algorithm. + + +LZMA SDK +-------- + +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 +-------------- + +To compile the sources to Windows binaries you need Visual Studio compiler and/or Windows SDK. +You can use latest Windows Studio 2017 to compile binaries for x86, x64 and arm64 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 + arm64 : Windows Studio 2017 + arm : Windows Studio 2017 + 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. +The 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 under Unix/Linux +-------------------------- +Check this site for Posix/Linux version: +http://sourceforge.net/projects/p7zip/ + + +Notes: +------ +7-Zip consists of COM modules (DLL files). +But 7-Zip doesn't use standard COM interfaces for creating objects. +Look at +7zip\UI\Client7z folder for example of using DLL files of 7-Zip. +Some DLL files can use other DLL files from 7-Zip. +If you don't like it, you must use standalone version of DLL. +To compile standalone version of DLL you must include all used parts +to project and define some defs. +For example, 7zip\Bundles\Format7z is a standalone version of 7z.dll +that works with 7z format. So you can use such DLL in your project +without additional DLL files. + + +Description of 7-Zip sources package +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +DOC Documentation +--- + 7zFormat.txt - 7z format description + copying.txt - GNU LGPL license + unRarLicense.txt - License for unRAR part of source code + src-history.txt - Sources history + Methods.txt - Compression method IDs + readme.txt - Readme file + lzma.txt - LZMA compression description + 7zip.nsi - installer script for NSIS + 7zip.wix - installer script for WIX + + +Asm - Source code in Assembler (optimized code for CRC calculation and Intel-AES encryption) + +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. + 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 / decompression + + 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 index 7fcb09a00..51921cd0b 100644 --- a/DOC/src-history.txt +++ b/DOC/src-history.txt @@ -1,595 +1,595 @@ -HISTORY of the 7-Zip source code --------------------------------- - -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 - OutBuffer.h: COutBuffer uses ISequentialOutStream *_stream; instead of CMyComPtr - - -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. - +HISTORY of the 7-Zip source code +-------------------------------- + +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 + OutBuffer.h: COutBuffer uses ISequentialOutStream *_stream; instead of CMyComPtr + + +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. +