Compare commits

...

2 Commits
15.05 ... 15.07

Author SHA1 Message Date
Igor Pavlov
f6444c3256 15.07 2016-05-28 00:16:55 +01:00
Igor Pavlov
cba375916f 15.06 2016-05-28 00:16:55 +01:00
225 changed files with 13774 additions and 4339 deletions

View File

@@ -1,5 +1,5 @@
/* 7zDec.c -- Decoding from 7z folder
2015-06-13 : Igor Pavlov : Public domain */
2015-08-01 : Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -144,11 +144,11 @@ static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, I
for (;;)
{
Byte *inBuf = NULL;
const void *inBuf = NULL;
size_t lookahead = (1 << 18);
if (lookahead > inSize)
lookahead = (size_t)inSize;
res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
res = inStream->Look(inStream, &inBuf, &lookahead);
if (res != SZ_OK)
break;
@@ -197,11 +197,11 @@ static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize,
for (;;)
{
Byte *inBuf = NULL;
const void *inBuf = NULL;
size_t lookahead = (1 << 18);
if (lookahead > inSize)
lookahead = (size_t)inSize;
res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
res = inStream->Look(inStream, &inBuf, &lookahead);
if (res != SZ_OK)
break;
@@ -237,11 +237,11 @@ static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer
{
while (inSize > 0)
{
void *inBuf;
const void *inBuf;
size_t curSize = (1 << 18);
if (curSize > inSize)
curSize = (size_t)inSize;
RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize));
RINOK(inStream->Look(inStream, &inBuf, &curSize));
if (curSize == 0)
return SZ_ERROR_INPUT_EOF;
memcpy(outBuffer, inBuf, curSize);
@@ -429,7 +429,7 @@ static SRes SzFolder_Decode2(const CSzFolder *folder,
RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
}
#endif
else
else
return SZ_ERROR_UNSUPPORTED;
}
else if (coder->MethodID == k_BCJ2)

View File

@@ -1,10 +1,12 @@
#define MY_VER_MAJOR 15
#define MY_VER_MINOR 05
#define MY_VER_MINOR 07
#define MY_VER_BUILD 00
#define MY_VERSION "15.05 beta"
#define MY_DATE "2015-06-14"
#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"
#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
#define MY_COPYRIGHT_CR "Copyright (c) 1999-2015 Igor Pavlov"

View File

@@ -1,5 +1,5 @@
/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code)
2014-11-09 : Igor Pavlov : Public domain */
2015-08-01 : Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -178,8 +178,8 @@ SRes Bcj2Dec_Decode(CBcj2Dec *p)
p->state =
p->bufs[BCJ2_STREAM_MAIN] ==
p->lims[BCJ2_STREAM_MAIN] ?
BCJ2_STREAM_MAIN :
BCJ2_DEC_STATE_ORIG;
(unsigned)BCJ2_STREAM_MAIN :
(unsigned)BCJ2_DEC_STATE_ORIG;
return SZ_OK;
}

48
C/Blake2.h Normal file
View File

@@ -0,0 +1,48 @@
/* Blake2.h -- BLAKE2 Hash
2015-06-30 : Igor Pavlov : Public domain
2015 : Samuel Neves : Public domain */
#ifndef __BLAKE2_H
#define __BLAKE2_H
#include "7zTypes.h"
EXTERN_C_BEGIN
#define BLAKE2S_BLOCK_SIZE 64
#define BLAKE2S_DIGEST_SIZE 32
#define BLAKE2SP_PARALLEL_DEGREE 8
typedef struct
{
UInt32 h[8];
UInt32 t[2];
UInt32 f[2];
Byte buf[BLAKE2S_BLOCK_SIZE];
UInt32 bufPos;
UInt32 lastNode_f1;
UInt32 dummy[2]; /* for sizeof(CBlake2s) alignment */
} CBlake2s;
/* You need to xor CBlake2s::h[i] with input parameter block after Blake2s_Init0() */
/*
void Blake2s_Init0(CBlake2s *p);
void Blake2s_Update(CBlake2s *p, const Byte *data, size_t size);
void Blake2s_Final(CBlake2s *p, Byte *digest);
*/
typedef struct
{
CBlake2s S[BLAKE2SP_PARALLEL_DEGREE];
unsigned bufPos;
} CBlake2sp;
void Blake2sp_Init(CBlake2sp *p);
void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size);
void Blake2sp_Final(CBlake2sp *p, Byte *digest);
EXTERN_C_END
#endif

244
C/Blake2s.c Normal file
View File

@@ -0,0 +1,244 @@
/* Blake2s.c -- BLAKE2s and BLAKE2sp Hash
2015-06-30 : Igor Pavlov : Public domain
2015 : Samuel Neves : Public domain */
#include <string.h>
#include "Blake2.h"
#include "CpuArch.h"
#include "RotateDefs.h"
#define rotr32 rotrFixed
#define BLAKE2S_NUM_ROUNDS 10
#define BLAKE2S_FINAL_FLAG (~(UInt32)0)
static const UInt32 k_Blake2s_IV[8] =
{
0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
};
static const Byte k_Blake2s_Sigma[BLAKE2S_NUM_ROUNDS][16] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
};
void Blake2s_Init0(CBlake2s *p)
{
unsigned i;
for (i = 0; i < 8; i++)
p->h[i] = k_Blake2s_IV[i];
p->t[0] = 0;
p->t[1] = 0;
p->f[0] = 0;
p->f[1] = 0;
p->bufPos = 0;
p->lastNode_f1 = 0;
}
static void Blake2s_Compress(CBlake2s *p)
{
UInt32 m[16];
UInt32 v[16];
{
unsigned i;
for (i = 0; i < 16; i++)
m[i] = GetUi32(p->buf + i * sizeof(m[i]));
for (i = 0; i < 8; i++)
v[i] = p->h[i];
}
v[ 8] = k_Blake2s_IV[0];
v[ 9] = k_Blake2s_IV[1];
v[10] = k_Blake2s_IV[2];
v[11] = k_Blake2s_IV[3];
v[12] = p->t[0] ^ k_Blake2s_IV[4];
v[13] = p->t[1] ^ k_Blake2s_IV[5];
v[14] = p->f[0] ^ k_Blake2s_IV[6];
v[15] = p->f[1] ^ k_Blake2s_IV[7];
#define G(r,i,a,b,c,d) \
a += b + m[sigma[2*i+0]]; d ^= a; d = rotr32(d, 16); c += d; b ^= c; b = rotr32(b, 12); \
a += b + m[sigma[2*i+1]]; d ^= a; d = rotr32(d, 8); c += d; b ^= c; b = rotr32(b, 7); \
#define R(r) \
G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
G(r,2,v[ 2],v[ 6],v[10],v[14]); \
G(r,3,v[ 3],v[ 7],v[11],v[15]); \
G(r,4,v[ 0],v[ 5],v[10],v[15]); \
G(r,5,v[ 1],v[ 6],v[11],v[12]); \
G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
{
unsigned r;
for (r = 0; r < BLAKE2S_NUM_ROUNDS; r++)
{
const Byte *sigma = k_Blake2s_Sigma[r];
R(r);
}
/* R(0); R(1); R(2); R(3); R(4); R(5); R(6); R(7); R(8); R(9); */
}
#undef G
#undef R
{
unsigned i;
for (i = 0; i < 8; i++)
p->h[i] ^= v[i] ^ v[i + 8];
}
}
#define Blake2s_Increment_Counter(S, inc) \
{ p->t[0] += (inc); p->t[1] += (p->t[0] < (inc)); }
#define Blake2s_Set_LastBlock(p) \
{ p->f[0] = BLAKE2S_FINAL_FLAG; p->f[1] = p->lastNode_f1; }
static void Blake2s_Update(CBlake2s *p, const Byte *data, size_t size)
{
while (size != 0)
{
unsigned pos = (unsigned)p->bufPos;
unsigned rem = BLAKE2S_BLOCK_SIZE - pos;
if (size <= rem)
{
memcpy(p->buf + pos, data, size);
p->bufPos += (UInt32)size;
return;
}
memcpy(p->buf + pos, data, rem);
Blake2s_Increment_Counter(S, BLAKE2S_BLOCK_SIZE);
Blake2s_Compress(p);
p->bufPos = 0;
data += rem;
size -= rem;
}
}
static void Blake2s_Final(CBlake2s *p, Byte *digest)
{
unsigned i;
Blake2s_Increment_Counter(S, (UInt32)p->bufPos);
Blake2s_Set_LastBlock(p);
memset(p->buf + p->bufPos, 0, BLAKE2S_BLOCK_SIZE - p->bufPos);
Blake2s_Compress(p);
for (i = 0; i < 8; i++)
SetUi32(digest + sizeof(p->h[i]) * i, p->h[i]);
}
/* ---------- BLAKE2s ---------- */
/* we need to xor CBlake2s::h[i] with input parameter block after Blake2s_Init0() */
/*
typedef struct
{
Byte digest_length;
Byte key_length;
Byte fanout;
Byte depth;
UInt32 leaf_length;
Byte node_offset[6];
Byte node_depth;
Byte inner_length;
Byte salt[BLAKE2S_SALTBYTES];
Byte personal[BLAKE2S_PERSONALBYTES];
} CBlake2sParam;
*/
static void Blake2sp_Init_Spec(CBlake2s *p, unsigned node_offset, unsigned node_depth)
{
Blake2s_Init0(p);
p->h[0] ^= (BLAKE2S_DIGEST_SIZE | ((UInt32)BLAKE2SP_PARALLEL_DEGREE << 16) | ((UInt32)2 << 24));
p->h[2] ^= ((UInt32)node_offset);
p->h[3] ^= ((UInt32)node_depth << 16) | ((UInt32)BLAKE2S_DIGEST_SIZE << 24);
/*
P->digest_length = BLAKE2S_DIGEST_SIZE;
P->key_length = 0;
P->fanout = BLAKE2SP_PARALLEL_DEGREE;
P->depth = 2;
P->leaf_length = 0;
store48(P->node_offset, node_offset);
P->node_depth = node_depth;
P->inner_length = BLAKE2S_DIGEST_SIZE;
*/
}
void Blake2sp_Init(CBlake2sp *p)
{
unsigned i;
p->bufPos = 0;
for (i = 0; i < BLAKE2SP_PARALLEL_DEGREE; i++)
Blake2sp_Init_Spec(&p->S[i], i, 0);
p->S[BLAKE2SP_PARALLEL_DEGREE - 1].lastNode_f1 = BLAKE2S_FINAL_FLAG;
}
void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size)
{
unsigned pos = p->bufPos;
while (size != 0)
{
unsigned index = pos / BLAKE2S_BLOCK_SIZE;
unsigned rem = BLAKE2S_BLOCK_SIZE - (pos & (BLAKE2S_BLOCK_SIZE - 1));
if (rem > size)
rem = (unsigned)size;
Blake2s_Update(&p->S[index], data, rem);
size -= rem;
data += rem;
pos += rem;
pos &= (BLAKE2S_BLOCK_SIZE * BLAKE2SP_PARALLEL_DEGREE - 1);
}
p->bufPos = pos;
}
void Blake2sp_Final(CBlake2sp *p, Byte *digest)
{
CBlake2s R;
unsigned i;
Blake2sp_Init_Spec(&R, 0, 1);
R.lastNode_f1 = BLAKE2S_FINAL_FLAG;
for (i = 0; i < BLAKE2SP_PARALLEL_DEGREE; i++)
{
Byte hash[BLAKE2S_DIGEST_SIZE];
Blake2s_Final(&p->S[i], hash);
Blake2s_Update(&R, hash, BLAKE2S_DIGEST_SIZE);
}
Blake2s_Final(&R, digest);
}

View File

@@ -1,5 +1,5 @@
/* Compiler.h
2015-03-25 : Igor Pavlov : Public domain */
2015-08-02 : Igor Pavlov : Public domain */
#ifndef __7Z_COMPILER_H
#define __7Z_COMPILER_H
@@ -18,6 +18,7 @@
#else
#pragma warning(disable : 4511) // copy constructor could not be generated
#pragma warning(disable : 4512) // assignment operator could not be generated
#pragma warning(disable : 4514) // unreferenced inline function has been removed
#pragma warning(disable : 4702) // unreachable code
#pragma warning(disable : 4710) // not inlined
#pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information

View File

@@ -1,5 +1,5 @@
/* CpuArch.h -- CPU specific code
2015-03-25: Igor Pavlov : Public domain */
2015-08-02: Igor Pavlov : Public domain */
#ifndef __CPU_ARCH_H
#define __CPU_ARCH_H
@@ -90,9 +90,10 @@ Stop_Compiling_Bad_Endian
#define GetUi16(p) (*(const UInt16 *)(const void *)(p))
#define GetUi32(p) (*(const UInt32 *)(const void *)(p))
#define GetUi64(p) (*(const UInt64 *)(const void *)(p))
#define SetUi16(p, v) *(UInt16 *)(p) = (v);
#define SetUi32(p, v) *(UInt32 *)(p) = (v);
#define SetUi64(p, v) *(UInt64 *)(p) = (v);
#define SetUi16(p, v) { *(UInt16 *)(p) = (v); }
#define SetUi32(p, v) { *(UInt32 *)(p) = (v); }
#define SetUi64(p, v) { *(UInt64 *)(p) = (v); }
#else

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

