342 lines
9.1 KiB
C
342 lines
9.1 KiB
C
|
/* 7zDecode.c */
|
||
|
|
||
|
#include <memory.h>
|
||
|
|
||
|
#include "7zDecode.h"
|
||
|
#ifdef _SZ_ONE_DIRECTORY
|
||
|
#include "LzmaDecode.h"
|
||
|
#else
|
||
|
#include "../../Compress/Lzma/LzmaDecode.h"
|
||
|
#include "../../Compress/Branch/BranchX86.h"
|
||
|
#include "../../Compress/Branch/BranchX86_2.h"
|
||
|
#endif
|
||
|
|
||
|
#define k_Copy 0
|
||
|
#define k_LZMA 0x30101
|
||
|
#define k_BCJ 0x03030103
|
||
|
#define k_BCJ2 0x0303011B
|
||
|
|
||
|
#ifdef _LZMA_IN_CB
|
||
|
|
||
|
typedef struct _CLzmaInCallbackImp
|
||
|
{
|
||
|
ILzmaInCallback InCallback;
|
||
|
ISzInStream *InStream;
|
||
|
CFileSize Size;
|
||
|
} CLzmaInCallbackImp;
|
||
|
|
||
|
int LzmaReadImp(void *object, const unsigned char **buffer, SizeT *size)
|
||
|
{
|
||
|
CLzmaInCallbackImp *cb = (CLzmaInCallbackImp *)object;
|
||
|
size_t processedSize;
|
||
|
SZ_RESULT res;
|
||
|
size_t curSize = (1 << 20);
|
||
|
if (curSize > cb->Size)
|
||
|
curSize = (size_t)cb->Size;
|
||
|
*size = 0;
|
||
|
res = cb->InStream->Read((void *)cb->InStream, (void **)buffer, curSize, &processedSize);
|
||
|
*size = (SizeT)processedSize;
|
||
|
if (processedSize > curSize)
|
||
|
return (int)SZE_FAIL;
|
||
|
cb->Size -= processedSize;
|
||
|
if (res == SZ_OK)
|
||
|
return 0;
|
||
|
return (int)res;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
SZ_RESULT SzDecodeLzma(CCoderInfo *coder, CFileSize inSize,
|
||
|
#ifdef _LZMA_IN_CB
|
||
|
ISzInStream *inStream,
|
||
|
#else
|
||
|
const Byte *inBuffer,
|
||
|
#endif
|
||
|
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
|
||
|
{
|
||
|
#ifdef _LZMA_IN_CB
|
||
|
CLzmaInCallbackImp lzmaCallback;
|
||
|
#else
|
||
|
SizeT inProcessed;
|
||
|
#endif
|
||
|
|
||
|
CLzmaDecoderState state; /* it's about 24-80 bytes structure, if int is 32-bit */
|
||
|
int result;
|
||
|
SizeT outSizeProcessedLoc;
|
||
|
|
||
|
#ifdef _LZMA_IN_CB
|
||
|
lzmaCallback.Size = inSize;
|
||
|
lzmaCallback.InStream = inStream;
|
||
|
lzmaCallback.InCallback.Read = LzmaReadImp;
|
||
|
#endif
|
||
|
|
||
|
if (LzmaDecodeProperties(&state.Properties, coder->Properties.Items,
|
||
|
(unsigned)coder->Properties.Capacity) != LZMA_RESULT_OK)
|
||
|
return SZE_FAIL;
|
||
|
|
||
|
state.Probs = (CProb *)allocMain->Alloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
|
||
|
if (state.Probs == 0)
|
||
|
return SZE_OUTOFMEMORY;
|
||
|
|
||
|
#ifdef _LZMA_OUT_READ
|
||
|
if (state.Properties.DictionarySize == 0)
|
||
|
state.Dictionary = 0;
|
||
|
else
|
||
|
{
|
||
|
state.Dictionary = (unsigned char *)allocMain->Alloc(state.Properties.DictionarySize);
|
||
|
if (state.Dictionary == 0)
|
||
|
{
|
||
|
allocMain->Free(state.Probs);
|
||
|
return SZE_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
LzmaDecoderInit(&state);
|
||
|
#endif
|
||
|
|
||
|
result = LzmaDecode(&state,
|
||
|
#ifdef _LZMA_IN_CB
|
||
|
&lzmaCallback.InCallback,
|
||
|
#else
|
||
|
inBuffer, (SizeT)inSize, &inProcessed,
|
||
|
#endif
|
||
|
outBuffer, (SizeT)outSize, &outSizeProcessedLoc);
|
||
|
allocMain->Free(state.Probs);
|
||
|
#ifdef _LZMA_OUT_READ
|
||
|
allocMain->Free(state.Dictionary);
|
||
|
#endif
|
||
|
if (result == LZMA_RESULT_DATA_ERROR)
|
||
|
return SZE_DATA_ERROR;
|
||
|
if (result != LZMA_RESULT_OK)
|
||
|
return SZE_FAIL;
|
||
|
return (outSizeProcessedLoc == outSize) ? SZ_OK : SZE_DATA_ERROR;
|
||
|
}
|
||
|
|
||
|
#ifdef _LZMA_IN_CB
|
||
|
SZ_RESULT SzDecodeCopy(CFileSize inSize, ISzInStream *inStream, Byte *outBuffer)
|
||
|
{
|
||
|
while (inSize > 0)
|
||
|
{
|
||
|
void *inBuffer;
|
||
|
size_t processedSize, curSize = (1 << 18);
|
||
|
if (curSize > inSize)
|
||
|
curSize = (size_t)(inSize);
|
||
|
RINOK(inStream->Read((void *)inStream, (void **)&inBuffer, curSize, &processedSize));
|
||
|
if (processedSize == 0)
|
||
|
return SZE_DATA_ERROR;
|
||
|
if (processedSize > curSize)
|
||
|
return SZE_FAIL;
|
||
|
memcpy(outBuffer, inBuffer, processedSize);
|
||
|
outBuffer += processedSize;
|
||
|
inSize -= processedSize;
|
||
|
}
|
||
|
return SZ_OK;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#define IS_UNSUPPORTED_METHOD(m) ((m) != k_Copy && (m) != k_LZMA)
|
||
|
#define IS_UNSUPPORTED_CODER(c) (IS_UNSUPPORTED_METHOD(c.MethodID) || c.NumInStreams != 1 || c.NumOutStreams != 1)
|
||
|
#define IS_NO_BCJ(c) (c.MethodID != k_BCJ || c.NumInStreams != 1 || c.NumOutStreams != 1)
|
||
|
#define IS_NO_BCJ2(c) (c.MethodID != k_BCJ2 || c.NumInStreams != 4 || c.NumOutStreams != 1)
|
||
|
|
||
|
SZ_RESULT CheckSupportedFolder(const CFolder *f)
|
||
|
{
|
||
|
if (f->NumCoders < 1 || f->NumCoders > 4)
|
||
|
return SZE_NOTIMPL;
|
||
|
if (IS_UNSUPPORTED_CODER(f->Coders[0]))
|
||
|
return SZE_NOTIMPL;
|
||
|
if (f->NumCoders == 1)
|
||
|
{
|
||
|
if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
|
||
|
return SZE_NOTIMPL;
|
||
|
return SZ_OK;
|
||
|
}
|
||
|
if (f->NumCoders == 2)
|
||
|
{
|
||
|
if (IS_NO_BCJ(f->Coders[1]) ||
|
||
|
f->NumPackStreams != 1 || f->PackStreams[0] != 0 ||
|
||
|
f->NumBindPairs != 1 ||
|
||
|
f->BindPairs[0].InIndex != 1 || f->BindPairs[0].OutIndex != 0)
|
||
|
return SZE_NOTIMPL;
|
||
|
return SZ_OK;
|
||
|
}
|
||
|
if (f->NumCoders == 4)
|
||
|
{
|
||
|
if (IS_UNSUPPORTED_CODER(f->Coders[1]) ||
|
||
|
IS_UNSUPPORTED_CODER(f->Coders[2]) ||
|
||
|
IS_NO_BCJ2(f->Coders[3]))
|
||
|
return SZE_NOTIMPL;
|
||
|
if (f->NumPackStreams != 4 ||
|
||
|
f->PackStreams[0] != 2 ||
|
||
|
f->PackStreams[1] != 6 ||
|
||
|
f->PackStreams[2] != 1 ||
|
||
|
f->PackStreams[3] != 0 ||
|
||
|
f->NumBindPairs != 3 ||
|
||
|
f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
|
||
|
f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
|
||
|
f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
|
||
|
return SZE_NOTIMPL;
|
||
|
return SZ_OK;
|
||
|
}
|
||
|
return SZE_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
CFileSize GetSum(const CFileSize *values, UInt32 index)
|
||
|
{
|
||
|
CFileSize sum = 0;
|
||
|
UInt32 i;
|
||
|
for (i = 0; i < index; i++)
|
||
|
sum += values[i];
|
||
|
return sum;
|
||
|
}
|
||
|
|
||
|
SZ_RESULT SzDecode2(const CFileSize *packSizes, const CFolder *folder,
|
||
|
#ifdef _LZMA_IN_CB
|
||
|
ISzInStream *inStream, CFileSize startPos,
|
||
|
#else
|
||
|
const Byte *inBuffer,
|
||
|
#endif
|
||
|
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain,
|
||
|
Byte *tempBuf[])
|
||
|
{
|
||
|
UInt32 ci;
|
||
|
size_t tempSizes[3] = { 0, 0, 0};
|
||
|
size_t tempSize3 = 0;
|
||
|
Byte *tempBuf3 = 0;
|
||
|
|
||
|
RINOK(CheckSupportedFolder(folder));
|
||
|
|
||
|
for (ci = 0; ci < folder->NumCoders; ci++)
|
||
|
{
|
||
|
CCoderInfo *coder = &folder->Coders[ci];
|
||
|
|
||
|
if (coder->MethodID == k_Copy || coder->MethodID == k_LZMA)
|
||
|
{
|
||
|
UInt32 si = 0;
|
||
|
CFileSize offset;
|
||
|
CFileSize inSize;
|
||
|
Byte *outBufCur = outBuffer;
|
||
|
size_t outSizeCur = outSize;
|
||
|
if (folder->NumCoders == 4)
|
||
|
{
|
||
|
UInt32 indices[] = { 3, 2, 0 };
|
||
|
CFileSize unpackSize = folder->UnPackSizes[ci];
|
||
|
si = indices[ci];
|
||
|
if (ci < 2)
|
||
|
{
|
||
|
Byte *temp;
|
||
|
outSizeCur = (size_t)unpackSize;
|
||
|
if (outSizeCur != unpackSize)
|
||
|
return SZE_OUTOFMEMORY;
|
||
|
temp = (Byte *)allocMain->Alloc(outSizeCur);
|
||
|
if (temp == 0 && outSizeCur != 0)
|
||
|
return SZE_OUTOFMEMORY;
|
||
|
outBufCur = tempBuf[1 - ci] = temp;
|
||
|
tempSizes[1 - ci] = outSizeCur;
|
||
|
}
|
||
|
else if (ci == 2)
|
||
|
{
|
||
|
if (unpackSize > outSize)
|
||
|
return SZE_OUTOFMEMORY;
|
||
|
tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
|
||
|
tempSize3 = outSizeCur = (size_t)unpackSize;
|
||
|
}
|
||
|
else
|
||
|
return SZE_NOTIMPL;
|
||
|
}
|
||
|
offset = GetSum(packSizes, si);
|
||
|
inSize = packSizes[si];
|
||
|
#ifdef _LZMA_IN_CB
|
||
|
RINOK(inStream->Seek(inStream, startPos + offset));
|
||
|
#endif
|
||
|
|
||
|
if (coder->MethodID == k_Copy)
|
||
|
{
|
||
|
if (inSize != outSizeCur)
|
||
|
return SZE_DATA_ERROR;
|
||
|
|
||
|
#ifdef _LZMA_IN_CB
|
||
|
RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
|
||
|
#else
|
||
|
memcpy(outBufCur, inBuffer + (size_t)offset, (size_t)inSize);
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SZ_RESULT res = SzDecodeLzma(coder, inSize,
|
||
|
#ifdef _LZMA_IN_CB
|
||
|
inStream,
|
||
|
#else
|
||
|
inBuffer + (size_t)offset,
|
||
|
#endif
|
||
|
outBufCur, outSizeCur, allocMain);
|
||
|
RINOK(res)
|
||
|
}
|
||
|
}
|
||
|
else if (coder->MethodID == k_BCJ)
|
||
|
{
|
||
|
UInt32 state;
|
||
|
if (ci != 1)
|
||
|
return SZE_NOTIMPL;
|
||
|
x86_Convert_Init(state);
|
||
|
x86_Convert(outBuffer, outSize, 0, &state, 0);
|
||
|
}
|
||
|
else if (coder->MethodID == k_BCJ2)
|
||
|
{
|
||
|
CFileSize offset = GetSum(packSizes, 1);
|
||
|
CFileSize s3Size = packSizes[1];
|
||
|
SZ_RESULT res;
|
||
|
if (ci != 3)
|
||
|
return SZE_NOTIMPL;
|
||
|
|
||
|
#ifdef _LZMA_IN_CB
|
||
|
RINOK(inStream->Seek(inStream, startPos + offset));
|
||
|
tempSizes[2] = (size_t)s3Size;
|
||
|
if (tempSizes[2] != s3Size)
|
||
|
return SZE_OUTOFMEMORY;
|
||
|
tempBuf[2] = (Byte *)allocMain->Alloc(tempSizes[2]);
|
||
|
if (tempBuf[2] == 0 && tempSizes[2] != 0)
|
||
|
return SZE_OUTOFMEMORY;
|
||
|
res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
|
||
|
RINOK(res)
|
||
|
#endif
|
||
|
|
||
|
res = x86_2_Decode(
|
||
|
tempBuf3, tempSize3,
|
||
|
tempBuf[0], tempSizes[0],
|
||
|
tempBuf[1], tempSizes[1],
|
||
|
#ifdef _LZMA_IN_CB
|
||
|
tempBuf[2], tempSizes[2],
|
||
|
#else
|
||
|
inBuffer + (size_t)offset, (size_t)s3Size,
|
||
|
#endif
|
||
|
outBuffer, outSize);
|
||
|
RINOK(res)
|
||
|
}
|
||
|
else
|
||
|
return SZE_NOTIMPL;
|
||
|
}
|
||
|
return SZ_OK;
|
||
|
}
|
||
|
|
||
|
SZ_RESULT SzDecode(const CFileSize *packSizes, const CFolder *folder,
|
||
|
#ifdef _LZMA_IN_CB
|
||
|
ISzInStream *inStream, CFileSize startPos,
|
||
|
#else
|
||
|
const Byte *inBuffer,
|
||
|
#endif
|
||
|
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
|
||
|
{
|
||
|
Byte *tempBuf[3] = { 0, 0, 0};
|
||
|
int i;
|
||
|
SZ_RESULT res = SzDecode2(packSizes, folder,
|
||
|
#ifdef _LZMA_IN_CB
|
||
|
inStream, startPos,
|
||
|
#else
|
||
|
inBuffer,
|
||
|
#endif
|
||
|
outBuffer, outSize, allocMain, tempBuf);
|
||
|
for (i = 0; i < 3; i++)
|
||
|
allocMain->Free(tempBuf[i]);
|
||
|
return res;
|
||
|
}
|