| 1 | /* 7zArcIn.c -- 7z Input functions\r |
| 2 | 2016-05-16 : Igor Pavlov : Public domain */\r |
| 3 | \r |
| 4 | #include "Precomp.h"\r |
| 5 | \r |
| 6 | #include <string.h>\r |
| 7 | \r |
| 8 | #include "7z.h"\r |
| 9 | #include "7zBuf.h"\r |
| 10 | #include "7zCrc.h"\r |
| 11 | #include "CpuArch.h"\r |
| 12 | \r |
| 13 | #define MY_ALLOC(T, p, size, alloc) { \\r |
| 14 | if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; }\r |
| 15 | \r |
| 16 | #define MY_ALLOC_ZE(T, p, size, alloc) { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) }\r |
| 17 | \r |
| 18 | #define MY_ALLOC_AND_CPY(to, size, from, alloc) \\r |
| 19 | { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); }\r |
| 20 | \r |
| 21 | #define MY_ALLOC_ZE_AND_CPY(to, size, from, alloc) \\r |
| 22 | { if ((size) == 0) p = NULL; else { MY_ALLOC_AND_CPY(to, size, from, alloc) } }\r |
| 23 | \r |
| 24 | #define k7zMajorVersion 0\r |
| 25 | \r |
| 26 | enum EIdEnum\r |
| 27 | {\r |
| 28 | k7zIdEnd,\r |
| 29 | k7zIdHeader,\r |
| 30 | k7zIdArchiveProperties,\r |
| 31 | k7zIdAdditionalStreamsInfo,\r |
| 32 | k7zIdMainStreamsInfo,\r |
| 33 | k7zIdFilesInfo,\r |
| 34 | k7zIdPackInfo,\r |
| 35 | k7zIdUnpackInfo,\r |
| 36 | k7zIdSubStreamsInfo,\r |
| 37 | k7zIdSize,\r |
| 38 | k7zIdCRC,\r |
| 39 | k7zIdFolder,\r |
| 40 | k7zIdCodersUnpackSize,\r |
| 41 | k7zIdNumUnpackStream,\r |
| 42 | k7zIdEmptyStream,\r |
| 43 | k7zIdEmptyFile,\r |
| 44 | k7zIdAnti,\r |
| 45 | k7zIdName,\r |
| 46 | k7zIdCTime,\r |
| 47 | k7zIdATime,\r |
| 48 | k7zIdMTime,\r |
| 49 | k7zIdWinAttrib,\r |
| 50 | k7zIdComment,\r |
| 51 | k7zIdEncodedHeader,\r |
| 52 | k7zIdStartPos,\r |
| 53 | k7zIdDummy\r |
| 54 | // k7zNtSecure,\r |
| 55 | // k7zParent,\r |
| 56 | // k7zIsReal\r |
| 57 | };\r |
| 58 | \r |
| 59 | const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};\r |
| 60 | \r |
| 61 | #define SzBitUi32s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; }\r |
| 62 | \r |
| 63 | static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAlloc *alloc)\r |
| 64 | {\r |
| 65 | if (num == 0)\r |
| 66 | {\r |
| 67 | p->Defs = NULL;\r |
| 68 | p->Vals = NULL;\r |
| 69 | }\r |
| 70 | else\r |
| 71 | {\r |
| 72 | MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc);\r |
| 73 | MY_ALLOC(UInt32, p->Vals, num, alloc);\r |
| 74 | }\r |
| 75 | return SZ_OK;\r |
| 76 | }\r |
| 77 | \r |
| 78 | void SzBitUi32s_Free(CSzBitUi32s *p, ISzAlloc *alloc)\r |
| 79 | {\r |
| 80 | IAlloc_Free(alloc, p->Defs); p->Defs = NULL;\r |
| 81 | IAlloc_Free(alloc, p->Vals); p->Vals = NULL;\r |
| 82 | }\r |
| 83 | \r |
| 84 | #define SzBitUi64s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; }\r |
| 85 | \r |
| 86 | void SzBitUi64s_Free(CSzBitUi64s *p, ISzAlloc *alloc)\r |
| 87 | {\r |
| 88 | IAlloc_Free(alloc, p->Defs); p->Defs = NULL;\r |
| 89 | IAlloc_Free(alloc, p->Vals); p->Vals = NULL;\r |
| 90 | }\r |
| 91 | \r |
| 92 | \r |
| 93 | static void SzAr_Init(CSzAr *p)\r |
| 94 | {\r |
| 95 | p->NumPackStreams = 0;\r |
| 96 | p->NumFolders = 0;\r |
| 97 | \r |
| 98 | p->PackPositions = NULL;\r |
| 99 | SzBitUi32s_Init(&p->FolderCRCs);\r |
| 100 | \r |
| 101 | p->FoCodersOffsets = NULL;\r |
| 102 | p->FoStartPackStreamIndex = NULL;\r |
| 103 | p->FoToCoderUnpackSizes = NULL;\r |
| 104 | p->FoToMainUnpackSizeIndex = NULL;\r |
| 105 | p->CoderUnpackSizes = NULL;\r |
| 106 | \r |
| 107 | p->CodersData = NULL;\r |
| 108 | }\r |
| 109 | \r |
| 110 | static void SzAr_Free(CSzAr *p, ISzAlloc *alloc)\r |
| 111 | {\r |
| 112 | IAlloc_Free(alloc, p->PackPositions);\r |
| 113 | SzBitUi32s_Free(&p->FolderCRCs, alloc);\r |
| 114 | \r |
| 115 | IAlloc_Free(alloc, p->FoCodersOffsets);\r |
| 116 | IAlloc_Free(alloc, p->FoStartPackStreamIndex);\r |
| 117 | IAlloc_Free(alloc, p->FoToCoderUnpackSizes);\r |
| 118 | IAlloc_Free(alloc, p->FoToMainUnpackSizeIndex);\r |
| 119 | IAlloc_Free(alloc, p->CoderUnpackSizes);\r |
| 120 | \r |
| 121 | IAlloc_Free(alloc, p->CodersData);\r |
| 122 | \r |
| 123 | SzAr_Init(p);\r |
| 124 | }\r |
| 125 | \r |
| 126 | \r |
| 127 | void SzArEx_Init(CSzArEx *p)\r |
| 128 | {\r |
| 129 | SzAr_Init(&p->db);\r |
| 130 | \r |
| 131 | p->NumFiles = 0;\r |
| 132 | p->dataPos = 0;\r |
| 133 | \r |
| 134 | p->UnpackPositions = NULL;\r |
| 135 | p->IsDirs = NULL;\r |
| 136 | \r |
| 137 | p->FolderToFile = NULL;\r |
| 138 | p->FileToFolder = NULL;\r |
| 139 | \r |
| 140 | p->FileNameOffsets = NULL;\r |
| 141 | p->FileNames = NULL;\r |
| 142 | \r |
| 143 | SzBitUi32s_Init(&p->CRCs);\r |
| 144 | SzBitUi32s_Init(&p->Attribs);\r |
| 145 | // SzBitUi32s_Init(&p->Parents);\r |
| 146 | SzBitUi64s_Init(&p->MTime);\r |
| 147 | SzBitUi64s_Init(&p->CTime);\r |
| 148 | }\r |
| 149 | \r |
| 150 | void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc)\r |
| 151 | {\r |
| 152 | IAlloc_Free(alloc, p->UnpackPositions);\r |
| 153 | IAlloc_Free(alloc, p->IsDirs);\r |
| 154 | \r |
| 155 | IAlloc_Free(alloc, p->FolderToFile);\r |
| 156 | IAlloc_Free(alloc, p->FileToFolder);\r |
| 157 | \r |
| 158 | IAlloc_Free(alloc, p->FileNameOffsets);\r |
| 159 | IAlloc_Free(alloc, p->FileNames);\r |
| 160 | \r |
| 161 | SzBitUi32s_Free(&p->CRCs, alloc);\r |
| 162 | SzBitUi32s_Free(&p->Attribs, alloc);\r |
| 163 | // SzBitUi32s_Free(&p->Parents, alloc);\r |
| 164 | SzBitUi64s_Free(&p->MTime, alloc);\r |
| 165 | SzBitUi64s_Free(&p->CTime, alloc);\r |
| 166 | \r |
| 167 | SzAr_Free(&p->db, alloc);\r |
| 168 | SzArEx_Init(p);\r |
| 169 | }\r |
| 170 | \r |
| 171 | \r |
| 172 | static int TestSignatureCandidate(const Byte *testBytes)\r |
| 173 | {\r |
| 174 | unsigned i;\r |
| 175 | for (i = 0; i < k7zSignatureSize; i++)\r |
| 176 | if (testBytes[i] != k7zSignature[i])\r |
| 177 | return 0;\r |
| 178 | return 1;\r |
| 179 | }\r |
| 180 | \r |
| 181 | #define SzData_Clear(p) { (p)->Data = NULL; (p)->Size = 0; }\r |
| 182 | \r |
| 183 | #define SZ_READ_BYTE_SD(_sd_, dest) if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; (_sd_)->Size--; dest = *(_sd_)->Data++;\r |
| 184 | #define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest)\r |
| 185 | #define SZ_READ_BYTE_2(dest) if (sd.Size == 0) return SZ_ERROR_ARCHIVE; sd.Size--; dest = *sd.Data++;\r |
| 186 | \r |
| 187 | #define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); }\r |
| 188 | #define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); }\r |
| 189 | \r |
| 190 | #define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \\r |
| 191 | dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4);\r |
| 192 | \r |
| 193 | static MY_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value)\r |
| 194 | {\r |
| 195 | Byte firstByte, mask;\r |
| 196 | unsigned i;\r |
| 197 | UInt32 v;\r |
| 198 | \r |
| 199 | SZ_READ_BYTE(firstByte);\r |
| 200 | if ((firstByte & 0x80) == 0)\r |
| 201 | {\r |
| 202 | *value = firstByte;\r |
| 203 | return SZ_OK;\r |
| 204 | }\r |
| 205 | SZ_READ_BYTE(v);\r |
| 206 | if ((firstByte & 0x40) == 0)\r |
| 207 | {\r |
| 208 | *value = (((UInt32)firstByte & 0x3F) << 8) | v;\r |
| 209 | return SZ_OK;\r |
| 210 | }\r |
| 211 | SZ_READ_BYTE(mask);\r |
| 212 | *value = v | ((UInt32)mask << 8);\r |
| 213 | mask = 0x20;\r |
| 214 | for (i = 2; i < 8; i++)\r |
| 215 | {\r |
| 216 | Byte b;\r |
| 217 | if ((firstByte & mask) == 0)\r |
| 218 | {\r |
| 219 | UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1);\r |
| 220 | *value |= (highPart << (8 * i));\r |
| 221 | return SZ_OK;\r |
| 222 | }\r |
| 223 | SZ_READ_BYTE(b);\r |
| 224 | *value |= ((UInt64)b << (8 * i));\r |
| 225 | mask >>= 1;\r |
| 226 | }\r |
| 227 | return SZ_OK;\r |
| 228 | }\r |
| 229 | \r |
| 230 | \r |
| 231 | static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value)\r |
| 232 | {\r |
| 233 | Byte firstByte;\r |
| 234 | UInt64 value64;\r |
| 235 | if (sd->Size == 0)\r |
| 236 | return SZ_ERROR_ARCHIVE;\r |
| 237 | firstByte = *sd->Data;\r |
| 238 | if ((firstByte & 0x80) == 0)\r |
| 239 | {\r |
| 240 | *value = firstByte;\r |
| 241 | sd->Data++;\r |
| 242 | sd->Size--;\r |
| 243 | return SZ_OK;\r |
| 244 | }\r |
| 245 | RINOK(ReadNumber(sd, &value64));\r |
| 246 | if (value64 >= (UInt32)0x80000000 - 1)\r |
| 247 | return SZ_ERROR_UNSUPPORTED;\r |
| 248 | if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4)))\r |
| 249 | return SZ_ERROR_UNSUPPORTED;\r |
| 250 | *value = (UInt32)value64;\r |
| 251 | return SZ_OK;\r |
| 252 | }\r |
| 253 | \r |
| 254 | #define ReadID(sd, value) ReadNumber(sd, value)\r |
| 255 | \r |
| 256 | static SRes SkipData(CSzData *sd)\r |
| 257 | {\r |
| 258 | UInt64 size;\r |
| 259 | RINOK(ReadNumber(sd, &size));\r |
| 260 | if (size > sd->Size)\r |
| 261 | return SZ_ERROR_ARCHIVE;\r |
| 262 | SKIP_DATA(sd, size);\r |
| 263 | return SZ_OK;\r |
| 264 | }\r |
| 265 | \r |
| 266 | static SRes WaitId(CSzData *sd, UInt32 id)\r |
| 267 | {\r |
| 268 | for (;;)\r |
| 269 | {\r |
| 270 | UInt64 type;\r |
| 271 | RINOK(ReadID(sd, &type));\r |
| 272 | if (type == id)\r |
| 273 | return SZ_OK;\r |
| 274 | if (type == k7zIdEnd)\r |
| 275 | return SZ_ERROR_ARCHIVE;\r |
| 276 | RINOK(SkipData(sd));\r |
| 277 | }\r |
| 278 | }\r |
| 279 | \r |
| 280 | static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v)\r |
| 281 | {\r |
| 282 | UInt32 numBytes = (numItems + 7) >> 3;\r |
| 283 | if (numBytes > sd->Size)\r |
| 284 | return SZ_ERROR_ARCHIVE;\r |
| 285 | *v = sd->Data;\r |
| 286 | SKIP_DATA(sd, numBytes);\r |
| 287 | return SZ_OK;\r |
| 288 | }\r |
| 289 | \r |
| 290 | static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems)\r |
| 291 | {\r |
| 292 | Byte b = 0;\r |
| 293 | unsigned m = 0;\r |
| 294 | UInt32 sum = 0;\r |
| 295 | for (; numItems != 0; numItems--)\r |
| 296 | {\r |
| 297 | if (m == 0)\r |
| 298 | {\r |
| 299 | b = *bits++;\r |
| 300 | m = 8;\r |
| 301 | }\r |
| 302 | m--;\r |
| 303 | sum += ((b >> m) & 1);\r |
| 304 | }\r |
| 305 | return sum;\r |
| 306 | }\r |
| 307 | \r |
| 308 | static MY_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAlloc *alloc)\r |
| 309 | {\r |
| 310 | Byte allAreDefined;\r |
| 311 | Byte *v2;\r |
| 312 | UInt32 numBytes = (numItems + 7) >> 3;\r |
| 313 | *v = NULL;\r |
| 314 | SZ_READ_BYTE(allAreDefined);\r |
| 315 | if (numBytes == 0)\r |
| 316 | return SZ_OK;\r |
| 317 | if (allAreDefined == 0)\r |
| 318 | {\r |
| 319 | if (numBytes > sd->Size)\r |
| 320 | return SZ_ERROR_ARCHIVE;\r |
| 321 | MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc);\r |
| 322 | SKIP_DATA(sd, numBytes);\r |
| 323 | return SZ_OK;\r |
| 324 | }\r |
| 325 | MY_ALLOC(Byte, *v, numBytes, alloc);\r |
| 326 | v2 = *v;\r |
| 327 | memset(v2, 0xFF, (size_t)numBytes);\r |
| 328 | {\r |
| 329 | unsigned numBits = (unsigned)numItems & 7;\r |
| 330 | if (numBits != 0)\r |
| 331 | v2[numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits));\r |
| 332 | }\r |
| 333 | return SZ_OK;\r |
| 334 | }\r |
| 335 | \r |
| 336 | static MY_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc)\r |
| 337 | {\r |
| 338 | UInt32 i;\r |
| 339 | CSzData sd;\r |
| 340 | UInt32 *vals;\r |
| 341 | const Byte *defs;\r |
| 342 | MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc);\r |
| 343 | sd = *sd2;\r |
| 344 | defs = crcs->Defs;\r |
| 345 | vals = crcs->Vals;\r |
| 346 | for (i = 0; i < numItems; i++)\r |
| 347 | if (SzBitArray_Check(defs, i))\r |
| 348 | {\r |
| 349 | SZ_READ_32(vals[i]);\r |
| 350 | }\r |
| 351 | else\r |
| 352 | vals[i] = 0;\r |
| 353 | *sd2 = sd;\r |
| 354 | return SZ_OK;\r |
| 355 | }\r |
| 356 | \r |
| 357 | static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc)\r |
| 358 | {\r |
| 359 | SzBitUi32s_Free(crcs, alloc);\r |
| 360 | RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc));\r |
| 361 | return ReadUi32s(sd, numItems, crcs, alloc);\r |
| 362 | }\r |
| 363 | \r |
| 364 | static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems)\r |
| 365 | {\r |
| 366 | Byte allAreDefined;\r |
| 367 | UInt32 numDefined = numItems;\r |
| 368 | SZ_READ_BYTE(allAreDefined);\r |
| 369 | if (!allAreDefined)\r |
| 370 | {\r |
| 371 | size_t numBytes = (numItems + 7) >> 3;\r |
| 372 | if (numBytes > sd->Size)\r |
| 373 | return SZ_ERROR_ARCHIVE;\r |
| 374 | numDefined = CountDefinedBits(sd->Data, numItems);\r |
| 375 | SKIP_DATA(sd, numBytes);\r |
| 376 | }\r |
| 377 | if (numDefined > (sd->Size >> 2))\r |
| 378 | return SZ_ERROR_ARCHIVE;\r |
| 379 | SKIP_DATA(sd, (size_t)numDefined * 4);\r |
| 380 | return SZ_OK;\r |
| 381 | }\r |
| 382 | \r |
| 383 | static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAlloc *alloc)\r |
| 384 | {\r |
| 385 | RINOK(SzReadNumber32(sd, &p->NumPackStreams));\r |
| 386 | \r |
| 387 | RINOK(WaitId(sd, k7zIdSize));\r |
| 388 | MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc);\r |
| 389 | {\r |
| 390 | UInt64 sum = 0;\r |
| 391 | UInt32 i;\r |
| 392 | UInt32 numPackStreams = p->NumPackStreams;\r |
| 393 | for (i = 0; i < numPackStreams; i++)\r |
| 394 | {\r |
| 395 | UInt64 packSize;\r |
| 396 | p->PackPositions[i] = sum;\r |
| 397 | RINOK(ReadNumber(sd, &packSize));\r |
| 398 | sum += packSize;\r |
| 399 | if (sum < packSize)\r |
| 400 | return SZ_ERROR_ARCHIVE;\r |
| 401 | }\r |
| 402 | p->PackPositions[i] = sum;\r |
| 403 | }\r |
| 404 | \r |
| 405 | for (;;)\r |
| 406 | {\r |
| 407 | UInt64 type;\r |
| 408 | RINOK(ReadID(sd, &type));\r |
| 409 | if (type == k7zIdEnd)\r |
| 410 | return SZ_OK;\r |
| 411 | if (type == k7zIdCRC)\r |
| 412 | {\r |
| 413 | /* CRC of packed streams is unused now */\r |
| 414 | RINOK(SkipBitUi32s(sd, p->NumPackStreams));\r |
| 415 | continue;\r |
| 416 | }\r |
| 417 | RINOK(SkipData(sd));\r |
| 418 | }\r |
| 419 | }\r |
| 420 | \r |
| 421 | /*\r |
| 422 | static SRes SzReadSwitch(CSzData *sd)\r |
| 423 | {\r |
| 424 | Byte external;\r |
| 425 | RINOK(SzReadByte(sd, &external));\r |
| 426 | return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED;\r |
| 427 | }\r |
| 428 | */\r |
| 429 | \r |
| 430 | #define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX)\r |
| 431 | \r |
| 432 | SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd)\r |
| 433 | {\r |
| 434 | UInt32 numCoders, i;\r |
| 435 | UInt32 numInStreams = 0;\r |
| 436 | const Byte *dataStart = sd->Data;\r |
| 437 | \r |
| 438 | f->NumCoders = 0;\r |
| 439 | f->NumBonds = 0;\r |
| 440 | f->NumPackStreams = 0;\r |
| 441 | f->UnpackStream = 0;\r |
| 442 | \r |
| 443 | RINOK(SzReadNumber32(sd, &numCoders));\r |
| 444 | if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX)\r |
| 445 | return SZ_ERROR_UNSUPPORTED;\r |
| 446 | \r |
| 447 | for (i = 0; i < numCoders; i++)\r |
| 448 | {\r |
| 449 | Byte mainByte;\r |
| 450 | CSzCoderInfo *coder = f->Coders + i;\r |
| 451 | unsigned idSize, j;\r |
| 452 | UInt64 id;\r |
| 453 | \r |
| 454 | SZ_READ_BYTE(mainByte);\r |
| 455 | if ((mainByte & 0xC0) != 0)\r |
| 456 | return SZ_ERROR_UNSUPPORTED;\r |
| 457 | \r |
| 458 | idSize = (unsigned)(mainByte & 0xF);\r |
| 459 | if (idSize > sizeof(id))\r |
| 460 | return SZ_ERROR_UNSUPPORTED;\r |
| 461 | if (idSize > sd->Size)\r |
| 462 | return SZ_ERROR_ARCHIVE;\r |
| 463 | id = 0;\r |
| 464 | for (j = 0; j < idSize; j++)\r |
| 465 | {\r |
| 466 | id = ((id << 8) | *sd->Data);\r |
| 467 | sd->Data++;\r |
| 468 | sd->Size--;\r |
| 469 | }\r |
| 470 | if (id > (UInt32)0xFFFFFFFF)\r |
| 471 | return SZ_ERROR_UNSUPPORTED;\r |
| 472 | coder->MethodID = (UInt32)id;\r |
| 473 | \r |
| 474 | coder->NumStreams = 1;\r |
| 475 | coder->PropsOffset = 0;\r |
| 476 | coder->PropsSize = 0;\r |
| 477 | \r |
| 478 | if ((mainByte & 0x10) != 0)\r |
| 479 | {\r |
| 480 | UInt32 numStreams;\r |
| 481 | \r |
| 482 | RINOK(SzReadNumber32(sd, &numStreams));\r |
| 483 | if (numStreams > k_NumCodersStreams_in_Folder_MAX)\r |
| 484 | return SZ_ERROR_UNSUPPORTED;\r |
| 485 | coder->NumStreams = (Byte)numStreams;\r |
| 486 | \r |
| 487 | RINOK(SzReadNumber32(sd, &numStreams));\r |
| 488 | if (numStreams != 1)\r |
| 489 | return SZ_ERROR_UNSUPPORTED;\r |
| 490 | }\r |
| 491 | \r |
| 492 | numInStreams += coder->NumStreams;\r |
| 493 | \r |
| 494 | if (numInStreams > k_NumCodersStreams_in_Folder_MAX)\r |
| 495 | return SZ_ERROR_UNSUPPORTED;\r |
| 496 | \r |
| 497 | if ((mainByte & 0x20) != 0)\r |
| 498 | {\r |
| 499 | UInt32 propsSize = 0;\r |
| 500 | RINOK(SzReadNumber32(sd, &propsSize));\r |
| 501 | if (propsSize > sd->Size)\r |
| 502 | return SZ_ERROR_ARCHIVE;\r |
| 503 | if (propsSize >= 0x80)\r |
| 504 | return SZ_ERROR_UNSUPPORTED;\r |
| 505 | coder->PropsOffset = sd->Data - dataStart;\r |
| 506 | coder->PropsSize = (Byte)propsSize;\r |
| 507 | sd->Data += (size_t)propsSize;\r |
| 508 | sd->Size -= (size_t)propsSize;\r |
| 509 | }\r |
| 510 | }\r |
| 511 | \r |
| 512 | /*\r |
| 513 | if (numInStreams == 1 && numCoders == 1)\r |
| 514 | {\r |
| 515 | f->NumPackStreams = 1;\r |
| 516 | f->PackStreams[0] = 0;\r |
| 517 | }\r |
| 518 | else\r |
| 519 | */\r |
| 520 | {\r |
| 521 | Byte streamUsed[k_NumCodersStreams_in_Folder_MAX];\r |
| 522 | UInt32 numBonds, numPackStreams;\r |
| 523 | \r |
| 524 | numBonds = numCoders - 1;\r |
| 525 | if (numInStreams < numBonds)\r |
| 526 | return SZ_ERROR_ARCHIVE;\r |
| 527 | if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX)\r |
| 528 | return SZ_ERROR_UNSUPPORTED;\r |
| 529 | f->NumBonds = numBonds;\r |
| 530 | \r |
| 531 | numPackStreams = numInStreams - numBonds;\r |
| 532 | if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX)\r |
| 533 | return SZ_ERROR_UNSUPPORTED;\r |
| 534 | f->NumPackStreams = numPackStreams;\r |
| 535 | \r |
| 536 | for (i = 0; i < numInStreams; i++)\r |
| 537 | streamUsed[i] = False;\r |
| 538 | \r |
| 539 | if (numBonds != 0)\r |
| 540 | {\r |
| 541 | Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX];\r |
| 542 | \r |
| 543 | for (i = 0; i < numCoders; i++)\r |
| 544 | coderUsed[i] = False;\r |
| 545 | \r |
| 546 | for (i = 0; i < numBonds; i++)\r |
| 547 | {\r |
| 548 | CSzBond *bp = f->Bonds + i;\r |
| 549 | \r |
| 550 | RINOK(SzReadNumber32(sd, &bp->InIndex));\r |
| 551 | if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex])\r |
| 552 | return SZ_ERROR_ARCHIVE;\r |
| 553 | streamUsed[bp->InIndex] = True;\r |
| 554 | \r |
| 555 | RINOK(SzReadNumber32(sd, &bp->OutIndex));\r |
| 556 | if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex])\r |
| 557 | return SZ_ERROR_ARCHIVE;\r |
| 558 | coderUsed[bp->OutIndex] = True;\r |
| 559 | }\r |
| 560 | \r |
| 561 | for (i = 0; i < numCoders; i++)\r |
| 562 | if (!coderUsed[i])\r |
| 563 | {\r |
| 564 | f->UnpackStream = i;\r |
| 565 | break;\r |
| 566 | }\r |
| 567 | \r |
| 568 | if (i == numCoders)\r |
| 569 | return SZ_ERROR_ARCHIVE;\r |
| 570 | }\r |
| 571 | \r |
| 572 | if (numPackStreams == 1)\r |
| 573 | {\r |
| 574 | for (i = 0; i < numInStreams; i++)\r |
| 575 | if (!streamUsed[i])\r |
| 576 | break;\r |
| 577 | if (i == numInStreams)\r |
| 578 | return SZ_ERROR_ARCHIVE;\r |
| 579 | f->PackStreams[0] = i;\r |
| 580 | }\r |
| 581 | else\r |
| 582 | for (i = 0; i < numPackStreams; i++)\r |
| 583 | {\r |
| 584 | UInt32 index;\r |
| 585 | RINOK(SzReadNumber32(sd, &index));\r |
| 586 | if (index >= numInStreams || streamUsed[index])\r |
| 587 | return SZ_ERROR_ARCHIVE;\r |
| 588 | streamUsed[index] = True;\r |
| 589 | f->PackStreams[i] = index;\r |
| 590 | }\r |
| 591 | }\r |
| 592 | \r |
| 593 | f->NumCoders = numCoders;\r |
| 594 | \r |
| 595 | return SZ_OK;\r |
| 596 | }\r |
| 597 | \r |
| 598 | \r |
| 599 | static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num)\r |
| 600 | {\r |
| 601 | CSzData sd;\r |
| 602 | sd = *sd2;\r |
| 603 | for (; num != 0; num--)\r |
| 604 | {\r |
| 605 | Byte firstByte, mask;\r |
| 606 | unsigned i;\r |
| 607 | SZ_READ_BYTE_2(firstByte);\r |
| 608 | if ((firstByte & 0x80) == 0)\r |
| 609 | continue;\r |
| 610 | if ((firstByte & 0x40) == 0)\r |
| 611 | {\r |
| 612 | if (sd.Size == 0)\r |
| 613 | return SZ_ERROR_ARCHIVE;\r |
| 614 | sd.Size--;\r |
| 615 | sd.Data++;\r |
| 616 | continue;\r |
| 617 | }\r |
| 618 | mask = 0x20;\r |
| 619 | for (i = 2; i < 8 && (firstByte & mask) != 0; i++)\r |
| 620 | mask >>= 1;\r |
| 621 | if (i > sd.Size)\r |
| 622 | return SZ_ERROR_ARCHIVE;\r |
| 623 | SKIP_DATA2(sd, i);\r |
| 624 | }\r |
| 625 | *sd2 = sd;\r |
| 626 | return SZ_OK;\r |
| 627 | }\r |
| 628 | \r |
| 629 | \r |
| 630 | #define k_Scan_NumCoders_MAX 64\r |
| 631 | #define k_Scan_NumCodersStreams_in_Folder_MAX 64\r |
| 632 | \r |
| 633 | \r |
| 634 | static SRes ReadUnpackInfo(CSzAr *p,\r |
| 635 | CSzData *sd2,\r |
| 636 | UInt32 numFoldersMax,\r |
| 637 | const CBuf *tempBufs, UInt32 numTempBufs,\r |
| 638 | ISzAlloc *alloc)\r |
| 639 | {\r |
| 640 | CSzData sd;\r |
| 641 | \r |
| 642 | UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex;\r |
| 643 | const Byte *startBufPtr;\r |
| 644 | Byte external;\r |
| 645 | \r |
| 646 | RINOK(WaitId(sd2, k7zIdFolder));\r |
| 647 | \r |
| 648 | RINOK(SzReadNumber32(sd2, &numFolders));\r |
| 649 | if (numFolders > numFoldersMax)\r |
| 650 | return SZ_ERROR_UNSUPPORTED;\r |
| 651 | p->NumFolders = numFolders;\r |
| 652 | \r |
| 653 | SZ_READ_BYTE_SD(sd2, external);\r |
| 654 | if (external == 0)\r |
| 655 | sd = *sd2;\r |
| 656 | else\r |
| 657 | {\r |
| 658 | UInt32 index;\r |
| 659 | RINOK(SzReadNumber32(sd2, &index));\r |
| 660 | if (index >= numTempBufs)\r |
| 661 | return SZ_ERROR_ARCHIVE;\r |
| 662 | sd.Data = tempBufs[index].data;\r |
| 663 | sd.Size = tempBufs[index].size;\r |
| 664 | }\r |
| 665 | \r |
| 666 | MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc);\r |
| 667 | MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc);\r |
| 668 | MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc);\r |
| 669 | MY_ALLOC(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc);\r |
| 670 | \r |
| 671 | startBufPtr = sd.Data;\r |
| 672 | \r |
| 673 | packStreamIndex = 0;\r |
| 674 | numCodersOutStreams = 0;\r |
| 675 | \r |
| 676 | for (fo = 0; fo < numFolders; fo++)\r |
| 677 | {\r |
| 678 | UInt32 numCoders, ci, numInStreams = 0;\r |
| 679 | \r |
| 680 | p->FoCodersOffsets[fo] = sd.Data - startBufPtr;\r |
| 681 | \r |
| 682 | RINOK(SzReadNumber32(&sd, &numCoders));\r |
| 683 | if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX)\r |
| 684 | return SZ_ERROR_UNSUPPORTED;\r |
| 685 | \r |
| 686 | for (ci = 0; ci < numCoders; ci++)\r |
| 687 | {\r |
| 688 | Byte mainByte;\r |
| 689 | unsigned idSize;\r |
| 690 | UInt32 coderInStreams;\r |
| 691 | \r |
| 692 | SZ_READ_BYTE_2(mainByte);\r |
| 693 | if ((mainByte & 0xC0) != 0)\r |
| 694 | return SZ_ERROR_UNSUPPORTED;\r |
| 695 | idSize = (mainByte & 0xF);\r |
| 696 | if (idSize > 8)\r |
| 697 | return SZ_ERROR_UNSUPPORTED;\r |
| 698 | if (idSize > sd.Size)\r |
| 699 | return SZ_ERROR_ARCHIVE;\r |
| 700 | SKIP_DATA2(sd, idSize);\r |
| 701 | \r |
| 702 | coderInStreams = 1;\r |
| 703 | \r |
| 704 | if ((mainByte & 0x10) != 0)\r |
| 705 | {\r |
| 706 | UInt32 coderOutStreams;\r |
| 707 | RINOK(SzReadNumber32(&sd, &coderInStreams));\r |
| 708 | RINOK(SzReadNumber32(&sd, &coderOutStreams));\r |
| 709 | if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1)\r |
| 710 | return SZ_ERROR_UNSUPPORTED;\r |
| 711 | }\r |
| 712 | \r |
| 713 | numInStreams += coderInStreams;\r |
| 714 | \r |
| 715 | if ((mainByte & 0x20) != 0)\r |
| 716 | {\r |
| 717 | UInt32 propsSize;\r |
| 718 | RINOK(SzReadNumber32(&sd, &propsSize));\r |
| 719 | if (propsSize > sd.Size)\r |
| 720 | return SZ_ERROR_ARCHIVE;\r |
| 721 | SKIP_DATA2(sd, propsSize);\r |
| 722 | }\r |
| 723 | }\r |
| 724 | \r |
| 725 | {\r |
| 726 | UInt32 indexOfMainStream = 0;\r |
| 727 | UInt32 numPackStreams = 1;\r |
| 728 | \r |
| 729 | if (numCoders != 1 || numInStreams != 1)\r |
| 730 | {\r |
| 731 | Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX];\r |
| 732 | Byte coderUsed[k_Scan_NumCoders_MAX];\r |
| 733 | \r |
| 734 | UInt32 i;\r |
| 735 | UInt32 numBonds = numCoders - 1;\r |
| 736 | if (numInStreams < numBonds)\r |
| 737 | return SZ_ERROR_ARCHIVE;\r |
| 738 | \r |
| 739 | if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX)\r |
| 740 | return SZ_ERROR_UNSUPPORTED;\r |
| 741 | \r |
| 742 | for (i = 0; i < numInStreams; i++)\r |
| 743 | streamUsed[i] = False;\r |
| 744 | for (i = 0; i < numCoders; i++)\r |
| 745 | coderUsed[i] = False;\r |
| 746 | \r |
| 747 | for (i = 0; i < numBonds; i++)\r |
| 748 | {\r |
| 749 | UInt32 index;\r |
| 750 | \r |
| 751 | RINOK(SzReadNumber32(&sd, &index));\r |
| 752 | if (index >= numInStreams || streamUsed[index])\r |
| 753 | return SZ_ERROR_ARCHIVE;\r |
| 754 | streamUsed[index] = True;\r |
| 755 | \r |
| 756 | RINOK(SzReadNumber32(&sd, &index));\r |
| 757 | if (index >= numCoders || coderUsed[index])\r |
| 758 | return SZ_ERROR_ARCHIVE;\r |
| 759 | coderUsed[index] = True;\r |
| 760 | }\r |
| 761 | \r |
| 762 | numPackStreams = numInStreams - numBonds;\r |
| 763 | \r |
| 764 | if (numPackStreams != 1)\r |
| 765 | for (i = 0; i < numPackStreams; i++)\r |
| 766 | {\r |
| 767 | UInt32 index;\r |
| 768 | RINOK(SzReadNumber32(&sd, &index));\r |
| 769 | if (index >= numInStreams || streamUsed[index])\r |
| 770 | return SZ_ERROR_ARCHIVE;\r |
| 771 | streamUsed[index] = True;\r |
| 772 | }\r |
| 773 | \r |
| 774 | for (i = 0; i < numCoders; i++)\r |
| 775 | if (!coderUsed[i])\r |
| 776 | {\r |
| 777 | indexOfMainStream = i;\r |
| 778 | break;\r |
| 779 | }\r |
| 780 | \r |
| 781 | if (i == numCoders)\r |
| 782 | return SZ_ERROR_ARCHIVE;\r |
| 783 | }\r |
| 784 | \r |
| 785 | p->FoStartPackStreamIndex[fo] = packStreamIndex;\r |
| 786 | p->FoToCoderUnpackSizes[fo] = numCodersOutStreams;\r |
| 787 | p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream;\r |
| 788 | numCodersOutStreams += numCoders;\r |
| 789 | if (numCodersOutStreams < numCoders)\r |
| 790 | return SZ_ERROR_UNSUPPORTED;\r |
| 791 | if (numPackStreams > p->NumPackStreams - packStreamIndex)\r |
| 792 | return SZ_ERROR_ARCHIVE;\r |
| 793 | packStreamIndex += numPackStreams;\r |
| 794 | }\r |
| 795 | }\r |
| 796 | \r |
| 797 | p->FoToCoderUnpackSizes[fo] = numCodersOutStreams;\r |
| 798 | \r |
| 799 | {\r |
| 800 | size_t dataSize = sd.Data - startBufPtr;\r |
| 801 | p->FoStartPackStreamIndex[fo] = packStreamIndex;\r |
| 802 | p->FoCodersOffsets[fo] = dataSize;\r |
| 803 | MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc);\r |
| 804 | }\r |
| 805 | \r |
| 806 | if (external != 0)\r |
| 807 | {\r |
| 808 | if (sd.Size != 0)\r |
| 809 | return SZ_ERROR_ARCHIVE;\r |
| 810 | sd = *sd2;\r |
| 811 | }\r |
| 812 | \r |
| 813 | RINOK(WaitId(&sd, k7zIdCodersUnpackSize));\r |
| 814 | \r |
| 815 | MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc);\r |
| 816 | {\r |
| 817 | UInt32 i;\r |
| 818 | for (i = 0; i < numCodersOutStreams; i++)\r |
| 819 | {\r |
| 820 | RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i));\r |
| 821 | }\r |
| 822 | }\r |
| 823 | \r |
| 824 | for (;;)\r |
| 825 | {\r |
| 826 | UInt64 type;\r |
| 827 | RINOK(ReadID(&sd, &type));\r |
| 828 | if (type == k7zIdEnd)\r |
| 829 | {\r |
| 830 | *sd2 = sd;\r |
| 831 | return SZ_OK;\r |
| 832 | }\r |
| 833 | if (type == k7zIdCRC)\r |
| 834 | {\r |
| 835 | RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc));\r |
| 836 | continue;\r |
| 837 | }\r |
| 838 | RINOK(SkipData(&sd));\r |
| 839 | }\r |
| 840 | }\r |
| 841 | \r |
| 842 | \r |
| 843 | UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex)\r |
| 844 | {\r |
| 845 | return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]];\r |
| 846 | }\r |
| 847 | \r |
| 848 | \r |
| 849 | typedef struct\r |
| 850 | {\r |
| 851 | UInt32 NumTotalSubStreams;\r |
| 852 | UInt32 NumSubDigests;\r |
| 853 | CSzData sdNumSubStreams;\r |
| 854 | CSzData sdSizes;\r |
| 855 | CSzData sdCRCs;\r |
| 856 | } CSubStreamInfo;\r |
| 857 | \r |
| 858 | \r |
| 859 | static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi)\r |
| 860 | {\r |
| 861 | UInt64 type = 0;\r |
| 862 | UInt32 numSubDigests = 0;\r |
| 863 | UInt32 numFolders = p->NumFolders;\r |
| 864 | UInt32 numUnpackStreams = numFolders;\r |
| 865 | UInt32 numUnpackSizesInData = 0;\r |
| 866 | \r |
| 867 | for (;;)\r |
| 868 | {\r |
| 869 | RINOK(ReadID(sd, &type));\r |
| 870 | if (type == k7zIdNumUnpackStream)\r |
| 871 | {\r |
| 872 | UInt32 i;\r |
| 873 | ssi->sdNumSubStreams.Data = sd->Data;\r |
| 874 | numUnpackStreams = 0;\r |
| 875 | numSubDigests = 0;\r |
| 876 | for (i = 0; i < numFolders; i++)\r |
| 877 | {\r |
| 878 | UInt32 numStreams;\r |
| 879 | RINOK(SzReadNumber32(sd, &numStreams));\r |
| 880 | if (numUnpackStreams > numUnpackStreams + numStreams)\r |
| 881 | return SZ_ERROR_UNSUPPORTED;\r |
| 882 | numUnpackStreams += numStreams;\r |
| 883 | if (numStreams != 0)\r |
| 884 | numUnpackSizesInData += (numStreams - 1);\r |
| 885 | if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i))\r |
| 886 | numSubDigests += numStreams;\r |
| 887 | }\r |
| 888 | ssi->sdNumSubStreams.Size = sd->Data - ssi->sdNumSubStreams.Data;\r |
| 889 | continue;\r |
| 890 | }\r |
| 891 | if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd)\r |
| 892 | break;\r |
| 893 | RINOK(SkipData(sd));\r |
| 894 | }\r |
| 895 | \r |
| 896 | if (!ssi->sdNumSubStreams.Data)\r |
| 897 | {\r |
| 898 | numSubDigests = numFolders;\r |
| 899 | if (p->FolderCRCs.Defs)\r |
| 900 | numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders);\r |
| 901 | }\r |
| 902 | \r |
| 903 | ssi->NumTotalSubStreams = numUnpackStreams;\r |
| 904 | ssi->NumSubDigests = numSubDigests;\r |
| 905 | \r |
| 906 | if (type == k7zIdSize)\r |
| 907 | {\r |
| 908 | ssi->sdSizes.Data = sd->Data;\r |
| 909 | RINOK(SkipNumbers(sd, numUnpackSizesInData));\r |
| 910 | ssi->sdSizes.Size = sd->Data - ssi->sdSizes.Data;\r |
| 911 | RINOK(ReadID(sd, &type));\r |
| 912 | }\r |
| 913 | \r |
| 914 | for (;;)\r |
| 915 | {\r |
| 916 | if (type == k7zIdEnd)\r |
| 917 | return SZ_OK;\r |
| 918 | if (type == k7zIdCRC)\r |
| 919 | {\r |
| 920 | ssi->sdCRCs.Data = sd->Data;\r |
| 921 | RINOK(SkipBitUi32s(sd, numSubDigests));\r |
| 922 | ssi->sdCRCs.Size = sd->Data - ssi->sdCRCs.Data;\r |
| 923 | }\r |
| 924 | else\r |
| 925 | {\r |
| 926 | RINOK(SkipData(sd));\r |
| 927 | }\r |
| 928 | RINOK(ReadID(sd, &type));\r |
| 929 | }\r |
| 930 | }\r |
| 931 | \r |
| 932 | static SRes SzReadStreamsInfo(CSzAr *p,\r |
| 933 | CSzData *sd,\r |
| 934 | UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs,\r |
| 935 | UInt64 *dataOffset,\r |
| 936 | CSubStreamInfo *ssi,\r |
| 937 | ISzAlloc *alloc)\r |
| 938 | {\r |
| 939 | UInt64 type;\r |
| 940 | \r |
| 941 | SzData_Clear(&ssi->sdSizes);\r |
| 942 | SzData_Clear(&ssi->sdCRCs);\r |
| 943 | SzData_Clear(&ssi->sdNumSubStreams);\r |
| 944 | \r |
| 945 | *dataOffset = 0;\r |
| 946 | RINOK(ReadID(sd, &type));\r |
| 947 | if (type == k7zIdPackInfo)\r |
| 948 | {\r |
| 949 | RINOK(ReadNumber(sd, dataOffset));\r |
| 950 | RINOK(ReadPackInfo(p, sd, alloc));\r |
| 951 | RINOK(ReadID(sd, &type));\r |
| 952 | }\r |
| 953 | if (type == k7zIdUnpackInfo)\r |
| 954 | {\r |
| 955 | RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc));\r |
| 956 | RINOK(ReadID(sd, &type));\r |
| 957 | }\r |
| 958 | if (type == k7zIdSubStreamsInfo)\r |
| 959 | {\r |
| 960 | RINOK(ReadSubStreamsInfo(p, sd, ssi));\r |
| 961 | RINOK(ReadID(sd, &type));\r |
| 962 | }\r |
| 963 | else\r |
| 964 | {\r |
| 965 | ssi->NumTotalSubStreams = p->NumFolders;\r |
| 966 | // ssi->NumSubDigests = 0;\r |
| 967 | }\r |
| 968 | \r |
| 969 | return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED);\r |
| 970 | }\r |
| 971 | \r |
| 972 | static SRes SzReadAndDecodePackedStreams(\r |
| 973 | ILookInStream *inStream,\r |
| 974 | CSzData *sd,\r |
| 975 | CBuf *tempBufs,\r |
| 976 | UInt32 numFoldersMax,\r |
| 977 | UInt64 baseOffset,\r |
| 978 | CSzAr *p,\r |
| 979 | ISzAlloc *allocTemp)\r |
| 980 | {\r |
| 981 | UInt64 dataStartPos;\r |
| 982 | UInt32 fo;\r |
| 983 | CSubStreamInfo ssi;\r |
| 984 | \r |
| 985 | RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp));\r |
| 986 | \r |
| 987 | dataStartPos += baseOffset;\r |
| 988 | if (p->NumFolders == 0)\r |
| 989 | return SZ_ERROR_ARCHIVE;\r |
| 990 | \r |
| 991 | for (fo = 0; fo < p->NumFolders; fo++)\r |
| 992 | Buf_Init(tempBufs + fo);\r |
| 993 | \r |
| 994 | for (fo = 0; fo < p->NumFolders; fo++)\r |
| 995 | {\r |
| 996 | CBuf *tempBuf = tempBufs + fo;\r |
| 997 | UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo);\r |
| 998 | if ((size_t)unpackSize != unpackSize)\r |
| 999 | return SZ_ERROR_MEM;\r |
| 1000 | if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp))\r |
| 1001 | return SZ_ERROR_MEM;\r |
| 1002 | }\r |
| 1003 | \r |
| 1004 | for (fo = 0; fo < p->NumFolders; fo++)\r |
| 1005 | {\r |
| 1006 | const CBuf *tempBuf = tempBufs + fo;\r |
| 1007 | RINOK(LookInStream_SeekTo(inStream, dataStartPos));\r |
| 1008 | RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp));\r |
| 1009 | }\r |
| 1010 | \r |
| 1011 | return SZ_OK;\r |
| 1012 | }\r |
| 1013 | \r |
| 1014 | static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets)\r |
| 1015 | {\r |
| 1016 | size_t pos = 0;\r |
| 1017 | *offsets++ = 0;\r |
| 1018 | if (numFiles == 0)\r |
| 1019 | return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE;\r |
| 1020 | if (size < 2)\r |
| 1021 | return SZ_ERROR_ARCHIVE;\r |
| 1022 | if (data[size - 2] != 0 || data[size - 1] != 0)\r |
| 1023 | return SZ_ERROR_ARCHIVE;\r |
| 1024 | do\r |
| 1025 | {\r |
| 1026 | const Byte *p;\r |
| 1027 | if (pos == size)\r |
| 1028 | return SZ_ERROR_ARCHIVE;\r |
| 1029 | for (p = data + pos;\r |
| 1030 | #ifdef _WIN32\r |
| 1031 | *(const UInt16 *)p != 0\r |
| 1032 | #else\r |
| 1033 | p[0] != 0 || p[1] != 0\r |
| 1034 | #endif\r |
| 1035 | ; p += 2);\r |
| 1036 | pos = p - data + 2;\r |
| 1037 | *offsets++ = (pos >> 1);\r |
| 1038 | }\r |
| 1039 | while (--numFiles);\r |
| 1040 | return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;\r |
| 1041 | }\r |
| 1042 | \r |
| 1043 | static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num,\r |
| 1044 | CSzData *sd2,\r |
| 1045 | const CBuf *tempBufs, UInt32 numTempBufs,\r |
| 1046 | ISzAlloc *alloc)\r |
| 1047 | {\r |
| 1048 | CSzData sd;\r |
| 1049 | UInt32 i;\r |
| 1050 | CNtfsFileTime *vals;\r |
| 1051 | Byte *defs;\r |
| 1052 | Byte external;\r |
| 1053 | \r |
| 1054 | RINOK(ReadBitVector(sd2, num, &p->Defs, alloc));\r |
| 1055 | \r |
| 1056 | SZ_READ_BYTE_SD(sd2, external);\r |
| 1057 | if (external == 0)\r |
| 1058 | sd = *sd2;\r |
| 1059 | else\r |
| 1060 | {\r |
| 1061 | UInt32 index;\r |
| 1062 | RINOK(SzReadNumber32(sd2, &index));\r |
| 1063 | if (index >= numTempBufs)\r |
| 1064 | return SZ_ERROR_ARCHIVE;\r |
| 1065 | sd.Data = tempBufs[index].data;\r |
| 1066 | sd.Size = tempBufs[index].size;\r |
| 1067 | }\r |
| 1068 | \r |
| 1069 | MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc);\r |
| 1070 | vals = p->Vals;\r |
| 1071 | defs = p->Defs;\r |
| 1072 | for (i = 0; i < num; i++)\r |
| 1073 | if (SzBitArray_Check(defs, i))\r |
| 1074 | {\r |
| 1075 | if (sd.Size < 8)\r |
| 1076 | return SZ_ERROR_ARCHIVE;\r |
| 1077 | vals[i].Low = GetUi32(sd.Data);\r |
| 1078 | vals[i].High = GetUi32(sd.Data + 4);\r |
| 1079 | SKIP_DATA2(sd, 8);\r |
| 1080 | }\r |
| 1081 | else\r |
| 1082 | vals[i].High = vals[i].Low = 0;\r |
| 1083 | \r |
| 1084 | if (external == 0)\r |
| 1085 | *sd2 = sd;\r |
| 1086 | \r |
| 1087 | return SZ_OK;\r |
| 1088 | }\r |
| 1089 | \r |
| 1090 | \r |
| 1091 | #define NUM_ADDITIONAL_STREAMS_MAX 8\r |
| 1092 | \r |
| 1093 | \r |
| 1094 | static SRes SzReadHeader2(\r |
| 1095 | CSzArEx *p, /* allocMain */\r |
| 1096 | CSzData *sd,\r |
| 1097 | ILookInStream *inStream,\r |
| 1098 | CBuf *tempBufs, UInt32 *numTempBufs,\r |
| 1099 | ISzAlloc *allocMain,\r |
| 1100 | ISzAlloc *allocTemp\r |
| 1101 | )\r |
| 1102 | {\r |
| 1103 | CSubStreamInfo ssi;\r |
| 1104 | \r |
| 1105 | {\r |
| 1106 | UInt64 type;\r |
| 1107 | \r |
| 1108 | SzData_Clear(&ssi.sdSizes);\r |
| 1109 | SzData_Clear(&ssi.sdCRCs);\r |
| 1110 | SzData_Clear(&ssi.sdNumSubStreams);\r |
| 1111 | \r |
| 1112 | ssi.NumSubDigests = 0;\r |
| 1113 | ssi.NumTotalSubStreams = 0;\r |
| 1114 | \r |
| 1115 | RINOK(ReadID(sd, &type));\r |
| 1116 | \r |
| 1117 | if (type == k7zIdArchiveProperties)\r |
| 1118 | {\r |
| 1119 | for (;;)\r |
| 1120 | {\r |
| 1121 | UInt64 type2;\r |
| 1122 | RINOK(ReadID(sd, &type2));\r |
| 1123 | if (type2 == k7zIdEnd)\r |
| 1124 | break;\r |
| 1125 | RINOK(SkipData(sd));\r |
| 1126 | }\r |
| 1127 | RINOK(ReadID(sd, &type));\r |
| 1128 | }\r |
| 1129 | \r |
| 1130 | if (type == k7zIdAdditionalStreamsInfo)\r |
| 1131 | {\r |
| 1132 | CSzAr tempAr;\r |
| 1133 | SRes res;\r |
| 1134 | \r |
| 1135 | SzAr_Init(&tempAr);\r |
| 1136 | res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX,\r |
| 1137 | p->startPosAfterHeader, &tempAr, allocTemp);\r |
| 1138 | *numTempBufs = tempAr.NumFolders;\r |
| 1139 | SzAr_Free(&tempAr, allocTemp);\r |
| 1140 | \r |
| 1141 | if (res != SZ_OK)\r |
| 1142 | return res;\r |
| 1143 | RINOK(ReadID(sd, &type));\r |
| 1144 | }\r |
| 1145 | \r |
| 1146 | if (type == k7zIdMainStreamsInfo)\r |
| 1147 | {\r |
| 1148 | RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs,\r |
| 1149 | &p->dataPos, &ssi, allocMain));\r |
| 1150 | p->dataPos += p->startPosAfterHeader;\r |
| 1151 | RINOK(ReadID(sd, &type));\r |
| 1152 | }\r |
| 1153 | \r |
| 1154 | if (type == k7zIdEnd)\r |
| 1155 | {\r |
| 1156 | return SZ_OK;\r |
| 1157 | }\r |
| 1158 | \r |
| 1159 | if (type != k7zIdFilesInfo)\r |
| 1160 | return SZ_ERROR_ARCHIVE;\r |
| 1161 | }\r |
| 1162 | \r |
| 1163 | {\r |
| 1164 | UInt32 numFiles = 0;\r |
| 1165 | UInt32 numEmptyStreams = 0;\r |
| 1166 | const Byte *emptyStreams = NULL;\r |
| 1167 | const Byte *emptyFiles = NULL;\r |
| 1168 | \r |
| 1169 | RINOK(SzReadNumber32(sd, &numFiles));\r |
| 1170 | p->NumFiles = numFiles;\r |
| 1171 | \r |
| 1172 | for (;;)\r |
| 1173 | {\r |
| 1174 | UInt64 type;\r |
| 1175 | UInt64 size;\r |
| 1176 | RINOK(ReadID(sd, &type));\r |
| 1177 | if (type == k7zIdEnd)\r |
| 1178 | break;\r |
| 1179 | RINOK(ReadNumber(sd, &size));\r |
| 1180 | if (size > sd->Size)\r |
| 1181 | return SZ_ERROR_ARCHIVE;\r |
| 1182 | \r |
| 1183 | if (type >= ((UInt32)1 << 8))\r |
| 1184 | {\r |
| 1185 | SKIP_DATA(sd, size);\r |
| 1186 | }\r |
| 1187 | else switch ((unsigned)type)\r |
| 1188 | {\r |
| 1189 | case k7zIdName:\r |
| 1190 | {\r |
| 1191 | size_t namesSize;\r |
| 1192 | const Byte *namesData;\r |
| 1193 | Byte external;\r |
| 1194 | \r |
| 1195 | SZ_READ_BYTE(external);\r |
| 1196 | if (external == 0)\r |
| 1197 | {\r |
| 1198 | namesSize = (size_t)size - 1;\r |
| 1199 | namesData = sd->Data;\r |
| 1200 | }\r |
| 1201 | else\r |
| 1202 | {\r |
| 1203 | UInt32 index;\r |
| 1204 | RINOK(SzReadNumber32(sd, &index));\r |
| 1205 | if (index >= *numTempBufs)\r |
| 1206 | return SZ_ERROR_ARCHIVE;\r |
| 1207 | namesData = (tempBufs)[index].data;\r |
| 1208 | namesSize = (tempBufs)[index].size;\r |
| 1209 | }\r |
| 1210 | \r |
| 1211 | if ((namesSize & 1) != 0)\r |
| 1212 | return SZ_ERROR_ARCHIVE;\r |
| 1213 | MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain);\r |
| 1214 | MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain);\r |
| 1215 | RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets))\r |
| 1216 | if (external == 0)\r |
| 1217 | {\r |
| 1218 | SKIP_DATA(sd, namesSize);\r |
| 1219 | }\r |
| 1220 | break;\r |
| 1221 | }\r |
| 1222 | case k7zIdEmptyStream:\r |
| 1223 | {\r |
| 1224 | RINOK(RememberBitVector(sd, numFiles, &emptyStreams));\r |
| 1225 | numEmptyStreams = CountDefinedBits(emptyStreams, numFiles);\r |
| 1226 | emptyFiles = NULL;\r |
| 1227 | break;\r |
| 1228 | }\r |
| 1229 | case k7zIdEmptyFile:\r |
| 1230 | {\r |
| 1231 | RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles));\r |
| 1232 | break;\r |
| 1233 | }\r |
| 1234 | case k7zIdWinAttrib:\r |
| 1235 | {\r |
| 1236 | Byte external;\r |
| 1237 | CSzData sdSwitch;\r |
| 1238 | CSzData *sdPtr;\r |
| 1239 | SzBitUi32s_Free(&p->Attribs, allocMain);\r |
| 1240 | RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain));\r |
| 1241 | \r |
| 1242 | SZ_READ_BYTE(external);\r |
| 1243 | if (external == 0)\r |
| 1244 | sdPtr = sd;\r |
| 1245 | else\r |
| 1246 | {\r |
| 1247 | UInt32 index;\r |
| 1248 | RINOK(SzReadNumber32(sd, &index));\r |
| 1249 | if (index >= *numTempBufs)\r |
| 1250 | return SZ_ERROR_ARCHIVE;\r |
| 1251 | sdSwitch.Data = (tempBufs)[index].data;\r |
| 1252 | sdSwitch.Size = (tempBufs)[index].size;\r |
| 1253 | sdPtr = &sdSwitch;\r |
| 1254 | }\r |
| 1255 | RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain));\r |
| 1256 | break;\r |
| 1257 | }\r |
| 1258 | /*\r |
| 1259 | case k7zParent:\r |
| 1260 | {\r |
| 1261 | SzBitUi32s_Free(&p->Parents, allocMain);\r |
| 1262 | RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain));\r |
| 1263 | RINOK(SzReadSwitch(sd));\r |
| 1264 | RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain));\r |
| 1265 | break;\r |
| 1266 | }\r |
| 1267 | */\r |
| 1268 | case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break;\r |
| 1269 | case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break;\r |
| 1270 | default:\r |
| 1271 | {\r |
| 1272 | SKIP_DATA(sd, size);\r |
| 1273 | }\r |
| 1274 | }\r |
| 1275 | }\r |
| 1276 | \r |
| 1277 | if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams)\r |
| 1278 | return SZ_ERROR_ARCHIVE;\r |
| 1279 | \r |
| 1280 | for (;;)\r |
| 1281 | {\r |
| 1282 | UInt64 type;\r |
| 1283 | RINOK(ReadID(sd, &type));\r |
| 1284 | if (type == k7zIdEnd)\r |
| 1285 | break;\r |
| 1286 | RINOK(SkipData(sd));\r |
| 1287 | }\r |
| 1288 | \r |
| 1289 | {\r |
| 1290 | UInt32 i;\r |
| 1291 | UInt32 emptyFileIndex = 0;\r |
| 1292 | UInt32 folderIndex = 0;\r |
| 1293 | UInt32 remSubStreams = 0;\r |
| 1294 | UInt32 numSubStreams = 0;\r |
| 1295 | UInt64 unpackPos = 0;\r |
| 1296 | const Byte *digestsDefs = NULL;\r |
| 1297 | const Byte *digestsVals = NULL;\r |
| 1298 | UInt32 digestsValsIndex = 0;\r |
| 1299 | UInt32 digestIndex;\r |
| 1300 | Byte allDigestsDefined = 0;\r |
| 1301 | Byte isDirMask = 0;\r |
| 1302 | Byte crcMask = 0;\r |
| 1303 | Byte mask = 0x80;\r |
| 1304 | \r |
| 1305 | MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain);\r |
| 1306 | MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain);\r |
| 1307 | MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain);\r |
| 1308 | MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain);\r |
| 1309 | \r |
| 1310 | RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain));\r |
| 1311 | \r |
| 1312 | if (ssi.sdCRCs.Size != 0)\r |
| 1313 | {\r |
| 1314 | SZ_READ_BYTE_SD(&ssi.sdCRCs, allDigestsDefined);\r |
| 1315 | if (allDigestsDefined)\r |
| 1316 | digestsVals = ssi.sdCRCs.Data;\r |
| 1317 | else\r |
| 1318 | {\r |
| 1319 | size_t numBytes = (ssi.NumSubDigests + 7) >> 3;\r |
| 1320 | digestsDefs = ssi.sdCRCs.Data;\r |
| 1321 | digestsVals = digestsDefs + numBytes;\r |
| 1322 | }\r |
| 1323 | }\r |
| 1324 | \r |
| 1325 | digestIndex = 0;\r |
| 1326 | \r |
| 1327 | for (i = 0; i < numFiles; i++, mask >>= 1)\r |
| 1328 | {\r |
| 1329 | if (mask == 0)\r |
| 1330 | {\r |
| 1331 | UInt32 byteIndex = (i - 1) >> 3;\r |
| 1332 | p->IsDirs[byteIndex] = isDirMask;\r |
| 1333 | p->CRCs.Defs[byteIndex] = crcMask;\r |
| 1334 | isDirMask = 0;\r |
| 1335 | crcMask = 0;\r |
| 1336 | mask = 0x80;\r |
| 1337 | }\r |
| 1338 | \r |
| 1339 | p->UnpackPositions[i] = unpackPos;\r |
| 1340 | p->CRCs.Vals[i] = 0;\r |
| 1341 | \r |
| 1342 | if (emptyStreams && SzBitArray_Check(emptyStreams, i))\r |
| 1343 | {\r |
| 1344 | if (emptyFiles)\r |
| 1345 | {\r |
| 1346 | if (!SzBitArray_Check(emptyFiles, emptyFileIndex))\r |
| 1347 | isDirMask |= mask;\r |
| 1348 | emptyFileIndex++;\r |
| 1349 | }\r |
| 1350 | else\r |
| 1351 | isDirMask |= mask;\r |
| 1352 | if (remSubStreams == 0)\r |
| 1353 | {\r |
| 1354 | p->FileToFolder[i] = (UInt32)-1;\r |
| 1355 | continue;\r |
| 1356 | }\r |
| 1357 | }\r |
| 1358 | \r |
| 1359 | if (remSubStreams == 0)\r |
| 1360 | {\r |
| 1361 | for (;;)\r |
| 1362 | {\r |
| 1363 | if (folderIndex >= p->db.NumFolders)\r |
| 1364 | return SZ_ERROR_ARCHIVE;\r |
| 1365 | p->FolderToFile[folderIndex] = i;\r |
| 1366 | numSubStreams = 1;\r |
| 1367 | if (ssi.sdNumSubStreams.Data)\r |
| 1368 | {\r |
| 1369 | RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams));\r |
| 1370 | }\r |
| 1371 | remSubStreams = numSubStreams;\r |
| 1372 | if (numSubStreams != 0)\r |
| 1373 | break;\r |
| 1374 | {\r |
| 1375 | UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);\r |
| 1376 | unpackPos += folderUnpackSize;\r |
| 1377 | if (unpackPos < folderUnpackSize)\r |
| 1378 | return SZ_ERROR_ARCHIVE;\r |
| 1379 | }\r |
| 1380 | \r |
| 1381 | folderIndex++;\r |
| 1382 | }\r |
| 1383 | }\r |
| 1384 | \r |
| 1385 | p->FileToFolder[i] = folderIndex;\r |
| 1386 | \r |
| 1387 | if (emptyStreams && SzBitArray_Check(emptyStreams, i))\r |
| 1388 | continue;\r |
| 1389 | \r |
| 1390 | if (--remSubStreams == 0)\r |
| 1391 | {\r |
| 1392 | UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);\r |
| 1393 | UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]];\r |
| 1394 | if (folderUnpackSize < unpackPos - startFolderUnpackPos)\r |
| 1395 | return SZ_ERROR_ARCHIVE;\r |
| 1396 | unpackPos = startFolderUnpackPos + folderUnpackSize;\r |
| 1397 | if (unpackPos < folderUnpackSize)\r |
| 1398 | return SZ_ERROR_ARCHIVE;\r |
| 1399 | \r |
| 1400 | if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i))\r |
| 1401 | {\r |
| 1402 | p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex];\r |
| 1403 | crcMask |= mask;\r |
| 1404 | }\r |
| 1405 | else if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex)))\r |
| 1406 | {\r |
| 1407 | p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4);\r |
| 1408 | digestsValsIndex++;\r |
| 1409 | crcMask |= mask;\r |
| 1410 | }\r |
| 1411 | \r |
| 1412 | folderIndex++;\r |
| 1413 | }\r |
| 1414 | else\r |
| 1415 | {\r |
| 1416 | UInt64 v;\r |
| 1417 | RINOK(ReadNumber(&ssi.sdSizes, &v));\r |
| 1418 | unpackPos += v;\r |
| 1419 | if (unpackPos < v)\r |
| 1420 | return SZ_ERROR_ARCHIVE;\r |
| 1421 | if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex)))\r |
| 1422 | {\r |
| 1423 | p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4);\r |
| 1424 | digestsValsIndex++;\r |
| 1425 | crcMask |= mask;\r |
| 1426 | }\r |
| 1427 | }\r |
| 1428 | }\r |
| 1429 | \r |
| 1430 | if (mask != 0x80)\r |
| 1431 | {\r |
| 1432 | UInt32 byteIndex = (i - 1) >> 3;\r |
| 1433 | p->IsDirs[byteIndex] = isDirMask;\r |
| 1434 | p->CRCs.Defs[byteIndex] = crcMask;\r |
| 1435 | }\r |
| 1436 | \r |
| 1437 | p->UnpackPositions[i] = unpackPos;\r |
| 1438 | \r |
| 1439 | if (remSubStreams != 0)\r |
| 1440 | return SZ_ERROR_ARCHIVE;\r |
| 1441 | \r |
| 1442 | for (;;)\r |
| 1443 | {\r |
| 1444 | p->FolderToFile[folderIndex] = i;\r |
| 1445 | if (folderIndex >= p->db.NumFolders)\r |
| 1446 | break;\r |
| 1447 | if (!ssi.sdNumSubStreams.Data)\r |
| 1448 | return SZ_ERROR_ARCHIVE;\r |
| 1449 | RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams));\r |
| 1450 | if (numSubStreams != 0)\r |
| 1451 | return SZ_ERROR_ARCHIVE;\r |
| 1452 | /*\r |
| 1453 | {\r |
| 1454 | UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);\r |
| 1455 | unpackPos += folderUnpackSize;\r |
| 1456 | if (unpackPos < folderUnpackSize)\r |
| 1457 | return SZ_ERROR_ARCHIVE;\r |
| 1458 | }\r |
| 1459 | */\r |
| 1460 | folderIndex++;\r |
| 1461 | }\r |
| 1462 | \r |
| 1463 | if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0)\r |
| 1464 | return SZ_ERROR_ARCHIVE;\r |
| 1465 | }\r |
| 1466 | }\r |
| 1467 | return SZ_OK;\r |
| 1468 | }\r |
| 1469 | \r |
| 1470 | \r |
| 1471 | static SRes SzReadHeader(\r |
| 1472 | CSzArEx *p,\r |
| 1473 | CSzData *sd,\r |
| 1474 | ILookInStream *inStream,\r |
| 1475 | ISzAlloc *allocMain,\r |
| 1476 | ISzAlloc *allocTemp)\r |
| 1477 | {\r |
| 1478 | UInt32 i;\r |
| 1479 | UInt32 numTempBufs = 0;\r |
| 1480 | SRes res;\r |
| 1481 | CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX];\r |
| 1482 | \r |
| 1483 | for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++)\r |
| 1484 | Buf_Init(tempBufs + i);\r |
| 1485 | \r |
| 1486 | res = SzReadHeader2(p, sd, inStream,\r |
| 1487 | tempBufs, &numTempBufs,\r |
| 1488 | allocMain, allocTemp);\r |
| 1489 | \r |
| 1490 | for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++)\r |
| 1491 | Buf_Free(tempBufs + i, allocTemp);\r |
| 1492 | \r |
| 1493 | RINOK(res);\r |
| 1494 | \r |
| 1495 | if (sd->Size != 0)\r |
| 1496 | return SZ_ERROR_FAIL;\r |
| 1497 | \r |
| 1498 | return res;\r |
| 1499 | }\r |
| 1500 | \r |
| 1501 | static SRes SzArEx_Open2(\r |
| 1502 | CSzArEx *p,\r |
| 1503 | ILookInStream *inStream,\r |
| 1504 | ISzAlloc *allocMain,\r |
| 1505 | ISzAlloc *allocTemp)\r |
| 1506 | {\r |
| 1507 | Byte header[k7zStartHeaderSize];\r |
| 1508 | Int64 startArcPos;\r |
| 1509 | UInt64 nextHeaderOffset, nextHeaderSize;\r |
| 1510 | size_t nextHeaderSizeT;\r |
| 1511 | UInt32 nextHeaderCRC;\r |
| 1512 | CBuf buf;\r |
| 1513 | SRes res;\r |
| 1514 | \r |
| 1515 | startArcPos = 0;\r |
| 1516 | RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR));\r |
| 1517 | \r |
| 1518 | RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE));\r |
| 1519 | \r |
| 1520 | if (!TestSignatureCandidate(header))\r |
| 1521 | return SZ_ERROR_NO_ARCHIVE;\r |
| 1522 | if (header[6] != k7zMajorVersion)\r |
| 1523 | return SZ_ERROR_UNSUPPORTED;\r |
| 1524 | \r |
| 1525 | nextHeaderOffset = GetUi64(header + 12);\r |
| 1526 | nextHeaderSize = GetUi64(header + 20);\r |
| 1527 | nextHeaderCRC = GetUi32(header + 28);\r |
| 1528 | \r |
| 1529 | p->startPosAfterHeader = startArcPos + k7zStartHeaderSize;\r |
| 1530 | \r |
| 1531 | if (CrcCalc(header + 12, 20) != GetUi32(header + 8))\r |
| 1532 | return SZ_ERROR_CRC;\r |
| 1533 | \r |
| 1534 | nextHeaderSizeT = (size_t)nextHeaderSize;\r |
| 1535 | if (nextHeaderSizeT != nextHeaderSize)\r |
| 1536 | return SZ_ERROR_MEM;\r |
| 1537 | if (nextHeaderSizeT == 0)\r |
| 1538 | return SZ_OK;\r |
| 1539 | if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize ||\r |
| 1540 | nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize)\r |
| 1541 | return SZ_ERROR_NO_ARCHIVE;\r |
| 1542 | \r |
| 1543 | {\r |
| 1544 | Int64 pos = 0;\r |
| 1545 | RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END));\r |
| 1546 | if ((UInt64)pos < startArcPos + nextHeaderOffset ||\r |
| 1547 | (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset ||\r |
| 1548 | (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)\r |
| 1549 | return SZ_ERROR_INPUT_EOF;\r |
| 1550 | }\r |
| 1551 | \r |
| 1552 | RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset));\r |
| 1553 | \r |
| 1554 | if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp))\r |
| 1555 | return SZ_ERROR_MEM;\r |
| 1556 | \r |
| 1557 | res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT);\r |
| 1558 | \r |
| 1559 | if (res == SZ_OK)\r |
| 1560 | {\r |
| 1561 | res = SZ_ERROR_ARCHIVE;\r |
| 1562 | if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC)\r |
| 1563 | {\r |
| 1564 | CSzData sd;\r |
| 1565 | UInt64 type;\r |
| 1566 | sd.Data = buf.data;\r |
| 1567 | sd.Size = buf.size;\r |
| 1568 | \r |
| 1569 | res = ReadID(&sd, &type);\r |
| 1570 | \r |
| 1571 | if (res == SZ_OK && type == k7zIdEncodedHeader)\r |
| 1572 | {\r |
| 1573 | CSzAr tempAr;\r |
| 1574 | CBuf tempBuf;\r |
| 1575 | Buf_Init(&tempBuf);\r |
| 1576 | \r |
| 1577 | SzAr_Init(&tempAr);\r |
| 1578 | res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp);\r |
| 1579 | SzAr_Free(&tempAr, allocTemp);\r |
| 1580 | \r |
| 1581 | if (res != SZ_OK)\r |
| 1582 | {\r |
| 1583 | Buf_Free(&tempBuf, allocTemp);\r |
| 1584 | }\r |
| 1585 | else\r |
| 1586 | {\r |
| 1587 | Buf_Free(&buf, allocTemp);\r |
| 1588 | buf.data = tempBuf.data;\r |
| 1589 | buf.size = tempBuf.size;\r |
| 1590 | sd.Data = buf.data;\r |
| 1591 | sd.Size = buf.size;\r |
| 1592 | res = ReadID(&sd, &type);\r |
| 1593 | }\r |
| 1594 | }\r |
| 1595 | \r |
| 1596 | if (res == SZ_OK)\r |
| 1597 | {\r |
| 1598 | if (type == k7zIdHeader)\r |
| 1599 | {\r |
| 1600 | /*\r |
| 1601 | CSzData sd2;\r |
| 1602 | unsigned ttt;\r |
| 1603 | for (ttt = 0; ttt < 40000; ttt++)\r |
| 1604 | {\r |
| 1605 | SzArEx_Free(p, allocMain);\r |
| 1606 | sd2 = sd;\r |
| 1607 | res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp);\r |
| 1608 | if (res != SZ_OK)\r |
| 1609 | break;\r |
| 1610 | }\r |
| 1611 | */\r |
| 1612 | res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp);\r |
| 1613 | }\r |
| 1614 | else\r |
| 1615 | res = SZ_ERROR_UNSUPPORTED;\r |
| 1616 | }\r |
| 1617 | }\r |
| 1618 | }\r |
| 1619 | \r |
| 1620 | Buf_Free(&buf, allocTemp);\r |
| 1621 | return res;\r |
| 1622 | }\r |
| 1623 | \r |
| 1624 | \r |
| 1625 | SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream,\r |
| 1626 | ISzAlloc *allocMain, ISzAlloc *allocTemp)\r |
| 1627 | {\r |
| 1628 | SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp);\r |
| 1629 | if (res != SZ_OK)\r |
| 1630 | SzArEx_Free(p, allocMain);\r |
| 1631 | return res;\r |
| 1632 | }\r |
| 1633 | \r |
| 1634 | \r |
| 1635 | SRes SzArEx_Extract(\r |
| 1636 | const CSzArEx *p,\r |
| 1637 | ILookInStream *inStream,\r |
| 1638 | UInt32 fileIndex,\r |
| 1639 | UInt32 *blockIndex,\r |
| 1640 | Byte **tempBuf,\r |
| 1641 | size_t *outBufferSize,\r |
| 1642 | size_t *offset,\r |
| 1643 | size_t *outSizeProcessed,\r |
| 1644 | ISzAlloc *allocMain,\r |
| 1645 | ISzAlloc *allocTemp)\r |
| 1646 | {\r |
| 1647 | UInt32 folderIndex = p->FileToFolder[fileIndex];\r |
| 1648 | SRes res = SZ_OK;\r |
| 1649 | \r |
| 1650 | *offset = 0;\r |
| 1651 | *outSizeProcessed = 0;\r |
| 1652 | \r |
| 1653 | if (folderIndex == (UInt32)-1)\r |
| 1654 | {\r |
| 1655 | IAlloc_Free(allocMain, *tempBuf);\r |
| 1656 | *blockIndex = folderIndex;\r |
| 1657 | *tempBuf = NULL;\r |
| 1658 | *outBufferSize = 0;\r |
| 1659 | return SZ_OK;\r |
| 1660 | }\r |
| 1661 | \r |
| 1662 | if (*tempBuf == NULL || *blockIndex != folderIndex)\r |
| 1663 | {\r |
| 1664 | UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex);\r |
| 1665 | /*\r |
| 1666 | UInt64 unpackSizeSpec =\r |
| 1667 | p->UnpackPositions[p->FolderToFile[folderIndex + 1]] -\r |
| 1668 | p->UnpackPositions[p->FolderToFile[folderIndex]];\r |
| 1669 | */\r |
| 1670 | size_t unpackSize = (size_t)unpackSizeSpec;\r |
| 1671 | \r |
| 1672 | if (unpackSize != unpackSizeSpec)\r |
| 1673 | return SZ_ERROR_MEM;\r |
| 1674 | *blockIndex = folderIndex;\r |
| 1675 | IAlloc_Free(allocMain, *tempBuf);\r |
| 1676 | *tempBuf = NULL;\r |
| 1677 | \r |
| 1678 | if (res == SZ_OK)\r |
| 1679 | {\r |
| 1680 | *outBufferSize = unpackSize;\r |
| 1681 | if (unpackSize != 0)\r |
| 1682 | {\r |
| 1683 | *tempBuf = (Byte *)IAlloc_Alloc(allocMain, unpackSize);\r |
| 1684 | if (*tempBuf == NULL)\r |
| 1685 | res = SZ_ERROR_MEM;\r |
| 1686 | }\r |
| 1687 | \r |
| 1688 | if (res == SZ_OK)\r |
| 1689 | {\r |
| 1690 | res = SzAr_DecodeFolder(&p->db, folderIndex,\r |
| 1691 | inStream, p->dataPos, *tempBuf, unpackSize, allocTemp);\r |
| 1692 | }\r |
| 1693 | }\r |
| 1694 | }\r |
| 1695 | \r |
| 1696 | if (res == SZ_OK)\r |
| 1697 | {\r |
| 1698 | UInt64 unpackPos = p->UnpackPositions[fileIndex];\r |
| 1699 | *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]);\r |
| 1700 | *outSizeProcessed = (size_t)(p->UnpackPositions[fileIndex + 1] - unpackPos);\r |
| 1701 | if (*offset + *outSizeProcessed > *outBufferSize)\r |
| 1702 | return SZ_ERROR_FAIL;\r |
| 1703 | if (SzBitWithVals_Check(&p->CRCs, fileIndex))\r |
| 1704 | if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex])\r |
| 1705 | res = SZ_ERROR_CRC;\r |
| 1706 | }\r |
| 1707 | \r |
| 1708 | return res;\r |
| 1709 | }\r |
| 1710 | \r |
| 1711 | \r |
| 1712 | size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest)\r |
| 1713 | {\r |
| 1714 | size_t offs = p->FileNameOffsets[fileIndex];\r |
| 1715 | size_t len = p->FileNameOffsets[fileIndex + 1] - offs;\r |
| 1716 | if (dest != 0)\r |
| 1717 | {\r |
| 1718 | size_t i;\r |
| 1719 | const Byte *src = p->FileNames + offs * 2;\r |
| 1720 | for (i = 0; i < len; i++)\r |
| 1721 | dest[i] = GetUi16(src + i * 2);\r |
| 1722 | }\r |
| 1723 | return len;\r |
| 1724 | }\r |
| 1725 | \r |
| 1726 | /*\r |
| 1727 | size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex)\r |
| 1728 | {\r |
| 1729 | size_t len;\r |
| 1730 | if (!p->FileNameOffsets)\r |
| 1731 | return 1;\r |
| 1732 | len = 0;\r |
| 1733 | for (;;)\r |
| 1734 | {\r |
| 1735 | UInt32 parent = (UInt32)(Int32)-1;\r |
| 1736 | len += p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];\r |
| 1737 | if SzBitWithVals_Check(&p->Parents, fileIndex)\r |
| 1738 | parent = p->Parents.Vals[fileIndex];\r |
| 1739 | if (parent == (UInt32)(Int32)-1)\r |
| 1740 | return len;\r |
| 1741 | fileIndex = parent;\r |
| 1742 | }\r |
| 1743 | }\r |
| 1744 | \r |
| 1745 | UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest)\r |
| 1746 | {\r |
| 1747 | Bool needSlash;\r |
| 1748 | if (!p->FileNameOffsets)\r |
| 1749 | {\r |
| 1750 | *(--dest) = 0;\r |
| 1751 | return dest;\r |
| 1752 | }\r |
| 1753 | needSlash = False;\r |
| 1754 | for (;;)\r |
| 1755 | {\r |
| 1756 | UInt32 parent = (UInt32)(Int32)-1;\r |
| 1757 | size_t curLen = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];\r |
| 1758 | SzArEx_GetFileNameUtf16(p, fileIndex, dest - curLen);\r |
| 1759 | if (needSlash)\r |
| 1760 | *(dest - 1) = '/';\r |
| 1761 | needSlash = True;\r |
| 1762 | dest -= curLen;\r |
| 1763 | \r |
| 1764 | if SzBitWithVals_Check(&p->Parents, fileIndex)\r |
| 1765 | parent = p->Parents.Vals[fileIndex];\r |
| 1766 | if (parent == (UInt32)(Int32)-1)\r |
| 1767 | return dest;\r |
| 1768 | fileIndex = parent;\r |
| 1769 | }\r |
| 1770 | }\r |
| 1771 | */\r |