@@ -1,5 +1,5 @@
/* LzmaDec.c -- LZMA Decoder
2015-05-14 : Igor Pavlov : Public domain */
2015-06-23 : Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -438,10 +438,16 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
if (checkDicSize == 0)
{
if (distance >= processedPos)
{
p->dicPos = dicPos;
return SZ_ERROR_DATA;
}
}
else if (distance >= checkDicSize)
{
p->dicPos = dicPos;
return SZ_ERROR_DATA;
}
state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
}
@@ -453,7 +459,10 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
SizeT pos;
if ((rem = limit - dicPos) == 0)
{
p->dicPos = dicPos;
return SZ_ERROR_DATA;
}
curLen = ((rem < len) ? (unsigned)rem : len);
pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0);

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,5 +1,5 @@
/* 7zMain.c - Test application for 7z Decoder
2015-05-11 : Igor Pavlov : Public domain */
2015-08-02 : Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -328,22 +328,20 @@ void PrintError(char *sz)
printf("\nERROR: %s\n", sz);
}
#ifdef USE_WINDOWS_FILE
static void GetAttribString(UInt32 wa, Bool isDir, char *s)
{
#ifdef USE_WINDOWS_FILE
s[0] = (char)(((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || isDir) ? 'D' : '.');
s[1] = (char)(((wa & FILE_ATTRIBUTE_READONLY ) != 0) ? 'R': '.');
s[2] = (char)(((wa & FILE_ATTRIBUTE_HIDDEN ) != 0) ? 'H': '.');
s[3] = (char)(((wa & FILE_ATTRIBUTE_SYSTEM ) != 0) ? 'S': '.');
s[4] = (char)(((wa & FILE_ATTRIBUTE_ARCHIVE ) != 0) ? 'A': '.');
s[5] = '\0';
s[5] = 0;
#else
s[0] = (char)(((wa & (1 << 4)) != 0 || isDir) ? 'D' : '.');
s[1] = 0;
#endif
}
#else
static void GetAttribString(UInt32, Bool, char *s)
{
s[0] = '\0';
}
#endif
// #define NUM_PARENTS_MAX 128

View File

@@ -1,10 +1,10 @@
PROG = 7zDec
CXX = g++
CXX = gcc
LIB =
RM = rm -f
CFLAGS = -c -O2 -Wall
OBJS = 7zMain.o 7zAlloc.o 7zArcIn.o 7zBuf.o 7zBuf2.o 7zCrc.o 7zCrcOpt.o 7zDec.o CpuArch.o LzmaDec.o Lzma2Dec.o Bra.o Bra86.o Bcj2.o Ppmd7.o Ppmd7Dec.o 7zFile.o 7zStream.o
OBJS = 7zMain.o 7zAlloc.o 7zArcIn.o 7zBuf.o 7zBuf2.o 7zCrc.o 7zCrcOpt.o 7zDec.o CpuArch.o Delta.o LzmaDec.o Lzma2Dec.o Bra.o Bra86.o BraIA64.o Bcj2.o Ppmd7.o Ppmd7Dec.o 7zFile.o 7zStream.o
all: $(PROG)
@@ -38,6 +38,9 @@ $(PROG): $(OBJS)
CpuArch.o: ../../CpuArch.c
$(CXX) $(CFLAGS) ../../CpuArch.c
Delta.o: ../../Delta.c
$(CXX) $(CFLAGS) ../../Delta.c
LzmaDec.o: ../../LzmaDec.c
$(CXX) $(CFLAGS) ../../LzmaDec.c
@@ -50,6 +53,9 @@ Bra.o: ../../Bra.c
Bra86.o: ../../Bra86.c
$(CXX) $(CFLAGS) ../../Bra86.c
BraIA64.o: ../../BraIA64.c
$(CXX) $(CFLAGS) ../../BraIA64.c
Bcj2.o: ../../Bcj2.c
$(CXX) $(CFLAGS) ../../Bcj2.c

View File

@@ -1,5 +1,5 @@
/* 7zipInnstall.c - 7-Zip Installer
2015-06-13 : Igor Pavlov : Public domain */
/* 7zipInstall.c - 7-Zip Installer
2015-08-04 : Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -37,7 +37,7 @@ static const WCHAR *k_Reg_Software_7zip = L"Software\\7-Zip";
#define k_7zip_with_Ver_base L"7-Zip " LLL(MY_VERSION)
#ifdef _64BIT_INSTALLER
#define k_7zip_with_Ver k_7zip_with_Ver_base L" x64"
#define k_7zip_with_Ver k_7zip_with_Ver_base L" (x64)"
#else
#define k_7zip_with_Ver k_7zip_with_Ver_base
#endif
@@ -84,6 +84,8 @@ static HWND g_Path_HWND;
static HWND g_InfoLine_HWND;
static HWND g_Progress_HWND;
static DWORD g_TotalSize;
static WCHAR path[MAX_PATH * 2 + 40];
@@ -143,7 +145,7 @@ static WRes CreateComplexDir()
if (IS_DRIVE_PATH(s))
prefixSize = 3;
else if (IS_SEPAR(s[1]) && IS_SEPAR(s[1]))
else if (IS_SEPAR(s[0]) && IS_SEPAR(s[1]))
prefixSize = 2;
else
return ERROR_INVALID_NAME;
@@ -796,16 +798,30 @@ static void WriteShellEx()
// wcscpy(destPath, path);
// wcscat(destPath, L"7zFM.exe");
MyRegistry_SetString(destKey, L"DisplayName", k_7zip_with_Ver_str);
MyRegistry_SetString(destKey, L"DisplayVersion", LLL(MY_VERSION_NUMBERS));
MyRegistry_SetString(destKey, L"DisplayIcon", destPath);
wcscpy(destPath, path);
// MyRegistry_SetString(destKey, L"InstallLocation", destPath);
MyRegistry_SetString(destKey, L"InstallLocation", destPath);
wcscat(destPath, L"Uninstall.exe");
// wcscat(destPath, L"\"");
MyRegistry_SetString(destKey, L"UninstallString", destPath);
MyRegistry_SetDWORD(destKey, L"NoModify", 1);
MyRegistry_SetDWORD(destKey, L"NoRepair", 1);
MyRegistry_SetDWORD(destKey, L"EstimatedSize", g_TotalSize >> 10);
MyRegistry_SetDWORD(destKey, L"VersionMajor", MY_VER_MAJOR);
MyRegistry_SetDWORD(destKey, L"VersionMinor", MY_VER_MINOR);
MyRegistry_SetString(destKey, L"Publisher", LLL(MY_AUTHOR_NAME));
// MyRegistry_SetString(destKey, L"HelpLink", L"http://www.7-zip.org/support.html");
// MyRegistry_SetString(destKey, L"URLInfoAbout", L"http://www.7-zip.org/");
// MyRegistry_SetString(destKey, L"URLUpdateInfo", L"http://www.7-zip.org/");
RegCloseKey(destKey);
}
}
@@ -1108,6 +1124,23 @@ if (res == SZ_OK)
FileInStream_CreateVTable(&archiveStream);
LookToRead_CreateVTable(&lookStream, False);
{
// Remove post spaces
unsigned endPos = 0;
unsigned i = 0;
for (;;)
{
wchar_t c = path[i++];
if (c == 0)
break;
if (c != ' ')
endPos = i;
}
path[endPos] = 0;
}
NormalizePrefix(path);
winRes = CreateComplexDir();
@@ -1131,6 +1164,8 @@ if (res == SZ_OK)
UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call, if(!outBuf) */
Byte *outBuf = NULL; /* it must be NULL before first call for each new archive. */
size_t outBufSize = 0; /* it can have any value before first call, if(!outBuf) */
g_TotalSize = 0;
if (!g_SilentMode)
{
@@ -1309,6 +1344,8 @@ if (res == SZ_OK)
res = SZ_ERROR_FAIL;
}
g_TotalSize += (DWORD)outSizeProcessed;
#ifdef USE_WINDOWS_FILE
if (SzBitWithVals_Check(&db.MTime, i))
{

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,5 +1,5 @@
/* 7zipUninstall.c - 7-Zip Uninstaller
2015-06-13 : Igor Pavlov : Public domain */
2015-08-09 : Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -31,7 +31,7 @@
#define k_7zip_with_Ver_base L"7-Zip " LLL(MY_VERSION)
#ifdef _64BIT_INSTALLER
#define k_7zip_with_Ver k_7zip_with_Ver_base L" x64"
#define k_7zip_with_Ver k_7zip_with_Ver_base L" (x64)"
#else
#define k_7zip_with_Ver k_7zip_with_Ver_base
#endif

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

@@ -301,6 +301,12 @@ HRESULT CDecoder::Decode(
{
const CCoderInfo &coderInfo = folderInfo.Coders[i];
#ifndef _SFX
// we don't support RAR codecs here
if ((coderInfo.MethodID >> 8) == 0x403)
return E_NOTIMPL;
#endif
CCreatedCoder cod;
RINOK(CreateCoder(
EXTERNAL_CODECS_LOC_VARS

View File

@@ -44,6 +44,7 @@ public:
UInt64 _numSolidBytes;
bool _numSolidBytesDefined;
bool _solidExtension;
bool _useTypeSorting;
bool _compressHeaders;
bool _encryptHeadersSpecified;

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();
@@ -508,14 +509,19 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (ui.NewData)
{
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(i, kpidSize, &prop));
if (prop.vt != VT_UI8)
return E_INVALIDARG;
ui.Size = (UInt64)prop.uhVal.QuadPart;
if (ui.Size != 0 && ui.IsAnti)
return E_INVALIDARG;
ui.Size = 0;
if (!ui.IsDir)
{
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(i, kpidSize, &prop));
if (prop.vt != VT_UI8)
return E_INVALIDARG;
ui.Size = (UInt64)prop.uhVal.QuadPart;
if (ui.Size != 0 && ui.IsAnti)
return E_INVALIDARG;
}
}
updateItems.Add(ui);
}
@@ -613,6 +619,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
options.NumSolidFiles = _numSolidFiles;
options.NumSolidBytes = _numSolidBytes;
options.SolidExtension = _solidExtension;
options.UseTypeSorting = _useTypeSorting;
options.RemoveSfxBlock = _removeSfxBlock;
// options.VolumeMode = _volumeMode;
@@ -701,6 +709,7 @@ void COutHandler::InitProps()
// _volumeMode = false;
InitSolid();
_useTypeSorting = false;
}
HRESULT COutHandler::SetSolidFromString(const UString &s)
@@ -821,6 +830,8 @@ HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &val
if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer);
if (name.IsEqualTo("qs")) return PROPVARIANT_to_bool(value, _useTypeSorting);
// if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode);
}
return CMultiMethodProps::SetProperty(name, value);

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); }
@@ -554,11 +554,11 @@ static int CompareEmptyItems(const unsigned *p1, const unsigned *p2, void *param
}
static const char *g_Exts =
" lzma 7z ace arc arj bz bz2 deb lzo lzx gz pak rpm sit tgz tbz tbz2 tgz cab ha lha lzh rar zoo"
" 7z xz lzma ace arc arj bz tbz bz2 tbz2 cab deb gz tgz ha lha lzh lzo lzx pak rar rpm sit zoo"
" zip jar ear war msi"
" 3gp avi mov mpeg mpg mpe wmv"
" aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav"
" swf "
" swf"
" chm hxi hxs"
" gif jpeg jpg jp2 png tiff bmp ico psd psp"
" awg ps eps cgm dxf svg vrml wmf emf ai md"
@@ -569,9 +569,9 @@ static const char *g_Exts =
" vmdk dsk nvram vmem vmsd vmsn vmss vmtm"
" inl inc idl acf asa h hpp hxx c cpp cxx rc java cs pas bas vb cls ctl frm dlg def"
" f77 f f90 f95"
" asm sql manifest dep "
" mak clw csproj vcproj sln dsp dsw "
" class "
" asm sql manifest dep"
" mak clw csproj vcproj sln dsp dsw"
" class"
" bat cmd"
" xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml"
" awk sed hta js php php3 php4 php5 phptml pl pm py pyo rb sh tcl vbs"
@@ -580,7 +580,7 @@ static const char *g_Exts =
" abw afp cwk lwp wpd wps wpt wrf wri"
" abf afm bdf fon mgf otf pcf pfa snf ttf"
" dbf mdb nsf ntf wdb db fdb gdb"
" exe dll ocx vbx sfx sys tlb awx com obj lib out o so "
" exe dll ocx vbx sfx sys tlb awx com obj lib out o so"
" pdb pch idb ncb opt";
static unsigned GetExtIndex(const char *ext)
@@ -2251,7 +2251,7 @@ HRESULT Update(
continue;
CRecordVector<CRefItem> refItems;
refItems.ClearAndSetSize(numFiles);
bool sortByType = (numSolidFiles > 1);
bool sortByType = (options.UseTypeSorting && numSolidFiles > 1);
for (i = 0; i < numFiles; i++)
refItems[i] = CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType);
CSortParam sortParam;

View File

@@ -97,6 +97,9 @@ struct CUpdateOptions
UInt64 NumSolidFiles;
UInt64 NumSolidBytes;
bool SolidExtension;
bool UseTypeSorting;
bool RemoveSfxBlock;
bool MultiThreadMixer;
@@ -109,6 +112,7 @@ struct CUpdateOptions
NumSolidFiles((UInt64)(Int64)(-1)),
NumSolidBytes((UInt64)(Int64)(-1)),
SolidExtension(false),
UseTypeSorting(true),
RemoveSfxBlock(false),
MultiThreadMixer(true)
{}

View File

@@ -1,5 +1,5 @@
PROG = 7z.dll
DEF_FILE = ../../Archive/Archive2.def
DEF_FILE = ../Archive.def
CFLAGS = $(CFLAGS) \
-DEXTERNAL_CODECS \
@@ -60,9 +60,11 @@ WIN_OBJS = \
$O\StreamUtils.obj \
$O\VirtThread.obj \
COMPRESS_OBJS = \
$O\CopyCoder.obj \
AR_COMMON_OBJS = \
$O\CoderMixer2.obj \
$O\CoderMixer2MT.obj \
$O\CrossThreadProgress.obj \
$O\HandlerOut.obj \
$O\InStreamWithCRC.obj \
@@ -76,4 +78,6 @@ C_OBJS = \
$O\CpuArch.obj \
$O\Threads.obj \
!include "../../Crc.mak"
!include "../../7zip.mak"

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

@@ -1,19 +0,0 @@
// CoderMixer.cpp
#include "StdAfx.h"
#include "CoderMixer.h"
namespace NCoderMixer {
void CCoderInfo::SetCoderInfo(const UInt64 *inSize, const UInt64 *outSize)
{
InSizeAssigned = (inSize != 0);
if (InSizeAssigned)
InSizeValue = *inSize;
OutSizeAssigned = (outSize != 0);
if (OutSizeAssigned)
OutSizeValue = *outSize;
}
}

