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