//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Writes a ushort patch value to a stream. </summary> /// /// <param name="target"> The target stream. </param> /// <param name="writeAddress"> The address to write to. </param> /// <param name="data"> The data to write. </param> /// /// <returns> true if it succeeds, false if it fails. </returns> private bool WriteUInt16(MemoryStream target , long writeAddress , PatchDefinition.Data data) { if ((writeAddress + 2) >= target.Length) { OnErrorOccurred("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 parsedValue; if (!Utilities.Parse.TryParseHex(data.Value, out parsedValue)) { OnErrorOccurred("Failed to parse value ({0}). Inform the developers of this.", data.ID); return(false); } // Swap the value's endianness if required if (data.SwapEndian) { ushort endianSwapped = 0; endianSwapped |= (ushort)((parsedValue & 0xff00) >> 8); endianSwapped |= (ushort)((parsedValue & 0x00ff) << 8); parsedValue = endianSwapped; } // Write the value to the stream target.Seek(writeAddress, SeekOrigin.Begin); target.Write(BitConverter.GetBytes(parsedValue), 0, 2); return(true); }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Writes a string patch value to a stream. </summary> /// /// <param name="target"> The target stream. </param> /// <param name="writeAddress"> The address to write to. </param> /// <param name="data"> The data to write. </param> /// /// <returns> true if it succeeds, false if it fails. </returns> private bool WriteString(Stream target , long writeAddress , PatchDefinition.Data data) { // Default write length to the length of the string if zero int writeLength = data.Length; if (writeLength == 0) { writeLength = data.Value.Length; } // Check we are not writing out of bounds if ((writeAddress + writeLength) >= target.Length) { OnErrorOccurred("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 var bytes = Encoding.ASCII.GetBytes(data.Value); target.Seek(writeAddress, SeekOrigin.Begin); target.Write(bytes, 0, writeLength); // If necessary, write a null character to terminate the string if (data.WriteNull) { target.WriteByte(0); } return(true); }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Writes a byte array patch value to a stream. </summary> /// /// <param name="target"> The target stream. </param> /// <param name="writeAddress"> The address to write to. </param> /// <param name="data"> The data to write. </param> /// /// <returns> true if it succeeds, false if it fails. </returns> private bool WriteBytes(Stream target , long writeAddress , PatchDefinition.Data data) { // Check the strings length is a multiple of two if (data.Value.Length % 2 != 0) { OnErrorOccurred("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 byte[] bytes = null; try { // Convert every two characters into a byte bytes = Enumerable.Range(0, data.Value.Length) .Where(index => (index % 2) == 0) .Select(index => Convert.ToByte(data.Value.Substring(index, 2), 16)) .ToArray(); } catch (Exception) { OnErrorOccurred("Failed to parse a byte array ({0}). Inform the developers of this.", data.ID); return(false); } // Default the write length to the array length if zero int writeLength = data.Length; if (writeLength == 0) { writeLength = bytes.Length; } if ((writeAddress + writeLength) >= target.Length) { OnErrorOccurred("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 target.Seek(writeAddress, SeekOrigin.Begin); target.Write(bytes, 0, writeLength); return(true); }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Writes patch data to a stream. </summary> /// /// <param name="output"> The output stream. </param> /// <param name="address"> The write address. </param> /// <param name="imageBase"> The image base address. </param> /// <param name="data"> The data to write. </param> /// /// <returns> true if it succeeds, false if it fails. </returns> private bool WriteData(MemoryStream output, uint address, int imageBase, PatchDefinition.Data data) { // Calculate the byte address and move to it long writeAddress = address - imageBase; if (writeAddress >= output.Length) { OnErrorOccurred("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(writeAddress, SeekOrigin.Begin); bool success = false; switch (data.Type) { case PatchDefinition.ValueType.String: success = WriteString(output, writeAddress, data); break; case PatchDefinition.ValueType.UInteger32: success = WriteUInt32(output, writeAddress, data); break; case PatchDefinition.ValueType.UInteger16: success = WriteUInt16(output, writeAddress, data); break; case PatchDefinition.ValueType.Byte: success = WriteByte(output, writeAddress, data); break; case PatchDefinition.ValueType.Bytes: success = WriteBytes(output, writeAddress, data); break; } return(success); }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Writes a byte patch value to a stream. </summary> /// /// <param name="target"> The target stream. </param> /// <param name="writeAddress"> The address to write to. </param> /// <param name="data"> The data to write. </param> /// /// <returns> true if it succeeds, false if it fails. </returns> private bool WriteByte(MemoryStream target , long writeAddress , PatchDefinition.Data data) { if ((writeAddress + 1) >= target.Length) { OnErrorOccurred("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 parsedValue; if (!Utilities.Parse.TryParseHex(data.Value, out parsedValue)) { OnErrorOccurred("Failed to parse value ({0}). Inform the developers of this.", data.ID); return(false); } // Write the value to the stream target.Seek(writeAddress, SeekOrigin.Begin); target.WriteByte(parsedValue); return(true); }