summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/lzma/C/XzDec.c
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2023-05-04 02:41:16 +1000
committer Vas Crabb <vas@vastheman.com>2023-05-04 02:41:16 +1000
commita504bde3a7462b54fafd5cfc2f52e58d0f3218e1 (patch)
tree8b3108d572b1a0873a6cdbb4e8af1f17179545c3 /3rdparty/lzma/C/XzDec.c
parentbefb9bf4a8cfdb2b693a32e32535b5eac522c5d8 (diff)
3rdparty/lzma: Updated to LZMA SDK version 22.01
Diffstat (limited to '3rdparty/lzma/C/XzDec.c')
-rw-r--r--3rdparty/lzma/C/XzDec.c2342
1 files changed, 2133 insertions, 209 deletions
diff --git a/3rdparty/lzma/C/XzDec.c b/3rdparty/lzma/C/XzDec.c
index 1edc0245637..3f96a37f94f 100644
--- a/3rdparty/lzma/C/XzDec.c
+++ b/3rdparty/lzma/C/XzDec.c
@@ -1,14 +1,33 @@
/* XzDec.c -- Xz Decode
-2015-11-09 : Igor Pavlov : Public domain */
+2021-09-04 : 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>
@@ -19,16 +38,18 @@
#include "Delta.h"
#include "Lzma2Dec.h"
+// #define USE_SUBBLOCK
+
#ifdef USE_SUBBLOCK
#include "Bcj3Dec.c"
-#include "SbDec.c"
+#include "SbDec.h"
#endif
#include "Xz.h"
#define XZ_CHECK_SIZE_MAX 64
-#define CODER_BUF_SIZE (1 << 17)
+#define CODER_BUF_SIZE ((size_t)1 << 17)
unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value)
{
@@ -56,8 +77,9 @@ typedef struct
size_t bufConv;
size_t bufTotal;
- UInt32 methodId;
int encodeMode;
+
+ UInt32 methodId;
UInt32 delta;
UInt32 ip;
UInt32 x86State;
@@ -66,12 +88,12 @@ typedef struct
Byte buf[BRA_BUF_SIZE];
} CBraState;
-static void BraState_Free(void *pp, ISzAlloc *alloc)
+static void BraState_Free(void *pp, ISzAllocPtr alloc)
{
- alloc->Free(alloc, pp);
+ ISzAlloc_Free(alloc, pp);
}
-static SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
+static SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
{
CBraState *p = ((CBraState *)pp);
UNUSED_VAR(alloc);
@@ -121,69 +143,84 @@ static void BraState_Init(void *pp)
Delta_Init(p->deltaState);
}
-#define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: p->bufConv = isa ## _Convert(p->buf, p->bufTotal, p->ip, p->encodeMode); break;
-static SRes BraState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
- int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
+#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);
- SizeT destLenOrig = *destLen;
- SizeT srcLenOrig = *srcLen;
+ 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 = 0;
- while (destLenOrig > 0)
+ // *wasFinished = False;
+ *status = CODER_STATUS_NOT_FINISHED;
+
+ while (destRem > 0)
{
if (p->bufPos != p->bufConv)
{
- size_t curSize = p->bufConv - p->bufPos;
- if (curSize > destLenOrig)
- curSize = destLenOrig;
- memcpy(dest, p->buf + p->bufPos, curSize);
- p->bufPos += curSize;
- *destLen += curSize;
- dest += curSize;
- destLenOrig -= curSize;
+ 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 curSize = BRA_BUF_SIZE - p->bufTotal;
- if (curSize > srcLenOrig)
- curSize = srcLenOrig;
- memcpy(p->buf + p->bufTotal, src, curSize);
- *srcLen += curSize;
- src += curSize;
- srcLenOrig -= curSize;
- p->bufTotal += curSize;
+ 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;
- switch (p->methodId)
- {
- case XZ_ID_Delta:
- if (p->encodeMode)
- Delta_Encode(p->deltaState, p->delta, p->buf, p->bufTotal);
- else
- Delta_Decode(p->deltaState, p->delta, p->buf, p->bufTotal);
- p->bufConv = p->bufTotal;
- break;
- case XZ_ID_X86:
- p->bufConv = x86_Convert(p->buf, p->bufTotal, 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)
- default:
- return SZ_ERROR_UNSUPPORTED;
- }
- p->ip += (UInt32)p->bufConv;
+
+ p->bufConv = BraState_Filter(pp, p->buf, p->bufTotal);
if (p->bufConv == 0)
{
@@ -192,48 +229,55 @@ static SRes BraState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src,
p->bufConv = p->bufTotal;
}
}
- if (p->bufTotal == p->bufPos && srcLenOrig == 0 && srcWasFinished)
- *wasFinished = 1;
+
+ 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, ISzAlloc *alloc)
+
+SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc);
+SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc)
{
CBraState *decoder;
- if (id != XZ_ID_Delta &&
- id != XZ_ID_X86 &&
- id != XZ_ID_PPC &&
- id != XZ_ID_IA64 &&
- id != XZ_ID_ARM &&
- id != XZ_ID_ARMT &&
- id != XZ_ID_SPARC)
+ if (id < XZ_ID_Delta || id > XZ_ID_SPARC)
return SZ_ERROR_UNSUPPORTED;
- p->p = 0;
- decoder = (CBraState *)alloc->Alloc(alloc, sizeof(CBraState));
- if (decoder == 0)
- return SZ_ERROR_MEM;
+ decoder = (CBraState *)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;
- p->p = decoder;
- p->Free = BraState_Free;
- p->SetProps = BraState_SetProps;
- p->Init = BraState_Init;
- p->Code = BraState_Code;
return SZ_OK;
}
+
+
/* ---------- SbState ---------- */
#ifdef USE_SUBBLOCK
-static void SbState_Free(void *pp, ISzAlloc *alloc)
+static void SbState_Free(void *pp, ISzAllocPtr alloc)
{
CSbDec *p = (CSbDec *)pp;
SbDec_Free(p);
- alloc->Free(alloc, pp);
+ ISzAlloc_Free(alloc, pp);
}
-static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
+static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
{
UNUSED_VAR(pp);
UNUSED_VAR(props);
@@ -246,8 +290,10 @@ static void SbState_Init(void *pp)
SbDec_Init((CSbDec *)pp);
}
-static SRes SbState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
- int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
+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;
@@ -260,102 +306,185 @@ static SRes SbState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src,
res = SbDec_Decode((CSbDec *)pp);
*destLen -= p->destLen;
*srcLen -= p->srcLen;
- *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */
+ // *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */
+ *status = (*destLen == 0 && *srcLen == 0) ?
+ CODER_STATUS_FINISHED_WITH_MARK :
+ CODER_STATUS_NOT_FINISHED;
return res;
}
-SRes SbState_SetFromMethod(IStateCoder *p, ISzAlloc *alloc)
+static SRes SbState_SetFromMethod(IStateCoder *p, ISzAllocPtr alloc)
{
- CSbDec *decoder;
- p->p = 0;
- decoder = alloc->Alloc(alloc, sizeof(CSbDec));
- if (decoder == 0)
- return SZ_ERROR_MEM;
- p->p = decoder;
- p->Free = SbState_Free;
- p->SetProps = SbState_SetProps;
- p->Init = SbState_Init;
- p->Code = SbState_Code;
+ 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
-/* ---------- Lzma2State ---------- */
-static void Lzma2State_Free(void *pp, ISzAlloc *alloc)
+
+/* ---------- Lzma2 ---------- */
+
+typedef struct
+{
+ CLzma2Dec decoder;
+ BoolInt outBufMode;
+} CLzma2Dec_Spec;
+
+
+static void Lzma2State_Free(void *pp, ISzAllocPtr alloc)
{
- Lzma2Dec_Free((CLzma2Dec *)pp, alloc);
- alloc->Free(alloc, pp);
+ 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, ISzAlloc *alloc)
+static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
{
if (propSize != 1)
return SZ_ERROR_UNSUPPORTED;
- return Lzma2Dec_Allocate((CLzma2Dec *)pp, props[0], alloc);
+ {
+ 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 *)pp);
+ Lzma2Dec_Init(&((CLzma2Dec_Spec *)pp)->decoder);
}
-static SRes Lzma2State_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
- int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
+
+/*
+ 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)
{
- ELzmaStatus status;
+ CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)pp;
+ ELzmaStatus status2;
/* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */
- SRes res = Lzma2Dec_DecodeToBuf((CLzma2Dec *)pp, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status);
+ SRes res;
UNUSED_VAR(srcWasFinished);
- *wasFinished = (status == LZMA_STATUS_FINISHED_WITH_MARK);
+ 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 = (ECoderStatus)status2;
return res;
}
-static SRes Lzma2State_SetFromMethod(IStateCoder *p, ISzAlloc *alloc)
+
+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 *decoder = (CLzma2Dec *)alloc->Alloc(alloc, sizeof(CLzma2Dec));
- p->p = decoder;
- if (decoder == 0)
- return SZ_ERROR_MEM;
- p->Free = Lzma2State_Free;
- p->SetProps = Lzma2State_SetProps;
- p->Init = Lzma2State_Init;
- p->Code = Lzma2State_Code;
- Lzma2Dec_Construct(decoder);
+ 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;
}
-void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc)
+
+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;
}
-void MixCoder_Free(CMixCoder *p)
+
+static void MixCoder_Free(CMixCoder *p)
{
unsigned i;
- for (i = 0; i < p->numCoders; i++)
+ p->numCoders = 0;
+ for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
{
IStateCoder *sc = &p->coders[i];
- if (p->alloc && sc->p)
+ if (sc->p)
+ {
sc->Free(sc->p, p->alloc);
+ sc->p = NULL;
+ }
}
- p->numCoders = 0;
if (p->buf)
{
- p->alloc->Free(p->alloc, p->buf);
+ ISzAlloc_Free(p->alloc, p->buf);
p->buf = NULL; /* 9.31: the BUG was fixed */
}
}
-void MixCoder_Init(CMixCoder *p)
+static void MixCoder_Init(CMixCoder *p)
{
unsigned i;
for (i = 0; i < MIXCODER_NUM_FILTERS_MAX - 1; i++)
@@ -368,16 +497,22 @@ void MixCoder_Init(CMixCoder *p)
{
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;
}
-SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId)
+
+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, p->alloc);
+ 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
@@ -387,31 +522,128 @@ SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId)
return BraState_SetFromMethod(sc, methodId, 0, p->alloc);
}
-SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen,
+
+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, ECoderStatus *status)
+ ECoderFinishMode finishMode)
{
SizeT destLenOrig = *destLen;
SizeT srcLenOrig = *srcLen;
- Bool allFinished = True;
+
*destLen = 0;
*srcLen = 0;
- *status = CODER_STATUS_NOT_FINISHED;
- if (!p->buf)
+ if (p->wasFinished)
+ return p->res;
+
+ p->status = CODER_STATUS_NOT_FINISHED;
+
+ // if (p->SingleBufMode)
+ if (p->outBuf)
{
- p->buf = (Byte *)p->alloc->Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1));
- if (!p->buf)
- return SZ_ERROR_MEM;
+ 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;
+ BoolInt processed = False;
+ BoolInt 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;
@@ -421,79 +653,106 @@ SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen,
{
SRes res;
IStateCoder *coder = &p->coders[i];
- Byte *destCur;
- SizeT destLenCur, srcLenCur;
- const Byte *srcCur;
- int srcFinishedCur;
+ Byte *dest2;
+ SizeT destLen2, srcLen2; // destLen2_Orig;
+ const Byte *src2;
+ int srcFinished2;
int encodingWasFinished;
+ ECoderStatus status2;
if (i == 0)
{
- srcCur = src;
- srcLenCur = srcLenOrig - *srcLen;
- srcFinishedCur = srcWasFinished;
+ src2 = src;
+ srcLen2 = srcLenOrig - *srcLen;
+ srcFinished2 = srcWasFinished;
}
else
{
- srcCur = p->buf + (CODER_BUF_SIZE * (i - 1)) + p->pos[i - 1];
- srcLenCur = p->size[i - 1] - p->pos[i - 1];
- srcFinishedCur = p->finished[i - 1];
+ 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)
{
- destCur = dest;
- destLenCur = destLenOrig - *destLen;
+ dest2 = dest;
+ destLen2 = destLenOrig - *destLen;
}
else
{
if (p->pos[i] != p->size[i])
continue;
- destCur = p->buf + (CODER_BUF_SIZE * i);
- destLenCur = CODER_BUF_SIZE;
+ dest2 = p->buf + (CODER_BUF_SIZE * i);
+ destLen2 = CODER_BUF_SIZE;
}
- res = coder->Code(coder->p, destCur, &destLenCur, srcCur, &srcLenCur, srcFinishedCur, finishMode, &encodingWasFinished);
+ // 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 += srcLenCur;
- src += srcLenCur;
+ *srcLen += srcLen2;
+ src += srcLen2;
}
else
- {
- p->pos[i - 1] += srcLenCur;
- }
+ p->pos[(size_t)i - 1] += srcLen2;
if (i == p->numCoders - 1)
{
- *destLen += destLenCur;
- dest += destLenCur;
+ *destLen += destLen2;
+ dest += destLen2;
}
else
{
- p->size[i] = destLenCur;
+ p->size[i] = destLen2;
p->pos[i] = 0;
p->finished[i] = encodingWasFinished;
}
- if (res != SZ_OK)
- return res;
-
- if (destLenCur != 0 || srcLenCur != 0)
+ if (destLen2 != 0 || srcLen2 != 0)
processed = True;
}
+
if (!processed)
- break;
+ {
+ if (allFinished)
+ p->status = CODER_STATUS_FINISHED_WITH_MARK;
+ return resMain;
+ }
}
- if (allFinished)
- *status = CODER_STATUS_FINISHED_WITH_MARK;
- return SZ_OK;
}
+
SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf)
{
*p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE);
@@ -503,18 +762,46 @@ SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf)
return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
}
-static Bool Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf)
+static BoolInt 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) &&
- memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0);
+ 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; }
+ if (s == 0) return SZ_ERROR_ARCHIVE; \
+ pos += s; }
+
+
+static BoolInt 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)
@@ -523,14 +810,15 @@ SRes XzBlock_Parse(CXzBlock *p, const Byte *header)
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;
- if (pos == headerSize)
- return SZ_ERROR_ARCHIVE;
p->flags = header[pos++];
+ p->packSize = (UInt64)(Int64)-1;
if (XzBlock_HasPackSize(p))
{
READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize);
@@ -538,6 +826,7 @@ SRes XzBlock_Parse(CXzBlock *p, const Byte *header)
return SZ_ERROR_ARCHIVE;
}
+ p->unpackSize = (UInt64)(Int64)-1;
if (XzBlock_HasUnpackSize(p))
READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize);
@@ -564,37 +853,56 @@ SRes XzBlock_Parse(CXzBlock *p, const Byte *header)
#endif
}
+ if (XzBlock_HasUnsupportedFlags(p))
+ return SZ_ERROR_UNSUPPORTED;
+
while (pos < headerSize)
if (header[pos++] != 0)
return SZ_ERROR_ARCHIVE;
return SZ_OK;
}
-SRes XzDec_Init(CMixCoder *p, const CXzBlock *block)
+
+
+
+static SRes XzDecMix_Init(CMixCoder *p, const CXzBlock *block, Byte *outBuf, size_t outBufSize)
{
unsigned i;
- Bool needReInit = True;
+ BoolInt needReInit = True;
unsigned numFilters = XzBlock_GetNumFilters(block);
-
- if (numFilters == p->numCoders)
+
+ 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;
- needReInit = (i != numFilters);
+ }
}
+
+ // p->SingleBufMode = (outBuf != NULL);
+ p->outBuf = outBuf;
+ p->outBufSize = outBufSize;
+
+ // p->SingleBufMode = False;
+ // outBuf = NULL;
if (needReInit)
{
MixCoder_Free(p);
- p->numCoders = numFilters;
for (i = 0; i < numFilters; i++)
{
- const CXzFilter *f = &block->filters[numFilters - 1 - i];
- RINOK(MixCoder_SetFromMethod(p, i, f->id));
+ 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];
@@ -606,6 +914,8 @@ SRes XzDec_Init(CMixCoder *p, const CXzBlock *block)
return SZ_OK;
}
+
+
void XzUnpacker_Init(CXzUnpacker *p)
{
p->state = XZ_STATE_STREAM_HEADER;
@@ -614,75 +924,171 @@ void XzUnpacker_Init(CXzUnpacker *p)
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, ISzAlloc *alloc)
+
+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, ECoderFinishMode finishMode, ECoderStatus *status)
+ 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 = srcLenOrig - *srcLen;
+ SizeT srcRem;
if (p->state == XZ_STATE_BLOCK)
{
SizeT destLen2 = destLenOrig - *destLen;
SizeT srcLen2 = srcLenOrig - *srcLen;
SRes res;
+
+ ECoderFinishMode finishMode2 = finishMode;
+ BoolInt srcFinished2 = srcFinished;
+ BoolInt 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, dest, &destLen2, src, &srcLen2, False, finishMode, status);
- XzCheck_Update(&p->check, dest, destLen2);
+ {
+ 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;
- dest += destLen2;
p->unpackSize += destLen2;
-
+
RINOK(res);
-
- if (*status == CODER_STATUS_FINISHED_WITH_MARK)
- {
- Byte temp[32];
- unsigned num = Xz_WriteVarInt(temp, p->packSize + p->blockHeaderSize + XzFlags_GetCheckSize(p->streamFlags));
- num += Xz_WriteVarInt(temp + num, p->unpackSize);
- Sha256_Update(&p->sha, temp, num);
- p->indexSize += num;
- p->numBlocks++;
+
+ 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;
+ }
}
- else if (srcLen2 == 0 && destLen2 == 0)
- return SZ_OK;
-
- continue;
+ // continue;
}
- if (srcRem == 0)
+ 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;
@@ -696,6 +1102,8 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
{
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)++;
}
@@ -703,10 +1111,10 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
{
RINOK(Xz_ParseHeader(&p->streamFlags, p->buf));
p->numStartedStreams++;
- p->state = XZ_STATE_BLOCK_HEADER;
- Sha256_Init(&p->sha);
p->indexSize = 0;
p->numBlocks = 0;
+ Sha256_Init(&p->sha);
+ p->state = XZ_STATE_BLOCK_HEADER;
p->pos = 0;
}
break;
@@ -720,6 +1128,8 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
(*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;
@@ -727,10 +1137,13 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
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;
}
- else if (p->pos != p->blockHeaderSize)
+
+ if (p->pos != p->blockHeaderSize)
{
UInt32 cur = p->blockHeaderSize - p->pos;
if (cur > srcRem)
@@ -743,20 +1156,32 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
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));
- RINOK(XzDec_Init(&p->decoder, &p->block));
+ 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 (((p->packSize + p->alignPos) & 3) != 0)
+ 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)
@@ -768,20 +1193,31 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
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;
}
- else
{
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;
@@ -841,9 +1277,10 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
}
else
{
+ const Byte *ptr = p->buf;
p->state = XZ_STATE_STREAM_FOOTER;
p->pos = 0;
- if (CRC_GET_DIGEST(p->crc) != GetUi32(p->buf))
+ if (CRC_GET_DIGEST(p->crc) != GetUi32(ptr))
return SZ_ERROR_CRC;
}
break;
@@ -897,17 +1334,1504 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
*/
}
-Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p)
+
+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);
+}
+
+
+BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p)
+{
+ return (p->state == XZ_STATE_BLOCK_HEADER) && (p->pos == 0);
+}
+
+BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p)
{
return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0);
}
-UInt64 XzUnpacker_GetExtraSize(CXzUnpacker *p)
+UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p)
{
UInt64 num = 0;
if (p->state == XZ_STATE_STREAM_PADDING)
- num += p->padSize;
+ num = p->padSize;
else if (p->state == XZ_STATE_STREAM_HEADER)
- num += p->padSize + p->pos;
+ 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;
+ BoolInt skipMode;
+ // BoolInt finishedWithMark;
+ EMtDecParseState parseState;
+ BoolInt parsing_Truncated;
+ BoolInt atBlockHeader;
+ CXzStreamFlags streamFlags;
+ // UInt64 numFinishedStreams
+ UInt64 numStreams;
+ UInt64 numTotalBlocks;
+ UInt64 numBlocks;
+
+ BoolInt 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;
+
+ BoolInt finishMode;
+ BoolInt outSize_Defined;
+ UInt64 outSize;
+
+ UInt64 outProcessed;
+ UInt64 inProcessed;
+ UInt64 readProcessed;
+ BoolInt readWasFinished;
+ SRes readRes;
+ SRes writeRes;
+
+ Byte *outBuf;
+ size_t outBufSize;
+ Byte *inBuf;
+ size_t inBufSize;
+
+ CXzUnpacker dec;
+
+ ECoderStatus status;
+ SRes codeRes;
+
+ #ifndef _7ZIP_ST
+ BoolInt 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; // it's set to error code, if the size Code() output doesn't patch the size from Parsing stage
+ // it can be = SZ_ERROR_INPUT_EOF
+ // it can be = SZ_ERROR_DATA, in some another cases
+ BoolInt isBlockHeaderState_Parse;
+ BoolInt isBlockHeaderState_Write;
+ UInt64 outProcessed_Parse;
+ BoolInt parsing_Truncated;
+
+ BoolInt 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;
+
+ XzUnpacker_Construct(&p->dec, &p->alignOffsetAlloc.vt);
+
+ 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)
+{
+ XzUnpacker_Free(&p->dec);
+
+ 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 SZ_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 (srcSize > coder->inPreSize - coder->inCodeSize)
+ return SZ_ERROR_FAIL;
+
+ if (coder->inCodeSize < coder->inPreHeaderSize)
+ {
+ size_t step = coder->inPreHeaderSize - coder->inCodeSize;
+ if (step > srcSize)
+ step = srcSize;
+ src += step;
+ srcSize -= step;
+ coder->inCodeSize += step;
+ *inCodePos = coder->inCodeSize;
+ 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 SZ_OK;
+ }
+ return coder->codeRes;
+}
+
+
+#define XZDECMT_STREAM_WRITE_STEP (1 << 24)
+
+static SRes XzDecMt_Callback_Write(void *pp, unsigned coderIndex,
+ BoolInt needWriteToStream,
+ const Byte *src, size_t srcSize, BoolInt isCross,
+ // int srcFinished,
+ BoolInt *needContinue,
+ BoolInt *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 = (int)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 = (int)coderIndex;
+ return res;
+ }
+
+ RINOK(res);
+
+ if (coder->inPreSize != coder->inCodeSize
+ || coder->blockPackTotal != coder->inCodeSize)
+ {
+ me->finishedDecoderIndex = (int)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;
+ }
+
+ /*
+ We have processed all xz-blocks of stream,
+ And xz unpacker is at XZ_STATE_BLOCK_HEADER state, where
+ (src) is a pointer to xz-Index structure.
+ We finish reading of current xz-Stream, including Zero padding after xz-Stream.
+ We exit, if we reach extra byte (first byte of new-Stream or another data).
+ But we don't update input stream pointer for that new extra byte.
+ If extra byte is not correct first byte of xz-signature,
+ we have SZ_ERROR_NO_ARCHIVE error here.
+ */
+
+ res = XzUnpacker_Code(dec,
+ NULL, &outSizeCur,
+ src, &srcProcessed,
+ me->mtc.readWasFinished, // srcFinished
+ CODER_FINISH_END, // CODER_FINISH_ANY,
+ &status);
+
+ // res = SZ_ERROR_ARCHIVE; // for failure test
+
+ me->status = status;
+ me->codeRes = res;
+
+ if (isCross)
+ me->mtc.crossStart += srcProcessed;
+
+ me->mtc.inProcessed += srcProcessed;
+ me->mtc.mtProgress.totalInSize = me->mtc.inProcessed;
+
+ srcSize -= srcProcessed;
+ src += srcProcessed;
+
+ if (res != SZ_OK)
+ {
+ return SZ_OK;
+ // return res;
+ }
+
+ if (dec->state == XZ_STATE_STREAM_HEADER)
+ {
+ *needContinue = True;
+ me->isBlockHeaderState_Parse = False;
+ me->isBlockHeaderState_Write = False;
+
+ if (!isCross)
+ {
+ Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc);
+ if (!crossBuf)
+ return SZ_ERROR_MEM;
+ if (srcSize != 0)
+ memcpy(crossBuf, src, srcSize);
+ me->mtc.crossStart = 0;
+ me->mtc.crossEnd = srcSize;
+ }
+
+ PRF_STR_INT("XZ_STATE_STREAM_HEADER crossEnd = ", (unsigned)me->mtc.crossEnd);
+
+ return SZ_OK;
+ }
+
+ if (status != CODER_STATUS_NEEDS_MORE_INPUT || srcSize != 0)
+ {
+ return SZ_ERROR_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;
+
+ // 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 *)crossBuf, &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,
+ crossBuf + 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 SZ_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 SZ_ERROR_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->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;
+}
+
+
+
+/*
+ XzDecMt_Decode_ST() can return SZ_OK or the following errors
+ - SZ_ERROR_MEM for memory allocation error
+ - error from XzUnpacker_Code() function
+ - SZ_ERROR_WRITE for ISeqOutStream::Write(). stat->CombinedRes_Type = SZ_ERROR_WRITE in that case
+ - ICompressProgress::Progress() error, stat->CombinedRes_Type = SZ_ERROR_PROGRESS.
+ But XzDecMt_Decode_ST() doesn't return ISeqInStream::Read() errors.
+ ISeqInStream::Read() result is set to p->readRes.
+ also it can set stat->CombinedRes_Type to SZ_ERROR_WRITE or SZ_ERROR_PROGRESS.
+*/
+
+static SRes XzDecMt_Decode_ST(CXzDecMt *p
+ #ifndef _7ZIP_ST
+ , BoolInt 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;
+ BoolInt 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 *)p->inBuf, &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)
+ {
+ const size_t written = ISeqOutStream_Write(p->outStream, p->outBuf, outPos);
+ // p->outProcessed += written; // 21.01: BUG fixed
+ if (written != outPos)
+ {
+ stat->CombinedRes_Type = SZ_ERROR_WRITE;
+ return SZ_ERROR_WRITE;
+ }
+ outPos = 0;
+ }
+
+ if (p->progress && res == SZ_OK)
+ {
+ if (p->inProcessed - inPrev >= (1 << 22) ||
+ p->outProcessed - outPrev >= (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)
+ {
+ // p->codeRes is preliminary error from XzUnpacker_Code.
+ // and it can be corrected later as final result
+ // so we return SZ_OK here instead of (res);
+ return SZ_OK;
+ // return res;
+ }
+ }
+}
+
+
+
+/*
+XzStatInfo_SetStat() transforms
+ CXzUnpacker return code and status to combined CXzStatInfo results.
+ it can convert SZ_OK to SZ_ERROR_INPUT_EOF
+ it can convert SZ_ERROR_NO_ARCHIVE to SZ_OK and (DataAfterEnd = 1)
+*/
+
+static void XzStatInfo_SetStat(const CXzUnpacker *dec,
+ int finishMode,
+ // UInt64 readProcessed,
+ UInt64 inProcessed,
+ SRes res, // it's result from CXzUnpacker unpacker
+ ECoderStatus status,
+ BoolInt 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
+ // any extra data is part of correct data
+ extraSize = 0;
+ // if xz stream was not finished, then we need more data
+ if (!XzUnpacker_IsStreamWasFinished(dec))
+ res = SZ_ERROR_INPUT_EOF;
+ }
+ else
+ {
+ // CODER_STATUS_FINISHED_WITH_MARK is not possible for multi stream xz decoding
+ // so he we have (status == CODER_STATUS_NOT_FINISHED)
+ // if (status != CODER_STATUS_FINISHED_WITH_MARK)
+ if (!decodingTruncated || finishMode)
+ 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 and inProcessed don't include "bad" byte
+ */
+ // if (inProcessed == extraSize), there was no any good xz stream header, and we keep error
+ if (inProcessed != extraSize) // if there were good xz streams before error
+ {
+ // if (extraSize != 0 || readProcessed != inProcessed)
+ {
+ // he we suppose that all xz streams were finsihed OK, and we have
+ // some extra data after all streams
+ stat->DataAfterEnd = True;
+ res = SZ_OK;
+ }
+ }
+ }
+
+ if (stat->DecodeRes == SZ_OK)
+ stat->DecodeRes = res;
+
+ stat->InSize -= extraSize;
+}
+
+
+
+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
+ BoolInt 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->readRes = SZ_OK;
+
+ p->codeRes = SZ_OK;
+ p->status = CODER_STATUS_NOT_SPECIFIED;
+
+ 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)
+ {
+ IMtDecCallback2 vt;
+ BoolInt needContinue;
+ SRes res;
+ // we just free ST buffers here
+ // but we still keep state variables, that was set in XzUnpacker_Init()
+ 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;
+
+
+ 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;
+ BoolInt truncated = False;
+ ECoderStatus status;
+ const CXzUnpacker *dec;
+
+ stat->OutSize = p->outProcessed;
+
+ if (p->finishedDecoderIndex >= 0)
+ {
+ const 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 SZ_ERROR_FAIL;
+
+ if (p->mainErrorCode != SZ_OK)
+ stat->DecodeRes = p->mainErrorCode;
+
+ XzStatInfo_SetStat(dec, p->finishMode,
+ // p->mtc.readProcessed,
+ p->mtc.inProcessed,
+ codeRes, status,
+ truncated,
+ stat);
+ }
+
+ if (res == SZ_OK)
+ {
+ stat->ReadRes = p->mtc.readRes;
+
+ 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
+ && stat->DecodeRes == SZ_ERROR_INPUT_EOF)
+ {
+ res = p->mtc.readRes;
+ stat->CombinedRes_Type = SZ_ERROR_READ;
+ }
+ else if (stat->DecodeRes != SZ_OK)
+ res = stat->DecodeRes;
+ }
+
+ 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
+ );
+
+ #ifndef _7ZIP_ST
+ // we must set error code from MT decoding at first
+ if (p->mainErrorCode != SZ_OK)
+ stat->DecodeRes = p->mainErrorCode;
+ #endif
+
+ XzStatInfo_SetStat(&p->dec,
+ p->finishMode,
+ // p->readProcessed,
+ p->inProcessed,
+ p->codeRes, p->status,
+ False, // truncated
+ stat);
+
+ stat->ReadRes = p->readRes;
+
+ if (res == SZ_OK)
+ {
+ if (p->readRes != SZ_OK
+ // && p->inProcessed == p->readProcessed
+ && stat->DecodeRes == SZ_ERROR_INPUT_EOF)
+ {
+ // we set read error as combined error, only if that error was the reason
+ // of decoding problem
+ res = p->readRes;
+ stat->CombinedRes_Type = SZ_ERROR_READ;
+ }
+ else if (stat->DecodeRes != SZ_OK)
+ res = stat->DecodeRes;
+ }
+
+ stat->CombinedRes = res;
+ if (stat->CombinedRes_Type == SZ_OK)
+ stat->CombinedRes_Type = res;
+ return res;
+ }
+}