add CHD support.
[pcsx_rearmed.git] / deps / lzma-16.04 / C / XzDec.c
CommitLineData
ce188d4d 1/* XzDec.c -- Xz Decode\r
22015-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
33unsigned 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
53typedef 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
69static void BraState_Free(void *pp, ISzAlloc *alloc)\r
70{\r
71 alloc->Free(alloc, pp);\r
72}\r
73\r
74static 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
115static 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
126static 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
200SRes 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
229static 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
236static 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
244static void SbState_Init(void *pp)\r
245{\r
246 SbDec_Init((CSbDec *)pp);\r
247}\r
248\r
249static 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
267SRes 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
287static 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
293static 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
300static void Lzma2State_Init(void *pp)\r
301{\r
302 Lzma2Dec_Init((CLzma2Dec *)pp);\r
303}\r
304\r
305static 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
316static 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
331void 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
341void 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
358void 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
374SRes 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
390SRes 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
497SRes 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
506static 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
520SRes 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
573SRes 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
609void 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
619void 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
625void XzUnpacker_Free(CXzUnpacker *p)\r
626{\r
627 MixCoder_Free(&p->decoder);\r
628}\r
629\r
630SRes 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
900Bool 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
905UInt64 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