We've just updated MediaWiki and its underlying software. If anything doesn't look or work quite right, please mention it to us. --RanAS
IPS patching code
From SnesLab
IPS patching
C#
// Noobish Noobsicle wrote this IPS patching code // romname is the original ROM, patchname is the patch to apply FileStream romstream = new FileStream (romname, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); FileStream ipsstream = new FileStream (patchname, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); int lint = (int)ipsstream.Length; byte[] ipsbyte = new byte[ipsstream.Length]; byte[] rombyte = new byte[romstream.Length]; IAsyncResult romresult; IAsyncResult ipsresult = ipsstream.BeginRead (ipsbyte, 0, lint, null, null); ipsstream.EndRead (ipsresult); int ipson = 5; int totalrepeats = 0; int offset = 0; bool keepgoing = true; while (keepgoing == true) { offset = ipsbyte[ipson] * 0x10000 + ipsbyte[ipson + 1] * 0x100 + ipsbyte[ipson + 2]; ipson++; ipson++; ipson++; if (ipsbyte[ipson] * 256 + ipsbyte[ipson + 1] == 0) { ipson++; ipson++; totalrepeats = ipsbyte[ipson] * 256 + ipsbyte[ipson + 1]; ipson++; ipson++; byte[] repeatbyte = new byte[totalrepeats]; for (int ontime = 0; ontime < totalrepeats; ontime++) repeatbyte[ontime] = ipsbyte[ipson]; romstream.Seek (offset, SeekOrigin.Begin); romresult = romstream.BeginWrite (repeatbyte, 0, totalrepeats, null, null); romstream.EndWrite (romresult); ipson++; } else { totalrepeats = ipsbyte[ipson] * 256 + ipsbyte[ipson + 1]; ipson++; ipson++; romstream.Seek (offset, SeekOrigin.Begin); romresult = romstream.BeginWrite (ipsbyte, ipson, totalrepeats, null, null); romstream.EndWrite (romresult); ipson = ipson + totalrepeats; } if (ipsbyte[ipson] == 69 && ipsbyte[ipson + 1] == 79 && ipsbyte[ipson + 2] == 70) keepgoing = false; } romstream.Close (); ipsstream.Close ();
VB.NET
Dim romstream As New FileStream(romname, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite) Dim ipsstream As New FileStream(patchname, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite) Dim lint As Integer = CInt(ipsstream.Length) Dim ipsbyte As Byte() = New Byte(ipsstream.Length - 1) {} Dim rombyte As Byte() = New Byte(romstream.Length - 1) {} Dim romresult As IAsyncResult Dim ipsresult As IAsyncResult = ipsstream.BeginRead(ipsbyte, 0, lint, Nothing, Nothing) ipsstream.EndRead(ipsresult) Dim ipson As Integer = 5 Dim totalrepeats As Integer = 0 Dim offset As Integer = 0 Dim keepgoing As Boolean = True '''///////////////End Init code '''///////////////Start main code While keepgoing = True offset = ipsbyte(ipson) * &H10000 + ipsbyte(ipson + 1) * &H100 + ipsbyte(ipson + 2) ipson += 1 ipson += 1 ipson += 1 '''//////////split between repeating byte mode and standard mode If ipsbyte(ipson) * 256 + ipsbyte(ipson + 1) = 0 Then '''/////////repeating byte mode ipson += 1 ipson += 1 totalrepeats = ipsbyte(ipson) * 256 + ipsbyte(ipson + 1) ipson += 1 ipson += 1 Dim repeatbyte As Byte() = New Byte(totalrepeats - 1) {} For ontime As Integer = 0 To totalrepeats - 1 repeatbyte(ontime) = ipsbyte(ipson) Next romstream.Seek(offset, SeekOrigin.Begin) romresult = romstream.BeginWrite(repeatbyte, 0, totalrepeats, Nothing, Nothing) romstream.EndWrite(romresult) ipson += 1 Else '''/////////standard mode totalrepeats = ipsbyte(ipson) * 256 + ipsbyte(ipson + 1) ipson += 1 ipson += 1 romstream.Seek(offset, SeekOrigin.Begin) romresult = romstream.BeginWrite(ipsbyte, ipson, totalrepeats, Nothing, Nothing) romstream.EndWrite(romresult) ipson = ipson + totalrepeats End If '''//////////Test For "EOF" If ipsbyte(ipson) = 69 AndAlso ipsbyte(ipson + 1) = 79 AndAlso ipsbyte(ipson + 2) = 70 Then keepgoing = False End If End While romstream.Close() ipsstream.Close()
Ruby
#!/usr/bin/env ruby # -*- encoding: US-ASCII -*- # ruby-ips.rb --Kernigh, March 2009 # This program is in the public domain and has no copyright. require 'optparse' filename = nil sflag = false opts = OptionParser.new do |opts| opts.banner = "usage: #{$0} [-s] [-f file] patch..." opts.on("-f FILE", "Apply patches to FILE") do |f| filename = f end opts.on("-s", "Work silently") do |l| sflag = true end end opts.parse! # usage message if no arguments if ARGV.size == 0 puts opts exit 0 end if sflag && (not filename) $stderr.puts "#{$0}: nothing to do" exit 1 end # compatibility with Ruby before 1.8.7 unless 3.respond_to? :ord # with Ruby 1.8, "x"[0] is Fixnum # with Ruby 1.9, "x"[0] is String, "x"[0].ord is Fixnum class Integer def ord self end end end # subroutines def unpack2(bytes) (bytes[0].ord << 8) + bytes[1].ord end def unpack3(bytes) (bytes[0].ord << 16) + (bytes[1].ord << 8) + bytes[2].ord end def hex(num) "0x#{num.to_s(16)} (#{num})" end # start work file = open(filename, File::RDWR) if filename ARGV.each do |patchname| # provide pinfo, pwarn for this patch pinfo = if sflag lambda { |m| } else $stdout.puts "#{patchname}:" lambda { |m| $stdout.puts " #{m}" } end pwarn = lambda { |m| $stderr.puts "#{patchname}: #{m}" } # open patch patch = open(patchname, File::RDONLY) # check magic bytes unless patch.read(5) == "PATCH" pwarn.call "bad magic bytes, not an IPS patch" exit 1 end # lambda to read patch and check number of bytes pread = lambda do |count| bytes = patch.read(count) if bytes.length < count pwarn.call "read #{bytes.length} bytes from patch, " + "expected #{count} bytes" pwarn.call "unexpected end of patch file" exit 1 end bytes end # process each record while true offset = pread.call(3) # "EOF" marks the end of patch if offset == "EOF" # count the remaining bytes in the file rem = patch.stat.size - patch.pos case rem when 0 pinfo.call "end of patch" when 3 # truncate support, as in Lunar IPS tru = unpack3(pread.call(3)) pinfo.call "truncate to #{hex(tru)} bytes" file.truncate(tru) if filename else pwarn.call "unexpected data after end of " + "patch, #{hex(rem)} bytes ..." pwarn.call "... problem with offset " + "\"EOF\" #{hex("EOF")}?" exit 1 end break end offset = unpack3(offset) length = unpack2(pread.call(2)) case length when 0 # RLE support length = unpack2(pread.call(2)) byte = pread.call(1) pinfo.call "patch to file offset #{hex(offset)}, " + "length #{hex(length)}, RLE" if filename file.pos = offset file.write(byte * length) end else pinfo.call "patch to file offset #{hex(offset)}, " + "length #{hex(length)}" if filename file.pos = offset file.write(pread.call(length)) else pread.call(length) end end end patch.close end file.close if filename