private bool TestBundleForIDStrings(string bundle_id)
        {
            string bundle_id_path = Path.Combine(StaticStorage.settings.AssetsFolder, bundle_id);
            if (!File.Exists(Path.Combine(StaticStorage.settings.AssetsFolder, bundle_id + ".bundle")) || !File.Exists(Path.Combine(StaticStorage.settings.AssetsFolder, bundle_id + "_h.bundle")))
                return false;

            BundleHeader bundle = new BundleHeader();
            if (!bundle.Load(bundle_id_path))
            {
                StaticStorage.log.writeLine(string.Format("[Update error] Failed to parse bundle header. ({0})", bundle_id));
                return false;
            }

            string bundle_file = bundle_id_path + ".bundle";
            if (!File.Exists(bundle_file))
            {
                StaticStorage.log.writeLine(String.Format("[Update error] Bundle file does not exist. ({0})", bundle_file));
                return false;
            }

            foreach (BundleEntry be in bundle.Entries)
            {
                NameEntry ne = StaticStorage.Index.Id2Name(be.Id);

                if (ne != null && ne.Path == 0x9234DD22C60D71B8 && ne.Extension == 0x9234DD22C60D71B8)
                {
                    return true;
                }
            }
            return false;
        }
        public bool RetrieveHashlist()
        {
            HashSet<string> new_paths = new HashSet<string>();
            HashSet<string> new_exts = new HashSet<string>();
            HashSet<string> new_other = new HashSet<string>();
            StringBuilder sb = new StringBuilder();
            string[] known_bundles = { "all_7", "all_0", "all_14" }; //Payday: The Heist, Payday 2 Demo, Payday 2

            string[] idstring_data;

            foreach (string bundle_id in known_bundles)
            {
                string bundle_id_path = Path.Combine(StaticStorage.settings.AssetsFolder, bundle_id);
                if (!File.Exists(Path.Combine(StaticStorage.settings.AssetsFolder, bundle_id + ".bundle")) || !File.Exists(Path.Combine(StaticStorage.settings.AssetsFolder, bundle_id + "_h.bundle")))
                    continue;

                BundleHeader bundle = new BundleHeader();
                if (!bundle.Load(bundle_id_path))
                {
                    StaticStorage.log.writeLine(string.Format("[Update error] Failed to parse bundle header. ({0})", bundle_id));
                    return false;
                }

                string bundle_file = bundle_id_path + ".bundle";
                if (!File.Exists(bundle_file))
                {
                    StaticStorage.log.writeLine(string.Format("[Update error] Bundle file does not exist. ({0})", bundle_file));
                    return false;
                }
                using (FileStream fs = new FileStream(bundle_file, FileMode.Open, FileAccess.Read))
                {
                    using (BinaryReader br = new BinaryReader(fs))
                    {
                        byte[] data;
                        foreach (BundleEntry be in bundle.Entries)
                        {
                            NameEntry ne = StaticStorage.Index.Id2Name(be.Id);
                            if (ne == null)
                                continue;

                            if (ne.Path == 0x9234DD22C60D71B8 && ne.Extension == 0x9234DD22C60D71B8)
                            {
                                fs.Position = be.Address;
                                if (be.Length == -1)
                                    data = br.ReadBytes((int)(fs.Length - fs.Position));
                                else
                                    data = br.ReadBytes((int)be.Length);

                                foreach (byte read in data)
                                    sb.Append((char)read);

                                idstring_data = sb.ToString().Split('\0');
                                sb.Clear();

                                foreach (string idstring in idstring_data)
                                {
                                    if (idstring.Contains("/"))
                                        new_paths.Add(idstring);
                                    else if (!idstring.Contains("/") && !idstring.Contains(".") && !idstring.Contains(":") && !idstring.Contains("\\"))
                                        new_exts.Add(idstring);
                                    else
                                        new_other.Add(idstring);
                                }

                                new_paths.Add("idstring_lookup");
                                new_paths.Add("existing_banks");

                                StaticStorage.Known_Index.Clear();
                                StaticStorage.Known_Index.Load(ref new_paths, ref new_exts, ref new_other);

                                StaticStorage.Known_Index.GenerateHashList(HashlistFile);

                                new_paths.Clear();
                                new_exts.Clear();

                                return true;
                            }
                        }
                        br.Close();
                    }
                    fs.Close();
                }
            }
            return false;
        }
        /// <summary>
        /// The retrieve file from bundle.
        /// </summary>
        /// <param name="bundleId">
        /// The bundle id.
        /// </param>
        /// <param name="data">
        /// The file data.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        private bool RetrieveFile(string bundleId, out MemoryStream data)
        {
            data = new MemoryStream();
            var inHeader = new BundleHeader();
            if (!inHeader.Load(Path.Combine(this._assetFolder, "asset_backups", bundleId)))
                return false;

            var inBundle = new FileStream(Path.Combine(this._assetFolder, bundleId + ".bundle"), FileMode.Open, FileAccess.Read);
            var inBundleBinary = new BinaryReader(inBundle);
            int currentEntry = 1;
            int entryCount = inHeader.Entries.Count;

            foreach (BundleEntry entry in inHeader.Entries)
            {
                if (currentEntry % 100 == 0)
                {
                    this.SetBundleProgress(
                        string.Format("Reading entry {0}/{1}", currentEntry, entryCount),
                        (int)((currentEntry / (float)entryCount) * 100.0f));
                }

                if (this._rewriteItems.ContainsKey(entry.Id))
                {
                    inBundle.Seek(entry.Address, SeekOrigin.Begin);
                    long readLength = entry.Length == -1 ? inBundle.Length - inBundle.Position : entry.Length;
                    data.Write(inBundleBinary.ReadBytes((int)readLength), 0, (int)readLength);
                    break;
                }
                currentEntry += 1;
            }

            inBundleBinary.Close();
            inBundle.Close();

            this.SetBundleProgress("Done", 100);
            return true;
        }
        public void StartBundle()
        {
            if (!String.IsNullOrWhiteSpace(StaticStorage.settings.ListLogFile))
            {
                listlog = StaticStorage.settings.ListLogFile;
            }
            else
            {
                listlog = "./listlog.log";
            }

            string extract_folder;
            if (String.IsNullOrWhiteSpace(StaticStorage.settings.CustomExtractPath))
            {
                if (!Directory.Exists(Path.Combine(StaticStorage.settings.AssetsFolder, "extract")))
                {
                    Directory.CreateDirectory(Path.Combine(StaticStorage.settings.AssetsFolder, "extract"));
                }
                extract_folder = Path.Combine(StaticStorage.settings.AssetsFolder, "extract");
            }
            else
            {
                extract_folder = StaticStorage.settings.CustomExtractPath;
            }

            TextWriteLine("Loading blb index...");

            if (!TestAssetsFolder())
            {
                //this.StartExtracting.Enabled = true;
                MessageBox.Show("Failed to parse bundle_db.blb. Are you sure the path is valid and the file is not corrupt?");
                TextWriteLine("Failed to parse bundle_db.blb. Are you sure the path is valid and the file is not corrupt?");

                //Finished = true;
                return;
            }

            //You don't need to clear them, they're loaded once and done.
            //KnownIndex.Clear();
            //NameIndex.Clear();
            TextWriteLine("Paths and Extensions Updated Successfully");
            listlogger = new StreamWriter(listlog, true);
            if (extract_one && extract_id.Length > 0)
            {
                bundle = new BundleHeader();
                if (!bundle.Load(Path.Combine(StaticStorage.settings.AssetsFolder, extract_id)))
                {
                    MessageBox.Show("Failed to parse bundle header.");
                    TextWriteLine("Failed to parse bundle header.");
                    //Finished = true;
                    return;
                }
                if (StaticStorage.settings.List || StaticStorage.settings.ListData)
                {
                    current_bundle = 0;
                    total_bundle = 1;
                    progress = 0;
                    ListBundle(Path.Combine(StaticStorage.settings.AssetsFolder, extract_id));
                    current_bundle = 1;
                    total_bundle = 1;
                    progress = 100;
                    //Finished = true;
                }
                else
                {
                    current_bundle = 0;
                    total_bundle = 1;
                    progress = 0;
                    TextWriteLine("Extract bundle: " + extract_id);
                    ExtractBundle(extract_id);
                    current_bundle = 1;
                    total_bundle = 1;
                    progress = 100;
                    //Finished = true;
                }
            }
            else
            {
                int TotalBundles = 0;
                int CurrentBundle = 0;
                //float Division = 100.0f;
                TotalBundles = Directory.EnumerateFiles(StaticStorage.settings.AssetsFolder, "*_h.bundle").Count();
                current_bundle = 0;
                total_bundle = (uint)TotalBundles;
                progress = (uint)(((float)CurrentBundle / TotalBundles) * 100);
                foreach (string file in Directory.EnumerateFiles(StaticStorage.settings.AssetsFolder, "*_h.bundle"))
                {
                    string bundle_id = file.Replace("_h.bundle", "");
                    bundle_id = Path.GetFileName(bundle_id);

                    string bundle_path = file.Replace("_h.bundle", "");
                    //Console.WriteLine(bundle_id);
                    bundle = new BundleHeader();
                    TextWriteLine("Loading bundle header " + bundle_id);
                    if (!bundle.Load(bundle_path))
                    {
                        MessageBox.Show("Failed to parse bundle header.");
                        TextWriteLine("Failed to parse bundle header.");
                        //TextWriteLine("Done");
                        return;
                    }
                    if (StaticStorage.settings.List || StaticStorage.settings.ListData)
                    {
                        //TextWriteLine("List Only");
                        ListBundle(bundle_path);
                        CurrentBundle++;
                        current_bundle = (uint)CurrentBundle;
                        total_bundle = (uint)TotalBundles;
                        progress = (uint)(((float)CurrentBundle / TotalBundles) * 100);
                    }
                    else
                    {
                        TextWriteLine("Extracting bundle: " + bundle_id);
                        ExtractBundle(bundle_id);
                        //TextWriteLine("Extraction Done");
                        CurrentBundle++;
                        current_bundle = (uint)CurrentBundle;
                        total_bundle = (uint)TotalBundles;
                        progress = (uint)(((float)CurrentBundle / TotalBundles) * 100);
                    }
                }
            }
            //DialogResult dialogResult = MessageBox.Show("Finished", "Finished", MessageBoxButtons.OK);
            //if (dialogResult == DialogResult.OK)
            //{
                //Finished = true;
            //}
            listlogger.Close();
            listlogger = null;
        }
        /// <summary>
        /// The patch bundle.
        /// </summary>
        /// <param name="bundleId">
        /// The bundle id.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        private bool PatchBundle(string bundleId)
        {
            System.Diagnostics.Stopwatch st_total = new System.Diagnostics.Stopwatch();
            System.Diagnostics.Stopwatch st_entry = new System.Diagnostics.Stopwatch();
            System.Diagnostics.Stopwatch st_writing = new System.Diagnostics.Stopwatch();

            bool isAll = bundleId.Contains("all_");
            var inHeader = new BundleHeader();
            if (!inHeader.Load(Path.Combine(this._assetFolder, bundleId)))
            {
                return false;
            }

            var outHeader = new BundleHeader();
            outHeader.Footer = inHeader.Footer;
            outHeader.Header = inHeader.Header;
            outHeader.HasLengthField = inHeader.HasLengthField;
            var inBundle = new FileStream(Path.Combine(this._assetFolder, bundleId + ".bundle"), FileMode.Open, FileAccess.Read);
            var outBundle = new FileStream(
                Path.Combine(this._assetFolder, bundleId + ".bundle.new"),
                FileMode.Create,
                FileAccess.ReadWrite);
            //BufferedStream bsin = new BufferedStream(inBundle);
            //BufferedStream bsout = new BufferedStream(outBundle);
            var br = new BinaryReader(inBundle);
            var bw = new BinaryWriter(outBundle);
            long inFileLength = inBundle.Length;
            int currentAddress = 0;
            int currentEntry = 1;
            int entryCount = inHeader.Entries.Count;

            //stream buffers
            //int bufferSize = 4096; //1024^2
            byte[] buffer = new byte[this.bufferSize];

            if (isAll)
                inHeader.SortEntriesAddress();

            foreach (BundleEntry entry in inHeader.Entries)
            {
                st_total.Restart();
                st_entry.Restart();

                if (currentEntry % 100 == 0)
                {
                    this.SetBundleProgress(
                        string.Format("Writing entry {0}/{1}", currentEntry, entryCount),
                        (int)((currentEntry / (float)entryCount) * 100.0f));
                }

                var newEntry = new BundleEntry();
                newEntry.Id = entry.Id;
                newEntry.Length = entry.Length;
                newEntry.Address = (uint)currentAddress;
                bool replaced = false;
                bool firstpatched = false;
                bool restore = false;

                if (this._rewriteItems.ContainsKey(entry.Id))
                {
                    if (this._rewriteItems[entry.Id].toRestore)
                        restore = true;

                    MemoryStream newData = new MemoryStream();

                    if (restore)
                    {
                        if (this._backupType == 0)
                        {
                            var inRestoreBundle = new FileStream(Path.Combine(this._assetFolder, "asset_backups", bundleId + ".bundle"), FileMode.Open, FileAccess.Read);
                            var inRestoreHeader = new BundleHeader();
                            if (!inRestoreHeader.Load(Path.Combine(this._assetFolder, "asset_backups", bundleId)))
                                return false;

                            foreach (BundleEntry restoreEntry in inRestoreHeader.Entries)
                            {
                                if (restoreEntry.Id == entry.Id)
                                {
                                    newEntry.Length = this.RestoreEntry(restoreEntry, 0, inRestoreBundle, newData);
                                    replaced = true;
                                    break;
                                }
                            }
                        }
                        else
                        {
                            NameEntry ne = StaticStorage.Index.Id2Name(entry.Id);
                            if (File.Exists(Path.Combine(this._assetFolder, "asset_backups", ne.ToString())))
                            {
                                using (FileStream importFS = new FileStream(Path.Combine(this._assetFolder, "asset_backups", ne.ToString()), FileMode.Open, FileAccess.Read))
                                {
                                    using (BinaryReader importBR = new BinaryReader(importFS))
                                    {
                                        newEntry.Length = (int)importFS.Length;

                                        newData.Seek(0, SeekOrigin.Begin);
                                        newData.Write(importBR.ReadBytes((int)importFS.Length), 0, (int)importFS.Length);
                                        replaced = true;
                                    }
                                }

                            }
                            else
                            {
                                return false;
                            }
                        }
                    }

                    if (this._rewriteItems[entry.Id].priorityBundleRewriteItem != new BundleRewriteItem())
                    {
                        newEntry.Length = this.WriteZipEntry(entry, inBundle, newData, this._rewriteItems[entry.Id].priorityBundleRewriteItem);
                        firstpatched = true;
                        replaced = true;
                    }

                    foreach (var rewriteItem in this._rewriteItems[entry.Id].BundleRewriteItem_queue)
                    {
                        if (rewriteItem.toRemove)
                            continue;

                        if (!firstpatched)
                        {
                            newEntry.Length = this.WriteZipEntry(entry, inBundle, newData, rewriteItem);
                            firstpatched = true;
                        }
                        else
                        {
                            newEntry.Length = this.WriteZipEntry(newEntry, newData, newData, rewriteItem);
                        }

                        replaced = true;
                    }

                    if (newData.Length > 0L)
                    {

                        //buffer = new byte[megabyte];
                        newData.Position = 0L;
                        int bytesRead = newData.Read(buffer, 0, this.bufferSize);
                        while (bytesRead > 0)
                        {
                            outBundle.Write(buffer, 0, bytesRead);
                            bytesRead = newData.Read(buffer, 0, this.bufferSize);
                        }

                        //outBundle.Seek(currentAddress, SeekOrigin.Begin);
                        //newData.CopyTo(outBundle);
                    }

                }

                st_entry.Stop();
                st_writing.Restart();

                if (replaced)
                    currentAddress += newEntry.Length;

                outHeader.Entries.Add(newEntry);

                if (!replaced)
                {
                    /*
                        inBundle.Seek(entry.Address, SeekOrigin.Begin);
                        long entryLength = entry.Length == -1 ? inBundle.Length - inBundle.Position : entry.Length;
                        var br = new BinaryReader(inBundle);
                        var bw = new BinaryWriter(outBundle);
                        bw.Write(br.ReadBytes((int)entryLength));
                        currentAddress += (int)entryLength;
                     */

                    //inBundle.Seek(entry.Address, SeekOrigin.Begin);
                    inBundle.Seek((long)entry.Address, SeekOrigin.Begin);
                    long entryLength = (entry.Length == -1 ? inFileLength - (long)entry.Address : (long)entry.Length);
                    int remaining = (int)entryLength;
                    int totalread = 0;
                    //buffer = new byte[megabyte];
                    //bw.Write(br.ReadBytes((int)entryLength));

                    int bytesRead = inBundle.Read(buffer, 0, (((remaining - totalread) / this.bufferSize) > 0 ? this.bufferSize : remaining - totalread));
                    totalread += bytesRead;
                    while (bytesRead > 0 && totalread <= remaining)
                    {
                        bw.Write(buffer, 0, bytesRead);
                        bytesRead = inBundle.Read(buffer, 0, (((remaining - totalread) / this.bufferSize) > 0 ? this.bufferSize : remaining - totalread));
                        totalread += bytesRead;
                    }
                    //bw.Flush();

                    currentAddress += (int)entryLength;
                }

                currentEntry += 1;
                CurrentEntryCount++;
                SpeedEntryCount++;

                st_writing.Stop();
                st_total.Stop();
                if (st_total.ElapsedMilliseconds > 200)
                    Console.WriteLine(bundleId + " - T: " + st_total.ElapsedMilliseconds + " ms. [entry: " + st_entry.ElapsedMilliseconds + " ms. writing: " + st_writing.ElapsedMilliseconds + " ms.] with " + newEntry.Length + " for replaced " + replaced);
            }

            bw.Flush();
            inBundle.Close();
            outBundle.Close();

            if (isAll)
                outHeader.SortEntriesId();
            var outHeaderStream = new FileStream(
                Path.Combine(this._assetFolder, bundleId + "_h.bundle"),
                FileMode.OpenOrCreate,
                FileAccess.Write);
            var outHeaderBr = new BinaryWriter(outHeaderStream);
            outHeader.WriteHeader(outHeaderBr);
            foreach (BundleEntry entry in outHeader.Entries)
            {
                entry.WriteEntry(outHeaderBr, outHeader.HasLengthField);
            }

            outHeader.WriteFooter(outHeaderBr);
            outHeaderBr.Close();
            outHeaderStream.Close();
            File.Delete(Path.Combine(this._assetFolder, bundleId + ".bundle"));
            File.Move(Path.Combine(this._assetFolder, bundleId + ".bundle.new"), Path.Combine(this._assetFolder, bundleId + ".bundle"));
            this.SetBundleProgress("Done", 100);
            return true;
        }
        /// <summary>
        /// The patch bundle restore.
        /// </summary>
        /// <param name="bundleId">
        /// The bundle id.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        private bool PatchBundleRestore(BundleMod mod, string bundleId, bool method)
        {
            if (method)
            {
                if (!File.Exists(Path.Combine(this._assetFolder, bundleId + ".bundle")) || !File.Exists(Path.Combine(this._assetFolder, bundleId + "_h.bundle")) || !File.Exists(Path.Combine(this._assetFolder, "asset_backups", bundleId + ".bundle")) || !File.Exists(Path.Combine(this._assetFolder, "asset_backups", bundleId + "_h.bundle")))
                    return false;

                File.Delete(Path.Combine(this._assetFolder, bundleId + ".bundle"));
                File.Delete(Path.Combine(this._assetFolder, bundleId + "_h.bundle"));
                File.Copy(Path.Combine(this._assetFolder, "asset_backups", bundleId + ".bundle"), Path.Combine(this._assetFolder, bundleId + ".bundle"), true);
                File.Copy(Path.Combine(this._assetFolder, "asset_backups", bundleId + "_h.bundle"), Path.Combine(this._assetFolder, bundleId + "_h.bundle"), true);
                this.SetBundleProgress("Done", 100);
                return true;
            }

            var inHeader = new BundleHeader();
            var inRestoreHeader = new BundleHeader();
            Dictionary<uint, BundleEntry> inRestoreDictionary = new Dictionary<uint, BundleEntry>();
            if (!inHeader.Load(Path.Combine(this._assetFolder, bundleId)))
            {
                return false;
            }

            if (!inRestoreHeader.Load(Path.Combine(this._assetFolder, "asset_backups", bundleId)))
                return false;

            foreach (BundleEntry entry in inRestoreHeader.Entries)
            {
                if (!inRestoreDictionary.ContainsKey(entry.Id))
                    inRestoreDictionary.Add(entry.Id, entry);
            }

            var outHeader = new BundleHeader();
            outHeader.Footer = inHeader.Footer;
            outHeader.Header = inHeader.Header;
            outHeader.HasLengthField = inHeader.HasLengthField;
            var inRestoreBundle = new FileStream(Path.Combine(this._assetFolder, "asset_backups", bundleId + ".bundle"), FileMode.Open, FileAccess.Read);
            var inBundle = new FileStream(Path.Combine(this._assetFolder, bundleId + ".bundle"), FileMode.Open, FileAccess.Read);
            var outBundle = new FileStream(
                Path.Combine(this._assetFolder, bundleId + ".bundle.new"),
                FileMode.OpenOrCreate,
                FileAccess.ReadWrite);
            int currentAddress = 0;
            int currentEntry = 1;
            int entryCount = inHeader.Entries.Count;
            foreach (BundleEntry entry in inHeader.Entries)
            {
                if (currentEntry % 100 == 0)
                {
                    this.SetBundleProgress(
                        string.Format("Writing entry {0}/{1}", currentEntry, entryCount),
                        (int)((currentEntry / (float)entryCount) * 100.0f));
                }

                var newEntry = new BundleEntry();
                newEntry.Id = entry.Id;
                newEntry.Length = entry.Length;
                newEntry.Address = (uint)currentAddress;
                bool replaced = false;

                foreach (int length in from rewriteItem in mod.ItemQueue
                                       where rewriteItem.Ids.Contains(entry.Id)
                                       select this.RestoreEntry(inRestoreDictionary[entry.Id], (uint)currentAddress, inRestoreBundle, outBundle))
                {
                    currentAddress += length;
                    newEntry.Length = length;
                    replaced = true;
                    break;
                }

                outHeader.Entries.Add(newEntry);

                if (!replaced)
                {
                    inBundle.Seek(entry.Address, SeekOrigin.Begin);
                    long entryLength = entry.Length == -1 ? inBundle.Length - inBundle.Position : entry.Length;
                    var br = new BinaryReader(inBundle);
                    var bw = new BinaryWriter(outBundle);
                    bw.Write(br.ReadBytes((int)entryLength));
                    currentAddress += (int)entryLength;
                }

                currentEntry += 1;
            }

            inBundle.Close();
            inRestoreBundle.Close();
            outBundle.Close();
            var outHeaderStream = new FileStream(
                Path.Combine(this._assetFolder, bundleId + "_h.bundle"),
                FileMode.OpenOrCreate,
                FileAccess.Write);
            var outHeaderBr = new BinaryWriter(outHeaderStream);
            outHeader.WriteHeader(outHeaderBr);
            foreach (BundleEntry entry in outHeader.Entries)
            {
                entry.WriteEntry(outHeaderBr, outHeader.HasLengthField);
            }

            outHeader.WriteFooter(outHeaderBr);
            outHeaderBr.Close();
            outHeaderStream.Close();
            File.Delete(Path.Combine(this._assetFolder, bundleId + ".bundle"));
            File.Move(Path.Combine(this._assetFolder, bundleId + ".bundle.new"), Path.Combine(this._assetFolder, bundleId + ".bundle"));
            this.SetBundleProgress("Done", 100);
            return true;
        }
        /// <summary>
        /// The locate bundles to rewrite.
        /// </summary>
        /// <param name="success">
        /// The success.
        /// </param>
        /// <returns>
        /// The <see cref="HashSet"/>.
        /// </returns>
        private HashSet<string> LocateBundlesToRewrite(out bool success)
        {
            success = false;
            var bundles = new HashSet<string>();
            this.SetTotalProgress("Determining Bundles To Modify", -1);
            List<string> files = Directory.EnumerateFiles(this._assetFolder, "*_h.bundle").ToList();

            for (int i = 0; i < files.Count; i++ )
            {
                string file = files[i];
                this.SetBundleProgress(
                        string.Format("Reviewing Bundle {0}/{1}", i, files.Count),
                        (int)((i / (float)files.Count) * 100.0f));

                string bundlePath = file.Replace("_h.bundle", string.Empty);
                var header = new BundleHeader();
                if (!header.Load(bundlePath))
                {
                    this.Error = "Failed to parse bundle header: " + bundlePath;
                    return bundles;
                }

                foreach (BundleEntry entry in header.Entries)
                {
                    bool found = false;
                    if (this._mod.ItemQueue.Any(rewriteItem => rewriteItem.Ids.Contains(entry.Id)))
                    {
                        bundles.Add(Path.GetFileNameWithoutExtension(bundlePath));
                        this.TotalEntryCount += header.Entries.Count;
                        found = true;
                    }

                    if (found)
                    {
                        break;
                    }
                }
            }

            this.SetBundleProgress("Done", 100);
            success = true;
            return bundles;
        }
        private void CheckBundle(string bundleId)
        {
            var bundleSize = new FileInfo(bundleId + ".bundle").Length;

            //repair can be attempted, no guarantees
            //repair.. it's f****d.

            var bundle = new BundleHeader();
            if (!bundle.Load(bundleId))
            {
                throw new Exception("Corrupted BundleHeader");
            }

            //repair can be attempted, no guarantees
            //repair would consist of checking against a backup, given it exists

            foreach (BundleEntry be in bundle.Entries)
            {
                NameEntry ne = StaticStorage.Index.Id2Name(be.Id);
                if (ne == null)
                {
                    throw new Exception("Invalid NameEntry");
                }

                if (be.Address + be.Length > bundleSize)
                {
                    throw new Exception("Attempt to read past end of bundle");
                }
            }

            //can be repaired
            //repair would consist of resorting the entries, given they are all valid

            if (Path.GetFileNameWithoutExtension(bundleId).StartsWith("all_"))
            {
                //it's an all_ bundle... BundleHeader items should be sorted by Address (length 0 first)

                uint prevID = 0;

                foreach (BundleEntry entry in bundle.Entries)
                {
                    if (entry.Id < prevID)
                        throw new Exception("Invalid BundleEntry not sorted by ID");

                    prevID = entry.Id;
                }

            }
            else
            {
                //it's a regular bundle... BundleHeader items should be sorted by ID

                uint prevAddress = 0;

                foreach (BundleEntry entry in bundle.Entries)
                {
                    if (entry.Address < prevAddress)
                        throw new Exception("Invalid BundleEntry not sorted by Address");

                    prevAddress = entry.Address;
                }

            }
        }
        /// <summary>
        /// The backup bundle entry.
        /// </summary>
        /// <param name="bundlePath">
        /// The bundle path.
        /// </param>
        private void BackupEntries(BundleMod mod, string bundlePath)
        {
            string backupFolder = Path.Combine(this._assetFolder, "asset_backups") + "\\";
            Directory.CreateDirectory(backupFolder);

            var header = new BundleHeader();
            if (!header.Load(bundlePath))
            {
                this.Error = "Failed to parse bundle header: " + bundlePath;
            }

            var bundleFS = new FileStream(bundlePath + ".bundle", FileMode.Open, FileAccess.Read);
            var bundleBR = new BinaryReader(bundleFS);

            foreach (BundleEntry entry in header.Entries)
            {
                BundleRewriteItem rewriteEntryItem;
                BundleRewriteItem backupRewriteItem = new BundleRewriteItem();
                if (mod.ItemQueue.Any(rewriteItem => rewriteItem.Ids.Contains(entry.Id)))
                {
                    NameEntry ne = StaticStorage.Index.Id2Name(entry.Id);
                    rewriteEntryItem = mod.ItemQueue.First(rewriteItem => rewriteItem.Ids.Contains(entry.Id));

                    if (!File.Exists(backupFolder + ne.ToString()))
                    {
                        using (FileStream exportFS = new FileStream(backupFolder + ne.ToString(), FileMode.CreateNew, FileAccess.Write))
                        {
                            using (BinaryWriter exportBW = new BinaryWriter(exportFS))
                            {
                                long entryLength = entry.Length == -1 ? bundleFS.Length - bundleFS.Position : entry.Length;
                                bundleFS.Seek(entry.Address, SeekOrigin.Begin);
                                exportBW.Write(bundleBR.ReadBytes((int)entryLength));
                            }
                        }
                    }
                }
            }

            bundleBR.Close();
            bundleFS.Close();
        }
        /// <summary>
        /// The retrieve file from bundle.
        /// </summary>
        /// <param name="bundleId">
        /// The bundle id.
        /// </param>
        /// <param name="data">
        /// The file data.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public bool RetrieveFile(BundleRewriteItem item, out MemoryStream data)
        {
            data = new MemoryStream();

            if (item.Ids == null)
            {
                item.Ids = StaticStorage.Index.Entry2Id(
                        item.BundlePath,
                        item.BundleExtension,
                        item.BundleLanguage,
                        item.IsLanguageSpecific);
            }

            string bundleId = "";
            foreach (string file in Directory.EnumerateFiles(this._assetFolder, "*_h.bundle"))
            {
                string bundlePath = file.Replace("_h.bundle", string.Empty);
                var header = new BundleHeader();
                if (!header.Load(bundlePath))
                {
                    this.Error = "Failed to parse bundle header: " + bundlePath;
                    return false;
                }

                foreach (BundleEntry entry in header.Entries)
                {
                    if (item.Ids.Contains(entry.Id) && entry.Length > 0)
                    {
                        bundleId = Path.GetFileNameWithoutExtension(bundlePath);

                        var inBundle = new FileStream(Path.Combine(this._assetFolder, bundleId + ".bundle"), FileMode.Open, FileAccess.Read);
                        var inBundleBinary = new BinaryReader(inBundle);

                        inBundle.Seek(entry.Address, SeekOrigin.Begin);
                        long readLength = entry.Length == -1 ? inBundle.Length - inBundle.Position : entry.Length;
                        data.Write(inBundleBinary.ReadBytes((int)readLength), 0, (int)readLength);

                        data.Position = 0L;
                        inBundleBinary.Close();
                        inBundle.Close();

                        return true;
                    }
                }
            }

            return false;
        }
        /// <summary>
        /// The locate bundles.
        /// </summary>
        /// <param name="success">
        /// The success.
        /// </param>
        /// <returns>
        /// The <see cref="HashSet"/>.
        /// </returns>
        public Dictionary<string, List<uint>> LocateBundles(out bool success, List<uint> ids)
        {
            success = false;
            var bundles = new Dictionary<string, List<uint>>();
            var files = Directory.EnumerateFiles(this._assetFolder, "*_h.bundle").ToList();

            for (int i = 0; i < files.Count; i++ )
            {
                string file = files[i];
                this.SetBundleProgress(
                        string.Format("Reviewing Bundle {0}/{1}", i, files.Count),
                        (int)((i / (float)files.Count) * 100.0f));

                List<uint> enties = new List<uint>();
                string bundlePath = file.Replace("_h.bundle", string.Empty);
                var header = new BundleHeader();
                if (!header.Load(bundlePath))
                {
                    this.Error = "Failed to parse bundle header: " + bundlePath;
                    return bundles;
                }

                foreach (BundleEntry entry in header.Entries)
                {
                    if (ids.Contains(entry.Id))
                    {
                        enties.Add(entry.Id);
                    }
                }

                if (enties.Count > 0)
                    bundles.Add(Path.GetFileNameWithoutExtension(bundlePath), enties);

            }

            this.SetBundleProgress("Done", 100);
            success = true;
            return bundles;
        }