Beispiel #1
0
        public static CDNConfigFile GetCDNConfig(string url, string hash)
        {
            string content;
            var    cdnConfig = new CDNConfigFile();

            if (url.StartsWith("http"))
            {
                try
                {
                    content = Encoding.UTF8.GetString(CDN.Get(url + "/config/" + hash[0] + hash[1] + "/" + hash[2] + hash[3] + "/" + hash));
                }
                catch (Exception e)
                {
                    Logger.WriteLine("Error retrieving CDN config: " + e.Message);
                    return(cdnConfig);
                }
            }
            else
            {
                content = File.ReadAllText(Path.Combine(url, "config", "" + hash[0] + hash[1], "" + hash[2] + hash[3], hash));
            }


            var cdnConfigLines = content.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);

            for (var i = 0; i < cdnConfigLines.Count(); i++)
            {
                if (cdnConfigLines[i].StartsWith("#") || cdnConfigLines[i].Length == 0)
                {
                    continue;
                }
                var cols = cdnConfigLines[i].Split(new string[] { " = " }, StringSplitOptions.RemoveEmptyEntries);
                switch (cols[0])
                {
                case "archives":
                    var archives = cols[1].Split(' ');
                    cdnConfig.archives = new MD5Hash[archives.Length];
                    for (var j = 0; j < archives.Length; j++)
                    {
                        cdnConfig.archives[j] = archives[j].ToByteArray().ToMD5();
                    }
                    break;

                case "archive-group":
                    cdnConfig.archiveGroup = cols[1];
                    break;

                case "patch-archives":
                    if (cols.Length > 1)
                    {
                        var patchArchives = cols[1].Split(' ');
                        cdnConfig.patchArchives = new MD5Hash[patchArchives.Length];
                        for (var j = 0; j < patchArchives.Length; j++)
                        {
                            cdnConfig.patchArchives[j] = patchArchives[j].ToByteArray().ToMD5();
                        }
                    }
                    break;

                case "patch-archive-group":
                    cdnConfig.patchArchiveGroup = cols[1];
                    break;

                case "builds":
                    var builds = cols[1].Split(' ');
                    cdnConfig.builds = builds;
                    break;

                case "file-index":
                    cdnConfig.fileIndex = cols[1];
                    break;

                case "file-index-size":
                    cdnConfig.fileIndexSize = cols[1];
                    break;

                case "patch-file-index":
                    cdnConfig.patchFileIndex = cols[1];
                    break;

                case "patch-file-index-size":
                    cdnConfig.patchFileIndexSize = cols[1];
                    break;

                case "archives-index-size":
                case "patch-archives-index-size":
                    break;

                default:
                    Logger.WriteLine("!!!!!!!! Unknown cdnconfig variable '" + cols[0] + "'");
                    break;
                }
            }

            return(cdnConfig);
        }
