/// <summary> /// Create a new VolumeHeader from a Stream and version /// </summary> public static VolumeHeader Create(Stream stream, int version) { var header = new VolumeHeader(); if (version <= 5) { if (stream.Length - stream.Position < Constants.VOLUME_HEADER_SIZE_V5) { return(null); } header.DataOffset = stream.ReadUInt32(); stream.Seek(4, SeekOrigin.Current); header.FirstFileIndex = stream.ReadUInt32(); header.LastFileIndex = stream.ReadUInt32(); header.FirstFileOffset = stream.ReadUInt32(); header.FirstFileSizeExpanded = stream.ReadUInt32(); header.FirstFileSizeCompressed = stream.ReadUInt32(); header.LastFileOffset = stream.ReadUInt32(); header.LastFileSizeExpanded = stream.ReadUInt32(); header.LastFileSizeCompressed = stream.ReadUInt32(); if (header.LastFileOffset == 0) { header.LastFileOffset = int.MaxValue; } } else { if (stream.Length - stream.Position < Constants.VOLUME_HEADER_SIZE_V6) { return(null); } header.DataOffset = stream.ReadUInt32(); header.DataOffsetHigh = stream.ReadUInt32(); header.FirstFileIndex = stream.ReadUInt32(); header.LastFileIndex = stream.ReadUInt32(); header.FirstFileOffset = stream.ReadUInt32(); header.FirstFileOffsetHigh = stream.ReadUInt32(); header.FirstFileSizeExpanded = stream.ReadUInt32(); header.FirstFileSizeExpandedHigh = stream.ReadUInt32(); header.FirstFileSizeCompressed = stream.ReadUInt32(); header.FirstFileSizeCompressedHigh = stream.ReadUInt32(); header.LastFileOffset = stream.ReadUInt32(); header.LastFileOffsetHigh = stream.ReadUInt32(); header.LastFileSizeExpanded = stream.ReadUInt32(); header.LastFileSizeExpandedHigh = stream.ReadUInt32(); header.LastFileSizeCompressed = stream.ReadUInt32(); header.LastFileSizeCompressedHigh = stream.ReadUInt32(); } return(header); }
/// <summary> /// Open the volume at the inputted index /// </summary> public bool OpenVolume(int volume) { this.VolumeFile?.Close(); this.VolumeFile = this.Cabinet.OpenFileForReading(volume, Constants.CABINET_SUFFIX); if (this.VolumeFile == null) { Console.Error.WriteLine($"Failed to open input cabinet file {volume}"); return(false); } var commonHeader = CommonHeader.Create(this.VolumeFile); if (commonHeader == default) { return(false); } this.VolumeHeader = VolumeHeader.Create(this.VolumeFile, this.Cabinet.HeaderList.MajorVersion); if (this.VolumeHeader == null) { return(false); } // enable support for split archives for IS5 if (this.Cabinet.HeaderList.MajorVersion == 5) { if (this.Index < (this.Cabinet.HeaderList.Descriptor.FileCount - 1) && this.Index == this.VolumeHeader.LastFileIndex && this.VolumeHeader.LastFileSizeCompressed != this.FileDescriptor.CompressedSize) { this.FileDescriptor.Flags |= FileDescriptorFlag.FILE_SPLIT; } else if (this.Index > 0 && this.Index == this.VolumeHeader.FirstFileIndex && this.VolumeHeader.FirstFileSizeCompressed != this.FileDescriptor.CompressedSize) { this.FileDescriptor.Flags |= FileDescriptorFlag.FILE_SPLIT; } } ulong dataOffset, volumeBytesLeftCompressed, volumeBytesLeftExpanded; if (this.FileDescriptor.Flags.HasFlag(FileDescriptorFlag.FILE_SPLIT)) { if (this.Index == this.VolumeHeader.LastFileIndex && this.VolumeHeader.LastFileOffset != 0x7FFFFFFF) { // can be first file too dataOffset = this.VolumeHeader.LastFileOffset; volumeBytesLeftExpanded = this.VolumeHeader.LastFileSizeExpanded; volumeBytesLeftCompressed = this.VolumeHeader.LastFileSizeCompressed; } else if (this.Index == this.VolumeHeader.FirstFileIndex) { dataOffset = this.VolumeHeader.FirstFileOffset; volumeBytesLeftExpanded = this.VolumeHeader.FirstFileSizeExpanded; volumeBytesLeftCompressed = this.VolumeHeader.FirstFileSizeCompressed; } else { return(true); } } else { dataOffset = this.FileDescriptor.DataOffset; volumeBytesLeftExpanded = this.FileDescriptor.ExpandedSize; volumeBytesLeftCompressed = this.FileDescriptor.CompressedSize; } if (this.FileDescriptor.Flags.HasFlag(FileDescriptorFlag.FILE_COMPRESSED)) { this.VolumeBytesLeft = volumeBytesLeftCompressed; } else { this.VolumeBytesLeft = volumeBytesLeftExpanded; } this.VolumeFile.Seek((long)dataOffset, SeekOrigin.Begin); this.Volume = volume; return(true); }