private void ParseIndex(Stream stream, int i)
        {
            using (var br = new BinaryReader(stream))
            {
                stream.Seek(-12, SeekOrigin.End);
                int count = br.ReadInt32();
                stream.Seek(0, SeekOrigin.Begin);

                if (count * (16 + 4 + 4) > stream.Length)
                    throw new Exception("ParseIndex failed");

                for (int j = 0; j < count; ++j)
                {
                    byte[] key = br.ReadBytes(16);

                    if (key.IsZeroed()) // wtf?
                        key = br.ReadBytes(16);

                    if (key.IsZeroed()) // wtf?
                        throw new Exception("key.IsZeroed()");

                    IndexEntry entry = new IndexEntry();
                    entry.Index = i;
                    entry.Size = br.ReadInt32BE();
                    entry.Offset = br.ReadInt32BE();

                    CDNIndexData.Add(key, entry);
                }
            }
        }
 protected Stream OpenFileOnlineInternal(IndexEntry idxInfo, MD5Hash key)
 {
     if (idxInfo != null)
     {
         Stream s = CDNIndex.OpenDataFile(idxInfo);
         return new BLTEStream(s, key);
     }
     else
     {
         Stream s = CDNIndex.OpenDataFileDirect(key);
         return new BLTEStream(s, key);
     }
 }