View File

@@ -1,32 +0,0 @@
// CoderMixer.h
#ifndef __CODER_MIXER_H
#define __CODER_MIXER_H
#include "../../../Common/MyCom.h"
#include "../../ICoder.h"
namespace NCoderMixer {
struct CCoderInfo
{
CMyComPtr<ICompressCoder> Coder;
CMyComPtr<ISequentialInStream> InStream;
CMyComPtr<ISequentialOutStream> OutStream;
CMyComPtr<ICompressProgressInfo> Progress;
UInt64 InSizeValue;
UInt64 OutSizeValue;
bool InSizeAssigned;
bool OutSizeAssigned;
void ReInit()
{
InSizeAssigned = OutSizeAssigned = false;
}
void SetCoderInfo(const UInt64 *inSize, const UInt64 *outSize);
};
}
#endif

View File

@@ -1,254 +0,0 @@
// CoderMixer2MT.cpp
#include "StdAfx.h"
#include "CoderMixer2MT.h"
namespace NCoderMixer2 {
void CCoderMT::Execute() { Code(NULL); }
void CCoderMT::Code(ICompressProgressInfo *progress)
{
unsigned numInStreams = EncodeMode ? 1 : NumStreams;
unsigned numOutStreams = EncodeMode ? NumStreams : 1;
InStreamPointers.ClearAndReserve(numInStreams);
OutStreamPointers.ClearAndReserve(numOutStreams);
unsigned i;
for (i = 0; i < numInStreams; i++)
InStreamPointers.AddInReserved((ISequentialInStream *)InStreams[i]);
for (i = 0; i < numOutStreams; i++)
OutStreamPointers.AddInReserved((ISequentialOutStream *)OutStreams[i]);
// we suppose that UnpackSizePointer and PackSizePointers contain correct pointers.
/*
if (UnpackSizePointer)
UnpackSizePointer = &UnpackSize;
for (i = 0; i < NumStreams; i++)
if (PackSizePointers[i])
PackSizePointers[i] = &PackSizes[i];
*/
if (Coder)
Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0],
EncodeMode ? UnpackSizePointer : PackSizePointers[0],
EncodeMode ? PackSizePointers[0] : UnpackSizePointer,
progress);
else
Result = Coder2->Code(
&InStreamPointers.Front(), EncodeMode ? &UnpackSizePointer : &PackSizePointers.Front(), numInStreams,
&OutStreamPointers.Front(), EncodeMode ? &PackSizePointers.Front(): &UnpackSizePointer, numOutStreams,
progress);
InStreamPointers.Clear();
OutStreamPointers.Clear();
for (i = 0; i < InStreams.Size(); i++)
InStreams[i].Release();
for (i = 0; i < OutStreams.Size(); i++)
OutStreams[i].Release();
}
HRESULT CMixerMT::SetBindInfo(const CBindInfo &bindInfo)
{
CMixer::SetBindInfo(bindInfo);
_streamBinders.Clear();
FOR_VECTOR (i, _bi.Bonds)
{
RINOK(_streamBinders.AddNew().CreateEvents());
}
return S_OK;
}
void CMixerMT::AddCoder(ICompressCoder *coder, ICompressCoder2 *coder2, bool isFilter)
{
const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()];
CCoderMT &c2 = _coders.AddNew();
c2.NumStreams = c.NumStreams;
c2.EncodeMode = EncodeMode;
c2.Coder = coder;
c2.Coder2 = coder2;
IsFilter_Vector.Add(isFilter);
}
CCoder &CMixerMT::GetCoder(unsigned index)
{
return _coders[index];
}
void CMixerMT::ReInit()
{
FOR_VECTOR (i, _streamBinders)
_streamBinders[i].ReInit();
}
void CMixerMT::SelectMainCoder(bool useFirst)
{
unsigned ci = _bi.UnpackCoder;
if (!useFirst)
for (;;)
{
if (_coders[ci].NumStreams != 1)
break;
if (!IsFilter_Vector[ci])
break;
UInt32 st = _bi.Coder_to_Stream[ci];
if (_bi.IsStream_in_PackStreams(st))
break;
int bond = _bi.FindBond_for_PackStream(st);
if (bond < 0)
throw 20150213;
ci = _bi.Bonds[bond].UnpackIndex;
}
MainCoderIndex = ci;
}
HRESULT CMixerMT::Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams)
{
unsigned i;
for (i = 0; i < _coders.Size(); i++)
{
CCoderMT &coderInfo = _coders[i];
const CCoderStreamsInfo &csi = _bi.Coders[i];
UInt32 j;
unsigned numInStreams = EncodeMode ? 1 : csi.NumStreams;
unsigned numOutStreams = EncodeMode ? csi.NumStreams : 1;
coderInfo.InStreams.Clear();
for (j = 0; j < numInStreams; j++)
coderInfo.InStreams.AddNew();
coderInfo.OutStreams.Clear();
for (j = 0; j < numOutStreams; j++)
coderInfo.OutStreams.AddNew();
}
for (i = 0; i < _bi.Bonds.Size(); i++)
{
const CBond &bond = _bi.Bonds[i];
UInt32 inCoderIndex, inCoderStreamIndex;
UInt32 outCoderIndex, outCoderStreamIndex;
{
UInt32 coderIndex, coderStreamIndex;
_bi.GetCoder_for_Stream(bond.PackIndex, coderIndex, coderStreamIndex);
inCoderIndex = EncodeMode ? bond.UnpackIndex : coderIndex;
outCoderIndex = EncodeMode ? coderIndex : bond.UnpackIndex;
inCoderStreamIndex = EncodeMode ? 0 : coderStreamIndex;
outCoderStreamIndex = EncodeMode ? coderStreamIndex : 0;
}
_streamBinders[i].CreateStreams(
&_coders[inCoderIndex].InStreams[inCoderStreamIndex],
&_coders[outCoderIndex].OutStreams[outCoderStreamIndex]);
CMyComPtr<ICompressSetBufSize> inSetSize, outSetSize;
_coders[inCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&inSetSize);
_coders[outCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&outSetSize);
if (inSetSize && outSetSize)
{
const UInt32 kBufSize = 1 << 19;
inSetSize->SetInBufSize(inCoderStreamIndex, kBufSize);
outSetSize->SetOutBufSize(outCoderStreamIndex, kBufSize);
}
}
{
CCoderMT &cod = _coders[_bi.UnpackCoder];
if (EncodeMode)
cod.InStreams[0] = inStreams[0];
else
cod.OutStreams[0] = outStreams[0];
}
for (i = 0; i < _bi.PackStreams.Size(); i++)
{
UInt32 coderIndex, coderStreamIndex;
_bi.GetCoder_for_Stream(_bi.PackStreams[i], coderIndex, coderStreamIndex);
CCoderMT &cod = _coders[coderIndex];
if (EncodeMode)
cod.OutStreams[coderStreamIndex] = outStreams[i];
else
cod.InStreams[coderStreamIndex] = inStreams[i];
}
return S_OK;
}
HRESULT CMixerMT::ReturnIfError(HRESULT code)
{
FOR_VECTOR (i, _coders)
if (_coders[i].Result == code)
return code;
return S_OK;
}
HRESULT CMixerMT::Code(
ISequentialInStream * const *inStreams,
ISequentialOutStream * const *outStreams,
ICompressProgressInfo *progress)
{
Init(inStreams, outStreams);
unsigned i;
for (i = 0; i < _coders.Size(); i++)
if (i != MainCoderIndex)
{
RINOK(_coders[i].Create());
}
for (i = 0; i < _coders.Size(); i++)
if (i != MainCoderIndex)
_coders[i].Start();
_coders[MainCoderIndex].Code(progress);
for (i = 0; i < _coders.Size(); i++)
if (i != MainCoderIndex)
_coders[i].WaitExecuteFinish();
RINOK(ReturnIfError(E_ABORT));
RINOK(ReturnIfError(E_OUTOFMEMORY));
for (i = 0; i < _coders.Size(); i++)
{
HRESULT result = _coders[i].Result;
if (result != S_OK
&& result != k_My_HRESULT_WritingWasCut
&& result != S_FALSE
&& result != E_FAIL)
return result;
}
RINOK(ReturnIfError(S_FALSE));
for (i = 0; i < _coders.Size(); i++)
{
HRESULT result = _coders[i].Result;
if (result != S_OK && result != k_My_HRESULT_WritingWasCut)
return result;
}
return S_OK;
}
UInt64 CMixerMT::GetBondStreamSize(unsigned bondIndex) const
{
return _streamBinders[bondIndex].ProcessedSize;
}
}

View File

@@ -1,77 +0,0 @@
// CoderMixer2MT.h
#ifndef __CODER_MIXER2_MT_H
#define __CODER_MIXER2_MT_H
#include "../../../Common/MyCom.h"
#include "../../Common/StreamBinder.h"
#include "../../Common/VirtThread.h"
#include "CoderMixer2.h"
namespace NCoderMixer2 {
class CCoderMT: public CCoder, public CVirtThread
{
CLASS_NO_COPY(CCoderMT)
CRecordVector<ISequentialInStream*> InStreamPointers;
CRecordVector<ISequentialOutStream*> OutStreamPointers;
private:
void Execute();
public:
bool EncodeMode;
HRESULT Result;
CObjectVector< CMyComPtr<ISequentialInStream> > InStreams;
CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams;
CCoderMT(): EncodeMode(false) {}
~CCoderMT() { CVirtThread::WaitThreadFinish(); }
void Code(ICompressProgressInfo *progress);
};
class CMixerMT:
public IUnknown,
public CMixer,
public CMyUnknownImp
{
CObjectVector<CStreamBinder> _streamBinders;
HRESULT Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams);
HRESULT ReturnIfError(HRESULT code);
public:
CObjectVector<CCoderMT> _coders;
MY_UNKNOWN_IMP
virtual HRESULT SetBindInfo(const CBindInfo &bindInfo);
virtual void AddCoder(ICompressCoder *coder, ICompressCoder2 *coder2, bool isFilter);
virtual CCoder &GetCoder(unsigned index);
virtual void SelectMainCoder(bool useFirst);
virtual void ReInit();
virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes)
{ _coders[coderIndex].SetCoderInfo(unpackSize, packSizes); }
virtual HRESULT Code(
ISequentialInStream * const *inStreams,
ISequentialOutStream * const *outStreams,
ICompressProgressInfo *progress);
virtual UInt64 GetBondStreamSize(unsigned bondIndex) const;
CMixerMT(bool encodeMode): CMixer(encodeMode) {}
};
}
#endif

View File

