all repos — mgba @ b1d915abbc8924613bea12ae37e3a39d35d8c08f

mGBA Game Boy Advance Emulator

src/third-party/lzma/XzDec.c (view raw)

  1/* XzDec.c -- Xz Decode
  22015-11-09 : Igor Pavlov : Public domain */
  3
  4#include "Precomp.h"
  5
  6/* #define XZ_DUMP */
  7
  8#ifdef XZ_DUMP
  9#include <stdio.h>
 10#endif
 11
 12#include <stdlib.h>
 13#include <string.h>
 14
 15#include "7zCrc.h"
 16#include "Alloc.h"
 17#include "Bra.h"
 18#include "CpuArch.h"
 19#include "Delta.h"
 20#include "Lzma2Dec.h"
 21
 22#ifdef USE_SUBBLOCK
 23#include "Bcj3Dec.c"
 24#include "SbDec.c"
 25#endif
 26
 27#include "Xz.h"
 28
 29#define XZ_CHECK_SIZE_MAX 64
 30
 31#define CODER_BUF_SIZE (1 << 17)
 32
 33unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value)
 34{
 35  unsigned i, limit;
 36  *value = 0;
 37  limit = (maxSize > 9) ? 9 : (unsigned)maxSize;
 38
 39  for (i = 0; i < limit;)
 40  {
 41    Byte b = p[i];
 42    *value |= (UInt64)(b & 0x7F) << (7 * i++);
 43    if ((b & 0x80) == 0)
 44      return (b == 0 && i != 1) ? 0 : i;
 45  }
 46  return 0;
 47}
 48
 49/* ---------- BraState ---------- */
 50
 51#define BRA_BUF_SIZE (1 << 14)
 52
 53typedef struct
 54{
 55  size_t bufPos;
 56  size_t bufConv;
 57  size_t bufTotal;
 58
 59  UInt32 methodId;
 60  int encodeMode;
 61  UInt32 delta;
 62  UInt32 ip;
 63  UInt32 x86State;
 64  Byte deltaState[DELTA_STATE_SIZE];
 65
 66  Byte buf[BRA_BUF_SIZE];
 67} CBraState;
 68
 69static void BraState_Free(void *pp, ISzAlloc *alloc)
 70{
 71  alloc->Free(alloc, pp);
 72}
 73
 74static SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
 75{
 76  CBraState *p = ((CBraState *)pp);
 77  UNUSED_VAR(alloc);
 78  p->ip = 0;
 79  if (p->methodId == XZ_ID_Delta)
 80  {
 81    if (propSize != 1)
 82      return SZ_ERROR_UNSUPPORTED;
 83    p->delta = (unsigned)props[0] + 1;
 84  }
 85  else
 86  {
 87    if (propSize == 4)
 88    {
 89      UInt32 v = GetUi32(props);
 90      switch (p->methodId)
 91      {
 92        case XZ_ID_PPC:
 93        case XZ_ID_ARM:
 94        case XZ_ID_SPARC:
 95          if ((v & 3) != 0)
 96            return SZ_ERROR_UNSUPPORTED;
 97          break;
 98        case XZ_ID_ARMT:
 99          if ((v & 1) != 0)
100            return SZ_ERROR_UNSUPPORTED;
101          break;
102        case XZ_ID_IA64:
103          if ((v & 0xF) != 0)
104            return SZ_ERROR_UNSUPPORTED;
105          break;
106      }
107      p->ip = v;
108    }
109    else if (propSize != 0)
110      return SZ_ERROR_UNSUPPORTED;
111  }
112  return SZ_OK;
113}
114
115static void BraState_Init(void *pp)
116{
117  CBraState *p = ((CBraState *)pp);
118  p->bufPos = p->bufConv = p->bufTotal = 0;
119  x86_Convert_Init(p->x86State);
120  if (p->methodId == XZ_ID_Delta)
121    Delta_Init(p->deltaState);
122}
123
124#define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: p->bufConv = isa ## _Convert(p->buf, p->bufTotal, p->ip, p->encodeMode); break;
125
126static SRes BraState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
127    int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
128{
129  CBraState *p = ((CBraState *)pp);
130  SizeT destLenOrig = *destLen;
131  SizeT srcLenOrig = *srcLen;
132  UNUSED_VAR(finishMode);
133  *destLen = 0;
134  *srcLen = 0;
135  *wasFinished = 0;
136  while (destLenOrig > 0)
137  {
138    if (p->bufPos != p->bufConv)
139    {
140      size_t curSize = p->bufConv - p->bufPos;
141      if (curSize > destLenOrig)
142        curSize = destLenOrig;
143      memcpy(dest, p->buf + p->bufPos, curSize);
144      p->bufPos += curSize;
145      *destLen += curSize;
146      dest += curSize;
147      destLenOrig -= curSize;
148      continue;
149    }
150    p->bufTotal -= p->bufPos;
151    memmove(p->buf, p->buf + p->bufPos, p->bufTotal);
152    p->bufPos = 0;
153    p->bufConv = 0;
154    {
155      size_t curSize = BRA_BUF_SIZE - p->bufTotal;
156      if (curSize > srcLenOrig)
157        curSize = srcLenOrig;
158      memcpy(p->buf + p->bufTotal, src, curSize);
159      *srcLen += curSize;
160      src += curSize;
161      srcLenOrig -= curSize;
162      p->bufTotal += curSize;
163    }
164    if (p->bufTotal == 0)
165      break;
166    switch (p->methodId)
167    {
168      case XZ_ID_Delta:
169        if (p->encodeMode)
170          Delta_Encode(p->deltaState, p->delta, p->buf, p->bufTotal);
171        else
172          Delta_Decode(p->deltaState, p->delta, p->buf, p->bufTotal);
173        p->bufConv = p->bufTotal;
174        break;
175      case XZ_ID_X86:
176        p->bufConv = x86_Convert(p->buf, p->bufTotal, p->ip, &p->x86State, p->encodeMode);
177        break;
178      CASE_BRA_CONV(PPC)
179      CASE_BRA_CONV(IA64)
180      CASE_BRA_CONV(ARM)
181      CASE_BRA_CONV(ARMT)
182      CASE_BRA_CONV(SPARC)
183      default:
184        return SZ_ERROR_UNSUPPORTED;
185    }
186    p->ip += (UInt32)p->bufConv;
187
188    if (p->bufConv == 0)
189    {
190      if (!srcWasFinished)
191        break;
192      p->bufConv = p->bufTotal;
193    }
194  }
195  if (p->bufTotal == p->bufPos && srcLenOrig == 0 && srcWasFinished)
196    *wasFinished = 1;
197  return SZ_OK;
198}
199
200SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAlloc *alloc)
201{
202  CBraState *decoder;
203  if (id != XZ_ID_Delta &&
204      id != XZ_ID_X86 &&
205      id != XZ_ID_PPC &&
206      id != XZ_ID_IA64 &&
207      id != XZ_ID_ARM &&
208      id != XZ_ID_ARMT &&
209      id != XZ_ID_SPARC)
210    return SZ_ERROR_UNSUPPORTED;
211  p->p = 0;
212  decoder = (CBraState *)alloc->Alloc(alloc, sizeof(CBraState));
213  if (decoder == 0)
214    return SZ_ERROR_MEM;
215  decoder->methodId = (UInt32)id;
216  decoder->encodeMode = encodeMode;
217  p->p = decoder;
218  p->Free = BraState_Free;
219  p->SetProps = BraState_SetProps;
220  p->Init = BraState_Init;
221  p->Code = BraState_Code;
222  return SZ_OK;
223}
224
225/* ---------- SbState ---------- */
226
227#ifdef USE_SUBBLOCK
228
229static void SbState_Free(void *pp, ISzAlloc *alloc)
230{
231  CSbDec *p = (CSbDec *)pp;
232  SbDec_Free(p);
233  alloc->Free(alloc, pp);
234}
235
236static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
237{
238  UNUSED_VAR(pp);
239  UNUSED_VAR(props);
240  UNUSED_VAR(alloc);
241  return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
242}
243
244static void SbState_Init(void *pp)
245{
246  SbDec_Init((CSbDec *)pp);
247}
248
249static SRes SbState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
250    int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
251{
252  CSbDec *p = (CSbDec *)pp;
253  SRes res;
254  UNUSED_VAR(srcWasFinished);
255  p->dest = dest;
256  p->destLen = *destLen;
257  p->src = src;
258  p->srcLen = *srcLen;
259  p->finish = finishMode; /* change it */
260  res = SbDec_Decode((CSbDec *)pp);
261  *destLen -= p->destLen;
262  *srcLen -= p->srcLen;
263  *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */
264  return res;
265}
266
267SRes SbState_SetFromMethod(IStateCoder *p, ISzAlloc *alloc)
268{
269  CSbDec *decoder;
270  p->p = 0;
271  decoder = alloc->Alloc(alloc, sizeof(CSbDec));
272  if (decoder == 0)
273    return SZ_ERROR_MEM;
274  p->p = decoder;
275  p->Free = SbState_Free;
276  p->SetProps = SbState_SetProps;
277  p->Init = SbState_Init;
278  p->Code = SbState_Code;
279  SbDec_Construct(decoder);
280  SbDec_SetAlloc(decoder, alloc);
281  return SZ_OK;
282}
283#endif
284
285/* ---------- Lzma2State ---------- */
286
287static void Lzma2State_Free(void *pp, ISzAlloc *alloc)
288{
289  Lzma2Dec_Free((CLzma2Dec *)pp, alloc);
290  alloc->Free(alloc, pp);
291}
292
293static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
294{
295  if (propSize != 1)
296    return SZ_ERROR_UNSUPPORTED;
297  return Lzma2Dec_Allocate((CLzma2Dec *)pp, props[0], alloc);
298}
299
300static void Lzma2State_Init(void *pp)
301{
302  Lzma2Dec_Init((CLzma2Dec *)pp);
303}
304
305static SRes Lzma2State_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
306    int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
307{
308  ELzmaStatus status;
309  /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */
310  SRes res = Lzma2Dec_DecodeToBuf((CLzma2Dec *)pp, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status);
311  UNUSED_VAR(srcWasFinished);
312  *wasFinished = (status == LZMA_STATUS_FINISHED_WITH_MARK);
313  return res;
314}
315
316static SRes Lzma2State_SetFromMethod(IStateCoder *p, ISzAlloc *alloc)
317{
318  CLzma2Dec *decoder = (CLzma2Dec *)alloc->Alloc(alloc, sizeof(CLzma2Dec));
319  p->p = decoder;
320  if (decoder == 0)
321    return SZ_ERROR_MEM;
322  p->Free = Lzma2State_Free;
323  p->SetProps = Lzma2State_SetProps;
324  p->Init = Lzma2State_Init;
325  p->Code = Lzma2State_Code;
326  Lzma2Dec_Construct(decoder);
327  return SZ_OK;
328}
329
330
331void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc)
332{
333  unsigned i;
334  p->alloc = alloc;
335  p->buf = NULL;
336  p->numCoders = 0;
337  for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
338    p->coders[i].p = NULL;
339}
340
341void MixCoder_Free(CMixCoder *p)
342{
343  unsigned i;
344  for (i = 0; i < p->numCoders; i++)
345  {
346    IStateCoder *sc = &p->coders[i];
347    if (p->alloc && sc->p)
348      sc->Free(sc->p, p->alloc);
349  }
350  p->numCoders = 0;
351  if (p->buf)
352  {
353    p->alloc->Free(p->alloc, p->buf);
354    p->buf = NULL; /* 9.31: the BUG was fixed */
355  }
356}
357
358void MixCoder_Init(CMixCoder *p)
359{
360  unsigned i;
361  for (i = 0; i < MIXCODER_NUM_FILTERS_MAX - 1; i++)
362  {
363    p->size[i] = 0;
364    p->pos[i] = 0;
365    p->finished[i] = 0;
366  }
367  for (i = 0; i < p->numCoders; i++)
368  {
369    IStateCoder *coder = &p->coders[i];
370    coder->Init(coder->p);
371  }
372}
373
374SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId)
375{
376  IStateCoder *sc = &p->coders[coderIndex];
377  p->ids[coderIndex] = methodId;
378  switch (methodId)
379  {
380    case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, p->alloc);
381    #ifdef USE_SUBBLOCK
382    case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc);
383    #endif
384  }
385  if (coderIndex == 0)
386    return SZ_ERROR_UNSUPPORTED;
387  return BraState_SetFromMethod(sc, methodId, 0, p->alloc);
388}
389
390SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen,
391    const Byte *src, SizeT *srcLen, int srcWasFinished,
392    ECoderFinishMode finishMode, ECoderStatus *status)
393{
394  SizeT destLenOrig = *destLen;
395  SizeT srcLenOrig = *srcLen;
396  Bool allFinished = True;
397  *destLen = 0;
398  *srcLen = 0;
399  *status = CODER_STATUS_NOT_FINISHED;
400
401  if (!p->buf)
402  {
403    p->buf = (Byte *)p->alloc->Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1));
404    if (!p->buf)
405      return SZ_ERROR_MEM;
406  }
407
408  if (p->numCoders != 1)
409    finishMode = CODER_FINISH_ANY;
410
411  for (;;)
412  {
413    Bool processed = False;
414    unsigned i;
415    /*
416    if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY)
417      break;
418    */
419
420    for (i = 0; i < p->numCoders; i++)
421    {
422      SRes res;
423      IStateCoder *coder = &p->coders[i];
424      Byte *destCur;
425      SizeT destLenCur, srcLenCur;
426      const Byte *srcCur;
427      int srcFinishedCur;
428      int encodingWasFinished;
429      
430      if (i == 0)
431      {
432        srcCur = src;
433        srcLenCur = srcLenOrig - *srcLen;
434        srcFinishedCur = srcWasFinished;
435      }
436      else
437      {
438        srcCur = p->buf + (CODER_BUF_SIZE * (i - 1)) + p->pos[i - 1];
439        srcLenCur = p->size[i - 1] - p->pos[i - 1];
440        srcFinishedCur = p->finished[i - 1];
441      }
442      
443      if (i == p->numCoders - 1)
444      {
445        destCur = dest;
446        destLenCur = destLenOrig - *destLen;
447      }
448      else
449      {
450        if (p->pos[i] != p->size[i])
451          continue;
452        destCur = p->buf + (CODER_BUF_SIZE * i);
453        destLenCur = CODER_BUF_SIZE;
454      }
455      
456      res = coder->Code(coder->p, destCur, &destLenCur, srcCur, &srcLenCur, srcFinishedCur, finishMode, &encodingWasFinished);
457
458      if (!encodingWasFinished)
459        allFinished = False;
460
461      if (i == 0)
462      {
463        *srcLen += srcLenCur;
464        src += srcLenCur;
465      }
466      else
467      {
468        p->pos[i - 1] += srcLenCur;
469      }
470
471      if (i == p->numCoders - 1)
472      {
473        *destLen += destLenCur;
474        dest += destLenCur;
475      }
476      else
477      {
478        p->size[i] = destLenCur;
479        p->pos[i] = 0;
480        p->finished[i] = encodingWasFinished;
481      }
482      
483      if (res != SZ_OK)
484        return res;
485
486      if (destLenCur != 0 || srcLenCur != 0)
487        processed = True;
488    }
489    if (!processed)
490      break;
491  }
492  if (allFinished)
493    *status = CODER_STATUS_FINISHED_WITH_MARK;
494  return SZ_OK;
495}
496
497SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf)
498{
499  *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE);
500  if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) !=
501      GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE))
502    return SZ_ERROR_NO_ARCHIVE;
503  return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
504}
505
506static Bool Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf)
507{
508  return
509      indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2) &&
510      (GetUi32(buf) == CrcCalc(buf + 4, 6) &&
511      flags == GetBe16(buf + 8) &&
512      memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0);
513}
514
515#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
516  { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
517  if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }
518
519
520SRes XzBlock_Parse(CXzBlock *p, const Byte *header)
521{
522  unsigned pos;
523  unsigned numFilters, i;
524  unsigned headerSize = (unsigned)header[0] << 2;
525
526  if (CrcCalc(header, headerSize) != GetUi32(header + headerSize))
527    return SZ_ERROR_ARCHIVE;
528
529  pos = 1;
530  if (pos == headerSize)
531    return SZ_ERROR_ARCHIVE;
532  p->flags = header[pos++];
533
534  if (XzBlock_HasPackSize(p))
535  {
536    READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize);
537    if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63)
538      return SZ_ERROR_ARCHIVE;
539  }
540
541  if (XzBlock_HasUnpackSize(p))
542    READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize);
543
544  numFilters = XzBlock_GetNumFilters(p);
545  for (i = 0; i < numFilters; i++)
546  {
547    CXzFilter *filter = p->filters + i;
548    UInt64 size;
549    READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id);
550    READ_VARINT_AND_CHECK(header, pos, headerSize, &size);
551    if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX)
552      return SZ_ERROR_ARCHIVE;
553    filter->propsSize = (UInt32)size;
554    memcpy(filter->props, header + pos, (size_t)size);
555    pos += (unsigned)size;
556
557    #ifdef XZ_DUMP
558    printf("\nf[%u] = %2X: ", i, (unsigned)filter->id);
559    {
560      unsigned i;
561      for (i = 0; i < size; i++)
562        printf(" %2X", filter->props[i]);
563    }
564    #endif
565  }
566
567  while (pos < headerSize)
568    if (header[pos++] != 0)
569      return SZ_ERROR_ARCHIVE;
570  return SZ_OK;
571}
572
573SRes XzDec_Init(CMixCoder *p, const CXzBlock *block)
574{
575  unsigned i;
576  Bool needReInit = True;
577  unsigned numFilters = XzBlock_GetNumFilters(block);
578  
579  if (numFilters == p->numCoders)
580  {
581    for (i = 0; i < numFilters; i++)
582      if (p->ids[i] != block->filters[numFilters - 1 - i].id)
583        break;
584    needReInit = (i != numFilters);
585  }
586  
587  if (needReInit)
588  {
589    MixCoder_Free(p);
590    p->numCoders = numFilters;
591    for (i = 0; i < numFilters; i++)
592    {
593      const CXzFilter *f = &block->filters[numFilters - 1 - i];
594      RINOK(MixCoder_SetFromMethod(p, i, f->id));
595    }
596  }
597  
598  for (i = 0; i < numFilters; i++)
599  {
600    const CXzFilter *f = &block->filters[numFilters - 1 - i];
601    IStateCoder *sc = &p->coders[i];
602    RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc));
603  }
604  
605  MixCoder_Init(p);
606  return SZ_OK;
607}
608
609void XzUnpacker_Init(CXzUnpacker *p)
610{
611  p->state = XZ_STATE_STREAM_HEADER;
612  p->pos = 0;
613  p->numStartedStreams = 0;
614  p->numFinishedStreams = 0;
615  p->numTotalBlocks = 0;
616  p->padSize = 0;
617}
618
619void XzUnpacker_Construct(CXzUnpacker *p, ISzAlloc *alloc)
620{
621  MixCoder_Construct(&p->decoder, alloc);
622  XzUnpacker_Init(p);
623}
624
625void XzUnpacker_Free(CXzUnpacker *p)
626{
627  MixCoder_Free(&p->decoder);
628}
629
630SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
631    const Byte *src, SizeT *srcLen, ECoderFinishMode finishMode, ECoderStatus *status)
632{
633  SizeT destLenOrig = *destLen;
634  SizeT srcLenOrig = *srcLen;
635  *destLen = 0;
636  *srcLen = 0;
637  *status = CODER_STATUS_NOT_SPECIFIED;
638  for (;;)
639  {
640    SizeT srcRem = srcLenOrig - *srcLen;
641
642    if (p->state == XZ_STATE_BLOCK)
643    {
644      SizeT destLen2 = destLenOrig - *destLen;
645      SizeT srcLen2 = srcLenOrig - *srcLen;
646      SRes res;
647      if (srcLen2 == 0 && destLen2 == 0)
648      {
649        *status = CODER_STATUS_NOT_FINISHED;
650        return SZ_OK;
651      }
652      
653      res = MixCoder_Code(&p->decoder, dest, &destLen2, src, &srcLen2, False, finishMode, status);
654      XzCheck_Update(&p->check, dest, destLen2);
655      
656      (*srcLen) += srcLen2;
657      src += srcLen2;
658      p->packSize += srcLen2;
659      
660      (*destLen) += destLen2;
661      dest += destLen2;
662      p->unpackSize += destLen2;
663      
664      RINOK(res);
665      
666      if (*status == CODER_STATUS_FINISHED_WITH_MARK)
667      {
668        Byte temp[32];
669        unsigned num = Xz_WriteVarInt(temp, p->packSize + p->blockHeaderSize + XzFlags_GetCheckSize(p->streamFlags));
670        num += Xz_WriteVarInt(temp + num, p->unpackSize);
671        Sha256_Update(&p->sha, temp, num);
672        p->indexSize += num;
673        p->numBlocks++;
674        
675        p->state = XZ_STATE_BLOCK_FOOTER;
676        p->pos = 0;
677        p->alignPos = 0;
678      }
679      else if (srcLen2 == 0 && destLen2 == 0)
680        return SZ_OK;
681      
682      continue;
683    }
684
685    if (srcRem == 0)
686    {
687      *status = CODER_STATUS_NEEDS_MORE_INPUT;
688      return SZ_OK;
689    }
690
691    switch (p->state)
692    {
693      case XZ_STATE_STREAM_HEADER:
694      {
695        if (p->pos < XZ_STREAM_HEADER_SIZE)
696        {
697          if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos])
698            return SZ_ERROR_NO_ARCHIVE;
699          p->buf[p->pos++] = *src++;
700          (*srcLen)++;
701        }
702        else
703        {
704          RINOK(Xz_ParseHeader(&p->streamFlags, p->buf));
705          p->numStartedStreams++;
706          p->state = XZ_STATE_BLOCK_HEADER;
707          Sha256_Init(&p->sha);
708          p->indexSize = 0;
709          p->numBlocks = 0;
710          p->pos = 0;
711        }
712        break;
713      }
714
715      case XZ_STATE_BLOCK_HEADER:
716      {
717        if (p->pos == 0)
718        {
719          p->buf[p->pos++] = *src++;
720          (*srcLen)++;
721          if (p->buf[0] == 0)
722          {
723            p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks);
724            p->indexPos = p->indexPreSize;
725            p->indexSize += p->indexPreSize;
726            Sha256_Final(&p->sha, p->shaDigest);
727            Sha256_Init(&p->sha);
728            p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize);
729            p->state = XZ_STATE_STREAM_INDEX;
730          }
731          p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4;
732        }
733        else if (p->pos != p->blockHeaderSize)
734        {
735          UInt32 cur = p->blockHeaderSize - p->pos;
736          if (cur > srcRem)
737            cur = (UInt32)srcRem;
738          memcpy(p->buf + p->pos, src, cur);
739          p->pos += cur;
740          (*srcLen) += cur;
741          src += cur;
742        }
743        else
744        {
745          RINOK(XzBlock_Parse(&p->block, p->buf));
746          p->numTotalBlocks++;
747          p->state = XZ_STATE_BLOCK;
748          p->packSize = 0;
749          p->unpackSize = 0;
750          XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags));
751          RINOK(XzDec_Init(&p->decoder, &p->block));
752        }
753        break;
754      }
755
756      case XZ_STATE_BLOCK_FOOTER:
757      {
758        if (((p->packSize + p->alignPos) & 3) != 0)
759        {
760          (*srcLen)++;
761          p->alignPos++;
762          if (*src++ != 0)
763            return SZ_ERROR_CRC;
764        }
765        else
766        {
767          UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags);
768          UInt32 cur = checkSize - p->pos;
769          if (cur != 0)
770          {
771            if (cur > srcRem)
772              cur = (UInt32)srcRem;
773            memcpy(p->buf + p->pos, src, cur);
774            p->pos += cur;
775            (*srcLen) += cur;
776            src += cur;
777          }
778          else
779          {
780            Byte digest[XZ_CHECK_SIZE_MAX];
781            p->state = XZ_STATE_BLOCK_HEADER;
782            p->pos = 0;
783            if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0)
784              return SZ_ERROR_CRC;
785          }
786        }
787        break;
788      }
789
790      case XZ_STATE_STREAM_INDEX:
791      {
792        if (p->pos < p->indexPreSize)
793        {
794          (*srcLen)++;
795          if (*src++ != p->buf[p->pos++])
796            return SZ_ERROR_CRC;
797        }
798        else
799        {
800          if (p->indexPos < p->indexSize)
801          {
802            UInt64 cur = p->indexSize - p->indexPos;
803            if (srcRem > cur)
804              srcRem = (SizeT)cur;
805            p->crc = CrcUpdate(p->crc, src, srcRem);
806            Sha256_Update(&p->sha, src, srcRem);
807            (*srcLen) += srcRem;
808            src += srcRem;
809            p->indexPos += srcRem;
810          }
811          else if ((p->indexPos & 3) != 0)
812          {
813            Byte b = *src++;
814            p->crc = CRC_UPDATE_BYTE(p->crc, b);
815            (*srcLen)++;
816            p->indexPos++;
817            p->indexSize++;
818            if (b != 0)
819              return SZ_ERROR_CRC;
820          }
821          else
822          {
823            Byte digest[SHA256_DIGEST_SIZE];
824            p->state = XZ_STATE_STREAM_INDEX_CRC;
825            p->indexSize += 4;
826            p->pos = 0;
827            Sha256_Final(&p->sha, digest);
828            if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0)
829              return SZ_ERROR_CRC;
830          }
831        }
832        break;
833      }
834
835      case XZ_STATE_STREAM_INDEX_CRC:
836      {
837        if (p->pos < 4)
838        {
839          (*srcLen)++;
840          p->buf[p->pos++] = *src++;
841        }
842        else
843        {
844          p->state = XZ_STATE_STREAM_FOOTER;
845          p->pos = 0;
846          if (CRC_GET_DIGEST(p->crc) != GetUi32(p->buf))
847            return SZ_ERROR_CRC;
848        }
849        break;
850      }
851
852      case XZ_STATE_STREAM_FOOTER:
853      {
854        UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos;
855        if (cur > srcRem)
856          cur = (UInt32)srcRem;
857        memcpy(p->buf + p->pos, src, cur);
858        p->pos += cur;
859        (*srcLen) += cur;
860        src += cur;
861        if (p->pos == XZ_STREAM_FOOTER_SIZE)
862        {
863          p->state = XZ_STATE_STREAM_PADDING;
864          p->numFinishedStreams++;
865          p->padSize = 0;
866          if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf))
867            return SZ_ERROR_CRC;
868        }
869        break;
870      }
871
872      case XZ_STATE_STREAM_PADDING:
873      {
874        if (*src != 0)
875        {
876          if (((UInt32)p->padSize & 3) != 0)
877            return SZ_ERROR_NO_ARCHIVE;
878          p->pos = 0;
879          p->state = XZ_STATE_STREAM_HEADER;
880        }
881        else
882        {
883          (*srcLen)++;
884          src++;
885          p->padSize++;
886        }
887        break;
888      }
889      
890      case XZ_STATE_BLOCK: break; /* to disable GCC warning */
891    }
892  }
893  /*
894  if (p->state == XZ_STATE_FINISHED)
895    *status = CODER_STATUS_FINISHED_WITH_MARK;
896  return SZ_OK;
897  */
898}
899
900Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p)
901{
902  return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0);
903}
904
905UInt64 XzUnpacker_GetExtraSize(CXzUnpacker *p)
906{
907  UInt64 num = 0;
908  if (p->state == XZ_STATE_STREAM_PADDING)
909    num += p->padSize;
910  else if (p->state == XZ_STATE_STREAM_HEADER)
911    num += p->padSize + p->pos;
912  return num;
913}