Beispiel #2
0
        public static BuildConfigFile GetBuildConfig(string url, string hash)
        {
            string content;

            var buildConfig = new BuildConfigFile();

            if (url.StartsWith("http"))
            {
                try
                {
                    content = Encoding.UTF8.GetString(CDN.Get(url + "/config/" + hash[0] + hash[1] + "/" + hash[2] + hash[3] + "/" + hash));
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error retrieving CDN config: " + e.Message);
                    return(buildConfig);
                }
            }
            else
            {
                content = File.ReadAllText(Path.Combine(url, "config", "" + hash[0] + hash[1], "" + hash[2] + hash[3], hash));
            }

            if (string.IsNullOrEmpty(content) || !content.StartsWith("# Build"))
            {
                Console.WriteLine("Error reading build config!");
                return(buildConfig);
            }

            var lines = content.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);

            for (var i = 0; i < lines.Count(); i++)
            {
                if (lines[i].StartsWith("#") || lines[i].Length == 0)
                {
                    continue;
                }
                var cols = lines[i].Split(new string[] { " = " }, StringSplitOptions.RemoveEmptyEntries);
                switch (cols[0])
                {
                case "root":
                    buildConfig.root = cols[1].ToByteArray().ToMD5();
                    break;

                case "download":
                    var downloadSplit = cols[1].Split(' ');

                    buildConfig.download    = new MD5Hash[downloadSplit.Length];
                    buildConfig.download[0] = downloadSplit[0].ToByteArray().ToMD5();

                    if (downloadSplit.Length > 1)
                    {
                        buildConfig.download[1] = downloadSplit[1].ToByteArray().ToMD5();
                    }

                    break;

                case "install":
                    var installSplit = cols[1].Split(' ');

                    buildConfig.install    = new MD5Hash[installSplit.Length];
                    buildConfig.install[0] = installSplit[0].ToByteArray().ToMD5();

                    if (installSplit.Length > 1)
                    {
                        buildConfig.install[1] = installSplit[1].ToByteArray().ToMD5();
                    }
                    break;

                case "encoding":
                    var encodingSplit = cols[1].Split(' ');

                    buildConfig.encoding    = new MD5Hash[encodingSplit.Length];
                    buildConfig.encoding[0] = encodingSplit[0].ToByteArray().ToMD5();

                    if (encodingSplit.Length > 1)
                    {
                        buildConfig.encoding[1] = encodingSplit[1].ToByteArray().ToMD5();
                    }
                    break;

                case "encoding-size":
                    var encodingSize = cols[1].Split(' ');
                    buildConfig.encodingSize = encodingSize;
                    break;

                case "size":
                    buildConfig.size = cols[1].Split(' ');
                    break;

                case "size-size":
                    buildConfig.sizeSize = cols[1].Split(' ');
                    break;

                case "build-name":
                    buildConfig.buildName = cols[1];
                    break;

                case "build-playbuild-installer":
                    buildConfig.buildPlaybuildInstaller = cols[1];
                    break;

                case "build-product":
                    buildConfig.buildProduct = cols[1];
                    break;

                case "build-uid":
                    buildConfig.buildUid = cols[1];
                    break;

                case "patch":
                    buildConfig.patch = cols[1].ToByteArray().ToMD5();
                    break;

                case "patch-size":
                    buildConfig.patchSize = cols[1];
                    break;

                case "patch-config":
                    buildConfig.patchConfig = cols[1].ToByteArray().ToMD5();
                    break;

                case "build-branch":     // Overwatch
                    buildConfig.buildBranch = cols[1];
                    break;

                case "build-num":     // Agent
                case "build-number":  // Overwatch
                case "build-version": // Catalog
                    buildConfig.buildNumber = cols[1];
                    break;

                case "build-attributes":     // Agent
                    buildConfig.buildAttributes = cols[1];
                    break;

                case "build-comments":     // D3
                    buildConfig.buildComments = cols[1];
                    break;

                case "build-creator":     // D3
                    buildConfig.buildCreator = cols[1];
                    break;

                case "build-fixed-hash":     // S2
                    buildConfig.buildFixedHash = cols[1];
                    break;

                case "build-replay-hash":     // S2
                    buildConfig.buildReplayHash = cols[1];
                    break;

                case "build-t1-manifest-version":
                    buildConfig.buildManifestVersion = cols[1];
                    break;

                case "install-size":
                    buildConfig.installSize = cols[1].Split(' ');
                    break;

                case "download-size":
                    buildConfig.downloadSize = cols[1].Split(' ');
                    break;

                case "build-partial-priority":
                case "partial-priority":
                    buildConfig.partialPriority = cols[1];
                    break;

                case "partial-priority-size":
                    buildConfig.partialPrioritySize = cols[1];
                    break;

                default:
                    Logger.WriteLine("!!!!!!!! Unknown buildconfig variable '" + cols[0] + "'");
                    break;
                }
            }

            return(buildConfig);
        }
