public void SaveFileTo(int fileDataId, string fullName, string extractPath) => SaveFileTo(FileDataHash.ComputeHash(fileDataId), extractPath, fullName);
public WowRootHandler(BinaryReader stream, BackgroundWorker worker) { worker?.ReportProgress(0, "Loading root..."); int numFilesRead = 0; var magic = stream.ReadInt32(); var numFilesTotal = stream.ReadInt32(); var numFilesWithNameHash = stream.ReadInt32(); while (stream.BaseStream.Position < stream.BaseStream.Length) { int count = stream.ReadInt32(); numFilesRead += count; ContentFlags contentFlags = (ContentFlags)stream.ReadUInt32(); LocaleFlags localeFlags = (LocaleFlags)stream.ReadUInt32(); if (localeFlags == LocaleFlags.None) { throw new Exception("block.LocaleFlags == LocaleFlags.None"); } if (contentFlags != ContentFlags.None && (contentFlags & (ContentFlags.F00000001 | ContentFlags.Windows | ContentFlags.MacOS | ContentFlags.Alternate | ContentFlags.F00020000 | ContentFlags.F00080000 | ContentFlags.F00100000 | ContentFlags.F00400000 | ContentFlags.F02000000 | ContentFlags.NotCompressed | ContentFlags.NoNameHash | ContentFlags.F20000000)) == 0) { throw new Exception("block.ContentFlags != ContentFlags.None"); } RootEntry[] entries = new RootEntry[count]; int[] filedataIds = new int[count]; int fileDataIndex = 0; for (var i = 0; i < count; ++i) { entries[i].LocaleFlags = localeFlags; entries[i].ContentFlags = contentFlags; filedataIds[i] = fileDataIndex + stream.ReadInt32(); fileDataIndex = filedataIds[i] + 1; } //Debug.Log("Block: {0} {1} (size {2})", block.ContentFlags, block.LocaleFlags, count); ulong[] nameHashes = null; for (var i = 0; i < count; ++i) { entries[i].MD5 = stream.Read <MD5Hash>(); } if (numFilesRead > numFilesTotal - numFilesWithNameHash) { nameHashes = new ulong[count]; for (var i = 0; i < count; ++i) { nameHashes[i] = stream.ReadUInt64(); } } //for (var i = 0; i < count; ++i) Parallel.For(0, count, i => { var fileDataId = filedataIds[i]; var hash = 0UL; if (nameHashes == null) { hash = FileDataHash.ComputeHash(fileDataId); } else { hash = nameHashes[i]; } RootData.Add(fileDataId, entries[i]); FileDataStore.TryAdd(fileDataId, hash); FileDataStoreReverse.TryAdd(hash, fileDataId); // if (nameHashes != null) // { // // generate our custom hash as well so we can still find file without calling GetHashByFileDataId in some weird cases // var fileDataHash = FileDataHash.ComputeHash(fileDataId); // FileDataStoreReverse.TryAdd(fileDataHash, fileDataId); // } }); worker?.ReportProgress((int)(stream.BaseStream.Position / (float)stream.BaseStream.Length * 100), "Loading root..."); } }
public WowRootHandler(BinaryReader stream, BackgroundWorkerEx worker) { worker?.ReportProgress(0, "Loading \"root\"..."); int magic = stream.ReadInt32(); int numFilesTotal = 0, numFilesWithNameHash = 0, numFilesRead = 0; const int TSFMMagic = 0x4D465354; if (magic == TSFMMagic) { numFilesTotal = stream.ReadInt32(); numFilesWithNameHash = stream.ReadInt32(); } else { stream.BaseStream.Position -= 4; } while (stream.BaseStream.Position < stream.BaseStream.Length) { int count = stream.ReadInt32(); numFilesRead += count; ContentFlags contentFlags = (ContentFlags)stream.ReadUInt32(); LocaleFlags localeFlags = (LocaleFlags)stream.ReadUInt32(); if (localeFlags == LocaleFlags.None) { throw new InvalidDataException("block.LocaleFlags == LocaleFlags.None"); } if (contentFlags != ContentFlags.None && (contentFlags & (ContentFlags.F00000001 | ContentFlags.Windows | ContentFlags.MacOS | ContentFlags.Alternate | ContentFlags.F00020000 | ContentFlags.F00080000 | ContentFlags.F00100000 | ContentFlags.F00200000 | ContentFlags.F00400000 | ContentFlags.F02000000 | ContentFlags.NotCompressed | ContentFlags.NoNameHash | ContentFlags.F20000000)) == 0) { throw new InvalidDataException("block.ContentFlags != ContentFlags.None"); } RootEntry[] entries = new RootEntry[count]; int[] filedataIds = new int[count]; int fileDataIndex = 0; for (var i = 0; i < count; ++i) { entries[i].LocaleFlags = localeFlags; entries[i].ContentFlags = contentFlags; filedataIds[i] = fileDataIndex + stream.ReadInt32(); fileDataIndex = filedataIds[i] + 1; } //Console.WriteLine("Block: {0} {1} (size {2})", block.ContentFlags, block.LocaleFlags, count); ulong[] nameHashes = null; if (magic == TSFMMagic) { for (var i = 0; i < count; ++i) { entries[i].cKey = stream.Read <MD5Hash>(); } if ((contentFlags & ContentFlags.NoNameHash) == 0) { nameHashes = new ulong[count]; for (var i = 0; i < count; ++i) { nameHashes[i] = stream.ReadUInt64(); } } } else { nameHashes = new ulong[count]; for (var i = 0; i < count; ++i) { entries[i].cKey = stream.Read <MD5Hash>(); nameHashes[i] = stream.ReadUInt64(); } } for (var i = 0; i < count; ++i) { int fileDataId = filedataIds[i]; //Logger.WriteLine("filedataid {0}", fileDataId); ulong hash; if (nameHashes == null) { hash = FileDataHash.ComputeHash(fileDataId); } else { hash = nameHashes[i]; } RootData.Add(fileDataId, entries[i]); //Console.WriteLine("File: {0:X8} {1:X16} {2}", entries[i].FileDataId, hash, entries[i].MD5.ToHexString()); if (FileDataStore.TryGetValue(fileDataId, out ulong hash2)) { if (hash2 == hash) { // duplicate, skipping } else { Logger.WriteLine("ERROR: got miltiple hashes for filedataid {0}", fileDataId); } continue; } FileDataStore.Add(fileDataId, hash); FileDataStoreReverse.Add(hash, fileDataId); if (nameHashes != null) { // generate our custom hash as well so we can still find file without calling GetHashByFileDataId in some weird cases ulong fileDataHash = FileDataHash.ComputeHash(fileDataId); FileDataStoreReverse.Add(fileDataHash, fileDataId); } } worker?.ReportProgress((int)(stream.BaseStream.Position / (float)stream.BaseStream.Length * 100)); } }
public WowRootHandler(BinaryReader stream) { int numFilesRead = 0; var magic = stream.ReadInt32(); var numFilesTotal = stream.ReadInt32(); var numFilesWithNameHash = stream.ReadInt32(); while (stream.BaseStream.Position < stream.BaseStream.Length) { int count = stream.ReadInt32(); numFilesRead += count; ContentFlags contentFlags = (ContentFlags)stream.ReadUInt32(); LocaleFlags localeFlags = (LocaleFlags)stream.ReadUInt32(); if (localeFlags == LocaleFlags.None) { throw new Exception("block.LocaleFlags == LocaleFlags.None"); } if (contentFlags != ContentFlags.None && (contentFlags & (ContentFlags.F00000001 | ContentFlags.Windows | ContentFlags.MacOS | ContentFlags.Alternate | ContentFlags.F00020000 | ContentFlags.F00080000 | ContentFlags.F00100000 | ContentFlags.F00400000 | ContentFlags.F02000000 | ContentFlags.NotCompressed | ContentFlags.NoNameHash | ContentFlags.F20000000)) == 0) { throw new Exception("block.ContentFlags != ContentFlags.None"); } RootEntry[] entries = new RootEntry[count]; int[] filedataIds = new int[count]; int fileDataIndex = 0; for (var i = 0; i < count; ++i) { entries[i].LocaleFlags = localeFlags; entries[i].ContentFlags = contentFlags; filedataIds[i] = fileDataIndex + stream.ReadInt32(); fileDataIndex = filedataIds[i] + 1; } //Console.WriteLine("Block: {0} {1} (size {2})", block.ContentFlags, block.LocaleFlags, count); ulong[] nameHashes = null; for (var i = 0; i < count; ++i) { entries[i].MD5 = stream.Read <MD5Hash>(); } if (numFilesRead > numFilesTotal - numFilesWithNameHash) { nameHashes = new ulong[count]; for (var i = 0; i < count; ++i) { nameHashes[i] = stream.ReadUInt64(); } } for (var i = 0; i < count; ++i) { var fileDataId = filedataIds[i]; var hash = 0UL; if (nameHashes == null) { hash = FileDataHash.ComputeHash(fileDataId); } else { hash = nameHashes[i]; } RootData.Add(fileDataId, entries[i]); if (FileDataStore.TryGetValue(fileDataId, out ulong hash2)) { if (hash2 != hash) { Console.WriteLine("ERROR: got multiple hashes for filedataid {0}", fileDataId); } continue; } FileDataStore.Add(fileDataId, hash); FileDataStoreReverse.Add(hash, fileDataId); } ; } }