internal static string Interpret(string path) { string fn = Path.GetFileName(path); if (fn == "save0.bin" || fn == "save1.bin" || fn == "save2.bin") { return FixMajoraChecksum(path); } if (fn.StartsWith("message") && (fn.EndsWith("_US.bin") || fn.EndsWith("_UK.bin"))) { return ParseShuffleText(path); } DARC darc = analyze(path); FARC farc = new FARC(); GAR gar = new GAR(); SARC sarc = new SARC(); ShuffleARC sharc = new ShuffleARC(); if (!darc.valid) farc = analyzeFARC(path); if (!farc.valid) gar = analyzeGAR(path); if (!gar.valid) sharc = AnalyzeShuffle(path); if (!sharc.valid) sarc = analyzeSARC(path); string ret = ""; if (darc.valid) { ret += "Header Offset: " + darc.HeaderOffset + Environment.NewLine + "File Count: " + darc.Files.Files.Count + Environment.NewLine; int extracted = 0; int folder = 0; for (int i = 0; i < darc.Files.Files.Count; i++) { if (darc.Files.Files[i].Folder > 0) { folder++; } else { extracted++; string dir = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + darc.FileName + Path.DirectorySeparatorChar; if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } string outPath = dir + darc.Files.FileNames[i]; var fs = File.OpenRead(path); fs.Seek(darc.Files.Files[i].Offset, SeekOrigin.Begin); byte[] fileBuffer = new byte[darc.Files.Files[i].Length]; fs.Read(fileBuffer, 0, fileBuffer.Length); fs.Close(); File.WriteAllBytes(outPath, fileBuffer); } } ret += "Extracted " + extracted + " files"; if (folder > 0) { ret += ", did not extract " + folder + " folders"; } ret += "." + Environment.NewLine + "Open a .DARC/.SARC/.FARC/.GAR/Shuffle Archive file (or drag/drop)."; } else if (farc.valid) { ret += "Header Offset: " + farc.HeaderOffset + Environment.NewLine; int extracted = 0; for (int i = 0; i < farc.Files.Files.Count; i++) { extracted++; string dir = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + "FARC_" + farc.FileName + Path.DirectorySeparatorChar; if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } string outPath = dir + farc.Files.FileNames[i]; var fs = File.OpenRead(farc.FilePath + "\\" + farc.FileName + farc.Extension); fs.Seek(farc.Files.Files[i].Offset + farc.DataOffset, SeekOrigin.Begin); byte[] fileBuffer = new byte[farc.Files.Files[i].Length]; fs.Read(fileBuffer, 0, fileBuffer.Length); fs.Close(); File.WriteAllBytes(outPath, fileBuffer); } ret += "Extracted " + extracted + " files"; ret += "." + Environment.NewLine + ".DARC/.FARC/.SARC/.GAR/Shuffle Archive file (or drag/drop)."; } else if (gar.valid) { ret += "New GAR with " + gar.FileCount + " files." + Environment.NewLine; string dir = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + gar.FileName + Path.DirectorySeparatorChar; if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } for (int i = 0; i < gar.FileCount; i++) { var fs = File.OpenRead(path); fs.Seek(gar.Files[i].Offset, SeekOrigin.Begin); byte[] fileBuffer = new byte[gar.Files[i].Length]; fs.Read(fileBuffer, 0, fileBuffer.Length); fs.Close(); File.WriteAllBytes(dir + gar.Files[i].NameWithExtension, fileBuffer); ret += "Extracted " + gar.Files[i].NameWithExtension + " (Offset: " + gar.Files[i].Offset.ToString("X8") + ", Len: " + gar.Files[i].Length.ToString("X8") + ")." + Environment.NewLine; } ret += Environment.NewLine; } else if (sharc.valid) { ret += "New Shuffle Archive with " + sharc.FileCount + " files." + Environment.NewLine; string dir = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + sharc.FileName + "_" + Path.DirectorySeparatorChar; if (!Directory.Exists(dir)) { Console.WriteLine("Making dir: " + dir); Directory.CreateDirectory(dir); } string diglen = "".PadLeft((int)(Math.Log10(sharc.FileCount) + 1), '0'); for (int i = 0; i < sharc.FileCount; i++) { var fs = File.OpenRead(path); fs.Seek(sharc.Files[i].Offset, SeekOrigin.Begin); byte[] fileBuffer = new byte[sharc.Files[i].Length]; fs.Read(fileBuffer, 0, fileBuffer.Length); fs.Close(); uint check = 0; for (int j = 0; j < fileBuffer.Length; j += 4) check += BitConverter.ToUInt32(fileBuffer, j); Console.WriteLine(i.ToString(diglen) + ": " + check.ToString("X8")); File.WriteAllBytes(dir + i.ToString(diglen) + ".zip", fileBuffer); ret += "Extracted " + i.ToString(diglen) + " (Offset: " + sharc.Files[i].Offset.ToString("X8") + ", Len: " + sharc.Files[i].Length.ToString("X8") + ")." + Environment.NewLine; } ret += Environment.NewLine; } else if (sarc.valid) { ret = "New SARC with " + sarc.SFat.EntryCount + " files." + Environment.NewLine; string dir = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + sarc.FileName + "_" + Path.DirectorySeparatorChar; if (!Directory.Exists(dir)) { Console.WriteLine("Making dir: " + dir); Directory.CreateDirectory(dir); } foreach (SFATEntry t in sarc.SFat.Entries) { var fs = File.OpenRead(path); uint FileLen = t.FileDataEnd - t.FileDataStart; fs.Seek(t.FileDataStart + sarc.DataOffset, SeekOrigin.Begin); byte[] fileBuffer = new byte[FileLen]; fs.Read(fileBuffer, 0, (int)FileLen); fs.Seek(sarc.SFnt.StringOffset, SeekOrigin.Begin); fs.Seek((t.FileNameOffset & 0x00FFFFFF) * 4, SeekOrigin.Current); StringBuilder sb = new StringBuilder(); for (char c = (char)fs.ReadByte(); c != 0; c = (char)fs.ReadByte()) { sb.Append(c); } string FileName = sb.ToString().Replace('/', Path.DirectorySeparatorChar); fs.Close(); string FileDir = Path.GetDirectoryName(dir + FileName) + Path.DirectorySeparatorChar; if (!Directory.Exists(FileDir)) { Console.WriteLine("Making dir: " + FileDir); Directory.CreateDirectory(FileDir); } File.WriteAllBytes(dir + FileName, fileBuffer); } } else { ret = "Not a valid .DARC/.FARC/.SARC/.GAR/Shuffle Archive file"; } return ret; }
internal static string Interpret(string path) { string fn = Path.GetFileName(path); if (fn == "save0.bin" || fn == "save1.bin" || fn == "save2.bin") { return(FixMajoraChecksum(path)); } if (fn.StartsWith("message") && (fn.EndsWith("_US.bin") || fn.EndsWith("_UK.bin"))) { return(ParseShuffleText(path)); } DARC darc = analyze(path); FARC farc = new FARC(); GAR gar = new GAR(); SARC sarc = new SARC(); ShuffleARC sharc = new ShuffleARC(); if (!darc.valid) { farc = analyzeFARC(path); } if (!farc.valid) { gar = analyzeGAR(path); } if (!gar.valid) { sharc = AnalyzeShuffle(path); } if (!sharc.valid) { sarc = analyzeSARC(path); } string ret = ""; if (darc.valid) { ret += "Header Offset: " + darc.HeaderOffset + Environment.NewLine + "File Count: " + darc.Files.Files.Count + Environment.NewLine; int extracted = 0; int folder = 0; for (int i = 0; i < darc.Files.Files.Count; i++) { if (darc.Files.Files[i].Folder > 0) { folder++; } else { extracted++; string dir = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + darc.FileName + Path.DirectorySeparatorChar; if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } string outPath = dir + darc.Files.FileNames[i]; var fs = File.OpenRead(path); fs.Seek(darc.Files.Files[i].Offset, SeekOrigin.Begin); byte[] fileBuffer = new byte[darc.Files.Files[i].Length]; fs.Read(fileBuffer, 0, fileBuffer.Length); fs.Close(); File.WriteAllBytes(outPath, fileBuffer); } } ret += "Extracted " + extracted + " files"; if (folder > 0) { ret += ", did not extract " + folder + " folders"; } ret += "." + Environment.NewLine + "Open a .DARC/.SARC/.FARC/.GAR/Shuffle Archive file (or drag/drop)."; } else if (farc.valid) { ret += "Header Offset: " + farc.HeaderOffset + Environment.NewLine; int extracted = 0; for (int i = 0; i < farc.Files.Files.Count; i++) { extracted++; string dir = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + "FARC_" + farc.FileName + Path.DirectorySeparatorChar; if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } string outPath = dir + farc.Files.FileNames[i]; var fs = File.OpenRead(farc.FilePath + "\\" + farc.FileName + farc.Extension); fs.Seek(farc.Files.Files[i].Offset + farc.DataOffset, SeekOrigin.Begin); byte[] fileBuffer = new byte[farc.Files.Files[i].Length]; fs.Read(fileBuffer, 0, fileBuffer.Length); fs.Close(); File.WriteAllBytes(outPath, fileBuffer); } ret += "Extracted " + extracted + " files"; ret += "." + Environment.NewLine + ".DARC/.FARC/.SARC/.GAR/Shuffle Archive file (or drag/drop)."; } else if (gar.valid) { ret += "New GAR with " + gar.FileCount + " files." + Environment.NewLine; string dir = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + gar.FileName + Path.DirectorySeparatorChar; if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } for (int i = 0; i < gar.FileCount; i++) { var fs = File.OpenRead(path); fs.Seek(gar.Files[i].Offset, SeekOrigin.Begin); byte[] fileBuffer = new byte[gar.Files[i].Length]; fs.Read(fileBuffer, 0, fileBuffer.Length); fs.Close(); File.WriteAllBytes(dir + gar.Files[i].NameWithExtension, fileBuffer); ret += "Extracted " + gar.Files[i].NameWithExtension + " (Offset: " + gar.Files[i].Offset.ToString("X8") + ", Len: " + gar.Files[i].Length.ToString("X8") + ")." + Environment.NewLine; } ret += Environment.NewLine; } else if (sharc.valid) { ret += "New Shuffle Archive with " + sharc.FileCount + " files." + Environment.NewLine; string dir = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + sharc.FileName + "_" + Path.DirectorySeparatorChar; if (!Directory.Exists(dir)) { Console.WriteLine("Making dir: " + dir); Directory.CreateDirectory(dir); } string diglen = "".PadLeft((int)(Math.Log10(sharc.FileCount) + 1), '0'); for (int i = 0; i < sharc.FileCount; i++) { var fs = File.OpenRead(path); fs.Seek(sharc.Files[i].Offset, SeekOrigin.Begin); byte[] fileBuffer = new byte[sharc.Files[i].Length]; fs.Read(fileBuffer, 0, fileBuffer.Length); fs.Close(); uint check = 0; for (int j = 0; j < fileBuffer.Length; j += 4) { check += BitConverter.ToUInt32(fileBuffer, j); } Console.WriteLine(i.ToString(diglen) + ": " + check.ToString("X8")); File.WriteAllBytes(dir + i.ToString(diglen) + ".zip", fileBuffer); ret += "Extracted " + i.ToString(diglen) + " (Offset: " + sharc.Files[i].Offset.ToString("X8") + ", Len: " + sharc.Files[i].Length.ToString("X8") + ")." + Environment.NewLine; } ret += Environment.NewLine; } else if (sarc.valid) { ret = "New SARC with " + sarc.SFat.EntryCount + " files." + Environment.NewLine; string dir = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + sarc.FileName + "_" + Path.DirectorySeparatorChar; if (!Directory.Exists(dir)) { Console.WriteLine("Making dir: " + dir); Directory.CreateDirectory(dir); } foreach (SFATEntry t in sarc.SFat.Entries) { var fs = File.OpenRead(path); uint FileLen = t.FileDataEnd - t.FileDataStart; fs.Seek(t.FileDataStart + sarc.DataOffset, SeekOrigin.Begin); byte[] fileBuffer = new byte[FileLen]; fs.Read(fileBuffer, 0, (int)FileLen); fs.Seek(sarc.SFnt.StringOffset, SeekOrigin.Begin); fs.Seek((t.FileNameOffset & 0x00FFFFFF) * 4, SeekOrigin.Current); StringBuilder sb = new StringBuilder(); for (char c = (char)fs.ReadByte(); c != 0; c = (char)fs.ReadByte()) { sb.Append(c); } string FileName = sb.ToString().Replace('/', Path.DirectorySeparatorChar); fs.Close(); string FileDir = Path.GetDirectoryName(dir + FileName) + Path.DirectorySeparatorChar; if (!Directory.Exists(FileDir)) { Console.WriteLine("Making dir: " + FileDir); Directory.CreateDirectory(FileDir); } File.WriteAllBytes(dir + FileName, fileBuffer); } } else { ret = "Not a valid .DARC/.FARC/.SARC/.GAR/Shuffle Archive file"; } return(ret); }
internal static FARC analyzeFARC(string path) { FARC farc = new FARC { FileName = Path.GetFileNameWithoutExtension(path), FilePath = Path.GetDirectoryName(path), Extension = Path.GetExtension(path) }; BinaryReader br = new BinaryReader(File.OpenRead(path)); long len = br.BaseStream.Length; farc.Magic = br.ReadUInt32(); UInt32 m = farc.Magic; farc.HeaderOffset = 0; while (m != 0x43524146 && farc.HeaderOffset < len - 4) //FARC { m = br.ReadUInt32(); farc.HeaderOffset += 4; } if (farc.HeaderOffset >= len - 4) { farc.valid = false; return farc; } farc.Magic = m; farc.valid = true; br.BaseStream.Seek(farc.HeaderOffset + 0x24, SeekOrigin.Begin); farc.SirOffset = br.ReadUInt32() + farc.HeaderOffset; br.ReadUInt32(); //unk farc.DataOffset = br.ReadUInt32() + farc.HeaderOffset; br.BaseStream.Seek(farc.SirOffset, SeekOrigin.Begin); farc.SirMagic = br.ReadUInt32(); if (farc.SirMagic != 0x30524953) { farc.valid = false; return farc; } farc.MetaPointer = farc.SirOffset + br.ReadUInt32(); br.BaseStream.Seek(farc.MetaPointer, SeekOrigin.Begin); farc.TableOffset = farc.SirOffset + br.ReadUInt32(); farc.FileCount = br.ReadUInt32(); br.BaseStream.Seek(farc.TableOffset, SeekOrigin.Begin); FARCFileTable ft = new FARCFileTable { Files = new List<FARCFile>(), FileNames = new List<string>() }; for (int i = 0; i < farc.FileCount; i++) { FARCFile file = new FARCFile { NameOffset = br.ReadUInt32(), Offset = br.ReadUInt32(), Length = br.ReadUInt32() }; br.ReadUInt32(); //align to 0x10 FARCFile f2 = file; ft.Files.Add(f2); } for (int i = 0; i < farc.FileCount; i++) { br.BaseStream.Seek(ft.Files[i].NameOffset + farc.SirOffset, SeekOrigin.Begin); MemoryStream stream = new MemoryStream(); int firstByte = 1, secondByte = 1; while (firstByte != 0 || secondByte != 0) { firstByte = br.ReadByte(); secondByte = br.ReadByte(); stream.WriteByte((byte) firstByte); stream.WriteByte((byte) secondByte); } ft.FileNames.Add(Encoding.Unicode.GetString(stream.ToArray())); stream.Close(); } farc.Files = ft; farc.FileName = Path.GetFileNameWithoutExtension(path); farc.FilePath = Path.GetDirectoryName(path); farc.Extension = Path.GetExtension(path); return farc; }
internal static FARC analyzeFARC(string path) { FARC farc = new FARC { FileName = Path.GetFileNameWithoutExtension(path), FilePath = Path.GetDirectoryName(path), Extension = Path.GetExtension(path) }; BinaryReader br = new BinaryReader(File.OpenRead(path)); long len = br.BaseStream.Length; farc.Magic = br.ReadUInt32(); uint m = farc.Magic; farc.HeaderOffset = 0; while (m != 0x43524146 && farc.HeaderOffset < len - 4) //FARC { m = br.ReadUInt32(); farc.HeaderOffset += 4; } if (farc.HeaderOffset >= len - 4) { farc.valid = false; return(farc); } farc.Magic = m; farc.valid = true; br.BaseStream.Seek(farc.HeaderOffset + 0x24, SeekOrigin.Begin); farc.SirOffset = br.ReadUInt32() + farc.HeaderOffset; br.ReadUInt32(); //unk farc.DataOffset = br.ReadUInt32() + farc.HeaderOffset; br.BaseStream.Seek(farc.SirOffset, SeekOrigin.Begin); farc.SirMagic = br.ReadUInt32(); if (farc.SirMagic != 0x30524953) { farc.valid = false; return(farc); } farc.MetaPointer = farc.SirOffset + br.ReadUInt32(); br.BaseStream.Seek(farc.MetaPointer, SeekOrigin.Begin); farc.TableOffset = farc.SirOffset + br.ReadUInt32(); farc.FileCount = br.ReadUInt32(); br.BaseStream.Seek(farc.TableOffset, SeekOrigin.Begin); FARCFileTable ft = new FARCFileTable { Files = new List <FARCFile>(), FileNames = new List <string>() }; for (int i = 0; i < farc.FileCount; i++) { FARCFile file = new FARCFile { NameOffset = br.ReadUInt32(), Offset = br.ReadUInt32(), Length = br.ReadUInt32() }; br.ReadUInt32(); //align to 0x10 FARCFile f2 = file; ft.Files.Add(f2); } for (int i = 0; i < farc.FileCount; i++) { br.BaseStream.Seek(ft.Files[i].NameOffset + farc.SirOffset, SeekOrigin.Begin); MemoryStream stream = new MemoryStream(); int firstByte = 1, secondByte = 1; while (firstByte != 0 || secondByte != 0) { firstByte = br.ReadByte(); secondByte = br.ReadByte(); stream.WriteByte((byte)firstByte); stream.WriteByte((byte)secondByte); } ft.FileNames.Add(Encoding.Unicode.GetString(stream.ToArray())); stream.Close(); } farc.Files = ft; farc.FileName = Path.GetFileNameWithoutExtension(path); farc.FilePath = Path.GetDirectoryName(path); farc.Extension = Path.GetExtension(path); return(farc); }