mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-17 08:11:49 -06:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de4f8c22fe | ||
|
|
b75af1bba6 | ||
|
|
c65230d858 | ||
|
|
2eb60a0598 | ||
|
|
044e4bb741 | ||
|
|
e279500d76 | ||
|
|
708873490e |
@@ -1,7 +1,6 @@
|
||||
/* 7zAlloc.c -- Allocation functions
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
2010-10-29 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "7zAlloc.h"
|
||||
|
||||
/* #define _SZ_ALLOC_DEBUG */
|
||||
@@ -1,14 +1,10 @@
|
||||
/* 7zAlloc.h -- Allocation functions
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
2010-10-29 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_ALLOC_H
|
||||
#define __7Z_ALLOC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
void *SzAlloc(void *p, size_t size);
|
||||
void SzFree(void *p, void *address);
|
||||
@@ -16,8 +12,4 @@ void SzFree(void *p, void *address);
|
||||
void *SzAllocTemp(void *p, size_t size);
|
||||
void SzFreeTemp(void *p, void *address);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
52
C/7zDec.c
52
C/7zDec.c
@@ -1,5 +1,5 @@
|
||||
/* 7zDec.c -- Decoding from 7z folder
|
||||
2010-03-15 : Igor Pavlov : Public domain */
|
||||
2010-11-02 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
#define k_LZMA2 0x21
|
||||
#define k_LZMA 0x30101
|
||||
#define k_BCJ 0x03030103
|
||||
#define k_PPC 0x03030205
|
||||
#define k_ARM 0x03030501
|
||||
#define k_ARMT 0x03030701
|
||||
#define k_SPARC 0x03030805
|
||||
#define k_BCJ2 0x0303011B
|
||||
|
||||
#ifdef _7ZIP_PPMD_SUPPPORT
|
||||
@@ -260,7 +264,6 @@ static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
|
||||
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)
|
||||
|
||||
static SRes CheckSupportedFolder(const CSzFolder *f)
|
||||
@@ -277,11 +280,24 @@ static SRes CheckSupportedFolder(const CSzFolder *f)
|
||||
}
|
||||
if (f->NumCoders == 2)
|
||||
{
|
||||
if (!IS_BCJ(&f->Coders[1]) ||
|
||||
f->NumPackStreams != 1 || f->PackStreams[0] != 0 ||
|
||||
CSzCoderInfo *c = &f->Coders[1];
|
||||
if (c->MethodID > (UInt32)0xFFFFFFFF ||
|
||||
c->NumInStreams != 1 ||
|
||||
c->NumOutStreams != 1 ||
|
||||
f->NumPackStreams != 1 ||
|
||||
f->PackStreams[0] != 0 ||
|
||||
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;
|
||||
switch ((UInt32)c->MethodID)
|
||||
{
|
||||
case k_BCJ:
|
||||
case k_ARM:
|
||||
break;
|
||||
default:
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
if (f->NumCoders == 4)
|
||||
@@ -314,6 +330,8 @@ static UInt64 GetSum(const UInt64 *values, UInt32 index)
|
||||
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,
|
||||
ILookInStream *inStream, UInt64 startPos,
|
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
|
||||
@@ -391,14 +409,6 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
|
||||
#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)
|
||||
{
|
||||
UInt64 offset = GetSum(packSizes, 1);
|
||||
@@ -425,7 +435,23 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
|
||||
RINOK(res)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ci != 1)
|
||||
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;
|
||||
}
|
||||
|
||||
16
C/7zIn.c
16
C/7zIn.c
@@ -1,5 +1,5 @@
|
||||
/* 7zIn.c -- 7z Input functions
|
||||
2010-03-11 : Igor Pavlov : Public domain */
|
||||
2010-10-29 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -1218,12 +1218,16 @@ static SRes SzArEx_Open2(
|
||||
ISzAlloc *allocTemp)
|
||||
{
|
||||
Byte header[k7zStartHeaderSize];
|
||||
Int64 startArcPos;
|
||||
UInt64 nextHeaderOffset, nextHeaderSize;
|
||||
size_t nextHeaderSizeT;
|
||||
UInt32 nextHeaderCRC;
|
||||
CBuf buffer;
|
||||
SRes res;
|
||||
|
||||
startArcPos = 0;
|
||||
RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR));
|
||||
|
||||
RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE));
|
||||
|
||||
if (!TestSignatureCandidate(header))
|
||||
@@ -1235,7 +1239,7 @@ static SRes SzArEx_Open2(
|
||||
nextHeaderSize = GetUi64(header + 20);
|
||||
nextHeaderCRC = GetUi32(header + 28);
|
||||
|
||||
p->startPosAfterHeader = k7zStartHeaderSize;
|
||||
p->startPosAfterHeader = startArcPos + k7zStartHeaderSize;
|
||||
|
||||
if (CrcCalc(header + 12, 20) != GetUi32(header + 8))
|
||||
return SZ_ERROR_CRC;
|
||||
@@ -1252,13 +1256,13 @@ static SRes SzArEx_Open2(
|
||||
{
|
||||
Int64 pos = 0;
|
||||
RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END));
|
||||
if ((UInt64)pos < nextHeaderOffset ||
|
||||
(UInt64)pos < k7zStartHeaderSize + nextHeaderOffset ||
|
||||
(UInt64)pos < k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)
|
||||
if ((UInt64)pos < startArcPos + nextHeaderOffset ||
|
||||
(UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset ||
|
||||
(UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)
|
||||
return SZ_ERROR_INPUT_EOF;
|
||||
}
|
||||
|
||||
RINOK(LookInStream_SeekTo(inStream, k7zStartHeaderSize + nextHeaderOffset));
|
||||
RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset));
|
||||
|
||||
if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp))
|
||||
return SZ_ERROR_MEM;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#define MY_VER_MAJOR 9
|
||||
#define MY_VER_MINOR 13
|
||||
#define MY_VER_MINOR 20
|
||||
#define MY_VER_BUILD 0
|
||||
#define MY_VERSION "9.13 beta"
|
||||
#define MY_DATE "2010-04-15"
|
||||
#define MY_VERSION "9.20"
|
||||
#define MY_DATE "2010-11-18"
|
||||
#define MY_COPYRIGHT ": Igor Pavlov : Public domain"
|
||||
#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE
|
||||
|
||||
6
C/Bra.c
6
C/Bra.c
@@ -1,5 +1,5 @@
|
||||
/* Bra.c -- Converters for RISC code
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
2010-04-16 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Bra.h"
|
||||
|
||||
@@ -104,8 +104,8 @@ SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
|
||||
size -= 4;
|
||||
for (i = 0; i <= size; i += 4)
|
||||
{
|
||||
if (data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00 ||
|
||||
data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0)
|
||||
if ((data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00) ||
|
||||
(data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0))
|
||||
{
|
||||
UInt32 src =
|
||||
((UInt32)data[i + 0] << 24) |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* CpuArch.c -- CPU specific code
|
||||
2009-12-12: Igor Pavlov : Public domain */
|
||||
2010-10-26: Igor Pavlov : Public domain */
|
||||
|
||||
#include "CpuArch.h"
|
||||
|
||||
|
||||
21
C/CpuArch.h
21
C/CpuArch.h
@@ -1,5 +1,5 @@
|
||||
/* CpuArch.h -- CPU specific code
|
||||
2010-03-11: Igor Pavlov : Public domain */
|
||||
2010-10-26: Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __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
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_M_IA64)
|
||||
#define MY_CPU_IA64_LE
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_X86_OR_AMD64)
|
||||
#define MY_CPU_LE_UNALIGN
|
||||
#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
|
||||
#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
|
||||
|
||||
#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 SetUi16(p, d) *(UInt16 *)(p) = (d);
|
||||
#define SetUi32(p, d) *(UInt32 *)(p) = (d);
|
||||
#define SetUi64(p, d) *(UInt64 *)(p) = (d);
|
||||
|
||||
#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))[3] = (Byte)(_x_ >> 24); }
|
||||
|
||||
#define SetUi64(p, d) { UInt64 _x64_ = (d); \
|
||||
SetUi32(p, (UInt32)_x64_); \
|
||||
SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); }
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Lzma2Enc.c -- LZMA2 Encoder
|
||||
2010-03-25 : Igor Pavlov : Public domain */
|
||||
2010-09-24 : Igor Pavlov : Public domain */
|
||||
|
||||
/* #include <stdio.h> */
|
||||
#include <string.h>
|
||||
@@ -141,7 +141,7 @@ static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf,
|
||||
|
||||
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;
|
||||
outBuf[destPos++] = (Byte)(pm >> 8);
|
||||
@@ -269,7 +269,7 @@ static SRes Lzma2Enc_EncodeMt1(CLzma2EncInt *p, CLzma2Enc *mainEncoder,
|
||||
|
||||
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)
|
||||
return SZ_ERROR_MEM;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* LzmaEnc.c -- LZMA Encoder
|
||||
2009-11-24 : Igor Pavlov : Public domain */
|
||||
2010-04-16 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -395,7 +395,7 @@ SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
|
||||
LzmaEncProps_Normalize(&props);
|
||||
|
||||
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;
|
||||
p->dictSize = props.dictSize;
|
||||
p->matchFinderCycles = props.mc;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* MtCoder.c -- Multi-thread Coder
|
||||
2010-03-24 : Igor Pavlov : Public domain */
|
||||
2010-09-24 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -148,7 +148,7 @@ static void CMtThread_Destruct(CMtThread *p)
|
||||
#define MY_BUF_ALLOC(buf, size, newSize) \
|
||||
if (buf == 0 || size != newSize) \
|
||||
{ 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; }
|
||||
|
||||
static SRes CMtThread_Prepare(CMtThread *p)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Ppmd8Dec.c -- PPMdI Decoder
|
||||
2010-03-12 : Igor Pavlov : Public domain
|
||||
2010-04-16 : Igor Pavlov : Public domain
|
||||
This code is based on:
|
||||
PPMd var.I (2002): Dmitry Shkarin : 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;
|
||||
|
||||
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->Range <<= 8;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Ppmd8Enc.c -- PPMdI Encoder
|
||||
2010-03-12 : Igor Pavlov : Public domain
|
||||
2010-04-16 : Igor Pavlov : Public domain
|
||||
This code is based on:
|
||||
PPMd var.I (2002): Dmitry Shkarin : 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)
|
||||
{
|
||||
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->Range <<= 8;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* Crypto/Sha256.c -- SHA-256 Hash function
|
||||
2008-11-06 : Igor Pavlov : Public domain
|
||||
/* Crypto/Sha256.c -- SHA-256 Hash
|
||||
2010-06-11 : Igor Pavlov : Public domain
|
||||
This code is based on public domain code from Wei Dai's Crypto++ library. */
|
||||
|
||||
#include "Sha256.h"
|
||||
#include "RotateDefs.h"
|
||||
#include "Sha256.h"
|
||||
|
||||
/* define it for speed optimization */
|
||||
/* #define _SHA256_UNROLL */
|
||||
@@ -71,7 +71,7 @@ void Sha256_Init(CSha256 *p)
|
||||
|
||||
#endif
|
||||
|
||||
const UInt32 K[64] = {
|
||||
static const UInt32 K[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
|
||||
10
C/Sha256.h
10
C/Sha256.h
@@ -1,14 +1,12 @@
|
||||
/* Sha256.h -- SHA-256 Hash
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
2010-06-11 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __CRYPTO_SHA256_H
|
||||
#define __CRYPTO_SHA256_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#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_Final(CSha256 *p, Byte *digest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
|
||||
4
C/Sort.c
4
C/Sort.c
@@ -1,7 +1,5 @@
|
||||
/* Sort.c -- Sort functions
|
||||
2008-08-17
|
||||
Igor Pavlov
|
||||
Public domain */
|
||||
2010-09-17 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Sort.h"
|
||||
|
||||
|
||||
20
C/Types.h
20
C/Types.h
@@ -1,5 +1,5 @@
|
||||
/* Types.h -- Basic types
|
||||
2010-03-11 : Igor Pavlov : Public domain */
|
||||
2010-10-09 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_TYPES_H
|
||||
#define __7Z_TYPES_H
|
||||
@@ -77,9 +77,11 @@ typedef unsigned long UInt64;
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
typedef __int64 Int64;
|
||||
typedef unsigned __int64 UInt64;
|
||||
#define UINT64_CONST(n) n
|
||||
#else
|
||||
typedef long long int Int64;
|
||||
typedef unsigned long long int UInt64;
|
||||
#define UINT64_CONST(n) n ## ULL
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -231,6 +233,22 @@ typedef struct
|
||||
#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
|
||||
#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
|
||||
|
||||
#endif
|
||||
|
||||
@@ -92,6 +92,14 @@ 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
|
||||
@@ -141,6 +149,10 @@ 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
|
||||
@@ -196,14 +208,6 @@ SOURCE=..\..\Types.h
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zAlloc.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zAlloc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zMain.c
|
||||
# End Source File
|
||||
# End Target
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
/* 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 <string.h>
|
||||
|
||||
#include "../../7z.h"
|
||||
#include "../../7zAlloc.h"
|
||||
#include "../../7zCrc.h"
|
||||
#include "../../7zFile.h"
|
||||
#include "../../7zVersion.h"
|
||||
|
||||
#include "7zAlloc.h"
|
||||
|
||||
#ifndef USE_WINDOWS_FILE
|
||||
/* for mkdir */
|
||||
#ifdef _WIN32
|
||||
@@ -21,12 +20,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define CHAR_PATH_SEPARATOR '\\'
|
||||
#else
|
||||
#define CHAR_PATH_SEPARATOR '/'
|
||||
#endif
|
||||
|
||||
static ISzAlloc g_Alloc = { SzAlloc, SzFree };
|
||||
|
||||
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
|
||||
|
||||
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;
|
||||
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 = '_';
|
||||
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);
|
||||
if (numChars == 0 || numChars >= size)
|
||||
return SZ_ERROR_FAIL;
|
||||
@@ -172,15 +172,16 @@ static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void PrintString(const UInt16 *s)
|
||||
static SRes PrintString(const UInt16 *s)
|
||||
{
|
||||
CBuf buf;
|
||||
SRes res;
|
||||
Buf_Init(&buf);
|
||||
if (Utf16_To_Char(&buf, s, 0) == 0)
|
||||
{
|
||||
printf("%s", buf.data);
|
||||
res = Utf16_To_Char(&buf, s, 0);
|
||||
if (res == SZ_OK)
|
||||
fputs((const char *)buf.data, stdout);
|
||||
Buf_Free(&buf, &g_Alloc);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
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);
|
||||
PrintString(temp);
|
||||
res = PrintString(temp);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
if (f->IsDir)
|
||||
printf("/");
|
||||
printf("\n");
|
||||
continue;
|
||||
}
|
||||
printf(testCommand ?
|
||||
fputs(testCommand ?
|
||||
"Testing ":
|
||||
"Extracting ");
|
||||
PrintString(temp);
|
||||
"Extracting ",
|
||||
stdout);
|
||||
res = PrintString(temp);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
if (f->IsDir)
|
||||
printf("/");
|
||||
else
|
||||
|
||||
@@ -4,6 +4,7 @@ CFLAGS = $(CFLAGS) -D_7ZIP_PPMD_SUPPPORT
|
||||
PROG = 7zDec.exe
|
||||
|
||||
C_OBJS = \
|
||||
$O\7zAlloc.obj \
|
||||
$O\7zBuf.obj \
|
||||
$O\7zBuf2.obj \
|
||||
$O\7zCrc.obj \
|
||||
@@ -13,6 +14,7 @@ C_OBJS = \
|
||||
$O\7zIn.obj \
|
||||
$O\7zStream.obj \
|
||||
$O\Bcj2.obj \
|
||||
$O\Bra.obj \
|
||||
$O\Bra86.obj \
|
||||
$O\CpuArch.obj \
|
||||
$O\Lzma2Dec.obj \
|
||||
@@ -21,7 +23,6 @@ C_OBJS = \
|
||||
$O\Ppmd7Dec.obj \
|
||||
|
||||
7Z_OBJS = \
|
||||
$O\7zAlloc.obj \
|
||||
$O\7zMain.obj \
|
||||
|
||||
OBJS = \
|
||||
|
||||
@@ -4,7 +4,7 @@ LIB =
|
||||
RM = rm -f
|
||||
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)
|
||||
|
||||
@@ -15,7 +15,7 @@ $(PROG): $(OBJS)
|
||||
$(CXX) $(CFLAGS) 7zMain.c
|
||||
|
||||
7zAlloc.o: 7zAlloc.c
|
||||
$(CXX) $(CFLAGS) 7zAlloc.c
|
||||
$(CXX) $(CFLAGS) ../../7zAlloc.c
|
||||
|
||||
7zBuf.o: ../../7zBuf.c
|
||||
$(CXX) $(CFLAGS) ../../7zBuf.c
|
||||
@@ -44,6 +44,9 @@ LzmaDec.o: ../../LzmaDec.c
|
||||
Lzma2Dec.o: ../../Lzma2Dec.c
|
||||
$(CXX) $(CFLAGS) ../../Lzma2Dec.c
|
||||
|
||||
Bra.o: ../../Bra.c
|
||||
$(CXX) $(CFLAGS) ../../Bra.c
|
||||
|
||||
Bra86.o: ../../Bra86.c
|
||||
$(CXX) $(CFLAGS) ../../Bra86.c
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* 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
|
||||
|
||||
@@ -249,6 +249,6 @@ int MY_CDECL main(int numArgs, const char *args[])
|
||||
{
|
||||
char rs[800] = { 0 };
|
||||
int res = main2(numArgs, args, rs);
|
||||
printf(rs);
|
||||
fputs(rs, stdout);
|
||||
return res;
|
||||
}
|
||||
|
||||
592
C/Util/SfxSetup/SfxSetup.c
Executable file
592
C/Util/SfxSetup/SfxSetup.c
Executable 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
198
C/Util/SfxSetup/SfxSetup.dsp
Executable 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
29
C/Util/SfxSetup/SfxSetup.dsw
Executable 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
35
C/Util/SfxSetup/makefile
Executable 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
35
C/Util/SfxSetup/makefile_con
Executable 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
6
C/Util/SfxSetup/resource.rc
Executable 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
BIN
C/Util/SfxSetup/setup.ico
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
12
C/Xz.h
12
C/Xz.h
@@ -1,14 +1,12 @@
|
||||
/* Xz.h - Xz interface
|
||||
2009-04-15 : Igor Pavlov : Public domain */
|
||||
2010-09-17 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __XZ_H
|
||||
#define __XZ_H
|
||||
|
||||
#include "Sha256.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#define XZ_ID_Subblock 1
|
||||
#define XZ_ID_Delta 3
|
||||
@@ -140,7 +138,7 @@ typedef enum
|
||||
CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */
|
||||
CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
|
||||
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;
|
||||
|
||||
typedef enum
|
||||
@@ -249,8 +247,6 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
||||
|
||||
Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* XzCrc64.c -- CRC64 calculation
|
||||
2009-04-15 : Igor Pavlov : Public domain */
|
||||
2010-04-16 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "XzCrc64.h"
|
||||
|
||||
#define kCrc64Poly 0xC96C5795D7870F42
|
||||
#define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42)
|
||||
UInt64 g_Crc64Table[256];
|
||||
|
||||
void MY_FAST_CALL Crc64GenerateTable(void)
|
||||
|
||||
16
C/XzCrc64.h
16
C/XzCrc64.h
@@ -1,5 +1,5 @@
|
||||
/* XzCrc64.c -- CRC64 calculation
|
||||
2009-04-15 : Igor Pavlov : Public domain */
|
||||
/* XzCrc64.h -- CRC64 calculation
|
||||
2010-04-16 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __XZ_CRC64_H
|
||||
#define __XZ_CRC64_H
|
||||
@@ -8,23 +8,19 @@
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
extern UInt64 g_Crc64Table[];
|
||||
|
||||
void MY_FAST_CALL Crc64GenerateTable(void);
|
||||
|
||||
#define CRC64_INIT_VAL 0xFFFFFFFFFFFFFFFF
|
||||
#define CRC64_GET_DIGEST(crc) ((crc) ^ 0xFFFFFFFFFFFFFFFF)
|
||||
#define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF)
|
||||
#define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL)
|
||||
#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 Crc64Calc(const void *data, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* XzDec.c -- Xz Decode
|
||||
2009-06-08 : Igor Pavlov : Public domain */
|
||||
2010-04-16 : Igor Pavlov : Public domain */
|
||||
|
||||
/* #define XZ_DUMP */
|
||||
|
||||
@@ -858,6 +858,8 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case XZ_STATE_BLOCK: break; /* to disable GCC warning */
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
||||
@@ -193,11 +193,9 @@ HRESULT CEncoder::Encode(
|
||||
// UInt64 outStreamStartPos;
|
||||
// RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos));
|
||||
|
||||
CSequentialInStreamSizeCount2 *inStreamSizeCountSpec =
|
||||
new CSequentialInStreamSizeCount2;
|
||||
CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2;
|
||||
CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
|
||||
CSequentialOutStreamSizeCount *outStreamSizeCountSpec =
|
||||
new CSequentialOutStreamSizeCount;
|
||||
CSequentialOutStreamSizeCount *outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
|
||||
CMyComPtr<ISequentialOutStream> outStreamSizeCount = outStreamSizeCountSpec;
|
||||
|
||||
inStreamSizeCountSpec->Init(inStream);
|
||||
@@ -226,13 +224,11 @@ HRESULT CEncoder::Encode(
|
||||
_mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
|
||||
if (writeCoderProperties != NULL)
|
||||
{
|
||||
CSequentialOutStreamImp *outStreamSpec = new CSequentialOutStreamImp;
|
||||
CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
outStreamSpec->Init();
|
||||
writeCoderProperties->WriteCoderProperties(outStream);
|
||||
size_t size = outStreamSpec->GetSize();
|
||||
encodingInfo.Props.SetCapacity(size);
|
||||
memmove(encodingInfo.Props, outStreamSpec->GetBuffer(), size);
|
||||
outStreamSpec->CopyToBuffer(encodingInfo.Props);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,8 +246,7 @@ HRESULT CEncoder::Encode(
|
||||
RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1,
|
||||
&outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress));
|
||||
|
||||
ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods,
|
||||
folderItem);
|
||||
ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, folderItem);
|
||||
|
||||
packSizes.Add(outStreamSizeCountSpec->GetSize());
|
||||
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "7zHandler.h"
|
||||
#include "7zFolderOutStream.h"
|
||||
#include "../../../Common/ComTry.h"
|
||||
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
|
||||
#include "7zDecode.h"
|
||||
// #include "7z1Decode.h"
|
||||
|
||||
#include "../../../Common/ComTry.h"
|
||||
#include "../../Common/StreamObjects.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "7zFolderOutStream.h"
|
||||
#include "7zHandler.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
@@ -138,7 +137,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
}
|
||||
}
|
||||
|
||||
extractCallback->SetTotal(importantTotalUnpacked);
|
||||
RINOK(extractCallback->SetTotal(importantTotalUnpacked));
|
||||
|
||||
CDecoder decoder(
|
||||
#ifdef _ST_MODE
|
||||
@@ -149,27 +148,26 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
);
|
||||
// CDecoder1 decoder;
|
||||
|
||||
UInt64 currentTotalPacked = 0;
|
||||
UInt64 currentTotalUnpacked = 0;
|
||||
UInt64 totalFolderUnpacked;
|
||||
UInt64 totalFolderPacked;
|
||||
UInt64 totalPacked = 0;
|
||||
UInt64 totalUnpacked = 0;
|
||||
UInt64 curPacked, curUnpacked;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
for(int i = 0; i < extractFolderInfoVector.Size(); i++,
|
||||
currentTotalUnpacked += totalFolderUnpacked,
|
||||
currentTotalPacked += totalFolderPacked)
|
||||
for (int i = 0;; i++, totalUnpacked += curUnpacked, totalPacked += curPacked)
|
||||
{
|
||||
lps->OutSize = currentTotalUnpacked;
|
||||
lps->InSize = currentTotalPacked;
|
||||
lps->OutSize = totalUnpacked;
|
||||
lps->InSize = totalPacked;
|
||||
RINOK(lps->SetCur());
|
||||
|
||||
const CExtractFolderInfo &efi = extractFolderInfoVector[i];
|
||||
totalFolderUnpacked = efi.UnpackSize;
|
||||
if (i >= extractFolderInfoVector.Size())
|
||||
break;
|
||||
|
||||
totalFolderPacked = 0;
|
||||
const CExtractFolderInfo &efi = extractFolderInfoVector[i];
|
||||
curUnpacked = efi.UnpackSize;
|
||||
curPacked = 0;
|
||||
|
||||
CFolderOutStream *folderOutStream = new CFolderOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
|
||||
@@ -187,7 +185,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
else
|
||||
startIndex = db.FolderStartFileIndex[efi.FolderIndex];
|
||||
|
||||
|
||||
HRESULT result = folderOutStream->Init(&db,
|
||||
#ifdef _7Z_VOL
|
||||
volume.StartRef2Index,
|
||||
@@ -205,7 +202,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
CNum folderIndex = efi.FolderIndex;
|
||||
const CFolder &folderInfo = db.Folders[folderIndex];
|
||||
|
||||
totalFolderPacked = _db.GetFolderFullPackSize(folderIndex);
|
||||
curPacked = _db.GetFolderFullPackSize(folderIndex);
|
||||
|
||||
CNum packStreamIndex = db.FolderStartPackStreamIndex[folderIndex];
|
||||
UInt64 folderStartPackPos = db.GetFolderStreamPos(folderIndex, 0);
|
||||
|
||||
@@ -32,7 +32,6 @@ HRESULT CFolderInStream::OpenStream()
|
||||
_filePos = 0;
|
||||
while (_fileIndex < _numFiles)
|
||||
{
|
||||
_currentSizeIsDefined = false;
|
||||
CMyComPtr<ISequentialInStream> stream;
|
||||
HRESULT result = _updateCallback->GetStream(_fileIndices[_fileIndex], &stream);
|
||||
if (result != S_OK && result != S_FALSE)
|
||||
@@ -40,26 +39,22 @@ HRESULT CFolderInStream::OpenStream()
|
||||
_fileIndex++;
|
||||
_inStreamWithHashSpec->SetStream(stream);
|
||||
_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));
|
||||
Sizes.Add(0);
|
||||
Processed.Add(result == S_OK);
|
||||
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;
|
||||
}
|
||||
@@ -74,6 +69,7 @@ HRESULT CFolderInStream::CloseStream()
|
||||
RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
|
||||
_inStreamWithHashSpec->ReleaseStream();
|
||||
_fileIsOpen = false;
|
||||
_currentSizeIsDefined = false;
|
||||
Processed.Add(true);
|
||||
Sizes.Add(_filePos);
|
||||
AddDigest();
|
||||
@@ -82,43 +78,40 @@ HRESULT CFolderInStream::CloseStream()
|
||||
|
||||
STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
UInt32 realProcessedSize = 0;
|
||||
while ((_fileIndex < _numFiles || _fileIsOpen) && size > 0)
|
||||
if (processedSize != 0)
|
||||
*processedSize = 0;
|
||||
while (size > 0)
|
||||
{
|
||||
if (_fileIsOpen)
|
||||
{
|
||||
UInt32 localProcessedSize;
|
||||
RINOK(_inStreamWithHash->Read(
|
||||
((Byte *)data) + realProcessedSize, size, &localProcessedSize));
|
||||
if (localProcessedSize == 0)
|
||||
UInt32 processed2;
|
||||
RINOK(_inStreamWithHash->Read(data, size, &processed2));
|
||||
if (processed2 == 0)
|
||||
{
|
||||
RINOK(CloseStream());
|
||||
continue;
|
||||
}
|
||||
realProcessedSize += localProcessedSize;
|
||||
_filePos += localProcessedSize;
|
||||
size -= localProcessedSize;
|
||||
if (processedSize != 0)
|
||||
*processedSize = processed2;
|
||||
_filePos += processed2;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_fileIndex >= _numFiles)
|
||||
break;
|
||||
RINOK(OpenStream());
|
||||
}
|
||||
}
|
||||
if (processedSize != 0)
|
||||
*processedSize = realProcessedSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
|
||||
{
|
||||
*value = 0;
|
||||
int subStreamIndex = (int)subStream;
|
||||
if (subStreamIndex < 0 || subStream > Sizes.Size())
|
||||
int index2 = (int)subStream;
|
||||
if (index2 < 0 || subStream > Sizes.Size())
|
||||
return E_FAIL;
|
||||
if (subStreamIndex < Sizes.Size())
|
||||
if (index2 < Sizes.Size())
|
||||
{
|
||||
*value= Sizes[subStreamIndex];
|
||||
*value = Sizes[index2];
|
||||
return S_OK;
|
||||
}
|
||||
if (!_currentSizeIsDefined)
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
// 7z/FolderInStream.h
|
||||
// 7zFolderInStream.h
|
||||
|
||||
#ifndef __7Z_FOLDERINSTREAM_H
|
||||
#define __7Z_FOLDERINSTREAM_H
|
||||
|
||||
#include "7zItem.h"
|
||||
#include "7zHeader.h"
|
||||
#ifndef __7Z_FOLDER_IN_STREAM_H
|
||||
#define __7Z_FOLDER_IN_STREAM_H
|
||||
|
||||
#include "../../ICoder.h"
|
||||
#include "../IArchive.h"
|
||||
#include "../Common/InStreamWithCRC.h"
|
||||
#include "../../IStream.h"
|
||||
#include "../../ICoder.h"
|
||||
|
||||
#include "7zItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
@@ -19,26 +17,14 @@ class CFolderInStream:
|
||||
public ICompressGetSubStreamSize,
|
||||
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;
|
||||
CMyComPtr<ISequentialInStream> _inStreamWithHash;
|
||||
CMyComPtr<IArchiveUpdateCallback> _updateCallback;
|
||||
|
||||
bool _currentSizeIsDefined;
|
||||
UInt64 _currentSize;
|
||||
|
||||
bool _fileIsOpen;
|
||||
UInt64 _currentSize;
|
||||
UInt64 _filePos;
|
||||
|
||||
const UInt32 *_fileIndices;
|
||||
UInt32 _numFiles;
|
||||
UInt32 _fileIndex;
|
||||
@@ -46,12 +32,18 @@ private:
|
||||
HRESULT OpenStream();
|
||||
HRESULT CloseStream();
|
||||
void AddDigest();
|
||||
|
||||
public:
|
||||
void Init(IArchiveUpdateCallback *updateCallback,
|
||||
const UInt32 *fileIndices, UInt32 numFiles);
|
||||
CRecordVector<bool> Processed;
|
||||
CRecordVector<UInt32> CRCs;
|
||||
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 size = 0;
|
||||
|
||||
@@ -14,13 +14,13 @@ CFolderOutStream::CFolderOutStream()
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::Init(
|
||||
const CArchiveDatabaseEx *archiveDatabase,
|
||||
const CArchiveDatabaseEx *db,
|
||||
UInt32 ref2Offset, UInt32 startIndex,
|
||||
const CBoolVector *extractStatuses,
|
||||
IArchiveExtractCallback *extractCallback,
|
||||
bool testMode, bool checkCrc)
|
||||
{
|
||||
_db = archiveDatabase;
|
||||
_db = db;
|
||||
_ref2Offset = ref2Offset;
|
||||
_startIndex = startIndex;
|
||||
|
||||
@@ -121,6 +121,15 @@ STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *proc
|
||||
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)
|
||||
{
|
||||
while (_currentIndex < _extractStatuses->Size())
|
||||
|
||||
@@ -3,17 +3,18 @@
|
||||
#ifndef __7Z_FOLDER_OUT_STREAM_H
|
||||
#define __7Z_FOLDER_OUT_STREAM_H
|
||||
|
||||
#include "7zIn.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
#include "../IArchive.h"
|
||||
#include "../Common/OutStreamWithCRC.h"
|
||||
|
||||
#include "7zIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
class CFolderOutStream:
|
||||
public ISequentialOutStream,
|
||||
public ICompressGetSubStreamSize,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
COutStreamWithCRC *_crcStreamSpec;
|
||||
@@ -34,14 +35,15 @@ class CFolderOutStream:
|
||||
HRESULT CloseFileAndSetResult();
|
||||
HRESULT ProcessEmptyFiles();
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
|
||||
|
||||
CFolderOutStream();
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
|
||||
|
||||
HRESULT Init(
|
||||
const CArchiveDatabaseEx *archiveDatabase,
|
||||
const CArchiveDatabaseEx *db,
|
||||
UInt32 ref2Offset, UInt32 startIndex,
|
||||
const CBoolVector *extractStatuses,
|
||||
IArchiveExtractCallback *extractCallback,
|
||||
|
||||
@@ -120,7 +120,7 @@ public:
|
||||
kUnsupportedVersion = 0,
|
||||
kUnsupported,
|
||||
kIncorrect,
|
||||
kEndOfData,
|
||||
kEndOfData
|
||||
} Cause;
|
||||
CInArchiveException(CCauseType cause): Cause(cause) {};
|
||||
};
|
||||
@@ -280,28 +280,46 @@ void CInByte2::ReadString(UString &s)
|
||||
_pos += rem + 2;
|
||||
}
|
||||
|
||||
static inline bool TestSignatureCandidate(const Byte *p)
|
||||
static inline bool TestSignature(const Byte *p)
|
||||
{
|
||||
for (int i = 0; i < kSignatureSize; i++)
|
||||
if (p[i] != kSignature[i])
|
||||
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)
|
||||
{
|
||||
RINOK(ReadStream_FALSE(stream, _header, kHeaderSize));
|
||||
|
||||
if (TestSignatureCandidate(_header))
|
||||
if (TestSignature2(_header))
|
||||
return S_OK;
|
||||
|
||||
CByteBuffer byteBuffer;
|
||||
const UInt32 kBufferSize = (1 << 16);
|
||||
byteBuffer.SetCapacity(kBufferSize);
|
||||
Byte *buffer = byteBuffer;
|
||||
UInt32 numPrevBytes = kHeaderSize - 1;
|
||||
memcpy(buffer, _header + 1, numPrevBytes);
|
||||
UInt64 curTestPos = _arhiveBeginStreamPosition + 1;
|
||||
UInt32 numPrevBytes = kHeaderSize;
|
||||
memcpy(buffer, _header, kHeaderSize);
|
||||
UInt64 curTestPos = _arhiveBeginStreamPosition;
|
||||
for (;;)
|
||||
{
|
||||
if (searchHeaderSizeLimit != NULL)
|
||||
@@ -316,14 +334,14 @@ HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *search
|
||||
if (processedSize == 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
while (numPrevBytes < kHeaderSize);
|
||||
UInt32 numTests = numPrevBytes - kHeaderSize + 1;
|
||||
while (numPrevBytes <= kHeaderSize);
|
||||
UInt32 numTests = numPrevBytes - kHeaderSize;
|
||||
for (UInt32 pos = 0; pos < numTests; pos++)
|
||||
{
|
||||
for (; buffer[pos] != '7' && pos < numTests; pos++);
|
||||
if (pos == numTests)
|
||||
break;
|
||||
if (TestSignatureCandidate(buffer + pos))
|
||||
if (TestSignature(buffer + pos))
|
||||
{
|
||||
memcpy(_header, buffer + pos, kHeaderSize);
|
||||
curTestPos += pos;
|
||||
@@ -812,7 +830,7 @@ HRESULT CInArchive::ReadAndDecodePackedStreams(
|
||||
ThrowUnsupported();
|
||||
data.SetCapacity(unpackSize);
|
||||
|
||||
CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2;
|
||||
CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
|
||||
outStreamSpec->Init(data, unpackSize);
|
||||
|
||||
@@ -1164,16 +1182,14 @@ HRESULT CInArchive::ReadDatabase2(
|
||||
nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
|
||||
RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
#ifdef FORMAT_7Z_RECOVERY
|
||||
crcFromArchive = crc;
|
||||
#endif
|
||||
|
||||
db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
|
||||
|
||||
{
|
||||
if (crc != crcFromArchive)
|
||||
ThrowIncorrect();
|
||||
}
|
||||
|
||||
db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
|
||||
|
||||
if (nextHeaderSize == 0)
|
||||
return S_OK;
|
||||
@@ -1181,6 +1197,9 @@ HRESULT CInArchive::ReadDatabase2(
|
||||
if (nextHeaderSize > (UInt64)0xFFFFFFFF)
|
||||
return S_FALSE;
|
||||
|
||||
if ((Int64)nextHeaderOffset < 0)
|
||||
return S_FALSE;
|
||||
|
||||
RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));
|
||||
|
||||
CByteBuffer buffer2;
|
||||
|
||||
@@ -19,32 +19,33 @@ struct CPropMap
|
||||
|
||||
CPropMap kPropMap[] =
|
||||
{
|
||||
{ NID::kName, NULL, kpidPath, VT_BSTR},
|
||||
{ NID::kSize, NULL, kpidSize, VT_UI8},
|
||||
{ NID::kPackInfo, NULL, kpidPackSize, VT_UI8},
|
||||
{ NID::kName, { NULL, kpidPath, VT_BSTR } },
|
||||
{ NID::kSize, { NULL, kpidSize, VT_UI8 } },
|
||||
{ NID::kPackInfo, { NULL, kpidPackSize, VT_UI8 } },
|
||||
|
||||
#ifdef _MULTI_PACK
|
||||
{ 100, L"Pack0", kpidPackedSize0, VT_UI8},
|
||||
{ 101, L"Pack1", kpidPackedSize1, VT_UI8},
|
||||
{ 102, L"Pack2", kpidPackedSize2, VT_UI8},
|
||||
{ 103, L"Pack3", kpidPackedSize3, VT_UI8},
|
||||
{ 104, L"Pack4", kpidPackedSize4, VT_UI8},
|
||||
{ 100, { L"Pack0", kpidPackedSize0, VT_UI8 } },
|
||||
{ 101, { L"Pack1", kpidPackedSize1, VT_UI8 } },
|
||||
{ 102, { L"Pack2", kpidPackedSize2, VT_UI8 } },
|
||||
{ 103, { L"Pack3", kpidPackedSize3, VT_UI8 } },
|
||||
{ 104, { L"Pack4", kpidPackedSize4, VT_UI8 } },
|
||||
#endif
|
||||
|
||||
{ NID::kCTime, NULL, kpidCTime, VT_FILETIME},
|
||||
{ NID::kMTime, NULL, kpidMTime, VT_FILETIME},
|
||||
{ NID::kATime, NULL, kpidATime, VT_FILETIME},
|
||||
{ NID::kWinAttributes, NULL, kpidAttrib, VT_UI4},
|
||||
{ NID::kStartPos, NULL, kpidPosition, VT_UI4},
|
||||
{ NID::kCTime, { NULL, kpidCTime, VT_FILETIME } },
|
||||
{ NID::kMTime, { NULL, kpidMTime, VT_FILETIME } },
|
||||
{ NID::kATime, { NULL, kpidATime, VT_FILETIME } },
|
||||
{ NID::kWinAttributes, { NULL, kpidAttrib, 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
|
||||
{ 97, NULL, kpidEncrypted, VT_BOOL},
|
||||
{ 98, NULL, kpidMethod, VT_BSTR},
|
||||
{ 99, NULL, kpidBlock, VT_UI4}
|
||||
,
|
||||
{ 97, { NULL,kpidEncrypted, VT_BOOL } },
|
||||
{ 98, { NULL,kpidMethod, VT_BSTR } },
|
||||
{ 99, { NULL,kpidBlock, VT_UI4 } }
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject)
|
||||
|
||||
STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
if (formatIndex >= g_NumArcs)
|
||||
return E_INVALIDARG;
|
||||
const CArcInfo &arc = *g_Arcs[formatIndex];
|
||||
@@ -119,6 +120,7 @@ STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value)
|
||||
|
||||
@@ -264,7 +264,7 @@ struct CInArchiveException
|
||||
{
|
||||
kUnexpectedEndOfArchive = 0,
|
||||
kCRCError,
|
||||
kIncorrectArchive,
|
||||
kIncorrectArchive
|
||||
}
|
||||
Cause;
|
||||
CInArchiveException(CCauseType cause): Cause(cause) {};
|
||||
|
||||
@@ -41,7 +41,7 @@ enum
|
||||
};
|
||||
#endif
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
static STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
@@ -57,18 +57,18 @@ STATPROPSTG kProps[] =
|
||||
#endif
|
||||
};
|
||||
|
||||
static const wchar_t *kMethods[] =
|
||||
static const char *kMethods[] =
|
||||
{
|
||||
L"None",
|
||||
L"MSZip",
|
||||
L"Quantum",
|
||||
L"LZX"
|
||||
"None",
|
||||
"MSZip",
|
||||
"Quantum",
|
||||
"LZX"
|
||||
};
|
||||
|
||||
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, kpidSolid, VT_BOOL},
|
||||
@@ -87,7 +87,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
case kpidMethod:
|
||||
{
|
||||
UString resString;
|
||||
AString resString;
|
||||
CRecordVector<Byte> ids;
|
||||
int i;
|
||||
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++)
|
||||
{
|
||||
Byte id = ids[i];
|
||||
UString method = (id < kNumMethods) ? kMethods[id] : kUnknownMethod;
|
||||
AString method = (id < kNumMethods) ? kMethods[id] : kUnknownMethod;
|
||||
if (!resString.IsEmpty())
|
||||
resString += L' ';
|
||||
resString += ' ';
|
||||
resString += method;
|
||||
}
|
||||
prop = resString;
|
||||
@@ -171,12 +171,12 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
|
||||
UInt32 realFolderIndex = item.GetFolderIndex(db.Folders.Size());
|
||||
const CFolder &folder = db.Folders[realFolderIndex];
|
||||
int methodIndex = folder.GetCompressionMethod();
|
||||
UString method = (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod;
|
||||
AString method = (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod;
|
||||
if (methodIndex == NHeader::NCompressionMethodMajor::kLZX ||
|
||||
methodIndex == NHeader::NCompressionMethodMajor::kQuantum)
|
||||
{
|
||||
method += L":";
|
||||
wchar_t temp[32];
|
||||
method += ':';
|
||||
char temp[32];
|
||||
ConvertUInt64ToString(folder.CompressionTypeMinor, temp);
|
||||
method += temp;
|
||||
}
|
||||
|
||||
@@ -15,12 +15,9 @@ namespace NChm{
|
||||
// define CHM_LOW, if you want to see low level items
|
||||
// #define CHM_LOW
|
||||
|
||||
static const GUID kChmLzxGuid =
|
||||
{ 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 kDesGuid =
|
||||
{ 0x67F6E4A2, 0x60BF, 0x11D3, 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF };
|
||||
static const GUID kChmLzxGuid = { 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 kDesGuid = { 0x67F6E4A2, 0x60BF, 0x11D3, { 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF } };
|
||||
|
||||
static bool AreGuidsEqual(REFGUID g1, REFGUID g2)
|
||||
{
|
||||
|
||||
@@ -87,7 +87,7 @@ CCoderInfo2::CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams):
|
||||
{
|
||||
InSizes.Reserve(NumInStreams);
|
||||
InSizePointers.Reserve(NumInStreams);
|
||||
OutSizePointers.Reserve(NumOutStreams);
|
||||
OutSizes.Reserve(NumOutStreams);
|
||||
OutSizePointers.Reserve(NumOutStreams);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,8 +21,10 @@ STDMETHODIMP CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSi
|
||||
{
|
||||
UInt32 realProcessedSize;
|
||||
HRESULT result = _stream->Read(data, size, &realProcessedSize);
|
||||
/*
|
||||
if (size > 0 && realProcessedSize == 0)
|
||||
_wasFinished = true;
|
||||
*/
|
||||
_size += realProcessedSize;
|
||||
_crc = CrcUpdate(_crc, data, realProcessedSize);
|
||||
if(processedSize != NULL)
|
||||
|
||||
@@ -49,19 +49,19 @@ private:
|
||||
CMyComPtr<IInStream> _stream;
|
||||
UInt64 _size;
|
||||
UInt32 _crc;
|
||||
bool _wasFinished;
|
||||
// bool _wasFinished;
|
||||
public:
|
||||
void SetStream(IInStream *stream) { _stream = stream; }
|
||||
void Init()
|
||||
{
|
||||
_size = 0;
|
||||
_wasFinished = false;
|
||||
// _wasFinished = false;
|
||||
_crc = CRC_INIT_VAL;
|
||||
}
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
|
||||
UInt64 GetSize() const { return _size; }
|
||||
bool WasFinished() const { return _wasFinished; }
|
||||
// bool WasFinished() const { return _wasFinished; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../../C/Types.h"
|
||||
|
||||
#include "ItemNameUtils.h"
|
||||
|
||||
namespace NArchive {
|
||||
|
||||
@@ -6,73 +6,62 @@
|
||||
|
||||
STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if(processedSize != NULL)
|
||||
if (processedSize)
|
||||
*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];
|
||||
if (_pos == s.Size)
|
||||
int left = 0, mid = _streamIndex, right = Streams.Size();
|
||||
for (;;)
|
||||
{
|
||||
_streamIndex++;
|
||||
_pos = 0;
|
||||
continue;
|
||||
}
|
||||
RINOK(s.Stream->Seek(s.Pos + _pos, STREAM_SEEK_SET, 0));
|
||||
UInt32 sizeToRead = UInt32(MyMin((UInt64)size, s.Size - _pos));
|
||||
UInt32 realProcessed;
|
||||
HRESULT result = s.Stream->Read(data, sizeToRead, &realProcessed);
|
||||
data = (void *)((Byte *)data + realProcessed);
|
||||
size -= realProcessed;
|
||||
if(processedSize != NULL)
|
||||
*processedSize += realProcessed;
|
||||
_pos += realProcessed;
|
||||
_seekPos += realProcessed;
|
||||
RINOK(result);
|
||||
CSubStreamInfo &m = Streams[mid];
|
||||
if (_pos < m.GlobalOffset)
|
||||
right = mid;
|
||||
else if (_pos >= m.GlobalOffset + m.Size)
|
||||
left = mid + 1;
|
||||
else
|
||||
{
|
||||
_streamIndex = mid;
|
||||
break;
|
||||
}
|
||||
return S_OK;
|
||||
mid = (left + right) / 2;
|
||||
}
|
||||
_streamIndex = mid;
|
||||
}
|
||||
|
||||
STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin,
|
||||
UInt64 *newPosition)
|
||||
CSubStreamInfo &s = Streams[_streamIndex];
|
||||
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)
|
||||
{
|
||||
case STREAM_SEEK_SET:
|
||||
newPos = offset;
|
||||
break;
|
||||
case STREAM_SEEK_CUR:
|
||||
newPos = _seekPos + offset;
|
||||
break;
|
||||
case STREAM_SEEK_END:
|
||||
newPos = _totalLength + offset;
|
||||
break;
|
||||
default:
|
||||
return STG_E_INVALIDFUNCTION;
|
||||
case STREAM_SEEK_SET: _pos = offset; break;
|
||||
case STREAM_SEEK_CUR: _pos = _pos + offset; break;
|
||||
case STREAM_SEEK_END: _pos = _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)
|
||||
*newPosition = newPos;
|
||||
*newPosition = _pos;
|
||||
return S_OK;
|
||||
}
|
||||
_seekPos += size;
|
||||
}
|
||||
if (newPos == _seekPos)
|
||||
{
|
||||
if (newPosition != 0)
|
||||
*newPosition = newPos;
|
||||
return S_OK;
|
||||
}
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,36 +1,44 @@
|
||||
// MultiStream.h
|
||||
|
||||
#ifndef __MULTISTREAM_H
|
||||
#define __MULTISTREAM_H
|
||||
#ifndef __MULTI_STREAM_H
|
||||
#define __MULTI_STREAM_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
#include "../../../Common/MyVector.h"
|
||||
#include "../../Archive/IArchive.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
class CMultiStream:
|
||||
public IInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
int _streamIndex;
|
||||
UInt64 _pos;
|
||||
UInt64 _seekPos;
|
||||
UInt64 _totalLength;
|
||||
int _streamIndex;
|
||||
public:
|
||||
struct CSubStreamInfo
|
||||
{
|
||||
CMyComPtr<IInStream> Stream;
|
||||
UInt64 Pos;
|
||||
UInt64 Size;
|
||||
UInt64 GlobalOffset;
|
||||
UInt64 LocalPos;
|
||||
};
|
||||
CObjectVector<CSubStreamInfo> Streams;
|
||||
void Init()
|
||||
|
||||
HRESULT Init()
|
||||
{
|
||||
_streamIndex = 0;
|
||||
_pos = 0;
|
||||
_seekPos = 0;
|
||||
_totalLength = 0;
|
||||
UInt64 total = 0;
|
||||
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)
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/StringToInt.h"
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/StringToInt.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Windows/Time.h"
|
||||
@@ -25,10 +25,10 @@ namespace NFileHeader
|
||||
{
|
||||
namespace NMagic
|
||||
{
|
||||
extern const char *kMagic1 = "070701";
|
||||
extern const char *kMagic2 = "070702";
|
||||
extern const char *kMagic3 = "070707";
|
||||
extern const char *kEndName = "TRAILER!!!";
|
||||
const char *kMagic1 = "070701";
|
||||
const char *kMagic2 = "070702";
|
||||
const char *kMagic3 = "070707";
|
||||
const char *kEndName = "TRAILER!!!";
|
||||
|
||||
const Byte kMagicForRecord2[2] = { 0xC7, 0x71 };
|
||||
}
|
||||
|
||||
644
CPP/7zip/Archive/CramfsHandler.cpp
Executable file
644
CPP/7zip/Archive/CramfsHandler.cpp
Executable 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)
|
||||
|
||||
}}
|
||||
@@ -3,8 +3,6 @@
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/Defs.h"
|
||||
#include "Common/NewHandler.h"
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/StringToInt.h"
|
||||
|
||||
|
||||
@@ -277,9 +277,9 @@ static const CUInt32PCharPair g_AbiOS[] =
|
||||
|
||||
static const CUInt32PCharPair g_SegmentFlags[] =
|
||||
{
|
||||
{ 1 << 0, "Execute" },
|
||||
{ 1 << 1, "Write" },
|
||||
{ 1 << 2, "Read" }
|
||||
{ 0, "Execute" },
|
||||
{ 1, "Write" },
|
||||
{ 2, "Read" }
|
||||
};
|
||||
|
||||
static const char *g_Types[] =
|
||||
|
||||
@@ -526,7 +526,14 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level)
|
||||
item.Attrib = attrib;
|
||||
item.Flags = p[12];
|
||||
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.CTime2 = p[13];
|
||||
item.ADate = Get16(p + 18);
|
||||
@@ -578,8 +585,12 @@ HRESULT CDatabase::Open()
|
||||
return S_FALSE;
|
||||
UInt64 fileSize;
|
||||
RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize));
|
||||
|
||||
/* we comment that check to support truncated images */
|
||||
/*
|
||||
if (fileSize < Header.GetPhySize())
|
||||
return S_FALSE;
|
||||
*/
|
||||
|
||||
if (Header.IsFat32())
|
||||
{
|
||||
|
||||
BIN
CPP/7zip/Archive/Icons/squashfs.ico
Executable file
BIN
CPP/7zip/Archive/Icons/squashfs.ico
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
@@ -3,9 +3,7 @@
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/Defs.h"
|
||||
#include "Common/IntToString.h"
|
||||
#include "Common/NewHandler.h"
|
||||
#include "Common/StringConvert.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
@@ -26,7 +24,7 @@ using namespace NTime;
|
||||
namespace NArchive {
|
||||
namespace NIso {
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
static const STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsDir, VT_BOOL},
|
||||
@@ -35,8 +33,17 @@ STATPROPSTG kProps[] =
|
||||
{ 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_ArcProps_NO
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
const UInt64 * /* maxCheckStartPosition */,
|
||||
@@ -68,6 +75,58 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
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)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
@@ -89,9 +148,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
prop = (const wchar_t *)s;
|
||||
break;
|
||||
}
|
||||
case kpidIsDir:
|
||||
prop = false;
|
||||
break;
|
||||
case kpidIsDir: prop = false; break;
|
||||
case kpidSize:
|
||||
case kpidPackSize:
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case kpidIsDir:
|
||||
prop = item.IsDir();
|
||||
break;
|
||||
case kpidIsDir: prop = item.IsDir(); break;
|
||||
case kpidSize:
|
||||
case kpidPackSize:
|
||||
if (!item.IsDir())
|
||||
@@ -133,16 +188,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
break;
|
||||
case kpidMTime:
|
||||
{
|
||||
FILETIME utcFileTime;
|
||||
if (item.DateTime.GetFileTime(utcFileTime))
|
||||
prop = utcFileTime;
|
||||
/*
|
||||
else
|
||||
{
|
||||
utcFileTime.dwLowDateTime = 0;
|
||||
utcFileTime.dwHighDateTime = 0;
|
||||
}
|
||||
*/
|
||||
FILETIME utc;
|
||||
if (item.DateTime.GetFileTime(utc))
|
||||
prop = utc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ UInt16 CInArchive::ReadUInt16()
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (b[i] != b[3 - i])
|
||||
throw 1;
|
||||
IncorrectBigEndian = true;
|
||||
value |= ((UInt16)(b[i]) << (8 * i));
|
||||
}
|
||||
return (UInt16)value;
|
||||
@@ -440,6 +440,7 @@ HRESULT CInArchive::Open(IInStream *inStream)
|
||||
|
||||
void CInArchive::Clear()
|
||||
{
|
||||
IncorrectBigEndian = false;
|
||||
Refs.Clear();
|
||||
_rootDir.Clear();
|
||||
VolDescs.Clear();
|
||||
|
||||
@@ -111,6 +111,20 @@ struct CDateTime
|
||||
signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded.
|
||||
bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 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
|
||||
@@ -268,6 +282,7 @@ public:
|
||||
int MainVolDescIndex;
|
||||
UInt32 BlockSize;
|
||||
CObjectVector<CBootInitialEntry> BootEntries;
|
||||
bool IncorrectBigEndian;
|
||||
|
||||
|
||||
bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); }
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
static IInArchive *CreateArc() { return new NArchive::NIso::CHandler; }
|
||||
|
||||
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)
|
||||
|
||||
@@ -266,7 +266,7 @@ HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
|
||||
return (startHeader[0] == 0) ? S_OK: S_FALSE;
|
||||
|
||||
const Byte *p = header;
|
||||
memmove(item.Method, p, kMethodIdSize);
|
||||
memcpy(item.Method, p, kMethodIdSize);
|
||||
if (!item.IsValidMethod())
|
||||
return S_OK;
|
||||
p += kMethodIdSize;
|
||||
@@ -378,7 +378,7 @@ static const char *GetOS(Byte osId)
|
||||
if (g_OsPairs[i].Id == osId)
|
||||
return g_OsPairs[i].Name;
|
||||
return kUnknownOS;
|
||||
};
|
||||
}
|
||||
|
||||
static STATPROPSTG kProps[] =
|
||||
{
|
||||
@@ -400,7 +400,7 @@ public:
|
||||
static UInt16 Table[256];
|
||||
static void InitTable();
|
||||
|
||||
CCRC(): _value(0){};
|
||||
CCRC(): _value(0) {}
|
||||
void Init() { _value = 0; }
|
||||
void Update(const void *data, size_t size);
|
||||
UInt16 GetDigest() const { return _value; }
|
||||
@@ -460,7 +460,6 @@ public:
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
UInt32 GetCRC() const { return _crc.GetDigest(); }
|
||||
void InitCRC() { _crc.Init(); }
|
||||
|
||||
};
|
||||
|
||||
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;
|
||||
totalPacked += item.PackSize;
|
||||
}
|
||||
extractCallback->SetTotal(totalUnPacked);
|
||||
RINOK(extractCallback->SetTotal(totalUnPacked));
|
||||
|
||||
UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;
|
||||
UInt64 currentItemUnPacked, currentItemPacked;
|
||||
|
||||
@@ -77,16 +77,16 @@ static const char *g_FileTypes[] =
|
||||
|
||||
static const CUInt32PCharPair g_Flags[] =
|
||||
{
|
||||
{ (UInt32)1 << 31, "PURE_INSTRUCTIONS" },
|
||||
{ 1 << 30, "NO_TOC" },
|
||||
{ 1 << 29, "STRIP_STATIC_SYMS" },
|
||||
{ 1 << 28, "NO_DEAD_STRIP" },
|
||||
{ 1 << 27, "LIVE_SUPPORT" },
|
||||
{ 1 << 26, "SELF_MODIFYING_CODE" },
|
||||
{ 1 << 25, "DEBUG" },
|
||||
{ 1 << 10, "SOME_INSTRUCTIONS" },
|
||||
{ 1 << 9, "EXT_RELOC" },
|
||||
{ 1 << 8, "LOC_RELOC" }
|
||||
{ 31, "PURE_INSTRUCTIONS" },
|
||||
{ 30, "NO_TOC" },
|
||||
{ 29, "STRIP_STATIC_SYMS" },
|
||||
{ 28, "NO_DEAD_STRIP" },
|
||||
{ 27, "LIVE_SUPPORT" },
|
||||
{ 26, "SELF_MODIFYING_CODE" },
|
||||
{ 25, "DEBUG" },
|
||||
{ 10, "SOME_INSTRUCTIONS" },
|
||||
{ 9, "EXT_RELOC" },
|
||||
{ 8, "LOC_RELOC" }
|
||||
};
|
||||
|
||||
static const CUInt32PCharPair g_MachinePairs[] =
|
||||
|
||||
@@ -332,7 +332,7 @@ enum
|
||||
{
|
||||
kpidPrimary = kpidUserDefined,
|
||||
kpidBegChs,
|
||||
kpidEndChs,
|
||||
kpidEndChs
|
||||
};
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
|
||||
@@ -7,15 +7,14 @@
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "../../Common/MethodId.h"
|
||||
#include "../../Common/CreateCoder.h"
|
||||
|
||||
#include "../../Compress/BZip2Decoder.h"
|
||||
#include "../../Compress/DeflateDecoder.h"
|
||||
#include "../../Compress/LzmaDecoder.h"
|
||||
|
||||
namespace NArchive {
|
||||
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;
|
||||
|
||||
HRESULT CDecoder::Init(
|
||||
@@ -31,24 +30,14 @@ HRESULT CDecoder::Init(
|
||||
_method = method;
|
||||
if (!_codecInStream)
|
||||
{
|
||||
CMethodId methodID;
|
||||
switch (method)
|
||||
{
|
||||
case NMethodType::kCopy: methodID = k_Copy; break;
|
||||
case NMethodType::kDeflate: methodID = k_Deflate; break;
|
||||
case NMethodType::kBZip2: methodID = k_BZip2; break;
|
||||
case NMethodType::kLZMA: methodID = k_LZMA; break;
|
||||
// case NMethodType::kCopy: return E_NOTIMPL;
|
||||
case NMethodType::kDeflate: _codecInStream = new NCompress::NDeflate::NDecoder::CNsisCOMCoder(); break;
|
||||
case NMethodType::kBZip2: _codecInStream = new NCompress::NBZip2::CNsisDecoder(); break;
|
||||
case NMethodType::kLZMA: _codecInStream = new NCompress::NLzma::CDecoder(); break;
|
||||
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)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/IntToString.h"
|
||||
#include "Common/NewHandler.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
|
||||
@@ -314,6 +313,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
byteBuf.SetCapacity(kBufferLength);
|
||||
Byte *buffer = byteBuf;
|
||||
|
||||
CByteBuffer tempBuf;
|
||||
|
||||
bool dataError = false;
|
||||
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
|
||||
{
|
||||
@@ -358,6 +359,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
bool sizeIsKnown = false;
|
||||
UInt32 fullSize = 0;
|
||||
|
||||
bool writeToTemp = false;
|
||||
bool readFromTemp = false;
|
||||
|
||||
if (_archive.IsSolid)
|
||||
{
|
||||
UInt64 pos = _archive.GetPosOfSolidItem(index);
|
||||
@@ -390,8 +394,21 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
fullSize = Get32(buffer2);
|
||||
sizeIsKnown = 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
|
||||
{
|
||||
RINOK(_inStream->Seek(_archive.GetPosOfNonSolidItem(index) + 4, STREAM_SEEK_SET, NULL));
|
||||
@@ -435,6 +452,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
break;
|
||||
}
|
||||
|
||||
if (writeToTemp)
|
||||
memcpy((Byte *)tempBuf + (size_t)offset, buffer, processedSize);
|
||||
|
||||
fullSize -= (UInt32)processedSize;
|
||||
streamPos += processedSize;
|
||||
offset += processedSize;
|
||||
@@ -451,6 +471,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (readFromTemp)
|
||||
{
|
||||
if (!testMode)
|
||||
RINOK(WriteStream(realOutStream, tempBuf, tempBuf.GetCapacity()));
|
||||
}
|
||||
else
|
||||
while (fullSize > 0)
|
||||
{
|
||||
UInt32 curSize = MyMin(fullSize, kBufferLength);
|
||||
|
||||
@@ -1151,16 +1151,25 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
|
||||
bool sameName = IsUnicode ?
|
||||
(Items[i].NameU == Items[i + 1].NameU) :
|
||||
(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);
|
||||
else
|
||||
i++;
|
||||
}
|
||||
for (i = 0; i + 1 < Items.Size(); i++)
|
||||
for (i = 0; i < Items.Size(); 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.EstimatedSize = Items[i + 1].Pos - item.Pos - 4;
|
||||
item.EstimatedSize = nextPos - curPos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!IsSolid)
|
||||
{
|
||||
@@ -1275,6 +1284,11 @@ static bool IsLZMA(const Byte *p, UInt32 &dictionary, bool &thereIsFlag)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsBZip2(const Byte *p)
|
||||
{
|
||||
return (p[0] == 0x31 && p[1] < 14);
|
||||
}
|
||||
|
||||
HRESULT CInArchive::Open2(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS2
|
||||
)
|
||||
@@ -1312,8 +1326,15 @@ HRESULT CInArchive::Open2(
|
||||
else if (sig[3] == 0x80)
|
||||
{
|
||||
IsSolid = false;
|
||||
if (IsBZip2(sig + 4))
|
||||
Method = NMethodType::kBZip2;
|
||||
else
|
||||
Method = NMethodType::kDeflate;
|
||||
}
|
||||
else if (IsBZip2(sig))
|
||||
{
|
||||
Method = NMethodType::kBZip2;
|
||||
}
|
||||
else
|
||||
{
|
||||
Method = NMethodType::kDeflate;
|
||||
|
||||
@@ -156,7 +156,7 @@ struct CMftRef
|
||||
#define ATNAME(n) ATTR_TYPE_ ## n
|
||||
#define DEF_ATTR_TYPE(v, n) ATNAME(n) = v
|
||||
|
||||
typedef enum
|
||||
enum
|
||||
{
|
||||
DEF_ATTR_TYPE(0x00, UNUSED),
|
||||
DEF_ATTR_TYPE(0x10, STANDARD_INFO),
|
||||
@@ -873,7 +873,7 @@ STDMETHODIMP CByteBufStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPo
|
||||
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)
|
||||
{
|
||||
CExtent e;
|
||||
@@ -969,6 +969,7 @@ struct CMftRec
|
||||
void ParseDataNames();
|
||||
HRESULT GetStream(IInStream *mainStream, int dataIndex,
|
||||
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(); }
|
||||
|
||||
@@ -1036,6 +1037,35 @@ HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex,
|
||||
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,
|
||||
CObjectVector<CAttr> *attrs)
|
||||
{
|
||||
@@ -1283,10 +1313,12 @@ HRESULT CDatabase::Open()
|
||||
{
|
||||
if (OpenCallback)
|
||||
{
|
||||
// Sleep(0);
|
||||
UInt64 numFiles = Recs.Size();
|
||||
if ((numFiles & 0x3FF) == 0)
|
||||
{
|
||||
RINOK(OpenCallback->SetCompleted(&numFiles, &pos64));
|
||||
}
|
||||
}
|
||||
UInt32 readSize = kBufSize;
|
||||
UInt64 rem = mftSize - pos64;
|
||||
if (readSize > rem)
|
||||
@@ -1423,7 +1455,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
static const STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsDir, VT_BOOL},
|
||||
@@ -1433,10 +1465,11 @@ STATPROPSTG kProps[] =
|
||||
{ NULL, kpidCTime, VT_FILETIME},
|
||||
{ NULL, kpidATime, VT_FILETIME},
|
||||
{ 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, kpidFileSystem, VT_BSTR},
|
||||
@@ -1580,6 +1613,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
case kpidLinks: prop = rec.MyNumNameLinks; break;
|
||||
case kpidSize: if (data) prop = data->GetSize(); 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);
|
||||
return S_OK;
|
||||
|
||||
@@ -98,7 +98,7 @@ void CDirLink::Parse(const Byte *p)
|
||||
{
|
||||
Va = Get32(p);
|
||||
Size = Get32(p + 4);
|
||||
};
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
@@ -300,53 +300,53 @@ void CSection::Parse(const Byte *p)
|
||||
|
||||
static const CUInt32PCharPair g_HeaderCharacts[] =
|
||||
{
|
||||
{ 1 << 1, "Executable" },
|
||||
{ 1 << 13, "DLL" },
|
||||
{ 1 << 8, "32-bit" },
|
||||
{ 1 << 5, "LargeAddress" },
|
||||
{ 1 << 0, "NoRelocs" },
|
||||
{ 1 << 2, "NoLineNums" },
|
||||
{ 1 << 3, "NoLocalSyms" },
|
||||
{ 1 << 4, "AggressiveWsTrim" },
|
||||
{ 1 << 9, "NoDebugInfo" },
|
||||
{ 1 << 10, "RemovableRun" },
|
||||
{ 1 << 11, "NetRun" },
|
||||
{ 1 << 12, "System" },
|
||||
{ 1 << 14, "UniCPU" },
|
||||
{ 1 << 7, "Little-Endian" },
|
||||
{ 1 << 15, "Big-Endian" }
|
||||
{ 1, "Executable" },
|
||||
{ 13, "DLL" },
|
||||
{ 8, "32-bit" },
|
||||
{ 5, "LargeAddress" },
|
||||
{ 0, "NoRelocs" },
|
||||
{ 2, "NoLineNums" },
|
||||
{ 3, "NoLocalSyms" },
|
||||
{ 4, "AggressiveWsTrim" },
|
||||
{ 9, "NoDebugInfo" },
|
||||
{ 10, "RemovableRun" },
|
||||
{ 11, "NetRun" },
|
||||
{ 12, "System" },
|
||||
{ 14, "UniCPU" },
|
||||
{ 7, "Little-Endian" },
|
||||
{ 15, "Big-Endian" }
|
||||
};
|
||||
|
||||
static const CUInt32PCharPair g_DllCharacts[] =
|
||||
{
|
||||
{ 1 << 6, "Relocated" },
|
||||
{ 1 << 7, "Integrity" },
|
||||
{ 1 << 8, "NX-Compatible" },
|
||||
{ 1 << 9, "NoIsolation" },
|
||||
{ 1 << 10, "NoSEH" },
|
||||
{ 1 << 11, "NoBind" },
|
||||
{ 1 << 13, "WDM" },
|
||||
{ 1 << 15, "TerminalServerAware" }
|
||||
{ 6, "Relocated" },
|
||||
{ 7, "Integrity" },
|
||||
{ 8, "NX-Compatible" },
|
||||
{ 9, "NoIsolation" },
|
||||
{ 10, "NoSEH" },
|
||||
{ 11, "NoBind" },
|
||||
{ 13, "WDM" },
|
||||
{ 15, "TerminalServerAware" }
|
||||
};
|
||||
|
||||
static const CUInt32PCharPair g_SectFlags[] =
|
||||
{
|
||||
{ 1 << 3, "NoPad" },
|
||||
{ 1 << 5, "Code" },
|
||||
{ 1 << 6, "InitializedData" },
|
||||
{ 1 << 7, "UninitializedData" },
|
||||
{ 1 << 9, "Comments" },
|
||||
{ 1 << 11, "Remove" },
|
||||
{ 1 << 12, "COMDAT" },
|
||||
{ 1 << 15, "GP" },
|
||||
{ 1 << 24, "ExtendedRelocations" },
|
||||
{ 1 << 25, "Discardable" },
|
||||
{ 1 << 26, "NotCached" },
|
||||
{ 1 << 27, "NotPaged" },
|
||||
{ 1 << 28, "Shared" },
|
||||
{ 1 << 29, "Execute" },
|
||||
{ 1 << 30, "Read" },
|
||||
{ (UInt32)1 << 31, "Write" }
|
||||
{ 3, "NoPad" },
|
||||
{ 5, "Code" },
|
||||
{ 6, "InitializedData" },
|
||||
{ 7, "UninitializedData" },
|
||||
{ 9, "Comments" },
|
||||
{ 11, "Remove" },
|
||||
{ 12, "COMDAT" },
|
||||
{ 15, "GP" },
|
||||
{ 24, "ExtendedRelocations" },
|
||||
{ 25, "Discardable" },
|
||||
{ 26, "NotCached" },
|
||||
{ 27, "NotPaged" },
|
||||
{ 28, "Shared" },
|
||||
{ 29, "Execute" },
|
||||
{ 30, "Read" },
|
||||
{ 31, "Write" }
|
||||
};
|
||||
|
||||
static const CUInt32PCharPair g_MachinePairs[] =
|
||||
@@ -991,7 +991,7 @@ bool CBitmapInfoHeader::Parse(const Byte *p, size_t size)
|
||||
Compression = Get32(p + 16);
|
||||
SizeImage = Get32(p + 20);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
static UInt32 GetImageSize(UInt32 xSize, UInt32 ySize, UInt32 bitCount)
|
||||
{
|
||||
@@ -1723,6 +1723,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
size_t offset = item.Offset - sect.Va;
|
||||
if (!CheckItem(sect, item, offset))
|
||||
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);
|
||||
memcpy(referenceBuf->Buf, item.Header, item.HeaderSize);
|
||||
memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Common/StringConvert.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Windows/PropVariantUtils.h"
|
||||
#include "Windows/Time.h"
|
||||
|
||||
#include "../../IPassword.h"
|
||||
@@ -46,7 +47,21 @@ static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);
|
||||
|
||||
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, kpidIsDir, VT_BOOL},
|
||||
@@ -68,8 +83,9 @@ STATPROPSTG kProps[] =
|
||||
{ NULL, kpidUnpackVer, VT_UI1}
|
||||
};
|
||||
|
||||
STATPROPSTG kArcProps[] =
|
||||
static const STATPROPSTG kArcProps[] =
|
||||
{
|
||||
{ NULL, kpidCharacts, VT_BSTR},
|
||||
{ NULL, kpidSolid, VT_BOOL},
|
||||
{ NULL, kpidNumBlocks, VT_UI4},
|
||||
// { NULL, kpidEncrypted, VT_BOOL},
|
||||
@@ -93,11 +109,12 @@ UInt64 CHandler::GetPackSize(int refIndex) const
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
// COM_TRY_BEGIN
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
switch(propID)
|
||||
{
|
||||
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 kpidIsVolume: prop = _archiveInfo.IsVolume(); break;
|
||||
case kpidNumVolumes: prop = (UInt32)_archives.Size(); break;
|
||||
@@ -112,10 +129,11 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
prop = (UInt32)numBlocks;
|
||||
break;
|
||||
}
|
||||
case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
// COM_TRY_END
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
@@ -324,19 +342,19 @@ public:
|
||||
|
||||
HRESULT CHandler::Open2(IInStream *stream,
|
||||
const UInt64 *maxCheckStartPosition,
|
||||
IArchiveOpenCallback *openArchiveCallback)
|
||||
IArchiveOpenCallback *openCallback)
|
||||
{
|
||||
{
|
||||
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
|
||||
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
|
||||
CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openArchiveCallback;
|
||||
CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openCallback;
|
||||
|
||||
CVolumeName seqName;
|
||||
|
||||
UInt64 totalBytes = 0;
|
||||
UInt64 curBytes = 0;
|
||||
|
||||
if (openArchiveCallback != NULL)
|
||||
if (openCallback)
|
||||
{
|
||||
openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
|
||||
openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
|
||||
@@ -378,12 +396,12 @@ HRESULT CHandler::Open2(IInStream *stream,
|
||||
inStream = stream;
|
||||
|
||||
UInt64 endPos = 0;
|
||||
if (openArchiveCallback != NULL)
|
||||
{
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
if (openCallback)
|
||||
{
|
||||
totalBytes += endPos;
|
||||
RINOK(openArchiveCallback->SetTotal(NULL, &totalBytes));
|
||||
RINOK(openCallback->SetTotal(NULL, &totalBytes));
|
||||
}
|
||||
|
||||
NArchive::NRar::CInArchive archive;
|
||||
@@ -395,8 +413,16 @@ HRESULT CHandler::Open2(IInStream *stream,
|
||||
CItemEx item;
|
||||
for (;;)
|
||||
{
|
||||
if (archive.m_Position > endPos)
|
||||
{
|
||||
AddErrorMessage("Unexpected end of archive");
|
||||
break;
|
||||
}
|
||||
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 (decryptionError && _items.IsEmpty())
|
||||
@@ -426,11 +452,11 @@ HRESULT CHandler::Open2(IInStream *stream,
|
||||
_refItems.Add(refItem);
|
||||
}
|
||||
_items.Add(item);
|
||||
if (openArchiveCallback != NULL && _items.Size() % 100 == 0)
|
||||
if (openCallback && _items.Size() % 100 == 0)
|
||||
{
|
||||
UInt64 numFiles = _items.Size();
|
||||
UInt64 numBytes = curBytes + item.Position;
|
||||
RINOK(openArchiveCallback->SetCompleted(&numFiles, &numBytes));
|
||||
RINOK(openCallback->SetCompleted(&numFiles, &numBytes));
|
||||
}
|
||||
}
|
||||
curBytes += endPos;
|
||||
@@ -442,13 +468,13 @@ HRESULT CHandler::Open2(IInStream *stream,
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
const UInt64 *maxCheckStartPosition,
|
||||
IArchiveOpenCallback *openArchiveCallback)
|
||||
IArchiveOpenCallback *openCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
Close();
|
||||
try
|
||||
{
|
||||
HRESULT res = Open2(stream, maxCheckStartPosition, openArchiveCallback);
|
||||
HRESULT res = Open2(stream, maxCheckStartPosition, openCallback);
|
||||
if (res != S_OK)
|
||||
Close();
|
||||
return res;
|
||||
@@ -461,6 +487,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
_errorMessage.Empty();
|
||||
_refItems.Clear();
|
||||
_items.Clear();
|
||||
_archives.Clear();
|
||||
@@ -520,7 +547,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
lastIndex = index + 1;
|
||||
}
|
||||
|
||||
extractCallback->SetTotal(importantTotalUnPacked);
|
||||
RINOK(extractCallback->SetTotal(importantTotalUnPacked));
|
||||
UInt64 currentImportantTotalUnPacked = 0;
|
||||
UInt64 currentImportantTotalPacked = 0;
|
||||
UInt64 currentUnPackSize, currentPackSize;
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
#define __RAR_HANDLER_H
|
||||
|
||||
#include "../IArchive.h"
|
||||
#include "RarIn.h"
|
||||
#include "RarVolumeInStream.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
|
||||
#include "RarIn.h"
|
||||
#include "RarVolumeInStream.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NRar {
|
||||
|
||||
@@ -17,26 +18,15 @@ class CHandler:
|
||||
PUBLIC_ISetCompressCodecsInfo
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_QUERYINTERFACE_BEGIN2(IInArchive)
|
||||
QUERY_ENTRY_ISetCompressCodecsInfo
|
||||
MY_QUERYINTERFACE_END
|
||||
MY_ADDREF_RELEASE
|
||||
|
||||
INTERFACE_IInArchive(;)
|
||||
|
||||
DECL_ISetCompressCodecsInfo
|
||||
|
||||
private:
|
||||
CRecordVector<CRefItem> _refItems;
|
||||
CObjectVector<CItemEx> _items;
|
||||
CObjectVector<CInArchive> _archives;
|
||||
NArchive::NRar::CInArchiveInfo _archiveInfo;
|
||||
AString _errorMessage;
|
||||
|
||||
DECL_EXTERNAL_CODECS_VARS
|
||||
|
||||
UInt64 GetPackSize(int refIndex) const;
|
||||
// NArchive::NRar::CInArchive _archive;
|
||||
|
||||
bool IsSolid(int refIndex)
|
||||
{
|
||||
@@ -49,10 +39,26 @@ private:
|
||||
}
|
||||
return item.IsSolid();
|
||||
}
|
||||
void AddErrorMessage(const AString &s)
|
||||
{
|
||||
if (!_errorMessage.IsEmpty())
|
||||
_errorMessage += '\n';
|
||||
_errorMessage += s;
|
||||
}
|
||||
|
||||
HRESULT Open2(IInStream *stream,
|
||||
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
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -19,15 +19,15 @@ namespace NBlockType
|
||||
enum EBlockType
|
||||
{
|
||||
kMarker = 0x72,
|
||||
kArchiveHeader = 0x73,
|
||||
kFileHeader = 0x74,
|
||||
kCommentHeader = 0x75,
|
||||
kOldAuthenticity = 0x76,
|
||||
kSubBlock = 0x77,
|
||||
kRecoveryRecord = 0x78,
|
||||
kAuthenticity = 0x79,
|
||||
|
||||
kEndOfArchive = 0x7B // Is not safe
|
||||
kArchiveHeader,
|
||||
kFileHeader,
|
||||
kCommentHeader,
|
||||
kOldAuthenticity,
|
||||
kOldSubBlock,
|
||||
kRecoveryRecord,
|
||||
kAuthenticity,
|
||||
kSubBlock,
|
||||
kEndOfArchive
|
||||
};
|
||||
}
|
||||
|
||||
@@ -46,29 +46,10 @@ namespace NArchive
|
||||
|
||||
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 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
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../../C/7zCrc.h"
|
||||
#include "../../../../C/CpuArch.h"
|
||||
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/UTFConvert.h"
|
||||
@@ -14,9 +15,16 @@
|
||||
|
||||
#include "RarIn.h"
|
||||
|
||||
#define Get16(p) GetUi16(p)
|
||||
#define Get32(p) GetUi32(p)
|
||||
#define Get64(p) GetUi64(p)
|
||||
|
||||
namespace NArchive {
|
||||
namespace NRar {
|
||||
|
||||
static const char *k_UnexpectedEnd = "Unexpected end of archive";
|
||||
static const char *k_DecryptionError = "Decryption Error";
|
||||
|
||||
void CInArchive::ThrowExceptionWithCode(
|
||||
CInArchiveException::CCauseType cause)
|
||||
{
|
||||
@@ -42,76 +50,30 @@ void CInArchive::Close()
|
||||
m_Stream.Release();
|
||||
}
|
||||
|
||||
|
||||
static inline bool TestMarkerCandidate(const void *aTestBytes)
|
||||
HRESULT CInArchive::ReadBytesSpec(void *data, size_t *resSize)
|
||||
{
|
||||
for (UInt32 i = 0; i < NHeader::kMarkerSize; i++)
|
||||
if (((const Byte *)aTestBytes)[i] != NHeader::kMarker[i])
|
||||
return false;
|
||||
return true;
|
||||
if (m_CryptoMode)
|
||||
{
|
||||
size_t size = *resSize;
|
||||
*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;
|
||||
}
|
||||
|
||||
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);
|
||||
return ReadStream(m_Stream, data, resSize);
|
||||
}
|
||||
|
||||
bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size)
|
||||
{
|
||||
if (m_CryptoMode)
|
||||
{
|
||||
const Byte *bufData = m_DecryptedDataAligned;
|
||||
UInt32 bufSize = m_DecryptedDataSize;
|
||||
UInt32 i;
|
||||
for (i = 0; i < size && m_CryptoPos < bufSize; i++)
|
||||
((Byte *)data)[i] = bufData[m_CryptoPos++];
|
||||
return (i == size);
|
||||
size_t processed = size;
|
||||
if (ReadBytesSpec(data, &processed) != S_OK)
|
||||
return false;
|
||||
return processed == 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)
|
||||
{
|
||||
@@ -119,63 +81,49 @@ HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_SET, &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];
|
||||
UInt32 processedSize;
|
||||
ReadBytes(buf, sizeof(buf), &processedSize);
|
||||
if (processedSize != sizeof(buf))
|
||||
return S_FALSE;
|
||||
m_CurData = buf;
|
||||
m_CurPos = 0;
|
||||
m_PosLimit = sizeof(buf);
|
||||
RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize));
|
||||
AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize);
|
||||
|
||||
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;
|
||||
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);
|
||||
UInt32 blockSize = Get16(buf + 5);
|
||||
|
||||
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 (processedSize != 1)
|
||||
if (blockSize <= headerSize)
|
||||
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(m_ArchiveHeader.CRC != (CRC_GET_DIGEST(crc) & 0xFFFF))
|
||||
ThrowExceptionWithCode(CInArchiveException::kArchiveHeaderCRCError);
|
||||
if (m_ArchiveHeader.Type != NHeader::NBlockType::kArchiveHeader)
|
||||
if (blockSize < headerSize ||
|
||||
buf[2] != NHeader::NBlockType::kArchiveHeader ||
|
||||
(UInt32)Get16(buf) != (CrcCalc(buf + 2, headerSize - 2) & 0xFFFF))
|
||||
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;
|
||||
}
|
||||
|
||||
void CInArchive::SkipArchiveComment()
|
||||
{
|
||||
if (!m_SeekOnArchiveComment)
|
||||
return;
|
||||
AddToSeekValue(m_ArchiveHeader.Size - m_ArchiveHeader.GetBaseSize());
|
||||
m_SeekOnArchiveComment = false;
|
||||
}
|
||||
|
||||
void CInArchive::GetArchiveInfo(CInArchiveInfo &archiveInfo) const
|
||||
{
|
||||
archiveInfo.StartPosition = m_ArchiveStartPosition;
|
||||
archiveInfo.Flags = m_ArchiveHeader.Flags;
|
||||
archiveInfo.CommentPosition = m_ArchiveCommentPosition;
|
||||
archiveInfo.CommentSize = (UInt16)(m_ArchiveHeader.Size - NHeader::NArchive::kArchiveHeaderSize);
|
||||
archiveInfo = _header;
|
||||
}
|
||||
|
||||
static void DecodeUnicodeFileName(const char *name, const Byte *encName,
|
||||
@@ -372,29 +320,24 @@ void CInArchive::AddToSeekValue(UInt64 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;
|
||||
if (m_SeekOnArchiveComment)
|
||||
SkipArchiveComment();
|
||||
for (;;)
|
||||
{
|
||||
if(!SeekInArchive(m_Position))
|
||||
return S_FALSE;
|
||||
if (!m_CryptoMode && (m_ArchiveHeader.Flags &
|
||||
SeekInArchive(m_Position);
|
||||
if (!m_CryptoMode && (_header.Flags &
|
||||
NHeader::NArchive::kBlockHeadersAreEncrypted) != 0)
|
||||
{
|
||||
m_CryptoMode = false;
|
||||
if (getTextPassword == 0)
|
||||
return S_FALSE;
|
||||
if(!SeekInArchive(m_Position))
|
||||
return S_FALSE;
|
||||
if (!m_RarAES)
|
||||
{
|
||||
m_RarAESSpec = new NCrypto::NRar29::CDecoder;
|
||||
m_RarAES = m_RarAESSpec;
|
||||
}
|
||||
m_RarAESSpec->SetRar350Mode(m_ArchiveHeader.IsEncryptOld());
|
||||
m_RarAESSpec->SetRar350Mode(_header.IsEncryptOld());
|
||||
|
||||
// Salt
|
||||
const UInt32 kSaltSize = 8;
|
||||
@@ -438,8 +381,14 @@ HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPa
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
m_CurData = (Byte *)m_FileHeaderData;
|
||||
m_CurPos = 0;
|
||||
@@ -460,7 +409,12 @@ HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPa
|
||||
m_FileHeaderData.EnsureCapacity(m_BlockHeader.HeadSize);
|
||||
m_CurData = (Byte *)m_FileHeaderData;
|
||||
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);
|
||||
if ((CrcCalc(m_CurData + 2,
|
||||
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))
|
||||
{
|
||||
decryptionError = true;
|
||||
errorMessage = k_DecryptionError;
|
||||
return S_FALSE;
|
||||
}
|
||||
if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0)
|
||||
{
|
||||
m_FileHeaderData.EnsureCapacity(7 + 4);
|
||||
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;
|
||||
UInt32 dataSize = ReadUInt32();
|
||||
AddToSeekValue(dataSize);
|
||||
if (m_CryptoMode && dataSize > (1 << 27))
|
||||
{
|
||||
decryptionError = true;
|
||||
errorMessage = k_DecryptionError;
|
||||
return S_FALSE;
|
||||
}
|
||||
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, &newPosition);
|
||||
return newPosition == position;
|
||||
m_Stream->Seek(position, STREAM_SEEK_SET, NULL);
|
||||
}
|
||||
|
||||
ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size)
|
||||
|
||||
@@ -33,18 +33,20 @@ public:
|
||||
CInArchiveException(CCauseType cause) : Cause(cause) {}
|
||||
};
|
||||
|
||||
class CInArchiveInfo
|
||||
|
||||
struct CInArchiveInfo
|
||||
{
|
||||
public:
|
||||
UInt32 Flags;
|
||||
Byte EncryptVersion;
|
||||
UInt64 StartPosition;
|
||||
UInt16 Flags;
|
||||
UInt64 CommentPosition;
|
||||
UInt16 CommentSize;
|
||||
|
||||
bool IsSolid() const { return (Flags & NHeader::NArchive::kSolid) != 0; }
|
||||
bool IsCommented() const { return (Flags & NHeader::NArchive::kComment) != 0; }
|
||||
bool IsVolume() const { return (Flags & NHeader::NArchive::kVolume) != 0; }
|
||||
bool HaveNewVolumeName() const { return (Flags & NHeader::NArchive::kNewVolName) != 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
|
||||
@@ -52,23 +54,19 @@ class CInArchive
|
||||
CMyComPtr<IInStream> m_Stream;
|
||||
|
||||
UInt64 m_StreamStartPosition;
|
||||
UInt64 m_Position;
|
||||
UInt64 m_ArchiveStartPosition;
|
||||
|
||||
NHeader::NArchive::CHeader360 m_ArchiveHeader;
|
||||
CInArchiveInfo _header;
|
||||
CDynamicBuffer<char> m_NameBuffer;
|
||||
CDynamicBuffer<wchar_t> _unicodeNameBuffer;
|
||||
bool m_SeekOnArchiveComment;
|
||||
UInt64 m_ArchiveCommentPosition;
|
||||
|
||||
CByteBuffer _comment;
|
||||
|
||||
void ReadName(CItemEx &item, int nameSize);
|
||||
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);
|
||||
void ReadBytesAndTestResult(void *data, UInt32 size);
|
||||
|
||||
HRESULT FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
|
||||
HRESULT Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
|
||||
|
||||
void ThrowExceptionWithCode(CInArchiveException::CCauseType cause);
|
||||
@@ -108,15 +106,15 @@ class CInArchive
|
||||
}
|
||||
|
||||
public:
|
||||
UInt64 m_Position;
|
||||
|
||||
HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit);
|
||||
void Close();
|
||||
HRESULT GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError);
|
||||
|
||||
void SkipArchiveComment();
|
||||
HRESULT GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage);
|
||||
|
||||
void GetArchiveInfo(CInArchiveInfo &archiveInfo) const;
|
||||
|
||||
bool SeekInArchive(UInt64 position);
|
||||
void SeekInArchive(UInt64 position);
|
||||
ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
|
||||
};
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ static HRESULT RedSigHeaderSig(IInStream *inStream, CSigHeaderSig &h)
|
||||
char dat[kCSigHeaderSigSize];
|
||||
char *cur = dat;
|
||||
RINOK(ReadStream_FALSE(inStream, dat, kCSigHeaderSigSize));
|
||||
memmove(h.Magic, cur, 4);
|
||||
memcpy(h.Magic, cur, 4);
|
||||
cur += 4;
|
||||
cur += 4;
|
||||
h.IndexLen = Get32(cur);
|
||||
@@ -95,7 +95,7 @@ HRESULT OpenArchive(IInStream *inStream)
|
||||
char *cur = leadData;
|
||||
CLead lead;
|
||||
RINOK(ReadStream_FALSE(inStream, leadData, kLeadSize));
|
||||
memmove(lead.Magic, cur, 4);
|
||||
memcpy(lead.Magic, cur, 4);
|
||||
cur += 4;
|
||||
lead.Major = *cur++;
|
||||
lead.Minor = *cur++;
|
||||
@@ -103,7 +103,7 @@ HRESULT OpenArchive(IInStream *inStream)
|
||||
cur += 2;
|
||||
lead.ArchNum = Get16(cur);
|
||||
cur += 2;
|
||||
memmove(lead.Name, cur, sizeof(lead.Name));
|
||||
memcpy(lead.Name, cur, sizeof(lead.Name));
|
||||
cur += sizeof(lead.Name);
|
||||
lead.OSNum = Get16(cur);
|
||||
cur += 2;
|
||||
|
||||
@@ -347,7 +347,6 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
CMultiStream::CSubStreamInfo subStreamInfo;
|
||||
subStreamInfo.Stream = _streams[i];
|
||||
subStreamInfo.Pos = 0;
|
||||
subStreamInfo.Size = _sizes[i];
|
||||
streamSpec->Streams.Add(subStreamInfo);
|
||||
}
|
||||
|
||||
2155
CPP/7zip/Archive/SquashfsHandler.cpp
Executable file
2155
CPP/7zip/Archive/SquashfsHandler.cpp
Executable file
File diff suppressed because it is too large
Load Diff
@@ -3,8 +3,6 @@
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/Defs.h"
|
||||
#include "Common/NewHandler.h"
|
||||
#include "Common/StringConvert.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
@@ -12,6 +10,8 @@
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/StreamObjects.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "../Common/ItemNameUtils.h"
|
||||
|
||||
@@ -23,7 +23,9 @@ using namespace NWindows;
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
static const char *kUnexpectedEnd = "Unexpected end of archive";
|
||||
|
||||
static const STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsDir, VT_BOOL},
|
||||
@@ -36,8 +38,14 @@ STATPROPSTG kProps[] =
|
||||
{ NULL, kpidLink, VT_BSTR}
|
||||
};
|
||||
|
||||
static const STATPROPSTG kArcProps[] =
|
||||
{
|
||||
{ NULL, kpidPhySize, VT_UI8},
|
||||
{ NULL, kpidHeadersSize, VT_UI8}
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps_NO_Table
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
@@ -45,11 +53,22 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
switch(propID)
|
||||
{
|
||||
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);
|
||||
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)
|
||||
{
|
||||
UInt64 endPos = 0;
|
||||
@@ -58,26 +77,29 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
|
||||
_isGood = true;
|
||||
UInt64 pos = 0;
|
||||
_phySizeDefined = true;
|
||||
for (;;)
|
||||
{
|
||||
CItemEx item;
|
||||
bool filled;
|
||||
item.HeaderPosition = pos;
|
||||
RINOK(ReadItem(stream, filled, item));
|
||||
RINOK(ReadItem2(stream, filled, item));
|
||||
if (!filled)
|
||||
break;
|
||||
_items.Add(item);
|
||||
|
||||
RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &pos));
|
||||
if (pos > endPos)
|
||||
return S_FALSE;
|
||||
if (pos == endPos)
|
||||
RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &_phySize));
|
||||
if (_phySize > endPos)
|
||||
{
|
||||
_isGood = false;
|
||||
_errorMessage = kUnexpectedEnd;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
if (_phySize == endPos)
|
||||
{
|
||||
_errorMessage = "There are no trailing zero-filled records";
|
||||
break;
|
||||
}
|
||||
*/
|
||||
if (callback != NULL)
|
||||
{
|
||||
if (_items.Size() == 1)
|
||||
@@ -87,7 +109,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
if (_items.Size() % 100 == 0)
|
||||
{
|
||||
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()
|
||||
{
|
||||
_errorMessage.Empty();
|
||||
_phySizeDefined = false;
|
||||
_phySize = 0;
|
||||
_headersSize = 0;
|
||||
_curIndex = 0;
|
||||
_latestIsRead = false;
|
||||
_items.Clear();
|
||||
@@ -163,16 +188,24 @@ HRESULT CHandler::SkipTo(UInt32 index)
|
||||
{
|
||||
UInt64 packSize = _latestItem.GetPackSize();
|
||||
RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL));
|
||||
_phySize += copyCoderSpec->TotalSize;
|
||||
if (copyCoderSpec->TotalSize != packSize)
|
||||
{
|
||||
_errorMessage = kUnexpectedEnd;
|
||||
return S_FALSE;
|
||||
}
|
||||
_latestIsRead = false;
|
||||
_curIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool filled;
|
||||
// item.HeaderPosition = pos;
|
||||
RINOK(ReadItem(_seqStream, filled, _latestItem));
|
||||
RINOK(ReadItem2(_seqStream, filled, _latestItem));
|
||||
if (!filled)
|
||||
{
|
||||
_phySizeDefined = true;
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
_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 kpidIsDir: prop = item->IsDir(); break;
|
||||
case kpidSize: prop = item->Size; break;
|
||||
case kpidSize: prop = item->GetUnpackSize(); break;
|
||||
case kpidPackSize: prop = item->GetPackSize(); break;
|
||||
case kpidMTime:
|
||||
if (item->MTime != 0)
|
||||
@@ -244,7 +277,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
UInt64 totalSize = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < numItems; i++)
|
||||
totalSize += _items[allFilesMode ? i : indices[i]].Size;
|
||||
totalSize += _items[allFilesMode ? i : indices[i]].GetUnpackSize();
|
||||
extractCallback->SetTotal(totalSize);
|
||||
|
||||
UInt64 totalPackSize;
|
||||
@@ -284,7 +317,8 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
item = &_items[index];
|
||||
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
totalSize += item->Size;
|
||||
UInt64 unpackSize = item->GetUnpackSize();
|
||||
totalSize += unpackSize;
|
||||
totalPackSize += item->GetPackSize();
|
||||
if (item->IsDir())
|
||||
{
|
||||
@@ -304,14 +338,21 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
|
||||
outStreamSpec->SetStream(realOutStream);
|
||||
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)
|
||||
{
|
||||
RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
streamSpec->Init(item->GetPackSize());
|
||||
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
||||
}
|
||||
if (seqMode)
|
||||
{
|
||||
_latestIsRead = false;
|
||||
@@ -330,6 +371,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
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);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
@@ -23,18 +23,20 @@ class CHandler:
|
||||
CObjectVector<CItemEx> _items;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CMyComPtr<ISequentialInStream> _seqStream;
|
||||
bool _isGood;
|
||||
|
||||
UInt32 _curIndex;
|
||||
bool _latestIsRead;
|
||||
CItemEx _latestItem;
|
||||
|
||||
UInt64 _phySize;
|
||||
UInt64 _headersSize;
|
||||
bool _phySizeDefined;
|
||||
AString _errorMessage;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec;
|
||||
CMyComPtr<ICompressCoder> copyCoder;
|
||||
|
||||
HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
|
||||
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
|
||||
HRESULT SkipTo(UInt32 index);
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
IArchiveUpdateCallback *callback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
if ((_stream && !_isGood) || _seqStream)
|
||||
if ((_stream && !_errorMessage.IsEmpty()) || _seqStream)
|
||||
return E_NOTIMPL;
|
||||
CObjectVector<CUpdateItem> updateItems;
|
||||
for (UInt32 i = 0; i < numItems; i++)
|
||||
@@ -107,8 +107,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
if (prop.vt != VT_UI8)
|
||||
return E_INVALIDARG;
|
||||
ui.Size = prop.uhVal.QuadPart;
|
||||
/*
|
||||
// now we support GNU extension for big files
|
||||
if (ui.Size >= ((UInt64)1 << 33))
|
||||
return E_INVALIDARG;
|
||||
*/
|
||||
}
|
||||
updateItems.Add(ui);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../../C/CpuArch.h"
|
||||
|
||||
#include "Common/StringToInt.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
@@ -61,20 +63,40 @@ static void ReadString(const char *s, int size, AString &result)
|
||||
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 *p = buf;
|
||||
|
||||
error.Empty();
|
||||
filled = false;
|
||||
|
||||
processedSize = NFileHeader::kRecordSize;
|
||||
bool thereAreEmptyRecords = false;
|
||||
for (;;)
|
||||
{
|
||||
size_t processedSize = NFileHeader::kRecordSize;
|
||||
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;
|
||||
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;
|
||||
|
||||
@@ -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.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;
|
||||
|
||||
UInt32 checkSum;
|
||||
@@ -123,59 +154,54 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item)
|
||||
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
|
||||
{
|
||||
size_t processedSize;
|
||||
RINOK(GetNextItemReal(stream, filled, item, processedSize));
|
||||
item.HeaderSize = 0;
|
||||
bool flagL = false;
|
||||
bool flagK = false;
|
||||
AString nameL;
|
||||
AString nameK;
|
||||
for (;;)
|
||||
{
|
||||
RINOK(GetNextItemReal(stream, filled, item, error));
|
||||
if (!filled)
|
||||
return S_OK;
|
||||
// GNUtar extension
|
||||
if (item.LinkFlag == 'L' || // NEXT file has a long name
|
||||
item.LinkFlag == 'K') // NEXT file has a long linkname
|
||||
{
|
||||
if (item.Name.Compare(NFileHeader::kLongLink) != 0)
|
||||
if (item.Name.Compare(NFileHeader::kLongLink2) != 0)
|
||||
return S_FALSE;
|
||||
AString *name;
|
||||
if (item.LinkFlag == 'L')
|
||||
{ if (flagL) return S_FALSE; flagL = true; name = &nameL; }
|
||||
else
|
||||
{ if (flagK) return S_FALSE; flagK = true; name = &nameK; }
|
||||
|
||||
AString fullName;
|
||||
if (item.Size > (1 << 15))
|
||||
if (item.Name.Compare(NFileHeader::kLongLink) != 0 &&
|
||||
item.Name.Compare(NFileHeader::kLongLink2) != 0)
|
||||
return S_FALSE;
|
||||
if (item.Size > (1 << 14))
|
||||
return S_FALSE;
|
||||
int packSize = (int)item.GetPackSize();
|
||||
char *buffer = fullName.GetBuffer(packSize + 1);
|
||||
|
||||
RINOK(ReadStream_FALSE(stream, buffer, packSize));
|
||||
processedSize += packSize;
|
||||
buffer[item.Size] = '\0';
|
||||
fullName.ReleaseBuffer();
|
||||
|
||||
UInt64 headerPosition = item.HeaderPosition;
|
||||
if (item.LinkFlag == 'L')
|
||||
{
|
||||
size_t processedSize2;
|
||||
RINOK(GetNextItemReal(stream, filled, item, processedSize2));
|
||||
item.LongLinkSize = (unsigned)processedSize;
|
||||
char *buf = name->GetBuffer(packSize);
|
||||
RINOK(ReadStream_FALSE(stream, buf, packSize));
|
||||
item.HeaderSize += packSize;
|
||||
buf[(size_t)item.Size] = '\0';
|
||||
name->ReleaseBuffer();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
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')
|
||||
if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X')
|
||||
{
|
||||
// pax Extended Header
|
||||
return S_OK;
|
||||
}
|
||||
else if (item.LinkFlag == NFileHeader::NLinkFlag::kDumpDir)
|
||||
{
|
||||
// GNU Extensions to the Archive Format
|
||||
return S_OK;
|
||||
}
|
||||
else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
|
||||
return S_FALSE;
|
||||
if (flagL) item.Name = nameL;
|
||||
if (flagK) item.LinkName = nameK;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Archive/TarIn.h
|
||||
// TarIn.h
|
||||
|
||||
#ifndef __ARCHIVE_TAR_IN_H
|
||||
#define __ARCHIVE_TAR_IN_H
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
#include "TarItem.h"
|
||||
@@ -11,7 +10,7 @@
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
|
||||
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, AString &error);
|
||||
|
||||
}}
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ struct CItem
|
||||
bool DeviceMajorDefined;
|
||||
bool DeviceMinorDefined;
|
||||
|
||||
bool IsLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymbolicLink && (Size == 0); }
|
||||
UInt64 GetUnpackSize() const { return IsLink() ? LinkName.Length() : Size; }
|
||||
|
||||
bool IsDir() const
|
||||
{
|
||||
switch(LinkFlag)
|
||||
@@ -58,10 +61,10 @@ struct CItem
|
||||
|
||||
struct CItemEx: public CItem
|
||||
{
|
||||
UInt64 HeaderPosition;
|
||||
unsigned LongLinkSize;
|
||||
UInt64 GetDataPosition() const { return HeaderPosition + LongLinkSize + NFileHeader::kRecordSize; }
|
||||
UInt64 GetFullSize() const { return LongLinkSize + NFileHeader::kRecordSize + Size; }
|
||||
UInt64 HeaderPos;
|
||||
unsigned HeaderSize;
|
||||
UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
|
||||
UInt64 GetFullSize() const { return HeaderSize + Size; }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -53,17 +53,23 @@ static bool MakeOctalString8(char *s, UInt32 value)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool MakeOctalString12(char *s, UInt64 value)
|
||||
static void MakeOctalString12(char *s, UInt64 value)
|
||||
{
|
||||
AString tempString = MakeOctalString(value);
|
||||
const int kMaxSize = 12;
|
||||
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();
|
||||
for(int i = 0; i < numSpaces; i++)
|
||||
s[i] = ' ';
|
||||
memmove(s + numSpaces, (const char *)tempString, tempString.Length());
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
cur += NFileHeader::kNameSize;
|
||||
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.Mode));
|
||||
cur += 8;
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.UID));
|
||||
cur += 8;
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.GID));
|
||||
cur += 8;
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.Mode)); cur += 8;
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.UID)); cur += 8;
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.GID)); cur += 8;
|
||||
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString12(cur, item.Size));
|
||||
cur += 12;
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString12(cur, item.MTime));
|
||||
cur += 12;
|
||||
MakeOctalString12(cur, item.Size); cur += 12;
|
||||
MakeOctalString12(cur, item.MTime); cur += 12;
|
||||
|
||||
memmove(cur, NFileHeader::kCheckSumBlanks, 8);
|
||||
cur += 8;
|
||||
|
||||
@@ -111,25 +111,25 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
||||
}
|
||||
else
|
||||
{
|
||||
const CItemEx &existItemInfo = inputItems[ui.IndexInArchive];
|
||||
const CItemEx &existItem = inputItems[ui.IndexInArchive];
|
||||
UInt64 size;
|
||||
if (ui.NewProps)
|
||||
{
|
||||
RINOK(outArchive.WriteHeader(item));
|
||||
RINOK(inStream->Seek(existItemInfo.GetDataPosition(), STREAM_SEEK_SET, NULL));
|
||||
size = existItemInfo.Size;
|
||||
RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL));
|
||||
size = existItem.Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(inStream->Seek(existItemInfo.HeaderPosition, STREAM_SEEK_SET, NULL));
|
||||
size = existItemInfo.GetFullSize();
|
||||
RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL));
|
||||
size = existItem.GetFullSize();
|
||||
}
|
||||
streamSpec->Init(size);
|
||||
|
||||
RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
|
||||
if (copyCoderSpec->TotalSize != size)
|
||||
return E_FAIL;
|
||||
RINOK(outArchive.FillDataResidual(existItemInfo.Size));
|
||||
RINOK(outArchive.FillDataResidual(existItem.Size));
|
||||
complexity += size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/NewHandler.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Windows/Time.h"
|
||||
@@ -34,7 +33,7 @@ void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop)
|
||||
prop = ft;
|
||||
}
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
static STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsDir, VT_BOOL},
|
||||
@@ -44,7 +43,7 @@ STATPROPSTG kProps[] =
|
||||
{ NULL, kpidATime, VT_FILETIME}
|
||||
};
|
||||
|
||||
STATPROPSTG kArcProps[] =
|
||||
static STATPROPSTG kArcProps[] =
|
||||
{
|
||||
{ NULL, kpidComment, VT_BSTR},
|
||||
{ NULL, kpidClusterSize, VT_UI4},
|
||||
|
||||
@@ -35,4 +35,3 @@ public:
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -202,7 +202,7 @@ enum EDescriptorType
|
||||
DESC_TYPE_UnallocatedSpace = 263,
|
||||
DESC_TYPE_SpaceBitmap = 264,
|
||||
DESC_TYPE_PartitionIntegrity = 265,
|
||||
DESC_TYPE_ExtendedFile = 266,
|
||||
DESC_TYPE_ExtendedFile = 266
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
static IInArchive *CreateArc() { return new NArchive::NUdf::CHandler; }
|
||||
|
||||
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)
|
||||
|
||||
@@ -2,18 +2,17 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/IntToString.h"
|
||||
#include "Common/Defs.h"
|
||||
#include "../../../../C/CpuArch.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/IntToString.h"
|
||||
#include "Common/StringToInt.h"
|
||||
#include "Common/UTFConvert.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
|
||||
#include "../../../../C/CpuArch.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "WimHandler.h"
|
||||
|
||||
@@ -28,17 +27,18 @@ namespace NWim {
|
||||
|
||||
#define WIM_DETAILS
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
static STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsDir, VT_BOOL},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidAttrib, VT_UI4},
|
||||
{ NULL, kpidMethod, VT_BSTR},
|
||||
{ NULL, kpidMTime, 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
|
||||
, { NULL, kpidVolume, VT_UI4}
|
||||
@@ -47,14 +47,15 @@ STATPROPSTG kProps[] =
|
||||
#endif
|
||||
};
|
||||
|
||||
STATPROPSTG kArcProps[] =
|
||||
static STATPROPSTG kArcProps[] =
|
||||
{
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidMethod, VT_BSTR},
|
||||
{ NULL, kpidCTime, VT_FILETIME},
|
||||
{ NULL, kpidMTime, VT_FILETIME},
|
||||
{ NULL, kpidComment, VT_FILETIME},
|
||||
{ NULL, kpidComment, VT_BSTR},
|
||||
{ NULL, kpidUnpackVer, VT_BSTR},
|
||||
{ NULL, kpidIsVolume, VT_BOOL},
|
||||
{ NULL, kpidVolume, VT_UI4},
|
||||
{ NULL, kpidNumVolumes, VT_UI4}
|
||||
@@ -87,49 +88,51 @@ static bool ParseNumber32(const AString &s, UInt32 &res)
|
||||
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 cTimeIndex = item.FindSubTag(s);
|
||||
if (cTimeIndex >= 0)
|
||||
int index = item.FindSubTag(tag);
|
||||
if (index >= 0)
|
||||
{
|
||||
const CXmlItem &timeItem = item.SubItems[cTimeIndex];
|
||||
UInt32 high = 0, low = 0;
|
||||
if (ParseNumber32(timeItem.GetSubStringForTag("HIGHPART"), high) &&
|
||||
ParseNumber32(timeItem.GetSubStringForTag("LOWPART"), low))
|
||||
const CXmlItem &timeItem = item.SubItems[index];
|
||||
UInt32 low = 0, high = 0;
|
||||
if (ParseNumber32(timeItem.GetSubStringForTag("LOWPART"), low) &&
|
||||
ParseNumber32(timeItem.GetSubStringForTag("HIGHPART"), high))
|
||||
{
|
||||
defined = true;
|
||||
ft.dwHighDateTime = high;
|
||||
ft.dwLowDateTime = low;
|
||||
ft.dwHighDateTime = high;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CImageInfo::Parse(const CXmlItem &item)
|
||||
{
|
||||
ParseTime(item, CTimeDefined, CTime, "CREATIONTIME");
|
||||
ParseTime(item, MTimeDefined, MTime, "LASTMODIFICATIONTIME");
|
||||
CTimeDefined = ParseTime(item, CTime, "CREATIONTIME");
|
||||
MTimeDefined = ParseTime(item, MTime, "LASTMODIFICATIONTIME");
|
||||
NameDefined = ConvertUTF8ToUnicode(item.GetSubStringForTag("NAME"), Name);
|
||||
// IndexDefined = ParseNumber32(item.GetPropertyValue("INDEX"), Index);
|
||||
}
|
||||
|
||||
void CXml::Parse()
|
||||
void CXml::ToUnicode(UString &s)
|
||||
{
|
||||
size_t size = Data.GetCapacity();
|
||||
if (size < 2 || (size & 1) != 0 || (size > 1 << 24))
|
||||
if (size < 2 || (size & 1) != 0 || size > (1 << 24))
|
||||
return;
|
||||
const Byte *p = Data;
|
||||
if (Get16(p) != 0xFEFF)
|
||||
return;
|
||||
UString s;
|
||||
{
|
||||
wchar_t *chars = s.GetBuffer((int)size / 2 + 1);
|
||||
wchar_t *chars = s.GetBuffer((int)size / 2);
|
||||
for (size_t i = 2; i < size; i += 2)
|
||||
*chars++ = (wchar_t)Get16(p + i);
|
||||
*chars = 0;
|
||||
s.ReleaseBuffer();
|
||||
}
|
||||
|
||||
void CXml::Parse()
|
||||
{
|
||||
UString s;
|
||||
ToUnicode(s);
|
||||
AString utf;
|
||||
if (!ConvertUnicodeToUTF8(s, utf))
|
||||
return;
|
||||
@@ -151,10 +154,9 @@ void CXml::Parse()
|
||||
}
|
||||
}
|
||||
|
||||
static const wchar_t *kStreamsNamePrefix = L"Files" WSTRING_PATH_SEPARATOR;
|
||||
static const wchar_t *kMethodLZX = L"LZX";
|
||||
static const wchar_t *kMethodXpress = L"XPress";
|
||||
static const wchar_t *kMethodCopy = L"Copy";
|
||||
static const char *kMethodLZX = "LZX";
|
||||
static const char *kMethodXpress = "XPress";
|
||||
static const char *kMethodCopy = "Copy";
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps
|
||||
@@ -165,22 +167,22 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
|
||||
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)
|
||||
image = &xml.Images[0];
|
||||
}
|
||||
|
||||
switch(propID)
|
||||
{
|
||||
case kpidSize: prop = m_Database.GetUnpackSize(); break;
|
||||
case kpidPackSize: prop = m_Database.GetPackSize(); break;
|
||||
case kpidSize: prop = _db.GetUnpackSize(); break;
|
||||
case kpidPackSize: prop = _db.GetPackSize(); break;
|
||||
|
||||
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;
|
||||
for (int i = 0; i < xml.Images.Size(); i++)
|
||||
{
|
||||
@@ -195,9 +197,9 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
break;
|
||||
|
||||
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;
|
||||
for (int i = 0; i < xml.Images.Size(); i++)
|
||||
{
|
||||
@@ -211,32 +213,65 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
}
|
||||
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:
|
||||
if (m_Xmls.Size() > 0)
|
||||
if (_xmls.Size() > 0)
|
||||
{
|
||||
UInt16 volIndex = m_Xmls[0].VolIndex;
|
||||
if (volIndex < m_Volumes.Size())
|
||||
prop = (m_Volumes[volIndex].Header.NumParts > 1);
|
||||
UInt16 volIndex = _xmls[0].VolIndex;
|
||||
if (volIndex < _volumes.Size())
|
||||
prop = (_volumes[volIndex].Header.NumParts > 1);
|
||||
}
|
||||
break;
|
||||
case kpidVolume:
|
||||
if (m_Xmls.Size() > 0)
|
||||
if (_xmls.Size() > 0)
|
||||
{
|
||||
UInt16 volIndex = m_Xmls[0].VolIndex;
|
||||
if (volIndex < m_Volumes.Size())
|
||||
prop = (UInt32)m_Volumes[volIndex].Header.PartNumber;
|
||||
UInt16 volIndex = _xmls[0].VolIndex;
|
||||
if (volIndex < _volumes.Size())
|
||||
prop = (UInt32)_volumes[volIndex].Header.PartNumber;
|
||||
}
|
||||
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:
|
||||
{
|
||||
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 = vol.Header;
|
||||
const CHeader &header = _volumes[_xmls[i].VolIndex].Header;
|
||||
if (header.IsCompressed())
|
||||
if (header.IsLzxMode())
|
||||
lzx = true;
|
||||
@@ -245,19 +280,19 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
else
|
||||
copy = true;
|
||||
}
|
||||
UString res;
|
||||
AString res;
|
||||
if (lzx)
|
||||
res = kMethodLZX;
|
||||
if (xpress)
|
||||
{
|
||||
if (!res.IsEmpty())
|
||||
res += L' ';
|
||||
res += ' ';
|
||||
res += kMethodXpress;
|
||||
}
|
||||
if (copy)
|
||||
{
|
||||
if (!res.IsEmpty())
|
||||
res += L' ';
|
||||
res += ' ';
|
||||
res += kMethodCopy;
|
||||
}
|
||||
prop = res;
|
||||
@@ -272,35 +307,41 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
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 CVolume *vol = NULL;
|
||||
if (item.StreamIndex >= 0)
|
||||
{
|
||||
si = &m_Database.Streams[item.StreamIndex];
|
||||
vol = &m_Volumes[si->PartNumber];
|
||||
si = &_db.Streams[item.StreamIndex];
|
||||
vol = &_volumes[si->PartNumber];
|
||||
}
|
||||
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPath:
|
||||
if (item.HasMetadata)
|
||||
prop = item.Name;
|
||||
prop = _db.GetItemPath(realIndex);
|
||||
else
|
||||
{
|
||||
wchar_t sz[32];
|
||||
ConvertUInt64ToString(item.StreamIndex, sz);
|
||||
UString s = sz;
|
||||
while (s.Length() < m_NameLenForStreams)
|
||||
s = L'0' + s;
|
||||
s = UString(kStreamsNamePrefix) + s;
|
||||
char sz[16];
|
||||
ConvertUInt32ToString(item.StreamIndex, sz);
|
||||
AString s = sz;
|
||||
while (s.Length() < _nameLenForStreams)
|
||||
s = '0' + s;
|
||||
/*
|
||||
if (si->Resource.IsFree())
|
||||
prefix = "[Free]";
|
||||
*/
|
||||
s = "[Files]" STRING_PATH_SEPARATOR + s;
|
||||
prop = s;
|
||||
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 kpidCTime: if (item.HasMetadata) prop = item.CTime; break;
|
||||
case kpidATime: if (item.HasMetadata) prop = item.ATime; break;
|
||||
@@ -318,22 +359,21 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
}
|
||||
else
|
||||
{
|
||||
index -= m_Database.Items.Size();
|
||||
index -= _db.SortedItems.Size();
|
||||
{
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPath:
|
||||
{
|
||||
wchar_t sz[32];
|
||||
ConvertUInt64ToString(m_Xmls[index].VolIndex, sz);
|
||||
UString s = (UString)sz + L".xml";
|
||||
prop = s;
|
||||
char sz[16];
|
||||
ConvertUInt32ToString(_xmls[index].VolIndex, sz);
|
||||
prop = (AString)"[" + (AString)sz + "].xml";
|
||||
break;
|
||||
}
|
||||
case kpidIsDir: prop = false; break;
|
||||
case kpidPackSize:
|
||||
case kpidSize: prop = (UInt64)m_Xmls[index].Data.GetCapacity(); break;
|
||||
case kpidMethod: prop = L"Copy"; break;
|
||||
case kpidSize: prop = (UInt64)_xmls[index].Data.GetCapacity(); break;
|
||||
case kpidMethod: prop = kMethodCopy; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -362,8 +402,8 @@ public:
|
||||
|
||||
UString GetNextName(UInt32 index)
|
||||
{
|
||||
wchar_t s[32];
|
||||
ConvertUInt64ToString((index), s);
|
||||
wchar_t s[16];
|
||||
ConvertUInt32ToString(index, s);
|
||||
return _before + (UString)s + _after;
|
||||
}
|
||||
};
|
||||
@@ -374,7 +414,6 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
Close();
|
||||
try
|
||||
{
|
||||
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
|
||||
|
||||
@@ -410,14 +449,16 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
|
||||
continue;
|
||||
return res;
|
||||
}
|
||||
_version = header.Version;
|
||||
_isOldVersion = header.IsOldVersion();
|
||||
if (firstVolumeIndex >= 0)
|
||||
if (!header.AreFromOnArchive(m_Volumes[firstVolumeIndex].Header))
|
||||
if (!header.AreFromOnArchive(_volumes[firstVolumeIndex].Header))
|
||||
break;
|
||||
if (m_Volumes.Size() > header.PartNumber && m_Volumes[header.PartNumber].Stream)
|
||||
if (_volumes.Size() > header.PartNumber && _volumes[header.PartNumber].Stream)
|
||||
break;
|
||||
CXml xml;
|
||||
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 (i == 1)
|
||||
@@ -427,22 +468,22 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
|
||||
return res;
|
||||
}
|
||||
|
||||
while (m_Volumes.Size() <= header.PartNumber)
|
||||
m_Volumes.Add(CVolume());
|
||||
CVolume &volume = m_Volumes[header.PartNumber];
|
||||
while (_volumes.Size() <= header.PartNumber)
|
||||
_volumes.Add(CVolume());
|
||||
CVolume &volume = _volumes[header.PartNumber];
|
||||
volume.Header = header;
|
||||
volume.Stream = curStream;
|
||||
|
||||
firstVolumeIndex = header.PartNumber;
|
||||
|
||||
bool needAddXml = true;
|
||||
if (m_Xmls.Size() != 0)
|
||||
if (xml.Data == m_Xmls[0].Data)
|
||||
if (_xmls.Size() != 0)
|
||||
if (xml.Data == _xmls[0].Data)
|
||||
needAddXml = false;
|
||||
if (needAddXml)
|
||||
{
|
||||
xml.Parse();
|
||||
m_Xmls.Add(xml);
|
||||
_xmls.Add(xml);
|
||||
}
|
||||
|
||||
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];
|
||||
ConvertUInt64ToString(m_Database.Streams.Size(), sz);
|
||||
m_NameLenForStreams = MyStringLen(sz);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return S_FALSE;
|
||||
wchar_t sz[16];
|
||||
ConvertUInt32ToString(_db.Streams.Size(), sz);
|
||||
_nameLenForStreams = MyStringLen(sz);
|
||||
|
||||
_xmlInComments = (_xmls.Size() == 1 && !_db.ShowImageNumber);
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
@@ -478,10 +518,10 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
m_Database.Clear();
|
||||
m_Volumes.Clear();
|
||||
m_Xmls.Clear();
|
||||
m_NameLenForStreams = 0;
|
||||
_db.Clear();
|
||||
_volumes.Clear();
|
||||
_xmls.Clear();
|
||||
_nameLenForStreams = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -492,7 +532,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
bool allFilesMode = (numItems == (UInt32)-1);
|
||||
|
||||
if (allFilesMode)
|
||||
numItems = m_Database.Items.Size() + m_Xmls.Size();
|
||||
numItems = _db.SortedItems.Size() + _xmls.Size();
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
|
||||
@@ -501,17 +541,17 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
for (i = 0; i < numItems; 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)
|
||||
{
|
||||
const CStreamInfo &si = m_Database.Streams[streamIndex];
|
||||
const CStreamInfo &si = _db.Streams[streamIndex];
|
||||
totalSize += si.Resource.UnpackSize;
|
||||
}
|
||||
}
|
||||
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));
|
||||
@@ -546,12 +586,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
if (index >= (UInt32)m_Database.Items.Size())
|
||||
if (index >= (UInt32)_db.SortedItems.Size())
|
||||
{
|
||||
if (!testMode && !realOutStream)
|
||||
continue;
|
||||
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();
|
||||
if (realOutStream)
|
||||
{
|
||||
@@ -562,7 +602,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
continue;
|
||||
}
|
||||
|
||||
const CItem &item = m_Database.Items[index];
|
||||
const CItem &item = _db.Items[_db.SortedItems[index]];
|
||||
int streamIndex = item.StreamIndex;
|
||||
if (streamIndex < 0)
|
||||
{
|
||||
@@ -576,7 +616,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
continue;
|
||||
}
|
||||
|
||||
const CStreamInfo &si = m_Database.Streams[streamIndex];
|
||||
const CStreamInfo &si = _db.Streams[streamIndex];
|
||||
currentItemUnPacked = si.Resource.UnpackSize;
|
||||
currentItemPacked = si.Resource.PackSize;
|
||||
|
||||
@@ -587,7 +627,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
if (streamIndex != prevSuccessStreamIndex || realOutStream)
|
||||
{
|
||||
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(),
|
||||
realOutStream, progress, digest);
|
||||
if (res == S_OK)
|
||||
@@ -611,7 +651,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "Common/MyCom.h"
|
||||
#include "Common/MyXml.h"
|
||||
|
||||
#include "../IArchive.h"
|
||||
#include "WimIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
@@ -40,25 +39,37 @@ struct CXml
|
||||
{
|
||||
CByteBuffer Data;
|
||||
UInt16 VolIndex;
|
||||
|
||||
CObjectVector<CImageInfo> Images;
|
||||
|
||||
void ToUnicode(UString &s);
|
||||
void Parse();
|
||||
};
|
||||
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CDatabase _db;
|
||||
UInt32 _version;
|
||||
bool _isOldVersion;
|
||||
CObjectVector<CVolume> _volumes;
|
||||
CObjectVector<CXml> _xmls;
|
||||
int _nameLenForStreams;
|
||||
bool _xmlInComments;
|
||||
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(IInArchive)
|
||||
INTERFACE_IInArchive(;)
|
||||
};
|
||||
|
||||
private:
|
||||
CDatabase m_Database;
|
||||
CObjectVector<CVolume> m_Volumes;
|
||||
CObjectVector<CXml> m_Xmls;
|
||||
int m_NameLenForStreams;
|
||||
class COutHandler:
|
||||
public IOutArchive,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(IOutArchive)
|
||||
INTERFACE_IOutArchive(;)
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
639
CPP/7zip/Archive/Wim/WimHandlerOut.cpp
Executable file
639
CPP/7zip/Archive/Wim/WimHandlerOut.cpp
Executable 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
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -21,9 +21,6 @@
|
||||
namespace NArchive {
|
||||
namespace NWim {
|
||||
|
||||
static const int kChunkSizeBits = 15;
|
||||
static const UInt32 kChunkSize = (1 << kChunkSizeBits);
|
||||
|
||||
namespace NXpress {
|
||||
|
||||
class CDecoderFlusher
|
||||
@@ -44,7 +41,7 @@ HRESULT CDecoder::CodeSpec(UInt32 outSize)
|
||||
{
|
||||
{
|
||||
Byte levels[kMainTableSize];
|
||||
for (int i = 0; i < kMainTableSize; i += 2)
|
||||
for (unsigned i = 0; i < kMainTableSize; i += 2)
|
||||
{
|
||||
Byte b = m_InBitStream.DirectReadByte();
|
||||
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,
|
||||
ISequentialOutStream *outStream, ICompressProgressInfo *progress)
|
||||
{
|
||||
@@ -249,7 +240,7 @@ static HRESULT UnpackData(IInStream *inStream, const CResource &resource, bool l
|
||||
buf.Free();
|
||||
buf.SetCapacity(size);
|
||||
|
||||
CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2();
|
||||
CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream();
|
||||
CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
|
||||
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);
|
||||
}
|
||||
|
||||
static const UInt32 kSignatureSize = 8;
|
||||
static const Byte kSignature[kSignatureSize] = { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 };
|
||||
|
||||
void CResource::Parse(const Byte *p)
|
||||
{
|
||||
Flags = p[7];
|
||||
@@ -270,74 +258,300 @@ void CResource::Parse(const Byte *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);
|
||||
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.RefCount = Get32(p + 26);
|
||||
memcpy(s.Hash, p + 30, kHashSize);
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT ParseDirItem(const Byte *base, size_t pos, size_t size,
|
||||
const UString &prefix, CObjectVector<CItem> &items)
|
||||
static const wchar_t *kLongPath = L"[LongPath]";
|
||||
|
||||
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)
|
||||
return S_FALSE;
|
||||
const Byte *p = base + pos;
|
||||
UInt64 length = Get64(p);
|
||||
if (length == 0)
|
||||
const CItem &item = Items[index];
|
||||
index = item.Parent;
|
||||
if (index >= 0 || !SkipRoot)
|
||||
size += item.Name.Length() + newLevel;
|
||||
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;
|
||||
if (pos + 102 > size || pos + length + 8 > size || length > ((UInt64)1 << 62))
|
||||
if (Get16(p + size) != 0)
|
||||
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;
|
||||
item.Attrib = Get32(p + 8);
|
||||
// item.SecurityId = Get32(p + 0xC);
|
||||
UInt64 subdirOffset = Get64(p + 0x10);
|
||||
GetFileTimeFromMem(p + 0x28, &item.CTime);
|
||||
GetFileTimeFromMem(p + 0x30, &item.ATime);
|
||||
GetFileTimeFromMem(p + 0x38, &item.MTime);
|
||||
UInt32 timeOffset = IsOldVersion ? 0x18: 0x28;
|
||||
GetFileTimeFromMem(p + timeOffset, &item.CTime);
|
||||
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);
|
||||
}
|
||||
// UInt32 numStreams = Get16(p + dirRecordSize - 6);
|
||||
UInt32 shortNameLen = Get16(p + dirRecordSize - 4);
|
||||
UInt32 fileNameLen = Get16(p + dirRecordSize - 2);
|
||||
|
||||
// UInt16 shortNameLen = Get16(p + 98);
|
||||
UInt16 fileNameLen = Get16(p + 100);
|
||||
|
||||
size_t tempPos = pos + 102;
|
||||
if (tempPos + fileNameLen > size)
|
||||
if ((shortNameLen & 1) != 0 || (fileNameLen & 1) != 0)
|
||||
return S_FALSE;
|
||||
|
||||
wchar_t *sz = item.Name.GetBuffer(prefix.Length() + fileNameLen / 2 + 1);
|
||||
MyStringCopy(sz, (const wchar_t *)prefix);
|
||||
sz += prefix.Length();
|
||||
for (UInt16 i = 0; i + 2 <= fileNameLen; i += 2)
|
||||
*sz++ = Get16(base + tempPos + i);
|
||||
*sz++ = '\0';
|
||||
item.Name.ReleaseBuffer();
|
||||
if (fileNameLen == 0 && item.isDir() && !item.HasStream())
|
||||
UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2);
|
||||
UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2);
|
||||
|
||||
if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) > len)
|
||||
return S_FALSE;
|
||||
p += dirRecordSize;
|
||||
|
||||
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.Name.Delete(item.Name.Length() - 1);
|
||||
}
|
||||
items.Add(item);
|
||||
pos += (size_t)length;
|
||||
if (item.isDir() && (subdirOffset != 0))
|
||||
|
||||
item.Parent = parent;
|
||||
prevIndex = Items.Add(item);
|
||||
if (item.IsDir() && subdirOffset != 0)
|
||||
{
|
||||
if (subdirOffset >= size)
|
||||
return S_FALSE;
|
||||
RINOK(ParseDirItem(base, (size_t)subdirOffset, size, item.Name + WCHAR_PATH_SEPARATOR, items));
|
||||
RINOK(ParseDirItem((size_t)subdirOffset, prevIndex));
|
||||
}
|
||||
Items[prevIndex].Order = Order++;
|
||||
pos += (size_t)len;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT ParseDir(const Byte *base, size_t size,
|
||||
const UString &prefix, CObjectVector<CItem> &items)
|
||||
HRESULT CDatabase::ParseImageDirs(const CByteBuffer &buf, int parent)
|
||||
{
|
||||
DirData = buf;
|
||||
DirSize = buf.GetCapacity();
|
||||
|
||||
size_t pos = 0;
|
||||
if (pos + 8 > size)
|
||||
if (DirSize < 8)
|
||||
return S_FALSE;
|
||||
const Byte *p = base + pos;
|
||||
const Byte *p = DirData;
|
||||
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);
|
||||
pos += 8;
|
||||
{
|
||||
@@ -346,29 +560,162 @@ static HRESULT ParseDir(const Byte *base, size_t size,
|
||||
UInt64 sum = 0;
|
||||
for (UInt32 i = 0; i < numEntries; i++)
|
||||
{
|
||||
if (pos + 8 > size)
|
||||
if (pos + 8 > DirSize)
|
||||
return S_FALSE;
|
||||
UInt64 len = Get64(p + pos);
|
||||
entryLens.Add(len);
|
||||
sum += len;
|
||||
pos += 8;
|
||||
}
|
||||
pos += sum; // skip security descriptors
|
||||
pos += (size_t)sum; // skip security descriptors
|
||||
while ((pos & 7) != 0)
|
||||
pos++;
|
||||
if (pos != totalLength)
|
||||
return S_FALSE;
|
||||
*/
|
||||
if (totalLength == 0)
|
||||
pos = 8;
|
||||
else if (totalLength < 8)
|
||||
return S_FALSE;
|
||||
else
|
||||
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;
|
||||
return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize);
|
||||
UInt32 headerSize = Get32(p + 8);
|
||||
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 */)
|
||||
{
|
||||
@@ -378,24 +725,39 @@ static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, voi
|
||||
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 CItem &i2 = **((const CItem **)a2);
|
||||
const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param;
|
||||
return MyCompare(streams[*p1].Id, streams[*p2].Id);
|
||||
}
|
||||
|
||||
if (i1.isDir() != i2.isDir())
|
||||
return (i1.isDir()) ? 1 : -1;
|
||||
if (i1.isDir())
|
||||
return -MyStringCompareNoCase(i1.Name, i2.Name);
|
||||
static int CompareHashRefs(const int *p1, const int *p2, void *param)
|
||||
{
|
||||
const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param;
|
||||
return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize);
|
||||
}
|
||||
|
||||
int res = MyCompare(i1.StreamIndex, i2.StreamIndex);
|
||||
if (res != 0)
|
||||
return res;
|
||||
return MyStringCompareNoCase(i1.Name, i2.Name);
|
||||
static int FindId(const CRecordVector<CStreamInfo> &streams,
|
||||
const CIntVector &sortedByHash, UInt32 id)
|
||||
{
|
||||
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,
|
||||
const CRecordVector<int> &sortedByHash, const Byte *hash)
|
||||
const CIntVector &sortedByHash, const Byte *hash)
|
||||
{
|
||||
int left = 0, right = streams.Size();
|
||||
while (left != right)
|
||||
@@ -417,153 +779,76 @@ static int FindHash(const CRecordVector<CStreamInfo> &streams,
|
||||
return -1;
|
||||
}
|
||||
|
||||
HRESULT CHeader::Parse(const Byte *p)
|
||||
static int CompareItems(const int *a1, const int *a2, void *param)
|
||||
{
|
||||
UInt32 haderSize = Get32(p + 8);
|
||||
if (haderSize < 0x74)
|
||||
return S_FALSE;
|
||||
Version = Get32(p + 0x0C);
|
||||
Flags = Get32(p + 0x10);
|
||||
if (!IsSupported())
|
||||
return S_FALSE;
|
||||
UInt32 chunkSize = Get32(p + 0x14);
|
||||
if (chunkSize != kChunkSize && chunkSize != 0)
|
||||
return S_FALSE;
|
||||
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;
|
||||
const CObjectVector<CItem> &items = ((CDatabase *)param)->Items;
|
||||
const CItem &i1 = items[*a1];
|
||||
const CItem &i2 = items[*a2];
|
||||
|
||||
if (i1.IsDir() != i2.IsDir())
|
||||
return i1.IsDir() ? 1 : -1;
|
||||
int res = MyCompare(i1.StreamIndex, i2.StreamIndex);
|
||||
if (res != 0)
|
||||
return res;
|
||||
return MyCompare(i1.Order, i2.Order);
|
||||
}
|
||||
|
||||
HRESULT ReadHeader(IInStream *inStream, CHeader &h)
|
||||
HRESULT CDatabase::Sort(bool skipRootDir)
|
||||
{
|
||||
const UInt32 kHeaderSizeMax = 0xD0;
|
||||
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);
|
||||
Streams.Sort(CompareStreamsByPos, NULL);
|
||||
|
||||
{
|
||||
CRecordVector<int> sortedByHash;
|
||||
CIntVector sortedByHash;
|
||||
{
|
||||
for (int j = 0; j < db.Streams.Size(); j++)
|
||||
sortedByHash.Add(j);
|
||||
sortedByHash.Sort(CompareHashRefs, &db.Streams);
|
||||
for (int i = 0; i < Streams.Size(); i++)
|
||||
sortedByHash.Add(i);
|
||||
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;
|
||||
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;
|
||||
int j;
|
||||
for (j = 0; j < db.Streams.Size(); j++)
|
||||
int i;
|
||||
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(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)
|
||||
used[item.StreamIndex] = true;
|
||||
}
|
||||
for (j = 0; j < db.Streams.Size(); j++)
|
||||
if (!used[j])
|
||||
for (i = 0; i < Streams.Size(); i++)
|
||||
if (!used[i])
|
||||
{
|
||||
CItem item;
|
||||
item.StreamIndex = j;
|
||||
item.StreamIndex = i;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
#include "../../Compress/LzxDecoder.h"
|
||||
|
||||
#include "../IArchive.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NWim {
|
||||
|
||||
@@ -56,7 +58,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
const int kNumHuffmanBits = 16;
|
||||
const unsigned kNumHuffmanBits = 16;
|
||||
const UInt32 kMatchMinLen = 3;
|
||||
const UInt32 kNumLenSlots = 16;
|
||||
const UInt32 kNumPosSlots = 16;
|
||||
@@ -85,8 +87,10 @@ public:
|
||||
|
||||
namespace NResourceFlags
|
||||
{
|
||||
const Byte Compressed = 4;
|
||||
const Byte kFree = 1;
|
||||
const Byte kMetadata = 2;
|
||||
const Byte Compressed = 4;
|
||||
const Byte Spanned = 4;
|
||||
}
|
||||
|
||||
struct CResource
|
||||
@@ -96,9 +100,18 @@ struct CResource
|
||||
UInt64 UnpackSize;
|
||||
Byte Flags;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
PackSize = 0;
|
||||
Offset = 0;
|
||||
UnpackSize = 0;
|
||||
Flags = 0;
|
||||
}
|
||||
void Parse(const Byte *p);
|
||||
bool IsCompressed() const { return (Flags & NResourceFlags::Compressed) != 0; }
|
||||
void WriteTo(Byte *p) const;
|
||||
bool IsFree() const { return (Flags & NResourceFlags::kFree) != 0; }
|
||||
bool IsMetadata() const { return (Flags & NResourceFlags::kMetadata) != 0; }
|
||||
bool IsCompressed() const { return (Flags & NResourceFlags::Compressed) != 0; }
|
||||
bool IsEmpty() const { return (UnpackSize == 0); }
|
||||
};
|
||||
|
||||
@@ -111,30 +124,38 @@ namespace NHeaderFlags
|
||||
const UInt32 kLZX = 0x40000;
|
||||
}
|
||||
|
||||
const UInt32 kWimVersion = 0x010D00;
|
||||
const UInt32 kHeaderSizeMax = 0xD0;
|
||||
const UInt32 kSignatureSize = 8;
|
||||
extern const Byte kSignature[kSignatureSize];
|
||||
const unsigned kChunkSizeBits = 15;
|
||||
const UInt32 kChunkSize = (1 << kChunkSizeBits);
|
||||
|
||||
struct CHeader
|
||||
{
|
||||
UInt32 Flags;
|
||||
UInt32 Version;
|
||||
// UInt32 ChunkSize;
|
||||
UInt32 Flags;
|
||||
UInt32 ChunkSize;
|
||||
Byte Guid[16];
|
||||
UInt16 PartNumber;
|
||||
UInt16 NumParts;
|
||||
UInt32 NumImages;
|
||||
Byte Guid[16];
|
||||
|
||||
CResource OffsetResource;
|
||||
CResource XmlResource;
|
||||
CResource MetadataResource;
|
||||
/*
|
||||
CResource IntegrityResource;
|
||||
UInt32 BootIndex;
|
||||
*/
|
||||
|
||||
void SetDefaultFields(bool useLZX);
|
||||
|
||||
void WriteTo(Byte *p) const;
|
||||
HRESULT Parse(const Byte *p);
|
||||
bool IsCompressed() const { return (Flags & NHeaderFlags::kCompression) != 0; }
|
||||
bool IsSupported() const { return (!IsCompressed() || (Flags & NHeaderFlags::kLZX) != 0 || (Flags & NHeaderFlags::kXPRESS) != 0 ) ; }
|
||||
bool IsLzxMode() const { return (Flags & NHeaderFlags::kLZX) != 0; }
|
||||
bool IsSpanned() const { return (!IsCompressed() || (Flags & NHeaderFlags::kSpanned) != 0); }
|
||||
|
||||
bool IsOldVersion() const { return (Version <= 0x010A00); }
|
||||
bool IsNewVersion() const { return (Version > 0x010C00); }
|
||||
|
||||
bool AreFromOnArchive(const CHeader &h)
|
||||
@@ -151,39 +172,65 @@ struct CStreamInfo
|
||||
CResource Resource;
|
||||
UInt16 PartNumber;
|
||||
UInt32 RefCount;
|
||||
UInt32 Id;
|
||||
BYTE Hash[kHashSize];
|
||||
|
||||
void WriteTo(Byte *p) const;
|
||||
};
|
||||
|
||||
const UInt32 kDirRecordSizeOld = 62;
|
||||
const UInt32 kDirRecordSize = 102;
|
||||
|
||||
struct CItem
|
||||
{
|
||||
UString Name;
|
||||
UString ShortName;
|
||||
UInt32 Attrib;
|
||||
// UInt32 SecurityId;
|
||||
BYTE Hash[kHashSize];
|
||||
UInt32 Id;
|
||||
FILETIME CTime;
|
||||
FILETIME ATime;
|
||||
FILETIME MTime;
|
||||
// UInt32 ReparseTag;
|
||||
// UInt64 HardLink;
|
||||
// UInt16 NumStreams;
|
||||
// UInt16 ShortNameLen;
|
||||
int StreamIndex;
|
||||
int Parent;
|
||||
unsigned Order;
|
||||
bool HasMetadata;
|
||||
CItem(): HasMetadata(true), StreamIndex(-1) {}
|
||||
bool isDir() const { return HasMetadata && ((Attrib & 0x10) != 0); }
|
||||
CItem(): HasMetadata(true), StreamIndex(-1), Id(0) {}
|
||||
bool IsDir() const { return HasMetadata && ((Attrib & 0x10) != 0); }
|
||||
bool HasStream() const
|
||||
{
|
||||
for (int i = 0; i < kHashSize; i++)
|
||||
for (unsigned i = 0; i < kHashSize; i++)
|
||||
if (Hash[i] != 0)
|
||||
return true;
|
||||
return false;
|
||||
return Id != 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct CDatabase
|
||||
class CDatabase
|
||||
{
|
||||
const Byte *DirData;
|
||||
size_t DirSize;
|
||||
size_t DirProcessed;
|
||||
size_t DirStartOffset;
|
||||
int Order;
|
||||
IArchiveOpenCallback *OpenCallback;
|
||||
|
||||
HRESULT ParseDirItem(size_t pos, int parent);
|
||||
HRESULT ParseImageDirs(const CByteBuffer &buf, int parent);
|
||||
|
||||
public:
|
||||
CRecordVector<CStreamInfo> Streams;
|
||||
CObjectVector<CItem> Items;
|
||||
CIntVector SortedItems;
|
||||
int NumImages;
|
||||
bool SkipRoot;
|
||||
bool ShowImageNumber;
|
||||
|
||||
bool IsOldVersion;
|
||||
|
||||
UInt64 GetUnpackSize() const
|
||||
{
|
||||
@@ -205,12 +252,27 @@ struct CDatabase
|
||||
{
|
||||
Streams.Clear();
|
||||
Items.Clear();
|
||||
SortedItems.Clear();
|
||||
NumImages = 0;
|
||||
|
||||
SkipRoot = true;
|
||||
ShowImageNumber = true;
|
||||
IsOldVersion = false;
|
||||
}
|
||||
|
||||
UString GetItemPath(int index) const;
|
||||
|
||||
HRESULT Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback);
|
||||
|
||||
void DetectPathMode()
|
||||
{
|
||||
ShowImageNumber = (NumImages != 1);
|
||||
}
|
||||
|
||||
HRESULT Sort(bool skipRootDir);
|
||||
};
|
||||
|
||||
HRESULT ReadHeader(IInStream *inStream, CHeader &header);
|
||||
HRESULT OpenArchive(IInStream *inStream, const CHeader &header, CByteBuffer &xml, CDatabase &database);
|
||||
HRESULT SortDatabase(CDatabase &database);
|
||||
|
||||
class CUnpacker
|
||||
{
|
||||
|
||||
@@ -6,8 +6,13 @@
|
||||
|
||||
#include "WimHandler.h"
|
||||
static IInArchive *CreateArc() { return new NArchive::NWim::CHandler; }
|
||||
#ifndef EXTRACT_ONLY
|
||||
static IOutArchive *CreateArcOut() { return new NArchive::NWim::COutHandler; }
|
||||
#else
|
||||
#define CreateArcOut 0
|
||||
#endif
|
||||
|
||||
static CArcInfo g_ArcInfo =
|
||||
{ L"Wim", L"wim swm", 0, 0xE6, { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }, 8, false, CreateArc, 0 };
|
||||
{ L"wim", L"wim swm", 0, 0xE6, { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }, 8, false, CreateArc, CreateArcOut };
|
||||
|
||||
REGISTER_ARC(Wim)
|
||||
|
||||
@@ -268,7 +268,7 @@ HRESULT CHandler::Open2(IInStream *stream)
|
||||
inStreamLimSpec->SetStream(stream);
|
||||
inStreamLimSpec->Init(packSize);
|
||||
|
||||
CSequentialOutStreamImp2 *outStreamLimSpec = new CSequentialOutStreamImp2;
|
||||
CBufPtrSeqOutStream *outStreamLimSpec = new CBufPtrSeqOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStreamLim(outStreamLimSpec);
|
||||
outStreamLimSpec->Init((Byte *)ss, (size_t)unpackSize);
|
||||
|
||||
|
||||
@@ -53,18 +53,17 @@ HRESULT CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIAN
|
||||
EncoderSpec = new NCompress::NLzma::CEncoder;
|
||||
Encoder = EncoderSpec;
|
||||
}
|
||||
CSequentialOutStreamImp *outStreamSpec = new CSequentialOutStreamImp;
|
||||
CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
outStreamSpec->Init();
|
||||
outStreamSpec->Init(Header + 4, kLzmaPropsSize);
|
||||
RINOK(EncoderSpec->SetCoderProperties(propIDs, props, numProps));
|
||||
RINOK(EncoderSpec->WriteCoderProperties(outStream));
|
||||
if (outStreamSpec->GetSize() != kLzmaPropsSize)
|
||||
if (outStreamSpec->GetPos() != kLzmaPropsSize)
|
||||
return E_FAIL;
|
||||
Header[0] = MY_VER_MAJOR;
|
||||
Header[1] = MY_VER_MINOR;
|
||||
Header[2] = kLzmaPropsSize;
|
||||
Header[3] = 0;
|
||||
memcpy(Header + 4, outStreamSpec->GetBuffer(), kLzmaPropsSize);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -146,6 +145,7 @@ HRESULT CAddCommon::Compress(
|
||||
opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default;
|
||||
if (inCrcStreamSpec != 0)
|
||||
RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
RINOK(outStream->SetSize(0));
|
||||
RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
if (_options.PasswordIsDefined)
|
||||
{
|
||||
@@ -218,7 +218,7 @@ HRESULT CAddCommon::Compress(
|
||||
_options.Algo,
|
||||
_options.DicSize,
|
||||
_options.NumFastBytes,
|
||||
(BSTR)(const wchar_t *)_options.MatchFinder,
|
||||
const_cast<BSTR>((const wchar_t *)_options.MatchFinder),
|
||||
_options.NumMatchFinderCycles
|
||||
};
|
||||
PROPID propIDs[] =
|
||||
@@ -373,7 +373,7 @@ HRESULT CAddCommon::Compress(
|
||||
RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize));
|
||||
}
|
||||
opRes.Method = method;
|
||||
return outStream->SetSize(opRes.PackSize);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -70,8 +70,8 @@ static const char *kMethods[] =
|
||||
"Shrink",
|
||||
"Reduced1",
|
||||
"Reduced2",
|
||||
"Reduced2",
|
||||
"Reduced3",
|
||||
"Reduced4",
|
||||
"Implode",
|
||||
"Tokenizing",
|
||||
"Deflate",
|
||||
|
||||
@@ -63,8 +63,8 @@ private:
|
||||
Byte m_AesKeyMode;
|
||||
|
||||
bool m_WriteNtfsTimeExtra;
|
||||
bool m_ForseLocal;
|
||||
bool m_ForseUtf8;
|
||||
bool m_ForceLocal;
|
||||
bool m_ForceUtf8;
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
UInt32 _numThreads;
|
||||
@@ -88,8 +88,8 @@ private:
|
||||
m_IsAesMode = false;
|
||||
m_AesKeyMode = 3; // aes-256
|
||||
m_WriteNtfsTimeExtra = true;
|
||||
m_ForseLocal = false;
|
||||
m_ForseUtf8 = false;
|
||||
m_ForceLocal = false;
|
||||
m_ForceUtf8 = false;
|
||||
#ifndef _7ZIP_ST
|
||||
_numThreads = NWindows::NSystem::GetNumberOfProcessors();;
|
||||
#endif
|
||||
|
||||
@@ -189,11 +189,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
name += kSlash;
|
||||
|
||||
bool tryUtf8 = true;
|
||||
if (m_ForseLocal || !m_ForseUtf8)
|
||||
if (m_ForceLocal || !m_ForceUtf8)
|
||||
{
|
||||
bool defaultCharWasUsed;
|
||||
ui.Name = UnicodeStringToMultiByte(name, CP_OEMCP, '_', defaultCharWasUsed);
|
||||
tryUtf8 = (!m_ForseLocal && (defaultCharWasUsed ||
|
||||
tryUtf8 = (!m_ForceLocal && (defaultCharWasUsed ||
|
||||
MultiByteToUnicodeString(ui.Name, CP_OEMCP) != name));
|
||||
}
|
||||
|
||||
@@ -512,15 +512,15 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v
|
||||
}
|
||||
else if (name.CompareNoCase(L"CL") == 0)
|
||||
{
|
||||
RINOK(SetBoolProperty(m_ForseLocal, prop));
|
||||
if (m_ForseLocal)
|
||||
m_ForseUtf8 = false;
|
||||
RINOK(SetBoolProperty(m_ForceLocal, prop));
|
||||
if (m_ForceLocal)
|
||||
m_ForceUtf8 = false;
|
||||
}
|
||||
else if (name.CompareNoCase(L"CU") == 0)
|
||||
{
|
||||
RINOK(SetBoolProperty(m_ForseUtf8, prop));
|
||||
if (m_ForseUtf8)
|
||||
m_ForseLocal = false;
|
||||
RINOK(SetBoolProperty(m_ForceUtf8, prop));
|
||||
if (m_ForceUtf8)
|
||||
m_ForceLocal = false;
|
||||
}
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user