@@ -1,562 +0,0 @@
// CoderMixer2ST.cpp
#include "StdAfx.h"
#include "CoderMixer2ST.h"
STDMETHODIMP CSequentialInStreamCalcSize::Read(void *data, UInt32 size, UInt32 *processedSize)
{
UInt32 realProcessed = 0;
HRESULT result = S_OK;
if (_stream)
result = _stream->Read(data, size, &realProcessed);
_size += realProcessed;
if (size != 0 && realProcessed == 0)
_wasFinished = true;
if (processedSize)
*processedSize = realProcessed;
return result;
}
STDMETHODIMP COutStreamCalcSize::Write(const void *data, UInt32 size, UInt32 *processedSize)
{
HRESULT result = S_OK;
if (_stream)
result = _stream->Write(data, size, &size);
_size += size;
if (processedSize)
*processedSize = size;
return result;
}
STDMETHODIMP COutStreamCalcSize::Flush()
{
HRESULT result = S_OK;
if (_stream)
{
CMyComPtr<IOutStreamFlush> outStreamFlush;
_stream.QueryInterface(IID_IOutStreamFlush, &outStreamFlush);
if (outStreamFlush)
result = outStreamFlush->Flush();;
}
return result;
}
namespace NCoderMixer2 {
CMixerST::CMixerST(bool encodeMode):
CMixer(encodeMode)
{}
CMixerST::~CMixerST() {}
void CMixerST::AddCoder(ICompressCoder *coder, ICompressCoder2 *coder2, bool isFilter)
{
IsFilter_Vector.Add(isFilter);
const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()];
CCoderST &c2 = _coders.AddNew();
c2.NumStreams = c.NumStreams;
c2.Coder = coder;
c2.Coder2 = coder2;
/*
if (isFilter)
{
c2.CanRead = true;
c2.CanWrite = true;
}
else
*/
{
IUnknown *unk = (coder ? (IUnknown *)coder : (IUnknown *)coder2);
{
CMyComPtr<ISequentialInStream> s;
unk->QueryInterface(IID_ISequentialInStream, (void**)&s);
c2.CanRead = (s != NULL);
}
{
CMyComPtr<ISequentialOutStream> s;
unk->QueryInterface(IID_ISequentialOutStream, (void**)&s);
c2.CanWrite = (s != NULL);
}
}
}
CCoder &CMixerST::GetCoder(unsigned index)
{
return _coders[index];
}
void CMixerST::ReInit() {}
HRESULT CMixerST::GetInStream2(
ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
UInt32 outStreamIndex, ISequentialInStream **inStreamRes)
{
UInt32 coderIndex = outStreamIndex, coderStreamIndex = 0;
if (EncodeMode)
{
_bi.GetCoder_for_Stream(outStreamIndex, coderIndex, coderStreamIndex);
if (coderStreamIndex != 0)
return E_NOTIMPL;
}
const CCoder &coder = _coders[coderIndex];
CMyComPtr<ISequentialInStream> seqInStream;
coder.QueryInterface(IID_ISequentialInStream, (void **)&seqInStream);
if (!seqInStream)
return E_NOTIMPL;
UInt32 numInStreams = EncodeMode ? 1 : coder.NumStreams;
UInt32 startIndex = EncodeMode ? coderIndex : _bi.Coder_to_Stream[coderIndex];
bool isSet = false;
if (numInStreams == 1)
{
CMyComPtr<ICompressSetInStream> setStream;
coder.QueryInterface(IID_ICompressSetInStream, (void **)&setStream);
if (setStream)
{
CMyComPtr<ISequentialInStream> seqInStream2;
RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + 0, &seqInStream2));
RINOK(setStream->SetInStream(seqInStream2));
isSet = true;
}
}
if (!isSet && numInStreams != 0)
{
CMyComPtr<ICompressSetInStream2> setStream2;
coder.QueryInterface(IID_ICompressSetInStream2, (void **)&setStream2);
if (!setStream2)
return E_NOTIMPL;
for (UInt32 i = 0; i < numInStreams; i++)
{
CMyComPtr<ISequentialInStream> seqInStream2;
RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + i, &seqInStream2));
RINOK(setStream2->SetInStream2(i, seqInStream2));
}
}
*inStreamRes = seqInStream.Detach();
return S_OK;
}
HRESULT CMixerST::GetInStream(
ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
UInt32 inStreamIndex, ISequentialInStream **inStreamRes)
{
CMyComPtr<ISequentialInStream> seqInStream;
{
int index = -1;
if (EncodeMode)
{
if (_bi.UnpackCoder == inStreamIndex)
index = 0;
}
else
index = _bi.FindStream_in_PackStreams(inStreamIndex);
if (index >= 0)
{
seqInStream = inStreams[index];
*inStreamRes = seqInStream.Detach();
return S_OK;
}
}
int bond = FindBond_for_Stream(
true, // forInputStream
inStreamIndex);
if (bond < 0)
return E_INVALIDARG;
RINOK(GetInStream2(inStreams, /* inSizes, */
_bi.Bonds[bond].Get_OutIndex(EncodeMode), &seqInStream));
while (_binderStreams.Size() <= (unsigned)bond)
_binderStreams.AddNew();
CStBinderStream &bs = _binderStreams[bond];
if (bs.StreamRef || bs.InStreamSpec)
return E_NOTIMPL;
CSequentialInStreamCalcSize *spec = new CSequentialInStreamCalcSize;
bs.StreamRef = spec;
bs.InStreamSpec = spec;
spec->SetStream(seqInStream);
spec->Init();
seqInStream = bs.InStreamSpec;
*inStreamRes = seqInStream.Detach();
return S_OK;
}
HRESULT CMixerST::GetOutStream(
ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */
UInt32 outStreamIndex, ISequentialOutStream **outStreamRes)
{
CMyComPtr<ISequentialOutStream> seqOutStream;
{
int index = -1;
if (!EncodeMode)
{
if (_bi.UnpackCoder == outStreamIndex)
index = 0;
}
else
index = _bi.FindStream_in_PackStreams(outStreamIndex);
if (index >= 0)
{
seqOutStream = outStreams[index];
*outStreamRes = seqOutStream.Detach();
return S_OK;
}
}
int bond = FindBond_for_Stream(
false, // forInputStream
outStreamIndex);
if (bond < 0)
return E_INVALIDARG;
UInt32 inStreamIndex = _bi.Bonds[bond].Get_InIndex(EncodeMode);
UInt32 coderIndex = inStreamIndex;
UInt32 coderStreamIndex = 0;
if (!EncodeMode)
_bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex);
CCoder &coder = _coders[coderIndex];
/*
if (!coder.Coder)
return E_NOTIMPL;
*/
coder.QueryInterface(IID_ISequentialOutStream, (void **)&seqOutStream);
if (!seqOutStream)
return E_NOTIMPL;
UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1;
UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex;
bool isSet = false;
if (numOutStreams == 1)
{
CMyComPtr<ICompressSetOutStream> setOutStream;
coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream);
if (setOutStream)
{
CMyComPtr<ISequentialOutStream> seqOutStream2;
RINOK(GetOutStream(outStreams, /* outSizes, */ startIndex + 0, &seqOutStream2));
RINOK(setOutStream->SetOutStream(seqOutStream2));
isSet = true;
}
}
if (!isSet && numOutStreams != 0)
{
// return E_NOTIMPL;
// /*
CMyComPtr<ICompressSetOutStream2> setStream2;
coder.QueryInterface(IID_ICompressSetOutStream2, (void **)&setStream2);
if (!setStream2)
return E_NOTIMPL;
for (UInt32 i = 0; i < numOutStreams; i++)
{
CMyComPtr<ISequentialOutStream> seqOutStream2;
RINOK(GetOutStream(outStreams, startIndex + i, &seqOutStream2));
RINOK(setStream2->SetOutStream2(i, seqOutStream2));
}
// */
}
while (_binderStreams.Size() <= (unsigned)bond)
_binderStreams.AddNew();
CStBinderStream &bs = _binderStreams[bond];
if (bs.StreamRef || bs.OutStreamSpec)
return E_NOTIMPL;
COutStreamCalcSize *spec = new COutStreamCalcSize;
bs.StreamRef = (ISequentialOutStream *)spec;
bs.OutStreamSpec = spec;
spec->SetStream(seqOutStream);
spec->Init();
seqOutStream = bs.OutStreamSpec;
*outStreamRes = seqOutStream.Detach();
return S_OK;
}
static HRESULT GetError(HRESULT res, HRESULT res2)
{
if (res == res2)
return res;
if (res == S_OK)
return res2;
if (res == k_My_HRESULT_WritingWasCut)
{
if (res2 != S_OK)
return res2;
}
return res;
}
HRESULT CMixerST::FlushStream(UInt32 streamIndex)
{
{
int index = -1;
if (!EncodeMode)
{
if (_bi.UnpackCoder == streamIndex)
index = 0;
}
else
index = _bi.FindStream_in_PackStreams(streamIndex);
if (index >= 0)
return S_OK;
}
int bond = FindBond_for_Stream(
false, // forInputStream
streamIndex);
if (bond < 0)
return E_INVALIDARG;
UInt32 inStreamIndex = _bi.Bonds[bond].Get_InIndex(EncodeMode);
UInt32 coderIndex = inStreamIndex;
UInt32 coderStreamIndex = 0;
if (!EncodeMode)
_bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex);
CCoder &coder = _coders[coderIndex];
CMyComPtr<IOutStreamFlush> flush;
coder.QueryInterface(IID_IOutStreamFlush, (void **)&flush);
HRESULT res = S_OK;
if (flush)
{
res = flush->Flush();
}
return GetError(res, FlushCoder(coderIndex));
}
HRESULT CMixerST::FlushCoder(UInt32 coderIndex)
{
CCoder &coder = _coders[coderIndex];
UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1;
UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex;
HRESULT res = S_OK;
for (unsigned i = 0; i < numOutStreams; i++)
res = GetError(res, FlushStream(startIndex + i));
return res;
}
void CMixerST::SelectMainCoder(bool useFirst)
{
unsigned ci = _bi.UnpackCoder;
int firstNonFilter = -1;
int firstAllowed = ci;
for (;;)
{
const CCoderST &coder = _coders[ci];
// break;
if (ci != _bi.UnpackCoder)
if (EncodeMode ? !coder.CanWrite : !coder.CanRead)
{
firstAllowed = ci;
firstNonFilter = -2;
}
if (coder.NumStreams != 1)
break;
UInt32 st = _bi.Coder_to_Stream[ci];
if (_bi.IsStream_in_PackStreams(st))
break;
int bond = _bi.FindBond_for_PackStream(st);
if (bond < 0)
throw 20150213;
if (EncodeMode ? !coder.CanRead : !coder.CanWrite)
break;
if (firstNonFilter == -1 && !IsFilter_Vector[ci])
firstNonFilter = ci;
ci = _bi.Bonds[bond].UnpackIndex;
}
ci = firstNonFilter;
if (firstNonFilter < 0 || useFirst)
ci = firstAllowed;
MainCoderIndex = ci;
}
HRESULT CMixerST::Code(
ISequentialInStream * const *inStreams,
ISequentialOutStream * const *outStreams,
ICompressProgressInfo *progress)
{
_binderStreams.Clear();
unsigned ci = MainCoderIndex;
const CCoder &mainCoder = _coders[MainCoderIndex];
CObjectVector< CMyComPtr<ISequentialInStream> > seqInStreams;
CObjectVector< CMyComPtr<ISequentialOutStream> > seqOutStreams;
UInt32 numInStreams = EncodeMode ? 1 : mainCoder.NumStreams;
UInt32 numOutStreams = !EncodeMode ? 1 : mainCoder.NumStreams;
UInt32 startInIndex = EncodeMode ? ci : _bi.Coder_to_Stream[ci];
UInt32 startOutIndex = !EncodeMode ? ci : _bi.Coder_to_Stream[ci];
UInt32 i;
for (i = 0; i < numInStreams; i++)
{
CMyComPtr<ISequentialInStream> seqInStream;
RINOK(GetInStream(inStreams, /* inSizes, */ startInIndex + i, &seqInStream));
seqInStreams.Add(seqInStream);
}
for (i = 0; i < numOutStreams; i++)
{
CMyComPtr<ISequentialOutStream> seqOutStream;
RINOK(GetOutStream(outStreams, /* outSizes, */ startOutIndex + i, &seqOutStream));
seqOutStreams.Add(seqOutStream);
}
CRecordVector< ISequentialInStream * > seqInStreamsSpec;
CRecordVector< ISequentialOutStream * > seqOutStreamsSpec;
for (i = 0; i < numInStreams; i++)
seqInStreamsSpec.Add(seqInStreams[i]);
for (i = 0; i < numOutStreams; i++)
seqOutStreamsSpec.Add(seqOutStreams[i]);
for (i = 0; i < _coders.Size(); i++)
{
if (i == ci)
continue;
CCoder &coder = _coders[i];
CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize);
if (setOutStreamSize)
{
RINOK(setOutStreamSize->SetOutStreamSize(
EncodeMode ? coder.PackSizePointers[0] : coder.UnpackSizePointer));
}
}
const UInt64 * const *isSizes2 = EncodeMode ? &mainCoder.UnpackSizePointer : &mainCoder.PackSizePointers.Front();
const UInt64 * const *outSizes2 = EncodeMode ? &mainCoder.PackSizePointers.Front() : &mainCoder.UnpackSizePointer;
HRESULT res;
if (mainCoder.Coder)
{
res = mainCoder.Coder->Code(
seqInStreamsSpec[0], seqOutStreamsSpec[0],
isSizes2[0], outSizes2[0],
progress);
}
else
{
res = mainCoder.Coder2->Code(
&seqInStreamsSpec.Front(), isSizes2, numInStreams,
&seqOutStreamsSpec.Front(), outSizes2, numOutStreams,
progress);
}
if (res == k_My_HRESULT_WritingWasCut)
res = S_OK;
if (res == S_OK || res == S_FALSE)
{
res = GetError(res, FlushCoder(ci));
}
for (i = 0; i < _binderStreams.Size(); i++)
{
const CStBinderStream &bs = _binderStreams[i];
if (bs.InStreamSpec)
bs.InStreamSpec->ReleaseStream();
else
bs.OutStreamSpec->ReleaseStream();
}
if (res == k_My_HRESULT_WritingWasCut)
res = S_OK;
return res;
}
HRESULT CMixerST::GetMainUnpackStream(
ISequentialInStream * const *inStreams,
ISequentialInStream **inStreamRes)
{
CMyComPtr<ISequentialInStream> seqInStream;
RINOK(GetInStream2(inStreams, /* inSizes, */
_bi.UnpackCoder, &seqInStream))
FOR_VECTOR (i, _coders)
{
CCoder &coder = _coders[i];
CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize);
if (setOutStreamSize)
{
RINOK(setOutStreamSize->SetOutStreamSize(coder.UnpackSizePointer));
}
}
*inStreamRes = seqInStream.Detach();
return S_OK;
}
UInt64 CMixerST::GetBondStreamSize(unsigned bondIndex) const
{
const CStBinderStream &bs = _binderStreams[bondIndex];
if (bs.InStreamSpec)
return bs.InStreamSpec->GetSize();
return bs.OutStreamSpec->GetSize();
}
}

View File

@@ -1,129 +0,0 @@
// CoderMixer2ST.h
#ifndef __CODER_MIXER2_ST_H
#define __CODER_MIXER2_ST_H
#include "../../../Common/MyCom.h"
#include "../../ICoder.h"
#include "CoderMixer2.h"
class CSequentialInStreamCalcSize:
public ISequentialInStream,
public CMyUnknownImp
{
public:
MY_UNKNOWN_IMP1(ISequentialInStream)
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
private:
CMyComPtr<ISequentialInStream> _stream;
UInt64 _size;
bool _wasFinished;
public:
void SetStream(ISequentialInStream *stream) { _stream = stream; }
void Init()
{
_size = 0;
_wasFinished = false;
}
void ReleaseStream() { _stream.Release(); }
UInt64 GetSize() const { return _size; }
bool WasFinished() const { return _wasFinished; }
};
class COutStreamCalcSize:
public ISequentialOutStream,
public IOutStreamFlush,
public CMyUnknownImp
{
CMyComPtr<ISequentialOutStream> _stream;
UInt64 _size;
public:
MY_UNKNOWN_IMP2(ISequentialOutStream, IOutStreamFlush)
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
STDMETHOD(Flush)();
void SetStream(ISequentialOutStream *stream) { _stream = stream; }
void ReleaseStream() { _stream.Release(); }
void Init() { _size = 0; }
UInt64 GetSize() const { return _size; }
};
namespace NCoderMixer2 {
struct CCoderST: public CCoder
{
bool CanRead;
bool CanWrite;
CCoderST(): CanRead(false), CanWrite(false) {}
};
struct CStBinderStream
{
CSequentialInStreamCalcSize *InStreamSpec;
COutStreamCalcSize *OutStreamSpec;
CMyComPtr<IUnknown> StreamRef;
CStBinderStream(): InStreamSpec(NULL), OutStreamSpec(NULL) {}
};
class CMixerST:
public IUnknown,
public CMixer,
public CMyUnknownImp
{
HRESULT GetInStream2(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
UInt32 outStreamIndex, ISequentialInStream **inStreamRes);
HRESULT GetInStream(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
UInt32 inStreamIndex, ISequentialInStream **inStreamRes);
HRESULT GetOutStream(ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */
UInt32 outStreamIndex, ISequentialOutStream **outStreamRes);
HRESULT FlushStream(UInt32 streamIndex);
HRESULT FlushCoder(UInt32 coderIndex);
public:
CObjectVector<CCoderST> _coders;
CObjectVector<CStBinderStream> _binderStreams;
MY_UNKNOWN_IMP
CMixerST(bool encodeMode);
~CMixerST();
virtual void AddCoder(ICompressCoder *coder, ICompressCoder2 *coder2, bool isFilter);
virtual CCoder &GetCoder(unsigned index);
virtual void SelectMainCoder(bool useFirst);
virtual void ReInit();
virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes)
{ _coders[coderIndex].SetCoderInfo(unpackSize, packSizes); }
virtual HRESULT Code(
ISequentialInStream * const *inStreams,
ISequentialOutStream * const *outStreams,
ICompressProgressInfo *progress);
virtual UInt64 GetBondStreamSize(unsigned bondIndex) const;
HRESULT GetMainUnpackStream(
ISequentialInStream * const *inStreams,
ISequentialInStream **inStreamRes);
};
}
#endif

