1 /* 7zDec.c -- Decoding from 7z folder
2 2019-02-02 : Igor Pavlov : Public domain */
8 /* #define _7ZIP_PPMD_SUPPPORT */
19 #ifdef _7ZIP_PPMD_SUPPPORT
26 #define k_LZMA 0x30101
27 #define k_BCJ 0x3030103
28 #define k_BCJ2 0x303011B
29 #define k_PPC 0x3030205
30 #define k_IA64 0x3030401
31 #define k_ARM 0x3030501
32 #define k_ARMT 0x3030701
33 #define k_SPARC 0x3030805
36 #ifdef _7ZIP_PPMD_SUPPPORT
38 #define k_PPMD 0x30401
49 const ILookInStream
*inStream
;
52 static Byte
ReadByte(const IByteIn
*pp
)
54 CByteInToLook
*p
= CONTAINER_FROM_VTBL(pp
, CByteInToLook
, vt
);
59 size_t size
= p
->cur
- p
->begin
;
61 p
->res
= ILookInStream_Skip(p
->inStream
, size
);
63 p
->res
= ILookInStream_Look(p
->inStream
, (const void **)&p
->begin
, &size
);
65 p
->end
= p
->begin
+ size
;
73 static SRes
SzDecodePpmd(const Byte
*props
, unsigned propsSize
, UInt64 inSize
, const ILookInStream
*inStream
,
74 Byte
*outBuffer
, SizeT outSize
, ISzAllocPtr allocMain
)
81 s
.inStream
= inStream
;
82 s
.begin
= s
.end
= s
.cur
= NULL
;
88 return SZ_ERROR_UNSUPPORTED
;
91 unsigned order
= props
[0];
92 UInt32 memSize
= GetUi32(props
+ 1);
93 if (order
< PPMD7_MIN_ORDER
||
94 order
> PPMD7_MAX_ORDER
||
95 memSize
< PPMD7_MIN_MEM_SIZE
||
96 memSize
> PPMD7_MAX_MEM_SIZE
)
97 return SZ_ERROR_UNSUPPORTED
;
98 Ppmd7_Construct(&ppmd
);
99 if (!Ppmd7_Alloc(&ppmd
, memSize
, allocMain
))
101 Ppmd7_Init(&ppmd
, order
);
105 Ppmd7z_RangeDec_CreateVTable(&rc
);
107 if (!Ppmd7z_RangeDec_Init(&rc
))
110 res
= (s
.res
!= SZ_OK
? s
.res
: SZ_ERROR_DATA
);
114 for (i
= 0; i
< outSize
; i
++)
116 int sym
= Ppmd7_DecodeSymbol(&ppmd
, &rc
.vt
);
117 if (s
.extra
|| sym
< 0)
119 outBuffer
[i
] = (Byte
)sym
;
122 res
= (s
.res
!= SZ_OK
? s
.res
: SZ_ERROR_DATA
);
123 else if (s
.processed
+ (s
.cur
- s
.begin
) != inSize
|| !Ppmd7z_RangeDec_IsFinishedOK(&rc
))
127 Ppmd7_Free(&ppmd
, allocMain
);
134 static SRes
SzDecodeLzma(const Byte
*props
, unsigned propsSize
, UInt64 inSize
, ILookInStream
*inStream
,
135 Byte
*outBuffer
, SizeT outSize
, ISzAllocPtr allocMain
)
140 LzmaDec_Construct(&state
);
141 RINOK(LzmaDec_AllocateProbs(&state
, props
, propsSize
, allocMain
));
142 state
.dic
= outBuffer
;
143 state
.dicBufSize
= outSize
;
144 LzmaDec_Init(&state
);
148 const void *inBuf
= NULL
;
149 size_t lookahead
= (1 << 18);
150 if (lookahead
> inSize
)
151 lookahead
= (size_t)inSize
;
152 res
= ILookInStream_Look(inStream
, &inBuf
, &lookahead
);
157 SizeT inProcessed
= (SizeT
)lookahead
, dicPos
= state
.dicPos
;
159 res
= LzmaDec_DecodeToDic(&state
, outSize
, (const Byte
*)inBuf
, &inProcessed
, LZMA_FINISH_END
, &status
);
160 lookahead
-= inProcessed
;
161 inSize
-= inProcessed
;
165 if (status
== LZMA_STATUS_FINISHED_WITH_MARK
)
167 if (outSize
!= state
.dicPos
|| inSize
!= 0)
172 if (outSize
== state
.dicPos
&& inSize
== 0 && status
== LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
)
175 if (inProcessed
== 0 && dicPos
== state
.dicPos
)
181 res
= ILookInStream_Skip(inStream
, inProcessed
);
187 LzmaDec_FreeProbs(&state
, allocMain
);
192 #ifndef _7Z_NO_METHOD_LZMA2
194 static SRes
SzDecodeLzma2(const Byte
*props
, unsigned propsSize
, UInt64 inSize
, ILookInStream
*inStream
,
195 Byte
*outBuffer
, SizeT outSize
, ISzAllocPtr allocMain
)
200 Lzma2Dec_Construct(&state
);
202 return SZ_ERROR_DATA
;
203 RINOK(Lzma2Dec_AllocateProbs(&state
, props
[0], allocMain
));
204 state
.decoder
.dic
= outBuffer
;
205 state
.decoder
.dicBufSize
= outSize
;
206 Lzma2Dec_Init(&state
);
210 const void *inBuf
= NULL
;
211 size_t lookahead
= (1 << 18);
212 if (lookahead
> inSize
)
213 lookahead
= (size_t)inSize
;
214 res
= ILookInStream_Look(inStream
, &inBuf
, &lookahead
);
219 SizeT inProcessed
= (SizeT
)lookahead
, dicPos
= state
.decoder
.dicPos
;
221 res
= Lzma2Dec_DecodeToDic(&state
, outSize
, (const Byte
*)inBuf
, &inProcessed
, LZMA_FINISH_END
, &status
);
222 lookahead
-= inProcessed
;
223 inSize
-= inProcessed
;
227 if (status
== LZMA_STATUS_FINISHED_WITH_MARK
)
229 if (outSize
!= state
.decoder
.dicPos
|| inSize
!= 0)
234 if (inProcessed
== 0 && dicPos
== state
.decoder
.dicPos
)
240 res
= ILookInStream_Skip(inStream
, inProcessed
);
246 Lzma2Dec_FreeProbs(&state
, allocMain
);
253 static SRes
SzDecodeCopy(UInt64 inSize
, ILookInStream
*inStream
, Byte
*outBuffer
)
258 size_t curSize
= (1 << 18);
259 if (curSize
> inSize
)
260 curSize
= (size_t)inSize
;
261 RINOK(ILookInStream_Look(inStream
, &inBuf
, &curSize
));
263 return SZ_ERROR_INPUT_EOF
;
264 memcpy(outBuffer
, inBuf
, curSize
);
265 outBuffer
+= curSize
;
267 RINOK(ILookInStream_Skip(inStream
, curSize
));
272 static BoolInt
IS_MAIN_METHOD(UInt32 m
)
278 #ifndef _7Z_NO_METHOD_LZMA2
281 #ifdef _7ZIP_PPMD_SUPPPORT
289 static BoolInt
IS_SUPPORTED_CODER(const CSzCoderInfo
*c
)
293 /* && c->MethodID <= (UInt32)0xFFFFFFFF */
294 && IS_MAIN_METHOD((UInt32
)c
->MethodID
);
297 #define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4)
299 static SRes
CheckSupportedFolder(const CSzFolder
*f
)
301 if (f
->NumCoders
< 1 || f
->NumCoders
> 4)
302 return SZ_ERROR_UNSUPPORTED
;
303 if (!IS_SUPPORTED_CODER(&f
->Coders
[0]))
304 return SZ_ERROR_UNSUPPORTED
;
305 if (f
->NumCoders
== 1)
307 if (f
->NumPackStreams
!= 1 || f
->PackStreams
[0] != 0 || f
->NumBonds
!= 0)
308 return SZ_ERROR_UNSUPPORTED
;
313 #ifndef _7Z_NO_METHODS_FILTERS
315 if (f
->NumCoders
== 2)
317 const CSzCoderInfo
*c
= &f
->Coders
[1];
319 /* c->MethodID > (UInt32)0xFFFFFFFF || */
321 || f
->NumPackStreams
!= 1
322 || f
->PackStreams
[0] != 0
324 || f
->Bonds
[0].InIndex
!= 1
325 || f
->Bonds
[0].OutIndex
!= 0)
326 return SZ_ERROR_UNSUPPORTED
;
327 switch ((UInt32
)c
->MethodID
)
338 return SZ_ERROR_UNSUPPORTED
;
346 if (f
->NumCoders
== 4)
348 if (!IS_SUPPORTED_CODER(&f
->Coders
[1])
349 || !IS_SUPPORTED_CODER(&f
->Coders
[2])
350 || !IS_BCJ2(&f
->Coders
[3]))
351 return SZ_ERROR_UNSUPPORTED
;
352 if (f
->NumPackStreams
!= 4
353 || f
->PackStreams
[0] != 2
354 || f
->PackStreams
[1] != 6
355 || f
->PackStreams
[2] != 1
356 || f
->PackStreams
[3] != 0
358 || f
->Bonds
[0].InIndex
!= 5 || f
->Bonds
[0].OutIndex
!= 0
359 || f
->Bonds
[1].InIndex
!= 4 || f
->Bonds
[1].OutIndex
!= 1
360 || f
->Bonds
[2].InIndex
!= 3 || f
->Bonds
[2].OutIndex
!= 2)
361 return SZ_ERROR_UNSUPPORTED
;
365 return SZ_ERROR_UNSUPPORTED
;
368 #define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
370 static SRes
SzFolder_Decode2(const CSzFolder
*folder
,
371 const Byte
*propsData
,
372 const UInt64
*unpackSizes
,
373 const UInt64
*packPositions
,
374 ILookInStream
*inStream
, UInt64 startPos
,
375 Byte
*outBuffer
, SizeT outSize
, ISzAllocPtr allocMain
,
379 SizeT tempSizes
[3] = { 0, 0, 0};
383 RINOK(CheckSupportedFolder(folder
));
385 for (ci
= 0; ci
< folder
->NumCoders
; ci
++)
387 const CSzCoderInfo
*coder
= &folder
->Coders
[ci
];
389 if (IS_MAIN_METHOD((UInt32
)coder
->MethodID
))
394 Byte
*outBufCur
= outBuffer
;
395 SizeT outSizeCur
= outSize
;
396 if (folder
->NumCoders
== 4)
398 UInt32 indices
[] = { 3, 2, 0 };
399 UInt64 unpackSize
= unpackSizes
[ci
];
404 outSizeCur
= (SizeT
)unpackSize
;
405 if (outSizeCur
!= unpackSize
)
407 temp
= (Byte
*)ISzAlloc_Alloc(allocMain
, outSizeCur
);
408 if (!temp
&& outSizeCur
!= 0)
410 outBufCur
= tempBuf
[1 - ci
] = temp
;
411 tempSizes
[1 - ci
] = outSizeCur
;
415 if (unpackSize
> outSize
) /* check it */
416 return SZ_ERROR_PARAM
;
417 tempBuf3
= outBufCur
= outBuffer
+ (outSize
- (size_t)unpackSize
);
418 tempSize3
= outSizeCur
= (SizeT
)unpackSize
;
421 return SZ_ERROR_UNSUPPORTED
;
423 offset
= packPositions
[si
];
424 inSize
= packPositions
[(size_t)si
+ 1] - offset
;
425 RINOK(LookInStream_SeekTo(inStream
, startPos
+ offset
));
427 if (coder
->MethodID
== k_Copy
)
429 if (inSize
!= outSizeCur
) /* check it */
430 return SZ_ERROR_DATA
;
431 RINOK(SzDecodeCopy(inSize
, inStream
, outBufCur
));
433 else if (coder
->MethodID
== k_LZMA
)
435 RINOK(SzDecodeLzma(propsData
+ coder
->PropsOffset
, coder
->PropsSize
, inSize
, inStream
, outBufCur
, outSizeCur
, allocMain
));
437 #ifndef _7Z_NO_METHOD_LZMA2
438 else if (coder
->MethodID
== k_LZMA2
)
440 RINOK(SzDecodeLzma2(propsData
+ coder
->PropsOffset
, coder
->PropsSize
, inSize
, inStream
, outBufCur
, outSizeCur
, allocMain
));
443 #ifdef _7ZIP_PPMD_SUPPPORT
444 else if (coder
->MethodID
== k_PPMD
)
446 RINOK(SzDecodePpmd(propsData
+ coder
->PropsOffset
, coder
->PropsSize
, inSize
, inStream
, outBufCur
, outSizeCur
, allocMain
));
450 return SZ_ERROR_UNSUPPORTED
;
452 else if (coder
->MethodID
== k_BCJ2
)
454 UInt64 offset
= packPositions
[1];
455 UInt64 s3Size
= packPositions
[2] - offset
;
458 return SZ_ERROR_UNSUPPORTED
;
460 tempSizes
[2] = (SizeT
)s3Size
;
461 if (tempSizes
[2] != s3Size
)
463 tempBuf
[2] = (Byte
*)ISzAlloc_Alloc(allocMain
, tempSizes
[2]);
464 if (!tempBuf
[2] && tempSizes
[2] != 0)
467 RINOK(LookInStream_SeekTo(inStream
, startPos
+ offset
));
468 RINOK(SzDecodeCopy(s3Size
, inStream
, tempBuf
[2]));
470 if ((tempSizes
[0] & 3) != 0 ||
471 (tempSizes
[1] & 3) != 0 ||
472 tempSize3
+ tempSizes
[0] + tempSizes
[1] != outSize
)
473 return SZ_ERROR_DATA
;
478 p
.bufs
[0] = tempBuf3
; p
.lims
[0] = tempBuf3
+ tempSize3
;
479 p
.bufs
[1] = tempBuf
[0]; p
.lims
[1] = tempBuf
[0] + tempSizes
[0];
480 p
.bufs
[2] = tempBuf
[1]; p
.lims
[2] = tempBuf
[1] + tempSizes
[1];
481 p
.bufs
[3] = tempBuf
[2]; p
.lims
[3] = tempBuf
[2] + tempSizes
[2];
484 p
.destLim
= outBuffer
+ outSize
;
487 RINOK(Bcj2Dec_Decode(&p
));
491 for (i
= 0; i
< 4; i
++)
492 if (p
.bufs
[i
] != p
.lims
[i
])
493 return SZ_ERROR_DATA
;
495 if (!Bcj2Dec_IsFinished(&p
))
496 return SZ_ERROR_DATA
;
498 if (p
.dest
!= p
.destLim
499 || p
.state
!= BCJ2_STREAM_MAIN
)
500 return SZ_ERROR_DATA
;
504 #ifndef _7Z_NO_METHODS_FILTERS
507 if (coder
->MethodID
== k_Delta
)
509 if (coder
->PropsSize
!= 1)
510 return SZ_ERROR_UNSUPPORTED
;
512 Byte state
[DELTA_STATE_SIZE
];
514 Delta_Decode(state
, (unsigned)(propsData
[coder
->PropsOffset
]) + 1, outBuffer
, outSize
);
519 if (coder
->PropsSize
!= 0)
520 return SZ_ERROR_UNSUPPORTED
;
521 switch (coder
->MethodID
)
526 x86_Convert_Init(state
);
527 x86_Convert(outBuffer
, outSize
, 0, &state
, 0);
536 return SZ_ERROR_UNSUPPORTED
;
542 return SZ_ERROR_UNSUPPORTED
;
549 SRes
SzAr_DecodeFolder(const CSzAr
*p
, UInt32 folderIndex
,
550 ILookInStream
*inStream
, UInt64 startPos
,
551 Byte
*outBuffer
, size_t outSize
,
552 ISzAllocPtr allocMain
)
558 const Byte
*data
= p
->CodersData
+ p
->FoCodersOffsets
[folderIndex
];
560 sd
.Size
= p
->FoCodersOffsets
[(size_t)folderIndex
+ 1] - p
->FoCodersOffsets
[folderIndex
];
562 res
= SzGetNextFolderItem(&folder
, &sd
);
568 || folder
.UnpackStream
!= p
->FoToMainUnpackSizeIndex
[folderIndex
]
569 || outSize
!= SzAr_GetFolderUnpackSize(p
, folderIndex
))
570 return SZ_ERROR_FAIL
;
573 Byte
*tempBuf
[3] = { 0, 0, 0};
575 res
= SzFolder_Decode2(&folder
, data
,
576 &p
->CoderUnpackSizes
[p
->FoToCoderUnpackSizes
[folderIndex
]],
577 p
->PackPositions
+ p
->FoStartPackStreamIndex
[folderIndex
],
579 outBuffer
, (SizeT
)outSize
, allocMain
, tempBuf
);
581 for (i
= 0; i
< 3; i
++)
582 ISzAlloc_Free(allocMain
, tempBuf
[i
]);
585 if (SzBitWithVals_Check(&p
->FolderCRCs
, folderIndex
))
586 if (CrcCalc(outBuffer
, outSize
) != p
->FolderCRCs
.Vals
[folderIndex
])