Beispiel #1
0
 public HashTable([JetBrains.Annotations.NotNull] byte[] data)
 {
     using var ms = new MemoryStream(data);
     using var br = new BinaryReader(ms);
     for (long i = 0; i < data.Length; i += HashTableEntry.GetSize())
     {
         var entryBytes = br.ReadBytes((int)HashTableEntry.GetSize());
         var newEntry   = new HashTableEntry(entryBytes);
         _entries.Add(newEntry);
     }
 }
Beispiel #2
0
        public bool TryFindEntry([NotNull] string fileName, out HashTableEntry tableEntry)
        {
            var entryHomeIndex = MPQCrypt.Hash(fileName, HashType.FileHashTableOffset) & (uint)_entries.Count - 1;
            var hashA          = MPQCrypt.Hash(fileName, HashType.FilePathA);
            var hashB          = MPQCrypt.Hash(fileName, HashType.FilePathB);

            if (!TryFindEntry(hashA, hashB, entryHomeIndex, out tableEntry))
            {
                return(false);
            }

            return(true);
        }
Beispiel #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="HashTable"/> class from
 /// a block of data containing hash table entries.
 /// </summary>
 /// <param name="data">Data.</param>
 public HashTable(byte[] data)
 {
     using (MemoryStream ms = new MemoryStream(data))
     {
         using (BinaryReader br = new BinaryReader(ms))
         {
             for (long i = 0; i < data.Length; i += HashTableEntry.GetSize())
             {
                 byte[]         entryBytes = br.ReadBytes((int)HashTableEntry.GetSize());
                 HashTableEntry newEntry   = new HashTableEntry(entryBytes);
                 this.Entries.Add(newEntry);
             }
         }
     }
 }
Beispiel #4
0
 public ulong GetSize()
 {
     return((ulong)(_entries.Count * HashTableEntry.GetSize()));
 }
Beispiel #5
0
        public bool TryFindEntry
        (
            uint hashA,
            uint hashB,
            uint entryHomeIndex,
            out HashTableEntry tableEntry
        )
        {
            tableEntry = null;

            // First, see if the file has ever existed. If it has and matches, return it.
            if (_entries[(int)entryHomeIndex].HasFileEverExisted())
            {
                if (_entries[(int)entryHomeIndex].GetPrimaryHash() == hashA && _entries[(int)entryHomeIndex].GetSecondaryHash() == hashB)
                {
                    tableEntry = _entries[(int)entryHomeIndex];
                    return(true);
                }
            }
            else
            {
                return(false);
            }

            // If that file doesn't match (but has existed, or is occupied, let's keep looking down the table.
            HashTableEntry currentEntry;
            HashTableEntry deletionEntry = null;

            for (var i = (int)entryHomeIndex + 1; i < _entries.Count - 1; ++i)
            {
                currentEntry = _entries[i];
                if (!currentEntry.HasFileEverExisted())
                {
                    continue;
                }

                if (currentEntry.GetPrimaryHash() != hashA || currentEntry.GetSecondaryHash() != hashB)
                {
                    continue;
                }

                if (currentEntry.DoesFileExist())
                {
                    // Found it!
                    tableEntry = currentEntry;
                    return(true);
                }

                // The file might have been deleted. Store it as a possible return candidate, but keep looking.
                deletionEntry = currentEntry;
            }

            // Still nothing? Loop around and scan the start of the table as well
            for (var i = 0; i < entryHomeIndex; ++i)
            {
                currentEntry = _entries[i];
                if (!currentEntry.HasFileEverExisted())
                {
                    continue;
                }

                if (currentEntry.GetPrimaryHash() != hashA || currentEntry.GetSecondaryHash() != hashB)
                {
                    continue;
                }

                if (currentEntry.DoesFileExist())
                {
                    // Found it!
                    tableEntry = currentEntry;
                    return(true);
                }

                // The file might have been deleted. Store it as a possible return candidate, but keep looking.
                deletionEntry = currentEntry;
            }

            if (deletionEntry is null)
            {
                return(false);
            }

            // We found the file, but it's been deleted.
            tableEntry = deletionEntry;
            return(true);
        }
