public Patcher(string patch_id) { // build the location of the patch definition resource // open the resource for reading Stream xml_stream = null; xml_stream = GetType().Assembly.GetManifestResourceStream(String.Format("FilePatcher.PatchDefinitions.{0}.xml", patch_id)); if (xml_stream == null) { throw new Exception(String.Format("Matching patch definition for {0} was not found. Inform the developers of the problem.", patch_id)); } // deserialize the definition xml XmlSerializer serializer = new XmlSerializer(typeof(FilePatch)); m_file_patch = serializer.Deserialize(xml_stream) as FilePatch; if (m_file_patch == null) { throw new Exception(String.Format("Failed to deserialize a file patch xml {0}. Inform the developers of the problem.", patch_id)); } // create the message list ErrorMessages = new List <string>(); }
private bool WriteData(uint address, FilePatch.Data data, Stream output) { uint peaddress = 0; if(!ParseHex(m_file_patch.PEAddressMaskString, out peaddress)) { ErrorMessages.Add(String.Format("Failed to parse PE address mask string ({0}). Inform the developers of this.", data.ID)); return false; } // calculate the byte address and move to it long write_address = address - peaddress; if (write_address >= output.Length) { ErrorMessages.Add(String.Format("Failed to write patch data ({0}) as the pointer is beyond the end of the file. Inform the developers of this.", data.ID)); return false; } output.Seek(write_address, SeekOrigin.Begin); int write_length = data.Length; switch (data.Type) { case FilePatch.ValueType.String: { // default write length to te length of the string if zero if(write_length == 0) write_length = data.Value.Length; if ((write_address + write_length) >= output.Length) { ErrorMessages.Add(String.Format("Failed to write patch data ({0}) as the data would write beyond the end of the file. Inform the developers of this.", data.ID)); return false; } // write the strings bytes as ASCII byte[] bytes = Encoding.ASCII.GetBytes(data.Value); output.Write(bytes, 0, write_length); // if necessary, write a null character to terminate the string if (data.WriteNull) output.WriteByte(0); } break; case FilePatch.ValueType.UInteger32: { if ((write_address + 4) >= output.Length) { ErrorMessages.Add(String.Format("Failed to write patch data ({0}) as the data would write beyond the end of the file. Inform the developers of this.", data.ID)); return false; } // try and parse the hex string uint parsed_value; if (!ParseHex(data.Value, out parsed_value)) { ErrorMessages.Add(String.Format("Failed to parse a uint32 ({0}). Inform the developers of this.", data.ID)); return false; } // swap the uint's endianness if required if (data.SwapEndian) { uint endian_swapped = 0; endian_swapped |= (uint)((parsed_value & 0xff000000) >> 24); endian_swapped |= (uint)((parsed_value & 0x00ff0000) >> 8); endian_swapped |= (uint)((parsed_value & 0x0000ff00) << 8); endian_swapped |= (uint)((parsed_value & 0x000000ff) << 24); parsed_value = endian_swapped; } // write the value to the stream output.Write(BitConverter.GetBytes(parsed_value), 0, 4); } break; case FilePatch.ValueType.UInteger16: { if ((write_address + 2) >= output.Length) { ErrorMessages.Add(String.Format("Failed to write patch data ({0}) as the data would write beyond the end of the file. Inform the developers of this.", data.ID)); return false; } // try and parse the hex string ushort parsed_value; if (!ParseHex(data.Value, out parsed_value)) { ErrorMessages.Add(String.Format("Failed to parse a uint16 ({0}). Inform the developers of this.", data.ID)); return false; } // swap the uint's endianness if required if (data.SwapEndian) { ushort endian_swapped = 0; endian_swapped |= (ushort)((parsed_value & 0xff00) >> 8); endian_swapped |= (ushort)((parsed_value & 0x00ff) << 8); parsed_value = endian_swapped; } // write the value to the stream output.Write(BitConverter.GetBytes(parsed_value), 0, 2); } break; case FilePatch.ValueType.Byte: { if ((write_address + 1) >= output.Length) { ErrorMessages.Add(String.Format("Failed to write patch data ({0}) as the data would write beyond the end of the file. Inform the developers of this.", data.ID)); return false; } // try and parse the hex string byte parsed_value; if (!ParseHex(data.Value, out parsed_value)) { ErrorMessages.Add(String.Format("Failed to parse a byte ({0}). Inform the developers of this.", data.ID)); return false; } // write the value to the stream output.WriteByte(parsed_value); } break; case FilePatch.ValueType.Bytes: { // check the strings length is a multiple of two if (data.Value.Length % 2 != 0) { ErrorMessages.Add(String.Format("The length of a hex byte string ({0}) in the file patcher is odd. Inform the developers.", data.ID)); return false; } // create the byte array using (MemoryStream byte_stream = new MemoryStream()) { // convert every two characters into a byte for (int i = 0; i < data.Value.Length; i += 2) { byte parsed_byte = 0; if(!ParseHex(data.Value.Substring(i, 2), out parsed_byte)) { ErrorMessages.Add(String.Format("Failed to parse a byte array ({0}). Inform the developers of this.", data.ID)); return false; } byte_stream.WriteByte(parsed_byte); } // default the write length to the array length if zero if (write_length == 0) write_length = (int)byte_stream.Length; if ((write_address + write_length) >= output.Length) { ErrorMessages.Add(String.Format("Failed to write patch data ({0}) as the data would write beyond the end of the file. Inform the developers of this.", data.ID)); return false; } // write the byte array to the stream output.Write(byte_stream.GetBuffer(), 0, write_length); } } break; } return true; }
private bool ApplyPatch(FilePatch.Patch patch, Stream file) { // apply each patch foreach (var address in patch.Addresses) { // find a matching data block FilePatch.Data data = patch.Data.Find( delegate(FilePatch.Data value) { if (address.Value.Equals(value.ID)) return true; return false; } ); // error if a data block was not found if (data == null) { ErrorMessages.Add(String.Format("A patch address references an invalid data id ({0}). Inform the developers of this", address.Value)); return false; } // parse the address uint pointer = 0; if (!ParseHex(address.PTRString, out pointer)) { ErrorMessages.Add(String.Format("Failed to parse an addresses pointer string ({0}). Inform the developers of this", address.Value)); return false; } // write the data to the current address if (!WriteData(pointer, data, file)) return false; } return true; }
public Patcher(string patch_id) { // build the location of the patch definition resource // open the resource for reading Stream xml_stream = null; xml_stream = GetType().Assembly.GetManifestResourceStream(String.Format("FilePatcher.PatchDefinitions.{0}.xml", patch_id)); if (xml_stream == null) throw new Exception(String.Format("Matching patch definition for {0} was not found. Inform the developers of the problem.", patch_id)); // deserialize the definition xml XmlSerializer serializer = new XmlSerializer(typeof(FilePatch)); m_file_patch = serializer.Deserialize(xml_stream) as FilePatch; if (m_file_patch == null) throw new Exception(String.Format("Failed to deserialize a file patch xml {0}. Inform the developers of the problem.", patch_id)); // create the message list ErrorMessages = new List<string>(); }