public void BuildCABMap(string[] blks) { // the cab map is comprised of an array of paths followed by a map of cab identifiers to indices into that path array // it would be more correct to load only the required mhy0 from the .blk, but i'm lazy // TODO: this should be moved into library code and not gui code, also should be made async using (var mapFile = File.Create("cabMap.bin")) { using (var mapWriter = new BinaryWriter(mapFile)) { int collisions = 0; var cabMapInt = new Dictionary <Guid, int>(); cabMap.Clear(); mapWriter.Write(blks.Length); for (int i = 0; i < blks.Length; i++) { Logger.Info(String.Format("processing blk {0}/{1} ({2})", i + 1, blks.Length, blks[i])); Progress.Report(i + 1, blks.Length); mapWriter.Write(blks[i]); var blkFile = new BlkFile(new FileReader(blks[i])); foreach (var mhy0 in blkFile.Files) { if (mhy0.ID == Guid.Empty) { continue; } if (cabMap.ContainsKey(mhy0.ID)) { //throw new InvalidDataException("mhy0 id collision found"); // i don't think i can do much about this // colliding mhy0s appear to just contain the same data anyways... //Logger.Warning(String.Format("mhy0 id collision! {0} {1}", mhy0.ID, cabDuplicateMap[mhy0.ID])); collisions++; continue; } cabMapInt.Add(mhy0.ID, i); cabMap.Add(mhy0.ID, blks[i]); } } mapWriter.Write(cabMap.Count); foreach (var mapEntry in cabMapInt) { mapWriter.Write(mapEntry.Key.ToByteArray()); // ToByteArray has a weird order mapWriter.Write(mapEntry.Value); } Logger.Info(String.Format("finished processing {0} blks with {1} cabs and {2} id collisions", blks.Length, cabMap.Count, collisions)); } } }
private void LoadBlkFile(FileReader reader, Guid?targetId = null) { if (targetId == null) { Logger.Info("Loading " + reader.FileName); } else { Logger.Info("Loading " + reader.FileName + " with target ID " + targetId.Value.ToString()); } try { var blkFile = new BlkFile(reader); bool targetFound = false; for (int i = 0; i < blkFile.Files.Count; i++) { //Console.WriteLine(blkFile.Files[i].ID); if (targetId.HasValue && targetId.Value != blkFile.Files[i].ID) { continue; } targetFound = true; // TODO: proper dummyPath var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), string.Format("{0}_{1}", reader.FileName, blkFile.Files[i].ID.ToString())); var subReader = new FileReader(dummyPath, new MemoryStream(blkFile.Files[i].Data)); var asset = LoadAssetsFromMemory(subReader, dummyPath); if (asset == null) { //Logger.Error("what"); continue; } foreach (var sharedFile in asset.m_Externals) { var sharedFileName = sharedFile.fileName; var sharedFileNameWithID = string.Format("{0}_{1}", sharedFileName, sharedFile.cabId.ToString()); if (!sharedFileName.EndsWith(".blk")) { // this will directly load .blk files, so anything that isn't one is not supported Logger.Warning(String.Format("attempted to load non-blk shared file ({0})", sharedFileName)); continue; } if (!importFilesHash.Contains(sharedFileNameWithID)) { var sharedFilePath = Path.Combine(Path.GetDirectoryName(reader.FullPath), sharedFileName); if (!File.Exists(sharedFilePath)) { var findFiles = Directory.GetFiles(Path.GetDirectoryName(reader.FullPath), sharedFileName, SearchOption.AllDirectories); if (findFiles.Length > 0) { sharedFilePath = findFiles[0]; } } if (File.Exists(sharedFilePath)) { // TODO: proper integration with the loading bar LoadBlkFile(new FileReader(sharedFilePath), sharedFile.cabId); //importFiles.Add(sharedFilePath); importFilesHash.Add(sharedFileNameWithID); } } } } if (blkFile.Files.Count > 0 && !targetFound) { Logger.Warning("failed to find target mhy0"); } } catch (Exception e) { Logger.Error($"Error while reading blk file {reader.FileName}", e); } finally { reader.Dispose(); } }