View File

@@ -1,99 +0,0 @@
// CoderMixerMT.cpp
#include "StdAfx.h"
#include "CoderMixerMT.h"
namespace NCoderMixer {
void CCoder::Execute() { Code(NULL); }
void CCoder::Code(ICompressProgressInfo *progress)
{
Result = Coder->Code(InStream, OutStream,
InSizeAssigned ? &InSizeValue : NULL,
OutSizeAssigned ? &OutSizeValue : NULL,
progress);
InStream.Release();
OutStream.Release();
}
void CCoderMixerMT::AddCoder(ICompressCoder *coder)
{
_coders.Add(CCoder());
_coders.Back().Coder = coder;
}
void CCoderMixerMT::ReInit()
{
for(int i = 0; i < _coders.Size(); i++)
_coders[i].ReInit();
}
HRESULT CCoderMixerMT::ReturnIfError(HRESULT code)
{
for (int i = 0; i < _coders.Size(); i++)
if (_coders[i].Result == code)
return code;
return S_OK;
}
STDMETHODIMP CCoderMixerMT::Code(ISequentialInStream *inStream,
ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 * /* outSize */,
ICompressProgressInfo *progress)
{
_coders.Front().InStream = inStream;
int i;
_coders.Back().OutStream = outStream;
for (i = 0; i < _coders.Size(); i++)
if (i != _progressCoderIndex)
{
RINOK(_coders[i].Create());
}
_streamBinders.Clear();
for (i = 0; i + 1 < _coders.Size(); i++)
{
_streamBinders.Add(CStreamBinder());
CStreamBinder &sb = _streamBinders[i];
RINOK(sb.CreateEvents());
sb.CreateStreams(&_coders[i + 1].InStream, &_coders[i].OutStream);
}
for(i = 0; i < _streamBinders.Size(); i++)
_streamBinders[i].ReInit();
for (i = 0; i < _coders.Size(); i++)
if (i != _progressCoderIndex)
_coders[i].Start();
_coders[_progressCoderIndex].Code(progress);
for (i = 0; i < _coders.Size(); i++)
if (i != _progressCoderIndex)
_coders[i].WaitExecuteFinish();
RINOK(ReturnIfError(E_ABORT));
RINOK(ReturnIfError(E_OUTOFMEMORY));
for (i = 0; i < _coders.Size(); i++)
{
HRESULT result = _coders[i].Result;
if (result != S_OK && result != E_FAIL && result != S_FALSE)
return result;
}
RINOK(ReturnIfError(S_FALSE));
for (i = 0; i < _coders.Size(); i++)
{
HRESULT result = _coders[i].Result;
if (result != S_OK)
return result;
}
return S_OK;
}
}

View File

@@ -1,70 +0,0 @@
// CoderMixerMT.h
#ifndef __CODER_MIXER_MT_H
#define __CODER_MIXER_MT_H
#include "../../../Common/MyVector.h"
#include "../../../Common/MyCom.h"
#include "../../ICoder.h"
#include "../../Common/StreamBinder.h"
#include "../../Common/VirtThread.h"
#include "CoderMixer.h"
namespace NCoderMixer {
struct CCoder: public CCoderInfo, public CVirtThread
{
HRESULT Result;
virtual void Execute();
void Code(ICompressProgressInfo *progress);
virtual ~CCoder() { CVirtThread::WaitThreadFinish(); }
};
/*
for each coder
AddCoder()
SetProgressIndex(UInt32 coderIndex);
for each file
{
ReInit()
for each coder
SetCoderInfo
Code
}
*/
class CCoderMixerMT:
public ICompressCoder,
public CMyUnknownImp
{
CObjectVector<CStreamBinder> _streamBinders;
int _progressCoderIndex;
HRESULT ReturnIfError(HRESULT code);
public:
CObjectVector<CCoder> _coders;
MY_UNKNOWN_IMP
STDMETHOD(Code)(ISequentialInStream *inStream,
ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize,
ICompressProgressInfo *progress);
void AddCoder(ICompressCoder *coder);
void SetProgressCoderIndex(int coderIndex) { _progressCoderIndex = coderIndex; }
void ReInit();
void SetCoderInfo(UInt32 coderIndex, const UInt64 *inSize, const UInt64 *outSize)
{ _coders[coderIndex].SetCoderInfo(inSize, outSize); }
/*
UInt64 GetWriteProcessedSize(UInt32 binderIndex) const
{ return _streamBinders[binderIndex].ProcessedSize; }
*/
};
}
#endif

View File

@@ -2,6 +2,8 @@
#include "StdAfx.h"
#include <string.h>
#include "../../../Common/MyBuffer.h"
#include "../../Common/StreamUtils.h"

View File

@@ -1,7 +1,7 @@
// FindSignature.h
#ifndef __FINDSIGNATURE_H
#define __FINDSIGNATURE_H
#ifndef __FIND_SIGNATURE_H
#define __FIND_SIGNATURE_H
#include "../../IStream.h"

View File

@@ -2,6 +2,8 @@
#include "StdAfx.h"
#include "../../Common/MyWindows.h"
#include "../../Common/MyInitGuid.h"
#if defined(_7ZIP_LARGE_PAGES)

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

