using System; using System.Collections.Generic; using System.Text; namespace Pterodactyl { public class OSUpgradeFile { #region Declarations private const int _PAGE_SIZE = 16384; private string _path; private Dictionary _pages; public enum CalculatorModel { TI73 = 1, TI83P = 2, TI83PSE = 3, TI84P = 4, TI84PSE = 5 }; #endregion #region Constructors/Teardown public OSUpgradeFile(string path) { _path = path; _pages = new Dictionary(); _ParseFile(path); } #endregion #region Public Methods public byte[] ToBinaryImage(CalculatorModel model) { //Determine number of pages depending on model int pages; switch (model) { case CalculatorModel.TI73: case CalculatorModel.TI83P: pages = 0x20; break; case CalculatorModel.TI84P: pages = 0x40; break; case CalculatorModel.TI83PSE: case CalculatorModel.TI84PSE: pages = 0x80; break; default: throw new InvalidOperationException("Invalid model specified!"); } //Create the byte array var ret = new byte[_PAGE_SIZE * pages]; for (int i = 0; i < ret.Length; i++) ret[i] = 0xFF; //For each page, fill in the data if we have it for (int i = 0; i < pages; i++) { int page = i; if (page > 0x08) page |= (pages - 0x10); //Assume all 0xFF to start with for (int j = 0; j < _PAGE_SIZE; j++) ret[_PAGE_SIZE * page + j] = 0xFF; //Now fill in what we have for this page if (_pages.ContainsKey(i)) { for (int j = 0; j < _pages[i].Length; j++) ret[_PAGE_SIZE * page + j] = _pages[i][j]; } } return ret; } #endregion #region Local Methods private void _ParseFile(string path) { //Get the string data from the Intel Hex file //This is awful... var stream = new System.IO.FileStream(path, System.IO.FileMode.Open); stream.Seek(0x4E, System.IO.SeekOrigin.Begin); long remaining = (long)stream.Length - stream.Position; var raw = new byte[remaining]; stream.Read(raw, 0, (int)remaining); stream.Close(); var data = new char[remaining]; for (int i = 0; i < raw.Length; i++) data[i] = (char)raw[i]; var hexData = new System.IO.StringReader(new string(data)); string line; int lastPage = 0; bool captureData = false; do { line = hexData.ReadLine(); //Parse Intel Hex line if (line != null) { if (line != null && line.Length > 0 && line[0] == ':') { //Get rid of the colon line = line.TrimStart(':'); //Extract the data out of the string int bytes = Convert.ToInt32(line.Substring(0, 2), 16); int address = Convert.ToInt32(line.Substring(2, 4), 16); int type = Convert.ToInt32(line.Substring(6, 2), 16); var dataBytes = new byte[bytes]; for (int i = 0; i < bytes; i++) dataBytes[i] = Convert.ToByte(line.Substring(8 + (i * 2), 2), 16); switch (type) { case 1: //not sure... { captureData = !captureData; } break; case 0: //data { if (captureData) { //Add the page array if we don't already have it if (!_pages.ContainsKey(lastPage)) _pages.Add(lastPage, new byte[_PAGE_SIZE]); //Save the data in our array for (int i = 0; i < dataBytes.Length; i++) _pages[lastPage][(address & (_PAGE_SIZE - 1)) + i] = dataBytes[i]; } } break; case 2: //page record { lastPage = ((dataBytes[0] << 8) | dataBytes[1]) & 0x1F; } break; default: throw new InvalidOperationException("Invalid record type " + type); } } } } while (line != null); hexData.Close(); } #endregion } }