Compare commits

...

9 Commits
9.11 ... 9.20

Author SHA1 Message Date
Igor Pavlov
de4f8c22fe 9.20 2016-05-28 00:16:05 +01:00
Igor Pavlov
b75af1bba6 9.19 2016-05-28 00:16:04 +01:00
Igor Pavlov
c65230d858 9.18 2016-05-28 00:16:04 +01:00
Igor Pavlov
2eb60a0598 9.17 2016-05-28 00:16:04 +01:00
Igor Pavlov
044e4bb741 9.16 2016-05-28 00:16:03 +01:00
Igor Pavlov
e279500d76 9.15 2016-05-28 00:16:03 +01:00
Igor Pavlov
708873490e 9.14 2016-05-28 00:16:03 +01:00
Igor Pavlov
3dacb5eb8a 9.13 2016-05-28 00:16:03 +01:00
Igor Pavlov
76b173af78 9.12 2016-05-28 00:16:02 +01:00
272 changed files with 8741 additions and 2726 deletions

View File

@@ -1,7 +1,6 @@
/* 7zAlloc.c -- Allocation functions /* 7zAlloc.c -- Allocation functions
2008-10-04 : Igor Pavlov : Public domain */ 2010-10-29 : Igor Pavlov : Public domain */
#include <stdlib.h>
#include "7zAlloc.h" #include "7zAlloc.h"
/* #define _SZ_ALLOC_DEBUG */ /* #define _SZ_ALLOC_DEBUG */

View File

@@ -1,14 +1,10 @@
/* 7zAlloc.h -- Allocation functions /* 7zAlloc.h -- Allocation functions
2009-02-07 : Igor Pavlov : Public domain */ 2010-10-29 : Igor Pavlov : Public domain */
#ifndef __7Z_ALLOC_H #ifndef __7Z_ALLOC_H
#define __7Z_ALLOC_H #define __7Z_ALLOC_H
#include <stddef.h> #include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
void *SzAlloc(void *p, size_t size); void *SzAlloc(void *p, size_t size);
void SzFree(void *p, void *address); void SzFree(void *p, void *address);
@@ -16,8 +12,4 @@ void SzFree(void *p, void *address);
void *SzAllocTemp(void *p, size_t size); void *SzAllocTemp(void *p, size_t size);
void SzFreeTemp(void *p, void *address); void SzFreeTemp(void *p, void *address);
#ifdef __cplusplus
}
#endif
#endif #endif

View File

@@ -1,5 +1,5 @@
/* 7zDec.c -- Decoding from 7z folder /* 7zDec.c -- Decoding from 7z folder
2010-03-15 : Igor Pavlov : Public domain */ 2010-11-02 : Igor Pavlov : Public domain */
#include <string.h> #include <string.h>
@@ -20,6 +20,10 @@
#define k_LZMA2 0x21 #define k_LZMA2 0x21
#define k_LZMA 0x30101 #define k_LZMA 0x30101
#define k_BCJ 0x03030103 #define k_BCJ 0x03030103
#define k_PPC 0x03030205
#define k_ARM 0x03030501
#define k_ARMT 0x03030701
#define k_SPARC 0x03030805
#define k_BCJ2 0x0303011B #define k_BCJ2 0x0303011B
#ifdef _7ZIP_PPMD_SUPPPORT #ifdef _7ZIP_PPMD_SUPPPORT
@@ -260,7 +264,6 @@ static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
IS_MAIN_METHOD((UInt32)c->MethodID); IS_MAIN_METHOD((UInt32)c->MethodID);
} }
#define IS_BCJ(c) ((c)->MethodID == k_BCJ && (c)->NumInStreams == 1 && (c)->NumOutStreams == 1)
#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1) #define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
static SRes CheckSupportedFolder(const CSzFolder *f) static SRes CheckSupportedFolder(const CSzFolder *f)
@@ -277,11 +280,24 @@ static SRes CheckSupportedFolder(const CSzFolder *f)
} }
if (f->NumCoders == 2) if (f->NumCoders == 2)
{ {
if (!IS_BCJ(&f->Coders[1]) || CSzCoderInfo *c = &f->Coders[1];
f->NumPackStreams != 1 || f->PackStreams[0] != 0 || if (c->MethodID > (UInt32)0xFFFFFFFF ||
c->NumInStreams != 1 ||
c->NumOutStreams != 1 ||
f->NumPackStreams != 1 ||
f->PackStreams[0] != 0 ||
f->NumBindPairs != 1 || f->NumBindPairs != 1 ||
f->BindPairs[0].InIndex != 1 || f->BindPairs[0].OutIndex != 0) f->BindPairs[0].InIndex != 1 ||
f->BindPairs[0].OutIndex != 0)
return SZ_ERROR_UNSUPPORTED; return SZ_ERROR_UNSUPPORTED;
switch ((UInt32)c->MethodID)
{
case k_BCJ:
case k_ARM:
break;
default:
return SZ_ERROR_UNSUPPORTED;
}
return SZ_OK; return SZ_OK;
} }
if (f->NumCoders == 4) if (f->NumCoders == 4)
@@ -314,6 +330,8 @@ static UInt64 GetSum(const UInt64 *values, UInt32 index)
return sum; return sum;
} }
#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
ILookInStream *inStream, UInt64 startPos, ILookInStream *inStream, UInt64 startPos,
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain, Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
@@ -391,14 +409,6 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
#endif #endif
} }
} }
else if (coder->MethodID == k_BCJ)
{
UInt32 state;
if (ci != 1)
return SZ_ERROR_UNSUPPORTED;
x86_Convert_Init(state);
x86_Convert(outBuffer, outSize, 0, &state, 0);
}
else if (coder->MethodID == k_BCJ2) else if (coder->MethodID == k_BCJ2)
{ {
UInt64 offset = GetSum(packSizes, 1); UInt64 offset = GetSum(packSizes, 1);
@@ -425,7 +435,23 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
RINOK(res) RINOK(res)
} }
else else
{
if (ci != 1)
return SZ_ERROR_UNSUPPORTED; return SZ_ERROR_UNSUPPORTED;
switch(coder->MethodID)
{
case k_BCJ:
{
UInt32 state;
x86_Convert_Init(state);
x86_Convert(outBuffer, outSize, 0, &state, 0);
break;
}
CASE_BRA_CONV(ARM)
default:
return SZ_ERROR_UNSUPPORTED;
}
}
} }
return SZ_OK; return SZ_OK;
} }

View File

@@ -1,5 +1,5 @@
/* 7zIn.c -- 7z Input functions /* 7zIn.c -- 7z Input functions
2010-03-11 : Igor Pavlov : Public domain */ 2010-10-29 : Igor Pavlov : Public domain */
#include <string.h> #include <string.h>
@@ -1218,12 +1218,16 @@ static SRes SzArEx_Open2(
ISzAlloc *allocTemp) ISzAlloc *allocTemp)
{ {
Byte header[k7zStartHeaderSize]; Byte header[k7zStartHeaderSize];
Int64 startArcPos;
UInt64 nextHeaderOffset, nextHeaderSize; UInt64 nextHeaderOffset, nextHeaderSize;
size_t nextHeaderSizeT; size_t nextHeaderSizeT;
UInt32 nextHeaderCRC; UInt32 nextHeaderCRC;
CBuf buffer; CBuf buffer;
SRes res; SRes res;
startArcPos = 0;
RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR));
RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE));
if (!TestSignatureCandidate(header)) if (!TestSignatureCandidate(header))
@@ -1235,7 +1239,7 @@ static SRes SzArEx_Open2(
nextHeaderSize = GetUi64(header + 20); nextHeaderSize = GetUi64(header + 20);
nextHeaderCRC = GetUi32(header + 28); nextHeaderCRC = GetUi32(header + 28);
p->startPosAfterHeader = k7zStartHeaderSize; p->startPosAfterHeader = startArcPos + k7zStartHeaderSize;
if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) if (CrcCalc(header + 12, 20) != GetUi32(header + 8))
return SZ_ERROR_CRC; return SZ_ERROR_CRC;
@@ -1252,13 +1256,13 @@ static SRes SzArEx_Open2(
{ {
Int64 pos = 0; Int64 pos = 0;
RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END));
if ((UInt64)pos < nextHeaderOffset || if ((UInt64)pos < startArcPos + nextHeaderOffset ||
(UInt64)pos < k7zStartHeaderSize + nextHeaderOffset || (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset ||
(UInt64)pos < k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)
return SZ_ERROR_INPUT_EOF; return SZ_ERROR_INPUT_EOF;
} }
RINOK(LookInStream_SeekTo(inStream, k7zStartHeaderSize + nextHeaderOffset)); RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset));
if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp)) if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp))
return SZ_ERROR_MEM; return SZ_ERROR_MEM;

View File

@@ -1,7 +1,7 @@
#define MY_VER_MAJOR 9 #define MY_VER_MAJOR 9
#define MY_VER_MINOR 11 #define MY_VER_MINOR 20
#define MY_VER_BUILD 0 #define MY_VER_BUILD 0
#define MY_VERSION "9.11 beta" #define MY_VERSION "9.20"
#define MY_DATE "2010-03-15" #define MY_DATE "2010-11-18"
#define MY_COPYRIGHT ": Igor Pavlov : Public domain" #define MY_COPYRIGHT ": Igor Pavlov : Public domain"
#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE #define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE

View File

@@ -1,5 +1,5 @@
/* Bra.c -- Converters for RISC code /* Bra.c -- Converters for RISC code
2008-10-04 : Igor Pavlov : Public domain */ 2010-04-16 : Igor Pavlov : Public domain */
#include "Bra.h" #include "Bra.h"
@@ -104,8 +104,8 @@ SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
size -= 4; size -= 4;
for (i = 0; i <= size; i += 4) for (i = 0; i <= size; i += 4)
{ {
if (data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00 || if ((data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00) ||
data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0) (data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0))
{ {
UInt32 src = UInt32 src =
((UInt32)data[i + 0] << 24) | ((UInt32)data[i + 0] << 24) |

View File

@@ -1,5 +1,5 @@
/* CpuArch.c -- CPU specific code /* CpuArch.c -- CPU specific code
2009-12-12: Igor Pavlov : Public domain */ 2010-10-26: Igor Pavlov : Public domain */
#include "CpuArch.h" #include "CpuArch.h"

View File

@@ -1,5 +1,5 @@
/* CpuArch.h -- CPU specific code /* CpuArch.h -- CPU specific code
2010-03-11: Igor Pavlov : Public domain */ 2010-10-26: Igor Pavlov : Public domain */
#ifndef __CPU_ARCH_H #ifndef __CPU_ARCH_H
#define __CPU_ARCH_H #define __CPU_ARCH_H
@@ -40,14 +40,26 @@ If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of pla
#define MY_CPU_ARM_LE #define MY_CPU_ARM_LE
#endif #endif
#if defined(_WIN32) && defined(_M_IA64)
#define MY_CPU_IA64_LE
#endif
#if defined(MY_CPU_X86_OR_AMD64) #if defined(MY_CPU_X86_OR_AMD64)
#define MY_CPU_LE_UNALIGN #define MY_CPU_LE_UNALIGN
#endif #endif
#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) #if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__)
#define MY_CPU_LE #define MY_CPU_LE
#endif #endif
#if defined(__BIG_ENDIAN__)
#define MY_CPU_BE
#endif
#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
Stop_Compiling_Bad_Endian
#endif
#ifdef MY_CPU_LE_UNALIGN #ifdef MY_CPU_LE_UNALIGN
#define GetUi16(p) (*(const UInt16 *)(p)) #define GetUi16(p) (*(const UInt16 *)(p))
@@ -55,6 +67,7 @@ If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of pla
#define GetUi64(p) (*(const UInt64 *)(p)) #define GetUi64(p) (*(const UInt64 *)(p))
#define SetUi16(p, d) *(UInt16 *)(p) = (d); #define SetUi16(p, d) *(UInt16 *)(p) = (d);
#define SetUi32(p, d) *(UInt32 *)(p) = (d); #define SetUi32(p, d) *(UInt32 *)(p) = (d);
#define SetUi64(p, d) *(UInt64 *)(p) = (d);
#else #else
@@ -78,6 +91,10 @@ If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of pla
((Byte *)(p))[2] = (Byte)(_x_ >> 16); \ ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \
((Byte *)(p))[3] = (Byte)(_x_ >> 24); } ((Byte *)(p))[3] = (Byte)(_x_ >> 24); }
#define SetUi64(p, d) { UInt64 _x64_ = (d); \
SetUi32(p, (UInt32)_x64_); \
SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); }
#endif #endif
#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300) #if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300)

View File

@@ -1,5 +1,5 @@
/* Lzma2Enc.c -- LZMA2 Encoder /* Lzma2Enc.c -- LZMA2 Encoder
2009-11-24 : Igor Pavlov : Public domain */ 2010-09-24 : Igor Pavlov : Public domain */
/* #include <stdio.h> */ /* #include <stdio.h> */
#include <string.h> #include <string.h>
@@ -141,7 +141,7 @@ static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf,
PRF(printf(" ")); PRF(printf(" "));
outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | (u >> 16) & 0x1F); outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F));
outBuf[destPos++] = (Byte)(u >> 8); outBuf[destPos++] = (Byte)(u >> 8);
outBuf[destPos++] = (Byte)u; outBuf[destPos++] = (Byte)u;
outBuf[destPos++] = (Byte)(pm >> 8); outBuf[destPos++] = (Byte)(pm >> 8);
@@ -173,6 +173,65 @@ void Lzma2EncProps_Init(CLzma2EncProps *p)
p->blockSize = 0; p->blockSize = 0;
} }
void Lzma2EncProps_Normalize(CLzma2EncProps *p)
{
int t1, t1n, t2, t3;
{
CLzmaEncProps lzmaProps = p->lzmaProps;
LzmaEncProps_Normalize(&lzmaProps);
t1n = lzmaProps.numThreads;
}
t1 = p->lzmaProps.numThreads;
t2 = p->numBlockThreads;
t3 = p->numTotalThreads;
if (t2 > NUM_MT_CODER_THREADS_MAX)
t2 = NUM_MT_CODER_THREADS_MAX;
if (t3 <= 0)
{
if (t2 <= 0)
t2 = 1;
t3 = t1n * t2;
}
else if (t2 <= 0)
{
t2 = t3 / t1n;
if (t2 == 0)
{
t1 = 1;
t2 = t3;
}
if (t2 > NUM_MT_CODER_THREADS_MAX)
t2 = NUM_MT_CODER_THREADS_MAX;
}
else if (t1 <= 0)
{
t1 = t3 / t2;
if (t1 == 0)
t1 = 1;
}
else
t3 = t1n * t2;
p->lzmaProps.numThreads = t1;
p->numBlockThreads = t2;
p->numTotalThreads = t3;
LzmaEncProps_Normalize(&p->lzmaProps);
if (p->blockSize == 0)
{
UInt32 dictSize = p->lzmaProps.dictSize;
UInt64 blockSize = (UInt64)dictSize << 2;
const UInt32 kMinSize = (UInt32)1 << 20;
const UInt32 kMaxSize = (UInt32)1 << 28;
if (blockSize < kMinSize) blockSize = kMinSize;
if (blockSize > kMaxSize) blockSize = kMaxSize;
if (blockSize < dictSize) blockSize = dictSize;
p->blockSize = (size_t)blockSize;
}
}
static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize)
{ {
@@ -181,9 +240,7 @@ static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize)
/* ---------- Lzma2 ---------- */ /* ---------- Lzma2 ---------- */
extern struct _CLzma2Enc; typedef struct
typedef struct _CLzma2Enc
{ {
Byte propEncoded; Byte propEncoded;
CLzma2EncProps props; CLzma2EncProps props;
@@ -212,7 +269,7 @@ static SRes Lzma2Enc_EncodeMt1(CLzma2EncInt *p, CLzma2Enc *mainEncoder,
if (mainEncoder->outBuf == 0) if (mainEncoder->outBuf == 0)
{ {
mainEncoder->outBuf = IAlloc_Alloc(mainEncoder->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); mainEncoder->outBuf = (Byte *)IAlloc_Alloc(mainEncoder->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX);
if (mainEncoder->outBuf == 0) if (mainEncoder->outBuf == 0)
return SZ_ERROR_MEM; return SZ_ERROR_MEM;
} }
@@ -351,70 +408,6 @@ void Lzma2Enc_Destroy(CLzma2EncHandle pp)
IAlloc_Free(p->alloc, pp); IAlloc_Free(p->alloc, pp);
} }
void Lzma2EncProps_Normalize(CLzma2EncProps *p)
{
int t1, t1n, t2, t3;
CLzmaEncProps lzmaProps = p->lzmaProps;
LzmaEncProps_Normalize(&lzmaProps);
t1 = p->lzmaProps.numThreads;
t1n = lzmaProps.numThreads;
t2 = p->numBlockThreads;
t3 = p->numTotalThreads;
#ifndef _7ZIP_ST
if (t2 > NUM_MT_CODER_THREADS_MAX)
t2 = NUM_MT_CODER_THREADS_MAX;
#else
t2 = 1;
#endif
if (t3 <= 0)
{
if (t2 <= 0)
t2 = 1;
t3 = t1n * t2;
}
else
{
if (t2 <= 0)
{
t2 = t3 / t1n;
if (t2 == 0)
{
t1 = 1;
t2 = t3;
}
}
else if (t1 <= 0)
{
t1 = t3 / t2;
if (t1 == 0)
t1 = 1;
}
else
t3 = t1n * t2;
}
p->lzmaProps.numThreads = t1;
p->numBlockThreads = t2;
p->numTotalThreads = t3;
LzmaEncProps_Normalize(&p->lzmaProps);
if (p->blockSize == 0)
{
UInt64 blockSize = (UInt64)lzmaProps.dictSize << 2;
const UInt32 kMinSize = (UInt32)1 << 20;
const UInt32 kMaxSize = (UInt32)1 << 28;
if (blockSize < kMinSize) blockSize = kMinSize;
if (blockSize > kMaxSize) blockSize = kMaxSize;
if (blockSize < lzmaProps.dictSize)
blockSize = lzmaProps.dictSize;
p->blockSize = (size_t)blockSize;
}
}
SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props) SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props)
{ {
CLzma2Enc *p = (CLzma2Enc *)pp; CLzma2Enc *p = (CLzma2Enc *)pp;

View File

@@ -1,5 +1,5 @@
/* LzmaEnc.c -- LZMA Encoder /* LzmaEnc.c -- LZMA Encoder
2009-11-24 : Igor Pavlov : Public domain */ 2010-04-16 : Igor Pavlov : Public domain */
#include <string.h> #include <string.h>
@@ -395,7 +395,7 @@ SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
LzmaEncProps_Normalize(&props); LzmaEncProps_Normalize(&props);
if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX ||
props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30)) props.dictSize > ((UInt32)1 << kDicLogSizeMaxCompress) || props.dictSize > ((UInt32)1 << 30))
return SZ_ERROR_PARAM; return SZ_ERROR_PARAM;
p->dictSize = props.dictSize; p->dictSize = props.dictSize;
p->matchFinderCycles = props.mc; p->matchFinderCycles = props.mc;

View File

@@ -1,5 +1,5 @@
/* MtCoder.c -- Multi-thread Coder /* MtCoder.c -- Multi-thread Coder
2009-03-26 : Igor Pavlov : Public domain */ 2010-09-24 : Igor Pavlov : Public domain */
#include <stdio.h> #include <stdio.h>
@@ -148,7 +148,7 @@ static void CMtThread_Destruct(CMtThread *p)
#define MY_BUF_ALLOC(buf, size, newSize) \ #define MY_BUF_ALLOC(buf, size, newSize) \
if (buf == 0 || size != newSize) \ if (buf == 0 || size != newSize) \
{ IAlloc_Free(p->mtCoder->alloc, buf); \ { IAlloc_Free(p->mtCoder->alloc, buf); \
size = newSize; buf = IAlloc_Alloc(p->mtCoder->alloc, size); \ size = newSize; buf = (Byte *)IAlloc_Alloc(p->mtCoder->alloc, size); \
if (buf == 0) return SZ_ERROR_MEM; } if (buf == 0) return SZ_ERROR_MEM; }
static SRes CMtThread_Prepare(CMtThread *p) static SRes CMtThread_Prepare(CMtThread *p)
@@ -306,7 +306,7 @@ SRes MtCoder_Code(CMtCoder *p)
for (i = 0; i < numThreads; i++) for (i = 0; i < numThreads; i++)
{ {
CMtThread *t = &p->threads[i]; CMtThread *t = &p->threads[i];
if (LoopThread_StartSubThread(&t->thread) != SZ_OK || i == 10) if (LoopThread_StartSubThread(&t->thread) != SZ_OK)
{ {
res = SZ_ERROR_THREAD; res = SZ_ERROR_THREAD;
p->threads[0].stopReading = True; p->threads[0].stopReading = True;

View File

@@ -1,5 +1,5 @@
/* Ppmd8.c -- PPMdI codec /* Ppmd8.c -- PPMdI codec
2010-03-15 : Igor Pavlov : Public domain 2010-03-24 : Igor Pavlov : Public domain
This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */ This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */
#include <memory.h> #include <memory.h>
@@ -410,6 +410,10 @@ static void Refresh(CPpmd8 *p, CTX_PTR ctx, unsigned oldNU, unsigned scale)
unsigned i = ctx->NumStats, escFreq, sumFreq, flags; unsigned i = ctx->NumStats, escFreq, sumFreq, flags;
CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1); CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1);
ctx->Stats = REF(s); ctx->Stats = REF(s);
#ifdef PPMD8_FREEZE_SUPPORT
/* fixed over Shkarin's code. Fixed code is not compatible with original code for some files in FREEZE mode. */
scale |= (ctx->SummFreq >= ((UInt32)1 << 15));
#endif
flags = (ctx->Flags & (0x10 + 0x04 * scale)) + 0x08 * (s->Symbol >= 0x40); flags = (ctx->Flags & (0x10 + 0x04 * scale)) + 0x08 * (s->Symbol >= 0x40);
escFreq = ctx->SummFreq - s->Freq; escFreq = ctx->SummFreq - s->Freq;
sumFreq = (s->Freq = (Byte)((s->Freq + scale) >> scale)); sumFreq = (s->Freq = (Byte)((s->Freq + scale) >> scale));

View File

@@ -1,5 +1,5 @@
/* Ppmd8.h -- PPMdI codec /* Ppmd8.h -- PPMdI codec
2010-03-12 : Igor Pavlov : Public domain 2010-03-24 : Igor Pavlov : Public domain
This code is based on: This code is based on:
PPMd var.I (2002): Dmitry Shkarin : Public domain PPMd var.I (2002): Dmitry Shkarin : Public domain
Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
@@ -35,8 +35,9 @@ typedef struct CPpmd8_Context_
#define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) #define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)
/* There is some bug in FREEZE mode (including original code, /* The BUG in Shkarin's code for FREEZE mode was fixed, but that fixed
so we disable FREEZE mode support */ code is not compatible with original code for some files compressed
in FREEZE mode. So we disable FREEZE mode support. */
enum enum
{ {

View File

@@ -1,5 +1,5 @@
/* Ppmd8Dec.c -- PPMdI Decoder /* Ppmd8Dec.c -- PPMdI Decoder
2010-03-12 : Igor Pavlov : Public domain 2010-04-16 : Igor Pavlov : Public domain
This code is based on: This code is based on:
PPMd var.I (2002): Dmitry Shkarin : Public domain PPMd var.I (2002): Dmitry Shkarin : Public domain
Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
@@ -33,7 +33,7 @@ static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size)
p->Range *= size; p->Range *= size;
while ((p->Low ^ (p->Low + p->Range)) < kTop || while ((p->Low ^ (p->Low + p->Range)) < kTop ||
p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1)) (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1)))
{ {
p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In); p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In);
p->Range <<= 8; p->Range <<= 8;

View File

@@ -1,5 +1,5 @@
/* Ppmd8Enc.c -- PPMdI Encoder /* Ppmd8Enc.c -- PPMdI Encoder
2010-03-12 : Igor Pavlov : Public domain 2010-04-16 : Igor Pavlov : Public domain
This code is based on: This code is based on:
PPMd var.I (2002): Dmitry Shkarin : Public domain PPMd var.I (2002): Dmitry Shkarin : Public domain
Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
@@ -19,7 +19,7 @@ void Ppmd8_RangeEnc_FlushData(CPpmd8 *p)
static void RangeEnc_Normalize(CPpmd8 *p) static void RangeEnc_Normalize(CPpmd8 *p)
{ {
while ((p->Low ^ (p->Low + p->Range)) < kTop || while ((p->Low ^ (p->Low + p->Range)) < kTop ||
p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1)) (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1)))
{ {
p->Stream.Out->Write(p->Stream.Out, (Byte)(p->Low >> 24)); p->Stream.Out->Write(p->Stream.Out, (Byte)(p->Low >> 24));
p->Range <<= 8; p->Range <<= 8;

View File

@@ -1,9 +1,9 @@
/* Crypto/Sha256.c -- SHA-256 Hash function /* Crypto/Sha256.c -- SHA-256 Hash
2008-11-06 : Igor Pavlov : Public domain 2010-06-11 : Igor Pavlov : Public domain
This code is based on public domain code from Wei Dai's Crypto++ library. */ This code is based on public domain code from Wei Dai's Crypto++ library. */
#include "Sha256.h"
#include "RotateDefs.h" #include "RotateDefs.h"
#include "Sha256.h"
/* define it for speed optimization */ /* define it for speed optimization */
/* #define _SHA256_UNROLL */ /* #define _SHA256_UNROLL */
@@ -71,7 +71,7 @@ void Sha256_Init(CSha256 *p)
#endif #endif
const UInt32 K[64] = { static const UInt32 K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,

View File

@@ -1,14 +1,12 @@
/* Sha256.h -- SHA-256 Hash /* Sha256.h -- SHA-256 Hash
2009-02-07 : Igor Pavlov : Public domain */ 2010-06-11 : Igor Pavlov : Public domain */
#ifndef __CRYPTO_SHA256_H #ifndef __CRYPTO_SHA256_H
#define __CRYPTO_SHA256_H #define __CRYPTO_SHA256_H
#include "Types.h" #include "Types.h"
#ifdef __cplusplus EXTERN_C_BEGIN
extern "C" {
#endif
#define SHA256_DIGEST_SIZE 32 #define SHA256_DIGEST_SIZE 32
@@ -23,8 +21,6 @@ void Sha256_Init(CSha256 *p);
void Sha256_Update(CSha256 *p, const Byte *data, size_t size); void Sha256_Update(CSha256 *p, const Byte *data, size_t size);
void Sha256_Final(CSha256 *p, Byte *digest); void Sha256_Final(CSha256 *p, Byte *digest);
#ifdef __cplusplus EXTERN_C_END
}
#endif
#endif #endif

View File

@@ -1,7 +1,5 @@
/* Sort.c -- Sort functions /* Sort.c -- Sort functions
2008-08-17 2010-09-17 : Igor Pavlov : Public domain */
Igor Pavlov
Public domain */
#include "Sort.h" #include "Sort.h"

View File

@@ -1,5 +1,5 @@
/* Types.h -- Basic types /* Types.h -- Basic types
2010-03-11 : Igor Pavlov : Public domain */ 2010-10-09 : Igor Pavlov : Public domain */
#ifndef __7Z_TYPES_H #ifndef __7Z_TYPES_H
#define __7Z_TYPES_H #define __7Z_TYPES_H
@@ -77,9 +77,11 @@ typedef unsigned long UInt64;
#if defined(_MSC_VER) || defined(__BORLANDC__) #if defined(_MSC_VER) || defined(__BORLANDC__)
typedef __int64 Int64; typedef __int64 Int64;
typedef unsigned __int64 UInt64; typedef unsigned __int64 UInt64;
#define UINT64_CONST(n) n
#else #else
typedef long long int Int64; typedef long long int Int64;
typedef unsigned long long int UInt64; typedef unsigned long long int UInt64;
#define UINT64_CONST(n) n ## ULL
#endif #endif
#endif #endif
@@ -231,6 +233,22 @@ typedef struct
#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) #define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
#define IAlloc_Free(p, a) (p)->Free((p), a) #define IAlloc_Free(p, a) (p)->Free((p), a)
#ifdef _WIN32
#define CHAR_PATH_SEPARATOR '\\'
#define WCHAR_PATH_SEPARATOR L'\\'
#define STRING_PATH_SEPARATOR "\\"
#define WSTRING_PATH_SEPARATOR L"\\"
#else
#define CHAR_PATH_SEPARATOR '/'
#define WCHAR_PATH_SEPARATOR L'/'
#define STRING_PATH_SEPARATOR "/"
#define WSTRING_PATH_SEPARATOR L"/"
#endif
EXTERN_C_END EXTERN_C_END
#endif #endif

View File

@@ -92,6 +92,14 @@ SOURCE=..\..\7z.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\..\7zAlloc.c
# End Source File
# Begin Source File
SOURCE=..\..\7zAlloc.h
# End Source File
# Begin Source File
SOURCE=..\..\7zBuf.c SOURCE=..\..\7zBuf.c
# End Source File # End Source File
# Begin Source File # Begin Source File
@@ -141,6 +149,10 @@ SOURCE=..\..\Bcj2.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\..\Bra.c
# End Source File
# Begin Source File
SOURCE=..\..\Bra.h SOURCE=..\..\Bra.h
# End Source File # End Source File
# Begin Source File # Begin Source File
@@ -196,14 +208,6 @@ SOURCE=..\..\Types.h
# End Group # End Group
# Begin Source File # Begin Source File
SOURCE=.\7zAlloc.c
# End Source File
# Begin Source File
SOURCE=.\7zAlloc.h
# End Source File
# Begin Source File
SOURCE=.\7zMain.c SOURCE=.\7zMain.c
# End Source File # End Source File
# End Target # End Target

View File

@@ -1,16 +1,15 @@
/* 7zMain.c - Test application for 7z Decoder /* 7zMain.c - Test application for 7z Decoder
2010-03-12 : Igor Pavlov : Public domain */ 2010-10-28 : Igor Pavlov : Public domain */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "../../7z.h" #include "../../7z.h"
#include "../../7zAlloc.h"
#include "../../7zCrc.h" #include "../../7zCrc.h"
#include "../../7zFile.h" #include "../../7zFile.h"
#include "../../7zVersion.h" #include "../../7zVersion.h"
#include "7zAlloc.h"
#ifndef USE_WINDOWS_FILE #ifndef USE_WINDOWS_FILE
/* for mkdir */ /* for mkdir */
#ifdef _WIN32 #ifdef _WIN32
@@ -21,12 +20,6 @@
#endif #endif
#endif #endif
#ifdef _WIN32
#define CHAR_PATH_SEPARATOR '\\'
#else
#define CHAR_PATH_SEPARATOR '/'
#endif
static ISzAlloc g_Alloc = { SzAlloc, SzFree }; static ISzAlloc g_Alloc = { SzAlloc, SzFree };
static int Buf_EnsureSize(CBuf *dest, size_t size) static int Buf_EnsureSize(CBuf *dest, size_t size)
@@ -104,7 +97,7 @@ static SRes Utf16_To_Utf8Buf(CBuf *dest, const UInt16 *src, size_t srcLen)
} }
#endif #endif
static WRes Utf16_To_Char(CBuf *buf, const UInt16 *s, int fileMode) static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s, int fileMode)
{ {
int len = 0; int len = 0;
for (len = 0; s[len] != '\0'; len++); for (len = 0; s[len] != '\0'; len++);
@@ -117,7 +110,14 @@ static WRes Utf16_To_Char(CBuf *buf, const UInt16 *s, int fileMode)
{ {
char defaultChar = '_'; char defaultChar = '_';
BOOL defUsed; BOOL defUsed;
int numChars = WideCharToMultiByte(fileMode ? (AreFileApisANSI() ? CP_ACP : CP_OEMCP) : CP_OEMCP, int numChars = WideCharToMultiByte(fileMode ?
(
#ifdef UNDER_CE
CP_ACP
#else
AreFileApisANSI() ? CP_ACP : CP_OEMCP
#endif
) : CP_OEMCP,
0, s, len, (char *)buf->data, size, &defaultChar, &defUsed); 0, s, len, (char *)buf->data, size, &defaultChar, &defUsed);
if (numChars == 0 || numChars >= size) if (numChars == 0 || numChars >= size)
return SZ_ERROR_FAIL; return SZ_ERROR_FAIL;
@@ -172,15 +172,16 @@ static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name)
#endif #endif
} }
static void PrintString(const UInt16 *s) static SRes PrintString(const UInt16 *s)
{ {
CBuf buf; CBuf buf;
SRes res;
Buf_Init(&buf); Buf_Init(&buf);
if (Utf16_To_Char(&buf, s, 0) == 0) res = Utf16_To_Char(&buf, s, 0);
{ if (res == SZ_OK)
printf("%s", buf.data); fputs((const char *)buf.data, stdout);
Buf_Free(&buf, &g_Alloc); Buf_Free(&buf, &g_Alloc);
} return res;
} }
static void UInt64ToStr(UInt64 value, char *s) static void UInt64ToStr(UInt64 value, char *s)
@@ -398,16 +399,21 @@ int MY_CDECL main(int numargs, char *args[])
} }
printf("%s %s %10s ", t, attr, s); printf("%s %s %10s ", t, attr, s);
PrintString(temp); res = PrintString(temp);
if (res != SZ_OK)
break;
if (f->IsDir) if (f->IsDir)
printf("/"); printf("/");
printf("\n"); printf("\n");
continue; continue;
} }
printf(testCommand ? fputs(testCommand ?
"Testing ": "Testing ":
"Extracting "); "Extracting ",
PrintString(temp); stdout);
res = PrintString(temp);
if (res != SZ_OK)
break;
if (f->IsDir) if (f->IsDir)
printf("/"); printf("/");
else else

View File

@@ -4,6 +4,7 @@ CFLAGS = $(CFLAGS) -D_7ZIP_PPMD_SUPPPORT
PROG = 7zDec.exe PROG = 7zDec.exe
C_OBJS = \ C_OBJS = \
$O\7zAlloc.obj \
$O\7zBuf.obj \ $O\7zBuf.obj \
$O\7zBuf2.obj \ $O\7zBuf2.obj \
$O\7zCrc.obj \ $O\7zCrc.obj \
@@ -13,6 +14,7 @@ C_OBJS = \
$O\7zIn.obj \ $O\7zIn.obj \
$O\7zStream.obj \ $O\7zStream.obj \
$O\Bcj2.obj \ $O\Bcj2.obj \
$O\Bra.obj \
$O\Bra86.obj \ $O\Bra86.obj \
$O\CpuArch.obj \ $O\CpuArch.obj \
$O\Lzma2Dec.obj \ $O\Lzma2Dec.obj \
@@ -21,7 +23,6 @@ C_OBJS = \
$O\Ppmd7Dec.obj \ $O\Ppmd7Dec.obj \
7Z_OBJS = \ 7Z_OBJS = \
$O\7zAlloc.obj \
$O\7zMain.obj \ $O\7zMain.obj \
OBJS = \ OBJS = \

View File

@@ -4,7 +4,7 @@ LIB =
RM = rm -f RM = rm -f
CFLAGS = -c -O2 -Wall CFLAGS = -c -O2 -Wall
OBJS = 7zMain.o 7zAlloc.o 7zBuf.o 7zBuf2.o 7zCrc.o 7zCrcOpt.o 7zDec.o 7zIn.o CpuArch.o LzmaDec.o Lzma2Dec.o Bra86.o Bcj2.o Ppmd7.o Ppmd7Dec.o 7zFile.o 7zStream.o OBJS = 7zMain.o 7zAlloc.o 7zBuf.o 7zBuf2.o 7zCrc.o 7zCrcOpt.o 7zDec.o 7zIn.o CpuArch.o LzmaDec.o Lzma2Dec.o Bra.o Bra86.o Bcj2.o Ppmd7.o Ppmd7Dec.o 7zFile.o 7zStream.o
all: $(PROG) all: $(PROG)
@@ -15,7 +15,7 @@ $(PROG): $(OBJS)
$(CXX) $(CFLAGS) 7zMain.c $(CXX) $(CFLAGS) 7zMain.c
7zAlloc.o: 7zAlloc.c 7zAlloc.o: 7zAlloc.c
$(CXX) $(CFLAGS) 7zAlloc.c $(CXX) $(CFLAGS) ../../7zAlloc.c
7zBuf.o: ../../7zBuf.c 7zBuf.o: ../../7zBuf.c
$(CXX) $(CFLAGS) ../../7zBuf.c $(CXX) $(CFLAGS) ../../7zBuf.c
@@ -44,6 +44,9 @@ LzmaDec.o: ../../LzmaDec.c
Lzma2Dec.o: ../../Lzma2Dec.c Lzma2Dec.o: ../../Lzma2Dec.c
$(CXX) $(CFLAGS) ../../Lzma2Dec.c $(CXX) $(CFLAGS) ../../Lzma2Dec.c
Bra.o: ../../Bra.c
$(CXX) $(CFLAGS) ../../Bra.c
Bra86.o: ../../Bra86.c Bra86.o: ../../Bra86.c
$(CXX) $(CFLAGS) ../../Bra86.c $(CXX) $(CFLAGS) ../../Bra86.c

