SRes SzArEx_Extract( const CSzArEx *p, ISeekInStream *inStream, const UInt16 *outputDir, ICompressProgress *progress, ISzAlloc *allocTemp) { UInt32 blockIndex = 0xffffffff; UInt64 totalUnpackSize = 0; UInt32 i; SRes res = SZ_OK; for (i = 0; i < p->db.NumFolders; i++) { CSzFolder *folder = p->db.Folders + i; UInt64 unpackSize = SzFolder_GetUnpackSize(folder); totalUnpackSize += unpackSize; } if(progress != NULL) CompressCallback_Init((CCompressCallback*)progress,totalUnpackSize); for (i = 0; i < p->db.NumFiles; i++) { UInt32 folderIndex = p->FileIndexToFolderIndexMap[i]; if (folderIndex == (UInt32)-1) { blockIndex = folderIndex; continue; } if(folderIndex != blockIndex) { CSzFolder *folder = p->db.Folders + folderIndex; UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder); size_t unpackSize = (size_t)unpackSizeSpec; UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0); CFolderOutStream outStream; FolderOutStream_Init(&outStream,p,folderIndex,outputDir); if (unpackSize != unpackSizeSpec) return SZ_ERROR_MEM; blockIndex = folderIndex; res = SzFolder_Decode(folder, p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex], inStream, startOffset, &outStream.s, unpackSize, progress, allocTemp); File_Close(&outStream.file); if(res != SZ_OK) break; } } return res; }
void FolderOutStream_Init(CFolderOutStream *p, const CSzArEx* ar, UInt32 folderIndex, const UInt16* outputDir) { p->s.Write = FolderOutStream_Write; p->ar = ar; p->startIndex = ar->FolderStartFileIndex[folderIndex]; p->currentIndex = 0; p->folderSize = SzFolder_GetUnpackSize(ar->db.Folders + folderIndex); p->fileSize = 0; p->crc = CRC_INIT_VAL; p->checkCrc = False; p->outputDir = outputDir; p->bufPos = 0; File_Construct(&p->file); }
static SRes SzReadAndDecodePackedStreams2( ISeekInStream *inStream, CSzData *sd, ISeqOutStream *outStream, UInt64 baseOffset, CSzAr *p, UInt64 **unpackSizes, Byte **digestsDefined, UInt32 **digests, ISzAlloc *allocTemp) { CMemOutStream* memStream; UInt32 numUnpackStreams = 0; UInt64 dataStartPos; CSzFolder *folder; UInt64 unpackSize; SRes res; Int64 offset; RINOK(SzReadStreamsInfo(sd, &dataStartPos, p, &numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp, allocTemp)); dataStartPos += baseOffset; if (p->NumFolders != 1) return SZ_ERROR_ARCHIVE; folder = p->Folders; unpackSize = SzFolder_GetUnpackSize(folder); offset = (Int64)dataStartPos; RINOK(inStream->Seek(inStream, &offset, SZ_SEEK_SET)); memStream = (CMemOutStream*)outStream; if (!Buf_Create((CBuf*)&memStream->data, (size_t)unpackSize, allocTemp)) return SZ_ERROR_MEM; res = SzFolder_Decode(folder, p->PackSizes, inStream, dataStartPos, outStream, (size_t)unpackSize, NULL, allocTemp); RINOK(res); if (folder->UnpackCRCDefined) if (CrcCalc(memStream->data, (size_t)unpackSize) != folder->UnpackCRC) return SZ_ERROR_CRC; return SZ_OK; }
static SRes SzReadAndDecodePackedStreams2( ILookInStream *inStream, CSzData *sd, CBuf *outBuffer, UInt64 baseOffset, CSzAr *p, UInt64 **unpackSizes, Byte **digestsDefined, UInt32 **digests, ISzAlloc *allocTemp) { UInt32 numUnpackStreams = 0; UInt64 dataStartPos; CSzFolder *folder; UInt64 unpackSize; SRes res; RINOK(SzReadStreamsInfo(sd, &dataStartPos, p, &numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp, allocTemp)); dataStartPos += baseOffset; if (p->NumFolders != 1) return SZ_ERROR_ARCHIVE; folder = p->Folders; unpackSize = SzFolder_GetUnpackSize(folder); RINOK(LookInStream_SeekTo(inStream, dataStartPos)); if (!Buf_Create(outBuffer, (size_t)unpackSize, allocTemp)) return SZ_ERROR_MEM; res = SzFolder_Decode(folder, p->PackSizes, inStream, dataStartPos, outBuffer->data, (size_t)unpackSize, allocTemp); RINOK(res); #ifdef _7ZIP_CRC_SUPPORT if (folder->UnpackCRCDefined) if (CrcCalc(outBuffer->data, (size_t)unpackSize) != folder->UnpackCRC) return SZ_ERROR_CRC; #endif return SZ_OK; }
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; }
CArchive7Zip::CArchive7Zip(const std::string& name) : CArchiveBase(name), isOpen(false) { blockIndex = 0xFFFFFFFF; outBuffer = NULL; outBufferSize = 0; allocImp.Alloc = SzAlloc; allocImp.Free = SzFree; allocTempImp.Alloc = SzAllocTemp; allocTempImp.Free = SzFreeTemp; SzArEx_Init(&db); WRes wres = InFile_Open(&archiveStream.file, name.c_str()); if (wres) { boost::system::error_code e(wres, boost::system::get_system_category()); LogObject() << "Error opening " << name << ": " << e.message() << " (" << e.value() << ")"; return; } FileInStream_CreateVTable(&archiveStream); LookToRead_CreateVTable(&lookStream, False); lookStream.realStream = &archiveStream.s; LookToRead_Init(&lookStream); CrcGenerateTable(); SRes res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp); if (res == SZ_OK) { isOpen = true; } else { isOpen = false; std::string error; switch (res) { case SZ_ERROR_FAIL: error = "Extracting failed"; break; case SZ_ERROR_CRC: error = "CRC error (archive corrupted?)"; break; case SZ_ERROR_INPUT_EOF: error = "Unexpected end of file (truncated?)"; break; case SZ_ERROR_MEM: error = "Out of memory"; break; case SZ_ERROR_UNSUPPORTED: error = "Unsupported archive"; break; case SZ_ERROR_NO_ARCHIVE: error = "Archive not found"; break; default: error = "Unknown error"; break; } LogObject() << "Error opening " << name << ": " << error; return; } // In 7zip talk, folders are pack-units (solid blocks), // not related to file-system folders. UInt64* folderUnpackSizes = new UInt64[db.db.NumFolders]; for (int fi = 0; fi < db.db.NumFolders; fi++) { folderUnpackSizes[fi] = SzFolder_GetUnpackSize(db.db.Folders + fi); } // Get contents of archive and store name->int mapping for (unsigned i = 0; i < db.db.NumFiles; ++i) { CSzFileItem* f = db.db.Files + i; if ((f->Size >= 0) && !f->IsDir) { std::string fileName = f->Name; FileData fd; fd.origName = fileName; fd.fp = i; fd.size = f->Size; fd.crc = (f->Size > 0) ? f->FileCRC : 0; const UInt32 folderIndex = db.FileIndexToFolderIndexMap[i]; if (folderIndex == ((UInt32)-1)) { // file has no folder assigned fd.unpackedSize = f->Size; fd.packedSize = f->Size; } else { fd.unpackedSize = folderUnpackSizes[folderIndex]; fd.packedSize = db.db.PackSizes[folderIndex]; } StringToLowerInPlace(fileName); fileData.push_back(fd); lcNameIndex[fileName] = fileData.size()-1; } } delete [] folderUnpackSizes; }
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->FileCRCDefined) { 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; }