/// <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 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;
        }