View File

@@ -1,5 +1,5 @@
/* LzmaUtil.c -- Test application for LZMA compression /* LzmaUtil.c -- Test application for LZMA compression
2009-08-14 : Igor Pavlov : Public domain */ 2010-09-20 : Igor Pavlov : Public domain */
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
@@ -249,6 +249,6 @@ int MY_CDECL main(int numArgs, const char *args[])
{ {
char rs[800] = { 0 }; char rs[800] = { 0 };
int res = main2(numArgs, args, rs); int res = main2(numArgs, args, rs);
printf(rs); fputs(rs, stdout);
return res; return res;
} }

592
C/Util/SfxSetup/SfxSetup.c Executable file
View File

@@ -0,0 +1,592 @@
/* SfxSetup.c - 7z SFX Setup
2010-11-11 : Igor Pavlov : Public domain */
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#ifdef _CONSOLE
#include <stdio.h>
#endif
#include "../../7z.h"
#include "../../7zAlloc.h"
#include "../../7zCrc.h"
#include "../../7zFile.h"
#include "../../CpuArch.h"
#define k_EXE_ExtIndex 1
static const char *kExts[] =
{
"bat",
"exe",
"inf",
"msi",
#ifdef UNDER_CE
"cab",
#endif
"html",
"htm"
};
static const char *kNames[] =
{
"setup",
"install",
"run",
"start"
};
static unsigned FindExt(const wchar_t *s, unsigned *extLen)
{
unsigned len = (unsigned)wcslen(s);
unsigned i;
for (i = len; i > 0; i--)
{
if (s[i - 1] == '.')
{
*extLen = len - i;
return i - 1;
}
}
*extLen = 0;
return len;
}
#define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) -= 0x20 : (c)))
static unsigned FindItem(const char **items, unsigned num, const wchar_t *s, unsigned len)
{
unsigned i;
for (i = 0; i < num; i++)
{
const char *item = items[i];
unsigned itemLen = (unsigned)strlen(item);
unsigned j;
if (len != itemLen)
continue;
for (j = 0; j < len; j++)
{
unsigned c = item[j];
if (c != s[j] && MAKE_CHAR_UPPER(c) != s[j])
break;
}
if (j == len)
return i;
}
return i;
}
#ifdef _CONSOLE
static BOOL WINAPI HandlerRoutine(DWORD ctrlType)
{
ctrlType = ctrlType;
return TRUE;
}
#endif
static void PrintErrorMessage(const char *message)
{
#ifdef _CONSOLE
printf("\n7-Zip Error: %s\n", message);
#else
#ifdef UNDER_CE
WCHAR messageW[256 + 4];
unsigned i;
for (i = 0; i < 256 && message[i] != 0; i++)
messageW[i] = message[i];
messageW[i] = 0;
MessageBoxW(0, messageW, L"7-Zip Error", MB_ICONERROR);
#else
MessageBoxA(0, message, "7-Zip Error", MB_ICONERROR);
#endif
#endif
}
static WRes MyCreateDir(const WCHAR *name)
{
return CreateDirectoryW(name, NULL) ? 0 : GetLastError();
}
#ifdef UNDER_CE
#define kBufferSize (1 << 13)
#else
#define kBufferSize (1 << 15)
#endif
#define kSignatureSearchLimit (1 << 22)
static Bool FindSignature(CSzFile *stream, UInt64 *resPos)
{
Byte buf[kBufferSize];
size_t numPrevBytes = 0;
*resPos = 0;
for (;;)
{
size_t numTests, pos;
if (*resPos > kSignatureSearchLimit)
return False;
do
{
size_t processed = kBufferSize - numPrevBytes;
if (File_Read(stream, buf + numPrevBytes, &processed) != 0)
return False;
if (processed == 0)
return False;
numPrevBytes += processed;
}
while (numPrevBytes <= k7zStartHeaderSize);
numTests = numPrevBytes - k7zStartHeaderSize;
for (pos = 0; pos < numTests; pos++)
{
for (; buf[pos] != '7' && pos < numTests; pos++);
if (pos == numTests)
break;
if (memcmp(buf + pos, k7zSignature, k7zSignatureSize) == 0)
if (CrcCalc(buf + pos + 12, 20) == GetUi32(buf + pos + 8))
{
*resPos += pos;
return True;
}
}
*resPos += numTests;
numPrevBytes -= numTests;
memmove(buf, buf + numTests, numPrevBytes);
}
}
static Bool DoesFileOrDirExist(const WCHAR *path)
{
WIN32_FIND_DATAW fd;
HANDLE handle;
handle = FindFirstFileW(path, &fd);
if (handle == INVALID_HANDLE_VALUE)
return False;
FindClose(handle);
return True;
}
static WRes RemoveDirWithSubItems(WCHAR *path)
{
WIN32_FIND_DATAW fd;
HANDLE handle;
WRes res = 0;
size_t len = wcslen(path);
wcscpy(path + len, L"*");
handle = FindFirstFileW(path, &fd);
path[len] = L'\0';
if (handle == INVALID_HANDLE_VALUE)
return GetLastError();
for (;;)
{
if (wcscmp(fd.cFileName, L".") != 0 &&
wcscmp(fd.cFileName, L"..") != 0)
{
wcscpy(path + len, fd.cFileName);
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
wcscat(path, L"\\");
res = RemoveDirWithSubItems(path);
}
else
{
SetFileAttributesW(path, 0);
if (DeleteFileW(path) == 0)
res = GetLastError();
}
if (res != 0)
break;
}
if (!FindNextFileW(handle, &fd))
{
res = GetLastError();
if (res == ERROR_NO_MORE_FILES)
res = 0;
break;
}
}
path[len] = L'\0';
FindClose(handle);
if (res == 0)
{
if (!RemoveDirectoryW(path))
res = GetLastError();
}
return res;
}
#ifdef _CONSOLE
int MY_CDECL main()
#else
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
#ifdef UNDER_CE
LPWSTR
#else
LPSTR
#endif
lpCmdLine, int nCmdShow)
#endif
{
CFileInStream archiveStream;
CLookToRead lookStream;
CSzArEx db;
SRes res = SZ_OK;
ISzAlloc allocImp;
ISzAlloc allocTempImp;
WCHAR sfxPath[MAX_PATH + 2];
WCHAR path[MAX_PATH * 3 + 2];
size_t pathLen;
DWORD winRes;
const wchar_t *cmdLineParams;
const char *errorMessage = NULL;
Bool useShellExecute = True;
#ifdef _CONSOLE
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
#else
hInstance = hInstance;
hPrevInstance = hPrevInstance;
lpCmdLine = lpCmdLine;
nCmdShow = nCmdShow;
#endif
CrcGenerateTable();
allocImp.Alloc = SzAlloc;
allocImp.Free = SzFree;
allocTempImp.Alloc = SzAllocTemp;
allocTempImp.Free = SzFreeTemp;
FileInStream_CreateVTable(&archiveStream);
LookToRead_CreateVTable(&lookStream, False);
winRes = GetModuleFileNameW(NULL, sfxPath, MAX_PATH);
if (winRes == 0 || winRes > MAX_PATH)
return 1;
{
cmdLineParams = GetCommandLineW();
#ifndef UNDER_CE
{
Bool quoteMode = False;
for (;; cmdLineParams++)
{
wchar_t c = *cmdLineParams;
if (c == L'\"')
quoteMode = !quoteMode;
else if (c == 0 || (c == L' ' && !quoteMode))
break;
}
}
#endif
}
{
unsigned i;
DWORD d;
winRes = GetTempPathW(MAX_PATH, path);
if (winRes == 0 || winRes > MAX_PATH)
return 1;
pathLen = wcslen(path);
d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId();
for (i = 0;; i++, d += GetTickCount())
{
if (i >= 100)
{
res = SZ_ERROR_FAIL;
break;
}
wcscpy(path + pathLen, L"7z");
{
wchar_t *s = path + wcslen(path);
UInt32 value = d;
unsigned k;
for (k = 0; k < 8; k++)
{
unsigned t = value & 0xF;
value >>= 4;
s[7 - k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
}
s[k] = '\0';
}
if (DoesFileOrDirExist(path))
continue;
if (CreateDirectoryW(path, NULL))
{
wcscat(path, L"\\");
pathLen = wcslen(path);
break;
}
if (GetLastError() != ERROR_ALREADY_EXISTS)
{
res = SZ_ERROR_FAIL;
break;
}
}
if (res != SZ_OK)
errorMessage = "Can't create temp folder";
}
if (res != SZ_OK)
{
if (!errorMessage)
errorMessage = "Error";
PrintErrorMessage(errorMessage);
return 1;
}
if (InFile_OpenW(&archiveStream.file, sfxPath) != 0)
{
errorMessage = "can not open input file";
res = SZ_ERROR_FAIL;
}
else
{
UInt64 pos = 0;
if (!FindSignature(&archiveStream.file, &pos))
res = SZ_ERROR_FAIL;
else if (File_Seek(&archiveStream.file, (Int64 *)&pos, SZ_SEEK_SET) != 0)
res = SZ_ERROR_FAIL;
if (res != 0)
errorMessage = "Can't find 7z archive";
}
if (res == SZ_OK)
{
lookStream.realStream = &archiveStream.s;
LookToRead_Init(&lookStream);
}
SzArEx_Init(&db);
if (res == SZ_OK)
{
res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp);
}
if (res == SZ_OK)
{
UInt32 executeFileIndex = (UInt32)(Int32)-1;
UInt32 minPrice = 1 << 30;
UInt32 i;
UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */
size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */
for (i = 0; i < db.db.NumFiles; i++)
{
size_t offset = 0;
size_t outSizeProcessed = 0;
const CSzFileItem *f = db.db.Files + i;
size_t len;
WCHAR *temp;
len = SzArEx_GetFileNameUtf16(&db, i, NULL);
if (len >= MAX_PATH)
{
res = SZ_ERROR_FAIL;
break;
}
temp = path + pathLen;
SzArEx_GetFileNameUtf16(&db, i, temp);
{
res = SzArEx_Extract(&db, &lookStream.s, i,
&blockIndex, &outBuffer, &outBufferSize,
&offset, &outSizeProcessed,
&allocImp, &allocTempImp);
if (res != SZ_OK)
break;
}
{
CSzFile outFile;
size_t processedSize;
size_t j;
size_t nameStartPos = 0;
for (j = 0; temp[j] != 0; j++)
{
if (temp[j] == '/')
{
temp[j] = 0;
MyCreateDir(path);
temp[j] = CHAR_PATH_SEPARATOR;
nameStartPos = j + 1;
}
}
if (f->IsDir)
{
MyCreateDir(path);
continue;
}
else
{
unsigned extLen;
const WCHAR *name = temp + nameStartPos;
unsigned len = (unsigned)wcslen(name);
unsigned nameLen = FindExt(temp + nameStartPos, &extLen);
unsigned extPrice = FindItem(kExts, sizeof(kExts) / sizeof(kExts[0]), name + len - extLen, extLen);
unsigned namePrice = FindItem(kNames, sizeof(kNames) / sizeof(kNames[0]), name, nameLen);
unsigned price = namePrice + extPrice * 64 + (nameStartPos == 0 ? 0 : (1 << 12));
if (minPrice > price)
{
minPrice = price;
executeFileIndex = i;
useShellExecute = (extPrice != k_EXE_ExtIndex);
}
if (DoesFileOrDirExist(path))
{
errorMessage = "Duplicate file";
res = SZ_ERROR_FAIL;
break;
}
if (OutFile_OpenW(&outFile, path))
{
errorMessage = "Can't open output file";
res = SZ_ERROR_FAIL;
break;
}
}
processedSize = outSizeProcessed;
if (File_Write(&outFile, outBuffer + offset, &processedSize) != 0 || processedSize != outSizeProcessed)
{
errorMessage = "Can't write output file";
res = SZ_ERROR_FAIL;
}
#ifdef USE_WINDOWS_FILE
if (f->MTimeDefined)
{
FILETIME mTime;
mTime.dwLowDateTime = f->MTime.Low;
mTime.dwHighDateTime = f->MTime.High;
SetFileTime(outFile.handle, NULL, NULL, &mTime);
}
#endif
{
SRes res2 = File_Close(&outFile);
if (res != SZ_OK)
break;
if (res2 != SZ_OK)
{
res = res2;
break;
}
}
#ifdef USE_WINDOWS_FILE
if (f->AttribDefined)
SetFileAttributesW(path, f->Attrib);
#endif
}
}
if (res == SZ_OK)
{
if (executeFileIndex == (UInt32)(Int32)-1)
{
errorMessage = "There is no file to execute";
res = SZ_ERROR_FAIL;
}
else
{
WCHAR *temp = path + pathLen;
UInt32 j;
SzArEx_GetFileNameUtf16(&db, executeFileIndex, temp);
for (j = 0; temp[j] != 0; j++)
if (temp[j] == '/')
temp[j] = CHAR_PATH_SEPARATOR;
}
}
IAlloc_Free(&allocImp, outBuffer);
}
SzArEx_Free(&db, &allocImp);
File_Close(&archiveStream.file);
if (res == SZ_OK)
{
HANDLE hProcess = 0;
if (useShellExecute)
{
SHELLEXECUTEINFO ei;
UINT32 executeRes;
BOOL success;
memset(&ei, 0, sizeof(ei));
ei.cbSize = sizeof(ei);
ei.lpFile = path;
ei.fMask = SEE_MASK_NOCLOSEPROCESS
#ifndef UNDER_CE
| SEE_MASK_FLAG_DDEWAIT
#endif
/* | SEE_MASK_NO_CONSOLE */
;
if (wcslen(cmdLineParams) != 0)
ei.lpParameters = cmdLineParams;
ei.nShow = SW_SHOWNORMAL; /* SW_HIDE; */
success = ShellExecuteEx(&ei);
executeRes = (UINT32)(UINT_PTR)ei.hInstApp;
if (!success || (executeRes <= 32 && executeRes != 0)) /* executeRes = 0 in Windows CE */
res = SZ_ERROR_FAIL;
else
hProcess = ei.hProcess;
}
else
{
STARTUPINFOW si;
PROCESS_INFORMATION pi;
WCHAR cmdLine[MAX_PATH * 3];
wcscpy(cmdLine, path);
wcscat(cmdLine, cmdLineParams);
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) == 0)
res = SZ_ERROR_FAIL;
else
{
CloseHandle(pi.hThread);
hProcess = pi.hProcess;
}
}
if (hProcess != 0)
{
WaitForSingleObject(hProcess, INFINITE);
CloseHandle(hProcess);
}
}
path[pathLen] = L'\0';
RemoveDirWithSubItems(path);
if (res == SZ_OK)
return 0;
{
if (res == SZ_ERROR_UNSUPPORTED)
errorMessage = "Decoder doesn't support this archive";
else if (res == SZ_ERROR_MEM)
errorMessage = "Can't allocate required memory";
else if (res == SZ_ERROR_CRC)
errorMessage = "CRC error";
else
{
if (!errorMessage)
errorMessage = "ERROR";
}
if (errorMessage)
PrintErrorMessage(errorMessage);
}
return 1;
}

198
C/Util/SfxSetup/SfxSetup.dsp Executable file
View File

@@ -0,0 +1,198 @@
# Microsoft Developer Studio Project File - Name="SfxSetup" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=SfxSetup - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "SfxSetup.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "SfxSetup.mak" CFG="SfxSetup - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "SfxSetup - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "SfxSetup - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "SfxSetup - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x419 /d "NDEBUG"
# ADD RSC /l 0x419 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
!ELSEIF "$(CFG)" == "SfxSetup - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x419 /d "_DEBUG"
# ADD RSC /l 0x419 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "SfxSetup - Win32 Release"
# Name "SfxSetup - Win32 Debug"
# Begin Group "Common"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\7z.h
# End Source File
# Begin Source File
SOURCE=..\..\7zAlloc.c
# End Source File
# Begin Source File
SOURCE=..\..\7zAlloc.h
# End Source File
# Begin Source File
SOURCE=..\..\7zBuf.c
# End Source File
# Begin Source File
SOURCE=..\..\7zBuf.h
# End Source File
# Begin Source File
SOURCE=..\..\7zCrc.c
# End Source File
# Begin Source File
SOURCE=..\..\7zCrc.h
# End Source File
# Begin Source File
SOURCE=..\..\7zCrcOpt.c
# End Source File
# Begin Source File
SOURCE=..\..\7zDec.c
# End Source File
# Begin Source File
SOURCE=..\..\7zFile.c
# End Source File
# Begin Source File
SOURCE=..\..\7zFile.h
# End Source File
# Begin Source File
SOURCE=..\..\7zIn.c
# End Source File
# Begin Source File
SOURCE=..\..\7zStream.c
# End Source File
# Begin Source File
SOURCE=..\..\Bcj2.c
# End Source File
# Begin Source File
SOURCE=..\..\Bcj2.h
# End Source File
# Begin Source File
SOURCE=..\..\Bra.c
# End Source File
# Begin Source File
SOURCE=..\..\Bra.h
# End Source File
# Begin Source File
SOURCE=..\..\Bra86.c
# End Source File
# Begin Source File
SOURCE=..\..\CpuArch.c
# End Source File
# Begin Source File
SOURCE=..\..\CpuArch.h
# End Source File
# Begin Source File
SOURCE=..\..\Lzma2Dec.c
# End Source File
# Begin Source File
SOURCE=..\..\Lzma2Dec.h
# End Source File
# Begin Source File
SOURCE=..\..\LzmaDec.c
# End Source File
# Begin Source File
SOURCE=..\..\LzmaDec.h
# End Source File
# Begin Source File
SOURCE=..\..\Types.h
# End Source File
# End Group
# Begin Source File
SOURCE=.\SfxSetup.c
# End Source File
# End Target
# End Project

29
C/Util/SfxSetup/SfxSetup.dsw Executable file
View File

@@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "SfxSetup"=.\SfxSetup.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

35
C/Util/SfxSetup/makefile Executable file
View File

@@ -0,0 +1,35 @@
PROG = 7zS2.sfx
LIBS = $(LIBS)
CFLAGS = $(CFLAGS) -DUNICODE -D_UNICODE
C_OBJS = \
$O\7zAlloc.obj \
$O\7zBuf.obj \
$O\7zBuf2.obj \
$O\7zCrc.obj \
$O\7zCrcOpt.obj \
$O\7zFile.obj \
$O\7zDec.obj \
$O\7zIn.obj \
$O\7zStream.obj \
$O\Bcj2.obj \
$O\Bra.obj \
$O\Bra86.obj \
$O\CpuArch.obj \
$O\Lzma2Dec.obj \
$O\LzmaDec.obj \
7Z_OBJS = \
$O\SfxSetup.obj \
OBJS = \
$(7Z_OBJS) \
$(C_OBJS) \
$O\resource.res
!include "../../../CPP/Build.mak"
$(7Z_OBJS): $(*B).c
$(COMPL_O1)
$(C_OBJS): ../../$(*B).c
$(COMPL_O1)

35
C/Util/SfxSetup/makefile_con Executable file
View File

@@ -0,0 +1,35 @@
PROG = 7zS2con.sfx
LIBS = $(LIBS)
CFLAGS = $(CFLAGS) -DUNICODE -D_UNICODE -D_CONSOLE
C_OBJS = \
$O\7zAlloc.obj \
$O\7zBuf.obj \
$O\7zBuf2.obj \
$O\7zCrc.obj \
$O\7zCrcOpt.obj \
$O\7zFile.obj \
$O\7zDec.obj \
$O\7zIn.obj \
$O\7zStream.obj \
$O\Bcj2.obj \
$O\Bra.obj \
$O\Bra86.obj \
$O\CpuArch.obj \
$O\Lzma2Dec.obj \
$O\LzmaDec.obj \
7Z_OBJS = \
$O\SfxSetup.obj \
OBJS = \
$(7Z_OBJS) \
$(C_OBJS) \
$O\resource.res
!include "../../../CPP/Build.mak"
$(7Z_OBJS): $(*B).c
$(COMPL_O1)
$(C_OBJS): ../../$(*B).c
$(COMPL_O1)

6
C/Util/SfxSetup/resource.rc Executable file
View File

@@ -0,0 +1,6 @@
#include "../../../CPP/7zip/MyVersionInfo.rc"
MY_VERSION_INFO_APP("7z Setup SFX small", "7zS2.sfx")
1 ICON "setup.ico"

BIN
C/Util/SfxSetup/setup.ico Executable file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

12
C/Xz.h
View File

@@ -1,14 +1,12 @@
/* Xz.h - Xz interface /* Xz.h - Xz interface
2009-04-15 : Igor Pavlov : Public domain */ 2010-09-17 : Igor Pavlov : Public domain */
#ifndef __XZ_H #ifndef __XZ_H
#define __XZ_H #define __XZ_H
#include "Sha256.h" #include "Sha256.h"
#ifdef __cplusplus EXTERN_C_BEGIN
extern "C" {
#endif
#define XZ_ID_Subblock 1 #define XZ_ID_Subblock 1
#define XZ_ID_Delta 3 #define XZ_ID_Delta 3
@@ -140,7 +138,7 @@ typedef enum
CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */ CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */
CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
CODER_STATUS_NOT_FINISHED, /* stream was not finished */ CODER_STATUS_NOT_FINISHED, /* stream was not finished */
CODER_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */
} ECoderStatus; } ECoderStatus;
typedef enum typedef enum
@@ -249,8 +247,6 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p); Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p);
#ifdef __cplusplus EXTERN_C_END
}
#endif
#endif #endif

View File

@@ -1,9 +1,9 @@
/* XzCrc64.c -- CRC64 calculation /* XzCrc64.c -- CRC64 calculation
2009-04-15 : Igor Pavlov : Public domain */ 2010-04-16 : Igor Pavlov : Public domain */
#include "XzCrc64.h" #include "XzCrc64.h"
#define kCrc64Poly 0xC96C5795D7870F42 #define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42)
UInt64 g_Crc64Table[256]; UInt64 g_Crc64Table[256];
void MY_FAST_CALL Crc64GenerateTable(void) void MY_FAST_CALL Crc64GenerateTable(void)

View File

@@ -1,5 +1,5 @@
/* XzCrc64.c -- CRC64 calculation /* XzCrc64.h -- CRC64 calculation
2009-04-15 : Igor Pavlov : Public domain */ 2010-04-16 : Igor Pavlov : Public domain */
#ifndef __XZ_CRC64_H #ifndef __XZ_CRC64_H
#define __XZ_CRC64_H #define __XZ_CRC64_H
@@ -8,23 +8,19 @@
#include "Types.h" #include "Types.h"
#ifdef __cplusplus EXTERN_C_BEGIN
extern "C" {
#endif
extern UInt64 g_Crc64Table[]; extern UInt64 g_Crc64Table[];
void MY_FAST_CALL Crc64GenerateTable(void); void MY_FAST_CALL Crc64GenerateTable(void);
#define CRC64_INIT_VAL 0xFFFFFFFFFFFFFFFF #define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF)
#define CRC64_GET_DIGEST(crc) ((crc) ^ 0xFFFFFFFFFFFFFFFF) #define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL)
#define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) #define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
UInt64 MY_FAST_CALL Crc64Update(UInt64 crc, const void *data, size_t size); UInt64 MY_FAST_CALL Crc64Update(UInt64 crc, const void *data, size_t size);
UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size); UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size);
#ifdef __cplusplus EXTERN_C_END
}
#endif
#endif #endif

View File

