This commit is contained in:
Igor Pavlov
2015-09-22 00:00:00 +00:00
committed by Kornel Lesiński
parent cba375916f
commit f6444c3256
96 changed files with 7301 additions and 2409 deletions

View File

@@ -1,9 +1,9 @@
#define MY_VER_MAJOR 15
#define MY_VER_MINOR 06
#define MY_VER_MINOR 07
#define MY_VER_BUILD 00
#define MY_VERSION_NUMBERS "15.06"
#define MY_VERSION "15.06 beta"
#define MY_DATE "2015-08-09"
#define MY_VERSION_NUMBERS "15.07"
#define MY_VERSION "15.07 beta"
#define MY_DATE "2015-09-17"
#undef MY_COPYRIGHT
#undef MY_VERSION_COPYRIGHT_DATE
#define MY_AUTHOR_NAME "Igor Pavlov"

View File

@@ -1,5 +1,5 @@
/* Lzma2Enc.c -- LZMA2 Encoder
2012-06-19 : Igor Pavlov : Public domain */
2015-09-16 : Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -109,6 +109,7 @@ static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf,
{
size_t destPos = 0;
PRF(printf("################# COPY "));
while (unpackSize > 0)
{
UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE;
@@ -121,6 +122,7 @@ static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf,
unpackSize -= u;
destPos += u;
p->srcPos += u;
if (outStream)
{
*packSizeRes += destPos;
@@ -132,9 +134,11 @@ static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf,
*packSizeRes = destPos;
/* needInitState = True; */
}
LzmaEnc_RestoreState(p->enc);
return SZ_OK;
}
{
size_t destPos = 0;
UInt32 u = unpackSize - 1;
@@ -160,11 +164,13 @@ static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf,
if (outStream)
if (outStream->Write(outStream, outBuf, destPos) != destPos)
return SZ_ERROR_WRITE;
*packSizeRes = destPos;
return SZ_OK;
}
}
/* ---------- Lzma2 Props ---------- */
void Lzma2EncProps_Init(CLzma2EncProps *p)
@@ -221,6 +227,8 @@ void Lzma2EncProps_Normalize(CLzma2EncProps *p)
LzmaEncProps_Normalize(&p->lzmaProps);
t1 = p->lzmaProps.numThreads;
if (p->blockSize == 0)
{
UInt32 dictSize = p->lzmaProps.dictSize;
@@ -232,7 +240,8 @@ void Lzma2EncProps_Normalize(CLzma2EncProps *p)
if (blockSize < dictSize) blockSize = dictSize;
p->blockSize = (size_t)blockSize;
}
if (t2 > 1)
if (t2 > 1 && p->lzmaProps.reduceSize != (UInt64)(Int64)-1)
{
UInt64 temp = p->lzmaProps.reduceSize + p->blockSize - 1;
if (temp > p->lzmaProps.reduceSize)
@@ -241,19 +250,24 @@ void Lzma2EncProps_Normalize(CLzma2EncProps *p)
if (numBlocks < (unsigned)t2)
{
t2 = (unsigned)numBlocks;
if (t2 == 0)
t2 = 1;
t3 = t1 * t2;
}
}
}
p->numBlockThreads = t2;
p->numTotalThreads = t3;
}
static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize)
{
return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK;
}
/* ---------- Lzma2 ---------- */
typedef struct
@@ -283,15 +297,17 @@ static SRes Lzma2Enc_EncodeMt1(CLzma2EncInt *p, CLzma2Enc *mainEncoder,
UInt64 packTotal = 0;
SRes res = SZ_OK;
if (mainEncoder->outBuf == 0)
if (!mainEncoder->outBuf)
{
mainEncoder->outBuf = (Byte *)IAlloc_Alloc(mainEncoder->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX);
if (mainEncoder->outBuf == 0)
if (!mainEncoder->outBuf)
return SZ_ERROR_MEM;
}
RINOK(Lzma2EncInt_Init(p, &mainEncoder->props));
RINOK(LzmaEnc_PrepareForLzma2(p->enc, inStream, LZMA2_KEEP_WINDOW_SIZE,
mainEncoder->alloc, mainEncoder->allocBig));
for (;;)
{
size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX;
@@ -305,16 +321,20 @@ static SRes Lzma2Enc_EncodeMt1(CLzma2EncInt *p, CLzma2Enc *mainEncoder,
if (packSize == 0)
break;
}
LzmaEnc_Finish(p->enc);
if (res == SZ_OK)
{
Byte b = 0;
if (outStream->Write(outStream, &b, 1) != 1)
return SZ_ERROR_WRITE;
}
return res;
}
#ifndef _7ZIP_ST
typedef struct
@@ -362,10 +382,12 @@ static SRes MtCallbackImp_Code(void *pp, unsigned index, Byte *dest, size_t *des
break;
}
}
LzmaEnc_Finish(p->enc);
if (res != SZ_OK)
return res;
}
if (finished)
{
if (*destSize == destLim)
@@ -378,12 +400,13 @@ static SRes MtCallbackImp_Code(void *pp, unsigned index, Byte *dest, size_t *des
#endif
/* ---------- Lzma2Enc ---------- */
CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig)
{
CLzma2Enc *p = (CLzma2Enc *)alloc->Alloc(alloc, sizeof(CLzma2Enc));
if (p == 0)
if (!p)
return NULL;
Lzma2EncProps_Init(&p->props);
Lzma2EncProps_Normalize(&p->props);
@@ -395,6 +418,7 @@ CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig)
for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
p->coders[i].enc = 0;
}
#ifndef _7ZIP_ST
MtCoder_Construct(&p->mtCoder);
#endif
@@ -456,10 +480,10 @@ SRes Lzma2Enc_Encode(CLzma2EncHandle pp,
for (i = 0; i < p->props.numBlockThreads; i++)
{
CLzma2EncInt *t = &p->coders[i];
if (t->enc == NULL)
if (!t->enc)
{
t->enc = LzmaEnc_Create(p->alloc);
if (t->enc == NULL)
if (!t->enc)
return SZ_ERROR_MEM;
}
}
@@ -470,7 +494,6 @@ SRes Lzma2Enc_Encode(CLzma2EncHandle pp,
return Lzma2Enc_EncodeMt1(&p->coders[0], p, outStream, inStream, progress);
#ifndef _7ZIP_ST
{
CMtCallbackImp mtCallback;

View File

@@ -4,7 +4,7 @@ This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
#include "Precomp.h"
#include <memory.h>
#include <string.h>
#include "Ppmd7.h"

View File

@@ -4,7 +4,7 @@ This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */
#include "Precomp.h"
#include <memory.h>
#include <string.h>
#include "Ppmd8.h"

View File

@@ -1,6 +1,6 @@
#define IDD_INSTALL 100
#define IDD_INSTALL 100
#define IDT_EXTRACT_EXTRACT_TO 110
#define IDT_EXTRACT_EXTRACT_TO 110
#define IDE_EXTRACT_PATH 111
#define IDB_EXTRACT_SET_PATH 112
#define IDT_CUR_FILE 113

View File

@@ -1,6 +1,6 @@
#define IDD_INSTALL 100
#define IDD_INSTALL 100
#define IDT_EXTRACT_EXTRACT_TO 110
#define IDT_EXTRACT_EXTRACT_TO 110
#define IDE_EXTRACT_PATH 111
#define IDT_CUR_FILE 113

View File

@@ -1,5 +1,5 @@
/* XzEnc.c -- Xz Encode
2015-05-01 : Igor Pavlov : Public domain */
2015-09-16 : Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -10,6 +10,7 @@
#include "Alloc.h"
#include "Bra.h"
#include "CpuArch.h"
#ifdef USE_SUBBLOCK
#include "Bcj3Enc.c"
#include "SbFind.c"
@@ -34,7 +35,7 @@ static SRes WriteBytesAndCrc(ISeqOutStream *s, const void *buf, UInt32 size, UIn
return WriteBytes(s, buf, size);
}
SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s)
static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s)
{
UInt32 crc;
Byte header[XZ_STREAM_HEADER_SIZE];
@@ -46,7 +47,8 @@ SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s)
return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE);
}
SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s)
static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s)
{
Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
@@ -75,7 +77,8 @@ SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s)
return WriteBytes(s, header, pos + 4);
}
SRes Xz_WriteFooter(CXzStream *p, ISeqOutStream *s)
static SRes Xz_WriteFooter(CXzStream *p, ISeqOutStream *s)
{
Byte buf[32];
UInt64 globalPos;
@@ -87,6 +90,7 @@ SRes Xz_WriteFooter(CXzStream *p, ISeqOutStream *s)
globalPos = pos;
buf[0] = 0;
RINOK(WriteBytesAndCrc(s, buf, pos, &crc));
for (i = 0; i < p->numBlocks; i++)
{
const CXzBlockSizes *block = &p->blocks[i];
@@ -95,7 +99,9 @@ SRes Xz_WriteFooter(CXzStream *p, ISeqOutStream *s)
globalPos += pos;
RINOK(WriteBytesAndCrc(s, buf, pos, &crc));
}
pos = ((unsigned)globalPos & 3);
if (pos != 0)
{
buf[0] = buf[1] = buf[2] = 0;
@@ -120,34 +126,36 @@ SRes Xz_WriteFooter(CXzStream *p, ISeqOutStream *s)
}
}
SRes Xz_AddIndexRecord(CXzStream *p, UInt64 unpackSize, UInt64 totalSize, ISzAlloc *alloc)
static SRes Xz_AddIndexRecord(CXzStream *p, UInt64 unpackSize, UInt64 totalSize, ISzAlloc *alloc)
{
if (p->blocks == 0 || p->numBlocksAllocated == p->numBlocks)
if (!p->blocks || p->numBlocksAllocated == p->numBlocks)
{
size_t num = (p->numBlocks + 1) * 2;
size_t num = p->numBlocks * 2 + 1;
size_t newSize = sizeof(CXzBlockSizes) * num;
CXzBlockSizes *blocks;
if (newSize / sizeof(CXzBlockSizes) != num)
return SZ_ERROR_MEM;
blocks = (CXzBlockSizes *)alloc->Alloc(alloc, newSize);
if (blocks == 0)
if (!blocks)
return SZ_ERROR_MEM;
if (p->numBlocks != 0)
{
memcpy(blocks, p->blocks, p->numBlocks * sizeof(CXzBlockSizes));
Xz_Free(p, alloc);
alloc->Free(alloc, p->blocks);
}
p->blocks = blocks;
p->numBlocksAllocated = num;
}
{
CXzBlockSizes *block = &p->blocks[p->numBlocks++];
block->totalSize = totalSize;
block->unpackSize = unpackSize;
block->totalSize = totalSize;
}
return SZ_OK;
}
/* ---------- CSeqCheckInStream ---------- */
typedef struct
@@ -178,6 +186,7 @@ static SRes SeqCheckInStream_Read(void *pp, void *data, size_t *size)
return res;
}
/* ---------- CSeqSizeOutStream ---------- */
typedef struct
@@ -195,6 +204,7 @@ static size_t MyWrite(void *pp, const void *data, size_t size)
return size;
}
/* ---------- CSeqInFilter ---------- */
#define FILTER_BUF_SIZE (1 << 20)
@@ -217,6 +227,7 @@ static SRes SeqInFilter_Read(void *pp, void *data, size_t *size)
if (sizeOriginal == 0)
return SZ_OK;
*size = 0;
for (;;)
{
if (!p->srcWasFinished && p->curPos == p->endPos)
@@ -274,6 +285,7 @@ static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props)
return SZ_OK;
}
/* ---------- CSbEncInStream ---------- */
#ifdef USE_SUBBLOCK
@@ -291,6 +303,7 @@ static SRes SbEncInStream_Read(void *pp, void *data, size_t *size)
size_t sizeOriginal = *size;
if (sizeOriginal == 0)
return S_OK;
for (;;)
{
if (p->enc.needRead && !p->enc.readWasFinished)
@@ -305,6 +318,7 @@ static SRes SbEncInStream_Read(void *pp, void *data, size_t *size)
}
p->enc.needRead = False;
}
*size = sizeOriginal;
RINOK(SbEnc_Read(&p->enc, data, size));
if (*size != 0 || !p->enc.needRead)
@@ -357,7 +371,7 @@ static void Lzma2WithFilters_Construct(CLzma2WithFilters *p, ISzAlloc *alloc, IS
static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p)
{
p->lzma2 = Lzma2Enc_Create(p->alloc, p->bigAlloc);
if (p->lzma2 == 0)
if (!p->lzma2)
return SZ_ERROR_MEM;
return SZ_OK;
}
@@ -375,10 +389,11 @@ static void Lzma2WithFilters_Free(CLzma2WithFilters *p)
}
}
void XzProps_Init(CXzProps *p)
{
p->lzma2Props = 0;
p->filterProps = 0;
p->lzma2Props = NULL;
p->filterProps = NULL;
p->checkId = XZ_CHECK_CRC32;
}
@@ -386,10 +401,11 @@ void XzFilterProps_Init(CXzFilterProps *p)
{
p->id = 0;
p->delta = 0;
p->ip= 0;
p->ip = 0;
p->ipDefined = False;
}
static SRes Xz_Compress(CXzStream *xz, CLzma2WithFilters *lzmaf,
ISeqOutStream *outStream, ISeqInStream *inStream,
const CXzProps *props, ICompressProgress *progress)
@@ -415,6 +431,7 @@ static SRes Xz_Compress(CXzStream *xz, CLzma2WithFilters *lzmaf,
filter = &block.filters[filterIndex++];
filter->id = fp->id;
filter->propsSize = 0;
if (fp->id == XZ_ID_Delta)
{
filter->props[0] = (Byte)(fp->delta - 1);
@@ -462,14 +479,16 @@ static SRes Xz_Compress(CXzStream *xz, CLzma2WithFilters *lzmaf,
{
UInt64 packPos = seqSizeOutStream.processed;
SRes res = Lzma2Enc_Encode(lzmaf->lzma2, &seqSizeOutStream.p,
fp ?
#ifdef USE_SUBBLOCK
(fp->id == XZ_ID_Subblock) ? &lzmaf->sb.p:
#endif
&lzmaf->filter.p:
&checkInStream.p,
progress);
fp ?
#ifdef USE_SUBBLOCK
(fp->id == XZ_ID_Subblock) ? &lzmaf->sb.p:
#endif
&lzmaf->filter.p:
&checkInStream.p,
progress);
RINOK(res);
block.unpackSize = checkInStream.processed;
block.packSize = seqSizeOutStream.processed - packPos;
@@ -478,7 +497,7 @@ static SRes Xz_Compress(CXzStream *xz, CLzma2WithFilters *lzmaf,
{
unsigned padSize = 0;
Byte buf[128];
while((((unsigned)block.packSize + padSize) & 3) != 0)
while ((((unsigned)block.packSize + padSize) & 3) != 0)
buf[padSize++] = 0;
SeqCheckInStream_GetDigest(&checkInStream, buf + padSize);
RINOK(WriteBytes(&seqSizeOutStream.p, buf, padSize + XzFlags_GetCheckSize(xz->flags)));
@@ -488,6 +507,7 @@ static SRes Xz_Compress(CXzStream *xz, CLzma2WithFilters *lzmaf,
return Xz_WriteFooter(xz, outStream);
}
SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,
const CXzProps *props, ICompressProgress *progress)
{
@@ -504,6 +524,7 @@ SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,
return res;
}
SRes Xz_EncodeEmpty(ISeqOutStream *outStream)
{
SRes res;

View File

@@ -282,7 +282,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
bool need_CTime = (Write_CTime.Def && Write_CTime.Val);
bool need_ATime = (Write_ATime.Def && Write_ATime.Val);
bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def);
if (db)
if (db && !db->Files.IsEmpty())
{
if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();

View File

@@ -118,11 +118,11 @@ static int Parse_EXE(const Byte *buf, size_t size, CFilterMode *filterMode)
#define ELF_SIG 0x464C457F
#define ELF_CLASS_32 1
#define ELF_CLASS_64 2
#define ELF_CLASS_32 1
#define ELF_CLASS_64 2
#define ELF_DATA_2LSB 1
#define ELF_DATA_2MSB 2
#define ELF_DATA_2LSB 1
#define ELF_DATA_2MSB 2
static UInt16 Get16(const Byte *p, Bool be) { if (be) return (UInt16)GetBe16(p); return (UInt16)GetUi16(p); }
static UInt32 Get32(const Byte *p, Bool be) { if (be) return GetBe32(p); return GetUi32(p); }

View File

@@ -7,16 +7,13 @@
#include "../../Common/ComTry.h"
#include "../../Common/Defs.h"
#include "../../Common/IntToString.h"
#include "../../Common/MyString.h"
#include "../../Windows/PropVariant.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamUtils.h"
#include "../Compress/CopyCoder.h"
#include "HandlerCont.h"
#define Get16(p) GetBe16(p)
#define Get32(p) GetBe32(p)
@@ -75,13 +72,9 @@ struct CItem
}
};
class CHandler:
public IInArchive,
public IInArchiveGetStream,
public CMyUnknownImp
class CHandler: public CHandlerCont
{
CRecordVector<CItem> _items;
CMyComPtr<IInStream> _stream;
unsigned _blockSizeLog;
UInt32 _numBlocks;
UInt64 _phySize;
@@ -89,11 +82,11 @@ class CHandler:
HRESULT ReadTables(IInStream *stream);
UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; }
UInt64 GetItemSize(const CItem &item) const { return BlocksToBytes(item.NumBlocks); }
virtual UInt64 GetItemPos(UInt32 index) const { return BlocksToBytes(_items[index].StartBlock); }
virtual UInt64 GetItemSize(UInt32 index) const { return BlocksToBytes(_items[index].NumBlocks); }
public:
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
INTERFACE_IInArchive_Cont(;)
};
static const UInt32 kSectorSize = 512;
@@ -300,7 +293,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
}
case kpidSize:
case kpidPackSize:
prop = GetItemSize(item);
prop = BlocksToBytes(item.NumBlocks);
break;
case kpidOffset: prop = BlocksToBytes(item.StartBlock); break;
}
@@ -309,73 +302,6 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
COM_TRY_END
}
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items.Size();
if (numItems == 0)
return S_OK;
UInt64 totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
totalSize += GetItemSize(_items[allFilesMode ? i : indices[i]]);
extractCallback->SetTotal(totalSize);
totalSize = 0;
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
CMyComPtr<ISequentialInStream> inStream(streamSpec);
streamSpec->SetStream(_stream);
for (i = 0; i < numItems; i++)
{
lps->InSize = totalSize;
lps->OutSize = totalSize;
RINOK(lps->SetCur());
CMyComPtr<ISequentialOutStream> outStream;
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
Int32 index = allFilesMode ? i : indices[i];
const CItem &item = _items[index];
RINOK(extractCallback->GetStream(index, &outStream, askMode));
UInt64 size = GetItemSize(item);
totalSize += size;
if (!testMode && !outStream)
continue;
RINOK(extractCallback->PrepareOperation(askMode));
RINOK(_stream->Seek(BlocksToBytes(item.StartBlock), STREAM_SEEK_SET, NULL));
streamSpec->Init(size);
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
outStream.Release();
RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == size ?
NExtract::NOperationResult::kOK:
NExtract::NOperationResult::kDataError));
}
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
{
COM_TRY_BEGIN
const CItem &item = _items[index];
return CreateLimitedInStream(_stream, BlocksToBytes(item.StartBlock), GetItemSize(item), stream);
COM_TRY_END
}
static const Byte k_Signature[] = { kSig0, kSig1 };
REGISTER_ARC_I(

View File

@@ -29,15 +29,24 @@ CCabBlockInStream::~CCabBlockInStream()
static UInt32 CheckSum(const Byte *p, UInt32 size)
{
UInt32 sum = 0;
for (UInt32 i = size >> 2; i != 0; i--)
for (; size >= 8; size -= 8)
{
sum ^= GetUi32(p) ^ GetUi32(p + 4);
p += 8;
}
if (size >= 4)
{
sum ^= GetUi32(p);
p += 4;
}
size &= 3;
if (size > 2) sum ^= (UInt32)(*p++) << 16;
if (size > 1) sum ^= (UInt32)(*p++) << 8;
if (size > 0) sum ^= (UInt32)(*p++);
return sum;
}

View File

@@ -25,10 +25,16 @@ public:
CCabBlockInStream(): _buf(0), ReservedSize(0), MsZip(false) {}
~CCabBlockInStream();
bool Create();
void InitForNewBlock() { _size = 0; _pos = 0; }
HRESULT PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize);
UInt32 GetPackSizeAvail() const { return _size - _pos; }
const Byte *GetData() const { return _buf + _pos; }
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
};

View File

@@ -569,13 +569,14 @@ public:
UInt64 folderSize,
IArchiveExtractCallback *extractCallback,
bool testMode);
HRESULT FlushCorrupted();
HRESULT FlushCorrupted(unsigned folderIndex);
HRESULT Unsupported();
UInt64 GetRemain() const { return m_FolderSize - m_PosInFolder; }
UInt64 GetPosInFolder() const { return m_PosInFolder; }
};
void CFolderOutStream::Init(
const CMvDatabaseEx *database,
const CRecordVector<bool> *extractStatuses,
@@ -600,6 +601,7 @@ void CFolderOutStream::Init(
NumIdenticalFiles = 0;
}
HRESULT CFolderOutStream::CloseFileWithResOp(Int32 resOp)
{
m_RealOutStream.Release();
@@ -608,6 +610,7 @@ HRESULT CFolderOutStream::CloseFileWithResOp(Int32 resOp)
return m_ExtractCallback->SetOperationResult(resOp);
}
HRESULT CFolderOutStream::CloseFile()
{
return CloseFileWithResOp(m_IsOk ?
@@ -615,6 +618,7 @@ HRESULT CFolderOutStream::CloseFile()
NExtract::NOperationResult::kDataError);
}
HRESULT CFolderOutStream::OpenFile()
{
if (NumIdenticalFiles == 0)
@@ -680,6 +684,7 @@ HRESULT CFolderOutStream::OpenFile()
return m_ExtractCallback->PrepareOperation(askMode);
}
HRESULT CFolderOutStream::WriteEmptyFiles()
{
if (m_FileIsOpen)
@@ -699,13 +704,15 @@ HRESULT CFolderOutStream::WriteEmptyFiles()
return S_OK;
}
// This is Write function
HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK)
{
COM_TRY_BEGIN
UInt32 realProcessed = 0;
if (processedSize)
*processedSize = 0;
while (size != 0)
{
if (m_FileIsOpen)
@@ -732,8 +739,10 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe
size -= numBytesToWrite;
m_RemainFileSize -= numBytesToWrite;
m_PosInFolder += numBytesToWrite;
if (res != S_OK)
return res;
if (m_RemainFileSize == 0)
{
RINOK(CloseFile());
@@ -754,17 +763,27 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe
{
RINOK(CloseFile());
}
RINOK(result);
}
TempBufMode = false;
}
if (realProcessed > 0)
break; // with this break this function works as Write-Part
}
else
{
if (m_CurrentIndex >= m_ExtractStatuses->Size())
return E_FAIL;
{
// we ignore extra data;
realProcessed += size;
if (processedSize)
*processedSize = realProcessed;
return S_OK;
// return E_FAIL;
}
const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
@@ -772,8 +791,10 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe
m_RemainFileSize = item.Size;
UInt32 fileOffset = item.Offset;
if (fileOffset < m_PosInFolder)
return E_FAIL;
if (fileOffset > m_PosInFolder)
{
UInt32 numBytesToWrite = MyMin(fileOffset - (UInt32)m_PosInFolder, size);
@@ -784,6 +805,7 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe
size -= numBytesToWrite;
m_PosInFolder += numBytesToWrite;
}
if (fileOffset == m_PosInFolder)
{
RINOK(OpenFile());
@@ -793,21 +815,39 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe
}
}
}
return WriteEmptyFiles();
COM_TRY_END
}
STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
{
return Write2(data, size, processedSize, true);
}
HRESULT CFolderOutStream::FlushCorrupted()
HRESULT CFolderOutStream::FlushCorrupted(unsigned folderIndex)
{
UInt64 remain = GetRemain();
if (remain == 0)
{
CMyComPtr<IArchiveExtractCallbackMessage> callbackMessage;
m_ExtractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage, &callbackMessage);
if (callbackMessage)
{
RINOK(callbackMessage->ReportExtractResult(NEventIndexType::kBlockIndex, folderIndex, NExtract::NOperationResult::kDataError));
}
return S_OK;
}
const unsigned kBufSize = (1 << 10);
Byte buf[kBufSize];
for (unsigned i = 0; i < kBufSize; i++)
buf[i] = 0;
for (;;)
{
UInt64 remain = GetRemain();
@@ -819,6 +859,7 @@ HRESULT CFolderOutStream::FlushCorrupted()
}
}
HRESULT CFolderOutStream::Unsupported()
{
while (m_CurrentIndex < m_ExtractStatuses->Size())
@@ -838,6 +879,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = m_Database.Items.Size();
@@ -883,10 +925,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ICompressCoder> deflateDecoder;
NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL;
CMyComPtr<ICompressCoder> lzxDecoder;
CMyComPtr<IUnknown> lzxDecoder;
NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL;
CMyComPtr<ICompressCoder> quantumDecoder;
CMyComPtr<IUnknown> quantumDecoder;
CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream();
CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec;
@@ -968,7 +1010,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CFolderOutStream *cabFolderOutStream = new CFolderOutStream;
CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream);
const CFolder &folder = db.Folders[item.GetFolderIndex(db.Folders.Size())];
unsigned folderIndex2 = item.GetFolderIndex(db.Folders.Size());
const CFolder &folder = db.Folders[folderIndex2];
cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2,
curUnpack, extractCallback, testMode);
@@ -980,6 +1023,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
case NHeader::NMethod::kNone:
break;
case NHeader::NMethod::kMSZip:
if (!deflateDecoder)
{
@@ -988,14 +1032,16 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
cabBlockInStreamSpec->MsZip = true;
break;
case NHeader::NMethod::kLZX:
if (!lzxDecoder)
{
lzxDecoderSpec = new NCompress::NLzx::CDecoder;
lzxDecoder = lzxDecoderSpec;
}
res = lzxDecoderSpec->SetParams(folder.MethodMinor);
res = lzxDecoderSpec->SetParams_and_Alloc(folder.MethodMinor);
break;
case NHeader::NMethod::kQuantum:
if (!quantumDecoder)
{
@@ -1004,6 +1050,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
res = quantumDecoderSpec->SetParams(folder.MethodMinor);
break;
default:
res = E_INVALIDARG;
break;
@@ -1022,6 +1069,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
int locFolderIndex = item.GetFolderIndex(db.Folders.Size());
bool keepHistory = false;
bool keepInputBuffer = false;
bool thereWasNotAlignedChunk = false;
for (UInt32 bl = 0; cabFolderOutStream->GetRemain() != 0;)
{
@@ -1058,6 +1106,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
continue;
}
}
bl++;
if (!keepInputBuffer)
@@ -1079,19 +1128,39 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
lps->InSize = totalPacked;
RINOK(lps->SetCur());
UInt64 unpackRemain = cabFolderOutStream->GetRemain();
const UInt32 kBlockSizeMax = (1 << 15);
if (unpackRemain > kBlockSizeMax)
unpackRemain = kBlockSizeMax;
if (unpackRemain > unpackSize)
unpackRemain = unpackSize;
/* We don't try to reduce last block.
Note that LZX converts data with x86 filter.
and filter needs larger input data than reduced size.
It's simpler to decompress full chunk here.
also we need full block for quantum for more integrity checks */
if (unpackSize > kBlockSizeMax)
{
res = S_FALSE;
break;
}
if (unpackSize != kBlockSizeMax)
{
if (thereWasNotAlignedChunk)
{
res = S_FALSE;
break;
}
thereWasNotAlignedChunk = true;
}
UInt64 unpackSize64 = unpackSize;
UInt32 packSizeChunk = cabBlockInStreamSpec->GetPackSizeAvail();
switch (folder.GetMethod())
{
case NHeader::NMethod::kNone:
res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackSize64, NULL);
break;
case NHeader::NMethod::kMSZip:
deflateDecoderSpec->Set_KeepHistory(keepHistory);
/* v9.31: now we follow MSZIP specification that requires to finish deflate stream at the end of each block.
@@ -1100,7 +1169,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Maybe we also should ignore that error?
Or we should extract full file and show the warning? */
deflateDecoderSpec->Set_NeedFinishInput(true);
res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackSize64, NULL);
if (res == S_OK)
{
if (!deflateDecoderSpec->IsFinished())
@@ -1108,16 +1177,24 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (!deflateDecoderSpec->IsFinalBlock())
res = S_FALSE;
}
break;
case NHeader::NMethod::kLZX:
lzxDecoderSpec->SetKeepHistory(keepHistory);
res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
lzxDecoderSpec->KeepHistoryForNext = true;
res = lzxDecoderSpec->Code(cabBlockInStreamSpec->GetData(), packSizeChunk, unpackSize);
if (res == S_OK)
res = WriteStream(outStream,
lzxDecoderSpec->GetUnpackData(),
lzxDecoderSpec->GetUnpackSize());
break;
case NHeader::NMethod::kQuantum:
quantumDecoderSpec->SetKeepHistory(keepHistory);
res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
break;
res = quantumDecoderSpec->Code(cabBlockInStreamSpec->GetData(),
packSizeChunk, outStream, unpackSize, keepHistory);
break;
}
if (res != S_OK)
@@ -1135,17 +1212,21 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(cabFolderOutStream->WriteEmptyFiles());
}
}
if (res != S_OK || cabFolderOutStream->GetRemain() != 0)
{
RINOK(cabFolderOutStream->FlushCorrupted());
RINOK(cabFolderOutStream->FlushCorrupted(folderIndex2));
}
totalUnPacked += curUnpack;
}
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
*numItems = m_Database.Items.Size();

View File

@@ -144,7 +144,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
if (item.Section == 0)
prop = "Copy";
else if (item.Section < m_Database.Sections.Size())
prop = m_Database.Sections[(int)item.Section].GetMethodName();
prop = m_Database.Sections[(unsigned)item.Section].GetMethodName();
break;
}
case kpidBlock:
@@ -315,8 +315,9 @@ HRESULT CChmFolderOutStream::WriteEmptyFiles()
HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK)
{
UInt32 realProcessed = 0;
if (processedSize != NULL)
if (processedSize)
*processedSize = 0;
while(size != 0)
{
if (m_FileIsOpen)
@@ -335,7 +336,7 @@ HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *proce
}
}
realProcessed += numBytesToWrite;
if (processedSize != NULL)
if (processedSize)
*processedSize = realProcessed;
data = (const void *)((const Byte *)data + numBytesToWrite);
size -= numBytesToWrite;
@@ -359,23 +360,32 @@ HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *proce
else
{
if (m_CurrentIndex >= m_NumFiles)
return E_FAIL;
{
realProcessed += size;
if (processedSize)
*processedSize = realProcessed;
return S_OK;
// return E_FAIL;
}
int fullIndex = m_StartIndex + m_CurrentIndex;
m_RemainFileSize = m_Database->GetFileSize(fullIndex);
UInt64 fileOffset = m_Database->GetFileOffset(fullIndex);
if (fileOffset < m_PosInSection)
return E_FAIL;
if (fileOffset > m_PosInSection)
{
UInt32 numBytesToWrite = (UInt32)MyMin(fileOffset - m_PosInSection, UInt64(size));
realProcessed += numBytesToWrite;
if (processedSize != NULL)
if (processedSize)
*processedSize = realProcessed;
data = (const void *)((const Byte *)data + numBytesToWrite);
size -= numBytesToWrite;
m_PosInSection += numBytesToWrite;
m_PosInFolder += numBytesToWrite;
}
if (fileOffset == m_PosInSection)
{
RINOK(OpenFile());
@@ -385,6 +395,7 @@ HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *proce
}
}
}
return WriteEmptyFiles();
}
@@ -430,7 +441,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 currentTotalSize = 0;
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
UInt32 i;
@@ -446,11 +457,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
UInt64 currentItemSize = 0;
UInt64 totalSize = 0;
if (m_Database.NewFormat)
totalSize = m_Database.NewFormatString.Len();
else
for (i = 0; i < numItems; i++)
totalSize += m_Database.Items[allFilesMode ? i : indices[i]].Size;
extractCallback->SetTotal(totalSize);
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
@@ -481,6 +494,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
continue;
}
const CItem &item = m_Database.Items[index];
currentItemSize = item.Size;
@@ -513,6 +527,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
UInt64 lastFolderIndex = ((UInt64)0 - 1);
for (i = 0; i < numItems; i++)
{
UInt32 index = allFilesMode ? i : indices[i];
@@ -526,7 +541,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
currentTotalSize += item.Size;
continue;
}
const CSectionInfo &section = m_Database.Sections[(int)item.Section];
const CSectionInfo &section = m_Database.Sections[(unsigned)item.Section];
if (section.IsLzx())
{
const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo;
@@ -541,14 +556,17 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(extractCallback->SetTotal(currentTotalSize));
NCompress::NLzx::CDecoder *lzxDecoderSpec = 0;
CMyComPtr<ICompressCoder> lzxDecoder;
NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL;
CMyComPtr<IUnknown> lzxDecoder;
CChmFolderOutStream *chmFolderOutStream = 0;
CMyComPtr<ISequentialOutStream> outStream;
currentTotalSize = 0;
CRecordVector<bool> extractStatuses;
CByteBuffer packBuf;
for (i = 0; i < numItems;)
{
RINOK(extractCallback->SetCompleted(&currentTotalSize));
@@ -560,6 +578,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 askMode= testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
if (item.IsDir())
{
CMyComPtr<ISequentialOutStream> realOutStream;
@@ -595,7 +614,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
continue;
}
const CSectionInfo &section = m_Database.Sections[(int)sectionIndex];
const CSectionInfo &section = m_Database.Sections[(unsigned)sectionIndex];
if (!section.IsLzx())
{
@@ -610,7 +629,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo;
if (chmFolderOutStream == 0)
if (!chmFolderOutStream)
{
chmFolderOutStream = new CChmFolderOutStream;
outStream = chmFolderOutStream;
@@ -618,7 +637,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
chmFolderOutStream->Init(&m_Database, extractCallback, testMode);
if (lzxDecoderSpec == NULL)
if (!lzxDecoderSpec)
{
lzxDecoderSpec = new NCompress::NLzx::CDecoder;
lzxDecoder = lzxDecoderSpec;
@@ -627,8 +646,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 folderIndex = m_Database.GetFolder(index);
UInt64 compressedPos = m_Database.ContentOffset + section.Offset;
UInt32 numDictBits = lzxInfo.GetNumDictBits();
RINOK(lzxDecoderSpec->SetParams(numDictBits));
RINOK(lzxDecoderSpec->SetParams_and_Alloc(lzxInfo.GetNumDictBits()));
const CItem *lastItem = &item;
extractStatuses.Clear();
@@ -645,10 +663,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
lastFolderIndex = m_Database.GetLastFolder(index);
UInt64 folderSize = lzxInfo.GetFolderSize();
UInt64 unPackSize = folderSize;
if (extractStatuses.IsEmpty())
chmFolderOutStream->m_StartIndex = index + 1;
else
chmFolderOutStream->m_StartIndex = index;
if (limitFolderIndex == folderIndex)
{
for (; i < numItems; i++)
@@ -671,6 +691,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
lastFolderIndex = m_Database.GetLastFolder(index);
}
}
unPackSize = MyMin(finishPos - startPos, unPackSize);
chmFolderOutStream->m_FolderSize = folderSize;
@@ -679,11 +700,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
chmFolderOutStream->m_ExtractStatuses = &extractStatuses;
chmFolderOutStream->m_NumFiles = extractStatuses.Size();
chmFolderOutStream->m_CurrentIndex = 0;
try
{
UInt64 startBlock = lzxInfo.GetBlockIndexFromFolderIndex(folderIndex);
const CResetTable &rt = lzxInfo.ResetTable;
UInt32 numBlocks = (UInt32)rt.GetNumBlocks(unPackSize);
for (UInt32 b = 0; b < numBlocks; b++)
{
UInt64 completedSize = currentTotalSize + chmFolderOutStream->m_PosInSection - startPos;
@@ -691,17 +714,35 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 bCur = startBlock + b;
if (bCur >= rt.ResetOffsets.Size())
return E_FAIL;
UInt64 offset = rt.ResetOffsets[(int)bCur];
UInt64 offset = rt.ResetOffsets[(unsigned)bCur];
UInt64 compressedSize;
rt.GetCompressedSizeOfBlock(bCur, compressedSize);
UInt64 rem = finishPos - chmFolderOutStream->m_PosInSection;
if (rem > rt.BlockSize)
rem = rt.BlockSize;
// chm writes full blocks. So we don't need to use reduced size for last block
RINOK(m_Stream->Seek(compressedPos + offset, STREAM_SEEK_SET, NULL));
streamSpec->SetStream(m_Stream);
streamSpec->Init(compressedSize);
lzxDecoderSpec->SetKeepHistory(b > 0);
HRESULT res = lzxDecoder->Code(inStream, outStream, NULL, &rem, NULL);
size_t compressedSizeT = (size_t)compressedSize;
if (compressedSizeT != compressedSize)
throw 2;
packBuf.AllocAtLeast(compressedSizeT);
HRESULT res = ReadStream_FALSE(inStream, packBuf, compressedSizeT);
if (res == S_OK)
{
lzxDecoderSpec->KeepHistoryForNext = true;
res = lzxDecoderSpec->Code(packBuf, compressedSizeT, kBlockSize); // rt.BlockSize;
if (res == S_OK)
res = WriteStream(chmFolderOutStream,
lzxDecoderSpec->GetUnpackData(),
lzxDecoderSpec->GetUnpackSize());
}
if (res != S_OK)
{
if (res != S_FALSE)
@@ -714,6 +755,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
RINOK(chmFolderOutStream->FlushCorrupted(unPackSize));
}
currentTotalSize += folderSize;
if (folderIndex == lastFolderIndex)
break;

View File

@@ -4,6 +4,8 @@
// #include <stdio.h>
#include "../../../../C/CpuArch.h"
#include "../../../Common/IntToString.h"
#include "../../../Common/UTFConvert.h"
@@ -11,6 +13,10 @@
#include "ChmIn.h"
#define Get16(p) GetUi16(p)
#define Get32(p) GetUi32(p)
#define Get64(p) GetUi64(p)
namespace NArchive {
namespace NChm {
@@ -168,38 +174,36 @@ Byte CInArchive::ReadByte()
void CInArchive::Skip(size_t size)
{
while (size-- != 0)
ReadByte();
if (_inBuffer.Skip(size) != size)
throw CEnexpectedEndException();
}
void CInArchive::ReadBytes(Byte *data, UInt32 size)
{
for (UInt32 i = 0; i < size; i++)
data[i] = ReadByte();
if (_inBuffer.ReadBytes(data, size) != size)
throw CEnexpectedEndException();
}
UInt16 CInArchive::ReadUInt16()
{
UInt16 val = 0;
for (int i = 0; i < 2; i++)
val |= ((UInt16)(ReadByte()) << (8 * i));
return val;
Byte b0, b1;
if (!_inBuffer.ReadByte(b0)) throw CEnexpectedEndException();
if (!_inBuffer.ReadByte(b1)) throw CEnexpectedEndException();
return (UInt16)(((UInt16)b1 << 8) | b0);
}
UInt32 CInArchive::ReadUInt32()
{
UInt32 val = 0;
for (int i = 0; i < 4; i++)
val |= ((UInt32)(ReadByte()) << (8 * i));
return val;
Byte p[4];
ReadBytes(p, 4);
return Get32(p);
}
UInt64 CInArchive::ReadUInt64()
{
UInt64 val = 0;
for (int i = 0; i < 8; i++)
val |= ((UInt64)(ReadByte()) << (8 * i));
return val;
Byte p[8];
ReadBytes(p, 8);
return Get64(p);
}
UInt64 CInArchive::ReadEncInt()
@@ -227,15 +231,10 @@ void CInArchive::ReadGUID(GUID &g)
void CInArchive::ReadString(unsigned size, AString &s)
{
s.Empty();
while (size-- != 0)
if (size != 0)
{
char c = (char)ReadByte();
if (c == 0)
{
Skip(size);
return;
}
s += c;
ReadBytes((Byte *)s.GetBuf(size), size);
s.ReleaseBuf_CalcLen(size);
}
}
@@ -380,6 +379,7 @@ HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database)
ReadUInt32(); // Chunk number of next listing chunk when reading
// directory in sequence (-1 if this is the last listing chunk)
unsigned numItems = 0;
for (;;)
{
UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos;
@@ -391,9 +391,16 @@ HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database)
RINOK(ReadDirEntry(database));
numItems++;
}
Skip(quickrefLength - 2);
if (ReadUInt16() != numItems)
return S_FALSE;
unsigned rrr = ReadUInt16();
if (rrr != numItems)
{
// Lazarus 9-26-2 chm contains 0 here.
if (rrr != 0)
return S_FALSE;
}
}
else
Skip(dirChunkSize - 4);
@@ -709,6 +716,14 @@ bool CFilesDatabase::Check()
return true;
}
static int inline GetLog(UInt32 num)
{
for (int i = 0; i < 32; i++)
if (((UInt32)1 << i) == num)
return i;
return -1;
}
HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
{
{
@@ -771,6 +786,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
{
// Control Data
RINOK(DecompressStream(inStream, database, sectionPrefix + kControlData));
FOR_VECTOR (mi, section.Methods)
{
CMethodInfo &method = section.Methods[mi];
@@ -785,27 +801,22 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
li.Version = ReadUInt32();
if (li.Version != 2 && li.Version != 3)
return S_FALSE;
li.ResetInterval = ReadUInt32();
li.WindowSize = ReadUInt32();
{
int n = GetLog(ReadUInt32());
if (n < 0 || n > 16)
return S_FALSE;
li.ResetIntervalBits = n;
}
{
int n = GetLog(ReadUInt32());
if (n < 0 || n > 16)
return S_FALSE;
li.WindowSizeBits = n;
}
li.CacheSize = ReadUInt32();
if (
li.ResetInterval != 1 &&
li.ResetInterval != 2 &&
li.ResetInterval != 4 &&
li.ResetInterval != 8 &&
li.ResetInterval != 16 &&
li.ResetInterval != 32 &&
li.ResetInterval != 64)
return S_FALSE;
if (
li.WindowSize != 1 &&
li.WindowSize != 2 &&
li.WindowSize != 4 &&
li.WindowSize != 8 &&
li.WindowSize != 16 &&
li.WindowSize != 32 &&
li.WindowSize != 64)
return S_FALSE;
numDWORDS -= 5;
while (numDWORDS-- != 0)
ReadUInt32();
@@ -835,6 +846,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
RINOK(DecompressStream(inStream, database, transformPrefix +
method.GetGuidString() + kResetTable));
CResetTable &rt = method.LzxInfo.ResetTable;
if (_chunkSize < 4)
{
if (_chunkSize != 0)
@@ -844,7 +856,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
return S_FALSE;
rt.UncompressedSize = 0;
rt.CompressedSize = 0;
rt.BlockSize = 0;
// rt.BlockSize = 0;
}
else
{
@@ -852,18 +864,45 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
if (ver != 2 && ver != 3)
return S_FALSE;
UInt32 numEntries = ReadUInt32();
if (ReadUInt32() != 8) // Size of table entry (bytes)
const unsigned kEntrySize = 8;
if (ReadUInt32() != kEntrySize)
return S_FALSE;
if (ReadUInt32() != 0x28) // Len of table header
const unsigned kRtHeaderSize = 4 * 4 + 8 * 3;
if (ReadUInt32() != kRtHeaderSize)
return S_FALSE;
if (kRtHeaderSize + kEntrySize * (UInt64)numEntries != _chunkSize)
return S_FALSE;
rt.UncompressedSize = ReadUInt64();
rt.CompressedSize = ReadUInt64();
rt.BlockSize = ReadUInt64(); // 0x8000 block size for locations below
if (rt.BlockSize != 0x8000)
UInt64 blockSize = ReadUInt64();
if (blockSize != kBlockSize)
return S_FALSE;
UInt64 numBlocks = (rt.UncompressedSize + kBlockSize + 1) / kBlockSize;
if (numEntries != numBlocks &&
numEntries != numBlocks + 1)
return S_FALSE;
rt.ResetOffsets.ClearAndReserve(numEntries);
for (UInt32 i = 0; i < numEntries; i++)
rt.ResetOffsets.AddInReserved(ReadUInt64());
{
UInt64 v = ReadUInt64();
if (i != 0 && v < rt.ResetOffsets[i - 1])
return S_FALSE;
rt.ResetOffsets.AddInReserved(v);
}
if (numEntries != 0)
if (rt.ResetOffsets[0] != 0)
return S_FALSE;
if (numEntries == numBlocks + 1)
{
// Lazarus 9-26-2 chm contains additional entty
if (rt.ResetOffsets.Back() != rt.CompressedSize)
return S_FALSE;
}
}
}
}
@@ -896,14 +935,16 @@ HRESULT CInArchive::Open2(IInStream *inStream,
if (_help2)
{
const int kSignatureSize = 8;
UInt64 signature = ((UInt64)kSignature_ITLS << 32)| kSignature_ITOL;
const unsigned kSignatureSize = 8;
const UInt64 signature = ((UInt64)kSignature_ITLS << 32) | kSignature_ITOL;
UInt64 limit = 1 << 18;
if (searchHeaderSizeLimit)
if (limit > *searchHeaderSizeLimit)
limit = *searchHeaderSizeLimit;
UInt64 val = 0;
for (;;)
{
Byte b;
@@ -919,6 +960,7 @@ HRESULT CInArchive::Open2(IInStream *inStream,
return S_FALSE;
}
}
database.StartPosition += _inBuffer.GetProcessedSize() - kSignatureSize;
RINOK(OpenHelp2(inStream, database));
if (database.NewFormat)

View File

@@ -36,12 +36,13 @@ struct CItem
bool IsDir() const
{
if (Name.Len() == 0)
if (Name.IsEmpty())
return false;
return (Name.Back() == '/');
}
};
struct CDatabase
{
UInt64 StartPosition;
@@ -73,11 +74,14 @@ struct CDatabase
}
};
const UInt32 kBlockSize = 1 << 15;
struct CResetTable
{
UInt64 UncompressedSize;
UInt64 CompressedSize;
UInt64 BlockSize;
// unsigned BlockSizeBits;
CRecordVector<UInt64> ResetOffsets;
bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const
@@ -91,39 +95,41 @@ struct CResetTable
size = ResetOffsets[(unsigned)(blockIndex + numBlocks)] - startPos;
return true;
}
bool GetCompressedSizeOfBlock(UInt64 blockIndex, UInt64 &size) const
{
return GetCompressedSizeOfBlocks(blockIndex, 1, size);
}
UInt64 GetNumBlocks(UInt64 size) const
{
return (size + BlockSize - 1) / BlockSize;
return (size + kBlockSize - 1) / kBlockSize;
}
};
struct CLzxInfo
{
UInt32 Version;
UInt32 ResetInterval;
UInt32 WindowSize;
unsigned ResetIntervalBits;
unsigned WindowSizeBits;
UInt32 CacheSize;
CResetTable ResetTable;
UInt32 GetNumDictBits() const
unsigned GetNumDictBits() const
{
if (Version == 2 || Version == 3)
{
for (unsigned i = 0; i <= 31; i++)
if (((UInt32)1 << i) >= WindowSize)
return 15 + i;
}
return 15 + WindowSizeBits;
return 0;
}
UInt64 GetFolderSize() const { return ResetTable.BlockSize * ResetInterval; }
UInt64 GetFolderSize() const { return kBlockSize << ResetIntervalBits; }
UInt64 GetFolder(UInt64 offset) const { return offset / GetFolderSize(); }
UInt64 GetFolderPos(UInt64 folderIndex) const { return folderIndex * GetFolderSize(); }
UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex * ResetInterval; }
UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex << ResetIntervalBits; }
bool GetOffsetOfFolder(UInt64 folderIndex, UInt64 &offset) const
{
UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
@@ -132,24 +138,28 @@ struct CLzxInfo
offset = ResetTable.ResetOffsets[(unsigned)blockIndex];
return true;
}
bool GetCompressedSizeOfFolder(UInt64 folderIndex, UInt64 &size) const
{
UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
return ResetTable.GetCompressedSizeOfBlocks(blockIndex, ResetInterval, size);
return ResetTable.GetCompressedSizeOfBlocks(blockIndex, (UInt32)1 << ResetIntervalBits, size);
}
};
struct CMethodInfo
{
GUID Guid;
CByteBuffer ControlData;
CLzxInfo LzxInfo;
bool IsLzx() const;
bool IsDes() const;
AString GetGuidString() const;
UString GetName() const;
};
struct CSectionInfo
{
UInt64 Offset;
@@ -203,19 +213,12 @@ public:
CDatabase::Clear();
HighLevelClear();
}
void SetIndices();
void Sort();
bool Check();
};
/*
class CProgressVirt
{
public:
STDMETHOD(SetTotal)(const UInt64 *numFiles) PURE;
STDMETHOD(SetCompleted)(const UInt64 *numFiles) PURE;
};
*/
class CInArchive
{

View File

@@ -545,8 +545,8 @@ HRESULT CHandler::Open2(IInStream *stream)
CChecksum masterChecksum;
masterChecksum.Parse(buf + 0x160);
// UInt32 imageVariant = Get32(buf + 0x1E8);
// UInt64 numSectors = Get64(buf + 0x1EC);
// UInt32 imageVariant = Get32(buf + 0x1E8);
// UInt64 numSectors = Get64(buf + 0x1EC);
// Byte reserved[0x12]
const UInt32 RSRC_HEAD_SIZE = 0x100;

View File

@@ -226,25 +226,25 @@ void CSegment::Parse(const Byte *p, bool mode64, bool be)
// Section types
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
#define SHT_DYNSYM 11
#define SHT_UNKNOWN12 12
#define SHT_UNKNOWN13 13
#define SHT_INIT_ARRAY 14
#define SHT_FINI_ARRAY 15
#define SHT_PREINIT_ARRAY 16
#define SHT_GROUP 17
#define SHT_SYMTAB_SHNDX 18
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
#define SHT_DYNSYM 11
#define SHT_UNKNOWN12 12
#define SHT_UNKNOWN13 13
#define SHT_INIT_ARRAY 14
#define SHT_FINI_ARRAY 15
#define SHT_PREINIT_ARRAY 16
#define SHT_GROUP 17
#define SHT_SYMTAB_SHNDX 18
static const CUInt32PCharPair g_SectTypes[] =
@@ -554,11 +554,11 @@ static const CUInt32PCharPair g_OS[] =
{ 255, "Standalone" }
};
#define ET_NONE 0
#define ET_REL 1
#define ET_EXEC 2
#define ET_DYN 3
#define ET_CORE 4
#define ET_NONE 0
#define ET_REL 1
#define ET_EXEC 2
#define ET_DYN 3
#define ET_CORE 4
static const char *g_Types[] =
{

View File

@@ -0,0 +1,386 @@
// GptHandler.cpp
#include "StdAfx.h"
#include "../../../C/7zCrc.h"
#include "../../../C/CpuArch.h"
#include "../../Common/ComTry.h"
#include "../../Common/IntToString.h"
#include "../../Common/MyBuffer.h"
#include "../../Windows/PropVariantUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamUtils.h"
#include "HandlerCont.h"
#define Get16(p) GetUi16(p)
#define Get32(p) GetUi32(p)
#define Get64(p) GetUi64(p)
using namespace NWindows;
namespace NArchive {
namespace NGpt {
#define SIGNATURE { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 }
static const unsigned k_SignatureSize = 12;
static const Byte k_Signature[k_SignatureSize] = SIGNATURE;
static const UInt32 kSectorSize = 512;
static const CUInt32PCharPair g_PartitionFlags[] =
{
{ 0, "Sys" },
{ 1, "Ignore" },
{ 2, "Legacy" },
{ 60, "Win-Read-only" },
{ 62, "Win-Hidden" },
{ 63, "Win-Not-Automount" }
};
static const unsigned kNameLen = 36;
struct CPartition
{
Byte Type[16];
Byte Id[16];
UInt64 FirstLba;
UInt64 LastLba;
UInt64 Flags;
Byte Name[kNameLen * 2];
bool IsUnused() const
{
for (unsigned i = 0; i < 16; i++)
if (Type[i] != 0)
return false;
return true;
}
UInt64 GetSize() const { return (LastLba - FirstLba + 1) * kSectorSize; }
UInt64 GetPos() const { return FirstLba * kSectorSize; }
UInt64 GetEnd() const { return (LastLba + 1) * kSectorSize; }
void Parse(const Byte *p)
{
memcpy(Type, p, 16);
memcpy(Id, p + 16, 16);
FirstLba = Get64(p + 32);
LastLba = Get64(p + 40);
Flags = Get64(p + 48);
memcpy(Name, p + 56, kNameLen * 2);
}
};
struct CPartType
{
UInt32 Id;
const char *Ext;
const char *Type;
};
static const CPartType kPartTypes[] =
{
// { 0x0, 0, "Unused" },
{ 0xC12A7328, 0, "EFI System" },
{ 0x024DEE41, 0, "MBR" },
{ 0xE3C9E316, 0, "Windows MSR" },
{ 0xEBD0A0A2, 0, "Windows BDP" },
{ 0x5808C8AA, 0, "Windows LDM Metadata" },
{ 0xAF9B60A0, 0, "Windows LDM Data" },
{ 0xDE94BBA4, 0, "Windows Recovery" },
// { 0x37AFFC90, 0, "IBM GPFS" },
// { 0xE75CAF8F, 0, "Windows Storage Spaces" },
{ 0x83BD6B9D, 0, "FreeBSD Boot" },
{ 0x516E7CB4, 0, "FreeBSD Data" },
{ 0x516E7CB5, 0, "FreeBSD Swap" },
{ 0x516E7CB6, "ufs", "FreeBSD UFS" },
{ 0x516E7CB8, 0, "FreeBSD Vinum" },
{ 0x516E7CB8, "zfs", "FreeBSD ZFS" },
{ 0x48465300, "hfsx", "HFS+" },
};
static int FindPartType(const Byte *guid)
{
UInt32 val = Get32(guid);
for (unsigned i = 0; i < ARRAY_SIZE(kPartTypes); i++)
if (kPartTypes[i].Id == val)
return i;
return -1;
}
static inline char GetHex(unsigned t) { return (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); }
static void PrintHex(unsigned v, char *s)
{
s[0] = GetHex((v >> 4) & 0xF);
s[1] = GetHex(v & 0xF);
}
static void ConvertUInt16ToHex4Digits(UInt32 val, char *s) throw()
{
PrintHex(val >> 8, s);
PrintHex(val & 0xFF, s + 2);
}
static void GuidToString(const Byte *g, char *s)
{
ConvertUInt32ToHex8Digits(Get32(g ), s); s += 8; *s++ = '-';
ConvertUInt16ToHex4Digits(Get16(g + 4), s); s += 4; *s++ = '-';
ConvertUInt16ToHex4Digits(Get16(g + 6), s); s += 4; *s++ = '-';
for (unsigned i = 0; i < 8; i++)
{
if (i == 2)
*s++ = '-';
PrintHex(g[8 + i], s);
s += 2;
}
*s = 0;
}
class CHandler: public CHandlerCont
{
CRecordVector<CPartition> _items;
UInt64 _totalSize;
Byte Guid[16];
CByteBuffer _buffer;
HRESULT Open2(IInStream *stream);
virtual UInt64 GetItemPos(UInt32 index) const { return _items[index].GetPos(); }
virtual UInt64 GetItemSize(UInt32 index) const { return _items[index].GetSize(); }
public:
INTERFACE_IInArchive_Cont(;)
};
HRESULT CHandler::Open2(IInStream *stream)
{
_buffer.Alloc(kSectorSize * 2);
RINOK(ReadStream_FALSE(stream, _buffer, kSectorSize * 2));
const Byte *buf = _buffer;
if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA)
return S_FALSE;
buf += kSectorSize;
if (memcmp(buf, k_Signature, k_SignatureSize) != 0)
return S_FALSE;
{
// if (Get32(buf + 8) != 0x10000) return S_FALSE; // revision
UInt32 headerSize = Get32(buf + 12); // = 0x5C usually
if (headerSize > kSectorSize)
return S_FALSE;
UInt32 crc = Get32(buf + 0x10);
SetUi32(_buffer + kSectorSize + 0x10, 0);
if (CrcCalc(_buffer + kSectorSize, headerSize) != crc)
return S_FALSE;
}
// UInt32 reserved = Get32(buf + 0x14);
UInt64 curLba = Get64(buf + 0x18);
if (curLba != 1)
return S_FALSE;
UInt64 backupLba = Get64(buf + 0x20);
// UInt64 firstUsableLba = Get64(buf + 0x28);
// UInt64 lastUsableLba = Get64(buf + 0x30);
memcpy(Guid, buf + 0x38, 16);
UInt64 tableLba = Get64(buf + 0x48);
if (tableLba < 2)
return S_FALSE;
UInt32 numEntries = Get32(buf + 0x50);
UInt32 entrySize = Get32(buf + 0x54); // = 128 usually
UInt32 entriesCrc = Get32(buf + 0x58);
if (entrySize < 128
|| entrySize > (1 << 12)
|| numEntries > (1 << 16)
|| tableLba < 2
|| tableLba >= ((UInt64)1 << (64 - 10)))
return S_FALSE;
UInt32 tableSize = entrySize * numEntries;
UInt32 tableSizeAligned = (tableSize + kSectorSize - 1) & ~(kSectorSize - 1);
_buffer.Alloc(tableSizeAligned);
UInt64 tableOffset = tableLba * kSectorSize;
RINOK(stream->Seek(tableOffset, STREAM_SEEK_SET, NULL));
RINOK(ReadStream_FALSE(stream, _buffer, tableSizeAligned));
if (CrcCalc(_buffer, tableSize) != entriesCrc)
return S_FALSE;
_totalSize = tableOffset + tableSizeAligned;
for (UInt32 i = 0; i < numEntries; i++)
{
CPartition item;
item.Parse(_buffer + i * entrySize);
if (item.IsUnused())
continue;
UInt64 endPos = item.GetEnd();
if (_totalSize < endPos)
_totalSize = endPos;
_items.Add(item);
}
UInt64 end = (backupLba + 1) * kSectorSize;
if (_totalSize < end)
_totalSize = end;
return S_OK;
}
STDMETHODIMP CHandler::Open(IInStream *stream,
const UInt64 * /* maxCheckStartPosition */,
IArchiveOpenCallback * /* openArchiveCallback */)
{
COM_TRY_BEGIN
Close();
RINOK(Open2(stream));
_stream = stream;
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::Close()
{
_totalSize = 0;
memset(Guid, 0, sizeof(Guid));
_items.Clear();
_stream.Release();
return S_OK;
}
static const Byte kProps[] =
{
kpidPath,
kpidSize,
kpidFileSystem,
kpidCharacts,
kpidOffset,
kpidId
};
static const Byte kArcProps[] =
{
kpidId
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
switch (propID)
{
case kpidMainSubfile:
{
if (_items.Size() == 1)
prop = (UInt32)0;
break;
}
case kpidPhySize: prop = _totalSize; break;
case kpidId:
{
char s[48];
GuidToString(Guid, s);
prop = s;
break;
}
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
*numItems = _items.Size();
return S_OK;
}
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
const CPartition &item = _items[index];
switch (propID)
{
case kpidPath:
{
UString s;
for (unsigned i = 0; i < kNameLen; i++)
{
wchar_t c = (wchar_t)Get16(item.Name + i * 2);
if (c == 0)
break;
s += c;
}
{
int typeIndex = FindPartType(item.Type);
s += L'.';
const char *ext = "img";
if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Ext)
ext = kPartTypes[(unsigned)typeIndex].Ext;
s.AddAscii(ext);
}
prop = s;
break;
}
case kpidSize:
case kpidPackSize: prop = item.GetSize(); break;
case kpidOffset: prop = item.GetPos(); break;
case kpidFileSystem:
{
char s[48];
const char *res;
int typeIndex = FindPartType(item.Type);
if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Type)
res = kPartTypes[(unsigned)typeIndex].Type;
else
{
GuidToString(item.Type, s);
res = s;
}
prop = res;
break;
}
case kpidId:
{
char s[48];
GuidToString(item.Id, s);
prop = s;
break;
}
case kpidCharacts: FLAGS64_TO_PROP(g_PartitionFlags, item.Flags, prop); break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
REGISTER_ARC_I(
"GPT", "gpt mbr", NULL, 0xCB,
k_Signature,
kSectorSize,
0,
NULL)
}}

View File

@@ -0,0 +1,230 @@
// HandlerCont.cpp
#include "StdAfx.h"
#include "../../Common/ComTry.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
#include "../Common/StreamUtils.h"
#include "../Compress/CopyCoder.h"
#include "HandlerCont.h"
namespace NArchive {
STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
{
RINOK(GetNumberOfItems(&numItems));
}
if (numItems == 0)
return S_OK;
UInt64 totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
totalSize += GetItemSize(allFilesMode ? i : indices[i]);
extractCallback->SetTotal(totalSize);
totalSize = 0;
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
CMyComPtr<ISequentialInStream> inStream(streamSpec);
streamSpec->SetStream(_stream);
for (i = 0; i < numItems; i++)
{
lps->InSize = totalSize;
lps->OutSize = totalSize;
RINOK(lps->SetCur());
CMyComPtr<ISequentialOutStream> outStream;
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
Int32 index = allFilesMode ? i : indices[i];
RINOK(extractCallback->GetStream(index, &outStream, askMode));
UInt64 size = GetItemSize(index);
totalSize += size;
if (!testMode && !outStream)
continue;
RINOK(extractCallback->PrepareOperation(askMode));
RINOK(_stream->Seek(GetItemPos(index), STREAM_SEEK_SET, NULL));
streamSpec->Init(size);
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
outStream.Release();
int opRes = NExtract::NOperationResult::kDataError;
if (copyCoderSpec->TotalSize == size)
opRes = NExtract::NOperationResult::kOK;
else if (copyCoderSpec->TotalSize < size)
opRes = NExtract::NOperationResult::kUnexpectedEnd;
RINOK(extractCallback->SetOperationResult(opRes));
}
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandlerCont::GetStream(UInt32 index, ISequentialInStream **stream)
{
COM_TRY_BEGIN
// const CPartition &item = _items[index];
return CreateLimitedInStream(_stream, GetItemPos(index), GetItemSize(index), stream);
COM_TRY_END
}
STDMETHODIMP CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
{
switch (seekOrigin)
{
case STREAM_SEEK_SET: break;
case STREAM_SEEK_CUR: offset += _virtPos; break;
case STREAM_SEEK_END: offset += _size; break;
default: return STG_E_INVALIDFUNCTION;
}
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
_virtPos = offset;
if (newPosition)
*newPosition = offset;
return S_OK;
}
static const Byte k_GDP_Signature[] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' };
static const char *GetImgExt(ISequentialInStream *stream)
{
const size_t kHeaderSize = 1 << 10;
Byte buf[kHeaderSize];
if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK)
{
if (buf[0x1FE] == 0x55 && buf[0x1FF] == 0xAA)
{
if (memcmp(buf + 512, k_GDP_Signature, sizeof(k_GDP_Signature)) == 0)
return "gpt";
return "mbr";
}
}
return NULL;
}
void CHandlerImg::CloseAtError()
{
Stream.Release();
}
STDMETHODIMP CHandlerImg::Open(IInStream *stream,
const UInt64 * /* maxCheckStartPosition */,
IArchiveOpenCallback * openCallback)
{
COM_TRY_BEGIN
{
Close();
HRESULT res;
try
{
res = Open2(stream, openCallback);
if (res == S_OK)
{
CMyComPtr<ISequentialInStream> inStream;
HRESULT res2 = GetStream(0, &inStream);
if (res2 == S_OK && inStream)
_imgExt = GetImgExt(inStream);
return S_OK;
}
}
catch(...)
{
CloseAtError();
throw;
}
CloseAtError();
return res;
}
COM_TRY_END
}
STDMETHODIMP CHandlerImg::GetNumberOfItems(UInt32 *numItems)
{
*numItems = 1;
return S_OK;
}
STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
if (numItems == 0)
return S_OK;
if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
RINOK(extractCallback->SetTotal(_size));
CMyComPtr<ISequentialOutStream> outStream;
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
RINOK(extractCallback->GetStream(0, &outStream, askMode));
if (!testMode && !outStream)
return S_OK;
RINOK(extractCallback->PrepareOperation(askMode));
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
int opRes = NExtract::NOperationResult::kDataError;
CMyComPtr<ISequentialInStream> inStream;
HRESULT hres = GetStream(0, &inStream);
if (hres == S_FALSE)
hres = E_NOTIMPL;
if (hres == S_OK && inStream)
{
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
hres = copyCoder->Code(inStream, outStream, NULL, &_size, progress);
if (hres == S_OK)
{
if (copyCoderSpec->TotalSize == _size)
opRes = NExtract::NOperationResult::kOK;
else if (copyCoderSpec->TotalSize < _size)
opRes = NExtract::NOperationResult::kUnexpectedEnd;
}
}
inStream.Release();
outStream.Release();
if (hres != S_OK)
{
if (hres == S_FALSE)
opRes = NExtract::NOperationResult::kDataError;
else if (hres == E_NOTIMPL)
opRes = NExtract::NOperationResult::kUnsupportedMethod;
else
return hres;
}
return extractCallback->SetOperationResult(opRes);
COM_TRY_END
}
}

View File

@@ -0,0 +1,90 @@
// HandlerCont.h
#ifndef __HANDLER_CONT_H
#define __HANDLER_CONT_H
#include "../../Common/MyCom.h"
#include "IArchive.h"
namespace NArchive {
#define INTERFACE_IInArchive_Cont(x) \
STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) MY_NO_THROW_DECL_ONLY x; \
STDMETHOD(Close)() MY_NO_THROW_DECL_ONLY x; \
STDMETHOD(GetNumberOfItems)(UInt32 *numItems) MY_NO_THROW_DECL_ONLY x; \
STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \
/* STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY x; */ \
STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \
STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \
STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \
STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \
STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \
class CHandlerCont:
public IInArchive,
public IInArchiveGetStream,
public CMyUnknownImp
{
protected:
CMyComPtr<IInStream> _stream;
virtual UInt64 GetItemPos(UInt32 index) const = 0;
virtual UInt64 GetItemSize(UInt32 index) const = 0;
public:
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive_Cont(PURE)
STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY;
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
};
#define INTERFACE_IInArchive_Img(x) \
/* STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) MY_NO_THROW_DECL_ONLY x; */ \
STDMETHOD(Close)() MY_NO_THROW_DECL_ONLY x; \
/* STDMETHOD(GetNumberOfItems)(UInt32 *numItems) MY_NO_THROW_DECL_ONLY x; */ \
STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \
/* STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY x; */ \
STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \
STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \
STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \
STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \
STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \
class CHandlerImg:
public IInStream,
public IInArchive,
public IInArchiveGetStream,
public CMyUnknownImp
{
protected:
UInt64 _virtPos;
UInt64 _posInArc;
UInt64 _size;
CMyComPtr<IInStream> Stream;
const char *_imgExt;
virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0;
virtual void CloseAtError();
public:
MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream)
INTERFACE_IInArchive_Img(PURE)
STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback);
STDMETHOD(GetNumberOfItems)(UInt32 *numItems);
STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback);
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) = 0;
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) = 0;
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
};
}
#endif

View File

@@ -40,7 +40,7 @@ namespace NMacho {
#define CPU_SUBTYPE_LIB64 (1 << 31)
#define CPU_SUBTYPE_POWERPC_970 100
#define CPU_SUBTYPE_POWERPC_970 100
static const char * const k_PowerPc_SubTypes[] =
{

View File

@@ -13,16 +13,13 @@
#include "../../Common/ComTry.h"
#include "../../Common/IntToString.h"
#include "../../Common/MyBuffer.h"
#include "../../Common/MyString.h"
#include "../../Windows/PropVariant.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamUtils.h"
#include "../Compress/CopyCoder.h"
#include "HandlerCont.h"
#ifdef SHOW_DEBUG_INFO
#define PRF(x) x
@@ -56,12 +53,15 @@ struct CChs
#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
// Chs in some MBRs contains only low bits of "Cyl number". So we disable check.
/*
static int CompareChs(const CChs &c1, const CChs &c2)
{
RINOZ(MyCompare(c1.GetCyl(), c2.GetCyl()));
RINOZ(MyCompare(c1.Head, c2.Head));
return MyCompare(c1.GetSector(), c2.GetSector());
}
*/
static void AddUIntToString(UInt32 val, AString &res)
{
@@ -112,12 +112,11 @@ struct CPartition
return true;
if (Status != 0 && Status != 0x80)
return false;
return
BeginChs.Check() &&
EndChs.Check() &&
CompareChs(BeginChs, EndChs) <= 0 &&
NumBlocks > 0 &&
CheckLbaLimits();
return BeginChs.Check()
&& EndChs.Check()
// && CompareChs(BeginChs, EndChs) <= 0
&& NumBlocks > 0
&& CheckLbaLimits();
}
#ifdef SHOW_DEBUG_INFO
@@ -159,11 +158,12 @@ static const CPartType kPartTypes[] =
{ 0x1E, kFat, "FAT16-LBA-WIN95-Hidden" },
{ 0x82, 0, "Solaris x86 / Linux swap" },
{ 0x83, 0, "Linux" },
{ 0xA5, 0, "BSD slice" },
{ 0xBE, 0, "Solaris 8 boot" },
{ 0xBF, 0, "New Solaris x86" },
{ 0xC2, 0, "Linux-Hidden" },
{ 0xC3, 0, "Linux swap-Hidden" },
{ 0xEE, 0, "EFI-MBR" },
{ 0xEE, 0, "GPT" },
{ 0xEE, 0, "EFI" }
};
@@ -183,21 +183,17 @@ struct CItem
CPartition Part;
};
class CHandler:
public IInArchive,
public IInArchiveGetStream,
public CMyUnknownImp
class CHandler: public CHandlerCont
{
CMyComPtr<IInStream> _stream;
CObjectVector<CItem> _items;
UInt64 _totalSize;
CByteBuffer _buffer;
virtual UInt64 GetItemPos(UInt32 index) const { return _items[index].Part.GetPos(); }
virtual UInt64 GetItemSize(UInt32 index) const { return _items[index].Size; }
HRESULT ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, unsigned level);
public:
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
INTERFACE_IInArchive_Cont(;)
};
HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, unsigned level)
@@ -391,7 +387,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
const CItem &item = _items[index];
const CPartition &part = item.Part;
switch(propID)
switch (propID)
{
case kpidPath:
{
@@ -421,7 +417,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = res;
}
break;
case kpidSize: prop = item.Size; break;;
case kpidSize:
case kpidPackSize: prop = item.Size; break;
case kpidOffset: prop = part.GetPos(); break;
case kpidPrimary: if (item.IsReal) prop = item.IsPrim; break;
@@ -433,72 +429,6 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
COM_TRY_END
}
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items.Size();
if (numItems == 0)
return S_OK;
UInt64 totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
totalSize += _items[allFilesMode ? i : indices[i]].Size;
extractCallback->SetTotal(totalSize);
totalSize = 0;
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
CMyComPtr<ISequentialInStream> inStream(streamSpec);
streamSpec->SetStream(_stream);
for (i = 0; i < numItems; i++)
{
lps->InSize = totalSize;
lps->OutSize = totalSize;
RINOK(lps->SetCur());
CMyComPtr<ISequentialOutStream> outStream;
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
Int32 index = allFilesMode ? i : indices[i];
const CItem &item = _items[index];
const CPartition &part = item.Part;
RINOK(extractCallback->GetStream(index, &outStream, askMode));
totalSize += item.Size;
if (!testMode && !outStream)
continue;
RINOK(extractCallback->PrepareOperation(askMode));
RINOK(_stream->Seek(part.GetPos(), STREAM_SEEK_SET, NULL));
streamSpec->Init(item.Size);
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
outStream.Release();
RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == item.Size ?
NExtract::NOperationResult::kOK:
NExtract::NOperationResult::kDataError));
}
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
{
COM_TRY_BEGIN
const CItem &item = _items[index];
return CreateLimitedInStream(_stream, item.Part.GetPos(), item.Size, stream);
COM_TRY_END
}
// 3, { 1, 1, 0 },
// 2, { 0x55, 0x1FF },

View File

@@ -10,12 +10,10 @@
#include "../../Windows/PropVariant.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamUtils.h"
#include "../Compress/CopyCoder.h"
#include "HandlerCont.h"
static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); }
@@ -36,7 +34,7 @@ namespace NMub {
#define MACH_CPU_SUBTYPE_LIB64 (1 << 31)
#define MACH_CPU_SUBTYPE_I386_ALL 3
#define MACH_CPU_SUBTYPE_I386_ALL 3
struct CItem
{
@@ -49,12 +47,8 @@ struct CItem
static const UInt32 kNumFilesMax = 10;
class CHandler:
public IInArchive,
public IInArchiveGetStream,
public CMyUnknownImp
class CHandler: public CHandlerCont
{
CMyComPtr<IInStream> _stream;
// UInt64 _startPos;
UInt64 _phySize;
UInt32 _numItems;
@@ -62,10 +56,10 @@ class CHandler:
CItem _items[kNumFilesMax];
HRESULT Open2(IInStream *stream);
virtual UInt64 GetItemPos(UInt32 index) const { return _items[index].Offset; }
virtual UInt64 GetItemSize(UInt32 index) const { return _items[index].Size; }
public:
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
INTERFACE_IInArchive_Cont(;)
};
static const Byte kArcProps[] =
@@ -223,75 +217,6 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _numItems;
if (numItems == 0)
return S_OK;
UInt64 totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
totalSize += _items[allFilesMode ? i : indices[i]].Size;
extractCallback->SetTotal(totalSize);
UInt64 currentTotalSize = 0;
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
CMyComPtr<ISequentialInStream> inStream(streamSpec);
streamSpec->SetStream(_stream);
for (i = 0; i < numItems; i++)
{
lps->InSize = lps->OutSize = currentTotalSize;
RINOK(lps->SetCur());
CMyComPtr<ISequentialOutStream> realOutStream;
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
UInt32 index = allFilesMode ? i : indices[i];
const CItem &item = _items[index];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
currentTotalSize += item.Size;
if (!testMode && !realOutStream)
continue;
RINOK(extractCallback->PrepareOperation(askMode));
if (testMode)
{
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
continue;
}
RINOK(_stream->Seek(/* _startPos + */ item.Offset, STREAM_SEEK_SET, NULL));
streamSpec->Init(item.Size);
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
realOutStream.Release();
RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
NExtract::NOperationResult::kOK:
NExtract::NOperationResult::kDataError));
}
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
{
COM_TRY_BEGIN
const CItem &item = _items[index];
return CreateLimitedInStream(_stream, /* _startPos + */ item.Offset, item.Size, stream);
COM_TRY_END
}
namespace NBe {
static const Byte k_Signature[] = {

View File

@@ -2514,8 +2514,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
attrib |= FILE_ATTRIBUTE_DIRECTORY;
/* some system entries can contain extra flags (Index View).
// 0x10000000 (Directory)
// 0x20000000 FILE_ATTR_VIEW_INDEX_PRESENT MFT_RECORD_IS_VIEW_INDEX (Index View)
// 0x10000000 (Directory)
// 0x20000000 FILE_ATTR_VIEW_INDEX_PRESENT MFT_RECORD_IS_VIEW_INDEX (Index View)
But we don't need them */
attrib &= 0xFFFF;

View File

@@ -0,0 +1,611 @@
// QcowHandler.cpp
#include "StdAfx.h"
// #include <stdio.h>
#include "../../../C/CpuArch.h"
#include "../../Common/ComTry.h"
#include "../../Common/IntToString.h"
#include "../../Windows/PropVariant.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamObjects.h"
#include "../Common/StreamUtils.h"
#include "../Compress/DeflateDecoder.h"
#include "HandlerCont.h"
#define Get32(p) GetBe32(p)
#define Get64(p) GetBe64(p)
using namespace NWindows;
namespace NArchive {
namespace NQcow {
#define SIGNATURE { 'Q', 'F', 'I', 0xFB, 0, 0, 0 }
static const Byte k_Signature[] = SIGNATURE;
class CHandler: public CHandlerImg
{
unsigned _clusterBits;
unsigned _numMidBits;
UInt64 _compressedFlag;
CObjectVector<CByteBuffer> _tables;
UInt64 _cacheCluster;
CByteBuffer _cache;
CByteBuffer _cacheCompressed;
UInt64 _comprPos;
size_t _comprSize;
UInt64 _phySize;
CBufInStream *_bufInStreamSpec;
CMyComPtr<ISequentialInStream> _bufInStream;
CBufPtrSeqOutStream *_bufOutStreamSpec;
CMyComPtr<ISequentialOutStream> _bufOutStream;
NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoderSpec;
CMyComPtr<ICompressCoder> _deflateDecoder;
bool _needDeflate;
bool _isArc;
bool _unsupported;
UInt32 _version;
UInt32 _cryptMethod;
HRESULT Seek(UInt64 offset)
{
_posInArc = offset;
return Stream->Seek(offset, STREAM_SEEK_SET, NULL);
}
HRESULT InitAndSeek()
{
_virtPos = 0;
return Seek(0);
}
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback);
public:
INTERFACE_IInArchive_Img(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
};
STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
{
if (processedSize)
*processedSize = 0;
if (_virtPos >= _size)
return S_OK;
{
UInt64 rem = _size - _virtPos;
if (size > rem)
size = (UInt32)rem;
if (size == 0)
return S_OK;
}
for (;;)
{
UInt64 cluster = _virtPos >> _clusterBits;
size_t clusterSize = (size_t)1 << _clusterBits;
size_t lowBits = (size_t)_virtPos & (clusterSize - 1);
{
size_t rem = clusterSize - lowBits;
if (size > rem)
size = (UInt32)rem;
}
if (cluster == _cacheCluster)
{
memcpy(data, _cache + lowBits, size);
_virtPos += size;
if (processedSize)
*processedSize = size;
return S_OK;
}
UInt64 high = cluster >> _numMidBits;
if (high < _tables.Size())
{
const CByteBuffer &buffer = _tables[(unsigned)high];
if (buffer.Size() != 0)
{
size_t midBits = (size_t)cluster & (((size_t)1 << _numMidBits) - 1);
const Byte *p = (const Byte *)buffer + (midBits << 3);
UInt64 v = Get64(p);
if (v != 0)
{
if ((v & _compressedFlag) != 0)
{
if (_version <= 1)
return E_FAIL;
unsigned numOffsetBits = (62 - (_clusterBits - 8));
UInt64 offset = v & (((UInt64)1 << 62) - 1);
const size_t dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9;
offset &= ((UInt64)1 << numOffsetBits) - 1;
UInt64 sectorOffset = offset >> 9 << 9;
UInt64 offset2inCache = sectorOffset - _comprPos;
if (sectorOffset >= _comprPos && offset2inCache < _comprSize)
{
if (offset2inCache != 0)
{
_comprSize -= (size_t)offset2inCache;
memmove(_cacheCompressed, _cacheCompressed + offset2inCache, _comprSize);
_comprPos = sectorOffset;
}
sectorOffset += _comprSize;
}
else
{
_comprPos = sectorOffset;
_comprSize = 0;
}
// printf("\nDeflate");
if (sectorOffset != _posInArc)
{
// printf("\nDeflate %12I64x %12I64x\n", sectorOffset, sectorOffset - _posInArc);
RINOK(Seek(sectorOffset));
}
if (_cacheCompressed.Size() < dataSize)
return E_FAIL;
size_t dataSize3 = dataSize - _comprSize;
size_t dataSize2 = dataSize3;
RINOK(ReadStream(Stream, _cacheCompressed + _comprSize, &dataSize2));
_posInArc += dataSize2;
if (dataSize2 != dataSize3)
return E_FAIL;
_comprSize += dataSize2;
const size_t kSectorMask = (1 << 9) - 1;
size_t offsetInSector = ((size_t)offset & kSectorMask);
_bufInStreamSpec->Init(_cacheCompressed + offsetInSector, dataSize - offsetInSector);
_cacheCluster = (UInt64)(Int64)-1;
if (_cache.Size() < clusterSize)
return E_FAIL;
_bufOutStreamSpec->Init(_cache, clusterSize);
// Do we need to use smaller block than clusterSize for last cluster?
UInt64 blockSize64 = clusterSize;
HRESULT res = _deflateDecoderSpec->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL);
/*
if (_bufOutStreamSpec->GetPos() != clusterSize)
memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos());
*/
if (res == S_OK)
if (!_deflateDecoderSpec->IsFinished()
|| _bufOutStreamSpec->GetPos() != clusterSize)
res = S_FALSE;
RINOK(res);
_cacheCluster = cluster;
continue;
/*
memcpy(data, _cache + lowBits, size);
_virtPos += size;
if (processedSize)
*processedSize = size;
return S_OK;
*/
}
// version 3 support zero clusters
if (((UInt32)v & 511) != 1)
{
v &= (_compressedFlag - 1);
v += lowBits;
if (v != _posInArc)
{
// printf("\n%12I64x\n", v - _posInArc);
RINOK(Seek(v));
}
HRESULT res = Stream->Read(data, size, &size);
_posInArc += size;
_virtPos += size;
if (processedSize)
*processedSize = size;
return res;
}
}
}
}
memset(data, 0, size);
_virtPos += size;
if (processedSize)
*processedSize = size;
return S_OK;
}
}
static const Byte kProps[] =
{
kpidSize,
kpidPackSize
};
static const Byte kArcProps[] =
{
kpidClusterSize,
kpidUnpackVer,
kpidMethod
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
switch (propID)
{
case kpidMainSubfile: prop = (UInt32)0; break;
case kpidClusterSize: prop = (UInt32)1 << _clusterBits; break;
case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
case kpidUnpackVer: prop = _version; break;
case kpidMethod:
{
AString s;
if (_needDeflate)
s = "Deflate";
if (_cryptMethod != 0)
{
s.Add_Space_if_NotEmpty();
if (_cryptMethod == 1)
s += "AES";
else
{
char temp[16];
ConvertUInt32ToString(_cryptMethod, temp);
s += temp;
}
}
if (!s.IsEmpty())
prop = s;
break;
}
case kpidErrorFlags:
{
UInt32 v = 0;
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;;
if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
// if (_headerError) v |= kpv_ErrorFlags_HeadersError;
if (!Stream && v == 0 && _isArc)
v = kpv_ErrorFlags_HeadersError;
if (v != 0)
prop = v;
break;
}
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
switch (propID)
{
case kpidSize: prop = _size; break;
case kpidPackSize: prop = _phySize; break;
case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
{
const unsigned kHeaderSize = 18 * 4;
Byte buf[kHeaderSize];
RINOK(ReadStream_FALSE(stream, buf, kHeaderSize));
if (memcmp(buf, k_Signature, 4) != 0)
return S_FALSE;
_version = Get32(buf + 4);
if (_version < 1 || _version > 3)
return S_FALSE;
const UInt64 backOffset = Get64(buf + 8);
// UInt32 backSize = Get32(buf + 0x10);
UInt64 l1Offset = 0;
UInt32 l1Size = 0;
if (_version == 1)
{
// _mTime = Get32(buf + 0x14); // is unused im most images
_size = Get64(buf + 0x18);
_clusterBits = buf[0x20];
_numMidBits = buf[0x21];
if (_clusterBits < 9 || _clusterBits > 30)
return S_FALSE;
if (_numMidBits < 1 || _numMidBits > 28)
return S_FALSE;
_cryptMethod = Get32(buf + 0x24);
l1Offset = Get64(buf + 0x28);
if (l1Offset < 0x30)
return S_FALSE;
unsigned numBits2 = (_clusterBits + _numMidBits);
UInt64 l1Size64 = (_size + (((UInt64)1 << numBits2) - 1)) >> numBits2;
if (l1Size64 > ((UInt32)1 << 31))
return S_FALSE;
l1Size = (UInt32)l1Size64;
}
else
{
_clusterBits = Get32(buf + 0x14);
if (_clusterBits < 9 || _clusterBits > 30)
return S_FALSE;
_numMidBits = _clusterBits - 3;
_size = Get64(buf + 0x18);
_cryptMethod = Get32(buf + 0x20);
l1Size = Get32(buf + 0x24);
l1Offset = Get64(buf + 0x28); // must be aligned for cluster
UInt64 refOffset = Get64(buf + 0x30); // must be aligned for cluster
UInt32 refClusters = Get32(buf + 0x38);
// UInt32 numSnapshots = Get32(buf + 0x3C);
// UInt64 snapshotsOffset = Get64(buf + 0x40); // must be aligned for cluster
/*
if (numSnapshots != 0)
return S_FALSE;
*/
if (refClusters != 0)
{
size_t numBytes = refClusters << _clusterBits;
/*
CByteBuffer refs;
refs.Alloc(numBytes);
RINOK(stream->Seek(refOffset, STREAM_SEEK_SET, NULL));
RINOK(ReadStream_FALSE(stream, refs, numBytes));
*/
UInt64 end = refOffset + numBytes;
if (_phySize < end)
_phySize = end;
/*
for (size_t i = 0; i < numBytes; i += 2)
{
UInt32 v = GetBe16((const Byte *)refs + (size_t)i);
if (v == 0)
continue;
}
*/
}
}
_isArc = true;
if (backOffset != 0)
{
_unsupported = true;
return S_FALSE;
}
const size_t clusterSize = (size_t)1 << _clusterBits;
CByteBuffer table;
{
size_t t1SizeBytes = (size_t)l1Size << 3;
if ((t1SizeBytes >> 3) != l1Size)
return S_FALSE;
table.Alloc(t1SizeBytes);
RINOK(stream->Seek(l1Offset, STREAM_SEEK_SET, NULL));
RINOK(ReadStream_FALSE(stream, table, t1SizeBytes));
{
UInt64 end = l1Offset + t1SizeBytes;
// we need to uses align end for empty qcow files
end = (end + clusterSize - 1) >> _clusterBits << _clusterBits;
if (_phySize < end)
_phySize = end;
}
}
if (openCallback)
{
UInt64 totalBytes = (UInt64)l1Size << (_numMidBits + 3);
RINOK(openCallback->SetTotal(NULL, &totalBytes));
}
_compressedFlag = (_version <= 1) ? ((UInt64)1 << 63) : ((UInt64)1 << 62);
const UInt64 offsetMask = _compressedFlag - 1;
for (UInt32 i = 0; i < l1Size; i++)
{
if (openCallback)
{
UInt64 numBytes = (UInt64)i << (_numMidBits + 3);
RINOK(openCallback->SetCompleted(NULL, &numBytes));
}
UInt64 v = Get64((const Byte *)table + (size_t)i * 8);
v &= offsetMask;
CByteBuffer &buf = _tables.AddNew();
if (v == 0)
continue;
buf.Alloc((size_t)1 << (_numMidBits + 3));
RINOK(stream->Seek(v, STREAM_SEEK_SET, NULL));
RINOK(ReadStream_FALSE(stream, buf, clusterSize));
UInt64 end = v + clusterSize;
if (_phySize < end)
_phySize = end;
for (size_t k = 0; k < clusterSize; k += 8)
{
UInt64 v = Get64((const Byte *)buf + (size_t)k);
if (v == 0)
continue;
UInt64 offset = v & offsetMask;
size_t dataSize = clusterSize;
if ((v & _compressedFlag) != 0)
{
if (_version <= 1)
{
unsigned numOffsetBits = (63 - _clusterBits);
dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9;
offset &= ((UInt64)1 << numOffsetBits) - 1;
dataSize = 0;
// offset >>= 9;
// offset <<= 9;
}
else
{
unsigned numOffsetBits = (62 - (_clusterBits - 8));
dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9;
offset &= ((UInt64)1 << numOffsetBits) - 1;
offset >>= 9;
offset <<= 9;
}
_needDeflate = true;
}
else
{
UInt32 low = (UInt32)v & 511;
if (low != 0)
{
// version 3 support zero clusters
if (_version < 3 || low != 1)
{
_unsupported = true;
return S_FALSE;
}
}
}
UInt64 end = offset + dataSize;
if (_phySize < end)
_phySize = end;
}
}
if (_cryptMethod != 0)
_unsupported = true;
if (_needDeflate && _version <= 1) // that case was not implemented
_unsupported = true;
Stream = stream;
return S_OK;
}
STDMETHODIMP CHandler::Close()
{
_tables.Clear();
_phySize = 0;
_size = 0;
_cacheCluster = (UInt64)(Int64)-1;
_comprPos = 0;
_comprSize = 0;
_needDeflate = false;
_isArc = false;
_unsupported = false;
_imgExt = NULL;
Stream.Release();
return S_OK;
}
STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)
{
COM_TRY_BEGIN
*stream = NULL;
if (_unsupported)
return S_FALSE;
if (_needDeflate)
{
if (_version <= 1)
return S_FALSE;
if (!_bufInStream)
{
_bufInStreamSpec = new CBufInStream;
_bufInStream = _bufInStreamSpec;
}
if (!_bufOutStream)
{
_bufOutStreamSpec = new CBufPtrSeqOutStream();
_bufOutStream = _bufOutStreamSpec;
}
if (!_deflateDecoder)
{
_deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder();
_deflateDecoder = _deflateDecoderSpec;
_deflateDecoderSpec->Set_NeedFinishInput(true);
}
size_t clusterSize = (size_t)1 << _clusterBits;
_cache.AllocAtLeast(clusterSize);
_cacheCompressed.AllocAtLeast(clusterSize * 2);
}
CMyComPtr<ISequentialInStream> streamTemp = this;
RINOK(InitAndSeek());
*stream = streamTemp.Detach();
return S_OK;
COM_TRY_END
}
REGISTER_ARC_I(
"QCOW", "qcow qcow2 qcow2c", NULL, 0xCA,
k_Signature,
0,
0,
NULL)
}}

View File

@@ -17,110 +17,110 @@ inline bool IsDigit(wchar_t c)
class CVolumeName
{
bool _first;
bool _newStyle;
UString _unchangedPart;
UString _changedPart;
UString _afterPart;
bool _needChangeForNext;
UString _before;
UString _changed;
UString _after;
public:
CVolumeName(): _newStyle(true) {};
CVolumeName(): _needChangeForNext(true) {};
bool InitName(const UString &name, bool newStyle = true)
{
_first = true;
_newStyle = newStyle;
_needChangeForNext = true;
_after.Empty();
UString base = name;
int dotPos = name.ReverseFind_Dot();
UString basePart = name;
if (dotPos >= 0)
{
UString ext = name.Ptr(dotPos + 1);
const UString ext = name.Ptr(dotPos + 1);
if (ext.IsEqualTo_Ascii_NoCase("rar"))
{
_afterPart = name.Ptr(dotPos);
basePart = name.Left(dotPos);
_after = name.Ptr(dotPos);
base.DeleteFrom(dotPos);
}
else if (ext.IsEqualTo_Ascii_NoCase("exe"))
{
_afterPart.SetFromAscii(".rar");
basePart = name.Left(dotPos);
_after.SetFromAscii(".rar");
base.DeleteFrom(dotPos);
}
else if (!_newStyle)
else if (!newStyle)
{
if (ext.IsEqualTo_Ascii_NoCase("000") ||
ext.IsEqualTo_Ascii_NoCase("001") ||
ext.IsEqualTo_Ascii_NoCase("r00") ||
ext.IsEqualTo_Ascii_NoCase("r01"))
{
_afterPart.Empty();
_first = false;
_changedPart = ext;
_unchangedPart = name.Left(dotPos + 1);
_changed = ext;
_before = name.Left(dotPos + 1);
return true;
}
}
}
if (!_newStyle)
if (newStyle)
{
_afterPart.Empty();
_unchangedPart = basePart;
_unchangedPart += L'.';
_changedPart.SetFromAscii("r00");
return true;
unsigned i = base.Len();
for (; i != 0; i--)
if (!IsDigit(base[i - 1]))
break;
if (i != base.Len())
{
_before = base.Left(i);
_changed = base.Ptr(i);
return true;
}
}
if (basePart.IsEmpty())
return false;
unsigned i = basePart.Len();
do
if (!IsDigit(basePart[i - 1]))
break;
while (--i);
_unchangedPart = basePart.Left(i);
_changedPart = basePart.Ptr(i);
_after.Empty();
_before = base;
_before += L'.';
_changed.SetFromAscii("r00");
_needChangeForNext = false;
return true;
}
/*
void MakeBeforeFirstName()
{
unsigned len = _changedPart.Len();
_changedPart.Empty();
unsigned len = _changed.Len();
_changed.Empty();
for (unsigned i = 0; i < len; i++)
_changedPart += L'0';
_changed += L'0';
}
*/
UString GetNextName()
{
if (_newStyle || !_first)
if (_needChangeForNext)
{
unsigned i = _changedPart.Len();
unsigned i = _changed.Len();
if (i == 0)
return UString();
for (;;)
{
wchar_t c = _changedPart[--i];
wchar_t c = _changed[--i];
if (c == L'9')
{
c = L'0';
_changedPart.ReplaceOneCharAtPos(i, c);
_changed.ReplaceOneCharAtPos(i, c);
if (i == 0)
{
_changedPart.InsertAtFront(L'1');
_changed.InsertAtFront(L'1');
break;
}
continue;
}
c++;
_changedPart.ReplaceOneCharAtPos(i, c);
_changed.ReplaceOneCharAtPos(i, c);
break;
}
}
_first = false;
return _unchangedPart + _changedPart + _afterPart;
_needChangeForNext = true;
return _before + _changed + _after;
}
};

View File

@@ -4,21 +4,19 @@
#include "../../../C/CpuArch.h"
#include "../../Common/MyBuffer.h"
#include "../../Common/ComTry.h"
#include "../../Common/IntToString.h"
#include "../../Common/MyString.h"
#include "../../Common/StringConvert.h"
#include "../../Common/UTFConvert.h"
#include "../../Windows/PropVariant.h"
#include "../../Windows/TimeUtils.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamUtils.h"
#include "../Compress/CopyCoder.h"
#include "HandlerCont.h"
// #define _SHOW_RPM_METADATA
@@ -169,13 +167,8 @@ struct CEntry
}
};
class CHandler:
public IInArchive,
public IInArchiveGetStream,
public CMyUnknownImp
class CHandler: public CHandlerCont
{
CMyComPtr<IInStream> _stream;
UInt64 _headersSize; // is equal to start offset of payload data
UInt64 _payloadSize;
UInt64 _size;
@@ -232,10 +225,11 @@ class CHandler:
HRESULT ReadHeader(ISequentialInStream *stream, bool isMainHeader);
HRESULT Open2(ISequentialInStream *stream);
virtual UInt64 GetItemPos(UInt32) const { return _headersSize; }
virtual UInt64 GetItemSize(UInt32) const { return _size; }
public:
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
INTERFACE_IInArchive_Cont(;)
};
static const Byte kArcProps[] =
@@ -728,50 +722,6 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
if (numItems == 0)
return S_OK;
if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
RINOK(extractCallback->SetTotal(_size));
CMyComPtr<ISequentialOutStream> outStream;
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
RINOK(extractCallback->GetStream(0, &outStream, askMode));
if (!testMode && !outStream)
return S_OK;
RINOK(extractCallback->PrepareOperation(askMode));
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
RINOK(_stream->Seek(_headersSize, STREAM_SEEK_SET, NULL));
RINOK(copyCoder->Code(_stream, outStream, NULL, &_size, progress));
outStream.Release();
Int32 opRes = NExtract::NOperationResult::kOK;
if (copyCoderSpec->TotalSize < _size)
opRes = NExtract::NOperationResult::kUnexpectedEnd;
return extractCallback->SetOperationResult(opRes);
COM_TRY_END
}
STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)
{
COM_TRY_BEGIN
return CreateLimitedInStream(_stream, _headersSize, _size, stream);
COM_TRY_END
}
static const Byte k_Signature[] = { 0xED, 0xAB, 0xEE, 0xDB};
REGISTER_ARC_I(

View File

@@ -12,7 +12,7 @@ namespace NTar {
static const Byte k_Signature[] = { 'u', 's', 't', 'a', 'r' };
REGISTER_ARC_IO(
"tar", "tar", 0, 0xEE,
"tar", "tar ova", 0, 0xEE,
k_Signature,
NFileHeader::kUstarMagic_Offset,
NArcInfoFlags::kStartOpen |

View File

@@ -0,0 +1,362 @@
// VdiHandler.cpp
#include "StdAfx.h"
// #include <stdio.h>
#include "../../../C/CpuArch.h"
#include "../../Common/ComTry.h"
#include "../../Common/IntToString.h"
#include "../../Common/MyBuffer.h"
#include "../../Windows/PropVariant.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamUtils.h"
#include "HandlerCont.h"
#define Get32(p) GetUi32(p)
#define Get64(p) GetUi64(p)
using namespace NWindows;
namespace NArchive {
namespace NVdi {
#define SIGNATURE { 0x7F, 0x10, 0xDA, 0xBE }
static const Byte k_Signature[] = SIGNATURE;
static const unsigned k_ClusterBits = 20;
static const UInt32 k_ClusterSize = (UInt32)1 << k_ClusterBits;
static const UInt32 k_UnusedCluster = 0xFFFFFFFF;
// static const UInt32 kDiskType_Dynamic = 1;
// static const UInt32 kDiskType_Static = 2;
static const char * const kDiskTypes[] =
{
"0"
, "Dynamic"
, "Static"
};
class CHandler: public CHandlerImg
{
UInt32 _dataOffset;
CByteBuffer _table;
UInt64 _phySize;
UInt32 _imageType;
bool _isArc;
bool _unsupported;
HRESULT Seek(UInt64 offset)
{
_posInArc = offset;
return Stream->Seek(offset, STREAM_SEEK_SET, NULL);
}
HRESULT InitAndSeek()
{
_virtPos = 0;
return Seek(0);
}
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback);
public:
INTERFACE_IInArchive_Img(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
};
STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
{
if (processedSize)
*processedSize = 0;
if (_virtPos >= _size)
return S_OK;
{
UInt64 rem = _size - _virtPos;
if (size > rem)
size = (UInt32)rem;
if (size == 0)
return S_OK;
}
{
UInt64 cluster = _virtPos >> k_ClusterBits;
UInt32 lowBits = (UInt32)_virtPos & (k_ClusterSize - 1);
{
UInt32 rem = k_ClusterSize - lowBits;
if (size > rem)
size = rem;
}
cluster <<= 2;
if (cluster < _table.Size())
{
const Byte *p = (const Byte *)_table + (size_t)cluster;
UInt32 v = Get32(p);
if (v != k_UnusedCluster)
{
UInt64 offset = _dataOffset + ((UInt64)v << k_ClusterBits);
offset += lowBits;
if (offset != _posInArc)
{
RINOK(Seek(offset));
}
HRESULT res = Stream->Read(data, size, &size);
_posInArc += size;
_virtPos += size;
if (processedSize)
*processedSize = size;
return res;
}
}
memset(data, 0, size);
_virtPos += size;
if (processedSize)
*processedSize = size;
return S_OK;
}
}
static const Byte kProps[] =
{
kpidSize,
kpidPackSize
};
static const Byte kArcProps[] =
{
kpidHeadersSize,
kpidMethod
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
switch (propID)
{
case kpidMainSubfile: prop = (UInt32)0; break;
case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
case kpidHeadersSize: prop = _dataOffset; break;
case kpidMethod:
{
char s[16];
const char *ptr;
if (_imageType < ARRAY_SIZE(kDiskTypes))
ptr = kDiskTypes[_imageType];
else
{
ConvertUInt32ToString(_imageType, s);
ptr = s;
}
prop = ptr;
break;
}
case kpidErrorFlags:
{
UInt32 v = 0;
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;;
if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
// if (_headerError) v |= kpv_ErrorFlags_HeadersError;
if (!Stream && v == 0 && _isArc)
v = kpv_ErrorFlags_HeadersError;
if (v != 0)
prop = v;
break;
}
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
switch (propID)
{
case kpidSize: prop = _size; break;
case kpidPackSize: prop = _phySize - _dataOffset; break;
case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
static bool IsEmptyGuid(const Byte *data)
{
for (unsigned i = 0; i < 16; i++)
if (data[i] != 0)
return false;
return true;
}
HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback * /* openCallback */)
{
const unsigned kHeaderSize = 512;
Byte buf[kHeaderSize];
RINOK(ReadStream_FALSE(stream, buf, kHeaderSize));
if (memcmp(buf + 0x40, k_Signature, sizeof(k_Signature)) != 0)
return S_FALSE;
UInt32 version = Get32(buf + 0x44);
if (version >= 0x20000)
return S_FALSE;
UInt32 headerSize = Get32(buf + 0x48);
if (headerSize < 0x140 || headerSize > 0x1B8)
return S_FALSE;
_imageType = Get32(buf + 0x4C);
_dataOffset = Get32(buf + 0x158);
UInt32 tableOffset = Get32(buf + 0x154);
if (tableOffset < 0x200)
return S_FALSE;
UInt32 sectorSize = Get32(buf + 0x168);
if (sectorSize != 0x200)
return S_FALSE;
_size = Get64(buf + 0x170);
_isArc = true;
if (_imageType > 2)
{
_unsupported = true;
return S_FALSE;
}
if (_dataOffset < tableOffset)
return S_FALSE;
UInt32 blockSize = Get32(buf + 0x178);
if (blockSize != ((UInt32)1 << k_ClusterBits))
{
_unsupported = true;
return S_FALSE;
}
UInt32 totalBlocks = Get32(buf + 0x180);
{
UInt64 size2 = (UInt64)totalBlocks << k_ClusterBits;
if (size2 < _size)
{
_unsupported = true;
return S_FALSE;
}
/*
if (size2 > _size)
_size = size2;
*/
}
if (headerSize >= 0x180)
{
if (!IsEmptyGuid(buf + 0x1A8) ||
!IsEmptyGuid(buf + 0x1B8))
{
_unsupported = true;
return S_FALSE;
}
}
UInt32 numAllocatedBlocks = Get32(buf + 0x184);
{
UInt32 tableReserved = _dataOffset - tableOffset;
if ((tableReserved >> 2) < totalBlocks)
return S_FALSE;
}
_phySize = _dataOffset + ((UInt64)numAllocatedBlocks << k_ClusterBits);
size_t numBytes = (size_t)totalBlocks * 4;
if ((numBytes >> 2) != totalBlocks)
{
_unsupported = true;
return S_FALSE;
}
_table.Alloc(numBytes);
RINOK(stream->Seek(tableOffset, STREAM_SEEK_SET, NULL));
RINOK(ReadStream_FALSE(stream, _table, numBytes));
const Byte *data = _table;
for (UInt32 i = 0; i < totalBlocks; i++)
{
UInt32 v = Get32(data + (size_t)i * 4);
if (v == k_UnusedCluster)
continue;
if (v >= numAllocatedBlocks)
return S_FALSE;
}
Stream = stream;
return S_OK;
}
STDMETHODIMP CHandler::Close()
{
_table.Free();
_phySize = 0;
_size = 0;
_isArc = false;
_unsupported = false;
_imgExt = NULL;
Stream.Release();
return S_OK;
}
STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)
{
COM_TRY_BEGIN
*stream = NULL;
if (_unsupported)
return S_FALSE;
CMyComPtr<ISequentialInStream> streamTemp = this;
RINOK(InitAndSeek());
*stream = streamTemp.Detach();
return S_OK;
COM_TRY_END
}
REGISTER_ARC_I(
"VDI", "vdi", NULL, 0xC9,
k_Signature,
0x40,
0,
NULL)
}}

View File

@@ -10,11 +10,10 @@
#include "../../Windows/PropVariant.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamUtils.h"
#include "../Compress/CopyCoder.h"
#include "HandlerCont.h"
#define Get16(p) GetBe16(p)
#define Get32(p) GetBe32(p)
@@ -217,14 +216,8 @@ bool CDynHeader::Parse(const Byte *p)
return CheckBlock(p, 1024, 0x24, 0x240 + 8 * 24);
}
class CHandler:
public IInStream,
public IInArchive,
public IInArchiveGetStream,
public CMyUnknownImp
class CHandler: public CHandlerImg
{
UInt64 _virtPos;
UInt64 _posInArc;
UInt64 _posInArcLimit;
UInt64 _startOffset;
UInt64 _phySize;
@@ -235,7 +228,7 @@ class CHandler:
CByteBuffer BitMap;
UInt32 BitMapTag;
UInt32 NumUsedBlocks;
CMyComPtr<IInStream> Stream;
// CMyComPtr<IInStream> Stream;
CMyComPtr<IInStream> ParentStream;
CHandler *Parent;
UString _errorMessage;
@@ -309,14 +302,17 @@ class CHandler:
HRESULT Open3();
HRESULT Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, unsigned level);
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback)
{
return Open2(stream, NULL, openArchiveCallback, 0);
}
void CloseAtError();
public:
MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream)
INTERFACE_IInArchive_Img(;)
INTERFACE_IInArchive(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
};
HRESULT CHandler::Seek(UInt64 offset) { return Stream->Seek(_startOffset + offset, STREAM_SEEK_SET, NULL); }
@@ -360,6 +356,7 @@ HRESULT CHandler::Open3()
Byte header[kHeaderSize];
RINOK(ReadStream_FALSE(Stream, header, kHeaderSize));
bool headerIsOK = Footer.Parse(header);
_size = Footer.CurrentSize;
if (headerIsOK && !Footer.ThereIsDynamic())
{
@@ -388,6 +385,7 @@ HRESULT CHandler::Open3()
{
if (!Footer.Parse(buf))
return S_FALSE;
_size = Footer.CurrentSize;
if (Footer.ThereIsDynamic())
return S_FALSE; // we can't open Dynamic Archive backward.
_posInArcLimit = Footer.CurrentSize;
@@ -594,22 +592,6 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
return res;
}
STDMETHODIMP CHandler::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
{
switch (seekOrigin)
{
case STREAM_SEEK_SET: break;
case STREAM_SEEK_CUR: offset += _virtPos; break;
case STREAM_SEEK_END: offset += Footer.CurrentSize; break;
default: return STG_E_INVALIDFUNCTION;
}
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
_virtPos = offset;
if (newPosition)
*newPosition = offset;
return S_OK;
}
enum
{
@@ -842,31 +824,7 @@ HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback
return S_OK;
}
STDMETHODIMP CHandler::Open(IInStream *stream,
const UInt64 * /* maxCheckStartPosition */,
IArchiveOpenCallback * openArchiveCallback)
{
COM_TRY_BEGIN
{
HRESULT res;
try
{
res = Open2(stream, NULL, openArchiveCallback, 0);
if (res == S_OK)
return S_OK;
}
catch(...)
{
Close();
throw;
}
Close();
return res;
}
COM_TRY_END
}
STDMETHODIMP CHandler::Close()
void CHandler::CloseAtError()
{
_phySize = 0;
Bat.Clear();
@@ -877,89 +835,40 @@ STDMETHODIMP CHandler::Close()
Dyn.Clear();
_errorMessage.Empty();
// _unexpectedEnd = false;
return S_OK;
_imgExt = NULL;
}
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
STDMETHODIMP CHandler::Close()
{
*numItems = 1;
CloseAtError();
return S_OK;
}
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
{
// COM_TRY_BEGIN
COM_TRY_BEGIN
NCOM::CPropVariant prop;
switch(propID)
switch (propID)
{
case kpidSize: prop = Footer.CurrentSize; break;
case kpidPackSize: prop = GetPackSize(); break;
case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break;
case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
/*
case kpidNumCyls: prop = Footer.NumCyls(); break;
case kpidNumHeads: prop = Footer.NumHeads(); break;
case kpidSectorsPerTrack: prop = Footer.NumSectorsPerTrack(); break;
*/
}
prop.Detach(value);
return S_OK;
// COM_TRY_END
}
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
if (numItems == 0)
return S_OK;
if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
RINOK(extractCallback->SetTotal(Footer.CurrentSize));
CMyComPtr<ISequentialOutStream> outStream;
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
RINOK(extractCallback->GetStream(0, &outStream, askMode));
if (!testMode && !outStream)
return S_OK;
RINOK(extractCallback->PrepareOperation(askMode));
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
int res = NExtract::NOperationResult::kDataError;
CMyComPtr<ISequentialInStream> inStream;
HRESULT hres = GetStream(0, &inStream);
if (hres == S_FALSE)
res = NExtract::NOperationResult::kUnsupportedMethod;
else
{
RINOK(hres);
HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
if (hres == S_OK)
{
if (copyCoderSpec->TotalSize == Footer.CurrentSize)
res = NExtract::NOperationResult::kOK;
}
else
{
if (hres != S_FALSE)
{
RINOK(hres);
}
}
}
outStream.Release();
return extractCallback->SetOperationResult(res);
COM_TRY_END
}
STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)
{
COM_TRY_BEGIN
@@ -984,7 +893,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea
}
REGISTER_ARC_I(
"VHD", "vhd", ".mbr", 0xDC,
"VHD", "vhd", NULL, 0xDC,
kSignature,
0,
NArcInfoFlags::kUseGlobalOffset,

View File

@@ -0,0 +1,890 @@
// VmdkHandler.cpp
#include "StdAfx.h"
// #include <stdio.h>
#include "../../../C/CpuArch.h"
#include "../../Common/ComTry.h"
#include "../../Common/IntToString.h"
#include "../../Windows/PropVariant.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamObjects.h"
#include "../Common/StreamUtils.h"
#include "../Compress/ZlibDecoder.h"
#include "HandlerCont.h"
#define Get16(p) GetUi16(p)
#define Get32(p) GetUi32(p)
#define Get64(p) GetUi64(p)
using namespace NWindows;
namespace NArchive {
namespace NVmdk {
#define SIGNATURE { 'K', 'D', 'M', 'V' }
static const Byte k_Signature[] = SIGNATURE;
static const UInt32 k_Flags_NL = (UInt32)1 << 0;
static const UInt32 k_Flags_RGD = (UInt32)1 << 1;
static const UInt32 k_Flags_ZeroGrain = (UInt32)1 << 2;
static const UInt32 k_Flags_Compressed = (UInt32)1 << 16;
static const UInt32 k_Flags_Marker = (UInt32)1 << 17;
static const unsigned k_NumMidBits = 9; // num bits for index in Grain Table
struct CHeader
{
UInt32 flags;
UInt32 version;
UInt64 capacity;
UInt64 grainSize;
UInt64 descriptorOffset;
UInt64 descriptorSize;
UInt32 numGTEsPerGT;
UInt16 algo;
// Byte uncleanShutdown;
// UInt64 rgdOffset;
UInt64 gdOffset;
UInt64 overHead;
bool Is_NL() const { return (flags & k_Flags_NL) != 0; };
bool Is_ZeroGrain() const { return (flags & k_Flags_ZeroGrain) != 0; };
bool Is_Compressed() const { return (flags & k_Flags_Compressed) != 0; };
bool Is_Marker() const { return (flags & k_Flags_Marker) != 0; };
bool Parse(const Byte *buf);
bool IsSameImageFor(const CHeader &h) const
{
return flags == h.flags
&& version == h.version
&& capacity == h.capacity
&& grainSize == h.grainSize
&& algo == h.algo;
}
};
bool CHeader::Parse(const Byte *buf)
{
if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0)
return false;
version = Get32(buf + 0x4);
flags = Get32(buf + 0x8);
capacity = Get64(buf + 0xC);
grainSize = Get64(buf + 0x14);
descriptorOffset = Get64(buf + 0x1C);
descriptorSize = Get64(buf + 0x24);
numGTEsPerGT = Get32(buf + 0x2C);
// rgdOffset = Get64(buf + 0x30);
gdOffset = Get64(buf + 0x38);
overHead = Get64(buf + 0x40);
// uncleanShutdown = buf[0x48];
algo = Get16(buf + 0x4D);
if (Is_NL() && Get32(buf + 0x49) != 0x0A0D200A) // do we need Is_NL() check here?
return false;
return (numGTEsPerGT == (1 << k_NumMidBits)) && (version <= 3);
}
enum
{
k_Marker_END_OF_STREAM = 0,
k_Marker_GRAIN_TABLE = 1,
k_Marker_GRAIN_DIR = 2,
k_Marker_FOOTER = 3
};
struct CMarker
{
UInt64 NumSectors;
UInt32 SpecSize; // = 0 for metadata sectors
UInt32 Type;
void Parse(const Byte *p)
{
NumSectors = Get64(p);
SpecSize = Get32(p + 8);
Type = Get32(p + 12);
}
};
struct CDescriptor
{
AString CID;
AString parentCID;
AString createType;
AStringVector Extents;
void Clear()
{
CID.Empty();
parentCID.Empty();
createType.Empty();
Extents.Clear();
}
void Parse(const Byte *p, size_t size);
};
static bool Str_to_ValName(const AString &s, AString &name, AString &val)
{
name.Empty();
val.Empty();
int qu = s.Find('"');
int eq = s.Find('=');
if (eq < 0 || (qu >= 0 && eq > qu))
return false;
name = s.Left(eq);
name.Trim();
val = s.Ptr(eq + 1);
val.Trim();
return true;
}
void CDescriptor::Parse(const Byte *p, size_t size)
{
Clear();
AString s;
AString name;
AString val;
for (size_t i = 0;; i++)
{
char c = p[i];
if (i == size || c == 0 || c == 0xA || c == 0xD)
{
if (!s.IsEmpty() && s[0] != '#')
{
if (Str_to_ValName(s, name, val))
{
if (name.IsEqualTo_Ascii_NoCase("CID"))
CID = val;
else if (name.IsEqualTo_Ascii_NoCase("parentCID"))
parentCID = val;
else if (name.IsEqualTo_Ascii_NoCase("createType"))
createType = val;
}
else
Extents.Add(s);
}
s.Empty();
if (c == 0 || i >= size)
break;
}
else
s += (char)c;
}
}
class CHandler: public CHandlerImg
{
unsigned _clusterBits;
CObjectVector<CByteBuffer> _tables;
UInt64 _cacheCluster;
CByteBuffer _cache;
CByteBuffer _cacheCompressed;
UInt64 _phySize;
UInt32 _zeroSector;
bool _needDeflate;
bool _isArc;
bool _unsupported;
// bool _headerError;
CBufInStream *_bufInStreamSpec;
CMyComPtr<ISequentialInStream> _bufInStream;
CBufPtrSeqOutStream *_bufOutStreamSpec;
CMyComPtr<ISequentialOutStream> _bufOutStream;
NCompress::NZlib::CDecoder *_zlibDecoderSpec;
CMyComPtr<ICompressCoder> _zlibDecoder;
CByteBuffer _descriptorBuf;
CDescriptor _descriptor;
CHeader h;
HRESULT Seek(UInt64 offset)
{
_posInArc = offset;
return Stream->Seek(offset, STREAM_SEEK_SET, NULL);
}
HRESULT InitAndSeek()
{
_virtPos = 0;
return Seek(0);
}
HRESULT ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors);
virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback);
public:
INTERFACE_IInArchive_Img(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
};
STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
{
if (processedSize)
*processedSize = 0;
if (_virtPos >= _size)
return S_OK;
{
UInt64 rem = _size - _virtPos;
if (size > rem)
size = (UInt32)rem;
if (size == 0)
return S_OK;
}
for (;;)
{
const UInt64 cluster = _virtPos >> _clusterBits;
const size_t clusterSize = (size_t)1 << _clusterBits;
const size_t lowBits = (size_t)_virtPos & (clusterSize - 1);
{
size_t rem = clusterSize - lowBits;
if (size > rem)
size = (UInt32)rem;
}
if (cluster == _cacheCluster)
{
memcpy(data, _cache + lowBits, size);
_virtPos += size;
if (processedSize)
*processedSize = size;
return S_OK;
}
const UInt64 high = cluster >> k_NumMidBits;
if (high < _tables.Size())
{
const CByteBuffer &table = _tables[(unsigned)high];
if (table.Size() != 0)
{
const size_t midBits = (size_t)cluster & ((1 << k_NumMidBits) - 1);
const Byte *p = (const Byte *)table + (midBits << 2);
const UInt32 v = Get32(p);
if (v != 0 && v != _zeroSector)
{
UInt64 offset = (UInt64)v << 9;
if (_needDeflate)
{
if (offset != _posInArc)
{
// printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - _posInArc));
RINOK(Seek(offset));
}
const size_t kStartSize = 1 << 9;
{
size_t curSize = kStartSize;
HRESULT res = ReadStream(Stream, _cacheCompressed, &curSize);
_posInArc += curSize;
RINOK(res);
if (curSize != kStartSize)
return S_FALSE;
}
if (Get64(_cacheCompressed) != (cluster << (_clusterBits - 9)))
return S_FALSE;
UInt32 dataSize = Get32(_cacheCompressed + 8);
if (dataSize > ((UInt32)1 << 31))
return S_FALSE;
size_t dataSize2 = (size_t)dataSize + 12;
if (dataSize2 > kStartSize)
{
dataSize2 = (dataSize2 + 511) & ~(size_t)511;
if (dataSize2 > _cacheCompressed.Size())
return S_FALSE;
size_t curSize = dataSize2 - kStartSize;
const size_t curSize2 = curSize;
HRESULT res = ReadStream(Stream, _cacheCompressed + kStartSize, &curSize);
_posInArc += curSize;
RINOK(res);
if (curSize != curSize2)
return S_FALSE;
}
_bufInStreamSpec->Init(_cacheCompressed + 12, dataSize);
_cacheCluster = (UInt64)(Int64)-1;
if (_cache.Size() < clusterSize)
return E_FAIL;
_bufOutStreamSpec->Init(_cache, clusterSize);
// Do we need to use smaller block than clusterSize for last cluster?
UInt64 blockSize64 = clusterSize;
HRESULT res = _zlibDecoderSpec->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL);
// if (_bufOutStreamSpec->GetPos() != clusterSize)
// memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos());
if (res == S_OK)
if (_bufOutStreamSpec->GetPos() != clusterSize
|| _zlibDecoderSpec->GetInputProcessedSize() != dataSize)
res = S_FALSE;
RINOK(res);
_cacheCluster = cluster;
continue;
/*
memcpy(data, _cache + lowBits, size);
_virtPos += size;
if (processedSize)
*processedSize = size;
return S_OK;
*/
}
{
offset += lowBits;
if (offset != _posInArc)
{
// printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - _posInArc));
RINOK(Seek(offset));
}
HRESULT res = Stream->Read(data, size, &size);
_posInArc += size;
_virtPos += size;
if (processedSize)
*processedSize = size;
return res;
}
}
}
}
memset(data, 0, size);
_virtPos += size;
if (processedSize)
*processedSize = size;
return S_OK;
}
}
static const Byte kProps[] =
{
kpidSize,
kpidPackSize
};
static const Byte kArcProps[] =
{
kpidClusterSize,
kpidHeadersSize,
kpidMethod,
kpidId,
kpidName,
kpidComment
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
switch (propID)
{
case kpidMainSubfile: prop = (UInt32)0; break;
case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
case kpidClusterSize: prop = (UInt32)1 << _clusterBits; break;
case kpidHeadersSize: prop = (h.overHead << 9); break;
case kpidMethod:
{
AString s;
if (!_descriptor.createType.IsEmpty())
s = _descriptor.createType;
if (h.algo != 0)
{
s.Add_Space_if_NotEmpty();
if (h.algo == 1)
s += "zlib";
else
{
char temp[16];
ConvertUInt32ToString(h.algo, temp);
s += temp;
}
}
if (h.Is_Marker())
{
s.Add_Space_if_NotEmpty();
s += "Marker";
}
if (!s.IsEmpty())
prop = s;
break;
}
case kpidComment:
{
if (_descriptorBuf.Size() != 0)
{
AString s;
s.SetFrom_CalcLen((const char *)(const Byte *)_descriptorBuf, (unsigned)_descriptorBuf.Size());
if (!s.IsEmpty() && s.Len() <= (1 << 16))
prop = s;
}
break;
}
case kpidId:
if (!_descriptor.CID.IsEmpty())
{
prop = _descriptor.CID;
break;
}
case kpidName:
{
if (_descriptor.Extents.Size() == 1)
{
const AString &s = _descriptor.Extents[0];
if (!s.IsEmpty())
{
if (s.Back() == '"')
{
AString s2 = s;
s2.DeleteBack();
if (s2.Len() > 5 && StringsAreEqualNoCase_Ascii(s2.RightPtr(5), ".vmdk"))
{
int pos = s2.ReverseFind('"');
if (pos >= 0)
{
s2.DeleteFrontal(pos + 1);
prop = s2;
}
}
}
}
}
break;
}
case kpidErrorFlags:
{
UInt32 v = 0;
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;;
if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
// if (_headerError) v |= kpv_ErrorFlags_HeadersError;
if (!Stream && v == 0 && _isArc)
v = kpv_ErrorFlags_HeadersError;
if (v != 0)
prop = v;
break;
}
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
switch (propID)
{
case kpidSize: prop = _size; break;
case kpidPackSize:
{
UInt64 ov = (h.overHead << 9);
if (_phySize >= ov)
prop = _phySize - ov;
break;
}
case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
static int inline GetLog(UInt64 num)
{
for (int i = 0; i < 64; i++)
if (((UInt64)1 << i) == num)
return i;
return -1;
}
HRESULT CHandler::ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors)
{
sector <<= 9;
RINOK(stream->Seek(sector, STREAM_SEEK_SET, NULL));
size_t size = numSectors << 9;
RINOK(ReadStream_FALSE(stream, data, size));
UInt64 end = sector + size;
if (_phySize < end)
_phySize = end;
return S_OK;
}
HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
{
const unsigned kSectoreSize = 512;
Byte buf[kSectoreSize];
size_t headerSize = kSectoreSize;
RINOK(ReadStream(stream, buf, &headerSize));
if (headerSize < sizeof(k_Signature))
return S_FALSE;
if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0)
{
const char *kSignature_Descriptor = "# Disk DescriptorFile";
size_t k_SigDesc_Size = strlen(kSignature_Descriptor);
if (headerSize >= k_SigDesc_Size)
if (memcmp(buf, kSignature_Descriptor, k_SigDesc_Size) == 0)
{
_unsupported = true;
_isArc = true;
// return E_NOTIMPL;
}
return S_FALSE;
}
if (headerSize != kSectoreSize)
return S_FALSE;
// CHeader h;
if (!h.Parse(buf))
return S_FALSE;
if (h.descriptorSize != 0)
{
if (h.descriptorOffset < 1)
return S_FALSE;
if (h.descriptorSize > (1 << 20))
return S_FALSE;
size_t numBytes = (size_t)h.descriptorSize << 9;
_descriptorBuf.Alloc(numBytes);
RINOK(ReadForHeader(stream, h.descriptorOffset, _descriptorBuf, (size_t)h.descriptorSize));
if (h.descriptorOffset == 1 && h.Is_Marker() && Get64(_descriptorBuf) == 0)
{
// We check data as end marker.
// and if probably it's footer's copy of header, we don't want to open it.
return S_FALSE;
}
}
if (h.gdOffset == (UInt64)(Int64)-1)
{
// Grain Dir is at end of file
UInt64 endPos;
RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
if ((endPos & 511) != 0)
return S_FALSE;
const size_t kEndSize = 512 * 3;
Byte buf2[kEndSize];
if (endPos < kEndSize)
return S_FALSE;
RINOK(stream->Seek(endPos - kEndSize, STREAM_SEEK_SET, NULL));
RINOK(ReadStream_FALSE(stream, buf2, kEndSize));
CHeader h2;
if (!h2.Parse(buf2 + 512))
return S_FALSE;
if (!h.IsSameImageFor(h2))
return S_FALSE;
h = h2;
CMarker m;
m.Parse(buf2);
if (m.NumSectors != 1 || m.SpecSize != 0 || m.Type != k_Marker_FOOTER)
return S_FALSE;
m.Parse(buf2 + 512 * 2);
if (m.NumSectors != 0 || m.SpecSize != 0 || m.Type != k_Marker_END_OF_STREAM)
return S_FALSE;
_phySize = endPos;
}
int grainSize_Log = GetLog(h.grainSize);
if (grainSize_Log < 3 || grainSize_Log > 30 - 9) // grain size must be >= 4 KB
return S_FALSE;
if (h.capacity >= ((UInt64)1 << (63 - 9)))
return S_FALSE;
if (h.overHead >= ((UInt64)1 << (63 - 9)))
return S_FALSE;
_isArc = true;
_clusterBits = (9 + grainSize_Log);
_size = h.capacity << 9;
_needDeflate = (h.algo >= 1);
if (h.Is_Compressed() ? (h.algo > 1 || !h.Is_Marker()) : (h.algo != 0))
{
_unsupported = true;
_phySize = 0;
return S_FALSE;
}
{
UInt64 overHeadBytes = h.overHead << 9;
if (_phySize < overHeadBytes)
_phySize = overHeadBytes;
}
_zeroSector = 0;
if (h.Is_ZeroGrain())
_zeroSector = 1;
const UInt64 numSectorsPerGde = (UInt64)1 << (grainSize_Log + k_NumMidBits);
const UInt64 numGdeEntries = (h.capacity + numSectorsPerGde - 1) >> (grainSize_Log + k_NumMidBits);
CByteBuffer table;
if (numGdeEntries != 0)
{
if (h.gdOffset == 0)
return S_FALSE;
size_t numSectors = (size_t)((numGdeEntries + ((1 << (9 - 2)) - 1)) >> (9 - 2));
size_t t1SizeBytes = numSectors << 9;
if ((t1SizeBytes >> 2) < numGdeEntries)
return S_FALSE;
table.Alloc(t1SizeBytes);
if (h.Is_Marker())
{
Byte buf2[1 << 9];
if (ReadForHeader(stream, h.gdOffset - 1, buf2, 1) != S_OK)
return S_FALSE;
{
CMarker m;
m.Parse(buf2);
if (m.Type != k_Marker_GRAIN_DIR
|| m.NumSectors != numSectors
|| m.SpecSize != 0)
return S_FALSE;
}
}
RINOK(ReadForHeader(stream, h.gdOffset, table, numSectors));
}
size_t clusterSize = (size_t)1 << _clusterBits;
if (openCallback)
{
UInt64 totalBytes = (UInt64)numGdeEntries << (k_NumMidBits + 2);
RINOK(openCallback->SetTotal(NULL, &totalBytes));
}
UInt64 lastSector = 0;
UInt64 lastVirtCluster = 0;
size_t numProcessed_Prev = 0;
for (size_t i = 0; i < numGdeEntries; i++)
{
UInt32 v = Get32((const Byte *)table + (size_t)i * 4);
CByteBuffer &buf = _tables.AddNew();
if (v == 0 || v == _zeroSector)
continue;
if (openCallback && ((i - numProcessed_Prev) & 0xFFF) == 0)
{
UInt64 numBytes = (UInt64)i << (k_NumMidBits + 2);
RINOK(openCallback->SetCompleted(NULL, &numBytes));
numProcessed_Prev = i;
}
const size_t k_NumSectors = (size_t)1 << (k_NumMidBits - 9 + 2);
if (h.Is_Marker())
{
Byte buf2[1 << 9];
if (ReadForHeader(stream, v - 1, buf2, 1) != S_OK)
return S_FALSE;
{
CMarker m;
m.Parse(buf2);
if (m.Type != k_Marker_GRAIN_TABLE
|| m.NumSectors != k_NumSectors
|| m.SpecSize != 0)
return S_FALSE;
}
}
const size_t k_NumMidItems = (size_t)1 << k_NumMidBits;
buf.Alloc(k_NumMidItems * 4);
RINOK(ReadForHeader(stream, v, buf, k_NumSectors));
for (size_t k = 0; k < k_NumMidItems; k++)
{
UInt32 v = Get32((const Byte *)buf + (size_t)k * 4);
if (v == 0 || v == _zeroSector)
continue;
if (v < h.overHead)
return S_FALSE;
if (lastSector < v)
{
lastSector = v;
if (_needDeflate)
lastVirtCluster = ((UInt64)i << k_NumMidBits) + k;
}
}
}
if (!_needDeflate)
{
UInt64 end = ((UInt64)lastSector << 9) + clusterSize;
if (_phySize < end)
_phySize = end;
}
else if (lastSector != 0)
{
Byte buf[1 << 9];
if (ReadForHeader(stream, lastSector, buf, 1) == S_OK)
{
UInt64 lba = Get64(buf);
if (lba == (lastVirtCluster << (_clusterBits - 9)))
{
UInt32 dataSize = Get32(buf + 8);
size_t dataSize2 = (size_t)dataSize + 12;
dataSize2 = (dataSize2 + 511) & ~(size_t)511;
UInt64 end = ((UInt64)lastSector << 9) + dataSize2;
if (_phySize < end)
_phySize = end;
}
}
}
if (_descriptorBuf.Size() != 0)
{
_descriptor.Parse(_descriptorBuf, _descriptorBuf.Size());
if (!_descriptor.parentCID.IsEmpty())
if (!_descriptor.parentCID.IsEqualTo_Ascii_NoCase("ffffffff"))
_unsupported = true;
}
Stream = stream;
return S_OK;
}
STDMETHODIMP CHandler::Close()
{
_phySize = 0;
_size = 0;
_cacheCluster = (UInt64)(Int64)-1;
_zeroSector = 0;
_clusterBits = 0;
_needDeflate = false;
_isArc = false;
_unsupported = false;
// _headerError = false;
_tables.Clear();
_descriptorBuf.Free();
_descriptor.Clear();
_imgExt = NULL;
Stream.Release();
return S_OK;
}
STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)
{
COM_TRY_BEGIN
*stream = 0;
if (_unsupported)
return S_FALSE;
if (_needDeflate)
{
if (!_bufInStream)
{
_bufInStreamSpec = new CBufInStream;
_bufInStream = _bufInStreamSpec;
}
if (!_bufOutStream)
{
_bufOutStreamSpec = new CBufPtrSeqOutStream();
_bufOutStream = _bufOutStreamSpec;
}
if (!_zlibDecoder)
{
_zlibDecoderSpec = new NCompress::NZlib::CDecoder;
_zlibDecoder = _zlibDecoderSpec;
}
size_t clusterSize = (size_t)1 << _clusterBits;
_cache.AllocAtLeast(clusterSize);
_cacheCompressed.AllocAtLeast(clusterSize * 2);
}
CMyComPtr<ISequentialInStream> streamTemp = this;
RINOK(InitAndSeek());
*stream = streamTemp.Detach();
return S_OK;
COM_TRY_END
}
REGISTER_ARC_I(
"VMDK", "vmdk", NULL, 0xC8,
k_Signature,
0,
0,
NULL)
}}

View File

@@ -22,6 +22,8 @@ using namespace NWindows;
namespace NArchive {
namespace NWim {
#define FILES_DIR_NAME "[DELETED]"
// #define WIM_DETAILS
static const Byte kProps[] =
@@ -35,6 +37,7 @@ static const Byte kProps[] =
kpidATime,
kpidAttrib,
kpidMethod,
kpidSolid,
kpidShortName,
kpidINode,
kpidLinks,
@@ -58,6 +61,7 @@ static const STATPROPSTG kArcProps[] =
{ NULL, kpidSize, VT_UI8},
{ NULL, kpidPackSize, VT_UI8},
{ NULL, kpidMethod, VT_BSTR},
{ NULL, kpidClusterSize, VT_UI4},
{ NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidMTime, VT_FILETIME},
{ NULL, kpidComment, VT_BSTR},
@@ -69,9 +73,16 @@ static const STATPROPSTG kArcProps[] =
{ (LPOLESTR)L"Boot Image", kpidBootImage, VT_UI4}
};
static const char *kMethodLZX = "LZX";
static const char *kMethodXpress = "XPress";
static const char *kMethodCopy = "Copy";
static const char * const k_Methods[] =
{
"Copy"
, "XPress"
, "LZX"
, "LZMS"
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps_WITH_NAME
@@ -200,6 +211,18 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
break;
case kpidNumVolumes: if (_volumes.Size() > 0) prop = (UInt32)(_volumes.Size() - 1); break;
case kpidClusterSize:
if (_xmls.Size() > 0)
{
UInt16 volIndex = _xmls[0].VolIndex;
if (volIndex < _volumes.Size())
{
const CHeader &h = _volumes[volIndex].Header;
prop = (UInt32)1 << h.ChunkSizeBits;
}
}
break;
case kpidName:
if (_firstVolumeIndex >= 0)
{
@@ -252,36 +275,61 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidNumImages: prop = (UInt32)_db.Images.Size(); break;
case kpidBootImage: if (_bootIndex != 0) prop = (UInt32)_bootIndex; break;
case kpidMethod:
{
bool lzx = false, xpress = false, copy = false;
FOR_VECTOR (i, _xmls)
UInt32 methodUnknown = 0;
UInt32 methodMask = 0;
unsigned chunkSizeBits = 0;
{
const CHeader &header = _volumes[_xmls[i].VolIndex].Header;
if (header.IsCompressed())
if (header.IsLzxMode())
lzx = true;
FOR_VECTOR (i, _xmls)
{
const CHeader &header = _volumes[_xmls[i].VolIndex].Header;
unsigned method = header.GetMethod();
if (method < ARRAY_SIZE(k_Methods))
methodMask |= ((UInt32)1 << method);
else
xpress = true;
else
copy = true;
methodUnknown = method;
if (chunkSizeBits < header.ChunkSizeBits)
chunkSizeBits = header.ChunkSizeBits;
}
}
AString res;
if (lzx)
res = kMethodLZX;
if (xpress)
bool numMethods = 0;
for (unsigned i = 0; i < ARRAY_SIZE(k_Methods); i++)
{
res.Add_Space_if_NotEmpty();
res += kMethodXpress;
if (methodMask & ((UInt32)1 << i))
{
res.Add_Space_if_NotEmpty();
res += k_Methods[i];
numMethods++;
}
}
if (copy)
if (methodUnknown != 0)
{
char temp[32];
ConvertUInt32ToString(methodUnknown, temp);
res.Add_Space_if_NotEmpty();
res += kMethodCopy;
res += temp;
numMethods++;
}
if (numMethods == 1 && chunkSizeBits != 0)
{
char temp[32];
temp[0] = ':';
ConvertUInt32ToString((UInt32)chunkSizeBits, temp + 1);
res += temp;
}
prop = res;
break;
}
case kpidIsTree: prop = true; break;
case kpidIsAltStream: prop = _db.ThereAreAltStreams; break;
case kpidIsAux: prop = true; break;
@@ -293,8 +341,8 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
UInt32 flags = 0;
if (!_isArc) flags |= kpv_ErrorFlags_IsNotArc;
// if (HeadersError) flags |= kpv_ErrorFlags_HeadersError;
// if (UnexpectedEnd) flags |= kpv_ErrorFlags_UnexpectedEndOfArc;
if (_db.HeadersError) flags |= kpv_ErrorFlags_HeadersError;
if (_unsupported) flags |= kpv_ErrorFlags_UnsupportedMethod;
prop = flags;
break;
}
@@ -313,23 +361,13 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidReadOnly:
{
bool readOnly = false;
if (ThereIsError())
readOnly = true;
else if (_volumes.Size() != 0)
{
if (_version != kWimVersion
|| _volumes.Size() != 2
|| _volumes[0].Stream
// || _db.Images.Size() > kNumImagesMax
)
readOnly = true;
}
bool readOnly = !IsUpdateSupported();
if (readOnly)
prop = readOnly;
break;
}
}
prop.Detach(value);
return S_OK;
COM_TRY_END
@@ -342,7 +380,29 @@ void GetFileTime(const Byte *p, NCOM::CPropVariant &prop)
prop.filetime.dwHighDateTime = Get32(p + 4);
}
#define FILES_DIR_NAME "[Files]"
static void MethodToProp(int method, int chunksSizeBits, NCOM::CPropVariant &prop)
{
if (method >= 0)
{
char temp[32];
if ((unsigned)method < ARRAY_SIZE(k_Methods))
strcpy(temp, k_Methods[method]);
else
ConvertUInt32ToString((unsigned)method, temp);
if (chunksSizeBits >= 0)
{
size_t pos = strlen(temp);
temp[pos++] = ':';
ConvertUInt32ToString((unsigned)chunksSizeBits, temp + pos);
}
prop = temp;
}
}
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
@@ -413,8 +473,59 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
_db.GetShortName(realIndex, prop);
break;
case kpidPackSize: prop = (UInt64)(si ? si->Resource.PackSize : 0); break;
case kpidSize: prop = (UInt64)(si ? si->Resource.UnpackSize : 0); break;
case kpidPackSize:
{
UInt64 size = 0;
if (si)
{
if (!si->Resource.IsSolidSmall())
{
size = si->Resource.PackSize;
prop = size;
}
else
{
if (si->Resource.SolidIndex >= 0)
{
const CSolid &ss = _db.Solids[(unsigned)si->Resource.SolidIndex];
if (ss.FirstSmallStream == item.StreamIndex)
prop = _db.DataStreams[ss.StreamIndex].Resource.PackSize;
}
}
}
break;
}
case kpidSize:
{
UInt64 size = 0;
if (si)
{
if (si->Resource.IsSolid())
{
if (si->Resource.IsSolidBig())
{
if (si->Resource.SolidIndex >= 0)
{
CSolid &ss = _db.Solids[(unsigned)si->Resource.SolidIndex];
prop = ss.UnpackSize;
}
}
else
{
size = si->Resource.PackSize;
prop = size;
}
}
else
{
size = si->Resource.UnpackSize;
prop = size;
}
}
break;
}
case kpidIsDir: prop = item.IsDir; break;
case kpidIsAltStream: prop = item.IsAltStream; break;
case kpidNumAltStreams:
@@ -467,8 +578,33 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = (UInt32)item.StreamIndex;
break;
case kpidMethod: if (si) prop = si->Resource.IsCompressed() ?
(vol->Header.IsLzxMode() ? kMethodLZX : kMethodXpress) : kMethodCopy; break;
case kpidMethod:
if (si)
{
const CResource &r = si->Resource;
if (r.IsSolid())
{
if (r.SolidIndex >= 0)
{
CSolid &ss = _db.Solids[r.SolidIndex];
MethodToProp(ss.Method, ss.ChunkSizeBits, prop);
}
}
else
{
int method = 0;
int chunkSizeBits = -1;
if (r.IsCompressed())
{
method = vol->Header.GetMethod();
chunkSizeBits = vol->Header.ChunkSizeBits;
}
MethodToProp(method, chunkSizeBits, prop);
}
}
break;
case kpidSolid: if (si) prop = si->Resource.IsSolid(); break;
case kpidLinks: if (si) prop = (UInt32)si->RefCount; break;
#ifdef WIM_DETAILS
case kpidVolume: if (si) prop = (UInt32)si->PartNumber; break;
@@ -488,7 +624,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidIsDir: prop = false; break;
case kpidPackSize:
case kpidSize: prop = (UInt64)_xmls[index].Data.Size(); break;
case kpidMethod: prop = kMethodCopy; break;
case kpidMethod: /* prop = k_Method_Copy; */ break;
}
}
else
@@ -629,14 +765,6 @@ STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentTyp
return S_OK;
}
static bool IsEmptySha(const Byte *data)
{
for (int i = 0; i < kHashSize; i++)
if (data[i] != 0)
return false;
return true;
}
STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)
{
*data = NULL;
@@ -773,6 +901,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal
for (UInt32 i = 1; i <= numVolumes; i++)
{
CMyComPtr<IInStream> curStream;
if (i == 1)
curStream = inStream;
else
@@ -786,14 +915,17 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal
if (!curStream)
break;
}
CHeader header;
HRESULT res = NWim::ReadHeader(curStream, header, _phySize);
if (res != S_OK)
{
if (i != 1 && res == S_FALSE)
continue;
return res;
}
_isArc = true;
_bootIndex = header.BootIndex;
_version = header.Version;
@@ -806,17 +938,25 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal
CWimXml xml;
xml.VolIndex = header.PartNumber;
res = _db.OpenXml(curStream, header, xml.Data);
if (res == S_OK)
{
if (!xml.Parse())
_xmlError = true;
if (xml.IsEncrypted)
{
_unsupported = true;
return S_FALSE;
}
UInt64 totalFiles = xml.GetTotalFilesAndDirs() + xml.Images.Size();
totalFiles += 16 + xml.Images.Size() * 4; // we reserve some additional items
if (totalFiles >= ((UInt32)1 << 30))
totalFiles = 0;
res = _db.Open(curStream, header, (unsigned)totalFiles, callback);
}
if (res != S_OK)
{
if (i != 1 && res == S_FALSE)
@@ -859,7 +999,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal
}
}
RINOK(_db.FillAndCheck());
RINOK(_db.FillAndCheck(_volumes));
int defaultImageIndex = (int)_defaultImageNumber - 1;
bool showImageNumber = (_db.Images.Size() != 1 && defaultImageIndex < 0);
@@ -901,9 +1041,11 @@ STDMETHODIMP CHandler::Close()
_numIgnoreItems = 0;
_xmlError = false;
_isArc = false;
_unsupported = false;
return S_OK;
}
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
@@ -917,6 +1059,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt32 i;
UInt64 totalSize = 0;
for (i = 0; i < numItems; i++)
{
UInt32 index = allFilesMode ? i : indices[i];
@@ -926,7 +1069,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (streamIndex >= 0)
{
const CStreamInfo &si = _db.DataStreams[streamIndex];
totalSize += si.Resource.UnpackSize;
totalSize += _db.Get_UnpackSize_of_Resource(si.Resource);
}
}
else
@@ -939,9 +1082,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(extractCallback->SetTotal(totalSize));
UInt64 currentTotalPacked = 0;
UInt64 currentTotalUnPacked = 0;
UInt64 currentItemUnPacked, currentItemPacked;
UInt64 currentItemUnPacked;
int prevSuccessStreamIndex = -1;
@@ -951,13 +1093,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
for (i = 0; i < numItems; currentTotalUnPacked += currentItemUnPacked,
currentTotalPacked += currentItemPacked)
for (i = 0; i < numItems;
currentTotalUnPacked += currentItemUnPacked)
{
currentItemUnPacked = 0;
currentItemPacked = 0;
lps->InSize = currentTotalPacked;
lps->InSize = unpacker.TotalPacked;
lps->OutSize = currentTotalUnPacked;
RINOK(lps->SetCur());
@@ -1005,8 +1146,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
const CStreamInfo &si = _db.DataStreams[streamIndex];
currentItemUnPacked = si.Resource.UnpackSize;
currentItemPacked = si.Resource.PackSize;
currentItemUnPacked = _db.Get_UnpackSize_of_Resource(si.Resource);
// currentItemPacked = _db.Get_PackSize_of_Resource(streamIndex);
if (!testMode && !realOutStream)
continue;
@@ -1016,17 +1157,20 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
Byte digest[kHashSize];
const CVolume &vol = _volumes[si.PartNumber];
HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header.IsLzxMode(),
realOutStream, progress, digest);
bool needDigest = !si.IsEmptyHash();
HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header, &_db,
realOutStream, progress, needDigest ? digest : NULL);
if (res == S_OK)
{
if (memcmp(digest, si.Hash, kHashSize) == 0)
if (!needDigest || memcmp(digest, si.Hash, kHashSize) == 0)
prevSuccessStreamIndex = streamIndex;
else
opRes = NExtract::NOperationResult::kCRCError;
}
else if (res == S_FALSE)
opRes = NExtract::NOperationResult::kDataError;
else if (res == E_NOTIMPL)
opRes = NExtract::NOperationResult::kUnsupportedMethod;
else
return res;
}

View File

@@ -10,6 +10,8 @@
namespace NArchive {
namespace NWim {
static const Int32 kNumImagesMaxUpdate = (1 << 10);
class CHandler:
public IInArchive,
public IArchiveGetRawProps,
@@ -34,6 +36,7 @@ class CHandler:
bool _xmlError;
bool _isArc;
bool _unsupported;
bool _set_use_ShowImageNumber;
bool _set_showImageNumber;
@@ -53,6 +56,26 @@ class CHandler:
_defaultImageNumber = -1;
}
bool IsUpdateSupported() const
{
if (ThereIsError()) return false;
if (_db.Images.Size() > kNumImagesMaxUpdate) return false;
// Solid format is complicated. So we disable updating now.
if (!_db.Solids.IsEmpty()) return false;
if (_volumes.Size() == 0)
return true;
if (_volumes.Size() != 2) return false;
if (_volumes[0].Stream) return false;
if (_version != k_Version_NonSolid
// && _version != k_Version_Solid
) return false;
return true;
}
bool ThereIsError() const { return _xmlError || _db.ThereIsError(); }
HRESULT GetSecurity(UInt32 realIndex, const void **data, UInt32 *dataSize, UInt32 *propType);

View File

@@ -2,10 +2,6 @@
#include "StdAfx.h"
// #include <stdio.h>
#include "../../../../C/CpuArch.h"
#include "../../../Common/ComTry.h"
#include "../../../Common/IntToString.h"
#include "../../../Common/StringToInt.h"
@@ -30,49 +26,36 @@ using namespace NWindows;
namespace NArchive {
namespace NWim {
static const Int32 kNumImagesMax = (1 << 10);
struct CSha1Hash
static int AddUniqHash(const CStreamInfo *streams, CUIntVector &sorted, const Byte *h, int streamIndexForInsert)
{
Byte Hash[kHashSize];
};
class CHashList
{
CUIntVector Sorted;
public:
CRecordVector<CSha1Hash> Digests;
int AddUniq(const Byte *h);
};
// returns -1 : if it's new HASH
int CHashList::AddUniq(const Byte *h)
{
unsigned left = 0, right = Sorted.Size();
unsigned left = 0, right = sorted.Size();
while (left != right)
{
unsigned mid = (left + right) / 2;
unsigned index = Sorted[mid];
const Byte *hash2 = Digests[index].Hash;
unsigned index = sorted[mid];
const Byte *hash2 = streams[index].Hash;
unsigned i;
for (i = 0; i < kHashSize; i++)
if (h[i] != hash2[i])
break;
if (i == kHashSize)
return index;
if (h[i] < hash2[i])
right = mid;
else
left = mid + 1;
}
CSha1Hash h2;
memcpy(h2.Hash, h, kHashSize);
Sorted.Insert(left, Digests.Add(h2));
if (streamIndexForInsert >= 0)
sorted.Insert(left, streamIndexForInsert);
return -1;
}
struct CAltStream
{
int UpdateIndex;
@@ -84,6 +67,7 @@ struct CAltStream
CAltStream(): UpdateIndex(-1), HashIndex(-1), Skip(false) {}
};
struct CMetaItem
{
int UpdateIndex;
@@ -114,6 +98,7 @@ struct CMetaItem
Skip(false), NumSkipAltStreams(0) {}
};
static int Compare_HardLink_MetaItems(const CMetaItem &a1, const CMetaItem &a2)
{
if (a1.VolID < a2.VolID) return -1;
@@ -125,6 +110,7 @@ static int Compare_HardLink_MetaItems(const CMetaItem &a1, const CMetaItem &a2)
return ::CompareFileTime(&a1.MTime, &a2.MTime);
}
static int AddToHardLinkList(const CObjectVector<CMetaItem> &metaItems, unsigned indexOfItem, CUIntVector &indexes)
{
const CMetaItem &mi = metaItems[indexOfItem];
@@ -145,6 +131,7 @@ static int AddToHardLinkList(const CObjectVector<CMetaItem> &metaItems, unsigned
return -1;
}
struct CUpdateItem
{
unsigned CallbackIndex; // index in callback
@@ -160,6 +147,7 @@ struct CUpdateItem
CUpdateItem(): MetaIndex(-1), AltStreamIndex(-1), InArcIndex(-1) {}
};
struct CDir
{
int MetaIndex;
@@ -224,12 +212,14 @@ bool CDir::FindDir(const CObjectVector<CMetaItem> &items, const UString &name, u
return false;
}
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
{
*type = NFileTimeType::kWindows;
return S_OK;
}
HRESULT CHandler::GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value)
{
if (arcIndex >= 0)
@@ -237,6 +227,7 @@ HRESULT CHandler::GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callba
return callback->GetProperty(callbackIndex, propID, value);
}
HRESULT CHandler::GetTime(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, FILETIME &ft)
{
ft.dwLowDateTime = ft.dwHighDateTime = 0;
@@ -249,6 +240,7 @@ HRESULT CHandler::GetTime(IArchiveUpdateCallback *callback, UInt32 callbackIndex
return S_OK;
}
static HRESULT GetRootTime(
IArchiveGetRootProps *callback,
IArchiveGetRootProps *arcRoot,
@@ -292,6 +284,7 @@ void CResource::WriteTo(Byte *p) const
Set64(p + 16, UnpackSize);
}
void CHeader::WriteTo(Byte *p) const
{
memcpy(p, kSignature, kSignatureSize);
@@ -311,6 +304,7 @@ void CHeader::WriteTo(Byte *p) const
memset(p + 0x94, 0, 60);
}
void CStreamInfo::WriteTo(Byte *p) const
{
Resource.WriteTo(p);
@@ -319,6 +313,7 @@ void CStreamInfo::WriteTo(Byte *p) const
memcpy(p + 0x1E, Hash, kHashSize);
}
class CInStreamWithSha1:
public ISequentialInStream,
public CMyUnknownImp
@@ -352,6 +347,7 @@ STDMETHODIMP CInStreamWithSha1::Read(void *data, UInt32 size, UInt32 *processedS
return result;
}
static void SetFileTimeToMem(Byte *p, const FILETIME &ft)
{
Set32(p, ft.dwLowDateTime);
@@ -391,7 +387,8 @@ static size_t WriteItem_Dummy(const CMetaItem &item)
return totalLen;
}
static size_t WriteItem(const CRecordVector<CSha1Hash> &digests, const CMetaItem &item, Byte *p)
static size_t WriteItem(const CStreamInfo *streams, const CMetaItem &item, Byte *p)
{
if (item.Skip)
return 0;
@@ -437,7 +434,7 @@ static size_t WriteItem(const CRecordVector<CSha1Hash> &digests, const CMetaItem
if (item.GetNumAltStreams() == 0)
{
if (item.HashIndex >= 0)
memcpy(p + 0x40, digests[item.HashIndex].Hash, kHashSize);
memcpy(p + 0x40, streams[item.HashIndex].Hash, kHashSize);
}
else
{
@@ -450,7 +447,7 @@ static size_t WriteItem(const CRecordVector<CSha1Hash> &digests, const CMetaItem
memset(p, 0, curLen);
Set64(p, curLen);
if (item.HashIndex >= 0)
memcpy(p + 0x10, digests[item.HashIndex].Hash, kHashSize);
memcpy(p + 0x10, streams[item.HashIndex].Hash, kHashSize);
totalLen += curLen;
p += curLen;
}
@@ -468,7 +465,7 @@ static size_t WriteItem(const CRecordVector<CSha1Hash> &digests, const CMetaItem
Set64(p, curLen);
if (ss.HashIndex >= 0)
memcpy(p + 0x10, digests[ss.HashIndex].Hash, kHashSize);
memcpy(p + 0x10, streams[ss.HashIndex].Hash, kHashSize);
Set16(p + 0x24, (UInt16)fileNameLen);
for (i = 0; i * 2 < fileNameLen; i++)
Set16(p + 0x26 + i * 2, ss.Name[i]);
@@ -480,10 +477,11 @@ static size_t WriteItem(const CRecordVector<CSha1Hash> &digests, const CMetaItem
return totalLen;
}
struct CDb
{
CMetaItem DefaultDirItem;
const CRecordVector<CSha1Hash> *Hashes;
const CStreamInfo *Hashes;
CObjectVector<CMetaItem> MetaItems;
CRecordVector<CUpdateItem> UpdateItems;
CUIntVector UpdateIndexes; /* indexes in UpdateItems in order of writing data streams
@@ -494,6 +492,7 @@ struct CDb
void WriteOrderList(const CDir &tree);
};
size_t CDb::WriteTree_Dummy(const CDir &tree) const
{
unsigned i;
@@ -509,11 +508,12 @@ size_t CDb::WriteTree_Dummy(const CDir &tree) const
return pos + 8;
}
void CDb::WriteTree(const CDir &tree, Byte *dest, size_t &pos) const
{
unsigned i;
for (i = 0; i < tree.Files.Size(); i++)
pos += WriteItem(*Hashes, MetaItems[tree.Files[i]], dest + pos);
pos += WriteItem(Hashes, MetaItems[tree.Files[i]], dest + pos);
size_t posStart = pos;
for (i = 0; i < tree.Dirs.Size(); i++)
@@ -530,7 +530,7 @@ void CDb::WriteTree(const CDir &tree, Byte *dest, size_t &pos) const
bool needCreateTree = (metaItem.Reparse.Size() == 0)
|| !subDir.Files.IsEmpty()
|| !subDir.Dirs.IsEmpty();
size_t len = WriteItem(*Hashes, metaItem, dest + posStart);
size_t len = WriteItem(Hashes, metaItem, dest + posStart);
posStart += len;
if (needCreateTree)
{
@@ -540,6 +540,7 @@ void CDb::WriteTree(const CDir &tree, Byte *dest, size_t &pos) const
}
}
void CDb::WriteOrderList(const CDir &tree)
{
if (tree.MetaIndex >= 0)
@@ -564,6 +565,7 @@ void CDb::WriteOrderList(const CDir &tree)
WriteOrderList(tree.Dirs[i]);
}
static void AddTag_ToString(AString &s, const char *name, const char *value)
{
s += '<';
@@ -576,6 +578,7 @@ static void AddTag_ToString(AString &s, const char *name, const char *value)
s += '>';
}
static void AddTagUInt64_ToString(AString &s, const char *name, UInt64 value)
{
char temp[32];
@@ -583,6 +586,7 @@ static void AddTagUInt64_ToString(AString &s, const char *name, UInt64 value)
AddTag_ToString(s, name, temp);
}
static CXmlItem &AddUniqueTag(CXmlItem &parentItem, const char *name)
{
int index = parentItem.FindSubTag(name);
@@ -598,6 +602,7 @@ static CXmlItem &AddUniqueTag(CXmlItem &parentItem, const char *name)
return subItem;
}
static void AddTag_UInt64_2(CXmlItem &item, UInt64 value)
{
CXmlItem &subItem = item.SubItems.AddNew();
@@ -607,11 +612,13 @@ static void AddTag_UInt64_2(CXmlItem &item, UInt64 value)
subItem.Name = temp;
}
static void AddTag_UInt64(CXmlItem &parentItem, const char *name, UInt64 value)
{
AddTag_UInt64_2(AddUniqueTag(parentItem, name), value);
}
static void AddTag_Hex(CXmlItem &item, const char *name, UInt32 value)
{
item.IsTag = true;
@@ -625,17 +632,20 @@ static void AddTag_Hex(CXmlItem &item, const char *name, UInt32 value)
subItem.Name = temp;
}
static void AddTag_Time_2(CXmlItem &item, const FILETIME &ft)
{
AddTag_Hex(item.SubItems.AddNew(), "HIGHPART", ft.dwHighDateTime);
AddTag_Hex(item.SubItems.AddNew(), "LOWPART", ft.dwLowDateTime);
}
static void AddTag_Time(CXmlItem &parentItem, const char *name, const FILETIME &ft)
{
AddTag_Time_2(AddUniqueTag(parentItem, name), ft);
}
static void AddTag_String_IfEmpty(CXmlItem &parentItem, const char *name, const char *value)
{
int index = parentItem.FindSubTag(name);
@@ -649,15 +659,17 @@ static void AddTag_String_IfEmpty(CXmlItem &parentItem, const char *name, const
subItem.Name = value;
}
void CHeader::SetDefaultFields(bool useLZX)
{
Version = kWimVersion;
Version = k_Version_NonSolid;
Flags = NHeaderFlags::kReparsePointFixup;
ChunkSize = 0;
if (useLZX)
{
Flags |= NHeaderFlags::kCompression | NHeaderFlags::kLZX;
ChunkSize = kChunkSize;
ChunkSizeBits = kChunkSizeBits;
}
g_RandomGenerator.Generate(Guid, 16);
PartNumber = 1;
@@ -670,19 +682,23 @@ void CHeader::SetDefaultFields(bool useLZX)
IntegrityResource.Clear();
}
static void AddTrees(CObjectVector<CDir> &trees, CObjectVector<CMetaItem> &metaItems, const CMetaItem &ri, int curTreeIndex)
{
while (curTreeIndex >= (int)trees.Size())
trees.AddNew().Dirs.AddNew().MetaIndex = metaItems.Add(ri);
}
#define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z')
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 numItems, IArchiveUpdateCallback *callback)
{
COM_TRY_BEGIN
if (ThereIsError())
if (!IsUpdateSupported())
return E_NOTIMPL;
bool isUpdate = (_volumes.Size() != 0);
@@ -692,14 +708,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
if (isUpdate)
{
showImageNumber = _showImageNumber;
if (_version != kWimVersion)
return E_NOTIMPL;
if (_volumes.Size() != 2 || _volumes[0].Stream)
return E_NOTIMPL;
if (!showImageNumber)
defaultImageIndex = _db.IndexOfUserImage;
if (_db.Images.Size() > kNumImagesMax)
return E_NOTIMPL;
}
else
{
@@ -708,7 +718,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
defaultImageIndex = 0;
}
if (defaultImageIndex >= kNumImagesMax)
if (defaultImageIndex >= kNumImagesMaxUpdate)
return E_NOTIMPL;
CMyComPtr<IOutStream> outStream;
@@ -783,7 +793,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
UInt64 val = ConvertStringToUInt64(path, &end);
if (end == path)
return E_INVALIDARG;
if (val == 0 || val > kNumImagesMax)
if (val == 0 || val > kNumImagesMaxUpdate)
return E_INVALIDARG;
wchar_t c = *end;
if (c != 0 && c != ':' && c != L'/' && c != WCHAR_PATH_SEPARATOR)
@@ -889,6 +899,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
UInt32 indexInArchive;
Int32 newData, newProps;
RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
if (newData == 0 || newProps == 0)
{
if (indexInArchive >= _db.SortedItems.Size())
@@ -910,7 +921,14 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
// if deleted item was not renamed, we just skip it
if (newProps == 0)
continue;
if (item.StreamIndex >= 0)
{
// we don't support property change for SolidBig streams
if (_db.DataStreams[item.StreamIndex].Resource.IsSolidBig())
return E_NOTIMPL;
}
}
if (newData == 0)
ui.InArcIndex = indexInArchive;
}
@@ -955,6 +973,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
}
NCOM::CPropVariant prop;
if (newData)
{
RINOK(callback->GetProperty(i, kpidSize, &prop));
@@ -963,6 +982,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
{
RINOK(GetProperty(indexInArchive, kpidSize, &prop));
}
if (prop.vt == VT_UI8)
size = prop.uhVal.QuadPart;
else if (prop.vt != VT_EMPTY)
@@ -999,7 +1019,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
UInt64 val = ConvertStringToUInt64(path, &end);
if (end == path)
return E_INVALIDARG;
if (val == 0 || val > kNumImagesMax)
if (val == 0 || val > kNumImagesMaxUpdate)
return E_INVALIDARG;
imageIndex = (int)val - 1;
@@ -1111,6 +1131,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
ui.MetaIndex = db.MetaItems.Size();
db.MetaItems.AddNew();
}
CMetaItem &mi = db.MetaItems[ui.MetaIndex];
mi.Size = size;
mi.IsDir = isDir;
@@ -1163,6 +1184,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
{
getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType);
}
if (dataSize != 0)
{
if (propType != NPropDataType::kRaw)
@@ -1173,6 +1195,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
data = NULL;
dataSize = 0;
propType = 0;
if (arcIndex >= 0)
{
GetRawProp(arcIndex, kpidNtReparse, &data, &dataSize, &propType);
@@ -1181,6 +1204,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
{
getRawProps->GetRawProp(i, kpidNtReparse, &data, &dataSize, &propType);
}
if (dataSize != 0)
{
if (propType != NPropDataType::kRaw)
@@ -1228,7 +1252,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
UInt64 complexity = 0;
unsigned numDataStreams = _db.DataStreams.Size();
CIntArr streamsRefs(numDataStreams);
CUIntArr streamsRefs(numDataStreams);
for (i = 0; i < numDataStreams; i++)
streamsRefs[i] = 0;
@@ -1249,11 +1273,13 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
}
}
// ---------- Update Streams Refs Counts in changed images
for (i = 0; i < db.UpdateIndexes.Size(); i++)
{
const CUpdateItem &ui = db.UpdateItems[db.UpdateIndexes[i]];
if (ui.InArcIndex >= 0)
{
if ((unsigned)ui.InArcIndex >= _db.SortedItems.Size())
@@ -1274,12 +1300,32 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
}
}
// Clear ref counts for SolidBig streams
for (i = 0; i < _db.DataStreams.Size(); i++)
if (_db.DataStreams[i].Resource.IsSolidBig())
streamsRefs[i] = 0;
// Set ref counts for SolidBig streams
for (i = 0; i < _db.DataStreams.Size(); i++)
if (streamsRefs[i] != 0)
complexity += _db.DataStreams[i].Resource.PackSize;
{
const CResource &rs = _db.DataStreams[i].Resource;
if (rs.IsSolidSmall())
streamsRefs[_db.Solids[rs.SolidIndex].StreamIndex] = 1;
}
for (i = 0; i < _db.DataStreams.Size(); i++)
if (streamsRefs[i] != 0)
{
const CResource &rs = _db.DataStreams[i].Resource;
if (!rs.IsSolidSmall())
complexity += rs.PackSize;
}
RINOK(callback->SetTotal(complexity));
UInt64 totalComplexity = complexity;
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
@@ -1300,7 +1346,9 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
{
const CHeader &srcHeader = _volumes[1].Header;
header.Flags = srcHeader.Flags;
header.Version = srcHeader.Version;
header.ChunkSize = srcHeader.ChunkSize;
header.ChunkSizeBits = srcHeader.ChunkSizeBits;
}
Byte buf[kHeaderSizeMax];
@@ -1322,40 +1370,84 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
}
// these two lists have same sizes and same hashes in same order.
CHashList hashes;
CObjectVector<CStreamInfo> streams;
CRecordVector<CStreamInfo> streams;
CUIntVector sortedHashes; // indexes to streams, sorted by SHA1
// ---------- Copy unchanged data streams ----------
UInt64 solidRunOffset = 0;
UInt64 curSolidSize = 0;
for (i = 0; i < _db.DataStreams.Size(); i++)
{
if (streamsRefs[i] == 0)
continue;
const CStreamInfo &siOld = _db.DataStreams[i];
const CResource &rs = siOld.Resource;
unsigned numRefs = streamsRefs[i];
if (numRefs == 0)
{
if (!rs.IsSolidSmall())
continue;
if (streamsRefs[_db.Solids[rs.SolidIndex].StreamIndex] == 0)
continue;
}
lps->InSize = lps->OutSize = complexity;
RINOK(lps->SetCur());
const CStreamInfo &siOld = _db.DataStreams[i];
if (hashes.AddUniq(siOld.Hash) >= 0)
return E_FAIL; // two streams with same SHA-1
RINOK(_volumes[siOld.PartNumber].Stream->Seek(siOld.Resource.Offset, STREAM_SEEK_SET, NULL));
inStreamLimitedSpec->Init(siOld.Resource.PackSize);
RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
if (copyCoderSpec->TotalSize != siOld.Resource.PackSize)
return E_FAIL;
CStreamInfo &s = streams.AddNew();
s.Resource = siOld.Resource;
s.Resource.Offset = curPos;
int streamIndex = streams.Size();
CStreamInfo s;
s.Resource = rs;
s.PartNumber = 1;
s.RefCount = streamsRefs[i];
s.RefCount = numRefs;
memcpy(s.Hash, siOld.Hash, kHashSize);
curPos += s.Resource.PackSize;
lps->ProgressOffset += s.Resource.PackSize;
if (rs.IsSolid())
{
CSolid &ss = _db.Solids[rs.SolidIndex];
if (rs.IsSolidSmall())
{
UInt64 oldOffset = ss.SolidOffset;
if (rs.Offset < oldOffset)
return E_FAIL;
UInt64 relatOffset = rs.Offset - oldOffset;
s.Resource.Offset = solidRunOffset + relatOffset;
}
else
{
// IsSolidBig
solidRunOffset += curSolidSize;
curSolidSize = ss.UnpackSize;
}
}
else
{
solidRunOffset = 0;
curSolidSize = 0;
}
if (!rs.IsSolid() || rs.IsSolidSmall())
{
int find = AddUniqHash(&streams.Front(), sortedHashes, siOld.Hash, streamIndex);
if (find >= 0)
return E_FAIL; // two streams with same SHA-1
}
if (!rs.IsSolid() || rs.IsSolidBig())
{
RINOK(_volumes[siOld.PartNumber].Stream->Seek(rs.Offset, STREAM_SEEK_SET, NULL));
inStreamLimitedSpec->Init(rs.PackSize);
RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
if (copyCoderSpec->TotalSize != rs.PackSize)
return E_FAIL;
s.Resource.Offset = curPos;
curPos += rs.PackSize;
lps->ProgressOffset += rs.PackSize;
}
streams.Add(s);
}
@@ -1367,7 +1459,6 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
{
lps->InSize = lps->OutSize = complexity;
RINOK(lps->SetCur());
const CUpdateItem &ui = db.UpdateItems[db.UpdateIndexes[i]];
CMetaItem &mi = db.MetaItems[ui.MetaIndex];
UInt64 size = 0;
@@ -1396,7 +1487,9 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
if ((unsigned)ui.InArcIndex >= _db.SortedItems.Size())
return E_FAIL;
const CItem &item = _db.Items[_db.SortedItems[ui.InArcIndex]];
if (item.StreamIndex < 0)
{
if (size == 0)
@@ -1408,19 +1501,23 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
// We support empty file (size = 0, but with stream and SHA-1) from old archive
const CStreamInfo &siOld = _db.DataStreams[item.StreamIndex];
int index = AddUniqHash(&streams.Front(), sortedHashes, siOld.Hash, -1);
// we must have written that stream already
int index = hashes.AddUniq(siOld.Hash);
if (index < 0)
return E_FAIL;
if (ui.AltStreamIndex < 0)
mi.HashIndex = index;
else
mi.AltStreams[ui.AltStreamIndex].HashIndex = index;
continue;
}
CMyComPtr<ISequentialInStream> fileInStream;
HRESULT res = callback->GetStream(ui.CallbackIndex, &fileInStream);
if (res == S_FALSE)
{
if (ui.AltStreamIndex >= 0)
@@ -1452,8 +1549,6 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
if (getProps2->GetProps2(&props) == S_OK)
{
mi.Attrib = props.Attrib;
mi.Size = props.Size;
size = props.Size;
mi.CTime = props.CTime;
mi.ATime = props.ATime;
mi.MTime = props.MTime;
@@ -1463,6 +1558,19 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
mi.VolID = props.VolID;
if (mi.FileID != 0)
miIndex = AddToHardLinkList(db.MetaItems, ui.MetaIndex, hlIndexes);
if (props.Size != size && props.Size != (UInt64)(Int64)-1)
{
Int64 delta = (Int64)props.Size - (Int64)size;
Int64 newComplexity = totalComplexity + delta;
if (newComplexity > 0)
{
totalComplexity = newComplexity;
callback->SetTotal(totalComplexity);
}
mi.Size = props.Size;
size = props.Size;
}
}
}
}
@@ -1484,14 +1592,16 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
sha1.Update((const Byte *)mi.Reparse + 8, packSize);
Byte hash[kHashSize];
sha1.Final(hash);
int index = hashes.AddUniq(hash);
int index = AddUniqHash(&streams.Front(), sortedHashes, hash, streams.Size());
if (index >= 0)
streams[index].RefCount++;
else
{
RINOK(WriteStream(outStream, (const Byte *)mi.Reparse + 8, packSize));
index = streams.Size();
CStreamInfo &s = streams.AddNew();
RINOK(WriteStream(outStream, (const Byte *)mi.Reparse + 8, packSize));
CStreamInfo s;
s.Resource.PackSize = packSize;
s.Resource.Offset = curPos;
s.Resource.UnpackSize = packSize;
@@ -1504,7 +1614,10 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
s.RefCount = 1;
memcpy(s.Hash, hash, kHashSize);
curPos += packSize;
streams.Add(s);
}
mi.HashIndex = index;
}
else
@@ -1534,7 +1647,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
Byte hash[kHashSize];
UInt64 packSize = offsetBlockSize + size;
inShaStreamSpec->Final(hash);
int index = hashes.AddUniq(hash);
int index = AddUniqHash(&streams.Front(), sortedHashes, hash, streams.Size());
if (index >= 0)
{
@@ -1545,7 +1659,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
else
{
index = streams.Size();
CStreamInfo &s = streams.AddNew();
CStreamInfo s;
s.Resource.PackSize = packSize;
s.Resource.Offset = curPos;
s.Resource.UnpackSize = size;
@@ -1558,6 +1672,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
s.RefCount = 1;
memcpy(s.Hash, hash, kHashSize);
curPos += packSize;
streams.Add(s);
}
if (ui.AltStreamIndex < 0)
@@ -1658,15 +1774,16 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
Set32((Byte *)meta, (UInt32)pos); // size of security data
}
db.Hashes = &hashes.Digests;
db.Hashes = &streams.Front();
db.WriteTree(tree, (Byte *)meta, pos);
{
NCrypto::NSha1::CContext sha;
sha.Init();
sha.Update((const Byte *)meta, pos);
CSha1Hash digest;
sha.Final(digest.Hash);
Byte digest[kHashSize];
sha.Final(digest);
CStreamInfo s;
s.Resource.PackSize = pos;
@@ -1675,7 +1792,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
s.Resource.Flags = NResourceFlags::kMetadata;
s.PartNumber = 1;
s.RefCount = 1;
memcpy(s.Hash, digest.Hash, kHashSize);
memcpy(s.Hash, digest, kHashSize);
streams.Add(s);
if (_bootIndex != 0 && _bootIndex == (UInt32)i + 1)

View File

File diff suppressed because it is too large Load Diff

View File

@@ -3,12 +3,15 @@
#ifndef __ARCHIVE_WIM_IN_H
#define __ARCHIVE_WIM_IN_H
#include "../../../../C/Alloc.h"
#include "../../../Common/MyBuffer.h"
#include "../../../Common/MyXml.h"
#include "../../../Windows/PropVariant.h"
#include "../../Compress/CopyCoder.h"
#include "../../Compress/LzmsDecoder.h"
#include "../../Compress/LzxDecoder.h"
#include "../IArchive.h"
@@ -16,8 +19,20 @@
namespace NArchive {
namespace NWim {
const UInt32 kDirRecordSizeOld = 62;
const UInt32 kDirRecordSize = 102;
/*
WIM versions:
hexVer : headerSize : ver
: 1.07.01 - 1.08.01 : Longhorn.4001-4015 - another header, no signature, CAB compression
10900 : 60 : 1.09 : Longhorn.4029-4039 (2003)
10A00 : 60 : 1.10 : Longhorn.4083 (2004) image starting from 1
10B00 : ?? : 1.11 : ??
10C00 : 74 : 1.12 : Longhorn.4093 - VistaBeta1.5112 (2005) - (Multi-Part, SHA1)
10D00 : D0 : 1.13 : VistaBeta2 - Win10, (NumImages, BootIndex, IntegrityResource)
00E00 : D0 : 0.14 : LZMS, solid, esd, dism
*/
const unsigned kDirRecordSizeOld = 62;
const unsigned kDirRecordSize = 102;
/*
There is error in WIM specification about dwReparseTag, dwReparseReserved and liHardLink fields.
@@ -114,85 +129,26 @@ const UInt32 kDirRecordSize = 102;
*/
namespace NXpress {
class CBitStream
{
CInBuffer m_Stream;
UInt32 m_Value;
unsigned m_BitPos;
public:
bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
void SetStream(ISequentialInStream *s) { m_Stream.SetStream(s); }
void Init() { m_Stream.Init(); m_BitPos = 0; }
// UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - m_BitPos / 8; }
Byte DirectReadByte() { return m_Stream.ReadByte(); }
void Normalize()
{
if (m_BitPos < 16)
{
Byte b0 = m_Stream.ReadByte();
Byte b1 = m_Stream.ReadByte();
m_Value = (m_Value << 8) | b1;
m_Value = (m_Value << 8) | b0;
m_BitPos += 16;
}
}
UInt32 GetValue(unsigned numBits)
{
Normalize();
return (m_Value >> (m_BitPos - numBits)) & ((1 << numBits) - 1);
}
void MovePos(unsigned numBits) { m_BitPos -= numBits; }
UInt32 ReadBits(unsigned numBits)
{
UInt32 res = GetValue(numBits);
m_BitPos -= numBits;
return res;
}
};
const unsigned kNumHuffmanBits = 16;
const UInt32 kMatchMinLen = 3;
const UInt32 kNumLenSlots = 16;
const UInt32 kNumPosSlots = 16;
const UInt32 kNumPosLenSlots = kNumPosSlots * kNumLenSlots;
const UInt32 kMainTableSize = 256 + kNumPosLenSlots;
class CDecoder
{
CBitStream m_InBitStream;
CLzOutWindow m_OutWindowStream;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
HRESULT CodeSpec(UInt32 size);
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize);
public:
HRESULT Flush() { return m_OutWindowStream.Flush(); }
HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize);
};
}
namespace NResourceFlags
{
const Byte kFree = 1;
const Byte kMetadata = 2;
const Byte Compressed = 4;
// const Byte Spanned = 4;
// const Byte kFree = 1 << 0;
const Byte kMetadata = 1 << 1;
const Byte kCompressed = 1 << 2;
// const Byte kSpanned = 1 << 3;
const Byte kSolid = 1 << 4;
}
const UInt64 k_SolidBig_Resource_Marker = (UInt64)1 << 32;
struct CResource
{
UInt64 PackSize;
UInt64 Offset;
UInt64 UnpackSize;
Byte Flags;
bool KeepSolid;
int SolidIndex;
void Clear()
{
@@ -200,7 +156,10 @@ struct CResource
Offset = 0;
UnpackSize = 0;
Flags = 0;
KeepSolid = false;
SolidIndex = -1;
}
UInt64 GetEndLimit() const { return Offset + PackSize; }
void Parse(const Byte *p);
void ParseAndUpdatePhySize(const Byte *p, UInt64 &phySize)
@@ -212,59 +171,130 @@ struct CResource
}
void WriteTo(Byte *p) const;
bool IsFree() const { return (Flags & NResourceFlags::kFree) != 0; }
bool IsMetadata() const { return (Flags & NResourceFlags::kMetadata) != 0; }
bool IsCompressed() const { return (Flags & NResourceFlags::Compressed) != 0; }
bool IsCompressed() const { return (Flags & NResourceFlags::kCompressed) != 0; }
bool IsSolid() const { return (Flags & NResourceFlags::kSolid) != 0; }
bool IsSolidBig() const { return IsSolid() && UnpackSize == k_SolidBig_Resource_Marker; }
bool IsSolidSmall() const { return IsSolid() && UnpackSize == 0; }
bool IsEmpty() const { return (UnpackSize == 0); }
};
struct CSolid
{
unsigned StreamIndex;
// unsigned NumRefs;
int FirstSmallStream;
UInt64 SolidOffset;
UInt64 UnpackSize;
int Method;
int ChunkSizeBits;
UInt64 HeadersSize;
// size_t NumChunks;
CObjArray<UInt64> Chunks; // [NumChunks + 1] (start offset)
UInt64 GetChunkPackSize(size_t chunkIndex) const { return Chunks[chunkIndex + 1] - Chunks[chunkIndex]; }
CSolid():
FirstSmallStream(-1),
// NumRefs(0),
Method(-1)
{}
};
namespace NHeaderFlags
{
const UInt32 kCompression = 2;
const UInt32 kReadOnly = 4;
const UInt32 kSpanned = 8;
const UInt32 kResourceOnly = 0x10;
const UInt32 kMetadataOnly = 0x20;
const UInt32 kWriteInProgress = 0x40;
const UInt32 kReparsePointFixup = 0x80;
const UInt32 kXPRESS = 0x20000;
const UInt32 kLZX = 0x40000;
const UInt32 kCompression = 1 << 1;
const UInt32 kReadOnly = 1 << 2;
const UInt32 kSpanned = 1 << 3;
const UInt32 kResourceOnly = 1 << 4;
const UInt32 kMetadataOnly = 1 << 5;
const UInt32 kWriteInProgress = 1 << 6;
const UInt32 kReparsePointFixup = 1 << 7;
const UInt32 kXPRESS = (UInt32)1 << 17;
const UInt32 kLZX = (UInt32)1 << 18;
const UInt32 kLZMS = (UInt32)1 << 19;
const UInt32 kMethodMask = 0xFFFE0000;
}
const UInt32 kWimVersion = 0x010D00;
namespace NMethod
{
const UInt32 kXPRESS = 1;
const UInt32 kLZX = 2;
const UInt32 kLZMS = 3;
}
const UInt32 k_Version_NonSolid = 0x10D00;
const UInt32 k_Version_Solid = 0xE00;
const unsigned kHeaderSizeMax = 0xD0;
const unsigned kSignatureSize = 8;
extern const Byte kSignature[kSignatureSize];
const unsigned kChunkSizeBits = 15;
const UInt32 kChunkSize = (1 << kChunkSizeBits);
const UInt32 kChunkSize = (UInt32)1 << kChunkSizeBits;
struct CHeader
{
UInt32 Version;
UInt32 Flags;
UInt32 ChunkSize;
unsigned ChunkSizeBits;
Byte Guid[16];
UInt16 PartNumber;
UInt16 NumParts;
UInt32 NumImages;
UInt32 BootIndex;
bool _IsOldVersion; // 1.10-
bool _IsNewVersion; // 1.13+ or 0.14
CResource OffsetResource;
CResource XmlResource;
CResource MetadataResource;
CResource IntegrityResource;
UInt32 BootIndex;
void SetDefaultFields(bool useLZX);
void WriteTo(Byte *p) const;
HRESULT Parse(const Byte *p, UInt64 &phySize);
bool IsCompressed() const { return (Flags & NHeaderFlags::kCompression) != 0; }
bool IsSupported() const { return (!IsCompressed() || (Flags & NHeaderFlags::kLZX) != 0 || (Flags & NHeaderFlags::kXPRESS) != 0 ) ; }
bool IsLzxMode() const { return (Flags & NHeaderFlags::kLZX) != 0; }
bool IsSpanned() const { return (!IsCompressed() || (Flags & NHeaderFlags::kSpanned) != 0); }
bool IsOldVersion() const { return (Version <= 0x010A00); }
bool IsNewVersion() const { return (Version > 0x010C00); }
bool IsSupported() const
{
return (!IsCompressed()
|| (Flags & NHeaderFlags::kLZX) != 0
|| (Flags & NHeaderFlags::kXPRESS) != 0
|| (Flags & NHeaderFlags::kLZMS) != 0);
}
unsigned GetMethod() const
{
if (!IsCompressed())
return 0;
UInt32 mask = (Flags & NHeaderFlags::kMethodMask);
if (mask == 0) return 0;
if (mask == NHeaderFlags::kXPRESS) return NMethod::kXPRESS;
if (mask == NHeaderFlags::kLZX) return NMethod::kLZX;
if (mask == NHeaderFlags::kLZMS) return NMethod::kLZMS;
return mask;
}
bool IsOldVersion() const { return _IsOldVersion; }
bool IsNewVersion() const { return _IsNewVersion; }
bool IsSolidVersion() const { return (Version == k_Version_Solid); }
bool AreFromOnArchive(const CHeader &h)
{
@@ -272,7 +302,17 @@ struct CHeader
}
};
const unsigned kHashSize = 20;
inline bool IsEmptySha(const Byte *data)
{
for (unsigned i = 0; i < kHashSize; i++)
if (data[i] != 0)
return false;
return true;
}
const unsigned kStreamInfoSize = 24 + 2 + 4 + kHashSize;
struct CStreamInfo
@@ -283,9 +323,12 @@ struct CStreamInfo
UInt32 Id; // for OLD WIM format
Byte Hash[kHashSize];
bool IsEmptyHash() const { return IsEmptySha(Hash); }
void WriteTo(Byte *p) const;
};
struct CItem
{
size_t Offset;
@@ -321,6 +364,7 @@ struct CImage
CImage(): VirtualRootIndex(-1) {}
};
struct CImageInfo
{
bool CTimeDefined;
@@ -345,6 +389,7 @@ struct CImageInfo
void Parse(const CXmlItem &item);
};
struct CWimXml
{
CByteBuffer Data;
@@ -354,6 +399,7 @@ struct CWimXml
CObjectVector<CImageInfo> Images;
UString FileName;
bool IsEncrypted;
UInt64 GetTotalFilesAndDirs() const
{
@@ -365,14 +411,18 @@ struct CWimXml
void ToUnicode(UString &s);
bool Parse();
CWimXml(): IsEncrypted(false) {}
};
struct CVolume
{
CHeader Header;
CMyComPtr<IInStream> Stream;
};
class CDatabase
{
Byte *DirData;
@@ -386,10 +436,10 @@ class CDatabase
public:
CRecordVector<CStreamInfo> DataStreams;
CRecordVector<CStreamInfo> MetaStreams;
CObjectVector<CSolid> Solids;
CRecordVector<CItem> Items;
CObjectVector<CByteBuffer> ReparseItems;
CIntVector ItemToReparse; // from index_in_Items to index_in_ReparseItems
@@ -397,10 +447,15 @@ public:
CObjectVector<CImage> Images;
bool IsOldVersion9;
bool IsOldVersion;
bool ThereAreDeletedStreams;
bool ThereAreAltStreams;
bool RefCountError;
bool HeadersError;
bool GetStartImageIndex() const { return IsOldVersion9 ? 0 : 1; }
unsigned GetDirAlignMask() const { return IsOldVersion9 ? 3 : 7; }
// User Items can contain all images or just one image from all.
CUIntVector SortedItems;
@@ -423,6 +478,31 @@ public:
bool ItemHasStream(const CItem &item) const;
UInt64 Get_UnpackSize_of_Resource(const CResource &r) const
{
if (!r.IsSolid())
return r.UnpackSize;
if (r.IsSolidSmall())
return r.PackSize;
if (r.IsSolidBig() && r.SolidIndex >= 0)
return Solids[(unsigned)r.SolidIndex].UnpackSize;
return 0;
}
UInt64 Get_PackSize_of_Resource(unsigned streamIndex) const
{
const CResource &r = DataStreams[streamIndex].Resource;
if (!r.IsSolidSmall())
return r.PackSize;
if (r.SolidIndex >= 0)
{
const CSolid &ss = Solids[(unsigned)r.SolidIndex];
if (ss.FirstSmallStream == (int)streamIndex)
return DataStreams[ss.StreamIndex].Resource.PackSize;
}
return 0;
}
UInt64 GetUnpackSize() const
{
UInt64 res = 0;
@@ -442,8 +522,8 @@ public:
void Clear()
{
DataStreams.Clear();
MetaStreams.Clear();
Solids.Clear();
Items.Clear();
ReparseItems.Clear();
@@ -458,6 +538,7 @@ public:
ThereAreDeletedStreams = false;
ThereAreAltStreams = false;
RefCountError = false;
HeadersError = false;
}
CDatabase(): RefCountError(false) {}
@@ -468,7 +549,7 @@ public:
HRESULT OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml);
HRESULT Open(IInStream *inStream, const CHeader &h, unsigned numItemsReserve, IArchiveOpenCallback *openCallback);
HRESULT FillAndCheck();
HRESULT FillAndCheck(const CObjectVector<CVolume> &volumes);
/*
imageIndex showImageNumber NumImages
@@ -484,23 +565,87 @@ public:
HRESULT ReadHeader(IInStream *inStream, CHeader &header, UInt64 &phySize);
struct CMidBuf
{
Byte *Data;
size_t _size;
CMidBuf(): Data(NULL), _size(0) {}
void EnsureCapacity(size_t size)
{
if (size > _size)
{
::MidFree(Data);
_size = 0;
Data = (Byte *)::MidAlloc(size);
if (Data)
_size = size;
}
}
~CMidBuf() { ::MidFree(Data); }
};
class CUnpacker
{
NCompress::CCopyCoder *copyCoderSpec;
CMyComPtr<ICompressCoder> copyCoder;
NCompress::NLzx::CDecoder *lzxDecoderSpec;
CMyComPtr<ICompressCoder> lzxDecoder;
CMyComPtr<IUnknown> lzxDecoder;
NXpress::CDecoder xpressDecoder;
NCompress::NLzms::CDecoder *lzmsDecoder;
CByteBuffer sizesBuf;
HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode,
ISequentialOutStream *outStream, ICompressProgressInfo *progress);
CMidBuf packBuf;
CMidBuf unpackBuf;
// solid resource
int _solidIndex;
size_t _unpackedChunkIndex;
HRESULT UnpackChunk(
ISequentialInStream *inStream,
unsigned method, unsigned chunkSizeBits,
size_t inSize, size_t outSize,
ISequentialOutStream *outStream);
HRESULT Unpack2(
IInStream *inStream,
const CResource &res,
const CHeader &header,
const CDatabase *db,
ISequentialOutStream *outStream,
ICompressProgressInfo *progress);
public:
HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode,
ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest);
UInt64 TotalPacked;
CUnpacker():
lzmsDecoder(NULL),
_solidIndex(-1),
_unpackedChunkIndex(0),
TotalPacked(0)
{}
~CUnpacker();
HRESULT Unpack(
IInStream *inStream,
const CResource &res,
const CHeader &header,
const CDatabase *db,
ISequentialOutStream *outStream,
ICompressProgressInfo *progress,
Byte *digest);
HRESULT UnpackData(IInStream *inStream,
const CResource &resource, const CHeader &header,
const CDatabase *db,
CByteBuffer &buf, Byte *digest);
};
}}

View File

@@ -10,7 +10,7 @@ namespace NArchive {
namespace NWim {
REGISTER_ARC_IO(
"wim", "wim swm", 0, 0xE6,
"wim", "wim swm esd", 0, 0xE6,
kSignature,
0,
NArcInfoFlags::kAltStreams |

View File

@@ -351,7 +351,8 @@ struct COpenCallbackWrap
static SRes OpenCallbackProgress(void *pp, UInt64 inSize, UInt64 /* outSize */)
{
COpenCallbackWrap *p = (COpenCallbackWrap *)pp;
p->Res = p->OpenCallback->SetCompleted(NULL, &inSize);
if (p->OpenCallback)
p->Res = p->OpenCallback->SetCompleted(NULL, &inSize);
return (SRes)p->Res;
}
@@ -414,7 +415,10 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal
}
RINOK(inStream->Seek(0, STREAM_SEEK_END, &_stat.PhySize));
RINOK(callback->SetTotal(NULL, &_stat.PhySize));
if (callback)
{
RINOK(callback->SetTotal(NULL, &_stat.PhySize));
}
CSeekInStreamWrap inStreamImp(inStream);
@@ -466,7 +470,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal
COM_TRY_BEGIN
{
Close();
return Open2(inStream, /* 0, */ callback);
return Open2(inStream, callback);
}
COM_TRY_END
}

View File

@@ -8,7 +8,7 @@
#include "../../../Common/Defs.h"
#include "../../../Common/StringConvert.h"
#include "../../../Windows/Defs.h"
#include "../../../Windows/TimeUtils.h"
#include "../../../Windows/Thread.h"
#include "../../Common/CreateCoder.h"
@@ -61,6 +61,7 @@ static HRESULT WriteRange(IInStream *inStream, COutArchive &outArchive,
return progress->SetRatioInfo(&range.Size, &range.Size);
}
static void SetFileHeader(
COutArchive &archive,
const CCompressionMethodMode &options,
@@ -108,6 +109,7 @@ static void SetFileHeader(
}
}
static void SetItemInfoFromCompressingResult(const CCompressingResult &compressingResult,
bool isAesMode, Byte aesKeyMode, CItem &item)
{
@@ -134,6 +136,7 @@ static void SetItemInfoFromCompressingResult(const CCompressingResult &compressi
}
}
#ifndef _7ZIP_ST
static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo);
@@ -188,7 +191,6 @@ struct CThreadInfo
Thread.Wait();
Thread.Close();
}
};
void CThreadInfo::WaitAndCode()
@@ -390,9 +392,11 @@ static HRESULT UpdateItemOldData(
complexity += range.Size;
archive.MoveCurPos(range.Size);
}
return S_OK;
}
static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options,
const CUpdateItem &ui, CItemOut &item)
{
@@ -404,15 +408,65 @@ static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *o
archive.WriteLocalHeader_And_SeekToNextFile(item);
}
static inline bool IsZero_FILETIME(const FILETIME &ft)
{
return (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0);
}
static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileInStream,
IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity)
{
CMyComPtr<IStreamGetProps> getProps;
fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
if (!getProps)
return;
FILETIME cTime, aTime, mTime;
UInt64 size;
// UInt32 attrib;
if (getProps->GetProps(&size, &cTime, &aTime, &mTime, NULL) != S_OK)
return;
if (size != item.Size && size != (UInt64)(Int64)-1)
{
Int64 newComplexity = totalComplexity + ((Int64)size - (Int64)item.Size);
if (newComplexity > 0)
{
totalComplexity = newComplexity;
updateCallback->SetTotal(totalComplexity);
}
item.Size = size;
}
if (!IsZero_FILETIME(mTime))
{
item.Ntfs_MTime = mTime;
FILETIME loc = { 0, 0 };
if (FileTimeToLocalFileTime(&mTime, &loc))
{
item.Time = 0;
NTime::FileTimeToDosTime(loc, item.Time);
}
}
if (!IsZero_FILETIME(cTime)) item.Ntfs_CTime = cTime;
if (!IsZero_FILETIME(aTime)) item.Ntfs_ATime = aTime;
// item.Attrib = attrib;
}
static HRESULT Update2St(
DECL_EXTERNAL_CODECS_LOC_VARS
COutArchive &archive,
CInArchive *inArchive,
const CObjectVector<CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
CObjectVector<CUpdateItem> &updateItems,
const CCompressionMethodMode *options,
const CByteBuffer *comment,
IArchiveUpdateCallback *updateCallback,
UInt64 &totalComplexity,
IArchiveUpdateCallbackFile *opCallback)
{
CLocalProgress *lps = new CLocalProgress;
@@ -429,7 +483,7 @@ static HRESULT Update2St(
lps->InSize = unpackSizeTotal;
lps->OutSize = packSizeTotal;
RINOK(lps->SetCur());
const CUpdateItem &ui = updateItems[itemIndex];
CUpdateItem &ui = updateItems[itemIndex];
CItemEx itemEx;
CItemOut item;
@@ -471,8 +525,10 @@ static HRESULT Update2St(
}
*/
// file Size can be 64-bit !!!
UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity);
SetFileHeader(archive, *options, ui, item);
// file Size can be 64-bit !!!
archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options->IsRealAesMode());
CCompressingResult compressingResult;
CMyComPtr<IOutStream> outStream;
@@ -508,6 +564,7 @@ static HRESULT Update2St(
lps->SendRatio = true;
lps->ProgressOffset += complexity;
}
items.Add(item);
lps->ProgressOffset += kLocalHeaderSize;
}
@@ -519,12 +576,13 @@ static HRESULT Update2St(
return S_OK;
}
static HRESULT Update2(
DECL_EXTERNAL_CODECS_LOC_VARS
COutArchive &archive,
CInArchive *inArchive,
const CObjectVector<CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
CObjectVector<CUpdateItem> &updateItems,
const CCompressionMethodMode *options,
const CByteBuffer *comment,
IArchiveUpdateCallback *updateCallback)
@@ -567,6 +625,8 @@ static HRESULT Update2(
complexity++; // end of central
updateCallback->SetTotal(complexity);
UInt64 totalComplexity = complexity;
CAddCommon compressor(*options);
complexity = 0;
@@ -596,6 +656,7 @@ static HRESULT Update2(
mtMode = false;
Byte method = options->MethodSequence.Front();
if (!mtMode)
{
if (options2.MethodInfo.FindProp(NCoderPropID::kNumThreads) < 0)
@@ -643,7 +704,7 @@ static HRESULT Update2(
return Update2St(
EXTERNAL_CODECS_LOC_VARS
archive, inArchive,
inputItems, updateItems, &options2, comment, updateCallback, opCallback);
inputItems, updateItems, &options2, comment, updateCallback, totalComplexity, opCallback);
#ifndef _7ZIP_ST
@@ -691,8 +752,8 @@ static HRESULT Update2(
RINOK(threadInfo.CreateThread());
}
}
unsigned mtItemIndex = 0;
unsigned mtItemIndex = 0;
unsigned itemIndex = 0;
int lastRealStreamItemIndex = -1;
@@ -700,11 +761,12 @@ static HRESULT Update2(
{
if ((UInt32)threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size())
{
const CUpdateItem &ui = updateItems[mtItemIndex++];
CUpdateItem &ui = updateItems[mtItemIndex++];
if (!ui.NewData)
continue;
CItemEx itemEx;
CItemOut item;
if (ui.NewProps)
{
if (ui.IsDir)
@@ -719,7 +781,9 @@ static HRESULT Update2(
if (item.IsDir())
continue;
}
CMyComPtr<ISequentialInStream> fileInStream;
{
NWindows::NSynchronization::CCriticalSectionLock lock(mtProgressMixerSpec->Mixer2->CriticalSection);
HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
@@ -735,6 +799,7 @@ static HRESULT Update2(
RINOK(res);
if (!fileInStream)
return E_INVALIDARG;
UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity);
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
}
@@ -760,6 +825,7 @@ static HRESULT Update2(
break;
}
}
continue;
}
@@ -773,6 +839,7 @@ static HRESULT Update2(
CItemEx itemEx;
CItemOut item;
if (!ui.NewProps || !ui.NewData)
{
itemEx = inputItems[ui.IndexInArc];
@@ -784,6 +851,7 @@ static HRESULT Update2(
if (ui.NewData)
{
bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir());
if (isDir)
{
WriteDirHeader(archive, options, ui, item);
@@ -799,6 +867,7 @@ static HRESULT Update2(
}
CMemBlocks2 &memRef = refs.Refs[itemIndex];
if (memRef.Defined)
{
CMyComPtr<IOutStream> outStream;
@@ -834,6 +903,7 @@ static HRESULT Update2(
DWORD lastError = GetLastError();
return lastError != 0 ? lastError : E_FAIL;
}
unsigned t = (unsigned)(result - WAIT_OBJECT_0);
if (t >= compressingCompletedEvents.Size())
return E_FAIL;
@@ -844,6 +914,7 @@ static HRESULT Update2(
RINOK(threadInfo.Result);
threadIndices.Delete(t);
compressingCompletedEvents.Delete(t);
if (t == 0)
{
RINOK(threadInfo.OutStreamSpec->WriteToRealStream());
@@ -868,17 +939,20 @@ static HRESULT Update2(
{
RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity));
}
items.Add(item);
complexity += kLocalHeaderSize;
mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
itemIndex++;
}
RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL));
archive.WriteCentralDir(items, comment);
return S_OK;
#endif
}
static const size_t kCacheBlockSize = (1 << 20);
static const size_t kCacheSize = (kCacheBlockSize << 2);
static const size_t kCacheMask = (kCacheSize - 1);
@@ -1095,7 +1169,7 @@ STDMETHODIMP CCacheOutStream::SetSize(UInt64 newSize)
HRESULT Update(
DECL_EXTERNAL_CODECS_LOC_VARS
const CObjectVector<CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
CObjectVector<CUpdateItem> &updateItems,
ISequentialOutStream *seqOutStream,
CInArchive *inArchive, bool removeSfx,
CCompressionMethodMode *compressionMethodMode,

View File

@@ -48,7 +48,7 @@ struct CUpdateItem
HRESULT Update(
DECL_EXTERNAL_CODECS_LOC_VARS
const CObjectVector<CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
CObjectVector<CUpdateItem> &updateItems,
ISequentialOutStream *seqOutStream,
CInArchive *inArchive, bool removeSfx,
CCompressionMethodMode *compressionMethodMode,

View File

@@ -1145,14 +1145,6 @@ SOURCE=..\..\Compress\Lzx.h
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Lzx86Converter.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Lzx86Converter.h
# End Source File
# Begin Source File
SOURCE=..\..\Compress\LzxDecoder.cpp
# End Source File
# Begin Source File

View File

@@ -161,7 +161,6 @@ COMPRESS_OBJS = \
$O\LzmaEncoder.obj \
$O\LzmaRegister.obj \
$O\LzOutWindow.obj \
$O\Lzx86Converter.obj \
$O\LzxDecoder.obj \
$O\PpmdDecoder.obj \
$O\PpmdEncoder.obj \

View File

@@ -64,6 +64,8 @@ AR_OBJS = \
$O\FatHandler.obj \
$O\FlvHandler.obj \
$O\GzHandler.obj \
$O\GptHandler.obj \
$O\HandlerCont.obj \
$O\HfsHandler.obj \
$O\IhexHandler.obj \
$O\LzhHandler.obj \
@@ -75,12 +77,15 @@ AR_OBJS = \
$O\NtfsHandler.obj \
$O\PeHandler.obj \
$O\PpmdHandler.obj \
$O\QcowHandler.obj \
$O\RpmHandler.obj \
$O\SplitHandler.obj \
$O\SquashfsHandler.obj \
$O\SwfHandler.obj \
$O\UefiHandler.obj \
$O\VdiHandler.obj \
$O\VhdHandler.obj \
$O\VmdkHandler.obj \
$O\XarHandler.obj \
$O\XzHandler.obj \
$O\ZHandler.obj \
@@ -201,8 +206,8 @@ COMPRESS_OBJS = \
$O\LzmaDecoder.obj \
$O\LzmaEncoder.obj \
$O\LzmaRegister.obj \
$O\LzmsDecoder.obj \
$O\LzOutWindow.obj \
$O\Lzx86Converter.obj \
$O\LzxDecoder.obj \
$O\PpmdDecoder.obj \
$O\PpmdEncoder.obj \
@@ -219,6 +224,7 @@ COMPRESS_OBJS = \
$O\ZlibDecoder.obj \
$O\ZlibEncoder.obj \
$O\ZDecoder.obj \
$O\XPressDecoder.obj \
CRYPTO_OBJS = \
$O\7zAes.obj \

View File

@@ -756,15 +756,17 @@ SOURCE=..\..\Compress\Lzx.h
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Lzx86Converter.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Lzx86Converter.h
# End Source File
# Begin Source File
SOURCE=..\..\Compress\LzxDecoder.cpp
!IF "$(CFG)" == "7z - Win32 Release"
# ADD CPP /O2
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "7z - Win32 Debug"
!ENDIF
# End Source File
# Begin Source File
@@ -793,6 +795,24 @@ SOURCE=..\..\Compress\LzhDecoder.h
# End Source File
# Begin Source File
SOURCE=..\..\Compress\LzmsDecoder.cpp
!IF "$(CFG)" == "7z - Win32 Release"
# ADD CPP /O2
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "7z - Win32 Debug"
!ENDIF
# End Source File
# Begin Source File
SOURCE=..\..\Compress\LzmsDecoder.h
# End Source File
# Begin Source File
SOURCE=..\..\Compress\LzOutWindow.cpp
# End Source File
# Begin Source File
@@ -801,6 +821,24 @@ SOURCE=..\..\Compress\LzOutWindow.h
# End Source File
# Begin Source File
SOURCE=..\..\Compress\XpressDecoder.cpp
!IF "$(CFG)" == "7z - Win32 Release"
# ADD CPP /O2
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "7z - Win32 Debug"
!ENDIF
# End Source File
# Begin Source File
SOURCE=..\..\Compress\XpressDecoder.h
# End Source File
# Begin Source File
SOURCE=..\..\Compress\ZDecoder.cpp
# End Source File
# Begin Source File
@@ -2401,10 +2439,22 @@ SOURCE=..\..\Archive\FlvHandler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\GptHandler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\GzHandler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\HandlerCont.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\HandlerCont.h
# End Source File
# Begin Source File
SOURCE=..\..\Archive\HfsHandler.cpp
# End Source File
# Begin Source File
@@ -2463,6 +2513,10 @@ SOURCE=..\..\Archive\PpmdHandler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\QcowHandler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\RpmHandler.cpp
# End Source File
# Begin Source File
@@ -2483,10 +2537,18 @@ SOURCE=..\..\Archive\UefiHandler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\VdiHandler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\VhdHandler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\VmdkHandler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\XarHandler.cpp
# End Source File
# Begin Source File

View File

@@ -173,7 +173,7 @@ HRESULT CBase::ReadBlock(UInt32 *charCounters, UInt32 blockSizeMax, CBlockProps
}
for (; i < kMaxAlphaSize; i++)
lens[i] = 0;
if (!m_HuffmanDecoders[t].SetCodeLengths(lens))
if (!m_HuffmanDecoders[t].Build(lens))
return S_FALSE;
}
while (++t < numTables);
@@ -205,7 +205,7 @@ HRESULT CBase::ReadBlock(UInt32 *charCounters, UInt32 blockSizeMax, CBlockProps
if (BitDecoder.ExtraBitsWereRead_Fast())
break;
UInt32 nextSym = huffmanDecoder->DecodeSymbol(&BitDecoder);
UInt32 nextSym = huffmanDecoder->Decode(&BitDecoder);
if (nextSym < 2)
{

View File

@@ -26,39 +26,51 @@ Byte CCoder::ReadAlignedByte()
return m_InBitStream.ReadAlignedByte();
}
bool CCoder::DeCodeLevelTable(Byte *values, unsigned numSymbols)
bool CCoder::DecodeLevels(Byte *levels, unsigned numSymbols)
{
unsigned i = 0;
do
{
UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
if (number < kTableDirectLevels)
values[i++] = (Byte)number;
else if (number < kLevelTableSize)
UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream);
if (sym < kTableDirectLevels)
levels[i++] = (Byte)sym;
else
{
if (number == kTableLevelRepNumber)
if (sym >= kLevelTableSize)
return false;
unsigned num;
unsigned numBits;
Byte symbol;
if (sym == kTableLevelRepNumber)
{
if (i == 0)
return false;
unsigned num = ReadBits(2) + 3;
for (; num > 0 && i < numSymbols; num--, i++)
values[i] = values[i - 1];
numBits = 2;
num = 0;
symbol = levels[i - 1];
}
else
{
unsigned num;
if (number == kTableLevel0Number)
num = ReadBits(3) + 3;
else
num = ReadBits(7) + 11;
for (; num > 0 && i < numSymbols; num--)
values[i++] = 0;
sym -= kTableLevel0Number;
sym <<= 2;
numBits = 3 + (unsigned)sym;
num = ((unsigned)sym << 1);
symbol = 0;
}
num += i + 3 + ReadBits(numBits);
if (num > numSymbols)
return false;
do
levels[i++] = symbol;
while (i < num);
}
else
return false;
}
while (i < numSymbols);
return true;
}
@@ -116,10 +128,10 @@ bool CCoder::ReadTables(void)
if (m_InBitStream.ExtraBitsWereRead())
return false;
RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
RIF(m_LevelDecoder.Build(levelLevels));
Byte tmpLevels[kFixedMainTableSize + kFixedDistTableSize];
if (!DeCodeLevelTable(tmpLevels, numLitLenLevels + _numDistLevels))
if (!DecodeLevels(tmpLevels, numLitLenLevels + _numDistLevels))
return false;
if (m_InBitStream.ExtraBitsWereRead())
@@ -129,8 +141,8 @@ bool CCoder::ReadTables(void)
memcpy(levels.litLenLevels, tmpLevels, numLitLenLevels);
memcpy(levels.distLevels, tmpLevels + numLitLenLevels, _numDistLevels);
}
RIF(m_MainDecoder.SetCodeLengths(levels.litLenLevels));
return m_DistDecoder.SetCodeLengths(levels.distLevels);
RIF(m_MainDecoder.Build(levels.litLenLevels));
return m_DistDecoder.Build(levels.distLevels);
}
HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
@@ -161,6 +173,7 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
{
if (m_InBitStream.ExtraBitsWereRead())
return S_FALSE;
if (_needReadTable)
{
if (m_FinalBlock)
@@ -194,43 +207,44 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
if (m_InBitStream.ExtraBitsWereRead_Fast())
return S_FALSE;
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
if (number < 0x100)
UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
if (sym < 0x100)
{
m_OutWindowStream.PutByte((Byte)number);
m_OutWindowStream.PutByte((Byte)sym);
curSize--;
continue;
}
else if (number == kSymbolEndOfBlock)
else if (sym == kSymbolEndOfBlock)
{
_needReadTable = true;
break;
}
else if (number < kMainTableSize)
else if (sym < kMainTableSize)
{
number -= kSymbolMatch;
sym -= kSymbolMatch;
UInt32 len;
{
unsigned numBits;
if (_deflate64Mode)
{
len = kLenStart64[number];
numBits = kLenDirectBits64[number];
len = kLenStart64[sym];
numBits = kLenDirectBits64[sym];
}
else
{
len = kLenStart32[number];
numBits = kLenDirectBits32[number];
len = kLenStart32[sym];
numBits = kLenDirectBits32[sym];
}
len += kMatchMinLen + m_InBitStream.ReadBits(numBits);
}
UInt32 locLen = len;
if (locLen > curSize)
locLen = (UInt32)curSize;
number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
if (number >= _numDistLevels)
sym = m_DistDecoder.Decode(&m_InBitStream);
if (sym >= _numDistLevels)
return S_FALSE;
UInt32 distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]);
UInt32 distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
if (!m_OutWindowStream.CopyBlock(distance, locLen))
return S_FALSE;
curSize -= locLen;
@@ -248,7 +262,7 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
if (finishInputStream && curSize == 0)
{
if (m_MainDecoder.DecodeSymbol(&m_InBitStream) != kSymbolEndOfBlock)
if (m_MainDecoder.Decode(&m_InBitStream) != kSymbolEndOfBlock)
return S_FALSE;
_needReadTable = true;
}
@@ -260,6 +274,7 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
return S_OK;
}
#ifdef _NO_EXCEPTIONS
#define DEFLATE_TRY_BEGIN
@@ -275,6 +290,7 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
#endif
HRESULT CCoder::CodeReal(ISequentialOutStream *outStream,
const UInt64 *outSize, ICompressProgressInfo *progress)
{
@@ -285,6 +301,7 @@ HRESULT CCoder::CodeReal(ISequentialOutStream *outStream,
const UInt64 inStart = _needInitInStream ? 0 : m_InBitStream.GetProcessedSize();
const UInt64 start = m_OutWindowStream.GetProcessedSize();
for (;;)
{
UInt32 curSize = 1 << 18;
@@ -311,12 +328,14 @@ HRESULT CCoder::CodeReal(ISequentialOutStream *outStream,
RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
}
}
if (_remainLen == kLenIdFinished && ZlibMode)
{
m_InBitStream.AlignToByte();
for (unsigned i = 0; i < 4; i++)
ZlibFooter[i] = ReadAlignedByte();
}
flusher.NeedFlush = false;
res = Flush();
if (res == S_OK && _remainLen != kLenIdNeedInit && InputEofError())
@@ -337,7 +356,7 @@ HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStr
STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value)
{
if (value == NULL)
if (!value)
return E_INVALIDARG;
*value = m_InBitStream.GetProcessedSize();
return S_OK;

View File

@@ -36,7 +36,7 @@ class CCoder:
NBitl::CDecoder<CInBuffer> m_InBitStream;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedMainTableSize> m_MainDecoder;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedDistTableSize> m_DistDecoder;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
NCompress::NHuffman::CDecoder7b<kLevelTableSize> m_LevelDecoder;
UInt32 m_StoredBlockSize;
@@ -56,7 +56,7 @@ class CCoder:
UInt32 ReadBits(unsigned numBits);
bool DeCodeLevelTable(Byte *values, unsigned numSymbols);
bool DecodeLevels(Byte *levels, unsigned numSymbols);
bool ReadTables();
HRESULT Flush() { return m_OutWindowStream.Flush(); }

View File

@@ -8,42 +8,33 @@
namespace NCompress {
namespace NHuffman {
const unsigned kNumTableBits = 9;
template <unsigned kNumBitsMax, UInt32 m_NumSymbols>
template <unsigned kNumBitsMax, UInt32 m_NumSymbols, unsigned kNumTableBits = 9>
class CDecoder
{
UInt32 m_Limits[kNumBitsMax + 1]; // m_Limits[i] = value limit for symbols with length = i
UInt32 m_Positions[kNumBitsMax + 1]; // m_Positions[i] = index in m_Symbols[] of first symbol with length = i
UInt32 m_Symbols[m_NumSymbols];
Byte m_Lengths[1 << kNumTableBits]; // Table of length for short codes
UInt32 _limits[kNumBitsMax + 2];
UInt32 _poses[kNumBitsMax + 1];
UInt16 _lens[1 << kNumTableBits];
UInt16 _symbols[m_NumSymbols];
public:
bool SetCodeLengths(const Byte *lens)
bool Build(const Byte *lens) throw()
{
UInt32 lenCounts[kNumBitsMax + 1];
UInt32 tmpPositions[kNumBitsMax + 1];
UInt32 tmpPoses[kNumBitsMax + 1];
unsigned i;
for (i = 1; i <= kNumBitsMax; i++)
for (i = 0; i <= kNumBitsMax; i++)
lenCounts[i] = 0;
UInt32 symbol;
UInt32 sym;
for (symbol = 0; symbol < m_NumSymbols; symbol++)
{
unsigned len = lens[symbol];
if (len > kNumBitsMax)
return false;
lenCounts[len]++;
m_Symbols[symbol] = 0xFFFFFFFF;
}
for (sym = 0; sym < m_NumSymbols; sym++)
lenCounts[lens[sym]]++;
lenCounts[0] = 0;
m_Positions[0] = m_Limits[0] = 0;
_poses[0] = 0;
_limits[0] = 0;
UInt32 startPos = 0;
UInt32 index = 0;
const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
for (i = 1; i <= kNumBitsMax; i++)
@@ -51,44 +42,216 @@ public:
startPos += lenCounts[i] << (kNumBitsMax - i);
if (startPos > kMaxValue)
return false;
m_Limits[i] = (i == kNumBitsMax) ? kMaxValue : startPos;
m_Positions[i] = m_Positions[i - 1] + lenCounts[i - 1];
tmpPositions[i] = m_Positions[i];
if (i <= kNumTableBits)
_limits[i] = startPos;
_poses[i] = _poses[i - 1] + lenCounts[i - 1];
tmpPoses[i] = _poses[i];
}
_limits[kNumBitsMax + 1] = kMaxValue;
for (sym = 0; sym < m_NumSymbols; sym++)
{
unsigned len = lens[sym];
if (len == 0)
continue;
unsigned offset = tmpPoses[len];
_symbols[offset] = (UInt16)sym;
tmpPoses[len] = offset + 1;
if (len <= kNumTableBits)
{
UInt32 limit = (m_Limits[i] >> (kNumBitsMax - kNumTableBits));
for (; index < limit; index++)
m_Lengths[index] = (Byte)i;
offset -= _poses[len];
UInt32 num = (UInt32)1 << (kNumTableBits - len);
UInt16 val = (UInt16)((sym << 4) | len);
UInt16 *dest = _lens + (_limits[len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len));
for (UInt32 k = 0; k < num; k++)
dest[k] = val;
}
}
for (symbol = 0; symbol < m_NumSymbols; symbol++)
return true;
}
bool BuildFull(const Byte *lens, UInt32 numSymbols = m_NumSymbols) throw()
{
UInt32 lenCounts[kNumBitsMax + 1];
UInt32 tmpPoses[kNumBitsMax + 1];
unsigned i;
for (i = 0; i <= kNumBitsMax; i++)
lenCounts[i] = 0;
UInt32 sym;
for (sym = 0; sym < numSymbols; sym++)
lenCounts[lens[sym]]++;
lenCounts[0] = 0;
_poses[0] = 0;
_limits[0] = 0;
UInt32 startPos = 0;
const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
for (i = 1; i <= kNumBitsMax; i++)
{
unsigned len = lens[symbol];
if (len != 0)
m_Symbols[tmpPositions[len]++] = symbol;
startPos += lenCounts[i] << (kNumBitsMax - i);
if (startPos > kMaxValue)
return false;
_limits[i] = startPos;
_poses[i] = _poses[i - 1] + lenCounts[i - 1];
tmpPoses[i] = _poses[i];
}
_limits[kNumBitsMax + 1] = kMaxValue;
for (sym = 0; sym < numSymbols; sym++)
{
unsigned len = lens[sym];
if (len == 0)
continue;
unsigned offset = tmpPoses[len];
_symbols[offset] = (UInt16)sym;
tmpPoses[len] = offset + 1;
if (len <= kNumTableBits)
{
offset -= _poses[len];
UInt32 num = (UInt32)1 << (kNumTableBits - len);
UInt16 val = (UInt16)((sym << 4) | len);
UInt16 *dest = _lens + (_limits[len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len));
for (UInt32 k = 0; k < num; k++)
dest[k] = val;
}
}
return startPos == kMaxValue;
}
template <class TBitDecoder>
UInt32 Decode(TBitDecoder *bitStream) const throw()
{
UInt32 val = bitStream->GetValue(kNumBitsMax);
if (val < _limits[kNumTableBits])
{
UInt32 pair = _lens[val >> (kNumBitsMax - kNumTableBits)];
bitStream->MovePos((unsigned)(pair & 0xF));
return pair >> 4;
}
unsigned numBits;
for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++);
if (numBits > kNumBitsMax)
return 0xFFFFFFFF;
bitStream->MovePos(numBits);
UInt32 index = _poses[numBits] + ((val - _limits[numBits - 1]) >> (kNumBitsMax - numBits));
return _symbols[index];
}
template <class TBitDecoder>
UInt32 DecodeFull(TBitDecoder *bitStream) const throw()
{
UInt32 val = bitStream->GetValue(kNumBitsMax);
if (val < _limits[kNumTableBits])
{
UInt32 pair = _lens[val >> (kNumBitsMax - kNumTableBits)];
bitStream->MovePos((unsigned)(pair & 0xF));
return pair >> 4;
}
unsigned numBits;
for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++);
bitStream->MovePos(numBits);
UInt32 index = _poses[numBits] + ((val - _limits[numBits - 1]) >> (kNumBitsMax - numBits));
return _symbols[index];
}
};
template <UInt32 m_NumSymbols>
class CDecoder7b
{
Byte _lens[1 << 7];
public:
bool Build(const Byte *lens) throw()
{
const unsigned kNumBitsMax = 7;
UInt32 lenCounts[kNumBitsMax + 1];
UInt32 tmpPoses[kNumBitsMax + 1];
UInt32 _poses[kNumBitsMax + 1];
UInt32 _limits[kNumBitsMax + 1];
unsigned i;
for (i = 0; i <= kNumBitsMax; i++)
lenCounts[i] = 0;
UInt32 sym;
for (sym = 0; sym < m_NumSymbols; sym++)
lenCounts[lens[sym]]++;
lenCounts[0] = 0;
_poses[0] = 0;
_limits[0] = 0;
UInt32 startPos = 0;
const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
for (i = 1; i <= kNumBitsMax; i++)
{
startPos += lenCounts[i] << (kNumBitsMax - i);
if (startPos > kMaxValue)
return false;
_limits[i] = startPos;
_poses[i] = _poses[i - 1] + lenCounts[i - 1];
tmpPoses[i] = _poses[i];
}
for (sym = 0; sym < m_NumSymbols; sym++)
{
unsigned len = lens[sym];
if (len == 0)
continue;
unsigned offset = tmpPoses[len];
tmpPoses[len] = offset + 1;
{
offset -= _poses[len];
UInt32 num = (UInt32)1 << (kNumBitsMax - len);
Byte val = (Byte)((sym << 3) | len);
Byte *dest = _lens + (_limits[len - 1]) + (offset << (kNumBitsMax - len));
for (UInt32 k = 0; k < num; k++)
dest[k] = val;
}
}
{
UInt32 limit = _limits[kNumBitsMax];
UInt32 num = ((UInt32)1 << kNumBitsMax) - limit;
Byte *dest = _lens + limit;
for (UInt32 k = 0; k < num; k++)
dest[k] = (Byte)(0x1F << 3);
}
return true;
}
template <class TBitDecoder>
UInt32 DecodeSymbol(TBitDecoder *bitStream)
UInt32 Decode(TBitDecoder *bitStream) const throw()
{
unsigned numBits;
UInt32 val = bitStream->GetValue(kNumBitsMax);
if (val < m_Limits[kNumTableBits])
numBits = m_Lengths[val >> (kNumBitsMax - kNumTableBits)];
else
for (numBits = kNumTableBits + 1; val >= m_Limits[numBits]; numBits++);
bitStream->MovePos(numBits);
UInt32 index = m_Positions[numBits] + ((val - m_Limits[numBits - 1]) >> (kNumBitsMax - numBits));
if (index >= m_NumSymbols)
// throw CDecoderException(); // test it
return 0xFFFFFFFF;
return m_Symbols[index];
UInt32 val = bitStream->GetValue(7);
UInt32 pair = _lens[val];
bitStream->MovePos((unsigned)(pair & 0x7));
return pair >> 3;
}
};

View File

@@ -71,7 +71,7 @@ bool CCoder::ReadTP(unsigned num, unsigned numBits, int spec)
if (!CheckCodeLens(lens, NPT))
return false;
return _decoderT.SetCodeLengths(lens);
return _decoderT.Build(lens);
}
}
@@ -101,7 +101,7 @@ bool CCoder::ReadC()
{
UInt32 c = (unsigned)_symbolT;
if (_symbolT < 0)
c = _decoderT.DecodeSymbol(&_inBitStream);
c = _decoderT.Decode(&_inBitStream);
if (c <= 2)
{
@@ -129,7 +129,7 @@ bool CCoder::ReadC()
if (!CheckCodeLens(lens, NC))
return false;
return _decoderC.SetCodeLengths(lens);
return _decoderC.Build(lens);
}
}
@@ -169,7 +169,7 @@ HRESULT CCoder::CodeReal(UInt64 rem, ICompressProgressInfo *progress)
UInt32 number = (unsigned)_symbolC;
if (_symbolC < 0)
number = _decoderC.DecodeSymbol(&_inBitStream);
number = _decoderC.Decode(&_inBitStream);
if (number < 256)
{
@@ -182,7 +182,7 @@ HRESULT CCoder::CodeReal(UInt64 rem, ICompressProgressInfo *progress)
UInt32 dist = (unsigned)_symbolT;
if (_symbolT < 0)
dist = _decoderT.DecodeSymbol(&_inBitStream);
dist = _decoderT.Decode(&_inBitStream);
if (dist > 1)
{

View File

@@ -0,0 +1,573 @@
// LzmsDecoder.cpp
// The code is based on LZMS description from wimlib code
#include "StdAfx.h"
#include "../../../C/Alloc.h"
#include "LzmsDecoder.h"
namespace NCompress {
namespace NLzms {
static UInt32 g_PosBases[k_NumPosSyms /* + 1 */];
static Byte g_PosDirectBits[k_NumPosSyms];
static const Byte k_PosRuns[31] =
{
8, 0, 9, 7, 10, 15, 15, 20, 20, 30, 33, 40, 42, 45, 60, 73,
80, 85, 95, 105, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
};
static UInt32 g_LenBases[k_NumLenSyms];
static const Byte k_LenDirectBits[k_NumLenSyms] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2,
2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 6,
7, 8, 9, 10, 16, 30,
};
static struct CInit
{
CInit()
{
{
unsigned sum = 0;
for (unsigned i = 0; i < sizeof(k_PosRuns); i++)
{
unsigned t = k_PosRuns[i];
for (unsigned y = 0; y < t; y++)
g_PosDirectBits[sum + y] = (Byte)i;
sum += t;
}
}
{
UInt32 sum = 1;
for (unsigned i = 0; i < k_NumPosSyms; i++)
{
g_PosBases[i] = sum;
sum += (UInt32)1 << g_PosDirectBits[i];
}
// g_PosBases[k_NumPosSyms] = sum;
}
{
UInt32 sum = 1;
for (unsigned i = 0; i < k_NumLenSyms; i++)
{
g_LenBases[i] = sum;
sum += (UInt32)1 << k_LenDirectBits[i];
}
}
}
} g_Init;
static unsigned GetNumPosSlots(size_t size)
{
if (size < 2)
return 0;
size--;
if (size >= g_PosBases[k_NumPosSyms - 1])
return k_NumPosSyms;
unsigned left = 0;
unsigned right = k_NumPosSyms;
for (;;)
{
unsigned m = (left + right) / 2;
if (left == m)
return m + 1;
if (size >= g_PosBases[m])
left = m;
else
right = m;
}
}
static const Int32 k_x86_WindowSize = 65535;
static const Int32 k_x86_TransOffset = 1023;
static const size_t k_x86_HistorySize = (1 << 16);
static void x86_Filter(Byte *data, UInt32 size, Int32 *history)
{
if (size <= 17)
return;
Byte isCode[256];
memset(isCode, 0, 256);
isCode[0x48] = 1;
isCode[0x4C] = 1;
isCode[0xE8] = 1;
isCode[0xE9] = 1;
isCode[0xF0] = 1;
isCode[0xFF] = 1;
{
for (size_t i = 0; i < k_x86_HistorySize; i++)
history[i] = -(Int32)k_x86_WindowSize - 1;
}
size -= 16;
const unsigned kSave = 6;
const Byte savedByte = data[size + kSave];
data[size + kSave] = 0xE8;
Int32 last_x86_pos = -k_x86_TransOffset - 1;
// first byte is ignored
Int32 i = 0;
for (;;)
{
const Byte *p = data + (UInt32)i;
for (;;)
{
if (isCode[*(++p)]) break;
if (isCode[*(++p)]) break;
}
i = (Int32)(p - data);
if ((UInt32)i >= size)
break;
UInt32 codeLen;
Int32 maxTransOffset = k_x86_TransOffset;
Byte b = p[0];
if (b == 0x48)
{
if (p[1] == 0x8B)
{
if ((p[2] & 0xF7) != 0x5)
continue;
// MOV RAX / RCX, [RIP + disp32]
}
else if (p[1] == 0x8D) // LEA
{
if ((p[2] & 0x7) != 0x5)
continue;
// LEA R**, []
}
else
continue;
codeLen = 3;
}
else if (b == 0x4C)
{
if (p[1] != 0x8D || (p[2] & 0x7) != 0x5)
continue;
// LEA R*, []
codeLen = 3;
}
else if (b == 0xE8)
{
// CALL
codeLen = 1;
maxTransOffset /= 2;
}
else if (b == 0xE9)
{
// JUMP
i += 4;
continue;
}
else if (b == 0xF0)
{
if (p[1] != 0x83 || p[2] != 0x05)
continue;
// LOCK ADD [RIP + disp32], imm8
// LOCK ADD [disp32], imm8
codeLen = 3;
}
else
// if (b == 0xFF)
{
if (p[1] != 0x15)
continue;
// CALL [RIP + disp32];
// CALL [disp32];
codeLen = 2;
}
Int32 *target;
{
const Byte *p2 = p + codeLen;
UInt32 n = GetUi32(p2);
if (i - last_x86_pos <= maxTransOffset)
{
n -= i;
SetUi32(p2, n);
}
target = history + (((UInt32)i + n) & 0xFFFF);
}
i += codeLen + sizeof(UInt32) - 1;
if (i - *target <= k_x86_WindowSize)
last_x86_pos = i;
*target = i;
}
data[size + kSave] = savedByte;
}
static const int kLenIdNeedInit = -2;
CDecoder::CDecoder():
_x86_history(NULL)
{
}
CDecoder::~CDecoder()
{
::MidFree(_x86_history);
}
#define RIF(x) { if (!(x)) return false; }
#define LIMIT_CHECK if (_bs._buf < _rc.cur) return S_FALSE;
// #define LIMIT_CHECK
#define READ_BITS_CHECK(numDirectBits) \
if (_bs._buf < _rc.cur) return S_FALSE; \
if ((size_t)(_bs._buf - _rc.cur) < (numDirectBits >> 3)) return S_FALSE;
#define HUFF_DEC(sym, pp) \
sym = pp.DecodeFull(&_bs); \
pp.Freqs[sym]++; \
if (--pp.RebuildRem == 0) pp.Rebuild();
HRESULT CDecoder::CodeReal(const Byte *in, size_t inSize, Byte *_win, size_t outSize)
{
// size_t inSizeT = (size_t)(inSize);
// Byte *_win;
// size_t _pos;
_pos = 0;
CBitDecoder _bs;
CRangeDecoder _rc;
if (inSize < 8 || (inSize & 1) != 0)
return S_FALSE;
_rc.Init(in, inSize);
if (_rc.code >= _rc.range)
return S_FALSE;
_bs.Init(in, inSize);
{
{
unsigned i;
for (i = 0 ; i < k_NumReps + 1; i++)
_reps[i] = i + 1;
for (i = 0 ; i < k_NumReps + 1; i++)
_deltaReps[i] = i + 1;
mainState = 0;
matchState = 0;
{ for (size_t i = 0; i < k_NumMainProbs; i++) mainProbs[i].Init(); }
{ for (size_t i = 0; i < k_NumMatchProbs; i++) matchProbs[i].Init(); }
{
for (size_t k = 0; k < k_NumReps; k++)
{
lzRepStates[k] = 0;
for (size_t i = 0; i < k_NumRepProbs; i++)
lzRepProbs[k][i].Init();
}
}
{
for (size_t k = 0; k < k_NumReps; k++)
{
deltaRepStates[k] = 0;
for (size_t i = 0; i < k_NumRepProbs; i++)
deltaRepProbs[k][i].Init();
}
}
m_LitDecoder.Init();
m_LenDecoder.Init();
m_PowerDecoder.Init();
unsigned numPosSyms = GetNumPosSlots(outSize);
if (numPosSyms < 2)
numPosSyms = 2;
m_PosDecoder.Init(numPosSyms);
m_DeltaDecoder.Init(numPosSyms);
}
}
{
unsigned prevType = 0;
while (_pos < outSize)
{
if (_rc.Decode(&mainState, k_NumMainProbs, mainProbs) == 0)
{
UInt32 number;
HUFF_DEC(number, m_LitDecoder);
LIMIT_CHECK
_win[_pos++] = (Byte)number;
prevType = 0;
}
else if (_rc.Decode(&matchState, k_NumMatchProbs, matchProbs) == 0)
{
UInt32 distance;
if (_rc.Decode(&lzRepStates[0], k_NumRepProbs, lzRepProbs[0]) == 0)
{
UInt32 number;
HUFF_DEC(number, m_PosDecoder);
LIMIT_CHECK
unsigned numDirectBits = g_PosDirectBits[number];
distance = g_PosBases[number];
READ_BITS_CHECK(numDirectBits);
distance += _bs.ReadBits32(numDirectBits);
// LIMIT_CHECK
_reps[3] = _reps[2];
_reps[2] = _reps[1];
_reps[1] = _reps[0];
_reps[0] = distance;
}
else
{
if (_rc.Decode(&lzRepStates[1], k_NumRepProbs, lzRepProbs[1]) == 0)
{
if (prevType != 1)
distance = _reps[0];
else
{
distance = _reps[1];
_reps[1] = _reps[0];
_reps[0] = distance;
}
}
else if (_rc.Decode(&lzRepStates[2], k_NumRepProbs, lzRepProbs[2]) == 0)
{
if (prevType != 1)
{
distance = _reps[1];
_reps[1] = _reps[0];
_reps[0] = distance;
}
else
{
distance = _reps[2];
_reps[2] = _reps[1];
_reps[1] = _reps[0];
_reps[0] = distance;
}
}
else
{
if (prevType != 1)
{
distance = _reps[2];
_reps[2] = _reps[1];
_reps[1] = _reps[0];
_reps[0] = distance;
}
else
{
distance = _reps[3];
_reps[3] = _reps[2];
_reps[2] = _reps[1];
_reps[1] = _reps[0];
_reps[0] = distance;
}
}
}
UInt32 lenSlot;
HUFF_DEC(lenSlot, m_LenDecoder);
LIMIT_CHECK
UInt32 len = g_LenBases[lenSlot];
{
unsigned numDirectBits = k_LenDirectBits[lenSlot];
READ_BITS_CHECK(numDirectBits);
len += _bs.ReadBits32(numDirectBits);
}
// LIMIT_CHECK
if (len > outSize - _pos)
return S_FALSE;
if (distance > _pos)
return S_FALSE;
Byte *dest = _win + _pos;
const Byte *src = dest - distance;
_pos += len;
do
*dest++ = *src++;
while (--len);
prevType = 1;
}
else
{
UInt64 distance;
UInt32 power;
UInt32 distance32;
if (_rc.Decode(&deltaRepStates[0], k_NumRepProbs, deltaRepProbs[0]) == 0)
{
HUFF_DEC(power, m_PowerDecoder);
LIMIT_CHECK
UInt32 number;
HUFF_DEC(number, m_DeltaDecoder);
LIMIT_CHECK
unsigned numDirectBits = g_PosDirectBits[number];
distance32 = g_PosBases[number];
READ_BITS_CHECK(numDirectBits);
distance32 += _bs.ReadBits32(numDirectBits);
// LIMIT_CHECK
distance = ((UInt64)power << 32) | distance32;
_deltaReps[3] = _deltaReps[2];
_deltaReps[2] = _deltaReps[1];
_deltaReps[1] = _deltaReps[0];
_deltaReps[0] = distance;
}
else
{
if (_rc.Decode(&deltaRepStates[1], k_NumRepProbs, deltaRepProbs[1]) == 0)
{
if (prevType != 2)
distance = _deltaReps[0];
else
{
distance = _deltaReps[1];
_deltaReps[1] = _deltaReps[0];
_deltaReps[0] = distance;
}
}
else if (_rc.Decode(&deltaRepStates[2], k_NumRepProbs, deltaRepProbs[2]) == 0)
{
if (prevType != 2)
{
distance = _deltaReps[1];
_deltaReps[1] = _deltaReps[0];
_deltaReps[0] = distance;
}
else
{
distance = _deltaReps[2];
_deltaReps[2] = _deltaReps[1];
_deltaReps[1] = _deltaReps[0];
_deltaReps[0] = distance;
}
}
else
{
if (prevType != 2)
{
distance = _deltaReps[2];
_deltaReps[2] = _deltaReps[1];
_deltaReps[1] = _deltaReps[0];
_deltaReps[0] = distance;
}
else
{
distance = _deltaReps[3];
_deltaReps[3] = _deltaReps[2];
_deltaReps[2] = _deltaReps[1];
_deltaReps[1] = _deltaReps[0];
_deltaReps[0] = distance;
}
}
distance32 = (UInt32)_deltaReps[0] & 0xFFFFFFFF;
power = (UInt32)(_deltaReps[0] >> 32);
}
UInt32 dist = (distance32 << power);
UInt32 lenSlot;
HUFF_DEC(lenSlot, m_LenDecoder);
LIMIT_CHECK
UInt32 len = g_LenBases[lenSlot];
{
unsigned numDirectBits = k_LenDirectBits[lenSlot];
READ_BITS_CHECK(numDirectBits);
len += _bs.ReadBits32(numDirectBits);
}
// LIMIT_CHECK
if (len > outSize - _pos)
return S_FALSE;
if (dist > _pos)
return S_FALSE;
size_t span = (size_t)1 << power;
Byte *dest = _win + _pos - span;
const Byte *src = dest - dist;
_pos += len;
do
{
*(dest + span) = (Byte)(*(dest) + *(src + span) - *(src));
src++;
dest++;
}
while (--len);
prevType = 2;
}
}
}
_rc.Normalize();
if (_rc.code != 0)
return S_FALSE;
if (_rc.cur > _bs._buf ||
_rc.cur == _bs._buf && _bs._bitPos != 0)
return S_FALSE;
/*
int delta = (int)(_bs._buf - _rc.cur);
if (_bs._bitPos != 0)
delta--;
if ((delta & 1))
delta--;
printf("%d ", delta);
*/
return S_OK;
}
HRESULT CDecoder::Code(const Byte *in, size_t inSize, Byte *out, size_t outSize)
{
if (!_x86_history)
{
_x86_history = (Int32 *)::MidAlloc(sizeof(Int32) * k_x86_HistorySize);
if (!_x86_history)
return E_OUTOFMEMORY;
}
HRESULT res;
// try
{
res = CodeReal(in, inSize, out, outSize);
}
// catch (...) { res = S_FALSE; }
x86_Filter(out, (UInt32)_pos, _x86_history);
return res;
}
}}

View File

@@ -0,0 +1,271 @@
// LzmsDecoder.h
// The code is based on LZMS description from wimlib code
#ifndef __LZMS_DECODER_H
#define __LZMS_DECODER_H
// #define SHOW_DEBUG_INFO
#ifdef SHOW_DEBUG_INFO
#include <stdio.h>
#define PRF(x) x
#else
// #define PRF(x)
#endif
#include "../../../C/CpuArch.h"
#include "../../../C/HuffEnc.h"
#include "../../Common/MyBuffer.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
#include "HuffmanDecoder.h"
namespace NCompress {
namespace NLzms {
class CBitDecoder
{
public:
const Byte *_buf;
unsigned _bitPos;
void Init(const Byte *buf, size_t size) throw()
{
_buf = buf + size;
_bitPos = 0;
}
UInt32 GetValue(unsigned numBits) const
{
UInt32 v = ((UInt32)_buf[-1] << 16) | ((UInt32)_buf[-2] << 8) | (UInt32)_buf[-3];
v >>= (24 - numBits - _bitPos);
return v & ((1 << numBits) - 1);
}
void MovePos(unsigned numBits)
{
_bitPos += numBits;
_buf -= (_bitPos >> 3);
_bitPos &= 7;
}
UInt32 ReadBits32(unsigned numBits)
{
UInt32 mask = (((UInt32)1 << numBits) - 1);
numBits += _bitPos;
const Byte *buf = _buf;
UInt32 v = GetUi32(buf - 4);
if (numBits > 32)
{
v <<= (numBits - 32);
v |= (UInt32)buf[-5] >> (40 - numBits);
}
else
v >>= (32 - numBits);
_buf = buf - (numBits >> 3);
_bitPos = numBits & 7;
return v & mask;
}
};
const unsigned k_NumLitSyms = 256;
const unsigned k_NumLenSyms = 54;
const unsigned k_NumPosSyms = 799;
const unsigned k_NumPowerSyms = 8;
const unsigned k_NumProbBits = 6;
const unsigned k_ProbLimit = 1 << k_NumProbBits;
const unsigned k_InitialProb = 48;
const UInt32 k_InitialHist = 0x55555555;
const unsigned k_NumReps = 3;
const unsigned k_NumMainProbs = 16;
const unsigned k_NumMatchProbs = 32;
const unsigned k_NumRepProbs = 64;
const unsigned k_NumHuffmanBits = 15;
template <UInt32 m_NumSyms, UInt32 m_RebuildFreq, unsigned numTableBits>
class CHuffDecoder: public NCompress::NHuffman::CDecoder<k_NumHuffmanBits, m_NumSyms, numTableBits>
{
public:
UInt32 RebuildRem;
UInt32 NumSyms;
UInt32 Freqs[m_NumSyms];
void Generate() throw()
{
UInt32 vals[m_NumSyms];
Byte levels[m_NumSyms];
// We need to check that our algorithm is OK, when optimal Huffman tree uses more than 15 levels !!!
Huffman_Generate(Freqs, vals, levels, NumSyms, k_NumHuffmanBits);
/*
for (UInt32 i = NumSyms; i < m_NumSyms; i++)
levels[i] = 0;
*/
this->BuildFull(levels, NumSyms);
}
void Rebuild() throw()
{
Generate();
RebuildRem = m_RebuildFreq;
UInt32 num = NumSyms;
for (UInt32 i = 0; i < num; i++)
Freqs[i] = (Freqs[i] >> 1) + 1;
}
public:
void Init(UInt32 numSyms = m_NumSyms) throw()
{
RebuildRem = m_RebuildFreq;
NumSyms = numSyms;
for (UInt32 i = 0; i < numSyms; i++)
Freqs[i] = 1;
// for (; i < m_NumSyms; i++) Freqs[i] = 0;
Generate();
}
};
struct CProbEntry
{
UInt32 Prob;
UInt64 Hist;
void Init()
{
Prob = k_InitialProb;
Hist = k_InitialHist;
}
UInt32 GetProb() const throw()
{
UInt32 prob = Prob;
if (prob == 0)
prob = 1;
else if (prob == k_ProbLimit)
prob = k_ProbLimit - 1;
return prob;
}
void Update(unsigned bit) throw()
{
Prob += (Int32)(Hist >> (k_ProbLimit - 1)) - (Int32)bit;
Hist = (Hist << 1) | bit;
}
};
struct CRangeDecoder
{
UInt32 range;
UInt32 code;
const Byte *cur;
// const Byte *end;
void Init(const Byte *data, size_t /* size */) throw()
{
range = 0xFFFFFFFF;
code = (((UInt32)GetUi16(data)) << 16) | GetUi16(data + 2);
cur = data + 4;
// end = data + size;
}
void Normalize()
{
if (range <= 0xFFFF)
{
range <<= 16;
code <<= 16;
// if (cur >= end) throw 1;
code |= GetUi16(cur);
cur += 2;
}
}
unsigned Decode(UInt32 *state, UInt32 numStates, struct CProbEntry *probs)
{
UInt32 st = *state;
CProbEntry *entry = &probs[st];
st = (st << 1) & (numStates - 1);
UInt32 prob = entry->GetProb();
if (range <= 0xFFFF)
{
range <<= 16;
code <<= 16;
// if (cur >= end) throw 1;
code |= GetUi16(cur);
cur += 2;
}
UInt32 bound = (range >> k_NumProbBits) * prob;
if (code < bound)
{
range = bound;
*state = st;
entry->Update(0);
return 0;
}
else
{
range -= bound;
code -= bound;
*state = st | 1;
entry->Update(1);
return 1;
}
}
};
class CDecoder
{
// CRangeDecoder _rc;
// CBitDecoder _bs;
size_t _pos;
UInt32 _reps[k_NumReps + 1];
UInt64 _deltaReps[k_NumReps + 1];
UInt32 mainState;
UInt32 matchState;
UInt32 lzRepStates[k_NumReps];
UInt32 deltaRepStates[k_NumReps];
struct CProbEntry mainProbs[k_NumMainProbs];
struct CProbEntry matchProbs[k_NumMatchProbs];
struct CProbEntry lzRepProbs[k_NumReps][k_NumRepProbs];
struct CProbEntry deltaRepProbs[k_NumReps][k_NumRepProbs];
CHuffDecoder<k_NumLitSyms, 1024, 9> m_LitDecoder;
CHuffDecoder<k_NumPosSyms, 1024, 9> m_PosDecoder;
CHuffDecoder<k_NumLenSyms, 512, 8> m_LenDecoder;
CHuffDecoder<k_NumPowerSyms, 512, 6> m_PowerDecoder;
CHuffDecoder<k_NumPosSyms, 1024, 9> m_DeltaDecoder;
Int32 *_x86_history;
HRESULT CodeReal(const Byte *in, size_t inSize, Byte *out, size_t outSize);
public:
CDecoder();
~CDecoder();
HRESULT Code(const Byte *in, size_t inSize, Byte *out, size_t outSize);
const size_t GetUnpackSize() const { return _pos; }
};
}}
#endif

View File

@@ -6,55 +6,51 @@
namespace NCompress {
namespace NLzx {
const unsigned kBlockType_NumBits = 3;
const unsigned kBlockType_Verbatim = 1;
const unsigned kBlockType_Aligned = 2;
const unsigned kBlockType_Uncompressed = 3;
const unsigned kNumHuffmanBits = 16;
const UInt32 kNumRepDistances = 3;
const unsigned kNumReps = 3;
const UInt32 kNumLenSlots = 8;
const UInt32 kMatchMinLen = 2;
const UInt32 kNumLenSymbols = 249;
const UInt32 kMatchMaxLen = kMatchMinLen + (kNumLenSlots - 1) + kNumLenSymbols - 1;
const unsigned kNumLenSlots = 8;
const unsigned kMatchMinLen = 2;
const unsigned kNumLenSymbols = 249;
const unsigned kMatchMaxLen = kMatchMinLen + (kNumLenSlots - 1) + kNumLenSymbols - 1;
const unsigned kNumAlignLevelBits = 3;
const unsigned kNumAlignBits = 3;
const UInt32 kAlignTableSize = 1 << kNumAlignBits;
const unsigned kAlignTableSize = 1 << kNumAlignBits;
const UInt32 kNumPosSlots = 50;
const UInt32 kNumPosLenSlots = kNumPosSlots * kNumLenSlots;
const unsigned kNumPosSlots = 50;
const unsigned kNumPosLenSlots = kNumPosSlots * kNumLenSlots;
const UInt32 kMainTableSize = 256 + kNumPosLenSlots;
const UInt32 kLevelTableSize = 20;
const UInt32 kMaxTableSize = kMainTableSize;
const unsigned kMainTableSize = 256 + kNumPosLenSlots;
const unsigned kLevelTableSize = 20;
const unsigned kMaxTableSize = kMainTableSize;
const unsigned kNumBlockTypeBits = 3;
const unsigned kBlockTypeVerbatim = 1;
const unsigned kBlockTypeAligned = 2;
const unsigned kBlockTypeUncompressed = 3;
const unsigned kNumLevelBits = 4;
const unsigned kUncompressedBlockSizeNumBits = 24;
const unsigned kLevelSym_Zero1 = 17;
const unsigned kLevelSym_Zero2 = 18;
const unsigned kLevelSym_Same = 19;
const unsigned kNumBitsForPreTreeLevel = 4;
const unsigned kLevelSym_Zero1_Start = 4;
const unsigned kLevelSym_Zero1_NumBits = 4;
const unsigned kLevelSymbolZeros = 17;
const unsigned kLevelSymbolZerosBig = 18;
const unsigned kLevelSymbolSame = 19;
const unsigned kLevelSym_Zero2_Start = kLevelSym_Zero1_Start + (1 << kLevelSym_Zero1_NumBits);
const unsigned kLevelSym_Zero2_NumBits = 5;
const unsigned kLevelSymbolZerosStartValue = 4;
const unsigned kLevelSymbolZerosNumBits = 4;
const unsigned kLevelSym_Same_NumBits = 1;
const unsigned kLevelSym_Same_Start = 4;
const unsigned kLevelSymbolZerosBigStartValue = kLevelSymbolZerosStartValue +
(1 << kLevelSymbolZerosNumBits);
const unsigned kLevelSymbolZerosBigNumBits = 5;
const unsigned kLevelSymbolSameNumBits = 1;
const unsigned kLevelSymbolSameStartValue = 4;
const unsigned kNumBitsForAlignLevel = 3;
const unsigned kNumDictionaryBitsMin = 15;
const unsigned kNumDictionaryBitsMax = 21;
const UInt32 kDictionarySizeMax = (1 << kNumDictionaryBitsMax);
const unsigned kNumDictBits_Min = 15;
const unsigned kNumDictBits_Max = 21;
const UInt32 kDictSize_Max = (UInt32)1 << kNumDictBits_Max;
const unsigned kNumLinearPosSlotBits = 17;
const UInt32 kNumPowerPosSlots = 0x26;
const unsigned kNumPowerPosSlots = 38;
}}

View File

@@ -1,90 +0,0 @@
// Lzx86Converter.cpp
#include "StdAfx.h"
#include "../../Common/Defs.h"
#include "Lzx86Converter.h"
namespace NCompress {
namespace NLzx {
static const UInt32 kResidue = 6 + 4;
void Cx86ConvertOutStream::MakeTranslation()
{
if (_pos <= kResidue)
return;
UInt32 numBytes = _pos - kResidue;
Byte *buf = _buf;
for (UInt32 i = 0; i < numBytes;)
{
if (buf[i++] == 0xE8)
{
Int32 absValue = 0;
unsigned j;
for (j = 0; j < 4; j++)
absValue += (UInt32)buf[i + j] << (j * 8);
Int32 pos = (Int32)(_processedSize + i - 1);
if (absValue >= -pos && absValue < (Int32)_translationSize)
{
UInt32 offset = (absValue >= 0) ?
absValue - pos :
absValue + _translationSize;
for (j = 0; j < 4; j++)
{
buf[i + j] = (Byte)(offset & 0xFF);
offset >>= 8;
}
}
i += 4;
}
}
}
STDMETHODIMP Cx86ConvertOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
{
if (processedSize)
*processedSize = 0;
if (!_translationMode)
return _stream->Write(data, size, processedSize);
UInt32 realProcessedSize = 0;
while (realProcessedSize < size)
{
UInt32 writeSize = MyMin(size - realProcessedSize, kUncompressedBlockSize - _pos);
memcpy(_buf + _pos, (const Byte *)data + realProcessedSize, writeSize);
_pos += writeSize;
realProcessedSize += writeSize;
if (_pos == kUncompressedBlockSize)
{
RINOK(Flush());
}
}
if (processedSize)
*processedSize = realProcessedSize;
return S_OK;
}
HRESULT Cx86ConvertOutStream::Flush()
{
if (_pos == 0)
return S_OK;
if (_translationMode)
MakeTranslation();
UInt32 pos = 0;
do
{
UInt32 processed;
RINOK(_stream->Write(_buf + pos, _pos - pos, &processed));
if (processed == 0)
return E_FAIL;
pos += processed;
}
while (pos < _pos);
_processedSize += _pos;
_pos = 0;
_translationMode = (_translationMode && (_processedSize < ((UInt32)1 << 30)));
return S_OK;
}
}}

View File

@@ -1,45 +0,0 @@
// Lzx86Converter.h
#ifndef __LZX_86_CONVERTER_H
#define __LZX_86_CONVERTER_H
#include "../../Common/MyCom.h"
#include "../IStream.h"
namespace NCompress {
namespace NLzx {
const unsigned kUncompressedBlockSize = (unsigned)1 << 15;
class Cx86ConvertOutStream:
public ISequentialOutStream,
public CMyUnknownImp
{
ISequentialOutStream *_stream;
UInt32 _processedSize;
UInt32 _pos;
UInt32 _translationSize;
bool _translationMode;
Byte _buf[kUncompressedBlockSize];
void MakeTranslation();
public:
void SetStream(ISequentialOutStream *outStream) { _stream = outStream; }
void Init(bool translationMode, UInt32 translationSize)
{
_translationMode = translationMode;
_translationSize = translationSize;
_processedSize = 0;
_pos = 0;
}
HRESULT Flush();
MY_UNKNOWN_IMP
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
};
}}
#endif

View File

@@ -2,394 +2,528 @@
#include "StdAfx.h"
#include "../../Common/Defs.h"
#include <string.h>
// #define SHOW_DEBUG_INFO
#ifdef SHOW_DEBUG_INFO
#include <stdio.h>
#define PRF(x) x
#else
#define PRF(x)
#endif
#include "../../../C/Alloc.h"
#include "LzxDecoder.h"
namespace NCompress {
namespace NLzx {
const int kLenIdNeedInit = -2;
static void x86_Filter(Byte *data, UInt32 size, UInt32 processedSize, UInt32 translationSize)
{
const UInt32 kResidue = 10;
if (size <= kResidue)
return;
size -= kResidue;
Byte save = data[size + 4];
data[size + 4] = 0xE8;
for (UInt32 i = 0;;)
{
const Byte *p = data + i;
for (;;)
{
if (*p++ == 0xE8) break;
if (*p++ == 0xE8) break;
if (*p++ == 0xE8) break;
if (*p++ == 0xE8) break;
}
i = (UInt32)(p - data);
if (i > size)
break;
{
Int32 v = GetUi32(p);
Int32 pos = (Int32)((Int32)1 - (Int32)(processedSize + i));
i += 4;
if (v >= pos && v < (Int32)translationSize)
{
v += (v >= 0 ? pos : translationSize);
SetUi32(p, v);
}
}
}
data[size + 4] = save;
}
CDecoder::CDecoder(bool wimMode):
_keepHistory(false),
_skipByte(false),
_wimMode(wimMode)
_win(NULL),
_keepHistory(false),
_skipByte(false),
_wimMode(wimMode),
_numDictBits(15),
_unpackBlockSize(0),
_x86_buf(NULL),
_x86_translationSize(0),
KeepHistoryForNext(true),
NeedAlloc(true),
_unpackedData(NULL)
{
m_x86ConvertOutStreamSpec = new Cx86ConvertOutStream;
m_x86ConvertOutStream = m_x86ConvertOutStreamSpec;
}
/*
void CDecoder::ReleaseStreams()
CDecoder::~CDecoder()
{
m_OutWindowStream.ReleaseStream();
m_InBitStream.ReleaseStream();
m_x86ConvertOutStreamSpec->ReleaseStream();
}
*/
STDMETHODIMP CDecoder::Flush()
{
RINOK(m_OutWindowStream.Flush());
return m_x86ConvertOutStreamSpec->Flush();
if (NeedAlloc)
::MidFree(_win);
::MidFree(_x86_buf);
}
UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); }
HRESULT CDecoder::Flush()
{
if (_x86_translationSize != 0)
{
Byte *destData = _win + _writePos;
UInt32 curSize = _pos - _writePos;
if (KeepHistoryForNext)
{
if (!_x86_buf)
{
// we must change it to support another chunk sizes
const size_t kChunkSize = (size_t)1 << 15;
if (curSize > kChunkSize)
return E_NOTIMPL;
_x86_buf = (Byte *)::MidAlloc(kChunkSize);
if (!_x86_buf)
return E_OUTOFMEMORY;
}
memcpy(_x86_buf, destData, curSize);
_unpackedData = _x86_buf;
destData = _x86_buf;
}
x86_Filter(destData, (UInt32)curSize, _x86_processedSize, _x86_translationSize);
_x86_processedSize += (UInt32)curSize;
if (_x86_processedSize >= ((UInt32)1 << 30))
_x86_translationSize = 0;
}
return S_OK;
}
UInt32 CDecoder::ReadBits(unsigned numBits) { return _bitStream.ReadBitsSmall(numBits); }
#define RIF(x) { if (!(x)) return false; }
bool CDecoder::ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols)
bool CDecoder::ReadTable(Byte *levels, unsigned numSymbols)
{
Byte levelLevels[kLevelTableSize];
UInt32 i;
for (i = 0; i < kLevelTableSize; i++)
levelLevels[i] = (Byte)ReadBits(kNumBitsForPreTreeLevel);
RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
unsigned num = 0;
Byte symbol = 0;
for (i = 0; i < numSymbols;)
{
if (num != 0)
Byte levels2[kLevelTableSize];
for (unsigned i = 0; i < kLevelTableSize; i++)
levels2[i] = (Byte)ReadBits(kNumLevelBits);
RIF(_levelDecoder.Build(levels2));
}
unsigned i = 0;
do
{
UInt32 sym = _levelDecoder.Decode(&_bitStream);
if (sym <= kNumHuffmanBits)
{
lastLevels[i] = newLevels[i] = symbol;
i++;
num--;
int delta = (int)levels[i] - (int)sym;
delta += (delta < 0) ? (kNumHuffmanBits + 1) : 0;
levels[i++] = (Byte)delta;
continue;
}
UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
if (number == kLevelSymbolZeros)
unsigned num;
Byte symbol;
if (sym < kLevelSym_Same)
{
num = kLevelSymbolZerosStartValue + (unsigned)ReadBits(kLevelSymbolZerosNumBits);
sym -= kLevelSym_Zero1;
num = kLevelSym_Zero1_Start + ((unsigned)sym << kLevelSym_Zero1_NumBits) +
(unsigned)ReadBits(kLevelSym_Zero1_NumBits + sym);
symbol = 0;
}
else if (number == kLevelSymbolZerosBig)
else if (sym == kLevelSym_Same)
{
num = kLevelSymbolZerosBigStartValue + (unsigned)ReadBits(kLevelSymbolZerosBigNumBits);
symbol = 0;
}
else if (number == kLevelSymbolSame || number <= kNumHuffmanBits)
{
if (number <= kNumHuffmanBits)
num = 1;
else
{
num = kLevelSymbolSameStartValue + (unsigned)ReadBits(kLevelSymbolSameNumBits);
number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
if (number > kNumHuffmanBits)
return false;
}
symbol = Byte((17 + lastLevels[i] - number) % (kNumHuffmanBits + 1));
num = kLevelSym_Same_Start + (unsigned)ReadBits(kLevelSym_Same_NumBits);
sym = _levelDecoder.Decode(&_bitStream);
if (sym > kNumHuffmanBits)
return false;
int delta = (int)levels[i] - (int)sym;
delta += (delta < 0) ? (kNumHuffmanBits + 1) : 0;
symbol = (Byte)delta;
}
else
return false;
unsigned limit = i + num;
if (limit > numSymbols)
return false;
do
levels[i++] = symbol;
while (i < limit);
}
while (i < numSymbols);
return true;
}
bool CDecoder::ReadTables(void)
{
Byte newLevels[kMaxTableSize];
{
if (_skipByte)
m_InBitStream.DirectReadByte();
m_InBitStream.Normalize();
unsigned blockType = (unsigned)ReadBits(kNumBlockTypeBits);
if (blockType > kBlockTypeUncompressed)
return false;
if (_wimMode)
if (ReadBits(1) == 1)
m_UnCompressedBlockSize = (1 << 15);
else
m_UnCompressedBlockSize = ReadBits(16);
else
m_UnCompressedBlockSize = m_InBitStream.ReadBitsBig(kUncompressedBlockSizeNumBits);
m_IsUncompressedBlock = (blockType == kBlockTypeUncompressed);
_skipByte = (m_IsUncompressedBlock && ((m_UnCompressedBlockSize & 1) != 0));
if (m_IsUncompressedBlock)
{
ReadBits(16 - m_InBitStream.GetBitPosition());
if (!m_InBitStream.ReadUInt32(m_RepDistances[0]))
if (_bitStream.DirectReadByte() != 0)
return false;
m_RepDistances[0]--;
for (unsigned i = 1; i < kNumRepDistances; i++)
}
_bitStream.NormalizeBig();
unsigned blockType = (unsigned)ReadBits(kBlockType_NumBits);
if (blockType > kBlockType_Uncompressed)
return false;
_unpackBlockSize = (1 << 15);
if (!_wimMode || ReadBits(1) == 0)
{
_unpackBlockSize = ReadBits(16);
// wimlib supports chunks larger than 32KB (unsupported my MS wim).
if (!_wimMode || _numDictBits >= 16)
{
UInt32 rep = 0;
for (unsigned j = 0; j < 4; j++)
rep |= (UInt32)m_InBitStream.DirectReadByte() << (8 * j);
m_RepDistances[i] = rep - 1;
_unpackBlockSize <<= 8;
_unpackBlockSize |= ReadBits(8);
}
}
PRF(printf("\nBlockSize = %6d %s ", _unpackBlockSize, (_pos & 1) ? "@@@" : " "));
_isUncompressedBlock = (blockType == kBlockType_Uncompressed);
_skipByte = false;
if (_isUncompressedBlock)
{
_skipByte = ((_unpackBlockSize & 1) != 0);
PRF(printf(" UncompressedBlock "));
if (_unpackBlockSize & 1)
{
PRF(printf(" ######### "));
}
if (!_bitStream.PrepareUncompressed())
return false;
if (_bitStream.GetRem() < kNumReps * 4)
return false;
for (unsigned i = 0; i < kNumReps; i++)
{
UInt32 rep = _bitStream.ReadUInt32();
if (rep > _winSize)
return false;
_reps[i] = rep;
}
return true;
}
m_AlignIsUsed = (blockType == kBlockTypeAligned);
if (m_AlignIsUsed)
_numAlignBits = 64;
if (blockType == kBlockType_Aligned)
{
Byte levels[kAlignTableSize];
_numAlignBits = kNumAlignBits;
for (unsigned i = 0; i < kAlignTableSize; i++)
newLevels[i] = (Byte)ReadBits(kNumBitsForAlignLevel);
RIF(m_AlignDecoder.SetCodeLengths(newLevels));
levels[i] = (Byte)ReadBits(kNumAlignLevelBits);
RIF(_alignDecoder.Build(levels));
}
}
RIF(ReadTable(m_LastMainLevels, newLevels, 256));
RIF(ReadTable(m_LastMainLevels + 256, newLevels + 256, m_NumPosLenSlots));
for (UInt32 i = 256 + m_NumPosLenSlots; i < kMainTableSize; i++)
newLevels[i] = 0;
RIF(m_MainDecoder.SetCodeLengths(newLevels));
RIF(ReadTable(m_LastLenLevels, newLevels, kNumLenSymbols));
return m_LenDecoder.SetCodeLengths(newLevels);
}
class CDecoderFlusher
{
CDecoder *m_Decoder;
public:
bool NeedFlush;
CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {}
~CDecoderFlusher()
{
if (NeedFlush)
m_Decoder->Flush();
// m_Decoder->ReleaseStreams();
}
};
void CDecoder::ClearPrevLevels()
{
unsigned i;
for (i = 0; i < kMainTableSize; i++)
m_LastMainLevels[i] = 0;
for (i = 0; i < kNumLenSymbols; i++)
m_LastLenLevels[i] = 0;
RIF(ReadTable(_mainLevels, 256));
RIF(ReadTable(_mainLevels + 256, _numPosLenSlots));
unsigned end = 256 + _numPosLenSlots;
memset(_mainLevels + end, 0, kMainTableSize - end);
RIF(_mainDecoder.Build(_mainLevels));
RIF(ReadTable(_lenLevels, kNumLenSymbols));
return _lenDecoder.Build(_lenLevels);
}
HRESULT CDecoder::CodeSpec(UInt32 curSize)
{
if (_remainLen == kLenIdNeedInit)
if (!_keepHistory || !_isUncompressedBlock)
_bitStream.NormalizeBig();
if (!_keepHistory)
{
_remainLen = 0;
m_InBitStream.Init();
if (!_keepHistory || !m_IsUncompressedBlock)
m_InBitStream.Normalize();
if (!_keepHistory)
_skipByte = false;
_unpackBlockSize = 0;
memset(_mainLevels, 0, kMainTableSize);
memset(_lenLevels, 0, kNumLenSymbols);
{
_skipByte = false;
m_UnCompressedBlockSize = 0;
ClearPrevLevels();
UInt32 i86TranslationSize = 12000000;
bool translationMode = true;
_x86_translationSize = 12000000;
if (!_wimMode)
{
translationMode = (ReadBits(1) != 0);
if (translationMode)
_x86_translationSize = 0;
if (ReadBits(1) != 0)
{
i86TranslationSize = ReadBits(16) << 16;
i86TranslationSize |= ReadBits(16);
UInt32 v = ReadBits(16) << 16;
v |= ReadBits(16);
_x86_translationSize = v;
}
}
m_x86ConvertOutStreamSpec->Init(translationMode, i86TranslationSize);
for (unsigned i = 0 ; i < kNumRepDistances; i++)
m_RepDistances[i] = 0;
_x86_processedSize = 0;
}
}
while (_remainLen > 0 && curSize > 0)
{
m_OutWindowStream.PutByte(m_OutWindowStream.GetByte(m_RepDistances[0]));
_remainLen--;
curSize--;
_reps[0] = 1;
_reps[1] = 1;
_reps[2] = 1;
}
while (curSize > 0)
{
if (m_UnCompressedBlockSize == 0)
if (_bitStream.WasExtraReadError_Fast())
return S_FALSE;
if (_unpackBlockSize == 0)
{
if (!ReadTables())
return S_FALSE;
UInt32 next = (Int32)MyMin(m_UnCompressedBlockSize, curSize);
curSize -= next;
m_UnCompressedBlockSize -= next;
if (m_IsUncompressedBlock)
{
while (next > 0)
{
m_OutWindowStream.PutByte(m_InBitStream.DirectReadByte());
next--;
}
continue;
}
else while (next > 0)
UInt32 next = _unpackBlockSize;
if (next > curSize)
next = curSize;
if (_isUncompressedBlock)
{
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
if (number < 256)
size_t rem = _bitStream.GetRem();
if (rem == 0)
return S_FALSE;
if (next > rem)
next = (UInt32)rem;
_bitStream.CopyTo(_win + _pos, next);
_pos += next;
curSize -= next;
_unpackBlockSize -= next;
/* we don't know where skipByte can be placed, if it's end of chunk:
1) in current chunk - there are such cab archives, if chunk is last
2) in next chunk - are there such archives ? */
if (_skipByte
&& _unpackBlockSize == 0
&& curSize == 0
&& _bitStream.IsOneDirectByteLeft())
{
m_OutWindowStream.PutByte((Byte)number);
next--;
}
else
{
UInt32 posLenSlot = number - 256;
if (posLenSlot >= m_NumPosLenSlots)
_skipByte = false;
if (_bitStream.DirectReadByte() != 0)
return S_FALSE;
UInt32 posSlot = posLenSlot / kNumLenSlots;
UInt32 lenSlot = posLenSlot % kNumLenSlots;
}
continue;
}
curSize -= next;
_unpackBlockSize -= next;
Byte *win = _win;
while (next > 0)
{
if (_bitStream.WasExtraReadError_Fast())
return S_FALSE;
UInt32 sym = _mainDecoder.Decode(&_bitStream);
if (sym < 256)
{
win[_pos++] = (Byte)sym;
next--;
continue;
}
{
sym -= 256;
if (sym >= _numPosLenSlots)
return S_FALSE;
UInt32 posSlot = sym / kNumLenSlots;
UInt32 lenSlot = sym % kNumLenSlots;
UInt32 len = kMatchMinLen + lenSlot;
if (lenSlot == kNumLenSlots - 1)
{
UInt32 lenTemp = m_LenDecoder.DecodeSymbol(&m_InBitStream);
UInt32 lenTemp = _lenDecoder.Decode(&_bitStream);
if (lenTemp >= kNumLenSymbols)
return S_FALSE;
len += lenTemp;
len = kMatchMinLen + kNumLenSlots - 1 + lenTemp;
}
if (posSlot < kNumRepDistances)
UInt32 dist;
if (posSlot < kNumReps)
{
UInt32 distance = m_RepDistances[posSlot];
m_RepDistances[posSlot] = m_RepDistances[0];
m_RepDistances[0] = distance;
dist = _reps[posSlot];
_reps[posSlot] = _reps[0];
_reps[0] = dist;
}
else
{
UInt32 distance;
unsigned numDirectBits;
if (posSlot < kNumPowerPosSlots)
{
numDirectBits = (unsigned)(posSlot >> 1) - 1;
distance = ((2 | (posSlot & 1)) << numDirectBits);
dist = ((2 | (posSlot & 1)) << numDirectBits);
}
else
{
numDirectBits = kNumLinearPosSlotBits;
distance = ((posSlot - 0x22) << kNumLinearPosSlotBits);
dist = ((posSlot - 0x22) << kNumLinearPosSlotBits);
}
if (m_AlignIsUsed && numDirectBits >= kNumAlignBits)
if (numDirectBits >= _numAlignBits)
{
distance += (m_InBitStream.ReadBits(numDirectBits - kNumAlignBits) << kNumAlignBits);
UInt32 alignTemp = m_AlignDecoder.DecodeSymbol(&m_InBitStream);
dist += (_bitStream.ReadBitsSmall(numDirectBits - kNumAlignBits) << kNumAlignBits);
UInt32 alignTemp = _alignDecoder.Decode(&_bitStream);
if (alignTemp >= kAlignTableSize)
return S_FALSE;
distance += alignTemp;
dist += alignTemp;
}
else
distance += m_InBitStream.ReadBits(numDirectBits);
m_RepDistances[2] = m_RepDistances[1];
m_RepDistances[1] = m_RepDistances[0];
m_RepDistances[0] = distance - kNumRepDistances;
dist += _bitStream.ReadBitsBig(numDirectBits);
dist -= kNumReps - 1;
_reps[2] = _reps[1];
_reps[1] = _reps[0];
_reps[0] = dist;
}
UInt32 locLen = len;
if (locLen > next)
locLen = next;
if (!m_OutWindowStream.CopyBlock(m_RepDistances[0], locLen))
if (len > next)
return S_FALSE;
len -= locLen;
next -= locLen;
if (len != 0)
if (dist > _pos && !_overDict)
return S_FALSE;
Byte *dest = win + _pos;
const UInt32 mask = (_winSize - 1);
UInt32 srcPos = (_pos - dist) & mask;
next -= len;
if (len > _winSize - srcPos)
{
_remainLen = (int)len;
return S_OK;
_pos += len;
do
{
*dest++ = win[srcPos++];
srcPos &= mask;
}
while (--len);
}
else
{
ptrdiff_t src = (ptrdiff_t)srcPos - (ptrdiff_t)_pos;
_pos += len;
const Byte *lim = dest + len;
*(dest) = *(dest + src);
dest++;
do
*(dest) = *(dest + src);
while (++dest != lim);
}
}
}
}
if (!_bitStream.WasFinishedOK())
return S_FALSE;
return S_OK;
}
HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress)
HRESULT CDecoder::Code(const Byte *inData, size_t inSize, UInt32 outSize)
{
if (outSize == NULL)
return E_INVALIDARG;
UInt64 size = *outSize;
// RINOK(SetInStream(inStream));
m_InBitStream.SetStream(inStream);
m_x86ConvertOutStreamSpec->SetStream(outStream);
m_OutWindowStream.SetStream(m_x86ConvertOutStream);
RINOK(SetOutStreamSize(outSize));
CDecoderFlusher flusher(this);
const UInt64 start = m_OutWindowStream.GetProcessedSize();
for (;;)
if (_pos == _winSize)
{
UInt32 curSize = 1 << 18;
UInt64 rem = size - (m_OutWindowStream.GetProcessedSize() - start);
if (curSize > rem)
curSize = (UInt32)rem;
if (curSize == 0)
break;
RINOK(CodeSpec(curSize));
if (progress != NULL)
_pos = 0;
_overDict = true;
}
if (!_keepHistory)
{
_pos = 0;
_overDict = false;
}
_writePos = _pos;
_unpackedData = _win + _pos;
if (outSize > _winSize - _pos)
return S_FALSE;
PRF(printf("\ninSize = %d", inSize));
if ((inSize & 1) != 0)
{
PRF(printf(" ---------"));
}
if (inSize < 1)
return S_FALSE;
_bitStream.Init(inData, inSize);
HRESULT res = CodeSpec(outSize);
HRESULT res2 = Flush();
return (res == S_OK ? res2 : res);
}
HRESULT CDecoder::SetParams2(unsigned numDictBits)
{
_numDictBits = numDictBits;
if (numDictBits < kNumDictBits_Min || numDictBits > kNumDictBits_Max)
return E_INVALIDARG;
unsigned numPosSlots = (numDictBits < 20) ?
numDictBits * 2 :
34 + ((unsigned)1 << (numDictBits - 17));
_numPosLenSlots = numPosSlots * kNumLenSlots;
return S_OK;
}
HRESULT CDecoder::SetParams_and_Alloc(unsigned numDictBits)
{
RINOK(SetParams2(numDictBits));
UInt32 newWinSize = (UInt32)1 << numDictBits;
if (NeedAlloc)
{
if (!_win || newWinSize != _winSize)
{
UInt64 inSize = m_InBitStream.GetProcessedSize();
UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;
RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
::MidFree(_win);
_winSize = 0;
_win = (Byte *)::MidAlloc(newWinSize);
if (!_win)
return E_OUTOFMEMORY;
}
}
flusher.NeedFlush = false;
return Flush();
}
HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
{
try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
catch(const CLzOutWindowException &e) { return e.ErrorCode; }
catch(...) { return S_FALSE; }
}
/*
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
{
m_InStreamRef = inStream;
m_InBitStream.SetStream(inStream);
return S_OK;
}
STDMETHODIMP CDecoder::ReleaseInStream()
{
m_InStreamRef.Release();
return S_OK;
}
*/
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
{
if (outSize == NULL)
return E_FAIL;
// flush calls m_x86ConvertOutStreamSpec->flush, so we must init x86Convert.
if (!_keepHistory)
m_x86ConvertOutStreamSpec->Init(false, 0);
_remainLen = kLenIdNeedInit;
m_OutWindowStream.Init(_keepHistory);
return S_OK;
}
HRESULT CDecoder::SetParams(unsigned numDictBits)
{
if (numDictBits < kNumDictionaryBitsMin || numDictBits > kNumDictionaryBitsMax)
return E_INVALIDARG;
UInt32 numPosSlots;
if (numDictBits < 20)
numPosSlots = 30 + (numDictBits - 15) * 2;
else if (numDictBits == 20)
numPosSlots = 42;
else
numPosSlots = 50;
m_NumPosLenSlots = numPosSlots * kNumLenSlots;
if (!m_OutWindowStream.Create(kDictionarySizeMax))
return E_OUTOFMEMORY;
if (!m_InBitStream.Create(1 << 16))
return E_OUTOFMEMORY;
_winSize = (UInt32)newWinSize;
return S_OK;
}

View File

@@ -3,155 +3,240 @@
#ifndef __LZX_DECODER_H
#define __LZX_DECODER_H
#include "../ICoder.h"
#include "../../../C/CpuArch.h"
#include "../Common/InBuffer.h"
#include "../../Common/MyCom.h"
#include "HuffmanDecoder.h"
#include "LzOutWindow.h"
#include "Lzx.h"
#include "Lzx86Converter.h"
namespace NCompress {
namespace NLzx {
namespace NBitStream {
const unsigned kNumBigValueBits = 8 * 4;
const unsigned kNumValueBits = 17;
const UInt32 kBitDecoderValueMask = (1 << kNumValueBits) - 1;
class CDecoder
class CBitDecoder
{
CInBuffer _stream;
UInt32 _value;
unsigned _bitPos;
UInt32 _value;
const Byte *_buf;
const Byte *_bufLim;
UInt32 _extraSize;
public:
CDecoder() {}
bool Create(UInt32 bufSize) { return _stream.Create(bufSize); }
void SetStream(ISequentialInStream *s) { _stream.SetStream(s); }
void Init()
void Init(const Byte *data, size_t size)
{
_stream.Init();
_bitPos = kNumBigValueBits;
_buf = data;
_bufLim = data + size - 1;
_bitPos = 0;
_extraSize = 0;
}
UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); }
size_t GetRem() const { return _bufLim + 1 - _buf; }
bool WasExtraReadError_Fast() const { return _extraSize > 4; }
unsigned GetBitPosition() const { return _bitPos & 0xF; }
void Normalize()
bool WasFinishedOK() const
{
for (; _bitPos >= 16; _bitPos -= 16)
if (_buf != _bufLim + 1)
return false;
if ((_bitPos >> 4) * 2 != _extraSize)
return false;
unsigned numBits = _bitPos & 15;
return (((_value >> (_bitPos - numBits)) & (((UInt32)1 << numBits) - 1)) == 0);
}
void NormalizeSmall()
{
if (_bitPos <= 16)
{
Byte b0 = _stream.ReadByte();
Byte b1 = _stream.ReadByte();
_value = (_value << 8) | b1;
_value = (_value << 8) | b0;
UInt32 val;
if (_buf >= _bufLim)
{
val = 0xFFFF;
_extraSize += 2;
}
else
{
val = GetUi16(_buf);
_buf += 2;
}
_value = (_value << 16) | val;
_bitPos += 16;
}
}
void NormalizeBig()
{
if (_bitPos <= 16)
{
UInt32 val;
if (_buf >= _bufLim)
{
val = 0xFFFF;
_extraSize += 2;
}
else
{
val = GetUi16(_buf);
_buf += 2;
}
_value = (_value << 16) | val;
_bitPos += 16;
if (_bitPos <= 16)
{
UInt32 val;
if (_buf >= _bufLim)
{
val = 0xFFFF;
_extraSize += 2;
}
else
{
val = GetUi16(_buf);
_buf += 2;
}
_value = (_value << 16) | val;
_bitPos += 16;
}
}
}
UInt32 GetValue(unsigned numBits) const
{
return ((_value >> ((32 - kNumValueBits) - _bitPos)) & kBitDecoderValueMask) >> (kNumValueBits - numBits);
return (_value >> (_bitPos - numBits)) & (((UInt32)1 << numBits) - 1);
}
void MovePos(unsigned numBits)
{
_bitPos += numBits;
Normalize();
_bitPos -= numBits;
NormalizeSmall();
}
UInt32 ReadBits(unsigned numBits)
UInt32 ReadBitsSmall(unsigned numBits)
{
UInt32 res = GetValue(numBits);
MovePos(numBits);
return res;
_bitPos -= numBits;
UInt32 val = (_value >> _bitPos) & (((UInt32)1 << numBits) - 1);
NormalizeSmall();
return val;
}
UInt32 ReadBitsBig(unsigned numBits)
{
unsigned numBits0 = numBits / 2;
unsigned numBits1 = numBits - numBits0;
UInt32 res = ReadBits(numBits0) << numBits1;
return res + ReadBits(numBits1);
_bitPos -= numBits;
UInt32 val = (_value >> _bitPos) & (((UInt32)1 << numBits) - 1);
NormalizeBig();
return val;
}
bool ReadUInt32(UInt32 &v)
bool PrepareUncompressed()
{
if (_bitPos != 0)
if (_extraSize != 0)
return false;
v = ((_value >> 16) & 0xFFFF) | ((_value << 16) & 0xFFFF0000);
_bitPos = kNumBigValueBits;
unsigned numBits = _bitPos - 16;
if (((_value >> 16) & (((UInt32)1 << numBits) - 1)) != 0)
return false;
_buf -= 2;
_bitPos = 0;
return true;
}
Byte DirectReadByte() { return _stream.ReadByte(); }
UInt32 ReadUInt32()
{
UInt32 v = GetUi32(_buf);
_buf += 4;
return v;
}
void CopyTo(Byte *dest, size_t size)
{
memcpy(dest, _buf, size);
_buf += size;
}
bool IsOneDirectByteLeft() const { return _buf == _bufLim && _extraSize == 0; }
Byte DirectReadByte()
{
if (_buf > _bufLim)
{
_extraSize++;
return 0xFF;
}
return *_buf++;
}
};
}
class CDecoder :
public ICompressCoder,
class CDecoder:
public IUnknown,
public CMyUnknownImp
{
// CMyComPtr<ISequentialInStream> m_InStreamRef;
NBitStream::CDecoder m_InBitStream;
CLzOutWindow m_OutWindowStream;
CBitDecoder _bitStream;
Byte *_win;
UInt32 _pos;
UInt32 _winSize;
UInt32 m_RepDistances[kNumRepDistances];
UInt32 m_NumPosLenSlots;
bool m_IsUncompressedBlock;
bool m_AlignIsUsed;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kNumLenSymbols> m_LenDecoder;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
Byte m_LastMainLevels[kMainTableSize];
Byte m_LastLenLevels[kNumLenSymbols];
Cx86ConvertOutStream *m_x86ConvertOutStreamSpec;
CMyComPtr<ISequentialOutStream> m_x86ConvertOutStream;
UInt32 m_UnCompressedBlockSize;
bool _keepHistory;
int _remainLen;
bool _overDict;
bool _isUncompressedBlock;
bool _skipByte;
unsigned _numAlignBits;
UInt32 _reps[kNumReps];
UInt32 _numPosLenSlots;
UInt32 _unpackBlockSize;
public:
bool KeepHistoryForNext;
bool NeedAlloc;
private:
bool _keepHistory;
bool _wimMode;
unsigned _numDictBits;
UInt32 _writePos;
Byte *_x86_buf;
UInt32 _x86_translationSize;
UInt32 _x86_processedSize;
Byte *_unpackedData;
NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> _mainDecoder;
NHuffman::CDecoder<kNumHuffmanBits, kNumLenSymbols> _lenDecoder;
NHuffman::CDecoder7b<kAlignTableSize> _alignDecoder;
NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize, 7> _levelDecoder;
Byte _mainLevels[kMainTableSize];
Byte _lenLevels[kNumLenSymbols];
HRESULT Flush();
UInt32 ReadBits(unsigned numBits);
bool ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols);
bool ReadTable(Byte *levels, unsigned numSymbols);
bool ReadTables();
void ClearPrevLevels();
HRESULT CodeSpec(UInt32 size);
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
HRESULT SetParams2(unsigned numDictBits);
public:
CDecoder(bool wimMode = false);
~CDecoder();
MY_UNKNOWN_IMP
// void ReleaseStreams();
STDMETHOD(Flush)();
HRESULT SetExternalWindow(Byte *win, unsigned numDictBits)
{
NeedAlloc = false;
_win = win;
_winSize = (UInt32)1 << numDictBits;
return SetParams2(numDictBits);
}
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
// STDMETHOD(SetInStream)(ISequentialInStream *inStream);
// STDMETHOD(ReleaseInStream)();
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
HRESULT SetParams_and_Alloc(unsigned numDictBits);
HRESULT SetParams(unsigned numDictBits);
void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
HRESULT Code(const Byte *inData, size_t inSize, UInt32 outSize);
bool WasBlockFinished() const { return _unpackBlockSize == 0; }
const Byte *GetUnpackData() const { return _unpackedData; }
const UInt32 GetUnpackSize() const { return _pos - _writePos; }
};
}}

View File

@@ -9,13 +9,81 @@
namespace NCompress {
namespace NQuantum {
static const int kLenIdNeedInit = -2;
static const unsigned kNumLenSymbols = 27;
static const unsigned kMatchMinLen = 3;
static const unsigned kNumSimplePosSlots = 4;
static const unsigned kNumSimpleLenSlots = 6;
static const UInt16 kUpdateStep = 8;
static const UInt16 kFreqSumMax = 3800;
static const unsigned kReorderCountStart = 4;
static const unsigned kReorderCount = 50;
void CModelDecoder::Init(unsigned numItems)
{
NumItems = numItems;
ReorderCount = kReorderCountStart;
for (unsigned i = 0; i < numItems; i++)
{
Freqs[i] = (UInt16)(numItems - i);
Vals[i] = (Byte)i;
}
Freqs[numItems] = 0;
}
unsigned CModelDecoder::Decode(CRangeDecoder *rc)
{
UInt32 threshold = rc->GetThreshold(Freqs[0]);
unsigned i;
for (i = 1; Freqs[i] > threshold; i++);
rc->Decode(Freqs[i], Freqs[i - 1], Freqs[0]);
unsigned res = Vals[--i];
do
Freqs[i] += kUpdateStep;
while (i--);
if (Freqs[0] > kFreqSumMax)
{
if (--ReorderCount == 0)
{
ReorderCount = kReorderCount;
for (i = 0; i < NumItems; i++)
Freqs[i] = (UInt16)(((Freqs[i] - Freqs[i + 1]) + 1) >> 1);
for (i = 0; i < NumItems - 1; i++)
for (unsigned j = i + 1; j < NumItems; j++)
if (Freqs[i] < Freqs[j])
{
UInt16 tmpFreq = Freqs[i];
Byte tmpVal = Vals[i];
Freqs[i] = Freqs[j];
Vals[i] = Vals[j];
Freqs[j] = tmpFreq;
Vals[j] = tmpVal;
}
do
Freqs[i] = (UInt16)(Freqs[i] + Freqs[i + 1]);
while (i--);
}
else
{
i = NumItems - 1;
do
{
Freqs[i] >>= 1;
if (Freqs[i] <= Freqs[i + 1])
Freqs[i] = (UInt16)(Freqs[i + 1] + 1);
}
while (i--);
}
}
return res;
}
void CDecoder::Init()
{
m_Selector.Init(kNumSelectors);
@@ -29,156 +97,97 @@ void CDecoder::Init()
m_LenSlot.Init(kNumLenSymbols);
}
HRESULT CDecoder::CodeSpec(UInt32 curSize)
HRESULT CDecoder::CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize)
{
if (_remainLen == kLenIdNeedInit)
{
_rangeDecoder.Init();
_remainLen = 0;
}
if (curSize == 0)
return S_OK;
if (inSize < 2)
return S_FALSE;
while (_remainLen > 0 && curSize > 0)
{
_remainLen--;
Byte b = _outWindowStream.GetByte(_rep0);
_outWindowStream.PutByte(b);
curSize--;
}
CRangeDecoder rc;
rc.Stream.SetStreamAndInit(inData, inSize);
rc.Init();
while (curSize > 0)
while (outSize != 0)
{
if (_rangeDecoder.Stream.WasFinished())
if (rc.Stream.WasExtraRead())
return S_FALSE;
unsigned selector = m_Selector.Decode(&_rangeDecoder);
unsigned selector = m_Selector.Decode(&rc);
if (selector < kNumLitSelectors)
{
Byte b = (Byte)((selector << (8 - kNumLitSelectorBits)) + m_Literals[selector].Decode(&_rangeDecoder));
_outWindowStream.PutByte(b);
curSize--;
Byte b = (Byte)((selector << (8 - kNumLitSelectorBits)) + m_Literals[selector].Decode(&rc));
_outWindow.PutByte(b);
outSize--;
}
else
{
selector -= kNumLitSelectors;
unsigned len = selector + kMatchMinLen;
if (selector == 2)
{
unsigned lenSlot = m_LenSlot.Decode(&_rangeDecoder);
unsigned lenSlot = m_LenSlot.Decode(&rc);
if (lenSlot >= kNumSimpleLenSlots)
{
lenSlot -= 2;
int numDirectBits = (int)(lenSlot >> 2);
unsigned numDirectBits = (unsigned)(lenSlot >> 2);
len += ((4 | (lenSlot & 3)) << numDirectBits) - 2;
if (numDirectBits < 6)
len += _rangeDecoder.Stream.ReadBits(numDirectBits);
len += rc.Stream.ReadBits(numDirectBits);
}
else
len += lenSlot;
}
UInt32 rep0 = m_PosSlot[selector].Decode(&_rangeDecoder);
if (rep0 >= kNumSimplePosSlots)
UInt32 dist = m_PosSlot[selector].Decode(&rc);
if (dist >= kNumSimplePosSlots)
{
int numDirectBits = (int)((rep0 >> 1) - 1);
rep0 = ((2 | (rep0 & 1)) << numDirectBits) + _rangeDecoder.Stream.ReadBits(numDirectBits);
unsigned numDirectBits = (unsigned)((dist >> 1) - 1);
dist = ((2 | (dist & 1)) << numDirectBits) + rc.Stream.ReadBits(numDirectBits);
}
unsigned locLen = len;
if (len > curSize)
locLen = (unsigned)curSize;
if (!_outWindowStream.CopyBlock(rep0, locLen))
if (len > outSize)
locLen = (unsigned)outSize;
if (!_outWindow.CopyBlock(dist, locLen))
return S_FALSE;
curSize -= locLen;
outSize -= locLen;
len -= locLen;
if (len != 0)
{
_remainLen = (int)len;
_rep0 = rep0;
break;
}
return S_FALSE;
}
}
return _rangeDecoder.Stream.WasFinished() ? S_FALSE : S_OK;
return rc.Finish() ? S_OK : S_FALSE;
}
HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress)
HRESULT CDecoder::Code(const Byte *inData, size_t inSize,
ISequentialOutStream *outStream, UInt32 outSize,
bool keepHistory)
{
if (outSize == NULL)
return E_INVALIDARG;
UInt64 size = *outSize;
// SetInStream(inStream);
_rangeDecoder.SetStream(inStream);
_outWindowStream.SetStream(outStream);
SetOutStreamSize(outSize);
CDecoderFlusher flusher(this);
const UInt64 start = _outWindowStream.GetProcessedSize();
for (;;)
try
{
UInt32 curSize = 1 << 18;
UInt64 rem = size - (_outWindowStream.GetProcessedSize() - start);
if (curSize > rem)
curSize = (UInt32)rem;
if (curSize == 0)
break;
RINOK(CodeSpec(curSize));
if (progress != NULL)
{
UInt64 inSize = _rangeDecoder.GetProcessedSize();
UInt64 nowPos64 = _outWindowStream.GetProcessedSize() - start;
RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
}
}
flusher.NeedFlush = false;
return Flush();
}
_outWindow.SetStream(outStream);
_outWindow.Init(keepHistory);
if (!keepHistory)
Init();
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; }
HRESULT res = CodeSpec(inData, inSize, outSize);
HRESULT res2 = _outWindow.Flush();
return res != S_OK ? res : res2;
}
catch(const CLzOutWindowException &e) { return e.ErrorCode; }
catch(...) { return S_FALSE; }
}
/*
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
{
m_InStreamRef = inStream;
_rangeDecoder.SetStream(inStream);
return S_OK;
}
STDMETHODIMP CDecoder::ReleaseInStream()
{
m_InStreamRef.Release();
return S_OK;
}
*/
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
{
if (outSize == NULL)
return E_FAIL;
_remainLen = kLenIdNeedInit;
_outWindowStream.Init(_keepHistory);
if (!_keepHistory)
Init();
return S_OK;
}
HRESULT CDecoder::SetParams(int numDictBits)
HRESULT CDecoder::SetParams(unsigned numDictBits)
{
if (numDictBits > 21)
return E_INVALIDARG;
_numDictBits = numDictBits;
if (!_outWindowStream.Create((UInt32)1 << _numDictBits))
return E_OUTOFMEMORY;
if (!_rangeDecoder.Create(1 << 20))
if (!_outWindow.Create((UInt32)1 << _numDictBits))
return E_OUTOFMEMORY;
return S_OK;
}

View File

@@ -5,92 +5,94 @@
#include "../../Common/MyCom.h"
#include "../ICoder.h"
#include "../Common/InBuffer.h"
#include "LzOutWindow.h"
namespace NCompress {
namespace NQuantum {
class CStreamBitDecoder
class CBitDecoder
{
UInt32 Value;
CInBuffer Stream;
bool _extra;
const Byte *_buf;
const Byte *_bufLim;
public:
bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); }
// void ReleaseStream() { Stream.ReleaseStream(); }
void Finish() { Value = 0x10000; }
void Init()
void SetStreamAndInit(const Byte *inData, size_t inSize)
{
Stream.Init();
_buf = inData;
_bufLim = inData + inSize;
Value = 0x10000;
_extra = false;
}
UInt64 GetProcessedSize() const { return Stream.GetProcessedSize(); }
bool WasFinished() const { return Stream.WasFinished(); }
bool WasExtraRead() const { return _extra; }
bool WasFinishedOK() const
{
return !_extra && _buf == _bufLim;
}
UInt32 ReadBit()
{
if (Value >= 0x10000)
Value = 0x100 | Stream.ReadByte();
{
Byte b;
if (_buf >= _bufLim)
{
b = 0xFF;
_extra = true;
}
else
b = *_buf++;
Value = 0x100 | b;
}
UInt32 res = (Value >> 7) & 1;
Value <<= 1;
return res;
}
UInt32 ReadBits(int numBits) // numBits > 0
UInt32 ReadStart16Bits()
{
// we use check for extra read in another code.
UInt32 val = ((UInt32)*_buf << 8) | _buf[1];
_buf += 2;
return val;
}
UInt32 ReadBits(unsigned numBits) // numBits > 0
{
UInt32 res = 0;
do
res = (res << 1) | ReadBit();
while (--numBits != 0);
while (--numBits);
return res;
}
};
const unsigned kNumLitSelectorBits = 2;
const unsigned kNumLitSelectors = (1 << kNumLitSelectorBits);
const unsigned kNumLitSymbols = 1 << (8 - kNumLitSelectorBits);
const unsigned kNumMatchSelectors = 3;
const unsigned kNumSelectors = kNumLitSelectors + kNumMatchSelectors;
const unsigned kNumSymbolsMax = kNumLitSymbols; // 64
namespace NRangeCoder {
class CDecoder
class CRangeDecoder
{
UInt32 Low;
UInt32 Range;
UInt32 Code;
public:
CStreamBitDecoder Stream;
bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); }
// void ReleaseStream() { Stream.ReleaseStream(); }
CBitDecoder Stream;
void Init()
{
Stream.Init();
Low = 0;
Range = 0x10000;
Code = Stream.ReadBits(16);
Code = Stream.ReadStart16Bits();
}
void Finish()
bool Finish()
{
// we need these extra two Bit_reads
Stream.ReadBit();
Stream.ReadBit();
Stream.Finish();
// do all streams use these two bits at end?
if (Stream.ReadBit() != 0) return false;
if (Stream.ReadBit() != 0) return false;
return Stream.WasFinishedOK();
}
UInt64 GetProcessedSize() const { return Stream.GetProcessedSize(); }
UInt32 GetThreshold(UInt32 total) const
{
return ((Code + 1) * total - 1) / Range; // & 0xFFFF is not required;
@@ -119,148 +121,52 @@ public:
}
};
const UInt16 kUpdateStep = 8;
const UInt16 kFreqSumMax = 3800;
const UInt16 kReorderCountStart = 4;
const UInt16 kReorderCount = 50;
const unsigned kNumLitSelectorBits = 2;
const unsigned kNumLitSelectors = (1 << kNumLitSelectorBits);
const unsigned kNumLitSymbols = 1 << (8 - kNumLitSelectorBits);
const unsigned kNumMatchSelectors = 3;
const unsigned kNumSelectors = kNumLitSelectors + kNumMatchSelectors;
const unsigned kNumSymbolsMax = kNumLitSymbols; // 64
class CModelDecoder
{
unsigned NumItems;
unsigned ReorderCount;
UInt16 Freqs[kNumSymbolsMax + 1];
Byte Values[kNumSymbolsMax];
Byte Vals[kNumSymbolsMax];
public:
void Init(unsigned numItems)
{
NumItems = numItems;
ReorderCount = kReorderCountStart;
for (unsigned i = 0; i < numItems; i++)
{
Freqs[i] = (UInt16)(numItems - i);
Values[i] = (Byte)i;
}
Freqs[numItems] = 0;
}
unsigned Decode(CDecoder *rangeDecoder)
{
UInt32 threshold = rangeDecoder->GetThreshold(Freqs[0]);
unsigned i;
for (i = 1; Freqs[i] > threshold; i++);
rangeDecoder->Decode(Freqs[i], Freqs[i - 1], Freqs[0]);
unsigned res = Values[--i];
do
Freqs[i] += kUpdateStep;
while (i-- != 0);
if (Freqs[0] > kFreqSumMax)
{
if (--ReorderCount == 0)
{
ReorderCount = kReorderCount;
for (i = 0; i < NumItems; i++)
Freqs[i] = (UInt16)(((Freqs[i] - Freqs[i + 1]) + 1) >> 1);
for (i = 0; i < NumItems - 1; i++)
for (unsigned j = i + 1; j < NumItems; j++)
if (Freqs[i] < Freqs[j])
{
UInt16 tmpFreq = Freqs[i];
Byte tmpVal = Values[i];
Freqs[i] = Freqs[j];
Values[i] = Values[j];
Freqs[j] = tmpFreq;
Values[j] = tmpVal;
}
do
Freqs[i] = (UInt16)(Freqs[i] + Freqs[i + 1]);
while (i-- != 0);
}
else
{
i = NumItems - 1;
do
{
Freqs[i] >>= 1;
if (Freqs[i] <= Freqs[i + 1])
Freqs[i] = (UInt16)(Freqs[i + 1] + 1);
}
while (i-- != 0);
}
}
return res;
}
void Init(unsigned numItems);
unsigned Decode(CRangeDecoder *rc);
};
}
class CDecoder:
public ICompressCoder,
// public ICompressSetInStream,
// public ICompressSetOutStreamSize,
public IUnknown,
public CMyUnknownImp
{
CLzOutWindow _outWindowStream;
// CMyComPtr<ISequentialInStream> m_InStreamRef;
NRangeCoder::CDecoder _rangeDecoder;
CLzOutWindow _outWindow;
unsigned _numDictBits;
UInt64 _outSize;
int _remainLen; // -1 means end of stream. // -2 means need Init
UInt32 _rep0;
CModelDecoder m_Selector;
CModelDecoder m_Literals[kNumLitSelectors];
CModelDecoder m_PosSlot[kNumMatchSelectors];
CModelDecoder m_LenSlot;
int _numDictBits;
bool _keepHistory;
NRangeCoder::CModelDecoder m_Selector;
NRangeCoder::CModelDecoder m_Literals[kNumLitSelectors];
NRangeCoder::CModelDecoder m_PosSlot[kNumMatchSelectors];
NRangeCoder::CModelDecoder m_LenSlot;
void Init();
HRESULT CodeSpec(UInt32 size);
HRESULT CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize);
public:
MY_UNKNOWN_IMP
/*
MY_UNKNOWN_IMP2(
ICompressSetInStream,
ICompressSetOutStreamSize)
void ReleaseStreams()
{
_outWindowStream.ReleaseStream();
ReleaseInStream();
}
*/
HRESULT Code(const Byte *inData, size_t inSize,
ISequentialOutStream *outStream, UInt32 outSize,
bool keepHistory);
class CDecoderFlusher
{
CDecoder *_decoder;
public:
bool NeedFlush;
CDecoderFlusher(CDecoder *decoder): _decoder(decoder), NeedFlush(true) {}
~CDecoderFlusher()
{
if (NeedFlush)
_decoder->Flush();
// _decoder->ReleaseStreams();
}
};
HRESULT SetParams(unsigned numDictBits);
HRESULT Flush() { return _outWindowStream.Flush(); }
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
// STDMETHOD(SetInStream)(ISequentialInStream *inStream);
// STDMETHOD(ReleaseInStream)();
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
HRESULT SetParams(int numDictBits);
void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
CDecoder(): _keepHistory(false) {}
CDecoder(): _numDictBits(0) {}
virtual ~CDecoder() {}
};

View File

@@ -122,21 +122,21 @@ bool CDecoder::ReadTables(void)
unsigned i;
for (i = 0; i < kLevelTableSize; i++)
levelLevels[i] = (Byte)ReadBits(4);
RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
RIF(m_LevelDecoder.Build(levelLevels));
i = 0;
while (i < numLevels)
{
UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
if (number < kTableDirectLevels)
UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream);
if (sym < kTableDirectLevels)
{
newLevels[i] = (Byte)((number + m_LastLevels[i]) & kLevelMask);
newLevels[i] = (Byte)((sym + m_LastLevels[i]) & kLevelMask);
i++;
}
else
{
if (number == kTableLevelRepNumber)
if (sym == kTableLevelRepNumber)
{
unsigned t = ReadBits(2) + 3;
for (unsigned reps = t; reps > 0 && i < numLevels; reps--, i++)
@@ -145,9 +145,9 @@ bool CDecoder::ReadTables(void)
else
{
unsigned num;
if (number == kTableLevel0Number)
if (sym == kTableLevel0Number)
num = ReadBits(3) + 3;
else if (number == kTableLevel0Number2)
else if (sym == kTableLevel0Number2)
num = ReadBits(7) + 11;
else
return false;
@@ -160,13 +160,13 @@ bool CDecoder::ReadTables(void)
if (m_AudioMode)
for (i = 0; i < m_NumChannels; i++)
{
RIF(m_MMDecoders[i].SetCodeLengths(&newLevels[i * kMMTableSize]));
RIF(m_MMDecoders[i].Build(&newLevels[i * kMMTableSize]));
}
else
{
RIF(m_MainDecoder.SetCodeLengths(&newLevels[0]));
RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize]));
RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize]));
RIF(m_MainDecoder.Build(&newLevels[0]));
RIF(m_DistDecoder.Build(&newLevels[kMainTableSize]));
RIF(m_LenDecoder.Build(&newLevels[kMainTableSize + kDistTableSize]));
}
memcpy(m_LastLevels, newLevels, kMaxTableSize);
@@ -182,7 +182,7 @@ bool CDecoder::ReadLastTables()
// if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
if (m_AudioMode)
{
UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream);
UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
if (symbol == 256)
return ReadTables();
if (symbol >= kMMTableSize)
@@ -190,10 +190,10 @@ bool CDecoder::ReadLastTables()
}
else
{
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
if (number == kReadTableNumber)
UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
if (sym == kReadTableNumber)
return ReadTables();
if (number >= kMainTableSize)
if (sym >= kMainTableSize)
return false;
}
return true;
@@ -216,7 +216,7 @@ bool CDecoder::DecodeMm(UInt32 pos)
{
while (pos-- > 0)
{
UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream);
UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
if (symbol == 256)
return true;
if (symbol >= kMMTableSize)
@@ -238,23 +238,23 @@ bool CDecoder::DecodeLz(Int32 pos)
{
while (pos > 0)
{
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
UInt32 length, distance;
if (number < 256)
if (sym < 256)
{
m_OutWindowStream.PutByte(Byte(number));
m_OutWindowStream.PutByte(Byte(sym));
pos--;
continue;
}
else if (number >= kMatchNumber)
else if (sym >= kMatchNumber)
{
number -= kMatchNumber;
length = kNormalMatchMinLen + UInt32(kLenStart[number]) +
m_InBitStream.ReadBits(kLenDirectBits[number]);
number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
if (number >= kDistTableSize)
sym -= kMatchNumber;
length = kNormalMatchMinLen + UInt32(kLenStart[sym]) +
m_InBitStream.ReadBits(kLenDirectBits[sym]);
sym = m_DistDecoder.Decode(&m_InBitStream);
if (sym >= kDistTableSize)
return false;
distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]);
distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
if (distance >= kDistLimit3)
{
length += 2 - ((distance - kDistLimit4) >> 31);
@@ -263,20 +263,20 @@ bool CDecoder::DecodeLz(Int32 pos)
// length++;
}
}
else if (number == kRepBothNumber)
else if (sym == kRepBothNumber)
{
length = m_LastLength;
if (length == 0)
return false;
distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3];
}
else if (number < kLen2Number)
else if (sym < kLen2Number)
{
distance = m_RepDists[(m_RepDistPtr - (number - kRepNumber + 1)) & 3];
number = m_LenDecoder.DecodeSymbol(&m_InBitStream);
if (number >= kLenTableSize)
distance = m_RepDists[(m_RepDistPtr - (sym - kRepNumber + 1)) & 3];
sym = m_LenDecoder.Decode(&m_InBitStream);
if (sym >= kLenTableSize)
return false;
length = 2 + kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
length = 2 + kLenStart[sym] + m_InBitStream.ReadBits(kLenDirectBits[sym]);
if (distance >= kDistLimit2)
{
length++;
@@ -289,14 +289,14 @@ bool CDecoder::DecodeLz(Int32 pos)
}
}
}
else if (number < kReadTableNumber)
else if (sym < kReadTableNumber)
{
number -= kLen2Number;
distance = kLen2DistStarts[number] +
m_InBitStream.ReadBits(kLen2DistDirectBits[number]);
sym -= kLen2Number;
distance = kLen2DistStarts[sym] +
m_InBitStream.ReadBits(kLen2DistDirectBits[sym]);
length = 2;
}
else if (number == kReadTableNumber)
else if (sym == kReadTableNumber)
return true;
else
return false;

View File

@@ -568,26 +568,26 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing)
}
levelLevels[i] = (Byte)length;
}
RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
RIF(m_LevelDecoder.Build(levelLevels));
i = 0;
while (i < kTablesSizesSum)
{
UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream.BitDecoder);
if (number < 16)
UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream.BitDecoder);
if (sym < 16)
{
newLevels[i] = Byte((number + m_LastLevels[i]) & 15);
newLevels[i] = Byte((sym + m_LastLevels[i]) & 15);
i++;
}
else if (number > kLevelTableSize)
else if (sym > kLevelTableSize)
return S_FALSE;
else
{
int num;
if (((number - 16) & 1) == 0)
if (((sym - 16) & 1) == 0)
num = ReadBits(3) + 3;
else
num = ReadBits(7) + 11;
if (number < 18)
if (sym < 18)
{
if (i == 0)
return S_FALSE;
@@ -612,10 +612,10 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing)
}
*/
RIF(m_MainDecoder.SetCodeLengths(&newLevels[0]));
RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize]));
RIF(m_AlignDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize]));
RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize]));
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]));
memcpy(m_LastLevels, newLevels, kTablesSizesSum);
return S_OK;
@@ -687,38 +687,38 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
if (InputEofError_Fast())
return S_FALSE;
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream.BitDecoder);
if (number < 256)
UInt32 sym = m_MainDecoder.Decode(&m_InBitStream.BitDecoder);
if (sym < 256)
{
PutByte((Byte)number);
PutByte((Byte)sym);
continue;
}
else if (number == kSymbolReadTable)
else if (sym == kSymbolReadTable)
{
RINOK(ReadEndOfBlock(keepDecompressing));
break;
}
else if (number == 257)
else if (sym == 257)
{
if (!ReadVmCodeLZ())
return S_FALSE;
continue;
}
else if (number == 258)
else if (sym == 258)
{
if (length == 0)
return S_FALSE;
}
else if (number < kSymbolRep + 4)
else if (sym < kSymbolRep + 4)
{
if (number != kSymbolRep)
if (sym != kSymbolRep)
{
UInt32 distance;
if (number == kSymbolRep + 1)
if (sym == kSymbolRep + 1)
distance = rep1;
else
{
if (number == kSymbolRep + 2)
if (sym == kSymbolRep + 2)
distance = rep2;
else
{
@@ -731,32 +731,32 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
rep0 = distance;
}
UInt32 number = m_LenDecoder.DecodeSymbol(&m_InBitStream.BitDecoder);
if (number >= kLenTableSize)
UInt32 sym = m_LenDecoder.Decode(&m_InBitStream.BitDecoder);
if (sym >= kLenTableSize)
return S_FALSE;
length = 2 + kLenStart[number] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[number]);
length = 2 + kLenStart[sym] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[sym]);
}
else
{
rep3 = rep2;
rep2 = rep1;
rep1 = rep0;
if (number < 271)
if (sym < 271)
{
number -= 263;
rep0 = kLen2DistStarts[number] + m_InBitStream.BitDecoder.ReadBits(kLen2DistDirectBits[number]);
sym -= 263;
rep0 = kLen2DistStarts[sym] + m_InBitStream.BitDecoder.ReadBits(kLen2DistDirectBits[sym]);
length = 2;
}
else if (number < 299)
else if (sym < 299)
{
number -= 271;
length = kNormalMatchMinLen + (UInt32)kLenStart[number] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[number]);
UInt32 number = m_DistDecoder.DecodeSymbol(&m_InBitStream.BitDecoder);
if (number >= kDistTableSize)
sym -= 271;
length = kNormalMatchMinLen + (UInt32)kLenStart[sym] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[sym]);
UInt32 sym = m_DistDecoder.Decode(&m_InBitStream.BitDecoder);
if (sym >= kDistTableSize)
return S_FALSE;
rep0 = kDistStart[number];
int numBits = kDistDirectBits[number];
if (number >= (kNumAlignBits * 2) + 2)
rep0 = kDistStart[sym];
int numBits = kDistDirectBits[sym];
if (sym >= (kNumAlignBits * 2) + 2)
{
if (numBits > kNumAlignBits)
rep0 += (m_InBitStream.BitDecoder.ReadBits(numBits - kNumAlignBits) << kNumAlignBits);
@@ -767,13 +767,13 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
}
else
{
UInt32 number = m_AlignDecoder.DecodeSymbol(&m_InBitStream.BitDecoder);
if (number < (1 << kNumAlignBits))
UInt32 sym = m_AlignDecoder.Decode(&m_InBitStream.BitDecoder);
if (sym < (1 << kNumAlignBits))
{
rep0 += number;
PrevAlignBits = number;
rep0 += sym;
PrevAlignBits = sym;
}
else if (number == (1 << kNumAlignBits))
else if (sym == (1 << kNumAlignBits))
{
PrevAlignCount = kNumAlignReps;
rep0 += PrevAlignBits;

View File

@@ -304,6 +304,7 @@ HRESULT CDecoder::AddFilter(CBitDecoder &_bitStream)
// if (f.Size > ((UInt32)1 << 16)) _unsupportedFilter = true;
f.Type = (Byte)_bitStream.ReadBits9fix(3);
f.Channels = 0;
if (f.Type == FILTER_DELTA)
f.Channels = (Byte)(_bitStream.ReadBits9fix(5) + 1);
f.Start = _lzSize + blockStart;
@@ -408,7 +409,7 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
if (_bitStream.IsBlockOverRead())
return S_FALSE;
RIF(m_LevelDecoder.SetCodeLengths(lens2));
RIF(m_LevelDecoder.Build(lens2));
}
Byte lens[kTablesSizesSum];
@@ -424,7 +425,7 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
return S_FALSE;
}
UInt32 sym = m_LevelDecoder.DecodeSymbol(&_bitStream);
UInt32 sym = m_LevelDecoder.Decode(&_bitStream);
if (sym < 16)
lens[i++] = (Byte)sym;
@@ -466,10 +467,10 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
if (_bitStream.InputEofError())
return S_FALSE;
RIF(m_MainDecoder.SetCodeLengths(&lens[0]));
RIF(m_DistDecoder.SetCodeLengths(&lens[kMainTableSize]));
RIF(m_AlignDecoder.SetCodeLengths(&lens[kMainTableSize + kDistTableSize]));
RIF(m_LenDecoder.SetCodeLengths(&lens[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]));
_useAlignBits = false;
// _useAlignBits = true;
@@ -601,7 +602,7 @@ HRESULT CDecoder::DecodeLZ()
}
}
UInt32 sym = m_MainDecoder.DecodeSymbol(&_bitStream);
UInt32 sym = m_MainDecoder.Decode(&_bitStream);
if (sym < 256)
{
@@ -638,7 +639,7 @@ HRESULT CDecoder::DecodeLZ()
rep0 = dist;
}
UInt32 sym = m_LenDecoder.DecodeSymbol(&_bitStream);
UInt32 sym = m_LenDecoder.Decode(&_bitStream);
if (sym >= kLenTableSize)
break; // return S_FALSE;
len = SlotToLen(_bitStream, sym);
@@ -669,7 +670,7 @@ HRESULT CDecoder::DecodeLZ()
_reps[1] = rep0;
len = SlotToLen(_bitStream, sym - (kSymbolRep + kNumReps));
rep0 = m_DistDecoder.DecodeSymbol(&_bitStream);
rep0 = m_DistDecoder.Decode(&_bitStream);
if (rep0 >= 4)
{
@@ -690,7 +691,7 @@ HRESULT CDecoder::DecodeLZ()
{
// if (numBits > kNumAlignBits)
rep0 += (_bitStream.ReadBits32(numBits - kNumAlignBits) << kNumAlignBits);
UInt32 a = m_AlignDecoder.DecodeSymbol(&_bitStream);
UInt32 a = m_AlignDecoder.Decode(&_bitStream);
if (a >= kAlignTableSize)
break; // return S_FALSE;
rep0 += a;

View File

@@ -0,0 +1,129 @@
// XpressDecoder.cpp
#include "StdAfx.h"
// #include <stdio.h>
#include "../../../C/CpuArch.h"
#include "HuffmanDecoder.h"
namespace NCompress {
namespace NXpress {
struct CBitStream
{
UInt32 Value;
unsigned BitPos;
UInt32 GetValue(unsigned numBits) const
{
return (Value >> (BitPos - numBits)) & ((1 << numBits) - 1);
}
void MovePos(unsigned numBits)
{
BitPos -= numBits;
}
};
#define BIT_STREAM_NORMALIZE \
if (bs.BitPos < 16) { \
if (in >= lim) return S_FALSE; \
bs.Value = (bs.Value << 16) | GetUi16(in); \
in += 2; bs.BitPos += 16; }
const unsigned kNumHuffBits = 15;
const unsigned kNumLenSlots = 16;
const unsigned kNumPosSlots = 16;
const unsigned kNumSyms = 256 + kNumPosSlots * kNumLenSlots;
HRESULT Decode(const Byte *in, size_t inSize, Byte *out, size_t outSize)
{
NCompress::NHuffman::CDecoder<kNumHuffBits, kNumSyms> huff;
if (inSize < kNumSyms / 2 + 4)
return S_FALSE;
{
Byte levels[kNumSyms];
for (unsigned i = 0; i < kNumSyms / 2; i++)
{
Byte b = in[i];
levels[i * 2] = (Byte)(b & 0xF);
levels[i * 2 + 1] = (Byte)(b >> 4);
}
if (!huff.BuildFull(levels))
return S_FALSE;
}
CBitStream bs;
const Byte *lim = in + inSize - 1;
in += kNumSyms / 2;
bs.Value = (GetUi16(in) << 16) | GetUi16(in + 2);
in += 4;
bs.BitPos = 32;
size_t pos = 0;
for (;;)
{
// printf("\n%d", pos);
UInt32 sym = huff.DecodeFull(&bs);
// printf(" sym = %d", sym);
BIT_STREAM_NORMALIZE
if (pos >= outSize)
return (sym == 256 && in == lim + 1) ? S_OK : S_FALSE;
if (sym < 256)
out[pos++] = (Byte)sym;
else
{
sym -= 256;
UInt32 dist = sym / kNumLenSlots;
UInt32 len = sym & (kNumLenSlots - 1);
if (len == kNumLenSlots - 1)
{
if (in > lim)
return S_FALSE;
len = *in++;
if (len == 0xFF)
{
if (in >= lim)
return S_FALSE;
len = GetUi16(in);
in += 2;
}
else
len += kNumLenSlots - 1;
}
bs.BitPos -= dist;
dist = (UInt32)1 << dist;
dist += ((bs.Value >> bs.BitPos) & (dist - 1));
BIT_STREAM_NORMALIZE
if (len > outSize - pos)
return S_FALSE;
if (dist > pos)
return S_FALSE;
Byte *dest = out + pos;
const Byte *src = dest - dist;
pos += len + 3;
len += 1;
*dest++ = *src++;
*dest++ = *src++;
do
*dest++ = *src++;
while (--len);
}
}
}
}}

View File

@@ -0,0 +1,13 @@
// XpressDecoder.h
#ifndef __XPRESS_DECODER_H
#define __XPRESS_DECODER_H
namespace NCompress {
namespace NXpress {
HRESULT Decode(const Byte *in, size_t inSize, Byte *out, size_t outSize);
}}
#endif

View File

@@ -163,6 +163,10 @@ Handler GUIDs:
0C xz
0D ppmd
C8 VMDK
C9 VDI
CA Qcow
CB GPT
CC Rar5
CD IHex
CE Hxs

View File

@@ -1465,6 +1465,9 @@ STDMETHODIMP CAgentFolder::Extract(const UInt32 *indices,
extractCallbackSpec->InitForMulti(false, pathMode, overwriteMode);
if (extractCallback2)
extractCallback2->SetTotal(_agentSpec->GetArc().GetEstmatedPhySize());
FString pathU;
if (path)
{

View File

@@ -251,7 +251,9 @@ public:
FOR_VECTOR (i, _archiveLink.Arcs)
{
const CArc &arc = _archiveLink.Arcs[i];
if (!g_CodecsObj->Formats[arc.FormatIndex].UpdateEnabled || arc.IsReadOnly)
if (arc.FormatIndex < 0
|| arc.IsReadOnly
|| !g_CodecsObj->Formats[arc.FormatIndex].UpdateEnabled)
return true;
}
return false;
@@ -274,9 +276,14 @@ public:
UString s2;
if (arc.ErrorInfo.ErrorFormatIndex >= 0)
{
s2.AddAscii("Can not open the file as [");
s2 += g_CodecsObj->Formats[arc.ErrorInfo.ErrorFormatIndex].Name;
s2.AddAscii("] archive");
if (arc.ErrorInfo.ErrorFormatIndex == arc.FormatIndex)
s2.AddAscii("Warning: The archive is open with offset");
else
{
s2.AddAscii("Can not open the file as [");
s2 += g_CodecsObj->GetFormatNamePtr(arc.ErrorInfo.ErrorFormatIndex);
s2.AddAscii("] archive");
}
}
if (!arc.ErrorInfo.ErrorMessage.IsEmpty())
@@ -288,6 +295,7 @@ public:
s2.AddAscii("]: ");
s2 += arc.ErrorInfo.ErrorMessage;
}
if (!s2.IsEmpty())
{
if (!s.IsEmpty())

View File

@@ -216,10 +216,9 @@ void CArchiveExtractCallback::Init(
// _progressTotal = 0;
// _progressTotal_Defined = false;
_progressTotal = _packTotal;
_progressTotal_Defined = true;
_packTotal = packSize;
_progressTotal = packSize;
_progressTotal_Defined = true;
_extractCallback2 = extractCallback2;
_compressProgress.Release();
@@ -962,7 +961,12 @@ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)
bool isAnti = false;
RINOK(_arc->IsItemAnti(index, isAnti));
Correct_FsPath(_pathMode == NExtract::NPathMode::kAbsPaths, pathParts, _item.MainIsDir);
#ifdef SUPPORT_ALT_STREAMS
if (!_item.IsAltStream
|| !pathParts.IsEmpty()
|| !(_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt))
#endif
Correct_FsPath(_pathMode == NExtract::NPathMode::kAbsPaths, pathParts, _item.MainIsDir);
#ifdef SUPPORT_ALT_STREAMS
@@ -970,12 +974,18 @@ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)
{
UString s = _item.AltStreamName;
Correct_AltStream_Name(s);
bool needColon = ((!_removePartsForAltStreams && _pathMode != NExtract::NPathMode::kNoPathsAlt) || !pathParts.IsEmpty());
bool needColon = true;
if (pathParts.IsEmpty())
{
pathParts.AddNew();
if (_pathMode == NExtract::NPathMode::kAbsPaths &&
if (_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt)
needColon = false;
}
else if (_pathMode == NExtract::NPathMode::kAbsPaths &&
NWildcard::GetNumPrefixParts_if_DrivePath(pathParts) == pathParts.Size())
pathParts.AddNew();
UString &name = pathParts.Back();
if (needColon)
name += (wchar_t)(_ntOptions.ReplaceColonForAltStream ? L'_' : L':');

View File

@@ -17,7 +17,9 @@ static void ReplaceIncorrectChars(UString &s)
if (
#ifdef _WIN32
c == ':' || c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"'
|| c == '/' ||
|| c == '/'
|| c == 0x202E // RLO
||
#endif
c == WCHAR_PATH_SEPARATOR)
s.ReplaceOneCharAtPos(i, '_');
@@ -53,7 +55,9 @@ void Correct_AltStream_Name(UString &s)
for (unsigned i = 0; i < len; i++)
{
wchar_t c = s[i];
if (c == ':' || c == '\\' || c == '/')
if (c == ':' || c == '\\' || c == '/'
|| c == 0x202E // RLO
)
s.ReplaceOneCharAtPos(i, '_');
}
if (s.IsEmpty())

View File

@@ -299,6 +299,8 @@ public:
UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file
// bool offsetDefined;
UInt64 GetEstmatedPhySize() const { return PhySizeDefined ? PhySize : FileSize; }
UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler
Int64 GetGlobalOffset() const { return ArcStreamOffset + Offset; } // it's global offset of archive

View File

@@ -847,7 +847,7 @@ int Main2(
#endif
ecs->Init(g_StdStream, g_ErrStream, percentsStream);
ecs->MutiArcMode = (ArchivePathsSorted.Size() > 1);
ecs->MultiArcMode = (ArchivePathsSorted.Size() > 1);
ecs->LogLevel = options.LogLevel;
ecs->PercentsNameLevel = percentsNameLevel;

View File

@@ -19,7 +19,7 @@ HRESULT COpenCallbackConsole::Open_CheckBreak()
HRESULT COpenCallbackConsole::Open_SetTotal(const UInt64 *files, const UInt64 *bytes)
{
if (!MutiArcMode && NeedPercents())
if (!MultiArcMode && NeedPercents())
{
if (files)
{
@@ -46,7 +46,7 @@ HRESULT COpenCallbackConsole::Open_SetTotal(const UInt64 *files, const UInt64 *b
HRESULT COpenCallbackConsole::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes)
{
if (!MutiArcMode && NeedPercents())
if (!MultiArcMode && NeedPercents())
{
if (files)
{

View File

@@ -26,7 +26,7 @@ protected:
public:
bool MutiArcMode;
bool MultiArcMode;
void ClosePercents()
{
@@ -37,7 +37,7 @@ public:
COpenCallbackConsole():
_totalFilesDefined(false),
_totalBytesDefined(false),
MutiArcMode(false)
MultiArcMode(false)
#ifndef _NO_CRYPTO
, PasswordIsDefined(false)

View File

@@ -373,18 +373,21 @@ static HANDLE MyOpenFilePluginW(const wchar_t *name)
HRESULT result = ::OpenArchive(fullName, &archiveHandler,
archiverInfoResult, defaultName, openArchiveCallback);
*/
if (result != S_OK)
{
if (result == E_ABORT)
return (HANDLE)-2;
ShowSysErrorMessage(result);
return INVALID_HANDLE_VALUE;
}
if (result == E_ABORT)
return (HANDLE)-2;
UString errorMessage = agent->GetErrorMessage();
if (!errorMessage.IsEmpty())
g_StartupInfo.ShowErrorMessage(UnicodeStringToMultiByte(errorMessage, CP_OEMCP));
if (result != S_OK)
{
if (result == S_FALSE)
return INVALID_HANDLE_VALUE;
ShowSysErrorMessage(result);
return INVALID_HANDLE_VALUE;
}
// ::OutputDebugStringA("after OpenArchive\n");
CPlugin *plugin = new CPlugin(

View File

@@ -68,6 +68,7 @@ void CStartupInfo::SetErrorTitle(AString &s)
s += GetMsgString(NMessageID::kError);
}
/*
int CStartupInfo::ShowErrorMessage(const char *message)
{
AString s;
@@ -75,6 +76,7 @@ int CStartupInfo::ShowErrorMessage(const char *message)
const char *items[]= { s, message };
return ShowWarningWithOk(items, ARRAY_SIZE(items));
}
*/
int CStartupInfo::ShowErrorMessage2(const char *m1, const char *m2)
{
@@ -84,48 +86,45 @@ int CStartupInfo::ShowErrorMessage2(const char *m1, const char *m2)
return ShowWarningWithOk(items, ARRAY_SIZE(items));
}
/*
static void SplitString(const AString &srcString, AStringVector &destStrings)
static void SplitString(const AString &src, AStringVector &destStrings)
{
destStrings.Clear();
AString string;
unsigned len = srcString.Len();
AString s;
unsigned len = src.Len();
if (len == 0)
return;
for (unsigned i = 0; i < len; i++)
{
char c = srcString[i];
char c = src[i];
if (c == '\n')
{
if (!string.IsEmpty())
if (!s.IsEmpty())
{
destStrings.Add(string);
string.Empty();
destStrings.Add(s);
s.Empty();
}
}
else
string += c;
s += c;
}
if (!string.IsEmpty())
destStrings.Add(string);
if (!s.IsEmpty())
destStrings.Add(s);
}
*/
/*
int CStartupInfo::ShowMessageLines(const char *message)
int CStartupInfo::ShowErrorMessage(const char *message)
{
AStringVector strings;
SplitString(message, strings);
const unsigned kNumStringsMax = 20;
const char *items[kNumStringsMax + 1] = { GetMsgString(NMessageID::kError) };
unsigned pos = 1;
const char *items[kNumStringsMax + 1];
unsigned pos = 0;
items[pos++] = GetMsgString(NMessageID::kError);
for (unsigned i = 0; i < strings.Size() && pos < kNumStringsMax; i++)
items[pos++] = strings[i];
items[pos++] = GetMsgString(NMessageID::kOk);
return ShowMessage(FMSG_WARNING, NULL, items, pos, 1);
}
*/
/*
int CStartupInfo::ShowMessageLines(const char *message)

View File

@@ -188,7 +188,7 @@ public:
// File Menu
void OpenItem() { GetFocusedPanel().OpenSelectedItems(true); }
void OpenItemInside() { GetFocusedPanel().OpenFocusedItemAsInternal(); }
void OpenItemInside(const wchar_t *type) { GetFocusedPanel().OpenFocusedItemAsInternal(type); }
void OpenItemOutside() { GetFocusedPanel().OpenSelectedItems(false); }
void EditItem(bool useEditor) { GetFocusedPanel().EditItem(useEditor); }
void Rename() { GetFocusedPanel().RenameFile(); }

View File

@@ -91,15 +91,45 @@ HRESULT CExtractCallbackImp::Open_CheckBreak()
return ProgressDialog->Sync.CheckStop();
}
HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */)
HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 *files, const UInt64 *bytes)
{
// if (numFiles != NULL) ProgressDialog->Sync.SetNumFilesTotal(*numFiles);
return S_OK;
HRESULT res = S_OK;
if (!MultiArcMode)
{
if (files)
{
_totalFilesDefined = true;
// res = ProgressDialog->Sync.Set_NumFilesTotal(*files);
}
else
_totalFilesDefined = false;
if (bytes)
{
_totalBytesDefined = true;
ProgressDialog->Sync.Set_NumBytesTotal(*bytes);
}
else
_totalBytesDefined = false;
}
return res;
}
HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */)
HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes)
{
// if (numFiles != NULL) ProgressDialog->Sync.SetNumFilesCur(*numFiles);
if (!MultiArcMode)
{
if (files)
{
ProgressDialog->Sync.Set_NumFilesCur(*files);
}
if (bytes)
{
}
}
return ProgressDialog->Sync.CheckStop();
}

View File

@@ -284,6 +284,10 @@ public:
UString _lang_Skipping;
UString _lang_Empty;
bool _totalFilesDefined;
bool _totalBytesDefined;
bool MultiArcMode;
CExtractCallbackImp():
#ifndef _NO_CRYPTO
PasswordIsDefined(false),
@@ -291,7 +295,12 @@ public:
#endif
OverwriteMode(NExtract::NOverwriteMode::kAsk),
StreamMode(false),
ProcessAltStreams(true)
ProcessAltStreams(true),
_totalFilesDefined(false),
_totalBytesDefined(false),
MultiArcMode(false)
#ifndef _SFX
, _hashCalc(NULL)
#endif

View File

@@ -2,13 +2,13 @@
#define IDB_LINK_LINK 7701
#define IDT_LINK_PATH_FROM 7702
#define IDT_LINK_PATH_TO 7703
#define IDT_LINK_PATH_FROM 7702
#define IDT_LINK_PATH_TO 7703
#define IDG_LINK_TYPE 7710
#define IDR_LINK_TYPE_HARD 7711
#define IDR_LINK_TYPE_SYM_FILE 7712
#define IDR_LINK_TYPE_SYM_DIR 7713
#define IDR_LINK_TYPE_SYM_FILE 7712
#define IDR_LINK_TYPE_SYM_DIR 7713
#define IDR_LINK_TYPE_JUNCTION 7714

View File

@@ -143,7 +143,9 @@ static void MyChangeMenu(HMENU menuLoc, int level, int menuIndex)
else
continue;
}
LangString_OnlyFromLangFile(langID, newString);
if (newString.IsEmpty())
continue;
}
@@ -154,7 +156,21 @@ static void MyChangeMenu(HMENU menuLoc, int level, int menuIndex)
int langPos = FindLangItem(item.wID);
// we don't need lang change for CRC items!!!
LangString_OnlyFromLangFile(langPos >= 0 ? kIDLangPairs[langPos].LangID : item.wID, newString);
UInt32 langID = langPos >= 0 ? kIDLangPairs[langPos].LangID : item.wID;
if (langID == IDM_OPEN_INSIDE_ONE || langID == IDM_OPEN_INSIDE_PARSER)
{
LangString_OnlyFromLangFile(IDM_OPEN_INSIDE, newString);
newString.Replace(L"&", L"");
int tabPos = newString.Find(L"\t");
if (tabPos >= 0)
newString.DeleteFrom(tabPos);
newString += (langID == IDM_OPEN_INSIDE_ONE ? L" *" : L" #");
}
else
LangString_OnlyFromLangFile(langID, newString);
if (newString.IsEmpty())
continue;
@@ -162,6 +178,7 @@ static void MyChangeMenu(HMENU menuLoc, int level, int menuIndex)
if (tabPos >= 0)
newString += item.StringValue.Ptr(tabPos);
}
{
item.StringValue = newString;
item.fMask = Get_fMask_for_String();
@@ -358,6 +375,7 @@ void CFileMenu::Load(HMENU hMenu, unsigned startPos)
ReadRegDiff(diffPath);
unsigned numRealItems = startPos;
for (unsigned i = 0;; i++)
{
CMenuItem item;
@@ -375,6 +393,13 @@ void CFileMenu::Load(HMENU hMenu, unsigned startPos)
if (item.wID == IDM_DIFF && diffPath.IsEmpty())
continue;
if (item.wID == IDM_OPEN_INSIDE_ONE || item.wID == IDM_OPEN_INSIDE_PARSER)
{
// We use diff as "super mode" marker for additional commands.
if (diffPath.IsEmpty())
continue;
}
bool isOneFsFile = (isFsFolder && numItems == 1 && allAreFiles);
bool disable = (!isOneFsFile && (item.wID == IDM_SPLIT || item.wID == IDM_COMBINE));
@@ -415,6 +440,7 @@ void CFileMenu::Load(HMENU hMenu, unsigned startPos)
numRealItems = startPos;
}
}
destMenu.RemoveAllItemsFrom(numRealItems);
}
@@ -432,7 +458,11 @@ bool ExecuteFileCommand(int id)
{
// File
case IDM_OPEN: g_App.OpenItem(); break;
case IDM_OPEN_INSIDE: g_App.OpenItemInside(); break;
case IDM_OPEN_INSIDE: g_App.OpenItemInside(NULL); break;
case IDM_OPEN_INSIDE_ONE: g_App.OpenItemInside(L"*"); break;
case IDM_OPEN_INSIDE_PARSER: g_App.OpenItemInside(L"#"); break;
case IDM_OPEN_OUTSIDE: g_App.OpenItemOutside(); break;
case IDM_FILE_VIEW: g_App.EditItem(false); break;
case IDM_FILE_EDIT: g_App.EditItem(true); break;

View File

@@ -285,7 +285,7 @@ private:
HRESULT InitColumns();
// void InitColumns2(PROPID sortID);
void InsertColumn(int index);
void InsertColumn(unsigned index);
void SetFocusedSelectedItem(int index, bool select);
HRESULT RefreshListCtrl(const UString &focusedName, int focusedPos, bool selectFocused,
@@ -351,6 +351,7 @@ public:
*/
return (UInt32)item.lParam;
}
int GetRealItemIndex(int indexInListView) const
{
/*
@@ -690,7 +691,7 @@ public:
void OpenAltStreams();
void OpenFocusedItemAsInternal();
void OpenFocusedItemAsInternal(const wchar_t *type = NULL);
void OpenSelectedItems(bool internal);
void OpenFolderExternal(int index);
@@ -703,13 +704,14 @@ public:
const UString &arcFormat,
bool &encrypted);
HRESULT OpenItemAsArchive(const UString &relPath, const UString &arcFormat, bool &encrypted);
HRESULT OpenItemAsArchive(int index);
HRESULT OpenItemAsArchive(int index, const wchar_t *type = NULL);
void OpenItemInArchive(int index, bool tryInternal, bool tryExternal,
bool editMode, bool useEditor);
bool editMode, bool useEditor, const wchar_t *type = NULL);
HRESULT OnOpenItemChanged(UInt32 index, const wchar_t *fullFilePath, bool usePassword, const UString &password);
LRESULT OnOpenItemChanged(LPARAM lParam);
void OpenItem(int index, bool tryInternal, bool tryExternal);
bool IsVirus_Message(const UString &name);
void OpenItem(int index, bool tryInternal, bool tryExternal, const wchar_t *type = NULL);
void EditItem(bool useEditor);
void EditItem(int index, bool useEditor);

View File

@@ -157,12 +157,6 @@ public:
}
};
static bool IsNameVirus(const UString &name)
{
// return (name.Find(L" ") >= 0);
return (wcsstr(name, L" ") != NULL);
}
struct CTmpProcessInfo: public CTempFileInfo
{
CChildProcesses Processes;
@@ -320,12 +314,12 @@ HRESULT CPanel::OpenItemAsArchive(const UString &relPath, const UString &arcForm
return OpenItemAsArchive(NULL, tfi, fullPath, arcFormat, encrypted);
}
HRESULT CPanel::OpenItemAsArchive(int index)
HRESULT CPanel::OpenItemAsArchive(int index, const wchar_t *type)
{
CDisableTimerProcessing disableTimerProcessing1(*this);
CDisableNotify disableNotify(*this);
bool encrypted;
HRESULT res = OpenItemAsArchive(GetItemRelPath2(index), UString(), encrypted);
HRESULT res = OpenItemAsArchive(GetItemRelPath2(index), type ? type : L"", encrypted);
if (res != S_OK)
{
RefreshTitle(true); // in case of error we must refresh changed title of 7zFM
@@ -600,19 +594,77 @@ void CPanel::OpenFolderExternal(int index)
StartApplicationDontWait(fsPrefix, name, (HWND)*this);
}
void CPanel::OpenItem(int index, bool tryInternal, bool tryExternal)
bool CPanel::IsVirus_Message(const UString &name)
{
UString name2;
const wchar_t cRLO = (wchar_t)0x202E;
bool isVirus = false;
bool isSpaceError = false;
name2 = name;
if (name2.Find(cRLO) >= 0)
{
UString badString = cRLO;
name2.Replace(badString, L"[RLO]");
isVirus = true;
}
{
const wchar_t *kVirusSpaces = L" ";
// const unsigned kNumSpaces = strlen(kVirusSpaces);
for (;;)
{
int pos = name2.Find(kVirusSpaces);
if (pos < 0)
break;
isVirus = true;
isSpaceError = true;
name2.Replace(kVirusSpaces, L" ");
}
}
if (!isVirus)
return false;
UString s = LangString(IDS_VIRUS);
if (!isSpaceError)
{
int pos1 = s.Find(L'(');
if (pos1 >= 0)
{
int pos2 = s.Find(L')', pos1 + 1);
if (pos2 >= 0)
{
s.Delete(pos1, pos2 + 1 - pos1);
if (pos1 > 0 && s[pos1 - 1] == ' ' && s[pos1] == '.')
s.Delete(pos1 - 1);
}
}
}
UString name3 = name;
name3.Replace(L'\n', L'_');
name2.Replace(L'\n', L'_');
s.Add_LF(); s += name2;
s.Add_LF(); s += name3;
MessageBoxMyError(s);
return true;
}
void CPanel::OpenItem(int index, bool tryInternal, bool tryExternal, const wchar_t *type)
{
CDisableTimerProcessing disableTimerProcessing(*this);
UString name = GetItemRelPath2(index);
if (IsNameVirus(name))
{
MessageBoxErrorLang(IDS_VIRUS);
if (IsVirus_Message(name))
return;
}
if (!_parentFolders.IsEmpty())
{
OpenItemInArchive(index, tryInternal, tryExternal, false, false);
OpenItemInArchive(index, tryInternal, tryExternal, false, false, type);
return;
}
@@ -623,7 +675,7 @@ void CPanel::OpenItem(int index, bool tryInternal, bool tryExternal)
if (tryInternal)
if (!tryExternal || !DoItemAlwaysStart(name))
{
HRESULT res = OpenItemAsArchive(index);
HRESULT res = OpenItemAsArchive(index, type);
disableNotify.Restore(); // we must restore to allow text notification update
InvalidateList();
if (res == S_OK || res == E_ABORT)
@@ -634,6 +686,7 @@ void CPanel::OpenItem(int index, bool tryInternal, bool tryExternal)
return;
}
}
if (tryExternal)
{
// SetCurrentDirectory opens HANDLE to folder!!!
@@ -939,16 +992,13 @@ static HRESULT GetTime(IFolderFolder *folder, UInt32 index, PROPID propID, FILET
}
*/
void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bool editMode, bool useEditor)
void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bool editMode, bool useEditor, const wchar_t *type)
{
const UString name = GetItemName(index);
const UString relPath = GetItemRelPath(index);
if (IsNameVirus(name))
{
MessageBoxErrorLang(IDS_VIRUS);
if (IsVirus_Message(name))
return;
}
if (!_folderOperations)
{
@@ -966,6 +1016,7 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo
MessageBoxLastError();
return;
}
FString tempDir = tempDirectory.GetPath();
FString tempDirNorm = tempDir;
NName::NormalizeDirPathPrefix(tempDirNorm);
@@ -993,7 +1044,7 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo
if (subStream)
{
bool encrypted;
HRESULT res = OpenItemAsArchive(subStream, tempFileInfo, fullVirtPath, UString(), encrypted);
HRESULT res = OpenItemAsArchive(subStream, tempFileInfo, fullVirtPath, type ? type : L"", encrypted);
if (res == S_OK)
{
tempDirectory.DisableDeleting();
@@ -1104,7 +1155,7 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo
CMyComPtr<IInStream> bufInStream = bufInStreamSpec;
bufInStreamSpec->Init(file.Data, streamSize, virtFileSystem);
bool encrypted;
if (OpenItemAsArchive(bufInStream, tempFileInfo, fullVirtPath, UString(), encrypted) == S_OK)
if (OpenItemAsArchive(bufInStream, tempFileInfo, fullVirtPath, type ? type : L"", encrypted) == S_OK)
{
tempDirectory.DisableDeleting();
RefreshListCtrl();
@@ -1130,7 +1181,7 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo
if (tryAsArchive)
{
bool encrypted;
if (OpenItemAsArchive(NULL, tempFileInfo, fullVirtPath, UString(), encrypted) == S_OK)
if (OpenItemAsArchive(NULL, tempFileInfo, fullVirtPath, type ? type : L"", encrypted) == S_OK)
{
tempDirectory.DisableDeleting();
RefreshListCtrl();

View File

@@ -210,14 +210,15 @@ HRESULT CPanel::InitColumns()
*/
_sortID = _listViewInfo.SortID;
_visibleProperties.Sort();
for (i = 0; i < _visibleProperties.Size(); i++)
{
InsertColumn(i);
}
return S_OK;
}
void CPanel::InsertColumn(int index)
void CPanel::InsertColumn(unsigned index)
{
const CItemProperty &prop = _visibleProperties[index];
LV_COLUMNW column;
@@ -225,6 +226,7 @@ void CPanel::InsertColumn(int index)
column.cx = prop.Width;
column.fmt = GetColumnAlign(prop.ID, prop.Type);
column.iOrder = prop.Order;
// iOrder must be <= _listView.ItemCount
column.iSubItem = index;
column.pszText = const_cast<wchar_t *>((const wchar_t *)prop.Name);
_listView.InsertColumn(index, &column);
@@ -775,7 +777,7 @@ void CPanel::EditItem(bool useEditor)
EditItem(realIndex, useEditor);
}
void CPanel::OpenFocusedItemAsInternal()
void CPanel::OpenFocusedItemAsInternal(const wchar_t *type)
{
int focusedItem = _listView.GetFocusedItem();
if (focusedItem < 0)
@@ -784,7 +786,7 @@ void CPanel::OpenFocusedItemAsInternal()
if (IsItem_Folder(realIndex))
OpenFolder(realIndex);
else
OpenItem(realIndex, true, false);
OpenItem(realIndex, true, false, type);
}
void CPanel::OpenSelectedItems(bool tryInternal)
@@ -1059,10 +1061,10 @@ void CPanel::ShowColumnsContextMenu(int x, int y)
if (prop.IsVisible)
{
int prevVisibleSize = _visibleProperties.Size();
prop.Order = prevVisibleSize;
unsigned num = _visibleProperties.Size();
prop.Order = num;
_visibleProperties.Add(prop);
InsertColumn(prevVisibleSize);
InsertColumn(num);
}
else
{

View File

@@ -320,23 +320,33 @@ LRESULT CPanel::SetItemText(LVITEMW &item)
const wchar_t *name = NULL;
unsigned nameLen = 0;
_folderGetItemName->GetItemName(realIndex, &name, &nameLen);
if (name)
{
unsigned dest = 0;
unsigned limit = item.cchTextMax - 1;
for (unsigned i = 0; dest < limit;)
{
wchar_t c = name[i++];
if (c == 0)
break;
text[dest++] = c;
if (c != ' ')
{
if (c != 0x202E) // RLO
continue;
text[dest - 1] = '_';
continue;
}
if (name[i + 1] != ' ')
continue;
unsigned t = 2;
for (; name[i + t] == ' '; t++);
if (t >= 4 && dest + 4 <= limit)
{
text[dest++] = '.';
@@ -346,6 +356,7 @@ LRESULT CPanel::SetItemText(LVITEMW &item)
i += t;
}
}
text[dest] = 0;
return 0;
}

View File

@@ -47,6 +47,9 @@
#define IDM_LINK 558
#define IDM_ALT_STREAMS 559
#define IDM_OPEN_INSIDE_ONE 590
#define IDM_OPEN_INSIDE_PARSER 591
#define IDM_SELECT_ALL 600
#define IDM_DESELECT_ALL 601
#define IDM_INVERT_SELECTION 602

View File

@@ -19,6 +19,8 @@ BEGIN
BEGIN
MENUITEM "&Open\tEnter", IDM_OPEN
MENUITEM "Open &Inside\tCtrl+PgDn", IDM_OPEN_INSIDE
MENUITEM "Open Inside *", IDM_OPEN_INSIDE_ONE
MENUITEM "Open Inside #", IDM_OPEN_INSIDE_PARSER
MENUITEM "Open O&utside\tShift+Enter", IDM_OPEN_OUTSIDE
MENUITEM "&View\tF3", IDM_FILE_VIEW
MENUITEM "&Edit\tF4", IDM_FILE_EDIT

View File

@@ -18,7 +18,7 @@
#define IDX_EXTRACT_ELIM_DUP 3430
#define IDX_EXTRACT_NT_SECUR 3431
// #define IDX_EXTRACT_ALT_STREAMS 3432
// #define IDX_EXTRACT_ALT_STREAMS 3432
#define IDX_PASSWORD_SHOW 3803
#define IDG_PASSWORD 3807

View File

@@ -254,6 +254,8 @@ static int Main2()
}
}
ecs->MultiArcMode = (ArchivePathsSorted.Size() > 1);
HRESULT result = ExtractGUI(codecs,
formatIndices, excludedFormatIndices,
ArchivePathsSorted,

View File

@@ -1,10 +1,10 @@
#define IDS_PROGRESS_REMOVE 3305
#define IDS_PROGRESS_ADD 3320
#define IDS_PROGRESS_UPDATE 3321
#define IDS_PROGRESS_ANALYZE 3322
#define IDS_PROGRESS_REPLICATE 3323
#define IDS_PROGRESS_REPACK 3324
#define IDS_PROGRESS_ADD 3320
#define IDS_PROGRESS_UPDATE 3321
#define IDS_PROGRESS_ANALYZE 3322
#define IDS_PROGRESS_REPLICATE 3323
#define IDS_PROGRESS_REPACK 3324
#define IDS_PROGRESS_DELETE 3326
#define IDS_PROGRESS_HEADER 3327
#define IDS_PROGRESS_DELETE 3326
#define IDS_PROGRESS_HEADER 3327

View File

@@ -156,6 +156,7 @@ public:
typedef CObjArray<unsigned char> CByteArr;
typedef CObjArray<bool> CBoolArr;
typedef CObjArray<int> CIntArr;
typedef CObjArray<unsigned> CUIntArr;
template <class T> class CObjArray2

View File

@@ -108,3 +108,42 @@ void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NCOM
{
prop = FlagsToString(pairs, num, flags);
}
AString Flags64ToString(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags)
{
AString s;
for (unsigned i = 0; i < num; i++)
{
const CUInt32PCharPair &p = pairs[i];
UInt64 flag = (UInt64)1 << (unsigned)p.Value;
if ((flags & flag) != 0)
{
if (p.Name[0] != 0)
{
if (!s.IsEmpty())
s += ' ';
s += p.Name;
}
}
flags &= ~flag;
}
if (flags != 0)
{
if (!s.IsEmpty())
s += ' ';
{
char sz[32];
sz[0] = '0';
sz[1] = 'x';
ConvertUInt64ToHex(flags, sz + 2);
s += sz;
}
}
return s;
}
void Flags64ToProp(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags, NCOM::CPropVariant &prop)
{
prop = Flags64ToString(pairs, num, flags);
}

View File

@@ -27,4 +27,7 @@ void TypeToProp(const char * const table[], unsigned num, UInt32 value, NWindows
#define FLAGS_TO_PROP(pairs, value, prop) FlagsToProp(pairs, ARRAY_SIZE(pairs), value, prop)
#define TYPE_TO_PROP(table, value, prop) TypeToProp(table, ARRAY_SIZE(table), value, prop)
void Flags64ToProp(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags, NWindows::NCOM::CPropVariant &prop);
#define FLAGS64_TO_PROP(pairs, value, prop) Flags64ToProp(pairs, ARRAY_SIZE(pairs), value, prop)
#endif

View File

@@ -10,8 +10,8 @@ AppName = "7-Zip"
InstallDir = %CE1%\%AppName%
[Strings]
AppVer = "15.06"
AppDate = "2015-08-09"
AppVer = "15.07"
AppDate = "2015-09-17"
[CEDevice]
; ProcessorType = 2577 ; ARM

View File

@@ -2,7 +2,7 @@
;Defines
!define VERSION_MAJOR 15
!define VERSION_MINOR 06
!define VERSION_MINOR 07
!define VERSION_POSTFIX_FULL " beta"
!ifdef WIN64
!ifdef IA64

View File

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

View File

@@ -1,4 +1,4 @@
7-Zip 15.06 Sources
7-Zip 15.07 Sources
-------------------
7-Zip is a file archiver for Windows.