Beispiel #3
0
        public static EncodingFile GetEncoding(string url, string hash, int encodingSize = 0, bool parseTableB = false, bool checkStuff = false)
        {
            var encoding = new EncodingFile();

            byte[] content;

            if (url.Substring(0, 4) == "http")
            {
                content = CDN.Get(url + "data/" + hash[0] + hash[1] + "/" + hash[2] + hash[3] + "/" + hash);

                if (encodingSize != 0 && encodingSize != content.Length)
                {
                    content = CDN.Get(url + "data/" + hash[0] + hash[1] + "/" + hash[2] + hash[3] + "/" + hash, true);

                    if (encodingSize != content.Length && encodingSize != 0)
                    {
                        throw new Exception("File corrupt/not fully downloaded! Remove " + "data / " + hash[0] + hash[1] + " / " + hash[2] + hash[3] + " / " + hash + " from cache.");
                    }
                }
            }
            else
            {
                content = File.ReadAllBytes(Path.Combine(url, "data", "" + hash[0] + hash[1], "" + hash[2] + hash[3], hash));
            }

            using (BinaryReader bin = new BinaryReader(new MemoryStream(BLTE.Parse(content))))
            {
                if (Encoding.UTF8.GetString(bin.ReadBytes(2)) != "EN")
                {
                    throw new Exception("Error while parsing encoding file. Did BLTE header size change?");
                }
                encoding.version         = bin.ReadByte();
                encoding.cKeyLength      = bin.ReadByte();
                encoding.eKeyLength      = bin.ReadByte();
                encoding.cKeyPageSize    = bin.ReadUInt16(true);
                encoding.eKeyPageSize    = bin.ReadUInt16(true);
                encoding.cKeyPageCount   = bin.ReadUInt32(true);
                encoding.eKeyPageCount   = bin.ReadUInt32(true);
                encoding.stringBlockSize = bin.ReadUInt40(true);

                var headerLength = bin.BaseStream.Position;

                if (parseTableB)
                {
                    var stringBlockEntries = new List <string>();

                    while ((bin.BaseStream.Position - headerLength) != (long)encoding.stringBlockSize)
                    {
                        stringBlockEntries.Add(bin.ReadCString());
                    }

                    encoding.stringBlockEntries = stringBlockEntries.ToArray();
                }
                else
                {
                    bin.BaseStream.Position += (long)encoding.stringBlockSize;
                }

                /* Table A */
                if (checkStuff)
                {
                    encoding.aHeaders = new EncodingHeaderEntry[encoding.cKeyPageCount];

                    for (int i = 0; i < encoding.cKeyPageCount; i++)
                    {
                        encoding.aHeaders[i].firstHash = bin.Read <MD5Hash>();
                        encoding.aHeaders[i].checksum  = bin.Read <MD5Hash>();
                    }
                }
                else
                {
                    bin.BaseStream.Position += encoding.cKeyPageCount * 32;
                }

                var tableAstart = bin.BaseStream.Position;

                Dictionary <MD5Hash, EncodingFileEntry> entries = new Dictionary <MD5Hash, EncodingFileEntry>(new MD5HashComparer());

                for (int i = 0; i < encoding.cKeyPageCount; i++)
                {
                    byte keysCount;

                    while ((keysCount = bin.ReadByte()) != 0)
                    {
                        EncodingFileEntry entry = new EncodingFileEntry()
                        {
                            size = bin.ReadInt40BE()
                        };

                        var cKey = bin.Read <MD5Hash>();

                        // @TODO add support for multiple encoding keys
                        for (int key = 0; key < keysCount; key++)
                        {
                            if (key == 0)
                            {
                                entry.eKey = bin.Read <MD5Hash>();
                            }
                            else
                            {
                                bin.ReadBytes(16);
                            }
                        }
                        entries.Add(cKey, entry);
                    }

                    var remaining = 4096 - ((bin.BaseStream.Position - tableAstart) % 4096);
                    if (remaining > 0)
                    {
                        bin.BaseStream.Position += remaining;
                    }
                }

                encoding.aEntries = entries;

                if (!parseTableB)
                {
                    return(encoding);
                }

                /* Table B */
                if (checkStuff)
                {
                    encoding.bHeaders = new EncodingHeaderEntry[encoding.eKeyPageCount];

                    for (int i = 0; i < encoding.eKeyPageCount; i++)
                    {
                        encoding.bHeaders[i].firstHash = bin.Read <MD5Hash>();
                        encoding.bHeaders[i].checksum  = bin.Read <MD5Hash>();
                    }
                }
                else
                {
                    bin.BaseStream.Position += encoding.eKeyPageCount * 32;
                }

                var tableBstart = bin.BaseStream.Position;

                List <EncodingFileDescEntry> b_entries = new List <EncodingFileDescEntry>();

                while (bin.BaseStream.Position < tableBstart + 4096 * encoding.eKeyPageCount)
                {
                    var remaining = 4096 - (bin.BaseStream.Position - tableBstart) % 4096;

                    if (remaining < 25)
                    {
                        bin.BaseStream.Position += remaining;
                        continue;
                    }

                    EncodingFileDescEntry entry = new EncodingFileDescEntry()
                    {
                        key            = bin.Read <MD5Hash>(),
                        stringIndex    = bin.ReadUInt32(true),
                        compressedSize = bin.ReadUInt40(true)
                    };

                    if (entry.stringIndex == uint.MaxValue)
                    {
                        break;
                    }

                    b_entries.Add(entry);
                }

                encoding.bEntries = b_entries.ToArray();
            }

            return(encoding);
        }