@@ -1,5 +1,5 @@
/* XzDec.c -- Xz Decode /* XzDec.c -- Xz Decode
2009-06-08 : Igor Pavlov : Public domain */ 2010-04-16 : Igor Pavlov : Public domain */
/* #define XZ_DUMP */ /* #define XZ_DUMP */
@@ -858,6 +858,8 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
} }
break; break;
} }
case XZ_STATE_BLOCK: break; /* to disable GCC warning */
} }
} }
/* /*

View File

@@ -232,7 +232,7 @@ HRESULT CDecoder::Decode(
size_t size = props.GetCapacity(); size_t size = props.GetCapacity();
if (size > 0xFFFFFFFF) if (size > 0xFFFFFFFF)
return E_NOTIMPL; return E_NOTIMPL;
if (size > 0) // if (size > 0)
{ {
RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size)); RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size));
} }

View File

@@ -193,11 +193,9 @@ HRESULT CEncoder::Encode(
// UInt64 outStreamStartPos; // UInt64 outStreamStartPos;
// RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos)); // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos));
CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2;
new CSequentialInStreamSizeCount2;
CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec; CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
CSequentialOutStreamSizeCount *outStreamSizeCountSpec = CSequentialOutStreamSizeCount *outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
new CSequentialOutStreamSizeCount;
CMyComPtr<ISequentialOutStream> outStreamSizeCount = outStreamSizeCountSpec; CMyComPtr<ISequentialOutStream> outStreamSizeCount = outStreamSizeCountSpec;
inStreamSizeCountSpec->Init(inStream); inStreamSizeCountSpec->Init(inStream);
@@ -226,13 +224,11 @@ HRESULT CEncoder::Encode(
_mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties); _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
if (writeCoderProperties != NULL) if (writeCoderProperties != NULL)
{ {
CSequentialOutStreamImp *outStreamSpec = new CSequentialOutStreamImp; CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
outStreamSpec->Init(); outStreamSpec->Init();
writeCoderProperties->WriteCoderProperties(outStream); writeCoderProperties->WriteCoderProperties(outStream);
size_t size = outStreamSpec->GetSize(); outStreamSpec->CopyToBuffer(encodingInfo.Props);
encodingInfo.Props.SetCapacity(size);
memmove(encodingInfo.Props, outStreamSpec->GetBuffer(), size);
} }
} }
@@ -250,8 +246,7 @@ HRESULT CEncoder::Encode(
RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1, RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1,
&outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress)); &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress));
ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, folderItem);
folderItem);
packSizes.Add(outStreamSizeCountSpec->GetSize()); packSizes.Add(outStreamSizeCountSpec->GetSize());

View File

@@ -2,15 +2,14 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "7zHandler.h" #include "../../../Common/ComTry.h"
#include "7zFolderOutStream.h"
#include "../../Common/ProgressUtils.h"
#include "7zDecode.h" #include "7zDecode.h"
// #include "7z1Decode.h" // #include "7z1Decode.h"
#include "7zFolderOutStream.h"
#include "../../../Common/ComTry.h" #include "7zHandler.h"
#include "../../Common/StreamObjects.h"
#include "../../Common/ProgressUtils.h"
#include "../../Common/LimitedStreams.h"
namespace NArchive { namespace NArchive {
namespace N7z { namespace N7z {
@@ -138,7 +137,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
} }
} }
extractCallback->SetTotal(importantTotalUnpacked); RINOK(extractCallback->SetTotal(importantTotalUnpacked));
CDecoder decoder( CDecoder decoder(
#ifdef _ST_MODE #ifdef _ST_MODE
@@ -149,27 +148,26 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
); );
// CDecoder1 decoder; // CDecoder1 decoder;
UInt64 currentTotalPacked = 0; UInt64 totalPacked = 0;
UInt64 currentTotalUnpacked = 0; UInt64 totalUnpacked = 0;
UInt64 totalFolderUnpacked; UInt64 curPacked, curUnpacked;
UInt64 totalFolderPacked;
CLocalProgress *lps = new CLocalProgress; CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps; CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false); lps->Init(extractCallback, false);
for(int i = 0; i < extractFolderInfoVector.Size(); i++, for (int i = 0;; i++, totalUnpacked += curUnpacked, totalPacked += curPacked)
currentTotalUnpacked += totalFolderUnpacked,
currentTotalPacked += totalFolderPacked)
{ {
lps->OutSize = currentTotalUnpacked; lps->OutSize = totalUnpacked;
lps->InSize = currentTotalPacked; lps->InSize = totalPacked;
RINOK(lps->SetCur()); RINOK(lps->SetCur());
const CExtractFolderInfo &efi = extractFolderInfoVector[i]; if (i >= extractFolderInfoVector.Size())
totalFolderUnpacked = efi.UnpackSize; break;
totalFolderPacked = 0; const CExtractFolderInfo &efi = extractFolderInfoVector[i];
curUnpacked = efi.UnpackSize;
curPacked = 0;
CFolderOutStream *folderOutStream = new CFolderOutStream; CFolderOutStream *folderOutStream = new CFolderOutStream;
CMyComPtr<ISequentialOutStream> outStream(folderOutStream); CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
@@ -187,7 +185,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
else else
startIndex = db.FolderStartFileIndex[efi.FolderIndex]; startIndex = db.FolderStartFileIndex[efi.FolderIndex];
HRESULT result = folderOutStream->Init(&db, HRESULT result = folderOutStream->Init(&db,
#ifdef _7Z_VOL #ifdef _7Z_VOL
volume.StartRef2Index, volume.StartRef2Index,
@@ -205,7 +202,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CNum folderIndex = efi.FolderIndex; CNum folderIndex = efi.FolderIndex;
const CFolder &folderInfo = db.Folders[folderIndex]; const CFolder &folderInfo = db.Folders[folderIndex];
totalFolderPacked = _db.GetFolderFullPackSize(folderIndex); curPacked = _db.GetFolderFullPackSize(folderIndex);
CNum packStreamIndex = db.FolderStartPackStreamIndex[folderIndex]; CNum packStreamIndex = db.FolderStartPackStreamIndex[folderIndex];
UInt64 folderStartPackPos = db.GetFolderStreamPos(folderIndex, 0); UInt64 folderStartPackPos = db.GetFolderStreamPos(folderIndex, 0);

View File

@@ -32,7 +32,6 @@ HRESULT CFolderInStream::OpenStream()
_filePos = 0; _filePos = 0;
while (_fileIndex < _numFiles) while (_fileIndex < _numFiles)
{ {
_currentSizeIsDefined = false;
CMyComPtr<ISequentialInStream> stream; CMyComPtr<ISequentialInStream> stream;
HRESULT result = _updateCallback->GetStream(_fileIndices[_fileIndex], &stream); HRESULT result = _updateCallback->GetStream(_fileIndices[_fileIndex], &stream);
if (result != S_OK && result != S_FALSE) if (result != S_OK && result != S_FALSE)
@@ -40,26 +39,22 @@ HRESULT CFolderInStream::OpenStream()
_fileIndex++; _fileIndex++;
_inStreamWithHashSpec->SetStream(stream); _inStreamWithHashSpec->SetStream(stream);
_inStreamWithHashSpec->Init(); _inStreamWithHashSpec->Init();
if (!stream) if (stream)
{ {
_fileIsOpen = true;
CMyComPtr<IStreamGetSize> streamGetSize;
stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
if (streamGetSize)
{
RINOK(streamGetSize->GetSize(&_currentSize));
_currentSizeIsDefined = true;
}
return S_OK;
}
RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
Sizes.Add(0); Sizes.Add(0);
Processed.Add(result == S_OK); Processed.Add(result == S_OK);
AddDigest(); AddDigest();
continue;
}
CMyComPtr<IStreamGetSize> streamGetSize;
if (stream.QueryInterface(IID_IStreamGetSize, &streamGetSize) == S_OK)
{
if(streamGetSize)
{
_currentSizeIsDefined = true;
RINOK(streamGetSize->GetSize(&_currentSize));
}
}
_fileIsOpen = true;
return S_OK;
} }
return S_OK; return S_OK;
} }
@@ -74,6 +69,7 @@ HRESULT CFolderInStream::CloseStream()
RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
_inStreamWithHashSpec->ReleaseStream(); _inStreamWithHashSpec->ReleaseStream();
_fileIsOpen = false; _fileIsOpen = false;
_currentSizeIsDefined = false;
Processed.Add(true); Processed.Add(true);
Sizes.Add(_filePos); Sizes.Add(_filePos);
AddDigest(); AddDigest();
@@ -82,43 +78,40 @@ HRESULT CFolderInStream::CloseStream()
STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize) STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
{ {
UInt32 realProcessedSize = 0; if (processedSize != 0)
while ((_fileIndex < _numFiles || _fileIsOpen) && size > 0) *processedSize = 0;
while (size > 0)
{ {
if (_fileIsOpen) if (_fileIsOpen)
{ {
UInt32 localProcessedSize; UInt32 processed2;
RINOK(_inStreamWithHash->Read( RINOK(_inStreamWithHash->Read(data, size, &processed2));
((Byte *)data) + realProcessedSize, size, &localProcessedSize)); if (processed2 == 0)
if (localProcessedSize == 0)
{ {
RINOK(CloseStream()); RINOK(CloseStream());
continue; continue;
} }
realProcessedSize += localProcessedSize; if (processedSize != 0)
_filePos += localProcessedSize; *processedSize = processed2;
size -= localProcessedSize; _filePos += processed2;
break; break;
} }
else if (_fileIndex >= _numFiles)
{ break;
RINOK(OpenStream()); RINOK(OpenStream());
} }
}
if (processedSize != 0)
*processedSize = realProcessedSize;
return S_OK; return S_OK;
} }
STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value) STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
{ {
*value = 0; *value = 0;
int subStreamIndex = (int)subStream; int index2 = (int)subStream;
if (subStreamIndex < 0 || subStream > Sizes.Size()) if (index2 < 0 || subStream > Sizes.Size())
return E_FAIL; return E_FAIL;
if (subStreamIndex < Sizes.Size()) if (index2 < Sizes.Size())
{ {
*value= Sizes[subStreamIndex]; *value = Sizes[index2];
return S_OK; return S_OK;
} }
if (!_currentSizeIsDefined) if (!_currentSizeIsDefined)

View File

@@ -1,15 +1,13 @@
// 7z/FolderInStream.h // 7zFolderInStream.h
#ifndef __7Z_FOLDERINSTREAM_H #ifndef __7Z_FOLDER_IN_STREAM_H
#define __7Z_FOLDERINSTREAM_H #define __7Z_FOLDER_IN_STREAM_H
#include "7zItem.h"
#include "7zHeader.h"
#include "../../ICoder.h"
#include "../IArchive.h" #include "../IArchive.h"
#include "../Common/InStreamWithCRC.h" #include "../Common/InStreamWithCRC.h"
#include "../../IStream.h"
#include "../../ICoder.h" #include "7zItem.h"
namespace NArchive { namespace NArchive {
namespace N7z { namespace N7z {
@@ -19,26 +17,14 @@ class CFolderInStream:
public ICompressGetSubStreamSize, public ICompressGetSubStreamSize,
public CMyUnknownImp public CMyUnknownImp
{ {
public:
MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
CFolderInStream();
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
private:
CSequentialInStreamWithCRC *_inStreamWithHashSpec; CSequentialInStreamWithCRC *_inStreamWithHashSpec;
CMyComPtr<ISequentialInStream> _inStreamWithHash; CMyComPtr<ISequentialInStream> _inStreamWithHash;
CMyComPtr<IArchiveUpdateCallback> _updateCallback; CMyComPtr<IArchiveUpdateCallback> _updateCallback;
bool _currentSizeIsDefined; bool _currentSizeIsDefined;
UInt64 _currentSize;
bool _fileIsOpen; bool _fileIsOpen;
UInt64 _currentSize;
UInt64 _filePos; UInt64 _filePos;
const UInt32 *_fileIndices; const UInt32 *_fileIndices;
UInt32 _numFiles; UInt32 _numFiles;
UInt32 _fileIndex; UInt32 _fileIndex;
@@ -46,12 +32,18 @@ private:
HRESULT OpenStream(); HRESULT OpenStream();
HRESULT CloseStream(); HRESULT CloseStream();
void AddDigest(); void AddDigest();
public: public:
void Init(IArchiveUpdateCallback *updateCallback,
const UInt32 *fileIndices, UInt32 numFiles);
CRecordVector<bool> Processed; CRecordVector<bool> Processed;
CRecordVector<UInt32> CRCs; CRecordVector<UInt32> CRCs;
CRecordVector<UInt64> Sizes; CRecordVector<UInt64> Sizes;
MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
CFolderInStream();
void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *fileIndices, UInt32 numFiles);
UInt64 GetFullSize() const UInt64 GetFullSize() const
{ {
UInt64 size = 0; UInt64 size = 0;

View File

@@ -14,13 +14,13 @@ CFolderOutStream::CFolderOutStream()
} }
HRESULT CFolderOutStream::Init( HRESULT CFolderOutStream::Init(
const CArchiveDatabaseEx *archiveDatabase, const CArchiveDatabaseEx *db,
UInt32 ref2Offset, UInt32 startIndex, UInt32 ref2Offset, UInt32 startIndex,
const CBoolVector *extractStatuses, const CBoolVector *extractStatuses,
IArchiveExtractCallback *extractCallback, IArchiveExtractCallback *extractCallback,
bool testMode, bool checkCrc) bool testMode, bool checkCrc)
{ {
_db = archiveDatabase; _db = db;
_ref2Offset = ref2Offset; _ref2Offset = ref2Offset;
_startIndex = startIndex; _startIndex = startIndex;
@@ -121,6 +121,15 @@ STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *proc
return S_OK; return S_OK;
} }
STDMETHODIMP CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
{
*value = 0;
if ((int)subStream >= _extractStatuses->Size())
return S_FALSE;
*value = _db->Files[_startIndex + (int)subStream].Size;
return S_OK;
}
HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult) HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult)
{ {
while (_currentIndex < _extractStatuses->Size()) while (_currentIndex < _extractStatuses->Size())

View File

@@ -3,17 +3,18 @@
#ifndef __7Z_FOLDER_OUT_STREAM_H #ifndef __7Z_FOLDER_OUT_STREAM_H
#define __7Z_FOLDER_OUT_STREAM_H #define __7Z_FOLDER_OUT_STREAM_H
#include "7zIn.h"
#include "../../IStream.h" #include "../../IStream.h"
#include "../IArchive.h" #include "../IArchive.h"
#include "../Common/OutStreamWithCRC.h" #include "../Common/OutStreamWithCRC.h"
#include "7zIn.h"
namespace NArchive { namespace NArchive {
namespace N7z { namespace N7z {
class CFolderOutStream: class CFolderOutStream:
public ISequentialOutStream, public ISequentialOutStream,
public ICompressGetSubStreamSize,
public CMyUnknownImp public CMyUnknownImp
{ {
COutStreamWithCRC *_crcStreamSpec; COutStreamWithCRC *_crcStreamSpec;
@@ -34,14 +35,15 @@ class CFolderOutStream:
HRESULT CloseFileAndSetResult(); HRESULT CloseFileAndSetResult();
HRESULT ProcessEmptyFiles(); HRESULT ProcessEmptyFiles();
public: public:
MY_UNKNOWN_IMP MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
CFolderOutStream(); CFolderOutStream();
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
HRESULT Init( HRESULT Init(
const CArchiveDatabaseEx *archiveDatabase, const CArchiveDatabaseEx *db,
UInt32 ref2Offset, UInt32 startIndex, UInt32 ref2Offset, UInt32 startIndex,
const CBoolVector *extractStatuses, const CBoolVector *extractStatuses,
IArchiveExtractCallback *extractCallback, IArchiveExtractCallback *extractCallback,

View File

@@ -120,7 +120,7 @@ public:
kUnsupportedVersion = 0, kUnsupportedVersion = 0,
kUnsupported, kUnsupported,
kIncorrect, kIncorrect,
kEndOfData, kEndOfData
} Cause; } Cause;
CInArchiveException(CCauseType cause): Cause(cause) {}; CInArchiveException(CCauseType cause): Cause(cause) {};
}; };
@@ -280,28 +280,46 @@ void CInByte2::ReadString(UString &s)
_pos += rem + 2; _pos += rem + 2;
} }
static inline bool TestSignatureCandidate(const Byte *p) static inline bool TestSignature(const Byte *p)
{ {
for (int i = 0; i < kSignatureSize; i++) for (int i = 0; i < kSignatureSize; i++)
if (p[i] != kSignature[i]) if (p[i] != kSignature[i])
return false; return false;
return (p[0x1A] == 0 && p[0x1B] == 0); return CrcCalc(p + 12, 20) == GetUi32(p + 8);
} }
#ifdef FORMAT_7Z_RECOVERY
static inline bool TestSignature2(const Byte *p)
{
int i;
for (i = 0; i < kSignatureSize; i++)
if (p[i] != kSignature[i])
return false;
if (CrcCalc(p + 12, 20) == GetUi32(p + 8))
return true;
for (i = 8; i < kHeaderSize; i++)
if (p[i] != 0)
return false;
return (p[6] != 0 || p[7] != 0);
}
#else
#define TestSignature2(p) TestSignature(p)
#endif
HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit) HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
{ {
RINOK(ReadStream_FALSE(stream, _header, kHeaderSize)); RINOK(ReadStream_FALSE(stream, _header, kHeaderSize));
if (TestSignatureCandidate(_header)) if (TestSignature2(_header))
return S_OK; return S_OK;
CByteBuffer byteBuffer; CByteBuffer byteBuffer;
const UInt32 kBufferSize = (1 << 16); const UInt32 kBufferSize = (1 << 16);
byteBuffer.SetCapacity(kBufferSize); byteBuffer.SetCapacity(kBufferSize);
Byte *buffer = byteBuffer; Byte *buffer = byteBuffer;
UInt32 numPrevBytes = kHeaderSize - 1; UInt32 numPrevBytes = kHeaderSize;
memcpy(buffer, _header + 1, numPrevBytes); memcpy(buffer, _header, kHeaderSize);
UInt64 curTestPos = _arhiveBeginStreamPosition + 1; UInt64 curTestPos = _arhiveBeginStreamPosition;
for (;;) for (;;)
{ {
if (searchHeaderSizeLimit != NULL) if (searchHeaderSizeLimit != NULL)
@@ -316,14 +334,14 @@ HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *search
if (processedSize == 0) if (processedSize == 0)
return S_FALSE; return S_FALSE;
} }
while (numPrevBytes < kHeaderSize); while (numPrevBytes <= kHeaderSize);
UInt32 numTests = numPrevBytes - kHeaderSize + 1; UInt32 numTests = numPrevBytes - kHeaderSize;
for (UInt32 pos = 0; pos < numTests; pos++) for (UInt32 pos = 0; pos < numTests; pos++)
{ {
for (; buffer[pos] != '7' && pos < numTests; pos++); for (; buffer[pos] != '7' && pos < numTests; pos++);
if (pos == numTests) if (pos == numTests)
break; break;
if (TestSignatureCandidate(buffer + pos)) if (TestSignature(buffer + pos))
{ {
memcpy(_header, buffer + pos, kHeaderSize); memcpy(_header, buffer + pos, kHeaderSize);
curTestPos += pos; curTestPos += pos;
@@ -812,7 +830,7 @@ HRESULT CInArchive::ReadAndDecodePackedStreams(
ThrowUnsupported(); ThrowUnsupported();
data.SetCapacity(unpackSize); data.SetCapacity(unpackSize);
CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2; CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
outStreamSpec->Init(data, unpackSize); outStreamSpec->Init(data, unpackSize);
@@ -1164,16 +1182,14 @@ HRESULT CInArchive::ReadDatabase2(
nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize); nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL)); RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
} }
else
#endif #endif
{
#ifdef FORMAT_7Z_RECOVERY
crcFromArchive = crc;
#endif
db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
if (crc != crcFromArchive) if (crc != crcFromArchive)
ThrowIncorrect(); ThrowIncorrect();
}
db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
if (nextHeaderSize == 0) if (nextHeaderSize == 0)
return S_OK; return S_OK;
@@ -1181,6 +1197,9 @@ HRESULT CInArchive::ReadDatabase2(
if (nextHeaderSize > (UInt64)0xFFFFFFFF) if (nextHeaderSize > (UInt64)0xFFFFFFFF)
return S_FALSE; return S_FALSE;
if ((Int64)nextHeaderOffset < 0)
return S_FALSE;
RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL)); RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));
CByteBuffer buffer2; CByteBuffer buffer2;

View File

@@ -19,32 +19,33 @@ struct CPropMap
CPropMap kPropMap[] = CPropMap kPropMap[] =
{ {
{ NID::kName, NULL, kpidPath, VT_BSTR}, { NID::kName, { NULL, kpidPath, VT_BSTR } },
{ NID::kSize, NULL, kpidSize, VT_UI8}, { NID::kSize, { NULL, kpidSize, VT_UI8 } },
{ NID::kPackInfo, NULL, kpidPackSize, VT_UI8}, { NID::kPackInfo, { NULL, kpidPackSize, VT_UI8 } },
#ifdef _MULTI_PACK #ifdef _MULTI_PACK
{ 100, L"Pack0", kpidPackedSize0, VT_UI8}, { 100, { L"Pack0", kpidPackedSize0, VT_UI8 } },
{ 101, L"Pack1", kpidPackedSize1, VT_UI8}, { 101, { L"Pack1", kpidPackedSize1, VT_UI8 } },
{ 102, L"Pack2", kpidPackedSize2, VT_UI8}, { 102, { L"Pack2", kpidPackedSize2, VT_UI8 } },
{ 103, L"Pack3", kpidPackedSize3, VT_UI8}, { 103, { L"Pack3", kpidPackedSize3, VT_UI8 } },
{ 104, L"Pack4", kpidPackedSize4, VT_UI8}, { 104, { L"Pack4", kpidPackedSize4, VT_UI8 } },
#endif #endif
{ NID::kCTime, NULL, kpidCTime, VT_FILETIME}, { NID::kCTime, { NULL, kpidCTime, VT_FILETIME } },
{ NID::kMTime, NULL, kpidMTime, VT_FILETIME}, { NID::kMTime, { NULL, kpidMTime, VT_FILETIME } },
{ NID::kATime, NULL, kpidATime, VT_FILETIME}, { NID::kATime, { NULL, kpidATime, VT_FILETIME } },
{ NID::kWinAttributes, NULL, kpidAttrib, VT_UI4}, { NID::kWinAttributes, { NULL, kpidAttrib, VT_UI4 } },
{ NID::kStartPos, NULL, kpidPosition, VT_UI4}, { NID::kStartPos, { NULL, kpidPosition, VT_UI4 } },
{ NID::kCRC, NULL, kpidCRC, VT_UI4}, { NID::kCRC, { NULL, kpidCRC, VT_UI4 } },
{ NID::kAnti, NULL, kpidIsAnti, VT_BOOL}, { NID::kAnti, { NULL, kpidIsAnti, VT_BOOL } }
#ifndef _SFX #ifndef _SFX
{ 97, NULL, kpidEncrypted, VT_BOOL}, ,
{ 98, NULL, kpidMethod, VT_BSTR}, { 97, { NULL,kpidEncrypted, VT_BOOL } },
{ 99, NULL, kpidBlock, VT_UI4} { 98, { NULL,kpidMethod, VT_BSTR } },
{ 99, { NULL,kpidBlock, VT_UI4 } }
#endif #endif
}; };

View File

@@ -382,6 +382,12 @@ static void MakeExeMethod(const CCompressionMethodMode &method,
prop.Value = kNumFastBytesForBCJ2_LZMA; prop.Value = kNumFastBytesForBCJ2_LZMA;
methodFull.Props.Add(prop); methodFull.Props.Add(prop);
} }
{
CProp prop;
prop.Id = NCoderPropID::kNumThreads;
prop.Value = (UInt32)1;
methodFull.Props.Add(prop);
}
exeMethod.Methods.Add(methodFull); exeMethod.Methods.Add(methodFull);
exeMethod.Methods.Add(methodFull); exeMethod.Methods.Add(methodFull);

View File

@@ -85,6 +85,7 @@ STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject)
STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value) STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value)
{ {
COM_TRY_BEGIN
if (formatIndex >= g_NumArcs) if (formatIndex >= g_NumArcs)
return E_INVALIDARG; return E_INVALIDARG;
const CArcInfo &arc = *g_Arcs[formatIndex]; const CArcInfo &arc = *g_Arcs[formatIndex];
@@ -119,6 +120,7 @@ STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value
} }
prop.Detach(value); prop.Detach(value);
return S_OK; return S_OK;
COM_TRY_END
} }
STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value) STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value)

View File

@@ -264,7 +264,7 @@ struct CInArchiveException
{ {
kUnexpectedEndOfArchive = 0, kUnexpectedEndOfArchive = 0,
kCRCError, kCRCError,
kIncorrectArchive, kIncorrectArchive
} }
Cause; Cause;
CInArchiveException(CCauseType cause): Cause(cause) {}; CInArchiveException(CCauseType cause): Cause(cause) {};

View File

@@ -2,6 +2,8 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "../../../../C/Alloc.h"
#include "Common/Buffer.h" #include "Common/Buffer.h"
#include "Common/ComTry.h" #include "Common/ComTry.h"
#include "Common/Defs.h" #include "Common/Defs.h"
@@ -32,8 +34,6 @@ namespace NCab {
// #define _CAB_DETAILS // #define _CAB_DETAILS
static const UInt32 kMaxTempBufSize = 1 << 20;
#ifdef _CAB_DETAILS #ifdef _CAB_DETAILS
enum enum
{ {
@@ -41,7 +41,7 @@ enum
}; };
#endif #endif
STATPROPSTG kProps[] = static STATPROPSTG kProps[] =
{ {
{ NULL, kpidPath, VT_BSTR}, { NULL, kpidPath, VT_BSTR},
{ NULL, kpidSize, VT_UI8}, { NULL, kpidSize, VT_UI8},
@@ -57,18 +57,18 @@ STATPROPSTG kProps[] =
#endif #endif
}; };
static const wchar_t *kMethods[] = static const char *kMethods[] =
{ {
L"None", "None",
L"MSZip", "MSZip",
L"Quantum", "Quantum",
L"LZX" "LZX"
}; };
static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]); static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]);
static const wchar_t *kUnknownMethod = L"Unknown"; static const char *kUnknownMethod = "Unknown";
STATPROPSTG kArcProps[] = static STATPROPSTG kArcProps[] =
{ {
{ NULL, kpidMethod, VT_BSTR}, { NULL, kpidMethod, VT_BSTR},
// { NULL, kpidSolid, VT_BOOL}, // { NULL, kpidSolid, VT_BOOL},
@@ -87,7 +87,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{ {
case kpidMethod: case kpidMethod:
{ {
UString resString; AString resString;
CRecordVector<Byte> ids; CRecordVector<Byte> ids;
int i; int i;
for (int v = 0; v < m_Database.Volumes.Size(); v++) for (int v = 0; v < m_Database.Volumes.Size(); v++)
@@ -99,9 +99,9 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
for (i = 0; i < ids.Size(); i++) for (i = 0; i < ids.Size(); i++)
{ {
Byte id = ids[i]; Byte id = ids[i];
UString method = (id < kNumMethods) ? kMethods[id] : kUnknownMethod; AString method = (id < kNumMethods) ? kMethods[id] : kUnknownMethod;
if (!resString.IsEmpty()) if (!resString.IsEmpty())
resString += L' '; resString += ' ';
resString += method; resString += method;
} }
prop = resString; prop = resString;
@@ -171,12 +171,12 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
UInt32 realFolderIndex = item.GetFolderIndex(db.Folders.Size()); UInt32 realFolderIndex = item.GetFolderIndex(db.Folders.Size());
const CFolder &folder = db.Folders[realFolderIndex]; const CFolder &folder = db.Folders[realFolderIndex];
int methodIndex = folder.GetCompressionMethod(); int methodIndex = folder.GetCompressionMethod();
UString method = (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod; AString method = (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod;
if (methodIndex == NHeader::NCompressionMethodMajor::kLZX || if (methodIndex == NHeader::NCompressionMethodMajor::kLZX ||
methodIndex == NHeader::NCompressionMethodMajor::kQuantum) methodIndex == NHeader::NCompressionMethodMajor::kQuantum)
{ {
method += L":"; method += ':';
wchar_t temp[32]; char temp[32];
ConvertUInt64ToString(folder.CompressionTypeMinor, temp); ConvertUInt64ToString(folder.CompressionTypeMinor, temp);
method += temp; method += temp;
} }
@@ -344,9 +344,10 @@ private:
const CMvDatabaseEx *m_Database; const CMvDatabaseEx *m_Database;
const CRecordVector<bool> *m_ExtractStatuses; const CRecordVector<bool> *m_ExtractStatuses;
CByteBuffer TempBuf; Byte *TempBuf;
UInt32 TempBufSize;
int NumIdenticalFiles;
bool TempBufMode; bool TempBufMode;
bool IsSupported;
UInt32 m_BufStartFolderOffset; UInt32 m_BufStartFolderOffset;
int m_StartIndex; int m_StartIndex;
@@ -362,12 +363,21 @@ private:
UInt64 m_FolderSize; UInt64 m_FolderSize;
UInt64 m_PosInFolder; UInt64 m_PosInFolder;
void FreeTempBuf()
{
::MyFree(TempBuf);
TempBuf = NULL;
}
HRESULT OpenFile(); HRESULT OpenFile();
HRESULT CloseFileWithResOp(Int32 resOp);
HRESULT CloseFile(); HRESULT CloseFile();
HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK); HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK);
public: public:
HRESULT WriteEmptyFiles(); HRESULT WriteEmptyFiles();
CFolderOutStream(): TempBuf(NULL) {}
~CFolderOutStream() { FreeTempBuf(); }
void Init( void Init(
const CMvDatabaseEx *database, const CMvDatabaseEx *database,
const CRecordVector<bool> *extractStatuses, const CRecordVector<bool> *extractStatuses,
@@ -403,32 +413,33 @@ void CFolderOutStream::Init(
m_FileIsOpen = false; m_FileIsOpen = false;
m_IsOk = true; m_IsOk = true;
TempBufMode = false; TempBufMode = false;
NumIdenticalFiles = 0;
}
HRESULT CFolderOutStream::CloseFileWithResOp(Int32 resOp)
{
m_RealOutStream.Release();
m_FileIsOpen = false;
NumIdenticalFiles--;
return m_ExtractCallback->SetOperationResult(resOp);
} }
HRESULT CFolderOutStream::CloseFile() HRESULT CFolderOutStream::CloseFile()
{ {
m_RealOutStream.Release(); return CloseFileWithResOp(m_IsOk ?
HRESULT res = m_ExtractCallback->SetOperationResult(m_IsOk ?
NExtract::NOperationResult::kOK: NExtract::NOperationResult::kOK:
NExtract::NOperationResult::kDataError); NExtract::NOperationResult::kDataError);
m_FileIsOpen = false;
return res;
} }
HRESULT CFolderOutStream::OpenFile() HRESULT CFolderOutStream::OpenFile()
{ {
Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ? if (NumIdenticalFiles == 0)
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract) :
NExtract::NAskMode::kSkip;
if (!TempBufMode)
{ {
const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
int curIndex = m_CurrentIndex + 1; int numExtractItems = 0;
for (; curIndex < m_ExtractStatuses->Size(); curIndex++) int curIndex;
if ((*m_ExtractStatuses)[curIndex]) for (curIndex = m_CurrentIndex; curIndex < m_ExtractStatuses->Size(); curIndex++)
{ {
const CMvItem &mvItem2 = m_Database->Items[m_StartIndex + curIndex]; const CMvItem &mvItem2 = m_Database->Items[m_StartIndex + curIndex];
const CItem &item2 = m_Database->Volumes[mvItem2.VolumeIndex].Items[mvItem2.ItemIndex]; const CItem &item2 = m_Database->Volumes[mvItem2.VolumeIndex].Items[mvItem2.ItemIndex];
@@ -436,21 +447,46 @@ HRESULT CFolderOutStream::OpenFile()
item.Size != item2.Size || item.Size != item2.Size ||
item.Size == 0) item.Size == 0)
break; break;
if (!m_TestMode && (*m_ExtractStatuses)[curIndex])
numExtractItems++;
} }
if (curIndex > m_CurrentIndex + 1) NumIdenticalFiles = (curIndex - m_CurrentIndex);
if (NumIdenticalFiles == 0)
NumIdenticalFiles = 1;
TempBufMode = false;
if (numExtractItems > 1)
{ {
size_t oldCapacity = TempBuf.GetCapacity(); if (!TempBuf || item.Size > TempBufSize)
IsSupported = (item.Size <= kMaxTempBufSize);
if (item.Size > oldCapacity && IsSupported)
{ {
TempBuf.SetCapacity(0); FreeTempBuf();
TempBuf.SetCapacity(item.Size); TempBuf = (Byte *)MyAlloc(item.Size);
TempBufSize = item.Size;
if (TempBuf == NULL)
return E_OUTOFMEMORY;
} }
TempBufMode = true; TempBufMode = true;
m_BufStartFolderOffset = item.Offset; m_BufStartFolderOffset = item.Offset;
} }
else if (numExtractItems == 1)
{
while (NumIdenticalFiles && !(*m_ExtractStatuses)[m_CurrentIndex])
{
CMyComPtr<ISequentialOutStream> stream;
RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &stream, NExtract::NAskMode::kSkip));
if (stream)
return E_FAIL;
RINOK(m_ExtractCallback->PrepareOperation(NExtract::NAskMode::kSkip));
m_CurrentIndex++;
m_FileIsOpen = true;
CloseFile();
}
}
} }
Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract) :
NExtract::NAskMode::kSkip;
RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode)); RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode));
if (!m_RealOutStream && !m_TestMode) if (!m_RealOutStream && !m_TestMode)
askMode = NExtract::NAskMode::kSkip; askMode = NExtract::NAskMode::kSkip;
@@ -499,7 +535,7 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe
res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal); res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal);
numBytesToWrite = processedSizeLocal; numBytesToWrite = processedSizeLocal;
} }
if (TempBufMode && IsSupported) if (TempBufMode && TempBuf)
memcpy(TempBuf + (m_PosInFolder - m_BufStartFolderOffset), data, numBytesToWrite); memcpy(TempBuf + (m_PosInFolder - m_BufStartFolderOffset), data, numBytesToWrite);
} }
realProcessed += numBytesToWrite; realProcessed += numBytesToWrite;
@@ -513,39 +549,28 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe
return res; return res;
if (m_RemainFileSize == 0) if (m_RemainFileSize == 0)
{ {
m_RealOutStream.Release();
RINOK(CloseFile()); RINOK(CloseFile());
if (TempBufMode) while (NumIdenticalFiles)
{ {
while (m_CurrentIndex < m_ExtractStatuses->Size())
{
const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
if (item.Offset != m_BufStartFolderOffset)
break;
HRESULT result = OpenFile(); HRESULT result = OpenFile();
m_FileIsOpen = true; m_FileIsOpen = true;
m_CurrentIndex++; m_CurrentIndex++;
m_IsOk = true; if (result == S_OK && m_RealOutStream && TempBuf)
if (result == S_OK && m_RealOutStream && IsSupported) result = WriteStream(m_RealOutStream, TempBuf, (size_t)(m_PosInFolder - m_BufStartFolderOffset));
result = WriteStream(m_RealOutStream, TempBuf, item.Size);
if (IsSupported) if (!TempBuf && TempBufMode && m_RealOutStream)
{ {
RINOK(CloseFile()); RINOK(CloseFileWithResOp(NExtract::NOperationResult::kUnSupportedMethod));
RINOK(result);
} }
else else
{ {
m_RealOutStream.Release(); RINOK(CloseFile());
RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
m_FileIsOpen = false;
} }
RINOK(result);
} }
TempBufMode = false; TempBufMode = false;
} }
}
if (realProcessed > 0) if (realProcessed > 0)
break; // with this break this function works as Write-Part break; // with this break this function works as Write-Part
} }

View File

@@ -15,12 +15,9 @@ namespace NChm{
// define CHM_LOW, if you want to see low level items // define CHM_LOW, if you want to see low level items
// #define CHM_LOW // #define CHM_LOW
static const GUID kChmLzxGuid = static const GUID kChmLzxGuid = { 0x7FC28940, 0x9D31, 0x11D0, { 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C } };
{ 0x7FC28940, 0x9D31, 0x11D0, 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C }; static const GUID kHelp2LzxGuid = { 0x0A9007C6, 0x4076, 0x11D3, { 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 } };
static const GUID kHelp2LzxGuid = static const GUID kDesGuid = { 0x67F6E4A2, 0x60BF, 0x11D3, { 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF } };
{ 0x0A9007C6, 0x4076, 0x11D3, 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 };
static const GUID kDesGuid =
{ 0x67F6E4A2, 0x60BF, 0x11D3, 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF };
static bool AreGuidsEqual(REFGUID g1, REFGUID g2) static bool AreGuidsEqual(REFGUID g1, REFGUID g2)
{ {

View File

@@ -87,7 +87,7 @@ CCoderInfo2::CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams):
{ {
InSizes.Reserve(NumInStreams); InSizes.Reserve(NumInStreams);
InSizePointers.Reserve(NumInStreams); InSizePointers.Reserve(NumInStreams);
OutSizePointers.Reserve(NumOutStreams); OutSizes.Reserve(NumOutStreams);
OutSizePointers.Reserve(NumOutStreams); OutSizePointers.Reserve(NumOutStreams);
} }

View File

@@ -149,6 +149,16 @@ HRESULT CCoderMixer2MT::Init(ISequentialInStream **inStreams, ISequentialOutStre
_streamBinders[i].CreateStreams( _streamBinders[i].CreateStreams(
&_coders[inCoderIndex].InStreams[inCoderStreamIndex], &_coders[inCoderIndex].InStreams[inCoderStreamIndex],
&_coders[outCoderIndex].OutStreams[outCoderStreamIndex]); &_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);
}
} }
for (i = 0; i < _bindInfo.InStreams.Size(); i++) for (i = 0; i < _bindInfo.InStreams.Size(); i++)

View File

@@ -21,8 +21,10 @@ STDMETHODIMP CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSi
{ {
UInt32 realProcessedSize; UInt32 realProcessedSize;
HRESULT result = _stream->Read(data, size, &realProcessedSize); HRESULT result = _stream->Read(data, size, &realProcessedSize);
/*
if (size > 0 && realProcessedSize == 0) if (size > 0 && realProcessedSize == 0)
_wasFinished = true; _wasFinished = true;
*/
_size += realProcessedSize; _size += realProcessedSize;
_crc = CrcUpdate(_crc, data, realProcessedSize); _crc = CrcUpdate(_crc, data, realProcessedSize);
if(processedSize != NULL) if(processedSize != NULL)

View File

@@ -49,19 +49,19 @@ private:
CMyComPtr<IInStream> _stream; CMyComPtr<IInStream> _stream;
UInt64 _size; UInt64 _size;
UInt32 _crc; UInt32 _crc;
bool _wasFinished; // bool _wasFinished;
public: public:
void SetStream(IInStream *stream) { _stream = stream; } void SetStream(IInStream *stream) { _stream = stream; }
void Init() void Init()
{ {
_size = 0; _size = 0;
_wasFinished = false; // _wasFinished = false;
_crc = CRC_INIT_VAL; _crc = CRC_INIT_VAL;
} }
void ReleaseStream() { _stream.Release(); } void ReleaseStream() { _stream.Release(); }
UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
UInt64 GetSize() const { return _size; } UInt64 GetSize() const { return _size; }
bool WasFinished() const { return _wasFinished; } // bool WasFinished() const { return _wasFinished; }
}; };
#endif #endif

View File

