Files
easy7zip/C/Archive/7z/7zDecode.c
Igor Pavlov 3901bf0ab8 4.58 beta
2016-05-28 00:15:55 +01:00

340 lines
8.7 KiB
C
Executable File

/* 7zDecode.c Decoding from 7z folder
2008-04-09
Igor Pavlov
Copyright (c) 1999-2008 Igor Pavlov
Read 7zDecode.h for license options */
#include <string.h>
#include "7zDecode.h"
#include "../../LzmaDec.h"
#include "../../Bra.h"
#include "../../Bcj2.h"
#define k_Copy 0
#define k_LZMA 0x30101
#define k_BCJ 0x03030103
#define k_BCJ2 0x0303011B
/*
#ifdef _LZMA_IN_CB
*/
static SRes SzDecodeLzma(CSzCoderInfo *coder, CFileSize inSize, ISzInStream *inStream,
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
{
CLzmaDec state;
int res = SZ_OK;
size_t _inSize;
Byte *inBuf = NULL;
LzmaDec_Construct(&state);
RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain));
state.dic = outBuffer;
state.dicBufSize = outSize;
LzmaDec_Init(&state);
_inSize = 0;
for (;;)
{
if (_inSize == 0)
{
_inSize = (1 << 18);
if (_inSize > inSize)
_inSize = (size_t)(inSize);
res = inStream->Read((void *)inStream, (void **)&inBuf, &_inSize);
if (res != SZ_OK)
break;
inSize -= _inSize;
}
{
SizeT inProcessed = _inSize, dicPos = state.dicPos;
ELzmaStatus status;
res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
_inSize -= inProcessed;
inBuf = (Byte *)inBuf + inProcessed;
if (res != SZ_OK)
break;
if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
{
if (state.dicBufSize != outSize || _inSize != 0 ||
(status != LZMA_STATUS_FINISHED_WITH_MARK &&
status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
res = SZ_ERROR_DATA;
break;
}
}
}
LzmaDec_FreeProbs(&state, allocMain);
return res;
}
static SRes SzDecodeCopy(CFileSize inSize, ISzInStream *inStream, Byte *outBuffer)
{
while (inSize > 0)
{
void *inBuffer;
size_t curSize = (1 << 18);
if (curSize > inSize)
curSize = (size_t)(inSize);
RINOK(inStream->Read((void *)inStream, (void **)&inBuffer, &curSize));
if (curSize == 0)
return SZ_ERROR_INPUT_EOF;
memcpy(outBuffer, inBuffer, curSize);
outBuffer += curSize;
inSize -= curSize;
}
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)
SRes CheckSupportedFolder(const CSzFolder *f)
{
if (f->NumCoders < 1 || f->NumCoders > 4)
return SZ_ERROR_UNSUPPORTED;
if (IS_UNSUPPORTED_CODER(f->Coders[0]))
return SZ_ERROR_UNSUPPORTED;
if (f->NumCoders == 1)
{
if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
return SZ_ERROR_UNSUPPORTED;
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 SZ_ERROR_UNSUPPORTED;
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 SZ_ERROR_UNSUPPORTED;
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 SZ_ERROR_UNSUPPORTED;
return SZ_OK;
}
return SZ_ERROR_UNSUPPORTED;
}
CFileSize GetSum(const CFileSize *values, UInt32 index)
{
CFileSize sum = 0;
UInt32 i;
for (i = 0; i < index; i++)
sum += values[i];
return sum;
}
SRes SzDecode2(const CFileSize *packSizes, const CSzFolder *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++)
{
CSzCoderInfo *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 SZ_ERROR_MEM;
temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
if (temp == 0 && outSizeCur != 0)
return SZ_ERROR_MEM;
outBufCur = tempBuf[1 - ci] = temp;
tempSizes[1 - ci] = outSizeCur;
}
else if (ci == 2)
{
if (unpackSize > outSize) // check it
return SZ_ERROR_PARAM; // check it
tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
tempSize3 = outSizeCur = (size_t)unpackSize;
}
else
return SZ_ERROR_UNSUPPORTED;
}
offset = GetSum(packSizes, si);
inSize = packSizes[si];
/*
#ifdef _LZMA_IN_CB
*/
RINOK(inStream->Seek(inStream, startPos + offset, SZ_SEEK_SET));
/*
#endif
*/
if (coder->MethodID == k_Copy)
{
if (inSize != outSizeCur) // check it
return SZ_ERROR_DATA;
/*
#ifdef _LZMA_IN_CB
*/
RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
/*
#else
memcpy(outBufCur, inBuffer + (size_t)offset, (size_t)inSize);
#endif
*/
}
else
{
/*
#ifdef _LZMA_IN_CB
*/
SRes res = SzDecodeLzma(coder, inSize,
inStream,
outBufCur, outSizeCur, allocMain);
/*
#else
SizeT lzmaOutSizeT = outSizeCur;
SizeT lzmaInSizeT = (SizeT)inSize;
SRes res = LzmaDecode(outBufCur, &lzmaOutSizeT,
inBuffer + (size_t)offset, &lzmaInSizeT,
coder->Props.Items, (unsigned)coder->Props.size, LZMA_FINISH_BYTE, allocMain);
#endif
*/
RINOK(res);
}
}
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)
{
CFileSize offset = GetSum(packSizes, 1);
CFileSize s3Size = packSizes[1];
SRes res;
if (ci != 3)
return SZ_ERROR_UNSUPPORTED;
/*
#ifdef _LZMA_IN_CB
*/
RINOK(inStream->Seek(inStream, startPos + offset, SZ_SEEK_SET));
tempSizes[2] = (size_t)s3Size;
if (tempSizes[2] != s3Size)
return SZ_ERROR_MEM;
tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
if (tempBuf[2] == 0 && tempSizes[2] != 0)
return SZ_ERROR_MEM;
res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
RINOK(res)
/*
#endif
*/
res = Bcj2_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 SZ_ERROR_UNSUPPORTED;
}
return SZ_OK;
}
SRes SzDecode(const CFileSize *packSizes, const CSzFolder *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;
SRes res = SzDecode2(packSizes, folder,
/*
#ifdef _LZMA_IN_CB
*/
inStream, startPos,
/*
#else
inBuffer,
#endif
*/
outBuffer, outSize, allocMain, tempBuf);
for (i = 0; i < 3; i++)
IAlloc_Free(allocMain, tempBuf[i]);
return res;
}