Files
TencentOS-tiny/components/ota/common/lzma/3rdparty/XzDec.c
daishengdong 5b51d50ade add ota algorithm for device
1. effective "Differential Upgrade" patch algorithm with high compression rate
2. effective recovery algorithm support recovery firmware in blocks which has low memory consumption and wear-leveling strategies, especially suitable for embeded devices with low RAM.
3. add sample ota bootloader project, see:
board\TencentOS_tiny_EVB_MX_Plus\KEIL\ota\ota_bootloader_recovery
4. add sample application project for download firmware through http, see:
board\TencentOS_tiny_EVB_MX_Plus\KEIL\ota\ota_application_download_through_http
5. add sample application project for download firmware through qcloud explorer console, see:
board\TencentOS_tiny_EVB_MX_Plus\KEIL\ota\ota_application_download_through_qcloud_iot_explorer
6. an OTA markdown document is pending
2020-06-02 15:03:42 +08:00

2769 lines
63 KiB
C

/* XzDec.c -- Xz Decode
2019-02-02 : Igor Pavlov : Public domain */
#include "Precomp.h"
// #include <stdio.h>
// #define XZ_DUMP
/* #define XZ_DUMP */
#define _7ZIP_ST
#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 = (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;
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;
BoolInt 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 = (ECoderStatus)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 (;;)
{
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;
*/
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 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)
&& 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 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)
{
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;
BoolInt 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;
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,
(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);
}
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(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;
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;
// CXzStatInfo *stat;
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;
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 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,
BoolInt needWriteToStream,
const Byte *src, size_t srcSize,
// 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 = 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
, 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 *)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,
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
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
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->codeRes = 0;
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)
{
IMtDecCallback vt;
// 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;
{
BoolInt 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;
BoolInt 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;
}
}