@@ -16,7 +16,7 @@
/* If NSIS_SCRIPT is defined, it will decompile NSIS script to [NSIS].nsi file.
The code is much larger in that case. */
#define NSIS_SCRIPT
// #define NSIS_SCRIPT
namespace NArchive {
namespace NNsis {

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,410 @@
// Rar5Handler.h
#ifndef __RAR5_HANDLER_H
#define __RAR5_HANDLER_H
#include "../../../../C/Blake2.h"
#include "../../../Common/MyBuffer.h"
#include "../../../Windows/PropVariant.h"
#include "../../Common/CreateCoder.h"
#include "../IArchive.h"
namespace NArchive {
namespace NRar5 {
namespace NHeaderFlags
{
const unsigned kExtra = 1 << 0;
const unsigned kData = 1 << 1;
// const unsigned kUnknown = 1 << 2;
const unsigned kPrevVol = 1 << 3;
const unsigned kNextVol = 1 << 4;
// const unsigned kIsChild = 1 << 5;
// const unsigned kPreserveChild = 1 << 6;
}
namespace NHeaderType
{
enum
{
kArc = 1,
kFile,
kService,
kArcEncrypt,
kEndOfArc
};
}
namespace NArcFlags
{
const unsigned kVol = 1 << 0;
const unsigned kVolNumber = 1 << 1;
const unsigned kSolid = 1 << 2;
// const unsigned kRecovery = 1 << 3;
// const unsigned kLocked = 1 << 4;
}
const unsigned kArcExtraRecordType_Locator = 1;
namespace NLocatorFlags
{
const unsigned kQuickOpen = 1 << 0;
const unsigned kRecovery = 1 << 1;
}
namespace NFileFlags
{
const unsigned kIsDir = 1 << 0;
const unsigned kUnixTime = 1 << 1;
const unsigned kCrc32 = 1 << 2;
const unsigned kUnknownSize = 1 << 3;
}
namespace NMethodFlags
{
// const unsigned kVersionMask = 0x3F;
const unsigned kSolid = 1 << 6;
}
namespace NArcEndFlags
{
const unsigned kMoreVols = 1 << 0;
}
enum EHostOS
{
kHost_Windows = 0,
kHost_Unix
};
// ---------- Extra ----------
namespace NExtraRecordType
{
enum
{
kCrypto = 1,
kHash,
kTime,
kVersion,
kLink,
kUnixOwner,
kSubdata
};
}
// const unsigned kCryptoAlgo_AES = 0;
namespace NCryptoFlags
{
const unsigned kPswCheck = 1 << 0;
const unsigned kUseMAC = 1 << 1;
}
struct CCryptoInfo
{
UInt64 Algo;
UInt64 Flags;
Byte Cnt;
bool UseMAC() const { return (Flags & NCryptoFlags::kUseMAC) != 0; }
bool IsThereCheck() const { return (Flags & NCryptoFlags::kPswCheck) != 0; }
bool Parse(const Byte *p, size_t size);
};
const unsigned kHashID_Blake2sp = 0;
namespace NTimeRecord
{
enum
{
k_Index_MTime = 0,
k_Index_CTime,
k_Index_ATime
};
namespace NFlags
{
const unsigned kUnixTime = 1 << 0;
const unsigned kMTime = 1 << 1;
// const unsigned kCTime = 1 << 2;
// const unsigned kATime = 1 << 3;
}
}
namespace NLinkType
{
enum
{
kUnixSymLink = 1,
kWinSymLink,
kWinJunction,
kHardLink,
kFileCopy
};
}
namespace NLinkFlags
{
const unsigned kTargetIsDir = 1 << 0;
}
struct CItem
{
UInt32 CommonFlags;
UInt32 Flags;
Byte RecordType;
bool Version_Defined;
int ACL;
AString Name;
int VolIndex;
int NextItem;
UInt32 UnixMTime;
UInt32 CRC;
UInt32 Attrib;
UInt32 Method;
CByteBuffer Extra;
UInt64 Size;
UInt64 PackSize;
UInt64 HostOS;
UInt64 DataPos;
UInt64 Version;
CItem() { Clear(); }
void Clear()
{
CommonFlags = 0;
Flags = 0;
VolIndex = 0;
NextItem = -1;
Version_Defined = false;
Version = 0;
Name.Empty();
Extra.Free();
ACL = -1;
}
bool IsSplitBefore() const { return (CommonFlags & NHeaderFlags::kPrevVol) != 0; }
bool IsSplitAfter() const { return (CommonFlags & NHeaderFlags::kNextVol) != 0; }
bool IsSplit() const { return (CommonFlags & (NHeaderFlags::kPrevVol | NHeaderFlags::kNextVol)) != 0; }
bool IsDir() const { return (Flags & NFileFlags::kIsDir) != 0; }
bool Has_UnixMTime() const { return (Flags & NFileFlags::kUnixTime) != 0; }
bool Has_CRC() const { return (Flags & NFileFlags::kCrc32) != 0; }
bool Is_UnknownSize() const { return (Flags & NFileFlags::kUnknownSize) != 0; }
bool IsNextForItem(const CItem &prev) const
{
return !IsDir() && !prev.IsDir() && IsSplitBefore() && prev.IsSplitAfter() && (Name == prev.Name);
// && false;
}
bool IsSolid() const { return ((UInt32)Method & NMethodFlags::kSolid) != 0; }
unsigned GetAlgoVersion() const { return (unsigned)Method & 0x3F; }
unsigned GetMethod() const { return ((unsigned)Method >> 7) & 0x7; }
UInt32 GetDictSize() const { return (((UInt32)Method >> 10) & 0xF); }
bool IsService() const { return RecordType == NHeaderType::kService; }
bool Is_STM() const { return IsService() && Name == "STM"; }
bool Is_CMT() const { return IsService() && Name == "CMT"; }
bool Is_ACL() const { return IsService() && Name == "ACL"; }
// bool Is_QO() const { return IsService() && Name == "QO"; }
int FindExtra(unsigned type, unsigned &recordDataSize) const;
bool IsEncrypted() const
{
unsigned size;
return FindExtra(NExtraRecordType::kCrypto, size) >= 0;
}
int FindExtra_Blake() const
{
unsigned size = 0;
int offset = FindExtra(NExtraRecordType::kHash, size);
if (offset >= 0
&& size == BLAKE2S_DIGEST_SIZE + 1
&& Extra[(unsigned)offset] == kHashID_Blake2sp)
return offset + 1;
return -1;
}
bool FindExtra_Version(UInt64 &version) const;
struct CLinkInfo
{
UInt64 Type;
UInt64 Flags;
unsigned NameOffset;
unsigned NameLen;
};
bool FindExtra_Link(CLinkInfo &link) const;
void Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const;
bool Is_CopyLink() const;
bool NeedUse_as_CopyLink() const { return PackSize == 0 && Is_CopyLink(); }
bool GetAltStreamName(AString &name) const;
UInt32 GetWinAttrib() const
{
UInt32 a;
switch (HostOS)
{
case kHost_Windows: a = Attrib; break;
case kHost_Unix: a = (Attrib << 16); break;
default: a = 0;
}
// if (IsDir()) a |= FILE_ATTRIBUTE_DIRECTORY;
return a;
}
UInt64 GetDataPosition() const { return DataPos; }
};
struct CInArcInfo
{
UInt64 Flags;
UInt64 VolNumber;
UInt64 StartPos;
UInt64 EndPos;
UInt64 EndFlags;
bool EndOfArchive_was_Read;
bool IsEncrypted;
// CByteBuffer Extra;
/*
struct CLocator
{
UInt64 Flags;
UInt64 QuickOpen;
UInt64 Recovery;
bool Is_QuickOpen() const { return (Flags & NLocatorFlags::kQuickOpen) != 0; }
bool Is_Recovery() const { return (Flags & NLocatorFlags::kRecovery) != 0; }
};
int FindExtra(unsigned type, unsigned &recordDataSize) const;
bool FindExtra_Locator(CLocator &locator) const;
*/
CInArcInfo():
Flags(0),
VolNumber(0),
StartPos(0),
EndPos(0),
EndFlags(0),
EndOfArchive_was_Read(false),
IsEncrypted(false)
{}
/*
void Clear()
{
Flags = 0;
VolNumber = 0;
StartPos = 0;
EndPos = 0;
EndFlags = 0;
EndOfArchive_was_Read = false;
Extra.Free();
}
*/
UInt64 GetPhySize() const { return EndPos - StartPos; }
bool AreMoreVolumes() const { return (EndFlags & NArcEndFlags::kMoreVols) != 0; }
bool IsVolume() const { return (Flags & NArcFlags::kVol) != 0; }
bool IsSolid() const { return (Flags & NArcFlags::kSolid) != 0; }
bool Is_VolNumber_Defined() const { return (Flags & NArcFlags::kVolNumber) != 0; }
UInt64 GetVolIndex() const { return Is_VolNumber_Defined() ? VolNumber : 0; }
};
struct CRefItem
{
unsigned Item;
unsigned Last;
int Parent;
int Link;
};
struct CArc
{
CMyComPtr<IInStream> Stream;
CInArcInfo Info;
};
class CHandler:
public IInArchive,
public IArchiveGetRawProps,
PUBLIC_ISetCompressCodecsInfo
public CMyUnknownImp
{
public:
CRecordVector<CRefItem> _refs;
CObjectVector<CItem> _items;
private:
CObjectVector<CArc> _arcs;
CObjectVector<CByteBuffer> _acls;
UInt32 _errorFlags;
// UInt32 _warningFlags;
bool _isArc;
CByteBuffer _comment;
DECL_EXTERNAL_CODECS_VARS
UInt64 GetPackSize(unsigned refIndex) const;
void FillLinks();
HRESULT Open2(IInStream *stream,
const UInt64 *maxCheckStartPosition,
IArchiveOpenCallback *openCallback);
public:
MY_QUERYINTERFACE_BEGIN2(IInArchive)
MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps)
QUERY_ENTRY_ISetCompressCodecsInfo
MY_QUERYINTERFACE_END
MY_ADDREF_RELEASE
INTERFACE_IInArchive(;)
INTERFACE_IArchiveGetRawProps(;)
DECL_ISetCompressCodecsInfo
};
}}
#endif

View File

@@ -30,6 +30,7 @@
#include "../Common/ItemNameUtils.h"
#include "../Common/OutStreamWithCRC.h"
#include "RarVol.h"
#include "RarHandler.h"
using namespace NWindows;
@@ -44,6 +45,8 @@ namespace NRar {
static const Byte kMarker[NHeader::kMarkerSize] = SIGNATURE;
const unsigned kPasswordLen_MAX = 127;
bool CItem::IgnoreItem() const
{
switch (HostOS)
@@ -131,7 +134,7 @@ class CInArchive
CByteBuffer _comment;
CByteBuffer m_FileHeaderData;
NHeader::NBlock::CBlock m_BlockHeader;
NCrypto::NRar29::CDecoder *m_RarAESSpec;
NCrypto::NRar3::CDecoder *m_RarAESSpec;
CMyComPtr<ICompressFilter> m_RarAES;
CBuffer<Byte> m_DecryptedData;
Byte *m_DecryptedDataAligned;
@@ -362,6 +365,7 @@ static int ReadTime(const Byte *p, unsigned size, Byte mask, CRarTime &rarTime)
_ttt_ .DosTime = Get32(p); p += 4; size -= 4; \
READ_TIME(_mask_, _ttt_); } \
bool CInArchive::ReadHeaderReal(const Byte *p, unsigned size, CItem &item)
{
const Byte *pStart = p;
@@ -500,7 +504,7 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass
}
if (!m_RarAES)
{
m_RarAESSpec = new NCrypto::NRar29::CDecoder;
m_RarAESSpec = new NCrypto::NRar3::CDecoder;
m_RarAES = m_RarAESSpec;
}
m_RarAESSpec->SetRar350Mode(ArcInfo.IsEncryptOld());
@@ -518,7 +522,10 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass
unsigned len = 0;
if (password)
len = MyStringLen(password);
CByteBuffer buffer(len * 2);
if (len > kPasswordLen_MAX)
len = kPasswordLen_MAX;
CByteArr buffer(len * 2);
for (unsigned i = 0; i < len; i++)
{
wchar_t c = password[i];
@@ -526,7 +533,7 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass
((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
}
RINOK(m_RarAESSpec->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size()));
m_RarAESSpec->SetPassword((const Byte *)buffer, len * 2);
const UInt32 kDecryptedBufferSize = (1 << 12);
if (m_DecryptedData.Size() == 0)
@@ -990,121 +997,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
COM_TRY_END
}
static bool IsDigit(wchar_t c)
{
return c >= L'0' && c <= L'9';
}
class CVolumeName
{
bool _first;
bool _newStyle;
UString _unchangedPart;
UString _changedPart;
UString _afterPart;
public:
CVolumeName(): _newStyle(true) {};
bool InitName(const UString &name, bool newStyle)
{
_first = true;
_newStyle = newStyle;
int dotPos = name.ReverseFind_Dot();
UString basePart = name;
if (dotPos >= 0)
{
UString ext = name.Ptr(dotPos + 1);
if (ext.IsEqualTo_Ascii_NoCase("rar"))
{
_afterPart = name.Ptr(dotPos);
basePart = name.Left(dotPos);
}
else if (ext.IsEqualTo_Ascii_NoCase("exe"))
{
_afterPart.SetFromAscii(".rar");
basePart = name.Left(dotPos);
}
else if (!_newStyle)
{
if (ext.IsEqualTo_Ascii_NoCase("000") ||
ext.IsEqualTo_Ascii_NoCase("001") ||
ext.IsEqualTo_Ascii_NoCase("r00") ||
ext.IsEqualTo_Ascii_NoCase("r01"))
{
_afterPart.Empty();
_first = false;
_changedPart = ext;
_unchangedPart = name.Left(dotPos + 1);
return true;
}
}
}
if (!_newStyle)
{
_afterPart.Empty();
_unchangedPart = basePart;
_unchangedPart += L'.';
_changedPart.SetFromAscii("r00");
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);
return true;
}
/*
void MakeBeforeFirstName()
{
unsigned len = _changedPart.Len();
_changedPart.Empty();
for (unsigned i = 0; i < len; i++)
_changedPart += L'0';
}
*/
UString GetNextName()
{
if (_newStyle || !_first)
{
unsigned i = _changedPart.Len();
for (;;)
{
wchar_t c = _changedPart[--i];
if (c == L'9')
{
c = L'0';
_changedPart.ReplaceOneCharAtPos(i, c);
if (i == 0)
{
_changedPart.InsertAtFront(L'1');
break;
}
continue;
}
c++;
_changedPart.ReplaceOneCharAtPos(i, c);
break;
}
}
_first = false;
return _unchangedPart + _changedPart + _afterPart;
}
};
static HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize)
HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize)
{
areThereNonZeros = false;
numZeros = 0;
@@ -1136,7 +1030,6 @@ HRESULT CHandler::Open2(IInStream *stream,
{
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openCallback;
CVolumeName seqName;
@@ -1145,8 +1038,8 @@ HRESULT CHandler::Open2(IInStream *stream,
if (openCallback)
{
openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
openCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
}
CInArchive archive;
@@ -1363,108 +1256,91 @@ struct CMethodItem
};
class CFolderInStream:
class CVolsInStream:
public ISequentialInStream,
public CMyUnknownImp
{
public:
MY_UNKNOWN_IMP
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
private:
const CObjectVector<CArc> *_archives;
UInt64 _rem;
ISequentialInStream *_stream;
const CObjectVector<CArc> *_arcs;
const CObjectVector<CItem> *_items;
CRefItem _refItem;
unsigned _curIndex;
UInt32 _crc;
bool _fileIsOpen;
CMyComPtr<ISequentialInStream> _stream;
bool _calcCrc;
HRESULT OpenStream();
HRESULT CloseStream();
public:
void Init(const CObjectVector<CArc> *archives,
const CObjectVector<CItem> *items,
const CRefItem &refItem);
MY_UNKNOWN_IMP
CRecordVector<UInt32> CRCs;
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
void Init(const CObjectVector<CArc> *arcs,
const CObjectVector<CItem> *items,
const CRefItem &refItem)
{
_arcs = arcs;
_items = items;
_refItem = refItem;
_curIndex = 0;
_stream = NULL;
CrcIsOK = true;
}
bool CrcIsOK;
};
ISequentialInStream* CArc::CreateLimitedStream(UInt64 offset, UInt64 size) const
{
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
CMyComPtr<ISequentialInStream> inStream(streamSpec);
Stream->Seek(offset, STREAM_SEEK_SET, NULL);
streamSpec->SetStream(Stream);
streamSpec->Init(size);
return inStream.Detach();
}
void CFolderInStream::Init(
const CObjectVector<CArc> *archives,
const CObjectVector<CItem> *items,
const CRefItem &refItem)
{
_archives = archives;
_items = items;
_refItem = refItem;
_curIndex = 0;
CRCs.Clear();
_fileIsOpen = false;
}
HRESULT CFolderInStream::OpenStream()
{
while (_curIndex < _refItem.NumItems)
{
const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex];
_stream.Attach((*_archives)[_refItem.VolumeIndex + _curIndex].
CreateLimitedStream(item.GetDataPosition(), item.PackSize));
_curIndex++;
_fileIsOpen = true;
_crc = CRC_INIT_VAL;
return S_OK;
}
return S_OK;
}
HRESULT CFolderInStream::CloseStream()
{
CRCs.Add(CRC_GET_DIGEST(_crc));
_stream.Release();
_fileIsOpen = false;
return S_OK;
}
STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
STDMETHODIMP CVolsInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
{
if (processedSize)
*processedSize = 0;
UInt32 realProcessedSize = 0;
while ((_curIndex < _refItem.NumItems || _fileIsOpen) && size > 0)
while (size != 0)
{
if (_fileIsOpen)
if (!_stream)
{
UInt32 localProcessedSize;
RINOK(_stream->Read(
((Byte *)data) + realProcessedSize, size, &localProcessedSize));
_crc = CrcUpdate(_crc, ((Byte *)data) + realProcessedSize, localProcessedSize);
if (localProcessedSize == 0)
{
RINOK(CloseStream());
continue;
}
realProcessedSize += localProcessedSize;
size -= localProcessedSize;
break;
if (_curIndex >= _refItem.NumItems)
break;
const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex];
IInStream *s = (*_arcs)[_refItem.VolumeIndex + _curIndex].Stream;
RINOK(s->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL));
_stream = s;
_calcCrc = (CrcIsOK && item.IsSplitAfter());
_crc = CRC_INIT_VAL;
_rem = item.PackSize;
}
else
{
RINOK(OpenStream());
UInt32 cur = size;
if (cur > _rem)
cur = (UInt32)_rem;
UInt32 num = cur;
HRESULT res = _stream->Read(data, cur, &cur);
if (_calcCrc)
_crc = CrcUpdate(_crc, data, cur);
realProcessedSize += cur;
if (processedSize)
*processedSize = realProcessedSize;
data = (Byte *)data + cur;
size -= cur;
_rem -= cur;
if (_rem == 0)
{
const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex];
_curIndex++;
if (_calcCrc && CRC_GET_DIGEST(_crc) != item.FileCRC)
CrcIsOK = false;
_stream = NULL;
}
if (res != S_OK)
return res;
if (realProcessedSize != 0)
return S_OK;
if (cur == 0 && num != 0)
return S_OK;
}
}
if (processedSize != 0)
*processedSize = realProcessedSize;
return S_OK;
}
@@ -1526,13 +1402,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CFilterCoder *filterStreamSpec = new CFilterCoder(false);
CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec;
NCrypto::NRar20::CDecoder *rar20CryptoDecoderSpec = NULL;
NCrypto::NRar2::CDecoder *rar20CryptoDecoderSpec = NULL;
CMyComPtr<ICompressFilter> rar20CryptoDecoder;
NCrypto::NRar29::CDecoder *rar29CryptoDecoderSpec = NULL;
CMyComPtr<ICompressFilter> rar29CryptoDecoder;
NCrypto::NRar3::CDecoder *rar3CryptoDecoderSpec = NULL;
CMyComPtr<ICompressFilter> rar3CryptoDecoder;
CFolderInStream *folderInStreamSpec = NULL;
CMyComPtr<ISequentialInStream> folderInStream;
CVolsInStream *volsInStreamSpec = NULL;
CMyComPtr<ISequentialInStream> volsInStream;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
@@ -1602,26 +1478,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
outStreamSpec->Init();
realOutStream.Release();
/*
for (unsigned partIndex = 0; partIndex < 1; partIndex++)
if (!volsInStream)
{
CMyComPtr<ISequentialInStream> inStream;
// item redefinition
const CItem &item = _items[refItem.ItemIndex + partIndex];
CInArchive &archive = _arcs[refItem.VolumeIndex + partIndex];
inStream.Attach(archive.CreateLimitedStream(item.GetDataPosition(),
item.PackSize));
*/
if (!folderInStream)
{
folderInStreamSpec = new CFolderInStream;
folderInStream = folderInStreamSpec;
volsInStreamSpec = new CVolsInStream;
volsInStream = volsInStreamSpec;
}
folderInStreamSpec->Init(&_arcs, &_items, refItem);
volsInStreamSpec->Init(&_arcs, &_items, refItem);
UInt64 packSize = currentPackSize;
@@ -1632,29 +1495,29 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (item.IsEncrypted())
{
CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
// CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
if (item.UnPackVersion >= 29)
{
if (!rar29CryptoDecoder)
if (!rar3CryptoDecoder)
{
rar29CryptoDecoderSpec = new NCrypto::NRar29::CDecoder;
rar29CryptoDecoder = rar29CryptoDecoderSpec;
rar3CryptoDecoderSpec = new NCrypto::NRar3::CDecoder;
rar3CryptoDecoder = rar3CryptoDecoderSpec;
}
rar29CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);
rar3CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);
/*
CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties;
RINOK(rar29CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2,
RINOK(rar3CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2,
&cryptoProperties));
*/
RINOK(rar29CryptoDecoderSpec->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0));
filterStreamSpec->Filter = rar29CryptoDecoder;
RINOK(rar3CryptoDecoderSpec->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0));
filterStreamSpec->Filter = rar3CryptoDecoder;
}
else if (item.UnPackVersion >= 20)
{
if (!rar20CryptoDecoder)
{
rar20CryptoDecoderSpec = new NCrypto::NRar20::CDecoder;
rar20CryptoDecoderSpec = new NCrypto::NRar2::CDecoder;
rar20CryptoDecoder = rar20CryptoDecoderSpec;
}
filterStreamSpec->Filter = rar20CryptoDecoder;
@@ -1666,49 +1529,66 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
continue;
}
RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword));
// RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword));
if (!getTextPassword)
extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
if (getTextPassword)
if (!getTextPassword)
{
outStream.Release();
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod));
continue;
}
// if (getTextPassword)
{
CMyComBSTR password;
RINOK(getTextPassword->CryptoGetTextPassword(&password));
if (item.UnPackVersion >= 29)
{
UString unicodePassword;
unsigned len = 0;
if (password)
len = MyStringLen(password);
CByteBuffer buffer(len * 2);
if (len > kPasswordLen_MAX)
len = kPasswordLen_MAX;
CByteArr buffer(len * 2);
for (unsigned i = 0; i < len; i++)
{
wchar_t c = password[i];
((Byte *)buffer)[i * 2] = (Byte)c;
((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
}
RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size()));
rar3CryptoDecoderSpec->SetPassword((const Byte *)buffer, len * 2);
}
else
{
AString oemPassword;
if (password)
oemPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len()));
{
UString unicode = (LPCOLESTR)password;
if (unicode.Len() > kPasswordLen_MAX)
unicode.DeleteFrom(kPasswordLen_MAX);
oemPassword = UnicodeStringToMultiByte(unicode, CP_OEMCP);
}
rar20CryptoDecoderSpec->SetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len());
}
}
/*
else
{
RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));
RINOK(cryptoSetPassword->CryptoSetPassword(NULL, 0));
}
*/
filterStreamSpec->SetInStream(folderInStream);
filterStreamSpec->SetInStream(volsInStream);
filterStreamSpec->SetOutStreamSize(NULL);
inStream = filterStream;
}
else
{
inStream = folderInStream;
inStream = volsInStream;
}
CMyComPtr<ICompressCoder> commonCoder;
@@ -1766,7 +1646,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Byte isSolid = (Byte)((IsSolid(index) || item.IsSplitBefore()) ? 1: 0);
if (solidStart)
{
isSolid = false;
isSolid = 0;
solidStart = false;
}
@@ -1786,46 +1666,25 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (item.IsEncrypted())
filterStreamSpec->ReleaseInStream();
if (result == S_FALSE)
{
outStream.Release();
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError));
continue;
}
if (result != S_OK)
return result;
const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
int opRes = (volsInStreamSpec->CrcIsOK && outStreamSpec->GetCRC() == lastItem.FileCRC) ?
NExtract::NOperationResult::kOK:
NExtract::NOperationResult::kCRCError;
outStream.Release();
/*
if (refItem.NumItems == 1 &&
!item.IsSplitBefore() && !item.IsSplitAfter())
*/
if (result != S_OK)
{
const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
bool crcOK = outStreamSpec->GetCRC() == lastItem.FileCRC;
outStream.Release();
RINOK(extractCallback->SetOperationResult(crcOK ?
NExtract::NOperationResult::kOK:
NExtract::NOperationResult::kCRCError));
if (result == S_FALSE)
opRes = NExtract::NOperationResult::kDataError;
else if (result == E_NOTIMPL)
opRes = NExtract::NOperationResult::kUnsupportedMethod;
else
return result;
}
/*
else
{
bool crcOK = true;
for (unsigned partIndex = 0; partIndex < refItem.NumItems; partIndex++)
{
const CItem &item = _items[refItem.ItemIndex + partIndex];
if (item.FileCRC != folderInStreamSpec->CRCs[partIndex])
{
crcOK = false;
break;
}
}
RINOK(extractCallback->SetOperationResult(crcOK ?
NExtract::NOperationResult::kOK:
NExtract::NOperationResult::kCRCError));
}
*/
RINOK(extractCallback->SetOperationResult(opRes));
}
return S_OK;
COM_TRY_END
}

