public static SARC Analyze(string path) { var sarc = new SARC { FileName = Path.GetFileNameWithoutExtension(path), FilePath = Path.GetDirectoryName(path), Extension = Path.GetExtension(path), valid = true }; using (var fs = File.OpenRead(path)) using (var br = new BinaryReader(fs)) { sarc.Signature = new string(br.ReadChars(4)); if (sarc.Signature != "SARC") { sarc.valid = false; return(sarc); } sarc.HeaderSize = br.ReadUInt16(); sarc.Endianness = br.ReadUInt16(); sarc.FileSize = br.ReadUInt32(); sarc.DataOffset = br.ReadUInt32(); sarc.Unknown = br.ReadUInt32(); sarc.SFat = new SFAT { Signature = new string(br.ReadChars(4)), HeaderSize = br.ReadUInt16(), EntryCount = br.ReadUInt16(), HashMult = br.ReadUInt32(), Entries = new List <SFATEntry>() }; if (sarc.SFat.Signature != "SFAT") { sarc.valid = false; return(sarc); } for (var i = 0; i < sarc.SFat.EntryCount; i++) { var s = new SFATEntry { FileNameHash = br.ReadUInt32(), FileNameOffset = br.ReadUInt32(), FileDataStart = br.ReadUInt32(), FileDataEnd = br.ReadUInt32() }; sarc.SFat.Entries.Add(s); } sarc.SFnt = new SFNT { Signature = new string(br.ReadChars(4)), HeaderSize = br.ReadUInt16(), Unknown = br.ReadUInt16(), StringOffset = (uint)br.BaseStream.Position }; if (sarc.SFnt.Signature != "SFNT") { sarc.valid = false; return(sarc); } } sarc.Data = File.ReadAllBytes(path); if (sarc.FileSize == sarc.Data.Length) { return(sarc); } sarc.valid = false; sarc.Data = null; return(sarc); }
static void UpdateArchives(Options opts) { Util.Log("Testing Crypto Server..."); var passed_selftest = NetworkUtils.TestCryptoServer(IPAddress.Parse(opts.InputIP)); foreach (var country in country_list.Keys) { var country_dir = Path.Combine("data", country); var country_id = country_list[country]; Directory.CreateDirectory(country_dir); foreach (var archive in badge_filelist) { var archive_path = Path.Combine(country_dir, archive); var sarc_path = Path.Combine(country_dir, Path.GetFileNameWithoutExtension(archive_path) + ".sarc"); var xml_path = Path.Combine(country_dir, Path.GetFileNameWithoutExtension(archive_path) + ".xml"); var server_file = string.Format(server, country_id, archive); Util.Log($"{country} / {archive}...", false); if (!File.Exists(archive_path)) { Util.Log("Downloading...", false); var arc = NetworkUtils.TryDownload(server_file); if (arc != null) { File.WriteAllBytes(archive_path, arc); if (File.Exists(sarc_path)) { File.Delete(sarc_path); } } else { Util.Log("Download failed"); continue; } } else { var old = File.ReadAllBytes(archive_path); var new_arc = NetworkUtils.DownloadFirstBytes(server_file); if (new_arc == null) { continue; } if (!(new_arc.SequenceEqual(old.Take(new_arc.Length)))) { Util.Log("Updating...", false); var arc = NetworkUtils.TryDownload(server_file); if (arc != null) { File.WriteAllBytes(archive_path, arc); if (File.Exists(sarc_path)) { File.Delete(sarc_path); } } else { Util.Log("Update failed"); continue; } } } if (!File.Exists(sarc_path) && passed_selftest) { keep_log = true; Util.Log("Decrypting...", false); var dec_boss = NetworkUtils.TryDecryptBOSS(File.ReadAllBytes(archive_path), IPAddress.Parse(opts.InputIP)); if (dec_boss == null) { continue; } File.WriteAllBytes(sarc_path, dec_boss.Skip(0x296).ToArray()); sarc = SARC.Analyze(sarc_path); if (!sarc.valid) { Util.Log($"Not a valid SARC. Maybe bad decryption...?"); passed_selftest = false; File.Delete(sarc_path); continue; } } else if (!File.Exists(sarc_path)) { Util.Log("Done"); continue; } else { sarc = SARC.Analyze(sarc_path); if (!sarc.valid) { Util.Log("SARC file corrupted"); File.Delete(sarc_path); continue; } } Util.Log($"Extracting..."); var sarchashes = Util.DeserializeFile <SARCFileHashes>(xml_path) ?? new SARCFileHashes(); var data_dir = Path.Combine(country_dir, Path.GetFileNameWithoutExtension(archive_path), "files"); var decompressed_data_dir = Path.Combine(country_dir, Path.GetFileNameWithoutExtension(archive_path), "decompressed"); Directory.CreateDirectory(data_dir); Directory.CreateDirectory(decompressed_data_dir); foreach (var entry in sarc.SFat.Entries) { var path = Path.Combine(data_dir, sarc.GetFilePath(entry)); var decompressed_path = Path.Combine(decompressed_data_dir, Path.ChangeExtension(sarc.GetFilePath(entry), null)); Directory.CreateDirectory(Path.GetDirectoryName(path)); Directory.CreateDirectory(Path.GetDirectoryName(decompressed_path)); var hashresult = sarchashes.IsHashEqual(sarc.GetFilePath(entry), sarc.GetFileHash(entry)); sarchashes.SetHash(sarc.GetFilePath(entry), sarc.GetFileHash(entry)); if (!File.Exists(path)) { Util.Log(hashresult == SARCHashResult.NotFound ? $"New {country} file: {Path.GetFileName(path)}" : hashresult == SARCHashResult.Equal ? $"{country} file: {Path.GetFileName(path)} was deleted" : $"Updated {country} file: {Path.GetFileName(path)}"); WriteSARCFileData(opts, entry, country, path, decompressed_path); } else { if (hashresult != SARCHashResult.NotEqual) { continue; } Util.Log($"Updated {country} file: {Path.GetFileName(path)}"); //Can't do nothing for updated files, //or the file will ALWAYS say its updated every run, not the intended result. WriteSARCFileData(opts, entry, country, path, decompressed_path); } } Util.Serialize(sarchashes, xml_path); Util.Log($"{country} / {archive}...Extraction Complete"); } } }