mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-18 06:11:52 -06:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
866a06f5a0 | ||
|
|
da28077952 |
@@ -1,7 +1,7 @@
|
||||
#define MY_VER_MAJOR 17
|
||||
#define MY_VER_MAJOR 18
|
||||
#define MY_VER_MINOR 01
|
||||
#define MY_VER_BUILD 0
|
||||
#define MY_VERSION_NUMBERS "17.01 beta"
|
||||
#define MY_VERSION_NUMBERS "18.01"
|
||||
#define MY_VERSION MY_VERSION_NUMBERS
|
||||
|
||||
#ifdef MY_CPU_NAME
|
||||
@@ -10,12 +10,12 @@
|
||||
#define MY_VERSION_CPU MY_VERSION
|
||||
#endif
|
||||
|
||||
#define MY_DATE "2017-08-28"
|
||||
#define MY_DATE "2018-01-28"
|
||||
#undef MY_COPYRIGHT
|
||||
#undef MY_VERSION_COPYRIGHT_DATE
|
||||
#define MY_AUTHOR_NAME "Igor Pavlov"
|
||||
#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
|
||||
#define MY_COPYRIGHT_CR "Copyright (c) 1999-2017 Igor Pavlov"
|
||||
#define MY_COPYRIGHT_CR "Copyright (c) 1999-2018 Igor Pavlov"
|
||||
|
||||
#ifdef USE_COPYRIGHT_CR
|
||||
#define MY_COPYRIGHT MY_COPYRIGHT_CR
|
||||
|
||||
17
C/XzDec.c
17
C/XzDec.c
@@ -1,5 +1,5 @@
|
||||
/* XzDec.c -- Xz Decode
|
||||
2017-07-27 : Igor Pavlov : Public domain */
|
||||
2018-01-21 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
@@ -742,7 +742,8 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
||||
|
||||
srcRem = srcLenOrig - *srcLen;
|
||||
|
||||
if (srcRem == 0)
|
||||
// XZ_STATE_BLOCK_FOOTER can transit to XZ_STATE_BLOCK_HEADER without input bytes
|
||||
if (srcRem == 0 && p->state != XZ_STATE_BLOCK_FOOTER)
|
||||
{
|
||||
*status = CODER_STATUS_NEEDS_MORE_INPUT;
|
||||
return SZ_OK;
|
||||
@@ -820,8 +821,13 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
||||
|
||||
case XZ_STATE_BLOCK_FOOTER:
|
||||
{
|
||||
if (((p->packSize + p->alignPos) & 3) != 0)
|
||||
if ((((unsigned)p->packSize + p->alignPos) & 3) != 0)
|
||||
{
|
||||
if (srcRem == 0)
|
||||
{
|
||||
*status = CODER_STATUS_NEEDS_MORE_INPUT;
|
||||
return SZ_OK;
|
||||
}
|
||||
(*srcLen)++;
|
||||
p->alignPos++;
|
||||
if (*src++ != 0)
|
||||
@@ -833,6 +839,11 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
||||
UInt32 cur = checkSize - p->pos;
|
||||
if (cur != 0)
|
||||
{
|
||||
if (srcRem == 0)
|
||||
{
|
||||
*status = CODER_STATUS_NEEDS_MORE_INPUT;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (cur > srcRem)
|
||||
cur = (UInt32)srcRem;
|
||||
memcpy(p->buf + p->pos, src, cur);
|
||||
|
||||
@@ -377,11 +377,17 @@ static SRes SeqInFilter_Read(const ISeqInStream *pp, void *data, size_t *size)
|
||||
static void SeqInFilter_Construct(CSeqInFilter *p)
|
||||
{
|
||||
p->buf = NULL;
|
||||
p->StateCoder.p = NULL;
|
||||
p->p.Read = SeqInFilter_Read;
|
||||
}
|
||||
|
||||
static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc)
|
||||
{
|
||||
if (p->StateCoder.p)
|
||||
{
|
||||
p->StateCoder.Free(p->StateCoder.p, alloc);
|
||||
p->StateCoder.p = NULL;
|
||||
}
|
||||
if (p->buf)
|
||||
{
|
||||
ISzAlloc_Free(alloc, p->buf);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "../Compress/BZip2Decoder.h"
|
||||
#include "../Compress/CopyCoder.h"
|
||||
#include "../Compress/LzfseDecoder.h"
|
||||
#include "../Compress/ZlibDecoder.h"
|
||||
|
||||
#include "Common/OutStreamWithCRC.h"
|
||||
@@ -121,6 +122,7 @@ enum
|
||||
METHOD_ADC = 0x80000004,
|
||||
METHOD_ZLIB = 0x80000005,
|
||||
METHOD_BZIP2 = 0x80000006,
|
||||
METHOD_LZFSE = 0x80000007,
|
||||
METHOD_COMMENT = 0x7FFFFFFE, // is used to comment "+beg" and "+end" in extra field.
|
||||
METHOD_END = 0xFFFFFFFF
|
||||
};
|
||||
@@ -276,6 +278,7 @@ void CMethods::GetString(AString &res) const
|
||||
case METHOD_ADC: s = "ADC"; break;
|
||||
case METHOD_ZLIB: s = "ZLIB"; break;
|
||||
case METHOD_BZIP2: s = "BZip2"; break;
|
||||
case METHOD_LZFSE: s = "LZFSE"; break;
|
||||
default: ConvertUInt32ToString(type, buf); s = buf;
|
||||
}
|
||||
res.Add_OptSpaced(s);
|
||||
@@ -307,6 +310,10 @@ static const CAppleName k_Names[] =
|
||||
{ true, "hfs", "Apple_HFS" },
|
||||
{ true, "hfsx", "Apple_HFSX" },
|
||||
{ true, "ufs", "Apple_UFS" },
|
||||
|
||||
// efi_sys partition is FAT32, but it's not main file. So we use (IsFs = false)
|
||||
{ false, "efi_sys", "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" },
|
||||
|
||||
{ false, "free", "Apple_Free" },
|
||||
{ false, "ddm", "DDM" },
|
||||
{ false, NULL, "Apple_partition_map" },
|
||||
@@ -1247,6 +1254,11 @@ STDMETHODIMP CAdcDecoder::Code(ISequentialInStream *inStream,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
@@ -1292,6 +1304,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
CAdcDecoder *adcCoderSpec = new CAdcDecoder();
|
||||
CMyComPtr<ICompressCoder> adcCoder = adcCoderSpec;
|
||||
|
||||
NCompress::NLzfse::CDecoder *lzfseCoderSpec = new NCompress::NLzfse::CDecoder();
|
||||
CMyComPtr<ICompressCoder> lzfseCoder = lzfseCoderSpec;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
@@ -1419,6 +1434,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
opRes = NExtract::NOperationResult::kDataError;
|
||||
break;
|
||||
}
|
||||
|
||||
case METHOD_LZFSE:
|
||||
{
|
||||
res = lzfseCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, progress);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
opRes = NExtract::NOperationResult::kUnsupportedMethod;
|
||||
@@ -1490,6 +1511,9 @@ class CInStream:
|
||||
CAdcDecoder *adcCoderSpec;
|
||||
CMyComPtr<ICompressCoder> adcCoder;
|
||||
|
||||
NCompress::NLzfse::CDecoder *lzfseCoderSpec;
|
||||
CMyComPtr<ICompressCoder> lzfseCoder;
|
||||
|
||||
CBufPtrSeqOutStream *outStreamSpec;
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
|
||||
@@ -1651,6 +1675,15 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
if (res == S_OK && bzip2CoderSpec->GetInputProcessedSize() != block.PackSize)
|
||||
res = S_FALSE;
|
||||
break;
|
||||
|
||||
case METHOD_LZFSE:
|
||||
if (!lzfseCoder)
|
||||
{
|
||||
lzfseCoderSpec = new NCompress::NLzfse::CDecoder();
|
||||
lzfseCoder = lzfseCoderSpec;
|
||||
}
|
||||
res = lzfseCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
return E_FAIL;
|
||||
@@ -1738,6 +1771,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
case METHOD_ADC:
|
||||
case METHOD_ZLIB:
|
||||
case METHOD_BZIP2:
|
||||
case METHOD_LZFSE:
|
||||
case METHOD_END:
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -180,7 +180,7 @@ UInt32 CInArchive::ReadDigits(int numDigits)
|
||||
Byte b = ReadByte();
|
||||
if (b < '0' || b > '9')
|
||||
{
|
||||
if (b == 0) // it's bug in some CD's
|
||||
if (b == 0 || b == ' ') // it's bug in some CD's
|
||||
b = '0';
|
||||
else
|
||||
throw CHeaderErrorException();
|
||||
|
||||
@@ -109,7 +109,8 @@ void CVersion::ToProp(NCOM::CPropVariant &prop)
|
||||
prop = sz;
|
||||
}
|
||||
|
||||
static const unsigned kHeaderSize = 4 + 20;
|
||||
static const unsigned kCoffHeaderSize = 20;
|
||||
static const unsigned kPeHeaderSize = 4 + kCoffHeaderSize;
|
||||
static const unsigned k_OptHeader32_Size_MIN = 96;
|
||||
static const unsigned k_OptHeader64_Size_MIN = 112;
|
||||
|
||||
@@ -125,15 +126,14 @@ struct CHeader
|
||||
UInt16 OptHeaderSize;
|
||||
UInt16 Flags;
|
||||
|
||||
bool Parse(const Byte *p);
|
||||
void ParseBase(const Byte *p);
|
||||
bool ParseCoff(const Byte *p);
|
||||
bool ParsePe(const Byte *p);
|
||||
bool IsDll() const { return (Flags & PE_IMAGE_FILE_DLL) != 0; }
|
||||
};
|
||||
|
||||
bool CHeader::Parse(const Byte *p)
|
||||
void CHeader::ParseBase(const Byte *p)
|
||||
{
|
||||
if (Get32(p) != k_Signature32)
|
||||
return false;
|
||||
p += 4;
|
||||
G16( 0, Machine);
|
||||
G16( 2, NumSections);
|
||||
G32( 4, Time);
|
||||
@@ -141,6 +141,13 @@ bool CHeader::Parse(const Byte *p)
|
||||
G32(12, NumSymbols);
|
||||
G16(16, OptHeaderSize);
|
||||
G16(18, Flags);
|
||||
}
|
||||
|
||||
bool CHeader::ParsePe(const Byte *p)
|
||||
{
|
||||
if (Get32(p) != k_Signature32)
|
||||
return false;
|
||||
ParseBase(p + 4);
|
||||
return OptHeaderSize >= k_OptHeader32_Size_MIN;
|
||||
}
|
||||
|
||||
@@ -380,6 +387,10 @@ void CSection::Parse(const Byte *p)
|
||||
G32(36, Flags);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// IMAGE_FILE_*
|
||||
|
||||
static const CUInt32PCharPair g_HeaderCharacts[] =
|
||||
{
|
||||
{ 1, "Executable" },
|
||||
@@ -399,39 +410,65 @@ static const CUInt32PCharPair g_HeaderCharacts[] =
|
||||
{ 15, "Big-Endian" }
|
||||
};
|
||||
|
||||
static const CUInt32PCharPair g_DllCharacts[] =
|
||||
// IMAGE_DLLCHARACTERISTICS_*
|
||||
|
||||
static const char * const g_DllCharacts[] =
|
||||
{
|
||||
{ 5, "HighEntropyVA" },
|
||||
{ 6, "Relocated" },
|
||||
{ 7, "Integrity" },
|
||||
{ 8, "NX-Compatible" },
|
||||
{ 9, "NoIsolation" },
|
||||
{ 10, "NoSEH" },
|
||||
{ 11, "NoBind" },
|
||||
{ 12, "AppContainer" },
|
||||
{ 13, "WDM" },
|
||||
{ 14, "GuardCF" },
|
||||
{ 15, "TerminalServerAware" }
|
||||
NULL
|
||||
, NULL
|
||||
, NULL
|
||||
, NULL
|
||||
, NULL
|
||||
, "HighEntropyVA"
|
||||
, "Relocated"
|
||||
, "Integrity"
|
||||
, "NX-Compatible"
|
||||
, "NoIsolation"
|
||||
, "NoSEH"
|
||||
, "NoBind"
|
||||
, "AppContainer"
|
||||
, "WDM"
|
||||
, "GuardCF"
|
||||
, "TerminalServerAware"
|
||||
};
|
||||
|
||||
static const CUInt32PCharPair g_SectFlags[] =
|
||||
|
||||
// IMAGE_SCN_* constants:
|
||||
|
||||
static const char * const g_SectFlags[] =
|
||||
{
|
||||
{ 3, "NoPad" },
|
||||
{ 5, "Code" },
|
||||
{ 6, "InitializedData" },
|
||||
{ 7, "UninitializedData" },
|
||||
{ 9, "Comments" },
|
||||
{ 11, "Remove" },
|
||||
{ 12, "COMDAT" },
|
||||
{ 15, "GP" },
|
||||
{ 24, "ExtendedRelocations" },
|
||||
{ 25, "Discardable" },
|
||||
{ 26, "NotCached" },
|
||||
{ 27, "NotPaged" },
|
||||
{ 28, "Shared" },
|
||||
{ 29, "Execute" },
|
||||
{ 30, "Read" },
|
||||
{ 31, "Write" }
|
||||
NULL
|
||||
, NULL
|
||||
, NULL
|
||||
, "NoPad"
|
||||
, NULL
|
||||
, "Code"
|
||||
, "InitializedData"
|
||||
, "UninitializedData"
|
||||
, "Other"
|
||||
, "Comments"
|
||||
, NULL // OVER
|
||||
, "Remove"
|
||||
, "COMDAT"
|
||||
, NULL
|
||||
, "NO_DEFER_SPEC_EXC"
|
||||
, "GP" // MEM_FARDATA
|
||||
, NULL // SYSHEAP
|
||||
, "PURGEABLE" // 16BIT
|
||||
, "LOCKED"
|
||||
, "PRELOAD"
|
||||
, NULL
|
||||
, NULL
|
||||
, NULL
|
||||
, NULL
|
||||
, "ExtendedRelocations"
|
||||
, "Discardable"
|
||||
, "NotCached"
|
||||
, "NotPaged"
|
||||
, "Shared"
|
||||
, "Execute"
|
||||
, "Read"
|
||||
, "Write"
|
||||
};
|
||||
|
||||
static const CUInt32PCharPair g_MachinePairs[] =
|
||||
@@ -699,7 +736,6 @@ class CHandler:
|
||||
{
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CObjectVector<CSection> _sections;
|
||||
UInt32 _peOffset;
|
||||
CHeader _header;
|
||||
UInt32 _totalSize;
|
||||
Int32 _mainSubfile;
|
||||
@@ -720,9 +756,12 @@ class CHandler:
|
||||
bool _parseResources;
|
||||
bool _checksumError;
|
||||
|
||||
bool IsOpt() const { return _header.OptHeaderSize != 0; }
|
||||
|
||||
COptHeader _optHeader;
|
||||
|
||||
bool _allowTail;
|
||||
bool _coffMode;
|
||||
|
||||
HRESULT LoadDebugSections(IInStream *stream, bool &thereIsSection);
|
||||
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
|
||||
@@ -742,7 +781,10 @@ class CHandler:
|
||||
}
|
||||
|
||||
public:
|
||||
CHandler(): _allowTail(false) {}
|
||||
CHandler(bool coffMode = false):
|
||||
_coffMode(coffMode),
|
||||
_allowTail(coffMode)
|
||||
{}
|
||||
|
||||
MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IArchiveAllowTail)
|
||||
INTERFACE_IInArchive(;)
|
||||
@@ -841,6 +883,34 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPhySize: prop = _totalSize; break;
|
||||
case kpidComment: if (!_versionFullString.IsEmpty()) prop = _versionFullString; break;
|
||||
case kpidShortComment:
|
||||
if (!_versionShortString.IsEmpty())
|
||||
prop = _versionShortString;
|
||||
else
|
||||
{
|
||||
PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop);
|
||||
}
|
||||
break;
|
||||
|
||||
case kpidName: if (!_originalFilename.IsEmpty()) prop = _originalFilename; break;
|
||||
|
||||
// case kpidIsSelfExe: prop = !_header.IsDll(); break;
|
||||
// case kpidError:
|
||||
case kpidWarning: if (_checksumError) prop = "Checksum error"; break;
|
||||
|
||||
case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break;
|
||||
case kpidMTime:
|
||||
case kpidCTime: TimeToProp(_header.Time, prop); break;
|
||||
case kpidCharacts: FLAGS_TO_PROP(g_HeaderCharacts, _header.Flags, prop); break;
|
||||
case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
|
||||
|
||||
default:
|
||||
if (IsOpt())
|
||||
switch (propID)
|
||||
{
|
||||
|
||||
case kpidSectAlign: prop = _optHeader.SectAlign; break;
|
||||
case kpidFileAlign: prop = _optHeader.FileAlign; break;
|
||||
case kpidLinkerVer:
|
||||
@@ -857,37 +927,19 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
case kpidInitDataSize: prop = _optHeader.InitDataSize; break;
|
||||
case kpidUnInitDataSize: prop = _optHeader.UninitDataSize; break;
|
||||
case kpidImageSize: prop = _optHeader.ImageSize; break;
|
||||
case kpidPhySize: prop = _totalSize; break;
|
||||
case kpidHeadersSize: prop = _optHeader.HeadersSize; break;
|
||||
case kpidChecksum: prop = _optHeader.CheckSum; break;
|
||||
case 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";
|
||||
prop = "dll";
|
||||
else if (_optHeader.IsSybSystem_EFI())
|
||||
prop = "efi";
|
||||
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: TYPE_TO_PROP(g_SubSystems, _optHeader.SubSystem, prop); break;
|
||||
|
||||
case kpidMTime:
|
||||
case kpidCTime: TimeToProp(_header.Time, prop); break;
|
||||
case kpidCharacts: FLAGS_TO_PROP(g_HeaderCharacts, _header.Flags, prop); break;
|
||||
case kpidDllCharacts: FLAGS_TO_PROP(g_DllCharacts, _optHeader.DllCharacts, prop); break;
|
||||
case kpidStackReserve: prop = _optHeader.StackReserve; break;
|
||||
case kpidStackCommit: prop = _optHeader.StackCommit; break;
|
||||
@@ -898,8 +950,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
// case kpidAddressOfEntryPoint: prop = _optHeader.AddressOfEntryPoint; break;
|
||||
// case kpidBaseOfCode: prop = _optHeader.BaseOfCode; break;
|
||||
// case kpidBaseOfData32: if (!_optHeader.Is64Bit()) prop = _optHeader.BaseOfData32; break;
|
||||
|
||||
case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
@@ -1056,7 +1107,24 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
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 kpidCharacts:
|
||||
if (item.IsRealSect)
|
||||
{
|
||||
UInt32 flags = item.Flags;
|
||||
const UInt32 MY__IMAGE_SCN_ALIGN_MASK = 0x00F00000;
|
||||
AString s = FlagsToString(g_SectFlags, ARRAY_SIZE(g_SectFlags), item.Flags & ~MY__IMAGE_SCN_ALIGN_MASK);
|
||||
const UInt32 align = ((flags >> 20) & 0xF);
|
||||
if (align != 0)
|
||||
{
|
||||
char sz[32];
|
||||
ConvertUInt32ToString(1 << (align - 1), sz);
|
||||
s.Add_Space();
|
||||
s += "align_";
|
||||
s += sz;
|
||||
}
|
||||
prop = s;
|
||||
}
|
||||
break;
|
||||
case kpidZerosTailIsAllowed: if (!item.IsRealSect) prop = true; break;
|
||||
}
|
||||
}
|
||||
@@ -1073,8 +1141,17 @@ HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection)
|
||||
return S_OK;
|
||||
const unsigned kEntrySize = 28;
|
||||
UInt32 numItems = debugLink.Size / kEntrySize;
|
||||
if (numItems * kEntrySize != debugLink.Size || numItems > 16)
|
||||
if (numItems > 16)
|
||||
return S_FALSE;
|
||||
|
||||
// MAC's EFI file: numItems can be incorrect. Only first CDebugEntry entry is correct.
|
||||
// debugLink.Size = kEntrySize + some_data, pointed by entry[0].
|
||||
if (numItems * kEntrySize != debugLink.Size)
|
||||
{
|
||||
// return S_FALSE;
|
||||
if (numItems > 1)
|
||||
numItems = 1;
|
||||
}
|
||||
|
||||
UInt64 pa = 0;
|
||||
unsigned i;
|
||||
@@ -2114,6 +2191,26 @@ HRESULT CHandler::OpenResources(unsigned sectionIndex, IInStream *stream, IArchi
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
bool CHeader::ParseCoff(const Byte *p)
|
||||
{
|
||||
ParseBase(p);
|
||||
if (PointerToSymbolTable < kCoffHeaderSize)
|
||||
return false;
|
||||
if (NumSymbols >= (1 << 24))
|
||||
return false;
|
||||
if (OptHeaderSize != 0 && OptHeaderSize < k_OptHeader32_Size_MIN)
|
||||
return false;
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(g_MachinePairs); i++)
|
||||
if (Machine == g_MachinePairs[i].Value)
|
||||
return true;
|
||||
if (Machine == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static inline bool CheckPeOffset(UInt32 pe)
|
||||
{
|
||||
// ((pe & 7) == 0) is for most PE files. But there is unusual EFI-PE file that uses unaligned pe value.
|
||||
@@ -2133,10 +2230,10 @@ API_FUNC_static_IsArc IsArc_Pe(const Byte *p, size_t size)
|
||||
UInt32 pe = Get32(p + 0x3C);
|
||||
if (!CheckPeOffset(pe))
|
||||
return k_IsArc_Res_NO;
|
||||
if (pe + kHeaderSize > size)
|
||||
if (pe + kPeHeaderSize > size)
|
||||
return k_IsArc_Res_NEED_MORE;
|
||||
CHeader header;
|
||||
if (!header.Parse(p + pe))
|
||||
if (!header.ParsePe(p + pe))
|
||||
return k_IsArc_Res_NO;
|
||||
return k_IsArc_Res_YES;
|
||||
}
|
||||
@@ -2144,32 +2241,47 @@ API_FUNC_static_IsArc IsArc_Pe(const Byte *p, size_t size)
|
||||
|
||||
HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
{
|
||||
UInt32 coffOffset = 0;
|
||||
if (_coffMode)
|
||||
{
|
||||
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))
|
||||
Byte h[kCoffHeaderSize];
|
||||
RINOK(ReadStream_FALSE(stream, h, kCoffHeaderSize));
|
||||
if (!_header.ParseCoff(h))
|
||||
return S_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
Byte h[kHeaderSize];
|
||||
RINOK(stream->Seek(_peOffset, STREAM_SEEK_SET, NULL));
|
||||
RINOK(ReadStream_FALSE(stream, h, kHeaderSize));
|
||||
if (!_header.Parse(h))
|
||||
return S_FALSE;
|
||||
UInt32 _peOffset;
|
||||
{
|
||||
Byte h[kStartSize];
|
||||
RINOK(ReadStream_FALSE(stream, h, kStartSize));
|
||||
if (h[0] != 'M' || h[1] != 'Z')
|
||||
return S_FALSE;
|
||||
/* most of PE files contain 0x0090 at offset 2.
|
||||
But some rare PE files contain another values. So we don't use that check.
|
||||
if (Get16(h + 2) != 0x90) return false; */
|
||||
_peOffset = Get32(h + 0x3C);
|
||||
if (!CheckPeOffset(_peOffset))
|
||||
return S_FALSE;
|
||||
coffOffset = _peOffset + 4;
|
||||
}
|
||||
{
|
||||
Byte h[kPeHeaderSize];
|
||||
RINOK(stream->Seek(_peOffset, STREAM_SEEK_SET, NULL));
|
||||
RINOK(ReadStream_FALSE(stream, h, kPeHeaderSize));
|
||||
if (!_header.ParsePe(h))
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 bufSize = _header.OptHeaderSize + (UInt32)_header.NumSections * kSectionSize;
|
||||
_totalSize = _peOffset + kHeaderSize + bufSize;
|
||||
const UInt32 optStart = coffOffset + kCoffHeaderSize;
|
||||
const UInt32 bufSize = _header.OptHeaderSize + (UInt32)_header.NumSections * kSectionSize;
|
||||
_totalSize = optStart + bufSize;
|
||||
CByteBuffer buffer(bufSize);
|
||||
|
||||
RINOK(ReadStream_FALSE(stream, buffer, bufSize));
|
||||
|
||||
if (_header.OptHeaderSize != 0)
|
||||
if (!_optHeader.Parse(buffer, _header.OptHeaderSize))
|
||||
return S_FALSE;
|
||||
|
||||
@@ -2207,7 +2319,9 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
for (i = 0; i < _sections.Size(); i++)
|
||||
_sections[i].UpdateTotalSize(_totalSize);
|
||||
|
||||
bool thereISDebug;
|
||||
bool thereISDebug = false;
|
||||
if (IsOpt())
|
||||
{
|
||||
RINOK(LoadDebugSections(stream, thereISDebug));
|
||||
|
||||
const CDirLink &certLink = _optHeader.DirItems[kDirLink_Certificate];
|
||||
@@ -2256,8 +2370,9 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
_totalSize += (UInt32)k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_header.NumSymbols > 0 && _header.PointerToSymbolTable >= 512)
|
||||
if (_header.NumSymbols > 0 && _header.PointerToSymbolTable >= optStart)
|
||||
{
|
||||
if (_header.NumSymbols >= (1 << 24))
|
||||
return S_FALSE;
|
||||
@@ -2306,11 +2421,12 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
}
|
||||
|
||||
|
||||
if (IsOpt())
|
||||
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));
|
||||
RINOK(CalcCheckSum(stream, _totalSize, optStart + k_CheckSum_Field_Offset, checkSum));
|
||||
_checksumError = (checkSum != _optHeader.CheckSum);
|
||||
}
|
||||
|
||||
@@ -2333,6 +2449,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
const CSection § = _sections[i];
|
||||
CMixItem mixItem;
|
||||
mixItem.SectionIndex = i;
|
||||
if (IsOpt())
|
||||
if (_parseResources && sect.Name == ".rsrc" && _items.IsEmpty())
|
||||
{
|
||||
const unsigned numMixItems = _mixItems.Size();
|
||||
@@ -2480,6 +2597,8 @@ STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_totalSize = 0;
|
||||
_checksumError = false;
|
||||
_mainSubfile = -1;
|
||||
|
||||
_stream.Release();
|
||||
_sections.Clear();
|
||||
_mixItems.Clear();
|
||||
@@ -2675,10 +2794,41 @@ REGISTER_ARC_I(
|
||||
0,
|
||||
NArcInfoFlags::kPreArc,
|
||||
IsArc_Pe)
|
||||
|
||||
|
||||
}
|
||||
|
||||
namespace NCoff {
|
||||
|
||||
API_FUNC_static_IsArc IsArc_Coff(const Byte *p, size_t size)
|
||||
{
|
||||
if (size < NPe::kCoffHeaderSize)
|
||||
return k_IsArc_Res_NEED_MORE;
|
||||
NPe::CHeader header;
|
||||
if (!header.ParseCoff(p))
|
||||
return k_IsArc_Res_NO;
|
||||
return k_IsArc_Res_YES;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
static const Byte k_Signature[] =
|
||||
{
|
||||
2, 0x4C, 0x01, // x86
|
||||
2, 0x64, 0x86, // x64
|
||||
2, 0x64, 0xAA // ARM64
|
||||
};
|
||||
REGISTER_ARC_I_CLS(
|
||||
*/
|
||||
|
||||
REGISTER_ARC_I_CLS_NO_SIG(
|
||||
NPe::CHandler(true),
|
||||
"COFF", "obj", 0, 0xC6,
|
||||
// k_Signature,
|
||||
0,
|
||||
// NArcInfoFlags::kMultiSignature |
|
||||
NArcInfoFlags::kStartOpen,
|
||||
IsArc_Coff)
|
||||
}
|
||||
|
||||
|
||||
namespace NTe {
|
||||
|
||||
@@ -136,6 +136,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
thereAreAesUpdates = true;
|
||||
if (!IntToBool(newProps))
|
||||
ui.IsDir = inputItem.IsDir();
|
||||
// ui.IsAltStream = inputItem.IsAltStream();
|
||||
}
|
||||
|
||||
if (IntToBool(newProps))
|
||||
@@ -175,6 +176,33 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
ui.IsDir = (prop.boolVal != VARIANT_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
bool isAltStream = false;
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(callback->GetProperty(i, kpidIsAltStream, &prop));
|
||||
if (prop.vt == VT_BOOL)
|
||||
isAltStream = (prop.boolVal != VARIANT_FALSE);
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (isAltStream)
|
||||
{
|
||||
if (ui.IsDir)
|
||||
return E_INVALIDARG;
|
||||
int delim = name.ReverseFind(L':');
|
||||
if (delim >= 0)
|
||||
{
|
||||
name.Delete(delim, 1);
|
||||
name.Insert(delim, UString(k_SpecName_NTFS_STREAM));
|
||||
ui.IsAltStream = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
CPropVariant prop;
|
||||
RINOK(callback->GetProperty(i, kpidTimeType, &prop));
|
||||
|
||||
@@ -131,6 +131,7 @@ namespace NFileHeader
|
||||
const unsigned kDescriptorUsedMask = 1 << 3;
|
||||
const unsigned kStrongEncrypted = 1 << 6;
|
||||
const unsigned kUtf8 = 1 << 11;
|
||||
const unsigned kAltStream = 1 << 14;
|
||||
|
||||
const unsigned kImplodeDictionarySizeMask = 1 << 1;
|
||||
const unsigned kImplodeLiteralsOnMask = 1 << 2;
|
||||
|
||||
@@ -20,10 +20,13 @@ class CItemEx: public CItem
|
||||
{
|
||||
public:
|
||||
UInt32 LocalFullHeaderSize; // including Name and Extra
|
||||
// int ParentOfAltStream; // -1, if not AltStream
|
||||
|
||||
bool DescriptorWasRead;
|
||||
|
||||
CItemEx(): DescriptorWasRead(false) {}
|
||||
CItemEx():
|
||||
// ParentOfAltStream(-1),
|
||||
DescriptorWasRead(false) {}
|
||||
|
||||
UInt64 GetLocalFullSize() const
|
||||
{ return LocalFullHeaderSize + GetPackSizeWithDescriptor(); }
|
||||
|
||||
@@ -20,6 +20,12 @@ namespace NZip {
|
||||
|
||||
using namespace NFileHeader;
|
||||
|
||||
|
||||
/*
|
||||
const char *k_SpecName_NTFS_STREAM = "@@NTFS@STREAM@";
|
||||
const char *k_SpecName_MAC_RESOURCE_FORK = "@@MAC@RESOURCE-FORK@";
|
||||
*/
|
||||
|
||||
static const CUInt32PCharPair g_ExtraTypes[] =
|
||||
{
|
||||
{ NExtraID::kZip64, "Zip64" },
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
namespace NArchive {
|
||||
namespace NZip {
|
||||
|
||||
/*
|
||||
extern const char *k_SpecName_NTFS_STREAM;
|
||||
extern const char *k_SpecName_MAC_RESOURCE_FORK;
|
||||
*/
|
||||
|
||||
struct CVersion
|
||||
{
|
||||
Byte Version;
|
||||
@@ -233,6 +238,7 @@ public:
|
||||
bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || Method == NFileHeader::NCompressionMethod::kWzAES); }
|
||||
bool IsLzmaEOS() const { return (Flags & NFileHeader::NFlags::kLzmaEOS) != 0; }
|
||||
bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; }
|
||||
// bool IsAltStream() const { return (Flags & NFileHeader::NFlags::kAltStream) != 0; }
|
||||
|
||||
unsigned GetDeflateLevel() const { return (Flags >> 1) & 3; }
|
||||
|
||||
@@ -264,6 +270,7 @@ public:
|
||||
void ClearFlags() { Flags = 0; }
|
||||
void SetEncrypted(bool encrypted) { SetFlag(NFileHeader::NFlags::kEncrypted, encrypted); }
|
||||
void SetUtf8(bool isUtf8) { SetFlag(NFileHeader::NFlags::kUtf8, isUtf8); }
|
||||
// void SetFlag_AltStream(bool isAltStream) { SetFlag(NFileHeader::NFlags::kAltStream, isAltStream); }
|
||||
void SetDescriptorMode(bool useDescriptor) { SetFlag(NFileHeader::NFlags::kDescriptorUsedMask, useDescriptor); }
|
||||
|
||||
UINT GetCodePage() const { return CP_OEMCP; }
|
||||
|
||||
@@ -75,6 +75,7 @@ static void SetFileHeader(
|
||||
item.Name = ui.Name;
|
||||
item.Comment = ui.Comment;
|
||||
item.SetUtf8(ui.IsUtf8);
|
||||
// item.SetFlag_AltStream(ui.IsAltStream);
|
||||
item.ExternalAttrib = ui.Attrib;
|
||||
item.Time = ui.Time;
|
||||
item.Ntfs_MTime = ui.Ntfs_MTime;
|
||||
@@ -280,6 +281,7 @@ public:
|
||||
MY_UNKNOWN_IMP
|
||||
void Create(IProgress *progress, bool inSizeIsMain);
|
||||
void SetProgressOffset(UInt64 progressOffset);
|
||||
void SetProgressOffset_NoLock(UInt64 progressOffset);
|
||||
HRESULT SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize);
|
||||
STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
|
||||
};
|
||||
@@ -292,11 +294,16 @@ void CMtProgressMixer2::Create(IProgress *progress, bool inSizeIsMain)
|
||||
ProgressOffset = InSizes[0] = InSizes[1] = OutSizes[0] = OutSizes[1] = 0;
|
||||
}
|
||||
|
||||
void CMtProgressMixer2::SetProgressOffset_NoLock(UInt64 progressOffset)
|
||||
{
|
||||
InSizes[1] = OutSizes[1] = 0;
|
||||
ProgressOffset = progressOffset;
|
||||
}
|
||||
|
||||
void CMtProgressMixer2::SetProgressOffset(UInt64 progressOffset)
|
||||
{
|
||||
CriticalSection.Enter();
|
||||
InSizes[1] = OutSizes[1] = 0;
|
||||
ProgressOffset = progressOffset;
|
||||
SetProgressOffset_NoLock(progressOffset);
|
||||
CriticalSection.Leave();
|
||||
}
|
||||
|
||||
@@ -384,6 +391,7 @@ static HRESULT UpdateItemOldData(
|
||||
item.Comment = ui.Comment;
|
||||
item.Name = ui.Name;
|
||||
item.SetUtf8(ui.IsUtf8);
|
||||
// item.SetFlag_AltStream(ui.IsAltStream);
|
||||
item.Time = ui.Time;
|
||||
item.Ntfs_MTime = ui.Ntfs_MTime;
|
||||
item.Ntfs_ATime = ui.Ntfs_ATime;
|
||||
@@ -602,8 +610,11 @@ static HRESULT Update2St(
|
||||
lps->InSize = unpackSizeTotal;
|
||||
lps->OutSize = packSizeTotal;
|
||||
RINOK(lps->SetCur());
|
||||
|
||||
archive.WriteCentralDir(items, comment);
|
||||
return S_OK;
|
||||
|
||||
lps->ProgressOffset += kCentralHeaderSize * updateItems.Size() + 1;
|
||||
return lps->SetCur();
|
||||
}
|
||||
|
||||
|
||||
@@ -897,7 +908,7 @@ static HRESULT Update2(
|
||||
{
|
||||
complexity += ui.Size;
|
||||
complexity += kLocalHeaderSize;
|
||||
mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
|
||||
mtProgressMixerSpec->Mixer2->SetProgressOffset_NoLock(complexity);
|
||||
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
|
||||
memRef2.Skip = true;
|
||||
continue;
|
||||
@@ -1107,8 +1118,13 @@ static HRESULT Update2(
|
||||
}
|
||||
|
||||
RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL));
|
||||
|
||||
archive.WriteCentralDir(items, comment);
|
||||
return S_OK;
|
||||
|
||||
complexity += kCentralHeaderSize * updateItems.Size() + 1;
|
||||
mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
|
||||
return mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ struct CUpdateItem
|
||||
bool IsDir;
|
||||
bool NtfsTimeIsDefined;
|
||||
bool IsUtf8;
|
||||
// bool IsAltStream;
|
||||
int IndexInArc;
|
||||
int IndexInClient;
|
||||
UInt32 Attrib;
|
||||
@@ -50,12 +51,19 @@ struct CUpdateItem
|
||||
IsDir = false;
|
||||
NtfsTimeIsDefined = false;
|
||||
IsUtf8 = false;
|
||||
// IsAltStream = false;
|
||||
Size = 0;
|
||||
Name.Empty();
|
||||
Comment.Free();
|
||||
}
|
||||
|
||||
CUpdateItem(): NtfsTimeIsDefined(false), IsUtf8(false), Size(0) {}
|
||||
CUpdateItem():
|
||||
IsDir(false),
|
||||
NtfsTimeIsDefined(false),
|
||||
IsUtf8(false),
|
||||
// IsAltStream(false),
|
||||
Size(0)
|
||||
{}
|
||||
};
|
||||
|
||||
HRESULT Update(
|
||||
|
||||
@@ -198,6 +198,7 @@ COMPRESS_OBJS = \
|
||||
$O\DeflateRegister.obj \
|
||||
$O\DeltaFilter.obj \
|
||||
$O\ImplodeDecoder.obj \
|
||||
$O\LzfseDecoder.obj \
|
||||
$O\LzhDecoder.obj \
|
||||
$O\Lzma2Decoder.obj \
|
||||
$O\Lzma2Encoder.obj \
|
||||
|
||||
@@ -961,6 +961,24 @@ SOURCE=..\..\Compress\HuffmanDecoder.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\LzfseDecoder.cpp
|
||||
|
||||
!IF "$(CFG)" == "7z - Win32 Release"
|
||||
|
||||
# ADD CPP /O2
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
|
||||
!ELSEIF "$(CFG)" == "7z - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\LzfseDecoder.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\LzhDecoder.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
@@ -28,14 +28,23 @@ HRESULT SResToHRESULT(SRes res) throw()
|
||||
switch (res)
|
||||
{
|
||||
case SZ_OK: return S_OK;
|
||||
case SZ_ERROR_DATA: return S_FALSE;
|
||||
case SZ_ERROR_CRC: return S_FALSE;
|
||||
|
||||
case SZ_ERROR_DATA:
|
||||
case SZ_ERROR_CRC:
|
||||
case SZ_ERROR_INPUT_EOF:
|
||||
return S_FALSE;
|
||||
|
||||
case SZ_ERROR_MEM: return E_OUTOFMEMORY;
|
||||
case SZ_ERROR_PARAM: return E_INVALIDARG;
|
||||
case SZ_ERROR_PROGRESS: return E_ABORT;
|
||||
case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
|
||||
// case SZ_ERROR_THREAD: return E_FAIL;
|
||||
// case SZ_ERROR_READ: return E_FAIL;
|
||||
// case SZ_ERROR_OUTPUT_EOF:
|
||||
// case SZ_ERROR_READ:
|
||||
// case SZ_ERROR_WRITE:
|
||||
// case SZ_ERROR_THREAD:
|
||||
// case SZ_ERROR_ARCHIVE:
|
||||
// case SZ_ERROR_NO_ARCHIVE:
|
||||
// return E_FAIL;
|
||||
}
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
@@ -97,6 +97,33 @@ Byte CInBufferBase::ReadByte_FromNewBlock()
|
||||
|
||||
size_t CInBufferBase::ReadBytes(Byte *buf, size_t size)
|
||||
{
|
||||
size_t num = 0;
|
||||
for (;;)
|
||||
{
|
||||
const size_t rem = _bufLim - _buf;
|
||||
if (size <= rem)
|
||||
{
|
||||
if (size != 0)
|
||||
{
|
||||
memcpy(buf, _buf, size);
|
||||
_buf += size;
|
||||
num += size;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
if (rem != 0)
|
||||
{
|
||||
memcpy(buf, _buf, rem);
|
||||
_buf += rem;
|
||||
buf += rem;
|
||||
num += rem;
|
||||
size -= rem;
|
||||
}
|
||||
if (!ReadBlock())
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
if ((size_t)(_bufLim - _buf) >= size)
|
||||
{
|
||||
const Byte *src = _buf;
|
||||
@@ -113,6 +140,7 @@ size_t CInBufferBase::ReadBytes(Byte *buf, size_t size)
|
||||
buf[i] = *_buf++;
|
||||
}
|
||||
return size;
|
||||
*/
|
||||
}
|
||||
|
||||
size_t CInBufferBase::Skip(size_t size)
|
||||
|
||||
@@ -50,6 +50,17 @@ const UInt32 kNumSelectorsMax = (2 + (kBlockSizeMax / kGroupSize));
|
||||
|
||||
const unsigned kRleModeRepSize = 4;
|
||||
|
||||
/*
|
||||
The number of selectors stored in bzip2 block:
|
||||
(numSelectors <= 18001) - must work with any decoder.
|
||||
(numSelectors == 18002) - works with bzip2 1.0.6 decoder and all derived decoders.
|
||||
(numSelectors > 18002)
|
||||
7-Zip decoder doesn't support it.
|
||||
bzip2 1.0.6 decoder can overflow selector[18002] arrays. But there are another
|
||||
arrays after selector arrays. So the compiled code works.
|
||||
lbzip2 2.5 encoder can write up to (18001 + 7) selectors.
|
||||
*/
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -411,9 +411,13 @@ SRes CBase::ReadBlock2()
|
||||
lens[state4] = (Byte)state3;
|
||||
state5 = 0;
|
||||
}
|
||||
|
||||
// lbzip2 2.5 can produce dummy tree, where lens[i] = kMaxHuffmanLen
|
||||
// BuildFull() returns error for such tree
|
||||
/*
|
||||
for (unsigned i = state4; i < kMaxAlphaSize; i++)
|
||||
lens[i] = 0;
|
||||
if (!huffs[state2].Build(lens))
|
||||
*/
|
||||
if (!huffs[state2].BuildFull(lens, state4))
|
||||
return SZ_ERROR_DATA;
|
||||
@@ -474,7 +478,7 @@ SRes CBase::ReadBlock2()
|
||||
for (len = kNumTableBits + 1; val >= huff->_limits[len]; len++);
|
||||
/*
|
||||
if (len > kNumBitsMax)
|
||||
return SZ_ERROR_DATA;
|
||||
return SZ_ERROR_DATA; // that check is required, if NHuffman::Build() was used instead of BuildFull()
|
||||
*/
|
||||
if (_numBits < len)
|
||||
{
|
||||
|
||||
@@ -56,6 +56,39 @@ public:
|
||||
if (pos == _limitPos)
|
||||
FlushWithCheck();
|
||||
}
|
||||
|
||||
void PutBytes(const Byte *data, UInt32 size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
UInt32 pos = _pos;
|
||||
Byte *buf = _buf;
|
||||
buf[pos++] = *data++;
|
||||
size--;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 limitPos = _limitPos;
|
||||
UInt32 rem = limitPos - pos;
|
||||
if (rem == 0)
|
||||
{
|
||||
_pos = pos;
|
||||
FlushWithCheck();
|
||||
pos = _pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
break;
|
||||
|
||||
if (rem > size)
|
||||
rem = size;
|
||||
size -= rem;
|
||||
do
|
||||
buf[pos++] = *data++;
|
||||
while (--rem);
|
||||
}
|
||||
_pos = pos;
|
||||
}
|
||||
|
||||
Byte GetByte(UInt32 distance) const
|
||||
{
|
||||
|
||||
925
CPP/7zip/Compress/LzfseDecoder.cpp
Normal file
925
CPP/7zip/Compress/LzfseDecoder.cpp
Normal file
@@ -0,0 +1,925 @@
|
||||
// LzfseDecoder.cpp
|
||||
|
||||
/*
|
||||
This code implements LZFSE data decompressing.
|
||||
The code from "LZFSE compression library" was used.
|
||||
|
||||
2018 : Igor Pavlov : BSD 3-clause License : the code in this file
|
||||
2015-2017 : Apple Inc : BSD 3-clause License : original "LZFSE compression library" code
|
||||
|
||||
The code in the "LZFSE compression library" is licensed under the "BSD 3-clause License":
|
||||
----
|
||||
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
----
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
// #define SHOW_DEBUG_INFO
|
||||
|
||||
#ifdef SHOW_DEBUG_INFO
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef SHOW_DEBUG_INFO
|
||||
#define PRF(x) x
|
||||
#else
|
||||
#define PRF(x)
|
||||
#endif
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "LzfseDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzfse {
|
||||
|
||||
static const Byte kSignature_LZFSE_V1 = 0x31; // '1'
|
||||
static const Byte kSignature_LZFSE_V2 = 0x32; // '2'
|
||||
|
||||
|
||||
HRESULT CDecoder::GetUInt32(UInt32 &val)
|
||||
{
|
||||
Byte b[4];
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
if (!m_InStream.ReadByte(b[i]))
|
||||
return S_FALSE;
|
||||
val = GetUi32(b);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT CDecoder::DecodeUncompressed(UInt32 unpackSize)
|
||||
{
|
||||
PRF(printf("\nUncompressed %7u\n", unpackSize));
|
||||
|
||||
const unsigned kBufSize = 1 << 8;
|
||||
Byte buf[kBufSize];
|
||||
for (;;)
|
||||
{
|
||||
if (unpackSize == 0)
|
||||
return S_OK;
|
||||
UInt32 cur = unpackSize;
|
||||
if (cur > kBufSize)
|
||||
cur = kBufSize;
|
||||
UInt32 cur2 = (UInt32)m_InStream.ReadBytes(buf, cur);
|
||||
m_OutWindowStream.PutBytes(buf, cur2);
|
||||
if (cur != cur2)
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT CDecoder::DecodeLzvn(UInt32 unpackSize)
|
||||
{
|
||||
UInt32 packSize;
|
||||
RINOK(GetUInt32(packSize));
|
||||
|
||||
PRF(printf("\nLZVN %7u %7u", unpackSize, packSize));
|
||||
|
||||
UInt32 D = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (packSize == 0)
|
||||
return S_FALSE;
|
||||
Byte b;
|
||||
if (!m_InStream.ReadByte(b))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
|
||||
UInt32 M;
|
||||
UInt32 L;
|
||||
|
||||
if (b >= 0xE0)
|
||||
{
|
||||
/*
|
||||
large L - 11100000 LLLLLLLL <LITERALS>
|
||||
small L - 1110LLLL <LITERALS>
|
||||
|
||||
large Rep - 11110000 MMMMMMMM
|
||||
small Rep - 1111MMMM
|
||||
*/
|
||||
|
||||
M = b & 0xF;
|
||||
if (M == 0)
|
||||
{
|
||||
if (packSize == 0)
|
||||
return S_FALSE;
|
||||
Byte b1;
|
||||
if (!m_InStream.ReadByte(b1))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
M = (UInt32)b1 + 16;
|
||||
}
|
||||
L = 0;
|
||||
if ((b & 0x10) == 0)
|
||||
{
|
||||
// Literals only
|
||||
L = M;
|
||||
M = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ERROR codes
|
||||
else if ((b & 0xF0) == 0x70) // 0111xxxx
|
||||
return S_FALSE;
|
||||
else if ((b & 0xF0) == 0xD0) // 1101xxxx
|
||||
return S_FALSE;
|
||||
|
||||
else
|
||||
{
|
||||
if ((b & 0xE0) == 0xA0)
|
||||
{
|
||||
// medium - 101LLMMM DDDDDDMM DDDDDDDD <LITERALS>
|
||||
if (packSize < 2)
|
||||
return S_FALSE;
|
||||
Byte b1;
|
||||
if (!m_InStream.ReadByte(b1))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
|
||||
Byte b2;
|
||||
if (!m_InStream.ReadByte(b2))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
L = (((UInt32)b >> 3) & 3);
|
||||
M = (((UInt32)b & 7) << 2) + (b1 & 3);
|
||||
D = ((UInt32)b1 >> 2) + ((UInt32)b2 << 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
L = (UInt32)b >> 6;
|
||||
M = ((UInt32)b >> 3) & 7;
|
||||
if ((b & 0x7) == 6)
|
||||
{
|
||||
// REP - LLMMM110 <LITERALS>
|
||||
if (L == 0)
|
||||
{
|
||||
// spec
|
||||
if (M == 0)
|
||||
break; // EOS
|
||||
if (M <= 2)
|
||||
continue; // NOP
|
||||
return S_FALSE; // UNDEFINED
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packSize == 0)
|
||||
return S_FALSE;
|
||||
Byte b1;
|
||||
if (!m_InStream.ReadByte(b1))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
|
||||
// large - LLMMM111 DDDDDDDD DDDDDDDD <LITERALS>
|
||||
// small - LLMMMDDD DDDDDDDD <LITERALS>
|
||||
D = ((UInt32)b & 7);
|
||||
if (D == 7)
|
||||
{
|
||||
if (packSize == 0)
|
||||
return S_FALSE;
|
||||
Byte b2;
|
||||
if (!m_InStream.ReadByte(b2))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
D = b2;
|
||||
}
|
||||
D = (D << 8) + b1;
|
||||
}
|
||||
}
|
||||
|
||||
M += 3;
|
||||
}
|
||||
{
|
||||
for (unsigned i = 0; i < L; i++)
|
||||
{
|
||||
if (packSize == 0 || unpackSize == 0)
|
||||
return S_FALSE;
|
||||
Byte b1;
|
||||
if (!m_InStream.ReadByte(b1))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
m_OutWindowStream.PutByte(b1);
|
||||
unpackSize--;
|
||||
}
|
||||
}
|
||||
|
||||
if (M != 0)
|
||||
{
|
||||
if (unpackSize == 0 || D == 0)
|
||||
return S_FALSE;
|
||||
unsigned cur = M;
|
||||
if (cur > unpackSize)
|
||||
cur = (unsigned)unpackSize;
|
||||
if (!m_OutWindowStream.CopyBlock(D - 1, cur))
|
||||
return S_FALSE;
|
||||
unpackSize -= cur;
|
||||
if (cur != M)
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (unpackSize != 0)
|
||||
return S_FALSE;
|
||||
|
||||
// LZVN encoder writes 7 additional zero bytes
|
||||
if (packSize != 7)
|
||||
return S_FALSE;
|
||||
do
|
||||
{
|
||||
Byte b;
|
||||
if (!m_InStream.ReadByte(b))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
if (b != 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
while (packSize != 0);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ---------- LZFSE ----------
|
||||
|
||||
#define MATCHES_PER_BLOCK 10000
|
||||
#define LITERALS_PER_BLOCK (4 * MATCHES_PER_BLOCK)
|
||||
|
||||
#define NUM_L_SYMBOLS 20
|
||||
#define NUM_M_SYMBOLS 20
|
||||
#define NUM_D_SYMBOLS 64
|
||||
#define NUM_LIT_SYMBOLS 256
|
||||
|
||||
#define NUM_SYMBOLS ( \
|
||||
NUM_L_SYMBOLS + \
|
||||
NUM_M_SYMBOLS + \
|
||||
NUM_D_SYMBOLS + \
|
||||
NUM_LIT_SYMBOLS)
|
||||
|
||||
#define NUM_L_STATES (1 << 6)
|
||||
#define NUM_M_STATES (1 << 6)
|
||||
#define NUM_D_STATES (1 << 8)
|
||||
#define NUM_LIT_STATES (1 << 10)
|
||||
|
||||
|
||||
typedef UInt32 CFseState;
|
||||
|
||||
|
||||
static UInt32 SumFreqs(const UInt16 *freqs, unsigned num)
|
||||
{
|
||||
UInt32 sum = 0;
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
sum += (UInt32)freqs[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
static MY_FORCE_INLINE unsigned CountZeroBits(UInt32 val, UInt32 mask)
|
||||
{
|
||||
for (unsigned i = 0;;)
|
||||
{
|
||||
if (val & mask)
|
||||
return i;
|
||||
i++;
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static MY_FORCE_INLINE void InitLitTable(const UInt16 *freqs, UInt32 *table)
|
||||
{
|
||||
for (unsigned i = 0; i < NUM_LIT_SYMBOLS; i++)
|
||||
{
|
||||
unsigned f = freqs[i];
|
||||
if (f == 0)
|
||||
continue;
|
||||
|
||||
// 0 < f <= numStates
|
||||
// 0 <= k <= numStatesLog
|
||||
// numStates <= (f<<k) < numStates * 2
|
||||
// 0 < j0 <= f
|
||||
// (f + j0) = next_power_of_2 for f
|
||||
unsigned k = CountZeroBits(f, NUM_LIT_STATES);
|
||||
unsigned j0 = (((unsigned)NUM_LIT_STATES * 2) >> k) - f;
|
||||
|
||||
/*
|
||||
CEntry
|
||||
{
|
||||
Byte k;
|
||||
Byte symbol;
|
||||
UInt16 delta;
|
||||
};
|
||||
*/
|
||||
|
||||
UInt32 e = ((UInt32)i << 8) + k;
|
||||
k += 16;
|
||||
UInt32 d = e + ((UInt32)f << k) - ((UInt32)NUM_LIT_STATES << 16);
|
||||
UInt32 step = (UInt32)1 << k;
|
||||
|
||||
unsigned j = 0;
|
||||
do
|
||||
{
|
||||
*table++ = d;
|
||||
d += step;
|
||||
}
|
||||
while (++j < j0);
|
||||
|
||||
e--;
|
||||
step >>= 1;
|
||||
|
||||
for (j = j0; j < f; j++)
|
||||
{
|
||||
*table++ = e;
|
||||
e += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte totalBits;
|
||||
Byte extraBits;
|
||||
UInt16 delta;
|
||||
UInt32 vbase;
|
||||
} CExtraEntry;
|
||||
|
||||
|
||||
static void InitExtraDecoderTable(unsigned numStates,
|
||||
unsigned numSymbols,
|
||||
const UInt16 *freqs,
|
||||
const Byte *vbits,
|
||||
CExtraEntry *table)
|
||||
{
|
||||
UInt32 vbase = 0;
|
||||
|
||||
for (unsigned i = 0; i < numSymbols; i++)
|
||||
{
|
||||
unsigned f = freqs[i];
|
||||
unsigned extraBits = vbits[i];
|
||||
|
||||
if (f != 0)
|
||||
{
|
||||
unsigned k = CountZeroBits(f, numStates);
|
||||
unsigned j0 = ((2 * numStates) >> k) - f;
|
||||
|
||||
unsigned j = 0;
|
||||
do
|
||||
{
|
||||
CExtraEntry *e = table++;
|
||||
e->totalBits = (Byte)(k + extraBits);
|
||||
e->extraBits = (Byte)extraBits;
|
||||
e->delta = (UInt16)(((f + j) << k) - numStates);
|
||||
e->vbase = vbase;
|
||||
}
|
||||
while (++j < j0);
|
||||
|
||||
f -= j0;
|
||||
k--;
|
||||
|
||||
for (j = 0; j < f; j++)
|
||||
{
|
||||
CExtraEntry *e = table++;
|
||||
e->totalBits = (Byte)(k + extraBits);
|
||||
e->extraBits = (Byte)extraBits;
|
||||
e->delta = (UInt16)(j << k);
|
||||
e->vbase = vbase;
|
||||
}
|
||||
}
|
||||
|
||||
vbase += ((UInt32)1 << extraBits);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const Byte k_L_extra[NUM_L_SYMBOLS] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 8
|
||||
};
|
||||
|
||||
static const Byte k_M_extra[NUM_M_SYMBOLS] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11
|
||||
};
|
||||
|
||||
static const Byte k_D_extra[NUM_D_SYMBOLS] =
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
|
||||
8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
|
||||
12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ---------- CBitStream ----------
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 accum;
|
||||
unsigned numBits; // [0, 31] - Number of valid bits in (accum), other bits are 0
|
||||
} CBitStream;
|
||||
|
||||
|
||||
static MY_FORCE_INLINE int FseInStream_Init(CBitStream *s,
|
||||
int n, // [-7, 0], (-n == number_of_unused_bits) in last byte
|
||||
const Byte **pbuf)
|
||||
{
|
||||
*pbuf -= 4;
|
||||
s->accum = GetUi32(*pbuf);
|
||||
if (n)
|
||||
{
|
||||
s->numBits = n + 32;
|
||||
if ((s->accum >> s->numBits) != 0)
|
||||
return -1; // ERROR, encoder should have zeroed the upper bits
|
||||
}
|
||||
else
|
||||
{
|
||||
*pbuf += 1;
|
||||
s->accum >>= 8;
|
||||
s->numBits = 24;
|
||||
}
|
||||
return 0; // OK
|
||||
}
|
||||
|
||||
|
||||
// 0 <= numBits < 32
|
||||
#define mask31(x, numBits) ((x) & (((UInt32)1 << (numBits)) - 1))
|
||||
|
||||
#define FseInStream_FLUSH \
|
||||
{ unsigned nbits = (31 - in.numBits) & -8; \
|
||||
if (nbits) { \
|
||||
buf -= (nbits >> 3); \
|
||||
if (buf < buf_check) return S_FALSE; \
|
||||
UInt32 v = GetUi32(buf); \
|
||||
in.accum = (in.accum << nbits) | mask31(v, nbits); \
|
||||
in.numBits += nbits; }}
|
||||
|
||||
|
||||
|
||||
static MY_FORCE_INLINE UInt32 BitStream_Pull(CBitStream *s, unsigned numBits)
|
||||
{
|
||||
s->numBits -= numBits;
|
||||
UInt32 v = s->accum >> s->numBits;
|
||||
s->accum = mask31(s->accum, s->numBits);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
#define DECODE_LIT(dest, pstate) { \
|
||||
UInt32 e = lit_decoder[pstate]; \
|
||||
pstate = (CFseState)((e >> 16) + BitStream_Pull(&in, e & 0xff)); \
|
||||
dest = (Byte)(e >> 8); }
|
||||
|
||||
|
||||
static MY_FORCE_INLINE UInt32 FseDecodeExtra(CFseState *pstate,
|
||||
const CExtraEntry *table,
|
||||
CBitStream *s)
|
||||
{
|
||||
const CExtraEntry *e = &table[*pstate];
|
||||
UInt32 v = BitStream_Pull(s, e->totalBits);
|
||||
unsigned extraBits = e->extraBits;
|
||||
*pstate = (CFseState)(e->delta + (v >> extraBits));
|
||||
return e->vbase + mask31(v, extraBits);
|
||||
}
|
||||
|
||||
|
||||
#define freqs_L (freqs)
|
||||
#define freqs_M (freqs_L + NUM_L_SYMBOLS)
|
||||
#define freqs_D (freqs_M + NUM_M_SYMBOLS)
|
||||
#define freqs_LIT (freqs_D + NUM_D_SYMBOLS)
|
||||
|
||||
#define GET_BITS_64(v, offset, num, dest) dest = (UInt32) ((v >> (offset)) & ((1 << (num)) - 1));
|
||||
#define GET_BITS_32(v, offset, num, dest) dest = (CFseState)((v >> (offset)) & ((1 << (num)) - 1));
|
||||
|
||||
|
||||
HRESULT CDecoder::DecodeLzfse(UInt32 unpackSize, Byte version)
|
||||
{
|
||||
PRF(printf("\nLZFSE-%d %7u", version - '0', unpackSize));
|
||||
|
||||
UInt32 numLiterals;
|
||||
UInt32 litPayloadSize;
|
||||
Int32 literal_bits;
|
||||
|
||||
UInt32 lit_state_0;
|
||||
UInt32 lit_state_1;
|
||||
UInt32 lit_state_2;
|
||||
UInt32 lit_state_3;
|
||||
|
||||
UInt32 numMatches;
|
||||
UInt32 lmdPayloadSize;
|
||||
Int32 lmd_bits;
|
||||
|
||||
CFseState l_state;
|
||||
CFseState m_state;
|
||||
CFseState d_state;
|
||||
|
||||
UInt16 freqs[NUM_SYMBOLS];
|
||||
|
||||
if (version == kSignature_LZFSE_V1)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
// we need examples to test LZFSE-V1 code
|
||||
/*
|
||||
const unsigned k_v1_SubHeaderSize = 7 * 4 + 7 * 2;
|
||||
const unsigned k_v1_HeaderSize = k_v1_SubHeaderSize + NUM_SYMBOLS * 2;
|
||||
_buffer.AllocAtLeast(k_v1_HeaderSize);
|
||||
if (m_InStream.ReadBytes(_buffer, k_v1_HeaderSize) != k_v1_HeaderSize)
|
||||
return S_FALSE;
|
||||
|
||||
const Byte *buf = _buffer;
|
||||
#define GET_32(offs, dest) dest = GetUi32(buf + offs)
|
||||
#define GET_16(offs, dest) dest = GetUi16(buf + offs)
|
||||
|
||||
UInt32 payload_bytes;
|
||||
GET_32(0, payload_bytes);
|
||||
GET_32(4, numLiterals);
|
||||
GET_32(8, numMatches);
|
||||
GET_32(12, litPayloadSize);
|
||||
GET_32(16, lmdPayloadSize);
|
||||
if (litPayloadSize > (1 << 20) || lmdPayloadSize > (1 << 20))
|
||||
return S_FALSE;
|
||||
GET_32(20, literal_bits);
|
||||
if (literal_bits < -7 || literal_bits > 0)
|
||||
return S_FALSE;
|
||||
|
||||
GET_16(24, lit_state_0);
|
||||
GET_16(26, lit_state_1);
|
||||
GET_16(28, lit_state_2);
|
||||
GET_16(30, lit_state_3);
|
||||
|
||||
GET_32(32, lmd_bits);
|
||||
if (lmd_bits < -7 || lmd_bits > 0)
|
||||
return S_FALSE;
|
||||
|
||||
GET_16(36, l_state);
|
||||
GET_16(38, m_state);
|
||||
GET_16(40, d_state);
|
||||
|
||||
for (unsigned i = 0; i < NUM_SYMBOLS; i++)
|
||||
freqs[i] = GetUi16(buf + k_v1_SubHeaderSize + i * 2);
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 headerSize;
|
||||
{
|
||||
const unsigned kPreHeaderSize = 4 * 2; // signature and upackSize
|
||||
const unsigned kHeaderSize = 8 * 3;
|
||||
Byte temp[kHeaderSize];
|
||||
if (m_InStream.ReadBytes(temp, kHeaderSize) != kHeaderSize)
|
||||
return S_FALSE;
|
||||
|
||||
UInt64 v;
|
||||
|
||||
v = GetUi64(temp);
|
||||
GET_BITS_64(v, 0, 20, numLiterals);
|
||||
GET_BITS_64(v, 20, 20, litPayloadSize);
|
||||
GET_BITS_64(v, 40, 20, numMatches);
|
||||
GET_BITS_64(v, 60, 3 + 1, literal_bits); // (NumberOfUsedBits - 1)
|
||||
literal_bits -= 7; // (-NumberOfUnusedBits)
|
||||
if (literal_bits > 0)
|
||||
return S_FALSE;
|
||||
// GET_BITS_64(v, 63, 1, unused);
|
||||
|
||||
v = GetUi64(temp + 8);
|
||||
GET_BITS_64(v, 0, 10, lit_state_0);
|
||||
GET_BITS_64(v, 10, 10, lit_state_1);
|
||||
GET_BITS_64(v, 20, 10, lit_state_2);
|
||||
GET_BITS_64(v, 30, 10, lit_state_3);
|
||||
GET_BITS_64(v, 40, 20, lmdPayloadSize);
|
||||
GET_BITS_64(v, 60, 3 + 1, lmd_bits);
|
||||
lmd_bits -= 7;
|
||||
if (lmd_bits > 0)
|
||||
return S_FALSE;
|
||||
// GET_BITS_64(v, 63, 1, unused)
|
||||
|
||||
UInt32 v32 = GetUi32(temp + 20);
|
||||
// (total header size in bytes; this does not
|
||||
// correspond to a field in the uncompressed header version,
|
||||
// but is required; we wouldn't know the size of the
|
||||
// compresssed header otherwise.
|
||||
GET_BITS_32(v32, 0, 10, l_state);
|
||||
GET_BITS_32(v32, 10, 10, m_state);
|
||||
GET_BITS_32(v32, 20, 10 + 2, d_state);
|
||||
// GET_BITS_64(v, 62, 2, unused);
|
||||
|
||||
headerSize = GetUi32(temp + 16);
|
||||
if (headerSize <= kPreHeaderSize + kHeaderSize)
|
||||
return S_FALSE;
|
||||
headerSize -= kPreHeaderSize + kHeaderSize;
|
||||
}
|
||||
|
||||
// no freqs case is not allowed ?
|
||||
// memset(freqs, 0, sizeof(freqs));
|
||||
// if (headerSize != 0)
|
||||
{
|
||||
static const Byte numBitsTable[32] =
|
||||
{
|
||||
2, 3, 2, 5, 2, 3, 2, 8, 2, 3, 2, 5, 2, 3, 2, 14,
|
||||
2, 3, 2, 5, 2, 3, 2, 8, 2, 3, 2, 5, 2, 3, 2, 14
|
||||
};
|
||||
|
||||
static const Byte valueTable[32] =
|
||||
{
|
||||
0, 2, 1, 4, 0, 3, 1, 8, 0, 2, 1, 5, 0, 3, 1, 24,
|
||||
0, 2, 1, 6, 0, 3, 1, 8, 0, 2, 1, 7, 0, 3, 1, 24
|
||||
};
|
||||
|
||||
UInt32 accum = 0;
|
||||
unsigned numBits = 0;
|
||||
|
||||
for (unsigned i = 0; i < NUM_SYMBOLS; i++)
|
||||
{
|
||||
while (numBits <= 14 && headerSize != 0)
|
||||
{
|
||||
Byte b;
|
||||
if (!m_InStream.ReadByte(b))
|
||||
return S_FALSE;
|
||||
accum |= (UInt32)b << numBits;
|
||||
numBits += 8;
|
||||
headerSize--;
|
||||
}
|
||||
|
||||
unsigned b = (unsigned)accum & 31;
|
||||
unsigned n = numBitsTable[b];
|
||||
if (numBits < n)
|
||||
return S_FALSE;
|
||||
numBits -= n;
|
||||
UInt32 f = valueTable[b];
|
||||
if (n >= 8)
|
||||
f += ((accum >> 4) & (0x3ff >> (14 - n)));
|
||||
accum >>= n;
|
||||
freqs[i] = (UInt16)f;
|
||||
}
|
||||
|
||||
if (numBits >= 8 || headerSize != 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
PRF(printf(" Literals=%6u Matches=%6u", numLiterals, numMatches));
|
||||
|
||||
if (numLiterals > LITERALS_PER_BLOCK
|
||||
|| (numLiterals & 3) != 0
|
||||
|| numMatches > MATCHES_PER_BLOCK
|
||||
|| lit_state_0 >= NUM_LIT_STATES
|
||||
|| lit_state_1 >= NUM_LIT_STATES
|
||||
|| lit_state_2 >= NUM_LIT_STATES
|
||||
|| lit_state_3 >= NUM_LIT_STATES
|
||||
|| l_state >= NUM_L_STATES
|
||||
|| m_state >= NUM_M_STATES
|
||||
|| d_state >= NUM_D_STATES)
|
||||
return S_FALSE;
|
||||
|
||||
// only full table is allowed ?
|
||||
if ( SumFreqs(freqs_L, NUM_L_SYMBOLS) != NUM_L_STATES
|
||||
|| SumFreqs(freqs_M, NUM_M_SYMBOLS) != NUM_M_STATES
|
||||
|| SumFreqs(freqs_D, NUM_D_SYMBOLS) != NUM_D_STATES
|
||||
|| SumFreqs(freqs_LIT, NUM_LIT_SYMBOLS) != NUM_LIT_STATES)
|
||||
return S_FALSE;
|
||||
|
||||
|
||||
const unsigned kPad = 16;
|
||||
|
||||
// ---------- Decode literals ----------
|
||||
|
||||
{
|
||||
_literals.AllocAtLeast(LITERALS_PER_BLOCK + 16);
|
||||
_buffer.AllocAtLeast(kPad + litPayloadSize);
|
||||
memset(_buffer, 0, kPad);
|
||||
|
||||
if (m_InStream.ReadBytes(_buffer + kPad, litPayloadSize) != litPayloadSize)
|
||||
return S_FALSE;
|
||||
|
||||
UInt32 lit_decoder[NUM_LIT_STATES];
|
||||
InitLitTable(freqs_LIT, lit_decoder);
|
||||
|
||||
const Byte *buf_start = _buffer + kPad;
|
||||
const Byte *buf_check = buf_start - 4;
|
||||
const Byte *buf = buf_start + litPayloadSize;
|
||||
CBitStream in;
|
||||
if (FseInStream_Init(&in, literal_bits, &buf) != 0)
|
||||
return S_FALSE;
|
||||
|
||||
Byte *lit = _literals;
|
||||
const Byte *lit_limit = lit + numLiterals;
|
||||
for (; lit < lit_limit; lit += 4)
|
||||
{
|
||||
FseInStream_FLUSH
|
||||
DECODE_LIT (lit[0], lit_state_0);
|
||||
DECODE_LIT (lit[1], lit_state_1);
|
||||
FseInStream_FLUSH
|
||||
DECODE_LIT (lit[2], lit_state_2);
|
||||
DECODE_LIT (lit[3], lit_state_3);
|
||||
}
|
||||
|
||||
if ((buf_start - buf) * 8 != (int)in.numBits)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
|
||||
// ---------- Decode LMD ----------
|
||||
|
||||
_buffer.AllocAtLeast(kPad + lmdPayloadSize);
|
||||
memset(_buffer, 0, kPad);
|
||||
if (m_InStream.ReadBytes(_buffer + kPad, lmdPayloadSize) != lmdPayloadSize)
|
||||
return S_FALSE;
|
||||
|
||||
CExtraEntry l_decoder[NUM_L_STATES];
|
||||
CExtraEntry m_decoder[NUM_M_STATES];
|
||||
CExtraEntry d_decoder[NUM_D_STATES];
|
||||
|
||||
InitExtraDecoderTable(NUM_L_STATES, NUM_L_SYMBOLS, freqs_L, k_L_extra, l_decoder);
|
||||
InitExtraDecoderTable(NUM_M_STATES, NUM_M_SYMBOLS, freqs_M, k_M_extra, m_decoder);
|
||||
InitExtraDecoderTable(NUM_D_STATES, NUM_D_SYMBOLS, freqs_D, k_D_extra, d_decoder);
|
||||
|
||||
const Byte *buf_start = _buffer + kPad;
|
||||
const Byte *buf_check = buf_start - 4;
|
||||
const Byte *buf = buf_start + lmdPayloadSize;
|
||||
CBitStream in;
|
||||
if (FseInStream_Init(&in, lmd_bits, &buf))
|
||||
return S_FALSE;
|
||||
|
||||
const Byte *lit = _literals;
|
||||
const Byte *lit_limit = lit + numLiterals;
|
||||
|
||||
UInt32 D = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (numMatches == 0)
|
||||
break;
|
||||
numMatches--;
|
||||
|
||||
FseInStream_FLUSH
|
||||
|
||||
unsigned L = (unsigned)FseDecodeExtra(&l_state, l_decoder, &in);
|
||||
|
||||
FseInStream_FLUSH
|
||||
|
||||
unsigned M = (unsigned)FseDecodeExtra(&m_state, m_decoder, &in);
|
||||
|
||||
FseInStream_FLUSH
|
||||
|
||||
{
|
||||
UInt32 new_D = FseDecodeExtra(&d_state, d_decoder, &in);
|
||||
if (new_D)
|
||||
D = new_D;
|
||||
}
|
||||
|
||||
if (L != 0)
|
||||
{
|
||||
if (L > (size_t)(lit_limit - lit))
|
||||
return S_FALSE;
|
||||
unsigned cur = L;
|
||||
if (cur > unpackSize)
|
||||
cur = (unsigned)unpackSize;
|
||||
m_OutWindowStream.PutBytes(lit, cur);
|
||||
unpackSize -= cur;
|
||||
lit += cur;
|
||||
if (cur != L)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (M != 0)
|
||||
{
|
||||
if (unpackSize == 0 || D == 0)
|
||||
return S_FALSE;
|
||||
unsigned cur = M;
|
||||
if (cur > unpackSize)
|
||||
cur = (unsigned)unpackSize;
|
||||
if (!m_OutWindowStream.CopyBlock(D - 1, cur))
|
||||
return S_FALSE;
|
||||
unpackSize -= cur;
|
||||
if (cur != M)
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (unpackSize != 0)
|
||||
return S_FALSE;
|
||||
|
||||
// LZFSE encoder writes 8 additional zero bytes before LMD payload
|
||||
// We test it:
|
||||
if ((buf - buf_start) * 8 + in.numBits != 64)
|
||||
return S_FALSE;
|
||||
if (GetUi64(buf_start) != 0)
|
||||
return S_FALSE;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
PRF(printf("\n\nLzfseDecoder %7u %7u\n", (unsigned)*outSize, (unsigned)*inSize));
|
||||
|
||||
const UInt32 kLzfseDictSize = 1 << 18;
|
||||
if (!m_OutWindowStream.Create(kLzfseDictSize))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!m_InStream.Create(1 << 18))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
m_OutWindowStream.SetStream(outStream);
|
||||
m_OutWindowStream.Init(false);
|
||||
m_InStream.SetStream(inStream);
|
||||
m_InStream.Init();
|
||||
|
||||
CCoderReleaser coderReleaser(this);
|
||||
|
||||
UInt64 prevOut = 0;
|
||||
UInt64 prevIn = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const UInt64 pos = m_OutWindowStream.GetProcessedSize();
|
||||
const UInt64 packPos = m_InStream.GetProcessedSize();
|
||||
|
||||
if (progress && ((pos - prevOut) >= (1 << 22) || (packPos - prevIn) >= (1 << 22)))
|
||||
{
|
||||
RINOK(progress->SetRatioInfo(&packPos, &pos));
|
||||
prevIn = packPos;
|
||||
prevOut = pos;
|
||||
}
|
||||
|
||||
const UInt64 rem = *outSize - pos;
|
||||
UInt32 v;
|
||||
RINOK(GetUInt32(v))
|
||||
if ((v & 0xFFFFFF) != 0x787662) // bvx
|
||||
return S_FALSE;
|
||||
v >>= 24;
|
||||
|
||||
if (v == 0x24) // '$', end of stream
|
||||
break;
|
||||
|
||||
UInt32 unpackSize;
|
||||
RINOK(GetUInt32(unpackSize));
|
||||
|
||||
UInt32 cur = unpackSize;
|
||||
if (cur > rem)
|
||||
cur = (UInt32)rem;
|
||||
|
||||
unpackSize -= cur;
|
||||
|
||||
HRESULT res;
|
||||
if (v == kSignature_LZFSE_V1 || v == kSignature_LZFSE_V2)
|
||||
res = DecodeLzfse(cur, (Byte)v);
|
||||
else if (v == 0x6E) // 'n'
|
||||
res = DecodeLzvn(cur);
|
||||
else if (v == 0x2D) // '-'
|
||||
res = DecodeUncompressed(cur);
|
||||
else
|
||||
return E_NOTIMPL;
|
||||
|
||||
if (res != S_OK)
|
||||
return res;
|
||||
|
||||
if (unpackSize != 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
coderReleaser.NeedFlush = false;
|
||||
HRESULT res = m_OutWindowStream.Flush();
|
||||
if (res == S_OK)
|
||||
if (*inSize != m_InStream.GetProcessedSize()
|
||||
|| *outSize != m_OutWindowStream.GetProcessedSize())
|
||||
res = S_FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
|
||||
catch(const CInBufferException &e) { return e.ErrorCode; }
|
||||
catch(const CLzOutWindowException &e) { return e.ErrorCode; }
|
||||
catch(...) { return E_OUTOFMEMORY; }
|
||||
// catch(...) { return S_FALSE; }
|
||||
}
|
||||
|
||||
}}
|
||||
58
CPP/7zip/Compress/LzfseDecoder.h
Normal file
58
CPP/7zip/Compress/LzfseDecoder.h
Normal file
@@ -0,0 +1,58 @@
|
||||
// LzfseDecoder.h
|
||||
|
||||
#ifndef __LZFSE_DECODER_H
|
||||
#define __LZFSE_DECODER_H
|
||||
|
||||
#include "../../Common/MyBuffer.h"
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/InBuffer.h"
|
||||
|
||||
#include "LzOutWindow.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzfse {
|
||||
|
||||
class CDecoder:
|
||||
public ICompressCoder,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLzOutWindow m_OutWindowStream;
|
||||
CInBuffer m_InStream;
|
||||
CByteBuffer _literals;
|
||||
CByteBuffer _buffer;
|
||||
|
||||
class CCoderReleaser
|
||||
{
|
||||
CDecoder *m_Coder;
|
||||
public:
|
||||
bool NeedFlush;
|
||||
CCoderReleaser(CDecoder *coder): m_Coder(coder), NeedFlush(true) {}
|
||||
~CCoderReleaser()
|
||||
{
|
||||
if (NeedFlush)
|
||||
m_Coder->m_OutWindowStream.Flush();
|
||||
}
|
||||
};
|
||||
friend class CCoderReleaser;
|
||||
|
||||
HRESULT GetUInt32(UInt32 &val);
|
||||
|
||||
HRESULT DecodeUncompressed(UInt32 unpackSize);
|
||||
HRESULT DecodeLzvn(UInt32 unpackSize);
|
||||
HRESULT DecodeLzfse(UInt32 unpackSize, Byte version);
|
||||
|
||||
STDMETHOD(CodeReal)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize,
|
||||
const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
};
|
||||
*/
|
||||
|
||||
CDecoder::CDecoder(): m_IsSolid(false) { }
|
||||
CDecoder::CDecoder(): m_IsSolid(false), _errorMode(false) { }
|
||||
|
||||
void CDecoder::InitStructures()
|
||||
{
|
||||
@@ -406,9 +406,14 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
|
||||
InitData();
|
||||
if (!m_IsSolid)
|
||||
{
|
||||
_errorMode = false;
|
||||
InitStructures();
|
||||
InitHuff();
|
||||
}
|
||||
|
||||
if (_errorMode)
|
||||
return S_FALSE;
|
||||
|
||||
if (m_UnpackSize > 0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
@@ -477,9 +482,9 @@ STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
|
||||
catch(const CInBufferException &e) { return e.ErrorCode; }
|
||||
catch(const CLzOutWindowException &e) { return e.ErrorCode; }
|
||||
catch(...) { return S_FALSE; }
|
||||
catch(const CInBufferException &e) { _errorMode = true; return e.ErrorCode; }
|
||||
catch(const CLzOutWindowException &e) { _errorMode = true; return e.ErrorCode; }
|
||||
catch(...) { _errorMode = true; return S_FALSE; }
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
|
||||
|
||||
@@ -39,6 +39,7 @@ public:
|
||||
|
||||
Int64 m_UnpackSize;
|
||||
bool m_IsSolid;
|
||||
bool _errorMode;
|
||||
|
||||
UInt32 ReadBits(int numBits);
|
||||
HRESULT CopyBlock(UInt32 distance, UInt32 len);
|
||||
|
||||
@@ -130,7 +130,7 @@ bool CDecoder::ReadTables(void)
|
||||
|
||||
i = 0;
|
||||
|
||||
while (i < numLevels)
|
||||
do
|
||||
{
|
||||
UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream);
|
||||
if (sym < kTableDirectLevels)
|
||||
@@ -144,10 +144,7 @@ bool CDecoder::ReadTables(void)
|
||||
{
|
||||
unsigned num = ReadBits(2) + 3;
|
||||
if (i == 0)
|
||||
{
|
||||
// return false;
|
||||
continue; // original unRAR
|
||||
}
|
||||
return false;
|
||||
num += i;
|
||||
if (num > numLevels)
|
||||
{
|
||||
@@ -180,6 +177,10 @@ bool CDecoder::ReadTables(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
while (i < numLevels);
|
||||
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return false;
|
||||
|
||||
if (m_AudioMode)
|
||||
for (i = 0; i < m_NumChannels; i++)
|
||||
@@ -244,6 +245,8 @@ bool CDecoder::DecodeMm(UInt32 pos)
|
||||
while (pos-- != 0)
|
||||
{
|
||||
UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return false;
|
||||
if (symbol >= 256)
|
||||
return symbol == 256;
|
||||
/*
|
||||
@@ -264,6 +267,8 @@ bool CDecoder::DecodeLz(Int32 pos)
|
||||
while (pos > 0)
|
||||
{
|
||||
UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return false;
|
||||
UInt32 length, distance;
|
||||
if (sym < 256)
|
||||
{
|
||||
@@ -389,15 +394,19 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
|
||||
if (!DecodeLz((Int32)blockSize))
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return S_FALSE;
|
||||
|
||||
UInt64 globalPos = m_OutWindowStream.GetProcessedSize();
|
||||
pos = globalPos - blockStartPos;
|
||||
if (pos < blockSize)
|
||||
if (!ReadTables())
|
||||
return S_FALSE;
|
||||
pos = globalPos - startPos;
|
||||
if (progress != 0)
|
||||
if (progress)
|
||||
{
|
||||
UInt64 packSize = m_InBitStream.GetProcessedSize();
|
||||
const UInt64 packSize = m_InBitStream.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&packSize, &pos));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,8 @@ CDecoder::CDecoder():
|
||||
_writtenFileSize(0),
|
||||
_vmData(0),
|
||||
_vmCode(0),
|
||||
m_IsSolid(false)
|
||||
m_IsSolid(false),
|
||||
_errorMode(false)
|
||||
{
|
||||
Ppmd7_Construct(&_ppmd);
|
||||
}
|
||||
@@ -135,7 +136,7 @@ HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr)
|
||||
return WriteData(_window, endPtr);
|
||||
}
|
||||
|
||||
void CDecoder::ExecuteFilter(int tempFilterIndex, NVm::CBlockRef &outBlockRef)
|
||||
void CDecoder::ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef)
|
||||
{
|
||||
CTempFilter *tempFilter = _tempFilters[tempFilterIndex];
|
||||
tempFilter->InitR[6] = (UInt32)_writtenFileSize;
|
||||
@@ -405,7 +406,7 @@ bool CDecoder::ReadVmCodePPM()
|
||||
|
||||
#define RIF(x) { if (!(x)) return S_FALSE; }
|
||||
|
||||
UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.BitDecoder.ReadBits(numBits); }
|
||||
UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.BitDecoder.ReadBits(numBits); }
|
||||
|
||||
// ---------- PPM ----------
|
||||
|
||||
@@ -414,7 +415,7 @@ HRESULT CDecoder::InitPPM()
|
||||
unsigned maxOrder = (unsigned)ReadBits(7);
|
||||
|
||||
bool reset = ((maxOrder & 0x20) != 0);
|
||||
int maxMB = 0;
|
||||
UInt32 maxMB = 0;
|
||||
if (reset)
|
||||
maxMB = (Byte)ReadBits(8);
|
||||
else
|
||||
@@ -556,12 +557,13 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing)
|
||||
PrevAlignCount = 0;
|
||||
|
||||
Byte levelLevels[kLevelTableSize];
|
||||
Byte newLevels[kTablesSizesSum];
|
||||
Byte lens[kTablesSizesSum];
|
||||
|
||||
if (ReadBits(1) == 0)
|
||||
memset(m_LastLevels, 0, kTablesSizesSum);
|
||||
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < kLevelTableSize; i++)
|
||||
{
|
||||
UInt32 length = ReadBits(4);
|
||||
@@ -579,39 +581,44 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing)
|
||||
}
|
||||
levelLevels[i] = (Byte)length;
|
||||
}
|
||||
|
||||
RIF(m_LevelDecoder.Build(levelLevels));
|
||||
|
||||
i = 0;
|
||||
while (i < kTablesSizesSum)
|
||||
|
||||
do
|
||||
{
|
||||
UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream.BitDecoder);
|
||||
if (sym < 16)
|
||||
{
|
||||
newLevels[i] = Byte((sym + m_LastLevels[i]) & 15);
|
||||
lens[i] = Byte((sym + m_LastLevels[i]) & 15);
|
||||
i++;
|
||||
}
|
||||
else if (sym > kLevelTableSize)
|
||||
return S_FALSE;
|
||||
else
|
||||
{
|
||||
int num;
|
||||
if (((sym - 16) & 1) == 0)
|
||||
num = ReadBits(3) + 3;
|
||||
else
|
||||
num = ReadBits(7) + 11;
|
||||
if (sym < 18)
|
||||
unsigned num = ((sym - 16) & 1) * 4;
|
||||
num += num + 3 + (unsigned)ReadBits(num + 3);
|
||||
num += i;
|
||||
if (num > kTablesSizesSum)
|
||||
num = kTablesSizesSum;
|
||||
Byte v = 0;
|
||||
if (sym < 16 + 2)
|
||||
{
|
||||
if (i == 0)
|
||||
return S_FALSE;
|
||||
for (; num > 0 && i < kTablesSizesSum; num--, i++)
|
||||
newLevels[i] = newLevels[(size_t)i - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; num > 0 && i < kTablesSizesSum; num--)
|
||||
newLevels[i++] = 0;
|
||||
v = lens[(size_t)i - 1];
|
||||
}
|
||||
do
|
||||
lens[i++] = v;
|
||||
while (i < num);
|
||||
}
|
||||
}
|
||||
while (i < kTablesSizesSum);
|
||||
|
||||
if (InputEofError())
|
||||
return S_FALSE;
|
||||
|
||||
TablesRead = true;
|
||||
|
||||
@@ -624,12 +631,12 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing)
|
||||
}
|
||||
*/
|
||||
|
||||
RIF(m_MainDecoder.Build(&newLevels[0]));
|
||||
RIF(m_DistDecoder.Build(&newLevels[kMainTableSize]));
|
||||
RIF(m_AlignDecoder.Build(&newLevels[kMainTableSize + kDistTableSize]));
|
||||
RIF(m_LenDecoder.Build(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize]));
|
||||
RIF(m_MainDecoder.Build(&lens[0]));
|
||||
RIF(m_DistDecoder.Build(&lens[kMainTableSize]));
|
||||
RIF(m_AlignDecoder.Build(&lens[kMainTableSize + kDistTableSize]));
|
||||
RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize + kAlignTableSize]));
|
||||
|
||||
memcpy(m_LastLevels, newLevels, kTablesSizesSum);
|
||||
memcpy(m_LastLevels, lens, kTablesSizesSum);
|
||||
|
||||
TablesOK = true;
|
||||
|
||||
@@ -769,7 +776,7 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
|
||||
if (sym2 >= kDistTableSize)
|
||||
return S_FALSE;
|
||||
rep0 = kDistStart[sym2];
|
||||
int numBits = kDistDirectBits[sym2];
|
||||
unsigned numBits = kDistDirectBits[sym2];
|
||||
if (sym2 >= (kNumAlignBits * 2) + 2)
|
||||
{
|
||||
if (numBits > kNumAlignBits)
|
||||
@@ -835,8 +842,12 @@ HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
|
||||
PpmEscChar = 2;
|
||||
PpmError = true;
|
||||
InitFilters();
|
||||
_errorMode = false;
|
||||
}
|
||||
|
||||
if (_errorMode)
|
||||
return S_FALSE;
|
||||
|
||||
if (!m_IsSolid || !TablesRead)
|
||||
{
|
||||
bool keepDecompressing;
|
||||
@@ -915,8 +926,8 @@ STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream
|
||||
_unpackSize = outSize ? *outSize : (UInt64)(Int64)-1;
|
||||
return CodeReal(progress);
|
||||
}
|
||||
catch(const CInBufferException &e) { return e.ErrorCode; }
|
||||
catch(...) { return S_FALSE; }
|
||||
catch(const CInBufferException &e) { _errorMode = true; return e.ErrorCode; }
|
||||
catch(...) { _errorMode = true; return S_FALSE; }
|
||||
// CNewException is possible here. But probably CNewException is caused
|
||||
// by error in data stream.
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ const UInt32 kLenTableSize = 28;
|
||||
const UInt32 kMainTableSize = 256 + 1 + 1 + 1 + kNumReps + kNumLen2Symbols + kLenTableSize;
|
||||
const UInt32 kDistTableSize = 60;
|
||||
|
||||
const int kNumAlignBits = 4;
|
||||
const unsigned kNumAlignBits = 4;
|
||||
const UInt32 kAlignTableSize = (1 << kNumAlignBits) + 1;
|
||||
|
||||
const UInt32 kLevelTableSize = 20;
|
||||
@@ -158,7 +158,7 @@ struct CTempFilter: public NVm::CProgramInitState
|
||||
}
|
||||
};
|
||||
|
||||
const int kNumHuffmanBits = 15;
|
||||
const unsigned kNumHuffmanBits = 15;
|
||||
|
||||
class CDecoder:
|
||||
public ICompressCoder,
|
||||
@@ -192,6 +192,7 @@ class CDecoder:
|
||||
UInt32 _lastFilter;
|
||||
|
||||
bool m_IsSolid;
|
||||
bool _errorMode;
|
||||
|
||||
bool _lzMode;
|
||||
bool _unsupportedFilter;
|
||||
@@ -209,7 +210,7 @@ class CDecoder:
|
||||
HRESULT WriteDataToStream(const Byte *data, UInt32 size);
|
||||
HRESULT WriteData(const Byte *data, UInt32 size);
|
||||
HRESULT WriteArea(UInt32 startPtr, UInt32 endPtr);
|
||||
void ExecuteFilter(int tempFilterIndex, NVm::CBlockRef &outBlockRef);
|
||||
void ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef);
|
||||
HRESULT WriteBuf();
|
||||
|
||||
void InitFilters();
|
||||
@@ -217,7 +218,7 @@ class CDecoder:
|
||||
bool ReadVmCodeLZ();
|
||||
bool ReadVmCodePPM();
|
||||
|
||||
UInt32 ReadBits(int numBits);
|
||||
UInt32 ReadBits(unsigned numBits);
|
||||
|
||||
HRESULT InitPPM();
|
||||
int DecodePpmSymbol();
|
||||
|
||||
@@ -421,7 +421,7 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
|
||||
Byte lens[kTablesSizesSum];
|
||||
unsigned i = 0;
|
||||
|
||||
while (i < kTablesSizesSum)
|
||||
do
|
||||
{
|
||||
if (_bitStream._buf >= _bitStream._bufCheck2)
|
||||
{
|
||||
@@ -439,34 +439,24 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
|
||||
return S_FALSE;
|
||||
else
|
||||
{
|
||||
sym -= 16;
|
||||
unsigned sh = ((sym & 1) << 2);
|
||||
unsigned num = (unsigned)_bitStream.ReadBits9(3 + sh) + 3 + (sh << 1);
|
||||
|
||||
unsigned num = ((sym - 16) & 1) * 4;
|
||||
num += num + 3 + (unsigned)_bitStream.ReadBits9(num + 3);
|
||||
num += i;
|
||||
if (num > kTablesSizesSum)
|
||||
num = kTablesSizesSum;
|
||||
|
||||
if (sym < 2)
|
||||
Byte v = 0;
|
||||
if (sym < 16 + 2)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
// return S_FALSE;
|
||||
continue; // original unRAR
|
||||
}
|
||||
Byte v = lens[(size_t)i - 1];
|
||||
do
|
||||
lens[i++] = v;
|
||||
while (i < num);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
lens[i++] = 0;
|
||||
while (i < num);
|
||||
return S_FALSE;
|
||||
v = lens[(size_t)i - 1];
|
||||
}
|
||||
do
|
||||
lens[i++] = v;
|
||||
while (i < num);
|
||||
}
|
||||
}
|
||||
while (i < kTablesSizesSum);
|
||||
|
||||
if (_bitStream.IsBlockOverRead())
|
||||
return S_FALSE;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
namespace NCompress {
|
||||
namespace NShrink {
|
||||
|
||||
static const UInt32 kEmpty = 256; // kNumItems;
|
||||
static const UInt32 kBufferSize = (1 << 18);
|
||||
static const unsigned kNumMinBits = 9;
|
||||
|
||||
@@ -34,20 +35,15 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
|
||||
outBuffer.Init();
|
||||
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < 257; i++)
|
||||
_parents[i] = (UInt16)i;
|
||||
for (; i < kNumItems; i++)
|
||||
_parents[i] = kNumItems;
|
||||
for (i = 0; i < kNumItems; i++)
|
||||
_suffixes[i] = 0;
|
||||
for (unsigned i = 0; i < kNumItems; i++)
|
||||
_parents[i] = kEmpty;
|
||||
}
|
||||
|
||||
UInt64 prevPos = 0, inPrev = 0;
|
||||
UInt64 outPrev = 0, inPrev = 0;
|
||||
unsigned numBits = kNumMinBits;
|
||||
unsigned head = 257;
|
||||
int lastSym = -1;
|
||||
Byte lastChar2 = 0;
|
||||
Byte lastChar = 0;
|
||||
bool moreOut = false;
|
||||
|
||||
HRESULT res = S_FALSE;
|
||||
@@ -67,18 +63,22 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
|
||||
break;
|
||||
}
|
||||
eofCheck = true;
|
||||
// Is specSym(=256) allowed after end of stream
|
||||
// Do we need to read it here
|
||||
// Is specSym(=256) allowed after end of stream ?
|
||||
// Do we need to read it here ?
|
||||
}
|
||||
|
||||
if (progress)
|
||||
{
|
||||
if (nowPos - prevPos >= (1 << 18)
|
||||
|| _inProcessed - inPrev >= (1 << 20))
|
||||
if (nowPos - outPrev >= (1 << 20) || _inProcessed - inPrev >= (1 << 20))
|
||||
{
|
||||
prevPos = nowPos;
|
||||
outPrev = nowPos;
|
||||
inPrev = _inProcessed;
|
||||
RINOK(progress->SetRatioInfo(&_inProcessed, &nowPos));
|
||||
res = progress->SetRatioInfo(&_inProcessed, &nowPos);
|
||||
if (res != SZ_OK)
|
||||
{
|
||||
// break;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,23 +105,30 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
|
||||
continue;
|
||||
}
|
||||
if (sym != 2)
|
||||
break;
|
||||
{
|
||||
break;
|
||||
// continue; // info-zip just ignores such code
|
||||
}
|
||||
{
|
||||
/*
|
||||
---------- Free leaf nodes ----------
|
||||
Note : that code can mark _parents[lastSym] as free, and next
|
||||
inserted node will be Orphan in that case.
|
||||
*/
|
||||
|
||||
unsigned i;
|
||||
for (i = 257; i < kNumItems; i++)
|
||||
for (i = 256; i < kNumItems; i++)
|
||||
_stack[i] = 0;
|
||||
for (i = 257; i < kNumItems; i++)
|
||||
{
|
||||
unsigned par = _parents[i];
|
||||
if (par != kNumItems)
|
||||
if (par != kEmpty)
|
||||
_stack[par] = 1;
|
||||
}
|
||||
for (i = 257; i < kNumItems; i++)
|
||||
if (_stack[i] == 0)
|
||||
_parents[i] = kNumItems;
|
||||
|
||||
_parents[i] = kEmpty;
|
||||
head = 257;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -137,27 +144,22 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
|
||||
bool needPrev = false;
|
||||
if (head < kNumItems && lastSym >= 0)
|
||||
{
|
||||
while (head < kNumItems && _parents[head] != kNumItems)
|
||||
while (head < kNumItems && _parents[head] != kEmpty)
|
||||
head++;
|
||||
if (head < kNumItems)
|
||||
{
|
||||
if (head == (unsigned)lastSym)
|
||||
{
|
||||
// we need to fix the code for that case
|
||||
// _parents[head] is not allowed to link to itself
|
||||
res = E_NOTIMPL;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
if (head == lastSym), it updates Orphan to self-linked Orphan and creates two problems:
|
||||
1) we must check _stack[i++] overflow in code that walks tree nodes.
|
||||
2) self-linked node can not be removed. So such self-linked nodes can occupy all _parents items.
|
||||
*/
|
||||
needPrev = true;
|
||||
_parents[head] = (UInt16)lastSym;
|
||||
_suffixes[head] = (Byte)lastChar2;
|
||||
_suffixes[head] = (Byte)lastChar;
|
||||
head++;
|
||||
}
|
||||
}
|
||||
|
||||
if (_parents[sym] == kNumItems)
|
||||
break;
|
||||
|
||||
lastSym = sym;
|
||||
unsigned cur = sym;
|
||||
unsigned i = 0;
|
||||
@@ -166,10 +168,17 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
|
||||
{
|
||||
_stack[i++] = _suffixes[cur];
|
||||
cur = _parents[cur];
|
||||
// don't change that code:
|
||||
// Orphan Check and self-linked Orphan check (_stack overflow check);
|
||||
if (cur == kEmpty || i >= kNumItems)
|
||||
break;
|
||||
}
|
||||
|
||||
if (cur == kEmpty || i >= kNumItems)
|
||||
break;
|
||||
|
||||
_stack[i++] = (Byte)cur;
|
||||
lastChar2 = (Byte)cur;
|
||||
lastChar = (Byte)cur;
|
||||
|
||||
if (needPrev)
|
||||
_suffixes[(size_t)head - 1] = (Byte)cur;
|
||||
|
||||
@@ -19,8 +19,8 @@ class CDecoder :
|
||||
public ICompressGetInStreamProcessedSize,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
UInt64 _inProcessed;
|
||||
bool _fullStreamMode;
|
||||
UInt64 _inProcessed;
|
||||
|
||||
UInt16 _parents[kNumItems];
|
||||
Byte _suffixes[kNumItems];
|
||||
|
||||
@@ -162,8 +162,9 @@ void CDecoder::Hmac_Convert_32Bytes(Byte *data) const
|
||||
};
|
||||
|
||||
|
||||
static CKey g_Key;
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
static CKey g_Key;
|
||||
static NWindows::NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
|
||||
#define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
|
||||
#else
|
||||
|
||||
@@ -1217,7 +1217,12 @@ STDMETHODIMP CAgentFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
|
||||
if (propID == kpidReadOnly)
|
||||
prop = _agentSpec->IsThereReadOnlyArc();
|
||||
{
|
||||
if (_agentSpec->Is_Attrib_ReadOnly())
|
||||
prop = true;
|
||||
else
|
||||
prop = _agentSpec->IsThereReadOnlyArc();
|
||||
}
|
||||
else if (_proxy2)
|
||||
{
|
||||
const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex];
|
||||
@@ -1507,11 +1512,18 @@ STDMETHODIMP CAgentFolder::Extract(const UInt32 *indices,
|
||||
|
||||
#endif
|
||||
|
||||
HRESULT result = _agentSpec->GetArchive()->Extract(&realIndices.Front(),
|
||||
realIndices.Size(), testMode, extractCallback);
|
||||
if (result == S_OK)
|
||||
result = extractCallbackSpec->SetDirsTimes();
|
||||
return result;
|
||||
{
|
||||
CArchiveExtractCallback_Closer ecsCloser(extractCallbackSpec);
|
||||
|
||||
HRESULT res = _agentSpec->GetArchive()->Extract(&realIndices.Front(),
|
||||
realIndices.Size(), testMode, extractCallback);
|
||||
|
||||
HRESULT res2 = ecsCloser.Close();
|
||||
if (res == S_OK)
|
||||
res = res2;
|
||||
return res;
|
||||
}
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
@@ -1557,6 +1569,7 @@ STDMETHODIMP CAgent::Open(
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
_archiveFilePath = filePath;
|
||||
_attrib = 0;
|
||||
NFile::NFind::CFileInfo fi;
|
||||
_isDeviceFile = false;
|
||||
if (!inStream)
|
||||
@@ -1565,6 +1578,7 @@ STDMETHODIMP CAgent::Open(
|
||||
return ::GetLastError();
|
||||
if (fi.IsDir())
|
||||
return E_FAIL;
|
||||
_attrib = fi.Attrib;
|
||||
_isDeviceFile = fi.IsDevice;
|
||||
}
|
||||
CArcInfoEx archiverInfo0, archiverInfo1;
|
||||
|
||||
@@ -241,6 +241,7 @@ public:
|
||||
CAgentFolder *_agentFolder;
|
||||
|
||||
UString _archiveFilePath;
|
||||
DWORD _attrib;
|
||||
bool _isDeviceFile;
|
||||
|
||||
#ifndef EXTRACT_ONLY
|
||||
@@ -252,6 +253,11 @@ public:
|
||||
IInArchive *GetArchive() const { if ( _archiveLink.Arcs.IsEmpty()) return 0; return GetArc().Archive; }
|
||||
bool CanUpdate() const;
|
||||
|
||||
bool Is_Attrib_ReadOnly() const
|
||||
{
|
||||
return _attrib != INVALID_FILE_ATTRIBUTES && (_attrib & FILE_ATTRIBUTE_READONLY);
|
||||
}
|
||||
|
||||
bool IsThereReadOnlyArc() const
|
||||
{
|
||||
FOR_VECTOR (i, _archiveLink.Arcs)
|
||||
|
||||
@@ -124,6 +124,7 @@ enum Enum
|
||||
kTechMode,
|
||||
|
||||
kShareForWrite,
|
||||
kStopAfterOpenError,
|
||||
kCaseSensitive,
|
||||
kArcNameMode,
|
||||
|
||||
@@ -245,6 +246,7 @@ static const CSwitchForm kSwitchForms[] =
|
||||
{ "slt" },
|
||||
|
||||
{ "ssw" },
|
||||
{ "sse" },
|
||||
{ "ssc", NSwitchType::kMinus },
|
||||
{ "sa", NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet },
|
||||
|
||||
@@ -1299,6 +1301,8 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
|
||||
|
||||
if (parser[NKey::kShareForWrite].ThereIs)
|
||||
updateOptions.OpenShareForWrite = true;
|
||||
if (parser[NKey::kStopAfterOpenError].ThereIs)
|
||||
updateOptions.StopAfterOpenError = true;
|
||||
|
||||
updateOptions.PathMode = censorPathMode;
|
||||
|
||||
|
||||
@@ -182,6 +182,7 @@ HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *r
|
||||
#endif
|
||||
|
||||
CArchiveExtractCallback::CArchiveExtractCallback():
|
||||
_arc(NULL),
|
||||
WriteCTime(true),
|
||||
WriteATime(true),
|
||||
WriteMTime(true),
|
||||
@@ -205,8 +206,8 @@ void CArchiveExtractCallback::Init(
|
||||
const UStringVector &removePathParts, bool removePartsForAltStreams,
|
||||
UInt64 packSize)
|
||||
{
|
||||
_extractedFolderPaths.Clear();
|
||||
_extractedFolderIndices.Clear();
|
||||
ClearExtractedDirsInfo();
|
||||
_outFileStream.Release();
|
||||
|
||||
#ifdef SUPPORT_LINKS
|
||||
_hardLinks.Clear();
|
||||
@@ -368,9 +369,11 @@ void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPat
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CArchiveExtractCallback::GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined)
|
||||
HRESULT CArchiveExtractCallback::GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined)
|
||||
{
|
||||
filetimeIsDefined = false;
|
||||
filetime.dwLowDateTime = 0;
|
||||
filetime.dwHighDateTime = 0;
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(_arc->Archive->GetProperty(index, propID, &prop));
|
||||
if (prop.vt == VT_FILETIME)
|
||||
@@ -734,7 +737,8 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
|
||||
return E_FAIL;
|
||||
UString s;
|
||||
CReparseAttr reparse;
|
||||
isOkReparse = reparse.Parse((const Byte *)data, dataSize);
|
||||
DWORD errorCode = 0;
|
||||
isOkReparse = reparse.Parse((const Byte *)data, dataSize, errorCode);
|
||||
if (isOkReparse)
|
||||
{
|
||||
isHardLink = false;
|
||||
@@ -1030,14 +1034,36 @@ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)
|
||||
{
|
||||
FString fullPathNew;
|
||||
CreateComplexDirectory(pathParts, fullPathNew);
|
||||
|
||||
if (_item.IsDir)
|
||||
{
|
||||
_extractedFolderPaths.Add(fullPathNew);
|
||||
_extractedFolderIndices.Add(index);
|
||||
SetDirTime(fullPathNew,
|
||||
(WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL,
|
||||
(WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL,
|
||||
(WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
|
||||
CDirPathTime &pt = _extractedFolders.AddNew();
|
||||
|
||||
pt.CTime = _fi.CTime;
|
||||
pt.CTimeDefined = (WriteCTime && _fi.CTimeDefined);
|
||||
|
||||
pt.ATime = _fi.ATime;
|
||||
pt.ATimeDefined = (WriteATime && _fi.ATimeDefined);
|
||||
|
||||
pt.MTimeDefined = false;
|
||||
|
||||
if (WriteMTime)
|
||||
{
|
||||
if (_fi.MTimeDefined)
|
||||
{
|
||||
pt.MTime = _fi.MTime;
|
||||
pt.MTimeDefined = true;
|
||||
}
|
||||
else if (_arc->MTimeDefined)
|
||||
{
|
||||
pt.MTime = _arc->MTime;
|
||||
pt.MTimeDefined = true;
|
||||
}
|
||||
}
|
||||
|
||||
pt.Path = fullPathNew;
|
||||
|
||||
pt.SetDirTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1270,7 +1296,8 @@ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)
|
||||
if (FillLinkData(data, fs2us(existPath), !isJunction))
|
||||
{
|
||||
CReparseAttr attr;
|
||||
if (!attr.Parse(data, data.Size()))
|
||||
DWORD errorCode = 0;
|
||||
if (!attr.Parse(data, data.Size(), errorCode))
|
||||
{
|
||||
RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path)));
|
||||
// return E_FAIL;
|
||||
@@ -1447,6 +1474,33 @@ STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)
|
||||
}
|
||||
|
||||
|
||||
HRESULT CArchiveExtractCallback::CloseFile()
|
||||
{
|
||||
if (!_outFileStream)
|
||||
return S_OK;
|
||||
|
||||
HRESULT hres = S_OK;
|
||||
_outFileStreamSpec->SetTime(
|
||||
(WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL,
|
||||
(WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL,
|
||||
(WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
|
||||
|
||||
const UInt64 processedSize = _outFileStreamSpec->ProcessedSize;
|
||||
if (_fileLengthWasSet && _curSize > processedSize)
|
||||
{
|
||||
bool res = _outFileStreamSpec->File.SetLength(processedSize);
|
||||
_fileLengthWasSet = res;
|
||||
if (!res)
|
||||
hres = SendMessageError_with_LastError(kCantSetFileLen, us2fs(_item.Path));
|
||||
}
|
||||
_curSize = processedSize;
|
||||
_curSizeDefined = true;
|
||||
RINOK(_outFileStreamSpec->Close());
|
||||
_outFileStream.Release();
|
||||
return hres;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
@@ -1475,27 +1529,7 @@ STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes)
|
||||
|
||||
#endif
|
||||
|
||||
if (_outFileStream)
|
||||
{
|
||||
HRESULT hres = S_OK;
|
||||
_outFileStreamSpec->SetTime(
|
||||
(WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL,
|
||||
(WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL,
|
||||
(WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
|
||||
const UInt64 processedSize = _outFileStreamSpec->ProcessedSize;
|
||||
if (_fileLengthWasSet && _curSize > processedSize)
|
||||
{
|
||||
bool res = _outFileStreamSpec->File.SetLength(processedSize);
|
||||
_fileLengthWasSet = res;
|
||||
if (!res)
|
||||
hres = SendMessageError_with_LastError(kCantSetFileLen, us2fs(_item.Path));
|
||||
}
|
||||
_curSize = processedSize;
|
||||
_curSizeDefined = true;
|
||||
RINOK(_outFileStreamSpec->Close());
|
||||
_outFileStream.Release();
|
||||
RINOK(hres);
|
||||
}
|
||||
RINOK(CloseFile());
|
||||
|
||||
#ifdef _USE_SECURITY_CODE
|
||||
if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps)
|
||||
@@ -1592,71 +1626,66 @@ STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
|
||||
}
|
||||
|
||||
|
||||
struct CExtrRefSortPair
|
||||
{
|
||||
unsigned Len;
|
||||
unsigned Index;
|
||||
|
||||
int Compare(const CExtrRefSortPair &a) const;
|
||||
};
|
||||
|
||||
#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
|
||||
|
||||
int CExtrRefSortPair::Compare(const CExtrRefSortPair &a) const
|
||||
{
|
||||
RINOZ(-MyCompare(Len, a.Len));
|
||||
return MyCompare(Index, a.Index);
|
||||
}
|
||||
|
||||
static unsigned GetNumSlashes(const FChar *s)
|
||||
void CDirPathSortPair::SetNumSlashes(const FChar *s)
|
||||
{
|
||||
for (unsigned numSlashes = 0;;)
|
||||
{
|
||||
FChar c = *s++;
|
||||
if (c == 0)
|
||||
return numSlashes;
|
||||
{
|
||||
Len = numSlashes;
|
||||
return;
|
||||
}
|
||||
if (IS_PATH_SEPAR(c))
|
||||
numSlashes++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CDirPathTime::SetDirTime()
|
||||
{
|
||||
return NDir::SetDirTime(Path,
|
||||
CTimeDefined ? &CTime : NULL,
|
||||
ATimeDefined ? &ATime : NULL,
|
||||
MTimeDefined ? &MTime : NULL);
|
||||
}
|
||||
|
||||
|
||||
HRESULT CArchiveExtractCallback::SetDirsTimes()
|
||||
{
|
||||
CRecordVector<CExtrRefSortPair> pairs;
|
||||
pairs.ClearAndSetSize(_extractedFolderPaths.Size());
|
||||
if (!_arc)
|
||||
return S_OK;
|
||||
|
||||
CRecordVector<CDirPathSortPair> pairs;
|
||||
pairs.ClearAndSetSize(_extractedFolders.Size());
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < _extractedFolderPaths.Size(); i++)
|
||||
for (i = 0; i < _extractedFolders.Size(); i++)
|
||||
{
|
||||
CExtrRefSortPair &pair = pairs[i];
|
||||
CDirPathSortPair &pair = pairs[i];
|
||||
pair.Index = i;
|
||||
pair.Len = GetNumSlashes(_extractedFolderPaths[i]);
|
||||
pair.SetNumSlashes(_extractedFolders[i].Path);
|
||||
}
|
||||
|
||||
pairs.Sort2();
|
||||
|
||||
for (i = 0; i < pairs.Size(); i++)
|
||||
{
|
||||
int pairIndex = pairs[i].Index;
|
||||
int index = _extractedFolderIndices[pairIndex];
|
||||
|
||||
FILETIME CTime;
|
||||
FILETIME ATime;
|
||||
FILETIME MTime;
|
||||
|
||||
bool CTimeDefined;
|
||||
bool ATimeDefined;
|
||||
bool MTimeDefined;
|
||||
|
||||
RINOK(GetTime(index, kpidCTime, CTime, CTimeDefined));
|
||||
RINOK(GetTime(index, kpidATime, ATime, ATimeDefined));
|
||||
RINOK(GetTime(index, kpidMTime, MTime, MTimeDefined));
|
||||
|
||||
// printf("\n%S", _extractedFolderPaths[pairIndex]);
|
||||
SetDirTime(_extractedFolderPaths[pairIndex],
|
||||
(WriteCTime && CTimeDefined) ? &CTime : NULL,
|
||||
(WriteATime && ATimeDefined) ? &ATime : NULL,
|
||||
(WriteMTime && MTimeDefined) ? &MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
|
||||
_extractedFolders[pairs[i].Index].SetDirTime();
|
||||
// if (!) return GetLastError();
|
||||
}
|
||||
|
||||
ClearExtractedDirsInfo();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CArchiveExtractCallback::CloseArc()
|
||||
{
|
||||
HRESULT res = CloseFile();
|
||||
HRESULT res2 = SetDirsTimes();
|
||||
if (res == S_OK)
|
||||
res = res2;
|
||||
_arc = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -151,6 +151,25 @@ struct CIndexToPathPair
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
struct CDirPathTime
|
||||
{
|
||||
FILETIME CTime;
|
||||
FILETIME ATime;
|
||||
FILETIME MTime;
|
||||
|
||||
bool CTimeDefined;
|
||||
bool ATimeDefined;
|
||||
bool MTimeDefined;
|
||||
|
||||
FString Path;
|
||||
|
||||
bool SetDirTime();
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CArchiveExtractCallback:
|
||||
public IArchiveExtractCallback,
|
||||
public IArchiveExtractCallbackMessage,
|
||||
@@ -241,15 +260,14 @@ class CArchiveExtractCallback:
|
||||
UInt64 _progressTotal;
|
||||
bool _progressTotal_Defined;
|
||||
|
||||
FStringVector _extractedFolderPaths;
|
||||
CRecordVector<UInt32> _extractedFolderIndices;
|
||||
CObjectVector<CDirPathTime> _extractedFolders;
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX)
|
||||
bool _saclEnabled;
|
||||
#endif
|
||||
|
||||
void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath);
|
||||
HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);
|
||||
HRESULT GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);
|
||||
HRESULT GetUnpackSize();
|
||||
|
||||
HRESULT SendMessageError(const char *message, const FString &path);
|
||||
@@ -343,9 +361,43 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
HRESULT CloseArc();
|
||||
|
||||
private:
|
||||
void ClearExtractedDirsInfo()
|
||||
{
|
||||
_extractedFolders.Clear();
|
||||
}
|
||||
|
||||
HRESULT CloseFile();
|
||||
HRESULT SetDirsTimes();
|
||||
};
|
||||
|
||||
|
||||
struct CArchiveExtractCallback_Closer
|
||||
{
|
||||
CArchiveExtractCallback *_ref;
|
||||
|
||||
CArchiveExtractCallback_Closer(CArchiveExtractCallback *ref): _ref(ref) {}
|
||||
|
||||
HRESULT Close()
|
||||
{
|
||||
HRESULT res = S_OK;
|
||||
if (_ref)
|
||||
{
|
||||
res = _ref->CloseArc();
|
||||
_ref = NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
~CArchiveExtractCallback_Closer()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -386,15 +386,27 @@ HRESULT CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi,
|
||||
return S_OK;
|
||||
const FString path = phyPrefix + fi.Name;
|
||||
CByteBuffer &buf = dirItem.ReparseData;
|
||||
DWORD res = 0;
|
||||
if (NIO::GetReparseData(path, buf))
|
||||
{
|
||||
CReparseAttr attr;
|
||||
if (attr.Parse(buf, buf.Size()))
|
||||
if (attr.Parse(buf, buf.Size(), res))
|
||||
return S_OK;
|
||||
// we ignore unknown reparse points
|
||||
if (res != ERROR_INVALID_REPARSE_DATA)
|
||||
res = 0;
|
||||
}
|
||||
DWORD res = ::GetLastError();
|
||||
else
|
||||
{
|
||||
res = ::GetLastError();
|
||||
if (res == 0)
|
||||
res = ERROR_INVALID_FUNCTION;
|
||||
}
|
||||
|
||||
buf.Free();
|
||||
return AddError(path , res);
|
||||
if (res == 0)
|
||||
return S_OK;
|
||||
return AddError(path, res);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -865,7 +877,8 @@ void CDirItems::FillFixedReparse()
|
||||
continue;
|
||||
|
||||
CReparseAttr attr;
|
||||
if (!attr.Parse(item.ReparseData, item.ReparseData.Size()))
|
||||
DWORD errorCode = 0;
|
||||
if (!attr.Parse(item.ReparseData, item.ReparseData.Size(), errorCode))
|
||||
continue;
|
||||
if (attr.IsRelative())
|
||||
continue;
|
||||
|
||||
@@ -197,6 +197,9 @@ static HRESULT DecompressArchive(
|
||||
|
||||
HRESULT result;
|
||||
Int32 testMode = (options.TestMode && !calcCrc) ? 1: 0;
|
||||
|
||||
CArchiveExtractCallback_Closer ecsCloser(ecs);
|
||||
|
||||
if (options.StdInMode)
|
||||
{
|
||||
result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, ecs);
|
||||
@@ -206,8 +209,11 @@ static HRESULT DecompressArchive(
|
||||
}
|
||||
else
|
||||
result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, ecs);
|
||||
if (result == S_OK && !options.StdInMode)
|
||||
result = ecs->SetDirsTimes();
|
||||
|
||||
HRESULT res2 = ecsCloser.Close();
|
||||
if (result == S_OK)
|
||||
result = res2;
|
||||
|
||||
return callback->ExtractResult(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -857,7 +857,7 @@ HRESULT CArc::GetItem(UInt32 index, CReadArcItem &item) const
|
||||
|
||||
if (item.WriteToAltStreamIfColon || needFindAltStream)
|
||||
{
|
||||
/* Good handler must support GetRawProps::GetParent for alt streams./
|
||||
/* Good handler must support GetRawProps::GetParent for alt streams.
|
||||
So the following code currently is not used */
|
||||
int colon = FindAltStreamColon_in_Path(item.Path);
|
||||
if (colon >= 0)
|
||||
|
||||
@@ -414,4 +414,23 @@ struct CArchiveLink
|
||||
|
||||
bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types);
|
||||
|
||||
|
||||
struct CDirPathSortPair
|
||||
{
|
||||
unsigned Len;
|
||||
unsigned Index;
|
||||
|
||||
void SetNumSlashes(const FChar *s);
|
||||
|
||||
int Compare(const CDirPathSortPair &a) const
|
||||
{
|
||||
// We need sorting order where parent items will be after child items
|
||||
if (Len < a.Len) return 1;
|
||||
if (Len > a.Len) return -1;
|
||||
if (Index < a.Index) return -1;
|
||||
if (Index > a.Index) return 1;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -224,7 +224,6 @@ static inline void AddHexToString(AString &res, unsigned v)
|
||||
{
|
||||
res += (char)GetHex(v >> 4);
|
||||
res += (char)GetHex(v & 0xF);
|
||||
res += ' ';
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -269,6 +268,14 @@ struct CSecID2Name
|
||||
const char *sz;
|
||||
};
|
||||
|
||||
static int FindPairIndex(const CSecID2Name * pairs, unsigned num, UInt32 id)
|
||||
{
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
if (pairs[i].n == id)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const CSecID2Name sid_32_Names[] =
|
||||
{
|
||||
{ 544, "Administrators" },
|
||||
@@ -359,22 +366,22 @@ static void ParseSid(AString &s, const Byte *p, UInt32 lim, UInt32 &sidSize)
|
||||
if (v0 == 32 && num == 2)
|
||||
{
|
||||
UInt32 v1 = Get32(p + 12);
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(sid_32_Names); i++)
|
||||
if (sid_32_Names[i].n == v1)
|
||||
{
|
||||
s += sid_32_Names[i].sz;
|
||||
return;
|
||||
}
|
||||
int index = FindPairIndex(sid_32_Names, ARRAY_SIZE(sid_32_Names), v1);
|
||||
if (index >= 0)
|
||||
{
|
||||
s += sid_32_Names[index].sz;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (v0 == 21 && num == 5)
|
||||
{
|
||||
UInt32 v4 = Get32(p + 8 + 4 * 4);
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(sid_21_Names); i++)
|
||||
if (sid_21_Names[i].n == v4)
|
||||
{
|
||||
s += sid_21_Names[i].sz;
|
||||
return;
|
||||
}
|
||||
int index = FindPairIndex(sid_21_Names, ARRAY_SIZE(sid_21_Names), v4);
|
||||
if (index >= 0)
|
||||
{
|
||||
s += sid_21_Names[index].sz;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (v0 == 80 && num == 6)
|
||||
{
|
||||
@@ -419,20 +426,13 @@ static void ParseOwner(AString &s, const Byte *p, UInt32 size, UInt32 pos)
|
||||
ParseSid(s, p + pos, size - pos, sidSize);
|
||||
}
|
||||
|
||||
static void AddUInt32ToString(AString &s, UInt32 val)
|
||||
{
|
||||
char sz[16];
|
||||
ConvertUInt32ToString(val, sz);
|
||||
s += sz;
|
||||
}
|
||||
|
||||
static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName, UInt32 flags, UInt32 offset)
|
||||
{
|
||||
UInt32 control = Get16(p + 2);
|
||||
if ((flags & control) == 0)
|
||||
return;
|
||||
UInt32 pos = Get32(p + offset);
|
||||
s += ' ';
|
||||
s.Add_Space();
|
||||
s += strName;
|
||||
if (pos >= size)
|
||||
return;
|
||||
@@ -443,7 +443,7 @@ static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName
|
||||
if (Get16(p) != 2) // revision
|
||||
return;
|
||||
UInt32 num = Get32(p + 4);
|
||||
AddUInt32ToString(s, num);
|
||||
s.Add_UInt32(num);
|
||||
|
||||
/*
|
||||
UInt32 aclSize = Get16(p + 2);
|
||||
@@ -466,7 +466,7 @@ static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName
|
||||
size -= 8;
|
||||
|
||||
UInt32 sidSize = 0;
|
||||
s += ' ';
|
||||
s.Add_Space();
|
||||
ParseSid(s, p, size, sidSize);
|
||||
if (sidSize == 0)
|
||||
return;
|
||||
@@ -508,12 +508,12 @@ void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s)
|
||||
return;
|
||||
}
|
||||
ParseOwner(s, data, size, Get32(data + 4));
|
||||
s += ' ';
|
||||
s.Add_Space();
|
||||
ParseOwner(s, data, size, Get32(data + 8));
|
||||
ParseAcl(s, data, size, "s:", MY_SE_SACL_PRESENT, 12);
|
||||
ParseAcl(s, data, size, "d:", MY_SE_DACL_PRESENT, 16);
|
||||
s += ' ';
|
||||
AddUInt32ToString(s, size);
|
||||
s.Add_Space();
|
||||
s.Add_UInt32(size);
|
||||
// s += '\n';
|
||||
// s += Data_To_Hex(data, size);
|
||||
}
|
||||
@@ -567,11 +567,38 @@ bool CheckNtSecure(const Byte *data, UInt32 size) throw()
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// IO_REPARSE_TAG_*
|
||||
|
||||
static const CSecID2Name k_ReparseTags[] =
|
||||
{
|
||||
{ 0xA0000003, "MOUNT_POINT" },
|
||||
{ 0xC0000004, "HSM" },
|
||||
{ 0x80000005, "DRIVE_EXTENDER" },
|
||||
{ 0x80000006, "HSM2" },
|
||||
{ 0x80000007, "SIS" },
|
||||
{ 0x80000008, "WIM" },
|
||||
{ 0x80000009, "CSV" },
|
||||
{ 0x8000000A, "DFS" },
|
||||
{ 0x8000000B, "FILTER_MANAGER" },
|
||||
{ 0xA000000C, "SYMLINK" },
|
||||
{ 0xA0000010, "IIS_CACHE" },
|
||||
{ 0x80000012, "DFSR" },
|
||||
{ 0x80000013, "DEDUP" },
|
||||
{ 0xC0000014, "APPXSTRM" },
|
||||
{ 0x80000014, "NFS" },
|
||||
{ 0x80000015, "FILE_PLACEHOLDER" },
|
||||
{ 0x80000016, "DFM" },
|
||||
{ 0x80000017, "WOF" }
|
||||
};
|
||||
|
||||
bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s)
|
||||
{
|
||||
s.Empty();
|
||||
NFile::CReparseAttr attr;
|
||||
if (attr.Parse(data, size))
|
||||
DWORD errorCode = 0;
|
||||
if (attr.Parse(data, size, errorCode))
|
||||
{
|
||||
if (!attr.IsSymLink())
|
||||
s += "Junction: ";
|
||||
@@ -593,19 +620,48 @@ bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s)
|
||||
if (Get16(data + 6) != 0) // padding
|
||||
return false;
|
||||
|
||||
char hex[16];
|
||||
ConvertUInt32ToHex8Digits(tag, hex);
|
||||
s += hex;
|
||||
s.Add_Space();
|
||||
|
||||
data += 8;
|
||||
|
||||
for (UInt32 i = 0; i < len; i++)
|
||||
/*
|
||||
#define _my_IO_REPARSE_TAG_DEDUP (0x80000013L)
|
||||
if (tag == _my_IO_REPARSE_TAG_DEDUP)
|
||||
{
|
||||
unsigned b = ((const Byte *)data)[i];
|
||||
s += (char)GetHex((b >> 4) & 0xF);
|
||||
s += (char)GetHex(b & 0xF);
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
int index = FindPairIndex(k_ReparseTags, ARRAY_SIZE(k_ReparseTags), tag);
|
||||
if (index >= 0)
|
||||
s += k_ReparseTags[index].sz;
|
||||
else
|
||||
{
|
||||
s += "REPARSE:";
|
||||
char hex[16];
|
||||
ConvertUInt32ToHex8Digits(tag, hex);
|
||||
s += hex;
|
||||
}
|
||||
}
|
||||
|
||||
s += ":";
|
||||
s.Add_UInt32(len);
|
||||
|
||||
if (len != 0)
|
||||
{
|
||||
s.Add_Space();
|
||||
|
||||
data += 8;
|
||||
|
||||
for (UInt32 i = 0; i < len; i++)
|
||||
{
|
||||
if (i >= 8)
|
||||
{
|
||||
s += "...";
|
||||
break;
|
||||
}
|
||||
unsigned b = data[i];
|
||||
s += (char)GetHex((b >> 4) & 0xF);
|
||||
s += (char)GetHex(b & 0xF);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -735,6 +735,7 @@ static HRESULT Compress(
|
||||
CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
|
||||
|
||||
updateCallbackSpec->ShareForWrite = options.OpenShareForWrite;
|
||||
updateCallbackSpec->StopAfterOpenError = options.StopAfterOpenError;
|
||||
updateCallbackSpec->StdInMode = options.StdInMode;
|
||||
updateCallbackSpec->Callback = callback;
|
||||
|
||||
@@ -1045,32 +1046,6 @@ static HRESULT EnumerateInArchiveItems(
|
||||
|
||||
#endif
|
||||
|
||||
struct CRefSortPair
|
||||
{
|
||||
unsigned Len;
|
||||
unsigned Index;
|
||||
};
|
||||
|
||||
#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
|
||||
|
||||
static int CompareRefSortPair(const CRefSortPair *a1, const CRefSortPair *a2, void *)
|
||||
{
|
||||
RINOZ(-MyCompare(a1->Len, a2->Len));
|
||||
return MyCompare(a1->Index, a2->Index);
|
||||
}
|
||||
|
||||
static unsigned GetNumSlashes(const FChar *s)
|
||||
{
|
||||
for (unsigned numSlashes = 0;;)
|
||||
{
|
||||
FChar c = *s++;
|
||||
if (c == 0)
|
||||
return numSlashes;
|
||||
if (IS_PATH_SEPAR(c))
|
||||
numSlashes++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void ConvertToLongNames(NWildcard::CCensor &censor);
|
||||
#endif
|
||||
@@ -1189,6 +1164,16 @@ HRESULT UpdateArchive(
|
||||
throw "there is no such archive";
|
||||
if (fi.IsDevice)
|
||||
return E_NOTIMPL;
|
||||
|
||||
if (!options.StdOutMode && options.UpdateArchiveItself)
|
||||
if (fi.IsReadOnly())
|
||||
{
|
||||
errorInfo.SystemError = ERROR_ACCESS_DENIED;
|
||||
errorInfo.Message = "The file is read-only";
|
||||
errorInfo.FileNames.Add(arcPath);
|
||||
return errorInfo.Get_HRESULT_Error();
|
||||
}
|
||||
|
||||
if (options.VolumesSizes.Size() > 0)
|
||||
{
|
||||
errorInfo.FileNames.Add(us2fs(arcPath));
|
||||
@@ -1509,9 +1494,13 @@ HRESULT UpdateArchive(
|
||||
CArchivePath &ap = options.Commands[0].ArchivePath;
|
||||
const FString &tempPath = ap.GetTempPath();
|
||||
|
||||
// DWORD attrib = 0;
|
||||
if (thereIsInArchive)
|
||||
{
|
||||
// attrib = NFind::GetFileAttrib(us2fs(arcPath));
|
||||
if (!DeleteFileAlways(us2fs(arcPath)))
|
||||
return errorInfo.SetFromLastError("cannot delete the file", us2fs(arcPath));
|
||||
}
|
||||
|
||||
if (!MyMoveFile(tempPath, us2fs(arcPath)))
|
||||
{
|
||||
@@ -1519,6 +1508,15 @@ HRESULT UpdateArchive(
|
||||
errorInfo.FileNames.Add(us2fs(arcPath));
|
||||
return errorInfo.Get_HRESULT_Error();
|
||||
}
|
||||
|
||||
/*
|
||||
if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY))
|
||||
{
|
||||
DWORD attrib2 = NFind::GetFileAttrib(us2fs(arcPath));
|
||||
if (attrib2 != INVALID_FILE_ATTRIBUTES)
|
||||
NDir::SetFileAttrib(us2fs(arcPath), attrib2 | FILE_ATTRIBUTE_READONLY);
|
||||
}
|
||||
*/
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
@@ -1608,7 +1606,7 @@ HRESULT UpdateArchive(
|
||||
|
||||
if (options.DeleteAfterCompressing)
|
||||
{
|
||||
CRecordVector<CRefSortPair> pairs;
|
||||
CRecordVector<CDirPathSortPair> pairs;
|
||||
FStringVector foldersNames;
|
||||
|
||||
unsigned i;
|
||||
@@ -1616,12 +1614,12 @@ HRESULT UpdateArchive(
|
||||
for (i = 0; i < dirItems.Items.Size(); i++)
|
||||
{
|
||||
const CDirItem &dirItem = dirItems.Items[i];
|
||||
FString phyPath = dirItems.GetPhyPath(i);
|
||||
const FString phyPath = dirItems.GetPhyPath(i);
|
||||
if (dirItem.IsDir())
|
||||
{
|
||||
CRefSortPair pair;
|
||||
CDirPathSortPair pair;
|
||||
pair.Index = i;
|
||||
pair.Len = GetNumSlashes(phyPath);
|
||||
pair.SetNumSlashes(phyPath);
|
||||
pairs.Add(pair);
|
||||
}
|
||||
else
|
||||
@@ -1654,11 +1652,11 @@ HRESULT UpdateArchive(
|
||||
}
|
||||
}
|
||||
|
||||
pairs.Sort(CompareRefSortPair, NULL);
|
||||
pairs.Sort2();
|
||||
|
||||
for (i = 0; i < pairs.Size(); i++)
|
||||
{
|
||||
FString phyPath = dirItems.GetPhyPath(pairs[i].Index);
|
||||
const FString phyPath = dirItems.GetPhyPath(pairs[i].Index);
|
||||
if (NFind::DoesDirExist(phyPath))
|
||||
{
|
||||
RINOK(callback->DeletingAfterArchiving(phyPath, true));
|
||||
|
||||
@@ -92,6 +92,7 @@ struct CUpdateOptions
|
||||
FString SfxModule;
|
||||
|
||||
bool OpenShareForWrite;
|
||||
bool StopAfterOpenError;
|
||||
|
||||
bool StdInMode;
|
||||
UString StdInFileName;
|
||||
@@ -127,6 +128,7 @@ struct CUpdateOptions
|
||||
EMailMode(false),
|
||||
EMailRemoveAfter(false),
|
||||
OpenShareForWrite(false),
|
||||
StopAfterOpenError(false),
|
||||
ArcNameMode(k_ArcNameMode_Smart),
|
||||
PathMode(NWildcard::k_RelatPath),
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ CArchiveUpdateCallback::CArchiveUpdateCallback():
|
||||
Comment(NULL),
|
||||
|
||||
ShareForWrite(false),
|
||||
StopAfterOpenError(false),
|
||||
StdInMode(false),
|
||||
|
||||
KeepOriginalItemNames(false),
|
||||
@@ -346,7 +347,8 @@ STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR
|
||||
// if (di.IsDir())
|
||||
{
|
||||
CReparseAttr attr;
|
||||
if (attr.Parse(di.ReparseData, di.ReparseData.Size()))
|
||||
DWORD errorCode = 0;
|
||||
if (attr.Parse(di.ReparseData, di.ReparseData.Size(), errorCode))
|
||||
{
|
||||
UString simpleName = attr.GetPath();
|
||||
if (attr.IsRelative())
|
||||
@@ -512,7 +514,12 @@ STDMETHODIMP CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStrea
|
||||
#endif
|
||||
if (!inStreamSpec->OpenShared(path, ShareForWrite))
|
||||
{
|
||||
return Callback->OpenFileError(path, ::GetLastError());
|
||||
DWORD error = ::GetLastError();
|
||||
HRESULT hres = Callback->OpenFileError(path, error);
|
||||
if (StopAfterOpenError)
|
||||
if (hres == S_OK || hres == S_FALSE)
|
||||
return HRESULT_FROM_WIN32(error);
|
||||
return hres;
|
||||
}
|
||||
|
||||
if (StoreHardLinks)
|
||||
|
||||
@@ -136,6 +136,7 @@ public:
|
||||
const UString *Comment;
|
||||
|
||||
bool ShareForWrite;
|
||||
bool StopAfterOpenError;
|
||||
bool StdInMode;
|
||||
|
||||
bool KeepOriginalItemNames;
|
||||
|
||||
@@ -95,6 +95,16 @@ void PrintSize_bytes_Smart(AString &s, UInt64 val)
|
||||
s += ')';
|
||||
}
|
||||
|
||||
void PrintSize_bytes_Smart_comma(AString &s, UInt64 val)
|
||||
{
|
||||
if (val == (UInt64)(Int64)-1)
|
||||
return;
|
||||
s += ", ";
|
||||
PrintSize_bytes_Smart(s, val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Print_DirItemsStat(AString &s, const CDirItemsStat &st)
|
||||
{
|
||||
if (st.NumDirs != 0)
|
||||
@@ -103,14 +113,12 @@ void Print_DirItemsStat(AString &s, const CDirItemsStat &st)
|
||||
s += ", ";
|
||||
}
|
||||
Print_UInt64_and_String(s, st.NumFiles, st.NumFiles == 1 ? "file" : "files");
|
||||
s += ", ";
|
||||
PrintSize_bytes_Smart(s, st.FilesSize);
|
||||
PrintSize_bytes_Smart_comma(s, st.FilesSize);
|
||||
if (st.NumAltStreams != 0)
|
||||
{
|
||||
s.Add_LF();
|
||||
Print_UInt64_and_String(s, st.NumAltStreams, "alternate streams");
|
||||
s += ", ";
|
||||
PrintSize_bytes_Smart(s, st.AltStreamsSize);
|
||||
PrintSize_bytes_Smart_comma(s, st.AltStreamsSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +252,7 @@ static const char * const kTab = " ";
|
||||
static void PrintFileInfo(CStdOutStream *_so, const wchar_t *path, const FILETIME *ft, const UInt64 *size)
|
||||
{
|
||||
*_so << kTab << "Path: " << path << endl;
|
||||
if (size)
|
||||
if (size && *size != (UInt64)(Int64)-1)
|
||||
{
|
||||
AString s;
|
||||
PrintSize_bytes_Smart(s, *size);
|
||||
|
||||
@@ -150,6 +150,7 @@ static const char * const kHelpString =
|
||||
" -spe : eliminate duplication of root folder for extract command\n"
|
||||
" -spf : use fully qualified file paths\n"
|
||||
" -ssc[-] : set sensitive case mode\n"
|
||||
" -sse : stop archive creating, if it can't open some input file\n"
|
||||
" -ssw : compress shared files\n"
|
||||
" -stl : set archive timestamp from the most recently modified file\n"
|
||||
" -stm{HexMask} : set CPU thread affinity mask (hexadecimal number)\n"
|
||||
|
||||
@@ -55,7 +55,8 @@ static bool GetSymLink(CFSTR path, CReparseAttr &attr)
|
||||
if (!file.DeviceIoControlOut(my_FSCTL_GET_REPARSE_POINT, buf, kBufSize, &returnedSize))
|
||||
return false;
|
||||
|
||||
if (!attr.Parse(buf, returnedSize))
|
||||
DWORD errorCode = 0;
|
||||
if (!attr.Parse(buf, returnedSize, errorCode))
|
||||
return false;
|
||||
|
||||
CByteBuffer data2;
|
||||
@@ -291,7 +292,8 @@ void CLinkDialog::OnButton_Link()
|
||||
}
|
||||
|
||||
CReparseAttr attr;
|
||||
if (!attr.Parse(data, data.Size()))
|
||||
DWORD errorCode = 0;
|
||||
if (!attr.Parse(data, data.Size(), errorCode))
|
||||
{
|
||||
ShowError(L"Internal conversion error");
|
||||
return;
|
||||
|
||||
@@ -827,7 +827,8 @@ void CPanel::OpenFolder(int index)
|
||||
SetNewFolder(newFolder);
|
||||
LoadFullPath();
|
||||
RefreshListCtrl();
|
||||
_listView.SetItemState_Selected(_listView.GetFocusedItem());
|
||||
// 17.02: fixed : now we don't select first item
|
||||
// _listView.SetItemState_Selected(_listView.GetFocusedItem());
|
||||
_listView.EnsureVisible(_listView.GetFocusedItem(), false);
|
||||
}
|
||||
|
||||
|
||||
@@ -702,6 +702,8 @@ void CPanel::Refresh_StatusBar()
|
||||
|
||||
wchar_t temp[32];
|
||||
ConvertUInt32ToString(indices.Size(), temp);
|
||||
wcscat(temp, L" / ");
|
||||
ConvertUInt32ToString(_selectedStatusVector.Size(), temp + wcslen(temp));
|
||||
|
||||
// UString s1 = MyFormatNew(g_App.LangString_N_SELECTED_ITEMS, NumberToString(indices.Size()));
|
||||
// UString s1 = MyFormatNew(IDS_N_SELECTED_ITEMS, NumberToString(indices.Size()));
|
||||
|
||||
@@ -403,82 +403,117 @@ void CPanel::EditPaste()
|
||||
// InvokeSystemCommand("paste");
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct CFolderPidls
|
||||
{
|
||||
LPITEMIDLIST parent;
|
||||
CRecordVector<LPITEMIDLIST> items;
|
||||
|
||||
CFolderPidls(): parent(NULL) {}
|
||||
~CFolderPidls()
|
||||
{
|
||||
FOR_VECTOR (i, items)
|
||||
CoTaskMemFree(items[i]);
|
||||
CoTaskMemFree(parent);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
HRESULT CPanel::CreateShellContextMenu(
|
||||
const CRecordVector<UInt32> &operatedIndices,
|
||||
CMyComPtr<IContextMenu> &systemContextMenu)
|
||||
{
|
||||
systemContextMenu.Release();
|
||||
UString folderPath = GetFsPath();
|
||||
const UString folderPath = GetFsPath();
|
||||
|
||||
CMyComPtr<IShellFolder> desktopFolder;
|
||||
RINOK(::SHGetDesktopFolder(&desktopFolder));
|
||||
if (!desktopFolder)
|
||||
{
|
||||
// ShowMessage("Failed to get Desktop folder.");
|
||||
// ShowMessage("Failed to get Desktop folder");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Separate the file from the folder.
|
||||
|
||||
|
||||
// Get a pidl for the folder the file
|
||||
// is located in.
|
||||
LPITEMIDLIST parentPidl;
|
||||
CFolderPidls pidls;
|
||||
DWORD eaten;
|
||||
|
||||
// if (folderPath.IsEmpty()), then ParseDisplayName returns pidls of "My Computer"
|
||||
RINOK(desktopFolder->ParseDisplayName(
|
||||
GetParent(), 0, (wchar_t *)(const wchar_t *)folderPath,
|
||||
&eaten, &parentPidl, 0));
|
||||
GetParent(), NULL, (wchar_t *)(const wchar_t *)folderPath,
|
||||
&eaten, &pidls.parent, NULL));
|
||||
|
||||
/*
|
||||
STRRET pName;
|
||||
res = desktopFolder->GetDisplayNameOf(pidls.parent, SHGDN_NORMAL, &pName);
|
||||
WCHAR dir[MAX_PATH];
|
||||
if (!SHGetPathFromIDListW(pidls.parent, dir))
|
||||
dir[0] = 0;
|
||||
*/
|
||||
|
||||
if (!pidls.parent)
|
||||
return E_FAIL;
|
||||
|
||||
if (operatedIndices.IsEmpty())
|
||||
{
|
||||
// how to get IContextMenu, if there are no selected files?
|
||||
return E_FAIL;
|
||||
|
||||
/*
|
||||
xp64 :
|
||||
1) we can't use GetUIObjectOf() with (numItems == 0), it throws exception
|
||||
2) we can't use desktopFolder->GetUIObjectOf() with absolute pidls of folder
|
||||
context menu items are different in that case:
|
||||
"Open / Explorer" for folder
|
||||
"Delete" for "My Computer" icon
|
||||
"Preperties" for "System"
|
||||
*/
|
||||
/*
|
||||
parentFolder = desktopFolder;
|
||||
pidls.items.AddInReserved(pidls.parent);
|
||||
pidls.parent = NULL;
|
||||
*/
|
||||
|
||||
// CreateViewObject() doesn't show all context menu items
|
||||
/*
|
||||
HRESULT res = parentFolder->CreateViewObject(
|
||||
GetParent(), IID_IContextMenu, (void**)&systemContextMenu);
|
||||
*/
|
||||
}
|
||||
|
||||
// Get an IShellFolder for the folder
|
||||
// the file is located in.
|
||||
CMyComPtr<IShellFolder> parentFolder;
|
||||
RINOK(desktopFolder->BindToObject(parentPidl,
|
||||
0, IID_IShellFolder, (void**)&parentFolder));
|
||||
RINOK(desktopFolder->BindToObject(pidls.parent,
|
||||
NULL, IID_IShellFolder, (void**)&parentFolder));
|
||||
if (!parentFolder)
|
||||
{
|
||||
// ShowMessage("Invalid file name.");
|
||||
// ShowMessage("Invalid file name");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Get a pidl for the file itself.
|
||||
CRecordVector<LPITEMIDLIST> pidls;
|
||||
pidls.ClearAndReserve(operatedIndices.Size());
|
||||
pidls.items.ClearAndReserve(operatedIndices.Size());
|
||||
FOR_VECTOR (i, operatedIndices)
|
||||
{
|
||||
LPITEMIDLIST pidl;
|
||||
UString fileName = GetItemRelPath2(operatedIndices[i]);
|
||||
const UString fileName = GetItemRelPath2(operatedIndices[i]);
|
||||
RINOK(parentFolder->ParseDisplayName(GetParent(), 0,
|
||||
(wchar_t *)(const wchar_t *)fileName, &eaten, &pidl, 0));
|
||||
pidls.AddInReserved(pidl);
|
||||
(wchar_t *)(const wchar_t *)fileName, &eaten, &pidl, 0));
|
||||
pidls.items.AddInReserved(pidl);
|
||||
}
|
||||
|
||||
// Get IContextMenu for items
|
||||
|
||||
ITEMIDLIST temp;
|
||||
if (pidls.Size() == 0)
|
||||
RINOK(parentFolder->GetUIObjectOf(GetParent(), pidls.items.Size(),
|
||||
(LPCITEMIDLIST *)&pidls.items.Front(), IID_IContextMenu, 0, (void**)&systemContextMenu));
|
||||
|
||||
if (!systemContextMenu)
|
||||
{
|
||||
temp.mkid.cb = 0;
|
||||
/*
|
||||
LPITEMIDLIST pidl;
|
||||
HRESULT result = parentFolder->ParseDisplayName(GetParent(), 0,
|
||||
L"." WSTRING_PATH_SEPARATOR, &eaten, &pidl, 0);
|
||||
if (result != NOERROR)
|
||||
return;
|
||||
*/
|
||||
pidls.Add(&temp);
|
||||
}
|
||||
|
||||
// Get the IContextMenu for the file.
|
||||
CMyComPtr<IContextMenu> cm;
|
||||
RINOK( parentFolder->GetUIObjectOf(GetParent(), pidls.Size(),
|
||||
(LPCITEMIDLIST *)&pidls.Front(), IID_IContextMenu, 0, (void**)&cm));
|
||||
if (!cm)
|
||||
{
|
||||
// ShowMessage("Unable to get context menu interface.");
|
||||
// ShowMessage("Unable to get context menu interface");
|
||||
return E_FAIL;
|
||||
}
|
||||
systemContextMenu = cm;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void CPanel::CreateSystemMenu(HMENU menuSpec,
|
||||
const CRecordVector<UInt32> &operatedIndices,
|
||||
CMyComPtr<IContextMenu> &systemContextMenu)
|
||||
|
||||
@@ -218,6 +218,8 @@ void CPanel::InvertSelection()
|
||||
FOR_VECTOR (i, _selectedStatusVector)
|
||||
if (_selectedStatusVector[i])
|
||||
numSelected++;
|
||||
// 17.02: fixed : now we invert item even, if single item is selected
|
||||
/*
|
||||
if (numSelected == 1)
|
||||
{
|
||||
int focused = _listView.GetFocusedItem();
|
||||
@@ -229,6 +231,7 @@ void CPanel::InvertSelection()
|
||||
_selectedStatusVector[realIndex] = false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
FOR_VECTOR (i, _selectedStatusVector)
|
||||
_selectedStatusVector[i] = !_selectedStatusVector[i];
|
||||
|
||||
@@ -77,8 +77,6 @@ UString CVolSeqName::GetNextName()
|
||||
return UnchangedPart + ChangedPart;
|
||||
}
|
||||
|
||||
static const UInt32 kBufSize = (1 << 20);
|
||||
|
||||
class CThreadSplit: public CProgressThreadVirt
|
||||
{
|
||||
HRESULT ProcessVirt();
|
||||
@@ -89,30 +87,84 @@ public:
|
||||
CRecordVector<UInt64> VolumeSizes;
|
||||
};
|
||||
|
||||
|
||||
class CPreAllocOutFile
|
||||
{
|
||||
UInt64 _preAllocSize;
|
||||
public:
|
||||
NIO::COutFile File;
|
||||
UInt64 Written;
|
||||
|
||||
CPreAllocOutFile(): _preAllocSize(0), Written(0) {}
|
||||
|
||||
~CPreAllocOutFile()
|
||||
{
|
||||
SetCorrectFileLength();
|
||||
}
|
||||
|
||||
void PreAlloc(UInt64 preAllocSize)
|
||||
{
|
||||
_preAllocSize = 0;
|
||||
if (File.SetLength(preAllocSize))
|
||||
_preAllocSize = preAllocSize;
|
||||
File.SeekToBegin();
|
||||
}
|
||||
|
||||
bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw()
|
||||
{
|
||||
bool res = File.Write(data, size, processedSize);
|
||||
Written += processedSize;
|
||||
return res;
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
SetCorrectFileLength();
|
||||
Written = 0;
|
||||
_preAllocSize = 0;
|
||||
File.Close();
|
||||
}
|
||||
|
||||
void SetCorrectFileLength()
|
||||
{
|
||||
if (Written < _preAllocSize)
|
||||
{
|
||||
File.SetLength(Written);
|
||||
_preAllocSize = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static const UInt32 kBufSize = (1 << 20);
|
||||
|
||||
HRESULT CThreadSplit::ProcessVirt()
|
||||
{
|
||||
NIO::CInFile inFile;
|
||||
if (!inFile.Open(FilePath))
|
||||
return GetLastError();
|
||||
NIO::COutFile outFile;
|
||||
CMyBuffer bufferObject;
|
||||
if (!bufferObject.Allocate(kBufSize))
|
||||
|
||||
CPreAllocOutFile outFile;
|
||||
|
||||
CMyBuffer buffer;
|
||||
if (!buffer.Allocate(kBufSize))
|
||||
return E_OUTOFMEMORY;
|
||||
Byte *buffer = (Byte *)(void *)bufferObject;
|
||||
UInt64 curVolSize = 0;
|
||||
|
||||
CVolSeqName seqName;
|
||||
seqName.SetNumDigits(NumVolumes);
|
||||
|
||||
UInt64 length;
|
||||
if (!inFile.GetLength(length))
|
||||
return GetLastError();
|
||||
|
||||
CProgressSync &sync = ProgressDialog.Sync;
|
||||
sync.Set_NumBytesTotal(length);
|
||||
UInt64 pos = 0;
|
||||
|
||||
UInt64 pos = 0;
|
||||
UInt64 prev = 0;
|
||||
UInt64 numFiles = 0;
|
||||
unsigned volIndex = 0;
|
||||
|
||||
|
||||
for (;;)
|
||||
{
|
||||
UInt64 volSize;
|
||||
@@ -121,46 +173,65 @@ HRESULT CThreadSplit::ProcessVirt()
|
||||
else
|
||||
volSize = VolumeSizes.Back();
|
||||
|
||||
UInt32 needSize = (UInt32)(MyMin((UInt64)kBufSize, volSize - curVolSize));
|
||||
UInt32 needSize = kBufSize;
|
||||
{
|
||||
const UInt64 rem = volSize - outFile.Written;
|
||||
if (needSize > rem)
|
||||
needSize = (UInt32)rem;
|
||||
}
|
||||
UInt32 processedSize;
|
||||
if (!inFile.Read(buffer, needSize, processedSize))
|
||||
return GetLastError();
|
||||
if (processedSize == 0)
|
||||
break;
|
||||
return S_OK;
|
||||
needSize = processedSize;
|
||||
if (curVolSize == 0)
|
||||
|
||||
if (outFile.Written == 0)
|
||||
{
|
||||
FString name = VolBasePath;
|
||||
name += '.';
|
||||
name += us2fs(seqName.GetNextName());
|
||||
sync.Set_FilePath(fs2us(name));
|
||||
sync.Set_NumFilesCur(numFiles++);
|
||||
if (!outFile.Create(name, false))
|
||||
if (!outFile.File.Create(name, false))
|
||||
{
|
||||
HRESULT res = GetLastError();
|
||||
AddErrorPath(name);
|
||||
return res;
|
||||
}
|
||||
UInt64 expectSize = volSize;
|
||||
if (pos < length)
|
||||
{
|
||||
const UInt64 rem = length - pos;
|
||||
if (expectSize > rem)
|
||||
expectSize = rem;
|
||||
}
|
||||
outFile.PreAlloc(expectSize);
|
||||
}
|
||||
|
||||
if (!outFile.Write(buffer, needSize, processedSize))
|
||||
return GetLastError();
|
||||
if (needSize != processedSize)
|
||||
throw g_Message_FileWriteError;
|
||||
curVolSize += processedSize;
|
||||
if (curVolSize == volSize)
|
||||
|
||||
pos += processedSize;
|
||||
|
||||
if (outFile.Written == volSize)
|
||||
{
|
||||
outFile.Close();
|
||||
sync.Set_NumFilesCur(++numFiles);
|
||||
if (volIndex < VolumeSizes.Size())
|
||||
volIndex++;
|
||||
curVolSize = 0;
|
||||
}
|
||||
pos += processedSize;
|
||||
RINOK(sync.Set_NumBytesCur(pos));
|
||||
|
||||
if (pos - prev >= ((UInt32)1 << 22) || outFile.Written == 0)
|
||||
{
|
||||
RINOK(sync.Set_NumBytesCur(pos));
|
||||
prev = pos;
|
||||
}
|
||||
}
|
||||
sync.Set_NumFilesCur(numFiles);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void CApp::Split()
|
||||
{
|
||||
int srcPanelIndex = GetFocusedPanelIndex();
|
||||
|
||||
@@ -861,6 +861,7 @@ bool CCompressDialog::OnCommand(int code, int itemID, LPARAM lParam)
|
||||
{
|
||||
bool isSFX = IsSFX();
|
||||
SaveOptionsInMem();
|
||||
m_Solid.ResetContent();
|
||||
SetLevel();
|
||||
SetSolidBlockSize();
|
||||
SetNumThreads();
|
||||
|
||||
@@ -15,11 +15,11 @@ O=O
|
||||
!ENDIF
|
||||
|
||||
!IF "$(CPU)" == "AMD64"
|
||||
MY_ML = ml64 -Dx64
|
||||
MY_ML = ml64 -Dx64 -WX
|
||||
!ELSEIF "$(CPU)" == "ARM"
|
||||
MY_ML = armasm
|
||||
MY_ML = armasm -WX
|
||||
!ELSE
|
||||
MY_ML = ml
|
||||
MY_ML = ml -WX
|
||||
!ENDIF
|
||||
|
||||
|
||||
@@ -32,9 +32,9 @@ LFLAGS = $(LFLAGS) /ENTRY:mainACRTStartup
|
||||
!IFNDEF NEW_COMPILER
|
||||
LFLAGS = $(LFLAGS) -OPT:NOWIN98
|
||||
!ENDIF
|
||||
# !IF "$(CPU)" != "ARM"
|
||||
!IF "$(CPU)" != "ARM" && "$(CPU)" != "ARM64"
|
||||
CFLAGS = $(CFLAGS) -Gr
|
||||
# !ENDIF
|
||||
!ENDIF
|
||||
LIBS = $(LIBS) user32.lib advapi32.lib shell32.lib
|
||||
!ENDIF
|
||||
|
||||
@@ -82,9 +82,9 @@ LFLAGS = $(LFLAGS) /LARGEADDRESSAWARE
|
||||
!IFDEF DEF_FILE
|
||||
LFLAGS = $(LFLAGS) -DLL -DEF:$(DEF_FILE)
|
||||
!ELSE
|
||||
# !IF "$(CPU)" != "ARM"
|
||||
!IF "$(CPU)" != "ARM" && "$(CPU)" != "ARM64"
|
||||
LFLAGS = $(LFLAGS) /FIXED
|
||||
# !ENDIF
|
||||
!ENDIF
|
||||
# /BASE:0x400000
|
||||
!ENDIF
|
||||
|
||||
|
||||
@@ -667,12 +667,27 @@ bool CTempFile::Remove()
|
||||
|
||||
bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore)
|
||||
{
|
||||
// DWORD attrib = 0;
|
||||
if (deleteDestBefore)
|
||||
{
|
||||
if (NFind::DoesFileExist(name))
|
||||
{
|
||||
// attrib = NFind::GetFileAttrib(name);
|
||||
if (!DeleteFileAlways(name))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DisableDeleting();
|
||||
return MyMoveFile(_path, name);
|
||||
|
||||
/*
|
||||
if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY))
|
||||
{
|
||||
DWORD attrib2 = NFind::GetFileAttrib(name);
|
||||
if (attrib2 != INVALID_FILE_ATTRIBUTES)
|
||||
SetFileAttrib(name, attrib2 | FILE_ATTRIBUTE_READONLY);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
bool CTempDir::Create(CFSTR prefix)
|
||||
|
||||
@@ -45,7 +45,11 @@ struct CReparseAttr
|
||||
UString PrintName;
|
||||
|
||||
CReparseAttr(): Tag(0), Flags(0) {}
|
||||
bool Parse(const Byte *p, size_t size);
|
||||
|
||||
// Parse()
|
||||
// returns true and (errorCode = 0), if (correct MOUNT_POINT or SYMLINK)
|
||||
// returns false and (errorCode = ERROR_REPARSE_TAG_MISMATCH), if not (MOUNT_POINT or SYMLINK)
|
||||
bool Parse(const Byte *p, size_t size, DWORD &errorCode);
|
||||
|
||||
bool IsMountPoint() const { return Tag == _my_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction
|
||||
bool IsSymLink() const { return Tag == _my_IO_REPARSE_TAG_SYMLINK; }
|
||||
@@ -171,7 +175,12 @@ public:
|
||||
|
||||
bool OpenReparse(CFSTR fileName)
|
||||
{
|
||||
return Open(fileName, FILE_SHARE_READ, OPEN_EXISTING,
|
||||
// 17.02 fix: to support Windows XP compatibility junctions:
|
||||
// we use Create() with (desiredAccess = 0) instead of Open() with GENERIC_READ
|
||||
return
|
||||
Create(fileName, 0,
|
||||
// Open(fileName,
|
||||
FILE_SHARE_READ, OPEN_EXISTING,
|
||||
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS);
|
||||
}
|
||||
|
||||
|
||||
@@ -194,8 +194,9 @@ static void GetString(const Byte *p, unsigned len, UString &res)
|
||||
res.ReleaseBuf_SetLen(i);
|
||||
}
|
||||
|
||||
bool CReparseAttr::Parse(const Byte *p, size_t size)
|
||||
bool CReparseAttr::Parse(const Byte *p, size_t size, DWORD &errorCode)
|
||||
{
|
||||
errorCode = ERROR_INVALID_REPARSE_DATA;
|
||||
if (size < 8)
|
||||
return false;
|
||||
Tag = Get32(p);
|
||||
@@ -209,8 +210,10 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
|
||||
*/
|
||||
if (Tag != _my_IO_REPARSE_TAG_MOUNT_POINT &&
|
||||
Tag != _my_IO_REPARSE_TAG_SYMLINK)
|
||||
// return true;
|
||||
{
|
||||
errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Get16(p + 6) != 0) // padding
|
||||
return false;
|
||||
@@ -247,6 +250,7 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
|
||||
GetString(p + subOffs, subLen >> 1, SubsName);
|
||||
GetString(p + printOffs, printLen >> 1, PrintName);
|
||||
|
||||
errorCode = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ AppName = "7-Zip"
|
||||
InstallDir = %CE1%\%AppName%
|
||||
|
||||
[Strings]
|
||||
AppVer = "17.01"
|
||||
AppDate = "2017-08-28"
|
||||
AppVer = "18.01"
|
||||
AppDate = "2018-01-28"
|
||||
|
||||
[CEDevice]
|
||||
; ProcessorType = 2577 ; ARM
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;--------------------------------
|
||||
;Defines
|
||||
|
||||
!define VERSION_MAJOR 17
|
||||
!define VERSION_MAJOR 18
|
||||
!define VERSION_MINOR 01
|
||||
!define VERSION_POSTFIX_FULL " beta"
|
||||
!define VERSION_POSTFIX_FULL ""
|
||||
!ifdef WIN64
|
||||
!ifdef IA64
|
||||
!define VERSION_SYS_POSTFIX_FULL " for Windows IA-64"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<?define VerMajor = "17" ?>
|
||||
<?define VerMajor = "18" ?>
|
||||
<?define VerMinor = "01" ?>
|
||||
<?define VerBuild = "00" ?>
|
||||
<?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?>
|
||||
|
||||
@@ -3,15 +3,20 @@
|
||||
License for use and distribution
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
7-Zip Copyright (C) 1999-2017 Igor Pavlov.
|
||||
7-Zip Copyright (C) 1999-2018 Igor Pavlov.
|
||||
|
||||
Licenses for files are:
|
||||
The licenses for files are:
|
||||
|
||||
1) CPP/7zip/Compress/Rar* files: the "GNU LGPL" with "unRAR license restriction"
|
||||
2) CPP/7zip/Compress/LzfseDecoder.cpp: the "BSD 3-clause License"
|
||||
3) Some files are "public domain" files, if "public domain" status is stated in source file.
|
||||
4) the "GNU LGPL" for all other files. If there is no license information in
|
||||
some source file, that file is under the "GNU LGPL".
|
||||
|
||||
The "GNU LGPL" with "unRAR license restriction" means that you must follow both
|
||||
"GNU LGPL" rules and "unRAR license restriction" rules.
|
||||
|
||||
1) CPP/7zip/Compress/Rar* files: GNU LGPL + unRAR restriction
|
||||
2) All other files: GNU LGPL
|
||||
|
||||
The GNU LGPL + unRAR restriction means that you must follow both
|
||||
GNU LGPL rules and unRAR restriction rules.
|
||||
|
||||
|
||||
GNU LGPL information
|
||||
@@ -32,8 +37,41 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
unRAR restriction
|
||||
-----------------
|
||||
|
||||
|
||||
BSD 3-clause License
|
||||
--------------------
|
||||
|
||||
The "BSD 3-clause License" is used for the code in LzfseDecoder.cpp that implements LZFSE data decompression.
|
||||
That code was derived from the code in the "LZFSE compression library" developed by Apple Inc,
|
||||
that also uses the "BSD 3-clause License":
|
||||
|
||||
----
|
||||
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
----
|
||||
|
||||
|
||||
|
||||
|
||||
unRAR license restriction
|
||||
-------------------------
|
||||
|
||||
The decompression engine for RAR archives was developed using source
|
||||
code of unRAR program.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
7-Zip 17.00 beta Sources
|
||||
------------------------
|
||||
7-Zip 18.01 Sources
|
||||
-------------------
|
||||
|
||||
7-Zip is a file archiver for Windows.
|
||||
|
||||
7-Zip Copyright (C) 1999-2017 Igor Pavlov.
|
||||
7-Zip Copyright (C) 1999-2018 Igor Pavlov.
|
||||
|
||||
|
||||
License Info
|
||||
|
||||
Reference in New Issue
Block a user