View File

@@ -0,0 +1,129 @@
// RarVol.h
#ifndef __ARCHIVE_RAR_VOL_H
#define __ARCHIVE_RAR_VOL_H
#include "../../../Common/StringConvert.h"
#include "RarHeader.h"
namespace NArchive {
namespace NRar {
inline bool IsDigit(wchar_t c)
{
return c >= L'0' && c <= L'9';
}
class CVolumeName
{
bool _needChangeForNext;
UString _before;
UString _changed;
UString _after;
public:
CVolumeName(): _needChangeForNext(true) {};
bool InitName(const UString &name, bool newStyle = true)
{
_needChangeForNext = true;
_after.Empty();
UString base = name;
int dotPos = name.ReverseFind_Dot();
if (dotPos >= 0)
{
const UString ext = name.Ptr(dotPos + 1);
if (ext.IsEqualTo_Ascii_NoCase("rar"))
{
_after = name.Ptr(dotPos);
base.DeleteFrom(dotPos);
}
else if (ext.IsEqualTo_Ascii_NoCase("exe"))
{
_after.SetFromAscii(".rar");
base.DeleteFrom(dotPos);
}
else if (!newStyle)
{
if (ext.IsEqualTo_Ascii_NoCase("000") ||
ext.IsEqualTo_Ascii_NoCase("001") ||
ext.IsEqualTo_Ascii_NoCase("r00") ||
ext.IsEqualTo_Ascii_NoCase("r01"))
{
_changed = ext;
_before = name.Left(dotPos + 1);
return true;
}
}
}
if (newStyle)
{
unsigned i = base.Len();
for (; i != 0; i--)
if (!IsDigit(base[i - 1]))
break;
if (i != base.Len())
{
_before = base.Left(i);
_changed = base.Ptr(i);
return true;
}
}
_after.Empty();
_before = base;
_before += L'.';
_changed.SetFromAscii("r00");
_needChangeForNext = false;
return true;
}
/*
void MakeBeforeFirstName()
{
unsigned len = _changed.Len();
_changed.Empty();
for (unsigned i = 0; i < len; i++)
_changed += L'0';
}
*/
UString GetNextName()
{
if (_needChangeForNext)
{
unsigned i = _changed.Len();
if (i == 0)
return UString();
for (;;)
{
wchar_t c = _changed[--i];
if (c == L'9')
{
c = L'0';
_changed.ReplaceOneCharAtPos(i, c);
if (i == 0)
{
_changed.InsertAtFront(L'1');
break;
}
continue;
}
c++;
_changed.ReplaceOneCharAtPos(i, c);
break;
}
}
_needChangeForNext = true;
return _before + _changed + _after;
}
};
}}
#endif

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

@@ -29,11 +29,13 @@ HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID pro
{
NCOM::CPropVariant prop;
RINOK(callback->GetProperty(index, propId, &prop));
if (prop.vt == VT_BSTR)
{
UString s = prop.bstrVal;
if (convertSlash)
s = NItemName::MakeLegalName(s);
if (codePage == CP_UTF8)
{
ConvertUnicodeToUTF8(s, res);
@@ -44,9 +46,11 @@ HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID pro
}
else if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
return S_OK;
}
// sort old files with original order.
static int CompareUpdateItems(void *const *p1, void *const *p2, void *)
@@ -57,33 +61,39 @@ static int CompareUpdateItems(void *const *p1, void *const *p2, void *)
{
if (u2.NewProps)
return -1;
return MyCompare(u1.IndexInArchive, u2.IndexInArchive);
return MyCompare(u1.IndexInArc, u2.IndexInArc);
}
if (!u2.NewProps)
return 1;
return MyCompare(u1.IndexInClient, u2.IndexInClient);
}
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
IArchiveUpdateCallback *callback)
{
COM_TRY_BEGIN
if ((_stream && (_error != k_ErrorType_OK /* || _isSparse */)) || _seqStream)
return E_NOTIMPL;
CObjectVector<CUpdateItem> updateItems;
UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage);
for (UInt32 i = 0; i < numItems; i++)
{
CUpdateItem ui;
Int32 newData;
Int32 newProps;
UInt32 indexInArchive;
UInt32 indexInArc;
if (!callback)
return E_FAIL;
RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc));
ui.NewProps = IntToBool(newProps);
ui.NewData = IntToBool(newData);
ui.IndexInArchive = indexInArchive;
ui.IndexInArc = indexInArc;
ui.IndexInClient = i;
if (IntToBool(newProps))
@@ -109,6 +119,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
else
ui.Mode = prop.ulVal;
}
{
NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, kpidMTime, &prop));
@@ -119,6 +130,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
else
ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime);
}
RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, true));
if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/')
ui.Name += '/';
@@ -139,14 +151,18 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return E_INVALIDARG;
*/
}
updateItems.Add(ui);
}
if (_thereIsPaxExtendedHeader)
{
// we restore original order of files, if there is pax header block
updateItems.Sort(CompareUpdateItems, NULL);
}
return UpdateArchive(_stream, outStream, _items, updateItems, codePage, callback);
COM_TRY_END
}

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

@@ -43,7 +43,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
if (ui.NewData)
complexity += ui.Size;
else
complexity += inputItems[ui.IndexInArchive].GetFullSize();
complexity += inputItems[ui.IndexInArc].GetFullSize();
}
RINOK(updateCallback->SetTotal(complexity));
@@ -68,12 +68,14 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
const CUpdateItem &ui = updateItems[i];
CItem item;
if (ui.NewProps)
{
item.Mode = ui.Mode;
item.Name = ui.Name;
item.User = ui.User;
item.Group = ui.Group;
if (ui.IsDir)
{
item.LinkFlag = NFileHeader::NLinkFlag::kDirectory;
@@ -84,6 +86,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
item.LinkFlag = NFileHeader::NLinkFlag::kNormal;
item.PackSize = ui.Size;
}
item.MTime = ui.MTime;
item.DeviceMajorDefined = false;
item.DeviceMinorDefined = false;
@@ -92,7 +95,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
memcpy(item.Magic, NFileHeader::NMagic::kUsTar_00, 8);
}
else
item = inputItems[ui.IndexInArchive];
item = inputItems[ui.IndexInArc];
AString symLink;
if (ui.NewData || ui.NewProps)
@@ -116,6 +119,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
CMyComPtr<ISequentialInStream> fileInStream;
bool needWrite = true;
if (!symLink.IsEmpty())
{
item.PackSize = 0;
@@ -124,6 +128,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
else
{
HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
if (res == S_FALSE)
needWrite = false;
else
@@ -141,10 +146,17 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK)
{
item.PackSize = size2;
item.Size = size2;
item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);;
}
}
}
else
{
item.PackSize = 0;
item.Size = 0;
}
{
AString hardLink;
RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, codePage, true));
@@ -183,13 +195,15 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
RINOK(outArchive.FillDataResidual(item.PackSize));
}
}
complexity += item.PackSize;
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
}
else
{
const CItemEx &existItem = inputItems[ui.IndexInArchive];
const CItemEx &existItem = inputItems[ui.IndexInArc];
UInt64 size;
if (ui.NewProps)
{
// memcpy(item.Magic, NFileHeader::NMagic::kEmpty, 8);
@@ -225,12 +239,13 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL));
size = existItem.GetFullSize();
}
streamSpec->Init(size);
if (opCallback)
{
RINOK(opCallback->ReportOperation(
NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArchive,
NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc,
NUpdateNotifyOp::kReplicate))
}
@@ -242,6 +257,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
complexity += size;
}
}
lps->InSize = lps->OutSize = complexity;
RINOK(lps->SetCur());
return outArchive.WriteFinishHeader();

View File

@@ -4,6 +4,7 @@
#define __TAR_UPDATE_H
#include "../IArchive.h"
#include "TarItem.h"
namespace NArchive {
@@ -11,10 +12,10 @@ namespace NTar {
struct CUpdateItem
{
int IndexInArchive;
int IndexInArc;
int IndexInClient;
Int64 MTime;
UInt64 Size;
Int64 MTime;
UInt32 Mode;
bool NewData;
bool NewProps;
@@ -22,6 +23,8 @@ struct CUpdateItem
AString Name;
AString User;
AString Group;
CUpdateItem(): Size(0), IsDir(false) {}
};
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,

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
@@ -199,6 +210,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;
RINOK(callback->SetTotal(complexity));
{
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,8 +1647,9 @@ 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)
{
streams[index].RefCount++;
@@ -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,9 +436,9 @@ class CDatabase
public:
CRecordVector<CStreamInfo> DataStreams;
CRecordVector<CStreamInfo> MetaStreams;
CObjectVector<CSolid> Solids;
CRecordVector<CItem> Items;
CObjectVector<CByteBuffer> 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

@@ -358,15 +358,24 @@ HRESULT CHandler::Open2(IInStream *stream)
return S_FALSE;
UInt64 totalPackSize = 0;
unsigned numMainFiles = 0;
FOR_VECTOR(i, _files)
{
const CFile &file = _files[i];
file.UpdateTotalPackSize(totalPackSize);
if (file.Name == "Payload")
{
_mainSubfile = i;
numMainFiles++;
}
if (file.Name == "PackageInfo")
_is_pkg = true;
}
if (numMainFiles > 1)
_mainSubfile = -1;
_phySize = _dataStartPos + totalPackSize;
return S_OK;

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

@@ -207,7 +207,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
}
if (IntToBool(newData))
{
UInt64 size;
UInt64 size = 0;
if (!ui.IsDir)
{
NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, kpidSize, &prop));
@@ -219,6 +220,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
largestSizeDefined = true;
}
ui.Size = size;
// ui.Size -= ui.Size / 2;
}
updateItems.Add(ui);

