private IEnumerable <CatalogueEntry> BuildFileListInCatalogues(IEnumerable <BundleList> bundleCollections) { foreach (var collection in bundleCollections) { string appendPrefix = collection.Name; foreach (var item in collection.Bundles) { // using a level of indirection if (item.Indirection != null) { if (item.Properties.ContainsKey("id")) { appendPrefix = collection.Name + @"\" + ((string)item.Properties["id"].Value).Replace(@"/", @"\"); } foreach (var entry in BuildFileListInCatalogues(item.Indirection.BundleCollections)) { entry.ResolvedName = appendPrefix + @"\" + entry.ResolvedName; yield return(entry); } } // directly else { if (item.Properties.ContainsKey("sha1")) { byte[] sha1 = (byte[])item.Properties["sha1"].Value; CatalogueEntry catalogueEntry = FindCorrespondingCatalogueEntry(sha1); if (catalogueEntry != null) { if (item.Properties.ContainsKey("name")) { catalogueEntry.ResolvedName = ((string)item.Properties["name"].Value).Replace(@"/", @"\"); } else if (item.Properties.ContainsKey("id")) { catalogueEntry.ResolvedName = Helpers.ByteArrayToString((byte[])item.Properties["id"].Value); } catalogueEntry.ResolvedName = appendPrefix + @"\" + catalogueEntry.ResolvedName; yield return(catalogueEntry); } } } } } }
private void BuildCatalogueEntry(Catalogue catalogue, byte version) { byte[] hash = ReadBytes(20); CatalogueEntry entry = new CatalogueEntry(); entry.Offset = ReadInt32(); entry.Size = ReadInt32(); if (version == 0x01) { entry.Extra = ReadInt32(); } entry.Archive = ReadInt32(); catalogue.Files[hash] = entry; entry.Parent = catalogue; }
public void ImportFiles(string tableOfContentsName) { Dictionary <string, string> filesToOverwriteMap = new Dictionary <string, string>(); string directory = Path.GetDirectoryName(tableOfContentsName) + @"\" + Path.GetFileNameWithoutExtension(tableOfContentsName); Random generator = new Random(); ResolveNewFiles(tableOfContentsName, directory); bool isIndirect = myTableOfContents.Payload.BundleCollections.Where(bundleList => bundleList.Bundles.Count() > 0).First().Bundles.First().Indirection != null; List <bool> isIndirectionConsistentAndMatching = myTableOfContents.Payload.BundleCollections.Select(bundleList => bundleList.Bundles.All(bundle => (bundle.Indirection != null) == isIndirect)).Distinct().ToList(); bool isIndirectOrMixed = false; if (isIndirectionConsistentAndMatching.Count() != 1 || !isIndirectionConsistentAndMatching.First()) { isIndirectOrMixed = true; } string originalSuperBundlePath = Path.ChangeExtension(tableOfContentsName, "sb"); string newSuperBundlePath = Path.ChangeExtension(tableOfContentsName, "sb_" + generator.Next().ToString()); // table of contents pointing directly to raw files in superbundles if (!myTableOfContents.Payload.Properties.ContainsKey("cas")) { filesToOverwriteMap.Add(originalSuperBundlePath, newSuperBundlePath); // write superbundle var allBundles = myTableOfContents.Payload.BundleCollections.SelectMany(bundleList => bundleList.Bundles).OrderBy(superBundle => (long)superBundle.Properties["offset"].Value); using (BinaryReader originalReader = new BinaryReader(File.Open(originalSuperBundlePath, FileMode.Open))) { using (BundleBinaryWriter writer = new BundleBinaryWriter(File.Open(newSuperBundlePath, FileMode.Create))) { foreach (SuperBundle superBundle in allBundles) { Int64 initialFilePosition = writer.BaseStream.Position; if (superBundle.Changed == null) { long offset = (long)superBundle.Properties["offset"].Value; originalReader.BaseStream.Seek(offset, SeekOrigin.Begin); writer.Write(originalReader.ReadBytes((int)superBundle.Properties["size"].Value)); } else { superBundle.Properties["size"].Value = ChunkHandler.Chunk(writer, superBundle); } superBundle.Properties["offset"].Value = initialFilePosition; } } } // write table of contents string newTableOfContentsName = Path.ChangeExtension(tableOfContentsName, @".toc_" + generator.Next().ToString()); filesToOverwriteMap.Add(tableOfContentsName, newTableOfContentsName); using (BundleBinaryWriter writer = new BundleBinaryWriter(File.Open(newTableOfContentsName, FileMode.Create))) { writer.Write(myTableOfContents.Header); writer.Write(myTableOfContents.Payload); } } // table of contents pointing to raw files in catalogues else { IEnumerable <SuperBundle> modifiedBundles; if (isIndirectOrMixed) { modifiedBundles = myTableOfContents.Payload.BundleCollections .SelectMany(bundleList => bundleList.Bundles .Where(superBundles => superBundles.Indirection != null) .SelectMany(superBundles => superBundles.Indirection.BundleCollections .SelectMany(indirectBundleList => indirectBundleList.Bundles))) .Where(bundle => bundle.Changed != null); } else { modifiedBundles = myTableOfContents.Payload.BundleCollections.SelectMany(bundleList => bundleList.Bundles).Where(bundle => bundle.Changed != null); } // write cas foreach (SuperBundle superBundle in modifiedBundles) { CatalogueEntry catEntry = FindCorrespondingCatalogueEntry((byte[])superBundle.Properties["sha1"].Value); catEntry.Changed = true; string pathToNewCascade = Path.GetDirectoryName(catEntry.Parent.Path) + @"\\" + "cas_99.cas"; catEntry.Archive = 99; using (BundleBinaryWriter writer = new BundleBinaryWriter(File.Open(pathToNewCascade, FileMode.Append))) { if (writer.BaseStream.Position == 0 && myTableOfContents.Header.Version == 0x03) { writer.Write(Catalogue.CasHeader); } catEntry.Offset = (int)writer.BaseStream.Position; int fileSize = ChunkHandler.Chunk(writer, superBundle); catEntry.Size = fileSize; if (superBundle.Properties.ContainsKey("size")) { superBundle.Properties["size"].Value = (Int64)fileSize; } if (superBundle.Properties.ContainsKey("originalSize")) { superBundle.Properties["originalSize"].Value = (Int64) new FileInfo(superBundle.Changed).Length; } } } // write catalogue foreach (Catalogue catalogue in myCatalogues.Where(_ => _.Files.Values.Any(entry => entry.Changed))) { // fix for duplicates catalogue.NumberOfFiles = catalogue.Files.Count; string newCataloguePath = catalogue.Path + "_tmp" + generator.Next().ToString(); filesToOverwriteMap.Add(catalogue.Path, newCataloguePath); using (BundleBinaryWriter writer = new BundleBinaryWriter(File.Open(newCataloguePath, FileMode.Create))) { writer.Write(myTableOfContents.Header.Version, catalogue); } } // write superbundle if (isIndirectOrMixed) { filesToOverwriteMap.Add(originalSuperBundlePath, newSuperBundlePath); // write table of contents using (BundleBinaryWriter writer = new BundleBinaryWriter(File.Open(newSuperBundlePath, FileMode.Create))) { using (BinaryReader originalReader = new BinaryReader(File.Open(originalSuperBundlePath, FileMode.Open))) { originalReader.BaseStream.Seek(0, SeekOrigin.Begin); writer.Write(originalReader.ReadBytes(16)); } foreach (SuperBundle indirectSuperBundle in myTableOfContents.Payload.BundleCollections.SelectMany(_ => _.Bundles.Select(x => x.Indirection))) { writer.Write(indirectSuperBundle); } writer.Write((Int16)0); } } } CleanupTemporaryFiles(filesToOverwriteMap); }