Allow specifying ROM type in file load dialog
[lsnes.git] / src / library / patch-ips.cpp
blob12747cc714efd5ec48c431b024d0189ad707dfc8
1 #include "minmax.hpp"
2 #include "patch.hpp"
3 #include "serialization.hpp"
4 #include "string.hpp"
5 #include <cstdint>
6 #include <limits>
7 #include <cstring>
8 #include <iostream>
10 namespace
12 uint8_t readbyte(const char* buf, uint64_t& pos, uint64_t size)
14 if(pos >= size)
15 (stringfmt() << "Attempted to read byte past the end of patch (" << pos << " >= "
16 << size << ").").throwex();
17 return static_cast<uint8_t>(buf[pos++]);
20 struct ips_patcher : public rom_patcher
22 ~ips_patcher() throw();
23 bool identify(const std::vector<char>& patch) throw();
24 void dopatch(std::vector<char>& out, const std::vector<char>& original,
25 const std::vector<char>& patch, int32_t offset) throw(std::bad_alloc, std::runtime_error);
26 } ipspatch;
28 ips_patcher::~ips_patcher() throw()
32 bool ips_patcher::identify(const std::vector<char>& patch) throw()
34 return (patch.size() > 5 && patch[0] == 'P' && patch[1] == 'A' && patch[2] == 'T' && patch[3] == 'C' &&
35 patch[4] == 'H');
38 void ips_patcher::dopatch(std::vector<char>& out, const std::vector<char>& original,
39 const std::vector<char>& patch, int32_t offset) throw(std::bad_alloc, std::runtime_error)
41 //Initial guess.
42 out = original;
43 const char* _patch = &patch[0];
44 size_t psize = patch.size();
46 uint64_t ioffset = 5;
47 while(true) {
48 bool rle = false;
49 uint8_t b;
50 uint32_t off = 0, l = 0;
51 off |= static_cast<uint32_t>(readbyte(_patch, ioffset, psize)) << 16;
52 off |= static_cast<uint32_t>(readbyte(_patch, ioffset, psize)) << 8;
53 off |= static_cast<uint32_t>(readbyte(_patch, ioffset, psize));
54 if(off == 0x454F46)
55 break; //EOF code.
56 l |= static_cast<uint32_t>(readbyte(_patch, ioffset, psize)) << 8;
57 l |= static_cast<uint32_t>(readbyte(_patch, ioffset, psize));
58 if(l == 0) {
59 //RLE.
60 l |= static_cast<uint32_t>(readbyte(_patch, ioffset, psize)) << 8;
61 l |= static_cast<uint32_t>(readbyte(_patch, ioffset, psize));
62 b = readbyte(_patch, ioffset, psize);
63 rle = true;
65 uint64_t extra = 0;
66 if(offset >= 0)
67 off += offset;
68 else {
69 uint32_t noffset = static_cast<uint32_t>(-offset);
70 uint32_t fromoff = min(noffset, off);
71 off -= fromoff;
72 extra = min(noffset - fromoff, l);
73 l -= extra;
75 if(off + l >= out.size())
76 out.resize(off + l);
77 if(!rle) {
78 ioffset += extra;
79 for(uint64_t i = 0; i < l; i++)
80 out[off + i] = readbyte(_patch, ioffset, psize);
81 } else
82 for(uint64_t i = 0; i < l; i++)
83 out[off + i] = b;