static int Buf_EnsureSize(CBuf *dest, size_t size) { if (dest->size >= size) return 1; Buf_Free(dest, &g_Alloc); return Buf_Create(dest, size, &g_Alloc); }
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 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 SzGetNextFolderItem(CSzData *sd, CSzFolder *folder, ISzAlloc *alloc) { uint32_t numCoders, numBindPairs, numPackStreams, i; uint32_t numInStreams = 0, numOutStreams = 0; RINOK(SzReadNumber32(sd, &numCoders)); if (numCoders > NUM_FOLDER_CODERS_MAX) return SZ_ERROR_UNSUPPORTED; folder->NumCoders = numCoders; MY_ALLOC(CSzCoderInfo, folder->Coders, (size_t)numCoders, alloc); for (i = 0; i < numCoders; i++) SzCoderInfo_Init(folder->Coders + i); for (i = 0; i < numCoders; i++) { uint8_t mainuint8_t; CSzCoderInfo *coder = folder->Coders + i; { unsigned idSize, j; uint8_t longID[15]; RINOK(SzReaduint8_t(sd, &mainuint8_t)); idSize = (unsigned)(mainuint8_t & 0xF); RINOK(SzReaduint8_ts(sd, longID, idSize)); if (idSize > sizeof(coder->MethodID)) return SZ_ERROR_UNSUPPORTED; coder->MethodID = 0; for (j = 0; j < idSize; j++) coder->MethodID |= (uint64_t)longID[idSize - 1 - j] << (8 * j); if ((mainuint8_t & 0x10) != 0) { RINOK(SzReadNumber32(sd, &coder->NumInStreams)); RINOK(SzReadNumber32(sd, &coder->NumOutStreams)); if (coder->NumInStreams > NUM_CODER_STREAMS_MAX || coder->NumOutStreams > NUM_CODER_STREAMS_MAX) return SZ_ERROR_UNSUPPORTED; } else { coder->NumInStreams = 1; coder->NumOutStreams = 1; } if ((mainuint8_t & 0x20) != 0) { uint64_t propertiesSize = 0; RINOK(SzReadNumber(sd, &propertiesSize)); if (!Buf_Create(&coder->Props, (size_t)propertiesSize, alloc)) return SZ_ERROR_MEM; RINOK(SzReaduint8_ts(sd, coder->Props.data, (size_t)propertiesSize)); } } while ((mainuint8_t & 0x80) != 0) { RINOK(SzReaduint8_t(sd, &mainuint8_t)); RINOK(SzSkeepDataSize(sd, (mainuint8_t & 0xF))); if ((mainuint8_t & 0x10) != 0) { uint32_t n; RINOK(SzReadNumber32(sd, &n)); RINOK(SzReadNumber32(sd, &n)); } if ((mainuint8_t & 0x20) != 0) { uint64_t propertiesSize = 0; RINOK(SzReadNumber(sd, &propertiesSize)); RINOK(SzSkeepDataSize(sd, propertiesSize)); } } numInStreams += coder->NumInStreams; numOutStreams += coder->NumOutStreams; } if (numOutStreams == 0) return SZ_ERROR_UNSUPPORTED; folder->NumBindPairs = numBindPairs = numOutStreams - 1; MY_ALLOC(CSzBindPair, folder->BindPairs, (size_t)numBindPairs, alloc); for (i = 0; i < numBindPairs; i++) { CSzBindPair *bp = folder->BindPairs + i; RINOK(SzReadNumber32(sd, &bp->InIndex)); RINOK(SzReadNumber32(sd, &bp->OutIndex)); } if (numInStreams < numBindPairs) return SZ_ERROR_UNSUPPORTED; folder->NumPackStreams = numPackStreams = numInStreams - numBindPairs; MY_ALLOC(uint32_t, folder->PackStreams, (size_t)numPackStreams, alloc); if (numPackStreams == 1) { for (i = 0; i < numInStreams ; i++) if (SzFolder_FindBindPairForInStream(folder, i) < 0) break; if (i == numInStreams) return SZ_ERROR_UNSUPPORTED; folder->PackStreams[0] = i; } else for (i = 0; i < numPackStreams; i++) { RINOK(SzReadNumber32(sd, folder->PackStreams + i)); } return SZ_OK; }
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; }