Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        /// <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);
        }