/* Lzma2DecMt.c -- LZMA2 Decoder Multi-thread | |
2018-07-04 : Igor Pavlov : Public domain */ | |
#include "Precomp.h" | |
// #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)) | |
#define PRF_STR_INT_2(s, d1, d2) PRF(printf("\n" s " %d %d\n", (unsigned)d1, (unsigned)d2)) | |
// #define _7ZIP_ST | |
#include "Alloc.h" | |
#include "Lzma2Dec.h" | |
#include "Lzma2DecMt.h" | |
#ifndef _7ZIP_ST | |
#include "MtDec.h" | |
#endif | |
#define LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT (1 << 28) | |
void Lzma2DecMtProps_Init(CLzma2DecMtProps *p) | |
{ | |
p->inBufSize_ST = 1 << 20; | |
p->outStep_ST = 1 << 20; | |
#ifndef _7ZIP_ST | |
p->numThreads = 1; | |
p->inBufSize_MT = 1 << 18; | |
p->outBlockMax = LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT; | |
p->inBlockMax = p->outBlockMax + p->outBlockMax / 16; | |
#endif | |
} | |
#ifndef _7ZIP_ST | |
/* ---------- CLzma2DecMtThread ---------- */ | |
typedef struct | |
{ | |
CLzma2Dec dec; | |
Byte dec_created; | |
Byte needInit; | |
Byte *outBuf; | |
size_t outBufSize; | |
EMtDecParseState state; | |
ELzma2ParseStatus parseStatus; | |
size_t inPreSize; | |
size_t outPreSize; | |
size_t inCodeSize; | |
size_t outCodeSize; | |
SRes codeRes; | |
CAlignOffsetAlloc alloc; | |
Byte mtPad[1 << 7]; | |
} CLzma2DecMtThread; | |
#endif | |
/* ---------- CLzma2DecMt ---------- */ | |
typedef struct | |
{ | |
// ISzAllocPtr alloc; | |
ISzAllocPtr allocMid; | |
CAlignOffsetAlloc alignOffsetAlloc; | |
CLzma2DecMtProps props; | |
Byte prop; | |
ISeqInStream *inStream; | |
ISeqOutStream *outStream; | |
ICompressProgress *progress; | |
BoolInt finishMode; | |
BoolInt outSize_Defined; | |
UInt64 outSize; | |
UInt64 outProcessed; | |
UInt64 inProcessed; | |
BoolInt readWasFinished; | |
SRes readRes; | |
Byte *inBuf; | |
size_t inBufSize; | |
Byte dec_created; | |
CLzma2Dec dec; | |
size_t inPos; | |
size_t inLim; | |
#ifndef _7ZIP_ST | |
UInt64 outProcessed_Parse; | |
BoolInt mtc_WasConstructed; | |
CMtDec mtc; | |
CLzma2DecMtThread coders[MTDEC__THREADS_MAX]; | |
#endif | |
} CLzma2DecMt; | |
CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid) | |
{ | |
CLzma2DecMt *p = (CLzma2DecMt *)ISzAlloc_Alloc(alloc, sizeof(CLzma2DecMt)); | |
if (!p) | |
return NULL; | |
// p->alloc = alloc; | |
p->allocMid = allocMid; | |
AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc); | |
p->alignOffsetAlloc.numAlignBits = 7; | |
p->alignOffsetAlloc.offset = 0; | |
p->alignOffsetAlloc.baseAlloc = alloc; | |
p->inBuf = NULL; | |
p->inBufSize = 0; | |
p->dec_created = False; | |
// Lzma2DecMtProps_Init(&p->props); | |
#ifndef _7ZIP_ST | |
p->mtc_WasConstructed = False; | |
{ | |
unsigned i; | |
for (i = 0; i < MTDEC__THREADS_MAX; i++) | |
{ | |
CLzma2DecMtThread *t = &p->coders[i]; | |
t->dec_created = False; | |
t->outBuf = NULL; | |
t->outBufSize = 0; | |
} | |
} | |
#endif | |
return p; | |
} | |
#ifndef _7ZIP_ST | |
static void Lzma2DecMt_FreeOutBufs(CLzma2DecMt *p) | |
{ | |
unsigned i; | |
for (i = 0; i < MTDEC__THREADS_MAX; i++) | |
{ | |
CLzma2DecMtThread *t = &p->coders[i]; | |
if (t->outBuf) | |
{ | |
ISzAlloc_Free(p->allocMid, t->outBuf); | |
t->outBuf = NULL; | |
t->outBufSize = 0; | |
} | |
} | |
} | |
#endif | |
static void Lzma2DecMt_FreeSt(CLzma2DecMt *p) | |
{ | |
if (p->dec_created) | |
{ | |
Lzma2Dec_Free(&p->dec, &p->alignOffsetAlloc.vt); | |
p->dec_created = False; | |
} | |
if (p->inBuf) | |
{ | |
ISzAlloc_Free(p->allocMid, p->inBuf); | |
p->inBuf = NULL; | |
} | |
p->inBufSize = 0; | |
} | |
void Lzma2DecMt_Destroy(CLzma2DecMtHandle pp) | |
{ | |
CLzma2DecMt *p = (CLzma2DecMt *)pp; | |
Lzma2DecMt_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++) | |
{ | |
CLzma2DecMtThread *t = &p->coders[i]; | |
if (t->dec_created) | |
{ | |
// we don't need to free dict here | |
Lzma2Dec_FreeProbs(&t->dec, &t->alloc.vt); // p->alloc !!! | |
t->dec_created = False; | |
} | |
} | |
} | |
Lzma2DecMt_FreeOutBufs(p); | |
#endif | |
ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, pp); | |
} | |
#ifndef _7ZIP_ST | |
static void Lzma2DecMt_MtCallback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc) | |
{ | |
CLzma2DecMt *me = (CLzma2DecMt *)obj; | |
CLzma2DecMtThread *t = &me->coders[coderIndex]; | |
PRF_STR_INT_2("Parse", coderIndex, cc->srcSize); | |
cc->state = MTDEC_PARSE_CONTINUE; | |
if (cc->startCall) | |
{ | |
if (!t->dec_created) | |
{ | |
Lzma2Dec_Construct(&t->dec); | |
t->dec_created = True; | |
AlignOffsetAlloc_CreateVTable(&t->alloc); | |
{ | |
/* (1 << 12) is expected size of one way in data cache. | |
We optimize alignment for cache line size of 128 bytes and smaller */ | |
const unsigned kNumAlignBits = 12; | |
const unsigned kNumCacheLineBits = 7; /* <= kNumAlignBits */ | |
t->alloc.numAlignBits = kNumAlignBits; | |
t->alloc.offset = ((UInt32)coderIndex * ((1 << 11) + (1 << 8) + (1 << 6))) & ((1 << kNumAlignBits) - (1 << kNumCacheLineBits)); | |
t->alloc.baseAlloc = me->alignOffsetAlloc.baseAlloc; | |
} | |
} | |
Lzma2Dec_Init(&t->dec); | |
t->inPreSize = 0; | |
t->outPreSize = 0; | |
// t->blockWasFinished = False; | |
// t->finishedWithMark = False; | |
t->parseStatus = LZMA_STATUS_NOT_SPECIFIED; | |
t->state = MTDEC_PARSE_CONTINUE; | |
t->inCodeSize = 0; | |
t->outCodeSize = 0; | |
t->codeRes = SZ_OK; | |
// (cc->srcSize == 0) is allowed | |
} | |
{ | |
ELzma2ParseStatus status; | |
BoolInt overflow; | |
UInt32 unpackRem = 0; | |
int checkFinishBlock = True; | |
size_t limit = me->props.outBlockMax; | |
if (me->outSize_Defined) | |
{ | |
UInt64 rem = me->outSize - me->outProcessed_Parse; | |
if (limit >= rem) | |
{ | |
limit = (size_t)rem; | |
if (!me->finishMode) | |
checkFinishBlock = False; | |
} | |
} | |
// checkFinishBlock = False, if we want to decode partial data | |
// that must be finished at position <= outBlockMax. | |
{ | |
const SizeT srcOrig = cc->srcSize; | |
SizeT srcSize_Point = 0; | |
SizeT dicPos_Point = 0; | |
cc->srcSize = 0; | |
overflow = False; | |
for (;;) | |
{ | |
SizeT srcCur = srcOrig - cc->srcSize; | |
status = Lzma2Dec_Parse(&t->dec, | |
limit - t->dec.decoder.dicPos, | |
cc->src + cc->srcSize, &srcCur, | |
checkFinishBlock); | |
cc->srcSize += srcCur; | |
if (status == LZMA2_PARSE_STATUS_NEW_CHUNK) | |
{ | |
if (t->dec.unpackSize > me->props.outBlockMax - t->dec.decoder.dicPos) | |
{ | |
overflow = True; | |
break; | |
} | |
continue; | |
} | |
if (status == LZMA2_PARSE_STATUS_NEW_BLOCK) | |
{ | |
if (t->dec.decoder.dicPos == 0) | |
continue; | |
// we decode small blocks in one thread | |
if (t->dec.decoder.dicPos >= (1 << 14)) | |
break; | |
dicPos_Point = t->dec.decoder.dicPos; | |
srcSize_Point = cc->srcSize; | |
continue; | |
} | |
if ((int)status == LZMA_STATUS_NOT_FINISHED && checkFinishBlock | |
// && limit == t->dec.decoder.dicPos | |
// && limit == me->props.outBlockMax | |
) | |
{ | |
overflow = True; | |
break; | |
} | |
unpackRem = Lzma2Dec_GetUnpackExtra(&t->dec); | |
break; | |
} | |
if (dicPos_Point != 0 | |
&& (int)status != LZMA2_PARSE_STATUS_NEW_BLOCK | |
&& (int)status != LZMA_STATUS_FINISHED_WITH_MARK | |
&& (int)status != LZMA_STATUS_NOT_SPECIFIED) | |
{ | |
// we revert to latest newBlock state | |
status = LZMA2_PARSE_STATUS_NEW_BLOCK; | |
unpackRem = 0; | |
t->dec.decoder.dicPos = dicPos_Point; | |
cc->srcSize = srcSize_Point; | |
overflow = False; | |
} | |
} | |
t->inPreSize += cc->srcSize; | |
t->parseStatus = status; | |
if (overflow) | |
cc->state = MTDEC_PARSE_OVERFLOW; | |
else | |
{ | |
size_t dicPos = t->dec.decoder.dicPos; | |
if ((int)status != LZMA_STATUS_NEEDS_MORE_INPUT) | |
{ | |
if (status == LZMA2_PARSE_STATUS_NEW_BLOCK) | |
{ | |
cc->state = MTDEC_PARSE_NEW; | |
cc->srcSize--; // we don't need control byte of next block | |
t->inPreSize--; | |
} | |
else | |
{ | |
cc->state = MTDEC_PARSE_END; | |
if ((int)status != LZMA_STATUS_FINISHED_WITH_MARK) | |
{ | |
// (status == LZMA_STATUS_NOT_SPECIFIED) | |
// (status == LZMA_STATUS_NOT_FINISHED) | |
if (unpackRem != 0) | |
{ | |
/* we also reserve space for max possible number of output bytes of current LZMA chunk */ | |
SizeT rem = limit - dicPos; | |
if (rem > unpackRem) | |
rem = unpackRem; | |
dicPos += rem; | |
} | |
} | |
} | |
me->outProcessed_Parse += dicPos; | |
} | |
cc->outPos = dicPos; | |
t->outPreSize = (size_t)dicPos; | |
} | |
t->state = cc->state; | |
return; | |
} | |
} | |
static SRes Lzma2DecMt_MtCallback_PreCode(void *pp, unsigned coderIndex) | |
{ | |
CLzma2DecMt *me = (CLzma2DecMt *)pp; | |
CLzma2DecMtThread *t = &me->coders[coderIndex]; | |
Byte *dest = t->outBuf; | |
if (t->inPreSize == 0) | |
{ | |
t->codeRes = SZ_ERROR_DATA; | |
return t->codeRes; | |
} | |
if (!dest || t->outBufSize < t->outPreSize) | |
{ | |
if (dest) | |
{ | |
ISzAlloc_Free(me->allocMid, dest); | |
t->outBuf = NULL; | |
t->outBufSize = 0; | |
} | |
dest = (Byte *)ISzAlloc_Alloc(me->allocMid, t->outPreSize | |
// + (1 << 28) | |
); | |
// Sleep(200); | |
if (!dest) | |
return SZ_ERROR_MEM; | |
t->outBuf = dest; | |
t->outBufSize = t->outPreSize; | |
} | |
t->dec.decoder.dic = dest; | |
t->dec.decoder.dicBufSize = t->outPreSize; | |
t->needInit = True; | |
return Lzma2Dec_AllocateProbs(&t->dec, me->prop, &t->alloc.vt); // alloc.vt | |
} | |
static SRes Lzma2DecMt_MtCallback_Code(void *pp, unsigned coderIndex, | |
const Byte *src, size_t srcSize, int srcFinished, | |
// int finished, int blockFinished, | |
UInt64 *inCodePos, UInt64 *outCodePos, int *stop) | |
{ | |
CLzma2DecMt *me = (CLzma2DecMt *)pp; | |
CLzma2DecMtThread *t = &me->coders[coderIndex]; | |
UNUSED_VAR(srcFinished) | |
PRF_STR_INT_2("Code", coderIndex, srcSize); | |
*inCodePos = t->inCodeSize; | |
*outCodePos = 0; | |
*stop = True; | |
if (t->needInit) | |
{ | |
Lzma2Dec_Init(&t->dec); | |
t->needInit = False; | |
} | |
{ | |
ELzmaStatus status; | |
size_t srcProcessed = srcSize; | |
BoolInt blockWasFinished = | |
((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK | |
|| t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK); | |
SRes res = Lzma2Dec_DecodeToDic(&t->dec, | |
t->outPreSize, | |
src, &srcProcessed, | |
blockWasFinished ? LZMA_FINISH_END : LZMA_FINISH_ANY, | |
&status); | |
t->codeRes = res; | |
t->inCodeSize += srcProcessed; | |
*inCodePos = t->inCodeSize; | |
t->outCodeSize = t->dec.decoder.dicPos; | |
*outCodePos = t->dec.decoder.dicPos; | |
if (res != SZ_OK) | |
return res; | |
if (srcProcessed == srcSize) | |
*stop = False; | |
if (blockWasFinished) | |
{ | |
if (srcSize != srcProcessed) | |
return SZ_ERROR_FAIL; | |
if (t->inPreSize == t->inCodeSize) | |
{ | |
if (t->outPreSize != t->outCodeSize) | |
return SZ_ERROR_FAIL; | |
*stop = True; | |
} | |
} | |
else | |
{ | |
if (t->outPreSize == t->outCodeSize) | |
*stop = True; | |
} | |
return SZ_OK; | |
} | |
} | |
#define LZMA2DECMT_STREAM_WRITE_STEP (1 << 24) | |
static SRes Lzma2DecMt_MtCallback_Write(void *pp, unsigned coderIndex, | |
BoolInt needWriteToStream, | |
const Byte *src, size_t srcSize, | |
BoolInt *needContinue, BoolInt *canRecode) | |
{ | |
CLzma2DecMt *me = (CLzma2DecMt *)pp; | |
const CLzma2DecMtThread *t = &me->coders[coderIndex]; | |
size_t size = t->outCodeSize; | |
const Byte *data = t->outBuf; | |
BoolInt needContinue2 = True; | |
PRF_STR_INT_2("Write", coderIndex, srcSize); | |
*needContinue = False; | |
*canRecode = True; | |
UNUSED_VAR(src) | |
UNUSED_VAR(srcSize) | |
if ( | |
// t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK | |
t->state == MTDEC_PARSE_OVERFLOW | |
|| t->state == MTDEC_PARSE_END) | |
needContinue2 = False; | |
if (!needWriteToStream) | |
return SZ_OK; | |
me->mtc.inProcessed += t->inCodeSize; | |
if (t->codeRes == SZ_OK) | |
if ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK | |
|| t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK) | |
if (t->outPreSize != t->outCodeSize | |
|| t->inPreSize != t->inCodeSize) | |
return SZ_ERROR_FAIL; | |
*canRecode = False; | |
if (me->outStream) | |
{ | |
for (;;) | |
{ | |
size_t cur = size; | |
size_t written; | |
if (cur > LZMA2DECMT_STREAM_WRITE_STEP) | |
cur = LZMA2DECMT_STREAM_WRITE_STEP; | |
written = ISeqOutStream_Write(me->outStream, data, cur); | |
me->outProcessed += written; | |
// me->mtc.writtenTotal += written; | |
if (written != cur) | |
return SZ_ERROR_WRITE; | |
data += cur; | |
size -= cur; | |
if (size == 0) | |
{ | |
*needContinue = needContinue2; | |
return SZ_OK; | |
} | |
RINOK(MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0)); | |
} | |
} | |
return SZ_ERROR_FAIL; | |
/* | |
if (size > me->outBufSize) | |
return SZ_ERROR_OUTPUT_EOF; | |
memcpy(me->outBuf, data, size); | |
me->outBufSize -= size; | |
me->outBuf += size; | |
*needContinue = needContinue2; | |
return SZ_OK; | |
*/ | |
} | |
#endif | |
static SRes Lzma2Dec_Prepare_ST(CLzma2DecMt *p) | |
{ | |
if (!p->dec_created) | |
{ | |
Lzma2Dec_Construct(&p->dec); | |
p->dec_created = True; | |
} | |
RINOK(Lzma2Dec_Allocate(&p->dec, p->prop, &p->alignOffsetAlloc.vt)); | |
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; | |
} | |
Lzma2Dec_Init(&p->dec); | |
return SZ_OK; | |
} | |
static SRes Lzma2Dec_Decode_ST(CLzma2DecMt *p | |
#ifndef _7ZIP_ST | |
, BoolInt tMode | |
#endif | |
) | |
{ | |
SizeT wrPos; | |
size_t inPos, inLim; | |
const Byte *inData; | |
UInt64 inPrev, outPrev; | |
CLzma2Dec *dec; | |
#ifndef _7ZIP_ST | |
if (tMode) | |
{ | |
Lzma2DecMt_FreeOutBufs(p); | |
tMode = MtDec_PrepareRead(&p->mtc); | |
} | |
#endif | |
RINOK(Lzma2Dec_Prepare_ST(p)); | |
dec = &p->dec; | |
inPrev = p->inProcessed; | |
outPrev = p->outProcessed; | |
inPos = 0; | |
inLim = 0; | |
inData = NULL; | |
wrPos = dec->decoder.dicPos; | |
for (;;) | |
{ | |
SizeT dicPos; | |
SizeT size; | |
ELzmaFinishMode finishMode; | |
SizeT inProcessed; | |
ELzmaStatus status; | |
SRes res; | |
SizeT outProcessed; | |
BoolInt outFinished; | |
BoolInt needStop; | |
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; | |
// inLim -= 5; p->readWasFinished = True; // for test | |
if (inLim == 0 || p->readRes != SZ_OK) | |
p->readWasFinished = True; | |
} | |
} | |
dicPos = dec->decoder.dicPos; | |
{ | |
SizeT next = dec->decoder.dicBufSize; | |
if (next - wrPos > p->props.outStep_ST) | |
next = wrPos + p->props.outStep_ST; | |
size = next - dicPos; | |
} | |
finishMode = LZMA_FINISH_ANY; | |
if (p->outSize_Defined) | |
{ | |
const UInt64 rem = p->outSize - p->outProcessed; | |
if (size >= rem) | |
{ | |
size = (SizeT)rem; | |
if (p->finishMode) | |
finishMode = LZMA_FINISH_END; | |
} | |
} | |
inProcessed = inLim - inPos; | |
res = Lzma2Dec_DecodeToDic(dec, dicPos + size, inData + inPos, &inProcessed, finishMode, &status); | |
inPos += inProcessed; | |
p->inProcessed += inProcessed; | |
outProcessed = dec->decoder.dicPos - dicPos; | |
p->outProcessed += outProcessed; | |
outFinished = (p->outSize_Defined && p->outSize <= p->outProcessed); | |
needStop = (res != SZ_OK | |
|| (inProcessed == 0 && outProcessed == 0) | |
|| status == LZMA_STATUS_FINISHED_WITH_MARK | |
|| (!p->finishMode && outFinished)); | |
if (needStop || outProcessed >= size) | |
{ | |
SRes res2; | |
{ | |
size_t writeSize = dec->decoder.dicPos - wrPos; | |
size_t written = ISeqOutStream_Write(p->outStream, dec->decoder.dic + wrPos, writeSize); | |
res2 = (written == writeSize) ? SZ_OK : SZ_ERROR_WRITE; | |
} | |
if (dec->decoder.dicPos == dec->decoder.dicBufSize) | |
dec->decoder.dicPos = 0; | |
wrPos = dec->decoder.dicPos; | |
RINOK(res2); | |
if (needStop) | |
{ | |
if (res != SZ_OK) | |
return res; | |
if (status == LZMA_STATUS_FINISHED_WITH_MARK) | |
{ | |
if (p->finishMode) | |
{ | |
if (p->outSize_Defined && p->outSize != p->outProcessed) | |
return SZ_ERROR_DATA; | |
} | |
return SZ_OK; | |
} | |
if (!p->finishMode && outFinished) | |
return SZ_OK; | |
if (status == LZMA_STATUS_NEEDS_MORE_INPUT) | |
return SZ_ERROR_INPUT_EOF; | |
return SZ_ERROR_DATA; | |
} | |
} | |
if (p->progress) | |
{ | |
UInt64 inDelta = p->inProcessed - inPrev; | |
UInt64 outDelta = p->outProcessed - outPrev; | |
if (inDelta >= (1 << 22) || outDelta >= (1 << 22)) | |
{ | |
RINOK(ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed)); | |
inPrev = p->inProcessed; | |
outPrev = p->outProcessed; | |
} | |
} | |
} | |
} | |
SRes Lzma2DecMt_Decode(CLzma2DecMtHandle pp, | |
Byte prop, | |
const CLzma2DecMtProps *props, | |
ISeqOutStream *outStream, const UInt64 *outDataSize, int finishMode, | |
// Byte *outBuf, size_t *outBufSize, | |
ISeqInStream *inStream, | |
// const Byte *inData, size_t inDataSize, | |
UInt64 *inProcessed, | |
// UInt64 *outProcessed, | |
int *isMT, | |
ICompressProgress *progress) | |
{ | |
CLzma2DecMt *p = (CLzma2DecMt *)pp; | |
#ifndef _7ZIP_ST | |
BoolInt tMode; | |
#endif | |
*inProcessed = 0; | |
if (prop > 40) | |
return SZ_ERROR_UNSUPPORTED; | |
p->prop = prop; | |
p->props = *props; | |
p->inStream = inStream; | |
p->outStream = outStream; | |
p->progress = progress; | |
p->outSize = 0; | |
p->outSize_Defined = False; | |
if (outDataSize) | |
{ | |
p->outSize_Defined = True; | |
p->outSize = *outDataSize; | |
} | |
p->finishMode = finishMode; | |
p->outProcessed = 0; | |
p->inProcessed = 0; | |
p->readWasFinished = False; | |
*isMT = False; | |
#ifndef _7ZIP_ST | |
tMode = False; | |
// p->mtc.parseRes = SZ_OK; | |
// p->mtc.numFilledThreads = 0; | |
// p->mtc.crossStart = 0; | |
// p->mtc.crossEnd = 0; | |
// p->mtc.allocError_for_Read_BlockIndex = 0; | |
// p->mtc.isAllocError = False; | |
if (p->props.numThreads > 1) | |
{ | |
IMtDecCallback vt; | |
Lzma2DecMt_FreeSt(p); | |
p->outProcessed_Parse = 0; | |
if (!p->mtc_WasConstructed) | |
{ | |
p->mtc_WasConstructed = True; | |
MtDec_Construct(&p->mtc); | |
} | |
p->mtc.progress = progress; | |
p->mtc.inStream = inStream; | |
// p->outBuf = NULL; | |
// p->outBufSize = 0; | |
/* | |
if (!outStream) | |
{ | |
// p->outBuf = outBuf; | |
// p->outBufSize = *outBufSize; | |
// *outBufSize = 0; | |
return SZ_ERROR_PARAM; | |
} | |
*/ | |
// p->mtc.inBlockMax = p->props.inBlockMax; | |
p->mtc.alloc = &p->alignOffsetAlloc.vt; | |
// p->alignOffsetAlloc.baseAlloc; | |
// p->mtc.inData = inData; | |
// p->mtc.inDataSize = inDataSize; | |
p->mtc.mtCallback = &vt; | |
p->mtc.mtCallbackObject = p; | |
p->mtc.inBufSize = p->props.inBufSize_MT; | |
p->mtc.numThreadsMax = p->props.numThreads; | |
*isMT = True; | |
vt.Parse = Lzma2DecMt_MtCallback_Parse; | |
vt.PreCode = Lzma2DecMt_MtCallback_PreCode; | |
vt.Code = Lzma2DecMt_MtCallback_Code; | |
vt.Write = Lzma2DecMt_MtCallback_Write; | |
{ | |
BoolInt needContinue = False; | |
SRes res = MtDec_Code(&p->mtc); | |
/* | |
if (!outStream) | |
*outBufSize = p->outBuf - outBuf; | |
*/ | |
*inProcessed = p->mtc.inProcessed; | |
needContinue = False; | |
if (res == SZ_OK) | |
{ | |
if (p->mtc.mtProgress.res != SZ_OK) | |
res = p->mtc.mtProgress.res; | |
else | |
needContinue = p->mtc.needContinue; | |
} | |
if (!needContinue) | |
{ | |
if (res == SZ_OK) | |
return p->mtc.readRes; | |
return res; | |
} | |
tMode = True; | |
p->readRes = p->mtc.readRes; | |
p->readWasFinished = p->mtc.readWasFinished; | |
p->inProcessed = p->mtc.inProcessed; | |
PRF_STR("----- decoding ST -----"); | |
} | |
} | |
#endif | |
*isMT = False; | |
{ | |
SRes res = Lzma2Dec_Decode_ST(p | |
#ifndef _7ZIP_ST | |
, tMode | |
#endif | |
); | |
*inProcessed = p->inProcessed; | |
// res = SZ_OK; // for test | |
if (res == SZ_OK && p->readRes != SZ_OK) | |
res = p->readRes; | |
/* | |
#ifndef _7ZIP_ST | |
if (res == SZ_OK && tMode && p->mtc.parseRes != SZ_OK) | |
res = p->mtc.parseRes; | |
#endif | |
*/ | |
return res; | |
} | |
} | |
/* ---------- Read from CLzma2DecMtHandle Interface ---------- */ | |
SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp, | |
Byte prop, | |
const CLzma2DecMtProps *props, | |
const UInt64 *outDataSize, int finishMode, | |
ISeqInStream *inStream) | |
{ | |
CLzma2DecMt *p = (CLzma2DecMt *)pp; | |
if (prop > 40) | |
return SZ_ERROR_UNSUPPORTED; | |
p->prop = prop; | |
p->props = *props; | |
p->inStream = inStream; | |
p->outSize = 0; | |
p->outSize_Defined = False; | |
if (outDataSize) | |
{ | |
p->outSize_Defined = True; | |
p->outSize = *outDataSize; | |
} | |
p->finishMode = finishMode; | |
p->outProcessed = 0; | |
p->inProcessed = 0; | |
p->inPos = 0; | |
p->inLim = 0; | |
return Lzma2Dec_Prepare_ST(p); | |
} | |
SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp, | |
Byte *data, size_t *outSize, | |
UInt64 *inStreamProcessed) | |
{ | |
CLzma2DecMt *p = (CLzma2DecMt *)pp; | |
ELzmaFinishMode finishMode; | |
SRes readRes; | |
size_t size = *outSize; | |
*outSize = 0; | |
*inStreamProcessed = 0; | |
finishMode = LZMA_FINISH_ANY; | |
if (p->outSize_Defined) | |
{ | |
const UInt64 rem = p->outSize - p->outProcessed; | |
if (size >= rem) | |
{ | |
size = (size_t)rem; | |
if (p->finishMode) | |
finishMode = LZMA_FINISH_END; | |
} | |
} | |
readRes = SZ_OK; | |
for (;;) | |
{ | |
SizeT inCur; | |
SizeT outCur; | |
ELzmaStatus status; | |
SRes res; | |
if (p->inPos == p->inLim && readRes == SZ_OK) | |
{ | |
p->inPos = 0; | |
p->inLim = p->props.inBufSize_ST; | |
readRes = ISeqInStream_Read(p->inStream, p->inBuf, &p->inLim); | |
} | |
inCur = p->inLim - p->inPos; | |
outCur = size; | |
res = Lzma2Dec_DecodeToBuf(&p->dec, data, &outCur, | |
p->inBuf + p->inPos, &inCur, finishMode, &status); | |
p->inPos += inCur; | |
p->inProcessed += inCur; | |
*inStreamProcessed += inCur; | |
p->outProcessed += outCur; | |
*outSize += outCur; | |
size -= outCur; | |
data += outCur; | |
if (res != 0) | |
return res; | |
/* | |
if (status == LZMA_STATUS_FINISHED_WITH_MARK) | |
return readRes; | |
if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT) | |
{ | |
if (p->finishMode && p->outSize_Defined && p->outProcessed >= p->outSize) | |
return SZ_ERROR_DATA; | |
return readRes; | |
} | |
*/ | |
if (inCur == 0 && outCur == 0) | |
return readRes; | |
} | |
} |