예제 #1
0
        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);
        }
예제 #2
0
        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);
        }