@@ -2,6 +2,8 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "../../../../C/Types.h"
#include "ItemNameUtils.h" #include "ItemNameUtils.h"
namespace NArchive { namespace NArchive {

View File

@@ -6,73 +6,62 @@
STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize) STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize)
{ {
if(processedSize != NULL) if (processedSize)
*processedSize = 0; *processedSize = 0;
while(_streamIndex < Streams.Size() && size > 0) if (size == 0)
return S_OK;
if (_pos >= _totalLength)
return (_pos == _totalLength) ? S_OK : E_FAIL;
{ {
CSubStreamInfo &s = Streams[_streamIndex]; int left = 0, mid = _streamIndex, right = Streams.Size();
if (_pos == s.Size) for (;;)
{ {
_streamIndex++; CSubStreamInfo &m = Streams[mid];
_pos = 0; if (_pos < m.GlobalOffset)
continue; right = mid;
} else if (_pos >= m.GlobalOffset + m.Size)
RINOK(s.Stream->Seek(s.Pos + _pos, STREAM_SEEK_SET, 0)); left = mid + 1;
UInt32 sizeToRead = UInt32(MyMin((UInt64)size, s.Size - _pos)); else
UInt32 realProcessed; {
HRESULT result = s.Stream->Read(data, sizeToRead, &realProcessed); _streamIndex = mid;
data = (void *)((Byte *)data + realProcessed);
size -= realProcessed;
if(processedSize != NULL)
*processedSize += realProcessed;
_pos += realProcessed;
_seekPos += realProcessed;
RINOK(result);
break; break;
} }
return S_OK; mid = (left + right) / 2;
}
_streamIndex = mid;
} }
STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, CSubStreamInfo &s = Streams[_streamIndex];
UInt64 *newPosition) UInt64 localPos = _pos - s.GlobalOffset;
if (localPos != s.LocalPos)
{
RINOK(s.Stream->Seek(localPos, STREAM_SEEK_SET, &s.LocalPos));
}
UInt64 rem = s.Size - localPos;
if (size > rem)
size = (UInt32)rem;
HRESULT result = s.Stream->Read(data, size, &size);
_pos += size;
s.LocalPos += size;
if (processedSize)
*processedSize = size;
return result;
}
STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
{ {
UInt64 newPos;
switch(seekOrigin) switch(seekOrigin)
{ {
case STREAM_SEEK_SET: case STREAM_SEEK_SET: _pos = offset; break;
newPos = offset; case STREAM_SEEK_CUR: _pos = _pos + offset; break;
break; case STREAM_SEEK_END: _pos = _totalLength + offset; break;
case STREAM_SEEK_CUR: default: return STG_E_INVALIDFUNCTION;
newPos = _seekPos + offset;
break;
case STREAM_SEEK_END:
newPos = _totalLength + offset;
break;
default:
return STG_E_INVALIDFUNCTION;
} }
_seekPos = 0;
for (_streamIndex = 0; _streamIndex < Streams.Size(); _streamIndex++)
{
UInt64 size = Streams[_streamIndex].Size;
if (newPos < _seekPos + size)
{
_pos = newPos - _seekPos;
_seekPos += _pos;
if (newPosition != 0) if (newPosition != 0)
*newPosition = newPos; *newPosition = _pos;
return S_OK; return S_OK;
} }
_seekPos += size;
}
if (newPos == _seekPos)
{
if (newPosition != 0)
*newPosition = newPos;
return S_OK;
}
return E_FAIL;
}
/* /*

View File

@@ -1,36 +1,44 @@
// MultiStream.h // MultiStream.h
#ifndef __MULTISTREAM_H #ifndef __MULTI_STREAM_H
#define __MULTISTREAM_H #define __MULTI_STREAM_H
#include "../../../Common/MyCom.h" #include "../../../Common/MyCom.h"
#include "../../../Common/MyVector.h" #include "../../../Common/MyVector.h"
#include "../../Archive/IArchive.h"
#include "../../IStream.h"
class CMultiStream: class CMultiStream:
public IInStream, public IInStream,
public CMyUnknownImp public CMyUnknownImp
{ {
int _streamIndex;
UInt64 _pos; UInt64 _pos;
UInt64 _seekPos;
UInt64 _totalLength; UInt64 _totalLength;
int _streamIndex;
public: public:
struct CSubStreamInfo struct CSubStreamInfo
{ {
CMyComPtr<IInStream> Stream; CMyComPtr<IInStream> Stream;
UInt64 Pos;
UInt64 Size; UInt64 Size;
UInt64 GlobalOffset;
UInt64 LocalPos;
}; };
CObjectVector<CSubStreamInfo> Streams; CObjectVector<CSubStreamInfo> Streams;
void Init()
HRESULT Init()
{ {
_streamIndex = 0; UInt64 total = 0;
_pos = 0;
_seekPos = 0;
_totalLength = 0;
for (int i = 0; i < Streams.Size(); i++) for (int i = 0; i < Streams.Size(); i++)
_totalLength += Streams[i].Size; {
CSubStreamInfo &s = Streams[i];
s.GlobalOffset = total;
total += Streams[i].Size;
RINOK(s.Stream->Seek(0, STREAM_SEEK_CUR, &s.LocalPos));
}
_totalLength = total;
_pos = 0;
_streamIndex = 0;
return S_OK;
} }
MY_UNKNOWN_IMP1(IInStream) MY_UNKNOWN_IMP1(IInStream)

View File

@@ -3,8 +3,8 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "Common/ComTry.h" #include "Common/ComTry.h"
#include "Common/StringToInt.h"
#include "Common/StringConvert.h" #include "Common/StringConvert.h"
#include "Common/StringToInt.h"
#include "Windows/PropVariant.h" #include "Windows/PropVariant.h"
#include "Windows/Time.h" #include "Windows/Time.h"
@@ -25,10 +25,10 @@ namespace NFileHeader
{ {
namespace NMagic namespace NMagic
{ {
extern const char *kMagic1 = "070701"; const char *kMagic1 = "070701";
extern const char *kMagic2 = "070702"; const char *kMagic2 = "070702";
extern const char *kMagic3 = "070707"; const char *kMagic3 = "070707";
extern const char *kEndName = "TRAILER!!!"; const char *kEndName = "TRAILER!!!";
const Byte kMagicForRecord2[2] = { 0xC7, 0x71 }; const Byte kMagicForRecord2[2] = { 0xC7, 0x71 };
} }

View File

@@ -0,0 +1,644 @@
// CramfsHandler.cpp
#include "StdAfx.h"
#include "../../../C/7zCrc.h"
#include "../../../C/CpuArch.h"
#include "../../../C/Alloc.h"
#include "Common/ComTry.h"
#include "Common/StringConvert.h"
#include "Windows/PropVariantUtils.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamObjects.h"
#include "../Common/StreamUtils.h"
#include "../Compress/CopyCoder.h"
#include "../Compress/ZlibDecoder.h"
namespace NArchive {
namespace NCramfs {
#define SIGNATURE { 'C','o','m','p','r','e','s','s','e','d',' ','R','O','M','F','S' }
static const UInt32 kSignatureSize = 16;
static const char kSignature[kSignatureSize] = SIGNATURE;
static const UInt32 kArcSizeMax = (256 + 16) << 20;
static const UInt32 kNumFilesMax = (1 << 19);
static const unsigned kNumDirLevelsMax = (1 << 8);
static const UInt32 kHeaderSize = 0x40;
static const unsigned kHeaderNameSize = 16;
static const UInt32 kNodeSize = 12;
static const UInt32 kFlag_FsVer2 = (1 << 0);
static const CUInt32PCharPair k_Flags[] =
{
{ 0, "Ver2" },
{ 1, "SortedDirs" },
{ 8, "Holes" },
{ 9, "WrongSignature" },
{ 10, "ShiftedRootOffset" }
};
static const unsigned kBlockSizeLog = 12;
static const UInt32 kBlockSize = 1 << kBlockSizeLog;
/*
struct CNode
{
UInt16 Mode;
UInt16 Uid;
UInt32 Size;
Byte Gid;
UInt32 NameLen;
UInt32 Offset;
void Parse(const Byte *p)
{
Mode = GetUi16(p);
Uid = GetUi16(p + 2);
Size = Get32(p + 4) & 0xFFFFFF;
Gid = p[7];
NameLen = p[8] & 0x3F;
Offset = Get32(p + 8) >> 6;
}
};
*/
#define Get32(p) (be ? GetBe32(p) : GetUi32(p))
static UInt32 GetMode(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); }
static bool IsDir(const Byte *p, bool be) { return (GetMode(p, be) & 0xF000) == 0x4000; }
static UInt32 GetSize(const Byte *p, bool be)
{
if (be)
return GetBe32(p + 4) >> 8;
else
return GetUi32(p + 4) & 0xFFFFFF;
}
static UInt32 GetNameLen(const Byte *p, bool be)
{
if (be)
return (p[8] & 0xFC);
else
return (p[8] & 0x3F) << 2;
}
static UInt32 GetOffset(const Byte *p, bool be)
{
if (be)
return (GetBe32(p + 8) & 0x03FFFFFF) << 2;
else
return GetUi32(p + 8) >> 6 << 2;
}
struct CItem
{
UInt32 Offset;
int Parent;
};
struct CHeader
{
bool be;
UInt32 Size;
UInt32 Flags;
// UInt32 Future;
UInt32 Crc;
// UInt32 Edition;
UInt32 NumBlocks;
UInt32 NumFiles;
char Name[kHeaderNameSize];
bool Parse(const Byte *p)
{
if (memcmp(p + 16, kSignature, kSignatureSize) != 0)
return false;
switch(GetUi32(p))
{
case 0x28CD3D45: be = false; break;
case 0x453DCD28: be = true; break;
default: return false;
}
Size = Get32(p + 4);
Flags = Get32(p + 8);
// Future = Get32(p + 0xC);
Crc = Get32(p + 0x20);
// Edition = Get32(p + 0x24);
NumBlocks = Get32(p + 0x28);
NumFiles = Get32(p + 0x2C);
memcpy(Name, p + 0x30, kHeaderNameSize);
return true;
}
bool IsVer2() const { return (Flags & kFlag_FsVer2) != 0; }
};
class CHandler:
public IInArchive,
public IInArchiveGetStream,
public CMyUnknownImp
{
CRecordVector<CItem> _items;
CMyComPtr<IInStream> _stream;
Byte *_data;
UInt32 _size;
UInt32 _headersSize;
AString _errorMessage;
CHeader _h;
// Current file
NCompress::NZlib::CDecoder *_zlibDecoderSpec;
CMyComPtr<ICompressCoder> _zlibDecoder;
CBufInStream *_inStreamSpec;
CMyComPtr<ISequentialInStream> _inStream;
CBufPtrSeqOutStream *_outStreamSpec;
CMyComPtr<ISequentialOutStream> _outStream;
UInt32 _curBlocksOffset;
UInt32 _curNumBlocks;
HRESULT OpenDir(int parent, UInt32 baseOffsetBase, unsigned level);
HRESULT Open2(IInStream *inStream);
AString GetPath(int index) const;
bool GetPackSize(int index, UInt32 &res) const;
void Free();
public:
CHandler(): _data(0) {}
~CHandler() { Free(); }
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
};
static const STATPROPSTG kProps[] =
{
{ NULL, kpidPath, VT_BSTR},
{ NULL, kpidIsDir, VT_BOOL},
{ NULL, kpidSize, VT_UI4},
{ NULL, kpidPackSize, VT_UI4},
{ NULL, kpidPosixAttrib, VT_UI4}
// { NULL, kpidOffset, VT_UI4}
};
static const STATPROPSTG kArcProps[] =
{
{ NULL, kpidName, VT_BSTR},
{ NULL, kpidBigEndian, VT_BOOL},
{ NULL, kpidCharacts, VT_BSTR},
{ NULL, kpidPhySize, VT_UI4},
{ NULL, kpidHeadersSize, VT_UI4},
{ NULL, kpidNumSubFiles, VT_UI4},
{ NULL, kpidNumBlocks, VT_UI4}
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
HRESULT CHandler::OpenDir(int parent, UInt32 baseOffset, unsigned level)
{
const Byte *p = _data + baseOffset;
bool be = _h.be;
if (!IsDir(p, be))
return S_OK;
UInt32 offset = GetOffset(p, be);
UInt32 size = GetSize(p, be);
if (offset == 0 && size == 0)
return S_OK;
UInt32 end = offset + size;
if (offset < kHeaderSize || end > _size || level > kNumDirLevelsMax)
return S_FALSE;
if (end > _headersSize)
_headersSize = end;
int startIndex = _items.Size();
while (size != 0)
{
if (size < kNodeSize || (UInt32)_items.Size() >= kNumFilesMax)
return S_FALSE;
CItem item;
item.Parent = parent;
item.Offset = offset;
_items.Add(item);
UInt32 nodeLen = kNodeSize + GetNameLen(_data + offset, be);
if (size < nodeLen)
return S_FALSE;
offset += nodeLen;
size -= nodeLen;
}
int endIndex = _items.Size();
for (int i = startIndex; i < endIndex; i++)
{
RINOK(OpenDir(i, _items[i].Offset, level + 1));
}
return S_OK;
}
HRESULT CHandler::Open2(IInStream *inStream)
{
Byte buf[kHeaderSize];
RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize));
if (!_h.Parse(buf))
return S_FALSE;
if (_h.IsVer2())
{
if (_h.Size < kHeaderSize || _h.Size > kArcSizeMax || _h.NumFiles > kNumFilesMax)
return S_FALSE;
}
else
{
UInt64 size;
RINOK(inStream->Seek(0, STREAM_SEEK_END, &size));
if (size > kArcSizeMax)
return S_FALSE;
_h.Size = (UInt32)size;
RINOK(inStream->Seek(kHeaderSize, STREAM_SEEK_SET, NULL));
}
_data = (Byte *)MidAlloc(_h.Size);
if (_data == 0)
return E_OUTOFMEMORY;
memcpy(_data, buf, kHeaderSize);
size_t processed = _h.Size - kHeaderSize;
RINOK(ReadStream(inStream, _data + kHeaderSize, &processed));
if (processed < kNodeSize)
return S_FALSE;
_size = kHeaderSize + (UInt32)processed;
if (_size != _h.Size)
_errorMessage = "Unexpected end of archive";
else
{
SetUi32(_data + 0x20, 0);
if (_h.IsVer2())
if (CrcCalc(_data, _h.Size) != _h.Crc)
_errorMessage = "CRC error";
}
if (_h.IsVer2())
_items.Reserve(_h.NumFiles - 1);
return OpenDir(-1, kHeaderSize, 0);
}
AString CHandler::GetPath(int index) const
{
unsigned len = 0;
int indexMem = index;
do
{
const CItem &item = _items[index];
index = item.Parent;
const Byte *p = _data + item.Offset;
unsigned size = GetNameLen(p, _h.be);
p += kNodeSize;
unsigned i;
for (i = 0; i < size && p[i]; i++);
len += i + 1;
}
while (index >= 0);
len--;
AString path;
char *dest = path.GetBuffer(len) + len;
index = indexMem;
for (;;)
{
const CItem &item = _items[index];
index = item.Parent;
const Byte *p = _data + item.Offset;
unsigned size = GetNameLen(p, _h.be);
p += kNodeSize;
unsigned i;
for (i = 0; i < size && p[i]; i++);
dest -= i;
memcpy(dest, p, i);
if (index < 0)
break;
*(--dest) = CHAR_PATH_SEPARATOR;
}
path.ReleaseBuffer(len);
return path;
}
bool CHandler::GetPackSize(int index, UInt32 &res) const
{
const CItem &item = _items[index];
const Byte *p = _data + item.Offset;
bool be = _h.be;
UInt32 offset = GetOffset(p, be);
if (offset < kHeaderSize)
return false;
UInt32 numBlocks = (GetSize(p, be) + kBlockSize - 1) >> kBlockSizeLog;
UInt32 start = offset + numBlocks * 4;
if (start > _size)
return false;
UInt32 end = Get32(_data + start - 4);
if (end < start)
return false;
res = end - start;
return true;
}
STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */)
{
COM_TRY_BEGIN
{
Close();
RINOK(Open2(stream));
_stream = stream;
}
return S_OK;
COM_TRY_END
}
void CHandler::Free()
{
MidFree(_data);
_data = 0;
}
STDMETHODIMP CHandler::Close()
{
_headersSize = 0;
_items.Clear();
_stream.Release();
_errorMessage.Empty();
Free();
return S_OK;
}
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
*numItems = _items.Size();
return S_OK;
}
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
switch(propID)
{
case kpidName:
{
char dest[kHeaderNameSize + 4];
memcpy(dest, _h.Name, kHeaderNameSize);
dest[kHeaderNameSize] = 0;
prop = dest;
break;
}
case kpidBigEndian: prop = _h.be; break;
case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break;
case kpidNumBlocks: if (_h.IsVer2()) prop = _h.NumBlocks; break;
case kpidNumSubFiles: if (_h.IsVer2()) prop = _h.NumFiles; break;
case kpidPhySize: if (_h.IsVer2()) prop = _h.Size; break;
case kpidHeadersSize: prop = _headersSize; break;
case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
const CItem &item = _items[index];
const Byte *p = _data + item.Offset;
bool be = _h.be;
bool isDir = IsDir(p, be);
switch(propID)
{
case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break;
case kpidIsDir: prop = isDir; break;
// case kpidOffset: prop = (UInt32)GetOffset(p, be); break;
case kpidSize: if (!isDir) prop = GetSize(p, be); break;
case kpidPackSize:
if (!isDir)
{
UInt32 size;
if (GetPackSize(index, size))
prop = size;
}
break;
case kpidPosixAttrib: prop = (UInt32)GetMode(p, be); break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
class CCramfsInStream: public CCachedInStream
{
HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
public:
CHandler *Handler;
};
HRESULT CCramfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
{
return Handler->ReadBlock(blockIndex, dest, blockSize);
}
HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
{
if (!_zlibDecoder)
{
_zlibDecoderSpec = new NCompress::NZlib::CDecoder();
_zlibDecoder = _zlibDecoderSpec;
}
if (!_inStream)
{
_inStreamSpec = new CBufInStream();
_inStream = _inStreamSpec;
}
if (!_outStream)
{
_outStreamSpec = new CBufPtrSeqOutStream();
_outStream = _outStreamSpec;
}
bool be = _h.be;
const Byte *p = _data + (_curBlocksOffset + (UInt32)blockIndex * 4);
UInt32 start = (blockIndex == 0 ? _curBlocksOffset + _curNumBlocks * 4: Get32(p - 4));
UInt32 end = Get32(p);
if (end < start || end > _size)
return S_FALSE;
UInt32 inSize = end - start;
_inStreamSpec->Init(_data + start, inSize);
_outStreamSpec->Init(dest, blockSize);
RINOK(_zlibDecoder->Code(_inStream, _outStream, NULL, NULL, NULL));
return (_zlibDecoderSpec->GetInputProcessedSize() == inSize &&
_outStreamSpec->GetPos() == blockSize) ? S_OK : S_FALSE;
}
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
bool allFilesMode = (numItems == (UInt32)-1);
if (allFilesMode)
numItems = _items.Size();
if (numItems == 0)
return S_OK;
bool be = _h.be;
UInt64 totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
{
const Byte *p = _data + _items[allFilesMode ? i : indices[i]].Offset;
if (!IsDir(p, be))
totalSize += GetSize(p, be);
}
extractCallback->SetTotal(totalSize);
UInt64 totalPackSize;
totalSize = totalPackSize = 0;
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
CMyComPtr<ISequentialInStream> inStream(streamSpec);
streamSpec->SetStream(_stream);
for (i = 0; i < numItems; i++)
{
lps->InSize = totalPackSize;
lps->OutSize = totalSize;
RINOK(lps->SetCur());
CMyComPtr<ISequentialOutStream> outStream;
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
UInt32 index = allFilesMode ? i : indices[i];
const CItem &item = _items[index];
RINOK(extractCallback->GetStream(index, &outStream, askMode));
const Byte *p = _data + item.Offset;
if (IsDir(p, be))
{
RINOK(extractCallback->PrepareOperation(askMode));
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
continue;
}
UInt32 curSize = GetSize(p, be);
totalSize += curSize;
UInt32 packSize;
if (GetPackSize(index, packSize))
totalPackSize += packSize;
if (!testMode && !outStream)
continue;
RINOK(extractCallback->PrepareOperation(askMode));
UInt32 offset = GetOffset(p, be);
if (offset < kHeaderSize)
curSize = 0;
int res = NExtract::NOperationResult::kDataError;
{
CMyComPtr<ISequentialInStream> inSeqStream;
CMyComPtr<IInStream> inStream;
HRESULT hres = GetStream(index, &inSeqStream);
if (inSeqStream)
inSeqStream.QueryInterface(IID_IInStream, &inStream);
if (hres == E_OUTOFMEMORY)
return E_OUTOFMEMORY;
if (hres == S_FALSE || !inStream)
res = NExtract::NOperationResult::kUnSupportedMethod;
else
{
RINOK(hres);
if (inStream)
{
HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
if (hres != S_OK && hres != S_FALSE)
{
RINOK(hres);
}
if (copyCoderSpec->TotalSize == curSize && hres == S_OK)
res = NExtract::NOperationResult::kOK;
}
}
}
RINOK(extractCallback->SetOperationResult(res));
}
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
{
COM_TRY_BEGIN
const CItem &item = _items[index];
const Byte *p = _data + item.Offset;
bool be = _h.be;
if (IsDir(p, be))
return E_FAIL;
UInt32 size = GetSize(p, be);
UInt32 numBlocks = (size + kBlockSize - 1) >> kBlockSizeLog;
UInt32 offset = GetOffset(p, be);
if (offset < kHeaderSize)
{
if (offset != 0)
return S_FALSE;
CBufInStream *streamSpec = new CBufInStream;
CMyComPtr<IInStream> streamTemp = streamSpec;
streamSpec->Init(NULL, 0);
*stream = streamTemp.Detach();
return S_OK;
}
if (offset + numBlocks * 4 > _size)
return S_FALSE;
UInt32 prev = offset;
for (UInt32 i = 0; i < numBlocks; i++)
{
UInt32 next = Get32(_data + offset + i * 4);
if (next < prev || next > _size)
return S_FALSE;
prev = next;
}
CCramfsInStream *streamSpec = new CCramfsInStream;
CMyComPtr<IInStream> streamTemp = streamSpec;
_curNumBlocks = numBlocks;
_curBlocksOffset = offset;
streamSpec->Handler = this;
if (!streamSpec->Alloc(kBlockSizeLog, 21 - kBlockSizeLog))
return E_OUTOFMEMORY;
streamSpec->Init(size);
*stream = streamTemp.Detach();
return S_OK;
COM_TRY_END
}
static IInArchive *CreateArc() { return new NArchive::NCramfs::CHandler; }
static CArcInfo g_ArcInfo =
{ L"CramFS", L"cramfs", 0, 0xD3, SIGNATURE, kSignatureSize, false, CreateArc, 0 };
REGISTER_ARC(Cramfs)
}}

View File

@@ -3,8 +3,6 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "Common/ComTry.h" #include "Common/ComTry.h"
#include "Common/Defs.h"
#include "Common/NewHandler.h"
#include "Common/StringConvert.h" #include "Common/StringConvert.h"
#include "Common/StringToInt.h" #include "Common/StringToInt.h"

View File

@@ -277,9 +277,9 @@ static const CUInt32PCharPair g_AbiOS[] =
static const CUInt32PCharPair g_SegmentFlags[] = static const CUInt32PCharPair g_SegmentFlags[] =
{ {
{ 1 << 0, "Execute" }, { 0, "Execute" },
{ 1 << 1, "Write" }, { 1, "Write" },
{ 1 << 2, "Read" } { 2, "Read" }
}; };
static const char *g_Types[] = static const char *g_Types[] =

View File

@@ -526,7 +526,14 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level)
item.Attrib = attrib; item.Attrib = attrib;
item.Flags = p[12]; item.Flags = p[12];
item.Size = Get32(p + 28); item.Size = Get32(p + 28);
item.Cluster = Get16(p + 26) | ((UInt32)Get16(p + 20) << 16); item.Cluster = Get16(p + 26);
if (Header.NumFatBits > 16)
item.Cluster |= ((UInt32)Get16(p + 20) << 16);
else
{
// OS/2 and WinNT probably can store EA (extended atributes) in that field.
}
item.CTime = Get32(p + 14); item.CTime = Get32(p + 14);
item.CTime2 = p[13]; item.CTime2 = p[13];
item.ADate = Get16(p + 18); item.ADate = Get16(p + 18);
@@ -578,8 +585,12 @@ HRESULT CDatabase::Open()
return S_FALSE; return S_FALSE;
UInt64 fileSize; UInt64 fileSize;
RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize)); RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize));
/* we comment that check to support truncated images */
/*
if (fileSize < Header.GetPhySize()) if (fileSize < Header.GetPhySize())
return S_FALSE; return S_FALSE;
*/
if (Header.IsFat32()) if (Header.IsFat32())
{ {

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -3,9 +3,7 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "Common/ComTry.h" #include "Common/ComTry.h"
#include "Common/Defs.h"
#include "Common/IntToString.h" #include "Common/IntToString.h"
#include "Common/NewHandler.h"
#include "Common/StringConvert.h" #include "Common/StringConvert.h"
#include "Windows/PropVariant.h" #include "Windows/PropVariant.h"
@@ -26,7 +24,7 @@ using namespace NTime;
namespace NArchive { namespace NArchive {
namespace NIso { namespace NIso {
STATPROPSTG kProps[] = static const STATPROPSTG kProps[] =
{ {
{ NULL, kpidPath, VT_BSTR}, { NULL, kpidPath, VT_BSTR},
{ NULL, kpidIsDir, VT_BOOL}, { NULL, kpidIsDir, VT_BOOL},
@@ -35,8 +33,17 @@ STATPROPSTG kProps[] =
{ NULL, kpidMTime, VT_FILETIME} { NULL, kpidMTime, VT_FILETIME}
}; };
static const STATPROPSTG kArcProps[] =
{
{ NULL, kpidComment, VT_BSTR},
{ NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidMTime, VT_FILETIME}
// { NULL, kpidPhySize, VT_UI8},
// { NULL, kpidHeadersSize, VT_UI8}
};
IMP_IInArchive_Props IMP_IInArchive_Props
IMP_IInArchive_ArcProps_NO IMP_IInArchive_ArcProps
STDMETHODIMP CHandler::Open(IInStream *stream, STDMETHODIMP CHandler::Open(IInStream *stream,
const UInt64 * /* maxCheckStartPosition */, const UInt64 * /* maxCheckStartPosition */,
@@ -68,6 +75,58 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK; return S_OK;
} }
static void AddString(AString &s, const char *name, const Byte *p, int size)
{
int i;
for (i = 0; i < size && p[i]; i++);
for (; i > 0 && p[i - 1] == ' '; i--);
if (i != 0)
{
AString d;
memcpy(d.GetBuffer(i), p, i);
d.ReleaseBuffer(i);
s += '\n';
s += name;
s += ": ";
s += d;
}
}
#define ADD_STRING(n, v) AddString(s, n, vol. ## v, sizeof(vol. ## v))
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
const CVolumeDescriptor &vol = _archive.VolDescs[_archive.MainVolDescIndex];
switch(propID)
{
case kpidComment:
{
AString s;
ADD_STRING("System", SystemId);
ADD_STRING("Volume", VolumeId);
ADD_STRING("VolumeSet", VolumeSetId);
ADD_STRING("Publisher", PublisherId);
ADD_STRING("Preparer", DataPreparerId);
ADD_STRING("Application", ApplicationId);
ADD_STRING("Copyright", CopyrightFileId);
ADD_STRING("Abstract", AbstractFileId);
ADD_STRING("Bib", BibFileId);
prop = s;
break;
}
case kpidCTime: { FILETIME utc; if (vol.CTime.GetFileTime(utc)) prop = utc; break; }
case kpidMTime: { FILETIME utc; if (vol.MTime.GetFileTime(utc)) prop = utc; break; }
// case kpidPhySize: break;
// case kpidHeadersSize: break;
case kpidError: if (_archive.IncorrectBigEndian) prop = "Incorrect big-endian headers"; break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{ {
COM_TRY_BEGIN COM_TRY_BEGIN
@@ -89,9 +148,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = (const wchar_t *)s; prop = (const wchar_t *)s;
break; break;
} }
case kpidIsDir: case kpidIsDir: prop = false; break;
prop = false;
break;
case kpidSize: case kpidSize:
case kpidPackSize: case kpidPackSize:
prop = (UInt64)_archive.GetBootItemSize(index); prop = (UInt64)_archive.GetBootItemSize(index);
@@ -123,9 +180,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = (const wchar_t *)NItemName::GetOSName2(s); prop = (const wchar_t *)NItemName::GetOSName2(s);
} }
break; break;
case kpidIsDir: case kpidIsDir: prop = item.IsDir(); break;
prop = item.IsDir();
break;
case kpidSize: case kpidSize:
case kpidPackSize: case kpidPackSize:
if (!item.IsDir()) if (!item.IsDir())
@@ -133,16 +188,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
break; break;
case kpidMTime: case kpidMTime:
{ {
FILETIME utcFileTime; FILETIME utc;
if (item.DateTime.GetFileTime(utcFileTime)) if (item.DateTime.GetFileTime(utc))
prop = utcFileTime; prop = utc;
/*
else
{
utcFileTime.dwLowDateTime = 0;
utcFileTime.dwHighDateTime = 0;
}
*/
break; break;
} }
} }

View File

@@ -65,7 +65,7 @@ UInt16 CInArchive::ReadUInt16()
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
if (b[i] != b[3 - i]) if (b[i] != b[3 - i])
throw 1; IncorrectBigEndian = true;
value |= ((UInt16)(b[i]) << (8 * i)); value |= ((UInt16)(b[i]) << (8 * i));
} }
return (UInt16)value; return (UInt16)value;
@@ -440,6 +440,7 @@ HRESULT CInArchive::Open(IInStream *inStream)
void CInArchive::Clear() void CInArchive::Clear()
{ {
IncorrectBigEndian = false;
Refs.Clear(); Refs.Clear();
_rootDir.Clear(); _rootDir.Clear();
VolDescs.Clear(); VolDescs.Clear();

View File

@@ -111,6 +111,20 @@ struct CDateTime
signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded. signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded.
bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 && bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 &&
Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; } Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; }
bool GetFileTime(FILETIME &ft) const
{
UInt64 value;
bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, value);
if (res)
{
value -= (UInt64)((Int64)GmtOffset * 15 * 60);
value *= 10000000;
}
ft.dwLowDateTime = (DWORD)value;
ft.dwHighDateTime = (DWORD)(value >> 32);
return res;
}
}; };
struct CBootRecordDescriptor struct CBootRecordDescriptor
@@ -268,6 +282,7 @@ public:
int MainVolDescIndex; int MainVolDescIndex;
UInt32 BlockSize; UInt32 BlockSize;
CObjectVector<CBootInitialEntry> BootEntries; CObjectVector<CBootInitialEntry> BootEntries;
bool IncorrectBigEndian;
bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); } bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); }

View File

@@ -8,6 +8,6 @@
static IInArchive *CreateArc() { return new NArchive::NIso::CHandler; } static IInArchive *CreateArc() { return new NArchive::NIso::CHandler; }
static CArcInfo g_ArcInfo = static CArcInfo g_ArcInfo =
{ L"Iso", L"iso", 0, 0xE7, { 'C', 'D', '0', '0', '1', 0x1 }, 7, false, CreateArc, 0 }; { L"Iso", L"iso img", 0, 0xE7, { 'C', 'D', '0', '0', '1', 0x1 }, 7, false, CreateArc, 0 };
REGISTER_ARC(Iso) REGISTER_ARC(Iso)

View File

@@ -266,7 +266,7 @@ HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
return (startHeader[0] == 0) ? S_OK: S_FALSE; return (startHeader[0] == 0) ? S_OK: S_FALSE;
const Byte *p = header; const Byte *p = header;
memmove(item.Method, p, kMethodIdSize); memcpy(item.Method, p, kMethodIdSize);
if (!item.IsValidMethod()) if (!item.IsValidMethod())
return S_OK; return S_OK;
p += kMethodIdSize; p += kMethodIdSize;
@@ -378,7 +378,7 @@ static const char *GetOS(Byte osId)
if (g_OsPairs[i].Id == osId) if (g_OsPairs[i].Id == osId)
return g_OsPairs[i].Name; return g_OsPairs[i].Name;
return kUnknownOS; return kUnknownOS;
}; }
static STATPROPSTG kProps[] = static STATPROPSTG kProps[] =
{ {
@@ -400,7 +400,7 @@ public:
static UInt16 Table[256]; static UInt16 Table[256];
static void InitTable(); static void InitTable();
CCRC(): _value(0){}; CCRC(): _value(0) {}
void Init() { _value = 0; } void Init() { _value = 0; }
void Update(const void *data, size_t size); void Update(const void *data, size_t size);
UInt16 GetDigest() const { return _value; } UInt16 GetDigest() const { return _value; }
@@ -460,7 +460,6 @@ public:
void ReleaseStream() { _stream.Release(); } void ReleaseStream() { _stream.Release(); }
UInt32 GetCRC() const { return _crc.GetDigest(); } UInt32 GetCRC() const { return _crc.GetDigest(); }
void InitCRC() { _crc.Init(); } void InitCRC() { _crc.Init(); }
}; };
STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize) STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)
@@ -646,7 +645,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
totalUnPacked += item.Size; totalUnPacked += item.Size;
totalPacked += item.PackSize; totalPacked += item.PackSize;
} }
extractCallback->SetTotal(totalUnPacked); RINOK(extractCallback->SetTotal(totalUnPacked));
UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0; UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;
UInt64 currentItemUnPacked, currentItemPacked; UInt64 currentItemUnPacked, currentItemPacked;

View File

