1 /* 7zDec.c -- Decoding from 7z folder
2 2010-11-02 : Igor Pavlov : Public domain */
6 /* #define _7ZIP_PPMD_SUPPPORT */
15 #ifdef _7ZIP_PPMD_SUPPPORT
21 #define k_LZMA 0x30101
22 #define k_BCJ 0x03030103
23 #define k_PPC 0x03030205
24 #define k_ARM 0x03030501
25 #define k_ARMT 0x03030701
26 #define k_SPARC 0x03030805
27 #define k_BCJ2 0x0303011B
29 #ifdef _7ZIP_PPMD_SUPPPORT
31 #define k_PPMD 0x30401
42 ILookInStream
*inStream
;
45 static Byte
ReadByte(void *pp
)
47 CByteInToLook
*p
= (CByteInToLook
*)pp
;
52 size_t size
= p
->cur
- p
->begin
;
54 p
->res
= p
->inStream
->Skip(p
->inStream
, size
);
56 p
->res
= p
->inStream
->Look(p
->inStream
, (const void **)&p
->begin
, &size
);
58 p
->end
= p
->begin
+ size
;
66 static SRes
SzDecodePpmd(CSzCoderInfo
*coder
, UInt64 inSize
, ILookInStream
*inStream
,
67 Byte
*outBuffer
, SizeT outSize
, ISzAlloc
*allocMain
)
74 s
.inStream
= inStream
;
75 s
.begin
= s
.end
= s
.cur
= NULL
;
80 if (coder
->Props
.size
!= 5)
81 return SZ_ERROR_UNSUPPORTED
;
84 unsigned order
= coder
->Props
.data
[0];
85 UInt32 memSize
= GetUi32(coder
->Props
.data
+ 1);
86 if (order
< PPMD7_MIN_ORDER
||
87 order
> PPMD7_MAX_ORDER
||
88 memSize
< PPMD7_MIN_MEM_SIZE
||
89 memSize
> PPMD7_MAX_MEM_SIZE
)
90 return SZ_ERROR_UNSUPPORTED
;
91 Ppmd7_Construct(&ppmd
);
92 if (!Ppmd7_Alloc(&ppmd
, memSize
, allocMain
))
94 Ppmd7_Init(&ppmd
, order
);
98 Ppmd7z_RangeDec_CreateVTable(&rc
);
100 if (!Ppmd7z_RangeDec_Init(&rc
))
103 res
= (s
.res
!= SZ_OK
? s
.res
: SZ_ERROR_DATA
);
107 for (i
= 0; i
< outSize
; i
++)
109 int sym
= Ppmd7_DecodeSymbol(&ppmd
, &rc
.p
);
110 if (s
.extra
|| sym
< 0)
112 outBuffer
[i
] = (Byte
)sym
;
115 res
= (s
.res
!= SZ_OK
? s
.res
: SZ_ERROR_DATA
);
116 else if (s
.processed
+ (s
.cur
- s
.begin
) != inSize
|| !Ppmd7z_RangeDec_IsFinishedOK(&rc
))
120 Ppmd7_Free(&ppmd
, allocMain
);
127 static SRes
SzDecodeLzma(CSzCoderInfo
*coder
, UInt64 inSize
, ILookInStream
*inStream
,
128 Byte
*outBuffer
, SizeT outSize
, ISzAlloc
*allocMain
)
133 LzmaDec_Construct(&state
);
134 RINOK(LzmaDec_AllocateProbs(&state
, coder
->Props
.data
, (unsigned)coder
->Props
.size
, allocMain
));
135 state
.dic
= outBuffer
;
136 state
.dicBufSize
= outSize
;
137 LzmaDec_Init(&state
);
142 size_t lookahead
= (1 << 18);
143 if (lookahead
> inSize
)
144 lookahead
= (size_t)inSize
;
145 res
= inStream
->Look((void *)inStream
, (const void **)&inBuf
, &lookahead
);
150 SizeT inProcessed
= (SizeT
)lookahead
, dicPos
= state
.dicPos
;
152 res
= LzmaDec_DecodeToDic(&state
, outSize
, inBuf
, &inProcessed
, LZMA_FINISH_END
, &status
);
153 lookahead
-= inProcessed
;
154 inSize
-= inProcessed
;
157 if (state
.dicPos
== state
.dicBufSize
|| (inProcessed
== 0 && dicPos
== state
.dicPos
))
159 if (state
.dicBufSize
!= outSize
|| lookahead
!= 0 ||
160 (status
!= LZMA_STATUS_FINISHED_WITH_MARK
&&
161 status
!= LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
))
165 res
= inStream
->Skip((void *)inStream
, inProcessed
);
171 LzmaDec_FreeProbs(&state
, allocMain
);
175 static SRes
SzDecodeLzma2(CSzCoderInfo
*coder
, UInt64 inSize
, ILookInStream
*inStream
,
176 Byte
*outBuffer
, SizeT outSize
, ISzAlloc
*allocMain
)
181 Lzma2Dec_Construct(&state
);
182 if (coder
->Props
.size
!= 1)
183 return SZ_ERROR_DATA
;
184 RINOK(Lzma2Dec_AllocateProbs(&state
, coder
->Props
.data
[0], allocMain
));
185 state
.decoder
.dic
= outBuffer
;
186 state
.decoder
.dicBufSize
= outSize
;
187 Lzma2Dec_Init(&state
);
192 size_t lookahead
= (1 << 18);
193 if (lookahead
> inSize
)
194 lookahead
= (size_t)inSize
;
195 res
= inStream
->Look((void *)inStream
, (const void **)&inBuf
, &lookahead
);
200 SizeT inProcessed
= (SizeT
)lookahead
, dicPos
= state
.decoder
.dicPos
;
202 res
= Lzma2Dec_DecodeToDic(&state
, outSize
, inBuf
, &inProcessed
, LZMA_FINISH_END
, &status
);
203 lookahead
-= inProcessed
;
204 inSize
-= inProcessed
;
207 if (state
.decoder
.dicPos
== state
.decoder
.dicBufSize
|| (inProcessed
== 0 && dicPos
== state
.decoder
.dicPos
))
209 if (state
.decoder
.dicBufSize
!= outSize
|| lookahead
!= 0 ||
210 (status
!= LZMA_STATUS_FINISHED_WITH_MARK
))
214 res
= inStream
->Skip((void *)inStream
, inProcessed
);
220 Lzma2Dec_FreeProbs(&state
, allocMain
);
224 static SRes
SzDecodeCopy(UInt64 inSize
, ILookInStream
*inStream
, Byte
*outBuffer
)
229 size_t curSize
= (1 << 18);
230 if (curSize
> inSize
)
231 curSize
= (size_t)inSize
;
232 RINOK(inStream
->Look((void *)inStream
, (const void **)&inBuf
, &curSize
));
234 return SZ_ERROR_INPUT_EOF
;
235 memcpy(outBuffer
, inBuf
, curSize
);
236 outBuffer
+= curSize
;
238 RINOK(inStream
->Skip((void *)inStream
, curSize
));
243 static Bool
IS_MAIN_METHOD(UInt32 m
)
250 #ifdef _7ZIP_PPMD_SUPPPORT
258 static Bool
IS_SUPPORTED_CODER(const CSzCoderInfo
*c
)
261 c
->NumInStreams
== 1 &&
262 c
->NumOutStreams
== 1 &&
263 c
->MethodID
<= (UInt32
)0xFFFFFFFF &&
264 IS_MAIN_METHOD((UInt32
)c
->MethodID
);
267 #define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
269 static SRes
CheckSupportedFolder(const CSzFolder
*f
)
271 if (f
->NumCoders
< 1 || f
->NumCoders
> 4)
272 return SZ_ERROR_UNSUPPORTED
;
273 if (!IS_SUPPORTED_CODER(&f
->Coders
[0]))
274 return SZ_ERROR_UNSUPPORTED
;
275 if (f
->NumCoders
== 1)
277 if (f
->NumPackStreams
!= 1 || f
->PackStreams
[0] != 0 || f
->NumBindPairs
!= 0)
278 return SZ_ERROR_UNSUPPORTED
;
281 if (f
->NumCoders
== 2)
283 CSzCoderInfo
*c
= &f
->Coders
[1];
284 if (c
->MethodID
> (UInt32
)0xFFFFFFFF ||
285 c
->NumInStreams
!= 1 ||
286 c
->NumOutStreams
!= 1 ||
287 f
->NumPackStreams
!= 1 ||
288 f
->PackStreams
[0] != 0 ||
289 f
->NumBindPairs
!= 1 ||
290 f
->BindPairs
[0].InIndex
!= 1 ||
291 f
->BindPairs
[0].OutIndex
!= 0)
292 return SZ_ERROR_UNSUPPORTED
;
293 switch ((UInt32
)c
->MethodID
)
299 return SZ_ERROR_UNSUPPORTED
;
303 if (f
->NumCoders
== 4)
305 if (!IS_SUPPORTED_CODER(&f
->Coders
[1]) ||
306 !IS_SUPPORTED_CODER(&f
->Coders
[2]) ||
307 !IS_BCJ2(&f
->Coders
[3]))
308 return SZ_ERROR_UNSUPPORTED
;
309 if (f
->NumPackStreams
!= 4 ||
310 f
->PackStreams
[0] != 2 ||
311 f
->PackStreams
[1] != 6 ||
312 f
->PackStreams
[2] != 1 ||
313 f
->PackStreams
[3] != 0 ||
314 f
->NumBindPairs
!= 3 ||
315 f
->BindPairs
[0].InIndex
!= 5 || f
->BindPairs
[0].OutIndex
!= 0 ||
316 f
->BindPairs
[1].InIndex
!= 4 || f
->BindPairs
[1].OutIndex
!= 1 ||
317 f
->BindPairs
[2].InIndex
!= 3 || f
->BindPairs
[2].OutIndex
!= 2)
318 return SZ_ERROR_UNSUPPORTED
;
321 return SZ_ERROR_UNSUPPORTED
;
324 static UInt64
GetSum(const UInt64
*values
, UInt32 index
)
328 for (i
= 0; i
< index
; i
++)
333 #define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
335 static SRes
SzFolder_Decode2(const CSzFolder
*folder
, const UInt64
*packSizes
,
336 ILookInStream
*inStream
, UInt64 startPos
,
337 Byte
*outBuffer
, SizeT outSize
, ISzAlloc
*allocMain
,
341 SizeT tempSizes
[3] = { 0, 0, 0};
345 RINOK(CheckSupportedFolder(folder
));
347 for (ci
= 0; ci
< folder
->NumCoders
; ci
++)
349 CSzCoderInfo
*coder
= &folder
->Coders
[ci
];
351 if (IS_MAIN_METHOD((UInt32
)coder
->MethodID
))
356 Byte
*outBufCur
= outBuffer
;
357 SizeT outSizeCur
= outSize
;
358 if (folder
->NumCoders
== 4)
360 UInt32 indices
[] = { 3, 2, 0 };
361 UInt64 unpackSize
= folder
->UnpackSizes
[ci
];
366 outSizeCur
= (SizeT
)unpackSize
;
367 if (outSizeCur
!= unpackSize
)
369 temp
= (Byte
*)IAlloc_Alloc(allocMain
, outSizeCur
);
370 if (temp
== 0 && outSizeCur
!= 0)
372 outBufCur
= tempBuf
[1 - ci
] = temp
;
373 tempSizes
[1 - ci
] = outSizeCur
;
377 if (unpackSize
> outSize
) /* check it */
378 return SZ_ERROR_PARAM
;
379 tempBuf3
= outBufCur
= outBuffer
+ (outSize
- (size_t)unpackSize
);
380 tempSize3
= outSizeCur
= (SizeT
)unpackSize
;
383 return SZ_ERROR_UNSUPPORTED
;
385 offset
= GetSum(packSizes
, si
);
386 inSize
= packSizes
[si
];
387 RINOK(LookInStream_SeekTo(inStream
, startPos
+ offset
));
389 if (coder
->MethodID
== k_Copy
)
391 if (inSize
!= outSizeCur
) /* check it */
392 return SZ_ERROR_DATA
;
393 RINOK(SzDecodeCopy(inSize
, inStream
, outBufCur
));
395 else if (coder
->MethodID
== k_LZMA
)
397 RINOK(SzDecodeLzma(coder
, inSize
, inStream
, outBufCur
, outSizeCur
, allocMain
));
399 else if (coder
->MethodID
== k_LZMA2
)
401 RINOK(SzDecodeLzma2(coder
, inSize
, inStream
, outBufCur
, outSizeCur
, allocMain
));
405 #ifdef _7ZIP_PPMD_SUPPPORT
406 RINOK(SzDecodePpmd(coder
, inSize
, inStream
, outBufCur
, outSizeCur
, allocMain
));
408 return SZ_ERROR_UNSUPPORTED
;
412 else if (coder
->MethodID
== k_BCJ2
)
414 UInt64 offset
= GetSum(packSizes
, 1);
415 UInt64 s3Size
= packSizes
[1];
418 return SZ_ERROR_UNSUPPORTED
;
419 RINOK(LookInStream_SeekTo(inStream
, startPos
+ offset
));
420 tempSizes
[2] = (SizeT
)s3Size
;
421 if (tempSizes
[2] != s3Size
)
423 tempBuf
[2] = (Byte
*)IAlloc_Alloc(allocMain
, tempSizes
[2]);
424 if (tempBuf
[2] == 0 && tempSizes
[2] != 0)
426 res
= SzDecodeCopy(s3Size
, inStream
, tempBuf
[2]);
431 tempBuf
[0], tempSizes
[0],
432 tempBuf
[1], tempSizes
[1],
433 tempBuf
[2], tempSizes
[2],
440 return SZ_ERROR_UNSUPPORTED
;
441 switch(coder
->MethodID
)
446 x86_Convert_Init(state
);
447 x86_Convert(outBuffer
, outSize
, 0, &state
, 0);
452 return SZ_ERROR_UNSUPPORTED
;
459 SRes
SzFolder_Decode(const CSzFolder
*folder
, const UInt64
*packSizes
,
460 ILookInStream
*inStream
, UInt64 startPos
,
461 Byte
*outBuffer
, size_t outSize
, ISzAlloc
*allocMain
)
463 Byte
*tempBuf
[3] = { 0, 0, 0};
465 SRes res
= SzFolder_Decode2(folder
, packSizes
, inStream
, startPos
,
466 outBuffer
, (SizeT
)outSize
, allocMain
, tempBuf
);
467 for (i
= 0; i
< 3; i
++)
468 IAlloc_Free(allocMain
, tempBuf
[i
]);