static SRes SzReadArchiveProperties(CSzData *sd) { for (;;) { uint64_t type; RINOK(SzReadID(sd, &type)); if (type == k7zIdEnd) break; SzSkeepData(sd); } return SZ_OK; }
static SRes SzWaitAttribute(CSzData *sd, uint64_t attribute) { for (;;) { uint64_t type; RINOK(SzReadID(sd, &type)); if (type == attribute) return SZ_OK; if (type == k7zIdEnd) return SZ_ERROR_ARCHIVE; RINOK(SzSkeepData(sd)); } }
static SRes SzReadPackInfo( CSzData *sd, uint64_t *dataOffset, uint32_t *numPackStreams, uint64_t **packSizes, uint8_t **packCRCsDefined, uint32_t **packCRCs, ISzAlloc *alloc) { uint32_t i; RINOK(SzReadNumber(sd, dataOffset)); RINOK(SzReadNumber32(sd, numPackStreams)); RINOK(SzWaitAttribute(sd, k7zIdSize)); MY_ALLOC(uint64_t, *packSizes, (size_t)*numPackStreams, alloc); for (i = 0; i < *numPackStreams; i++) { RINOK(SzReadNumber(sd, (*packSizes) + i)); } for (;;) { uint64_t type; RINOK(SzReadID(sd, &type)); if (type == k7zIdEnd) break; if (type == k7zIdCRC) { RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, alloc)); continue; } RINOK(SzSkeepData(sd)); } if (*packCRCsDefined == 0) { MY_ALLOC(uint8_t, *packCRCsDefined, (size_t)*numPackStreams, alloc); MY_ALLOC(uint32_t, *packCRCs, (size_t)*numPackStreams, alloc); for (i = 0; i < *numPackStreams; i++) { (*packCRCsDefined)[i] = 0; (*packCRCs)[i] = 0; } } return SZ_OK; }
static SRes SzReadStreamsInfo( CSzData *sd, uint64_t *dataOffset, CSzAr *p, uint32_t *numUnpackStreams, uint64_t **unpackSizes, /* allocTemp */ uint8_t **digestsDefined, /* allocTemp */ uint32_t **digests, /* allocTemp */ ISzAlloc *alloc, ISzAlloc *allocTemp) { for (;;) { uint64_t type; RINOK(SzReadID(sd, &type)); if ((uint64_t)(int)type != type) return SZ_ERROR_UNSUPPORTED; switch((int)type) { case k7zIdEnd: return SZ_OK; case k7zIdPackInfo: { RINOK(SzReadPackInfo(sd, dataOffset, &p->NumPackStreams, &p->PackSizes, &p->PackCRCsDefined, &p->PackCRCs, alloc)); break; } case k7zIdUnpackInfo: { RINOK(SzReadUnpackInfo(sd, &p->NumFolders, &p->Folders, alloc, allocTemp)); break; } case k7zIdSubStreamsInfo: { RINOK(SzReadSubStreamsInfo(sd, p->NumFolders, p->Folders, numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp)); break; } default: return SZ_ERROR_UNSUPPORTED; } } }
static SRes SzReadHeader2( CSzArEx *p, /* allocMain */ CSzData *sd, uint64_t **unpackSizes, /* allocTemp */ uint8_t **digestsDefined, /* allocTemp */ uint32_t **digests, /* allocTemp */ uint8_t **emptyStreamVector, /* allocTemp */ uint8_t **emptyFileVector, /* allocTemp */ uint8_t **lwtVector, /* allocTemp */ ISzAlloc *allocMain, ISzAlloc *allocTemp) { uint64_t type; uint32_t numUnpackStreams = 0; uint32_t numFiles = 0; CSzFileItem *files = 0; uint32_t numEmptyStreams = 0; uint32_t i; RINOK(SzReadID(sd, &type)); if (type == k7zIdArchiveProperties) { RINOK(SzReadArchiveProperties(sd)); RINOK(SzReadID(sd, &type)); } if (type == k7zIdMainStreamsInfo) { RINOK(SzReadStreamsInfo(sd, &p->dataPos, &p->db, &numUnpackStreams, unpackSizes, digestsDefined, digests, allocMain, allocTemp)); p->dataPos += p->startPosAfterHeader; RINOK(SzReadID(sd, &type)); } if (type == k7zIdEnd) return SZ_OK; if (type != k7zIdFilesInfo) return SZ_ERROR_ARCHIVE; RINOK(SzReadNumber32(sd, &numFiles)); p->db.NumFiles = numFiles; MY_ALLOC(CSzFileItem, files, (size_t)numFiles, allocMain); p->db.Files = files; for (i = 0; i < numFiles; i++) SzFile_Init(files + i); for (;;) { uint64_t size; RINOK(SzReadID(sd, &type)); if (type == k7zIdEnd) break; RINOK(SzReadNumber(sd, &size)); if (size > sd->Size) return SZ_ERROR_ARCHIVE; if ((uint64_t)(int)type != type) { RINOK(SzSkeepDataSize(sd, size)); } else switch((int)type) { case k7zIdName: { size_t namesSize; RINOK(SzReadSwitch(sd)); namesSize = (size_t)size - 1; if ((namesSize & 1) != 0) return SZ_ERROR_ARCHIVE; if (!Buf_Create(&p->FileNames, namesSize, allocMain)) return SZ_ERROR_MEM; MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); memcpy(p->FileNames.data, sd->Data, namesSize); RINOK(SzReadFileNames(sd->Data, namesSize >> 1, numFiles, p->FileNameOffsets)) RINOK(SzSkeepDataSize(sd, namesSize)); break; } case k7zIdEmptyStream: { RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp)); numEmptyStreams = 0; for (i = 0; i < numFiles; i++) if ((*emptyStreamVector)[i]) numEmptyStreams++; break; } case k7zIdEmptyFile: { RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp)); break; } case k7zIdWinAttributes: { RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); RINOK(SzReadSwitch(sd)); for (i = 0; i < numFiles; i++) { CSzFileItem *f = &files[i]; uint8_t defined = (*lwtVector)[i]; f->AttribDefined = defined; f->Attrib = 0; if (defined) { RINOK(SzReaduint32_t(sd, &f->Attrib)); } } IAlloc_Free(allocTemp, *lwtVector); *lwtVector = NULL; break; } case k7zIdMTime: { RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); RINOK(SzReadSwitch(sd)); for (i = 0; i < numFiles; i++) { CSzFileItem *f = &files[i]; uint8_t defined = (*lwtVector)[i]; f->MTimeDefined = defined; f->MTime.Low = f->MTime.High = 0; if (defined) { RINOK(SzReaduint32_t(sd, &f->MTime.Low)); RINOK(SzReaduint32_t(sd, &f->MTime.High)); } } IAlloc_Free(allocTemp, *lwtVector); *lwtVector = NULL; break; } default: { RINOK(SzSkeepDataSize(sd, size)); } } } { uint32_t emptyFileIndex = 0; uint32_t sizeIndex = 0; for (i = 0; i < numFiles; i++) { CSzFileItem *file = files + i; file->IsAnti = 0; if (*emptyStreamVector == 0) file->HasStream = 1; else file->HasStream = (uint8_t)((*emptyStreamVector)[i] ? 0 : 1); if (file->HasStream) { file->IsDir = 0; file->Size = (*unpackSizes)[sizeIndex]; file->Crc = (*digests)[sizeIndex]; file->CrcDefined = (uint8_t)(*digestsDefined)[sizeIndex]; sizeIndex++; } else { if (*emptyFileVector == 0) file->IsDir = 1; else file->IsDir = (uint8_t)((*emptyFileVector)[emptyFileIndex] ? 0 : 1); emptyFileIndex++; file->Size = 0; file->Crc = 0; file->CrcDefined = 0; } } } return SzArEx_Fill(p, allocMain); }
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)); } }
static SRes SzReadUnpackInfo( CSzData *sd, uint32_t *numFolders, CSzFolder **folders, /* for alloc */ ISzAlloc *alloc, ISzAlloc *allocTemp) { uint32_t i; RINOK(SzWaitAttribute(sd, k7zIdFolder)); RINOK(SzReadNumber32(sd, numFolders)); { RINOK(SzReadSwitch(sd)); MY_ALLOC(CSzFolder, *folders, (size_t)*numFolders, alloc); for (i = 0; i < *numFolders; i++) SzFolder_Init((*folders) + i); for (i = 0; i < *numFolders; i++) { RINOK(SzGetNextFolderItem(sd, (*folders) + i, alloc)); } } RINOK(SzWaitAttribute(sd, k7zIdCodersUnpackSize)); for (i = 0; i < *numFolders; i++) { uint32_t j; CSzFolder *folder = (*folders) + i; uint32_t numOutStreams = SzFolder_GetNumOutStreams(folder); MY_ALLOC(uint64_t, folder->UnpackSizes, (size_t)numOutStreams, alloc); for (j = 0; j < numOutStreams; j++) { RINOK(SzReadNumber(sd, folder->UnpackSizes + j)); } } for (;;) { uint64_t type; RINOK(SzReadID(sd, &type)); if (type == k7zIdEnd) return SZ_OK; if (type == k7zIdCRC) { SRes res; uint8_t *crcsDefined = 0; uint32_t *crcs = 0; res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp); if (res == SZ_OK) { for (i = 0; i < *numFolders; i++) { CSzFolder *folder = (*folders) + i; folder->UnpackCRCDefined = crcsDefined[i]; folder->UnpackCRC = crcs[i]; } } IAlloc_Free(allocTemp, crcs); IAlloc_Free(allocTemp, crcsDefined); RINOK(res); continue; } RINOK(SzSkeepData(sd)); } }
static SRes SzArEx_Open2( CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp) { uint8_t header[k7zStartHeaderSize]; int64_t startArcPos; uint64_t nextHeaderOffset, nextHeaderSize; size_t nextHeaderSizeT; uint32_t nextHeaderCRC; CBuf buffer; SRes res; startArcPos = 0; RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR)); RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); if (!TestSignatureCandidate(header)) return SZ_ERROR_NO_ARCHIVE; if (header[6] != k7zMajorVersion) return SZ_ERROR_UNSUPPORTED; nextHeaderOffset = GetUi64(header + 12); nextHeaderSize = GetUi64(header + 20); nextHeaderCRC = GetUi32(header + 28); p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) return SZ_ERROR_CRC; nextHeaderSizeT = (size_t)nextHeaderSize; if (nextHeaderSizeT != nextHeaderSize) return SZ_ERROR_MEM; if (nextHeaderSizeT == 0) return SZ_OK; if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) return SZ_ERROR_NO_ARCHIVE; { int64_t pos = 0; RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); if ((uint64_t)pos < startArcPos + nextHeaderOffset || (uint64_t)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || (uint64_t)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) return SZ_ERROR_INPUT_EOF; } RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp)) return SZ_ERROR_MEM; res = LookInStream_Read(inStream, buffer.data, nextHeaderSizeT); if (res == SZ_OK) { res = SZ_ERROR_ARCHIVE; if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC) { CSzData sd; uint64_t type; sd.Data = buffer.data; sd.Size = buffer.size; res = SzReadID(&sd, &type); if (res == SZ_OK) { if (type == k7zIdEncodedHeader) { CBuf outBuffer; Buf_Init(&outBuffer); res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, p->startPosAfterHeader, allocTemp); if (res != SZ_OK) Buf_Free(&outBuffer, allocTemp); else { Buf_Free(&buffer, allocTemp); buffer.data = outBuffer.data; buffer.size = outBuffer.size; sd.Data = buffer.data; sd.Size = buffer.size; res = SzReadID(&sd, &type); } } } if (res == SZ_OK) { if (type == k7zIdHeader) res = SzReadHeader(p, &sd, allocMain, allocTemp); else res = SZ_ERROR_UNSUPPORTED; } } } Buf_Free(&buffer, allocTemp); return res; }
static SRes SzArEx_Open2( CSzArEx *p, ISeekInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp) { Byte header[k7zStartHeaderSize]; Int64 startArcPos; UInt64 nextHeaderOffset, nextHeaderSize; size_t nextHeaderSizeT; UInt32 nextHeaderCRC; CBuf buffer; SRes res; size_t readSize; startArcPos = 0; RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR)); readSize = k7zStartHeaderSize; res = inStream->Read(inStream, header, &readSize); if(res != SZ_OK) return SZ_ERROR_NO_ARCHIVE; if (!TestSignatureCandidate(header)) return SZ_ERROR_NO_ARCHIVE; if (header[6] != k7zMajorVersion) return SZ_ERROR_UNSUPPORTED; nextHeaderOffset = GetUi64(header + 12); nextHeaderSize = GetUi64(header + 20); nextHeaderCRC = GetUi32(header + 28); p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) return SZ_ERROR_CRC; nextHeaderSizeT = (size_t)nextHeaderSize; if (nextHeaderSizeT != nextHeaderSize) return SZ_ERROR_MEM; if (nextHeaderSizeT == 0) return SZ_OK; if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) return SZ_ERROR_NO_ARCHIVE; { Int64 pos = 0; RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); if ((UInt64)pos < startArcPos + nextHeaderOffset || (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) return SZ_ERROR_INPUT_EOF; pos = startArcPos + k7zStartHeaderSize + nextHeaderOffset; RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_SET)); } if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp)) return SZ_ERROR_MEM; readSize = nextHeaderSizeT; res = inStream->Read(inStream, buffer.data, &readSize); if (res == SZ_OK) { res = SZ_ERROR_ARCHIVE; if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC) { CSzData sd; UInt64 type; sd.Data = buffer.data; sd.Size = buffer.size; res = SzReadID(&sd, &type); if (res == SZ_OK) { if (type == k7zIdEncodedHeader) { CMemOutStream outStream; MemOutStream_Init(&outStream); res = SzReadAndDecodePackedStreams(inStream, &sd, &outStream.s, p->startPosAfterHeader, allocTemp); if (res != SZ_OK) Buf_Free((CBuf*)&outStream.data, allocTemp); else { Buf_Free(&buffer, allocTemp); buffer.data = outStream.data; buffer.size = outStream.size; sd.Data = buffer.data; sd.Size = buffer.size; res = SzReadID(&sd, &type); } } } if (res == SZ_OK) { if (type == k7zIdHeader) res = SzReadHeader(p, &sd, allocMain, allocTemp); else res = SZ_ERROR_UNSUPPORTED; } } } Buf_Free(&buffer, allocTemp); return res; }