summaryrefslogtreecommitdiffstats
path: root/other-licenses/7zstub/src/C/XzDec.c
diff options
context:
space:
mode:
Diffstat (limited to 'other-licenses/7zstub/src/C/XzDec.c')
-rw-r--r--other-licenses/7zstub/src/C/XzDec.c2773
1 files changed, 2773 insertions, 0 deletions
diff --git a/other-licenses/7zstub/src/C/XzDec.c b/other-licenses/7zstub/src/C/XzDec.c
new file mode 100644
index 000000000..ebf198336
--- /dev/null
+++ b/other-licenses/7zstub/src/C/XzDec.c
@@ -0,0 +1,2773 @@
+/* XzDec.c -- Xz Decode
+2018-04-24 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+// #include <stdio.h>
+
+// #define XZ_DUMP
+
+/* #define XZ_DUMP */
+
+#ifdef XZ_DUMP
+#include <stdio.h>
+#endif
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#define PRF_STR(s) PRF(printf("\n" s "\n"))
+#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d))
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "7zCrc.h"
+#include "Alloc.h"
+#include "Bra.h"
+#include "CpuArch.h"
+#include "Delta.h"
+#include "Lzma2Dec.h"
+
+// #define USE_SUBBLOCK
+
+#ifdef USE_SUBBLOCK
+#include "Bcj3Dec.c"
+#include "SbDec.h"
+#endif
+
+#include "Xz.h"
+
+#define XZ_CHECK_SIZE_MAX 64
+
+#define CODER_BUF_SIZE ((size_t)1 << 17)
+
+unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value)
+{
+ unsigned i, limit;
+ *value = 0;
+ limit = (maxSize > 9) ? 9 : (unsigned)maxSize;
+
+ for (i = 0; i < limit;)
+ {
+ Byte b = p[i];
+ *value |= (UInt64)(b & 0x7F) << (7 * i++);
+ if ((b & 0x80) == 0)
+ return (b == 0 && i != 1) ? 0 : i;
+ }
+ return 0;
+}
+
+/* ---------- BraState ---------- */
+
+#define BRA_BUF_SIZE (1 << 14)
+
+typedef struct
+{
+ size_t bufPos;
+ size_t bufConv;
+ size_t bufTotal;
+
+ int encodeMode;
+
+ UInt32 methodId;
+ UInt32 delta;
+ UInt32 ip;
+ UInt32 x86State;
+ Byte deltaState[DELTA_STATE_SIZE];
+
+ Byte buf[BRA_BUF_SIZE];
+} CBraState;
+
+static void BraState_Free(void *pp, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, pp);
+}
+
+static SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
+{
+ CBraState *p = ((CBraState *)pp);
+ UNUSED_VAR(alloc);
+ p->ip = 0;
+ if (p->methodId == XZ_ID_Delta)
+ {
+ if (propSize != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ p->delta = (unsigned)props[0] + 1;
+ }
+ else
+ {
+ if (propSize == 4)
+ {
+ UInt32 v = GetUi32(props);
+ switch (p->methodId)
+ {
+ case XZ_ID_PPC:
+ case XZ_ID_ARM:
+ case XZ_ID_SPARC:
+ if ((v & 3) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ break;
+ case XZ_ID_ARMT:
+ if ((v & 1) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ break;
+ case XZ_ID_IA64:
+ if ((v & 0xF) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ break;
+ }
+ p->ip = v;
+ }
+ else if (propSize != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ return SZ_OK;
+}
+
+static void BraState_Init(void *pp)
+{
+ CBraState *p = ((CBraState *)pp);
+ p->bufPos = p->bufConv = p->bufTotal = 0;
+ x86_Convert_Init(p->x86State);
+ if (p->methodId == XZ_ID_Delta)
+ Delta_Init(p->deltaState);
+}
+
+
+#define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: size = isa ## _Convert(data, size, p->ip, p->encodeMode); break;
+
+static SizeT BraState_Filter(void *pp, Byte *data, SizeT size)
+{
+ CBraState *p = ((CBraState *)pp);
+ switch (p->methodId)
+ {
+ case XZ_ID_Delta:
+ if (p->encodeMode)
+ Delta_Encode(p->deltaState, p->delta, data, size);
+ else
+ Delta_Decode(p->deltaState, p->delta, data, size);
+ break;
+ case XZ_ID_X86:
+ size = x86_Convert(data, size, p->ip, &p->x86State, p->encodeMode);
+ break;
+ CASE_BRA_CONV(PPC)
+ CASE_BRA_CONV(IA64)
+ CASE_BRA_CONV(ARM)
+ CASE_BRA_CONV(ARMT)
+ CASE_BRA_CONV(SPARC)
+ }
+ p->ip += (UInt32)size;
+ return size;
+}
+
+
+static SRes BraState_Code2(void *pp,
+ Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, int srcWasFinished,
+ ECoderFinishMode finishMode,
+ // int *wasFinished
+ ECoderStatus *status)
+{
+ CBraState *p = ((CBraState *)pp);
+ SizeT destRem = *destLen;
+ SizeT srcRem = *srcLen;
+ UNUSED_VAR(finishMode);
+
+ *destLen = 0;
+ *srcLen = 0;
+ // *wasFinished = False;
+ *status = CODER_STATUS_NOT_FINISHED;
+
+ while (destRem > 0)
+ {
+ if (p->bufPos != p->bufConv)
+ {
+ size_t size = p->bufConv - p->bufPos;
+ if (size > destRem)
+ size = destRem;
+ memcpy(dest, p->buf + p->bufPos, size);
+ p->bufPos += size;
+ *destLen += size;
+ dest += size;
+ destRem -= size;
+ continue;
+ }
+
+ p->bufTotal -= p->bufPos;
+ memmove(p->buf, p->buf + p->bufPos, p->bufTotal);
+ p->bufPos = 0;
+ p->bufConv = 0;
+ {
+ size_t size = BRA_BUF_SIZE - p->bufTotal;
+ if (size > srcRem)
+ size = srcRem;
+ memcpy(p->buf + p->bufTotal, src, size);
+ *srcLen += size;
+ src += size;
+ srcRem -= size;
+ p->bufTotal += size;
+ }
+ if (p->bufTotal == 0)
+ break;
+
+ p->bufConv = BraState_Filter(pp, p->buf, p->bufTotal);
+
+ if (p->bufConv == 0)
+ {
+ if (!srcWasFinished)
+ break;
+ p->bufConv = p->bufTotal;
+ }
+ }
+
+ if (p->bufTotal == p->bufPos && srcRem == 0 && srcWasFinished)
+ {
+ *status = CODER_STATUS_FINISHED_WITH_MARK;
+ // *wasFinished = 1;
+ }
+
+ return SZ_OK;
+}
+
+
+SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc)
+{
+ CBraState *decoder;
+ if (id < XZ_ID_Delta || id > XZ_ID_SPARC)
+ return SZ_ERROR_UNSUPPORTED;
+ decoder = p->p;
+ if (!decoder)
+ {
+ decoder = (CBraState *)ISzAlloc_Alloc(alloc, sizeof(CBraState));
+ if (!decoder)
+ return SZ_ERROR_MEM;
+ p->p = decoder;
+ p->Free = BraState_Free;
+ p->SetProps = BraState_SetProps;
+ p->Init = BraState_Init;
+ p->Code2 = BraState_Code2;
+ p->Filter = BraState_Filter;
+ }
+ decoder->methodId = (UInt32)id;
+ decoder->encodeMode = encodeMode;
+ return SZ_OK;
+}
+
+
+
+/* ---------- SbState ---------- */
+
+#ifdef USE_SUBBLOCK
+
+static void SbState_Free(void *pp, ISzAllocPtr alloc)
+{
+ CSbDec *p = (CSbDec *)pp;
+ SbDec_Free(p);
+ ISzAlloc_Free(alloc, pp);
+}
+
+static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
+{
+ UNUSED_VAR(pp);
+ UNUSED_VAR(props);
+ UNUSED_VAR(alloc);
+ return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
+}
+
+static void SbState_Init(void *pp)
+{
+ SbDec_Init((CSbDec *)pp);
+}
+
+static SRes SbState_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode,
+ // int *wasFinished
+ ECoderStatus *status)
+{
+ CSbDec *p = (CSbDec *)pp;
+ SRes res;
+ UNUSED_VAR(srcWasFinished);
+ p->dest = dest;
+ p->destLen = *destLen;
+ p->src = src;
+ p->srcLen = *srcLen;
+ p->finish = finishMode; /* change it */
+ res = SbDec_Decode((CSbDec *)pp);
+ *destLen -= p->destLen;
+ *srcLen -= p->srcLen;
+ // *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */
+ *status = (*destLen == 0 && *srcLen == 0) ?
+ CODER_STATUS_FINISHED_WITH_MARK :
+ CODER_STATUS_NOT_FINISHED;
+ return res;
+}
+
+static SRes SbState_SetFromMethod(IStateCoder *p, ISzAllocPtr alloc)
+{
+ CSbDec *decoder = (CSbDec *)p->p;
+ if (!decoder)
+ {
+ decoder = (CSbDec *)ISzAlloc_Alloc(alloc, sizeof(CSbDec));
+ if (!decoder)
+ return SZ_ERROR_MEM;
+ p->p = decoder;
+ p->Free = SbState_Free;
+ p->SetProps = SbState_SetProps;
+ p->Init = SbState_Init;
+ p->Code2 = SbState_Code2;
+ p->Filter = NULL;
+ }
+ SbDec_Construct(decoder);
+ SbDec_SetAlloc(decoder, alloc);
+ return SZ_OK;
+}
+
+#endif
+
+
+
+/* ---------- Lzma2 ---------- */
+
+typedef struct
+{
+ CLzma2Dec decoder;
+ Bool outBufMode;
+} CLzma2Dec_Spec;
+
+
+static void Lzma2State_Free(void *pp, ISzAllocPtr alloc)
+{
+ CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp;
+ if (p->outBufMode)
+ Lzma2Dec_FreeProbs(&p->decoder, alloc);
+ else
+ Lzma2Dec_Free(&p->decoder, alloc);
+ ISzAlloc_Free(alloc, pp);
+}
+
+static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
+{
+ if (propSize != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ {
+ CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp;
+ if (p->outBufMode)
+ return Lzma2Dec_AllocateProbs(&p->decoder, props[0], alloc);
+ else
+ return Lzma2Dec_Allocate(&p->decoder, props[0], alloc);
+ }
+}
+
+static void Lzma2State_Init(void *pp)
+{
+ Lzma2Dec_Init(&((CLzma2Dec_Spec *)pp)->decoder);
+}
+
+
+/*
+ if (outBufMode), then (dest) is not used. Use NULL.
+ Data is unpacked to (spec->decoder.decoder.dic) output buffer.
+*/
+
+static SRes Lzma2State_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode,
+ // int *wasFinished,
+ ECoderStatus *status)
+{
+ CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)pp;
+ ELzmaStatus status2;
+ /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */
+ SRes res;
+ UNUSED_VAR(srcWasFinished);
+ if (spec->outBufMode)
+ {
+ SizeT dicPos = spec->decoder.decoder.dicPos;
+ SizeT dicLimit = dicPos + *destLen;
+ res = Lzma2Dec_DecodeToDic(&spec->decoder, dicLimit, src, srcLen, (ELzmaFinishMode)finishMode, &status2);
+ *destLen = spec->decoder.decoder.dicPos - dicPos;
+ }
+ else
+ res = Lzma2Dec_DecodeToBuf(&spec->decoder, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status2);
+ // *wasFinished = (status2 == LZMA_STATUS_FINISHED_WITH_MARK);
+ // ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder
+ *status = status2;
+ return res;
+}
+
+
+static SRes Lzma2State_SetFromMethod(IStateCoder *p, Byte *outBuf, size_t outBufSize, ISzAllocPtr alloc)
+{
+ CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p;
+ if (!spec)
+ {
+ spec = (CLzma2Dec_Spec *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Dec_Spec));
+ if (!spec)
+ return SZ_ERROR_MEM;
+ p->p = spec;
+ p->Free = Lzma2State_Free;
+ p->SetProps = Lzma2State_SetProps;
+ p->Init = Lzma2State_Init;
+ p->Code2 = Lzma2State_Code2;
+ p->Filter = NULL;
+ Lzma2Dec_Construct(&spec->decoder);
+ }
+ spec->outBufMode = False;
+ if (outBuf)
+ {
+ spec->outBufMode = True;
+ spec->decoder.decoder.dic = outBuf;
+ spec->decoder.decoder.dicBufSize = outBufSize;
+ }
+ return SZ_OK;
+}
+
+
+static SRes Lzma2State_ResetOutBuf(IStateCoder *p, Byte *outBuf, size_t outBufSize)
+{
+ CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p;
+ if ((spec->outBufMode && !outBuf) || (!spec->outBufMode && outBuf))
+ return SZ_ERROR_FAIL;
+ if (outBuf)
+ {
+ spec->decoder.decoder.dic = outBuf;
+ spec->decoder.decoder.dicBufSize = outBufSize;
+ }
+ return SZ_OK;
+}
+
+
+
+static void MixCoder_Construct(CMixCoder *p, ISzAllocPtr alloc)
+{
+ unsigned i;
+ p->alloc = alloc;
+ p->buf = NULL;
+ p->numCoders = 0;
+
+ p->outBufSize = 0;
+ p->outBuf = NULL;
+ // p->SingleBufMode = False;
+
+ for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
+ p->coders[i].p = NULL;
+}
+
+
+static void MixCoder_Free(CMixCoder *p)
+{
+ unsigned i;
+ p->numCoders = 0;
+ for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
+ {
+ IStateCoder *sc = &p->coders[i];
+ if (sc->p)
+ {
+ sc->Free(sc->p, p->alloc);
+ sc->p = NULL;
+ }
+ }
+ if (p->buf)
+ {
+ ISzAlloc_Free(p->alloc, p->buf);
+ p->buf = NULL; /* 9.31: the BUG was fixed */
+ }
+}
+
+static void MixCoder_Init(CMixCoder *p)
+{
+ unsigned i;
+ for (i = 0; i < MIXCODER_NUM_FILTERS_MAX - 1; i++)
+ {
+ p->size[i] = 0;
+ p->pos[i] = 0;
+ p->finished[i] = 0;
+ }
+ for (i = 0; i < p->numCoders; i++)
+ {
+ IStateCoder *coder = &p->coders[i];
+ coder->Init(coder->p);
+ p->results[i] = SZ_OK;
+ }
+ p->outWritten = 0;
+ p->wasFinished = False;
+ p->res = SZ_OK;
+ p->status = CODER_STATUS_NOT_SPECIFIED;
+}
+
+
+static SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize)
+{
+ IStateCoder *sc = &p->coders[coderIndex];
+ p->ids[coderIndex] = methodId;
+ switch (methodId)
+ {
+ case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, outBuf, outBufSize, p->alloc);
+ #ifdef USE_SUBBLOCK
+ case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc);
+ #endif
+ }
+ if (coderIndex == 0)
+ return SZ_ERROR_UNSUPPORTED;
+ return BraState_SetFromMethod(sc, methodId, 0, p->alloc);
+}
+
+
+static SRes MixCoder_ResetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize)
+{
+ IStateCoder *sc = &p->coders[coderIndex];
+ switch (methodId)
+ {
+ case XZ_ID_LZMA2: return Lzma2State_ResetOutBuf(sc, outBuf, outBufSize);
+ }
+ return SZ_ERROR_UNSUPPORTED;
+}
+
+
+
+/*
+ if (destFinish) - then unpack data block is finished at (*destLen) position,
+ and we can return data that were not processed by filter
+
+output (status) can be :
+ CODER_STATUS_NOT_FINISHED
+ CODER_STATUS_FINISHED_WITH_MARK
+ CODER_STATUS_NEEDS_MORE_INPUT - not implemented still
+*/
+
+static SRes MixCoder_Code(CMixCoder *p,
+ Byte *dest, SizeT *destLen, int destFinish,
+ const Byte *src, SizeT *srcLen, int srcWasFinished,
+ ECoderFinishMode finishMode)
+{
+ SizeT destLenOrig = *destLen;
+ SizeT srcLenOrig = *srcLen;
+
+ *destLen = 0;
+ *srcLen = 0;
+
+ if (p->wasFinished)
+ return p->res;
+
+ p->status = CODER_STATUS_NOT_FINISHED;
+
+ // if (p->SingleBufMode)
+ if (p->outBuf)
+ {
+ SRes res;
+ SizeT destLen2, srcLen2;
+ int wasFinished;
+
+ PRF_STR("------- MixCoder Single ----------");
+
+ srcLen2 = srcLenOrig;
+ destLen2 = destLenOrig;
+
+ {
+ IStateCoder *coder = &p->coders[0];
+ res = coder->Code2(coder->p, NULL, &destLen2, src, &srcLen2, srcWasFinished, finishMode,
+ // &wasFinished,
+ &p->status);
+ wasFinished = (p->status == CODER_STATUS_FINISHED_WITH_MARK);
+ }
+
+ p->res = res;
+
+ /*
+ if (wasFinished)
+ p->status = CODER_STATUS_FINISHED_WITH_MARK;
+ else
+ {
+ if (res == SZ_OK)
+ if (destLen2 != destLenOrig)
+ p->status = CODER_STATUS_NEEDS_MORE_INPUT;
+ }
+ */
+
+
+ *srcLen = srcLen2;
+ src += srcLen2;
+ p->outWritten += destLen2;
+
+ if (res != SZ_OK || srcWasFinished || wasFinished)
+ p->wasFinished = True;
+
+ if (p->numCoders == 1)
+ *destLen = destLen2;
+ else if (p->wasFinished)
+ {
+ unsigned i;
+ size_t processed = p->outWritten;
+
+ for (i = 1; i < p->numCoders; i++)
+ {
+ IStateCoder *coder = &p->coders[i];
+ processed = coder->Filter(coder->p, p->outBuf, processed);
+ if (wasFinished || (destFinish && p->outWritten == destLenOrig))
+ processed = p->outWritten;
+ PRF_STR_INT("filter", i);
+ }
+ *destLen = processed;
+ }
+ return res;
+ }
+
+ PRF_STR("standard mix");
+
+ if (p->numCoders != 1)
+ {
+ if (!p->buf)
+ {
+ p->buf = (Byte *)ISzAlloc_Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1));
+ if (!p->buf)
+ return SZ_ERROR_MEM;
+ }
+
+ finishMode = CODER_FINISH_ANY;
+ }
+
+ for (;;)
+ {
+ Bool processed = False;
+ Bool allFinished = True;
+ SRes resMain = SZ_OK;
+ unsigned i;
+
+ p->status = CODER_STATUS_NOT_FINISHED;
+ /*
+ if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY)
+ break;
+ */
+
+ for (i = 0; i < p->numCoders; i++)
+ {
+ SRes res;
+ IStateCoder *coder = &p->coders[i];
+ Byte *dest2;
+ SizeT destLen2, srcLen2; // destLen2_Orig;
+ const Byte *src2;
+ int srcFinished2;
+ int encodingWasFinished;
+ ECoderStatus status2;
+
+ if (i == 0)
+ {
+ src2 = src;
+ srcLen2 = srcLenOrig - *srcLen;
+ srcFinished2 = srcWasFinished;
+ }
+ else
+ {
+ size_t k = i - 1;
+ src2 = p->buf + (CODER_BUF_SIZE * k) + p->pos[k];
+ srcLen2 = p->size[k] - p->pos[k];
+ srcFinished2 = p->finished[k];
+ }
+
+ if (i == p->numCoders - 1)
+ {
+ dest2 = dest;
+ destLen2 = destLenOrig - *destLen;
+ }
+ else
+ {
+ if (p->pos[i] != p->size[i])
+ continue;
+ dest2 = p->buf + (CODER_BUF_SIZE * i);
+ destLen2 = CODER_BUF_SIZE;
+ }
+
+ // destLen2_Orig = destLen2;
+
+ if (p->results[i] != SZ_OK)
+ {
+ if (resMain == SZ_OK)
+ resMain = p->results[i];
+ continue;
+ }
+
+ res = coder->Code2(coder->p,
+ dest2, &destLen2,
+ src2, &srcLen2, srcFinished2,
+ finishMode,
+ // &encodingWasFinished,
+ &status2);
+
+ if (res != SZ_OK)
+ {
+ p->results[i] = res;
+ if (resMain == SZ_OK)
+ resMain = res;
+ }
+
+ encodingWasFinished = (status2 == CODER_STATUS_FINISHED_WITH_MARK);
+
+ if (!encodingWasFinished)
+ {
+ allFinished = False;
+ if (p->numCoders == 1 && res == SZ_OK)
+ p->status = status2;
+ }
+
+ if (i == 0)
+ {
+ *srcLen += srcLen2;
+ src += srcLen2;
+ }
+ else
+ p->pos[(size_t)i - 1] += srcLen2;
+
+ if (i == p->numCoders - 1)
+ {
+ *destLen += destLen2;
+ dest += destLen2;
+ }
+ else
+ {
+ p->size[i] = destLen2;
+ p->pos[i] = 0;
+ p->finished[i] = encodingWasFinished;
+ }
+
+ if (destLen2 != 0 || srcLen2 != 0)
+ processed = True;
+ }
+
+ if (!processed)
+ {
+ if (allFinished)
+ p->status = CODER_STATUS_FINISHED_WITH_MARK;
+ return resMain;
+ }
+ }
+}
+
+
+SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf)
+{
+ *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE);
+ if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) !=
+ GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE))
+ return SZ_ERROR_NO_ARCHIVE;
+ return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
+}
+
+static Bool Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf)
+{
+ return indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2)
+ && GetUi32(buf) == CrcCalc(buf + 4, 6)
+ && flags == GetBe16(buf + 8)
+ && buf[10] == XZ_FOOTER_SIG_0
+ && buf[11] == XZ_FOOTER_SIG_1;
+}
+
+#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
+ { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
+ if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }
+
+
+static Bool XzBlock_AreSupportedFilters(const CXzBlock *p)
+{
+ unsigned numFilters = XzBlock_GetNumFilters(p) - 1;
+ unsigned i;
+ {
+ const CXzFilter *f = &p->filters[numFilters];
+ if (f->id != XZ_ID_LZMA2 || f->propsSize != 1 || f->props[0] > 40)
+ return False;
+ }
+
+ for (i = 0; i < numFilters; i++)
+ {
+ const CXzFilter *f = &p->filters[i];
+ if (f->id == XZ_ID_Delta)
+ {
+ if (f->propsSize != 1)
+ return False;
+ }
+ else if (f->id < XZ_ID_Delta
+ || f->id > XZ_ID_SPARC
+ || (f->propsSize != 0 && f->propsSize != 4))
+ return False;
+ }
+ return True;
+}
+
+
+SRes XzBlock_Parse(CXzBlock *p, const Byte *header)
+{
+ unsigned pos;
+ unsigned numFilters, i;
+ unsigned headerSize = (unsigned)header[0] << 2;
+
+ /* (headerSize != 0) : another code checks */
+
+ if (CrcCalc(header, headerSize) != GetUi32(header + headerSize))
+ return SZ_ERROR_ARCHIVE;
+
+ pos = 1;
+ p->flags = header[pos++];
+
+ p->packSize = (UInt64)(Int64)-1;
+ if (XzBlock_HasPackSize(p))
+ {
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize);
+ if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ p->unpackSize = (UInt64)(Int64)-1;
+ if (XzBlock_HasUnpackSize(p))
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize);
+
+ numFilters = XzBlock_GetNumFilters(p);
+ for (i = 0; i < numFilters; i++)
+ {
+ CXzFilter *filter = p->filters + i;
+ UInt64 size;
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id);
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &size);
+ if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX)
+ return SZ_ERROR_ARCHIVE;
+ filter->propsSize = (UInt32)size;
+ memcpy(filter->props, header + pos, (size_t)size);
+ pos += (unsigned)size;
+
+ #ifdef XZ_DUMP
+ printf("\nf[%u] = %2X: ", i, (unsigned)filter->id);
+ {
+ unsigned i;
+ for (i = 0; i < size; i++)
+ printf(" %2X", filter->props[i]);
+ }
+ #endif
+ }
+
+ if (XzBlock_HasUnsupportedFlags(p))
+ return SZ_ERROR_UNSUPPORTED;
+
+ while (pos < headerSize)
+ if (header[pos++] != 0)
+ return SZ_ERROR_ARCHIVE;
+ return SZ_OK;
+}
+
+
+
+
+static SRes XzDecMix_Init(CMixCoder *p, const CXzBlock *block, Byte *outBuf, size_t outBufSize)
+{
+ unsigned i;
+ Bool needReInit = True;
+ unsigned numFilters = XzBlock_GetNumFilters(block);
+
+ if (numFilters == p->numCoders && ((p->outBuf && outBuf) || (!p->outBuf && !outBuf)))
+ {
+ needReInit = False;
+ for (i = 0; i < numFilters; i++)
+ if (p->ids[i] != block->filters[numFilters - 1 - i].id)
+ {
+ needReInit = True;
+ break;
+ }
+ }
+
+ // p->SingleBufMode = (outBuf != NULL);
+ p->outBuf = outBuf;
+ p->outBufSize = outBufSize;
+
+ // p->SingleBufMode = False;
+ // outBuf = NULL;
+
+ if (needReInit)
+ {
+ MixCoder_Free(p);
+ for (i = 0; i < numFilters; i++)
+ {
+ RINOK(MixCoder_SetFromMethod(p, i, block->filters[numFilters - 1 - i].id, outBuf, outBufSize));
+ }
+ p->numCoders = numFilters;
+ }
+ else
+ {
+ RINOK(MixCoder_ResetFromMethod(p, 0, block->filters[numFilters - 1].id, outBuf, outBufSize));
+ }
+
+ for (i = 0; i < numFilters; i++)
+ {
+ const CXzFilter *f = &block->filters[numFilters - 1 - i];
+ IStateCoder *sc = &p->coders[i];
+ RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc));
+ }
+
+ MixCoder_Init(p);
+ return SZ_OK;
+}
+
+
+
+void XzUnpacker_Init(CXzUnpacker *p)
+{
+ p->state = XZ_STATE_STREAM_HEADER;
+ p->pos = 0;
+ p->numStartedStreams = 0;
+ p->numFinishedStreams = 0;
+ p->numTotalBlocks = 0;
+ p->padSize = 0;
+ p->decodeOnlyOneBlock = 0;
+
+ p->parseMode = False;
+ p->decodeToStreamSignature = False;
+
+ // p->outBuf = NULL;
+ // p->outBufSize = 0;
+ p->outDataWritten = 0;
+}
+
+
+void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize)
+{
+ p->outBuf = outBuf;
+ p->outBufSize = outBufSize;
+}
+
+
+void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc)
+{
+ MixCoder_Construct(&p->decoder, alloc);
+ p->outBuf = NULL;
+ p->outBufSize = 0;
+ XzUnpacker_Init(p);
+}
+
+
+void XzUnpacker_Free(CXzUnpacker *p)
+{
+ MixCoder_Free(&p->decoder);
+}
+
+
+void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p)
+{
+ p->indexSize = 0;
+ p->numBlocks = 0;
+ Sha256_Init(&p->sha);
+ p->state = XZ_STATE_BLOCK_HEADER;
+ p->pos = 0;
+ p->decodeOnlyOneBlock = 1;
+}
+
+
+static void XzUnpacker_UpdateIndex(CXzUnpacker *p, UInt64 packSize, UInt64 unpackSize)
+{
+ Byte temp[32];
+ unsigned num = Xz_WriteVarInt(temp, packSize);
+ num += Xz_WriteVarInt(temp + num, unpackSize);
+ Sha256_Update(&p->sha, temp, num);
+ p->indexSize += num;
+ p->numBlocks++;
+}
+
+
+
+SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, int srcFinished,
+ ECoderFinishMode finishMode, ECoderStatus *status)
+{
+ SizeT destLenOrig = *destLen;
+ SizeT srcLenOrig = *srcLen;
+ *destLen = 0;
+ *srcLen = 0;
+ *status = CODER_STATUS_NOT_SPECIFIED;
+
+ for (;;)
+ {
+ SizeT srcRem;
+
+ if (p->state == XZ_STATE_BLOCK)
+ {
+ SizeT destLen2 = destLenOrig - *destLen;
+ SizeT srcLen2 = srcLenOrig - *srcLen;
+ SRes res;
+
+ ECoderFinishMode finishMode2 = finishMode;
+ Bool srcFinished2 = srcFinished;
+ Bool destFinish = False;
+
+ if (p->block.packSize != (UInt64)(Int64)-1)
+ {
+ UInt64 rem = p->block.packSize - p->packSize;
+ if (srcLen2 >= rem)
+ {
+ srcFinished2 = True;
+ srcLen2 = (SizeT)rem;
+ }
+ if (rem == 0 && p->block.unpackSize == p->unpackSize)
+ return SZ_ERROR_DATA;
+ }
+
+ if (p->block.unpackSize != (UInt64)(Int64)-1)
+ {
+ UInt64 rem = p->block.unpackSize - p->unpackSize;
+ if (destLen2 >= rem)
+ {
+ destFinish = True;
+ finishMode2 = CODER_FINISH_END;
+ destLen2 = (SizeT)rem;
+ }
+ }
+
+ /*
+ if (srcLen2 == 0 && destLen2 == 0)
+ {
+ *status = CODER_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+ */
+
+ {
+ res = MixCoder_Code(&p->decoder,
+ (p->outBuf ? NULL : dest), &destLen2, destFinish,
+ src, &srcLen2, srcFinished2,
+ finishMode2);
+
+ *status = p->decoder.status;
+ XzCheck_Update(&p->check, (p->outBuf ? p->outBuf + p->outDataWritten : dest), destLen2);
+ if (!p->outBuf)
+ dest += destLen2;
+ p->outDataWritten += destLen2;
+ }
+
+ (*srcLen) += srcLen2;
+ src += srcLen2;
+ p->packSize += srcLen2;
+ (*destLen) += destLen2;
+ p->unpackSize += destLen2;
+
+ RINOK(res);
+
+ if (*status != CODER_STATUS_FINISHED_WITH_MARK)
+ {
+ if (p->block.packSize == p->packSize
+ && *status == CODER_STATUS_NEEDS_MORE_INPUT)
+ {
+ PRF_STR("CODER_STATUS_NEEDS_MORE_INPUT");
+ *status = CODER_STATUS_NOT_SPECIFIED;
+ return SZ_ERROR_DATA;
+ }
+
+ return SZ_OK;
+ }
+ {
+ XzUnpacker_UpdateIndex(p, XzUnpacker_GetPackSizeForIndex(p), p->unpackSize);
+ p->state = XZ_STATE_BLOCK_FOOTER;
+ p->pos = 0;
+ p->alignPos = 0;
+ *status = CODER_STATUS_NOT_SPECIFIED;
+
+ if ((p->block.packSize != (UInt64)(Int64)-1 && p->block.packSize != p->packSize)
+ || (p->block.unpackSize != (UInt64)(Int64)-1 && p->block.unpackSize != p->unpackSize))
+ {
+ PRF_STR("ERROR: block.size mismatch");
+ return SZ_ERROR_DATA;
+ }
+ }
+ // continue;
+ }
+
+ srcRem = srcLenOrig - *srcLen;
+
+ // XZ_STATE_BLOCK_FOOTER can transit to XZ_STATE_BLOCK_HEADER without input bytes
+ if (srcRem == 0 && p->state != XZ_STATE_BLOCK_FOOTER)
+ {
+ *status = CODER_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+
+ switch (p->state)
+ {
+ case XZ_STATE_STREAM_HEADER:
+ {
+ if (p->pos < XZ_STREAM_HEADER_SIZE)
+ {
+ if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos])
+ return SZ_ERROR_NO_ARCHIVE;
+ if (p->decodeToStreamSignature)
+ return SZ_OK;
+ p->buf[p->pos++] = *src++;
+ (*srcLen)++;
+ }
+ else
+ {
+ RINOK(Xz_ParseHeader(&p->streamFlags, p->buf));
+ p->numStartedStreams++;
+ p->indexSize = 0;
+ p->numBlocks = 0;
+ Sha256_Init(&p->sha);
+ p->state = XZ_STATE_BLOCK_HEADER;
+ p->pos = 0;
+ }
+ break;
+ }
+
+ case XZ_STATE_BLOCK_HEADER:
+ {
+ if (p->pos == 0)
+ {
+ p->buf[p->pos++] = *src++;
+ (*srcLen)++;
+ if (p->buf[0] == 0)
+ {
+ if (p->decodeOnlyOneBlock)
+ return SZ_ERROR_DATA;
+ p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks);
+ p->indexPos = p->indexPreSize;
+ p->indexSize += p->indexPreSize;
+ Sha256_Final(&p->sha, p->shaDigest);
+ Sha256_Init(&p->sha);
+ p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize);
+ p->state = XZ_STATE_STREAM_INDEX;
+ break;
+ }
+ p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4;
+ break;
+ }
+
+ if (p->pos != p->blockHeaderSize)
+ {
+ UInt32 cur = p->blockHeaderSize - p->pos;
+ if (cur > srcRem)
+ cur = (UInt32)srcRem;
+ memcpy(p->buf + p->pos, src, cur);
+ p->pos += cur;
+ (*srcLen) += cur;
+ src += cur;
+ }
+ else
+ {
+ RINOK(XzBlock_Parse(&p->block, p->buf));
+ if (!XzBlock_AreSupportedFilters(&p->block))
+ return SZ_ERROR_UNSUPPORTED;
+ p->numTotalBlocks++;
+ p->state = XZ_STATE_BLOCK;
+ p->packSize = 0;
+ p->unpackSize = 0;
+ XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags));
+ if (p->parseMode)
+ {
+ p->headerParsedOk = True;
+ return SZ_OK;
+ }
+ RINOK(XzDecMix_Init(&p->decoder, &p->block, p->outBuf, p->outBufSize));
+ }
+ break;
+ }
+
+ case XZ_STATE_BLOCK_FOOTER:
+ {
+ if ((((unsigned)p->packSize + p->alignPos) & 3) != 0)
+ {
+ if (srcRem == 0)
+ {
+ *status = CODER_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ (*srcLen)++;
+ p->alignPos++;
+ if (*src++ != 0)
+ return SZ_ERROR_CRC;
+ }
+ else
+ {
+ UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags);
+ UInt32 cur = checkSize - p->pos;
+ if (cur != 0)
+ {
+ if (srcRem == 0)
+ {
+ *status = CODER_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (cur > srcRem)
+ cur = (UInt32)srcRem;
+ memcpy(p->buf + p->pos, src, cur);
+ p->pos += cur;
+ (*srcLen) += cur;
+ src += cur;
+ if (checkSize != p->pos)
+ break;
+ }
+ {
+ Byte digest[XZ_CHECK_SIZE_MAX];
+ p->state = XZ_STATE_BLOCK_HEADER;
+ p->pos = 0;
+ if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0)
+ return SZ_ERROR_CRC;
+ if (p->decodeOnlyOneBlock)
+ {
+ *status = CODER_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+ }
+ }
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_INDEX:
+ {
+ if (p->pos < p->indexPreSize)
+ {
+ (*srcLen)++;
+ if (*src++ != p->buf[p->pos++])
+ return SZ_ERROR_CRC;
+ }
+ else
+ {
+ if (p->indexPos < p->indexSize)
+ {
+ UInt64 cur = p->indexSize - p->indexPos;
+ if (srcRem > cur)
+ srcRem = (SizeT)cur;
+ p->crc = CrcUpdate(p->crc, src, srcRem);
+ Sha256_Update(&p->sha, src, srcRem);
+ (*srcLen) += srcRem;
+ src += srcRem;
+ p->indexPos += srcRem;
+ }
+ else if ((p->indexPos & 3) != 0)
+ {
+ Byte b = *src++;
+ p->crc = CRC_UPDATE_BYTE(p->crc, b);
+ (*srcLen)++;
+ p->indexPos++;
+ p->indexSize++;
+ if (b != 0)
+ return SZ_ERROR_CRC;
+ }
+ else
+ {
+ Byte digest[SHA256_DIGEST_SIZE];
+ p->state = XZ_STATE_STREAM_INDEX_CRC;
+ p->indexSize += 4;
+ p->pos = 0;
+ Sha256_Final(&p->sha, digest);
+ if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0)
+ return SZ_ERROR_CRC;
+ }
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_INDEX_CRC:
+ {
+ if (p->pos < 4)
+ {
+ (*srcLen)++;
+ p->buf[p->pos++] = *src++;
+ }
+ else
+ {
+ p->state = XZ_STATE_STREAM_FOOTER;
+ p->pos = 0;
+ if (CRC_GET_DIGEST(p->crc) != GetUi32(p->buf))
+ return SZ_ERROR_CRC;
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_FOOTER:
+ {
+ UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos;
+ if (cur > srcRem)
+ cur = (UInt32)srcRem;
+ memcpy(p->buf + p->pos, src, cur);
+ p->pos += cur;
+ (*srcLen) += cur;
+ src += cur;
+ if (p->pos == XZ_STREAM_FOOTER_SIZE)
+ {
+ p->state = XZ_STATE_STREAM_PADDING;
+ p->numFinishedStreams++;
+ p->padSize = 0;
+ if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf))
+ return SZ_ERROR_CRC;
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_PADDING:
+ {
+ if (*src != 0)
+ {
+ if (((UInt32)p->padSize & 3) != 0)
+ return SZ_ERROR_NO_ARCHIVE;
+ p->pos = 0;
+ p->state = XZ_STATE_STREAM_HEADER;
+ }
+ else
+ {
+ (*srcLen)++;
+ src++;
+ p->padSize++;
+ }
+ break;
+ }
+
+ case XZ_STATE_BLOCK: break; /* to disable GCC warning */
+ }
+ }
+ /*
+ if (p->state == XZ_STATE_FINISHED)
+ *status = CODER_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+ */
+}
+
+
+SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen,
+ ECoderFinishMode finishMode, ECoderStatus *status)
+{
+ XzUnpacker_Init(p);
+ XzUnpacker_SetOutBuf(p, dest, *destLen);
+
+ return XzUnpacker_Code(p,
+ NULL, destLen,
+ src, srcLen, True,
+ finishMode, status);
+}
+
+
+Bool XzUnpacker_IsBlockFinished(const CXzUnpacker *p)
+{
+ return (p->state == XZ_STATE_BLOCK_HEADER) && (p->pos == 0);
+}
+
+Bool XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p)
+{
+ return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0);
+}
+
+UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p)
+{
+ UInt64 num = 0;
+ if (p->state == XZ_STATE_STREAM_PADDING)
+ num = p->padSize;
+ else if (p->state == XZ_STATE_STREAM_HEADER)
+ num = p->padSize + p->pos;
+ return num;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifndef _7ZIP_ST
+#include "MtDec.h"
+#endif
+
+
+void XzDecMtProps_Init(CXzDecMtProps *p)
+{
+ p->inBufSize_ST = 1 << 18;
+ p->outStep_ST = 1 << 20;
+ p->ignoreErrors = False;
+
+ #ifndef _7ZIP_ST
+ p->numThreads = 1;
+ p->inBufSize_MT = 1 << 18;
+ p->memUseMax = sizeof(size_t) << 28;
+ #endif
+}
+
+
+
+#ifndef _7ZIP_ST
+
+/* ---------- CXzDecMtThread ---------- */
+
+typedef struct
+{
+ Byte *outBuf;
+ size_t outBufSize;
+ size_t outPreSize;
+ size_t inPreSize;
+ size_t inPreHeaderSize;
+ size_t blockPackSize_for_Index; // including block header and checksum.
+ size_t blockPackTotal; // including stream header, block header and checksum.
+ size_t inCodeSize;
+ size_t outCodeSize;
+ ECoderStatus status;
+ SRes codeRes;
+ Bool skipMode;
+ // Bool finishedWithMark;
+ EMtDecParseState parseState;
+ Bool parsing_Truncated;
+ Bool atBlockHeader;
+ CXzStreamFlags streamFlags;
+ // UInt64 numFinishedStreams
+ UInt64 numStreams;
+ UInt64 numTotalBlocks;
+ UInt64 numBlocks;
+
+ Bool dec_created;
+ CXzUnpacker dec;
+
+ Byte mtPad[1 << 7];
+} CXzDecMtThread;
+
+#endif
+
+
+/* ---------- CXzDecMt ---------- */
+
+typedef struct
+{
+ CAlignOffsetAlloc alignOffsetAlloc;
+ ISzAllocPtr allocMid;
+
+ CXzDecMtProps props;
+ size_t unpackBlockMaxSize;
+
+ ISeqInStream *inStream;
+ ISeqOutStream *outStream;
+ ICompressProgress *progress;
+ // CXzStatInfo *stat;
+
+ Bool finishMode;
+ Bool outSize_Defined;
+ UInt64 outSize;
+
+ UInt64 outProcessed;
+ UInt64 inProcessed;
+ UInt64 readProcessed;
+ Bool readWasFinished;
+ SRes readRes;
+ SRes writeRes;
+
+ Byte *outBuf;
+ size_t outBufSize;
+ Byte *inBuf;
+ size_t inBufSize;
+ Bool dec_created;
+ CXzUnpacker dec;
+
+ ECoderStatus status;
+ SRes codeRes;
+
+ #ifndef _7ZIP_ST
+ Bool mainDecoderWasCalled;
+ // int statErrorDefined;
+ int finishedDecoderIndex;
+
+ // global values that are used in Parse stage
+ CXzStreamFlags streamFlags;
+ // UInt64 numFinishedStreams
+ UInt64 numStreams;
+ UInt64 numTotalBlocks;
+ UInt64 numBlocks;
+
+ // UInt64 numBadBlocks;
+ SRes mainErrorCode;
+
+ Bool isBlockHeaderState_Parse;
+ Bool isBlockHeaderState_Write;
+ UInt64 outProcessed_Parse;
+ Bool parsing_Truncated;
+
+ Bool mtc_WasConstructed;
+ CMtDec mtc;
+ CXzDecMtThread coders[MTDEC__THREADS_MAX];
+ #endif
+
+} CXzDecMt;
+
+
+
+CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid)
+{
+ CXzDecMt *p = (CXzDecMt *)ISzAlloc_Alloc(alloc, sizeof(CXzDecMt));
+ if (!p)
+ return NULL;
+
+ AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc);
+ p->alignOffsetAlloc.baseAlloc = alloc;
+ p->alignOffsetAlloc.numAlignBits = 7;
+ p->alignOffsetAlloc.offset = 0;
+
+ p->allocMid = allocMid;
+
+ p->outBuf = NULL;
+ p->outBufSize = 0;
+ p->inBuf = NULL;
+ p->inBufSize = 0;
+ p->dec_created = False;
+
+ p->unpackBlockMaxSize = 0;
+
+ XzDecMtProps_Init(&p->props);
+
+ #ifndef _7ZIP_ST
+ p->mtc_WasConstructed = False;
+ {
+ unsigned i;
+ for (i = 0; i < MTDEC__THREADS_MAX; i++)
+ {
+ CXzDecMtThread *coder = &p->coders[i];
+ coder->dec_created = False;
+ coder->outBuf = NULL;
+ coder->outBufSize = 0;
+ }
+ }
+ #endif
+
+ return p;
+}
+
+
+#ifndef _7ZIP_ST
+
+static void XzDecMt_FreeOutBufs(CXzDecMt *p)
+{
+ unsigned i;
+ for (i = 0; i < MTDEC__THREADS_MAX; i++)
+ {
+ CXzDecMtThread *coder = &p->coders[i];
+ if (coder->outBuf)
+ {
+ ISzAlloc_Free(p->allocMid, coder->outBuf);
+ coder->outBuf = NULL;
+ coder->outBufSize = 0;
+ }
+ }
+ p->unpackBlockMaxSize = 0;
+}
+
+#endif
+
+
+
+static void XzDecMt_FreeSt(CXzDecMt *p)
+{
+ if (p->dec_created)
+ {
+ XzUnpacker_Free(&p->dec);
+ p->dec_created = False;
+ }
+
+ if (p->outBuf)
+ {
+ ISzAlloc_Free(p->allocMid, p->outBuf);
+ p->outBuf = NULL;
+ }
+ p->outBufSize = 0;
+
+ if (p->inBuf)
+ {
+ ISzAlloc_Free(p->allocMid, p->inBuf);
+ p->inBuf = NULL;
+ }
+ p->inBufSize = 0;
+}
+
+
+void XzDecMt_Destroy(CXzDecMtHandle pp)
+{
+ CXzDecMt *p = (CXzDecMt *)pp;
+
+ XzDecMt_FreeSt(p);
+
+ #ifndef _7ZIP_ST
+
+ if (p->mtc_WasConstructed)
+ {
+ MtDec_Destruct(&p->mtc);
+ p->mtc_WasConstructed = False;
+ }
+ {
+ unsigned i;
+ for (i = 0; i < MTDEC__THREADS_MAX; i++)
+ {
+ CXzDecMtThread *t = &p->coders[i];
+ if (t->dec_created)
+ {
+ // we don't need to free dict here
+ XzUnpacker_Free(&t->dec);
+ t->dec_created = False;
+ }
+ }
+ }
+ XzDecMt_FreeOutBufs(p);
+
+ #endif
+
+ ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, pp);
+}
+
+
+
+#ifndef _7ZIP_ST
+
+static void XzDecMt_Callback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc)
+{
+ CXzDecMt *me = (CXzDecMt *)obj;
+ CXzDecMtThread *coder = &me->coders[coderIndex];
+ size_t srcSize = cc->srcSize;
+
+ cc->srcSize = 0;
+ cc->outPos = 0;
+ cc->state = MTDEC_PARSE_CONTINUE;
+
+ cc->canCreateNewThread = True;
+
+ if (cc->startCall)
+ {
+ coder->outPreSize = 0;
+ coder->inPreSize = 0;
+ coder->inPreHeaderSize = 0;
+ coder->parseState = MTDEC_PARSE_CONTINUE;
+ coder->parsing_Truncated = False;
+ coder->skipMode = False;
+ coder->codeRes = SZ_OK;
+ coder->status = CODER_STATUS_NOT_SPECIFIED;
+ coder->inCodeSize = 0;
+ coder->outCodeSize = 0;
+
+ coder->numStreams = me->numStreams;
+ coder->numTotalBlocks = me->numTotalBlocks;
+ coder->numBlocks = me->numBlocks;
+
+ if (!coder->dec_created)
+ {
+ XzUnpacker_Construct(&coder->dec, &me->alignOffsetAlloc.vt);
+ coder->dec_created = True;
+ }
+
+ XzUnpacker_Init(&coder->dec);
+
+ if (me->isBlockHeaderState_Parse)
+ {
+ coder->dec.streamFlags = me->streamFlags;
+ coder->atBlockHeader = True;
+ XzUnpacker_PrepareToRandomBlockDecoding(&coder->dec);
+ }
+ else
+ {
+ coder->atBlockHeader = False;
+ me->isBlockHeaderState_Parse = True;
+ }
+
+ coder->dec.numStartedStreams = me->numStreams;
+ coder->dec.numTotalBlocks = me->numTotalBlocks;
+ coder->dec.numBlocks = me->numBlocks;
+ }
+
+ while (!coder->skipMode)
+ {
+ ECoderStatus status;
+ SRes res;
+ size_t srcSize2 = srcSize;
+ size_t destSize = (size_t)0 - 1;
+
+ coder->dec.parseMode = True;
+ coder->dec.headerParsedOk = False;
+
+ PRF_STR_INT("Parse", srcSize2);
+
+ res = XzUnpacker_Code(&coder->dec,
+ NULL, &destSize,
+ cc->src, &srcSize2, cc->srcFinished,
+ CODER_FINISH_END, &status);
+
+ // PRF(printf(" res = %d, srcSize2 = %d", res, (unsigned)srcSize2));
+
+ coder->codeRes = res;
+ coder->status = status;
+ cc->srcSize += srcSize2;
+ srcSize -= srcSize2;
+ coder->inPreHeaderSize += srcSize2;
+ coder->inPreSize = coder->inPreHeaderSize;
+
+ if (res != SZ_OK)
+ {
+ cc->state =
+ coder->parseState = MTDEC_PARSE_END;
+ /*
+ if (res == SZ_ERROR_MEM)
+ return res;
+ return SZ_OK;
+ */
+ return; // res;
+ }
+
+ if (coder->dec.headerParsedOk)
+ {
+ const CXzBlock *block = &coder->dec.block;
+ if (XzBlock_HasUnpackSize(block)
+ // && block->unpackSize <= me->props.outBlockMax
+ && XzBlock_HasPackSize(block))
+ {
+ {
+ if (block->unpackSize * 2 * me->mtc.numStartedThreads > me->props.memUseMax)
+ {
+ cc->state = MTDEC_PARSE_OVERFLOW;
+ return; // SZ_OK;
+ }
+ }
+ {
+ UInt64 packSize = block->packSize;
+ UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3);
+ UInt32 checkSize = XzFlags_GetCheckSize(coder->dec.streamFlags);
+ UInt64 blockPackSum = coder->inPreSize + packSizeAligned + checkSize;
+ // if (blockPackSum <= me->props.inBlockMax)
+ // unpackBlockMaxSize
+ {
+ coder->blockPackSize_for_Index = (size_t)(coder->dec.blockHeaderSize + packSize + checkSize);
+ coder->blockPackTotal = (size_t)blockPackSum;
+ coder->outPreSize = (size_t)block->unpackSize;
+ coder->streamFlags = coder->dec.streamFlags;
+ me->streamFlags = coder->dec.streamFlags;
+ coder->skipMode = True;
+ break;
+ }
+ }
+ }
+ }
+ else
+ // if (coder->inPreSize <= me->props.inBlockMax)
+ {
+ if (!cc->srcFinished)
+ return; // SZ_OK;
+ cc->state =
+ coder->parseState = MTDEC_PARSE_END;
+ return; // SZ_OK;
+ }
+ cc->state = MTDEC_PARSE_OVERFLOW;
+ return; // SZ_OK;
+ }
+
+ // ---------- skipMode ----------
+ {
+ UInt64 rem = coder->blockPackTotal - coder->inPreSize;
+ size_t cur = srcSize;
+ if (cur > rem)
+ cur = (size_t)rem;
+ cc->srcSize += cur;
+ coder->inPreSize += cur;
+ srcSize -= cur;
+
+ if (coder->inPreSize == coder->blockPackTotal)
+ {
+ if (srcSize == 0)
+ {
+ if (!cc->srcFinished)
+ return; // SZ_OK;
+ cc->state = MTDEC_PARSE_END;
+ }
+ else if ((cc->src)[cc->srcSize] == 0) // we check control byte of next block
+ cc->state = MTDEC_PARSE_END;
+ else
+ {
+ cc->state = MTDEC_PARSE_NEW;
+
+ {
+ size_t blockMax = me->unpackBlockMaxSize;
+ if (blockMax < coder->outPreSize)
+ blockMax = coder->outPreSize;
+ {
+ UInt64 required = (UInt64)blockMax * (me->mtc.numStartedThreads + 1) * 2;
+ if (me->props.memUseMax < required)
+ cc->canCreateNewThread = False;
+ }
+ }
+
+ if (me->outSize_Defined)
+ {
+ // next block can be zero size
+ const UInt64 rem2 = me->outSize - me->outProcessed_Parse;
+ if (rem2 < coder->outPreSize)
+ {
+ coder->parsing_Truncated = True;
+ cc->state = MTDEC_PARSE_END;
+ }
+ me->outProcessed_Parse += coder->outPreSize;
+ }
+ }
+ }
+ else if (cc->srcFinished)
+ cc->state = MTDEC_PARSE_END;
+ else
+ return; // SZ_OK;
+
+ coder->parseState = cc->state;
+ cc->outPos = coder->outPreSize;
+
+ me->numStreams = coder->dec.numStartedStreams;
+ me->numTotalBlocks = coder->dec.numTotalBlocks;
+ me->numBlocks = coder->dec.numBlocks + 1;
+ return; // SZ_OK;
+ }
+}
+
+
+static SRes XzDecMt_Callback_PreCode(void *pp, unsigned coderIndex)
+{
+ CXzDecMt *me = (CXzDecMt *)pp;
+ CXzDecMtThread *coder = &me->coders[coderIndex];
+ Byte *dest;
+
+ if (!coder->dec.headerParsedOk)
+ return SZ_OK;
+
+ dest = coder->outBuf;
+
+ if (!dest || coder->outBufSize < coder->outPreSize)
+ {
+ if (dest)
+ {
+ ISzAlloc_Free(me->allocMid, dest);
+ coder->outBuf = NULL;
+ coder->outBufSize = 0;
+ }
+ {
+ size_t outPreSize = coder->outPreSize;
+ if (outPreSize == 0)
+ outPreSize = 1;
+ dest = (Byte *)ISzAlloc_Alloc(me->allocMid, outPreSize);
+ }
+ if (!dest)
+ return SZ_ERROR_MEM;
+ coder->outBuf = dest;
+ coder->outBufSize = coder->outPreSize;
+
+ if (coder->outBufSize > me->unpackBlockMaxSize)
+ me->unpackBlockMaxSize = coder->outBufSize;
+ }
+
+ // return SZ_ERROR_MEM;
+
+ XzUnpacker_SetOutBuf(&coder->dec, coder->outBuf, coder->outBufSize);
+
+ {
+ SRes res = XzDecMix_Init(&coder->dec.decoder, &coder->dec.block, coder->outBuf, coder->outBufSize);
+ // res = SZ_ERROR_UNSUPPORTED; // to test
+ coder->codeRes = res;
+ if (res != SZ_OK)
+ {
+ // if (res == SZ_ERROR_MEM) return res;
+ if (me->props.ignoreErrors && res != SZ_ERROR_MEM)
+ return S_OK;
+ return res;
+ }
+ }
+
+ return SZ_OK;
+}
+
+
+static SRes XzDecMt_Callback_Code(void *pp, unsigned coderIndex,
+ const Byte *src, size_t srcSize, int srcFinished,
+ // int finished, int blockFinished,
+ UInt64 *inCodePos, UInt64 *outCodePos, int *stop)
+{
+ CXzDecMt *me = (CXzDecMt *)pp;
+ CXzDecMtThread *coder = &me->coders[coderIndex];
+
+ *inCodePos = coder->inCodeSize;
+ *outCodePos = coder->outCodeSize;
+ *stop = True;
+
+ if (coder->inCodeSize < coder->inPreHeaderSize)
+ {
+ UInt64 rem = coder->inPreHeaderSize - coder->inCodeSize;
+ size_t step = srcSize;
+ if (step > rem)
+ step = (size_t)rem;
+ src += step;
+ srcSize -= step;
+ coder->inCodeSize += step;
+ if (coder->inCodeSize < coder->inPreHeaderSize)
+ {
+ *stop = False;
+ return SZ_OK;
+ }
+ }
+
+ if (!coder->dec.headerParsedOk)
+ return SZ_OK;
+ if (!coder->outBuf)
+ return SZ_OK;
+
+ if (coder->codeRes == SZ_OK)
+ {
+ ECoderStatus status;
+ SRes res;
+ size_t srcProcessed = srcSize;
+ size_t outSizeCur = coder->outPreSize - coder->dec.outDataWritten;
+
+ // PRF(printf("\nCallback_Code: Code %d %d\n", (unsigned)srcSize, (unsigned)outSizeCur));
+
+ res = XzUnpacker_Code(&coder->dec,
+ NULL, &outSizeCur,
+ src, &srcProcessed, srcFinished,
+ // coder->finishedWithMark ? CODER_FINISH_END : CODER_FINISH_ANY,
+ CODER_FINISH_END,
+ &status);
+
+ // PRF(printf(" res = %d, srcSize2 = %d, outSizeCur = %d", res, (unsigned)srcProcessed, (unsigned)outSizeCur));
+
+ coder->codeRes = res;
+ coder->status = status;
+ coder->inCodeSize += srcProcessed;
+ coder->outCodeSize = coder->dec.outDataWritten;
+ *inCodePos = coder->inCodeSize;
+ *outCodePos = coder->outCodeSize;
+
+ if (res == SZ_OK)
+ {
+ if (srcProcessed == srcSize)
+ *stop = False;
+ return SZ_OK;
+ }
+ }
+
+ if (me->props.ignoreErrors && coder->codeRes != SZ_ERROR_MEM)
+ {
+ *inCodePos = coder->inPreSize;
+ *outCodePos = coder->outPreSize;
+ return S_OK;
+ }
+ return coder->codeRes;
+}
+
+
+#define XZDECMT_STREAM_WRITE_STEP (1 << 24)
+
+static SRes XzDecMt_Callback_Write(void *pp, unsigned coderIndex,
+ Bool needWriteToStream,
+ const Byte *src, size_t srcSize,
+ // int srcFinished,
+ Bool *needContinue,
+ Bool *canRecode)
+{
+ CXzDecMt *me = (CXzDecMt *)pp;
+ const CXzDecMtThread *coder = &me->coders[coderIndex];
+
+ // PRF(printf("\nWrite processed = %d srcSize = %d\n", (unsigned)me->mtc.inProcessed, (unsigned)srcSize));
+
+ *needContinue = False;
+ *canRecode = True;
+
+ if (!needWriteToStream)
+ return SZ_OK;
+
+ if (!coder->dec.headerParsedOk || !coder->outBuf)
+ {
+ if (me->finishedDecoderIndex < 0)
+ me->finishedDecoderIndex = coderIndex;
+ return SZ_OK;
+ }
+
+ if (me->finishedDecoderIndex >= 0)
+ return SZ_OK;
+
+ me->mtc.inProcessed += coder->inCodeSize;
+
+ *canRecode = False;
+
+ {
+ SRes res;
+ size_t size = coder->outCodeSize;
+ Byte *data = coder->outBuf;
+
+ // we use in me->dec: sha, numBlocks, indexSize
+
+ if (!me->isBlockHeaderState_Write)
+ {
+ XzUnpacker_PrepareToRandomBlockDecoding(&me->dec);
+ me->dec.decodeOnlyOneBlock = False;
+ me->dec.numStartedStreams = coder->dec.numStartedStreams;
+ me->dec.streamFlags = coder->streamFlags;
+
+ me->isBlockHeaderState_Write = True;
+ }
+
+ me->dec.numTotalBlocks = coder->dec.numTotalBlocks;
+ XzUnpacker_UpdateIndex(&me->dec, coder->blockPackSize_for_Index, coder->outPreSize);
+
+ if (coder->outPreSize != size)
+ {
+ if (me->props.ignoreErrors)
+ {
+ memset(data + size, 0, coder->outPreSize - size);
+ size = coder->outPreSize;
+ }
+ // me->numBadBlocks++;
+ if (me->mainErrorCode == SZ_OK)
+ {
+ if ((int)coder->status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ me->mainErrorCode = SZ_ERROR_INPUT_EOF;
+ else
+ me->mainErrorCode = SZ_ERROR_DATA;
+ }
+ }
+
+ if (me->writeRes != SZ_OK)
+ return me->writeRes;
+
+ res = SZ_OK;
+ {
+ if (me->outSize_Defined)
+ {
+ const UInt64 rem = me->outSize - me->outProcessed;
+ if (size > rem)
+ size = (SizeT)rem;
+ }
+
+ for (;;)
+ {
+ size_t cur = size;
+ size_t written;
+ if (cur > XZDECMT_STREAM_WRITE_STEP)
+ cur = XZDECMT_STREAM_WRITE_STEP;
+
+ written = ISeqOutStream_Write(me->outStream, data, cur);
+
+ // PRF(printf("\nWritten ask = %d written = %d\n", (unsigned)cur, (unsigned)written));
+
+ me->outProcessed += written;
+ if (written != cur)
+ {
+ me->writeRes = SZ_ERROR_WRITE;
+ res = me->writeRes;
+ break;
+ }
+ data += cur;
+ size -= cur;
+ // PRF_STR_INT("Written size =", size);
+ if (size == 0)
+ break;
+ res = MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0);
+ if (res != SZ_OK)
+ break;
+ }
+ }
+
+ if (coder->codeRes != SZ_OK)
+ if (!me->props.ignoreErrors)
+ {
+ me->finishedDecoderIndex = coderIndex;
+ return res;
+ }
+
+ RINOK(res);
+
+ if (coder->inPreSize != coder->inCodeSize
+ || coder->blockPackTotal != coder->inCodeSize)
+ {
+ me->finishedDecoderIndex = coderIndex;
+ return SZ_OK;
+ }
+
+ if (coder->parseState != MTDEC_PARSE_END)
+ {
+ *needContinue = True;
+ return SZ_OK;
+ }
+ }
+
+ // (coder->state == MTDEC_PARSE_END) means that there are no other working threads
+ // so we can use mtc variables without lock
+
+ PRF_STR_INT("Write MTDEC_PARSE_END", me->mtc.inProcessed);
+
+ me->mtc.mtProgress.totalInSize = me->mtc.inProcessed;
+ {
+ CXzUnpacker *dec = &me->dec;
+
+ PRF_STR_INT("PostSingle", srcSize);
+
+ {
+ size_t srcProcessed = srcSize;
+ ECoderStatus status;
+ size_t outSizeCur = 0;
+ SRes res;
+
+ // dec->decodeOnlyOneBlock = False;
+ dec->decodeToStreamSignature = True;
+
+ me->mainDecoderWasCalled = True;
+
+ if (coder->parsing_Truncated)
+ {
+ me->parsing_Truncated = True;
+ return SZ_OK;
+ }
+
+ res = XzUnpacker_Code(dec,
+ NULL, &outSizeCur,
+ src, &srcProcessed,
+ me->mtc.readWasFinished, // srcFinished
+ CODER_FINISH_END, // CODER_FINISH_ANY,
+ &status);
+
+ me->status = status;
+ me->codeRes = res;
+
+ me->mtc.inProcessed += srcProcessed;
+ me->mtc.mtProgress.totalInSize = me->mtc.inProcessed;
+
+ if (res != SZ_OK)
+ {
+ return S_OK;
+ // return res;
+ }
+
+ if (dec->state == XZ_STATE_STREAM_HEADER)
+ {
+ *needContinue = True;
+ me->isBlockHeaderState_Parse = False;
+ me->isBlockHeaderState_Write = False;
+ {
+ Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc);
+ if (!crossBuf)
+ return SZ_ERROR_MEM;
+ memcpy(crossBuf, src + srcProcessed, srcSize - srcProcessed);
+ }
+ me->mtc.crossStart = 0;
+ me->mtc.crossEnd = srcSize - srcProcessed;
+ return SZ_OK;
+ }
+
+ if (status != CODER_STATUS_NEEDS_MORE_INPUT)
+ {
+ return E_FAIL;
+ }
+
+ if (me->mtc.readWasFinished)
+ {
+ return SZ_OK;
+ }
+ }
+
+ {
+ size_t inPos;
+ size_t inLim;
+ const Byte *inData;
+ UInt64 inProgressPrev = me->mtc.inProcessed;
+
+ // XzDecMt_Prepare_InBuf_ST(p);
+ Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc);
+ if (!crossBuf)
+ return SZ_ERROR_MEM;
+
+ inPos = 0;
+ inLim = 0;
+ // outProcessed = 0;
+
+ inData = crossBuf;
+
+ for (;;)
+ {
+ SizeT inProcessed;
+ SizeT outProcessed;
+ ECoderStatus status;
+ SRes res;
+
+ if (inPos == inLim)
+ {
+ if (!me->mtc.readWasFinished)
+ {
+ inPos = 0;
+ inLim = me->mtc.inBufSize;
+ me->mtc.readRes = ISeqInStream_Read(me->inStream, (void *)inData, &inLim);
+ me->mtc.readProcessed += inLim;
+ if (inLim == 0 || me->mtc.readRes != SZ_OK)
+ me->mtc.readWasFinished = True;
+ }
+ }
+
+ inProcessed = inLim - inPos;
+ outProcessed = 0;
+
+ res = XzUnpacker_Code(dec,
+ NULL, &outProcessed,
+ inData + inPos, &inProcessed,
+ (inProcessed == 0), // srcFinished
+ CODER_FINISH_END, &status);
+
+ me->codeRes = res;
+ me->status = status;
+ inPos += inProcessed;
+ me->mtc.inProcessed += inProcessed;
+ me->mtc.mtProgress.totalInSize = me->mtc.inProcessed;
+
+ if (res != SZ_OK)
+ {
+ return S_OK;
+ // return res;
+ }
+
+ if (dec->state == XZ_STATE_STREAM_HEADER)
+ {
+ *needContinue = True;
+ me->mtc.crossStart = inPos;
+ me->mtc.crossEnd = inLim;
+ me->isBlockHeaderState_Parse = False;
+ me->isBlockHeaderState_Write = False;
+ return SZ_OK;
+ }
+
+ if (status != CODER_STATUS_NEEDS_MORE_INPUT)
+ return E_FAIL;
+
+ if (me->mtc.progress)
+ {
+ UInt64 inDelta = me->mtc.inProcessed - inProgressPrev;
+ if (inDelta >= (1 << 22))
+ {
+ RINOK(MtProgress_Progress_ST(&me->mtc.mtProgress));
+ inProgressPrev = me->mtc.inProcessed;
+ }
+ }
+ if (me->mtc.readWasFinished)
+ return SZ_OK;
+ }
+ }
+ }
+}
+
+
+#endif
+
+
+
+void XzStatInfo_Clear(CXzStatInfo *p)
+{
+ p->InSize = 0;
+ p->OutSize = 0;
+
+ p->NumStreams = 0;
+ p->NumBlocks = 0;
+
+ p->UnpackSize_Defined = False;
+
+ p->NumStreams_Defined = False;
+ p->NumBlocks_Defined = False;
+
+ // p->IsArc = False;
+ // p->UnexpectedEnd = False;
+ // p->Unsupported = False;
+ // p->HeadersError = False;
+ // p->DataError = False;
+ // p->CrcError = False;
+
+ p->DataAfterEnd = False;
+ p->DecodingTruncated = False;
+
+ p->DecodeRes = SZ_OK;
+ p->ReadRes = SZ_OK;
+ p->ProgressRes = SZ_OK;
+
+ p->CombinedRes = SZ_OK;
+ p->CombinedRes_Type = SZ_OK;
+}
+
+
+
+
+static SRes XzDecMt_Decode_ST(CXzDecMt *p
+ #ifndef _7ZIP_ST
+ , Bool tMode
+ #endif
+ , CXzStatInfo *stat)
+{
+ size_t outPos;
+ size_t inPos, inLim;
+ const Byte *inData;
+ UInt64 inPrev, outPrev;
+
+ CXzUnpacker *dec;
+
+ #ifndef _7ZIP_ST
+ if (tMode)
+ {
+ XzDecMt_FreeOutBufs(p);
+ tMode = MtDec_PrepareRead(&p->mtc);
+ }
+ #endif
+
+ if (!p->outBuf || p->outBufSize != p->props.outStep_ST)
+ {
+ ISzAlloc_Free(p->allocMid, p->outBuf);
+ p->outBufSize = 0;
+ p->outBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.outStep_ST);
+ if (!p->outBuf)
+ return SZ_ERROR_MEM;
+ p->outBufSize = p->props.outStep_ST;
+ }
+
+ if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST)
+ {
+ ISzAlloc_Free(p->allocMid, p->inBuf);
+ p->inBufSize = 0;
+ p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST);
+ if (!p->inBuf)
+ return SZ_ERROR_MEM;
+ p->inBufSize = p->props.inBufSize_ST;
+ }
+
+ dec = &p->dec;
+ dec->decodeToStreamSignature = False;
+ // dec->decodeOnlyOneBlock = False;
+
+ XzUnpacker_SetOutBuf(dec, NULL, 0);
+
+ inPrev = p->inProcessed;
+ outPrev = p->outProcessed;
+
+ inPos = 0;
+ inLim = 0;
+ inData = NULL;
+ outPos = 0;
+
+ for (;;)
+ {
+ SizeT outSize;
+ Bool finished;
+ ECoderFinishMode finishMode;
+ SizeT inProcessed;
+ ECoderStatus status;
+ SRes res;
+
+ SizeT outProcessed;
+
+
+
+ if (inPos == inLim)
+ {
+ #ifndef _7ZIP_ST
+ if (tMode)
+ {
+ inData = MtDec_Read(&p->mtc, &inLim);
+ inPos = 0;
+ if (inData)
+ continue;
+ tMode = False;
+ inLim = 0;
+ }
+ #endif
+
+ if (!p->readWasFinished)
+ {
+ inPos = 0;
+ inLim = p->inBufSize;
+ inData = p->inBuf;
+ p->readRes = ISeqInStream_Read(p->inStream, (void *)inData, &inLim);
+ p->readProcessed += inLim;
+ if (inLim == 0 || p->readRes != SZ_OK)
+ p->readWasFinished = True;
+ }
+ }
+
+ outSize = p->props.outStep_ST - outPos;
+
+ finishMode = CODER_FINISH_ANY;
+ if (p->outSize_Defined)
+ {
+ const UInt64 rem = p->outSize - p->outProcessed;
+ if (outSize >= rem)
+ {
+ outSize = (SizeT)rem;
+ if (p->finishMode)
+ finishMode = CODER_FINISH_END;
+ }
+ }
+
+ inProcessed = inLim - inPos;
+ outProcessed = outSize;
+
+ res = XzUnpacker_Code(dec, p->outBuf + outPos, &outProcessed,
+ inData + inPos, &inProcessed,
+ (inPos == inLim), // srcFinished
+ finishMode, &status);
+
+ p->codeRes = res;
+ p->status = status;
+
+ inPos += inProcessed;
+ outPos += outProcessed;
+ p->inProcessed += inProcessed;
+ p->outProcessed += outProcessed;
+
+ finished = ((inProcessed == 0 && outProcessed == 0) || res != SZ_OK);
+
+ if (finished || outProcessed >= outSize)
+ if (outPos != 0)
+ {
+ size_t written = ISeqOutStream_Write(p->outStream, p->outBuf, outPos);
+ p->outProcessed += written;
+ if (written != outPos)
+ {
+ stat->CombinedRes_Type = SZ_ERROR_WRITE;
+ return SZ_ERROR_WRITE;
+ }
+ outPos = 0;
+ }
+
+ if (p->progress && res == SZ_OK)
+ {
+ UInt64 inDelta = p->inProcessed - inPrev;
+ UInt64 outDelta = p->outProcessed - outPrev;
+ if (inDelta >= (1 << 22) || outDelta >= (1 << 22))
+ {
+ res = ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed);
+ if (res != SZ_OK)
+ {
+ stat->CombinedRes_Type = SZ_ERROR_PROGRESS;
+ stat->ProgressRes = res;
+ return res;
+ }
+ inPrev = p->inProcessed;
+ outPrev = p->outProcessed;
+ }
+ }
+
+ if (finished)
+ return res;
+ }
+}
+
+static SRes XzStatInfo_SetStat(const CXzUnpacker *dec,
+ int finishMode,
+ UInt64 readProcessed, UInt64 inProcessed,
+ SRes res, ECoderStatus status,
+ Bool decodingTruncated,
+ CXzStatInfo *stat)
+{
+ UInt64 extraSize;
+
+ stat->DecodingTruncated = (Byte)(decodingTruncated ? 1 : 0);
+ stat->InSize = inProcessed;
+ stat->NumStreams = dec->numStartedStreams;
+ stat->NumBlocks = dec->numTotalBlocks;
+
+ stat->UnpackSize_Defined = True;
+ stat->NumStreams_Defined = True;
+ stat->NumBlocks_Defined = True;
+
+ extraSize = XzUnpacker_GetExtraSize(dec);
+
+ if (res == SZ_OK)
+ {
+ if (status == CODER_STATUS_NEEDS_MORE_INPUT)
+ {
+ // CODER_STATUS_NEEDS_MORE_INPUT is expected status for correct xz streams
+ extraSize = 0;
+ if (!XzUnpacker_IsStreamWasFinished(dec))
+ res = SZ_ERROR_INPUT_EOF;
+ }
+ else if (!decodingTruncated || finishMode) // (status == CODER_STATUS_NOT_FINISHED)
+ res = SZ_ERROR_DATA;
+ }
+ else if (res == SZ_ERROR_NO_ARCHIVE)
+ {
+ /*
+ SZ_ERROR_NO_ARCHIVE is possible for 2 states:
+ XZ_STATE_STREAM_HEADER - if bad signature or bad CRC
+ XZ_STATE_STREAM_PADDING - if non-zero padding data
+ extraSize / inProcessed don't include "bad" byte
+ */
+ if (inProcessed != extraSize) // if good streams before error
+ if (extraSize != 0 || readProcessed != inProcessed)
+ {
+ stat->DataAfterEnd = True;
+ // there is some good xz stream before. So we set SZ_OK
+ res = SZ_OK;
+ }
+ }
+
+ stat->DecodeRes = res;
+
+ stat->InSize -= extraSize;
+ return res;
+}
+
+
+SRes XzDecMt_Decode(CXzDecMtHandle pp,
+ const CXzDecMtProps *props,
+ const UInt64 *outDataSize, int finishMode,
+ ISeqOutStream *outStream,
+ // Byte *outBuf, size_t *outBufSize,
+ ISeqInStream *inStream,
+ // const Byte *inData, size_t inDataSize,
+ CXzStatInfo *stat,
+ int *isMT,
+ ICompressProgress *progress)
+{
+ CXzDecMt *p = (CXzDecMt *)pp;
+ #ifndef _7ZIP_ST
+ Bool tMode;
+ #endif
+
+ XzStatInfo_Clear(stat);
+
+ p->props = *props;
+
+ p->inStream = inStream;
+ p->outStream = outStream;
+ p->progress = progress;
+ // p->stat = stat;
+
+ p->outSize = 0;
+ p->outSize_Defined = False;
+ if (outDataSize)
+ {
+ p->outSize_Defined = True;
+ p->outSize = *outDataSize;
+ }
+
+ p->finishMode = finishMode;
+
+ // p->outSize = 457; p->outSize_Defined = True; p->finishMode = False; // for test
+
+ p->writeRes = SZ_OK;
+ p->outProcessed = 0;
+ p->inProcessed = 0;
+ p->readProcessed = 0;
+ p->readWasFinished = False;
+
+ p->codeRes = 0;
+ p->status = CODER_STATUS_NOT_SPECIFIED;
+
+ if (!p->dec_created)
+ {
+ XzUnpacker_Construct(&p->dec, &p->alignOffsetAlloc.vt);
+ p->dec_created = True;
+ }
+ XzUnpacker_Init(&p->dec);
+
+
+ *isMT = False;
+
+ /*
+ p->outBuf = NULL;
+ p->outBufSize = 0;
+ if (!outStream)
+ {
+ p->outBuf = outBuf;
+ p->outBufSize = *outBufSize;
+ *outBufSize = 0;
+ }
+ */
+
+
+ #ifndef _7ZIP_ST
+
+ p->isBlockHeaderState_Parse = False;
+ p->isBlockHeaderState_Write = False;
+ // p->numBadBlocks = 0;
+ p->mainErrorCode = SZ_OK;
+ p->mainDecoderWasCalled = False;
+
+ tMode = False;
+
+ if (p->props.numThreads > 1)
+ {
+ IMtDecCallback vt;
+
+ XzDecMt_FreeSt(p);
+
+ p->outProcessed_Parse = 0;
+ p->parsing_Truncated = False;
+
+ p->numStreams = 0;
+ p->numTotalBlocks = 0;
+ p->numBlocks = 0;
+ p->finishedDecoderIndex = -1;
+
+ if (!p->mtc_WasConstructed)
+ {
+ p->mtc_WasConstructed = True;
+ MtDec_Construct(&p->mtc);
+ }
+
+ p->mtc.mtCallback = &vt;
+ p->mtc.mtCallbackObject = p;
+
+ p->mtc.progress = progress;
+ p->mtc.inStream = inStream;
+ p->mtc.alloc = &p->alignOffsetAlloc.vt;
+ // p->mtc.inData = inData;
+ // p->mtc.inDataSize = inDataSize;
+ p->mtc.inBufSize = p->props.inBufSize_MT;
+ // p->mtc.inBlockMax = p->props.inBlockMax;
+ p->mtc.numThreadsMax = p->props.numThreads;
+
+ *isMT = True;
+
+ vt.Parse = XzDecMt_Callback_Parse;
+ vt.PreCode = XzDecMt_Callback_PreCode;
+ vt.Code = XzDecMt_Callback_Code;
+ vt.Write = XzDecMt_Callback_Write;
+
+ {
+ Bool needContinue;
+
+ SRes res = MtDec_Code(&p->mtc);
+
+ stat->InSize = p->mtc.inProcessed;
+
+ p->inProcessed = p->mtc.inProcessed;
+ p->readRes = p->mtc.readRes;
+ p->readWasFinished = p->mtc.readWasFinished;
+ p->readProcessed = p->mtc.readProcessed;
+
+ tMode = True;
+ needContinue = False;
+
+ if (res == SZ_OK)
+ {
+ if (p->mtc.mtProgress.res != SZ_OK)
+ {
+ res = p->mtc.mtProgress.res;
+ stat->ProgressRes = res;
+ stat->CombinedRes_Type = SZ_ERROR_PROGRESS;
+ }
+ else
+ needContinue = p->mtc.needContinue;
+ }
+
+ if (!needContinue)
+ {
+ SRes codeRes;
+ Bool truncated = False;
+ ECoderStatus status;
+ CXzUnpacker *dec;
+
+ stat->OutSize = p->outProcessed;
+
+ if (p->finishedDecoderIndex >= 0)
+ {
+ CXzDecMtThread *coder = &p->coders[(unsigned)p->finishedDecoderIndex];
+ codeRes = coder->codeRes;
+ dec = &coder->dec;
+ status = coder->status;
+ }
+ else if (p->mainDecoderWasCalled)
+ {
+ codeRes = p->codeRes;
+ dec = &p->dec;
+ status = p->status;
+ truncated = p->parsing_Truncated;
+ }
+ else
+ return E_FAIL;
+
+ XzStatInfo_SetStat(dec, p->finishMode,
+ p->mtc.readProcessed, p->mtc.inProcessed,
+ codeRes, status,
+ truncated,
+ stat);
+
+ if (res == SZ_OK)
+ {
+ if (p->writeRes != SZ_OK)
+ {
+ res = p->writeRes;
+ stat->CombinedRes_Type = SZ_ERROR_WRITE;
+ }
+ else if (p->mtc.readRes != SZ_OK && p->mtc.inProcessed == p->mtc.readProcessed)
+ {
+ res = p->mtc.readRes;
+ stat->ReadRes = res;
+ stat->CombinedRes_Type = SZ_ERROR_READ;
+ }
+ else if (p->mainErrorCode != SZ_OK)
+ {
+ res = p->mainErrorCode;
+ }
+ }
+
+ stat->CombinedRes = res;
+ if (stat->CombinedRes_Type == SZ_OK)
+ stat->CombinedRes_Type = res;
+ return res;
+ }
+
+ PRF_STR("----- decoding ST -----");
+ }
+ }
+
+ #endif
+
+
+ *isMT = False;
+
+ {
+ SRes res = XzDecMt_Decode_ST(p
+ #ifndef _7ZIP_ST
+ , tMode
+ #endif
+ , stat
+ );
+
+ XzStatInfo_SetStat(&p->dec,
+ p->finishMode,
+ p->readProcessed, p->inProcessed,
+ p->codeRes, p->status,
+ False, // truncated
+ stat);
+
+ if (res == SZ_OK)
+ {
+ /*
+ if (p->writeRes != SZ_OK)
+ {
+ res = p->writeRes;
+ stat->CombinedRes_Type = SZ_ERROR_WRITE;
+ }
+ else
+ */
+ if (p->readRes != SZ_OK && p->inProcessed == p->readProcessed)
+ {
+ res = p->readRes;
+ stat->ReadRes = res;
+ stat->CombinedRes_Type = SZ_ERROR_READ;
+ }
+ #ifndef _7ZIP_ST
+ else if (p->mainErrorCode != SZ_OK)
+ res = p->mainErrorCode;
+ #endif
+ }
+
+ stat->CombinedRes = res;
+ if (stat->CombinedRes_Type == SZ_OK)
+ stat->CombinedRes_Type = res;
+ return res;
+ }
+}