@@ -41,7 +41,7 @@ namespace NMacho {
#define MACH_SECT_ATTR_ZEROFILL 1 #define MACH_SECT_ATTR_ZEROFILL 1
const char *g_SectTypes[] = static const char *g_SectTypes[] =
{ {
"REGULAR", "REGULAR",
"ZEROFILL", "ZEROFILL",
@@ -60,7 +60,7 @@ const char *g_SectTypes[] =
"16BYTE_LITERALS" "16BYTE_LITERALS"
}; };
const char *g_FileTypes[] = static const char *g_FileTypes[] =
{ {
"0", "0",
"OBJECT", "OBJECT",
@@ -77,16 +77,16 @@ const char *g_FileTypes[] =
static const CUInt32PCharPair g_Flags[] = static const CUInt32PCharPair g_Flags[] =
{ {
{ (UInt32)1 << 31, "PURE_INSTRUCTIONS" }, { 31, "PURE_INSTRUCTIONS" },
{ 1 << 30, "NO_TOC" }, { 30, "NO_TOC" },
{ 1 << 29, "STRIP_STATIC_SYMS" }, { 29, "STRIP_STATIC_SYMS" },
{ 1 << 28, "NO_DEAD_STRIP" }, { 28, "NO_DEAD_STRIP" },
{ 1 << 27, "LIVE_SUPPORT" }, { 27, "LIVE_SUPPORT" },
{ 1 << 26, "SELF_MODIFYING_CODE" }, { 26, "SELF_MODIFYING_CODE" },
{ 1 << 25, "DEBUG" }, { 25, "DEBUG" },
{ 1 << 10, "SOME_INSTRUCTIONS" }, { 10, "SOME_INSTRUCTIONS" },
{ 1 << 9, "EXT_RELOC" }, { 9, "EXT_RELOC" },
{ 1 << 8, "LOC_RELOC" } { 8, "LOC_RELOC" }
}; };
static const CUInt32PCharPair g_MachinePairs[] = static const CUInt32PCharPair g_MachinePairs[] =
@@ -111,11 +111,18 @@ struct CSection
char Name[kNameSize]; char Name[kNameSize];
char SegName[kNameSize]; char SegName[kNameSize];
UInt64 Va; UInt64 Va;
UInt64 Size; UInt64 Pa;
UInt32 Pa; UInt64 VSize;
UInt64 PSize;
UInt32 Flags; UInt32 Flags;
int SegmentIndex; int SegmentIndex;
UInt64 GetPackSize() const { return Flags == MACH_SECT_ATTR_ZEROFILL ? 0 : Size; }
bool IsDummy;
CSection(): IsDummy(false) {}
// UInt64 GetPackSize() const { return Flags == MACH_SECT_ATTR_ZEROFILL ? 0 : Size; }
UInt64 GetPackSize() const { return PSize; }
}; };
@@ -195,8 +202,9 @@ bool CHandler::Parse(const Byte *buf, UInt32 size)
if (cmdSize < offs) if (cmdSize < offs)
break; break;
{
UInt64 vmAddr, vmSize, phAddr, phSize; UInt64 vmAddr, vmSize, phAddr, phSize;
{
if (cmd == MACH_CMD_SEGMENT_64) if (cmd == MACH_CMD_SEGMENT_64)
{ {
vmAddr = Get64(buf + 0x18, be); vmAddr = Get64(buf + 0x18, be);
@@ -226,7 +234,19 @@ bool CHandler::Parse(const Byte *buf, UInt32 size)
if (numSections > (1 << 8)) if (numSections > (1 << 8))
return false; return false;
while (numSections-- != 0) if (numSections == 0)
{
CSection section;
section.IsDummy = true;
section.SegmentIndex = _segments.Size() - 1;
section.Va = vmAddr;
section.PSize = phSize;
section.VSize = vmSize;
section.Pa = phAddr;
section.Flags = 0;
_sections.Add(section);
}
else do
{ {
CSection section; CSection section;
UInt32 headerSize = (cmd == MACH_CMD_SEGMENT_64) ? 0x50 : 0x44; UInt32 headerSize = (cmd == MACH_CMD_SEGMENT_64) ? 0x50 : 0x44;
@@ -236,23 +256,29 @@ bool CHandler::Parse(const Byte *buf, UInt32 size)
if (cmd == MACH_CMD_SEGMENT_64) if (cmd == MACH_CMD_SEGMENT_64)
{ {
section.Va = Get64(p + 0x20, be); section.Va = Get64(p + 0x20, be);
section.Size = Get64(p + 0x28, be); section.VSize = Get64(p + 0x28, be);
section.Pa = Get32(p + 0x30, be); section.Pa = Get32(p + 0x30, be);
section.Flags = Get32(p + 0x40, be); section.Flags = Get32(p + 0x40, be);
} }
else else
{ {
section.Va = Get32(p + 0x20, be); section.Va = Get32(p + 0x20, be);
section.Size = Get32(p + 0x24, be); section.VSize = Get32(p + 0x24, be);
section.Pa = Get32(p + 0x28, be); section.Pa = Get32(p + 0x28, be);
section.Flags = Get32(p + 0x38, be); section.Flags = Get32(p + 0x38, be);
} }
if (section.Flags == MACH_SECT_ATTR_ZEROFILL)
section.PSize = 0;
else
section.PSize = section.VSize;
memcpy(section.Name, p, kNameSize); memcpy(section.Name, p, kNameSize);
memcpy(section.SegName, p + kNameSize, kNameSize); memcpy(section.SegName, p + kNameSize, kNameSize);
section.SegmentIndex = _segments.Size() - 1; section.SegmentIndex = _segments.Size() - 1;
_sections.Add(section); _sections.Add(section);
offs += headerSize; offs += headerSize;
} }
while (--numSections);
if (offs != cmdSize) if (offs != cmdSize)
return false; return false;
} }
@@ -263,7 +289,7 @@ bool CHandler::Parse(const Byte *buf, UInt32 size)
return reduceCommands || (size == 0); return reduceCommands || (size == 0);
} }
STATPROPSTG kArcProps[] = static STATPROPSTG kArcProps[] =
{ {
{ NULL, kpidCpu, VT_BSTR}, { NULL, kpidCpu, VT_BSTR},
{ NULL, kpidBit64, VT_BOOL}, { NULL, kpidBit64, VT_BOOL},
@@ -273,7 +299,7 @@ STATPROPSTG kArcProps[] =
{ NULL, kpidHeadersSize, VT_UI4} { NULL, kpidHeadersSize, VT_UI4}
}; };
STATPROPSTG kProps[] = static STATPROPSTG kProps[] =
{ {
{ NULL, kpidPath, VT_BSTR}, { NULL, kpidPath, VT_BSTR},
{ NULL, kpidSize, VT_UI8}, { NULL, kpidSize, VT_UI8},
@@ -333,10 +359,17 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
const CSection &item = _sections[index]; const CSection &item = _sections[index];
switch(propID) switch(propID)
{ {
case kpidPath: StringToProp(GetName(_segments[item.SegmentIndex].Name) + GetName(item.Name), prop); break; case kpidPath:
case kpidSize: prop = (UInt64)item.Size; break; {
AString s = GetName(_segments[item.SegmentIndex].Name);
if (!item.IsDummy)
s += GetName(item.Name);
StringToProp(s, prop);
break;
}
case kpidSize: /* prop = (UInt64)item.VSize; break; */
case kpidPackSize: prop = (UInt64)item.GetPackSize(); break; case kpidPackSize: prop = (UInt64)item.GetPackSize(); break;
case kpidCharacts: StringToProp(SectFlagsToString(item.Flags), prop); break; case kpidCharacts: if (!item.IsDummy) StringToProp(SectFlagsToString(item.Flags), prop); break;
case kpidOffset: prop = item.Pa; break; case kpidOffset: prop = item.Pa; break;
case kpidVa: prop = item.Va; break; case kpidVa: prop = item.Va; break;
} }

View File

@@ -332,7 +332,7 @@ enum
{ {
kpidPrimary = kpidUserDefined, kpidPrimary = kpidUserDefined,
kpidBegChs, kpidBegChs,
kpidEndChs, kpidEndChs
}; };
STATPROPSTG kProps[] = STATPROPSTG kProps[] =

View File

@@ -7,15 +7,14 @@
#include "../../Common/StreamUtils.h" #include "../../Common/StreamUtils.h"
#include "../../Common/MethodId.h" #include "../../Common/MethodId.h"
#include "../../Common/CreateCoder.h"
#include "../../Compress/BZip2Decoder.h"
#include "../../Compress/DeflateDecoder.h"
#include "../../Compress/LzmaDecoder.h"
namespace NArchive { namespace NArchive {
namespace NNsis { namespace NNsis {
static const CMethodId k_Copy = 0x0;
static const CMethodId k_Deflate = 0x040901;
static const CMethodId k_BZip2 = 0x040902;
static const CMethodId k_LZMA = 0x030101;
static const CMethodId k_BCJ_X86 = 0x03030103; static const CMethodId k_BCJ_X86 = 0x03030103;
HRESULT CDecoder::Init( HRESULT CDecoder::Init(
@@ -31,24 +30,14 @@ HRESULT CDecoder::Init(
_method = method; _method = method;
if (!_codecInStream) if (!_codecInStream)
{ {
CMethodId methodID;
switch (method) switch (method)
{ {
case NMethodType::kCopy: methodID = k_Copy; break; // case NMethodType::kCopy: return E_NOTIMPL;
case NMethodType::kDeflate: methodID = k_Deflate; break; case NMethodType::kDeflate: _codecInStream = new NCompress::NDeflate::NDecoder::CNsisCOMCoder(); break;
case NMethodType::kBZip2: methodID = k_BZip2; break; case NMethodType::kBZip2: _codecInStream = new NCompress::NBZip2::CNsisDecoder(); break;
case NMethodType::kLZMA: methodID = k_LZMA; break; case NMethodType::kLZMA: _codecInStream = new NCompress::NLzma::CDecoder(); break;
default: return E_NOTIMPL; default: return E_NOTIMPL;
} }
CMyComPtr<ICompressCoder> coder;
RINOK(CreateCoder(
EXTERNAL_CODECS_LOC_VARS
methodID, coder, false));
if (!coder)
return E_NOTIMPL;
coder.QueryInterface(IID_ISequentialInStream, &_codecInStream);
if (!_codecInStream)
return E_NOTIMPL;
} }
if (thereIsFilterFlag) if (thereIsFilterFlag)

View File

@@ -6,7 +6,6 @@
#include "Common/ComTry.h" #include "Common/ComTry.h"
#include "Common/IntToString.h" #include "Common/IntToString.h"
#include "Common/NewHandler.h"
#include "Windows/PropVariant.h" #include "Windows/PropVariant.h"
@@ -23,20 +22,20 @@ using namespace NWindows;
namespace NArchive { namespace NArchive {
namespace NNsis { namespace NNsis {
static const wchar_t *kBcjMethod = L"BCJ"; static const char *kBcjMethod = "BCJ";
static const wchar_t *kUnknownMethod = L"Unknown"; static const char *kUnknownMethod = "Unknown";
static const wchar_t *kMethods[] = static const char *kMethods[] =
{ {
L"Copy", "Copy",
L"Deflate", "Deflate",
L"BZip2", "BZip2",
L"LZMA" "LZMA"
}; };
static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]); static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]);
STATPROPSTG kProps[] = static STATPROPSTG kProps[] =
{ {
{ NULL, kpidPath, VT_BSTR}, { NULL, kpidPath, VT_BSTR},
{ NULL, kpidSize, VT_UI8}, { NULL, kpidSize, VT_UI8},
@@ -46,7 +45,7 @@ STATPROPSTG kProps[] =
{ NULL, kpidSolid, VT_BOOL} { NULL, kpidSolid, VT_BOOL}
}; };
STATPROPSTG kArcProps[] = static STATPROPSTG kArcProps[] =
{ {
{ NULL, kpidMethod, VT_BSTR}, { NULL, kpidMethod, VT_BSTR},
{ NULL, kpidSolid, VT_BOOL} { NULL, kpidSolid, VT_BOOL}
@@ -116,50 +115,45 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK; return S_OK;
} }
static UString ConvertUInt32ToString(UInt32 value) static AString UInt32ToString(UInt32 value)
{ {
wchar_t buffer[32]; char buffer[16];
ConvertUInt64ToString(value, buffer); ConvertUInt32ToString(value, buffer);
return buffer; return buffer;
} }
static UString GetStringForSizeValue(UInt32 value) static AString GetStringForSizeValue(UInt32 value)
{ {
for (int i = 31; i >= 0; i--) for (int i = 31; i >= 0; i--)
if ((UInt32(1) << i) == value) if (((UInt32)1 << i) == value)
return ConvertUInt32ToString(i); return UInt32ToString(i);
UString result; char c = 'b';
if (value % (1 << 20) == 0) if (value % (1 << 20) == 0)
{ {
result += ConvertUInt32ToString(value >> 20); value >>= 20;
result += L"m"; c = 'm';
} }
else if (value % (1 << 10) == 0) else if (value % (1 << 10) == 0)
{ {
result += ConvertUInt32ToString(value >> 10); value >>= 10;
result += L"k"; c = 'k';
} }
else return UInt32ToString(value) + c;
{
result += ConvertUInt32ToString(value);
result += L"b";
}
return result;
} }
UString CHandler::GetMethod(bool useItemFilter, UInt32 dictionary) const AString CHandler::GetMethod(bool useItemFilter, UInt32 dictionary) const
{ {
NMethodType::EEnum methodIndex = _archive.Method; NMethodType::EEnum methodIndex = _archive.Method;
UString method; AString method;
if (_archive.IsSolid && _archive.UseFilter || !_archive.IsSolid && useItemFilter) if (_archive.IsSolid && _archive.UseFilter || !_archive.IsSolid && useItemFilter)
{ {
method += kBcjMethod; method += kBcjMethod;
method += L" "; method += ' ';
} }
method += (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod; method += (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod;
if (methodIndex == NMethodType::kLZMA) if (methodIndex == NMethodType::kLZMA)
{ {
method += L":"; method += ':';
method += GetStringForSizeValue(_archive.IsSolid ? _archive.DictionarySize: dictionary); method += GetStringForSizeValue(_archive.IsSolid ? _archive.DictionarySize: dictionary);
} }
return method; return method;
@@ -319,6 +313,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
byteBuf.SetCapacity(kBufferLength); byteBuf.SetCapacity(kBufferLength);
Byte *buffer = byteBuf; Byte *buffer = byteBuf;
CByteBuffer tempBuf;
bool dataError = false; bool dataError = false;
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
{ {
@@ -363,6 +359,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
bool sizeIsKnown = false; bool sizeIsKnown = false;
UInt32 fullSize = 0; UInt32 fullSize = 0;
bool writeToTemp = false;
bool readFromTemp = false;
if (_archive.IsSolid) if (_archive.IsSolid)
{ {
UInt64 pos = _archive.GetPosOfSolidItem(index); UInt64 pos = _archive.GetPosOfSolidItem(index);
@@ -395,8 +394,21 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
fullSize = Get32(buffer2); fullSize = Get32(buffer2);
sizeIsKnown = true; sizeIsKnown = true;
needDecompress = true; needDecompress = true;
if (!testMode && i + 1 < numItems)
{
UInt64 nextPos = _archive.GetPosOfSolidItem(allFilesMode ? i : indices[i + 1]);
if (nextPos < streamPos + fullSize)
{
tempBuf.Free();
tempBuf.SetCapacity(fullSize);
writeToTemp = true;
} }
} }
}
else
readFromTemp = true;
}
else else
{ {
RINOK(_inStream->Seek(_archive.GetPosOfNonSolidItem(index) + 4, STREAM_SEEK_SET, NULL)); RINOK(_inStream->Seek(_archive.GetPosOfNonSolidItem(index) + 4, STREAM_SEEK_SET, NULL));
@@ -440,6 +452,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
break; break;
} }
if (writeToTemp)
memcpy((Byte *)tempBuf + (size_t)offset, buffer, processedSize);
fullSize -= (UInt32)processedSize; fullSize -= (UInt32)processedSize;
streamPos += processedSize; streamPos += processedSize;
offset += processedSize; offset += processedSize;
@@ -456,6 +471,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
} }
else else
{ {
if (readFromTemp)
{
if (!testMode)
RINOK(WriteStream(realOutStream, tempBuf, tempBuf.GetCapacity()));
}
else
while (fullSize > 0) while (fullSize > 0)
{ {
UInt32 curSize = MyMin(fullSize, kBufferLength); UInt32 curSize = MyMin(fullSize, kBufferLength);

View File

@@ -26,7 +26,7 @@ class CHandler:
bool GetUncompressedSize(int index, UInt32 &size); bool GetUncompressedSize(int index, UInt32 &size);
bool GetCompressedSize(int index, UInt32 &size); bool GetCompressedSize(int index, UInt32 &size);
UString GetMethod(bool useItemFilter, UInt32 dictionary) const; AString GetMethod(bool useItemFilter, UInt32 dictionary) const;
public: public:
MY_QUERYINTERFACE_BEGIN2(IInArchive) MY_QUERYINTERFACE_BEGIN2(IInArchive)
QUERY_ENTRY_ISetCompressCodecsInfo QUERY_ENTRY_ISetCompressCodecsInfo

View File

@@ -1151,16 +1151,25 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
bool sameName = IsUnicode ? bool sameName = IsUnicode ?
(Items[i].NameU == Items[i + 1].NameU) : (Items[i].NameU == Items[i + 1].NameU) :
(Items[i].NameA == Items[i + 1].NameA); (Items[i].NameA == Items[i + 1].NameA);
if (Items[i].Pos == Items[i + 1].Pos && (IsSolid || sameName)) if (Items[i].Pos == Items[i + 1].Pos && sameName)
Items.Delete(i + 1); Items.Delete(i + 1);
else else
i++; i++;
} }
for (i = 0; i + 1 < Items.Size(); i++) for (i = 0; i < Items.Size(); i++)
{ {
CItem &item = Items[i]; CItem &item = Items[i];
UInt32 curPos = item.Pos + 4;
for (int nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++)
{
UInt32 nextPos = Items[nextIndex].Pos;
if (curPos <= nextPos)
{
item.EstimatedSizeIsDefined = true; item.EstimatedSizeIsDefined = true;
item.EstimatedSize = Items[i + 1].Pos - item.Pos - 4; item.EstimatedSize = nextPos - curPos;
break;
}
}
} }
if (!IsSolid) if (!IsSolid)
{ {
@@ -1275,6 +1284,11 @@ static bool IsLZMA(const Byte *p, UInt32 &dictionary, bool &thereIsFlag)
return false; return false;
} }
static bool IsBZip2(const Byte *p)
{
return (p[0] == 0x31 && p[1] < 14);
}
HRESULT CInArchive::Open2( HRESULT CInArchive::Open2(
DECL_EXTERNAL_CODECS_LOC_VARS2 DECL_EXTERNAL_CODECS_LOC_VARS2
) )
@@ -1290,6 +1304,7 @@ HRESULT CInArchive::Open2(
_headerIsCompressed = true; _headerIsCompressed = true;
IsSolid = true; IsSolid = true;
FilterFlag = false; FilterFlag = false;
DictionarySize = 1;
UInt32 compressedHeaderSize = Get32(sig); UInt32 compressedHeaderSize = Get32(sig);
@@ -1311,8 +1326,15 @@ HRESULT CInArchive::Open2(
else if (sig[3] == 0x80) else if (sig[3] == 0x80)
{ {
IsSolid = false; IsSolid = false;
if (IsBZip2(sig + 4))
Method = NMethodType::kBZip2;
else
Method = NMethodType::kDeflate; Method = NMethodType::kDeflate;
} }
else if (IsBZip2(sig))
{
Method = NMethodType::kBZip2;
}
else else
{ {
Method = NMethodType::kDeflate; Method = NMethodType::kDeflate;

View File

@@ -72,7 +72,7 @@ struct CItem
UInt32 DictionarySize; UInt32 DictionarySize;
CItem(): IsUnicode(false), UseFilter(false), IsCompressed(true), SizeIsDefined(false), CItem(): IsUnicode(false), UseFilter(false), IsCompressed(true), SizeIsDefined(false),
CompressedSizeIsDefined(false), EstimatedSizeIsDefined(false), Size(0) {} CompressedSizeIsDefined(false), EstimatedSizeIsDefined(false), Size(0), DictionarySize(1) {}
bool IsINSTDIR() const bool IsINSTDIR() const
{ {

View File

@@ -156,7 +156,7 @@ struct CMftRef
#define ATNAME(n) ATTR_TYPE_ ## n #define ATNAME(n) ATTR_TYPE_ ## n
#define DEF_ATTR_TYPE(v, n) ATNAME(n) = v #define DEF_ATTR_TYPE(v, n) ATNAME(n) = v
typedef enum enum
{ {
DEF_ATTR_TYPE(0x00, UNUSED), DEF_ATTR_TYPE(0x00, UNUSED),
DEF_ATTR_TYPE(0x10, STANDARD_INFO), DEF_ATTR_TYPE(0x10, STANDARD_INFO),
@@ -873,7 +873,7 @@ STDMETHODIMP CByteBufStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPo
return S_OK; return S_OK;
} }
HRESULT DataParseExtents(int clusterSizeLog, const CObjectVector<CAttr> attrs, static HRESULT DataParseExtents(int clusterSizeLog, const CObjectVector<CAttr> &attrs,
int attrIndex, int attrIndexLim, UInt64 numPhysClusters, CRecordVector<CExtent> &Extents) int attrIndex, int attrIndexLim, UInt64 numPhysClusters, CRecordVector<CExtent> &Extents)
{ {
CExtent e; CExtent e;
@@ -969,6 +969,7 @@ struct CMftRec
void ParseDataNames(); void ParseDataNames();
HRESULT GetStream(IInStream *mainStream, int dataIndex, HRESULT GetStream(IInStream *mainStream, int dataIndex,
int clusterSizeLog, UInt64 numPhysClusters, IInStream **stream) const; int clusterSizeLog, UInt64 numPhysClusters, IInStream **stream) const;
int GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClusters) const;
UInt64 GetSize(int dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); } UInt64 GetSize(int dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); }
@@ -1036,6 +1037,35 @@ HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex,
return S_OK; return S_OK;
} }
int CMftRec::GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClusters) const
{
if (dataIndex < 0)
return 0;
{
const CDataRef &ref = DataRefs[dataIndex];
int numNonResident = 0;
int i;
for (i = ref.Start; i < ref.Start + ref.Num; i++)
if (DataAttrs[i].NonResident)
numNonResident++;
const CAttr &attr0 = DataAttrs[ref.Start];
if (numNonResident != 0 || ref.Num != 1)
{
if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported())
return 0; // error;
CRecordVector<CExtent> extents;
if (DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, extents) != S_OK)
return 0; // error;
return extents.Size() - 1;
}
// if (attr0.Data.GetCapacity() != 0)
// return 1;
return 0;
}
}
bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNumber, bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNumber,
CObjectVector<CAttr> *attrs) CObjectVector<CAttr> *attrs)
{ {
@@ -1283,10 +1313,12 @@ HRESULT CDatabase::Open()
{ {
if (OpenCallback) if (OpenCallback)
{ {
// Sleep(0);
UInt64 numFiles = Recs.Size(); UInt64 numFiles = Recs.Size();
if ((numFiles & 0x3FF) == 0)
{
RINOK(OpenCallback->SetCompleted(&numFiles, &pos64)); RINOK(OpenCallback->SetCompleted(&numFiles, &pos64));
} }
}
UInt32 readSize = kBufSize; UInt32 readSize = kBufSize;
UInt64 rem = mftSize - pos64; UInt64 rem = mftSize - pos64;
if (readSize > rem) if (readSize > rem)
@@ -1423,7 +1455,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
COM_TRY_END COM_TRY_END
} }
STATPROPSTG kProps[] = static const STATPROPSTG kProps[] =
{ {
{ NULL, kpidPath, VT_BSTR}, { NULL, kpidPath, VT_BSTR},
{ NULL, kpidIsDir, VT_BOOL}, { NULL, kpidIsDir, VT_BOOL},
@@ -1433,10 +1465,11 @@ STATPROPSTG kProps[] =
{ NULL, kpidCTime, VT_FILETIME}, { NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidATime, VT_FILETIME}, { NULL, kpidATime, VT_FILETIME},
{ NULL, kpidAttrib, VT_UI4}, { NULL, kpidAttrib, VT_UI4},
{ NULL, kpidLinks, VT_UI4} { NULL, kpidLinks, VT_UI4},
{ NULL, kpidNumBlocks, VT_UI4}
}; };
STATPROPSTG kArcProps[] = static const STATPROPSTG kArcProps[] =
{ {
{ NULL, kpidVolumeName, VT_BSTR}, { NULL, kpidVolumeName, VT_BSTR},
{ NULL, kpidFileSystem, VT_BSTR}, { NULL, kpidFileSystem, VT_BSTR},
@@ -1580,6 +1613,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidLinks: prop = rec.MyNumNameLinks; break; case kpidLinks: prop = rec.MyNumNameLinks; break;
case kpidSize: if (data) prop = data->GetSize(); break; case kpidSize: if (data) prop = data->GetSize(); break;
case kpidPackSize: if (data) prop = data->GetPackSize(); break; case kpidPackSize: if (data) prop = data->GetPackSize(); break;
case kpidNumBlocks: if (data) prop = (UInt32)rec.GetNumExtents(item.DataIndex, Header.ClusterSizeLog, Header.NumClusters); break;
} }
prop.Detach(value); prop.Detach(value);
return S_OK; return S_OK;

View File

@@ -98,7 +98,7 @@ void CDirLink::Parse(const Byte *p)
{ {
Va = Get32(p); Va = Get32(p);
Size = Get32(p + 4); Size = Get32(p + 4);
}; }
enum enum
{ {
@@ -145,7 +145,7 @@ struct COptHeader
// UInt32 AddressOfEntryPoint; // UInt32 AddressOfEntryPoint;
// UInt32 BaseOfCode; // UInt32 BaseOfCode;
// UInt32 BaseOfData32; // UInt32 BaseOfData32;
// UInt64 ImageBase; UInt64 ImageBase;
UInt32 SectAlign; UInt32 SectAlign;
UInt32 FileAlign; UInt32 FileAlign;
@@ -202,8 +202,8 @@ bool COptHeader::Parse(const Byte *p, UInt32 size)
// AddressOfEntryPoint = Get32(p + 16); // AddressOfEntryPoint = Get32(p + 16);
// BaseOfCode = Get32(p + 20); // BaseOfCode = Get32(p + 20);
// BaseOfData32 = Get32(p + 24); // BaseOfData32 = hdr64 ? 0: Get32(p + 24);
// ImageBase = hdr64 ? GetUi64(p + 24) :Get32(p + 28); ImageBase = hdr64 ? GetUi64(p + 24) : Get32(p + 28);
SectAlign = Get32(p + 32); SectAlign = Get32(p + 32);
FileAlign = Get32(p + 36); FileAlign = Get32(p + 36);
@@ -300,53 +300,53 @@ void CSection::Parse(const Byte *p)
static const CUInt32PCharPair g_HeaderCharacts[] = static const CUInt32PCharPair g_HeaderCharacts[] =
{ {
{ 1 << 1, "Executable" }, { 1, "Executable" },
{ 1 << 13, "DLL" }, { 13, "DLL" },
{ 1 << 8, "32-bit" }, { 8, "32-bit" },
{ 1 << 5, "LargeAddress" }, { 5, "LargeAddress" },
{ 1 << 0, "NoRelocs" }, { 0, "NoRelocs" },
{ 1 << 2, "NoLineNums" }, { 2, "NoLineNums" },
{ 1 << 3, "NoLocalSyms" }, { 3, "NoLocalSyms" },
{ 1 << 4, "AggressiveWsTrim" }, { 4, "AggressiveWsTrim" },
{ 1 << 9, "NoDebugInfo" }, { 9, "NoDebugInfo" },
{ 1 << 10, "RemovableRun" }, { 10, "RemovableRun" },
{ 1 << 11, "NetRun" }, { 11, "NetRun" },
{ 1 << 12, "System" }, { 12, "System" },
{ 1 << 14, "UniCPU" }, { 14, "UniCPU" },
{ 1 << 7, "Little-Endian" }, { 7, "Little-Endian" },
{ 1 << 15, "Big-Endian" } { 15, "Big-Endian" }
}; };
static const CUInt32PCharPair g_DllCharacts[] = static const CUInt32PCharPair g_DllCharacts[] =
{ {
{ 1 << 6, "Relocated" }, { 6, "Relocated" },
{ 1 << 7, "Integrity" }, { 7, "Integrity" },
{ 1 << 8, "NX-Compatible" }, { 8, "NX-Compatible" },
{ 1 << 9, "NoIsolation" }, { 9, "NoIsolation" },
{ 1 << 10, "NoSEH" }, { 10, "NoSEH" },
{ 1 << 11, "NoBind" }, { 11, "NoBind" },
{ 1 << 13, "WDM" }, { 13, "WDM" },
{ 1 << 15, "TerminalServerAware" } { 15, "TerminalServerAware" }
}; };
static const CUInt32PCharPair g_SectFlags[] = static const CUInt32PCharPair g_SectFlags[] =
{ {
{ 1 << 3, "NoPad" }, { 3, "NoPad" },
{ 1 << 5, "Code" }, { 5, "Code" },
{ 1 << 6, "InitializedData" }, { 6, "InitializedData" },
{ 1 << 7, "UninitializedData" }, { 7, "UninitializedData" },
{ 1 << 9, "Comments" }, { 9, "Comments" },
{ 1 << 11, "Remove" }, { 11, "Remove" },
{ 1 << 12, "COMDAT" }, { 12, "COMDAT" },
{ 1 << 15, "GP" }, { 15, "GP" },
{ 1 << 24, "ExtendedRelocations" }, { 24, "ExtendedRelocations" },
{ 1 << 25, "Discardable" }, { 25, "Discardable" },
{ 1 << 26, "NotCached" }, { 26, "NotCached" },
{ 1 << 27, "NotPaged" }, { 27, "NotPaged" },
{ 1 << 28, "Shared" }, { 28, "Shared" },
{ 1 << 29, "Execute" }, { 29, "Execute" },
{ 1 << 30, "Read" }, { 30, "Read" },
{ (UInt32)1 << 31, "Write" } { 31, "Write" }
}; };
static const CUInt32PCharPair g_MachinePairs[] = static const CUInt32PCharPair g_MachinePairs[] =
@@ -450,6 +450,7 @@ struct CResItem
bool IsIcon() const { return Type == 3; } bool IsIcon() const { return Type == 3; }
bool IsString() const { return Type == 6; } bool IsString() const { return Type == 6; }
bool IsRcData() const { return Type == 10; } bool IsRcData() const { return Type == 10; }
bool IsRcDataOrUnknown() const { return IsRcData() || Type > 64; }
}; };
struct CStringItem struct CStringItem
@@ -624,6 +625,10 @@ enum
kpidStackCommit, kpidStackCommit,
kpidHeapReserve, kpidHeapReserve,
kpidHeapCommit, kpidHeapCommit,
kpidImageBase
// kpidAddressOfEntryPoint,
// kpidBaseOfCode,
// kpidBaseOfData32,
}; };
STATPROPSTG kArcProps[] = STATPROPSTG kArcProps[] =
@@ -651,6 +656,10 @@ STATPROPSTG kArcProps[] =
{ L"Stack Commit", kpidStackCommit, VT_UI8}, { L"Stack Commit", kpidStackCommit, VT_UI8},
{ L"Heap Reserve", kpidHeapReserve, VT_UI8}, { L"Heap Reserve", kpidHeapReserve, VT_UI8},
{ L"Heap Commit", kpidHeapCommit, VT_UI8}, { L"Heap Commit", kpidHeapCommit, VT_UI8},
{ L"Image Base", kpidImageBase, VT_UI8}
// { L"Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8},
// { L"Base Of Code", kpidBaseOfCode, VT_UI8},
// { L"Base Of Data", kpidBaseOfData32, VT_UI8},
}; };
STATPROPSTG kProps[] = STATPROPSTG kProps[] =
@@ -719,6 +728,12 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidStackCommit: prop = _optHeader.StackCommit; break; case kpidStackCommit: prop = _optHeader.StackCommit; break;
case kpidHeapReserve: prop = _optHeader.HeapReserve; break; case kpidHeapReserve: prop = _optHeader.HeapReserve; break;
case kpidHeapCommit: prop = _optHeader.HeapCommit; break; case kpidHeapCommit: prop = _optHeader.HeapCommit; break;
case kpidImageBase: prop = _optHeader.ImageBase; break;
// case kpidAddressOfEntryPoint: prop = _optHeader.AddressOfEntryPoint; break;
// case kpidBaseOfCode: prop = _optHeader.BaseOfCode; break;
// case kpidBaseOfData32: if (!_optHeader.Is64Bit()) prop = _optHeader.BaseOfData32; break;
case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break; case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
} }
prop.Detach(value); prop.Detach(value);
@@ -976,7 +991,7 @@ bool CBitmapInfoHeader::Parse(const Byte *p, size_t size)
Compression = Get32(p + 16); Compression = Get32(p + 16);
SizeImage = Get32(p + 20); SizeImage = Get32(p + 20);
return true; return true;
}; }
static UInt32 GetImageSize(UInt32 xSize, UInt32 ySize, UInt32 bitCount) static UInt32 GetImageSize(UInt32 xSize, UInt32 ySize, UInt32 bitCount)
{ {
@@ -1392,7 +1407,8 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
_parseResources = true; _parseResources = true;
UInt64 mainSize = 0, mainSize2 = 0; UInt64 mainSize = 0, mainSize2 = 0;
for (int i = 0; i < _sections.Size(); i++) int i;
for (i = 0; i < _sections.Size(); i++)
{ {
const CSection &sect = _sections[i]; const CSection &sect = _sections[i];
CMixItem mixItem; CMixItem mixItem;
@@ -1410,7 +1426,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
{ {
mixItem.ResourceIndex = j; mixItem.ResourceIndex = j;
mixItem.StringIndex = -1; mixItem.StringIndex = -1;
if (item.IsRcData()) if (item.IsRcDataOrUnknown())
{ {
if (item.Size >= mainSize) if (item.Size >= mainSize)
{ {
@@ -1468,8 +1484,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
} }
_mixItems.Add(mixItem); _mixItems.Add(mixItem);
} }
if (mainSize2 >= (1 << 20) && mainSize < mainSize2 * 2) if (mainSize2 >= (1 << 20) && mainSize < mainSize2 * 2)
_mainSubfile = -1; _mainSubfile = -1;
for (i = 0; i < _mixItems.Size(); i++)
{
const CMixItem &mixItem = _mixItems[i];
if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name == "_winzip_")
{
_mainSubfile = i;
break;
}
}
return S_OK; return S_OK;
} }
@@ -1695,6 +1723,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
size_t offset = item.Offset - sect.Va; size_t offset = item.Offset - sect.Va;
if (!CheckItem(sect, item, offset)) if (!CheckItem(sect, item, offset))
return S_FALSE; return S_FALSE;
if (item.HeaderSize == 0)
{
CBufInStream *streamSpec = new CBufInStream;
CMyComPtr<IInStream> streamTemp2 = streamSpec;
streamSpec->Init(_buf + offset, item.Size, (IInArchive *)this);
*stream = streamTemp2.Detach();
return S_OK;
}
referenceBuf->Buf.SetCapacity(item.HeaderSize + item.Size); referenceBuf->Buf.SetCapacity(item.HeaderSize + item.Size);
memcpy(referenceBuf->Buf, item.Header, item.HeaderSize); memcpy(referenceBuf->Buf, item.Header, item.HeaderSize);
memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size); memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size);

View File

@@ -7,6 +7,7 @@
#include "Common/StringConvert.h" #include "Common/StringConvert.h"
#include "Windows/PropVariant.h" #include "Windows/PropVariant.h"
#include "Windows/PropVariantUtils.h"
#include "Windows/Time.h" #include "Windows/Time.h"
#include "../../IPassword.h" #include "../../IPassword.h"
@@ -46,7 +47,21 @@ static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);
static const wchar_t *kUnknownOS = L"Unknown"; static const wchar_t *kUnknownOS = L"Unknown";
STATPROPSTG kProps[] = static const CUInt32PCharPair k_Flags[] =
{
{ 0, "Volume" },
{ 1, "Comment" },
{ 2, "Lock" },
{ 3, "Solid" },
{ 4, "NewVolName" }, // pack_comment in old versuons
{ 5, "Authenticity" },
{ 6, "Recovery" },
{ 7, "BlockEncryption" },
{ 8, "FirstVolume" },
{ 9, "EncryptVer" }
};
static const STATPROPSTG kProps[] =
{ {
{ NULL, kpidPath, VT_BSTR}, { NULL, kpidPath, VT_BSTR},
{ NULL, kpidIsDir, VT_BOOL}, { NULL, kpidIsDir, VT_BOOL},
@@ -68,8 +83,9 @@ STATPROPSTG kProps[] =
{ NULL, kpidUnpackVer, VT_UI1} { NULL, kpidUnpackVer, VT_UI1}
}; };
STATPROPSTG kArcProps[] = static const STATPROPSTG kArcProps[] =
{ {
{ NULL, kpidCharacts, VT_BSTR},
{ NULL, kpidSolid, VT_BOOL}, { NULL, kpidSolid, VT_BOOL},
{ NULL, kpidNumBlocks, VT_UI4}, { NULL, kpidNumBlocks, VT_UI4},
// { NULL, kpidEncrypted, VT_BOOL}, // { NULL, kpidEncrypted, VT_BOOL},
@@ -93,11 +109,12 @@ UInt64 CHandler::GetPackSize(int refIndex) const
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{ {
// COM_TRY_BEGIN COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop; NWindows::NCOM::CPropVariant prop;
switch(propID) switch(propID)
{ {
case kpidSolid: prop = _archiveInfo.IsSolid(); break; case kpidSolid: prop = _archiveInfo.IsSolid(); break;
case kpidCharacts: FLAGS_TO_PROP(k_Flags, _archiveInfo.Flags, prop); break;
// case kpidEncrypted: prop = _archiveInfo.IsEncrypted(); break; // it's for encrypted names. // case kpidEncrypted: prop = _archiveInfo.IsEncrypted(); break; // it's for encrypted names.
case kpidIsVolume: prop = _archiveInfo.IsVolume(); break; case kpidIsVolume: prop = _archiveInfo.IsVolume(); break;
case kpidNumVolumes: prop = (UInt32)_archives.Size(); break; case kpidNumVolumes: prop = (UInt32)_archives.Size(); break;
@@ -112,10 +129,11 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
prop = (UInt32)numBlocks; prop = (UInt32)numBlocks;
break; break;
} }
case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
} }
prop.Detach(value); prop.Detach(value);
return S_OK; return S_OK;
// COM_TRY_END COM_TRY_END
} }
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
@@ -324,19 +342,19 @@ public:
HRESULT CHandler::Open2(IInStream *stream, HRESULT CHandler::Open2(IInStream *stream,
const UInt64 *maxCheckStartPosition, const UInt64 *maxCheckStartPosition,
IArchiveOpenCallback *openArchiveCallback) IArchiveOpenCallback *openCallback)
{ {
{ {
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
CMyComPtr<ICryptoGetTextPassword> getTextPassword; CMyComPtr<ICryptoGetTextPassword> getTextPassword;
CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openArchiveCallback; CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openCallback;
CVolumeName seqName; CVolumeName seqName;
UInt64 totalBytes = 0; UInt64 totalBytes = 0;
UInt64 curBytes = 0; UInt64 curBytes = 0;
if (openArchiveCallback != NULL) if (openCallback)
{ {
openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback); openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
@@ -378,12 +396,12 @@ HRESULT CHandler::Open2(IInStream *stream,
inStream = stream; inStream = stream;
UInt64 endPos = 0; UInt64 endPos = 0;
if (openArchiveCallback != NULL)
{
RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
if (openCallback)
{
totalBytes += endPos; totalBytes += endPos;
RINOK(openArchiveCallback->SetTotal(NULL, &totalBytes)); RINOK(openCallback->SetTotal(NULL, &totalBytes));
} }
NArchive::NRar::CInArchive archive; NArchive::NRar::CInArchive archive;
@@ -395,8 +413,16 @@ HRESULT CHandler::Open2(IInStream *stream,
CItemEx item; CItemEx item;
for (;;) for (;;)
{ {
if (archive.m_Position > endPos)
{
AddErrorMessage("Unexpected end of archive");
break;
}
bool decryptionError; bool decryptionError;
HRESULT result = archive.GetNextItem(item, getTextPassword, decryptionError); AString errorMessageLoc;
HRESULT result = archive.GetNextItem(item, getTextPassword, decryptionError, errorMessageLoc);
if (errorMessageLoc)
AddErrorMessage(errorMessageLoc);
if (result == S_FALSE) if (result == S_FALSE)
{ {
if (decryptionError && _items.IsEmpty()) if (decryptionError && _items.IsEmpty())
@@ -426,11 +452,11 @@ HRESULT CHandler::Open2(IInStream *stream,
_refItems.Add(refItem); _refItems.Add(refItem);
} }
_items.Add(item); _items.Add(item);
if (openArchiveCallback != NULL && _items.Size() % 100 == 0) if (openCallback && _items.Size() % 100 == 0)
{ {
UInt64 numFiles = _items.Size(); UInt64 numFiles = _items.Size();
UInt64 numBytes = curBytes + item.Position; UInt64 numBytes = curBytes + item.Position;
RINOK(openArchiveCallback->SetCompleted(&numFiles, &numBytes)); RINOK(openCallback->SetCompleted(&numFiles, &numBytes));
} }
} }
curBytes += endPos; curBytes += endPos;
@@ -442,13 +468,13 @@ HRESULT CHandler::Open2(IInStream *stream,
STDMETHODIMP CHandler::Open(IInStream *stream, STDMETHODIMP CHandler::Open(IInStream *stream,
const UInt64 *maxCheckStartPosition, const UInt64 *maxCheckStartPosition,
IArchiveOpenCallback *openArchiveCallback) IArchiveOpenCallback *openCallback)
{ {
COM_TRY_BEGIN COM_TRY_BEGIN
Close(); Close();
try try
{ {
HRESULT res = Open2(stream, maxCheckStartPosition, openArchiveCallback); HRESULT res = Open2(stream, maxCheckStartPosition, openCallback);
if (res != S_OK) if (res != S_OK)
Close(); Close();
return res; return res;
@@ -461,6 +487,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
STDMETHODIMP CHandler::Close() STDMETHODIMP CHandler::Close()
{ {
COM_TRY_BEGIN COM_TRY_BEGIN
_errorMessage.Empty();
_refItems.Clear(); _refItems.Clear();
_items.Clear(); _items.Clear();
_archives.Clear(); _archives.Clear();
@@ -520,7 +547,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
lastIndex = index + 1; lastIndex = index + 1;
} }
extractCallback->SetTotal(importantTotalUnPacked); RINOK(extractCallback->SetTotal(importantTotalUnPacked));
UInt64 currentImportantTotalUnPacked = 0; UInt64 currentImportantTotalUnPacked = 0;
UInt64 currentImportantTotalPacked = 0; UInt64 currentImportantTotalPacked = 0;
UInt64 currentUnPackSize, currentPackSize; UInt64 currentUnPackSize, currentPackSize;

View File

@@ -4,11 +4,12 @@
#define __RAR_HANDLER_H #define __RAR_HANDLER_H
#include "../IArchive.h" #include "../IArchive.h"
#include "RarIn.h"
#include "RarVolumeInStream.h"
#include "../../Common/CreateCoder.h" #include "../../Common/CreateCoder.h"
#include "RarIn.h"
#include "RarVolumeInStream.h"
namespace NArchive { namespace NArchive {
namespace NRar { namespace NRar {
@@ -17,26 +18,15 @@ class CHandler:
PUBLIC_ISetCompressCodecsInfo PUBLIC_ISetCompressCodecsInfo
public CMyUnknownImp public CMyUnknownImp
{ {
public:
MY_QUERYINTERFACE_BEGIN2(IInArchive)
QUERY_ENTRY_ISetCompressCodecsInfo
MY_QUERYINTERFACE_END
MY_ADDREF_RELEASE
INTERFACE_IInArchive(;)
DECL_ISetCompressCodecsInfo
private:
CRecordVector<CRefItem> _refItems; CRecordVector<CRefItem> _refItems;
CObjectVector<CItemEx> _items; CObjectVector<CItemEx> _items;
CObjectVector<CInArchive> _archives; CObjectVector<CInArchive> _archives;
NArchive::NRar::CInArchiveInfo _archiveInfo; NArchive::NRar::CInArchiveInfo _archiveInfo;
AString _errorMessage;
DECL_EXTERNAL_CODECS_VARS DECL_EXTERNAL_CODECS_VARS
UInt64 GetPackSize(int refIndex) const; UInt64 GetPackSize(int refIndex) const;
// NArchive::NRar::CInArchive _archive;
bool IsSolid(int refIndex) bool IsSolid(int refIndex)
{ {
@@ -49,10 +39,26 @@ private:
} }
return item.IsSolid(); return item.IsSolid();
} }
void AddErrorMessage(const AString &s)
{
if (!_errorMessage.IsEmpty())
_errorMessage += '\n';
_errorMessage += s;
}
HRESULT Open2(IInStream *stream, HRESULT Open2(IInStream *stream,
const UInt64 *maxCheckStartPosition, const UInt64 *maxCheckStartPosition,
IArchiveOpenCallback *openArchiveCallback); IArchiveOpenCallback *openCallback);
public:
MY_QUERYINTERFACE_BEGIN2(IInArchive)
QUERY_ENTRY_ISetCompressCodecsInfo
MY_QUERYINTERFACE_END
MY_ADDREF_RELEASE
INTERFACE_IInArchive(;)
DECL_ISetCompressCodecsInfo
}; };
}} }}

View File

@@ -19,15 +19,15 @@ namespace NBlockType
enum EBlockType enum EBlockType
{ {
kMarker = 0x72, kMarker = 0x72,
kArchiveHeader = 0x73, kArchiveHeader,
kFileHeader = 0x74, kFileHeader,
kCommentHeader = 0x75, kCommentHeader,
kOldAuthenticity = 0x76, kOldAuthenticity,
kSubBlock = 0x77, kOldSubBlock,
kRecoveryRecord = 0x78, kRecoveryRecord,
kAuthenticity = 0x79, kAuthenticity,
kSubBlock,
kEndOfArchive = 0x7B // Is not safe kEndOfArchive
}; };
} }
@@ -46,29 +46,10 @@ namespace NArchive
const int kHeaderSizeMin = 7; const int kHeaderSizeMin = 7;
struct CBlock
{
UInt16 CRC;
Byte Type;
UInt16 Flags;
UInt16 Size;
UInt16 Reserved1;
UInt32 Reserved2;
// UInt16 GetRealCRC() const;
};
const int kArchiveHeaderSize = 13; const int kArchiveHeaderSize = 13;
const int kBlockHeadersAreEncrypted = 0x80; const int kBlockHeadersAreEncrypted = 0x80;
struct CHeader360: public CBlock
{
Byte EncryptVersion;
bool IsEncrypted() const { return (Flags & NHeader::NArchive::kBlockEncryption) != 0; }
bool IsThereEncryptVer() const { return (Flags & NHeader::NArchive::kEncryptVer) != 0; }
bool IsEncryptOld() const { return (!IsThereEncryptVer() || EncryptVersion < 36); }
UInt32 GetBaseSize() const { return kArchiveHeaderSize + (IsEncryptOld() ? 0 : 1); }
};
} }
namespace NFile namespace NFile

View File

@@ -3,6 +3,7 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "../../../../C/7zCrc.h" #include "../../../../C/7zCrc.h"
#include "../../../../C/CpuArch.h"
#include "Common/StringConvert.h" #include "Common/StringConvert.h"
#include "Common/UTFConvert.h" #include "Common/UTFConvert.h"
@@ -14,9 +15,16 @@
#include "RarIn.h" #include "RarIn.h"
#define Get16(p) GetUi16(p)
#define Get32(p) GetUi32(p)
#define Get64(p) GetUi64(p)
namespace NArchive { namespace NArchive {
namespace NRar { namespace NRar {
static const char *k_UnexpectedEnd = "Unexpected end of archive";
static const char *k_DecryptionError = "Decryption Error";
void CInArchive::ThrowExceptionWithCode( void CInArchive::ThrowExceptionWithCode(
CInArchiveException::CCauseType cause) CInArchiveException::CCauseType cause)
{ {
@@ -42,76 +50,30 @@ void CInArchive::Close()
m_Stream.Release(); m_Stream.Release();
} }
HRESULT CInArchive::ReadBytesSpec(void *data, size_t *resSize)
static inline bool TestMarkerCandidate(const void *aTestBytes)
{ {
for (UInt32 i = 0; i < NHeader::kMarkerSize; i++) if (m_CryptoMode)
if (((const Byte *)aTestBytes)[i] != NHeader::kMarker[i]) {
return false; size_t size = *resSize;
return true; *resSize = 0;
const Byte *bufData = m_DecryptedDataAligned;
UInt32 bufSize = m_DecryptedDataSize;
size_t i;
for (i = 0; i < size && m_CryptoPos < bufSize; i++)
((Byte *)data)[i] = bufData[m_CryptoPos++];
*resSize = i;
return S_OK;
} }
return ReadStream(m_Stream, data, resSize);
HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
{
RINOK(FindSignatureInStream(stream,
NHeader::kMarker, NHeader::kMarkerSize,
searchHeaderSizeLimit, m_ArchiveStartPosition));
m_Stream = stream;
m_Position = m_ArchiveStartPosition + NHeader::kMarkerSize;
return m_Stream->Seek(m_Position, STREAM_SEEK_SET, NULL);
}
void CInArchive::ThrowUnexpectedEndOfArchiveException()
{
ThrowExceptionWithCode(CInArchiveException::kUnexpectedEndOfArchive);
} }
bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size) bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size)
{ {
if (m_CryptoMode) size_t processed = size;
{ if (ReadBytesSpec(data, &processed) != S_OK)
const Byte *bufData = m_DecryptedDataAligned; return false;
UInt32 bufSize = m_DecryptedDataSize; return processed == size;
UInt32 i;
for (i = 0; i < size && m_CryptoPos < bufSize; i++)
((Byte *)data)[i] = bufData[m_CryptoPos++];
return (i == size);
} }
return (ReadStream_FALSE(m_Stream, data, size) == S_OK);
}
void CInArchive::ReadBytesAndTestResult(void *data, UInt32 size)
{
if(!ReadBytesAndTestSize(data,size))
ThrowUnexpectedEndOfArchiveException();
}
HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize)
{
size_t realProcessedSize = size;
HRESULT result = ReadStream(m_Stream, data, &realProcessedSize);
if (processedSize != NULL)
*processedSize = (UInt32)realProcessedSize;
AddToSeekValue(realProcessedSize);
return result;
}
static UInt32 CrcUpdateUInt16(UInt32 crc, UInt16 v)
{
crc = CRC_UPDATE_BYTE(crc, (Byte)(v & 0xFF));
crc = CRC_UPDATE_BYTE(crc, (Byte)((v >> 8) & 0xFF));
return crc;
}
static UInt32 CrcUpdateUInt32(UInt32 crc, UInt32 v)
{
crc = CRC_UPDATE_BYTE(crc, (Byte)(v & 0xFF));
crc = CRC_UPDATE_BYTE(crc, (Byte)((v >> 8) & 0xFF));
crc = CRC_UPDATE_BYTE(crc, (Byte)((v >> 16) & 0xFF));
crc = CRC_UPDATE_BYTE(crc, (Byte)((v >> 24) & 0xFF));
return crc;
}
HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit) HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
{ {
@@ -119,63 +81,49 @@ HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit
RINOK(stream->Seek(0, STREAM_SEEK_SET, &m_StreamStartPosition)); RINOK(stream->Seek(0, STREAM_SEEK_SET, &m_StreamStartPosition));
m_Position = m_StreamStartPosition; m_Position = m_StreamStartPosition;
RINOK(FindAndReadMarker(stream, searchHeaderSizeLimit)); UInt64 arcStartPos;
RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize,
searchHeaderSizeLimit, arcStartPos));
m_Position = arcStartPos + NHeader::kMarkerSize;
RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1];
Byte buf[NHeader::NArchive::kArchiveHeaderSize]; RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize));
UInt32 processedSize; AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize);
ReadBytes(buf, sizeof(buf), &processedSize);
if (processedSize != sizeof(buf))
return S_FALSE;
m_CurData = buf;
m_CurPos = 0;
m_PosLimit = sizeof(buf);
m_ArchiveHeader.CRC = ReadUInt16();
m_ArchiveHeader.Type = ReadByte();
m_ArchiveHeader.Flags = ReadUInt16();
m_ArchiveHeader.Size = ReadUInt16();
m_ArchiveHeader.Reserved1 = ReadUInt16();
m_ArchiveHeader.Reserved2 = ReadUInt32();
m_ArchiveHeader.EncryptVersion = 0;
UInt32 crc = CRC_INIT_VAL; UInt32 blockSize = Get16(buf + 5);
crc = CRC_UPDATE_BYTE(crc, m_ArchiveHeader.Type);
crc = CrcUpdateUInt16(crc, m_ArchiveHeader.Flags);
crc = CrcUpdateUInt16(crc, m_ArchiveHeader.Size);
crc = CrcUpdateUInt16(crc, m_ArchiveHeader.Reserved1);
crc = CrcUpdateUInt32(crc, m_ArchiveHeader.Reserved2);
if (m_ArchiveHeader.IsThereEncryptVer() && m_ArchiveHeader.Size > NHeader::NArchive::kArchiveHeaderSize) _header.EncryptVersion = 0;
_header.Flags = Get16(buf + 3);
UInt32 headerSize = NHeader::NArchive::kArchiveHeaderSize;
if (_header.IsThereEncryptVer())
{ {
ReadBytes(&m_ArchiveHeader.EncryptVersion, 1, &processedSize); if (blockSize <= headerSize)
if (processedSize != 1)
return S_FALSE; return S_FALSE;
crc = CRC_UPDATE_BYTE(crc, m_ArchiveHeader.EncryptVersion); RINOK(ReadStream_FALSE(stream, buf + NHeader::NArchive::kArchiveHeaderSize, 1));
AddToSeekValue(1);
_header.EncryptVersion = buf[NHeader::NArchive::kArchiveHeaderSize];
headerSize += 1;
} }
if (blockSize < headerSize ||
if(m_ArchiveHeader.CRC != (CRC_GET_DIGEST(crc) & 0xFFFF)) buf[2] != NHeader::NBlockType::kArchiveHeader ||
ThrowExceptionWithCode(CInArchiveException::kArchiveHeaderCRCError); (UInt32)Get16(buf) != (CrcCalc(buf + 2, headerSize - 2) & 0xFFFF))
if (m_ArchiveHeader.Type != NHeader::NBlockType::kArchiveHeader)
return S_FALSE; return S_FALSE;
m_ArchiveCommentPosition = m_Position;
m_SeekOnArchiveComment = true; size_t commentSize = blockSize - headerSize;
_comment.SetCapacity(commentSize);
RINOK(ReadStream_FALSE(stream, _comment, commentSize));
AddToSeekValue(commentSize);
m_Stream = stream;
_header.StartPosition = arcStartPos;
return S_OK; return S_OK;
} }
void CInArchive::SkipArchiveComment()
{
if (!m_SeekOnArchiveComment)
return;
AddToSeekValue(m_ArchiveHeader.Size - m_ArchiveHeader.GetBaseSize());
m_SeekOnArchiveComment = false;
}
void CInArchive::GetArchiveInfo(CInArchiveInfo &archiveInfo) const void CInArchive::GetArchiveInfo(CInArchiveInfo &archiveInfo) const
{ {
archiveInfo.StartPosition = m_ArchiveStartPosition; archiveInfo = _header;
archiveInfo.Flags = m_ArchiveHeader.Flags;
archiveInfo.CommentPosition = m_ArchiveCommentPosition;
archiveInfo.CommentSize = (UInt16)(m_ArchiveHeader.Size - NHeader::NArchive::kArchiveHeaderSize);
} }
static void DecodeUnicodeFileName(const char *name, const Byte *encName, static void DecodeUnicodeFileName(const char *name, const Byte *encName,
@@ -372,29 +320,24 @@ void CInArchive::AddToSeekValue(UInt64 addValue)
m_Position += addValue; m_Position += addValue;
} }
HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError) HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage)
{ {
decryptionError = false; decryptionError = false;
if (m_SeekOnArchiveComment)
SkipArchiveComment();
for (;;) for (;;)
{ {
if(!SeekInArchive(m_Position)) SeekInArchive(m_Position);
return S_FALSE; if (!m_CryptoMode && (_header.Flags &
if (!m_CryptoMode && (m_ArchiveHeader.Flags &
NHeader::NArchive::kBlockHeadersAreEncrypted) != 0) NHeader::NArchive::kBlockHeadersAreEncrypted) != 0)
{ {
m_CryptoMode = false; m_CryptoMode = false;
if (getTextPassword == 0) if (getTextPassword == 0)
return S_FALSE; return S_FALSE;
if(!SeekInArchive(m_Position))
return S_FALSE;
if (!m_RarAES) if (!m_RarAES)
{ {
m_RarAESSpec = new NCrypto::NRar29::CDecoder; m_RarAESSpec = new NCrypto::NRar29::CDecoder;
m_RarAES = m_RarAESSpec; m_RarAES = m_RarAESSpec;
} }
m_RarAESSpec->SetRar350Mode(m_ArchiveHeader.IsEncryptOld()); m_RarAESSpec->SetRar350Mode(_header.IsEncryptOld());
// Salt // Salt
const UInt32 kSaltSize = 8; const UInt32 kSaltSize = 8;
@@ -438,8 +381,14 @@ HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPa
} }
m_FileHeaderData.EnsureCapacity(7); m_FileHeaderData.EnsureCapacity(7);
if(!ReadBytesAndTestSize((Byte *)m_FileHeaderData, 7)) size_t processed = 7;
RINOK(ReadBytesSpec((Byte *)m_FileHeaderData, &processed));
if (processed != 7)
{
if (processed != 0)
errorMessage = k_UnexpectedEnd;
return S_FALSE; return S_FALSE;
}
m_CurData = (Byte *)m_FileHeaderData; m_CurData = (Byte *)m_FileHeaderData;
m_CurPos = 0; m_CurPos = 0;
@@ -460,7 +409,12 @@ HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPa
m_FileHeaderData.EnsureCapacity(m_BlockHeader.HeadSize); m_FileHeaderData.EnsureCapacity(m_BlockHeader.HeadSize);
m_CurData = (Byte *)m_FileHeaderData; m_CurData = (Byte *)m_FileHeaderData;
m_PosLimit = m_BlockHeader.HeadSize; m_PosLimit = m_BlockHeader.HeadSize;
ReadBytesAndTestResult(m_CurData + m_CurPos, m_BlockHeader.HeadSize - 7); if (!ReadBytesAndTestSize(m_CurData + m_CurPos, m_BlockHeader.HeadSize - 7))
{
errorMessage = k_UnexpectedEnd;
return S_FALSE;
}
ReadHeaderReal(item); ReadHeaderReal(item);
if ((CrcCalc(m_CurData + 2, if ((CrcCalc(m_CurData + 2,
m_BlockHeader.HeadSize - item.CommentSize - 2) & 0xFFFF) != m_BlockHeader.CRC) m_BlockHeader.HeadSize - item.CommentSize - 2) & 0xFFFF) != m_BlockHeader.CRC)
@@ -475,19 +429,25 @@ HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPa
if (m_CryptoMode && m_BlockHeader.HeadSize > (1 << 10)) if (m_CryptoMode && m_BlockHeader.HeadSize > (1 << 10))
{ {
decryptionError = true; decryptionError = true;
errorMessage = k_DecryptionError;
return S_FALSE; return S_FALSE;
} }
if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0) if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0)
{ {
m_FileHeaderData.EnsureCapacity(7 + 4); m_FileHeaderData.EnsureCapacity(7 + 4);
m_CurData = (Byte *)m_FileHeaderData; m_CurData = (Byte *)m_FileHeaderData;
ReadBytesAndTestResult(m_CurData + m_CurPos, 4); // test it if (!ReadBytesAndTestSize(m_CurData + m_CurPos, 4))
{
errorMessage = k_UnexpectedEnd;
return S_FALSE;
}
m_PosLimit = 7 + 4; m_PosLimit = 7 + 4;
UInt32 dataSize = ReadUInt32(); UInt32 dataSize = ReadUInt32();
AddToSeekValue(dataSize); AddToSeekValue(dataSize);
if (m_CryptoMode && dataSize > (1 << 27)) if (m_CryptoMode && dataSize > (1 << 27))
{ {
decryptionError = true; decryptionError = true;
errorMessage = k_DecryptionError;
return S_FALSE; return S_FALSE;
} }
m_CryptoPos = m_BlockHeader.HeadSize; m_CryptoPos = m_BlockHeader.HeadSize;
@@ -500,11 +460,9 @@ HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPa
} }
} }
bool CInArchive::SeekInArchive(UInt64 position) void CInArchive::SeekInArchive(UInt64 position)
{ {
UInt64 newPosition; m_Stream->Seek(position, STREAM_SEEK_SET, NULL);
m_Stream->Seek(position, STREAM_SEEK_SET, &newPosition);
return newPosition == position;
} }
ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size) ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size)

View File

@@ -33,18 +33,20 @@ public:
CInArchiveException(CCauseType cause) : Cause(cause) {} CInArchiveException(CCauseType cause) : Cause(cause) {}
}; };
class CInArchiveInfo
struct CInArchiveInfo
{ {
public: UInt32 Flags;
Byte EncryptVersion;
UInt64 StartPosition; UInt64 StartPosition;
UInt16 Flags;
UInt64 CommentPosition;
UInt16 CommentSize;
bool IsSolid() const { return (Flags & NHeader::NArchive::kSolid) != 0; } bool IsSolid() const { return (Flags & NHeader::NArchive::kSolid) != 0; }
bool IsCommented() const { return (Flags & NHeader::NArchive::kComment) != 0; } bool IsCommented() const { return (Flags & NHeader::NArchive::kComment) != 0; }
bool IsVolume() const { return (Flags & NHeader::NArchive::kVolume) != 0; } bool IsVolume() const { return (Flags & NHeader::NArchive::kVolume) != 0; }
bool HaveNewVolumeName() const { return (Flags & NHeader::NArchive::kNewVolName) != 0; } bool HaveNewVolumeName() const { return (Flags & NHeader::NArchive::kNewVolName) != 0; }
bool IsEncrypted() const { return (Flags & NHeader::NArchive::kBlockEncryption) != 0; } bool IsEncrypted() const { return (Flags & NHeader::NArchive::kBlockEncryption) != 0; }
bool IsThereEncryptVer() const { return (Flags & NHeader::NArchive::kEncryptVer) != 0; }
bool IsEncryptOld() const { return (!IsThereEncryptVer() || EncryptVersion < 36); }
}; };
class CInArchive class CInArchive
@@ -52,23 +54,19 @@ class CInArchive
CMyComPtr<IInStream> m_Stream; CMyComPtr<IInStream> m_Stream;
UInt64 m_StreamStartPosition; UInt64 m_StreamStartPosition;
UInt64 m_Position;
UInt64 m_ArchiveStartPosition;
NHeader::NArchive::CHeader360 m_ArchiveHeader; CInArchiveInfo _header;
CDynamicBuffer<char> m_NameBuffer; CDynamicBuffer<char> m_NameBuffer;
CDynamicBuffer<wchar_t> _unicodeNameBuffer; CDynamicBuffer<wchar_t> _unicodeNameBuffer;
bool m_SeekOnArchiveComment;
UInt64 m_ArchiveCommentPosition; CByteBuffer _comment;
void ReadName(CItemEx &item, int nameSize); void ReadName(CItemEx &item, int nameSize);
void ReadHeaderReal(CItemEx &item); void ReadHeaderReal(CItemEx &item);
HRESULT ReadBytes(void *data, UInt32 size, UInt32 *aProcessedSize); HRESULT ReadBytesSpec(void *data, size_t *size);
bool ReadBytesAndTestSize(void *data, UInt32 size); bool ReadBytesAndTestSize(void *data, UInt32 size);
void ReadBytesAndTestResult(void *data, UInt32 size);
HRESULT FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
HRESULT Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit); HRESULT Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
void ThrowExceptionWithCode(CInArchiveException::CCauseType cause); void ThrowExceptionWithCode(CInArchiveException::CCauseType cause);
@@ -108,15 +106,15 @@ class CInArchive
} }
public: public:
UInt64 m_Position;
HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit); HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit);
void Close(); void Close();
HRESULT GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError); HRESULT GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage);
void SkipArchiveComment();
void GetArchiveInfo(CInArchiveInfo &archiveInfo) const; void GetArchiveInfo(CInArchiveInfo &archiveInfo) const;
bool SeekInArchive(UInt64 position); void SeekInArchive(UInt64 position);
ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size); ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
}; };

