private List <uint> ReadFileSectorOffsetTable ( [NotNull] BlockTableEntry fileBlockEntry, uint fileKey = 0 ) { var sectorOffsets = new List <uint>(); if (fileBlockEntry.IsEncrypted()) { MPQCrypt.DecryptSectorOffsetTable(_archiveReader, ref sectorOffsets, fileBlockEntry.GetBlockSize(), fileKey - 1); } else { // As protection against corrupt or maliciously zeroed blocks or corrupt blocks, // reading will be escaped early if the sector offset table is not consistent. // Should the total size as predicted by the sector offset table go beyond the total // block size, or if an offset is not unique, no file will be read and the function will // escape early. uint sectorOffset = 0; while (sectorOffset != fileBlockEntry.GetBlockSize()) { sectorOffset = _archiveReader.ReadUInt32(); // Should the resulting sector offset be less than the previous data, then the data is inconsistent // and no table should be returned. if (sectorOffsets.LastOrDefault() > sectorOffset) { throw new InvalidFileSectorTableException( "The read offset in the sector table was less than the previous offset."); } // Should the resulting sector offset be greater than the total block size, then the data is // inconsistent and no file should be returned. if (sectorOffset > fileBlockEntry.GetBlockSize()) { throw new InvalidFileSectorTableException( "The read offset in the sector table was greater than the total size of the data block."); } // Should the resulting sector not be unique, something is wrong and no table should be returned. if (sectorOffsets.Contains(sectorOffset)) { throw new InvalidFileSectorTableException( "The read offset in the sector table was not unique to the whole table."); } // The offset should be valid, so add it to the table. sectorOffsets.Add(sectorOffset); } } return(sectorOffsets); }
/// <summary> /// Extracts a file which is stored as a single unit in the archive. /// </summary> /// <param name="fileBlockEntry">The block entry of the file.</param> /// <param name="fileKey">The encryption key of the file.</param> /// <returns>The complete file data.</returns> private byte[] ExtractSingleUnitFile(BlockTableEntry fileBlockEntry, uint fileKey) { // This file does not use sectoring, but may still be encrypted or compressed. byte[] fileData = this.ArchiveReader.ReadBytes((int)fileBlockEntry.GetBlockSize()); if (fileBlockEntry.IsEncrypted()) { // Decrypt the block fileData = MPQCrypt.DecryptData(fileData, fileKey); } // Decompress the sector if neccesary if (fileBlockEntry.IsCompressed()) { fileData = Compression.DecompressSector(fileData, fileBlockEntry.Flags); } return(fileData); }