private void ModDetails_Load(object sender, EventArgs e) { this.Text = "Mod Details - " + this._mod.Name; this.ModNameText.Text = this._mod.Name; this.AuthorText.Text = this._mod.Author; this.DescriptionText.Text = this._mod.Description; foreach (BundleRewriteItem item in this._mod.ItemQueue) { BundleRewriteItem newBri = new BundleRewriteItem(); newBri.ReplacementFile = Path.GetFileName(this._mod.file)+"/"+item.ReplacementFile; String sourcefile = ""; String path = StaticStorage.Known_Index.GetAny(item.BundlePath); String extension = StaticStorage.Known_Index.GetExtension(item.BundleExtension); if (!string.IsNullOrEmpty(path) && !string.IsNullOrEmpty(extension)) { if (item.IsLanguageSpecific) sourcefile = path + "." + item.BundleLanguage + "." + extension; else sourcefile = path + "." + extension; newBri.SourceFile = sourcefile; _items.Add(newBri); } } this.ReplacementFilesGridView.DataSource = _items; this.ReplacementFilesGridView.Update(); }
private void ParseFileLine(string currentLine, int currentLineNumber) { ulong path, extension = 0; uint language = 0; string[] pieces = currentLine.Split(':'); if (pieces.Length < 2) this.Error("File line didn't contain two pieces.", currentLineNumber); this.CheckFile(pieces[0].Trim(), out path, out language, out extension, currentLineNumber); if (!File.Exists(this.modScriptPath + "/" + pieces[1].Trim())) this.Error("Replacement file does not exist.", currentLineNumber); var item = new BundleRewriteItem { BundleExtension = extension, BundleLanguage = language, BundlePath = path, IsLanguageSpecific = language != 0 ? true : false, SourceFile = pieces[0].Trim(), ReplacementFile = this.modScriptPath + "/" + pieces[1].Trim() }; this.newMod.ItemQueue.Add(item); }
/// <summary> /// The add bundle changes. /// </summary> /// <param name="ids"> /// The ids. /// </param> /// <param name="path"> /// The path. /// </param> /// <param name="extension"> /// The extension. /// </param> /// <param name="language"> /// The language. /// </param> /// <param name="languageSpecific"> /// The language_specific. /// </param> private void AddBundleChanges( HashSet<uint> ids, ulong path, ulong extension, uint language, bool languageSpecific, int replacementType) { var rewriteItem = new BundleRewriteItem { BundleExtension = extension, BundlePath = path, BundleLanguage = language, IsLanguageSpecific = languageSpecific, SourceFile = BundleFileName.Text.ToLower().Replace('\\', '/'), ReplacementFile = this.ReplacementFileName.Text, ReplacementType = replacementType }; this.newMod.ItemQueue.Add(rewriteItem); this.lastRewriteItem = rewriteItem; this.UndoLast.Enabled = true; }
/// <summary> /// The apply mod. /// </summary> public void ApplyMod() { this.Done = false; using (this.Zip = new ZipFile(this._zipPath)) { bool wasSuccessful = false; this._mod.ItemQueue.RemoveWhere(i => i.BundleExtension == 0xAB2664BF82E646UL); this._mod.ItemQueue.RemoveWhere(i => i.BundleExtension == 0xAB2664BF82E6460C); this._mod.ItemQueue.RemoveWhere(i => i.BundleExtension == 0x29104BC4AC649965); if (!this.LocateChangeIds()) return; HashSet<string> bundles = this.LocateBundlesToRewrite(out wasSuccessful); if (!wasSuccessful) return; if (!this._patchAllBundles) bundles.RemoveWhere(i => i.StartsWith("all_")); if (bundles.Count <= 0) { this.Error = "Unable to locate any bundles with the requested items in them.\n" + "If the changed file(s) only exists within an all_x.bundle file you will need to enable the option to patch all_x.bundle files.\n" + "Refer to the patch description for if this is required."; return; } this.SetTotalProgress("Backing up Bundles", -1); int currentBundle = 1; int bundleCount = bundles.Count; foreach (var bundle in bundles) { this.SetBundleProgress( string.Format("{0}/{1}", currentBundle, bundleCount), (int)((currentBundle / (float)bundleCount) * 100.0f)); if (this._backupType == 1) this.BackupEntries(this._mod, Path.Combine(this._assetFolder, bundle)); else { this.BackupFile(Path.Combine(this._assetFolder, bundle + "_h.bundle")); this.BackupFile(Path.Combine(this._assetFolder, bundle + ".bundle")); } currentBundle += 1; } backupEntry.Name = this._mod.Name; backupEntry.Author = this._mod.Author; backupEntry.Description = this._mod.Description; backupEntry.BackupType = (this._backupType == 0) ? "Bundles" : "Bundle Entries"; backupEntry.InstallDate = DateTime.Now; backupEntry.RewriteAll = this._patchAllBundles; HashSet<BundleRewriteItem> backupQueue = new HashSet<BundleRewriteItem>(); foreach (BundleRewriteItem bri in this._mod.ItemQueue) { BundleRewriteItem newbri = new BundleRewriteItem(); newbri.BundleExtension = bri.BundleExtension; newbri.BundleLanguage = bri.BundleLanguage; newbri.BundlePath = bri.BundlePath; newbri.Ids = bri.Ids; newbri.IsLanguageSpecific = bri.IsLanguageSpecific; backupQueue.Add(newbri); } backupEntry.ItemQueue = backupQueue; allowBackup = true; currentBundle = 1; TotalElapsedTime.Start(); foreach (var bundle in bundles) { this.SetTotalProgress( string.Format("Patching Bundle {0}/{1}", currentBundle, bundleCount), (int)((currentBundle / (float)bundleCount) * 100.0f)); if (!this.PatchBundle(bundle)) return; currentBundle += 1; } TotalElapsedTime.Stop(); } this.SetTotalProgress("Done", 100); this.Done = true; }
private void ConfigureReplacementButton_Click(object sender, EventArgs e) { /* * File Replacement * Patch Script * Strings Patch * Sound Bank Patch */ ulong path, extension; uint language; switch(this.fileReplacementType_ComboBox.Text) { case ("File Replacement"): return; case ("Strings Patch"): if (!this.CheckBundleFileName(this.BundleFileName.Text.ToLower().Replace('\\', '/'), out path, out extension, out language)) { return; } BundleRewriteItem tempBRI = new BundleRewriteItem(path, language, extension); tempBRI.IsLanguageSpecific = (Path.GetFileName(this.BundleFileName.Text).Split('.').Length == 3); BundleRewriter br = new BundleRewriter(StaticStorage.settings.AssetsFolder); MemoryStream stringsStream = new MemoryStream(); br.RetrieveFile(tempBRI, out stringsStream); DieselStrings ds = new DieselStrings(stringsStream); ManageStrings msForm = new ManageStrings(ds); msForm.ShowDialog(this); /* FileControl filecontrolForm = new FileControl(); filecontrolForm.filecontrolDictionary = filecontrolDictionary; filecontrolForm.filecontrolSelectedDictionary = filecontrolSelectedDictionary; filecontrolForm.ShowDialog(this); filecontrolSelectedDictionary = filecontrolForm.filecontrolSelectedDictionary; */ break; case ("Sound Bank Patch"): if (!this.CheckBundleFileName(this.BundleFileName.Text.ToLower().Replace('\\', '/'), out path, out extension, out language)) { return; } BundleRewriteItem soundtempBRI = new BundleRewriteItem(path, language, extension); soundtempBRI.IsLanguageSpecific = (Path.GetFileName(this.BundleFileName.Text).Split('.').Length == 3); BundleRewriter soundbr = new BundleRewriter(StaticStorage.settings.AssetsFolder); MemoryStream soundStream = new MemoryStream(); soundbr.RetrieveFile(soundtempBRI, out soundStream); SoundPatch spForm = new SoundPatch(Path.GetFileNameWithoutExtension(this.BundleFileName.Text.ToLower()), soundStream); spForm.ShowDialog(this); break; default: break; } }
/// <summary> /// The apply changes. /// </summary> public void ApplyChanges(BundleMod[] toAddModsList, bool method) { this.Done = false; using (this.Zip = new ZipFile(this._zipPath)) { bool wasSuccessful = false; this._mod.ItemQueue.RemoveWhere(i => i.BundleExtension == 0xAB2664BF82E646UL); this._mod.ItemQueue.RemoveWhere(i => i.BundleExtension == 0xAB2664BF82E6460C); this._mod.ItemQueue.RemoveWhere(i => i.BundleExtension == 0x29104BC4AC649965); if (!this.LocateChangeIds()) return; var toRemove = this._mod.ItemQueue.Where(p => p.toRemove); //var toReinstall = this._mod.ItemQueue.Where(p => p.toReinstall); var toInstall = this._mod.ItemQueue.Where(p => !p.toRemove); if (this._overrideFolder) { this.SetTotalProgress("Utilizing Override Folder", -1); HashSet<BundleEntryPath> toSharedFolder = new HashSet<BundleEntryPath>(); HashSet<BundleEntryPath> overrideApplied = new HashSet<BundleEntryPath>(); Dictionary<BundleEntryPath, HashSet<BundleRewriteItem>> bep_sorted = new Dictionary<BundleEntryPath, HashSet<BundleRewriteItem>>(); foreach (BundleRewriteItem bri in this._mod.ItemQueue) { if (bri.toRemove) continue; if (bep_sorted.ContainsKey(bri.getBundleEntryPath())) { if (this._overrideFolderShared && !toSharedFolder.Contains(bri.getBundleEntryPath())) toSharedFolder.Add(bri.getBundleEntryPath()); bep_sorted[bri.getBundleEntryPath()].Add(bri); } else { HashSet<BundleRewriteItem> newbrihs = new HashSet<BundleRewriteItem>(); newbrihs.Add(bri); bep_sorted.Add(bri.getBundleEntryPath(), newbrihs); } } HashSet<BundleRewriteItem> reducedItemQueue = new HashSet<BundleRewriteItem>(); int override_count = 1; foreach (BundleRewriteItem bri in this._mod.ItemQueue) { this.SetBundleProgress( string.Format("Processing {0}/{1}", override_count, this._mod.ItemQueue.Count), (int)((override_count / (float)this._mod.ItemQueue.Count) * 100.0f)); if (bri.isOverrideable() //&& !bri.ReplacementFile.EndsWith(".script") ) { if (!string.IsNullOrEmpty(StaticStorage.Known_Index.GetPath(bri.BundlePath)) && !string.IsNullOrEmpty(StaticStorage.Known_Index.GetExtension(bri.BundleExtension)) ) { string extrname = ""; extrname += StaticStorage.Known_Index.GetPath(bri.BundlePath); extrname += "." + StaticStorage.Known_Index.GetExtension(bri.BundleExtension); string modName = bri.getEscapedName(); if (bri.toRemove) { if (!toSharedFolder.Contains(bri.getBundleEntryPath()) && File.Exists(Path.Combine(this._assetFolder, "mod_overrides", "Bundle_Modder_Shared", extrname))) File.Delete(Path.Combine(this._assetFolder, "mod_overrides", "Bundle_Modder_Shared", extrname)); else if (File.Exists(Path.Combine(this._assetFolder, "mod_overrides", modName, extrname))) File.Delete(Path.Combine(this._assetFolder, "mod_overrides", modName, extrname)); DeleteEmptyDirs(Path.Combine(this._assetFolder, "mod_overrides", modName)); } else { if (bri.toReinstall) { if (File.Exists(Path.Combine(this._assetFolder, "mod_overrides", modName, extrname))) File.Delete(Path.Combine(this._assetFolder, "mod_overrides", modName, extrname)); } String path; if (this._overrideFolderShared && toSharedFolder.Contains(bri.getBundleEntryPath())) path = Path.Combine(this._assetFolder, "mod_overrides", "Bundle_Modder_Shared", extrname); else path = Path.Combine(this._assetFolder, "mod_overrides", modName, extrname); if (!Directory.Exists(Path.GetDirectoryName(path))) Directory.CreateDirectory(Path.GetDirectoryName(path)); HashSet<BundleRewriteItem> bep_items = new HashSet<BundleRewriteItem>(); if (bep_sorted.ContainsKey(bri.getBundleEntryPath())) bep_items = bep_sorted[bri.getBundleEntryPath()]; var outOverride = new FileStream( path, FileMode.Create, FileAccess.ReadWrite); int runningcount = 0; foreach (var item in bep_items) { if (item.SourceFile != null) { if(this.Zip == null) this.Zip = new ZipFile(item.SourceFile); if (!this.Zip.Name.Equals(item.SourceFile)) { this.Zip.Dispose(); this.Zip = new ZipFile(item.SourceFile); } } else continue; ZipEntry zip_entry = this.Zip[item.ReplacementFile]; if (zip_entry != null) { if (zip_entry.UsesEncryption) { zip_entry.Password = "******"; //zip_entry.Encryption = EncryptionAlgorithm.WinZipAes256; } MemoryStream zipEntryData = new MemoryStream(); if (item.ReplacementFile.EndsWith(".script")) { MemoryStream scriptData = new MemoryStream(); zip_entry.Extract(scriptData); scriptData.Seek(0, SeekOrigin.Begin); MemoryStream bundleData = new MemoryStream(); if (RetrieveFile(item, out bundleData)) { if (runningcount > 0) { bundleData.SetLength(0); outOverride.Seek(0, SeekOrigin.Begin); outOverride.CopyTo(bundleData); } StreamReader scriptStream = new StreamReader(scriptData); List<BundleRewriteScriptAction> scriptActions = ParseScriptActions(ref scriptStream, zip_entry.FileName); scriptData.Close(); scriptStream.Close(); //apply script functions here bundleData.Seek(0, SeekOrigin.Begin); List<byte> entryBytes = bundleData.ToArray().ToList(); outOverride.Seek(0, SeekOrigin.Begin); ApplyScriptActions(ref entryBytes, ref scriptActions); foreach (byte b in entryBytes) outOverride.WriteByte(b); } else { reducedItemQueue.Add(item); } } else { outOverride.Position = 0L; zipEntryData.Position = 0L; zip_entry.Extract(zipEntryData); zipEntryData.Position = 0L; zipEntryData.CopyTo(outOverride, this.bufferSize); //foreach (byte b in zipEntryData.ToArray().ToList()) // outOverride.WriteByte(b); } outOverride.Flush(); } runningcount++; } outOverride.Close(); } } else { reducedItemQueue.Add(bri); } } else { if (this._overrideFolderDummies) { string modName = bri.ModName; modName = Path.GetInvalidFileNameChars().Aggregate(modName, (current, c) => current.Replace(c.ToString(), "_")); if (bri.toRemove) { if (Directory.Exists(Path.Combine(this._assetFolder, "mod_overrides", modName))) { //Directory.Delete(Path.Combine(this._assetFolder, "mod_overrides", modName), true); DeleteDirectory(Path.Combine(this._assetFolder, "mod_overrides", modName)); } } else { if (!Directory.Exists(Path.Combine(this._assetFolder, "mod_overrides", modName))) Directory.CreateDirectory(Path.Combine(this._assetFolder, "mod_overrides", modName)); } } reducedItemQueue.Add(bri); } override_count++; } this.SetBundleProgress("Done", 100); this._mod.ItemQueue = reducedItemQueue; } HashSet<string> bundles = this.LocateBundlesToRewrite(out wasSuccessful); if (!wasSuccessful) return; if (!this._patchAllBundles) bundles.RemoveWhere(i => i.StartsWith("all_")); if (bundles.Count <= 0 && !this._overrideFolder) { this.Error = "Unable to locate any bundles with the requested items in them.\n" + "If the changed file(s) only exists within an all_x.bundle file you will need to enable the option to patch all_x.bundle files.\n" + "Refer to the patch description for if this is required."; return; } this.SetTotalProgress("Backing up Bundles", -1); this.CurrentBundlesCount = 1; this.TotalBundlesCount = bundles.Count; foreach (var bundle in bundles) { this.SetBundleProgress( string.Format("Backing up Bundle {0}/{1}", this.CurrentBundlesCount, this.TotalBundlesCount), (int)((this.CurrentBundlesCount / (float)this.TotalBundlesCount) * 100.0f)); if (this._backupType == 1) { this.BackupEntries(this._mod, Path.Combine(this._assetFolder, bundle)); } else { this.BackupFile(Path.Combine(this._assetFolder, bundle + "_h.bundle")); this.BackupFile(Path.Combine(this._assetFolder, bundle + ".bundle")); } this.CurrentBundlesCount += 1; } foreach (BundleMod bm in toAddModsList) { BackupEntry multibackupEntry = new BackupEntry(); multibackupEntry.Name = bm.Name; multibackupEntry.Author = bm.Author; multibackupEntry.Description = bm.Description; multibackupEntry.BackupType = (this._backupType == 0) ? "Bundles" : "Bundle Entries"; multibackupEntry.InstallDate = DateTime.Now; multibackupEntry.RewriteAll = this._patchAllBundles; HashSet<BundleRewriteItem> backupQueue = new HashSet<BundleRewriteItem>(); foreach (BundleRewriteItem bri in bm.ItemQueue) { BundleRewriteItem newbri = new BundleRewriteItem(); newbri.BundleExtension = bri.BundleExtension; newbri.BundleLanguage = bri.BundleLanguage; newbri.BundlePath = bri.BundlePath; newbri.Ids = bri.Ids; newbri.IsLanguageSpecific = bri.IsLanguageSpecific; if (this._backupType == 0) newbri.ReplacementFile = bri.ReplacementFile; else newbri.ReplacementFile = bri.BundlePath.ToString("x") + '.' + bri.BundleLanguage.ToString("x") + '.' + bri.BundleExtension.ToString("x"); newbri.SourceFile = bri.SourceFile; backupQueue.Add(newbri); } multibackupEntry.ItemQueue = backupQueue; backupEntries.Add(multibackupEntry); } allowBackup = true; foreach (var rewriteItem in this._mod.ItemQueue) { foreach (var id in rewriteItem.Ids) { if (this._rewriteItems.ContainsKey(id)) { if (rewriteItem.toRemove) this._rewriteItems[id].toRestore = true; if (rewriteItem.ReplacementFile.EndsWith(".script")) { this._rewriteItems[id].BundleRewriteItem_queue.Add(rewriteItem); } else { if (rewriteItem.priority) { this._rewriteItems[id].priorityBundleRewriteItem = rewriteItem; } else { //Don't add... it's not part of priority this._rewriteItems[id].BundleRewriteItem_queue.Add(rewriteItem); } } } else { BundleRewriteEntryID breid = new BundleRewriteEntryID(); if (rewriteItem.toRemove) breid.toRestore = true; if (rewriteItem.ReplacementFile.EndsWith(".script")) { breid.BundleRewriteItem_queue.Add(rewriteItem); } else { if (rewriteItem.priority) { breid.priorityBundleRewriteItem = rewriteItem; } else { //Don't add, it's not part of priority breid.BundleRewriteItem_queue.Add(rewriteItem); } } this._rewriteItems.Add(id, breid); } } } this.CurrentBundlesCount = 1; TotalElapsedTime.Start(); SpeedElapsedTime.Start(); foreach (var bundle in bundles) { CurrentBundle = bundle; this.SetTotalProgress( string.Format("Patching Bundle {0}/{1}", this.CurrentBundlesCount, this.TotalBundlesCount), (int)((this.CurrentBundlesCount / (float)this.TotalBundlesCount) * 100.0f)); if (!this.PatchBundle(bundle)) return; this.CurrentBundlesCount += 1; } TotalElapsedTime.Stop(); SpeedElapsedTime.Stop(); } this.Zip.Dispose(); this.SetTotalProgress("Done", 100); this.Done = true; }
/// <summary> /// The write zip entry. /// </summary> /// <param name="output"> /// The output. /// </param> /// <param name="rewriteItem"> /// Replacement parameters in form of BundleRewriteItem /// </param> /// <returns> /// How many bytes were written to the stream. /// </returns> private int WriteZipEntry(BundleEntry bundleEntry, Stream input, Stream output, BundleRewriteItem rewriteItem) { if (rewriteItem.SourceFile != null) { if(this.Zip == null) this.Zip = new ZipFile(rewriteItem.SourceFile); else if (!this.Zip.Name.Equals(rewriteItem.SourceFile)) { this.Zip.Dispose(); this.Zip = new ZipFile(rewriteItem.SourceFile); } } int extractedLength = 0; ZipEntry zip_entry = this.Zip[rewriteItem.ReplacementFile]; if (zip_entry != null) { if (zip_entry.UsesEncryption) { zip_entry.Password = "******"; //zip_entry.Encryption = EncryptionAlgorithm.WinZipAes256; } var br = new BinaryReader(input); var bw = new BinaryWriter(output); var data = new MemoryStream(); zip_entry.Extract(data); data.Seek(0, SeekOrigin.Begin); if (zip_entry.FileName.EndsWith(".script")) { StreamReader scriptStream = new StreamReader(data); List<BundleRewriteScriptAction> scriptActions = ParseScriptActions(ref scriptStream, zip_entry.FileName); data.Close(); scriptStream.Close(); //apply script functions here if (input != output) input.Seek(bundleEntry.Address, SeekOrigin.Begin); else input.Seek(0, SeekOrigin.Begin); long entryLength = bundleEntry.Length == -1 ? input.Length - input.Position : bundleEntry.Length; List<byte> entryBytes = br.ReadBytes((int)entryLength).ToList(); output.Seek(0, SeekOrigin.Begin); if (!ApplyScriptActions(ref entryBytes, ref scriptActions)) { bw.Write(br.ReadBytes((int)entryLength)); return (int)(entryLength); } bw.Write(entryBytes.ToArray()); return (int)entryBytes.ToArray().Length; } output.Seek(0, SeekOrigin.Begin); zip_entry.Extract(output); extractedLength = (int)zip_entry.UncompressedSize; data.Close(); } return extractedLength; }
private Dictionary<string, string> RetrieveStrings(BundleRewriteItem filepath) { this.Done = false; this._mod.ItemQueue.Clear(); this._mod.ItemQueue.Add(filepath); if (!this.LocateChangeIds()) return null; bool wasSuccessful; HashSet<string> bundles = this.LocateBundlesToRewrite(out wasSuccessful); if (!wasSuccessful) return null; if (bundles.Count <= 0) { this.Error = "Unable to locate any bundles with the requested items in them.\n" + "If the changed file(s) only exists within an all_x.bundle file you will need to enable the option to patch all_x.bundle files.\n" + "Refer to the patch description for if this is required."; return null; } int currentBundle = 1; int bundleCount = bundles.Count; MemoryStream file_data = new MemoryStream(); foreach (var bundle in bundles) { this.SetTotalProgress( string.Format("Reading Bundle {0}/{1}", currentBundle, bundleCount), (int)((currentBundle / (float)bundleCount) * 100.0f)); if (!this.RetrieveFile(bundle, out file_data)) return null; if (file_data.Length > 0) break; currentBundle += 1; } if (file_data.Length == 0) return null; //Extract strings here... Dictionary<string, string> return_dictionary = new Dictionary<string, string>(); this.SetTotalProgress("Done", 100); this.Done = true; return return_dictionary; }
/// <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; }