View File

@@ -79,7 +79,7 @@ static HRESULT RedSigHeaderSig(IInStream *inStream, CSigHeaderSig &h)
char dat[kCSigHeaderSigSize]; char dat[kCSigHeaderSigSize];
char *cur = dat; char *cur = dat;
RINOK(ReadStream_FALSE(inStream, dat, kCSigHeaderSigSize)); RINOK(ReadStream_FALSE(inStream, dat, kCSigHeaderSigSize));
memmove(h.Magic, cur, 4); memcpy(h.Magic, cur, 4);
cur += 4; cur += 4;
cur += 4; cur += 4;
h.IndexLen = Get32(cur); h.IndexLen = Get32(cur);
@@ -95,7 +95,7 @@ HRESULT OpenArchive(IInStream *inStream)
char *cur = leadData; char *cur = leadData;
CLead lead; CLead lead;
RINOK(ReadStream_FALSE(inStream, leadData, kLeadSize)); RINOK(ReadStream_FALSE(inStream, leadData, kLeadSize));
memmove(lead.Magic, cur, 4); memcpy(lead.Magic, cur, 4);
cur += 4; cur += 4;
lead.Major = *cur++; lead.Major = *cur++;
lead.Minor = *cur++; lead.Minor = *cur++;
@@ -103,7 +103,7 @@ HRESULT OpenArchive(IInStream *inStream)
cur += 2; cur += 2;
lead.ArchNum = Get16(cur); lead.ArchNum = Get16(cur);
cur += 2; cur += 2;
memmove(lead.Name, cur, sizeof(lead.Name)); memcpy(lead.Name, cur, sizeof(lead.Name));
cur += sizeof(lead.Name); cur += sizeof(lead.Name);
lead.OSNum = Get16(cur); lead.OSNum = Get16(cur);
cur += 2; cur += 2;

View File

@@ -347,7 +347,6 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
{ {
CMultiStream::CSubStreamInfo subStreamInfo; CMultiStream::CSubStreamInfo subStreamInfo;
subStreamInfo.Stream = _streams[i]; subStreamInfo.Stream = _streams[i];
subStreamInfo.Pos = 0;
subStreamInfo.Size = _sizes[i]; subStreamInfo.Size = _sizes[i];
streamSpec->Streams.Add(subStreamInfo); streamSpec->Streams.Add(subStreamInfo);
} }

View File

File diff suppressed because it is too large Load Diff

View File

@@ -3,8 +3,6 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "Common/ComTry.h" #include "Common/ComTry.h"
#include "Common/Defs.h"
#include "Common/NewHandler.h"
#include "Common/StringConvert.h" #include "Common/StringConvert.h"
#include "Windows/PropVariant.h" #include "Windows/PropVariant.h"
@@ -12,6 +10,8 @@
#include "../../Common/LimitedStreams.h" #include "../../Common/LimitedStreams.h"
#include "../../Common/ProgressUtils.h" #include "../../Common/ProgressUtils.h"
#include "../../Common/StreamObjects.h"
#include "../../Common/StreamUtils.h"
#include "../Common/ItemNameUtils.h" #include "../Common/ItemNameUtils.h"
@@ -23,7 +23,9 @@ using namespace NWindows;
namespace NArchive { namespace NArchive {
namespace NTar { namespace NTar {
STATPROPSTG kProps[] = static const char *kUnexpectedEnd = "Unexpected end of archive";
static const STATPROPSTG kProps[] =
{ {
{ NULL, kpidPath, VT_BSTR}, { NULL, kpidPath, VT_BSTR},
{ NULL, kpidIsDir, VT_BOOL}, { NULL, kpidIsDir, VT_BOOL},
@@ -36,8 +38,14 @@ STATPROPSTG kProps[] =
{ NULL, kpidLink, VT_BSTR} { NULL, kpidLink, VT_BSTR}
}; };
static const STATPROPSTG kArcProps[] =
{
{ NULL, kpidPhySize, VT_UI8},
{ NULL, kpidHeadersSize, VT_UI8}
};
IMP_IInArchive_Props IMP_IInArchive_Props
IMP_IInArchive_ArcProps_NO_Table IMP_IInArchive_ArcProps
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{ {
@@ -45,11 +53,22 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
switch(propID) switch(propID)
{ {
case kpidPhySize: if (_phySizeDefined) prop = _phySize; break; case kpidPhySize: if (_phySizeDefined) prop = _phySize; break;
case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break;
case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
} }
prop.Detach(value); prop.Detach(value);
return S_OK; return S_OK;
} }
HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item)
{
item.HeaderPos = _phySize;
RINOK(ReadItem(stream, filled, item, _errorMessage));
_phySize += item.HeaderSize;
_headersSize += item.HeaderSize;
return S_OK;
}
HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
{ {
UInt64 endPos = 0; UInt64 endPos = 0;
@@ -58,26 +77,29 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
} }
_isGood = true; _phySizeDefined = true;
UInt64 pos = 0;
for (;;) for (;;)
{ {
CItemEx item; CItemEx item;
bool filled; bool filled;
item.HeaderPosition = pos; RINOK(ReadItem2(stream, filled, item));
RINOK(ReadItem(stream, filled, item));
if (!filled) if (!filled)
break; break;
_items.Add(item); _items.Add(item);
RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &pos)); RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &_phySize));
if (pos > endPos) if (_phySize > endPos)
return S_FALSE;
if (pos == endPos)
{ {
_isGood = false; _errorMessage = kUnexpectedEnd;
break; break;
} }
/*
if (_phySize == endPos)
{
_errorMessage = "There are no trailing zero-filled records";
break;
}
*/
if (callback != NULL) if (callback != NULL)
{ {
if (_items.Size() == 1) if (_items.Size() == 1)
@@ -87,7 +109,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
if (_items.Size() % 100 == 0) if (_items.Size() % 100 == 0)
{ {
UInt64 numFiles = _items.Size(); UInt64 numFiles = _items.Size();
RINOK(callback->SetCompleted(&numFiles, &pos)); RINOK(callback->SetCompleted(&numFiles, &_phySize));
} }
} }
} }
@@ -134,7 +156,10 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
STDMETHODIMP CHandler::Close() STDMETHODIMP CHandler::Close()
{ {
_errorMessage.Empty();
_phySizeDefined = false; _phySizeDefined = false;
_phySize = 0;
_headersSize = 0;
_curIndex = 0; _curIndex = 0;
_latestIsRead = false; _latestIsRead = false;
_items.Clear(); _items.Clear();
@@ -163,16 +188,24 @@ HRESULT CHandler::SkipTo(UInt32 index)
{ {
UInt64 packSize = _latestItem.GetPackSize(); UInt64 packSize = _latestItem.GetPackSize();
RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL)); RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL));
_phySize += copyCoderSpec->TotalSize;
if (copyCoderSpec->TotalSize != packSize)
{
_errorMessage = kUnexpectedEnd;
return S_FALSE;
}
_latestIsRead = false; _latestIsRead = false;
_curIndex++; _curIndex++;
} }
else else
{ {
bool filled; bool filled;
// item.HeaderPosition = pos; RINOK(ReadItem2(_seqStream, filled, _latestItem));
RINOK(ReadItem(_seqStream, filled, _latestItem));
if (!filled) if (!filled)
{
_phySizeDefined = true;
return E_INVALIDARG; return E_INVALIDARG;
}
_latestIsRead = true; _latestIsRead = true;
} }
} }
@@ -207,7 +240,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{ {
case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break; case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break;
case kpidIsDir: prop = item->IsDir(); break; case kpidIsDir: prop = item->IsDir(); break;
case kpidSize: prop = item->Size; break; case kpidSize: prop = item->GetUnpackSize(); break;
case kpidPackSize: prop = item->GetPackSize(); break; case kpidPackSize: prop = item->GetPackSize(); break;
case kpidMTime: case kpidMTime:
if (item->MTime != 0) if (item->MTime != 0)
@@ -244,7 +277,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 totalSize = 0; UInt64 totalSize = 0;
UInt32 i; UInt32 i;
for (i = 0; i < numItems; i++) for (i = 0; i < numItems; i++)
totalSize += _items[allFilesMode ? i : indices[i]].Size; totalSize += _items[allFilesMode ? i : indices[i]].GetUnpackSize();
extractCallback->SetTotal(totalSize); extractCallback->SetTotal(totalSize);
UInt64 totalPackSize; UInt64 totalPackSize;
@@ -284,7 +317,8 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
item = &_items[index]; item = &_items[index];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
totalSize += item->Size; UInt64 unpackSize = item->GetUnpackSize();
totalSize += unpackSize;
totalPackSize += item->GetPackSize(); totalPackSize += item->GetPackSize();
if (item->IsDir()) if (item->IsDir())
{ {
@@ -304,14 +338,21 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
outStreamSpec->SetStream(realOutStream); outStreamSpec->SetStream(realOutStream);
realOutStream.Release(); realOutStream.Release();
outStreamSpec->Init(skipMode ? 0 : item->Size, true); outStreamSpec->Init(skipMode ? 0 : unpackSize, true);
if (item->IsLink())
{
RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length()));
}
else
{
if (!seqMode) if (!seqMode)
{ {
RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL)); RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL));
} }
streamSpec->Init(item->GetPackSize()); streamSpec->Init(item->GetPackSize());
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
}
if (seqMode) if (seqMode)
{ {
_latestIsRead = false; _latestIsRead = false;
@@ -330,6 +371,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
{ {
COM_TRY_BEGIN COM_TRY_BEGIN
const CItemEx &item = _items[index]; const CItemEx &item = _items[index];
if (item.IsLink())
{
CBufInStream *streamSpec = new CBufInStream;
CMyComPtr<IInStream> streamTemp = streamSpec;
streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Length(), (IInArchive *)this);
*stream = streamTemp.Detach();
return S_OK;
}
return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream); return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream);
COM_TRY_END COM_TRY_END
} }

View File

@@ -23,18 +23,20 @@ class CHandler:
CObjectVector<CItemEx> _items; CObjectVector<CItemEx> _items;
CMyComPtr<IInStream> _stream; CMyComPtr<IInStream> _stream;
CMyComPtr<ISequentialInStream> _seqStream; CMyComPtr<ISequentialInStream> _seqStream;
bool _isGood;
UInt32 _curIndex; UInt32 _curIndex;
bool _latestIsRead; bool _latestIsRead;
CItemEx _latestItem; CItemEx _latestItem;
UInt64 _phySize; UInt64 _phySize;
UInt64 _headersSize;
bool _phySizeDefined; bool _phySizeDefined;
AString _errorMessage;
NCompress::CCopyCoder *copyCoderSpec; NCompress::CCopyCoder *copyCoderSpec;
CMyComPtr<ICompressCoder> copyCoder; CMyComPtr<ICompressCoder> copyCoder;
HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
HRESULT SkipTo(UInt32 index); HRESULT SkipTo(UInt32 index);

View File

@@ -37,7 +37,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
IArchiveUpdateCallback *callback) IArchiveUpdateCallback *callback)
{ {
COM_TRY_BEGIN COM_TRY_BEGIN
if ((_stream && !_isGood) || _seqStream) if ((_stream && !_errorMessage.IsEmpty()) || _seqStream)
return E_NOTIMPL; return E_NOTIMPL;
CObjectVector<CUpdateItem> updateItems; CObjectVector<CUpdateItem> updateItems;
for (UInt32 i = 0; i < numItems; i++) for (UInt32 i = 0; i < numItems; i++)
@@ -107,8 +107,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (prop.vt != VT_UI8) if (prop.vt != VT_UI8)
return E_INVALIDARG; return E_INVALIDARG;
ui.Size = prop.uhVal.QuadPart; ui.Size = prop.uhVal.QuadPart;
/*
// now we support GNU extension for big files
if (ui.Size >= ((UInt64)1 << 33)) if (ui.Size >= ((UInt64)1 << 33))
return E_INVALIDARG; return E_INVALIDARG;
*/
} }
updateItems.Add(ui); updateItems.Add(ui);
} }

View File

@@ -2,6 +2,8 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "../../../../C/CpuArch.h"
#include "Common/StringToInt.h" #include "Common/StringToInt.h"
#include "../../Common/StreamUtils.h" #include "../../Common/StreamUtils.h"
@@ -61,20 +63,40 @@ static void ReadString(const char *s, int size, AString &result)
result = temp; result = temp;
} }
static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, size_t &processedSize) static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
{ {
item.LongLinkSize = 0;
char buf[NFileHeader::kRecordSize]; char buf[NFileHeader::kRecordSize];
char *p = buf; char *p = buf;
error.Empty();
filled = false; filled = false;
processedSize = NFileHeader::kRecordSize; bool thereAreEmptyRecords = false;
for (;;)
{
size_t processedSize = NFileHeader::kRecordSize;
RINOK(ReadStream(stream, buf, &processedSize)); RINOK(ReadStream(stream, buf, &processedSize));
if (processedSize == 0 || (processedSize == NFileHeader::kRecordSize && IsRecordLast(buf))) if (processedSize == 0)
{
if (!thereAreEmptyRecords )
error = "There are no trailing zero-filled records";
return S_OK; return S_OK;
if (processedSize < NFileHeader::kRecordSize) }
return S_FALSE; if (processedSize != NFileHeader::kRecordSize)
{
error = "There is no correct record at the end of archive";
return S_OK;
}
item.HeaderSize += NFileHeader::kRecordSize;
if (!IsRecordLast(buf))
break;
thereAreEmptyRecords = true;
}
if (thereAreEmptyRecords)
{
error = "There are data after end of archive";
return S_OK;
}
ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize; ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize;
@@ -83,7 +105,16 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; p += 8; if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; p += 8;
if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; p += 8; if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; p += 8;
RIF(OctalToNumber(p, 12, item.Size)); p += 12; if (GetBe32(p) == (UInt32)1 << 31)
{
// GNU extension
item.Size = GetBe64(p + 4);
}
else
{
RIF(OctalToNumber(p, 12, item.Size));
}
p += 12;
RIF(OctalToNumber32(p, 12, item.MTime)); p += 12; RIF(OctalToNumber32(p, 12, item.MTime)); p += 12;
UInt32 checkSum; UInt32 checkSum;
@@ -123,59 +154,54 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
return S_OK; return S_OK;
} }
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item) HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
{ {
size_t processedSize; item.HeaderSize = 0;
RINOK(GetNextItemReal(stream, filled, item, processedSize)); bool flagL = false;
bool flagK = false;
AString nameL;
AString nameK;
for (;;)
{
RINOK(GetNextItemReal(stream, filled, item, error));
if (!filled) if (!filled)
return S_OK; return S_OK;
// GNUtar extension
if (item.LinkFlag == 'L' || // NEXT file has a long name if (item.LinkFlag == 'L' || // NEXT file has a long name
item.LinkFlag == 'K') // NEXT file has a long linkname item.LinkFlag == 'K') // NEXT file has a long linkname
{ {
if (item.Name.Compare(NFileHeader::kLongLink) != 0) AString *name;
if (item.Name.Compare(NFileHeader::kLongLink2) != 0) if (item.LinkFlag == 'L')
return S_FALSE; { if (flagL) return S_FALSE; flagL = true; name = &nameL; }
else
{ if (flagK) return S_FALSE; flagK = true; name = &nameK; }
AString fullName; if (item.Name.Compare(NFileHeader::kLongLink) != 0 &&
if (item.Size > (1 << 15)) item.Name.Compare(NFileHeader::kLongLink2) != 0)
return S_FALSE;
if (item.Size > (1 << 14))
return S_FALSE; return S_FALSE;
int packSize = (int)item.GetPackSize(); int packSize = (int)item.GetPackSize();
char *buffer = fullName.GetBuffer(packSize + 1); char *buf = name->GetBuffer(packSize);
RINOK(ReadStream_FALSE(stream, buf, packSize));
RINOK(ReadStream_FALSE(stream, buffer, packSize)); item.HeaderSize += packSize;
processedSize += packSize; buf[(size_t)item.Size] = '\0';
buffer[item.Size] = '\0'; name->ReleaseBuffer();
fullName.ReleaseBuffer(); continue;
UInt64 headerPosition = item.HeaderPosition;
if (item.LinkFlag == 'L')
{
size_t processedSize2;
RINOK(GetNextItemReal(stream, filled, item, processedSize2));
item.LongLinkSize = (unsigned)processedSize;
} }
else if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X')
{
item.LongLinkSize = (unsigned)processedSize - NFileHeader::kRecordSize;
item.Size = 0;
}
item.Name = fullName;
item.HeaderPosition = headerPosition;
}
else if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X')
{ {
// pax Extended Header // pax Extended Header
return S_OK;
} }
else if (item.LinkFlag == NFileHeader::NLinkFlag::kDumpDir) else if (item.LinkFlag == NFileHeader::NLinkFlag::kDumpDir)
{ {
// GNU Extensions to the Archive Format // GNU Extensions to the Archive Format
return S_OK;
} }
else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0)) else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
return S_FALSE; return S_FALSE;
if (flagL) item.Name = nameL;
if (flagK) item.LinkName = nameK;
return S_OK; return S_OK;
} }
}
}} }}

View File

@@ -1,9 +1,8 @@
// Archive/TarIn.h // TarIn.h
#ifndef __ARCHIVE_TAR_IN_H #ifndef __ARCHIVE_TAR_IN_H
#define __ARCHIVE_TAR_IN_H #define __ARCHIVE_TAR_IN_H
#include "Common/MyCom.h"
#include "../../IStream.h" #include "../../IStream.h"
#include "TarItem.h" #include "TarItem.h"
@@ -11,7 +10,7 @@
namespace NArchive { namespace NArchive {
namespace NTar { namespace NTar {
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo); HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, AString &error);
}} }}

View File

@@ -31,6 +31,9 @@ struct CItem
bool DeviceMajorDefined; bool DeviceMajorDefined;
bool DeviceMinorDefined; bool DeviceMinorDefined;
bool IsLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymbolicLink && (Size == 0); }
UInt64 GetUnpackSize() const { return IsLink() ? LinkName.Length() : Size; }
bool IsDir() const bool IsDir() const
{ {
switch(LinkFlag) switch(LinkFlag)
@@ -58,10 +61,10 @@ struct CItem
struct CItemEx: public CItem struct CItemEx: public CItem
{ {
UInt64 HeaderPosition; UInt64 HeaderPos;
unsigned LongLinkSize; unsigned HeaderSize;
UInt64 GetDataPosition() const { return HeaderPosition + LongLinkSize + NFileHeader::kRecordSize; } UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
UInt64 GetFullSize() const { return LongLinkSize + NFileHeader::kRecordSize + Size; } UInt64 GetFullSize() const { return HeaderSize + Size; }
}; };
}} }}

View File

@@ -53,17 +53,23 @@ static bool MakeOctalString8(char *s, UInt32 value)
return true; return true;
} }
static bool MakeOctalString12(char *s, UInt64 value) static void MakeOctalString12(char *s, UInt64 value)
{ {
AString tempString = MakeOctalString(value); AString tempString = MakeOctalString(value);
const int kMaxSize = 12; const int kMaxSize = 12;
if (tempString.Length() > kMaxSize) if (tempString.Length() > kMaxSize)
return false; {
// GNU extension;
s[0] = (char)(Byte)0x80;
s[1] = s[2] = s[3] = 0;
for (int i = 0; i < 8; i++, value <<= 8)
s[4 + i] = (char)(value >> 56);
return;
}
int numSpaces = kMaxSize - tempString.Length(); int numSpaces = kMaxSize - tempString.Length();
for(int i = 0; i < numSpaces; i++) for(int i = 0; i < numSpaces; i++)
s[i] = ' '; s[i] = ' ';
memmove(s + numSpaces, (const char *)tempString, tempString.Length()); memmove(s + numSpaces, (const char *)tempString, tempString.Length());
return true;
} }
static bool CopyString(char *dest, const AString &src, int maxSize) static bool CopyString(char *dest, const AString &src, int maxSize)
@@ -90,17 +96,12 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
MyStrNCpy(cur, item.Name, NFileHeader::kNameSize); MyStrNCpy(cur, item.Name, NFileHeader::kNameSize);
cur += NFileHeader::kNameSize; cur += NFileHeader::kNameSize;
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.Mode)); RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.Mode)); cur += 8;
cur += 8; RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.UID)); cur += 8;
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.UID)); RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.GID)); cur += 8;
cur += 8;
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.GID));
cur += 8;
RETURN_IF_NOT_TRUE(MakeOctalString12(cur, item.Size)); MakeOctalString12(cur, item.Size); cur += 12;
cur += 12; MakeOctalString12(cur, item.MTime); cur += 12;
RETURN_IF_NOT_TRUE(MakeOctalString12(cur, item.MTime));
cur += 12;
memmove(cur, NFileHeader::kCheckSumBlanks, 8); memmove(cur, NFileHeader::kCheckSumBlanks, 8);
cur += 8; cur += 8;

