/// <summary> /// Try to read the initial and final calibration IDs /// </summary> private bool TryReadCalibrationChange(Blob blob, ref int offset) { uint tempUInt32 = 0; if (!blob.TryGetUInt32(ref tempUInt32, ref offset)) { Trace.WriteLine("This patch file's metadata is way too short (no calibration metadata)."); return false; } if (tempUInt32 != calibrationIdPrefix) { Trace.WriteLine(String.Format("Expected calibration id prefix {0:X8}, found {1:X8}", calibrationIdPrefix, tempUInt32)); return false; } if (!blob.TryGetUInt32(ref tempUInt32, ref offset)) { Trace.WriteLine("This patch file's metadata is way too short (no calibration address)."); return false; } uint calibrationAddress = tempUInt32; if (!blob.TryGetUInt32(ref tempUInt32, ref offset)) { Trace.WriteLine("This patch file's metadata is way too short (no calibration length)."); return false; } uint calibrationLength = tempUInt32; string initialCalibrationId; if (!this.TryReadCalibrationId(blob, ref offset, out initialCalibrationId)) { return false; } this.InitialCalibrationId = initialCalibrationId; string finalCalibrationId; if (!this.TryReadCalibrationId(blob, ref offset, out finalCalibrationId)) { return false; } this.FinalCalibrationId = finalCalibrationId; // Synthesize calibration-change patch and blobs. Patch patch = new Patch( "Calibration ID Patch", calibrationAddress, calibrationAddress + (calibrationLength - 1)); patch.IsMetaChecked = true; patch.Baseline = new Blob( calibrationAddress + Mod.BaselineOffset, Encoding.ASCII.GetBytes(initialCalibrationId)); patch.Payload = new Blob( calibrationAddress, Encoding.ASCII.GetBytes(finalCalibrationId)); this.patchList.AddPatch(patch); return true; }
/// <summary> /// Given a patch, look up the content Blob and write it into the ROM. /// </summary> private bool TryApplyPatch(Patch patch, Stream romStream) { romStream.Seek(patch.StartAddress, SeekOrigin.Begin); if (patch.Payload == null) { Trace.WriteLine(String.Format("No blob found for patch starting at {0:X8}", patch.StartAddress)); return false; } if (patch.StartAddress + patch.Payload.Content.Count != patch.EndAddress + 1) { Trace.WriteLine(String.Format("Payload blob for patch starting at {0:X8} does not contain the entire patch.", patch.StartAddress)); Trace.WriteLine(String.Format("Patch start {0:X8}, end {1:X8}, length {2:X8}", patch.StartAddress, patch.EndAddress, patch.Length)); Trace.WriteLine(String.Format("Payload blob length {2:X8}", patch.Payload.Content.Count)); return false; } romStream.Write(patch.Payload.Content.ToArray(), 0, (int) patch.Payload.Content.Count); return true; }
/// <summary> /// Print the current contents of the ROM in the address range for the given patch. /// Contains a check against metadata when IsMetaChecked = true /// </summary> private bool TryCheckPrintBaseline(Patch patch, Stream outStream) { uint patchLength = patch.Length; byte[] buffer = new byte[patchLength]; //read baseline ROM data blob into buffer if (!this.TryReadBuffer(outStream, patch.StartAddress, buffer)) { return false; } if (patch.IsMetaChecked) { patch.MetaCheck((IEnumerable<byte>)buffer); } using ( StreamWriter textWriter = File.AppendText(this.ModIdent + ".patch")) { //TextWriter textWriter = new StreamWriter(consoleOutputStream); //OUTPUT DIRECT TO FILE, ADD VERSIONING SYSTEM SRecordWriter writer = new SRecordWriter(textWriter); // The "baselineOffset" delta is how we distinguish baseline data from patch data. writer.Write(patch.StartAddress + BaselineOffset, buffer); } return true; }
/// <summary> /// Construct a Pull JSR HOOK patch from the metadata blob. /// </summary> private bool TrySynthesizePullJsrHookPatch(Blob metadata, out Patch patch, ref int offset, List<Blob> blobs) { uint address = 0; string name; if (!metadata.TryGetUInt32(ref address, ref offset)) { throw new InvalidDataException("This patch's metadata contains an incomplete 4-byte patch record (no address)."); } if (!TryReadMetaString(metadata, out name, ref offset)) { Trace.WriteLine("Patch at metadata offset: " + offset + "contains invalid name."); name ="UNKNOWN PATCH"; } byte[] jsrbytes = new byte[] {0xF0,0x48,0x00,0x09}; patch = new PullJSRHookPatch(name, address, address + 3); patch.IsMetaChecked = true;//remove thsi patch.Payload = new Blob(patch.StartAddress, jsrbytes); //this.blobs.Add(new Blob(address, BitConverter.GetBytes(newValue).Reverse())); //this.blobs.Add(new Blob(address + BaselineOffset, BitConverter.GetBytes(oldValue).Reverse())); return true; }
/// <summary> /// Determine whether the bytes from a Patch's expected data match the contents of the ROM. /// </summary> private bool ValidateBytes(Patch patch, Stream romStream) { uint patchLength = patch.Length; byte[] buffer = new byte[patchLength]; if (!this.TryReadBuffer(romStream, patch.StartAddress, buffer)) { Console.Write("tryreadbuffer failed in validatebytes"); return false; } // DumpBuffer("Actual ", buffer, buffer.Length); // DumpBuffer("Expected", expectedData.Content, buffer.Length); int mismatches = 0; byte expected; for (int index = 0; index < patchLength; index++) { byte actual = buffer[index]; if (!patch.IsNewPatch) { if (index >= patch.Baseline.Content.Count) { Trace.WriteLine("Expected data is smaller than patch size."); return false; } expected = patch.Baseline.Content[index]; } else expected = 0xFF; if (actual != expected) { mismatches++; } } if (mismatches == 0) { Trace.WriteLine("Valid."); return true; } Trace.WriteLine("Invalid."); Trace.WriteLine(String.Format("{0} bytes (of {1}) do not meet expectations.", mismatches, patchLength)); return false; }
/// <summary> /// Construct a Last 2 of 4-byte patch from the metadata blob. /// </summary> private bool TrySynthesizeLast2Of4BytePatch(Blob metadata, out Patch patch, ref int offset) { uint address = 0; uint oldValue = 0; uint newValue = 0; string name; if (!metadata.TryGetUInt32(ref address, ref offset)) { throw new InvalidDataException("This patch's metadata contains an incomplete l2o4-byte patch record (no address)."); } if (!metadata.TryGetUInt32(ref oldValue, ref offset)) { throw new InvalidDataException("This patch's metadata contains an incomplete l2o4-byte patch record (no baseline value)."); } if (!metadata.TryGetUInt32(ref newValue, ref offset)) { throw new InvalidDataException("This patch's metadata contains an incomplete l2o4-byte patch record (no patch value)."); } if (!TryReadMetaString(metadata, out name, ref offset)) { Trace.WriteLine("Patch at metadata offset: " + offset + "contains invalid name."); name ="UNKNOWN PATCH"; } patch = new Patch(name, address + 2, address + 3); patch.IsMetaChecked = true; patch.Baseline = new Blob(address + 2 + BaselineOffset, BitConverter.GetBytes(oldValue).Take(2).Reverse()); patch.Payload = new Blob(address + 2, BitConverter.GetBytes(newValue).Take(2).Reverse()); return true; }
/// <summary> /// Read a single Patch from the metadata blob. /// </summary> /// <remarks> /// Consider returning false, printing error message. But, need to /// be certain to abort the whole process at that point... /// </remarks> private bool TryReadPatch(Blob metadata, out Patch patch, ref int offset, List<Blob> blobs ) { uint start = 0; uint end = 0; string name; if (!metadata.TryGetUInt32(ref start, ref offset)) { throw new InvalidDataException("Patch at metadata offset: " + offset + " contains an incomplete patch record (no start address)."); } if (!metadata.TryGetUInt32(ref end, ref offset)) { throw new InvalidDataException("Patch at metadata offset: " + offset + " contains an incomplete patch record (no end address)."); } if(!TryReadMetaString(metadata,out name, ref offset)) { Trace.WriteLine("Patch at metadata offset: " + offset + "contains invalid name."); name ="UNKNOWN PATCH"; } patch = new Patch(name,start, end); Blob baselineBlob; if (!this.TryGetPatchBlob(patch.StartAddress + BaselineOffset, patch.Length, out baselineBlob, blobs)) { if (baselineBlob != null) return false; } patch.Baseline = baselineBlob; Blob payloadBlob; if (!this.TryGetPatchBlob(patch.StartAddress, patch.Length, out payloadBlob, blobs)) { return false; } patch.Payload = payloadBlob; return true; }
private bool TryReadMetaHeader8(Blob metadata, ref int offset) { UInt32 cookie = 0; uint tempInt = 0; Patch patch = null; while ((metadata.Content.Count > offset + 8) && metadata.TryGetUInt32(ref cookie, ref offset)) { if (cookie == Mod.calibrationIdPrefix) { if (!metadata.TryGetUInt32(ref tempInt, ref offset)) { Trace.WriteLine("This patch file's metadata is way too short (no calibration address)."); return false; } this.CalIdAddress = tempInt; if (!metadata.TryGetUInt32(ref tempInt, ref offset)) { Trace.WriteLine("This patch file's metadata is way too short (no calibration length)."); return false; } this.CalIdLength = tempInt; string initialCalibrationId; if (!this.TryReadCalibrationId(metadata, ref offset, out initialCalibrationId)) { return false; } this.InitialCalibrationId = initialCalibrationId; string finalCalibrationId; if (!this.TryReadCalibrationId(metadata, ref offset, out finalCalibrationId)) { return false; } if (finalCalibrationId.ContainsCI("ffffffff")) { StringBuilder s = new StringBuilder(initialCalibrationId, 0,initialCalibrationId.Length, initialCalibrationId.Length); s.Remove(initialCalibrationId.Length-2,2); s.Insert(initialCalibrationId.Length-2,"MM"); FinalCalibrationId = s.ToString(); } this.FinalCalibrationId = finalCalibrationId; // Synthesize calibration-change patch and blobs. patch = new Patch( "Calibration ID Patch", CalIdAddress, CalIdAddress + (CalIdLength - 1)); patch.IsMetaChecked = true; patch.Baseline = new Blob( CalIdAddress + Mod.BaselineOffset, Encoding.ASCII.GetBytes(initialCalibrationId)); patch.Payload = new Blob( CalIdAddress, Encoding.ASCII.GetBytes(finalCalibrationId)); this.patchList.AddPatch(patch); } else if (cookie == modIdPrefix) { if (metadata.TryGetUInt32(ref tempInt, ref offset)) { this.ModIdentAddress = tempInt; } string metaString = null; if (this.TryReadMetaString(metadata, out metaString, ref offset)) { // found modName, output to string! this.ModIdent = metaString; } } else if (cookie == ecuIdPrefix) { if (metadata.TryGetUInt32(ref tempInt, ref offset)) { this.EcuIdAddress = tempInt; } if (metadata.TryGetUInt32(ref tempInt, ref offset)) { this.EcuIdLength = tempInt; } string metaString = null; if (this.TryReadMetaString(metadata, out metaString, ref offset)) { // found modName, output to string! this.InitialEcuId = metaString; } metadata.TryGetUInt32(ref tempInt, ref offset); if (this.TryReadMetaString(metadata, out metaString, ref offset)) { // found modName, output to string! this.FinalEcuId = metaString; } } else if (cookie == modAuthorPrefix) { string metaString = null; if (this.TryReadMetaString(metadata, out metaString, ref offset)) { // found modName, output to string! this.ModAuthor = metaString; } else { Trace.WriteLine("Invalid patch found." + patch.ToString()); return false; } } else if (cookie == modBuildPrefix) { string metaString = null; if (this.TryReadMetaString(metadata, out metaString, ref offset)) { // found modName, output to string! this.ModBuild = metaString; } else { Trace.WriteLine("Invalid patch found." + patch.ToString()); return false; } } else if (cookie == modInfoPrefix) { string metaString = null; if (this.TryReadMetaString(metadata, out metaString, ref offset)) { // found Trace.WriteLine("Patch at metadata offset: " + offset + "contains invalid name."); name ="UNKNOWN PATCH";, output to string! this.ModInfo = metaString.Replace("__", Environment.NewLine); } else { Trace.WriteLine("Invalid ModInfo found." + patch.ToString()); return false; } } else if (cookie == endoffile) { break; } } if (this.InitialEcuId.Length == this.FinalEcuId.Length) { // Synthesize calibration-change patch and blobs. if (FinalEcuId.ContainsCI("ffffffff")) { StringBuilder feid = new StringBuilder(Regex.Split(this.ModIdent,".v")[1].Replace(".", "")); while (feid.Length < this.InitialEcuId.Length) { feid.Append("F"); } this.FinalEcuId = feid.ToString(); } patch = new Patch( "ECU ID Patch", EcuIdAddress, EcuIdAddress + ((EcuIdLength / 2) - 1)); patch.IsMetaChecked = true; patch.Baseline = new Blob( EcuIdAddress + Mod.BaselineOffset, InitialEcuId.ToByteArray()); patch.Payload = new Blob( EcuIdAddress, FinalEcuId.ToByteArray()); this.patchList.AddPatch(patch); } if (this.patchList.Count < 2) { Trace.WriteLine("This patch file's metadata contains no CALID or ECUID patch!!."); return false; } return true; }
private bool TryProcessRecord(Patch patch, SRecord record) { if (record.Payload == null) { return true; } int startAddress = (int)(this.apply ? patch.StartAddress : patch.StartAddress + Mod.BaselineOffset); int endAddress = (int)(this.apply ? patch.EndAddress : patch.EndAddress + Mod.BaselineOffset); for (uint address = record.Address; address < record.Address + record.Payload.Length; address++) { if (address >= startAddress && address <= endAddress) { this.romStream.Position = address; int i = this.romStream.ReadByte(); if (i == -1) { Trace.WriteLine(String.Format("Reached end of file while trying to verify address {0:X8}", address)); return false; } int recordAddresss = (int)(this.apply ? record.Address : record.Address - Mod.BaselineOffset); uint payloadIndex = address - record.Address; byte b = record.Payload[payloadIndex]; if (i != b) { Trace.WriteLine(String.Format("Address {0:X8} contains {1:X2}, but should contain {2:X2}", address, b, payloadIndex)); return false; } } } return true; }
private bool TryVerifyPatch(Patch patch) { // using (this.patchReader) //using (this.romStream) //{ // this.patchReader.Open(); SRecord record; while (this.patchReader.TryReadNextRecord(out record)) { if (!this.TryProcessRecord(patch, record)) { Dispose(); return false; } } Dispose(); return true; }