This commit is contained in:
Igor Pavlov
2018-01-30 00:15:34 +00:00
committed by Kornel
parent da28077952
commit 866a06f5a0
30 changed files with 1413 additions and 119 deletions

View File

@@ -1,7 +1,7 @@
#define MY_VER_MAJOR 18
#define MY_VER_MINOR 00
#define MY_VER_MINOR 01
#define MY_VER_BUILD 0
#define MY_VERSION_NUMBERS "18.00 beta"
#define MY_VERSION_NUMBERS "18.01"
#define MY_VERSION MY_VERSION_NUMBERS
#ifdef MY_CPU_NAME
@@ -10,7 +10,7 @@
#define MY_VERSION_CPU MY_VERSION
#endif
#define MY_DATE "2018-01-10"
#define MY_DATE "2018-01-28"
#undef MY_COPYRIGHT
#undef MY_VERSION_COPYRIGHT_DATE
#define MY_AUTHOR_NAME "Igor Pavlov"

View File

@@ -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);

View File

@@ -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:

View File

@@ -387,6 +387,10 @@ void CSection::Parse(const Byte *p)
G32(36, Flags);
}
// IMAGE_FILE_*
static const CUInt32PCharPair g_HeaderCharacts[] =
{
{ 1, "Executable" },
@@ -406,9 +410,7 @@ static const CUInt32PCharPair g_HeaderCharacts[] =
{ 15, "Big-Endian" }
};
// IMAGE_DLLCHARACTERISTICS_* constants
// IMAGE_DLLCHARACTERISTICS_*
static const char * const g_DllCharacts[] =
{
@@ -930,7 +932,9 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidExtension:
if (_header.IsDll())
prop = _optHeader.IsSybSystem_EFI() ? "efi" : "dll";
prop = "dll";
else if (_optHeader.IsSybSystem_EFI())
prop = "efi";
break;
case kpidBit64: if (_optHeader.Is64Bit()) prop = true; break;
@@ -1137,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;
@@ -2191,6 +2204,9 @@ bool CHeader::ParseCoff(const Byte *p)
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;
}

View File

@@ -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));

View File

@@ -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;

View File

@@ -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(); }

View File

@@ -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" },

View File

@@ -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; }

View File

@@ -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
}

View File

@@ -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(

View File

@@ -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 \

View File

@@ -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

View File

@@ -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)

View File

@@ -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
{

View 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; }
}
}}

View 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

View File

@@ -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];
@@ -1564,6 +1569,7 @@ STDMETHODIMP CAgent::Open(
{
COM_TRY_BEGIN
_archiveFilePath = filePath;
_attrib = 0;
NFile::NFind::CFileInfo fi;
_isDeviceFile = false;
if (!inStream)
@@ -1572,6 +1578,7 @@ STDMETHODIMP CAgent::Open(
return ::GetLastError();
if (fi.IsDir())
return E_FAIL;
_attrib = fi.Attrib;
_isDeviceFile = fi.IsDevice;
}
CArcInfoEx archiverInfo0, archiverInfo1;

View File

@@ -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)

View File

@@ -372,6 +372,8 @@ void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPat
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)
@@ -1032,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();
}
}
}
@@ -1602,75 +1626,53 @@ 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()
{
if (!_arc)
return S_OK;
CRecordVector<CExtrRefSortPair> pairs;
pairs.ClearAndSetSize(_extractedFolderPaths.Size());
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++)
{
unsigned pairIndex = pairs[i].Index;
UInt32 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();

View File

@@ -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,8 +260,7 @@ 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;
@@ -348,8 +366,7 @@ public:
private:
void ClearExtractedDirsInfo()
{
_extractedFolderPaths.Clear();
_extractedFolderIndices.Clear();
_extractedFolders.Clear();
}
HRESULT CloseFile();

View File

@@ -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)

View File

@@ -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

View File

@@ -1046,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
@@ -1190,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));
@@ -1510,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)))
{
@@ -1520,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(...)
{
@@ -1609,7 +1606,7 @@ HRESULT UpdateArchive(
if (options.DeleteAfterCompressing)
{
CRecordVector<CRefSortPair> pairs;
CRecordVector<CDirPathSortPair> pairs;
FStringVector foldersNames;
unsigned i;
@@ -1617,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
@@ -1655,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));

View File

@@ -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)

View File

@@ -10,8 +10,8 @@ AppName = "7-Zip"
InstallDir = %CE1%\%AppName%
[Strings]
AppVer = "18.00"
AppDate = "2018-01-10"
AppVer = "18.01"
AppDate = "2018-01-28"
[CEDevice]
; ProcessorType = 2577 ; ARM

View File

@@ -2,8 +2,8 @@
;Defines
!define VERSION_MAJOR 18
!define VERSION_MINOR 00
!define VERSION_POSTFIX_FULL " beta"
!define VERSION_MINOR 01
!define VERSION_POSTFIX_FULL ""
!ifdef WIN64
!ifdef IA64
!define VERSION_SYS_POSTFIX_FULL " for Windows IA-64"

View File

@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<?define VerMajor = "18" ?>
<?define VerMinor = "00" ?>
<?define VerMinor = "01" ?>
<?define VerBuild = "00" ?>
<?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?>
<?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?>

View File

@@ -5,13 +5,18 @@
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.

View File

@@ -1,5 +1,5 @@
7-Zip 18.00 beta Sources
------------------------
7-Zip 18.01 Sources
-------------------
7-Zip is a file archiver for Windows.