Source code

Revision control

Copy as Markdown

Other Tools

/* 7zDec.c -- Decoding from 7z folder↩
2017-04-03 : Igor Pavlov : Public domain */
#include "Precomp.h"
#include <string.h>↩
/* #define _7ZIP_PPMD_SUPPPORT */
#include "7z.h"
#include "7zCrc.h"
#include "Bcj2.h"
#include "Bra.h"
#include "CpuArch.h"
#include "Delta.h"
#include "LzmaDec.h"
#include "Lzma2Dec.h"
#ifdef _7ZIP_PPMD_SUPPPORT↩
#include "Ppmd7.h"
#endif
#define k_Copy 0↩
#define k_Delta 3↩
#define k_LZMA2 0x21↩
#define k_LZMA 0x30101↩
#define k_BCJ 0x3030103↩
#define k_BCJ2 0x303011B↩
#define k_PPC 0x3030205↩
#define k_IA64 0x3030401↩
#define k_ARM 0x3030501↩
#define k_ARMT 0x3030701↩
#define k_SPARC 0x3030805↩
#ifdef _7ZIP_PPMD_SUPPPORT↩
#define k_PPMD 0x30401↩
typedef struct
{↩
IByteIn vt;↩
const Byte *cur;↩
const Byte *end;↩
const Byte *begin;↩
UInt64 processed;↩
Bool extra;↩
SRes res;↩
const ILookInStream *inStream;↩
} CByteInToLook;↩
static Byte ReadByte(const IByteIn *pp)↩
{↩
CByteInToLook *p = CONTAINER_FROM_VTBL(pp, CByteInToLook, vt);↩
if (p->cur != p->end)↩
return *p->cur++;↩
if (p->res == SZ_OK)↩
{↩
size_t size = p->cur - p->begin;↩
p->processed += size;↩
p->res = ILookInStream_Skip(p->inStream, size);↩
size = (1 << 25);↩
p->res = ILookInStream_Look(p->inStream, (const void **)&p->begin, &size);↩
p->cur = p->begin;↩
p->end = p->begin + size;↩
if (size != 0)↩
return *p->cur++;;↩
}↩
p->extra = True;↩
return 0;↩
}↩
static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, const ILookInStream *inStream,↩
Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)↩
{↩
CPpmd7 ppmd;↩
CByteInToLook s;↩
SRes res = SZ_OK;↩
s.vt.Read = ReadByte;↩
s.inStream = inStream;↩
s.begin = s.end = s.cur = NULL;↩
s.extra = False;↩
s.res = SZ_OK;↩
s.processed = 0;↩
if (propsSize != 5)↩
return SZ_ERROR_UNSUPPORTED;↩
{↩
unsigned order = props[0];↩
UInt32 memSize = GetUi32(props + 1);↩
if (order < PPMD7_MIN_ORDER ||↩
order > PPMD7_MAX_ORDER ||↩
memSize < PPMD7_MIN_MEM_SIZE ||↩
memSize > PPMD7_MAX_MEM_SIZE)↩
return SZ_ERROR_UNSUPPORTED;↩
Ppmd7_Construct(&ppmd);↩
if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))↩
return SZ_ERROR_MEM;↩
Ppmd7_Init(&ppmd, order);↩
}↩
{↩
CPpmd7z_RangeDec rc;↩
Ppmd7z_RangeDec_CreateVTable(&rc);↩
rc.Stream = &s.vt;↩
if (!Ppmd7z_RangeDec_Init(&rc))↩
res = SZ_ERROR_DATA;↩
else if (s.extra)↩
res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);↩
else
{↩
SizeT i;↩
for (i = 0; i < outSize; i++)↩
{↩
int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.vt);↩
if (s.extra || sym < 0)↩
break;↩
outBuffer[i] = (Byte)sym;↩
}↩
if (i != outSize)↩
res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);↩
else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))↩
res = SZ_ERROR_DATA;↩
}↩
}↩
Ppmd7_Free(&ppmd, allocMain);↩
return res;↩
}↩
#endif
static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,↩
Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)↩
{↩
CLzmaDec state;↩
SRes res = SZ_OK;↩
LzmaDec_Construct(&state);↩
RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain));↩
state.dic = outBuffer;↩
state.dicBufSize = outSize;↩
LzmaDec_Init(&state);↩
for (;;)↩
{↩
const void *inBuf = NULL;↩
size_t lookahead = (1 << 18);↩
if (lookahead > inSize)↩
lookahead = (size_t)inSize;↩
res = ILookInStream_Look(inStream, &inBuf, &lookahead);↩
if (res != SZ_OK)↩
break;↩
{↩
SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;↩
ELzmaStatus status;↩
res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);↩
lookahead -= inProcessed;↩
inSize -= inProcessed;↩
if (res != SZ_OK)↩
break;↩
if (status == LZMA_STATUS_FINISHED_WITH_MARK)↩
{↩
if (outSize != state.dicPos || inSize != 0)↩
res = SZ_ERROR_DATA;↩
break;↩
}↩
if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)↩
break;↩
if (inProcessed == 0 && dicPos == state.dicPos)↩
{↩
res = SZ_ERROR_DATA;↩
break;↩
}↩
res = ILookInStream_Skip(inStream, inProcessed);↩
if (res != SZ_OK)↩
break;↩
}↩
}↩
LzmaDec_FreeProbs(&state, allocMain);↩
return res;↩
}↩
#ifndef _7Z_NO_METHOD_LZMA2↩
static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,↩
Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)↩
{↩
CLzma2Dec state;↩
SRes res = SZ_OK;↩
Lzma2Dec_Construct(&state);↩
if (propsSize != 1)↩
return SZ_ERROR_DATA;↩
RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain));↩
state.decoder.dic = outBuffer;↩
state.decoder.dicBufSize = outSize;↩
Lzma2Dec_Init(&state);↩
for (;;)↩
{↩
const void *inBuf = NULL;↩
size_t lookahead = (1 << 18);↩
if (lookahead > inSize)↩
lookahead = (size_t)inSize;↩
res = ILookInStream_Look(inStream, &inBuf, &lookahead);↩
if (res != SZ_OK)↩
break;↩
{↩
SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;↩
ELzmaStatus status;↩
res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);↩
lookahead -= inProcessed;↩
inSize -= inProcessed;↩
if (res != SZ_OK)↩
break;↩
if (status == LZMA_STATUS_FINISHED_WITH_MARK)↩
{↩
if (outSize != state.decoder.dicPos || inSize != 0)↩
res = SZ_ERROR_DATA;↩
break;↩
}↩
if (inProcessed == 0 && dicPos == state.decoder.dicPos)↩
{↩
res = SZ_ERROR_DATA;↩
break;↩
}↩
res = ILookInStream_Skip(inStream, inProcessed);↩
if (res != SZ_OK)↩
break;↩
}↩
}↩
Lzma2Dec_FreeProbs(&state, allocMain);↩
return res;↩
}↩
#endif
static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)↩
{↩
while (inSize > 0)↩
{↩
const void *inBuf;↩
size_t curSize = (1 << 18);↩
if (curSize > inSize)↩
curSize = (size_t)inSize;↩
RINOK(ILookInStream_Look(inStream, &inBuf, &curSize));↩
if (curSize == 0)↩
return SZ_ERROR_INPUT_EOF;↩
memcpy(outBuffer, inBuf, curSize);↩
outBuffer += curSize;↩
inSize -= curSize;↩
RINOK(ILookInStream_Skip(inStream, curSize));↩
}↩
return SZ_OK;↩
}↩
static Bool IS_MAIN_METHOD(UInt32 m)↩
{↩
switch (m)↩
{↩
case k_Copy:↩
case k_LZMA:↩
#ifndef _7Z_NO_METHOD_LZMA2↩
case k_LZMA2:↩
#endif
#ifdef _7ZIP_PPMD_SUPPPORT↩
case k_PPMD:↩
#endif
return True;↩
}↩
return False;↩
}↩
static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)↩
{↩
return
c->NumStreams == 1↩
/* && c->MethodID <= (UInt32)0xFFFFFFFF */
&& IS_MAIN_METHOD((UInt32)c->MethodID);↩
}↩
#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4)↩
static SRes CheckSupportedFolder(const CSzFolder *f)↩
{↩
if (f->NumCoders < 1 || f->NumCoders > 4)↩
return SZ_ERROR_UNSUPPORTED;↩
if (!IS_SUPPORTED_CODER(&f->Coders[0]))↩
return SZ_ERROR_UNSUPPORTED;↩
if (f->NumCoders == 1)↩
{↩
if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0)↩
return SZ_ERROR_UNSUPPORTED;↩
return SZ_OK;↩
}↩
#ifndef _7Z_NO_METHODS_FILTERS↩
if (f->NumCoders == 2)↩
{↩
const CSzCoderInfo *c = &f->Coders[1];↩
if (↩
/* c->MethodID > (UInt32)0xFFFFFFFF || */
c->NumStreams != 1↩
|| f->NumPackStreams != 1↩
|| f->PackStreams[0] != 0↩
|| f->NumBonds != 1↩
|| f->Bonds[0].InIndex != 1↩
|| f->Bonds[0].OutIndex != 0)↩
return SZ_ERROR_UNSUPPORTED;↩
switch ((UInt32)c->MethodID)↩
{↩
case k_Delta:↩
case k_BCJ:↩
case k_PPC:↩
case k_IA64:↩
case k_SPARC:↩
case k_ARM:↩
case k_ARMT:↩
break;↩
default:↩
return SZ_ERROR_UNSUPPORTED;↩
}↩
return SZ_OK;↩
}↩
#endif
if (f->NumCoders == 4)↩
{↩
if (!IS_SUPPORTED_CODER(&f->Coders[1])↩
|| !IS_SUPPORTED_CODER(&f->Coders[2])↩
|| !IS_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->NumBonds != 3↩
|| f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0↩
|| f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1↩
|| f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2)↩
return SZ_ERROR_UNSUPPORTED;↩
return SZ_OK;↩
}↩
return SZ_ERROR_UNSUPPORTED;↩
}↩
#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;↩
static SRes SzFolder_Decode2(const CSzFolder *folder,↩
const Byte *propsData,↩
const UInt64 *unpackSizes,↩
const UInt64 *packPositions,↩
ILookInStream *inStream, UInt64 startPos,↩
Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain,↩
Byte *tempBuf[])↩
{↩
UInt32 ci;↩
SizeT tempSizes[3] = { 0, 0, 0};↩
SizeT tempSize3 = 0;↩
Byte *tempBuf3 = 0;↩
RINOK(CheckSupportedFolder(folder));↩
for (ci = 0; ci < folder->NumCoders; ci++)↩
{↩
const CSzCoderInfo *coder = &folder->Coders[ci];↩
if (IS_MAIN_METHOD((UInt32)coder->MethodID))↩
{↩
UInt32 si = 0;↩
UInt64 offset;↩
UInt64 inSize;↩
Byte *outBufCur = outBuffer;↩
SizeT outSizeCur = outSize;↩
if (folder->NumCoders == 4)↩
{↩
UInt32 indices[] = { 3, 2, 0 };↩
UInt64 unpackSize = unpackSizes[ci];↩
si = indices[ci];↩
if (ci < 2)↩
{↩
Byte *temp;↩
outSizeCur = (SizeT)unpackSize;↩
if (outSizeCur != unpackSize)↩
return SZ_ERROR_MEM;↩
temp = (Byte *)ISzAlloc_Alloc(allocMain, outSizeCur);↩
if (!temp && 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;↩
tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);↩
tempSize3 = outSizeCur = (SizeT)unpackSize;↩
}↩
else
return SZ_ERROR_UNSUPPORTED;↩
}↩
offset = packPositions[si];↩
inSize = packPositions[(size_t)si + 1] - offset;↩
RINOK(LookInStream_SeekTo(inStream, startPos + offset));↩
if (coder->MethodID == k_Copy)↩
{↩
if (inSize != outSizeCur) /* check it */
return SZ_ERROR_DATA;↩
RINOK(SzDecodeCopy(inSize, inStream, outBufCur));↩
}↩
else if (coder->MethodID == k_LZMA)↩
{↩
RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));↩
}↩
#ifndef _7Z_NO_METHOD_LZMA2↩
else if (coder->MethodID == k_LZMA2)↩
{↩
RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));↩
}↩
#endif
#ifdef _7ZIP_PPMD_SUPPPORT↩
else if (coder->MethodID == k_PPMD)↩
{↩
RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));↩
}↩
#endif
else
return SZ_ERROR_UNSUPPORTED;↩
}↩
else if (coder->MethodID == k_BCJ2)↩
{↩
UInt64 offset = packPositions[1];↩
UInt64 s3Size = packPositions[2] - offset;↩
if (ci != 3)↩
return SZ_ERROR_UNSUPPORTED;↩
tempSizes[2] = (SizeT)s3Size;↩
if (tempSizes[2] != s3Size)↩
return SZ_ERROR_MEM;↩
tempBuf[2] = (Byte *)ISzAlloc_Alloc(allocMain, tempSizes[2]);↩
if (!tempBuf[2] && tempSizes[2] != 0)↩
return SZ_ERROR_MEM;↩
RINOK(LookInStream_SeekTo(inStream, startPos + offset));↩
RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2]));↩
if ((tempSizes[0] & 3) != 0 ||↩
(tempSizes[1] & 3) != 0 ||↩
tempSize3 + tempSizes[0] + tempSizes[1] != outSize)↩
return SZ_ERROR_DATA;↩
{↩
CBcj2Dec p;↩
p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3;↩
p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0];↩
p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1];↩
p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2];↩
p.dest = outBuffer;↩
p.destLim = outBuffer + outSize;↩
Bcj2Dec_Init(&p);↩
RINOK(Bcj2Dec_Decode(&p));↩
{↩
unsigned i;↩
for (i = 0; i < 4; i++)↩
if (p.bufs[i] != p.lims[i])↩
return SZ_ERROR_DATA;↩
if (!Bcj2Dec_IsFinished(&p))↩
return SZ_ERROR_DATA;↩
if (p.dest != p.destLim↩
|| p.state != BCJ2_STREAM_MAIN)↩
return SZ_ERROR_DATA;↩
}↩
}↩
}↩
#ifndef _7Z_NO_METHODS_FILTERS↩
else if (ci == 1)↩
{↩
if (coder->MethodID == k_Delta)↩
{↩
if (coder->PropsSize != 1)↩
return SZ_ERROR_UNSUPPORTED;↩
{↩
Byte state[DELTA_STATE_SIZE];↩
Delta_Init(state);↩
Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize);↩
}↩
}↩
else
{↩
if (coder->PropsSize != 0)↩
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(PPC)↩
CASE_BRA_CONV(IA64)↩
CASE_BRA_CONV(SPARC)↩
CASE_BRA_CONV(ARM)↩
CASE_BRA_CONV(ARMT)↩
default:↩
return SZ_ERROR_UNSUPPORTED;↩
}↩
}↩
}↩
#endif
else
return SZ_ERROR_UNSUPPORTED;↩
}↩
return SZ_OK;↩
}↩
SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,↩
ILookInStream *inStream, UInt64 startPos,↩
Byte *outBuffer, size_t outSize,↩
ISzAllocPtr allocMain)↩
{↩
SRes res;↩
CSzFolder folder;↩
CSzData sd;↩
const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];↩
sd.Data = data;↩
sd.Size = p->FoCodersOffsets[(size_t)folderIndex + 1] - p->FoCodersOffsets[folderIndex];↩
res = SzGetNextFolderItem(&folder, &sd);↩
if (res != SZ_OK)↩
return res;↩
if (sd.Size != 0↩
|| folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex]↩
|| outSize != SzAr_GetFolderUnpackSize(p, folderIndex))↩
return SZ_ERROR_FAIL;↩
{↩
unsigned i;↩
Byte *tempBuf[3] = { 0, 0, 0};↩
res = SzFolder_Decode2(&folder, data,↩
&p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]],↩
p->PackPositions + p->FoStartPackStreamIndex[folderIndex],↩
inStream, startPos,↩
outBuffer, (SizeT)outSize, allocMain, tempBuf);↩
for (i = 0; i < 3; i++)↩
ISzAlloc_Free(allocMain, tempBuf[i]);↩
if (res == SZ_OK)↩
if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex))↩
if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex])↩
res = SZ_ERROR_CRC;↩
return res;↩
}↩
}↩