| 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 |