Exemple #3
0
        private void ParseIndex(string idx)
        {
            using (var fs = new FileStream(idx, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            using (var br = new BinaryReader(fs))
            {
                int h2Len = br.ReadInt32();
                int h2Check = br.ReadInt32();
                byte[] h2 = br.ReadBytes(h2Len);

                long padPos = (8 + h2Len + 0x0F) & 0xFFFFFFF0;
                fs.Position = padPos;

                int dataLen = br.ReadInt32();
                int dataCheck = br.ReadInt32();

                int numBlocks = dataLen / 18;

                for (int i = 0; i < numBlocks; i++)
                {
                    IndexEntry info = new IndexEntry();
                    byte[] key = br.ReadBytes(9);
                    byte indexHigh = br.ReadByte();
                    int indexLow = br.ReadInt32BE();

                    info.Index = (indexHigh << 2 | (byte)((indexLow & 0xC0000000) >> 30));
                    info.Offset = (indexLow & 0x3FFFFFFF);
                    info.Size = br.ReadInt32();

                    // duplicate keys wtf...
                    //IndexData[key] = info; // use last key
                    if (!LocalIndexData.ContainsKey(key)) // use first key
                        LocalIndexData.Add(key, info);
                }

                padPos = (dataLen + 0x0FFF) & 0xFFFFF000;
                fs.Position = padPos;

                fs.Position += numBlocks * 18;
                //for (int i = 0; i < numBlocks; i++)
                //{
                //    var bytes = br.ReadBytes(18); // unknown data
                //}

                //if (fs.Position != fs.Length)
                //    throw new Exception("idx file under read");
            }
        }
Exemple #4
0
        private CASCHandler(CASCConfig config, CDNHandler cdn, BackgroundWorker worker)
        {
            this.config = config;
            this.cdn = cdn;
            if (!config.OnlineMode)
            {
                var idxFiles = GetIdxFiles(this.config.BasePath);

                if (idxFiles.Count == 0)
                    throw new FileNotFoundException("idx files missing!");

                if (worker != null) worker.ReportProgress(0);

                int idxIndex = 0;

                foreach (var idx in idxFiles)
                {
                    using (var fs = new FileStream(idx, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    using (var br = new BinaryReader(fs))
                    {
                        int h2Len = br.ReadInt32();
                        int h2Check = br.ReadInt32();
                        byte[] h2 = br.ReadBytes(h2Len);

                        long padPos = (8 + h2Len + 0x0F) & 0xFFFFFFF0;
                        fs.Position = padPos;

                        int dataLen = br.ReadInt32();
                        int dataCheck = br.ReadInt32();

                        int numBlocks = dataLen / 18;

                        for (int i = 0; i < numBlocks; i++)
                        {
                            IndexEntry info = new IndexEntry();
                            byte[] key = br.ReadBytes(9);
                            int indexHigh = br.ReadByte();
                            int indexLow = br.ReadInt32BE();

                            info.Index = (int)((byte)(indexHigh << 2) | ((indexLow & 0xC0000000) >> 30));
                            info.Offset = (indexLow & 0x3FFFFFFF);
                            info.Size = br.ReadInt32();

                            // duplicate keys wtf...
                            //IndexData[key] = info; // use last key
                            if (!LocalIndexData.ContainsKey(key)) // use first key
                                LocalIndexData.Add(key, info);
                        }

                        padPos = (dataLen + 0x0FFF) & 0xFFFFF000;
                        fs.Position = padPos;

                        fs.Position += numBlocks * 18;
                        //for (int i = 0; i < numBlocks; i++)
                        //{
                        //    var bytes = br.ReadBytes(18); // unknown data
                        //}

                        if (fs.Position != fs.Position)
                            throw new Exception("idx file under read");
                    }

                    if (worker != null) worker.ReportProgress((int)((float)++idxIndex / (float)idxFiles.Count * 100));
                }

                Logger.WriteLine("CASCHandler: loaded {0} indexes", LocalIndexData.Count);
            }

            if (worker != null) worker.ReportProgress(0);

            using (var fs = OpenEncodingFile())
            using (var br = new BinaryReader(fs))
            {
                br.ReadBytes(2); // EN
                byte b1 = br.ReadByte();
                byte b2 = br.ReadByte();
                byte b3 = br.ReadByte();
                ushort s1 = br.ReadUInt16();
                ushort s2 = br.ReadUInt16();
                int numEntries = br.ReadInt32BE();
                int i1 = br.ReadInt32BE();
                byte b4 = br.ReadByte();
                int entriesOfs = br.ReadInt32BE();

                fs.Position += entriesOfs; // skip strings

                fs.Position += numEntries * 32;
                //for (int i = 0; i < numEntries; ++i)
                //{
                //    br.ReadBytes(16);
                //    br.ReadBytes(16);
                //}

                for (int i = 0; i < numEntries; ++i)
                {
                    ushort keysCount;

                    while ((keysCount = br.ReadUInt16()) != 0)
                    {
                        int fileSize = br.ReadInt32BE();
                        byte[] md5 = br.ReadBytes(16);

                        var entry = new EncodingEntry();
                        entry.Size = fileSize;

                        for (int ki = 0; ki < keysCount; ++ki)
                        {
                            byte[] key = br.ReadBytes(16);

                            entry.Keys.Add(key);
                        }

                        //Encodings[md5] = entry;
                        EncodingData.Add(md5, entry);
                    }

                    //br.ReadBytes(28);
                    while (br.PeekChar() == 0)
                        fs.Position++;

                    if (worker != null) worker.ReportProgress((int)((float)fs.Position / (float)fs.Length * 100));
                }
                //var pos = br.BaseStream.Position;
                //for (int i = 0; i < i1; ++i)
                //{
                //    br.ReadBytes(16);
                //    br.ReadBytes(16);
                //}
                Logger.WriteLine("CASCHandler: loaded {0} encoding data", EncodingData.Count);
            }

            if (worker != null) worker.ReportProgress(0);

            using (var fs = OpenRootFile())
            using (var br = new BinaryReader(fs))
            {
                while (fs.Position < fs.Length)
                {
                    int count = br.ReadInt32();

                    RootBlock block = new RootBlock();
                    block.Unk1 = br.ReadUInt32();
                    block.Flags = (LocaleFlags)br.ReadUInt32();

                    if (block.Flags == LocaleFlags.None)
                        throw new Exception("block.Flags == LocaleFlags.None");

                    RootEntry[] entries = new RootEntry[count];

                    for (var i = 0; i < count; ++i)
                    {
                        entries[i] = new RootEntry();
                        entries[i].Block = block;
                        entries[i].Unk1 = br.ReadInt32();
                    }

                    for (var i = 0; i < count; ++i)
                    {
                        entries[i].MD5 = br.ReadBytes(16);

                        ulong hash = br.ReadUInt64();
                        entries[i].Hash = hash;

                        // don't load other locales
                        //if (block.Flags != LocaleFlags.All && (block.Flags & LocaleFlags.enUS) == 0)
                        //    continue;

                        if (!RootData.ContainsKey(hash))
                        {
                            RootData[hash] = new List<RootEntry>();
                            RootData[hash].Add(entries[i]);
                        }
                        else
                            RootData[hash].Add(entries[i]);
                    }

                    if (worker != null) worker.ReportProgress((int)((float)fs.Position / (float)fs.Length * 100));
                }

                Logger.WriteLine("CASCHandler: loaded {0} root data", RootData.Count);
            }

            if (worker != null) worker.ReportProgress(0);
        }
        private unsafe void ParseIndex(string idx)
        {
            using (var fs = new FileStream(idx, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            using (var br = new BinaryReader(fs))
            {
                int h2Len = br.ReadInt32();
                int h2Check = br.ReadInt32();
                byte[] h2 = br.ReadBytes(h2Len);

                long padPos = (8 + h2Len + 0x0F) & 0xFFFFFFF0;
                fs.Position = padPos;

                int dataLen = br.ReadInt32();
                int dataCheck = br.ReadInt32();

                int numBlocks = dataLen / 18;

                //byte[] buf = new byte[8];

                for (int i = 0; i < numBlocks; i++)
                {
                    IndexEntry info = new IndexEntry();
                    byte[] keyBytes = br.ReadBytes(9);
                    Array.Resize(ref keyBytes, 16);

                    MD5Hash key;

                    fixed (byte *ptr = keyBytes)
                        key = *(MD5Hash*)ptr;

                    byte indexHigh = br.ReadByte();
                    int indexLow = br.ReadInt32BE();

                    info.Index = (indexHigh << 2 | (byte)((indexLow & 0xC0000000) >> 30));
                    info.Offset = (indexLow & 0x3FFFFFFF);

                    //for (int j = 3; j < 8; j++)
                    //    buf[7 - j] = br.ReadByte();

                    //long val = BitConverter.ToInt64(buf, 0);
                    //info.Index = (int)(val / 0x40000000);
                    //info.Offset = (int)(val % 0x40000000);

                    info.Size = br.ReadInt32();

                    // duplicate keys wtf...
                    //IndexData[key] = info; // use last key
                    if (!LocalIndexData.ContainsKey(key)) // use first key
                        LocalIndexData.Add(key, info);
                }

                padPos = (dataLen + 0x0FFF) & 0xFFFFF000;
                fs.Position = padPos;

                fs.Position += numBlocks * 18;
                //for (int i = 0; i < numBlocks; i++)
                //{
                //    var bytes = br.ReadBytes(18); // unknown data
                //}

                //if (fs.Position != fs.Length)
                //    throw new Exception("idx file under read");
            }
        }
        public Stream OpenDataFile(IndexEntry entry)
        {
            var archive = config.Archives[entry.Index];

            string file = config.CDNPath + "/data/" + archive.Substring(0, 2) + "/" + archive.Substring(2, 2) + "/" + archive;
            string url = "http://" + config.CDNHost + "/" + file;

            Stream stream = Cache.OpenFile(file, url, true);

            if (stream != null)
            {
                stream.Position = entry.Offset;
                MemoryStream ms = new MemoryStream(entry.Size);
                stream.CopyBytes(ms, entry.Size);
                ms.Position = 0;
                return ms;
            }

            //using (HttpClient client = new HttpClient())
            //{
            //    client.DefaultRequestHeaders.Range = new RangeHeaderValue(entry.Offset, entry.Offset + entry.Size - 1);

            //    var resp = client.GetStreamAsync(url).Result;

            //    MemoryStream ms = new MemoryStream(entry.Size);
            //    resp.CopyBytes(ms, entry.Size);
            //    ms.Position = 0;
            //    return ms;
            //}

            HttpWebRequest req = WebRequest.CreateHttp(url);
            //req.Headers[HttpRequestHeader.Range] = string.Format("bytes={0}-{1}", entry.Offset, entry.Offset + entry.Size - 1);
            req.AddRange(entry.Offset, entry.Offset + entry.Size - 1);
            using (HttpWebResponse resp = (HttpWebResponse)req.GetResponseAsync().Result)
            {
                MemoryStream ms = new MemoryStream(entry.Size);
                resp.GetResponseStream().CopyBytes(ms, entry.Size);
                ms.Position = 0;
                return ms;
            }
        }
        public Stream OpenDataFile(IndexEntry entry)
        {
            var archive = CASCConfig.Archives[entry.Index];

            string file = CASCConfig.CDNPath + "/data/" + archive.Substring(0, 2) + "/" + archive.Substring(2, 2) + "/" + archive;
            string url = "http://" + CASCConfig.CDNHost + "/" + file;

            Stream stream = Cache.OpenFile(file, url, true);

            if (stream != null)
            {
                stream.Position = entry.Offset;
                MemoryStream ms = new MemoryStream(entry.Size);
                stream.CopyBytes(ms, entry.Size);
                ms.Position = 0;
                return ms;
            }

            HttpWebRequest req = WebRequest.CreateHttp(url);
            req.AddRange(entry.Offset, entry.Offset + entry.Size - 1);
            using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
            {
                MemoryStream ms = new MemoryStream(entry.Size);
                resp.GetResponseStream().CopyBytes(ms, entry.Size);
                ms.Position = 0;
                return ms;
            }
        }
        protected Stream GetLocalDataStreamInternal(IndexEntry idxInfo, MD5Hash key)
        {
            if (idxInfo == null)
                throw new Exception("local index missing");

            Stream dataStream = GetDataStream(idxInfo.Index);
            dataStream.Position = idxInfo.Offset;

            using (BinaryReader reader = new BinaryReader(dataStream, Encoding.ASCII, true))
            {
                byte[] md5 = reader.ReadBytes(16);
                Array.Reverse(md5);

                if (!key.EqualsTo(md5))
                    throw new Exception("local data corrupted");

                int size = reader.ReadInt32();

                if (size != idxInfo.Size)
                    throw new Exception("local data corrupted");

                //byte[] unkData1 = reader.ReadBytes(2);
                //byte[] unkData2 = reader.ReadBytes(8);
                dataStream.Position += 10;

                byte[] data = reader.ReadBytes(idxInfo.Size - 30);

                return new MemoryStream(data);
            }
        }
 protected void ExtractFileOnlineInternal(IndexEntry idxInfo, MD5Hash key, string path, string name)
 {
     if (idxInfo != null)
     {
         using (Stream s = CDNIndex.OpenDataFile(idxInfo))
         using (BLTEStream blte = new BLTEStream(s, key))
         {
             blte.ExtractToFile(path, name);
         }
     }
     else
     {
         using (Stream s = CDNIndex.OpenDataFileDirect(key))
         using (BLTEStream blte = new BLTEStream(s, key))
         {
             blte.ExtractToFile(path, name);
         }
     }
 }
Exemple #10
0
        public CASCHandler(CASCFolder root, BackgroundWorker worker)
        {
            if (!OnlineMode)
            {
                var idxFiles = GetIdxFiles(Properties.Settings.Default.WowPath);

                if (idxFiles.Count == 0)
                    throw new FileNotFoundException("idx files missing!");

                worker.ReportProgress(0);

                int idxIndex = 0;

                foreach (var idx in idxFiles)
                {
                    using (var fs = new FileStream(idx, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    using (var br = new BinaryReader(fs))
                    {
                        int h2Len = br.ReadInt32();
                        int h2Check = br.ReadInt32();
                        byte[] h2 = br.ReadBytes(h2Len);

                        long padPos = (8 + h2Len + 0x0F) & 0xFFFFFFF0;
                        fs.Position = padPos;

                        int dataLen = br.ReadInt32();
                        int dataCheck = br.ReadInt32();

                        int numBlocks = dataLen / 18;

                        for (int i = 0; i < numBlocks; i++)
                        {
                            IndexEntry info = new IndexEntry();
                            byte[] key = br.ReadBytes(9);
                            int indexHigh = br.ReadByte();
                            int indexLow = br.ReadInt32BE();

                            info.Index = (int)((byte)(indexHigh << 2) | ((indexLow & 0xC0000000) >> 30));
                            info.Offset = (indexLow & 0x3FFFFFFF);
                            info.Size = br.ReadInt32();

                            // duplicate keys wtf...
                            //IndexData[key] = info; // use last key
                            if (!LocalIndexData.ContainsKey(key)) // use first key
                                LocalIndexData.Add(key, info);
                        }

                        padPos = (dataLen + 0x0FFF) & 0xFFFFF000;
                        fs.Position = padPos;

                        fs.Position += numBlocks * 18;
                        //for (int i = 0; i < numBlocks; i++)
                        //{
                        //    var bytes = br.ReadBytes(18); // unknown data
                        //}

                        if (fs.Position != fs.Position)
                            throw new Exception("idx file under read");
                    }

                    worker.ReportProgress((int)((float)++idxIndex / (float)idxFiles.Count * 100));
                }

                Logger.WriteLine("CASCHandler: loaded {0} indexes", LocalIndexData.Count);
            }

            worker.ReportProgress(0);

            using (var fs = OpenEncodingFile())
            using (var br = new BinaryReader(fs))
            {
                br.ReadBytes(2); // EN
                byte b1 = br.ReadByte();
                byte b2 = br.ReadByte();
                byte b3 = br.ReadByte();
                ushort s1 = br.ReadUInt16();
                ushort s2 = br.ReadUInt16();
                int numEntries = br.ReadInt32BE();
                int i1 = br.ReadInt32BE();
                byte b4 = br.ReadByte();
                int entriesOfs = br.ReadInt32BE();

                fs.Position += entriesOfs; // skip strings

                fs.Position += numEntries * 32;
                //for (int i = 0; i < numEntries; ++i)
                //{
                //    br.ReadBytes(16);
                //    br.ReadBytes(16);
                //}

                for (int i = 0; i < numEntries; ++i)
                {
                    ushort keysCount;

                    while ((keysCount = br.ReadUInt16()) != 0)
                    {
                        int fileSize = br.ReadInt32BE();
                        byte[] md5 = br.ReadBytes(16);

                        var entry = new EncodingEntry();
                        entry.Size = fileSize;

                        for (int ki = 0; ki < keysCount; ++ki)
                        {
                            byte[] key = br.ReadBytes(16);

                            entry.Keys.Add(key);
                        }

                        //Encodings[md5] = entry;
                        EncodingData.Add(md5, entry);
                    }

                    //br.ReadBytes(28);
                    while (br.PeekChar() == 0)
                        fs.Position++;

                    worker.ReportProgress((int)((float)fs.Position / (float)fs.Length * 100));
                }
                //var pos = br.BaseStream.Position;
                //for (int i = 0; i < i1; ++i)
                //{
                //    br.ReadBytes(16);
                //    br.ReadBytes(16);
                //}
                Logger.WriteLine("CASCHandler: loaded {0} encoding data", EncodingData.Count);
            }

            worker.ReportProgress(0);

            using (var fs = OpenRootFile())
            using (var br = new BinaryReader(fs))
            {
                while (fs.Position < fs.Length)
                {
                    int count = br.ReadInt32();

                    RootBlock block = new RootBlock();
                    block.Unk1 = br.ReadUInt32();
                    block.Flags = (LocaleFlags)br.ReadUInt32();

                    if (block.Flags == LocaleFlags.None)
                        throw new Exception("block.Flags == LocaleFlags.None");

                    RootEntry[] entries = new RootEntry[count];

                    for (var i = 0; i < count; ++i)
                    {
                        entries[i] = new RootEntry();
                        entries[i].Block = block;
                        entries[i].Unk1 = br.ReadInt32();
                    }

                    for (var i = 0; i < count; ++i)
                    {
                        entries[i].MD5 = br.ReadBytes(16);

                        ulong hash = br.ReadUInt64();
                        entries[i].Hash = hash;

                        // don't load other locales
                        //if (block.Flags != LocaleFlags.All && (block.Flags & LocaleFlags.enUS) == 0)
                        //    continue;

                        if (!RootData.ContainsKey(hash))
                        {
                            RootData[hash] = new List<RootEntry>();
                            RootData[hash].Add(entries[i]);
                        }
                        else
                            RootData[hash].Add(entries[i]);
                    }

                    worker.ReportProgress((int)((float)fs.Position / (float)fs.Length * 100));
                }

                Logger.WriteLine("CASCHandler: loaded {0} root data", RootData.Count);
            }

            worker.ReportProgress(0);

            if (File.Exists(listFile))
            {
                FolderNames[Hasher.ComputeHash("root")] = "root";

                using (StreamReader sr = new StreamReader(listFile))
                {
                    string file;
                    int filesCount = 0;

                    CASCFolder folder = root;

                    while ((file = sr.ReadLine()) != null)
                    {
                        ulong fileHash = Hasher.ComputeHash(file);

                        // skip invalid names
                        if (!RootData.ContainsKey(fileHash))
                        {
                            Logger.WriteLine("Invalid file name: {0}", file);
                            continue;
                        }

                        filesCount++;

                        string[] parts = file.Split('\\');

                        for (int i = 0; i < parts.Length; ++i)
                        {
                            bool isFile = (i == parts.Length - 1);

                            ulong hash = isFile ? fileHash : Hasher.ComputeHash(parts[i]);

                            ICASCEntry entry = folder.GetEntry(hash);

                            if (entry == null)
                            {
                                if (isFile)
                                {
                                    entry = new CASCFile(hash);
                                    FileNames[hash] = file;
                                }
                                else
                                {
                                    entry = new CASCFolder(hash);
                                    FolderNames[hash] = parts[i];
                                }

                                folder.SubEntries[hash] = entry;

                                if (isFile)
                                {
                                    folder = root;
                                    break;
                                }
                            }

                            folder = entry as CASCFolder;
                        }

                        if ((filesCount % 1000) == 0)
                            worker.ReportProgress((int)((float)sr.BaseStream.Position / (float)sr.BaseStream.Length * 100));
                    }

                    Logger.WriteLine("CASCHandler: loaded {0} file names", FileNames.Count);
                }
            }
            else
            {
                throw new FileNotFoundException("list file missing!");
            }
        }