Beispiel #4
0
        public static void GetIndexes(string url, MD5Hash[] archives)
        {
            Parallel.ForEach(archives, (archive, state, i) =>
            {
                uint indexID;
                string indexName = archive.ToHexString().ToLower();

                try
                {
                    cacheLock.EnterUpgradeableReadLock();

                    if (!CASC.indexNames.Contains(archives[i], new MD5HashComparer()))
                    {
                        try
                        {
                            cacheLock.EnterWriteLock();
                            CASC.indexNames.Add(archive);
                            indexID = (uint)CASC.indexNames.Count - 1;
                        }
                        finally
                        {
                            cacheLock.ExitWriteLock();
                        }
                    }
                    else
                    {
                        return;
                    }
                }
                finally
                {
                    cacheLock.ExitUpgradeableReadLock();
                }


                byte[] indexContent;

                if (url.StartsWith("http"))
                {
                    indexContent = CDN.Get(url + "data/" + indexName[0] + indexName[1] + "/" + indexName[2] + indexName[3] + "/" + indexName + ".index");
                }
                else
                {
                    indexContent = File.ReadAllBytes(Path.Combine(url, "data", "" + indexName[0] + indexName[1], "" + indexName[2] + indexName[3], indexName + ".index"));
                }

                using (BinaryReader bin = new BinaryReader(new MemoryStream(indexContent)))
                {
                    bin.BaseStream.Position = bin.BaseStream.Length - 12;
                    var entryCount          = bin.ReadUInt32();
                    bin.BaseStream.Position = 0;

                    int indexEntries = indexContent.Length / 4096;

                    var entriesRead = 0;
                    for (var b = 0; b < indexEntries; b++)
                    {
                        for (var bi = 0; bi < 170; bi++)
                        {
                            var headerHash = bin.Read <MD5Hash>();

                            var entry = new IndexEntry()
                            {
                                indexID = indexID,
                                size    = bin.ReadUInt32(true),
                                offset  = bin.ReadUInt32(true)
                            };

                            entriesRead++;

                            cacheLock.EnterUpgradeableReadLock();
                            try
                            {
                                if (!CASC.indexDictionary.ContainsKey(headerHash))
                                {
                                    cacheLock.EnterWriteLock();
                                    try
                                    {
                                        CASC.indexDictionary.Add(headerHash, entry);
                                    }
                                    finally
                                    {
                                        cacheLock.ExitWriteLock();
                                    }
                                }
                            }
                            finally
                            {
                                cacheLock.ExitUpgradeableReadLock();
                            }
                        }

                        if (entriesRead == entryCount)
                        {
                            return;
                        }

                        // 16 bytes padding that rounds the chunk to 4096 bytes (index entry is 24 bytes, 24 * 170 = 4080 bytes so 16 bytes remain)
                        bin.ReadBytes(16);
                    }
                }
            });
        }
