public RootHandler() { GlobalRoot = new RootChunk() { ContentFlags = ContentFlags.None, LocaleFlags = LocaleFlags.All_WoW }; encodingMap = new EncodingMap(EncodingType.ZLib, 9); }
/// <summary> /// Parses a character set into an encoding. /// </summary> /// <param name="characterSet">The character set to parse</param> /// <returns>An encoding which corresponds to the character set</returns> /// <exception cref="ArgumentNullException">If <paramref name="characterSet" /> is <see langword="null" /></exception> internal static Encoding FindEncoding(string characterSet) { if (characterSet == null) { throw new ArgumentNullException(nameof(characterSet)); } var charSetUpper = characterSet.ToUpperInvariant(); // Check if the characterSet is explicitly mapped to an encoding if (EncodingMap.ContainsKey(charSetUpper)) { return(EncodingMap[charSetUpper]); } // Try to generally find the encoding try { if (!charSetUpper.Contains("WINDOWS") && !charSetUpper.Contains("CP")) { return(Encoding.GetEncoding(characterSet)); } // It seems the characterSet contains an codepage value, which we should use to parse the encoding charSetUpper = charSetUpper.Replace("CP", ""); // Remove cp charSetUpper = charSetUpper.Replace("WINDOWS", ""); // Remove windows charSetUpper = charSetUpper.Replace("-", ""); // Remove - which could be used as cp-1554 // Now we hope the only thing left in the characterSet is numbers. var codepageNumber = int.Parse(charSetUpper, CultureInfo.InvariantCulture); return(Encoding.GetEncoding(codepageNumber)); // It seems there is no codepage value in the characterSet. It must be a named encoding } catch (ArgumentException) { // The encoding could not be found generally. // Try to use the FallbackDecoder if it is defined. // Check if it is defined if (FallbackDecoder == null) { throw; // It was not defined - throw catched exception } // Use the FallbackDecoder var fallbackDecoderResult = FallbackDecoder(characterSet); // Check if the FallbackDecoder had a solution if (fallbackDecoderResult != null) { return(fallbackDecoderResult); } // If no solution was found, throw catched exception throw; } }
/// <summary> /// Creates an optimized encoding mapping that can be consumed by an optimized version of charmap_encode. /// </summary> public static EncodingMap charmap_build(string decoding_table) { if (decoding_table.Length != 256) { throw PythonOps.TypeError("charmap_build expected 256 character string"); } EncodingMap map = new EncodingMap(); for (int i = 0; i < decoding_table.Length; i++) { map.Mapping[(int)decoding_table[i]] = (char)i; } return map; }
/// <summary> /// Puts a mapping from <paramref name="characterSet" /> to <paramref name="encoding" /> /// into the <see cref="EncodingFinder" />'s internal mapping Dictionary. /// </summary> /// <param name="characterSet">The string that maps to the <paramref name="encoding" /></param> /// <param name="encoding">The <see cref="Encoding" /> that should be mapped from <paramref name="characterSet" /></param> /// <exception cref="ArgumentNullException">If <paramref name="characterSet" /> is <see langword="null" /></exception> /// <exception cref="ArgumentNullException">If <paramref name="encoding" /> is <see langword="null" /></exception> public static void AddMapping(string characterSet, Encoding encoding) { if (characterSet == null) { throw new ArgumentNullException(nameof(characterSet)); } if (encoding == null) { throw new ArgumentNullException(nameof(encoding)); } // Add the mapping using uppercase EncodingMap.Add(characterSet.ToUpperInvariant(), encoding); }
public RootHandler(Stream data, LocaleFlags locale, uint minimumid = 0) { this.minimumId = minimumid; this.locale = locale; BinaryReader stream = new BinaryReader(data); long length = stream.BaseStream.Length; while (stream.BaseStream.Position < length) { RootChunk chunk = new RootChunk() { Count = stream.ReadUInt32(), ContentFlags = (ContentFlags)stream.ReadUInt32(), LocaleFlags = (LocaleFlags)stream.ReadUInt32(), }; // set the global root if (chunk.LocaleFlags == LocaleFlags.All_WoW && chunk.ContentFlags == ContentFlags.None) { GlobalRoot = chunk; } uint fileDataIndex = 0; for (int i = 0; i < chunk.Count; i++) { uint offset = stream.ReadUInt32(); RootEntry entry = new RootEntry() { FileDataIdOffset = offset, FileDataId = fileDataIndex + offset }; fileDataIndex = entry.FileDataId + 1; chunk.Entries.Add(entry); } foreach (var entry in chunk.Entries) { entry.CEKey = new MD5Hash(stream); entry.NameHash = stream.ReadUInt64(); maxId = Math.Max(maxId, entry.FileDataId); } Chunks.Add(chunk); } if (GlobalRoot == null) { CASContainer.Logger.LogCritical($"No Global root found. Root file is corrupt."); return; } // set maxid from cache maxId = Math.Max(Math.Max(maxId, minimumid), CASContainer.Settings.Cache?.MaxId ?? 0); // store encoding map encodingMap = (data as BLTEStream)?.EncodingMap.FirstOrDefault() ?? new EncodingMap(EncodingType.ZLib, 9); stream?.Dispose(); data?.Dispose(); }
public RootHandler(Stream data, LocaleFlags locale, uint minimumid = 0, bool onlineListfile = false) { this.minimumId = minimumid; this.locale = locale; string cdnPath = Helper.GetCDNPath("listfile.csv"); if (!(File.Exists(Path.Combine(CASContainer.Settings.OutputPath, cdnPath))) && onlineListfile) { CASContainer.Logger.LogInformation("Downloading listfile from WoW.Tools"); ListFileClient.DownloadFile("https://wow.tools/casc/listfile/download/csv/unverified", cdnPath); } BinaryReader stream = new BinaryReader(data); // 8.2 root change int magic = stream.ReadInt32(); bool newFormat = magic == headerMagic; if (newFormat) { allFiles = stream.ReadInt32(); namedFiles = stream.ReadInt32(); } else { stream.BaseStream.Position = 0; } long length = stream.BaseStream.Length; while (stream.BaseStream.Position < length) { RootChunk chunk = new RootChunk() { Count = stream.ReadUInt32(), ContentFlags = (ContentFlags)stream.ReadUInt32(), LocaleFlags = (LocaleFlags)stream.ReadUInt32(), }; parsedFiles += (int)chunk.Count; // set the global root if (chunk.LocaleFlags == LocaleFlags.All_WoW && chunk.ContentFlags == ContentFlags.None) { GlobalRoot = chunk; } uint fileDataIndex = 0; for (int i = 0; i < chunk.Count; i++) { uint offset = stream.ReadUInt32(); RootEntry entry = new RootEntry() { FileDataIdOffset = offset, FileDataId = fileDataIndex + offset }; fileDataIndex = entry.FileDataId + 1; chunk.Entries.Add(entry); } if (newFormat) { foreach (var entry in chunk.Entries) { entry.CEKey = new MD5Hash(stream); maxId = Math.Max(maxId, entry.FileDataId); } if (parsedFiles > allFiles - namedFiles) { foreach (var entry in chunk.Entries) { entry.NameHash = stream.ReadUInt64(); } } else // no namehash { foreach (var entry in chunk.Entries) { entry.NameHash = 0; } } } else { foreach (var entry in chunk.Entries) { entry.CEKey = new MD5Hash(stream); entry.NameHash = stream.ReadUInt64(); maxId = Math.Max(maxId, entry.FileDataId); } } Chunks.Add(chunk); } if (GlobalRoot == null) { CASContainer.Logger.LogCritical($"No Global root found. Root file is corrupt."); return; } // use listfile to assign names var listFileLines = File.ReadAllLines(cdnPath); foreach (var listFileData in listFileLines) { var splitData = listFileData.Split(';'); if (splitData.Length != 2) { continue; } if (!uint.TryParse(splitData[0], out uint listFileDataID)) { continue; } ListFile[listFileDataID] = new Jenkins96().ComputeHash(splitData[1]); } foreach (var chunk in Chunks) { foreach (var entry in chunk.Entries) { if (entry.NameHash == 0) { if (ListFile.ContainsKey(entry.FileDataId)) { entry.NameHash = ListFile[entry.FileDataId]; } } } } // set maxid from cache maxId = Math.Max(Math.Max(maxId, minimumid), CASContainer.Settings.Cache?.MaxId ?? 0); // store encoding map encodingMap = (data as BLTEStream)?.EncodingMap.FirstOrDefault() ?? new EncodingMap(EncodingType.ZLib, 9); stream?.Dispose(); data?.Dispose(); }