| OLD | NEW |
| (Empty) |
| 1 /* 7zDecode.c -- Decoding from 7z folder | |
| 2 2008-11-23 : Igor Pavlov : Public domain */ | |
| 3 | |
| 4 #include <string.h> | |
| 5 | |
| 6 #include "../../Bcj2.h" | |
| 7 #include "../../Bra.h" | |
| 8 #include "../../LzmaDec.h" | |
| 9 #include "7zDecode.h" | |
| 10 | |
| 11 #define k_Copy 0 | |
| 12 #define k_LZMA 0x30101 | |
| 13 #define k_BCJ 0x03030103 | |
| 14 #define k_BCJ2 0x0303011B | |
| 15 | |
| 16 static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inSt
ream, | |
| 17 Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) | |
| 18 { | |
| 19 CLzmaDec state; | |
| 20 SRes res = SZ_OK; | |
| 21 | |
| 22 LzmaDec_Construct(&state); | |
| 23 RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.
size, allocMain)); | |
| 24 state.dic = outBuffer; | |
| 25 state.dicBufSize = outSize; | |
| 26 LzmaDec_Init(&state); | |
| 27 | |
| 28 for (;;) | |
| 29 { | |
| 30 Byte *inBuf = NULL; | |
| 31 size_t lookahead = (1 << 18); | |
| 32 if (lookahead > inSize) | |
| 33 lookahead = (size_t)inSize; | |
| 34 res = inStream->Look((void *)inStream, (void **)&inBuf, &lookahead); | |
| 35 if (res != SZ_OK) | |
| 36 break; | |
| 37 | |
| 38 { | |
| 39 SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos; | |
| 40 ELzmaStatus status; | |
| 41 res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINIS
H_END, &status); | |
| 42 lookahead -= inProcessed; | |
| 43 inSize -= inProcessed; | |
| 44 if (res != SZ_OK) | |
| 45 break; | |
| 46 if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == sta
te.dicPos)) | |
| 47 { | |
| 48 if (state.dicBufSize != outSize || lookahead != 0 || | |
| 49 (status != LZMA_STATUS_FINISHED_WITH_MARK && | |
| 50 status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)) | |
| 51 res = SZ_ERROR_DATA; | |
| 52 break; | |
| 53 } | |
| 54 res = inStream->Skip((void *)inStream, inProcessed); | |
| 55 if (res != SZ_OK) | |
| 56 break; | |
| 57 } | |
| 58 } | |
| 59 | |
| 60 LzmaDec_FreeProbs(&state, allocMain); | |
| 61 return res; | |
| 62 } | |
| 63 | |
| 64 static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer
) | |
| 65 { | |
| 66 while (inSize > 0) | |
| 67 { | |
| 68 void *inBuf; | |
| 69 size_t curSize = (1 << 18); | |
| 70 if (curSize > inSize) | |
| 71 curSize = (size_t)inSize; | |
| 72 RINOK(inStream->Look((void *)inStream, (void **)&inBuf, &curSize)); | |
| 73 if (curSize == 0) | |
| 74 return SZ_ERROR_INPUT_EOF; | |
| 75 memcpy(outBuffer, inBuf, curSize); | |
| 76 outBuffer += curSize; | |
| 77 inSize -= curSize; | |
| 78 RINOK(inStream->Skip((void *)inStream, curSize)); | |
| 79 } | |
| 80 return SZ_OK; | |
| 81 } | |
| 82 | |
| 83 #define IS_UNSUPPORTED_METHOD(m) ((m) != k_Copy && (m) != k_LZMA) | |
| 84 #define IS_UNSUPPORTED_CODER(c) (IS_UNSUPPORTED_METHOD(c.MethodID) || c.NumInStr
eams != 1 || c.NumOutStreams != 1) | |
| 85 #define IS_NO_BCJ(c) (c.MethodID != k_BCJ || c.NumInStreams != 1 || c.NumOutStre
ams != 1) | |
| 86 #define IS_NO_BCJ2(c) (c.MethodID != k_BCJ2 || c.NumInStreams != 4 || c.NumOutSt
reams != 1) | |
| 87 | |
| 88 SRes CheckSupportedFolder(const CSzFolder *f) | |
| 89 { | |
| 90 if (f->NumCoders < 1 || f->NumCoders > 4) | |
| 91 return SZ_ERROR_UNSUPPORTED; | |
| 92 if (IS_UNSUPPORTED_CODER(f->Coders[0])) | |
| 93 return SZ_ERROR_UNSUPPORTED; | |
| 94 if (f->NumCoders == 1) | |
| 95 { | |
| 96 if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0
) | |
| 97 return SZ_ERROR_UNSUPPORTED; | |
| 98 return SZ_OK; | |
| 99 } | |
| 100 if (f->NumCoders == 2) | |
| 101 { | |
| 102 if (IS_NO_BCJ(f->Coders[1]) || | |
| 103 f->NumPackStreams != 1 || f->PackStreams[0] != 0 || | |
| 104 f->NumBindPairs != 1 || | |
| 105 f->BindPairs[0].InIndex != 1 || f->BindPairs[0].OutIndex != 0) | |
| 106 return SZ_ERROR_UNSUPPORTED; | |
| 107 return SZ_OK; | |
| 108 } | |
| 109 if (f->NumCoders == 4) | |
| 110 { | |
| 111 if (IS_UNSUPPORTED_CODER(f->Coders[1]) || | |
| 112 IS_UNSUPPORTED_CODER(f->Coders[2]) || | |
| 113 IS_NO_BCJ2(f->Coders[3])) | |
| 114 return SZ_ERROR_UNSUPPORTED; | |
| 115 if (f->NumPackStreams != 4 || | |
| 116 f->PackStreams[0] != 2 || | |
| 117 f->PackStreams[1] != 6 || | |
| 118 f->PackStreams[2] != 1 || | |
| 119 f->PackStreams[3] != 0 || | |
| 120 f->NumBindPairs != 3 || | |
| 121 f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 || | |
| 122 f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 || | |
| 123 f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2) | |
| 124 return SZ_ERROR_UNSUPPORTED; | |
| 125 return SZ_OK; | |
| 126 } | |
| 127 return SZ_ERROR_UNSUPPORTED; | |
| 128 } | |
| 129 | |
| 130 UInt64 GetSum(const UInt64 *values, UInt32 index) | |
| 131 { | |
| 132 UInt64 sum = 0; | |
| 133 UInt32 i; | |
| 134 for (i = 0; i < index; i++) | |
| 135 sum += values[i]; | |
| 136 return sum; | |
| 137 } | |
| 138 | |
| 139 SRes SzDecode2(const UInt64 *packSizes, const CSzFolder *folder, | |
| 140 ILookInStream *inStream, UInt64 startPos, | |
| 141 Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain, | |
| 142 Byte *tempBuf[]) | |
| 143 { | |
| 144 UInt32 ci; | |
| 145 SizeT tempSizes[3] = { 0, 0, 0}; | |
| 146 SizeT tempSize3 = 0; | |
| 147 Byte *tempBuf3 = 0; | |
| 148 | |
| 149 RINOK(CheckSupportedFolder(folder)); | |
| 150 | |
| 151 for (ci = 0; ci < folder->NumCoders; ci++) | |
| 152 { | |
| 153 CSzCoderInfo *coder = &folder->Coders[ci]; | |
| 154 | |
| 155 if (coder->MethodID == k_Copy || coder->MethodID == k_LZMA) | |
| 156 { | |
| 157 UInt32 si = 0; | |
| 158 UInt64 offset; | |
| 159 UInt64 inSize; | |
| 160 Byte *outBufCur = outBuffer; | |
| 161 SizeT outSizeCur = outSize; | |
| 162 if (folder->NumCoders == 4) | |
| 163 { | |
| 164 UInt32 indices[] = { 3, 2, 0 }; | |
| 165 UInt64 unpackSize = folder->UnpackSizes[ci]; | |
| 166 si = indices[ci]; | |
| 167 if (ci < 2) | |
| 168 { | |
| 169 Byte *temp; | |
| 170 outSizeCur = (SizeT)unpackSize; | |
| 171 if (outSizeCur != unpackSize) | |
| 172 return SZ_ERROR_MEM; | |
| 173 temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur); | |
| 174 if (temp == 0 && outSizeCur != 0) | |
| 175 return SZ_ERROR_MEM; | |
| 176 outBufCur = tempBuf[1 - ci] = temp; | |
| 177 tempSizes[1 - ci] = outSizeCur; | |
| 178 } | |
| 179 else if (ci == 2) | |
| 180 { | |
| 181 if (unpackSize > outSize) /* check it */ | |
| 182 return SZ_ERROR_PARAM; | |
| 183 tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); | |
| 184 tempSize3 = outSizeCur = (SizeT)unpackSize; | |
| 185 } | |
| 186 else | |
| 187 return SZ_ERROR_UNSUPPORTED; | |
| 188 } | |
| 189 offset = GetSum(packSizes, si); | |
| 190 inSize = packSizes[si]; | |
| 191 RINOK(LookInStream_SeekTo(inStream, startPos + offset)); | |
| 192 | |
| 193 if (coder->MethodID == k_Copy) | |
| 194 { | |
| 195 if (inSize != outSizeCur) /* check it */ | |
| 196 return SZ_ERROR_DATA; | |
| 197 RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); | |
| 198 } | |
| 199 else | |
| 200 { | |
| 201 RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, alloc
Main)); | |
| 202 } | |
| 203 } | |
| 204 else if (coder->MethodID == k_BCJ) | |
| 205 { | |
| 206 UInt32 state; | |
| 207 if (ci != 1) | |
| 208 return SZ_ERROR_UNSUPPORTED; | |
| 209 x86_Convert_Init(state); | |
| 210 x86_Convert(outBuffer, outSize, 0, &state, 0); | |
| 211 } | |
| 212 else if (coder->MethodID == k_BCJ2) | |
| 213 { | |
| 214 UInt64 offset = GetSum(packSizes, 1); | |
| 215 UInt64 s3Size = packSizes[1]; | |
| 216 SRes res; | |
| 217 if (ci != 3) | |
| 218 return SZ_ERROR_UNSUPPORTED; | |
| 219 RINOK(LookInStream_SeekTo(inStream, startPos + offset)); | |
| 220 tempSizes[2] = (SizeT)s3Size; | |
| 221 if (tempSizes[2] != s3Size) | |
| 222 return SZ_ERROR_MEM; | |
| 223 tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]); | |
| 224 if (tempBuf[2] == 0 && tempSizes[2] != 0) | |
| 225 return SZ_ERROR_MEM; | |
| 226 res = SzDecodeCopy(s3Size, inStream, tempBuf[2]); | |
| 227 RINOK(res) | |
| 228 | |
| 229 res = Bcj2_Decode( | |
| 230 tempBuf3, tempSize3, | |
| 231 tempBuf[0], tempSizes[0], | |
| 232 tempBuf[1], tempSizes[1], | |
| 233 tempBuf[2], tempSizes[2], | |
| 234 outBuffer, outSize); | |
| 235 RINOK(res) | |
| 236 } | |
| 237 else | |
| 238 return SZ_ERROR_UNSUPPORTED; | |
| 239 } | |
| 240 return SZ_OK; | |
| 241 } | |
| 242 | |
| 243 SRes SzDecode(const UInt64 *packSizes, const CSzFolder *folder, | |
| 244 ILookInStream *inStream, UInt64 startPos, | |
| 245 Byte *outBuffer, size_t outSize, ISzAlloc *allocMain) | |
| 246 { | |
| 247 Byte *tempBuf[3] = { 0, 0, 0}; | |
| 248 int i; | |
| 249 SRes res = SzDecode2(packSizes, folder, inStream, startPos, | |
| 250 outBuffer, (SizeT)outSize, allocMain, tempBuf); | |
| 251 for (i = 0; i < 3; i++) | |
| 252 IAlloc_Free(allocMain, tempBuf[i]); | |
| 253 return res; | |
| 254 } | |
| OLD | NEW |