Beispiel #5
0
        public static RootFile GetRoot(string url, string hash, bool parseIt = false)
        {
            var root = new RootFile
            {
                entriesLookup = new MultiDictionary <ulong, RootEntry>(),
                entriesFDID   = new MultiDictionary <uint, RootEntry>(),
            };

            byte[] content;

            if (url.StartsWith("http:"))
            {
                content = CDN.Get(url + "data/" + hash[0] + hash[1] + "/" + hash[2] + hash[3] + "/" + hash);
            }
            else
            {
                content = File.ReadAllBytes(Path.Combine(url, "data", "" + hash[0] + hash[1], "" + hash[2] + hash[3], hash));
            }

            if (!parseIt)
            {
                return(root);
            }

            var hasher = new Jenkins96();

            var  namedCount   = 0;
            var  unnamedCount = 0;
            uint totalFiles   = 0;
            uint namedFiles   = 0;
            var  newRoot      = false;

            using (BinaryReader bin = new BinaryReader(new MemoryStream(BLTE.Parse(content))))
            {
                var header = bin.ReadUInt32();
                if (header == 1296454484)
                {
                    totalFiles = bin.ReadUInt32();
                    namedFiles = bin.ReadUInt32();
                    newRoot    = true;
                }
                else
                {
                    bin.BaseStream.Position = 0;
                }

                while (bin.BaseStream.Position < bin.BaseStream.Length)
                {
                    var count        = bin.ReadUInt32();
                    var contentFlags = (ContentFlags)bin.ReadUInt32();
                    var localeFlags  = (LocaleFlags)bin.ReadUInt32();

                    var entries     = new RootEntry[count];
                    var filedataIds = new int[count];

                    var fileDataIndex = 0;
                    for (var i = 0; i < count; ++i)
                    {
                        entries[i].localeFlags  = localeFlags;
                        entries[i].contentFlags = contentFlags;

                        filedataIds[i]        = fileDataIndex + bin.ReadInt32();
                        entries[i].fileDataID = (uint)filedataIds[i];
                        fileDataIndex         = filedataIds[i] + 1;
                    }

                    if (!newRoot)
                    {
                        for (var i = 0; i < count; ++i)
                        {
                            entries[i].md5    = bin.Read <MD5Hash>();
                            entries[i].lookup = bin.ReadUInt64();
                            root.entriesLookup.Add(entries[i].lookup, entries[i]);
                            root.entriesFDID.Add(entries[i].fileDataID, entries[i]);
                        }
                    }
                    else
                    {
                        for (var i = 0; i < count; ++i)
                        {
                            entries[i].md5 = bin.Read <MD5Hash>();
                        }

                        for (var i = 0; i < count; ++i)
                        {
                            if (contentFlags.HasFlag(ContentFlags.NoNames))
                            {
                                //entries[i].lookup = hasher.ComputeHash("BY_FDID_" + entries[i].fileDataID);
                                entries[i].lookup = 0;
                                unnamedCount++;
                            }
                            else
                            {
                                entries[i].lookup = bin.ReadUInt64();
                                namedCount++;

                                root.entriesLookup.Add(entries[i].lookup, entries[i]);
                            }

                            root.entriesFDID.Add(entries[i].fileDataID, entries[i]);
                        }
                    }
                }
            }

            return(root);
        }