Example #1
0
 public RootHandler()
 {
     GlobalRoot = new RootChunk()
     {
         ContentFlags = ContentFlags.None, LocaleFlags = LocaleFlags.All_WoW
     };
     encodingMap = new EncodingMap(EncodingType.ZLib, 9);
 }
Example #2
0
        /// <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;
            }
        }
Example #3
0
        /// <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;
        }
Example #4
0
        /// <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);
        }
Example #5
0
        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();
        }
Example #6
0
        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();
        }