View File

@@ -111,25 +111,25 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
} }
else else
{ {
const CItemEx &existItemInfo = inputItems[ui.IndexInArchive]; const CItemEx &existItem = inputItems[ui.IndexInArchive];
UInt64 size; UInt64 size;
if (ui.NewProps) if (ui.NewProps)
{ {
RINOK(outArchive.WriteHeader(item)); RINOK(outArchive.WriteHeader(item));
RINOK(inStream->Seek(existItemInfo.GetDataPosition(), STREAM_SEEK_SET, NULL)); RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL));
size = existItemInfo.Size; size = existItem.Size;
} }
else else
{ {
RINOK(inStream->Seek(existItemInfo.HeaderPosition, STREAM_SEEK_SET, NULL)); RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL));
size = existItemInfo.GetFullSize(); size = existItem.GetFullSize();
} }
streamSpec->Init(size); streamSpec->Init(size);
RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
if (copyCoderSpec->TotalSize != size) if (copyCoderSpec->TotalSize != size)
return E_FAIL; return E_FAIL;
RINOK(outArchive.FillDataResidual(existItemInfo.Size)); RINOK(outArchive.FillDataResidual(existItem.Size));
complexity += size; complexity += size;
} }
} }

View File

@@ -3,7 +3,6 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "Common/ComTry.h" #include "Common/ComTry.h"
#include "Common/NewHandler.h"
#include "Windows/PropVariant.h" #include "Windows/PropVariant.h"
#include "Windows/Time.h" #include "Windows/Time.h"
@@ -34,7 +33,7 @@ void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop)
prop = ft; prop = ft;
} }
STATPROPSTG kProps[] = static STATPROPSTG kProps[] =
{ {
{ NULL, kpidPath, VT_BSTR}, { NULL, kpidPath, VT_BSTR},
{ NULL, kpidIsDir, VT_BOOL}, { NULL, kpidIsDir, VT_BOOL},
@@ -44,7 +43,7 @@ STATPROPSTG kProps[] =
{ NULL, kpidATime, VT_FILETIME} { NULL, kpidATime, VT_FILETIME}
}; };
STATPROPSTG kArcProps[] = static STATPROPSTG kArcProps[] =
{ {
{ NULL, kpidComment, VT_BSTR}, { NULL, kpidComment, VT_BSTR},
{ NULL, kpidClusterSize, VT_UI4}, { NULL, kpidClusterSize, VT_UI4},

View File

@@ -35,4 +35,3 @@ public:
}} }}
#endif #endif

View File

@@ -202,7 +202,7 @@ enum EDescriptorType
DESC_TYPE_UnallocatedSpace = 263, DESC_TYPE_UnallocatedSpace = 263,
DESC_TYPE_SpaceBitmap = 264, DESC_TYPE_SpaceBitmap = 264,
DESC_TYPE_PartitionIntegrity = 265, DESC_TYPE_PartitionIntegrity = 265,
DESC_TYPE_ExtendedFile = 266, DESC_TYPE_ExtendedFile = 266
}; };

View File

@@ -8,6 +8,6 @@
static IInArchive *CreateArc() { return new NArchive::NUdf::CHandler; } static IInArchive *CreateArc() { return new NArchive::NUdf::CHandler; }
static CArcInfo g_ArcInfo = static CArcInfo g_ArcInfo =
{ L"Udf", L"iso", 0, 0xE0, { 0, 'N', 'S', 'R', '0' }, 5, false, CreateArc, 0 }; { L"Udf", L"iso img", 0, 0xE0, { 0, 'N', 'S', 'R', '0' }, 5, false, CreateArc, 0 };
REGISTER_ARC(Udf) REGISTER_ARC(Udf)

View File

@@ -2,18 +2,17 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "Common/IntToString.h" #include "../../../../C/CpuArch.h"
#include "Common/Defs.h"
#include "Common/ComTry.h" #include "Common/ComTry.h"
#include "Common/IntToString.h"
#include "Common/StringToInt.h" #include "Common/StringToInt.h"
#include "Common/UTFConvert.h" #include "Common/UTFConvert.h"
#include "Windows/PropVariant.h" #include "Windows/PropVariant.h"
#include "../../Common/StreamUtils.h"
#include "../../Common/ProgressUtils.h" #include "../../Common/ProgressUtils.h"
#include "../../Common/StreamUtils.h"
#include "../../../../C/CpuArch.h"
#include "WimHandler.h" #include "WimHandler.h"
@@ -28,17 +27,18 @@ namespace NWim {
#define WIM_DETAILS #define WIM_DETAILS
STATPROPSTG kProps[] = static STATPROPSTG kProps[] =
{ {
{ NULL, kpidPath, VT_BSTR}, { NULL, kpidPath, VT_BSTR},
{ NULL, kpidIsDir, VT_BOOL}, { NULL, kpidIsDir, VT_BOOL},
{ NULL, kpidSize, VT_UI8}, { NULL, kpidSize, VT_UI8},
{ NULL, kpidPackSize, VT_UI8}, { NULL, kpidPackSize, VT_UI8},
{ NULL, kpidAttrib, VT_UI4},
{ NULL, kpidMethod, VT_BSTR},
{ NULL, kpidMTime, VT_FILETIME}, { NULL, kpidMTime, VT_FILETIME},
{ NULL, kpidCTime, VT_FILETIME}, { NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidATime, VT_FILETIME} { NULL, kpidATime, VT_FILETIME},
{ NULL, kpidAttrib, VT_UI4},
{ NULL, kpidMethod, VT_BSTR},
{ NULL, kpidShortName, VT_BSTR}
#ifdef WIM_DETAILS #ifdef WIM_DETAILS
, { NULL, kpidVolume, VT_UI4} , { NULL, kpidVolume, VT_UI4}
@@ -47,14 +47,15 @@ STATPROPSTG kProps[] =
#endif #endif
}; };
STATPROPSTG kArcProps[] = static STATPROPSTG kArcProps[] =
{ {
{ NULL, kpidSize, VT_UI8}, { NULL, kpidSize, VT_UI8},
{ NULL, kpidPackSize, VT_UI8}, { NULL, kpidPackSize, VT_UI8},
{ NULL, kpidMethod, VT_BSTR}, { NULL, kpidMethod, VT_BSTR},
{ NULL, kpidCTime, VT_FILETIME}, { NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidMTime, VT_FILETIME}, { NULL, kpidMTime, VT_FILETIME},
{ NULL, kpidComment, VT_FILETIME}, { NULL, kpidComment, VT_BSTR},
{ NULL, kpidUnpackVer, VT_BSTR},
{ NULL, kpidIsVolume, VT_BOOL}, { NULL, kpidIsVolume, VT_BOOL},
{ NULL, kpidVolume, VT_UI4}, { NULL, kpidVolume, VT_UI4},
{ NULL, kpidNumVolumes, VT_UI4} { NULL, kpidNumVolumes, VT_UI4}
@@ -87,49 +88,51 @@ static bool ParseNumber32(const AString &s, UInt32 &res)
return true; return true;
} }
void ParseTime(const CXmlItem &item, bool &defined, FILETIME &ft, const AString &s) bool ParseTime(const CXmlItem &item, FILETIME &ft, const char *tag)
{ {
defined = false; int index = item.FindSubTag(tag);
int cTimeIndex = item.FindSubTag(s); if (index >= 0)
if (cTimeIndex >= 0)
{ {
const CXmlItem &timeItem = item.SubItems[cTimeIndex]; const CXmlItem &timeItem = item.SubItems[index];
UInt32 high = 0, low = 0; UInt32 low = 0, high = 0;
if (ParseNumber32(timeItem.GetSubStringForTag("HIGHPART"), high) && if (ParseNumber32(timeItem.GetSubStringForTag("LOWPART"), low) &&
ParseNumber32(timeItem.GetSubStringForTag("LOWPART"), low)) ParseNumber32(timeItem.GetSubStringForTag("HIGHPART"), high))
{ {
defined = true;
ft.dwHighDateTime = high;
ft.dwLowDateTime = low; ft.dwLowDateTime = low;
ft.dwHighDateTime = high;
return true;
} }
} }
return false;
} }
void CImageInfo::Parse(const CXmlItem &item) void CImageInfo::Parse(const CXmlItem &item)
{ {
ParseTime(item, CTimeDefined, CTime, "CREATIONTIME"); CTimeDefined = ParseTime(item, CTime, "CREATIONTIME");
ParseTime(item, MTimeDefined, MTime, "LASTMODIFICATIONTIME"); MTimeDefined = ParseTime(item, MTime, "LASTMODIFICATIONTIME");
NameDefined = ConvertUTF8ToUnicode(item.GetSubStringForTag("NAME"), Name); NameDefined = ConvertUTF8ToUnicode(item.GetSubStringForTag("NAME"), Name);
// IndexDefined = ParseNumber32(item.GetPropertyValue("INDEX"), Index); // IndexDefined = ParseNumber32(item.GetPropertyValue("INDEX"), Index);
} }
void CXml::Parse() void CXml::ToUnicode(UString &s)
{ {
size_t size = Data.GetCapacity(); size_t size = Data.GetCapacity();
if (size < 2 || (size & 1) != 0 || (size > 1 << 24)) if (size < 2 || (size & 1) != 0 || size > (1 << 24))
return; return;
const Byte *p = Data; const Byte *p = Data;
if (Get16(p) != 0xFEFF) if (Get16(p) != 0xFEFF)
return; return;
UString s; wchar_t *chars = s.GetBuffer((int)size / 2);
{
wchar_t *chars = s.GetBuffer((int)size / 2 + 1);
for (size_t i = 2; i < size; i += 2) for (size_t i = 2; i < size; i += 2)
*chars++ = (wchar_t)Get16(p + i); *chars++ = (wchar_t)Get16(p + i);
*chars = 0; *chars = 0;
s.ReleaseBuffer(); s.ReleaseBuffer();
} }
void CXml::Parse()
{
UString s;
ToUnicode(s);
AString utf; AString utf;
if (!ConvertUnicodeToUTF8(s, utf)) if (!ConvertUnicodeToUTF8(s, utf))
return; return;
@@ -151,10 +154,9 @@ void CXml::Parse()
} }
} }
static const wchar_t *kStreamsNamePrefix = L"Files" WSTRING_PATH_SEPARATOR; static const char *kMethodLZX = "LZX";
static const wchar_t *kMethodLZX = L"LZX"; static const char *kMethodXpress = "XPress";
static const wchar_t *kMethodXpress = L"XPress"; static const char *kMethodCopy = "Copy";
static const wchar_t *kMethodCopy = L"Copy";
IMP_IInArchive_Props IMP_IInArchive_Props
IMP_IInArchive_ArcProps IMP_IInArchive_ArcProps
@@ -165,22 +167,22 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
NWindows::NCOM::CPropVariant prop; NWindows::NCOM::CPropVariant prop;
const CImageInfo *image = NULL; const CImageInfo *image = NULL;
if (m_Xmls.Size() == 1) if (_xmls.Size() == 1)
{ {
const CXml &xml = m_Xmls[0]; const CXml &xml = _xmls[0];
if (xml.Images.Size() == 1) if (xml.Images.Size() == 1)
image = &xml.Images[0]; image = &xml.Images[0];
} }
switch(propID) switch(propID)
{ {
case kpidSize: prop = m_Database.GetUnpackSize(); break; case kpidSize: prop = _db.GetUnpackSize(); break;
case kpidPackSize: prop = m_Database.GetPackSize(); break; case kpidPackSize: prop = _db.GetPackSize(); break;
case kpidCTime: case kpidCTime:
if (m_Xmls.Size() == 1) if (_xmls.Size() == 1)
{ {
const CXml &xml = m_Xmls[0]; const CXml &xml = _xmls[0];
int index = -1; int index = -1;
for (int i = 0; i < xml.Images.Size(); i++) for (int i = 0; i < xml.Images.Size(); i++)
{ {
@@ -195,9 +197,9 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
break; break;
case kpidMTime: case kpidMTime:
if (m_Xmls.Size() == 1) if (_xmls.Size() == 1)
{ {
const CXml &xml = m_Xmls[0]; const CXml &xml = _xmls[0];
int index = -1; int index = -1;
for (int i = 0; i < xml.Images.Size(); i++) for (int i = 0; i < xml.Images.Size(); i++)
{ {
@@ -211,32 +213,65 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
} }
break; break;
case kpidComment: if (image != NULL && image->NameDefined) prop = image->Name; break; case kpidComment:
if (image != NULL)
{
if (_xmlInComments)
{
UString s;
_xmls[0].ToUnicode(s);
prop = s;
}
else if (image->NameDefined)
prop = image->Name;
}
break;
case kpidUnpackVer:
{
UInt32 ver1 = _version >> 16;
UInt32 ver2 = (_version >> 8) & 0xFF;
UInt32 ver3 = (_version) & 0xFF;
char s[16];
ConvertUInt32ToString(ver1, s);
AString res = s;
res += '.';
ConvertUInt32ToString(ver2, s);
res += s;
if (ver3 != 0)
{
res += '.';
ConvertUInt32ToString(ver3, s);
res += s;
}
prop = res;
break;
}
case kpidIsVolume: case kpidIsVolume:
if (m_Xmls.Size() > 0) if (_xmls.Size() > 0)
{ {
UInt16 volIndex = m_Xmls[0].VolIndex; UInt16 volIndex = _xmls[0].VolIndex;
if (volIndex < m_Volumes.Size()) if (volIndex < _volumes.Size())
prop = (m_Volumes[volIndex].Header.NumParts > 1); prop = (_volumes[volIndex].Header.NumParts > 1);
} }
break; break;
case kpidVolume: case kpidVolume:
if (m_Xmls.Size() > 0) if (_xmls.Size() > 0)
{ {
UInt16 volIndex = m_Xmls[0].VolIndex; UInt16 volIndex = _xmls[0].VolIndex;
if (volIndex < m_Volumes.Size()) if (volIndex < _volumes.Size())
prop = (UInt32)m_Volumes[volIndex].Header.PartNumber; prop = (UInt32)_volumes[volIndex].Header.PartNumber;
} }
break; break;
case kpidNumVolumes: if (m_Volumes.Size() > 0) prop = (UInt32)(m_Volumes.Size() - 1); break; case kpidNumVolumes: if (_volumes.Size() > 0) prop = (UInt32)(_volumes.Size() - 1); break;
case kpidMethod: case kpidMethod:
{ {
bool lzx = false, xpress = false, copy = false; bool lzx = false, xpress = false, copy = false;
for (int i = 0; i < m_Xmls.Size(); i++) for (int i = 0; i < _xmls.Size(); i++)
{ {
const CVolume &vol = m_Volumes[m_Xmls[i].VolIndex]; const CHeader &header = _volumes[_xmls[i].VolIndex].Header;
const CHeader &header = vol.Header;
if (header.IsCompressed()) if (header.IsCompressed())
if (header.IsLzxMode()) if (header.IsLzxMode())
lzx = true; lzx = true;
@@ -245,19 +280,19 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
else else
copy = true; copy = true;
} }
UString res; AString res;
if (lzx) if (lzx)
res = kMethodLZX; res = kMethodLZX;
if (xpress) if (xpress)
{ {
if (!res.IsEmpty()) if (!res.IsEmpty())
res += L' '; res += ' ';
res += kMethodXpress; res += kMethodXpress;
} }
if (copy) if (copy)
{ {
if (!res.IsEmpty()) if (!res.IsEmpty())
res += L' '; res += ' ';
res += kMethodCopy; res += kMethodCopy;
} }
prop = res; prop = res;
@@ -272,35 +307,41 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{ {
COM_TRY_BEGIN COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop; NWindows::NCOM::CPropVariant prop;
if (index < (UInt32)m_Database.Items.Size()) if (index < (UInt32)_db.SortedItems.Size())
{ {
const CItem &item = m_Database.Items[index]; int realIndex = _db.SortedItems[index];
const CItem &item = _db.Items[realIndex];
const CStreamInfo *si = NULL; const CStreamInfo *si = NULL;
const CVolume *vol = NULL; const CVolume *vol = NULL;
if (item.StreamIndex >= 0) if (item.StreamIndex >= 0)
{ {
si = &m_Database.Streams[item.StreamIndex]; si = &_db.Streams[item.StreamIndex];
vol = &m_Volumes[si->PartNumber]; vol = &_volumes[si->PartNumber];
} }
switch(propID) switch(propID)
{ {
case kpidPath: case kpidPath:
if (item.HasMetadata) if (item.HasMetadata)
prop = item.Name; prop = _db.GetItemPath(realIndex);
else else
{ {
wchar_t sz[32]; char sz[16];
ConvertUInt64ToString(item.StreamIndex, sz); ConvertUInt32ToString(item.StreamIndex, sz);
UString s = sz; AString s = sz;
while (s.Length() < m_NameLenForStreams) while (s.Length() < _nameLenForStreams)
s = L'0' + s; s = '0' + s;
s = UString(kStreamsNamePrefix) + s; /*
if (si->Resource.IsFree())
prefix = "[Free]";
*/
s = "[Files]" STRING_PATH_SEPARATOR + s;
prop = s; prop = s;
break;
} }
break; break;
case kpidIsDir: prop = item.isDir(); break; case kpidShortName: if (item.HasMetadata) prop = item.ShortName; break;
case kpidIsDir: prop = item.IsDir(); break;
case kpidAttrib: if (item.HasMetadata) prop = item.Attrib; break; case kpidAttrib: if (item.HasMetadata) prop = item.Attrib; break;
case kpidCTime: if (item.HasMetadata) prop = item.CTime; break; case kpidCTime: if (item.HasMetadata) prop = item.CTime; break;
case kpidATime: if (item.HasMetadata) prop = item.ATime; break; case kpidATime: if (item.HasMetadata) prop = item.ATime; break;
@@ -318,22 +359,21 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
} }
else else
{ {
index -= m_Database.Items.Size(); index -= _db.SortedItems.Size();
{ {
switch(propID) switch(propID)
{ {
case kpidPath: case kpidPath:
{ {
wchar_t sz[32]; char sz[16];
ConvertUInt64ToString(m_Xmls[index].VolIndex, sz); ConvertUInt32ToString(_xmls[index].VolIndex, sz);
UString s = (UString)sz + L".xml"; prop = (AString)"[" + (AString)sz + "].xml";
prop = s;
break; break;
} }
case kpidIsDir: prop = false; break; case kpidIsDir: prop = false; break;
case kpidPackSize: case kpidPackSize:
case kpidSize: prop = (UInt64)m_Xmls[index].Data.GetCapacity(); break; case kpidSize: prop = (UInt64)_xmls[index].Data.GetCapacity(); break;
case kpidMethod: prop = L"Copy"; break; case kpidMethod: prop = kMethodCopy; break;
} }
} }
} }
@@ -362,8 +402,8 @@ public:
UString GetNextName(UInt32 index) UString GetNextName(UInt32 index)
{ {
wchar_t s[32]; wchar_t s[16];
ConvertUInt64ToString((index), s); ConvertUInt32ToString(index, s);
return _before + (UString)s + _after; return _before + (UString)s + _after;
} }
}; };
@@ -374,7 +414,6 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
{ {
COM_TRY_BEGIN COM_TRY_BEGIN
Close(); Close();
try
{ {
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
@@ -410,14 +449,16 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
continue; continue;
return res; return res;
} }
_version = header.Version;
_isOldVersion = header.IsOldVersion();
if (firstVolumeIndex >= 0) if (firstVolumeIndex >= 0)
if (!header.AreFromOnArchive(m_Volumes[firstVolumeIndex].Header)) if (!header.AreFromOnArchive(_volumes[firstVolumeIndex].Header))
break; break;
if (m_Volumes.Size() > header.PartNumber && m_Volumes[header.PartNumber].Stream) if (_volumes.Size() > header.PartNumber && _volumes[header.PartNumber].Stream)
break; break;
CXml xml; CXml xml;
xml.VolIndex = header.PartNumber; xml.VolIndex = header.PartNumber;
res = OpenArchive(curStream, header, xml.Data, m_Database); res = _db.Open(curStream, header, xml.Data, openArchiveCallback);
if (res != S_OK) if (res != S_OK)
{ {
if (i == 1) if (i == 1)
@@ -427,22 +468,22 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
return res; return res;
} }
while (m_Volumes.Size() <= header.PartNumber) while (_volumes.Size() <= header.PartNumber)
m_Volumes.Add(CVolume()); _volumes.Add(CVolume());
CVolume &volume = m_Volumes[header.PartNumber]; CVolume &volume = _volumes[header.PartNumber];
volume.Header = header; volume.Header = header;
volume.Stream = curStream; volume.Stream = curStream;
firstVolumeIndex = header.PartNumber; firstVolumeIndex = header.PartNumber;
bool needAddXml = true; bool needAddXml = true;
if (m_Xmls.Size() != 0) if (_xmls.Size() != 0)
if (xml.Data == m_Xmls[0].Data) if (xml.Data == _xmls[0].Data)
needAddXml = false; needAddXml = false;
if (needAddXml) if (needAddXml)
{ {
xml.Parse(); xml.Parse();
m_Xmls.Add(xml); _xmls.Add(xml);
} }
if (i == 1) if (i == 1)
@@ -462,15 +503,14 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
} }
} }
RINOK(SortDatabase(m_Database)); _db.DetectPathMode();
RINOK(_db.Sort(_db.SkipRoot));
wchar_t sz[32]; wchar_t sz[16];
ConvertUInt64ToString(m_Database.Streams.Size(), sz); ConvertUInt32ToString(_db.Streams.Size(), sz);
m_NameLenForStreams = MyStringLen(sz); _nameLenForStreams = MyStringLen(sz);
}
catch(...) _xmlInComments = (_xmls.Size() == 1 && !_db.ShowImageNumber);
{
return S_FALSE;
} }
return S_OK; return S_OK;
COM_TRY_END COM_TRY_END
@@ -478,10 +518,10 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
STDMETHODIMP CHandler::Close() STDMETHODIMP CHandler::Close()
{ {
m_Database.Clear(); _db.Clear();
m_Volumes.Clear(); _volumes.Clear();
m_Xmls.Clear(); _xmls.Clear();
m_NameLenForStreams = 0; _nameLenForStreams = 0;
return S_OK; return S_OK;
} }
@@ -492,7 +532,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
bool allFilesMode = (numItems == (UInt32)-1); bool allFilesMode = (numItems == (UInt32)-1);
if (allFilesMode) if (allFilesMode)
numItems = m_Database.Items.Size() + m_Xmls.Size(); numItems = _db.SortedItems.Size() + _xmls.Size();
if (numItems == 0) if (numItems == 0)
return S_OK; return S_OK;
@@ -501,17 +541,17 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
for (i = 0; i < numItems; i++) for (i = 0; i < numItems; i++)
{ {
UInt32 index = allFilesMode ? i : indices[i]; UInt32 index = allFilesMode ? i : indices[i];
if (index < (UInt32)m_Database.Items.Size()) if (index < (UInt32)_db.SortedItems.Size())
{ {
int streamIndex = m_Database.Items[index].StreamIndex; int streamIndex = _db.Items[_db.SortedItems[index]].StreamIndex;
if (streamIndex >= 0) if (streamIndex >= 0)
{ {
const CStreamInfo &si = m_Database.Streams[streamIndex]; const CStreamInfo &si = _db.Streams[streamIndex];
totalSize += si.Resource.UnpackSize; totalSize += si.Resource.UnpackSize;
} }
} }
else else
totalSize += m_Xmls[index - (UInt32)m_Database.Items.Size()].Data.GetCapacity(); totalSize += _xmls[index - (UInt32)_db.SortedItems.Size()].Data.GetCapacity();
} }
RINOK(extractCallback->SetTotal(totalSize)); RINOK(extractCallback->SetTotal(totalSize));
@@ -546,12 +586,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ISequentialOutStream> realOutStream; CMyComPtr<ISequentialOutStream> realOutStream;
RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
if (index >= (UInt32)m_Database.Items.Size()) if (index >= (UInt32)_db.SortedItems.Size())
{ {
if (!testMode && !realOutStream) if (!testMode && !realOutStream)
continue; continue;
RINOK(extractCallback->PrepareOperation(askMode)); RINOK(extractCallback->PrepareOperation(askMode));
const CByteBuffer &data = m_Xmls[index - (UInt32)m_Database.Items.Size()].Data; const CByteBuffer &data = _xmls[index - (UInt32)_db.SortedItems.Size()].Data;
currentItemUnPacked = data.GetCapacity(); currentItemUnPacked = data.GetCapacity();
if (realOutStream) if (realOutStream)
{ {
@@ -562,7 +602,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
continue; continue;
} }
const CItem &item = m_Database.Items[index]; const CItem &item = _db.Items[_db.SortedItems[index]];
int streamIndex = item.StreamIndex; int streamIndex = item.StreamIndex;
if (streamIndex < 0) if (streamIndex < 0)
{ {
@@ -576,7 +616,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
continue; continue;
} }
const CStreamInfo &si = m_Database.Streams[streamIndex]; const CStreamInfo &si = _db.Streams[streamIndex];
currentItemUnPacked = si.Resource.UnpackSize; currentItemUnPacked = si.Resource.UnpackSize;
currentItemPacked = si.Resource.PackSize; currentItemPacked = si.Resource.PackSize;
@@ -587,7 +627,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (streamIndex != prevSuccessStreamIndex || realOutStream) if (streamIndex != prevSuccessStreamIndex || realOutStream)
{ {
Byte digest[20]; Byte digest[20];
const CVolume &vol = m_Volumes[si.PartNumber]; const CVolume &vol = _volumes[si.PartNumber];
HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header.IsLzxMode(), HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header.IsLzxMode(),
realOutStream, progress, digest); realOutStream, progress, digest);
if (res == S_OK) if (res == S_OK)
@@ -611,7 +651,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{ {
*numItems = m_Database.Items.Size() + m_Xmls.Size(); *numItems = _db.SortedItems.Size();
if (!_xmlInComments)
*numItems += _xmls.Size();
return S_OK; return S_OK;
} }

View File

@@ -6,7 +6,6 @@
#include "Common/MyCom.h" #include "Common/MyCom.h"
#include "Common/MyXml.h" #include "Common/MyXml.h"
#include "../IArchive.h"
#include "WimIn.h" #include "WimIn.h"
namespace NArchive { namespace NArchive {
@@ -40,25 +39,37 @@ struct CXml
{ {
CByteBuffer Data; CByteBuffer Data;
UInt16 VolIndex; UInt16 VolIndex;
CObjectVector<CImageInfo> Images; CObjectVector<CImageInfo> Images;
void ToUnicode(UString &s);
void Parse(); void Parse();
}; };
class CHandler: class CHandler:
public IInArchive, public IInArchive,
public CMyUnknownImp public CMyUnknownImp
{ {
CDatabase _db;
UInt32 _version;
bool _isOldVersion;
CObjectVector<CVolume> _volumes;
CObjectVector<CXml> _xmls;
int _nameLenForStreams;
bool _xmlInComments;
public: public:
MY_UNKNOWN_IMP1(IInArchive) MY_UNKNOWN_IMP1(IInArchive)
INTERFACE_IInArchive(;) INTERFACE_IInArchive(;)
};
private: class COutHandler:
CDatabase m_Database; public IOutArchive,
CObjectVector<CVolume> m_Volumes; public CMyUnknownImp
CObjectVector<CXml> m_Xmls; {
int m_NameLenForStreams; public:
MY_UNKNOWN_IMP1(IOutArchive)
INTERFACE_IOutArchive(;)
}; };
}} }}

View File

@@ -0,0 +1,639 @@
// WimHandlerOut.cpp
#include "StdAfx.h"
#include "../../../../C/CpuArch.h"
#include "Common/ComTry.h"
#include "Common/IntToString.h"
#include "Windows/PropVariant.h"
#include "Windows/Time.h"
#include "../../Common/LimitedStreams.h"
#include "../../Common/ProgressUtils.h"
#include "../../Common/StreamUtils.h"
#include "../../Crypto/RandGen.h"
#include "../../Crypto/Sha1.h"
#include "WimHandler.h"
using namespace NWindows;
namespace NArchive {
namespace NWim {
struct CSha1Hash
{
Byte Hash[kHashSize];
};
struct CHashList
{
CRecordVector<CSha1Hash> Digests;
CIntVector Sorted;
int AddUnique(const CSha1Hash &h);
};
int CHashList::AddUnique(const CSha1Hash &h)
{
int left = 0, right = Sorted.Size();
while (left != right)
{
int mid = (left + right) / 2;
int index = Sorted[mid];
UInt32 i;
const Byte *hash2 = Digests[index].Hash;
for (i = 0; i < kHashSize; i++)
if (h.Hash[i] != hash2[i])
break;
if (i == kHashSize)
return index;
if (h.Hash[i] < hash2[i])
right = mid;
else
left = mid + 1;
}
Sorted.Insert(left, Digests.Add(h));
return -1;
}
struct CUpdateItem
{
UString Name;
UInt64 Size;
FILETIME CTime;
FILETIME ATime;
FILETIME MTime;
UInt32 Attrib;
bool IsDir;
int HashIndex;
CUpdateItem(): HashIndex(-1) {}
};
struct CDir
{
int Index;
UString Name;
CObjectVector<CDir> Dirs;
CIntVector Files;
CDir(): Index(-1) {}
bool IsLeaf() const { return Index >= 0; }
UInt64 GetNumDirs() const;
UInt64 GetNumFiles() const;
CDir* AddDir(CObjectVector<CUpdateItem> &items, const UString &name, int index);
};
UInt64 CDir::GetNumDirs() const
{
UInt64 num = Dirs.Size();
for (int i = 0; i < Dirs.Size(); i++)
num += Dirs[i].GetNumDirs();
return num;
}
UInt64 CDir::GetNumFiles() const
{
UInt64 num = Files.Size();
for (int i = 0; i < Dirs.Size(); i++)
num += Dirs[i].GetNumFiles();
return num;
}
CDir* CDir::AddDir(CObjectVector<CUpdateItem> &items, const UString &name, int index)
{
int left = 0, right = Dirs.Size();
while (left != right)
{
int mid = (left + right) / 2;
CDir &d = Dirs[mid];
int compare = name.CompareNoCase(d.IsLeaf() ? items[Dirs[mid].Index].Name : d.Name);
if (compare == 0)
{
if (index >= 0)
d.Index = index;
return &d;
}
if (compare < 0)
right = mid;
else
left = mid + 1;
}
Dirs.Insert(left, CDir());
CDir &d = Dirs[left];
d.Index = index;
if (index < 0)
d.Name = name;
return &d;
}
STDMETHODIMP COutHandler::GetFileTimeType(UInt32 *type)
{
*type = NFileTimeType::kWindows;
return S_OK;
}
static HRESULT GetTime(IArchiveUpdateCallback *callback, int index, PROPID propID, FILETIME &ft)
{
ft.dwLowDateTime = ft.dwHighDateTime = 0;
NCOM::CPropVariant prop;
RINOK(callback->GetProperty(index, propID, &prop));
if (prop.vt == VT_FILETIME)
ft = prop.filetime;
else if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
return S_OK;
}
#define Set16(p, d) SetUi16(p, d)
#define Set32(p, d) SetUi32(p, d)
#define Set64(p, d) SetUi64(p, d)
void CResource::WriteTo(Byte *p) const
{
Set64(p, PackSize);
p[7] = Flags;
Set64(p + 8, Offset);
Set64(p + 16, UnpackSize);
}
void CHeader::WriteTo(Byte *p) const
{
memcpy(p, kSignature, kSignatureSize);
Set32(p + 8, kHeaderSizeMax);
Set32(p + 0xC, Version);
Set32(p + 0x10, Flags);
Set32(p + 0x14, ChunkSize);
memcpy(p + 0x18, Guid, 16);
Set16(p + 0x28, PartNumber);
Set16(p + 0x2A, NumParts);
Set32(p + 0x2C, NumImages);
OffsetResource.WriteTo(p + 0x30);
XmlResource.WriteTo(p + 0x48);
MetadataResource.WriteTo(p + 0x60);
IntegrityResource.WriteTo(p + 0x7C);
Set32(p + 0x78, BootIndex);
memset(p + 0x94, 0, 60);
}
void CStreamInfo::WriteTo(Byte *p) const
{
Resource.WriteTo(p);
Set16(p + 0x18, PartNumber);
Set32(p + 0x1A, RefCount);
memcpy(p + 0x1E, Hash, kHashSize);
}
class CInStreamWithSha1:
public ISequentialInStream,
public CMyUnknownImp
{
CMyComPtr<ISequentialInStream> _stream;
UInt64 _size;
NCrypto::NSha1::CContext _sha;
public:
MY_UNKNOWN_IMP1(IInStream)
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
void SetStream(ISequentialInStream *stream) { _stream = stream; }
void Init()
{
_size = 0;
_sha.Init();
}
void ReleaseStream() { _stream.Release(); }
UInt64 GetSize() const { return _size; }
void Final(Byte *digest) { _sha.Final(digest); }
};
STDMETHODIMP CInStreamWithSha1::Read(void *data, UInt32 size, UInt32 *processedSize)
{
UInt32 realProcessedSize;
HRESULT result = _stream->Read(data, size, &realProcessedSize);
_size += realProcessedSize;
_sha.Update((const Byte *)data, realProcessedSize);
if (processedSize != NULL)
*processedSize = realProcessedSize;
return result;
}
static void SetFileTimeToMem(Byte *p, const FILETIME &ft)
{
Set32(p, ft.dwLowDateTime);
Set32(p + 4, ft.dwHighDateTime);
}
static size_t WriteItem(const CUpdateItem &item, Byte *p, const Byte *hash)
{
int fileNameLen = item.Name.Length() * 2;
int fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2);
size_t totalLen = ((kDirRecordSize + fileNameLen2 + 6) & ~7);
if (p)
{
memset(p, 0, totalLen);
Set64(p, totalLen);
Set64(p + 8, item.Attrib);
Set32(p + 0xC, (UInt32)(Int32)-1); // item.SecurityId
// Set64(p + 0x10, 0); // subdirOffset
SetFileTimeToMem(p + 0x28, item.CTime);
SetFileTimeToMem(p + 0x30, item.ATime);
SetFileTimeToMem(p + 0x38, item.MTime);
if (hash)
memcpy(p + 0x40, hash, kHashSize);
/*
else
memset(p + 0x40, 0, kHashSize);
*/
// Set16(p + 98, 0); // shortNameLen
Set16(p + 100, (UInt16)fileNameLen);
for (int i = 0; i * 2 < fileNameLen; i++)
Set16(p + kDirRecordSize + i * 2, item.Name[i]);
}
return totalLen;
}
static void WriteTree(const CDir &tree, CRecordVector<CSha1Hash> &digests,
CUpdateItem &defaultDirItem,
CObjectVector<CUpdateItem> &updateItems, Byte *dest, size_t &pos)
{
int i;
for (i = 0; i < tree.Files.Size(); i++)
{
const CUpdateItem &ui = updateItems[tree.Files[i]];
pos += WriteItem(ui, dest ? dest + pos : NULL,
ui.HashIndex >= 0 ? digests[ui.HashIndex].Hash : NULL);
}
size_t posStart = pos;
for (i = 0; i < tree.Dirs.Size(); i++)
{
const CDir &subfolder = tree.Dirs[i];
CUpdateItem *item = &defaultDirItem;
if (subfolder.IsLeaf())
item = &updateItems[subfolder.Index];
else
defaultDirItem.Name = subfolder.Name;
pos += WriteItem(*item, NULL, NULL);
}
if (dest)
Set64(dest + pos, 0);
pos += 8;
for (i = 0; i < tree.Dirs.Size(); i++)
{
const CDir &subfolder = tree.Dirs[i];
if (dest)
{
CUpdateItem *item = &defaultDirItem;
if (subfolder.IsLeaf())
item = &updateItems[subfolder.Index];
else
defaultDirItem.Name = subfolder.Name;
size_t len = WriteItem(*item, dest + posStart, NULL);
Set64(dest + posStart + 0x10, pos);
posStart += len;
}
WriteTree(subfolder, digests, defaultDirItem, updateItems, dest, pos);
}
}
static void AddTag(AString &s, const char *name, const AString &value)
{
s += "<";
s += name;
s += ">";
s += value;
s += "</";
s += name;
s += ">";
}
static void AddTagUInt64(AString &s, const char *name, UInt64 value)
{
char temp[32];
ConvertUInt64ToString(value, temp);
AddTag(s, name, temp);
}
static AString TimeToXml(FILETIME &ft)
{
AString res;
char temp[16] = { '0', 'x' };
ConvertUInt32ToHexWithZeros(ft.dwHighDateTime, temp + 2);
AddTag(res, "HIGHPART", temp);
ConvertUInt32ToHexWithZeros(ft.dwLowDateTime, temp + 2);
AddTag(res, "LOWPART", temp);
return res;
}
void CHeader::SetDefaultFields(bool useLZX)
{
Version = kWimVersion;
Flags = NHeaderFlags::kRpFix;
ChunkSize = 0;
if (useLZX)
{
Flags |= NHeaderFlags::kCompression | NHeaderFlags::kLZX;
ChunkSize = kChunkSize;
}
g_RandomGenerator.Generate(Guid, 16);
PartNumber = 1;
NumParts = 1;
NumImages = 1;
BootIndex = 0;
OffsetResource.Clear();
XmlResource.Clear();
MetadataResource.Clear();
IntegrityResource.Clear();
}
static HRESULT UpdateArchive(ISequentialOutStream *seqOutStream,
CDir &rootFolder,
CObjectVector<CUpdateItem> &updateItems,
IArchiveUpdateCallback *callback)
{
CMyComPtr<IOutStream> outStream;
RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));
if (!outStream)
return E_NOTIMPL;
UInt64 complexity = 0;
int i;
for (i = 0; i < updateItems.Size(); i++)
complexity += updateItems[i].Size;
RINOK(callback->SetTotal(complexity));
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(callback, true);
complexity = 0;
bool useCompression = false;
CHeader header;
header.SetDefaultFields(useCompression);
Byte buf[kHeaderSizeMax];
header.WriteTo(buf);
RINOK(WriteStream(outStream, buf, kHeaderSizeMax));
CHashList hashes;
CObjectVector<CStreamInfo> streams;
UInt64 curPos = kHeaderSizeMax;
UInt64 unpackTotalSize = 0;
for (i = 0; i < updateItems.Size(); i++)
{
lps->InSize = lps->OutSize = complexity;
RINOK(lps->SetCur());
CUpdateItem &ui = updateItems[i];
if (ui.IsDir || ui.Size == 0)
continue;
CInStreamWithSha1 *inShaStreamSpec = new CInStreamWithSha1;
CMyComPtr<ISequentialInStream> inShaStream = inShaStreamSpec;
{
CMyComPtr<ISequentialInStream> fileInStream;
HRESULT res = callback->GetStream(i, &fileInStream);
if (res != S_FALSE)
{
RINOK(res);
inShaStreamSpec->SetStream(fileInStream);
fileInStream.Release();
inShaStreamSpec->Init();
UInt64 offsetBlockSize = 0;
if (useCompression)
{
for (UInt64 t = kChunkSize; t < ui.Size; t += kChunkSize)
{
Byte buf[8];
SetUi32(buf, (UInt32)t);
RINOK(WriteStream(outStream, buf, 4));
offsetBlockSize += 4;
}
}
RINOK(copyCoder->Code(inShaStream, outStream, NULL, NULL, progress));
ui.Size = copyCoderSpec->TotalSize;
CSha1Hash hash;
unpackTotalSize += ui.Size;
UInt64 packSize = offsetBlockSize + ui.Size;
inShaStreamSpec->Final(hash.Hash);
int index = hashes.AddUnique(hash);
if (index >= 0)
{
ui.HashIndex = index;
streams[index].RefCount++;
outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos);
outStream->SetSize(curPos);
}
else
{
ui.HashIndex = hashes.Digests.Size() - 1;
CStreamInfo s;
s.Resource.PackSize = packSize;
s.Resource.Offset = curPos;
s.Resource.UnpackSize = ui.Size;
s.Resource.Flags = 0;
if (useCompression)
s.Resource.Flags = NResourceFlags::Compressed;
s.PartNumber = 1;
s.RefCount = 1;
memcpy(s.Hash, hash.Hash, kHashSize);
streams.Add(s);
curPos += packSize;
}
}
fileInStream.Release();
complexity += ui.Size;
RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
}
}
CUpdateItem ri;
FILETIME ft;
NTime::GetCurUtcFileTime(ft);
ri.MTime = ri.ATime = ri.CTime = ft;
ri.Attrib = FILE_ATTRIBUTE_DIRECTORY;
const UInt32 kSecuritySize = 8;
size_t pos = kSecuritySize;
WriteTree(rootFolder, hashes.Digests, ri, updateItems, NULL, pos);
CByteBuffer meta;
meta.SetCapacity(pos);
// we can write 0 here only if there is no security data, imageX does it,
// but some programs expect size = 8
Set32((Byte *)meta, 8); // size of security data
Set32((Byte *)meta + 4, 0); // num security entries
pos = kSecuritySize;
WriteTree(rootFolder, hashes.Digests, ri, updateItems, (Byte *)meta, pos);
{
NCrypto::NSha1::CContext sha;
sha.Init();
sha.Update((const Byte *)meta, pos);
CSha1Hash digest;
sha.Final(digest.Hash);
CStreamInfo s;
s.Resource.PackSize = pos;
s.Resource.Offset = curPos;
s.Resource.UnpackSize = pos;
s.Resource.Flags = NResourceFlags::kMetadata;
s.PartNumber = 1;
s.RefCount = 1;
memcpy(s.Hash, digest.Hash, kHashSize);
streams.Add(s);
RINOK(WriteStream(outStream, (const Byte *)meta, pos));
meta.Free();
curPos += pos;
}
header.OffsetResource.UnpackSize = header.OffsetResource.PackSize = (UInt64)streams.Size() * kStreamInfoSize;
header.OffsetResource.Offset = curPos;
header.OffsetResource.Flags = NResourceFlags::kMetadata;
for (i = 0; i < streams.Size(); i++)
{
Byte buf[kStreamInfoSize];
streams[i].WriteTo(buf);
RINOK(WriteStream(outStream, buf, kStreamInfoSize));
curPos += kStreamInfoSize;
}
AString xml = "<WIM>";
AddTagUInt64(xml, "TOTALBYTES", curPos);
xml += "<IMAGE INDEX=\"1\"><NAME>1</NAME>";
AddTagUInt64(xml, "DIRCOUNT", rootFolder.GetNumDirs());
AddTagUInt64(xml, "FILECOUNT", rootFolder.GetNumFiles());
AddTagUInt64(xml, "TOTALBYTES", unpackTotalSize);
NTime::GetCurUtcFileTime(ft);
AddTag(xml, "CREATIONTIME", TimeToXml(ft));
AddTag(xml, "LASTMODIFICATIONTIME", TimeToXml(ft));
xml += "</IMAGE></WIM>";
size_t xmlSize = (xml.Length() + 1) * 2;
meta.SetCapacity(xmlSize);
Set16((Byte *)meta, 0xFEFF);
for (i = 0; i < xml.Length(); i++)
Set16((Byte *)meta + 2 + i * 2, xml[i]);
RINOK(WriteStream(outStream, (const Byte *)meta, xmlSize));
meta.Free();
header.XmlResource.UnpackSize = header.XmlResource.PackSize = xmlSize;
header.XmlResource.Offset = curPos;
header.XmlResource.Flags = NResourceFlags::kMetadata;
outStream->Seek(0, STREAM_SEEK_SET, NULL);
header.WriteTo(buf);
return WriteStream(outStream, buf, kHeaderSizeMax);
}
STDMETHODIMP COutHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
IArchiveUpdateCallback *callback)
{
COM_TRY_BEGIN
CObjectVector<CUpdateItem> updateItems;
CDir tree;
tree.Dirs.Add(CDir());
CDir &rootFolder = tree.Dirs.Back();
for (UInt32 i = 0; i < numItems; i++)
{
CUpdateItem ui;
Int32 newData, newProps;
UInt32 indexInArchive;
if (!callback)
return E_FAIL;
RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
{
NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, kpidIsDir, &prop));
if (prop.vt == VT_EMPTY)
ui.IsDir = false;
else if (prop.vt != VT_BOOL)
return E_INVALIDARG;
else
ui.IsDir = (prop.boolVal != VARIANT_FALSE);
}
{
NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, kpidAttrib, &prop));
if (prop.vt == VT_EMPTY)
ui.Attrib = (ui.IsDir ? FILE_ATTRIBUTE_DIRECTORY : 0);
else if (prop.vt != VT_UI4)
return E_INVALIDARG;
else
ui.Attrib = prop.ulVal;
}
RINOK(GetTime(callback, i, kpidCTime, ui.CTime));
RINOK(GetTime(callback, i, kpidATime, ui.ATime));
RINOK(GetTime(callback, i, kpidMTime, ui.MTime));
{
NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, kpidSize, &prop));
if (prop.vt != VT_UI8)
return E_INVALIDARG;
ui.Size = prop.uhVal.QuadPart;
}
UString path;
NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, kpidPath, &prop));
if (prop.vt == VT_BSTR)
path = prop.bstrVal;
else if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
CDir *curItem = &rootFolder;
int len = path.Length();
UString fileName;
for (int j = 0; j < len; j++)
{
wchar_t c = path[j];
if (c == WCHAR_PATH_SEPARATOR || c == L'/')
{
curItem = curItem->AddDir(updateItems, fileName, -1);
fileName.Empty();
}
else
fileName += c;
}
ui.Name = fileName;
updateItems.Add(ui);
if (ui.IsDir)
curItem->AddDir(updateItems, fileName, (int)i);
else
curItem->Files.Add(i);
}
return UpdateArchive(outStream, tree, updateItems, callback);
COM_TRY_END
}
}}

