using System; using System.Collections.Generic; using System.Text; namespace Pterodactyl { class Startup { static void Main(string[] args) { try { if (args.Length < 1) { throw new InvalidArgumentsException("No arguments specified"); } else { string command = Convert.ToString(args[0]).Trim().ToLower(); switch (command) { case "73u2rom": case "8xu2rom": { if (args.Length != 3) throw new InvalidArgumentsException(command, "Invalid number of arguments"); //Convert the file _ConvertXXUToBIN(args[1], args[2]); } break; case "extract": { //Extract contents of a file given offset and length into a separate file if (args.Length != 5) throw new InvalidArgumentsException(command, "Invalid number of arguments"); //Extract the data _ExtractData(args[1], Convert.ToInt32(args[2], 16), Convert.ToInt32(args[3], 16), args[4]); } break; case "idcscript": { //Generate an IDC script file from text file of equates if (args.Length != 3) throw new InvalidArgumentsException(command, "Invalid number of arguments"); _GenerateIDCScript(args[1], args[2]); } break; case "eplocs": { //Generate text files of entry point (BCALL) locations if (args.Length != 7) throw new InvalidArgumentsException(command, "Invalid number of arguments"); _GenerateEPLocations(args[1], Convert.ToInt32(args[2], 16), Convert.ToInt32(args[3], 16), Convert.ToInt32(args[4], 16), args[5], args[6]); } break; case "eplocs0": { //Generate text file of page 0 equates using entry point locations/names if (args.Length != 7) throw new InvalidArgumentsException(command, "Invalid number of arguments"); _GenerateEP0Locations(args[1], Convert.ToInt32(args[2], 16), Convert.ToInt32(args[3], 16), Convert.ToInt32(args[4], 16), args[5], args[6]); } break; case "makeequ": { //Generate text file of equates for entry point locations given page if (args.Length != 4) throw new InvalidArgumentsException(command, "Invalid number of arguments"); _GenerateEquatesFile(args[1], Convert.ToInt32(args[2], 16), args[3]); } break; default: throw new InvalidArgumentsException("Invalid command: " + args[0]); } } } catch (InvalidArgumentsException iaex) { _WriteUsage(iaex.Command, iaex.Message); } catch (CommandException cex) { _WriteError(cex.Command, cex.Message); } catch (Exception ex) { _WriteError(ex.Message); } if (System.Diagnostics.Debugger.IsAttached) Console.ReadKey(); } private static void _WriteError(string message) { var asm = System.Reflection.Assembly.GetExecutingAssembly(); var asmName = asm.GetName(); Console.WriteLine(asmName.FullName + " v" + asmName.Version.ToString(3)); Console.WriteLine("Performs a variety of functions useful for disassembling 73U/8XU OSes."); Console.WriteLine(); Console.WriteLine("Usage: [command] [arguments for command]"); Console.WriteLine(" where [command] is one of the following:"); Console.WriteLine(); Console.WriteLine("73u2rom Converts a 73U file into a binary ROM image."); Console.WriteLine("8xu2rom Converts an 8XU file into a binary ROM image."); Console.WriteLine(); Console.WriteLine("Run each command without any arguments for specific usage."); Console.WriteLine(); Console.WriteLine("ERROR: " + message); } private static void _WriteError(string command, string message) { var asm = System.Reflection.Assembly.GetExecutingAssembly(); var asmName = asm.GetName(); Console.WriteLine(asmName.FullName + " v" + asmName.Version.ToString(3)); Console.WriteLine("Performs a variety of functions useful for disassembling 73U/8XU OSes."); Console.WriteLine(); Console.WriteLine(String.Format("ERROR: {0}: {1}", command, message)); } private static void _WriteUsage(string command, string message) { var asm = System.Reflection.Assembly.GetExecutingAssembly(); var asmName = asm.GetName(); Console.WriteLine(asmName.Name + " v" + asmName.Version.ToString(3)); Console.WriteLine("Performs a variety of functions useful for disassembling 73U/8XU OSes."); Console.WriteLine(); if (String.IsNullOrEmpty(command)) Console.WriteLine("ERROR: " + message); else Console.WriteLine(String.Format("ERROR: {0}: {1}", command, message)); Console.WriteLine(); switch (command) { case "73u2rom": { Console.WriteLine("Usage: 73u2rom [input file] [output file]"); } break; case "8xu2rom": { Console.WriteLine("Usage: 8xu2rom [input file] [output file]"); } break; case "extract": { Console.WriteLine("Usage: extract [input file] [offset in hex]"); Console.WriteLine(" [length in hex] [output file]"); } break; case "idcscript": { Console.WriteLine("Usage: idcscript [text file of equates] [output IDC file]"); Console.WriteLine(" Text file must contain one entry per line as below:"); Console.WriteLine(" [4-character address in hex]:[name of equate]"); } break; case "eplocs": { Console.WriteLine("Usage: eplocs [binary file containing address:page entries]"); Console.WriteLine(" [start offset, points to first entry]"); Console.WriteLine(" [end offset, points beyond last entry]"); Console.WriteLine(" [entry point address of first entry (ex. 4000)]"); Console.WriteLine(" [file of ti83plus.inc equates]"); Console.WriteLine(" [output text file]"); Console.WriteLine(" Equates file should only have entry point EQU lines."); Console.WriteLine(" Output file contains entries in following format:"); Console.WriteLine(" page:address:entryPointAddress:entryPointName"); Console.WriteLine(" Page is 2-char hex, address is 4-char hex."); Console.WriteLine(" entryPointAddress is 4-char hex."); Console.WriteLine(" entryPointName is calculated if not in equates file."); } break; default: break; } } private static void _ConvertXXUToBIN(string infile, string outfile) { var file = new OSUpgradeFile(infile); var stream = new System.IO.FileStream(outfile, System.IO.FileMode.Create); var rom = new System.IO.BinaryWriter(stream); rom.Write(file.ToBinaryImage(OSUpgradeFile.CalculatorModel.TI83P)); rom.Close(); Console.WriteLine(String.Format("File {0} successfully written.", outfile)); } private static void _ExtractData(string infile, int offset, int length, string outfile) { var stream = new System.IO.FileStream(infile, System.IO.FileMode.Open); stream.Seek(offset, System.IO.SeekOrigin.Begin); var output = new System.IO.FileStream(outfile, System.IO.FileMode.Create); var data = new byte[length]; stream.Read(data, 0, length); stream.Close(); output.Write(data, 0, length); output.Close(); Console.WriteLine(String.Format("File {0} successfully written.", outfile)); } private static void _GenerateIDCScript(string infile, string outfile) { //Read in file of equates var equates = new Dictionary(); var reader = new System.IO.StreamReader(infile); string line; do { line = reader.ReadLine(); if (line != null && line.Contains(":")) { var strs = line.Split(':'); int address = Convert.ToInt32(strs[0], 16); if (equates.ContainsKey(address)) { Console.WriteLine(String.Format("WARNING: Address {0}, equate {1} already exists.", strs[0], strs[1])); } else { equates.Add(address, strs[1]); } } } while (line != null); reader.Close(); //Write out start of IDC script var output = new System.IO.StreamWriter(outfile); output.WriteLine("#define UNLOADED_FILE 1"); output.WriteLine("#include "); output.WriteLine(); output.WriteLine("static main(void) {"); //Write out equates foreach (var equate in equates) { output.WriteLine(String.Format(" MakeName (0X{0}, \"{1}\");", Convert.ToString(equate.Key, 16), equate.Value)); if (equate.Key <= 0x8000) { output.WriteLine(String.Format(" MakeCode (0X{0});", Convert.ToString(equate.Key, 16))); } } //Finalize IDC script file output.WriteLine("}"); output.WriteLine(); output.Close(); Console.WriteLine(String.Format("File {0} successfully written.", outfile)); } public struct EPEntry { public int page; public int address; public int entryPointAddress; public string entryPointName; }; private static void _GenerateEPLocations(string infile, int startAddress, int endAddress, int epAddressBase, string equatefile, string outfile) { //Read in address:page entries var stream = new System.IO.FileStream(infile, System.IO.FileMode.Open); stream.Seek(startAddress & 0x3FFF, System.IO.SeekOrigin.Begin); var data = new byte[endAddress-startAddress]; stream.Read(data, 0, data.Length); stream.Close(); //Generate list of entries from the raw data var entries = new List(); int epAddress = epAddressBase; for (int i = 0; i < data.Length / 3; i++) { var entry = new EPEntry(); entry.address = (data[i * 3 + 1] << 8) | data[i * 3 + 0]; entry.page = data[i * 3 + 2]; entry.entryPointAddress = epAddress; entries.Add(entry); epAddress += 3; } //Read in the file of equates var equates = new System.IO.StreamReader(equatefile); string line; var epNames = new Dictionary(); do { line = equates.ReadLine(); if (line != null && line.ToLower().Contains("equ")) { var strs = line.Split(new string[] { " ", "\t" }, StringSplitOptions.RemoveEmptyEntries); epNames.Add(Convert.ToInt32(strs[2].TrimEnd('h'), 16), strs[0]); } } while (line != null); equates.Close(); //Try to assign names to our entries for (int i = 0; i < entries.Count; i++) { var entry = entries[i]; if (epNames.ContainsKey(entries[i].entryPointAddress)) { entry.entryPointName = epNames[entry.entryPointAddress]; } else { entry.entryPointName = "BCALL_" + String.Format("{0:X4}", entry.entryPointAddress); } entries[i] = entry; } //Write out text file of entries var output = new System.IO.StreamWriter(outfile); for (int i = 0; i < entries.Count; i++) { output.WriteLine(String.Format("{0:X2}:{1:X4}:{2:X4}:{3}", entries[i].page, entries[i].address, entries[i].entryPointAddress, entries[i].entryPointName)); } output.Close(); Console.WriteLine(String.Format("File {0} written successfully.", outfile)); } private static void _GenerateEP0Locations(string infile, int startAddress, int endAddress, int epAddressBase, string locfile, string outfile) { //Read in address:page entries var stream = new System.IO.FileStream(infile, System.IO.FileMode.Open); stream.Seek(startAddress, System.IO.SeekOrigin.Begin); var data = new byte[endAddress - startAddress]; stream.Read(data, 0, data.Length); stream.Close(); //Generate list of entries from the raw data var entries = new List(); int epAddress = epAddressBase; for (int i = 0; i < data.Length / 6; i++) { var entry = new EPEntry(); entry.address = (data[i * 6 + 1 + 3] << 8) | data[i * 6 + 0 + 3]; entry.page = data[i * 6 + 2 + 3]; entry.entryPointAddress = epAddress; entries.Add(entry); epAddress += 6; } //Read in the file of equates var locs = new System.IO.StreamReader(locfile); string line; var epNames = new List(); do { line = locs.ReadLine(); if (line != null && line.Length > 0) { //Get the BCALL list var entry = new EPEntry(); entry.page = Convert.ToInt32(line.Substring(0, 2), 16); entry.address = Convert.ToInt32(line.Substring(3, 4), 16); entry.entryPointAddress = Convert.ToInt32(line.Substring(8, 4), 16); entry.entryPointName = line.Substring(13); epNames.Add(entry); } } while (line != null); locs.Close(); //Try to assign names to our entries for (int i = 0; i < entries.Count; i++) { var entry = entries[i]; EPEntry foundEntry = new EPEntry(); bool found = false; for (int j = 0; j < epNames.Count; j++) { if (epNames[j].page == entry.page && epNames[j].address == entry.address) { foundEntry = epNames[j]; found = true; break; } } if (found) { entry.entryPointName = foundEntry.entryPointName; } else { entry.entryPointName = "Page0Call_" + String.Format("{0:X4}", entry.entryPointAddress); } entries[i] = entry; } //Write out text file of entries var output = new System.IO.StreamWriter(outfile); for (int i = 0; i < entries.Count; i++) { output.WriteLine(String.Format("{0:X4}:{1}", entries[i].entryPointAddress, entries[i].entryPointName)); } output.Close(); Console.WriteLine(String.Format("File {0} written successfully.", outfile)); } private static void _GenerateEquatesFile(string infile, int page, string outfile) { //Read in the entry point locations file var locs = new System.IO.StreamReader(infile); string line; var epNames = new List(); do { line = locs.ReadLine(); if (line != null && line.Length > 0) { //Get the BCALL list var entry = new EPEntry(); entry.page = Convert.ToInt32(line.Substring(0, 2), 16); entry.address = Convert.ToInt32(line.Substring(3, 4), 16); entry.entryPointAddress = Convert.ToInt32(line.Substring(8, 4), 16); entry.entryPointName = line.Substring(13); epNames.Add(entry); } } while (line != null); locs.Close(); //Write out text file of equates that match the requested page var output = new System.IO.StreamWriter(outfile); foreach (var entry in epNames) { if (entry.page == page) { output.WriteLine(String.Format("{0:X4}:{1}", entry.address, entry.entryPointName)); } } output.Close(); Console.WriteLine(String.Format("File {0} written successfully.", outfile)); } } }