public Stream OpenFile(CFFILE entry) { if (decompressed == null) { if (!DecompressFolder()) { return(null); } } return(new WindowedStream(decompressed, entry.uoffFolderStart, entry.cbFile)); }
public bool GetEntry(string fileName, ref CFFILE entry, bool caseSensitive = true) { foreach (var pair in Entries) { if (caseSensitive) { if (fileName == pair.Item2) { entry = pair.Item1; return(true); } } else { if (fileName.ToLower() == pair.Item2.ToLower()) { entry = pair.Item1; return(true); } } } return(false); }
public bool Read() { reader.BaseStream.Position = 0; var magic = reader.ReadUInt16(); if (magic != 0x5a4d && magic != 0x4d5a) { Console.WriteLine("Error: recovery isn't proper EXE file!"); return(false); } Console.WriteLine("Scanning EXE..."); cabHeaderPos = new List <long>(); // Track position/length ourselves instead of needing to call stream accessors long position = reader.BaseStream.Position; long length = reader.BaseStream.Length; // Fast pattern search via sliding-window, kinda // From https://codereview.stackexchange.com/questions/202235/finding-specific-small-byte-arrays-in-large-binary-files ulong pattern = ((ulong)0x4643534D).EndianSwap(); ulong view = 0; long viewed = 0; while (position + 8 < length) { view = (view << 8) | reader.ReadByte(); // shift-in next byte position++; viewed++; if (view == pattern && viewed >= 8) // make sure we already got at least 4 bytes { cabHeaderPos.Add(position - 8); } } if (cabHeaderPos.Count < 2) { Console.WriteLine("Error: couldn't find required CAB files inside recovery!"); return(false); } string[] csv = null; // Read the meta cab in the exe, contains some info about the other cabs // Usually the second cab in the file, but we'll try the third cabinet in the file if it exists, and use it if it contains manifest.csv // (because second cabinet inside xbox OG SDKs seems to be corrupt or something, with the data actually being in the third one, odd) var metaIdx = cabHeaderPos.Count > 2 ? 2 : 1; while (cabHeaderPos.Count > 1) { var thisIdx = metaIdx; reader.BaseStream.Position = cabHeaderPos[metaIdx]; metaIdx = 1; // Try reading metacab var metaCab = new CabFile(reader.BaseStream); if (!metaCab.Read()) { continue; } // Read the manifest file... var manifest = new CFFILE(); if (!metaCab.GetEntry("manifest.csv", ref manifest, false)) { continue; } // Remove the meta cab from cab header list... cabHeaderPos.RemoveAt(thisIdx); Stream manifestStream = null; try { manifestStream = metaCab.OpenFile(manifest); if (manifestStream == null) { continue; } } catch { continue; } using (var reader2 = new BinaryReader(manifestStream)) { byte[] data = reader2.ReadBytes((int)reader2.BaseStream.Length); var str = Encoding.ASCII.GetString(data); csv = str.Replace("\r\n", "\n").Split(new char[] { '\n' }); } break; } if (csv == null) { Console.WriteLine("Error: failed to read manifest.csv from meta-cab section!"); return(false); } Variants = new List <string>(); Entries = new List <ManifestEntry>(); foreach (var line in csv) { if (string.IsNullOrEmpty(line)) { continue; } var parts = new List <string>(line.Split(new char[] { ',' })); if (parts.Count < 6) { continue; } // Older SDKs don't have a variant section, so we'll insert one if (parts[1] == "file" || parts[1] == "copy" || parts[1] == "sharedfile" || parts[1] == "backupsharedfile" || parts[1] == "singlefile") { parts.Insert(1, ""); } if (parts[2] != "file" && parts[2] != "copy" && parts[2] != "sharedfile" && parts[2] != "backupsharedfile" && parts[2] != "singlefile") { continue; } var entry = new ManifestEntry(); entry.LangID = parts[0]; entry.Variant = parts[1]; entry.Action = parts[2]; entry.BasePath = parts[3]; entry.FilePath = parts[4]; entry.CopyDestPath = parts[5]; if (string.IsNullOrEmpty(entry.Variant)) { entry.Variant = "_All"; } Entries.Add(entry); if (!Variants.Contains(entry.Variant)) { Variants.Add(entry.Variant); } } Console.WriteLine(); Console.WriteLine($"EXE contents:"); Console.WriteLine($"{Entries.Count} file{(Entries.Count == 1 ? "" : "s")}"); Console.WriteLine($"{Variants.Count} variant{(Variants.Count == 1 ? "" : "s")}:"); foreach (var variant in Variants) { int numFiles = 0; foreach (var entry in Entries) { if (entry.Variant == variant) { numFiles++; } } Console.WriteLine($" - {variant} ({numFiles} file{(numFiles == 1 ? "" : "s")})"); } Console.WriteLine(); // TODO: devices (need to read settings.ini from metaCab) return(true); }