static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) { switch(p->state) { case LZMA2_STATE_CONTROL: p->control = b; PRF(printf("\n %4X ", p->decoder.dicPos)); PRF(printf(" %2X", b)); if (p->control == 0) return LZMA2_STATE_FINISHED; if (LZMA2_IS_UNCOMPRESSED_STATE(p)) { if ((p->control & 0x7F) > 2) return LZMA2_STATE_ERROR; p->unpackSize = 0; } else p->unpackSize = (UInt32)(p->control & 0x1F) << 16; return LZMA2_STATE_UNPACK0; case LZMA2_STATE_UNPACK0: p->unpackSize |= (UInt32)b << 8; return LZMA2_STATE_UNPACK1; case LZMA2_STATE_UNPACK1: p->unpackSize |= (UInt32)b; p->unpackSize++; PRF(printf(" %8d", p->unpackSize)); return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; case LZMA2_STATE_PACK0: p->packSize = (UInt32)b << 8; return LZMA2_STATE_PACK1; case LZMA2_STATE_PACK1: p->packSize |= (UInt32)b; p->packSize++; PRF(printf(" %8d", p->packSize)); return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP: (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA); case LZMA2_STATE_PROP: { int lc, lp; if (b >= (9 * 5 * 5)) return LZMA2_STATE_ERROR; lc = b % 9; b /= 9; p->decoder.prop.pb = b / 5; lp = b % 5; if (lc + lp > LZMA2_LCLP_MAX) return LZMA2_STATE_ERROR; p->decoder.prop.lc = lc; p->decoder.prop.lp = lp; p->needInitProp = False; return LZMA2_STATE_DATA; } } return LZMA2_STATE_ERROR; }
static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) { switch (p->state) { case LZMA2_STATE_CONTROL: p->isExtraMode = False; p->control = b; PRF(printf("\n %8X", (unsigned)p->decoder.dicPos)); PRF(printf(" %02X", (unsigned)b)); if (b == 0) return LZMA2_STATE_FINISHED; if (LZMA2_IS_UNCOMPRESSED_STATE(p)) { if (b == LZMA2_CONTROL_COPY_RESET_DIC) p->needInitLevel = 0xC0; else if (b > 2 || p->needInitLevel == 0xE0) return LZMA2_STATE_ERROR; } else { if (b < p->needInitLevel) return LZMA2_STATE_ERROR; p->needInitLevel = 0; p->unpackSize = (UInt32)(b & 0x1F) << 16; } return LZMA2_STATE_UNPACK0; case LZMA2_STATE_UNPACK0: p->unpackSize |= (UInt32)b << 8; return LZMA2_STATE_UNPACK1; case LZMA2_STATE_UNPACK1: p->unpackSize |= (UInt32)b; p->unpackSize++; PRF(printf(" %7u", (unsigned)p->unpackSize)); return LZMA2_IS_UNCOMPRESSED_STATE(p) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; case LZMA2_STATE_PACK0: p->packSize = (UInt32)b << 8; return LZMA2_STATE_PACK1; case LZMA2_STATE_PACK1: p->packSize |= (UInt32)b; p->packSize++; // if (p->packSize < 5) return LZMA2_STATE_ERROR; PRF(printf(" %5u", (unsigned)p->packSize)); return (p->control & 0x40) ? LZMA2_STATE_PROP : LZMA2_STATE_DATA; case LZMA2_STATE_PROP: { unsigned lc, lp; if (b >= (9 * 5 * 5)) return LZMA2_STATE_ERROR; lc = b % 9; b /= 9; p->decoder.prop.pb = (Byte)(b / 5); lp = b % 5; if (lc + lp > LZMA2_LCLP_MAX) return LZMA2_STATE_ERROR; p->decoder.prop.lc = (Byte)lc; p->decoder.prop.lp = (Byte)lp; return LZMA2_STATE_DATA; } } return LZMA2_STATE_ERROR; }
ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p, SizeT outSize, const Byte *src, SizeT *srcLen, int checkFinishBlock) { SizeT inSize = *srcLen; *srcLen = 0; while (p->state != LZMA2_STATE_ERROR) { if (p->state == LZMA2_STATE_FINISHED) return (ELzma2ParseStatus)LZMA_STATUS_FINISHED_WITH_MARK; if (outSize == 0 && !checkFinishBlock) return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) { if (*srcLen == inSize) return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; (*srcLen)++; p->state = Lzma2Dec_UpdateState(p, *src++); if (p->state == LZMA2_STATE_UNPACK0) { // if (p->decoder.dicPos != 0) if (p->control == LZMA2_CONTROL_COPY_RESET_DIC || p->control >= 0xE0) return LZMA2_PARSE_STATUS_NEW_BLOCK; // if (outSize == 0) return LZMA_STATUS_NOT_FINISHED; } // The following code can be commented. // It's not big problem, if we read additional input bytes. // It will be stopped later in LZMA2_STATE_DATA / LZMA2_STATE_DATA_CONT state. if (outSize == 0 && p->state != LZMA2_STATE_FINISHED) { // checkFinishBlock is true. So we expect that block must be finished, // We can return LZMA_STATUS_NOT_SPECIFIED or LZMA_STATUS_NOT_FINISHED here // break; return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; } if (p->state == LZMA2_STATE_DATA) return LZMA2_PARSE_STATUS_NEW_CHUNK; continue; } if (outSize == 0) return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; { SizeT inCur = inSize - *srcLen; if (LZMA2_IS_UNCOMPRESSED_STATE(p)) { if (inCur == 0) return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; if (inCur > p->unpackSize) inCur = p->unpackSize; if (inCur > outSize) inCur = outSize; p->decoder.dicPos += inCur; src += inCur; *srcLen += inCur; outSize -= inCur; p->unpackSize -= (UInt32)inCur; p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; } else { p->isExtraMode = True; if (inCur == 0) { if (p->packSize != 0) return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; } else if (p->state == LZMA2_STATE_DATA) { p->state = LZMA2_STATE_DATA_CONT; if (*src != 0) { // first byte of lzma chunk must be Zero *srcLen += 1; p->packSize--; break; } } if (inCur > p->packSize) inCur = (SizeT)p->packSize; src += inCur; *srcLen += inCur; p->packSize -= (UInt32)inCur; if (p->packSize == 0) { SizeT rem = outSize; if (rem > p->unpackSize) rem = p->unpackSize; p->decoder.dicPos += rem; p->unpackSize -= (UInt32)rem; outSize -= rem; if (p->unpackSize == 0) p->state = LZMA2_STATE_CONTROL; } } } } p->state = LZMA2_STATE_ERROR; return (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED; }
SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT inSize = *srcLen; *srcLen = 0; *status = LZMA_STATUS_NOT_SPECIFIED; while (p->state != LZMA2_STATE_ERROR) { SizeT dicPos; if (p->state == LZMA2_STATE_FINISHED) { *status = LZMA_STATUS_FINISHED_WITH_MARK; return SZ_OK; } dicPos = p->decoder.dicPos; if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_OK; } if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) { if (*srcLen == inSize) { *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } (*srcLen)++; p->state = Lzma2Dec_UpdateState(p, *src++); if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED) break; continue; } { SizeT inCur = inSize - *srcLen; SizeT outCur = dicLimit - dicPos; ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; if (outCur >= p->unpackSize) { outCur = (SizeT)p->unpackSize; curFinishMode = LZMA_FINISH_END; } if (LZMA2_IS_UNCOMPRESSED_STATE(p)) { if (inCur == 0) { *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (p->state == LZMA2_STATE_DATA) { BoolInt initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); LzmaDec_InitDicAndState(&p->decoder, initDic, False); } if (inCur > outCur) inCur = outCur; if (inCur == 0) break; LzmaDec_UpdateWithUncompressed(&p->decoder, src, inCur); src += inCur; *srcLen += inCur; p->unpackSize -= (UInt32)inCur; p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; } else { SRes res; if (p->state == LZMA2_STATE_DATA) { BoolInt initDic = (p->control >= 0xE0); BoolInt initState = (p->control >= 0xA0); LzmaDec_InitDicAndState(&p->decoder, initDic, initState); p->state = LZMA2_STATE_DATA_CONT; } if (inCur > p->packSize) inCur = (SizeT)p->packSize; res = LzmaDec_DecodeToDic(&p->decoder, dicPos + outCur, src, &inCur, curFinishMode, status); src += inCur; *srcLen += inCur; p->packSize -= (UInt32)inCur; outCur = p->decoder.dicPos - dicPos; p->unpackSize -= (UInt32)outCur; if (res != 0) break; if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) { if (p->packSize == 0) break; return SZ_OK; } if (inCur == 0 && outCur == 0) { if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK || p->unpackSize != 0 || p->packSize != 0) break; p->state = LZMA2_STATE_CONTROL; } *status = LZMA_STATUS_NOT_SPECIFIED; } } } *status = LZMA_STATUS_NOT_SPECIFIED; p->state = LZMA2_STATE_ERROR; return SZ_ERROR_DATA; }
SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT inSize = *srcLen; *srcLen = 0; *status = LZMA_STATUS_NOT_SPECIFIED; while (p->state != LZMA2_STATE_FINISHED) { SizeT dicPos = p->decoder.dicPos; if (p->state == LZMA2_STATE_ERROR) return SZ_ERROR_DATA; if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_OK; } if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) { if (*srcLen == inSize) { *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } (*srcLen)++; p->state = Lzma2Dec_UpdateState(p, *src++); continue; } { SizeT destSizeCur = dicLimit - dicPos; SizeT srcSizeCur = inSize - *srcLen; ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; if (p->unpackSize <= destSizeCur) { destSizeCur = (SizeT)p->unpackSize; curFinishMode = LZMA_FINISH_END; } if (LZMA2_IS_UNCOMPRESSED_STATE(p)) { if (*srcLen == inSize) { *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (p->state == LZMA2_STATE_DATA) { Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); if (initDic) p->needInitProp = p->needInitState = True; else if (p->needInitDic) return SZ_ERROR_DATA; p->needInitDic = False; LzmaDec_InitDicAndState(&p->decoder, initDic, False); } if (srcSizeCur > destSizeCur) srcSizeCur = destSizeCur; if (srcSizeCur == 0) return SZ_ERROR_DATA; LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur); src += srcSizeCur; *srcLen += srcSizeCur; p->unpackSize -= (UInt32)srcSizeCur; p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; } else { SizeT outSizeProcessed; SRes res; if (p->state == LZMA2_STATE_DATA) { int mode = LZMA2_GET_LZMA_MODE(p); Bool initDic = (mode == 3); Bool initState = (mode > 0); if ((!initDic && p->needInitDic) || (!initState && p->needInitState)) return SZ_ERROR_DATA; LzmaDec_InitDicAndState(&p->decoder, initDic, initState); p->needInitDic = False; p->needInitState = False; p->state = LZMA2_STATE_DATA_CONT; } if (srcSizeCur > p->packSize) srcSizeCur = (SizeT)p->packSize; res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status); src += srcSizeCur; *srcLen += srcSizeCur; p->packSize -= (UInt32)srcSizeCur; outSizeProcessed = p->decoder.dicPos - dicPos; p->unpackSize -= (UInt32)outSizeProcessed; RINOK(res); if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) return res; if (srcSizeCur == 0 && outSizeProcessed == 0) { if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK || p->unpackSize != 0 || p->packSize != 0) return SZ_ERROR_DATA; p->state = LZMA2_STATE_CONTROL; } if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) *status = LZMA_STATUS_NOT_FINISHED; } } } *status = LZMA_STATUS_FINISHED_WITH_MARK; return SZ_OK; }