123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591 |
- /* 7zDec.c -- Decoding from 7z folder
- 2019-02-02 : 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;
- BoolInt 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, (const Byte *)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, (const Byte *)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 BoolInt 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 BoolInt 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;
- }
- }
|