View File

@@ -591,6 +591,29 @@ static bool FlagsAreSame(const CItem &i1, const CItem &i2)
return ((i1.Flags & mask) == (i2.Flags & mask));
}
// #ifdef _WIN32
static bool AreEqualPaths_IgnoreSlashes(const char *s1, const char *s2)
{
for (;;)
{
char c1 = *s1++;
char c2 = *s2++;
if (c1 == c2)
{
if (c1 == 0)
return true;
}
else
{
if (c1 == '\\') c1 = '/';
if (c2 == '\\') c2 = '/';
if (c1 != c2)
return false;
}
}
}
// #endif
static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem)
{
if (!FlagsAreSame(cdItem, localItem))
@@ -611,7 +634,30 @@ static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem)
return false;
*/
if (cdItem.Name != localItem.Name)
return false;
{
// #ifdef _WIN32
// some xap files use backslash in central dir items.
// we can ignore such errors in windows, where all slashes are converted to backslashes
unsigned hostOs = cdItem.GetHostOS();
if (hostOs == NFileHeader::NHostOS::kFAT ||
hostOs == NFileHeader::NHostOS::kNTFS)
{
if (!AreEqualPaths_IgnoreSlashes(cdItem.Name, localItem.Name))
{
// pkzip 2.50 uses DOS encoding in central dir and WIN encoding in local header.
// so we ignore that error
if (hostOs != NFileHeader::NHostOS::kFAT
|| cdItem.MadeByVersion.Version != 25)
return false;
}
}
/*
else
#endif
return false;
*/
}
return true;
}

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,
@@ -103,10 +104,12 @@ static void SetFileHeader(
item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir;
item.Method = kMethodForDirectory;
item.PackSize = 0;
item.Crc = 0; // test it
item.Size = 0;
item.Crc = 0;
}
}
static void SetItemInfoFromCompressingResult(const CCompressingResult &compressingResult,
bool isAesMode, Byte aesKeyMode, CItem &item)
{
@@ -133,6 +136,7 @@ static void SetItemInfoFromCompressingResult(const CCompressingResult &compressi
}
}
#ifndef _7ZIP_ST
static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo);
@@ -187,7 +191,6 @@ struct CThreadInfo
Thread.Wait();
Thread.Close();
}
};
void CThreadInfo::WaitAndCode()
@@ -389,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)
{
@@ -403,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;
@@ -428,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;
@@ -470,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;
@@ -507,6 +564,7 @@ static HRESULT Update2St(
lps->SendRatio = true;
lps->ProgressOffset += complexity;
}
items.Add(item);
lps->ProgressOffset += kLocalHeaderSize;
}
@@ -518,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)
@@ -566,6 +625,8 @@ static HRESULT Update2(
complexity++; // end of central
updateCallback->SetTotal(complexity);
UInt64 totalComplexity = complexity;
CAddCommon compressor(*options);
complexity = 0;
@@ -595,6 +656,7 @@ static HRESULT Update2(
mtMode = false;
Byte method = options->MethodSequence.Front();
if (!mtMode)
{
if (options2.MethodInfo.FindProp(NCoderPropID::kNumThreads) < 0)
@@ -642,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
@@ -690,8 +752,8 @@ static HRESULT Update2(
RINOK(threadInfo.CreateThread());
}
}
unsigned mtItemIndex = 0;
unsigned mtItemIndex = 0;
unsigned itemIndex = 0;
int lastRealStreamItemIndex = -1;
@@ -699,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)
@@ -718,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);
@@ -734,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));
}
@@ -759,6 +825,7 @@ static HRESULT Update2(
break;
}
}
continue;
}
@@ -772,6 +839,7 @@ static HRESULT Update2(
CItemEx itemEx;
CItemOut item;
if (!ui.NewProps || !ui.NewData)
{
itemEx = inputItems[ui.IndexInArc];
@@ -783,6 +851,7 @@ static HRESULT Update2(
if (ui.NewData)
{
bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir());
if (isDir)
{
WriteDirHeader(archive, options, ui, item);
@@ -798,6 +867,7 @@ static HRESULT Update2(
}
CMemBlocks2 &memRef = refs.Refs[itemIndex];
if (memRef.Defined)
{
CMyComPtr<IOutStream> outStream;
@@ -833,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;
@@ -843,6 +914,7 @@ static HRESULT Update2(
RINOK(threadInfo.Result);
threadIndices.Delete(t);
compressingCompletedEvents.Delete(t);
if (t == 0)
{
RINOK(threadInfo.OutStreamSpec->WriteToRealStream());
@@ -867,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);
@@ -1094,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

@@ -332,14 +332,6 @@ SOURCE=..\..\Archive\7z\7zUpdate.h
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\Archive\Common\CoderMixer.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\Common\CoderMixer.h
# End Source File
# Begin Source File
SOURCE=..\..\Archive\Common\CoderMixer2.cpp
# End Source File
# Begin Source File

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 \
@@ -141,6 +146,7 @@ NSIS_OBJS = \
RAR_OBJS = \
$O\RarHandler.obj \
$O\Rar5Handler.obj \
TAR_OBJS = \
$O\TarHandler.obj \
@@ -200,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 \
@@ -212,21 +218,25 @@ COMPRESS_OBJS = \
$O\Rar2Decoder.obj \
$O\Rar3Decoder.obj \
$O\Rar3Vm.obj \
$O\Rar5Decoder.obj \
$O\RarCodecsRegister.obj \
$O\ShrinkDecoder.obj \
$O\ZlibDecoder.obj \
$O\ZlibEncoder.obj \
$O\ZDecoder.obj \
$O\XPressDecoder.obj \
CRYPTO_OBJS = \
$O\7zAes.obj \
$O\7zAesRegister.obj \
$O\HmacSha1.obj \
$O\HmacSha256.obj \
$O\MyAes.obj \
$O\MyAesReg.obj \
$O\Pbkdf2HmacSha1.obj \
$O\RandGen.obj \
$O\Rar20Crypto.obj \
$O\Rar5Aes.obj \
$O\RarAes.obj \
$O\WzAes.obj \
$O\ZipCrypto.obj \
@@ -239,6 +249,7 @@ C_OBJS = \
$O\Alloc.obj \
$O\Bcj2.obj \
$O\Bcj2Enc.obj \
$O\Blake2s.obj \
$O\Bra.obj \
$O\Bra86.obj \
$O\BraIA64.obj \

View File

@@ -243,6 +243,10 @@ SOURCE=..\..\..\Common\CrcReg.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\Defs.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\DynamicBuffer.h
# End Source File
# Begin Source File
@@ -452,6 +456,24 @@ SOURCE=..\..\Compress\Rar3Vm.h
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Rar5Decoder.cpp
!IF "$(CFG)" == "7z - Win32 Release"
# ADD CPP /O2
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "7z - Win32 Debug"
!ENDIF
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Rar5Decoder.h
# End Source File
# Begin Source File
SOURCE=..\..\Compress\RarCodecsRegister.cpp
# End Source File
# End Group
@@ -734,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
@@ -771,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
@@ -779,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
@@ -821,6 +881,14 @@ SOURCE=..\..\Crypto\HmacSha1.h
# End Source File
# Begin Source File
SOURCE=..\..\Crypto\HmacSha256.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Crypto\HmacSha256.h
# End Source File
# Begin Source File
SOURCE=..\..\Crypto\MyAes.cpp
# End Source File
# Begin Source File
@@ -887,6 +955,14 @@ SOURCE=..\..\Crypto\Rar20Crypto.h
# End Source File
# Begin Source File
SOURCE=..\..\Crypto\Rar5Aes.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Crypto\Rar5Aes.h
# End Source File
# Begin Source File
SOURCE=..\..\Crypto\RarAes.cpp
# End Source File
# Begin Source File
@@ -1319,6 +1395,26 @@ SOURCE=..\..\..\..\C\Bcj2Enc.c
# End Source File
# Begin Source File
SOURCE=..\..\..\..\C\Blake2.h
# End Source File
# Begin Source File
SOURCE=..\..\..\..\C\Blake2s.c
!IF "$(CFG)" == "7z - Win32 Release"
# ADD CPP /O2
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "7z - Win32 Debug"
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=..\..\..\..\C\Bra.c
!IF "$(CFG)" == "7z - Win32 Release"
@@ -1874,6 +1970,14 @@ SOURCE=..\..\Archive\7z\7zUpdateItem.h
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\Archive\Rar\Rar5Handler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\Rar\Rar5Handler.h
# End Source File
# Begin Source File
SOURCE=..\..\Archive\Rar\RarHandler.cpp
# End Source File
# Begin Source File
@@ -1888,6 +1992,10 @@ SOURCE=..\..\Archive\Rar\RarHeader.h
SOURCE=..\..\Archive\Rar\RarItem.h
# End Source File
# Begin Source File
SOURCE=..\..\Archive\Rar\RarVol.h
# End Source File
# End Group
# Begin Group "Cab"
@@ -2331,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
@@ -2393,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
@@ -2413,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

@@ -12,7 +12,7 @@
#define MY_SET_BINARY_MODE(file)
#endif
// #include "../../../Common/MyWindows.h"
#include "../../../Common/MyWindows.h"
#include "../../../Common/MyInitGuid.h"
#include "../../../../C/7zVersion.h"

View File

@@ -2,6 +2,8 @@
#include "StdAfx.h"
#include "../../../Common/MyWindows.h"
#include "../../../Common/MyInitGuid.h"
#include "../../../Common/CommandLineParser.h"

View File

@@ -2,6 +2,8 @@
#include "StdAfx.h"
#include "../../../Common/MyWindows.h"
#include "../../../Common/MyInitGuid.h"
#include "../../../Common/CommandLineParser.h"

View File

@@ -2,6 +2,8 @@
#include "StdAfx.h"
#include "../../../Common/MyWindows.h"
#include <Shlwapi.h>
#include "../../../Common/MyInitGuid.h"

View File

@@ -19,7 +19,7 @@
struct CAlignedMidBuffer
{
#ifndef _WIN32
#ifdef _WIN32
Byte *_buf;

View File

@@ -2,6 +2,8 @@
#include "StdAfx.h"
#include <string.h>
#include "LimitedStreams.h"
#include "../../Common/Defs.h"

View File

@@ -2,6 +2,8 @@
#include "StdAfx.h"
#include "../../Common/MyWindows.h"
#include "../PropID.h"
// VARTYPE
@@ -101,5 +103,6 @@ const Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED] =
VT_UI8,
VT_UI8,
VT_BOOL,
VT_BSTR // kpidOutName
VT_BSTR,
VT_BSTR
};

View File

@@ -2,6 +2,8 @@
#include "StdAfx.h"
#include <string.h>
#include "UniqBlocks.h"
unsigned CUniqBlocks::AddUniq(const Byte *data, size_t size)

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

@@ -2,3 +2,5 @@ EXPORTS
CreateObject PRIVATE
GetNumberOfMethods PRIVATE
GetMethodProperty PRIVATE
CreateDecoder PRIVATE
CreateEncoder PRIVATE

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

@@ -130,14 +130,14 @@ CCoder::CCoder(bool deflate64Mode):
m_Values(0),
m_Tables(0)
{
{
CEncProps props;
SetProps(&props);
}
m_MatchMaxLen = deflate64Mode ? kMatchMaxLen64 : kMatchMaxLen32;
m_NumLenCombinations = deflate64Mode ? kNumLenSymbols64 : kNumLenSymbols32;
m_LenStart = deflate64Mode ? kLenStart64 : kLenStart32;
m_LenDirectBits = deflate64Mode ? kLenDirectBits64 : kLenDirectBits32;
{
CEncProps props;
SetProps(&props);
}
MatchFinder_Construct(&_lzInWindow);
}

View File

@@ -8,84 +8,250 @@
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()
{
unsigned lenCounts[kNumBitsMax + 1];
UInt32 tmpPositions[kNumBitsMax + 1];
unsigned i;
for (i = 1; i <= kNumBitsMax; i++)
lenCounts[i] = 0;
UInt32 symbol;
UInt32 lenCounts[kNumBitsMax + 1];
UInt32 tmpPoses[kNumBitsMax + 1];
for (symbol = 0; symbol < m_NumSymbols; symbol++)
{
unsigned len = lens[symbol];
if (len > kNumBitsMax)
return false;
lenCounts[len]++;
m_Symbols[symbol] = 0xFFFFFFFF;
}
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;
m_Positions[0] = m_Limits[0] = 0;
_poses[0] = 0;
_limits[0] = 0;
UInt32 startPos = 0;
UInt32 index = 0;
const UInt32 kMaxValue = (1 << kNumBitsMax);
const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
for (i = 1; i <= kNumBitsMax; i++)
{
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 value = bitStream->GetValue(kNumBitsMax);
if (value < m_Limits[kNumTableBits])
numBits = m_Lengths[value >> (kNumBitsMax - kNumTableBits)];
else
for (numBits = kNumTableBits + 1; value >= m_Limits[numBits]; numBits++);
bitStream->MovePos(numBits);
UInt32 index = m_Positions[numBits] +
((value - 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 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 kLevelSym_Same_NumBits = 1;
const unsigned kLevelSym_Same_Start = 4;
const unsigned kNumDictBits_Min = 15;
const unsigned kNumDictBits_Max = 21;
const UInt32 kDictSize_Max = (UInt32)1 << kNumDictBits_Max;
const unsigned kNumLinearPosSlotBits = 17;
const UInt32 kNumPowerPosSlots = 0x26;
const unsigned kNumPowerPosSlots = 38;
}}

Some files were not shown because too many files have changed in this diff Show More