static SRes SzReadSubStreamsInfo( CSzData *sd, uint32_t numFolders, CSzFolder *folders, uint32_t *numUnpackStreams, uint64_t **unpackSizes, uint8_t **digestsDefined, uint32_t **digests, ISzAlloc *allocTemp) { uint64_t type = 0; uint32_t i; uint32_t si = 0; uint32_t numDigests = 0; for (i = 0; i < numFolders; i++) folders[i].NumUnpackStreams = 1; *numUnpackStreams = numFolders; for (;;) { RINOK(SzReadID(sd, &type)); if (type == k7zIdNumUnpackStream) { *numUnpackStreams = 0; for (i = 0; i < numFolders; i++) { uint32_t numStreams; RINOK(SzReadNumber32(sd, &numStreams)); folders[i].NumUnpackStreams = numStreams; *numUnpackStreams += numStreams; } continue; } if (type == k7zIdCRC || type == k7zIdSize) break; if (type == k7zIdEnd) break; RINOK(SzSkeepData(sd)); } if (*numUnpackStreams == 0) { *unpackSizes = 0; *digestsDefined = 0; *digests = 0; } else { *unpackSizes = (uint64_t *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(uint64_t)); RINOM(*unpackSizes); *digestsDefined = (uint8_t *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(uint8_t)); RINOM(*digestsDefined); *digests = (uint32_t *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(uint32_t)); RINOM(*digests); } for (i = 0; i < numFolders; i++) { /* v3.13 incorrectly worked with empty folders v4.07: we check that folder is empty */ uint64_t sum = 0; uint32_t j; uint32_t numSubstreams = folders[i].NumUnpackStreams; if (numSubstreams == 0) continue; if (type == k7zIdSize) for (j = 1; j < numSubstreams; j++) { uint64_t size; RINOK(SzReadNumber(sd, &size)); (*unpackSizes)[si++] = size; sum += size; } (*unpackSizes)[si++] = SzFolder_GetUnpackSize(folders + i) - sum; } if (type == k7zIdSize) { RINOK(SzReadID(sd, &type)); } for (i = 0; i < *numUnpackStreams; i++) { (*digestsDefined)[i] = 0; (*digests)[i] = 0; } for (i = 0; i < numFolders; i++) { uint32_t numSubstreams = folders[i].NumUnpackStreams; if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) numDigests += numSubstreams; } si = 0; for (;;) { if (type == k7zIdCRC) { int digestIndex = 0; uint8_t *digestsDefined2 = 0; uint32_t *digests2 = 0; SRes res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp); if (res == SZ_OK) { for (i = 0; i < numFolders; i++) { CSzFolder *folder = folders + i; uint32_t numSubstreams = folder->NumUnpackStreams; if (numSubstreams == 1 && folder->UnpackCRCDefined) { (*digestsDefined)[si] = 1; (*digests)[si] = folder->UnpackCRC; si++; } else { uint32_t j; for (j = 0; j < numSubstreams; j++, digestIndex++) { (*digestsDefined)[si] = digestsDefined2[digestIndex]; (*digests)[si] = digests2[digestIndex]; si++; } } } } IAlloc_Free(allocTemp, digestsDefined2); IAlloc_Free(allocTemp, digests2); RINOK(res); } else if (type == k7zIdEnd) return SZ_OK; else { RINOK(SzSkeepData(sd)); } RINOK(SzReadID(sd, &type)); } }
SRes SzArEx_Extract( const CSzArEx *p, ILookInStream *inStream, uint32_t fileIndex, uint32_t *blockIndex, uint8_t **outBuffer, size_t *outBufferSize, size_t *offset, size_t *outSizeProcessed, ISzAlloc *allocMain, ISzAlloc *allocTemp) { uint32_t folderIndex = p->FileIndexToFolderIndexMap[fileIndex]; SRes res = SZ_OK; *offset = 0; *outSizeProcessed = 0; if (folderIndex == (uint32_t)-1) { IAlloc_Free(allocMain, *outBuffer); *blockIndex = folderIndex; *outBuffer = 0; *outBufferSize = 0; return SZ_OK; } if (*outBuffer == 0 || *blockIndex != folderIndex) { CSzFolder *folder = p->db.Folders + folderIndex; uint64_t unpackSizeSpec = SzFolder_GetUnpackSize(folder); size_t unpackSize = (size_t)unpackSizeSpec; uint64_t startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0); if (unpackSize != unpackSizeSpec) return SZ_ERROR_MEM; *blockIndex = folderIndex; IAlloc_Free(allocMain, *outBuffer); *outBuffer = 0; RINOK(LookInStream_SeekTo(inStream, startOffset)); if (res == SZ_OK) { *outBufferSize = unpackSize; if (unpackSize != 0) { *outBuffer = (uint8_t *)IAlloc_Alloc(allocMain, unpackSize); if (*outBuffer == 0) res = SZ_ERROR_MEM; } if (res == SZ_OK) { res = SzFolder_Decode(folder, p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex], inStream, startOffset, *outBuffer, unpackSize, allocTemp); if (res == SZ_OK) { if (folder->UnpackCRCDefined) { if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC) res = SZ_ERROR_CRC; } } } } } if (res == SZ_OK) { uint32_t i; CSzFileItem *fileItem = p->db.Files + fileIndex; *offset = 0; for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++) *offset += (uint32_t)p->db.Files[i].Size; *outSizeProcessed = (size_t)fileItem->Size; if (*offset + *outSizeProcessed > *outBufferSize) return SZ_ERROR_FAIL; if (fileItem->CrcDefined && CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->Crc) res = SZ_ERROR_CRC; } return res; }
static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, ILookInStream *inStream, UInt64 startPos, Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain, Byte *tempBuf[]) { UInt32 ci; SizeT tempSizes[3] = { 0, 0, 0}; SizeT tempSize3 = 0; Byte *tempBuf3 = 0; RINOK(CheckSupportedFolder(folder)); for (ci = 0; ci < folder->NumCoders; ci++) { CSzCoderInfo *coder = &folder->Coders[ci]; if (IS_MAIN_METHOD((UInt32)coder->MethodID)) { UInt32 si = 0; UInt64 offset; UInt64 inSize; Byte *outBufCur = outBuffer; SizeT outSizeCur = outSize; if (folder->NumCoders == 4) { UInt32 indices[] = { 3, 2, 0 }; UInt64 unpackSize = folder->UnpackSizes[ci]; si = indices[ci]; if (ci < 2) { Byte *temp; outSizeCur = (SizeT)unpackSize; if (outSizeCur != unpackSize) return SZ_ERROR_MEM; temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur); if (temp == 0 && outSizeCur != 0) return SZ_ERROR_MEM; outBufCur = tempBuf[1 - ci] = temp; tempSizes[1 - ci] = outSizeCur; } else if (ci == 2) { if (unpackSize > outSize) /* check it */ return SZ_ERROR_PARAM; tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); tempSize3 = outSizeCur = (SizeT)unpackSize; } else return SZ_ERROR_UNSUPPORTED; } offset = GetSum(packSizes, si); inSize = packSizes[si]; RINOK(LookInStream_SeekTo(inStream, startPos + offset)); if (coder->MethodID == k_Copy) { if (inSize != outSizeCur) /* check it */ return SZ_ERROR_DATA; RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); } else if (coder->MethodID == k_LZMA) { RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); } else if (coder->MethodID == k_LZMA2) { #ifdef _7ZIP_LZMA2_SUPPPORT RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); #else return SZ_ERROR_UNSUPPORTED; #endif } else { #ifdef _7ZIP_PPMD_SUPPPORT RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); #else return SZ_ERROR_UNSUPPORTED; #endif } } else if (coder->MethodID == k_BCJ2) { UInt64 offset = GetSum(packSizes, 1); UInt64 s3Size = packSizes[1]; SRes res; if (ci != 3) return SZ_ERROR_UNSUPPORTED; RINOK(LookInStream_SeekTo(inStream, startPos + offset)); tempSizes[2] = (SizeT)s3Size; if (tempSizes[2] != s3Size) return SZ_ERROR_MEM; tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]); if (tempBuf[2] == 0 && tempSizes[2] != 0) return SZ_ERROR_MEM; res = SzDecodeCopy(s3Size, inStream, tempBuf[2]); RINOK(res) res = Bcj2_Decode( tempBuf3, tempSize3, tempBuf[0], tempSizes[0], tempBuf[1], tempSizes[1], tempBuf[2], tempSizes[2], outBuffer, outSize); RINOK(res) } else { if (ci != 1)
SRes SzAr_Extract( const CSzArEx *p, ISzInStream *inStream, UInt32 fileIndex, UInt32 *blockIndex, Byte **outBuffer, size_t *outBufferSize, size_t *offset, size_t *outSizeProcessed, ISzAlloc *allocMain, ISzAlloc *allocTemp) { UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex]; SRes res = SZ_OK; *offset = 0; *outSizeProcessed = 0; if (folderIndex == (UInt32)-1) { IAlloc_Free(allocMain, *outBuffer); *blockIndex = folderIndex; *outBuffer = 0; *outBufferSize = 0; return SZ_OK; } if (*outBuffer == 0 || *blockIndex != folderIndex) { CSzFolder *folder = p->db.Folders + folderIndex; CFileSize unPackSizeSpec = SzFolder_GetUnPackSize(folder); size_t unPackSize = (size_t)unPackSizeSpec; CFileSize startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0); if (unPackSize != unPackSizeSpec) return SZ_ERROR_MEM; *blockIndex = folderIndex; IAlloc_Free(allocMain, *outBuffer); *outBuffer = 0; RINOK(inStream->Seek(inStream, startOffset, SZ_SEEK_SET)); if (res == SZ_OK) { *outBufferSize = unPackSize; if (unPackSize != 0) { *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unPackSize); if (*outBuffer == 0) res = SZ_ERROR_MEM; } if (res == SZ_OK) { res = SzDecode(p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex], folder, inStream, startOffset, *outBuffer, unPackSize, allocTemp); if (res == SZ_OK) { if (folder->UnPackCRCDefined) { if (CrcCalc(*outBuffer, unPackSize) != folder->UnPackCRC) res = SZ_ERROR_CRC; } } } } } if (res == SZ_OK) { UInt32 i; CSzFileItem *fileItem = p->db.Files + fileIndex; *offset = 0; for(i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++) *offset += (UInt32)p->db.Files[i].Size; *outSizeProcessed = (size_t)fileItem->Size; if (*offset + *outSizeProcessed > *outBufferSize) return SZ_ERROR_FAIL; { if (fileItem->IsFileCRCDefined) { if (CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->FileCRC) res = SZ_ERROR_CRC; } } } return res; }
SRes SzArEx_Extract( const CSzArEx *p, ILookInStream *inStream, UInt32 fileIndex, SzArEx_DictCache *dictCache, ISzAlloc *allocMain, ISzAlloc *allocTemp) { UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex]; SRes res = SZ_OK; dictCache->entryOffset = 0; dictCache->outSizeProcessed = 0; if (folderIndex == (UInt32)-1) { SzArEx_DictCache_free(dictCache); dictCache->blockIndex = folderIndex; return SZ_OK; } if (dictCache->outBuffer == 0 || dictCache->blockIndex != folderIndex) { CSzFolder *folder = p->db.Folders + folderIndex; UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder); size_t unpackSize = (size_t)unpackSizeSpec; UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0); if (unpackSize != unpackSizeSpec) return SZ_ERROR_MEM; SzArEx_DictCache_free(dictCache); dictCache->blockIndex = folderIndex; RINOK(LookInStream_SeekTo(inStream, startOffset)); if (res == SZ_OK) { dictCache->outBufferSize = unpackSize; if (unpackSize != 0) { if (dictCache->mapFilename && (unpackSize >= k7zUnpackMapDictionaryInMemoryMaxNumBytes)) { // map to disk is enabled and file is larger than 1 megabyte. // note that an error condition is checked by seeing if // dictCache->outBuffer after a map attempt SzArEx_DictCache_mmap(dictCache); } else { dictCache->outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize); } if (dictCache->outBuffer == 0) res = SZ_ERROR_MEM; } if (res == SZ_OK) { res = SzFolder_Decode(folder, p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex], inStream, startOffset, dictCache->outBuffer, unpackSize, allocTemp); if (res == SZ_OK) { if (folder->UnpackCRCDefined) { #ifdef _7ZIP_CRC_SUPPORT if (CrcCalc(dictCache->outBuffer, unpackSize) != folder->UnpackCRC) res = SZ_ERROR_CRC; #endif } } } } } if (res == SZ_OK) { UInt32 i; CSzFileItem *fileItem = p->db.Files + fileIndex; dictCache->entryOffset = 0; for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++) dictCache->entryOffset += (UInt32)p->db.Files[i].Size; dictCache->outSizeProcessed = (size_t)fileItem->Size; if (dictCache->entryOffset + dictCache->outSizeProcessed > dictCache->outBufferSize) return SZ_ERROR_FAIL; #ifdef _7ZIP_CRC_SUPPORT if (fileItem->CrcDefined && CrcCalc(dictCache->outBuffer + dictCache->entryOffset, dictCache->outSizeProcessed) != fileItem->Crc) res = SZ_ERROR_CRC; #endif } return res; }
SRes SzDecode2(const CFileSize *packSizes, const CSzFolder *folder, /* #ifdef _LZMA_IN_CB */ ISzInStream *inStream, CFileSize startPos, /* #else const Byte *inBuffer, #endif */ Byte *outBuffer, size_t outSize, ISzAlloc *allocMain, Byte *tempBuf[]) { UInt32 ci; size_t tempSizes[3] = { 0, 0, 0}; size_t tempSize3 = 0; Byte *tempBuf3 = 0; RINOK(CheckSupportedFolder(folder)); for (ci = 0; ci < folder->NumCoders; ci++) { CSzCoderInfo *coder = &folder->Coders[ci]; if (coder->MethodID == k_Copy || coder->MethodID == k_LZMA || coder->MethodID == k_BZ2 || coder->MethodID == k_PPMD) { UInt32 si = 0; CFileSize offset; CFileSize inSize; Byte *outBufCur = outBuffer; size_t outSizeCur = outSize; if (folder->NumCoders == 4) { UInt32 indices[] = { 3, 2, 0 }; CFileSize unpackSize = folder->UnpackSizes[ci]; si = indices[ci]; if (ci < 2) { Byte *temp; outSizeCur = (size_t)unpackSize; if (outSizeCur != unpackSize) return SZ_ERROR_MEM; temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur); if (temp == 0 && outSizeCur != 0) return SZ_ERROR_MEM; outBufCur = tempBuf[1 - ci] = temp; tempSizes[1 - ci] = outSizeCur; } else if (ci == 2) { if (unpackSize > outSize) // check it return SZ_ERROR_PARAM; // check it tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); tempSize3 = outSizeCur = (size_t)unpackSize; } else return SZ_ERROR_UNSUPPORTED; } offset = GetSum(packSizes, si); inSize = packSizes[si]; /* #ifdef _LZMA_IN_CB */ RINOK(inStream->Seek(inStream, startPos + offset, SZ_SEEK_SET)); /* #endif */ if (coder->MethodID == k_Copy) { if (inSize != outSizeCur) // check it return SZ_ERROR_DATA; /* #ifdef _LZMA_IN_CB */ RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); /* #else memcpy(outBufCur, inBuffer + (size_t)offset, (size_t)inSize); #endif */ } else if(coder->MethodID == k_PPMD) { SRes res = SZ_OK; struct PPMdProps pprops; pprops.maxorder = coder->Props.data[0]; pprops.suballocsize = (coder->Props.data[1]) | (coder->Props.data[2] << 8) | (coder->Props.data[3] << 16) | (coder->Props.data[4] << 24); PPMdSubAllocatorVariantH *alloc=CreateSubAllocatorVariantH(pprops.suballocsize); PPMdModelVariantH model; StartPPMdModelVariantH(&model,inStream,alloc,pprops.maxorder,TRUE); outSizeCur = 0; while(outSizeCur < outSize) { int byte=NextPPMdVariantHByte(&model); if(byte<0) break; *outBufCur = byte; outBufCur++; outSizeCur++; } FreeSubAllocatorVariantH(alloc); // RINOK(res) } else if(coder->MethodID == k_BZ2) { int bzres = BZ_OK; SRes res = SZ_OK; bz_stream bzstrm; bzstrm.bzalloc = BzAlloc; bzstrm.bzfree = BzFree; bzstrm.opaque = NULL; void *inBuffer = NULL; size_t size = inSize; bzres = BZ2_bzDecompressInit(&bzstrm,0,0); if(bzres == BZ_OK) res = SZ_OK; else res=SZ_ERROR_MEM; RINOK(res) bzstrm.next_out = outBufCur; bzstrm.avail_out = outSizeCur; do { size=inSize; RINOK(inStream->Read(inStream, (void **)&inBuffer, &size)); inSize -= size; bzstrm.next_in = (char *)(inBuffer); bzstrm.avail_in = size; do { bzres = BZ2_bzDecompress(&bzstrm); }while(bzstrm.avail_in>0 && bzres==BZ_OK); }while (bzres==BZ_OK); BZ2_bzDecompressEnd(&bzstrm); switch(bzres) { case BZ_CONFIG_ERROR: case BZ_PARAM_ERROR: res=SZ_ERROR_FAIL; break; case BZ_MEM_ERROR: case BZ_OUTBUFF_FULL: res=SZ_ERROR_MEM; break; case BZ_DATA_ERROR_MAGIC: case BZ_UNEXPECTED_EOF: res=SZ_ERROR_DATA; break; case BZ_DATA_ERROR: res=SZ_ERROR_CRC; break; case BZ_OK: res=SZ_OK; break; default: res=SZ_OK; break; } RINOK(res) } else {