Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pavlov <ipavlov@users.sourceforge.net>2014-11-23 03:00:00 +0300
committerKornel LesiƄski <kornel@geekhood.net>2016-05-28 02:16:51 +0300
commitf08f4dcc3c02464c17753b3feafcfe5243b9e236 (patch)
treeb0e1b15bc5368d92dff422e8ec0818564a2b00b8 /CPP/7zip/Archive
parent83f8ddcc5b2161e1e3c49666265257fca8aeb12c (diff)
9.349.34
Diffstat (limited to 'CPP/7zip/Archive')
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7z.dsp16
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7z.dsw0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zCompressionMode.cpp0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zCompressionMode.h0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zDecode.cpp123
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zDecode.h9
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zEncode.cpp94
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zEncode.h2
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zExtract.cpp46
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zFolderInStream.cpp4
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zFolderInStream.h2
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zFolderOutStream.cpp2
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zFolderOutStream.h6
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zHandler.cpp701
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zHandler.h25
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zHandlerOut.cpp378
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zHeader.cpp5
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zHeader.h10
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zIn.cpp1364
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zIn.h333
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zItem.h208
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zOut.cpp463
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zOut.h207
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zProperties.cpp48
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zProperties.h0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zRegister.cpp23
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zSpecStream.cpp10
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zSpecStream.h0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zUpdate.cpp503
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/7zUpdate.h40
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/StdAfx.cpp0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/StdAfx.h3
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/makefile43
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/7z/resource.rc0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/ApmHandler.cpp113
-rw-r--r--CPP/7zip/Archive/ArHandler.cpp857
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Archive.def0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Archive2.def4
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/ArchiveExports.cpp64
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/ArjHandler.cpp636
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Bz2Handler.cpp253
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Cab/CabBlockInStream.cpp191
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Cab/CabBlockInStream.h31
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Cab/CabHandler.cpp512
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Cab/CabHandler.h11
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Cab/CabHeader.cpp0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Cab/CabHeader.h23
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Cab/CabIn.cpp446
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Cab/CabIn.h129
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Cab/CabItem.h29
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Cab/CabRegister.cpp14
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Cab/StdAfx.h2
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Chm/ChmHandler.cpp118
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Chm/ChmHandler.h8
-rwxr-xr-xCPP/7zip/Archive/Chm/ChmHeader.cpp24
-rwxr-xr-xCPP/7zip/Archive/Chm/ChmHeader.h28
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Chm/ChmIn.cpp275
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Chm/ChmIn.h46
-rwxr-xr-xCPP/7zip/Archive/Chm/ChmRegister.cpp13
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Chm/StdAfx.h2
-rwxr-xr-xCPP/7zip/Archive/Com/ComHandler.cpp239
-rwxr-xr-xCPP/7zip/Archive/Com/ComHandler.h28
-rwxr-xr-xCPP/7zip/Archive/Com/ComIn.cpp389
-rwxr-xr-xCPP/7zip/Archive/Com/ComIn.h119
-rwxr-xr-xCPP/7zip/Archive/Com/ComRegister.cpp13
-rw-r--r--CPP/7zip/Archive/ComHandler.cpp875
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/CoderMixer.cpp0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/CoderMixer.h0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/CoderMixer2.cpp70
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/CoderMixer2.h19
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/CoderMixer2MT.cpp56
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/CoderMixer2MT.h12
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/CoderMixer2ST.cpp4
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/CoderMixer2ST.h0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/CoderMixerMT.cpp0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/CoderMixerMT.h0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/CrossThreadProgress.cpp0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/CrossThreadProgress.h0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/DummyOutStream.cpp19
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/DummyOutStream.h7
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/FindSignature.cpp12
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/FindSignature.h0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/HandlerOut.cpp36
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/HandlerOut.h14
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/InStreamWithCRC.cpp32
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/InStreamWithCRC.h0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/ItemNameUtils.cpp37
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/ItemNameUtils.h7
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/MultiStream.cpp43
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/MultiStream.h6
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/OutStreamWithCRC.cpp0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/OutStreamWithCRC.h1
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/OutStreamWithSha1.cpp0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/OutStreamWithSha1.h0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/ParseProperties.cpp0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/ParseProperties.h0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Common/StdAfx.h3
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/CpioHandler.cpp834
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/CramfsHandler.cpp283
-rwxr-xr-xCPP/7zip/Archive/DebHandler.cpp413
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/DeflateProps.cpp0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/DeflateProps.h0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/DllExports.cpp2
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/DllExports2.cpp26
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/DmgHandler.cpp1294
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/ElfHandler.cpp793
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/FatHandler.cpp120
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/FlvHandler.cpp253
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/GzHandler.cpp662
-rwxr-xr-xCPP/7zip/Archive/Hfs/HfsHandler.cpp243
-rwxr-xr-xCPP/7zip/Archive/Hfs/HfsHandler.h26
-rwxr-xr-xCPP/7zip/Archive/Hfs/HfsIn.cpp480
-rwxr-xr-xCPP/7zip/Archive/Hfs/HfsIn.h154
-rwxr-xr-xCPP/7zip/Archive/Hfs/HfsRegister.cpp13
-rw-r--r--CPP/7zip/Archive/HfsHandler.cpp1874
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/IArchive.h327
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/7z.icobin4710 -> 4710 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/arj.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/bz2.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/cab.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/cpio.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/deb.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/dmg.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/fat.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/gz.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/hfs.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/iso.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/lzh.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/lzma.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/ntfs.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/rar.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/rpm.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/split.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/squashfs.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/tar.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/vhd.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/wim.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/xar.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/xz.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/z.icobin3638 -> 3638 bytes
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Icons/zip.icobin3638 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/IhexHandler.cpp500
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Iso/IsoHandler.cpp194
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Iso/IsoHandler.h3
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Iso/IsoHeader.cpp12
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Iso/IsoHeader.h9
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Iso/IsoIn.cpp197
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Iso/IsoIn.h88
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Iso/IsoItem.h62
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Iso/IsoRegister.cpp14
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Iso/StdAfx.h3
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/LzhHandler.cpp111
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/LzmaHandler.cpp323
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/MachoHandler.cpp640
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/MbrHandler.cpp36
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/MslzHandler.cpp308
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/MubHandler.cpp180
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Nsis/NsisDecode.cpp221
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Nsis/NsisDecode.h41
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Nsis/NsisHandler.cpp643
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Nsis/NsisHandler.h25
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Nsis/NsisIn.cpp6343
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Nsis/NsisIn.h423
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Nsis/NsisRegister.cpp15
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Nsis/StdAfx.h3
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/NtfsHandler.cpp1478
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/PeHandler.cpp1967
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/PpmdHandler.cpp55
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Rar/RarHandler.cpp1287
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Rar/RarHandler.h79
-rwxr-xr-xCPP/7zip/Archive/Rar/RarHeader.cpp21
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Rar/RarHeader.h69
-rwxr-xr-xCPP/7zip/Archive/Rar/RarIn.cpp478
-rwxr-xr-xCPP/7zip/Archive/Rar/RarIn.h123
-rwxr-xr-xCPP/7zip/Archive/Rar/RarItem.cpp55
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Rar/RarItem.h40
-rwxr-xr-xCPP/7zip/Archive/Rar/RarRegister.cpp13
-rwxr-xr-xCPP/7zip/Archive/Rar/RarVolumeInStream.cpp78
-rwxr-xr-xCPP/7zip/Archive/Rar/RarVolumeInStream.h49
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Rar/StdAfx.cpp0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Rar/StdAfx.h2
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/RpmHandler.cpp821
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/SplitHandler.cpp275
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/SquashfsHandler.cpp240
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/StdAfx.h3
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/SwfHandler.cpp651
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Tar/StdAfx.h3
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Tar/TarHandler.cpp388
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Tar/TarHandler.h32
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Tar/TarHandlerOut.cpp71
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Tar/TarHeader.cpp12
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Tar/TarHeader.h65
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Tar/TarIn.cpp239
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Tar/TarIn.h11
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Tar/TarItem.h23
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Tar/TarOut.cpp230
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Tar/TarOut.h18
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Tar/TarRegister.cpp22
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Tar/TarUpdate.cpp129
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Tar/TarUpdate.h1
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Udf/StdAfx.h3
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Udf/UdfHandler.cpp170
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Udf/UdfHandler.h11
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Udf/UdfIn.cpp393
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Udf/UdfIn.h54
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Udf/UdfRegister.cpp6
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/UefiHandler.cpp419
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/VhdHandler.cpp517
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Wim/StdAfx.h2
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Wim/WimHandler.cpp817
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Wim/WimHandler.h99
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Wim/WimHandlerOut.cpp1753
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Wim/WimIn.cpp1099
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Wim/WimIn.h355
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Wim/WimRegister.cpp23
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/XarHandler.cpp365
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/XzHandler.cpp661
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/ZHandler.cpp148
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/StdAfx.h2
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipAddCommon.cpp49
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipAddCommon.h0
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipCompressionMode.h2
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipHandler.cpp531
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipHandler.h10
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipHandlerOut.cpp151
-rwxr-xr-xCPP/7zip/Archive/Zip/ZipHeader.cpp36
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipHeader.h264
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipIn.cpp1323
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipIn.h178
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipItem.cpp109
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipItem.h226
-rwxr-xr-xCPP/7zip/Archive/Zip/ZipItemEx.h34
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipOut.cpp331
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipOut.h68
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipRegister.cpp27
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipUpdate.cpp296
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipUpdate.h19
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/makefile0
238 files changed, 33542 insertions, 14766 deletions
diff --git a/CPP/7zip/Archive/7z/7z.dsp b/CPP/7zip/Archive/7z/7z.dsp
index 0484228d..53913f77 100755..100644
--- a/CPP/7zip/Archive/7z/7z.dsp
+++ b/CPP/7zip/Archive/7z/7z.dsp
@@ -328,6 +328,14 @@ SOURCE=..\..\..\Common\StringToInt.cpp
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"
@@ -482,6 +490,10 @@ 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
@@ -558,6 +570,10 @@ 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
diff --git a/CPP/7zip/Archive/7z/7z.dsw b/CPP/7zip/Archive/7z/7z.dsw
index 702a86c7..702a86c7 100755..100644
--- a/CPP/7zip/Archive/7z/7z.dsw
+++ b/CPP/7zip/Archive/7z/7z.dsw
diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.cpp b/CPP/7zip/Archive/7z/7zCompressionMode.cpp
index 6774fc48..6774fc48 100755..100644
--- a/CPP/7zip/Archive/7z/7zCompressionMode.cpp
+++ b/CPP/7zip/Archive/7z/7zCompressionMode.cpp
diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.h b/CPP/7zip/Archive/7z/7zCompressionMode.h
index 5cde97c3..5cde97c3 100755..100644
--- a/CPP/7zip/Archive/7z/7zCompressionMode.h
+++ b/CPP/7zip/Archive/7z/7zCompressionMode.h
diff --git a/CPP/7zip/Archive/7z/7zDecode.cpp b/CPP/7zip/Archive/7z/7zDecode.cpp
index 425a3415..7f0e45d1 100755..100644
--- a/CPP/7zip/Archive/7z/7zDecode.cpp
+++ b/CPP/7zip/Archive/7z/7zDecode.cpp
@@ -16,29 +16,33 @@ static void ConvertFolderItemInfoToBindInfo(const CFolder &folder,
CBindInfoEx &bindInfo)
{
bindInfo.Clear();
- int i;
+ bindInfo.BindPairs.ClearAndSetSize(folder.BindPairs.Size());
+ unsigned i;
for (i = 0; i < folder.BindPairs.Size(); i++)
{
- NCoderMixer::CBindPair bindPair;
+ NCoderMixer::CBindPair &bindPair = bindInfo.BindPairs[i];
bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex;
bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex;
- bindInfo.BindPairs.Add(bindPair);
}
+
+ bindInfo.Coders.ClearAndSetSize(folder.Coders.Size());
+ bindInfo.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size());
+
UInt32 outStreamIndex = 0;
for (i = 0; i < folder.Coders.Size(); i++)
{
- NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+ NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i];
const CCoderInfo &coderInfo = folder.Coders[i];
coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams;
coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams;
- bindInfo.Coders.Add(coderStreamsInfo);
- bindInfo.CoderMethodIDs.Add(coderInfo.MethodID);
+ bindInfo.CoderMethodIDs[i] = coderInfo.MethodID;
for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++)
if (folder.FindBindPairForOutStream(outStreamIndex) < 0)
bindInfo.OutStreams.Add(outStreamIndex);
}
+ bindInfo.InStreams.ClearAndSetSize(folder.PackStreams.Size());
for (i = 0; i < folder.PackStreams.Size(); i++)
- bindInfo.InStreams.Add((UInt32)folder.PackStreams[i]);
+ bindInfo.InStreams[i] = (UInt32)folder.PackStreams[i];
}
static bool AreCodersEqual(const NCoderMixer::CCoderStreamsInfo &a1,
@@ -58,7 +62,7 @@ static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2)
{
if (a1.Coders.Size() != a2.Coders.Size())
return false;
- int i;
+ unsigned i;
for (i = 0; i < a1.Coders.Size(); i++)
if (!AreCodersEqual(a1.Coders[i], a2.Coders[i]))
return false;
@@ -90,45 +94,49 @@ HRESULT CDecoder::Decode(
DECL_EXTERNAL_CODECS_LOC_VARS
IInStream *inStream,
UInt64 startPos,
- const UInt64 *packSizes,
- const CFolder &folderInfo,
+ const CFolders &folders, int folderIndex,
ISequentialOutStream *outStream,
ICompressProgressInfo *compressProgress
- #ifndef _NO_CRYPTO
- , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
- #endif
+ _7Z_DECODER_CRYPRO_VARS_DECL
#if !defined(_7ZIP_ST) && !defined(_SFX)
, bool mtMode, UInt32 numThreads
#endif
)
{
- if (!folderInfo.CheckStructure())
+ const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]];
+ CFolder folderInfo;
+ folders.ParseFolderInfo(folderIndex, folderInfo);
+
+ if (!folderInfo.CheckStructure(folders.GetNumFolderUnpackSizes(folderIndex)))
return E_NOTIMPL;
+
+ /*
+ We don't need to init isEncrypted and passwordIsDefined
+ We must upgrade them only
#ifndef _NO_CRYPTO
+ isEncrypted = false;
passwordIsDefined = false;
#endif
+ */
+
CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
CLockedInStream lockedInStream;
lockedInStream.Init(inStream);
- for (int j = 0; j < folderInfo.PackStreams.Size(); j++)
+ for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++)
{
- CLockedSequentialInStreamImp *lockedStreamImpSpec = new
- CLockedSequentialInStreamImp;
+ CLockedSequentialInStreamImp *lockedStreamImpSpec = new CLockedSequentialInStreamImp;
CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec;
- lockedStreamImpSpec->Init(&lockedInStream, startPos);
- startPos += packSizes[j];
-
- CLimitedSequentialInStream *streamSpec = new
- CLimitedSequentialInStream;
+ lockedStreamImpSpec->Init(&lockedInStream, startPos + packPositions[j]);
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
CMyComPtr<ISequentialInStream> inStream = streamSpec;
streamSpec->SetStream(lockedStreamImp);
- streamSpec->Init(packSizes[j]);
+ streamSpec->Init(packPositions[j + 1] - packPositions[j]);
inStreams.Add(inStream);
}
- int numCoders = folderInfo.Coders.Size();
+ unsigned numCoders = folderInfo.Coders.Size();
CBindInfoEx bindInfo;
ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo);
@@ -139,7 +147,7 @@ HRESULT CDecoder::Decode(
createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev);
if (createNewCoders)
{
- int i;
+ unsigned i;
_decoders.Clear();
// _decoders2.Clear();
@@ -204,17 +212,19 @@ HRESULT CDecoder::Decode(
decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
if (setCompressCodecsInfo)
{
- RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo));
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs));
}
#endif
}
_bindInfoExPrev = bindInfo;
_bindInfoExPrevIsDefined = true;
}
- int i;
+ unsigned i;
_mixerCoderCommon->ReInit();
- UInt32 packStreamIndex = 0, unpackStreamIndex = 0;
+ UInt32 packStreamIndex = 0;
+ UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex];
+ UInt32 unpackStreamIndex = unpackStreamIndexStart;
UInt32 coderIndex = 0;
// UInt32 coder2Index = 0;
@@ -229,7 +239,7 @@ HRESULT CDecoder::Decode(
if (setDecoderProperties)
{
const CByteBuffer &props = coderInfo.Props;
- size_t size = props.GetCapacity();
+ size_t size = props.Size();
if (size > 0xFFFFFFFF)
return E_NOTIMPL;
// if (size > 0)
@@ -257,22 +267,23 @@ HRESULT CDecoder::Decode(
decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
if (cryptoSetPassword)
{
- if (getTextPassword == 0)
- return E_FAIL;
+ isEncrypted = true;
+ if (!getTextPassword)
+ return E_NOTIMPL;
CMyComBSTR passwordBSTR;
RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR));
- CByteBuffer buffer;
passwordIsDefined = true;
- const UString password(passwordBSTR);
- const UInt32 sizeInBytes = password.Length() * 2;
- buffer.SetCapacity(sizeInBytes);
- for (int i = 0; i < password.Length(); i++)
+ size_t len = 0;
+ if (passwordBSTR)
+ len = MyStringLen((BSTR)passwordBSTR);
+ CByteBuffer buffer(len * 2);
+ for (size_t i = 0; i < len; i++)
{
- wchar_t c = password[i];
+ wchar_t c = passwordBSTR[i];
((Byte *)buffer)[i * 2] = (Byte)c;
((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
}
- RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes));
+ RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size()));
}
}
#endif
@@ -281,32 +292,30 @@ HRESULT CDecoder::Decode(
UInt32 numInStreams = (UInt32)coderInfo.NumInStreams;
UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams;
- CRecordVector<const UInt64 *> packSizesPointers;
- CRecordVector<const UInt64 *> unpackSizesPointers;
- packSizesPointers.Reserve(numInStreams);
- unpackSizesPointers.Reserve(numOutStreams);
+ CObjArray<UInt64> packSizes(numInStreams);
+ CObjArray<const UInt64 *> packSizesPointers(numInStreams);
+ CObjArray<const UInt64 *> unpackSizesPointers(numOutStreams);
UInt32 j;
+
for (j = 0; j < numOutStreams; j++, unpackStreamIndex++)
- unpackSizesPointers.Add(&folderInfo.UnpackSizes[unpackStreamIndex]);
+ unpackSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndex];
for (j = 0; j < numInStreams; j++, packStreamIndex++)
{
int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex);
if (bindPairIndex >= 0)
- packSizesPointers.Add(
- &folderInfo.UnpackSizes[(UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]);
+ packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + (UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex];
else
{
int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex);
if (index < 0)
- return E_FAIL;
- packSizesPointers.Add(&packSizes[index]);
+ return S_FALSE; // check it
+ packSizes[j] = packPositions[index + 1] - packPositions[index];
+ packSizesPointers[j] = &packSizes[j];
}
}
- _mixerCoderCommon->SetCoderInfo(i,
- &packSizesPointers.Front(),
- &unpackSizesPointers.Front());
+ _mixerCoderCommon->SetCoderInfo(i, packSizesPointers, unpackSizesPointers);
}
UInt32 mainCoder, temp;
bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp);
@@ -320,13 +329,15 @@ HRESULT CDecoder::Decode(
if (numCoders == 0)
return 0;
- CRecordVector<ISequentialInStream *> inStreamPointers;
- inStreamPointers.Reserve(inStreams.Size());
- for (i = 0; i < inStreams.Size(); i++)
- inStreamPointers.Add(inStreams[i]);
+ unsigned num = inStreams.Size();
+ CObjArray<ISequentialInStream *> inStreamPointers(num);
+ for (i = 0; i < num; i++)
+ inStreamPointers[i] = inStreams[i];
ISequentialOutStream *outStreamPointer = outStream;
- return _mixerCoder->Code(&inStreamPointers.Front(), NULL,
- inStreams.Size(), &outStreamPointer, NULL, 1, compressProgress);
+ return _mixerCoder->Code(
+ inStreamPointers, NULL, num,
+ &outStreamPointer, NULL, 1,
+ compressProgress);
}
}}
diff --git a/CPP/7zip/Archive/7z/7zDecode.h b/CPP/7zip/Archive/7z/7zDecode.h
index d8a424a3..1361772c 100755..100644
--- a/CPP/7zip/Archive/7z/7zDecode.h
+++ b/CPP/7zip/Archive/7z/7zDecode.h
@@ -14,7 +14,7 @@
#include "../../Common/CreateCoder.h"
-#include "7zItem.h"
+#include "7zIn.h"
namespace NArchive {
namespace N7z {
@@ -50,13 +50,10 @@ public:
DECL_EXTERNAL_CODECS_LOC_VARS
IInStream *inStream,
UInt64 startPos,
- const UInt64 *packSizes,
- const CFolder &folder,
+ const CFolders &folders, int folderIndex,
ISequentialOutStream *outStream,
ICompressProgressInfo *compressProgress
- #ifndef _NO_CRYPTO
- , ICryptoGetTextPassword *getTextPasswordSpec, bool &passwordIsDefined
- #endif
+ _7Z_DECODER_CRYPRO_VARS_DECL
#if !defined(_7ZIP_ST) && !defined(_SFX)
, bool mtMode, UInt32 numThreads
#endif
diff --git a/CPP/7zip/Archive/7z/7zEncode.cpp b/CPP/7zip/Archive/7z/7zEncode.cpp
index 614f9913..36ff5177 100755..100644
--- a/CPP/7zip/Archive/7z/7zEncode.cpp
+++ b/CPP/7zip/Archive/7z/7zEncode.cpp
@@ -23,30 +23,30 @@ static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindIn
const CRecordVector<CMethodId> decompressionMethods,
CFolder &folder)
{
- folder.Coders.Clear();
// bindInfo.CoderMethodIDs.Clear();
// folder.OutStreams.Clear();
- folder.PackStreams.Clear();
- folder.BindPairs.Clear();
- int i;
+ folder.BindPairs.SetSize(bindInfo.BindPairs.Size());
+ unsigned i;
for (i = 0; i < bindInfo.BindPairs.Size(); i++)
{
- CBindPair bindPair;
- bindPair.InIndex = bindInfo.BindPairs[i].InIndex;
- bindPair.OutIndex = bindInfo.BindPairs[i].OutIndex;
- folder.BindPairs.Add(bindPair);
+ CBindPair &bp = folder.BindPairs[i];
+ const NCoderMixer::CBindPair &mixerBp = bindInfo.BindPairs[i];
+ bp.InIndex = mixerBp.InIndex;
+ bp.OutIndex = mixerBp.OutIndex;
}
+ folder.Coders.SetSize(bindInfo.Coders.Size());
for (i = 0; i < bindInfo.Coders.Size(); i++)
{
- CCoderInfo coderInfo;
+ CCoderInfo &coderInfo = folder.Coders[i];
const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i];
coderInfo.NumInStreams = coderStreamsInfo.NumInStreams;
coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams;
coderInfo.MethodID = decompressionMethods[i];
- folder.Coders.Add(coderInfo);
+ // coderInfo.Props can be nonFree;
}
+ folder.PackStreams.SetSize(bindInfo.InStreams.Size());
for (i = 0; i < bindInfo.InStreams.Size(); i++)
- folder.PackStreams.Add(bindInfo.InStreams[i]);
+ folder.PackStreams[i] = bindInfo.InStreams[i];
}
static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, IUnknown *coder)
@@ -65,11 +65,10 @@ HRESULT CEncoder::CreateMixerCoder(
_mixerCoderSpec = new NCoderMixer::CCoderMixer2MT;
_mixerCoder = _mixerCoderSpec;
RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo));
- for (int i = 0; i < _options.Methods.Size(); i++)
+ FOR_VECTOR (i, _options.Methods)
{
const CMethodFull &methodFull = _options.Methods[i];
- _codersInfo.Add(CCoderInfo());
- CCoderInfo &encodingInfo = _codersInfo.Back();
+ CCoderInfo &encodingInfo = _codersInfo.AddNew();
encodingInfo.MethodID = methodFull.Id;
CMyComPtr<ICompressCoder> encoder;
CMyComPtr<ICompressCoder2> encoder2;
@@ -100,7 +99,7 @@ HRESULT CEncoder::CreateMixerCoder(
/*
CMyComPtr<ICryptoResetSalt> resetSalt;
encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt);
- if (resetSalt != NULL)
+ if (resetSalt)
{
resetSalt->ResetSalt();
}
@@ -111,7 +110,7 @@ HRESULT CEncoder::CreateMixerCoder(
encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
if (setCompressCodecsInfo)
{
- RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo));
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs));
}
#endif
@@ -120,10 +119,9 @@ HRESULT CEncoder::CreateMixerCoder(
if (cryptoSetPassword)
{
- CByteBuffer buffer;
- const UInt32 sizeInBytes = _options.Password.Length() * 2;
- buffer.SetCapacity(sizeInBytes);
- for (int i = 0; i < _options.Password.Length(); i++)
+ const UInt32 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;
@@ -145,13 +143,15 @@ HRESULT CEncoder::Encode(
ISequentialInStream *inStream,
const UInt64 *inStreamSize, const UInt64 *inSizeForReduce,
CFolder &folderItem,
+ CRecordVector<UInt64> &coderUnpackSizes,
+ UInt64 &unpackSize,
ISequentialOutStream *outStream,
CRecordVector<UInt64> &packSizes,
ICompressProgressInfo *compressProgress)
{
RINOK(EncoderConstr());
- if (_mixerCoderSpec == NULL)
+ if (!_mixerCoderSpec)
{
RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce));
}
@@ -161,13 +161,13 @@ HRESULT CEncoder::Encode(
CObjectVector<CInOutTempBuffer> inOutTempBuffers;
CObjectVector<CSequentialOutTempBufferImp *> tempBufferSpecs;
CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
- int numMethods = _bindInfo.Coders.Size();
- int i;
+ unsigned numMethods = _bindInfo.Coders.Size();
+ unsigned i;
for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
{
- inOutTempBuffers.Add(CInOutTempBuffer());
- inOutTempBuffers.Back().Create();
- inOutTempBuffers.Back().InitWriting();
+ CInOutTempBuffer &iotb = inOutTempBuffers.AddNew();
+ iotb.Create();
+ iotb.InitWriting();
}
for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
{
@@ -186,7 +186,7 @@ HRESULT CEncoder::Encode(
UInt32 mainCoderIndex, mainStreamIndex;
_bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex);
- if (inStreamSize != NULL)
+ if (inStreamSize)
{
CRecordVector<const UInt64 *> sizePointers;
for (UInt32 i = 0; i < _bindInfo.Coders[mainCoderIndex].NumInStreams; i++)
@@ -203,17 +203,24 @@ HRESULT CEncoder::Encode(
CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2;
CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
- CSequentialOutStreamSizeCount *outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
- CMyComPtr<ISequentialOutStream> outStreamSizeCount = outStreamSizeCountSpec;
+ CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL;
+ CMyComPtr<ISequentialOutStream> outStreamSizeCount;
inStreamSizeCountSpec->Init(inStream);
- outStreamSizeCountSpec->SetStream(outStream);
- outStreamSizeCountSpec->Init();
CRecordVector<ISequentialInStream *> inStreamPointers;
CRecordVector<ISequentialOutStream *> outStreamPointers;
inStreamPointers.Add(inStreamSizeCount);
- outStreamPointers.Add(outStreamSizeCount);
+
+ if (_bindInfo.OutStreams.Size() != 0)
+ {
+ outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
+ outStreamSizeCount = outStreamSizeCountSpec;
+ outStreamSizeCountSpec->SetStream(outStream);
+ outStreamSizeCountSpec->Init();
+ outStreamPointers.Add(outStreamSizeCount);
+ }
+
for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
outStreamPointers.Add(tempBuffers[i - 1]);
@@ -223,14 +230,14 @@ HRESULT CEncoder::Encode(
CMyComPtr<ICryptoResetInitVector> resetInitVector;
_mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector);
- if (resetInitVector != NULL)
+ if (resetInitVector)
{
resetInitVector->ResetInitVector();
}
CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
_mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
- if (writeCoderProperties != NULL)
+ if (writeCoderProperties)
{
CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
@@ -256,7 +263,8 @@ HRESULT CEncoder::Encode(
ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, folderItem);
- packSizes.Add(outStreamSizeCountSpec->GetSize());
+ if (_bindInfo.OutStreams.Size() != 0)
+ packSizes.Add(outStreamSizeCountSpec->GetSize());
for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
{
@@ -264,19 +272,23 @@ HRESULT CEncoder::Encode(
RINOK(inOutTempBuffer.WriteToStream(outStream));
packSizes.Add(inOutTempBuffer.GetDataSize());
}
-
+
+ unpackSize = 0;
for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++)
{
int binder = _bindInfo.FindBinderForInStream(
_bindReverseConverter->DestOutToSrcInMap[i]);
UInt64 streamSize;
if (binder < 0)
+ {
streamSize = inStreamSizeCountSpec->GetSize();
+ unpackSize = streamSize;
+ }
else
streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder);
- folderItem.UnpackSizes.Add(streamSize);
+ coderUnpackSizes.Add(streamSize);
}
- for (i = numMethods - 1; i >= 0; i--)
+ for (i = 0; i < numMethods; i++)
folderItem.Coders[numMethods - 1 - i].Props = _codersInfo[i].Props;
return S_OK;
}
@@ -323,7 +335,7 @@ HRESULT CEncoder::EncoderConstr()
{
UInt32 numInStreams = 0, numOutStreams = 0;
- int i;
+ unsigned i;
for (i = 0; i < _options.Methods.Size(); i++)
{
const CMethodFull &methodFull = _options.Methods[i];
@@ -339,7 +351,7 @@ HRESULT CEncoder::EncoderConstr()
bindPair.OutIndex = numOutStreams;
_bindInfo.BindPairs.Add(bindPair);
}
- else
+ else if (coderStreamsInfo.NumOutStreams != 0)
_bindInfo.OutStreams.Insert(0, numOutStreams);
for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++)
_bindInfo.OutStreams.Add(numOutStreams + j);
@@ -398,7 +410,7 @@ HRESULT CEncoder::EncoderConstr()
if (_options.PasswordIsDefined)
{
- int numCryptoStreams = _bindInfo.OutStreams.Size();
+ unsigned numCryptoStreams = _bindInfo.OutStreams.Size();
for (i = 0; i < numCryptoStreams; i++)
{
diff --git a/CPP/7zip/Archive/7z/7zEncode.h b/CPP/7zip/Archive/7z/7zEncode.h
index 4909a6e8..8e20bdb5 100755..100644
--- a/CPP/7zip/Archive/7z/7zEncode.h
+++ b/CPP/7zip/Archive/7z/7zEncode.h
@@ -45,6 +45,8 @@ public:
ISequentialInStream *inStream,
const UInt64 *inStreamSize, const UInt64 *inSizeForReduce,
CFolder &folderItem,
+ CRecordVector<UInt64> &coderUnpackSizes,
+ UInt64 &unpackSize,
ISequentialOutStream *outStream,
CRecordVector<UInt64> &packSizes,
ICompressProgressInfo *compressProgress);
diff --git a/CPP/7zip/Archive/7z/7zExtract.cpp b/CPP/7zip/Archive/7z/7zExtract.cpp
index d55f38e1..6d2c5b06 100755..100644
--- a/CPP/7zip/Archive/7z/7zExtract.cpp
+++ b/CPP/7zip/Archive/7z/7zExtract.cpp
@@ -37,8 +37,8 @@ struct CExtractFolderInfo
{
if (fileIndex != kNumNoIndex)
{
- ExtractStatuses.Reserve(1);
- ExtractStatuses.Add(true);
+ ExtractStatuses.ClearAndSetSize(1);
+ ExtractStatuses[0] = true;
}
};
};
@@ -51,7 +51,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
UInt64 importantTotalUnpacked = 0;
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems =
#ifdef _7Z_VOL
@@ -67,7 +67,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if(_volumes.Size() != 1)
return E_FAIL;
const CVolume &volume = _volumes.Front();
- const CArchiveDatabaseEx &_db = volume.Database;
+ const CDbEx &_db = volume.Database;
IInStream *_inStream = volume.Stream;
*/
@@ -86,10 +86,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
int volumeIndex = ref.VolumeIndex;
const CVolume &volume = _volumes[volumeIndex];
- const CArchiveDatabaseEx &db = volume.Database;
+ const CDbEx &db = volume.Database;
UInt32 fileIndex = ref.ItemIndex;
#else
- const CArchiveDatabaseEx &db = _db;
+ const CDbEx &db = _db;
UInt32 fileIndex = ref2Index;
#endif
@@ -115,8 +115,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
volumeIndex,
#endif
kNumNoIndex, folderIndex));
- const CFolder &folderInfo = db.Folders[folderIndex];
- UInt64 unpackSize = folderInfo.GetUnpackSize();
+ UInt64 unpackSize = db.GetFolderUnpackSize(folderIndex);
importantTotalUnpacked += unpackSize;
extractFolderInfoVector.Back().UnpackSize = unpackSize;
}
@@ -156,7 +155,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
- for (int i = 0;; i++, totalUnpacked += curUnpacked, totalPacked += curPacked)
+ for (unsigned i = 0;; i++, totalUnpacked += curUnpacked, totalPacked += curPacked)
{
lps->OutSize = totalUnpacked;
lps->InSize = totalPacked;
@@ -174,9 +173,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
#ifdef _7Z_VOL
const CVolume &volume = _volumes[efi.VolumeIndex];
- const CArchiveDatabaseEx &db = volume.Database;
+ const CDbEx &db = volume.Database;
#else
- const CArchiveDatabaseEx &db = _db;
+ const CDbEx &db = _db;
#endif
CNum startIndex;
@@ -200,13 +199,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
continue;
CNum folderIndex = efi.FolderIndex;
- const CFolder &folderInfo = db.Folders[folderIndex];
-
curPacked = _db.GetFolderFullPackSize(folderIndex);
- CNum packStreamIndex = db.FolderStartPackStreamIndex[folderIndex];
- UInt64 folderStartPackPos = db.GetFolderStreamPos(folderIndex, 0);
-
#ifndef _NO_CRYPTO
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
if (extractCallback)
@@ -216,26 +210,24 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
try
{
#ifndef _NO_CRYPTO
- bool passwordIsDefined;
+ bool isEncrypted = false;
+ bool passwordIsDefined = false;
#endif
HRESULT result = decoder.Decode(
EXTERNAL_CODECS_VARS
#ifdef _7Z_VOL
- volume.Stream,
+ volume.Stream,
#else
- _inStream,
+ _inStream,
#endif
- folderStartPackPos,
- &db.PackSizes[packStreamIndex],
- folderInfo,
+ db.ArcInfo.DataStartPosition,
+ db, folderIndex,
outStream,
progress
- #ifndef _NO_CRYPTO
- , getTextPassword, passwordIsDefined
- #endif
+ _7Z_DECODER_CRYPRO_VARS
#if !defined(_7ZIP_ST) && !defined(_SFX)
- , true, _numThreads
+ , true, _numThreads
#endif
);
@@ -246,7 +238,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
if (result == E_NOTIMPL)
{
- RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kUnSupportedMethod));
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kUnsupportedMethod));
continue;
}
if (result != S_OK)
diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.cpp b/CPP/7zip/Archive/7z/7zFolderInStream.cpp
index edd276bc..3f420a51 100755..100644
--- a/CPP/7zip/Archive/7z/7zFolderInStream.cpp
+++ b/CPP/7zip/Archive/7z/7zFolderInStream.cpp
@@ -106,8 +106,8 @@ STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSiz
STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
{
*value = 0;
- int index2 = (int)subStream;
- if (index2 < 0 || subStream > Sizes.Size())
+ unsigned index2 = (unsigned)subStream;
+ if (subStream > Sizes.Size())
return E_FAIL;
if (index2 < Sizes.Size())
{
diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.h b/CPP/7zip/Archive/7z/7zFolderInStream.h
index 6df3672a..4ed4b2dd 100755..100644
--- a/CPP/7zip/Archive/7z/7zFolderInStream.h
+++ b/CPP/7zip/Archive/7z/7zFolderInStream.h
@@ -47,7 +47,7 @@ public:
UInt64 GetFullSize() const
{
UInt64 size = 0;
- for (int i = 0; i < Sizes.Size(); i++)
+ FOR_VECTOR (i, Sizes)
size += Sizes[i];
return size;
}
diff --git a/CPP/7zip/Archive/7z/7zFolderOutStream.cpp b/CPP/7zip/Archive/7z/7zFolderOutStream.cpp
index 22c4600e..847f65bf 100755..100644
--- a/CPP/7zip/Archive/7z/7zFolderOutStream.cpp
+++ b/CPP/7zip/Archive/7z/7zFolderOutStream.cpp
@@ -14,7 +14,7 @@ CFolderOutStream::CFolderOutStream()
}
HRESULT CFolderOutStream::Init(
- const CArchiveDatabaseEx *db,
+ const CDbEx *db,
UInt32 ref2Offset, UInt32 startIndex,
const CBoolVector *extractStatuses,
IArchiveExtractCallback *extractCallback,
diff --git a/CPP/7zip/Archive/7z/7zFolderOutStream.h b/CPP/7zip/Archive/7z/7zFolderOutStream.h
index f9bb1af4..cc2d7734 100755..100644
--- a/CPP/7zip/Archive/7z/7zFolderOutStream.h
+++ b/CPP/7zip/Archive/7z/7zFolderOutStream.h
@@ -19,12 +19,12 @@ class CFolderOutStream:
{
COutStreamWithCRC *_crcStreamSpec;
CMyComPtr<ISequentialOutStream> _crcStream;
- const CArchiveDatabaseEx *_db;
+ const CDbEx *_db;
const CBoolVector *_extractStatuses;
CMyComPtr<IArchiveExtractCallback> _extractCallback;
UInt32 _ref2Offset;
UInt32 _startIndex;
- int _currentIndex;
+ unsigned _currentIndex;
bool _testMode;
bool _checkCrc;
bool _fileIsOpen;
@@ -43,7 +43,7 @@ public:
STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
HRESULT Init(
- const CArchiveDatabaseEx *db,
+ const CDbEx *db,
UInt32 ref2Offset, UInt32 startIndex,
const CBoolVector *extractStatuses,
IArchiveExtractCallback *extractCallback,
diff --git a/CPP/7zip/Archive/7z/7zHandler.cpp b/CPP/7zip/Archive/7z/7zHandler.cpp
index 93d4f51e..82983419 100755..100644
--- a/CPP/7zip/Archive/7z/7zHandler.cpp
+++ b/CPP/7zip/Archive/7z/7zHandler.cpp
@@ -23,6 +23,7 @@
#endif
using namespace NWindows;
+using namespace NCOM;
namespace NArchive {
namespace N7z {
@@ -30,6 +31,7 @@ namespace N7z {
CHandler::CHandler()
{
#ifndef _NO_CRYPTO
+ _isEncrypted = false;
_passwordIsDefined = false;
#endif
@@ -49,11 +51,12 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
#ifdef _SFX
-IMP_IInArchive_ArcProps_NO
+IMP_IInArchive_ArcProps_NO_Table
-STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 * /* numProperties */)
+STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps)
{
- return E_NOTIMPL;
+ *numProps = 0;
+ return S_OK;
}
STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,
@@ -62,156 +65,473 @@ STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,
return E_NOTIMPL;
}
-
#else
-static const STATPROPSTG kArcProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidSolid, VT_BOOL},
- { NULL, kpidNumBlocks, VT_UI4},
- { NULL, kpidPhySize, VT_UI8},
- { NULL, kpidHeadersSize, VT_UI8},
- { NULL, kpidOffset, VT_UI8}
+ kpidHeadersSize,
+ kpidMethod,
+ kpidSolid,
+ kpidNumBlocks
+ // , kpidIsTree
};
-static inline wchar_t GetHex(Byte value)
+IMP_IInArchive_ArcProps
+
+static inline char GetHex(unsigned value)
{
- return (wchar_t)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+ return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
}
-static UString ConvertMethodIdToString(UInt64 id)
+static unsigned ConvertMethodIdToString_Back(char *s, UInt64 id)
{
- wchar_t s[32];
- int len = 32;
- s[--len] = 0;
+ int len = 0;
do
{
- s[--len] = GetHex((Byte)id & 0xF); id >>= 4;
- s[--len] = GetHex((Byte)id & 0xF); id >>= 4;
+ s[--len] = GetHex((unsigned)id & 0xF); id >>= 4;
+ s[--len] = GetHex((unsigned)id & 0xF); id >>= 4;
}
while (id != 0);
- return s + len;
+ 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)
+{
+ UString methodName;
+ FindMethod(EXTERNAL_CODECS_VARS id, methodName);
+ if (methodName.IsEmpty())
+ {
+ for (unsigned i = 0; i < methodName.Len(); i++)
+ if (methodName[i] >= 0x80)
+ {
+ methodName.Empty();
+ break;
+ }
+ }
+ if (methodName.IsEmpty())
+ ConvertMethodIdToString(s, id);
+ else
+ for (unsigned i = 0; i < methodName.Len(); i++)
+ s += (char)methodName[i];
+}
+
+#endif
+
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
+ #ifndef _SFX
COM_TRY_BEGIN
+ #endif
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
+ #ifndef _SFX
case kpidMethod:
{
- UString resString;
- CRecordVector<UInt64> ids;
- int i;
- for (i = 0; i < _db.Folders.Size(); i++)
+ AString s;
+ const CParsedMethods &pm = _db.ParsedMethods;
+ FOR_VECTOR (i, pm.IDs)
{
- const CFolder &f = _db.Folders[i];
- for (int j = f.Coders.Size() - 1; j >= 0; j--)
- ids.AddToUniqueSorted(f.Coders[j].MethodID);
- }
-
- for (i = 0; i < ids.Size(); i++)
- {
- UInt64 id = ids[i];
- UString methodName;
- /* bool methodIsKnown = */ FindMethod(EXTERNAL_CODECS_VARS id, methodName);
- if (methodName.IsEmpty())
- methodName = ConvertMethodIdToString(id);
- if (!resString.IsEmpty())
- resString += L' ';
- resString += methodName;
+ UInt64 id = pm.IDs[i];
+ if (!s.IsEmpty())
+ s += ' ';
+ 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 = resString;
+ prop = s;
break;
}
case kpidSolid: prop = _db.IsSolid(); break;
- case kpidNumBlocks: prop = (UInt32)_db.Folders.Size(); break;
+ case kpidNumBlocks: prop = (UInt32)_db.NumFolders; break;
case kpidHeadersSize: prop = _db.HeadersSize; break;
case kpidPhySize: prop = _db.PhySize; break;
- case kpidOffset: if (_db.ArchiveInfo.StartPosition != 0) prop = _db.ArchiveInfo.StartPosition; break;
+ 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;
+ }
}
prop.Detach(value);
return S_OK;
+ #ifndef _SFX
COM_TRY_END
+ #endif
}
-IMP_IInArchive_ArcProps
-
-#endif
-
-static void SetPropFromUInt64Def(CUInt64DefVector &v, int index, NCOM::CPropVariant &prop)
+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--)
{
- FILETIME ft;
- ft.dwLowDateTime = (DWORD)value;
- ft.dwHighDateTime = (DWORD)(value >> 32);
- prop = ft;
+ 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;
}
-#ifndef _SFX
+STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps)
+{
+ *numProps = 0;
+ return S_OK;
+}
-static UString ConvertUInt32ToString(UInt32 value)
+STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)
{
- wchar_t buffer[32];
- ConvertUInt64ToString(value, buffer);
- return buffer;
+ *name = NULL;
+ *propID = kpidNtSecure;
+ return S_OK;
}
-static UString GetStringForSizeValue(UInt32 value)
+STDMETHODIMP CHandler::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)
{
- for (int i = 31; i >= 0; i--)
- if ((UInt32(1) << i) == value)
- return ConvertUInt32ToString(i);
- UString result;
- if (value % (1 << 20) == 0)
- {
- result += ConvertUInt32ToString(value >> 20);
- result += L"m";
- }
- else if (value % (1 << 10) == 0)
+ /*
+ 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)
{
- result += ConvertUInt32ToString(value >> 10);
- result += L"k";
+ *data = (void *)_db.GetName(index);
+ if (*data)
+ {
+ *dataSize = (UInt32)((_db.NameOffsets[index + 1] - _db.NameOffsets[index]) * 2);
+ *propType = NPropDataType::kUtf16z;
+ }
+ return S_OK;
}
- else
+ /*
+ if (propID == kpidNtSecure)
{
- result += ConvertUInt32ToString(value);
- result += L"b";
+ 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 result;
+ */
+ return S_OK;
}
-static inline void AddHexToString(UString &res, Byte value)
-{
- res += GetHex((Byte)(value >> 4));
- res += GetHex((Byte)(value & 0xF));
-}
+#ifndef _SFX
-static void AddProp32(UString &s, const wchar_t *name, UInt32 v)
+HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const
{
- s += name;
- s += ConvertUInt32ToString(v);
-}
+ 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;
-#endif
-
-bool CHandler::IsEncrypted(UInt32 index2) const
-{
- CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
- if (folderIndex != kNumNoIndex)
- return _db.Folders[folderIndex].IsEncrypted();
- 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);
+
+ // 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);
+ 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 p = props[0];
+ if ((p & 1) == 0)
+ ConvertUInt32ToString((UInt32)((p >> 1) + 12), s);
+ else
+ GetStringForSizeValue(s, 3 << ((p >> 1) + 11));
+ }
+ }
+ else if (id == k_PPMD)
+ {
+ name = "PPMD";
+ if (propsSize == 5)
+ {
+ Byte order = *props;
+ char *dest = s;
+ *dest++ = 'o';
+ ConvertUInt32ToString(order, dest);
+ dest += MyStringLen(dest);
+ dest = MyStpCpy(dest, ":mem");
+ GetStringForSizeValue(dest, GetUi32(props + 1));
+ }
+ }
+ else if (id == k_Delta)
+ {
+ name = "Delta";
+ if (propsSize == 1)
+ ConvertUInt32ToString((UInt32)props[0] + 1, s);
+ }
+ else if (id == k_BCJ2) name = "BCJ2";
+ else if (id == k_BCJ) name = "BCJ";
+ else if (id == k_AES)
+ {
+ name = "7zAES";
+ if (propsSize >= 1)
+ {
+ Byte firstByte = props[0];
+ UInt32 numCyclesPower = firstByte & 0x3F;
+ ConvertUInt32ToString(numCyclesPower, s);
+ }
+ }
+ }
+
+ if (name)
+ {
+ unsigned nameLen = MyStringLen(name);
+ unsigned propsLen = MyStringLen(s);
+ unsigned totalLen = nameLen + propsLen;
+ if (propsLen != 0)
+ totalLen++;
+ if (needSpace)
+ totalLen++;
+ if (totalLen + 5 >= pos)
+ break;
+ pos -= totalLen;
+ MyStringCopy(temp + pos, name);
+ if (propsLen != 0)
+ {
+ char *dest = temp + pos + nameLen;
+ *dest++ = ':';
+ MyStringCopy(dest, s);
+ }
+ if (needSpace)
+ temp[pos + totalLen - 1] = ' ';
+ }
+ else
+ {
+ UString methodName;
+ FindMethod(EXTERNAL_CODECS_VARS id64, methodName);
+ if (methodName.IsEmpty())
+ {
+ for (unsigned j = 0; j < methodName.Len(); j++)
+ if (methodName[j] >= 0x80)
+ {
+ methodName.Empty();
+ break;
+ }
+ }
+ 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] = (char)methodName[i];
+ }
+ }
+ }
+ if (numCoders != 0 && pos >= 4)
+ {
+ temp[--pos] = ' ';
+ temp[--pos] = '.';
+ temp[--pos] = '.';
+ temp[--pos] = '.';
+ }
+ return PropVarEm_Set_Str(prop, temp + pos);
+ // }
}
-STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+#endif
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
- COM_TRY_BEGIN
- NCOM::CPropVariant prop;
+ PropVariant_Clear(value);
+ // COM_TRY_BEGIN
+ // NCOM::CPropVariant prop;
/*
const CRef2 &ref2 = _refs[index];
@@ -225,14 +545,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
switch(propID)
{
- case kpidPath:
- if (!item.Name.IsEmpty())
- prop = NItemName::GetOSName(item.Name);
- break;
- case kpidIsDir: prop = item.IsDir; break;
+ case kpidIsDir: PropVarEm_Set_Bool(value, item.IsDir); break;
case kpidSize:
{
- prop = item.Size;
+ PropVarEm_Set_UInt64(value, item.Size);
// prop = ref2.Size;
break;
}
@@ -244,130 +560,49 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
if (folderIndex != kNumNoIndex)
{
if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2)
- prop = _db.GetFolderFullPackSize(folderIndex);
+ PropVarEm_Set_UInt64(value, _db.GetFolderFullPackSize(folderIndex));
/*
else
- prop = (UInt64)0;
+ PropVarEm_Set_UInt64(value, 0);
*/
}
else
- prop = (UInt64)0;
+ PropVarEm_Set_UInt64(value, 0);
}
break;
}
- case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) prop = v; break; }
- case kpidCTime: SetPropFromUInt64Def(_db.CTime, index2, prop); break;
- case kpidATime: SetPropFromUInt64Def(_db.ATime, index2, prop); break;
- case kpidMTime: SetPropFromUInt64Def(_db.MTime, index2, prop); break;
- case kpidAttrib: if (item.AttribDefined) prop = item.Attrib; break;
- case kpidCRC: if (item.CrcDefined) prop = item.Crc; break;
- case kpidEncrypted: prop = IsEncrypted(index2); break;
- case kpidIsAnti: prop = _db.IsItemAnti(index2); break;
- #ifndef _SFX
- case kpidMethod:
+ // 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 (item.AttribDefined) PropVarEm_Set_UInt32(value, item.Attrib); 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:
{
- CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
- if (folderIndex != kNumNoIndex)
+ int id = _db.SecureIDs[index];
+ size_t offs = _db.SecureOffsets[id];
+ size_t size = _db.SecureOffsets[id + 1] - offs;
+ if (size >= 0)
{
- const CFolder &folderInfo = _db.Folders[folderIndex];
- UString methodsString;
- for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
- {
- const CCoderInfo &coder = folderInfo.Coders[i];
- if (!methodsString.IsEmpty())
- methodsString += L' ';
-
- UString methodName, propsString;
- bool methodIsKnown = FindMethod(
- EXTERNAL_CODECS_VARS
- coder.MethodID, methodName);
-
- if (!methodIsKnown)
- methodsString += ConvertMethodIdToString(coder.MethodID);
- else
- {
- methodsString += methodName;
- if (coder.MethodID == k_Delta && coder.Props.GetCapacity() == 1)
- propsString = ConvertUInt32ToString((UInt32)coder.Props[0] + 1);
- else if (coder.MethodID == k_LZMA && coder.Props.GetCapacity() == 5)
- {
- UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1);
- propsString = GetStringForSizeValue(dicSize);
- UInt32 d = coder.Props[0];
- UInt32 lc = d % 9;
- d /= 9;
- UInt32 pb = d / 5;
- UInt32 lp = d % 5;
- if (lc != 3) AddProp32(propsString, L":lc", lc);
- if (lp != 0) AddProp32(propsString, L":lp", lp);
- if (pb != 2) AddProp32(propsString, L":pb", pb);
- }
- else if (coder.MethodID == k_LZMA2 && coder.Props.GetCapacity() == 1)
- {
- Byte p = coder.Props[0];
- UInt32 dicSize = (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11));
- propsString = GetStringForSizeValue(dicSize);
- }
- else if (coder.MethodID == k_PPMD && coder.Props.GetCapacity() == 5)
- {
- Byte order = *(const Byte *)coder.Props;
- propsString = L'o';
- propsString += ConvertUInt32ToString(order);
- propsString += L":mem";
- UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1);
- propsString += GetStringForSizeValue(dicSize);
- }
- else if (coder.MethodID == k_AES && coder.Props.GetCapacity() >= 1)
- {
- const Byte *data = (const Byte *)coder.Props;
- Byte firstByte = *data++;
- UInt32 numCyclesPower = firstByte & 0x3F;
- propsString = ConvertUInt32ToString(numCyclesPower);
- /*
- if ((firstByte & 0xC0) != 0)
- {
- UInt32 saltSize = (firstByte >> 7) & 1;
- UInt32 ivSize = (firstByte >> 6) & 1;
- if (coder.Props.GetCapacity() >= 2)
- {
- Byte secondByte = *data++;
- saltSize += (secondByte >> 4);
- ivSize += (secondByte & 0x0F);
- }
- }
- */
- }
- }
- if (!propsString.IsEmpty())
- {
- methodsString += L':';
- methodsString += propsString;
- }
- else if (coder.Props.GetCapacity() > 0)
- {
- methodsString += L":[";
- for (size_t bi = 0; bi < coder.Props.GetCapacity(); bi++)
- {
- if (bi > 5 && bi + 1 < coder.Props.GetCapacity())
- {
- methodsString += L"..";
- break;
- }
- else
- AddHexToString(methodsString, coder.Props[bi]);
- }
- methodsString += L']';
- }
- }
- prop = methodsString;
+ prop.SetBlob(_db.SecureBuf + offs, (ULONG)size);
}
+ break;
}
- break;
+ */
+
+ case kpidPath: return _db.GetPath(index, value);
+ #ifndef _SFX
+ case kpidMethod: return SetMethodToProp(_db.FileIndexToFolderIndexMap[index2], value);
case kpidBlock:
{
CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
if (folderIndex != kNumNoIndex)
- prop = (UInt32)folderIndex;
+ PropVarEm_Set_UInt32(value, (UInt32)folderIndex);
}
break;
case kpidPackedSize0:
@@ -376,6 +611,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
case kpidPackedSize3:
case kpidPackedSize4:
{
+ /*
CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
if (folderIndex != kNumNoIndex)
{
@@ -390,13 +626,14 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
}
else
prop = (UInt64)0;
+ */
}
break;
#endif
}
- prop.Detach(value);
+ // prop.Detach(value);
return S_OK;
- COM_TRY_END
+ // COM_TRY_END
}
STDMETHODIMP CHandler::Open(IInStream *stream,
@@ -408,6 +645,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
#ifndef _SFX
_fileInfoPopIDs.Clear();
#endif
+
try
{
CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
@@ -415,31 +653,30 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
#ifndef _NO_CRYPTO
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
if (openArchiveCallback)
- {
- openArchiveCallbackTemp.QueryInterface(
- IID_ICryptoGetTextPassword, &getTextPassword);
- }
+ openArchiveCallbackTemp.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
#endif
+
CInArchive archive;
+ _db.IsArc = false;
RINOK(archive.Open(stream, maxCheckStartPosition));
- #ifndef _NO_CRYPTO
- _passwordIsDefined = false;
- UString password;
- #endif
+ _db.IsArc = true;
+
HRESULT result = archive.ReadDatabase(
- EXTERNAL_CODECS_VARS
- _db
- #ifndef _NO_CRYPTO
- , getTextPassword, _passwordIsDefined
- #endif
- );
+ EXTERNAL_CODECS_VARS
+ _db
+ #ifndef _NO_CRYPTO
+ , getTextPassword, _isEncrypted, _passwordIsDefined
+ #endif
+ );
RINOK(result);
- _db.Fill();
+
_inStream = stream;
}
catch(...)
{
Close();
+ // return E_INVALIDARG;
+ // we must return out_of_memory here
return S_FALSE;
}
// _inStream = stream;
@@ -455,6 +692,10 @@ STDMETHODIMP CHandler::Close()
COM_TRY_BEGIN
_inStream.Release();
_db.Clear();
+ #ifndef _NO_CRYPTO
+ _isEncrypted = false;
+ _passwordIsDefined = false;
+ #endif
return S_OK;
COM_TRY_END
}
@@ -462,16 +703,16 @@ STDMETHODIMP CHandler::Close()
#ifdef __7Z_SET_PROPERTIES
#ifdef EXTRACT_ONLY
-STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
{
COM_TRY_BEGIN
const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
_numThreads = numProcessors;
- for (int i = 0; i < numProperties; i++)
+ for (UInt32 i = 0; i < numProps; i++)
{
UString name = names[i];
- name.MakeUpper();
+ name.MakeLower_Ascii();
if (name.IsEmpty())
return E_INVALIDARG;
const PROPVARIANT &value = values[i];
@@ -479,9 +720,9 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v
int index = ParseStringToUInt32(name, number);
if (index == 0)
{
- if(name.Left(2).CompareNoCase(L"MT") == 0)
+ if (name.IsPrefixedBy(L"mt"))
{
- RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
+ RINOK(ParseMtProp(name.Ptr(2), value, numProcessors, _numThreads));
continue;
}
else
diff --git a/CPP/7zip/Archive/7z/7zHandler.h b/CPP/7zip/Archive/7z/7zHandler.h
index 247b55f7..dad943e0 100755..100644
--- a/CPP/7zip/Archive/7z/7zHandler.h
+++ b/CPP/7zip/Archive/7z/7zHandler.h
@@ -58,10 +58,11 @@ public:
bool _compressHeaders;
bool _encryptHeadersSpecified;
bool _encryptHeaders;
+ // bool _useParents; 9.26
- bool WriteCTime;
- bool WriteATime;
- bool WriteMTime;
+ CBoolPair Write_CTime;
+ CBoolPair Write_ATime;
+ CBoolPair Write_MTime;
bool _volumeMode;
@@ -85,10 +86,8 @@ public:
#endif
class CHandler:
- #ifndef EXTRACT_ONLY
- public COutHandler,
- #endif
public IInArchive,
+ public IArchiveGetRawProps,
#ifdef __7Z_SET_PROPERTIES
public ISetProperties,
#endif
@@ -97,9 +96,13 @@ class CHandler:
#endif
PUBLIC_ISetCompressCodecsInfo
public CMyUnknownImp
+ #ifndef EXTRACT_ONLY
+ , public COutHandler
+ #endif
{
public:
MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ // MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps)
#ifdef __7Z_SET_PROPERTIES
MY_QUERYINTERFACE_ENTRY(ISetProperties)
#endif
@@ -111,9 +114,10 @@ public:
MY_ADDREF_RELEASE
INTERFACE_IInArchive(;)
+ INTERFACE_IArchiveGetRawProps(;)
#ifdef __7Z_SET_PROPERTIES
- STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties);
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps);
#endif
#ifndef EXTRACT_ONLY
@@ -126,8 +130,9 @@ public:
private:
CMyComPtr<IInStream> _inStream;
- NArchive::N7z::CArchiveDatabaseEx _db;
+ NArchive::N7z::CDbEx _db;
#ifndef _NO_CRYPTO
+ bool _isEncrypted;
bool _passwordIsDefined;
#endif
@@ -156,11 +161,13 @@ private:
#endif
- bool IsEncrypted(UInt32 index2) const;
+ bool IsFolderEncrypted(CNum folderIndex) const;
#ifndef _SFX
CRecordVector<UInt64> _fileInfoPopIDs;
void FillPopIDs();
+ void AddMethodName(AString &s, UInt64 id);
+ HRESULT SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const;
#endif
diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp
index dd73ee84..2f6a4c37 100755..100644
--- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp
+++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp
@@ -4,6 +4,7 @@
#include "../../../Common/ComTry.h"
#include "../../../Common/StringToInt.h"
+#include "../../../Common/Wildcard.h"
#include "../Common/ItemNameUtils.h"
#include "../Common/ParseProperties.h"
@@ -18,7 +19,7 @@ namespace NArchive {
namespace N7z {
static const wchar_t *k_LZMA_Name = L"LZMA";
-static const wchar_t *kDefaultMethodName = k_LZMA_Name;
+static const wchar_t *kDefaultMethodName = L"LZMA2";
static const wchar_t *k_Copy_Name = L"Copy";
static const wchar_t *k_MatchFinder_ForHeaders = L"BT2";
@@ -67,9 +68,9 @@ HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod)
void CHandler::AddDefaultMethod()
{
- for (int i = 0; i < _methods.Size(); i++)
+ FOR_VECTOR (i, _methods)
{
- UString &methodName = _methods[0].MethodName;
+ UString &methodName = _methods[i].MethodName;
if (methodName.IsEmpty())
methodName = kDefaultMethodName;
}
@@ -95,7 +96,7 @@ HRESULT CHandler::SetMainMethod(
const UInt64 kSolidBytes_Max = ((UInt64)1 << 32) - 1;
bool needSolid = false;
- for (int i = 0; i < methods.Size(); i++)
+ FOR_VECTOR (i, methods)
{
COneMethodInfo &oneMethodInfo = methods[i];
SetGlobalLevelAndThreads(oneMethodInfo
@@ -139,12 +140,10 @@ HRESULT CHandler::SetMainMethod(
return S_OK;
}
-static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, bool writeTime, PROPID propID, UInt64 &ft, bool &ftDefined)
+static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, UInt64 &ft, bool &ftDefined)
{
- ft = 0;
- ftDefined = false;
- if (!writeTime)
- return S_OK;
+ // ft = 0;
+ // ftDefined = false;
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(index, propID, &prop));
if (prop.vt == VT_FILETIME)
@@ -154,15 +153,87 @@ static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, bool w
}
else if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
+ else
+ {
+ ft = 0;
+ ftDefined = false;
+ }
return S_OK;
}
+/*
+
+#ifdef _WIN32
+static const wchar_t kDirDelimiter1 = L'\\';
+#endif
+static const wchar_t kDirDelimiter2 = L'/';
+
+static inline bool IsCharDirLimiter(wchar_t c)
+{
+ return (
+ #ifdef _WIN32
+ c == kDirDelimiter1 ||
+ #endif
+ c == kDirDelimiter2);
+}
+
+static int FillSortIndex(CObjectVector<CTreeFolder> &treeFolders, int cur, int curSortIndex)
+{
+ CTreeFolder &tf = treeFolders[cur];
+ tf.SortIndex = curSortIndex++;
+ for (int i = 0; i < tf.SubFolders.Size(); i++)
+ curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex);
+ tf.SortIndexEnd = curSortIndex;
+ return curSortIndex;
+}
+
+static int FindSubFolder(const CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name, int &insertPos)
+{
+ const CIntVector &subFolders = treeFolders[cur].SubFolders;
+ int left = 0, right = subFolders.Size();
+ insertPos = -1;
+ for (;;)
+ {
+ if (left == right)
+ {
+ insertPos = left;
+ return -1;
+ }
+ int mid = (left + right) / 2;
+ int midFolder = subFolders[mid];
+ int compare = CompareFileNames(name, treeFolders[midFolder].Name);
+ if (compare == 0)
+ return midFolder;
+ if (compare < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+}
+
+static int AddFolder(CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name)
+{
+ int insertPos;
+ int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos);
+ if (folderIndex < 0)
+ {
+ folderIndex = treeFolders.Size();
+ CTreeFolder &newFolder = treeFolders.AddNew();
+ newFolder.Parent = cur;
+ newFolder.Name = name;
+ treeFolders[cur].SubFolders.Insert(insertPos, folderIndex);
+ }
+ // else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234;
+ return folderIndex;
+}
+*/
+
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
IArchiveUpdateCallback *updateCallback)
{
COM_TRY_BEGIN
- const CArchiveDatabaseEx *db = 0;
+ const CDbEx *db = 0;
#ifdef _7Z_VOL
if (_volumes.Size() > 1)
return E_FAIL;
@@ -177,8 +248,35 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
db = &_db;
#endif
+ /*
+ CMyComPtr<IArchiveGetRawProps> getRawProps;
+ updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps);
+
+ CUniqBlocks secureBlocks;
+ secureBlocks.AddUniq(NULL, 0);
+
+ CObjectVector<CTreeFolder> treeFolders;
+ {
+ CTreeFolder folder;
+ folder.Parent = -1;
+ treeFolders.Add(folder);
+ }
+ */
+
CObjectVector<CUpdateItem> updateItems;
-
+
+ bool need_CTime = (Write_CTime.Def && Write_CTime.Val);
+ bool need_ATime = (Write_ATime.Def && Write_ATime.Val);
+ bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def);
+ if (db)
+ {
+ 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();
+ }
+
+ UString s;
+
for (UInt32 i = 0; i < numItems; i++)
{
Int32 newData, newProps;
@@ -194,24 +292,35 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
ui.IsAnti = false;
ui.Size = 0;
+ UString name;
+ // bool isAltStream = false;
if (ui.IndexInArchive != -1)
{
- if (db == 0 || ui.IndexInArchive >= db->Files.Size())
+ if (db == 0 || (unsigned)ui.IndexInArchive >= db->Files.Size())
return E_INVALIDARG;
const CFileItem &fi = db->Files[ui.IndexInArchive];
- ui.Name = fi.Name;
+ if (!ui.NewProps)
+ {
+ NCOM::CPropVariant prop;
+ RINOK(_db.GetPath(ui.IndexInArchive, &prop));
+ if (prop.vt == VT_BSTR)
+ name = prop.bstrVal;
+ }
ui.IsDir = fi.IsDir;
ui.Size = fi.Size;
+ // isAltStream = fi.IsAltStream;
ui.IsAnti = db->IsItemAnti(ui.IndexInArchive);
- ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime);
- ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime);
- ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime);
+ if (!ui.NewProps)
+ {
+ ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime);
+ ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime);
+ ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime);
+ }
}
if (ui.NewProps)
{
- bool nameIsDefined;
bool folderStatusIsDefined;
{
NCOM::CPropVariant prop;
@@ -228,21 +337,35 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
}
// we need MTime to sort files.
- RINOK(GetTime(updateCallback, i, WriteCTime, kpidCTime, ui.CTime, ui.CTimeDefined));
- RINOK(GetTime(updateCallback, i, WriteATime, kpidATime, ui.ATime, ui.ATimeDefined));
- RINOK(GetTime(updateCallback, i, true, kpidMTime, ui.MTime, ui.MTimeDefined));
+ 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)
- nameIsDefined = false;
+ {
+ }
else if (prop.vt != VT_BSTR)
return E_INVALIDARG;
else
{
- ui.Name = NItemName::MakeLegalName(prop.bstrVal);
- nameIsDefined = true;
+ name = NItemName::MakeLegalName(prop.bstrVal);
}
}
{
@@ -270,6 +393,19 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
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;
@@ -284,6 +420,80 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
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)
{
@@ -298,6 +508,16 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
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, _methods
@@ -317,17 +537,17 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
CMyComPtr<ICryptoGetTextPassword2> getPassword2;
updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2);
+ methodMode.PasswordIsDefined = false;
+ methodMode.Password.Empty();
if (getPassword2)
{
CMyComBSTR password;
Int32 passwordIsDefined;
RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password));
methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
- if (methodMode.PasswordIsDefined)
+ if (methodMode.PasswordIsDefined && (BSTR)password)
methodMode.Password = password;
}
- else
- methodMode.PasswordIsDefined = false;
bool compressMainHeader = _compressHeaders; // check it
@@ -360,9 +580,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
options.MaxFilter = level >= 8;
options.HeaderOptions.CompressMainHeader = compressMainHeader;
- options.HeaderOptions.WriteCTime = WriteCTime;
- options.HeaderOptions.WriteATime = WriteATime;
- options.HeaderOptions.WriteMTime = WriteMTime;
+ /*
+ options.HeaderOptions.WriteCTime = Write_CTime;
+ options.HeaderOptions.WriteATime = Write_ATime;
+ options.HeaderOptions.WriteMTime = Write_MTime;
+ */
options.NumSolidFiles = _numSolidFiles;
options.NumSolidBytes = _numSolidBytes;
@@ -371,11 +593,23 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
options.VolumeMode = _volumeMode;
COutArchive archive;
- CArchiveDatabase newDatabase;
+ CArchiveDatabaseOut newDatabase;
CMyComPtr<ICryptoGetTextPassword> getPassword;
updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword);
+ /*
+ if (secureBlocks.Sorted.Size() > 1)
+ {
+ secureBlocks.GetReverseMap();
+ for (int i = 0; i < updateItems.Size(); i++)
+ {
+ int &secureIndex = updateItems[i].SecureIndex;
+ secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex];
+ }
+ }
+ */
+
res = Update(
EXTERNAL_CODECS_VARS
#ifdef _7Z_VOL
@@ -386,6 +620,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
db,
#endif
updateItems,
+ // treeFolders,
+ // secureBlocks,
archive, newDatabase, outStream, updateCallback, options
#ifndef _NO_CRYPTO
, getPassword
@@ -409,7 +645,7 @@ static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream
if (index == 0)
return E_INVALIDARG;
srcString.Delete(0, index);
- if (srcString[0] == 'S')
+ if (srcString[0] == 's')
{
srcString.Delete(0);
int index = ParseStringToUInt32(srcString, stream);
@@ -428,11 +664,12 @@ void COutHandler::InitProps()
_compressHeaders = true;
_encryptHeadersSpecified = false;
_encryptHeaders = false;
+ // _useParents = false;
- WriteCTime = false;
- WriteATime = false;
- WriteMTime = true;
-
+ Write_CTime.Init();
+ Write_ATime.Init();
+ Write_MTime.Init();
+
_volumeMode = false;
InitSolid();
}
@@ -440,24 +677,24 @@ void COutHandler::InitProps()
HRESULT COutHandler::SetSolidFromString(const UString &s)
{
UString s2 = s;
- s2.MakeUpper();
- for (int i = 0; i < s2.Length();)
+ 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')
+ if (s2[i++] != 'e')
return E_INVALIDARG;
_solidExtension = true;
continue;
}
i += (int)(end - start);
- if (i == s2.Length())
+ if (i == s2.Len())
return E_INVALIDARG;
wchar_t c = s2[i++];
- if (c == 'F')
+ if (c == 'f')
{
if (v < 1)
v = 1;
@@ -468,10 +705,11 @@ HRESULT COutHandler::SetSolidFromString(const UString &s)
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 '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);
@@ -501,14 +739,21 @@ HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value)
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.MakeUpper();
+ name.MakeLower_Ascii();
if (name.IsEmpty())
return E_INVALIDARG;
- if (name[0] == L'S')
+ if (name[0] == L's')
{
name.Delete(0);
if (name.IsEmpty())
@@ -520,47 +765,52 @@ HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &val
UInt32 number;
int index = ParseStringToUInt32(name, number);
- UString realName = name.Mid(index);
+ UString realName = name.Ptr(index);
if (index == 0)
{
- if (name.CompareNoCase(L"RSFX") == 0) return PROPVARIANT_to_bool(value, _removeSfxBlock);
- if (name.CompareNoCase(L"HC") == 0) return PROPVARIANT_to_bool(value, _compressHeaders);
- if (name.CompareNoCase(L"HCF") == 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.CompareNoCase(L"HE") == 0)
+
+ if (name.IsEqualTo("he"))
{
RINOK(PROPVARIANT_to_bool(value, _encryptHeaders));
_encryptHeadersSpecified = true;
return S_OK;
}
- if (name.CompareNoCase(L"TC") == 0) return PROPVARIANT_to_bool(value, WriteCTime);
- if (name.CompareNoCase(L"TA") == 0) return PROPVARIANT_to_bool(value, WriteATime);
- if (name.CompareNoCase(L"TM") == 0) return PROPVARIANT_to_bool(value, WriteMTime);
- if (name.CompareNoCase(L"V") == 0) return PROPVARIANT_to_bool(value, _volumeMode);
+
+ 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("v")) return PROPVARIANT_to_bool(value, _volumeMode);
}
return CMultiMethodProps::SetProperty(name, value);
}
-STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
{
COM_TRY_BEGIN
_binds.Clear();
InitProps();
- for (int i = 0; i < numProps; i++)
+ for (UInt32 i = 0; i < numProps; i++)
{
UString name = names[i];
- name.MakeUpper();
+ name.MakeLower_Ascii();
if (name.IsEmpty())
return E_INVALIDARG;
const PROPVARIANT &value = values[i];
- if (name[0] == 'B')
+ if (name[0] == 'b')
{
if (value.vt != VT_EMPTY)
return E_INVALIDARG;
@@ -580,10 +830,10 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v
RINOK(SetProperty(name, value));
}
- int numEmptyMethods = GetNumEmptyMethods();
+ unsigned numEmptyMethods = GetNumEmptyMethods();
if (numEmptyMethods > 0)
{
- int k;
+ unsigned k;
for (k = 0; k < _binds.Size(); k++)
{
const CBind &bind = _binds[k];
@@ -597,14 +847,14 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v
bind.InCoder -= (UInt32)numEmptyMethods;
bind.OutCoder -= (UInt32)numEmptyMethods;
}
- _methods.Delete(0, numEmptyMethods);
+ _methods.DeleteFrontal(numEmptyMethods);
}
AddDefaultMethod();
if (!_filterMethod.MethodName.IsEmpty())
{
- for (int k = 0; k < _binds.Size(); k++)
+ FOR_VECTOR (k, _binds)
{
CBind &bind = _binds[k];
bind.InCoder++;
@@ -613,7 +863,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v
_methods.Insert(0, _filterMethod);
}
- for (int k = 0; k < _binds.Size(); k++)
+ FOR_VECTOR (k, _binds)
{
const CBind &bind = _binds[k];
if (bind.InCoder >= (UInt32)_methods.Size() ||
diff --git a/CPP/7zip/Archive/7z/7zHeader.cpp b/CPP/7zip/Archive/7z/7zHeader.cpp
index 5b5f2fb3..acff2fdd 100755..100644
--- a/CPP/7zip/Archive/7z/7zHeader.cpp
+++ b/CPP/7zip/Archive/7z/7zHeader.cpp
@@ -1,6 +1,7 @@
// 7zHeader.cpp
#include "StdAfx.h"
+
#include "7zHeader.h"
namespace NArchive {
@@ -11,4 +12,8 @@ Byte kSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
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 30622b90..d72fdefa 100755..100644
--- a/CPP/7zip/Archive/7z/7zHeader.h
+++ b/CPP/7zip/Archive/7z/7zHeader.h
@@ -3,12 +3,12 @@
#ifndef __7Z_HEADER_H
#define __7Z_HEADER_H
-#include "../../../Common/Types.h"
+#include "../../../Common/MyTypes.h"
namespace NArchive {
namespace N7z {
-const int kSignatureSize = 6;
+const unsigned kSignatureSize = 6;
extern Byte kSignature[kSignatureSize];
// #define _7Z_VOL
@@ -82,13 +82,17 @@ namespace NID
kCTime,
kATime,
kMTime,
- kWinAttributes,
+ kWinAttrib,
kComment,
kEncodedHeader,
kStartPos,
kDummy
+
+ // kNtSecure,
+ // kParent,
+ // kIsAux
};
}
diff --git a/CPP/7zip/Archive/7z/7zIn.cpp b/CPP/7zip/Archive/7z/7zIn.cpp
index fd751a74..d84cf0b0 100755..100644
--- a/CPP/7zip/Archive/7z/7zIn.cpp
+++ b/CPP/7zip/Archive/7z/7zIn.cpp
@@ -20,15 +20,21 @@
#define FORMAT_7Z_RECOVERY
#endif
+using namespace NWindows;
+using namespace NCOM;
+
namespace NArchive {
namespace N7z {
-static void BoolVector_Fill_False(CBoolVector &v, int size)
+static const UInt32 k_LZMA2 = 0x21;
+static const UInt32 k_LZMA = 0x030101;
+
+static void BoolVector_Fill_False(CBoolVector &v, unsigned size)
{
- v.Clear();
- v.Reserve(size);
- for (int i = 0; i < size; i++)
- v.Add(false);
+ v.ClearAndSetSize(size);
+ bool *p = &v[0];
+ for (unsigned i = 0; i < size; i++)
+ p[i] = false;
}
static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index)
@@ -40,11 +46,11 @@ static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index)
return res;
}
-bool CFolder::CheckStructure() const
+bool CFolder::CheckStructure(unsigned numUnpackSizes) const
{
- const int kNumCodersMax = sizeof(UInt32) * 8; // don't change it
- const int kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax
- const int kNumBindsMax = 32;
+ const unsigned kNumCodersMax = sizeof(UInt32) * 8; // don't change it
+ const unsigned kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax
+ const unsigned kNumBindsMax = 32;
if (Coders.Size() > kNumCodersMax || BindPairs.Size() > kNumBindsMax)
return false;
@@ -53,7 +59,7 @@ bool CFolder::CheckStructure() const
CBoolVector v;
BoolVector_Fill_False(v, BindPairs.Size() + PackStreams.Size());
- int i;
+ unsigned i;
for (i = 0; i < BindPairs.Size(); i++)
if (BoolVector_GetAndSet(v, BindPairs[i].InIndex))
return false;
@@ -61,19 +67,19 @@ bool CFolder::CheckStructure() const
if (BoolVector_GetAndSet(v, PackStreams[i]))
return false;
- BoolVector_Fill_False(v, UnpackSizes.Size());
+ BoolVector_Fill_False(v, numUnpackSizes);
for (i = 0; i < BindPairs.Size(); i++)
if (BoolVector_GetAndSet(v, BindPairs[i].OutIndex))
return false;
}
UInt32 mask[kMaskSize];
- int i;
+ unsigned i;
for (i = 0; i < kMaskSize; i++)
mask[i] = 0;
{
- CIntVector inStreamToCoder, outStreamToCoder;
+ CUIntVector inStreamToCoder, outStreamToCoder;
for (i = 0; i < Coders.Size(); i++)
{
CNum j;
@@ -92,7 +98,7 @@ bool CFolder::CheckStructure() const
}
for (i = 0; i < kMaskSize; i++)
- for (int j = 0; j < kMaskSize; j++)
+ for (unsigned j = 0; j < kMaskSize; j++)
if (((1 << j) & mask[i]) != 0)
mask[i] |= mask[j];
@@ -104,43 +110,23 @@ bool CFolder::CheckStructure() const
}
class CInArchiveException {};
+class CUnsupportedFeatureException: public CInArchiveException {};
static void ThrowException() { throw CInArchiveException(); }
static inline void ThrowEndOfData() { ThrowException(); }
-static inline void ThrowUnsupported() { ThrowException(); }
+static inline void ThrowUnsupported() { throw CUnsupportedFeatureException(); }
static inline void ThrowIncorrect() { ThrowException(); }
-static inline void ThrowUnsupportedVersion() { ThrowException(); }
-
-/*
-class CInArchiveException
-{
-public:
- enum CCauseType
- {
- kUnsupportedVersion = 0,
- kUnsupported,
- kIncorrect,
- kEndOfData
- } Cause;
- CInArchiveException(CCauseType cause): Cause(cause) {};
-};
-
-static void ThrowException(CInArchiveException::CCauseType c) { throw CInArchiveException(c); }
-static void ThrowEndOfData() { ThrowException(CInArchiveException::kEndOfData); }
-static void ThrowUnsupported() { ThrowException(CInArchiveException::kUnsupported); }
-static void ThrowIncorrect() { ThrowException(CInArchiveException::kIncorrect); }
-static void ThrowUnsupportedVersion() { ThrowException(CInArchiveException::kUnsupportedVersion); }
-*/
class CStreamSwitch
{
CInArchive *_archive;
bool _needRemove;
+ bool _needUpdatePos;
public:
- CStreamSwitch(): _needRemove(false) {}
+ CStreamSwitch(): _needRemove(false), _needUpdatePos(false) {}
~CStreamSwitch() { Remove(); }
void Remove();
- void Set(CInArchive *archive, const Byte *data, size_t size);
+ void Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos);
void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
};
@@ -149,22 +135,25 @@ void CStreamSwitch::Remove()
{
if (_needRemove)
{
- _archive->DeleteByteStream();
+ if (_archive->_inByteBack->GetRem() != 0)
+ _archive->ThereIsHeaderError = true;
+ _archive->DeleteByteStream(_needUpdatePos);
_needRemove = false;
}
}
-void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size)
+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.GetCapacity());
+ Set(archive, byteBuffer, byteBuffer.Size(), false);
}
void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
@@ -173,13 +162,22 @@ void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *d
Byte external = archive->ReadByte();
if (external != 0)
{
- int dataIndex = (int)archive->ReadNum();
- if (dataIndex < 0 || dataIndex >= dataVector->Size())
+ 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)
@@ -191,8 +189,8 @@ void CInByte2::ReadBytes(Byte *data, size_t size)
{
if (size > _size - _pos)
ThrowEndOfData();
- for (size_t i = 0; i < size; i++)
- data[i] = _buffer[_pos++];
+ memcpy(data, _buffer + _pos, size);
+ _pos += size;
}
void CInByte2::SkipData(UInt64 size)
@@ -207,31 +205,75 @@ void CInByte2::SkipData()
SkipData(ReadNumber());
}
-UInt64 CInByte2::ReadNumber()
+static UInt64 ReadNumberSpec(const Byte *p, size_t size, size_t &processed)
{
- if (_pos >= _size)
- ThrowEndOfData();
- Byte firstByte = _buffer[_pos++];
- Byte mask = 0x80;
- UInt64 value = 0;
- for (int i = 0; i < 8; i++)
+ if (size == 0)
+ {
+ processed = 0;
+ return 0;
+ }
+ Byte firstByte = *p++;
+ size--;
+ if ((firstByte & 0x80) == 0)
+ {
+ processed = 1;
+ return firstByte;
+ }
+ Byte mask = 0x40;
+ if (size == 0)
+ {
+ processed = 0;
+ return 0;
+ }
+ UInt64 value = (UInt64)*p;
+ p++;
+ size--;
+ for (unsigned i = 1; i < 8; i++)
{
if ((firstByte & mask) == 0)
{
UInt64 highPart = firstByte & (mask - 1);
value += (highPart << (i * 8));
+ processed = i + 1;
return value;
}
- if (_pos >= _size)
- ThrowEndOfData();
- value |= ((UInt64)_buffer[_pos++] << (8 * i));
+ if (size == 0)
+ {
+ processed = 0;
+ return 0;
+ }
+ value |= ((UInt64)*p << (i * 8));
+ p++;
+ size--;
mask >>= 1;
}
+ 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();
@@ -256,48 +298,21 @@ UInt64 CInByte2::ReadUInt64()
return res;
}
-void CInByte2::ReadString(UString &s)
-{
- const Byte *buf = _buffer + _pos;
- size_t rem = (_size - _pos) / 2 * 2;
- {
- size_t i;
- for (i = 0; i < rem; i += 2)
- if (buf[i] == 0 && buf[i + 1] == 0)
- break;
- if (i == rem)
- ThrowEndOfData();
- rem = i;
- }
- int len = (int)(rem / 2);
- if (len < 0 || (size_t)len * 2 != rem)
- ThrowUnsupported();
- wchar_t *p = s.GetBuffer(len);
- int i;
- for (i = 0; i < len; i++, buf += 2)
- p[i] = (wchar_t)Get16(buf);
- s.ReleaseBuffer(len);
- _pos += rem + 2;
-}
+#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)
{
- for (int i = 0; i < kSignatureSize; i++)
- if (p[i] != kSignature[i])
- return false;
- return CrcCalc(p + 12, 20) == GetUi32(p + 8);
+ CHECK_SIGNATURE
+ return CrcCalc(p + 12, 20) == Get32(p + 8);
}
#ifdef FORMAT_7Z_RECOVERY
static inline bool TestSignature2(const Byte *p)
{
- int i;
- for (i = 0; i < kSignatureSize; i++)
- if (p[i] != kSignature[i])
- return false;
- if (CrcCalc(p + 12, 20) == GetUi32(p + 8))
+ CHECK_SIGNATURE;
+ if (CrcCalc(p + 12, 20) == Get32(p + 8))
return true;
- for (i = 8; i < kHeaderSize; i++)
+ for (unsigned i = 8; i < kHeaderSize; i++)
if (p[i] != 0)
return false;
return (p[6] != 0 || p[7] != 0);
@@ -312,39 +327,52 @@ HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *search
if (TestSignature2(_header))
return S_OK;
+ if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0)
+ return S_FALSE;
- CByteBuffer byteBuffer;
- const UInt32 kBufferSize = (1 << 16);
- byteBuffer.SetCapacity(kBufferSize);
- Byte *buffer = byteBuffer;
- memcpy(buffer, _header, kHeaderSize);
- UInt64 curTestPos = _arhiveBeginStreamPosition;
+ const UInt32 kBufSize = 1 << 15;
+ CByteArr buf(kBufSize);
+ memcpy(buf, _header, kHeaderSize);
+ UInt64 offset = 0;
+
for (;;)
{
- if (searchHeaderSizeLimit != NULL)
- if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
- break;
- UInt32 processedSize;
- RINOK(stream->Read(buffer + kHeaderSize, kBufferSize - kHeaderSize, &processedSize));
- if (processedSize == 0)
+ UInt32 readSize = kBufSize - kHeaderSize;
+ {
+ 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 = 1; pos <= processedSize; pos++)
+ for (UInt32 pos = 0;;)
{
- for (; buffer[pos] != '7' && pos <= processedSize; pos++);
- if (pos > processedSize)
+ 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;
- if (TestSignature(buffer + pos))
+ pos = (UInt32)(p - buf);
+ if (TestSignature(p))
{
- memcpy(_header, buffer + pos, kHeaderSize);
- curTestPos += pos;
- _arhiveBeginStreamPosition = curTestPos;
- return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL);
+ memcpy(_header, p, kHeaderSize);
+ _arhiveBeginStreamPosition += offset + pos;
+ return stream->Seek(_arhiveBeginStreamPosition + kHeaderSize, STREAM_SEEK_SET, NULL);
}
}
- curTestPos += processedSize;
- memmove(buffer, buffer + processedSize, kHeaderSize);
+ offset += processed;
+ memmove(buf, buf + processed, kHeaderSize);
}
- return S_FALSE;
}
// S_FALSE means that file is not archive
@@ -362,7 +390,9 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
void CInArchive::Close()
{
+ _numInByteBufs = 0;
_stream.Release();
+ ThereIsHeaderError = false;
}
void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */)
@@ -375,30 +405,32 @@ void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */)
}
}
-void CInArchive::GetNextFolderItem(CFolder &folder)
+// CFolder &folder can be non empty. So we must set all fields
+
+void CInByte2::ParseFolder(CFolder &folder)
{
CNum numCoders = ReadNum();
- folder.Coders.Clear();
- folder.Coders.Reserve((int)numCoders);
+ folder.Coders.SetSize(numCoders);
+
CNum numInStreams = 0;
CNum numOutStreams = 0;
CNum i;
for (i = 0; i < numCoders; i++)
{
- folder.Coders.Add(CCoderInfo());
- CCoderInfo &coder = folder.Coders.Back();
-
+ CCoderInfo &coder = folder.Coders[i];
{
Byte mainByte = ReadByte();
- int idSize = (mainByte & 0xF);
- Byte longID[15];
- ReadBytes(longID, idSize);
- if (idSize > 8)
+ if ((mainByte & 0xC0) != 0)
ThrowUnsupported();
+ unsigned idSize = (mainByte & 0xF);
+ if (idSize > 8 || idSize > GetRem())
+ ThrowUnsupported();
+ const Byte *longID = GetPtr();
UInt64 id = 0;
- for (int j = 0; j < idSize; j++)
- id |= (UInt64)longID[idSize - 1 - j] << (8 * j);
+ for (unsigned j = 0; j < idSize; j++)
+ id = ((id << 8) | longID[j]);
+ SkipDataNoCheck(idSize);
coder.MethodID = id;
if ((mainByte & 0x10) != 0)
@@ -414,53 +446,117 @@ void CInArchive::GetNextFolderItem(CFolder &folder)
if ((mainByte & 0x20) != 0)
{
CNum propsSize = ReadNum();
- coder.Props.SetCapacity((size_t)propsSize);
+ coder.Props.Alloc((size_t)propsSize);
ReadBytes((Byte *)coder.Props, (size_t)propsSize);
}
- if ((mainByte & 0x80) != 0)
- ThrowUnsupported();
+ else
+ coder.Props.Free();
}
numInStreams += coder.NumInStreams;
numOutStreams += coder.NumOutStreams;
}
CNum numBindPairs = numOutStreams - 1;
- folder.BindPairs.Clear();
- folder.BindPairs.Reserve(numBindPairs);
+ folder.BindPairs.SetSize(numBindPairs);
for (i = 0; i < numBindPairs; i++)
{
- CBindPair bp;
+ CBindPair &bp = folder.BindPairs[i];
bp.InIndex = ReadNum();
bp.OutIndex = ReadNum();
- folder.BindPairs.Add(bp);
}
if (numInStreams < numBindPairs)
ThrowUnsupported();
CNum numPackStreams = numInStreams - numBindPairs;
- folder.PackStreams.Reserve(numPackStreams);
+ folder.PackStreams.SetSize(numPackStreams);
if (numPackStreams == 1)
{
for (i = 0; i < numInStreams; i++)
if (folder.FindBindPairForInStream(i) < 0)
{
- folder.PackStreams.Add(i);
+ folder.PackStreams[0] = i;
break;
}
- if (folder.PackStreams.Size() != 1)
+ if (i == numInStreams)
ThrowUnsupported();
}
else
for (i = 0; i < numPackStreams; i++)
- folder.PackStreams.Add(ReadNum());
+ 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 CInArchive::WaitAttribute(UInt64 attribute)
+
+HRESULT CDatabase::GetPath(unsigned index, PROPVARIANT *path) const
+{
+ PropVariant_Clear(path);
+ if (!NameOffsets || !NamesBuf)
+ 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 << 12) || 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;
+ do
+ {
+ p -= 2;
+ --s;
+ wchar_t c = Get16(p);
+ if (c == '/')
+ c = WCHAR_PATH_SEPARATOR;
+ *s = c;
+ }
+ while (--len);
+ /*
+ 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 == attribute)
+ if (type == id)
return;
if (type == NID::kEnd)
ThrowIncorrect();
@@ -468,90 +564,209 @@ void CInArchive::WaitAttribute(UInt64 attribute)
}
}
-void CInArchive::ReadHashDigests(int numItems,
- CBoolVector &digestsDefined,
- CRecordVector<UInt32> &digests)
+void CInArchive::ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs)
{
- ReadBoolVector2(numItems, digestsDefined);
- digests.Clear();
- digests.Reserve(numItems);
- for (int i = 0; i < numItems; i++)
+ ReadBoolVector2(numItems, crcs.Defs);
+ crcs.Vals.ClearAndSetSize(numItems);
+ UInt32 *p = &crcs.Vals[0];
+ const bool *defs = &crcs.Defs[0];
+ for (unsigned i = 0; i < numItems; i++)
{
UInt32 crc = 0;
- if (digestsDefined[i])
+ if (defs[i])
crc = ReadUInt32();
- digests.Add(crc);
+ p[i] = crc;
}
}
-void CInArchive::ReadPackInfo(
- UInt64 &dataOffset,
- CRecordVector<UInt64> &packSizes,
- CBoolVector &packCRCsDefined,
- CRecordVector<UInt32> &packCRCs)
+void CInArchive::ReadPackInfo(CFolders &f)
{
- dataOffset = ReadNumber();
CNum numPackStreams = ReadNum();
-
- WaitAttribute(NID::kSize);
- packSizes.Clear();
- packSizes.Reserve(numPackStreams);
+
+ WaitId(NID::kSize);
+ f.PackPositions.Alloc(numPackStreams + 1);
+ f.NumPackStreams = numPackStreams;
+ UInt64 sum = 0;
for (CNum i = 0; i < numPackStreams; i++)
- packSizes.Add(ReadNumber());
+ {
+ 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)
- break;
+ return;
if (type == NID::kCRC)
{
- ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs);
+ CUInt32DefVector PackCRCs;
+ ReadHashDigests(numPackStreams, PackCRCs);
continue;
}
SkipData();
}
- if (packCRCsDefined.IsEmpty())
- {
- BoolVector_Fill_False(packCRCsDefined, numPackStreams);
- packCRCs.Reserve(numPackStreams);
- packCRCs.Clear();
- for (CNum i = 0; i < numPackStreams; i++)
- packCRCs.Add(0);
- }
}
void CInArchive::ReadUnpackInfo(
const CObjectVector<CByteBuffer> *dataVector,
- CObjectVector<CFolder> &folders)
+ CFolders &folders)
{
- WaitAttribute(NID::kFolder);
+ WaitId(NID::kFolder);
CNum numFolders = ReadNum();
+ CNum numCodersOutStreams = 0;
{
CStreamSwitch streamSwitch;
streamSwitch.Set(this, dataVector);
- folders.Clear();
- folders.Reserve(numFolders);
- for (CNum i = 0; i < numFolders; i++)
+ 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);
+
+ CRecordVector<bool> InStreamUsed;
+ CRecordVector<bool> OutStreamUsed;
+
+ CNum packStreamIndex = 0;
+ CNum fo;
+ CInByte2 *inByte = _inByteBack;
+ for (fo = 0; fo < numFolders; fo++)
{
- folders.Add(CFolder());
- GetNextFolderItem(folders.Back());
+ UInt32 numOutStreams = 0;
+ UInt32 indexOfMainStream = 0;
+ UInt32 numPackStreams = 0;
+ folders.FoCodersDataOffset[fo] = _inByteBack->GetPtr() - startBufPtr;
+
+ numOutStreams = 0;
+ CNum numInStreams = 0;
+ CNum numCoders = inByte->ReadNum();
+ 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;
+ CNum coderOutStreams = 1;
+ if ((mainByte & 0x10) != 0)
+ {
+ coderInStreams = inByte->ReadNum();
+ coderOutStreams = inByte->ReadNum();
+ }
+ numInStreams += coderInStreams;
+ if (numInStreams < coderInStreams)
+ ThrowUnsupported();
+ numOutStreams += coderOutStreams;
+ if (numOutStreams < coderOutStreams)
+ 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 (numOutStreams == 1 && numInStreams == 1)
+ {
+ indexOfMainStream = 0;
+ numPackStreams = 1;
+ }
+ else
+ {
+ UInt32 i;
+ if (numOutStreams == 0)
+ ThrowUnsupported();
+ CNum numBindPairs = numOutStreams - 1;
+ if (numInStreams < numBindPairs)
+ ThrowUnsupported();
+ if (numInStreams >= 256 || numOutStreams >= 256)
+ ThrowUnsupported();
+
+ InStreamUsed.ClearAndSetSize(numInStreams);
+ for (i = 0; i < numInStreams; i++)
+ InStreamUsed[i] = false;
+
+ OutStreamUsed.ClearAndSetSize(numOutStreams);
+ for (i = 0; i < numOutStreams; i++)
+ OutStreamUsed[i] = false;
+
+ for (i = 0; i < numBindPairs; i++)
+ {
+ CNum index = ReadNum();
+ if (index >= numInStreams || InStreamUsed[index])
+ ThrowUnsupported();
+ InStreamUsed[index] = true;
+ index = ReadNum();
+ if (index >= numOutStreams || OutStreamUsed[index])
+ ThrowUnsupported();
+ OutStreamUsed[index] = true;
+ }
+
+ numPackStreams = numInStreams - numBindPairs;
+
+ if (numPackStreams != 1)
+ for (i = 0; i < numPackStreams; i++)
+ inByte->ReadNum(); // PackStreams
+
+ for (i = 0; i < numOutStreams; i++)
+ if (!OutStreamUsed[i])
+ {
+ indexOfMainStream = i;
+ break;
+ }
+ if (i == numOutStreams)
+ ThrowUnsupported();
+ }
+ folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams;
+ numCodersOutStreams += numOutStreams;
+ folders.FoStartPackStreamIndex[fo] = packStreamIndex;
+ 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);
}
- WaitAttribute(NID::kCodersUnpackSize);
-
- CNum i;
- for (i = 0; i < numFolders; i++)
- {
- CFolder &folder = folders[i];
- CNum numOutStreams = folder.GetNumOutStreams();
- folder.UnpackSizes.Reserve(numOutStreams);
- for (CNum j = 0; j < numOutStreams; j++)
- folder.UnpackSizes.Add(ReadNumber());
- }
+ WaitId(NID::kCodersUnpackSize);
+ folders.CoderUnpackSizes.Alloc(numCodersOutStreams);
+ for (CNum i = 0; i < numCodersOutStreams; i++)
+ folders.CoderUnpackSizes[i] = ReadNumber();
for (;;)
{
@@ -560,15 +775,7 @@ void CInArchive::ReadUnpackInfo(
return;
if (type == NID::kCRC)
{
- CBoolVector crcsDefined;
- CRecordVector<UInt32> crcs;
- ReadHashDigests(numFolders, crcsDefined, crcs);
- for (i = 0; i < numFolders; i++)
- {
- CFolder &folder = folders[i];
- folder.UnpackCRCDefined = crcsDefined[i];
- folder.UnpackCRC = crcs[i];
- }
+ ReadHashDigests(numFolders, folders.FolderCRCs);
continue;
}
SkipData();
@@ -576,170 +783,217 @@ void CInArchive::ReadUnpackInfo(
}
void CInArchive::ReadSubStreamsInfo(
- const CObjectVector<CFolder> &folders,
- CRecordVector<CNum> &numUnpackStreamsInFolders,
+ CFolders &folders,
CRecordVector<UInt64> &unpackSizes,
- CBoolVector &digestsDefined,
- CRecordVector<UInt32> &digests)
+ CUInt32DefVector &digests)
{
- numUnpackStreamsInFolders.Clear();
- numUnpackStreamsInFolders.Reserve(folders.Size());
+ 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 (int i = 0; i < folders.Size(); i++)
- numUnpackStreamsInFolders.Add(ReadNum());
+ for (i = 0; i < folders.NumFolders; i++)
+ folders.NumUnpackStreamsVector[i] = ReadNum();
continue;
}
- if (type == NID::kCRC || type == NID::kSize)
- break;
- if (type == NID::kEnd)
+ if (type == NID::kCRC || type == NID::kSize || type == NID::kEnd)
break;
SkipData();
}
- if (numUnpackStreamsInFolders.IsEmpty())
- for (int i = 0; i < folders.Size(); i++)
- numUnpackStreamsInFolders.Add(1);
-
- int i;
- for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
+ if (type == NID::kSize)
{
- // v3.13 incorrectly worked with empty folders
- // v4.07: we check that folder is empty
- CNum numSubstreams = numUnpackStreamsInFolders[i];
- if (numSubstreams == 0)
- continue;
- UInt64 sum = 0;
- for (CNum j = 1; j < numSubstreams; j++)
- if (type == NID::kSize)
+ 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();
}
- unpackSizes.Add(folders[i].GetUnpackSize() - sum);
- }
- if (type == NID::kSize)
+ 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));
+ }
+ }
- int numDigests = 0;
- int numDigestsTotal = 0;
- for (i = 0; i < folders.Size(); i++)
+ unsigned numDigests = 0;
+ for (i = 0; i < folders.NumFolders; i++)
{
- CNum numSubstreams = numUnpackStreamsInFolders[i];
- if (numSubstreams != 1 || !folders[i].UnpackCRCDefined)
+ CNum numSubstreams = folders.NumUnpackStreamsVector[i];
+ if (numSubstreams != 1 || !folders.FolderCRCs.ValidAndDefined(i))
numDigests += numSubstreams;
- numDigestsTotal += numSubstreams;
}
for (;;)
{
+ if (type == NID::kEnd)
+ break;
if (type == NID::kCRC)
{
- CBoolVector digestsDefined2;
- CRecordVector<UInt32> digests2;
- ReadHashDigests(numDigests, digestsDefined2, digests2);
- int digestIndex = 0;
- for (i = 0; i < folders.Size(); i++)
+ // 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 = numUnpackStreamsInFolders[i];
- const CFolder &folder = folders[i];
- if (numSubstreams == 1 && folder.UnpackCRCDefined)
+ CNum numSubstreams = folders.NumUnpackStreamsVector[i];
+ if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i))
{
- digestsDefined.Add(true);
- digests.Add(folder.UnpackCRC);
+ 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++;
}
- else
- for (CNum j = 0; j < numSubstreams; j++, digestIndex++)
- {
- digestsDefined.Add(digestsDefined2[digestIndex]);
- digests.Add(digests2[digestIndex]);
- }
}
+ // if (k != unpackSizes.Size()) throw 1234567;
}
- else if (type == NID::kEnd)
+ else
+ SkipData();
+
+ type = ReadID();
+ }
+
+ if (digests.Defs.Size() != unpackSizes.Size())
+ {
+ digests.ClearAndSetSize(unpackSizes.Size());
+ unsigned k = 0;
+ for (i = 0; i < folders.NumFolders; i++)
{
- if (digestsDefined.IsEmpty())
+ CNum numSubstreams = folders.NumUnpackStreamsVector[i];
+ if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i))
{
- BoolVector_Fill_False(digestsDefined, numDigestsTotal);
- digests.Clear();
- for (int i = 0; i < numDigestsTotal; i++)
- digests.Add(0);
+ 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++;
}
- return;
}
- else
- SkipData();
- type = ReadID();
}
}
void CInArchive::ReadStreamsInfo(
const CObjectVector<CByteBuffer> *dataVector,
UInt64 &dataOffset,
- CRecordVector<UInt64> &packSizes,
- CBoolVector &packCRCsDefined,
- CRecordVector<UInt32> &packCRCs,
- CObjectVector<CFolder> &folders,
- CRecordVector<CNum> &numUnpackStreamsInFolders,
+ CFolders &folders,
CRecordVector<UInt64> &unpackSizes,
- CBoolVector &digestsDefined,
- CRecordVector<UInt32> &digests)
+ CUInt32DefVector &digests)
{
- for (;;)
+ UInt64 type = ReadID();
+
+ if (type == NID::kPackInfo)
{
- UInt64 type = ReadID();
- if (type > ((UInt32)1 << 30))
- ThrowIncorrect();
- switch((UInt32)type)
+ 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++)
{
- case NID::kEnd:
- return;
- case NID::kPackInfo:
- {
- ReadPackInfo(dataOffset, packSizes, packCRCsDefined, packCRCs);
- break;
- }
- case NID::kUnpackInfo:
- {
- ReadUnpackInfo(dataVector, folders);
- break;
- }
- case NID::kSubStreamsInfo:
- {
- ReadSubStreamsInfo(folders, numUnpackStreamsInFolders,
- unpackSizes, digestsDefined, digests);
- break;
- }
- default:
- ThrowIncorrect();
+ folders.NumUnpackStreamsVector[i] = 1;
+ unpackSizes.Add(folders.GetFolderUnpackSize(i));
+ // digests.Vals[i] = 0;
}
}
+
+ if (type != NID::kEnd)
+ ThrowIncorrect();
}
-void CInArchive::ReadBoolVector(int numItems, CBoolVector &v)
+void CInArchive::ReadBoolVector(unsigned numItems, CBoolVector &v)
{
- v.Clear();
- v.Reserve(numItems);
+ v.ClearAndSetSize(numItems);
Byte b = 0;
Byte mask = 0;
- for (int i = 0; i < numItems; i++)
+ bool *p = &v[0];
+ for (unsigned i = 0; i < numItems; i++)
{
if (mask == 0)
{
b = ReadByte();
mask = 0x80;
}
- v.Add((b & mask) != 0);
+ p[i] = ((b & mask) != 0);
mask >>= 1;
}
}
-void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v)
+void CInArchive::ReadBoolVector2(unsigned numItems, CBoolVector &v)
{
Byte allAreDefined = ReadByte();
if (allAreDefined == 0)
@@ -747,27 +1001,30 @@ void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v)
ReadBoolVector(numItems, v);
return;
}
- v.Clear();
- v.Reserve(numItems);
- for (int i = 0; i < numItems; i++)
- v.Add(true);
+ v.ClearAndSetSize(numItems);
+ bool *p = &v[0];
+ for (unsigned i = 0; i < numItems; i++)
+ p[i] = true;
}
void CInArchive::ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
- CUInt64DefVector &v, int numFiles)
+ CUInt64DefVector &v, unsigned numItems)
{
- ReadBoolVector2(numFiles, v.Defined);
+ ReadBoolVector2(numItems, v.Defs);
CStreamSwitch streamSwitch;
streamSwitch.Set(this, &dataVector);
- v.Values.Reserve(numFiles);
+
+ v.Vals.ClearAndSetSize(numItems);
+ UInt64 *p = &v.Vals[0];
+ const bool *defs = &v.Defs[0];
- for (int i = 0; i < numFiles; i++)
+ for (unsigned i = 0; i < numItems; i++)
{
UInt64 t = 0;
- if (v.Defined[i])
+ if (defs[i])
t = ReadUInt64();
- v.Values.Add(t);
+ p[i] = t;
}
}
@@ -775,35 +1032,19 @@ HRESULT CInArchive::ReadAndDecodePackedStreams(
DECL_EXTERNAL_CODECS_LOC_VARS
UInt64 baseOffset,
UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
- #ifndef _NO_CRYPTO
- , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
- #endif
+ _7Z_DECODER_CRYPRO_VARS_DECL
)
{
- CRecordVector<UInt64> packSizes;
- CBoolVector packCRCsDefined;
- CRecordVector<UInt32> packCRCs;
- CObjectVector<CFolder> folders;
-
- CRecordVector<CNum> numUnpackStreamsInFolders;
+ CFolders folders;
CRecordVector<UInt64> unpackSizes;
- CBoolVector digestsDefined;
- CRecordVector<UInt32> digests;
+ CUInt32DefVector digests;
ReadStreamsInfo(NULL,
dataOffset,
- packSizes,
- packCRCsDefined,
- packCRCs,
folders,
- numUnpackStreamsInFolders,
unpackSizes,
- digestsDefined,
digests);
- // db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader;
-
- CNum packIndex = 0;
CDecoder decoder(
#ifdef _ST_MODE
false
@@ -811,17 +1052,15 @@ HRESULT CInArchive::ReadAndDecodePackedStreams(
true
#endif
);
- UInt64 dataStartPos = baseOffset + dataOffset;
- for (int i = 0; i < folders.Size(); i++)
+
+ for (CNum i = 0; i < folders.NumFolders; i++)
{
- const CFolder &folder = folders[i];
- dataVector.Add(CByteBuffer());
- CByteBuffer &data = dataVector.Back();
- UInt64 unpackSize64 = folder.GetUnpackSize();
+ CByteBuffer &data = dataVector.AddNew();
+ UInt64 unpackSize64 = folders.GetFolderUnpackSize(i);
size_t unpackSize = (size_t)unpackSize64;
if (unpackSize != unpackSize64)
ThrowUnsupported();
- data.SetCapacity(unpackSize);
+ data.Alloc(unpackSize);
CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
@@ -829,43 +1068,35 @@ HRESULT CInArchive::ReadAndDecodePackedStreams(
HRESULT result = decoder.Decode(
EXTERNAL_CODECS_LOC_VARS
- _stream, dataStartPos,
- &packSizes[packIndex], folder, outStream, NULL
- #ifndef _NO_CRYPTO
- , getTextPassword, passwordIsDefined
- #endif
+ _stream, baseOffset + dataOffset,
+ folders, i,
+ outStream, NULL
+ _7Z_DECODER_CRYPRO_VARS
#if !defined(_7ZIP_ST) && !defined(_SFX)
, false, 1
#endif
);
RINOK(result);
- if (folder.UnpackCRCDefined)
- if (CrcCalc(data, unpackSize) != folder.UnpackCRC)
+ if (folders.FolderCRCs.ValidAndDefined(i))
+ if (CrcCalc(data, unpackSize) != folders.FolderCRCs.Vals[i])
ThrowIncorrect();
- for (int j = 0; j < folder.PackStreams.Size(); j++)
- {
- UInt64 packSize = packSizes[packIndex++];
- dataStartPos += packSize;
- HeadersSize += packSize;
- }
}
+ HeadersSize += folders.PackPositions[folders.NumPackStreams];
return S_OK;
}
HRESULT CInArchive::ReadHeader(
DECL_EXTERNAL_CODECS_LOC_VARS
- CArchiveDatabaseEx &db
- #ifndef _NO_CRYPTO
- , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
- #endif
+ CDbEx &db
+ _7Z_DECODER_CRYPRO_VARS_DECL
)
{
UInt64 type = ReadID();
if (type == NID::kArchiveProperties)
{
- ReadArchiveProperties(db.ArchiveInfo);
+ ReadArchiveProperties(db.ArcInfo);
type = ReadID();
}
@@ -875,70 +1106,53 @@ HRESULT CInArchive::ReadHeader(
{
HRESULT result = ReadAndDecodePackedStreams(
EXTERNAL_CODECS_LOC_VARS
- db.ArchiveInfo.StartPositionAfterHeader,
- db.ArchiveInfo.DataStartPosition2,
+ db.ArcInfo.StartPositionAfterHeader,
+ db.ArcInfo.DataStartPosition2,
dataVector
- #ifndef _NO_CRYPTO
- , getTextPassword, passwordIsDefined
- #endif
+ _7Z_DECODER_CRYPRO_VARS
);
RINOK(result);
- db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader;
+ db.ArcInfo.DataStartPosition2 += db.ArcInfo.StartPositionAfterHeader;
type = ReadID();
}
CRecordVector<UInt64> unpackSizes;
- CBoolVector digestsDefined;
- CRecordVector<UInt32> digests;
+ CUInt32DefVector digests;
if (type == NID::kMainStreamsInfo)
{
ReadStreamsInfo(&dataVector,
- db.ArchiveInfo.DataStartPosition,
- db.PackSizes,
- db.PackCRCsDefined,
- db.PackCRCs,
- db.Folders,
- db.NumUnpackStreamsVector,
+ db.ArcInfo.DataStartPosition,
+ (CFolders &)db,
unpackSizes,
- digestsDefined,
digests);
- db.ArchiveInfo.DataStartPosition += db.ArchiveInfo.StartPositionAfterHeader;
+ db.ArcInfo.DataStartPosition += db.ArcInfo.StartPositionAfterHeader;
type = ReadID();
}
- else
- {
- for (int i = 0; i < db.Folders.Size(); i++)
- {
- db.NumUnpackStreamsVector.Add(1);
- CFolder &folder = db.Folders[i];
- unpackSizes.Add(folder.GetUnpackSize());
- digestsDefined.Add(folder.UnpackCRCDefined);
- digests.Add(folder.UnpackCRC);
- }
- }
db.Files.Clear();
- if (type == NID::kEnd)
- return S_OK;
- if (type != NID::kFilesInfo)
- ThrowIncorrect();
+ if (type == NID::kFilesInfo)
+ {
CNum numFiles = ReadNum();
+ db.Files.ClearAndSetSize(numFiles);
+ CNum i;
+ /*
db.Files.Reserve(numFiles);
CNum i;
for (i = 0; i < numFiles; i++)
db.Files.Add(CFileItem());
+ */
- db.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize);
- if (!db.PackSizes.IsEmpty())
- db.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo);
- if (numFiles > 0 && !digests.IsEmpty())
- db.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC);
+ 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;
- BoolVector_Fill_False(emptyStreamVector, (int)numFiles);
+ BoolVector_Fill_False(emptyStreamVector, (unsigned)numFiles);
CBoolVector emptyFileVector;
CBoolVector antiFileVector;
CNum numEmptyStreams = 0;
@@ -949,7 +1163,10 @@ HRESULT CInArchive::ReadHeader(
if (type == NID::kEnd)
break;
UInt64 size = ReadNumber();
- size_t ppp = _inByteBack->_pos;
+ if (size > _inByteBack->GetRem())
+ ThrowIncorrect();
+ CStreamSwitch switchProp;
+ switchProp.Set(this, _inByteBack->GetPtr(), (size_t)size, true);
bool addPropIdToList = true;
bool isKnownType = true;
if (type > ((UInt32)1 << 30))
@@ -960,11 +1177,29 @@ HRESULT CInArchive::ReadHeader(
{
CStreamSwitch streamSwitch;
streamSwitch.Set(this, &dataVector);
- for (int i = 0; i < db.Files.Size(); i++)
- _inByteBack->ReadString(db.Files[i].Name);
+ size_t rem = _inByteBack->GetRem();
+ db.NamesBuf.Alloc(rem);
+ ReadBytes(db.NamesBuf, rem);
+ db.NameOffsets.Alloc(db.Files.Size() + 1);
+ size_t pos = 0;
+ unsigned i;
+ for (i = 0; i < db.Files.Size(); 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::kWinAttributes:
+ case NID::kWinAttrib:
{
CBoolVector boolVector;
ReadBoolVector2(db.Files.Size(), boolVector);
@@ -979,9 +1214,40 @@ HRESULT CInArchive::ReadHeader(
}
break;
}
+ /*
+ case NID::kIsAux:
+ {
+ ReadBoolVector(db.Files.Size(), db.IsAux);
+ break;
+ }
+ case NID::kParent:
+ {
+ db.IsTree = true;
+ // CBoolVector boolVector;
+ // ReadBoolVector2(db.Files.Size(), boolVector);
+ // CStreamSwitch streamSwitch;
+ // streamSwitch.Set(this, &dataVector);
+ CBoolVector boolVector;
+ ReadBoolVector2(db.Files.Size(), 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 = 0;
for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)
if (emptyStreamVector[i])
numEmptyStreams++;
@@ -993,34 +1259,83 @@ HRESULT CInArchive::ReadHeader(
}
case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break;
case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break;
- case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (int)numFiles); break;
- case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (int)numFiles); break;
- case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (int)numFiles); break;
- case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (int)numFiles); break;
+ case NID::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)
- ThrowIncorrect();
+ 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 < db.Files.Size(); 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.ArchiveInfo.FileInfoPopIDs.Add(type);
+ if (addPropIdToList)
+ db.ArcInfo.FileInfoPopIDs.Add(type);
}
else
- SkipData(size);
- bool checkRecordsSize = (db.ArchiveInfo.Version.Major > 0 ||
- db.ArchiveInfo.Version.Minor > 2);
- if (checkRecordsSize && _inByteBack->_pos - ppp != size)
+ {
+ db.UnsupportedFeatureWarning = true;
+ _inByteBack->SkipRem();
+ }
+ // SkipData worked incorrectly in some versions before v4.59 (7zVer <= 00.02)
+ if (_inByteBack->GetRem() != 0)
ThrowIncorrect();
}
+ type = ReadID(); // Read (NID::kEnd) end of headers
+
CNum emptyFileIndex = 0;
CNum sizeIndex = 0;
@@ -1034,13 +1349,15 @@ HRESULT CInArchive::ReadHeader(
CFileItem &file = db.Files[i];
bool isAnti;
file.HasStream = !emptyStreamVector[i];
+ file.Crc = 0;
if (file.HasStream)
{
file.IsDir = false;
isAnti = false;
file.Size = unpackSizes[sizeIndex];
- file.Crc = digests[sizeIndex];
- file.CrcDefined = digestsDefined[sizeIndex];
+ file.CrcDefined = digests.ValidAndDefined(sizeIndex);
+ if (file.CrcDefined)
+ file.Crc = digests.Vals[sizeIndex];
sizeIndex++;
}
else
@@ -1054,158 +1371,181 @@ HRESULT CInArchive::ReadHeader(
if (numAntiItems != 0)
db.IsAnti.Add(isAnti);
}
- return S_OK;
-}
-
-
-void CArchiveDatabaseEx::FillFolderStartPackStream()
-{
- FolderStartPackStreamIndex.Clear();
- FolderStartPackStreamIndex.Reserve(Folders.Size());
- CNum startPos = 0;
- for (int i = 0; i < Folders.Size(); i++)
- {
- FolderStartPackStreamIndex.Add(startPos);
- startPos += (CNum)Folders[i].PackStreams.Size();
- }
-}
-
-void CArchiveDatabaseEx::FillStartPos()
-{
- PackStreamStartPositions.Clear();
- PackStreamStartPositions.Reserve(PackSizes.Size());
- UInt64 startPos = 0;
- for (int i = 0; i < PackSizes.Size(); i++)
- {
- PackStreamStartPositions.Add(startPos);
- startPos += PackSizes[i];
}
+ db.FillLinks();
+ /*
+ if (type != NID::kEnd)
+ ThrowIncorrect();
+ if (_inByteBack->GetRem() != 0)
+ ThrowIncorrect();
+ */
+ return S_OK;
}
-void CArchiveDatabaseEx::FillFolderStartFileIndex()
+void CDbEx::FillLinks()
{
- FolderStartFileIndex.Clear();
- FolderStartFileIndex.Reserve(Folders.Size());
- FileIndexToFolderIndexMap.Clear();
- FileIndexToFolderIndexMap.Reserve(Files.Size());
+ FolderStartFileIndex.ClearAndSetSize(NumFolders);
- int folderIndex = 0;
+ FileIndexToFolderIndexMap.ClearAndSetSize(Files.Size());
+
+ CNum folderIndex = 0;
CNum indexInFolder = 0;
- for (int i = 0; i < Files.Size(); i++)
+ unsigned i;
+ for (i = 0; i < Files.Size(); i++)
{
- const CFileItem &file = Files[i];
- bool emptyStream = !file.HasStream;
- if (emptyStream && indexInFolder == 0)
- {
- FileIndexToFolderIndexMap.Add(kNumNoIndex);
- continue;
- }
+ bool emptyStream = !Files[i].HasStream;
if (indexInFolder == 0)
{
+ if (emptyStream)
+ {
+ FileIndexToFolderIndexMap[i] = kNumNoIndex;
+ continue;
+ }
// v3.13 incorrectly worked with empty folders
- // v4.07: Loop for skipping empty folders
+ // v4.07: we skip empty folders
for (;;)
{
- if (folderIndex >= Folders.Size())
+ if (folderIndex >= NumFolders)
ThrowIncorrect();
- FolderStartFileIndex.Add(i); // check it
+ FolderStartFileIndex[folderIndex] = i;
if (NumUnpackStreamsVector[folderIndex] != 0)
break;
folderIndex++;
}
}
- FileIndexToFolderIndexMap.Add(folderIndex);
+ FileIndexToFolderIndexMap[i] = folderIndex;
if (emptyStream)
continue;
- indexInFolder++;
- if (indexInFolder >= NumUnpackStreamsVector[folderIndex])
+ if (++indexInFolder >= NumUnpackStreamsVector[folderIndex])
{
folderIndex++;
indexInFolder = 0;
}
}
+
+ if (indexInFolder != 0)
+ folderIndex++;
+ /*
+ if (indexInFolder != 0)
+ ThrowIncorrect();
+ */
+ for (;;)
+ {
+ if (folderIndex >= NumFolders)
+ return;
+ FolderStartFileIndex[folderIndex] = i;
+ /*
+ if (NumUnpackStreamsVector[folderIndex] != 0)
+ ThrowIncorrect();;
+ */
+ folderIndex++;
+ }
}
HRESULT CInArchive::ReadDatabase2(
DECL_EXTERNAL_CODECS_LOC_VARS
- CArchiveDatabaseEx &db
- #ifndef _NO_CRYPTO
- , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
- #endif
+ CDbEx &db
+ _7Z_DECODER_CRYPRO_VARS_DECL
)
{
db.Clear();
- db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
+ db.ArcInfo.StartPosition = _arhiveBeginStreamPosition;
- db.ArchiveInfo.Version.Major = _header[6];
- db.ArchiveInfo.Version.Minor = _header[7];
+ db.ArcInfo.Version.Major = _header[6];
+ db.ArcInfo.Version.Minor = _header[7];
- if (db.ArchiveInfo.Version.Major != kMajorVersion)
- ThrowUnsupportedVersion();
+ if (db.ArcInfo.Version.Major != kMajorVersion)
+ {
+ // db.UnsupportedVersion = true;
+ return S_FALSE;
+ }
- UInt32 crcFromArchive = Get32(_header + 8);
- UInt64 nextHeaderOffset = Get64(_header + 0xC);
- UInt64 nextHeaderSize = Get64(_header + 0x14);
- UInt32 nextHeaderCRC = Get32(_header + 0x1C);
- UInt32 crc = CrcCalc(_header + 0xC, 20);
+ UInt64 nextHeaderOffset = Get64(_header + 12);
+ UInt64 nextHeaderSize = Get64(_header + 20);
+ UInt32 nextHeaderCRC = Get32(_header + 28);
#ifdef FORMAT_7Z_RECOVERY
- if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
+ UInt32 crcFromArc = Get32(_header + 8);
+ if (crcFromArc == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
{
- UInt64 cur, cur2;
+ UInt64 cur, fileSize;
RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));
- const int kCheckSize = 500;
+ const unsigned kCheckSize = 512;
Byte buf[kCheckSize];
- RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2));
- int checkSize = kCheckSize;
- if (cur2 - cur < kCheckSize)
- checkSize = (int)(cur2 - cur);
- RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2));
-
+ RINOK(_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));
- int i;
- for (i = (int)checkSize - 2; i >= 0; i--)
- if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)
- break;
- if (i < 0)
+ 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 = cur2 - cur + i;
+ nextHeaderOffset = rem - nextHeaderSize;
nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
+ db.StartHeaderWasRecovered = true;
}
else
#endif
{
- if (crc != crcFromArchive)
- ThrowIncorrect();
+ // Crc was tested already at signature check
+ // if (CrcCalc(_header + 12, 20) != crcFromArchive) ThrowIncorrect();
}
- db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
+ 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 (nextHeaderSize > (UInt64)(UInt32)0xFFFFFFFF)
- return S_FALSE;
-
- if ((Int64)nextHeaderOffset < 0)
- return S_FALSE;
-
- if (db.ArchiveInfo.StartPositionAfterHeader + nextHeaderOffset > _fileEndPosition)
+ }
+
+ 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));
- CByteBuffer buffer2;
- buffer2.SetCapacity((size_t)nextHeaderSize);
+ size_t nextHeaderSize_t = (size_t)nextHeaderSize;
+ if (nextHeaderSize_t != nextHeaderSize)
+ return E_OUTOFMEMORY;
+ CByteBuffer buffer2(nextHeaderSize_t);
- RINOK(ReadStream_FALSE(_stream, buffer2, (size_t)nextHeaderSize));
- HeadersSize += kHeaderSize + nextHeaderSize;
- db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize;
+ RINOK(ReadStream_FALSE(_stream, buffer2, nextHeaderSize_t));
- if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC)
+ if (CrcCalc(buffer2, nextHeaderSize_t) != nextHeaderCRC)
ThrowIncorrect();
+
+ if (!db.StartHeaderWasRecovered)
+ db.PhySizeWasConfirmed = true;
CStreamSwitch streamSwitch;
streamSwitch.Set(this, buffer2);
@@ -1219,12 +1559,10 @@ HRESULT CInArchive::ReadDatabase2(
ThrowIncorrect();
HRESULT result = ReadAndDecodePackedStreams(
EXTERNAL_CODECS_LOC_VARS
- db.ArchiveInfo.StartPositionAfterHeader,
- db.ArchiveInfo.DataStartPosition2,
+ db.ArcInfo.StartPositionAfterHeader,
+ db.ArcInfo.DataStartPosition2,
dataVector
- #ifndef _NO_CRYPTO
- , getTextPassword, passwordIsDefined
- #endif
+ _7Z_DECODER_CRYPRO_VARS
);
RINOK(result);
if (dataVector.Size() == 0)
@@ -1237,35 +1575,45 @@ HRESULT CInArchive::ReadDatabase2(
ThrowIncorrect();
}
+ db.IsArc = true;
+
db.HeadersSize = HeadersSize;
return ReadHeader(
EXTERNAL_CODECS_LOC_VARS
db
- #ifndef _NO_CRYPTO
- , getTextPassword, passwordIsDefined
- #endif
+ _7Z_DECODER_CRYPRO_VARS
);
}
HRESULT CInArchive::ReadDatabase(
DECL_EXTERNAL_CODECS_LOC_VARS
- CArchiveDatabaseEx &db
- #ifndef _NO_CRYPTO
- , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
- #endif
+ CDbEx &db
+ _7Z_DECODER_CRYPRO_VARS_DECL
)
{
try
{
- return ReadDatabase2(
+ HRESULT res = ReadDatabase2(
EXTERNAL_CODECS_LOC_VARS db
- #ifndef _NO_CRYPTO
- , getTextPassword, passwordIsDefined
- #endif
+ _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;
}
- catch(CInArchiveException &) { return S_FALSE; }
}
}}
diff --git a/CPP/7zip/Archive/7z/7zIn.h b/CPP/7zip/Archive/7z/7zIn.h
index 4305a8c5..1836a06b 100755..100644
--- a/CPP/7zip/Archive/7z/7zIn.h
+++ b/CPP/7zip/Archive/7z/7zIn.h
@@ -5,6 +5,8 @@
#include "../../../Common/MyCom.h"
+#include "../../../Windows/PropVariant.h"
+
#include "../../IPassword.h"
#include "../../IStream.h"
@@ -15,7 +17,147 @@
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
+#define _7Z_DECODER_CRYPRO_VARS , getTextPassword, isEncrypted, passwordIsDefined
+#endif
+
+struct CParsedMethods
+{
+ Byte Lzma2Prop;
+ UInt32 LzmaDic;
+ CRecordVector<UInt64> IDs;
+
+ CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {}
+};
+
+struct CFolders
+{
+ CNum NumPackStreams;
+ CNum NumFolders;
+
+ CObjArray<UInt64> PackPositions; // NumPackStreams + 1
+ // CUInt32DefVector PackCRCs; // we don't use PackCRCs now
+
+ CUInt32DefVector FolderCRCs; // NumFolders
+ CObjArray<CNum> NumUnpackStreamsVector; // NumFolders
+
+ CObjArray<UInt64> CoderUnpackSizes; // including unpack sizes of bind coders
+ CObjArray<CNum> FoToCoderUnpackSizes; // NumFolders + 1
+ CObjArray<CNum> FoStartPackStreamIndex; // NumFolders + 1
+ CObjArray<Byte> FoToMainUnpackSizeIndex; // NumFolders
+ CObjArray<size_t> FoCodersDataOffset; // NumFolders + 1
+ CByteBuffer CodersData;
+
+ CParsedMethods ParsedMethods;
+
+ void ParseFolderInfo(unsigned folderIndex, CFolder &folder) const;
+
+ unsigned GetNumFolderUnpackSizes(unsigned folderIndex) const
+ {
+ return 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];
+ }
+
+ void Clear()
+ {
+ NumPackStreams = 0;
+ PackPositions.Free();
+ // PackCRCs.Clear();
+
+ NumFolders = 0;
+ FolderCRCs.Clear();
+ NumUnpackStreamsVector.Free();
+ CoderUnpackSizes.Free();
+ FoToCoderUnpackSizes.Free();
+ FoStartPackStreamIndex.Free();
+ FoToMainUnpackSizeIndex.Free();
+ FoCodersDataOffset.Free();
+ CodersData.Free();
+ }
+};
+
+struct CDatabase: public CFolders
+{
+ CRecordVector<CFileItem> Files;
+
+ CUInt64DefVector CTime;
+ CUInt64DefVector ATime;
+ CUInt64DefVector MTime;
+ CUInt64DefVector StartPos;
+ CRecordVector<bool> IsAnti;
+ /*
+ CRecordVector<bool> IsAux;
+ CByteBuffer SecureBuf;
+ CRecordVector<UInt32> SecureIDs;
+ */
+
+ CByteBuffer NamesBuf;
+ CObjArray<size_t> NameOffsets; // numFiles + 1, conatins offsets of UINt16 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();
+ 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 wchar_t * GetName(unsigned index) const
+ {
+ if (!NameOffsets || !NamesBuf)
+ return NULL;
+ return (const wchar_t *)(const Byte *)NamesBuf + NameOffsets[index];
+ };
+
+ HRESULT GetPath(unsigned index, PROPVARIANT *path) const;
+};
+
struct CInArchiveInfo
{
CArchiveVersion Version;
@@ -24,29 +166,73 @@ struct CInArchiveInfo
UInt64 DataStartPosition;
UInt64 DataStartPosition2;
CRecordVector<UInt64> FileInfoPopIDs;
+
void Clear()
{
+ StartPosition = 0;
+ StartPositionAfterHeader = 0;
+ DataStartPosition = 0;
+ DataStartPosition2 = 0;
FileInfoPopIDs.Clear();
}
};
-struct CArchiveDatabaseEx: public CArchiveDatabase
+struct CDbEx: public CDatabase
{
- CInArchiveInfo ArchiveInfo;
- CRecordVector<UInt64> PackStreamStartPositions;
- CRecordVector<CNum> FolderStartPackStreamIndex;
+ CInArchiveInfo ArcInfo;
CRecordVector<CNum> FolderStartFileIndex;
CRecordVector<CNum> FileIndexToFolderIndexMap;
UInt64 HeadersSize;
UInt64 PhySize;
+ /*
+ CRecordVector<size_t> SecureOffsets;
+ bool IsTree;
+ bool ThereAreAltStreams;
+ */
+
+ bool IsArc;
+ bool PhySizeWasConfirmed;
+
+ bool ThereIsHeaderError;
+ bool UnexpectedEnd;
+ // bool UnsupportedVersion;
+
+ bool StartHeaderWasRecovered;
+ bool UnsupportedFeatureWarning;
+ bool UnsupportedFeatureError;
+
+ /*
+ void ClearSecureEx()
+ {
+ ClearSecure();
+ SecureOffsets.Clear();
+ }
+ */
+
void Clear()
{
- CArchiveDatabase::Clear();
- ArchiveInfo.Clear();
- PackStreamStartPositions.Clear();
- FolderStartPackStreamIndex.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.Clear();
FileIndexToFolderIndexMap.Clear();
@@ -54,36 +240,25 @@ struct CArchiveDatabaseEx: public CArchiveDatabase
PhySize = 0;
}
- void FillFolderStartPackStream();
- void FillStartPos();
- void FillFolderStartFileIndex();
-
- void Fill()
- {
- FillFolderStartPackStream();
- FillStartPos();
- FillFolderStartFileIndex();
- }
+ void FillLinks();
- UInt64 GetFolderStreamPos(int folderIndex, int indexInFolder) const
+ UInt64 GetFolderStreamPos(unsigned folderIndex, unsigned indexInFolder) const
{
- return ArchiveInfo.DataStartPosition +
- PackStreamStartPositions[FolderStartPackStreamIndex[folderIndex] + indexInFolder];
+ return ArcInfo.DataStartPosition +
+ PackPositions[FoStartPackStreamIndex[folderIndex] + indexInFolder];
}
- UInt64 GetFolderFullPackSize(int folderIndex) const
+ UInt64 GetFolderFullPackSize(unsigned folderIndex) const
{
- CNum packStreamIndex = FolderStartPackStreamIndex[folderIndex];
- const CFolder &folder = Folders[folderIndex];
- UInt64 size = 0;
- for (int i = 0; i < folder.PackStreams.Size(); i++)
- size += PackSizes[packStreamIndex + i];
- return size;
+ return
+ PackPositions[FoStartPackStreamIndex[folderIndex + 1]] -
+ PackPositions[FoStartPackStreamIndex[folderIndex]];
}
- UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const
+ UInt64 GetFolderPackStreamSize(unsigned folderIndex, unsigned streamIndex) const
{
- return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
+ unsigned i = FoStartPackStreamIndex[folderIndex] + streamIndex;
+ return PackPositions[i + 1] - PackPositions[i];
}
UInt64 GetFilePackSize(CNum fileIndex) const
@@ -96,12 +271,17 @@ struct CArchiveDatabaseEx: public CArchiveDatabase
}
};
-class CInByte2
+const unsigned kNumBufLevelsMax = 4;
+
+struct CInByte2
{
const Byte *_buffer;
- size_t _size;
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;
@@ -110,13 +290,17 @@ public:
}
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 ReadString(UString &s);
+
+ void ParseFolder(CFolder &folder);
};
class CStreamSwitch;
@@ -129,8 +313,11 @@ class CInArchive
CMyComPtr<IInStream> _stream;
- CObjectVector<CInByte2> _inByteVector;
+ unsigned _numInByteBufs;
+ CInByte2 _inByteVector[kNumBufLevelsMax];
+
CInByte2 *_inByteBack;
+ bool ThereIsHeaderError;
UInt64 _arhiveBeginStreamPosition;
UInt64 _fileEndPosition;
@@ -139,18 +326,17 @@ class CInArchive
UInt64 HeadersSize;
- void AddByteStream(const Byte *buffer, size_t size)
- {
- _inByteVector.Add(CInByte2());
- _inByteBack = &_inByteVector.Back();
- _inByteBack->Init(buffer, size);
- }
+ void AddByteStream(const Byte *buffer, size_t size);
- void DeleteByteStream()
+ void DeleteByteStream(bool needUpdatePos)
{
- _inByteVector.DeleteBack();
- if (!_inByteVector.IsEmpty())
- _inByteBack = &_inByteVector.Back();
+ _numInByteBufs--;
+ if (_numInByteBufs > 0)
+ {
+ _inByteBack = &_inByteVector[_numInByteBufs - 1];
+ if (needUpdatePos)
+ _inByteBack->_pos += _inByteVector[_numInByteBufs]._pos;
+ }
}
private:
@@ -165,79 +351,58 @@ private:
UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); }
void SkipData(UInt64 size) { _inByteBack->SkipData(size); }
void SkipData() { _inByteBack->SkipData(); }
- void WaitAttribute(UInt64 attribute);
+ void WaitId(UInt64 id);
void ReadArchiveProperties(CInArchiveInfo &archiveInfo);
- void GetNextFolderItem(CFolder &itemInfo);
- void ReadHashDigests(int numItems,
- CBoolVector &digestsDefined, CRecordVector<UInt32> &digests);
+ void ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs);
- void ReadPackInfo(
- UInt64 &dataOffset,
- CRecordVector<UInt64> &packSizes,
- CBoolVector &packCRCsDefined,
- CRecordVector<UInt32> &packCRCs);
+ void ReadPackInfo(CFolders &f);
void ReadUnpackInfo(
const CObjectVector<CByteBuffer> *dataVector,
- CObjectVector<CFolder> &folders);
+ CFolders &folders);
void ReadSubStreamsInfo(
- const CObjectVector<CFolder> &folders,
- CRecordVector<CNum> &numUnpackStreamsInFolders,
+ CFolders &folders,
CRecordVector<UInt64> &unpackSizes,
- CBoolVector &digestsDefined,
- CRecordVector<UInt32> &digests);
+ CUInt32DefVector &digests);
void ReadStreamsInfo(
const CObjectVector<CByteBuffer> *dataVector,
UInt64 &dataOffset,
- CRecordVector<UInt64> &packSizes,
- CBoolVector &packCRCsDefined,
- CRecordVector<UInt32> &packCRCs,
- CObjectVector<CFolder> &folders,
- CRecordVector<CNum> &numUnpackStreamsInFolders,
+ CFolders &folders,
CRecordVector<UInt64> &unpackSizes,
- CBoolVector &digestsDefined,
- CRecordVector<UInt32> &digests);
-
+ CUInt32DefVector &digests);
- void ReadBoolVector(int numItems, CBoolVector &v);
- void ReadBoolVector2(int numItems, CBoolVector &v);
+ void ReadBoolVector(unsigned numItems, CBoolVector &v);
+ void ReadBoolVector2(unsigned numItems, CBoolVector &v);
void ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
- CUInt64DefVector &v, int numFiles);
+ CUInt64DefVector &v, unsigned numItems);
HRESULT ReadAndDecodePackedStreams(
DECL_EXTERNAL_CODECS_LOC_VARS
UInt64 baseOffset, UInt64 &dataOffset,
CObjectVector<CByteBuffer> &dataVector
- #ifndef _NO_CRYPTO
- , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
- #endif
+ _7Z_DECODER_CRYPRO_VARS_DECL
);
HRESULT ReadHeader(
DECL_EXTERNAL_CODECS_LOC_VARS
- CArchiveDatabaseEx &db
- #ifndef _NO_CRYPTO
- ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
- #endif
+ CDbEx &db
+ _7Z_DECODER_CRYPRO_VARS_DECL
);
HRESULT ReadDatabase2(
DECL_EXTERNAL_CODECS_LOC_VARS
- CArchiveDatabaseEx &db
- #ifndef _NO_CRYPTO
- ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
- #endif
+ CDbEx &db
+ _7Z_DECODER_CRYPRO_VARS_DECL
);
public:
+ CInArchive(): _numInByteBufs(0) { }
HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive
void Close();
HRESULT ReadDatabase(
DECL_EXTERNAL_CODECS_LOC_VARS
- CArchiveDatabaseEx &db
- #ifndef _NO_CRYPTO
- ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
- #endif
+ CDbEx &db
+ _7Z_DECODER_CRYPRO_VARS_DECL
);
};
diff --git a/CPP/7zip/Archive/7z/7zItem.h b/CPP/7zip/Archive/7z/7zItem.h
index 34f10775..02a86196 100755..100644
--- a/CPP/7zip/Archive/7z/7zItem.h
+++ b/CPP/7zip/Archive/7z/7zItem.h
@@ -3,7 +3,7 @@
#ifndef __7Z_ITEM_H
#define __7Z_ITEM_H
-#include "../../../Common/Buffer.h"
+#include "../../../Common/MyBuffer.h"
#include "../../../Common/MyString.h"
#include "../../Common/MethodId.h"
@@ -25,6 +25,7 @@ struct CCoderInfo
CByteBuffer Props;
CNum NumInStreams;
CNum NumOutStreams;
+
bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); }
};
@@ -36,55 +37,48 @@ struct CBindPair
struct CFolder
{
- CObjectVector<CCoderInfo> Coders;
- CRecordVector<CBindPair> BindPairs;
- CRecordVector<CNum> PackStreams;
- CRecordVector<UInt64> UnpackSizes;
- UInt32 UnpackCRC;
- bool UnpackCRCDefined;
-
- CFolder(): UnpackCRCDefined(false) {}
-
- UInt64 GetUnpackSize() const // test it
- {
- if (UnpackSizes.IsEmpty())
- return 0;
- for (int i = UnpackSizes.Size() - 1; i >= 0; i--)
- if (FindBindPairForOutStream(i) < 0)
- return UnpackSizes[i];
- throw 1;
- }
+ CObjArray2<CCoderInfo> Coders;
+ CObjArray2<CBindPair> BindPairs;
+ CObjArray2<CNum> PackStreams;
CNum GetNumOutStreams() const
{
CNum result = 0;
- for (int i = 0; i < Coders.Size(); i++)
+ FOR_VECTOR(i, Coders)
result += Coders[i].NumOutStreams;
return result;
}
int FindBindPairForInStream(CNum inStreamIndex) const
{
- for(int i = 0; i < BindPairs.Size(); i++)
+ FOR_VECTOR(i, BindPairs)
if (BindPairs[i].InIndex == inStreamIndex)
return i;
return -1;
}
int FindBindPairForOutStream(CNum outStreamIndex) const
{
- for(int i = 0; i < BindPairs.Size(); i++)
+ FOR_VECTOR(i, BindPairs)
if (BindPairs[i].OutIndex == outStreamIndex)
return i;
return -1;
}
int FindPackStreamArrayIndex(CNum inStreamIndex) const
{
- for(int i = 0; i < PackStreams.Size(); i++)
+ FOR_VECTOR(i, PackStreams)
if (PackStreams[i] == inStreamIndex)
return i;
return -1;
}
+ int GetIndexOfMainOutStream() const
+ {
+ for (int i = (int)GetNumOutStreams() - 1; i >= 0; i--)
+ if (FindBindPairForOutStream(i) < 0)
+ return i;
+ throw 1;
+ }
+
bool IsEncrypted() const
{
for (int i = Coders.Size() - 1; i >= 0; i--)
@@ -93,50 +87,66 @@ struct CFolder
return false;
}
- bool CheckStructure() const;
+ bool CheckStructure(unsigned numUnpackSizes) const;
+};
+
+struct CUInt32DefVector
+{
+ CBoolVector Defs;
+ CRecordVector<UInt32> Vals;
+
+ void ClearAndSetSize(unsigned newSize)
+ {
+ Defs.ClearAndSetSize(newSize);
+ Vals.ClearAndSetSize(newSize);
+ }
+
+ void Clear()
+ {
+ Defs.Clear();
+ Vals.Clear();
+ }
+
+ void ReserveDown()
+ {
+ Defs.ReserveDown();
+ Vals.ReserveDown();
+ }
+
+ bool ValidAndDefined(unsigned i) const { return i < Defs.Size() && Defs[i]; }
};
struct CUInt64DefVector
{
- CRecordVector<UInt64> Values;
- CRecordVector<bool> Defined;
+ CBoolVector Defs;
+ CRecordVector<UInt64> Vals;
void Clear()
{
- Values.Clear();
- Defined.Clear();
+ Defs.Clear();
+ Vals.Clear();
}
void ReserveDown()
{
- Values.ReserveDown();
- Values.ReserveDown();
+ Defs.ReserveDown();
+ Vals.ReserveDown();
}
- bool GetItem(int index, UInt64 &value) const
+ bool GetItem(unsigned index, UInt64 &value) const
{
- if (index < Defined.Size() && Defined[index])
+ if (index < Defs.Size() && Defs[index])
{
- value = Values[index];
+ value = Vals[index];
return true;
}
value = 0;
return false;
}
- void SetItem(int index, bool defined, UInt64 value)
- {
- while (index >= Defined.Size())
- Defined.Add(false);
- Defined[index] = defined;
- if (!defined)
- return;
- while (index >= Values.Size())
- Values.Add(0);
- Values[index] = value;
- }
+ void SetItem(unsigned index, bool defined, UInt64 value);
- bool CheckSize(int size) const { return Defined.Size() == size || Defined.Size() == 0; }
+ bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; }
};
struct CFileItem
@@ -144,8 +154,10 @@ struct CFileItem
UInt64 Size;
UInt32 Attrib;
UInt32 Crc;
- UString Name;
-
+ /*
+ int Parent;
+ bool IsAltStream;
+ */
bool HasStream; // Test it !!! it means that there is
// stream in some folder. It can be empty stream
bool IsDir;
@@ -153,6 +165,10 @@ struct CFileItem
bool AttribDefined;
CFileItem():
+ /*
+ Parent(-1),
+ IsAltStream(false),
+ */
HasStream(true),
IsDir(false),
CrcDefined(false),
@@ -165,104 +181,6 @@ struct CFileItem
}
};
-struct CFileItem2
-{
- UInt64 CTime;
- UInt64 ATime;
- UInt64 MTime;
- UInt64 StartPos;
- bool CTimeDefined;
- bool ATimeDefined;
- bool MTimeDefined;
- bool StartPosDefined;
- bool IsAnti;
-};
-
-struct CArchiveDatabase
-{
- CRecordVector<UInt64> PackSizes;
- CRecordVector<bool> PackCRCsDefined;
- CRecordVector<UInt32> PackCRCs;
- CObjectVector<CFolder> Folders;
- CRecordVector<CNum> NumUnpackStreamsVector;
- CObjectVector<CFileItem> Files;
-
- CUInt64DefVector CTime;
- CUInt64DefVector ATime;
- CUInt64DefVector MTime;
- CUInt64DefVector StartPos;
- CRecordVector<bool> IsAnti;
-
- void Clear()
- {
- PackSizes.Clear();
- PackCRCsDefined.Clear();
- PackCRCs.Clear();
- Folders.Clear();
- NumUnpackStreamsVector.Clear();
- Files.Clear();
- CTime.Clear();
- ATime.Clear();
- MTime.Clear();
- StartPos.Clear();
- IsAnti.Clear();
- }
-
- void ReserveDown()
- {
- PackSizes.ReserveDown();
- PackCRCsDefined.ReserveDown();
- PackCRCs.ReserveDown();
- Folders.ReserveDown();
- NumUnpackStreamsVector.ReserveDown();
- Files.ReserveDown();
- CTime.ReserveDown();
- ATime.ReserveDown();
- MTime.ReserveDown();
- StartPos.ReserveDown();
- IsAnti.ReserveDown();
- }
-
- bool IsEmpty() const
- {
- return (PackSizes.IsEmpty() &&
- PackCRCsDefined.IsEmpty() &&
- PackCRCs.IsEmpty() &&
- Folders.IsEmpty() &&
- NumUnpackStreamsVector.IsEmpty() &&
- Files.IsEmpty());
- }
-
- bool CheckNumFiles() const
- {
- int size = Files.Size();
- return (
- CTime.CheckSize(size) &&
- ATime.CheckSize(size) &&
- MTime.CheckSize(size) &&
- StartPos.CheckSize(size) &&
- (size == IsAnti.Size() || IsAnti.Size() == 0));
- }
-
- bool IsSolid() const
- {
- for (int i = 0; i < NumUnpackStreamsVector.Size(); i++)
- if (NumUnpackStreamsVector[i] > 1)
- return true;
- return false;
- }
- bool IsItemAnti(int index) const { return (index < IsAnti.Size() && IsAnti[index]); }
- void SetItemAnti(int index, bool isAnti)
- {
- while (index >= IsAnti.Size())
- IsAnti.Add(false);
- IsAnti[index] = isAnti;
- }
-
- void GetFile(int index, CFileItem &file, CFileItem2 &file2) const;
- void AddFile(const CFileItem &file, const CFileItem2 &file2);
-};
-
}}
#endif
diff --git a/CPP/7zip/Archive/7z/7zOut.cpp b/CPP/7zip/Archive/7z/7zOut.cpp
index 0c8aa7e8..9ff97595 100755..100644
--- a/CPP/7zip/Archive/7z/7zOut.cpp
+++ b/CPP/7zip/Archive/7z/7zOut.cpp
@@ -10,35 +10,15 @@
#include "7zOut.h"
-static HRESULT WriteBytes(ISequentialOutStream *stream, const void *data, size_t size)
-{
- while (size > 0)
- {
- UInt32 curSize = (UInt32)MyMin(size, (size_t)0xFFFFFFFF);
- UInt32 processedSize;
- RINOK(stream->Write(data, curSize, &processedSize));
- if (processedSize == 0)
- return E_FAIL;
- data = (const void *)((const Byte *)data + processedSize);
- size -= processedSize;
- }
- return S_OK;
-}
-
namespace NArchive {
namespace N7z {
-HRESULT COutArchive::WriteDirect(const void *data, UInt32 size)
-{
- return ::WriteBytes(SeqStream, data, size);
-}
-
HRESULT COutArchive::WriteSignature()
{
Byte buf[8];
memcpy(buf, kSignature, kSignatureSize);
buf[kSignatureSize] = kMajorVersion;
- buf[kSignatureSize + 1] = 3;
+ buf[kSignatureSize + 1] = 4;
return WriteDirect(buf, 8);
}
@@ -145,7 +125,9 @@ HRESULT COutArchive::SkipPrefixArchiveHeader()
if (_endMarker)
return S_OK;
#endif
- return Stream->Seek(24, STREAM_SEEK_CUR, NULL);
+ Byte buf[24];
+ memset(buf, 0, 24);
+ return WriteDirect(buf, 24);
}
UInt64 COutArchive::GetPos() const
@@ -271,19 +253,19 @@ UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props)
void COutArchive::WriteFolder(const CFolder &folder)
{
WriteNumber(folder.Coders.Size());
- int i;
+ unsigned i;
for (i = 0; i < folder.Coders.Size(); i++)
{
const CCoderInfo &coder = folder.Coders[i];
{
- size_t propsSize = coder.Props.GetCapacity();
+ size_t propsSize = coder.Props.Size();
UInt64 id = coder.MethodID;
int idSize;
for (idSize = 1; idSize < sizeof(id); idSize++)
if ((id >> (8 * idSize)) == 0)
break;
- BYTE longID[15];
+ Byte longID[15];
for (int t = idSize - 1; t >= 0 ; t--, id >>= 8)
longID[t] = (Byte)(id & 0xFF);
Byte b;
@@ -321,7 +303,7 @@ void COutArchive::WriteBoolVector(const CBoolVector &boolVector)
{
Byte b = 0;
Byte mask = 0x80;
- for (int i = 0; i < boolVector.Size(); i++)
+ FOR_VECTOR (i, boolVector)
{
if (boolVector[i])
b |= mask;
@@ -337,37 +319,42 @@ void COutArchive::WriteBoolVector(const CBoolVector &boolVector)
WriteByte(b);
}
+static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; }
-void COutArchive::WriteHashDigests(
- const CRecordVector<bool> &digestsDefined,
- const CRecordVector<UInt32> &digests)
+void COutArchive::WritePropBoolVector(Byte id, const CBoolVector &boolVector)
{
- int numDefined = 0;
- int i;
- for (i = 0; i < digestsDefined.Size(); i++)
- if (digestsDefined[i])
+ WriteByte(id);
+ WriteNumber(Bv_GetSizeInBytes(boolVector));
+ WriteBoolVector(boolVector);
+}
+
+void COutArchive::WriteHashDigests(const CUInt32DefVector &digests)
+{
+ unsigned numDefined = 0;
+ unsigned i;
+ for (i = 0; i < digests.Defs.Size(); i++)
+ if (digests.Defs[i])
numDefined++;
if (numDefined == 0)
return;
WriteByte(NID::kCRC);
- if (numDefined == digestsDefined.Size())
+ if (numDefined == digests.Defs.Size())
WriteByte(1);
else
{
WriteByte(0);
- WriteBoolVector(digestsDefined);
+ WriteBoolVector(digests.Defs);
}
- for (i = 0; i < digests.Size(); i++)
- if (digestsDefined[i])
- WriteUInt32(digests[i]);
+ for (i = 0; i < digests.Defs.Size(); i++)
+ if (digests.Defs[i])
+ WriteUInt32(digests.Vals[i]);
}
void COutArchive::WritePackInfo(
UInt64 dataOffset,
const CRecordVector<UInt64> &packSizes,
- const CRecordVector<bool> &packCRCsDefined,
- const CRecordVector<UInt32> &packCRCs)
+ const CUInt32DefVector &packCRCs)
{
if (packSizes.IsEmpty())
return;
@@ -375,15 +362,15 @@ void COutArchive::WritePackInfo(
WriteNumber(dataOffset);
WriteNumber(packSizes.Size());
WriteByte(NID::kSize);
- for (int i = 0; i < packSizes.Size(); i++)
+ FOR_VECTOR (i, packSizes)
WriteNumber(packSizes[i]);
- WriteHashDigests(packCRCsDefined, packCRCs);
+ WriteHashDigests(packCRCs);
WriteByte(NID::kEnd);
}
-void COutArchive::WriteUnpackInfo(const CObjectVector<CFolder> &folders)
+void COutArchive::WriteUnpackInfo(const CObjectVector<CFolder> &folders, const COutFolders &outFolders)
{
if (folders.IsEmpty())
return;
@@ -394,44 +381,29 @@ void COutArchive::WriteUnpackInfo(const CObjectVector<CFolder> &folders)
WriteNumber(folders.Size());
{
WriteByte(0);
- for (int i = 0; i < folders.Size(); i++)
+ FOR_VECTOR (i, folders)
WriteFolder(folders[i]);
}
WriteByte(NID::kCodersUnpackSize);
- int i;
- for (i = 0; i < folders.Size(); i++)
- {
- const CFolder &folder = folders[i];
- for (int j = 0; j < folder.UnpackSizes.Size(); j++)
- WriteNumber(folder.UnpackSizes[j]);
- }
-
- CRecordVector<bool> unpackCRCsDefined;
- CRecordVector<UInt32> unpackCRCs;
- for (i = 0; i < folders.Size(); i++)
- {
- const CFolder &folder = folders[i];
- unpackCRCsDefined.Add(folder.UnpackCRCDefined);
- unpackCRCs.Add(folder.UnpackCRC);
- }
- WriteHashDigests(unpackCRCsDefined, unpackCRCs);
-
+ FOR_VECTOR (i, outFolders.CoderUnpackSizes)
+ WriteNumber(outFolders.CoderUnpackSizes[i]);
+
+ WriteHashDigests(outFolders.FolderUnpackCRCs);
+
WriteByte(NID::kEnd);
}
-void COutArchive::WriteSubStreamsInfo(
- const CObjectVector<CFolder> &folders,
- const CRecordVector<CNum> &numUnpackStreamsInFolders,
+void COutArchive::WriteSubStreamsInfo(const CObjectVector<CFolder> &folders,
+ const COutFolders &outFolders,
const CRecordVector<UInt64> &unpackSizes,
- const CRecordVector<bool> &digestsDefined,
- const CRecordVector<UInt32> &digests)
+ const CUInt32DefVector &digests)
{
+ const CRecordVector<CNum> &numUnpackStreamsInFolders = outFolders.NumUnpackStreamsVector;
WriteByte(NID::kSubStreamsInfo);
- int i;
+ unsigned i;
for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
- {
if (numUnpackStreamsInFolders[i] != 1)
{
WriteByte(NID::kNumUnpackStream);
@@ -439,54 +411,50 @@ void COutArchive::WriteSubStreamsInfo(
WriteNumber(numUnpackStreamsInFolders[i]);
break;
}
- }
-
- bool needFlag = true;
- CNum index = 0;
for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
- for (CNum j = 0; j < numUnpackStreamsInFolders[i]; j++)
+ if (numUnpackStreamsInFolders[i] > 1)
{
- if (j + 1 != numUnpackStreamsInFolders[i])
+ WriteByte(NID::kSize);
+ CNum index = 0;
+ for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
{
- if (needFlag)
- WriteByte(NID::kSize);
- needFlag = false;
- WriteNumber(unpackSizes[index]);
+ CNum num = numUnpackStreamsInFolders[i];
+ for (CNum j = 0; j < num; j++)
+ {
+ if (j + 1 != num)
+ WriteNumber(unpackSizes[index]);
+ index++;
+ }
}
- index++;
+ break;
}
- CRecordVector<bool> digestsDefined2;
- CRecordVector<UInt32> digests2;
+ CUInt32DefVector digests2;
- int digestIndex = 0;
+ unsigned digestIndex = 0;
for (i = 0; i < folders.Size(); i++)
{
- int numSubStreams = (int)numUnpackStreamsInFolders[i];
- if (numSubStreams == 1 && folders[i].UnpackCRCDefined)
+ unsigned numSubStreams = (unsigned)numUnpackStreamsInFolders[i];
+ if (numSubStreams == 1 && outFolders.FolderUnpackCRCs.ValidAndDefined(i))
digestIndex++;
else
- for (int j = 0; j < numSubStreams; j++, digestIndex++)
+ for (unsigned j = 0; j < numSubStreams; j++, digestIndex++)
{
- digestsDefined2.Add(digestsDefined[digestIndex]);
- digests2.Add(digests[digestIndex]);
+ digests2.Defs.Add(digests.Defs[digestIndex]);
+ digests2.Vals.Add(digests.Vals[digestIndex]);
}
}
- WriteHashDigests(digestsDefined2, digests2);
+ WriteHashDigests(digests2);
WriteByte(NID::kEnd);
}
-void COutArchive::SkipAlign(unsigned /* pos */, unsigned /* alignSize */)
-{
- return;
-}
-
-/*
-7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field.
+// 7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field.
void COutArchive::SkipAlign(unsigned pos, unsigned alignSize)
{
+ if (!_useAlign)
+ return;
pos += (unsigned)GetPos();
pos &= (alignSize - 1);
if (pos == 0)
@@ -500,11 +468,8 @@ void COutArchive::SkipAlign(unsigned pos, unsigned alignSize)
for (unsigned i = 0; i < skip; i++)
WriteByte(0);
}
-*/
-
-static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; }
-void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, Byte type, unsigned itemSize)
+void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize)
{
const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v);
const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2;
@@ -524,48 +489,53 @@ void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, B
void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type)
{
- int numDefined = 0;
+ unsigned numDefined = 0;
- int i;
- for (i = 0; i < v.Defined.Size(); i++)
- if (v.Defined[i])
+ unsigned i;
+ for (i = 0; i < v.Defs.Size(); i++)
+ if (v.Defs[i])
numDefined++;
if (numDefined == 0)
return;
- WriteAlignedBoolHeader(v.Defined, numDefined, type, 8);
+ WriteAlignedBoolHeader(v.Defs, numDefined, type, 8);
- for (i = 0; i < v.Defined.Size(); i++)
- if (v.Defined[i])
- WriteUInt64(v.Values[i]);
+ for (i = 0; i < v.Defs.Size(); i++)
+ if (v.Defs[i])
+ WriteUInt64(v.Vals[i]);
}
HRESULT COutArchive::EncodeStream(
DECL_EXTERNAL_CODECS_LOC_VARS
CEncoder &encoder, const CByteBuffer &data,
- CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders)
+ CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders, COutFolders &outFolders)
{
CBufInStream *streamSpec = new CBufInStream;
CMyComPtr<ISequentialInStream> stream = streamSpec;
- streamSpec->Init(data, data.GetCapacity());
- CFolder folderItem;
- folderItem.UnpackCRCDefined = true;
- folderItem.UnpackCRC = CrcCalc(data, data.GetCapacity());
- UInt64 dataSize64 = data.GetCapacity();
+ 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;
RINOK(encoder.Encode(
EXTERNAL_CODECS_LOC_VARS
- stream, NULL, &dataSize64, folderItem, SeqStream, packSizes, NULL))
- folders.Add(folderItem);
+ stream, NULL, &dataSize64, folders.AddNew(), outFolders.CoderUnpackSizes, unpackSize, SeqStream, packSizes, NULL))
return S_OK;
}
void COutArchive::WriteHeader(
- const CArchiveDatabase &db,
- const CHeaderOptions &headerOptions,
+ const CArchiveDatabaseOut &db,
+ // const CHeaderOptions &headerOptions,
UInt64 &headerOffset)
{
- int i;
+ /*
+ bool thereIsSecure = (db.SecureBuf.Size() != 0);
+ */
+ _useAlign = true;
+
+ unsigned i;
UInt64 packedSize = 0;
for (i = 0; i < db.PackSizes.Size(); i++)
@@ -580,31 +550,22 @@ void COutArchive::WriteHeader(
if (db.Folders.Size() > 0)
{
WriteByte(NID::kMainStreamsInfo);
- WritePackInfo(0, db.PackSizes,
- db.PackCRCsDefined,
- db.PackCRCs);
-
- WriteUnpackInfo(db.Folders);
+ WritePackInfo(0, db.PackSizes, db.PackCRCs);
+ WriteUnpackInfo(db.Folders, (const COutFolders &)db);
CRecordVector<UInt64> unpackSizes;
- CRecordVector<bool> digestsDefined;
- CRecordVector<UInt32> digests;
+ CUInt32DefVector digests;
for (i = 0; i < db.Files.Size(); i++)
{
const CFileItem &file = db.Files[i];
if (!file.HasStream)
continue;
unpackSizes.Add(file.Size);
- digestsDefined.Add(file.CrcDefined);
- digests.Add(file.Crc);
+ digests.Defs.Add(file.CrcDefined);
+ digests.Vals.Add(file.Crc);
}
- WriteSubStreamsInfo(
- db.Folders,
- db.NumUnpackStreamsVector,
- unpackSizes,
- digestsDefined,
- digests);
+ WriteSubStreamsInfo(db.Folders, (const COutFolders &)db, unpackSizes, digests);
WriteByte(NID::kEnd);
}
@@ -618,85 +579,75 @@ void COutArchive::WriteHeader(
WriteNumber(db.Files.Size());
{
- /* ---------- Empty Streams ---------- */
- CBoolVector emptyStreamVector;
- emptyStreamVector.Reserve(db.Files.Size());
- int numEmptyStreams = 0;
- for (i = 0; i < db.Files.Size(); i++)
- if (db.Files[i].HasStream)
- emptyStreamVector.Add(false);
- else
- {
- emptyStreamVector.Add(true);
- numEmptyStreams++;
- }
- if (numEmptyStreams > 0)
- {
- WriteByte(NID::kEmptyStream);
- WriteNumber(Bv_GetSizeInBytes(emptyStreamVector));
- WriteBoolVector(emptyStreamVector);
-
- CBoolVector emptyFileVector, antiVector;
- emptyFileVector.Reserve(numEmptyStreams);
- antiVector.Reserve(numEmptyStreams);
- CNum numEmptyFiles = 0, numAntiItems = 0;
+ /* ---------- Empty Streams ---------- */
+ CBoolVector emptyStreamVector;
+ emptyStreamVector.ClearAndSetSize(db.Files.Size());
+ unsigned numEmptyStreams = 0;
for (i = 0; i < db.Files.Size(); i++)
+ if (db.Files[i].HasStream)
+ emptyStreamVector[i] = false;
+ else
+ {
+ emptyStreamVector[i] = true;
+ numEmptyStreams++;
+ }
+ if (numEmptyStreams != 0)
{
- const CFileItem &file = db.Files[i];
- if (!file.HasStream)
+ WritePropBoolVector(NID::kEmptyStream, emptyStreamVector);
+
+ CBoolVector emptyFileVector, antiVector;
+ emptyFileVector.ClearAndSetSize(numEmptyStreams);
+ antiVector.ClearAndSetSize(numEmptyStreams);
+ bool thereAreEmptyFiles = false, thereAreAntiItems = false;
+ unsigned cur = 0;
+ for (i = 0; i < db.Files.Size(); i++)
{
- emptyFileVector.Add(!file.IsDir);
+ const CFileItem &file = db.Files[i];
+ if (file.HasStream)
+ continue;
+ emptyFileVector[cur] = !file.IsDir;
if (!file.IsDir)
- numEmptyFiles++;
+ thereAreEmptyFiles = true;
bool isAnti = db.IsItemAnti(i);
- antiVector.Add(isAnti);
+ antiVector[cur] = isAnti;
if (isAnti)
- numAntiItems++;
+ thereAreAntiItems = true;
+ cur++;
}
+
+ if (thereAreEmptyFiles)
+ WritePropBoolVector(NID::kEmptyFile, emptyFileVector);
+ if (thereAreAntiItems)
+ WritePropBoolVector(NID::kAnti, antiVector);
}
-
- if (numEmptyFiles > 0)
- {
- WriteByte(NID::kEmptyFile);
- WriteNumber(Bv_GetSizeInBytes(emptyFileVector));
- WriteBoolVector(emptyFileVector);
- }
-
- if (numAntiItems > 0)
- {
- WriteByte(NID::kAnti);
- WriteNumber(Bv_GetSizeInBytes(antiVector));
- WriteBoolVector(antiVector);
- }
- }
}
{
/* ---------- Names ---------- */
- int numDefined = 0;
+ unsigned numDefined = 0;
size_t namesDataSize = 0;
- for (int i = 0; i < db.Files.Size(); i++)
+ FOR_VECTOR (i, db.Files)
{
- const UString &name = db.Files[i].Name;
+ const UString &name = db.Names[i];
if (!name.IsEmpty())
numDefined++;
- namesDataSize += (name.Length() + 1) * 2;
+ namesDataSize += (name.Len() + 1) * 2;
}
if (numDefined > 0)
{
namesDataSize++;
- SkipAlign(2 + GetBigNumberSize(namesDataSize), 2);
+ SkipAlign(2 + GetBigNumberSize(namesDataSize), 16);
WriteByte(NID::kName);
WriteNumber(namesDataSize);
WriteByte(0);
- for (int i = 0; i < db.Files.Size(); i++)
+ FOR_VECTOR (i, db.Files)
{
- const UString &name = db.Files[i].Name;
- for (int t = 0; t <= name.Length(); t++)
+ const UString &name = db.Names[i];
+ for (unsigned t = 0; t <= name.Len(); t++)
{
wchar_t c = name[t];
WriteByte((Byte)c);
@@ -706,26 +657,26 @@ void COutArchive::WriteHeader(
}
}
- if (headerOptions.WriteCTime) WriteUInt64DefVector(db.CTime, NID::kCTime);
- if (headerOptions.WriteATime) WriteUInt64DefVector(db.ATime, NID::kATime);
- if (headerOptions.WriteMTime) WriteUInt64DefVector(db.MTime, NID::kMTime);
+ /* if (headerOptions.WriteCTime) */ WriteUInt64DefVector(db.CTime, NID::kCTime);
+ /* if (headerOptions.WriteATime) */ WriteUInt64DefVector(db.ATime, NID::kATime);
+ /* if (headerOptions.WriteMTime) */ WriteUInt64DefVector(db.MTime, NID::kMTime);
WriteUInt64DefVector(db.StartPos, NID::kStartPos);
{
/* ---------- Write Attrib ---------- */
CBoolVector boolVector;
- boolVector.Reserve(db.Files.Size());
- int numDefined = 0;
+ boolVector.ClearAndSetSize(db.Files.Size());
+ unsigned numDefined = 0;
for (i = 0; i < db.Files.Size(); i++)
{
bool defined = db.Files[i].AttribDefined;
- boolVector.Add(defined);
+ boolVector[i] = defined;
if (defined)
numDefined++;
}
- if (numDefined > 0)
+ if (numDefined != 0)
{
- WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttributes, 4);
+ WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttrib, 4);
for (i = 0; i < db.Files.Size(); i++)
{
const CFileItem &file = db.Files[i];
@@ -735,13 +686,95 @@ void COutArchive::WriteHeader(
}
}
+ /*
+ {
+ // ---------- Write IsAux ----------
+ unsigned numAux = 0;
+ const CBoolVector &isAux = db.IsAux;
+ for (i = 0; i < isAux.Size(); i++)
+ if (isAux[i])
+ numAux++;
+ if (numAux > 0)
+ {
+ const unsigned bvSize = Bv_GetSizeInBytes(isAux);
+ WriteByte(NID::kIsAux);
+ WriteNumber(bvSize);
+ WriteBoolVector(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)
+ {
+ // WriteAlignedBoolHeader(boolVector, numDefined, NID::kParent, 4);
+ const unsigned bvSize = (numIsDir == boolVector.Size()) ? 0 : Bv_GetSizeInBytes(boolVector);
+ const UInt64 dataSize = (UInt64)db.Files.Size() * 4 + bvSize + 1;
+ SkipAlign(2 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), 4);
+
+ 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]);
+ SkipAlign(2 + GetBigNumberSize(secureDataSize), 4);
+ 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 CArchiveDatabase &db,
+ const CArchiveDatabaseOut &db,
const CCompressionMethodMode *options,
const CHeaderOptions &headerOptions)
{
@@ -773,17 +806,16 @@ HRESULT COutArchive::WriteDatabase(
_countMode = encodeHeaders;
_writeToStream = true;
_countSize = 0;
- WriteHeader(db, headerOptions, headerOffset);
+ WriteHeader(db, /* headerOptions, */ headerOffset);
if (encodeHeaders)
{
- CByteBuffer buf;
- buf.SetCapacity(_countSize);
+ CByteBuffer buf(_countSize);
_outByte2.Init((Byte *)buf, _countSize);
_countMode = false;
_writeToStream = false;
- WriteHeader(db, headerOptions, headerOffset);
+ WriteHeader(db, /* headerOptions, */ headerOffset);
if (_countSize != _outByte2.GetPos())
return E_FAIL;
@@ -794,10 +826,12 @@ HRESULT COutArchive::WriteDatabase(
CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions);
CRecordVector<UInt64> packSizes;
CObjectVector<CFolder> folders;
+ COutFolders outFolders;
+
RINOK(EncodeStream(
EXTERNAL_CODECS_LOC_VARS
encoder, buf,
- packSizes, folders));
+ packSizes, folders, outFolders));
_writeToStream = true;
@@ -805,11 +839,10 @@ HRESULT COutArchive::WriteDatabase(
throw 1;
WriteID(NID::kEncodedHeader);
- WritePackInfo(headerOffset, packSizes,
- CRecordVector<bool>(), CRecordVector<UInt32>());
- WriteUnpackInfo(folders);
+ WritePackInfo(headerOffset, packSizes, CUInt32DefVector());
+ WriteUnpackInfo(folders, outFolders);
WriteByte(NID::kEnd);
- for (int i = 0; i < packSizes.Size(); i++)
+ FOR_VECTOR (i, packSizes)
headerOffset += packSizes[i];
}
RINOK(_outByte.Flush());
@@ -842,24 +875,28 @@ HRESULT COutArchive::WriteDatabase(
}
}
-void CArchiveDatabase::GetFile(int index, CFileItem &file, CFileItem2 &file2) const
+void CUInt64DefVector::SetItem(unsigned index, bool defined, UInt64 value)
{
- file = Files[index];
- file2.CTimeDefined = CTime.GetItem(index, file2.CTime);
- file2.ATimeDefined = ATime.GetItem(index, file2.ATime);
- file2.MTimeDefined = MTime.GetItem(index, file2.MTime);
- file2.StartPosDefined = StartPos.GetItem(index, file2.StartPos);
- file2.IsAnti = IsItemAnti(index);
+ while (index >= Defs.Size())
+ Defs.Add(false);
+ Defs[index] = defined;
+ if (!defined)
+ return;
+ while (index >= Vals.Size())
+ Vals.Add(0);
+ Vals[index] = value;
}
-void CArchiveDatabase::AddFile(const CFileItem &file, const CFileItem2 &file2)
+void CArchiveDatabaseOut::AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name)
{
- int index = Files.Size();
+ 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);
- SetItemAnti(index, file2.IsAnti);
+ 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 7b1b528e..cead4bce 100755..100644
--- a/CPP/7zip/Archive/7z/7zOut.h
+++ b/CPP/7zip/Archive/7z/7zOut.h
@@ -9,6 +9,7 @@
#include "7zItem.h"
#include "../../Common/OutBuffer.h"
+#include "../../Common/StreamUtils.h"
namespace NArchive {
namespace N7z {
@@ -45,27 +46,191 @@ public:
struct CHeaderOptions
{
bool CompressMainHeader;
+ /*
bool WriteCTime;
bool WriteATime;
bool WriteMTime;
+ */
CHeaderOptions():
- CompressMainHeader(true),
- WriteCTime(false),
- WriteATime(false),
- WriteMTime(true)
+ CompressMainHeader(true)
+ /*
+ , WriteCTime(false)
+ , WriteATime(false)
+ , WriteMTime(true)
+ */
{}
};
+
+struct CFileItem2
+{
+ UInt64 CTime;
+ UInt64 ATime;
+ UInt64 MTime;
+ UInt64 StartPos;
+ bool CTimeDefined;
+ bool ATimeDefined;
+ bool MTimeDefined;
+ bool StartPosDefined;
+ bool IsAnti;
+ // bool IsAux;
+
+ void Init()
+ {
+ CTimeDefined = false;
+ ATimeDefined = false;
+ MTimeDefined = false;
+ StartPosDefined = false;
+ IsAnti = false;
+ // IsAux = false;
+ }
+};
+
+struct COutFolders
+{
+ CUInt32DefVector FolderUnpackCRCs; // Now we use it for headers only.
+
+ CRecordVector<CNum> NumUnpackStreamsVector;
+ CRecordVector<UInt64> CoderUnpackSizes; // including unpack sizes of bind coders
+
+ void OutFoldersClear()
+ {
+ FolderUnpackCRCs.Clear();
+ NumUnpackStreamsVector.Clear();
+ CoderUnpackSizes.Clear();
+ }
+
+ void OutFoldersReserveDown()
+ {
+ FolderUnpackCRCs.ReserveDown();
+ NumUnpackStreamsVector.ReserveDown();
+ CoderUnpackSizes.ReserveDown();
+ }
+};
+
+struct CArchiveDatabaseOut: public COutFolders
+{
+ CRecordVector<UInt64> PackSizes;
+ CUInt32DefVector PackCRCs;
+ CObjectVector<CFolder> Folders;
+
+ CRecordVector<CFileItem> Files;
+ UStringVector Names;
+ CUInt64DefVector CTime;
+ CUInt64DefVector ATime;
+ CUInt64DefVector MTime;
+ CUInt64DefVector StartPos;
+ CRecordVector<bool> IsAnti;
+
+ /*
+ CRecordVector<bool> IsAux;
+
+ CByteBuffer SecureBuf;
+ CRecordVector<UInt32> SecureSizes;
+ CRecordVector<UInt32> SecureIDs;
+
+ void ClearSecure()
+ {
+ SecureBuf.Free();
+ SecureSizes.Clear();
+ SecureIDs.Clear();
+ }
+ */
+
+ void Clear()
+ {
+ OutFoldersClear();
+
+ PackSizes.Clear();
+ PackCRCs.Clear();
+ Folders.Clear();
+
+ Files.Clear();
+ Names.Clear();
+ CTime.Clear();
+ ATime.Clear();
+ MTime.Clear();
+ StartPos.Clear();
+ 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();
+ 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) &&
+ (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);
+ 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.GetCapacity()); }
+ void WriteBytes(const CByteBuffer &data) { WriteBytes(data, data.Size()); }
void WriteByte(Byte b);
void WriteUInt32(UInt32 value);
void WriteUInt64(UInt64 value);
@@ -75,36 +240,36 @@ class COutArchive
void WriteFolder(const CFolder &folder);
HRESULT WriteFileHeader(const CFileItem &itemInfo);
void WriteBoolVector(const CBoolVector &boolVector);
- void WriteHashDigests(
- const CRecordVector<bool> &digestsDefined,
- const CRecordVector<UInt32> &hashDigests);
+ void WritePropBoolVector(Byte id, const CBoolVector &boolVector);
+
+ void WriteHashDigests(const CUInt32DefVector &digests);
void WritePackInfo(
UInt64 dataOffset,
const CRecordVector<UInt64> &packSizes,
- const CRecordVector<bool> &packCRCsDefined,
- const CRecordVector<UInt32> &packCRCs);
+ const CUInt32DefVector &packCRCs);
- void WriteUnpackInfo(const CObjectVector<CFolder> &folders);
+ void WriteUnpackInfo(
+ const CObjectVector<CFolder> &folders,
+ const COutFolders &outFolders);
void WriteSubStreamsInfo(
const CObjectVector<CFolder> &folders,
- const CRecordVector<CNum> &numUnpackStreamsInFolders,
+ const COutFolders &outFolders,
const CRecordVector<UInt64> &unpackSizes,
- const CRecordVector<bool> &digestsDefined,
- const CRecordVector<UInt32> &hashDigests);
+ const CUInt32DefVector &digests);
void SkipAlign(unsigned pos, unsigned alignSize);
- void WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, Byte type, unsigned itemSize);
+ void WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize);
void WriteUInt64DefVector(const CUInt64DefVector &v, Byte type);
HRESULT EncodeStream(
DECL_EXTERNAL_CODECS_LOC_VARS
CEncoder &encoder, const CByteBuffer &data,
- CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders);
+ CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders, COutFolders &outFolders);
void WriteHeader(
- const CArchiveDatabase &db,
- const CHeaderOptions &headerOptions,
+ const CArchiveDatabaseOut &db,
+ // const CHeaderOptions &headerOptions,
UInt64 &headerOffset);
bool _countMode;
@@ -118,6 +283,8 @@ class COutArchive
bool _endMarker;
#endif
+ bool _useAlign;
+
HRESULT WriteSignature();
#ifdef _7Z_VOL
HRESULT WriteFinishSignature();
@@ -136,7 +303,7 @@ public:
HRESULT SkipPrefixArchiveHeader();
HRESULT WriteDatabase(
DECL_EXTERNAL_CODECS_LOC_VARS
- const CArchiveDatabase &db,
+ const CArchiveDatabaseOut &db,
const CCompressionMethodMode *options,
const CHeaderOptions &headerOptions);
diff --git a/CPP/7zip/Archive/7z/7zProperties.cpp b/CPP/7zip/Archive/7z/7zProperties.cpp
index fd4af49c..5ed36947 100755..100644
--- a/CPP/7zip/Archive/7z/7zProperties.cpp
+++ b/CPP/7zip/Archive/7z/7zProperties.cpp
@@ -17,7 +17,7 @@ struct CPropMap
STATPROPSTG StatPROPSTG;
};
-CPropMap kPropMap[] =
+static const CPropMap kPropMap[] =
{
{ NID::kName, { NULL, kpidPath, VT_BSTR } },
{ NID::kSize, { NULL, kpidSize, VT_UI8 } },
@@ -34,11 +34,12 @@ CPropMap kPropMap[] =
{ NID::kCTime, { NULL, kpidCTime, VT_FILETIME } },
{ NID::kMTime, { NULL, kpidMTime, VT_FILETIME } },
{ NID::kATime, { NULL, kpidATime, VT_FILETIME } },
- { NID::kWinAttributes, { NULL, kpidAttrib, VT_UI4 } },
+ { NID::kWinAttrib, { NULL, kpidAttrib, VT_UI4 } },
{ NID::kStartPos, { NULL, kpidPosition, VT_UI4 } },
{ NID::kCRC, { NULL, kpidCRC, VT_UI4 } },
+// { NID::kIsAux, { NULL, kpidIsAux, VT_BOOL } },
{ NID::kAnti, { NULL, kpidIsAnti, VT_BOOL } }
#ifndef _SFX
@@ -49,11 +50,9 @@ CPropMap kPropMap[] =
#endif
};
-static const int kPropMapSize = sizeof(kPropMap) / sizeof(kPropMap[0]);
-
static int FindPropInMap(UInt64 filePropID)
{
- for (int i = 0; i < kPropMapSize; i++)
+ for (int i = 0; i < ARRAY_SIZE(kPropMap); i++)
if (kPropMap[i].FilePropID == filePropID)
return i;
return -1;
@@ -62,7 +61,7 @@ static int FindPropInMap(UInt64 filePropID)
static void CopyOneItem(CRecordVector<UInt64> &src,
CRecordVector<UInt64> &dest, UInt32 item)
{
- for (int i = 0; i < src.Size(); i++)
+ FOR_VECTOR (i, src)
if (src[i] == item)
{
dest.Add(item);
@@ -73,7 +72,7 @@ static void CopyOneItem(CRecordVector<UInt64> &src,
static void RemoveOneItem(CRecordVector<UInt64> &src, UInt32 item)
{
- for (int i = 0; i < src.Size(); i++)
+ FOR_VECTOR (i, src)
if (src[i] == item)
{
src.Delete(i);
@@ -83,7 +82,7 @@ static void RemoveOneItem(CRecordVector<UInt64> &src, UInt32 item)
static void InsertToHead(CRecordVector<UInt64> &dest, UInt32 item)
{
- for (int i = 0; i < dest.Size(); i++)
+ FOR_VECTOR (i, dest)
if (dest[i] == item)
{
dest.Delete(i);
@@ -92,6 +91,8 @@ static void InsertToHead(CRecordVector<UInt64> &dest, UInt32 item)
dest.Insert(0, item);
}
+#define COPY_ONE_ITEM(id) CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::id);
+
void CHandler::FillPopIDs()
{
_fileInfoPopIDs.Clear();
@@ -103,21 +104,26 @@ void CHandler::FillPopIDs()
const CArchiveDatabaseEx &_db = volume.Database;
#endif
- CRecordVector<UInt64> fileInfoPopIDs = _db.ArchiveInfo.FileInfoPopIDs;
+ CRecordVector<UInt64> fileInfoPopIDs = _db.ArcInfo.FileInfoPopIDs;
RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream);
RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile);
+ /*
+ RemoveOneItem(fileInfoPopIDs, NID::kParent);
+ RemoveOneItem(fileInfoPopIDs, NID::kNtSecure);
+ */
+
+ COPY_ONE_ITEM(kName);
+ COPY_ONE_ITEM(kAnti);
+ COPY_ONE_ITEM(kSize);
+ COPY_ONE_ITEM(kPackInfo);
+ COPY_ONE_ITEM(kCTime);
+ COPY_ONE_ITEM(kMTime);
+ COPY_ONE_ITEM(kATime);
+ COPY_ONE_ITEM(kWinAttrib);
+ COPY_ONE_ITEM(kCRC);
+ COPY_ONE_ITEM(kComment);
- CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kName);
- CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kAnti);
- CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kSize);
- CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kPackInfo);
- CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCTime);
- CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kMTime);
- CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kATime);
- CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kWinAttributes);
- CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCRC);
- CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kComment);
_fileInfoPopIDs += fileInfoPopIDs;
#ifndef _SFX
@@ -141,9 +147,9 @@ void CHandler::FillPopIDs()
#endif
}
-STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties)
+STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps)
{
- *numProperties = _fileInfoPopIDs.Size();
+ *numProps = _fileInfoPopIDs.Size();
return S_OK;
}
diff --git a/CPP/7zip/Archive/7z/7zProperties.h b/CPP/7zip/Archive/7z/7zProperties.h
index 66181795..66181795 100755..100644
--- a/CPP/7zip/Archive/7z/7zProperties.h
+++ b/CPP/7zip/Archive/7z/7zProperties.h
diff --git a/CPP/7zip/Archive/7z/7zRegister.cpp b/CPP/7zip/Archive/7z/7zRegister.cpp
index 6e9bf6b9..37ea29d3 100755..100644
--- a/CPP/7zip/Archive/7z/7zRegister.cpp
+++ b/CPP/7zip/Archive/7z/7zRegister.cpp
@@ -5,14 +5,21 @@
#include "../../Common/RegisterArc.h"
#include "7zHandler.h"
-static IInArchive *CreateArc() { return new NArchive::N7z::CHandler; }
-#ifndef EXTRACT_ONLY
-static IOutArchive *CreateArcOut() { return new NArchive::N7z::CHandler; }
-#else
-#define CreateArcOut 0
-#endif
+
+namespace NArchive {
+namespace N7z {
+
+IMP_CreateArcIn
+IMP_CreateArcOut
static CArcInfo g_ArcInfo =
- { L"7z", L"7z", 0, 7, {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}, 6, false, CreateArc, CreateArcOut };
+ { "7z", "7z", 0, 7,
+ 6, {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C},
+ 0,
+ NArcInfoFlags::kFindSignature,
+ REF_CreateArc_Pair };
+
+REGISTER_ARC_DEC_SIG(7z)
+// REGISTER_ARC(7z)
-REGISTER_ARC(7z)
+}}
diff --git a/CPP/7zip/Archive/7z/7zSpecStream.cpp b/CPP/7zip/Archive/7z/7zSpecStream.cpp
index 06969636..8e45d987 100755..100644
--- a/CPP/7zip/Archive/7z/7zSpecStream.cpp
+++ b/CPP/7zip/Archive/7z/7zSpecStream.cpp
@@ -9,16 +9,14 @@ STDMETHODIMP CSequentialInStreamSizeCount2::Read(void *data, UInt32 size, UInt32
UInt32 realProcessedSize;
HRESULT result = _stream->Read(data, size, &realProcessedSize);
_size += realProcessedSize;
- if (processedSize != 0)
+ if (processedSize)
*processedSize = realProcessedSize;
return result;
}
-STDMETHODIMP CSequentialInStreamSizeCount2::GetSubStreamSize(
- UInt64 subStream, UInt64 *value)
+STDMETHODIMP CSequentialInStreamSizeCount2::GetSubStreamSize(UInt64 subStream, UInt64 *value)
{
- if (_getSubStreamSize == NULL)
+ if (!_getSubStreamSize)
return E_NOTIMPL;
- return _getSubStreamSize->GetSubStreamSize(subStream, value);
+ return _getSubStreamSize->GetSubStreamSize(subStream, value);
}
-
diff --git a/CPP/7zip/Archive/7z/7zSpecStream.h b/CPP/7zip/Archive/7z/7zSpecStream.h
index 2e26efd5..2e26efd5 100755..100644
--- a/CPP/7zip/Archive/7z/7zSpecStream.h
+++ b/CPP/7zip/Archive/7z/7zSpecStream.h
diff --git a/CPP/7zip/Archive/7z/7zUpdate.cpp b/CPP/7zip/Archive/7z/7zUpdate.cpp
index e63b09d2..96befa23 100755..100644
--- a/CPP/7zip/Archive/7z/7zUpdate.cpp
+++ b/CPP/7zip/Archive/7z/7zUpdate.cpp
@@ -4,10 +4,11 @@
#include "../../../../C/CpuArch.h"
-#include "../../Common/LimitedStreams.h"
-#include "../../Common/ProgressUtils.h"
+#include "../../../Common/Wildcard.h"
#include "../../Common/CreateCoder.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
#include "../../Compress/CopyCoder.h"
@@ -58,19 +59,20 @@ int CUpdateItem::GetExtensionPos() const
int slashPos = GetReverseSlashPos(Name);
int dotPos = Name.ReverseFind(L'.');
if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
- return Name.Length();
+ return Name.Len();
return dotPos + 1;
}
UString CUpdateItem::GetExtension() const
{
- return Name.Mid(GetExtensionPos());
+ 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();
@@ -110,11 +112,12 @@ static int CompareFolders(const CFolder &f1, const CFolder &f2)
RINOZ(CompareBindPairs(f1.BindPairs[i], f2.BindPairs[i]));
return 0;
}
+*/
/*
static int CompareFiles(const CFileItem &f1, const CFileItem &f2)
{
- return MyStringCompareNoCase(f1.Name, f2.Name);
+ return CompareFileNames(f1.Name, f2.Name);
}
*/
@@ -125,15 +128,19 @@ struct CFolderRepack
CNum NumCopyFiles;
};
-static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void *param)
+static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void * /* param */)
{
RINOZ_COMP(p1->Group, p2->Group);
int i1 = p1->FolderIndex;
int i2 = p2->FolderIndex;
- const CArchiveDatabaseEx &db = *(const CArchiveDatabaseEx *)param;
+ /*
+ // 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(
@@ -147,25 +154,31 @@ static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2
*/
}
-////////////////////////////////////////////////////////////
+/*
+ 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 int *p1, const int *p2, void *param)
{
const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param;
const CUpdateItem &u1 = updateItems[*p1];
const CUpdateItem &u2 = updateItems[*p2];
+ // NonAnti < Anti
+ if (u1.IsAnti != u2.IsAnti)
+ return (u1.IsAnti ? 1 : -1);
if (u1.IsDir != u2.IsDir)
- return (u1.IsDir) ? 1 : -1;
- if (u1.IsDir)
{
- if (u1.IsAnti != u2.IsAnti)
+ // Dir.NonAnti < File < Dir.Anti
+ if (u1.IsDir)
return (u1.IsAnti ? 1 : -1);
- int n = MyStringCompareNoCase(u1.Name, u2.Name);
- return -n;
+ return (u2.IsAnti ? -1 : 1);
}
- if (u1.IsAnti != u2.IsAnti)
- return (u1.IsAnti ? 1 : -1);
- return MyStringCompareNoCase(u1.Name, u2.Name);
+ int n = CompareFileNames(u1.Name, u2.Name);
+ return (u1.IsDir && u1.IsAnti) ? -n : n;
}
static const char *g_Exts =
@@ -198,7 +211,7 @@ static const char *g_Exts =
" exe dll ocx vbx sfx sys tlb awx com obj lib out o so "
" pdb pch idb ncb opt";
-int GetExtIndex(const char *ext)
+static int GetExtIndex(const char *ext)
{
int extIndex = 1;
const char *p = g_Exts;
@@ -237,7 +250,9 @@ struct CRefItem
UInt32 Index;
UInt32 ExtensionPos;
UInt32 NamePos;
- int ExtensionIndex;
+ unsigned ExtensionIndex;
+
+ CRefItem() {};
CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType):
UpdateItem(&ui),
Index(index),
@@ -248,64 +263,134 @@ struct CRefItem
if (sortByType)
{
int slashPos = GetReverseSlashPos(ui.Name);
- NamePos = ((slashPos >= 0) ? (slashPos + 1) : 0);
+ NamePos = slashPos + 1;
int dotPos = ui.Name.ReverseFind(L'.');
- if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
- ExtensionPos = ui.Name.Length();
+ if (dotPos < 0 || dotPos < slashPos)
+ ExtensionPos = ui.Name.Len();
else
{
ExtensionPos = dotPos + 1;
- UString us = ui.Name.Mid(ExtensionPos);
- if (!us.IsEmpty())
+ if (ExtensionPos != ui.Name.Len())
{
- us.MakeLower();
- int i;
AString s;
- for (i = 0; i < us.Length(); i++)
+ for (unsigned pos = ExtensionPos;; pos++)
{
- wchar_t c = us[i];
+ wchar_t c = ui.Name[pos];
if (c >= 0x80)
break;
- s += (char)c;
+ if (c == 0)
+ {
+ ExtensionIndex = GetExtIndex(s);
+ break;
+ }
+ s += (char)MyCharLower_Ascii((char)c);
}
- if (i == us.Length())
- ExtensionIndex = GetExtIndex(s);
- else
- ExtensionIndex = 0;
}
}
}
}
};
+struct CSortParam
+{
+ // const CObjectVector<CTreeFolder> *TreeFolders;
+ bool SortByType;
+};
+
+/*
+ we sort files in such order:
+ - Dir.NonAnti (name sorted)
+ - alt streams
+ - Dirs
+ - Dir.Anti (reverse name sorted)
+*/
+
+
static int CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *param)
{
const CRefItem &a1 = *p1;
const CRefItem &a2 = *p2;
const CUpdateItem &u1 = *a1.UpdateItem;
const CUpdateItem &u2 = *a2.UpdateItem;
- int n;
+
+ /*
+ 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;
+ return u1.IsDir ? 1 : -1;
if (u1.IsDir)
{
if (u1.IsAnti != u2.IsAnti)
return (u1.IsAnti ? 1 : -1);
- n = MyStringCompareNoCase(u1.Name, u2.Name);
+ int n = CompareFileNames(u1.Name, u2.Name);
return -n;
}
- bool sortByType = *(bool *)param;
+
+ // bool sortByType = *(bool *)param;
+ const CSortParam *sortParam = (const CSortParam *)param;
+ bool sortByType = sortParam->SortByType;
if (sortByType)
{
RINOZ_COMP(a1.ExtensionIndex, a2.ExtensionIndex);
- RINOZ(MyStringCompareNoCase(u1.Name + a1.ExtensionPos, u2.Name + a2.ExtensionPos));
- RINOZ(MyStringCompareNoCase(u1.Name + a1.NamePos, u2.Name + a2.NamePos));
+ 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);
}
- return MyStringCompareNoCase(u1.Name, u2.Name);
+ /*
+ 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
@@ -313,19 +398,19 @@ struct CSolidGroup
CRecordVector<UInt32> Indices;
};
-static wchar_t *g_ExeExts[] =
+static const wchar_t *g_ExeExts[] =
{
- L"dll",
- L"exe",
- L"ocx",
- L"sfx",
- L"sys"
+ L"dll"
+ , L"exe"
+ , L"ocx"
+ , L"sfx"
+ , L"sys"
};
-static bool IsExeExt(const UString &ext)
+static bool IsExeExt(const wchar_t *ext)
{
- for (int i = 0; i < sizeof(g_ExeExts) / sizeof(g_ExeExts[0]); i++)
- if (ext.CompareNoCase(g_ExeExts[i]) == 0)
+ for (int i = 0; i < ARRAY_SIZE(g_ExeExts); i++)
+ if (MyStringCompareNoCase(ext, g_ExeExts[i]) == 0)
return true;
return false;
}
@@ -402,7 +487,6 @@ static void MakeExeMethod(CCompressionMethodMode &mode,
static void FromUpdateItemToFileItem(const CUpdateItem &ui,
CFileItem &file, CFileItem2 &file2)
{
- file.Name = NItemName::MakeLegalName(ui.Name);
if (ui.AttribDefined)
file.SetAttrib(ui.Attrib);
@@ -410,11 +494,13 @@ static void FromUpdateItemToFileItem(const CUpdateItem &ui,
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;
file.Size = ui.Size;
file.IsDir = ui.IsDir;
file.HasStream = ui.HasStream();
+ // file.IsAltStream = ui.IsAltStream;
}
class CFolderOutStream2:
@@ -423,11 +509,11 @@ class CFolderOutStream2:
{
COutStreamWithCRC *_crcStreamSpec;
CMyComPtr<ISequentialOutStream> _crcStream;
- const CArchiveDatabaseEx *_db;
+ const CDbEx *_db;
const CBoolVector *_extractStatuses;
CMyComPtr<ISequentialOutStream> _outStream;
UInt32 _startIndex;
- int _currentIndex;
+ unsigned _currentIndex;
bool _fileIsOpen;
UInt64 _rem;
@@ -444,7 +530,7 @@ public:
_crcStream = _crcStreamSpec;
}
- HRESULT Init(const CArchiveDatabaseEx *db, UInt32 startIndex,
+ HRESULT Init(const CDbEx *db, UInt32 startIndex,
const CBoolVector *extractStatuses, ISequentialOutStream *outStream);
void ReleaseOutStream();
HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; }
@@ -452,7 +538,7 @@ public:
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
};
-HRESULT CFolderOutStream2::Init(const CArchiveDatabaseEx *db, UInt32 startIndex,
+HRESULT CFolderOutStream2::Init(const CDbEx *db, UInt32 startIndex,
const CBoolVector *extractStatuses, ISequentialOutStream *outStream)
{
_db = db;
@@ -551,13 +637,13 @@ public:
CMyComPtr<ISequentialOutStream> Fos;
UInt64 StartPos;
- const UInt64 *PackSizes;
- const CFolder *Folder;
+ const CFolders *Folders;
+ int FolderIndex;
#ifndef _NO_CRYPTO
- CMyComPtr<ICryptoGetTextPassword> GetTextPassword;
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
#endif
- DECL_EXTERNAL_CODECS_VARS
+ DECL_EXTERNAL_CODECS_LOC_VARS2;
CDecoder Decoder;
#ifndef _7ZIP_ST
@@ -585,21 +671,20 @@ void CThreadDecoder::Execute()
try
{
#ifndef _NO_CRYPTO
- bool passwordIsDefined;
+ bool isEncrypted = false;
+ bool passwordIsDefined = false;
#endif
+
Result = Decoder.Decode(
- EXTERNAL_CODECS_VARS
+ EXTERNAL_CODECS_LOC_VARS
InStream,
StartPos,
- PackSizes,
- *Folder,
+ *Folders, FolderIndex,
Fos,
NULL
- #ifndef _NO_CRYPTO
- , GetTextPassword, passwordIsDefined
- #endif
+ _7Z_DECODER_CRYPRO_VARS
#ifndef _7ZIP_ST
- , MtMode, NumThreads
+ , MtMode, NumThreads
#endif
);
}
@@ -614,7 +699,7 @@ void CThreadDecoder::Execute()
bool static Is86FilteredFolder(const CFolder &f)
{
- for (int i = 0; i < f.Coders.Size(); i++)
+ FOR_VECTOR(i, f.Coders)
{
CMethodId m = f.Coders[i].MethodID;
if (m == k_BCJ || m == k_BCJ2)
@@ -650,13 +735,26 @@ static bool IsEncryptedGroup(int group) { return (group & 2) != 0; }
static int GetGroupIndex(bool encrypted, int bcjFiltered)
{ return (encrypted ? 2 : 0) + (bcjFiltered ? 1 : 0); }
+static void GetFile(const CDatabase &inDb, int 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.IsAnti = inDb.IsItemAnti(index);
+ // file2.IsAux = inDb.IsItemAux(index);
+}
+
HRESULT Update(
DECL_EXTERNAL_CODECS_LOC_VARS
IInStream *inStream,
- const CArchiveDatabaseEx *db,
+ const CDbEx *db,
const CObjectVector<CUpdateItem> &updateItems,
+ // const CObjectVector<CTreeFolder> &treeFolders,
+ // const CUniqBlocks &secureBlocks,
COutArchive &archive,
- CArchiveDatabase &newDatabase,
+ CArchiveDatabaseOut &newDatabase,
ISequentialOutStream *seqOutStream,
IArchiveUpdateCallback *updateCallback,
const CUpdateOptions &options
@@ -668,6 +766,9 @@ HRESULT Update(
UInt64 numSolidFiles = options.NumSolidFiles;
if (numSolidFiles == 0)
numSolidFiles = 1;
+
+ // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes();
+
/*
CMyComPtr<IOutStream> outStream;
RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));
@@ -675,23 +776,23 @@ HRESULT Update(
return E_NOTIMPL;
*/
- UInt64 startBlockSize = db != 0 ? db->ArchiveInfo.StartPosition: 0;
+ UInt64 startBlockSize = db != 0 ? db->ArcInfo.StartPosition: 0;
if (startBlockSize > 0 && !options.RemoveSfxBlock)
{
RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL));
}
- CRecordVector<int> fileIndexToUpdateIndexMap;
+ CIntArr fileIndexToUpdateIndexMap;
CRecordVector<CFolderRepack> folderRefs;
UInt64 complexity = 0;
UInt64 inSizeForReduce2 = 0;
bool needEncryptedRepack = false;
if (db != 0)
{
- fileIndexToUpdateIndexMap.Reserve(db->Files.Size());
- int i;
+ fileIndexToUpdateIndexMap.Alloc(db->Files.Size());
+ unsigned i;
for (i = 0; i < db->Files.Size(); i++)
- fileIndexToUpdateIndexMap.Add(-1);
+ fileIndexToUpdateIndexMap[i] = -1;
for (i = 0; i < updateItems.Size(); i++)
{
@@ -700,7 +801,7 @@ HRESULT Update(
fileIndexToUpdateIndexMap[index] = i;
}
- for (i = 0; i < db->Folders.Size(); i++)
+ for (i = 0; i < (int)db->NumFolders; i++)
{
CNum indexInFolder = 0;
CNum numCopyItems = 0;
@@ -727,7 +828,8 @@ HRESULT Update(
CFolderRepack rep;
rep.FolderIndex = i;
rep.NumCopyFiles = numCopyItems;
- const CFolder &f = db->Folders[i];
+ CFolder f;
+ db->ParseFolderInfo(i, f);
bool isEncrypted = f.IsEncrypted();
rep.Group = GetGroupIndex(isEncrypted, Is86FilteredFolder(f));
folderRefs.Add(rep);
@@ -746,7 +848,7 @@ HRESULT Update(
}
UInt64 inSizeForReduce = 0;
- int i;
+ unsigned i;
for (i = 0; i < updateItems.Size(); i++)
{
const CUpdateItem &ui = updateItems[i];
@@ -776,18 +878,17 @@ HRESULT Update(
if (!folderRefs.IsEmpty())
{
#ifdef EXTERNAL_CODECS
- threadDecoder._codecsInfo = codecsInfo;
- threadDecoder._externalCodecs = *externalCodecs;
+ threadDecoder.__externalCodecs = __externalCodecs;
#endif
RINOK(threadDecoder.Create());
}
CObjectVector<CSolidGroup> groups;
for (i = 0; i < kNumGroupsMax; i++)
- groups.Add(CSolidGroup());
+ groups.AddNew();
{
- // ---------- Split files to 2 groups ----------
+ // ---------- Split files to groups ----------
bool useFilters = options.UseFilters;
const CCompressionMethodMode &method = *options.Method;
@@ -803,7 +904,7 @@ HRESULT Update(
{
int dotPos = ui.Name.ReverseFind(L'.');
if (dotPos >= 0)
- filteredGroup = IsExeExt(ui.Name.Mid(dotPos + 1));
+ filteredGroup = IsExeExt(ui.Name.Ptr(dotPos + 1));
}
groups[GetGroupIndex(method.PasswordIsDefined, filteredGroup)].Indices.Add(i);
}
@@ -815,7 +916,7 @@ HRESULT Update(
if (needEncryptedRepack)
{
getPasswordSpec = new CCryptoGetTextPassword;
- threadDecoder.GetTextPassword = getPasswordSpec;
+ threadDecoder.getTextPassword = getPasswordSpec;
if (options.Method->PasswordIsDefined)
getPasswordSpec->Password = options.Method->Password;
@@ -825,18 +926,111 @@ HRESULT Update(
return E_NOTIMPL;
CMyComBSTR password;
RINOK(getDecoderPassword->CryptoGetTextPassword(&password));
- getPasswordSpec->Password = password;
+ if ((BSTR)password)
+ getPasswordSpec->Password = password;
}
}
#endif
+
// ---------- Compress ----------
RINOK(archive.Create(seqOutStream, false));
RINOK(archive.SkipPrefixArchiveHeader());
- int folderRefIndex = 0;
+ /*
+ 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)
+ FromUpdateItemToFileItem(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 ---------- */
+ CRecordVector<int> emptyRefs;
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (ui.NewData)
+ {
+ if (ui.HasStream())
+ continue;
+ }
+ else if (ui.IndexInArchive != -1 && db->Files[ui.IndexInArchive].HasStream)
+ continue;
+ /*
+ 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)
+ {
+ FromUpdateItemToFileItem(ui, file, file2);
+ name = ui.Name;
+ }
+ else
+ {
+ GetFile(*db, ui.IndexInArchive, file, file2);
+ name = db->GetName(ui.IndexInArchive);
+ }
+
+ /*
+ if (totalSecureDataSize != 0)
+ newDatabase.SecureIDs.Add(ui.SecureIndex);
+ file.Parent = ui.ParentFolderIndex;
+ */
+ newDatabase.AddFile(file, file2, name);
+ }
+ }
+
+ unsigned folderRefIndex = 0;
lps->ProgressOffset = 0;
for (int groupIndex = 0; groupIndex < kNumGroupsMax; groupIndex++)
@@ -879,15 +1073,20 @@ HRESULT Update(
db->GetFolderStreamPos(folderIndex, 0), packSize, progress));
lps->ProgressOffset += packSize;
- const CFolder &folder = db->Folders[folderIndex];
- CNum startIndex = db->FolderStartPackStreamIndex[folderIndex];
- for (int j = 0; j < folder.PackStreams.Size(); j++)
+ CFolder &folder = newDatabase.Folders.AddNew();
+ db->ParseFolderInfo(folderIndex, folder);
+ CNum startIndex = db->FoStartPackStreamIndex[folderIndex];
+ for (unsigned j = 0; j < folder.PackStreams.Size(); j++)
{
- newDatabase.PackSizes.Add(db->PackSizes[startIndex + j]);
+ newDatabase.PackSizes.Add(db->GetStreamPackSize(startIndex + j));
// newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]);
// newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]);
}
- newDatabase.Folders.Add(folder);
+
+ UInt32 indexStart = db->FoToCoderUnpackSizes[folderIndex];
+ UInt32 indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1];
+ for (; indexStart < indexEnd; indexStart++)
+ newDatabase.CoderUnpackSizes.Add(db->CoderUnpackSizes[indexStart]);
}
else
{
@@ -909,8 +1108,8 @@ HRESULT Update(
extractStatuses.Add(needExtract);
}
- int startPackIndex = newDatabase.PackSizes.Size();
- CFolder newFolder;
+ unsigned startPackIndex = newDatabase.PackSizes.Size();
+ UInt64 curUnpackSize;
{
CMyComPtr<ISequentialInStream> sbInStream;
{
@@ -921,16 +1120,17 @@ HRESULT Update(
}
threadDecoder.InStream = inStream;
- threadDecoder.Folder = &db->Folders[folderIndex];
- threadDecoder.StartPos = db->GetFolderStreamPos(folderIndex, 0);
- threadDecoder.PackSizes = &db->PackSizes[db->FolderStartPackStreamIndex[folderIndex]];
+ threadDecoder.Folders = (const CFolders *)db;
+ threadDecoder.FolderIndex = folderIndex;
+ threadDecoder.StartPos = db->ArcInfo.DataStartPosition; // db->GetFolderStreamPos(folderIndex, 0);
threadDecoder.Start();
RINOK(encoder.Encode(
- EXTERNAL_CODECS_LOC_VARS
- sbInStream, NULL, &inSizeForReduce, newFolder,
- archive.SeqStream, newDatabase.PackSizes, progress));
+ EXTERNAL_CODECS_LOC_VARS
+ sbInStream, NULL, &inSizeForReduce,
+ newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curUnpackSize,
+ archive.SeqStream, newDatabase.PackSizes, progress));
threadDecoder.WaitExecuteFinish();
}
@@ -939,9 +1139,7 @@ HRESULT Update(
for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
lps->OutSize += newDatabase.PackSizes[startPackIndex];
- lps->InSize += newFolder.GetUnpackSize();
-
- newDatabase.Folders.Add(newFolder);
+ lps->InSize += curUnpackSize;
}
newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles);
@@ -953,7 +1151,8 @@ HRESULT Update(
{
CFileItem file;
CFileItem2 file2;
- db->GetFile(fi, file, file2);
+ GetFile(*db, fi, file, file2);
+ UString name = db->GetName(fi);
if (file.HasStream)
{
indexInFolder++;
@@ -972,30 +1171,40 @@ HRESULT Update(
uf.CrcDefined = file.CrcDefined;
uf.HasStream = file.HasStream;
file = uf;
+ name = ui.Name;
}
- newDatabase.AddFile(file, file2);
+ /*
+ 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);
}
}
}
}
- int numFiles = group.Indices.Size();
+ unsigned numFiles = group.Indices.Size();
if (numFiles == 0)
continue;
CRecordVector<CRefItem> refItems;
- refItems.Reserve(numFiles);
+ refItems.ClearAndSetSize(numFiles);
bool sortByType = (numSolidFiles > 1);
for (i = 0; i < numFiles; i++)
- refItems.Add(CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType));
- refItems.Sort(CompareUpdateItems, (void *)&sortByType);
+ refItems[i] = CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType);
+ CSortParam sortParam;
+ // sortParam.TreeFolders = &treeFolders;
+ sortParam.SortByType = sortByType;
+ refItems.Sort(CompareUpdateItems, (void *)&sortParam);
- CRecordVector<UInt32> indices;
- indices.Reserve(numFiles);
+ CObjArray<UInt32> indices(numFiles);
for (i = 0; i < numFiles; i++)
{
UInt32 index = refItems[i].Index;
- indices.Add(index);
+ indices[i] = index;
/*
const CUpdateItem &ui = updateItems[index];
CFileItem file;
@@ -1027,7 +1236,7 @@ HRESULT Update(
if (numSubFiles == 0)
prevExtension = ext;
else
- if (ext.CompareNoCase(prevExtension) != 0)
+ if (!ext.IsEqualToNoCase(prevExtension))
break;
}
}
@@ -1038,34 +1247,39 @@ HRESULT Update(
CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
- CFolder folderItem;
-
- int startPackIndex = newDatabase.PackSizes.Size();
+ unsigned startPackIndex = newDatabase.PackSizes.Size();
+ UInt64 curFolderUnpackSize;
RINOK(encoder.Encode(
EXTERNAL_CODECS_LOC_VARS
- solidInStream, NULL, &inSizeForReduce, folderItem,
+ solidInStream, NULL, &inSizeForReduce,
+ newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curFolderUnpackSize,
archive.SeqStream, newDatabase.PackSizes, progress));
for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
lps->OutSize += newDatabase.PackSizes[startPackIndex];
- lps->InSize += folderItem.GetUnpackSize();
+ lps->InSize += curFolderUnpackSize;
// for ()
// newDatabase.PackCRCsDefined.Add(false);
// newDatabase.PackCRCs.Add(0);
- newDatabase.Folders.Add(folderItem);
-
CNum numUnpackStreams = 0;
for (int subIndex = 0; subIndex < numSubFiles; subIndex++)
{
const CUpdateItem &ui = updateItems[indices[i + subIndex]];
CFileItem file;
CFileItem2 file2;
+ UString name;
if (ui.NewProps)
+ {
FromUpdateItemToFileItem(ui, file, file2);
+ name = ui.Name;
+ }
else
- db->GetFile(ui.IndexInArchive, file, file2);
+ {
+ GetFile(*db, ui.IndexInArchive, file, file2);
+ name = db->GetName(ui.IndexInArchive);
+ }
if (file2.IsAnti || file.IsDir)
return E_FAIL;
@@ -1092,7 +1306,14 @@ HRESULT Update(
file.CrcDefined = false;
file.HasStream = false;
}
- newDatabase.AddFile(file, file2);
+ /*
+ 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.
@@ -1112,36 +1333,28 @@ HRESULT Update(
groups.ClearAndFree();
*/
+ /*
+ for (i = 0; i < newDatabase.Files.Size(); i++)
{
- // ---------- Write Folders & Empty Files ----------
-
- CRecordVector<int> emptyRefs;
- for (i = 0; i < updateItems.Size(); i++)
- {
- const CUpdateItem &ui = updateItems[i];
- if (ui.NewData)
- {
- if (ui.HasStream())
- continue;
- }
- else if (ui.IndexInArchive != -1 && db->Files[ui.IndexInArchive].HasStream)
- continue;
- emptyRefs.Add(i);
- }
- emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems);
- for (i = 0; i < emptyRefs.Size(); i++)
+ 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 CUpdateItem &ui = updateItems[emptyRefs[i]];
- CFileItem file;
- CFileItem2 file2;
- if (ui.NewProps)
- FromUpdateItemToFileItem(ui, file, file2);
- else
- db->GetFile(ui.IndexInArchive, file, file2);
- newDatabase.AddFile(file, file2);
+ const CByteBuffer &buf = secureBlocks.Bufs[secureBlocks.Sorted[i]];
+ size_t size = buf.GetCapacity();
+ memcpy(newDatabase.SecureBuf + pos, buf, size);
+ newDatabase.SecureSizes.Add((UInt32)size);
+ pos += size;
}
}
-
+ */
newDatabase.ReserveDown();
return S_OK;
}
diff --git a/CPP/7zip/Archive/7z/7zUpdate.h b/CPP/7zip/Archive/7z/7zUpdate.h
index 31e36224..d00276e0 100755..100644
--- a/CPP/7zip/Archive/7z/7zUpdate.h
+++ b/CPP/7zip/Archive/7z/7zUpdate.h
@@ -3,15 +3,31 @@
#ifndef __7Z_UPDATE_H
#define __7Z_UPDATE_H
+#include "../IArchive.h"
+
+// #include "../../Common/UniqBlocks.h"
+
#include "7zCompressionMode.h"
#include "7zIn.h"
#include "7zOut.h"
-#include "../IArchive.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;
@@ -23,6 +39,15 @@ struct CUpdateItem
UInt64 Size;
UString Name;
+ /*
+ bool IsAltStream;
+ int ParentFolderIndex;
+ int TreeFolderIndex;
+ */
+
+ // that code is not used in 9.26
+ // int ParentSortIndex;
+ // int ParentSortIndexEnd;
UInt32 Attrib;
@@ -37,15 +62,20 @@ struct CUpdateItem
bool ATimeDefined;
bool MTimeDefined;
+ // int SecureIndex; // 0 means (no_security)
+
bool HasStream() const { return !IsDir && !IsAnti && Size != 0; }
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); };
@@ -72,10 +102,12 @@ struct CUpdateOptions
HRESULT Update(
DECL_EXTERNAL_CODECS_LOC_VARS
IInStream *inStream,
- const CArchiveDatabaseEx *db,
+ const CDbEx *db,
const CObjectVector<CUpdateItem> &updateItems,
+ // const CObjectVector<CTreeFolder> &treeFolders, // treeFolders[0] is root
+ // const CUniqBlocks &secureBlocks,
COutArchive &archive,
- CArchiveDatabase &newDatabase,
+ CArchiveDatabaseOut &newDatabase,
ISequentialOutStream *seqOutStream,
IArchiveUpdateCallback *updateCallback,
const CUpdateOptions &options
diff --git a/CPP/7zip/Archive/7z/StdAfx.cpp b/CPP/7zip/Archive/7z/StdAfx.cpp
index d0feea85..d0feea85 100755..100644
--- a/CPP/7zip/Archive/7z/StdAfx.cpp
+++ b/CPP/7zip/Archive/7z/StdAfx.cpp
diff --git a/CPP/7zip/Archive/7z/StdAfx.h b/CPP/7zip/Archive/7z/StdAfx.h
index 2e4be10b..2854ff3e 100755..100644
--- a/CPP/7zip/Archive/7z/StdAfx.h
+++ b/CPP/7zip/Archive/7z/StdAfx.h
@@ -3,7 +3,6 @@
#ifndef __STDAFX_H
#define __STDAFX_H
-#include "../../../Common/MyWindows.h"
-#include "../../../Common/NewHandler.h"
+#include "../../../Common/Common.h"
#endif
diff --git a/CPP/7zip/Archive/7z/makefile b/CPP/7zip/Archive/7z/makefile
index 0abb3756..19982112 100755..100644
--- a/CPP/7zip/Archive/7z/makefile
+++ b/CPP/7zip/Archive/7z/makefile
@@ -1,6 +1,6 @@
PROG = 7z.dll
-DEF_FILE = ../Archive.def
-CFLAGS = $(CFLAGS) -I ../../../ \
+DEF_FILE = ../../Archive/Archive2.def
+CFLAGS = $(CFLAGS) \
-DEXTERNAL_CODECS \
AR_OBJS = \
@@ -32,12 +32,14 @@ COMMON_OBJS = \
$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 \
@@ -52,6 +54,7 @@ WIN_OBJS = \
$O\MethodProps.obj \
$O\OutBuffer.obj \
$O\ProgressUtils.obj \
+ $O\PropId.obj \
$O\StreamBinder.obj \
$O\StreamObjects.obj \
$O\StreamUtils.obj \
@@ -73,38 +76,4 @@ C_OBJS = \
$O\CpuArch.obj \
$O\Threads.obj \
-!include "../../Crc.mak"
-
-OBJS = \
- $O\StdAfx.obj \
- $(AR_OBJS) \
- $(7Z_OBJS) \
- $(COMMON_OBJS) \
- $(WIN_OBJS) \
- $(7ZIP_COMMON_OBJS) \
- $(AR_COMMON_OBJS) \
- $O\CopyCoder.obj \
- $(C_OBJS) \
- $(ASM_OBJS) \
- $O\resource.res
-
-!include "../../../Build.mak"
-
-$(AR_OBJS): ../$(*B).cpp
- $(COMPL)
-$(7Z_OBJS): $(*B).cpp
- $(COMPL)
-$(COMMON_OBJS): ../../../Common/$(*B).cpp
- $(COMPL)
-$(WIN_OBJS): ../../../Windows/$(*B).cpp
- $(COMPL)
-$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
- $(COMPL)
-$(AR_COMMON_OBJS): ../Common/$(*B).cpp
- $(COMPL)
-$O\CopyCoder.obj: ../../Compress/$(*B).cpp
- $(COMPL)
-$(C_OBJS): ../../../../C/$(*B).c
- $(COMPL_O2)
-
-!include "../../Asm.mak"
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Archive/7z/resource.rc b/CPP/7zip/Archive/7z/resource.rc
index f79dac08..f79dac08 100755..100644
--- a/CPP/7zip/Archive/7z/resource.rc
+++ b/CPP/7zip/Archive/7z/resource.rc
diff --git a/CPP/7zip/Archive/ApmHandler.cpp b/CPP/7zip/Archive/ApmHandler.cpp
index a3b5e19b..04cd06fa 100755..100644
--- a/CPP/7zip/Archive/ApmHandler.cpp
+++ b/CPP/7zip/Archive/ApmHandler.cpp
@@ -4,11 +4,12 @@
#include "../../../C/CpuArch.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/MyString.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/Defs.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyString.h"
-#include "Windows/PropVariant.h"
+#include "../../Windows/PropVariant.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -25,6 +26,9 @@ using namespace NWindows;
namespace NArchive {
namespace NApm {
+static const Byte kSig0 = 'E';
+static const Byte kSig1 = 'R';
+
struct CItem
{
UInt32 StartBlock;
@@ -45,13 +49,13 @@ struct CItem
bool Parse(const Byte *p, UInt32 &numBlocksInMap)
{
- if (p[0] != 0x50 || p[1] != 0x4D || p[2] != 0 || p[3] != 0)
- return false;
numBlocksInMap = Get32(p + 4);
StartBlock = Get32(p + 8);
NumBlocks = Get32(p + 0xC);
memcpy(Name, p + 0x10, 32);
memcpy(Type, p + 0x30, 32);
+ if (p[0] != 0x50 || p[1] != 0x4D || p[2] != 0 || p[3] != 0)
+ return false;
/*
DataStartBlock = Get32(p + 0x50);
NumDataBlocks = Get32(p + 0x54);
@@ -76,42 +80,56 @@ class CHandler:
public IInArchiveGetStream,
public CMyUnknownImp
{
- CMyComPtr<IInStream> _stream;
CRecordVector<CItem> _items;
-
- int _blockSizeLog;
+ CMyComPtr<IInStream> _stream;
+ unsigned _blockSizeLog;
UInt32 _numBlocks;
+ UInt64 _phySize;
+ bool _isArc;
HRESULT ReadTables(IInStream *stream);
UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; }
- UInt64 GetItemSize(const CItem &item) { return BlocksToBytes(item.NumBlocks); }
+ UInt64 GetItemSize(const CItem &item) const { return BlocksToBytes(item.NumBlocks); }
public:
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
};
-static inline int GetLog(UInt32 num)
+static const UInt32 kSectorSize = 512;
+
+API_FUNC_static_IsArc IsArc_Apm(const Byte *p, size_t size)
{
- for (int i = 0; i < 31; i++)
- if (((UInt32)1 << i) == num)
- return i;
- return -1;
+ 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)
{
- const UInt32 kSectorSize = 512;
Byte buf[kSectorSize];
{
RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
- if (buf[0] != 0x45 || buf[1] != 0x52)
- return S_FALSE;
- _blockSizeLog = GetLog(Get16(buf + 2));
- if (_blockSizeLog < 9 || _blockSizeLog > 14)
+ 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 (int i = 8; i < 16; i++)
+ for (i = 8; i < 16; i++)
if (buf[i] != 0)
return S_FALSE;
}
@@ -123,13 +141,14 @@ HRESULT CHandler::ReadTables(IInStream *stream)
}
UInt32 numBlocksInMap = 0;
+
for (unsigned i = 0;;)
{
RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
CItem item;
- UInt32 numBlocksInMap2;
+ UInt32 numBlocksInMap2 = 0;
if (!item.Parse(buf, numBlocksInMap2))
return S_FALSE;
if (i == 0)
@@ -154,12 +173,13 @@ HRESULT CHandler::ReadTables(IInStream *stream)
if (++i == numBlocksInMap)
break;
}
+
+ _phySize = BlocksToBytes(_numBlocks);
+ _isArc = true;
return S_OK;
}
-STDMETHODIMP CHandler::Open(IInStream *stream,
- const UInt64 * /* maxCheckStartPosition */,
- IArchiveOpenCallback * /* openArchiveCallback */)
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */)
{
COM_TRY_BEGIN
Close();
@@ -171,22 +191,23 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
STDMETHODIMP CHandler::Close()
{
+ _isArc = false;
+ _phySize = 0;
_items.Clear();
_stream.Release();
return S_OK;
}
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidOffset, VT_UI8}
+ kpidPath,
+ kpidSize,
+ kpidOffset
};
-STATPROPSTG kArcProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidClusterSize, VT_UI4},
- { NULL, kpidPhySize, VT_UI8}
+ kpidClusterSize
};
IMP_IInArchive_Props
@@ -195,7 +216,7 @@ IMP_IInArchive_ArcProps
static AString GetString(const char *s)
{
AString res;
- for (int i = 0; i < 32 && s[i] != 0; i++)
+ for (unsigned i = 0; i < 32 && s[i] != 0; i++)
res += s[i];
return res;
}
@@ -204,12 +225,12 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidMainSubfile:
{
int mainIndex = -1;
- for (int i = 0; i < _items.Size(); i++)
+ FOR_VECTOR (i, _items)
{
AString s = GetString(_items[i].Type);
if (s != "Apple_Free" &&
@@ -228,7 +249,15 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
break;
}
case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break;
- case kpidPhySize: prop = BlocksToBytes(_numBlocks); 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;
@@ -246,7 +275,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
COM_TRY_BEGIN
NCOM::CPropVariant prop;
const CItem &item = _items[index];
- switch(propID)
+ switch (propID)
{
case kpidPath:
{
@@ -283,7 +312,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items.Size();
if (numItems == 0)
@@ -346,10 +375,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"APM", L"", 0, 0xD4, { 0x50, 0x4D, 0, 0, 0, 0, 0 }, 7, false, CreateArc, 0 };
+ { "APM", "apm", 0, 0xD4,
+ 2, { kSig0, kSig1 },
+ 0,
+ 0,
+ CreateArc, NULL, IsArc_Apm };
REGISTER_ARC(Apm)
diff --git a/CPP/7zip/Archive/ArHandler.cpp b/CPP/7zip/Archive/ArHandler.cpp
new file mode 100644
index 00000000..b7dcda85
--- /dev/null
+++ b/CPP/7zip/Archive/ArHandler.cpp
@@ -0,0 +1,857 @@
+// 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 *k_TypeExtionsions[] =
+{
+ "ar"
+ , "a"
+ , "deb"
+ , "lib"
+};
+
+enum ESubType
+{
+ kSubType_None,
+ kSubType_BSD
+};
+
+/*
+struct CHeader
+{
+ char Name[kNameSize];
+ char MTime[kTimeSize];
+ char User[kUserSize];
+ char Group[kUserSize];
+ char Mode[kModeSize];
+ char Size[kSizeSize];
+ char Quote;
+ char NewLine;
+};
+*/
+
+struct CItem
+{
+ AString Name;
+ UInt64 Size;
+ UInt32 MTime;
+ UInt32 User;
+ UInt32 Group;
+ UInt32 Mode;
+
+ UInt64 HeaderPos;
+ UInt64 HeaderSize;
+
+ int TextFileIndex;
+ int SameNameIndex;
+
+ CItem(): TextFileIndex(-1), SameNameIndex(-1) {}
+ UInt64 GetDataPos() const { return HeaderPos + HeaderSize; };
+};
+
+class CInArchive
+{
+ CMyComPtr<IInStream> m_Stream;
+
+public:
+ UInt64 Position;
+ ESubType SubType;
+
+ HRESULT GetNextItem(CItem &itemInfo, bool &filled);
+ HRESULT Open(IInStream *inStream);
+ HRESULT SkipData(UInt64 dataSize)
+ {
+ return m_Stream->Seek(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)
+ return true; // some items doesn't contaion 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)
+ return true; // some items doesn't contaion 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.GetBuffer(longNameLen);
+ HRESULT res = ReadStream(m_Stream, s, &processedSize);
+ s[longNameLen] = 0;
+ item.Name.ReleaseBuffer();
+ 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<CItem> _items;
+ CMyComPtr<IInStream> _stream;
+ Int32 _mainSubfile;
+ UInt64 _phySize;
+
+ EType _type;
+ ESubType _subType;
+ int _longNames_FileIndex;
+ AString _libFiles[2];
+ unsigned _numLibFiles;
+ AString _errorMessage;
+ bool _isArc;
+
+
+ void UpdateErrorMessage(const char *s);
+
+ HRESULT ParseLongNames(IInStream *stream);
+ void ChangeDuplicateNames();
+ int FindItem(UInt32 offset) const;
+ HRESULT AddFunc(UInt32 offset, const Byte *data, size_t size, size_t &pos);
+ HRESULT ParseLibSymbols(IInStream *stream, unsigned fileIndex);
+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));
+ size_t size = (size_t)item.Size;
+
+ CByteArr p(size);
+ RINOK(ReadStream_FALSE(stream, p, size));
+ for (i = 0; i < _items.Size(); i++)
+ {
+ CItem &item = _items[i];
+ if (item.Name[0] != '/')
+ continue;
+ const char *ptr = item.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++;
+ }
+ item.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[_type]; break;
+ case kpidShortComment:
+ case kpidSubType:
+ {
+ AString s = k_TypeExtionsions[_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::GetOSName2(MultiByteToUnicodeString(item.Name, CP_OEMCP));
+ break;
+ case kpidSize:
+ case kpidPackSize:
+ if (item.TextFileIndex >= 0)
+ prop = (UInt64)_libFiles[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[item.TextFileIndex].Len() : item.Size;
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ 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[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[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[item.TextFileIndex];
+ Create_BufInStream_WithNewBuf((const void *)(const char *)f, f.Len(), stream);
+ return S_OK;
+ }
+ else
+ return CreateLimitedInStream(_stream, item.GetDataPos(), item.Size, stream);
+ COM_TRY_END
+}
+
+IMP_CreateArcIn
+
+static CArcInfo g_ArcInfo =
+ { "Ar", "ar a deb lib", 0, 0xEC,
+ kSignatureLen, SIGNATURE,
+ 0,
+ 0,
+ CreateArc };
+
+REGISTER_ARC(Ar)
+
+}}
diff --git a/CPP/7zip/Archive/Archive.def b/CPP/7zip/Archive/Archive.def
index 55b530b2..55b530b2 100755..100644
--- a/CPP/7zip/Archive/Archive.def
+++ b/CPP/7zip/Archive/Archive.def
diff --git a/CPP/7zip/Archive/Archive2.def b/CPP/7zip/Archive/Archive2.def
index 885d39d1..66feb41d 100755..100644
--- a/CPP/7zip/Archive/Archive2.def
+++ b/CPP/7zip/Archive/Archive2.def
@@ -3,7 +3,9 @@ EXPORTS
GetHandlerProperty PRIVATE
GetNumberOfFormats PRIVATE
GetHandlerProperty2 PRIVATE
- CreateObject PRIVATE
GetNumberOfMethods PRIVATE
GetMethodProperty PRIVATE
+ GetHashers PRIVATE
SetLargePageMode PRIVATE
+ SetCaseSensitive PRIVATE
+ GetIsArc PRIVATE \ No newline at end of file
diff --git a/CPP/7zip/Archive/ArchiveExports.cpp b/CPP/7zip/Archive/ArchiveExports.cpp
index c7908b59..c7d6611b 100755..100644
--- a/CPP/7zip/Archive/ArchiveExports.cpp
+++ b/CPP/7zip/Archive/ArchiveExports.cpp
@@ -2,24 +2,28 @@
#include "StdAfx.h"
+#include "../../../C/7zVersion.h"
+
#include "../../Common/ComTry.h"
#include "../../Windows/PropVariant.h"
#include "../Common/RegisterArc.h"
-static const unsigned int kNumArcsMax = 48;
-static unsigned int g_NumArcs = 0;
-static unsigned int g_DefaultArcIndex = 0;
+static const unsigned kNumArcsMax = 64;
+static unsigned g_NumArcs = 0;
+static unsigned g_DefaultArcIndex = 0;
static const CArcInfo *g_Arcs[kNumArcsMax];
+
void RegisterArc(const CArcInfo *arcInfo)
{
if (g_NumArcs < kNumArcsMax)
{
- const wchar_t *p = arcInfo->Name;
+ const char *p = arcInfo->Name;
if (p[0] == '7' && p[1] == 'z' && p[2] == 0)
g_DefaultArcIndex = g_NumArcs;
- g_Arcs[g_NumArcs++] = arcInfo;
+ g_Arcs[g_NumArcs] = arcInfo;
+ g_NumArcs++;
}
}
@@ -28,7 +32,7 @@ DEFINE_GUID(CLSID_CArchiveHandler,
#define CLS_ARC_ID_ITEM(cls) ((cls).Data4[5])
-static inline HRESULT SetPropString(const char *s, unsigned int size, PROPVARIANT *value)
+static inline HRESULT SetPropString(const char *s, unsigned size, PROPVARIANT *value)
{
if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != 0)
value->vt = VT_BSTR;
@@ -86,37 +90,38 @@ STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject)
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)
+ switch (propID)
{
- case NArchive::kName:
- prop = arc.Name;
- break;
- case NArchive::kClassID:
+ case NArchive::NHandlerPropID::kName: prop = arc.Name; break;
+ case NArchive::NHandlerPropID::kClassID:
{
GUID clsId = CLSID_CArchiveHandler;
CLS_ARC_ID_ITEM(clsId) = arc.ClassId;
return SetPropGUID(clsId, value);
}
- case NArchive::kExtension:
- if (arc.Ext != 0)
- prop = arc.Ext;
- break;
- case NArchive::kAddExtension:
- if (arc.AddExt != 0)
- prop = arc.AddExt;
- break;
- case NArchive::kUpdate:
- prop = (bool)(arc.CreateOutArchive != 0);
+ 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.IsMultiSignature())
+ return SetPropString((const char *)arc.Signature, arc.SignatureSize, value);
break;
- case NArchive::kKeepName:
- prop = arc.KeepName;
+ case NArchive::NHandlerPropID::kMultiSignature:
+ if (arc.IsMultiSignature())
+ return SetPropString((const char *)arc.Signature, arc.SignatureSize, value);
break;
- case NArchive::kStartSignature:
- return SetPropString((const char *)arc.Signature, arc.SignatureSize, value);
}
prop.Detach(value);
return S_OK;
@@ -133,3 +138,12 @@ 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 4dd686ec..ad44c62a 100755..100644
--- a/CPP/7zip/Archive/ArjHandler.cpp
+++ b/CPP/7zip/Archive/ArjHandler.cpp
@@ -4,11 +4,12 @@
#include "../../../C/CpuArch.h"
-#include "Common/ComTry.h"
-#include "Common/StringConvert.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/StringConvert.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -31,74 +32,85 @@ using namespace NWindows;
namespace NArchive {
namespace NArj {
-const int kBlockSizeMin = 30;
-const int kBlockSizeMax = 2600;
+static const unsigned kBlockSizeMin = 30;
+static const unsigned kBlockSizeMax = 2600;
-namespace NSignature
+static const Byte kSig0 = 0x60;
+static const Byte kSig1 = 0xEA;
+
+namespace NCompressionMethod
{
- const Byte kSig0 = 0x60;
- const Byte kSig1 = 0xEA;
+ enum
+ {
+ kStored = 0,
+ kCompressed1a = 1,
+ kCompressed1b = 2,
+ kCompressed1c = 3,
+ kCompressed2 = 4,
+ kNoDataNoCRC = 8,
+ kNoData = 9
+ };
}
-namespace NFileHeader
+namespace NFileType
{
- namespace NCompressionMethod
+ enum
{
- enum
- {
- kStored = 0,
- kCompressed1a = 1,
- kCompressed1b = 2,
- kCompressed1c = 3,
- kCompressed2 = 4,
- kNoDataNoCRC = 8,
- kNoData = 9
- };
- }
+ kBinary = 0,
+ k7BitText,
+ kArchiveHeader,
+ kDirectory,
+ kVolumeLablel,
+ kChapterLabel
+ };
+}
- namespace NFileType
- {
- enum
- {
- kBinary = 0,
- k7BitText = 1,
- kArchiveHeader = 2,
- kDirectory = 3,
- kVolumeLablel = 4,
- kChapterLabel = 5
- };
- }
-
- namespace NFlags
- {
- const Byte kGarbled = 1;
- const Byte kVolume = 4;
- const Byte kExtFile = 8;
- const Byte kPathSym = 0x10;
- const Byte kBackup = 0x20;
- }
+namespace 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
+namespace NHostOS
+{
+ enum EEnum
{
- enum EEnum
- {
- kMSDOS = 0, // filesystem used by MS-DOS, OS/2, Win32
- // pkarj 2.50 (FAT / VFAT / FAT32 file systems)
- kPRIMOS,
- kUnix,
- kAMIGA,
- kMac,
- kOS_2,
- kAPPLE_GS,
- kAtari_ST,
- kNext,
- kVAX_VMS,
- kWIN95
- };
- }
+ 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
+ };
}
-struct CArchiveHeader
+static const char *kHostOS[] =
+{
+ "MSDOS"
+ , "PRIMOS"
+ , "UNIX"
+ , "AMIGA"
+ , "MAC"
+ , "OS/2"
+ , "APPLE GS"
+ , "ATARI ST"
+ , "NEXT"
+ , "VAX VMS"
+ , "WIN95"
+};
+
+struct CArcHeader
{
// Byte ArchiverVersion;
// Byte ExtractVersion;
@@ -110,9 +122,9 @@ struct CArchiveHeader
UInt32 CTime;
UInt32 MTime;
UInt32 ArchiveSize;
- // UInt32 SecurityEnvelopeFilePosition;
- // UInt16 FilespecPositionInFilename;
- // UInt16 LengthOfSecurityEnvelopeSata;
+ // UInt32 SecurPos;
+ // UInt16 FilespecPosInFilename;
+ UInt16 SecurSize;
// Byte EncryptionVersion;
// Byte LastChapter;
AString Name;
@@ -121,47 +133,71 @@ struct CArchiveHeader
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)
{
- AString s;
for (unsigned i = 0; i < size;)
{
char c = (char)p[i++];
if (c == 0)
{
size = i;
- res = s;
+ res = (const char *)p;
return S_OK;
}
- s += c;
}
return S_FALSE;
}
-HRESULT CArchiveHeader::Parse(const Byte *p, unsigned size)
+HRESULT CArcHeader::Parse(const Byte *p, unsigned size)
{
- if (size < kBlockSizeMin)
- return S_FALSE;
- Byte firstHeaderSize = p[0];
- if (firstHeaderSize > 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] != NFileHeader::NFileType::kArchiveHeader)
+ if (p[6] != NFileType::kArchiveHeader)
return S_FALSE;
// Reserved = p[7];
CTime = Get32(p + 8);
MTime = Get32(p + 12);
- ArchiveSize = Get32(p + 16);
- // SecurityEnvelopeFilePosition = Get32(p + 20);
+ ArchiveSize = Get32(p + 16); // it can be zero. (currently used only for secured archives)
+ // SecurPos = Get32(p + 20);
// UInt16 filespecPositionInFilename = Get16(p + 24);
- // LengthOfSecurityEnvelopeSata = Get16(p + 26);
+ SecurSize = Get16(p + 26);
// EncryptionVersion = p[28];
// LastChapter = p[29];
- unsigned pos = firstHeaderSize;
+ unsigned pos = headerSize;
unsigned size1 = size - pos;
RINOK(ReadString(p + pos, size1, Name));
pos += size1;
@@ -189,32 +225,30 @@ struct CItem
Byte Method;
Byte FileType;
- // UInt16 FilespecPositionInFilename;
+ // UInt16 FilespecPosInFilename;
UInt16 FileAccessMode;
// Byte FirstChapter;
// Byte LastChapter;
UInt64 DataPosition;
- bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kGarbled) != 0; }
- bool IsDir() const { return (FileType == NFileHeader::NFileType::kDirectory); }
- bool IsSplitAfter() const { return (Flags & NFileHeader::NFlags::kVolume) != 0; }
- bool IsSplitBefore() const { return (Flags & NFileHeader::NFlags::kExtFile) != 0; }
- UInt32 GetWinAttributes() const
+ 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 winAtrributes;
- switch(HostOS)
+ UInt32 atrrib = 0;
+ switch (HostOS)
{
- case NFileHeader::NHostOS::kMSDOS:
- case NFileHeader::NHostOS::kWIN95:
- winAtrributes = FileAccessMode;
+ case NHostOS::kMSDOS:
+ case NHostOS::kWIN95:
+ atrrib = FileAccessMode;
break;
- default:
- winAtrributes = 0;
}
if (IsDir())
- winAtrributes |= FILE_ATTRIBUTE_DIRECTORY;
- return winAtrributes;
+ atrrib |= FILE_ATTRIBUTE_DIRECTORY;
+ return atrrib;
}
HRESULT Parse(const Byte *p, unsigned size);
@@ -222,11 +256,9 @@ struct CItem
HRESULT CItem::Parse(const Byte *p, unsigned size)
{
- if (size < kBlockSizeMin)
+ Byte headerSize = p[0];
+ if (headerSize < kBlockSizeMin || headerSize > size)
return S_FALSE;
-
- Byte firstHeaderSize = p[0];
-
Version = p[1];
ExtractVersion = p[2];
HostOS = p[3];
@@ -238,16 +270,16 @@ HRESULT CItem::Parse(const Byte *p, unsigned size)
PackSize = Get32(p + 12);
Size = Get32(p + 16);
FileCRC = Get32(p + 20);
- // FilespecPositionInFilename = Get16(p + 24);
+ // FilespecPosInFilename = Get16(p + 24);
FileAccessMode = Get16(p + 26);
// FirstChapter = p[28];
// FirstChapter = p[29];
SplitPos = 0;
- if (IsSplitBefore() && firstHeaderSize >= 34)
+ if (IsSplitBefore() && headerSize >= 34)
SplitPos = Get32(p + 30);
- unsigned pos = firstHeaderSize;
+ unsigned pos = headerSize;
unsigned size1 = size - pos;
RINOK(ReadString(p + pos, size1, Name));
pos += size1;
@@ -258,180 +290,121 @@ HRESULT CItem::Parse(const Byte *p, unsigned size)
return S_OK;
}
-struct CInArchiveException
+enum EErrorType
{
- enum CCauseType
- {
- kUnexpectedEndOfArchive = 0,
- kCRCError,
- kIncorrectArchive
- }
- Cause;
- CInArchiveException(CCauseType cause): Cause(cause) {};
+ k_ErrorType_OK,
+ k_ErrorType_Corrupted,
+ k_ErrorType_UnexpectedEnd,
};
-class CInArchive
+class CArc
{
- UInt32 _blockSize;
- Byte _block[kBlockSizeMax + 4];
-
- HRESULT ReadBlock(bool &filled);
- HRESULT ReadSignatureAndBlock(bool &filled);
- HRESULT SkipExtendedHeaders();
-
- HRESULT SafeReadBytes(void *data, UInt32 size);
-
public:
- CArchiveHeader Header;
-
+ UInt64 Processed;
+ EErrorType Error;
+ bool IsArc;
IInStream *Stream;
IArchiveOpenCallback *Callback;
UInt64 NumFiles;
- UInt64 NumBytes;
+ CArcHeader Header;
- HRESULT Open(const UInt64 *searchHeaderSizeLimit);
- HRESULT GetNextItem(bool &filled, CItem &item);
-};
-
-static inline bool TestMarkerCandidate(const Byte *p, unsigned maxSize)
-{
- if (p[0] != NSignature::kSig0 || p[1] != NSignature::kSig1)
- return false;
- UInt32 blockSize = Get16(p + 2);
- p += 4;
- if (p[6] != NFileHeader::NFileType::kArchiveHeader ||
- p[0] > blockSize ||
- maxSize < 2 + 2 + blockSize + 4 ||
- blockSize < kBlockSizeMin || blockSize > kBlockSizeMax ||
- p[28] > 8) // EncryptionVersion
- return false;
- // return (Get32(p + blockSize) == CrcCalc(p, blockSize));
- return true;
-}
-
-static HRESULT FindAndReadMarker(ISequentialInStream *stream, const UInt64 *searchHeaderSizeLimit, UInt64 &position)
-{
- position = 0;
-
- const int kMarkerSizeMin = 2 + 2 + kBlockSizeMin + 4;
- const int kMarkerSizeMax = 2 + 2 + kBlockSizeMax + 4;
-
- CByteBuffer byteBuffer;
- const UInt32 kBufSize = 1 << 16;
- byteBuffer.SetCapacity(kBufSize);
- Byte *buf = byteBuffer;
-
- size_t processedSize = kMarkerSizeMax;
- RINOK(ReadStream(stream, buf, &processedSize));
- if (processedSize < kMarkerSizeMin)
- return S_FALSE;
- if (TestMarkerCandidate(buf, (unsigned)processedSize))
- return S_OK;
-
- UInt32 numBytesPrev = (UInt32)processedSize - 1;
- memmove(buf, buf + 1, numBytesPrev);
- UInt64 curTestPos = 1;
- for (;;)
+ HRESULT Open();
+ HRESULT GetNextItem(CItem &item, bool &filled);
+ void Close()
{
- if (searchHeaderSizeLimit != NULL)
- if (curTestPos > *searchHeaderSizeLimit)
- return S_FALSE;
- processedSize = kBufSize - numBytesPrev;
- RINOK(ReadStream(stream, buf + numBytesPrev, &processedSize));
- UInt32 numBytesInBuffer = numBytesPrev + (UInt32)processedSize;
- if (numBytesInBuffer < kMarkerSizeMin)
- return S_FALSE;
- UInt32 numTests = numBytesInBuffer - kMarkerSizeMin + 1;
- UInt32 pos;
- for (pos = 0; pos < numTests; pos++)
- {
- for (; buf[pos] != NSignature::kSig0 && pos < numTests; pos++);
- if (pos == numTests)
- break;
- if (TestMarkerCandidate(buf + pos, numBytesInBuffer - pos))
- {
- position = curTestPos + pos;
- return S_OK;
- }
- }
- curTestPos += pos;
- numBytesPrev = numBytesInBuffer - numTests;
- memmove(buf, buf + numTests, numBytesPrev);
+ IsArc = false;
+ Error = k_ErrorType_OK;
}
-}
+private:
+ UInt32 _blockSize;
+ Byte _block[kBlockSizeMax + 4];
-HRESULT CInArchive::SafeReadBytes(void *data, UInt32 size)
+ HRESULT ReadBlock(bool &filled, bool readSignature);
+ HRESULT SkipExtendedHeaders();
+ HRESULT Read(void *data, size_t *size);
+};
+
+HRESULT CArc::Read(void *data, size_t *size)
{
- size_t processed = size;
- RINOK(ReadStream(Stream, data, &processed));
- if (processed != size)
- throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
- return S_OK;
+ HRESULT res = ReadStream(Stream, data, size);
+ Processed += *size;
+ return res;
}
-HRESULT CInArchive::ReadBlock(bool &filled)
+#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[2];
- RINOK(SafeReadBytes(buf, 2));
- _blockSize = Get16(buf);
- if (_blockSize == 0)
+ 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;
- if (_blockSize > kBlockSizeMax)
- throw CInArchiveException(CInArchiveException::kIncorrectArchive);
- RINOK(SafeReadBytes(_block, _blockSize + 4));
- NumBytes += _blockSize + 6;
+ }
+ READ_STREAM(_block, _blockSize + 4);
if (Get32(_block + _blockSize) != CrcCalc(_block, _blockSize))
- throw CInArchiveException(CInArchiveException::kCRCError);
+ {
+ Error = k_ErrorType_Corrupted;
+ return S_OK;
+ }
filled = true;
return S_OK;
}
-HRESULT CInArchive::ReadSignatureAndBlock(bool &filled)
-{
- Byte id[2];
- RINOK(SafeReadBytes(id, 2));
- if (id[0] != NSignature::kSig0 || id[1] != NSignature::kSig1)
- throw CInArchiveException(CInArchiveException::kIncorrectArchive);
- return ReadBlock(filled);
-}
-
-HRESULT CInArchive::SkipExtendedHeaders()
+HRESULT CArc::SkipExtendedHeaders()
{
for (UInt32 i = 0;; i++)
{
bool filled;
- RINOK(ReadBlock(filled));
+ RINOK(ReadBlock(filled, false));
if (!filled)
return S_OK;
if (Callback && (i & 0xFF) == 0)
- RINOK(Callback->SetCompleted(&NumFiles, &NumBytes));
+ RINOK(Callback->SetCompleted(&NumFiles, &Processed));
}
}
-HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit)
+HRESULT CArc::Open()
{
- UInt64 position = 0;
- RINOK(FindAndReadMarker(Stream, searchHeaderSizeLimit, position));
- RINOK(Stream->Seek(position, STREAM_SEEK_SET, NULL));
bool filled;
- RINOK(ReadSignatureAndBlock(filled));
+ RINOK(ReadBlock(filled, true));
if (!filled)
return S_FALSE;
RINOK(Header.Parse(_block, _blockSize));
+ IsArc = true;
return SkipExtendedHeaders();
}
-HRESULT CInArchive::GetNextItem(bool &filled, CItem &item)
+HRESULT CArc::GetNextItem(CItem &item, bool &filled)
{
- RINOK(ReadSignatureAndBlock(filled));
+ RINOK(ReadBlock(filled, true));
if (!filled)
return S_OK;
filled = false;
- RINOK(item.Parse(_block, _blockSize));
+ if (item.Parse(_block, _blockSize) != S_OK)
+ {
+ Error = k_ErrorType_Corrupted;
+ return S_OK;
+ }
/*
UInt32 extraData;
- if ((header.Flags & NFileHeader::NFlags::kExtFile) != 0)
+ if ((header.Flags & NFlags::kExtFile) != 0)
extraData = GetUi32(_block + pos);
*/
@@ -444,67 +417,47 @@ class CHandler:
public IInArchive,
public CMyUnknownImp
{
+ CObjectVector<CItem> _items;
+ CMyComPtr<IInStream> _stream;
+ UInt64 _phySize;
+ CArc _arc;
public:
MY_UNKNOWN_IMP1(IInArchive)
INTERFACE_IInArchive(;)
- HRESULT Open2(IInStream *inStream, const UInt64 *maxCheckStartPosition,
- IArchiveOpenCallback *callback);
-private:
- CInArchive _archive;
- CObjectVector<CItem> _items;
- CMyComPtr<IInStream> _stream;
+ HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback);
};
-const wchar_t *kHostOS[] =
+static const Byte kArcProps[] =
{
- L"MSDOS",
- L"PRIMOS",
- L"UNIX",
- L"AMIGA",
- L"MAC",
- L"OS/2",
- L"APPLE GS",
- L"ATARI ST",
- L"NEXT",
- L"VAX VMS",
- L"WIN95"
+ kpidName,
+ kpidCTime,
+ kpidMTime,
+ kpidHostOS,
+ kpidComment
};
-const wchar_t *kUnknownOS = L"Unknown";
-
-const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);
-
-STATPROPSTG kArcProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidName, VT_BSTR},
- { NULL, kpidCTime, VT_BSTR},
- { NULL, kpidMTime, VT_BSTR},
- { NULL, kpidHostOS, VT_BSTR},
- { NULL, kpidComment, VT_BSTR}
-};
-
-STATPROPSTG kProps[] =
-{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI4},
- { NULL, kpidPosition, VT_UI8},
- { NULL, kpidPackSize, VT_UI4},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidAttrib, VT_UI4},
- { NULL, kpidEncrypted, VT_BOOL},
- { NULL, kpidCRC, VT_UI4},
- { NULL, kpidMethod, VT_UI1},
- { NULL, kpidHostOS, VT_BSTR},
- { NULL, kpidComment, VT_BSTR}
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPosition,
+ kpidPackSize,
+ kpidMTime,
+ kpidAttrib,
+ kpidEncrypted,
+ kpidCRC,
+ kpidMethod,
+ kpidHostOS,
+ kpidComment
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
-static void SetTime(UInt32 dosTime, NWindows::NCOM::CPropVariant &prop)
+static void SetTime(UInt32 dosTime, NCOM::CPropVariant &prop)
{
if (dosTime == 0)
return;
@@ -519,12 +472,21 @@ static void SetTime(UInt32 dosTime, NWindows::NCOM::CPropVariant &prop)
prop = utc;
}
-static void SetHostOS(Byte hostOS, NWindows::NCOM::CPropVariant &prop)
+static void SetHostOS(Byte hostOS, NCOM::CPropVariant &prop)
{
- prop = hostOS < kNumHostOSes ? kHostOS[hostOS] : kUnknownOS;
+ char temp[16];
+ const char *s = NULL;
+ if (hostOS < ARRAY_SIZE(kHostOS))
+ s = kHostOS[hostOS];
+ else
+ {
+ ConvertUInt32ToString(hostOS, temp);
+ s = temp;
+ }
+ prop = s;
}
-static void SetUnicodeString(const AString &s, NWindows::NCOM::CPropVariant &prop)
+static void SetUnicodeString(const AString &s, NCOM::CPropVariant &prop)
{
if (!s.IsEmpty())
prop = MultiByteToUnicodeString(s, CP_OEMCP);
@@ -533,14 +495,27 @@ static void SetUnicodeString(const AString &s, NWindows::NCOM::CPropVariant &pro
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ NCOM::CPropVariant prop;
+ switch (propID)
{
- case kpidName: SetUnicodeString(_archive.Header.Name, prop); break;
- case kpidCTime: SetTime(_archive.Header.CTime, prop); break;
- case kpidMTime: SetTime(_archive.Header.MTime, prop); break;
- case kpidHostOS: SetHostOS(_archive.Header.HostOS, prop); break;
- case kpidComment: SetUnicodeString(_archive.Header.Comment, prop); break;
+ 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;
@@ -556,16 +531,16 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
+ NCOM::CPropVariant prop;
const CItem &item = _items[index];
- switch(propID)
+ switch (propID)
{
case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
case kpidIsDir: prop = item.IsDir(); break;
case kpidSize: prop = item.Size; break;
case kpidPackSize: prop = item.PackSize; break;
case kpidPosition: if (item.IsSplitBefore() || item.IsSplitAfter()) prop = (UInt64)item.SplitPos; break;
- case kpidAttrib: prop = item.GetWinAttributes(); break;
+ case kpidAttrib: prop = item.GetWinAttrib(); break;
case kpidEncrypted: prop = item.IsEncrypted(); break;
case kpidCRC: prop = item.FileCRC; break;
case kpidMethod: prop = item.Method; break;
@@ -578,75 +553,88 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
COM_TRY_END
}
-HRESULT CHandler::Open2(IInStream *inStream, const UInt64 *maxCheckStartPosition,
- IArchiveOpenCallback *callback)
+HRESULT CHandler::Open2(IInStream *inStream, IArchiveOpenCallback *callback)
{
Close();
UInt64 endPos = 0;
- if (callback != NULL)
- {
- RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
- RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
- }
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
- _archive.Stream = inStream;
- _archive.Callback = callback;
- _archive.NumFiles = _archive.NumBytes = 0;
+ _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;
- RINOK(_archive.Open(maxCheckStartPosition));
- if (callback != NULL)
- RINOK(callback->SetTotal(NULL, &endPos));
for (;;)
{
CItem item;
bool filled;
+ _arc.Error = k_ErrorType_OK;
+ RINOK(_arc.GetNextItem(item, filled));
- RINOK(_archive.GetNextItem(filled, item));
-
- RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &item.DataPosition));
+ 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);
- if (inStream->Seek(item.PackSize, STREAM_SEEK_CUR, NULL) != S_OK)
- throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
+ UInt64 pos = item.DataPosition + item.PackSize;
+ if (_arc.Header.ArchiveSize == 0)
+ _phySize = pos;
+ if (pos > endPos)
+ {
+ _arc.Error = k_ErrorType_UnexpectedEnd;
+ break;
+ }
- _archive.NumFiles = _items.Size();
- _archive.NumBytes = item.DataPosition;
+ RINOK(inStream->Seek(pos, STREAM_SEEK_SET, NULL));
+ _arc.NumFiles = _items.Size();
+ _arc.Processed = pos;
- if (callback != NULL && _items.Size() % 100 == 0)
+ if (callback && (_items.Size() & 0xFF) == 0)
{
- RINOK(callback->SetCompleted(&_archive.NumFiles, &_archive.NumBytes));
+ RINOK(callback->SetCompleted(&_arc.NumFiles, &_arc.Processed));
}
}
return S_OK;
}
STDMETHODIMP CHandler::Open(IInStream *inStream,
- const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback)
+ const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback)
{
COM_TRY_BEGIN
HRESULT res;
- try
{
- res = Open2(inStream, maxCheckStartPosition, callback);
+ res = Open2(inStream, callback);
if (res == S_OK)
{
_stream = inStream;
return S_OK;
}
}
- catch(const CInArchiveException &) { res = S_FALSE; }
- Close();
return res;
COM_TRY_END
}
STDMETHODIMP CHandler::Close()
{
+ _arc.Close();
+ _phySize = 0;
_items.Clear();
_stream.Release();
return S_OK;
@@ -657,7 +645,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
COM_TRY_BEGIN
UInt64 totalUnpacked = 0, totalPacked = 0;
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items.Size();
if (numItems == 0)
@@ -736,28 +724,28 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 opRes = NExtract::NOperationResult::kOK;
if (item.IsEncrypted())
- opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
else
{
- switch(item.Method)
+ switch (item.Method)
{
- case NFileHeader::NCompressionMethod::kStored:
+ case NCompressionMethod::kStored:
{
result = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize)
result = S_FALSE;
break;
}
- case NFileHeader::NCompressionMethod::kCompressed1a:
- case NFileHeader::NCompressionMethod::kCompressed1b:
- case NFileHeader::NCompressionMethod::kCompressed1c:
+ case NCompressionMethod::kCompressed1a:
+ case NCompressionMethod::kCompressed1b:
+ case NCompressionMethod::kCompressed1c:
{
if (!arj1Decoder)
arj1Decoder = new NCompress::NArj::NDecoder1::CCoder;
result = arj1Decoder->Code(inStream, outStream, NULL, &curUnpacked, progress);
break;
}
- case NFileHeader::NCompressionMethod::kCompressed2:
+ case NCompressionMethod::kCompressed2:
{
if (!arj2Decoder)
arj2Decoder = new NCompress::NArj::NDecoder2::CCoder;
@@ -765,7 +753,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
break;
}
default:
- opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
}
}
if (opRes == NExtract::NOperationResult::kOK)
@@ -788,10 +776,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"Arj", L"arj", 0, 4, { 0x60, 0xEA }, 2, false, CreateArc, 0 };
+ { "Arj", "arj", 0, 4,
+ 2, { kSig0, kSig1 },
+ 0,
+ 0,
+ CreateArc, NULL, IsArc_Arj };
REGISTER_ARC(Arj)
diff --git a/CPP/7zip/Archive/Bz2Handler.cpp b/CPP/7zip/Archive/Bz2Handler.cpp
index 49ae8c79..704cdc73 100755..100644
--- a/CPP/7zip/Archive/Bz2Handler.cpp
+++ b/CPP/7zip/Archive/Bz2Handler.cpp
@@ -2,7 +2,7 @@
#include "StdAfx.h"
-#include "Common/ComTry.h"
+#include "../../Common/ComTry.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
@@ -29,37 +29,70 @@ class CHandler:
{
CMyComPtr<IInStream> _stream;
CMyComPtr<ISequentialInStream> _seqStream;
+
+ bool _isArc;
+ bool _needSeekToStart;
+ bool _dataAfterEnd;
+ bool _needMoreInput;
+
+ bool _packSize_Defined;
+ bool _unpackSize_Defined;
+ bool _numStreams_Defined;
+ bool _numBlocks_Defined;
+
UInt64 _packSize;
- UInt64 _startPosition;
- bool _packSizeDefined;
+ UInt64 _unpackSize;
+ UInt64 _numStreams;
+ UInt64 _numBlocks;
CSingleMethodProps _props;
public:
- MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties)
-
+ MY_UNKNOWN_IMP4(
+ IInArchive,
+ IArchiveOpenSeq,
+ IOutArchive,
+ ISetProperties)
INTERFACE_IInArchive(;)
INTERFACE_IOutArchive(;)
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
- STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps);
CHandler() { }
};
-static const STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPackSize, VT_UI8}
+ kpidSize,
+ kpidPackSize
+};
+
+static const Byte kArcProps[] =
+{
+ kpidNumStreams,
+ kpidNumBlocks
};
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO_Table
+IMP_IInArchive_ArcProps
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
NCOM::CPropVariant prop;
switch (propID)
{
- case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ 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;
@@ -71,54 +104,75 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
-STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
{
- NWindows::NCOM::CPropVariant prop;
+ NCOM::CPropVariant prop;
switch (propID)
{
- case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidPackSize: if (_packSize_Defined) prop = _packSize; break;
+ case kpidSize: if (_unpackSize_Defined) prop = _unpackSize; break;
}
prop.Detach(value);
return S_OK;
}
-STDMETHODIMP CHandler::Open(IInStream *stream,
- const UInt64 * /* maxCheckStartPosition */,
- IArchiveOpenCallback * /* openArchiveCallback */)
+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
- try
+ Close();
{
- Close();
- RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPosition));
- const int kSignatureSize = 3;
- Byte buf[kSignatureSize];
- RINOK(ReadStream_FALSE(stream, buf, kSignatureSize));
- if (buf[0] != 'B' || buf[1] != 'Z' || buf[2] != 'h')
+ Byte buf[kSignatureCheckSize];
+ RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize));
+ if (IsArc_BZip2(buf, kSignatureCheckSize) == k_IsArc_Res_NO)
return S_FALSE;
-
- UInt64 endPosition;
- RINOK(stream->Seek(0, STREAM_SEEK_END, &endPosition));
- _packSize = endPosition - _startPosition;
- _packSizeDefined = true;
+ _isArc = true;
_stream = stream;
_seqStream = stream;
+ _needSeekToStart = true;
}
- catch(...) { return S_FALSE; }
return S_OK;
COM_TRY_END
}
+
STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
{
Close();
+ _isArc = true;
_seqStream = stream;
return S_OK;
}
STDMETHODIMP CHandler::Close()
{
- _packSizeDefined = false;
+ _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;
@@ -130,13 +184,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_BEGIN
if (numItems == 0)
return S_OK;
- if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
- if (_stream)
+ if (_packSize_Defined)
extractCallback->SetTotal(_packSize);
- UInt64 currentTotalPacked = 0;
- RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+
+ // RINOK(extractCallback->SetCompleted(&packSize));
+
CMyComPtr<ISequentialOutStream> realOutStream;
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
@@ -147,14 +202,23 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
extractCallback->PrepareOperation(askMode);
- NCompress::NBZip2::CDecoder *decoderSpec = new NCompress::NBZip2::CDecoder;
- CMyComPtr<ICompressCoder> decoder = decoderSpec;
- if (_stream)
+ if (_needSeekToStart)
{
- RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ if (!_stream)
+ return E_FAIL;
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
}
+ else
+ _needSeekToStart = true;
+
+ Int32 opRes;
+
+ try
+ {
+ NCompress::NBZip2::CDecoder *decoderSpec = new NCompress::NBZip2::CDecoder;
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
decoderSpec->SetInStream(_seqStream);
#ifndef _7ZIP_ST
@@ -172,43 +236,104 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, true);
+ UInt64 packSize = 0;
+ UInt64 unpackedSize = 0;
+ UInt64 numStreams = 0;
+
+ decoderSpec->InitNumBlocks();
+
HRESULT result = S_OK;
- bool firstItem = true;
for (;;)
{
- lps->InSize = currentTotalPacked;
- lps->OutSize = outStreamSpec->GetSize();
+ lps->InSize = packSize;
+ lps->OutSize = unpackedSize;
RINOK(lps->SetCur());
- bool isBz2;
- result = decoderSpec->CodeResume(outStream, isBz2, progress);
+ result = decoderSpec->CodeResume(outStream, progress);
- if (result != S_OK)
+ if (result != S_FALSE && result != S_OK)
+ return result;
+
+ if (decoderSpec->IsBz)
+ numStreams++;
+ else if (numStreams == 0)
+ {
+ _isArc = false;
+ result = S_FALSE;
+ break;
+ }
+
+ unpackedSize = outStreamSpec->GetSize();
+ UInt64 streamSize = decoderSpec->GetStreamSize();
+
+ if (streamSize == packSize)
+ {
+ // no new bytes in input stream, So it's good end of archive.
+ result = S_OK;
+ break;
+ }
+
+ if (!decoderSpec->IsBz)
+ {
+ _dataAfterEnd = true;
+ result = S_FALSE;
break;
- if (!isBz2)
+ }
+
+ if (decoderSpec->Base.BitDecoder.ExtraBitsWereRead())
{
- if (firstItem)
- result = S_FALSE;
+ _needMoreInput = true;
+ packSize = streamSize;
+ result = S_FALSE;
break;
}
- firstItem = false;
- _packSize = currentTotalPacked = decoderSpec->GetInputProcessedSize();
- _packSizeDefined = true;
+ packSize = decoderSpec->GetInputProcessedSize();
+
+ if (packSize > streamSize)
+ return E_FAIL;
+
+ if (result != S_OK)
+ break;
}
+
+ if (numStreams != 0)
+ {
+ _packSize = packSize;
+ _unpackSize = unpackedSize;
+ _numStreams = numStreams;
+ _numBlocks = decoderSpec->GetNumBlocks();
+
+ _packSize_Defined = true;
+ _unpackSize_Defined = true;
+ _numStreams_Defined = true;
+ _numBlocks_Defined = true;
+ }
+
decoderSpec->ReleaseInStream();
outStream.Release();
- Int32 retResult;
- if (result == S_OK)
- retResult = NExtract::NOperationResult::kOK;
+ if (!_isArc)
+ opRes = NExtract::NOperationResult::kIsNotArc;
+ else if (_needMoreInput)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ else if (decoderSpec->CrcError)
+ opRes = NExtract::NOperationResult::kCRCError;
+ else if (_dataAfterEnd)
+ opRes = NExtract::NOperationResult::kDataAfterEnd;
else if (result == S_FALSE)
- retResult = NExtract::NOperationResult::kDataError;
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (result == S_OK)
+ opRes = NExtract::NOperationResult::kOK;
else
return result;
- return extractCallback->SetOperationResult(retResult);
+
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+
+ return extractCallback->SetOperationResult(opRes);
COM_TRY_END
}
@@ -280,24 +405,24 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (indexInArchive != 0)
return E_INVALIDARG;
if (_stream)
- RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
return NCompress::CopyStream(_stream, outStream, NULL);
}
-STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
{
return _props.SetProperties(names, values, numProps);
}
-static IInArchive *CreateArc() { return new CHandler; }
-#ifndef EXTRACT_ONLY
-static IOutArchive *CreateArcOut() { return new CHandler; }
-#else
-#define CreateArcOut 0
-#endif
+IMP_CreateArcIn
+IMP_CreateArcOut
static CArcInfo g_ArcInfo =
- { L"bzip2", L"bz2 bzip2 tbz2 tbz", L"* * .tar .tar", 2, { 'B', 'Z', 'h' }, 3, true, CreateArc, CreateArcOut };
+ { "bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2,
+ 3, { 'B', 'Z', 'h' },
+ 0,
+ NArcInfoFlags::kKeepName,
+ REF_CreateArc_Pair, IsArc_BZip2 };
REGISTER_ARC(BZip2)
diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
index 12c73eb5..cebec610 100755..100644
--- a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
+++ b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
@@ -3,8 +3,7 @@
#include "StdAfx.h"
#include "../../../../C/Alloc.h"
-
-#include "Common/Defs.h"
+#include "../../../../C/CpuArch.h"
#include "../../Common/StreamUtils.h"
@@ -17,173 +16,73 @@ static const UInt32 kBlockSize = (1 << 16);
bool CCabBlockInStream::Create()
{
- if (!_buffer)
- _buffer = (Byte *)::MyAlloc(kBlockSize);
- return (_buffer != 0);
+ if (!_buf)
+ _buf = (Byte *)::MyAlloc(kBlockSize);
+ return _buf != 0;
}
CCabBlockInStream::~CCabBlockInStream()
{
- MyFree(_buffer);
+ ::MyFree(_buf);
}
-class CCheckSum2
-{
- UInt32 m_Value;
- int m_Pos;
- Byte m_Hist[4];
-public:
- CCheckSum2(): m_Value(0){};
- void Init() { m_Value = 0; m_Pos = 0; }
- void Update(const void *data, UInt32 size);
- void FinishDataUpdate()
- {
- for (int i = 0; i < m_Pos; i++)
- m_Value ^= ((UInt32)(m_Hist[i])) << (8 * (m_Pos - i - 1));
- }
- void UpdateUInt32(UInt32 v) { m_Value ^= v; }
- UInt32 GetResult() const { return m_Value; }
-};
-
-void CCheckSum2::Update(const void *data, UInt32 size)
+static UInt32 CheckSum(const Byte *p, UInt32 size)
{
- UInt32 checkSum = m_Value;
- const Byte *dataPointer = (const Byte *)data;
-
- while (size != 0 && m_Pos != 0)
- {
- m_Hist[m_Pos] = *dataPointer++;
- m_Pos = (m_Pos + 1) & 3;
- size--;
- if (m_Pos == 0)
- for (int i = 0; i < 4; i++)
- checkSum ^= ((UInt32)m_Hist[i]) << (8 * i);
- }
-
- int numWords = size / 4;
-
- while (numWords-- != 0)
+ UInt32 sum = 0;
+ for (UInt32 i = size >> 2; i != 0; i--)
{
- UInt32 temp = *dataPointer++;
- temp |= ((UInt32)(*dataPointer++)) << 8;
- temp |= ((UInt32)(*dataPointer++)) << 16;
- temp |= ((UInt32)(*dataPointer++)) << 24;
- checkSum ^= temp;
+ sum ^= GetUi32(p);
+ p += 4;
}
- m_Value = checkSum;
-
size &= 3;
-
- while (size != 0)
- {
- m_Hist[m_Pos] = *dataPointer++;
- m_Pos = (m_Pos + 1) & 3;
- size--;
- }
+ if (size > 2) sum ^= (UInt32)(*p++) << 16;
+ if (size > 1) sum ^= (UInt32)(*p++) << 8;
+ if (size > 0) sum ^= (UInt32)(*p++);
+ return sum;
}
-static const UInt32 kDataBlockHeaderSize = 8;
-
-class CTempCabInBuffer2
+HRESULT CCabBlockInStream::PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize)
{
-public:
- Byte Buffer[kDataBlockHeaderSize];
- UInt32 Pos;
- Byte ReadByte()
- {
- return Buffer[Pos++];
- }
- UInt32 ReadUInt32()
- {
- UInt32 value = 0;
- for (int i = 0; i < 4; i++)
- value |= (((UInt32)ReadByte()) << (8 * i));
- return value;
- }
- UInt16 ReadUInt16()
- {
- UInt16 value = 0;
- for (int i = 0; i < 2; i++)
- value |= (((UInt16)ReadByte()) << (8 * i));
- return value;
- }
-};
-
-HRESULT CCabBlockInStream::PreRead(UInt32 &packSize, UInt32 &unpackSize)
-{
- CTempCabInBuffer2 inBuffer;
- inBuffer.Pos = 0;
- RINOK(ReadStream_FALSE(_stream, inBuffer.Buffer, kDataBlockHeaderSize))
-
- UInt32 checkSum = inBuffer.ReadUInt32();
- packSize = inBuffer.ReadUInt16();
- unpackSize = inBuffer.ReadUInt16();
- if (ReservedSize != 0)
- {
- RINOK(ReadStream_FALSE(_stream, _buffer, ReservedSize));
- }
- _pos = 0;
- CCheckSum2 checkSumCalc;
- checkSumCalc.Init();
- UInt32 packSize2 = packSize;
- if (MsZip && _size == 0)
+ 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 (packSize < 2)
- return S_FALSE; // bad block;
- Byte sig[2];
- RINOK(ReadStream_FALSE(_stream, sig, 2));
- if (sig[0] != 0x43 || sig[1] != 0x4B)
+ 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;
- packSize2 -= 2;
- checkSumCalc.Update(sig, 2);
}
- if (kBlockSize - _size < packSize2)
- return S_FALSE;
-
- UInt32 curSize = packSize2;
- if (curSize != 0)
- {
- size_t processedSizeLoc = curSize;
- RINOK(ReadStream(_stream, _buffer + _size, &processedSizeLoc));
- checkSumCalc.Update(_buffer + _size, (UInt32)processedSizeLoc);
- _size += (UInt32)processedSizeLoc;
- if (processedSizeLoc != curSize)
+ if (GetUi32(header) != 0) // checkSum
+ if (CheckSum(header, kHeaderSize + ReservedSize) != CheckSum(_buf + _size, packSize))
return S_FALSE;
- }
- TotalPackSize = _size;
- checkSumCalc.FinishDataUpdate();
-
- bool dataError;
- if (checkSum == 0)
- dataError = false;
- else
- {
- checkSumCalc.UpdateUInt32(packSize | (((UInt32)unpackSize) << 16));
- dataError = (checkSumCalc.GetResult() != checkSum);
- }
- DataError |= dataError;
- return dataError ? S_FALSE : S_OK;
+ _size += packSize;
+ return S_OK;
}
STDMETHODIMP CCabBlockInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
{
- if (processedSize != 0)
- *processedSize = 0;
- if (size == 0)
- return S_OK;
- if (_size != 0)
- {
- size = MyMin(_size, size);
- memmove(data, _buffer + _pos, size);
- _pos += size;
- _size -= size;
- if (processedSize != 0)
- *processedSize = size;
- return S_OK;
- }
- return S_OK; // no blocks data
+ 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 1db3835b..b795ed97 100755..100644
--- a/CPP/7zip/Archive/Cab/CabBlockInStream.h
+++ b/CPP/7zip/Archive/Cab/CabBlockInStream.h
@@ -1,9 +1,9 @@
-// CabBlockInStream.cpp
+// CabBlockInStream.h
-#ifndef __CABBLOCKINSTREAM_H
-#define __CABBLOCKINSTREAM_H
+#ifndef __CAB_BLOCK_IN_STREAM_H
+#define __CAB_BLOCK_IN_STREAM_H
-#include "Common/MyCom.h"
+#include "../../../Common/MyCom.h"
#include "../../IStream.h"
namespace NArchive {
@@ -13,30 +13,23 @@ class CCabBlockInStream:
public ISequentialInStream,
public CMyUnknownImp
{
- CMyComPtr<ISequentialInStream> _stream;
- Byte *_buffer;
- UInt32 _pos;
+ Byte *_buf;
UInt32 _size;
+ UInt32 _pos;
public:
- UInt32 TotalPackSize;
- UInt32 ReservedSize;
- bool DataError;
+ UInt32 ReservedSize; // < 256
bool MsZip;
- CCabBlockInStream(): _buffer(0), ReservedSize(0), MsZip(false), DataError(false), TotalPackSize(0) {}
+ MY_UNKNOWN_IMP
+
+ CCabBlockInStream(): _buf(0), ReservedSize(0), MsZip(false) {}
~CCabBlockInStream();
bool Create();
- void SetStream(ISequentialInStream *stream) { _stream = stream; }
-
- void InitForNewFolder() { TotalPackSize = 0; }
- void InitForNewBlock() { _size = 0; }
-
- MY_UNKNOWN_IMP
+ void InitForNewBlock() { _size = 0; _pos = 0; }
+ HRESULT PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize);
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
-
- HRESULT PreRead(UInt32 &packSize, UInt32 &unpackSize);
};
}}
diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp
index fd707fe5..22bc93a0 100755..100644
--- a/CPP/7zip/Archive/Cab/CabHandler.cpp
+++ b/CPP/7zip/Archive/Cab/CabHandler.cpp
@@ -2,15 +2,17 @@
#include "StdAfx.h"
+// #include <stdio.h>
+
#include "../../../../C/Alloc.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/StringConvert.h"
-#include "Common/UTFConvert.h"
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/UTFConvert.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/TimeUtils.h"
#include "../../Common/ProgressUtils.h"
#include "../../Common/StreamUtils.h"
@@ -39,102 +41,243 @@ enum
};
#endif
-static STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidAttrib, VT_UI4},
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidBlock, VT_I4}
+ kpidPath,
+ kpidSize,
+ kpidMTime,
+ kpidAttrib,
+ kpidMethod,
+ kpidBlock
#ifdef _CAB_DETAILS
,
- { L"BlockReal", kpidBlockReal, VT_UI4},
- { NULL, kpidOffset, VT_UI4},
- { NULL, kpidVolume, VT_UI4}
+ // kpidBlockReal, // L"BlockReal",
+ kpidOffset,
+ kpidVolume
#endif
};
-static const char *kMethods[] =
+static const Byte kArcProps[] =
{
- "None",
- "MSZip",
- "Quantum",
- "LZX"
+ kpidTotalPhySize,
+ kpidMethod,
+ // kpidSolid,
+ kpidNumBlocks,
+ kpidNumVolumes,
+ kpidVolumeIndex,
+ kpidId
};
-static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]);
-static const char *kUnknownMethod = "Unknown";
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
-static STATPROPSTG kArcProps[] =
+static const char *kMethods[] =
{
- { NULL, kpidMethod, VT_BSTR},
- // { NULL, kpidSolid, VT_BOOL},
- { NULL, kpidNumBlocks, VT_UI4},
- { NULL, kpidNumVolumes, VT_UI4}
+ "None"
+ , "MSZip"
+ , "Quantum"
+ , "LZX"
};
-IMP_IInArchive_Props
-IMP_IInArchive_ArcProps
+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
- NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ NCOM::CPropVariant prop;
+ switch (propID)
{
case kpidMethod:
{
- AString resString;
- CRecordVector<Byte> ids;
- int i;
- for (int v = 0; v < m_Database.Volumes.Size(); v++)
+ UInt32 mask = 0;
+ UInt32 params[2] = { 0, 0 };
{
- const CDatabaseEx &de = m_Database.Volumes[v];
- for (i = 0; i < de.Folders.Size(); i++)
- ids.AddToUniqueSorted(de.Folders[i].GetCompressionMethod());
+ FOR_VECTOR (v, m_Database.Volumes)
+ {
+ const CRecordVector<CFolder> &folders = m_Database.Volumes[v].Folders;
+ FOR_VECTOR (i, folders)
+ {
+ const CFolder &folder = folders[i];
+ unsigned method = folder.GetMethod();
+ mask |= ((UInt32)1 << method);
+ if (method == NHeader::NMethod::kLZX ||
+ method == NHeader::NMethod::kQuantum)
+ {
+ unsigned di = (method == NHeader::NMethod::kQuantum) ? 0 : 1;
+ if (params[di] < folder.MethodMinor)
+ params[di] = folder.MethodMinor;
+ }
+ }
+ }
}
- for (i = 0; i < ids.Size(); i++)
+ AString s;
+ for (unsigned i = 0; i < kNumMethodsMax; i++)
{
- Byte id = ids[i];
- AString method = (id < kNumMethods) ? kMethods[id] : kUnknownMethod;
- if (!resString.IsEmpty())
- resString += ' ';
- resString += method;
+ if ((mask & (1 << i)) == 0)
+ continue;
+ if (!s.IsEmpty())
+ s += ' ';
+ char temp[kMethodNameBufSize];
+ SetMethodName(temp, i, params[i == NHeader::NMethod::kQuantum ? 0 : 1]);
+ s += temp;
}
- prop = resString;
+ prop = s;
break;
}
// case kpidSolid: prop = _database.IsSolid(); break;
case kpidNumBlocks:
{
UInt32 numFolders = 0;
- for (int v = 0; v < m_Database.Volumes.Size(); v++)
+ FOR_VECTOR (v, m_Database.Volumes)
numFolders += m_Database.Volumes[v].Folders.Size();
prop = numFolders;
break;
}
- case kpidNumVolumes:
+
+ 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.Size() == 1)
+ {
+ 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;
+ char temp[32];
+ ConvertUInt32ToString(ai.SetID, temp);
+ s += temp;
+ ConvertUInt32ToString(ai.CabinetNumber + 1, temp);
+ s += '_';
+ s += temp;
+ 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)
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
+ NCOM::CPropVariant prop;
const CMvItem &mvItem = m_Database.Items[index];
const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex];
- int itemIndex = mvItem.ItemIndex;
+ unsigned itemIndex = mvItem.ItemIndex;
const CItem &item = db.Items[itemIndex];
- switch(propID)
+ switch (propID)
{
case kpidPath:
{
@@ -146,9 +289,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
prop = (const wchar_t *)NItemName::WinNameToOSName(unicodeName);
break;
}
+
case kpidIsDir: prop = item.IsDir(); break;
case kpidSize: prop = item.Size; break;
- case kpidAttrib: prop = item.GetWinAttributes(); break;
+ case kpidAttrib: prop = item.GetWinAttrib(); break;
case kpidMTime:
{
@@ -168,24 +312,17 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
{
UInt32 realFolderIndex = item.GetFolderIndex(db.Folders.Size());
const CFolder &folder = db.Folders[realFolderIndex];
- int methodIndex = folder.GetCompressionMethod();
- AString method = (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod;
- if (methodIndex == NHeader::NCompressionMethodMajor::kLZX ||
- methodIndex == NHeader::NCompressionMethodMajor::kQuantum)
- {
- method += ':';
- char temp[32];
- ConvertUInt64ToString(folder.CompressionTypeMinor, temp);
- method += temp;
- }
- prop = method;
+ 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 kpidBlockReal: prop = (UInt32)item.FolderIndex; break;
case kpidOffset: prop = (UInt32)item.Offset; break;
case kpidVolume: prop = (UInt32)mvItem.VolumeIndex; break;
@@ -196,39 +333,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
COM_TRY_END
}
-/*
-class CProgressImp: public CProgressVirt
-{
- CMyComPtr<IArchiveOpenCallback> m_OpenArchiveCallback;
-public:
- STDMETHOD(SetTotal)(const UInt64 *numFiles);
- STDMETHOD(SetCompleted)(const UInt64 *numFiles);
- void Init(IArchiveOpenCallback *openArchiveCallback)
- { m_OpenArchiveCallback = openArchiveCallback; }
-};
-
-STDMETHODIMP CProgressImp::SetTotal(const UInt64 *numFiles)
-{
- if (m_OpenArchiveCallback)
- return m_OpenArchiveCallback->SetCompleted(numFiles, NULL);
- return S_OK;
-}
-
-STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles)
-{
- if (m_OpenArchiveCallback)
- return m_OpenArchiveCallback->SetCompleted(numFiles, NULL);
- return S_OK;
-}
-*/
-
STDMETHODIMP CHandler::Open(IInStream *inStream,
const UInt64 *maxCheckStartPosition,
IArchiveOpenCallback *callback)
{
COM_TRY_BEGIN
Close();
- HRESULT res = S_FALSE;
+
CInArchive archive;
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
@@ -236,96 +347,169 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
CMyComPtr<IInStream> nextStream = inStream;
bool prevChecked = false;
UInt64 numItems = 0;
- try
+ unsigned numTempVolumes = 0;
+ // try
{
- while (nextStream != 0)
+ while (nextStream != NULL)
{
CDatabaseEx db;
db.Stream = nextStream;
- res = archive.Open(maxCheckStartPosition, db);
- if (res == S_OK)
+ HRESULT res = archive.Open(db, maxCheckStartPosition);
+ _errorInHeaders |= archive.HeaderError;
+ _errorInHeaders |= archive.ErrorInNames;
+ _unexpectedEnd |= archive.UnexpectedEnd;
+
+ if (res == S_OK && !m_Database.Volumes.IsEmpty())
{
- if (!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 CDatabaseEx &dbPrev = m_Database.Volumes[prevChecked ? m_Database.Volumes.Size() - 1 : 0];
- if (dbPrev.ArchiveInfo.SetID != db.ArchiveInfo.SetID ||
- dbPrev.ArchiveInfo.CabinetNumber + (prevChecked ? 1: - 1) !=
- db.ArchiveInfo.CabinetNumber)
+ 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)
- m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : 0, db);
- else if (res != S_FALSE)
- return res;
+ {
+ 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;
+ }
}
- numItems += db.Items.Size();
RINOK(callback->SetCompleted(&numItems, NULL));
- nextStream = 0;
+ nextStream = NULL;
+
for (;;)
{
- const COtherArchive *otherArchive = 0;
+ const COtherArc *otherArc = NULL;
if (!prevChecked)
{
- const CInArchiveInfo &ai = m_Database.Volumes.Front().ArchiveInfo;
- if (ai.IsTherePrev())
- otherArchive = &ai.PrevArc;
+ if (numTempVolumes == 0)
+ {
+ const CInArcInfo &ai = m_Database.Volumes[0].ArcInfo;
+ if (ai.IsTherePrev())
+ otherArc = &ai.PrevArc;
+ else
+ prevChecked = true;
+ }
else
- prevChecked = true;
+ {
+ 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 (otherArchive == 0)
+ if (!otherArc)
{
- const CInArchiveInfo &ai = m_Database.Volumes.Back().ArchiveInfo;
+ const CInArcInfo &ai = m_Database.Volumes.Back().ArcInfo;
if (ai.IsThereNext())
- otherArchive = &ai.NextArc;
+ otherArc = &ai.NextArc;
}
- if (!otherArchive)
+ if (!otherArc)
break;
- const UString fullName = MultiByteToUnicodeString(otherArchive->FileName, CP_ACP);
if (!openVolumeCallback)
break;
-
+ // printf("\n%s", otherArc->FileName);
+ const UString fullName = MultiByteToUnicodeString(otherArc->FileName, CP_ACP);
HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream);
if (result == S_OK)
break;
if (result != S_FALSE)
return result;
+
+ if (!_errorMessage.IsEmpty())
+ _errorMessage += L"\n";
+ _errorMessage += L"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 (res == S_OK)
+ if (m_Database.Volumes.IsEmpty())
+ return S_FALSE;
+ else
{
m_Database.FillSortAndShrink();
if (!m_Database.Check())
- res = S_FALSE;
+ return S_FALSE;
}
}
- catch(...)
- {
- res = S_FALSE;
- }
- if (res != S_OK)
- {
- Close();
- return res;
- }
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;
}
@@ -348,8 +532,8 @@ private:
bool TempBufMode;
UInt32 m_BufStartFolderOffset;
- int m_StartIndex;
- int m_CurrentIndex;
+ unsigned m_StartIndex;
+ unsigned m_CurrentIndex;
CMyComPtr<IArchiveExtractCallback> m_ExtractCallback;
bool m_TestMode;
@@ -379,7 +563,7 @@ public:
void Init(
const CMvDatabaseEx *database,
const CRecordVector<bool> *extractStatuses,
- int startIndex,
+ unsigned startIndex,
UInt64 folderSize,
IArchiveExtractCallback *extractCallback,
bool testMode);
@@ -393,7 +577,7 @@ public:
void CFolderOutStream::Init(
const CMvDatabaseEx *database,
const CRecordVector<bool> *extractStatuses,
- int startIndex,
+ unsigned startIndex,
UInt64 folderSize,
IArchiveExtractCallback *extractCallback,
bool testMode)
@@ -436,7 +620,7 @@ HRESULT CFolderOutStream::OpenFile()
const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
int numExtractItems = 0;
- int curIndex;
+ unsigned curIndex;
for (curIndex = m_CurrentIndex; curIndex < m_ExtractStatuses->Size(); curIndex++)
{
const CMvItem &mvItem2 = m_Database->Items[m_StartIndex + curIndex];
@@ -559,7 +743,7 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe
if (!TempBuf && TempBufMode && m_RealOutStream)
{
- RINOK(CloseFileWithResOp(NExtract::NOperationResult::kUnSupportedMethod));
+ RINOK(CloseFileWithResOp(NExtract::NOperationResult::kUnsupportedMethod));
}
else
{
@@ -638,7 +822,7 @@ HRESULT CFolderOutStream::Unsupported()
if (result != S_FALSE && result != S_OK)
return result;
m_RealOutStream.Release();
- RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod));
m_CurrentIndex++;
}
return S_OK;
@@ -649,7 +833,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = m_Database.Items.Size();
if (numItems == 0)
@@ -709,7 +893,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
const CMvItem &mvItem = m_Database.Items[index];
const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex];
- int itemIndex = mvItem.ItemIndex;
+ unsigned itemIndex = mvItem.ItemIndex;
const CItem &item = db.Items[itemIndex];
i++;
@@ -747,7 +931,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
extractStatuses.Add(true);
startIndex++;
UInt64 curUnpack = item.GetEndOffset();
- for(;i < numItems; i++)
+ for (; i < numItems; i++)
{
int indexNext = allFilesMode ? i : indices[i];
const CMvItem &mvItem = m_Database.Items[indexNext];
@@ -779,11 +963,11 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
cabBlockInStreamSpec->MsZip = false;
HRESULT res = S_OK;
- switch(folder.GetCompressionMethod())
+ switch (folder.GetMethod())
{
- case NHeader::NCompressionMethodMajor::kNone:
+ case NHeader::NMethod::kNone:
break;
- case NHeader::NCompressionMethodMajor::kMSZip:
+ case NHeader::NMethod::kMSZip:
if (!deflateDecoder)
{
deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder;
@@ -791,21 +975,21 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
cabBlockInStreamSpec->MsZip = true;
break;
- case NHeader::NCompressionMethodMajor::kLZX:
+ case NHeader::NMethod::kLZX:
if (!lzxDecoder)
{
lzxDecoderSpec = new NCompress::NLzx::CDecoder;
lzxDecoder = lzxDecoderSpec;
}
- res = lzxDecoderSpec->SetParams(folder.CompressionTypeMinor);
+ res = lzxDecoderSpec->SetParams(folder.MethodMinor);
break;
- case NHeader::NCompressionMethodMajor::kQuantum:
+ case NHeader::NMethod::kQuantum:
if (!quantumDecoder)
{
quantumDecoderSpec = new NCompress::NQuantum::CDecoder;
quantumDecoder = quantumDecoderSpec;
}
- res = quantumDecoderSpec->SetParams(folder.CompressionTypeMinor);
+ res = quantumDecoderSpec->SetParams(folder.MethodMinor);
break;
default:
res = E_INVALIDARG;
@@ -820,9 +1004,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
RINOK(res);
- cabBlockInStreamSpec->InitForNewFolder();
{
- int volIndex = mvItem.VolumeIndex;
+ unsigned volIndex = mvItem.VolumeIndex;
int locFolderIndex = item.GetFolderIndex(db.Folders.Size());
bool keepHistory = false;
bool keepInputBuffer = false;
@@ -838,8 +1021,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
const CFolder &folder = db.Folders[locFolderIndex];
if (f == 0)
{
- cabBlockInStreamSpec->SetStream(db.Stream);
- cabBlockInStreamSpec->ReservedSize = db.ArchiveInfo.GetDataBlockReserveSize();
+ cabBlockInStreamSpec->ReservedSize = db.ArcInfo.GetDataBlockReserveSize();
RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK_SET, NULL));
}
if (f == folder.NumDataBlocks)
@@ -851,13 +1033,11 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
f++;
- cabBlockInStreamSpec->DataError = false;
-
if (!keepInputBuffer)
cabBlockInStreamSpec->InitForNewBlock();
UInt32 packSize, unpackSize;
- res = cabBlockInStreamSpec->PreRead(packSize, unpackSize);
+ res = cabBlockInStreamSpec->PreRead(db.Stream, packSize, unpackSize);
if (res == S_FALSE)
break;
RINOK(res);
@@ -878,22 +1058,36 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (unpackRemain > kBlockSizeMax)
unpackRemain = kBlockSizeMax;
if (unpackRemain > unpackSize)
- unpackRemain = unpackSize;
+ unpackRemain = unpackSize;
- switch(folder.GetCompressionMethod())
+ switch (folder.GetMethod())
{
- case NHeader::NCompressionMethodMajor::kNone:
+ case NHeader::NMethod::kNone:
res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
break;
- case NHeader::NCompressionMethodMajor::kMSZip:
- deflateDecoderSpec->SetKeepHistory(keepHistory);
+ 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, &unpackRemain, NULL);
+ if (res == S_OK)
+ {
+ if (!deflateDecoderSpec->IsFinished())
+ res = S_FALSE;
+ if (!deflateDecoderSpec->IsFinalBlock())
+ res = S_FALSE;
+ }
+
break;
- case NHeader::NCompressionMethodMajor::kLZX:
+ case NHeader::NMethod::kLZX:
lzxDecoderSpec->SetKeepHistory(keepHistory);
res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
break;
- case NHeader::NCompressionMethodMajor::kQuantum:
+ case NHeader::NMethod::kQuantum:
quantumDecoderSpec->SetKeepHistory(keepHistory);
res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
break;
diff --git a/CPP/7zip/Archive/Cab/CabHandler.h b/CPP/7zip/Archive/Cab/CabHandler.h
index 1edcd11e..6f44b875 100755..100644
--- a/CPP/7zip/Archive/Cab/CabHandler.h
+++ b/CPP/7zip/Archive/Cab/CabHandler.h
@@ -3,8 +3,10 @@
#ifndef __CAB_HANDLER_H
#define __CAB_HANDLER_H
-#include "Common/MyCom.h"
+#include "../../../Common/MyCom.h"
+
#include "../IArchive.h"
+
#include "CabIn.h"
namespace NArchive {
@@ -21,6 +23,13 @@ public:
private:
CMvDatabaseEx m_Database;
+ UString _errorMessage;
+ bool _isArc;
+ bool _errorInHeaders;
+ bool _unexpectedEnd;
+ // int _mainVolIndex;
+ UInt32 _phySize;
+ UInt64 _offset;
};
}}
diff --git a/CPP/7zip/Archive/Cab/CabHeader.cpp b/CPP/7zip/Archive/Cab/CabHeader.cpp
index 0cba1b0b..0cba1b0b 100755..100644
--- a/CPP/7zip/Archive/Cab/CabHeader.cpp
+++ b/CPP/7zip/Archive/Cab/CabHeader.cpp
diff --git a/CPP/7zip/Archive/Cab/CabHeader.h b/CPP/7zip/Archive/Cab/CabHeader.h
index 0f0d2af3..9ec0760a 100755..100644
--- a/CPP/7zip/Archive/Cab/CabHeader.h
+++ b/CPP/7zip/Archive/Cab/CabHeader.h
@@ -3,7 +3,7 @@
#ifndef __ARCHIVE_CAB_HEADER_H
#define __ARCHIVE_CAB_HEADER_H
-#include "Common/Types.h"
+#include "../../../Common/MyTypes.h"
namespace NArchive {
namespace NCab {
@@ -12,17 +12,14 @@ namespace NHeader {
const unsigned kMarkerSize = 8;
extern Byte kMarker[kMarkerSize];
-namespace NArchive
+namespace NArcFlags
{
- namespace NFlags
- {
- const int kPrevCabinet = 0x0001;
- const int kNextCabinet = 0x0002;
- const int kReservePresent = 0x0004;
- }
+ const unsigned kPrevCabinet = 1;
+ const unsigned kNextCabinet = 2;
+ const unsigned kReservePresent = 4;
}
-namespace NCompressionMethodMajor
+namespace NMethod
{
const Byte kNone = 0;
const Byte kMSZip = 1;
@@ -30,13 +27,13 @@ namespace NCompressionMethodMajor
const Byte kLZX = 3;
}
-const int kFileNameIsUTFAttributeMask = 0x80;
+const unsigned kFileNameIsUtf8_Mask = 0x80;
namespace NFolderIndex
{
- const int kContinuedFromPrev = 0xFFFD;
- const int kContinuedToNext = 0xFFFE;
- const int kContinuedPrevAndNext = 0xFFFF;
+ const unsigned kContinuedFromPrev = 0xFFFD;
+ const unsigned kContinuedToNext = 0xFFFE;
+ const unsigned kContinuedPrevAndNext = 0xFFFF;
}
}}}
diff --git a/CPP/7zip/Archive/Cab/CabIn.cpp b/CPP/7zip/Archive/Cab/CabIn.cpp
index c0bffa2d..c499f05f 100755..100644
--- a/CPP/7zip/Archive/Cab/CabIn.cpp
+++ b/CPP/7zip/Archive/Cab/CabIn.cpp
@@ -2,154 +2,353 @@
#include "StdAfx.h"
-#include "../Common/FindSignature.h"
+// #include <stdio.h>
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/StreamUtils.h"
#include "CabIn.h"
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
namespace NArchive {
namespace NCab {
-Byte CInArchive::Read8()
+struct CUnexpectedEndException {};
+
+void CInArchive::Skip(unsigned size)
{
- Byte b;
- if (!inBuffer.ReadByte(b))
- throw CInArchiveException(CInArchiveException::kUnsupported);
- return b;
+ if (_inBuffer.Skip(size) != size)
+ throw CUnexpectedEndException();
}
-UInt16 CInArchive::Read16()
+void CInArchive::Read(Byte *data, unsigned size)
{
- UInt16 value = 0;
- for (int i = 0; i < 2; i++)
- {
- Byte b = Read8();
- value |= (UInt16(b) << (8 * i));
- }
- return value;
+ if (_inBuffer.ReadBytes(data, size) != size)
+ throw CUnexpectedEndException();
}
-UInt32 CInArchive::Read32()
+void CInArchive::ReadName(AString &s)
{
- UInt32 value = 0;
- for (int i = 0; i < 4; i++)
+ for (size_t i = 0; i < ((size_t)1 << 13); i++)
{
- Byte b = Read8();
- value |= (UInt32(b) << (8 * i));
+ Byte b;
+ if (!_inBuffer.ReadByte(b))
+ throw CUnexpectedEndException();
+ if (b == 0)
+ {
+ memcpy(s.GetBuffer((unsigned)i), _tempBuf, i);
+ s.ReleaseBuffer((unsigned)i);
+ return;
+ }
+ if (_tempBuf.Size() == i)
+ _tempBuf.ChangeSize_KeepData(i * 2, i);
+ _tempBuf[i] = b;
}
- return value;
-}
-
-AString CInArchive::SafeReadName()
-{
- AString name;
+
for (;;)
{
- Byte b = Read8();
+ Byte b;
+ if (!_inBuffer.ReadByte(b))
+ throw CUnexpectedEndException();
if (b == 0)
- return name;
- name += (char)b;
+ break;
}
+
+ ErrorInNames = true;
+ s = "[ERROR-LONG-PATH]";
}
-void CInArchive::ReadOtherArchive(COtherArchive &oa)
+void CInArchive::ReadOtherArc(COtherArc &oa)
{
- oa.FileName = SafeReadName();
- oa.DiskName = SafeReadName();
+ ReadName(oa.FileName);
+ ReadName(oa.DiskName);
}
-void CInArchive::Skip(UInt32 size)
+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()
{
- while (size-- != 0)
- Read8();
+ 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;
+ }
}
-HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit, CDatabaseEx &db)
+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)
{
- IInStream *stream = db.Stream;
+ IsArc = false;
+ ErrorInNames = false;
+ UnexpectedEnd = false;
+ HeaderError = false;
+
db.Clear();
- RINOK(stream->Seek(0, STREAM_SEEK_SET, &db.StartPosition));
-
- RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize,
- searchHeaderSizeLimit, db.StartPosition));
-
- RINOK(stream->Seek(db.StartPosition + NHeader::kMarkerSize, STREAM_SEEK_SET, NULL));
- if (!inBuffer.Create(1 << 17))
- return E_OUTOFMEMORY;
- inBuffer.SetStream(stream);
- inBuffer.Init();
-
- CInArchiveInfo &ai = db.ArchiveInfo;
-
- ai.Size = Read32();
- if (Read32() != 0)
- return S_FALSE;
- ai.FileHeadersOffset = Read32();
- if (Read32() != 0)
- return S_FALSE;
-
- ai.VersionMinor = Read8();
- ai.VersionMajor = Read8();
- ai.NumFolders = Read16();
- ai.NumFiles = Read16();
- ai.Flags = Read16();
- if (ai.Flags > 7)
- return S_FALSE;
- ai.SetID = Read16();
- ai.CabinetNumber = Read16();
+ RINOK(db.Stream->Seek(0, STREAM_SEEK_CUR, &db.StartPosition));
+ // UInt64 temp = db.StartPosition;
- if (ai.ReserveBlockPresent())
+ CByteBuffer buffer;
+ CInArcInfo &ai = db.ArcInfo;
+ UInt64 startInBuf = 0;
+
+ CLimitedSequentialInStream *limitedStreamSpec = NULL;
+ CMyComPtr<ISequentialInStream> limitedStream;
+
+ // for (int iii = 0; iii < 10000; iii++)
{
- ai.PerCabinetAreaSize = Read16();
- ai.PerFolderAreaSize = Read8();
- ai.PerDataBlockAreaSize = Read8();
+ // 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;
- Skip(ai.PerCabinetAreaSize);
+ 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())
{
- if (ai.IsTherePrev())
- ReadOtherArchive(ai.PrevArc);
- if (ai.IsThereNext())
- ReadOtherArchive(ai.NextArc);
+ 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);
- int i;
+ UInt32 i;
+ db.Folders.ClearAndReserve(ai.NumFolders);
for (i = 0; i < ai.NumFolders; i++)
{
+ Read(p, 8);
CFolder folder;
-
- folder.DataStart = Read32();
- folder.NumDataBlocks = Read16();
- folder.CompressionTypeMajor = Read8();
- folder.CompressionTypeMinor = Read8();
-
- Skip(ai.PerFolderAreaSize);
- db.Folders.Add(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);
}
- RINOK(stream->Seek(db.StartPosition + ai.FileHeadersOffset, STREAM_SEEK_SET, NULL));
+ // 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();
+ }
- inBuffer.SetStream(stream);
- inBuffer.Init();
+ db.Items.ClearAndReserve(ai.NumFiles);
for (i = 0; i < ai.NumFiles; i++)
{
- CItem item;
- item.Size = Read32();
- item.Offset = Read32();
- item.FolderIndex = Read16();
- UInt16 pureDate = Read16();
- UInt16 pureTime = Read16();
- item.Time = ((UInt32(pureDate) << 16)) | pureTime;
- item.Attributes = Read16();
- item.Name = SafeReadName();
- int folderIndex = item.GetFolderIndex(db.Folders.Size());
- if (folderIndex >= db.Folders.Size())
+ 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;
- db.Items.Add(item);
+ }
}
+
+ // }
+
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)
@@ -161,10 +360,8 @@ static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param)
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;
+ if (isDir1 && !isDir2) return -1;
+ if (isDir2 && !isDir1) return 1;
int f1 = mvDb.GetFolderIndex(p1);
int f2 = mvDb.GetFolderIndex(p2);
RINOZ(MyCompare(f1, f2));
@@ -174,7 +371,7 @@ static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param)
return MyCompare(p1->ItemIndex, p2->ItemIndex);
}
-bool CMvDatabaseEx::AreItemsEqual(int i1, int i2)
+bool CMvDatabaseEx::AreItemsEqual(unsigned i1, unsigned i2)
{
const CMvItem *p1 = &Items[i1];
const CMvItem *p2 = &Items[i2];
@@ -182,10 +379,10 @@ bool CMvDatabaseEx::AreItemsEqual(int i1, int i2)
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;
+ return GetFolderIndex(p1) == GetFolderIndex(p2)
+ && item1.Offset == item2.Offset
+ && item1.Size == item2.Size
+ && item1.Name == item2.Name;
}
void CMvDatabaseEx::FillSortAndShrink()
@@ -194,7 +391,7 @@ void CMvDatabaseEx::FillSortAndShrink()
StartFolderOfVol.Clear();
FolderStartFileIndex.Clear();
int offset = 0;
- for (int v = 0; v < Volumes.Size(); v++)
+ FOR_VECTOR (v, Volumes)
{
const CDatabaseEx &db = Volumes[v];
int curOffset = offset;
@@ -205,32 +402,35 @@ void CMvDatabaseEx::FillSortAndShrink()
CMvItem mvItem;
mvItem.VolumeIndex = v;
- for (int i = 0 ; i < db.Items.Size(); i++)
+ FOR_VECTOR (i, db.Items)
{
mvItem.ItemIndex = i;
Items.Add(mvItem);
}
}
- Items.Sort(CompareMvItems, (void *)this);
- int j = 1;
- int i;
- for (i = 1; i < Items.Size(); i++)
- if (!AreItemsEqual(i, i -1))
- Items[j++] = Items[i];
- Items.DeleteFrom(j);
+ 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 (i = 0; i < Items.Size(); i++)
+ FOR_VECTOR (i, Items)
{
int folderIndex = GetFolderIndex(&Items[i]);
- if (folderIndex >= FolderStartFileIndex.Size())
+ if (folderIndex >= (int)FolderStartFileIndex.Size())
FolderStartFileIndex.Add(i);
}
}
bool CMvDatabaseEx::Check()
{
- for (int v = 1; v < Volumes.Size(); v++)
+ for (unsigned v = 1; v < Volumes.Size(); v++)
{
const CDatabaseEx &db1 = Volumes[v];
if (db1.IsTherePrevFolder())
@@ -240,19 +440,19 @@ bool CMvDatabaseEx::Check()
return false;
const CFolder &f0 = db0.Folders.Back();
const CFolder &f1 = db1.Folders.Front();
- if (f0.CompressionTypeMajor != f1.CompressionTypeMajor ||
- f0.CompressionTypeMinor != f1.CompressionTypeMinor)
+ if (f0.MethodMajor != f1.MethodMajor ||
+ f0.MethodMinor != f1.MethodMinor)
return false;
}
}
UInt32 beginPos = 0;
UInt64 endPos = 0;
int prevFolder = -2;
- for (int i = 0; i < Items.Size(); i++)
+ FOR_VECTOR (i, Items)
{
const CMvItem &mvItem = Items[i];
int fIndex = GetFolderIndex(&mvItem);
- if (fIndex >= FolderStartFileIndex.Size())
+ if (fIndex >= (int)FolderStartFileIndex.Size())
return false;
const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
if (item.IsDir())
diff --git a/CPP/7zip/Archive/Cab/CabIn.h b/CPP/7zip/Archive/Cab/CabIn.h
index 1e9b188b..4fdab77b 100755..100644
--- a/CPP/7zip/Archive/Cab/CabIn.h
+++ b/CPP/7zip/Archive/Cab/CabIn.h
@@ -3,96 +3,88 @@
#ifndef __ARCHIVE_CAB_IN_H
#define __ARCHIVE_CAB_IN_H
-#include "../../IStream.h"
+#include "../../../Common/MyBuffer.h"
+#include "../../../Common/MyCom.h"
+
#include "../../Common/InBuffer.h"
-#include "CabHeader.h"
+
#include "CabItem.h"
namespace NArchive {
namespace NCab {
-class CInArchiveException
-{
-public:
- enum CCauseType
- {
- kUnexpectedEndOfArchive = 0,
- kIncorrectArchive,
- kUnsupported
- } Cause;
- CInArchiveException(CCauseType cause) : Cause(cause) {}
-};
-
-struct COtherArchive
+struct COtherArc
{
AString FileName;
AString DiskName;
};
-struct CArchiveInfo
+struct CArchInfo
{
- Byte VersionMinor; /* cabinet file format version, minor */
- Byte VersionMajor; /* cabinet file format version, major */
- UInt16 NumFolders; /* number of CFFOLDER entries in this cabinet */
- UInt16 NumFiles; /* number of CFFILE entries in this cabinet */
- UInt16 Flags; /* cabinet file option indicators */
- UInt16 SetID; /* must be the same for all cabinets in a set */
- UInt16 CabinetNumber; /* number of this cabinet file in a set */
-
- bool ReserveBlockPresent() const { return (Flags & NHeader::NArchive::NFlags::kReservePresent) != 0; }
-
- bool IsTherePrev() const { return (Flags & NHeader::NArchive::NFlags::kPrevCabinet) != 0; }
- bool IsThereNext() const { return (Flags & NHeader::NArchive::NFlags::kNextCabinet) != 0; }
-
- UInt16 PerCabinetAreaSize; // (optional) size of per-cabinet reserved area
- Byte PerFolderAreaSize; // (optional) size of per-folder reserved area
- Byte PerDataBlockAreaSize; // (optional) size of per-datablock reserved area
-
- Byte GetDataBlockReserveSize() const { return (Byte)(ReserveBlockPresent() ? PerDataBlockAreaSize : 0); }
-
- COtherArchive PrevArc;
- COtherArchive NextArc;
-
- CArchiveInfo()
+ 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()
{
Clear();
}
void Clear()
{
- PerCabinetAreaSize = 0;
- PerFolderAreaSize = 0;
- PerDataBlockAreaSize = 0;
+ PerCabinet_AreaSize = 0;
+ PerFolder_AreaSize = 0;
+ PerDataBlock_AreaSize = 0;
}
};
-struct CInArchiveInfo: public CArchiveInfo
+struct CInArcInfo: public CArchInfo
{
- UInt32 Size; /* size of this cabinet file in bytes */
+ UInt32 Size; // size of this cabinet file in bytes
UInt32 FileHeadersOffset; // offset of the first CFFILE entry
+
+ bool Parse(const Byte *p);
};
struct CDatabase
{
- UInt64 StartPosition;
- CInArchiveInfo ArchiveInfo;
- CObjectVector<CFolder> Folders;
+ CRecordVector<CFolder> Folders;
CObjectVector<CItem> Items;
+ UInt64 StartPosition;
+ CInArcInfo ArcInfo;
void Clear()
{
- ArchiveInfo.Clear();
+ ArcInfo.Clear();
Folders.Clear();
Items.Clear();
}
+
bool IsTherePrevFolder() const
{
- for (int i = 0; i < Items.Size(); i++)
+ FOR_VECTOR (i, Items)
if (Items[i].ContinuedFromPrev())
return true;
return false;
}
+
int GetNumberOfNewFolders() const
{
int res = Folders.Size();
@@ -100,8 +92,6 @@ struct CDatabase
res--;
return res;
}
- UInt32 GetFileOffset(int index) const { return Items[index].Offset; }
- UInt32 GetFileSize(int index) const { return Items[index].Size; }
};
struct CDatabaseEx: public CDatabase
@@ -111,25 +101,27 @@ struct CDatabaseEx: public CDatabase
struct CMvItem
{
- int VolumeIndex;
- int ItemIndex;
+ unsigned VolumeIndex;
+ unsigned ItemIndex;
};
class CMvDatabaseEx
{
- bool AreItemsEqual(int i1, int i2);
+ bool AreItemsEqual(unsigned i1, unsigned i2);
+
public:
CObjectVector<CDatabaseEx> Volumes;
CRecordVector<CMvItem> Items;
- CRecordVector<int> StartFolderOfVol;
- CRecordVector<int> FolderStartFileIndex;
-
+ CRecordVector<int> StartFolderOfVol; // can be negative
+ CRecordVector<unsigned> FolderStartFileIndex;
+
int GetFolderIndex(const CMvItem *mvi) const
{
const CDatabaseEx &db = Volumes[mvi->VolumeIndex];
return StartFolderOfVol[mvi->VolumeIndex] +
db.Items[mvi->ItemIndex].GetFolderIndex(db.Folders.Size());
}
+
void Clear()
{
Volumes.Clear();
@@ -137,23 +129,30 @@ public:
StartFolderOfVol.Clear();
FolderStartFileIndex.Clear();
}
+
void FillSortAndShrink();
bool Check();
};
+
class CInArchive
{
- CInBuffer inBuffer;
+ CInBufferBase _inBuffer;
+ CByteBuffer _tempBuf;
- Byte Read8();
- UInt16 Read16();
- UInt32 Read32();
- AString SafeReadName();
- void Skip(UInt32 size);
- void ReadOtherArchive(COtherArchive &oa);
+ 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:
- HRESULT Open(const UInt64 *searchHeaderSizeLimit, CDatabaseEx &db);
+ bool IsArc;
+ bool ErrorInNames;
+ bool UnexpectedEnd;
+ bool HeaderError;
+
+ HRESULT Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit);
};
}}
diff --git a/CPP/7zip/Archive/Cab/CabItem.h b/CPP/7zip/Archive/Cab/CabItem.h
index 63a1e856..eda62bda 100755..100644
--- a/CPP/7zip/Archive/Cab/CabItem.h
+++ b/CPP/7zip/Archive/Cab/CabItem.h
@@ -3,20 +3,23 @@
#ifndef __ARCHIVE_CAB_ITEM_H
#define __ARCHIVE_CAB_ITEM_H
-#include "Common/Types.h"
-#include "Common/MyString.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 CompressionTypeMajor;
- Byte CompressionTypeMinor;
- Byte GetCompressionMethod() const { return (Byte)(CompressionTypeMajor & 0xF); }
+ Byte MethodMajor;
+ Byte MethodMinor;
+
+ Byte GetMethod() const { return (Byte)(MethodMajor & 0xF); }
};
struct CItem
@@ -25,27 +28,27 @@ struct CItem
UInt32 Offset;
UInt32 Size;
UInt32 Time;
- UInt16 FolderIndex;
+ UInt32 FolderIndex;
UInt16 Flags;
UInt16 Attributes;
UInt64 GetEndOffset() const { return (UInt64)Offset + Size; }
- UInt32 GetWinAttributes() const { return (Attributes & ~NHeader::kFileNameIsUTFAttributeMask); }
- bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUTFAttributeMask) != 0; }
+ 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);
+ FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev ||
+ FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext;
}
bool ContinuedToNext() const
{
return
- (FolderIndex == NHeader::NFolderIndex::kContinuedToNext) ||
- (FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext);
+ FolderIndex == NHeader::NFolderIndex::kContinuedToNext ||
+ FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext;
}
int GetFolderIndex(int numFolders) const
@@ -53,7 +56,7 @@ struct CItem
if (ContinuedFromPrev())
return 0;
if (ContinuedToNext())
- return (numFolders - 1);
+ return numFolders - 1;
return FolderIndex;
}
};
diff --git a/CPP/7zip/Archive/Cab/CabRegister.cpp b/CPP/7zip/Archive/Cab/CabRegister.cpp
index 15fe4099..acad4c4a 100755..100644
--- a/CPP/7zip/Archive/Cab/CabRegister.cpp
+++ b/CPP/7zip/Archive/Cab/CabRegister.cpp
@@ -5,9 +5,19 @@
#include "../../Common/RegisterArc.h"
#include "CabHandler.h"
-static IInArchive *CreateArc() { return new NArchive::NCab::CHandler; }
+
+namespace NArchive {
+namespace NCab {
+
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"Cab", L"cab", 0, 8, { 0x4D, 0x53, 0x43, 0x46 }, 4, false, CreateArc, 0 };
+ { "Cab", "cab", 0, 8,
+ 8, { 'M', 'S', 'C', 'F', 0, 0, 0, 0 },
+ 0,
+ NArcInfoFlags::kFindSignature,
+ CreateArc };
REGISTER_ARC(Cab)
+
+}}
diff --git a/CPP/7zip/Archive/Cab/StdAfx.h b/CPP/7zip/Archive/Cab/StdAfx.h
index e7fb6986..2854ff3e 100755..100644
--- a/CPP/7zip/Archive/Cab/StdAfx.h
+++ b/CPP/7zip/Archive/Cab/StdAfx.h
@@ -3,6 +3,6 @@
#ifndef __STDAFX_H
#define __STDAFX_H
-#include "../../../Common/MyWindows.h"
+#include "../../../Common/Common.h"
#endif
diff --git a/CPP/7zip/Archive/Chm/ChmHandler.cpp b/CPP/7zip/Archive/Chm/ChmHandler.cpp
index a9e334b0..c67ded28 100755..100644
--- a/CPP/7zip/Archive/Chm/ChmHandler.cpp
+++ b/CPP/7zip/Archive/Chm/ChmHandler.cpp
@@ -2,17 +2,17 @@
#include "StdAfx.h"
-#include "Common/ComTry.h"
-#include "Common/Defs.h"
-#include "Common/StringConvert.h"
-#include "Common/UTFConvert.h"
+#include "../../../Common/ComTry.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/UTFConvert.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.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"
@@ -38,44 +38,45 @@ enum
#endif
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidBlock, VT_UI4}
+ kpidPath,
+ kpidSize,
+ kpidMethod,
+ kpidBlock
#ifdef _CHM_DETAILS
,
- { L"Section", kpidSection, VT_UI4},
- { NULL, kpidOffset, VT_UI4}
+ L"Section", kpidSection,
+ kpidOffset
#endif
};
-STATPROPSTG kArcProps[] =
+/*
+static const Byte kArcProps[] =
{
- { NULL, kpidNumBlocks, VT_UI8}
+ // kpidNumBlocks,
};
+*/
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO
-/*
-IMP_IInArchive_ArcProps
+IMP_IInArchive_ArcProps_NO_Table
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
- COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ // COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
{
+ /*
case kpidNumBlocks:
{
UInt64 numBlocks = 0;
- for (int i = 0; i < m_Database.Sections.Size(); i++)
+ FOR_VECTOR(i, m_Database.Sections)
{
const CSectionInfo &s = m_Database.Sections[i];
- for (int j = 0; j < s.Methods.Size(); j++)
+ FOR_VECTOR(j, s.Methods)
{
const CMethodInfo &m = s.Methods[j];
if (m.IsLzx())
@@ -85,23 +86,27 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
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
+ // COM_TRY_END
}
-*/
-STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
+ NCOM::CPropVariant prop;
if (m_Database.NewFormat)
{
switch(propID)
{
case kpidSize:
- prop = (UInt64)m_Database.NewFormatString.Length();
+ prop = (UInt64)m_Database.NewFormatString.Len();
break;
}
prop.Detach(value);
@@ -113,7 +118,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
else
entryIndex = m_Database.Indices[index];
const CItem &item = m_Database.Items[entryIndex];
- switch(propID)
+ switch (propID)
{
case kpidPath:
{
@@ -122,7 +127,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
{
if (!m_Database.LowLevel)
{
- if (us.Length() > 1)
+ if (us.Len() > 1)
if (us[0] == L'/')
us.Delete(0);
}
@@ -160,6 +165,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
COM_TRY_END
}
+/*
class CProgressImp: public CProgressVirt
{
CMyComPtr<IArchiveOpenCallback> _callback;
@@ -182,18 +188,25 @@ STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles)
return _callback->SetCompleted(numFiles, NULL);
return S_OK;
}
+*/
STDMETHODIMP CHandler::Open(IInStream *inStream,
const UInt64 *maxCheckStartPosition,
IArchiveOpenCallback * /* openArchiveCallback */)
{
COM_TRY_BEGIN
- m_Stream.Release();
+ Close();
try
{
- CInArchive archive;
+ CInArchive archive(_help2);
// CProgressImp progressImp(openArchiveCallback);
- RINOK(archive.Open(inStream, maxCheckStartPosition, m_Database));
+ 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;
@@ -210,6 +223,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
STDMETHODIMP CHandler::Close()
{
+ m_ErrorFlags = 0;
m_Database.Clear();
m_Stream.Release();
return S_OK;
@@ -402,7 +416,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = m_Database.NewFormat ? 1:
@@ -432,7 +446,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 currentItemSize = 0;
UInt64 totalSize = 0;
if (m_Database.NewFormat)
- totalSize = m_Database.NewFormatString.Length();
+ totalSize = m_Database.NewFormatString.Len();
else
for (i = 0; i < numItems; i++)
totalSize += m_Database.Items[allFilesMode ? i : indices[i]].Size;
@@ -460,7 +474,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
continue;
if (!testMode)
{
- UInt32 size = m_Database.NewFormatString.Length();
+ UInt32 size = m_Database.NewFormatString.Len();
RINOK(WriteStream(realOutStream, (const char *)m_Database.NewFormatString, size));
}
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
@@ -475,7 +489,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(extractCallback->PrepareOperation(askMode));
if (item.Section != 0)
{
- RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod));
continue;
}
@@ -589,7 +603,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (!testMode && !realOutStream)
continue;
RINOK(extractCallback->PrepareOperation(askMode));
- RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod));
continue;
}
@@ -718,4 +732,32 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
+namespace NChm {
+
+IMP_CreateArcIn_2(CHandler(false))
+
+static CArcInfo g_ArcInfo =
+ { "Chm", "chm chi chq chw", 0, 0xE9,
+ 12, { 'I', 'T', 'S', 'F', 3, 0, 0, 0, 0x60, 0, 0, 0 },
+ 0,
+ 0,
+ CreateArc };
+
+REGISTER_ARC(Chm)
+}
+
+namespace NHxs {
+
+IMP_CreateArcIn_2(CHandler(true))
+
+static CArcInfo g_ArcInfo =
+ { "Hxs", "hxs hxi hxr hxq hxw lit", 0, 0xCE,
+ 16, { 'I', 'T', 'O', 'L', 'I', 'T', 'L', 'S', 1, 0, 0, 0, 0x28, 0, 0, 0 },
+ 0,
+ NArcInfoFlags::kFindSignature,
+ CreateArc };
+
+REGISTER_ARC(Hxs)
+}
+
}}
diff --git a/CPP/7zip/Archive/Chm/ChmHandler.h b/CPP/7zip/Archive/Chm/ChmHandler.h
index 440c50f1..884f391b 100755..100644
--- a/CPP/7zip/Archive/Chm/ChmHandler.h
+++ b/CPP/7zip/Archive/Chm/ChmHandler.h
@@ -3,8 +3,10 @@
#ifndef __ARCHIVE_CHM_HANDLER_H
#define __ARCHIVE_CHM_HANDLER_H
-#include "Common/MyCom.h"
+#include "../../../Common/MyCom.h"
+
#include "../IArchive.h"
+
#include "ChmIn.h"
namespace NArchive {
@@ -19,9 +21,13 @@ public:
INTERFACE_IInArchive(;)
+ bool _help2;
+ CHandler(bool help2): _help2(help2) {}
+
private:
CFilesDatabase m_Database;
CMyComPtr<IInStream> m_Stream;
+ UInt32 m_ErrorFlags;
};
}}
diff --git a/CPP/7zip/Archive/Chm/ChmHeader.cpp b/CPP/7zip/Archive/Chm/ChmHeader.cpp
deleted file mode 100755
index e8dc9f3e..00000000
--- a/CPP/7zip/Archive/Chm/ChmHeader.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Archive/Chm/Header.h
-
-#include "StdAfx.h"
-
-#include "ChmHeader.h"
-
-namespace NArchive{
-namespace NChm{
-namespace NHeader{
-
-UInt32 kItsfSignature = 0x46535449 + 1;
-UInt32 kItolSignature = 0x4C4F5449 + 1;
-static class CSignatureInitializer
-{
-public:
- CSignatureInitializer()
- {
- kItsfSignature--;
- kItolSignature--;
- }
-}g_SignatureInitializer;
-
-
-}}}
diff --git a/CPP/7zip/Archive/Chm/ChmHeader.h b/CPP/7zip/Archive/Chm/ChmHeader.h
deleted file mode 100755
index 9f1bd42b..00000000
--- a/CPP/7zip/Archive/Chm/ChmHeader.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Archive/Chm/Header.h
-
-#ifndef __ARCHIVE_CHM_HEADER_H
-#define __ARCHIVE_CHM_HEADER_H
-
-#include "Common/Types.h"
-
-namespace NArchive {
-namespace NChm {
-namespace NHeader{
-
-const UInt32 kItspSignature = 0x50535449;
-const UInt32 kPmglSignature = 0x4C474D50;
-const UInt32 kLzxcSignature = 0x43585A4C;
-
-const UInt32 kIfcmSignature = 0x4D434649;
-const UInt32 kAollSignature = 0x4C4C4F41;
-const UInt32 kCaolSignature = 0x4C4F4143;
-
-extern UInt32 kItsfSignature;
-
-extern UInt32 kItolSignature;
-const UInt32 kItlsSignature = 0x534C5449;
-UInt64 inline GetHxsSignature() { return ((UInt64)kItlsSignature << 32) | kItolSignature; }
-
-}}}
-
-#endif
diff --git a/CPP/7zip/Archive/Chm/ChmIn.cpp b/CPP/7zip/Archive/Chm/ChmIn.cpp
index d52b9ba6..9b0bb199 100755..100644
--- a/CPP/7zip/Archive/Chm/ChmIn.cpp
+++ b/CPP/7zip/Archive/Chm/ChmIn.cpp
@@ -2,8 +2,10 @@
#include "StdAfx.h"
-#include "Common/IntToString.h"
-#include "Common/UTFConvert.h"
+// #include <stdio.h>
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/UTFConvert.h"
#include "../../Common/LimitedStreams.h"
@@ -12,6 +14,21 @@
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
@@ -31,9 +48,9 @@ static bool AreGuidsEqual(REFGUID g1, REFGUID g2)
return true;
}
-static char GetHex(Byte value)
+static char GetHex(unsigned v)
{
- return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+ return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10)));
}
static void PrintByte(Byte b, AString &s)
@@ -103,10 +120,10 @@ UString CMethodInfo::GetName() const
else
{
s2 = GetGuidString();
- if (ControlData.GetCapacity() > 0)
+ if (ControlData.Size() > 0)
{
s2 += ':';
- for (size_t i = 0; i < ControlData.GetCapacity(); i++)
+ for (size_t i = 0; i < ControlData.Size(); i++)
PrintByte(ControlData[i], s2);
}
}
@@ -132,7 +149,7 @@ UString CSectionInfo::GetMethodName() const
s += temp;
s += L": ";
}
- for (int i = 0; i < Methods.Size(); i++)
+ FOR_VECTOR (i, Methods)
{
if (i != 0)
s += L' ';
@@ -145,7 +162,7 @@ Byte CInArchive::ReadByte()
{
Byte b;
if (!_inBuffer.ReadByte(b))
- throw 1;
+ throw CEnexpectedEndException();
return b;
}
@@ -163,32 +180,32 @@ void CInArchive::ReadBytes(Byte *data, UInt32 size)
UInt16 CInArchive::ReadUInt16()
{
- UInt16 value = 0;
+ UInt16 val = 0;
for (int i = 0; i < 2; i++)
- value |= ((UInt16)(ReadByte()) << (8 * i));
- return value;
+ val |= ((UInt16)(ReadByte()) << (8 * i));
+ return val;
}
UInt32 CInArchive::ReadUInt32()
{
- UInt32 value = 0;
+ UInt32 val = 0;
for (int i = 0; i < 4; i++)
- value |= ((UInt32)(ReadByte()) << (8 * i));
- return value;
+ val |= ((UInt32)(ReadByte()) << (8 * i));
+ return val;
}
UInt64 CInArchive::ReadUInt64()
{
- UInt64 value = 0;
+ UInt64 val = 0;
for (int i = 0; i < 8; i++)
- value |= ((UInt64)(ReadByte()) << (8 * i));
- return value;
+ val |= ((UInt64)(ReadByte()) << (8 * i));
+ return val;
}
UInt64 CInArchive::ReadEncInt()
{
- UInt64 val = 0;;
- for (int i = 0; i < 10; i++)
+ UInt64 val = 0;
+ for (int i = 0; i < 9; i++)
{
Byte b = ReadByte();
val |= (b & 0x7F);
@@ -196,7 +213,7 @@ UInt64 CInArchive::ReadEncInt()
return val;
val <<= 7;
}
- throw 1;
+ throw CHeaderErrorException();
}
void CInArchive::ReadGUID(GUID &g)
@@ -207,10 +224,10 @@ void CInArchive::ReadGUID(GUID &g)
ReadBytes(g.Data4, 8);
}
-void CInArchive::ReadString(int size, AString &s)
+void CInArchive::ReadString(unsigned size, AString &s)
{
s.Empty();
- while(size-- != 0)
+ while (size-- != 0)
{
char c = (char)ReadByte();
if (c == 0)
@@ -222,10 +239,10 @@ void CInArchive::ReadString(int size, AString &s)
}
}
-void CInArchive::ReadUString(int size, UString &s)
+void CInArchive::ReadUString(unsigned size, UString &s)
{
s.Empty();
- while(size-- != 0)
+ while (size-- != 0)
{
wchar_t c = ReadUInt16();
if (c == 0)
@@ -244,6 +261,7 @@ HRESULT CInArchive::ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size)
CMyComPtr<ISequentialInStream> limitedStream(streamSpec);
streamSpec->SetStream(inStream);
streamSpec->Init(size);
+ m_InStreamRef = limitedStream;
_inBuffer.SetStream(limitedStream);
_inBuffer.Init();
return S_OK;
@@ -252,10 +270,10 @@ HRESULT CInArchive::ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size)
HRESULT CInArchive::ReadDirEntry(CDatabase &database)
{
CItem item;
- UInt64 nameLength = ReadEncInt();
- if (nameLength == 0 || nameLength >= 0x10000000)
+ UInt64 nameLen = ReadEncInt();
+ if (nameLen == 0 || nameLen > (1 << 13))
return S_FALSE;
- ReadString((int)nameLength, item.Name);
+ ReadString((unsigned)nameLen, item.Name);
item.Section = ReadEncInt();
item.Offset = ReadEncInt();
item.Size = ReadEncInt();
@@ -268,9 +286,14 @@ 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).
@@ -280,37 +303,39 @@ HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database)
GUID g;
ReadGUID(g); // {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC}
ReadGUID(g); // {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC}
- const int kNumSections = 2;
+ const unsigned kNumSections = 2;
UInt64 sectionOffsets[kNumSections];
UInt64 sectionSizes[kNumSections];
- int i;
+ 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 = _startPosition + 0x58
+ database.ContentOffset = database.StartPosition + 0x58
*/
- /*
// Section 0
ReadChunk(inStream, sectionOffsets[0], sectionSizes[0]);
- if (sectionSizes[0] != 0x18)
+ if (sectionSizes[0] < 0x18)
+ return S_FALSE;
+ if (ReadUInt32() != 0x01FE)
return S_FALSE;
- ReadUInt32(); // unknown: 01FE
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() != NHeader::kItspSignature)
+ if (ReadUInt32() != kSignature_ITSP)
return S_FALSE;
if (ReadUInt32() != 1) // version
return S_FALSE;
@@ -340,13 +365,13 @@ HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database)
for (UInt32 ci = 0; ci < numDirChunks; ci++)
{
UInt64 chunkPos = _inBuffer.GetProcessedSize();
- if (ReadUInt32() == NHeader::kPmglSignature)
+ 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(); // Length of free space and/or quickref area at end of directory chunk
+ 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
@@ -354,7 +379,7 @@ HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database)
// directory in sequence (-1 if this is the first listing chunk)
ReadUInt32(); // Chunk number of next listing chunk when reading
// directory in sequence (-1 if this is the last listing chunk)
- int numItems = 0;
+ unsigned numItems = 0;
for (;;)
{
UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos;
@@ -383,10 +408,13 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
if (ReadUInt32() != 0x28) // Location of header section table
return S_FALSE;
UInt32 numHeaderSections = ReadUInt32();
- const int kNumHeaderSectionsMax = 5;
+ const unsigned kNumHeaderSectionsMax = 5;
if (numHeaderSections != kNumHeaderSectionsMax)
return S_FALSE;
- ReadUInt32(); // Length of post-header table
+
+ IsArc = true;
+
+ ReadUInt32(); // Len of post-header table
GUID g;
ReadGUID(g); // {0A9007C1-4076-11D3-8789-0000F8105754}
@@ -398,6 +426,8 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
{
sectionOffsets[i] = ReadUInt64();
sectionSizes[i] = ReadUInt64();
+ UInt64 end = sectionOffsets[i] + sectionSizes[i];
+ database.UpdatePhySize(end);
}
// Post-Header
@@ -436,11 +466,11 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
ReadUInt32(); // $20000 (Same as field following chunk size in directory index)
ReadUInt64(); // 0 (unknown)
- if (ReadUInt32() != NHeader::kCaolSignature)
+ if (ReadUInt32() != kSignature_CAOL)
return S_FALSE;
if (ReadUInt32() != 2) // (Most likely a version number)
return S_FALSE;
- UInt32 caolLength = ReadUInt32(); // $50 (Length of the CAOL section, which includes the ITSF section)
+ 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.
@@ -458,13 +488,15 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
ReadUInt32(); // 0 (Unknown)
if (caolLength == 0x2C)
{
- database.ContentOffset = 0;
+ // 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() != NHeader::kItsfSignature)
+ if (ReadUInt32() != kSignature_ITSF)
return S_FALSE;
if (ReadUInt32() != 4) // $4 (Version number -- CHM uses 3)
return S_FALSE;
@@ -473,7 +505,7 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
UInt32 unknown = ReadUInt32();
if (unknown != 0 && unknown != 1) // = 0 for some HxW files, 1 in other cases;
return S_FALSE;
- database.ContentOffset = _startPosition + ReadUInt64();
+ database.ContentOffset = database.StartPosition + ReadUInt64();
/* UInt32 timeStamp = */ ReadUInt32();
// A timestamp of some sort.
// Considered as a big-endian DWORD, it appears to contain
@@ -486,21 +518,21 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
return S_FALSE;
}
- /*
// Section 0
- ReadChunk(inStream, _startPosition + sectionOffsets[0], sectionSizes[0]);
- if (sectionSizes[0] != 0x18)
+ ReadChunk(inStream, database.StartPosition + sectionOffsets[0], sectionSizes[0]);
+ if (sectionSizes[0] < 0x18)
+ return S_FALSE;
+ if (ReadUInt32() != 0x01FE)
return S_FALSE;
- ReadUInt32(); // unknown: 01FE
ReadUInt32(); // unknown: 0
UInt64 fileSize = ReadUInt64();
+ database.UpdatePhySize(fileSize);
ReadUInt32(); // unknown: 0
ReadUInt32(); // unknown: 0
- */
// Section 1: The Directory Listing
- ReadChunk(inStream, _startPosition + sectionOffsets[1], sectionSizes[1]);
- if (ReadUInt32() != NHeader::kIfcmSignature)
+ 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;
@@ -516,9 +548,9 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
for (UInt32 ci = 0; ci < numDirChunks; ci++)
{
UInt64 chunkPos = _inBuffer.GetProcessedSize();
- if (ReadUInt32() == NHeader::kAollSignature)
+ if (ReadUInt32() == kSignature_AOLL)
{
- UInt32 quickrefLength = ReadUInt32(); // Length of quickref area at end of directory chunk
+ UInt32 quickrefLength = ReadUInt32(); // Len of quickref area at end of directory chunk
if (quickrefLength > dirChunkSize || quickrefLength < 2)
return S_FALSE;
ReadUInt64(); // Directory chunk number
@@ -533,7 +565,7 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
ReadUInt32(); // 1 (unknown -- other values have also been seen here)
ReadUInt32(); // 0 (unknown)
- int numItems = 0;
+ unsigned numItems = 0;
for (;;)
{
UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos;
@@ -544,11 +576,11 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
break;
if (database.NewFormat)
{
- UInt16 nameLength = ReadUInt16();
- if (nameLength == 0)
+ UInt16 nameLen = ReadUInt16();
+ if (nameLen == 0)
return S_FALSE;
UString name;
- ReadUString((int)nameLength, name);
+ ReadUString((unsigned)nameLen, name);
AString s;
ConvertUnicodeToUTF8(name, s);
Byte b = ReadByte();
@@ -637,10 +669,10 @@ static int CompareFiles(const int *p1, const int *p2, void *param)
void CFilesDatabase::SetIndices()
{
- for (int i = 0; i < Items.Size(); i++)
+ FOR_VECTOR (i, Items)
{
const CItem &item = Items[i];
- if (item.IsUserItem() && item.Name.Length() != 1)
+ if (item.IsUserItem() && item.Name.Len() != 1)
Indices.Add(i);
}
}
@@ -654,7 +686,7 @@ bool CFilesDatabase::Check()
{
UInt64 maxPos = 0;
UInt64 prevSection = 0;
- for(int i = 0; i < Indices.Size(); i++)
+ FOR_VECTOR (i, Indices)
{
const CItem &item = Items[Indices[i]];
if (item.Section == 0 || item.IsDir())
@@ -684,9 +716,9 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
for (int i = 0; i < numSections; i++)
{
CSectionInfo section;
- UInt16 nameLength = ReadUInt16();
+ UInt16 nameLen = ReadUInt16();
UString name;
- ReadUString(nameLength, name);
+ ReadUString(nameLen, name);
if (ReadUInt16() != 0)
return S_FALSE;
if (!ConvertUnicodeToUTF8(name, section.Name))
@@ -695,7 +727,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
}
}
- int i;
+ unsigned i;
for (i = 1; i < database.Sections.Size(); i++)
{
CSectionInfo &section = database.Sections[i];
@@ -736,7 +768,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
{
// Control Data
RINOK(DecompressStream(inStream, database, sectionPrefix + kControlData));
- for (int mi = 0; mi < section.Methods.Size(); mi++)
+ FOR_VECTOR (mi, section.Methods)
{
CMethodInfo &method = section.Methods[mi];
UInt32 numDWORDS = ReadUInt32();
@@ -744,7 +776,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
{
if (numDWORDS < 5)
return S_FALSE;
- if (ReadUInt32() != NHeader::kLzxcSignature)
+ if (ReadUInt32() != kSignature_LZXC)
return S_FALSE;
CLzxInfo &li = method.LzxInfo;
li.Version = ReadUInt32();
@@ -778,7 +810,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
else
{
UInt32 numBytes = numDWORDS * 4;
- method.ControlData.SetCapacity(numBytes);
+ method.ControlData.Alloc(numBytes);
ReadBytes(method.ControlData, numBytes);
}
}
@@ -791,7 +823,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
}
// read ResetTable for LZX
- for (int mi = 0; mi < section.Methods.Size(); mi++)
+ FOR_VECTOR (mi, section.Methods)
{
CMethodInfo &method = section.Methods[mi];
if (method.IsLzx())
@@ -819,16 +851,16 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
UInt32 numEntries = ReadUInt32();
if (ReadUInt32() != 8) // Size of table entry (bytes)
return S_FALSE;
- if (ReadUInt32() != 0x28) // Length of table header
+ if (ReadUInt32() != 0x28) // Len of table header
return S_FALSE;
rt.UncompressedSize = ReadUInt64();
rt.CompressedSize = ReadUInt64();
rt.BlockSize = ReadUInt64(); // 0x8000 block size for locations below
if (rt.BlockSize != 0x8000)
return S_FALSE;
- rt.ResetOffsets.Reserve(numEntries);
+ rt.ResetOffsets.ClearAndReserve(numEntries);
for (UInt32 i = 0; i < numEntries; i++)
- rt.ResetOffsets.Add(ReadUInt64());
+ rt.ResetOffsets.AddInReserved(ReadUInt64());
}
}
}
@@ -843,77 +875,91 @@ 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, &_startPosition));
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &database.StartPosition));
- database.Help2Format = false;
- const UInt32 chmVersion = 3;
+ if (!_inBuffer.Create(1 << 14))
+ return E_OUTOFMEMORY;
+ _inBuffer.SetStream(inStream);
+ _inBuffer.Init();
+
+ if (_help2)
{
- if (!_inBuffer.Create(1 << 14))
- return E_OUTOFMEMORY;
- _inBuffer.SetStream(inStream);
- _inBuffer.Init();
- UInt64 value = 0;
const int kSignatureSize = 8;
- UInt64 hxsSignature = NHeader::GetHxsSignature();
- UInt64 chmSignature = ((UInt64)chmVersion << 32)| NHeader::kItsfSignature;
+ UInt64 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;
- value >>= 8;
- value |= ((UInt64)b) << ((kSignatureSize - 1) * 8);
+ val >>= 8;
+ val |= ((UInt64)b) << ((kSignatureSize - 1) * 8);
if (_inBuffer.GetProcessedSize() >= kSignatureSize)
{
- if (value == chmSignature)
- break;
- if (value == hxsSignature)
- {
- database.Help2Format = true;
+ if (val == signature)
break;
- }
if (_inBuffer.GetProcessedSize() > limit)
return S_FALSE;
}
}
- _startPosition += _inBuffer.GetProcessedSize() - kSignatureSize;
- }
-
- if (database.Help2Format)
- {
+ 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
{
- HRESULT res = OpenHighLevel(inStream, database);
- if (res == S_FALSE)
+ try
+ {
+ HRESULT res = OpenHighLevel(inStream, database);
+ if (res == S_FALSE)
+ {
+ UnsupportedFeature = true;
+ database.HighLevelClear();
+ return S_OK;
+ }
+ RINOK(res);
+ database.LowLevel = false;
+ }
+ catch(...)
{
database.HighLevelClear();
- return S_OK;
+ throw;
}
- RINOK(res);
- database.LowLevel = false;
- }
- catch(...)
- {
- return S_OK;
}
+ // catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(CEnexpectedEndException &) { UnexpectedEnd = true; }
+ catch(CHeaderErrorException &) { HeadersError = true; }
+ catch(...) { throw; }
+
#endif
+
return S_OK;
}
@@ -923,15 +969,22 @@ HRESULT CInArchive::Open(IInStream *inStream,
{
try
{
- HRESULT res = Open2(inStream, searchHeaderSizeLimit, database);
- _inBuffer.ReleaseStream();
- return res;
- }
- catch(...)
- {
- _inBuffer.ReleaseStream();
- throw;
+ 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 4b1ac7a6..70764ab9 100755..100644
--- a/CPP/7zip/Archive/Chm/ChmIn.h
+++ b/CPP/7zip/Archive/Chm/ChmIn.h
@@ -3,13 +3,12 @@
#ifndef __ARCHIVE_CHM_IN_H
#define __ARCHIVE_CHM_IN_H
-#include "Common/Buffer.h"
-#include "Common/MyString.h"
+#include "../../../Common/MyBuffer.h"
+#include "../../../Common/MyString.h"
#include "../../IStream.h"
-#include "../../Common/InBuffer.h"
-#include "ChmHeader.h"
+#include "../../Common/InBuffer.h"
namespace NArchive {
namespace NChm {
@@ -23,21 +22,21 @@ struct CItem
bool IsFormatRelatedItem() const
{
- if (Name.Length() < 2)
+ if (Name.Len() < 2)
return false;
return Name[0] == ':' && Name[1] == ':';
}
bool IsUserItem() const
{
- if (Name.Length() < 2)
+ if (Name.Len() < 2)
return false;
return Name[0] == '/';
}
bool IsDir() const
{
- if (Name.Length() == 0)
+ if (Name.Len() == 0)
return false;
return (Name.Back() == '/');
}
@@ -45,15 +44,19 @@ struct CItem
struct CDatabase
{
+ UInt64 StartPosition;
UInt64 ContentOffset;
CObjectVector<CItem> Items;
AString NewFormatString;
bool Help2Format;
bool NewFormat;
+ UInt64 PhySize;
+
+ void UpdatePhySize(UInt64 v) { if (PhySize < v) PhySize = v; }
int FindItem(const AString &name) const
{
- for (int i = 0; i < Items.Size(); i++)
+ FOR_VECTOR (i, Items)
if (Items[i].Name == name)
return i;
return -1;
@@ -65,6 +68,8 @@ struct CDatabase
NewFormatString.Empty();
Help2Format = false;
Items.Clear();
+ StartPosition = 0;
+ PhySize = 0;
}
};
@@ -74,15 +79,16 @@ struct CResetTable
UInt64 CompressedSize;
UInt64 BlockSize;
CRecordVector<UInt64> ResetOffsets;
+
bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const
{
if (blockIndex >= ResetOffsets.Size())
return false;
- UInt64 startPos = ResetOffsets[(int)blockIndex];
+ UInt64 startPos = ResetOffsets[(unsigned)blockIndex];
if (blockIndex + numBlocks >= ResetOffsets.Size())
size = CompressedSize - startPos;
else
- size = ResetOffsets[(int)(blockIndex + numBlocks)] - startPos;
+ size = ResetOffsets[(unsigned)(blockIndex + numBlocks)] - startPos;
return true;
}
bool GetCompressedSizeOfBlock(UInt64 blockIndex, UInt64 &size) const
@@ -107,7 +113,7 @@ struct CLzxInfo
{
if (Version == 2 || Version == 3)
{
- for (int i = 0; i <= 31; i++)
+ for (unsigned i = 0; i <= 31; i++)
if (((UInt32)1 << i) >= WindowSize)
return 15 + i;
}
@@ -123,7 +129,7 @@ struct CLzxInfo
UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
if (blockIndex >= ResetTable.ResetOffsets.Size())
return false;
- offset = ResetTable.ResetOffsets[(int)blockIndex];
+ offset = ResetTable.ResetOffsets[(unsigned)blockIndex];
return true;
}
bool GetCompressedSizeOfFolder(UInt64 folderIndex, UInt64 &size) const
@@ -202,18 +208,21 @@ public:
bool Check();
};
+/*
class CProgressVirt
{
public:
STDMETHOD(SetTotal)(const UInt64 *numFiles) PURE;
STDMETHOD(SetCompleted)(const UInt64 *numFiles) PURE;
};
+*/
class CInArchive
{
- UInt64 _startPosition;
+ CMyComPtr<ISequentialInStream> m_InStreamRef;
::CInBuffer _inBuffer;
UInt64 _chunkSize;
+ bool _help2;
Byte ReadByte();
void ReadBytes(Byte *data, UInt32 size);
@@ -222,8 +231,8 @@ class CInArchive
UInt32 ReadUInt32();
UInt64 ReadUInt64();
UInt64 ReadEncInt();
- void ReadString(int size, AString &s);
- void ReadUString(int size, UString &s);
+ void ReadString(unsigned size, AString &s);
+ void ReadUString(unsigned size, UString &s);
void ReadGUID(GUID &g);
HRESULT ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size);
@@ -232,6 +241,13 @@ class CInArchive
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);
diff --git a/CPP/7zip/Archive/Chm/ChmRegister.cpp b/CPP/7zip/Archive/Chm/ChmRegister.cpp
deleted file mode 100755
index e5f38afa..00000000
--- a/CPP/7zip/Archive/Chm/ChmRegister.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// ChmRegister.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/RegisterArc.h"
-
-#include "ChmHandler.h"
-static IInArchive *CreateArc() { return new NArchive::NChm::CHandler; }
-
-static CArcInfo g_ArcInfo =
- { L"Chm", L"chm chi chq chw hxs hxi hxr hxq hxw lit", 0, 0xE9, { 'I', 'T', 'S', 'F' }, 4, false, CreateArc, 0 };
-
-REGISTER_ARC(Chm)
diff --git a/CPP/7zip/Archive/Chm/StdAfx.h b/CPP/7zip/Archive/Chm/StdAfx.h
index e7fb6986..2854ff3e 100755..100644
--- a/CPP/7zip/Archive/Chm/StdAfx.h
+++ b/CPP/7zip/Archive/Chm/StdAfx.h
@@ -3,6 +3,6 @@
#ifndef __STDAFX_H
#define __STDAFX_H
-#include "../../../Common/MyWindows.h"
+#include "../../../Common/Common.h"
#endif
diff --git a/CPP/7zip/Archive/Com/ComHandler.cpp b/CPP/7zip/Archive/Com/ComHandler.cpp
deleted file mode 100755
index 58f76439..00000000
--- a/CPP/7zip/Archive/Com/ComHandler.cpp
+++ /dev/null
@@ -1,239 +0,0 @@
-// ComHandler.cpp
-
-#include "StdAfx.h"
-
-#include "Common/ComTry.h"
-
-#include "Windows/PropVariant.h"
-
-#include "../../Common/LimitedStreams.h"
-#include "../../Common/ProgressUtils.h"
-#include "../../Common/StreamUtils.h"
-
-#include "../../Compress/CopyCoder.h"
-
-#include "ComHandler.h"
-
-namespace NArchive {
-namespace NCom {
-
-STATPROPSTG kProps[] =
-{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidCTime, VT_FILETIME},
- { NULL, kpidMTime, VT_FILETIME}
-};
-
-STATPROPSTG kArcProps[] =
-{
- { NULL, kpidClusterSize, VT_UI4},
- { NULL, kpidSectorSize, VT_UI4}
-};
-
-IMP_IInArchive_Props
-IMP_IInArchive_ArcProps
-
-STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
-{
- COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- switch(propID)
- {
- case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break;
- case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; break;
- case kpidMainSubfile: if (_db.MainSubfile >= 0) prop = (UInt32)_db.MainSubfile; break;
- }
- prop.Detach(value);
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
-{
- COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- const CRef &ref = _db.Refs[index];
- const CItem &item = _db.Items[ref.Did];
-
- switch(propID)
- {
- case kpidPath: prop = _db.GetItemPath(index); break;
- case kpidIsDir: prop = item.IsDir(); break;
- case kpidCTime: prop = item.CTime; break;
- case kpidMTime: prop = item.MTime; break;
- case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break;
- case kpidSize: if (!item.IsDir()) prop = item.Size; break;
- }
- prop.Detach(value);
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::Open(IInStream *inStream,
- const UInt64 * /* maxCheckStartPosition */,
- IArchiveOpenCallback * /* openArchiveCallback */)
-{
- COM_TRY_BEGIN
- Close();
- try
- {
- if (_db.Open(inStream) != S_OK)
- return S_FALSE;
- _stream = inStream;
- }
- catch(...) { return S_FALSE; }
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::Close()
-{
- _db.Clear();
- _stream.Release();
- return S_OK;
-}
-
-STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
- Int32 testMode, IArchiveExtractCallback *extractCallback)
-{
- COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
- if (allFilesMode)
- numItems = _db.Refs.Size();
- if (numItems == 0)
- return S_OK;
- UInt32 i;
- UInt64 totalSize = 0;
- for(i = 0; i < numItems; i++)
- {
- const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did];
- if (!item.IsDir())
- totalSize += item.Size;
- }
- RINOK(extractCallback->SetTotal(totalSize));
-
- UInt64 totalPackSize;
- totalSize = totalPackSize = 0;
-
- NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
- CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
-
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> progress = lps;
- lps->Init(extractCallback, false);
-
- for (i = 0; i < numItems; i++)
- {
- lps->InSize = totalPackSize;
- lps->OutSize = totalSize;
- RINOK(lps->SetCur());
- Int32 index = allFilesMode ? i : indices[i];
- const CItem &item = _db.Items[_db.Refs[index].Did];
-
- CMyComPtr<ISequentialOutStream> outStream;
- Int32 askMode = testMode ?
- NExtract::NAskMode::kTest :
- NExtract::NAskMode::kExtract;
- RINOK(extractCallback->GetStream(index, &outStream, askMode));
-
- if (item.IsDir())
- {
- RINOK(extractCallback->PrepareOperation(askMode));
- RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
- continue;
- }
-
- totalPackSize += _db.GetItemPackSize(item.Size);
- totalSize += item.Size;
-
- if (!testMode && !outStream)
- continue;
- RINOK(extractCallback->PrepareOperation(askMode));
- Int32 res = NExtract::NOperationResult::kDataError;
- CMyComPtr<ISequentialInStream> inStream;
- HRESULT hres = GetStream(index, &inStream);
- if (hres == S_FALSE)
- res = NExtract::NOperationResult::kDataError;
- else if (hres == E_NOTIMPL)
- res = NExtract::NOperationResult::kUnSupportedMethod;
- else
- {
- RINOK(hres);
- if (inStream)
- {
- RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
- if (copyCoderSpec->TotalSize == item.Size)
- res = NExtract::NOperationResult::kOK;
- }
- }
- outStream.Release();
- RINOK(extractCallback->SetOperationResult(res));
- }
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
-{
- *numItems = _db.Refs.Size();
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
-{
- COM_TRY_BEGIN
- *stream = 0;
- const CItem &item = _db.Items[_db.Refs[index].Did];
- CClusterInStream *streamSpec = new CClusterInStream;
- CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
- streamSpec->Stream = _stream;
- streamSpec->StartOffset = 0;
-
- bool isLargeStream = _db.IsLargeStream(item.Size);
- int bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits;
- streamSpec->BlockSizeLog = bsLog;
- streamSpec->Size = item.Size;
-
- UInt32 clusterSize = (UInt32)1 << bsLog;
- UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog;
- if (numClusters64 >= ((UInt32)1 << 31))
- return E_NOTIMPL;
- streamSpec->Vector.Reserve((int)numClusters64);
- UInt32 sid = item.Sid;
- UInt64 size = item.Size;
-
- if (size != 0)
- {
- for (;; size -= clusterSize)
- {
- if (isLargeStream)
- {
- if (sid >= _db.FatSize)
- return S_FALSE;
- streamSpec->Vector.Add(sid + 1);
- sid = _db.Fat[sid];
- }
- else
- {
- UInt64 val;
- if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32)
- return S_FALSE;
- streamSpec->Vector.Add((UInt32)val);
- sid = _db.Mat[sid];
- }
- if (size <= clusterSize)
- break;
- }
- }
- if (sid != NFatID::kEndOfChain)
- return S_FALSE;
- RINOK(streamSpec->InitAndSeek());
- *stream = streamTemp.Detach();
- return S_OK;
- COM_TRY_END
-}
-
-}}
diff --git a/CPP/7zip/Archive/Com/ComHandler.h b/CPP/7zip/Archive/Com/ComHandler.h
deleted file mode 100755
index f2b7de96..00000000
--- a/CPP/7zip/Archive/Com/ComHandler.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// ComHandler.h
-
-#ifndef __ARCHIVE_COM_HANDLER_H
-#define __ARCHIVE_COM_HANDLER_H
-
-#include "Common/MyCom.h"
-#include "../IArchive.h"
-#include "ComIn.h"
-
-namespace NArchive {
-namespace NCom {
-
-class CHandler:
- public IInArchive,
- public IInArchiveGetStream,
- public CMyUnknownImp
-{
- CMyComPtr<IInStream> _stream;
- CDatabase _db;
-public:
- MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
- INTERFACE_IInArchive(;)
- STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
-};
-
-}}
-
-#endif
diff --git a/CPP/7zip/Archive/Com/ComIn.cpp b/CPP/7zip/Archive/Com/ComIn.cpp
deleted file mode 100755
index 2203ca53..00000000
--- a/CPP/7zip/Archive/Com/ComIn.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-// Archive/ComIn.cpp
-
-#include "StdAfx.h"
-
-#include "../../../../C/Alloc.h"
-#include "../../../../C/CpuArch.h"
-
-#include "Common/IntToString.h"
-#include "Common/MyCom.h"
-
-#include "../../Common/StreamUtils.h"
-
-#include "ComIn.h"
-
-#define Get16(p) GetUi16(p)
-#define Get32(p) GetUi32(p)
-
-namespace NArchive{
-namespace NCom{
-
-static const UInt32 kSignatureSize = 8;
-static const Byte kSignature[kSignatureSize] = { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };
-
-void CUInt32Buf::Free()
-{
- MyFree(_buf);
- _buf = 0;
-}
-
-bool CUInt32Buf::Allocate(UInt32 numItems)
-{
- Free();
- if (numItems == 0)
- return true;
- size_t newSize = (size_t)numItems * sizeof(UInt32);
- if (newSize / sizeof(UInt32) != numItems)
- return false;
- _buf = (UInt32 *)MyAlloc(newSize);
- return (_buf != 0);
-}
-
-static HRESULT ReadSector(IInStream *inStream, Byte *buf, int sectorSizeBits, UInt32 sid)
-{
- RINOK(inStream->Seek((((UInt64)sid + 1) << sectorSizeBits), STREAM_SEEK_SET, NULL));
- return ReadStream_FALSE(inStream, buf, (UInt32)1 << sectorSizeBits);
-}
-
-static HRESULT ReadIDs(IInStream *inStream, Byte *buf, int sectorSizeBits, UInt32 sid, UInt32 *dest)
-{
- RINOK(ReadSector(inStream, buf, sectorSizeBits, sid));
- UInt32 sectorSize = (UInt32)1 << sectorSizeBits;
- for (UInt32 t = 0; t < sectorSize; t += 4)
- *dest++ = Get32(buf + t);
- return S_OK;
-}
-
-static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
-{
- ft->dwLowDateTime = Get32(p);
- ft->dwHighDateTime = Get32(p + 4);
-}
-
-void CItem::Parse(const Byte *p, bool mode64bit)
-{
- memcpy(Name, p, kNameSizeMax);
- // NameSize = Get16(p + 64);
- Type = p[66];
- LeftDid = Get32(p + 68);
- RightDid = Get32(p + 72);
- SonDid = Get32(p + 76);
- // Flags = Get32(p + 96);
- GetFileTimeFromMem(p + 100, &CTime);
- GetFileTimeFromMem(p + 108, &MTime);
- Sid = Get32(p + 116);
- Size = Get32(p + 120);
- if (mode64bit)
- Size |= ((UInt64)Get32(p + 124) << 32);
-}
-
-void CDatabase::Clear()
-{
- Fat.Free();
- MiniSids.Free();
- Mat.Free();
- Items.Clear();
- Refs.Clear();
-}
-
-static const UInt32 kNoDid = 0xFFFFFFFF;
-
-HRESULT CDatabase::AddNode(int parent, UInt32 did)
-{
- if (did == kNoDid)
- return S_OK;
- if (did >= (UInt32)Items.Size())
- return S_FALSE;
- const CItem &item = Items[did];
- if (item.IsEmpty())
- return S_FALSE;
- CRef ref;
- ref.Parent = parent;
- ref.Did = did;
- int index = Refs.Add(ref);
- if (Refs.Size() > Items.Size())
- return S_FALSE;
- RINOK(AddNode(parent, item.LeftDid));
- RINOK(AddNode(parent, item.RightDid));
- if (item.IsDir())
- {
- RINOK(AddNode(index, item.SonDid));
- }
- return S_OK;
-}
-
-static const char kCharOpenBracket = '[';
-static const char kCharCloseBracket = ']';
-
-static UString CompoundNameToFileName(const UString &s)
-{
- UString res;
- for (int i = 0; i < s.Length(); i++)
- {
- wchar_t c = s[i];
- if (c < 0x20)
- {
- res += kCharOpenBracket;
- wchar_t buf[32];
- ConvertUInt32ToString(c, buf);
- res += buf;
- res += kCharCloseBracket;
- }
- else
- res += c;
- }
- return res;
-}
-
-static char g_MsiChars[] =
-"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._";
-
-static const wchar_t *kMsi_ID = L""; // L"{msi}";
-
-static const int kMsiNumBits = 6;
-static const UInt32 kMsiNumChars = 1 << kMsiNumBits;
-static const UInt32 kMsiCharMask = kMsiNumChars - 1;
-static const UInt32 kMsiStartUnicodeChar = 0x3800;
-static const UInt32 kMsiUnicodeRange = kMsiNumChars * (kMsiNumChars + 1);
-
-bool CompoundMsiNameToFileName(const UString &name, UString &resultName)
-{
- resultName.Empty();
- for (int i = 0; i < name.Length(); i++)
- {
- wchar_t c = name[i];
- if (c < kMsiStartUnicodeChar || c > kMsiStartUnicodeChar + kMsiUnicodeRange)
- return false;
- if (i == 0)
- resultName += kMsi_ID;
- c -= kMsiStartUnicodeChar;
-
- UInt32 c0 = c & kMsiCharMask;
- UInt32 c1 = c >> kMsiNumBits;
-
- if (c1 <= kMsiNumChars)
- {
- resultName += (wchar_t)g_MsiChars[c0];
- if (c1 == kMsiNumChars)
- break;
- resultName += (wchar_t)g_MsiChars[c1];
- }
- else
- resultName += L'!';
- }
- return true;
-}
-
-static UString ConvertName(const Byte *p, bool &isMsi)
-{
- isMsi = false;
- UString s;
- for (int i = 0; i < kNameSizeMax; i += 2)
- {
- wchar_t c = (p[i] | (wchar_t)p[i + 1] << 8);
- if (c == 0)
- break;
- s += c;
- }
- UString msiName;
- if (CompoundMsiNameToFileName(s, msiName))
- {
- isMsi = true;
- return msiName;
- }
- return CompoundNameToFileName(s);
-}
-
-static UString ConvertName(const Byte *p)
-{
- bool isMsi;
- return ConvertName(p, isMsi);
-}
-
-UString CDatabase::GetItemPath(UInt32 index) const
-{
- UString s;
- while (index != kNoDid)
- {
- const CRef &ref = Refs[index];
- const CItem &item = Items[ref.Did];
- if (!s.IsEmpty())
- s = (UString)WCHAR_PATH_SEPARATOR + s;
- s = ConvertName(item.Name) + s;
- index = ref.Parent;
- }
- return s;
-}
-
-HRESULT CDatabase::Open(IInStream *inStream)
-{
- MainSubfile = -1;
- static const UInt32 kHeaderSize = 512;
- Byte p[kHeaderSize];
- RINOK(ReadStream_FALSE(inStream, p, kHeaderSize));
- if (memcmp(p, kSignature, kSignatureSize) != 0)
- return S_FALSE;
- if (Get16(p + 0x1A) > 4) // majorVer
- return S_FALSE;
- if (Get16(p + 0x1C) != 0xFFFE)
- return S_FALSE;
- int sectorSizeBits = Get16(p + 0x1E);
- bool mode64bit = (sectorSizeBits >= 12);
- int miniSectorSizeBits = Get16(p + 0x20);
- SectorSizeBits = sectorSizeBits;
- MiniSectorSizeBits = miniSectorSizeBits;
-
- if (sectorSizeBits > 28 || miniSectorSizeBits > 28 ||
- sectorSizeBits < 7 || miniSectorSizeBits < 2 || miniSectorSizeBits > sectorSizeBits)
- return S_FALSE;
- UInt32 numSectorsForFAT = Get32(p + 0x2C);
- LongStreamMinSize = Get32(p + 0x38);
-
- UInt32 sectSize = (UInt32)1 << (int)sectorSizeBits;
-
- CByteBuffer sect;
- sect.SetCapacity(sectSize);
-
- int ssb2 = (int)(sectorSizeBits - 2);
- UInt32 numSidsInSec = (UInt32)1 << ssb2;
- UInt32 numFatItems = numSectorsForFAT << ssb2;
- if ((numFatItems >> ssb2) != numSectorsForFAT)
- return S_FALSE;
- FatSize = numFatItems;
-
- {
- CUInt32Buf bat;
- UInt32 numSectorsForBat = Get32(p + 0x48);
- const UInt32 kNumHeaderBatItems = 109;
- UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2);
- if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat)
- return S_FALSE;
- if (!bat.Allocate(numBatItems))
- return S_FALSE;
- UInt32 i;
- for (i = 0; i < kNumHeaderBatItems; i++)
- bat[i] = Get32(p + 0x4c + i * 4);
- UInt32 sid = Get32(p + 0x44);
- for (UInt32 s = 0; s < numSectorsForBat; s++)
- {
- RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, bat + i));
- i += numSidsInSec - 1;
- sid = bat[i];
- }
- numBatItems = i;
-
- if (!Fat.Allocate(numFatItems))
- return S_FALSE;
- UInt32 j = 0;
-
- for (i = 0; i < numFatItems; j++, i += numSidsInSec)
- {
- if (j >= numBatItems)
- return S_FALSE;
- RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], Fat + i));
- }
- }
-
- UInt32 numMatItems;
- {
- UInt32 numSectorsForMat = Get32(p + 0x40);
- numMatItems = (UInt32)numSectorsForMat << ssb2;
- if ((numMatItems >> ssb2) != numSectorsForMat)
- return S_FALSE;
- if (!Mat.Allocate(numMatItems))
- return S_FALSE;
- UInt32 i;
- UInt32 sid = Get32(p + 0x3C);
- for (i = 0; i < numMatItems; i += numSidsInSec)
- {
- RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, Mat + i));
- if (sid >= numFatItems)
- return S_FALSE;
- sid = Fat[sid];
- }
- if (sid != NFatID::kEndOfChain)
- return S_FALSE;
- }
-
- {
- UInt32 sid = Get32(p + 0x30);
- for (;;)
- {
- if (sid >= numFatItems)
- return S_FALSE;
- RINOK(ReadSector(inStream, sect, sectorSizeBits, sid));
- for (UInt32 i = 0; i < sectSize; i += 128)
- {
- CItem item;
- item.Parse(sect + i, mode64bit);
- Items.Add(item);
- }
- sid = Fat[sid];
- if (sid == NFatID::kEndOfChain)
- break;
- }
- }
-
- CItem root = Items[0];
-
- {
- UInt32 numSectorsInMiniStream;
- {
- UInt64 numSatSects64 = (root.Size + sectSize - 1) >> sectorSizeBits;
- if (numSatSects64 > NFatID::kMaxValue)
- return S_FALSE;
- numSectorsInMiniStream = (UInt32)numSatSects64;
- }
- NumSectorsInMiniStream = numSectorsInMiniStream;
- if (!MiniSids.Allocate(numSectorsInMiniStream))
- return S_FALSE;
- {
- UInt64 matSize64 = (root.Size + ((UInt64)1 << miniSectorSizeBits) - 1) >> miniSectorSizeBits;
- if (matSize64 > NFatID::kMaxValue)
- return S_FALSE;
- MatSize = (UInt32)matSize64;
- if (numMatItems < MatSize)
- return S_FALSE;
- }
-
- UInt32 sid = root.Sid;
- for (UInt32 i = 0; ; i++)
- {
- if (sid == NFatID::kEndOfChain)
- {
- if (i != numSectorsInMiniStream)
- return S_FALSE;
- break;
- }
- if (i >= numSectorsInMiniStream)
- return S_FALSE;
- MiniSids[i] = sid;
- if (sid >= numFatItems)
- return S_FALSE;
- sid = Fat[sid];
- }
- }
-
- RINOK(AddNode(-1, root.SonDid));
-
- unsigned numCabs = 0;
- for (int i = 0; i < Refs.Size(); i++)
- {
- const CItem &item = Items[Refs[i].Did];
- if (item.IsDir() || numCabs > 1)
- continue;
- bool isMsiName;
- UString msiName = ConvertName(item.Name, isMsiName);
- if (isMsiName && msiName.Right(4).CompareNoCase(L".cab") == 0)
- {
- numCabs++;
- MainSubfile = i;
- }
- }
- if (numCabs > 1)
- MainSubfile = -1;
-
- return S_OK;
-}
-
-}}
diff --git a/CPP/7zip/Archive/Com/ComIn.h b/CPP/7zip/Archive/Com/ComIn.h
deleted file mode 100755
index 429d3796..00000000
--- a/CPP/7zip/Archive/Com/ComIn.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// Archive/ComIn.h
-
-#ifndef __ARCHIVE_COM_IN_H
-#define __ARCHIVE_COM_IN_H
-
-#include "Common/MyString.h"
-#include "Common/Buffer.h"
-
-namespace NArchive {
-namespace NCom {
-
-struct CUInt32Buf
-{
- UInt32 *_buf;
-public:
- CUInt32Buf(): _buf(0) {}
- ~CUInt32Buf() { Free(); }
- void Free();
- bool Allocate(UInt32 numItems);
- operator UInt32 *() const { return _buf; };
-};
-
-namespace NFatID
-{
- const UInt32 kFree = 0xFFFFFFFF;
- const UInt32 kEndOfChain = 0xFFFFFFFE;
- const UInt32 kFatSector = 0xFFFFFFFD;
- const UInt32 kMatSector = 0xFFFFFFFC;
- const UInt32 kMaxValue = 0xFFFFFFFA;
-}
-
-namespace NItemType
-{
- const Byte kEmpty = 0;
- const Byte kStorage = 1;
- const Byte kStream = 2;
- const Byte kLockBytes = 3;
- const Byte kProperty = 4;
- const Byte kRootStorage = 5;
-}
-
-const UInt32 kNameSizeMax = 64;
-
-struct CItem
-{
- Byte Name[kNameSizeMax];
- // UInt16 NameSize;
- // UInt32 Flags;
- FILETIME CTime;
- FILETIME MTime;
- UInt64 Size;
- UInt32 LeftDid;
- UInt32 RightDid;
- UInt32 SonDid;
- UInt32 Sid;
- Byte Type;
-
- bool IsEmpty() const { return Type == NItemType::kEmpty; }
- bool IsDir() const { return Type == NItemType::kStorage || Type == NItemType::kRootStorage; }
-
- void Parse(const Byte *p, bool mode64bit);
-};
-
-struct CRef
-{
- int Parent;
- UInt32 Did;
-};
-
-class CDatabase
-{
- UInt32 NumSectorsInMiniStream;
- CUInt32Buf MiniSids;
-
- HRESULT AddNode(int parent, UInt32 did);
-public:
-
- CUInt32Buf Fat;
- UInt32 FatSize;
-
- CUInt32Buf Mat;
- UInt32 MatSize;
-
- CObjectVector<CItem> Items;
- CRecordVector<CRef> Refs;
-
- UInt32 LongStreamMinSize;
- int SectorSizeBits;
- int MiniSectorSizeBits;
-
- Int32 MainSubfile;
-
- void Clear();
- bool IsLargeStream(UInt64 size) const { return size >= LongStreamMinSize; }
- UString GetItemPath(UInt32 index) const;
-
- UInt64 GetItemPackSize(UInt64 size) const
- {
- UInt64 mask = ((UInt64)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1;
- return (size + mask) & ~mask;
- }
-
- bool GetMiniCluster(UInt32 sid, UInt64 &res) const
- {
- int subBits = SectorSizeBits - MiniSectorSizeBits;
- UInt32 fid = sid >> subBits;
- if (fid >= NumSectorsInMiniStream)
- return false;
- res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1));
- return true;
- }
-
- HRESULT Open(IInStream *inStream);
-};
-
-
-}}
-
-#endif
diff --git a/CPP/7zip/Archive/Com/ComRegister.cpp b/CPP/7zip/Archive/Com/ComRegister.cpp
deleted file mode 100755
index 6712b890..00000000
--- a/CPP/7zip/Archive/Com/ComRegister.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// ComRegister.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/RegisterArc.h"
-
-#include "ComHandler.h"
-static IInArchive *CreateArc() { return new NArchive::NCom::CHandler; }
-
-static CArcInfo g_ArcInfo =
- { L"Compound", L"msi msp doc xls ppt", 0, 0xE5, { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }, 8, false, CreateArc, 0 };
-
-REGISTER_ARC(Com)
diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp
new file mode 100644
index 00000000..fc686b94
--- /dev/null
+++ b/CPP/7zip/Archive/ComHandler.cpp
@@ -0,0 +1,875 @@
+// 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 UInt32 kSignatureSize = 8;
+static const Byte kSignature[kSignatureSize] = SIGNATURE;
+
+enum EType
+{
+ k_Type_Common,
+ k_Type_Msi,
+ k_Type_Msp,
+ k_Type_Doc,
+ k_Type_Ppt,
+ k_Type_Xls,
+};
+
+static const char *kExtensions[] =
+{
+ "compound"
+ , "msi"
+ , "msp"
+ , "doc"
+ , "ppt"
+ , "xls"
+};
+
+namespace NFatID
+{
+ static const UInt32 kFree = 0xFFFFFFFF;
+ static const UInt32 kEndOfChain = 0xFFFFFFFE;
+ static const UInt32 kFatSector = 0xFFFFFFFD;
+ static const UInt32 kMatSector = 0xFFFFFFFC;
+ static const UInt32 kMaxValue = 0xFFFFFFFA;
+}
+
+namespace NItemType
+{
+ static const Byte kEmpty = 0;
+ static const Byte kStorage = 1;
+ static const Byte kStream = 2;
+ static const Byte kLockBytes = 3;
+ static const Byte kProperty = 4;
+ static const Byte kRootStorage = 5;
+}
+
+static const UInt32 kNameSizeMax = 64;
+
+struct CItem
+{
+ Byte Name[kNameSizeMax];
+ // UInt16 NameSize;
+ // UInt32 Flags;
+ FILETIME CTime;
+ FILETIME MTime;
+ UInt64 Size;
+ UInt32 LeftDid;
+ UInt32 RightDid;
+ UInt32 SonDid;
+ UInt32 Sid;
+ Byte Type;
+
+ bool IsEmpty() const { return Type == NItemType::kEmpty; }
+ bool IsDir() const { return Type == NItemType::kStorage || Type == NItemType::kRootStorage; }
+
+ void Parse(const Byte *p, bool mode64bit);
+};
+
+struct CRef
+{
+ int Parent;
+ UInt32 Did;
+};
+
+class CDatabase
+{
+ UInt32 NumSectorsInMiniStream;
+ CObjArray<UInt32> MiniSids;
+
+ HRESULT AddNode(int parent, UInt32 did);
+public:
+
+ CObjArray<UInt32> Fat;
+ UInt32 FatSize;
+
+ CObjArray<UInt32> Mat;
+ UInt32 MatSize;
+
+ CObjectVector<CItem> Items;
+ CRecordVector<CRef> Refs;
+
+ UInt32 LongStreamMinSize;
+ unsigned SectorSizeBits;
+ unsigned MiniSectorSizeBits;
+
+ Int32 MainSubfile;
+
+ UInt64 PhySize;
+ 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, (UInt32)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 const char kCharOpenBracket = '[';
+static const char kCharCloseBracket = ']';
+
+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 += kCharOpenBracket;
+ wchar_t buf[32];
+ ConvertUInt32ToString(c, buf);
+ res += buf;
+ res += kCharCloseBracket;
+ }
+ else
+ res += c;
+ }
+ return res;
+}
+
+static char g_MsiChars[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._";
+
+static const wchar_t *kMsi_ID = L""; // L"{msi}";
+
+static const unsigned kMsiNumBits = 6;
+static const UInt32 kMsiNumChars = 1 << kMsiNumBits;
+static const UInt32 kMsiCharMask = kMsiNumChars - 1;
+static const UInt32 kMsiStartUnicodeChar = 0x3800;
+static const UInt32 kMsiUnicodeRange = kMsiNumChars * (kMsiNumChars + 1);
+
+static bool IsMsiName(const Byte *p)
+{
+ UInt32 c = Get16(p);
+ return
+ c >= kMsiStartUnicodeChar &&
+ c <= kMsiStartUnicodeChar + kMsiUnicodeRange;
+}
+
+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 &resultName)
+{
+ resultName.Empty();
+ for (unsigned i = 0; i < name.Len(); i++)
+ {
+ wchar_t c = name[i];
+ if (c < kMsiStartUnicodeChar || c > kMsiStartUnicodeChar + kMsiUnicodeRange)
+ return false;
+ if (i == 0)
+ resultName += kMsi_ID;
+ c -= kMsiStartUnicodeChar;
+
+ UInt32 c0 = c & kMsiCharMask;
+ UInt32 c1 = c >> kMsiNumBits;
+
+ if (c1 <= kMsiNumChars)
+ {
+ resultName += (wchar_t)g_MsiChars[c0];
+ if (c1 == kMsiNumChars)
+ break;
+ resultName += (wchar_t)g_MsiChars[c1];
+ }
+ else
+ resultName += L'!';
+ }
+ return true;
+}
+
+static UString ConvertName(const Byte *p, bool &isMsi)
+{
+ isMsi = false;
+ UString s;
+ for (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, kSignatureSize) != 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 > 28 ||
+ sectorSizeBits < 7 ||
+ miniSectorSizeBits > 28 ||
+ miniSectorSizeBits < 2 ||
+ miniSectorSizeBits > sectorSizeBits)
+ return S_FALSE;
+ UInt32 numSectorsForFAT = Get32(p + 0x2C); // SAT
+ LongStreamMinSize = Get32(p + 0x38);
+
+ UInt32 sectSize = (UInt32)1 << sectorSizeBits;
+
+ CByteBuffer sect(sectSize);
+
+ unsigned ssb2 = sectorSizeBits - 2;
+ UInt32 numSidsInSec = (UInt32)1 << ssb2;
+ UInt32 numFatItems = numSectorsForFAT << ssb2;
+ if ((numFatItems >> ssb2) != numSectorsForFAT)
+ return S_FALSE;
+ FatSize = numFatItems;
+
+ {
+ UInt32 numSectorsForBat = Get32(p + 0x48); // master sector allocation table
+ const UInt32 kNumHeaderBatItems = 109;
+ UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2);
+ if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat)
+ return S_FALSE;
+ CObjArray<UInt32> bat(numBatItems);
+ UInt32 i;
+ for (i = 0; i < kNumHeaderBatItems; i++)
+ bat[i] = Get32(p + 0x4c + i * 4);
+ UInt32 sid = Get32(p + 0x44);
+ for (UInt32 s = 0; s < numSectorsForBat; s++)
+ {
+ RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, bat + i));
+ i += numSidsInSec - 1;
+ sid = bat[i];
+ }
+ numBatItems = i;
+
+ Fat.Alloc(numFatItems);
+ UInt32 j = 0;
+
+ for (i = 0; i < numFatItems; j++, i += numSidsInSec)
+ {
+ if (j >= numBatItems)
+ return S_FALSE;
+ RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], Fat + i));
+ }
+ FatSize = numFatItems = i;
+ }
+
+ UInt32 numMatItems;
+ {
+ UInt32 numSectorsForMat = Get32(p + 0x40);
+ numMatItems = (UInt32)numSectorsForMat << ssb2;
+ if ((numMatItems >> ssb2) != numSectorsForMat)
+ return S_FALSE;
+ Mat.Alloc(numMatItems);
+ UInt32 i;
+ UInt32 sid = Get32(p + 0x3C); // short-sector table SID
+ for (i = 0; i < numMatItems; i += numSidsInSec)
+ {
+ RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, Mat + i));
+ if (sid >= numFatItems)
+ return S_FALSE;
+ sid = Fat[sid];
+ }
+ if (sid != NFatID::kEndOfChain)
+ return S_FALSE;
+ }
+
+ {
+ CByteBuffer used(numFatItems);
+ for (UInt32 i = 0; i < numFatItems; i++)
+ used[i] = 0;
+ UInt32 sid = Get32(p + 0x30); // directory stream SID
+ for (;;)
+ {
+ if (sid >= numFatItems)
+ return S_FALSE;
+ if (used[sid])
+ return S_FALSE;
+ used[sid] = 1;
+ RINOK(ReadSector(inStream, sect, sectorSizeBits, sid));
+ for (UInt32 i = 0; i < sectSize; i += 128)
+ {
+ CItem item;
+ item.Parse(sect + i, mode64bit);
+ Items.Add(item);
+ }
+ sid = Fat[sid];
+ if (sid == NFatID::kEndOfChain)
+ break;
+ }
+ }
+
+ const CItem &root = Items[0];
+
+ {
+ UInt32 numSectorsInMiniStream;
+ {
+ UInt64 numSatSects64 = (root.Size + sectSize - 1) >> sectorSizeBits;
+ if (numSatSects64 > NFatID::kMaxValue)
+ return S_FALSE;
+ numSectorsInMiniStream = (UInt32)numSatSects64;
+ }
+ NumSectorsInMiniStream = numSectorsInMiniStream;
+ MiniSids.Alloc(numSectorsInMiniStream);
+ {
+ UInt64 matSize64 = (root.Size + ((UInt64)1 << miniSectorSizeBits) - 1) >> miniSectorSizeBits;
+ if (matSize64 > NFatID::kMaxValue)
+ return S_FALSE;
+ MatSize = (UInt32)matSize64;
+ if (numMatItems < MatSize)
+ return S_FALSE;
+ }
+
+ UInt32 sid = root.Sid;
+ for (UInt32 i = 0; ; i++)
+ {
+ if (sid == NFatID::kEndOfChain)
+ {
+ if (i != numSectorsInMiniStream)
+ return S_FALSE;
+ break;
+ }
+ if (i >= numSectorsInMiniStream)
+ return S_FALSE;
+ MiniSids[i] = sid;
+ if (sid >= numFatItems)
+ return S_FALSE;
+ sid = Fat[sid];
+ }
+ }
+
+ RINOK(AddNode(-1, root.SonDid));
+
+ unsigned numCabs = 0;
+ FOR_VECTOR (i, Refs)
+ {
+ const CItem &item = Items[Refs[i].Did];
+ if (item.IsDir() || numCabs > 1)
+ continue;
+ bool isMsiName;
+ UString msiName = ConvertName(item.Name, isMsiName);
+ if (isMsiName && msiName.Len() >= 4 &&
+ MyStringCompareNoCase(msiName.RightPtr(4), L".cab") == 0)
+ {
+ 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<IInStream> _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[_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<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _db.Items[_db.Refs[index].Did];
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ totalPackSize += _db.GetItemPackSize(item.Size);
+ totalSize += item.Size;
+
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ Int32 res = NExtract::NOperationResult::kDataError;
+ CMyComPtr<ISequentialInStream> inStream;
+ HRESULT hres = GetStream(index, &inStream);
+ if (hres == S_FALSE)
+ res = NExtract::NOperationResult::kDataError;
+ else if (hres == E_NOTIMPL)
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ else
+ {
+ RINOK(hres);
+ if (inStream)
+ {
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ if (copyCoderSpec->TotalSize == item.Size)
+ res = NExtract::NOperationResult::kOK;
+ }
+ }
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _db.Refs.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = 0;
+ UInt32 itemIndex = _db.Refs[index].Did;
+ const CItem &item = _db.Items[itemIndex];
+ CClusterInStream *streamSpec = new CClusterInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->Stream = _stream;
+ streamSpec->StartOffset = 0;
+
+ 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
+}
+
+IMP_CreateArcIn
+
+static CArcInfo g_ArcInfo =
+ { "Compound", "msi msp doc xls ppt", 0, 0xE5,
+ kSignatureSize, SIGNATURE,
+ 0,
+ 0,
+ CreateArc };
+
+REGISTER_ARC(Com)
+
+}}
diff --git a/CPP/7zip/Archive/Common/CoderMixer.cpp b/CPP/7zip/Archive/Common/CoderMixer.cpp
index a19f0457..a19f0457 100755..100644
--- a/CPP/7zip/Archive/Common/CoderMixer.cpp
+++ b/CPP/7zip/Archive/Common/CoderMixer.cpp
diff --git a/CPP/7zip/Archive/Common/CoderMixer.h b/CPP/7zip/Archive/Common/CoderMixer.h
index 6379dd80..6379dd80 100755..100644
--- a/CPP/7zip/Archive/Common/CoderMixer.h
+++ b/CPP/7zip/Archive/Common/CoderMixer.h
diff --git a/CPP/7zip/Archive/Common/CoderMixer2.cpp b/CPP/7zip/Archive/Common/CoderMixer2.cpp
index 0b06a489..13019d1f 100755..100644
--- a/CPP/7zip/Archive/Common/CoderMixer2.cpp
+++ b/CPP/7zip/Archive/Common/CoderMixer2.cpp
@@ -11,16 +11,23 @@ CBindReverseConverter::CBindReverseConverter(const CBindInfo &srcBindInfo):
{
srcBindInfo.GetNumStreams(NumSrcInStreams, _numSrcOutStreams);
- UInt32 j;
+ UInt32 j;
+ _srcInToDestOutMap.ClearAndSetSize(NumSrcInStreams);
+ DestOutToSrcInMap.ClearAndSetSize(NumSrcInStreams);
+
for (j = 0; j < NumSrcInStreams; j++)
{
- _srcInToDestOutMap.Add(0);
- DestOutToSrcInMap.Add(0);
+ _srcInToDestOutMap[j] = 0;
+ DestOutToSrcInMap[j] = 0;
}
+
+ _srcOutToDestInMap.ClearAndSetSize(_numSrcOutStreams);
+ _destInToSrcOutMap.ClearAndSetSize(_numSrcOutStreams);
+
for (j = 0; j < _numSrcOutStreams; j++)
{
- _srcOutToDestInMap.Add(0);
- _destInToSrcOutMap.Add(0);
+ _srcOutToDestInMap[j] = 0;
+ _destInToSrcOutMap[j] = 0;
}
UInt32 destInOffset = 0;
@@ -53,66 +60,57 @@ CBindReverseConverter::CBindReverseConverter(const CBindInfo &srcBindInfo):
void CBindReverseConverter::CreateReverseBindInfo(CBindInfo &destBindInfo)
{
- destBindInfo.Coders.Clear();
- destBindInfo.BindPairs.Clear();
- destBindInfo.InStreams.Clear();
- destBindInfo.OutStreams.Clear();
+ destBindInfo.Coders.ClearAndReserve(_srcBindInfo.Coders.Size());
+ destBindInfo.BindPairs.ClearAndReserve(_srcBindInfo.BindPairs.Size());
+ destBindInfo.InStreams.ClearAndReserve(_srcBindInfo.OutStreams.Size());
+ destBindInfo.OutStreams.ClearAndReserve(_srcBindInfo.InStreams.Size());
- int i;
- for (i = _srcBindInfo.Coders.Size() - 1; i >= 0; i--)
+ unsigned i;
+ for (i = _srcBindInfo.Coders.Size(); i != 0;)
{
+ i--;
const CCoderStreamsInfo &srcCoderInfo = _srcBindInfo.Coders[i];
CCoderStreamsInfo destCoderInfo;
destCoderInfo.NumInStreams = srcCoderInfo.NumOutStreams;
destCoderInfo.NumOutStreams = srcCoderInfo.NumInStreams;
- destBindInfo.Coders.Add(destCoderInfo);
+ destBindInfo.Coders.AddInReserved(destCoderInfo);
}
- for (i = _srcBindInfo.BindPairs.Size() - 1; i >= 0; i--)
+ for (i = _srcBindInfo.BindPairs.Size(); i != 0;)
{
+ i--;
const CBindPair &srcBindPair = _srcBindInfo.BindPairs[i];
CBindPair destBindPair;
destBindPair.InIndex = _srcOutToDestInMap[srcBindPair.OutIndex];
destBindPair.OutIndex = _srcInToDestOutMap[srcBindPair.InIndex];
- destBindInfo.BindPairs.Add(destBindPair);
+ destBindInfo.BindPairs.AddInReserved(destBindPair);
}
for (i = 0; i < _srcBindInfo.InStreams.Size(); i++)
- destBindInfo.OutStreams.Add(_srcInToDestOutMap[_srcBindInfo.InStreams[i]]);
+ destBindInfo.OutStreams.AddInReserved(_srcInToDestOutMap[_srcBindInfo.InStreams[i]]);
for (i = 0; i < _srcBindInfo.OutStreams.Size(); i++)
- destBindInfo.InStreams.Add(_srcOutToDestInMap[_srcBindInfo.OutStreams[i]]);
-}
-
-CCoderInfo2::CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams):
- NumInStreams(numInStreams),
- NumOutStreams(numOutStreams)
-{
- InSizes.Reserve(NumInStreams);
- InSizePointers.Reserve(NumInStreams);
- OutSizes.Reserve(NumOutStreams);
- OutSizePointers.Reserve(NumOutStreams);
+ destBindInfo.InStreams.AddInReserved(_srcOutToDestInMap[_srcBindInfo.OutStreams[i]]);
}
-static void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes,
+void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes,
CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems)
{
- sizes.Clear();
- sizePointers.Clear();
+ sizes.ClearAndSetSize(numItems);
+ sizePointers.ClearAndSetSize(numItems);
for(UInt32 i = 0; i < numItems; i++)
{
- if (srcSizes == 0 || srcSizes[i] == NULL)
+ if (!srcSizes || !srcSizes[i])
{
- sizes.Add(0);
- sizePointers.Add(NULL);
+ sizes[i] = 0;
+ sizePointers[i] = NULL;
}
else
{
- sizes.Add(*srcSizes[i]);
- sizePointers.Add(&sizes.Back());
+ sizes[i] = *(srcSizes[i]);
+ sizePointers[i] = &sizes[i];
}
}
}
-void CCoderInfo2::SetCoderInfo(const UInt64 **inSizes,
- const UInt64 **outSizes)
+void CCoderInfo2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes)
{
SetSizes(inSizes, InSizes, InSizePointers, NumInStreams);
SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams);
diff --git a/CPP/7zip/Archive/Common/CoderMixer2.h b/CPP/7zip/Archive/Common/CoderMixer2.h
index a03722d6..50e7077a 100755..100644
--- a/CPP/7zip/Archive/Common/CoderMixer2.h
+++ b/CPP/7zip/Archive/Common/CoderMixer2.h
@@ -3,9 +3,9 @@
#ifndef __CODER_MIXER2_H
#define __CODER_MIXER2_H
-#include "../../../Common/MyVector.h"
-#include "../../../Common/Types.h"
#include "../../../Common/MyCom.h"
+#include "../../../Common/MyVector.h"
+
#include "../../ICoder.h"
namespace NCoderMixer {
@@ -52,7 +52,7 @@ struct CBindInfo
{
numInStreams = 0;
numOutStreams = 0;
- for (int i = 0; i < Coders.Size(); i++)
+ FOR_VECTOR (i, Coders)
{
const CCoderStreamsInfo &coderStreamsInfo = Coders[i];
numInStreams += coderStreamsInfo.NumInStreams;
@@ -62,14 +62,14 @@ struct CBindInfo
int FindBinderForInStream(UInt32 inStream) const
{
- for (int i = 0; i < BindPairs.Size(); i++)
+ FOR_VECTOR (i, BindPairs)
if (BindPairs[i].InIndex == inStream)
return i;
return -1;
}
int FindBinderForOutStream(UInt32 outStream) const
{
- for (int i = 0; i < BindPairs.Size(); i++)
+ FOR_VECTOR (i, BindPairs)
if (BindPairs[i].OutIndex == outStream)
return i;
return -1;
@@ -139,6 +139,9 @@ public:
void CreateReverseBindInfo(NCoderMixer::CBindInfo &destBindInfo);
};
+void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes,
+ CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems);
+
struct CCoderInfo2
{
CMyComPtr<ICompressCoder> Coder;
@@ -151,7 +154,9 @@ struct CCoderInfo2
CRecordVector<const UInt64 *> InSizePointers;
CRecordVector<const UInt64 *> OutSizePointers;
- CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams);
+ CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams):
+ NumInStreams(numInStreams),
+ NumOutStreams(numOutStreams) {}
void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes);
HRESULT QueryInterface(REFGUID iid, void** pp) const
@@ -170,5 +175,5 @@ public:
};
}
-#endif
+#endif
diff --git a/CPP/7zip/Archive/Common/CoderMixer2MT.cpp b/CPP/7zip/Archive/Common/CoderMixer2MT.cpp
index 87686e85..5288fbc1 100755..100644
--- a/CPP/7zip/Archive/Common/CoderMixer2MT.cpp
+++ b/CPP/7zip/Archive/Common/CoderMixer2MT.cpp
@@ -9,30 +9,28 @@ namespace NCoderMixer {
CCoder2::CCoder2(UInt32 numInStreams, UInt32 numOutStreams):
CCoderInfo2(numInStreams, numOutStreams)
{
- InStreams.Reserve(NumInStreams);
- InStreamPointers.Reserve(NumInStreams);
- OutStreams.Reserve(NumOutStreams);
- OutStreamPointers.Reserve(NumOutStreams);
+ InStreams.ClearAndReserve(NumInStreams);
+ OutStreams.ClearAndReserve(NumOutStreams);
}
void CCoder2::Execute() { Code(NULL); }
void CCoder2::Code(ICompressProgressInfo *progress)
{
- InStreamPointers.Clear();
- OutStreamPointers.Clear();
+ InStreamPointers.ClearAndReserve(NumInStreams);
+ OutStreamPointers.ClearAndReserve(NumOutStreams);
UInt32 i;
for (i = 0; i < NumInStreams; i++)
{
- if (InSizePointers[i] != NULL)
+ if (InSizePointers[i])
InSizePointers[i] = &InSizes[i];
- InStreamPointers.Add((ISequentialInStream *)InStreams[i]);
+ InStreamPointers.AddInReserved((ISequentialInStream *)InStreams[i]);
}
for (i = 0; i < NumOutStreams; i++)
{
- if (OutSizePointers[i] != NULL)
+ if (OutSizePointers[i])
OutSizePointers[i] = &OutSizes[i];
- OutStreamPointers.Add((ISequentialOutStream *)OutStreams[i]);
+ OutStreamPointers.AddInReserved((ISequentialOutStream *)OutStreams[i]);
}
if (Coder)
Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0],
@@ -41,7 +39,7 @@ void CCoder2::Code(ICompressProgressInfo *progress)
Result = Coder2->Code(&InStreamPointers.Front(), &InSizePointers.Front(), NumInStreams,
&OutStreamPointers.Front(), &OutSizePointers.Front(), NumOutStreams, progress);
{
- int i;
+ unsigned i;
for (i = 0; i < InStreams.Size(); i++)
InStreams[i].Release();
for (i = 0; i < OutStreams.Size(); i++)
@@ -49,32 +47,13 @@ void CCoder2::Code(ICompressProgressInfo *progress)
}
}
-static void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes,
- CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems)
-{
- sizes.Clear();
- sizePointers.Clear();
- for (UInt32 i = 0; i < numItems; i++)
- {
- if (srcSizes == 0 || srcSizes[i] == NULL)
- {
- sizes.Add(0);
- sizePointers.Add(NULL);
- }
- else
- {
- sizes.Add(*srcSizes[i]);
- sizePointers.Add(&sizes.Back());
- }
- }
-}
-
-
+/*
void CCoder2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes)
{
SetSizes(inSizes, InSizes, InSizePointers, NumInStreams);
SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams);
}
+*/
//////////////////////////////////////
// CCoderMixer2MT
@@ -83,10 +62,9 @@ HRESULT CCoderMixer2MT::SetBindInfo(const CBindInfo &bindInfo)
{
_bindInfo = bindInfo;
_streamBinders.Clear();
- for (int i = 0; i < _bindInfo.BindPairs.Size(); i++)
+ FOR_VECTOR (i, _bindInfo.BindPairs)
{
- _streamBinders.Add(CStreamBinder());
- RINOK(_streamBinders.Back().CreateEvents());
+ RINOK(_streamBinders.AddNew().CreateEvents());
}
return S_OK;
}
@@ -113,7 +91,7 @@ void CCoderMixer2MT::AddCoder2(ICompressCoder2 *coder)
void CCoderMixer2MT::ReInit()
{
- for (int i = 0; i < _streamBinders.Size(); i++)
+ FOR_VECTOR (i, _streamBinders)
_streamBinders[i].ReInit();
}
@@ -124,7 +102,7 @@ HRESULT CCoderMixer2MT::Init(ISequentialInStream **inStreams, ISequentialOutStre
if (_coders.Size() != _bindInfo.Coders.Size())
throw 0;
*/
- int i;
+ unsigned i;
for (i = 0; i < _coders.Size(); i++)
{
CCoder2 &coderInfo = _coders[i];
@@ -179,7 +157,7 @@ HRESULT CCoderMixer2MT::Init(ISequentialInStream **inStreams, ISequentialOutStre
HRESULT CCoderMixer2MT::ReturnIfError(HRESULT code)
{
- for (int i = 0; i < _coders.Size(); i++)
+ FOR_VECTOR (i, _coders)
if (_coders[i].Result == code)
return code;
return S_OK;
@@ -199,7 +177,7 @@ STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams,
Init(inStreams, outStreams);
- int i;
+ unsigned i;
for (i = 0; i < _coders.Size(); i++)
if (i != _progressCoderIndex)
{
diff --git a/CPP/7zip/Archive/Common/CoderMixer2MT.h b/CPP/7zip/Archive/Common/CoderMixer2MT.h
index 81bb3f0b..ba475cec 100755..100644
--- a/CPP/7zip/Archive/Common/CoderMixer2MT.h
+++ b/CPP/7zip/Archive/Common/CoderMixer2MT.h
@@ -12,15 +12,17 @@ namespace NCoderMixer {
struct CCoder2: public CCoderInfo2, public CVirtThread
{
+ CRecordVector<ISequentialInStream*> InStreamPointers;
+ CRecordVector<ISequentialOutStream*> OutStreamPointers;
+
+public:
HRESULT Result;
CObjectVector< CMyComPtr<ISequentialInStream> > InStreams;
CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams;
- CRecordVector<ISequentialInStream*> InStreamPointers;
- CRecordVector<ISequentialOutStream*> OutStreamPointers;
CCoder2(UInt32 numInStreams, UInt32 numOutStreams);
~CCoder2() { CVirtThread::WaitThreadFinish(); }
- void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes);
+ // void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes);
virtual void Execute();
void Code(ICompressProgressInfo *progress);
};
@@ -48,7 +50,7 @@ class CCoderMixer2MT:
{
CBindInfo _bindInfo;
CObjectVector<CStreamBinder> _streamBinders;
- int _progressCoderIndex;
+ unsigned _progressCoderIndex;
void AddCoderCommon();
HRESULT Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams);
@@ -68,7 +70,7 @@ public:
HRESULT SetBindInfo(const CBindInfo &bindInfo);
void AddCoder(ICompressCoder *coder);
void AddCoder2(ICompressCoder2 *coder);
- void SetProgressCoderIndex(int coderIndex) { _progressCoderIndex = coderIndex; }
+ void SetProgressCoderIndex(unsigned coderIndex) { _progressCoderIndex = coderIndex; }
void ReInit();
void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes)
diff --git a/CPP/7zip/Archive/Common/CoderMixer2ST.cpp b/CPP/7zip/Archive/Common/CoderMixer2ST.cpp
index a21ca0c0..a94ba115 100755..100644
--- a/CPP/7zip/Archive/Common/CoderMixer2ST.cpp
+++ b/CPP/7zip/Archive/Common/CoderMixer2ST.cpp
@@ -47,7 +47,7 @@ HRESULT CCoderMixer2ST::GetInStream(
{
seqInStream = inStreams[i];
*inStreamRes = seqInStream.Detach();
- return S_OK;
+ return S_OK;
}
int binderIndex = _bindInfo.FindBinderForInStream(streamIndex);
if (binderIndex < 0)
@@ -96,7 +96,7 @@ HRESULT CCoderMixer2ST::GetOutStream(
{
seqOutStream = outStreams[i];
*outStreamRes = seqOutStream.Detach();
- return S_OK;
+ return S_OK;
}
int binderIndex = _bindInfo.FindBinderForOutStream(streamIndex);
if (binderIndex < 0)
diff --git a/CPP/7zip/Archive/Common/CoderMixer2ST.h b/CPP/7zip/Archive/Common/CoderMixer2ST.h
index d35655ba..d35655ba 100755..100644
--- a/CPP/7zip/Archive/Common/CoderMixer2ST.h
+++ b/CPP/7zip/Archive/Common/CoderMixer2ST.h
diff --git a/CPP/7zip/Archive/Common/CoderMixerMT.cpp b/CPP/7zip/Archive/Common/CoderMixerMT.cpp
index 96ea76a3..96ea76a3 100755..100644
--- a/CPP/7zip/Archive/Common/CoderMixerMT.cpp
+++ b/CPP/7zip/Archive/Common/CoderMixerMT.cpp
diff --git a/CPP/7zip/Archive/Common/CoderMixerMT.h b/CPP/7zip/Archive/Common/CoderMixerMT.h
index 9491a965..9491a965 100755..100644
--- a/CPP/7zip/Archive/Common/CoderMixerMT.h
+++ b/CPP/7zip/Archive/Common/CoderMixerMT.h
diff --git a/CPP/7zip/Archive/Common/CrossThreadProgress.cpp b/CPP/7zip/Archive/Common/CrossThreadProgress.cpp
index a974b54c..a974b54c 100755..100644
--- a/CPP/7zip/Archive/Common/CrossThreadProgress.cpp
+++ b/CPP/7zip/Archive/Common/CrossThreadProgress.cpp
diff --git a/CPP/7zip/Archive/Common/CrossThreadProgress.h b/CPP/7zip/Archive/Common/CrossThreadProgress.h
index 7e0b1053..7e0b1053 100755..100644
--- a/CPP/7zip/Archive/Common/CrossThreadProgress.h
+++ b/CPP/7zip/Archive/Common/CrossThreadProgress.h
diff --git a/CPP/7zip/Archive/Common/DummyOutStream.cpp b/CPP/7zip/Archive/Common/DummyOutStream.cpp
index 54bcfec1..7c4f5487 100755..100644
--- a/CPP/7zip/Archive/Common/DummyOutStream.cpp
+++ b/CPP/7zip/Archive/Common/DummyOutStream.cpp
@@ -4,19 +4,14 @@
#include "DummyOutStream.h"
-STDMETHODIMP CDummyOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+STDMETHODIMP CDummyOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
{
- UInt32 realProcessedSize;
- HRESULT result;
- if(!_stream)
- {
- realProcessedSize = size;
- result = S_OK;
- }
- else
- result = _stream->Write(data, size, &realProcessedSize);
+ UInt32 realProcessedSize = size;
+ HRESULT res = S_OK;
+ if (_stream)
+ res = _stream->Write(data, size, &realProcessedSize);
_size += realProcessedSize;
- if(processedSize != NULL)
+ if (processedSize)
*processedSize = realProcessedSize;
- return result;
+ return res;
}
diff --git a/CPP/7zip/Archive/Common/DummyOutStream.h b/CPP/7zip/Archive/Common/DummyOutStream.h
index 13d5b62c..b5a51fc0 100755..100644
--- a/CPP/7zip/Archive/Common/DummyOutStream.h
+++ b/CPP/7zip/Archive/Common/DummyOutStream.h
@@ -1,10 +1,11 @@
// DummyOutStream.h
-#ifndef __DUMMYOUTSTREAM_H
-#define __DUMMYOUTSTREAM_H
+#ifndef __DUMMY_OUT_STREAM_H
+#define __DUMMY_OUT_STREAM_H
+
+#include "../../../Common/MyCom.h"
#include "../../IStream.h"
-#include "Common/MyCom.h"
class CDummyOutStream:
public ISequentialOutStream,
diff --git a/CPP/7zip/Archive/Common/FindSignature.cpp b/CPP/7zip/Archive/Common/FindSignature.cpp
index 15aa6cea..e9a0f032 100755..100644
--- a/CPP/7zip/Archive/Common/FindSignature.cpp
+++ b/CPP/7zip/Archive/Common/FindSignature.cpp
@@ -2,27 +2,25 @@
#include "StdAfx.h"
-#include "Common/Buffer.h"
-
-#include "FindSignature.h"
+#include "../../../Common/MyBuffer.h"
#include "../../Common/StreamUtils.h"
+#include "FindSignature.h"
+
HRESULT FindSignatureInStream(ISequentialInStream *stream,
const Byte *signature, unsigned signatureSize,
const UInt64 *limit, UInt64 &resPos)
{
resPos = 0;
- CByteBuffer byteBuffer2;
- byteBuffer2.SetCapacity(signatureSize);
+ 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;
- byteBuffer.SetCapacity(kBufferSize);
+ CByteBuffer byteBuffer(kBufferSize);
Byte *buffer = byteBuffer;
UInt32 numPrevBytes = signatureSize - 1;
memcpy(buffer, (const Byte *)byteBuffer2 + 1, numPrevBytes);
diff --git a/CPP/7zip/Archive/Common/FindSignature.h b/CPP/7zip/Archive/Common/FindSignature.h
index e15af573..e15af573 100755..100644
--- a/CPP/7zip/Archive/Common/FindSignature.h
+++ b/CPP/7zip/Archive/Common/FindSignature.h
diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp
index 7e6f4602..18ad5580 100755..100644
--- a/CPP/7zip/Archive/Common/HandlerOut.cpp
+++ b/CPP/7zip/Archive/Common/HandlerOut.cpp
@@ -27,7 +27,7 @@ void CMultiMethodProps::SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo
)
{
UInt32 level = _level;
- if (level != (UInt32)(UInt32)-1)
+ if (level != (UInt32)(Int32)-1)
SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level);
#ifndef _7ZIP_ST
SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
@@ -40,7 +40,7 @@ void CMultiMethodProps::Init()
_numProcessors = _numThreads = NSystem::GetNumberOfProcessors();
#endif
- _level = (UInt32)(UInt32)-1;
+ _level = (UInt32)(Int32)-1;
_autoFilter = true;
_crcSize = 4;
_filterMethod.Clear();
@@ -50,18 +50,18 @@ void CMultiMethodProps::Init()
HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
{
UString name = nameSpec;
- name.MakeUpper();
+ name.MakeLower_Ascii();
if (name.IsEmpty())
return E_INVALIDARG;
- if (name[0] == 'X')
+ if (name[0] == 'x')
{
name.Delete(0);
_level = 9;
return ParsePropToUInt32(name, value, _level);
}
- if (name == L"CRC")
+ if (name == L"crc")
{
name.Delete(0, 3);
_crcSize = 4;
@@ -70,17 +70,17 @@ HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIAN
UInt32 number;
int index = ParseStringToUInt32(name, number);
- UString realName = name.Mid(index);
+ UString realName = name.Ptr(index);
if (index == 0)
{
- if (name.Left(2).CompareNoCase(L"MT") == 0)
+ if (name.IsPrefixedBy(L"mt"))
{
#ifndef _7ZIP_ST
- RINOK(ParseMtProp(name.Mid(2), value, _numProcessors, _numThreads));
+ RINOK(ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads));
#endif
return S_OK;
}
- if (name.CompareNoCase(L"F") == 0)
+ if (name.IsEqualTo("f"))
{
HRESULT res = PROPVARIANT_to_bool(value, _autoFilter);
if (res == S_OK)
@@ -105,35 +105,35 @@ void CSingleMethodProps::Init()
_numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors();
AddNumThreadsProp(_numThreads);
#endif
- _level = (UInt32)(UInt32)-1;
+ _level = (UInt32)(Int32)-1;
}
-HRESULT CSingleMethodProps::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+HRESULT CSingleMethodProps::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
{
Init();
- for (int i = 0; i < numProps; i++)
+ for (UInt32 i = 0; i < numProps; i++)
{
UString name = names[i];
- name.MakeUpper();
+ name.MakeLower_Ascii();
if (name.IsEmpty())
return E_INVALIDARG;
const PROPVARIANT &value = values[i];
- if (name[0] == L'X')
+ if (name[0] == L'x')
{
UInt32 a = 9;
- RINOK(ParsePropToUInt32(name.Mid(1), value, a));
+ RINOK(ParsePropToUInt32(name.Ptr(1), value, a));
_level = a;
AddLevelProp(a);
}
- else if (name.Left(2).CompareNoCase(L"MT") == 0)
+ else if (name.IsPrefixedBy(L"mt"))
{
#ifndef _7ZIP_ST
- RINOK(ParseMtProp(name.Mid(2), value, _numProcessors, _numThreads));
+ RINOK(ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads));
AddNumThreadsProp(_numThreads);
#endif
}
else
- return ParseParamsFromPROPVARIANT(name, value);
+ return ParseMethodFromPROPVARIANT(names[i], value);
}
return S_OK;
}
diff --git a/CPP/7zip/Archive/Common/HandlerOut.h b/CPP/7zip/Archive/Common/HandlerOut.h
index d3c9a237..40a4a698 100755..100644
--- a/CPP/7zip/Archive/Common/HandlerOut.h
+++ b/CPP/7zip/Archive/Common/HandlerOut.h
@@ -27,16 +27,16 @@ public:
#endif
);
- int GetNumEmptyMethods() const
+ unsigned GetNumEmptyMethods() const
{
- int i;
+ unsigned i;
for (i = 0; i < _methods.Size(); i++)
if (!_methods[i].IsEmpty())
break;
return i;
}
- int GetLevel() const { return _level == (UInt32)(UInt32)-1 ? 5 : (int)_level; }
+ int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; }
void Init();
@@ -44,20 +44,20 @@ public:
HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
};
-class CSingleMethodProps: public CMethodProps
+class CSingleMethodProps: public COneMethodInfo
{
UInt32 _level;
- void Init();
public:
#ifndef _7ZIP_ST
UInt32 _numThreads;
UInt32 _numProcessors;
#endif
+ void Init();
CSingleMethodProps() { Init(); }
- int GetLevel() const { return _level == (UInt32)(UInt32)-1 ? 5 : (int)_level; }
- HRESULT SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
+ int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; }
+ HRESULT SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps);
};
}
diff --git a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
index 569a56f3..3f4dd3b8 100755..100644
--- a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
+++ b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
@@ -6,29 +6,33 @@
STDMETHODIMP CSequentialInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)
{
- UInt32 realProcessedSize;
- HRESULT result = _stream->Read(data, size, &realProcessedSize);
- _size += realProcessedSize;
- if (size > 0 && realProcessedSize == 0)
+ UInt32 realProcessed = 0;
+ HRESULT result = S_OK;
+ if (_stream)
+ _stream->Read(data, size, &realProcessed);
+ _size += realProcessed;
+ if (size > 0 && realProcessed == 0)
_wasFinished = true;
- _crc = CrcUpdate(_crc, data, realProcessedSize);
- if(processedSize != NULL)
- *processedSize = realProcessedSize;
+ _crc = CrcUpdate(_crc, data, realProcessed);
+ if (processedSize)
+ *processedSize = realProcessed;
return result;
}
STDMETHODIMP CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)
{
- UInt32 realProcessedSize;
- HRESULT result = _stream->Read(data, size, &realProcessedSize);
+ UInt32 realProcessed = 0;
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Read(data, size, &realProcessed);
+ _size += realProcessed;
/*
- if (size > 0 && realProcessedSize == 0)
+ if (size > 0 && realProcessed == 0)
_wasFinished = true;
*/
- _size += realProcessedSize;
- _crc = CrcUpdate(_crc, data, realProcessedSize);
- if(processedSize != NULL)
- *processedSize = realProcessedSize;
+ _crc = CrcUpdate(_crc, data, realProcessed);
+ if (processedSize)
+ *processedSize = realProcessed;
return result;
}
diff --git a/CPP/7zip/Archive/Common/InStreamWithCRC.h b/CPP/7zip/Archive/Common/InStreamWithCRC.h
index 31b761e4..31b761e4 100755..100644
--- a/CPP/7zip/Archive/Common/InStreamWithCRC.h
+++ b/CPP/7zip/Archive/Common/InStreamWithCRC.h
diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/CPP/7zip/Archive/Common/ItemNameUtils.cpp
index cc476fad..7cd3037b 100755..100644
--- a/CPP/7zip/Archive/Common/ItemNameUtils.cpp
+++ b/CPP/7zip/Archive/Common/ItemNameUtils.cpp
@@ -2,8 +2,6 @@
#include "StdAfx.h"
-#include "../../../../C/Types.h"
-
#include "ItemNameUtils.h"
namespace NArchive {
@@ -12,6 +10,21 @@ namespace NItemName {
static const wchar_t kOSDirDelimiter = WCHAR_PATH_SEPARATOR;
static const wchar_t kDirDelimiter = L'/';
+void ReplaceToOsPathSeparator(wchar_t *s)
+{
+ #ifdef _WIN32
+ for (;;)
+ {
+ wchar_t c = *s;
+ if (c == 0)
+ break;
+ if (c == kDirDelimiter)
+ *s = kOSDirDelimiter;
+ s++;
+ }
+ #endif
+}
+
UString MakeLegalName(const UString &name)
{
UString zipName = name;
@@ -36,15 +49,29 @@ UString GetOSName2(const UString &name)
return newName;
}
-bool HasTailSlash(const AString &name, UINT codePage)
+void ConvertToOSName2(UString &name)
+{
+ if (!name.IsEmpty())
+ {
+ name.Replace(kDirDelimiter, kOSDirDelimiter);
+ if (name.Back() == kOSDirDelimiter)
+ name.DeleteBack();
+ }
+}
+
+bool HasTailSlash(const AString &name, UINT
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ codePage
+ #endif
+ )
{
if (name.IsEmpty())
return false;
LPCSTR prev =
#if defined(_WIN32) && !defined(UNDER_CE)
- CharPrevExA((WORD)codePage, name, &name[name.Length()], 0);
+ CharPrevExA((WORD)codePage, name, &name[name.Len()], 0);
#else
- (LPCSTR)(name) + (name.Length() - 1);
+ (LPCSTR)(name) + (name.Len() - 1);
#endif
return (*prev == '/');
}
diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.h b/CPP/7zip/Archive/Common/ItemNameUtils.h
index 5eafacb1..d0dc76a4 100755..100644
--- a/CPP/7zip/Archive/Common/ItemNameUtils.h
+++ b/CPP/7zip/Archive/Common/ItemNameUtils.h
@@ -1,16 +1,19 @@
// Archive/Common/ItemNameUtils.h
-#ifndef __ARCHIVE_ITEMNAMEUTILS_H
-#define __ARCHIVE_ITEMNAMEUTILS_H
+#ifndef __ARCHIVE_ITEM_NAME_UTILS_H
+#define __ARCHIVE_ITEM_NAME_UTILS_H
#include "../../../Common/MyString.h"
namespace NArchive {
namespace NItemName {
+ void ReplaceToOsPathSeparator(wchar_t *s);
+
UString MakeLegalName(const UString &name);
UString GetOSName(const UString &name);
UString GetOSName2(const UString &name);
+ void ConvertToOSName2(UString &name);
bool HasTailSlash(const AString &name, UINT codePage);
#ifdef _WIN32
diff --git a/CPP/7zip/Archive/Common/MultiStream.cpp b/CPP/7zip/Archive/Common/MultiStream.cpp
index 04d11caf..5bf0bef9 100755..100644
--- a/CPP/7zip/Archive/Common/MultiStream.cpp
+++ b/CPP/7zip/Archive/Common/MultiStream.cpp
@@ -11,10 +11,10 @@ STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize)
if (size == 0)
return S_OK;
if (_pos >= _totalLength)
- return (_pos == _totalLength) ? S_OK : E_FAIL;
+ return S_OK;
{
- int left = 0, mid = _streamIndex, right = Streams.Size();
+ unsigned left = 0, mid = _streamIndex, right = Streams.Size();
for (;;)
{
CSubStreamInfo &m = Streams[mid];
@@ -51,15 +51,18 @@ STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize)
STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
{
- switch(seekOrigin)
+ switch (seekOrigin)
{
- case STREAM_SEEK_SET: _pos = offset; break;
- case STREAM_SEEK_CUR: _pos = _pos + offset; break;
- case STREAM_SEEK_END: _pos = _totalLength + offset; break;
+ 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 (newPosition != 0)
- *newPosition = _pos;
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _pos = offset;
+ if (newPosition)
+ *newPosition = offset;
return S_OK;
}
@@ -69,7 +72,7 @@ class COutVolumeStream:
public ISequentialOutStream,
public CMyUnknownImp
{
- int _volIndex;
+ unsigned _volIndex;
UInt64 _volSize;
UInt64 _curPos;
CMyComPtr<ISequentialOutStream> _volumeStream;
@@ -169,22 +172,20 @@ STDMETHODIMP COutMultiStream::Write(const void *data, UInt32 size, UInt32 *proce
STDMETHODIMP COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
{
- if(seekOrigin >= 3)
- return STG_E_INVALIDFUNCTION;
- switch(seekOrigin)
+ switch (seekOrigin)
{
- case STREAM_SEEK_SET:
- _absPos = offset;
- break;
- case STREAM_SEEK_CUR:
- _absPos += offset;
- break;
- case STREAM_SEEK_END:
- _absPos = _length + offset;
- break;
+ 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 3fceb7cc..2a1a4a43 100755..100644
--- a/CPP/7zip/Archive/Common/MultiStream.h
+++ b/CPP/7zip/Archive/Common/MultiStream.h
@@ -14,7 +14,7 @@ class CMultiStream:
{
UInt64 _pos;
UInt64 _totalLength;
- int _streamIndex;
+ unsigned _streamIndex;
public:
struct CSubStreamInfo
{
@@ -28,7 +28,7 @@ public:
HRESULT Init()
{
UInt64 total = 0;
- for (int i = 0; i < Streams.Size(); i++)
+ FOR_VECTOR (i, Streams)
{
CSubStreamInfo &s = Streams[i];
s.GlobalOffset = total;
@@ -52,7 +52,7 @@ class COutMultiStream:
public IOutStream,
public CMyUnknownImp
{
- int _streamIndex; // required stream
+ unsigned _streamIndex; // required stream
UInt64 _offsetPos; // offset from start of _streamIndex index
UInt64 _absPos;
UInt64 _length;
diff --git a/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp b/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
index f955c225..f955c225 100755..100644
--- a/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
+++ b/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
diff --git a/CPP/7zip/Archive/Common/OutStreamWithCRC.h b/CPP/7zip/Archive/Common/OutStreamWithCRC.h
index 115b442a..09b899bb 100755..100644
--- a/CPP/7zip/Archive/Common/OutStreamWithCRC.h
+++ b/CPP/7zip/Archive/Common/OutStreamWithCRC.h
@@ -28,6 +28,7 @@ public:
_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); }
diff --git a/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
index 0526c1b1..0526c1b1 100755..100644
--- a/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
+++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
diff --git a/CPP/7zip/Archive/Common/OutStreamWithSha1.h b/CPP/7zip/Archive/Common/OutStreamWithSha1.h
index 3bbfbbe1..3bbfbbe1 100755..100644
--- a/CPP/7zip/Archive/Common/OutStreamWithSha1.h
+++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.h
diff --git a/CPP/7zip/Archive/Common/ParseProperties.cpp b/CPP/7zip/Archive/Common/ParseProperties.cpp
index 63e4f3ef..63e4f3ef 100755..100644
--- a/CPP/7zip/Archive/Common/ParseProperties.cpp
+++ b/CPP/7zip/Archive/Common/ParseProperties.cpp
diff --git a/CPP/7zip/Archive/Common/ParseProperties.h b/CPP/7zip/Archive/Common/ParseProperties.h
index 1038a8c0..1038a8c0 100755..100644
--- a/CPP/7zip/Archive/Common/ParseProperties.h
+++ b/CPP/7zip/Archive/Common/ParseProperties.h
diff --git a/CPP/7zip/Archive/Common/StdAfx.h b/CPP/7zip/Archive/Common/StdAfx.h
index 2e4be10b..2854ff3e 100755..100644
--- a/CPP/7zip/Archive/Common/StdAfx.h
+++ b/CPP/7zip/Archive/Common/StdAfx.h
@@ -3,7 +3,6 @@
#ifndef __STDAFX_H
#define __STDAFX_H
-#include "../../../Common/MyWindows.h"
-#include "../../../Common/NewHandler.h"
+#include "../../../Common/Common.h"
#endif
diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp
index 0f32ef66..9c1271c4 100755..100644
--- a/CPP/7zip/Archive/CpioHandler.cpp
+++ b/CPP/7zip/Archive/CpioHandler.cpp
@@ -2,12 +2,15 @@
#include "StdAfx.h"
-#include "Common/ComTry.h"
-#include "Common/StringConvert.h"
-#include "Common/StringToInt.h"
+#include "../../../C/CpuArch.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
+#include "../../Common/ComTry.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"
@@ -18,24 +21,30 @@
#include "Common/ItemNameUtils.h"
+using namespace NWindows;
+
namespace NArchive {
namespace NCpio {
-namespace NFileHeader
-{
- namespace NMagic
- {
- const char *kMagic1 = "070701";
- const char *kMagic2 = "070702";
- const char *kMagic3 = "070707";
- const char *kEndName = "TRAILER!!!";
+static const Byte kMagicBin0 = 0xC7;
+static const Byte kMagicBin1 = 0x71;
- const Byte kMagicForRecord2[2] = { 0xC7, 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 *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;
- const UInt32 kRecord2Size = 26;
/*
- struct CRecord2
+ struct CBinRecord
{
unsigned short c_magic;
short c_dev;
@@ -49,13 +58,10 @@ namespace NFileHeader
unsigned short c_namesize;
unsigned short c_filesizes[2];
};
- */
-
- const UInt32 kRecordSize = 110;
- /*
- struct CRecord
+
+ struct CHexRecord
{
- char Magic[6]; // "070701" for "new" portable format, "070702" for CRC format
+ char Magic[6];
char inode[8];
char Mode[8];
char UID[8];
@@ -69,15 +75,26 @@ namespace NFileHeader
char RDevMinor[8]; //only valid for chr and blk special files
char NameSize[8]; // count includes terminating NUL in pathname
char ChkSum[8]; // 0 for "new" portable format; for CRC format the sum of all the bytes in the file
- bool CheckMagic() const
- { return memcmp(Magic, NMagic::kMagic1, 6) == 0 ||
- memcmp(Magic, NMagic::kMagic2, 6) == 0; };
};
- */
+*/
- const UInt32 kOctRecordSize = 76;
-
-}
+enum EType
+{
+ k_Type_BinLe,
+ k_Type_BinBe,
+ k_Type_Oct,
+ k_Type_Hex,
+ k_Type_HexCrc
+};
+
+static const char *k_Types[] =
+{
+ "Binary LE"
+ , "Binary BE"
+ , "Portable ASCII"
+ , "New ASCII"
+ , "New CRC"
+};
struct CItem
{
@@ -86,12 +103,9 @@ struct CItem
UInt32 Mode;
UInt32 UID;
UInt32 GID;
- UInt32 Size;
+ UInt64 Size;
UInt32 MTime;
- // char LinkFlag;
- // AString LinkName; ?????
- char Magic[8];
UInt32 NumLinks;
UInt32 DevMajor;
UInt32 DevMinor;
@@ -100,394 +114,479 @@ struct CItem
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 (Mode & 0170000) == 0040000; }
+ bool IsTrailer() const { return strcmp(Name, kName_TRAILER) == 0; }
+ UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; };
};
-class CItemEx: public CItem
+enum EErrorType
{
-public:
- UInt64 HeaderPosition;
- UInt32 HeaderSize;
- UInt64 GetDataPosition() const { return HeaderPosition + HeaderSize; };
+ k_ErrorType_OK,
+ k_ErrorType_Corrupted,
+ k_ErrorType_UnexpectedEnd,
};
-const UInt32 kMaxBlockSize = NFileHeader::kRecordSize;
-
-class CInArchive
+struct CInArchive
{
- CMyComPtr<IInStream> m_Stream;
- UInt64 m_Position;
-
- UInt16 _blockSize;
- Byte _block[kMaxBlockSize];
- UInt32 _blockPos;
- Byte ReadByte();
- UInt16 ReadUInt16();
- UInt32 ReadUInt32();
+ ISequentialInStream *Stream;
+ UInt64 Processed;
- bool ReadNumber(UInt32 &resultValue);
- bool ReadOctNumber(int size, UInt32 &resultValue);
-
- HRESULT ReadBytes(void *data, UInt32 size, UInt32 &processedSize);
-public:
- HRESULT Open(IInStream *inStream);
- HRESULT GetNextItem(bool &filled, CItemEx &itemInfo);
- HRESULT Skip(UInt64 numBytes);
- HRESULT SkipDataRecords(UInt64 dataSize, UInt32 align);
+ HRESULT Read(void *data, size_t *size);
+ HRESULT GetNextItem(CItem &item, EErrorType &errorType);
};
-HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 &processedSize)
+HRESULT CInArchive::Read(void *data, size_t *size)
{
- size_t realProcessedSize = size;
- RINOK(ReadStream(m_Stream, data, &realProcessedSize));
- processedSize = (UInt32)realProcessedSize;
- m_Position += processedSize;
- return S_OK;
+ HRESULT res = ReadStream(Stream, data, size);
+ Processed += *size;
+ return res;
}
-Byte CInArchive::ReadByte()
+static bool ReadHex(const Byte *p, UInt32 &resVal)
{
- if (_blockPos >= _blockSize)
- throw "Incorrect cpio archive";
- return _block[_blockPos++];
+ char sz[16];
+ memcpy(sz, p, 8);
+ sz[8] = 0;
+ const char *end;
+ resVal = ConvertHexStringToUInt32(sz, &end);
+ return (unsigned)(end - sz) == 8;
}
-UInt16 CInArchive::ReadUInt16()
+static bool ReadOct6(const Byte *p, UInt32 &resVal)
{
- UInt16 value = 0;
- for (int i = 0; i < 2; i++)
- {
- Byte b = ReadByte();
- value |= (UInt16(b) << (8 * i));
- }
- return value;
+ char sz[16];
+ memcpy(sz, p, 6);
+ sz[6] = 0;
+ const char *end;
+ resVal = ConvertOctStringToUInt32(sz, &end);
+ return (unsigned)(end - sz) == 6;
}
-UInt32 CInArchive::ReadUInt32()
+static bool ReadOct11(const Byte *p, UInt64 &resVal)
{
- UInt32 value = 0;
- for (int i = 0; i < 4; i++)
- {
- Byte b = ReadByte();
- value |= (UInt32(b) << (8 * i));
- }
- return value;
+ char sz[16];
+ memcpy(sz, p, 11);
+ sz[11] = 0;
+ const char *end;
+ resVal = ConvertOctStringToUInt64(sz, &end);
+ return (unsigned)(end - sz) == 11;
}
-HRESULT CInArchive::Open(IInStream *inStream)
-{
- RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
- m_Stream = inStream;
- return S_OK;
-}
-bool CInArchive::ReadNumber(UInt32 &resultValue)
-{
- resultValue = 0;
- for (int i = 0; i < 8; i++)
- {
- char c = char(ReadByte());
- int d;
- if (c >= '0' && c <= '9')
- d = c - '0';
- else if (c >= 'A' && c <= 'F')
- d = 10 + c - 'A';
- else if (c >= 'a' && c <= 'f')
- d = 10 + c - 'a';
- else
- return false;
- resultValue *= 0x10;
- resultValue += d;
- }
- return true;
-}
+#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 bool OctalToNumber(const char *s, UInt64 &res)
+static UInt32 GetAlignedSize(UInt32 size, UInt32 align)
{
- const char *end;
- res = ConvertOctStringToUInt64(s, &end);
- return (*end == ' ' || *end == 0);
+ while ((size & (align - 1)) != 0)
+ size++;
+ return size;
}
-static bool OctalToNumber32(const char *s, UInt32 &res)
-{
- UInt64 res64;
- if (!OctalToNumber(s, res64))
- return false;
- res = (UInt32)res64;
- return (res64 <= 0xFFFFFFFF);
-}
+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); }
-bool CInArchive::ReadOctNumber(int size, UInt32 &resultValue)
-{
- char sz[32 + 4];
- int i;
- for (i = 0; i < size && i < 32; i++)
- sz[i] = (char)ReadByte();
- sz[i] = 0;
- return OctalToNumber32(sz, resultValue);
-}
+#define G16(offs, v) v = Get16(p + (offs), be)
+#define G32(offs, v) v = Get32(p + (offs), be)
-#define GetFromHex(y) { if (!ReadNumber(y)) return S_FALSE; }
-#define GetFromOct6(y) { if (!ReadOctNumber(6, y)) return S_FALSE; }
-#define GetFromOct11(y) { if (!ReadOctNumber(11, y)) return S_FALSE; }
+static const unsigned kNameSizeMax = 1 << 12;
-static unsigned short ConvertValue(unsigned short value, bool convert)
+API_FUNC_static_IsArc IsArc_Cpio(const Byte *p, size_t size)
{
- if (!convert)
- return value;
- return (unsigned short)((((unsigned short)(value & 0xFF)) << 8) | (value >> 8));
-}
+ if (size < k_BinRecord_Size)
+ return k_IsArc_Res_NEED_MORE;
-static UInt32 GetAlignedSize(UInt32 size, UInt32 align)
-{
- while ((size & (align - 1)) != 0)
- size++;
- return size;
+ 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(bool &filled, CItemEx &item)
+HRESULT CInArchive::GetNextItem(CItem &item, EErrorType &errorType)
{
- filled = false;
+ errorType = k_ErrorType_Corrupted;
- UInt32 processedSize;
- item.HeaderPosition = m_Position;
+ Byte p[k_RecordSize_Max];
- _blockSize = kMaxBlockSize;
- RINOK(ReadBytes(_block, 2, processedSize));
- if (processedSize != 2)
- return S_FALSE;
- _blockPos = 0;
+ READ_STREAM(p, k_BinRecord_Size)
UInt32 nameSize;
- bool oldBE =
- _block[0] == NFileHeader::NMagic::kMagicForRecord2[1] &&
- _block[1] == NFileHeader::NMagic::kMagicForRecord2[0];
-
- bool binMode = (_block[0] == NFileHeader::NMagic::kMagicForRecord2[0] &&
- _block[1] == NFileHeader::NMagic::kMagicForRecord2[1]) ||
- oldBE;
-
- if (binMode)
+ if (p[0] != '0')
{
- RINOK(ReadBytes(_block + 2, NFileHeader::kRecord2Size - 2, processedSize));
- if (processedSize != NFileHeader::kRecord2Size - 2)
- return S_FALSE;
+ 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;
- _blockPos = 2;
item.DevMajor = 0;
- item.DevMinor = ConvertValue(ReadUInt16(), oldBE);
- item.inode = ConvertValue(ReadUInt16(), oldBE);
- item.Mode = ConvertValue(ReadUInt16(), oldBE);
- item.UID = ConvertValue(ReadUInt16(), oldBE);
- item.GID = ConvertValue(ReadUInt16(), oldBE);
- item.NumLinks = ConvertValue(ReadUInt16(), oldBE);
item.RDevMajor =0;
- item.RDevMinor = ConvertValue(ReadUInt16(), oldBE);
- UInt16 timeHigh = ConvertValue(ReadUInt16(), oldBE);
- UInt16 timeLow = ConvertValue(ReadUInt16(), oldBE);
- item.MTime = (UInt32(timeHigh) << 16) + timeLow;
- nameSize = ConvertValue(ReadUInt16(), oldBE);
- UInt16 sizeHigh = ConvertValue(ReadUInt16(), oldBE);
- UInt16 sizeLow = ConvertValue(ReadUInt16(), oldBE);
- item.Size = (UInt32(sizeHigh) << 16) + sizeLow;
-
item.ChkSum = 0;
- item.HeaderSize = GetAlignedSize(
- nameSize + NFileHeader::kRecord2Size, item.Align);
- nameSize = item.HeaderSize - NFileHeader::kRecord2Size;
+
+ 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
{
- RINOK(ReadBytes(_block + 2, 4, processedSize));
- if (processedSize != 4)
+ if (p[1] != '7' ||
+ p[2] != '0' ||
+ p[3] != '7' ||
+ p[4] != '0')
return S_FALSE;
-
- bool magicOK =
- memcmp(_block, NFileHeader::NMagic::kMagic1, 6) == 0 ||
- memcmp(_block, NFileHeader::NMagic::kMagic2, 6) == 0;
- _blockPos = 6;
- if (magicOK)
+ if (p[5] == kMagicOct)
{
- RINOK(ReadBytes(_block + 6, NFileHeader::kRecordSize - 6, processedSize));
- if (processedSize != NFileHeader::kRecordSize - 6)
- return S_FALSE;
- item.Align = 4;
+ 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;
- GetFromHex(item.inode);
- GetFromHex(item.Mode);
- GetFromHex(item.UID);
- GetFromHex(item.GID);
- GetFromHex(item.NumLinks);
- UInt32 mTime;
- GetFromHex(mTime);
- item.MTime = mTime;
- GetFromHex(item.Size);
- GetFromHex(item.DevMajor);
- GetFromHex(item.DevMinor);
- GetFromHex(item.RDevMajor);
- GetFromHex(item.RDevMinor);
- GetFromHex(nameSize);
- GetFromHex(item.ChkSum);
- item.HeaderSize = GetAlignedSize(
- nameSize + NFileHeader::kRecordSize, item.Align);
- nameSize = item.HeaderSize - NFileHeader::kRecordSize;
+ 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 (!memcmp(_block, NFileHeader::NMagic::kMagic3, 6) == 0)
- return S_FALSE;
- RINOK(ReadBytes(_block + 6, NFileHeader::kOctRecordSize - 6, processedSize));
- if (processedSize != NFileHeader::kOctRecordSize - 6)
+ if (p[5] == kMagicHex)
+ item.Type = k_Type_Hex;
+ else if (p[5] == kMagicHexCrc)
+ item.Type = k_Type_HexCrc;
+ else
return S_FALSE;
- item.Align = 1;
- item.DevMajor = 0;
- GetFromOct6(item.DevMinor);
- GetFromOct6(item.inode);
- GetFromOct6(item.Mode);
- GetFromOct6(item.UID);
- GetFromOct6(item.GID);
- GetFromOct6(item.NumLinks);
- item.RDevMajor = 0;
- GetFromOct6(item.RDevMinor);
- UInt32 mTime;
- GetFromOct11(mTime);
- item.MTime = mTime;
- GetFromOct6(nameSize);
- GetFromOct11(item.Size); // ?????
- item.HeaderSize = GetAlignedSize(
- nameSize + NFileHeader::kOctRecordSize, item.Align);
- nameSize = item.HeaderSize - NFileHeader::kOctRecordSize;
+
+ 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 == 0 || nameSize >= (1 << 27))
- return E_FAIL;
- RINOK(ReadBytes(item.Name.GetBuffer(nameSize), nameSize, processedSize));
- if (processedSize != nameSize)
- return E_FAIL;
+ if (nameSize > kNameSizeMax)
+ return S_FALSE;
+ if (nameSize == 0 || nameSize >= kNameSizeMax)
+ return S_OK;
+ char *s = item.Name.GetBuffer(nameSize);
+ size_t processedSize = nameSize;
+ RINOK(Read(s, &processedSize));
+ s[nameSize] = 0;
item.Name.ReleaseBuffer();
- if (strcmp(item.Name, NFileHeader::NMagic::kEndName) == 0)
+ if (processedSize != nameSize)
+ {
+ errorType = k_ErrorType_UnexpectedEnd;
return S_OK;
- filled = true;
- return S_OK;
-}
-
-HRESULT CInArchive::Skip(UInt64 numBytes)
-{
- UInt64 newPostion;
- RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion));
- m_Position += numBytes;
- if (m_Position != newPostion)
- return E_FAIL;
+ }
+ errorType = k_ErrorType_OK;
return S_OK;
}
-HRESULT CInArchive::SkipDataRecords(UInt64 dataSize, UInt32 align)
-{
- while ((dataSize & (align - 1)) != 0)
- dataSize++;
- return Skip(dataSize);
-}
-
-
class CHandler:
public IInArchive,
public IInArchiveGetStream,
public CMyUnknownImp
{
- CObjectVector<CItemEx> _items;
+ CObjectVector<CItem> _items;
CMyComPtr<IInStream> _stream;
+ UInt64 _phySize;
+ EType _Type;
+ EErrorType _error;
+ bool _isArc;
public:
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
};
-/*
-enum
+static const Byte kArcProps[] =
{
- kpidinode = kpidUserDefined,
- kpidiChkSum
+ kpidSubType
};
-*/
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidPosixAttrib, VT_UI4},
- // { L"inode", kpidinode, VT_UI4}
- // { L"CheckSum", kpidiChkSum, VT_UI4}
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidMTime,
+ kpidPosixAttrib,
+ kpidLinks
};
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO
+IMP_IInArchive_ArcProps
-STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- // try
+ NCOM::CPropVariant prop;
+ switch (propID)
{
- CInArchive archive;
+ case kpidSubType: prop = k_Types[_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;
- bool needSetTotal = true;
- if (callback != NULL)
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ if (callback)
{
- RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
- RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(callback->SetTotal(NULL, &endPos));
}
- RINOK(archive.Open(stream));
-
_items.Clear();
+ CInArchive arc;
+
+ arc.Stream = stream;
+ arc.Processed = 0;
for (;;)
{
- CItemEx item;
- bool filled;
- HRESULT result = archive.GetNextItem(filled, item);
+ 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 (!filled)
+ 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);
- if (callback != NULL)
+
{
- if (needSetTotal)
+ // 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)
{
- RINOK(callback->SetTotal(NULL, &endPos));
- needSetTotal = false;
+ _error = k_ErrorType_UnexpectedEnd;
+ break;
}
- if (_items.Size() % 100 == 0)
+
+ 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)
{
- UInt64 numFiles = _items.Size();
- UInt64 numBytes = item.HeaderPosition;
- RINOK(callback->SetCompleted(&numFiles, &numBytes));
+ unsigned i;
+ for (i = 0; i < processed && buf[i] == 0; i++);
+ if (i == processed)
+ _phySize += processed;
}
}
}
- if (_items.Size() == 0)
- return S_FALSE;
-
+
+ _isArc = true;
_stream = stream;
}
- /*
- catch(...)
- {
- return S_FALSE;
- }
- */
return S_OK;
COM_TRY_END
}
@@ -496,6 +595,10 @@ STDMETHODIMP CHandler::Close()
{
_items.Clear();
_stream.Release();
+ _phySize = 0;
+ _Type = k_Type_BinLe;
+ _isArc = false;
+ _error = k_ErrorType_OK;
return S_OK;
}
@@ -508,12 +611,24 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- const CItemEx &item = _items[index];
+ NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
- switch(propID)
+ switch (propID)
{
- case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
+ 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::GetOSName(res);
+ break;
+ }
case kpidIsDir: prop = item.IsDir(); break;
case kpidSize:
case kpidPackSize:
@@ -524,12 +639,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
if (item.MTime != 0)
{
FILETIME utc;
- NWindows::NTime::UnixTimeToFileTime(item.MTime, 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;
@@ -540,11 +656,53 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
COM_TRY_END
}
+class COutStreamWithSum:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+ UInt32 _crc;
+ bool _calculate;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(bool calculate = true)
+ {
+ _size = 0;
+ _calculate = calculate;
+ _crc = 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)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items.Size();
if (numItems == 0)
@@ -568,6 +726,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ISequentialInStream> inStream(streamSpec);
streamSpec->SetStream(_stream);
+ COutStreamWithSum *outStreamSumSpec = new COutStreamWithSum;
+ CMyComPtr<ISequentialOutStream> outStreamSum(outStreamSumSpec);
+
for (i = 0; i < numItems; i++)
{
lps->InSize = lps->OutSize = currentTotalSize;
@@ -577,7 +738,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
Int32 index = allFilesMode ? i : indices[i];
- const CItemEx &item = _items[index];
+ const CItem &item = _items[index];
RINOK(extractCallback->GetStream(index, &outStream, askMode));
currentTotalSize += item.Size;
if (item.IsDir())
@@ -588,19 +749,23 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
if (!testMode && !outStream)
continue;
+ outStreamSumSpec->Init(item.IsCrcFormat());
+ outStreamSumSpec->SetStream(outStream);
+ outStream.Release();
+
RINOK(extractCallback->PrepareOperation(askMode));
- if (testMode)
- {
- RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
- continue;
- }
RINOK(_stream->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL));
streamSpec->Init(item.Size);
- RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
- outStream.Release();
- RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
- NExtract::NOperationResult::kOK:
- NExtract::NOperationResult::kDataError));
+ 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
@@ -609,15 +774,24 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
{
COM_TRY_BEGIN
- const CItemEx &item = _items[index];
+ const CItem &item = _items[index];
return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream);
COM_TRY_END
}
-static IInArchive *CreateArc() { return new NArchive::NCpio::CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"Cpio", L"cpio", 0, 0xED, { 0 }, 0, false, CreateArc, 0 };
+ { "Cpio", "cpio", 0, 0xED,
+ 3 + 5 + 2 + 2,
+ {
+ 5, '0', '7', '0', '7', '0',
+ 2, kMagicBin0, kMagicBin1,
+ 2, kMagicBin1, kMagicBin0,
+ },
+ 0,
+ NArcInfoFlags::kMultiSignature,
+ CreateArc, NULL, IsArc_Cpio };
REGISTER_ARC(Cpio)
diff --git a/CPP/7zip/Archive/CramfsHandler.cpp b/CPP/7zip/Archive/CramfsHandler.cpp
index a55e3743..3764f1af 100755..100644
--- a/CPP/7zip/Archive/CramfsHandler.cpp
+++ b/CPP/7zip/Archive/CramfsHandler.cpp
@@ -3,13 +3,14 @@
#include "StdAfx.h"
#include "../../../C/7zCrc.h"
-#include "../../../C/CpuArch.h"
#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+#include "../../../C/LzmaDec.h"
-#include "Common/ComTry.h"
-#include "Common/StringConvert.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/StringConvert.h"
-#include "Windows/PropVariantUtils.h"
+#include "../../Windows/PropVariantUtils.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -38,6 +39,30 @@ 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 *k_Methods[] =
+{
+ "Copy"
+ , "ZLIB"
+ , "LZMA"
+ , "Unknown"
+};
+
static const CUInt32PCharPair k_Flags[] =
{
{ 0, "Ver2" },
@@ -48,7 +73,6 @@ static const CUInt32PCharPair k_Flags[] =
};
static const unsigned kBlockSizeLog = 12;
-static const UInt32 kBlockSize = 1 << kBlockSizeLog;
/*
struct CNode
@@ -141,6 +165,8 @@ struct CHeader
}
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:
@@ -153,14 +179,21 @@ class CHandler:
Byte *_data;
UInt32 _size;
UInt32 _headersSize;
- AString _errorMessage;
+
+ UInt32 _errorFlags;
+ bool _isArc;
+
CHeader _h;
+ UInt32 _phySize;
+
+ unsigned _method;
+ unsigned _blockSizeLog;
// Current file
NCompress::NZlib::CDecoder *_zlibDecoderSpec;
CMyComPtr<ICompressCoder> _zlibDecoder;
-
+
CBufInStream *_inStreamSpec;
CMyComPtr<ISequentialInStream> _inStream;
@@ -175,6 +208,18 @@ class CHandler:
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(); }
@@ -184,25 +229,26 @@ public:
HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
};
-static const STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI4},
- { NULL, kpidPackSize, VT_UI4},
- { NULL, kpidPosixAttrib, VT_UI4}
- // { NULL, kpidOffset, VT_UI4}
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidPosixAttrib
+ // kpidOffset
};
-static const STATPROPSTG kArcProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidName, VT_BSTR},
- { NULL, kpidBigEndian, VT_BOOL},
- { NULL, kpidCharacts, VT_BSTR},
- { NULL, kpidPhySize, VT_UI4},
- { NULL, kpidHeadersSize, VT_UI4},
- { NULL, kpidNumSubFiles, VT_UI4},
- { NULL, kpidNumBlocks, VT_UI4}
+ kpidVolumeName,
+ kpidBigEndian,
+ kpidCharacts,
+ kpidClusterSize,
+ kpidMethod,
+ kpidHeadersSize,
+ kpidNumSubFiles,
+ kpidNumBlocks
};
IMP_IInArchive_Props
@@ -221,10 +267,11 @@ HRESULT CHandler::OpenDir(int parent, UInt32 baseOffset, unsigned level)
UInt32 end = offset + size;
if (offset < kHeaderSize || end > _size || level > kNumDirLevelsMax)
return S_FALSE;
+ UpdatePhySize(end);
if (end > _headersSize)
_headersSize = end;
- int startIndex = _items.Size();
+ unsigned startIndex = _items.Size();
while (size != 0)
{
@@ -241,8 +288,8 @@ HRESULT CHandler::OpenDir(int parent, UInt32 baseOffset, unsigned level)
size -= nodeLen;
}
- int endIndex = _items.Size();
- for (int i = startIndex; i < endIndex; i++)
+ unsigned endIndex = _items.Size();
+ for (unsigned i = startIndex; i < endIndex; i++)
{
RINOK(OpenDir(i, _items[i].Offset, level + 1));
}
@@ -255,17 +302,26 @@ HRESULT CHandler::Open2(IInStream *inStream)
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)
- return S_FALSE;
+ size = kArcSizeMax;
_h.Size = (UInt32)size;
RINOK(inStream->Seek(kHeaderSize, STREAM_SEEK_SET, NULL));
}
@@ -278,18 +334,59 @@ HRESULT CHandler::Open2(IInStream *inStream)
if (processed < kNodeSize)
return S_FALSE;
_size = kHeaderSize + (UInt32)processed;
- if (_size != _h.Size)
- _errorMessage = "Unexpected end of archive";
- else
+ if (_h.IsVer2())
{
- SetUi32(_data + 0x20, 0);
- if (_h.IsVer2())
+ if (_size != _h.Size)
+ _errorFlags = kpv_ErrorFlags_UnexpectedEnd;
+ else
+ {
+ SetUi32(_data + 0x20, 0);
if (CrcCalc(_data, _h.Size) != _h.Crc)
- _errorMessage = "CRC error";
+ {
+ _errorFlags = kpv_ErrorFlags_HeadersError;
+ // _errorMessage = "CRC error";
+ }
+ }
+ if (_h.NumFiles >= 1)
+ _items.ClearAndReserve(_h.NumFiles - 1);
}
- if (_h.IsVer2())
- _items.Reserve(_h.NumFiles - 1);
- return OpenDir(-1, kHeaderSize, 0);
+
+ 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
@@ -334,13 +431,16 @@ AString CHandler::GetPath(int index) const
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 = (GetSize(p, be) + kBlockSize - 1) >> kBlockSizeLog;
+ UInt32 numBlocks = GetNumBlocks(GetSize(p, be));
+ if (numBlocks == 0)
+ return true;
UInt32 start = offset + numBlocks * 4;
if (start > _size)
return false;
@@ -357,6 +457,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb
{
Close();
RINOK(Open2(stream));
+ _isArc = true;
_stream = stream;
}
return S_OK;
@@ -371,10 +472,12 @@ void CHandler::Free()
STDMETHODIMP CHandler::Close()
{
+ _isArc = false;
+ _phySize = 0;
+ _errorFlags = 0;
_headersSize = 0;
_items.Clear();
_stream.Release();
- _errorMessage.Empty();
Free();
return S_OK;
}
@@ -389,9 +492,9 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
- case kpidName:
+ case kpidVolumeName:
{
char dest[kHeaderNameSize + 4];
memcpy(dest, _h.Name, kHeaderNameSize);
@@ -401,11 +504,20 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
}
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: if (_h.IsVer2()) prop = _h.Size; break;
+ case kpidPhySize: prop = _phySize; break;
case kpidHeadersSize: prop = _headersSize; break;
- case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = _errorFlags;
+ if (!_isArc)
+ v |= kpv_ErrorFlags_IsNotArc;
+ prop = v;
+ break;
+ }
}
prop.Detach(value);
return S_OK;
@@ -453,13 +565,60 @@ HRESULT CCramfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSi
return Handler->ReadBlock(blockIndex, dest, blockSize);
}
+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 };
+
HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
{
- if (!_zlibDecoder)
+ if (_method == k_Flags_Method_ZLIB)
{
- _zlibDecoderSpec = new NCompress::NZlib::CDecoder();
- _zlibDecoder = _zlibDecoderSpec;
+ 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;
+ }
+ }
+
+ bool be = _h.be;
+ const Byte *p = _data + (_curBlocksOffset + (UInt32)blockIndex * 4);
+ UInt32 start = (blockIndex == 0 ? _curBlocksOffset + _curNumBlocks * 4: Get32(p - 4));
+ UInt32 end = Get32(p);
+ if (end < start || end > _size)
+ return S_FALSE;
+ UInt32 inSize = end - start;
+
+ 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();
@@ -470,17 +629,10 @@ HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
_outStreamSpec = new CBufPtrSeqOutStream();
_outStream = _outStreamSpec;
}
- bool be = _h.be;
- const Byte *p = _data + (_curBlocksOffset + (UInt32)blockIndex * 4);
- UInt32 start = (blockIndex == 0 ? _curBlocksOffset + _curNumBlocks * 4: Get32(p - 4));
- UInt32 end = Get32(p);
- if (end < start || end > _size)
- return S_FALSE;
- UInt32 inSize = end - start;
_inStreamSpec->Init(_data + start, inSize);
_outStreamSpec->Init(dest, blockSize);
RINOK(_zlibDecoder->Code(_inStream, _outStream, NULL, NULL, NULL));
- return (_zlibDecoderSpec->GetInputProcessedSize() == inSize &&
+ return (inSize == _zlibDecoderSpec->GetInputProcessedSize() &&
_outStreamSpec->GetPos() == blockSize) ? S_OK : S_FALSE;
}
@@ -488,7 +640,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items.Size();
if (numItems == 0)
@@ -562,19 +714,22 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (hres == E_OUTOFMEMORY)
return E_OUTOFMEMORY;
if (hres == S_FALSE || !inStream)
- res = NExtract::NOperationResult::kUnSupportedMethod;
+ res = NExtract::NOperationResult::kUnsupportedMethod;
else
{
RINOK(hres);
if (inStream)
{
HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
- if (hres != S_OK && hres != S_FALSE)
+ if (hres == S_OK)
{
- RINOK(hres);
+ if (copyCoderSpec->TotalSize == curSize)
+ res = NExtract::NOperationResult::kOK;
}
- if (copyCoderSpec->TotalSize == curSize && hres == S_OK)
- res = NExtract::NOperationResult::kOK;
+ else if (hres == E_NOTIMPL)
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ else if (hres != S_FALSE)
+ return hres;
}
}
}
@@ -596,7 +751,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
return E_FAIL;
UInt32 size = GetSize(p, be);
- UInt32 numBlocks = (size + kBlockSize - 1) >> kBlockSizeLog;
+ UInt32 numBlocks = GetNumBlocks(size);
UInt32 offset = GetOffset(p, be);
if (offset < kHeaderSize)
{
@@ -625,7 +780,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
_curNumBlocks = numBlocks;
_curBlocksOffset = offset;
streamSpec->Handler = this;
- if (!streamSpec->Alloc(kBlockSizeLog, 21 - kBlockSizeLog))
+ if (!streamSpec->Alloc(_blockSizeLog, 21 - _blockSizeLog))
return E_OUTOFMEMORY;
streamSpec->Init(size);
*stream = streamTemp.Detach();
@@ -634,10 +789,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
COM_TRY_END
}
-static IInArchive *CreateArc() { return new NArchive::NCramfs::CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"CramFS", L"cramfs", 0, 0xD3, SIGNATURE, kSignatureSize, false, CreateArc, 0 };
+ { "CramFS", "cramfs", 0, 0xD3,
+ kSignatureSize, SIGNATURE,
+ 16,
+ 0,
+ CreateArc };
REGISTER_ARC(Cramfs)
diff --git a/CPP/7zip/Archive/DebHandler.cpp b/CPP/7zip/Archive/DebHandler.cpp
deleted file mode 100755
index 82d2cde8..00000000
--- a/CPP/7zip/Archive/DebHandler.cpp
+++ /dev/null
@@ -1,413 +0,0 @@
-// DebHandler.cpp
-
-#include "StdAfx.h"
-
-#include "Common/ComTry.h"
-#include "Common/StringConvert.h"
-#include "Common/StringToInt.h"
-
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
-
-#include "../Common/LimitedStreams.h"
-#include "../Common/ProgressUtils.h"
-#include "../Common/RegisterArc.h"
-#include "../Common/StreamUtils.h"
-
-#include "../Compress/CopyCoder.h"
-
-#include "Common/ItemNameUtils.h"
-
-using namespace NWindows;
-using namespace NTime;
-
-namespace NArchive {
-namespace NDeb {
-
-namespace NHeader
-{
- const int kSignatureLen = 8;
-
- const char *kSignature = "!<arch>\n";
-
- const int kNameSize = 16;
- const int kTimeSize = 12;
- const int kModeSize = 8;
- const int kSizeSize = 10;
-
- /*
- struct CHeader
- {
- char Name[kNameSize];
- char MTime[kTimeSize];
- char Number0[6];
- char Number1[6];
- char Mode[kModeSize];
- char Size[kSizeSize];
- char Quote;
- char NewLine;
- };
- */
- const int kHeaderSize = kNameSize + kTimeSize + 6 + 6 + kModeSize + kSizeSize + 1 + 1;
-}
-
-struct CItem
-{
- AString Name;
- UInt64 Size;
- UInt32 MTime;
- UInt32 Mode;
-
- UInt64 HeaderPos;
- UInt64 GetDataPos() const { return HeaderPos + NHeader::kHeaderSize; };
- // UInt64 GetFullSize() const { return NFileHeader::kRecordSize + Size; };
-};
-
-class CInArchive
-{
- CMyComPtr<IInStream> m_Stream;
-
- HRESULT GetNextItemReal(bool &filled, CItem &itemInfo);
-public:
- UInt64 m_Position;
- HRESULT Open(IInStream *inStream);
- HRESULT GetNextItem(bool &filled, CItem &itemInfo);
- HRESULT SkipData(UInt64 dataSize);
-};
-
-HRESULT CInArchive::Open(IInStream *inStream)
-{
- RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
- char signature[NHeader::kSignatureLen];
- RINOK(ReadStream_FALSE(inStream, signature, NHeader::kSignatureLen));
- m_Position += NHeader::kSignatureLen;
- if (memcmp(signature, NHeader::kSignature, NHeader::kSignatureLen) != 0)
- return S_FALSE;
- m_Stream = inStream;
- return S_OK;
-}
-
-static void MyStrNCpy(char *dest, const char *src, int size)
-{
- for (int i = 0; i < size; i++)
- {
- char c = src[i];
- dest[i] = c;
- if (c == 0)
- break;
- }
-}
-
-static bool OctalToNumber(const char *s, int size, UInt64 &res)
-{
- char sz[32];
- MyStrNCpy(sz, s, size);
- sz[size] = 0;
- const char *end;
- int i;
- for (i = 0; sz[i] == ' '; i++);
- res = ConvertOctStringToUInt64(sz + i, &end);
- return (*end == ' ' || *end == 0);
-}
-
-static bool OctalToNumber32(const char *s, int size, UInt32 &res)
-{
- UInt64 res64;
- if (!OctalToNumber(s, size, res64))
- return false;
- res = (UInt32)res64;
- return (res64 <= 0xFFFFFFFF);
-}
-
-static bool DecimalToNumber(const char *s, int size, UInt64 &res)
-{
- char sz[32];
- MyStrNCpy(sz, s, size);
- sz[size] = 0;
- const char *end;
- int i;
- for (i = 0; sz[i] == ' '; i++);
- res = ConvertStringToUInt64(sz + i, &end);
- return (*end == ' ' || *end == 0);
-}
-
-static bool DecimalToNumber32(const char *s, int size, UInt32 &res)
-{
- UInt64 res64;
- if (!DecimalToNumber(s, size, res64))
- return false;
- res = (UInt32)res64;
- return (res64 <= 0xFFFFFFFF);
-}
-
-#define RIF(x) { if (!(x)) return S_FALSE; }
-
-
-HRESULT CInArchive::GetNextItemReal(bool &filled, CItem &item)
-{
- filled = false;
-
- char header[NHeader::kHeaderSize];
- const char *cur = header;
-
- size_t processedSize = sizeof(header);
- item.HeaderPos = m_Position;
- RINOK(ReadStream(m_Stream, header, &processedSize));
- if (processedSize != sizeof(header))
- return S_OK;
- m_Position += processedSize;
-
- char tempString[NHeader::kNameSize + 1];
- MyStrNCpy(tempString, cur, NHeader::kNameSize);
- cur += NHeader::kNameSize;
- tempString[NHeader::kNameSize] = '\0';
- item.Name = tempString;
- item.Name.Trim();
-
- for (int i = 0; i < item.Name.Length(); i++)
- if (((Byte)item.Name[i]) < 0x20)
- return S_FALSE;
-
- RIF(DecimalToNumber32(cur, NHeader::kTimeSize, item.MTime));
- cur += NHeader::kTimeSize;
-
- cur += 6 + 6;
-
- RIF(OctalToNumber32(cur, NHeader::kModeSize, item.Mode));
- cur += NHeader::kModeSize;
-
- RIF(DecimalToNumber(cur, NHeader::kSizeSize, item.Size));
- cur += NHeader::kSizeSize;
-
- filled = true;
- return S_OK;
-}
-
-HRESULT CInArchive::GetNextItem(bool &filled, CItem &item)
-{
- for (;;)
- {
- RINOK(GetNextItemReal(filled, item));
- if (!filled)
- return S_OK;
- if (item.Name.Compare("debian-binary") != 0)
- return S_OK;
- if (item.Size != 4)
- return S_OK;
- SkipData(item.Size);
- }
-}
-
-HRESULT CInArchive::SkipData(UInt64 dataSize)
-{
- return m_Stream->Seek((dataSize + 1) & (~((UInt64)0x1)), STREAM_SEEK_CUR, &m_Position);
-}
-
-class CHandler:
- public IInArchive,
- public IInArchiveGetStream,
- public CMyUnknownImp
-{
- CObjectVector<CItem> _items;
- CMyComPtr<IInStream> _stream;
- Int32 _mainSubfile;
- UInt64 _phySize;
-public:
- MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
- INTERFACE_IInArchive(;)
- STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
-};
-
-static STATPROPSTG kArcProps[] =
-{
- { NULL, kpidPhySize, VT_UI8}
-};
-
-static STATPROPSTG kProps[] =
-{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME}
-};
-
-IMP_IInArchive_Props
-IMP_IInArchive_ArcProps
-
-STDMETHODIMP CHandler::Open(IInStream *stream,
- const UInt64 * /* maxCheckStartPosition */,
- IArchiveOpenCallback *openArchiveCallback)
-{
- COM_TRY_BEGIN
- {
- _mainSubfile = -1;
- CInArchive archive;
- if (archive.Open(stream) != S_OK)
- return S_FALSE;
- _items.Clear();
-
- if (openArchiveCallback != NULL)
- {
- RINOK(openArchiveCallback->SetTotal(NULL, NULL));
- UInt64 numFiles = _items.Size();
- RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
- }
-
- for (;;)
- {
- CItem item;
- bool filled;
- HRESULT result = archive.GetNextItem(filled, item);
- if (result == S_FALSE)
- return S_FALSE;
- if (result != S_OK)
- return S_FALSE;
- if (!filled)
- break;
- if (item.Name.Left(5) == "data.")
- _mainSubfile = _items.Size();
- _items.Add(item);
- archive.SkipData(item.Size);
- if (openArchiveCallback != NULL)
- {
- UInt64 numFiles = _items.Size();
- RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
- }
- }
- _stream = stream;
- _phySize = archive.m_Position;
- }
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::Close()
-{
- _stream.Release();
- _items.Clear();
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
-{
- *numItems = _items.Size();
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
-{
- NCOM::CPropVariant prop;
- switch(propID)
- {
- case kpidPhySize: prop = _phySize; break;
- case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
- }
- prop.Detach(value);
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
-{
- COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- const CItem &item = _items[index];
-
- switch(propID)
- {
- case kpidPath: prop = (const wchar_t *)NItemName::GetOSName2(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
- case kpidSize:
- case kpidPackSize:
- prop = item.Size;
- break;
- case kpidMTime:
- {
- if (item.MTime != 0)
- {
- FILETIME fileTime;
- NTime::UnixTimeToFileTime(item.MTime, fileTime);
- prop = fileTime;
- }
- break;
- }
- }
- prop.Detach(value);
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
- Int32 testMode, IArchiveExtractCallback *extractCallback)
-{
- COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
- if (allFilesMode)
- numItems = _items.Size();
- if (numItems == 0)
- return S_OK;
- UInt64 totalSize = 0;
- UInt32 i;
- for (i = 0; i < numItems; i++)
- totalSize += _items[allFilesMode ? i : indices[i]].Size;
- extractCallback->SetTotal(totalSize);
-
- UInt64 currentTotalSize = 0;
-
- NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
- CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
-
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> progress = lps;
- lps->Init(extractCallback, false);
-
- CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
- CMyComPtr<ISequentialInStream> inStream(streamSpec);
- streamSpec->SetStream(_stream);
-
- for (i = 0; i < numItems; i++)
- {
- lps->InSize = lps->OutSize = currentTotalSize;
- RINOK(lps->SetCur());
- CMyComPtr<ISequentialOutStream> realOutStream;
- Int32 askMode = testMode ?
- NExtract::NAskMode::kTest :
- NExtract::NAskMode::kExtract;
- Int32 index = allFilesMode ? i : indices[i];
- const CItem &item = _items[index];
- RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
- currentTotalSize += item.Size;
-
- if (!testMode && !realOutStream)
- continue;
- RINOK(extractCallback->PrepareOperation(askMode));
- if (testMode)
- {
- RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
- continue;
- }
- RINOK(_stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL));
- streamSpec->Init(item.Size);
- RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
- realOutStream.Release();
- RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
- NExtract::NOperationResult::kOK:
- NExtract::NOperationResult::kDataError));
- }
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
-{
- COM_TRY_BEGIN
- const CItem &item = _items[index];
- return CreateLimitedInStream(_stream, item.GetDataPos(), item.Size, stream);
- COM_TRY_END
-}
-
-static IInArchive *CreateArc() { return new NArchive::NDeb::CHandler; }
-
-static CArcInfo g_ArcInfo =
- { L"Deb", L"deb", 0, 0xEC, { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' }, 8, false, CreateArc, 0 };
-
-REGISTER_ARC(Deb)
-
-}}
diff --git a/CPP/7zip/Archive/DeflateProps.cpp b/CPP/7zip/Archive/DeflateProps.cpp
index ca3dc6f5..ca3dc6f5 100755..100644
--- a/CPP/7zip/Archive/DeflateProps.cpp
+++ b/CPP/7zip/Archive/DeflateProps.cpp
diff --git a/CPP/7zip/Archive/DeflateProps.h b/CPP/7zip/Archive/DeflateProps.h
index 9fd2c2e9..9fd2c2e9 100755..100644
--- a/CPP/7zip/Archive/DeflateProps.h
+++ b/CPP/7zip/Archive/DeflateProps.h
diff --git a/CPP/7zip/Archive/DllExports.cpp b/CPP/7zip/Archive/DllExports.cpp
index 6c72dea7..fa40d024 100755..100644
--- a/CPP/7zip/Archive/DllExports.cpp
+++ b/CPP/7zip/Archive/DllExports.cpp
@@ -3,8 +3,8 @@
#include "StdAfx.h"
#include "../../Common/MyInitGuid.h"
+
#include "../../Common/ComTry.h"
-#include "../../Common/Types.h"
#include "../../Windows/NtCheck.h"
#include "../../Windows/PropVariant.h"
diff --git a/CPP/7zip/Archive/DllExports2.cpp b/CPP/7zip/Archive/DllExports2.cpp
index ad14ff06..beb758a2 100755..100644
--- a/CPP/7zip/Archive/DllExports2.cpp
+++ b/CPP/7zip/Archive/DllExports2.cpp
@@ -1,4 +1,4 @@
-// DLLExports.cpp
+// DLLExports2.cpp
#include "StdAfx.h"
@@ -45,23 +45,23 @@ DEFINE_GUID(CLSID_CArchiveHandler,
static const UInt16 kDecodeId = 0x2790;
DEFINE_GUID(CLSID_CCodec,
-0x23170F69, 0x40C1, kDecodeId, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+0x23170F69, 0x40C1, kDecodeId, 0, 0, 0, 0, 0, 0, 0, 0);
STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
+STDAPI CreateHasher(const GUID *clsid, IHasher **hasher);
STDAPI CreateArchiver(const GUID *classID, const GUID *iid, void **outObject);
STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
{
// COM_TRY_BEGIN
*outObject = 0;
- if (*iid == IID_ICompressCoder || *iid == IID_ICompressCoder2 || *iid == IID_ICompressFilter)
- {
+ if (*iid == IID_ICompressCoder ||
+ *iid == IID_ICompressCoder2 ||
+ *iid == IID_ICompressFilter)
return CreateCoder(clsid, iid, outObject);
- }
- else
- {
- return CreateArchiver(clsid, iid, outObject);
- }
+ if (*iid == IID_IHasher)
+ return CreateHasher(clsid, (IHasher **)outObject);
+ return CreateArchiver(clsid, iid, outObject);
// COM_TRY_END
}
@@ -72,3 +72,11 @@ STDAPI SetLargePageMode()
#endif
return S_OK;
}
+
+extern bool g_CaseSensitive;
+
+STDAPI SetCaseSensitive(Int32 caseSensitive)
+{
+ g_CaseSensitive = (caseSensitive != 0);
+ return S_OK;
+}
diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp
index 5040d518..7166f2ce 100755..100644
--- a/CPP/7zip/Archive/DmgHandler.cpp
+++ b/CPP/7zip/Archive/DmgHandler.cpp
@@ -4,85 +4,115 @@
#include "../../../C/CpuArch.h"
-#include "Common/Buffer.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/MyXml.h"
-#include "Common/UTFConvert.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyXml.h"
+#include "../../Common/UTFConvert.h"
-#include "Windows/PropVariant.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/ZlibDecoder.h"
+#include "Common/OutStreamWithCRC.h"
+
// #define DMG_SHOW_RAW
// #include <stdio.h>
#define PRF(x) // x
+#define Get16(p) GetBe16(p)
#define Get32(p) GetBe32(p)
#define Get64(p) GetBe64(p)
-static int Base64ToByte(char c)
+static const Byte k_Base64Table[256] =
{
- if (c >= 'A' && c <= 'Z') return c - 'A';
- if (c >= 'a' && c <= 'z') return c - 'a' + 26;
- if (c >= '0' && c <= '9') return c - '0' + 52;
- if (c == '+') return 62;
- if (c == '/') return 63;
- if (c == '=') return 0;
- return -1;
-}
+ 64,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
+ 77,77,77,77,77,77,77,77,77,77,77,62,77,64,77,63,52,53,54,55,56,57,58,59,60,61,77,77,77,77,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 int Base64ToBin(Byte *dest, const char *src, int srcLen)
+static Byte *Base64ToBin(Byte *dest, const char *src)
{
- int srcPos = 0;
- int destPos = 0;
- while (srcPos < srcLen)
+ UInt32 val = 1;
+ UInt32 c = k_Base64Table[(Byte)(*src++)];
+ for (;;)
{
- Byte buf[4];
- int filled = 0;
- while (srcPos < srcLen)
+ /*
+ UInt32 c = (Byte)(*src++);
+ if (c >= 'A')
{
- int n = Base64ToByte(src[srcPos++]);
- if (n >= 0)
- {
- buf[filled++] = (Byte)n;
- if (filled == 4)
- break;
- }
+ if (c <= 'Z') c -= 'A';
+ else if (c >= 'a' && c <= 'z') c -= 'a' - 26;
+ else continue;
+ }
+ else if (c >= '0')
+ {
+ if (c <= '9') c += 52 - '0';
+ else if (c == '=') break;
+ else continue;
+ }
+ else if (c == '+') c = 62;
+ else if (c == '/') c = 63;
+ else if (c == 0) break;
+ else continue;
+ */
+
+ // UInt32 c = k_Base64Table[(Byte)(*src++)];
+ if (c < 64)
+ {
+ val = (val << 6) | c;
+ c = k_Base64Table[(Byte)(*src++)];
+ 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 (filled >= 2) { if (dest) dest[destPos] = (buf[0] << 2) | (buf[1] >> 4); destPos++; }
- if (filled >= 3) { if (dest) dest[destPos] = (buf[1] << 4) | (buf[2] >> 2); destPos++; }
- if (filled >= 4) { if (dest) dest[destPos] = (buf[2] << 6) | (buf[3] ); destPos++; }
+ if (c == 64)
+ break;
+ c = k_Base64Table[(Byte)(*src++)];
+ }
+ if (val >= ((UInt32)1 << 12))
+ {
+ if (val >= ((UInt32)1 << 18))
+ *dest++ = (Byte)(val >> 16);
+ *dest++ = (Byte)(val);
}
- return destPos;
+ return dest;
}
-static UString GetSizeString(UInt64 value)
-{
- wchar_t s[32];
- wchar_t c;
- if (value < (UInt64)20000) c = 0;
- else if (value < ((UInt64)20000 << 10)) { value >>= 10; c = L'K'; }
- else if (value < ((UInt64)20000 << 20)) { value >>= 20; c = L'M'; }
- else { value >>= 30; c = L'G'; }
- ConvertUInt64ToString(value, s);
- int p = MyStringLen(s);
- s[p++] = c;
- s[p++] = L'\0';
- return s;
-}
namespace NArchive {
namespace NDmg {
+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_COMMENT = 0x7FFFFFFE, // is used to comment "+beg" and "+end" in extra field.
+ METHOD_END = 0xFFFFFFFF
+};
+
struct CBlock
{
UInt32 Type;
@@ -92,176 +122,244 @@ struct CBlock
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
{
- CByteBuffer Raw;
+ UInt64 Size;
+ UInt64 PackSize;
UInt64 StartPos;
+ AString Name;
CRecordVector<CBlock> Blocks;
- UInt64 GetUnpackSize() const
- {
- UInt64 size = 0;
- for (int i = 0; i < Blocks.Size(); i++)
- size += Blocks[i].UnpSize;
- return size;
- };
- UInt64 GetPackSize() const
- {
- UInt64 size = 0;
- for (int i = 0; i < Blocks.Size(); i++)
- size += Blocks[i].PackSize;
- return size;
- };
+ CChecksum Checksum;
+ bool FullFileChecksum;
+
+ HRESULT Parse(const Byte *p, UInt32 size);
+};
+#ifdef DMG_SHOW_RAW
+struct CExtraFile
+{
+ CByteBuffer Data;
AString Name;
};
+#endif
class CHandler:
public IInArchive,
+ public IInArchiveGetStream,
public CMyUnknownImp
{
CMyComPtr<IInStream> _inStream;
-
- AString _xml;
CObjectVector<CFile> _files;
- CRecordVector<int> _fileIndices;
+ bool _masterCrcError;
+
+ UInt64 _startPos;
+ UInt64 _phySize;
+
+ #ifdef DMG_SHOW_RAW
+ CObjectVector<CExtraFile> _extras;
+ #endif
HRESULT Open2(IInStream *stream);
HRESULT Extract(IInStream *stream);
public:
- MY_UNKNOWN_IMP1(IInArchive)
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
};
const UInt32 kXmlSizeMax = ((UInt32)1 << 31) - (1 << 14);
-enum
-{
- METHOD_ZERO_0 = 0,
- METHOD_COPY = 1,
- METHOD_ZERO_2 = 2,
- METHOD_ADC = 0x80000004,
- METHOD_ZLIB = 0x80000005,
- METHOD_BZIP2 = 0x80000006,
- METHOD_DUMMY = 0x7FFFFFFE,
- METHOD_END = 0xFFFFFFFF
-};
-
-struct CMethodStat
-{
- UInt32 NumBlocks;
- UInt64 PackSize;
- UInt64 UnpSize;
- CMethodStat(): NumBlocks(0), PackSize(0), UnpSize(0) {}
-};
-
struct CMethods
{
- CRecordVector<CMethodStat> Stats;
CRecordVector<UInt32> Types;
+ CRecordVector<UInt32> ChecksumTypes;
+
void Update(const CFile &file);
- UString GetString() const;
+ void GetString(AString &s) const;
};
void CMethods::Update(const CFile &file)
{
- for (int i = 0; i < file.Blocks.Size(); i++)
- {
- const CBlock &b = file.Blocks[i];
- int index = Types.FindInSorted(b.Type);
- if (index < 0)
- {
- index = Types.AddToUniqueSorted(b.Type);
- Stats.Insert(index, CMethodStat());
- }
- CMethodStat &m = Stats[index];
- m.PackSize += b.PackSize;
- m.UnpSize += b.UnpSize;
- m.NumBlocks++;
- }
+ ChecksumTypes.AddToUniqueSorted(file.Checksum.Type);
+ FOR_VECTOR (i, file.Blocks)
+ Types.AddToUniqueSorted(file.Blocks[i].Type);
}
-UString CMethods::GetString() const
+void CMethods::GetString(AString &res) const
{
- UString res;
- for (int i = 0; i < Types.Size(); i++)
+ res.Empty();
+ unsigned i;
+ for (i = 0; i < Types.Size(); i++)
{
- if (i != 0)
- res += L' ';
- wchar_t buf[32];
- const wchar_t *s;
- const CMethodStat &m = Stats[i];
- bool showPack = true;
UInt32 type = Types[i];
- switch(type)
+ if (type == METHOD_COMMENT || type == METHOD_END)
+ continue;
+ char buf[16];
+ const char *s;
+ switch (type)
{
- case METHOD_ZERO_0: s = L"zero0"; showPack = (m.PackSize != 0); break;
- case METHOD_ZERO_2: s = L"zero2"; showPack = (m.PackSize != 0); break;
- case METHOD_COPY: s = L"copy"; showPack = (m.UnpSize != m.PackSize); break;
- case METHOD_ADC: s = L"adc"; break;
- case METHOD_ZLIB: s = L"zlib"; break;
- case METHOD_BZIP2: s = L"bzip2"; break;
- default: ConvertUInt64ToString(type, buf); s = buf;
+ 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;
+ default: ConvertUInt32ToString(type, buf); s = buf;
}
+ if (!res.IsEmpty())
+ res += ' ';
res += s;
- if (m.NumBlocks != 1)
- {
- res += L'[';
- ConvertUInt64ToString(m.NumBlocks, buf);
- res += buf;
- res += L']';
- }
- res += L'-';
- res += GetSizeString(m.UnpSize);
- if (showPack)
+ }
+ for (i = 0; i < ChecksumTypes.Size(); i++)
+ {
+ UInt32 type = ChecksumTypes[i];
+ char buf[32];
+ const char *s;
+ switch (type)
{
- res += L'-';
- res += GetSizeString(m.PackSize);
+ case kCheckSumType_CRC: s = "CRC"; break;
+ default:
+ ConvertUInt32ToString(type, MyStpCpy(buf, "Check"));
+ s = buf;
}
+ if (!res.IsEmpty())
+ res += ' ';
+ res += s;
}
- return res;
}
-STATPROPSTG kProps[] =
+struct CAppleName
+{
+ bool IsFs;
+ const char *Ext;
+ const char *AppleName;
+};
+
+static const CAppleName k_Names[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidComment, VT_BSTR},
- { NULL, kpidMethod, VT_BSTR}
+ { true, "hfs", "Apple_HFS" },
+ { true, "hfsx", "Apple_HFSX" },
+ { true, "ufs", "Apple_UFS" },
+ { 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
};
IMP_IInArchive_Props
-STATPROPSTG kArcProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidNumBlocks, VT_UI4}
+ kpidMethod,
+ kpidNumBlocks
};
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidMethod:
{
CMethods m;
- for (int i = 0; i < _files.Size(); i++)
+ FOR_VECTOR (i, _files)
m.Update(_files[i]);
- prop = m.GetString();
+ AString s;
+ m.GetString(s);
+ if (!s.IsEmpty())
+ prop = s;
break;
}
case kpidNumBlocks:
{
UInt64 numBlocks = 0;
- for (int i = 0; i < _files.Size(); i++)
+ FOR_VECTOR (i, _files)
numBlocks += _files[i].Blocks.Size();
prop = numBlocks;
break;
}
+ case kpidMainSubfile:
+ {
+ int mainIndex = -1;
+ int numFS = 0;
+ int 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 (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";
+ break;
+ case kpidOffset: prop = _startPos; break;
+ case kpidPhySize: prop = _phySize; break;
}
prop.Detach(value);
return S_OK;
@@ -270,9 +368,83 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
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 AString &key, const AString &nextTag)
{
- for (int i = 0; i + 1 < item.SubItems.Size(); i++)
+ 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))
@@ -281,134 +453,308 @@ static int FindKeyPair(const CXmlItem &item, const AString &key, const AString &
return -1;
}
-static AString GetStringFromKeyPair(const CXmlItem &item, const AString &key, const AString &nextTag)
+static const AString *GetStringFromKeyPair(const CXmlItem &item, const AString &key, const AString &nextTag)
{
int index = FindKeyPair(item, key, nextTag);
if (index >= 0)
- return item.SubItems[index].GetSubString();
- return AString();
+ return item.SubItems[index].GetSubStringPtr();
+ return NULL;
+}
+
+static const unsigned HEADER_SIZE = 0x200;
+
+static bool IsKoly(const Byte *p)
+{
+ 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::Open2(IInStream *stream)
{
- const int HEADER_SIZE = 0x1E0;
+ RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPos));
- UInt64 headerPos;
- RINOK(stream->Seek(-HEADER_SIZE, STREAM_SEEK_END, &headerPos));
Byte buf[HEADER_SIZE];
RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE));
- UInt64 address1 = Get64(buf + 0);
- UInt64 address2 = Get64(buf + 0xB8);
- UInt64 size64 = Get64(buf + 0xC0);
- if (address1 != address2 || size64 >= kXmlSizeMax || size64 == 0 ||
- address1 >= headerPos || address1 + size64 > headerPos)
- return S_FALSE;
- RINOK(stream->Seek(address1, STREAM_SEEK_SET, NULL));
- size_t size = (size_t)size64;
- char *ss = _xml.GetBuffer((int)size + 1);
- RINOK(ReadStream_FALSE(stream, ss, size));
- ss[size] = 0;
- _xml.ReleaseBuffer();
+ UInt64 headerPos;
+ if (IsKoly(buf))
+ headerPos = _startPos;
+ else
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &headerPos));
+ 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;
+ }
- CXml xml;
- if (!xml.Parse(_xml))
- return S_FALSE;
- if (xml.Root.Name != "plist")
+ // UInt32 flags = Get32(buf + 12);
+ // UInt64 runningDataForkOffset = Get64(buf + 0x10);
+ UInt64 dataForkOffset = Get64(buf + 0x18);
+ UInt64 dataForkLen = Get64(buf + 0x20);
+ UInt64 rsrcOffset = Get64(buf + 0x28);
+ UInt64 rsrcLen = Get64(buf + 0x30);
+ // UInt32 segmentNumber = Get32(buf + 0x38);
+ // UInt32 segmentCount = Get32(buf + 0x3C);
+ // Byte segmentGUID[16];
+ // CChecksum dataForkChecksum;
+ // dataForkChecksum.Parse(buf + 0x50);
+ UInt64 xmlOffset = Get64(buf + 0xD8);
+ UInt64 xmlLen = Get64(buf + 0xE0);
+
+ UInt64 totalLen = dataForkLen + rsrcLen + xmlLen;
+ if (totalLen > headerPos)
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)
+ _startPos = headerPos - totalLen;
+ _phySize = totalLen + HEADER_SIZE;
+ headerPos = totalLen;
+
+ if (headerPos < dataForkOffset ||
+ headerPos < dataForkOffset + dataForkLen ||
+ headerPos < rsrcOffset ||
+ headerPos < rsrcOffset + rsrcLen ||
+ headerPos < xmlOffset ||
+ headerPos < xmlOffset + xmlLen)
return S_FALSE;
- const CXmlItem &arrItem = rfDictItem.SubItems[arrIndex];
+ // Byte reserved[0x78]
+
+ CChecksum masterChecksum;
+ masterChecksum.Parse(buf + 0x160);
- int i;
- for (i = 0; i < arrItem.SubItems.Size(); i++)
+ // 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 = (rsrcLen > RSRC_HEAD_SIZE && rsrcLen < ((UInt32)1 << 24));
+ // useRsrc = false;
+
+ if (useRsrc)
{
- const CXmlItem &item = arrItem.SubItems[i];
- if (!item.IsTagged("dict"))
- continue;
+ #ifdef DMG_SHOW_RAW
+ CExtraFile &extra = _extras.AddNew();
+ extra.Name = "rsrc.bin";
+ CByteBuffer &rsrcBuf = extra.Data;
+ #else
+ CByteBuffer rsrcBuf;
+ #endif
+
+ size_t rsrcLenT = (size_t)rsrcLen;
+ rsrcBuf.Alloc(rsrcLenT);
+ RINOK(stream->Seek(_startPos + rsrcOffset, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(stream, rsrcBuf, rsrcLenT));
+
+ 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 >= rsrcLenT ||
+ mainDataSize >= rsrcLenT ||
+ footerOffset + footerSize != rsrcLenT ||
+ footerOffset != headSize + mainDataSize)
+ return S_FALSE;
+ if (footerSize < 16)
+ return S_FALSE;
+ if (memcmp(p, p + footerOffset, 16) != 0)
+ return S_FALSE;
- CFile file;
- file.StartPos = 0;
+ p += footerOffset;
- int destLen;
+ if ((UInt32)Get16(p + 0x18) != 0x1C)
+ return S_FALSE;
+ 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++)
{
- AString dataString;
- AString name = GetStringFromKeyPair(item, "Name", "string");
- if (name.IsEmpty())
- name = GetStringFromKeyPair(item, "CFName", "string");
- file.Name = name;
- dataString = GetStringFromKeyPair(item, "Data", "data");
-
- destLen = Base64ToBin(NULL, dataString, dataString.Length());
- file.Raw.SetCapacity(destLen);
- Base64ToBin(file.Raw, dataString, dataString.Length());
- }
+ const Byte *p2 = p + 0x1E + i * 8;
+
+ UInt32 typeId = Get32(p2);
+ if (typeId != 0x626C6B78) // blkx
+ continue;
+
+ UInt32 numFiles = (UInt32)Get16(p2 + 4) + 1;
+ UInt32 offs = Get16(p2 + 6);
+ if (0x1C + offs + 12 * numFiles > namesOffset)
+ return S_FALSE;
- if (destLen > 0xCC && Get32(file.Raw) == 0x6D697368)
+ for (UInt32 k = 0; k < numFiles; k++)
+ {
+ const Byte *p3 = p + 0x1C + offs + k * 12;
+ // UInt32 id = Get16(p3);
+ 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;
+ UInt32 blockSize = Get32(pBlock);
+
+ #ifdef DMG_SHOW_RAW
+ {
+ CExtraFile &extra = _extras.AddNew();
+ {
+ char extraName[16];
+ ConvertUInt32ToString(_files.Size(), extraName);
+ extra.Name = extraName;
+ }
+ CByteBuffer &rawBuf = extra.Data;
+ rawBuf.SetCapacity(blockSize);
+ memcpy(rawBuf, pBlock + 4, blockSize);
+ }
+ #endif
+
+ CFile &file = _files.AddNew();
+ 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++)
+ {
+ char c = namePtr[r];
+ if (c < 0x20 || c >= 0x80)
+ break;
+ file.Name += c;
+ }
+ }
+ RINOK(file.Parse(pBlock + 4, blockSize));
+ }
+ }
+ }
+ else
+ {
+ if (xmlLen >= kXmlSizeMax || xmlLen == 0)
+ return S_FALSE;
+ RINOK(stream->Seek(_startPos + dataForkLen, STREAM_SEEK_SET, NULL));
+ size_t size = (size_t)xmlLen;
+
+ CXml xml;
{
- PRF(printf("\n\n index = %d", _files.Size()));
- const int kRecordSize = 40;
- for (int offset = 0xCC; offset + kRecordSize <= destLen; offset += kRecordSize)
+ AString xmlStr;
+ char *ss = xmlStr.GetBuffer((int)size + 1);
+ RINOK(ReadStream_FALSE(stream, ss, size));
+ ss[size] = 0;
{
- const Byte *p = (const Byte *)file.Raw + offset;
- CBlock b;
- b.Type = Get32(p);
- if (b.Type == METHOD_END)
- break;
- if (b.Type == METHOD_DUMMY)
- continue;
-
- b.UnpPos = Get64(p + 0x08) << 9;
- b.UnpSize = Get64(p + 0x10) << 9;
- b.PackPos = Get64(p + 0x18);
- b.PackSize = Get64(p + 0x20);
-
- file.Blocks.Add(b);
-
- PRF(printf("\nType=%8x m[1]=%8x uPos=%8x uSize=%7x pPos=%8x pSize=%7x",
- b.Type, Get32(p + 4), (UInt32)b.UnpPos, (UInt32)b.UnpSize, (UInt32)b.PackPos, (UInt32)b.PackSize));
+ const char *p = ss;
+ for (;;)
+ {
+ if (*p == 0) break; p++;
+ if (*p == 0) break; p++;
+ if (*p == 0) break; p++;
+ if (*p == 0) break; p++;
+ }
+ xmlStr.ReleaseBuffer((int)(p - ss));
}
+ if (!xml.Parse(xmlStr))
+ return S_FALSE;
+
+ #ifdef DMG_SHOW_RAW
+ CExtraFile &extra = _extras.AddNew();
+ extra.Name = "a.xml";
+ extra.Data.SetCapacity(size);
+ memcpy(extra.Data, ss, size);
+ #endif
}
- int itemIndex = _files.Add(file);
- if (file.Blocks.Size() > 0)
+ 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)
{
- // if (file.Name.Find("HFS") >= 0)
- _fileIndices.Add(itemIndex);
+ const CXmlItem &item = arrItem.SubItems[i];
+ if (!item.IsTagged("dict"))
+ continue;
+
+ CByteBuffer rawBuf;
+ int destLen = 0;
+ {
+ const AString *dataString = GetStringFromKeyPair(item, "Data", "data");
+ if (!dataString)
+ return S_FALSE;
+ destLen = dataString->Len() / 4 * 3 + 4;
+ rawBuf.Alloc(destLen);
+ destLen = (int)(Base64ToBin(rawBuf, *dataString) - rawBuf);
+ #ifdef DMG_SHOW_RAW
+ CExtraFile &extra = _extras.AddNew();
+ {
+ char extraName[16];
+ ConvertUInt32ToString(_files.Size(), extraName);
+ extra.Name = extraName;
+ }
+ extra.Data.SetCapacity(destLen);
+ memcpy(extra.Data, 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));
}
}
-
- // PackPos for each new file is 0 in some DMG files. So we use additional StartPos
- bool allStartAreZeros = true;
- for (i = 0; i < _files.Size(); i++)
- {
- const CFile &file = _files[i];
- if (!file.Blocks.IsEmpty() && file.Blocks[0].PackPos != 0)
- allStartAreZeros = false;
- }
- UInt64 startPos = 0;
- if (allStartAreZeros)
+ if (masterChecksum.IsCrc32())
{
+ UInt32 crc = CRC_INIT_VAL;
+ unsigned i;
for (i = 0; i < _files.Size(); i++)
{
- CFile &file = _files[i];
- file.StartPos = startPos;
- if (!file.Blocks.IsEmpty())
- startPos += file.Blocks.Back().GetNextPackOffset();
+ 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;
@@ -431,24 +777,27 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
STDMETHODIMP CHandler::Close()
{
+ _phySize = 0;
_inStream.Release();
- _fileIndices.Clear();
_files.Clear();
- _xml.Empty();
+ _masterCrcError = false;
+ #ifdef DMG_SHOW_RAW
+ _extras.Clear();
+ #endif
return S_OK;
}
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
- *numItems = _fileIndices.Size()
+ *numItems = _files.Size()
#ifdef DMG_SHOW_RAW
- + _files.Size() + 1;
+ + _extras.Size()
#endif
;
return S_OK;
}
-#define RAW_PREFIX L"raw" WSTRING_PATH_SEPARATOR
+#define RAW_PREFIX "raw" STRING_PATH_SEPARATOR
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
@@ -456,69 +805,58 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
NWindows::NCOM::CPropVariant prop;
#ifdef DMG_SHOW_RAW
- if ((int)index == _fileIndices.Size())
+ if ((int)index >= _files.Size())
{
- switch(propID)
+ const CExtraFile &extra = _extras[index - _files.Size()];
+ switch (propID)
{
case kpidPath:
- prop = RAW_PREFIX L"a.xml";
+ prop = (AString)RAW_PREFIX + extra.Name;
break;
case kpidSize:
case kpidPackSize:
- prop = (UInt64)_xml.Length();
+ prop = (UInt64)extra.Data.Size();
break;
}
}
- else if ((int)index > _fileIndices.Size())
+ else
+ #endif
{
- int rawIndex = (int)index - (_fileIndices.Size() + 1);
- switch(propID)
+ const CFile &item = _files[index];
+ switch (propID)
{
- case kpidPath:
+ case kpidSize: prop = item.Size; break;
+ case kpidPackSize: prop = item.PackSize; break;
+ case kpidCRC:
{
- wchar_t s[32] = RAW_PREFIX;
- ConvertUInt64ToString(rawIndex, s + MyStringLen(s));
- prop = s;
+ if (item.Checksum.IsCrc32() && item.FullFileChecksum)
+ prop = item.Checksum.GetCrc32();
break;
}
- case kpidSize:
- case kpidPackSize:
- prop = (UInt64)_files[rawIndex].Raw.GetCapacity();
- break;
- }
- }
- else
- #endif
- {
- int itemIndex = _fileIndices[index];
- const CFile &item = _files[itemIndex];
- switch(propID)
- {
+
case kpidMethod:
{
CMethods m;
m.Update(item);
- UString resString = m.GetString();
- if (!resString.IsEmpty())
- prop = resString;
+ AString s;
+ m.GetString(s);
+ if (!s.IsEmpty())
+ prop = s;
break;
}
- // case kpidExtension: prop = L"hfs"; break;
-
case kpidPath:
{
- // break;
UString name;
- wchar_t s[32];
- ConvertUInt64ToString(index, s);
+ wchar_t s[16];
+ ConvertUInt32ToString(index, s);
name = s;
- int num = 10;
- int numDigits;
- for (numDigits = 1; num < _fileIndices.Size(); numDigits++)
+ unsigned num = 10;
+ unsigned numDigits;
+ for (numDigits = 1; num < _files.Size(); numDigits++)
num *= 10;
- while (name.Length() < numDigits)
- name = L'0' + name;
+ while (name.Len() < numDigits)
+ name.InsertAtFront(L'0');
AString subName;
int pos1 = item.Name.Find('(');
@@ -528,23 +866,27 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
int pos2 = item.Name.Find(')', pos1);
if (pos2 >= 0)
{
- subName = item.Name.Mid(pos1, pos2 - pos1);
+ subName.SetFrom(item.Name.Ptr(pos1), pos2 - pos1);
pos1 = subName.Find(':');
if (pos1 >= 0)
- subName = subName.Left(pos1);
+ subName.DeleteFrom(pos1);
}
}
subName.Trim();
if (!subName.IsEmpty())
{
- if (subName == "Apple_HFS")
- subName = "hfs";
- else if (subName == "Apple_HFSX")
- subName = "hfsx";
- else if (subName == "Apple_Free")
- subName = "free";
- else if (subName == "DDM")
- subName = "ddm";
+ 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 += L'.';
@@ -561,6 +903,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = name;
break;
}
+
case kpidComment:
{
UString name;
@@ -568,9 +911,6 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = name;
break;
}
-
- case kpidSize: prop = item.GetUnpackSize(); break;
- case kpidPackSize: prop = item.GetPackSize(); break;
}
}
prop.Detach(value);
@@ -585,11 +925,13 @@ class CAdcDecoder:
CLzOutWindow m_OutWindowStream;
CInBuffer m_InStream;
+ /*
void ReleaseStreams()
{
m_OutWindowStream.ReleaseStream();
m_InStream.ReleaseStream();
}
+ */
class CCoderReleaser
{
@@ -601,7 +943,7 @@ class CAdcDecoder:
{
if (NeedFlush)
m_Coder->m_OutWindowStream.Flush();
- m_Coder->ReleaseStreams();
+ // m_Coder->ReleaseStreams();
}
};
friend class CCoderReleaser;
@@ -711,7 +1053,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _files.Size();
if (numItems == 0)
@@ -722,13 +1064,11 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
int index = (int)(allFilesMode ? i : indices[i]);
#ifdef DMG_SHOW_RAW
- if (index == _fileIndices.Size())
- totalSize += _xml.Length();
- else if (index > _fileIndices.Size())
- totalSize += _files[index - (_fileIndices.Size() + 1)].Raw.GetCapacity();
+ if (index >= _files.Size())
+ totalSize += _extras[index - _files.Size()].Data.Size();
else
#endif
- totalSize += _files[_fileIndices[index]].GetUnpackSize();
+ totalSize += _files[index].Size;
}
extractCallback->SetTotal(totalSize);
@@ -738,8 +1078,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 currentUnpSize = 0;
const UInt32 kZeroBufSize = (1 << 14);
- CByteBuffer zeroBuf;
- zeroBuf.SetCapacity(kZeroBufSize);
+ CByteBuffer zeroBuf(kZeroBufSize);
memset(zeroBuf, 0, kZeroBufSize);
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
@@ -774,52 +1113,55 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
Int32 index = allFilesMode ? i : indices[i];
- // const CItemEx &item = _files[index];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
-
-
+
if (!testMode && !realOutStream)
continue;
RINOK(extractCallback->PrepareOperation(askMode));
+
+ COutStreamWithCRC *outCrcStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outCrcStream = outCrcStreamSpec;
+ outCrcStreamSpec->SetStream(realOutStream);
+ bool needCrc = false;
+ outCrcStreamSpec->Init(needCrc);
+
CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
- outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->SetStream(outCrcStream);
realOutStream.Release();
Int32 opRes = NExtract::NOperationResult::kOK;
#ifdef DMG_SHOW_RAW
- if (index > _fileIndices.Size())
+ if (index >= _files.Size())
{
- const CByteBuffer &buf = _files[index - (_fileIndices.Size() + 1)].Raw;
- outStreamSpec->Init(buf.GetCapacity());
- RINOK(WriteStream(outStream, buf, buf.GetCapacity()));
- currentPackSize = currentUnpSize = buf.GetCapacity();
- }
- else if (index == _fileIndices.Size())
- {
- outStreamSpec->Init(_xml.Length());
- RINOK(WriteStream(outStream, (const char *)_xml, _xml.Length()));
- currentPackSize = currentUnpSize = _xml.Length();
+ 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[_fileIndices[index]];
- currentPackSize = item.GetPackSize();
- currentUnpSize = item.GetUnpackSize();
+ const CFile &item = _files[index];
+ currentPackSize = item.PackSize;
+ currentUnpSize = item.Size;
+
+ needCrc = item.Checksum.IsCrc32();
UInt64 unpPos = 0;
UInt64 packPos = 0;
{
- for (int j = 0; j < item.Blocks.Size(); j++)
+ 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)
@@ -828,26 +1170,28 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
break;
}
- RINOK(_inStream->Seek(item.StartPos + block.PackPos, STREAM_SEEK_SET, NULL));
+ RINOK(_inStream->Seek(_startPos + item.StartPos + block.PackPos, STREAM_SEEK_SET, NULL));
streamSpec->Init(block.PackSize);
- // UInt64 startSize = outStreamSpec->GetSize();
bool realMethod = true;
outStreamSpec->Init(block.UnpSize);
HRESULT res = S_OK;
- switch(block.Type)
+ outCrcStreamSpec->EnableCalc(needCrc);
+
+ switch (block.Type)
{
case METHOD_ZERO_0:
case METHOD_ZERO_2:
realMethod = false;
if (block.PackSize != 0)
- opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ outCrcStreamSpec->EnableCalc(block.Type == METHOD_ZERO_0);
break;
case METHOD_COPY:
if (block.UnpSize != block.PackSize)
{
- opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
break;
}
res = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
@@ -862,6 +1206,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
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;
}
@@ -869,13 +1216,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
res = bzip2Coder->Code(inStream, outStream, NULL, NULL, progress);
if (res == S_OK)
- if (streamSpec->GetSize() != block.PackSize)
+ if (bzip2CoderSpec->GetInputProcessedSize() != block.PackSize)
opRes = NExtract::NOperationResult::kDataError;
break;
}
default:
- opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
break;
}
if (res != S_OK)
@@ -900,6 +1247,11 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
}
}
+ if (needCrc && opRes == NExtract::NOperationResult::kOK)
+ {
+ if (outCrcStreamSpec->GetCRC() != item.Checksum.GetCrc32())
+ opRes = NExtract::NOperationResult::kCRCError;
+ }
}
outStream.Release();
RINOK(extractCallback->SetOperationResult(opRes));
@@ -908,10 +1260,286 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+struct CChunk
+{
+ int BlockIndex;
+ UInt64 AccessMark;
+ CByteBuffer Buf;
+};
+
+class CInStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 _virtPos;
+ int _latestChunk;
+ int _latestBlock;
+ UInt64 _accessMark;
+ CObjectVector<CChunk> _chunks;
+
+ NCompress::NBZip2::CDecoder *bzip2CoderSpec;
+ CMyComPtr<ICompressCoder> bzip2Coder;
+
+ NCompress::NZlib::CDecoder *zlibCoderSpec;
+ CMyComPtr<ICompressCoder> zlibCoder;
+
+ CAdcDecoder *adcCoderSpec;
+ CMyComPtr<ICompressCoder> adcCoder;
+
+ CBufPtrSeqOutStream *outStreamSpec;
+ CMyComPtr<ISequentialOutStream> outStream;
+
+ CLimitedSequentialInStream *limitedStreamSpec;
+ CMyComPtr<ISequentialInStream> inStream;
+
+public:
+ CMyComPtr<IInStream> Stream;
+ UInt64 Size;
+ const CFile *File;
+ UInt64 _startPos;
+
+ HRESULT InitAndSeek(UInt64 startPos)
+ {
+ _startPos = startPos;
+ _virtPos = 0;
+ _latestChunk = -1;
+ _latestBlock = -1;
+ _accessMark = 0;
+
+ limitedStreamSpec = new CLimitedSequentialInStream;
+ inStream = limitedStreamSpec;
+ limitedStreamSpec->SetStream(Stream);
+
+ outStreamSpec = new CBufPtrSeqOutStream;
+ outStream = outStreamSpec;
+ return S_OK;
+ }
+
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+
+int FindBlock(const CRecordVector<CBlock> &blocks, UInt64 pos)
+{
+ int left = 0, right = blocks.Size();
+ for (;;)
+ {
+ int 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;
+ int 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 == blockIndex)
+ break;
+ if (i != _chunks.Size())
+ _latestChunk = i;
+ else
+ {
+ const int kNumChunksMax = 128;
+ int 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;
+
+ 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
+ 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<ISequentialInStream> specStream = spec;
+ spec->File = &_files[index];
+ const CFile &file = *spec->File;
+ FOR_VECTOR (i, file.Blocks)
+ {
+ const CBlock &block = file.Blocks[i];
+ switch (block.Type)
+ {
+ case METHOD_ZERO_0:
+ case METHOD_ZERO_2:
+ case METHOD_COPY:
+ case METHOD_ADC:
+ case METHOD_ZLIB:
+ case METHOD_BZIP2:
+ case METHOD_END:
+ break;
+ default:
+ return S_FALSE;
+ }
+ }
+ spec->Stream = _inStream;
+ spec->Size = spec->File->Size;
+ RINOK(spec->InitAndSeek(_startPos));
+ *stream = specStream.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"Dmg", L"dmg", 0, 0xE4, { 0 }, 0, false, CreateArc, 0 };
+ { "Dmg", "dmg", 0, 0xE4,
+ 12, { 'k','o','l','y', 0, 0, 0, 4, 0, 0, 2, 0 },
+ 0,
+ NArcInfoFlags::kBackwardOpen |
+ NArcInfoFlags::kUseGlobalOffset,
+ CreateArc };
REGISTER_ARC(Dmg)
diff --git a/CPP/7zip/Archive/ElfHandler.cpp b/CPP/7zip/Archive/ElfHandler.cpp
index c4ad78e9..1736219f 100755..100644
--- a/CPP/7zip/Archive/ElfHandler.cpp
+++ b/CPP/7zip/Archive/ElfHandler.cpp
@@ -4,11 +4,11 @@
#include "../../../C/CpuArch.h"
-#include "Common/Buffer.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
-#include "Windows/PropVariantUtils.h"
+#include "../../Windows/PropVariantUtils.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -17,22 +17,44 @@
#include "../Compress/CopyCoder.h"
-static UInt16 Get16(const Byte *p, int be) { if (be) return GetBe16(p); return GetUi16(p); }
-static UInt32 Get32(const Byte *p, int be) { if (be) return GetBe32(p); return GetUi32(p); }
-static UInt64 Get64(const Byte *p, int be) { if (be) return GetBe64(p); return GetUi64(p); }
-
using namespace NWindows;
+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
-#define NUM_SCAN_SECTIONS_MAX (1 << 6)
+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
{
@@ -49,37 +71,30 @@ struct CHeader
UInt64 ProgOffset;
UInt64 SectOffset;
UInt32 Flags;
- UInt16 ElfHeaderSize;
+ UInt16 HeaderSize;
UInt16 SegmentEntrySize;
UInt16 NumSegments;
- UInt16 SectEntrySize;
+ UInt16 SectionEntrySize;
UInt16 NumSections;
- // UInt16 SectNameStringTableIndex;
+ UInt16 NamesSectIndex;
bool Parse(const Byte *buf);
- bool CheckSegmentEntrySize() const
- {
- return (Mode64 && SegmentEntrySize == 0x38) || (!Mode64 && SegmentEntrySize == 0x20);
- };
-
- UInt64 GetHeadersSize() const
- { return ElfHeaderSize +
- (UInt64)SegmentEntrySize * NumSegments +
- (UInt64)SectEntrySize * NumSections; }
-
+ UInt64 GetHeadersSize() const { return (UInt64)HeaderSize +
+ (UInt32)NumSegments * SegmentEntrySize +
+ (UInt32)NumSections * SectionEntrySize; }
};
bool CHeader::Parse(const Byte *p)
{
- switch(p[4])
+ 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])
+ switch (p[5])
{
case ELF_DATA_2LSB: be = false; break;
case ELF_DATA_2MSB: be = true; break;
@@ -94,36 +109,72 @@ bool CHeader::Parse(const Byte *p)
if (p[i] != 0)
return false;
- Type = Get16(p + 0x10, be);
- Machine = Get16(p + 0x12, be);
+ G16(0x10, Type);
+ G16(0x12, Machine);
if (Get32(p + 0x14, be) != 1) // Version
return false;
if (Mode64)
{
- // EntryVa = Get64(p + 0x18, be);
- ProgOffset = Get64(p + 0x20, be);
- SectOffset = Get64(p + 0x28, be);
+ // G64(0x18, EntryVa);
+ G64(0x20, ProgOffset);
+ G64(0x28, SectOffset);
p += 0x30;
}
else
{
- // EntryVa = Get32(p + 0x18, be);
- ProgOffset = Get32(p + 0x1C, be);
- SectOffset = Get32(p + 0x20, be);
+ // G32(0x18, EntryVa);
+ G32(0x1C, ProgOffset);
+ G32(0x20, SectOffset);
p += 0x24;
}
- Flags = Get32(p + 0, be);
- ElfHeaderSize = Get16(p + 4, be);
- SegmentEntrySize = Get16(p + 6, be);
- NumSegments = Get16(p + 8, be);
- SectEntrySize = Get16(p + 10, be);
- NumSections = Get16(p + 12, be);
- // SectNameStringTableIndex = Get16(p + 14, be);
- return CheckSegmentEntrySize();
+ 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 *g_SegnmentTypes[] =
+{
+ "Unused",
+ "Loadable segment",
+ "Dynamic linking tables",
+ "Program interpreter path name",
+ "Note section",
+ "SHLIB",
+ "Program header table",
+ "TLS"
+};
+
+static const CUInt32PCharPair g_SegmentFlags[] =
+{
+ { 0, "Execute" },
+ { 1, "Write" },
+ { 2, "Read" }
+};
+
struct CSegment
{
UInt32 Type;
@@ -131,14 +182,14 @@ struct CSegment
UInt64 Offset;
UInt64 Va;
// UInt64 Pa;
- UInt64 PSize;
+ UInt64 Size;
UInt64 VSize;
- // UInt64 Align;
+ UInt64 Align;
void UpdateTotalSize(UInt64 &totalSize)
{
- UInt64 t = Offset + PSize;
- if (t > totalSize)
+ UInt64 t = Offset + Size;
+ if (totalSize < t)
totalSize = t;
}
void Parse(const Byte *p, bool mode64, bool be);
@@ -146,30 +197,169 @@ struct CSegment
void CSegment::Parse(const Byte *p, bool mode64, bool be)
{
- Type = Get32(p, be);
+ G32(0, Type);
if (mode64)
{
- Flags = Get32(p + 4, be);
- Offset = Get64(p + 8, be);
- Va = Get64(p + 0x10, be);
- // Pa = Get64(p + 0x18, be);
- PSize = Get64(p + 0x20, be);
- VSize = Get64(p + 0x28, be);
- // Align = Get64(p + 0x30, be);
+ G32(4, Flags);
+ G64(8, Offset);
+ G64(0x10, Va);
+ // G64(0x18, Pa);
+ G64(0x20, Size);
+ G64(0x28, VSize);
+ G64(0x30, Align);
}
else
{
- Offset = Get32(p + 4, be);
- Va = Get32(p + 8, be);
- // Pa = Get32(p + 12, be);
- PSize = Get32(p + 16, be);
- VSize = Get32(p + 20, be);
- Flags = Get32(p + 24, be);
- // Align = Get32(p + 28, be);
+ G32(4, Offset);
+ G32(8, Va);
+ // G32(0x0C, Pa);
+ G32(0x10, Size);
+ G32(0x14, VSize);
+ G32(0x18, Flags);
+ G32(0x1C, Align);
}
}
-static const CUInt32PCharPair g_MachinePairs[] =
+// 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 CUInt32PCharPair g_Machines[] =
{
{ 0, "None" },
{ 1, "AT&T WE 32100" },
@@ -192,6 +382,7 @@ static const CUInt32PCharPair g_MachinePairs[] =
{ 20, "PowerPC" },
{ 21, "PowerPC 64-bit" },
{ 22, "IBM S/390" },
+ { 23, "SPU" },
{ 36, "NEX v800" },
{ 37, "Fujitsu FR20" },
@@ -222,6 +413,7 @@ static const CUInt32PCharPair g_MachinePairs[] =
{ 62, "AMD64" },
{ 63, "Sony DSP" },
+
{ 66, "Siemens FX66" },
{ 67, "ST9+" },
{ 68, "ST7" },
@@ -251,15 +443,99 @@ static const CUInt32PCharPair g_MachinePairs[] =
{ 92, "OpenRISC" },
{ 93, "ARC Tangent-A5" },
{ 94, "Tensilica Xtensa" },
- { 0x9026, "Alpha" }
+ { 95, "Alphamosaic VideoCore" },
+ { 96, "Thompson MM GPP" },
+ { 97, "National Semiconductor 32K" },
+ { 98, "Tenor Network TPC" },
+ { 99, "Trebia SNP 1000" },
+ { 100, "ST200" },
+ { 101, "Ubicom IP2xxx" },
+ { 102, "MAX" },
+ { 103, "NS CompactRISC" },
+ { 104, "Fujitsu F2MC16" },
+ { 105, "TI msp430" },
+ { 106, "Blackfin (DSP)" },
+ { 107, "SE S1C33" },
+ { 108, "Sharp embedded" },
+ { 109, "Arca RISC" },
+ { 110, "Unicore" },
+ { 111, "eXcess" },
+ { 112, "DXP" },
+ { 113, "Altera Nios II" },
+ { 114, "NS CRX" },
+ { 115, "Motorola XGATE" },
+ { 116, "Infineon C16x/XC16x" },
+ { 117, "Renesas M16C" },
+ { 118, "Microchip Technology dsPIC30F" },
+ { 119, "Freescale CE" },
+ { 120, "Renesas M32C" },
+
+ { 131, "Altium TSK3000" },
+ { 132, "Freescale RS08" },
+ { 133, "Analog Devices SHARC" },
+ { 134, "Cyan Technology eCOG2" },
+ { 135, "Sunplus S+core7 RISC" },
+ { 136, "NJR 24-bit DSP" },
+ { 137, "Broadcom VideoCore III" },
+ { 138, "Lattice FPGA" },
+ { 139, "SE C17" },
+ { 140, "TI TMS320C6000" },
+ { 141, "TI TMS320C2000" },
+ { 142, "TI TMS320C55x" },
+
+ { 160, "STM 64bit VLIW Data Signal" },
+ { 161, "Cypress M8C" },
+ { 162, "Renesas R32C" },
+ { 163, "NXP TriMedia" },
+ { 164, "Qualcomm Hexagon" },
+ { 165, "Intel 8051" },
+ { 166, "STMicroelectronics STxP7x" },
+ { 167, "Andes" },
+ { 168, "Cyan Technology eCOG1X" },
+ { 169, "Dallas Semiconductor MAXQ30" },
+ { 170, "NJR 16-bit DSP" },
+ { 171, "M2000" },
+ { 172, "Cray NV2" },
+ { 173, "Renesas RX" },
+ { 174, "Imagination Technologies META" },
+ { 175, "MCST Elbrus" },
+ { 176, "Cyan Technology eCOG16" },
+ { 177, "National Semiconductor CR16" },
+ { 178, "Freescale ETPUnit" },
+ { 179, "Infineon SLE9X" },
+ { 180, "Intel L10M" },
+ { 181, "Intel K10M" },
+
+ { 183, "ARM64" },
+
+ { 185, "Atmel AVR32" },
+ { 186, "STM8" },
+ { 187, "Tilera TILE64" },
+ { 188, "Tilera TILEPro" },
+ { 189, "Xilinx MicroBlaze" },
+ { 190, "NVIDIA CUDA" },
+ { 191, "Tilera TILE-Gx" },
+ { 192, "CloudShield" },
+ { 193, "KIPO-KAIST Core-A 1st" },
+ { 194, "KIPO-KAIST Core-A 2nd" },
+ { 195, "Synopsys ARCompact V2" },
+ { 196, "Open8" },
+ { 197, "Renesas RL78" },
+ { 198, "Broadcom VideoCore V" },
+ { 199, "Renesas 78KOR" },
+ { 200, "Freescale 56800EX" },
+
+ { 47787, "Xilinx MicroBlaze" },
+ // { 0x9026, "Alpha" }
};
-static const CUInt32PCharPair g_AbiOS[] =
+static const CUInt32PCharPair g_OS[] =
{
{ 0, "None" },
{ 1, "HP-UX" },
{ 2, "NetBSD" },
{ 3, "Linux" },
+ { 4, "Hurd" },
{ 6, "Solaris" },
{ 7, "AIX" },
@@ -271,16 +547,18 @@ static const CUInt32PCharPair g_AbiOS[] =
{ 13, "OpenVMS" },
{ 14, "HP NSK" },
{ 15, "AROS" },
+ { 16, "FenixOS" },
+ { 64, "Bare-metal TMS320C6000" },
+ { 65, "Linux TMS320C6000" },
{ 97, "ARM" },
{ 255, "Standalone" }
};
-static const CUInt32PCharPair g_SegmentFlags[] =
-{
- { 0, "Execute" },
- { 1, "Write" },
- { 2, "Read" }
-};
+#define ET_NONE 0
+#define ET_REL 1
+#define ET_EXEC 2
+#define ET_DYN 3
+#define ET_CORE 4
static const char *g_Types[] =
{
@@ -291,101 +569,119 @@ static const char *g_Types[] =
"Core file"
};
-static const char *g_SegnmentTypes[] =
-{
- "Unused",
- "Loadable segment",
- "Dynamic linking tables",
- "Program interpreter path name",
- "Note section",
- "SHLIB",
- "Program header table",
- "TLS"
-};
-
class CHandler:
public IInArchive,
+ public IArchiveAllowTail,
public CMyUnknownImp
{
+ CRecordVector<CSegment> _segments;
+ CRecordVector<CSection> _sections;
+ CByteBuffer _namesData;
CMyComPtr<IInStream> _inStream;
- CObjectVector<CSegment> _sections;
- UInt32 _peOffset;
- CHeader _header;
UInt64 _totalSize;
+ CHeader _header;
+ bool _headersError;
+ bool _allowTail;
+
+ void GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const;
HRESULT Open2(IInStream *stream);
- bool Parse(const Byte *buf, UInt32 size);
public:
- MY_UNKNOWN_IMP1(IInArchive)
+ MY_UNKNOWN_IMP2(IInArchive, IArchiveAllowTail)
INTERFACE_IInArchive(;)
-};
+ STDMETHOD(AllowTail)(Int32 allowTail);
-#define ELF_PT_PHDR 6
+ CHandler(): _allowTail(false) {}
+};
-bool CHandler::Parse(const Byte *buf, UInt32 size)
+void CHandler::GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const
{
- if (size < 64)
- return false;
- if (!_header.Parse(buf))
- return false;
- if (_header.ProgOffset > size ||
- _header.ProgOffset + (UInt64)_header.SegmentEntrySize * _header.NumSegments > size ||
- _header.NumSegments > NUM_SCAN_SECTIONS_MAX)
- return false;
- const Byte *p = buf + _header.ProgOffset;
- _totalSize = _header.ProgOffset;
-
- for (int i = 0; i < _header.NumSegments; i++, p += _header.SegmentEntrySize)
+ if (index >= _sections.Size())
+ return;
+ const CSection &section = _sections[index];
+ UInt32 offset = section.Name;
+ if (index == SHN_UNDEF /* && section.Type == SHT_NULL && offset == 0 */)
{
- CSegment sect;
- sect.Parse(p, _header.Mode64, _header.Be);
- sect.UpdateTotalSize(_totalSize);
- if (sect.Type != ELF_PT_PHDR)
- _sections.Add(sect);
+ if (showNULL)
+ prop = "NULL";
+ return;
}
- UInt64 total2 = _header.SectOffset + (UInt64)_header.SectEntrySize * _header.NumSections;
- if (total2 > _totalSize)
- _totalSize = total2;
- return true;
+ 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;
+ }
}
-STATPROPSTG kArcProps[] =
+static const Byte kArcProps[] =
+{
+ kpidCpu,
+ kpidBit64,
+ kpidBigEndian,
+ kpidHostOS,
+ kpidCharacts,
+ kpidHeadersSize,
+ kpidName
+};
+
+enum
{
- { NULL, kpidCpu, VT_BSTR},
- { NULL, kpidBit64, VT_BOOL},
- { NULL, kpidBigEndian, VT_BOOL},
- { NULL, kpidHostOS, VT_BSTR},
- { NULL, kpidCharacts, VT_BSTR},
- { NULL, kpidPhySize, VT_UI8},
- { NULL, kpidHeadersSize, VT_UI8}
- };
-
-STATPROPSTG kProps[] =
+ kpidLinkSection = kpidUserDefined,
+ kpidInfoSection
+};
+
+static const STATPROPSTG kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidType, VT_BSTR},
- { NULL, kpidCharacts, VT_BSTR},
- { NULL, kpidOffset, VT_UI8},
- { NULL, kpidVa, VT_UI8}
+ { 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 }
+ , { L"Link Section", kpidLinkSection, VT_BSTR}
+ , { L"Info Section", kpidInfoSection, VT_BSTR}
};
-IMP_IInArchive_Props
+IMP_IInArchive_Props_WITH_NAME
IMP_IInArchive_ArcProps
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
- case kpidPhySize: prop = _totalSize; break;
- case kpidHeadersSize: prop = _header.GetHeadersSize(); break;
- case kpidBit64: if (_header.Mode64) prop = _header.Mode64; break;
- case kpidBigEndian: if (_header.Be) prop = _header.Be; break;
- case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break;
- case kpidHostOS: PAIR_TO_PROP(g_AbiOS, _header.Os, prop); break;
- case kpidCharacts: TYPE_TO_PROP(g_Types, _header.Type, prop); break;
+ 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: PAIR_TO_PROP(g_Machines, _header.Machine, prop); 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;
@@ -396,22 +692,45 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
- const CSegment &item = _sections[index];
- switch(propID)
+ if (index < _segments.Size())
{
- case kpidPath:
+ const CSegment &item = _segments[index];
+ switch (propID)
{
- wchar_t sz[32];
- ConvertUInt64ToString(index, sz);
- prop = sz;
- break;
+ 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;
}
- case kpidSize: prop = (UInt64)item.VSize; break;
- case kpidPackSize: prop = (UInt64)item.PSize; break;
- case kpidOffset: prop = item.Offset; break;
- case kpidVa: prop = item.Va; break;
- case kpidType: TYPE_TO_PROP(g_SegnmentTypes, item.Type, prop); break;
- case kpidCharacts: FLAGS_TO_PROP(g_SegmentFlags, item.Flags, prop); break;
}
prop.Detach(value);
return S_OK;
@@ -420,25 +739,118 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
HRESULT CHandler::Open2(IInStream *stream)
{
- const UInt32 kBufSize = 1 << 18;
- const UInt32 kSigSize = 4;
-
- CByteBuffer buffer;
- buffer.SetCapacity(kBufSize);
- Byte *buf = buffer;
-
- size_t processed = kSigSize;
- RINOK(ReadStream_FALSE(stream, buf, processed));
- if (buf[0] != 0x7F || buf[1] != 'E' || buf[2] != 'L' || buf[3] != 'F')
+ 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;
- processed = kBufSize - kSigSize;
- RINOK(ReadStream(stream, buf + kSigSize, &processed));
- processed += kSigSize;
- if (!Parse(buf, (UInt32)processed))
+ if (!_header.Parse(h))
return S_FALSE;
- UInt64 fileSize;
- RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
- return (fileSize == _totalSize) ? S_OK : 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 &sect = _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,
@@ -455,14 +867,19 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
STDMETHODIMP CHandler::Close()
{
+ _totalSize = 0;
+ _headersError = false;
+
_inStream.Release();
+ _segments.Clear();
_sections.Clear();
+ _namesData.Free();
return S_OK;
}
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
- *numItems = _sections.Size();
+ *numItems = _segments.Size() + _sections.Size();
return S_OK;
}
@@ -470,15 +887,20 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
- numItems = _sections.Size();
+ numItems = _segments.Size() + _sections.Size();
if (numItems == 0)
return S_OK;
UInt64 totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
- totalSize += _sections[allFilesMode ? i : indices[i]].PSize;
+ {
+ UInt32 index = allFilesMode ? i : indices[i];
+ totalSize += (index < _segments.Size()) ?
+ _segments[index].Size :
+ _sections[index - _segments.Size()].GetSize();
+ }
extractCallback->SetTotal(totalSize);
UInt64 currentTotalSize = 0;
@@ -503,8 +925,19 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
UInt32 index = allFilesMode ? i : indices[i];
- const CSegment &item = _sections[index];
- currentItemSize = item.PSize;
+ UInt64 offset;
+ if (index < _segments.Size())
+ {
+ const CSegment &item = _segments[index];
+ currentItemSize = item.Size;
+ offset = item.Offset;
+ }
+ else
+ {
+ const CSection &item = _sections[index - _segments.Size()];
+ currentItemSize = item.GetSize();
+ offset = item.Offset;
+ }
CMyComPtr<ISequentialOutStream> outStream;
RINOK(extractCallback->GetStream(index, &outStream, askMode));
@@ -512,7 +945,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
continue;
RINOK(extractCallback->PrepareOperation(askMode));
- RINOK(_inStream->Seek(item.Offset, STREAM_SEEK_SET, NULL));
+ RINOK(_inStream->Seek(offset, STREAM_SEEK_SET, NULL));
streamSpec->Init(currentItemSize);
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
outStream.Release();
@@ -524,10 +957,20 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+STDMETHODIMP CHandler::AllowTail(Int32 allowTail)
+{
+ _allowTail = IntToBool(allowTail);
+ return S_OK;
+}
+
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"ELF", L"", 0, 0xDE, { 0 }, 0, false, CreateArc, 0 };
+ { "ELF", "elf", 0, 0xDE,
+ 4, { 0x7F, 'E', 'L', 'F' },
+ 0,
+ NArcInfoFlags::kPreArc,
+ CreateArc };
REGISTER_ARC(Elf)
diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp
index 1c374a44..51064a1a 100755..100644
--- a/CPP/7zip/Archive/FatHandler.cpp
+++ b/CPP/7zip/Archive/FatHandler.cpp
@@ -6,14 +6,14 @@
#include "../../../C/CpuArch.h"
-#include "Common/Buffer.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/MyCom.h"
-#include "Common/StringConvert.h"
+#include "../../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/Time.h"
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -109,6 +109,16 @@ static int GetLog(UInt32 num)
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)
@@ -130,7 +140,7 @@ bool CHeader::Parse(const Byte *p)
if (s < 0)
return false;
SectorsPerClusterLog = (Byte)s;
- ClusterSizeLog = SectorSizeLog + SectorsPerClusterLog;
+ ClusterSizeLog = (Byte)(SectorSizeLog + SectorsPerClusterLog);
}
NumReservedSectors = Get16(p + 14);
@@ -151,7 +161,8 @@ bool CHeader::Parse(const Byte *p)
}
else
{
- if (codeOffset < 62)
+ // Some FAT12s don't contain VolFields
+ if (codeOffset < 62 - 24)
return false;
NumFatBits = 0;
UInt32 mask = (1 << (SectorSizeLog - 5)) - 1;
@@ -174,6 +185,7 @@ bool CHeader::Parse(const Byte *p)
// memcpy(OemName, p + 3, 5);
+ int curOffset = 36;
p += 36;
if (IsFat32())
{
@@ -192,13 +204,23 @@ bool CHeader::Parse(const Byte *p)
if (p[i] != 0)
return false;
p += 28;
+ curOffset += 28;
}
// DriveNumber = p[0];
- VolFieldsDefined = (p[2] == 0x29); // ExtendedBootSig
- VolId = Get32(p + 3);
- // memcpy(VolName, p + 7, 11);
- // memcpy(FileSys, p + 18, 8);
+ 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;
@@ -214,7 +236,7 @@ bool CHeader::Parse(const Byte *p)
{
if (NumFatBits == 32)
return false;
- NumFatBits = (numClusters < 0xFF5) ? 12: 16;
+ NumFatBits = (Byte)(numClusters < 0xFF5 ? 12 : 16);
BadCluster &= ((1 << NumFatBits) - 1);
}
else if (NumFatBits != 32)
@@ -258,7 +280,7 @@ static int CopyAndTrim(char *dest, const char *src, int size, bool toLower)
{
char c = dest[i];
if (c >= 'A' && c <= 'Z')
- dest[i] = c + 0x20;
+ dest[i] = (char)(c + 0x20);
}
for (i = size - 1; i >= 0 && dest[i] == ' '; i--);
return i + 1;
@@ -313,6 +335,8 @@ struct CDatabase
CByteBuffer ByteBuf;
UInt64 NumCurUsedBytes;
+ UInt64 PhySize;
+
CDatabase(): Fat(0) {}
~CDatabase() { ClearAndClose(); }
@@ -340,6 +364,7 @@ HRESULT CDatabase::SeekToSector(UInt32 sector)
void CDatabase::Clear()
{
+ PhySize = 0;
VolItemDefined = false;
NumDirClusters = 0;
NumCurUsedBytes = 0;
@@ -386,7 +411,11 @@ UString CDatabase::GetItemPath(Int32 index) const
if (index < 0)
return name;
item = &Items[index];
- name = item->GetName() + WCHAR_PATH_SEPARATOR + name;
+ name.InsertAtFront(WCHAR_PATH_SEPARATOR);
+ if (item->UName.IsEmpty())
+ name.Insert(0, item->GetShortName());
+ else
+ name.Insert(0, item->UName);
}
}
@@ -417,7 +446,7 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level)
RINOK(SeekToSector(Header.RootDirSector));
}
- ByteBuf.SetCapacity(blockSize);
+ ByteBuf.Alloc(blockSize);
UString curName;
int checkSum = -1;
int numLongRecords = -1;
@@ -516,7 +545,7 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level)
{
Byte sum = 0;
for (int i = 0; i < 11; i++)
- sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i];
+ sum = (Byte)(((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i]);
if (sum == checkSum)
item.UName = curName;
}
@@ -578,7 +607,6 @@ HRESULT CDatabase::Open()
Clear();
bool numFreeClustersDefined = false;
{
- static const UInt32 kHeaderSize = 512;
Byte buf[kHeaderSize];
RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize));
if (!Header.Parse(buf))
@@ -618,7 +646,7 @@ HRESULT CDatabase::Open()
if (Header.NumFatBits == 32)
{
const UInt32 kBufSize = (1 << 15);
- byteBuf.SetCapacity(kBufSize);
+ byteBuf.Alloc(kBufSize);
for (UInt32 i = 0; i < Header.FatSize;)
{
UInt32 size = Header.FatSize - i;
@@ -656,7 +684,7 @@ HRESULT CDatabase::Open()
{
const UInt32 kBufSize = (UInt32)Header.CalcFatSizeInSectors() << Header.SectorSizeLog;
NumCurUsedBytes += kBufSize;
- byteBuf.SetCapacity(kBufSize);
+ byteBuf.Alloc(kBufSize);
Byte *p = byteBuf;
RINOK(ReadStream_FALSE(InStream, p, kBufSize));
UInt32 fatSize = Header.FatSize;
@@ -682,7 +710,10 @@ HRESULT CDatabase::Open()
if ((Fat[0] & 0xFF) != Header.MediaType)
return S_FALSE;
- return ReadDir(-1, Header.RootCluster, 0);
+ RINOK(ReadDir(-1, Header.RootCluster, 0));
+
+ PhySize = Header.GetPhySize();
+ return S_OK;
}
class CHandler:
@@ -710,7 +741,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
streamSpec->Size = item.Size;
UInt32 numClusters = Header.GetNumClusters(item.Size);
- streamSpec->Vector.Reserve(numClusters);
+ streamSpec->Vector.ClearAndReserve(numClusters);
UInt32 cluster = item.Cluster;
UInt32 size = item.Size;
@@ -726,7 +757,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
{
if (!Header.IsValidCluster(cluster))
return S_FALSE;
- streamSpec->Vector.Add(cluster - 2);
+ streamSpec->Vector.AddInReserved(cluster - 2);
cluster = Fat[cluster];
if (size <= clusterSize)
break;
@@ -740,17 +771,17 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
COM_TRY_END
}
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidCTime, VT_FILETIME},
- { NULL, kpidATime, VT_FILETIME},
- { NULL, kpidAttrib, VT_UI8},
- { NULL, kpidShortName, VT_BSTR}
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ kpidAttrib,
+ kpidShortName
};
enum
@@ -761,11 +792,10 @@ enum
// kpidFileSysType
};
-STATPROPSTG kArcProps[] =
+static const STATPROPSTG kArcProps[] =
{
{ NULL, kpidFileSystem, VT_BSTR},
{ NULL, kpidClusterSize, VT_UI4},
- { NULL, kpidPhySize, VT_UI8},
{ NULL, kpidFreeSpace, VT_UI8},
{ NULL, kpidHeadersSize, VT_UI8},
{ NULL, kpidMTime, VT_FILETIME},
@@ -819,16 +849,20 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
case kpidFileSystem:
{
- wchar_t s[32] = { L'F', L'A', L'T' };
+ 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 = Header.GetPhySize(); 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;
@@ -901,7 +935,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = Items.Size();
if (numItems == 0)
@@ -986,10 +1020,14 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"FAT", L"fat img", 0, 0xDA, { 0x55, 0xAA }, 2, false, CreateArc, 0 };
+ { "FAT", "fat img", 0, 0xDA,
+ 2, { 0x55, 0xAA },
+ 0x1FE,
+ 0,
+ CreateArc, NULL, IsArc_Fat };
REGISTER_ARC(Fat)
diff --git a/CPP/7zip/Archive/FlvHandler.cpp b/CPP/7zip/Archive/FlvHandler.cpp
index a22c29e3..3bb4620b 100755..100644
--- a/CPP/7zip/Archive/FlvHandler.cpp
+++ b/CPP/7zip/Archive/FlvHandler.cpp
@@ -4,13 +4,13 @@
#include "../../../C/CpuArch.h"
-#include "Common/Buffer.h"
-#include "Common/ComTry.h"
-// #include "Common/Defs.h"
-#include "Common/MyString.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyString.h"
-#include "Windows/PropVariant.h"
+#include "../../Windows/PropVariant.h"
+#include "../Common/InBuffer.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamObjects.h"
@@ -29,9 +29,9 @@ namespace NArchive {
namespace NFlv {
static const UInt32 kFileSizeMax = (UInt32)1 << 30;
-static const int kNumChunksMax = (UInt32)1 << 23;
+static const UInt32 kNumChunksMax = (UInt32)1 << 23;
-const UInt32 kTagHeaderSize = 11;
+static const UInt32 kTagHeaderSize = 11;
static const Byte kFlag_Video = 1;
static const Byte kFlag_Audio = 4;
@@ -39,13 +39,11 @@ static const Byte kFlag_Audio = 4;
static const Byte kType_Audio = 8;
static const Byte kType_Video = 9;
static const Byte kType_Meta = 18;
-static const int kNumTypes = 19;
+static const unsigned kNumTypes = 19;
struct CItem
{
- UInt32 Offset;
- UInt32 Size;
- // UInt32 Time;
+ CByteBuffer Data;
Byte Type;
};
@@ -55,7 +53,7 @@ struct CItem2
Byte SubType;
Byte Props;
bool SameSubTypes;
- int NumChunks;
+ unsigned NumChunks;
size_t Size;
CReferenceBuf *BufSpec;
@@ -69,10 +67,12 @@ class CHandler:
public IInArchiveGetStream,
public CMyUnknownImp
{
- int _isRaw;
CMyComPtr<IInStream> _stream;
CObjectVector<CItem2> _items2;
// CByteBuffer _metadata;
+ bool _isRaw;
+ UInt64 _phySize;
+
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
AString GetComment();
public:
@@ -81,76 +81,64 @@ public:
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
};
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidNumBlocks, VT_UI4},
- { NULL, kpidComment, VT_BSTR}
+ kpidSize,
+ kpidNumBlocks,
+ kpidComment
};
-/*
-STATPROPSTG kArcProps[] =
-{
- { NULL, kpidComment, VT_BSTR}
-};
-*/
-
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO
+IMP_IInArchive_ArcProps_NO_Table
static const char *g_AudioTypes[16] =
{
- "pcm",
- "adpcm",
- "mp3",
- "pcm_le",
- "nellymoser16",
- "nellymoser8",
- "nellymoser",
- "g711a",
- "g711m",
- "audio9",
- "aac",
- "speex",
- "audio12",
- "audio13",
- "mp3",
- "audio15"
+ "pcm"
+ , "adpcm"
+ , "mp3"
+ , "pcm_le"
+ , "nellymoser16"
+ , "nellymoser8"
+ , "nellymoser"
+ , "g711a"
+ , "g711m"
+ , "audio9"
+ , "aac"
+ , "speex"
+ , "audio12"
+ , "audio13"
+ , "mp3"
+ , "audio15"
};
static const char *g_VideoTypes[16] =
{
- "video0",
- "jpeg",
- "h263",
- "screen",
- "vp6",
- "vp6alpha",
- "screen2",
- "avc",
- "video8",
- "video9",
- "video10",
- "video11",
- "video12",
- "video13",
- "video14",
- "video15"
+ "video0"
+ , "jpeg"
+ , "h263"
+ , "screen"
+ , "vp6"
+ , "vp6alpha"
+ , "screen2"
+ , "avc"
+ , "video8"
+ , "video9"
+ , "video10"
+ , "video11"
+ , "video12"
+ , "video13"
+ , "video14"
+ , "video15"
};
static const char *g_Rates[4] =
{
- "5.5 kHz",
- "11 kHz",
- "22 kHz",
- "44 kHz"
+ "5.5 kHz"
+ , "11 kHz"
+ , "22 kHz"
+ , "44 kHz"
};
-static void MyStrCat(char *d, const char *s)
-{
- MyStringCopy(d + MyStringLen(d), s);
-}
-
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
NWindows::NCOM::CPropVariant prop;
@@ -170,13 +158,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidComment:
{
char sz[64];
- MyStringCopy(sz, (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) );
+ char *s = MyStpCpy(sz, (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) );
if (item.IsAudio())
{
- MyStrCat(sz, " ");
- MyStrCat(sz, g_Rates[(item.Props >> 2) & 3]);
- MyStrCat(sz, (item.Props & 2) ? " 16-bit" : " 8-bit");
- MyStrCat(sz, (item.Props & 1) ? " stereo" : " mono");
+ *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;
@@ -190,7 +178,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
AString CHandler::GetComment()
{
const Byte *p = _metadata;
- size_t size = _metadata.GetCapacity();
+ size_t size = _metadata.Size();
AString res;
if (size > 0)
{
@@ -264,24 +252,25 @@ AString CHandler::GetComment()
return res;
}
+*/
+
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
- COM_TRY_BEGIN
+ // COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
switch(propID)
{
- case kpidComment: prop = GetComment(); break;
+ // 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
+ // COM_TRY_END
}
-*/
HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
{
- CRecordVector<CItem> items;
-
const UInt32 kHeaderSize = 13;
Byte header[kHeaderSize];
RINOK(ReadStream_FALSE(stream, header, kHeaderSize));
@@ -291,69 +280,51 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
header[3] != 1 ||
(header[4] & 0xFA) != 0)
return S_FALSE;
- UInt32 offset = Get32(header + 5);
+ UInt64 offset = Get32(header + 5);
if (offset != 9 || Get32(header + 9) != 0)
return S_FALSE;
- offset += 4;
+ offset = kHeaderSize;
- CByteBuffer inBuf;
- size_t fileSize;
- {
- UInt64 fileSize64;
- RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize64));
- if (fileSize64 > kFileSizeMax)
- return S_FALSE;
-
- if (callback)
- RINOK(callback->SetTotal(NULL, &fileSize64))
-
- RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
- fileSize = (size_t)fileSize64;
- inBuf.SetCapacity(fileSize);
- for (size_t pos = 0; pos < fileSize;)
- {
- UInt64 offset64 = pos;
- if (callback)
- RINOK(callback->SetCompleted(NULL, &offset64))
- size_t rem = MyMin(fileSize - pos, (size_t)(1 << 20));
- RINOK(ReadStream_FALSE(stream, inBuf + pos, rem));
- pos += rem;
- }
- }
+ CInBuffer inBuf;
+ if (!inBuf.Create(1 << 15))
+ return E_OUTOFMEMORY;
+ inBuf.SetStream(stream);
+ CObjectVector<CItem> items;
int lasts[kNumTypes];
- int i;
+ unsigned i;
for (i = 0; i < kNumTypes; i++)
lasts[i] = -1;
- while (offset < fileSize)
+ _phySize = offset;
+ for (;;)
{
+ Byte buf[kTagHeaderSize];
CItem item;
- item.Offset = offset;
- const Byte *buf = inBuf + offset;
- offset += kTagHeaderSize;
- if (offset > fileSize)
- return S_FALSE;
-
+ if (inBuf.ReadBytes(buf, kTagHeaderSize) != kTagHeaderSize)
+ break;
item.Type = buf[0];
UInt32 size = Get24(buf + 1);
if (size < 1)
- return S_FALSE;
+ break;
// item.Time = Get24(buf + 4);
// item.Time |= (UInt32)buf[7] << 24;
if (Get24(buf + 8) != 0) // streamID
- return S_FALSE;
+ break;
UInt32 curSize = kTagHeaderSize + size + 4;
- item.Size = curSize;
-
- offset += curSize - kTagHeaderSize;
- if (offset > fileSize)
- return S_FALSE;
-
- if (Get32(buf + kTagHeaderSize + size) != kTagHeaderSize + size)
- return S_FALSE;
+ 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)
@@ -363,20 +334,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
else
{
if (item.Type != kType_Audio && item.Type != kType_Video)
- return S_FALSE;
+ break;
if (items.Size() >= kNumChunksMax)
return S_FALSE;
Byte firstByte = buf[kTagHeaderSize];
Byte subType, props;
if (item.Type == kType_Audio)
{
- subType = firstByte >> 4;
- props = firstByte & 0xF;
+ subType = (Byte)(firstByte >> 4);
+ props = (Byte)(firstByte & 0xF);
}
else
{
- subType = firstByte & 0xF;
- props = firstByte >> 4;
+ subType = (Byte)(firstByte & 0xF);
+ props = (Byte)(firstByte >> 4);
}
int last = lasts[item.Type];
if (last < 0)
@@ -401,7 +372,14 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
}
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++)
@@ -412,12 +390,12 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
{
if (!item2.SameSubTypes)
return S_FALSE;
- itemBuf.SetCapacity((size_t)item2.Size - (kTagHeaderSize + 4 + 1) * item2.NumChunks);
+ itemBuf.Alloc((size_t)item2.Size - (size_t)(kTagHeaderSize + 4 + 1) * item2.NumChunks);
item2.Size = 0;
}
else
{
- itemBuf.SetCapacity(kHeaderSize + (size_t)item2.Size);
+ itemBuf.Alloc(kHeaderSize + (size_t)item2.Size);
memcpy(itemBuf, header, kHeaderSize);
itemBuf[4] = item2.IsAudio() ? kFlag_Audio : kFlag_Video;
item2.Size = kHeaderSize;
@@ -428,8 +406,8 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
{
const CItem &item = items[i];
CItem2 &item2 = _items2[lasts[item.Type]];
- size_t size = item.Size;
- const Byte *src = inBuf + item.Offset;
+ size_t size = item.Data.Size();
+ const Byte *src = item.Data;
if (_isRaw)
{
src += kTagHeaderSize + 1;
@@ -464,6 +442,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal
STDMETHODIMP CHandler::Close()
{
+ _phySize = 0;
_stream.Release();
_items2.Clear();
// _metadata.SetCapacity(0);
@@ -480,7 +459,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items2.Size();
if (numItems == 0)
@@ -514,7 +493,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(extractCallback->PrepareOperation(askMode));
if (outStream)
{
- RINOK(WriteStream(outStream, item.BufSpec->Buf, item.BufSpec->Buf.GetCapacity()));
+ RINOK(WriteStream(outStream, item.BufSpec->Buf, item.BufSpec->Buf.Size()));
}
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
}
@@ -534,10 +513,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"FLV", L"flv", 0, 0xD6, { 'F', 'L', 'V' }, 3, false, CreateArc, 0 };
+ { "FLV", "flv", 0, 0xD6,
+ 4, { 'F', 'L', 'V', 1, },
+ 0,
+ 0,
+ CreateArc };
REGISTER_ARC(Flv)
diff --git a/CPP/7zip/Archive/GzHandler.cpp b/CPP/7zip/Archive/GzHandler.cpp
index ede6b01b..69b3c3be 100755..100644
--- a/CPP/7zip/Archive/GzHandler.cpp
+++ b/CPP/7zip/Archive/GzHandler.cpp
@@ -2,13 +2,16 @@
#include "StdAfx.h"
+// #include <stdio.h>
+
#include "../../../C/CpuArch.h"
-#include "Common/ComTry.h"
-#include "Common/StringConvert.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/Defs.h"
+#include "../../Common/StringConvert.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
@@ -26,13 +29,19 @@
using namespace NWindows;
+using namespace NCompress;
+using namespace NDeflate;
+
namespace NArchive {
namespace NGz {
-static const UInt16 kSignature = 0x8B1F;
+ 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 NHeader
-{
namespace NFlags
{
const Byte kIsText = 1 << 0;
@@ -40,6 +49,7 @@ namespace NHeader
const Byte kExtra = 1 << 2;
const Byte kName = 1 << 3;
const Byte kComment = 1 << 4;
+ const Byte kReserved = 0xE0;
}
namespace NExtraFlags
@@ -48,11 +58,6 @@ namespace NHeader
const Byte kFastest = 4;
}
- namespace NCompressionMethod
- {
- const Byte kDeflate = 8;
- }
-
namespace NHostOS
{
enum EEnum
@@ -79,30 +84,29 @@ namespace NHeader
kUnknown = 255
};
}
-}
static const char *kHostOSes[] =
{
- "FAT",
- "AMIGA",
- "VMS",
- "Unix",
- "VM/CMS",
- "Atari",
- "HPFS",
- "Macintosh",
- "Z-System",
- "CP/M",
- "TOPS-20",
- "NTFS",
- "SMS/QDOS",
- "Acorn",
- "VFAT",
- "MVS",
- "BeOS",
- "Tandem",
- "OS/400",
- "OS/X"
+ "FAT"
+ , "AMIGA"
+ , "VMS"
+ , "Unix"
+ , "VM/CMS"
+ , "Atari"
+ , "HPFS"
+ , "Macintosh"
+ , "Z-System"
+ , "CP/M"
+ , "TOPS-20"
+ , "NTFS"
+ , "SMS/QDOS"
+ , "Acorn"
+ , "VFAT"
+ , "MVS"
+ , "BeOS"
+ , "Tandem"
+ , "OS/400"
+ , "OS/X"
};
static const char *kUnknownOS = "Unknown";
@@ -111,7 +115,6 @@ class CItem
{
bool TestFlag(Byte flag) const { return (Flags & flag) != 0; }
public:
- Byte Method;
Byte Flags;
Byte ExtraFlags;
Byte HostOS;
@@ -123,11 +126,12 @@ public:
AString Comment;
// CByteBuffer Extra;
- // bool IsText() const { return TestFlag(NHeader::NFlags::kIsText); }
- bool HeaderCrcIsPresent() const { return TestFlag(NHeader::NFlags::kCrc); }
- bool ExtraFieldIsPresent() const { return TestFlag(NHeader::NFlags::kExtra); }
- bool NameIsPresent() const { return TestFlag(NHeader::NFlags::kName); }
- bool CommentIsPresent() const { return TestFlag(NHeader::NFlags::kComment); }
+ // 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; }
void Clear()
{
@@ -136,48 +140,48 @@ public:
// Extra.SetCapacity(0);
}
- HRESULT ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream);
- HRESULT ReadFooter1(NCompress::NDeflate::NDecoder::CCOMCoder *stream);
+ 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(NCompress::NDeflate::NDecoder::CCOMCoder *stream, Byte *data, UInt32 size)
+static HRESULT ReadBytes(NDecoder::CCOMCoder *stream, Byte *data, UInt32 size)
{
for (UInt32 i = 0; i < size; i++)
- data[i] = stream->ReadByte();
+ data[i] = stream->ReadAlignedByte();
return stream->InputEofError() ? S_FALSE : S_OK;
}
-static HRESULT SkipBytes(NCompress::NDeflate::NDecoder::CCOMCoder *stream, UInt32 size)
+static HRESULT SkipBytes(NDecoder::CCOMCoder *stream, UInt32 size)
{
for (UInt32 i = 0; i < size; i++)
- stream->ReadByte();
+ stream->ReadAlignedByte();
return stream->InputEofError() ? S_FALSE : S_OK;
}
-static HRESULT ReadUInt16(NCompress::NDeflate::NDecoder::CCOMCoder *stream, UInt16 &value /* , UInt32 &crc */)
+static HRESULT ReadUInt16(NDecoder::CCOMCoder *stream, UInt32 &value /* , UInt32 &crc */)
{
value = 0;
for (int i = 0; i < 2; i++)
{
- Byte b = stream->ReadByte();
+ Byte b = stream->ReadAlignedByte();
if (stream->InputEofError())
return S_FALSE;
// crc = CRC_UPDATE_BYTE(crc, b);
- value |= (UInt16(b) << (8 * i));
+ value |= ((UInt32)(b) << (8 * i));
}
return S_OK;
}
-static HRESULT ReadString(NCompress::NDeflate::NDecoder::CCOMCoder *stream, AString &s, UInt32 limit /* , UInt32 &crc */)
+static HRESULT ReadString(NDecoder::CCOMCoder *stream, AString &s, size_t limit /* , UInt32 &crc */)
{
s.Empty();
- for (UInt32 i = 0; i < limit; i++)
+ for (size_t i = 0; i < limit; i++)
{
- Byte b = stream->ReadByte();
+ Byte b = stream->ReadAlignedByte();
if (stream->InputEofError())
return S_FALSE;
// crc = CRC_UPDATE_BYTE(crc, b);
@@ -188,7 +192,134 @@ static HRESULT ReadString(NCompress::NDeflate::NDecoder::CCOMCoder *stream, AStr
return S_FALSE;
}
-HRESULT CItem::ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream)
+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();
@@ -198,15 +329,15 @@ HRESULT CItem::ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream)
RINOK(ReadBytes(stream, buf, 10));
- if (GetUi16(buf) != kSignature)
+ if (buf[0] != kSignature_0 ||
+ buf[1] != kSignature_1 ||
+ buf[2] != kSignature_2)
return S_FALSE;
- Method = buf[2];
-
- if (Method != NHeader::NCompressionMethod::kDeflate)
+ Flags = buf[3];
+ if (!IsSupported())
return S_FALSE;
- Flags = buf[3];
Time = Get32(buf + 4);
ExtraFlags = buf[8];
HostOS = buf[9];
@@ -215,21 +346,21 @@ HRESULT CItem::ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream)
if (ExtraFieldIsPresent())
{
- UInt16 extraSize;
- RINOK(ReadUInt16(stream, extraSize /* , crc */));
- RINOK(SkipBytes(stream, extraSize));
- // Extra.SetCapacity(extraSize);
- // RINOK(ReadStream_FALSE(stream, Extra, extraSize));
- // crc = CrcUpdate(crc, Extra, extraSize);
+ 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, (1 << 10) /* , crc */));
+ RINOK(ReadString(stream, Name, kNameMaxLen /* , crc */));
if (CommentIsPresent())
- RINOK(ReadString(stream, Comment, (1 << 16) /* , crc */));
+ RINOK(ReadString(stream, Comment, kCommentMaxLen /* , crc */));
if (HeaderCrcIsPresent())
{
- UInt16 headerCRC;
+ UInt32 headerCRC;
// UInt32 dummy = 0;
RINOK(ReadUInt16(stream, headerCRC /* , dummy */));
/*
@@ -240,7 +371,7 @@ HRESULT CItem::ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream)
return stream->InputEofError() ? S_FALSE : S_OK;
}
-HRESULT CItem::ReadFooter1(NCompress::NDeflate::NDecoder::CCOMCoder *stream)
+HRESULT CItem::ReadFooter1(NDecoder::CCOMCoder *stream)
{
Byte buf[8];
RINOK(ReadBytes(stream, buf, 8));
@@ -261,10 +392,11 @@ HRESULT CItem::ReadFooter2(ISequentialInStream *stream)
HRESULT CItem::WriteHeader(ISequentialOutStream *stream)
{
Byte buf[10];
- SetUi16(buf, kSignature);
- buf[2] = Method;
- buf[3] = Flags & NHeader::NFlags::kName;
- // buf[3] |= NHeader::NFlags::kCrc;
+ 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;
@@ -272,8 +404,8 @@ HRESULT CItem::WriteHeader(ISequentialOutStream *stream)
// crc = CrcUpdate(CRC_INIT_VAL, buf, 10);
if (NameIsPresent())
{
- // crc = CrcUpdate(crc, (const char *)Name, Name.Length() + 1);
- RINOK(WriteStream(stream, (const char *)Name, Name.Length() + 1));
+ // 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));
@@ -296,54 +428,93 @@ class CHandler:
public CMyUnknownImp
{
CItem _item;
- UInt64 _startPosition;
- UInt64 _headerSize;
+
+ bool _isArc;
+ bool _needSeekToStart;
+ bool _dataAfterEnd;
+ bool _needMoreInput;
+
+ bool _packSize_Defined;
+ bool _unpackSize_Defined;
+ bool _numStreams_Defined;
+
UInt64 _packSize;
- bool _packSizeDefined;
+ UInt64 _unpackSize; // real unpack size (NOT from footer)
+ UInt64 _numStreams;
+ UInt64 _headerSize; // only start header (without footer)
+
CMyComPtr<IInStream> _stream;
CMyComPtr<ICompressCoder> _decoder;
- NCompress::NDeflate::NDecoder::CCOMCoder *_decoderSpec;
+ NDecoder::CCOMCoder *_decoderSpec;
CSingleMethodProps _props;
public:
- MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties)
+ MY_UNKNOWN_IMP4(
+ IInArchive,
+ IArchiveOpenSeq,
+ IOutArchive,
+ ISetProperties)
INTERFACE_IInArchive(;)
INTERFACE_IOutArchive(;)
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
- STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps);
CHandler()
{
- _decoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder;
+ _decoderSpec = new NDecoder::CCOMCoder;
_decoder = _decoderSpec;
}
};
-static STATPROPSTG const kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidHostOS, VT_BSTR},
- { NULL, kpidCRC, VT_UI4}
- // { NULL, kpidComment, VT_BSTR}
-}
-;
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidHostOS,
+ kpidCRC
+ // kpidComment
+};
+
+static const Byte kArcProps[] =
+{
+ kpidHeadersSize,
+ kpidNumStreams
+};
+
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO_Table
+IMP_IInArchive_ArcProps
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
+ COM_TRY_BEGIN
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
- case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ 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())
+ prop = MultiByteToUnicodeString(_item.Name, CP_ACP) + L".gz";
+ break;
}
prop.Detach(value);
return S_OK;
+ COM_TRY_END
}
@@ -353,11 +524,11 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
-STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ NCOM::CPropVariant prop;
+ switch (propID)
{
case kpidPath:
if (_item.NameIsPresent())
@@ -365,7 +536,6 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIA
break;
// case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break;
case kpidMTime:
- {
if (_item.Time != 0)
{
FILETIME utc;
@@ -373,10 +543,21 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIA
prop = utc;
}
break;
+ case kpidSize:
+ {
+ if (_unpackSize_Defined)
+ prop = _unpackSize;
+ else if (_stream)
+ prop = (UInt64)_item.Size32;
+ break;
}
- case kpidSize: if (_stream) prop = (UInt64)_item.Size32; break;
- case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
- case kpidHostOS: prop = (_item.HostOS < sizeof(kHostOSes) / sizeof(kHostOSes[0])) ?
+ case kpidPackSize:
+ {
+ if (_packSize_Defined || _stream)
+ prop = _packSize;
+ break;
+ }
+ case kpidHostOS: prop = (_item.HostOS < ARRAY_SIZE(kHostOSes)) ?
kHostOSes[_item.HostOS] : kUnknownOS; break;
case kpidCRC: if (_stream) prop = _item.Crc; break;
}
@@ -385,56 +566,81 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIA
COM_TRY_END
}
-STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)
+class CCompressProgressInfoImp:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
{
- COM_TRY_BEGIN
- HRESULT res;
- try
+ CMyComPtr<IArchiveOpenCallback> Callback;
+public:
+ UInt64 Offset;
+ MY_UNKNOWN_IMP1(ICompressProgressInfo)
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+ void Init(IArchiveOpenCallback *callback) { Callback = callback; }
+};
+
+STDMETHODIMP CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)
+{
+ if (Callback)
{
- RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPosition));
- res = OpenSeq(stream);
- if (res == S_OK)
- {
- UInt64 endPos;
- res = stream->Seek(-8, STREAM_SEEK_END, &endPos);
- _packSize = endPos + 8 - _startPosition;
- _packSizeDefined = true;
- if (res == S_OK)
- {
- res = _item.ReadFooter2(stream);
- _stream = stream;
- }
- }
+ UInt64 files = 0;
+ UInt64 value = Offset + *inSize;
+ return Callback->SetCompleted(&files, &value);
}
- catch(...) { res = S_FALSE; }
- if (res != S_OK)
- Close();
- return res;
+ 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
- HRESULT res;
try
{
Close();
_decoderSpec->SetInStream(stream);
_decoderSpec->InitInStream(true);
- res = _item.ReadHeader(_decoderSpec);
+ RINOK(_item.ReadHeader(_decoderSpec));
+ if (_decoderSpec->InputEofError())
+ return S_FALSE;
_headerSize = _decoderSpec->GetInputProcessedSize();
+ _isArc = true;
+ return S_OK;
}
- catch(...) { res = S_FALSE; }
- if (res != S_OK)
- Close();
- return res;
+ catch(const CInBufferException &e) { return e.ErrorCode; }
COM_TRY_END
}
STDMETHODIMP CHandler::Close()
{
- _packSizeDefined = false;
+ _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;
@@ -446,13 +652,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_BEGIN
if (numItems == 0)
return S_OK;
- if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
- if (_stream)
- extractCallback->SetTotal(_packSize);
- UInt64 currentTotalPacked = 0;
- RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+ // if (_stream) extractCallback->SetTotal(_packSize);
+ // UInt64 currentTotalPacked = 0;
+ // RINOK(extractCallback->SetCompleted(&currentTotalPacked));
CMyComPtr<ISequentialOutStream> realOutStream;
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
@@ -473,71 +678,166 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, true);
- if (_stream)
+ bool needReadFirstItem = _needSeekToStart;
+
+ if (_needSeekToStart)
{
- RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ if (!_stream)
+ return E_FAIL;
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
_decoderSpec->InitInStream(true);
+ // printf("\nSeek");
}
+ else
+ _needSeekToStart = true;
+
bool firstItem = true;
- Int32 opRes;
+
+ 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 = _decoderSpec->GetInputProcessedSize();
- _packSizeDefined = true;
- lps->OutSize = outStreamSpec->GetSize();
+ lps->InSize = packSize;
+ lps->OutSize = unpackedSize;
+
RINOK(lps->SetCur());
CItem item;
- if (!firstItem || _stream)
+
+ if (!firstItem || needReadFirstItem)
{
- HRESULT result = item.ReadHeader(_decoderSpec);
+ 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)
{
- if (result != S_FALSE)
- return result;
- opRes = firstItem ?
- NExtract::NOperationResult::kDataError :
- NExtract::NOperationResult::kOK;
+ _dataAfterEnd = true;
break;
}
}
+
+ numStreams++;
firstItem = false;
UInt64 startOffset = outStreamSpec->GetSize();
outStreamSpec->InitCRC();
- HRESULT result = _decoderSpec->CodeResume(outStream, NULL, progress);
- if (result != S_OK)
+ result = _decoderSpec->CodeResume(outStream, NULL, progress);
+
+ packSize = _decoderSpec->GetInputProcessedSize();
+ unpackedSize = outStreamSpec->GetSize();
+
+ if (result != S_OK && result != S_FALSE)
+ return result;
+
+ if (_decoderSpec->InputEofError())
{
- if (result != S_FALSE)
- return result;
- opRes = NExtract::NOperationResult::kDataError;
- break;
+ packSize = _decoderSpec->GetStreamSize();
+ _needMoreInput = true;
+ result = S_FALSE;
}
+ if (result != S_OK)
+ break;
+
_decoderSpec->AlignToByte();
- if (item.ReadFooter1(_decoderSpec) != S_OK)
+
+ result = item.ReadFooter1(_decoderSpec);
+
+ packSize = _decoderSpec->GetInputProcessedSize();
+
+ if (result != S_OK && result != S_FALSE)
+ return result;
+
+ if (result != S_OK)
{
- opRes = NExtract::NOperationResult::kDataError;
+ if (_decoderSpec->InputEofError())
+ {
+ _needMoreInput = true;
+ result = S_FALSE;
+ }
break;
}
+
if (item.Crc != outStreamSpec->GetCRC() ||
- item.Size32 != (UInt32)(outStreamSpec->GetSize() - startOffset))
+ item.Size32 != (UInt32)(unpackedSize - startOffset))
{
- opRes = NExtract::NOperationResult::kCRCError;
+ crcError = true;
+ result = S_FALSE;
break;
}
}
+
+ } 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();
- return extractCallback->SetOperationResult(opRes);
+
+ 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
- NHeader::NHostOS::kFAT;
+ NHostOS::kFAT;
#else
- NHeader::NHostOS::kUnix;
+ NHostOS::kUnix;
#endif
static HRESULT UpdateArchive(
@@ -565,16 +865,15 @@ static HRESULT UpdateArchive(
lps->Init(updateCallback, true);
CItem item = newItem;
- item.Method = NHeader::NCompressionMethod::kDeflate;
item.ExtraFlags = props.GetLevel() >= 7 ?
- NHeader::NExtraFlags::kMaximum :
- NHeader::NExtraFlags::kFastest;
+ NExtraFlags::kMaximum :
+ NExtraFlags::kFastest;
item.HostOS = kHostOS;
RINOK(item.WriteHeader(outStream));
- NCompress::NDeflate::NEncoder::CCOMCoder *deflateEncoderSpec = new NCompress::NDeflate::NEncoder::CCOMCoder;
+ NEncoder::CCOMCoder *deflateEncoderSpec = new NEncoder::CCOMCoder;
CMyComPtr<ICompressCoder> deflateEncoder = deflateEncoderSpec;
RINOK(props.SetCoderProps(deflateEncoderSpec, NULL));
RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress));
@@ -582,7 +881,7 @@ static HRESULT UpdateArchive(
item.Crc = inStreamSpec->GetCRC();
item.Size32 = (UInt32)inStreamSpec->GetSize();
RINOK(item.WriteFooter(outStream));
- return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
+ return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK);
}
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
@@ -609,13 +908,14 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (IntToBool(newProps))
{
{
- FILETIME utcTime;
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(0, kpidMTime, &prop));
- if (prop.vt != VT_FILETIME)
+ if (prop.vt == VT_FILETIME)
+ NTime::FileTimeToUnixTime(prop.filetime, newItem.Time);
+ else if (prop.vt == VT_EMPTY)
+ newItem.Time = 0;
+ else
return E_INVALIDARG;
- utcTime = prop.filetime;
- NTime::FileTimeToUnixTime(utcTime, newItem.Time);
}
{
NCOM::CPropVariant prop;
@@ -623,12 +923,12 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (prop.vt == VT_BSTR)
{
UString name = prop.bstrVal;
- int dirDelimiterPos = name.ReverseFind(CHAR_PATH_SEPARATOR);
+ int dirDelimiterPos = name.ReverseFind(WCHAR_PATH_SEPARATOR);
if (dirDelimiterPos >= 0)
- name = name.Mid(dirDelimiterPos + 1);
+ name = name.Ptr(dirDelimiterPos + 1);
newItem.Name = UnicodeStringToMultiByte(name, CP_ACP);
if (!newItem.Name.IsEmpty())
- newItem.Flags |= NHeader::NFlags::kName;
+ newItem.Flags |= NFlags::kName;
}
else if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
@@ -665,7 +965,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (!_stream)
return E_NOTIMPL;
- UInt64 offset = _startPosition;
+ UInt64 offset = 0;
if (IntToBool(newProps))
{
newItem.WriteHeader(outStream);
@@ -675,20 +975,20 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return NCompress::CopyStream(_stream, outStream, NULL);
}
-STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
{
return _props.SetProperties(names, values, numProps);
}
-static IInArchive *CreateArc() { return new CHandler; }
-#ifndef EXTRACT_ONLY
-static IOutArchive *CreateArcOut() { return new CHandler; }
-#else
-#define CreateArcOut 0
-#endif
+IMP_CreateArcIn
+IMP_CreateArcOut
static CArcInfo g_ArcInfo =
- { L"gzip", L"gz gzip tgz tpz", L"* * .tar .tar", 0xEF, { 0x1F, 0x8B, 8 }, 3, true, CreateArc, CreateArcOut };
+ { "gzip", "gz gzip tgz tpz", "* * .tar .tar", 0xEF,
+ 3, { kSignature_0, kSignature_1, kSignature_2 },
+ 0,
+ NArcInfoFlags::kKeepName,
+ REF_CreateArc_Pair, IsArc_Gz };
REGISTER_ARC(GZip)
diff --git a/CPP/7zip/Archive/Hfs/HfsHandler.cpp b/CPP/7zip/Archive/Hfs/HfsHandler.cpp
deleted file mode 100755
index f226458d..00000000
--- a/CPP/7zip/Archive/Hfs/HfsHandler.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-// HfsHandler.cpp
-
-#include "StdAfx.h"
-
-#include "Common/ComTry.h"
-#include "Windows/PropVariant.h"
-#include "../../Common/StreamUtils.h"
-#include "HfsHandler.h"
-
-namespace NArchive {
-namespace NHfs {
-
-STATPROPSTG kProps[] =
-{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidCTime, VT_FILETIME},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidATime, VT_FILETIME}
-};
-
-STATPROPSTG kArcProps[] =
-{
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidClusterSize, VT_UI4},
- { NULL, kpidFreeSpace, VT_UI8},
- { NULL, kpidCTime, VT_FILETIME},
- { NULL, kpidMTime, VT_FILETIME}
-};
-
-IMP_IInArchive_Props
-IMP_IInArchive_ArcProps
-
-static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop)
-{
- FILETIME ft;
- HfsTimeToFileTime(hfsTime, ft);
- prop = ft;
-}
-
-STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
-{
- COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- switch(propID)
- {
- case kpidMethod: prop = _db.Header.IsHfsX() ? L"HFSX" : L"HFS+"; break;
- case kpidClusterSize: prop = (UInt32)1 << _db.Header.BlockSizeLog; break;
- case kpidFreeSpace: prop = (UInt64)_db.Header.NumFreeBlocks << _db.Header.BlockSizeLog; break;
- case kpidMTime: HfsTimeToProp(_db.Header.MTime, prop); break;
- case kpidCTime:
- {
- FILETIME localFt, ft;
- HfsTimeToFileTime(_db.Header.CTime, localFt);
- if (LocalFileTimeToFileTime(&localFt, &ft))
- prop = ft;
- break;
- }
- }
- prop.Detach(value);
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
-{
- COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- const CItem &item = _db.Items[index];
- switch(propID)
- {
- case kpidPath: prop = _db.GetItemPath(index); break;
- case kpidIsDir: prop = item.IsDir(); break;
-
- case kpidCTime: HfsTimeToProp(item.CTime, prop); break;
- case kpidMTime: HfsTimeToProp(item.MTime, prop); break;
- case kpidATime: HfsTimeToProp(item.ATime, prop); break;
-
- case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumBlocks << _db.Header.BlockSizeLog; break;
- case kpidSize: if (!item.IsDir()) prop = item.Size; break;
- }
- prop.Detach(value);
- return S_OK;
- COM_TRY_END
-}
-
-class CProgressImp: public CProgressVirt
-{
- CMyComPtr<IArchiveOpenCallback> _callback;
-public:
- HRESULT SetTotal(UInt64 numFiles);
- HRESULT SetCompleted(UInt64 numFiles);
- CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {}
-};
-
-HRESULT CProgressImp::SetTotal(UInt64 numFiles)
-{
- if (_callback)
- return _callback->SetTotal(&numFiles, NULL);
- return S_OK;
-}
-
-HRESULT CProgressImp::SetCompleted(UInt64 numFiles)
-{
- if (_callback)
- return _callback->SetCompleted(&numFiles, NULL);
- return S_OK;
-}
-
-STDMETHODIMP CHandler::Open(IInStream *inStream,
- const UInt64 * /* maxCheckStartPosition */,
- IArchiveOpenCallback *callback)
-{
- COM_TRY_BEGIN
- Close();
- try
- {
- CProgressImp progressImp(callback);
- HRESULT res = _db.Open(inStream, &progressImp);
- if (res == E_ABORT)
- return res;
- if (res != S_OK)
- return S_FALSE;
- _stream = inStream;
- }
- catch(...) { return S_FALSE; }
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::Close()
-{
- _stream.Release();
- _db.Clear();
- return S_OK;
-}
-
-STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
- Int32 testMode, IArchiveExtractCallback *extractCallback)
-{
- COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
- if (allFilesMode)
- numItems = _db.Items.Size();
- if (numItems == 0)
- return S_OK;
- UInt32 i;
- UInt64 totalSize = 0;
- for (i = 0; i < numItems; i++)
- {
- const CItem &item = _db.Items[allFilesMode ? i : indices[i]];
- if (!item.IsDir())
- totalSize += item.Size;
- }
- RINOK(extractCallback->SetTotal(totalSize));
-
- UInt64 currentTotalSize = 0, currentItemSize = 0;
-
- CByteBuffer buf;
- const UInt32 kBufSize = (1 << 16);
- buf.SetCapacity(kBufSize);
-
- for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
- {
- RINOK(extractCallback->SetCompleted(&currentTotalSize));
- Int32 index = allFilesMode ? i : indices[i];
- const CItem &item = _db.Items[index];
- currentItemSize = 0;
- if (!item.IsDir())
- currentItemSize = item.Size;
-
- CMyComPtr<ISequentialOutStream> realOutStream;
- Int32 askMode = testMode ?
- NExtract::NAskMode::kTest :
- NExtract::NAskMode::kExtract;
- RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
-
- if (item.IsDir())
- {
- RINOK(extractCallback->PrepareOperation(askMode));
- RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
- continue;
- }
- if (!testMode && !realOutStream)
- continue;
- RINOK(extractCallback->PrepareOperation(askMode));
- UInt64 pos = 0;
- int res = NExtract::NOperationResult::kOK;
- int i;
- for (i = 0; i < item.Extents.Size(); i++)
- {
- if (item.Size == pos)
- break;
- if (res != NExtract::NOperationResult::kOK)
- break;
- const CExtent &e = item.Extents[i];
- RINOK(_stream->Seek((UInt64)e.Pos << _db.Header.BlockSizeLog, STREAM_SEEK_SET, NULL));
- UInt64 extentSize = (UInt64)e.NumBlocks << _db.Header.BlockSizeLog;
- for (;;)
- {
- if (extentSize == 0)
- break;
- UInt64 rem = item.Size - pos;
- if (rem == 0)
- {
- if (extentSize >= (UInt64)((UInt32)1 << _db.Header.BlockSizeLog))
- res = NExtract::NOperationResult::kDataError;
- break;
- }
- UInt32 curSize = kBufSize;
- if (curSize > rem)
- curSize = (UInt32)rem;
- if (curSize > extentSize)
- curSize = (UInt32)extentSize;
- RINOK(ReadStream_FALSE(_stream, buf, curSize));
- if (realOutStream)
- {
- RINOK(WriteStream(realOutStream, buf, curSize));
- }
- pos += curSize;
- extentSize -= curSize;
- UInt64 processed = currentTotalSize + pos;
- RINOK(extractCallback->SetCompleted(&processed));
- }
- }
- if (i != item.Extents.Size() || item.Size != pos)
- res = NExtract::NOperationResult::kDataError;
- realOutStream.Release();
- RINOK(extractCallback->SetOperationResult(res));
- }
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
-{
- *numItems = _db.Items.Size();
- return S_OK;
-}
-
-}}
diff --git a/CPP/7zip/Archive/Hfs/HfsHandler.h b/CPP/7zip/Archive/Hfs/HfsHandler.h
deleted file mode 100755
index 269af218..00000000
--- a/CPP/7zip/Archive/Hfs/HfsHandler.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// HfsHandler.h
-
-#ifndef __ARCHIVE_HFS_HANDLER_H
-#define __ARCHIVE_HFS_HANDLER_H
-
-#include "Common/MyCom.h"
-#include "../IArchive.h"
-#include "HfsIn.h"
-
-namespace NArchive {
-namespace NHfs {
-
-class CHandler:
- public IInArchive,
- public CMyUnknownImp
-{
- CMyComPtr<IInStream> _stream;
- CDatabase _db;
-public:
- MY_UNKNOWN_IMP1(IInArchive)
- INTERFACE_IInArchive(;)
-};
-
-}}
-
-#endif
diff --git a/CPP/7zip/Archive/Hfs/HfsIn.cpp b/CPP/7zip/Archive/Hfs/HfsIn.cpp
deleted file mode 100755
index 8391dd93..00000000
--- a/CPP/7zip/Archive/Hfs/HfsIn.cpp
+++ /dev/null
@@ -1,480 +0,0 @@
-// HfsIn.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/StreamUtils.h"
-#include "Common/IntToString.h"
-
-#include "HfsIn.h"
-
-#include "../../../../C/CpuArch.h"
-
-#define Get16(p) GetBe16(p)
-#define Get32(p) GetBe32(p)
-#define Get64(p) GetBe64(p)
-
-namespace NArchive {
-namespace NHfs {
-
-#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
-
-static int CompareIdToIndex(const CIdIndexPair *p1, const CIdIndexPair *p2, void * /* param */)
-{
- RINOZ(MyCompare(p1->ID, p2->ID));
- return MyCompare(p1->Index, p2->Index);
-}
-
-bool operator< (const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID < a2.ID); }
-bool operator> (const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID > a2.ID); }
-bool operator==(const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID == a2.ID); }
-bool operator!=(const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID != a2.ID); }
-
-static UString GetSpecName(const UString &name, UInt32 /* id */)
-{
- UString name2 = name;
- name2.Trim();
- if (name2.IsEmpty())
- {
- /*
- wchar_t s[32];
- ConvertUInt64ToString(id, s);
- return L"[" + (UString)s + L"]";
- */
- return L"[]";
- }
- return name;
-}
-
-UString CDatabase::GetItemPath(int index) const
-{
- const CItem *item = &Items[index];
- UString name = GetSpecName(item->Name, item->ID);
-
- for (int i = 0; i < 1000; i++)
- {
- if (item->ParentID < 16 && item->ParentID != 2)
- {
- if (item->ParentID != 1)
- break;
- return name;
- }
- CIdIndexPair pair;
- pair.ID = item->ParentID;
- pair.Index = 0;
- int indexInMap = IdToIndexMap.FindInSorted(pair);
- if (indexInMap < 0)
- break;
- item = &Items[IdToIndexMap[indexInMap].Index];
- name = GetSpecName(item->Name, item->ID) + WCHAR_PATH_SEPARATOR + name;
- }
- return (UString)L"Unknown" + WCHAR_PATH_SEPARATOR + name;
-}
-
-void CFork::Parse(const Byte *p)
-{
- Size = Get64(p);
- // ClumpSize = Get32(p + 8);
- NumBlocks = Get32(p + 0xC);
- for (int i = 0; i < 8; i++)
- {
- CExtent &e = Extents[i];
- e.Pos = Get32(p + 0x10 + i * 8);
- e.NumBlocks = Get32(p + 0x10 + i * 8 + 4);
- }
-}
-
-static HRESULT ReadExtent(int blockSizeLog, IInStream *inStream, Byte *buf, const CExtent &e)
-{
- RINOK(inStream->Seek((UInt64)e.Pos << blockSizeLog, STREAM_SEEK_SET, NULL));
- return ReadStream_FALSE(inStream, buf, (size_t)e.NumBlocks << blockSizeLog);
-}
-
-HRESULT CDatabase::ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream)
-{
- if (fork.NumBlocks >= Header.NumBlocks)
- return S_FALSE;
- size_t totalSize = (size_t)fork.NumBlocks << Header.BlockSizeLog;
- if ((totalSize >> Header.BlockSizeLog) != fork.NumBlocks)
- return S_FALSE;
- buf.SetCapacity(totalSize);
- UInt32 curBlock = 0;
- for (int i = 0; i < 8; i++)
- {
- if (curBlock >= fork.NumBlocks)
- break;
- const CExtent &e = fork.Extents[i];
- if (fork.NumBlocks - curBlock < e.NumBlocks || e.Pos >= Header.NumBlocks)
- return S_FALSE;
- RINOK(ReadExtent(Header.BlockSizeLog, inStream,
- (Byte *)buf + ((size_t)curBlock << Header.BlockSizeLog), e));
- curBlock += e.NumBlocks;
- }
- return S_OK;
-}
-
-struct CNodeDescriptor
-{
- UInt32 fLink;
- UInt32 bLink;
- Byte Kind;
- Byte Height;
- UInt16 NumRecords;
- // UInt16 Reserved;
- void Parse(const Byte *p);
-};
-
-void CNodeDescriptor::Parse(const Byte *p)
-{
- fLink = Get32(p);
- bLink = Get32(p + 4);
- Kind = p[8];
- Height = p[9];
- NumRecords = Get16(p + 10);
-}
-
-struct CHeaderRec
-{
- // UInt16 TreeDepth;
- // UInt32 RootNode;
- // UInt32 LeafRecords;
- UInt32 FirstLeafNode;
- // UInt32 LastLeafNode;
- int NodeSizeLog;
- // UInt16 MaxKeyLength;
- UInt32 TotalNodes;
- // UInt32 FreeNodes;
- // UInt16 Reserved1;
- // UInt32 ClumpSize;
- // Byte BtreeType;
- // Byte KeyCompareType;
- // UInt32 Attributes;
- // UInt32 Reserved3[16];
-
- HRESULT Parse(const Byte *p);
-};
-
-HRESULT CHeaderRec::Parse(const Byte *p)
-{
- // TreeDepth = Get16(p);
- // RootNode = Get32(p + 2);
- // LeafRecords = Get32(p + 6);
- FirstLeafNode = Get32(p + 0xA);
- // LastLeafNode = Get32(p + 0xE);
- UInt32 nodeSize = Get16(p + 0x12);
-
- int i;
- for (i = 9; ((UInt32)1 << i) != nodeSize; i++)
- if (i == 16)
- return S_FALSE;
- NodeSizeLog = i;
-
- // MaxKeyLength = Get16(p + 0x14);
- TotalNodes = Get32(p + 0x16);
- // FreeNodes = Get32(p + 0x1A);
- // Reserved1 = Get16(p + 0x1E);
- // ClumpSize = Get32(p + 0x20);
- // BtreeType = p[0x24];
- // KeyCompareType = p[0x25];
- // Attributes = Get32(p + 0x26);
- /*
- for (int i = 0; i < 16; i++)
- Reserved3[i] = Get32(p + 0x2A + i * 4);
- */
- return S_OK;
-}
-
-
-enum ENodeType
-{
- NODE_TYPE_LEAF = 0xFF,
- NODE_TYPE_INDEX = 0,
- NODE_TYPE_HEADER = 1,
- NODE_TYPE_MODE = 2
-};
-
-HRESULT CDatabase::LoadExtentFile(IInStream *inStream)
-{
- // FileExtents.Clear();
- // ResExtents.Clear();
-
- CByteBuffer extents;
- RINOK(ReadFile(Header.ExtentsFile, extents, inStream));
-
- const Byte *p = (const Byte *)extents;
-
- // CNodeDescriptor nodeDesc;
- // nodeDesc.Parse(p);
- CHeaderRec hr;
- RINOK(hr.Parse(p + 14));
-
- UInt32 node = hr.FirstLeafNode;
- if (node != 0)
- return S_FALSE;
- /*
- while (node != 0)
- {
- size_t nodeOffset = node * hr.NodeSize;
- if ((node + 1)* hr.NodeSize > CatalogBuf.GetCapacity())
- return S_FALSE;
- CNodeDescriptor desc;
- desc.Parse(p + nodeOffset);
- if (desc.Kind != NODE_TYPE_LEAF)
- return S_FALSE;
- UInt32 ptr = hr.NodeSize;
- for (int i = 0; i < desc.NumRecords; i++)
- {
- UInt32 offs = Get16(p + nodeOffset + hr.NodeSize - (i + 1) * 2);
- UInt32 offsNext = Get16(p + nodeOffset + hr.NodeSize - (i + 2) * 2);
-
- const Byte *r = p + nodeOffset + offs;
- int keyLength = Get16(r);
- Byte forkType = r[2];
- UInt32 id = Get16(r + 4);
- UInt32 startBlock = Get16(r + 4);
- CObjectVector<CIdExtents> *extents = (forkType == 0) ? &FileExtents : &ResExtents;
- if (extents->Size() == 0)
- extents->Add(CIdExtents());
- else
- {
- CIdExtents &e = extents->Back();
- if (e.ID != id)
- {
- if (e.ID > id)
- return S_FALSE;
- extents->Add(CIdExtents());
- }
- }
- CIdExtents &e = extents->Back();
- for (UInt32 k = offs + 10 + 2; k + 8 <= offsNext; k += 8)
- {
- CExtent ee;
- ee.Pos = Get32(p + nodeOffset + k);
- ee.NumBlocks = Get32(p + nodeOffset + k * 4);
- e.Extents.Add(ee);
- }
- }
- node = desc.fLink;
- }
- */
- return S_OK;
-}
-
-
-HRESULT CDatabase::LoadCatalog(IInStream *inStream, CProgressVirt *progress)
-{
- Items.Clear();
- IdToIndexMap.ClearAndFree();
-
- CByteBuffer catalogBuf;
- RINOK(ReadFile(Header.CatalogFile, catalogBuf, inStream));
- const Byte *p = (const Byte *)catalogBuf;
-
- // CNodeDescriptor nodeDesc;
- // nodeDesc.Parse(p);
- CHeaderRec hr;
- hr.Parse(p + 14);
-
- // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC);
-
- if ((catalogBuf.GetCapacity() >> hr.NodeSizeLog) < hr.TotalNodes)
- return S_FALSE;
-
- CByteBuffer usedBuf;
- usedBuf.SetCapacity(hr.TotalNodes);
- for (UInt32 i = 0; i < hr.TotalNodes; i++)
- usedBuf[i] = 0;
-
- UInt32 node = hr.FirstLeafNode;
- while (node != 0)
- {
- if (node >= hr.TotalNodes)
- return S_FALSE;
- if (usedBuf[node])
- return S_FALSE;
- usedBuf[node] = 1;
- size_t nodeOffset = (size_t)node << hr.NodeSizeLog;
- CNodeDescriptor desc;
- desc.Parse(p + nodeOffset);
- if (desc.Kind != NODE_TYPE_LEAF)
- return S_FALSE;
- for (int i = 0; i < desc.NumRecords; i++)
- {
- UInt32 nodeSize = (1 << hr.NodeSizeLog);
- UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2);
- UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2);
- UInt32 recSize = offsNext - offs;
- if (offsNext >= nodeSize || offsNext < offs || recSize < 6)
- return S_FALSE;
-
- CItem item;
-
- const Byte *r = p + nodeOffset + offs;
- UInt32 keyLength = Get16(r);
- item.ParentID = Get32(r + 2);
- UString name;
- if (keyLength < 6 || (keyLength & 1) != 0 || keyLength + 2 > recSize)
- return S_FALSE;
- r += 6;
- recSize -= 6;
- keyLength -= 6;
-
- int nameLength = Get16(r);
- if (nameLength * 2 != (int)keyLength)
- return S_FALSE;
- r += 2;
- recSize -= 2;
-
- wchar_t *pp = name.GetBuffer(nameLength + 1);
-
- int j;
- for (j = 0; j < nameLength; j++)
- pp[j] = ((wchar_t)r[j * 2] << 8) | r[j * 2 + 1];
- pp[j] = 0;
- name.ReleaseBuffer();
- r += j * 2;
- recSize -= j * 2;
-
- if (recSize < 2)
- return S_FALSE;
- item.Type = Get16(r);
-
- if (item.Type != RECORD_TYPE_FOLDER && item.Type != RECORD_TYPE_FILE)
- continue;
- if (recSize < 0x58)
- return S_FALSE;
-
- // item.Flags = Get16(r + 2);
- // item.Valence = Get32(r + 4);
- item.ID = Get32(r + 8);
- item.CTime = Get32(r + 0xC);
- item.MTime = Get32(r + 0x10);
- // item.AttrMTime = Get32(r + 0x14);
- item.ATime = Get32(r + 0x18);
- // item.BackupDate = Get32(r + 0x1C);
-
- /*
- item.OwnerID = Get32(r + 0x20);
- item.GroupID = Get32(r + 0x24);
- item.AdminFlags = r[0x28];
- item.OwnerFlags = r[0x29];
- item.FileMode = Get16(r + 0x2A);
- item.special.iNodeNum = Get16(r + 0x2C);
- */
-
- item.Name = name;
-
- if (item.IsDir())
- {
- CIdIndexPair pair;
- pair.ID = item.ID;
- pair.Index = Items.Size();
- IdToIndexMap.Add(pair);
- }
- else
- {
- CFork fd;
- recSize -= 0x58;
- r += 0x58;
- if (recSize < 0x50 * 2)
- return S_FALSE;
- fd.Parse(r);
- item.Size = fd.Size;
- item.NumBlocks = fd.NumBlocks;
- UInt32 curBlock = 0;
- for (int j = 0; j < 8; j++)
- {
- if (curBlock >= fd.NumBlocks)
- break;
- const CExtent &e = fd.Extents[j];
- item.Extents.Add(e);
- curBlock += e.NumBlocks;
- }
- }
- Items.Add(item);
- if (progress && Items.Size() % 100 == 0)
- {
- RINOK(progress->SetCompleted(Items.Size()));
- }
- }
- node = desc.fLink;
- }
- IdToIndexMap.Sort(CompareIdToIndex, NULL);
- return S_OK;
-}
-
-HRESULT CDatabase::Open(IInStream *inStream, CProgressVirt *progress)
-{
- static const UInt32 kHeaderSize = 1024 + 512;
- Byte buf[kHeaderSize];
- RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize));
- int i;
- for (i = 0; i < 1024; i++)
- if (buf[i] != 0)
- return S_FALSE;
- const Byte *p = buf + 1024;
- CVolHeader &h = Header;
-
- h.Header[0] = p[0];
- h.Header[1] = p[1];
- if (p[0] != 'H' || (p[1] != '+' && p[1] != 'X'))
- return S_FALSE;
- h.Version = Get16(p + 2);
- if (h.Version < 4 || h.Version > 5)
- return S_FALSE;
-
- // h.Attr = Get32(p + 4);
- // h.LastMountedVersion = Get32(p + 8);
- // h.JournalInfoBlock = Get32(p + 0xC);
-
- h.CTime = Get32(p + 0x10);
- h.MTime = Get32(p + 0x14);
- // h.BackupTime = Get32(p + 0x18);
- // h.CheckedTime = Get32(p + 0x1C);
-
- // h.NumFiles = Get32(p + 0x20);
- // h.NumFolders = Get32(p + 0x24);
-
- UInt32 numFiles = Get32(p + 0x20);
- UInt32 numFolders = Get32(p + 0x24);;
- if (progress)
- {
- RINOK(progress->SetTotal(numFolders + numFiles));
- }
-
- UInt32 blockSize = Get32(p + 0x28);
-
- for (i = 9; ((UInt32)1 << i) != blockSize; i++)
- if (i == 31)
- return S_FALSE;
- h.BlockSizeLog = i;
-
- h.NumBlocks = Get32(p + 0x2C);
- h.NumFreeBlocks = Get32(p + 0x30);
-
- /*
- h.WriteCount = Get32(p + 0x44);
- for (i = 0; i < 6; i++)
- h.FinderInfo[i] = Get32(p + 0x50 + i * 4);
- h.VolID = Get64(p + 0x68);
- */
-
- UInt64 endPos;
- RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
- if ((endPos >> h.BlockSizeLog) < h.NumBlocks)
- return S_FALSE;
-
- // h.AllocationFile.Parse(p + 0x70 + 0x50 * 0);
- h.ExtentsFile.Parse( p + 0x70 + 0x50 * 1);
- h.CatalogFile.Parse( p + 0x70 + 0x50 * 2);
- // h.AttributesFile.Parse(p + 0x70 + 0x50 * 3);
- // h.StartupFile.Parse( p + 0x70 + 0x50 * 4);
-
- RINOK(LoadExtentFile(inStream));
- RINOK(LoadCatalog(inStream, progress));
-
- // if (Header.NumFiles + Header.NumFolders != (UInt32)Items.Size()) return S_OK;
-
- return S_OK;
-}
-
-}}
diff --git a/CPP/7zip/Archive/Hfs/HfsIn.h b/CPP/7zip/Archive/Hfs/HfsIn.h
deleted file mode 100755
index c1953905..00000000
--- a/CPP/7zip/Archive/Hfs/HfsIn.h
+++ /dev/null
@@ -1,154 +0,0 @@
-// HfsIn.h
-
-#ifndef __ARCHIVE_HFS_IN_H
-#define __ARCHIVE_HFS_IN_H
-
-#include "Common/MyString.h"
-#include "Common/Buffer.h"
-
-namespace NArchive {
-namespace NHfs {
-
-struct CExtent
-{
- UInt32 Pos;
- UInt32 NumBlocks;
-};
-
-struct CFork
-{
- UInt64 Size;
- // UInt32 ClumpSize;
- UInt32 NumBlocks;
- CExtent Extents[8];
- void Parse(const Byte *p);
-};
-
-struct CVolHeader
-{
- Byte Header[2];
- UInt16 Version;
- // UInt32 Attr;
- // UInt32 LastMountedVersion;
- // UInt32 JournalInfoBlock;
-
- UInt32 CTime;
- UInt32 MTime;
- // UInt32 BackupTime;
- // UInt32 CheckedTime;
-
- // UInt32 NumFiles;
- // UInt32 NumFolders;
- int BlockSizeLog;
- UInt32 NumBlocks;
- UInt32 NumFreeBlocks;
-
- // UInt32 WriteCount;
- // UInt32 FinderInfo[8];
- // UInt64 VolID;
-
- // CFork AllocationFile;
- CFork ExtentsFile;
- CFork CatalogFile;
- // CFork AttributesFile;
- // CFork StartupFile;
-
- bool IsHfsX() const { return Version > 4; }
-};
-
-inline void HfsTimeToFileTime(UInt32 hfsTime, FILETIME &ft)
-{
- UInt64 v = ((UInt64)3600 * 24 * (365 * 303 + 24 * 3) + hfsTime) * 10000000;
- ft.dwLowDateTime = (DWORD)v;
- ft.dwHighDateTime = (DWORD)(v >> 32);
-}
-
-enum ERecordType
-{
- RECORD_TYPE_FOLDER = 1,
- RECORD_TYPE_FILE = 2,
- RECORD_TYPE_FOLDER_THREAD = 3,
- RECORD_TYPE_FILE_THREAD = 4
-};
-
-struct CItem
-{
- UString Name;
-
- UInt32 ParentID;
-
- UInt16 Type;
- // UInt16 Flags;
- // UInt32 Valence;
- UInt32 ID;
- UInt32 CTime;
- UInt32 MTime;
- // UInt32 AttrMTime;
- UInt32 ATime;
- // UInt32 BackupDate;
-
- /*
- UInt32 OwnerID;
- UInt32 GroupID;
- Byte AdminFlags;
- Byte OwnerFlags;
- UInt16 FileMode;
- union
- {
- UInt32 iNodeNum;
- UInt32 LinkCount;
- UInt32 RawDevice;
- } special;
- */
-
- UInt64 Size;
- UInt32 NumBlocks;
- CRecordVector<CExtent> Extents;
-
- bool IsDir() const { return Type == RECORD_TYPE_FOLDER; }
- CItem(): Size(0), NumBlocks(0) {}
-};
-
-struct CIdIndexPair
-{
- UInt32 ID;
- int Index;
-};
-
-struct CProgressVirt
-{
- virtual HRESULT SetTotal(UInt64 numFiles) PURE;
- virtual HRESULT SetCompleted(UInt64 numFiles) PURE;
-};
-
-class CDatabase
-{
- // CObjectVector<CIdExtents> FileExtents;
- // CObjectVector<CIdExtents> ResExtents;
- CRecordVector<CIdIndexPair> IdToIndexMap;
-
- HRESULT LoadExtentFile(IInStream *inStream);
- HRESULT LoadCatalog(IInStream *inStream, CProgressVirt *progress);
-
- HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream);
-public:
- CVolHeader Header;
- CObjectVector<CItem> Items;
- // bool CaseSensetive;
-
- void Clear()
- {
- // CaseSensetive = false;
- Items.Clear();
- // FileExtents.Clear();
- // ResExtents.Clear();
- IdToIndexMap.Clear();
- }
-
- UString GetItemPath(int index) const;
- HRESULT Open(IInStream *inStream, CProgressVirt *progress);
-};
-
-}}
-
-#endif
diff --git a/CPP/7zip/Archive/Hfs/HfsRegister.cpp b/CPP/7zip/Archive/Hfs/HfsRegister.cpp
deleted file mode 100755
index 51c3c2b1..00000000
--- a/CPP/7zip/Archive/Hfs/HfsRegister.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// HfsRegister.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/RegisterArc.h"
-
-#include "HfsHandler.h"
-static IInArchive *CreateArc() { return new NArchive::NHfs::CHandler; }
-
-static CArcInfo g_ArcInfo =
- { L"HFS", L"hfs", 0, 0xE3, { 'H', '+', 0, 4 }, 4, false, CreateArc, 0 };
-
-REGISTER_ARC(Hfs)
diff --git a/CPP/7zip/Archive/HfsHandler.cpp b/CPP/7zip/Archive/HfsHandler.cpp
new file mode 100644
index 00000000..ca1370d8
--- /dev/null
+++ b/CPP/7zip/Archive/HfsHandler.cpp
@@ -0,0 +1,1874 @@
+// 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 wchar_t *kResFileName = L"rsrc"; // L"com.apple.ResourceFork";
+
+struct CExtent
+{
+ UInt32 Pos;
+ UInt32 NumBlocks;
+};
+
+struct CIdExtents
+{
+ UInt32 ID;
+ UInt32 StartBlock;
+ CRecordVector<CExtent> Extents;
+};
+
+struct CFork
+{
+ UInt64 Size;
+ UInt32 NumBlocks;
+ // UInt32 ClumpSize;
+ CRecordVector<CExtent> Extents;
+
+ CFork(): Size(0), NumBlocks(0) {}
+
+ void Parse(const Byte *p);
+
+ bool IsEmpty() const { return Size == 0 && NumBlocks == 0 && Extents.Size() == 0; }
+
+ UInt32 Calc_NumBlocks_from_Extents() const;
+ bool Check_NumBlocks() const;
+
+ bool Check_Size_with_NumBlocks(unsigned blockSizeLog) const
+ {
+ return Size <= ((UInt64)NumBlocks << blockSizeLog);
+ }
+
+ bool IsOk(unsigned blockSizeLog) const
+ {
+ // we don't check cases with extra (empty) blocks in last extent
+ return Check_NumBlocks() && Check_Size_with_NumBlocks(blockSizeLog);
+ }
+
+ bool Upgrade(const CObjectVector<CIdExtents> &items, UInt32 id);
+ bool UpgradeAndTest(const CObjectVector<CIdExtents> &items, UInt32 id, unsigned blockSizeLog)
+ {
+ if (!Upgrade(items, id))
+ return false;
+ return IsOk(blockSizeLog);
+ }
+};
+
+static const unsigned kNumFixedExtents = 8;
+
+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<CIdIndexPair> &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<CIdExtents> &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<CIdExtents> &items, UInt32 id)
+{
+ int index = Find_in_IdExtents(items, id);
+ if (index < 0)
+ return true;
+ const CIdExtents &item = items[index];
+ if (Calc_NumBlocks_from_Extents() != item.StartBlock)
+ return false;
+ Extents += item.Extents;
+ return true;
+}
+
+
+struct CVolHeader
+{
+ Byte Header[2];
+ UInt16 Version;
+ // UInt32 Attr;
+ // UInt32 LastMountedVersion;
+ // UInt32 JournalInfoBlock;
+
+ UInt32 CTime;
+ UInt32 MTime;
+ // UInt32 BackupTime;
+ // UInt32 CheckedTime;
+
+ UInt32 NumFiles;
+ UInt32 NumFolders;
+ unsigned BlockSizeLog;
+ UInt32 NumBlocks;
+ UInt32 NumFreeBlocks;
+
+ // UInt32 WriteCount;
+ // UInt32 FinderInfo[8];
+ // UInt64 VolID;
+
+ UInt64 GetPhySize() const { return (UInt64)NumBlocks << BlockSizeLog; }
+ UInt64 GetFreeSize() const { return (UInt64)NumFreeBlocks << BlockSizeLog; }
+ bool IsHfsX() const { return Version > 4; }
+};
+
+inline void HfsTimeToFileTime(UInt32 hfsTime, FILETIME &ft)
+{
+ UInt64 v = ((UInt64)3600 * 24 * (365 * 303 + 24 * 3) + hfsTime) * 10000000;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+enum ERecordType
+{
+ RECORD_TYPE_FOLDER = 1,
+ RECORD_TYPE_FILE,
+ RECORD_TYPE_FOLDER_THREAD,
+ RECORD_TYPE_FILE_THREAD
+};
+
+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<CIdExtents> *overflowExtentsArray);
+ HRESULT LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress);
+ HRESULT LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents> *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress);
+ bool Parse_decmpgfs(const CAttr &attr, CItem &item, bool &skip);
+public:
+ CRecordVector<CRef> Refs;
+ CObjectVector<CItem> Items;
+ CObjectVector<CAttr> Attrs;
+
+ CByteBuffer AttrBuf;
+
+ CVolHeader Header;
+ bool HeadersError;
+ bool ThereAreAltStreams;
+ // bool CaseSensetive;
+ UString ResFileName;
+
+ UInt64 PhySize;
+
+ void Clear()
+ {
+ PhySize = 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++)
+ dest[j] = src[j];
+
+ 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((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 Parse(const Byte *p);
+};
+
+HRESULT CHeaderRec::Parse(const Byte *p)
+{
+ // TreeDepth = Get16(p);
+ // RootNode = Get32(p + 2);
+ // LeafRecords = Get32(p + 6);
+ FirstLeafNode = Get32(p + 0xA);
+ // LastLeafNode = Get32(p + 0xE);
+ UInt32 nodeSize = Get16(p + 0x12);
+
+ 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);
+ */
+ return S_OK;
+}
+
+
+static const Byte kNodeType_Leaf = 0xFF;
+// static const Byte kNodeType_Index = 0;
+// static const Byte kNodeType_Header = 1;
+// static const Byte kNodeType_Mode = 2;
+
+static const Byte kExtentForkType_Data = 0;
+static const Byte kExtentForkType_Resource = 0xFF;
+
+/* It loads data extents from Extents Overflow File
+ Most dmg installers are not fragmented. So there are no extents in Overflow File. */
+
+HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector<CIdExtents> *overflowExtentsArray)
+{
+ if (fork.NumBlocks == 0)
+ return S_OK;
+ CByteBuffer buf;
+ RINOK(ReadFile(fork, buf, inStream));
+ const Byte *p = (const Byte *)buf;
+
+ // CNodeDescriptor nodeDesc;
+ // nodeDesc.Parse(p);
+ CHeaderRec hr;
+ RINOK(hr.Parse(p + kNodeDescriptor_Size));
+
+ if ((buf.Size() >> hr.NodeSizeLog) < hr.TotalNodes)
+ return S_FALSE;
+
+ 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++)
+ {
+ UInt32 nodeSize = (UInt32)1 << hr.NodeSizeLog;
+ UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2);
+ 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<CIdExtents> &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.GetBuffer(len);
+ unsigned i;
+ for (i = 0; i < len; i++)
+ p[i] = Get16(data + i * 2);
+ p[i] = 0;
+ dest.ReleaseBuffer();
+}
+
+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.Parse(p + kNodeDescriptor_Size));
+
+ // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC);
+
+ if ((AttrBuf.Size() >> hr.NodeSizeLog) < hr.TotalNodes)
+ return S_FALSE;
+
+ 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++)
+ {
+ UInt32 nodeSize = (1 << hr.NodeSizeLog);
+ UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2);
+ UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2);
+ UInt32 recSize = offsNext - offs;
+ if (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 != L"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<CIdExtents> *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress)
+{
+ unsigned reserveSize = (unsigned)(Header.NumFolders + 1 + Header.NumFiles);
+ Items.ClearAndReserve(reserveSize);
+ Refs.ClearAndReserve(reserveSize);
+
+ CRecordVector<CIdIndexPair> IdToIndexMap;
+ IdToIndexMap.ClearAndReserve(reserveSize);
+
+ CByteBuffer buf;
+ RINOK(ReadFile(fork, buf, inStream));
+ const Byte *p = (const Byte *)buf;
+
+ // CNodeDescriptor nodeDesc;
+ // nodeDesc.Parse(p);
+ CHeaderRec hr;
+ hr.Parse(p + kNodeDescriptor_Size);
+
+ // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC);
+
+ if ((buf.Size() >> hr.NodeSizeLog) < hr.TotalNodes)
+ return S_FALSE;
+
+ 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;
+
+ 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++)
+ {
+ UInt32 nodeSize = (1 << hr.NodeSizeLog);
+ UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2);
+ UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2);
+ UInt32 recSize = offsNext - offs;
+ if (offs >= nodeSize
+ || offs >= 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 = L"[HFS+ Private Data]";
+ }
+ }
+
+ // Some dmg files have ' ' folder item.
+ if (item.Name.IsEmpty() || item.Name[0] == L' ')
+ item.Name = L"[]";
+ }
+ }
+
+ 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);
+
+HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress)
+{
+ Clear();
+ static const unsigned kHeaderSize = kHeaderPadSize + 512;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize));
+ {
+ 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] != '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<CIdExtents> overflowExtents[2];
+ if (!extentsFork.IsOk(Header.BlockSizeLog))
+ HeadersError = true;
+ else
+ {
+ HRESULT res = LoadExtentFile(extentsFork, inStream, overflowExtents);
+ if (res == S_FALSE)
+ HeadersError = true;
+ else if (res != S_OK)
+ return res;
+ }
+
+ if (!catalogFork.UpgradeAndTest(overflowExtents[0], kHfsID_CatalogFile, Header.BlockSizeLog))
+ return S_FALSE;
+
+ if (!attrFork.UpgradeAndTest(overflowExtents[0], kHfsID_AttributesFile, Header.BlockSizeLog))
+ HeadersError = true;
+ else
+ {
+ if (attrFork.Size != 0)
+ RINOK(LoadAttrs(attrFork, inStream, progress));
+ }
+
+ RINOK(LoadCatalog(catalogFork, overflowExtents, inStream, progress));
+
+ PhySize = Header.GetPhySize();
+ return S_OK;
+}
+
+
+
+class CHandler:
+ public IInArchive,
+ public IArchiveGetRawProps,
+ public IInArchiveGetStream,
+ public CMyUnknownImp,
+ public CDatabase
+{
+ CMyComPtr<IInStream> _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: prop = PhySize; 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<ISequentialInStream> 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<ISequentialInStream> 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);
+
+ 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<ICompressCoder> _zlibDecoder;
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ RINOK(extractCallback->SetCompleted(&currentTotalSize));
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CRef &ref = Refs[index];
+ const CItem &item = Items[ref.ItemIndex];
+ currentItemSize = Get_UnpackSize_of_Ref(ref);
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ 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<ISequentialInStream> 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((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)((UInt32)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<ISequentialInStream> extentStream = extentStreamSpec;
+
+ UInt64 rem = fork.Size;
+ UInt64 virt = 0;
+
+ FOR_VECTOR (i, fork.Extents)
+ {
+ const CExtent &e = fork.Extents[i];
+ if (e.NumBlocks == 0)
+ continue;
+ UInt64 cur = ((UInt64)e.NumBlocks << Header.BlockSizeLog);
+ if (cur > rem)
+ {
+ cur = rem;
+ if (i != fork.Extents.Size() - 1)
+ return S_FALSE;
+ }
+ CSeekExtent se;
+ se.Phy = (UInt64)e.Pos << Header.BlockSizeLog;
+ se.Virt = virt;
+ virt += cur;
+ rem -= cur;
+ extentStreamSpec->Extents.Add(se);
+ }
+
+ if (rem != 0)
+ return S_FALSE;
+
+ CSeekExtent se;
+ se.Phy = 0;
+ se.Virt = virt;
+ extentStreamSpec->Extents.Add(se);
+ extentStreamSpec->Stream = _stream;
+ extentStreamSpec->Init();
+ *stream = extentStream.Detach();
+ return S_OK;
+}
+
+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);
+}
+
+IMP_CreateArcIn
+
+static CArcInfo g_ArcInfo =
+ { "HFS", "hfs hfsx", 0, 0xE3,
+ 2 * (4 + 1),
+ {
+ 4, 'H', '+', 0, 4,
+ 4, 'H', 'X', 0, 5,
+ },
+ kHeaderPadSize,
+ NArcInfoFlags::kMultiSignature,
+ CreateArc };
+
+REGISTER_ARC(Hfs)
+
+}}
diff --git a/CPP/7zip/Archive/IArchive.h b/CPP/7zip/Archive/IArchive.h
index 85320276..63e16ac3 100755..100644
--- a/CPP/7zip/Archive/IArchive.h
+++ b/CPP/7zip/Archive/IArchive.h
@@ -20,20 +20,43 @@ namespace NFileTimeType
};
}
+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
{
- enum
+ namespace NHandlerPropID
{
- kName = 0,
- kClassID,
- kExtension,
- kAddExtension,
- kUpdate,
- kKeepName,
- kStartSignature,
- kFinishSignature,
- kAssociate
- };
+ 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
{
@@ -46,25 +69,32 @@ namespace NArchive
kSkip
};
}
+
namespace NOperationResult
{
enum
{
kOK = 0,
- kUnSupportedMethod,
+ kUnsupportedMethod,
kDataError,
- kCRCError
+ kCRCError,
+ kUnavailable,
+ kUnexpectedEnd,
+ kDataAfterEnd,
+ kIsNotArc,
+ kHeadersError
};
}
}
+
namespace NUpdate
{
namespace NOperationResult
{
enum
{
- kOK = 0,
- kError
+ kOK = 0
+ , // kError
};
}
}
@@ -79,10 +109,16 @@ ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10)
INTERFACE_IArchiveOpenCallback(PURE);
};
+/*
+IArchiveExtractCallback::GetStream
+ Result:
+ (*inStream == NULL) - for directories
+ (*inStream == NULL) - if link (hard link or symbolic link) was created
+*/
#define INTERFACE_IArchiveExtractCallback(x) \
INTERFACE_IProgress(x) \
- STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \
+ STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \
STDMETHOD(PrepareOperation)(Int32 askExtractMode) x; \
STDMETHOD(SetOperationResult)(Int32 resultEOperationResult) x; \
@@ -115,41 +151,175 @@ ARCHIVE_INTERFACE(IArchiveOpenSetSubArchiveName, 0x50)
/*
+IInArchive::Open
+ stream
+ if (kUseGlobalOffset), stream current position can be non 0.
+ if (!kUseGlobalOffset), stream current position is 0.
+ if (maxCheckStartPosition == NULL), the handler can try to search archive start in stream
+ if (*maxCheckStartPosition == 0), the handler must check only current position as archive start
+
IInArchive::Extract:
indices must be sorted
- numItems = 0xFFFFFFFF means "all files"
+ 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.
*/
#define INTERFACE_IInArchive(x) \
- STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openArchiveCallback) x; \
- STDMETHOD(Close)() x; \
- STDMETHOD(GetNumberOfItems)(UInt32 *numItems) x; \
- STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \
- STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) x; \
- STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) x; \
- STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties) x; \
- STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \
- STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProperties) x; \
- STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x;
+ STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) throw() x; \
+ STDMETHOD(Close)() throw() x; \
+ STDMETHOD(GetNumberOfItems)(UInt32 *numItems) throw() x; \
+ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) throw() x; \
+ STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) throw() x; \
+ STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) throw() x; \
+ STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) throw() x; \
+ STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) throw() x; \
+ STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) throw() x; \
+ STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) throw() 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 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)
+
+*/
+
#define INTERFACE_IArchiveUpdateCallback(x) \
INTERFACE_IProgress(x); \
- STDMETHOD(GetUpdateItemInfo)(UInt32 index, \
- Int32 *newData, /*1 - new data, 0 - old data */ \
- Int32 *newProperties, /* 1 - new properties, 0 - old properties */ \
- UInt32 *indexInArchive /* -1 if there is no in archive, or if doesn't matter */ \
- ) x; \
+ STDMETHOD(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; \
@@ -169,6 +339,27 @@ ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82)
INTERFACE_IArchiveUpdateCallback2(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; \
@@ -182,47 +373,61 @@ ARCHIVE_INTERFACE(IOutArchive, 0xA0)
ARCHIVE_INTERFACE(ISetProperties, 0x03)
{
- STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) PURE;
+ STDMETHOD(SetProperties)(const wchar_t **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 >= sizeof(k) / sizeof(k[0])) return E_INVALIDARG; \
- const STATPROPSTG &srcItem = k[index]; \
- *propID = srcItem.propid; *varType = srcItem.vt; *name = 0; return S_OK; } \
+ { 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_IInArchive_GetProp_WITH_NAME(k) \
(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
- { if(index >= sizeof(k) / sizeof(k[0])) return E_INVALIDARG; \
+ { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \
const STATPROPSTG &srcItem = k[index]; \
*propID = srcItem.propid; *varType = srcItem.vt; \
if (srcItem.lpwstrName == 0) *name = 0; else *name = ::SysAllocString(srcItem.lpwstrName); return S_OK; } \
#define IMP_IInArchive_Props \
- STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) \
- { *numProperties = sizeof(kProps) / sizeof(kProps[0]); return S_OK; } \
+ STDMETHODIMP CHandler::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 *numProperties) \
- { *numProperties = sizeof(kProps) / sizeof(kProps[0]); return S_OK; } \
+ 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 *numProperties) \
- { *numProperties = sizeof(kArcProps) / sizeof(kArcProps[0]); return S_OK; } \
+ 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 *numProperties) \
- { *numProperties = sizeof(kArcProps) / sizeof(kArcProps[0]); return S_OK; } \
+ 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 *numProperties) \
- { *numProperties = 0; return S_OK; } \
+ STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \
+ { *numProps = 0; return S_OK; } \
STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *) \
{ return E_NOTIMPL; } \
@@ -231,4 +436,32 @@ ARCHIVE_INTERFACE(ISetProperties, 0x03)
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/Icons/7z.ico b/CPP/7zip/Archive/Icons/7z.ico
index 319753a1..319753a1 100755..100644
--- a/CPP/7zip/Archive/Icons/7z.ico
+++ b/CPP/7zip/Archive/Icons/7z.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/arj.ico b/CPP/7zip/Archive/Icons/arj.ico
index c0f8b141..c0f8b141 100755..100644
--- a/CPP/7zip/Archive/Icons/arj.ico
+++ b/CPP/7zip/Archive/Icons/arj.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/bz2.ico b/CPP/7zip/Archive/Icons/bz2.ico
index f22abebc..f22abebc 100755..100644
--- a/CPP/7zip/Archive/Icons/bz2.ico
+++ b/CPP/7zip/Archive/Icons/bz2.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/cab.ico b/CPP/7zip/Archive/Icons/cab.ico
index c96c0f01..c96c0f01 100755..100644
--- a/CPP/7zip/Archive/Icons/cab.ico
+++ b/CPP/7zip/Archive/Icons/cab.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/cpio.ico b/CPP/7zip/Archive/Icons/cpio.ico
index 9abaabc7..9abaabc7 100755..100644
--- a/CPP/7zip/Archive/Icons/cpio.ico
+++ b/CPP/7zip/Archive/Icons/cpio.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/deb.ico b/CPP/7zip/Archive/Icons/deb.ico
index 97a08654..97a08654 100755..100644
--- a/CPP/7zip/Archive/Icons/deb.ico
+++ b/CPP/7zip/Archive/Icons/deb.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/dmg.ico b/CPP/7zip/Archive/Icons/dmg.ico
index 7d63b09f..7d63b09f 100755..100644
--- a/CPP/7zip/Archive/Icons/dmg.ico
+++ b/CPP/7zip/Archive/Icons/dmg.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/fat.ico b/CPP/7zip/Archive/Icons/fat.ico
index 7503d933..7503d933 100755..100644
--- a/CPP/7zip/Archive/Icons/fat.ico
+++ b/CPP/7zip/Archive/Icons/fat.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/gz.ico b/CPP/7zip/Archive/Icons/gz.ico
index d402a698..d402a698 100755..100644
--- a/CPP/7zip/Archive/Icons/gz.ico
+++ b/CPP/7zip/Archive/Icons/gz.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/hfs.ico b/CPP/7zip/Archive/Icons/hfs.ico
index bf2c1986..bf2c1986 100755..100644
--- a/CPP/7zip/Archive/Icons/hfs.ico
+++ b/CPP/7zip/Archive/Icons/hfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/iso.ico b/CPP/7zip/Archive/Icons/iso.ico
index b3e3ac2f..b3e3ac2f 100755..100644
--- a/CPP/7zip/Archive/Icons/iso.ico
+++ b/CPP/7zip/Archive/Icons/iso.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/lzh.ico b/CPP/7zip/Archive/Icons/lzh.ico
index 84dab49c..84dab49c 100755..100644
--- a/CPP/7zip/Archive/Icons/lzh.ico
+++ b/CPP/7zip/Archive/Icons/lzh.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/lzma.ico b/CPP/7zip/Archive/Icons/lzma.ico
index 2de2c249..2de2c249 100755..100644
--- a/CPP/7zip/Archive/Icons/lzma.ico
+++ b/CPP/7zip/Archive/Icons/lzma.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/ntfs.ico b/CPP/7zip/Archive/Icons/ntfs.ico
index 6b2aeb00..6b2aeb00 100755..100644
--- a/CPP/7zip/Archive/Icons/ntfs.ico
+++ b/CPP/7zip/Archive/Icons/ntfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/rar.ico b/CPP/7zip/Archive/Icons/rar.ico
index 2918d294..2918d294 100755..100644
--- a/CPP/7zip/Archive/Icons/rar.ico
+++ b/CPP/7zip/Archive/Icons/rar.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/rpm.ico b/CPP/7zip/Archive/Icons/rpm.ico
index cdeb8d1b..cdeb8d1b 100755..100644
--- a/CPP/7zip/Archive/Icons/rpm.ico
+++ b/CPP/7zip/Archive/Icons/rpm.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/split.ico b/CPP/7zip/Archive/Icons/split.ico
index 65723ff3..65723ff3 100755..100644
--- a/CPP/7zip/Archive/Icons/split.ico
+++ b/CPP/7zip/Archive/Icons/split.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/squashfs.ico b/CPP/7zip/Archive/Icons/squashfs.ico
index b802d942..b802d942 100755..100644
--- a/CPP/7zip/Archive/Icons/squashfs.ico
+++ b/CPP/7zip/Archive/Icons/squashfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/tar.ico b/CPP/7zip/Archive/Icons/tar.ico
index 6835885b..6835885b 100755..100644
--- a/CPP/7zip/Archive/Icons/tar.ico
+++ b/CPP/7zip/Archive/Icons/tar.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/vhd.ico b/CPP/7zip/Archive/Icons/vhd.ico
index 33bed3c9..33bed3c9 100755..100644
--- a/CPP/7zip/Archive/Icons/vhd.ico
+++ b/CPP/7zip/Archive/Icons/vhd.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/wim.ico b/CPP/7zip/Archive/Icons/wim.ico
index 887975e6..887975e6 100755..100644
--- a/CPP/7zip/Archive/Icons/wim.ico
+++ b/CPP/7zip/Archive/Icons/wim.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/xar.ico b/CPP/7zip/Archive/Icons/xar.ico
index 281aa7dc..281aa7dc 100755..100644
--- a/CPP/7zip/Archive/Icons/xar.ico
+++ b/CPP/7zip/Archive/Icons/xar.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/xz.ico b/CPP/7zip/Archive/Icons/xz.ico
index bc07a7eb..bc07a7eb 100755..100644
--- a/CPP/7zip/Archive/Icons/xz.ico
+++ b/CPP/7zip/Archive/Icons/xz.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/z.ico b/CPP/7zip/Archive/Icons/z.ico
index 2db53583..2db53583 100755..100644
--- a/CPP/7zip/Archive/Icons/z.ico
+++ b/CPP/7zip/Archive/Icons/z.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/zip.ico b/CPP/7zip/Archive/Icons/zip.ico
index 2af46066..2af46066 100755..100644
--- a/CPP/7zip/Archive/Icons/zip.ico
+++ b/CPP/7zip/Archive/Icons/zip.ico
Binary files differ
diff --git a/CPP/7zip/Archive/IhexHandler.cpp b/CPP/7zip/Archive/IhexHandler.cpp
new file mode 100644
index 00000000..bc468401
--- /dev/null
+++ b/CPP/7zip/Archive/IhexHandler.cpp
@@ -0,0 +1,500 @@
+// 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<CBlock> _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 = 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(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 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 int kNumLinesToCheck = 3; // 1 line is OK also, but we don't want false detection
+
+ for (int 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 = (num + 4);
+ size_t numBytes = numPairs * 2;
+ if (s.ReadBytes(temp, numBytes) != numBytes)
+ {
+ _needMoreInput = true;
+ return S_FALSE;
+ }
+
+ int 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;
+ }
+ memcpy(block->Data.GetCurPtrAndGrow(num), temp + 3, 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<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ currentItemSize = 0;
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CByteDynamicBuffer &data = _blocks[index].Data;
+ currentItemSize = data.GetPos();
+
+ CMyComPtr<ISequentialOutStream> 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
+}
+
+IMP_CreateArcIn
+
+static CArcInfo g_ArcInfo =
+ { "IHex", "ihex", 0, 0xCD,
+ 0, { 0 },
+ // 2, { ':', '1' },
+ 0,
+ NArcInfoFlags::kStartOpen,
+ CreateArc, NULL, IsArc_Ihex };
+
+REGISTER_ARC(Z)
+
+}}
diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp
index f040b033..fc984048 100755..100644
--- a/CPP/7zip/Archive/Iso/IsoHandler.cpp
+++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp
@@ -2,12 +2,12 @@
#include "StdAfx.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/StringConvert.h"
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/TimeUtils.h"
#include "../../Common/LimitedStreams.h"
#include "../../Common/ProgressUtils.h"
@@ -24,22 +24,21 @@ using namespace NTime;
namespace NArchive {
namespace NIso {
-static const STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME}
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime
};
-static const STATPROPSTG kArcProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidComment, VT_BSTR},
- { NULL, kpidCTime, VT_FILETIME},
- { NULL, kpidMTime, VT_FILETIME}
- // { NULL, kpidPhySize, VT_UI8},
- // { NULL, kpidHeadersSize, VT_UI8}
+ kpidComment,
+ kpidCTime,
+ kpidMTime,
+ // kpidHeadersSize
};
IMP_IInArchive_Props
@@ -51,13 +50,10 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
{
COM_TRY_BEGIN
Close();
- // try
{
- if (_archive.Open(stream) != S_OK)
- return S_FALSE;
+ RINOK(_archive.Open(stream));
_stream = stream;
}
- // catch(...) { return S_FALSE; }
return S_OK;
COM_TRY_END
}
@@ -75,9 +71,9 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
-static void AddString(AString &s, const char *name, const Byte *p, int size)
+static void AddString(AString &s, const char *name, const Byte *p, unsigned size)
{
- int i;
+ unsigned i;
for (i = 0; i < size && p[i]; i++);
for (; i > 0 && p[i - 1] == ' '; i--);
if (i != 0)
@@ -94,12 +90,21 @@ static void AddString(AString &s, const char *name, const Byte *p, int size)
#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
- NWindows::NCOM::CPropVariant prop;
+ NCOM::CPropVariant prop;
+ if (_stream)
+ {
const CVolumeDescriptor &vol = _archive.VolDescs[_archive.MainVolDescIndex];
- switch(propID)
+ switch (propID)
{
case kpidComment:
{
@@ -118,9 +123,35 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
}
case kpidCTime: { FILETIME utc; if (vol.CTime.GetFileTime(utc)) prop = utc; break; }
case kpidMTime: { FILETIME utc; if (vol.MTime.GetFileTime(utc)) prop = utc; break; }
- // case kpidPhySize: break;
- // case kpidHeadersSize: break;
- case kpidError: if (_archive.IncorrectBigEndian) prop = "Incorrect big-endian headers"; break;
+ }
+ }
+
+ 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;
@@ -130,22 +161,22 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
+ NCOM::CPropVariant prop;
if (index >= (UInt32)_archive.Refs.Size())
{
index -= _archive.Refs.Size();
const CBootInitialEntry &be = _archive.BootEntries[index];
- switch(propID)
+ switch (propID)
{
case kpidPath:
{
- // wchar_t name[32];
- // ConvertUInt64ToString(index + 1, name);
- UString s = L"[BOOT]" WSTRING_PATH_SEPARATOR;
+ // char name[16];
+ // ConvertUInt32ToString(index + 1, name);
+ AString s = "[BOOT]" STRING_PATH_SEPARATOR;
// s += name;
- // s += L"-";
+ // s += '-';
s += be.GetName();
- prop = (const wchar_t *)s;
+ prop = s;
break;
}
case kpidIsDir: prop = false; break;
@@ -159,7 +190,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
const CRef &ref = _archive.Refs[index];
const CDir &item = ref.Dir->_subItems[ref.Index];
- switch(propID)
+ switch (propID)
{
case kpidPath:
// if (item.FileId.GetCapacity() >= 0)
@@ -171,9 +202,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
s = MultiByteToUnicodeString(item.GetPath(_archive.IsSusp, _archive.SuspSkipSize), CP_OEMCP);
int pos = s.ReverseFind(L';');
- if (pos >= 0 && pos == s.Length() - 2)
+ if (pos >= 0 && pos == (int)s.Len() - 2)
if (s.Back() == L'1')
- s = s.Left(pos);
+ s.DeleteFrom(pos);
if (!s.IsEmpty())
if (s.Back() == L'.')
s.DeleteBack();
@@ -184,7 +215,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidSize:
case kpidPackSize:
if (!item.IsDir())
- prop = (UInt64)item.DataLength;
+ prop = (UInt64)ref.TotalSize;
break;
case kpidMTime:
{
@@ -204,7 +235,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _archive.Refs.Size();
if (numItems == 0)
@@ -219,7 +250,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
const CRef &ref = _archive.Refs[index];
const CDir &item = ref.Dir->_subItems[ref.Index];
if (!item.IsDir())
- totalSize += item.DataLength;
+ totalSize += ref.TotalSize;
}
else
totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size());
@@ -240,9 +271,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ISequentialInStream> inStream(streamSpec);
streamSpec->SetStream(_stream);
- CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
- CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
-
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
{
lps->InSize = lps->OutSize = currentTotalSize;
@@ -267,28 +295,54 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
continue;
}
- currentItemSize = item.DataLength;
+ currentItemSize = ref.TotalSize;
blockIndex = item.ExtentLocation;
}
else
{
- int bootIndex = index - _archive.Refs.Size();
+ 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));
- outStreamSpec->SetStream(realOutStream);
+
+ 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++)
+ {
+ if (e != 0)
+ lps->InSize = lps->OutSize = currentTotalSize + offset;
+ const CDir &item2 = ref.Dir->_subItems[ref.Index + e];
+ RINOK(_stream->Seek(item2.ExtentLocation * _archive.BlockSize, 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(blockIndex * _archive.BlockSize, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(currentItemSize);
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
+ if (copyCoderSpec->TotalSize != currentItemSize)
+ isOK = false;
+ }
realOutStream.Release();
- outStreamSpec->Init(currentItemSize);
- RINOK(_stream->Seek(blockIndex * _archive.BlockSize, STREAM_SEEK_SET, NULL));
- streamSpec->Init(currentItemSize);
- RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
- outStreamSpec->ReleaseStream();
- RINOK(extractCallback->SetOperationResult(outStreamSpec->IsFinishedOK() ?
+ RINOK(extractCallback->SetOperationResult(isOK ?
NExtract::NOperationResult::kOK:
NExtract::NOperationResult::kDataError));
}
@@ -308,12 +362,42 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
const CDir &item = ref.Dir->_subItems[ref.Index];
if (item.IsDir())
return S_FALSE;
- currentItemSize = item.DataLength;
+
+ if (ref.NumExtents > 1)
+ {
+ CExtentsStream *extentStreamSpec = new CExtentsStream();
+ CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
+
+ extentStreamSpec->Stream = _stream;
+
+ UInt64 virtOffset = 0;
+ for (UInt32 i = 0; i < ref.NumExtents; i++)
+ {
+ const CDir &item = ref.Dir->_subItems[ref.Index + i];
+ if (item.Size == 0)
+ continue;
+ CSeekExtent se;
+ se.Phy = (UInt64)item.ExtentLocation * _archive.BlockSize;
+ se.Virt = virtOffset;
+ extentStreamSpec->Extents.Add(se);
+ virtOffset += item.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
{
- int bootIndex = index - _archive.Refs.Size();
+ unsigned bootIndex = index - _archive.Refs.Size();
const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
currentItemSize = _archive.GetBootItemSize(bootIndex);
blockIndex = be.LoadRBA;
diff --git a/CPP/7zip/Archive/Iso/IsoHandler.h b/CPP/7zip/Archive/Iso/IsoHandler.h
index 1dcade8f..1923784d 100755..100644
--- a/CPP/7zip/Archive/Iso/IsoHandler.h
+++ b/CPP/7zip/Archive/Iso/IsoHandler.h
@@ -3,7 +3,8 @@
#ifndef __ISO_HANDLER_H
#define __ISO_HANDLER_H
-#include "Common/MyCom.h"
+#include "../../../Common/MyCom.h"
+
#include "../IArchive.h"
#include "IsoIn.h"
diff --git a/CPP/7zip/Archive/Iso/IsoHeader.cpp b/CPP/7zip/Archive/Iso/IsoHeader.cpp
index b3e418bb..1cd2516c 100755..100644
--- a/CPP/7zip/Archive/Iso/IsoHeader.cpp
+++ b/CPP/7zip/Archive/Iso/IsoHeader.cpp
@@ -9,13 +9,13 @@ namespace NIso {
const char *kElToritoSpec = "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0";
-const wchar_t *kMediaTypes[5] =
+const char *kMediaTypes[5] =
{
- L"NoEmulation",
- L"1.2M",
- L"1.44M",
- L"2.88M",
- L"HardDisk"
+ "NoEmulation"
+ , "1.2M"
+ , "1.44M"
+ , "2.88M"
+ , "HardDisk"
};
}}
diff --git a/CPP/7zip/Archive/Iso/IsoHeader.h b/CPP/7zip/Archive/Iso/IsoHeader.h
index 9702d70a..ce21b0ff 100755..100644
--- a/CPP/7zip/Archive/Iso/IsoHeader.h
+++ b/CPP/7zip/Archive/Iso/IsoHeader.h
@@ -3,7 +3,7 @@
#ifndef __ARCHIVE_ISO_HEADER_H
#define __ARCHIVE_ISO_HEADER_H
-#include "Common/Types.h"
+#include "../../../Common/MyTypes.h"
namespace NArchive {
namespace NIso {
@@ -22,6 +22,7 @@ const Byte kVersion = 1;
namespace NFileFlags
{
const Byte kDirectory = 1 << 1;
+ const Byte kNonFinalExtent = 1 << 7;
}
extern const char *kElToritoSpec;
@@ -42,7 +43,7 @@ namespace NBootPlatformId
const Byte kMac = 2;
}
-const BYTE kBootMediaTypeMask = 0xF;
+const Byte kBootMediaTypeMask = 0xF;
namespace NBootMediaType
{
@@ -53,8 +54,8 @@ namespace NBootMediaType
const Byte kHardDisk = 4;
}
-const int kNumBootMediaTypes = 5;
-extern const wchar_t *kMediaTypes[];
+const unsigned kNumBootMediaTypes = 5;
+extern const char *kMediaTypes[];
}}
diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp
index 7ed618d2..ba12acae 100755..100644
--- a/CPP/7zip/Archive/Iso/IsoIn.cpp
+++ b/CPP/7zip/Archive/Iso/IsoIn.cpp
@@ -2,24 +2,34 @@
#include "StdAfx.h"
-#include "IsoIn.h"
+#include "../../../Common/MyException.h"
#include "../../Common/StreamUtils.h"
+#include "IsoIn.h"
+
namespace NArchive {
namespace NIso {
+struct CUnexpectedEndException {};
+struct CHeaderErrorException {};
+struct CEndianErrorException {};
+
Byte CInArchive::ReadByte()
{
if (m_BufferPos >= BlockSize)
m_BufferPos = 0;
if (m_BufferPos == 0)
{
- size_t processedSize = BlockSize;
- if (ReadStream(_stream, m_Buffer, &processedSize) != S_OK)
- throw 1;
- if (processedSize != BlockSize)
- throw 1;
+ size_t processed = BlockSize;
+ HRESULT res = ReadStream(_stream, m_Buffer, &processed);
+ if (res != S_OK)
+ throw CSystemException(res);
+ if (processed != BlockSize)
+ throw CUnexpectedEndException();
+ UInt64 end = _position + processed;
+ if (PhySize < end)
+ PhySize = end;
}
Byte b = m_Buffer[m_BufferPos++];
_position++;
@@ -44,16 +54,16 @@ void CInArchive::SkipZeros(size_t size)
{
Byte b = ReadByte();
if (b != 0)
- throw 1;
+ throw CHeaderErrorException();
}
}
UInt16 CInArchive::ReadUInt16Spec()
{
- UInt16 value = 0;
+ UInt16 val = 0;
for (int i = 0; i < 2; i++)
- value |= ((UInt16)(ReadByte()) << (8 * i));
- return value;
+ val |= ((UInt16)(ReadByte()) << (8 * i));
+ return val;
}
@@ -61,47 +71,47 @@ UInt16 CInArchive::ReadUInt16()
{
Byte b[4];
ReadBytes(b, 4);
- UInt32 value = 0;
+ UInt32 val = 0;
for (int i = 0; i < 2; i++)
{
if (b[i] != b[3 - i])
IncorrectBigEndian = true;
- value |= ((UInt16)(b[i]) << (8 * i));
+ val |= ((UInt16)(b[i]) << (8 * i));
}
- return (UInt16)value;
+ return (UInt16)val;
}
UInt32 CInArchive::ReadUInt32Le()
{
- UInt32 value = 0;
+ UInt32 val = 0;
for (int i = 0; i < 4; i++)
- value |= ((UInt32)(ReadByte()) << (8 * i));
- return value;
+ val |= ((UInt32)(ReadByte()) << (8 * i));
+ return val;
}
UInt32 CInArchive::ReadUInt32Be()
{
- UInt32 value = 0;
+ UInt32 val = 0;
for (int i = 0; i < 4; i++)
{
- value <<= 8;
- value |= ReadByte();
+ val <<= 8;
+ val |= ReadByte();
}
- return value;
+ return val;
}
UInt32 CInArchive::ReadUInt32()
{
Byte b[8];
ReadBytes(b, 8);
- UInt32 value = 0;
+ UInt32 val = 0;
for (int i = 0; i < 4; i++)
{
if (b[i] != b[7 - i])
- throw 1;
- value |= ((UInt32)(b[i]) << (8 * i));
+ throw CEndianErrorException();
+ val |= ((UInt32)(b[i]) << (8 * i));
}
- return value;
+ return val;
}
UInt32 CInArchive::ReadDigits(int numDigits)
@@ -115,7 +125,7 @@ UInt32 CInArchive::ReadDigits(int numDigits)
if (b == 0) // it's bug in some CD's
b = '0';
else
- throw 1;
+ throw CHeaderErrorException();
}
UInt32 d = (UInt32)(b - '0');
res *= 10;
@@ -158,16 +168,16 @@ void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len)
{
r.ExtendedAttributeRecordLen = ReadByte();
if (r.ExtendedAttributeRecordLen != 0)
- throw 1;
+ throw CHeaderErrorException();
r.ExtentLocation = ReadUInt32();
- r.DataLength = ReadUInt32();
+ r.Size = ReadUInt32();
ReadRecordingDateTime(r.DateTime);
r.FileFlags = ReadByte();
r.FileUnitSize = ReadByte();
r.InterleaveGapSize = ReadByte();
r.VolSequenceNumber = ReadUInt16();
Byte idLen = ReadByte();
- r.FileId.SetCapacity(idLen);
+ r.FileId.Alloc(idLen);
ReadBytes((Byte *)r.FileId, idLen);
int padSize = 1 - (idLen & 1);
@@ -176,9 +186,9 @@ void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len)
int curPos = 33 + idLen + padSize;
if (curPos > len)
- throw 1;
+ throw CHeaderErrorException();
int rem = len - curPos;
- r.SystemUse.SetCapacity(rem);
+ r.SystemUse.Alloc(rem);
ReadBytes((Byte *)r.SystemUse, rem);
}
@@ -242,15 +252,34 @@ static inline bool CheckSignature(const Byte *sig, const Byte *data)
void CInArchive::SeekToBlock(UInt32 blockIndex)
{
- if (_stream->Seek((UInt64)blockIndex * VolDescs[MainVolDescIndex].LogicalBlockSize, STREAM_SEEK_SET, &_position) != S_OK)
- throw 1;
+ 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;
@@ -258,7 +287,7 @@ void CInArchive::ReadDir(CDir &d, int level)
for (;;)
{
UInt64 offset = _position - startPos;
- if (offset >= d.DataLength)
+ if (offset >= d.Size)
break;
Byte len = ReadByte();
if (len == 0)
@@ -273,21 +302,44 @@ void CInArchive::ReadDir(CDir &d, int level)
firstItem = false;
}
- for (int i = 0; i < d._subItems.Size(); i++)
+ FOR_VECTOR (i, d._subItems)
ReadDir(d._subItems[i], level + 1);
+
+ UniqStartLocations.DeleteBack();
}
void CInArchive::CreateRefs(CDir &d)
{
if (!d.IsDir())
return;
- for (int i = 0; i < d._subItems.Size(); i++)
+ 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.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);
}
@@ -310,13 +362,13 @@ void CInArchive::ReadBootInfo()
CBootValidationEntry e;
e.PlatformId = ReadByte();
if (ReadUInt16Spec() != 0)
- throw 1;
+ throw CHeaderErrorException();
ReadBytes(e.Id, sizeof(e.Id));
/* UInt16 checkSum = */ ReadUInt16Spec();
if (ReadByte() != 0x55)
- throw 1;
+ throw CHeaderErrorException();
if (ReadByte() != 0xAA)
- throw 1;
+ throw CHeaderErrorException();
}
b = ReadByte();
if (b == NBootEntryId::kInitialEntryBootable || b == NBootEntryId::kInitialEntryNotBootable)
@@ -327,11 +379,11 @@ void CInArchive::ReadBootInfo()
e.LoadSegment = ReadUInt16Spec();
e.SystemType = ReadByte();
if (ReadByte() != 0)
- throw 1;
+ throw CHeaderErrorException();
e.SectorCount = ReadUInt16Spec();
e.LoadRBA = ReadUInt32Le();
if (ReadByte() != 0)
- throw 1;
+ throw CHeaderErrorException();
BootEntries.Add(e);
}
else
@@ -340,16 +392,22 @@ void CInArchive::ReadBootInfo()
HRESULT CInArchive::Open2()
{
- Clear();
- RINOK(_stream->Seek(kStartPos, STREAM_SEEK_CUR, &_position));
+ _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;
@@ -372,9 +430,10 @@ HRESULT CInArchive::Open2()
continue;
*/
}
+
// version = 2 for ISO 9660:1999?
if (ver > 2)
- throw S_FALSE;
+ return S_FALSE;
if (sig[0] == NVolDescType::kTerminator)
{
@@ -382,7 +441,8 @@ HRESULT CInArchive::Open2()
// Skip(0x800 - 7);
// continue;
}
- switch(sig[0])
+
+ switch (sig[0])
{
case NVolDescType::kBootRecord:
{
@@ -408,6 +468,7 @@ HRESULT CInArchive::Open2()
break;
}
}
+
if (VolDescs.IsEmpty())
return S_FALSE;
for (MainVolDescIndex = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--)
@@ -417,30 +478,58 @@ HRESULT CInArchive::Open2()
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())
+ UpdatePhySize(item.ExtentLocation, item.Size);
+ }
+ }
+ }
+ {
+ FOR_VECTOR(i, BootEntries)
+ {
+ const CBootInitialEntry &be = BootEntries[i];
+ UpdatePhySize(be.LoadRBA, GetBootItemSize(i));
+ }
+ }
return S_OK;
}
HRESULT CInArchive::Open(IInStream *inStream)
{
+ Clear();
_stream = inStream;
- UInt64 pos;
- RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &pos));
- RINOK(_stream->Seek(0, STREAM_SEEK_END, &_archiveSize));
- RINOK(_stream->Seek(pos, STREAM_SEEK_SET, &_position));
- HRESULT res = S_FALSE;
- try { res = Open2(); }
- catch(...) { Clear(); res = S_FALSE; }
- _stream.Release();
- return res;
+ 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();
diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h
index f9c6f640..614b3744 100755..100644
--- a/CPP/7zip/Archive/Iso/IsoIn.h
+++ b/CPP/7zip/Archive/Iso/IsoIn.h
@@ -3,8 +3,8 @@
#ifndef __ARCHIVE_ISO_IN_H
#define __ARCHIVE_ISO_IN_H
-#include "Common/IntToString.h"
-#include "Common/MyCom.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/MyCom.h"
#include "../../IStream.h"
@@ -25,37 +25,37 @@ struct CDir: public CDirRecord
_subItems.Clear();
}
- int GetLength(bool checkSusp, int skipSize) const
+ unsigned GetLen(bool checkSusp, unsigned skipSize) const
{
- int len = GetLengthCur(checkSusp, skipSize);
+ unsigned len = GetLenCur(checkSusp, skipSize);
if (Parent != 0)
if (Parent->Parent != 0)
- len += 1 + Parent->GetLength(checkSusp, skipSize);
+ len += 1 + Parent->GetLen(checkSusp, skipSize);
return len;
}
- int GetLengthU() const
+ unsigned GetLenU() const
{
- int len = (int)(FileId.GetCapacity() / 2);
+ unsigned len = (unsigned)(FileId.Size() / 2);
if (Parent != 0)
if (Parent->Parent != 0)
- len += 1 + Parent->GetLengthU();
+ len += 1 + Parent->GetLenU();
return len;
}
- AString GetPath(bool checkSusp, int skipSize) const
+ AString GetPath(bool checkSusp, unsigned skipSize) const
{
AString s;
- int len = GetLength(checkSusp, skipSize);
- char *p = s.GetBuffer(len + 1);
+ unsigned len = GetLen(checkSusp, skipSize);
+ char *p = s.GetBuffer(len);
p += len;
*p = 0;
const CDir *cur = this;
for (;;)
{
- int curLen = cur->GetLengthCur(checkSusp, skipSize);
+ unsigned curLen = cur->GetLenCur(checkSusp, skipSize);
p -= curLen;
- memmove(p, (const char *)(const Byte *)cur->GetNameCur(checkSusp, skipSize), curLen);
+ memcpy(p, (const char *)(const Byte *)cur->GetNameCur(checkSusp, skipSize), curLen);
cur = cur->Parent;
if (cur == 0)
break;
@@ -71,16 +71,16 @@ struct CDir: public CDirRecord
UString GetPathU() const
{
UString s;
- int len = GetLengthU();
- wchar_t *p = s.GetBuffer(len + 1);
+ unsigned len = GetLenU();
+ wchar_t *p = s.GetBuffer(len);
p += len;
*p = 0;
const CDir *cur = this;
for (;;)
{
- int curLen = (int)(cur->FileId.GetCapacity() / 2);
+ unsigned curLen = (unsigned)(cur->FileId.Size() / 2);
p -= curLen;
- for (int i = 0; i < curLen; i++)
+ for (unsigned i = 0; i < curLen; i++)
{
Byte b0 = ((const Byte *)cur->FileId)[i * 2];
Byte b1 = ((const Byte *)cur->FileId)[i * 2 + 1];
@@ -163,23 +163,19 @@ struct CBootInitialEntry
return SectorCount * 512;
}
- UString GetName() const
+ AString GetName() const
{
- UString s;
- if (Bootable)
- s += L"Bootable";
+ AString s = (Bootable ? "Bootable" : "NotBootable");
+ s += '_';
+ if (BootMediaType < kNumBootMediaTypes)
+ s += kMediaTypes[BootMediaType];
else
- s += L"NotBootable";
- s += L"_";
- if (BootMediaType >= kNumBootMediaTypes)
{
- wchar_t name[16];
+ char name[16];
ConvertUInt32ToString(BootMediaType, name);
s += name;
}
- else
- s += kMediaTypes[BootMediaType];
- s += L".img";
+ s += ".img";
return s;
}
};
@@ -228,18 +224,19 @@ struct CVolumeDescriptor
struct CRef
{
- CDir *Dir;
+ const CDir *Dir;
UInt32 Index;
+ UInt32 NumExtents;
+ UInt64 TotalSize;
};
const UInt32 kBlockSize = 1 << 11;
class CInArchive
{
- CMyComPtr<IInStream> _stream;
+ IInStream *_stream;
UInt64 _position;
- Byte m_Buffer[kBlockSize];
UInt32 m_BufferPos;
CDir _rootDir;
@@ -275,15 +272,32 @@ public:
HRESULT Open(IInStream *inStream);
void Clear();
- UInt64 _archiveSize;
+ UInt64 _fileSize;
+ UInt64 PhySize;
CRecordVector<CRef> Refs;
CObjectVector<CVolumeDescriptor> VolDescs;
int MainVolDescIndex;
UInt32 BlockSize;
CObjectVector<CBootInitialEntry> BootEntries;
+
+ bool IsArc;
+ bool UnexpectedEnd;
+ bool HeadersError;
bool IncorrectBigEndian;
+ bool TooDeepDirs;
+ bool SelfLinkedDirs;
+ CRecordVector<UInt32> UniqStartLocations;
+
+ Byte m_Buffer[kBlockSize];
+ void UpdatePhySize(UInt32 blockIndex, UInt64 size)
+ {
+ UInt64 alignedSize = (size + BlockSize - 1) & ~((UInt64)BlockSize - 1);
+ UInt64 end = blockIndex * BlockSize + alignedSize;
+ if (PhySize < end)
+ PhySize = end;
+ }
bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); }
@@ -297,17 +311,17 @@ public:
size = (1440 << 10);
else if (be.BootMediaType == NBootMediaType::k2d88Floppy)
size = (2880 << 10);
- UInt64 startPos = be.LoadRBA * BlockSize;
- if (startPos < _archiveSize)
+ UInt64 startPos = (UInt64)be.LoadRBA * BlockSize;
+ if (startPos < _fileSize)
{
- if (_archiveSize - startPos < size)
- size = _archiveSize - startPos;
+ if (_fileSize - startPos < size)
+ size = _fileSize - startPos;
}
return size;
}
bool IsSusp;
- int SuspSkipSize;
+ unsigned SuspSkipSize;
};
}}
diff --git a/CPP/7zip/Archive/Iso/IsoItem.h b/CPP/7zip/Archive/Iso/IsoItem.h
index f39c2f5d..b6ae21b7 100755..100644
--- a/CPP/7zip/Archive/Iso/IsoItem.h
+++ b/CPP/7zip/Archive/Iso/IsoItem.h
@@ -3,11 +3,10 @@
#ifndef __ARCHIVE_ISO_ITEM_H
#define __ARCHIVE_ISO_ITEM_H
-#include "Common/Types.h"
-#include "Common/MyString.h"
-#include "Common/Buffer.h"
+#include "../../../Common/MyString.h"
+#include "../../../Common/MyBuffer.h"
-#include "Windows/Time.h"
+#include "../../../Windows/TimeUtils.h"
#include "IsoHeader.h"
@@ -41,62 +40,77 @@ struct CRecordingDateTime
struct CDirRecord
{
- Byte ExtendedAttributeRecordLen;
UInt32 ExtentLocation;
- UInt32 DataLength;
+ UInt32 Size;
CRecordingDateTime DateTime;
Byte FileFlags;
Byte FileUnitSize;
Byte InterleaveGapSize;
+ Byte ExtendedAttributeRecordLen;
UInt16 VolSequenceNumber;
CByteBuffer FileId;
CByteBuffer SystemUse;
- bool IsDir() const { return (FileFlags & NFileFlags::kDirectory) != 0; }
+ 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.GetCapacity() != 1)
+ if (FileId.Size() != 1)
return false;
Byte b = *(const Byte *)FileId;
return (b == 0 || b == 1);
}
- const Byte* FindSuspName(int skipSize, int &lenRes) const
+ const Byte* FindSuspName(unsigned skipSize, unsigned &lenRes) const
{
lenRes = 0;
+ if (SystemUse.Size() < skipSize)
+ return 0;
const Byte *p = (const Byte *)SystemUse + skipSize;
- int length = (int)(SystemUse.GetCapacity() - skipSize);
- while (length >= 5)
+ unsigned rem = (unsigned)(SystemUse.Size() - skipSize);
+ while (rem >= 5)
{
- int len = p[2];
+ unsigned len = p[2];
+ if (len > rem)
+ return 0;
if (p[0] == 'N' && p[1] == 'M' && p[3] == 1)
{
+ if (len < 5)
+ return 0; // Check it
lenRes = len - 5;
return p + 5;
}
p += len;
- length -= len;
+ rem -= len;
}
return 0;
}
- int GetLengthCur(bool checkSusp, int skipSize) const
+ unsigned GetLenCur(bool checkSusp, int skipSize) const
{
if (checkSusp)
{
- int len;
+ unsigned len;
const Byte *res = FindSuspName(skipSize, len);
if (res != 0)
return len;
}
- return (int)FileId.GetCapacity();
+ return (unsigned)FileId.Size();
}
const Byte* GetNameCur(bool checkSusp, int skipSize) const
{
if (checkSusp)
{
- int len;
+ unsigned len;
const Byte *res = FindSuspName(skipSize, len);
if (res != 0)
return res;
@@ -105,7 +119,7 @@ struct CDirRecord
}
- bool CheckSusp(const Byte *p, int &startPos) const
+ bool CheckSusp(const Byte *p, unsigned &startPos) const
{
if (p[0] == 'S' &&
p[1] == 'P' &&
@@ -120,17 +134,17 @@ struct CDirRecord
return false;
}
- bool CheckSusp(int &startPos) const
+ bool CheckSusp(unsigned &startPos) const
{
const Byte *p = (const Byte *)SystemUse;
- int length = (int)SystemUse.GetCapacity();
- const int kMinLen = 7;
- if (length < kMinLen)
+ unsigned len = (int)SystemUse.Size();
+ const unsigned kMinLen = 7;
+ if (len < kMinLen)
return false;
if (CheckSusp(p, startPos))
return true;
- const int kOffset2 = 14;
- if (length < kOffset2 + kMinLen)
+ const unsigned kOffset2 = 14;
+ if (len < kOffset2 + kMinLen)
return false;
return CheckSusp(p + kOffset2, startPos);
}
diff --git a/CPP/7zip/Archive/Iso/IsoRegister.cpp b/CPP/7zip/Archive/Iso/IsoRegister.cpp
index 67a09c76..c6f4a521 100755..100644
--- a/CPP/7zip/Archive/Iso/IsoRegister.cpp
+++ b/CPP/7zip/Archive/Iso/IsoRegister.cpp
@@ -5,9 +5,19 @@
#include "../../Common/RegisterArc.h"
#include "IsoHandler.h"
-static IInArchive *CreateArc() { return new NArchive::NIso::CHandler; }
+
+namespace NArchive {
+namespace NIso {
+
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"Iso", L"iso img", 0, 0xE7, { 'C', 'D', '0', '0', '1', 0x1 }, 7, false, CreateArc, 0 };
+ { "Iso", "iso img", 0, 0xE7,
+ 5, { 'C', 'D', '0', '0', '1' },
+ NArchive::NIso::kStartPos + 1,
+ 0,
+ CreateArc };
REGISTER_ARC(Iso)
+
+}}
diff --git a/CPP/7zip/Archive/Iso/StdAfx.h b/CPP/7zip/Archive/Iso/StdAfx.h
index 2e4be10b..2854ff3e 100755..100644
--- a/CPP/7zip/Archive/Iso/StdAfx.h
+++ b/CPP/7zip/Archive/Iso/StdAfx.h
@@ -3,7 +3,6 @@
#ifndef __STDAFX_H
#define __STDAFX_H
-#include "../../../Common/MyWindows.h"
-#include "../../../Common/NewHandler.h"
+#include "../../../Common/Common.h"
#endif
diff --git a/CPP/7zip/Archive/LzhHandler.cpp b/CPP/7zip/Archive/LzhHandler.cpp
index 194de47e..74f713f6 100755..100644
--- a/CPP/7zip/Archive/LzhHandler.cpp
+++ b/CPP/7zip/Archive/LzhHandler.cpp
@@ -4,12 +4,12 @@
#include "../../../C/CpuArch.h"
-#include "Common/Buffer.h"
-#include "Common/ComTry.h"
-#include "Common/StringConvert.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/StringConvert.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
#include "../ICoder.h"
@@ -44,10 +44,11 @@ struct CExtension
{
Byte Type;
CByteBuffer Data;
+
AString GetString() const
{
AString s;
- for (size_t i = 0; i < Data.GetCapacity(); i++)
+ for (size_t i = 0; i < Data.Size(); i++)
{
char c = (char)Data[i];
if (c == 0)
@@ -58,6 +59,21 @@ struct CExtension
}
};
+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;
@@ -85,7 +101,7 @@ struct CItem
{
if (!IsLhMethod())
return false;
- switch(Method[3])
+ switch (Method[3])
{
case '1':
return true;
@@ -97,7 +113,7 @@ struct CItem
{
if (!IsLhMethod())
return false;
- switch(Method[3])
+ switch (Method[3])
{
case '4':
case '5':
@@ -112,7 +128,7 @@ struct CItem
{
if (!IsLhMethod())
return 0;
- switch(Method[3])
+ switch (Method[3])
{
case '1': return 12;
case '2': return 13;
@@ -127,13 +143,14 @@ struct CItem
int FindExt(Byte type) const
{
- for (int i = 0; i < Extensions.Size(); i++)
+ 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)
{
@@ -219,7 +236,6 @@ static HRESULT GetNextItem(ISequentialInStream *stream, bool &filled, CItem &ite
return S_OK;
Byte header[256];
- const UInt32 kBasicPartSize = 22;
processedSize = kBasicPartSize;
RINOK(ReadStream(stream, header, &processedSize));
if (processedSize != kBasicPartSize)
@@ -281,7 +297,7 @@ static HRESULT GetNextItem(ISequentialInStream *stream, bool &filled, CItem &ite
CExtension ext;
RINOK(ReadStream_FALSE(stream, &ext.Type, 1))
nextSize -= 3;
- ext.Data.SetCapacity(nextSize);
+ ext.Data.Alloc(nextSize);
RINOK(ReadStream_FALSE(stream, (Byte *)ext.Data, nextSize))
item.Extensions.Add(ext);
Byte hdr2[2];
@@ -324,28 +340,23 @@ static const char *kUnknownOS = "Unknown";
static const char *GetOS(Byte osId)
{
- for (int i = 0; i < sizeof(g_OsPairs) / sizeof(g_OsPairs[0]); i++)
+ for (unsigned i = 0; i < ARRAY_SIZE(g_OsPairs); i++)
if (g_OsPairs[i].Id == osId)
return g_OsPairs[i].Name;
return kUnknownOS;
}
-static const STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- // { NULL, kpidAttrib, VT_UI4},
- { NULL, kpidCRC, VT_UI4},
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidHostOS, VT_BSTR}
-};
-
-static const STATPROPSTG kArcProps[] =
-{
- { NULL, kpidPhySize, VT_UI8}
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ // kpidAttrib,
+ kpidCRC,
+ kpidMethod,
+ kpidHostOS
};
class CCRC
@@ -446,7 +457,8 @@ class CHandler:
CObjectVector<CItemEx> _items;
CMyComPtr<IInStream> _stream;
UInt64 _phySize;
- AString _errorMessage;
+ UInt32 _errorFlags;
+ bool _isArc;
public:
MY_UNKNOWN_IMP1(IInArchive)
INTERFACE_IInArchive(;)
@@ -454,7 +466,7 @@ public:
};
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps
+IMP_IInArchive_ArcProps_NO_Table
CHandler::CHandler() {}
@@ -467,21 +479,26 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidPhySize: prop = _phySize; break;
- case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; 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)
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
+ NCOM::CPropVariant prop;
const CItemEx &item = _items[index];
- switch(propID)
+ switch (propID)
{
case kpidPath:
{
@@ -538,6 +555,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback)
{
COM_TRY_BEGIN
+ Close();
try
{
_items.Clear();
@@ -548,7 +566,6 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
- _phySize = 0;
for (;;)
{
CItemEx item;
@@ -557,7 +574,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
RINOK(stream->Seek(0, STREAM_SEEK_CUR, &item.DataPosition));
if (result == S_FALSE)
{
- _errorMessage = "Incorrect header";
+ _errorFlags = kpv_ErrorFlags_HeadersError;
break;
}
@@ -568,12 +585,14 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
break;
_items.Add(item);
+ _isArc = true;
+
UInt64 newPostion;
RINOK(stream->Seek(item.PackSize, STREAM_SEEK_CUR, &newPostion));
if (newPostion > endPos)
{
_phySize = endPos;
- _errorMessage = "Unexpected end of archive";
+ _errorFlags = kpv_ErrorFlags_UnexpectedEnd;
break;
}
_phySize = newPostion;
@@ -607,7 +626,9 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
STDMETHODIMP CHandler::Close()
{
- _errorMessage.Empty();
+ _isArc = false;
+ _phySize = 0;
+ _errorFlags = 0;
_items.Clear();
_stream.Release();
return S_OK;
@@ -619,7 +640,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_BEGIN
bool testMode = (testModeSpec != 0);
UInt64 totalUnPacked = 0, totalPacked = 0;
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items.Size();
if (numItems == 0)
@@ -730,7 +751,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
*/
else
- opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
if (opRes == NExtract::NOperationResult::kOK)
{
@@ -751,10 +772,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"Lzh", L"lzh lha", 0, 6, { '-', 'l' }, 2, false, CreateArc, 0 };
+ { "Lzh", "lzh lha", 0, 6,
+ 3, { '-', 'l', 'h' },
+ 2,
+ 0,
+ CreateArc, NULL, IsArc_Lzh };
REGISTER_ARC(Lzh)
diff --git a/CPP/7zip/Archive/LzmaHandler.cpp b/CPP/7zip/Archive/LzmaHandler.cpp
index 778c2fd8..d1e19677 100755..100644
--- a/CPP/7zip/Archive/LzmaHandler.cpp
+++ b/CPP/7zip/Archive/LzmaHandler.cpp
@@ -4,10 +4,10 @@
#include "../../../C/CpuArch.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
-#include "Windows/PropVariant.h"
+#include "../../Windows/PropVariant.h"
#include "../Common/CreateCoder.h"
#include "../Common/ProgressUtils.h"
@@ -26,17 +26,24 @@ namespace NLzma {
static bool CheckDicSize(const Byte *p)
{
UInt32 dicSize = GetUi32(p);
- for (int i = 1; i <= 30; i++)
+ 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);
}
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMethod, VT_BSTR}
+ kpidSize,
+ kpidPackSize,
+ kpidMethod
+};
+
+static const Byte kArcProps[] =
+{
+ kpidNumStreams
};
struct CHeader
@@ -62,16 +69,17 @@ bool CHeader::Parse(const Byte *buf, bool isThereFilter)
return
LzmaProps[0] < 5 * 5 * 9 &&
FilterID < 2 &&
- (!HasSize() || Size < ((UInt64)1 << 56)) &&
- CheckDicSize(LzmaProps + 1);
+ (!HasSize() || Size < ((UInt64)1 << 56))
+ && CheckDicSize(LzmaProps + 1);
}
class CDecoder
{
- NCompress::NLzma::CDecoder *_lzmaDecoderSpec;
CMyComPtr<ICompressCoder> _lzmaDecoder;
CMyComPtr<ISequentialOutStream> _bcjStream;
public:
+ NCompress::NLzma::CDecoder *_lzmaDecoderSpec;
+
~CDecoder();
HRESULT Create(DECL_EXTERNAL_CODECS_LOC_VARS
bool filtered, ISequentialInStream *inStream);
@@ -86,7 +94,7 @@ public:
{ return _lzmaDecoderSpec->ReadFromInputStream(data, size, processedSize); }
};
-static const UInt64 k_BCJ = 0x03030103;
+static const UInt32 k_BCJ = 0x03030103;
HRESULT CDecoder::Create(
DECL_EXTERNAL_CODECS_LOC_VARS
@@ -95,6 +103,7 @@ HRESULT CDecoder::Create(
if (!_lzmaDecoder)
{
_lzmaDecoderSpec = new NCompress::NLzma::CDecoder;
+ _lzmaDecoderSpec->FinishStream = true;
_lzmaDecoder = _lzmaDecoderSpec;
}
@@ -166,6 +175,10 @@ HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream,
}
RINOK(res);
+ if (header.HasSize())
+ if (_lzmaDecoderSpec->GetOutputProcessedSize() != header.Size)
+ return S_FALSE;
+
return S_OK;
}
@@ -178,11 +191,24 @@ class CHandler:
{
CHeader _header;
bool _lzma86;
- UInt64 _startPosition;
- UInt64 _packSize;
- bool _packSizeDefined;
CMyComPtr<IInStream> _stream;
CMyComPtr<ISequentialInStream> _seqStream;
+
+ bool _isArc;
+ bool _needSeekToStart;
+ bool _dataAfterEnd;
+ bool _needMoreInput;
+
+ bool _packSize_Defined;
+ bool _unpackSize_Defined;
+ bool _numStreams_Defined;
+
+ bool _unsupported;
+ bool _dataError;
+
+ UInt64 _packSize;
+ UInt64 _unpackSize;
+ UInt64 _numStreams;
DECL_EXTERNAL_CODECS_VARS
DECL_ISetCompressCodecsInfo
@@ -204,14 +230,26 @@ public:
};
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO_Table
+IMP_IInArchive_ArcProps
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
- case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ 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 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;
+ }
}
prop.Detach(value);
return S_OK;
@@ -226,50 +264,37 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
static void DictSizeToString(UInt32 value, char *s)
{
for (int i = 0; i <= 31; i++)
- if ((UInt32(1) << i) == value)
+ if (((UInt32)1 << i) == value)
{
::ConvertUInt32ToString(i, s);
return;
}
char c = 'b';
- if ((value & ((1 << 20) - 1)) == 0)
- {
- value >>= 20;
- c = 'm';
- }
- else if ((value & ((1 << 10) - 1)) == 0)
- {
- value >>= 10;
- c = 'k';
- }
+ if ((value & ((1 << 20) - 1)) == 0) { value >>= 20; c = 'm'; }
+ else if ((value & ((1 << 10) - 1)) == 0) { value >>= 10; c = 'k'; }
::ConvertUInt32ToString(value, s);
- int p = MyStringLen(s);
- s[p++] = c;
- s[p++] = '\0';
+ s += MyStringLen(s);
+ *s++ = c;
+ *s = 0;
}
-static void MyStrCat(char *d, const char *s)
-{
- MyStringCopy(d + MyStringLen(d), s);
-}
-
-STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
{
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidSize: if (_stream && _header.HasSize()) prop = _header.Size; break;
- case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidPackSize: if (_packSize_Defined) prop = _packSize; break;
case kpidMethod:
if (_stream)
{
- char s[64];
- s[0] = '\0';
+ char sz[64];
+ char *s = sz;
if (_header.FilterID != 0)
- MyStrCat(s, "BCJ ");
- MyStrCat(s, "LZMA:");
- DictSizeToString(_header.GetDicSize(), s + MyStringLen(s));
- prop = s;
+ s = MyStpCpy(s, "BCJ ");
+ s = MyStpCpy(s, "LZMA:");
+ DictSizeToString(_header.GetDicSize(), s);
+ prop = sz;
}
break;
}
@@ -277,11 +302,52 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIA
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 *)
{
- RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_startPosition));
+ Close();
- const UInt32 kBufSize = 1 + 5 + 8 + 1;
+ const UInt32 kBufSize = 1 + 5 + 8 + 2;
Byte buf[kBufSize];
RINOK(ReadStream_FALSE(inStream, buf, kBufSize));
@@ -289,35 +355,71 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal
if (!_header.Parse(buf, _lzma86))
return S_FALSE;
const Byte *start = buf + GetHeaderSize();
- if (start[0] != 0)
+ if (start[0] != 0 /* || (start[1] & 0x80) != 0 */ ) // empty stream with EOS is not 0x80
return S_FALSE;
- UInt64 endPos;
- RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
- _packSize = endPos - _startPosition;
- _packSizeDefined = true;
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &_packSize));
if (_packSize >= 24 && _header.Size == 0 && _header.FilterID == 0 && _header.LzmaProps[0] == 0)
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()
{
- _packSizeDefined = false;
+ _isArc = false;
+ _packSize_Defined = false;
+ _unpackSize_Defined = false;
+ _numStreams_Defined = false;
+
+ _dataAfterEnd = false;
+ _needMoreInput = false;
+ _unsupported = false;
+ _dataError = false;
+
+ _packSize = 0;
+
+ _needSeekToStart = false;
+
_stream.Release();
_seqStream.Release();
return S_OK;
}
+class CCompressProgressInfoImp:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+ CMyComPtr<IArchiveOpenCallback> Callback;
+public:
+ UInt64 Offset;
+
+ MY_UNKNOWN_IMP1(ICompressProgressInfo)
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+ void Init(IArchiveOpenCallback *callback) { Callback = callback; }
+};
+
+STDMETHODIMP CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)
+{
+ if (Callback)
+ {
+ 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)
@@ -325,10 +427,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_BEGIN
if (numItems == 0)
return S_OK;
- if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
- if (_stream)
+ if (_packSize_Defined)
extractCallback->SetTotal(_packSize);
@@ -352,10 +454,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, true);
- if (_stream)
+ if (_needSeekToStart)
{
- RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ if (!_stream)
+ return E_FAIL;
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
}
+ else
+ _needSeekToStart = true;
CDecoder decoder;
HRESULT result = decoder.Create(
@@ -363,67 +469,132 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
_lzma86, _seqStream);
RINOK(result);
- Int32 opRes = NExtract::NOperationResult::kOK;
bool firstItem = true;
+ UInt64 packSize = 0;
+ UInt64 unpackSize = 0;
+ UInt64 numStreams = 0;
+
+ bool dataAfterEnd = false;
+
for (;;)
{
- lps->OutSize = outStreamSpec->GetSize();
- lps->InSize = _packSize = decoder.GetInputProcessedSize();
- _packSizeDefined = true;
+ lps->InSize = packSize;
+ lps->OutSize = unpackSize;
RINOK(lps->SetCur());
- CHeader st;
-
const UInt32 kBufSize = 1 + 5 + 8;
Byte buf[kBufSize];
const UInt32 headerSize = GetHeaderSize();
UInt32 processed;
RINOK(decoder.ReadInput(buf, headerSize, &processed));
if (processed != headerSize)
+ {
+ 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)
{
- opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ _unsupported = true;
+ result = S_FALSE;
break;
}
if (result == S_FALSE)
- {
- opRes = NExtract::NOperationResult::kDataError;
break;
- }
RINOK(result);
}
+
if (firstItem)
- return E_FAIL;
+ {
+ _isArc = false;
+ result = S_FALSE;
+ }
+ else if (result == S_OK || result == S_FALSE)
+ {
+ if (dataAfterEnd)
+ _dataAfterEnd = true;
+ else if (decoder._lzmaDecoderSpec->NeedMoreInput)
+ _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(opRes);
+ return extractCallback->SetOperationResult(opResult);
COM_TRY_END
}
IMPL_ISetCompressCodecsInfo
-static IInArchive *CreateArc() { return new CHandler(false); }
-static IInArchive *CreateArc86() { return new CHandler(true); }
-
namespace NLzmaAr {
-
+
+IMP_CreateArcIn_2(CHandler(false))
+
static CArcInfo g_ArcInfo =
- { L"lzma", L"lzma", 0, 0xA, { 0 }, 0, true, CreateArc, NULL };
+ { "lzma", "lzma", 0, 0xA,
+ 0, { 0 },
+ // 2, { 0x5D, 0x00 },
+ 0,
+ NArcInfoFlags::kStartOpen |
+ NArcInfoFlags::kKeepName,
+ CreateArc, NULL,
+ IsArc_Lzma };
+
REGISTER_ARC(Lzma)
}
namespace NLzma86Ar {
+IMP_CreateArcIn_2(CHandler(true))
+
static CArcInfo g_ArcInfo =
- { L"lzma86", L"lzma86", 0, 0xB, { 0 }, 0, true, CreateArc86, NULL };
+ { "lzma86", "lzma86", 0, 0xB,
+ 0, { 0 },
+ 0,
+ NArcInfoFlags::kKeepName,
+ CreateArc, NULL,
+ IsArc_Lzma86 };
+
REGISTER_ARC(Lzma86)
}
diff --git a/CPP/7zip/Archive/MachoHandler.cpp b/CPP/7zip/Archive/MachoHandler.cpp
index a6261f34..11ff9703 100755..100644
--- a/CPP/7zip/Archive/MachoHandler.cpp
+++ b/CPP/7zip/Archive/MachoHandler.cpp
@@ -4,10 +4,12 @@
#include "../../../C/CpuArch.h"
-#include "Common/Buffer.h"
-#include "Common/ComTry.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/StringConvert.h"
+#include "../../Common/IntToString.h"
-#include "Windows/PropVariantUtils.h"
+#include "../../Windows/PropVariantUtils.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -16,65 +18,142 @@
#include "../Compress/CopyCoder.h"
-static UInt32 Get32(const Byte *p, int be) { if (be) return GetBe32(p); return GetUi32(p); }
-static UInt64 Get64(const Byte *p, int be) { if (be) return GetBe64(p); return GetUi64(p); }
+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 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 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 MACH_MACHINE_PPC64 (MACH_ARCH_ABI64 | MACH_MACHINE_PPC)
-#define MACH_MACHINE_AMD64 (MACH_ARCH_ABI64 | MACH_MACHINE_386)
+#define CPU_SUBTYPE_I386_ALL 3
-#define MACH_CMD_SEGMENT_32 1
-#define MACH_CMD_SEGMENT_64 0x19
+#define CPU_TYPE_PPC64 (CPU_ARCH_ABI64 | CPU_TYPE_PPC)
+#define CPU_TYPE_AMD64 (CPU_ARCH_ABI64 | CPU_TYPE_386)
-#define MACH_SECT_TYPE_MASK 0x000000FF
-#define MACH_SECT_ATTR_MASK 0xFFFFFF00
+#define CPU_SUBTYPE_LIB64 (1 << 31)
-#define MACH_SECT_ATTR_ZEROFILL 1
+#define CPU_SUBTYPE_POWERPC_970 100
+
+static const char *k_PowerPc_SubTypes[] =
+{
+ NULL
+ , "601"
+ , "602"
+ , "603"
+ , "603e"
+ , "603ev"
+ , "604"
+ , "604e"
+ , "620"
+ , "750"
+ , "7400"
+ , "7450"
+};
+
+static const CUInt32PCharPair g_CpuPairs[] =
+{
+ { 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 *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"
+ "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 *g_FileTypes[] =
{
- "0",
- "OBJECT",
- "EXECUTE",
- "FVMLIB",
- "CORE",
- "PRELOAD",
- "DYLIB",
- "DYLINKER",
- "BUNDLE",
- "DYLIB_STUB",
- "DSYM"
+ "0"
+ , "OBJECT"
+ , "EXECUTE"
+ , "FVMLIB"
+ , "CORE"
+ , "PRELOAD"
+ , "DYLIB"
+ , "DYLINKER"
+ , "BUNDLE"
+ , "DYLIB_STUB"
+ , "DSYM"
};
+
+static const char *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" },
@@ -89,16 +168,6 @@ static const CUInt32PCharPair g_Flags[] =
{ 8, "LOC_RELOC" }
};
-static const CUInt32PCharPair g_MachinePairs[] =
-{
- { MACH_MACHINE_386, "x86" },
- { MACH_MACHINE_ARM, "ARM" },
- { MACH_MACHINE_SPARC, "SPARC" },
- { MACH_MACHINE_PPC, "PowerPC" },
- { MACH_MACHINE_PPC64, "PowerPC 64-bit" },
- { MACH_MACHINE_AMD64, "x64" }
-};
-
static const int kNameSize = 16;
struct CSegment
@@ -121,209 +190,150 @@ struct CSection
bool IsDummy;
CSection(): IsDummy(false) {}
- // UInt64 GetPackSize() const { return Flags == MACH_SECT_ATTR_ZEROFILL ? 0 : Size; }
+ // UInt64 GetPackSize() const { return Flags == SECT_ATTR_ZEROFILL ? 0 : Size; }
UInt64 GetPackSize() const { return PSize; }
};
class CHandler:
public IInArchive,
+ public IArchiveAllowTail,
public CMyUnknownImp
{
CMyComPtr<IInStream> _inStream;
CObjectVector<CSegment> _segments;
CObjectVector<CSection> _sections;
+ bool _allowTail;
bool _mode64;
bool _be;
- UInt32 _machine;
+ UInt32 _cpuType;
+ UInt32 _cpuSubType;
UInt32 _type;
+ UInt32 _flags;
UInt32 _headersSize;
UInt64 _totalSize;
+
HRESULT Open2(ISequentialInStream *stream);
- bool Parse(const Byte *buf, UInt32 size);
public:
- MY_UNKNOWN_IMP1(IInArchive)
+ MY_UNKNOWN_IMP2(IInArchive, IArchiveAllowTail)
INTERFACE_IInArchive(;)
+ STDMETHOD(AllowTail)(Int32 allowTail);
+ CHandler(): _allowTail(false) {}
};
-bool CHandler::Parse(const Byte *buf, UInt32 size)
+static const Byte kArcProps[] =
{
- bool mode64 = _mode64;
- bool be = _be;
-
- const Byte *bufStart = buf;
- bool reduceCommands = false;
- if (size < 512)
- return false;
-
- _machine = Get32(buf + 4, be);
- _type = Get32(buf + 0xC, be);
-
- UInt32 numCommands = Get32(buf + 0x10, be);
- UInt32 commandsSize = Get32(buf + 0x14, be);
- if (commandsSize > size)
- return false;
-
- if (commandsSize > (1 << 24) || numCommands > (1 << 18))
- return false;
-
- if (numCommands > 16)
- {
- reduceCommands = true;
- numCommands = 16;
- }
-
- _headersSize = 0;
-
- buf += 0x1C;
- size -= 0x1C;
+ kpidCpu,
+ kpidBit64,
+ kpidBigEndian,
+ kpidCharacts,
+ kpidHeadersSize
+};
- if (mode64)
- {
- buf += 4;
- size -= 4;
- }
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidCharacts,
+ kpidOffset,
+ kpidVa
+};
- _totalSize = (UInt32)(buf - bufStart);
- if (commandsSize < size)
- size = commandsSize;
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
- for (UInt32 cmdIndex = 0; cmdIndex < numCommands; cmdIndex++)
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ CPropVariant prop;
+ switch (propID)
{
- if (size < 8)
- return false;
- UInt32 cmd = Get32(buf, be);
- UInt32 cmdSize = Get32(buf + 4, be);
- if (size < cmdSize)
- return false;
- if (cmd == MACH_CMD_SEGMENT_32 || cmd == MACH_CMD_SEGMENT_64)
+ case kpidShortComment:
+ case kpidCpu:
{
- UInt32 offs = (cmd == MACH_CMD_SEGMENT_64) ? 0x48 : 0x38;
- if (cmdSize < offs)
- break;
-
- UInt64 vmAddr, vmSize, phAddr, phSize;
-
+ AString s;
+ char temp[16];
+ UInt32 cpu = _cpuType & ~(UInt32)CPU_ARCH_ABI64;
+ if (_cpuType == CPU_TYPE_AMD64)
+ s = "x64";
+ else
{
- if (cmd == MACH_CMD_SEGMENT_64)
- {
- vmAddr = Get64(buf + 0x18, be);
- vmSize = Get64(buf + 0x20, be);
- phAddr = Get64(buf + 0x28, be);
- phSize = Get64(buf + 0x30, be);
- }
- else
+ const char *n = NULL;
+ for (unsigned i = 0; i < ARRAY_SIZE(g_CpuPairs); i++)
{
- vmAddr = Get32(buf + 0x18, be);
- vmSize = Get32(buf + 0x1C, be);
- phAddr = Get32(buf + 0x20, be);
- phSize = Get32(buf + 0x24, be);
+ const CUInt32PCharPair &pair = g_CpuPairs[i];
+ if (pair.Value == cpu)
+ {
+ n = pair.Name;
+ break;
+ }
}
+ if (!n)
{
- UInt64 totalSize = phAddr + phSize;
- if (totalSize > _totalSize)
- _totalSize = totalSize;
+ ConvertUInt32ToString(cpu, temp);
+ n = temp;
}
+ s = n;
+
+ if (_cpuType & CPU_ARCH_ABI64)
+ s += " 64-bit";
+ else if (_cpuSubType & CPU_SUBTYPE_LIB64)
+ s += " 64-bit lib";
}
-
- CSegment seg;
- memcpy(seg.Name, buf + 8, kNameSize);
- _segments.Add(seg);
-
- UInt32 numSections = Get32(buf + offs - 8, be);
- if (numSections > (1 << 8))
- return false;
-
- if (numSections == 0)
- {
- CSection section;
- section.IsDummy = true;
- section.SegmentIndex = _segments.Size() - 1;
- section.Va = vmAddr;
- section.PSize = phSize;
- section.VSize = vmSize;
- section.Pa = phAddr;
- section.Flags = 0;
- _sections.Add(section);
- }
- else do
+ UInt32 t = _cpuSubType & ~(UInt32)CPU_SUBTYPE_LIB64;
+ if (t != 0 && (t != CPU_SUBTYPE_I386_ALL || cpu != CPU_TYPE_386))
{
- CSection section;
- UInt32 headerSize = (cmd == MACH_CMD_SEGMENT_64) ? 0x50 : 0x44;
- const Byte *p = buf + offs;
- if (cmdSize - offs < headerSize)
- break;
- if (cmd == MACH_CMD_SEGMENT_64)
+ const char *n = NULL;
+ if (cpu == CPU_TYPE_PPC)
{
- section.Va = Get64(p + 0x20, be);
- section.VSize = Get64(p + 0x28, be);
- section.Pa = Get32(p + 0x30, be);
- section.Flags = Get32(p + 0x40, be);
+ if (t == CPU_SUBTYPE_POWERPC_970)
+ n = "970";
+ else if (t < ARRAY_SIZE(k_PowerPc_SubTypes))
+ n = k_PowerPc_SubTypes[t];
}
- else
+ if (!n)
{
- section.Va = Get32(p + 0x20, be);
- section.VSize = Get32(p + 0x24, be);
- section.Pa = Get32(p + 0x28, be);
- section.Flags = Get32(p + 0x38, be);
+ ConvertUInt32ToString(t, temp);
+ n = temp;
}
- if (section.Flags == MACH_SECT_ATTR_ZEROFILL)
- section.PSize = 0;
- else
- section.PSize = section.VSize;
- memcpy(section.Name, p, kNameSize);
- memcpy(section.SegName, p + kNameSize, kNameSize);
- section.SegmentIndex = _segments.Size() - 1;
- _sections.Add(section);
- offs += headerSize;
+ s += ' ';
+ s += n;
}
- while (--numSections);
-
- if (offs != cmdSize)
- return false;
+ 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 += ' ';
+ res += s;
+ }
+ prop = res;
+ break;
}
- buf += cmdSize;
- size -= cmdSize;
- }
- _headersSize = (UInt32)(buf - bufStart);
- return reduceCommands || (size == 0);
-}
-
-static STATPROPSTG kArcProps[] =
-{
- { NULL, kpidCpu, VT_BSTR},
- { NULL, kpidBit64, VT_BOOL},
- { NULL, kpidBigEndian, VT_BOOL},
- { NULL, kpidCharacts, VT_BSTR},
- { NULL, kpidPhySize, VT_UI8},
- { NULL, kpidHeadersSize, VT_UI4}
-};
-
-static STATPROPSTG kProps[] =
-{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidCharacts, VT_BSTR},
- { NULL, kpidOffset, VT_UI8},
- { NULL, kpidVa, VT_UI8}
-};
-
-IMP_IInArchive_Props
-IMP_IInArchive_ArcProps
-
-STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
-{
- COM_TRY_BEGIN
- NCOM::CPropVariant prop;
- switch(propID)
- {
- case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _machine, prop); break;
- case kpidCharacts: TYPE_TO_PROP(g_FileTypes, _type, prop); break;
case kpidPhySize: prop = _totalSize; break;
case kpidHeadersSize: prop = _headersSize; break;
case kpidBit64: if (_mode64) prop = _mode64; break;
case kpidBigEndian: if (_be) prop = _be; break;
+ 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;
@@ -340,10 +350,8 @@ static AString GetName(const char *name)
static AString SectFlagsToString(UInt32 flags)
{
- AString res = TypeToString(g_SectTypes, sizeof(g_SectTypes) / sizeof(g_SectTypes[0]),
- flags & MACH_SECT_TYPE_MASK);
- AString s = FlagsToString(g_Flags, sizeof(g_Flags) / sizeof(g_Flags[0]),
- flags & MACH_SECT_ATTR_MASK);
+ AString res = TypeToString(g_SectTypes, ARRAY_SIZE(g_SectTypes), flags & SECT_TYPE_MASK);
+ AString s = FlagsToString(g_Flags, ARRAY_SIZE(g_Flags), flags & SECT_ATTR_MASK);
if (!s.IsEmpty())
{
res += ' ';
@@ -355,21 +363,21 @@ static AString SectFlagsToString(UInt32 flags)
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NCOM::CPropVariant prop;
+ CPropVariant prop;
const CSection &item = _sections[index];
- switch(propID)
+ switch (propID)
{
case kpidPath:
{
AString s = GetName(_segments[item.SegmentIndex].Name);
if (!item.IsDummy)
s += GetName(item.Name);
- StringToProp(s, prop);
+ prop = MultiByteToUnicodeString(s);
break;
}
case kpidSize: /* prop = (UInt64)item.VSize; break; */
case kpidPackSize: prop = (UInt64)item.GetPackSize(); break;
- case kpidCharacts: if (!item.IsDummy) StringToProp(SectFlagsToString(item.Flags), prop); break;
+ case kpidCharacts: if (!item.IsDummy) prop = SectFlagsToString(item.Flags); break;
case kpidOffset: prop = item.Pa; break;
case kpidVa: prop = item.Va; break;
}
@@ -380,18 +388,12 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
HRESULT CHandler::Open2(ISequentialInStream *stream)
{
- const UInt32 kBufSize = 1 << 18;
- const UInt32 kSigSize = 4;
+ const UInt32 kStartHeaderSize = 7 * 4;
- CByteBuffer buffer;
- buffer.SetCapacity(kBufSize);
- Byte *buf = buffer;
-
- size_t processed = kSigSize;
- RINOK(ReadStream_FALSE(stream, buf, processed));
- UInt32 sig = GetUi32(buf);
+ Byte header[kStartHeaderSize];
+ RINOK(ReadStream_FALSE(stream, header, kStartHeaderSize));
bool be, mode64;
- switch(sig)
+ switch (GetUi32(header))
{
case 0xCEFAEDFE: be = true; mode64 = false; break;
case 0xCFFAEDFE: be = true; mode64 = true; break;
@@ -399,11 +401,148 @@ HRESULT CHandler::Open2(ISequentialInStream *stream)
case 0xFEEDFACF: be = false; mode64 = true; break;
default: return S_FALSE;
}
- processed = kBufSize - kSigSize;
- RINOK(ReadStream(stream, buf + kSigSize, &processed));
- _mode64 = mode64;
- _be = be;
- return Parse(buf, (UInt32)processed + kSigSize) ? S_OK : S_FALSE;
+
+ 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 &sect = _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 &sect = _sections.AddNew();
+ unsigned f32Offset;
+ if (cmd == CMD_SEGMENT_64)
+ {
+ sect.Va = Get64(p + 0x20, be);
+ sect.VSize = Get64(p + 0x28, be);
+ f32Offset = 0x30;
+ }
+ else
+ {
+ sect.Va = Get32(p + 0x20, be);
+ sect.VSize = Get32(p + 0x24, be);
+ f32Offset = 0x28;
+ }
+ sect.Pa = Get32(p + f32Offset, be);
+ sect.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,
@@ -413,6 +552,13 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
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
@@ -420,6 +566,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
STDMETHODIMP CHandler::Close()
{
+ _totalSize = 0;
_inStream.Release();
_sections.Clear();
_segments.Clear();
@@ -436,7 +583,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _sections.Size();
if (numItems == 0)
@@ -490,10 +637,27 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+STDMETHODIMP CHandler::AllowTail(Int32 allowTail)
+{
+ _allowTail = IntToBool(allowTail);
+ return S_OK;
+}
+
+IMP_CreateArcIn
+
+#define k_Signature { \
+ 4, 0xCE, 0xFA, 0xED, 0xFE, \
+ 4, 0xCF, 0xFA, 0xED, 0xFE, \
+ 4, 0xFE, 0xED, 0xFA, 0xCE, \
+ 4, 0xFE, 0xED, 0xFA, 0xCF }
static CArcInfo g_ArcInfo =
- { L"MachO", L"", 0, 0xDF, { 0 }, 0, false, CreateArc, 0 };
+ { "MachO", "macho", 0, 0xDF,
+ 4 * 5, k_Signature,
+ 0,
+ NArcInfoFlags::kMultiSignature |
+ NArcInfoFlags::kPreArc,
+ CreateArc };
REGISTER_ARC(Macho)
diff --git a/CPP/7zip/Archive/MbrHandler.cpp b/CPP/7zip/Archive/MbrHandler.cpp
index b6d79182..309bc286 100755..100644
--- a/CPP/7zip/Archive/MbrHandler.cpp
+++ b/CPP/7zip/Archive/MbrHandler.cpp
@@ -10,12 +10,12 @@
#include "../../../C/CpuArch.h"
-#include "Common/Buffer.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/MyString.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyString.h"
-#include "Windows/PropVariant.h"
+#include "../../Windows/PropVariant.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -169,7 +169,7 @@ static const CPartType kPartTypes[] =
static int FindPartType(UInt32 type)
{
- for (int i = 0; i < sizeof(kPartTypes) / sizeof(kPartTypes[0]); i++)
+ for (int i = 0; i < ARRAY_SIZE(kPartTypes); i++)
if (kPartTypes[i].Id == type)
return i;
return -1;
@@ -210,7 +210,7 @@ HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, int
{
const UInt32 kSectorSize = 512;
- _buffer.SetCapacity(kSectorSize);
+ _buffer.Alloc(kSectorSize);
Byte *buf = _buffer;
UInt64 newPos = (UInt64)lba << 9;
if (newPos + 512 > _totalSize)
@@ -243,7 +243,7 @@ HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, int
part.Print();
#endif
- int numItems = _items.Size();
+ unsigned numItems = _items.Size();
UInt32 newLba = lba + part.Lba;
if (part.IsExtended())
@@ -323,6 +323,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
STDMETHODIMP CHandler::Close()
{
+ _totalSize = 0;
_items.Clear();
_stream.Release();
return S_OK;
@@ -335,7 +336,7 @@ enum
kpidEndChs
};
-STATPROPSTG kProps[] =
+static const STATPROPSTG kProps[] =
{
{ NULL, kpidPath, VT_BSTR},
{ NULL, kpidSize, VT_UI8},
@@ -352,12 +353,12 @@ IMP_IInArchive_ArcProps_NO_Table
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidMainSubfile:
{
int mainIndex = -1;
- for (int i = 0; i < _items.Size(); i++)
+ FOR_VECTOR (i, _items)
if (_items[i].IsReal)
{
if (mainIndex >= 0)
@@ -371,6 +372,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
prop = (UInt32)mainIndex;
break;
}
+ case kpidPhySize: prop = _totalSize; break;
}
prop.Detach(value);
return S_OK;
@@ -435,7 +437,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items.Size();
if (numItems == 0)
@@ -497,10 +499,16 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"MBR", L"mbr", 0, 0xDB, { 1, 1, 0 }, 3, false, CreateArc, 0 };
+ { "MBR", "mbr", 0, 0xDB,
+ // 3, { 1, 1, 0 },
+ // 2, { 0x55, 0x1FF },
+ 0, { 0 },
+ 0,
+ NArcInfoFlags::kPureStartOpen,
+ CreateArc };
REGISTER_ARC(Mbr)
diff --git a/CPP/7zip/Archive/MslzHandler.cpp b/CPP/7zip/Archive/MslzHandler.cpp
index 67495e76..cb124c40 100755..100644
--- a/CPP/7zip/Archive/MslzHandler.cpp
+++ b/CPP/7zip/Archive/MslzHandler.cpp
@@ -4,10 +4,10 @@
#include "../../../C/CpuArch.h"
-#include "Common/ComTry.h"
-#include "Common/MyString.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/MyString.h"
-#include "Windows/PropVariant.h"
+#include "../../Windows/PropVariant.h"
#include "../Common/InBuffer.h"
#include "../Common/ProgressUtils.h"
@@ -19,28 +19,45 @@
namespace NArchive {
namespace NMslz {
+static const UInt32 kUnpackSizeMax = 0xFFFFFFE0;
+
class CHandler:
public IInArchive,
+ public IArchiveOpenSeq,
public CMyUnknownImp
{
- CMyComPtr<IInStream> _stream;
- UInt32 _size;
+ CMyComPtr<IInStream> _inStream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+
+ bool _isArc;
+ bool _needSeekToStart;
+ bool _dataAfterEnd;
+ bool _needMoreInput;
+
+ bool _packSize_Defined;
+ bool _unpackSize_Defined;
+
+ UInt32 _unpackSize;
UInt64 _packSize;
+ UInt64 _originalFileSize;
UString _name;
+
+ void ParseName(Byte replaceByte, IArchiveOpenCallback *callback);
public:
- MY_UNKNOWN_IMP1(IInArchive)
+ MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq)
INTERFACE_IInArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
};
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
};
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO
+IMP_IInArchive_ArcProps_NO_Table
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
@@ -48,15 +65,39 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
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)
+ switch (propID)
{
case kpidPath: if (!_name.IsEmpty()) prop = _name; break;
- case kpidSize: prop = _size; break;
- case kpidPackSize: prop = _packSize; 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;
@@ -67,69 +108,80 @@ static const unsigned kSignatureSize = 9;
static const unsigned kHeaderSize = kSignatureSize + 1 + 4;
#define MSLZ_SIGNATURE { 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33, 0x41 }
// old signature: 53 5A 20 88 F0 27 33
-static const Byte signature[kSignatureSize] = MSLZ_SIGNATURE;
+static const Byte kSignature[kSignatureSize] = MSLZ_SIGNATURE;
-static const wchar_t *g_Exts[] =
+// we support only 3 chars strings here
+static const char *g_Exts[] =
{
- L"dll",
- L"exe",
- L"kmd",
- L"sys"
+ "dll"
+ , "exe"
+ , "kmd"
+ , "sys"
};
+void CHandler::ParseName(Byte replaceByte, IArchiveOpenCallback *callback)
+{
+ if (!callback)
+ return;
+ CMyComPtr<IArchiveOpenVolumeCallback> 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] == ext[0] &&
+ s[s.Len() - 1] == ext[1])
+ {
+ replaceByte = ext[2];
+ break;
+ }
+ }
+ }
+ if (replaceByte >= 0x20 && replaceByte < 0x80)
+ _name += (wchar_t)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, signature, kSignatureSize) != 0)
+ if (memcmp(buffer, kSignature, kSignatureSize) != 0)
return S_FALSE;
- _size = GetUi32(buffer + 10);
- if (_size > 0xFFFFFFE0)
+ _unpackSize = GetUi32(buffer + 10);
+ if (_unpackSize > kUnpackSizeMax)
return S_FALSE;
- RINOK(stream->Seek(0, STREAM_SEEK_END, &_packSize));
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &_originalFileSize));
+ _packSize = _originalFileSize;
- if (callback)
- {
- CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
- callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
- if (openVolumeCallback)
- {
- NWindows::NCOM::CPropVariant prop;
- if (openVolumeCallback->GetProperty(kpidName, &prop) == S_OK && prop.vt == VT_BSTR)
- {
- UString baseName = prop.bstrVal;
- if (!baseName.IsEmpty() && baseName.Back() == L'_')
- {
- baseName.DeleteBack();
- Byte replaceByte = buffer[kSignatureSize];
- if (replaceByte == 0)
- {
- for (int i = 0; i < sizeof(g_Exts) / sizeof(g_Exts[0]); i++)
- {
- UString s = g_Exts[i];
- int len = s.Length();
- Byte b = (Byte)s.Back();
- s.DeleteBack();
- if (baseName.Length() >= len &&
- baseName[baseName.Length() - len] == '.' &&
- s.CompareNoCase(baseName.Right(len - 1)) == 0)
- {
- replaceByte = b;
- break;
- }
- }
- }
- if (replaceByte >= 0x20 && replaceByte < 0x80)
- _name = baseName + (wchar_t)replaceByte;
- }
- }
- }
- }
- _stream = stream;
+ ParseName(buffer[kSignatureSize], callback);
+
+ _isArc = true;
+ _unpackSize_Defined = true;
+ _inStream = stream;
+ _seqStream = stream;
}
return S_OK;
COM_TRY_END
@@ -137,7 +189,20 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPo
STDMETHODIMP CHandler::Close()
{
- _stream.Release();
+ _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;
}
@@ -147,12 +212,13 @@ STDMETHODIMP CHandler::Close()
// maxLen = 16; MS
#define PROGRESS_AND_WRITE \
- if ((dest & kMask) == 0) { RINOK(WriteStream(outStream, buf, kBufSize)); \
+ if ((dest & kMask) == 0) { if (outStream) RINOK(WriteStream(outStream, buf, kBufSize)); \
if ((dest & ((1 << 20) - 1)) == 0) \
- { UInt64 inSize = inStream.GetProcessedSize(); UInt64 outSize = dest; \
- RINOK(progress->SetRatioInfo(&inSize, &outSize)); }}
+ if (progress) \
+ { UInt64 inSize = inStream.GetProcessedSize(); UInt64 outSize = dest; \
+ RINOK(progress->SetRatioInfo(&inSize, &outSize)); }}
-static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UInt32 unpackSize, ICompressProgressInfo *progress)
+static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UInt32 unpackSize, bool &needMoreData, ICompressProgressInfo *progress)
{
const unsigned kBufSize = (1 << 12);
const unsigned kMask = kBufSize - 1;
@@ -163,11 +229,17 @@ static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UIn
{
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;
@@ -177,7 +249,10 @@ static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UIn
{
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;
@@ -192,7 +267,19 @@ static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UIn
}
}
}
- return WriteStream(outStream, buf, dest & kMask);
+ 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,
@@ -201,10 +288,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_BEGIN
if (numItems == 0)
return S_OK;
- if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
- extractCallback->SetTotal(_size);
+ // extractCallback->SetTotal(_unpackSize);
CMyComPtr<ISequentialOutStream> realOutStream;
Int32 askMode = testMode ?
@@ -225,32 +312,81 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
-
- RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
- CInBuffer s;
- if (!s.Create(1 << 20))
- return E_OUTOFMEMORY;
- s.SetStream(_stream);
- s.Init();
- Byte buffer[kHeaderSize];
+
+ if (_needSeekToStart)
+ {
+ if (!_inStream)
+ return E_FAIL;
+ RINOK(_inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+ else
+ _needSeekToStart = true;
+
Int32 opRes = NExtract::NOperationResult::kDataError;
- if (s.ReadBytes(buffer, kHeaderSize) == kHeaderSize)
+
+ bool isArc = false;
+ bool needMoreInput = false;
+ try
{
- HRESULT result = MslzDec(s, outStream, _size, progress);
- if (result == S_OK)
- opRes = NExtract::NOperationResult::kOK;
- else if (result != S_FALSE)
- return result;
+ 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
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"MsLZ", L"", 0, 0xD5, MSLZ_SIGNATURE, kSignatureSize, false, CreateArc, 0 };
+ { "MsLZ", "mslz", 0, 0xD5,
+ kSignatureSize, MSLZ_SIGNATURE,
+ 0,
+ 0,
+ CreateArc };
REGISTER_ARC(Mslz)
diff --git a/CPP/7zip/Archive/MubHandler.cpp b/CPP/7zip/Archive/MubHandler.cpp
index 5ebda099..39f8de27 100755..100644
--- a/CPP/7zip/Archive/MubHandler.cpp
+++ b/CPP/7zip/Archive/MubHandler.cpp
@@ -4,9 +4,11 @@
#include "../../../C/CpuArch.h"
-#include "Common/ComTry.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyString.h"
-#include "Windows/PropVariant.h"
+#include "../../Windows/PropVariant.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -15,32 +17,50 @@
#include "../Compress/CopyCoder.h"
-static UInt32 Get32(const Byte *p, int be) { if (be) return GetBe32(p); return GetUi32(p); }
+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_SUBTYPE_LIB64 (1 << 31)
+
+#define MACH_CPU_SUBTYPE_I386_ALL 3
+
struct CItem
{
UInt32 Type;
UInt32 SubType;
- UInt64 Offset;
- UInt64 Size;
- UInt32 Align;
- bool IsTail;
+ UInt32 Offset;
+ UInt32 Size;
+ // UInt32 Align;
};
-const UInt32 kNumFilesMax = 10;
+static const UInt32 kNumFilesMax = 10;
class CHandler:
public IInArchive,
public IInArchiveGetStream,
public CMyUnknownImp
{
- UInt64 _startPos;
CMyComPtr<IInStream> _stream;
+ // UInt64 _startPos;
+ UInt64 _phySize;
UInt32 _numItems;
- CItem _items[kNumFilesMax + 1];
+ bool _bigEndian;
+ CItem _items[kNumFilesMax];
+
HRESULT Open2(IInStream *stream);
public:
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
@@ -48,65 +68,79 @@ public:
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
};
-STATPROPSTG kProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidSize, VT_UI8}
+ kpidBigEndian
};
-IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO
+static const Byte kProps[] =
+{
+ kpidSize
+};
-#define MACH_ARCH_ABI64 0x1000000
-#define MACH_MACHINE_386 7
-#define MACH_MACHINE_ARM 12
-#define MACH_MACHINE_SPARC 14
-#define MACH_MACHINE_PPC 18
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
-#define MACH_MACHINE_PPC64 (MACH_MACHINE_PPC | MACH_ARCH_ABI64)
-#define MACH_MACHINE_AMD64 (MACH_MACHINE_386 | MACH_ARCH_ABI64)
+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)
{
- NWindows::NCOM::CPropVariant prop;
+ PropVariant_Clear(value);
const CItem &item = _items[index];
- switch(propID)
+ switch (propID)
{
case kpidExtension:
{
- const wchar_t *ext;
- if (item.IsTail)
- ext = L"tail";
- else
+ char temp[32];
+ const char *ext = 0;
+ switch (item.Type)
{
- switch(item.Type)
- {
- case MACH_MACHINE_386: ext = L"86"; break;
- case MACH_MACHINE_ARM: ext = L"arm"; break;
- case MACH_MACHINE_SPARC: ext = L"sparc"; break;
- case MACH_MACHINE_PPC: ext = L"ppc"; break;
- case MACH_MACHINE_PPC64: ext = L"ppc64"; break;
- case MACH_MACHINE_AMD64: ext = L"x64"; break;
- default: ext = L"unknown"; break;
- }
+ 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_PPC64: ext = "ppc64"; break;
+ case MACH_CPU_TYPE_AMD64: ext = "x64"; break;
+ default:
+ temp[0] = 'c';
+ temp[1] = 'p';
+ temp[2] = 'u';
+ ConvertUInt32ToString(item.Type, temp + 3);
+ break;
}
- prop = ext;
- 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:
- prop = (UInt64)item.Size;
+ PropVarEm_Set_UInt64(value, item.Size);
break;
}
- prop.Detach(value);
return S_OK;
}
-#define MACH_TYPE_ABI64 (1 << 24)
-#define MACH_SUBTYPE_ABI64 (1 << 31)
-
HRESULT CHandler::Open2(IInStream *stream)
{
- RINOK(stream->Seek(0, STREAM_SEEK_SET, &_startPos));
+ // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPos));
const UInt32 kHeaderSize = 8;
const UInt32 kRecordSize = 5 * 4;
@@ -124,44 +158,37 @@ HRESULT CHandler::Open2(IInStream *stream)
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.IsTail = false;
sb.Type = Get32(p, be);
sb.SubType = Get32(p + 4, be);
sb.Offset = Get32(p + 8, be);
sb.Size = Get32(p + 12, be);
- sb.Align = Get32(p + 16, be);
-
- if ((sb.Type & ~MACH_TYPE_ABI64) >= 0x100 ||
- (sb.SubType & ~MACH_SUBTYPE_ABI64) >= 0x100 ||
- sb.Align > 31)
+ 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 (endPos > endPosMax)
+ if (endPosMax < endPos)
endPosMax = endPos;
}
- UInt64 fileSize;
- RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
- fileSize -= _startPos;
_numItems = num;
- if (fileSize > endPosMax)
- {
- CItem &sb = _items[_numItems++];
- sb.IsTail = true;
- sb.Type = 0;
- sb.SubType = 0;
- sb.Offset = endPosMax;
- sb.Size = fileSize - endPosMax;
- sb.Align = 0;
- }
+ _phySize = endPosMax;
return S_OK;
}
@@ -186,6 +213,7 @@ STDMETHODIMP CHandler::Close()
{
_stream.Release();
_numItems = 0;
+ _phySize = 0;
return S_OK;
}
@@ -199,7 +227,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _numItems;
if (numItems == 0)
@@ -244,7 +272,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
continue;
}
- RINOK(_stream->Seek(_startPos + item.Offset, STREAM_SEEK_SET, NULL));
+ RINOK(_stream->Seek(/* _startPos + */ item.Offset, STREAM_SEEK_SET, NULL));
streamSpec->Init(item.Size);
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
realOutStream.Release();
@@ -260,15 +288,27 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
{
COM_TRY_BEGIN
const CItem &item = _items[index];
- return CreateLimitedInStream(_stream, _startPos + item.Offset, item.Size, stream);
+ return CreateLimitedInStream(_stream, /* _startPos + */ item.Offset, item.Size, stream);
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
+
+namespace NBe {
static CArcInfo g_ArcInfo =
- { L"Mub", L"", 0, 0xE2, { 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0 }, 7, false, CreateArc, 0 };
+ { "Mub", "mub", 0, 0xE2,
+ 2 + 7 + 4,
+ {
+ 7, 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0,
+ 4, 0xB9, 0xFA, 0xF1, 0x0E
+ },
+ 0,
+ NArcInfoFlags::kMultiSignature,
+ CreateArc };
REGISTER_ARC(Mub)
+}
+
}}
diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.cpp b/CPP/7zip/Archive/Nsis/NsisDecode.cpp
index 0845f965..bb73d273 100755..100644
--- a/CPP/7zip/Archive/Nsis/NsisDecode.cpp
+++ b/CPP/7zip/Archive/Nsis/NsisDecode.cpp
@@ -2,66 +2,65 @@
#include "StdAfx.h"
-#include "NsisDecode.h"
+#include "../../../../C/CpuArch.h"
-#include "../../Common/StreamUtils.h"
+#include "NsisDecode.h"
+#include "../../Common/CreateCoder.h"
+#include "../../Common/FilterCoder.h"
+#include "../../Common/LimitedStreams.h"
#include "../../Common/MethodId.h"
+#include "../../Compress/BcjCoder.h"
#include "../../Compress/BZip2Decoder.h"
#include "../../Compress/DeflateDecoder.h"
-#include "../../Compress/LzmaDecoder.h"
+
+#define Get32(p) GetUi32(p)
namespace NArchive {
namespace NNsis {
-static const CMethodId k_BCJ_X86 = 0x03030103;
-
-HRESULT CDecoder::Init(
- DECL_EXTERNAL_CODECS_LOC_VARS
- IInStream *inStream, NMethodType::EEnum method, bool thereIsFilterFlag, bool &useFilter)
+HRESULT CDecoder::Init(ISequentialInStream *inStream, bool &useFilter)
{
useFilter = false;
- CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
if (_decoderInStream)
- if (method != _method)
+ if (Method != _curMethod)
Release();
- _method = method;
+ _curMethod = Method;
if (!_codecInStream)
{
- switch (method)
+ switch (Method)
{
// case NMethodType::kCopy: return E_NOTIMPL;
case NMethodType::kDeflate: _codecInStream = new NCompress::NDeflate::NDecoder::CNsisCOMCoder(); break;
case NMethodType::kBZip2: _codecInStream = new NCompress::NBZip2::CNsisDecoder(); break;
- case NMethodType::kLZMA: _codecInStream = new NCompress::NLzma::CDecoder(); break;
+ case NMethodType::kLZMA:
+ _lzmaDecoder = new NCompress::NLzma::CDecoder();
+ _codecInStream = _lzmaDecoder;
+ break;
default: return E_NOTIMPL;
}
}
- if (thereIsFilterFlag)
+ if (FilterFlag)
{
- UInt32 processedSize;
- BYTE flag;
- RINOK(inStream->Read(&flag, 1, &processedSize));
- if (processedSize != 1)
- return E_FAIL;
+ Byte flag;
+ RINOK(ReadStream_FALSE(inStream, &flag, 1));
if (flag > 1)
return E_NOTIMPL;
useFilter = (flag != 0);
}
- if (useFilter)
+ if (!useFilter)
+ _decoderInStream = _codecInStream;
+ else
{
if (!_filterInStream)
{
- CMyComPtr<ICompressCoder> coder;
- RINOK(CreateCoder(
- EXTERNAL_CODECS_LOC_VARS
- k_BCJ_X86, coder, false));
- if (!coder)
- return E_NOTIMPL;
+ CFilterCoder *coderSpec = new CFilterCoder;
+ CMyComPtr<ICompressCoder> coder = coderSpec;
+ coderSpec->Filter = new CBCJ_x86_Decoder();
coder.QueryInterface(IID_ISequentialInStream, &_filterInStream);
if (!_filterInStream)
return E_NOTIMPL;
@@ -73,23 +72,13 @@ HRESULT CDecoder::Init(
RINOK(setInStream->SetInStream(_codecInStream));
_decoderInStream = _filterInStream;
}
- else
- _decoderInStream = _codecInStream;
- if (method == NMethodType::kLZMA)
+ if (Method == NMethodType::kLZMA)
{
- CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
- _codecInStream.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);
- if (setDecoderProperties)
- {
- static const UInt32 kPropertiesSize = 5;
- BYTE properties[kPropertiesSize];
- UInt32 processedSize;
- RINOK(inStream->Read(properties, kPropertiesSize, &processedSize));
- if (processedSize != kPropertiesSize)
- return E_FAIL;
- RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)properties, kPropertiesSize));
- }
+ const unsigned kPropsSize = LZMA_PROPS_SIZE;
+ Byte props[kPropsSize];
+ RINOK(ReadStream_FALSE(inStream, props, kPropsSize));
+ RINOK(_lzmaDecoder->SetDecoderProperties2((const Byte *)props, kPropsSize));
}
{
@@ -122,9 +111,155 @@ HRESULT CDecoder::Init(
return S_OK;
}
-HRESULT CDecoder::Read(void *data, size_t *processedSize)
+static const UInt32 kMask_IsCompressed = (UInt32)1 << 31;
+
+HRESULT CDecoder::SetToPos(UInt64 pos, ICompressProgressInfo *progress)
{
- return ReadStream(_decoderInStream, data, processedSize);;
+ if (StreamPos > pos)
+ return E_FAIL;
+ UInt64 inSizeStart = 0;
+ if (_lzmaDecoder)
+ inSizeStart = _lzmaDecoder->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;
+
+ UInt64 inSize = 0;
+ if (_lzmaDecoder)
+ inSize = _lzmaDecoder->GetInputProcessedSize() - inSizeStart;
+ RINOK(progress->SetRatioInfo(&inSize, &offset));
+ }
+ return S_OK;
+}
+
+HRESULT CDecoder::Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unpackSize,
+ ISequentialOutStream *realOutStream, ICompressProgressInfo *progress,
+ UInt32 &packSizeRes, UInt32 &unpackSizeRes)
+{
+ CLimitedSequentialInStream *limitedStreamSpec = NULL;
+ CMyComPtr<ISequentialInStream> limitedStream;
+ packSizeRes = 0;
+ unpackSizeRes = 0;
+
+ if (Solid)
+ {
+ Byte temp[4];
+ size_t processedSize = 4;
+ RINOK(Read(temp, &processedSize));
+ if (processedSize != 4)
+ return S_FALSE;
+ StreamPos += processedSize;
+ UInt32 size = Get32(temp);
+ if (unpackSizeDefined && size != unpackSize)
+ return S_FALSE;
+ unpackSize = size;
+ unpackSizeDefined = true;
+ }
+ else
+ {
+ Byte temp[4];
+ RINOK(ReadStream_FALSE(InputStream, temp, 4));
+ StreamPos += 4;
+ 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)
+ return S_FALSE;
+ outBuf->Alloc(unpackSize);
+ }
+
+ UInt64 inSizeStart = 0;
+ if (_lzmaDecoder)
+ inSizeStart = _lzmaDecoder->GetInputProcessedSize();
+
+ // we don't allow files larger than 4 GB;
+ if (!unpackSizeDefined)
+ unpackSize = 0xFFFFFFFF;
+ UInt32 offset = 0;
+
+ 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)
+ return S_FALSE;
+ break;
+ }
+ if (outBuf)
+ memcpy((Byte *)*outBuf + (size_t)offset, Buffer, size);
+ StreamPos += size;
+ offset += (UInt32)size;
+
+ UInt64 inSize = 0; // it can be improved: we need inSize for Deflate and BZip2 too.
+ if (_lzmaDecoder)
+ inSize = _lzmaDecoder->GetInputProcessedSize() - inSizeStart;
+ if (Solid)
+ packSizeRes = (UInt32)inSize;
+ unpackSizeRes += (UInt32)size;
+
+ UInt64 outSize = offset;
+ RINOK(progress->SetRatioInfo(&inSize, &outSize));
+ if (realOutStream)
+ RINOK(WriteStream(realOutStream, Buffer, size));
+ }
+ return S_OK;
}
}}
diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.h b/CPP/7zip/Archive/Nsis/NsisDecode.h
index 36aeb2b1..2ccaaf65 100755..100644
--- a/CPP/7zip/Archive/Nsis/NsisDecode.h
+++ b/CPP/7zip/Archive/Nsis/NsisDecode.h
@@ -3,9 +3,11 @@
#ifndef __NSIS_DECODE_H
#define __NSIS_DECODE_H
-#include "../../IStream.h"
+#include "../../../Common/MyBuffer.h"
-#include "../../Common/CreateCoder.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/LzmaDecoder.h"
namespace NArchive {
namespace NNsis {
@@ -21,25 +23,50 @@ namespace NMethodType
};
}
+/* 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 _method;
+ NMethodType::EEnum _curMethod; // method of created decoder
CMyComPtr<ISequentialInStream> _filterInStream;
CMyComPtr<ISequentialInStream> _codecInStream;
CMyComPtr<ISequentialInStream> _decoderInStream;
+ NCompress::NLzma::CDecoder *_lzmaDecoder;
+
public:
+ CMyComPtr<IInStream> InputStream; // for non-solid
+ UInt64 StreamPos; // the pos in unpacked for solid, the pos in Packed for non-solid
+
+ NMethodType::EEnum Method;
+ bool FilterFlag;
+ bool Solid;
+
+ CByteBuffer Buffer; // temp buf.
+
void Release()
{
_filterInStream.Release();
_codecInStream.Release();
_decoderInStream.Release();
+ InputStream.Release();
+ _lzmaDecoder = NULL;
}
- HRESULT Init(
- DECL_EXTERNAL_CODECS_LOC_VARS
- IInStream *inStream, NMethodType::EEnum method, bool thereIsFilterFlag, bool &useFilter);
- HRESULT Read(void *data, size_t *processedSize);
+
+ HRESULT Init(ISequentialInStream *inStream, bool &useFilter);
+ HRESULT Read(void *data, size_t *processedSize)
+ {
+ return ReadStream(_decoderInStream, data, processedSize);;
+ }
+
+
+ HRESULT CDecoder::SetToPos(UInt64 pos, ICompressProgressInfo *progress); // for solid
+ HRESULT Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unpackSize,
+ ISequentialOutStream *realOutStream, ICompressProgressInfo *progress,
+ UInt32 &packSizeRes, UInt32 &unpackSizeRes);
};
}}
diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.cpp b/CPP/7zip/Archive/Nsis/NsisHandler.cpp
index 4058bd2a..868ca6cb 100755..100644
--- a/CPP/7zip/Archive/Nsis/NsisHandler.cpp
+++ b/CPP/7zip/Archive/Nsis/NsisHandler.cpp
@@ -4,11 +4,12 @@
#include "../../../../C/CpuArch.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
-#include "Windows/PropVariant.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../Common/ProgressUtils.h"
#include "../../Common/StreamUtils.h"
#include "../Common/ItemNameUtils.h"
@@ -27,54 +28,160 @@ static const char *kUnknownMethod = "Unknown";
static const char *kMethods[] =
{
- "Copy",
- "Deflate",
- "BZip2",
- "LZMA"
+ "Copy"
+ , "Deflate"
+ , "BZip2"
+ , "LZMA"
};
-static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]);
-
-static STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidSolid, VT_BOOL}
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidAttrib,
+ kpidMethod,
+ kpidSolid,
+ kpidOffset
};
-static STATPROPSTG kArcProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidSolid, VT_BOOL}
+ kpidMethod,
+ kpidSolid,
+ kpidHeadersSize,
+ kpidEmbeddedStubSize,
+ kpidSubType
+ // kpidCodePage
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
+
+static AString UInt32ToString(UInt32 val)
+{
+ char s[16];
+ ConvertUInt32ToString(val, s);
+ return 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 += ' ';
+ }
+ s += (method < ARRAY_SIZE(kMethods)) ? kMethods[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 += ' ';
+ }
+ 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
- NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ NCOM::CPropVariant prop;
+ switch (propID)
{
- case kpidMethod:
+ // case kpidCodePage: if (_archive.IsUnicode) prop = "UTF-16"; break;
+ case kpidSubType:
{
- UInt32 dict = 1;
- bool filter = false;
- for (int i = 0; i < _archive.Items.Size(); i++)
+ AString s = _archive.GetFormatDescription();
+ if (!_archive.IsInstaller)
{
- const CItem &item = _archive.Items[i];
- filter |= item.UseFilter;
- if (item.DictionarySize > dict)
- dict = item.DictionarySize;
+ if (!s.IsEmpty())
+ s += ' ';
+ s += "(Uninstall)";
}
- prop = GetMethod(filter, dict);
+ 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 = _archive.ExeStub.Size() + _archive.FirstHeader.ArcSize; break;
+ case kpidEmbeddedStubSize: prop = _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;
@@ -82,16 +189,26 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
}
-STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * maxCheckStartPosition, IArchiveOpenCallback * /* openArchiveCallback */)
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback * /* openArchiveCallback */)
{
COM_TRY_BEGIN
Close();
{
- if (_archive.Open(
- EXTERNAL_CODECS_VARS
- stream, maxCheckStartPosition) != S_OK)
+ if (_archive.Open(stream, maxCheckStartPosition) != S_OK)
return S_FALSE;
- _inStream = stream;
+ {
+ 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
@@ -101,7 +218,6 @@ STDMETHODIMP CHandler::Close()
{
_archive.Clear();
_archive.Release();
- _inStream.Release();
return S_OK;
}
@@ -109,74 +225,30 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
*numItems = _archive.Items.Size()
#ifdef NSIS_SCRIPT
- + 1
+ + 1 + _archive.LicenseFiles.Size();
#endif
;
return S_OK;
}
-static AString UInt32ToString(UInt32 value)
-{
- char buffer[16];
- ConvertUInt32ToString(value, buffer);
- return buffer;
-}
-
-static AString GetStringForSizeValue(UInt32 value)
-{
- for (int i = 31; i >= 0; i--)
- if (((UInt32)1 << i) == value)
- return UInt32ToString(i);
- char c = 'b';
- if (value % (1 << 20) == 0)
- {
- value >>= 20;
- c = 'm';
- }
- else if (value % (1 << 10) == 0)
- {
- value >>= 10;
- c = 'k';
- }
- return UInt32ToString(value) + c;
-}
-
-AString CHandler::GetMethod(bool useItemFilter, UInt32 dictionary) const
-{
- NMethodType::EEnum methodIndex = _archive.Method;
- AString method;
- if (_archive.IsSolid && _archive.UseFilter || !_archive.IsSolid && useItemFilter)
- {
- method += kBcjMethod;
- method += ' ';
- }
- method += (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod;
- if (methodIndex == NMethodType::kLZMA)
- {
- method += ':';
- method += GetStringForSizeValue(_archive.IsSolid ? _archive.DictionarySize: dictionary);
- }
- return method;
-}
-
-bool CHandler::GetUncompressedSize(int index, UInt32 &size)
+bool CHandler::GetUncompressedSize(unsigned index, UInt32 &size) const
{
size = 0;
const CItem &item = _archive.Items[index];
- if (item.SizeIsDefined)
- size = item.Size;
- else if (_archive.IsSolid && item.EstimatedSizeIsDefined)
- size = item.EstimatedSize;
+ 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(int index, UInt32 &size)
+bool CHandler::GetCompressedSize(unsigned index, UInt32 &size) const
{
size = 0;
const CItem &item = _archive.Items[index];
- if (item.CompressedSizeIsDefined)
+ if (item.CompressedSize_Defined)
size = item.CompressedSize;
else
{
@@ -202,27 +274,42 @@ bool CHandler::GetCompressedSize(int index, UInt32 &size)
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
+ NCOM::CPropVariant prop;
#ifdef NSIS_SCRIPT
if (index >= (UInt32)_archive.Items.Size())
{
- switch(propID)
+ if (index == (UInt32)_archive.Items.Size())
{
- case kpidPath: prop = L"[NSIS].nsi"; break;
- case kpidSize:
- case kpidPackSize: prop = (UInt64)_archive.Script.Length(); break;
- case kpidSolid: prop = false; break;
+ 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)
+ switch (propID)
{
+ case kpidOffset: prop = item.Pos; break;
case kpidPath:
{
- UString s = NItemName::WinNameToOSName(item.GetReducedName(_archive.IsUnicode));
+ UString s = NItemName::WinNameToOSName(_archive.GetReducedName(index));
if (!s.IsEmpty())
prop = (const wchar_t *)s;
break;
@@ -248,7 +335,21 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = item.MTime;
break;
}
- case kpidMethod: prop = GetMethod(item.UseFilter, item.DictionarySize); 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;
}
}
@@ -257,24 +358,56 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
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)-1);
+ 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 >= (UInt32)_archive.Items.Size())
- totalSize += _archive.Script.Length();
+ 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
{
@@ -282,9 +415,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (_archive.IsSolid)
{
GetUncompressedSize(index, size);
- UInt64 pos = _archive.GetPosOfSolidItem(index);
- if (pos > totalSize)
- totalSize = pos + size;
+ UInt64 pos = (UInt64)_archive.GetPosOfSolidItem(index) + size;
+ if (solidPosMax < pos)
+ solidPosMax = pos;
}
else
{
@@ -293,33 +426,58 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
}
}
- extractCallback->SetTotal(totalSize);
- UInt64 currentTotalSize = 0;
- UInt32 currentItemSize = 0;
+ extractCallback->SetTotal(totalSize + solidPosMax);
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, !_archive.IsSolid);
- UInt64 streamPos = 0;
if (_archive.IsSolid)
{
- RINOK(_inStream->Seek(_archive.StreamOffset, STREAM_SEEK_SET, NULL));
- bool useFilter;
- RINOK(_archive.Decoder.Init(
- EXTERNAL_CODECS_VARS
- _inStream, _archive.Method, _archive.FilterFlag, useFilter));
+ RINOK(_archive.SeekTo_DataStreamOffset());
+ RINOK(_archive.InitDecoder());
+ _archive.Decoder.StreamPos = 0;
}
- CByteBuffer byteBuf;
- const UInt32 kBufferLength = 1 << 16;
- byteBuf.SetCapacity(kBufferLength);
- Byte *buffer = byteBuf;
+ /* 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;
-
- bool dataError = false;
- for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ 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)
{
- currentItemSize = 0;
- RINOK(extractCallback->SetCompleted(&currentTotalSize));
+ lps->InSize = curTotalPacked;
+ lps->OutSize = curTotalUnpacked;
+ if (_archive.IsSolid)
+ lps->OutSize += _archive.Decoder.StreamPos;
+
+ curPacked = 0;
+ curUnpacked = 0;
+ RINOK(lps->SetCur());
+
+ // RINOK(extractCallback->SetCompleted(&currentTotalSize));
CMyComPtr<ISequentialOutStream> realOutStream;
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
@@ -328,169 +486,184 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ bool dataError = false;
+
#ifdef NSIS_SCRIPT
if (index >= (UInt32)_archive.Items.Size())
{
- currentItemSize = _archive.Script.Length();
+ 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 (!testMode)
- RINOK(WriteStream(realOutStream, (const char *)_archive.Script, (UInt32)_archive.Script.Length()));
+ if (realOutStream)
+ RINOK(WriteStream(realOutStream, data, size));
}
else
#endif
{
const CItem &item = _archive.Items[index];
- if (_archive.IsSolid)
- GetUncompressedSize(index, currentItemSize);
- else
- GetCompressedSize(index, currentItemSize);
+ if (!_archive.IsSolid)
+ GetCompressedSize(index, curPacked);
if (!testMode && !realOutStream)
continue;
RINOK(extractCallback->PrepareOperation(askMode));
- if (!dataError)
+ dataError = solidDataError;
+
+ bool needDecompress = !solidDataError;
+ if (needDecompress)
{
- bool needDecompress = false;
- bool sizeIsKnown = false;
- UInt32 fullSize = 0;
+ if (testMode && _archive.IsSolid && _archive.GetPosOfSolidItem(index) == prevPos)
+ needDecompress = false;
+ }
+ if (needDecompress)
+ {
bool writeToTemp = false;
bool readFromTemp = false;
- if (_archive.IsSolid)
+ if (!_archive.IsSolid)
+ {
+ RINOK(_archive.SeekToNonSolidItem(index));
+ }
+ else
{
UInt64 pos = _archive.GetPosOfSolidItem(index);
- while (streamPos < pos)
+ if (pos < _archive.Decoder.StreamPos)
+ {
+ if (pos != tempPos)
+ solidDataError = dataError = true;
+ readFromTemp = true;
+ }
+ else
{
- size_t processedSize = (UInt32)MyMin(pos - streamPos, (UInt64)kBufferLength);
- HRESULT res = _archive.Decoder.Read(buffer, &processedSize);
+ HRESULT res = _archive.Decoder.SetToPos(pos, progress);
if (res != S_OK)
{
if (res != S_FALSE)
return res;
- dataError = true;
- break;
+ solidDataError = dataError = true;
}
- if (processedSize == 0)
+ else if (!testMode && i + 1 < numItems)
{
- dataError = true;
- break;
+ 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;
+ }
+ }
}
- streamPos += processedSize;
}
- if (streamPos == pos)
+ prevPos = pos;
+ }
+
+ if (!dataError)
+ {
+ UInt32 unpackSize = 0;
+ bool unpackSize_Defined = false;
+ bool writeToTemp1 = writeToTemp;
+ if (item.IsUninstaller)
{
- Byte buffer2[4];
- size_t processedSize = 4;
- RINOK(_archive.Decoder.Read(buffer2, &processedSize));
- if (processedSize != 4)
- return E_FAIL;
- streamPos += processedSize;
- fullSize = Get32(buffer2);
- sizeIsKnown = true;
- needDecompress = true;
-
- if (!testMode && i + 1 < numItems)
+ unpackSize = item.PatchSize;
+ unpackSize_Defined = true;
+ if (!readFromTemp)
+ writeToTemp = true;
+ writeToTemp1 = writeToTemp;
+ if (_archive.ExeStub.Size() == 0)
{
- UInt64 nextPos = _archive.GetPosOfSolidItem(allFilesMode ? i : indices[i + 1]);
- if (nextPos < streamPos + fullSize)
- {
+ if (writeToTemp1 && !readFromTemp)
tempBuf.Free();
- tempBuf.SetCapacity(fullSize);
- writeToTemp = true;
- }
+ writeToTemp1 = false;
}
}
- else
- readFromTemp = true;
- }
- else
- {
- RINOK(_inStream->Seek(_archive.GetPosOfNonSolidItem(index) + 4, STREAM_SEEK_SET, NULL));
- if (item.IsCompressed)
+
+ if (readFromTemp)
{
- needDecompress = true;
- bool useFilter;
- RINOK(_archive.Decoder.Init(
- EXTERNAL_CODECS_VARS
- _inStream, _archive.Method, _archive.FilterFlag, useFilter));
- // fullSize = Get32(buffer); // It's bug !!!
- // Test it: what is exact fullSize?
- fullSize = 0xFFFFFFFF;
+ if (realOutStream && !item.IsUninstaller)
+ RINOK(WriteStream(realOutStream, tempBuf, tempBuf.Size()));
}
else
- fullSize = item.Size;
- }
- if (!dataError)
- {
- if (needDecompress)
{
- UInt64 offset = 0;
- while (!sizeIsKnown || fullSize > 0)
+ UInt32 curUnpacked32 = 0;
+ HRESULT res = _archive.Decoder.Decode(
+ writeToTemp1 ? &tempBuf : NULL,
+ item.IsUninstaller, item.PatchSize,
+ item.IsUninstaller ? NULL : realOutStream,
+ progress,
+ curPacked, curUnpacked32);
+ curUnpacked = curUnpacked32;
+ if (_archive.IsSolid)
+ curUnpacked = 0;
+ if (res != S_OK)
{
- UInt32 curSize = kBufferLength;
- if (sizeIsKnown && curSize > fullSize)
- curSize = fullSize;
- size_t processedSize = curSize;
- HRESULT res = _archive.Decoder.Read(buffer, &processedSize);
- if (res != S_OK)
- {
- if (res != S_FALSE)
- return res;
- dataError = true;
- break;
- }
- if (processedSize == 0)
- {
- if (sizeIsKnown)
- dataError = true;
- break;
- }
-
- if (writeToTemp)
- memcpy((Byte *)tempBuf + (size_t)offset, buffer, processedSize);
-
- fullSize -= (UInt32)processedSize;
- streamPos += processedSize;
- offset += processedSize;
-
- UInt64 completed;
+ if (res != S_FALSE)
+ return res;
+ dataError = true;
if (_archive.IsSolid)
- completed = currentTotalSize + offset;
- else
- completed = streamPos;
- RINOK(extractCallback->SetCompleted(&completed));
- if (!testMode)
- RINOK(WriteStream(realOutStream, buffer, processedSize));
+ 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
{
- if (readFromTemp)
- {
- if (!testMode)
- RINOK(WriteStream(realOutStream, tempBuf, tempBuf.GetCapacity()));
- }
- else
- while (fullSize > 0)
+ UInt32 curPacked2 = 0;
+ UInt32 curUnpacked2 = 0;
+ 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)
{
- UInt32 curSize = MyMin(fullSize, kBufferLength);
- UInt32 processedSize;
- RINOK(_inStream->Read(buffer, curSize, &processedSize));
- if (processedSize == 0)
- {
- dataError = true;
- break;
- }
- fullSize -= processedSize;
- streamPos += processedSize;
- if (!testMode)
- RINOK(WriteStream(realOutStream, buffer, processedSize));
+ if (res != S_FALSE)
+ return res;
+ dataError = true;
+ if (_archive.IsSolid)
+ solidDataError = true;
}
}
}
@@ -505,6 +678,4 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
-IMPL_ISetCompressCodecsInfo
-
}}
diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.h b/CPP/7zip/Archive/Nsis/NsisHandler.h
index 6de493df..1eb8b731 100755..100644
--- a/CPP/7zip/Archive/Nsis/NsisHandler.h
+++ b/CPP/7zip/Archive/Nsis/NsisHandler.h
@@ -3,39 +3,32 @@
#ifndef __NSIS_HANDLER_H
#define __NSIS_HANDLER_H
-#include "Common/MyCom.h"
+#include "../../../Common/MyCom.h"
+
+#include "../../Common/CreateCoder.h"
+
#include "../IArchive.h"
#include "NsisIn.h"
-#include "../../Common/CreateCoder.h"
-
namespace NArchive {
namespace NNsis {
class CHandler:
public IInArchive,
- PUBLIC_ISetCompressCodecsInfo
public CMyUnknownImp
{
- CMyComPtr<IInStream> _inStream;
CInArchive _archive;
+ AString _methodString;
- DECL_EXTERNAL_CODECS_VARS
-
- bool GetUncompressedSize(int index, UInt32 &size);
- bool GetCompressedSize(int index, UInt32 &size);
+ bool GetUncompressedSize(unsigned index, UInt32 &size) const;
+ bool GetCompressedSize(unsigned index, UInt32 &size) const;
- AString GetMethod(bool useItemFilter, UInt32 dictionary) const;
+ // AString GetMethod(NMethodType::EEnum method, bool useItemFilter, UInt32 dictionary) const;
public:
- MY_QUERYINTERFACE_BEGIN2(IInArchive)
- QUERY_ENTRY_ISetCompressCodecsInfo
- MY_QUERYINTERFACE_END
- MY_ADDREF_RELEASE
+ MY_UNKNOWN_IMP1(IInArchive)
INTERFACE_IInArchive(;)
-
- DECL_ISetCompressCodecsInfo
};
}}
diff --git a/CPP/7zip/Archive/Nsis/NsisIn.cpp b/CPP/7zip/Archive/Nsis/NsisIn.cpp
index 40756008..71791c03 100755..100644
--- a/CPP/7zip/Archive/Nsis/NsisIn.cpp
+++ b/CPP/7zip/Archive/Nsis/NsisIn.cpp
@@ -2,1271 +2,5540 @@
#include "StdAfx.h"
-#include "../../../../C/CpuArch.h"
-
-#include "Common/IntToString.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 {
-Byte kSignature[kSignatureSize] = NSIS_SIGNATURE;
+static const size_t kInputBufSize = 1 << 20;
+
+static 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
-static const char *kCrLf = "\x0D\x0A";
+#define CR_LF "\x0D\x0A"
#endif
-#define NS_UN_SKIP_CODE 0xE000
-#define NS_UN_VAR_CODE 0xE001
-#define NS_UN_SHELL_CODE 0xE002
-#define NS_UN_LANG_CODE 0xE003
-#define NS_UN_CODES_START NS_UN_SKIP_CODE
-#define NS_UN_CODES_END NS_UN_LANG_CODE
+static const char *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
-Byte CInArchive::ReadByte()
+ 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
{
- if (_posInData >= _size)
- throw 1;
- return _data[_posInData++];
+ 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, // SerCtlColors
+ 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" },
+ { 2 }, // 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 *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 *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 void UIntToString(AString &s, UInt32 v)
+{
+ char sz[16];
+ ConvertUInt32ToString(v, sz);
+ s += sz;
}
-UInt32 CInArchive::ReadUInt32()
+#ifdef NSIS_SCRIPT
+
+void CInArchive::Add_UInt(UInt32 v)
{
- UInt32 value = 0;
- for (int i = 0; i < 4; i++)
- value |= ((UInt32)(ReadByte()) << (8 * i));
- return value;
+ char sz[16];
+ ConvertUInt32ToString(v, sz);
+ Script += sz;
}
-void CInArchive::ReadBlockHeader(CBlockHeader &bh)
+static void Add_SignedInt(CDynLimBuf &s, Int32 v)
{
- bh.Offset = ReadUInt32();
- bh.Num = ReadUInt32();
+ char sz[32];
+ ConvertInt64ToString(v, sz);
+ s += sz;
}
-#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+static void Add_Hex(CDynLimBuf &s, UInt32 v)
+{
+ char sz[16];
+ sz[0] = '0';
+ sz[1] = 'x';
+ ConvertUInt32ToHex(v, sz + 2);
+ s += sz;
+}
-static int CompareItems(void *const *p1, void *const *p2, void * /* param */)
+static UInt32 GetUi16Str_Len(const Byte *p)
{
- const CItem &i1 = **(CItem **)p1;
- const CItem &i2 = **(CItem **)p2;
- RINOZ(MyCompare(i1.Pos, i2.Pos));
- if (i1.IsUnicode)
+ 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)
{
- RINOZ(i1.PrefixU.Compare(i2.PrefixU));
- RINOZ(i1.NameU.Compare(i2.NameU));
+ 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
{
- RINOZ(i1.PrefixA.Compare(i2.PrefixA));
- RINOZ(i1.NameA.Compare(i2.NameA));
+ 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;
+ }
}
- return 0;
}
-static AString UIntToString(UInt32 v)
+#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 *kVarStrings[] =
{
- char sz[32];
- ConvertUInt64ToString(v, sz);
- return sz;
+ "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 += '_';
+ }
+ }
}
-static AString IntToString(Int32 v)
+void CInArchive::GetVar(AString &res, UInt32 index)
{
- char sz[32];
- ConvertInt64ToString(v, sz);
- return sz;
+ 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;
+ }
+ }
}
-AString CInArchive::ReadStringA(UInt32 pos) const
+#endif
+
+void CInArchive::GetNsisString_Unicode_Raw(const Byte *p)
{
- AString s;
- if (pos >= _size)
- return IntToString((Int32)pos);
- UInt32 offset = GetOffset() + _stringsPos + pos;
+ Raw_UString.Empty();
+
+ if (IsPark())
+ {
+ for (;;)
+ {
+ unsigned c = Get16(p);
+ p += 2;
+ if (c == 0)
+ break;
+ if (c < 0x80)
+ {
+ Raw_UString += (wchar_t)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);
+ }
+ for (const Byte *s = (const Byte *)(const char *)Raw_AString; *s != 0; s++)
+ Raw_UString += *s;
+ continue;
+ }
+ c = n;
+ }
+
+ Raw_UString += (wchar_t)c;
+ }
+
+ return;
+ }
+
+ // NSIS-3 Unicode
for (;;)
{
- if (offset >= _size)
- break; // throw 1;
- char c = _data[offset++];
+ unsigned c = Get16(p);
+ p += 2;
+ if (c > NS_3_CODE_SKIP)
+ {
+ Raw_UString += (wchar_t)c;
+ continue;
+ }
if (c == 0)
break;
- s += c;
+
+ 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);
+ }
+ for (const Byte *s = (const Byte *)(const char *)Raw_AString; *s != 0; s++)
+ Raw_UString += (wchar_t)*s;
}
- return s;
}
-UString CInArchive::ReadStringU(UInt32 pos) const
+#ifdef NSIS_SCRIPT
+
+static const Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+void CInArchive::GetNsisString_Unicode(AString &res, const Byte *p)
{
- UString s;
- UInt32 offset = GetOffset() + _stringsPos + (pos * 2);
for (;;)
{
- if (offset >= _size || offset + 1 >= _size)
- return s; // throw 1;
- char c0 = _data[offset++];
- char c1 = _data[offset++];
- wchar_t c = (c0 | ((wchar_t)c1 << 8));
+ unsigned c = Get16(p);
+ p += 2;
if (c == 0)
break;
- s += c;
+ 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);
}
- return s;
}
-/*
-static AString ParsePrefix(const AString &prefix)
+#endif
+
+void CInArchive::ReadString2_Raw(UInt32 pos)
{
- AString res = prefix;
- if (prefix.Length() >= 3)
+ Raw_AString.Empty();
+ Raw_UString.Empty();
+ if ((Int32)pos < 0)
+ Add_LangStr(Raw_AString, -((Int32)pos + 1));
+ else if (pos >= NumStringChars)
{
- if ((Byte)prefix[0] == 0xFD && (Byte)prefix[1] == 0x95 && (Byte)prefix[2] == 0x80)
- res = "$INSTDIR" + prefix.Mid(3);
- else if ((Byte)prefix[0] == 0xFD && (Byte)prefix[1] == 0x96 && (Byte)prefix[2] == 0x80)
- res = "$OUTDIR" + prefix.Mid(3);
+ Raw_AString += kErrorStr;
+ // UIntToString(Raw_AString, pos);
}
- return res;
+ else
+ {
+ if (IsUnicode)
+ GetNsisString_Unicode_Raw(_data + _stringsPos + pos * 2);
+ else
+ GetNsisString_Raw(_data + _stringsPos + pos);
+ return;
+ }
+ for (const char *s = (const char *)Raw_AString; *s != 0; s++)
+ Raw_UString += *s;
}
-*/
-#define SYSREGKEY "Software\\Microsoft\\Windows\\CurrentVersion"
+bool CInArchive::IsGoodString(UInt32 param) const
+{
+ if (param >= NumStringChars)
+ return false;
+ if (param == 0)
+ return true;
+ const Byte *p = _data + _stringsPos;
+ if (IsUnicode)
+ return (Get16(p + param * 2 - 2)) == 0;
+ return p[param - 1] == 0;
+}
-/*
-# define CSIDL_PROGRAMS 0x2
-# define CSIDL_PRINTERS 0x4
-# define CSIDL_PERSONAL 0x5
-# define CSIDL_FAVORITES 0x6
-# define CSIDL_STARTUP 0x7
-# define CSIDL_RECENT 0x8
-# define CSIDL_SENDTO 0x9
-# define CSIDL_STARTMENU 0xB
-# define CSIDL_MYMUSIC 0xD
-# define CSIDL_MYVIDEO 0xE
-
-# define CSIDL_DESKTOPDIRECTORY 0x10
-# define CSIDL_NETHOOD 0x13
-# define CSIDL_FONTS 0x14
-# define CSIDL_TEMPLATES 0x15
-# define CSIDL_COMMON_STARTMENU 0x16
-# define CSIDL_COMMON_PROGRAMS 0x17
-# define CSIDL_COMMON_STARTUP 0x18
-# define CSIDL_COMMON_DESKTOPDIRECTORY 0x19
-# define CSIDL_APPDATA 0x1A
-# define CSIDL_PRINTHOOD 0x1B
-# define CSIDL_LOCAL_APPDATA 0x1C
-# define CSIDL_ALTSTARTUP 0x1D
-# define CSIDL_COMMON_ALTSTARTUP 0x1E
-# define CSIDL_COMMON_FAVORITES 0x1F
-
-# define CSIDL_INTERNET_CACHE 0x20
-# define CSIDL_COOKIES 0x21
-# define CSIDL_HISTORY 0x22
-# define CSIDL_COMMON_APPDATA 0x23
-# define CSIDL_WINDOWS 0x24
-# define CSIDL_SYSTEM 0x25
-# define CSIDL_PROGRAM_FILES 0x26
-# define CSIDL_MYPICTURES 0x27
-# define CSIDL_PROFILE 0x28
-# define CSIDL_PROGRAM_FILES_COMMON 0x2B
-# define CSIDL_COMMON_TEMPLATES 0x2D
-# define CSIDL_COMMON_DOCUMENTS 0x2E
-# define CSIDL_COMMON_ADMINTOOLS 0x2F
-
-# define CSIDL_ADMINTOOLS 0x30
-# define CSIDL_COMMON_MUSIC 0x35
-# define CSIDL_COMMON_PICTURES 0x36
-# define CSIDL_COMMON_VIDEO 0x37
-# define CSIDL_RESOURCES 0x38
-# define CSIDL_RESOURCES_LOCALIZED 0x39
-# define CSIDL_CDBURN_AREA 0x3B
-*/
+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;
+}
-struct CCommandPair
+static const char *g_WinAttrib[] =
{
- int NumParams;
- const char *Name;
+ "READONLY"
+ , "HIDDEN"
+ , "SYSTEM"
+ , NULL
+ , "DIRECTORY"
+ , "ARCHIVE"
+ , "DEVICE"
+ , "NORMAL"
+ , "TEMPORARY"
+ , "SPARSE_FILE"
+ , "REPARSE_POINT"
+ , "COMPRESSED"
+ , "OFFLINE"
+ , "NOT_CONTENT_INDEXED"
+ , "ENCRYPTED"
+ , NULL
+ , "VIRTUAL"
};
-enum
+#define FLAGS_DELIMITER '|'
+
+static void FlagsToString2(CDynLimBuf &s, const char **table, unsigned num, UInt32 flags)
{
- // 0
- EW_INVALID_OPCODE, // zero is invalid. useful for catching errors. (otherwise an all zeroes instruction
- // does nothing, which is easily ignored but means something is wrong.
- EW_RET, // return from function call
- EW_NOP, // Nop/Jump, do nothing: 1, [?new address+1:advance one]
- EW_ABORT, // Abort: 1 [status]
- EW_QUIT, // Quit: 0
- EW_CALL, // Call: 1 [new address+1]
- EW_UPDATETEXT, // Update status text: 2 [update str, ui_st_updateflag=?ui_st_updateflag:this]
- EW_SLEEP, // Sleep: 1 [sleep time in milliseconds]
- EW_BRINGTOFRONT, // BringToFront: 0
- EW_CHDETAILSVIEW, // SetDetailsView: 2 [listaction,buttonaction]
-
- // 10
- EW_SETFILEATTRIBUTES, // SetFileAttributes: 2 [filename, attributes]
- EW_CREATEDIR, // Create directory: 2, [path, ?update$INSTDIR]
- EW_IFFILEEXISTS, // IfFileExists: 3, [file name, jump amount if exists, jump amount if not exists]
- EW_SETFLAG, // Sets a flag: 2 [id, data]
- EW_IFFLAG, // If a flag: 4 [on, off, id, new value mask]
- EW_GETFLAG, // Gets a flag: 2 [output, id]
- EW_RENAME, // Rename: 3 [old, new, rebootok]
- EW_GETFULLPATHNAME, // GetFullPathName: 2 [output, input, ?lfn:sfn]
- EW_SEARCHPATH, // SearchPath: 2 [output, filename]
- EW_GETTEMPFILENAME, // GetTempFileName: 2 [output, base_dir]
-
- // 20
- EW_EXTRACTFILE, // File to extract: 6 [overwriteflag, output filename, compressed filedata, filedatetimelow, filedatetimehigh, allow ignore]
- // overwriteflag: 0x1 = no. 0x0=force, 0x2=try, 0x3=if date is newer
- EW_DELETEFILE, // Delete File: 2, [filename, rebootok]
- EW_MESSAGEBOX, // MessageBox: 5,[MB_flags,text,retv1:retv2,moveonretv1:moveonretv2]
- EW_RMDIR, // RMDir: 2 [path, recursiveflag]
- EW_STRLEN, // StrLen: 2 [output, input]
- EW_ASSIGNVAR, // Assign: 4 [variable (0-9) to assign, string to assign, maxlen, startpos]
- EW_STRCMP, // StrCmp: 5 [str1, str2, jump_if_equal, jump_if_not_equal, case-sensitive?]
- EW_READENVSTR, // ReadEnvStr/ExpandEnvStrings: 3 [output, string_with_env_variables, IsRead]
- EW_INTCMP, // IntCmp: 6 [val1, val2, equal, val1<val2, val1>val2, unsigned?]
- EW_INTOP, // IntOp: 4 [output, input1, input2, op] where op: 0=add, 1=sub, 2=mul, 3=div, 4=bor, 5=band, 6=bxor, 7=bnot input1, 8=lnot input1, 9=lor, 10=land], 11=1%2
-
- // 30
- EW_INTFMT, // IntFmt: [output, format, input]
- EW_PUSHPOP, // Push/Pop/Exchange: 3 [variable/string, ?pop:push, ?exch]
- EW_FINDWINDOW, // FindWindow: 5, [outputvar, window class,window name, window_parent, window_after]
- EW_SENDMESSAGE, // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2]
- EW_ISWINDOW, // IsWindow: 3 [hwnd, jump_if_window, jump_if_notwindow]
- EW_GETDLGITEM, // GetDlgItem: 3: [outputvar, dialog, item_id]
- EW_SETCTLCOLORS, // SerCtlColors: 3: [hwnd, pointer to struct colors]
- EW_SETBRANDINGIMAGE, // SetBrandingImage: 1: [Bitmap file]
- EW_CREATEFONT, // CreateFont: 5: [handle output, face name, height, weight, flags]
- EW_SHOWWINDOW, // ShowWindow: 2: [hwnd, show state]
-
- // 40
- EW_SHELLEXEC, // ShellExecute program: 4, [shell action, complete commandline, parameters, showwindow]
- EW_EXECUTE, // Execute program: 3,[complete command line,waitflag,>=0?output errorcode]
- EW_GETFILETIME, // GetFileTime; 3 [file highout lowout]
- EW_GETDLLVERSION, // GetDLLVersion: 3 [file highout lowout]
- EW_REGISTERDLL, // Register DLL: 3,[DLL file name, string ptr of function to call, text to put in display (<0 if none/pass parms), 1 - no unload, 0 - unload]
- EW_CREATESHORTCUT, // Make Shortcut: 5, [link file, target file, parameters, icon file, iconindex|show mode<<8|hotkey<<16]
- EW_COPYFILES, // CopyFiles: 3 [source mask, destination location, flags]
- EW_REBOOT, // Reboot: 0
- EW_WRITEINI, // Write INI String: 4, [Section, Name, Value, INI File]
- EW_READINISTR, // ReadINIStr: 4 [output, section, name, ini_file]
-
- // 50
- EW_DELREG, // DeleteRegValue/DeleteRegKey: 4, [root key(int), KeyName, ValueName, delkeyonlyifempty]. ValueName is -1 if delete key
- EW_WRITEREG, // Write Registry value: 5, [RootKey(int),KeyName,ItemName,ItemData,typelen]
- // typelen=1 for str, 2 for dword, 3 for binary, 0 for expanded str
- EW_READREGSTR, // ReadRegStr: 5 [output, rootkey(int), keyname, itemname, ==1?int::str]
- EW_REGENUM, // RegEnum: 5 [output, rootkey, keyname, index, ?key:value]
- EW_FCLOSE, // FileClose: 1 [handle]
- EW_FOPEN, // FileOpen: 4 [name, openmode, createmode, outputhandle]
- EW_FPUTS, // FileWrite: 3 [handle, string, ?int:string]
- EW_FGETS, // FileRead: 4 [handle, output, maxlen, ?getchar:gets]
- EW_FSEEK, // FileSeek: 4 [handle, offset, mode, >=0?positionoutput]
- EW_FINDCLOSE, // FindClose: 1 [handle]
-
- // 60
- EW_FINDNEXT, // FindNext: 2 [output, handle]
- EW_FINDFIRST, // FindFirst: 2 [filespec, output, handleoutput]
- EW_WRITEUNINSTALLER, // WriteUninstaller: 3 [name, offset, icon_size]
- EW_LOG, // LogText: 2 [0, text] / LogSet: [1, logstate]
- EW_SECTIONSET, // SectionSetText: 3: [idx, 0, text]
- // SectionGetText: 3: [idx, 1, output]
- // SectionSetFlags: 3: [idx, 2, flags]
- // SectionGetFlags: 3: [idx, 3, output]
- EW_INSTTYPESET, // InstTypeSetFlags: 3: [idx, 0, flags]
- // InstTypeGetFlags: 3: [idx, 1, output]
- // instructions not actually implemented in exehead, but used in compiler.
- EW_GETLABELADDR, // both of these get converted to EW_ASSIGNVAR
- EW_GETFUNCTIONADDR,
+ 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);
+}
- EW_LOCKWINDOW
+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 *kOnFunc[] =
+{
+ "Init"
+ , "InstSuccess"
+ , "InstFailed"
+ , "UserAbort"
+ , "GUIInit"
+ , "GUIEnd"
+ , "MouseOverSection"
+ , "VerifyInstDir"
+ , "SelChange"
+ , "RebootFailed"
};
-#ifdef NSIS_SCRIPT
-static CCommandPair kCommandPairs[] =
-{
- { 0, "Invalid" },
- { 0, "Return" },
- { 1, "Goto" },
- { 0, "Abort" },
- { 0, "Quit" },
- { 1, "Call" },
- { 2, "UpdateSatusText" },
- { 1, "Sleep" },
- { 0, "BringToFront" },
- { 2, "SetDetailsView" },
-
- { 2, "SetFileAttributes" },
- { 2, "SetOutPath" },
- { 3, "IfFileExists" },
- { 2, "SetFlag" },
- { 4, "IfFlag" },
- { 2, "GetFlag" },
- { 3, "Rename" },
- { 2, "GetFullPathName" },
- { 2, "SearchPath" },
- { 2, "GetTempFileName" },
-
- { 6, "File" },
- { 2, "Delete" },
- { 5, "MessageBox" },
- { 2, "RMDir" },
- { 2, "StrLen" },
- { 4, "StrCpy" },
- { 5, "StrCmp" },
- { 3, "ReadEnvStr" },
- { 6, "IntCmp" },
- { 4, "IntOp" },
-
- { 3, "IntFmt" },
- { 3, "PushPop" },
- { 5, "FindWindow" },
- { 6, "SendMessage" },
- { 3, "IsWindow" },
- { 3, "GetDlgItem" },
- { 3, "SerCtlColors" },
- { 1, "SetBrandingImage" },
- { 5, "CreateFont" },
- { 2, "ShowWindow" },
-
- { 4, "ShellExecute" },
- { 3, "Execute" },
- { 3, "GetFileTime" },
- { 3, "GetDLLVersion" },
- { 3, "RegisterDLL" },
- { 5, "CreateShortCut" },
- { 3, "CopyFiles" },
- { 0, "Reboot" },
- { 4, "WriteINIStr" },
- { 4, "ReadINIStr" },
-
- { 4, "DelReg" },
- { 5, "WriteReg" },
- { 5, "ReadRegStr" },
- { 5, "RegEnum" },
- { 1, "FileClose" },
- { 4, "FileOpen" },
- { 3, "FileWrite" },
- { 4, "FileRead" },
- { 4, "FileSeek" },
- { 1, "FindClose" },
-
- { 2, "FindNext" },
- { 2, "FindFirst" },
- { 3, "WriteUninstaller" },
- { 2, "LogText" },
- { 3, "Section?etText" },
- { 3, "InstType?etFlags" },
- { 6, "GetLabelAddr" },
- { 2, "GetFunctionAddress" },
- { 6, "LockWindow" }
+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 *k_REBOOTOK = " /REBOOTOK";
+
+#define MY__MB_ABORTRETRYIGNORE 2
+#define MY__MB_RETRYCANCEL 5
+
+static const char *k_MB_Buttons[] =
+{
+ "OK"
+ , "OKCANCEL"
+ , "ABORTRETRYIGNORE"
+ , "YESNOCANCEL"
+ , "YESNO"
+ , "RETRYCANCEL"
+ , "CANCELTRYCONTINUE"
};
-#endif
+#define MY__MB_ICONSTOP (1 << 4)
-static const char *kShellStrings[] =
+static const char *k_MB_Icons[] =
+{
+ NULL
+ , "ICONSTOP"
+ , "ICONQUESTION"
+ , "ICONEXCLAMATION"
+ , "ICONINFORMATION"
+};
+
+static const char *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 *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 UInt32 ConvertHexStringToUInt32(const char *s, const char **end)
+{
+ UInt32 result = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ char c = *s;
+ UInt32 v;
+ if (c >= '0' && c <= '9') v = (c - '0');
+ else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A');
+ else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a');
+ else
+ {
+ if (end != NULL)
+ *end = s;
+ return result;
+ }
+ result <<= 4;
+ result |= v;
+ s++;
+ }
+ if (end != NULL)
+ *end = s;
+ return 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 *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)
{
- "",
- "",
-
- "SMPROGRAMS",
- "",
- "PRINTERS",
- "DOCUMENTS",
- "FAVORITES",
- "SMSTARTUP",
- "RECENT",
- "SENDTO",
- "",
- "STARTMENU",
- "",
- "MUSIC",
- "VIDEO",
- "",
-
- "DESKTOP",
- "",
- "",
- "NETHOOD",
- "FONTS",
- "TEMPLATES",
- "COMMONSTARTMENU",
- "COMMONFILES",
- "COMMON_STARTUP",
- "COMMON_DESKTOPDIRECTORY",
- "QUICKLAUNCH",
- "PRINTHOOD",
- "LOCALAPPDATA",
- "ALTSTARTUP",
- "ALTSTARTUP",
- "FAVORITES",
-
- "INTERNET_CACHE",
- "COOKIES",
- "HISTORY",
- "APPDATA",
- "WINDIR",
- "SYSDIR",
- "PROGRAMFILES",
- "PICTURES",
- "PROFILE",
- "",
- "",
- "COMMONFILES",
- "",
- "TEMPLATES",
- "DOCUMENTS",
- "ADMINTOOLS",
-
- "ADMINTOOLS",
- "",
- "",
- "",
- "",
- "MUSIC",
- "PICTURES",
- "VIDEO",
- "RESOURCES",
- "RESOURCES_LOCALIZED",
- "",
- "CDBURN_AREA"
+ 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 **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,
};
-static const int kNumShellStrings = sizeof(kShellStrings) / sizeof(kShellStrings[0]);
+// Names for NSIS exec_flags_t structure vars
+static const char *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 CMDLINE 20 // everything before here doesn't have trailing slash removal
-# define INSTDIR 21
-# define OUTDIR 22
-# define EXEDIR 23
-# define LANGUAGE 24
-# define TEMP 25
-# define PLUGINSDIR 26
-# define HWNDPARENT 27
-# define _CLICK 28
-# define _OUTDIR 29
+#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
*/
-static const char *kVarStrings[] =
+// page window proc
+enum
+{
+ PWP_LICENSE,
+ PWP_SELCOM,
+ PWP_DIR,
+ PWP_INSTFILES,
+ PWP_UNINST,
+ PWP_COMPLETED,
+ PWP_CUSTOM
+};
+
+static const char *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 *kSection_VarsNames[] =
{
- "CMDLINE",
- "INSTDIR",
- "OUTDIR",
- "EXEDIR",
- "LANGUAGE",
- "TEMP",
- "PLUGINSDIR",
- "EXEPATH", // test it
- "EXEFILE", // test it
- "HWNDPARENT",
- "_CLICK",
- "_OUTDIR"
+ "Text"
+ , "InstTypes"
+ , "Flags"
+ , "Code"
+ , "CodeSize"
+ , "Size" // size in KB
};
-static const int kNumVarStrings = sizeof(kVarStrings) / sizeof(kVarStrings[0]);
+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)
-static AString GetVar(UInt32 index)
+bool CInArchive::PrintSectionBegin(const CSection &sect, unsigned index)
{
- AString res = "$";
- if (index < 10)
- res += UIntToString(index);
- else if (index < 20)
+ AString name;
+ if (sect.Flags & SF_BOLD)
+ name += '!';
+ AString s2;
+ ReadString2(s2, sect.Name);
+ if (!IsInstaller)
{
- res += "R";
- res += UIntToString(index - 10);
+ if (!StringsAreEqualNoCase_Ascii(s2, "uninstall"))
+ name += "un.";
}
- else if (index < 20 + kNumVarStrings)
- res += kVarStrings[index - 20];
+ 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)
{
- res += "[";
- res += UIntToString(index);
- res += "]";
+ // probably we must show AddSize, only if there is additional size.
+ Tab();
+ AddCommentAndString("AddSize");
+ AddParam_UInt(sect.SizeKB);
+ AddLF();
}
- return res;
+
+ 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;
}
-#define NS_SKIP_CODE 252
-#define NS_VAR_CODE 253
-#define NS_SHELL_CODE 254
-#define NS_LANG_CODE 255
-#define NS_CODES_START NS_SKIP_CODE
+void CInArchive::PrintSectionEnd()
+{
+ AddStringLF("SectionEnd");
+ AddLF();
+}
+
+// static const unsigned kOnFuncShift = 4;
-static AString GetShellString(int index)
+void CInArchive::ClearLangComment()
{
- AString res = "$";
- if (index < kNumShellStrings)
+ 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())
{
- const char *sz = kShellStrings[index];
- if (sz[0] != 0)
- return res + sz;
+ 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();
}
- res += "SHELL[";
- res += UIntToString(index);
- res += "]";
- return res;
+ AddLF();
}
-// Based on Dave Laundon's simplified process_string
-AString GetNsisString(const AString &s)
+static const UInt32 kPageSize = 16 * 4;
+
+static const char *k_SetOverwrite_Modes[] =
+{
+ "on"
+ , "off"
+ , "try"
+ , "ifnewer"
+ , "ifdiff"
+ // "lastused"
+};
+
+
+void CInArchive::MessageBox_MB_Part(UInt32 param)
{
- AString res;
- for (int i = 0; i < s.Length();)
{
- unsigned char nVarIdx = s[i++];
- if (nVarIdx > NS_CODES_START && i + 2 <= s.Length())
+ UInt32 v = param & 0xF;
+ Script += " MB_";
+ if (v < ARRAY_SIZE(k_MB_Buttons))
+ Script += k_MB_Buttons[v];
+ else
{
- int nData = s[i++] & 0x7F;
- unsigned char c1 = s[i++];
- nData |= (((int)(c1 & 0x7F)) << 7);
+ 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 (int 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)
+{
+ if (!dest.IsEmpty())
+ dest += ' ';
+ 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 (nVarIdx == NS_SHELL_CODE)
- res += GetShellString(c1);
- else if (nVarIdx == NS_VAR_CODE)
- res += GetVar(nData);
- else if (nVarIdx == NS_LANG_CODE)
- res += "NS_LANG_CODE";
+ 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;
}
- else if (nVarIdx == NS_SKIP_CODE)
+
+ if (a >= EW_SECTIONSET && LogCmdIsEnabled)
{
- if (i < s.Length())
- res += s[i++];
+ if (a == EW_SECTIONSET)
+ return EW_LOG;
+ return a - 1;
}
- else // Normal char
- res += (char)nVarIdx;
+ if (a == EW_FPUTWS)
+ return EW_FINDPROC;
+ // if (a > EW_FPUTWS) return 0;
}
- return res;
+ return a;
}
-UString GetNsisString(const UString &s)
+void CInArchive::FindBadCmd(const CBlockHeader &bh, const Byte *p)
{
- UString res;
- for (int i = 0; i < s.Length();)
+ BadCmd = -1;
+
+ for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize)
{
- wchar_t nVarIdx = s[i++];
- if (nVarIdx > NS_UN_CODES_START && nVarIdx <= NS_UN_CODES_END)
+ 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)
{
- if (i == s.Length())
+ BadCmd = id;
+ continue;
+ }
+ for (i = 6; i != 0; i--)
+ {
+ UInt32 param = Get32(p + i * 4);
+ if (param != 0)
break;
- int nData = s[i++] & 0x7FFF;
+ }
+ if (id == EW_FINDPROC && i == 0)
+ {
+ BadCmd = id;
+ continue;
+ }
+ if (k_Commands[id].NumParams < i)
+ BadCmd = id;
+ }
+}
- if (nVarIdx == NS_UN_SHELL_CODE)
- res += GetUnicodeString(GetShellString(nData >> 8));
- else if (nVarIdx == NS_UN_VAR_CODE)
- res += GetUnicodeString(GetVar(nData));
- else if (nVarIdx == NS_UN_LANG_CODE)
- res += L"NS_LANG_CODE";
+/* 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;
+
+ {
+ const Byte *strData = _data + _stringsPos;
+ if (IsUnicode)
+ {
+ UInt32 num = NumStringChars;
+ for (UInt32 i = 0; i < num; i++)
+ {
+ if (Get16(strData + i * 2) == 0)
+ {
+ unsigned c2 = Get16(strData + 2 + i * 2);
+ // if (c2 <= NS_3_CODE_SKIP && c2 != NS_3_CODE_SHELL)
+ if (c2 == NS_3_CODE_VAR)
+ {
+ // it can be TXT/RTF string with marker char (1 or 2). so we must next char
+ // const wchar_t *p2 = (const wchar_t *)(strData + i * 2 + 2);
+ // p2 = p2;
+ if ((Get16(strData + 3 + i * 2) & 0x8000) != 0)
+ {
+ NsisType = k_NsisType_Nsis3;
+ strongNsis = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!strongNsis)
+ {
+ NsisType = k_NsisType_Park1;
+ strongPark = true;
+ }
}
- else if (nVarIdx == NS_UN_SKIP_CODE)
+ else
{
- if (i == s.Length())
- break;
- res += s[i++];
+ UInt32 num = NumStringChars;
+ 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);
}
- else // Normal char
- res += (char)nVarIdx;
}
- return res;
}
-AString CInArchive::ReadString2A(UInt32 pos) const
+Int32 CInArchive::GetVarIndex(UInt32 strPos) const
{
- return GetNsisString(ReadStringA(pos));
+ 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);
}
-UString CInArchive::ReadString2U(UInt32 pos) const
+Int32 CInArchive::GetVarIndex(UInt32 strPos, UInt32 &resOffset) const
{
- return GetNsisString(ReadStringU(pos));
+ 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;
}
-AString CInArchive::ReadString2(UInt32 pos) const
+Int32 CInArchive::GetVarIndexFinished(UInt32 strPos, Byte endChar, UInt32 &resOffset) const
{
+ resOffset = 0;
+ Int32 varIndex = GetVarIndex(strPos);
+ if (varIndex < 0)
+ return varIndex;
if (IsUnicode)
- return UnicodeStringToMultiByte(ReadString2U(pos));
+ {
+ if (NumStringChars - strPos < 3 * 2)
+ return -1;
+ const Byte *p = _data + _stringsPos + strPos * 2;
+ if (Get16(p + 4) != endChar)
+ return -1;
+ resOffset = 3;
+ }
else
- return ReadString2A(pos);
+ {
+ if (NumStringChars - strPos < 4)
+ return -1;
+ const Byte *p = _data + _stringsPos + strPos;
+ if (p[3] != endChar)
+ return -1;
+ resOffset = 4;
+ }
+ return varIndex;
}
-AString CInArchive::ReadString2Qw(UInt32 pos) const
+bool CInArchive::IsVarStr(UInt32 strPos, UInt32 varIndex) const
{
- return "\"" + ReadString2(pos) + "\"";
+ if (varIndex > (UInt32)0x7FFF)
+ return false;
+ UInt32 resOffset;
+ return GetVarIndexFinished(strPos, 0, resOffset) == (Int32)varIndex;
}
-#define DEL_DIR 1
-#define DEL_RECURSE 2
-#define DEL_REBOOT 4
-// #define DEL_SIMPLE 8
+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')
-static const int kNumEntryParams = 6;
+// 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);
+}
-struct CEntry
+void CInArchive::SetItemName(CItem &item, UInt32 strPos)
{
- UInt32 Which;
- UInt32 Params[kNumEntryParams];
- AString GetParamsString(int numParams);
- CEntry()
+ ReadString2_Raw(strPos);
+ bool isAbs = IsAbsolutePathVar(strPos);
+ if (IsUnicode)
{
- Which = 0;
- for (UInt32 j = 0; j < kNumEntryParams; j++)
- Params[j] = 0;
+ 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;
+ }
+}
-AString CEntry::GetParamsString(int numParams)
+HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
{
- AString s;
- for (int i = 0; i < numParams; i++)
+ #ifdef NSIS_SCRIPT
+ CDynLimBuf &s = Script;
+
+ CObjArray<UInt32> labels;
+ labels.Alloc(bh.Num);
+ memset(labels, 0, bh.Num * sizeof(UInt32));
+
{
- s += " ";
- UInt32 v = Params[i];
- if (v > 0xFFF00000)
- s += IntToString((Int32)Params[i]);
+ 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
- s += UIntToString(Params[i]);
+ {
+
+ 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();
+ }
+ }
}
- return s;
-}
-#ifdef NSIS_SCRIPT
+ CObjArray<CSection> Sections;
-static AString GetRegRootID(UInt32 val)
-{
- const char *s;
- switch(val)
{
- case 0: s = "SHCTX"; break;
- case 0x80000000: s = "HKCR"; break;
- case 0x80000001: s = "HKCU"; break;
- case 0x80000002: s = "HKLM"; break;
- case 0x80000003: s = "HKU"; break;
- case 0x80000004: s = "HKPD"; break;
- case 0x80000005: s = "HKCC"; break;
- case 0x80000006: s = "HKDD"; break;
- case 0x80000050: s = "HKPT"; break;
- case 0x80000060: s = "HKPN"; break;
- default:
- return UIntToString(val); break;
+ Separator();
+ PrintNumComment("SECTIONS", bhSections.Num);
+ PrintNumComment("COMMANDS", bh.Num);
+ AddLF();
+
+ if (bhSections.Num > (1 << 15)
+ // || bhSections.Offset > _size
+ // || (bhSections.Num * SectionSize > _size - bhSections.Offset)
+ )
+ {
+ AddErrorLF("Sections error");
+ }
+ else if (bhSections.Num != 0)
+ {
+ Sections.Alloc((unsigned)bhSections.Num);
+ const Byte *p = _data + bhSections.Offset;
+ for (UInt32 i = 0; i < bhSections.Num; i++, p += SectionSize)
+ {
+ CSection &section = Sections[i];
+ section.Parse(p);
+ if (section.StartCmdIndex < bh.Num)
+ labels[section.StartCmdIndex] |= CMD_REF_Section;
+ }
+ }
}
- return s;
-}
-#endif
+ #endif
-HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
-{
- _posInData = bh.Offset + GetOffset();
- AString prefixA;
- UString prefixU;
- for (UInt32 i = 0; i < bh.Num; i++)
+ 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 (int 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(L"$INSTDIR");
+ APrefixes.Add("$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)
{
- CEntry e;
- e.Which = ReadUInt32();
- for (UInt32 j = 0; j < kNumEntryParams; j++)
- e.Params[j] = ReadUInt32();
+ 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
- if (e.Which != EW_PUSHPOP && e.Which < sizeof(kCommandPairs) / sizeof(kCommandPairs[0]))
+
+ bool IsSectionGroup = false;
+ while (curSectionIndex < bhSections.Num)
{
- const CCommandPair &pair = kCommandPairs[e.Which];
- Script += pair.Name;
+ const CSection &sect = Sections[curSectionIndex];
+ if (sectionIsOpen)
+ {
+ if (sect.StartCmdIndex + sect.NumCommands + 1 != kkk)
+ break;
+ PrintSectionEnd();
+ sectionIsOpen = false;
+ // lastSectionEndCmd = kkk;
+ curSectionIndex++;
+ continue;
+ }
+ if (sect.StartCmdIndex != kkk)
+ break;
+ if (PrintSectionBegin(sect, curSectionIndex))
+ {
+ IsSectionGroup = true;
+ curSectionIndex++;
+ // do we need to flush prefixes in new section?
+ // FlushOutPathPrefixes();
+ }
+ else
+ sectionIsOpen = true;
}
+
+ /*
+ if (curOnFunc < OnFuncs.Size())
+ {
+ if ((OnFuncs[curOnFunc] >> kOnFuncShift) == kkk)
+ {
+ s += "Function .on";
+ s += kOnFunc[OnFuncs[curOnFunc++] & ((1 << kOnFuncShift) - 1)];
+ AddLF();
+ onFuncIsOpen = true;
+ }
+ }
+ */
+
+ if (labels[kkk] != 0 && labels[kkk] != CMD_REF_Section)
+ {
+ UInt32 flg = labels[kkk];
+ if (IsFunc(flg))
+ {
+ if ((int)kkk == InitPluginsDir_Start)
+ CommentOpen();
+
+ onFuncIsOpen = true;
+ s += "Function ";
+ Add_FuncName(labels, kkk);
+ if (IsPageFunc(flg))
+ {
+ BigSpaceComment();
+ s += "Page ";
+ Add_UInt((flg & CMD_REF_Page_Mask) >> CMD_REF_Page_NumShifts);
+ // if (flg & CMD_REF_Creator) s += ", Creator";
+ if (flg & CMD_REF_Leave) s += ", Leave";
+ if (flg & CMD_REF_Pre) s += ", Pre";
+ if (flg & CMD_REF_Show) s += ", Show";
+ }
+ AddLF();
+ }
+ if (flg & CMD_REF_Goto)
+ {
+ Add_LabelName(kkk);
+ s += ':';
+ AddLF();
+ }
+ }
+
+ if (commandId != EW_RET)
+ {
+ Tab(kkk < endCommentIndex);
+ }
+
+ /*
+ UInt32 originalCmd = Get32(p);
+ if (originalCmd >= EW_REGISTERDLL)
+ {
+ UIntToString(s, originalCmd);
+ s += ' ';
+ if (originalCmd != commandId)
+ {
+ UIntToString(s, commandId);
+ s += ' ';
+ }
+ }
+ */
+
+ unsigned numSkipParams = 0;
+
+ if (commandId < 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 (e.Which)
+ switch (commandId)
{
case EW_CREATEDIR:
{
- if (IsUnicode)
+ bool isSetOutPath = (params[1] != 0);
+
+ if (isSetOutPath)
{
- prefixU.Empty();
- prefixU = ReadString2U(e.Params[0]);
+ 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);
+ }
}
- else
+
+ #ifdef NSIS_SCRIPT
+ s += isSetOutPath ? "SetOutPath" : "CreateDirectory";
+ AddParam(params[0]);
+ #endif
+
+ break;
+ }
+
+
+ case EW_ASSIGNVAR:
+ {
+ if (params[0] == spec_outdir_VarIndex)
{
- prefixA.Empty();
- prefixA = ReadString2A(e.Params[0]);
+ spec_outdir_U.Empty();
+ spec_outdir_A.Empty();
+ if (IsVarStr(params[1], kVar_OUTDIR) &&
+ params[2] == 0 &&
+ params[3] == 0)
+ {
+ if (IsVarStr(params[1], kVar_OUTDIR))
+ {
+ spec_outdir_U = UPrefixes.Back(); // outdir_U;
+ spec_outdir_A = APrefixes.Back();// outdir_A;
+ }
+ }
}
+
#ifdef NSIS_SCRIPT
- Script += " ";
- if (IsUnicode)
- Script += UnicodeStringToMultiByte(prefixU);
- else
- Script += prefixA;
+
+ 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;
- item.IsUnicode = IsUnicode;
- if (IsUnicode)
+ 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
+
{
- item.PrefixU = prefixU;
- item.NameU = ReadString2U(e.Params[1]);
+ 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);
+ }
}
- else
+
{
- item.PrefixA = prefixA;
- item.NameA = ReadString2A(e.Params[1]);
+ 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;
+ }
}
- /* UInt32 overwriteFlag = e.Params[0]; */
- item.Pos = e.Params[2];
- item.MTime.dwLowDateTime = e.Params[3];
- item.MTime.dwHighDateTime = e.Params[4];
- /* UInt32 allowIgnore = e.Params[5]; */
- if (Items.Size() > 0)
+
+ 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
{
- /*
- if (item.Pos == Items.Back().Pos)
- continue;
- */
+ // 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
+ {
+ ReadString2_Raw(pars[1]);
+ if (IsUnicode)
+ {
+ if (!Raw_UString.IsEmpty())
+ item.NameU = Raw_UString;
+ }
+ else
+ {
+ if (!Raw_AString.IsEmpty())
+ item.NameA = Raw_AString;
+ }
+ }
+ }
+ }
}
- Items.Add(item);
- #ifdef NSIS_SCRIPT
- Script += " ";
+ /* UInt32 allowIgnore = params[5]; */
+ break;
+ }
- if (IsUnicode)
- Script += UnicodeStringToMultiByte(item.NameU);
- else
- Script += item.NameA;
+ 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]);
+
+ SmallSpaceComment();
+
+ /*
+ for (int i = 1; i < 3; i++)
+ AddParam_UInt(params[i]);
+ */
+
+ if (params[3] != 0)
+ 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 &sect = Sections[curSectionIndex];
+ if (sect.StartCmdIndex + sect.NumCommands == kkk)
+ {
+ PrintSectionEnd();
+ sectionIsOpen = false;
+ curSectionIndex++;
+ break;
+ }
+
+ // needComment = true;
+ // break;
+ }
+
+ /*
+ if (needComment)
+ s += " ;";
+ */
+ TabString("Return");
+ AddLF();
+ break;
+ }
+
+ case EW_NOP:
+ {
+ if (params[0] == 0)
+ s += "Nop";
+ else
+ {
+ s += "Goto";
+ Add_GotoVar(params[0]);
+ }
+ break;
+ }
+
+ case EW_ABORT:
+ {
+ AddOptionalParam(params[0]);
+ break;
+ }
+
+ case EW_CALL:
+ {
+ if (kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_EXTRACTFILE)
+ {
+ UInt32 par1 = GET_CMD_PARAM(p + kCmdSize, 1);
+
+ UInt32 pluginPar = 0;
+
+ if (GetVarIndexFinished(par1, '\\', pluginPar) == kVar_PLUGINSDIR)
+ {
+ pluginPar += par1;
+ UInt32 commandId2 = GetCmd(Get32(p + kCmdSize * 2));
+ if (commandId2 == EW_SETFLAG || commandId2 == EW_UPDATETEXT)
+ {
+ UInt32 i;
+ for (i = kkk + 3; i < bh.Num; i++)
+ {
+ const Byte *pCmd = p + kCmdSize * (i - kkk);
+ UInt32 commandId3 = GetCmd(Get32(pCmd));
+ if (commandId3 != EW_PUSHPOP
+ || GET_CMD_PARAM(pCmd, 1) != 0
+ || GET_CMD_PARAM(pCmd, 2) != 0)
+ break;
+ }
+ if (i < bh.Num)
+ {
+ const Byte *pCmd = p + kCmdSize * (i - kkk);
+
+ // UInt32 callDll_Param = GET_CMD_PARAM(pCmd, 0);
+ // UInt32 file_Param = GET_CMD_PARAM(p + kCmdSize, 1);
+
+ if (GetCmd(Get32(pCmd)) == EW_REGISTERDLL &&
+ AreTwoParamStringsEqual(
+ GET_CMD_PARAM(pCmd, 0),
+ GET_CMD_PARAM(p + kCmdSize, 1)))
+ {
+ // params[4] = 1 means GetModuleHandle attempt before default LoadLibraryEx;
+ /// new versions of NSIS use params[4] = 1 for Plugin command
+ if (GET_CMD_PARAM(pCmd, 2) == 0
+ // && GET_CMD_PARAM(pCmd, 4) != 0
+ )
+ {
+ {
+ AString s2;
+ ReadString2(s2, pluginPar);
+ if (s2.Len() >= 4 &&
+ StringsAreEqualNoCase_Ascii(s2.RightPtr(4), ".dll"))
+ s2.DeleteFrom(s2.Len() - 4);
+ s2 += "::";
+ AString func;
+ ReadString2(func, GET_CMD_PARAM(pCmd, 1));
+ s2 += func;
+ Add_QuStr(s2);
+
+ if (GET_CMD_PARAM(pCmd, 3) == 1)
+ s += " /NOUNLOAD";
+
+ for (UInt32 j = i - 1; j >= kkk + 3; j--)
+ {
+ const Byte *pCmd = p - kCmdSize * (kkk - j);
+ 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:
{
- Script += " ";
- Script += ReadString2(e.Params[0]);
- Script += " ";
- Script += UIntToString(e.Params[1]);
+ AddParam(params[0]);
break;
}
- case EW_SETFILEATTRIBUTES:
+
+ case EW_CHDETAILSVIEW:
{
- Script += " ";
- Script += ReadString2(e.Params[0]);
- Script += " ";
- Script += UIntToString(e.Params[1]);
+ 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:
{
- Script += " ";
- Script += ReadString2(e.Params[0]);
- Script += " ";
- Script += UIntToString(e.Params[1]);
- Script += " ";
- Script += UIntToString(e.Params[2]);
+ AddParam(params[0]);
+ Add_GotoVars2(&params[1]);
break;
}
+
+ case EW_SETFLAG:
+ {
+ AString temp;
+ ReadString2(temp, params[1]);
+ if (params[0] == k_ExecFlags_Errors && params[2] == 0)
+ {
+ s += (temp.Len() == 1 && temp[0] == '0') ? "ClearErrors" : "SetErrors";
+ break;
+ }
+ s += "Set";
+ Add_ExecFlags(params[0]);
+
+ if (params[2] != 0)
+ {
+ s += " lastused";
+ break;
+ }
+ UInt32 v;
+ if (StringToUInt32(temp, v))
+ {
+ const char *s2 = NULL;
+ switch (params[0])
+ {
+ case k_ExecFlags_AutoClose:
+ case k_ExecFlags_RebootFlag:
+ if (v < 2) s2 = (v == 0) ? "false" : "true"; break;
+ case k_ExecFlags_ShellVarContext:
+ if (v < 2) s2 = (v == 0) ? "current" : "all"; break;
+ case k_ExecFlags_Silent:
+ if (v < 2) s2 = (v == 0) ? "normal" : "silent"; break;
+ case k_ExecFlags_RegView:
+ if (v == 0) s2 = "32";
+ else if (v == 256) s2 = "64";
+ break;
+ case k_ExecFlags_DetailsPrint:
+ if (v == 0) s2 = "both";
+ else if (v == 2) s2 = "textonly";
+ else if (v == 4) s2 = "listonly";
+ else if (v == 6) s2 = "none";
+ }
+ if (s2)
+ {
+ s += ' ';
+ s += s2;
+ break;
+ }
+ }
+ SpaceQuStr(temp);
+ break;
+ }
+
+ case EW_IFFLAG:
+ {
+ Add_ExecFlags(params[2]);
+ Add_GotoVars2(&params[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:
{
- Script += " ";
- Script += ReadString2(e.Params[0]);
- Script += " ";
- Script += ReadString2(e.Params[1]);
- Script += " ";
- Script += UIntToString(e.Params[2]);
+ 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:
{
- Script += " ";
- Script += ReadString2(e.Params[0]);
- Script += " ";
- Script += ReadString2(e.Params[1]);
- Script += " ";
- Script += UIntToString(e.Params[2]);
+ if (params[2] == 0)
+ s += " /SHORT";
+ AddParam_Var(params[1]);
+ AddParam(params[0]);
break;
}
+
case EW_SEARCHPATH:
+ case EW_STRLEN:
{
- Script += " ";
- Script += ReadString2(e.Params[0]);
- Script += " ";
- Script += ReadString2(e.Params[1]);
+ AddParam_Var(params[0]);
+ AddParam(params[1]);
break;
}
+
case EW_GETTEMPFILENAME:
{
- AString s;
- Script += " ";
- Script += ReadString2(e.Params[0]);
- Script += " ";
- Script += ReadString2(e.Params[1]);
+ AddParam_Var(params[0]);
+ AString temp;
+ ReadString2(temp, params[1]);
+ if (temp != "$TEMP")
+ SpaceQuStr(temp);
break;
}
case EW_DELETEFILE:
{
- UInt64 flag = e.Params[1];
- if (flag != 0)
+ 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]);
{
- Script += " ";
- if (flag == DEL_REBOOT)
- Script += "/REBOOTOK";
- else
- Script += UIntToString(e.Params[1]);
+ UInt32 buttonID = (params[0] >> 21); // NSIS 2.06+
+ if (buttonID != 0)
+ {
+ s += " /SD";
+ Add_ButtonID(buttonID);
+ }
}
- Script += " ";
- Script += ReadString2(e.Params[0]);
+ 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:
{
- UInt64 flag = e.Params[1];
- if (flag != 0)
+ UInt32 flag = params[1];
+ if ((flag & DEL_RECURSE) != 0)
+ s += " /r";
+ if ((flag & DEL_REBOOT) != 0)
+ s += k_REBOOTOK;
+ AddParam(params[0]);
+ break;
+ }
+
+ case EW_STRCMP:
+ {
+ if (params[4] != 0)
+ s += 'S';
+ AddParams(params, 2);
+ Add_GotoVars2(&params[2]);
+ break;
+ }
+
+ case EW_READENVSTR:
+ {
+ s += (params[2] != 0) ?
+ "ReadEnvStr" :
+ "ExpandEnvStrings";
+ AddParam_Var(params[0]);
+ AString temp;
+ ReadString2(temp, params[1]);
+ if (params[2] != 0 &&temp.Len() >= 2 && temp[0] == '%' && temp.Back() == '%')
{
- if ((flag & DEL_REBOOT) != 0)
- Script += " /REBOOTOK";
- if ((flag & DEL_RECURSE) != 0)
- Script += " /r";
+ temp.DeleteBack();
+ temp.Delete(0);
}
- Script += " ";
- Script += ReadString2(e.Params[0]);
+ SpaceQuStr(temp);
break;
}
- case EW_STRLEN:
+
+ case EW_INTCMP:
{
- Script += " ";
- Script += GetVar(e.Params[0]);;
- Script += " ";
- Script += ReadString2Qw(e.Params[1]);
+ 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_ASSIGNVAR:
+
+ case EW_INTOP:
{
- Script += " ";
- Script += GetVar(e.Params[0]);;
- Script += " ";
- Script += ReadString2Qw(e.Params[1]);
- AString maxLen, startOffset;
- if (e.Params[2] != 0)
- maxLen = ReadString2(e.Params[2]);
- if (e.Params[3] != 0)
- startOffset = ReadString2(e.Params[3]);
- if (!maxLen.IsEmpty() || !startOffset.IsEmpty())
- {
- Script += " ";
- if (maxLen.IsEmpty())
- Script += "\"\"";
- else
- Script += maxLen;
- if (!startOffset.IsEmpty())
+ AddParam_Var(params[0]);
+ const char *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)
{
- Script += " ";
- Script += startOffset;
+ 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_STRCMP:
+
+ case EW_FINDWINDOW:
{
- Script += " ";
+ AddParam_Var(params[0]);
+ AddParam(params[1]);
+ AddOptionalParams(params + 2, 3);
+ break;
+ }
- Script += " ";
- Script += ReadString2Qw(e.Params[0]);
+ 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);
- Script += " ";
- Script += ReadString2Qw(e.Params[1]);
+ 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);
+ }
- for (int j = 2; j < 5; j++)
+ if ((Int32)params[0] >= 0)
+ AddParam_Var(params[0]);
+
+ spec >>= 2;
+ if (spec != 0)
{
- Script += " ";
- Script += UIntToString(e.Params[j]);
+ s += " /TIMEOUT=";
+ Add_UInt(spec);
}
break;
}
- case EW_INTCMP:
+
+ case EW_ISWINDOW:
{
- if (e.Params[5] != 0)
- Script += "U";
+ AddParam(params[0]);
+ Add_GotoVars2(&params[1]);
+ break;
+ }
+
+ case EW_GETDLGITEM:
+ {
+ AddParam_Var(params[0]);
+ AddParams(params + 1, 2);
+ break;
+ }
+
+ case EW_SETCTLCOLORS:
+ {
+ AddParam(params[0]);
+
+ UInt32 offset = params[1];
+
+ if (_size < bhCtlColors.Offset
+ || _size - bhCtlColors.Offset < offset
+ || _size - bhCtlColors.Offset - offset < k_CtlColors_Size)
+ {
+ AddError("bad offset");
+ break;
+ }
- Script += " ";
- Script += ReadString2(e.Params[0]);
- Script += " ";
- Script += ReadString2(e.Params[1]);
+ const Byte *p2 = _data + bhCtlColors.Offset + offset;
+ CNsis_CtlColors colors;
+ colors.Parse(p2);
- for (int i = 2; i < 5; i++)
+ 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)
{
- Script += " ";
- Script += UIntToString(e.Params[i]);
+ 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_INTOP:
+
+ case EW_SETBRANDINGIMAGE:
{
- Script += " ";
- Script += GetVar(e.Params[0]);
- Script += " ";
- int numOps = 2;
- AString op;
- switch (e.Params[3])
- {
- case 0: op = '+'; break;
- case 1: op = '-'; break;
- case 2: op = '*'; break;
- case 3: op = '/'; break;
- case 4: op = '|'; break;
- case 5: op = '&'; break;
- case 6: op = '^'; break;
- case 7: op = '~'; numOps = 1; break;
- case 8: op = '!'; numOps = 1; break;
- case 9: op = "||"; break;
- case 10: op = "&&"; break;
- case 11: op = '%'; break;
- default: op = UIntToString(e.Params[3]);
- }
- AString p1 = ReadString2(e.Params[1]);
- if (numOps == 1)
- {
- Script += op;
- Script += p1;
- }
+ 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
{
- Script += p1;
- Script += " ";
- Script += op;
- Script += " ";
- Script += ReadString2(e.Params[2]);
+ 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_PUSHPOP:
+ case EW_SHELLEXEC:
{
- int isPop = (e.Params[1] != 0);
- if (isPop)
+ AddParams(params, 2);
+ if (params[2] != 0 || params[3] != MY__SW_SHOWNORMAL)
{
- Script += "Pop";
- Script += " ";
- Script += GetVar(e.Params[0]);;
+ 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
{
- int isExch = (e.Params[2] != 0);
- if (isExch)
+ if (func == "DllUnregisterServer")
{
- Script += "Exch";
+ s += "UnRegDLL";
+ printFunc = false;
}
else
{
- Script += "Push";
- Script += " ";
- Script += ReadString2(e.Params[0]);
+ s += "RegDLL";
+ if (func == "DllRegisterServer")
+ printFunc = false;
}
+ AddParam(params[0]);
}
+ if (printFunc)
+ SpaceQuStr(func);
break;
}
- case EW_SENDMESSAGE:
+ case EW_CREATESHORTCUT:
{
- // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2]
- Script += " ";
- // Script += ReadString2(e.Params[0]);
- // Script += " ";
- Script += ReadString2(e.Params[1]);
- Script += " ";
- Script += ReadString2(e.Params[2]);
-
- Script += " ";
- UInt32 spec = e.Params[5];
- // if (spec & 1)
- Script += IntToString(e.Params[3]);
- // else
- // Script += ReadString2(e.Params[3]);
+ 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);
- Script += " ";
- // if (spec & 2)
- Script += IntToString(e.Params[4]);
- // else
- // Script += ReadString2(e.Params[4]);
+ UInt32 modKey = spec >> 24;
+ UInt32 key = (spec >> 16) & 0xFF;
- if ((Int32)e.Params[0] >= 0)
+ if (modKey == 0 && key == 0)
{
- Script += " ";
- Script += GetVar(e.Params[1]);
+ if (numParams < 6)
+ break;
+ Space();
+ AddQuotes();
}
-
- spec >>= 2;
- if (spec != 0)
+ else
{
- Script += " /TIMEOUT=";
- Script += IntToString(spec);
+ 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_GETDLGITEM:
+ case EW_COPYFILES:
{
- Script += " ";
- Script += GetVar(e.Params[0]);;
- Script += " ";
- Script += ReadString2(e.Params[1]);
- Script += " ";
- Script += ReadString2(e.Params[2]);
+ 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_REGISTERDLL:
+ case EW_REBOOT:
{
- Script += " ";
- Script += ReadString2(e.Params[0]);
- Script += " ";
- Script += ReadString2(e.Params[1]);
- Script += " ";
- Script += UIntToString(e.Params[2]);
+ if (params[0] != 0xbadf00d)
+ s += " ; Corrupted ???";
+ else if (kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_QUIT)
+ endCommentIndex = kkk + 2;
break;
}
- case EW_CREATESHORTCUT:
+ case EW_WRITEINI:
{
- AString s;
-
- Script += " ";
- Script += ReadString2Qw(e.Params[0]);
+ 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;
+ }
- Script += " ";
- Script += ReadString2Qw(e.Params[1]);
+ case EW_READINISTR:
+ {
+ AddParam_Var(params[0]);
+ AddParam(params[3]); // FileName
+ AddParams(params +1, 2); // Section, EntryName
+ break;
+ }
- for (int j = 2; j < 5; j++)
+ case EW_DELREG:
+ {
+ // NSIS 2.00 used another scheme!
+
+ if (params[4] == 0)
+ s += "Value";
+ else
{
- Script += " ";
- Script += UIntToString(e.Params[j]);
+ s += "Key";
+ if (params[4] & 2)
+ s += " /ifempty";
}
+ AddRegRoot(params[1]);
+ AddParam(params[2]);
+ AddOptionalParam(params[3]);
break;
}
- /*
- case EW_DELREG:
+ case EW_WRITEREG:
{
- AString keyName, valueName;
- keyName = ReadString2(e.Params[1]);
- bool isValue = (e.Params[2] != -1);
- if (isValue)
+ const char *s2 = 0;
+ switch (params[4])
{
- valueName = ReadString2(e.Params[2]);
- Script += "Key";
+ 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
- Script += "Value";
- Script += " ";
- Script += UIntToString(e.Params[0]);
- Script += " ";
- Script += keyName;
- if (isValue)
{
- Script += " ";
- Script += valueName;
+ // 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";
+ }
}
- Script += " ";
- Script += UIntToString(e.Params[3]);
break;
}
- */
- case EW_WRITEREG:
+ 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:
{
- AString s;
- switch(e.Params[4])
+ 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)
{
- case 1: s = "Str"; break;
- case 2: s = "ExpandStr"; break;
- case 3: s = "Bin"; break;
- case 4: s = "DWORD"; break;
- default: s = "?" + UIntToString(e.Params[4]); break;
+ Space();
+ s += cc;
+ break;
}
- Script += s;
- Script += " ";
- Script += GetRegRootID(e.Params[0]);
- Script += " ";
- AString keyName, valueName;
- keyName = ReadString2Qw(e.Params[1]);
- Script += keyName;
- Script += " ";
+ 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";
- valueName = ReadString2Qw(e.Params[2]);
- Script += valueName;
- Script += " ";
+ 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;
+ }
- valueName = ReadString2Qw(e.Params[3]);
- Script += valueName;
- Script += " ";
+ 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_WRITEUNINSTALLER:
+ case EW_FSEEK:
{
- Script += " ";
- Script += ReadString2(e.Params[0]);
- for (int j = 1; j < 3; j++)
+ 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)
{
- Script += " ";
- Script += UIntToString(e.Params[j]);
+ if (params[3] == 0) s += " SET"; // FILE_BEGIN
+ AddParam_Var(params[1]);
}
break;
}
- default:
+ 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:
{
- int numParams = kNumEntryParams;
- if (e.Which < sizeof(kCommandPairs) / sizeof(kCommandPairs[0]))
+ if (params[0] != 0)
{
- const CCommandPair &pair = kCommandPairs[e.Which];
- // Script += pair.Name;
- numParams = pair.NumParams;
+ s += "Set ";
+ s += (params[1] == 0) ? "off" : "on";
}
else
{
- Script += "Unknown";
- Script += UIntToString(e.Which);
+ s += "Text";
+ AddParam(params[1]);
}
- Script += e.GetParamsString(numParams);
+ }
+
+ 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
- Script += kCrLf;
+
+ unsigned numParams = kNumCommandParams;
+
+ for (; numParams > 0; numParams--)
+ if (params[numParams - 1] != 0)
+ break;
+
+ if (numParams > numSkipParams)
+ {
+ s += " ; !!!! Unknown Params: ";
+ unsigned i;
+ for (i = 0; i < numParams; i++)
+ AddParam(params[i]);
+
+ s += " ;";
+
+ for (i = 0; i < numParams; i++)
+ {
+ Space();
+ UInt32 v = params[i];
+ if (v > 0xFFF00000)
+ Add_SignedInt(s, (Int32)v);
+ else
+ Add_UInt(v);
+ }
+ }
+
+ NewLine();
+
#endif
}
+ #ifdef NSIS_SCRIPT
+
+ if (sectionIsOpen)
+ {
+ if (curSectionIndex < bhSections.Num)
+ {
+ const CSection &sect = Sections[curSectionIndex];
+ if (sect.StartCmdIndex + sect.NumCommands + 1 == kkk)
+ {
+ PrintSectionEnd();
+ sectionIsOpen = false;
+ // lastSectionEndCmd = kkk;
+ curSectionIndex++;
+ }
+ }
+ }
+
+ while (curSectionIndex < bhSections.Num)
+ {
+ const CSection &sect = Sections[curSectionIndex];
+ if (sectionIsOpen)
+ {
+ if (sect.StartCmdIndex + sect.NumCommands != kkk)
+ AddErrorLF("SECTION ERROR");
+ PrintSectionEnd();
+ sectionIsOpen = false;
+ curSectionIndex++;
+ }
+ else
+ {
+ if (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(wcscmp(
+ inArchive->UPrefixes[i1.Prefix],
+ inArchive->UPrefixes[i2.Prefix]));
+ }
+ RINOZ(wcscmp(i1.NameU, 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, 0);
- int i;
- // if (IsSolid)
- for (i = 0; i + 1 < Items.Size();)
+ Items.Sort(CompareItems, (void *)this);
+ unsigned i;
+
+ for (i = 0; i + 1 < Items.Size(); i++)
{
- bool sameName = IsUnicode ?
- (Items[i].NameU == Items[i + 1].NameU) :
- (Items[i].NameA == Items[i + 1].NameA);
- if (Items[i].Pos == Items[i + 1].Pos && sameName)
- Items.Delete(i + 1);
+ 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
- i++;
+ {
+ 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 (int nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++)
+ for (unsigned nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++)
{
UInt32 nextPos = Items[nextIndex].Pos;
if (curPos <= nextPos)
{
- item.EstimatedSizeIsDefined = true;
+ item.EstimatedSize_Defined = true;
item.EstimatedSize = nextPos - curPos;
break;
}
}
}
+
if (!IsSolid)
{
for (i = 0; i < Items.Size(); i++)
{
CItem &item = Items[i];
RINOK(_stream->Seek(GetPosOfNonSolidItem(i), STREAM_SEEK_SET, NULL));
- const UInt32 kSigSize = 4 + 1 + 5;
+ 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 & 0x80000000) != 0)
+ if ((size & kMask_IsCompressed) != 0)
{
item.IsCompressed = true;
- // is compressed;
- size &= ~0x80000000;
+ size &= ~kMask_IsCompressed;
if (Method == NMethodType::kLZMA)
{
if (processedSize < 9)
return S_FALSE;
+ /*
if (FilterFlag)
item.UseFilter = (sig[4] != 0);
- item.DictionarySize = Get32(sig + 5 + (FilterFlag ? 1 : 0));
+ */
+ item.DictionarySize = Get32(sig + 4 + 1 + (FilterFlag ? 1 : 0));
}
}
else
{
item.IsCompressed = false;
item.Size = size;
- item.SizeIsDefined = true;
+ item.Size_Defined = true;
}
item.CompressedSize = size;
- item.CompressedSizeIsDefined = true;
+ 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 *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.HeaderLength
- /* UInt32 ehFlags = */ ReadUInt32();
- CBlockHeader bhPages, bhSections, bhEntries, bhStrings, bhLangTables, bhCtlColors, bhData;
- // CBlockHeader bgFont;
- ReadBlockHeader(bhPages);
- ReadBlockHeader(bhSections);
- ReadBlockHeader(bhEntries);
- ReadBlockHeader(bhStrings);
- ReadBlockHeader(bhLangTables);
- ReadBlockHeader(bhCtlColors);
- // ReadBlockHeader(bgFont);
- ReadBlockHeader(bhData);
+ // ???? offset == FirstHeader.HeaderSize
+ const Byte *p = _data;
+
+ 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;
- UInt32 pos = GetOffset() + _stringsPos;
- int numZeros0 = 0;
- int numZeros1 = 0;
- int i;
- const int kBlockSize = 256;
- for (i = 0; i < kBlockSize; i++)
- {
- if (pos >= _size || pos + 1 >= _size)
- break;
- char c0 = _data[pos++];
- char c1 = _data[pos++];
- wchar_t c = (c0 | ((wchar_t)c1 << 8));
+ if (_stringsPos > _size)
+ return S_FALSE;
+ {
+ if (bhLangTables.Offset < bhStrings.Offset)
+ return S_FALSE;
+ 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 (c >= NS_UN_CODES_START && c < NS_UN_CODES_END)
+ }
+
+ if (bhEntries.Num > (1 << 25))
+ return S_FALSE;
+ if (bhEntries.Offset > _size)
+ return S_FALSE;
+ if (bhEntries.Num * kCmdSize > _size - bhEntries.Offset)
+ return S_FALSE;
+
+ DetectNsisType(bhEntries, _data + bhEntries.Offset);
+
+ #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)
{
- if (pos >= _size || pos + 1 >= _size)
- break;
- pos += 2;
- numZeros1++;
+ 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);
+ NewLine();
+ }
+ }
+
+
+ {
+ 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)
+ {
+ 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 + 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)
{
- if (c0 == 0 && c1 != 0)
- numZeros0++;
- if (c1 == 0)
- numZeros1++;
+ 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);
}
- // printf("\nnumZeros0 = %2x %2x", _data[pos + 0], _data[pos + 1]);
+
+ 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();
}
- IsUnicode = (numZeros1 > numZeros0 * 3 + kBlockSize / 16);
- // printf("\nnumZeros0 = %3d numZeros1 = %3d", numZeros0, numZeros1);
- return ReadEntries(bhEntries);
+
+ {
+ 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);
+ 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)
@@ -1276,7 +5545,7 @@ static bool IsLZMA(const Byte *p, UInt32 &dictionary, bool &thereIsFlag)
thereIsFlag = false;
return true;
}
- if (IsLZMA(p + 1, dictionary))
+ if (p[0] <= 1 && IsLZMA(p + 1, dictionary))
{
thereIsFlag = true;
return true;
@@ -1289,92 +5558,131 @@ static bool IsBZip2(const Byte *p)
return (p[0] == 0x31 && p[1] < 14);
}
-HRESULT CInArchive::Open2(
- DECL_EXTERNAL_CODECS_LOC_VARS2
- )
+HRESULT CInArchive::Open2(const Byte *sig, size_t size)
{
- RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &StreamOffset));
-
- const UInt32 kSigSize = 4 + 1 + 5 + 1; // size, flag, lzma props, lzma first byte
- BYTE sig[kSigSize];
- RINOK(ReadStream_FALSE(_stream, sig, kSigSize));
- UInt64 position;
- RINOK(_stream->Seek(StreamOffset, STREAM_SEEK_SET, &position));
+ 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);
- if (compressedHeaderSize == FirstHeader.HeaderLength)
+
+ /*
+ 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 (IsLZMA(sig + 4, DictionarySize, FilterFlag))
- {
- IsSolid = false;
- Method = NMethodType::kLZMA;
- }
else if (sig[3] == 0x80)
{
IsSolid = false;
- if (IsBZip2(sig + 4))
+ 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;
- }
- _posInData = 0;
- if (!IsSolid)
+ if (IsSolid)
+ {
+ RINOK(_stream->Seek(DataStreamOffset, STREAM_SEEK_SET, NULL));
+ }
+ else
{
- _headerIsCompressed = ((compressedHeaderSize & 0x80000000) != 0);
- if (_headerIsCompressed)
- compressedHeaderSize &= ~0x80000000;
+ _headerIsCompressed = ((compressedHeaderSize & kMask_IsCompressed) != 0);
+ compressedHeaderSize &= ~kMask_IsCompressed;
_nonSolidStartOffset = compressedHeaderSize;
- RINOK(_stream->Seek(StreamOffset + 4, STREAM_SEEK_SET, NULL));
+ RINOK(_stream->Seek(DataStreamOffset + 4, STREAM_SEEK_SET, NULL));
}
- UInt32 unpackSize = FirstHeader.HeaderLength;
+
+ _data.Alloc(FirstHeader.HeaderSize);
+ _size = (size_t)FirstHeader.HeaderSize;
+
+ Decoder.Method = Method;
+ Decoder.FilterFlag = FilterFlag;
+ Decoder.Solid = IsSolid;
+ Decoder.InputStream = _stream;
+ Decoder.Buffer.Alloc(kInputBufSize);
+ Decoder.StreamPos = 0;
+
if (_headerIsCompressed)
{
- // unpackSize = (1 << 23);
- _data.SetCapacity(unpackSize);
- RINOK(Decoder.Init(
- EXTERNAL_CODECS_LOC_VARS
- _stream, Method, FilterFlag, UseFilter));
- size_t processedSize = unpackSize;
+ RINOK(Decoder.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 != unpackSize)
+ if (processedSize != FirstHeader.HeaderSize)
return S_FALSE;
- _size = processedSize;
+
+ #ifdef NSIS_SCRIPT
if (IsSolid)
{
- UInt32 size2 = ReadUInt32();
- if (size2 < _size)
- _size = size2;
+ /* 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
{
- _data.SetCapacity(unpackSize);
- _size = (size_t)unpackSize;
- RINOK(ReadStream_FALSE(_stream, (Byte *)_data, unpackSize));
+ 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();
}
@@ -1404,57 +5712,212 @@ FirstHeader
UInt32 Flags;
Byte Signature[16];
// points to the header+sections+entries+stringtable in the datablock
- UInt32 HeaderLength;
- UInt32 ArchiveSize;
+ UInt32 HeaderSize;
+ UInt32 ArcSize;
}
*/
-HRESULT CInArchive::Open(
- DECL_EXTERNAL_CODECS_LOC_VARS
- IInStream *inStream, const UInt64 *maxCheckStartPosition)
+
+// ---------- 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_SET, NULL));
- UInt64 maxSize = ((maxCheckStartPosition != 0) ? *maxCheckStartPosition : 0);
- const UInt32 kStep = 512;
- Byte buffer[kStep];
- UInt64 position = 0;
- for (; position <= maxSize; position += kStep)
+ 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 (;;)
{
- RINOK(ReadStream_FALSE(inStream, buffer, kStep));
- if (memcmp(buffer + 4, kSignature, kSignatureSize) == 0)
+ 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;
+ }
}
- if (position > maxSize)
+
+ DataStreamOffset = pos + kStartHeaderSize;
+ FirstHeader.Flags = Get32(buf);
+ if ((FirstHeader.Flags & (~kFlagsMask)) != 0)
return S_FALSE;
- const UInt32 kStartHeaderSize = 4 * 7;
- RINOK(inStream->Seek(0, STREAM_SEEK_END, &_archiveSize));
- RINOK(inStream->Seek(position + kStartHeaderSize, STREAM_SEEK_SET, 0));
- FirstHeader.Flags = Get32(buffer);
- FirstHeader.HeaderLength = Get32(buffer + kSignatureSize + 4);
- FirstHeader.ArchiveSize = Get32(buffer + kSignatureSize + 8);
- if (_archiveSize - position < FirstHeader.ArchiveSize)
+ 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
{
- _stream = inStream;
- HRESULT res = Open2(EXTERNAL_CODECS_LOC_VARS2);
- if (res != S_OK)
- Clear();
+ 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();
- return res;
+ // Clear();
}
- catch(...) { Clear(); return S_FALSE; }
+ return res;
}
-void CInArchive::Clear()
+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;
+ 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 7ca719e4..3acd9ee5 100755..100644
--- a/CPP/7zip/Archive/Nsis/NsisIn.h
+++ b/CPP/7zip/Archive/Nsis/NsisIn.h
@@ -3,21 +3,28 @@
#ifndef __ARCHIVE_NSIS_IN_H
#define __ARCHIVE_NSIS_IN_H
-#include "Common/Buffer.h"
-#include "Common/MyCom.h"
-#include "Common/StringConvert.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"
-// #define NSIS_SCRIPT
+/* 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 int kSignatureSize = 16;
-#define NSIS_SIGNATURE { 0xEF, 0xBE, 0xAD, 0xDE, 0x4E, 0x75, 0x6C, 0x6C, 0x73, 0x6F, 0x66, 0x74, 0x49, 0x6E, 0x73, 0x74}
+const size_t kScriptSizeLimit = 1 << 27;
-extern Byte kSignature[kSignatureSize];
+const unsigned kSignatureSize = 16;
+#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
@@ -31,18 +38,17 @@ namespace NFlags
struct CFirstHeader
{
UInt32 Flags;
- UInt32 HeaderLength;
-
- UInt32 ArchiveSize;
+ UInt32 HeaderSize;
+ UInt32 ArcSize;
bool ThereIsCrc() const
{
- if ((Flags & NFlags::kForceCrc ) != 0)
- return true;
- return ((Flags & NFlags::kNoCrc) == 0);
+ return
+ (Flags & NFlags::kForceCrc) != 0 ||
+ (Flags & NFlags::kNoCrc) == 0;
}
- UInt32 GetDataSize() const { return ArchiveSize - (ThereIsCrc() ? 4 : 0); }
+ UInt32 GetDataSize() const { return ArcSize - (ThereIsCrc() ? 4 : 0); }
};
@@ -50,123 +56,330 @@ struct CBlockHeader
{
UInt32 Offset;
UInt32 Num;
+
+ void Parse(const Byte *p)
+ {
+ Offset = GetUi32(p);
+ Num = GetUi32(p + 4);
+ }
};
struct CItem
{
- AString PrefixA;
- UString PrefixU;
- AString NameA;
- UString NameU;
- FILETIME MTime;
- bool IsUnicode;
- bool UseFilter;
bool IsCompressed;
- bool SizeIsDefined;
- bool CompressedSizeIsDefined;
- bool EstimatedSizeIsDefined;
+ 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;
-
- CItem(): IsUnicode(false), UseFilter(false), IsCompressed(true), SizeIsDefined(false),
- CompressedSizeIsDefined(false), EstimatedSizeIsDefined(false), Size(0), DictionarySize(1) {}
+ UInt32 PatchSize; // for Uninstaller.exe
+ int Prefix; // - 1 means no prefix
- bool IsINSTDIR() const
+ 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)
{
- return (PrefixA.Length() >= 3 || PrefixU.Length() >= 3);
+ MTime.dwLowDateTime = 0;
+ MTime.dwHighDateTime = 0;
}
- UString GetReducedName(bool unicode) const
+ /*
+ bool IsINSTDIR() const
{
- UString s;
- if (unicode)
- s = PrefixU;
- else
- s = MultiByteToUnicodeString(PrefixA);
- if (s.Length() > 0)
- if (s.Back() != L'\\')
- s += L'\\';
- if (unicode)
- s += NameU;
- else
- s += MultiByteToUnicodeString(NameA);
- const int len = 9;
- if (s.Left(len).CompareNoCase(L"$INSTDIR\\") == 0)
- s = s.Mid(len);
- return s;
+ return (PrefixA.Len() >= 3 || PrefixU.Len() >= 3);
}
+ */
};
-class CInArchive
+enum ENsisType
{
- UInt64 _archiveSize;
- CMyComPtr<IInStream> _stream;
-
- Byte ReadByte();
- UInt32 ReadUInt32();
- HRESULT Open2(
- DECL_EXTERNAL_CODECS_LOC_VARS2
- );
- void ReadBlockHeader(CBlockHeader &bh);
- AString ReadStringA(UInt32 pos) const;
- UString ReadStringU(UInt32 pos) const;
- AString ReadString2A(UInt32 pos) const;
- UString ReadString2U(UInt32 pos) const;
- AString ReadString2(UInt32 pos) const;
- AString ReadString2Qw(UInt32 pos) const;
- HRESULT ReadEntries(const CBlockHeader &bh);
- HRESULT Parse();
+ 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;
- UInt64 _size;
+ CObjectVector<CItem> Items;
+ bool IsUnicode;
+private:
+ UInt32 _stringsPos; // relative to _data
+ UInt32 NumStringChars;
+ size_t _size; // it's Header Size
- size_t _posInData;
+ AString Raw_AString;
+ UString Raw_UString;
- UInt32 _stringsPos;
+ 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<UInt32> langStrIDs;
+ UInt32 numOnFunc;
+ UInt32 onFuncOffset;
+ // CRecordVector<UInt32> OnFuncs;
+ unsigned _numRootLicenses;
+ CRecordVector<UInt32> noParseStringIndexes;
+ AString _tempString_for_GetVar;
+ AString _tempString_for_AddFuncName;
+ AString _tempString;
+
+ #endif
+
+
public:
- HRESULT Open(
- DECL_EXTERNAL_CODECS_LOC_VARS
- IInStream *inStream, const UInt64 *maxCheckStartPosition);
- void Clear();
+ CMyComPtr<IInStream> _stream; // it's limited stream that contains only NSIS archive
+ UInt64 StartOffset; // offset in original stream.
+ UInt64 DataStreamOffset; // = sizeof(FirstHeader) = offset of Header in _stream
+
+ bool IsArc;
- UInt64 StreamOffset;
CDecoder Decoder;
- CObjectVector<CItem> Items;
+ CByteBuffer ExeStub;
CFirstHeader FirstHeader;
NMethodType::EEnum Method;
UInt32 DictionarySize;
bool IsSolid;
bool UseFilter;
bool FilterFlag;
- bool IsUnicode;
+
+ bool IsInstaller;
+ AString Name;
+ AString BrandingText;
+ UStringVector UPrefixes;
+ AStringVector APrefixes;
#ifdef NSIS_SCRIPT
- AString Script;
+ CObjectVector<CLicenseFile> LicenseFiles;
#endif
- UInt32 GetOffset() const { return IsSolid ? 4 : 0; }
- UInt64 GetDataPos(int index)
+
+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 **table, unsigned tableSize, UInt32 type);
+ void Add_ExecFlags(UInt32 flagsType);
+ void Add_SectOp(UInt32 opType);
+
+ void Add_Var(UInt32 index);
+ void AddParam_Var(UInt32 value);
+ void AddParam_UInt(UInt32 value);
+
+ void Add_GotoVar(UInt32 param);
+ void Add_GotoVar1(UInt32 param);
+ void Add_GotoVars2(const UInt32 *params);
+
+
+
+ bool PrintSectionBegin(const CSection &sect, unsigned index);
+ void PrintSectionEnd();
+
+ void GetNsisString(AString &res, const Byte *s);
+ void GetNsisString_Unicode(AString &res, const Byte *s);
+ UInt32 GetNumUsedVars() const;
+ void ReadString2(AString &s, UInt32 pos);
+
+ void MessageBox_MB_Part(UInt32 param);
+ void AddParam(UInt32 pos);
+ void AddOptionalParam(UInt32 pos);
+ void AddParams(const UInt32 *params, unsigned num);
+ void AddPageOption1(UInt32 param, const char *name);
+ void AddPageOption(const UInt32 *params, unsigned num, const char *name);
+ void AddOptionalParams(const UInt32 *params, unsigned num);
+ void AddRegRoot(UInt32 value);
+
+
+ void ClearLangComment();
+ void Separator();
+ void Space();
+ void Tab();
+ void Tab(bool commented);
+ void BigSpaceComment();
+ void SmallSpaceComment();
+ void AddCommentAndString(const char *s);
+ void AddError(const char *s);
+ void AddErrorLF(const char *s);
+ void CommentOpen();
+ void CommentClose();
+ void AddLF();
+ void AddQuotes();
+ void TabString(const char *s);
+ void AddStringLF(const char *s);
+ void NewLine();
+ void PrintNumComment(const char *name, UInt32 value);
+ void Add_QuStr(const AString &s);
+ void SpaceQuStr(const AString &s);
+ bool CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands);
+
+ #endif
+
+ #ifdef NSIS_SCRIPT
+ unsigned GetNumSupportedCommands() const;
+ #endif
+
+ UInt32 GetCmd(UInt32 a);
+ void FindBadCmd(const CBlockHeader &bh, const Byte *);
+ void DetectNsisType(const CBlockHeader &bh, const Byte *);
+
+ HRESULT ReadEntries(const CBlockHeader &bh);
+ HRESULT SortItems();
+ HRESULT Parse();
+ HRESULT Open2(const Byte *data, size_t size);
+ void Clear2();
+
+ void GetVar2(AString &res, UInt32 index);
+ void GetVar(AString &res, UInt32 index);
+ Int32 GetVarIndex(UInt32 strPos) const;
+ Int32 GetVarIndex(UInt32 strPos, UInt32 &resOffset) const;
+ Int32 GetVarIndexFinished(UInt32 strPos, Byte endChar, UInt32 &resOffset) const;
+ bool IsVarStr(UInt32 strPos, UInt32 varIndex) const;
+ bool IsAbsolutePathVar(UInt32 strPos) const;
+ void SetItemName(CItem &item, UInt32 strPos);
+
+public:
+ HRESULT Open(IInStream *inStream, const UInt64 *maxCheckStartPosition);
+ AString GetFormatDescription() const;
+ HRESULT InitDecoder()
+ {
+ bool useFilter;
+ return Decoder.Init(_stream, useFilter);
+ }
+
+ HRESULT SeekTo_DataStreamOffset()
+ {
+ return _stream->Seek(DataStreamOffset, STREAM_SEEK_SET, NULL);
+ }
+
+ HRESULT SeekToNonSolidItem(unsigned index)
+ {
+ return _stream->Seek(GetPosOfNonSolidItem(index), STREAM_SEEK_SET, NULL);
+ }
+
+ void Clear();
+
+ bool IsDirectString_Equal(UInt32 offset, const char *s) const;
+ /*
+ UInt64 GetDataPos(unsigned index)
{
const CItem &item = Items[index];
- return GetOffset() + FirstHeader.HeaderLength + item.Pos;
+ return GetOffset() + FirstHeader.HeaderSize + item.Pos;
}
+ */
- UInt64 GetPosOfSolidItem(int index) const
+ UInt64 GetPosOfSolidItem(unsigned index) const
{
const CItem &item = Items[index];
- return 4 + FirstHeader.HeaderLength + item.Pos;
+ return 4 + (UInt64)FirstHeader.HeaderSize + item.Pos;
}
- UInt64 GetPosOfNonSolidItem(int index) const
+ UInt64 GetPosOfNonSolidItem(unsigned index) const
{
const CItem &item = Items[index];
- return StreamOffset + _nonSolidStartOffset + 4 + item.Pos;
+ return DataStreamOffset + _nonSolidStartOffset + 4 + item.Pos;
}
void Release()
@@ -174,6 +387,52 @@ public:
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 += L'\\';
+ }
+
+ if (IsUnicode)
+ {
+ s += item.NameU;
+ if (item.NameU.IsEmpty())
+ s += L"file";
+ }
+ else
+ {
+ s += MultiByteToUnicodeString(item.NameA);
+ if (item.NameA.IsEmpty())
+ s += L"file";
+ }
+
+ const char *kRemoveStr = "$INSTDIR\\";
+ if (s.IsPrefixedBy_Ascii_NoCase(kRemoveStr))
+ s.Delete(0, MyStringLen(kRemoveStr));
+ if (item.IsUninstaller && ExeStub.Size() == 0)
+ s += L".nsis";
+ return s;
+ }
+
+ UString ConvertToUnicode(const AString &s) const;
+
+ CInArchive()
+ #ifdef NSIS_SCRIPT
+ : Script(kScriptSizeLimit)
+ #endif
+ {}
};
}}
diff --git a/CPP/7zip/Archive/Nsis/NsisRegister.cpp b/CPP/7zip/Archive/Nsis/NsisRegister.cpp
index 41dedb0d..b363bdec 100755..100644
--- a/CPP/7zip/Archive/Nsis/NsisRegister.cpp
+++ b/CPP/7zip/Archive/Nsis/NsisRegister.cpp
@@ -5,9 +5,20 @@
#include "../../Common/RegisterArc.h"
#include "NsisHandler.h"
-static IInArchive *CreateArc() { return new NArchive::NNsis::CHandler; }
+
+namespace NArchive {
+namespace NNsis {
+
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"Nsis", L"", 0, 0x9, NSIS_SIGNATURE, NArchive::NNsis::kSignatureSize, false, CreateArc, 0 };
+ { "Nsis", "nsis", 0, 0x9,
+ NArchive::NNsis::kSignatureSize, NSIS_SIGNATURE,
+ 4,
+ NArcInfoFlags::kFindSignature |
+ NArcInfoFlags::kUseGlobalOffset,
+ CreateArc };
REGISTER_ARC(Nsis)
+
+}}
diff --git a/CPP/7zip/Archive/Nsis/StdAfx.h b/CPP/7zip/Archive/Nsis/StdAfx.h
index 2e4be10b..2854ff3e 100755..100644
--- a/CPP/7zip/Archive/Nsis/StdAfx.h
+++ b/CPP/7zip/Archive/Nsis/StdAfx.h
@@ -3,7 +3,6 @@
#ifndef __STDAFX_H
#define __STDAFX_H
-#include "../../../Common/MyWindows.h"
-#include "../../../Common/NewHandler.h"
+#include "../../../Common/Common.h"
#endif
diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp
index 505486fc..dfe5eade 100755..100644
--- a/CPP/7zip/Archive/NtfsHandler.cpp
+++ b/CPP/7zip/Archive/NtfsHandler.cpp
@@ -11,15 +11,15 @@
#include "../../../C/CpuArch.h"
-#include "Common/Buffer.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/MyCom.h"
-#include "Common/StringConvert.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyCom.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
+#include "../Common/MethodProps.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamUtils.h"
@@ -30,8 +30,10 @@
#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
@@ -48,26 +50,36 @@
#define G32(p, dest) dest = Get32(p);
#define G64(p, dest) dest = Get64(p);
+using namespace NWindows;
+
namespace NArchive {
namespace Ntfs {
-static const UInt32 kNumSysRecs = 16;
-static const UInt32 kRecIndex_Volume = 3;
-static const UInt32 kRecIndex_BadClus = 8;
+static const wchar_t *kVirtualFolder_System = L"[SYSTEM]";
+static const wchar_t *kVirtualFolder_Lost_Normal = L"[LOST]";
+static const wchar_t *kVirtualFolder_Lost_Deleted = L"[UNKNOWN]";
+
+static const unsigned kNumSysRecs = 16;
+
+static const unsigned kRecIndex_Volume = 3;
+static const unsigned kRecIndex_BadClus = 8;
+static const unsigned kRecIndex_Security = 9;
struct CHeader
{
- Byte SectorSizeLog;
- Byte ClusterSizeLog;
+ unsigned SectorSizeLog;
+ unsigned ClusterSizeLog;
// Byte MediaType;
UInt32 NumHiddenSectors;
+ UInt64 NumSectors;
UInt64 NumClusters;
UInt64 MftCluster;
UInt64 SerialNumber;
UInt16 SectorsPerTrack;
UInt16 NumHeads;
- UInt64 GetPhySize() const { return NumClusters << ClusterSizeLog; }
+ 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);
};
@@ -89,35 +101,38 @@ bool CHeader::Parse(const Byte *p)
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;
+ case 0xEB: if (p[2] != 0x90) return false; codeOffset = 2 + (int)(signed char)p[1]; break;
default: return false;
}
- Byte sectorsPerClusterLog;
+ unsigned sectorsPerClusterLog;
if (memcmp(p + 3, "NTFS ", 8) != 0)
return false;
{
- int s = GetLog(Get16(p + 11));
- if (s < 9 || s > 12)
+ int t = GetLog(Get16(p + 11));
+ if (t < 9 || t > 12)
return false;
- SectorSizeLog = (Byte)s;
- s = GetLog(p[13]);
- if (s < 0)
+ SectorSizeLog = t;
+ t = GetLog(p[13]);
+ if (t < 0)
return false;
- sectorsPerClusterLog = (Byte)s;
+ sectorsPerClusterLog = t;
ClusterSizeLog = SectorSizeLog + sectorsPerClusterLog;
+ if (ClusterSizeLog > 30)
+ return false;
}
for (int i = 14; i < 21; i++)
if (p[i] != 0)
return false;
- // MediaType = p[21];
+ if (p[21] != 0xF8) // MediaType = Fixed_Disk
+ return false;
if (Get16(p + 22) != 0) // NumFatSectors
return false;
- G16(p + 24, SectorsPerTrack);
- G16(p + 26, NumHeads);
- G32(p + 28, NumHiddenSectors);
+ 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;
@@ -132,15 +147,19 @@ bool CHeader::Parse(const Byte *p)
return false;
if (p[0x27] != 0) // reserved
return false;
- UInt64 numSectors = Get64(p + 0x28);
- NumClusters = numSectors >> sectorsPerClusterLog;
+
+ 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);
+ G32(p + 0x40, numClustersInMftRec); // -10 means 2 ^10 = 1024 bytes.
G32(p + 0x44, numClustersInIndexBlock);
return (numClustersInMftRec < 256 && numClustersInIndexBlock < 256);
}
@@ -148,6 +167,7 @@ bool CHeader::Parse(const Byte *p)
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; }
@@ -178,17 +198,19 @@ enum
DEF_ATTR_TYPE(0x1000, FIRST_USER_DEFINED_ATTRIBUTE)
};
-static const Byte kFileNameType_Posix = 0;
-static const Byte kFileNameType_Win32 = 1;
-static const Byte kFileNameType_Dos = 2;
-static const Byte kFileNameType_Win32Dos = 3;
+static const Byte kFileNameType_Posix = 0;
+static const Byte kFileNameType_Win32 = 1;
+static const Byte kFileNameType_Dos = 2;
+static const Byte kFileNameType_Win32Dos = 3;
struct CFileNameAttr
{
CMftRef ParentDirRef;
+
+ // Probably these timestamps don't contain some useful timestamps. So we don't use them
// UInt64 CTime;
// UInt64 MTime;
- // UInt64 ThisRecMTime;
+ // UInt64 ThisRecMTime; // xp-64: the time of previous name change (not last name change. why?)
// UInt64 ATime;
// UInt64 AllocatedSize;
// UInt64 DataSize;
@@ -201,12 +223,12 @@ struct CFileNameAttr
bool Parse(const Byte *p, unsigned size);
};
-static void GetString(const Byte *p, unsigned length, UString &res)
+static void GetString(const Byte *p, unsigned len, UString &res)
{
- wchar_t *s = res.GetBuffer(length);
- for (unsigned i = 0; i < length; i++)
+ wchar_t *s = res.GetBuffer(len);
+ for (unsigned i = 0; i < len; i++)
s[i] = Get16(p + i * 2);
- s[length] = 0;
+ s[len] = 0;
res.ReleaseBuffer();
}
@@ -224,10 +246,10 @@ bool CFileNameAttr::Parse(const Byte *p, unsigned size)
G32(p + 0x38, Attrib);
// G16(p + 0x3C, PackedEaSize);
NameType = p[0x41];
- unsigned length = p[0x40];
- if (0x42 + length > size)
+ unsigned len = p[0x40];
+ if (0x42 + len > size)
return false;
- GetString(p + 0x42, length, Name);
+ GetString(p + 0x42, len, Name);
return true;
}
@@ -244,9 +266,9 @@ struct CSiAttr
UInt32 Version;
UInt32 ClassId;
UInt32 OwnerId;
- UInt32 SecurityId;
- UInt64 QuotaCharged;
*/
+ UInt32 SecurityId; // SecurityId = 0 is possible ?
+ // UInt64 QuotaCharged;
bool Parse(const Byte *p, unsigned size);
};
@@ -260,6 +282,9 @@ bool CSiAttr::Parse(const Byte *p, unsigned size)
// G64(p + 0x10, ThisRecMTime);
G64(p + 0x18, ATime);
G32(p + 0x20, Attrib);
+ SecurityId = 0;
+ if (size >= 0x38)
+ G32(p + 0x34, SecurityId);
return true;
}
@@ -295,7 +320,7 @@ bool CVolInfo::Parse(const Byte *p, unsigned size)
struct CAttr
{
UInt32 Type;
- // UInt32 Length;
+ // UInt32 Len;
UString Name;
// UInt16 Flags;
// UInt16 Instance;
@@ -317,15 +342,15 @@ struct CAttr
bool IsCompressionUnitSupported() const { return CompressionUnit == 0 || CompressionUnit == 4; }
UInt32 Parse(const Byte *p, unsigned size);
- bool ParseFileName(CFileNameAttr &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); }
- bool ParseSi(CSiAttr &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); }
- bool ParseVolInfo(CVolInfo &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); }
- bool ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, int compressionUnit) const;
- UInt64 GetSize() const { return NonResident ? Size : Data.GetCapacity(); }
+ bool ParseFileName(CFileNameAttr &a) const { return a.Parse(Data, (unsigned)Data.Size()); }
+ bool ParseSi(CSiAttr &a) const { return a.Parse(Data, (unsigned)Data.Size()); }
+ bool ParseVolInfo(CVolInfo &a) const { return a.Parse(Data, (unsigned)Data.Size()); }
+ bool ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, unsigned compressionUnit) const;
+ UInt64 GetSize() const { return NonResident ? Size : Data.Size(); }
UInt64 GetPackSize() const
{
if (!NonResident)
- return Data.GetCapacity();
+ return Data.Size();
if (CompressionUnit != 0)
return PackSize;
return AllocatedSize;
@@ -339,7 +364,7 @@ static int CompareAttr(void *const *elem1, void *const *elem2, void *)
const CAttr &a1 = *(*((const CAttr **)elem1));
const CAttr &a2 = *(*((const CAttr **)elem2));
RINOZ(MyCompare(a1.Type, a2.Type));
- RINOZ(MyCompare(a1.Name, a2.Name));
+ RINOZ(wcscmp(a1.Name, a2.Name));
return MyCompare(a1.LowVcn, a2.LowVcn);
}
@@ -349,25 +374,28 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size)
return 0;
G32(p, Type);
if (Type == 0xFFFFFFFF)
- return 4;
+ 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 length = Get32(p + 0x04);
- PRF(printf(" L=%3d", length));
- if (length > size)
+ UInt32 len = Get32(p + 0x04);
+ PRF(printf(" L=%3d", len));
+ if (len > size)
+ return 0;
+ if ((len & 7) != 0)
return 0;
NonResident = p[0x08];
{
- int nameLength = p[9];
+ unsigned nameLength = p[9];
UInt32 nameOffset = Get16(p + 0x0A);
if (nameLength != 0)
{
- if (nameOffset + nameLength * 2 > length)
+ if (nameOffset + nameLength * 2 > len)
return 0;
GetString(p + nameOffset, nameLength, Name);
- PRF(printf(" N=%S", Name));
+ PRF(printf(" N="));
+ PRF_UTF16(Name);
}
}
@@ -380,7 +408,7 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size)
UInt32 offs;
if (NonResident)
{
- if (length < 0x40)
+ if (len < 0x40)
return 0;
PRF(printf(" NR"));
G64(p + 0x10, LowVcn);
@@ -394,7 +422,7 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size)
PackSize = Size;
if (CompressionUnit != 0)
{
- if (length < 0x48)
+ if (len < 0x48)
return 0;
G64(p + 0x40, PackSize);
PRF(printf(" PS=%I64x", PackSize));
@@ -406,12 +434,12 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size)
PRF(printf(" IS=%I64d", InitializedSize));
PRF(printf(" Low=%I64d", LowVcn));
PRF(printf(" High=%I64d", HighVcn));
- PRF(printf(" CU=%d", (int)CompressionUnit));
- dataSize = length - offs;
+ PRF(printf(" CU=%d", (unsigned)CompressionUnit));
+ dataSize = len - offs;
}
else
{
- if (length < 0x18)
+ if (len < 0x18)
return 0;
PRF(printf(" RES"));
dataSize = Get32(p + 0x10);
@@ -420,24 +448,23 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size)
// G16(p + 0x16, ResidentFlags);
// PRF(printf(" ResFlags=%4X", ResidentFlags));
}
- if (offs > length || dataSize > length || length - dataSize < offs)
+ if (offs > len || dataSize > len || len - dataSize < offs)
return 0;
- Data.SetCapacity(dataSize);
- memcpy(Data, p + offs, dataSize);
+ Data.CopyFrom(p + offs, dataSize);
#ifdef SHOW_DEBUG_INFO
PRF(printf(" : "));
- for (unsigned i = 0; i < Data.GetCapacity(); i++)
+ for (unsigned i = 0; i < Data.Size(); i++)
{
- PRF(printf(" %02X", (int)Data[i]));
+ PRF(printf(" %02X", (unsigned)Data[i]));
}
#endif
- return length;
+ return len;
}
-bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, int compressionUnit) const
+bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, unsigned compressionUnit) const
{
const Byte *p = Data;
- unsigned size = (unsigned)Data.GetCapacity();
+ unsigned size = (unsigned)Data.Size();
UInt64 vcn = LowVcn;
UInt64 lcn = 0;
UInt64 highVcn1 = HighVcn + 1;
@@ -504,8 +531,8 @@ bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax,
static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
-static const int kNumCacheChunksLog = 1;
-static const UInt32 kNumCacheChunks = (1 << kNumCacheChunksLog);
+static const unsigned kNumCacheChunksLog = 1;
+static const size_t kNumCacheChunks = (1 << kNumCacheChunksLog);
class CInStream:
public IInStream,
@@ -518,32 +545,32 @@ class CInStream:
size_t _compressedPos;
UInt64 _tags[kNumCacheChunks];
- int _chunkSizeLog;
+ unsigned _chunkSizeLog;
CByteBuffer _inBuf;
CByteBuffer _outBuf;
public:
CMyComPtr<IInStream> Stream;
UInt64 Size;
UInt64 InitializedSize;
- int BlockSizeLog;
- int CompressionUnit;
+ unsigned BlockSizeLog;
+ unsigned CompressionUnit;
bool InUse;
CRecordVector<CExtent> Extents;
HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }
UInt32 GetCuSize() const { return (UInt32)1 << (BlockSizeLog + CompressionUnit); }
- HRESULT InitAndSeek(int compressionUnit)
+ HRESULT InitAndSeek(unsigned compressionUnit)
{
CompressionUnit = compressionUnit;
if (compressionUnit != 0)
{
UInt32 cuSize = GetCuSize();
- _inBuf.SetCapacity(cuSize);
+ _inBuf.Alloc(cuSize);
_chunkSizeLog = BlockSizeLog + CompressionUnit;
- _outBuf.SetCapacity(kNumCacheChunks << _chunkSizeLog);
+ _outBuf.Alloc(kNumCacheChunks << _chunkSizeLog);
}
- for (int i = 0; i < kNumCacheChunks; i++)
+ for (size_t i = 0; i < kNumCacheChunks; i++)
_tags[i] = kEmptyTag;
_sparseMode = false;
@@ -683,10 +710,10 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
UInt64 virtBlock = _virtPos >> BlockSizeLog;
UInt64 virtBlock2 = virtBlock & ~((UInt64)comprUnitSize - 1);
- int left = 0, right = Extents.Size();
+ unsigned left = 0, right = Extents.Size();
for (;;)
{
- int mid = (left + right) / 2;
+ unsigned mid = (left + right) / 2;
if (mid == left)
break;
if (virtBlock2 < Extents[mid].Virt)
@@ -698,7 +725,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
bool isCompressed = false;
UInt64 virtBlock2End = virtBlock2 + comprUnitSize;
if (CompressionUnit != 0)
- for (int i = left; i < Extents.Size(); i++)
+ for (unsigned i = left; i < Extents.Size(); i++)
{
const CExtent &e = Extents[i];
if (e.Virt >= virtBlock2End)
@@ -710,7 +737,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
}
}
- int i;
+ unsigned i;
for (i = left; Extents[i + 1].Virt <= virtBlock; i++);
_sparseMode = false;
@@ -733,7 +760,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
break;
}
bool thereArePhy = false;
- for (int i2 = left; i2 < Extents.Size(); i2++)
+ for (unsigned i2 = left; i2 < Extents.Size(); i2++)
{
const CExtent &e = Extents[i2];
if (e.Virt >= virtBlock2End)
@@ -812,19 +839,22 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
STDMETHODIMP CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
{
- UInt64 newVirtPos = offset;
- switch(seekOrigin)
+ switch (seekOrigin)
{
case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: newVirtPos += _virtPos; break;
- case STREAM_SEEK_END: newVirtPos += Size; break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += Size; break;
default: return STG_E_INVALIDFUNCTION;
}
- if (_virtPos != newVirtPos)
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ if (_virtPos != (UInt64)offset)
+ {
_curRem = 0;
- _virtPos = newVirtPos;
+ _virtPos = offset;
+ }
if (newPosition)
- *newPosition = newVirtPos;
+ *newPosition = offset;
return S_OK;
}
@@ -847,9 +877,9 @@ STDMETHODIMP CByteBufStream::Read(void *data, UInt32 size, UInt32 *processedSize
{
if (processedSize != NULL)
*processedSize = 0;
- if (_virtPos >= Buf.GetCapacity())
- return (_virtPos == Buf.GetCapacity()) ? S_OK: E_FAIL;
- UInt64 rem = Buf.GetCapacity() - _virtPos;
+ if (_virtPos >= Buf.Size())
+ return (_virtPos == Buf.Size()) ? S_OK: E_FAIL;
+ UInt64 rem = Buf.Size() - _virtPos;
if (rem < size)
size = (UInt32)rem;
memcpy(data, Buf + (size_t)_virtPos, size);
@@ -861,20 +891,23 @@ STDMETHODIMP CByteBufStream::Read(void *data, UInt32 size, UInt32 *processedSize
STDMETHODIMP CByteBufStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
{
- switch(seekOrigin)
+ switch (seekOrigin)
{
- case STREAM_SEEK_SET: _virtPos = offset; break;
- case STREAM_SEEK_CUR: _virtPos += offset; break;
- case STREAM_SEEK_END: _virtPos = Buf.GetCapacity() + offset; break;
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += Buf.Size(); break;
default: return STG_E_INVALIDFUNCTION;
}
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = offset;
if (newPosition)
- *newPosition = _virtPos;
+ *newPosition = offset;
return S_OK;
}
-static HRESULT DataParseExtents(int clusterSizeLog, const CObjectVector<CAttr> &attrs,
- int attrIndex, int attrIndexLim, UInt64 numPhysClusters, CRecordVector<CExtent> &Extents)
+static HRESULT DataParseExtents(unsigned clusterSizeLog, const CObjectVector<CAttr> &attrs,
+ unsigned attrIndex, unsigned attrIndexLim, UInt64 numPhysClusters, CRecordVector<CExtent> &Extents)
{
CExtent e;
e.Virt = 0;
@@ -887,12 +920,12 @@ static HRESULT DataParseExtents(int clusterSizeLog, const CObjectVector<CAttr> &
(attr0.AllocatedSize & ((1 << clusterSizeLog) - 1)) != 0)
return S_FALSE;
- for (int i = attrIndex; i < attrIndexLim; i++)
+ for (unsigned i = attrIndex; i < attrIndexLim; i++)
if (!attrs[i].ParseExtents(Extents, numPhysClusters, attr0.CompressionUnit))
return S_FALSE;
UInt64 packSizeCalc = 0;
- for (int k = 0; k < Extents.Size(); k++)
+ FOR_VECTOR (k, Extents)
{
CExtent &e = Extents[k];
if (!e.IsEmpty())
@@ -916,18 +949,18 @@ static HRESULT DataParseExtents(int clusterSizeLog, const CObjectVector<CAttr> &
struct CDataRef
{
- int Start;
- int Num;
+ unsigned Start;
+ unsigned Num;
};
-static const UInt32 kMagic_FILE = 0x454c4946;
+static const UInt32 kMagic_FILE = 0x454C4946;
static const UInt32 kMagic_BAAD = 0x44414142;
struct CMftRec
{
UInt32 Magic;
// UInt64 Lsn;
- UInt16 SeqNumber;
+ UInt16 SeqNumber; // Number of times this mft record has been reused
UInt16 Flags;
// UInt16 LinkCount;
// UInt16 NextAttrInstance;
@@ -938,8 +971,18 @@ struct CMftRec
CObjectVector<CAttr> DataAttrs;
CObjectVector<CFileNameAttr> FileNames;
CRecordVector<CDataRef> DataRefs;
+ // CAttr SecurityAttr;
CSiAttr SiAttr;
+
+ CByteBuffer ReparseData;
+
+ bool IsAltStream(int dataIndex) const
+ {
+ return dataIndex >= 0 && (
+ (IsDir() ||
+ !DataAttrs[DataRefs[dataIndex].Start].Name.IsEmpty()));
+ }
void MoveAttrsFrom(CMftRec &src)
{
@@ -952,12 +995,12 @@ struct CMftRec
UInt64 GetPackSize() const
{
UInt64 res = 0;
- for (int i = 0; i < DataRefs.Size(); i++)
+ FOR_VECTOR (i, DataRefs)
res += DataAttrs[DataRefs[i].Start].GetPackSize();
return res;
}
- bool Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNumber, CObjectVector<CAttr> *attrs);
+ bool Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 recNumber, CObjectVector<CAttr> *attrs);
bool IsEmpty() const { return (Magic <= 2); }
bool IsFILE() const { return (Magic == kMagic_FILE); }
@@ -968,10 +1011,10 @@ struct CMftRec
void ParseDataNames();
HRESULT GetStream(IInStream *mainStream, int dataIndex,
- int clusterSizeLog, UInt64 numPhysClusters, IInStream **stream) const;
- int GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClusters) const;
+ unsigned clusterSizeLog, UInt64 numPhysClusters, IInStream **stream) const;
+ unsigned GetNumExtents(int dataIndex, unsigned clusterSizeLog, UInt64 numPhysClusters) const;
- UInt64 GetSize(int dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); }
+ UInt64 GetSize(unsigned dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); }
CMftRec(): MyNumNameLinks(0) {}
};
@@ -981,7 +1024,7 @@ void CMftRec::ParseDataNames()
DataRefs.Clear();
DataAttrs.Sort(CompareAttr, 0);
- for (int i = 0; i < DataAttrs.Size();)
+ for (unsigned i = 0; i < DataAttrs.Size();)
{
CDataRef ref;
ref.Start = i;
@@ -994,7 +1037,7 @@ void CMftRec::ParseDataNames()
}
HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex,
- int clusterSizeLog, UInt64 numPhysClusters, IInStream **destStream) const
+ unsigned clusterSizeLog, UInt64 numPhysClusters, IInStream **destStream) const
{
*destStream = 0;
CByteBufStream *streamSpec = new CByteBufStream;
@@ -1003,11 +1046,11 @@ HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex,
if (dataIndex < 0)
return E_FAIL;
- if (dataIndex < DataRefs.Size())
+ if ((unsigned)dataIndex < DataRefs.Size())
{
const CDataRef &ref = DataRefs[dataIndex];
- int numNonResident = 0;
- int i;
+ unsigned numNonResident = 0;
+ unsigned i;
for (i = ref.Start; i < ref.Start + ref.Num; i++)
if (DataAttrs[i].NonResident)
numNonResident++;
@@ -1037,14 +1080,14 @@ HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex,
return S_OK;
}
-int CMftRec::GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClusters) const
+unsigned CMftRec::GetNumExtents(int dataIndex, unsigned clusterSizeLog, UInt64 numPhysClusters) const
{
if (dataIndex < 0)
return 0;
{
const CDataRef &ref = DataRefs[dataIndex];
- int numNonResident = 0;
- int i;
+ unsigned numNonResident = 0;
+ unsigned i;
for (i = ref.Start; i < ref.Start + ref.Num; i++)
if (DataAttrs[i].NonResident)
numNonResident++;
@@ -1060,36 +1103,49 @@ int CMftRec::GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClus
return 0; // error;
return extents.Size() - 1;
}
- // if (attr0.Data.GetCapacity() != 0)
+ // if (attr0.Data.Size() != 0)
// return 1;
return 0;
}
}
-bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNumber,
+bool CMftRec::Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 recNumber,
CObjectVector<CAttr> *attrs)
{
G32(p, Magic);
if (!IsFILE())
return IsEmpty() || IsBAAD();
- UInt32 usaOffset;
- UInt32 numUsaItems;
- G16(p + 0x04, usaOffset);
- G16(p + 0x06, numUsaItems);
- if ((usaOffset & 1) != 0 || usaOffset + numUsaItems * 2 > ((UInt32)1 << sectorSizeLog) - 2 ||
- numUsaItems == 0 || numUsaItems - 1 != numSectors)
- return false;
-
- UInt16 usn = Get16(p + usaOffset);
- // PRF(printf("\nusn = %d", usn));
- for (UInt32 i = 1; i < numUsaItems; i++)
{
- void *pp = p + (i << sectorSizeLog) - 2;
- if (Get16(pp) != usn)
+ 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;
- SetUi16(pp, Get16(p + usaOffset + i * 2));
+
+ if (usaOffset >= 0x30) // NTFS 3.1+
+ if (Get32(p + 0x2C) != recNumber)
+ 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);
@@ -1109,28 +1165,36 @@ bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNum
// return false; // Check it;
}
// G16(p + 0x28, NextAttrInstance);
- if (usaOffset >= 0x30)
- if (Get32(p + 0x2C) != recNumber) // NTFS 3.1+
- return false;
UInt32 limit = numSectors << sectorSizeLog;
- if (attrOffs >= limit || (attrOffs & 7) != 0 || bytesInUse > limit
+ if (attrOffs >= limit
+ || (attrOffs & 7) != 0
+ || (bytesInUse & 7) != 0
+ || bytesInUse > limit
|| bytesAlloc != limit)
return false;
+ limit = bytesInUse;
- for (UInt32 t = attrOffs; t < limit;)
+ for (UInt32 t = attrOffs;;)
{
+ if (t >= limit)
+ return false;
+
CAttr attr;
// PRF(printf("\n %2d:", Attrs.Size()));
PRF(printf("\n"));
- UInt32 length = attr.Parse(p + t, limit - t);
- if (length == 0 || limit - t < length)
+ UInt32 len = attr.Parse(p + t, limit - t);
+ if (len == 0 || limit - t < len)
return false;
- t += length;
+ t += len;
if (attr.Type == 0xFFFFFFFF)
+ {
+ if (t != limit)
+ return false;
break;
- switch(attr.Type)
+ }
+ switch (attr.Type)
{
case ATTR_TYPE_FILE_NAME:
{
@@ -1138,8 +1202,8 @@ bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNum
if (!attr.ParseFileName(fna))
return false;
FileNames.Add(fna);
- PRF(printf(" flags = %4x", (int)fna.NameType));
- PRF(printf("\n %S", fna.Name));
+ PRF(printf(" flags = %4x\n ", (int)fna.NameType));
+ PRF_UTF16(fna.Name);
break;
}
case ATTR_TYPE_STANDARD_INFO:
@@ -1149,6 +1213,14 @@ bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNum
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);
@@ -1161,49 +1233,99 @@ bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNum
struct CItem
{
- int RecIndex;
- int DataIndex;
- CMftRef ParentRef;
- UString Name;
- UInt32 Attrib;
-
- bool IsDir() const { return (DataIndex < 0); }
+ unsigned RecIndex; // index in Recs array
+ unsigned NameIndex; // index in CMftRec::FileNames
+
+ int DataIndex; /* index in CMftRec::DataRefs
+ -1: for folders
+ -1: for files that have no DATA_ATRIBUTE */
+
+ 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
+ -1: if there is no Host item */
+
+ CItem(): DataIndex(-1), ParentFolder(-1), ParentHost(-1) {}
+
+ bool IsDir() const { return DataIndex < 0; }
+ // check it !!!
+ // probably NTFS for empty file still creates empty DATA_ATTRIBUTE
+ // But it doesn't do it for $Secure:$SDS
};
struct CDatabase
{
- CHeader Header;
- CObjectVector<CItem> Items;
+ CRecordVector<CItem> Items;
CObjectVector<CMftRec> Recs;
CMyComPtr<IInStream> InStream;
+ CHeader Header;
+ unsigned RecSizeLog;
+ UInt64 PhySize;
+
IArchiveOpenCallback *OpenCallback;
CByteBuffer ByteBuf;
CObjectVector<CAttr> VolAttrs;
+ CByteBuffer SecurData;
+ CRecordVector<size_t> SecurOffsets;
+
+ bool _showSystemFiles;
+ bool _showDeletedFiles;
+ UStringVector VirtFolderNames;
+ 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();
- UString GetItemPath(Int32 index) const;
+ void GetItemPath(unsigned index, NCOM::CPropVariant &path) const;
HRESULT Open();
- HRESULT ReadDir(Int32 parent, UInt32 cluster, int level);
HRESULT SeekToCluster(UInt64 cluster);
- int FindMtfRec(const CMftRef &ref) const
+ int FindDirItemForMtfRec(UInt64 recIndex) const
{
- UInt64 val = ref.GetIndex();
- int left = 0, right = Items.Size();
+ if (recIndex >= Recs.Size())
+ return -1;
+ const CMftRec &rec = Recs[(unsigned)recIndex];
+ if (!rec.IsDir())
+ return -1;
+ unsigned left = 0, right = Items.Size();
while (left != right)
{
- int mid = (left + right) / 2;
- UInt64 midValue = Items[mid].RecIndex;
- if (val == midValue)
- return mid;
- if (val < midValue)
+ unsigned mid = (left + right) / 2;
+ const CItem &item = Items[mid];
+ UInt64 midValue = item.RecIndex;
+ if (recIndex == midValue)
+ {
+ // if (!item.IsAltStream)
+ // if (!rec.IsAltStream(item.DataIndex))
+ if (item.DataIndex < 0)
+ return mid;
+ right = mid;
+ }
+ else if (recIndex < midValue)
right = mid;
else
left = mid + 1;
@@ -1211,6 +1333,19 @@ struct CDatabase
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)
@@ -1222,6 +1357,15 @@ 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()
@@ -1232,55 +1376,273 @@ void CDatabase::ClearAndClose()
#define MY_DIR_PREFIX(x) L"[" x L"]" WSTRING_PATH_SEPARATOR
-UString CDatabase::GetItemPath(Int32 index) const
+void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const
{
const CItem *item = &Items[index];
- UString name = item->Name;
- for (int j = 0; j < 256; j++)
- {
- CMftRef ref = item->ParentRef;
- index = FindMtfRec(ref);
- if (ref.GetIndex() == 5)
- return name;
- if (index < 0 || Recs[Items[index].RecIndex].SeqNumber != ref.GetNumber())
- return MY_DIR_PREFIX(L"UNKNOWN") + name;
- item = &Items[index];
- name = item->Name + WCHAR_PATH_SEPARATOR + name;
- }
- return MY_DIR_PREFIX(L"BAD") + name;
+ unsigned size = 0;
+ const CMftRec &rec = Recs[item->RecIndex];
+ size += rec.FileNames[item->NameIndex].Name.Len();
+
+ bool isAltStream = rec.IsAltStream(item->DataIndex);
+ if (isAltStream)
+ {
+ const CAttr &data = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start];
+ size += data.Name.Len();
+ size++;
+ }
+
+ /*
+ if (item->ParentHost >= 0)
+ {
+ item = &Items[item->ParentHost];
+ size += item->Name.Len() + 1;
+ }
+ */
+
+ for (unsigned i = 0;; i++)
+ {
+ if (i > 256)
+ {
+ path = "[TOO-LONG]";
+ return;
+ }
+ const wchar_t *servName;
+ if (item->RecIndex < kNumSysRecs)
+ 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 == -2) ?
+ 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 UString &name = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start].Name;
+ size -= name.Len();
+ MyStringCopy(s + size, (const wchar_t *)name);
+ s[--size] = ':';
+ needColon = true;
+ }
+
+ {
+ const UString &name = rec.FileNames[item->NameIndex].Name;
+ unsigned len = name.Len();
+ MyStringCopy(s + size - len, (const wchar_t *)name);
+ if (needColon)
+ s[size] = ':';
+ size -= len;
+ }
+
+ /*
+ {
+ unsigned len = item->Name.Len();
+ size -= len;
+ MyStringCopy(s + size, (const wchar_t *)item->Name);
+ }
+ */
+
+
+ /*
+ if (item->ParentHost >= 0)
+ {
+ item = &Items[item->ParentHost];
+ unsigned len = item->Name.Len();
+ size--;
+ size -= len;
+ MyStringCopy(s + size, (const wchar_t *)item->Name);
+ s[size + len] = ':';
+ }
+ */
+
+ for (;;)
+ {
+ const wchar_t *servName;
+ if (item->RecIndex < kNumSysRecs)
+ servName = kVirtualFolder_System;
+ else
+ {
+ int index2 = item->ParentFolder;
+ if (index2 >= 0)
+ {
+ item = &Items[index2];
+ const UString &name = Recs[item->RecIndex].FileNames[item->NameIndex].Name;
+ unsigned len = name.Len();
+ size--;
+ size -= len;
+ MyStringCopy(s + size, (const wchar_t *)name);
+ s[size + len] = WCHAR_PATH_SEPARATOR;
+ continue;
+ }
+ if (index2 == -1)
+ break;
+ servName = (index2 == -2) ?
+ 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));
- if (fileSize < Header.GetPhySize())
- return S_FALSE;
-
+ {
+ static const UInt32 kHeaderSize = 512;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize));
+ if (!Header.Parse(buf))
+ return S_FALSE;
+
+ UInt64 fileSize;
+ RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize));
+ 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;
- int recSizeLog;
+
CMyComPtr<IInStream> mftStream;
{
UInt32 blockSize = 1 << 12;
- ByteBuf.SetCapacity(blockSize);
+ ByteBuf.Alloc(blockSize);
RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize));
- UInt32 allocSize = Get32(ByteBuf + 0x1C);
- recSizeLog = GetLog(allocSize);
- if (recSizeLog < Header.SectorSizeLog)
- return false;
- numSectorsInRec = 1 << (recSizeLog - Header.SectorSizeLog);
- if (!mftRec.Parse(ByteBuf, Header.SectorSizeLog, numSectorsInRec, NULL, 0))
+ {
+ 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;
@@ -1292,23 +1654,28 @@ HRESULT CDatabase::Open()
return S_FALSE;
}
+ // CObjectVector<CAttr> SecurityAttrs;
+
UInt64 mftSize = mftRec.DataAttrs[0].Size;
- if ((mftSize >> 4) > Header.GetPhySize())
+ if ((mftSize >> 4) > Header.GetPhySize_Clusters())
return S_FALSE;
- UInt64 numFiles = mftSize >> recSizeLog;
+ UInt64 numFiles = mftSize >> RecSizeLog;
if (numFiles > (1 << 30))
return S_FALSE;
if (OpenCallback)
{
RINOK(OpenCallback->SetTotal(&numFiles, &mftSize));
}
- const UInt32 kBufSize = (1 << 15);
- if (kBufSize < (1 << recSizeLog))
+
+ const size_t kBufSize = (1 << 15);
+ const size_t recSize = ((size_t)1 << RecSizeLog);
+ if (kBufSize < recSize)
return S_FALSE;
- ByteBuf.SetCapacity((size_t)kBufSize);
- Recs.Reserve((int)numFiles);
+ ByteBuf.Alloc(kBufSize);
+ Recs.ClearAndReserve((unsigned)numFiles);
+
for (UInt64 pos64 = 0;;)
{
if (OpenCallback)
@@ -1319,28 +1686,85 @@ HRESULT CDatabase::Open()
RINOK(OpenCallback->SetCompleted(&numFiles, &pos64));
}
}
- UInt32 readSize = kBufSize;
+ size_t readSize = kBufSize;
UInt64 rem = mftSize - pos64;
if (readSize > rem)
- readSize = (UInt32)rem;
- if (readSize < ((UInt32)1 << recSizeLog))
+ readSize = (size_t)rem;
+ if (readSize < recSize)
break;
- RINOK(ReadStream_FALSE(mftStream, ByteBuf, (size_t)readSize));
+ RINOK(ReadStream_FALSE(mftStream, ByteBuf, readSize));
pos64 += readSize;
- for (int i = 0; ((UInt32)(i + 1) << recSizeLog) <= readSize; i++)
+
+ for (size_t i = 0; readSize >= recSize; i += recSize, readSize -= recSize)
{
PRF(printf("\n---------------------"));
PRF(printf("\n%5d:", Recs.Size()));
- Byte *p = ByteBuf + ((UInt32)i << recSizeLog);
+
+ Byte *p = ByteBuf + i;
CMftRec rec;
- if (!rec.Parse(p, Header.SectorSizeLog, numSectorsInRec, (UInt32)Recs.Size(),
- (Recs.Size() == kRecIndex_Volume) ? &VolAttrs: NULL))
+
+ CObjectVector<CAttr> *attrs = NULL;
+ unsigned recIndex = Recs.Size();
+ switch (recIndex)
+ {
+ case kRecIndex_Volume: attrs = &VolAttrs; break;
+ // case kRecIndex_Security: attrs = &SecurityAttrs; break;
+ }
+
+ if (!rec.Parse(p, Header.SectorSizeLog, numSectorsInRec, (UInt32)Recs.Size(), attrs))
return S_FALSE;
Recs.Add(rec);
}
}
- int i;
+ /*
+ // 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];
@@ -1349,7 +1773,7 @@ HRESULT CDatabase::Open()
UInt64 refIndex = rec.BaseMftRef.GetIndex();
if (refIndex > (UInt32)Recs.Size())
return S_FALSE;
- CMftRec &refRec = Recs[(int)refIndex];
+ CMftRec &refRec = Recs[(unsigned)refIndex];
bool moveAttrs = (refRec.SeqNumber == rec.BaseMftRef.GetNumber() && refRec.BaseMftRef.IsBaseItself());
if (rec.InUse() && refRec.InUse())
{
@@ -1371,81 +1795,357 @@ HRESULT CDatabase::Open()
CMftRec &rec = Recs[i];
if (!rec.IsFILE() || !rec.BaseMftRef.IsBaseItself())
continue;
- int numNames = 0;
+ if (i < kNumSysRecs && !_showSystemFiles)
+ continue;
+ if (!rec.InUse() && !_showDeletedFiles)
+ continue;
+
+ unsigned numNames = 0;
// printf("\n%4d: ", i);
- for (int t = 0; t < rec.FileNames.Size(); t++)
+ FOR_VECTOR (t, rec.FileNames)
{
const CFileNameAttr &fna = rec.FileNames[t];
- // printf("%4d %S | ", (int)fna.NameType, fna.Name);
+ // PRF(printf("%4d ", (int)fna.NameType));
+ // PRF_UTF16(fna.Name)
+ // PRF(printf(" | "));
if (fna.IsDos())
continue;
- int numDatas = rec.DataRefs.Size();
+ unsigned numDatas = rec.DataRefs.Size();
- // For hard linked files we show substreams only for first Name.
+ /*
+ // we can use that code to reduce the number of alt streams
+ // For hard linked files we show alt streams only for first Name.
if (numDatas > 1 && numNames > 0)
numDatas = 1;
+ */
+
numNames++;
+ // here we suppose that first stream is main stream (unnamed stream).
+ // IS IT SO ????
+ int hostIndex = -1;
if (rec.IsDir())
{
CItem item;
- item.Name = fna.Name;
+ item.NameIndex = t;
item.RecIndex = i;
- item.DataIndex = -1;
- item.ParentRef = fna.ParentDirRef;
- item.Attrib = rec.SiAttr.Attrib | 0x10;
+ // item.ParentRef = fna.ParentDirRef;
+ // item.Attrib = rec.SiAttr.Attrib | 0x10;
// item.Attrib = fna.Attrib;
- Items.Add(item);
+ hostIndex = Items.Add(item);
+ }
+ else
+ {
+
+ // probably NTFS for empty file still creates empty DATA_ATTRIBUTE
+ // But it doesn't do it for $Secure:$SDS
+ if (rec.DataRefs.IsEmpty() ||
+ !rec.DataAttrs[rec.DataRefs[0].Start].Name.IsEmpty())
+ {
+ CItem item;
+ item.NameIndex = t;
+ item.RecIndex = i;
+ // item.ParentRef = fna.ParentDirRef;
+ // item.Attrib = rec.SiAttr.Attrib;
+ hostIndex = Items.Add(item);
+ }
+ }
+
+ {
+ bool isThereUnNamedStream = false;
+ for (unsigned di = 0; di < numDatas; di++)
+ {
+ const UString &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name;
+ if (subName.IsEmpty())
+ isThereUnNamedStream = true;
+ }
+ if (!rec.IsDir() && !isThereUnNamedStream)
+ {
+ // return S_FALSE;
+ }
}
- for (int di = 0; di < numDatas; di++)
+
+ for (unsigned di = 0; di < numDatas; di++)
{
CItem item;
- item.Name = fna.Name;
- item.Attrib = rec.SiAttr.Attrib;
+ item.NameIndex = t;
+ // item.FileNameAttr = fna;
+ // item.Name = fna.Name;
+ // item.Attrib = rec.SiAttr.Attrib;
const UString &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name;
- if (!subName.IsEmpty())
+ if (subName.IsEmpty())
+ {
+ if (hostIndex >= 0)
+ continue;
+ hostIndex = Items.Size();
+ }
+ else
{
// $BadClus:$Bad is sparse file for all clusters. So we skip it.
if (i == kRecIndex_BadClus && subName == L"$Bad")
continue;
- item.Name += L":";
- item.Name += subName;
- item.Attrib = fna.Attrib;
+ if (hostIndex >= 0)
+ {
+ // item.Name = subName;
+ }
+ else
+ {
+ // there is no host file for some streams
+ // return E_FAIL;
+ // item.Name += L":";
+ // item.Name += subName;
+ }
+ // item.Attrib = fna.Attrib;
+ item.ParentHost = hostIndex;
+ // item.IsAltStream = true;
+ ThereAreAltStreams = true;
}
PRF(printf("\n%3d", i));
- PRF(printf(" attrib=%2x", rec.SiAttr.Attrib));
- PRF(printf(" %S", item.Name));
+ PRF(printf(" attrib=%2x ", rec.SiAttr.Attrib));
+ // PRF_UTF16(item.Name);
item.RecIndex = i;
item.DataIndex = di;
- item.ParentRef = fna.ParentDirRef;
+ // item.ParentRef = fna.ParentDirRef;
Items.Add(item);
rec.MyNumNameLinks++;
}
}
- rec.FileNames.ClearAndFree();
+ // rec.FileNames.ClearAndFree();
+ }
+
+ if (Recs.Size() > kRecIndex_Security)
+ {
+ const CMftRec &rec = Recs[kRecIndex_Security];
+ FOR_VECTOR (di, rec.DataRefs)
+ {
+ const CAttr &attr = rec.DataAttrs[rec.DataRefs[di].Start];
+ if (attr.Name == L"$SDS")
+ {
+ CMyComPtr<IInStream> sdsStream;
+ RINOK(rec.GetStream(InStream, 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 == 5)
+ 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 = -2;
+ }
+ else
+ {
+ thereAreUnknownFolders_Deleted = true;
+ index = -3;
+ }
+ }
+ 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_IMP2(IInArchive, IInArchiveGetStream)
+ MY_UNKNOWN_IMP4(
+ IInArchive,
+ IArchiveGetRawProps,
+ IInArchiveGetStream,
+ ISetProperties)
INTERFACE_IInArchive(;)
+ INTERFACE_IArchiveGetRawProps(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+ STDMETHOD(SetProperties)(const wchar_t **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;
+ *parent = (UInt32)(Int32)-1;
+
+ if (index >= Items.Size())
+ return S_OK;
+ const CItem &item = Items[index];
+
+ if (item.ParentHost >= 0)
+ {
+ *parentType = NParentType::kAltStream;
+ *parent = (UInt32)(Int32)item.ParentHost;
+ return S_OK;
+ }
+ if (item.RecIndex < kNumSysRecs)
+ {
+ if (_showSystemFiles)
+ *parent = _systemFolderIndex;
+ }
+ else if (item.ParentFolder >= 0)
+ *parent = item.ParentFolder;
+ else if (item.ParentFolder == -2)
+ *parent = _lostFolderIndex_Normal;
+ else if (item.ParentFolder == -3)
+ *parent = _lostFolderIndex_Deleted;
+ 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 UString *s;
+ if (index >= Items.Size())
+ s = &VirtFolderNames[index - Items.Size()];
+ else
+ {
+ const CItem &item = Items[index];
+ const CMftRec &rec = Recs[item.RecIndex];
+
+ // fix it for no HOST case !!
+ // if (item.IsAltStream && item.DataIndex >= 0)
+ if (rec.IsAltStream(item.DataIndex))
+ {
+ if (item.ParentHost < 0)
+ return S_OK;
+ const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
+ s = &data.Name;
+ }
+ else
+ {
+ s = &rec.FileNames[item.NameIndex].Name;
+ }
+ // s = &item.Name;
+ }
+ *data = (const wchar_t *)*s;
+ *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];
@@ -1455,18 +2155,66 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
COM_TRY_END
}
+/*
+enum
+{
+ kpidLink2 = kpidUserDefined,
+ kpidLinkType,
+ kpidRecMTime,
+ kpidRecMTime2,
+ kpidMTime2,
+ kpidCTime2,
+ kpidATime2
+};
+
static const STATPROPSTG kProps[] =
{
{ NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
{ NULL, kpidSize, VT_UI8},
{ NULL, kpidPackSize, VT_UI8},
+
+ // { NULL, kpidLink, VT_BSTR},
+
+ // { L"Link 2", kpidLink2, VT_BSTR},
+ // { L"Link Type", kpidLinkType, VT_UI2},
+ { NULL, kpidINode, VT_UI8},
+
{ NULL, kpidMTime, VT_FILETIME},
{ NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidATime, VT_FILETIME},
+
+ // { L"Record Modified", kpidRecMTime, VT_FILETIME},
+
+ // { L"Modified 2", kpidMTime2, VT_FILETIME},
+ // { L"Created 2", kpidCTime2, VT_FILETIME},
+ // { L"Accessed 2", kpidATime2, VT_FILETIME},
+ // { L"Record Modified 2", kpidRecMTime2, VT_FILETIME},
+
{ NULL, kpidAttrib, VT_UI4},
- { NULL, kpidLinks, VT_UI4},
- { NULL, kpidNumBlocks, 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,
+ kpidIsDeleted
+};
+
+enum
+{
+ kpidRecordSize = kpidUserDefined
};
static const STATPROPSTG kArcProps[] =
@@ -1474,21 +2222,34 @@ static const STATPROPSTG kArcProps[] =
{ NULL, kpidVolumeName, VT_BSTR},
{ NULL, kpidFileSystem, VT_BSTR},
{ NULL, kpidClusterSize, VT_UI4},
- { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidSectorSize, VT_UI4},
+ { L"Record Size", kpidRecordSize, VT_UI4},
{ NULL, kpidHeadersSize, VT_UI8},
{ NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidId, VT_UI8},
+};
- { NULL, kpidSectorSize, VT_UI4},
- { NULL, kpidId, VT_UI8}
- // { NULL, kpidSectorsPerTrack, VT_UI4},
- // { NULL, kpidNumHeads, VT_UI4},
- // { NULL, kpidHiddenSectors, VT_UI4}
+/*
+static const Byte kArcProps[] =
+{
+ kpidVolumeName,
+ kpidFileSystem,
+ kpidClusterSize,
+ kpidHeadersSize,
+ kpidCTime,
+
+ kpidSectorSize,
+ kpidId
+ // kpidSectorsPerTrack,
+ // kpidNumHeads,
+ // kpidHiddenSectors
};
+*/
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps
+IMP_IInArchive_ArcProps_WITH_NAME
-static void NtfsTimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop)
+static void NtfsTimeToProp(UInt64 t, NCOM::CPropVariant &prop)
{
FILETIME ft;
ft.dwLowDateTime = (DWORD)t;
@@ -1499,19 +2260,19 @@ static void NtfsTimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop)
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
+ NCOM::CPropVariant prop;
const CMftRec *volRec = (Recs.Size() > kRecIndex_Volume ? &Recs[kRecIndex_Volume] : NULL);
- switch(propID)
+ switch (propID)
{
case kpidClusterSize: prop = Header.ClusterSize(); break;
- case kpidPhySize: prop = Header.GetPhySize(); break;
+ case kpidPhySize: prop = PhySize; break;
/*
case kpidHeadersSize:
{
UInt64 val = 0;
- for (int i = 0; i < kNumSysRecs; i++)
+ for (unsigned i = 0; i < kNumSysRecs; i++)
{
printf("\n%2d: %8I64d ", i, Recs[i].GetPackSize());
if (i == 8)
@@ -1522,16 +2283,18 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
break;
}
*/
- case kpidCTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.CTime, prop); break;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 (int i = 0; i < VolAttrs.Size(); i++)
+ FOR_VECTOR (i, VolAttrs)
{
const CAttr &attr = VolAttrs[i];
if (attr.Type == ATTR_TYPE_VOLUME_NAME)
{
UString name;
- GetString(attr.Data, (int)attr.Data.GetCapacity() / 2, name);
+ GetString(attr.Data, (unsigned)attr.Data.Size() / 2, name);
prop = name;
break;
}
@@ -1541,7 +2304,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidFileSystem:
{
AString s = "NTFS";
- for (int i = 0; i < VolAttrs.Size(); i++)
+ FOR_VECTOR (i, VolAttrs)
{
const CAttr &attr = VolAttrs[i];
if (attr.Type == ATTR_TYPE_VOLUME_INFO)
@@ -1564,7 +2327,31 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
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";
+
+ /*
+ 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;
@@ -1578,7 +2365,26 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
+ NCOM::CPropVariant prop;
+ if (index >= Items.Size())
+ {
+ switch (propID)
+ {
+ case kpidName:
+ case kpidPath:
+ prop = VirtFolderNames[index - Items.Size()];
+ 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];
@@ -1586,30 +2392,108 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
if (item.DataIndex >= 0)
data = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
- switch(propID)
+ // 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:
{
- UString name = GetItemPath(index);
- const wchar_t *prefix = NULL;
- if (!rec.InUse())
- prefix = MY_DIR_PREFIX(L"DELETED");
- else if (item.RecIndex < kNumSysRecs)
- prefix = MY_DIR_PREFIX(L"SYSTEM");
- if (prefix)
- name = prefix + name;
- prop = name;
+ // const CMftRec &rec = Recs[item.RecIndex];
+ // prop = ((UInt64)rec.SeqNumber << 48) | item.RecIndex;
+ prop = item.RecIndex;
+ break;
+ }
+
+ case kpidName:
+ {
+ // prop = item.Name;
+ const UString *s;
+ if (rec.IsAltStream(item.DataIndex))
+ {
+ const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
+ s = &data.Name;
+ if (item.ParentHost < 0)
+ {
+ UString s2 = rec.FileNames[item.NameIndex].Name;
+ s2 += L':';
+ s2 += *s;
+ prop = s2;
+ break;
+ }
+ }
+ else
+ {
+ s = &rec.FileNames[item.NameIndex].Name;
+ }
+ prop = *s;
+
break;
}
case kpidIsDir: prop = item.IsDir(); break;
+ case kpidIsAltStream: prop = rec.IsAltStream(item.DataIndex); 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:
- prop = item.Attrib;
+ {
+ 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;
+
+ prop = attrib;
break;
+ }
case kpidLinks: prop = rec.MyNumNameLinks; break;
case kpidSize: if (data) prop = data->GetSize(); break;
case kpidPackSize: if (data) prop = data->GetPackSize(); break;
@@ -1654,7 +2538,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = Items.Size();
if (numItems == 0)
@@ -1663,9 +2547,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
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 (!rec.IsDir())
+ if (item.DataIndex >= 0)
totalSize += rec.GetSize(item.DataIndex);
}
RINOK(extractCallback->SetTotal(totalSize));
@@ -1673,9 +2560,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 totalPackSize;
totalSize = totalPackSize = 0;
- CByteBuffer buf;
UInt32 clusterSize = Header.ClusterSize();
- buf.SetCapacity(clusterSize);
+ CByteBuffer buf(clusterSize);
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
@@ -1696,17 +2582,18 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
- Int32 index = allFilesMode ? i : indices[i];
+ UInt32 index = allFilesMode ? i : indices[i];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
- const CItem &item = Items[index];
- if (item.IsDir())
+ 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));
@@ -1723,7 +2610,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<IInStream> inStream;
HRESULT hres = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &inStream);
if (hres == S_FALSE)
- res = NExtract::NOperationResult::kUnSupportedMethod;
+ res = NExtract::NOperationResult::kUnsupportedMethod;
else
{
RINOK(hres);
@@ -1750,15 +2637,46 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
- *numItems = Items.Size();
+ *numItems = Items.Size() + VirtFolderNames.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
+{
+ InitProps();
+
+ 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("ld"))
+ {
+ RINOK(PROPVARIANT_to_bool(prop, _showDeletedFiles));
+ }
+ else if (name.IsEqualTo("ls"))
+ {
+ RINOK(PROPVARIANT_to_bool(prop, _showSystemFiles));
+ }
+ else
+ return E_INVALIDARG;
+ }
return S_OK;
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"NTFS", L"ntfs img", 0, 0xD9, { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 }, 9, false, CreateArc, 0 };
+ { "NTFS", "ntfs img", 0, 0xD9,
+ 9, { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 },
+ 3,
+ 0,
+ CreateArc };
-REGISTER_ARC(Fat)
+REGISTER_ARC(Ntfs)
}}
diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp
index e5946969..08bcd062 100755..100644
--- a/CPP/7zip/Archive/PeHandler.cpp
+++ b/CPP/7zip/Archive/PeHandler.cpp
@@ -2,15 +2,17 @@
#include "StdAfx.h"
+// #include <stdio.h>
+
#include "../../../C/CpuArch.h"
-#include "Common/DynamicBuffer.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/StringConvert.h"
+#include "../../Common/DynamicBuffer.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/StringConvert.h"
-#include "Windows/PropVariantUtils.h"
-#include "Windows/Time.h"
+#include "../../Windows/PropVariantUtils.h"
+#include "../../Windows/TimeUtils.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -24,21 +26,69 @@
#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 {
-#define NUM_SCAN_SECTIONS_MAX (1 << 6)
+static const UInt32 k_Signature = 0x00004550;
-#define PE_SIG 0x00004550
-#define PE_OptHeader_Magic_32 0x10B
-#define PE_OptHeader_Magic_64 0x20B
+static HRESULT CalcCheckSum(ISequentialInStream *stream, UInt32 size, UInt32 excludePos, UInt32 &res)
+{
+ const UInt32 kBufSizeMax = (UInt32)1 << 16;
+ UInt32 bufSize = MyMin(kBufSizeMax, size);
+ bufSize += (bufSize & 1);
+ 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));
+
+ if ((processed & 1) != 0)
+ buf[processed] = 0;
+
+ for (unsigned j = 0; j < 4; j++)
+ {
+ UInt32 e = excludePos + j;
+ if (pos <= e)
+ {
+ e -= pos;
+ if (e < processed)
+ buf[e] = 0;
+ }
+ }
+
+ for (size_t i = 0; i < processed; i += 2)
+ {
+ sum += Get16(buf + i);
+ sum = (sum + (sum >> 16)) & 0xFFFF;
+ }
+ pos += (UInt32)processed;
+ if (rem != processed)
+ break;
+ }
+ res = sum + pos;
+ return S_OK;
+}
static AString GetDecString(UInt32 v)
{
- char sz[32];
- ConvertUInt64ToString(v, sz);
+ char sz[16];
+ ConvertUInt32ToString(v, sz);
return sz;
}
@@ -47,65 +97,80 @@ struct CVersion
UInt16 Major;
UInt16 Minor;
- void Parse(const Byte *buf);
- AString GetString() const { return GetDecString(Major) + '.' + GetDecString(Minor); }
+ void Parse(const Byte *p)
+ {
+ G16(0, Major);
+ G16(2, Minor);
+ }
+ void ToProp(NCOM::CPropVariant &prop);
};
-void CVersion::Parse(const Byte *p)
+void CVersion::ToProp(NCOM::CPropVariant &prop)
{
- Major = Get16(p);
- Minor = Get16(p + 2);
+ char sz[32];
+ ConvertUInt32ToString(Major, sz);
+ unsigned len = MyStringLen(sz);
+ sz[len] = '.';
+ ConvertUInt32ToString(Minor, sz + len + 1);
+ prop = sz;
}
-static const UInt32 kHeaderSize = 4 + 20;
+static const unsigned kHeaderSize = 4 + 20;
+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;
- UInt16 Machine;
- bool Parse(const Byte *buf);
+ bool Parse(const Byte *p);
+ bool IsDll() const { return (Flags & PE_IMAGE_FILE_DLL) != 0; }
};
bool CHeader::Parse(const Byte *p)
{
- if (Get32(p) != PE_SIG)
+ if (Get32(p) != k_Signature)
return false;
p += 4;
- Machine = Get16(p + 0);
- NumSections = Get16(p + 2);
- Time = Get32(p + 4);
- PointerToSymbolTable = Get32(p + 8);
- NumSymbols = Get32(p + 12);
- OptHeaderSize = Get16(p + 16);
- Flags = Get16(p + 18);
- return true;
+ G16( 0, Machine);
+ G16( 2, NumSections);
+ G32( 4, Time);
+ G32( 8, PointerToSymbolTable);
+ G32(12, NumSymbols);
+ G16(16, OptHeaderSize);
+ G16(18, Flags);
+ return OptHeaderSize >= k_OptHeader32_Size_MIN;
}
struct CDirLink
{
UInt32 Va;
UInt32 Size;
- void Parse(const Byte *p);
+
+ CDirLink(): Va(0), Size(0) {}
+ void Parse(const Byte *p)
+ {
+ G32(0, Va);
+ G32(4, Size);
+ }
};
-void CDirLink::Parse(const Byte *p)
-{
- Va = Get32(p);
- Size = Get32(p + 4);
-}
-
enum
{
kDirLink_Certificate = 4,
kDirLink_Debug = 6
};
+static const UInt32 kNumDirItemsMax = 16;
+
struct CDebugEntry
{
UInt32 Flags;
@@ -116,21 +181,25 @@ struct CDebugEntry
UInt32 Va;
UInt32 Pa;
- void Parse(const Byte *p);
+ 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);
+ }
};
-void CDebugEntry::Parse(const Byte *p)
-{
- Flags = Get32(p);
- Time = Get32(p + 4);
- Ver.Parse(p + 8);
- Type = Get32(p + 12);
- Size = Get32(p + 16);
- Va = Get32(p + 20);
- Pa = Get32(p + 24);
-}
+static const UInt32 k_CheckSum_Field_Offset = 64;
-static const UInt32 kNumDirItemsMax = 16;
+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
{
@@ -178,10 +247,19 @@ struct COptHeader
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)
{
@@ -194,19 +272,14 @@ bool COptHeader::Parse(const Byte *p, UInt32 size)
LinkerVerMajor = p[2];
LinkerVerMinor = p[3];
- bool hdr64 = Is64Bit();
+ G32( 4, CodeSize);
+ G32( 8, InitDataSize);
+ G32(12, UninitDataSize);
+ // G32(16, AddressOfEntryPoint);
+ // G32(20, BaseOfCode);
- CodeSize = Get32(p + 4);
- InitDataSize = Get32(p + 8);
- UninitDataSize = Get32(p + 12);
-
- // AddressOfEntryPoint = Get32(p + 16);
- // BaseOfCode = Get32(p + 20);
- // BaseOfData32 = hdr64 ? 0: Get32(p + 24);
- ImageBase = hdr64 ? GetUi64(p + 24) : Get32(p + 28);
-
- SectAlign = Get32(p + 32);
- FileAlign = Get32(p + 36);
+ G32(32, SectAlign);
+ G32(36, FileAlign);
OsVer.Parse(p + 40);
ImageVer.Parse(p + 44);
@@ -214,28 +287,39 @@ bool COptHeader::Parse(const Byte *p, UInt32 size)
// reserved = Get32(p + 52);
- ImageSize = Get32(p + 56);
- HeadersSize = Get32(p + 60);
- CheckSum = Get32(p + 64);
- SubSystem = Get16(p + 68);
- DllCharacts = Get16(p + 70);
+ G32(56, ImageSize);
+ G32(60, HeadersSize);
+ G32(64, CheckSum);
+ G16(68, SubSystem);
+ G16(70, DllCharacts);
- if (hdr64)
+ UInt32 pos;
+ if (Is64Bit())
{
- StackReserve = Get64(p + 72);
- StackCommit = Get64(p + 80);
- HeapReserve = Get64(p + 88);
- HeapCommit = Get64(p + 96);
+ 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
{
- StackReserve = Get32(p + 72);
- StackCommit = Get32(p + 76);
- HeapReserve = Get32(p + 80);
- HeapCommit = Get32(p + 84);
+ // G32(24, BaseOfData32);
+ G32(28, ImageBase);
+ G32(72, StackReserve);
+ G32(76, StackCommit);
+ G32(80, HeapReserve);
+ G32(84, HeapCommit);
+ pos = 92;
}
- UInt32 pos = (hdr64 ? 108 : 92);
- NumDirItems = Get32(p + pos);
+
+ G32(pos, NumDirItems);
+ if (NumDirItems > (1 << 16))
+ return false;
pos += 4;
if (pos + 8 * NumDirItems != size)
return false;
@@ -257,28 +341,31 @@ struct CSection
UInt32 Flags;
UInt32 Time;
// UInt16 NumRelocs;
- bool IsDebug;
bool IsRealSect;
+ bool IsDebug;
bool IsAdditionalSection;
CSection(): IsRealSect(false), IsDebug(false), IsAdditionalSection(false) {}
- UInt64 GetPackSize() const { return PSize; }
- void UpdateTotalSize(UInt32 &totalSize)
+ void UpdateTotalSize(UInt32 &totalSize) const
{
UInt32 t = Pa + PSize;
- if (t > totalSize)
+ if (totalSize < t)
totalSize = t;
}
void Parse(const Byte *p);
+
+ int Compare(const CSection &s) const
+ {
+ RINOZ(MyCompare(Pa, s.Pa));
+ return MyCompare(PSize, s.PSize);
+ }
};
-static bool operator <(const CSection &a1, const CSection &a2) { return (a1.Pa < a2.Pa) || ((a1.Pa == a2.Pa) && (a1.PSize < a2.PSize)) ; }
-static bool operator ==(const CSection &a1, const CSection &a2) { return (a1.Pa == a2.Pa) && (a1.PSize == a2.PSize); }
+static const unsigned kNameSize = 8;
static AString GetName(const Byte *name)
{
- const int kNameSize = 8;
AString res;
char *p = res.GetBuffer(kNameSize);
memcpy(p, name, kNameSize);
@@ -290,12 +377,12 @@ static AString GetName(const Byte *name)
void CSection::Parse(const Byte *p)
{
Name = GetName(p);
- VSize = Get32(p + 8);
- Va = Get32(p + 12);
- PSize = Get32(p + 16);
- Pa = Get32(p + 20);
- // NumRelocs = Get16(p + 32);
- Flags = Get32(p + 36);
+ G32( 8, VSize);
+ G32(12, Va);
+ G32(16, PSize);
+ G32(20, Pa);
+ // G16(32, NumRelocs);
+ G32(36, Flags);
}
static const CUInt32PCharPair g_HeaderCharacts[] =
@@ -352,6 +439,7 @@ static const CUInt32PCharPair g_SectFlags[] =
static const CUInt32PCharPair g_MachinePairs[] =
{
{ 0x014C, "x86" },
+ { 0x014D, "I860" },
{ 0x0162, "MIPS-R3000" },
{ 0x0166, "MIPS-R4000" },
{ 0x0168, "MIPS-R10000" },
@@ -364,24 +452,31 @@ static const CUInt32PCharPair g_MachinePairs[] =
{ 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" },
- { 0x0200, "IA-64" },
- { 0x0366, "MIPSFPU" },
+ { 0x0366, "MIPS-FPU" },
+ { 0x0466, "MIPS-FPU16" },
+ { 0x0520, "TriCore" },
+ { 0x0CEF, "CEF" },
+ { 0x0EBC, "EFI" },
{ 0x8664, "x64" },
- { 0x0EBC, "EFI" }
+ { 0x9041, "M32R" },
+ { 0xC0EE, "CEE" }
};
static const CUInt32PCharPair g_SubSystems[] =
{
- { 0, "Unknown" },
- { 1, "Native" },
- { 2, "Windows GUI" },
- { 3, "Windows CUI" },
- { 7, "Posix" },
- { 9, "Windows CE" },
+ { 0, "Unknown" },
+ { 1, "Native" },
+ { 2, "Windows GUI" },
+ { 3, "Windows CUI" },
+ { 7, "Posix" },
+ { 9, "Windows CE" },
{ 10, "EFI" },
{ 11, "EFI Boot" },
{ 12, "EFI Runtime" },
@@ -391,35 +486,35 @@ static const CUInt32PCharPair g_SubSystems[] =
static const wchar_t *g_ResTypes[] =
{
- NULL,
- L"CURSOR",
- L"BITMAP",
- L"ICON",
- L"MENU",
- L"DIALOG",
- L"STRING",
- L"FONTDIR",
- L"FONT",
- L"ACCELERATOR",
- L"RCDATA",
- L"MESSAGETABLE",
- L"GROUP_CURSOR",
- NULL,
- L"GROUP_ICON",
- NULL,
- L"VERSION",
- L"DLGINCLUDE",
- NULL,
- L"PLUGPLAY",
- L"VXD",
- L"ANICURSOR",
- L"ANIICON",
- L"HTML",
- L"MANIFEST"
+ NULL
+ , L"CURSOR"
+ , L"BITMAP"
+ , L"ICON"
+ , L"MENU"
+ , L"DIALOG"
+ , L"STRING"
+ , L"FONTDIR"
+ , L"FONT"
+ , L"ACCELERATOR"
+ , L"RCDATA"
+ , L"MESSAGETABLE"
+ , L"GROUP_CURSOR"
+ , NULL
+ , L"GROUP_ICON"
+ , NULL
+ , L"VERSION"
+ , L"DLGINCLUDE"
+ , NULL
+ , L"PLUGPLAY"
+ , L"VXD"
+ , L"ANICURSOR"
+ , L"ANIICON"
+ , L"HTML"
+ , L"MANIFEST"
};
-const UInt32 kFlag = (UInt32)1 << 31;
-const UInt32 kMask = ~kFlag;
+static const UInt32 kFlag = (UInt32)1 << 31;
+static const UInt32 kMask = ~kFlag;
struct CTableItem
{
@@ -428,8 +523,8 @@ struct CTableItem
};
-const UInt32 kBmpHeaderSize = 14;
-const UInt32 kIconHeaderSize = 22;
+static const UInt32 kBmpHeaderSize = 14;
+static const UInt32 kIconHeaderSize = 22;
struct CResItem
{
@@ -450,45 +545,110 @@ struct CResItem
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 CStringItem
+struct CTextFile
{
- UInt32 Lang;
- UInt32 Size;
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 len);
+
+ void OpenBlock(int num)
+ {
+ AddSpaces(num);
+ AddChar('{');
+ NewLine();
+ }
+ void CloseBlock(int num)
+ {
+ AddSpaces(num);
+ AddChar('}');
+ NewLine();
+ }
};
-void CStringItem::AddChar(Byte c)
+void CTextFile::AddChar(Byte c)
+{
+ Byte *p = Buf.GetCurPtrAndGrow(2);
+ p[0] = c;
+ p[1] = 0;
+}
+
+void CTextFile::AddWChar(UInt16 c)
{
- Buf.EnsureCapacity(Size + 2);
- Buf[Size++] = c;
- Buf[Size++] = 0;
+ Byte *p = Buf.GetCurPtrAndGrow(2);
+ SetUi16(p, c);
}
-void CStringItem::AddWChar(UInt16 c)
+void CTextFile::AddWChar_Smart(UInt16 c)
{
if (c == '\n')
{
AddChar('\\');
c = 'n';
}
- Buf.EnsureCapacity(Size + 2);
- SetUi16(Buf + Size, c);
- Size += 2;
+ 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(' ');
+}
+
+void CTextFile::AddBytes(const Byte *data, size_t size)
+{
+ Byte *p = Buf.GetCurPtrAndGrow(size);
+ memcpy(p, data, size);
+}
+
+struct CStringItem: public CTextFile
+{
+ UInt32 Lang;
+};
+
+struct CByteBuffer_WithLang: public CByteBuffer
+{
+ UInt32 Lang;
+};
+
+
struct CMixItem
{
int SectionIndex;
int ResourceIndex;
int StringIndex;
+ int VersionIndex;
- bool IsSectionItem() const { return ResourceIndex < 0 && StringIndex < 0; };
+ CMixItem(): SectionIndex(-1), ResourceIndex(-1), StringIndex(-1), VersionIndex(-1) {}
+ bool IsSectionItem() const { return ResourceIndex < 0 && StringIndex < 0 && VersionIndex < 0; };
};
struct CUsedBitmap
@@ -498,113 +658,95 @@ public:
void Alloc(size_t size)
{
size = (size + 7) / 8;
- Buf.SetCapacity(size);
+ Buf.Alloc(size);
memset(Buf, 0, size);
}
+
void Free()
{
- Buf.SetCapacity(0);
+ Buf.Free();
}
- bool SetRange(size_t from, int size)
+
+ bool SetRange(size_t from, unsigned size)
{
- for (int i = 0; i < size; i++)
+ 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] = b | mask;
+ Buf[pos] = (Byte)(b | mask);
}
return true;
}
};
+struct CStringKeyValue
+{
+ UString Key;
+ UString Value;
+};
class CHandler:
public IInArchive,
public IInArchiveGetStream,
+ public IArchiveAllowTail,
public CMyUnknownImp
{
CMyComPtr<IInStream> _stream;
CObjectVector<CSection> _sections;
UInt32 _peOffset;
CHeader _header;
- COptHeader _optHeader;
UInt32 _totalSize;
- UInt32 _totalSizeLimited;
Int32 _mainSubfile;
+ CRecordVector<CMixItem> _mixItems;
CRecordVector<CResItem> _items;
CObjectVector<CStringItem> _strings;
+ CObjectVector<CByteBuffer_WithLang> _versionFiles;
+ UString _versionFullString;
+ UString _versionShortString;
+ UString _originalFilename;
+ CObjectVector<CStringKeyValue> _versionKeys;
CByteBuffer _buf;
bool _oneLang;
- UString _resourceFileName;
+ UString _resourcesPrefix;
CUsedBitmap _usedRes;
bool _parseResources;
+ bool _checksumError;
- CRecordVector<CMixItem> _mixItems;
+ COptHeader _optHeader;
+
+ bool _allowTail;
HRESULT LoadDebugSections(IInStream *stream, bool &thereIsSection);
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
- bool Parse(const Byte *buf, UInt32 size);
void AddResNameToString(UString &s, UInt32 id) const;
- UString GetLangPrefix(UInt32 lang);
+ void AddLangPrefix(UString &s, UInt32 lang) const;
HRESULT ReadString(UInt32 offset, UString &dest) const;
HRESULT ReadTable(UInt32 offset, CRecordVector<CTableItem> &items);
bool ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size);
- HRESULT OpenResources(int sectIndex, IInStream *stream, IArchiveOpenCallback *callback);
+ HRESULT OpenResources(unsigned sectIndex, IInStream *stream, IArchiveOpenCallback *callback);
void CloseResources();
bool CheckItem(const CSection &sect, const CResItem &item, size_t offset) const
{
- return item.Offset >= sect.Va && offset <= _buf.GetCapacity() && _buf.GetCapacity() - offset >= item.Size;
+ return item.Offset >= sect.Va && offset <= _buf.Size() && _buf.Size() - offset >= item.Size;
}
public:
- MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ CHandler(): _allowTail(false) {}
+
+ MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IArchiveAllowTail)
INTERFACE_IInArchive(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+ STDMETHOD(AllowTail)(Int32 allowTail);
};
-bool CHandler::Parse(const Byte *buf, UInt32 size)
-{
- UInt32 i;
- if (size < 512)
- return false;
- _peOffset = Get32(buf + 0x3C);
- if (_peOffset >= 0x1000 || _peOffset + 512 > size || (_peOffset & 7) != 0)
- return false;
-
- UInt32 pos = _peOffset;
- if (!_header.Parse(buf + pos))
- return false;
- if (_header.OptHeaderSize > 512 || _header.NumSections > NUM_SCAN_SECTIONS_MAX)
- return false;
- pos += kHeaderSize;
-
- if (!_optHeader.Parse(buf + pos, _header.OptHeaderSize))
- return false;
-
- pos += _header.OptHeaderSize;
- _totalSize = pos;
-
- for (i = 0; i < _header.NumSections; i++, pos += kSectionSize)
- {
- CSection sect;
- if (pos + kSectionSize > size)
- return false;
- sect.Parse(buf + pos);
- sect.IsRealSect = true;
- sect.UpdateTotalSize(_totalSize);
- _sections.Add(sect);
- }
-
- return true;
-}
enum
{
@@ -633,13 +775,15 @@ enum
static const STATPROPSTG kArcProps[] =
{
+ // { NULL, kpidWarning, VT_BSTR},
{ NULL, kpidCpu, VT_BSTR},
{ NULL, kpidBit64, VT_BOOL},
{ NULL, kpidCharacts, VT_BSTR},
{ NULL, kpidCTime, VT_FILETIME},
- { NULL, kpidPhySize, VT_UI4},
{ NULL, kpidHeadersSize, VT_UI4},
{ NULL, kpidChecksum, VT_UI4},
+ { NULL, kpidName, VT_BSTR},
+
{ L"Image Size", kpidImageSize, VT_UI4},
{ L"Section Alignment", kpidSectAlign, VT_UI4},
{ L"File Alignment", kpidFileAlign, VT_UI4},
@@ -656,31 +800,28 @@ static const STATPROPSTG kArcProps[] =
{ L"Stack Commit", kpidStackCommit, VT_UI8},
{ L"Heap Reserve", kpidHeapReserve, VT_UI8},
{ L"Heap Commit", kpidHeapCommit, VT_UI8},
- { L"Image Base", kpidImageBase, VT_UI8}
+ { L"Image Base", kpidImageBase, VT_UI8},
+ { NULL, kpidComment, VT_BSTR},
// { L"Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8},
// { L"Base Of Code", kpidBaseOfCode, VT_UI8},
// { L"Base Of Data", kpidBaseOfData32, VT_UI8},
};
-static const STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidCharacts, VT_BSTR},
- { NULL, kpidOffset, VT_UI8},
- { NULL, kpidVa, VT_UI8}
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidVirtualSize,
+ kpidCharacts,
+ kpidOffset,
+ kpidVa,
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps_WITH_NAME
-static void VerToProp(const CVersion &v, NCOM::CPropVariant &prop)
-{
- StringToProp(v.GetString(), prop);
-}
-
-void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop)
+static void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop)
{
if (unixTime != 0)
{
@@ -694,20 +835,20 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidSectAlign: prop = _optHeader.SectAlign; break;
case kpidFileAlign: prop = _optHeader.FileAlign; break;
case kpidLinkerVer:
{
CVersion v = { _optHeader.LinkerVerMajor, _optHeader.LinkerVerMinor };
- VerToProp(v, prop);
+ v.ToProp(prop);
break;
}
- case kpidOsVer: VerToProp(_optHeader.OsVer, prop); break;
- case kpidImageVer: VerToProp(_optHeader.ImageVer, prop); break;
- case kpidSubsysVer: VerToProp(_optHeader.SubsysVer, 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;
@@ -715,7 +856,27 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidPhySize: prop = _totalSize; break;
case kpidHeadersSize: prop = _optHeader.HeadersSize; break;
case kpidChecksum: prop = _optHeader.CheckSum; 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 kpidExtension:
+ if (_header.IsDll())
+ prop = _optHeader.IsSybSystem_EFI() ? "efi" : "dll";
+ 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 kpidBit64: if (_optHeader.Is64Bit()) prop = true; break;
case kpidSubSystem: PAIR_TO_PROP(g_SubSystems, _optHeader.SubSystem, prop); break;
@@ -741,6 +902,32 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
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.GetBuffer(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;
+ }
+ dest.ReleaseBuffer(i);
+ return S_OK;
+}
+
void CHandler::AddResNameToString(UString &s, UInt32 id) const
{
if ((id & kFlag) != 0)
@@ -748,32 +935,33 @@ void CHandler::AddResNameToString(UString &s, UInt32 id) const
UString name;
if (ReadString(id & kMask, name) == S_OK)
{
- if (name.IsEmpty())
- s += L"[]";
- else
+ const wchar_t *str = L"[]";
+ if (name.Len() > 1 && name[0] == '"' && name.Back() == '"')
{
- if (name.Length() > 1 && name[0] == '"' && name.Back() == '"')
- name = name.Mid(1, name.Length() - 2);
- s += name;
+ if (name.Len() != 2)
+ {
+ name.DeleteBack();
+ str = name.Ptr(1);
+ }
}
+ else if (!name.IsEmpty())
+ str = name;
+ s += str;
return;
}
}
- wchar_t sz[32];
+ wchar_t sz[16];
ConvertUInt32ToString(id, sz);
s += sz;
}
-UString CHandler::GetLangPrefix(UInt32 lang)
+void CHandler::AddLangPrefix(UString &s, UInt32 lang) const
{
- UString s = _resourceFileName;
- s += WCHAR_PATH_SEPARATOR;
if (!_oneLang)
{
AddResNameToString(s, lang);
s += WCHAR_PATH_SEPARATOR;
}
- return s;
}
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
@@ -784,43 +972,53 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
if (mixItem.StringIndex >= 0)
{
const CStringItem &item = _strings[mixItem.StringIndex];
- switch(propID)
+ switch (propID)
{
- case kpidPath: prop = GetLangPrefix(item.Lang) + L"string.txt"; break;
+ case kpidPath:
+ {
+ UString s = _resourcesPrefix;
+ AddLangPrefix(s, item.Lang);
+ s += L"string.txt";
+ prop = s;
+ break;
+ }
case kpidSize:
case kpidPackSize:
- prop = (UInt64)item.Size; break;
+ prop = (UInt64)item.FinalSize(); break;
}
}
- else if (mixItem.ResourceIndex < 0)
+ else if (mixItem.VersionIndex >= 0)
{
- const CSection &item = _sections[mixItem.SectionIndex];
- switch(propID)
+ const CByteBuffer_WithLang &item = _versionFiles[mixItem.VersionIndex];
+ switch (propID)
{
- case kpidPath: StringToProp(item.Name, prop); break;
- case kpidSize: prop = (UInt64)item.VSize; break;
- case kpidPackSize: prop = (UInt64)item.GetPackSize(); break;
- case kpidOffset: prop = item.Pa; break;
- case kpidVa: if (item.IsRealSect) prop = item.Va; break;
- case kpidMTime:
- case kpidCTime:
- TimeToProp(item.IsDebug ? item.Time : _header.Time, prop); break;
- case kpidCharacts: if (item.IsRealSect) FLAGS_TO_PROP(g_SectFlags, item.Flags, prop); break;
+ case kpidPath:
+ {
+ UString s = _resourcesPrefix;
+ AddLangPrefix(s, item.Lang);
+ s += L"version.txt";
+ prop = s;
+ break;
+ }
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)item.Size(); break;
}
}
- else
+ else if (mixItem.ResourceIndex >= 0)
{
const CResItem &item = _items[mixItem.ResourceIndex];
- switch(propID)
+ switch (propID)
{
case kpidPath:
{
- UString s = GetLangPrefix(item.Lang);
+ UString s = _resourcesPrefix;
+ AddLangPrefix(s, item.Lang);
{
const wchar_t *p = NULL;
- if (item.Type < sizeof(g_ResTypes) / sizeof(g_ResTypes[0]))
+ if (item.Type < ARRAY_SIZE(g_ResTypes))
p = g_ResTypes[item.Type];
- if (p != 0)
+ if (p)
s += p;
else
AddResNameToString(s, item.Type);
@@ -841,6 +1039,24 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
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)MyMin(item.PSize, item.VSize); 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) FLAGS_TO_PROP(g_SectFlags, item.Flags, prop); break;
+ case kpidZerosTailIsAllowed: if (!item.IsRealSect) prop = true; break;
+ }
+ }
prop.Detach(value);
return S_OK;
COM_TRY_END
@@ -858,11 +1074,11 @@ HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection)
return S_FALSE;
UInt64 pa = 0;
- int i;
+ unsigned i;
for (i = 0; i < _sections.Size(); i++)
{
const CSection &sect = _sections[i];
- if (sect.Va < debugLink.Va && debugLink.Va + debugLink.Size <= sect.Va + sect.PSize)
+ if (sect.Va <= debugLink.Va && debugLink.Va + debugLink.Size <= sect.Va + sect.PSize)
{
pa = sect.Pa + (debugLink.Va - sect.Va);
break;
@@ -870,19 +1086,18 @@ HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection)
}
if (i == _sections.Size())
{
- return S_OK;
// Exe for ARM requires S_OK
// return S_FALSE;
+ return S_OK;
}
- CByteBuffer buffer;
- buffer.SetCapacity(debugLink.Size);
+ 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 < (int)numItems; i++)
+ for (i = 0; i < numItems; i++)
{
CDebugEntry de;
de.Parse(buf);
@@ -890,20 +1105,19 @@ HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection)
if (de.Size == 0)
continue;
- CSection sect;
- sect.Name = ".debug" + GetDecString(i);
-
- sect.IsDebug = true;
- sect.Time = de.Time;
- sect.Va = de.Va;
- sect.Pa = de.Pa;
- sect.PSize = sect.VSize = de.Size;
- UInt32 totalSize = sect.Pa + sect.PSize;
+ UInt32 totalSize = de.Pa + de.Size;
if (totalSize > _totalSize)
{
_totalSize = totalSize;
- _sections.Add(sect);
thereIsSection = true;
+
+ CSection &sect = _sections.AddNew();
+ sect.Name = ".debug" + GetDecString(i);
+ sect.IsDebug = true;
+ sect.Time = de.Time;
+ sect.Va = de.Va;
+ sect.Pa = de.Pa;
+ sect.PSize = sect.VSize = de.Size;
}
buf += kEntrySize;
}
@@ -911,31 +1125,13 @@ HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection)
return S_OK;
}
-HRESULT CHandler::ReadString(UInt32 offset, UString &dest) const
-{
- if ((offset & 1) != 0 || offset >= _buf.GetCapacity())
- return S_FALSE;
- size_t rem = _buf.GetCapacity() - offset;
- if (rem < 2)
- return S_FALSE;
- unsigned length = Get16(_buf + offset);
- if ((rem - 2) / 2 < length)
- return S_FALSE;
- dest.Empty();
- offset += 2;
- for (unsigned i = 0; i < length; i++)
- dest += (wchar_t)Get16(_buf + offset + i * 2);
- return S_OK;
-}
-
HRESULT CHandler::ReadTable(UInt32 offset, CRecordVector<CTableItem> &items)
{
- if ((offset & 3) != 0 || offset >= _buf.GetCapacity())
+ if ((offset & 3) != 0 || offset >= _buf.Size())
return S_FALSE;
- size_t rem = _buf.GetCapacity() - offset;
+ size_t rem = _buf.Size() - offset;
if (rem < 16)
return S_FALSE;
- items.Clear();
unsigned numNameItems = Get16(_buf + offset + 12);
unsigned numIdItems = Get16(_buf + offset + 14);
unsigned numItems = numNameItems + numIdItems;
@@ -944,25 +1140,23 @@ HRESULT CHandler::ReadTable(UInt32 offset, CRecordVector<CTableItem> &items)
if (!_usedRes.SetRange(offset, 16 + numItems * 8))
return S_FALSE;
offset += 16;
- _oneLang = true;
- unsigned i;
- for (i = 0; i < numItems; i++)
+ items.ClearAndReserve(numItems);
+ for (unsigned i = 0; i < numItems; i++, offset += 8)
{
- CTableItem item;
const Byte *buf = _buf + offset;
- offset += 8;
+ CTableItem item;
item.ID = Get32(buf + 0);
- if (((item.ID & kFlag) != 0) != (i < numNameItems))
+ if ((bool)((item.ID & kFlag) != 0) != (bool)(i < numNameItems))
return S_FALSE;
item.Offset = Get32(buf + 4);
- items.Add(item);
+ items.AddInReserved(item);
}
return S_OK;
}
static const UInt32 kFileSizeMax = (UInt32)1 << 30;
-static const int kNumResItemsMax = (UInt32)1 << 23;
-static const int kNumStringLangsMax = 128;
+static const unsigned kNumResItemsMax = (unsigned)1 << 23;
+static const unsigned kNumStringLangsMax = 256;
// BITMAPINFOHEADER
struct CBitmapInfoHeader
@@ -984,12 +1178,12 @@ bool CBitmapInfoHeader::Parse(const Byte *p, size_t size)
{
if (size < kBitmapInfoHeader_Size || Get32(p) != kBitmapInfoHeader_Size)
return false;
- XSize = Get32(p + 4);
- YSize = (Int32)Get32(p + 8);
- Planes = Get16(p + 12);
- BitCount = Get16(p + 14);
- Compression = Get32(p + 16);
- SizeImage = Get32(p + 20);
+ G32( 4, XSize);
+ G32( 8, YSize);
+ G16(12, Planes);
+ G16(14, BitCount);
+ G32(16, Compression);
+ G32(20, SizeImage);
return true;
}
@@ -1089,7 +1283,7 @@ bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 si
if ((size & 1) != 0)
return false;
- int i;
+ unsigned i;
for (i = 0; i < _strings.Size(); i++)
if (_strings[i].Lang == lang)
break;
@@ -1097,10 +1291,8 @@ bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 si
{
if (_strings.Size() >= kNumStringLangsMax)
return false;
- CStringItem item;
- item.Size = 0;
+ CStringItem &item = _strings.AddNew();
item.Lang = lang;
- i = _strings.Add(item);
}
CStringItem &item = _strings[i];
@@ -1117,22 +1309,584 @@ bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 si
if (size - pos < len * 2)
return false;
char temp[32];
- ConvertUInt32ToString(id + i, temp);
+ ConvertUInt32ToString(id + i, temp);
size_t tempLen = strlen(temp);
size_t j;
for (j = 0; j < tempLen; j++)
item.AddChar(temp[j]);
item.AddChar('\t');
for (j = 0; j < len; j++, pos += 2)
- item.AddWChar(Get16(src + pos));
- item.AddChar(0x0D);
- item.AddChar(0x0A);
+ item.AddWChar_Smart(Get16(src + pos));
+ item.NewLine();
+ }
+ }
+ if (size == pos)
+ return true;
+
+ // Some rare case files have additional ZERO.
+ if (size == pos + 2 && Get16(src + pos) == 0)
+ return true;
+
+ return false;
+}
+
+
+// ---------- VERSION ----------
+
+static const UInt32 kMy_VS_FFI_SIGNATURE = 0xFEEF04BD;
+
+struct CMy_VS_FIXEDFILEINFO
+{
+ // UInt32 Signature;
+ // UInt32 StrucVersion;
+ UInt32 VersionMS;
+ UInt32 VersionLS;
+ UInt32 ProductVersionMS;
+ UInt32 ProductVersionLS;
+ UInt32 FlagsMask;
+ UInt32 Flags;
+ UInt32 OS;
+ UInt32 Type;
+ UInt32 Subtype;
+ UInt32 DateMS;
+ UInt32 DateLS;
+
+ bool Parse(const Byte *p);
+ void PrintToTextFile(CTextFile &f, CObjectVector<CStringKeyValue> &keys);
+};
+
+bool CMy_VS_FIXEDFILEINFO::Parse(const Byte *p)
+{
+ if (Get32(p) != kMy_VS_FFI_SIGNATURE) // signature;
+ return false;
+ // G32(0x04, StrucVersion);
+ G32(0x08, VersionMS);
+ G32(0x0C, VersionLS);
+ G32(0x10, ProductVersionMS);
+ G32(0x14, ProductVersionLS);
+ G32(0x18, FlagsMask);
+ G32(0x1C, Flags);
+ G32(0x20, OS);
+ G32(0x24, Type);
+ G32(0x28, Subtype);
+ G32(0x2C, DateMS);
+ G32(0x40, DateLS);
+ return true;
+}
+
+static void PrintUInt32(CTextFile &f, UInt32 v)
+{
+ char s[16];
+ ConvertUInt32ToString(v, s);
+ f.AddString(s);
+}
+
+static void PrintUInt32(UString &dest, UInt32 v)
+{
+ wchar_t s[16];
+ ConvertUInt32ToString(v, s);
+ dest += s;
+}
+
+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 += L'.';
+ PrintUInt32(s, LOWORD(ms)); s += L'.';
+ PrintUInt32(s, HIWORD(ls)); s += L'.';
+ PrintUInt32(s, LOWORD(ls));
+}
+
+static const char *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 *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 *k_VS_FileOS_Low[] =
+{
+ "VOS__BASE"
+ , "VOS__WINDOWS16"
+ , "VOS__PM16"
+ , "VOS__PM32"
+ , "VOS__WINDOWS32"
+};
+
+static const char *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 *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 *k_VS_FileSubType_FONT[] =
+{
+ "0"
+ , "VFT2_FONT_RASTER"
+ , "VFT2_FONT_VECTOR"
+ , "VFT2_FONT_TRUETYPE"
+};
+
+static int FindKey(CObjectVector<CStringKeyValue> &v, const UString &key)
+{
+ FOR_VECTOR (i, v)
+ if (v[i].Key == key)
+ return i;
+ return -1;
+}
+
+static void AddToUniqueUStringVector(CObjectVector<CStringKeyValue> &v, const UString &key, const UString &value)
+{
+ bool needInsert = false;
+ unsigned i;
+ for (i = 0; i < v.Size(); i++)
+ {
+ if (v[i].Key == key)
+ {
+ if (v[i].Value == value)
+ return;
+ needInsert = true;
+ }
+ else if (needInsert)
+ break;
+ }
+ CStringKeyValue &pair = v.InsertNew(i);
+ pair.Key = key;
+ pair.Value = value;
+}
+
+void CMy_VS_FIXEDFILEINFO::PrintToTextFile(CTextFile &f, CObjectVector<CStringKeyValue> &keys)
+{
+ f.AddString("FILEVERSION ");
+ PrintVersion(f, VersionMS, VersionLS);
+ f.NewLine();
+
+ f.AddString("PRODUCTVERSION ");
+ PrintVersion(f, ProductVersionMS, ProductVersionLS);
+ f.NewLine();
+
+ {
+ UString s;
+ PrintVersion(s, VersionMS, VersionLS);
+ AddToUniqueUStringVector(keys, L"FileVersion", s);
+ }
+ {
+ UString s;
+ PrintVersion(s, ProductVersionMS, ProductVersionLS);
+ AddToUniqueUStringVector(keys, L"ProductVersion", s);
+ }
+
+ f.AddString("FILEFLAGSMASK ");
+ PrintHex(f, FlagsMask);
+ f.NewLine();
+
+ f.AddString("FILEFLAGS ");
+ {
+ bool wasPrinted = false;
+ for (unsigned i = 0; i < 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;
}
}
- return (size == pos);
+ 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;
+ }
}
-HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpenCallback *callback)
+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;
+ int 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 > size)
+ return false;
+ switch (Get16(p + 4))
+ {
+ case 0: IsTextValue = false; break;
+ case 1: IsTextValue = true; break;
+ default: return false;
+ }
+ StrSize = Get_Utf16Str_Len_InBytes(p + k_ResoureBlockHeader_Size, TotalLen - k_ResoureBlockHeader_Size);
+ return StrSize >= 0;
+}
+
+static void AddParamString(CTextFile &f, const Byte *p, size_t sLen)
+{
+ f.AddChar(' ');
+ f.AddChar('\"');
+ f.AddBytes(p, sLen);
+ f.AddChar('\"');
+}
+
+static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector<CStringKeyValue> &keys)
+{
+ UInt32 pos;
+ {
+ const unsigned k_sizeof_VS_FIXEDFILEINFO = 13 * 4;
+
+ CVersionBlock vb;
+ if (!vb.Parse(p, size))
+ return false;
+ if (vb.ValueLen != k_sizeof_VS_FIXEDFILEINFO) // maybe 0 is allowed here?
+ return false;
+ if (vb.IsTextValue)
+ return false;
+ pos = k_ResoureBlockHeader_Size;
+ if (!CompareWStrStrings(p + pos, "VS_VERSION_INFO"))
+ return false;
+ pos += vb.StrSize + 2;
+ pos += (4 - pos) & 3;
+ if (pos + vb.ValueLen > vb.TotalLen)
+ return false;
+ /* sometimes resource contains zeros in remainder.
+ So we don't check that size != vb.TotalLen
+ // if (size != vb.TotalLen) return false;
+ */
+ if (size > vb.TotalLen)
+ size = vb.TotalLen;
+ CMy_VS_FIXEDFILEINFO FixedFileInfo;
+ if (!FixedFileInfo.Parse(p + pos))
+ return false;
+ FixedFileInfo.PrintToTextFile(f, keys);
+ pos += vb.ValueLen;
+ }
+
+ f.OpenBlock(0);
+
+ for (;;)
+ {
+ pos += (4 - pos) & 3;
+ if (pos >= size)
+ break;
+
+ CVersionBlock vb;
+ if (!vb.Parse(p + pos, size - pos))
+ return false;
+ if (vb.ValueLen != 0)
+ return false;
+ UInt32 endPos = pos + vb.TotalLen;
+ pos += k_ResoureBlockHeader_Size;
+
+ f.AddSpaces(2);
+ f.AddString("BLOCK");
+ AddParamString(f, p + pos, vb.StrSize);
+
+ f.NewLine();
+ f.OpenBlock(2);
+
+ if (CompareWStrStrings(p + pos, "VarFileInfo"))
+ {
+ pos += vb.StrSize + 2;
+ for (;;)
+ {
+ pos += (4 - pos) & 3;
+ if (pos >= endPos)
+ break;
+ CVersionBlock vb2;
+ if (!vb2.Parse(p + pos, endPos - pos))
+ return false;
+ UInt32 endPos2 = pos + vb2.TotalLen;
+ if (vb2.IsTextValue)
+ return false;
+ pos += k_ResoureBlockHeader_Size;
+ f.AddSpaces(4);
+ f.AddString("VALUE");
+ AddParamString(f, p + pos, vb2.StrSize);
+ if (!CompareWStrStrings(p + pos, "Translation"))
+ return false;
+ pos += vb2.StrSize + 2;
+ pos += (4 - pos) & 3;
+ if (pos + vb2.ValueLen != endPos2)
+ return false;
+ if ((vb2.ValueLen & 3) != 0)
+ return false;
+ UInt32 num = (vb2.ValueLen >> 2);
+ for (; num != 0; num--, pos += 4)
+ {
+ UInt32 dw = Get32(p + pos);
+ UInt32 lang = LOWORD(dw);
+ UInt32 codePage = HIWORD(dw);
+
+ f.AddString(", ");
+ PrintHex(f, lang);
+ f.AddString(", ");
+ PrintUInt32(f, codePage);
+ }
+ f.NewLine();
+ }
+ }
+ else
+ {
+ if (!CompareWStrStrings(p + pos, "StringFileInfo"))
+ return false;
+ pos += vb.StrSize + 2;
+
+ for (;;)
+ {
+ pos += (4 - pos) & 3;
+ if (pos >= endPos)
+ break;
+ CVersionBlock vb2;
+ if (!vb2.Parse(p + pos, endPos - pos))
+ return false;
+ UInt32 endPos2 = pos + vb2.TotalLen;
+ if (vb2.ValueLen != 0)
+ return false;
+ pos += k_ResoureBlockHeader_Size;
+
+ f.AddSpaces(4);
+ f.AddString("BLOCK");
+ AddParamString(f, p + pos, vb2.StrSize);
+ pos += vb2.StrSize + 2;
+
+ f.NewLine();
+ f.OpenBlock(4);
+
+ for (;;)
+ {
+ pos += (4 - pos) & 3;
+ if (pos >= endPos2)
+ break;
+
+ CVersionBlock vb3;
+ if (!vb3.Parse(p + pos, endPos2 - pos))
+ return false;
+ // ValueLen sometimes is a number of characters (not bytes)?
+ // So we don't use it.
+ UInt32 endPos3 = pos + vb3.TotalLen;
+ pos += k_ResoureBlockHeader_Size;
+
+ // we don't write string if it's not text
+ if (vb3.IsTextValue)
+ {
+ f.AddSpaces(6);
+ f.AddString("VALUE");
+ AddParamString(f, p + pos, vb3.StrSize);
+ UString key;
+ UString value;
+ CopyToUString(p + pos, key);
+ pos += vb3.StrSize + 2;
+
+ pos += (4 - pos) & 3;
+ if (vb3.ValueLen > 0 && pos + 2 <= endPos3)
+ {
+ f.AddChar(',');
+ f.AddSpaces((34 - (int)vb3.StrSize) / 2);
+ int sLen = Get_Utf16Str_Len_InBytes(p + pos, endPos3 - pos);
+ if (sLen < 0)
+ return false;
+ AddParamString(f, p + pos, 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 &sect = _sections[sectionIndex];
size_t fileSize = sect.PSize; // Maybe we need sect.VSize here !!!
@@ -1143,13 +1897,13 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe
if (callback)
RINOK(callback->SetTotal(NULL, &fileSize64));
RINOK(stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL));
- _buf.SetCapacity(fileSize);
+ _buf.Alloc(fileSize);
for (size_t pos = 0; pos < fileSize;)
{
UInt64 offset64 = pos;
if (callback)
RINOK(callback->SetCompleted(NULL, &offset64))
- size_t rem = MyMin(fileSize - pos, (size_t)(1 << 20));
+ size_t rem = MyMin(fileSize - pos, (size_t)(1 << 22));
RINOK(ReadStream_FALSE(stream, _buf + pos, rem));
pos += rem;
}
@@ -1162,7 +1916,7 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe
_oneLang = true;
bool stringsOk = true;
size_t maxOffset = 0;
- for (int i = 0; i < specItems.Size(); i++)
+ FOR_VECTOR (i, specItems)
{
const CTableItem &item1 = specItems[i];
if ((item1.Offset & kFlag) == 0)
@@ -1171,7 +1925,7 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe
CRecordVector<CTableItem> specItems2;
RINOK(ReadTable(item1.Offset & kMask, specItems2));
- for (int j = 0; j < specItems2.Size(); j++)
+ FOR_VECTOR (j, specItems2)
{
const CTableItem &item2 = specItems2[j];
if ((item2.Offset & kFlag) == 0)
@@ -1184,14 +1938,14 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe
item.Type = item1.ID;
item.ID = item2.ID;
- for (int k = 0; k < specItems3.Size(); k++)
+ 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.GetCapacity() || _buf.GetCapacity() - item3.Offset < 16)
+ if (item3.Offset >= _buf.Size() || _buf.Size() - item3.Offset < 16)
return S_FALSE;
const Byte *buf = _buf + item3.Offset;
item.Lang = item3.ID;
@@ -1225,6 +1979,24 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe
}
}
+ 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);
}
@@ -1233,7 +2005,7 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe
if (stringsOk && !_strings.IsEmpty())
{
- int i;
+ unsigned i;
for (i = 0; i < _items.Size(); i++)
{
CResItem &item = _items[i];
@@ -1242,10 +2014,9 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe
}
for (i = 0; i < _strings.Size(); i++)
{
- if (_strings[i].Size == 0)
+ if (_strings[i].FinalSize() == 0)
continue;
CMixItem mixItem;
- mixItem.ResourceIndex = -1;
mixItem.StringIndex = i;
mixItem.SectionIndex = sectionIndex;
_mixItems.Add(mixItem);
@@ -1259,7 +2030,8 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe
{
UInt32 mask = (1 << numBits) - 1;
size_t end = ((maxOffset + mask) & ~mask);
- if (end < sect.VSize && end <= sect.PSize)
+ // 9.29: we use only PSize. PSize can be larger than VSize
+ if (/* end < sect.VSize && */ end <= sect.PSize)
{
CSection sect2;
sect2.Flags = 0;
@@ -1274,72 +2046,158 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe
sect2.Pa = sect.Pa + (UInt32)maxOffset;
sect2.Va = sect.Va + (UInt32)maxOffset;
- sect2.PSize = sect.VSize - (UInt32)maxOffset;
- sect2.VSize = sect2.PSize;
- sect2.Name = ".rsrc_1";
- sect2.Time = 0;
- sect2.IsAdditionalSection = true;
- _sections.Add(sect2);
+
+ // 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;
}
-HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
+static inline bool CheckPeOffset(UInt32 pe)
{
- const UInt32 kBufSize = 1 << 18;
- const UInt32 kSigSize = 2;
+ return (pe >= 0x40 && pe <= 0x1000 && (pe & 7) == 0);
+}
- _mainSubfile = -1;
+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 + kHeaderSize > size)
+ return k_IsArc_Res_NEED_MORE;
+ CHeader header;
+ if (!header.Parse(p + pe))
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
+}
- CByteBuffer buffer;
- buffer.SetCapacity(kBufSize);
- Byte *buf = buffer;
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
+{
+ {
+ Byte h[kStartSize];
+ _mainSubfile = -1;
+ 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;
+ }
+ {
+ Byte h[kHeaderSize];
+ RINOK(stream->Seek(_peOffset, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(stream, h, kHeaderSize));
+ if (!_header.Parse(h))
+ return S_FALSE;
+ }
- size_t processed = kSigSize;
- RINOK(ReadStream_FALSE(stream, buf, processed));
- if (buf[0] != 'M' || buf[1] != 'Z')
- return S_FALSE;
- processed = kBufSize - kSigSize;
- RINOK(ReadStream(stream, buf + kSigSize, &processed));
- processed += kSigSize;
- if (!Parse(buf, (UInt32)processed))
+ UInt32 bufSize = _header.OptHeaderSize + (UInt32)_header.NumSections * kSectionSize;
+ _totalSize = _peOffset + kHeaderSize + bufSize;
+ CByteBuffer buffer(bufSize);
+
+ RINOK(ReadStream_FALSE(stream, buffer, bufSize));
+ if (!_optHeader.Parse(buffer, _header.OptHeaderSize))
return S_FALSE;
+
+ UInt32 pos = _header.OptHeaderSize;
+ unsigned i;
+ for (i = 0; i < _header.NumSections; i++, pos += kSectionSize)
+ {
+ CSection &sect = _sections.AddNew();
+ sect.Parse(buffer + pos);
+ sect.IsRealSect = true;
+
+ /* PE pre-file in .hxs file has errors:
+ PSize of resource is larger 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;
RINOK(LoadDebugSections(stream, thereISDebug));
const CDirLink &certLink = _optHeader.DirItems[kDirLink_Certificate];
if (certLink.Size != 0)
{
- CSection sect;
+ CSection &sect = _sections.AddNew();
sect.Name = "CERTIFICATE";
sect.Va = 0;
sect.Pa = certLink.Va;
sect.PSize = sect.VSize = certLink.Size;
sect.UpdateTotalSize(_totalSize);
- _sections.Add(sect);
}
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.Free();
- buffer.SetCapacity(kAlign);
+ 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 i;
for (i = 0; i < processed; i++)
- {
if (buf[i] != 0)
break;
- }
if (processed < size && processed < 100)
_totalSize += (UInt32)processed;
else if (((_totalSize + i) & 0x1FF) == 0 || processed < size)
@@ -1351,8 +2209,6 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
{
if (_header.NumSymbols >= (1 << 24))
return S_FALSE;
- CSection sect;
- sect.Name = "COFF_SYMBOLS";
UInt32 size = _header.NumSymbols * 18;
RINOK(stream->Seek((UInt64)_header.PointerToSymbolTable + size, STREAM_SEEK_SET, NULL));
Byte buf[4];
@@ -1362,38 +2218,31 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
return S_FALSE;
size += size2;
+ CSection &sect = _sections.AddNew();
+ sect.Name = "COFF_SYMBOLS";
sect.Va = 0;
sect.Pa = _header.PointerToSymbolTable;
sect.PSize = sect.VSize = size;
sect.UpdateTotalSize(_totalSize);
- _sections.Add(sect);
}
- UInt64 fileSize;
- RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
- if (fileSize > _totalSize)
- return S_FALSE;
- _totalSizeLimited = (_totalSize < fileSize) ? _totalSize : (UInt32)fileSize;
-
{
CObjectVector<CSection> sections = _sections;
sections.Sort();
UInt32 limit = (1 << 12);
- int num = 0;
- int numSections = sections.Size();
- for (int i = 0; i < numSections; i++)
+ unsigned num = 0;
+ FOR_VECTOR(i, sections)
{
const CSection &s = sections[i];
if (s.Pa > limit)
{
- CSection s2;
+ CSection &s2 = _sections.AddNew();
s2.Pa = s2.Va = limit;
s2.PSize = s2.VSize = s.Pa - limit;
s2.IsAdditionalSection = true;
s2.Name = '[';
s2.Name += GetDecString(num++);
s2.Name += ']';
- _sections.Add(s2);
limit = s.Pa;
}
UInt32 next = s.Pa + s.PSize;
@@ -1404,10 +2253,28 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
}
}
+
+ if (_optHeader.CheckSum != 0)
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ UInt32 checkSum = 0;
+ RINOK(CalcCheckSum(stream, _totalSize, _peOffset + kHeaderSize + 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;
- int i;
for (i = 0; i < _sections.Size(); i++)
{
const CSection &sect = _sections[i];
@@ -1418,14 +2285,14 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
HRESULT res = OpenResources(i, stream, callback);
if (res == S_OK)
{
- _resourceFileName = GetUnicodeString(sect.Name);
- for (int j = 0; j < _items.Size(); j++)
+ _resourcesPrefix.SetFromAscii(sect.Name);
+ _resourcesPrefix += WCHAR_PATH_SEPARATOR;
+ FOR_VECTOR (j, _items)
{
const CResItem &item = _items[j];
if (item.Enabled)
{
mixItem.ResourceIndex = j;
- mixItem.StringIndex = -1;
if (item.IsRcDataOrUnknown())
{
if (item.Size >= mainSize)
@@ -1440,6 +2307,9 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
_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();
@@ -1450,7 +2320,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
if (sect.PSize > end)
{
- CSection sect2;
+ CSection &sect2 = _sections.AddNew();
sect2.Flags = 0;
sect2.Pa = sect.Pa + end;
sect2.Va = sect.Va + end;
@@ -1459,18 +2329,16 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
sect2.Name = ".rsrc_2";
sect2.Time = 0;
sect2.IsAdditionalSection = true;
- _sections.Add(sect2);
}
}
}
+ */
continue;
}
if (res != S_FALSE)
return res;
CloseResources();
}
- mixItem.StringIndex = -1;
- mixItem.ResourceIndex = -1;
if (sect.IsAdditionalSection)
{
if (sect.PSize >= mainSize)
@@ -1498,55 +2366,35 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
}
}
- return S_OK;
-}
-
-HRESULT CalcCheckSum(ISequentialInStream *stream, UInt32 size, UInt32 excludePos, UInt32 &res)
-{
- // size &= ~1;
- const UInt32 kBufSize = 1 << 23;
- CByteBuffer buffer;
- buffer.SetCapacity(kBufSize);
- Byte *buf = buffer;
-
- UInt32 sum = 0;
- UInt32 pos = 0;
- for (;;)
+ for (i = 0; i < _versionKeys.Size(); i++)
{
- UInt32 rem = size - pos;
- if (rem > kBufSize)
- rem = kBufSize;
- if (rem == 0)
- break;
- size_t processed = rem;
- RINOK(ReadStream(stream, buf, &processed));
-
- /*
- for (; processed < rem; processed++)
- buf[processed] = 0;
- */
-
- if ((processed & 1) != 0)
- buf[processed] = 0;
-
- for (int j = 0; j < 4; j++)
- {
- UInt32 p = excludePos + j;
- if (pos <= p && p < pos + processed)
- buf[p - pos] = 0;
- }
+ if (i != 0)
+ _versionFullString += L'\n';
+ const CStringKeyValue &k = _versionKeys[i];
+ _versionFullString += k.Key;
+ _versionFullString += L": ";
+ _versionFullString += k.Value;
+ }
- for (size_t i = 0; i < processed; i += 2)
+ {
+ int keyIndex = FindKey(_versionKeys, L"OriginalFilename");
+ if (keyIndex >= 0)
+ _originalFilename = _versionKeys[keyIndex].Value;
+ }
+ {
+ int keyIndex = FindKey(_versionKeys, L"FileDescription");
+ if (keyIndex >= 0)
+ _versionShortString = _versionKeys[keyIndex].Value;
+ }
+ {
+ int keyIndex = FindKey(_versionKeys, L"FileVersion");
+ if (keyIndex >= 0)
{
- sum += Get16(buf + i);
- sum = (sum + (sum >> 16)) & 0xFFFF;
+ _versionShortString += L' ';
+ _versionShortString += _versionKeys[keyIndex].Value;
}
- pos += (UInt32)processed;
- if (rem != processed)
- break;
}
- sum += pos;
- res = sum;
+
return S_OK;
}
@@ -1565,11 +2413,18 @@ void CHandler::CloseResources()
_usedRes.Free();
_items.Clear();
_strings.Clear();
- _buf.SetCapacity(0);
+ _versionFiles.Clear();
+ _buf.Free();
+ _versionFullString.Empty();
+ _versionShortString.Empty();
+ _originalFilename.Empty();
+ _versionKeys.Clear();
}
STDMETHODIMP CHandler::Close()
{
+ _totalSize = 0;
+ _checksumError = false;
_stream.Release();
_sections.Clear();
_mixItems.Clear();
@@ -1587,7 +2442,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _mixItems.Size();
if (numItems == 0)
@@ -1597,12 +2452,16 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
for (i = 0; i < numItems; i++)
{
const CMixItem &mixItem = _mixItems[allFilesMode ? i : indices[i]];
+ UInt64 size;
if (mixItem.StringIndex >= 0)
- totalSize += _strings[mixItem.StringIndex].Size;
- else if (mixItem.ResourceIndex < 0)
- totalSize += _sections[mixItem.SectionIndex].GetPackSize();
+ 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
- totalSize += _items[mixItem.ResourceIndex].GetSize();
+ size = _sections[mixItem.SectionIndex].PSize;
+ totalSize += size;
}
extractCallback->SetTotal(totalSize);
@@ -1616,15 +2475,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
- bool checkSumOK = true;
- if (_optHeader.CheckSum != 0 && (int)numItems == _mixItems.Size())
- {
- UInt32 checkSum = 0;
- RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
- CalcCheckSum(_stream, _totalSizeLimited, _peOffset + kHeaderSize + 64, checkSum);
- checkSumOK = (checkSum == _optHeader.CheckSum);
- }
-
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
CMyComPtr<ISequentialInStream> inStream(streamSpec);
streamSpec->SetStream(_stream);
@@ -1647,27 +2497,26 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (mixItem.StringIndex >= 0)
{
const CStringItem &item = _strings[mixItem.StringIndex];
- currentItemSize = item.Size;
+ currentItemSize = item.FinalSize();
if (!testMode && !outStream)
continue;
RINOK(extractCallback->PrepareOperation(askMode));
if (outStream)
- RINOK(WriteStream(outStream, item.Buf, item.Size));
+ RINOK(WriteStream(outStream, item.Buf, item.FinalSize()));
}
- else if (mixItem.ResourceIndex < 0)
+ else if (mixItem.VersionIndex >= 0)
{
- currentItemSize = sect.GetPackSize();
+ const CByteBuffer &item = _versionFiles[mixItem.VersionIndex];
+ currentItemSize = item.Size();
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);
+ if (outStream)
+ RINOK(WriteStream(outStream, item, item.Size()));
}
- else
+ else if (mixItem.ResourceIndex >= 0)
{
const CResItem &item = _items[mixItem.ResourceIndex];
currentItemSize = item.GetSize();
@@ -1685,12 +2534,22 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(WriteStream(outStream, _buf + offset, item.Size));
}
}
+ else
+ {
+ currentItemSize = sect.PSize;
+ 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 ?
- checkSumOK ?
- NExtract::NOperationResult::kOK:
- NExtract::NOperationResult::kCRCError:
+ NExtract::NOperationResult::kOK :
NExtract::NOperationResult::kDataError));
}
return S_OK;
@@ -1714,8 +2573,12 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
if (mixItem.StringIndex >= 0)
{
const CStringItem &item = _strings[mixItem.StringIndex];
- referenceBuf->Buf.SetCapacity(item.Size);
- memcpy(referenceBuf->Buf, item.Buf, item.Size);
+ 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
{
@@ -1731,7 +2594,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
*stream = streamTemp2.Detach();
return S_OK;
}
- referenceBuf->Buf.SetCapacity(item.HeaderSize + item.Size);
+ referenceBuf->Buf.Alloc(item.HeaderSize + item.Size);
memcpy(referenceBuf->Buf, item.Header, item.HeaderSize);
memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size);
}
@@ -1742,10 +2605,20 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+STDMETHODIMP CHandler::AllowTail(Int32 allowTail)
+{
+ _allowTail = IntToBool(allowTail);
+ return S_OK;
+}
+
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"PE", L"exe dll sys", 0, 0xDD, { 'P', 'E', 0, 0 }, 4, false, CreateArc, 0 };
+ { "PE", "exe dll sys", 0, 0xDD,
+ 2, { 'M', 'Z' },
+ 0,
+ NArcInfoFlags::kPreArc,
+ CreateArc, NULL, IsArc_Pe };
REGISTER_ARC(Pe)
@@ -1758,13 +2631,17 @@ 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;
@@ -1776,8 +2653,10 @@ static bool FindValue(const CUInt32PCharPair *pairs, unsigned num, UInt32 value)
return false;
}
-#define MY_FIND_VALUE(pairs, value) FindValue(pairs, sizeof(pairs) / sizeof(pairs[0]), value)
+#define MY_FIND_VALUE(pairs, value) FindValue(pairs, ARRAY_SIZE(pairs), value)
+static const UInt32 kNumSection_MAX = 32;
+
struct CHeader
{
UInt16 Machine;
@@ -1788,41 +2667,65 @@ struct CHeader
UInt32 AddressOfEntryPoint;
UInt32 BaseOfCode;
UInt64 ImageBase;
- CDataDir DataDir[2]; // base relocation and debug directory
*/
+ CDataDir DataDir[2]; // base relocation and debug directory
- UInt32 ConvertPa(UInt32 pa) const { return pa - StrippedSize + kHeaderSize; }
+ bool ConvertPa(UInt32 &pa) const
+ {
+ if (pa < StrippedSize)
+ return false;
+ pa = pa - StrippedSize + kHeaderSize;
+ return true;
+ }
+ bool Parse(const Byte *p);
+};
- 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++)
{
- if (p[0] != 'V' || p[1] != 'Z')
+ CDataDir &dd = DataDir[i];
+ dd.Parse(p + 24 + i * 8);
+ if (dd.Size >= ((UInt32)1 << 28))
return false;
- Machine = Get16(p + 2);
- NumSections = p[4];
- SubSystem = p[5];
- StrippedSize = Get16(p + 6);
- /*
- AddressOfEntryPoint = Get32(p + 8);
- BaseOfCode = Get32(p + 12);
- ImageBase = Get64(p + 16);
- for (int i = 0; i < 2; i++)
- {
- const Byte *p2 = p + 24 + i * 8;
- DataDir[i].Va = Get32(p2);
- DataDir[i].Size = Get32(p2 + 4);
- }
- */
- return NumSections <= 64 &&
+ }
+ return
MY_FIND_VALUE(NPe::g_MachinePairs, Machine) &&
MY_FIND_VALUE(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[8];
+ Byte Name[NPe::kNameSize];
- // UInt32 VSize;
+ UInt32 VSize;
UInt32 Va;
UInt32 PSize;
UInt32 Pa;
@@ -1831,16 +2734,21 @@ struct CSection
void Parse(const Byte *p)
{
- memcpy(Name, p, 8);
- // VSize = Get32(p + 8);
- Va = Get32(p + 12);
- PSize = Get32(p + 16);
- Pa = Get32(p + 20);
- // NumRelocs = Get16(p + 32);
- Flags = Get32(p + 36);
+ 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 (PSize + Pa > Pa); }
+ bool Check() const
+ {
+ return
+ Pa <= ((UInt32)1 << 30) &&
+ PSize <= ((UInt32)1 << 30);
+ }
void UpdateTotalSize(UInt32 &totalSize)
{
@@ -1853,44 +2761,46 @@ struct CSection
class CHandler:
public IInArchive,
public IInArchiveGetStream,
+ public IArchiveAllowTail,
public CMyUnknownImp
{
- UInt32 _totalSize;
+ CRecordVector<CSection> _items;
CMyComPtr<IInStream> _stream;
- CObjectVector<CSection> _items;
+ UInt32 _totalSize;
+ bool _allowTail;
CHeader _h;
- UInt64 _fileSize;
HRESULT Open2(IInStream *stream);
public:
- MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IArchiveAllowTail)
INTERFACE_IInArchive(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+ STDMETHOD(AllowTail)(Int32 allowTail);
+ CHandler(): _allowTail(false) {}
};
-static const STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI4},
- { NULL, kpidPackSize, VT_UI4},
- { NULL, kpidCharacts, VT_BSTR},
- { NULL, kpidOffset, VT_UI4},
- { NULL, kpidVa, VT_UI8}
+ kpidPath,
+ kpidSize,
+ kpidVirtualSize,
+ kpidCharacts,
+ kpidOffset,
+ kpidVa
};
enum
{
- kpidSubSystem
+ kpidSubSystem = kpidUserDefined,
// , kpidImageBase
};
static const STATPROPSTG kArcProps[] =
{
- { NULL, kpidPhySize, VT_UI4},
- // { NULL, kpidHeadersSize, VT_UI4},
+ // { NULL, kpidHeadersSize, VT_UI4 },
{ NULL, kpidCpu, VT_BSTR},
- { L"Subsystem", kpidSubSystem, VT_BSTR},
- // { L"Image Base", kpidImageBase, VT_UI8}
+ { L"Subsystem", kpidSubSystem, VT_BSTR },
+ // { L"Image Base", kpidImageBase, VT_UI8 }
};
IMP_IInArchive_Props
@@ -1900,7 +2810,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidPhySize: prop = _totalSize; break;
case kpidCpu: PAIR_TO_PROP(NPe::g_MachinePairs, _h.Machine, prop); break;
@@ -1922,11 +2832,12 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
NCOM::CPropVariant prop;
{
const CSection &item = _items[index];
- switch(propID)
+ switch (propID)
{
- case kpidPath: StringToProp(NPe::GetName(item.Name), prop); break;
+ case kpidPath: prop = MultiByteToUnicodeString(NPe::GetName(item.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;
@@ -1941,28 +2852,41 @@ 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;
- CByteBuffer buf;
- UInt32 headerSize = NPe::kSectionSize * _h.NumSections;
- buf.SetCapacity(headerSize);
+ UInt32 headerSize = NPe::kSectionSize * (UInt32)_h.NumSections;
+ CByteArr buf(headerSize);
RINOK(ReadStream_FALSE(stream, buf, headerSize));
+ headerSize += kHeaderSize;
- _totalSize = kHeaderSize + headerSize;
-
- for (UInt32 i = 0; i < headerSize; i += NPe::kSectionSize)
+ _totalSize = headerSize;
+ _items.ClearAndReserve(_h.NumSections);
+ for (UInt32 i = 0; i < _h.NumSections; i++)
{
CSection sect;
- sect.Parse(buf + i);
- sect.Pa = _h.ConvertPa(sect.Pa);
- _items.Add(sect);
- sect.UpdateTotalSize(_totalSize);
+ 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);
}
- return stream->Seek(0, STREAM_SEEK_END, &_fileSize);
+ 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,
@@ -1984,9 +2908,9 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
STDMETHODIMP CHandler::Close()
{
+ _totalSize = 0;
_stream.Release();
_items.Clear();
- _totalSize = 0;
return S_OK;
}
@@ -2000,7 +2924,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items.Size();
if (numItems == 0)
@@ -2041,22 +2965,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
continue;
RINOK(extractCallback->PrepareOperation(askMode));
int res = NExtract::NOperationResult::kDataError;
- if (item.Pa <= _fileSize)
- {
- if (testMode)
- {
- if (item.Pa + item.PSize <= _fileSize)
- res = NExtract::NOperationResult::kOK;
- }
- else
- {
- 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;
- }
- }
+
+ 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));
}
@@ -2072,10 +2987,20 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+STDMETHODIMP CHandler::AllowTail(Int32 allowTail)
+{
+ _allowTail = IntToBool(allowTail);
+ return S_OK;
+}
+
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"TE", L"te", 0, 0xCF, { 'V', 'Z' }, 2, false, CreateArc, 0 };
+ { "TE", "te", 0, 0xCF,
+ 2, { 'V', 'Z' },
+ 0,
+ NArcInfoFlags::kPreArc,
+ CreateArc, NULL, IsArc_Te };
REGISTER_ARC(TE)
diff --git a/CPP/7zip/Archive/PpmdHandler.cpp b/CPP/7zip/Archive/PpmdHandler.cpp
index 9b2ef048..70e9ffac 100755..100644
--- a/CPP/7zip/Archive/PpmdHandler.cpp
+++ b/CPP/7zip/Archive/PpmdHandler.cpp
@@ -11,12 +11,12 @@ This code is based on:
#include "../../../C/Ppmd7.h"
#include "../../../C/Ppmd8.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/StringConvert.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/StringConvert.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
#include "../Common/CWrappers.h"
#include "../Common/ProgressUtils.h"
@@ -75,11 +75,12 @@ HRESULT CItem::ReadHeader(ISequentialInStream *s, UInt32 &headerSize)
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;
@@ -104,8 +105,8 @@ class CHandler:
{
CItem _item;
UInt32 _headerSize;
+ bool _packSize_Defined;
UInt64 _packSize;
- bool _packSizeDefined;
CMyComPtr<ISequentialInStream> _stream;
public:
@@ -114,12 +115,12 @@ public:
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
};
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidAttrib, VT_UI4},
- { NULL, kpidMethod, VT_BSTR}
+ kpidPath,
+ kpidMTime,
+ kpidAttrib,
+ kpidMethod
};
IMP_IInArchive_Props
@@ -128,9 +129,9 @@ IMP_IInArchive_ArcProps_NO_Table
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
- case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidPhySize: if (_packSize_Defined) prop = _packSize; break;
}
prop.Detach(value);
return S_OK;
@@ -151,22 +152,23 @@ static void UIntToString(AString &s, const char *prefix, unsigned value)
s += temp;
}
-STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ 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 (_packSizeDefined) prop = _packSize; break;
+ case kpidPackSize: if (_packSize_Defined) prop = _packSize; break;
case kpidMethod:
{
AString s = "PPMd";
@@ -209,7 +211,8 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
STDMETHODIMP CHandler::Close()
{
- _packSizeDefined = false;
+ _packSize = 0;
+ _packSize_Defined = false;
_stream.Release();
return S_OK;
}
@@ -356,7 +359,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
if (numItems == 0)
return S_OK;
- if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
// extractCallback->SetTotal(_packSize);
@@ -388,7 +391,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CPpmdCpp ppmd(_item.Ver);
if (!ppmd.Alloc(_item.MemInMB))
return E_OUTOFMEMORY;
- Int32 opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ Int32 opRes = NExtract::NOperationResult::kUnsupportedMethod;
if (_item.IsSupported())
{
opRes = NExtract::NOperationResult::kDataError;
@@ -428,7 +431,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
outSize += i;
_packSize = _headerSize + inBuf.GetProcessed();
- _packSizeDefined = true;
+ _packSize_Defined = true;
if (realOutStream)
{
RINOK(WriteStream(realOutStream, outBuf.Buf, i));
@@ -446,10 +449,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
return extractCallback->SetOperationResult(opRes);
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"Ppmd", L"pmd", 0, 0xD, { 0x8F, 0xAF, 0xAC, 0x84 }, 4, false, CreateArc, 0 };
+ { "Ppmd", "pmd", 0, 0xD,
+ 4, { 0x8F, 0xAF, 0xAC, 0x84 },
+ 0,
+ 0,
+ CreateArc };
REGISTER_ARC(Ppmd)
diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp
index 5d072d34..c4adee41 100755..100644
--- a/CPP/7zip/Archive/Rar/RarHandler.cpp
+++ b/CPP/7zip/Archive/Rar/RarHandler.cpp
@@ -2,50 +2,104 @@
#include "StdAfx.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/StringConvert.h"
+#include "../../../../C/CpuArch.h"
-#include "Windows/PropVariant.h"
-#include "Windows/PropVariantUtils.h"
-#include "Windows/Time.h"
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.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 "RarHandler.h"
using namespace NWindows;
-using namespace NTime;
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
namespace NArchive {
namespace NRar {
-static const wchar_t *kHostOS[] =
+#define SIGNATURE { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }
+
+static const Byte kMarker[NHeader::kMarkerSize] = SIGNATURE;
+
+bool CItem::IgnoreItem() const
{
- L"MS DOS",
- L"OS/2",
- L"Win32",
- L"Unix",
- L"Mac OS",
- L"BeOS"
-};
+ 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;
+}
-static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);
+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 *kHostOS[] =
+{
+ "MS DOS"
+ , "OS/2"
+ , "Win32"
+ , "Unix"
+ , "Mac OS"
+ , "BeOS"
+};
-static const wchar_t *kUnknownOS = L"Unknown";
+static const char *kUnknownOS = "Unknown";
static const CUInt32PCharPair k_Flags[] =
{
@@ -61,75 +115,771 @@ static const CUInt32PCharPair k_Flags[] =
{ 9, "EncryptVer" }
};
-static const STATPROPSTG kProps[] =
-{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidCTime, VT_FILETIME},
- { NULL, kpidATime, VT_FILETIME},
- { NULL, kpidAttrib, VT_UI4},
-
- { NULL, kpidEncrypted, VT_BOOL},
- { NULL, kpidSolid, VT_BOOL},
- { NULL, kpidCommented, VT_BOOL},
- { NULL, kpidSplitBefore, VT_BOOL},
- { NULL, kpidSplitAfter, VT_BOOL},
- { NULL, kpidCRC, VT_UI4},
- { NULL, kpidHostOS, VT_BSTR},
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidUnpackVer, VT_UI1}
+enum EErrorType
+{
+ k_ErrorType_OK,
+ k_ErrorType_Corrupted,
+ k_ErrorType_UnexpectedEnd,
+ k_ErrorType_DecryptionError
};
-static const STATPROPSTG kArcProps[] =
+class CInArchive
{
- { NULL, kpidCharacts, VT_BSTR},
- { NULL, kpidSolid, VT_BOOL},
- { NULL, kpidNumBlocks, VT_UI4},
- // { NULL, kpidEncrypted, VT_BOOL},
- { NULL, kpidIsVolume, VT_BOOL},
- { NULL, kpidNumVolumes, VT_UI4},
- { NULL, kpidPhySize, VT_UI8}
- // { NULL, kpidCommented, VT_BOOL}
+ IInStream *m_Stream;
+ UInt64 m_StreamStartPosition;
+ CBuffer<wchar_t> _unicodeNameBuffer;
+ CByteBuffer _comment;
+ CByteBuffer m_FileHeaderData;
+ NHeader::NBlock::CBlock m_BlockHeader;
+ NCrypto::NRar29::CDecoder *m_RarAESSpec;
+ CMyComPtr<ICompressFilter> m_RarAES;
+ CBuffer<Byte> m_DecryptedData;
+ Byte *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 void 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;
+ Byte highByte = encName[encPos++];
+ while (encPos < encSize && decPos < maxDecSize)
+ {
+ if (flagBits == 0)
+ {
+ flags = encName[encPos++];
+ flagBits = 8;
+ }
+ switch (flags >> 6)
+ {
+ case 0:
+ unicodeName[decPos++] = encName[encPos++];
+ break;
+ case 1:
+ unicodeName[decPos++] = (wchar_t)(encName[encPos++] + (highByte << 8));
+ break;
+ case 2:
+ unicodeName[decPos++] = (wchar_t)(encName[encPos] + (encName[encPos + 1] << 8));
+ encPos += 2;
+ break;
+ case 3:
+ {
+ unsigned len = encName[encPos++];
+ if (len & 0x80)
+ {
+ Byte correction = encName[encPos++];
+ for (len = (len & 0x7f) + 2;
+ len > 0 && decPos < maxDecSize; len--, decPos++)
+ unicodeName[decPos] = (wchar_t)(((name[decPos] + correction) & 0xff) + (highByte << 8));
+ }
+ else
+ for (len += 2; len > 0 && decPos < maxDecSize; len--, decPos++)
+ unicodeName[decPos] = name[decPos];
+ }
+ break;
+ }
+ flags <<= 2;
+ flagBits -= 2;
+ }
+ unicodeName[decPos < maxDecSize ? decPos : maxDecSize - 1] = 0;
+}
+
+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);
+ _unicodeNameBuffer.AllocAtLeast(uNameSizeMax + 1);
+ DecodeUnicodeFileName(p, p + i, nameSize - i, _unicodeNameBuffer, uNameSizeMax);
+ 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 += size2, size -= 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);
+ 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 = L".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::NRar29::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((BSTR)password);
+ CByteBuffer 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);
+ }
+
+ RINOK(m_RarAESSpec->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size()));
+
+ const UInt32 kDecryptedBufferSize = (1 << 12);
+ if (m_DecryptedData.Size() == 0)
+ {
+ const UInt32 kAlign = 16;
+ m_DecryptedData.Alloc(kDecryptedBufferSize + kAlign);
+ m_DecryptedDataAligned = (Byte *)((ptrdiff_t)((Byte *)m_DecryptedData + kAlign - 1) & ~(ptrdiff_t)(kAlign - 1));
+ }
+ RINOK(m_RarAES->Init());
+ size_t decryptedDataSizeT = kDecryptedBufferSize;
+ RINOK(ReadStream(m_Stream, m_DecryptedDataAligned, &decryptedDataSizeT));
+ m_DecryptedDataSize = (UInt32)decryptedDataSizeT;
+ m_DecryptedDataSize = m_RarAES->Filter(m_DecryptedDataAligned, m_DecryptedDataSize);
+
+ m_CryptoMode = true;
+ m_CryptoPos = 0;
+ }
+
+ m_FileHeaderData.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;
+ ArcInfo.VolNumber = (UInt32)Get16(m_FileHeaderData + offset);
+ }
+ }
+ 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, 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
+};
+
+static const Byte kArcProps[] =
+{
+ kpidTotalPhySize,
+ kpidCharacts,
+ kpidSolid,
+ kpidNumBlocks,
+ // kpidEncrypted,
+ kpidIsVolume,
+ kpidVolumeIndex,
+ kpidNumVolumes
+ // kpidCommented
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
-UInt64 CHandler::GetPackSize(int refIndex) const
+UInt64 CHandler::GetPackSize(unsigned refIndex) const
{
const CRefItem &refItem = _refItems[refIndex];
UInt64 totalPackSize = 0;
- for (int i = 0; i < refItem.NumItems; i++)
+ 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
- NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ NCOM::CPropVariant prop;
+ switch (propID)
{
- case kpidSolid: prop = _archiveInfo.IsSolid(); break;
- case kpidCharacts: FLAGS_TO_PROP(k_Flags, _archiveInfo.Flags, prop); break;
- // case kpidEncrypted: prop = _archiveInfo.IsEncrypted(); break; // it's for encrypted names.
- case kpidIsVolume: prop = _archiveInfo.IsVolume(); break;
- case kpidNumVolumes: prop = (UInt32)_archives.Size(); break;
- case kpidOffset: if (_archiveInfo.StartPosition != 0) prop = _archiveInfo.StartPosition; break;
- // case kpidCommented: prop = _archiveInfo.IsCommented(); break;
+ case 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())
+ {
+ if (!s.IsEmpty())
+ s += ' ';
+ 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 (int i = 0; i < _refItems.Size(); i++)
+ FOR_VECTOR (i, _refItems)
if (!IsSolid(i))
numBlocks++;
prop = (UInt32)numBlocks;
break;
}
- case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
+
+ // case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; 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())
+ {
+ char sz[16];
+ ConvertUInt32ToString((UInt32)_arcInfo.VolNumber + 1, sz);
+ unsigned len = MyStringLen(sz);
+ AString s = "part";
+ for (; len < 2; len++)
+ s += '0';
+ s += sz;
+ s += ".rar";
+ prop = s;
+ }
+ }
+ break;
}
prop.Detach(value);
return S_OK;
@@ -144,7 +894,7 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result)
{
- if (!DosTimeToFileTime(rarTime.DosTime, result))
+ if (!NTime::DosTimeToFileTime(rarTime.DosTime, result))
return false;
UInt64 value = (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime;
value += (UInt64)rarTime.LowSecond * 10000000;
@@ -156,7 +906,7 @@ static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result)
return true;
}
-static void RarTimeToProp(const CRarTime &rarTime, NWindows::NCOM::CPropVariant &prop)
+static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop)
{
FILETIME localFileTime, utcFileTime;
if (RarTimeToFileTime(rarTime, localFileTime))
@@ -169,22 +919,28 @@ static void RarTimeToProp(const CRarTime &rarTime, NWindows::NCOM::CPropVariant
prop = utcFileTime;
}
-STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
+ NCOM::CPropVariant prop;
const CRefItem &refItem = _refItems[index];
- const CItemEx &item = _items[refItem.ItemIndex];
+ const CItem &item = _items[refItem.ItemIndex];
+ /*
+ const CItem *mainItem = &item;
+ if (item.BaseFileIndex >= 0)
+ mainItem = &_items[_refItems[item.BaseFileIndex].ItemIndex];
+ */
switch(propID)
{
case kpidPath:
{
+ /*
UString u;
- if (item.HasUnicodeName() && !item.UnicodeName.IsEmpty())
- u = item.UnicodeName;
- else
- u = MultiByteToUnicodeString(item.Name, CP_OEMCP);
- prop = (const wchar_t *)NItemName::WinNameToOSName(u);
+ if (item.BaseFileIndex >= 0)
+ u = mainItem->GetName();
+ u += item.GetName();
+ */
+ prop = (const wchar_t *)NItemName::WinNameToOSName(item.GetName());
break;
}
case kpidIsDir: prop = item.IsDir(); break;
@@ -193,7 +949,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
case kpidMTime: RarTimeToProp(item.MTime, prop); break;
case kpidCTime: if (item.CTimeDefined) RarTimeToProp(item.CTime, prop); break;
case kpidATime: if (item.ATimeDefined) RarTimeToProp(item.ATime, prop); break;
- case kpidAttrib: prop = item.GetWinAttributes(); break;
+ case kpidAttrib: prop = item.GetWinAttrib(); break;
case kpidEncrypted: prop = item.IsEncrypted(); break;
case kpidSolid: prop = IsSolid(index); break;
case kpidCommented: prop = item.IsCommented(); break;
@@ -201,43 +957,44 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
case kpidSplitAfter: prop = _items[refItem.ItemIndex + refItem.NumItems - 1].IsSplitAfter(); break;
case kpidCRC:
{
- const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
+ const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
prop = ((lastItem.IsSplitAfter()) ? item.FileCRC : lastItem.FileCRC);
break;
}
case kpidUnpackVer: prop = item.UnPackVersion; break;
case kpidMethod:
{
- UString method;
- if (item.Method >= Byte('0') && item.Method <= Byte('5'))
+ char temp[16];
+ char *s = temp;
+ if (item.Method >= (Byte)'0' && item.Method <= (Byte)'5')
{
- method = L"m";
- wchar_t temp[32];
- ConvertUInt64ToString(item.Method - Byte('0'), temp);
- method += temp;
+ *s++ = 'm';
+ *s++ = (char)item.Method;
if (!item.IsDir())
{
- method += L":";
- ConvertUInt64ToString(16 + item.GetDictSize(), temp);
- method += temp;
+ *s++ = ':';
+ ConvertUInt32ToString(16 + item.GetDictSize(), s);
}
}
else
- {
- wchar_t temp[32];
- ConvertUInt64ToString(item.Method, temp);
- method += temp;
- }
- prop = method;
+ ConvertUInt32ToString(item.Method, s);
+ s += MyStringLen(s);
+ *s = 0;
+ prop = s;
break;
}
- case kpidHostOS: prop = (item.HostOS < kNumHostOSes) ? (kHostOS[item.HostOS]) : kUnknownOS; break;
+ case kpidHostOS: prop = (item.HostOS < ARRAY_SIZE(kHostOS)) ? kHostOS[item.HostOS] : kUnknownOS; break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
+static bool IsDigit(wchar_t c)
+{
+ return c >= L'0' && c <= L'9';
+}
+
class CVolumeName
{
bool _first;
@@ -256,23 +1013,23 @@ public:
UString basePart = name;
if (dotPos >= 0)
{
- UString ext = name.Mid(dotPos + 1);
- if (ext.CompareNoCase(L"rar") == 0)
+ UString ext = name.Ptr(dotPos + 1);
+ if (ext.IsEqualToNoCase(L"rar"))
{
- _afterPart = name.Mid(dotPos);
+ _afterPart = name.Ptr(dotPos);
basePart = name.Left(dotPos);
}
- else if (ext.CompareNoCase(L"exe") == 0)
+ else if (ext.IsEqualToNoCase(L"exe"))
{
_afterPart = L".rar";
basePart = name.Left(dotPos);
}
else if (!_newStyle)
{
- if (ext.CompareNoCase(L"000") == 0 ||
- ext.CompareNoCase(L"001") == 0 ||
- ext.CompareNoCase(L"r00") == 0 ||
- ext.CompareNoCase(L"r01") == 0)
+ if (ext.IsEqualToNoCase(L"000") ||
+ ext.IsEqualToNoCase(L"001") ||
+ ext.IsEqualToNoCase(L"r00") ||
+ ext.IsEqualToNoCase(L"r01"))
{
_afterPart.Empty();
_first = false;
@@ -291,46 +1048,49 @@ public:
return true;
}
- int numLetters = 1;
- if (basePart.Right(numLetters) == L"1" || basePart.Right(numLetters) == L"0")
- {
- while (numLetters < basePart.Length())
- {
- if (basePart[basePart.Length() - numLetters - 1] != '0')
- break;
- numLetters++;
- }
- }
- else
+ if (basePart.IsEmpty())
return false;
- _unchangedPart = basePart.Left(basePart.Length() - numLetters);
- _changedPart = basePart.Right(numLetters);
+ unsigned i = basePart.Len();
+ do
+ if (!IsDigit(basePart[i - 1]))
+ break;
+ while (--i);
+ _unchangedPart = basePart.Left(i);
+ _changedPart = basePart.Ptr(i);
return true;
}
+ /*
+ void MakeBeforeFirstName()
+ {
+ unsigned len = _changedPart.Len();
+ _changedPart.Empty();
+ for (unsigned i = 0; i < len; i++)
+ _changedPart += L'0';
+ }
+ */
+
UString GetNextName()
{
UString newName;
if (_newStyle || !_first)
{
- int i;
- int numLetters = _changedPart.Length();
- for (i = numLetters - 1; i >= 0; i--)
+ for (int i = (int)_changedPart.Len() - 1; i >= 0; i--)
{
wchar_t c = _changedPart[i];
if (c == L'9')
{
c = L'0';
- newName = c + newName;
+ newName.InsertAtFront(c);
if (i == 0)
- newName = UString(L'1') + newName;
+ newName.InsertAtFront(L'1');
continue;
}
c++;
newName = UString(c) + newName;
i--;
for (; i >= 0; i--)
- newName = _changedPart[i] + newName;
+ newName.InsertAtFront(_changedPart[i]);
break;
}
_changedPart = newName;
@@ -360,17 +1120,18 @@ HRESULT CHandler::Open2(IInStream *stream,
openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
}
+ CInArchive archive;
for (;;)
{
CMyComPtr<IInStream> inStream;
- if (!_archives.IsEmpty())
+ if (!_arcs.IsEmpty())
{
if (!openVolumeCallback)
break;
- if (_archives.Size() == 1)
+ if (_arcs.Size() == 1)
{
- if (!_archiveInfo.IsVolume())
+ if (!_arcInfo.IsVolume())
break;
UString baseName;
{
@@ -380,7 +1141,14 @@ HRESULT CHandler::Open2(IInStream *stream,
break;
baseName = prop.bstrVal;
}
- seqName.InitName(baseName, _archiveInfo.HaveNewVolumeName());
+ if (!seqName.InitName(baseName, _arcInfo.HaveNewVolumeName()))
+ break;
+ /*
+ if (_arcInfo.HaveNewVolumeName() && !_arcInfo.IsFirstVolume())
+ {
+ seqName.MakeBeforeFirstName();
+ }
+ */
}
UString fullName = seqName.GetNextName();
@@ -389,47 +1157,54 @@ HRESULT CHandler::Open2(IInStream *stream,
break;
if (result != S_OK)
return result;
- if (!stream)
+ if (!inStream)
break;
}
else
inStream = stream;
UInt64 endPos = 0;
- RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
- RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ 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));
}
- NArchive::NRar::CInArchive archive;
RINOK(archive.Open(inStream, maxCheckStartPosition));
-
- if (_archives.IsEmpty())
- archive.GetArchiveInfo(_archiveInfo);
-
- CItemEx item;
+ _isArc = true;
+ CItem item;
for (;;)
{
if (archive.m_Position > endPos)
{
- AddErrorMessage("Unexpected end of archive");
+ _errorFlags |= kpv_ErrorFlags_UnexpectedEnd;
break;
}
- bool decryptionError;
- AString errorMessageLoc;
- HRESULT result = archive.GetNextItem(item, getTextPassword, decryptionError, errorMessageLoc);
- if (errorMessageLoc)
- AddErrorMessage(errorMessageLoc);
- if (result == S_FALSE)
+ 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 (decryptionError && _items.IsEmpty())
+ if (error == k_ErrorType_DecryptionError && _items.IsEmpty())
return S_FALSE;
break;
}
- RINOK(result);
if (item.IgnoreItem())
continue;
@@ -448,7 +1223,7 @@ HRESULT CHandler::Open2(IInStream *stream,
CRefItem refItem;
refItem.ItemIndex = _items.Size();
refItem.NumItems = 1;
- refItem.VolumeIndex = _archives.Size();
+ refItem.VolumeIndex = _arcs.Size();
_refItems.Add(refItem);
}
_items.Add(item);
@@ -459,10 +1234,38 @@ HRESULT CHandler::Open2(IInStream *stream,
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;
- _archives.Add(archive);
+ {
+ CArc &arc = _arcs.AddNew();
+ arc.PhySize = archive.ArcInfo.GetPhySize();
+ arc.Stream = inStream;
+ }
}
}
+
+ /*
+ int baseFileIndex = -1;
+ for (int i = 0; i < _refItems.Size(); i++)
+ {
+ CItem &item = _items[_refItems[i].ItemIndex];
+ if (item.IsAltStream)
+ item.BaseFileIndex = baseFileIndex;
+ else
+ baseFileIndex = i;
+ }
+ */
return S_OK;
}
@@ -472,25 +1275,31 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
{
COM_TRY_BEGIN
Close();
- try
+ // try
{
HRESULT res = Open2(stream, maxCheckStartPosition, openCallback);
+ /*
if (res != S_OK)
Close();
+ */
+
return res;
}
- catch(const CInArchiveException &) { Close(); return S_FALSE; }
- catch(...) { Close(); throw; }
+ // catch(const CInArchiveException &) { Close(); return S_FALSE; }
+ // catch(...) { Close(); throw; }
COM_TRY_END
}
STDMETHODIMP CHandler::Close()
{
COM_TRY_BEGIN
- _errorMessage.Empty();
+ // _errorMessage.Empty();
+ _errorFlags = 0;
+ _warningFlags = 0;
+ _isArc = false;
_refItems.Clear();
_items.Clear();
- _archives.Clear();
+ _arcs.Clear();
return S_OK;
COM_TRY_END
}
@@ -502,6 +1311,111 @@ struct CMethodItem
};
+class CFolderInStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+private:
+ const CObjectVector<CArc> *_archives;
+ const CObjectVector<CItem> *_items;
+ CRefItem _refItem;
+ unsigned _curIndex;
+ UInt32 _crc;
+ bool _fileIsOpen;
+ CMyComPtr<ISequentialInStream> _stream;
+
+ HRESULT OpenStream();
+ HRESULT CloseStream();
+public:
+ void Init(const CObjectVector<CArc> *archives,
+ const CObjectVector<CItem> *items,
+ const CRefItem &refItem);
+
+ CRecordVector<UInt32> CRCs;
+};
+
+
+ISequentialInStream* CArc::CreateLimitedStream(UInt64 offset, UInt64 size) const
+{
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ Stream->Seek(offset, STREAM_SEEK_SET, NULL);
+ streamSpec->SetStream(Stream);
+ streamSpec->Init(size);
+ return inStream.Detach();
+}
+
+void CFolderInStream::Init(
+ const CObjectVector<CArc> *archives,
+ const CObjectVector<CItem> *items,
+ const CRefItem &refItem)
+{
+ _archives = archives;
+ _items = items;
+ _refItem = refItem;
+ _curIndex = 0;
+ CRCs.Clear();
+ _fileIsOpen = false;
+}
+
+HRESULT CFolderInStream::OpenStream()
+{
+ while (_curIndex < _refItem.NumItems)
+ {
+ const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex];
+ _stream.Attach((*_archives)[_refItem.VolumeIndex + _curIndex].
+ CreateLimitedStream(item.GetDataPosition(), item.PackSize));
+ _curIndex++;
+ _fileIsOpen = true;
+ _crc = CRC_INIT_VAL;
+ return S_OK;
+ }
+ return S_OK;
+}
+
+HRESULT CFolderInStream::CloseStream()
+{
+ CRCs.Add(CRC_GET_DIGEST(_crc));
+ _stream.Release();
+ _fileIsOpen = false;
+ return S_OK;
+}
+
+STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize = 0;
+ while ((_curIndex < _refItem.NumItems || _fileIsOpen) && size > 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 localProcessedSize;
+ RINOK(_stream->Read(
+ ((Byte *)data) + realProcessedSize, size, &localProcessedSize));
+ _crc = CrcUpdate(_crc, ((Byte *)data) + realProcessedSize, localProcessedSize);
+ if (localProcessedSize == 0)
+ {
+ RINOK(CloseStream());
+ continue;
+ }
+ realProcessedSize += localProcessedSize;
+ size -= localProcessedSize;
+ break;
+ }
+ else
+ {
+ RINOK(OpenStream());
+ }
+ }
+ if (processedSize != 0)
+ *processedSize = realProcessedSize;
+ return S_OK;
+}
+
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
@@ -511,23 +1425,23 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
// censoredTotalPacked = 0,
importantTotalUnPacked = 0;
// importantTotalPacked = 0;
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _refItems.Size();
if (numItems == 0)
return S_OK;
- int lastIndex = 0;
+ unsigned lastIndex = 0;
CRecordVector<int> importantIndexes;
CRecordVector<bool> extractStatuses;
for (UInt32 t = 0; t < numItems; t++)
{
- int index = allFilesMode ? t : indices[t];
+ unsigned index = allFilesMode ? t : indices[t];
const CRefItem &refItem = _refItems[index];
- const CItemEx &item = _items[refItem.ItemIndex];
+ const CItem &item = _items[refItem.ItemIndex];
censoredTotalUnPacked += item.Size;
// censoredTotalPacked += item.PackSize;
- int j;
+ unsigned j;
for (j = lastIndex; j <= index; j++)
// if (!_items[_refItems[j].ItemIndex].IsSolid())
if (!IsSolid(j))
@@ -535,9 +1449,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
for (j = lastIndex; j <= index; j++)
{
const CRefItem &refItem = _refItems[j];
- const CItemEx &item = _items[refItem.ItemIndex];
+ const CItem &item = _items[refItem.ItemIndex];
- // const CItemEx &item = _items[j];
+ // const CItem &item = _items[j];
importantTotalUnPacked += item.Size;
// importantTotalPacked += item.PackSize;
@@ -573,7 +1487,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
lps->Init(extractCallback, false);
bool solidStart = true;
- for (int i = 0; i < importantIndexes.Size(); i++,
+ for (unsigned i = 0; i < importantIndexes.Size(); i++,
currentImportantTotalUnPacked += currentUnPackSize,
currentImportantTotalPacked += currentPackSize)
{
@@ -593,7 +1507,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt32 index = importantIndexes[i];
const CRefItem &refItem = _refItems[index];
- const CItemEx &item = _items[refItem.ItemIndex];
+ const CItem &item = _items[refItem.ItemIndex];
currentUnPackSize = item.Size;
@@ -617,7 +1531,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (i < importantIndexes.Size() - 1)
{
// const CRefItem &nextRefItem = _refItems[importantIndexes[i + 1]];
- // const CItemEx &nextItemInfo = _items[nextRefItem.ItemIndex];
+ // const CItem &nextItemInfo = _items[nextRefItem.ItemIndex];
// mustBeProcessedAnywhere = nextItemInfo.IsSolid();
mustBeProcessedAnywhere = IsSolid(importantIndexes[i + 1]);
}
@@ -637,14 +1551,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
realOutStream.Release();
/*
- for (int partIndex = 0; partIndex < 1; partIndex++)
+ for (unsigned partIndex = 0; partIndex < 1; partIndex++)
{
CMyComPtr<ISequentialInStream> inStream;
// item redefinition
- const CItemEx &item = _items[refItem.ItemIndex + partIndex];
+ const CItem &item = _items[refItem.ItemIndex + partIndex];
- NArchive::NRar::CInArchive &archive = _archives[refItem.VolumeIndex + partIndex];
+ CInArchive &archive = _arcs[refItem.VolumeIndex + partIndex];
inStream.Attach(archive.CreateLimitedStream(item.GetDataPosition(),
item.PackSize));
@@ -655,7 +1569,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
folderInStream = folderInStreamSpec;
}
- folderInStreamSpec->Init(&_archives, &_items, refItem);
+ folderInStreamSpec->Init(&_arcs, &_items, refItem);
UInt64 packSize = currentPackSize;
@@ -694,7 +1608,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
else
{
outStream.Release();
- RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod));
continue;
}
RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword,
@@ -708,25 +1622,25 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(getTextPassword->CryptoGetTextPassword(&password));
if (item.UnPackVersion >= 29)
{
- CByteBuffer buffer;
- UString unicodePassword(password);
- const UInt32 sizeInBytes = unicodePassword.Length() * 2;
- buffer.SetCapacity(sizeInBytes);
- for (int i = 0; i < unicodePassword.Length(); i++)
+ UString unicodePassword;
+ unsigned len = 0;
+ if (password)
+ len = MyStringLen((BSTR)password);
+ CByteBuffer buffer(len * 2);
+ for (unsigned i = 0; i < len; i++)
{
- wchar_t c = unicodePassword[i];
+ wchar_t c = password[i];
((Byte *)buffer)[i * 2] = (Byte)c;
((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
}
- RINOK(cryptoSetPassword->CryptoSetPassword(
- (const Byte *)buffer, sizeInBytes));
+ RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size()));
}
else
{
- AString oemPassword = UnicodeStringToMultiByte(
- (const wchar_t *)password, CP_OEMCP);
- RINOK(cryptoSetPassword->CryptoSetPassword(
- (const Byte *)(const char *)oemPassword, oemPassword.Length()));
+ AString oemPassword;
+ if (password)
+ oemPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
+ RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len()));
}
}
else
@@ -754,15 +1668,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
case '4':
case '5':
{
- /*
- if (item.UnPackVersion >= 29)
- {
- outStream.Release();
- RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
- continue;
- }
- */
- int m;
+ unsigned m;
for (m = 0; m < methodItems.Size(); m++)
if (methodItems[m].RarUnPackVersion == item.UnPackVersion)
break;
@@ -772,7 +1678,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
mi.RarUnPackVersion = item.UnPackVersion;
mi.Coder.Release();
- if (item.UnPackVersion <= 30)
+ if (item.UnPackVersion <= 40)
{
UInt32 methodID = 0x040300;
if (item.UnPackVersion < 20)
@@ -787,7 +1693,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (mi.Coder == 0)
{
outStream.Release();
- RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod));
continue;
}
@@ -814,7 +1720,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
default:
outStream.Release();
- RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod));
continue;
}
HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &item.Size, progress);
@@ -834,7 +1740,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
!item.IsSplitBefore() && !item.IsSplitAfter())
*/
{
- const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
+ const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
bool crcOK = outStreamSpec->GetCRC() == lastItem.FileCRC;
outStream.Release();
RINOK(extractCallback->SetOperationResult(crcOK ?
@@ -845,9 +1751,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
else
{
bool crcOK = true;
- for (int partIndex = 0; partIndex < refItem.NumItems; partIndex++)
+ for (unsigned partIndex = 0; partIndex < refItem.NumItems; partIndex++)
{
- const CItemEx &item = _items[refItem.ItemIndex + partIndex];
+ const CItem &item = _items[refItem.ItemIndex + partIndex];
if (item.FileCRC != folderInStreamSpec->CRCs[partIndex])
{
crcOK = false;
@@ -866,4 +1772,15 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
IMPL_ISetCompressCodecsInfo
+IMP_CreateArcIn
+
+static CArcInfo g_ArcInfo =
+ { "Rar", "rar r00", 0, 3,
+ NHeader::kMarkerSize, SIGNATURE,
+ 0,
+ NArcInfoFlags::kFindSignature,
+ CreateArc };
+
+REGISTER_ARC(Rar)
+
}}
diff --git a/CPP/7zip/Archive/Rar/RarHandler.h b/CPP/7zip/Archive/Rar/RarHandler.h
index 79266827..81191be9 100755..100644
--- a/CPP/7zip/Archive/Rar/RarHandler.h
+++ b/CPP/7zip/Archive/Rar/RarHandler.h
@@ -7,44 +7,85 @@
#include "../../Common/CreateCoder.h"
-#include "RarIn.h"
-#include "RarVolumeInStream.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;
+
+ CInArcInfo(): EndFlags(0) {}
+
+ UInt64 GetPhySize() const { return EndPos - StartPos; }
+
+ bool IsSolid() const { return (Flags & NHeader::NArchive::kSolid) != 0; }
+ bool IsCommented() const { return (Flags & NHeader::NArchive::kComment) != 0; }
+ bool IsVolume() const { return (Flags & NHeader::NArchive::kVolume) != 0; }
+ bool HaveNewVolumeName() const { return (Flags & NHeader::NArchive::kNewVolName) != 0; }
+ bool IsFirstVolume() const { return (Flags & NHeader::NArchive::kFirstVolume) != 0; }
+ bool IsEncrypted() const { return (Flags & NHeader::NArchive::kBlockEncryption) != 0; }
+ bool IsThereEncryptVer() const { return (Flags & NHeader::NArchive::kEncryptVer) != 0; }
+ bool IsEncryptOld() const { return (!IsThereEncryptVer() || EncryptVersion < 36); }
+
+ bool Is_VolNumber_Defined() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_VolNumber) != 0; }
+ bool Is_DataCRC_Defined() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_DataCRC) != 0; }
+};
+
+struct CArc
+{
+ CMyComPtr<IInStream> Stream;
+ UInt64 PhySize;
+ // CByteBuffer Comment;
+
+ CArc(): PhySize(0) {}
+ ISequentialInStream *CreateLimitedStream(UInt64 offset, UInt64 size) const;
+};
+
+struct CRefItem
+{
+ unsigned VolumeIndex;
+ unsigned ItemIndex;
+ unsigned NumItems;
+};
+
class CHandler:
public IInArchive,
PUBLIC_ISetCompressCodecsInfo
public CMyUnknownImp
{
CRecordVector<CRefItem> _refItems;
- CObjectVector<CItemEx> _items;
- CObjectVector<CInArchive> _archives;
- NArchive::NRar::CInArchiveInfo _archiveInfo;
- AString _errorMessage;
+ CObjectVector<CItem> _items;
+ CObjectVector<CArc> _arcs;
+ NArchive::NRar::CInArcInfo _arcInfo;
+ // AString _errorMessage;
+ UInt32 _errorFlags;
+ UInt32 _warningFlags;
+ bool _isArc;
DECL_EXTERNAL_CODECS_VARS
- UInt64 GetPackSize(int refIndex) const;
-
- bool IsSolid(int refIndex)
- {
- const CItemEx &item = _items[_refItems[refIndex].ItemIndex];
- if (item.UnPackVersion < 20)
- {
- if (_archiveInfo.IsSolid())
- return (refIndex > 0);
- return false;
- }
- return item.IsSolid();
- }
+ 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,
diff --git a/CPP/7zip/Archive/Rar/RarHeader.cpp b/CPP/7zip/Archive/Rar/RarHeader.cpp
deleted file mode 100755
index 94481e02..00000000
--- a/CPP/7zip/Archive/Rar/RarHeader.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-// Archive/Rar/Headers.cpp
-
-#include "StdAfx.h"
-
-#include "RarHeader.h"
-
-namespace NArchive{
-namespace NRar{
-namespace NHeader{
-
-Byte kMarker[kMarkerSize] = {0x52 + 1, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00};
-
-class CMarkerInitializer
-{
-public:
- CMarkerInitializer() { kMarker[0]--; };
-};
-
-static CMarkerInitializer markerInitializer;
-
-}}}
diff --git a/CPP/7zip/Archive/Rar/RarHeader.h b/CPP/7zip/Archive/Rar/RarHeader.h
index 5c21a2ac..b518338a 100755..100644
--- a/CPP/7zip/Archive/Rar/RarHeader.h
+++ b/CPP/7zip/Archive/Rar/RarHeader.h
@@ -3,16 +3,15 @@
#ifndef __ARCHIVE_RAR_HEADER_H
#define __ARCHIVE_RAR_HEADER_H
-#include "Common/Types.h"
+#include "../../../Common/MyTypes.h"
namespace NArchive {
namespace NRar {
namespace NHeader {
-const int kMarkerSize = 7;
-extern Byte kMarker[kMarkerSize];
+const unsigned kMarkerSize = 7;
-const int kArchiveSolid = 0x1;
+const unsigned kArchiveSolid = 0x1;
namespace NBlockType
{
@@ -44,36 +43,40 @@ namespace NArchive
const UInt16 kFirstVolume = 0x100; // (set only by RAR 3.0 and later)
const UInt16 kEncryptVer = 0x200; // RAR 3.6 there is EncryptVer Byte in End of MainHeader
- const int kHeaderSizeMin = 7;
-
- const int kArchiveHeaderSize = 13;
+ const UInt16 kEndOfArc_Flags_NextVol = 1;
+ const UInt16 kEndOfArc_Flags_DataCRC = 2;
+ const UInt16 kEndOfArc_Flags_RevSpace = 4;
+ const UInt16 kEndOfArc_Flags_VolNumber = 8;
- const int kBlockHeadersAreEncrypted = 0x80;
+ const unsigned kHeaderSizeMin = 7;
+
+ const unsigned kArchiveHeaderSize = 13;
+ const unsigned kBlockHeadersAreEncrypted = 0x80;
}
namespace NFile
{
- const int kSplitBefore = 1 << 0;
- const int kSplitAfter = 1 << 1;
- const int kEncrypted = 1 << 2;
- const int kComment = 1 << 3;
- const int kSolid = 1 << 4;
+ const 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 int kDictBitStart = 5;
- const int kNumDictBits = 3;
- const int kDictMask = (1 << kNumDictBits) - 1;
- const int kDictDirectoryValue = 0x7;
+ const unsigned kDictBitStart = 5;
+ const unsigned kNumDictBits = 3;
+ const unsigned kDictMask = (1 << kNumDictBits) - 1;
+ const unsigned kDictDirectoryValue = 0x7;
- const int kSize64Bits = 1 << 8;
- const int kUnicodeName = 1 << 9;
- const int kSalt = 1 << 10;
- const int kOldVersion = 1 << 11;
- const int kExtTime = 1 << 12;
- // const int kExtFlags = 1 << 13;
- // const int kSkipIfUnknown = 1 << 14;
-
- const int kLongBlock = 1 << 15;
+ 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
@@ -134,17 +137,17 @@ namespace NFile
};
*/
- const int kLabelFileAttribute = 0x08;
- const int kWinFileDirectoryAttributeMask = 0x10;
+ const unsigned kLabelFileAttribute = 0x08;
+ const unsigned kWinFileDirectoryAttributeMask = 0x10;
enum CHostOS
{
kHostMSDOS = 0,
- kHostOS2 = 1,
- kHostWin32 = 2,
- kHostUnix = 3,
- kHostMacOS = 4,
- kHostBeOS = 5
+ kHostOS2 = 1,
+ kHostWin32 = 2,
+ kHostUnix = 3,
+ kHostMacOS = 4,
+ kHostBeOS = 5
};
}
diff --git a/CPP/7zip/Archive/Rar/RarIn.cpp b/CPP/7zip/Archive/Rar/RarIn.cpp
deleted file mode 100755
index a7d018ff..00000000
--- a/CPP/7zip/Archive/Rar/RarIn.cpp
+++ /dev/null
@@ -1,478 +0,0 @@
-// Archive/RarIn.cpp
-
-#include "StdAfx.h"
-
-#include "../../../../C/7zCrc.h"
-#include "../../../../C/CpuArch.h"
-
-#include "Common/StringConvert.h"
-#include "Common/UTFConvert.h"
-
-#include "../../Common/LimitedStreams.h"
-#include "../../Common/StreamUtils.h"
-
-#include "../Common/FindSignature.h"
-
-#include "RarIn.h"
-
-#define Get16(p) GetUi16(p)
-#define Get32(p) GetUi32(p)
-#define Get64(p) GetUi64(p)
-
-namespace NArchive {
-namespace NRar {
-
-static const char *k_UnexpectedEnd = "Unexpected end of archive";
-static const char *k_DecryptionError = "Decryption Error";
-
-void CInArchive::ThrowExceptionWithCode(
- CInArchiveException::CCauseType cause)
-{
- throw CInArchiveException(cause);
-}
-
-HRESULT CInArchive::Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit)
-{
- try
- {
- Close();
- HRESULT res = Open2(inStream, searchHeaderSizeLimit);
- if (res == S_OK)
- return res;
- Close();
- return res;
- }
- catch(...) { Close(); throw; }
-}
-
-void CInArchive::Close()
-{
- m_Stream.Release();
-}
-
-HRESULT CInArchive::ReadBytesSpec(void *data, size_t *resSize)
-{
- if (m_CryptoMode)
- {
- size_t size = *resSize;
- *resSize = 0;
- const Byte *bufData = m_DecryptedDataAligned;
- UInt32 bufSize = m_DecryptedDataSize;
- size_t i;
- for (i = 0; i < size && m_CryptoPos < bufSize; i++)
- ((Byte *)data)[i] = bufData[m_CryptoPos++];
- *resSize = i;
- return S_OK;
- }
- return ReadStream(m_Stream, data, resSize);
-}
-
-bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size)
-{
- size_t processed = size;
- if (ReadBytesSpec(data, &processed) != S_OK)
- return false;
- return processed == size;
-}
-
-HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
-{
- m_CryptoMode = false;
- RINOK(stream->Seek(0, STREAM_SEEK_SET, &m_StreamStartPosition));
- m_Position = m_StreamStartPosition;
-
- UInt64 arcStartPos;
- RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize,
- searchHeaderSizeLimit, arcStartPos));
- m_Position = arcStartPos + NHeader::kMarkerSize;
- RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
- Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1];
-
- RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize));
- AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize);
-
-
- UInt32 blockSize = Get16(buf + 5);
-
- _header.EncryptVersion = 0;
- _header.Flags = Get16(buf + 3);
-
- UInt32 headerSize = NHeader::NArchive::kArchiveHeaderSize;
- if (_header.IsThereEncryptVer())
- {
- if (blockSize <= headerSize)
- return S_FALSE;
- RINOK(ReadStream_FALSE(stream, buf + NHeader::NArchive::kArchiveHeaderSize, 1));
- AddToSeekValue(1);
- _header.EncryptVersion = buf[NHeader::NArchive::kArchiveHeaderSize];
- headerSize += 1;
- }
- if (blockSize < headerSize ||
- buf[2] != NHeader::NBlockType::kArchiveHeader ||
- (UInt32)Get16(buf) != (CrcCalc(buf + 2, headerSize - 2) & 0xFFFF))
- return S_FALSE;
-
- size_t commentSize = blockSize - headerSize;
- _comment.SetCapacity(commentSize);
- RINOK(ReadStream_FALSE(stream, _comment, commentSize));
- AddToSeekValue(commentSize);
- m_Stream = stream;
- _header.StartPosition = arcStartPos;
- return S_OK;
-}
-
-void CInArchive::GetArchiveInfo(CInArchiveInfo &archiveInfo) const
-{
- archiveInfo = _header;
-}
-
-static void DecodeUnicodeFileName(const char *name, const Byte *encName,
- int encSize, wchar_t *unicodeName, int maxDecSize)
-{
- int encPos = 0;
- int decPos = 0;
- int flagBits = 0;
- Byte flags = 0;
- Byte highByte = encName[encPos++];
- while (encPos < encSize && decPos < maxDecSize)
- {
- if (flagBits == 0)
- {
- flags = encName[encPos++];
- flagBits = 8;
- }
- switch(flags >> 6)
- {
- case 0:
- unicodeName[decPos++] = encName[encPos++];
- break;
- case 1:
- unicodeName[decPos++] = (wchar_t)(encName[encPos++] + (highByte << 8));
- break;
- case 2:
- unicodeName[decPos++] = (wchar_t)(encName[encPos] + (encName[encPos + 1] << 8));
- encPos += 2;
- break;
- case 3:
- {
- int length = encName[encPos++];
- if (length & 0x80)
- {
- Byte correction = encName[encPos++];
- for (length = (length & 0x7f) + 2;
- length > 0 && decPos < maxDecSize; length--, decPos++)
- unicodeName[decPos] = (wchar_t)(((name[decPos] + correction) & 0xff) + (highByte << 8));
- }
- else
- for (length += 2; length > 0 && decPos < maxDecSize; length--, decPos++)
- unicodeName[decPos] = name[decPos];
- }
- break;
- }
- flags <<= 2;
- flagBits -= 2;
- }
- unicodeName[decPos < maxDecSize ? decPos : maxDecSize - 1] = 0;
-}
-
-void CInArchive::ReadName(CItemEx &item, int nameSize)
-{
- item.UnicodeName.Empty();
- if (nameSize > 0)
- {
- m_NameBuffer.EnsureCapacity(nameSize + 1);
- char *buffer = (char *)m_NameBuffer;
-
- for (int i = 0; i < nameSize; i++)
- buffer[i] = ReadByte();
-
- int mainLen;
- for (mainLen = 0; mainLen < nameSize; mainLen++)
- if (buffer[mainLen] == '\0')
- break;
- buffer[mainLen] = '\0';
- item.Name = buffer;
-
- if(item.HasUnicodeName())
- {
- if(mainLen < nameSize)
- {
- int unicodeNameSizeMax = MyMin(nameSize, (0x400));
- _unicodeNameBuffer.EnsureCapacity(unicodeNameSizeMax + 1);
- DecodeUnicodeFileName(buffer, (const Byte *)buffer + mainLen + 1,
- nameSize - (mainLen + 1), _unicodeNameBuffer, unicodeNameSizeMax);
- item.UnicodeName = _unicodeNameBuffer;
- }
- else if (!ConvertUTF8ToUnicode(item.Name, item.UnicodeName))
- item.UnicodeName.Empty();
- }
- }
- else
- item.Name.Empty();
-}
-
-Byte CInArchive::ReadByte()
-{
- if (m_CurPos >= m_PosLimit)
- throw CInArchiveException(CInArchiveException::kIncorrectArchive);
- return m_CurData[m_CurPos++];
-}
-
-UInt16 CInArchive::ReadUInt16()
-{
- UInt16 value = 0;
- for (int i = 0; i < 2; i++)
- {
- Byte b = ReadByte();
- value |= (UInt16(b) << (8 * i));
- }
- return value;
-}
-
-UInt32 CInArchive::ReadUInt32()
-{
- UInt32 value = 0;
- for (int i = 0; i < 4; i++)
- {
- Byte b = ReadByte();
- value |= (UInt32(b) << (8 * i));
- }
- return value;
-}
-
-void CInArchive::ReadTime(Byte mask, CRarTime &rarTime)
-{
- rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0);
- int numDigits = (mask & 3);
- rarTime.SubTime[0] = rarTime.SubTime[1] = rarTime.SubTime[2] = 0;
- for (int i = 0; i < numDigits; i++)
- rarTime.SubTime[3 - numDigits + i] = ReadByte();
-}
-
-void CInArchive::ReadHeaderReal(CItemEx &item)
-{
- item.Flags = m_BlockHeader.Flags;
- item.PackSize = ReadUInt32();
- item.Size = ReadUInt32();
- item.HostOS = ReadByte();
- item.FileCRC = ReadUInt32();
- item.MTime.DosTime = ReadUInt32();
- item.UnPackVersion = ReadByte();
- item.Method = ReadByte();
- int nameSize = ReadUInt16();
- item.Attrib = ReadUInt32();
-
- item.MTime.LowSecond = 0;
- item.MTime.SubTime[0] =
- item.MTime.SubTime[1] =
- item.MTime.SubTime[2] = 0;
-
- if((item.Flags & NHeader::NFile::kSize64Bits) != 0)
- {
- item.PackSize |= ((UInt64)ReadUInt32() << 32);
- item.Size |= ((UInt64)ReadUInt32() << 32);
- }
-
- ReadName(item, nameSize);
-
- if (item.HasSalt())
- for (int i = 0; i < sizeof(item.Salt); i++)
- item.Salt[i] = ReadByte();
-
- // some rar archives have HasExtTime flag without field.
- if (m_CurPos < m_PosLimit && item.HasExtTime())
- {
- Byte accessMask = (Byte)(ReadByte() >> 4);
- Byte b = ReadByte();
- Byte modifMask = (Byte)(b >> 4);
- Byte createMask = (Byte)(b & 0xF);
- if ((modifMask & 8) != 0)
- ReadTime(modifMask, item.MTime);
- item.CTimeDefined = ((createMask & 8) != 0);
- if (item.CTimeDefined)
- {
- item.CTime.DosTime = ReadUInt32();
- ReadTime(createMask, item.CTime);
- }
- item.ATimeDefined = ((accessMask & 8) != 0);
- if (item.ATimeDefined)
- {
- item.ATime.DosTime = ReadUInt32();
- ReadTime(accessMask, item.ATime);
- }
- }
-
- UInt16 fileHeaderWithNameSize = (UInt16)m_CurPos;
-
- item.Position = m_Position;
- item.MainPartSize = fileHeaderWithNameSize;
- item.CommentSize = (UInt16)(m_BlockHeader.HeadSize - fileHeaderWithNameSize);
-
- if (m_CryptoMode)
- item.AlignSize = (UInt16)((16 - ((m_BlockHeader.HeadSize) & 0xF)) & 0xF);
- else
- item.AlignSize = 0;
- AddToSeekValue(m_BlockHeader.HeadSize);
-}
-
-void CInArchive::AddToSeekValue(UInt64 addValue)
-{
- m_Position += addValue;
-}
-
-HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage)
-{
- decryptionError = false;
- for (;;)
- {
- SeekInArchive(m_Position);
- if (!m_CryptoMode && (_header.Flags &
- NHeader::NArchive::kBlockHeadersAreEncrypted) != 0)
- {
- m_CryptoMode = false;
- if (getTextPassword == 0)
- return S_FALSE;
- if (!m_RarAES)
- {
- m_RarAESSpec = new NCrypto::NRar29::CDecoder;
- m_RarAES = m_RarAESSpec;
- }
- m_RarAESSpec->SetRar350Mode(_header.IsEncryptOld());
-
- // Salt
- const UInt32 kSaltSize = 8;
- Byte salt[kSaltSize];
- if(!ReadBytesAndTestSize(salt, kSaltSize))
- return S_FALSE;
- m_Position += kSaltSize;
- RINOK(m_RarAESSpec->SetDecoderProperties2(salt, kSaltSize))
- // Password
- CMyComBSTR password;
- RINOK(getTextPassword->CryptoGetTextPassword(&password))
- UString unicodePassword(password);
-
- CByteBuffer buffer;
- const UInt32 sizeInBytes = unicodePassword.Length() * 2;
- buffer.SetCapacity(sizeInBytes);
- for (int i = 0; i < unicodePassword.Length(); i++)
- {
- wchar_t c = unicodePassword[i];
- ((Byte *)buffer)[i * 2] = (Byte)c;
- ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
- }
-
- RINOK(m_RarAESSpec->CryptoSetPassword((const Byte *)buffer, sizeInBytes));
-
- const UInt32 kDecryptedBufferSize = (1 << 12);
- if (m_DecryptedData.GetCapacity() == 0)
- {
- const UInt32 kAlign = 16;
- m_DecryptedData.SetCapacity(kDecryptedBufferSize + kAlign);
- m_DecryptedDataAligned = (Byte *)((ptrdiff_t)((Byte *)m_DecryptedData + kAlign - 1) & ~(ptrdiff_t)(kAlign - 1));
- }
- RINOK(m_RarAES->Init());
- size_t decryptedDataSizeT = kDecryptedBufferSize;
- RINOK(ReadStream(m_Stream, m_DecryptedDataAligned, &decryptedDataSizeT));
- m_DecryptedDataSize = (UInt32)decryptedDataSizeT;
- m_DecryptedDataSize = m_RarAES->Filter(m_DecryptedDataAligned, m_DecryptedDataSize);
-
- m_CryptoMode = true;
- m_CryptoPos = 0;
- }
-
- m_FileHeaderData.EnsureCapacity(7);
- size_t processed = 7;
- RINOK(ReadBytesSpec((Byte *)m_FileHeaderData, &processed));
- if (processed != 7)
- {
- if (processed != 0)
- errorMessage = k_UnexpectedEnd;
- return S_FALSE;
- }
-
- m_CurData = (Byte *)m_FileHeaderData;
- m_CurPos = 0;
- m_PosLimit = 7;
- m_BlockHeader.CRC = ReadUInt16();
- m_BlockHeader.Type = ReadByte();
- m_BlockHeader.Flags = ReadUInt16();
- m_BlockHeader.HeadSize = ReadUInt16();
-
- if (m_BlockHeader.HeadSize < 7)
- ThrowExceptionWithCode(CInArchiveException::kIncorrectArchive);
-
- if (m_BlockHeader.Type == NHeader::NBlockType::kEndOfArchive)
- return S_FALSE;
-
- if (m_BlockHeader.Type == NHeader::NBlockType::kFileHeader)
- {
- m_FileHeaderData.EnsureCapacity(m_BlockHeader.HeadSize);
- m_CurData = (Byte *)m_FileHeaderData;
- m_PosLimit = m_BlockHeader.HeadSize;
- if (!ReadBytesAndTestSize(m_CurData + m_CurPos, m_BlockHeader.HeadSize - 7))
- {
- errorMessage = k_UnexpectedEnd;
- return S_FALSE;
- }
-
- ReadHeaderReal(item);
- if ((CrcCalc(m_CurData + 2,
- m_BlockHeader.HeadSize - item.CommentSize - 2) & 0xFFFF) != m_BlockHeader.CRC)
- ThrowExceptionWithCode(CInArchiveException::kFileHeaderCRCError);
-
- FinishCryptoBlock();
- m_CryptoMode = false;
- SeekInArchive(m_Position); // Move Position to compressed Data;
- AddToSeekValue(item.PackSize); // m_Position points to next header;
- return S_OK;
- }
- if (m_CryptoMode && m_BlockHeader.HeadSize > (1 << 10))
- {
- decryptionError = true;
- errorMessage = k_DecryptionError;
- return S_FALSE;
- }
- if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0)
- {
- m_FileHeaderData.EnsureCapacity(7 + 4);
- m_CurData = (Byte *)m_FileHeaderData;
- if (!ReadBytesAndTestSize(m_CurData + m_CurPos, 4))
- {
- errorMessage = k_UnexpectedEnd;
- return S_FALSE;
- }
- m_PosLimit = 7 + 4;
- UInt32 dataSize = ReadUInt32();
- AddToSeekValue(dataSize);
- if (m_CryptoMode && dataSize > (1 << 27))
- {
- decryptionError = true;
- errorMessage = k_DecryptionError;
- return S_FALSE;
- }
- m_CryptoPos = m_BlockHeader.HeadSize;
- }
- else
- m_CryptoPos = 0;
- AddToSeekValue(m_BlockHeader.HeadSize);
- FinishCryptoBlock();
- m_CryptoMode = false;
- }
-}
-
-void CInArchive::SeekInArchive(UInt64 position)
-{
- m_Stream->Seek(position, STREAM_SEEK_SET, NULL);
-}
-
-ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size)
-{
- CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
- CMyComPtr<ISequentialInStream> inStream(streamSpec);
- SeekInArchive(position);
- streamSpec->SetStream(m_Stream);
- streamSpec->Init(size);
- return inStream.Detach();
-}
-
-}}
diff --git a/CPP/7zip/Archive/Rar/RarIn.h b/CPP/7zip/Archive/Rar/RarIn.h
deleted file mode 100755
index a6998db2..00000000
--- a/CPP/7zip/Archive/Rar/RarIn.h
+++ /dev/null
@@ -1,123 +0,0 @@
-// RarIn.h
-
-#ifndef __ARCHIVE_RAR_IN_H
-#define __ARCHIVE_RAR_IN_H
-
-#include "Common/DynamicBuffer.h"
-#include "Common/MyCom.h"
-
-#include "../../ICoder.h"
-#include "../../IStream.h"
-
-#include "../../Common/StreamObjects.h"
-
-#include "../../Crypto/RarAes.h"
-
-#include "RarHeader.h"
-#include "RarItem.h"
-
-namespace NArchive {
-namespace NRar {
-
-class CInArchiveException
-{
-public:
- enum CCauseType
- {
- kUnexpectedEndOfArchive = 0,
- kArchiveHeaderCRCError,
- kFileHeaderCRCError,
- kIncorrectArchive
- }
- Cause;
- CInArchiveException(CCauseType cause) : Cause(cause) {}
-};
-
-
-struct CInArchiveInfo
-{
- UInt32 Flags;
- Byte EncryptVersion;
- UInt64 StartPosition;
-
- bool IsSolid() const { return (Flags & NHeader::NArchive::kSolid) != 0; }
- bool IsCommented() const { return (Flags & NHeader::NArchive::kComment) != 0; }
- bool IsVolume() const { return (Flags & NHeader::NArchive::kVolume) != 0; }
- bool HaveNewVolumeName() const { return (Flags & NHeader::NArchive::kNewVolName) != 0; }
- bool IsEncrypted() const { return (Flags & NHeader::NArchive::kBlockEncryption) != 0; }
- bool IsThereEncryptVer() const { return (Flags & NHeader::NArchive::kEncryptVer) != 0; }
- bool IsEncryptOld() const { return (!IsThereEncryptVer() || EncryptVersion < 36); }
-};
-
-class CInArchive
-{
- CMyComPtr<IInStream> m_Stream;
-
- UInt64 m_StreamStartPosition;
-
- CInArchiveInfo _header;
- CDynamicBuffer<char> m_NameBuffer;
- CDynamicBuffer<wchar_t> _unicodeNameBuffer;
-
- CByteBuffer _comment;
-
- void ReadName(CItemEx &item, int nameSize);
- void ReadHeaderReal(CItemEx &item);
-
- HRESULT ReadBytesSpec(void *data, size_t *size);
- bool ReadBytesAndTestSize(void *data, UInt32 size);
-
- HRESULT Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
-
- void ThrowExceptionWithCode(CInArchiveException::CCauseType cause);
- void ThrowUnexpectedEndOfArchiveException();
-
- void AddToSeekValue(UInt64 addValue);
-
- CDynamicBuffer<Byte> m_FileHeaderData;
-
- NHeader::NBlock::CBlock m_BlockHeader;
-
- NCrypto::NRar29::CDecoder *m_RarAESSpec;
- CMyComPtr<ICompressFilter> m_RarAES;
-
- Byte *m_CurData; // it must point to start of Rar::Block
- UInt32 m_CurPos;
- UInt32 m_PosLimit;
- Byte ReadByte();
- UInt16 ReadUInt16();
- UInt32 ReadUInt32();
- void ReadTime(Byte mask, CRarTime &rarTime);
-
- CBuffer<Byte> m_DecryptedData;
- Byte *m_DecryptedDataAligned;
- UInt32 m_DecryptedDataSize;
-
- bool m_CryptoMode;
- UInt32 m_CryptoPos;
- void FinishCryptoBlock()
- {
- if (m_CryptoMode)
- while ((m_CryptoPos & 0xF) != 0)
- {
- m_CryptoPos++;
- m_Position++;
- }
- }
-
-public:
- UInt64 m_Position;
-
- HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit);
- void Close();
- HRESULT GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage);
-
- void GetArchiveInfo(CInArchiveInfo &archiveInfo) const;
-
- void SeekInArchive(UInt64 position);
- ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
-};
-
-}}
-
-#endif
diff --git a/CPP/7zip/Archive/Rar/RarItem.cpp b/CPP/7zip/Archive/Rar/RarItem.cpp
deleted file mode 100755
index 9216ae57..00000000
--- a/CPP/7zip/Archive/Rar/RarItem.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-// RarItem.cpp
-
-#include "StdAfx.h"
-
-#include "RarItem.h"
-
-namespace NArchive{
-namespace NRar{
-
-bool CItem::IgnoreItem() const
-{
- switch(HostOS)
- {
- case NHeader::NFile::kHostMSDOS:
- case NHeader::NFile::kHostOS2:
- case NHeader::NFile::kHostWin32:
- return ((Attrib & NHeader::NFile::kLabelFileAttribute) != 0);
- }
- return false;
-}
-
-bool CItem::IsDir() const
-{
- if (GetDictSize() == NHeader::NFile::kDictDirectoryValue)
- return true;
- switch(HostOS)
- {
- case NHeader::NFile::kHostMSDOS:
- case NHeader::NFile::kHostOS2:
- case NHeader::NFile::kHostWin32:
- if ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
- return true;
- }
- return false;
-}
-
-UInt32 CItem::GetWinAttributes() const
-{
- UInt32 winAttributes;
- switch(HostOS)
- {
- case NHeader::NFile::kHostMSDOS:
- case NHeader::NFile::kHostOS2:
- case NHeader::NFile::kHostWin32:
- winAttributes = Attrib;
- break;
- default:
- winAttributes = 0; // must be converted from unix value;
- }
- if (IsDir())
- winAttributes |= NHeader::NFile::kWinFileDirectoryAttributeMask;
- return winAttributes;
-}
-
-}}
diff --git a/CPP/7zip/Archive/Rar/RarItem.h b/CPP/7zip/Archive/Rar/RarItem.h
index 4aa4d866..56d25f2c 100755..100644
--- a/CPP/7zip/Archive/Rar/RarItem.h
+++ b/CPP/7zip/Archive/Rar/RarItem.h
@@ -3,13 +3,12 @@
#ifndef __ARCHIVE_RAR_ITEM_H
#define __ARCHIVE_RAR_ITEM_H
-#include "Common/Types.h"
-#include "Common/MyString.h"
+#include "../../../Common/StringConvert.h"
#include "RarHeader.h"
-namespace NArchive{
-namespace NRar{
+namespace NArchive {
+namespace NRar {
struct CRarTime
{
@@ -56,18 +55,35 @@ struct CItem
UInt32 GetDictSize() const { return (Flags >> NHeader::NFile::kDictBitStart) & NHeader::NFile::kDictMask; }
bool IsDir() const;
bool IgnoreItem() const;
- UInt32 GetWinAttributes() const;
-
- CItem(): CTimeDefined(false), ATimeDefined(false) {}
-};
+ UInt32 GetWinAttrib() const;
-class CItemEx: public CItem
-{
-public:
UInt64 Position;
- UInt16 MainPartSize;
+ 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; };
diff --git a/CPP/7zip/Archive/Rar/RarRegister.cpp b/CPP/7zip/Archive/Rar/RarRegister.cpp
deleted file mode 100755
index 2bcf569e..00000000
--- a/CPP/7zip/Archive/Rar/RarRegister.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// RarRegister.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/RegisterArc.h"
-
-#include "RarHandler.h"
-static IInArchive *CreateArc() { return new NArchive::NRar::CHandler; }
-
-static CArcInfo g_ArcInfo =
- { L"Rar", L"rar r00", 0, 3, {0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00}, 7, false, CreateArc, 0, };
-
-REGISTER_ARC(Rar)
diff --git a/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp b/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp
deleted file mode 100755
index 25194f91..00000000
--- a/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-// RarVolumeInStream.cpp
-
-#include "StdAfx.h"
-
-#include "../../../../C/7zCrc.h"
-
-#include "RarVolumeInStream.h"
-
-namespace NArchive {
-namespace NRar {
-
-void CFolderInStream::Init(
- CObjectVector<CInArchive> *archives,
- const CObjectVector<CItemEx> *items,
- const CRefItem &refItem)
-{
- _archives = archives;
- _items = items;
- _refItem = refItem;
- _curIndex = 0;
- CRCs.Clear();
- _fileIsOpen = false;
-}
-
-HRESULT CFolderInStream::OpenStream()
-{
- while (_curIndex < _refItem.NumItems)
- {
- const CItemEx &item = (*_items)[_refItem.ItemIndex + _curIndex];
- _stream.Attach((*_archives)[_refItem.VolumeIndex + _curIndex].
- CreateLimitedStream(item.GetDataPosition(), item.PackSize));
- _curIndex++;
- _fileIsOpen = true;
- _crc = CRC_INIT_VAL;
- return S_OK;
- }
- return S_OK;
-}
-
-HRESULT CFolderInStream::CloseStream()
-{
- CRCs.Add(CRC_GET_DIGEST(_crc));
- _stream.Release();
- _fileIsOpen = false;
- return S_OK;
-}
-
-STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- UInt32 realProcessedSize = 0;
- while ((_curIndex < _refItem.NumItems || _fileIsOpen) && size > 0)
- {
- if (_fileIsOpen)
- {
- UInt32 localProcessedSize;
- RINOK(_stream->Read(
- ((Byte *)data) + realProcessedSize, size, &localProcessedSize));
- _crc = CrcUpdate(_crc, ((Byte *)data) + realProcessedSize, localProcessedSize);
- if (localProcessedSize == 0)
- {
- RINOK(CloseStream());
- continue;
- }
- realProcessedSize += localProcessedSize;
- size -= localProcessedSize;
- break;
- }
- else
- {
- RINOK(OpenStream());
- }
- }
- if (processedSize != 0)
- *processedSize = realProcessedSize;
- return S_OK;
-}
-
-}}
diff --git a/CPP/7zip/Archive/Rar/RarVolumeInStream.h b/CPP/7zip/Archive/Rar/RarVolumeInStream.h
deleted file mode 100755
index 78d95b10..00000000
--- a/CPP/7zip/Archive/Rar/RarVolumeInStream.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// RarVolumeInStream.h
-
-#ifndef __RAR_VOLUME_IN_STREAM_H
-#define __RAR_VOLUME_IN_STREAM_H
-
-#include "../../IStream.h"
-#include "RarIn.h"
-
-namespace NArchive {
-namespace NRar {
-
-struct CRefItem
-{
- int VolumeIndex;
- int ItemIndex;
- int NumItems;
-};
-
-class CFolderInStream:
- public ISequentialInStream,
- public CMyUnknownImp
-{
-public:
- MY_UNKNOWN_IMP
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
-
-private:
- CObjectVector<CInArchive> *_archives;
- const CObjectVector<CItemEx> *_items;
- CRefItem _refItem;
- int _curIndex;
- UInt32 _crc;
- bool _fileIsOpen;
- CMyComPtr<ISequentialInStream> _stream;
-
- HRESULT OpenStream();
- HRESULT CloseStream();
-public:
- void Init(CObjectVector<CInArchive> *archives,
- const CObjectVector<CItemEx> *items,
- const CRefItem &refItem);
-
- CRecordVector<UInt32> CRCs;
-};
-
-}}
-
-#endif
diff --git a/CPP/7zip/Archive/Rar/StdAfx.cpp b/CPP/7zip/Archive/Rar/StdAfx.cpp
index d0feea85..d0feea85 100755..100644
--- a/CPP/7zip/Archive/Rar/StdAfx.cpp
+++ b/CPP/7zip/Archive/Rar/StdAfx.cpp
diff --git a/CPP/7zip/Archive/Rar/StdAfx.h b/CPP/7zip/Archive/Rar/StdAfx.h
index e7fb6986..2854ff3e 100755..100644
--- a/CPP/7zip/Archive/Rar/StdAfx.h
+++ b/CPP/7zip/Archive/Rar/StdAfx.h
@@ -3,6 +3,6 @@
#ifndef __STDAFX_H
#define __STDAFX_H
-#include "../../../Common/MyWindows.h"
+#include "../../../Common/Common.h"
#endif
diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp
index 1d31d451..220bc650 100755..100644
--- a/CPP/7zip/Archive/RpmHandler.cpp
+++ b/CPP/7zip/Archive/RpmHandler.cpp
@@ -4,10 +4,14 @@
#include "../../../C/CpuArch.h"
-#include "Common/ComTry.h"
-#include "Common/MyString.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyString.h"
+#include "../../Common/StringConvert.h"
+#include "../../Common/UTFConvert.h"
-#include "Windows/PropVariant.h"
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -16,6 +20,8 @@
#include "../Compress/CopyCoder.h"
+// #define _SHOW_RPM_METADATA
+
using namespace NWindows;
#define Get16(p) GetBe16(p)
@@ -24,130 +30,144 @@ using namespace NWindows;
namespace NArchive {
namespace NRpm {
-/* Reference: lib/signature.h of rpm package */
-#define RPMSIG_NONE 0 /* Do not change! */
-/* The following types are no longer generated */
-#define RPMSIG_PGP262_1024 1 /* No longer generated */ /* 256 byte */
-/* These are the new-style signatures. They are Header structures. */
-/* Inside them we can put any number of any type of signature we like. */
+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_HEADERSIG 5 /* New Header style signature */
+#define RPMSIG_NONE 0 // Old signature
+#define RPMSIG_PGP262_1024 1 // Old signature
+#define RPMSIG_HEADERSIG 5 // New signature
-const UInt32 kLeadSize = 96;
-struct CLead
+enum
{
- unsigned char Magic[4];
- unsigned char Major; // not supported ver1, only support 2,3 and lator
- unsigned char Minor;
- UInt16 Type;
- UInt16 ArchNum;
- char Name[66];
- UInt16 OSNum;
- UInt16 SignatureType;
- char Reserved[16]; // pad to 96 bytes -- 8 byte aligned
- bool MagicCheck() const
- { return Magic[0] == 0xed && Magic[1] == 0xab && Magic[2] == 0xee && Magic[3] == 0xdb; };
+ kRpmType_Bin = 0,
+ kRpmType_Src = 1
};
-
-const UInt32 kEntryInfoSize = 16;
-/*
-struct CEntryInfo
+
+// 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
{
- int Tag;
- int Type;
- int Offset; // Offset from beginning of data segment, only defined on disk
- int Count;
+ 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
};
-*/
-// case: SignatureType == RPMSIG_HEADERSIG
-const UInt32 kCSigHeaderSigSize = 16;
-struct CSigHeaderSig
+static const char *k_CPUs[] =
{
- unsigned char Magic[4];
- UInt32 Reserved;
- UInt32 IndexLen; // count of index entries
- UInt32 DataLen; // number of bytes
- bool MagicCheck()
- { return Magic[0] == 0x8e && Magic[1] == 0xad && Magic[2] == 0xe8 && Magic[3] == 0x01; };
- UInt32 GetLostHeaderLen()
- { return IndexLen * kEntryInfoSize + DataLen; };
+ "noarch"
+ , "i386"
+ , "alpha"
+ , "sparc"
+ , "mips"
+ , "ppc"
+ , "m68k"
+ , "sgi"
+ , "rs6000"
+ , "ia64"
+ , "sparc64" // 10 ???
+ , "mipsel"
+ , "arm"
+ , "m68kmint"
+ , "s390"
+ , "s390x"
+ , "ppc64"
+ , "sh"
+ , "xtensa"
+ , "aarch64" // 19
};
-static HRESULT RedSigHeaderSig(IInStream *inStream, CSigHeaderSig &h)
+static const char *k_OS[] =
{
- char dat[kCSigHeaderSigSize];
- char *cur = dat;
- RINOK(ReadStream_FALSE(inStream, dat, kCSigHeaderSigSize));
- memcpy(h.Magic, cur, 4);
- cur += 4;
- cur += 4;
- h.IndexLen = Get32(cur);
- cur += 4;
- h.DataLen = Get32(cur);
- return S_OK;
-}
+ "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
+};
-HRESULT OpenArchive(IInStream *inStream)
+struct CLead
{
- UInt64 pos;
- char leadData[kLeadSize];
- char *cur = leadData;
- CLead lead;
- RINOK(ReadStream_FALSE(inStream, leadData, kLeadSize));
- memcpy(lead.Magic, cur, 4);
- cur += 4;
- lead.Major = *cur++;
- lead.Minor = *cur++;
- lead.Type = Get16(cur);
- cur += 2;
- lead.ArchNum = Get16(cur);
- cur += 2;
- memcpy(lead.Name, cur, sizeof(lead.Name));
- cur += sizeof(lead.Name);
- lead.OSNum = Get16(cur);
- cur += 2;
- lead.SignatureType = Get16(cur);
- cur += 2;
-
- if (!lead.MagicCheck() || lead.Major < 3)
- return S_FALSE;
+ unsigned char Major;
+ unsigned char Minor;
+ UInt16 Type;
+ UInt16 Cpu;
+ UInt16 Os;
+ UInt16 SignatureType;
+ char Name[kNameSize];
+ // char Reserved[16];
- CSigHeaderSig sigHeader, header;
- if (lead.SignatureType == RPMSIG_NONE)
- {
- ;
- }
- else if (lead.SignatureType == RPMSIG_PGP262_1024)
+ void Parse(const Byte *p)
{
- UInt64 pos;
- RINOK(inStream->Seek(256, STREAM_SEEK_CUR, &pos));
+ 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);
}
- else if (lead.SignatureType == RPMSIG_HEADERSIG)
+
+ bool IsSupported() const { return Major >= 3 && Type <= 1; }
+};
+
+struct CEntry
+{
+ UInt32 Tag;
+ UInt32 Type;
+ UInt32 Offset;
+ UInt32 Count;
+
+ void Parse(const Byte *p)
{
- RINOK(RedSigHeaderSig(inStream, sigHeader));
- if (!sigHeader.MagicCheck())
- return S_FALSE;
- UInt32 len = sigHeader.GetLostHeaderLen();
- RINOK(inStream->Seek(len, STREAM_SEEK_CUR, &pos));
- if ((pos % 8) != 0)
- {
- RINOK(inStream->Seek((pos / 8 + 1) * 8 - pos,
- STREAM_SEEK_CUR, &pos));
- }
+ Tag = Get32(p + 0);
+ Type = Get32(p + 4);
+ Offset = Get32(p + 8);
+ Count = Get32(p + 12);
}
- else
- return S_FALSE;
-
- RINOK(RedSigHeaderSig(inStream, header));
- if (!header.MagicCheck())
- return S_FALSE;
- int headerLen = header.GetLostHeaderLen();
- if (headerLen == -1)
- return S_FALSE;
- RINOK(inStream->Seek(headerLen, STREAM_SEEK_CUR, &pos));
- return S_OK;
-}
+};
class CHandler:
public IInArchive,
@@ -155,104 +175,575 @@ class CHandler:
public CMyUnknownImp
{
CMyComPtr<IInStream> _stream;
- UInt64 _pos;
+
+ UInt64 _headersSize; // is equal to start offset of payload data
+ UInt64 _payloadSize;
UInt64 _size;
- Byte _sig[4];
+ // _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;
+ #endif
+
+ void SetTime(NCOM::CPropVariant &prop) const
+ {
+ if (_time_Defined && _buildTime != 0)
+ {
+ FILETIME ft;
+ if (NTime::UnixTime64ToFileTime(_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);
public:
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
};
-STATPROPSTG kProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidSize, VT_UI8}
+ kpidHeadersSize,
+ kpidCpu,
+ kpidHostOS,
+ kpidCTime
+ #ifdef _SHOW_RPM_METADATA
+ , kpidComment
+ #endif
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidCTime
};
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO_Table
+IMP_IInArchive_ArcProps
-STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+void CHandler::AddCPU(AString &s) const
{
- NCOM::CPropVariant prop;
- switch(propID) { case kpidMainSubfile: prop = (UInt32)0; break; }
- prop.Detach(value);
- return S_OK;
+ if (!_arch.IsEmpty())
+ s += _arch;
+ else
+ {
+ if (_lead.Type == kRpmType_Bin)
+ {
+ char temp[16];
+ const char *p;
+ if (_lead.Cpu < ARRAY_SIZE(k_CPUs))
+ p = k_CPUs[_lead.Cpu];
+ else
+ {
+ ConvertUInt32ToString(_lead.Cpu, temp);
+ p = temp;
+ }
+ s += p;
+ }
+ }
}
-STDMETHODIMP CHandler::Open(IInStream *inStream,
- const UInt64 * /* maxCheckStartPosition */,
- IArchiveOpenCallback * /* openArchiveCallback */)
+AString CHandler::GetBaseName() const
{
- COM_TRY_BEGIN
- try
+ AString s;
+ if (!_name.IsEmpty())
{
- Close();
- if (OpenArchive(inStream) != S_OK)
- return S_FALSE;
- RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_pos));
- RINOK(ReadStream_FALSE(inStream, _sig, sizeof(_sig) / sizeof(_sig[0])));
- UInt64 endPosition;
- RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPosition));
- _size = endPosition - _pos;
- _stream = inStream;
- return S_OK;
+ s = _name;
+ if (!_version.IsEmpty())
+ {
+ s += '-';
+ s += _version;
+ }
+ if (!_release.IsEmpty())
+ {
+ s += '-';
+ s += _release;
+ }
}
- catch(...) { return S_FALSE; }
- COM_TRY_END
+ else
+ {
+ char *p = s.GetBuffer(kNameSize);
+ memcpy(p, _lead.Name, kNameSize);
+ p[kNameSize] = 0;
+ s.ReleaseBuffer();
+ }
+
+ s += '.';
+ if (_lead.Type == kRpmType_Src)
+ s += "src";
+ else
+ AddCPU(s);
+ return s;
}
-STDMETHODIMP CHandler::Close()
+void CHandler::AddSubFileExtension(AString &res) const
{
- _stream.Release();
- return S_OK;
+ 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::GetNumberOfItems(UInt32 *numItems)
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
- *numItems = 1;
+ 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
+ {
+ char temp[16];
+ const char *p;
+ if (_lead.Os < ARRAY_SIZE(k_OS))
+ p = k_OS[_lead.Os];
+ else
+ {
+ ConvertUInt32ToString(_lead.Os, temp);
+ p = temp;
+ }
+ prop = p;
+ }
+ break;
+ }
+
+ #ifdef _SHOW_RPM_METADATA
+ case kpidComment: SetStringProp(_metadata, prop); break;
+ #endif
+
+ case kpidName:
+ {
+ AString s = GetBaseName();
+ s += ".rpm";
+ SetStringProp(s, prop);
+ break;
+ }
+ }
+ prop.Detach(value);
return S_OK;
+ COM_TRY_END
}
+
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
{
NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ 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:
{
- char s[32];
- MyStringCopy(s, "cpio.");
- const char *ext;
- if (_sig[0] == 0x1F && _sig[1] == 0x8B)
- ext = "gz";
- else if (_sig[0] == 'B' && _sig[1] == 'Z' && _sig[2] == 'h')
- ext = "bz2";
- else
- ext = "lzma";
- MyStringCopy(s + MyStringLen(s), ext);
- prop = s;
+ prop = GetSubFileExtension();
break;
}
+ */
}
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
+ {
+ char temp[16];
+ ConvertUInt32ToString(entry.Tag, temp);
+
+ _metadata += temp;
+ _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 += ' ';
+ char temp[16];
+ ConvertUInt32ToString(Get32(p + t * 4), temp);
+ _metadata += temp;
+ }
+ #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 += ' ';
+ char temp[16];
+ ConvertUInt32ToString(Get16(p + t * 2), temp);
+ _metadata += temp;
+ }
+ }
+ 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
+ }
+ }
+
+ 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();
+ #endif
+
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
if (numItems == 0)
return S_OK;
- if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
RINOK(extractCallback->SetTotal(_size));
+
CMyComPtr<ISequentialOutStream> outStream;
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
@@ -262,30 +753,38 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
return S_OK;
RINOK(extractCallback->PrepareOperation(askMode));
- CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
- RINOK(_stream->Seek(_pos, STREAM_SEEK_SET, NULL));
- RINOK(copyCoder->Code(_stream, outStream, NULL, NULL, progress));
+ RINOK(_stream->Seek(_headersSize, STREAM_SEEK_SET, NULL));
+ RINOK(copyCoder->Code(_stream, outStream, NULL, &_size, progress));
outStream.Release();
- return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK);
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ if (copyCoderSpec->TotalSize < _size)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ return extractCallback->SetOperationResult(opRes);
COM_TRY_END
}
STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)
{
COM_TRY_BEGIN
- return CreateLimitedInStream(_stream, _pos, _size, stream);
+ return CreateLimitedInStream(_stream, _headersSize, _size, stream);
COM_TRY_END
}
-static IInArchive *CreateArc() { return new NArchive::NRpm::CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"Rpm", L"rpm", 0, 0xEB, { 0xED, 0xAB, 0xEE, 0xDB}, 4, false, CreateArc, 0 };
+ { "Rpm", "rpm", 0, 0xEB,
+ 4, { 0xED, 0xAB, 0xEE, 0xDB},
+ 0,
+ 0,
+ CreateArc };
REGISTER_ARC(Rpm)
diff --git a/CPP/7zip/Archive/SplitHandler.cpp b/CPP/7zip/Archive/SplitHandler.cpp
index 5d84de4e..19dc1b47 100755..100644
--- a/CPP/7zip/Archive/SplitHandler.cpp
+++ b/CPP/7zip/Archive/SplitHandler.cpp
@@ -2,10 +2,10 @@
#include "StdAfx.h"
-#include "Common/ComTry.h"
-#include "Common/MyString.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/MyString.h"
-#include "Windows/PropVariant.h"
+#include "../../Windows/PropVariant.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
@@ -19,15 +19,16 @@ using namespace NWindows;
namespace NArchive {
namespace NSplit {
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8}
+ kpidPath,
+ kpidSize
};
-STATPROPSTG kArcProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidNumVolumes, VT_UI4}
+ kpidNumVolumes,
+ kpidTotalPhySize
};
class CHandler:
@@ -35,10 +36,12 @@ class CHandler:
public IInArchiveGetStream,
public CMyUnknownImp
{
- UString _subName;
CObjectVector<CMyComPtr<IInStream> > _streams;
CRecordVector<UInt64> _sizes;
+ UString _subName;
UInt64 _totalSize;
+
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
public:
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
@@ -51,9 +54,11 @@ IMP_IInArchive_ArcProps
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
NCOM::CPropVariant prop;
- switch(propID)
+ 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);
@@ -72,20 +77,18 @@ struct CSeqName
if (_splitStyle)
{
int i;
- int numLetters = _changedPart.Length();
+ int numLetters = _changedPart.Len();
for (i = numLetters - 1; i >= 0; i--)
{
wchar_t c = _changedPart[i];
if (c == 'z')
{
- c = 'a';
- newName = c + newName;
+ newName.InsertAtFront('a');
continue;
}
else if (c == 'Z')
{
- c = 'A';
- newName = c + newName;
+ newName.InsertAtFront('A');
continue;
}
c++;
@@ -99,33 +102,32 @@ struct CSeqName
newName += newChar;
break;
}
- newName = c + newName;
+ newName.InsertAtFront(c);
i--;
for (; i >= 0; i--)
- newName = _changedPart[i] + newName;
+ newName.InsertAtFront(_changedPart[i]);
break;
}
}
else
{
int i;
- int numLetters = _changedPart.Length();
+ int numLetters = _changedPart.Len();
for (i = numLetters - 1; i >= 0; i--)
{
wchar_t c = _changedPart[i];
- if (c == L'9')
+ if (c == '9')
{
- c = L'0';
- newName = c + newName;
+ newName.InsertAtFront('0');
if (i == 0)
- newName = UString(L'1') + newName;
+ newName.InsertAtFront('1');
continue;
}
c++;
- newName = c + newName;
+ newName.InsertAtFront(c);
i--;
for (; i >= 0; i--)
- newName = _changedPart[i] + newName;
+ newName.InsertAtFront(_changedPart[i]);
break;
}
}
@@ -134,142 +136,139 @@ struct CSeqName
}
};
-STDMETHODIMP CHandler::Open(IInStream *stream,
- const UInt64 * /* maxCheckStartPosition */,
- IArchiveOpenCallback *openArchiveCallback)
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
{
- COM_TRY_BEGIN
Close();
- if (openArchiveCallback == 0)
+ if (!callback)
return S_FALSE;
- // try
+
+ CMyComPtr<IArchiveOpenVolumeCallback> volumeCallback;
+ callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback);
+ if (!volumeCallback)
+ return S_FALSE;
+
+ UString name;
{
- CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
- CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openArchiveCallback;
- if (openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback,
- &openVolumeCallback) != S_OK)
+ NCOM::CPropVariant prop;
+ RINOK(volumeCallback->GetProperty(kpidName, &prop));
+ if (prop.vt != VT_BSTR)
return S_FALSE;
-
- UString name;
- {
- NCOM::CPropVariant prop;
- RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
- if (prop.vt != VT_BSTR)
- return S_FALSE;
- name = prop.bstrVal;
- }
-
- int dotPos = name.ReverseFind('.');
- UString prefix, ext;
- if (dotPos >= 0)
- {
- prefix = name.Left(dotPos + 1);
- ext = name.Mid(dotPos + 1);
- }
- else
- ext = name;
- UString extBig = ext;
- extBig.MakeUpper();
-
- CSeqName seqName;
-
- int numLetters = 2;
- bool splitStyle = false;
- if (extBig.Right(2) == L"AA")
+ name = prop.bstrVal;
+ }
+
+ int dotPos = name.ReverseFind('.');
+ 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())
{
- splitStyle = true;
- while (numLetters < extBig.Length())
- {
- if (extBig[extBig.Length() - numLetters - 1] != 'A')
- break;
- numLetters++;
- }
+ if (ext2[ext2.Len() - numLetters - 1] != 'a')
+ break;
+ numLetters++;
}
- else if (ext.Right(2) == L"01")
+ }
+ else if (ext.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "01"))
+ {
+ while (numLetters < ext2.Len())
{
- while (numLetters < extBig.Length())
- {
- if (extBig[extBig.Length() - numLetters - 1] != '0')
- break;
- numLetters++;
- }
- if (numLetters != ext.Length())
- return S_FALSE;
+ if (ext2[ext2.Len() - numLetters - 1] != '0')
+ break;
+ numLetters++;
}
- else
+ if (numLetters != ext.Len())
return S_FALSE;
-
- _streams.Add(stream);
-
- seqName._unchangedPart = prefix + ext.Left(extBig.Length() - numLetters);
- seqName._changedPart = ext.Right(numLetters);
- seqName._splitStyle = splitStyle;
-
- if (prefix.Length() < 1)
- _subName = L"file";
- else
- _subName = prefix.Left(prefix.Length() - 1);
-
- _totalSize = 0;
- UInt64 size;
+ }
+ 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 = L"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;
+ }
+
+ _totalSize += size;
+ _sizes.Add(size);
+ _streams.Add(stream);
+
+ {
+ UInt64 numFiles = _streams.Size();
+ RINOK(callback->SetCompleted(&numFiles, NULL));
+ }
+
+ for (;;)
+ {
+ const UString fullName = seqName.GetNextName();
+ CMyComPtr<IInStream> nextStream;
+ HRESULT result = volumeCallback->GetStream(fullName, &nextStream);
+ if (result == S_FALSE)
+ break;
+ if (result != S_OK)
+ return result;
+ if (!stream)
+ break;
{
NCOM::CPropVariant prop;
- RINOK(openVolumeCallback->GetProperty(kpidSize, &prop));
+ RINOK(volumeCallback->GetProperty(kpidSize, &prop));
if (prop.vt != VT_UI8)
return E_INVALIDARG;
size = prop.uhVal.QuadPart;
}
_totalSize += size;
_sizes.Add(size);
-
- if (openArchiveCallback != NULL)
+ _streams.Add(nextStream);
{
UInt64 numFiles = _streams.Size();
- RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
- }
-
- for (;;)
- {
- UString fullName = seqName.GetNextName();
- CMyComPtr<IInStream> nextStream;
- HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream);
- if (result == S_FALSE)
- break;
- if (result != S_OK)
- return result;
- if (!stream)
- break;
- {
- NCOM::CPropVariant prop;
- RINOK(openVolumeCallback->GetProperty(kpidSize, &prop));
- if (prop.vt != VT_UI8)
- return E_INVALIDARG;
- size = prop.uhVal.QuadPart;
- }
- _totalSize += size;
- _sizes.Add(size);
- _streams.Add(nextStream);
- if (openArchiveCallback != NULL)
- {
- UInt64 numFiles = _streams.Size();
- RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
- }
+ RINOK(callback->SetCompleted(&numFiles, NULL));
}
}
- /*
- catch(...)
+
+ if (_streams.Size() == 1)
{
- return S_FALSE;
+ 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()
{
- _sizes.Clear();
+ _totalSize = 0;
+ _subName.Empty();
_streams.Clear();
+ _sizes.Clear();
return S_OK;
}
@@ -281,8 +280,8 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
{
- NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ NCOM::CPropVariant prop;
+ switch (propID)
{
case kpidPath: prop = _subName; break;
case kpidSize:
@@ -300,7 +299,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_BEGIN
if (numItems == 0)
return S_OK;
- if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
UInt64 currentTotalSize = 0;
@@ -321,7 +320,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
- for (int i = 0; i < _streams.Size(); i++)
+ FOR_VECTOR (i, _streams)
{
lps->InSize = lps->OutSize = currentTotalSize;
RINOK(lps->SetCur());
@@ -343,7 +342,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
*stream = 0;
CMultiStream *streamSpec = new CMultiStream;
CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
- for (int i = 0; i < _streams.Size(); i++)
+ FOR_VECTOR (i, _streams)
{
CMultiStream::CSubStreamInfo subStreamInfo;
subStreamInfo.Stream = _streams[i];
@@ -356,10 +355,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
-{ L"Split", L"001", 0, 0xEA, { 0 }, 0, false, CreateArc, 0 };
+ { "Split", "001", 0, 0xEA,
+ 0, { 0 },
+ 0,
+ 0,
+ CreateArc };
REGISTER_ARC(Split)
diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp
index efaffed1..617a1d66 100755..100644
--- a/CPP/7zip/Archive/SquashfsHandler.cpp
+++ b/CPP/7zip/Archive/SquashfsHandler.cpp
@@ -7,12 +7,12 @@
#include "../../../C/CpuArch.h"
#include "../../../C/Xz.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/StringConvert.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/StringConvert.h"
-#include "Windows/PropVariantUtils.h"
-#include "Windows/Time.h"
+#include "../../Windows/PropVariantUtils.h"
+#include "../../Windows/TimeUtils.h"
#include "../Common/CWrappers.h"
#include "../Common/LimitedStreams.h"
@@ -59,8 +59,6 @@ UInt64 Get64b(const Byte *p, bool be) { return be ? GetBe64(p) : GetUi64(p); }
#define GET_32(offs, dest) dest = Get32(p + (offs));
#define GET_64(offs, dest) dest = Get64(p + (offs));
-static const UInt32 kSignatureSize = 4;
-#define SIGNATURE { 'h', 's', 'q', 's' }
static const UInt32 kSignature32_LE = 0x73717368;
static const UInt32 kSignature32_BE = 0x68737173;
static const UInt32 kSignature32_LZ = 0x71736873;
@@ -72,11 +70,11 @@ static const UInt32 kSignature32_LZ = 0x71736873;
static const char *k_Methods[] =
{
- "Unknown",
- "ZLIB",
- "LZMA",
- "LZO",
- "XZ"
+ "Unknown"
+ , "ZLIB"
+ , "LZMA"
+ , "LZO"
+ , "XZ"
};
static const UInt32 kMetadataBlockSizeLog = 13;
@@ -315,17 +313,17 @@ UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h)
UInt16 t = Get16(p);
if (be)
{
- Type = t >> 12;
- Mode = t & 0xFFF;
- Uid = p[2] >> 4;
- Gid = p[2] & 0xF;
+ Type = (UInt16)(t >> 12);
+ Mode = (UInt16)(t & 0xFFF);
+ Uid = (UInt16)(p[2] >> 4);
+ Gid = (UInt16)(p[2] & 0xF);
}
else
{
- Type = t & 0xF;
- Mode = t >> 4;
- Uid = p[2] & 0xF;
- Gid = p[2] >> 4;
+ Type = (UInt16)(t & 0xF);
+ Mode = (UInt16)(t >> 4);
+ Uid = (UInt16)(p[2] & 0xF);
+ Gid = (UInt16)(p[2] >> 4);
}
// Xattr = kXattr_Empty;
@@ -339,20 +337,20 @@ UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h)
Byte t = p[3];
if (be)
{
- Type = t >> 4;
- Offset = t & 0xF;
+ Type = (UInt16)(t >> 4);
+ Offset = (UInt16)(t & 0xF);
}
else
{
- Type = t & 0xF;
- Offset = t >> 4;
+ Type = (UInt16)(t & 0xF);
+ Offset = (UInt16)(t >> 4);
}
return (Type == kType_FIFO || Type == kType_SOCK) ? 4 : 0;
}
Type--;
- Uid += (Type / 5) * 16;
- Type = (Type % 5) + 1;
+ Uid = (UInt16)(Uid + (Type / 5) * 16);
+ Type = (UInt16)((Type % 5) + 1);
if (Type == kType_FILE)
{
@@ -418,13 +416,13 @@ UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h)
UInt16 t = Get16(p);
if (be)
{
- Type = t >> 12;
- Mode = t & 0xFFF;
+ Type = (UInt16)(t >> 12);
+ Mode = (UInt16)(t & 0xFFF);
}
else
{
- Type = t & 0xF;
- Mode = t >> 4;
+ Type = (UInt16)(t & 0xF);
+ Mode = (UInt16)(t >> 4);
}
Uid = p[2];
Gid = p[3];
@@ -548,13 +546,13 @@ UInt32 CNode::Parse3(const Byte *p, UInt32 size, const CHeader &_h)
UInt16 t = Get16(p);
if (be)
{
- Type = t >> 12;
- Mode = t & 0xFFF;
+ Type = (UInt16)(t >> 12);
+ Mode = (UInt16)(t & 0xFFF);
}
else
{
- Type = t & 0xF;
- Mode = t >> 4;
+ Type = (UInt16)(t & 0xF);
+ Mode = (UInt16)(t >> 4);
}
Uid = p[2];
Gid = p[3];
@@ -841,6 +839,8 @@ class CHandler:
// CByteBuffer _uids;
// CByteBuffer _gids;
CHeader _h;
+ bool _noPropsLZMA;
+ bool _needCheckLzma;
CMyComPtr<IInStream> _stream;
UInt64 _sizeCalculated;
@@ -922,31 +922,30 @@ CHandler::CHandler()
_dynOutStream = _dynOutStreamSpec;
}
-static const STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidPosixAttrib, VT_UI4}
- // { NULL, kpidUser, VT_BSTR},
- // { NULL, kpidGroup, VT_BSTR},
- // { NULL, kpidLinks, VT_UI4},
- // { NULL, kpidOffset, VT_UI4}
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidPosixAttrib
+ // kpidUser,
+ // kpidGroup,
+ // kpidLinks,
+ // kpidOffset
};
-static const STATPROPSTG kArcProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidFileSystem, VT_BSTR},
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidBlock, VT_UI4},
- { NULL, kpidPhySize, VT_UI8},
- { NULL, kpidHeadersSize, VT_UI8},
- { NULL, kpidBigEndian, VT_BOOL},
- { NULL, kpidCTime, VT_FILETIME},
- { NULL, kpidCharacts, VT_BSTR}
- // { NULL, kpidNumBlocks, VT_UI4}
+ kpidHeadersSize,
+ kpidFileSystem,
+ kpidMethod,
+ kpidBlock,
+ kpidBigEndian,
+ kpidCTime,
+ kpidCharacts
+ // kpidNumBlocks
};
IMP_IInArchive_Props
@@ -1115,12 +1114,25 @@ HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool
UInt32 method = _h.Method;
if (_h.SeveralMethods)
{
- Byte props[1];
- RINOK(ReadStream_FALSE(_stream, props, 1));
- method = (props[0] == 0x5D ? kMethod_LZMA : kMethod_ZLIB);
+ 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)
@@ -1140,24 +1152,34 @@ HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool
_lzmaDecoderSpec->FinishStream = true;
_lzmaDecoder = _lzmaDecoderSpec;
}
- const UInt32 kPropsSize = 5 + 8;
+ const UInt32 kPropsSize = LZMA_PROPS_SIZE + 8;
Byte props[kPropsSize];
- ReadStream_FALSE(_limitedInStream, props, kPropsSize);
- RINOK(_lzmaDecoderSpec->SetDecoderProperties2(props, 5));
- UInt64 outSize = GetUi64(props + 5);
- if (outSize > outSizeMax)
- return S_FALSE;
+ 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 != kPropsSize + _lzmaDecoderSpec->GetInputProcessedSize())
+ if (inSize != propsSize + _lzmaDecoderSpec->GetInputProcessedSize())
return S_FALSE;
}
else
{
- if (_inputBuffer.GetCapacity() < inSize)
- {
- _inputBuffer.Free();
- _inputBuffer.SetCapacity(inSize);
- }
+ if (_inputBuffer.Size() < inSize)
+ _inputBuffer.Alloc(inSize);
RINOK(ReadStream_FALSE(_stream, _inputBuffer, inSize));
Byte *dest = outBuf;
@@ -1287,22 +1309,23 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned
if (blockIndex < 0)
return S_FALSE;
unpackPos = _dirs.UnpackPos[blockIndex] + n.Offset;
- if (unpackPos < n.Offset || unpackPos > _dirs.Data.GetCapacity())
+ if (unpackPos < n.Offset || unpackPos > _dirs.Data.Size())
return S_FALSE;
- UInt32 rem = (UInt32)_dirs.Data.GetCapacity() - unpackPos;
+ UInt32 rem = (UInt32)_dirs.Data.Size() - unpackPos;
const Byte *p = _dirs.Data + unpackPos;
UInt32 fileSize = (UInt32)n.FileSize;
- if (fileSize > rem)
- return S_FALSE;
- rem = fileSize;
+ // for some squashfs files: fileSize = rem + 3 !!!
if (_h.Major >= 3)
{
- if (rem < 3)
+ if (fileSize < 3)
return S_FALSE;
- rem -= 3;
+ fileSize -= 3;
}
+ if (fileSize > rem)
+ return S_FALSE;
+ rem = fileSize;
CRecordVector<CTempItem> tempItems;
while (rem != 0)
@@ -1412,7 +1435,7 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned
}
int startItemIndex = _items.Size() - tempItems.Size();
- for (int i = 0; i < tempItems.Size(); i++)
+ FOR_VECTOR (i, tempItems)
{
const CTempItem &tempItem = tempItems[i];
int index = startItemIndex + i;
@@ -1443,9 +1466,11 @@ HRESULT CHandler::Open2(IInStream *inStream)
if (!_h.IsSupported())
return E_NOTIMPL;
+ _noPropsLZMA = false;
+ _needCheckLzma = false;
switch (_h.Method)
{
- case kMethod_ZLIB:
+ case kMethod_ZLIB: _needCheckLzma = true; break;
case kMethod_LZMA:
case kMethod_LZO:
case kMethod_XZ:
@@ -1461,14 +1486,13 @@ HRESULT CHandler::Open2(IInStream *inStream)
{
if (_h.NumFrags > kNumFilesMax)
return S_FALSE;
- _frags.Reserve(_h.NumFrags);
- CByteBuffer data;
+ _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);
- data.SetCapacity(numBlocksBytes);
+ CByteBuffer data(numBlocksBytes);
RINOK(inStream->Seek(_h.FragTable, STREAM_SEEK_SET, NULL));
RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes));
bool be = _h.be;
@@ -1518,11 +1542,11 @@ HRESULT CHandler::Open2(IInStream *inStream)
return S_FALSE;
{
UInt32 pos = 0;
- UInt32 totalSize = (UInt32)_inodesData.Data.GetCapacity();
- _nodesPos.Reserve(_h.NumInodes);
- _nodes.Reserve(_h.NumInodes);
+ UInt32 totalSize = (UInt32)_inodesData.Data.Size();
+ _nodesPos.ClearAndReserve(_h.NumInodes);
+ _nodes.ClearAndReserve(_h.NumInodes);
// we use _blockToNode for binary search seed optimizations
- _blockToNode.Reserve(_inodesData.GetNumBlocks() + 1);
+ _blockToNode.ClearAndReserve(_inodesData.GetNumBlocks() + 1);
int curBlock = 0;
for (UInt32 i = 0; i < _h.NumInodes; i++)
{
@@ -1544,8 +1568,8 @@ HRESULT CHandler::Open2(IInStream *inStream)
_blockToNode.Add(_nodesPos.Size());
curBlock++;
}
- _nodesPos.Add(pos);
- _nodes.Add(n);
+ _nodesPos.AddInReserved(pos);
+ _nodes.AddInReserved(n);
pos += size;
}
_blockToNode.Add(_nodesPos.Size());
@@ -1657,7 +1681,6 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb
HRESULT res;
try
{
- RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
_openCallback = callback;
res = Open2(stream);
}
@@ -1679,6 +1702,8 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb
STDMETHODIMP CHandler::Close()
{
+ _sizeCalculated = 0;
+
_limitedInStreamSpec->ReleaseStream();
_stream.Release();
@@ -1801,12 +1826,14 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidMethod:
{
const char *s;
- if (_h.SeveralMethods)
+ if (_noPropsLZMA)
+ s = "LZMA Spec";
+ else if (_h.SeveralMethods)
s = "LZMA ZLIB";
else
{
s = k_Methods[0];
- if (_h.Method < sizeof(k_Methods) / sizeof(k_Methods[0]))
+ if (_h.Method < ARRAY_SIZE(k_Methods))
s = k_Methods[_h.Method];
}
prop = s;
@@ -1906,7 +1933,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
}
case kpidPosixAttrib:
{
- if (node.Type != 0 && node.Type < sizeof(k_TypeToMode) / sizeof(k_TypeToMode[0]))
+ if (node.Type != 0 && node.Type < ARRAY_SIZE(k_TypeToMode))
prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type];
break;
}
@@ -1914,7 +1941,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidUser:
{
UInt32 offset = node.Uid * 4;
- if (offset < _uids.GetCapacity())
+ if (offset < _uids.Size())
prop = (UInt32)Get32(_uids + offset);
break;
}
@@ -1923,13 +1950,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
if (_h.Major == 4 || node.Gid == _h.GetSpecGuidIndex())
{
UInt32 offset = node.Uid * 4;
- if (offset < _uids.GetCapacity())
+ if (offset < _uids.Size())
prop = (UInt32)Get32(_uids + offset);
}
else
{
UInt32 offset = node.Gid * 4;
- if (offset < _gids.GetCapacity())
+ if (offset < _gids.Size())
prop = (UInt32)Get32(_gids + offset);
}
break;
@@ -2028,7 +2055,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items.Size();
if (numItems == 0)
@@ -2095,7 +2122,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
if (hres == E_OUTOFMEMORY)
return hres;
- res = NExtract::NOperationResult::kUnSupportedMethod;
+ res = NExtract::NOperationResult::kUnsupportedMethod;
}
else
{
@@ -2110,7 +2137,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
else if (hres == E_NOTIMPL)
{
- res = NExtract::NOperationResult::kUnSupportedMethod;
+ res = NExtract::NOperationResult::kUnsupportedMethod;
}
else if(hres != S_FALSE)
{
@@ -2157,10 +2184,10 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
_nodeIndex = item.Node;
size_t cacheSize = _h.BlockSize;
- if (_cachedBlock.GetCapacity() != cacheSize)
+ if (_cachedBlock.Size() != cacheSize)
{
ClearCache();
- _cachedBlock.SetCapacity(cacheSize);
+ _cachedBlock.Alloc(cacheSize);
}
CSquashfsInStream *streamSpec = new CSquashfsInStream;
@@ -2179,10 +2206,19 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
COM_TRY_END
}
-static IInArchive *CreateArc() { return new NArchive::NSquashfs::CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"SquashFS", L"squashfs", 0, 0xD2, SIGNATURE, kSignatureSize, false, CreateArc, 0 };
+ { "SquashFS", "squashfs", 0, 0xD2,
+ 3 * (1 + 4),
+ {
+ 4, 'h', 's', 'q', 's',
+ 4, 's', 'q', 's', 'h',
+ 4, 's', 'h', 's', 'q',
+ },
+ 0,
+ NArcInfoFlags::kMultiSignature,
+ CreateArc };
REGISTER_ARC(Cramfs)
diff --git a/CPP/7zip/Archive/StdAfx.h b/CPP/7zip/Archive/StdAfx.h
index ef555ec1..1cbd7fea 100755..100644
--- a/CPP/7zip/Archive/StdAfx.h
+++ b/CPP/7zip/Archive/StdAfx.h
@@ -3,7 +3,6 @@
#ifndef __STDAFX_H
#define __STDAFX_H
-#include "../../Common/MyWindows.h"
-#include "../../Common/NewHandler.h"
+#include "../../Common/Common.h"
#endif
diff --git a/CPP/7zip/Archive/SwfHandler.cpp b/CPP/7zip/Archive/SwfHandler.cpp
index d7d9537e..7cfea330 100755..100644
--- a/CPP/7zip/Archive/SwfHandler.cpp
+++ b/CPP/7zip/Archive/SwfHandler.cpp
@@ -4,19 +4,23 @@
#include "../../../C/CpuArch.h"
-#include "Common/Buffer.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/MyString.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyString.h"
-#include "Windows/PropVariant.h"
+#include "../../Windows/PropVariant.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"
@@ -26,33 +30,120 @@
using namespace NWindows;
namespace NArchive {
+
+static const UInt32 kFileSizeMax = (UInt32)1 << 29;
+
namespace NSwfc {
-static const UInt32 kHeaderSize = 8;
+static const unsigned kHeaderBaseSize = 8;
+static const unsigned kHeaderLzmaSize = 17;
static const Byte SWF_UNCOMPRESSED = 'F';
-static const Byte SWF_COMPRESSED = 'C';
-static const Byte SWF_MIN_COMPRESSED_VER = 6;
+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 = 20;
+
+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[kHeaderSize];
+ Byte Buf[kHeaderLzmaSize];
+ unsigned HeaderSize;
UInt32 GetSize() const { return GetUi32(Buf + 4); }
- bool IsSwf(Byte c) const { return (Buf[0] == c && Buf[1] == 'W' && Buf[2] == 'S' && Buf[3] < 32); }
- bool IsUncompressed() const { return IsSwf(SWF_UNCOMPRESSED); }
- bool IsCompressed() const { return IsSwf(SWF_COMPRESSED); }
+ UInt32 GetLzmaPackSize() const { return GetUi32(Buf + 8); }
+ UInt32 GetLzmaDicSize() const { return GetUi32(Buf + 13); }
- void MakeUncompressed() { Buf[0] = SWF_UNCOMPRESSED; }
- void MakeCompressed()
+ 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;
- if (Buf[3] < SWF_MIN_COMPRESSED_VER)
- Buf[3] = SWF_MIN_COMPRESSED_VER;
+ 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) { return ReadStream_FALSE(stream, Buf, kHeaderSize); }
- HRESULT WriteHeader(ISequentialOutStream *stream) { return WriteStream(stream, Buf, kHeaderSize); }
+ HRESULT ReadHeader(ISequentialInStream *stream)
+ {
+ HeaderSize = kHeaderBaseSize;
+ return ReadStream_FALSE(stream, Buf, kHeaderBaseSize);
+ }
+ HRESULT WriteHeader(ISequentialOutStream *stream)
+ {
+ return WriteStream(stream, Buf, HeaderSize);
+ }
};
class CHandler:
@@ -69,19 +160,22 @@ class CHandler:
CMyComPtr<IInStream> _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 **names, const PROPVARIANT *values, Int32 numProps);
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps);
};
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8}
+ kpidSize,
+ kpidPackSize,
+ kpidMethod
};
IMP_IInArchive_Props
@@ -90,9 +184,10 @@ IMP_IInArchive_ArcProps_NO_Table
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
- case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidPhySize: if (_packSizeDefined) prop = _item.HeaderSize + _packSize; break;
+ case kpidIsNotArcType: prop = true; break;
}
prop.Detach(value);
return S_OK;
@@ -104,13 +199,48 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
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);
+ int pos = MyStringLen(s);
+ s[pos++] = c;
+ s[pos] = 0;
+}
+
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
{
NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidSize: prop = (UInt64)_item.GetSize(); break;
- case kpidPackSize: if (_packSizeDefined) prop = _packSize; 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;
@@ -126,30 +256,63 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb
STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
{
Close();
- HRESULT res = _item.ReadHeader(stream);
- if (res == S_OK)
- if (_item.IsCompressed())
- _seqStream = stream;
- else
- res = S_FALSE;
- return res;
+ 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<IArchiveOpenCallback> Callback;
+public:
+ UInt64 Offset;
+ MY_UNKNOWN_IMP1(ICompressProgressInfo)
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+ void Init(IArchiveOpenCallback *callback) { Callback = callback; }
+};
+
+STDMETHODIMP CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)
+{
+ if (Callback)
+ {
+ 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)-1 && (numItems != 1 || indices[0] != 0))
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
extractCallback->SetTotal(_item.GetSize());
@@ -163,9 +326,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
extractCallback->PrepareOperation(askMode);
- NCompress::NZlib::CDecoder *_decoderSpec = new NCompress::NZlib::CDecoder;
- CMyComPtr<ICompressCoder> _decoder = _decoderSpec;
-
CDummyOutStream *outStreamSpec = new CDummyOutStream;
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
outStreamSpec->SetStream(realOutStream);
@@ -176,24 +336,73 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
- lps->InSize = kHeaderSize;
+ lps->InSize = _item.HeaderSize;
lps->OutSize = outStreamSpec->GetSize();
RINOK(lps->SetCur());
CItem item = _item;
item.MakeUncompressed();
- RINOK(item.WriteHeader(outStream));
if (_stream)
- RINOK(_stream->Seek(kHeaderSize, STREAM_SEEK_SET, NULL));
- HRESULT result = _decoderSpec->Code(_seqStream, outStream, NULL, NULL, progress);
+ RINOK(_stream->Seek(_item.HeaderSize, STREAM_SEEK_SET, NULL));
+ NCompress::NZlib::CDecoder *_decoderZlibSpec = NULL;
+ NCompress::NLzma::CDecoder *_decoderLzmaSpec = NULL;
+ CMyComPtr<ICompressCoder> _decoder;
+
+ CMyComPtr<ISequentialInStream> inStream2;
+
+ UInt64 unpackSize = _item.GetSize() - (UInt32)8;
+ if (_item.IsZlib())
+ {
+ _decoderZlibSpec = new NCompress::NZlib::CDecoder;
+ _decoder = _decoderZlibSpec;
+ inStream2 = _seqStream;
+ }
+ else
+ {
+ /* Some .swf files with lzma contain additional 8 bytes at the end
+ in uncompressed stream.
+ What does that data mean ???
+ We don't decompress these additional 8 bytes */
+
+ // unpackSize = _item.GetSize();
+ // SetUi32(item.Buf + 4, (UInt32)(unpackSize + 8));
+ CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream;
+ inStream2 = limitedStreamSpec;
+ limitedStreamSpec->SetStream(_seqStream);
+ limitedStreamSpec->Init(_item.GetLzmaPackSize());
+
+ _decoderLzmaSpec = new NCompress::NLzma::CDecoder;
+ _decoder = _decoderLzmaSpec;
+ // _decoderLzmaSpec->FinishStream = true;
+
+ Byte props[5];
+ memcpy(props, _item.Buf + 12, 5);
+ UInt32 dicSize = _item.GetLzmaDicSize();
+ if (dicSize > (UInt32)unpackSize)
+ {
+ dicSize = (UInt32)unpackSize;
+ SetUi32(props + 1, dicSize);
+ }
+ RINOK(_decoderLzmaSpec->SetDecoderProperties2(props, 5));
+ }
+ RINOK(item.WriteHeader(outStream));
+ HRESULT result = _decoder->Code(inStream2, outStream, NULL, &unpackSize, progress);
Int32 opRes = NExtract::NOperationResult::kDataError;
if (result == S_OK)
{
- if (_item.GetSize() == outStreamSpec->GetSize())
+ if (item.GetSize() == outStreamSpec->GetSize())
{
- _packSizeDefined = true;
- _packSize = _decoderSpec->GetInputProcessedSize() + kHeaderSize;
- opRes = NExtract::NOperationResult::kOK;
+ 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)
@@ -204,8 +413,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
-static HRESULT UpdateArchive(ISequentialOutStream *outStream,
- UInt64 size, const CSingleMethodProps &props,
+static HRESULT UpdateArchive(ISequentialOutStream *outStream, UInt64 size,
+ bool lzmaMode, const CSingleMethodProps &props,
IArchiveUpdateCallback *updateCallback)
{
UInt64 complexity = 0;
@@ -215,27 +424,73 @@ static HRESULT UpdateArchive(ISequentialOutStream *outStream,
CMyComPtr<ISequentialInStream> fileInStream;
RINOK(updateCallback->GetStream(0, &fileInStream));
+ /*
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+ */
+
CItem item;
HRESULT res = item.ReadHeader(fileInStream);
if (res == S_FALSE)
return E_INVALIDARG;
RINOK(res);
- if (!item.IsUncompressed() || size != item.GetSize())
+ if (!item.IsSwf() || !item.IsUncompressed() || size != item.GetSize())
return E_INVALIDARG;
- item.MakeCompressed();
- item.WriteHeader(outStream);
+ NCompress::NZlib::CEncoder *encoderZlibSpec = NULL;
+ NCompress::NLzma::CEncoder *encoderLzmaSpec = NULL;
+ CMyComPtr<ICompressCoder> encoder;
+ CMyComPtr<IOutStream> outSeekStream;
+ if (lzmaMode)
+ {
+ outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream);
+ if (!outSeekStream)
+ return E_NOTIMPL;
+ encoderLzmaSpec = new NCompress::NLzma::CEncoder;
+ encoder = encoderLzmaSpec;
+ RINOK(props.SetCoderProps(encoderLzmaSpec, &size));
+ item.MakeLzma((UInt32)0xFFFFFFFF);
+ CBufPtrSeqOutStream *propStreamSpec = new CBufPtrSeqOutStream;
+ CMyComPtr<ISequentialOutStream> propStream = propStreamSpec;
+ propStreamSpec->Init(item.Buf + 12, 5);
+ RINOK(encoderLzmaSpec->WriteCoderProperties(propStream));
+ }
+ else
+ {
+ encoderZlibSpec = new NCompress::NZlib::CEncoder;
+ encoder = encoderZlibSpec;
+ encoderZlibSpec->Create();
+ RINOK(props.SetCoderProps(encoderZlibSpec->DeflateEncoderSpec, NULL));
+ item.MakeZlib();
+ }
+ RINOK(item.WriteHeader(outStream));
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(updateCallback, true);
- NCompress::NZlib::CEncoder *encoderSpec = new NCompress::NZlib::CEncoder;
- CMyComPtr<ICompressCoder> encoder = encoderSpec;
- encoderSpec->Create();
- RINOK(props.SetCoderProps(encoderSpec->DeflateEncoderSpec, NULL));
RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, progress));
- if (encoderSpec->GetInputProcessedSize() + kHeaderSize != size)
+ 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);
}
@@ -283,7 +538,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return E_INVALIDARG;
size = prop.uhVal.QuadPart;
}
- return UpdateArchive(outStream, size, _props, updateCallback);
+ return UpdateArchive(outStream, size, _lzmaMode, _props, updateCallback);
}
if (indexInArchive != 0)
@@ -301,20 +556,37 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return NCompress::CopyStream(_seqStream, outStream, NULL);
}
-STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
{
- return _props.SetProperties(names, values, numProps);
+ _lzmaMode = false;
+ RINOK(_props.SetProperties(names, values, numProps));
+ UString m = _props.MethodName;
+ m.MakeLower_Ascii();
+ if (m.IsEqualTo("lzma"))
+ {
+ return E_NOTIMPL;
+ // _lzmaMode = true;
+ }
+ else if (m.IsEqualTo("deflate") || m.IsEmpty())
+ _lzmaMode = false;
+ else
+ return E_INVALIDARG;
+ return S_OK;
}
-static IInArchive *CreateArc() { return new CHandler; }
-#ifndef EXTRACT_ONLY
-static IOutArchive *CreateArcOut() { return new CHandler; }
-#else
-#define CreateArcOut 0
-#endif
+IMP_CreateArcIn
+IMP_CreateArcOut
static CArcInfo g_ArcInfo =
- { L"SWFc", L"swf", L"~.swf", 0xD8, { 'C', 'W', 'S' }, 3, true, CreateArc, CreateArcOut };
+ { "SWFc", "swf", "~.swf", 0xD8,
+ 2 + 3 + 3,
+ {
+ 3, 'C', 'W', 'S',
+ 3, 'Z', 'W', 'S',
+ },
+ 0,
+ NArcInfoFlags::kMultiSignature,
+ REF_CreateArc_Pair, IsArc_Swfc };
REGISTER_ARC(Swfc)
@@ -322,8 +594,7 @@ REGISTER_ARC(Swfc)
namespace NSwf {
-static const UInt32 kFileSizeMax = (UInt32)1 << 30;
-static const int kNumTagsMax = (UInt32)1 << 23;
+static const unsigned kNumTagsMax = 1 << 23;
struct CTag
{
@@ -338,7 +609,7 @@ class CHandler:
{
CObjectVector<CTag> _tags;
NSwfc::CItem _item;
- UInt64 _packSize;
+ UInt64 _phySize;
HRESULT OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback);
HRESULT OpenSeq2(ISequentialInStream *stream, IArchiveOpenCallback *callback);
@@ -349,11 +620,11 @@ public:
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
};
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidComment, VT_BSTR}
+ kpidPath,
+ kpidSize,
+ kpidComment,
};
IMP_IInArchive_Props
@@ -362,9 +633,10 @@ IMP_IInArchive_ArcProps_NO_Table
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
- case kpidPhySize: prop = _packSize; break;
+ case kpidPhySize: prop = _phySize; break;
+ case kpidIsNotArcType: prop = true; break;
}
prop.Detach(value);
return S_OK;
@@ -379,105 +651,105 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
static const char *g_TagDesc[92] =
{
- "End",
- "ShowFrame",
- "DefineShape",
- NULL,
- "PlaceObject",
- "RemoveObject",
- "DefineBits",
- "DefineButton",
- "JPEGTables",
- "SetBackgroundColor",
- "DefineFont",
- "DefineText",
- "DoAction",
- "DefineFontInfo",
- "DefineSound",
- "StartSound",
- NULL,
- "DefineButtonSound",
- "SoundStreamHead",
- "SoundStreamBlock",
- "DefineBitsLossless",
- "DefineBitsJPEG2",
- "DefineShape2",
- "DefineButtonCxform",
- "Protect",
- NULL,
- "PlaceObject2",
- NULL,
- "RemoveObject2",
- NULL,
- NULL,
- NULL,
- "DefineShape3",
- "DefineText2",
- "DefineButton2",
- "DefineBitsJPEG3",
- "DefineBitsLossless2",
- "DefineEditText",
- NULL,
- "DefineSprite",
- NULL,
- "41",
- NULL,
- "FrameLabel",
- NULL,
- "SoundStreamHead2",
- "DefineMorphShape",
- NULL,
- "DefineFont2",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "ExportAssets",
- "ImportAssets",
- "EnableDebugger",
- "DoInitAction",
- "DefineVideoStream",
- "VideoFrame",
- "DefineFontInfo2",
- NULL,
- "EnableDebugger2",
- "ScriptLimits",
- "SetTabIndex",
- NULL,
- NULL,
- "FileAttributes",
- "PlaceObject3",
- "ImportAssets2",
- NULL,
- "DefineFontAlignZones",
- "CSMTextSettings",
- "DefineFont3",
- "SymbolClass",
- "Metadata",
- "DefineScalingGrid",
- NULL,
- NULL,
- NULL,
- "DoABC",
- "DefineShape4",
- "DefineMorphShape2",
- NULL,
- "DefineSceneAndFrameLabelData",
- "DefineBinaryData",
- "DefineFontName",
- "StartSound2",
- "DefineBitsJPEG4",
- "DefineFont4"
+ "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)
+ switch (propID)
{
case kpidPath:
{
@@ -491,9 +763,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
}
case kpidSize:
case kpidPackSize:
- prop = (UInt64)tag.Buf.GetCapacity(); break;
+ prop = (UInt64)tag.Buf.Size(); break;
case kpidComment:
- if (tag.Type < sizeof(g_TagDesc) / sizeof(g_TagDesc[0]))
+ if (tag.Type < ARRAY_SIZE(g_TagDesc))
{
const char *s = g_TagDesc[tag.Type];
if (s != NULL)
@@ -579,8 +851,12 @@ UInt32 CBitReader::ReadBits(unsigned numBits)
HRESULT CHandler::OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback)
{
RINOK(_item.ReadHeader(stream))
- if (!_item.IsUncompressed())
+ 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))
@@ -610,13 +886,12 @@ HRESULT CHandler::OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *ca
length = Read32(s);
if (type == 0)
break;
- UInt64 offset = s.GetProcessedSize() + NSwfc::kHeaderSize + length;
- if (offset > kFileSizeMax || _tags.Size() >= kNumTagsMax)
+ UInt64 offset = s.GetProcessedSize() + NSwfc::kHeaderBaseSize + length;
+ if (offset > uncompressedSize || _tags.Size() >= kNumTagsMax)
return S_FALSE;
- _tags.Add(CTag());
- CTag &tag = _tags.Back();
+ CTag &tag = _tags.AddNew();
tag.Type = type;
- tag.Buf.SetCapacity(length);
+ tag.Buf.Alloc(length);
if (s.ReadBytes(tag.Buf, length) != length)
return S_FALSE;
if (callback && offset >= offsetPrev + (1 << 20))
@@ -626,7 +901,12 @@ HRESULT CHandler::OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *ca
offsetPrev = offset;
}
}
- _packSize = s.GetProcessedSize() + NSwfc::kHeaderSize;
+ _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;
}
@@ -645,6 +925,7 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
STDMETHODIMP CHandler::Close()
{
+ _phySize = 0;
return S_OK;
}
@@ -652,7 +933,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _tags.Size();
if (numItems == 0)
@@ -660,7 +941,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
- totalSize += _tags[allFilesMode ? i : indices[i]].Buf.GetCapacity();
+ totalSize += _tags[allFilesMode ? i : indices[i]].Buf.Size();
extractCallback->SetTotal(totalSize);
CLocalProgress *lps = new CLocalProgress;
@@ -678,7 +959,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
NExtract::NAskMode::kExtract;
UInt32 index = allFilesMode ? i : indices[i];
const CByteBuffer &buf = _tags[index].Buf;
- totalSize += buf.GetCapacity();
+ totalSize += buf.Size();
CMyComPtr<ISequentialOutStream> outStream;
RINOK(extractCallback->GetStream(index, &outStream, askMode));
@@ -687,7 +968,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(extractCallback->PrepareOperation(askMode));
if (outStream)
- RINOK(WriteStream(outStream, buf, buf.GetCapacity()));
+ RINOK(WriteStream(outStream, buf, buf.Size()));
outStream.Release();
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
}
@@ -695,10 +976,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"SWF", L"swf", 0, 0xD7, { 'F', 'W', 'S' }, 3, true, CreateArc, 0 };
+ { "SWF", "swf", 0, 0xD7,
+ 3, { 'F', 'W', 'S' },
+ 0,
+ NArcInfoFlags::kKeepName,
+ CreateArc, NULL, NSwfc::IsArc_Swf };
REGISTER_ARC(Swf)
diff --git a/CPP/7zip/Archive/Tar/StdAfx.h b/CPP/7zip/Archive/Tar/StdAfx.h
index 2e4be10b..2854ff3e 100755..100644
--- a/CPP/7zip/Archive/Tar/StdAfx.h
+++ b/CPP/7zip/Archive/Tar/StdAfx.h
@@ -3,7 +3,6 @@
#ifndef __STDAFX_H
#define __STDAFX_H
-#include "../../../Common/MyWindows.h"
-#include "../../../Common/NewHandler.h"
+#include "../../../Common/Common.h"
#endif
diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp
index 251afdb7..fc7de5ae 100755..100644
--- a/CPP/7zip/Archive/Tar/TarHandler.cpp
+++ b/CPP/7zip/Archive/Tar/TarHandler.cpp
@@ -2,13 +2,15 @@
#include "StdAfx.h"
-#include "Common/ComTry.h"
-#include "Common/StringConvert.h"
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/UTFConvert.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.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"
@@ -16,32 +18,34 @@
#include "../Common/ItemNameUtils.h"
#include "TarHandler.h"
-#include "TarIn.h"
using namespace NWindows;
namespace NArchive {
namespace NTar {
-static const char *kUnexpectedEnd = "Unexpected end of archive";
+static const UINT k_DefaultCodePage = CP_OEMCP; // it uses it if UTF8 check in names shows error
-static const STATPROPSTG kProps[] =
+
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidPosixAttrib, VT_UI4},
- { NULL, kpidUser, VT_BSTR},
- { NULL, kpidGroup, VT_BSTR},
- { NULL, kpidLink, VT_BSTR}
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidPosixAttrib,
+ kpidUser,
+ kpidGroup,
+ kpidSymLink,
+ kpidHardLink,
+ // kpidLinkType
};
-static const STATPROPSTG kArcProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidPhySize, VT_UI8},
- { NULL, kpidHeadersSize, VT_UI8}
+ kpidHeadersSize,
+ kpidCodePage
};
IMP_IInArchive_Props
@@ -50,11 +54,42 @@ IMP_IInArchive_ArcProps
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidPhySize: if (_phySizeDefined) prop = _phySize; break;
case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break;
- case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; 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 kpidCodePage:
+ {
+ const char *name = NULL;
+ switch (_openCodePage)
+ {
+ case CP_OEMCP: name = "OEM"; break;
+ case CP_UTF8: name = "UTF-8"; break;
+ }
+ if (name != NULL)
+ prop = name;
+ else
+ {
+ char sz[16];
+ ConvertUInt32ToString(_openCodePage, sz);
+ prop = sz;
+ };
+ break;
+ }
}
prop.Detach(value);
return S_OK;
@@ -63,9 +98,16 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item)
{
item.HeaderPos = _phySize;
- RINOK(ReadItem(stream, filled, item, _errorMessage));
- if (filled && item.IsSparse())
- _isSparse = true;
+ RINOK(ReadItem(stream, filled, item, _error));
+ if (filled)
+ {
+ /*
+ if (item.IsSparse())
+ _isSparse = true;
+ */
+ if (item.IsPaxExtendedHeader())
+ _thereIsPaxExtendedHeader = true;
+ }
_phySize += item.HeaderSize;
_headersSize += item.HeaderSize;
return S_OK;
@@ -80,6 +122,14 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
}
_phySizeDefined = true;
+
+ bool utf8_OK = true;
+ if (!_forceCodePage)
+ {
+ if (!utf8_OK)
+ _curCodePage = k_DefaultCodePage;
+ }
+
for (;;)
{
CItemEx item;
@@ -87,12 +137,22 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
RINOK(ReadItem2(stream, filled, item));
if (!filled)
break;
+
+ _isArc = true;
_items.Add(item);
+
+ if (!_forceCodePage)
+ {
+ if (utf8_OK) utf8_OK = CheckUTF8(item.Name);
+ if (utf8_OK) utf8_OK = CheckUTF8(item.User);
+ if (utf8_OK) utf8_OK = CheckUTF8(item.Group);
+ if (utf8_OK) utf8_OK = CheckUTF8(item.LinkName);
+ }
RINOK(stream->Seek(item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize));
if (_phySize > endPos)
{
- _errorMessage = kUnexpectedEnd;
+ _error = k_ErrorType_UnexpectedEnd;
break;
}
/*
@@ -102,13 +162,13 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
break;
}
*/
- if (callback != NULL)
+ if (callback)
{
if (_items.Size() == 1)
{
RINOK(callback->SetTotal(NULL, &endPos));
}
- if (_items.Size() % 100 == 0)
+ if ((_items.Size() & 0x3FF) == 0)
{
UInt64 numFiles = _items.Size();
RINOK(callback->SetCompleted(&numFiles, &_phySize));
@@ -116,8 +176,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
}
}
+ 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<IArchiveOpenVolumeCallback> openVolumeCallback;
if (!callback)
return S_FALSE;
@@ -129,11 +201,12 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
return S_FALSE;
if (prop.vt != VT_BSTR)
return S_FALSE;
- UString baseName = prop.bstrVal;
- baseName = baseName.Right(4);
- if (baseName.CompareNoCase(L".tar") != 0)
+ unsigned len = MyStringLen(prop.bstrVal);
+ if (len < 4 || MyStringCompareNoCase(prop.bstrVal + len - 4, L".tar") != 0)
return S_FALSE;
}
+
+ _isArc = true;
return S_OK;
}
@@ -158,13 +231,16 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
STDMETHODIMP CHandler::Close()
{
- _errorMessage.Empty();
+ _isArc = false;
+ _error = k_ErrorType_OK;
+
_phySizeDefined = false;
_phySize = 0;
_headersSize = 0;
_curIndex = 0;
_latestIsRead = false;
- _isSparse = false;
+ // _isSparse = false;
+ _thereIsPaxExtendedHeader = false;
_items.Clear();
_seqStream.Release();
_stream.Release();
@@ -181,6 +257,8 @@ CHandler::CHandler()
{
copyCoderSpec = new NCompress::CCopyCoder();
copyCoder = copyCoderSpec;
+ _openCodePage = CP_UTF8;
+ Init();
}
HRESULT CHandler::SkipTo(UInt32 index)
@@ -194,7 +272,7 @@ HRESULT CHandler::SkipTo(UInt32 index)
_phySize += copyCoderSpec->TotalSize;
if (copyCoderSpec->TotalSize != packSize)
{
- _errorMessage = kUnexpectedEnd;
+ _error = k_ErrorType_UnexpectedEnd;
return S_FALSE;
}
_latestIsRead = false;
@@ -215,15 +293,29 @@ HRESULT CHandler::SkipTo(UInt32 index)
return S_OK;
}
-static UString TarStringToUnicode(const AString &s)
+void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs) const
{
- return MultiByteToUnicodeString(s, CP_OEMCP);
+ UString dest;
+ if (_curCodePage == CP_UTF8)
+ {
+ if (!ConvertUTF8ToUnicode(s, dest))
+ {
+ prop = "[ERROR-NAME]";
+ return;
+ }
+ }
+ else
+ dest = MultiByteToUnicodeString(s, _curCodePage);
+ if (toOs)
+ prop = NItemName::GetOSName2(dest);
+ else
+ prop = dest;
}
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
+ NCOM::CPropVariant prop;
const CItemEx *item;
if (_stream)
@@ -239,9 +331,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
}
}
- switch(propID)
+ switch (propID)
{
- case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break;
+ 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;
@@ -254,9 +346,11 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
}
break;
case kpidPosixAttrib: prop = item->Mode; break;
- case kpidUser: prop = TarStringToUnicode(item->User); break;
- case kpidGroup: prop = TarStringToUnicode(item->Group); break;
- case kpidLink: prop = TarStringToUnicode(item->LinkName); break;
+ 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;
@@ -272,7 +366,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (!seqMode)
stream = _stream;
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items.Size();
if (_stream && numItems == 0)
@@ -333,7 +427,18 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
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;
}
@@ -344,13 +449,20 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
outStreamSpec->Init(skipMode ? 0 : unpackSize, true);
Int32 opRes = NExtract::NOperationResult::kOK;
- if (item->IsSparse())
- opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ CMyComPtr<ISequentialInStream> inStream2;
+ if (!item->IsSparse())
+ inStream2 = inStream;
else
{
- if (item->IsLink())
+ GetStream(index, &inStream2);
+ if (!inStream2)
+ return E_FAIL;
+ }
+
+ {
+ if (item->IsSymLink())
{
- RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length()));
+ RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len()));
}
else
{
@@ -359,7 +471,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL));
}
streamSpec->Init(item->GetPackSizeAligned());
- RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ RINOK(copyCoder->Code(inStream2, outStream, NULL, NULL, progress));
}
if (outStreamSpec->GetRem() != 0)
opRes = NExtract::NOperationResult::kDataError;
@@ -376,22 +488,198 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
+class CSparseStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 _phyPos;
+ UInt64 _virtPos;
+ bool _needStartSeek;
+
+public:
+ CHandler *Handler;
+ CMyComPtr<IUnknown> HandlerRef;
+ unsigned ItemIndex;
+ CRecordVector<UInt64> 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())
- return E_NOTIMPL;
- if (item.IsLink())
+ {
+ CSparseStream *streamSpec = new CSparseStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ streamSpec->Init();
+ streamSpec->Handler = this;
+ streamSpec->HandlerRef = (IInArchive *)this;
+ streamSpec->ItemIndex = index;
+ streamSpec->PhyOffsets.Reserve(item.SparseBlocks.Size());
+ UInt64 offs = 0;
+ FOR_VECTOR(i, item.SparseBlocks)
+ {
+ const CSparseBlock &sb = item.SparseBlocks[i];
+ streamSpec->PhyOffsets.AddInReserved(offs);
+ offs += sb.Size;
+ }
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+
+ if (item.IsSymLink())
{
CBufInStream *streamSpec = new CBufInStream;
CMyComPtr<IInStream> streamTemp = streamSpec;
- streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Length(), (IInArchive *)this);
+ streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this);
*stream = streamTemp.Detach();
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;
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **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 9251edf6..23854767 100755..100644
--- a/CPP/7zip/Archive/Tar/TarHandler.h
+++ b/CPP/7zip/Archive/Tar/TarHandler.h
@@ -3,12 +3,15 @@
#ifndef __TAR_HANDLER_H
#define __TAR_HANDLER_H
-#include "Common/MyCom.h"
-#include "../IArchive.h"
+#include "../../../Common/MyCom.h"
+
+#include "../../../Windows/PropVariant.h"
#include "../../Compress/CopyCoder.h"
-#include "TarItem.h"
+#include "../IArchive.h"
+
+#include "TarIn.h"
namespace NArchive {
namespace NTar {
@@ -17,13 +20,15 @@ class CHandler:
public IInArchive,
public IArchiveOpenSeq,
public IInArchiveGetStream,
+ public ISetProperties,
public IOutArchive,
public CMyUnknownImp
{
+public:
CObjectVector<CItemEx> _items;
CMyComPtr<IInStream> _stream;
CMyComPtr<ISequentialInStream> _seqStream;
-
+private:
UInt32 _curIndex;
bool _latestIsRead;
CItemEx _latestItem;
@@ -31,8 +36,16 @@ class CHandler:
UInt64 _phySize;
UInt64 _headersSize;
bool _phySizeDefined;
- AString _errorMessage;
- bool _isSparse;
+ EErrorType _error;
+ bool _isArc;
+
+ // bool _isSparse;
+ bool _thereIsPaxExtendedHeader;
+
+ bool _forceCodePage;
+ UInt32 _specifiedCodePage;
+ UInt32 _curCodePage;
+ UInt32 _openCodePage;
NCompress::CCopyCoder *copyCoderSpec;
CMyComPtr<ICompressCoder> copyCoder;
@@ -40,12 +53,13 @@ class CHandler:
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_IMP4(
+ MY_UNKNOWN_IMP5(
IInArchive,
IArchiveOpenSeq,
IInArchiveGetStream,
+ ISetProperties,
IOutArchive
)
@@ -53,7 +67,9 @@ public:
INTERFACE_IOutArchive(;)
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps);
+ void Init();
CHandler();
};
diff --git a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
index b0ec63d1..b909e96c 100755..100644
--- a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
+++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
@@ -2,11 +2,13 @@
#include "StdAfx.h"
-#include "Common/ComTry.h"
-#include "Common/StringConvert.h"
+#include "../../../Common/ComTry.h"
+#include "../../../Common/Defs.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/UTFConvert.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/TimeUtils.h"
#include "TarHandler.h"
#include "TarUpdate.h"
@@ -22,24 +24,54 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
return S_OK;
}
-static HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res)
+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)
- res = UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP);
+ {
+ UString s = prop.bstrVal;
+ if (convertSlash)
+ s = NItemName::MakeLegalName(s);
+ if (codePage == CP_UTF8)
+ {
+ 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.IndexInArchive, u2.IndexInArchive);
+ }
+ 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 && (!_errorMessage.IsEmpty() || _isSparse)) || _seqStream)
+ if ((_stream && (_error != k_ErrorType_OK /* || _isSparse */)) || _seqStream)
return E_NOTIMPL;
CObjectVector<CUpdateItem> updateItems;
+ UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage);
for (UInt32 i = 0; i < numItems; i++)
{
CUpdateItem ui;
@@ -87,19 +119,13 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
else
ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime);
}
- {
- NCOM::CPropVariant prop;
- RINOK(callback->GetProperty(i, kpidPath, &prop));
- if (prop.vt == VT_BSTR)
- ui.Name = UnicodeStringToMultiByte(NItemName::MakeLegalName(prop.bstrVal), CP_OEMCP);
- else if (prop.vt != VT_EMPTY)
- return E_INVALIDARG;
- if (ui.IsDir)
- ui.Name += '/';
- }
- RINOK(GetPropString(callback, i, kpidUser, ui.User));
- RINOK(GetPropString(callback, i, kpidGroup, ui.Group));
+ 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;
@@ -115,7 +141,12 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
}
updateItems.Add(ui);
}
- return UpdateArchive(_stream, outStream, _items, updateItems, callback);
+ 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 3275b284..70be09f3 100755..100644
--- a/CPP/7zip/Archive/Tar/TarHeader.cpp
+++ b/CPP/7zip/Archive/Tar/TarHeader.cpp
@@ -1,4 +1,4 @@
-// Archive/Tar/Header.h
+// Archive/TarHeader.cpp
#include "StdAfx.h"
@@ -8,18 +8,16 @@ namespace NArchive {
namespace NTar {
namespace NFileHeader {
- // The checksum field is filled with this while the checksum is computed.
- const char *kCheckSumBlanks = " "; // 8 blanks, no null
-
const char *kLongLink = "././@LongLink";
const char *kLongLink2 = "@LongLink";
// The magic field is filled with this if uname and gname are valid.
namespace NMagic
{
- const char *kUsTar = "ustar"; // 5 chars
- const char *kGNUTar = "GNUtar "; // 7 chars and a null
- const char *kEmpty = "\0\0\0\0\0\0\0\0"; // 7 chars and a null
+ // const char *kUsTar = "ustar"; // 5 chars
+ // const char *kGNUTar = "GNUtar "; // 7 chars and a null
+ // const char *kEmpty = "\0\0\0\0\0\0\0\0";
+ 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 a212ae03..df594d81 100755..100644
--- a/CPP/7zip/Archive/Tar/TarHeader.h
+++ b/CPP/7zip/Archive/Tar/TarHeader.h
@@ -1,20 +1,22 @@
-// Archive/Tar/Header.h
+// Archive/TarHeader.h
#ifndef __ARCHIVE_TAR_HEADER_H
#define __ARCHIVE_TAR_HEADER_H
-#include "Common/Types.h"
+#include "../../../Common/MyTypes.h"
namespace NArchive {
namespace NTar {
namespace NFileHeader
{
- const int kRecordSize = 512;
- const int kNameSize = 100;
- const int kUserNameSize = 32;
- const int kGroupNameSize = 32;
- const int kPrefixSize = 155;
+ 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
@@ -42,66 +44,39 @@ namespace NFileHeader
};
*/
- namespace NMode
- {
- const int kSetUID = 04000; // Set UID on execution
- const int kSetGID = 02000; // Set GID on execution
- const int kSaveText = 01000; // Save text (sticky bit)
- }
-
- namespace NFilePermissions
- {
- const int kUserRead = 00400; // read by owner
- const int kUserWrite = 00200; // write by owner
- const int kUserExecute = 00100; // execute/search by owner
- const int kGroupRead = 00040; // read by group
- const int kGroupWrite = 00020; // write by group
- const int kGroupExecute = 00010; // execute/search by group
- const int kOtherRead = 00004; // read by other
- const int kOtherWrite = 00002; // write by other
- const int kOtherExecute = 00001; // execute/search by other
- }
-
-
- // The linkflag defines the type of file
namespace NLinkFlag
{
- const char kOldNormal = '\0'; // Normal disk file, Unix compatible
+ const char kOldNormal = 0; // Normal disk file, Unix compatible
const char kNormal = '0'; // Normal disk file
- const char kLink = '1'; // Link to previously dumped file
- const char kSymbolicLink = '2'; // Symbolic link
+ const char 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 kDumpDir = 'D'; /* GNUTYPE_DUMPDIR.
+ 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. */
-
- const char kSparse = 'S';
}
- // Further link types may be defined later.
-
- // The checksum field is filled with this while the checksum is computed.
- extern const char *kCheckSumBlanks;// = " "; // 8 blanks, no null
extern const char *kLongLink; // = "././@LongLink";
extern const char *kLongLink2; // = "@LongLink";
- // The magic field is filled with this if uname and gname are valid.
namespace NMagic
{
- extern const char *kUsTar; // = "ustar"; // 5 chars
- extern const char *kGNUTar; // = "GNUtar "; // 7 chars and a null
- extern const char *kEmpty; // = "GNUtar "; // 7 chars and a null
+ // extern const char *kUsTar; // = "ustar"; // 5 chars
+ // extern const char *kGNUTar; // = "GNUtar "; // 7 chars and a null
+ // extern const char *kEmpty; // = "\0\0\0\0\0\0\0\0"
+ extern const char kUsTar_00[];
}
-
}
}}
diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp
index b6e5e0f5..1584a520 100755..100644
--- a/CPP/7zip/Archive/Tar/TarIn.cpp
+++ b/CPP/7zip/Archive/Tar/TarIn.cpp
@@ -4,18 +4,20 @@
#include "../../../../C/CpuArch.h"
-#include "Common/StringToInt.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, int size)
+static void MyStrNCpy(char *dest, const char *src, unsigned size)
{
- for (int i = 0; i < size; i++)
+ for (unsigned i = 0; i < size; i++)
{
char c = src[i];
dest[i] = c;
@@ -24,19 +26,21 @@ static void MyStrNCpy(char *dest, const char *src, int size)
}
}
-static bool OctalToNumber(const char *srcString, int size, UInt64 &res)
+static bool OctalToNumber(const char *srcString, unsigned size, UInt64 &res)
{
char sz[32];
MyStrNCpy(sz, srcString, size);
sz[size] = 0;
const char *end;
- int i;
+ unsigned i;
for (i = 0; sz[i] == ' '; i++);
res = ConvertOctStringToUInt64(sz + i, &end);
+ if (end == sz + i)
+ return false;
return (*end == ' ' || *end == 0);
}
-static bool OctalToNumber32(const char *srcString, int size, UInt32 &res)
+static bool OctalToNumber32(const char *srcString, unsigned size, UInt32 &res)
{
UInt64 res64;
if (!OctalToNumber(srcString, size, res64))
@@ -45,17 +49,27 @@ static bool OctalToNumber32(const char *srcString, int size, UInt32 &res)
return (res64 <= 0xFFFFFFFF);
}
-#define RIF(x) { if (!(x)) return S_FALSE; }
+#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 (int i = 0; i < NFileHeader::kRecordSize; i++)
+ for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
if (buf[i] != 0)
return false;
return true;
}
-static void ReadString(const char *s, int size, AString &result)
+static void ReadString(const char *s, unsigned size, AString &result)
{
char temp[NFileHeader::kRecordSize + 1];
MyStrNCpy(temp, s, size);
@@ -88,12 +102,39 @@ static bool ParseSize(const char *p, UInt64 &val)
return OctalToNumber(p, 12, val);
}
-static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
+#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;
+ CHECK(OctalToNumber32(p, 8, mode)); p += 8;
+
+ // if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0;
+ p += 8;
+ // if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0;
+ p += 8;
+
+ UInt64 packSize;
+ Int64 time;
+ UInt32 checkSum;
+ CHECK(ParseSize(p, packSize)); p += 12;
+ CHECK(ParseInt64(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.Empty();
+ error = k_ErrorType_OK;
filled = false;
bool thereAreEmptyRecords = false;
@@ -103,26 +144,41 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
RINOK(ReadStream(stream, buf, &processedSize));
if (processedSize == 0)
{
- if (!thereAreEmptyRecords )
- error = "There are no trailing zero-filled records";
+ if (!thereAreEmptyRecords)
+ error = k_ErrorType_UnexpectedEnd; // "There are no trailing zero-filled records";
return S_OK;
}
if (processedSize != NFileHeader::kRecordSize)
{
- error = "There is no correct record at the end of archive";
+ 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;
}
- item.HeaderSize += NFileHeader::kRecordSize;
if (!IsRecordLast(buf))
break;
+ item.HeaderSize += NFileHeader::kRecordSize;
thereAreEmptyRecords = true;
}
if (thereAreEmptyRecords)
{
- error = "There are data after end of archive";
+ // error = "There are data after end of archive";
return S_OK;
}
+ error = k_ErrorType_Corrupted;
ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize;
RIF(OctalToNumber32(p, 8, item.Mode)); p += 8;
@@ -137,7 +193,7 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
UInt32 checkSum;
RIF(OctalToNumber32(p, 8, checkSum));
- memcpy(p, NFileHeader::kCheckSumBlanks, 8); p += 8;
+ memset(p, ' ', 8); p += 8;
item.LinkFlag = *p++;
@@ -148,93 +204,170 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
ReadString(p, NFileHeader::kUserNameSize, item.User); p += NFileHeader::kUserNameSize;
ReadString(p, NFileHeader::kGroupNameSize, item.Group); p += NFileHeader::kGroupNameSize;
- item.DeviceMajorDefined = (p[0] != 0); RIF(OctalToNumber32(p, 8, item.DeviceMajor)); p += 8;
- item.DeviceMinorDefined = (p[0] != 0); RIF(OctalToNumber32(p, 8, item.DeviceMinor)); p += 8;
+ 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;
AString prefix;
ReadString(p, NFileHeader::kPrefixSize, prefix);
p += NFileHeader::kPrefixSize;
- if (!prefix.IsEmpty() && item.IsMagic() &&
+ if (!prefix.IsEmpty() && item.IsUstarMagic() &&
(item.LinkFlag != 'L' /* || prefix != "00000000000" */ ))
item.Name = prefix + AString('/') + item.Name;
- if (item.LinkFlag == NFileHeader::NLinkFlag::kLink)
+ if (item.LinkFlag == NFileHeader::NLinkFlag::kHardLink)
{
item.PackSize = 0;
item.Size = 0;
}
- else if (item.LinkFlag == NFileHeader::NLinkFlag::kSparse)
+ /*
+ 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)
{
- if (buf[482] != 0)
- return S_FALSE;
+ Byte isExtended = buf[482];
+ if (isExtended != 0 && isExtended != 1)
+ return S_OK;
RIF(ParseSize(buf + 483, item.Size));
- p = buf + 386;
UInt64 min = 0;
- for (int i = 0; i < 4; i++, p += 24)
+ 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_FALSE;
+ return S_OK;
if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0)
- return S_FALSE;
+ return S_OK;
min = sb.Offset + sb.Size;
if (min < sb.Offset)
- return S_FALSE;
+ 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_FALSE;
+ return S_OK;
}
- UInt32 checkSumReal = 0;
- for (int i = 0; i < NFileHeader::kRecordSize; i++)
- checkSumReal += (Byte)buf[i];
-
- if (checkSumReal != checkSum)
- return S_FALSE;
-
filled = true;
+ error = k_ErrorType_OK;
return S_OK;
}
-HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
+HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error)
{
item.HeaderSize = 0;
bool flagL = false;
bool flagK = false;
AString nameL;
AString nameK;
+
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 == 'L' || // NEXT file has a long name
- item.LinkFlag == 'K') // NEXT file has a long linkname
+
+ 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 == 'L')
- { if (flagL) return S_FALSE; flagL = true; name = &nameL; }
+ if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName)
+ { if (flagL) return S_OK; flagL = true; name = &nameL; }
else
- { if (flagK) return S_FALSE; flagK = true; name = &nameK; }
+ { if (flagK) return S_OK; flagK = true; name = &nameK; }
- if (item.Name.Compare(NFileHeader::kLongLink) != 0 &&
- item.Name.Compare(NFileHeader::kLongLink2) != 0)
- return S_FALSE;
+ if (item.Name != NFileHeader::kLongLink &&
+ item.Name != NFileHeader::kLongLink2)
+ return S_OK;
if (item.PackSize > (1 << 14))
- return S_FALSE;
- int packSize = (int)item.GetPackSizeAligned();
+ return S_OK;
+ unsigned packSize = (unsigned)item.GetPackSizeAligned();
char *buf = name->GetBuffer(packSize);
- RINOK(ReadStream_FALSE(stream, buf, packSize));
- item.HeaderSize += packSize;
- buf[(size_t)item.PackSize] = '\0';
+ size_t processedSize = packSize;
+ HRESULT res = ReadStream(stream, buf, &processedSize);
+ item.HeaderSize += (unsigned)processedSize;
+ buf[(size_t)item.PackSize] = 0;
name->ReleaseBuffer();
+ RINOK(res);
+ if (processedSize != packSize)
+ {
+ error = k_ErrorType_UnexpectedEnd;
+ return S_OK;
+ }
continue;
}
+
switch (item.LinkFlag)
{
case 'g':
@@ -256,10 +389,12 @@ HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AStri
}
default:
if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
- return S_FALSE;
+ return S_OK;
}
+
if (flagL) item.Name = nameL;
if (flagK) item.LinkName = nameK;
+ error = k_ErrorType_OK;
return S_OK;
}
}
diff --git a/CPP/7zip/Archive/Tar/TarIn.h b/CPP/7zip/Archive/Tar/TarIn.h
index a5491ebe..a67b1dbd 100755..100644
--- a/CPP/7zip/Archive/Tar/TarIn.h
+++ b/CPP/7zip/Archive/Tar/TarIn.h
@@ -10,7 +10,16 @@
namespace NArchive {
namespace NTar {
-HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, AString &error);
+enum EErrorType
+{
+ k_ErrorType_OK,
+ k_ErrorType_Corrupted,
+ k_ErrorType_UnexpectedEnd,
+};
+
+HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, EErrorType &error);
+
+API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size);
}}
diff --git a/CPP/7zip/Archive/Tar/TarItem.h b/CPP/7zip/Archive/Tar/TarItem.h
index 3584a7ce..805a2e7c 100755..100644
--- a/CPP/7zip/Archive/Tar/TarItem.h
+++ b/CPP/7zip/Archive/Tar/TarItem.h
@@ -40,28 +40,41 @@ struct CItem
CRecordVector<CSparseBlock> SparseBlocks;
- bool IsLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymbolicLink && (Size == 0); }
+ 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 IsLink() ? LinkName.Length() : Size; }
+ 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;
+ }
bool IsDir() const
{
- switch(LinkFlag)
+ 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 IsMagic() const
+ bool IsUstarMagic() const
{
for (int i = 0; i < 5; i++)
- if (Magic[i] != NFileHeader::NMagic::kUsTar[i])
+ if (Magic[i] != NFileHeader::NMagic::kUsTar_00[i])
return false;
return true;
}
diff --git a/CPP/7zip/Archive/Tar/TarOut.cpp b/CPP/7zip/Archive/Tar/TarOut.cpp
index 6e699e28..51081e8b 100755..100644
--- a/CPP/7zip/Archive/Tar/TarOut.cpp
+++ b/CPP/7zip/Archive/Tar/TarOut.cpp
@@ -2,8 +2,6 @@
#include "StdAfx.h"
-#include "Common/IntToString.h"
-
#include "../../Common/StreamUtils.h"
#include "TarOut.h"
@@ -11,26 +9,15 @@
namespace NArchive {
namespace NTar {
-HRESULT COutArchive::WriteBytes(const void *buffer, UInt32 size)
-{
- return WriteStream(m_Stream, buffer, size);
-}
-
-void COutArchive::Create(ISequentialOutStream *outStream)
-{
- m_Stream = outStream;
-}
-
-static AString MakeOctalString(UInt64 value)
+HRESULT COutArchive::WriteBytes(const void *data, unsigned size)
{
- char s[32];
- ConvertUInt64ToString(value, s, 8);
- return AString(s) + ' ';
+ Pos += size;
+ return WriteStream(m_Stream, data, size);
}
-static void MyStrNCpy(char *dest, const char *src, int size)
+static void MyStrNCpy(char *dest, const char *src, unsigned size)
{
- for (int i = 0; i < size; i++)
+ for (unsigned i = 0; i < size; i++)
{
char c = src[i];
dest[i] = c;
@@ -39,54 +26,53 @@ static void MyStrNCpy(char *dest, const char *src, int size)
}
}
-static bool MakeOctalString8(char *s, UInt32 value)
+static bool WriteOctal_8(char *s, UInt32 val)
{
- AString tempString = MakeOctalString(value);
-
- const int kMaxSize = 8;
- if (tempString.Length() >= kMaxSize)
+ const unsigned kNumDigits = 8 - 1;
+ if (val >= ((UInt32)1 << (kNumDigits * 3)))
return false;
- int numSpaces = kMaxSize - (tempString.Length() + 1);
- for (int i = 0; i < numSpaces; i++)
- s[i] = ' ';
- MyStringCopy(s + numSpaces, (const char *)tempString);
+ for (unsigned i = 0; i < kNumDigits; i++)
+ {
+ s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
+ val >>= 3;
+ }
return true;
}
-static void MakeOctalString12(char *s, UInt64 value)
+static void WriteOctal_12(char *s, UInt64 val)
{
- AString tempString = MakeOctalString(value);
- const int kMaxSize = 12;
- if (tempString.Length() > kMaxSize)
+ 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 (int i = 0; i < 8; i++, value <<= 8)
- s[4 + i] = (char)(value >> 56);
+ for (unsigned i = 0; i < 8; i++, val <<= 8)
+ s[4 + i] = (char)(val >> 56);
return;
}
- int numSpaces = kMaxSize - tempString.Length();
- for (int i = 0; i < numSpaces; i++)
- s[i] = ' ';
- memmove(s + numSpaces, (const char *)tempString, tempString.Length());
+ for (unsigned i = 0; i < kNumDigits; i++)
+ {
+ s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
+ val >>= 3;
+ }
}
-static void MakeOctalString12_From_Int64(char *s, Int64 value)
+static void WriteOctal_12_Signed(char *s, Int64 val)
{
- if (value >= 0)
+ if (val >= 0)
{
- MakeOctalString12(s, value);
+ WriteOctal_12(s, val);
return;
}
s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF;
- for (int i = 0; i < 8; i++, value <<= 8)
- s[4 + i] = (char)(value >> 56);
+ for (unsigned i = 0; i < 8; i++, val <<= 8)
+ s[4 + i] = (char)(val >> 56);
}
-static bool CopyString(char *dest, const AString &src, int maxSize)
+static bool CopyString(char *dest, const AString &src, unsigned maxSize)
{
- if (src.Length() >= maxSize)
+ if (src.Len() >= maxSize)
return false;
MyStringCopy(dest, (const char *)src);
return true;
@@ -97,25 +83,22 @@ static bool CopyString(char *dest, const AString &src, int maxSize)
HRESULT COutArchive::WriteHeaderReal(const CItem &item)
{
char record[NFileHeader::kRecordSize];
+ memset(record, 0, NFileHeader::kRecordSize);
char *cur = record;
- int i;
- for (i = 0; i < NFileHeader::kRecordSize; i++)
- record[i] = 0;
- // RETURN_IF_NOT_TRUE(CopyString(header.Name, item.Name, NFileHeader::kNameSize));
- if (item.Name.Length() > NFileHeader::kNameSize)
+ if (item.Name.Len() > NFileHeader::kNameSize)
return E_FAIL;
MyStrNCpy(cur, item.Name, NFileHeader::kNameSize);
cur += NFileHeader::kNameSize;
- RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.Mode)); cur += 8;
- RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.UID)); cur += 8;
- RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.GID)); cur += 8;
+ 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;
- MakeOctalString12(cur, item.PackSize); cur += 12;
- MakeOctalString12_From_Int64(cur, item.MTime); cur += 12;
+ WriteOctal_12(cur, item.PackSize); cur += 12;
+ WriteOctal_12_Signed(cur, item.MTime); cur += 12;
- memmove(cur, NFileHeader::kCheckSumBlanks, 8);
+ memset(cur, ' ', 8);
cur += 8;
*cur++ = item.LinkFlag;
@@ -123,7 +106,7 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize));
cur += NFileHeader::kNameSize;
- memmove(cur, item.Magic, 8);
+ memcpy(cur, item.Magic, 8);
cur += 8;
RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize));
@@ -132,64 +115,127 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
cur += NFileHeader::kGroupNameSize;
- if (item.DeviceMajorDefined)
- RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMajor));
- cur += 8;
+ 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.DeviceMinorDefined)
- RETURN_IF_NOT_TRUE(MakeOctalString8(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;
+ }
- UInt32 checkSumReal = 0;
- for (i = 0; i < NFileHeader::kRecordSize; i++)
- checkSumReal += Byte(record[i]);
+ RINOK(WriteBytes(record, NFileHeader::kRecordSize));
- RETURN_IF_NOT_TRUE(MakeOctalString8(record + 148, checkSumReal));
+ 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 WriteBytes(record, NFileHeader::kRecordSize);
+ return S_OK;
}
HRESULT COutArchive::WriteHeader(const CItem &item)
{
- int nameSize = item.Name.Length();
- if (nameSize < NFileHeader::kNameSize)
+ 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 modifiedItem = item;
- int nameStreamSize = nameSize + 1;
- modifiedItem.PackSize = nameStreamSize;
- modifiedItem.LinkFlag = 'L';
- modifiedItem.Name = NFileHeader::kLongLink;
- modifiedItem.LinkName.Empty();
- RINOK(WriteHeaderReal(modifiedItem));
- RINOK(WriteBytes(item.Name, nameStreamSize));
- RINOK(FillDataResidual(nameStreamSize));
-
- modifiedItem = item;
- modifiedItem.Name = item.Name.Left(NFileHeader::kNameSize - 1);
- return WriteHeaderReal(modifiedItem);
+ 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)
{
- UInt32 lastRecordSize = UInt32(dataSize & (NFileHeader::kRecordSize - 1));
+ unsigned lastRecordSize = ((unsigned)dataSize & (NFileHeader::kRecordSize - 1));
if (lastRecordSize == 0)
return S_OK;
- UInt32 residualSize = NFileHeader::kRecordSize - lastRecordSize;
- Byte residualBytes[NFileHeader::kRecordSize];
- for (UInt32 i = 0; i < residualSize; i++)
- residualBytes[i] = 0;
- return WriteBytes(residualBytes, residualSize);
+ unsigned rem = NFileHeader::kRecordSize - lastRecordSize;
+ Byte buf[NFileHeader::kRecordSize];
+ memset(buf, 0, rem);
+ return WriteBytes(buf, rem);
}
HRESULT COutArchive::WriteFinishHeader()
{
Byte record[NFileHeader::kRecordSize];
- int i;
- for (i = 0; i < NFileHeader::kRecordSize; i++)
- record[i] = 0;
- for (i = 0; i < 2; i++)
+ memset(record, 0, NFileHeader::kRecordSize);
+ for (unsigned i = 0; i < 2; i++)
{
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
}
diff --git a/CPP/7zip/Archive/Tar/TarOut.h b/CPP/7zip/Archive/Tar/TarOut.h
index ef837869..ee9b965e 100755..100644
--- a/CPP/7zip/Archive/Tar/TarOut.h
+++ b/CPP/7zip/Archive/Tar/TarOut.h
@@ -3,21 +3,29 @@
#ifndef __ARCHIVE_TAR_OUT_H
#define __ARCHIVE_TAR_OUT_H
-#include "TarItem.h"
+#include "../../../Common/MyCom.h"
-#include "Common/MyCom.h"
#include "../../IStream.h"
+#include "TarItem.h"
+
namespace NArchive {
namespace NTar {
class COutArchive
{
CMyComPtr<ISequentialOutStream> m_Stream;
- HRESULT WriteBytes(const void *buffer, UInt32 size);
-public:
- void Create(ISequentialOutStream *outStream);
+
+ 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();
diff --git a/CPP/7zip/Archive/Tar/TarRegister.cpp b/CPP/7zip/Archive/Tar/TarRegister.cpp
index e21c0aac..9e0f6f21 100755..100644
--- a/CPP/7zip/Archive/Tar/TarRegister.cpp
+++ b/CPP/7zip/Archive/Tar/TarRegister.cpp
@@ -5,14 +5,22 @@
#include "../../Common/RegisterArc.h"
#include "TarHandler.h"
-static IInArchive *CreateArc() { return new NArchive::NTar::CHandler; }
-#ifndef EXTRACT_ONLY
-static IOutArchive *CreateArcOut() { return new NArchive::NTar::CHandler; }
-#else
-#define CreateArcOut 0
-#endif
+
+namespace NArchive {
+namespace NTar {
+
+IMP_CreateArcIn
+IMP_CreateArcOut
static CArcInfo g_ArcInfo =
-{ L"tar", L"tar", 0, 0xEE, { 'u', 's', 't', 'a', 'r' }, 5, false, CreateArc, CreateArcOut };
+ { "tar", "tar", 0, 0xEE,
+ 5, { 'u', 's', 't', 'a', 'r' },
+ NFileHeader::kUstarMagic_Offset,
+ NArcInfoFlags::kStartOpen |
+ NArcInfoFlags::kSymLinks |
+ NArcInfoFlags::kHardLinks,
+ REF_CreateArc_Pair, IsArc_Tar };
REGISTER_ARC(Tar)
+
+}}
diff --git a/CPP/7zip/Archive/Tar/TarUpdate.cpp b/CPP/7zip/Archive/Tar/TarUpdate.cpp
index fb123169..fdbce395 100755..100644
--- a/CPP/7zip/Archive/Tar/TarUpdate.cpp
+++ b/CPP/7zip/Archive/Tar/TarUpdate.cpp
@@ -2,6 +2,8 @@
#include "StdAfx.h"
+#include "../../../Windows/TimeUtils.h"
+
#include "../../Common/LimitedStreams.h"
#include "../../Common/ProgressUtils.h"
@@ -13,18 +15,26 @@
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<NArchive::NTar::CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
+ UINT codePage,
IArchiveUpdateCallback *updateCallback)
{
COutArchive outArchive;
outArchive.Create(outStream);
+ outArchive.Pos = 0;
+
+ CMyComPtr<IOutStream> outSeekStream;
+ outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream);
UInt64 complexity = 0;
- int i;
- for(i = 0; i < updateItems.Size(); i++)
+ unsigned i;
+ for (i = 0; i < updateItems.Size(); i++)
{
const CUpdateItem &ui = updateItems[i];
if (ui.NewData)
@@ -76,37 +86,101 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
item.DeviceMinorDefined = false;
item.UID = 0;
item.GID = 0;
- memmove(item.Magic, NFileHeader::NMagic::kEmpty, 8);
+ memcpy(item.Magic, NFileHeader::NMagic::kUsTar_00, 8);
}
else
item = inputItems[ui.IndexInArchive];
+ 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;
- }
- else
- item.PackSize = inputItems[ui.IndexInArchive].PackSize;
-
- if (ui.NewData)
- {
+
CMyComPtr<ISequentialInStream> fileInStream;
- HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
- if (res != S_FALSE)
+
+ bool needWrite = true;
+ if (!symLink.IsEmpty())
{
- RINOK(res);
+ 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<IStreamGetProps> 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.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);;
+ }
+ }
+ }
+ {
+ 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 (!ui.IsDir)
+ if (fileInStream)
{
RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress));
+ outArchive.Pos += copyCoderSpec->TotalSize;
if (copyCoderSpec->TotalSize != item.PackSize)
- return E_FAIL;
+ {
+ 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 += ui.Size;
+ complexity += item.PackSize;
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
}
else
@@ -115,6 +189,30 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
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;
@@ -129,6 +227,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
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;
}
diff --git a/CPP/7zip/Archive/Tar/TarUpdate.h b/CPP/7zip/Archive/Tar/TarUpdate.h
index 3f889739..c2393416 100755..100644
--- a/CPP/7zip/Archive/Tar/TarUpdate.h
+++ b/CPP/7zip/Archive/Tar/TarUpdate.h
@@ -27,6 +27,7 @@ struct CUpdateItem
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
const CObjectVector<CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
+ UINT codePage,
IArchiveUpdateCallback *updateCallback);
}}
diff --git a/CPP/7zip/Archive/Udf/StdAfx.h b/CPP/7zip/Archive/Udf/StdAfx.h
index 2e4be10b..2854ff3e 100755..100644
--- a/CPP/7zip/Archive/Udf/StdAfx.h
+++ b/CPP/7zip/Archive/Udf/StdAfx.h
@@ -3,7 +3,6 @@
#ifndef __STDAFX_H
#define __STDAFX_H
-#include "../../../Common/MyWindows.h"
-#include "../../../Common/NewHandler.h"
+#include "../../../Common/Common.h"
#endif
diff --git a/CPP/7zip/Archive/Udf/UdfHandler.cpp b/CPP/7zip/Archive/Udf/UdfHandler.cpp
index c7085272..6aa53ea9 100755..100644
--- a/CPP/7zip/Archive/Udf/UdfHandler.cpp
+++ b/CPP/7zip/Archive/Udf/UdfHandler.cpp
@@ -2,13 +2,14 @@
#include "StdAfx.h"
-#include "Common/ComTry.h"
+#include "../../../Common/ComTry.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.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"
@@ -18,7 +19,7 @@
namespace NArchive {
namespace NUdf {
-void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop)
+static void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop)
{
UInt64 numSecs;
const Byte *d = t.Data;
@@ -33,21 +34,21 @@ void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop)
prop = ft;
}
-static STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidATime, VT_FILETIME}
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidATime
};
-static STATPROPSTG kArcProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidComment, VT_BSTR},
- { NULL, kpidClusterSize, VT_UI4},
- { NULL, kpidCTime, VT_FILETIME}
+ kpidComment,
+ kpidClusterSize,
+ kpidCTime
};
IMP_IInArchive_Props
@@ -59,6 +60,8 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
NWindows::NCOM::CPropVariant prop;
switch(propID)
{
+ case kpidPhySize: prop = _archive.PhySize; break;
+
case kpidComment:
{
UString comment = _archive.GetComment();
@@ -71,7 +74,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
if (_archive.LogVols.Size() > 0)
{
UInt32 blockSize = _archive.LogVols[0].BlockSize;
- int i;
+ unsigned i;
for (i = 1; i < _archive.LogVols.Size(); i++)
if (_archive.LogVols[i].BlockSize != blockSize)
break;
@@ -88,6 +91,16 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
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;
+ prop = v;
+ break;
+ }
}
prop.Detach(value);
return S_OK;
@@ -127,9 +140,7 @@ HRESULT CProgressImp::SetCompleted()
return S_OK;
}
-STDMETHODIMP CHandler::Open(IInStream *stream,
- const UInt64 * /* maxCheckStartPosition */,
- IArchiveOpenCallback *callback)
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
{
COM_TRY_BEGIN
{
@@ -137,14 +148,14 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
CProgressImp progressImp(callback);
RINOK(_archive.Open(stream, &progressImp));
bool showVolName = (_archive.LogVols.Size() > 1);
- for (int volIndex = 0; volIndex < _archive.LogVols.Size(); volIndex++)
+ FOR_VECTOR (volIndex, _archive.LogVols)
{
const CLogVol &vol = _archive.LogVols[volIndex];
bool showFileSetName = (vol.FileSets.Size() > 1);
- for (int fsIndex = 0; fsIndex < vol.FileSets.Size(); fsIndex++)
+ FOR_VECTOR (fsIndex, vol.FileSets)
{
const CFileSet &fs = vol.FileSets[fsIndex];
- for (int i = ((showVolName || showFileSetName) ? 0 : 1); i < fs.Refs.Size(); i++)
+ for (unsigned i = ((showVolName || showFileSetName) ? 0 : 1); i < fs.Refs.Size(); i++)
{
CRef2 ref2;
ref2.Vol = volIndex;
@@ -184,7 +195,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
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)
+ switch (propID)
{
case kpidPath: prop = _archive.GetItemPath(ref2.Vol, ref2.Fs, ref2.Ref,
_archive.LogVols.Size() > 1, vol.FileSets.Size() > 1); break;
@@ -200,99 +211,6 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
COM_TRY_END
}
-struct CSeekExtent
-{
- UInt64 Phy;
- UInt64 Virt;
-};
-
-class CExtentsStream:
- public IInStream,
- public CMyUnknownImp
-{
- UInt64 _phyPos;
- UInt64 _virtPos;
- bool _needStartSeek;
-
- HRESULT SeekToPhys() { return Stream->Seek(_phyPos, STREAM_SEEK_SET, NULL); }
-
-public:
- CMyComPtr<IInStream> Stream;
- CRecordVector<CSeekExtent> Extents;
-
- MY_UNKNOWN_IMP1(IInStream)
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
- void ReleaseStream() { Stream.Release(); }
-
- void Init()
- {
- _virtPos = 0;
- _phyPos = 0;
- _needStartSeek = true;
- }
-
-};
-
-
-STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- if (size > 0)
- {
- UInt64 totalSize = Extents.Back().Virt;
- if (_virtPos >= totalSize)
- return (_virtPos == totalSize) ? S_OK : E_FAIL;
- int left = 0, right = Extents.Size() - 1;
- for (;;)
- {
- int mid = (left + right) / 2;
- if (mid == left)
- break;
- if (_virtPos < Extents[mid].Virt)
- right = mid;
- else
- left = mid;
- }
-
- const CSeekExtent &extent = Extents[left];
- UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt);
- if (_needStartSeek || _phyPos != phyPos)
- {
- _needStartSeek = false;
- _phyPos = phyPos;
- RINOK(SeekToPhys());
- }
-
- UInt64 rem = Extents[left + 1].Virt - _virtPos;
- if (size > rem)
- size = (UInt32)rem;
-
- HRESULT res = Stream->Read(data, size, &size);
- _phyPos += size;
- _virtPos += size;
- if (processedSize)
- *processedSize = size;
- return res;
- }
- return S_OK;
-}
-
-STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- switch(seekOrigin)
- {
- case STREAM_SEEK_SET: _virtPos = offset; break;
- case STREAM_SEEK_CUR: _virtPos += offset; break;
- case STREAM_SEEK_END: _virtPos = Extents.Back().Virt + offset; break;
- default: return STG_E_INVALIDFUNCTION;
- }
- if (newPosition)
- *newPosition = _virtPos;
- return S_OK;
-}
-
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
{
*stream = 0;
@@ -325,7 +243,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
extentStreamSpec->Stream = _inStream;
UInt64 virtOffset = 0;
- for (int extentIndex = 0; extentIndex < item.Extents.Size(); extentIndex++)
+ FOR_VECTOR (extentIndex, item.Extents)
{
const CMyExtent &extent = item.Extents[extentIndex];
UInt32 len = extent.GetLen();
@@ -363,7 +281,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _refs2.Size();
if (numItems == 0)
@@ -431,7 +349,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ISequentialInStream> udfInStream;
HRESULT res = GetStream(index, &udfInStream);
if (res == E_NOTIMPL)
- opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
else if (res != S_OK)
opRes = NExtract::NOperationResult::kDataError;
else
@@ -448,4 +366,18 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
+IMP_CreateArcIn
+
+static const UInt32 kIsoStartPos = 0x8000;
+
+static CArcInfo g_ArcInfo =
+ { "Udf", "udf iso img", 0, 0xE0,
+ // 5, { 0, 'N', 'S', 'R', '0' },
+ 6, { 1, 'C', 'D', '0', '0', '1' },
+ kIsoStartPos,
+ NArcInfoFlags::kStartOpen,
+ CreateArc, NULL, IsArc_Udf };
+
+REGISTER_ARC(Udf)
+
}}
diff --git a/CPP/7zip/Archive/Udf/UdfHandler.h b/CPP/7zip/Archive/Udf/UdfHandler.h
index f513727d..da44b232 100755..100644
--- a/CPP/7zip/Archive/Udf/UdfHandler.h
+++ b/CPP/7zip/Archive/Udf/UdfHandler.h
@@ -1,9 +1,10 @@
-// Udf/Handler.h
+// UdfHandler.h
#ifndef __UDF_HANDLER_H
#define __UDF_HANDLER_H
-#include "Common/MyCom.h"
+#include "../../../Common/MyCom.h"
+
#include "../IArchive.h"
#include "UdfIn.h"
@@ -13,9 +14,9 @@ namespace NUdf {
struct CRef2
{
- int Vol;
- int Fs;
- int Ref;
+ unsigned Vol;
+ unsigned Fs;
+ unsigned Ref;
};
class CHandler:
diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp
index d2a2884f..3053a0c1 100755..100644
--- a/CPP/7zip/Archive/Udf/UdfIn.cpp
+++ b/CPP/7zip/Archive/Udf/UdfIn.cpp
@@ -2,12 +2,25 @@
#include "StdAfx.h"
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#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)
@@ -15,24 +28,22 @@
namespace NArchive {
namespace NUdf {
-const int kNumPartitionsMax = 64;
-const int kNumLogVolumesMax = 64;
-const int kNumRecureseLevelsMax = 1 << 10;
-const int kNumItemsMax = 1 << 27;
-const int kNumFilesMax = 1 << 28;
-const int kNumRefsMax = 1 << 28;
-const UInt32 kNumExtentsMax = (UInt32)1 << 30;
-const UInt64 kFileNameLengthTotalMax = (UInt64)1 << 33;
-const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33;
-
-void MY_FAST_CALL Crc16GenerateTable(void);
+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) (g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8))
+#define CRC16_UPDATE_BYTE(crc, b) ((UInt16)(g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8)))
#define kCrc16Poly 0x1021
-UInt16 g_Crc16Table[256];
+static UInt16 g_Crc16Table[256];
void MY_FAST_CALL Crc16GenerateTable(void)
{
@@ -61,15 +72,14 @@ UInt16 MY_FAST_CALL Crc16Calc(const void *data, size_t size)
struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit;
-void CDString128::Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); }
+
void CDString::Parse(const Byte *p, unsigned size)
{
- Data.SetCapacity(size);
- memcpy(Data, p, size);
+ Data.CopyFrom(p, size);
}
-static UString ParseDString(const Byte *data, int size)
+static UString ParseDString(const Byte *data, unsigned size)
{
UString res;
wchar_t *p;
@@ -78,8 +88,8 @@ static UString ParseDString(const Byte *data, int size)
Byte type = data[0];
if (type == 8)
{
- p = res.GetBuffer((int)size + 1);
- for (int i = 1; i < size; i++)
+ p = res.GetBuffer(size);
+ for (unsigned i = 1; i < size; i++)
{
wchar_t c = data[i];
if (c == 0)
@@ -89,10 +99,10 @@ static UString ParseDString(const Byte *data, int size)
}
else if (type == 16)
{
- p = res.GetBuffer((int)size / 2 + 1);
- for (int i = 1; i + 2 <= size; i += 2)
+ p = res.GetBuffer(size / 2);
+ for (unsigned i = 1; i + 2 <= size; i += 2)
{
- wchar_t c = ((wchar_t)data[i] << 8) | data[i + 1];
+ wchar_t c = GetBe16(data + i);
if (c == 0)
break;
*p++ = c;
@@ -106,13 +116,14 @@ static UString ParseDString(const Byte *data, int size)
return res;
}
-UString CDString:: GetString() const { return ParseDString(Data, (int)Data.GetCapacity()); }
UString CDString128::GetString() const
{
- int size = Data[sizeof(Data) - 1];
- return ParseDString(Data, MyMin(size, (int)(sizeof(Data) - 1)));
+ 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)); }
/*
@@ -161,8 +172,8 @@ HRESULT CTag::Parse(const Byte *buf, size_t size)
return S_FALSE;
Byte sum = 0;
int i;
- for (i = 0; i < 4; i++) sum = sum + buf[i];
- for (i = 5; i < 16; i++) sum = sum + buf[i];
+ 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);
@@ -182,27 +193,27 @@ HRESULT CTag::Parse(const Byte *buf, size_t size)
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_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
+ 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
};
@@ -237,6 +248,8 @@ void CLongAllocDesc::Parse(const Byte *buf)
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);
@@ -244,7 +257,7 @@ bool CInArchive::CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UI
bool CInArchive::CheckItemExtents(int volIndex, const CItem &item) const
{
- for (int i = 0; i < item.Extents.Size(); i++)
+ FOR_VECTOR (i, item.Extents)
{
const CMyExtent &e = item.Extents[i];
if (!CheckExtent(volIndex, e.PartitionRef, e.Pos, e.GetLen()))
@@ -259,9 +272,14 @@ HRESULT CInArchive::Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32
return S_FALSE;
const CLogVol &vol = LogVols[volIndex];
const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
- RINOK(_stream->Seek(((UInt64)partition.Pos << SecLogSize) +
- (UInt64)blockPos * vol.BlockSize, STREAM_SEEK_SET, NULL));
- return ReadStream_FALSE(_stream, buf, len);
+ 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)
@@ -278,9 +296,9 @@ HRESULT CInArchive::ReadFromFile(int volIndex, const CItem &item, CByteBuffer &b
buf = item.InlineData;
return S_OK;
}
- buf.SetCapacity((size_t)item.Size);
+ buf.Alloc((size_t)item.Size);
size_t pos = 0;
- for (int i = 0; i < item.Extents.Size(); i++)
+ FOR_VECTOR (i, item.Extents)
{
const CMyExtent &e = item.Extents[i];
UInt32 len = e.GetLen();
@@ -407,9 +425,8 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la
if (lad.GetLen() != vol.BlockSize)
return S_FALSE;
- CByteBuffer buf;
size_t size = lad.GetLen();
- buf.SetCapacity(size);
+ CByteBuffer buf(size);
RINOK(Read(volIndex, lad, buf));
CTag tag;
@@ -456,8 +473,7 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la
if (desctType == ICB_DESC_TYPE_INLINE)
{
item.IsInline = true;
- item.InlineData.SetCapacity(allocDescriptorsLen);
- memcpy(item.InlineData, p + pos, allocDescriptorsLen);
+ item.InlineData.CopyFrom(p + pos, allocDescriptorsLen);
}
else
{
@@ -504,7 +520,7 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la
item.InlineData.Free();
const Byte *p = buf;
- size = buf.GetCapacity();
+ size = buf.Size();
size_t processedTotal = 0;
for (; processedTotal < size;)
{
@@ -519,7 +535,7 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la
// file.ImplUse = fileId.ImplUse;
file.Id = fileId.Id;
- _fileNameLengthTotal += file.Id.Data.GetCapacity();
+ _fileNameLengthTotal += file.Id.Data.Size();
if (_fileNameLengthTotal > kFileNameLengthTotalMax)
return S_FALSE;
@@ -538,9 +554,9 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la
return S_FALSE;
_numExtents += item.Extents.Size();
- if (item.InlineData.GetCapacity() > kInlineExtentsSizeMax - _inlineExtentsSize)
+ if (item.InlineData.Size() > kInlineExtentsSizeMax - _inlineExtentsSize)
return S_FALSE;
- _inlineExtentsSize += item.InlineData.GetCapacity();
+ _inlineExtentsSize += item.InlineData.Size();
}
return S_OK;
@@ -548,7 +564,7 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la
HRESULT CInArchive::FillRefs(CFileSet &fs, int fileIndex, int parent, int numRecurseAllowed)
{
- if (_numRefs % 10000 == 0)
+ if ((_numRefs & 0xFFF) == 0)
{
RINOK(_progress->SetCompleted());
}
@@ -563,23 +579,47 @@ HRESULT CInArchive::FillRefs(CFileSet &fs, int fileIndex, int parent, int numRec
parent = fs.Refs.Size();
fs.Refs.Add(ref);
const CItem &item = Items[Files[fileIndex].ItemIndex];
- for (int i = 0; i < item.SubFiles.Size(); i++)
+ 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;
+ UInt32 offset = (UInt32)256 << SecLogSize;
+ size_t bufSize = 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.
- UInt64 fileSize;
- RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize));
+ /*
const size_t kBufSize = 1 << 14;
Byte buf[kBufSize];
size_t readSize = (fileSize < kBufSize) ? (size_t)fileSize : kBufSize;
@@ -598,22 +638,69 @@ HRESULT CInArchive::Open2()
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));
+ size_t bufSize = 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;
- for (UInt32 location = extentVDS.Pos; ; location++)
+ 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++)
{
size_t bufSize = 1 << SecLogSize;
size_t pos = 0;
- RINOK(_stream->Seek((UInt64)location << SecLogSize, STREAM_SEEK_SET, NULL));
- RINOK(ReadStream_FALSE(_stream, buf, bufSize));
+ 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;
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;
@@ -631,10 +718,15 @@ HRESULT CInArchive::Open2()
// 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;
@@ -647,6 +739,8 @@ HRESULT CInArchive::Open2()
// 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);
@@ -654,6 +748,8 @@ HRESULT CInArchive::Open2()
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++)
{
@@ -670,10 +766,33 @@ HRESULT CInArchive::Open2()
// memcpy(pm.Data, buf + pos + 2, pm.Length - 2);
if (pm.Type == 1)
{
- if (pos + 6 > bufSize)
+ 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;
@@ -686,21 +805,26 @@ HRESULT CInArchive::Open2()
UInt64 totalSize = 0;
- int volIndex;
+ unsigned volIndex;
for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
{
CLogVol &vol = LogVols[volIndex];
- for (int pmIndex = 0; pmIndex < vol.PartitionMaps.Size(); pmIndex++)
+ FOR_VECTOR (pmIndex, vol.PartitionMaps)
{
CPartitionMap &pm = vol.PartitionMaps[pmIndex];
- int i;
+ unsigned i;
for (i = 0; i < Partitions.Size(); i++)
{
CPartition &part = Partitions[i];
if (part.Number == pm.PartitionNumber)
{
if (part.VolIndex >= 0)
- return S_FALSE;
+ {
+ // it's for 2.60. Fix it
+ if (part.VolIndex != (int)volIndex)
+ return S_FALSE;
+ // return S_FALSE;
+ }
pm.PartitionIndex = i;
part.VolIndex = volIndex;
@@ -715,27 +839,39 @@ HRESULT CInArchive::Open2()
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 buf;
- buf.SetCapacity(nextExtent.GetLen());
+ CByteBuffer buf(nextExtent.GetLen());
RINOK(Read(volIndex, nextExtent, buf));
const Byte *p = buf;
size_t size = nextExtent.GetLen();
CTag tag;
RINOK(tag.Parse(p, size));
+
+ if (tag.Id == DESC_TYPE_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);
@@ -757,16 +893,76 @@ HRESULT CInArchive::Open2()
// nextExtent.Parse(p + 448);
}
- for (int fsIndex = 0; fsIndex < vol.FileSets.Size(); fsIndex++)
+ FOR_VECTOR (fsIndex, vol.FileSets)
{
CFileSet &fs = vol.FileSets[fsIndex];
- int fileIndex = Files.Size();
- Files.Add(CFile());
- RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, kNumRecureseLevelsMax));
- RINOK(FillRefs(fs, fileIndex, -1, kNumRecureseLevelsMax));
+ 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);
+ }
+ }
}
}
+ {
+ UInt32 secMask = ((UInt32)1 << SecLogSize) - 1;
+ PhySize = (PhySize + secMask) & ~(UInt64)secMask;
+ }
+ if (PhySize < fileSize)
+ {
+ RINOK(_stream->Seek(PhySize, STREAM_SEEK_SET, NULL));
+ size_t bufSize = 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)
+ {
+ PhySize += bufSize;
+ }
+ }
+ }
return S_OK;
}
@@ -774,15 +970,38 @@ 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; }
+ try
+ {
+ res = Open2();
+ }
+ catch(...)
+ {
+ // Clear();
+ // res = S_FALSE;
+ _stream.Release();
+ throw;
+ }
_stream.Release();
return res;
+ */
}
void CInArchive::Clear()
{
+ IsArc = false;
+ Unsupported = false;
+ UnexpectedEnd = false;
+
+ PhySize = 0;
+ FileSize = 0;
+
Partitions.Clear();
LogVols.Clear();
Items.Clear();
@@ -797,7 +1016,7 @@ void CInArchive::Clear()
UString CInArchive::GetComment() const
{
UString res;
- for (int i = 0; i < LogVols.Size(); i++)
+ FOR_VECTOR (i, LogVols)
{
if (i > 0)
res += L" ";
@@ -827,7 +1046,7 @@ static void UpdateWithName(UString &res, const UString &addString)
if (res.IsEmpty())
res = addString;
else
- res = addString + WCHAR_PATH_SEPARATOR + res;
+ res.Insert(0, addString + WCHAR_PATH_SEPARATOR);
}
UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex,
@@ -851,7 +1070,7 @@ UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex,
if (showFsName)
{
wchar_t s[32];
- ConvertUInt64ToString(fsIndex, s);
+ ConvertUInt32ToString(fsIndex, s);
UString newName = L"File Set ";
newName += s;
UpdateWithName(name, newName);
@@ -860,7 +1079,7 @@ UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex,
if (showVolName)
{
wchar_t s[32];
- ConvertUInt64ToString(volIndex, s);
+ ConvertUInt32ToString(volIndex, s);
UString newName = s;
UString newName2 = vol.GetName();
if (newName2.IsEmpty())
diff --git a/CPP/7zip/Archive/Udf/UdfIn.h b/CPP/7zip/Archive/Udf/UdfIn.h
index 46b9a7e8..23693a71 100755..100644
--- a/CPP/7zip/Archive/Udf/UdfIn.h
+++ b/CPP/7zip/Archive/Udf/UdfIn.h
@@ -3,11 +3,11 @@
#ifndef __ARCHIVE_UDF_IN_H
#define __ARCHIVE_UDF_IN_H
-#include "Common/MyCom.h"
-#include "Common/IntToString.h"
-#include "Common/Buffer.h"
-#include "Common/MyString.h"
-#include "Common/MyMap.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/MyBuffer.h"
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyMap.h"
+#include "../../../Common/MyString.h"
#include "../../IStream.h"
@@ -22,6 +22,7 @@ namespace NUdf {
struct CDString32
{
Byte Data[32];
+
void Parse(const Byte *buf);
// UString GetString() const;
};
@@ -30,13 +31,15 @@ struct CDString32
struct CDString128
{
Byte Data[128];
- void Parse(const Byte *buf);
+
+ 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;
};
@@ -52,12 +55,12 @@ struct CTime
bool IsLocal() const { return GetType() == 1; }
int GetMinutesOffset() const
{
- int t = (Data[0] | ((UInt16)Data[1] << 8)) & 0xFFF;
+ 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] | ((UInt16)Data[3] << 8)); }
+ unsigned GetYear() const { return (Data[2] | ((unsigned)Data[3] << 8)); }
void Parse(const Byte *buf);
};
@@ -208,8 +211,9 @@ struct CFile
// CByteBuffer ImplUse;
CDString Id;
- CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {}
int ItemIndex;
+
+ CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {}
UString GetName() const { return Id.GetString(); }
};
@@ -217,7 +221,7 @@ struct CMyExtent
{
UInt32 Pos;
UInt32 Len;
- int PartitionRef;
+ unsigned PartitionRef;
UInt32 GetLen() const { return Len & 0x3FFFFFFF; }
UInt32 GetType() const { return Len >> 30; }
@@ -254,7 +258,7 @@ struct CItem
bool IsRecAndAlloc() const
{
- for (int i = 0; i < Extents.Size(); i++)
+ FOR_VECTOR (i, Extents)
if (!Extents[i].IsRecAndAlloc())
return false;
return true;
@@ -263,9 +267,9 @@ struct CItem
UInt64 GetChunksSumSize() const
{
if (IsInline)
- return InlineData.GetCapacity();
+ return InlineData.Size();
UInt64 size = 0;
- for (int i = 0; i < Extents.Size(); i++)
+ FOR_VECTOR (i, Extents)
size += Extents[i].GetLen();
return size;
}
@@ -331,7 +335,7 @@ struct CProgressVirt
class CInArchive
{
- CMyComPtr<IInStream> _stream;
+ IInStream *_stream;
CProgressVirt *_progress;
HRESULT Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf);
@@ -351,17 +355,29 @@ class CInArchive
UInt32 _numExtents;
UInt64 _inlineExtentsSize;
bool CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const;
-public:
- HRESULT Open(IInStream *inStream, CProgressVirt *progress);
- void Clear();
+public:
CObjectVector<CPartition> Partitions;
CObjectVector<CLogVol> LogVols;
CObjectVector<CItem> Items;
CObjectVector<CFile> Files;
- int SecLogSize;
+ unsigned SecLogSize;
+ UInt64 PhySize;
+ UInt64 FileSize;
+
+ bool IsArc;
+ bool Unsupported;
+ bool UnexpectedEnd;
+
+ 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,
@@ -370,6 +386,8 @@ public:
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/Udf/UdfRegister.cpp b/CPP/7zip/Archive/Udf/UdfRegister.cpp
index 1b08d120..ed32f12e 100755..100644
--- a/CPP/7zip/Archive/Udf/UdfRegister.cpp
+++ b/CPP/7zip/Archive/Udf/UdfRegister.cpp
@@ -5,9 +5,3 @@
#include "../../Common/RegisterArc.h"
#include "UdfHandler.h"
-static IInArchive *CreateArc() { return new NArchive::NUdf::CHandler; }
-
-static CArcInfo g_ArcInfo =
- { L"Udf", L"iso img", 0, 0xE0, { 0, 'N', 'S', 'R', '0' }, 5, false, CreateArc, 0 };
-
-REGISTER_ARC(Udf)
diff --git a/CPP/7zip/Archive/UefiHandler.cpp b/CPP/7zip/Archive/UefiHandler.cpp
index 88739d8f..2aaf7d8f 100755..100644
--- a/CPP/7zip/Archive/UefiHandler.cpp
+++ b/CPP/7zip/Archive/UefiHandler.cpp
@@ -4,8 +4,6 @@
// #define SHOW_DEBUG_INFO
-// #include <stdio.h>
-
#ifdef SHOW_DEBUG_INFO
#include <stdio.h>
#endif
@@ -15,13 +13,12 @@
#include "../../../C/CpuArch.h"
#include "../../../C/LzmaDec.h"
-#include "Common/Buffer.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/StringConvert.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/StringConvert.h"
-#include "Windows/PropVariant.h"
-#include "Windows/PropVariantUtils.h"
+#include "../../Windows/PropVariantUtils.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
@@ -30,8 +27,6 @@
#include "../Compress/CopyCoder.h"
-#include "./Common/FindSignature.h"
-
#ifdef SHOW_DEBUG_INFO
#define PRF(x) x
#else
@@ -43,8 +38,6 @@
#define Get64(p) GetUi64(p)
#define Get24(p) (Get32(p) & 0xFFFFFF)
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
-
namespace NArchive {
namespace NUefi {
@@ -71,7 +64,7 @@ static const Byte k_FFS_Guid[kGuidSize] = FFS_SIGNATURE;
static const Byte k_MacFS_Guid[kGuidSize] =
{ 0xAD,0xEE,0xAD,0x04,0xFF,0x61,0x31,0x4D,0xB6,0xBA,0x64,0xF8,0xBF,0x90,0x1F,0x5A };
-static const UInt32 kFvSignature = 0x4856465F;
+static const UInt32 kFvSignature = 0x4856465F; // "_FVH"
static const Byte kGuids[][kGuidSize] =
{
@@ -93,19 +86,19 @@ static const Byte kGuids[][kGuidSize] =
static const char *kGuidNames[] =
{
- "CRC",
- "VolumeTopFile",
- "ACPI",
- "ACPI2",
- "Main",
- "Intel32",
- "Intel64",
- "Intel32c",
- "Intel64c",
- "MacVolume",
- "MacUpdate.txt",
- "MacName",
- "Insyde"
+ "CRC"
+ , "VolumeTopFile"
+ , "ACPI"
+ , "ACPI2"
+ , "Main"
+ , "Intel32"
+ , "Intel64"
+ , "Intel32c"
+ , "Intel64c"
+ , "MacVolume"
+ , "MacUpdate.txt"
+ , "MacName"
+ , "Insyde"
};
enum
@@ -237,18 +230,18 @@ enum
static const char *g_FileTypes[] =
{
- "ALL",
- "RAW",
- "FREEFORM",
- "SECURITY_CORE",
- "PEI_CORE",
- "DXE_CORE",
- "PEIM",
- "DRIVER",
- "COMBINED_PEIM_DRIVER",
- "APPLICATION",
- "0xA",
- "VOLUME"
+ "ALL"
+ , "RAW"
+ , "FREEFORM"
+ , "SECURITY_CORE"
+ , "PEI_CORE"
+ , "DXE_CORE"
+ , "PEIM"
+ , "DRIVER"
+ , "COMBINED_PEIM_DRIVER"
+ , "APPLICATION"
+ , "0xA"
+ , "VOLUME"
};
// typedef Byte FFS_FILE_ATTRIBUTES;
@@ -334,9 +327,9 @@ static const CUInt32PCharPair g_SECTION_TYPE[] =
static const char *g_Methods[] =
{
- "COPY",
- "LZH",
- "LZMA"
+ "COPY"
+ , "LZH"
+ , "LZMA"
};
static AString UInt32ToString(UInt32 val)
@@ -446,7 +439,7 @@ class CFfsFileHeader
Byte Attrib;
Byte State;
- UInt16 GetTailReference() const { return CheckHeader | ((UInt16)CheckFile << 8); }
+ 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; }
@@ -474,6 +467,7 @@ public:
}
UInt32 GetDataSize() const { return Size - kFileHeaderSize - GetTailSize(); }
+ UInt32 GetDataSize2(UInt32 rem) const { return rem - kFileHeaderSize - GetTailSize(); }
bool Check(const Byte *p, UInt32 size)
{
@@ -544,8 +538,7 @@ public:
}
};
-#define GET_32(offs, dest) dest = Get32(p + (offs));
-#define GET_64(offs, dest) dest = Get64(p + (offs));
+#define G32(_offs_, dest) dest = Get32(p + (_offs_));
struct CCapsuleHeader
{
@@ -567,18 +560,18 @@ struct CCapsuleHeader
void Parse(const Byte *p)
{
- GET_32(0x10, HeaderSize);
- GET_32(0x14, Flags);
- GET_32(0x18, CapsuleImageSize);
- GET_32(0x1C, SequenceNumber);
- GET_32(0x30, OffsetToSplitInformation);
- GET_32(0x34, OffsetToCapsuleBody);
- GET_32(0x38, OffsetToOemDefinedHeader);
- GET_32(0x3C, OffsetToAuthorInformation);
- GET_32(0x40, OffsetToRevisionInformation);
- GET_32(0x44, OffsetToShortDescription);
- GET_32(0x48, OffsetToLongDescription);
- GET_32(0x4C, OffsetToApplicableDevices);
+ G32(0x10, HeaderSize);
+ G32(0x14, Flags);
+ G32(0x18, CapsuleImageSize);
+ 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);
}
};
@@ -655,6 +648,7 @@ class CHandler:
UInt32 _totalBufsSize;
CCapsuleHeader _h;
+ UInt64 _phySize;
void AddCommentString(const wchar_t *name, UInt32 pos);
int AddItem(const CItem &item);
@@ -663,7 +657,9 @@ class CHandler:
int AddBuf(UInt32 size);
HRESULT ParseSections(int bufIndex, UInt32 pos, UInt32 size, int parent, int method, int level);
- HRESULT ParseVolume(int bufIndex, UInt32 posBase, UInt32 size, 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);
@@ -674,21 +670,20 @@ public:
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
};
-static const STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidCharacts, VT_BSTR}
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidMethod,
+ kpidCharacts
};
-static const STATPROPSTG kArcProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidComment, VT_BSTR},
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidPhySize, VT_UI8},
- { NULL, kpidCharacts, VT_BSTR}
+ kpidComment,
+ kpidMethod,
+ kpidCharacts
};
IMP_IInArchive_Props
@@ -733,7 +728,7 @@ void CHandler::AddCommentString(const wchar_t *name, UInt32 pos)
return;
for (UInt32 i = pos;; i += 2)
{
- if (s.Length() > (1 << 16) || i >= _h.OffsetToCapsuleBody)
+ if (s.Len() > (1 << 16) || i >= _h.OffsetToCapsuleBody)
return;
wchar_t c = Get16(buf + i);
if (c == 0)
@@ -773,7 +768,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
break;
}
case kpidComment: if (!_comment.IsEmpty()) prop = _comment; break;
- case kpidPhySize: prop = (UInt64)_h.CapsuleImageSize; break;
+ case kpidPhySize: prop = (UInt64)_phySize; break;
}
prop.Detach(value);
return S_OK;
@@ -1037,7 +1032,7 @@ static HRESULT LzhDecode(Byte *dest, UInt32 destSize, const Byte *src, UInt32 sr
{
UInt32 c = extraHuff.DecodeSymbol(&bitDec);
if (c > 2)
- lens[i++] = (Byte)c - 2;
+ lens[i++] = (Byte)(c - 2);
else
{
UInt32 numZeros;
@@ -1163,8 +1158,8 @@ int CHandler::AddBuf(UInt32 size)
if (size > kBufTotalSizeMax - _totalBufsSize)
throw 1;
_totalBufsSize += size;
- int index = _bufs.Add(CByteBuffer());
- _bufs[index].SetCapacity(size);
+ int index = _bufs.Size();
+ _bufs.AddNew().Alloc(size);
return index;
}
@@ -1272,7 +1267,9 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p
pStart, 5, LZMA_FINISH_END, &status, &g_Alloc);
if (res != 0)
return S_FALSE;
- if (srcLen != srcLen2 || destLen != lzmaUncompressedSize || status != LZMA_STATUS_FINISHED_WITH_MARK)
+ if (srcLen != srcLen2 || destLen != lzmaUncompressedSize || (
+ status != LZMA_STATUS_FINISHED_WITH_MARK &&
+ status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
return S_FALSE;
RINOK(ParseSections(newBufIndex, 0, (UInt32)lzmaUncompressedSize, parent, compressionType, level));
}
@@ -1323,7 +1320,10 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p
{
item.KeepName = false;
int newParent = AddDirItem(item);
- RINOK(ParseVolume(bufIndex, posBase + pos + 4, sectSize - 4, newParent, method, level));
+ RINOK(ParseVolume(bufIndex, posBase + pos + 4,
+ sectSize - 4,
+ sectSize - 4,
+ newParent, method, level));
}
else
{
@@ -1341,7 +1341,10 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p
needAdd = false;
item.Name = "vol";
int newParent = AddDirItem(item);
- RINOK(ParseVolume(bufIndex, posBase + pos + 4 + kInsydeOffset, sectDataSize - kInsydeOffset, newParent, method, level));
+ RINOK(ParseVolume(bufIndex, posBase + pos + 4 + kInsydeOffset,
+ sectDataSize - kInsydeOffset,
+ sectDataSize - kInsydeOffset,
+ newParent, method, level));
}
if (needAdd)
@@ -1359,19 +1362,20 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p
AString s;
if (ParseDepedencyExpression(p + 4, sectDataSize, s))
{
- if (s.Length() < (1 << 9))
+ if (s.Len() < (1 << 9))
{
- s = '[' + s + ']';
+ s.InsertAtFront('[');
+ s += ']';
AddSpaceAndString(_items[item.Parent].Characts, s);
needAdd = false;
}
else
{
- item.BufIndex = AddBuf(s.Length());
+ item.BufIndex = AddBuf(s.Len());
CByteBuffer &buf0 = _bufs[item.BufIndex];
- memcpy(buf0, s, s.Length());
+ memcpy(buf0, s, s.Len());
item.Offset = 0;
- item.Size = s.Length();
+ item.Size = s.Len();
}
}
break;
@@ -1383,7 +1387,11 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p
AString s;
if (ParseUtf16zString2(p + 6, sectDataSize - 2, s))
{
- AddSpaceAndString(_items[item.Parent].Characts, (AString)"ver:" + UInt32ToString(Get16(p + 4)) + ' ' + s);
+ AString s2 = "ver:";
+ s2 += UInt32ToString(Get16(p + 4));
+ s2 += ' ';
+ s2 += s;
+ AddSpaceAndString(_items[item.Parent].Characts, s2);
needAdd = false;
}
}
@@ -1430,13 +1438,39 @@ static bool Is_FF_Stream(const Byte *p, UInt32 size)
return (Count_FF_Bytes(p, size) == size);
}
-HRESULT CHandler::ParseVolume(int bufIndex, UInt32 posBase, UInt32 size, int parent, int method, int level)
+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, size, level, "Volume");
level++;
- if (size < kFvHeaderSize)
+ if (exactSize < kFvHeaderSize)
return S_FALSE;
const Byte *p = _bufs[bufIndex] + posBase;
// first 16 bytes must be zeros, but they are not zeros sometimes.
@@ -1448,28 +1482,27 @@ HRESULT CHandler::ParseVolume(int bufIndex, UInt32 posBase, UInt32 size, int par
item.BufIndex = bufIndex;
item.Parent = parent;
item.Offset = posBase;
- item.Size = size;
+ item.Size = exactSize;
item.SetGuid(p + kFfsGuidOffset);
item.Name += " [VOLUME]";
AddItem(item);
return S_OK;
}
- if (Get32(p + 0x28) != kFvSignature)
- return S_FALSE;
- UInt32 attribs = Get32(p + 0x2C);
- if ((attribs & FVB_ERASE_POLARITY) == 0)
+ CVolFfsHeader ffsHeader;
+ if (!ffsHeader.Parse(p))
return S_FALSE;
// if (parent >= 0) AddSpaceAndString(_items[parent].Characts, FLAGS_TO_STRING(g_FV_Attribs, attribs));
- UInt64 fvLen = Get64(p + 0x20);
- UInt32 headerLen = Get16(p + 0x30);
- if (headerLen > size || headerLen < kFvHeaderSize || (headerLen & 0x7) != 0 ||
- fvLen > size || fvLen < headerLen)
+
+ // 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 < headerLen; i += 2)
+ for (UInt32 i = 0; i < ffsHeader.HeaderLen; i += 2)
checkCalc += Get16(p + i);
if ((checkCalc & 0xFFFF) != 0)
return S_FALSE;
@@ -1482,7 +1515,7 @@ HRESULT CHandler::ParseVolume(int bufIndex, UInt32 posBase, UInt32 size, int par
UInt32 pos = kFvHeaderSize;
for (;;)
{
- if (pos >= headerLen)
+ if (pos >= ffsHeader.HeaderLen)
return S_FALSE;
UInt32 numBlocks = Get32(p + pos);
UInt32 length = Get32(p + pos + 4);
@@ -1490,18 +1523,18 @@ HRESULT CHandler::ParseVolume(int bufIndex, UInt32 posBase, UInt32 size, int par
if (numBlocks == 0 && length == 0)
break;
}
- if (pos != headerLen)
+ if (pos != ffsHeader.HeaderLen)
return S_FALSE;
CRecordVector<UInt32> guidsVector;
for (;;)
{
- UInt32 rem = (UInt32)fvLen - pos;
+ UInt32 rem = (UInt32)ffsHeader.VolSize - pos;
if (rem < kFileHeaderSize)
break;
pos = (pos + 7) & ~7;
- rem = (UInt32)fvLen - pos;
+ rem = (UInt32)ffsHeader.VolSize - pos;
if (rem < kFileHeaderSize)
break;
@@ -1565,7 +1598,10 @@ HRESULT CHandler::ParseVolume(int bufIndex, UInt32 posBase, UInt32 size, int par
if (isVolume)
{
int newParent = AddDirItem(item);
- RINOK(ParseVolume(bufIndex, offset, sectSize, newParent, method, level));
+ 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);
@@ -1590,6 +1626,7 @@ HRESULT CHandler::OpenCapsule(IInStream *stream)
_h.OffsetToCapsuleBody < kHeaderSize ||
_h.OffsetToCapsuleBody > _h.CapsuleImageSize)
return S_FALSE;
+ _phySize = _h.CapsuleImageSize;
if (_h.SequenceNumber != 0 ||
_h.OffsetToSplitInformation != 0 )
@@ -1605,112 +1642,29 @@ HRESULT CHandler::OpenCapsule(IInStream *stream)
AddCommentString(L"Short Description", _h.OffsetToShortDescription);
AddCommentString(L"Long Description", _h.OffsetToLongDescription);
- return ParseVolume(bufIndex, _h.OffsetToCapsuleBody, _h.CapsuleImageSize - _h.OffsetToCapsuleBody, -1, -1, 0);
+ return ParseVolume(bufIndex, _h.OffsetToCapsuleBody,
+ _h.CapsuleImageSize - _h.OffsetToCapsuleBody,
+ _h.CapsuleImageSize - _h.OffsetToCapsuleBody,
+ -1, -1, 0);
}
-HRESULT CHandler::OpenFv(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback)
+HRESULT CHandler::OpenFv(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback * /* callback */)
{
- UInt64 fileSize;
- RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
- if (fileSize > (1 << 27))
+ Byte buf[kFvHeaderSize];
+ RINOK(ReadStream_FALSE(stream, buf, kFvHeaderSize));
+ if (!IsFfs(buf))
return S_FALSE;
-
- UInt32 volIndex = 0;
- UInt32 pos = 0, prevEnd = 0;
- if (callback)
- {
- RINOK(callback->SetTotal(NULL, &fileSize));
- }
-
- for (;;)
- {
- UInt64 limit = 0;
- UInt64 *limitPtr = NULL;
- if (maxCheckStartPosition)
- {
- UInt32 directSize = pos - prevEnd;
- if (directSize >= *maxCheckStartPosition)
- break;
- limit = *maxCheckStartPosition - directSize;
- limitPtr = &limit;
- }
-
- UInt64 resPos;
- RINOK(stream->Seek(pos + kFfsGuidOffset, STREAM_SEEK_SET, NULL));
- if (FindSignatureInStream(stream, k_FFS_Guid, kGuidSize, limitPtr, resPos) == S_FALSE)
- break;
-
- pos += (UInt32)resPos;
- UInt64 fvSize;
- {
- UInt32 rem = (UInt32)fileSize - pos;
- if (rem < kFvHeaderSize)
- break;
- RINOK(stream->Seek(pos, STREAM_SEEK_SET, NULL));
- Byte buf[kFvHeaderSize];
- RINOK(ReadStream_FALSE(stream, buf, kFvHeaderSize));
- fvSize = Get64(buf + 0x20);
- if (!IsFfs(buf) || fvSize > rem)
- {
- pos++;
- continue;
- }
- }
-
- RINOK(stream->Seek(prevEnd, STREAM_SEEK_SET, NULL));
-
- if (pos != prevEnd)
- {
- CItem item;
- item.Offset = 0;
- item.Size = pos - prevEnd;
- item.BufIndex = AddBuf(item.Size);
- CByteBuffer &buf0 = _bufs[item.BufIndex];
- RINOK(ReadStream_FALSE(stream, buf0, item.Size));
- item.Name = UInt32ToString(volIndex++);
- AddItem(item);
- }
-
- prevEnd = pos;
- RINOK(stream->Seek(pos, STREAM_SEEK_SET, NULL));
- UInt32 fvSize32 = (UInt32)fvSize;
- CItem item;
- item.BufIndex = AddBuf(fvSize32);
- CByteBuffer &buf0 = _bufs[item.BufIndex];
- item.Name = UInt32ToString(volIndex++);
- int parent = AddDirItem(item);
- ReadStream_FALSE(stream, buf0, fvSize32);
- RINOK(ParseVolume(item.BufIndex, 0, fvSize32, parent, -1, 0));
- pos += fvSize32;
- prevEnd = pos;
-
- if (callback)
- {
- UInt64 pos64 = pos;
- RINOK(callback->SetCompleted(NULL, &pos64));
- }
- }
- if (_items.Size() == 0)
+ CVolFfsHeader ffsHeader;
+ if (!ffsHeader.Parse(buf))
return S_FALSE;
-
- if (pos <= fileSize)
- {
- pos = (UInt32)fileSize;
- if (prevEnd < pos)
- {
- CItem item;
- item.Offset = 0;
- item.Size = pos - prevEnd;
- item.BufIndex = AddBuf(item.Size);
- CByteBuffer &buf0 = _bufs[item.BufIndex];
- RINOK(stream->Seek(prevEnd, STREAM_SEEK_SET, NULL));
- RINOK(ReadStream_FALSE(stream, buf0, item.Size));
- item.Name = UInt32ToString(volIndex++);
- AddItem(item);
- }
- }
- _h.CapsuleImageSize = pos;
- return S_OK;
+ 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;
+ int 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)
@@ -1724,20 +1678,21 @@ HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition,
RINOK(OpenFv(stream, maxCheckStartPosition, callback));
}
- CIntVector numChilds;
- numChilds.Reserve(_items.Size());
- int i;
- for (i = 0; i < _items.Size(); i++)
+ unsigned num = _items.Size();
+ CIntArr numChilds(num);
+ unsigned i;
+ for (i = 0; i < num; i++)
+ numChilds[i] = 0;
+ for (i = 0; i < num; i++)
{
- numChilds.Add(0);
int parent = _items[i].Parent;
if (parent >= 0)
numChilds[parent]++;
}
- for (i = 0; i < _items.Size(); i++)
+ for (i = 0; i < num; i++)
{
- CItem &item = _items[i];
+ const CItem &item = _items[i];
int parent = item.Parent;
if (parent >= 0)
{
@@ -1748,7 +1703,7 @@ HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition,
}
}
- CIntVector mainToReduced;
+ CUIntVector mainToReduced;
for (i = 0; i < _items.Size(); i++)
{
mainToReduced.Add(_items2.Size());
@@ -1807,18 +1762,18 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
{
COM_TRY_BEGIN
Close();
- try
{
- if (Open2(inStream, maxCheckStartPosition, callback) != S_OK)
- return S_FALSE;
+ HRESULT res = Open2(inStream, maxCheckStartPosition, callback);
+ if (res == E_NOTIMPL)
+ res = S_FALSE;
+ return res;
}
- catch(...) { return S_FALSE; }
- return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::Close()
{
+ _phySize = 0;
_totalBufsSize = 0;
_methodsMask = 0;
_items.Clear();
@@ -1839,7 +1794,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items2.Size();
if (numItems == 0)
@@ -1916,20 +1871,32 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
}
-namespace UEFIc
-{
- static IInArchive *CreateArc() { return new CHandler(true); }
- static CArcInfo g_ArcInfo =
- { L"UEFIc", L"scap", 0, 0xD0, CAPSULE_SIGNATURE, kCapsuleSigSize, false, CreateArc, 0 };
- REGISTER_ARC(UEFIc)
+namespace UEFIc {
+
+IMP_CreateArcIn_2(CHandler(true))
+
+static CArcInfo g_ArcInfo =
+ { "UEFIc", "scap", 0, 0xD0,
+ kCapsuleSigSize, CAPSULE_SIGNATURE,
+ 0,
+ NArcInfoFlags::kFindSignature,
+ CreateArc };
+
+REGISTER_ARC(UEFIc)
}
-namespace UEFIs
-{
- static IInArchive *CreateArc() { return new CHandler(false); }
- static CArcInfo g_ArcInfo =
- { L"UEFIs", L"", 0, 0xD1, FFS_SIGNATURE, kGuidSize, false, CreateArc, 0 };
- REGISTER_ARC(UEFIs)
+namespace UEFIf {
+
+IMP_CreateArcIn_2(CHandler(false))
+
+static CArcInfo g_ArcInfo =
+ { "UEFIf", "uefif", 0, 0xD1,
+ kGuidSize, FFS_SIGNATURE,
+ kFfsGuidOffset,
+ NArcInfoFlags::kFindSignature,
+ CreateArc };
+
+REGISTER_ARC(UEFIf)
}
}}
diff --git a/CPP/7zip/Archive/VhdHandler.cpp b/CPP/7zip/Archive/VhdHandler.cpp
index 9d1c928e..5268bd0b 100755..100644
--- a/CPP/7zip/Archive/VhdHandler.cpp
+++ b/CPP/7zip/Archive/VhdHandler.cpp
@@ -4,12 +4,12 @@
#include "../../../C/CpuArch.h"
-#include "Common/Buffer.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/MyString.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyString.h"
-#include "Windows/PropVariant.h"
+#include "../../Windows/PropVariant.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -22,14 +22,19 @@
#define Get32(p) GetBe32(p)
#define Get64(p) GetBe64(p)
-#define G32(p, dest) dest = Get32(p);
-#define G64(p, dest) dest = Get64(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;
@@ -38,11 +43,11 @@ static const UInt32 kDiskType_Diff = 4;
static const char *kDiskTypes[] =
{
- "0",
- "1",
- "Fixed",
- "Dynamic",
- "Differencing"
+ "0"
+ , "1"
+ , "Fixed"
+ , "Dynamic"
+ , "Differencing"
};
struct CFooter
@@ -73,7 +78,7 @@ struct CFooter
AString CFooter::GetTypeString() const
{
- if (Type < sizeof(kDiskTypes) / sizeof(kDiskTypes[0]))
+ if (Type < ARRAY_SIZE(kDiskTypes))
return kDiskTypes[Type];
char s[16];
ConvertUInt32ToString(Type, s);
@@ -96,27 +101,35 @@ static bool CheckBlock(const Byte *p, unsigned size, unsigned checkSumOffset, un
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, "conectix", 8) != 0)
+ 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;
- // G32(p + 0x08, Features);
- // G32(p + 0x0C, FormatVersion);
- G64(p + 0x10, DataOffset);
- G32(p + 0x18, CTime);
- G32(p + 0x1C, CreatorApp);
- G32(p + 0x20, CreatorVersion);
- G32(p + 0x24, CreatorHostOS);
- // G64(p + 0x28, OriginalSize);
- G64(p + 0x30, CurrentSize);
- G32(p + 0x38, DiskGeometry);
- G32(p + 0x3C, Type);
memcpy(Id, p + 0x44, 16);
SavedState = p[0x54];
- return CheckBlock(p, 512, 0x40, 0x55);
+ // if (DataOffset > ((UInt64)1 << 62)) return false;
+ // if (CurrentSize > ((UInt64)1 << 62)) return false;
+ return CheckBlock(p, kHeaderSize, 0x40, 0x55);
}
-/*
struct CParentLocatorEntry
{
UInt32 Code;
@@ -124,17 +137,15 @@ struct CParentLocatorEntry
UInt32 DataLen;
UInt64 DataOffset;
- bool Parse(const Byte *p);
+ bool Parse(const Byte *p)
+ {
+ G32(0x00, Code);
+ G32(0x04, DataSpace);
+ G32(0x08, DataLen);
+ G64(0x10, DataOffset);
+ return Get32(p + 0x0C) == 0; // Reserved
+ }
};
-bool CParentLocatorEntry::Parse(const Byte *p)
-{
- G32(p + 0x00, Code);
- G32(p + 0x04, DataSpace);
- G32(p + 0x08, DataLen);
- G32(p + 0x10, DataOffset);
- return (Get32(p + 0x0C) == 0); // Resrved
-}
-*/
struct CDynHeader
{
@@ -142,56 +153,63 @@ struct CDynHeader
UInt64 TableOffset;
// UInt32 HeaderVersion;
UInt32 NumBlocks;
- int BlockSizeLog;
+ unsigned BlockSizeLog;
UInt32 ParentTime;
Byte ParentId[16];
+ bool RelativeNameWasUsed;
UString ParentName;
- // CParentLocatorEntry ParentLocators[8];
+ UString RelativeParentNameFromLocator;
+ CParentLocatorEntry ParentLocators[8];
bool Parse(const Byte *p);
UInt32 NumBitMapSectors() const
{
- UInt32 numSectorsInBlock = (1 << (BlockSizeLog - 9));
- return (numSectorsInBlock + 512 * 8 - 1) / (512 * 8);
+ UInt32 numSectorsInBlock = (1 << (BlockSizeLog - kSectorSize_Log));
+ return (numSectorsInBlock + kSectorSize * 8 - 1) / (kSectorSize * 8);
+ }
+ void Clear()
+ {
+ RelativeNameWasUsed = false;
+ ParentName.Empty();
+ RelativeParentNameFromLocator.Empty();
}
};
-static int GetLog(UInt32 num)
-{
- for (int i = 0; i < 31; i++)
- if (((UInt32)1 << i) == num)
- return i;
- return -1;
-}
-
bool CDynHeader::Parse(const Byte *p)
{
if (memcmp(p, "cxsparse", 8) != 0)
return false;
- // G64(p + 0x08, DataOffset);
- G64(p + 0x10, TableOffset);
- // G32(p + 0x18, HeaderVersion);
- G32(p + 0x1C, NumBlocks);
- BlockSizeLog = GetLog(Get32(p + 0x20));
- if (BlockSizeLog < 9 || BlockSizeLog > 30)
- return false;
- G32(p + 0x38, ParentTime);
+ // 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 int kNameLength = 256;
- wchar_t *s = ParentName.GetBuffer(kNameLength);
- for (unsigned i = 0; i < kNameLength; i++)
+ const unsigned kNameLen = 256;
+ wchar_t *s = ParentName.GetBuffer(kNameLen);
+ for (unsigned i = 0; i < kNameLen; i++)
s[i] = Get16(p + 0x40 + i * 2);
- s[kNameLength] = 0;
+ s[kNameLen] = 0;
ParentName.ReleaseBuffer();
}
- /*
- for (int i = 0; i < 8; 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);
}
@@ -202,8 +220,10 @@ class CHandler:
public CMyUnknownImp
{
UInt64 _virtPos;
- UInt64 _phyPos;
- UInt64 _phyLimit;
+ UInt64 _posInArc;
+ UInt64 _posInArcLimit;
+ UInt64 _startOffset;
+ UInt64 _phySize;
CFooter Footer;
CDynHeader Dyn;
@@ -214,7 +234,22 @@ class CHandler:
CMyComPtr<IInStream> Stream;
CMyComPtr<IInStream> ParentStream;
CHandler *Parent;
+ UString _errorMessage;
+ // bool _unexpectedEnd;
+ void AddErrorMessage(const wchar_t *s)
+ {
+ if (!_errorMessage.IsEmpty())
+ _errorMessage += L'\n';
+ _errorMessage += s;
+ }
+ 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);
@@ -223,7 +258,7 @@ class CHandler:
UInt64 GetPackSize() const
{ return Footer.ThereIsDynamic() ? ((UInt64)NumUsedBlocks << Dyn.BlockSizeLog) : Footer.CurrentSize; }
- UString GetParentName() const
+ UString GetParentSequence() const
{
const CHandler *p = this;
UString res;
@@ -231,26 +266,45 @@ class CHandler:
{
if (!res.IsEmpty())
res += L" -> ";
- res += p->Dyn.ParentName;
+ 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 += L' ';
+ res += L'(';
+ res += anotherName;
+ res += L')';
+ }
p = p->Parent;
}
return res;
}
- bool IsOK() const
+ bool AreParentsOK() const
{
const CHandler *p = this;
while (p->NeedParent())
{
p = p->Parent;
- if (p == 0)
+ if (!p)
return false;
}
return true;
}
HRESULT Open3();
- HRESULT Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, int level);
+ HRESULT Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, unsigned level);
public:
MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream)
@@ -261,7 +315,7 @@ public:
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
};
-HRESULT CHandler::Seek(UInt64 offset) { return Stream->Seek(offset, STREAM_SEEK_SET, NULL); }
+HRESULT CHandler::Seek(UInt64 offset) { return Stream->Seek(_startOffset + offset, STREAM_SEEK_SET, NULL); }
HRESULT CHandler::InitAndSeek()
{
@@ -269,50 +323,122 @@ HRESULT CHandler::InitAndSeek()
{
RINOK(Parent->InitAndSeek());
}
- _virtPos = _phyPos = 0;
+ _virtPos = _posInArc = 0;
BitMapTag = kUnusedBlock;
- BitMap.SetCapacity(Dyn.NumBitMapSectors() << 9);
+ BitMap.Alloc(Dyn.NumBitMapSectors() << kSectorSize_Log);
return Seek(0);
}
HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size)
{
- if (offset + size > _phyLimit)
+ if (offset + size > _posInArcLimit)
return S_FALSE;
- if (offset != _phyPos)
+ if (offset != _posInArc)
{
- _phyPos = offset;
+ _posInArc = offset;
RINOK(Seek(offset));
}
HRESULT res = ReadStream_FALSE(Stream, data, size);
- _phyPos += size;
+ if (res == S_OK)
+ _posInArc += size;
+ else
+ Reset_PosInArc();
return res;
}
HRESULT CHandler::Open3()
{
- RINOK(Stream->Seek(0, STREAM_SEEK_END, &_phyPos));
- if (_phyPos < 512)
+ // 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);
+
+ 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];
- _phyLimit = _phyPos;
- RINOK(ReadPhy(_phyLimit - 512, buf, 512));
- if (!Footer.Parse(buf))
- return S_FALSE;
- _phyLimit -= 512;
+ RINOK(Stream->Seek(fileSize - kHeaderSize, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(Stream, buf, kHeaderSize));
- if (!Footer.ThereIsDynamic())
+ if (!headerIsOK)
+ {
+ if (!Footer.Parse(buf))
+ return S_FALSE;
+ 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;
+ }
- RINOK(ReadPhy(0, buf + 512, 512));
- if (memcmp(buf, buf + 512, 512) != 0)
- return S_FALSE;
+ _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.GetBuffer(len);
+ RINOK(ReadPhy(locator.DataOffset, nameBuf, locator.DataLen));
+ for (unsigned j = 0; j < len; j++)
+ s[j] = GetUi16(nameBuf + j * 2);
+ s[len] = 0;
+ tempString.ReleaseBuffer();
+ 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;
@@ -324,20 +450,69 @@ HRESULT CHandler::Open3()
else if (((Footer.CurrentSize - 1) >> Dyn.BlockSizeLog) + 1 != Dyn.NumBlocks)
return S_FALSE;
- Bat.Reserve(Dyn.NumBlocks);
+ 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, 512));
- for (UInt32 j = 0; j < 512; j += 4)
+ 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.Add(v);
+ }
+ 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(L"Can't find footer");
return S_OK;
}
@@ -371,17 +546,17 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
}
else
{
- UInt64 newPos = (UInt64)blockSectIndex << 9;
+ UInt64 newPos = (UInt64)blockSectIndex << kSectorSize_Log;
if (BitMapTag != blockIndex)
{
- RINOK(ReadPhy(newPos, BitMap, (UInt32)BitMap.GetCapacity()));
+ RINOK(ReadPhy(newPos, BitMap, (UInt32)BitMap.Size()));
BitMapTag = blockIndex;
}
- RINOK(ReadPhy(newPos + BitMap.GetCapacity() + offsetInBlock, data, size));
+ RINOK(ReadPhy(newPos + BitMap.Size() + offsetInBlock, data, size));
for (UInt32 cur = 0; cur < size;)
{
UInt32 rem = MyMin(0x200 - (offsetInBlock & 0x1FF), size - cur);
- UInt32 bmi = offsetInBlock >> 9;
+ UInt32 bmi = offsetInBlock >> kSectorSize_Log;
if (((BitMap[bmi >> 3] >> (7 - (bmi & 7))) & 1) == 0)
{
if (ParentStream)
@@ -409,15 +584,18 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
STDMETHODIMP CHandler::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
{
- switch(seekOrigin)
+ switch (seekOrigin)
{
- case STREAM_SEEK_SET: _virtPos = offset; break;
- case STREAM_SEEK_CUR: _virtPos += offset; break;
- case STREAM_SEEK_END: _virtPos = Footer.CurrentSize + offset; break;
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += Footer.CurrentSize; break;
default: return STG_E_INVALIDFUNCTION;
}
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = offset;
if (newPosition)
- *newPosition = _virtPos;
+ *newPosition = offset;
return S_OK;
}
@@ -427,9 +605,10 @@ enum
kpidSavedState
};
-STATPROPSTG kArcProps[] =
+static const STATPROPSTG kArcProps[] =
{
{ NULL, kpidSize, VT_UI8},
+ { NULL, kpidOffset, VT_UI8},
{ NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidClusterSize, VT_UI8},
{ NULL, kpidMethod, VT_BSTR},
@@ -440,16 +619,16 @@ STATPROPSTG kArcProps[] =
{ NULL, kpidId, VT_BSTR}
};
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidCTime, VT_FILETIME}
+ kpidSize,
+ kpidPackSize,
+ kpidCTime
/*
- { NULL, kpidNumCyls, VT_UI4},
- { NULL, kpidNumHeads, VT_UI4},
- { NULL, kpidSectorsPerTrack, VT_UI4}
+ { kpidNumCyls, VT_UI4},
+ { kpidNumHeads, VT_UI4},
+ { kpidSectorsPerTrack, VT_UI4}
*/
};
@@ -470,11 +649,11 @@ static void VhdTimeToFileTime(UInt32 vhdTime, NCOM::CPropVariant &prop)
prop = utc;
}
-static void StringToAString(char *dest, UInt32 s)
+static void StringToAString(char *dest, UInt32 val)
{
for (int i = 24; i >= 0; i -= 8)
{
- Byte b = (Byte)((s >> i) & 0xFF);
+ Byte b = (Byte)((val >> i) & 0xFF);
if (b < 0x20 || b > 0x7F)
break;
*dest++ = b;
@@ -496,11 +675,12 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
- switch(propID)
+ 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.GetTypeString();
@@ -535,7 +715,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
}
case kpidHostOS:
{
- if (Footer.CreatorHostOS == 0x5769326b)
+ if (Footer.CreatorHostOS == 0x5769326B)
prop = "Windows";
else
{
@@ -555,18 +735,32 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
break;
}
case kpidSavedState: prop = Footer.SavedState ? true : false; break;
- case kpidParent: if (NeedParent()) prop = GetParentName(); 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, int level)
+HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, unsigned level)
{
Close();
Stream = stream;
- if (level > 32)
+ 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)
@@ -575,16 +769,65 @@ HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback
return S_OK;
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
if (openArchiveCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback) != S_OK)
- return S_FALSE;
+ {
+ // return S_FALSE;
+ }
CMyComPtr<IInStream> nextStream;
- HRESULT res = openVolumeCallback->GetStream(Dyn.ParentName, &nextStream);
- if (res == S_FALSE)
- return S_OK;
- RINOK(res);
- Parent = new CHandler;
- ParentStream = Parent;
- return Parent->Open2(nextStream, this, openArchiveCallback, level + 1);
+ bool useRelative;
+ UString name;
+ if (!Dyn.RelativeParentNameFromLocator.IsEmpty())
+ {
+ useRelative = true;
+ name = Dyn.RelativeParentNameFromLocator;
+ }
+ else
+ {
+ useRelative = false;
+ name = Dyn.ParentName;
+ }
+ Dyn.RelativeNameWasUsed = useRelative;
+
+ if (openVolumeCallback)
+ {
+ 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_FALSE)
+ return S_OK;
+ }
+ RINOK(res);
+
+ Parent = new CHandler;
+ ParentStream = Parent;
+
+ res = Parent->Open2(nextStream, this, openArchiveCallback, level + 1);
+ if (res == S_FALSE)
+ {
+ Parent = NULL;
+ ParentStream.Release();
+ }
+ }
+ {
+ const CHandler *p = this;
+ while (p->NeedParent())
+ {
+ p = p->Parent;
+ if (p == 0)
+ {
+ AddErrorMessage(L"Can't open parent VHD file:");
+ AddErrorMessage(Dyn.ParentName);
+ break;
+ }
+ }
+ }
+ return S_OK;
}
STDMETHODIMP CHandler::Open(IInStream *stream,
@@ -613,11 +856,15 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
STDMETHODIMP CHandler::Close()
{
+ _phySize = 0;
Bat.Clear();
NumUsedBlocks = 0;
Parent = 0;
Stream.Release();
ParentStream.Release();
+ Dyn.Clear();
+ _errorMessage.Empty();
+ // _unexpectedEnd = false;
return S_OK;
}
@@ -629,8 +876,8 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
{
- COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
+ // COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
switch(propID)
{
@@ -645,7 +892,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN
}
prop.Detach(value);
return S_OK;
- COM_TRY_END
+ // COM_TRY_END
}
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
@@ -654,7 +901,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_BEGIN
if (numItems == 0)
return S_OK;
- if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
RINOK(extractCallback->SetTotal(Footer.CurrentSize));
@@ -678,7 +925,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ISequentialInStream> inStream;
HRESULT hres = GetStream(0, &inStream);
if (hres == S_FALSE)
- res = NExtract::NOperationResult::kUnSupportedMethod;
+ res = NExtract::NOperationResult::kUnsupportedMethod;
else
{
RINOK(hres);
@@ -715,7 +962,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea
*stream = streamTemp.Detach();
return S_OK;
}
- if (!Footer.ThereIsDynamic() || !IsOK())
+ if (!Footer.ThereIsDynamic() || !AreParentsOK())
return S_FALSE;
CMyComPtr<ISequentialInStream> streamTemp = this;
RINOK(InitAndSeek());
@@ -724,10 +971,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"VHD", L"vhd", L".mbr", 0xDC, { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x', 0, 0 }, 10, false, CreateArc, 0 };
+ { "VHD", "vhd", ".mbr", 0xDC,
+ kSignatureSize, SIGNATURE,
+ 0,
+ NArcInfoFlags::kUseGlobalOffset,
+ CreateArc };
REGISTER_ARC(Vhd)
diff --git a/CPP/7zip/Archive/Wim/StdAfx.h b/CPP/7zip/Archive/Wim/StdAfx.h
index e7fb6986..2854ff3e 100755..100644
--- a/CPP/7zip/Archive/Wim/StdAfx.h
+++ b/CPP/7zip/Archive/Wim/StdAfx.h
@@ -3,6 +3,6 @@
#ifndef __STDAFX_H
#define __STDAFX_H
-#include "../../../Common/MyWindows.h"
+#include "../../../Common/Common.h"
#endif
diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp
index eaad1e7c..6f0b10e2 100755..100644
--- a/CPP/7zip/Archive/Wim/WimHandler.cpp
+++ b/CPP/7zip/Archive/Wim/WimHandler.cpp
@@ -4,13 +4,10 @@
#include "../../../../C/CpuArch.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/StringToInt.h"
-#include "Common/UTFConvert.h"
-
-#include "Windows/PropVariant.h"
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+#include "../../Common/MethodProps.h"
#include "../../Common/ProgressUtils.h"
#include "../../Common/StreamUtils.h"
@@ -25,29 +22,36 @@ using namespace NWindows;
namespace NArchive {
namespace NWim {
-#define WIM_DETAILS
+// #define WIM_DETAILS
-static STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidCTime, VT_FILETIME},
- { NULL, kpidATime, VT_FILETIME},
- { NULL, kpidAttrib, VT_UI4},
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidShortName, VT_BSTR}
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ kpidAttrib,
+ kpidMethod,
+ kpidShortName,
+ kpidINode,
+ kpidLinks
#ifdef WIM_DETAILS
- , { NULL, kpidVolume, VT_UI4}
- , { NULL, kpidOffset, VT_UI8}
- , { NULL, kpidLinks, VT_UI4}
+ , kpidVolume
+ , kpidOffset
#endif
};
-static STATPROPSTG kArcProps[] =
+enum
+{
+ kpidNumImages = kpidUserDefined,
+ kpidBootImage
+};
+
+static const STATPROPSTG kArcProps[] =
{
{ NULL, kpidSize, VT_UI8},
{ NULL, kpidPackSize, VT_UI8},
@@ -58,133 +62,60 @@ static STATPROPSTG kArcProps[] =
{ NULL, kpidUnpackVer, VT_BSTR},
{ NULL, kpidIsVolume, VT_BOOL},
{ NULL, kpidVolume, VT_UI4},
- { NULL, kpidNumVolumes, VT_UI4}
+ { NULL, kpidNumVolumes, VT_UI4},
+ { L"Images", kpidNumImages, VT_UI4},
+ { L"Boot Image", kpidBootImage, VT_UI4}
};
-static bool ParseNumber64(const AString &s, UInt64 &res)
-{
- const char *end;
- if (s.Left(2) == "0x")
- {
- if (s.Length() == 2)
- return false;
- res = ConvertHexStringToUInt64((const char *)s + 2, &end);
- }
- else
- {
- if (s.IsEmpty())
- return false;
- res = ConvertStringToUInt64(s, &end);
- }
- return *end == 0;
-}
-
-static bool ParseNumber32(const AString &s, UInt32 &res)
-{
- UInt64 res64;
- if (!ParseNumber64(s, res64) || res64 >= ((UInt64)1 << 32))
- return false;
- res = (UInt32)res64;
- return true;
-}
-
-bool ParseTime(const CXmlItem &item, FILETIME &ft, const char *tag)
-{
- int index = item.FindSubTag(tag);
- if (index >= 0)
- {
- const CXmlItem &timeItem = item.SubItems[index];
- UInt32 low = 0, high = 0;
- if (ParseNumber32(timeItem.GetSubStringForTag("LOWPART"), low) &&
- ParseNumber32(timeItem.GetSubStringForTag("HIGHPART"), high))
- {
- ft.dwLowDateTime = low;
- ft.dwHighDateTime = high;
- return true;
- }
- }
- return false;
-}
+static const char *kMethodLZX = "LZX";
+static const char *kMethodXpress = "XPress";
+static const char *kMethodCopy = "Copy";
-void CImageInfo::Parse(const CXmlItem &item)
-{
- CTimeDefined = ParseTime(item, CTime, "CREATIONTIME");
- MTimeDefined = ParseTime(item, MTime, "LASTMODIFICATIONTIME");
- NameDefined = ConvertUTF8ToUnicode(item.GetSubStringForTag("NAME"), Name);
- // IndexDefined = ParseNumber32(item.GetPropertyValue("INDEX"), Index);
-}
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
-void CXml::ToUnicode(UString &s)
+static void AddErrorMessage(AString &s, const char *message)
{
- size_t size = Data.GetCapacity();
- if (size < 2 || (size & 1) != 0 || size > (1 << 24))
- return;
- const Byte *p = Data;
- if (Get16(p) != 0xFEFF)
- return;
- wchar_t *chars = s.GetBuffer((int)size / 2);
- for (size_t i = 2; i < size; i += 2)
- *chars++ = (wchar_t)Get16(p + i);
- *chars = 0;
- s.ReleaseBuffer();
+ if (!s.IsEmpty())
+ s += ". ";
+ s += message;
}
-void CXml::Parse()
+static void ConvertByteToHex(unsigned value, char *s)
{
- UString s;
- ToUnicode(s);
- AString utf;
- if (!ConvertUnicodeToUTF8(s, utf))
- return;
- ::CXml xml;
- if (!xml.Parse(utf))
- return;
- if (xml.Root.Name != "WIM")
- return;
-
- for (int i = 0; i < xml.Root.SubItems.Size(); i++)
+ for (int i = 0; i < 2; i++)
{
- const CXmlItem &item = xml.Root.SubItems[i];
- if (item.IsTagged("IMAGE"))
- {
- CImageInfo imageInfo;
- imageInfo.Parse(item);
- Images.Add(imageInfo);
- }
+ unsigned t = value & 0xF;
+ value >>= 4;
+ s[1 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
}
}
-static const char *kMethodLZX = "LZX";
-static const char *kMethodXpress = "XPress";
-static const char *kMethodCopy = "Copy";
-
-IMP_IInArchive_Props
-IMP_IInArchive_ArcProps
-
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
+ NCOM::CPropVariant prop;
const CImageInfo *image = NULL;
if (_xmls.Size() == 1)
{
- const CXml &xml = _xmls[0];
+ const CWimXml &xml = _xmls[0];
if (xml.Images.Size() == 1)
image = &xml.Images[0];
}
- switch(propID)
+ 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 CXml &xml = _xmls[0];
+ const CWimXml &xml = _xmls[0];
int index = -1;
- for (int i = 0; i < xml.Images.Size(); i++)
+ FOR_VECTOR (i, xml.Images)
{
const CImageInfo &image = xml.Images[i];
if (image.CTimeDefined)
@@ -199,9 +130,9 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidMTime:
if (_xmls.Size() == 1)
{
- const CXml &xml = _xmls[0];
+ const CWimXml &xml = _xmls[0];
int index = -1;
- for (int i = 0; i < xml.Images.Size(); i++)
+ FOR_VECTOR (i, xml.Images)
{
const CImageInfo &image = xml.Images[i];
if (image.MTimeDefined)
@@ -266,10 +197,63 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
}
break;
case kpidNumVolumes: if (_volumes.Size() > 0) prop = (UInt32)(_volumes.Size() - 1); break;
+
+ case kpidName:
+ if (_firstVolumeIndex >= 0)
+ {
+ const CHeader &h = _volumes[_firstVolumeIndex].Header;
+ if (GetUi32(h.Guid) != 0)
+ {
+ char temp[16 * 2 + 4];
+ int i;
+ for (i = 0; i < 4; i++)
+ ConvertByteToHex(h.Guid[i], temp + i * 2);
+ temp[i * 2] = 0;
+ AString s = temp;
+ const char *ext = ".wim";
+ if (h.NumParts != 1)
+ {
+ s += '_';
+ if (h.PartNumber != 1)
+ {
+ char sz[16];
+ ConvertUInt32ToString(h.PartNumber, sz);
+ s += sz;
+ }
+ 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)
+ {
+ char sz[16];
+ ConvertUInt32ToString(h.PartNumber, sz);
+ s = sz;
+ 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:
{
bool lzx = false, xpress = false, copy = false;
- for (int i = 0; i < _xmls.Size(); i++)
+ FOR_VECTOR (i, _xmls)
{
const CHeader &header = _volumes[_xmls[i].VolIndex].Header;
if (header.IsCompressed())
@@ -296,6 +280,34 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
res += kMethodCopy;
}
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 (HeadersError) flags |= kpv_ErrorFlags_HeadersError;
+ // if (UnexpectedEnd) flags |= kpv_ErrorFlags_UnexpectedEndOfArc;
+ 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;
}
}
prop.Detach(value);
@@ -303,104 +315,404 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
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);
+}
+
+#define FILES_DIR_NAME "[Files]"
+
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- if (index < (UInt32)_db.SortedItems.Size())
+ NCOM::CPropVariant prop;
+
+ if (index < _db.SortedItems.Size())
{
- int realIndex = _db.SortedItems[index];
+ 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.Streams[item.StreamIndex];
+ si = &_db.DataStreams[item.StreamIndex];
vol = &_volumes[si->PartNumber];
}
- switch(propID)
+ 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.HasMetadata)
- prop = _db.GetItemPath(realIndex);
+ if (item.ImageIndex >= 0)
+ _db.GetItemPath(realIndex, _showImageNumber, prop);
else
{
char sz[16];
ConvertUInt32ToString(item.StreamIndex, sz);
AString s = sz;
- while (s.Length() < _nameLenForStreams)
+ /*
+ while (s.Len() < _nameLenForStreams)
s = '0' + s;
+ */
/*
if (si->Resource.IsFree())
- prefix = "[Free]";
+ s = (AString)("[Free]" STRING_PATH_SEPARATOR) + sz;
+ else
*/
- s = "[Files]" STRING_PATH_SEPARATOR + s;
+ s = (AString)(FILES_DIR_NAME STRING_PATH_SEPARATOR) + sz;
prop = s;
}
break;
- case kpidShortName: if (item.HasMetadata) prop = item.ShortName; break;
-
- case kpidIsDir: prop = item.IsDir(); break;
- case kpidAttrib: if (item.HasMetadata) prop = item.Attrib; break;
- case kpidCTime: if (item.HasMetadata) prop = item.CTime; break;
- case kpidATime: if (item.HasMetadata) prop = item.ATime; break;
- case kpidMTime: if (item.HasMetadata) prop = item.MTime; break;
- case kpidPackSize: prop = si ? si->Resource.PackSize : (UInt64)0; break;
- case kpidSize: prop = si ? si->Resource.UnpackSize : (UInt64)0; break;
+
+ case 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: prop = (UInt64)(si ? si->Resource.PackSize : 0); break;
+ case kpidSize: prop = (UInt64)(si ? si->Resource.UnpackSize : 0); break;
+ case kpidIsDir: prop = item.IsDir; break;
+ case kpidIsAltStream: prop = item.IsAltStream; 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) prop = si->Resource.IsCompressed() ?
(vol->Header.IsLzxMode() ? kMethodLZX : kMethodXpress) : kMethodCopy; 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;
- case kpidLinks: prop = si ? (UInt32)si->RefCount : (UInt32)0; break;
#endif
}
}
else
{
index -= _db.SortedItems.Size();
+ if (index < _numXmlItems)
{
- switch(propID)
+ switch (propID)
{
case kpidPath:
- {
- char sz[16];
- ConvertUInt32ToString(_xmls[index].VolIndex, sz);
- prop = (AString)"[" + (AString)sz + "].xml";
- break;
- }
+ case kpidName: prop = _xmls[index].FileName; break;
case kpidIsDir: prop = false; break;
case kpidPackSize:
- case kpidSize: prop = (UInt64)_xmls[index].Data.GetCapacity(); break;
+ case kpidSize: prop = (UInt64)_xmls[index].Data.Size(); break;
case kpidMethod: prop = kMethodCopy; 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.NumExludededItems != 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.NumExludededItems != 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;
+}
+
+static bool IsEmptySha(const Byte *data)
+{
+ for (int i = 0; i < kHashSize; i++)
+ if (data[i] != 0)
+ return false;
+ return true;
+}
+
+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
{
- // UInt32 _volIndex;
UString _before;
UString _after;
public:
- CVolumeName() {};
-
void InitName(const UString &name)
{
- // _volIndex = 1;
int dotPos = name.ReverseFind('.');
if (dotPos < 0)
- dotPos = name.Length();
+ dotPos = name.Len();
_before = name.Left(dotPos);
- _after = name.Mid(dotPos);
+ _after = name.Ptr(dotPos);
}
- UString GetNextName(UInt32 index)
+ UString GetNextName(UInt32 index) const
{
wchar_t s[16];
ConvertUInt32ToString(index, s);
@@ -408,25 +720,26 @@ public:
}
};
-STDMETHODIMP CHandler::Open(IInStream *inStream,
- const UInt64 * /* maxCheckStartPosition */,
- IArchiveOpenCallback *openArchiveCallback)
+STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)
{
COM_TRY_BEGIN
+
Close();
{
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
CVolumeName seqName;
- if (openArchiveCallback != NULL)
- openArchiveCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+ if (callback)
+ callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
UInt32 numVolumes = 1;
- int firstVolumeIndex = -1;
+
for (UInt32 i = 1; i <= numVolumes; i++)
{
CMyComPtr<IInStream> curStream;
- if (i != 1)
+ if (i == 1)
+ curStream = inStream;
+ else
{
UString fullName = seqName.GetNextName(i);
HRESULT result = openVolumeCallback->GetStream(fullName, &curStream);
@@ -437,52 +750,59 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
if (!curStream)
break;
}
- else
- curStream = inStream;
CHeader header;
- HRESULT res = NWim::ReadHeader(curStream, header);
+ HRESULT res = NWim::ReadHeader(curStream, header, _phySize);
if (res != S_OK)
{
- if (i == 1)
- return res;
- if (res == S_FALSE)
+ 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))
+ if (_firstVolumeIndex >= 0)
+ if (!header.AreFromOnArchive(_volumes[_firstVolumeIndex].Header))
break;
if (_volumes.Size() > header.PartNumber && _volumes[header.PartNumber].Stream)
break;
- CXml xml;
+ CWimXml xml;
xml.VolIndex = header.PartNumber;
- res = _db.Open(curStream, header, xml.Data, openArchiveCallback);
+ res = _db.OpenXml(curStream, header, xml.Data);
+ if (res == S_OK)
+ {
+ if (!xml.Parse())
+ _xmlError = true;
+
+ 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)
- return res;
- if (res == S_FALSE)
+ if (i != 1 && res == S_FALSE)
continue;
return res;
}
while (_volumes.Size() <= header.PartNumber)
- _volumes.Add(CVolume());
+ _volumes.AddNew();
CVolume &volume = _volumes[header.PartNumber];
volume.Header = header;
volume.Stream = curStream;
- firstVolumeIndex = header.PartNumber;
+ _firstVolumeIndex = header.PartNumber;
- bool needAddXml = true;
- if (_xmls.Size() != 0)
- if (xml.Data == _xmls[0].Data)
- needAddXml = false;
- if (needAddXml)
+ if (_xmls.IsEmpty() || xml.Data != _xmls[0].Data)
{
- xml.Parse();
+ wchar_t sz[16];
+ ConvertUInt32ToString(xml.VolIndex, sz);
+ xml.FileName = L'[';
+ xml.FileName += sz;
+ xml.FileName += L"].xml";
_xmls.Add(xml);
}
@@ -503,14 +823,30 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
}
}
- _db.DetectPathMode();
- RINOK(_db.Sort(_db.SkipRoot));
+ RINOK(_db.FillAndCheck());
+ 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.Streams.Size(), sz);
+ ConvertUInt32ToString(_db.DataStreams.Size(), sz);
_nameLenForStreams = MyStringLen(sz);
+ */
- _xmlInComments = (_xmls.Size() == 1 && !_db.ShowImageNumber);
+ _xmlInComments = !_showImageNumber;
+ _numXmlItems = (_xmlInComments ? 0 : _xmls.Size());
+ _numIgnoreItems = _db.ThereAreDeletedStreams ? 1 : 0;
}
return S_OK;
COM_TRY_END
@@ -518,10 +854,17 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
STDMETHODIMP CHandler::Close()
{
+ _firstVolumeIndex = -1;
+ _phySize = 0;
_db.Clear();
_volumes.Clear();
_xmls.Clear();
- _nameLenForStreams = 0;
+ // _nameLenForStreams = 0;
+ _xmlInComments = false;
+ _numXmlItems = 0;
+ _numIgnoreItems = 0;
+ _xmlError = false;
+ _isArc = false;
return S_OK;
}
@@ -529,10 +872,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
- numItems = _db.SortedItems.Size() + _xmls.Size();
+ numItems = _db.SortedItems.Size() + _numXmlItems + _db.VirtualRoots.Size() + _numIgnoreItems;
if (numItems == 0)
return S_OK;
@@ -541,17 +884,21 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
for (i = 0; i < numItems; i++)
{
UInt32 index = allFilesMode ? i : indices[i];
- if (index < (UInt32)_db.SortedItems.Size())
+ if (index < _db.SortedItems.Size())
{
int streamIndex = _db.Items[_db.SortedItems[index]].StreamIndex;
if (streamIndex >= 0)
{
- const CStreamInfo &si = _db.Streams[streamIndex];
+ const CStreamInfo &si = _db.DataStreams[streamIndex];
totalSize += si.Resource.UnpackSize;
}
}
else
- totalSize += _xmls[index - (UInt32)_db.SortedItems.Size()].Data.GetCapacity();
+ {
+ index -= _db.SortedItems.Size();
+ if (index < (UInt32)_numXmlItems)
+ totalSize += _xmls[index].Data.Size();
+ }
}
RINOK(extractCallback->SetTotal(totalSize));
@@ -586,17 +933,21 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ISequentialOutStream> realOutStream;
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
- if (index >= (UInt32)_db.SortedItems.Size())
+ if (index >= _db.SortedItems.Size())
{
if (!testMode && !realOutStream)
continue;
RINOK(extractCallback->PrepareOperation(askMode));
- const CByteBuffer &data = _xmls[index - (UInt32)_db.SortedItems.Size()].Data;
- currentItemUnPacked = data.GetCapacity();
- if (realOutStream)
+ index -= _db.SortedItems.Size();
+ if (index < (UInt32)_numXmlItems)
{
- RINOK(WriteStream(realOutStream, (const Byte *)data, data.GetCapacity()));
- realOutStream.Release();
+ 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;
@@ -610,13 +961,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
continue;
RINOK(extractCallback->PrepareOperation(askMode));
realOutStream.Release();
- RINOK(extractCallback->SetOperationResult(item.HasStream() ?
- NExtract::NOperationResult::kDataError :
- NExtract::NOperationResult::kOK));
+ RINOK(extractCallback->SetOperationResult(_db.ItemHasStream(item) ?
+ NExtract::NOperationResult::kDataError :
+ NExtract::NOperationResult::kOK));
continue;
}
- const CStreamInfo &si = _db.Streams[streamIndex];
+ const CStreamInfo &si = _db.DataStreams[streamIndex];
currentItemUnPacked = si.Resource.UnpackSize;
currentItemPacked = si.Resource.PackSize;
@@ -626,7 +977,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 opRes = NExtract::NOperationResult::kOK;
if (streamIndex != prevSuccessStreamIndex || realOutStream)
{
- Byte digest[20];
+ Byte digest[kHashSize];
const CVolume &vol = _volumes[si.PartNumber];
HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header.IsLzxMode(),
realOutStream, progress, digest);
@@ -651,9 +1002,59 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
- *numItems = _db.SortedItems.Size();
- if (!_xmlInComments)
- *numItems += _xmls.Size();
+ *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 **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 aa92069a..416e11ca 100755..100644
--- a/CPP/7zip/Archive/Wim/WimHandler.h
+++ b/CPP/7zip/Archive/Wim/WimHandler.h
@@ -3,72 +3,75 @@
#ifndef __ARCHIVE_WIM_HANDLER_H
#define __ARCHIVE_WIM_HANDLER_H
-#include "Common/MyCom.h"
-#include "Common/MyXml.h"
+#include "../../../Common/MyCom.h"
#include "WimIn.h"
namespace NArchive {
namespace NWim {
-struct CVolume
-{
- CHeader Header;
- CMyComPtr<IInStream> Stream;
-};
-
-struct CImageInfo
-{
- bool CTimeDefined;
- bool MTimeDefined;
- bool NameDefined;
- // bool IndexDefined;
-
- FILETIME CTime;
- FILETIME MTime;
- UString Name;
- // UInt32 Index;
-
- CImageInfo(): CTimeDefined(false), MTimeDefined(false), NameDefined(false)
- // , IndexDefined(false)
- {}
- void Parse(const CXmlItem &item);
-};
-
-struct CXml
-{
- CByteBuffer Data;
- UInt16 VolIndex;
- CObjectVector<CImageInfo> Images;
-
- void ToUnicode(UString &s);
- void Parse();
-};
-
-
class CHandler:
public IInArchive,
+ public IArchiveGetRawProps,
+ public IArchiveGetRootProps,
+ public IArchiveKeepModeForNextOpen,
+ public ISetProperties,
+ public IOutArchive,
public CMyUnknownImp
{
CDatabase _db;
UInt32 _version;
bool _isOldVersion;
+ UInt32 _bootIndex;
+
CObjectVector<CVolume> _volumes;
- CObjectVector<CXml> _xmls;
- int _nameLenForStreams;
+ CObjectVector<CWimXml> _xmls;
+ // unsigned _nameLenForStreams;
bool _xmlInComments;
+
+ unsigned _numXmlItems;
+ unsigned _numIgnoreItems;
-public:
- MY_UNKNOWN_IMP1(IInArchive)
- INTERFACE_IInArchive(;)
-};
+ bool _xmlError;
+ bool _isArc;
-class COutHandler:
- public IOutArchive,
- public CMyUnknownImp
-{
+ 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 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:
- MY_UNKNOWN_IMP1(IOutArchive)
+ CHandler();
+ MY_UNKNOWN_IMP6(
+ IInArchive,
+ IArchiveGetRawProps,
+ IArchiveGetRootProps,
+ IArchiveKeepModeForNextOpen,
+ ISetProperties,
+ IOutArchive)
+ INTERFACE_IInArchive(;)
+ INTERFACE_IArchiveGetRawProps(;)
+ INTERFACE_IArchiveGetRootProps(;)
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps);
+ STDMETHOD(KeepModeForNextOpen)();
INTERFACE_IOutArchive(;)
};
diff --git a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
index 85f0771c..149989d1 100755..100644
--- a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
+++ b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
@@ -2,17 +2,23 @@
#include "StdAfx.h"
+// #include <stdio.h>
+
#include "../../../../C/CpuArch.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.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/Time.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/Sha1.h"
@@ -24,125 +30,218 @@ using namespace NWindows;
namespace NArchive {
namespace NWim {
+static const Int32 kNumImagesMax = (1 << 10);
+
struct CSha1Hash
{
Byte Hash[kHashSize];
};
-struct CHashList
+class CHashList
{
+ CUIntVector Sorted;
+public:
CRecordVector<CSha1Hash> Digests;
- CIntVector Sorted;
- int AddUnique(const CSha1Hash &h);
+ int AddUniq(const Byte *h);
};
-int CHashList::AddUnique(const CSha1Hash &h)
+// returns -1 : if it's new HASH
+
+int CHashList::AddUniq(const Byte *h)
{
- int left = 0, right = Sorted.Size();
+ unsigned left = 0, right = Sorted.Size();
while (left != right)
{
- int mid = (left + right) / 2;
- int index = Sorted[mid];
- UInt32 i;
+ unsigned mid = (left + right) / 2;
+ unsigned index = Sorted[mid];
const Byte *hash2 = Digests[index].Hash;
+ unsigned i;
for (i = 0; i < kHashSize; i++)
- if (h.Hash[i] != hash2[i])
+ if (h[i] != hash2[i])
break;
if (i == kHashSize)
return index;
- if (h.Hash[i] < hash2[i])
+ if (h[i] < hash2[i])
right = mid;
else
left = mid + 1;
}
- Sorted.Insert(left, Digests.Add(h));
+ CSha1Hash h2;
+ memcpy(h2.Hash, h, kHashSize);
+ Sorted.Insert(left, Digests.Add(h2));
return -1;
}
-struct CUpdateItem
+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;
- int HashIndex;
+ bool Skip;
+ unsigned NumSkipAltStreams;
+ CObjectVector<CAltStream> AltStreams;
+
+ CByteBuffer Reparse;
- CUpdateItem(): HashIndex(-1) {}
+ 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<CMetaItem> &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 Index;
- UString Name;
+ int MetaIndex;
CObjectVector<CDir> Dirs;
- CIntVector Files;
-
- CDir(): Index(-1) {}
- bool IsLeaf() const { return Index >= 0; }
- UInt64 GetNumDirs() const;
- UInt64 GetNumFiles() const;
- CDir* AddDir(CObjectVector<CUpdateItem> &items, const UString &name, int index);
+ CUIntVector Files; // indexes in MetaItems[]
+
+ CDir(): MetaIndex(-1) {}
+ unsigned GetNumDirs() const;
+ unsigned GetNumFiles() const;
+ UInt64 GetTotalSize(const CObjectVector<CMetaItem> &metaItems) const;
+ bool FindDir(const CObjectVector<CMetaItem> &items, const UString &name, unsigned &index);
};
-UInt64 CDir::GetNumDirs() const
+/* imagex counts Junctions as files (not as dirs).
+ We suppose that it's not correct */
+
+unsigned CDir::GetNumDirs() const
{
- UInt64 num = Dirs.Size();
- for (int i = 0; i < Dirs.Size(); i++)
+ unsigned num = Dirs.Size();
+ FOR_VECTOR (i, Dirs)
num += Dirs[i].GetNumDirs();
return num;
}
-UInt64 CDir::GetNumFiles() const
+unsigned CDir::GetNumFiles() const
{
- UInt64 num = Files.Size();
- for (int i = 0; i < Dirs.Size(); i++)
+ unsigned num = Files.Size();
+ FOR_VECTOR (i, Dirs)
num += Dirs[i].GetNumFiles();
return num;
}
-CDir* CDir::AddDir(CObjectVector<CUpdateItem> &items, const UString &name, int index)
+UInt64 CDir::GetTotalSize(const CObjectVector<CMetaItem> &metaItems) const
{
- int left = 0, right = Dirs.Size();
+ UInt64 sum = 0;
+ unsigned i;
+ for (i = 0; i < Files.Size(); i++)
+ sum += metaItems[Files[i]].Size;
+ for (i = 0; i < Dirs.Size(); i++)
+ sum += Dirs[i].GetTotalSize(metaItems);
+ return sum;
+}
+
+bool CDir::FindDir(const CObjectVector<CMetaItem> &items, const UString &name, unsigned &index)
+{
+ unsigned left = 0, right = Dirs.Size();
while (left != right)
{
- int mid = (left + right) / 2;
- CDir &d = Dirs[mid];
- int compare = name.CompareNoCase(d.IsLeaf() ? items[Dirs[mid].Index].Name : d.Name);
- if (compare == 0)
+ unsigned mid = (left + right) / 2;
+ int comp = CompareFileNames(name, items[Dirs[mid].MetaIndex].Name);
+ if (comp == 0)
{
- if (index >= 0)
- d.Index = index;
- return &d;
+ index = mid;
+ return true;
}
- if (compare < 0)
+ if (comp < 0)
right = mid;
else
left = mid + 1;
}
- Dirs.Insert(left, CDir());
- CDir &d = Dirs[left];
- d.Index = index;
- if (index < 0)
- d.Name = name;
- return &d;
+ index = left;
+ return false;
}
-
-STDMETHODIMP COutHandler::GetFileTimeType(UInt32 *type)
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
{
*type = NFileTimeType::kWindows;
return S_OK;
}
-static HRESULT GetTime(IArchiveUpdateCallback *callback, int index, PROPID propID, FILETIME &ft)
+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(callback->GetProperty(index, propID, &prop));
+ RINOK(GetOutProperty(callback, callbackIndex, arcIndex, propID, &prop));
if (prop.vt == VT_FILETIME)
ft = prop.filetime;
else if (prop.vt != VT_EMPTY)
@@ -150,6 +249,37 @@ static HRESULT GetTime(IArchiveUpdateCallback *callback, int index, PROPID propI
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)
@@ -217,7 +347,7 @@ STDMETHODIMP CInStreamWithSha1::Read(void *data, UInt32 size, UInt32 *processedS
HRESULT result = _stream->Read(data, size, &realProcessedSize);
_size += realProcessedSize;
_sha.Update((const Byte *)data, realProcessedSize);
- if (processedSize != NULL)
+ if (processedSize)
*processedSize = realProcessedSize;
return result;
}
@@ -228,116 +358,301 @@ static void SetFileTimeToMem(Byte *p, const FILETIME &ft)
Set32(p + 4, ft.dwHighDateTime);
}
-static size_t WriteItem(const CUpdateItem &item, Byte *p, const Byte *hash)
+static size_t WriteItem_Dummy(const CMetaItem &item)
{
- int fileNameLen = item.Name.Length() * 2;
- int fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2);
+ 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 + 6) & ~7);
- if (p)
+ size_t totalLen = ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7);
+ if (item.GetNumAltStreams() != 0)
{
- memset(p, 0, totalLen);
- Set64(p, totalLen);
- Set64(p + 8, item.Attrib);
- Set32(p + 0xC, (UInt32)(Int32)-1); // item.SecurityId
- // Set64(p + 0x10, 0); // subdirOffset
- SetFileTimeToMem(p + 0x28, item.CTime);
- SetFileTimeToMem(p + 0x30, item.ATime);
- SetFileTimeToMem(p + 0x38, item.MTime);
- if (hash)
- memcpy(p + 0x40, hash, kHashSize);
- /*
- else
- memset(p + 0x40, 0, kHashSize);
- */
- // Set16(p + 98, 0); // shortNameLen
- Set16(p + 100, (UInt16)fileNameLen);
- for (int i = 0; i * 2 < fileNameLen; i++)
- Set16(p + kDirRecordSize + i * 2, item.Name[i]);
+ 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 void WriteTree(const CDir &tree, CRecordVector<CSha1Hash> &digests,
- CUpdateItem &defaultDirItem,
- CObjectVector<CUpdateItem> &updateItems, Byte *dest, size_t &pos)
+static size_t WriteItem(const CRecordVector<CSha1Hash> &digests, const CMetaItem &item, Byte *p)
{
- int i;
- for (i = 0; i < tree.Files.Size(); i++)
+ 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)
{
- const CUpdateItem &ui = updateItems[tree.Files[i]];
- pos += WriteItem(ui, dest ? dest + pos : NULL,
- ui.HashIndex >= 0 ? digests[ui.HashIndex].Hash : NULL);
+ 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, digests[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, digests[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, digests[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;
+}
- size_t posStart = pos;
+struct CDb
+{
+ CMetaItem DefaultDirItem;
+ const CRecordVector<CSha1Hash> *Hashes;
+ CObjectVector<CMetaItem> MetaItems;
+ CRecordVector<CUpdateItem> UpdateItems;
+ CUIntVector UpdateIndexes; /* indexes in UpdateItems in order of writing data streams
+ to disk (the order of tree items). */
+
+ size_t WriteTree_Dummy(const CDir &tree) const;
+ void WriteTree(const CDir &tree, Byte *dest, size_t &pos) const;
+ void WriteOrderList(const CDir &tree);
+};
+
+size_t CDb::WriteTree_Dummy(const CDir &tree) const
+{
+ unsigned i;
+ size_t pos = 0;
+ for (i = 0; i < tree.Files.Size(); i++)
+ pos += WriteItem_Dummy(MetaItems[tree.Files[i]]);
for (i = 0; i < tree.Dirs.Size(); i++)
{
- const CDir &subfolder = tree.Dirs[i];
- CUpdateItem *item = &defaultDirItem;
- if (subfolder.IsLeaf())
- item = &updateItems[subfolder.Index];
- else
- defaultDirItem.Name = subfolder.Name;
- pos += WriteItem(*item, NULL, NULL);
+ 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);
- if (dest)
- Set64(dest + pos, 0);
+ 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 &subfolder = tree.Dirs[i];
- if (dest)
+ 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)
{
- CUpdateItem *item = &defaultDirItem;
- if (subfolder.IsLeaf())
- item = &updateItems[subfolder.Index];
- else
- defaultDirItem.Name = subfolder.Name;
- size_t len = WriteItem(*item, dest + posStart, NULL);
- Set64(dest + posStart + 0x10, pos);
- posStart += len;
+ Set64(dest + posStart - len + 0x10, pos); // subdirOffset
+ WriteTree(subDir, dest, pos);
}
- WriteTree(subfolder, digests, defaultDirItem, updateItems, dest, pos);
}
}
-static void AddTag(AString &s, const char *name, const AString &value)
+void CDb::WriteOrderList(const CDir &tree)
{
- s += "<";
+ 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 += '>';
s += value;
- s += "</";
+ s += '<';
+ s += '/';
s += name;
- s += ">";
+ s += '>';
+}
+
+static void AddTagUInt64_ToString(AString &s, const char *name, UInt64 value)
+{
+ char temp[32];
+ ConvertUInt64ToString(value, temp);
+ AddTag_ToString(s, name, temp);
}
-static void AddTagUInt64(AString &s, const char *name, UInt64 value)
+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);
- AddTag(s, name, 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 AString TimeToXml(FILETIME &ft)
+static void AddTag_String_IfEmpty(CXmlItem &parentItem, const char *name, const char *value)
{
- AString res;
- char temp[16] = { '0', 'x' };
- ConvertUInt32ToHexWithZeros(ft.dwHighDateTime, temp + 2);
- AddTag(res, "HIGHPART", temp);
- ConvertUInt32ToHexWithZeros(ft.dwLowDateTime, temp + 2);
- AddTag(res, "LOWPART", temp);
- return res;
+ 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 = kWimVersion;
- Flags = NHeaderFlags::kRpFix;
+ Flags = NHeaderFlags::kReparsePointFixup;
ChunkSize = 0;
if (useLZX)
{
@@ -355,24 +670,607 @@ void CHeader::SetDefaultFields(bool useLZX)
IntegrityResource.Clear();
}
-static HRESULT UpdateArchive(ISequentialOutStream *seqOutStream,
- CDir &rootFolder,
- CObjectVector<CUpdateItem> &updateItems,
- IArchiveUpdateCallback *callback)
+static void AddTrees(CObjectVector<CDir> &trees, CObjectVector<CMetaItem> &metaItems, const CMetaItem &ri, int curTreeIndex)
{
+ while (curTreeIndex >= (int)trees.Size())
+ trees.AddNew().Dirs.AddNew().MetaIndex = metaItems.Add(ri);
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 numItems, IArchiveUpdateCallback *callback)
+{
+ COM_TRY_BEGIN
+
+ if (ThereIsError())
+ return E_NOTIMPL;
+
+ bool isUpdate = (_volumes.Size() != 0);
+ int defaultImageIndex = _defaultImageNumber - 1;
+ bool showImageNumber;
+
+ if (isUpdate)
+ {
+ showImageNumber = _showImageNumber;
+ if (_version != kWimVersion)
+ return E_NOTIMPL;
+ if (_volumes.Size() != 2 || _volumes[0].Stream)
+ return E_NOTIMPL;
+ if (!showImageNumber)
+ defaultImageIndex = _db.IndexOfUserImage;
+ if (_db.Images.Size() > kNumImagesMax)
+ return E_NOTIMPL;
+ }
+ else
+ {
+ showImageNumber = (_set_use_ShowImageNumber && _set_showImageNumber);
+ if (!showImageNumber)
+ defaultImageIndex = 0;
+ }
+
+ if (defaultImageIndex >= kNumImagesMax)
+ return E_NOTIMPL;
+
CMyComPtr<IOutStream> outStream;
- RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));
+ RINOK(outSeqStream->QueryInterface(IID_IOutStream, (void **)&outStream));
if (!outStream)
return E_NOTIMPL;
+ if (!callback)
+ return E_FAIL;
+
+ CDb db;
+ CObjectVector<CDir> trees;
+
+ CMetaItem ri; // default DIR item
+ FILETIME ftCur;
+ NTime::GetCurUtcFileTime(ftCur);
+ ri.MTime = ri.ATime = ri.CTime = ftCur;
+ ri.Attrib = FILE_ATTRIBUTE_DIRECTORY;
+ ri.IsDir = true;
+
+
+ // ---------- Detect changed images ----------
+
+ unsigned i;
+ CBoolVector isChangedImage;
+ {
+ CUIntVector numUnchangedItemsInImage;
+ for (i = 0; i < _db.Images.Size(); i++)
+ {
+ numUnchangedItemsInImage.Add(0);
+ isChangedImage.Add(false);
+ }
+
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 indexInArchive;
+ Int32 newData, newProps;
+ RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
+ if (newProps == 0)
+ {
+ if (indexInArchive >= _db.SortedItems.Size())
+ continue;
+ const CItem &item = _db.Items[_db.SortedItems[indexInArchive]];
+ if (newData == 0)
+ {
+ if (item.ImageIndex >= 0)
+ numUnchangedItemsInImage[item.ImageIndex]++;
+ }
+ else
+ {
+ // oldProps & newData. Current version of 7-Zip doesn't use it
+ if (item.ImageIndex >= 0)
+ isChangedImage[item.ImageIndex] = true;
+ }
+ }
+ else if (!showImageNumber)
+ {
+ if (defaultImageIndex >= 0 && defaultImageIndex < (int)isChangedImage.Size())
+ isChangedImage[defaultImageIndex] = true;
+ }
+ else
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidPath, &prop));
+
+ if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ const wchar_t *path = prop.bstrVal;
+ if (!path)
+ return E_INVALIDARG;
+
+ const wchar_t *end;
+ UInt64 val = ConvertStringToUInt64(path, &end);
+ if (end == path)
+ return E_INVALIDARG;
+ if (val == 0 || val > kNumImagesMax)
+ 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 != _defaultImageNumber)
+ return E_INVALIDARG;
+ }
+ }
+
+ for (i = 0; i < _db.Images.Size(); i++)
+ if (!isChangedImage[i])
+ isChangedImage[i] = _db.GetNumUserItemsInImage(i) != numUnchangedItemsInImage[i];
+ }
+
+ if (defaultImageIndex >= 0)
+ {
+ for (i = 0; i < _db.Images.Size(); i++)
+ if ((int)i != defaultImageIndex)
+ isChangedImage[i] = false;
+ }
+
+ CMyComPtr<IArchiveGetRawProps> getRawProps;
+ callback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps);
+
+ CMyComPtr<IArchiveGetRootProps> getRootProps;
+ callback->QueryInterface(IID_IArchiveGetRootProps, (void **)&getRootProps);
+
+ CObjectVector<CUniqBlocks> secureBlocks;
+
+ if (!showImageNumber && (getRootProps || isUpdate) &&
+ (
+ defaultImageIndex >= (int)isChangedImage.Size()
+ || defaultImageIndex < 0 // test it
+ || isChangedImage[defaultImageIndex]
+ ))
+ {
+ // Fill Root Item: Metadata and security
+ CMetaItem rootItem = ri;
+ {
+ const void *data = NULL;
+ UInt32 dataSize = 0;
+ UInt32 propType = 0;
+ if (getRootProps)
+ {
+ RINOK(getRootProps->GetRootRawProp(kpidNtSecure, &data, &dataSize, &propType));
+ }
+ if (dataSize == 0 && isUpdate)
+ {
+ RINOK(GetRootRawProp(kpidNtSecure, &data, &dataSize, &propType));
+ }
+ if (dataSize != 0)
+ {
+ if (propType != NPropDataType::kRaw)
+ return E_FAIL;
+ while (defaultImageIndex >= (int)secureBlocks.Size())
+ secureBlocks.AddNew();
+ CUniqBlocks &secUniqBlocks = secureBlocks[defaultImageIndex];
+ rootItem.SecurityId = 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 (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 > kNumImagesMax)
+ 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;
+ const UString mainName = fileName.Left(colonPos);
+ unsigned indexOfDir;
+ 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 = 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;
- int i;
- for (i = 0; i < updateItems.Size(); i++)
- complexity += updateItems[i].Size;
+ unsigned numDataStreams = _db.DataStreams.Size();
+ CIntArr 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[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[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;
+ }
+ }
+
+ for (i = 0; i < _db.DataStreams.Size(); i++)
+ if (streamsRefs[i] != 0)
+ complexity += _db.DataStreams[i].Resource.PackSize;
+
RINOK(callback->SetTotal(complexity));
+
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
@@ -382,44 +1280,233 @@ static HRESULT UpdateArchive(ISequentialOutStream *seqOutStream,
complexity = 0;
- bool useCompression = false;
+ // bool useResourceCompression = false;
+ // use useResourceCompression only if CHeader::Flags compression is also set
CHeader header;
- header.SetDefaultFields(useCompression);
+ header.SetDefaultFields(false);
+
+ if (isUpdate)
+ {
+ const CHeader &srcHeader = _volumes[1].Header;
+ header.Flags = srcHeader.Flags;
+ header.ChunkSize = srcHeader.ChunkSize;
+ }
+
Byte buf[kHeaderSizeMax];
header.WriteTo(buf);
RINOK(WriteStream(outStream, buf, kHeaderSizeMax));
+ UInt64 curPos = kHeaderSizeMax;
+
+ CInStreamWithSha1 *inShaStreamSpec = new CInStreamWithSha1;
+ CMyComPtr<ISequentialInStream> inShaStream = inShaStreamSpec;
+
+ CLimitedSequentialInStream *inStreamLimitedSpec = NULL;
+ CMyComPtr<CLimitedSequentialInStream> inStreamLimited;
+ if (_volumes.Size() == 2)
+ {
+ inStreamLimitedSpec = new CLimitedSequentialInStream;
+ inStreamLimited = inStreamLimitedSpec;
+ inStreamLimitedSpec->SetStream(_volumes[1].Stream);
+ }
+
+
+ // these two lists have same sizes and same hashes in same order.
CHashList hashes;
CObjectVector<CStreamInfo> streams;
- UInt64 curPos = kHeaderSizeMax;
- UInt64 unpackTotalSize = 0;
- for (i = 0; i < updateItems.Size(); i++)
+
+ // ---------- Copy unchanged data streams ----------
+
+ for (i = 0; i < _db.DataStreams.Size(); i++)
+ {
+ if (streamsRefs[i] == 0)
+ continue;
+
+ lps->InSize = lps->OutSize = complexity;
+ RINOK(lps->SetCur());
+
+ const CStreamInfo &siOld = _db.DataStreams[i];
+ if (hashes.AddUniq(siOld.Hash) >= 0)
+ return E_FAIL; // two streams with same SHA-1
+
+ RINOK(_volumes[siOld.PartNumber].Stream->Seek(siOld.Resource.Offset, STREAM_SEEK_SET, NULL));
+ inStreamLimitedSpec->Init(siOld.Resource.PackSize);
+ RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
+ if (copyCoderSpec->TotalSize != siOld.Resource.PackSize)
+ return E_FAIL;
+
+ CStreamInfo &s = streams.AddNew();
+ s.Resource = siOld.Resource;
+ s.Resource.Offset = curPos;
+ s.PartNumber = 1;
+ s.RefCount = streamsRefs[i];
+ memcpy(s.Hash, siOld.Hash, kHashSize);
+
+ curPos += s.Resource.PackSize;
+ lps->ProgressOffset += s.Resource.PackSize;
+ }
+
+
+ // ---------- 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());
- CUpdateItem &ui = updateItems[i];
- if (ui.IsDir || ui.Size == 0)
- continue;
+ 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;
+ }
+ }
- CInStreamWithSha1 *inShaStreamSpec = new CInStreamWithSha1;
- CMyComPtr<ISequentialInStream> inShaStream = inShaStreamSpec;
+ 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];
+ // we must have written that stream already
+ int index = hashes.AddUniq(siOld.Hash);
+ if (index < 0)
+ return E_FAIL;
+ if (ui.AltStreamIndex < 0)
+ mi.HashIndex = index;
+ else
+ mi.AltStreams[ui.AltStreamIndex].HashIndex = index;
+ continue;
+ }
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+ HRESULT res = callback->GetStream(ui.CallbackIndex, &fileInStream);
+ if (res == S_FALSE)
{
- CMyComPtr<ISequentialInStream> fileInStream;
- HRESULT res = callback->GetStream(i, &fileInStream);
- if (res != S_FALSE)
+ if (ui.AltStreamIndex >= 0)
+ {
+ mi.NumSkipAltStreams++;
+ mi.AltStreams[ui.AltStreamIndex].Skip = true;
+ }
+ else
+ mi.Skip = true;
+ }
+ else
+ {
+ RINOK(res);
+
+ int miIndex = -1;
+
+ if (!fileInStream)
+ {
+ if (!mi.IsDir)
+ return E_INVALIDARG;
+ }
+ else if (ui.AltStreamIndex < 0)
+ {
+ CMyComPtr<IStreamGetProps2> getProps2;
+ fileInStream->QueryInterface(IID_IStreamGetProps2, (void **)&getProps2);
+ if (getProps2)
+ {
+ CStreamFileProps props;
+ if (getProps2->GetProps2(&props) == S_OK)
+ {
+ mi.Attrib = props.Attrib;
+ mi.Size = props.Size;
+ size = props.Size;
+ 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 (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 = hashes.AddUniq(hash);
+ if (index >= 0)
+ streams[index].RefCount++;
+ else
+ {
+ RINOK(WriteStream(outStream, (const Byte *)mi.Reparse + 8, packSize));
+ index = streams.Size();
+ CStreamInfo &s = streams.AddNew();
+ 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;
+ }
+ mi.HashIndex = index;
+ }
+ else
{
- RINOK(res);
inShaStreamSpec->SetStream(fileInStream);
fileInStream.Release();
inShaStreamSpec->Init();
UInt64 offsetBlockSize = 0;
- if (useCompression)
+ /*
+ if (useResourceCompression)
{
- for (UInt64 t = kChunkSize; t < ui.Size; t += kChunkSize)
+ for (UInt64 t = kChunkSize; t < size; t += kChunkSize)
{
Byte buf[8];
SetUi32(buf, (UInt32)t);
@@ -427,94 +1514,180 @@ static HRESULT UpdateArchive(ISequentialOutStream *seqOutStream,
offsetBlockSize += 4;
}
}
-
+ */
+
RINOK(copyCoder->Code(inShaStream, outStream, NULL, NULL, progress));
- ui.Size = copyCoderSpec->TotalSize;
-
- CSha1Hash hash;
- unpackTotalSize += ui.Size;
- UInt64 packSize = offsetBlockSize + ui.Size;
- inShaStreamSpec->Final(hash.Hash);
- int index = hashes.AddUnique(hash);
- if (index >= 0)
- {
- ui.HashIndex = index;
- streams[index].RefCount++;
- outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos);
- outStream->SetSize(curPos);
- }
- else
+ size = copyCoderSpec->TotalSize;
+
+ if (size != 0)
{
- ui.HashIndex = hashes.Digests.Size() - 1;
- CStreamInfo s;
- s.Resource.PackSize = packSize;
- s.Resource.Offset = curPos;
- s.Resource.UnpackSize = ui.Size;
- s.Resource.Flags = 0;
- if (useCompression)
+ Byte hash[kHashSize];
+ UInt64 packSize = offsetBlockSize + size;
+ inShaStreamSpec->Final(hash);
+ int index = hashes.AddUniq(hash);
+
+ if (index >= 0)
+ {
+ streams[index].RefCount++;
+ outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos);
+ outStream->SetSize(curPos);
+ }
+ else
+ {
+ index = streams.Size();
+ CStreamInfo &s = streams.AddNew();
+ 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.Hash, kHashSize);
- streams.Add(s);
- curPos += packSize;
+ */
+ s.PartNumber = 1;
+ s.RefCount = 1;
+ memcpy(s.Hash, hash, kHashSize);
+ curPos += packSize;
+ }
+
+ if (ui.AltStreamIndex < 0)
+ mi.HashIndex = index;
+ else
+ mi.AltStreams[ui.AltStreamIndex].HashIndex = index;
}
}
- fileInStream.Release();
- complexity += ui.Size;
- RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
}
+ fileInStream.Release();
+ complexity += size;
+ RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
}
- lps->InSize = lps->OutSize = complexity;
- RINOK(lps->SetCur());
- CUpdateItem ri;
- FILETIME ft;
- NTime::GetCurUtcFileTime(ft);
- ri.MTime = ri.ATime = ri.CTime = ft;
- ri.Attrib = FILE_ATTRIBUTE_DIRECTORY;
+ while (secureBlocks.Size() < numNewImages)
+ secureBlocks.AddNew();
- const UInt32 kSecuritySize = 8;
- size_t pos = kSecuritySize;
- WriteTree(rootFolder, hashes.Digests, ri, updateItems, NULL, pos);
-
- CByteBuffer meta;
- meta.SetCapacity(pos);
- // we can write 0 here only if there is no security data, imageX does it,
- // but some programs expect size = 8
- Set32((Byte *)meta, 8); // size of security data
- Set32((Byte *)meta + 4, 0); // num security entries
- pos = kSecuritySize;
- WriteTree(rootFolder, hashes.Digests, ri, updateItems, (Byte *)meta, pos);
+ // ---------- Write Images ----------
+ for (i = 0; i < numNewImages; i++)
{
- NCrypto::NSha1::CContext sha;
- sha.Init();
- sha.Update((const Byte *)meta, pos);
- CSha1Hash digest;
- sha.Final(digest.Hash);
+ 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;
+ }
- CStreamInfo s;
- s.Resource.PackSize = pos;
- s.Resource.Offset = curPos;
- s.Resource.UnpackSize = pos;
- s.Resource.Flags = NResourceFlags::kMetadata;
- s.PartNumber = 1;
- s.RefCount = 1;
- memcpy(s.Hash, digest.Hash, kHashSize);
- streams.Add(s);
- RINOK(WriteStream(outStream, (const Byte *)meta, pos));
- meta.Free();
- curPos += pos;
+ lps->ProgressOffset += s.Resource.PackSize;
+ curPos += s.Resource.PackSize;
+ // printf("\nWrite old image %x\n", i + 1);
+ continue;
+ }
+
+ const CDir &tree = trees[i];
+ const UInt32 kSecuritySize = 8;
+
+ size_t pos = kSecuritySize;
+
+ const CUniqBlocks &secUniqBlocks = secureBlocks[i];
+ const CObjectVector<CByteBuffer> &secBufs = secUniqBlocks.Bufs;
+ pos += (size_t)secUniqBlocks.GetTotalSizeInBytes();
+ pos += secBufs.Size() * 8;
+ pos = (pos + 7) & ~(size_t)7;
+
+ db.DefaultDirItem = ri;
+ pos += db.WriteTree_Dummy(tree);
+
+ CByteBuffer 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 i;
+ for (i = 0; i < secBufs.Size(); i++, pos += 8)
+ {
+ Set64(meta + pos, secBufs[i].Size());
+ }
+ for (i = 0; i < secBufs.Size(); i++)
+ {
+ const CByteBuffer &buf = secBufs[i];
+ size_t size = buf.Size();
+ 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 = &hashes.Digests;
+ db.WriteTree(tree, (Byte *)meta, pos);
+
+ {
+ NCrypto::NSha1::CContext sha;
+ sha.Init();
+ sha.Update((const Byte *)meta, pos);
+ CSha1Hash digest;
+ sha.Final(digest.Hash);
+
+ CStreamInfo s;
+ s.Resource.PackSize = pos;
+ s.Resource.Offset = curPos;
+ s.Resource.UnpackSize = pos;
+ s.Resource.Flags = NResourceFlags::kMetadata;
+ s.PartNumber = 1;
+ s.RefCount = 1;
+ memcpy(s.Hash, digest.Hash, kHashSize);
+ streams.Add(s);
+
+ 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];
@@ -524,116 +1697,70 @@ static HRESULT UpdateArchive(ISequentialOutStream *seqOutStream,
}
AString xml = "<WIM>";
- AddTagUInt64(xml, "TOTALBYTES", curPos);
- xml += "<IMAGE INDEX=\"1\"><NAME>1</NAME>";
- AddTagUInt64(xml, "DIRCOUNT", rootFolder.GetNumDirs());
- AddTagUInt64(xml, "FILECOUNT", rootFolder.GetNumFiles());
- AddTagUInt64(xml, "TOTALBYTES", unpackTotalSize);
- NTime::GetCurUtcFileTime(ft);
- AddTag(xml, "CREATIONTIME", TimeToXml(ft));
- AddTag(xml, "LASTMODIFICATIONTIME", TimeToXml(ft));
- xml += "</IMAGE></WIM>";
-
- size_t xmlSize = (xml.Length() + 1) * 2;
- meta.SetCapacity(xmlSize);
- Set16((Byte *)meta, 0xFEFF);
- for (i = 0; i < xml.Length(); i++)
- Set16((Byte *)meta + 2 + i * 2, xml[i]);
- RINOK(WriteStream(outStream, (const Byte *)meta, xmlSize));
- meta.Free();
-
- header.XmlResource.UnpackSize = header.XmlResource.PackSize = xmlSize;
- header.XmlResource.Offset = curPos;
- header.XmlResource.Flags = NResourceFlags::kMetadata;
-
- outStream->Seek(0, STREAM_SEEK_SET, NULL);
- header.WriteTo(buf);
- return WriteStream(outStream, buf, kHeaderSizeMax);
-}
-
-STDMETHODIMP COutHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
- IArchiveUpdateCallback *callback)
-{
- COM_TRY_BEGIN
- CObjectVector<CUpdateItem> updateItems;
- CDir tree;
- tree.Dirs.Add(CDir());
- CDir &rootFolder = tree.Dirs.Back();
-
- for (UInt32 i = 0; i < numItems; i++)
+ AddTagUInt64_ToString(xml, "TOTALBYTES", curPos);
+ for (i = 0; i < trees.Size(); i++)
{
- CUpdateItem ui;
- Int32 newData, newProps;
- UInt32 indexInArchive;
- if (!callback)
- return E_FAIL;
- RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
+ CDir &tree = trees[i];
+ CXmlItem item;
+ if (_xmls.Size() == 1)
{
- NCOM::CPropVariant prop;
- RINOK(callback->GetProperty(i, kpidIsDir, &prop));
- if (prop.vt == VT_EMPTY)
- ui.IsDir = false;
- else if (prop.vt != VT_BOOL)
- return E_INVALIDARG;
- else
- ui.IsDir = (prop.boolVal != VARIANT_FALSE);
- }
-
- {
- NCOM::CPropVariant prop;
- RINOK(callback->GetProperty(i, kpidAttrib, &prop));
- if (prop.vt == VT_EMPTY)
- ui.Attrib = (ui.IsDir ? FILE_ATTRIBUTE_DIRECTORY : 0);
- else if (prop.vt != VT_UI4)
- return E_INVALIDARG;
- else
- ui.Attrib = prop.ulVal;
- }
-
- RINOK(GetTime(callback, i, kpidCTime, ui.CTime));
- RINOK(GetTime(callback, i, kpidATime, ui.ATime));
- RINOK(GetTime(callback, i, kpidMTime, ui.MTime));
-
- {
- NCOM::CPropVariant prop;
- RINOK(callback->GetProperty(i, kpidSize, &prop));
- if (prop.vt != VT_UI8)
- return E_INVALIDARG;
- ui.Size = prop.uhVal.QuadPart;
+ 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];
+ }
}
-
- UString path;
- NCOM::CPropVariant prop;
- RINOK(callback->GetProperty(i, kpidPath, &prop));
- if (prop.vt == VT_BSTR)
- path = prop.bstrVal;
- else if (prop.vt != VT_EMPTY)
- return E_INVALIDARG;
-
- CDir *curItem = &rootFolder;
- int len = path.Length();
- UString fileName;
- for (int j = 0; j < len; j++)
+ if (i >= isChangedImage.Size() || isChangedImage[i])
{
- wchar_t c = path[j];
- if (c == WCHAR_PATH_SEPARATOR || c == L'/')
+ char temp[16];
+ if (item.Name.IsEmpty())
{
- curItem = curItem->AddDir(updateItems, fileName, -1);
- fileName.Empty();
+ ConvertUInt32ToString(i + 1, temp);
+ item.Name = "IMAGE";
+ item.IsTag = true;
+ CXmlProp &prop = item.Props.AddNew();
+ prop.Name = "INDEX";
+ prop.Value = temp;
}
- else
- fileName += c;
+
+ 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);
}
- ui.Name = fileName;
- updateItems.Add(ui);
- if (ui.IsDir)
- curItem->AddDir(updateItems, fileName, (int)i);
- else
- curItem->Files.Add(i);
+ item.AppendTo(xml);
}
- return UpdateArchive(outStream, tree, updateItems, callback);
+ xml += "</WIM>";
+
+ size_t xmlSize;
+ {
+ UString utf16String;
+ if (!ConvertUTF8ToUnicode(xml, utf16String))
+ return S_FALSE;
+ xmlSize = (utf16String.Len() + 1) * 2;
+
+ CByteBuffer xmlBuf(xmlSize);
+ Set16((Byte *)xmlBuf, 0xFEFF);
+ for (i = 0; i < (unsigned)utf16String.Len(); i++)
+ Set16((Byte *)xmlBuf + 2 + i * 2, utf16String[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();
+ 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 c210804d..cec037cc 100755..100644
--- a/CPP/7zip/Archive/Wim/WimIn.cpp
+++ b/CPP/7zip/Archive/Wim/WimIn.cpp
@@ -2,13 +2,17 @@
#include "StdAfx.h"
+// #include <stdio.h>
+
#include "../../../../C/CpuArch.h"
-#include "Common/IntToString.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringToInt.h"
+#include "../../../Common/UTFConvert.h"
-#include "../../Common/StreamUtils.h"
-#include "../../Common/StreamObjects.h"
#include "../../Common/LimitedStreams.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
#include "../Common/OutStreamWithSha1.h"
@@ -33,7 +37,6 @@ public:
{
if (NeedFlush)
m_Decoder->Flush();
- m_Decoder->ReleaseStreams();
}
};
@@ -44,8 +47,8 @@ HRESULT CDecoder::CodeSpec(UInt32 outSize)
for (unsigned i = 0; i < kMainTableSize; i += 2)
{
Byte b = m_InBitStream.DirectReadByte();
- levels[i] = b & 0xF;
- levels[i + 1] = b >> 4;
+ levels[i] = (Byte)(b & 0xF);
+ levels[i + 1] = (Byte)(b >> 4);
}
if (!m_MainDecoder.SetCodeLengths(levels))
return S_FALSE;
@@ -154,11 +157,7 @@ HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool l
size_t sizesBufSize = (size_t)sizesBufSize64;
if (sizesBufSize != sizesBufSize64)
return E_OUTOFMEMORY;
- if (sizesBufSize > sizesBuf.GetCapacity())
- {
- sizesBuf.Free();
- sizesBuf.SetCapacity(sizesBufSize);
- }
+ sizesBuf.AllocAtLeast(sizesBufSize);
RINOK(ReadStream_FALSE(inStream, (Byte *)sizesBuf, sizesBufSize));
const Byte *p = (const Byte *)sizesBuf;
@@ -237,8 +236,7 @@ static HRESULT UnpackData(IInStream *inStream, const CResource &resource, bool l
size_t size = (size_t)resource.UnpackSize;
if (size != resource.UnpackSize)
return E_OUTOFMEMORY;
- buf.Free();
- buf.SetCapacity(size);
+ buf.Alloc(size);
CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream();
CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
@@ -256,7 +254,7 @@ void CResource::Parse(const Byte *p)
UnpackSize = Get64(p + 16);
}
-#define GetResource(p, res) res.Parse(p)
+#define GET_RESOURCE(_p_, res) res.ParseAndUpdatePhySize(_p_, phySize)
static void GetStream(bool oldVersion, const Byte *p, CStreamInfo &s)
{
@@ -265,111 +263,151 @@ static void GetStream(bool oldVersion, const Byte *p, CStreamInfo &s)
{
s.PartNumber = 1;
s.Id = Get32(p + 24);
- s.RefCount = Get32(p + 28);
- memcpy(s.Hash, p + 32, kHashSize);
+ // printf("\n%d", s.Id);
+ p += 28;
}
else
{
s.PartNumber = Get16(p + 24);
- s.RefCount = Get32(p + 26);
- memcpy(s.Hash, p + 30, kHashSize);
+ p += 26;
}
+ s.RefCount = Get32(p);
+ memcpy(s.Hash, p + 4, kHashSize);
}
-static const wchar_t *kLongPath = L"[LongPath]";
-UString CDatabase::GetItemPath(const int index1) const
+static const char *kLongPath = "[LongPath]";
+
+void CDatabase::GetShortName(unsigned index, NWindows::NCOM::CPropVariant &name) const
{
- int size = 0;
+ 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 newLevel;
- for (newLevel = 0;; newLevel = 1)
+ unsigned newLevel;
+ int imageIndex = Items[index].ImageIndex;
+ const CImage &image = Images[imageIndex];
+ for (newLevel = 0;;)
{
const CItem &item = Items[index];
index = item.Parent;
- if (index >= 0 || !SkipRoot)
- size += item.Name.Length() + newLevel;
+ if (index >= 0 || image.NumEmptyRootItems == 0)
+ {
+ const Byte *meta = image.Meta + item.Offset;
+ meta += item.IsAltStream ?
+ (IsOldVersion ? 0x10 : 0x24) :
+ (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2);
+ size += Get16(meta) / 2;
+ size += newLevel;
+ newLevel = 1;
+ if ((UInt32)size >= ((UInt32)1 << 15))
+ {
+ path = kLongPath;
+ return;
+ }
+ }
if (index < 0)
break;
- if ((UInt32)size >= ((UInt32)1 << 16))
- return kLongPath;
}
- wchar_t temp[16];
- int imageLen = 0;
- if (ShowImageNumber)
+ if (showImageNumber)
{
- ConvertUInt32ToString(-1 - index, temp);
- imageLen = MyStringLen(temp);
- size += imageLen + 1;
+ size += image.RootName.Len();
+ size += newLevel;
}
- if ((UInt32)size >= ((UInt32)1 << 16))
- return kLongPath;
- UString path;
- wchar_t *s = path.GetBuffer(size);
+ wchar_t *s = path.AllocBstr(size);
s[size] = 0;
- if (ShowImageNumber)
+
+ if (showImageNumber)
{
- memcpy(s, temp, imageLen * sizeof(wchar_t));
- s[imageLen] = WCHAR_PATH_SEPARATOR;
+ MyStringCopy(s, (const wchar_t *)image.RootName);
+ if (newLevel)
+ s[image.RootName.Len()] = WCHAR_PATH_SEPARATOR;
}
index = index1;
-
- for (newLevel = 0;; newLevel = 1)
+ wchar_t separator = 0;
+ for (;;)
{
const CItem &item = Items[index];
index = item.Parent;
- if (index >= 0 || !SkipRoot)
+ if (index >= 0 || image.NumEmptyRootItems == 0)
{
- if (newLevel)
- s[--size] = WCHAR_PATH_SEPARATOR;
- size -= item.Name.Length();
- memcpy(s + size, item.Name, sizeof(wchar_t) * item.Name.Length());
+ if (separator)
+ s[--size] = separator;
+ const Byte *meta = image.Meta + item.Offset;
+ meta += (item.IsAltStream) ?
+ (IsOldVersion ? 0x10: 0x24) :
+ (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2);
+ UInt32 len = Get16(meta) / 2;
+ size -= len;
+ wchar_t *dest = s + size;
+ meta += 2;
+ for (UInt32 i = 0; i < len; i++)
+ dest[i] = Get16(meta + i * 2);
}
if (index < 0)
- {
- path.ReleaseBuffer();
- return path;
- }
+ return;
+ separator = item.IsAltStream ? L':' : WCHAR_PATH_SEPARATOR;
}
}
-static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
-{
- ft->dwLowDateTime = Get32(p);
- ft->dwHighDateTime = Get32(p + 4);
-}
-
-static HRESULT ReadName(const Byte *p, int size, UString &dest)
-{
- if (size == 0)
- return S_OK;
- if (Get16(p + size) != 0)
- return S_FALSE;
- wchar_t *s = dest.GetBuffer(size / 2);
- for (int i = 0; i <= size; i += 2)
- *s++ = Get16(p + i);
- dest.ReleaseBuffer();
- return S_OK;
-}
+// Root folders in OLD archives (ver = 1.10) conatin real items.
+// Root folders in NEW archives (ver > 1.11) contain only one folder with empty name.
HRESULT CDatabase::ParseDirItem(size_t pos, int parent)
{
if ((pos & 7) != 0)
return S_FALSE;
-
- int prevIndex = -1;
- for (int numItems = 0;; numItems++)
+
+ for (unsigned numItems = 0;; numItems++)
{
- if (OpenCallback)
+ if (OpenCallback && (Items.Size() & 0xFFFF) == 0)
{
UInt64 numFiles = Items.Size();
- if ((numFiles & 0x3FF) == 0)
- {
- RINOK(OpenCallback->SetCompleted(&numFiles, NULL));
- }
+ RINOK(OpenCallback->SetCompleted(&numFiles, NULL));
}
size_t rem = DirSize - pos;
if (pos < DirStartOffset || pos > DirSize || rem < 8)
@@ -379,32 +417,93 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent)
if (len == 0)
{
if (parent < 0 && numItems != 1)
- SkipRoot = false;
+ Images.Back().NumEmptyRootItems = 0;
DirProcessed += 8;
return S_OK;
}
if ((len & 7) != 0 || rem < len)
return S_FALSE;
- if (!IsOldVersion)
- if (len < 0x28)
- return S_FALSE;
DirProcessed += (size_t)len;
if (DirProcessed > DirSize)
return S_FALSE;
- int extraOffset = 0;
- if (IsOldVersion)
+
+ UInt32 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);
+ UInt32 numAltStreams = Get16(p + dirRecordSize - 6);
+ UInt32 shortNameLen = Get16(p + dirRecordSize - 4);
+ UInt32 fileNameLen = Get16(p + dirRecordSize - 2);
+ if ((shortNameLen & 1) != 0 || (fileNameLen & 1) != 0)
+ return S_FALSE;
+ UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2);
+ UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2);
+ if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) > len)
+ return S_FALSE;
+
+ p += dirRecordSize;
+
{
- if (len < 0x40 || (/* Get32(p + 12) == 0 && */ Get32(p + 0x14) != 0))
- {
- extraOffset = 0x10;
- }
+ 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;
+ }
+ 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;
}
- else if (Get64(p + 8) == 0)
- extraOffset = 0x24;
- if (extraOffset)
+
+ item.Offset = pos;
+ item.Parent = parent;
+ item.ImageIndex = Images.Size() - 1;
+ unsigned prevIndex = Items.Add(item);
+
+ pos += (size_t)len;
+
+ for (UInt32 i = 0; i < numAltStreams; i++)
{
- if (prevIndex == -1)
+ 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)
+ return S_FALSE;
+ if ((len & 7) != 0 || rem < len)
+ return S_FALSE;
+ if (IsOldVersion)
+ {
+ if (len < 0x18)
+ return S_FALSE;
+ }
+ else
+ if (len < 0x28)
+ return S_FALSE;
+ DirProcessed += (size_t)len;
+ if (DirProcessed > DirSize)
+ return S_FALSE;
+
+ unsigned extraOffset = 0;
+ if (IsOldVersion)
+ extraOffset = 0x10;
+ else
+ {
+ if (Get64(p + 8) != 0)
+ return S_FALSE;
+ extraOffset = 0x24;
+ }
UInt32 fileNameLen = Get16(p + extraOffset);
if ((fileNameLen & 1) != 0)
return S_FALSE;
@@ -414,188 +513,137 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent)
if (((extraOffset + 2 + fileNameLen2 + 6) & ~7) > len)
return S_FALSE;
- UString name;
- RINOK(ReadName(p + extraOffset + 2, fileNameLen, name));
+ {
+ const Byte *p2 = p + extraOffset + 2;
+ if (*(const UInt16 *)(p2 + fileNameLen) != 0)
+ return S_FALSE;
+ for (UInt32 j = 0; j < fileNameLen; j += 2)
+ if (*(const UInt16 *)(p2 + j) == 0)
+ return S_FALSE;
+ }
- CItem &prevItem = Items[prevIndex];
- if (name.IsEmpty() && !prevItem.HasStream())
+ if (fileNameLen == 0)
{
+ Byte *prevMeta = DirData + item.Offset;
if (IsOldVersion)
- prevItem.Id = Get32(p + 8);
+ memcpy(prevMeta + 0x10, p + 8, 4); // It's 32-bit Id
else
- memcpy(prevItem.Hash, p + 0x10, kHashSize);
+ memcpy(prevMeta + 0x40, p + 0x10, kHashSize);
}
else
{
- CItem item;
- item.Name = prevItem.Name + L':' + name;
- item.CTime = prevItem.CTime;
- item.ATime = prevItem.ATime;
- item.MTime = prevItem.MTime;
- if (IsOldVersion)
- {
- item.Id = Get32(p + 8);
- memset(item.Hash, 0, kHashSize);
- }
- else
- memcpy(item.Hash, p + 0x10, kHashSize);
- item.Attrib = 0;
- item.Order = Order++;
- item.Parent = parent;
- Items.Add(item);
+ ThereAreAltStreams = true;
+ CItem item2;
+ item2.Offset = pos;
+ item2.IsAltStream = true;
+ item2.Parent = prevIndex;
+ item2.ImageIndex = Images.Size() - 1;
+ Items.Add(item2);
}
pos += (size_t)len;
- continue;
}
- UInt32 dirRecordSize = IsOldVersion ? kDirRecordSizeOld : kDirRecordSize;
- if (len < dirRecordSize)
- return S_FALSE;
-
- CItem item;
- item.Attrib = Get32(p + 8);
- // item.SecurityId = Get32(p + 0xC);
- UInt64 subdirOffset = Get64(p + 0x10);
- UInt32 timeOffset = IsOldVersion ? 0x18: 0x28;
- GetFileTimeFromMem(p + timeOffset, &item.CTime);
- GetFileTimeFromMem(p + timeOffset + 8, &item.ATime);
- GetFileTimeFromMem(p + timeOffset + 16, &item.MTime);
- if (IsOldVersion)
- {
- item.Id = Get32(p + 0x10);
- memset(item.Hash, 0, kHashSize);
- }
- else
- {
- memcpy(item.Hash, p + 0x40, kHashSize);
- }
- // UInt32 numStreams = Get16(p + dirRecordSize - 6);
- UInt32 shortNameLen = Get16(p + dirRecordSize - 4);
- UInt32 fileNameLen = Get16(p + dirRecordSize - 2);
-
- if ((shortNameLen & 1) != 0 || (fileNameLen & 1) != 0)
- return S_FALSE;
-
- UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2);
- UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2);
-
- if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) > len)
- return S_FALSE;
- p += dirRecordSize;
-
- RINOK(ReadName(p, fileNameLen, item.Name));
- RINOK(ReadName(p + fileNameLen2, shortNameLen, item.ShortName));
-
- if (parent < 0 && (shortNameLen || fileNameLen || !item.IsDir()))
- SkipRoot = false;
-
- /*
- // there are some extra data for some files.
- p -= dirRecordSize;
- p += ((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7);
- if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) != len)
- p = p;
- */
-
- /*
- if (parent >= 0)
+ if (parent < 0 && numItems == 0 && shortNameLen == 0 && fileNameLen == 0 && item.IsDir)
{
- UString s = GetItemPath(parent) + L"\\" + item.Name;
- printf("\n%s %8x %S", item.IsDir() ? "D" : " ", (int)subdirOffset, (const wchar_t *)s);
+ CImage &image = Images.Back();
+ image.NumEmptyRootItems = Items.Size() - image.StartItem;
}
- */
-
- if (fileNameLen == 0 && item.IsDir() && !item.HasStream())
- item.Attrib = 0x10; // some swm archives have system/hidden attributes for root
- item.Parent = parent;
- prevIndex = Items.Add(item);
- if (item.IsDir() && subdirOffset != 0)
+ if (item.IsDir && subdirOffset != 0)
{
RINOK(ParseDirItem((size_t)subdirOffset, prevIndex));
}
- Items[prevIndex].Order = Order++;
- pos += (size_t)len;
}
}
-HRESULT CDatabase::ParseImageDirs(const CByteBuffer &buf, int parent)
+HRESULT CDatabase::ParseImageDirs(CByteBuffer &buf, int parent)
{
DirData = buf;
- DirSize = buf.GetCapacity();
-
- size_t pos = 0;
+ DirSize = buf.Size();
if (DirSize < 8)
return S_FALSE;
const Byte *p = DirData;
- UInt32 totalLength = Get32(p);
+ size_t pos = 0;
+ CImage &image = Images.Back();
+
if (IsOldVersion)
{
- for (pos = 4;; pos += 8)
+ // there is no specification about that code
+ UInt32 sum = 0;
+ image.SecurOffsets.Add(0);
+ for (;;)
{
- if (pos + 4 > DirSize)
- return S_FALSE;
- UInt32 n = Get32(p + pos);
- if (n == 0)
- break;
if (pos + 8 > DirSize)
return S_FALSE;
- totalLength += Get32(p + pos + 4);
- if (totalLength > DirSize)
+ UInt32 len = Get32(p + pos);
+ if (len > DirSize - sum)
return S_FALSE;
+ sum += len;
+ image.SecurOffsets.Add(sum);
+ UInt32 n = Get32(p + pos + 4); // what does this field mean?
+ pos += 8;
+ if (n == 0)
+ break;
}
- pos += totalLength + 4;
- pos = (pos + 7) & ~(size_t)7;
- if (pos > DirSize)
+ if (sum > DirSize - pos)
return S_FALSE;
+ FOR_VECTOR (i, image.SecurOffsets)
+ image.SecurOffsets[i] += (UInt32)pos;
+ pos += sum;
+ pos = (pos + 7) & ~(size_t)7;
}
else
{
-
- // UInt32 numEntries = Get32(p + 4);
- pos += 8;
- {
- /*
- CRecordVector<UInt64> entryLens;
- UInt64 sum = 0;
- for (UInt32 i = 0; i < numEntries; i++)
+ UInt32 totalLen = Get32(p);
+ if (totalLen == 0)
+ pos = 8;
+ else
{
- if (pos + 8 > DirSize)
+ if (totalLen < 8)
return S_FALSE;
- UInt64 len = Get64(p + pos);
- entryLens.Add(len);
- sum += len;
- pos += 8;
- }
- pos += (size_t)sum; // skip security descriptors
- while ((pos & 7) != 0)
- pos++;
- if (pos != totalLength)
- return S_FALSE;
- */
- if (totalLength == 0)
+ UInt32 numEntries = Get32(p + 4);
pos = 8;
- else if (totalLength < 8)
- return S_FALSE;
- else
- pos = totalLength;
- }
+ 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
- reference to that folder is empty */
- if (DirProcessed == DirSize - 8 && DirProcessed - DirStartOffset == 112 &&
- Get64(p + DirSize - 8) == 0)
+ /* 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;
return S_FALSE;
}
-HRESULT CHeader::Parse(const Byte *p)
+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())
@@ -603,7 +651,7 @@ HRESULT CHeader::Parse(const Byte *p)
ChunkSize = Get32(p + 0x14);
if (ChunkSize != kChunkSize && ChunkSize != 0)
return S_FALSE;
- int offset;
+ unsigned offset;
if (IsOldVersion())
{
if (headerSize != 0x60)
@@ -627,124 +675,190 @@ HRESULT CHeader::Parse(const Byte *p)
offset += 4;
}
}
- GetResource(p + offset, OffsetResource);
- GetResource(p + offset + 0x18, XmlResource);
- GetResource(p + offset + 0x30, MetadataResource);
+ GET_RESOURCE(p + offset , OffsetResource);
+ GET_RESOURCE(p + offset + 0x18, XmlResource);
+ GET_RESOURCE(p + offset + 0x30, MetadataResource);
+ BootIndex = 0;
if (IsNewVersion())
{
if (headerSize < 0xD0)
return S_FALSE;
- BootIndex = Get32(p + 0x48);
- IntegrityResource.Parse(p + offset + 0x4C);
+ 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)
+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);
+ return h.Parse(p, phySize);
}
-static HRESULT ReadStreams(bool oldVersion, IInStream *inStream, const CHeader &h, CDatabase &db)
+static HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db)
{
CByteBuffer offsetBuf;
RINOK(UnpackData(inStream, h.OffsetResource, h.IsLzxMode(), offsetBuf, NULL));
size_t i;
- size_t streamInfoSize = oldVersion ? kStreamInfoSize + 2 : kStreamInfoSize;
- for (i = 0; offsetBuf.GetCapacity() - i >= streamInfoSize; i += streamInfoSize)
+ size_t streamInfoSize = h.IsOldVersion() ? kStreamInfoSize + 2 : kStreamInfoSize;
+ for (i = 0; offsetBuf.Size() - i >= streamInfoSize; i += streamInfoSize)
{
CStreamInfo s;
- GetStream(oldVersion, (const Byte *)offsetBuf + i, s);
+ GetStream(h.IsOldVersion(), (const Byte *)offsetBuf + i, s);
if (s.PartNumber == h.PartNumber)
- db.Streams.Add(s);
+ {
+ if (s.Resource.IsMetadata())
+ {
+ if (s.RefCount == 0)
+ return S_FALSE;
+ if (s.RefCount > 1)
+ {
+ s.RefCount--;
+ db.DataStreams.Add(s);
+ }
+ s.RefCount = 1;
+ db.MetaStreams.Add(s);
+ }
+ else
+ db.DataStreams.Add(s);
+ }
}
- return (i == offsetBuf.GetCapacity()) ? S_OK : S_FALSE;
+ return (i == offsetBuf.Size()) ? S_OK : S_FALSE;
}
static bool IsEmptySha(const Byte *data)
{
- for (int i = 0; i < kHashSize; i++)
+ for (unsigned i = 0; i < kHashSize; i++)
if (data[i] != 0)
return false;
return true;
}
-HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback)
+HRESULT CDatabase::OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml)
+{
+ return UnpackData(inStream, h.XmlResource, h.IsLzxMode(), 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();
- RINOK(UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL));
- RINOK(ReadStreams(h.IsOldVersion(), inStream, h, *this));
+ RINOK(ReadStreams(inStream, h, *this));
+
+ // printf("\nh.PartNumber = %02d", (unsigned)h.PartNumber);
bool needBootMetadata = !h.MetadataResource.IsEmpty();
- Order = 0;
- if (h.PartNumber == 1)
+
+ FOR_VECTOR (i, MetaStreams)
{
- int imageIndex = 1;
- for (int i = 0; i < Streams.Size(); i++)
+ const CStreamInfo &si = MetaStreams[i];
+ /*
+ printf("\ni = %5d"
+ " Refs = %3d"
+ " Part = %1d"
+ " Offs = %7X"
+ " PackSize = %7X"
+ " Size = %7X"
+ " Flags = %d "
+ ,
+ i,
+ si.RefCount,
+ (unsigned)si.PartNumber,
+ (unsigned)si.Resource.Offset,
+ (unsigned)si.Resource.PackSize,
+ (unsigned)si.Resource.UnpackSize,
+ (unsigned)si.Resource.Flags
+ );
+ for (unsigned y = 0; y < 2; y++)
+ printf("%02X", (unsigned)si.Hash[y]);
+ */
+
+ if (h.PartNumber != 1 || si.PartNumber != h.PartNumber)
+ continue;
+
+ Byte hash[kHashSize];
+ CImage &image = Images.AddNew();
+ SetRootNames(image, Images.Size());
+ CByteBuffer &metadata = image.Meta;
+ RINOK(UnpackData(inStream, si.Resource, h.IsLzxMode(), 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)
{
- // if (imageIndex > 1) break;
- const CStreamInfo &si = Streams[i];
- if (!si.Resource.IsMetadata() || si.PartNumber != h.PartNumber)
- continue;
- Byte hash[kHashSize];
- CByteBuffer metadata;
- RINOK(UnpackData(inStream, si.Resource, h.IsLzxMode(), metadata, hash));
- if (memcmp(hash, si.Hash, kHashSize) != 0 &&
- !(h.IsOldVersion() && IsEmptySha(si.Hash)))
- return S_FALSE;
- NumImages++;
- RINOK(ParseImageDirs(metadata, -(int)(++imageIndex)));
- if (needBootMetadata)
- if (h.MetadataResource.Offset == si.Resource.Offset)
- needBootMetadata = false;
+ bool sameRes = (h.MetadataResource.Offset == si.Resource.Offset);
+ if (sameRes)
+ needBootMetadata = false;
+ bool isBootIndex = (h.BootIndex == (UInt32)Images.Size());
+ if (h.IsNewVersion())
+ {
+ if (sameRes && !isBootIndex)
+ return S_FALSE;
+ if (isBootIndex && !sameRes)
+ return S_FALSE;
+ }
}
}
if (needBootMetadata)
- {
- CByteBuffer metadata;
- RINOK(UnpackData(inStream, h.MetadataResource, h.IsLzxMode(), metadata, NULL));
- RINOK(ParseImageDirs(metadata, -1));
- NumImages++;
- }
+ return S_FALSE;
return S_OK;
}
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, void * /* param */)
{
- int res = MyCompare(p1->PartNumber, p2->PartNumber);
- if (res != 0)
- return res;
- return MyCompare(p1->Resource.Offset, p2->Resource.Offset);
+ 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 int *p1, const int *p2, void *param)
+static int CompareIDs(const unsigned *p1, const unsigned *p2, void *param)
{
const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param;
return MyCompare(streams[*p1].Id, streams[*p2].Id);
}
-static int CompareHashRefs(const int *p1, const int *p2, void *param)
+static int CompareHashRefs(const unsigned *p1, const unsigned *p2, void *param)
{
const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param;
return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize);
}
static int FindId(const CRecordVector<CStreamInfo> &streams,
- const CIntVector &sortedByHash, UInt32 id)
+ const CUIntVector &sortedByHash, UInt32 id)
{
- int left = 0, right = streams.Size();
+ unsigned left = 0, right = streams.Size();
while (left != right)
{
- int mid = (left + right) / 2;
- int streamIndex = sortedByHash[mid];
+ unsigned mid = (left + right) / 2;
+ unsigned streamIndex = sortedByHash[mid];
UInt32 id2 = streams[streamIndex].Id;
if (id == id2)
return streamIndex;
@@ -757,15 +871,15 @@ static int FindId(const CRecordVector<CStreamInfo> &streams,
}
static int FindHash(const CRecordVector<CStreamInfo> &streams,
- const CIntVector &sortedByHash, const Byte *hash)
+ const CUIntVector &sortedByHash, const Byte *hash)
{
- int left = 0, right = streams.Size();
+ unsigned left = 0, right = streams.Size();
while (left != right)
{
- int mid = (left + right) / 2;
- int streamIndex = sortedByHash[mid];
- UInt32 i;
+ unsigned mid = (left + right) / 2;
+ unsigned streamIndex = sortedByHash[mid];
const Byte *hash2 = streams[streamIndex].Hash;
+ unsigned i;
for (i = 0; i < kHashSize; i++)
if (hash[i] != hash2[i])
break;
@@ -779,77 +893,424 @@ static int FindHash(const CRecordVector<CStreamInfo> &streams,
return -1;
}
-static int CompareItems(const int *a1, const int *a2, void *param)
+bool CDatabase::ItemHasStream(const CItem &item) const
{
- const CObjectVector<CItem> &items = ((CDatabase *)param)->Items;
+ 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);
+ for (unsigned i = 0; i < kHashSize; i++)
+ if (meta[i] != 0)
+ return true;
+ return false;
+}
+
+static int CompareItems(const unsigned *a1, const unsigned *a2, void *param)
+{
+ const CRecordVector<CItem> &items = ((CDatabase *)param)->Items;
const CItem &i1 = items[*a1];
const CItem &i2 = items[*a2];
- if (i1.IsDir() != i2.IsDir())
- return i1.IsDir() ? 1 : -1;
- int res = MyCompare(i1.StreamIndex, i2.StreamIndex);
- if (res != 0)
- return res;
- return MyCompare(i1.Order, i2.Order);
+ 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::Sort(bool skipRootDir)
+HRESULT CDatabase::FillAndCheck()
{
- Streams.Sort(CompareStreamsByPos, NULL);
-
{
- CIntVector sortedByHash;
+ 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;
+ }
+ }
+
+ {
+ CUIntVector sortedByHash;
{
- for (int i = 0; i < Streams.Size(); i++)
- sortedByHash.Add(i);
+ unsigned num = DataStreams.Size();
+ sortedByHash.ClearAndSetSize(num);
+ unsigned *vals = &sortedByHash[0];
+ for (unsigned i = 0; i < num; i++)
+ vals[i] = i;
if (IsOldVersion)
- sortedByHash.Sort(CompareIDs, &Streams);
+ sortedByHash.Sort(CompareIDs, &DataStreams);
else
- sortedByHash.Sort(CompareHashRefs, &Streams);
+ sortedByHash.Sort(CompareHashRefs, &DataStreams);
}
- for (int i = 0; i < Items.Size(); i++)
+ FOR_VECTOR (i, Items)
{
CItem &item = Items[i];
item.StreamIndex = -1;
- if (item.HasStream())
- if (IsOldVersion)
- item.StreamIndex = FindId(Streams, sortedByHash, item.Id);
- else
- item.StreamIndex = FindHash(Streams, sortedByHash, item.Hash);
+ 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, sortedByHash, id);
+ }
+ }
+ /*
+ else if (item.IsDir)
+ {
+ // reparse points can have dirs some dir
+ }
+ */
+ else
+ {
+ hash += (item.IsAltStream ? 0x10 : 0x40);
+ unsigned hi;
+ for (hi = 0; hi < kHashSize; hi++)
+ if (hash[hi] != 0)
+ break;
+ if (hi != kHashSize)
+ {
+ item.StreamIndex = FindHash(DataStreams, sortedByHash, hash);
+ }
+ }
}
}
-
{
- CRecordVector<bool> used;
- int i;
- for (i = 0; i < Streams.Size(); i++)
+ CUIntVector refCounts;
+ refCounts.ClearAndSetSize(DataStreams.Size());
+ unsigned i;
+
+ for (i = 0; i < DataStreams.Size(); i++)
{
- const CStreamInfo &s = Streams[i];
- used.Add(s.Resource.IsMetadata() && s.PartNumber == 1);
- // used.Add(false);
+ 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++)
{
- CItem &item = Items[i];
- if (item.StreamIndex >= 0)
- used[item.StreamIndex] = true;
+ int streamIndex = Items[i].StreamIndex;
+ if (streamIndex >= 0)
+ refCounts[streamIndex]++;
}
- for (i = 0; i < Streams.Size(); i++)
- if (!used[i])
+
+ for (i = 0; i < DataStreams.Size(); i++)
+ {
+ const CStreamInfo &s = DataStreams[i];
+ if (s.RefCount != refCounts[i])
+ {
+ /*
+ printf("\ni = %5d si.Refcount = %d realRefs = %d size = %6d offset = %6x id = %4d ",
+ i, s.RefCount, refCounts[i], (unsigned)s.Resource.UnpackSize, (unsigned)s.Resource.Offset, s.Id);
+ */
+ // return S_FALSE;
+ RefCountError = true;
+ }
+ if (refCounts[i] == 0)
{
CItem item;
+ item.Offset = 0;
item.StreamIndex = i;
- item.HasMetadata = false;
+ item.ImageIndex = -1;
+ ThereAreDeletedStreams = true;
Items.Add(item);
}
+ }
}
+ return S_OK;
+}
+
+HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber)
+{
+ SortedItems.Clear();
+ VirtualRoots.Clear();
+ IndexOfUserImage = imageIndex;
+ NumExludededItems = 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)
+ NumExludededItems = image.NumEmptyRootItems;
+ }
+ }
+ else if ((unsigned)imageIndex < Images.Size())
+ {
+ const CImage &image = Images[imageIndex];
+ startItem = image.StartItem;
+ endItem = startItem + image.NumItems;
+ if (!showImageNumber)
+ NumExludededItems = image.NumEmptyRootItems;
+ }
+ if (NumExludededItems != 0)
+ {
+ ExludedItem = startItem;
+ startItem += NumExludededItems;
+ }
+
+ unsigned num = endItem - startItem;
+ SortedItems.ClearAndSetSize(num);
+ unsigned i;
+ for (i = 0; i < num; i++)
+ SortedItems[i] = startItem + i;
- SortedItems.Reserve(Items.Size());
- for (int i = (skipRootDir ? 1 : 0); i < Items.Size(); i++)
- SortedItems.Add(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<CVolume> &volumes, IArchiveOpenCallback *openCallback)
+{
+ ItemToReparse.Clear();
+ ReparseItems.Clear();
+
+ // we don't know about Reparse field for OLD WIM format
+ if (IsOldVersion)
+ return S_OK;
+
+ CIntVector streamToReparse;
+
+ FOR_VECTOR(i, Items)
+ {
+ // maybe it's better to use sorted items for faster access?
+ const CItem &item = Items[i];
+
+ 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 && (i & 0xFFFF) == 0)
+ {
+ UInt64 numFiles = Items.Size();
+ RINOK(openCallback->SetCompleted(&numFiles, NULL));
+ }
+
+ if (reparseIndex >= 0)
+ {
+ const CByteBuffer &reparse = ReparseItems[reparseIndex];
+ if (tag == Get32(reparse))
+ {
+ ItemToReparse[i] = 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 = UnpackData(vol.Stream, si.Resource, vol.Header.IsLzxMode(), 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());
+ memcpy(dest + 8, buf, buf.Size());
+ ItemToReparse[i] = 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.GetBuffer((unsigned)size / 2);
+ for (size_t i = 2; i < size; i += 2)
+ *chars++ = (wchar_t)Get16(p + i);
+ *chars = 0;
+ s.ReleaseBuffer();
+}
+
+bool CWimXml::Parse()
+{
+ UString s;
+ ToUnicode(s);
+ AString utf;
+ if (!ConvertUnicodeToUTF8(s, utf))
+ return false;
+ 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 || imageInfo.Index != (UInt32)Images.Size() + 1)
+ return false;
+ imageInfo.ItemIndexInXml = i;
+ Images.Add(imageInfo);
+ }
+ }
+ return true;
+}
+
}}
diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h
index da3e28a5..4b7c6d95 100755..100644
--- a/CPP/7zip/Archive/Wim/WimIn.h
+++ b/CPP/7zip/Archive/Wim/WimIn.h
@@ -3,8 +3,10 @@
#ifndef __ARCHIVE_WIM_IN_H
#define __ARCHIVE_WIM_IN_H
-#include "Common/Buffer.h"
-#include "Common/MyString.h"
+#include "../../../Common/MyBuffer.h"
+#include "../../../Common/MyXml.h"
+
+#include "../../../Windows/PropVariant.h"
#include "../../Compress/CopyCoder.h"
#include "../../Compress/LzxDecoder.h"
@@ -14,6 +16,104 @@
namespace NArchive {
namespace NWim {
+const UInt32 kDirRecordSizeOld = 62;
+const UInt32 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 NXpress {
class CBitStream
@@ -24,7 +124,6 @@ class CBitStream
public:
bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
void SetStream(ISequentialInStream *s) { m_Stream.SetStream(s); }
- void ReleaseStream() { m_Stream.ReleaseStream(); }
void Init() { m_Stream.Init(); m_BitPos = 0; }
// UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - m_BitPos / 8; }
@@ -74,11 +173,6 @@ class CDecoder
HRESULT CodeSpec(UInt32 size);
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize);
public:
- void ReleaseStreams()
- {
- m_OutWindowStream.ReleaseStream();
- m_InBitStream.ReleaseStream();
- }
HRESULT Flush() { return m_OutWindowStream.Flush(); }
HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize);
};
@@ -90,7 +184,7 @@ namespace NResourceFlags
const Byte kFree = 1;
const Byte kMetadata = 2;
const Byte Compressed = 4;
- const Byte Spanned = 4;
+ // const Byte Spanned = 4;
}
struct CResource
@@ -107,7 +201,16 @@ struct CResource
UnpackSize = 0;
Flags = 0;
}
+ 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 IsFree() const { return (Flags & NResourceFlags::kFree) != 0; }
bool IsMetadata() const { return (Flags & NResourceFlags::kMetadata) != 0; }
@@ -117,16 +220,21 @@ struct CResource
namespace NHeaderFlags
{
- const UInt32 kCompression = 2;
- const UInt32 kSpanned = 8;
- const UInt32 kRpFix = 0x80;
- const UInt32 kXPRESS = 0x20000;
- const UInt32 kLZX = 0x40000;
+ const UInt32 kCompression = 2;
+ const UInt32 kReadOnly = 4;
+ const UInt32 kSpanned = 8;
+ const UInt32 kResourceOnly = 0x10;
+ const UInt32 kMetadataOnly = 0x20;
+ const UInt32 kWriteInProgress = 0x40;
+ const UInt32 kReparsePointFixup = 0x80;
+ const UInt32 kXPRESS = 0x20000;
+ const UInt32 kLZX = 0x40000;
}
const UInt32 kWimVersion = 0x010D00;
-const UInt32 kHeaderSizeMax = 0xD0;
-const UInt32 kSignatureSize = 8;
+
+const unsigned kHeaderSizeMax = 0xD0;
+const unsigned kSignatureSize = 8;
extern const Byte kSignature[kSignatureSize];
const unsigned kChunkSizeBits = 15;
const UInt32 kChunkSize = (1 << kChunkSizeBits);
@@ -150,7 +258,7 @@ struct CHeader
void SetDefaultFields(bool useLZX);
void WriteTo(Byte *p) const;
- HRESULT Parse(const Byte *p);
+ 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 ) ; }
bool IsLzxMode() const { return (Flags & NHeaderFlags::kLZX) != 0; }
@@ -164,115 +272,217 @@ struct CHeader
}
};
-const UInt32 kHashSize = 20;
-const UInt32 kStreamInfoSize = 24 + 2 + 4 + kHashSize;
+const unsigned kHashSize = 20;
+const unsigned kStreamInfoSize = 24 + 2 + 4 + kHashSize;
struct CStreamInfo
{
CResource Resource;
- UInt16 PartNumber;
+ UInt16 PartNumber; // for NEW WIM format, we set it to 1 for OLD WIM format
UInt32 RefCount;
- UInt32 Id;
- BYTE Hash[kHashSize];
+ UInt32 Id; // for OLD WIM format
+ Byte Hash[kHashSize];
void WriteTo(Byte *p) const;
};
-const UInt32 kDirRecordSizeOld = 62;
-const UInt32 kDirRecordSize = 102;
-
struct CItem
{
- UString Name;
- UString ShortName;
- UInt32 Attrib;
- // UInt32 SecurityId;
- BYTE Hash[kHashSize];
- UInt32 Id;
- FILETIME CTime;
- FILETIME ATime;
- FILETIME MTime;
- // UInt32 ReparseTag;
- // UInt64 HardLink;
- // UInt16 NumStreams;
+ size_t Offset;
+ int IndexInSorted;
int StreamIndex;
int Parent;
- unsigned Order;
- bool HasMetadata;
- CItem(): HasMetadata(true), StreamIndex(-1), Id(0) {}
- bool IsDir() const { return HasMetadata && ((Attrib & 0x10) != 0); }
- bool HasStream() const
+ int ImageIndex; // -1 means that file is unreferenced in Images (deleted item?)
+ bool IsDir;
+ bool IsAltStream;
+
+ bool HasMetadata() const { return ImageIndex >= 0; }
+
+ CItem():
+ IndexInSorted(-1),
+ StreamIndex(-1),
+ Parent(-1),
+ IsDir(false),
+ IsAltStream(false)
+ {}
+};
+
+struct CImage
+{
+ CByteBuffer Meta;
+ CRecordVector<UInt32> SecurOffsets;
+ unsigned StartItem;
+ unsigned NumItems;
+ unsigned NumEmptyRootItems;
+ int VirtualRootIndex; // index in CDatabase::VirtualRoots[]
+ UString RootName;
+ CByteBuffer RootNameBuf;
+
+ CImage(): VirtualRootIndex(-1) {}
+};
+
+struct CImageInfo
+{
+ bool CTimeDefined;
+ bool MTimeDefined;
+ bool NameDefined;
+ bool IndexDefined;
+
+ FILETIME CTime;
+ FILETIME MTime;
+ UString Name;
+
+ UInt64 DirCount;
+ UInt64 FileCount;
+ UInt32 Index;
+
+ int ItemIndexInXml;
+
+ UInt64 GetTotalFilesAndDirs() const { return DirCount + FileCount; }
+
+ CImageInfo(): CTimeDefined(false), MTimeDefined(false), NameDefined(false),
+ IndexDefined(false), ItemIndexInXml(-1) {}
+ void Parse(const CXmlItem &item);
+};
+
+struct CWimXml
+{
+ CByteBuffer Data;
+ CXml Xml;
+
+ UInt16 VolIndex;
+ CObjectVector<CImageInfo> Images;
+
+ UString FileName;
+
+ UInt64 GetTotalFilesAndDirs() const
{
- for (unsigned i = 0; i < kHashSize; i++)
- if (Hash[i] != 0)
- return true;
- return Id != 0;
+ UInt64 sum = 0;
+ FOR_VECTOR (i, Images)
+ sum += Images[i].GetTotalFilesAndDirs();
+ return sum;
}
+
+ void ToUnicode(UString &s);
+ bool Parse();
+};
+
+struct CVolume
+{
+ CHeader Header;
+ CMyComPtr<IInStream> Stream;
};
class CDatabase
{
- const Byte *DirData;
+ Byte *DirData;
size_t DirSize;
size_t DirProcessed;
size_t DirStartOffset;
- int Order;
IArchiveOpenCallback *OpenCallback;
-
+
HRESULT ParseDirItem(size_t pos, int parent);
- HRESULT ParseImageDirs(const CByteBuffer &buf, int parent);
+ HRESULT ParseImageDirs(CByteBuffer &buf, int parent);
public:
- CRecordVector<CStreamInfo> Streams;
- CObjectVector<CItem> Items;
- CIntVector SortedItems;
- int NumImages;
- bool SkipRoot;
- bool ShowImageNumber;
+ CRecordVector<CStreamInfo> DataStreams;
+
+ CRecordVector<CStreamInfo> MetaStreams;
+
+ CRecordVector<CItem> Items;
+ CObjectVector<CByteBuffer> ReparseItems;
+ CIntVector ItemToReparse; // from index_in_Items to index_in_ReparseItems
+ // -1 means no reparse;
+
+ CObjectVector<CImage> Images;
+
bool IsOldVersion;
+ bool ThereAreDeletedStreams;
+ bool ThereAreAltStreams;
+ bool RefCountError;
+
+ // 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 NumExludededItems;
+ 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; }
+
+ unsigned GetNumUserItemsInImage(unsigned imageIndex) const
+ {
+ if (IndexOfUserImage >= 0 && imageIndex != (unsigned)IndexOfUserImage)
+ return 0;
+ if (imageIndex >= Images.Size())
+ return 0;
+ return Images[imageIndex].NumItems - NumExludededItems;
+ }
+
+ bool ItemHasStream(const CItem &item) const;
UInt64 GetUnpackSize() const
{
UInt64 res = 0;
- for (int i = 0; i < Streams.Size(); i++)
- res += Streams[i].Resource.UnpackSize;
+ FOR_VECTOR (i, DataStreams)
+ res += DataStreams[i].Resource.UnpackSize;
return res;
}
UInt64 GetPackSize() const
{
UInt64 res = 0;
- for (int i = 0; i < Streams.Size(); i++)
- res += Streams[i].Resource.PackSize;
+ FOR_VECTOR (i, DataStreams)
+ res += DataStreams[i].Resource.PackSize;
return res;
}
void Clear()
{
- Streams.Clear();
+ DataStreams.Clear();
+
+ MetaStreams.Clear();
+
Items.Clear();
+ ReparseItems.Clear();
+ ItemToReparse.Clear();
+
SortedItems.Clear();
- NumImages = 0;
+
+ Images.Clear();
+ VirtualRoots.Clear();
- SkipRoot = true;
- ShowImageNumber = true;
IsOldVersion = false;
+ ThereAreDeletedStreams = false;
+ ThereAreAltStreams = false;
+ RefCountError = false;
}
- UString GetItemPath(int index) const;
+ CDatabase(): RefCountError(false) {}
- HRESULT Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback);
+ 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;
- void DetectPathMode()
- {
- ShowImageNumber = (NumImages != 1);
- }
+ HRESULT OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml);
+ HRESULT Open(IInStream *inStream, const CHeader &h, unsigned numItemsReserve, IArchiveOpenCallback *openCallback);
+ HRESULT FillAndCheck();
- HRESULT Sort(bool skipRootDir);
+ /*
+ imageIndex showImageNumber NumImages
+ * true * Show Image_Number
+ -1 * >1 Show Image_Number
+ -1 false 1 Don't show Image_Number
+ N false * Don't show Image_Number
+ */
+ HRESULT GenerateSortedItems(int imageIndex, bool showImageNumber);
+
+ HRESULT ExtractReparseStreams(const CObjectVector<CVolume> &volumes, IArchiveOpenCallback *openCallback);
};
-HRESULT ReadHeader(IInStream *inStream, CHeader &header);
+HRESULT ReadHeader(IInStream *inStream, CHeader &header, UInt64 &phySize);
class CUnpacker
{
@@ -285,6 +495,7 @@ class CUnpacker
NXpress::CDecoder xpressDecoder;
CByteBuffer sizesBuf;
+
HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode,
ISequentialOutStream *outStream, ICompressProgressInfo *progress);
public:
diff --git a/CPP/7zip/Archive/Wim/WimRegister.cpp b/CPP/7zip/Archive/Wim/WimRegister.cpp
index 8da91436..35d78314 100755..100644
--- a/CPP/7zip/Archive/Wim/WimRegister.cpp
+++ b/CPP/7zip/Archive/Wim/WimRegister.cpp
@@ -5,14 +5,23 @@
#include "../../Common/RegisterArc.h"
#include "WimHandler.h"
-static IInArchive *CreateArc() { return new NArchive::NWim::CHandler; }
-#ifndef EXTRACT_ONLY
-static IOutArchive *CreateArcOut() { return new NArchive::NWim::COutHandler; }
-#else
-#define CreateArcOut 0
-#endif
+
+namespace NArchive {
+namespace NWim {
+
+IMP_CreateArcIn
+IMP_CreateArcOut
static CArcInfo g_ArcInfo =
- { L"wim", L"wim swm", 0, 0xE6, { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }, 8, false, CreateArc, CreateArcOut };
+ { "wim", "wim swm", 0, 0xE6,
+ 8, { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 },
+ 0,
+ NArcInfoFlags::kAltStreams |
+ NArcInfoFlags::kNtSecure |
+ NArcInfoFlags::kSymLinks |
+ NArcInfoFlags::kHardLinks
+ , REF_CreateArc_Pair };
REGISTER_ARC(Wim)
+
+}}
diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp
index e7d88b6c..918ef736 100755..100644
--- a/CPP/7zip/Archive/XarHandler.cpp
+++ b/CPP/7zip/Archive/XarHandler.cpp
@@ -4,13 +4,13 @@
#include "../../../C/CpuArch.h"
-#include "Common/ComTry.h"
-#include "Common/MyXml.h"
-#include "Common/StringToInt.h"
-#include "Common/UTFConvert.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/MyXml.h"
+#include "../../Common/StringToInt.h"
+#include "../../Common/UTFConvert.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -24,6 +24,8 @@
#include "Common/OutStreamWithSha1.h"
+using namespace NWindows;
+
#define XAR_SHOW_RAW
#define Get16(p) GetBe16(p)
@@ -33,6 +35,25 @@
namespace NArchive {
namespace NXar {
+static const UInt32 kXmlSizeMax = ((UInt32)1 << 30) - (1 << 14);
+static const UInt32 kXmlPackSizeMax = kXmlSizeMax;
+
+/*
+#define XAR_CKSUM_NONE 0
+#define XAR_CKSUM_SHA1 1
+#define XAR_CKSUM_MD5 2
+
+static const char *k_ChecksumAlgos[] =
+{
+ "None"
+ , "SHA-1"
+ , "MD5"
+};
+*/
+
+#define METHOD_NAME_ZLIB "zlib"
+
+
struct CFile
{
AString Name;
@@ -41,125 +62,153 @@ struct CFile
UInt64 PackSize;
UInt64 Offset;
- // UInt32 mode;
UInt64 CTime;
UInt64 MTime;
UInt64 ATime;
+ UInt32 Mode;
+
+ AString User;
+ AString Group;
bool IsDir;
bool HasData;
-
+ bool ModeDefined;
bool Sha1IsDefined;
- Byte Sha1[20];
// bool packSha1IsDefined;
- // Byte packSha1[20];
+
+ Byte Sha1[NCrypto::NSha1::kDigestSize];
+ // Byte packSha1[NCrypto::NSha1::kDigestSize];
int Parent;
- CFile(): IsDir(false), HasData(false), Sha1IsDefined(false),
- /* packSha1IsDefined(false), */
- Parent(-1), Size(0), PackSize(0), CTime(0), MTime(0), ATime(0) {}
+ 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<IInStream> _inStream;
AString _xml;
CObjectVector<CFile> _files;
+ // UInt32 _checkSumAlgo;
+ UInt64 _phySize;
+ Int32 _mainSubfile;
+ bool _is_pkg;
HRESULT Open2(IInStream *stream);
HRESULT Extract(IInStream *stream);
public:
- MY_UNKNOWN_IMP1(IInArchive)
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
};
-const UInt32 kXmlSizeMax = ((UInt32)1 << 30) - (1 << 14);
+static const Byte kArcProps[] =
+{
+ kpidSubType,
+ kpidHeadersSize
+};
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidCTime, VT_FILETIME},
- { NULL, kpidATime, VT_FILETIME},
- { NULL, kpidMethod, VT_BSTR}
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ kpidPosixAttrib,
+ kpidUser,
+ kpidGroup,
+ kpidMethod
};
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO
+IMP_IInArchive_ArcProps
-static bool ParseNumber(const char *s, int size, UInt32 &res)
-{
- const char *end;
- res = (UInt32)ConvertStringToUInt64(s, &end);
- return (end - s == size);
-}
+#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)
{
- AString s = item.GetSubStringForTag(name);
+ const AString s = item.GetSubStringForTag(name);
+ if (s.IsEmpty())
+ return false;
const char *end;
res = ConvertStringToUInt64(s, &end);
- return (end - (const char *)s == s.Length());
+ return *end == 0;
}
static UInt64 ParseTime(const CXmlItem &item, const char *name)
{
- AString s = item.GetSubStringForTag(name);
- if (s.Length() < 20)
+ 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;
- if (!ParseNumber(p, 4, year )) return 0;
- if (!ParseNumber(p + 5, 2, month)) return 0;
- if (!ParseNumber(p + 8, 2, day )) return 0;
- if (!ParseNumber(p + 11, 2, hour )) return 0;
- if (!ParseNumber(p + 14, 2, min )) return 0;
- if (!ParseNumber(p + 17, 2, sec )) return 0;
+ 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 (!NWindows::NTime::GetSecondsSince1601(year, month, day, hour, min, sec, numSecs))
+ if (!NTime::GetSecondsSince1601(year, month, day, hour, min, sec, numSecs))
return 0;
return numSecs * 10000000;
}
-static bool HexToByte(char c, Byte &res)
+static int HexToByte(char c)
{
- if (c >= '0' && c <= '9') res = c - '0';
- else if (c >= 'A' && c <= 'F') res = c - 'A' + 10;
- else if (c >= 'a' && c <= 'f') res = c - 'a' + 10;
- else return false;
- return true;
+ 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;
}
-#define METHOD_NAME_ZLIB "zlib"
-
static bool ParseSha1(const CXmlItem &item, const char *name, Byte *digest)
{
int index = item.FindSubTag(name);
- if (index < 0)
+ if (index < 0)
return false;
const CXmlItem &checkItem = item.SubItems[index];
- AString style = checkItem.GetPropertyValue("style");
+ const AString style = checkItem.GetPropVal("style");
if (style == "SHA1")
{
- AString s = checkItem.GetSubString();
- if (s.Length() != 40)
+ const AString s = checkItem.GetSubString();
+ if (s.Len() != NCrypto::NSha1::kDigestSize * 2)
return false;
- for (int i = 0; i < s.Length(); i += 2)
+ for (unsigned i = 0; i < s.Len(); i += 2)
{
- Byte b0, b1;
- if (!HexToByte(s[i], b0) || !HexToByte(s[i + 1], b1))
+ int b0 = HexToByte(s[i]);
+ int b1 = HexToByte(s[i + 1]);
+ if (b0 < 0 || b1 < 0)
return false;
- digest[i / 2] = (b0 << 4) | b1;
+ digest[i / 2] = (Byte)((b0 << 4) | b1);
}
return true;
}
@@ -203,17 +252,17 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren
const CXmlItem &encodingItem = dataItem.SubItems[encodingIndex];
if (encodingItem.IsTag)
{
- AString s = encodingItem.GetPropertyValue("style");
- if (s.Length() >= 0)
+ AString s = encodingItem.GetPropVal("style");
+ if (s.Len() >= 0)
{
AString appl = "application/";
- if (s.Left(appl.Length()) == appl)
+ if (s.IsPrefixedBy(appl))
{
- s = s.Mid(appl.Length());
+ s.DeleteFrontal(appl.Len());
AString xx = "x-";
- if (s.Left(xx.Length()) == xx)
+ if (s.IsPrefixedBy(xx))
{
- s = s.Mid(xx.Length());
+ s.DeleteFrontal(xx.Len());
if (s == "gzip")
s = METHOD_NAME_ZLIB;
}
@@ -227,9 +276,23 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren
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 (int i = 0; i < item.SubItems.Size(); i++)
+ FOR_VECTOR (i, item.SubItems)
if (!AddItem(item.SubItems[i], files, parent))
return false;
return true;
@@ -237,28 +300,28 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren
HRESULT CHandler::Open2(IInStream *stream)
{
- UInt64 archiveStartPos;
- RINOK(stream->Seek(0, STREAM_SEEK_SET, &archiveStartPos));
-
const UInt32 kHeaderSize = 0x1C;
Byte buf[kHeaderSize];
RINOK(ReadStream_FALSE(stream, buf, kHeaderSize));
UInt32 size = Get16(buf + 4);
- // UInt32 ver = Get16(buf + 6); // == 0
+ // 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);
- // UInt32 checkSumAlogo = Get32(buf + 0x18);
- if (unpackSize >= kXmlSizeMax)
+ // _checkSumAlgo = Get32(buf + 0x18);
+
+ if (packSize >= kXmlPackSizeMax ||
+ unpackSize >= kXmlSizeMax)
return S_FALSE;
- _dataStartPos = archiveStartPos + kHeaderSize + packSize;
+ _dataStartPos = kHeaderSize + packSize;
+ _phySize = _dataStartPos;
- char *ss = _xml.GetBuffer((int)unpackSize + 1);
+ char *ss = _xml.GetBuffer((unsigned)unpackSize);
NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
@@ -291,6 +354,19 @@ HRESULT CHandler::Open2(IInStream *stream)
return S_FALSE;
if (!AddItem(toc, _files, -1))
return S_FALSE;
+
+ UInt64 totalPackSize = 0;
+ FOR_VECTOR(i, _files)
+ {
+ const CFile &file = _files[i];
+ file.UpdateTotalPackSize(totalPackSize);
+ if (file.Name == "Payload")
+ _mainSubfile = i;
+ if (file.Name == "PackageInfo")
+ _is_pkg = true;
+ }
+ _phySize = _dataStartPos + totalPackSize;
+
return S_OK;
}
@@ -311,9 +387,12 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
STDMETHODIMP CHandler::Close()
{
+ _phySize = 0;
_inStream.Release();
_files.Clear();
_xml.Empty();
+ _mainSubfile = -1;
+ _is_pkg = false;
return S_OK;
}
@@ -327,7 +406,7 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
-static void TimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop)
+static void TimeToProp(UInt64 t, NCOM::CPropVariant &prop)
{
if (t != 0)
{
@@ -338,34 +417,56 @@ static void TimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop)
}
}
+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
- NWindows::NCOM::CPropVariant prop;
+ NCOM::CPropVariant prop;
#ifdef XAR_SHOW_RAW
- if ((int)index == _files.Size())
+ if (index == _files.Size())
{
- switch(propID)
+ switch (propID)
{
- case kpidPath: prop = L"[TOC].xml"; break;
+ case kpidPath: prop = "[TOC].xml"; break;
case kpidSize:
- case kpidPackSize: prop = (UInt64)_xml.Length(); break;
+ case kpidPackSize: prop = (UInt64)_xml.Len(); break;
}
}
else
#endif
{
const CFile &item = _files[index];
- switch(propID)
+ switch (propID)
{
- case kpidMethod:
- {
- UString name;
- if (!item.Method.IsEmpty() && ConvertUTF8ToUnicode(item.Method, name))
- prop = name;
- break;
- }
+ case kpidMethod: Utf8StringToProp(item.Method, prop); break;
+
case kpidPath:
{
AString path;
@@ -373,30 +474,40 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
do
{
const CFile &item = _files[cur];
- AString s = item.Name;
- if (s.IsEmpty())
- s = "unknown";
- if (path.IsEmpty())
- path = s;
+ if (!path.IsEmpty())
+ path.InsertAtFront(CHAR_PATH_SEPARATOR);
+ if (item.Name.IsEmpty())
+ path.Insert(0, "unknown");
else
- path = s + CHAR_PATH_SEPARATOR + path;
+ path.Insert(0, item.Name);
cur = item.Parent;
}
while (cur >= 0);
- UString name;
- if (ConvertUTF8ToUnicode(path, name))
- prop = name;
+ 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 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 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;
+ const UInt32 k_PosixAttrib_Dir = (1 << 14);
+ const UInt32 k_PosixAttrib_RegFile = (1 << 15);
+ if ((mode & 0xF000) == 0)
+ mode |= (item.IsDir ? k_PosixAttrib_Dir : k_PosixAttrib_RegFile);
+ prop = mode;
+ }
+ break;
+ case kpidUser: Utf8StringToProp(item.User, prop); break;
+ case kpidGroup: Utf8StringToProp(item.Group, prop); break;
}
}
prop.Detach(value);
@@ -408,7 +519,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _files.Size();
if (numItems == 0)
@@ -417,10 +528,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt32 i;
for (i = 0; i < numItems; i++)
{
- int index = (int)(allFilesMode ? i : indices[i]);
+ UInt32 index = (allFilesMode ? i : indices[i]);
#ifdef XAR_SHOW_RAW
if (index == _files.Size())
- totalSize += _xml.Length();
+ totalSize += _xml.Len();
else
#endif
totalSize += _files[index].Size;
@@ -433,8 +544,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 currentUnpSize = 0;
const UInt32 kZeroBufSize = (1 << 14);
- CByteBuffer zeroBuf;
- zeroBuf.SetCapacity(kZeroBufSize);
+ CByteBuffer zeroBuf(kZeroBufSize);
memset(zeroBuf, 0, kZeroBufSize);
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
@@ -478,7 +588,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
- Int32 index = allFilesMode ? i : indices[i];
+ UInt32 index = allFilesMode ? i : indices[i];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
if (index < _files.Size())
@@ -504,9 +614,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (index == _files.Size())
{
outStreamSha1Spec->Init(false);
- outStreamLimSpec->Init(_xml.Length());
- RINOK(WriteStream(outStream, (const char *)_xml, _xml.Length()));
- currentPackSize = currentUnpSize = _xml.Length();
+ outStreamLimSpec->Init(_xml.Len());
+ RINOK(WriteStream(outStream, (const char *)_xml, _xml.Len()));
+ currentPackSize = currentUnpSize = _xml.Len();
}
else
#endif
@@ -524,17 +634,17 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
HRESULT res = S_OK;
ICompressCoder *coder = NULL;
- if (item.Method.IsEmpty() || item.Method == "octet-stream")
+ if (item.IsCopyMethod())
if (item.PackSize == item.Size)
coder = copyCoder;
else
- opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ 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;
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
if (coder)
res = coder->Code(inStream, outStream, NULL, NULL, progress);
@@ -578,10 +688,35 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
-static IInArchive *CreateArc() { return new NArchive::NXar::CHandler; }
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ *stream = NULL;
+ COM_TRY_BEGIN
+ #ifdef XAR_SHOW_RAW
+ if (index == _files.Size())
+ {
+ Create_BufInStream_WithNewBuf((const void *)(const char *)_xml, _xml.Len(), 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
+}
+
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"Xar", L"xar", 0, 0xE1, { 'x', 'a', 'r', '!', 0, 0x1C }, 6, false, CreateArc, 0 };
+ { "Xar", "xar pkg", 0, 0xE1,
+ 6, { 'x', 'a', 'r', '!', 0, 0x1C },
+ 0,
+ 0,
+ CreateArc };
REGISTER_ARC(Xar)
diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp
index 8383488b..0de58a44 100755..100644
--- a/CPP/7zip/Archive/XzHandler.cpp
+++ b/CPP/7zip/Archive/XzHandler.cpp
@@ -7,8 +7,8 @@
#include "../../../C/XzEnc.h"
#include "../../Common/ComTry.h"
+#include "../../Common/Defs.h"
#include "../../Common/IntToString.h"
-#include "../../Common/StringConvert.h"
#include "../ICoder.h"
@@ -43,6 +43,81 @@ struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit;
static const wchar_t *k_LZMA2_Name = L"LZMA2";
+struct CStatInfo
+{
+ UInt64 InSize;
+ UInt64 OutSize;
+ UInt64 PhySize;
+
+ UInt64 NumStreams;
+ UInt64 NumBlocks;
+
+ bool UnpackSize_Defined;
+
+ bool NumStreams_Defined;
+ bool NumBlocks_Defined;
+
+ bool IsArc;
+ bool UnexpectedEnd;
+ bool DataAfterEnd;
+ bool Unsupported;
+ bool HeadersError;
+ bool DataError;
+ bool CrcError;
+
+ CStatInfo() { Clear(); }
+
+ void Clear()
+ {
+ InSize = 0;
+ OutSize = 0;
+ PhySize = 0;
+
+ NumStreams = 0;
+ NumBlocks = 0;
+
+ UnpackSize_Defined = false;
+
+ NumStreams_Defined = false;
+ NumBlocks_Defined = false;
+
+ UnexpectedEnd = false;
+ DataAfterEnd = false;
+ Unsupported = false;
+ HeadersError = false;
+ DataError = false;
+ CrcError = false;
+ IsArc = false;
+ }
+
+};
+
+struct IDecodeState: public CStatInfo
+{
+ SRes DecodeRes;
+
+ IDecodeState(): DecodeRes(SZ_OK) {}
+ virtual HRESULT Progress() = 0;
+
+ HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream);
+};
+
+struct CVirtProgress_To_LocalProgress: public IDecodeState
+{
+ CLocalProgress *lps;
+ CMyComPtr<ICompressProgressInfo> progress;
+
+ HRESULT Progress();
+};
+
+HRESULT CVirtProgress_To_LocalProgress::Progress()
+{
+ lps->InSize = InSize;
+ lps->OutSize = OutSize;
+ return lps->SetCur();
+}
+
+
class CHandler:
public IInArchive,
public IArchiveOpenSeq,
@@ -53,19 +128,17 @@ class CHandler:
#endif
public CMyUnknownImp
{
- Int64 _startPosition;
- UInt64 _packSize;
- UInt64 _unpackSize;
- UInt64 _numBlocks;
- AString _methodsString;
- bool _useSeq;
- UInt64 _unpackSizeDefined;
- UInt64 _packSizeDefined;
+ CStatInfo _stat;
+
+ bool _isArc;
+ bool _needSeekToStart;
+ bool _phySize_Defined;
CMyComPtr<IInStream> _stream;
CMyComPtr<ISequentialInStream> _seqStream;
UInt32 _filterId;
+ AString _methodsString;
void Init()
{
@@ -73,7 +146,15 @@ class CHandler:
CMultiMethodProps::Init();
}
- HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback);
+ HRESULT Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback);
+
+ HRESULT Decode2(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, IDecodeState &progress)
+ {
+ RINOK(progress.Decode(seqInStream, outStream));
+ _stat = progress;
+ _phySize_Defined = true;
+ return S_OK;
+ }
public:
MY_QUERYINTERFACE_BEGIN2(IInArchive)
@@ -90,7 +171,7 @@ public:
#ifndef EXTRACT_ONLY
INTERFACE_IOutArchive(;)
- STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps);
#endif
CHandler();
@@ -101,60 +182,60 @@ CHandler::CHandler()
Init();
}
-static STATPROPSTG const kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMethod, VT_BSTR}
+ kpidSize,
+ kpidPackSize,
+ kpidMethod
};
-static STATPROPSTG const kArcProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidNumBlocks, VT_UI4}
+ kpidMethod,
+ kpidNumStreams,
+ kpidNumBlocks
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
-static char GetHex(Byte value)
+static inline char GetHex(unsigned value)
{
return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
}
-static inline void AddHexToString(AString &res, Byte value)
+static inline void AddHexToString(AString &s, Byte value)
{
- res += GetHex((Byte)(value >> 4));
- res += GetHex((Byte)(value & 0xF));
+ s += GetHex(value >> 4);
+ s += GetHex(value & 0xF);
}
-static AString ConvertUInt32ToString(UInt32 value)
+static void AddUInt32ToString(AString &s, UInt32 value)
{
- char temp[32];
- ::ConvertUInt32ToString(value, temp);
- return temp;
+ char temp[16];
+ ConvertUInt32ToString(value, temp);
+ s += temp;
}
-static AString Lzma2PropToString(int prop)
+static void Lzma2PropToString(AString &s, unsigned prop)
{
+ char c = 0;
+ UInt32 size;
if ((prop & 1) == 0)
- return ConvertUInt32ToString(prop / 2 + 12);
- AString res;
- char c;
-
- UInt32 size = (2 | ((prop) & 1)) << ((prop) / 2 + 1);
-
- if (prop > 17)
- {
- res = ConvertUInt32ToString(size >> 10);
- c = 'm';
- }
+ size = prop / 2 + 12;
else
{
- res = ConvertUInt32ToString(size);
c = 'k';
+ size = (UInt32)(2 | (prop & 1)) << (prop / 2 + 1);
+ if (prop > 17)
+ {
+ size >>= 10;
+ c = 'm';
+ }
}
- return res + c;
+ AddUInt32ToString(s, size);
+ if (c != 0)
+ s += c;
}
struct CMethodNamePair
@@ -178,25 +259,29 @@ static const CMethodNamePair g_NamePairs[] =
static AString GetMethodString(const CXzFilter &f)
{
- AString s;
-
- for (int i = 0; i < sizeof(g_NamePairs) / sizeof(g_NamePairs[i]); i++)
+ const char *p = NULL;
+ for (unsigned i = 0; i < ARRAY_SIZE(g_NamePairs); i++)
if (g_NamePairs[i].Id == f.id)
- s = g_NamePairs[i].Name;
- if (s.IsEmpty())
+ {
+ p = g_NamePairs[i].Name;
+ break;
+ }
+ char temp[32];
+ if (!p)
{
- char temp[32];
::ConvertUInt64ToString(f.id, temp);
- s = temp;
+ p = temp;
}
+ AString s = p;
+
if (f.propsSize > 0)
{
s += ':';
if (f.id == XZ_ID_LZMA2 && f.propsSize == 1)
- s += Lzma2PropToString(f.props[0]);
+ Lzma2PropToString(s, f.props[0]);
else if (f.id == XZ_ID_Delta && f.propsSize == 1)
- s += ConvertUInt32ToString((UInt32)f.props[0] + 1);
+ AddUInt32ToString(s, (UInt32)f.props[0] + 1);
else
{
s += '[';
@@ -217,22 +302,22 @@ static void AddString(AString &dest, const AString &src)
static const char *kChecks[] =
{
- "NoCheck",
- "CRC32",
- NULL,
- NULL,
- "CRC64",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "SHA256",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
+ "NoCheck"
+ , "CRC32"
+ , NULL
+ , NULL
+ , "CRC64"
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , "SHA256"
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
};
static AString GetCheckString(const CXzs &xzs)
@@ -249,7 +334,10 @@ static AString GetCheckString(const CXzs &xzs)
if (kChecks[i])
s2 = kChecks[i];
else
- s2 = "Check-" + ConvertUInt32ToString((UInt32)i);
+ {
+ s2 = "Check-";
+ AddUInt32ToString(s2, (UInt32)i);
+ }
AddString(s, s2);
}
return s;
@@ -258,12 +346,26 @@ static AString GetCheckString(const CXzs &xzs)
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ NCOM::CPropVariant prop;
+ switch (propID)
{
- case kpidNumBlocks: if (!_useSeq) prop = _numBlocks; break;
- case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidPhySize: if (_phySize_Defined) prop = _stat.PhySize; 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 kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;;
+ if (_stat.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (_stat.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
+ if (_stat.HeadersError) v |= kpv_ErrorFlags_HeadersError;
+ if (_stat.Unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
+ if (_stat.DataError) v |= kpv_ErrorFlags_DataError;
+ if (_stat.CrcError) v |= kpv_ErrorFlags_CrcError;
+ prop = v;
+ }
}
prop.Detach(value);
return S_OK;
@@ -276,14 +378,14 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
-STDMETHODIMP CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value)
+STDMETHODIMP CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ NCOM::CPropVariant prop;
+ switch (propID)
{
- case kpidSize: if (_unpackSizeDefined) prop = _unpackSize; break;
- case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidSize: if (_stat.UnpackSize_Defined) prop = _stat.OutSize; break;
+ case kpidPackSize: if (_phySize_Defined) prop = _stat.PhySize; break;
case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
}
prop.Detach(value);
@@ -321,82 +423,124 @@ struct CXzsCPP
~CXzsCPP() { Xzs_Free(&p, &g_Alloc); }
};
-HRESULT CHandler::Open2(IInStream *inStream, IArchiveOpenCallback *callback)
+
+struct CVirtProgress_To_OpenProgress: public IDecodeState
{
- CSeekInStreamWrap inStreamImp(inStream);
+ IArchiveOpenCallback *Callback;
+ UInt64 Offset;
- CLookToRead lookStream;
- LookToRead_CreateVTable(&lookStream, True);
- lookStream.realStream = &inStreamImp.p;
- LookToRead_Init(&lookStream);
+ HRESULT Progress();
+};
- COpenCallbackWrap openWrap(callback);
- RINOK(inStream->Seek(0, STREAM_SEEK_END, &_packSize));
- RINOK(callback->SetTotal(NULL, &_packSize));
+HRESULT CVirtProgress_To_OpenProgress::Progress()
+{
+ if (Callback)
+ {
+ UInt64 files = 0;
+ UInt64 value = Offset + InSize;
+ return Callback->SetCompleted(&files, &value);
+ }
+ return S_OK;
+}
- CXzsCPP xzs;
- SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.s, &_startPosition, &openWrap.p, &g_Alloc);
- if (res == SZ_ERROR_NO_ARCHIVE && xzs.p.num > 0)
- res = SZ_OK;
- if (res == SZ_OK)
+static HRESULT SRes_to_Open_HRESULT(SRes res)
+{
+ switch (res)
{
- _packSize -= _startPosition;
- _unpackSize = Xzs_GetUnpackSize(&xzs.p);
- _unpackSizeDefined = _packSizeDefined = true;
- _numBlocks = (UInt64)Xzs_GetNumBlocks(&xzs.p);
+ 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;
+}
- RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback)
+{
+ _needSeekToStart = true;
+
+ {
CXzStreamFlags st;
CSeqInStreamWrap inStreamWrap(inStream);
- SRes res2 = Xz_ReadHeader(&st, &inStreamWrap.p);
+ SRes res = Xz_ReadHeader(&st, &inStreamWrap.p);
+ if (res != SZ_OK)
+ return SRes_to_Open_HRESULT(res);
- if (res2 == SZ_OK)
{
CXzBlock block;
Bool isIndex;
UInt32 headerSizeRes;
- res2 = XzBlock_ReadHeader(&block, &inStreamWrap.p, &isIndex, &headerSizeRes);
+ SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.p, &isIndex, &headerSizeRes);
if (res2 == SZ_OK && !isIndex)
{
- int numFilters = XzBlock_GetNumFilters(&block);
- for (int i = 0; i < numFilters; i++)
+ unsigned numFilters = XzBlock_GetNumFilters(&block);
+ for (unsigned i = 0; i < numFilters; i++)
AddString(_methodsString, GetMethodString(block.filters[i]));
}
}
- AddString(_methodsString, GetCheckString(xzs.p));
}
- if (res != SZ_OK || _startPosition != 0)
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &_stat.PhySize));
+ RINOK(callback->SetTotal(NULL, &_stat.PhySize));
+
+ CSeekInStreamWrap inStreamImp(inStream);
+
+ CLookToRead lookStream;
+ LookToRead_CreateVTable(&lookStream, True);
+ lookStream.realStream = &inStreamImp.p;
+ LookToRead_Init(&lookStream);
+
+ COpenCallbackWrap openWrap(callback);
+
+ CXzsCPP xzs;
+ Int64 startPosition;
+ SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.s, &startPosition, &openWrap.p, &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)
{
- RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
- CXzStreamFlags st;
- CSeqInStreamWrap inStreamWrap(inStream);
- SRes res2 = Xz_ReadHeader(&st, &inStreamWrap.p);
- if (res2 == SZ_OK)
- {
- res = res2;
- _startPosition = 0;
- _useSeq = True;
- _unpackSizeDefined = _packSizeDefined = false;
- }
+ _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;
+
+ AddString(_methodsString, GetCheckString(xzs.p));
+ }
+ else
+ {
+ res = SZ_OK;
}
- if (res == SZ_ERROR_NO_ARCHIVE)
- return S_FALSE;
- RINOK(SResToHRESULT(res));
+ 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
- try
{
Close();
- return Open2(inStream, callback);
+ return Open2(inStream, /* 0, */ callback);
}
- catch(...) { return S_FALSE; }
COM_TRY_END
}
@@ -404,15 +548,21 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
{
Close();
_seqStream = stream;
+ _isArc = true;
+ _needSeekToStart = false;
return S_OK;
}
STDMETHODIMP CHandler::Close()
{
- _numBlocks = 0;
- _useSeq = true;
- _unpackSizeDefined = _packSizeDefined = false;
- _methodsString.Empty();
+ _stat.Clear();
+
+ _isArc = false;
+ _needSeekToStart = false;
+
+ _phySize_Defined = false;
+
+ _methodsString.Empty();
_stream.Release();
_seqStream.Release();
return S_OK;
@@ -442,6 +592,7 @@ struct CXzUnpackerCPP
Byte *InBuf;
Byte *OutBuf;
CXzUnpacker p;
+
CXzUnpackerCPP(): InBuf(0), OutBuf(0)
{
XzUnpacker_Construct(&p, &g_Alloc);
@@ -454,129 +605,193 @@ struct CXzUnpackerCPP
}
};
-STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
- Int32 testMode, IArchiveExtractCallback *extractCallback)
+HRESULT IDecodeState::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream)
{
- COM_TRY_BEGIN
- if (numItems == 0)
- return S_OK;
- if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
- return E_INVALIDARG;
-
- extractCallback->SetTotal(_packSize);
- UInt64 currentTotalPacked = 0;
- RINOK(extractCallback->SetCompleted(&currentTotalPacked));
- CMyComPtr<ISequentialOutStream> realOutStream;
- Int32 askMode = testMode ?
- NExtract::NAskMode::kTest :
- NExtract::NAskMode::kExtract;
-
- RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
-
- if (!testMode && !realOutStream)
- return S_OK;
-
- extractCallback->PrepareOperation(askMode);
-
- if (_stream)
- {
- RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
- }
-
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> progress = lps;
- lps->Init(extractCallback, true);
-
- CCompressProgressWrap progressWrap(progress);
+ const size_t kInBufSize = 1 << 15;
+ const size_t kOutBufSize = 1 << 21;
- SRes res = S_OK;
+ DecodeRes = SZ_OK;
- const UInt32 kInBufSize = 1 << 15;
- const UInt32 kOutBufSize = 1 << 21;
-
- UInt32 inPos = 0;
- UInt32 inSize = 0;
- UInt32 outPos = 0;
CXzUnpackerCPP xzu;
XzUnpacker_Init(&xzu.p);
- {
- xzu.InBuf = (Byte *)MyAlloc(kInBufSize);
- xzu.OutBuf = (Byte *)MyAlloc(kOutBufSize);
- if (xzu.InBuf == 0 || xzu.OutBuf == 0)
- res = SZ_ERROR_MEM;
- }
- if (res == SZ_OK)
+ xzu.InBuf = (Byte *)MyAlloc(kInBufSize);
+ xzu.OutBuf = (Byte *)MyAlloc(kOutBufSize);
+ if (!xzu.InBuf || !xzu.OutBuf)
+ return E_OUTOFMEMORY;
+
+ UInt32 inSize = 0;
+ SizeT inPos = 0;
+ SizeT outPos = 0;
+
for (;;)
{
if (inPos == inSize)
{
inPos = inSize = 0;
- RINOK(_seqStream->Read(xzu.InBuf, kInBufSize, &inSize));
+ RINOK(seqInStream->Read(xzu.InBuf, kInBufSize, &inSize));
}
SizeT inLen = inSize - inPos;
SizeT outLen = kOutBufSize - outPos;
ECoderStatus status;
- res = XzUnpacker_Code(&xzu.p,
+
+ SRes res = XzUnpacker_Code(&xzu.p,
xzu.OutBuf + outPos, &outLen,
xzu.InBuf + inPos, &inLen,
(inSize == 0 ? CODER_FINISH_END : CODER_FINISH_ANY), &status);
- // printf("\n_inPos = %6d inLen = %5d, outLen = %5d", inPos, inLen, outLen);
+ inPos += inLen;
+ outPos += outLen;
+
+ InSize += inLen;
+ OutSize += outLen;
- inPos += (UInt32)inLen;
- outPos += (UInt32)outLen;
- lps->InSize += inLen;
- lps->OutSize += outLen;
+ DecodeRes = res;
- bool finished = (((inLen == 0) && (outLen == 0)) || res != SZ_OK);
+ bool finished = ((inLen == 0 && outLen == 0) || res != SZ_OK);
- if (outPos == kOutBufSize || finished)
+ if (outStream)
{
- if (realOutStream && outPos > 0)
+ if (outPos == kOutBufSize || finished)
{
- RINOK(WriteStream(realOutStream, xzu.OutBuf, outPos));
+ if (outPos != 0)
+ {
+ RINOK(WriteStream(outStream, xzu.OutBuf, outPos));
+ outPos = 0;
+ }
}
- outPos = 0;
}
- RINOK(lps->SetCur());
+ else
+ outPos = 0;
+
+ RINOK(Progress());
+
if (finished)
{
- _packSize = lps->InSize;
- _unpackSize = lps->OutSize;
- _packSizeDefined = _unpackSizeDefined = true;
+ PhySize = InSize;
+ NumStreams = xzu.p.numStartedStreams;
+ if (NumStreams > 0)
+ IsArc = true;
+ NumBlocks = xzu.p.numTotalBlocks;
+
+ UnpackSize_Defined = true;
+ NumStreams_Defined = true;
+ NumBlocks_Defined = true;
+
+ UInt64 extraSize = XzUnpacker_GetExtraSize(&xzu.p);
+
if (res == SZ_OK)
{
if (status == CODER_STATUS_NEEDS_MORE_INPUT)
{
- if (XzUnpacker_IsStreamWasFinished(&xzu.p))
- _packSize -= xzu.p.padSize;
- else
+ extraSize = 0;
+ if (!XzUnpacker_IsStreamWasFinished(&xzu.p))
+ {
+ // finished at padding bytes, but padding is not aligned for 4
+ UnexpectedEnd = true;
res = SZ_ERROR_DATA;
+ }
}
- else
+ else // status == CODER_STATUS_NOT_FINISHED
res = SZ_ERROR_DATA;
}
+ else if (res == SZ_ERROR_NO_ARCHIVE)
+ {
+ if (InSize == extraSize)
+ IsArc = false;
+ else
+ {
+ if (extraSize != 0 || inPos != inSize)
+ {
+ DataAfterEnd = true;
+ res = SZ_OK;
+ }
+ }
+ }
+
+ DecodeRes = res;
+ PhySize -= extraSize;
+
+ switch (res)
+ {
+ case SZ_OK: break;
+ case SZ_ERROR_NO_ARCHIVE: IsArc = false; break;
+ case SZ_ERROR_ARCHIVE: HeadersError = true; break;
+ case SZ_ERROR_UNSUPPORTED: Unsupported = true; break;
+ case SZ_ERROR_CRC: CrcError = true; break;
+ case SZ_ERROR_DATA: DataError = true; break;
+ default: DataError = true; break;
+ }
+
break;
}
}
- Int32 opRes;
- switch(res)
+ 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(_stat.PhySize);
+ UInt64 currentTotalPacked = 0;
+ RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CVirtProgress_To_LocalProgress vp;
+ vp.lps = new CLocalProgress;
+ vp.progress = vp.lps;
+ vp.lps->Init(extractCallback, true);
+
+
+ if (_needSeekToStart)
{
- case SZ_OK:
- opRes = NExtract::NOperationResult::kOK; break;
- case SZ_ERROR_UNSUPPORTED:
- opRes = NExtract::NOperationResult::kUnSupportedMethod; break;
- case SZ_ERROR_CRC:
- opRes = NExtract::NOperationResult::kCRCError; break;
- case SZ_ERROR_DATA:
- case SZ_ERROR_ARCHIVE:
- case SZ_ERROR_NO_ARCHIVE:
- opRes = NExtract::NOperationResult::kDataError; break;
- default:
- return SResToHRESULT(res);
+ if (!_stream)
+ return E_FAIL;
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
}
+ else
+ _needSeekToStart = true;
+
+ RINOK(Decode2(_seqStream, realOutStream, vp));
+
+ Int32 opRes;
+
+ if (!vp.IsArc)
+ opRes = NExtract::NOperationResult::kIsNotArc;
+ else if (vp.UnexpectedEnd)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ else if (vp.DataAfterEnd)
+ opRes = NExtract::NOperationResult::kDataAfterEnd;
+ else if (vp.CrcError)
+ opRes = NExtract::NOperationResult::kCRCError;
+ else if (vp.Unsupported)
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ else if (vp.HeadersError)
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (vp.DataError)
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (vp.DecodeRes != SZ_OK)
+ opRes = NExtract::NOperationResult::kDataError;
+ else
+ opRes = NExtract::NOperationResult::kOK;
+
realOutStream.Release();
return extractCallback->SetOperationResult(opRes);
COM_TRY_END
@@ -648,7 +863,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
RINOK(NCompress::NLzma2::SetLzma2Prop(NCoderPropID::kReduceSize, prop, lzma2Props));
}
- for (int i = 0; i < _methods.Size(); i++)
+ FOR_VECTOR (i, _methods)
{
COneMethodInfo &m = _methods[i];
SetGlobalLevelAndThreads(m
@@ -657,7 +872,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
#endif
);
{
- for (int j = 0; j < m.Props.Size(); j++)
+ FOR_VECTOR (j, m.Props)
{
const CProp &prop = m.Props[j];
RINOK(NCompress::NLzma2::SetLzma2Prop(prop.Id, prop.Value, lzma2Props));
@@ -692,7 +907,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (_filterId == XZ_ID_Delta)
{
bool deltaDefined = false;
- for (int j = 0; j < _filterMethod.Props.Size(); j++)
+ FOR_VECTOR (j, _filterMethod.Props)
{
const CProp &prop = _filterMethod.Props[j];
if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4)
@@ -715,29 +930,26 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (indexInArchive != 0)
return E_INVALIDARG;
if (_stream)
- RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
- return NCompress::CopyStream(_stream, outStream, 0);
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
+ return NCompress::CopyStream(_stream, outStream, NULL);
}
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
-
-STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
{
COM_TRY_BEGIN
Init();
- for (int i = 0; i < numProps; i++)
+ for (UInt32 i = 0; i < numProps; i++)
{
RINOK(SetProperty(names[i], values[i]));
}
if (!_filterMethod.MethodName.IsEmpty())
{
- int k;
+ unsigned k;
for (k = 0; k < ARRAY_SIZE(g_NamePairs); k++)
{
const CMethodNamePair &pair = g_NamePairs[k];
- UString m = GetUnicodeString(pair.Name);
- if (_filterMethod.MethodName.CompareNoCase(m) == 0)
+ if (StringsAreEqualNoCase_Ascii(_filterMethod.MethodName, pair.Name))
{
_filterId = pair.Id;
break;
@@ -747,8 +959,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v
return E_INVALIDARG;
}
- int numEmptyMethods = GetNumEmptyMethods();
- _methods.Delete(0, numEmptyMethods);
+ _methods.DeleteFrontal(GetNumEmptyMethods());
if (_methods.Size() > 1)
return E_INVALIDARG;
if (_methods.Size() == 1)
@@ -756,7 +967,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v
UString &methodName = _methods[0].MethodName;
if (methodName.IsEmpty())
methodName = k_LZMA2_Name;
- else if (methodName.CompareNoCase(k_LZMA2_Name) != 0)
+ else if (!methodName.IsEqualToNoCase(k_LZMA2_Name))
return E_INVALIDARG;
}
return S_OK;
@@ -765,15 +976,15 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v
#endif
-static IInArchive *CreateArc() { return new NArchive::NXz::CHandler; }
-#ifndef EXTRACT_ONLY
-static IOutArchive *CreateArcOut() { return new NArchive::NXz::CHandler; }
-#else
-#define CreateArcOut 0
-#endif
+IMP_CreateArcIn
+IMP_CreateArcOut
static CArcInfo g_ArcInfo =
- { L"xz", L"xz txz", L"* .tar", 0xC, {0xFD, '7' , 'z', 'X', 'Z', '\0'}, 6, true, CreateArc, CreateArcOut };
+ { "xz", "xz txz", "* .tar", 0xC,
+ 6, { 0xFD, '7' , 'z', 'X', 'Z', 0 },
+ 0,
+ NArcInfoFlags::kKeepName,
+ REF_CreateArc_Pair };
REGISTER_ARC(xz)
diff --git a/CPP/7zip/Archive/ZHandler.cpp b/CPP/7zip/Archive/ZHandler.cpp
index 49b76a11..459f3e35 100755..100644
--- a/CPP/7zip/Archive/ZHandler.cpp
+++ b/CPP/7zip/Archive/ZHandler.cpp
@@ -2,9 +2,9 @@
#include "StdAfx.h"
-#include "Common/ComTry.h"
+#include "../../Common/ComTry.h"
-#include "Windows/PropVariant.h"
+#include "../../Windows/PropVariant.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
@@ -22,21 +22,21 @@ class CHandler:
public CMyUnknownImp
{
CMyComPtr<IInStream> _stream;
- UInt64 _streamStartPosition;
UInt64 _packSize;
- Byte _properties;
+ // UInt64 _unpackSize;
+ // bool _unpackSize_Defined;
public:
MY_UNKNOWN_IMP1(IInArchive)
INTERFACE_IInArchive(;)
};
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPackSize, VT_UI8}
+ kpidPackSize
};
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO
+IMP_IInArchive_ArcProps_NO_Table
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
@@ -44,36 +44,110 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
-STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ 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;
}
-static const int kSignatureSize = 3;
+/*
+class CCompressProgressInfoImp:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+ CMyComPtr<IArchiveOpenCallback> 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 * /* openArchiveCallback */)
+ IArchiveOpenCallback * /* openCallback */)
{
COM_TRY_BEGIN
{
- RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_streamStartPosition));
- Byte buffer[kSignatureSize];
- RINOK(ReadStream_FALSE(stream, buffer, kSignatureSize));
- if (buffer[0] != 0x1F || buffer[1] != 0x9D)
+ // 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;
- _properties = buffer[2];
- UInt64 endPosition;
- RINOK(stream->Seek(0, STREAM_SEEK_END, &endPosition));
- _packSize = endPosition - _streamStartPosition - kSignatureSize;
-
+ UInt64 endPos;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
+ _packSize = endPos;
+
+ /*
+ bool fullCheck = false;
+ if (fullCheck)
+ {
+ CCompressProgressInfoImp *compressProgressSpec = new CCompressProgressInfoImp;
+ CMyComPtr<ICompressProgressInfo> compressProgress = compressProgressSpec;
+ compressProgressSpec->Init(openCallback);
+
+ NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder;
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(NULL);
+ outStreamSpec->Init();
+ decoderSpec->SetProp(_prop);
+ if (openCallback)
+ {
+ UInt64 files = 1;
+ RINOK(openCallback->SetTotal(&files, &endPos));
+ }
+ RINOK(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;
@@ -82,6 +156,8 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
STDMETHODIMP CHandler::Close()
{
+ _packSize = 0;
+ // _unpackSize_Defined = false;
_stream.Release();
return S_OK;
}
@@ -93,7 +169,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_BEGIN
if (numItems == 0)
return S_OK;
- if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
extractCallback->SetTotal(_packSize);
@@ -124,37 +200,37 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, true);
- RINOK(_stream->Seek(_streamStartPosition + kSignatureSize, STREAM_SEEK_SET, NULL));
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
- CMyComPtr<ICompressCoder> decoder;
NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder;
- decoder = decoderSpec;
-
- HRESULT result = decoderSpec->SetDecoderProperties2(&_properties, 1);
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
- int opResult;
- if (result != S_OK)
- opResult = NExtract::NOperationResult::kUnSupportedMethod;
- else
+ int opRes;
{
- result = decoder->Code(_stream, outStream, NULL, NULL, progress);
+ HRESULT result = decoder->Code(_stream, outStream, NULL, NULL, progress);
if (result == S_FALSE)
- opResult = NExtract::NOperationResult::kDataError;
+ opRes = NExtract::NOperationResult::kDataError;
else
{
RINOK(result);
- opResult = NExtract::NOperationResult::kOK;
+ opRes = NExtract::NOperationResult::kOK;
}
}
+ // _unpackSize = outStreamSpec->GetSize();
+ // _unpackSize_Defined = true;
outStream.Release();
- return extractCallback->SetOperationResult(opResult);
+ return extractCallback->SetOperationResult(opRes);
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"Z", L"z taz", L"* .tar", 5, { 0x1F, 0x9D }, 2, false, CreateArc, 0 };
+ { "Z", "z taz", "* .tar", 5,
+ 2, { 0x1F, 0x9D },
+ 0,
+ 0,
+ CreateArc, NULL, IsArc_Z };
REGISTER_ARC(Z)
diff --git a/CPP/7zip/Archive/Zip/StdAfx.h b/CPP/7zip/Archive/Zip/StdAfx.h
index e7fb6986..2854ff3e 100755..100644
--- a/CPP/7zip/Archive/Zip/StdAfx.h
+++ b/CPP/7zip/Archive/Zip/StdAfx.h
@@ -3,6 +3,6 @@
#ifndef __STDAFX_H
#define __STDAFX_H
-#include "../../../Common/MyWindows.h"
+#include "../../../Common/Common.h"
#endif
diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
index f77e4f23..9a0d7515 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
+++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
@@ -4,7 +4,7 @@
#include "../../../../C/7zCrc.h"
-#include "Windows/PropVariant.h"
+#include "../../../Windows/PropVariant.h"
#include "../../ICoder.h"
#include "../../IPassword.h"
@@ -85,18 +85,18 @@ CAddCommon::CAddCommon(const CCompressionMethodMode &options):
static HRESULT GetStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC)
{
UInt32 crc = CRC_INIT_VAL;
- const UInt32 kBufferSize = (1 << 14);
- Byte buffer[kBufferSize];
+ const UInt32 kBufSize = (1 << 14);
+ Byte buf[kBufSize];
for (;;)
{
- UInt32 realProcessedSize;
- RINOK(inStream->Read(buffer, kBufferSize, &realProcessedSize));
- if (realProcessedSize == 0)
+ UInt32 processed;
+ RINOK(inStream->Read(buf, kBufSize, &processed));
+ if (processed == 0)
{
resultCRC = CRC_GET_DIGEST(crc);
return S_OK;
}
- crc = CrcUpdate(crc, buffer, (size_t)realProcessedSize);
+ crc = CrcUpdate(crc, buf, (size_t)processed);
}
}
@@ -105,8 +105,14 @@ HRESULT CAddCommon::Compress(
ISequentialInStream *inStream, IOutStream *outStream,
ICompressProgressInfo *progress, CCompressingResult &opRes)
{
- CSequentialInStreamWithCRC *inSecCrcStreamSpec = 0;
- CInStreamWithCRC *inCrcStreamSpec = 0;
+ if (!inStream)
+ {
+ // We can create empty stream here. But it was already implemented in caller code in 9.33+
+ return E_INVALIDARG;
+ }
+
+ CSequentialInStreamWithCRC *inSecCrcStreamSpec = NULL;
+ CInStreamWithCRC *inCrcStreamSpec = NULL;
CMyComPtr<ISequentialInStream> inCrcStream;
{
CMyComPtr<IInStream> inStream2;
@@ -128,26 +134,30 @@ HRESULT CAddCommon::Compress(
}
}
- int numTestMethods = _options.MethodSequence.Size();
+ unsigned numTestMethods = _options.MethodSequence.Size();
+
if (numTestMethods > 1 || _options.PasswordIsDefined)
{
- if (inCrcStreamSpec == 0)
+ if (!inCrcStreamSpec)
{
if (_options.PasswordIsDefined)
return E_NOTIMPL;
numTestMethods = 1;
}
}
+
Byte method = 0;
COutStreamReleaser outStreamReleaser;
opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default;
- for (int i = 0; i < numTestMethods; i++)
+
+ for (unsigned i = 0; i < numTestMethods; i++)
{
opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default;
- if (inCrcStreamSpec != 0)
+ if (inCrcStreamSpec)
RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL));
RINOK(outStream->SetSize(0));
RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL));
+
if (_options.PasswordIsDefined)
{
opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_ZipCrypto;
@@ -157,6 +167,7 @@ HRESULT CAddCommon::Compress(
_cryptoStreamSpec = new CFilterCoder;
_cryptoStream = _cryptoStreamSpec;
}
+
if (_options.IsAesMode)
{
opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Aes;
@@ -164,7 +175,7 @@ HRESULT CAddCommon::Compress(
{
_cryptoStreamSpec->Filter = _filterAesSpec = new NCrypto::NWzAes::CEncoder;
_filterAesSpec->SetKeyMode(_options.AesKeyMode);
- RINOK(_filterAesSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Length()));
+ RINOK(_filterAesSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Len()));
}
RINOK(_filterAesSpec->WriteHeader(outStream));
}
@@ -173,19 +184,21 @@ HRESULT CAddCommon::Compress(
if (!_cryptoStreamSpec->Filter)
{
_cryptoStreamSpec->Filter = _filterSpec = new NCrypto::NZip::CEncoder;
- _filterSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Length());
+ _filterSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Len());
}
UInt32 crc = 0;
RINOK(GetStreamCRC(inStream, crc));
RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL));
RINOK(_filterSpec->WriteHeader(outStream, crc));
}
+
RINOK(_cryptoStreamSpec->SetOutStream(outStream));
outStreamReleaser.FilterCoder = _cryptoStreamSpec;
}
method = _options.MethodSequence[i];
- switch(method)
+
+ switch (method)
{
case NFileHeader::NCompressionMethod::kStored:
{
@@ -202,6 +215,7 @@ HRESULT CAddCommon::Compress(
RINOK(_copyCoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress));
break;
}
+
default:
{
if (!_compressEncoder)
@@ -272,7 +286,7 @@ HRESULT CAddCommon::Compress(
RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize));
- if (inCrcStreamSpec != 0)
+ if (inCrcStreamSpec)
{
opRes.CRC = inCrcStreamSpec->GetCRC();
opRes.UnpackSize = inCrcStreamSpec->GetSize();
@@ -292,6 +306,7 @@ HRESULT CAddCommon::Compress(
else if (opRes.PackSize < opRes.UnpackSize)
break;
}
+
if (_options.PasswordIsDefined && _options.IsAesMode)
{
RINOK(_filterAesSpec->WriteFooter(outStream));
diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.h b/CPP/7zip/Archive/Zip/ZipAddCommon.h
index e4c02db3..e4c02db3 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipAddCommon.h
+++ b/CPP/7zip/Archive/Zip/ZipAddCommon.h
diff --git a/CPP/7zip/Archive/Zip/ZipCompressionMode.h b/CPP/7zip/Archive/Zip/ZipCompressionMode.h
index 893daaab..86548d95 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipCompressionMode.h
+++ b/CPP/7zip/Archive/Zip/ZipCompressionMode.h
@@ -3,7 +3,7 @@
#ifndef __ZIP_COMPRESSION_MODE_H
#define __ZIP_COMPRESSION_MODE_H
-#include "Common/MyString.h"
+#include "../../../Common/MyString.h"
#ifndef _7ZIP_ST
#include "../../../Windows/System.h"
diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp
index 2281ed5b..f556068c 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipHandler.cpp
+++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp
@@ -2,11 +2,11 @@
#include "StdAfx.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/TimeUtils.h"
#include "../../IPassword.h"
@@ -40,98 +40,112 @@ static const CMethodId kMethodId_BZip2 = 0x040202;
static const char *kHostOS[] =
{
- "FAT",
- "AMIGA",
- "VMS",
- "Unix",
- "VM/CMS",
- "Atari",
- "HPFS",
- "Macintosh",
- "Z-System",
- "CP/M",
- "TOPS-20",
- "NTFS",
- "SMS/QDOS",
- "Acorn",
- "VFAT",
- "MVS",
- "BeOS",
- "Tandem",
- "OS/400",
- "OS/X"
+ "FAT"
+ , "AMIGA"
+ , "VMS"
+ , "Unix"
+ , "VM/CMS"
+ , "Atari"
+ , "HPFS"
+ , "Macintosh"
+ , "Z-System"
+ , "CP/M"
+ , "TOPS-20"
+ , "NTFS"
+ , "SMS/QDOS"
+ , "Acorn"
+ , "VFAT"
+ , "MVS"
+ , "BeOS"
+ , "Tandem"
+ , "OS/400"
+ , "OS/X"
};
-static const char *kUnknownOS = "Unknown";
-
static const char *kMethods[] =
{
- "Store",
- "Shrink",
- "Reduced1",
- "Reduced2",
- "Reduced3",
- "Reduced4",
- "Implode",
- "Tokenizing",
- "Deflate",
- "Deflate64",
- "PKImploding"
+ "Store"
+ , "Shrink"
+ , "Reduced1"
+ , "Reduced2"
+ , "Reduced3"
+ , "Reduced4"
+ , "Implode"
+ , "Tokenizing"
+ , "Deflate"
+ , "Deflate64"
+ , "PKImploding"
};
-static const char *kBZip2Method = "BZip2";
-static const char *kLZMAMethod = "LZMA";
-static const char *kJpegMethod = "Jpeg";
-static const char *kWavPackMethod = "WavPack";
-static const char *kPPMdMethod = "PPMd";
-static const char *kAESMethod = "AES";
-static const char *kZipCryptoMethod = "ZipCrypto";
-static const char *kStrongCryptoMethod = "StrongCrypto";
+static const char *kMethod_AES = "AES";
+static const char *kMethod_ZipCrypto = "ZipCrypto";
+static const char *kMethod_StrongCrypto = "StrongCrypto";
-static struct CStrongCryptoPair
+struct CIdToNamePair
{
- UInt16 Id;
+ unsigned Id;
const char *Name;
-} g_StrongCryptoPairs[] =
+};
+
+static const CIdToNamePair k_MethodIdNamePairs[] =
+{
+ { NFileHeader::NCompressionMethod::kBZip2, "BZip2" },
+ { NFileHeader::NCompressionMethod::kLZMA, "LZMA" },
+ { NFileHeader::NCompressionMethod::kJpeg, "Jpeg" },
+ { NFileHeader::NCompressionMethod::kWavPack, "WavPack" },
+ { NFileHeader::NCompressionMethod::kPPMd, "PPMd" }
+};
+
+static const CIdToNamePair k_StrongCryptoPairs[] =
{
- { NStrongCryptoFlags::kDES, "DES" },
- { NStrongCryptoFlags::kRC2old, "RC2a" },
- { NStrongCryptoFlags::k3DES168, "3DES-168" },
- { NStrongCryptoFlags::k3DES112, "3DES-112" },
- { NStrongCryptoFlags::kAES128, "pkAES-128" },
- { NStrongCryptoFlags::kAES192, "pkAES-192" },
- { NStrongCryptoFlags::kAES256, "pkAES-256" },
- { NStrongCryptoFlags::kRC2, "RC2" },
- { NStrongCryptoFlags::kBlowfish, "Blowfish" },
- { NStrongCryptoFlags::kTwofish, "Twofish" },
- { NStrongCryptoFlags::kRC4, "RC4" }
+ { 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 STATPROPSTG kProps[] =
+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[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidCTime, VT_FILETIME},
- { NULL, kpidATime, VT_FILETIME},
- { NULL, kpidAttrib, VT_UI4},
- // { NULL, kpidPosixAttrib, VT_UI4},
- { NULL, kpidEncrypted, VT_BOOL},
- { NULL, kpidComment, VT_BSTR},
- { NULL, kpidCRC, VT_UI4},
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidHostOS, VT_BSTR},
- { NULL, kpidUnpackVer, VT_UI4}
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ kpidAttrib,
+ // kpidPosixAttrib,
+ kpidEncrypted,
+ kpidComment,
+ kpidCRC,
+ kpidMethod,
+ kpidHostOS,
+ kpidUnpackVer
};
-static const STATPROPSTG kArcProps[] =
+static const Byte kArcProps[] =
{
- { NULL, kpidBit64, VT_BOOL},
- { NULL, kpidComment, VT_BSTR},
- { NULL, kpidPhySize, VT_UI8},
- { NULL, kpidOffset, VT_UI8}
+ kpidEmbeddedStubSize,
+ kpidBit64,
+ kpidComment
};
CHandler::CHandler()
@@ -142,12 +156,12 @@ CHandler::CHandler()
static AString BytesToString(const CByteBuffer &data)
{
AString s;
- int size = (int)data.GetCapacity();
+ unsigned size = (unsigned)data.Size();
if (size > 0)
{
- char *p = s.GetBuffer(size + 1);
+ char *p = s.GetBuffer(size);
memcpy(p, (const Byte *)data, size);
- p[size] = '\0';
+ p[size] = 0;
s.ReleaseBuffer();
}
return s;
@@ -160,13 +174,52 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break;
- case kpidComment: prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break;
+ case kpidComment: if (m_Archive.ArcInfo.Comment.Size() != 0) prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break;
case kpidPhySize: prop = m_Archive.ArcInfo.GetPhySize(); break;
- case kpidOffset: if (m_Archive.ArcInfo.StartPosition != 0) prop = m_Archive.ArcInfo.StartPosition; break;
- case kpidError: if (!m_Archive.IsOkHeaders) prop = "Incorrect headers"; break;
+ case kpidOffset: /* if (m_Archive.ArcInfo.Base != 0) */
+ prop = m_Archive.ArcInfo.Base; break;
+
+ case kpidEmbeddedStubSize:
+ {
+ UInt64 stubSize = m_Archive.ArcInfo.GetEmbeddedStubSize();
+ if (stubSize != 0)
+ prop = stubSize;
+ 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 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.ArcInfo.GetEmbeddedStubSize();
+ if (stubSize < (UInt64)-m_Archive.ArcInfo.Base)
+ v |= kpv_ErrorFlags_UnavailableStart;
+ }
+ if (m_Archive.NoCentralDir) v |= kpv_ErrorFlags_UnconfirmedStart;
+ prop = v;
+ break;
+ }
}
prop.Detach(value);
COM_TRY_END
@@ -184,24 +237,36 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
const CItemEx &item = m_Items[index];
- switch(propID)
+ switch (propID)
{
- case kpidPath: prop = NItemName::GetOSName2(item.GetUnicodeString(item.Name)); break;
+ case kpidPath:
+ {
+ UString res;
+ item.GetUnicodeString(item.Name, res, _forceCodePage, _specifiedCodePage);
+ NItemName::ConvertToOSName2(res);
+ prop = res;
+ break;
+ }
+
case kpidIsDir: prop = item.IsDir(); break;
- case kpidSize: prop = item.UnPackSize; break;
+ case kpidSize: prop = item.Size; break;
case kpidPackSize: prop = item.PackSize; break;
+
case kpidTimeType:
{
FILETIME ft;
UInt32 unixTime;
+ UInt32 type;
if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft))
- prop = (UInt32)NFileTimeType::kWindows;
+ type = NFileTimeType::kWindows;
else if (item.CentralExtra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime))
- prop = (UInt32)NFileTimeType::kUnix;
+ type = NFileTimeType::kUnix;
else
- prop = (UInt32)NFileTimeType::kDOS;
+ type = NFileTimeType::kDOS;
+ prop = type;
break;
}
+
case kpidCTime:
{
FILETIME ft;
@@ -209,6 +274,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = ft;
break;
}
+
case kpidATime:
{
FILETIME ft;
@@ -216,26 +282,33 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = ft;
break;
}
+
case kpidMTime:
{
FILETIME utc;
+ bool defined = true;
if (!item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc))
{
- UInt32 unixTime;
+ UInt32 unixTime = 0;
if (item.CentralExtra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime))
NTime::UnixTimeToFileTime(unixTime, utc);
else
{
FILETIME localFileTime;
- if (!NTime::DosTimeToFileTime(item.Time, localFileTime) ||
+ if (item.Time == 0)
+ defined = false;
+ else if (!NTime::DosTimeToFileTime(item.Time, localFileTime) ||
!LocalFileTimeToFileTime(&localFileTime, &utc))
utc.dwHighDateTime = utc.dwLowDateTime = 0;
}
}
- prop = utc;
+ if (defined)
+ prop = utc;
break;
}
+
case kpidAttrib: prop = item.GetWinAttrib(); break;
+
case kpidPosixAttrib:
{
UInt32 attrib;
@@ -243,83 +316,107 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = attrib;
break;
}
+
case kpidEncrypted: prop = item.IsEncrypted(); break;
- case kpidComment: prop = item.GetUnicodeString(BytesToString(item.Comment)); break;
- case kpidCRC: if (item.IsThereCrc()) prop = item.FileCRC; break;
+
+ case kpidComment:
+ {
+ if (item.Comment.Size() != 0)
+ {
+ UString res;
+ item.GetUnicodeString(BytesToString(item.Comment), res, _forceCodePage, _specifiedCodePage);
+ prop = res;
+ }
+ break;
+ }
+
+ case kpidCRC: if (item.IsThereCrc()) prop = item.Crc; break;
+
case kpidMethod:
{
- UInt16 methodId = item.CompressionMethod;
- AString method;
+ UInt16 methodId = item.Method;
+ AString m;
+
if (item.IsEncrypted())
{
if (methodId == NFileHeader::NCompressionMethod::kWzAES)
{
- method = kAESMethod;
- CWzAesExtraField aesField;
- if (item.CentralExtra.GetWzAesField(aesField))
+ m += kMethod_AES;
+ CWzAesExtra aesField;
+ if (item.CentralExtra.GetWzAes(aesField))
{
- method += '-';
- char s[32];
- ConvertUInt64ToString((aesField.Strength + 1) * 64 , s);
- method += s;
- method += ' ';
+ char s[16];
+ s[0] = '-';
+ ConvertUInt32ToString(((unsigned)aesField.Strength + 1) * 64 , s + 1);
+ m += s;
methodId = aesField.Method;
}
}
- else
+ else if (item.IsStrongEncrypted())
{
- if (item.IsStrongEncrypted())
+ CStrongCryptoExtra f;
+ f.AlgId = 0;
+ if (item.CentralExtra.GetStrongCrypto(f))
{
- CStrongCryptoField f;
- bool finded = false;
- if (item.CentralExtra.GetStrongCryptoField(f))
+ const char *s = FindNameForId(k_StrongCryptoPairs, ARRAY_SIZE(k_StrongCryptoPairs), f.AlgId);
+ if (s)
+ m += s;
+ else
{
- for (int i = 0; i < sizeof(g_StrongCryptoPairs) / sizeof(g_StrongCryptoPairs[0]); i++)
- {
- const CStrongCryptoPair &pair = g_StrongCryptoPairs[i];
- if (f.AlgId == pair.Id)
- {
- method += pair.Name;
- finded = true;
- break;
- }
- }
+ m += kMethod_StrongCrypto;
+ char temp[16];
+ temp[0] = ':';
+ ConvertUInt32ToString(f.AlgId, temp + 1);
+ m += temp;
}
- if (!finded)
- method += kStrongCryptoMethod;
}
else
- method += kZipCryptoMethod;
- method += ' ';
+ m += kMethod_StrongCrypto;
}
+ else
+ m += kMethod_ZipCrypto;
+ m += ' ';
}
- if (methodId < sizeof(kMethods) / sizeof(kMethods[0]))
- method += kMethods[methodId];
- else switch (methodId)
+
{
- case NFileHeader::NCompressionMethod::kLZMA:
- method += kLZMAMethod;
- if (item.IsLzmaEOS())
- method += ":EOS";
- break;
- case NFileHeader::NCompressionMethod::kBZip2: method += kBZip2Method; break;
- case NFileHeader::NCompressionMethod::kJpeg: method += kJpegMethod; break;
- case NFileHeader::NCompressionMethod::kWavPack: method += kWavPackMethod; break;
- case NFileHeader::NCompressionMethod::kPPMd: method += kPPMdMethod; break;
- default:
+ char temp[16];
+ const char *s = NULL;
+ if (methodId < ARRAY_SIZE(kMethods))
+ s = kMethods[methodId];
+ else
{
- char s[32];
- ConvertUInt64ToString(methodId, s);
- method += s;
+ s = FindNameForId(k_MethodIdNamePairs, ARRAY_SIZE(k_MethodIdNamePairs), methodId);
+ if (!s)
+ {
+ ConvertUInt32ToString(methodId, temp);
+ s = temp;
+ }
}
+ m += s;
+ if (methodId == NFileHeader::NCompressionMethod::kLZMA && item.IsLzmaEOS())
+ m += ":EOS";
}
- prop = method;
+
+ prop = m;
break;
}
+
case kpidHostOS:
- prop = (item.MadeByVersion.HostOS < sizeof(kHostOS) / sizeof(kHostOS[0])) ?
- (kHostOS[item.MadeByVersion.HostOS]) : kUnknownOS;
+ {
+ Byte hostOS = item.GetHostOS();
+ char temp[16];
+ const char *s = NULL;
+ if (hostOS < ARRAY_SIZE(kHostOS))
+ s = kHostOS[hostOS];
+ else
+ {
+ ConvertUInt32ToString(hostOS, temp);
+ s = temp;
+ }
+ prop = s;
break;
+ }
+
case kpidUnpackVer:
prop = (UInt32)item.ExtractVersion.Version;
break;
@@ -333,23 +430,25 @@ class CProgressImp: public CProgressVirt
{
CMyComPtr<IArchiveOpenCallback> _callback;
public:
- STDMETHOD(SetTotal)(UInt64 numFiles);
- STDMETHOD(SetCompleted)(UInt64 numFiles);
+ virtual HRESULT SetCompletedLocal(UInt64 numFiles, UInt64 numBytes);
+ virtual HRESULT SetTotalCD(UInt64 numFiles);
+ virtual HRESULT SetCompletedCD(UInt64 numFiles);
CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {}
};
-STDMETHODIMP CProgressImp::SetTotal(UInt64 numFiles)
+HRESULT CProgressImp::SetCompletedLocal(UInt64 numFiles, UInt64 numBytes)
{
- if (_callback)
- return _callback->SetTotal(&numFiles, NULL);
- return S_OK;
+ return _callback->SetCompleted(&numFiles, &numBytes);
}
-STDMETHODIMP CProgressImp::SetCompleted(UInt64 numFiles)
+HRESULT CProgressImp::SetTotalCD(UInt64 numFiles)
{
- if (_callback)
- return _callback->SetCompleted(&numFiles, NULL);
- return S_OK;
+ return _callback->SetTotal(&numFiles, NULL);
+}
+
+HRESULT CProgressImp::SetCompletedCD(UInt64 numFiles)
+{
+ return _callback->SetCompleted(&numFiles, NULL);
}
STDMETHODIMP CHandler::Open(IInStream *inStream,
@@ -359,12 +458,10 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
try
{
Close();
- RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
RINOK(m_Archive.Open(inStream, maxCheckStartPosition));
CProgressImp progressImp(callback);
- return m_Archive.ReadHeaders(m_Items, &progressImp);
+ return m_Archive.ReadHeaders(m_Items, callback ? &progressImp : NULL);
}
- catch(const CInArchiveException &) { Close(); return S_FALSE; }
catch(...) { Close(); throw; }
COM_TRY_END
}
@@ -467,26 +564,26 @@ HRESULT CZipDecoder::Decode(
bool needCRC = true;
bool wzAesMode = false;
bool pkAesMode = false;
- UInt16 methodId = item.CompressionMethod;
+ UInt16 methodId = item.Method;
if (item.IsEncrypted())
{
if (item.IsStrongEncrypted())
{
- CStrongCryptoField f;
- if (item.CentralExtra.GetStrongCryptoField(f))
+ CStrongCryptoExtra f;
+ if (item.CentralExtra.GetStrongCrypto(f))
{
pkAesMode = true;
}
if (!pkAesMode)
{
- res = NExtract::NOperationResult::kUnSupportedMethod;
+ res = NExtract::NOperationResult::kUnsupportedMethod;
return S_OK;
}
}
- if (methodId == NFileHeader::NCompressionMethod::kWzAES)
+ if (!pkAesMode && methodId == NFileHeader::NCompressionMethod::kWzAES)
{
- CWzAesExtraField aesField;
- if (item.CentralExtra.GetWzAesField(aesField))
+ CWzAesExtra aesField;
+ if (item.CentralExtra.GetWzAes(aesField))
{
wzAesMode = true;
needCRC = aesField.NeedCrc();
@@ -520,8 +617,8 @@ HRESULT CZipDecoder::Decode(
{
if (wzAesMode)
{
- CWzAesExtraField aesField;
- if (!item.CentralExtra.GetWzAesField(aesField))
+ CWzAesExtra aesField;
+ if (!item.CentralExtra.GetWzAes(aesField))
return S_OK;
methodId = aesField.Method;
if (!_wzAesDecoder)
@@ -562,31 +659,35 @@ HRESULT CZipDecoder::Decode(
CMyComBSTR password;
RINOK(getTextPassword->CryptoGetTextPassword(&password));
AString charPassword;
- if (wzAesMode || pkAesMode)
+ if (password)
{
- charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP);
- /*
- for (int i = 0;; i++)
+ if (wzAesMode || pkAesMode)
{
- wchar_t c = password[i];
- if (c == 0)
- break;
- if (c >= 0x80)
+ charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP);
+ /*
+ for (unsigned i = 0;; i++)
{
- res = NExtract::NOperationResult::kDataError;
- return S_OK;
+ wchar_t c = password[i];
+ if (c == 0)
+ break;
+ if (c >= 0x80)
+ {
+ res = NExtract::NOperationResult::kDataError;
+ return S_OK;
+ }
+ charPassword += (char)c;
}
- charPassword += (char)c;
+ */
+ }
+ else
+ {
+ /* pkzip25 / WinZip / Windows probably use ANSI for some files
+ We use OEM for compatibility with previous versions of 7-Zip? */
+ charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
}
- */
- }
- else
- {
- // we use OEM. WinZip/Windows probably use ANSI for some files
- charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
}
HRESULT result = cryptoSetPassword->CryptoSetPassword(
- (const Byte *)(const char *)charPassword, charPassword.Length());
+ (const Byte *)(const char *)charPassword, charPassword.Len());
if (result != S_OK)
return S_OK;
}
@@ -596,7 +697,7 @@ HRESULT CZipDecoder::Decode(
}
}
- int m;
+ unsigned m;
for (m = 0; m < methodItems.Size(); m++)
if (methodItems[m].ZipMethod == methodId)
break;
@@ -624,7 +725,7 @@ HRESULT CZipDecoder::Decode(
{
if (methodId > 0xFF)
{
- res = NExtract::NOperationResult::kUnSupportedMethod;
+ res = NExtract::NOperationResult::kUnsupportedMethod;
return S_OK;
}
szMethodID = kMethodId_ZipBase + (Byte)methodId;
@@ -634,7 +735,7 @@ HRESULT CZipDecoder::Decode(
if (mi.Coder == 0)
{
- res = NExtract::NOperationResult::kUnSupportedMethod;
+ res = NExtract::NOperationResult::kUnsupportedMethod;
return S_OK;
}
}
@@ -680,7 +781,7 @@ HRESULT CZipDecoder::Decode(
}
else if (pkAesMode)
{
- result =_pkAesDecoderSpec->ReadHeader(inStream, item.FileCRC, item.UnPackSize);
+ result =_pkAesDecoderSpec->ReadHeader(inStream, item.Crc, item.Size);
if (result == S_OK)
{
bool passwOK;
@@ -696,7 +797,16 @@ HRESULT CZipDecoder::Decode(
if (result == S_OK)
{
- RINOK(filterStreamSpec->SetInStream(inStream));
+ if (pkAesMode)
+ {
+ /* 9.31: The BUG in 9.24-9.30 was fixed. pkAes archives didn't work.
+ We don't need to call CAesCbcCoder::Init() to reset IV for data. */
+ filterStreamSpec->SetInStream_NoSubFilterInit(inStream);
+ }
+ else
+ {
+ RINOK(filterStreamSpec->SetInStream(inStream));
+ }
inStreamReleaser.FilterCoder = filterStreamSpec;
inStreamNew = filterStream;
if (wzAesMode)
@@ -709,12 +819,12 @@ HRESULT CZipDecoder::Decode(
else
inStreamNew = inStream;
if (result == S_OK)
- result = coder->Code(inStreamNew, outStream, NULL, &item.UnPackSize, compressProgress);
+ result = coder->Code(inStreamNew, outStream, NULL, &item.Size, compressProgress);
if (result == S_FALSE)
return S_OK;
if (result == E_NOTIMPL)
{
- res = NExtract::NOperationResult::kUnSupportedMethod;
+ res = NExtract::NOperationResult::kUnsupportedMethod;
return S_OK;
}
@@ -723,7 +833,7 @@ HRESULT CZipDecoder::Decode(
bool crcOK = true;
bool authOk = true;
if (needCRC)
- crcOK = (outStreamSpec->GetCRC() == item.FileCRC);
+ crcOK = (outStreamSpec->GetCRC() == item.Crc);
if (wzAesMode)
{
inStream.Attach(archive.CreateLimitedStream(authenticationPos, NCrypto::NWzAes::kMacSize));
@@ -744,7 +854,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_BEGIN
CZipDecoder myDecoder;
UInt64 totalUnPacked = 0, totalPacked = 0;
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = m_Items.Size();
if(numItems == 0)
@@ -753,7 +863,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
for (i = 0; i < numItems; i++)
{
const CItemEx &item = m_Items[allFilesMode ? i : indices[i]];
- totalUnPacked += item.UnPackSize;
+ totalUnPacked += item.Size;
totalPacked += item.PackSize;
}
RINOK(extractCallback->SetTotal(totalUnPacked));
@@ -765,7 +875,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
- for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked,
+ for (i = 0; i < numItems; i++,
+ currentTotalUnPacked += currentItemUnPacked,
currentTotalPacked += currentItemPacked)
{
currentItemUnPacked = 0;
@@ -779,11 +890,26 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
- Int32 index = allFilesMode ? i : indices[i];
+ 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));
- CItemEx item = m_Items[index];
+ if (!isLocalOffsetOK)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnavailable));
+ continue;
+ }
if (!item.FromLocal)
{
HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item);
@@ -793,14 +919,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
RINOK(extractCallback->PrepareOperation(askMode));
realOutStream.Release();
- RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kHeadersError));
}
continue;
}
RINOK(res);
}
- if (item.IsDir() || item.IgnoreItem())
+ if (item.IsDir())
{
// if (!testMode)
{
@@ -811,9 +937,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
continue;
}
- currentItemUnPacked = item.UnPackSize;
- currentItemPacked = item.PackSize;
-
if (!testMode && !realOutStream)
continue;
diff --git a/CPP/7zip/Archive/Zip/ZipHandler.h b/CPP/7zip/Archive/Zip/ZipHandler.h
index 33cf6fdc..7f1d2eba 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipHandler.h
+++ b/CPP/7zip/Archive/Zip/ZipHandler.h
@@ -3,7 +3,7 @@
#ifndef __ZIP_HANDLER_H
#define __ZIP_HANDLER_H
-#include "Common/DynamicBuffer.h"
+#include "../../../Common/DynamicBuffer.h"
#include "../../ICoder.h"
#include "../IArchive.h"
@@ -33,7 +33,7 @@ public:
INTERFACE_IInArchive(;)
INTERFACE_IOutArchive(;)
- STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties);
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps);
DECL_ISetCompressCodecsInfo
@@ -47,8 +47,11 @@ private:
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
@@ -58,8 +61,11 @@ private:
m_MainMethod = -1;
m_ForceAesMode = false;
m_WriteNtfsTimeExtra = true;
+ _removeSfxBlock = false;
m_ForceLocal = false;
m_ForceUtf8 = false;
+ _forceCodePage = false;
+ _specifiedCodePage = CP_OEMCP;
}
};
diff --git a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
index dd1ca136..ae58cbe2 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
+++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
@@ -2,12 +2,12 @@
#include "StdAfx.h"
-#include "Common/ComTry.h"
-#include "Common/StringConvert.h"
-#include "Common/StringToInt.h"
+#include "../../../Common/ComTry.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/TimeUtils.h"
#include "../../IPassword.h"
@@ -36,7 +36,7 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
static bool IsAsciiString(const UString &s)
{
- for (int i = 0; i < s.Length(); i++)
+ for (unsigned i = 0; i < s.Len(); i++)
{
wchar_t c = s[i];
if (c < 0x20 || c > 0x7F)
@@ -66,40 +66,48 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
IArchiveUpdateCallback *callback)
{
COM_TRY_BEGIN2
+
+ if (m_Archive.IsOpen())
+ {
+ if (!m_Archive.CanUpdate())
+ return E_NOTIMPL;
+ }
+
CObjectVector<CUpdateItem> updateItems;
bool thereAreAesUpdates = false;
UInt64 largestSize = 0;
bool largestSizeDefined = false;
+
for (UInt32 i = 0; i < numItems; i++)
{
CUpdateItem ui;
Int32 newData;
- Int32 newProperties;
+ Int32 newProps;
UInt32 indexInArchive;
if (!callback)
return E_FAIL;
- RINOK(callback->GetUpdateItemInfo(i, &newData, &newProperties, &indexInArchive));
- ui.NewProperties = IntToBool(newProperties);
+ RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
+ ui.NewProps = IntToBool(newProps);
ui.NewData = IntToBool(newData);
- ui.IndexInArchive = indexInArchive;
+ ui.IndexInArc = indexInArchive;
ui.IndexInClient = i;
- bool existInArchive = (indexInArchive != (UInt32)-1);
+ bool existInArchive = (indexInArchive != (UInt32)(Int32)-1);
if (existInArchive && newData)
if (m_Items[indexInArchive].IsAesEncrypted())
thereAreAesUpdates = true;
- if (IntToBool(newProperties))
+ if (IntToBool(newProps))
{
UString name;
{
NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, kpidAttrib, &prop));
if (prop.vt == VT_EMPTY)
- ui.Attributes = 0;
+ ui.Attrib = 0;
else if (prop.vt != VT_UI4)
return E_INVALIDARG;
else
- ui.Attributes = prop.ulVal;
+ ui.Attrib = prop.ulVal;
}
{
@@ -131,15 +139,15 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
else
ui.NtfsTimeIsDefined = m_WriteNtfsTimeExtra;
}
- RINOK(GetTime(callback, i, kpidMTime, ui.NtfsMTime));
- RINOK(GetTime(callback, i, kpidATime, ui.NtfsATime));
- RINOK(GetTime(callback, i, kpidCTime, ui.NtfsCTime));
+ 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.NtfsMTime.dwHighDateTime != 0 ||
- ui.NtfsMTime.dwLowDateTime != 0)
- if (!FileTimeToLocalFileTime(&ui.NtfsMTime, &localFileTime))
+ if (ui.Ntfs_MTime.dwHighDateTime != 0 ||
+ ui.Ntfs_MTime.dwLowDateTime != 0)
+ if (!FileTimeToLocalFileTime(&ui.Ntfs_MTime, &localFileTime))
return E_INVALIDARG;
FileTimeToDosTime(localFileTime, ui.Time);
}
@@ -159,25 +167,27 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (needSlash)
name += kSlash;
+ UINT codePage = _forceCodePage ? _specifiedCodePage : CP_OEMCP;
+
bool tryUtf8 = true;
- if (m_ForceLocal || !m_ForceUtf8)
+ if ((m_ForceLocal || !m_ForceUtf8) && codePage != CP_UTF8)
{
bool defaultCharWasUsed;
- ui.Name = UnicodeStringToMultiByte(name, CP_OEMCP, '_', defaultCharWasUsed);
+ ui.Name = UnicodeStringToMultiByte(name, codePage, '_', defaultCharWasUsed);
tryUtf8 = (!m_ForceLocal && (defaultCharWasUsed ||
- MultiByteToUnicodeString(ui.Name, CP_OEMCP) != name));
+ MultiByteToUnicodeString(ui.Name, codePage) != name));
}
if (tryUtf8)
{
- int i;
- for (i = 0; i < name.Length() && (unsigned)name[i] < 0x80; i++);
- ui.IsUtf8 = (i != name.Length());
+ unsigned i;
+ for (i = 0; i < name.Len() && (unsigned)name[i] < 0x80; i++);
+ ui.IsUtf8 = (i != name.Len());
if (!ConvertUnicodeToUTF8(name, ui.Name))
return E_INVALIDARG;
}
- if (ui.Name.Length() >= (1 << 16))
+ if (ui.Name.Len() >= (1 << 16))
return E_INVALIDARG;
ui.IndexInClient = i;
@@ -211,6 +221,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
largestSizeDefined = true;
}
ui.Size = size;
+ // ui.Size -= ui.Size / 2;
}
updateItems.Add(ui);
}
@@ -225,6 +236,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
options._dataSizeReduce = largestSize;
options._dataSizeReduceDefined = largestSizeDefined;
+ options.PasswordIsDefined = false;
+ options.Password.Empty();
if (getTextPassword)
{
CMyComBSTR password;
@@ -236,18 +249,17 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (!m_ForceAesMode)
options.IsAesMode = thereAreAesUpdates;
- if (!IsAsciiString((const wchar_t *)password))
+ if (!IsAsciiString((BSTR)password))
return E_INVALIDARG;
+ if (password)
+ options.Password = UnicodeStringToMultiByte((BSTR)password, CP_OEMCP);
if (options.IsAesMode)
{
- if (options.Password.Length() > NCrypto::NWzAes::kPasswordSizeMax)
+ if (options.Password.Len() > NCrypto::NWzAes::kPasswordSizeMax)
return E_INVALIDARG;
}
- options.Password = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
}
}
- else
- options.PasswordIsDefined = false;
Byte mainMethod;
if (m_MainMethod < 0)
@@ -263,68 +275,68 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return Update(
EXTERNAL_CODECS_VARS
m_Items, updateItems, outStream,
- m_Archive.IsOpen() ? &m_Archive : NULL, &options, callback);
+ m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock,
+ &options, callback);
+
COM_TRY_END2
}
struct CMethodIndexToName
{
unsigned Method;
- const wchar_t *Name;
+ const char *Name;
};
static const CMethodIndexToName k_SupportedMethods[] =
{
- { NFileHeader::NCompressionMethod::kStored, L"COPY" },
- { NFileHeader::NCompressionMethod::kDeflated, L"DEFLATE" },
- { NFileHeader::NCompressionMethod::kDeflated64, L"DEFLATE64" },
- { NFileHeader::NCompressionMethod::kBZip2, L"BZIP2" },
- { NFileHeader::NCompressionMethod::kLZMA, L"LZMA" },
- { NFileHeader::NCompressionMethod::kPPMd, L"PPMD" }
+ { NFileHeader::NCompressionMethod::kStored, "copy" },
+ { NFileHeader::NCompressionMethod::kDeflated, "deflate" },
+ { NFileHeader::NCompressionMethod::kDeflated64, "deflate64" },
+ { NFileHeader::NCompressionMethod::kBZip2, "bzip2" },
+ { NFileHeader::NCompressionMethod::kLZMA, "lzma" },
+ { NFileHeader::NCompressionMethod::kPPMd, "ppmd" }
};
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
-
-STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
{
InitMethodProps();
#ifndef _7ZIP_ST
const UInt32 numProcessors = _props.NumThreads;
#endif
- for (int i = 0; i < numProps; i++)
+ for (UInt32 i = 0; i < numProps; i++)
{
UString name = names[i];
- name.MakeUpper();
+ name.MakeLower_Ascii();
if (name.IsEmpty())
return E_INVALIDARG;
const PROPVARIANT &prop = values[i];
- if (name[0] == L'X')
+ if (name[0] == L'x')
{
UInt32 level = 9;
- RINOK(ParsePropToUInt32(name.Mid(1), prop, level));
+ RINOK(ParsePropToUInt32(name.Ptr(1), prop, level));
_props.Level = level;
_props.MethodInfo.AddLevelProp(level);
}
- else if (name == L"M")
+ else if (name == L"m")
{
if (prop.vt == VT_BSTR)
{
UString m = prop.bstrVal, m2;
- m.MakeUpper();
+ m.MakeLower_Ascii();
int colonPos = m.Find(L':');
if (colonPos >= 0)
{
- m2 = m.Mid(colonPos + 1);
- m = m.Left(colonPos);
+ m2 = m.Ptr(colonPos + 1);
+ m.DeleteFrom(colonPos);
}
- int k;
+ unsigned k;
for (k = 0; k < ARRAY_SIZE(k_SupportedMethods); k++)
{
const CMethodIndexToName &pair = k_SupportedMethods[k];
- if (m == pair.Name)
+ if (m.IsEqualTo(pair.Name))
{
if (!m2.IsEmpty())
{
@@ -339,7 +351,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v
}
else if (prop.vt == VT_UI4)
{
- int k;
+ unsigned k;
for (k = 0; k < ARRAY_SIZE(k_SupportedMethods); k++)
{
unsigned method = k_SupportedMethods[k].Method;
@@ -355,16 +367,16 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v
else
return E_INVALIDARG;
}
- else if (name.Left(2) == L"EM")
+ else if (name.IsPrefixedBy(L"em"))
{
if (prop.vt != VT_BSTR)
return E_INVALIDARG;
{
UString m = prop.bstrVal;
- m.MakeUpper();
- if (m.Left(3) == L"AES")
+ m.MakeLower_Ascii();
+ if (m.IsPrefixedBy(L"aes"))
{
- m = m.Mid(3);
+ m.DeleteFrontal(3);
if (m == L"128")
_props.AesKeyMode = 1;
else if (m == L"192")
@@ -376,7 +388,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v
_props.IsAesMode = true;
m_ForceAesMode = true;
}
- else if (m == L"ZIPCRYPTO")
+ else if (m == L"zipcrypto")
{
_props.IsAesMode = false;
m_ForceAesMode = true;
@@ -385,29 +397,40 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v
return E_INVALIDARG;
}
}
- else if (name.Left(2) == L"MT")
+ else if (name.IsPrefixedBy(L"mt"))
{
#ifndef _7ZIP_ST
- RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _props.NumThreads));
+ RINOK(ParseMtProp(name.Ptr(2), prop, numProcessors, _props.NumThreads));
_props.NumThreadsWasChanged = true;
#endif
}
- else if (name.CompareNoCase(L"TC") == 0)
+ else if (name.IsEqualTo("tc"))
{
RINOK(PROPVARIANT_to_bool(prop, m_WriteNtfsTimeExtra));
}
- else if (name.CompareNoCase(L"CL") == 0)
+ else if (name.IsEqualTo("cl"))
{
RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal));
if (m_ForceLocal)
m_ForceUtf8 = false;
}
- else if (name.CompareNoCase(L"CU") == 0)
+ 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
{
RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop));
diff --git a/CPP/7zip/Archive/Zip/ZipHeader.cpp b/CPP/7zip/Archive/Zip/ZipHeader.cpp
deleted file mode 100755
index 582187b5..00000000
--- a/CPP/7zip/Archive/Zip/ZipHeader.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-// Archive/Zip/Header.h
-
-#include "StdAfx.h"
-
-#include "ZipHeader.h"
-
-namespace NArchive {
-namespace NZip {
-
-namespace NSignature
-{
- UInt32 kLocalFileHeader = 0x04034B50 + 1;
- UInt32 kDataDescriptor = 0x08074B50 + 1;
- UInt32 kCentralFileHeader = 0x02014B50 + 1;
- UInt32 kEndOfCentralDir = 0x06054B50 + 1;
- UInt32 kZip64EndOfCentralDir = 0x06064B50 + 1;
- UInt32 kZip64EndOfCentralDirLocator = 0x07064B50 + 1;
-
- class CMarkersInitializer
- {
- public:
- CMarkersInitializer()
- {
- kLocalFileHeader--;
- kDataDescriptor--;
- kCentralFileHeader--;
- kEndOfCentralDir--;
- kZip64EndOfCentralDir--;
- kZip64EndOfCentralDirLocator--;
- }
- };
- static CMarkersInitializer g_MarkerInitializer;
-}
-
-}}
-
diff --git a/CPP/7zip/Archive/Zip/ZipHeader.h b/CPP/7zip/Archive/Zip/ZipHeader.h
index ce8c1e4f..1391cdf4 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipHeader.h
+++ b/CPP/7zip/Archive/Zip/ZipHeader.h
@@ -1,57 +1,39 @@
-// Archive/Zip/Header.h
+// ZipHeader.h
#ifndef __ARCHIVE_ZIP_HEADER_H
#define __ARCHIVE_ZIP_HEADER_H
-#include "Common/Types.h"
+#include "../../../Common/MyTypes.h"
namespace NArchive {
namespace NZip {
+const unsigned kMarkerSize = 4;
+
namespace NSignature
{
- extern UInt32 kLocalFileHeader;
- extern UInt32 kDataDescriptor;
- extern UInt32 kCentralFileHeader;
- extern UInt32 kEndOfCentralDir;
- extern UInt32 kZip64EndOfCentralDir;
- extern UInt32 kZip64EndOfCentralDirLocator;
-
- static const UInt32 kMarkerSize = 4;
+ const UInt32 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 UInt32 kEcdSize = 22;
-const UInt32 kZip64EcdSize = 44;
-const UInt32 kZip64EcdLocatorSize = 20;
-/*
-struct CEndOfCentralDirectoryRecord
-{
- UInt16 ThisDiskNumber;
- UInt16 StartCentralDirectoryDiskNumber;
- UInt16 NumEntriesInCentaralDirectoryOnThisDisk;
- UInt16 NumEntriesInCentaralDirectory;
- UInt32 CentralDirectorySize;
- UInt32 CentralDirectoryStartOffset;
- UInt16 CommentSize;
-};
+const unsigned kLocalHeaderSize = 4 + 26; // including signature
+const unsigned kDataDescriptorSize = 4 + 12; // including signature
+const unsigned kCentralHeaderSize = 4 + 42; // including signature
-struct CEndOfCentralDirectoryRecordFull
-{
- UInt32 Signature;
- CEndOfCentralDirectoryRecord Header;
-};
-*/
+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
{
- /*
- struct CVersion
- {
- Byte Version;
- Byte HostOS;
- };
- */
-
namespace NCompressionMethod
{
enum EType
@@ -77,7 +59,7 @@ namespace NFileHeader
kPPMd = 0x62,
kWzAES = 0x63
};
- const int kNumCompressionMethods = 11;
+
const Byte kMadeByProgramVersion = 63;
const Byte kExtractVersion_Default = 10;
@@ -90,8 +72,6 @@ namespace NFileHeader
const Byte kExtractVersion_Aes = 51;
const Byte kExtractVersion_LZMA = 63;
const Byte kExtractVersion_PPMd = 63;
-
- // const Byte kSupportedVersion = 20;
}
namespace NExtraID
@@ -127,155 +107,93 @@ namespace NFileHeader
};
}
- const UInt32 kLocalBlockSize = 26;
- /*
- struct CLocalBlock
- {
- CVersion ExtractVersion;
-
- UInt16 Flags;
- UInt16 CompressionMethod;
- UInt32 Time;
- UInt32 FileCRC;
- UInt32 PackSize;
- UInt32 UnPackSize;
- UInt16 NameSize;
- UInt16 ExtraSize;
- };
- */
-
- const UInt32 kDataDescriptorSize = 16;
- // const UInt32 kDataDescriptor64Size = 16 + 8;
- /*
- struct CDataDescriptor
- {
- UInt32 Signature;
- UInt32 FileCRC;
- UInt32 PackSize;
- UInt32 UnPackSize;
- };
-
- struct CLocalBlockFull
- {
- UInt32 Signature;
- CLocalBlock Header;
- };
- */
-
- const UInt32 kCentralBlockSize = 42;
- /*
- struct CBlock
- {
- CVersion MadeByVersion;
- CVersion ExtractVersion;
- UInt16 Flags;
- UInt16 CompressionMethod;
- UInt32 Time;
- UInt32 FileCRC;
- UInt32 PackSize;
- UInt32 UnPackSize;
- UInt16 NameSize;
- UInt16 ExtraSize;
- UInt16 CommentSize;
- UInt16 DiskNumberStart;
- UInt16 InternalAttributes;
- UInt32 ExternalAttributes;
- UInt32 LocalHeaderOffset;
- };
-
- struct CBlockFull
- {
- UInt32 Signature;
- CBlock Header;
- };
- */
-
namespace NFlags
{
- const int kEncrypted = 1 << 0;
- const int kLzmaEOS = 1 << 1;
- const int kDescriptorUsedMask = 1 << 3;
- const int kStrongEncrypted = 1 << 6;
- const int kUtf8 = 1 << 11;
-
- const int kImplodeDictionarySizeMask = 1 << 1;
- const int kImplodeLiteralsOnMask = 1 << 2;
+ const 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 kImplodeDictionarySizeMask = 1 << 1;
+ const unsigned kImplodeLiteralsOnMask = 1 << 2;
- const int kDeflateTypeBitStart = 1;
- const int kNumDeflateTypeBits = 2;
- const int kNumDeflateTypes = (1 << kNumDeflateTypeBits);
- const int kDeflateTypeMask = (1 << kNumDeflateTypeBits) - 1;
+ 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
+ kFAT = 0,
+ kAMIGA = 1,
+ kVMS = 2, // VAX/VMS
+ kUnix = 3,
+ kVM_CMS = 4,
+ kAtari = 5, // what if it's a minix filesystem? [cjh]
+ kHPFS = 6, // filesystem used by OS/2 (and NT 3.x)
+ kMac = 7,
+ kZ_System = 8,
+ kCPM = 9,
+ kTOPS20 = 10, // pkzip 2.50 NTFS
+ kNTFS = 11, // filesystem used by Windows NT
+ kQDOS = 12, // SMS/QDOS
+ kAcorn = 13, // Archimedes Acorn RISC OS
+ kVFAT = 14, // filesystem used by Windows 95, NT
+ kMVS = 15,
+ kBeOS = 16, // hybrid POSIX/database filesystem
+ kTandem = 17,
+ kOS400 = 18,
+ kOSX = 19
};
}
- namespace NUnixAttribute
+
+ namespace NUnixAttrib
{
- const UInt32 kIFMT = 0170000; /* Unix file type mask */
+ const UInt32 kIFMT = 0170000; // file type mask
- const UInt32 kIFDIR = 0040000; /* Unix directory */
- const UInt32 kIFREG = 0100000; /* Unix regular file */
- const UInt32 kIFSOCK = 0140000; /* Unix socket (BSD, not SysV or Amiga) */
- const UInt32 kIFLNK = 0120000; /* Unix symbolic link (not SysV, Amiga) */
- const UInt32 kIFBLK = 0060000; /* Unix block special (not Amiga) */
- const UInt32 kIFCHR = 0020000; /* Unix character special (not Amiga) */
- const UInt32 kIFIFO = 0010000; /* Unix fifo (BCC, not MSC or Amiga) */
+ const UInt32 kIFDIR = 0040000; // directory
+ const UInt32 kIFREG = 0100000; // regular file
+ const UInt32 kIFSOCK = 0140000; // socket (BSD, not SysV or Amiga)
+ const UInt32 kIFLNK = 0120000; // symbolic link (not SysV, Amiga)
+ const UInt32 kIFBLK = 0060000; // block special (not Amiga)
+ const UInt32 kIFCHR = 0020000; // character special (not Amiga)
+ const UInt32 kIFIFO = 0010000; // fifo (BCC, not MSC or Amiga)
- const UInt32 kISUID = 04000; /* Unix set user id on execution */
- const UInt32 kISGID = 02000; /* Unix set group id on execution */
- const UInt32 kISVTX = 01000; /* Unix directory permissions control */
- const UInt32 kENFMT = kISGID; /* Unix record locking enforcement flag */
- const UInt32 kIRWXU = 00700; /* Unix read, write, execute: owner */
- const UInt32 kIRUSR = 00400; /* Unix read permission: owner */
- const UInt32 kIWUSR = 00200; /* Unix write permission: owner */
- const UInt32 kIXUSR = 00100; /* Unix execute permission: owner */
- const UInt32 kIRWXG = 00070; /* Unix read, write, execute: group */
- const UInt32 kIRGRP = 00040; /* Unix read permission: group */
- const UInt32 kIWGRP = 00020; /* Unix write permission: group */
- const UInt32 kIXGRP = 00010; /* Unix execute permission: group */
- const UInt32 kIRWXO = 00007; /* Unix read, write, execute: other */
- const UInt32 kIROTH = 00004; /* Unix read permission: other */
- const UInt32 kIWOTH = 00002; /* Unix write permission: other */
- const UInt32 kIXOTH = 00001; /* Unix execute permission: other */
+ const UInt32 kISUID = 04000; // set user id on execution
+ const UInt32 kISGID = 02000; // set group id on execution
+ const UInt32 kISVTX = 01000; // directory permissions control
+ const UInt32 kENFMT = kISGID; // record locking enforcement flag
+ const UInt32 kIRWXU = 00700; // read, write, execute: owner
+ const UInt32 kIRUSR = 00400; // read permission: owner
+ const UInt32 kIWUSR = 00200; // write permission: owner
+ const UInt32 kIXUSR = 00100; // execute permission: owner
+ const UInt32 kIRWXG = 00070; // read, write, execute: group
+ const UInt32 kIRGRP = 00040; // read permission: group
+ const UInt32 kIWGRP = 00020; // write permission: group
+ const UInt32 kIXGRP = 00010; // execute permission: group
+ const UInt32 kIRWXO = 00007; // read, write, execute: other
+ const UInt32 kIROTH = 00004; // read permission: other
+ const UInt32 kIWOTH = 00002; // write permission: other
+ const UInt32 kIXOTH = 00001; // execute permission: other
}
- namespace NAmigaAttribute
+ 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 */
+ 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
}
}
diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp
index e930488f..345fbf56 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipIn.cpp
+++ b/CPP/7zip/Archive/Zip/ZipIn.cpp
@@ -2,13 +2,15 @@
#include "StdAfx.h"
-#include "../../../../C/CpuArch.h"
+// #include <stdio.h>
-#include "Common/DynamicBuffer.h"
+#include "../../../Common/DynamicBuffer.h"
#include "../../Common/LimitedStreams.h"
#include "../../Common/StreamUtils.h"
+#include "../IArchive.h"
+
#include "ZipIn.h"
#define Get16(p) GetUi16(p)
@@ -17,100 +19,342 @@
namespace NArchive {
namespace NZip {
-
+
+struct CEcd
+{
+ UInt16 thisDiskNumber;
+ UInt16 startCDDiskNumber;
+ UInt16 numEntriesInCDOnThisDisk;
+ UInt16 numEntriesInCD;
+ UInt32 cdSize;
+ UInt32 cdStartOffset;
+ UInt16 commentSize;
+
+ void Parse(const Byte *p);
+
+ bool IsEmptyArc()
+ {
+ return thisDiskNumber == 0 && startCDDiskNumber == 0 &&
+ numEntriesInCDOnThisDisk == 0 && numEntriesInCD == 0 && cdSize == 0
+ && cdStartOffset == 0 // test it
+ ;
+ }
+};
+
+void CEcd::Parse(const Byte *p)
+{
+ thisDiskNumber = Get16(p);
+ startCDDiskNumber = Get16(p + 2);
+ numEntriesInCDOnThisDisk = Get16(p + 4);
+ numEntriesInCD = Get16(p + 6);
+ cdSize = Get32(p + 8);
+ cdStartOffset = Get32(p + 12);
+ commentSize = Get16(p + 16);
+}
+
+struct CEcd64
+{
+ UInt16 versionMade;
+ UInt16 versionNeedExtract;
+ UInt32 thisDiskNumber;
+ UInt32 startCDDiskNumber;
+ UInt64 numEntriesInCDOnThisDisk;
+ UInt64 numEntriesInCD;
+ UInt64 cdSize;
+ UInt64 cdStartOffset;
+
+ void Parse(const Byte *p);
+ CEcd64() { memset(this, 0, sizeof(*this)); }
+};
+
+void CEcd64::Parse(const Byte *p)
+{
+ versionMade = Get16(p);
+ versionNeedExtract = Get16(p + 2);
+ thisDiskNumber = Get32(p + 4);
+ startCDDiskNumber = Get32(p + 8);
+ numEntriesInCDOnThisDisk = Get64(p + 12);
+ numEntriesInCD = Get64(p + 20);
+ cdSize = Get64(p + 28);
+ cdStartOffset = Get64(p + 36);
+}
+
HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
{
_inBufMode = false;
Close();
- RINOK(stream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition));
- m_Position = m_StreamStartPosition;
+ RINOK(stream->Seek(0, STREAM_SEEK_CUR, &m_Position));
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &ArcInfo.FileEndPos));
+ RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
+
+ // printf("\nOpen offset = %d", (int)m_Position);
RINOK(FindAndReadMarker(stream, searchHeaderSizeLimit));
RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
- m_Stream = stream;
+ Stream = stream;
return S_OK;
}
void CInArchive::Close()
{
- _inBuffer.ReleaseStream();
- m_Stream.Release();
+ IsArc = false;
+ HeadersError = false;
+ HeadersWarning = false;
+ ExtraMinorError = false;
+ UnexpectedEnd = false;
+ NoCentralDir = false;
+ IsZip64 = false;
+ Stream.Release();
}
HRESULT CInArchive::Seek(UInt64 offset)
{
- return m_Stream->Seek(offset, STREAM_SEEK_SET, NULL);
+ return Stream->Seek(offset, STREAM_SEEK_SET, NULL);
}
-//////////////////////////////////////
-// Markers
+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;
+}
-static inline bool TestMarkerCandidate(const Byte *p, UInt32 &value)
+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 value = Get32(p);
+
+ if (value == NSignature::kNoSpan)
+ {
+ p += 4;
+ size -= 4;
+ }
+
value = Get32(p);
- return
- (value == NSignature::kLocalFileHeader) ||
- (value == NSignature::kEndOfCentralDir);
+
+ if (value == 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 (value != 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);
+ unsigned nameSize = Get16(p + 22);
+ unsigned extraSize = Get16(p + 24);
+ 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)
+ 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)
+ return k_IsArc_Res_NO;
+ if (dataSize > size)
+ return k_IsArc_Res_NEED_MORE;
+ size -= dataSize;
+ extraSize -= dataSize;
+ p += dataSize;
+ }
+ }
+
+ return k_IsArc_Res_YES;
}
-static const UInt32 kNumMarkerAddtionalBytes = 2;
-static inline bool TestMarkerCandidate2(const Byte *p, UInt32 &value)
+static UInt32 IsArc_Zip_2(const Byte *p, size_t size, bool isFinal)
{
- value = Get32(p);
- if (value == NSignature::kEndOfCentralDir)
- return (Get16(p + 4) == 0);
- return (value == NSignature::kLocalFileHeader && p[4] < 128);
+ UInt32 res = IsArc_Zip(p, size);
+ if (res == k_IsArc_Res_NEED_MORE && isFinal)
+ return k_IsArc_Res_NO;
+ return res;
}
-HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchLimit)
{
ArcInfo.Clear();
- m_Position = m_StreamStartPosition;
+ ArcInfo.MarkerPos = m_Position;
+ ArcInfo.MarkerPos2 = m_Position;
- Byte marker[NSignature::kMarkerSize];
- RINOK(ReadStream_FALSE(stream, marker, NSignature::kMarkerSize));
- m_Position += NSignature::kMarkerSize;
- if (TestMarkerCandidate(marker, m_Signature))
- return S_OK;
+ if (searchLimit && *searchLimit == 0)
+ {
+ const unsigned kStartBufSize = kMarkerSize;
+ Byte startBuf[kStartBufSize];
+ size_t processed = kStartBufSize;
+ RINOK(ReadStream(stream, startBuf, &processed));
+ m_Position += processed;
+ if (processed < kMarkerSize)
+ return S_FALSE;
+ m_Signature = Get32(startBuf);
+ if (m_Signature != NSignature::kEcd &&
+ m_Signature != NSignature::kLocalFileHeader)
+ {
+ if (m_Signature != NSignature::kNoSpan)
+ return S_FALSE;
+ size_t processed = kStartBufSize;
+ RINOK(ReadStream(stream, startBuf, &processed));
+ m_Position += processed;
+ if (processed < kMarkerSize)
+ return S_FALSE;
+ m_Signature = Get32(startBuf);
+ if (m_Signature != NSignature::kEcd &&
+ m_Signature != NSignature::kLocalFileHeader)
+ return S_FALSE;
+ ArcInfo.MarkerPos2 += 4;
+ }
+
+ // we use weak test in case of *searchLimit == 0)
+ // since error will be detected later in Open function
+ // m_Position = ArcInfo.MarkerPos2 + 4;
+ return S_OK; // maybe we need to search backward.
+ }
+
+ const size_t kBufSize = (size_t)1 << 18; // must be larger than kCheckSize
+ const size_t kCheckSize = (size_t)1 << 16; // must be smaller than kBufSize
+ CByteArr buffer(kBufSize);
+
+ size_t numBytesInBuffer = 0;
+ UInt64 curScanPos = 0;
- CByteDynamicBuffer dynamicBuffer;
- const UInt32 kSearchMarkerBufferSize = 0x10000;
- dynamicBuffer.EnsureCapacity(kSearchMarkerBufferSize);
- Byte *buffer = dynamicBuffer;
- UInt32 numBytesPrev = NSignature::kMarkerSize - 1;
- memcpy(buffer, marker + 1, numBytesPrev);
- UInt64 curTestPos = m_StreamStartPosition + 1;
for (;;)
{
- if (searchHeaderSizeLimit != NULL)
- if (curTestPos - m_StreamStartPosition > *searchHeaderSizeLimit)
- break;
- size_t numReadBytes = kSearchMarkerBufferSize - numBytesPrev;
- RINOK(ReadStream(stream, buffer + numBytesPrev, &numReadBytes));
+ size_t numReadBytes = kBufSize - numBytesInBuffer;
+ RINOK(ReadStream(stream, buffer + numBytesInBuffer, &numReadBytes));
m_Position += numReadBytes;
- UInt32 numBytesInBuffer = numBytesPrev + (UInt32)numReadBytes;
- const UInt32 kMarker2Size = NSignature::kMarkerSize + kNumMarkerAddtionalBytes;
- if (numBytesInBuffer < kMarker2Size)
+ numBytesInBuffer += numReadBytes;
+ bool isFinished = (numBytesInBuffer != kBufSize);
+
+ size_t limit = (isFinished ? numBytesInBuffer : numBytesInBuffer - kCheckSize);
+
+ if (searchLimit && curScanPos + limit > *searchLimit)
+ limit = (size_t)(*searchLimit - curScanPos + 1);
+
+ if (limit < 1)
break;
- UInt32 numTests = numBytesInBuffer - kMarker2Size + 1;
- for (UInt32 pos = 0; pos < numTests; pos++)
+
+ const Byte *buf = buffer;
+ for (size_t pos = 0; pos < limit; pos++)
{
- if (buffer[pos] != 0x50)
+ if (buf[pos] != 0x50)
+ continue;
+ if (buf[pos + 1] != 0x4B)
continue;
- if (TestMarkerCandidate2(buffer + pos, m_Signature))
+ size_t rem = numBytesInBuffer - pos;
+ UInt32 res = IsArc_Zip_2(buf + pos, rem, isFinished);
+ if (res != k_IsArc_Res_NO)
{
- curTestPos += pos;
- ArcInfo.StartPosition = curTestPos;
- m_Position = curTestPos + NSignature::kMarkerSize;
+ if (rem < kMarkerSize)
+ return S_FALSE;
+ m_Signature = Get32(buf + pos);
+ ArcInfo.MarkerPos += curScanPos + pos;
+ ArcInfo.MarkerPos2 = ArcInfo.MarkerPos;
+ if (m_Signature == NSignature::kNoSpan)
+ {
+ m_Signature = Get32(buf + pos + 4);
+ ArcInfo.MarkerPos2 += 4;
+ }
+ m_Position = ArcInfo.MarkerPos2 + kMarkerSize;
return S_OK;
}
}
- curTestPos += numTests;
- numBytesPrev = numBytesInBuffer - numTests;
- memmove(buffer, buffer + numTests, numBytesPrev);
+
+ if (isFinished)
+ break;
+
+ curScanPos += limit;
+ numBytesInBuffer -= limit;
+ memmove(buffer, buffer + limit, numBytesInBuffer);
}
+
return S_FALSE;
}
+HRESULT CInArchive::IncreaseRealPosition(UInt64 addValue)
+{
+ return Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position);
+}
+
+class CUnexpectEnd {};
+
HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize)
{
size_t realProcessedSize = size;
@@ -121,42 +365,35 @@ HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize)
catch (const CInBufferException &e) { return e.ErrorCode; }
}
else
- result = ReadStream(m_Stream, data, &realProcessedSize);
- if (processedSize != NULL)
+ result = ReadStream(Stream, data, &realProcessedSize);
+ if (processedSize)
*processedSize = (UInt32)realProcessedSize;
m_Position += realProcessedSize;
return result;
}
-void CInArchive::Skip(UInt64 num)
-{
- for (UInt64 i = 0; i < num; i++)
- ReadByte();
-}
-
-void CInArchive::IncreaseRealPosition(UInt64 addValue)
-{
- if (m_Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position) != S_OK)
- throw CInArchiveException(CInArchiveException::kSeekStreamError);
-}
-
-bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size)
-{
- UInt32 realProcessedSize;
- if (ReadBytes(data, size, &realProcessedSize) != S_OK)
- throw CInArchiveException(CInArchiveException::kReadStreamError);
- return (realProcessedSize == size);
-}
-
-void CInArchive::SafeReadBytes(void *data, UInt32 size)
+void CInArchive::SafeReadBytes(void *data, unsigned size)
{
- if (!ReadBytesAndTestSize(data, size))
- throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
+ size_t processed = size;
+ if (_inBufMode)
+ {
+ processed = _inBuffer.ReadBytes((Byte *)data, size);
+ m_Position += processed;
+ }
+ else
+ {
+ HRESULT result = ReadStream(Stream, data, &processed);
+ m_Position += processed;
+ if (result != S_OK)
+ throw CSystemException(result);
+ }
+ if (processed != size)
+ throw CUnexpectEnd();
}
-void CInArchive::ReadBuffer(CByteBuffer &buffer, UInt32 size)
+void CInArchive::ReadBuffer(CByteBuffer &buffer, unsigned size)
{
- buffer.SetCapacity(size);
+ buffer.Alloc(size);
if (size > 0)
SafeReadBytes(buffer, size);
}
@@ -168,65 +405,73 @@ Byte CInArchive::ReadByte()
return b;
}
-UInt16 CInArchive::ReadUInt16()
-{
- Byte buf[2];
- SafeReadBytes(buf, 2);
- return Get16(buf);
-}
+UInt16 CInArchive::ReadUInt16() { Byte buf[2]; SafeReadBytes(buf, 2); return Get16(buf); }
+UInt32 CInArchive::ReadUInt32() { Byte buf[4]; SafeReadBytes(buf, 4); return Get32(buf); }
+UInt64 CInArchive::ReadUInt64() { Byte buf[8]; SafeReadBytes(buf, 8); return Get64(buf); }
-UInt32 CInArchive::ReadUInt32()
+void CInArchive::Skip(unsigned num)
{
- Byte buf[4];
- SafeReadBytes(buf, 4);
- return Get32(buf);
+ if (_inBufMode)
+ {
+ size_t skip = _inBuffer.Skip(num);
+ m_Position += skip;
+ if (skip != num)
+ throw CUnexpectEnd();
+ }
+ else
+ {
+ for (unsigned i = 0; i < num; i++)
+ ReadByte();
+ }
}
-UInt64 CInArchive::ReadUInt64()
+void CInArchive::Skip64(UInt64 num)
{
- Byte buf[8];
- SafeReadBytes(buf, 8);
- return Get64(buf);
+ for (UInt64 i = 0; i < num; i++)
+ ReadByte();
}
-bool CInArchive::ReadUInt32(UInt32 &value)
-{
- Byte buf[4];
- if (!ReadBytesAndTestSize(buf, 4))
- return false;
- value = Get32(buf);
- return true;
-}
-void CInArchive::ReadFileName(UInt32 nameSize, AString &dest)
+void CInArchive::ReadFileName(unsigned size, AString &s)
{
- if (nameSize == 0)
- dest.Empty();
- char *p = dest.GetBuffer((int)nameSize);
- SafeReadBytes(p, nameSize);
- p[nameSize] = 0;
- dest.ReleaseBuffer();
+ if (size == 0)
+ {
+ s.Empty();
+ return;
+ }
+ char *p = s.GetBuffer(size);
+ SafeReadBytes(p, size);
+ p[size] = 0;
+ s.ReleaseBuffer();
}
-void CInArchive::ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock,
+bool CInArchive::ReadExtra(unsigned extraSize, CExtraBlock &extraBlock,
UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber)
{
extraBlock.Clear();
UInt32 remain = extraSize;
- while(remain >= 4)
+ while (remain >= 4)
{
CExtraSubBlock subBlock;
subBlock.ID = ReadUInt16();
- UInt32 dataSize = ReadUInt16();
+ unsigned dataSize = ReadUInt16();
remain -= 4;
if (dataSize > remain) // it's bug
- dataSize = remain;
+ {
+ HeadersWarning = true;
+ Skip(remain);
+ return false;
+ }
if (subBlock.ID == NFileHeader::NExtraID::kZip64)
{
if (unpackSize == 0xFFFFFFFF)
{
if (dataSize < 8)
- break;
+ {
+ HeadersWarning = true;
+ Skip(remain);
+ return false;
+ }
unpackSize = ReadUInt64();
remain -= 8;
dataSize -= 8;
@@ -255,8 +500,7 @@ void CInArchive::ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock,
remain -= 4;
dataSize -= 4;
}
- for (UInt32 i = 0; i < dataSize; i++)
- ReadByte();
+ Skip(dataSize);
}
else
{
@@ -265,88 +509,125 @@ void CInArchive::ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock,
}
remain -= dataSize;
}
+ if (remain != 0)
+ {
+ ExtraMinorError = 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(remain);
+ return true;
}
-HRESULT CInArchive::ReadLocalItem(CItemEx &item)
+bool CInArchive::ReadLocalItem(CItemEx &item)
{
- const int kBufSize = 26;
- Byte p[kBufSize];
- SafeReadBytes(p, kBufSize);
+ const unsigned kPureHeaderSize = kLocalHeaderSize - 4;
+ Byte p[kPureHeaderSize];
+ SafeReadBytes(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];
item.Flags = Get16(p + 2);
- item.CompressionMethod = Get16(p + 4);
+ item.Method = Get16(p + 4);
item.Time = Get32(p + 6);
- item.FileCRC = Get32(p + 10);
+ item.Crc = Get32(p + 10);
item.PackSize = Get32(p + 14);
- item.UnPackSize = Get32(p + 18);
- UInt32 fileNameSize = Get16(p + 22);
- item.LocalExtraSize = Get16(p + 24);
- ReadFileName(fileNameSize, item.Name);
- item.FileHeaderWithNameSize = 4 + NFileHeader::kLocalBlockSize + fileNameSize;
- if (item.LocalExtraSize > 0)
+ item.Size = Get32(p + 18);
+ unsigned nameSize = Get16(p + 22);
+ unsigned extraSize = Get16(p + 24);
+ ReadFileName(nameSize, item.Name);
+ item.LocalFullHeaderSize = kLocalHeaderSize + (UInt32)nameSize + extraSize;
+
+ /*
+ if (item.IsDir())
+ item.Size = 0; // check It
+ */
+
+ if (extraSize > 0)
{
UInt64 localHeaderOffset = 0;
UInt32 diskStartNumber = 0;
- ReadExtra(item.LocalExtraSize, item.LocalExtra, item.UnPackSize, item.PackSize,
- localHeaderOffset, diskStartNumber);
+ if (!ReadExtra(extraSize, item.LocalExtra, item.Size, item.PackSize,
+ localHeaderOffset, diskStartNumber))
+ return false;
}
- /*
- if (item.IsDir())
- item.UnPackSize = 0; // check It
- */
- return S_OK;
+ if (!CheckDosTime(item.Time))
+ {
+ HeadersWarning = true;
+ // return false;
+ }
+ if (item.Name.Len() != nameSize)
+ return false;
+ return item.LocalFullHeaderSize <= ((UInt32)1 << 16);
}
-static bool FlagsAreSame(CItem &i1, CItem &i2)
+static bool FlagsAreSame(const CItem &i1, const CItem &i2)
{
- if (i1.CompressionMethod != i2.CompressionMethod)
+ if (i1.Method != i2.Method)
return false;
- // i1.Time
-
if (i1.Flags == i2.Flags)
return true;
UInt32 mask = 0xFFFF;
- switch(i1.CompressionMethod)
+ switch(i1.Method)
{
case NFileHeader::NCompressionMethod::kDeflated:
mask = 0x7FF9;
break;
default:
- if (i1.CompressionMethod <= NFileHeader::NCompressionMethod::kImploded)
+ if (i1.Method <= NFileHeader::NCompressionMethod::kImploded)
mask = 0x7FFF;
}
return ((i1.Flags & mask) == (i2.Flags & mask));
}
+static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem)
+{
+ if (!FlagsAreSame(cdItem, localItem))
+ return false;
+ if (!localItem.HasDescriptor())
+ {
+ if (cdItem.Crc != localItem.Crc ||
+ cdItem.PackSize != localItem.PackSize ||
+ cdItem.Size != localItem.Size)
+ 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)
+ return false;
+ return true;
+}
+
HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item)
{
if (item.FromLocal)
return S_OK;
try
{
- RINOK(Seek(ArcInfo.Base + item.LocalHeaderPosition));
+ UInt64 offset = ArcInfo.Base + item.LocalHeaderPos;
+ if (ArcInfo.Base < 0 && (Int64)offset < 0)
+ return S_FALSE;
+ RINOK(Seek(offset));
CItemEx localItem;
if (ReadUInt32() != NSignature::kLocalFileHeader)
return S_FALSE;
- RINOK(ReadLocalItem(localItem));
- if (!FlagsAreSame(item, localItem))
+ ReadLocalItem(localItem);
+ if (!AreItemsEqual(localItem, item))
return S_FALSE;
-
- if ((!localItem.HasDescriptor() &&
- (
- item.FileCRC != localItem.FileCRC ||
- item.PackSize != localItem.PackSize ||
- item.UnPackSize != localItem.UnPackSize
- )
- ) ||
- item.Name.Length() != localItem.Name.Length()
- )
- return S_FALSE;
- item.FileHeaderWithNameSize = localItem.FileHeaderWithNameSize;
- item.LocalExtraSize = localItem.LocalExtraSize;
+ item.LocalFullHeaderSize = localItem.LocalFullHeaderSize;
item.LocalExtra = localItem.LocalExtra;
item.FromLocal = true;
}
@@ -356,53 +637,45 @@ HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item)
HRESULT CInArchive::ReadLocalItemDescriptor(CItemEx &item)
{
- if (item.HasDescriptor())
+ const unsigned kBufSize = (1 << 12);
+ Byte buf[kBufSize];
+
+ UInt32 numBytesInBuffer = 0;
+ UInt32 packedSize = 0;
+
+ for (;;)
{
- const int kBufferSize = (1 << 12);
- Byte buffer[kBufferSize];
-
- UInt32 numBytesInBuffer = 0;
- UInt32 packedSize = 0;
-
- bool descriptorWasFound = false;
- for (;;)
+ UInt32 processedSize;
+ RINOK(ReadBytes(buf + numBytesInBuffer, kBufSize - numBytesInBuffer, &processedSize));
+ numBytesInBuffer += processedSize;
+ if (numBytesInBuffer < kDataDescriptorSize)
+ return S_FALSE;
+ UInt32 i;
+ for (i = 0; i <= numBytesInBuffer - kDataDescriptorSize; i++)
{
- UInt32 processedSize;
- RINOK(ReadBytes(buffer + numBytesInBuffer, kBufferSize - numBytesInBuffer, &processedSize));
- numBytesInBuffer += processedSize;
- if (numBytesInBuffer < NFileHeader::kDataDescriptorSize)
- return S_FALSE;
- UInt32 i;
- for (i = 0; i <= numBytesInBuffer - NFileHeader::kDataDescriptorSize; i++)
+ // descriptor signature field is Info-ZIP's extension to pkware Zip specification.
+ // New ZIP specification also allows descriptorSignature.
+ if (buf[i] != 0x50)
+ continue;
+ // !!!! It must be fixed for Zip64 archives
+ if (Get32(buf + i) == NSignature::kDataDescriptor)
{
- // descriptorSignature field is Info-ZIP's extension
- // to Zip specification.
- UInt32 descriptorSignature = Get32(buffer + i);
-
- // !!!! It must be fixed for Zip64 archives
- UInt32 descriptorPackSize = Get32(buffer + i + 8);
- if (descriptorSignature== NSignature::kDataDescriptor && descriptorPackSize == packedSize + i)
+ UInt32 descriptorPackSize = Get32(buf + i + 8);
+ if (descriptorPackSize == packedSize + i)
{
- descriptorWasFound = true;
- item.FileCRC = Get32(buffer + i + 4);
+ item.Crc = Get32(buf + i + 4);
item.PackSize = descriptorPackSize;
- item.UnPackSize = Get32(buffer + i + 12);
- IncreaseRealPosition(Int64(Int32(0 - (numBytesInBuffer - i - NFileHeader::kDataDescriptorSize))));
- break;
+ item.Size = Get32(buf + i + 12);
+ return IncreaseRealPosition(Int64(Int32(0 - (numBytesInBuffer - i - kDataDescriptorSize))));
}
}
- if (descriptorWasFound)
- break;
- packedSize += i;
- int j;
- for (j = 0; i < numBytesInBuffer; i++, j++)
- buffer[j] = buffer[i];
- numBytesInBuffer = j;
}
+ packedSize += i;
+ unsigned j;
+ for (j = 0; i < numBytesInBuffer; i++, j++)
+ buf[j] = buf[i];
+ numBytesInBuffer = j;
}
- else
- IncreaseRealPosition(item.PackSize);
- return S_OK;
}
HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item)
@@ -433,7 +706,7 @@ HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item)
unpackSize = ReadUInt32();
}
- if (crc != item.FileCRC || item.PackSize != packSize || item.UnPackSize != unpackSize)
+ if (crc != item.Crc || item.PackSize != packSize || item.Size != unpackSize)
return S_FALSE;
}
}
@@ -444,106 +717,161 @@ HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item)
HRESULT CInArchive::ReadCdItem(CItemEx &item)
{
item.FromCentral = true;
- const int kBufSize = 42;
- Byte p[kBufSize];
- SafeReadBytes(p, kBufSize);
+ Byte p[kCentralHeaderSize - 4];
+ SafeReadBytes(p, kCentralHeaderSize - 4);
+
item.MadeByVersion.Version = p[0];
item.MadeByVersion.HostOS = p[1];
item.ExtractVersion.Version = p[2];
item.ExtractVersion.HostOS = p[3];
item.Flags = Get16(p + 4);
- item.CompressionMethod = Get16(p + 6);
+ item.Method = Get16(p + 6);
item.Time = Get32(p + 8);
- item.FileCRC = Get32(p + 12);
+ item.Crc = Get32(p + 12);
item.PackSize = Get32(p + 16);
- item.UnPackSize = Get32(p + 20);
- UInt16 headerNameSize = Get16(p + 24);
- UInt16 headerExtraSize = Get16(p + 26);
- UInt16 headerCommentSize = Get16(p + 28);
- UInt32 headerDiskNumberStart = Get16(p + 30);
- item.InternalAttributes = Get16(p + 32);
- item.ExternalAttributes = Get32(p + 34);
- item.LocalHeaderPosition = Get32(p + 38);
- ReadFileName(headerNameSize, item.Name);
+ item.Size = Get32(p + 20);
+ unsigned nameSize = Get16(p + 24);
+ UInt16 extraSize = Get16(p + 26);
+ UInt16 commentSize = Get16(p + 28);
+ UInt32 diskNumberStart = Get16(p + 30);
+ item.InternalAttrib = Get16(p + 32);
+ item.ExternalAttrib = Get32(p + 34);
+ item.LocalHeaderPos = Get32(p + 38);
+ ReadFileName(nameSize, item.Name);
- if (headerExtraSize > 0)
+ if (extraSize > 0)
{
- ReadExtra(headerExtraSize, item.CentralExtra, item.UnPackSize, item.PackSize,
- item.LocalHeaderPosition, headerDiskNumberStart);
+ ReadExtra(extraSize, item.CentralExtra, item.Size, item.PackSize,
+ item.LocalHeaderPos, diskNumberStart);
}
- if (headerDiskNumberStart != 0)
- throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported);
+ if (diskNumberStart != 0)
+ return E_NOTIMPL;
// May be these strings must be deleted
/*
if (item.IsDir())
- item.UnPackSize = 0;
+ item.Size = 0;
*/
- ReadBuffer(item.Comment, headerCommentSize);
+ ReadBuffer(item.Comment, commentSize);
return S_OK;
}
+void CCdInfo::ParseEcd(const Byte *p)
+{
+ NumEntries = Get16(p + 10);
+ Size = Get32(p + 12);
+ Offset = Get32(p + 16);
+}
+
+void CCdInfo::ParseEcd64(const Byte *p)
+{
+ NumEntries = Get64(p + 24);
+ Size = Get64(p + 40);
+ Offset = Get64(p + 48);
+}
+
HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo)
{
+ if (offset >= ((UInt64)1 << 63))
+ return S_FALSE;
RINOK(Seek(offset));
- const UInt32 kEcd64Size = 56;
- Byte buf[kEcd64Size];
- if (!ReadBytesAndTestSize(buf, kEcd64Size))
+ Byte buf[kEcd64_FullSize];
+
+ RINOK(ReadStream_FALSE(Stream, buf, kEcd64_FullSize));
+
+ if (Get32(buf) != NSignature::kEcd64)
return S_FALSE;
- if (Get32(buf) != NSignature::kZip64EndOfCentralDir)
+ UInt64 mainSize = Get64(buf + 4);
+ if (mainSize < kEcd64_MainSize || mainSize > ((UInt64)1 << 32))
return S_FALSE;
- // cdInfo.NumEntries = Get64(buf + 24);
- cdInfo.Size = Get64(buf + 40);
- cdInfo.Offset = Get64(buf + 48);
+ cdInfo.ParseEcd64(buf);
return S_OK;
}
HRESULT CInArchive::FindCd(CCdInfo &cdInfo)
{
UInt64 endPosition;
- RINOK(m_Stream->Seek(0, STREAM_SEEK_END, &endPosition));
- const UInt32 kBufSizeMax = (1 << 16) + kEcdSize + kZip64EcdLocatorSize;
- CByteBuffer byteBuffer;
- byteBuffer.SetCapacity(kBufSizeMax);
- Byte *buf = byteBuffer;
+ RINOK(Stream->Seek(0, STREAM_SEEK_END, &endPosition));
+
+ const UInt32 kBufSizeMax = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize;
UInt32 bufSize = (endPosition < kBufSizeMax) ? (UInt32)endPosition : kBufSizeMax;
if (bufSize < kEcdSize)
return S_FALSE;
+ CByteArr byteBuffer(bufSize);
+
UInt64 startPosition = endPosition - bufSize;
- RINOK(m_Stream->Seek(startPosition, STREAM_SEEK_SET, &m_Position));
+ RINOK(Stream->Seek(startPosition, STREAM_SEEK_SET, &m_Position));
if (m_Position != startPosition)
return S_FALSE;
- if (!ReadBytesAndTestSize(buf, bufSize))
- return S_FALSE;
- for (int i = (int)(bufSize - kEcdSize); i >= 0; i--)
+
+ RINOK(ReadStream_FALSE(Stream, byteBuffer, bufSize));
+
+ const Byte *buf = byteBuffer;
+ for (UInt32 i = bufSize - kEcdSize;; i--)
{
- if (Get32(buf + i) == NSignature::kEndOfCentralDir)
+ if (buf[i] != 0x50)
{
- if (i >= kZip64EcdLocatorSize)
+ if (i == 0) return S_FALSE;
+ i--;
+ if (buf[i] != 0x50)
{
- const Byte *locator = buf + i - kZip64EcdLocatorSize;
- if (Get32(locator) == NSignature::kZip64EndOfCentralDirLocator)
+ if (i == 0) return S_FALSE;
+ continue;
+ }
+ }
+ if (Get32(buf + i) == NSignature::kEcd)
+ {
+ if (i >= kEcd64_FullSize + kEcd64Locator_Size)
+ {
+ const Byte *locator = buf + i - kEcd64Locator_Size;
+ if (Get32(locator) == NSignature::kEcd64Locator &&
+ Get32(locator + 4) == 0) // number of the disk with the start of the zip64 ECD
{
+ // Most of the zip64 use fixed size Zip64 ECD
+
UInt64 ecd64Offset = Get64(locator + 8);
- if (TryEcd64(ecd64Offset, cdInfo) == S_OK)
- return S_OK;
- if (TryEcd64(ArcInfo.StartPosition + ecd64Offset, cdInfo) == S_OK)
+ UInt64 absEcd64 = endPosition - bufSize + i - (kEcd64Locator_Size + kEcd64_FullSize);
+ {
+ const Byte *ecd64 = locator - kEcd64_FullSize;
+ if (Get32(ecd64) == NSignature::kEcd64 &&
+ Get64(ecd64 + 4) == kEcd64_MainSize)
+ {
+ cdInfo.ParseEcd64(ecd64);
+ ArcInfo.Base = absEcd64 - ecd64Offset;
+ return S_OK;
+ }
+ }
+
+ // some zip64 use variable size Zip64 ECD.
+ // we try to find it
+ if (absEcd64 != ecd64Offset)
+ {
+ if (TryEcd64(ecd64Offset, cdInfo) == S_OK)
+ {
+ ArcInfo.Base = 0;
+ return S_OK;
+ }
+ }
+ if (ArcInfo.MarkerPos != 0 &&
+ ArcInfo.MarkerPos + ecd64Offset != absEcd64)
{
- ArcInfo.Base = ArcInfo.StartPosition;
- return S_OK;
+ if (TryEcd64(ArcInfo.MarkerPos + ecd64Offset, cdInfo) == S_OK)
+ {
+ ArcInfo.Base = ArcInfo.MarkerPos;
+ return S_OK;
+ }
}
}
}
- if (Get32(buf + i + 4) == 0)
+ if (Get32(buf + i + 4) == 0) // ThisDiskNumber, StartCentralDirectoryDiskNumber;
{
- // cdInfo.NumEntries = GetUInt16(buf + i + 10);
- cdInfo.Size = Get32(buf + i + 12);
- cdInfo.Offset = Get32(buf + i + 16);
- UInt64 curPos = endPosition - bufSize + i;
+ cdInfo.ParseEcd(buf + i);
+ UInt64 absEcdPos = endPosition - bufSize + i;
UInt64 cdEnd = cdInfo.Size + cdInfo.Offset;
- if (curPos != cdEnd)
+ ArcInfo.Base = 0;
+ if (absEcdPos != cdEnd)
{
/*
if (cdInfo.Offset <= 16 && cdInfo.Size != 0)
@@ -553,290 +881,301 @@ HRESULT CInArchive::FindCd(CCdInfo &cdInfo)
}
else
*/
- ArcInfo.Base = curPos - cdEnd;
+ ArcInfo.Base = absEcdPos - cdEnd;
}
return S_OK;
}
}
+ if (i == 0)
+ return S_FALSE;
}
- return S_FALSE;
}
+
HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress)
{
items.Clear();
- RINOK(m_Stream->Seek(cdOffset, STREAM_SEEK_SET, &m_Position));
+ RINOK(Stream->Seek(cdOffset, STREAM_SEEK_SET, &m_Position));
if (m_Position != cdOffset)
return S_FALSE;
- if (!_inBuffer.Create(1 << 15))
- return E_OUTOFMEMORY;
- _inBuffer.SetStream(m_Stream);
_inBuffer.Init();
_inBufMode = true;
- while(m_Position - cdOffset < cdSize)
+ while (m_Position - cdOffset < cdSize)
{
if (ReadUInt32() != NSignature::kCentralFileHeader)
return S_FALSE;
CItemEx cdItem;
RINOK(ReadCdItem(cdItem));
items.Add(cdItem);
- if (progress && items.Size() % 1000 == 0)
- RINOK(progress->SetCompleted(items.Size()));
+ if (progress && items.Size() % 1 == 0)
+ RINOK(progress->SetCompletedCD(items.Size()));
}
return (m_Position - cdOffset == cdSize) ? S_OK : S_FALSE;
}
HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress)
{
- ArcInfo.Base = 0;
CCdInfo cdInfo;
RINOK(FindCd(cdInfo));
HRESULT res = S_FALSE;
cdSize = cdInfo.Size;
cdOffset = cdInfo.Offset;
+ if (progress)
+ progress->SetTotalCD(cdInfo.NumEntries);
res = TryReadCd(items, ArcInfo.Base + cdOffset, cdSize, progress);
if (res == S_FALSE && ArcInfo.Base == 0)
{
- res = TryReadCd(items, cdInfo.Offset + ArcInfo.StartPosition, cdSize, progress);
+ res = TryReadCd(items, ArcInfo.MarkerPos + cdOffset, cdSize, progress);
if (res == S_OK)
- ArcInfo.Base = ArcInfo.StartPosition;
+ ArcInfo.Base = ArcInfo.MarkerPos;
}
- if (!ReadUInt32(m_Signature))
- return S_FALSE;
return res;
}
-HRESULT CInArchive::ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset, int &numCdItems)
+static HRESULT FindItem(const CObjectVector<CItemEx> &items, UInt64 offset)
{
- items.Clear();
- numCdItems = 0;
- while (m_Signature == NSignature::kLocalFileHeader)
+ unsigned left = 0, right = items.Size();
+ for (;;)
{
- // FSeek points to next byte after signature
- // NFileHeader::CLocalBlock localHeader;
- CItemEx item;
- item.LocalHeaderPosition = m_Position - m_StreamStartPosition - 4; // points to signature;
- RINOK(ReadLocalItem(item));
- item.FromLocal = true;
- ReadLocalItemDescriptor(item);
- items.Add(item);
- if (progress && items.Size() % 100 == 0)
- RINOK(progress->SetCompleted(items.Size()));
- if (!ReadUInt32(m_Signature))
- break;
+ if (left >= right)
+ return -1;
+ unsigned index = (left + right) / 2;
+ UInt64 position = items[index].LocalHeaderPos;
+ if (offset == position)
+ return index;
+ if (offset < position)
+ right = index;
+ else
+ left = index + 1;
}
- cdOffset = m_Position - 4;
- int i;
- for (i = 0; i < items.Size(); i++, numCdItems++)
- {
- if (progress && i % 1000 == 0)
- RINOK(progress->SetCompleted(items.Size()));
- if (m_Signature == NSignature::kEndOfCentralDir)
- break;
-
- if (m_Signature != NSignature::kCentralFileHeader)
- return S_FALSE;
+}
- CItemEx cdItem;
- RINOK(ReadCdItem(cdItem));
+bool IsStrangeItem(const CItem &item)
+{
+ return item.Name.Len() > (1 << 14) || item.Method > (1 << 8);
+}
- if (i == 0)
+HRESULT CInArchive::ReadLocals(
+ CObjectVector<CItemEx> &items, CProgressVirt *progress)
+{
+ items.Clear();
+ while (m_Signature == NSignature::kLocalFileHeader)
+ {
+ CItemEx item;
+ item.LocalHeaderPos = m_Position - 4 - ArcInfo.MarkerPos;
+ // we write ralative LocalHeaderPos here. Later we can correct it to real Base.
+ try
{
- int j;
- for (j = 0; j < items.Size(); j++)
+ ReadLocalItem(item);
+ item.FromLocal = true;
+ if (item.HasDescriptor())
+ ReadLocalItemDescriptor(item);
+ else
{
- CItemEx &item = items[j];
- if (item.Name == cdItem.Name)
- {
- ArcInfo.Base = item.LocalHeaderPosition - cdItem.LocalHeaderPosition;
- break;
- }
+ RINOK(IncreaseRealPosition(item.PackSize));
}
- if (j == items.Size())
- return S_FALSE;
+ items.Add(item);
+ m_Signature = ReadUInt32();
}
-
- int index;
- int left = 0, right = items.Size();
- for (;;)
+ catch (CUnexpectEnd &)
{
- if (left >= right)
+ if (items.IsEmpty() || items.Size() == 1 && IsStrangeItem(items[0]))
return S_FALSE;
- index = (left + right) / 2;
- UInt64 position = items[index].LocalHeaderPosition - ArcInfo.Base;
- if (cdItem.LocalHeaderPosition == position)
- break;
- if (cdItem.LocalHeaderPosition < position)
- right = index;
- else
- left = index + 1;
+ throw;
}
- CItemEx &item = items[index];
- // item.LocalHeaderPosition = cdItem.LocalHeaderPosition;
- item.MadeByVersion = cdItem.MadeByVersion;
- item.CentralExtra = cdItem.CentralExtra;
-
- if (
- // item.ExtractVersion != cdItem.ExtractVersion ||
- !FlagsAreSame(item, cdItem) ||
- item.FileCRC != cdItem.FileCRC)
- return S_FALSE;
+ if (progress && items.Size() % 1 == 0)
+ RINOK(progress->SetCompletedLocal(items.Size(), item.LocalHeaderPos));
+ }
- if (item.Name.Length() != cdItem.Name.Length() ||
- item.PackSize != cdItem.PackSize ||
- item.UnPackSize != cdItem.UnPackSize
- )
- return S_FALSE;
- item.Name = cdItem.Name;
- item.InternalAttributes = cdItem.InternalAttributes;
- item.ExternalAttributes = cdItem.ExternalAttributes;
- item.Comment = cdItem.Comment;
- item.FromCentral = cdItem.FromCentral;
- if (!ReadUInt32(m_Signature))
+ if (items.Size() == 1 && m_Signature != NSignature::kCentralFileHeader)
+ if (IsStrangeItem(items[0]))
return S_FALSE;
- }
- for (i = 0; i < items.Size(); i++)
- items[i].LocalHeaderPosition -= ArcInfo.Base;
return S_OK;
}
-struct CEcd
-{
- UInt16 thisDiskNumber;
- UInt16 startCDDiskNumber;
- UInt16 numEntriesInCDOnThisDisk;
- UInt16 numEntriesInCD;
- UInt32 cdSize;
- UInt32 cdStartOffset;
- UInt16 commentSize;
- void Parse(const Byte *p);
-};
-
-void CEcd::Parse(const Byte *p)
-{
- thisDiskNumber = Get16(p);
- startCDDiskNumber = Get16(p + 2);
- numEntriesInCDOnThisDisk = Get16(p + 4);
- numEntriesInCD = Get16(p + 6);
- cdSize = Get32(p + 8);
- cdStartOffset = Get32(p + 12);
- commentSize = Get16(p + 16);
-}
-
-struct CEcd64
-{
- UInt16 versionMade;
- UInt16 versionNeedExtract;
- UInt32 thisDiskNumber;
- UInt32 startCDDiskNumber;
- UInt64 numEntriesInCDOnThisDisk;
- UInt64 numEntriesInCD;
- UInt64 cdSize;
- UInt64 cdStartOffset;
- void Parse(const Byte *p);
- CEcd64() { memset(this, 0, sizeof(*this)); }
-};
-
-void CEcd64::Parse(const Byte *p)
-{
- versionMade = Get16(p);
- versionNeedExtract = Get16(p + 2);
- thisDiskNumber = Get32(p + 4);
- startCDDiskNumber = Get32(p + 8);
- numEntriesInCDOnThisDisk = Get64(p + 12);
- numEntriesInCD = Get64(p + 20);
- cdSize = Get64(p + 28);
- cdStartOffset = Get64(p + 36);
-}
#define COPY_ECD_ITEM_16(n) if (!isZip64 || ecd. n != 0xFFFF) ecd64. n = ecd. n;
#define COPY_ECD_ITEM_32(n) if (!isZip64 || ecd. n != 0xFFFFFFFF) ecd64. n = ecd. n;
-HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress)
+HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items, CProgressVirt *progress)
{
- IsOkHeaders = true;
- // m_Signature must be kLocalFileHeaderSignature or
- // kEndOfCentralDirSignature
+ items.Clear();
+
+ // m_Signature must be kLocalFileHeader or kEcd
// m_Position points to next byte after signature
+ RINOK(Stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
- IsZip64 = false;
- items.Clear();
+ if (!_inBuffer.Create(1 << 15))
+ return E_OUTOFMEMORY;
+ _inBuffer.SetStream(Stream);
- UInt64 cdSize, cdStartOffset;
- HRESULT res;
- try
+ bool needReadCd = true;
+ bool localsWereRead = false;
+ if (m_Signature == NSignature::kEcd)
{
- res = ReadCd(items, cdStartOffset, cdSize, progress);
+ // It must be empty archive or backware archive
+ // we don't support backware archive still
+
+ const unsigned kBufSize = kEcdSize - 4;
+ Byte buf[kBufSize];
+ SafeReadBytes(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;
+ needReadCd = false;
+ IsArc = true; // check it: we need more tests?
+ RINOK(Stream->Seek(ArcInfo.MarkerPos2 + 4, STREAM_SEEK_SET, &m_Position));
}
- catch(CInArchiveException &)
+
+ UInt64 cdSize = 0, cdRelatOffset = 0, cdAbsOffset = 0;
+ HRESULT res = S_OK;
+
+ if (needReadCd)
{
- res = S_FALSE;
+ CItemEx firstItem;
+ // try
+ {
+ try
+ {
+ if (!ReadLocalItem(firstItem))
+ return S_FALSE;
+ }
+ catch(CUnexpectEnd &)
+ {
+ return S_FALSE;
+ }
+
+ IsArc = true;
+ res = ReadCd(items, cdRelatOffset, cdSize, progress);
+ if (res == S_OK)
+ m_Signature = ReadUInt32();
+ }
+ // catch() { 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
+ firstItem.LocalHeaderPos = ArcInfo.MarkerPos2 - ArcInfo.Base;
+ int index = FindItem(items, firstItem.LocalHeaderPos);
+ if (index == -1)
+ res = S_FALSE;
+ else if (!AreItemsEqual(firstItem, items[index]))
+ res = S_FALSE;
+ ArcInfo.CdWasRead = true;
+ ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos;
+ }
}
- if (res != S_FALSE && res != S_OK)
- return res;
- /*
- if (res != S_OK)
- return res;
- res = S_FALSE;
- */
+ CObjectVector<CItemEx> cdItems;
- int numCdItems = items.Size();
+ bool needSetBase = false;
+ unsigned numCdItems = items.Size();
+
if (res == S_FALSE)
{
+ // CD doesn't match firstItem so we clear items and read Locals.
+ items.Clear();
+ localsWereRead = true;
_inBufMode = false;
- ArcInfo.Base = 0;
- RINOK(m_Stream->Seek(ArcInfo.StartPosition, STREAM_SEEK_SET, &m_Position));
- if (m_Position != ArcInfo.StartPosition)
- return S_FALSE;
- if (!ReadUInt32(m_Signature))
- return S_FALSE;
- RINOK(ReadLocalsAndCd(items, progress, cdStartOffset, numCdItems));
- cdSize = (m_Position - 4) - cdStartOffset;
- cdStartOffset -= ArcInfo.Base;
+ ArcInfo.Base = ArcInfo.MarkerPos;
+ RINOK(Stream->Seek(ArcInfo.MarkerPos2, STREAM_SEEK_SET, &m_Position));
+ m_Signature = ReadUInt32();
+
+ RINOK(ReadLocals(items, progress));
+
+ if (m_Signature != NSignature::kCentralFileHeader)
+ {
+ m_Position -= 4;
+ NoCentralDir = true;
+ HeadersError = true;
+ return S_OK;
+ }
+ _inBufMode = true;
+ _inBuffer.Init();
+ cdAbsOffset = m_Position - 4;
+ for (;;)
+ {
+ CItemEx cdItem;
+ RINOK(ReadCdItem(cdItem));
+ cdItems.Add(cdItem);
+ if (progress && cdItems.Size() % 1 == 0)
+ RINOK(progress->SetCompletedCD(items.Size()));
+ m_Signature = ReadUInt32();
+ if (m_Signature != NSignature::kCentralFileHeader)
+ break;
+ }
+
+ cdSize = (m_Position - 4) - cdAbsOffset;
+ needSetBase = true;
+ numCdItems = cdItems.Size();
+
+ if (!cdItems.IsEmpty())
+ {
+ ArcInfo.CdWasRead = true;
+ ArcInfo.FirstItemRelatOffset = cdItems[0].LocalHeaderPos;
+ }
}
CEcd64 ecd64;
bool isZip64 = false;
- UInt64 zip64EcdStartOffset = m_Position - 4 - ArcInfo.Base;
- if (m_Signature == NSignature::kZip64EndOfCentralDir)
+ UInt64 ecd64AbsOffset = m_Position - 4;
+ if (m_Signature == NSignature::kEcd64)
{
IsZip64 = isZip64 = true;
UInt64 recordSize = ReadUInt64();
- const int kBufSize = kZip64EcdSize;
+ const unsigned kBufSize = kEcd64_MainSize;
Byte buf[kBufSize];
SafeReadBytes(buf, kBufSize);
ecd64.Parse(buf);
- Skip(recordSize - kZip64EcdSize);
- if (!ReadUInt32(m_Signature))
- return S_FALSE;
+ Skip64(recordSize - kEcd64_MainSize);
+ m_Signature = ReadUInt32();
+
if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0)
- throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported);
+ return E_NOTIMPL;
+
+ if (needSetBase)
+ {
+ ArcInfo.Base = cdAbsOffset - ecd64.cdStartOffset;
+ cdRelatOffset = ecd64.cdStartOffset;
+ needSetBase = false;
+ }
+
if (ecd64.numEntriesInCDOnThisDisk != numCdItems ||
ecd64.numEntriesInCD != numCdItems ||
ecd64.cdSize != cdSize ||
- (ecd64.cdStartOffset != cdStartOffset &&
+ (ecd64.cdStartOffset != cdRelatOffset &&
(!items.IsEmpty())))
return S_FALSE;
}
- if (m_Signature == NSignature::kZip64EndOfCentralDirLocator)
+ if (m_Signature == NSignature::kEcd64Locator)
{
+ if (!isZip64)
+ return S_FALSE;
/* UInt32 startEndCDDiskNumber = */ ReadUInt32();
- UInt64 endCDStartOffset = ReadUInt64();
+ UInt64 ecd64RelatOffset = ReadUInt64();
/* UInt32 numberOfDisks = */ ReadUInt32();
- if (zip64EcdStartOffset != endCDStartOffset)
- return S_FALSE;
- if (!ReadUInt32(m_Signature))
+ if (ecd64AbsOffset != ArcInfo.Base + ecd64RelatOffset)
return S_FALSE;
+ m_Signature = ReadUInt32();
}
- if (m_Signature != NSignature::kEndOfCentralDir)
+ if (m_Signature != NSignature::kEcd)
return S_FALSE;
- const int kBufSize = kEcdSize - 4;
+ const unsigned kBufSize = kEcdSize - 4;
Byte buf[kBufSize];
SafeReadBytes(buf, kBufSize);
CEcd ecd;
@@ -849,47 +1188,119 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *pr
COPY_ECD_ITEM_32(cdSize);
COPY_ECD_ITEM_32(cdStartOffset);
- ReadBuffer(ArcInfo.Comment, ecd.commentSize);
+ if (needSetBase)
+ {
+ ArcInfo.Base = cdAbsOffset - ecd64.cdStartOffset;
+ cdRelatOffset = ecd64.cdStartOffset;
+ needSetBase = false;
+ }
+
+ if (localsWereRead && (UInt64)ArcInfo.Base != ArcInfo.MarkerPos)
+ {
+ UInt64 delta = ArcInfo.MarkerPos - ArcInfo.Base;
+ for (unsigned i = 0; i < items.Size(); i++)
+ items[i].LocalHeaderPos += delta;
+ }
+
+
+ // ---------- merge Central Directory Items ----------
+
+ if (!cdItems.IsEmpty())
+ {
+ for (unsigned i = 0; i < cdItems.Size(); i++)
+ {
+ const CItemEx &cdItem = cdItems[i];
+ int index = FindItem(items, cdItem.LocalHeaderPos);
+ if (index == -1)
+ {
+ items.Add(cdItem);
+ 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)
+ continue;
+
+ // item.LocalHeaderPos = cdItem.LocalHeaderPos;
+ // 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;
+ }
+ }
if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0)
- throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported);
- if (numCdItems != items.Size())
- IsOkHeaders = false;
- if ((UInt16)ecd64.numEntriesInCDOnThisDisk != ((UInt16)numCdItems) ||
+ return E_NOTIMPL;
+
+ if (isZip64)
+ {
+ if (ecd64.numEntriesInCDOnThisDisk != items.Size())
+ HeadersError = true;
+ }
+ else
+ {
+ // old 7-zip could store 32-bit number of CD items to 16-bit field.
+ if ((UInt16)ecd64.numEntriesInCDOnThisDisk != (UInt16)numCdItems ||
+ (UInt16)ecd64.numEntriesInCDOnThisDisk != (UInt16)items.Size())
+ HeadersError = true;
+ }
+
+ ReadBuffer(ArcInfo.Comment, ecd.commentSize);
+ _inBufMode = false;
+ _inBuffer.Free();
+
+ if (
(UInt16)ecd64.numEntriesInCD != ((UInt16)numCdItems) ||
(UInt32)ecd64.cdSize != (UInt32)cdSize ||
- ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdStartOffset &&
+ ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdRelatOffset &&
(!items.IsEmpty())))
return S_FALSE;
- _inBufMode = false;
- _inBuffer.Free();
- ArcInfo.FinishPosition = m_Position;
+ // printf("\nOpen OK");
return S_OK;
}
+HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress)
+{
+ HRESULT res;
+ try
+ {
+ res = ReadHeaders2(items, progress);
+ }
+ catch (const CInBufferException &e) { res = e.ErrorCode; }
+ catch (const CUnexpectEnd &)
+ {
+ if (items.IsEmpty())
+ return S_FALSE;
+ UnexpectedEnd = true;
+ res = S_OK;
+ }
+ catch (...)
+ {
+ _inBufMode = false;
+ throw;
+ }
+ ArcInfo.FinishPos = m_Position;
+ _inBufMode = false;
+ return res;
+}
+
ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size)
{
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
CMyComPtr<ISequentialInStream> stream(streamSpec);
- SeekInArchive(ArcInfo.Base + position);
- streamSpec->SetStream(m_Stream);
+ Stream->Seek(ArcInfo.Base + position, STREAM_SEEK_SET, NULL);
+ streamSpec->SetStream(Stream);
streamSpec->Init(size);
return stream.Detach();
}
-IInStream* CInArchive::CreateStream()
-{
- CMyComPtr<IInStream> stream = m_Stream;
- return stream.Detach();
-}
-
-bool CInArchive::SeekInArchive(UInt64 position)
-{
- UInt64 newPosition;
- if (m_Stream->Seek(position, STREAM_SEEK_SET, &newPosition) != S_OK)
- return false;
- return (newPosition == position);
-}
-
}}
diff --git a/CPP/7zip/Archive/Zip/ZipIn.h b/CPP/7zip/Archive/Zip/ZipIn.h
index 0565339a..f6b349b1 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipIn.h
+++ b/CPP/7zip/Archive/Zip/ZipIn.h
@@ -3,121 +3,187 @@
#ifndef __ZIP_IN_H
#define __ZIP_IN_H
-#include "Common/MyCom.h"
+#include "../../../Common/MyCom.h"
#include "../../IStream.h"
#include "../../Common/InBuffer.h"
#include "ZipHeader.h"
-#include "ZipItemEx.h"
+#include "ZipItem.h"
+
+API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size);
namespace NArchive {
namespace NZip {
-class CInArchiveException
+class CItemEx: public CItem
{
public:
- enum ECauseType
- {
- kUnexpectedEndOfArchive = 0,
- kArchiceHeaderCRCError,
- kFileHeaderCRCError,
- kIncorrectArchive,
- kDataDescroptorsAreNotSupported,
- kMultiVolumeArchiveAreNotSupported,
- kReadStreamError,
- kSeekStreamError
- }
- Cause;
- CInArchiveException(ECauseType cause): Cause(cause) {}
+ UInt32 LocalFullHeaderSize; // including Name and Extra
+
+ UInt64 GetLocalFullSize() const
+ { return LocalFullHeaderSize + PackSize + (HasDescriptor() ? kDataDescriptorSize : 0); }
+ UInt64 GetDataPosition() const
+ { return LocalHeaderPos + LocalFullHeaderSize; };
};
-class CInArchiveInfo
+struct CInArchiveInfo
{
-public:
- UInt64 Base;
- UInt64 StartPosition;
- UInt64 FinishPosition;
+ 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 PK00 signature
+ = MarkerPos2 in most archives
+ = MarkerPos2 - 4 if there is PK00 signature */
+ UInt64 MarkerPos2; // Pos of first local item signature in stream
+ UInt64 FinishPos; // Finish pos of archive data
+ 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 */
+ bool CdWasRead;
+
CByteBuffer Comment;
- CInArchiveInfo(): Base(0), StartPosition(0) {}
- UInt64 GetPhySize() const { return FinishPosition - StartPosition; }
+ CInArchiveInfo(): Base(0), MarkerPos(0), MarkerPos2(0), FinishPos(0), FileEndPos(0),
+ FirstItemRelatOffset(0), CdWasRead(false) {}
+
+ UInt64 GetPhySize() const { return FinishPos - Base; }
+ UInt64 GetEmbeddedStubSize() const
+ {
+ if (CdWasRead)
+ return FirstItemRelatOffset;
+ return MarkerPos2 - Base;
+ }
+ bool ThereIsTail() const { return FileEndPos > FinishPos; }
+
void Clear()
{
Base = 0;
- StartPosition = 0;
- Comment.SetCapacity(0);
+ MarkerPos = 0;
+ MarkerPos2 = 0;
+ FinishPos = 0;
+ FileEndPos = 0;
+
+ FirstItemRelatOffset = 0;
+ CdWasRead = false;
+
+ Comment.Free();
}
};
-class CProgressVirt
+struct CProgressVirt
{
-public:
- STDMETHOD(SetTotal)(UInt64 numFiles) PURE;
- STDMETHOD(SetCompleted)(UInt64 numFiles) PURE;
+ virtual HRESULT SetCompletedLocal(UInt64 numFiles, UInt64 numBytes) = 0;
+ virtual HRESULT SetTotalCD(UInt64 numFiles) = 0;
+ virtual HRESULT SetCompletedCD(UInt64 numFiles) = 0;
};
struct CCdInfo
{
- // UInt64 NumEntries;
+ UInt64 NumEntries;
UInt64 Size;
UInt64 Offset;
+
+ void ParseEcd(const Byte *p);
+ void ParseEcd64(const Byte *p);
};
class CInArchive
{
- CMyComPtr<IInStream> m_Stream;
+ CInBuffer _inBuffer;
+ bool _inBufMode;
UInt32 m_Signature;
- UInt64 m_StreamStartPosition;
UInt64 m_Position;
-
- bool _inBufMode;
- CInBuffer _inBuffer;
HRESULT Seek(UInt64 offset);
-
HRESULT FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
- void ReadFileName(UInt32 nameSize, AString &dest);
-
+ HRESULT IncreaseRealPosition(UInt64 addValue);
+
HRESULT ReadBytes(void *data, UInt32 size, UInt32 *processedSize);
- bool ReadBytesAndTestSize(void *data, UInt32 size);
- void SafeReadBytes(void *data, UInt32 size);
- void ReadBuffer(CByteBuffer &buffer, UInt32 size);
+ void SafeReadBytes(void *data, unsigned size);
+ void ReadBuffer(CByteBuffer &buffer, unsigned size);
Byte ReadByte();
UInt16 ReadUInt16();
UInt32 ReadUInt32();
UInt64 ReadUInt64();
- bool ReadUInt32(UInt32 &signature);
-
- void Skip(UInt64 num);
- void IncreaseRealPosition(UInt64 addValue);
-
- void ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock,
+ void Skip(unsigned num);
+ void Skip64(UInt64 num);
+ void ReadFileName(unsigned nameSize, AString &dest);
+
+ bool ReadExtra(unsigned extraSize, CExtraBlock &extraBlock,
UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber);
- HRESULT ReadLocalItem(CItemEx &item);
+ bool ReadLocalItem(CItemEx &item);
HRESULT ReadLocalItemDescriptor(CItemEx &item);
HRESULT ReadCdItem(CItemEx &item);
HRESULT TryEcd64(UInt64 offset, CCdInfo &cdInfo);
HRESULT FindCd(CCdInfo &cdInfo);
HRESULT TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress);
HRESULT ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress);
- HRESULT ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset, int &numCdItems);
+ HRESULT ReadLocals(CObjectVector<CItemEx> &localItems, CProgressVirt *progress);
+
+ HRESULT ReadHeaders2(CObjectVector<CItemEx> &items, CProgressVirt *progress);
public:
CInArchiveInfo ArcInfo;
+
+ bool IsArc;
bool IsZip64;
- bool IsOkHeaders;
-
+ bool HeadersError;
+ bool HeadersWarning;
+ bool ExtraMinorError;
+ bool UnexpectedEnd;
+ bool NoCentralDir;
+
+ CMyComPtr<IInStream> Stream;
+
+ void Close();
+ HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
HRESULT ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress);
+
+ bool IsOpen() const { return Stream != NULL; }
+ bool AreThereErrors() const { return HeadersError || UnexpectedEnd; }
+
+ bool IsLocalOffsetOK(const CItemEx &item) const
+ {
+ if (item.FromLocal)
+ return true;
+ return /* ArcInfo.Base >= 0 || */ ArcInfo.Base + (Int64)item.LocalHeaderPos >= 0;
+ }
+
HRESULT ReadLocalItemAfterCdItem(CItemEx &item);
HRESULT ReadLocalItemAfterCdItemFull(CItemEx &item);
- HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
- void Close();
- bool SeekInArchive(UInt64 position);
+
ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
- IInStream* CreateStream();
- bool IsOpen() const { return m_Stream != NULL; }
+ UInt64 GetOffsetInStream(UInt64 offsetFromArc) const { return ArcInfo.Base + offsetFromArc; }
+
+ bool CanUpdate() const
+ {
+ if (AreThereErrors())
+ return false;
+ if (ArcInfo.Base < 0)
+ return false;
+ if ((Int64)ArcInfo.MarkerPos2 < ArcInfo.Base)
+ return false;
+
+ // 7-zip probably can update archives with embedded stubs.
+ // we just disable that feature for more safety.
+ if (ArcInfo.GetEmbeddedStubSize() != 0)
+ return false;
+
+ if (ArcInfo.ThereIsTail())
+ return false;
+ return true;
+ }
};
}}
diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp
index ad89f558..ae88944d 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipItem.cpp
+++ b/CPP/7zip/Archive/Zip/ZipItem.cpp
@@ -10,21 +10,13 @@
namespace NArchive {
namespace NZip {
-bool operator==(const CVersion &v1, const CVersion &v2)
-{
- return (v1.Version == v2.Version) && (v1.HostOS == v2.HostOS);
-}
+using namespace NFileHeader;
-bool operator!=(const CVersion &v1, const CVersion &v2)
-{
- return !(v1 == v2);
-}
-
-bool CExtraSubBlock::ExtractNtfsTime(int index, FILETIME &ft) const
+bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const
{
ft.dwHighDateTime = ft.dwLowDateTime = 0;
- UInt32 size = (UInt32)Data.GetCapacity();
- if (ID != NFileHeader::NExtraID::kNTFS || size < 32)
+ UInt32 size = (UInt32)Data.Size();
+ if (ID != NExtraID::kNTFS || size < 32)
return false;
const Byte *p = (const Byte *)Data;
p += 4; // for reserved
@@ -32,13 +24,13 @@ bool CExtraSubBlock::ExtractNtfsTime(int index, FILETIME &ft) const
while (size > 4)
{
UInt16 tag = GetUi16(p);
- UInt32 attrSize = GetUi16(p + 2);
+ unsigned attrSize = GetUi16(p + 2);
p += 4;
size -= 4;
if (attrSize > size)
attrSize = size;
- if (tag == NFileHeader::NNtfsExtra::kTagTime && attrSize >= 24)
+ if (tag == NNtfsExtra::kTagTime && attrSize >= 24)
{
p += 8 * index;
ft.dwLowDateTime = GetUi32(p);
@@ -51,25 +43,25 @@ bool CExtraSubBlock::ExtractNtfsTime(int index, FILETIME &ft) const
return false;
}
-bool CExtraSubBlock::ExtractUnixTime(bool isCentral, int index, UInt32 &res) const
+bool CExtraSubBlock::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const
{
res = 0;
- UInt32 size = (UInt32)Data.GetCapacity();
- if (ID != NFileHeader::NExtraID::kUnixTime || size < 5)
+ 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 != NFileHeader::NUnixTime::kMTime ||
- (flags & (1 << NFileHeader::NUnixTime::kMTime)) == 0 ||
+ if (index != NUnixTime::kMTime ||
+ (flags & (1 << NUnixTime::kMTime)) == 0 ||
size < 4)
return false;
res = GetUi32(p);
return true;
}
- for (int i = 0; i < 3; i++)
+ for (unsigned i = 0; i < 3; i++)
if ((flags & (1 << i)) != 0)
{
if (size < 4)
@@ -96,30 +88,33 @@ bool CItem::IsDir() const
return true;
if (!FromCentral)
return false;
- WORD highAttributes = WORD((ExternalAttributes >> 16 ) & 0xFFFF);
- switch (MadeByVersion.HostOS)
+
+ UInt16 highAttrib = (UInt16)((ExternalAttrib >> 16 ) & 0xFFFF);
+
+ Byte hostOS = GetHostOS();
+ switch (hostOS)
{
- case NFileHeader::NHostOS::kAMIGA:
- switch (highAttributes & NFileHeader::NAmigaAttribute::kIFMT)
+ case NHostOS::kAMIGA:
+ switch (highAttrib & NAmigaAttrib::kIFMT)
{
- case NFileHeader::NAmigaAttribute::kIFDIR: return true;
- case NFileHeader::NAmigaAttribute::kIFREG: return false;
+ case NAmigaAttrib::kIFDIR: return true;
+ case NAmigaAttrib::kIFREG: return false;
default: return false; // change it throw kUnknownAttributes;
}
- case NFileHeader::NHostOS::kFAT:
- case NFileHeader::NHostOS::kNTFS:
- case NFileHeader::NHostOS::kHPFS:
- case NFileHeader::NHostOS::kVFAT:
- return ((ExternalAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
- case NFileHeader::NHostOS::kAtari:
- case NFileHeader::NHostOS::kMac:
- case NFileHeader::NHostOS::kVMS:
- case NFileHeader::NHostOS::kVM_CMS:
- case NFileHeader::NHostOS::kAcorn:
- case NFileHeader::NHostOS::kMVS:
+ 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 NFileHeader::NHostOS::kUnix:
- return (highAttributes & NFileHeader::NUnixAttribute::kIFDIR) != 0;
+ case NHostOS::kUnix:
+ return (highAttrib & NUnixAttrib::kIFDIR) != 0;
default:
return false;
}
@@ -127,13 +122,13 @@ bool CItem::IsDir() const
UInt32 CItem::GetWinAttrib() const
{
- DWORD winAttrib = 0;
- switch (MadeByVersion.HostOS)
+ UInt32 winAttrib = 0;
+ switch (GetHostOS())
{
- case NFileHeader::NHostOS::kFAT:
- case NFileHeader::NHostOS::kNTFS:
+ case NHostOS::kFAT:
+ case NHostOS::kNTFS:
if (FromCentral)
- winAttrib = ExternalAttributes;
+ winAttrib = ExternalAttrib;
break;
}
if (IsDir()) // test it;
@@ -144,35 +139,15 @@ UInt32 CItem::GetWinAttrib() const
bool CItem::GetPosixAttrib(UInt32 &attrib) const
{
// some archivers can store PosixAttrib in high 16 bits even with HostOS=FAT.
- if (FromCentral && MadeByVersion.HostOS == NFileHeader::NHostOS::kUnix)
+ if (FromCentral && GetHostOS() == NHostOS::kUnix)
{
- attrib = ExternalAttributes >> 16;
+ attrib = ExternalAttrib >> 16;
return (attrib != 0);
}
attrib = 0;
if (IsDir())
- attrib = NFileHeader::NUnixAttribute::kIFDIR;
+ attrib = NUnixAttrib::kIFDIR;
return false;
}
-void CLocalItem::SetFlagBits(int startBitNumber, int numBits, int value)
-{
- UInt16 mask = (UInt16)(((1 << numBits) - 1) << startBitNumber);
- Flags &= ~mask;
- Flags |= value << startBitNumber;
-}
-
-void CLocalItem::SetBitMask(int bitMask, bool enable)
-{
- if(enable)
- Flags |= bitMask;
- else
- Flags &= ~bitMask;
-}
-
-void CLocalItem::SetEncrypted(bool encrypted)
- { SetBitMask(NFileHeader::NFlags::kEncrypted, encrypted); }
-void CLocalItem::SetUtf8(bool isUtf8)
- { SetBitMask(NFileHeader::NFlags::kUtf8, isUtf8); }
-
}}
diff --git a/CPP/7zip/Archive/Zip/ZipItem.h b/CPP/7zip/Archive/Zip/ZipItem.h
index 5efd433a..d50c3ae9 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipItem.h
+++ b/CPP/7zip/Archive/Zip/ZipItem.h
@@ -3,10 +3,12 @@
#ifndef __ARCHIVE_ZIP_ITEM_H
#define __ARCHIVE_ZIP_ITEM_H
-#include "Common/MyString.h"
-#include "Common/Buffer.h"
-#include "Common/UTFConvert.h"
-#include "Common/StringConvert.h"
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/MyBuffer.h"
+#include "../../../Common/MyString.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/UTFConvert.h"
#include "ZipHeader.h"
@@ -19,25 +21,25 @@ struct CVersion
Byte HostOS;
};
-bool operator==(const CVersion &v1, const CVersion &v2);
-bool operator!=(const CVersion &v1, const CVersion &v2);
-
struct CExtraSubBlock
{
UInt16 ID;
CByteBuffer Data;
- bool ExtractNtfsTime(int index, FILETIME &ft) const;
- bool ExtractUnixTime(bool isCentral, int index, UInt32 &res) const;
+
+ bool ExtractNtfsTime(unsigned index, FILETIME &ft) const;
+ bool ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const;
};
-struct CWzAesExtraField
+const unsigned k_WzAesExtra_Size = 7;
+
+struct CWzAesExtra
{
- UInt16 VendorVersion; // 0x0001 - AE-1, 0x0002 - AE-2,
- // UInt16 VendorId; // "AE"
- Byte Strength; // 1 - 128-bit , 2 - 192-bit , 3 - 256-bit
+ 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;
- CWzAesExtraField(): VendorVersion(2), Strength(3), Method(0) {}
+ CWzAesExtra(): VendorVersion(2), Strength(3), Method(0) {}
bool NeedCrc() const { return (VendorVersion == 1); }
@@ -45,19 +47,21 @@ struct CWzAesExtraField
{
if (sb.ID != NFileHeader::NExtraID::kWzAES)
return false;
- if (sb.Data.GetCapacity() < 7)
+ if (sb.Data.Size() < k_WzAesExtra_Size)
return false;
const Byte *p = (const Byte *)sb.Data;
- VendorVersion = (((UInt16)p[1]) << 8) | p[0];
+ VendorVersion = GetUi16(p);
if (p[2] != 'A' || p[3] != 'E')
return false;
Strength = p[4];
- Method = (((UInt16)p[6]) << 16) | p[5];
+ // 9.31: The BUG was fixed:
+ Method = GetUi16(p + 5);
return true;
}
+
void SetSubBlock(CExtraSubBlock &sb) const
{
- sb.Data.SetCapacity(7);
+ sb.Data.Alloc(k_WzAesExtra_Size);
sb.ID = NFileHeader::NExtraID::kWzAES;
Byte *p = (Byte *)sb.Data;
p[0] = (Byte)VendorVersion;
@@ -70,7 +74,7 @@ struct CWzAesExtraField
}
};
-namespace NStrongCryptoFlags
+namespace NStrongCrypto_AlgId
{
const UInt16 kDES = 0x6601;
const UInt16 kRC2old = 0x6602;
@@ -85,7 +89,7 @@ namespace NStrongCryptoFlags
const UInt16 kRC4 = 0x6801;
}
-struct CStrongCryptoField
+struct CStrongCryptoExtra
{
UInt16 Format;
UInt16 AlgId;
@@ -97,12 +101,12 @@ struct CStrongCryptoField
if (sb.ID != NFileHeader::NExtraID::kStrongEncrypt)
return false;
const Byte *p = (const Byte *)sb.Data;
- if (sb.Data.GetCapacity() < 8)
+ if (sb.Data.Size() < 8)
return false;
- Format = (((UInt16)p[1]) << 8) | p[0];
- AlgId = (((UInt16)p[3]) << 8) | p[2];
- BitLen = (((UInt16)p[5]) << 8) | p[4];
- Flags = (((UInt16)p[7]) << 8) | p[6];
+ Format = GetUi16(p + 0);
+ AlgId = GetUi16(p + 2);
+ BitLen = GetUi16(p + 4);
+ Flags = GetUi16(p + 6);
return (Format == 2);
}
};
@@ -110,39 +114,50 @@ struct CStrongCryptoField
struct CExtraBlock
{
CObjectVector<CExtraSubBlock> SubBlocks;
+
void Clear() { SubBlocks.Clear(); }
+
size_t GetSize() const
{
size_t res = 0;
- for (int i = 0; i < SubBlocks.Size(); i++)
- res += SubBlocks[i].Data.GetCapacity() + 2 + 2;
+ FOR_VECTOR (i, SubBlocks)
+ res += SubBlocks[i].Data.Size() + 2 + 2;
return res;
}
- bool GetWzAesField(CWzAesExtraField &aesField) const
+
+ bool GetWzAes(CWzAesExtra &e) const
{
- for (int i = 0; i < SubBlocks.Size(); i++)
- if (aesField.ParseFromSubBlock(SubBlocks[i]))
+ FOR_VECTOR (i, SubBlocks)
+ if (e.ParseFromSubBlock(SubBlocks[i]))
return true;
return false;
}
- bool GetStrongCryptoField(CStrongCryptoField &f) const
+ bool HasWzAes() const
+ {
+ CWzAesExtra e;
+ return GetWzAes(e);
+ }
+
+ bool GetStrongCrypto(CStrongCryptoExtra &e) const
{
- for (int i = 0; i < SubBlocks.Size(); i++)
- if (f.ParseFromSubBlock(SubBlocks[i]))
+ FOR_VECTOR (i, SubBlocks)
+ if (e.ParseFromSubBlock(SubBlocks[i]))
return true;
return false;
}
- bool HasWzAesField() const
+ /*
+ bool HasStrongCrypto() const
{
- CWzAesExtraField aesField;
- return GetWzAesField(aesField);
+ CStrongCryptoExtra e;
+ return GetStrongCrypto(e);
}
+ */
- bool GetNtfsTime(int index, FILETIME &ft) const
+ bool GetNtfsTime(unsigned index, FILETIME &ft) const
{
- for (int i = 0; i < SubBlocks.Size(); i++)
+ FOR_VECTOR (i, SubBlocks)
{
const CExtraSubBlock &sb = SubBlocks[i];
if (sb.ID == NFileHeader::NExtraID::kNTFS)
@@ -151,9 +166,9 @@ struct CExtraBlock
return false;
}
- bool GetUnixTime(bool isCentral, int index, UInt32 &res) const
+ bool GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const
{
- for (int i = 0; i < SubBlocks.Size(); i++)
+ FOR_VECTOR (i, SubBlocks)
{
const CExtraSubBlock &sb = SubBlocks[i];
if (sb.ID == NFileHeader::NExtraID::kUnixTime)
@@ -162,14 +177,6 @@ struct CExtraBlock
return false;
}
- /*
- bool HasStrongCryptoField() const
- {
- CStrongCryptoField f;
- return GetStrongCryptoField(f);
- }
- */
-
void RemoveUnknownSubBlocks()
{
for (int i = SubBlocks.Size() - 1; i >= 0; i--)
@@ -182,95 +189,134 @@ struct CExtraBlock
class CLocalItem
{
public:
- CVersion ExtractVersion;
UInt16 Flags;
- UInt16 CompressionMethod;
- UInt32 Time;
- UInt32 FileCRC;
+ UInt16 Method;
+ CVersion ExtractVersion;
+
+ UInt64 Size;
UInt64 PackSize;
- UInt64 UnPackSize;
+ UInt32 Time;
+ UInt32 Crc;
AString Name;
CExtraBlock LocalExtra;
bool IsUtf8() const { return (Flags & NFileHeader::NFlags::kUtf8) != 0; }
-
bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kEncrypted) != 0; }
bool IsStrongEncrypted() const { return IsEncrypted() && (Flags & NFileHeader::NFlags::kStrongEncrypted) != 0; };
- bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || CompressionMethod == NFileHeader::NCompressionMethod::kWzAES); };
-
+ bool 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 IsDir() const;
- bool IgnoreItem() const { return false; }
-
- bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; }
- UString GetUnicodeString(const AString &s) const
+ /*
+ void GetUnicodeString(const AString &s, UString &res) const
{
- UString res;
- if (IsUtf8())
- if (!ConvertUTF8ToUnicode(s, res))
- res.Empty();
- if (res.IsEmpty())
- res = MultiByteToUnicodeString(s, GetCodePage());
- return res;
+ bool isUtf8 = IsUtf8();
+ if (isUtf8)
+ if (ConvertUTF8ToUnicode(s, res))
+ return;
+ MultiByteToUnicodeString2(res, s, GetCodePage());
}
-
+ */
+
private:
- void SetFlagBits(int startBitNumber, int numBits, int value);
- void SetBitMask(int bitMask, bool enable);
+
+ void SetFlag(unsigned bitMask, bool enable)
+ {
+ if (enable)
+ Flags |= bitMask;
+ else
+ Flags &= ~bitMask;
+ }
+
public:
+
void ClearFlags() { Flags = 0; }
- void SetEncrypted(bool encrypted);
- void SetUtf8(bool isUtf8);
+ void SetEncrypted(bool encrypted) { SetFlag(NFileHeader::NFlags::kEncrypted, encrypted); }
+ void SetUtf8(bool isUtf8) { SetFlag(NFileHeader::NFlags::kUtf8, isUtf8); }
- WORD GetCodePage() const { return CP_OEMCP; }
+ UINT GetCodePage() const { return CP_OEMCP; }
};
+
class CItem: public CLocalItem
{
public:
CVersion MadeByVersion;
- UInt16 InternalAttributes;
- UInt32 ExternalAttributes;
+ UInt16 InternalAttrib;
+ UInt32 ExternalAttrib;
- UInt64 LocalHeaderPosition;
+ UInt64 LocalHeaderPos;
- FILETIME NtfsMTime;
- FILETIME NtfsATime;
- FILETIME NtfsCTime;
-
CExtraBlock CentralExtra;
CByteBuffer Comment;
bool FromLocal;
bool FromCentral;
- bool NtfsTimeIsDefined;
+ // 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;
+ }
+
bool IsDir() const;
UInt32 GetWinAttrib() const;
bool GetPosixAttrib(UInt32 &attrib) const;
+ Byte GetHostOS() const { return FromCentral ? MadeByVersion.HostOS : ExtractVersion.HostOS; }
+
+ void GetUnicodeString(const AString &s, UString &res, bool useSpecifiedCodePage, UINT codePage) const
+ {
+ bool isUtf8 = IsUtf8();
+
+ #ifdef _WIN32
+ if (!isUtf8)
+ {
+ if (useSpecifiedCodePage)
+ isUtf8 = (codePage == CP_UTF8);
+ 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;
+ }
+ }
+ #endif
+
+ if (isUtf8)
+ if (ConvertUTF8ToUnicode(s, res))
+ return;
+ MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage());
+ }
+
bool IsThereCrc() const
{
- if (CompressionMethod == NFileHeader::NCompressionMethod::kWzAES)
+ if (Method == NFileHeader::NCompressionMethod::kWzAES)
{
- CWzAesExtraField aesField;
- if (CentralExtra.GetWzAesField(aesField))
+ CWzAesExtra aesField;
+ if (CentralExtra.GetWzAes(aesField))
return aesField.NeedCrc();
}
- return (FileCRC != 0 || !IsDir());
+ return (Crc != 0 || !IsDir());
}
- WORD GetCodePage() const
+ UINT GetCodePage() const
{
- return (WORD)((MadeByVersion.HostOS == NFileHeader::NHostOS::kFAT
- || MadeByVersion.HostOS == NFileHeader::NHostOS::kNTFS
- ) ? CP_OEMCP : CP_ACP);
+ Byte hostOS = GetHostOS();
+ return (UINT)((
+ hostOS == NFileHeader::NHostOS::kFAT ||
+ hostOS == NFileHeader::NHostOS::kNTFS) ? CP_OEMCP : CP_ACP);
}
- CItem() : FromLocal(false), FromCentral(false), NtfsTimeIsDefined(false) {}
};
}}
diff --git a/CPP/7zip/Archive/Zip/ZipItemEx.h b/CPP/7zip/Archive/Zip/ZipItemEx.h
deleted file mode 100755
index ab62cdbb..00000000
--- a/CPP/7zip/Archive/Zip/ZipItemEx.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Archive/ZipItemEx.h
-
-#ifndef __ARCHIVE_ZIP_ITEMEX_H
-#define __ARCHIVE_ZIP_ITEMEX_H
-
-#include "ZipHeader.h"
-#include "ZipItem.h"
-
-namespace NArchive {
-namespace NZip {
-
-class CItemEx: public CItem
-{
-public:
- UInt32 FileHeaderWithNameSize;
- UInt16 LocalExtraSize;
-
- UInt64 GetLocalFullSize() const
- { return FileHeaderWithNameSize + LocalExtraSize + PackSize +
- (HasDescriptor() ? NFileHeader::kDataDescriptorSize : 0); };
- /*
- UInt64 GetLocalFullSize(bool isZip64) const
- { return FileHeaderWithNameSize + LocalExtraSize + PackSize +
- (HasDescriptor() ? (isZip64 ? NFileHeader::kDataDescriptor64Size : NFileHeader::kDataDescriptorSize) : 0); };
- */
- UInt64 GetLocalExtraPosition() const
- { return LocalHeaderPosition + FileHeaderWithNameSize; };
- UInt64 GetDataPosition() const
- { return GetLocalExtraPosition() + LocalExtraSize; };
-};
-
-}}
-
-#endif
diff --git a/CPP/7zip/Archive/Zip/ZipOut.cpp b/CPP/7zip/Archive/Zip/ZipOut.cpp
index aa82143e..2a1ba2c4 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipOut.cpp
+++ b/CPP/7zip/Archive/Zip/ZipOut.cpp
@@ -9,80 +9,93 @@
namespace NArchive {
namespace NZip {
-void COutArchive::Create(IOutStream *outStream)
+HRESULT COutArchive::Create(IOutStream *outStream)
{
+ m_CurPos = 0;
if (!m_OutBuffer.Create(1 << 16))
- throw CSystemException(E_OUTOFMEMORY);
+ return E_OUTOFMEMORY;
m_Stream = outStream;
m_OutBuffer.SetStream(outStream);
m_OutBuffer.Init();
- m_BasePosition = 0;
+
+ return m_Stream->Seek(0, STREAM_SEEK_CUR, &m_Base);
+}
+
+void COutArchive::MoveCurPos(UInt64 distanceToMove)
+{
+ m_CurPos += distanceToMove; // test overflow
}
-void COutArchive::MoveBasePosition(UInt64 distanceToMove)
+void COutArchive::SeekToRelatPos(UInt64 offset)
{
- m_BasePosition += distanceToMove; // test overflow
+ HRESULT res = m_Stream->Seek(m_Base + offset, STREAM_SEEK_SET, NULL);
+ if (res != S_OK)
+ throw CSystemException(res);
}
-void COutArchive::PrepareWriteCompressedDataZip64(UInt16 fileNameLength, bool isZip64, bool aesEncryption)
+void COutArchive::PrepareWriteCompressedDataZip64(unsigned fileNameLen, bool isZip64, bool aesEncryption)
{
m_IsZip64 = isZip64;
m_ExtraSize = isZip64 ? (4 + 8 + 8) : 0;
if (aesEncryption)
- m_ExtraSize += 4 + 7;
- m_LocalFileHeaderSize = 4 + NFileHeader::kLocalBlockSize + fileNameLength + m_ExtraSize;
+ m_ExtraSize += 4 + k_WzAesExtra_Size;
+ m_LocalFileHeaderSize = kLocalHeaderSize + fileNameLen + m_ExtraSize;
}
-void COutArchive::PrepareWriteCompressedData(UInt16 fileNameLength, UInt64 unPackSize, bool aesEncryption)
+void COutArchive::PrepareWriteCompressedData(unsigned fileNameLen, UInt64 unPackSize, bool aesEncryption)
{
- // We test it to 0xF8000000 to support case when compressed size
- // can be larger than uncompressed size.
- PrepareWriteCompressedDataZip64(fileNameLength, unPackSize >= 0xF8000000, aesEncryption);
+ // We use Zip64, if unPackSize size is larger than 0xF8000000 to support
+ // cases when compressed size can be about 3% larger than uncompressed size
+
+ PrepareWriteCompressedDataZip64(fileNameLen, unPackSize >= (UInt32)0xF8000000, aesEncryption);
}
-void COutArchive::PrepareWriteCompressedData2(UInt16 fileNameLength, UInt64 unPackSize, UInt64 packSize, bool aesEncryption)
+#define DOES_NEED_ZIP64(v) (v >= (UInt32)0xFFFFFFFF)
+
+void COutArchive::PrepareWriteCompressedData2(unsigned fileNameLen, UInt64 unPackSize, UInt64 packSize, bool aesEncryption)
{
- bool isUnPack64 = unPackSize >= 0xFFFFFFFF;
- bool isPack64 = packSize >= 0xFFFFFFFF;
- bool isZip64 = isPack64 || isUnPack64;
- PrepareWriteCompressedDataZip64(fileNameLength, isZip64, aesEncryption);
+ bool isZip64 =
+ DOES_NEED_ZIP64(unPackSize) ||
+ DOES_NEED_ZIP64(packSize);
+ PrepareWriteCompressedDataZip64(fileNameLen, isZip64, aesEncryption);
}
void COutArchive::WriteBytes(const void *buffer, UInt32 size)
{
m_OutBuffer.WriteBytes(buffer, size);
- m_BasePosition += size;
+ m_CurPos += size;
}
-void COutArchive::WriteByte(Byte b)
+void COutArchive::Write8(Byte b)
{
- WriteBytes(&b, 1);
+ m_OutBuffer.WriteByte(b);
+ m_CurPos++;
}
-void COutArchive::WriteUInt16(UInt16 value)
+void COutArchive::Write16(UInt16 val)
{
for (int i = 0; i < 2; i++)
{
- WriteByte((Byte)value);
- value >>= 8;
+ Write8((Byte)val);
+ val >>= 8;
}
}
-void COutArchive::WriteUInt32(UInt32 value)
+void COutArchive::Write32(UInt32 val)
{
for (int i = 0; i < 4; i++)
{
- WriteByte((Byte)value);
- value >>= 8;
+ Write8((Byte)val);
+ val >>= 8;
}
}
-void COutArchive::WriteUInt64(UInt64 value)
+void COutArchive::Write64(UInt64 val)
{
for (int i = 0; i < 8; i++)
{
- WriteByte((Byte)value);
- value >>= 8;
+ Write8((Byte)val);
+ val >>= 8;
}
}
@@ -90,178 +103,181 @@ void COutArchive::WriteExtra(const CExtraBlock &extra)
{
if (extra.SubBlocks.Size() != 0)
{
- for (int i = 0; i < extra.SubBlocks.Size(); i++)
+ FOR_VECTOR (i, extra.SubBlocks)
{
const CExtraSubBlock &subBlock = extra.SubBlocks[i];
- WriteUInt16(subBlock.ID);
- WriteUInt16((UInt16)subBlock.Data.GetCapacity());
- WriteBytes(subBlock.Data, (UInt32)subBlock.Data.GetCapacity());
+ Write16(subBlock.ID);
+ Write16((UInt16)subBlock.Data.Size());
+ WriteBytes(subBlock.Data, (UInt32)subBlock.Data.Size());
}
}
}
-void COutArchive::SeekTo(UInt64 offset)
+void COutArchive::WriteCommonItemInfo(const CLocalItem &item, bool isZip64)
{
- HRESULT res = m_Stream->Seek(offset, STREAM_SEEK_SET, NULL);
- if (res != S_OK)
- throw CSystemException(res);
+ {
+ 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);
+ Write32(item.Crc);
}
+#define WRITE_32_VAL_SPEC(__v, __isZip64) Write32((__isZip64) ? 0xFFFFFFFF : (UInt32)(__v));
+
void COutArchive::WriteLocalHeader(const CLocalItem &item)
{
- SeekTo(m_BasePosition);
+ SeekToCurPos();
- bool isZip64 = m_IsZip64 || item.PackSize >= 0xFFFFFFFF || item.UnPackSize >= 0xFFFFFFFF;
+ bool isZip64 = m_IsZip64 ||
+ DOES_NEED_ZIP64(item.PackSize) ||
+ DOES_NEED_ZIP64(item.Size);
- WriteUInt32(NSignature::kLocalFileHeader);
- {
- Byte ver = item.ExtractVersion.Version;
- if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
- ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
- WriteByte(ver);
- }
- WriteByte(item.ExtractVersion.HostOS);
- WriteUInt16(item.Flags);
- WriteUInt16(item.CompressionMethod);
- WriteUInt32(item.Time);
- WriteUInt32(item.FileCRC);
- WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.PackSize);
- WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize);
- WriteUInt16((UInt16)item.Name.Length());
+ Write32(NSignature::kLocalFileHeader);
+ WriteCommonItemInfo(item, isZip64);
+
+ WRITE_32_VAL_SPEC(item.PackSize, isZip64);
+ WRITE_32_VAL_SPEC(item.Size, isZip64);
+
+ Write16((UInt16)item.Name.Len());
{
- UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 16): 0) + item.LocalExtra.GetSize());
- if (localExtraSize > m_ExtraSize)
+ UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 8 + 8): 0) + item.LocalExtra.GetSize());
+ if (localExtraSize != m_ExtraSize)
throw CSystemException(E_FAIL);
}
- WriteUInt16((UInt16)m_ExtraSize); // test it;
- WriteBytes((const char *)item.Name, item.Name.Length());
+ Write16((UInt16)m_ExtraSize);
+ WriteBytes((const char *)item.Name, item.Name.Len());
- UInt32 extraPos = 0;
if (isZip64)
{
- extraPos += 4 + 16;
- WriteUInt16(NFileHeader::NExtraID::kZip64);
- WriteUInt16(16);
- WriteUInt64(item.UnPackSize);
- WriteUInt64(item.PackSize);
+ Write16(NFileHeader::NExtraID::kZip64);
+ Write16(8 + 8);
+ Write64(item.Size);
+ Write64(item.PackSize);
}
WriteExtra(item.LocalExtra);
- extraPos += (UInt32)item.LocalExtra.GetSize();
- for (; extraPos < m_ExtraSize; extraPos++)
- WriteByte(0);
+
+ // Why don't we write NTFS timestamps to local header?
+ // Probably we want to reduce size of archive?
m_OutBuffer.FlushWithCheck();
- MoveBasePosition(item.PackSize);
- SeekTo(m_BasePosition);
+ MoveCurPos(item.PackSize);
}
-void COutArchive::WriteCentralHeader(const CItem &item)
+void COutArchive::WriteCentralHeader(const CItemOut &item)
{
- bool isUnPack64 = item.UnPackSize >= 0xFFFFFFFF;
- bool isPack64 = item.PackSize >= 0xFFFFFFFF;
- bool isPosition64 = item.LocalHeaderPosition >= 0xFFFFFFFF;
- bool isZip64 = isPack64 || isUnPack64 || isPosition64;
+ 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;
- WriteUInt32(NSignature::kCentralFileHeader);
- WriteByte(item.MadeByVersion.Version);
- WriteByte(item.MadeByVersion.HostOS);
- {
- Byte ver = item.ExtractVersion.Version;
- if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
- ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
- WriteByte(ver);
- }
- WriteByte(item.ExtractVersion.HostOS);
- WriteUInt16(item.Flags);
- WriteUInt16(item.CompressionMethod);
- WriteUInt32(item.Time);
- WriteUInt32(item.FileCRC);
- WriteUInt32(isPack64 ? 0xFFFFFFFF: (UInt32)item.PackSize);
- WriteUInt32(isUnPack64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize);
- WriteUInt16((UInt16)item.Name.Length());
- UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
+ Write32(NSignature::kCentralFileHeader);
+ Write8(item.MadeByVersion.Version);
+ Write8(item.MadeByVersion.HostOS);
+
+ WriteCommonItemInfo(item, isZip64);
+
+ 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);
- UInt16 centralExtraSize = (UInt16)(isZip64 ? (4 + zip64ExtraSize) : 0) + (item.NtfsTimeIsDefined ? (4 + kNtfsExtraSize) : 0);
- centralExtraSize = (UInt16)(centralExtraSize + item.CentralExtra.GetSize());
- WriteUInt16(centralExtraSize); // test it;
- WriteUInt16((UInt16)item.Comment.GetCapacity());
- WriteUInt16(0); // DiskNumberStart;
- WriteUInt16(item.InternalAttributes);
- WriteUInt32(item.ExternalAttributes);
- WriteUInt32(isPosition64 ? 0xFFFFFFFF: (UInt32)item.LocalHeaderPosition);
- WriteBytes((const char *)item.Name, item.Name.Length());
+ const UInt16 centralExtraSize = (UInt16)(
+ (isZip64 ? 4 + zip64ExtraSize : 0) +
+ (item.NtfsTimeIsDefined ? 4 + kNtfsExtraSize : 0) +
+ item.CentralExtra.GetSize());
+
+ Write16(centralExtraSize); // test it;
+ Write16((UInt16)item.Comment.Size());
+ 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)
{
- WriteUInt16(NFileHeader::NExtraID::kZip64);
- WriteUInt16(zip64ExtraSize);
- if(isUnPack64)
- WriteUInt64(item.UnPackSize);
- if(isPack64)
- WriteUInt64(item.PackSize);
- if(isPosition64)
- WriteUInt64(item.LocalHeaderPosition);
+ Write16(NFileHeader::NExtraID::kZip64);
+ Write16(zip64ExtraSize);
+ if (isUnPack64)
+ Write64(item.Size);
+ if (isPack64)
+ Write64(item.PackSize);
+ if (isPosition64)
+ Write64(item.LocalHeaderPos);
}
+
if (item.NtfsTimeIsDefined)
{
- WriteUInt16(NFileHeader::NExtraID::kNTFS);
- WriteUInt16(kNtfsExtraSize);
- WriteUInt32(0); // reserved
- WriteUInt16(NFileHeader::NNtfsExtra::kTagTime);
- WriteUInt16(8 * 3);
- WriteUInt32(item.NtfsMTime.dwLowDateTime);
- WriteUInt32(item.NtfsMTime.dwHighDateTime);
- WriteUInt32(item.NtfsATime.dwLowDateTime);
- WriteUInt32(item.NtfsATime.dwHighDateTime);
- WriteUInt32(item.NtfsCTime.dwLowDateTime);
- WriteUInt32(item.NtfsCTime.dwHighDateTime);
+ 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 (item.Comment.GetCapacity() > 0)
- WriteBytes(item.Comment, (UInt32)item.Comment.GetCapacity());
+ if (item.Comment.Size() > 0)
+ WriteBytes(item.Comment, (UInt32)item.Comment.Size());
}
-void COutArchive::WriteCentralDir(const CObjectVector<CItem> &items, const CByteBuffer *comment)
+void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment)
{
- SeekTo(m_BasePosition);
+ SeekToCurPos();
- UInt64 cdOffset = GetCurrentPosition();
- for(int i = 0; i < items.Size(); i++)
+ UInt64 cdOffset = GetCurPos();
+ FOR_VECTOR (i, items)
WriteCentralHeader(items[i]);
- UInt64 cd64EndOffset = GetCurrentPosition();
+ UInt64 cd64EndOffset = GetCurPos();
UInt64 cdSize = cd64EndOffset - cdOffset;
- bool cdOffset64 = cdOffset >= 0xFFFFFFFF;
- bool cdSize64 = cdSize >= 0xFFFFFFFF;
+ 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)
{
- WriteUInt32(NSignature::kZip64EndOfCentralDir);
- WriteUInt64(kZip64EcdSize); // ThisDiskNumber = 0;
- WriteUInt16(45); // version
- WriteUInt16(45); // version
- WriteUInt32(0); // ThisDiskNumber = 0;
- WriteUInt32(0); // StartCentralDirectoryDiskNumber;;
- WriteUInt64((UInt64)items.Size());
- WriteUInt64((UInt64)items.Size());
- WriteUInt64((UInt64)cdSize);
- WriteUInt64((UInt64)cdOffset);
-
- WriteUInt32(NSignature::kZip64EndOfCentralDirLocator);
- WriteUInt32(0); // number of the disk with the start of the zip64 end of central directory
- WriteUInt64(cd64EndOffset);
- WriteUInt32(1); // total number of disks
+ Write32(NSignature::kEcd64);
+ Write64(kEcd64_MainSize);
+ 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);
+
+ 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
}
- WriteUInt32(NSignature::kEndOfCentralDir);
- WriteUInt16(0); // ThisDiskNumber = 0;
- WriteUInt16(0); // StartCentralDirectoryDiskNumber;
- WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size()));
- WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size()));
- WriteUInt32(cdSize64 ? 0xFFFFFFFF: (UInt32)cdSize);
- WriteUInt32(cdOffset64 ? 0xFFFFFFFF: (UInt32)cdOffset);
- UInt32 commentSize = (UInt32)(comment ? comment->GetCapacity() : 0);
- WriteUInt16((UInt16)commentSize);
+
+ 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);
+
+ UInt32 commentSize = (UInt32)(comment ? comment->Size() : 0);
+ Write16((UInt16)commentSize);
if (commentSize > 0)
WriteBytes((const Byte *)*comment, commentSize);
m_OutBuffer.FlushWithCheck();
@@ -271,14 +287,21 @@ void COutArchive::CreateStreamForCompressing(IOutStream **outStream)
{
COffsetOutStream *streamSpec = new COffsetOutStream;
CMyComPtr<IOutStream> tempStream(streamSpec);
- streamSpec->Init(m_Stream, m_BasePosition + m_LocalFileHeaderSize);
+ streamSpec->Init(m_Stream, m_Base + m_CurPos + m_LocalFileHeaderSize);
*outStream = tempStream.Detach();
}
+/*
void COutArchive::SeekToPackedDataPosition()
{
SeekTo(m_BasePosition + m_LocalFileHeaderSize);
}
+*/
+
+void COutArchive::SeekToCurPos()
+{
+ SeekToRelatPos(m_CurPos);
+}
void COutArchive::CreateStreamForCopying(ISequentialOutStream **outStream)
{
diff --git a/CPP/7zip/Archive/Zip/ZipOut.h b/CPP/7zip/Archive/Zip/ZipOut.h
index 2f6349e5..eaaa0320 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipOut.h
+++ b/CPP/7zip/Archive/Zip/ZipOut.h
@@ -3,7 +3,7 @@
#ifndef __ZIP_OUT_H
#define __ZIP_OUT_H
-#include "Common/MyCom.h"
+#include "../../../Common/MyCom.h"
#include "../../IStream.h"
#include "../../Common/OutBuffer.h"
@@ -14,41 +14,73 @@ namespace NArchive {
namespace NZip {
// can throw CSystemException and COutBufferException
-
+
+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) {}
+};
+
class COutArchive
{
CMyComPtr<IOutStream> m_Stream;
COutBuffer m_OutBuffer;
- UInt64 m_BasePosition;
+ UInt64 m_Base; // Base of arc (offset in output Stream)
+ UInt64 m_CurPos; // Curent position in archive (relative from m_Base)
+
UInt32 m_LocalFileHeaderSize;
UInt32 m_ExtraSize;
bool m_IsZip64;
+ void SeekToRelatPos(UInt64 offset);
+
void WriteBytes(const void *buffer, UInt32 size);
- void WriteByte(Byte b);
- void WriteUInt16(UInt16 value);
- void WriteUInt32(UInt32 value);
- void WriteUInt64(UInt64 value);
+ 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 WriteExtraHeader(const CItem &item);
- void WriteCentralHeader(const CItem &item);
void WriteExtra(const CExtraBlock &extra);
- void SeekTo(UInt64 offset);
+ void WriteCommonItemInfo(const CLocalItem &item, bool isZip64);
+ void WriteCentralHeader(const CItemOut &item);
+
+ void PrepareWriteCompressedDataZip64(unsigned fileNameLen, bool isZip64, bool aesEncryption);
+
public:
- void Create(IOutStream *outStream);
- void MoveBasePosition(UInt64 distanceToMove);
- UInt64 GetCurrentPosition() const { return m_BasePosition; };
- void PrepareWriteCompressedDataZip64(UInt16 fileNameLength, bool isZip64, bool aesEncryption);
- void PrepareWriteCompressedData(UInt16 fileNameLength, UInt64 unPackSize, bool aesEncryption);
- void PrepareWriteCompressedData2(UInt16 fileNameLength, UInt64 unPackSize, UInt64 packSize, bool aesEncryption);
+ HRESULT Create(IOutStream *outStream);
+
+ void MoveCurPos(UInt64 distanceToMove);
+ UInt64 GetCurPos() const { return m_CurPos; };
+
+ void SeekToCurPos();
+
+ void PrepareWriteCompressedData(unsigned fileNameLen, UInt64 unPackSize, bool aesEncryption);
+ void PrepareWriteCompressedData2(unsigned fileNameLen, UInt64 unPackSize, UInt64 packSize, bool aesEncryption);
void WriteLocalHeader(const CLocalItem &item);
- void WriteCentralDir(const CObjectVector<CItem> &items, const CByteBuffer *comment);
+ void WriteLocalHeader_And_SeekToNextFile(const CLocalItem &item)
+ {
+ WriteLocalHeader(item);
+ SeekToCurPos();
+ }
+
+ void WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment);
void CreateStreamForCompressing(IOutStream **outStream);
void CreateStreamForCopying(ISequentialOutStream **outStream);
- void SeekToPackedDataPosition();
};
}}
diff --git a/CPP/7zip/Archive/Zip/ZipRegister.cpp b/CPP/7zip/Archive/Zip/ZipRegister.cpp
index 3e7aade8..545e76c6 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipRegister.cpp
+++ b/CPP/7zip/Archive/Zip/ZipRegister.cpp
@@ -5,14 +5,27 @@
#include "../../Common/RegisterArc.h"
#include "ZipHandler.h"
-static IInArchive *CreateArc() { return new NArchive::NZip::CHandler; }
-#ifndef EXTRACT_ONLY
-static IOutArchive *CreateArcOut() { return new NArchive::NZip::CHandler; }
-#else
-#define CreateArcOut 0
-#endif
+
+namespace NArchive {
+namespace NZip {
+
+IMP_CreateArcIn
+IMP_CreateArcOut
static CArcInfo g_ArcInfo =
- { L"zip", L"zip jar xpi odt ods docx xlsx", 0, 1, { 0x50, 0x4B, 0x03, 0x04 }, 4, false, CreateArc, CreateArcOut };
+ { "zip", "zip zipx jar xpi odt ods docx xlsx epub", 0, 1,
+ 3 + 4 + 4 + 6,
+ {
+ 4, 0x50, 0x4B, 0x03, 0x04,
+ 4, 0x50, 0x4B, 0x05, 0x06,
+ 6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B,
+ },
+ 0,
+ NArcInfoFlags::kFindSignature |
+ NArcInfoFlags::kMultiSignature |
+ NArcInfoFlags::kUseGlobalOffset,
+ REF_CreateArc_Pair, IsArc_Zip };
REGISTER_ARC(Zip)
+
+}}
diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp
index a91364be..2978e387 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp
+++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp
@@ -4,12 +4,12 @@
#include "../../../../C/Alloc.h"
-#include "Common/AutoPtr.h"
-#include "Common/Defs.h"
-#include "Common/StringConvert.h"
+#include "../../../Common/AutoPtr.h"
+#include "../../../Common/Defs.h"
+#include "../../../Common/StringConvert.h"
-#include "Windows/Defs.h"
-#include "Windows/Thread.h"
+#include "../../../Windows/Defs.h"
+#include "../../../Windows/Thread.h"
#include "../../Common/CreateCoder.h"
#include "../../Common/LimitedStreams.h"
@@ -44,12 +44,12 @@ static const Byte kExtractHostOS = kHostOS;
static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStored;
-static HRESULT CopyBlockToArchive(ISequentialInStream *inStream,
+static HRESULT CopyBlockToArchive(ISequentialInStream *inStream, UInt64 size,
COutArchive &outArchive, ICompressProgressInfo *progress)
{
CMyComPtr<ISequentialOutStream> outStream;
outArchive.CreateStreamForCopying(&outStream);
- return NCompress::CopyStream(inStream, outStream, progress);
+ return NCompress::CopyStream_ExactSize(inStream, outStream, size, progress);
}
static HRESULT WriteRange(IInStream *inStream, COutArchive &outArchive,
@@ -57,13 +57,7 @@ static HRESULT WriteRange(IInStream *inStream, COutArchive &outArchive,
{
UInt64 position;
RINOK(inStream->Seek(range.Position, STREAM_SEEK_SET, &position));
-
- CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
- CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
- streamSpec->SetStream(inStream);
- streamSpec->Init(range.Size);
-
- RINOK(CopyBlockToArchive(inStreamLimited, outArchive, progress));
+ RINOK(CopyBlockToArchive(inStream, range.Size, outArchive, progress));
return progress->SetRatioInfo(&range.Size, &range.Size);
}
@@ -71,42 +65,42 @@ static void SetFileHeader(
COutArchive &archive,
const CCompressionMethodMode &options,
const CUpdateItem &ui,
- CItem &item)
+ CItemOut &item)
{
- item.UnPackSize = ui.Size;
+ item.Size = ui.Size;
bool isDir;
item.ClearFlags();
- if (ui.NewProperties)
+ if (ui.NewProps)
{
isDir = ui.IsDir;
item.Name = ui.Name;
item.SetUtf8(ui.IsUtf8);
- item.ExternalAttributes = ui.Attributes;
+ item.ExternalAttrib = ui.Attrib;
item.Time = ui.Time;
- item.NtfsMTime = ui.NtfsMTime;
- item.NtfsATime = ui.NtfsATime;
- item.NtfsCTime = ui.NtfsCTime;
+ 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.LocalHeaderPosition = archive.GetCurrentPosition();
+ item.LocalHeaderPos = archive.GetCurPos();
item.MadeByVersion.HostOS = kMadeByHostOS;
item.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion;
item.ExtractVersion.HostOS = kExtractHostOS;
- item.InternalAttributes = 0; // test it
+ item.InternalAttrib = 0; // test it
item.SetEncrypted(!isDir && options.PasswordIsDefined);
if (isDir)
{
item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir;
- item.CompressionMethod = kMethodForDirectory;
+ item.Method = kMethodForDirectory;
item.PackSize = 0;
- item.FileCRC = 0; // test it
+ item.Crc = 0; // test it
}
}
@@ -114,9 +108,9 @@ static void SetItemInfoFromCompressingResult(const CCompressingResult &compressi
bool isAesMode, Byte aesKeyMode, CItem &item)
{
item.ExtractVersion.Version = compressingResult.ExtractVersion;
- item.CompressionMethod = compressingResult.Method;
- item.FileCRC = compressingResult.CRC;
- item.UnPackSize = compressingResult.UnpackSize;
+ item.Method = compressingResult.Method;
+ item.Crc = compressingResult.CRC;
+ item.Size = compressingResult.UnpackSize;
item.PackSize = compressingResult.PackSize;
item.LocalExtra.Clear();
@@ -124,11 +118,11 @@ static void SetItemInfoFromCompressingResult(const CCompressingResult &compressi
if (isAesMode)
{
- CWzAesExtraField wzAesField;
+ CWzAesExtra wzAesField;
wzAesField.Strength = aesKeyMode;
wzAesField.Method = compressingResult.Method;
- item.CompressionMethod = NFileHeader::NCompressionMethod::kWzAES;
- item.FileCRC = 0;
+ item.Method = NFileHeader::NCompressionMethod::kWzAES;
+ item.Crc = 0;
CExtraSubBlock sb;
wzAesField.SetSubBlock(sb);
item.LocalExtra.SubBlocks.Add(sb);
@@ -142,10 +136,7 @@ static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo);
struct CThreadInfo
{
- #ifdef EXTERNAL_CODECS
- CMyComPtr<ICompressCodecsInfo> _codecsInfo;
- const CObjectVector<CCodecInfoEx> *_externalCodecs;
- #endif
+ DECL_EXTERNAL_CODECS_LOC_VARS2;
NWindows::CThread Thread;
NWindows::NSynchronization::CAutoResetEvent CompressEvent;
@@ -202,9 +193,7 @@ void CThreadInfo::WaitAndCode()
if (ExitThread)
return;
Result = Coder.Compress(
- #ifdef EXTERNAL_CODECS
- _codecsInfo, _externalCodecs,
- #endif
+ EXTERNAL_CODECS_LOC_VARS
InStream, OutStream, Progress, CompressingResult);
if (Result == S_OK && Progress)
Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize);
@@ -224,7 +213,7 @@ public:
CObjectVector<CThreadInfo> Threads;
~CThreads()
{
- for (int i = 0; i < Threads.Size(); i++)
+ FOR_VECTOR (i, Threads)
Threads[i].StopWaitClose();
}
};
@@ -245,7 +234,7 @@ public:
CMemRefs(CMemBlockManagerMt *manager): Manager(manager) {} ;
~CMemRefs()
{
- for (int i = 0; i < Refs.Size(); i++)
+ FOR_VECTOR (i, Refs)
Refs[i].FreeOpt(Manager);
}
};
@@ -335,69 +324,74 @@ STDMETHODIMP CMtProgressMixer::SetRatioInfo(const UInt64 *inSize, const UInt64 *
#endif
-static HRESULT UpdateItemOldData(COutArchive &archive,
- IInStream *inStream,
- const CUpdateItem &ui, CItemEx &item,
+static HRESULT UpdateItemOldData(
+ COutArchive &archive,
+ CInArchive *inArchive,
+ const CItemEx &itemEx,
+ const CUpdateItem &ui,
+ CItemOut &item,
/* bool izZip64, */
ICompressProgressInfo *progress,
UInt64 &complexity)
{
- if (ui.NewProperties)
+ if (ui.NewProps)
{
if (item.HasDescriptor())
return E_NOTIMPL;
// use old name size.
// CUpdateRange range(item.GetLocalExtraPosition(), item.LocalExtraSize + item.PackSize);
- CUpdateRange range(item.GetDataPosition(), item.PackSize);
+ CUpdateRange range(inArchive->GetOffsetInStream(itemEx.GetDataPosition()), itemEx.PackSize);
- // item.ExternalAttributes = ui.Attributes;
- // Test it
+ // we keep ExternalAttrib and some another properties from old archive
+ // item.ExternalAttrib = ui.Attrib;
+
item.Name = ui.Name;
item.SetUtf8(ui.IsUtf8);
item.Time = ui.Time;
- item.NtfsMTime = ui.NtfsMTime;
- item.NtfsATime = ui.NtfsATime;
- item.NtfsCTime = ui.NtfsCTime;
+ item.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.PrepareWriteCompressedData2((UInt16)item.Name.Length(), item.UnPackSize, item.PackSize, item.LocalExtra.HasWzAesField());
- item.LocalHeaderPosition = archive.GetCurrentPosition();
- archive.SeekToPackedDataPosition();
- RINOK(WriteRange(inStream, archive, range, progress));
- complexity += range.Size;
+ item.LocalHeaderPos = archive.GetCurPos();
+
+ archive.PrepareWriteCompressedData2(item.Name.Len(), item.Size, item.PackSize, item.LocalExtra.HasWzAes());
archive.WriteLocalHeader(item);
+ RINOK(WriteRange(inArchive->Stream, archive, range, progress));
+ complexity += range.Size;
}
else
{
- CUpdateRange range(item.LocalHeaderPosition, item.GetLocalFullSize());
+ CUpdateRange range(inArchive->GetOffsetInStream(itemEx.LocalHeaderPos), itemEx.GetLocalFullSize());
// set new header position
- item.LocalHeaderPosition = archive.GetCurrentPosition();
+ item.LocalHeaderPos = archive.GetCurPos();
- RINOK(WriteRange(inStream, archive, range, progress));
+ RINOK(WriteRange(inArchive->Stream, archive, range, progress));
complexity += range.Size;
- archive.MoveBasePosition(range.Size);
+ archive.MoveCurPos(range.Size);
}
return S_OK;
}
static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options,
- const CUpdateItem &ui, CItemEx &item)
+ const CUpdateItem &ui, CItemOut &item)
{
SetFileHeader(archive, *options, ui, item);
- archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsRealAesMode());
- archive.WriteLocalHeader(item);
+ archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size,
+ // options->IsRealAesMode()
+ false // fixed 9.31
+ );
+ archive.WriteLocalHeader_And_SeekToNextFile(item);
}
static HRESULT Update2St(
DECL_EXTERNAL_CODECS_LOC_VARS
COutArchive &archive,
CInArchive *inArchive,
- IInStream *inStream,
const CObjectVector<CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
const CCompressionMethodMode *options,
@@ -410,26 +404,29 @@ static HRESULT Update2St(
CAddCommon compressor(*options);
- CObjectVector<CItem> items;
+ CObjectVector<CItemOut> items;
UInt64 unpackSizeTotal = 0, packSizeTotal = 0;
- for (int itemIndex = 0; itemIndex < updateItems.Size(); itemIndex++)
+ FOR_VECTOR (itemIndex, updateItems)
{
lps->InSize = unpackSizeTotal;
lps->OutSize = packSizeTotal;
RINOK(lps->SetCur());
const CUpdateItem &ui = updateItems[itemIndex];
- CItemEx item;
- if (!ui.NewProperties || !ui.NewData)
+ CItemEx itemEx;
+ CItemOut item;
+
+ if (!ui.NewProps || !ui.NewData)
{
- item = inputItems[ui.IndexInArchive];
- if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK)
+ itemEx = inputItems[ui.IndexInArc];
+ if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK)
return E_NOTIMPL;
+ (CItem &)item = itemEx;
}
if (ui.NewData)
{
- bool isDir = ((ui.NewProperties) ? ui.IsDir : item.IsDir());
+ bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir());
if (isDir)
{
WriteDirHeader(archive, options, ui, item);
@@ -445,10 +442,12 @@ static HRESULT Update2St(
continue;
}
RINOK(res);
+ if (!fileInStream)
+ return E_INVALIDARG;
// file Size can be 64-bit !!!
SetFileHeader(archive, *options, ui, item);
- archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsRealAesMode());
+ archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options->IsRealAesMode());
CCompressingResult compressingResult;
CMyComPtr<IOutStream> outStream;
archive.CreateStreamForCompressing(&outStream);
@@ -456,9 +455,9 @@ static HRESULT Update2St(
EXTERNAL_CODECS_LOC_VARS
fileInStream, outStream, progress, compressingResult));
SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item);
- archive.WriteLocalHeader(item);
+ archive.WriteLocalHeader_And_SeekToNextFile(item);
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
- unpackSizeTotal += item.UnPackSize;
+ unpackSizeTotal += item.Size;
packSizeTotal += item.PackSize;
}
}
@@ -466,12 +465,12 @@ static HRESULT Update2St(
{
UInt64 complexity = 0;
lps->SendRatio = false;
- RINOK(UpdateItemOldData(archive, inStream, ui, item, progress, complexity));
+ RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, complexity));
lps->SendRatio = true;
lps->ProgressOffset += complexity;
}
items.Add(item);
- lps->ProgressOffset += NFileHeader::kLocalBlockSize;
+ lps->ProgressOffset += kLocalHeaderSize;
}
lps->InSize = unpackSizeTotal;
lps->OutSize = packSizeTotal;
@@ -484,7 +483,6 @@ static HRESULT Update2(
DECL_EXTERNAL_CODECS_LOC_VARS
COutArchive &archive,
CInArchive *inArchive,
- IInStream *inStream,
const CObjectVector<CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
const CCompressionMethodMode *options,
@@ -495,7 +493,7 @@ static HRESULT Update2(
UInt64 numFilesToCompress = 0;
UInt64 numBytesToCompress = 0;
- int i;
+ unsigned i;
for (i = 0; i < updateItems.Size(); i++)
{
const CUpdateItem &ui = updateItems[i];
@@ -511,18 +509,18 @@ static HRESULT Update2(
}
else
{
- CItemEx inputItem = inputItems[ui.IndexInArchive];
+ CItemEx inputItem = inputItems[ui.IndexInArc];
if (inArchive->ReadLocalItemAfterCdItemFull(inputItem) != S_OK)
return E_NOTIMPL;
complexity += inputItem.GetLocalFullSize();
// complexity += inputItem.GetCentralExtraPlusCommentSize();
}
- complexity += NFileHeader::kLocalBlockSize;
- complexity += NFileHeader::kCentralBlockSize;
+ complexity += kLocalHeaderSize;
+ complexity += kCentralHeaderSize;
}
if (comment)
- complexity += comment->GetCapacity();
+ complexity += comment->Size();
complexity++; // end of central
updateCallback->SetTotal(complexity);
@@ -540,6 +538,9 @@ static HRESULT Update2(
UInt32 numThreads = options->NumThreads;
if (numThreads > kNumMaxThreads)
numThreads = kNumMaxThreads;
+ if (numThreads < 1)
+ numThreads = 1;
+
const size_t kMemPerThread = (1 << 25);
const size_t kBlockSize = 1 << 16;
@@ -549,16 +550,18 @@ static HRESULT Update2(
if (numFilesToCompress <= 1)
mtMode = false;
+ Byte method = options->MethodSequence.Front();
if (!mtMode)
{
- if (numThreads < 2)
- if (options2.MethodInfo.FindProp(NCoderPropID::kNumThreads) < 0 &&
- options2.NumThreadsWasChanged)
- options2.MethodInfo.AddNumThreadsProp(1);
+ if (options2.MethodInfo.FindProp(NCoderPropID::kNumThreads) < 0)
+ {
+ // fixed for 9.31. bzip2 default is just one thread.
+ if (options2.NumThreadsWasChanged || method == NFileHeader::NCompressionMethod::kBZip2)
+ options2.MethodInfo.AddNumThreadsProp(numThreads);
+ }
}
else
{
- Byte method = options->MethodSequence.Front();
if (method == NFileHeader::NCompressionMethod::kStored && !options->PasswordIsDefined)
numThreads = 1;
if (method == NFileHeader::NCompressionMethod::kBZip2)
@@ -594,13 +597,13 @@ static HRESULT Update2(
#endif
return Update2St(
EXTERNAL_CODECS_LOC_VARS
- archive, inArchive, inStream,
+ archive, inArchive,
inputItems, updateItems, &options2, comment, updateCallback);
#ifndef _7ZIP_ST
- CObjectVector<CItem> items;
+ CObjectVector<CItemOut> items;
CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer;
CMyComPtr<ICompressProgressInfo> progress = mtProgressMixerSpec;
@@ -629,8 +632,7 @@ static HRESULT Update2(
{
CThreadInfo &threadInfo = threads.Threads[i];
#ifdef EXTERNAL_CODECS
- threadInfo._codecsInfo = codecsInfo;
- threadInfo._externalCodecs = externalCodecs;
+ threadInfo.__externalCodecs = __externalCodecs;
#endif
RINOK(threadInfo.CreateEvents());
threadInfo.OutStreamSpec = new COutMemStream(&memManager);
@@ -643,9 +645,9 @@ static HRESULT Update2(
RINOK(threadInfo.CreateThread());
}
}
- int mtItemIndex = 0;
+ unsigned mtItemIndex = 0;
- int itemIndex = 0;
+ unsigned itemIndex = 0;
int lastRealStreamItemIndex = -1;
while (itemIndex < updateItems.Size())
@@ -655,17 +657,19 @@ static HRESULT Update2(
const CUpdateItem &ui = updateItems[mtItemIndex++];
if (!ui.NewData)
continue;
- CItemEx item;
- if (ui.NewProperties)
+ CItemEx itemEx;
+ CItemOut item;
+ if (ui.NewProps)
{
if (ui.IsDir)
continue;
}
else
{
- item = inputItems[ui.IndexInArchive];
- if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK)
+ itemEx = inputItems[ui.IndexInArc];
+ if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK)
return E_NOTIMPL;
+ (CItem &)item = itemEx;
if (item.IsDir())
continue;
}
@@ -676,13 +680,15 @@ static HRESULT Update2(
if (res == S_FALSE)
{
complexity += ui.Size;
- complexity += NFileHeader::kLocalBlockSize;
+ complexity += kLocalHeaderSize;
mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
refs.Refs[mtItemIndex - 1].Skip = true;
continue;
}
RINOK(res);
+ if (!fileInStream)
+ return E_INVALIDARG;
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
}
@@ -719,29 +725,31 @@ static HRESULT Update2(
const CUpdateItem &ui = updateItems[itemIndex];
- CItemEx item;
- if (!ui.NewProperties || !ui.NewData)
+ CItemEx itemEx;
+ CItemOut item;
+ if (!ui.NewProps || !ui.NewData)
{
- item = inputItems[ui.IndexInArchive];
- if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK)
+ itemEx = inputItems[ui.IndexInArc];
+ if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK)
return E_NOTIMPL;
+ (CItem &)item = itemEx;
}
if (ui.NewData)
{
- bool isDir = ((ui.NewProperties) ? ui.IsDir : item.IsDir());
+ bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir());
if (isDir)
{
WriteDirHeader(archive, options, ui, item);
}
else
{
- if (lastRealStreamItemIndex < itemIndex)
+ if (lastRealStreamItemIndex < (int)itemIndex)
{
lastRealStreamItemIndex = itemIndex;
SetFileHeader(archive, *options, ui, item);
// file Size can be 64-bit !!!
- archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsRealAesMode());
+ archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options->IsRealAesMode());
}
CMemBlocks2 &memRef = refs.Refs[itemIndex];
@@ -750,10 +758,13 @@ static HRESULT Update2(
CMyComPtr<IOutStream> outStream;
archive.CreateStreamForCompressing(&outStream);
memRef.WriteToStream(memManager.GetBlockSize(), outStream);
+ SetFileHeader(archive, *options, ui, 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);
- SetFileHeader(archive, *options, ui, item);
- archive.WriteLocalHeader(item);
+ archive.WriteLocalHeader_And_SeekToNextFile(item);
// RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
memRef.FreeOpt(&memManager);
}
@@ -783,10 +794,10 @@ static HRESULT Update2(
{
RINOK(threadInfo.OutStreamSpec->WriteToRealStream());
threadInfo.OutStreamSpec->ReleaseOutStream();
+ SetFileHeader(archive, *options, ui, item);
SetItemInfoFromCompressingResult(threadInfo.CompressingResult,
options->IsRealAesMode(), options->AesKeyMode, item);
- SetFileHeader(archive, *options, ui, item);
- archive.WriteLocalHeader(item);
+ archive.WriteLocalHeader_And_SeekToNextFile(item);
}
else
{
@@ -801,10 +812,10 @@ static HRESULT Update2(
}
else
{
- RINOK(UpdateItemOldData(archive, inStream, ui, item, progress, complexity));
+ RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, complexity));
}
items.Add(item);
- complexity += NFileHeader::kLocalBlockSize;
+ complexity += kLocalHeaderSize;
mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
itemIndex++;
}
@@ -993,15 +1004,18 @@ STDMETHODIMP CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *proce
STDMETHODIMP CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
{
- switch(seekOrigin)
+ switch (seekOrigin)
{
- case STREAM_SEEK_SET: _virtPos = offset; break;
- case STREAM_SEEK_CUR: _virtPos += offset; break;
- case STREAM_SEEK_END: _virtPos = _virtSize + offset; break;
+ 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;
+ *newPosition = offset;
return S_OK;
}
@@ -1029,16 +1043,33 @@ HRESULT Update(
const CObjectVector<CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
ISequentialOutStream *seqOutStream,
- CInArchive *inArchive,
+ CInArchive *inArchive, bool removeSfx,
CCompressionMethodMode *compressionMethodMode,
IArchiveUpdateCallback *updateCallback)
{
+ if (inArchive)
+ {
+ if (!inArchive->CanUpdate())
+ return E_NOTIMPL;
+ }
+
+
CMyComPtr<IOutStream> outStream;
{
CMyComPtr<IOutStream> outStreamReal;
seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal);
if (!outStreamReal)
return E_NOTIMPL;
+
+ if (inArchive)
+ {
+ if (inArchive->ArcInfo.Base > 0 && !removeSfx)
+ {
+ RINOK(inArchive->Stream->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(NCompress::CopyStream_ExactSize(inArchive->Stream, outStreamReal, inArchive->ArcInfo.Base, NULL));
+ }
+ }
+
CCacheOutStream *cacheStream = new CCacheOutStream();
outStream = cacheStream;
if (!cacheStream->Allocate())
@@ -1046,32 +1077,23 @@ HRESULT Update(
RINOK(cacheStream->Init(outStreamReal));
}
- if (inArchive)
- {
- if (inArchive->ArcInfo.Base != 0 ||
- inArchive->ArcInfo.StartPosition != 0 ||
- !inArchive->IsOkHeaders)
- return E_NOTIMPL;
- }
-
COutArchive outArchive;
- outArchive.Create(outStream);
- /*
- if (inArchive && inArchive->ArcInfo.StartPosition > 0)
+ RINOK(outArchive.Create(outStream));
+
+ if (inArchive)
{
- CMyComPtr<ISequentialInStream> inStream;
- inStream.Attach(inArchive->CreateLimitedStream(0, inArchive->ArcInfo.StartPosition));
- RINOK(CopyBlockToArchive(inStream, outArchive, NULL));
- outArchive.MoveBasePosition(inArchive->ArcInfo.StartPosition);
+ if ((Int64)inArchive->ArcInfo.MarkerPos2 > inArchive->ArcInfo.Base)
+ {
+ RINOK(inArchive->Stream->Seek(inArchive->ArcInfo.Base, STREAM_SEEK_SET, NULL));
+ UInt64 embStubSize = inArchive->ArcInfo.MarkerPos2 - inArchive->ArcInfo.Base;
+ RINOK(NCompress::CopyStream_ExactSize(inArchive->Stream, outStream, embStubSize, NULL));
+ outArchive.MoveCurPos(embStubSize);
+ }
}
- */
- CMyComPtr<IInStream> inStream;
- if (inArchive)
- inStream.Attach(inArchive->CreateStream());
return Update2(
EXTERNAL_CODECS_LOC_VARS
- outArchive, inArchive, inStream,
+ outArchive, inArchive,
inputItems, updateItems,
compressionMethodMode,
inArchive ? &inArchive->ArcInfo.Comment : NULL,
diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.h b/CPP/7zip/Archive/Zip/ZipUpdate.h
index eee16738..747c07bc 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipUpdate.h
+++ b/CPP/7zip/Archive/Zip/ZipUpdate.h
@@ -1,4 +1,4 @@
-// Zip/Update.h
+// ZipUpdate.h
#ifndef __ZIP_UPDATE_H
#define __ZIP_UPDATE_H
@@ -18,28 +18,29 @@ struct CUpdateRange
{
UInt64 Position;
UInt64 Size;
- CUpdateRange() {};
+
+ // CUpdateRange() {};
CUpdateRange(UInt64 position, UInt64 size): Position(position), Size(size) {};
};
struct CUpdateItem
{
bool NewData;
- bool NewProperties;
+ bool NewProps;
bool IsDir;
bool NtfsTimeIsDefined;
bool IsUtf8;
- int IndexInArchive;
+ int IndexInArc;
int IndexInClient;
- UInt32 Attributes;
+ UInt32 Attrib;
UInt32 Time;
UInt64 Size;
AString Name;
// bool Commented;
// CUpdateRange CommentRange;
- FILETIME NtfsMTime;
- FILETIME NtfsATime;
- FILETIME NtfsCTime;
+ FILETIME Ntfs_MTime;
+ FILETIME Ntfs_ATime;
+ FILETIME Ntfs_CTime;
CUpdateItem(): NtfsTimeIsDefined(false), IsUtf8(false), Size(0) {}
};
@@ -49,7 +50,7 @@ HRESULT Update(
const CObjectVector<CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
ISequentialOutStream *seqOutStream,
- CInArchive *inArchive,
+ CInArchive *inArchive, bool removeSfx,
CCompressionMethodMode *compressionMethodMode,
IArchiveUpdateCallback *updateCallback);
diff --git a/CPP/7zip/Archive/makefile b/CPP/7zip/Archive/makefile
index 7512ad56..7512ad56 100755..100644
--- a/CPP/7zip/Archive/makefile
+++ b/CPP/7zip/Archive/makefile