Beispiel #6
0
        /// <summary>
        /// Finds a valid entry for a given hash pair, starting at the specified offset.
        /// </summary>
        /// <returns>The entry.</returns>
        /// <param name="hashA">A hash of the filename (Algorithm A).</param>
        /// <param name="hashB">A hash of the filename (Algorithm B)</param>
        /// <param name="entryHomeIndex">The home index for the file we're searching for. Reduces lookup times.</param>
        public HashTableEntry FindEntry(uint hashA, uint hashB, uint entryHomeIndex)
        {
            // First, see if the file has ever existed. If it has and matches, return it.
            if (this.Entries[(int)entryHomeIndex].HasFileEverExisted())
            {
                if (this.Entries[(int)entryHomeIndex].GetPrimaryHash() == hashA && this.Entries[(int)entryHomeIndex].GetSecondaryHash() == hashB)
                {
                    return(this.Entries[(int)entryHomeIndex]);
                }
            }
            else
            {
                return(null);
            }

            // If that file doesn't match (but has existed, or is occupied, let's keep looking down the table.
            HashTableEntry currentEntry  = null;
            HashTableEntry deletionEntry = null;

            for (int i = (int)entryHomeIndex + 1; i < this.Entries.Count - 1; ++i)
            {
                currentEntry = this.Entries[i];
                if (currentEntry.HasFileEverExisted())
                {
                    if (currentEntry.GetPrimaryHash() == hashA && currentEntry.GetSecondaryHash() == hashB)
                    {
                        if (currentEntry.DoesFileExist())
                        {
                            // Found it!
                            return(currentEntry);
                        }
                        else
                        {
                            // The file might have been deleted. Store it as a possible return candidate, but keep looking.
                            deletionEntry = currentEntry;
                        }
                    }
                }
            }

            // Still nothing? Loop around and scan the start of the table as well
            for (int i = 0; i < entryHomeIndex; ++i)
            {
                currentEntry = this.Entries[i];
                if (currentEntry.HasFileEverExisted())
                {
                    if (currentEntry.GetPrimaryHash() == hashA && currentEntry.GetSecondaryHash() == hashB)
                    {
                        if (currentEntry.DoesFileExist())
                        {
                            // Found it!
                            return(currentEntry);
                        }
                        else
                        {
                            // The file might have been deleted. Store it as a possible return candidate, but keep looking.
                            deletionEntry = currentEntry;
                        }
                    }
                }
            }

            // We found the file, but it's been deleted.
            return(deletionEntry);
        }
Beispiel #7
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Warcraft.MPQ.FileInfo.MPQFileInfo"/> class.
 /// </summary>
 /// <param name="InPath">In path.</param>
 /// <param name="InHashEntry">In hash entry.</param>
 /// <param name="InBlockEntry">In block entry.</param>
 public MPQFileInfo(string InPath, HashTableEntry InHashEntry, BlockTableEntry InBlockEntry)
 {
     this.Path = InPath;
     this.HashEntry = InHashEntry;
     this.BlockEntry = InBlockEntry;
 }
Beispiel #8
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Warcraft.MPQ.FileInfo.MPQFileInfo"/> class.
 /// </summary>
 /// <param name="InPath">In path.</param>
 /// <param name="InHashEntry">In hash entry.</param>
 /// <param name="InBlockEntry">In block entry.</param>
 /// <param name="InAttributes">In attributes.</param>
 public MPQFileInfo(string InPath, HashTableEntry InHashEntry, BlockTableEntry InBlockEntry, FileAttributes InAttributes)
     : this(InPath, InHashEntry, InBlockEntry)
 {
     this.Attributes = InAttributes;
 }