private void ReadHeader(CArchiveDatabaseEx db, IPasswordProvider getTextPassword) { Log.WriteLine("-- ReadHeader --"); Log.PushIndent(); try { BlockType? type = ReadId(); if (type == BlockType.ArchiveProperties) { ReadArchiveProperties(); type = ReadId(); } List<byte[]> dataVector = null; if (type == BlockType.AdditionalStreamsInfo) { dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, getTextPassword); type = ReadId(); } List<long> unpackSizes; List<uint?> digests; if (type == BlockType.MainStreamsInfo) { ReadStreamsInfo(dataVector, out db.DataStartPosition, out db.PackSizes, out db.PackCRCs, out db.Folders, out db.NumUnpackStreamsVector, out unpackSizes, out digests); db.DataStartPosition += db.StartPositionAfterHeader; type = ReadId(); } else { unpackSizes = new List<long>(db.Folders.Count); digests = new List<uint?>(db.Folders.Count); db.NumUnpackStreamsVector = new List<int>(db.Folders.Count); for (int i = 0; i < db.Folders.Count; i++) { var folder = db.Folders[i]; unpackSizes.Add(folder.GetUnpackSize()); digests.Add(folder.UnpackCRC); db.NumUnpackStreamsVector.Add(1); } } db.Files.Clear(); if (type == BlockType.End) return; if (type != BlockType.FilesInfo) throw new InvalidDataException(); int numFiles = ReadNum(); Log.WriteLine("NumFiles: " + numFiles); db.Files = new List<CFileItem>(numFiles); for (int i = 0; i < numFiles; i++) db.Files.Add(new CFileItem()); BitVector emptyStreamVector = new BitVector(numFiles); BitVector emptyFileVector = null; BitVector antiFileVector = null; int numEmptyStreams = 0; for (;;) { type = ReadId(); if (type == BlockType.End) break; long size = checked((long)ReadNumber()); // TODO: throw invalid data on negative int oldPos = _currentReader.Offset; switch (type) { case BlockType.Name: using (var streamSwitch = new CStreamSwitch()) { streamSwitch.Set(this, dataVector); Log.Write("FileNames:"); for (int i = 0; i < db.Files.Count; i++) { db.Files[i].Name = _currentReader.ReadString(); Log.Write(" " + db.Files[i].Name); } Log.WriteLine(); } break; case BlockType.WinAttributes: Log.Write("WinAttributes:"); ReadAttributeVector(dataVector, numFiles, delegate (int i, uint? attr) { db.Files[i].Attrib = attr; Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a")); }); Log.WriteLine(); break; case BlockType.EmptyStream: emptyStreamVector = ReadBitVector(numFiles); Log.Write("EmptyStream: "); for (int i = 0; i < emptyStreamVector.Length; i++) { if (emptyStreamVector[i]) { Log.Write("x"); numEmptyStreams++; } else { Log.Write("."); } } Log.WriteLine(); emptyFileVector = new BitVector(numEmptyStreams); antiFileVector = new BitVector(numEmptyStreams); break; case BlockType.EmptyFile: emptyFileVector = ReadBitVector(numEmptyStreams); Log.Write("EmptyFile: "); for (int i = 0; i < numEmptyStreams; i++) Log.Write(emptyFileVector[i] ? "x" : "."); Log.WriteLine(); break; case BlockType.Anti: antiFileVector = ReadBitVector(numEmptyStreams); Log.Write("Anti: "); for (int i = 0; i < numEmptyStreams; i++) Log.Write(antiFileVector[i] ? "x" : "."); Log.WriteLine(); break; case BlockType.StartPos: Log.Write("StartPos:"); ReadNumberVector(dataVector, numFiles, delegate (int i, long? startPos) { db.Files[i].StartPos = startPos; Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a")); }); Log.WriteLine(); break; case BlockType.CTime: Log.Write("CTime:"); ReadDateTimeVector(dataVector, numFiles, delegate (int i, DateTime? time) { db.Files[i].CTime = time; Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); }); Log.WriteLine(); break; case BlockType.ATime: Log.Write("ATime:"); ReadDateTimeVector(dataVector, numFiles, delegate (int i, DateTime? time) { db.Files[i].ATime = time; Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); }); Log.WriteLine(); break; case BlockType.MTime: Log.Write("MTime:"); ReadDateTimeVector(dataVector, numFiles, delegate (int i, DateTime? time) { db.Files[i].MTime = time; Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); }); Log.WriteLine(); break; case BlockType.Dummy: Log.Write("Dummy: " + size); for (long j = 0; j < size; j++) if (ReadByte() != 0) throw new InvalidDataException(); break; default: SkipData(size); break; } // since 0.3 record sizes must be correct bool checkRecordsSize = (db.MajorVersion > 0 || db.MinorVersion > 2); if (checkRecordsSize && _currentReader.Offset - oldPos != size) throw new InvalidDataException(); } int emptyFileIndex = 0; int sizeIndex = 0; for (int i = 0; i < numFiles; i++) { CFileItem file = db.Files[i]; file.HasStream = !emptyStreamVector[i]; if (file.HasStream) { file.IsDir = false; file.IsAnti = false; file.Size = unpackSizes[sizeIndex]; file.Crc = digests[sizeIndex]; sizeIndex++; } else { file.IsDir = !emptyFileVector[emptyFileIndex]; file.IsAnti = antiFileVector[emptyFileIndex]; emptyFileIndex++; file.Size = 0; file.Crc = null; } } } finally { Log.PopIndent(); } }
public void ReadDatabase(CArchiveDatabaseEx db, IPasswordProvider pass) { db.Clear(); db.MajorVersion = _header[6]; db.MinorVersion = _header[7]; if (db.MajorVersion != 0) throw new InvalidDataException(); uint crcFromArchive = DataReader.Get32(_header, 8); long nextHeaderOffset = (long)DataReader.Get64(_header, 0xC); long nextHeaderSize = (long)DataReader.Get64(_header, 0x14); uint nextHeaderCrc = DataReader.Get32(_header, 0x1C); uint crc = CRC.kInitCRC; crc = CRC.Update(crc, nextHeaderOffset); crc = CRC.Update(crc, nextHeaderSize); crc = CRC.Update(crc, nextHeaderCrc); crc = CRC.Finish(crc); if (crc != crcFromArchive) throw new InvalidDataException(); db.StartPositionAfterHeader = _streamOrigin + 0x20; // empty header is ok if (nextHeaderSize == 0) return; if (nextHeaderOffset < 0 || nextHeaderSize < 0 || nextHeaderSize > Int32.MaxValue) throw new InvalidDataException(); if (nextHeaderOffset > _streamEnding - db.StartPositionAfterHeader) throw new InvalidDataException(); _stream.Seek(nextHeaderOffset, SeekOrigin.Current); byte[] header = new byte[nextHeaderSize]; _stream.ReadExact(header, 0, header.Length); if (CRC.Finish(CRC.Update(CRC.kInitCRC, header, 0, header.Length)) != nextHeaderCrc) throw new InvalidDataException(); using (CStreamSwitch streamSwitch = new CStreamSwitch()) { streamSwitch.Set(this, header); BlockType? type = ReadId(); if (type != BlockType.Header) { if (type != BlockType.EncodedHeader) throw new InvalidDataException(); var dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, pass); // compressed header without content is odd but ok if (dataVector.Count == 0) return; if (dataVector.Count != 1) throw new InvalidDataException(); streamSwitch.Set(this, dataVector[0]); if (ReadId() != BlockType.Header) throw new InvalidDataException(); } ReadHeader(db, pass); } }
private Stream GetCachedDecoderStream(CArchiveDatabaseEx _db, int folderIndex, IPasswordProvider pw) { Stream s; if (!_cachedStreams.TryGetValue(folderIndex, out s)) { CFolder folderInfo = _db.Folders[folderIndex]; int packStreamIndex = _db.Folders[folderIndex].FirstPackStreamId; long folderStartPackPos = _db.GetFolderStreamPos(folderIndex, 0); List<long> packSizes = new List<long>(); for (int j = 0; j < folderInfo.PackStreams.Count; j++) packSizes.Add(_db.PackSizes[packStreamIndex + j]); s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(), folderInfo, pw); if (!s.CanSeek) s = new ManagedLzma._7zip.Decoder.FileBufferedDecoderStream(s); _cachedStreams.Add(folderIndex, s); } return s; }
public Stream OpenStream(CArchiveDatabaseEx _db, int fileIndex, IPasswordProvider pw) { int folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; int numFilesInFolder = _db.NumUnpackStreamsVector[folderIndex]; int firstFileIndex = _db.FolderStartFileIndex[folderIndex]; if (firstFileIndex > fileIndex || fileIndex - firstFileIndex >= numFilesInFolder) throw new InvalidOperationException(); int skipCount = fileIndex - firstFileIndex; long skipSize = 0; for (int i = 0; i < skipCount; i++) skipSize += _db.Files[firstFileIndex + i].Size; Stream s = GetCachedDecoderStream(_db, folderIndex, pw); s.Position = skipSize; return new master._7zip.Utilities.UnpackSubStream(s, _db.Files[fileIndex].Size); }
public IEnumerable<CFileItem> GetFiles(CArchiveDatabaseEx db) { return db.Files; }
public int GetFileIndex(CArchiveDatabaseEx db, CFileItem item) { return db.Files.IndexOf(item); }
public FolderUnpackStream(CArchiveDatabaseEx db, int p, int startIndex, List<bool> list) { this._db = db; this._otherIndex = p; this._startIndex = startIndex; this._extractStatuses = list; }
public void Extract(CArchiveDatabaseEx _db, int[] indices, IPasswordProvider pw) { int numItems; bool allFilesMode = (indices == null); if (allFilesMode) numItems = _db.Files.Count; else numItems = indices.Length; if (numItems == 0) return; List<CExtractFolderInfo> extractFolderInfoVector = new List<CExtractFolderInfo>(); for (int i = 0; i < numItems; i++) { int fileIndex = allFilesMode ? i : indices[i]; int folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; if (folderIndex == -1) { extractFolderInfoVector.Add(new CExtractFolderInfo(fileIndex, -1)); continue; } if (extractFolderInfoVector.Count == 0 || folderIndex != extractFolderInfoVector.Last().FolderIndex) extractFolderInfoVector.Add(new CExtractFolderInfo(-1, folderIndex)); CExtractFolderInfo efi = extractFolderInfoVector.Last(); int startIndex = _db.FolderStartFileIndex[folderIndex]; for (int index = efi.ExtractStatuses.Count; index <= fileIndex - startIndex; index++) efi.ExtractStatuses.Add(index == fileIndex - startIndex); } foreach (CExtractFolderInfo efi in extractFolderInfoVector) { int startIndex; if (efi.FileIndex != -1) startIndex = efi.FileIndex; else startIndex = _db.FolderStartFileIndex[efi.FolderIndex]; var outStream = new FolderUnpackStream(_db, 0, startIndex, efi.ExtractStatuses); if (efi.FileIndex != -1) continue; int folderIndex = efi.FolderIndex; CFolder folderInfo = _db.Folders[folderIndex]; int packStreamIndex = _db.Folders[folderIndex].FirstPackStreamId; long folderStartPackPos = _db.GetFolderStreamPos(folderIndex, 0); List<long> packSizes = new List<long>(); for (int j = 0; j < folderInfo.PackStreams.Count; j++) packSizes.Add(_db.PackSizes[packStreamIndex + j]); // TODO: If the decoding fails the last file may be extracted incompletely. Delete it? Stream s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(), folderInfo, pw); byte[] buffer = new byte[4 << 10]; for (;;) { int processed = s.Read(buffer, 0, buffer.Length); if (processed == 0) break; outStream.Write(buffer, 0, processed); } } }