View File

@@ -21,9 +21,6 @@
namespace NArchive { namespace NArchive {
namespace NWim { namespace NWim {
static const int kChunkSizeBits = 15;
static const UInt32 kChunkSize = (1 << kChunkSizeBits);
namespace NXpress { namespace NXpress {
class CDecoderFlusher class CDecoderFlusher
@@ -44,7 +41,7 @@ HRESULT CDecoder::CodeSpec(UInt32 outSize)
{ {
{ {
Byte levels[kMainTableSize]; Byte levels[kMainTableSize];
for (int i = 0; i < kMainTableSize; i += 2) for (unsigned i = 0; i < kMainTableSize; i += 2)
{ {
Byte b = m_InBitStream.DirectReadByte(); Byte b = m_InBitStream.DirectReadByte();
levels[i] = b & 0xF; levels[i] = b & 0xF;
@@ -128,12 +125,6 @@ HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outS
} }
static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
{
ft->dwLowDateTime = Get32(p);
ft->dwHighDateTime = Get32(p + 4);
}
HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool lzxMode, HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool lzxMode,
ISequentialOutStream *outStream, ICompressProgressInfo *progress) ISequentialOutStream *outStream, ICompressProgressInfo *progress)
{ {
@@ -249,7 +240,7 @@ static HRESULT UnpackData(IInStream *inStream, const CResource &resource, bool l
buf.Free(); buf.Free();
buf.SetCapacity(size); buf.SetCapacity(size);
CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2(); CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream();
CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
outStreamSpec->Init((Byte *)buf, size); outStreamSpec->Init((Byte *)buf, size);
@@ -257,9 +248,6 @@ static HRESULT UnpackData(IInStream *inStream, const CResource &resource, bool l
return unpacker.Unpack(inStream, resource, lzxMode, outStream, NULL, digest); return unpacker.Unpack(inStream, resource, lzxMode, outStream, NULL, digest);
} }
static const UInt32 kSignatureSize = 8;
static const Byte kSignature[kSignatureSize] = { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 };
void CResource::Parse(const Byte *p) void CResource::Parse(const Byte *p)
{ {
Flags = p[7]; Flags = p[7];
@@ -270,74 +258,300 @@ void CResource::Parse(const Byte *p)
#define GetResource(p, res) res.Parse(p) #define GetResource(p, res) res.Parse(p)
static void GetStream(const Byte *p, CStreamInfo &s) static void GetStream(bool oldVersion, const Byte *p, CStreamInfo &s)
{ {
s.Resource.Parse(p); s.Resource.Parse(p);
if (oldVersion)
{
s.PartNumber = 1;
s.Id = Get32(p + 24);
s.RefCount = Get32(p + 28);
memcpy(s.Hash, p + 32, kHashSize);
}
else
{
s.PartNumber = Get16(p + 24); s.PartNumber = Get16(p + 24);
s.RefCount = Get32(p + 26); s.RefCount = Get32(p + 26);
memcpy(s.Hash, p + 30, kHashSize); memcpy(s.Hash, p + 30, kHashSize);
} }
}
static HRESULT ParseDirItem(const Byte *base, size_t pos, size_t size, static const wchar_t *kLongPath = L"[LongPath]";
const UString &prefix, CObjectVector<CItem> &items)
UString CDatabase::GetItemPath(const int index1) const
{ {
for (;;) int size = 0;
int index = index1;
int newLevel;
for (newLevel = 0;; newLevel = 1)
{ {
if (pos + 8 > size) const CItem &item = Items[index];
return S_FALSE; index = item.Parent;
const Byte *p = base + pos; if (index >= 0 || !SkipRoot)
UInt64 length = Get64(p); size += item.Name.Length() + newLevel;
if (length == 0) if (index < 0)
break;
if ((UInt32)size >= ((UInt32)1 << 16))
return kLongPath;
}
wchar_t temp[16];
int imageLen = 0;
if (ShowImageNumber)
{
ConvertUInt32ToString(-1 - index, temp);
imageLen = MyStringLen(temp);
size += imageLen + 1;
}
if ((UInt32)size >= ((UInt32)1 << 16))
return kLongPath;
UString path;
wchar_t *s = path.GetBuffer(size);
s[size] = 0;
if (ShowImageNumber)
{
memcpy(s, temp, imageLen * sizeof(wchar_t));
s[imageLen] = WCHAR_PATH_SEPARATOR;
}
index = index1;
for (newLevel = 0;; newLevel = 1)
{
const CItem &item = Items[index];
index = item.Parent;
if (index >= 0 || !SkipRoot)
{
if (newLevel)
s[--size] = WCHAR_PATH_SEPARATOR;
size -= item.Name.Length();
memcpy(s + size, item.Name, sizeof(wchar_t) * item.Name.Length());
}
if (index < 0)
{
path.ReleaseBuffer();
return path;
}
}
}
static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
{
ft->dwLowDateTime = Get32(p);
ft->dwHighDateTime = Get32(p + 4);
}
static HRESULT ReadName(const Byte *p, int size, UString &dest)
{
if (size == 0)
return S_OK; return S_OK;
if (pos + 102 > size || pos + length + 8 > size || length > ((UInt64)1 << 62)) if (Get16(p + size) != 0)
return S_FALSE; return S_FALSE;
wchar_t *s = dest.GetBuffer(size / 2);
for (int i = 0; i <= size; i += 2)
*s++ = Get16(p + i);
dest.ReleaseBuffer();
return S_OK;
}
HRESULT CDatabase::ParseDirItem(size_t pos, int parent)
{
if ((pos & 7) != 0)
return S_FALSE;
int prevIndex = -1;
for (int numItems = 0;; numItems++)
{
if (OpenCallback)
{
UInt64 numFiles = Items.Size();
if ((numFiles & 0x3FF) == 0)
{
RINOK(OpenCallback->SetCompleted(&numFiles, NULL));
}
}
size_t rem = DirSize - pos;
if (pos < DirStartOffset || pos > DirSize || rem < 8)
return S_FALSE;
const Byte *p = DirData + pos;
UInt64 len = Get64(p);
if (len == 0)
{
if (parent < 0 && numItems != 1)
SkipRoot = false;
DirProcessed += 8;
return S_OK;
}
if ((len & 7) != 0 || rem < len)
return S_FALSE;
if (!IsOldVersion)
if (len < 0x28)
return S_FALSE;
DirProcessed += (size_t)len;
if (DirProcessed > DirSize)
return S_FALSE;
int extraOffset = 0;
if (IsOldVersion)
{
if (len < 0x40 || (/* Get32(p + 12) == 0 && */ Get32(p + 0x14) != 0))
{
extraOffset = 0x10;
}
}
else if (Get64(p + 8) == 0)
extraOffset = 0x24;
if (extraOffset)
{
if (prevIndex == -1)
return S_FALSE;
UInt32 fileNameLen = Get16(p + extraOffset);
if ((fileNameLen & 1) != 0)
return S_FALSE;
/* Probably different versions of ImageX can use different number of
additional ZEROs. So we don't use exact check. */
UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2);
if (((extraOffset + 2 + fileNameLen2 + 6) & ~7) > len)
return S_FALSE;
UString name;
RINOK(ReadName(p + extraOffset + 2, fileNameLen, name));
CItem &prevItem = Items[prevIndex];
if (name.IsEmpty() && !prevItem.HasStream())
{
if (IsOldVersion)
prevItem.Id = Get32(p + 8);
else
memcpy(prevItem.Hash, p + 0x10, kHashSize);
}
else
{
CItem item;
item.Name = prevItem.Name + L':' + name;
item.CTime = prevItem.CTime;
item.ATime = prevItem.ATime;
item.MTime = prevItem.MTime;
if (IsOldVersion)
{
item.Id = Get32(p + 8);
memset(item.Hash, 0, kHashSize);
}
else
memcpy(item.Hash, p + 0x10, kHashSize);
item.Attrib = 0;
item.Order = Order++;
item.Parent = parent;
Items.Add(item);
}
pos += (size_t)len;
continue;
}
UInt32 dirRecordSize = IsOldVersion ? kDirRecordSizeOld : kDirRecordSize;
if (len < dirRecordSize)
return S_FALSE;
CItem item; CItem item;
item.Attrib = Get32(p + 8); item.Attrib = Get32(p + 8);
// item.SecurityId = Get32(p + 0xC); // item.SecurityId = Get32(p + 0xC);
UInt64 subdirOffset = Get64(p + 0x10); UInt64 subdirOffset = Get64(p + 0x10);
GetFileTimeFromMem(p + 0x28, &item.CTime); UInt32 timeOffset = IsOldVersion ? 0x18: 0x28;
GetFileTimeFromMem(p + 0x30, &item.ATime); GetFileTimeFromMem(p + timeOffset, &item.CTime);
GetFileTimeFromMem(p + 0x38, &item.MTime); GetFileTimeFromMem(p + timeOffset + 8, &item.ATime);
GetFileTimeFromMem(p + timeOffset + 16, &item.MTime);
if (IsOldVersion)
{
item.Id = Get32(p + 0x10);
memset(item.Hash, 0, kHashSize);
}
else
{
memcpy(item.Hash, p + 0x40, kHashSize); memcpy(item.Hash, p + 0x40, kHashSize);
}
// UInt32 numStreams = Get16(p + dirRecordSize - 6);
UInt32 shortNameLen = Get16(p + dirRecordSize - 4);
UInt32 fileNameLen = Get16(p + dirRecordSize - 2);
// UInt16 shortNameLen = Get16(p + 98); if ((shortNameLen & 1) != 0 || (fileNameLen & 1) != 0)
UInt16 fileNameLen = Get16(p + 100);
size_t tempPos = pos + 102;
if (tempPos + fileNameLen > size)
return S_FALSE; return S_FALSE;
wchar_t *sz = item.Name.GetBuffer(prefix.Length() + fileNameLen / 2 + 1); UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2);
MyStringCopy(sz, (const wchar_t *)prefix); UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2);
sz += prefix.Length();
for (UInt16 i = 0; i + 2 <= fileNameLen; i += 2) if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) > len)
*sz++ = Get16(base + tempPos + i); return S_FALSE;
*sz++ = '\0'; p += dirRecordSize;
item.Name.ReleaseBuffer();
if (fileNameLen == 0 && item.isDir() && !item.HasStream()) RINOK(ReadName(p, fileNameLen, item.Name));
RINOK(ReadName(p + fileNameLen2, shortNameLen, item.ShortName));
if (parent < 0 && (shortNameLen || fileNameLen || !item.IsDir()))
SkipRoot = false;
/*
// there are some extra data for some files.
p -= dirRecordSize;
p += ((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7);
if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) != len)
p = p;
*/
/*
if (parent >= 0)
{ {
UString s = GetItemPath(parent) + L"\\" + item.Name;
printf("\n%s %8x %S", item.IsDir() ? "D" : " ", (int)subdirOffset, (const wchar_t *)s);
}
*/
if (fileNameLen == 0 && item.IsDir() && !item.HasStream())
item.Attrib = 0x10; // some swm archives have system/hidden attributes for root item.Attrib = 0x10; // some swm archives have system/hidden attributes for root
item.Name.Delete(item.Name.Length() - 1);
} item.Parent = parent;
items.Add(item); prevIndex = Items.Add(item);
pos += (size_t)length; if (item.IsDir() && subdirOffset != 0)
if (item.isDir() && (subdirOffset != 0))
{ {
if (subdirOffset >= size) RINOK(ParseDirItem((size_t)subdirOffset, prevIndex));
return S_FALSE;
RINOK(ParseDirItem(base, (size_t)subdirOffset, size, item.Name + WCHAR_PATH_SEPARATOR, items));
} }
Items[prevIndex].Order = Order++;
pos += (size_t)len;
} }
} }
static HRESULT ParseDir(const Byte *base, size_t size, HRESULT CDatabase::ParseImageDirs(const CByteBuffer &buf, int parent)
const UString &prefix, CObjectVector<CItem> &items)
{ {
DirData = buf;
DirSize = buf.GetCapacity();
size_t pos = 0; size_t pos = 0;
if (pos + 8 > size) if (DirSize < 8)
return S_FALSE; return S_FALSE;
const Byte *p = base + pos; const Byte *p = DirData;
UInt32 totalLength = Get32(p); UInt32 totalLength = Get32(p);
if (IsOldVersion)
{
for (pos = 4;; pos += 8)
{
if (pos + 4 > DirSize)
return S_FALSE;
UInt32 n = Get32(p + pos);
if (n == 0)
break;
if (pos + 8 > DirSize)
return S_FALSE;
totalLength += Get32(p + pos + 4);
if (totalLength > DirSize)
return S_FALSE;
}
pos += totalLength + 4;
pos = (pos + 7) & ~(size_t)7;
if (pos > DirSize)
return S_FALSE;
}
else
{
// UInt32 numEntries = Get32(p + 4); // UInt32 numEntries = Get32(p + 4);
pos += 8; pos += 8;
{ {
@@ -346,29 +560,162 @@ static HRESULT ParseDir(const Byte *base, size_t size,
UInt64 sum = 0; UInt64 sum = 0;
for (UInt32 i = 0; i < numEntries; i++) for (UInt32 i = 0; i < numEntries; i++)
{ {
if (pos + 8 > size) if (pos + 8 > DirSize)
return S_FALSE; return S_FALSE;
UInt64 len = Get64(p + pos); UInt64 len = Get64(p + pos);
entryLens.Add(len); entryLens.Add(len);
sum += len; sum += len;
pos += 8; pos += 8;
} }
pos += sum; // skip security descriptors pos += (size_t)sum; // skip security descriptors
while ((pos & 7) != 0) while ((pos & 7) != 0)
pos++; pos++;
if (pos != totalLength) if (pos != totalLength)
return S_FALSE; return S_FALSE;
*/ */
if (totalLength == 0)
pos = 8;
else if (totalLength < 8)
return S_FALSE;
else
pos = totalLength; pos = totalLength;
} }
return ParseDirItem(base, pos, size, prefix, items); }
DirStartOffset = DirProcessed = pos;
RINOK(ParseDirItem(pos, parent));
if (DirProcessed == DirSize)
return S_OK;
/* Original program writes additional 8 bytes (END_OF_ROOT_FOLDER), but
reference to that folder is empty */
if (DirProcessed == DirSize - 8 && DirProcessed - DirStartOffset == 112 &&
Get64(p + DirSize - 8) == 0)
return S_OK;
return S_FALSE;
} }
static int CompareHashRefs(const int *p1, const int *p2, void *param) HRESULT CHeader::Parse(const Byte *p)
{ {
const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param; UInt32 headerSize = Get32(p + 8);
return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize); Version = Get32(p + 0x0C);
Flags = Get32(p + 0x10);
if (!IsSupported())
return S_FALSE;
ChunkSize = Get32(p + 0x14);
if (ChunkSize != kChunkSize && ChunkSize != 0)
return S_FALSE;
int offset;
if (IsOldVersion())
{
if (headerSize != 0x60)
return S_FALSE;
memset(Guid, 0, 16);
offset = 0x18;
PartNumber = 1;
NumParts = 1;
} }
else
{
if (headerSize < 0x74)
return S_FALSE;
memcpy(Guid, p + 0x18, 16);
PartNumber = Get16(p + 0x28);
NumParts = Get16(p + 0x2A);
offset = 0x2C;
if (IsNewVersion())
{
NumImages = Get32(p + offset);
offset += 4;
}
}
GetResource(p + offset, OffsetResource);
GetResource(p + offset + 0x18, XmlResource);
GetResource(p + offset + 0x30, MetadataResource);
if (IsNewVersion())
{
if (headerSize < 0xD0)
return S_FALSE;
BootIndex = Get32(p + 0x48);
IntegrityResource.Parse(p + offset + 0x4C);
}
return S_OK;
}
const Byte kSignature[kSignatureSize] = { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 };
HRESULT ReadHeader(IInStream *inStream, CHeader &h)
{
Byte p[kHeaderSizeMax];
RINOK(ReadStream_FALSE(inStream, p, kHeaderSizeMax));
if (memcmp(p, kSignature, kSignatureSize) != 0)
return S_FALSE;
return h.Parse(p);
}
static HRESULT ReadStreams(bool oldVersion, IInStream *inStream, const CHeader &h, CDatabase &db)
{
CByteBuffer offsetBuf;
RINOK(UnpackData(inStream, h.OffsetResource, h.IsLzxMode(), offsetBuf, NULL));
size_t i;
size_t streamInfoSize = oldVersion ? kStreamInfoSize + 2 : kStreamInfoSize;
for (i = 0; offsetBuf.GetCapacity() - i >= streamInfoSize; i += streamInfoSize)
{
CStreamInfo s;
GetStream(oldVersion, (const Byte *)offsetBuf + i, s);
if (s.PartNumber == h.PartNumber)
db.Streams.Add(s);
}
return (i == offsetBuf.GetCapacity()) ? S_OK : S_FALSE;
}
static bool IsEmptySha(const Byte *data)
{
for (int i = 0; i < kHashSize; i++)
if (data[i] != 0)
return false;
return true;
}
HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback)
{
OpenCallback = openCallback;
IsOldVersion = h.IsOldVersion();
RINOK(UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL));
RINOK(ReadStreams(h.IsOldVersion(), inStream, h, *this));
bool needBootMetadata = !h.MetadataResource.IsEmpty();
Order = 0;
if (h.PartNumber == 1)
{
int imageIndex = 1;
for (int i = 0; i < Streams.Size(); i++)
{
// if (imageIndex > 1) break;
const CStreamInfo &si = Streams[i];
if (!si.Resource.IsMetadata() || si.PartNumber != h.PartNumber)
continue;
Byte hash[kHashSize];
CByteBuffer metadata;
RINOK(UnpackData(inStream, si.Resource, h.IsLzxMode(), metadata, hash));
if (memcmp(hash, si.Hash, kHashSize) != 0 &&
!(h.IsOldVersion() && IsEmptySha(si.Hash)))
return S_FALSE;
NumImages++;
RINOK(ParseImageDirs(metadata, -(int)(++imageIndex)));
if (needBootMetadata)
if (h.MetadataResource.Offset == si.Resource.Offset)
needBootMetadata = false;
}
}
if (needBootMetadata)
{
CByteBuffer metadata;
RINOK(UnpackData(inStream, h.MetadataResource, h.IsLzxMode(), metadata, NULL));
RINOK(ParseImageDirs(metadata, -1));
NumImages++;
}
return S_OK;
}
static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, void * /* param */) static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, void * /* param */)
{ {
@@ -378,24 +725,39 @@ static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, voi
return MyCompare(p1->Resource.Offset, p2->Resource.Offset); return MyCompare(p1->Resource.Offset, p2->Resource.Offset);
} }
int CompareItems(void *const *a1, void *const *a2, void * /* param */) static int CompareIDs(const int *p1, const int *p2, void *param)
{ {
const CItem &i1 = **((const CItem **)a1); const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param;
const CItem &i2 = **((const CItem **)a2); return MyCompare(streams[*p1].Id, streams[*p2].Id);
}
if (i1.isDir() != i2.isDir()) static int CompareHashRefs(const int *p1, const int *p2, void *param)
return (i1.isDir()) ? 1 : -1; {
if (i1.isDir()) const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param;
return -MyStringCompareNoCase(i1.Name, i2.Name); return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize);
}
int res = MyCompare(i1.StreamIndex, i2.StreamIndex); static int FindId(const CRecordVector<CStreamInfo> &streams,
if (res != 0) const CIntVector &sortedByHash, UInt32 id)
return res; {
return MyStringCompareNoCase(i1.Name, i2.Name); int left = 0, right = streams.Size();
while (left != right)
{
int mid = (left + right) / 2;
int streamIndex = sortedByHash[mid];
UInt32 id2 = streams[streamIndex].Id;
if (id == id2)
return streamIndex;
if (id < id2)
right = mid;
else
left = mid + 1;
}
return -1;
} }
static int FindHash(const CRecordVector<CStreamInfo> &streams, static int FindHash(const CRecordVector<CStreamInfo> &streams,
const CRecordVector<int> &sortedByHash, const Byte *hash) const CIntVector &sortedByHash, const Byte *hash)
{ {
int left = 0, right = streams.Size(); int left = 0, right = streams.Size();
while (left != right) while (left != right)
@@ -417,153 +779,76 @@ static int FindHash(const CRecordVector<CStreamInfo> &streams,
return -1; return -1;
} }
HRESULT CHeader::Parse(const Byte *p) static int CompareItems(const int *a1, const int *a2, void *param)
{ {
UInt32 haderSize = Get32(p + 8); const CObjectVector<CItem> &items = ((CDatabase *)param)->Items;
if (haderSize < 0x74) const CItem &i1 = items[*a1];
return S_FALSE; const CItem &i2 = items[*a2];
Version = Get32(p + 0x0C);
Flags = Get32(p + 0x10); if (i1.IsDir() != i2.IsDir())
if (!IsSupported()) return i1.IsDir() ? 1 : -1;
return S_FALSE; int res = MyCompare(i1.StreamIndex, i2.StreamIndex);
UInt32 chunkSize = Get32(p + 0x14); if (res != 0)
if (chunkSize != kChunkSize && chunkSize != 0) return res;
return S_FALSE; return MyCompare(i1.Order, i2.Order);
memcpy(Guid, p + 0x18, 16);
PartNumber = Get16(p + 0x28);
NumParts = Get16(p + 0x2A);
int offset = 0x2C;
if (IsNewVersion())
{
NumImages = Get32(p + offset);
offset += 4;
}
GetResource(p + offset, OffsetResource);
GetResource(p + offset + 0x18, XmlResource);
GetResource(p + offset + 0x30, MetadataResource);
/*
if (IsNewVersion())
{
if (haderSize < 0xD0)
return S_FALSE;
IntegrityResource.Parse(p + offset + 0x4C);
BootIndex = Get32(p + 0x48);
}
*/
return S_OK;
} }
HRESULT ReadHeader(IInStream *inStream, CHeader &h) HRESULT CDatabase::Sort(bool skipRootDir)
{ {
const UInt32 kHeaderSizeMax = 0xD0; Streams.Sort(CompareStreamsByPos, NULL);
Byte p[kHeaderSizeMax];
RINOK(ReadStream_FALSE(inStream, p, kHeaderSizeMax));
if (memcmp(p, kSignature, kSignatureSize) != 0)
return S_FALSE;
return h.Parse(p);
}
HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db)
{
CByteBuffer offsetBuf;
RINOK(UnpackData(inStream, h.OffsetResource, h.IsLzxMode(), offsetBuf, NULL));
for (size_t i = 0; i + kStreamInfoSize <= offsetBuf.GetCapacity(); i += kStreamInfoSize)
{
CStreamInfo s;
GetStream((const Byte *)offsetBuf + i, s);
if (s.PartNumber == h.PartNumber)
db.Streams.Add(s);
}
return S_OK;
}
HRESULT OpenArchive(IInStream *inStream, const CHeader &h, CByteBuffer &xml, CDatabase &db)
{
RINOK(UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL));
RINOK(ReadStreams(inStream, h, db));
bool needBootMetadata = !h.MetadataResource.IsEmpty();
if (h.PartNumber == 1)
{
int imageIndex = 1;
for (int j = 0; j < db.Streams.Size(); j++)
{
// if (imageIndex > 1) break;
const CStreamInfo &si = db.Streams[j];
if (!si.Resource.IsMetadata() || si.PartNumber != h.PartNumber)
continue;
Byte hash[kHashSize];
CByteBuffer metadata;
RINOK(UnpackData(inStream, si.Resource, h.IsLzxMode(), metadata, hash));
if (memcmp(hash, si.Hash, kHashSize) != 0)
return S_FALSE;
wchar_t sz[16];
ConvertUInt32ToString(imageIndex++, sz);
UString s = sz;
s += WCHAR_PATH_SEPARATOR;
RINOK(ParseDir(metadata, metadata.GetCapacity(), s, db.Items));
if (needBootMetadata)
if (h.MetadataResource.Offset == si.Resource.Offset)
needBootMetadata = false;
}
}
if (needBootMetadata)
{
CByteBuffer metadata;
RINOK(UnpackData(inStream, h.MetadataResource, h.IsLzxMode(), metadata, NULL));
RINOK(ParseDir(metadata, metadata.GetCapacity(), L"0" WSTRING_PATH_SEPARATOR, db.Items));
}
return S_OK;
}
HRESULT SortDatabase(CDatabase &db)
{
db.Streams.Sort(CompareStreamsByPos, NULL);
{ {
CRecordVector<int> sortedByHash; CIntVector sortedByHash;
{ {
for (int j = 0; j < db.Streams.Size(); j++) for (int i = 0; i < Streams.Size(); i++)
sortedByHash.Add(j); sortedByHash.Add(i);
sortedByHash.Sort(CompareHashRefs, &db.Streams); if (IsOldVersion)
sortedByHash.Sort(CompareIDs, &Streams);
else
sortedByHash.Sort(CompareHashRefs, &Streams);
} }
for (int i = 0; i < db.Items.Size(); i++) for (int i = 0; i < Items.Size(); i++)
{ {
CItem &item = db.Items[i]; CItem &item = Items[i];
item.StreamIndex = -1; item.StreamIndex = -1;
if (item.HasStream()) if (item.HasStream())
item.StreamIndex = FindHash(db.Streams, sortedByHash, item.Hash); if (IsOldVersion)
item.StreamIndex = FindId(Streams, sortedByHash, item.Id);
else
item.StreamIndex = FindHash(Streams, sortedByHash, item.Hash);
} }
} }
{ {
CRecordVector<bool> used; CRecordVector<bool> used;
int j; int i;
for (j = 0; j < db.Streams.Size(); j++) for (i = 0; i < Streams.Size(); i++)
{ {
const CStreamInfo &s = db.Streams[j]; const CStreamInfo &s = Streams[i];
used.Add(s.Resource.IsMetadata() && s.PartNumber == 1); used.Add(s.Resource.IsMetadata() && s.PartNumber == 1);
// used.Add(false);
} }
for (int i = 0; i < db.Items.Size(); i++) for (i = 0; i < Items.Size(); i++)
{ {
CItem &item = db.Items[i]; CItem &item = Items[i];
if (item.StreamIndex >= 0) if (item.StreamIndex >= 0)
used[item.StreamIndex] = true; used[item.StreamIndex] = true;
} }
for (j = 0; j < db.Streams.Size(); j++) for (i = 0; i < Streams.Size(); i++)
if (!used[j]) if (!used[i])
{ {
CItem item; CItem item;
item.StreamIndex = j; item.StreamIndex = i;
item.HasMetadata = false; item.HasMetadata = false;
db.Items.Add(item); Items.Add(item);
} }
} }
db.Items.Sort(CompareItems, NULL); SortedItems.Reserve(Items.Size());
for (int i = (skipRootDir ? 1 : 0); i < Items.Size(); i++)
SortedItems.Add(i);
SortedItems.Sort(CompareItems, this);
return S_OK; return S_OK;
} }

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