Movie editor: Fix compilation on Win32
[lsnes.git] / src / library / patch-ips.cpp
blob607a91e63c988bc578cb0cd75055ac90a68fdaf7
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 size_t left = patch.size() - ioffset;
50 uint8_t b;
51 uint32_t off = 0, l = 0;
52 off |= static_cast<uint32_t>(readbyte(_patch, ioffset, psize)) << 16;
53 off |= static_cast<uint32_t>(readbyte(_patch, ioffset, psize)) << 8;
54 off |= static_cast<uint32_t>(readbyte(_patch, ioffset, psize));
55 if(off == 0x454F46)
56 break; //EOF code.
57 l |= static_cast<uint32_t>(readbyte(_patch, ioffset, psize)) << 8;
58 l |= static_cast<uint32_t>(readbyte(_patch, ioffset, psize));
59 if(l == 0) {
60 //RLE.
61 l |= static_cast<uint32_t>(readbyte(_patch, ioffset, psize)) << 8;
62 l |= static_cast<uint32_t>(readbyte(_patch, ioffset, psize));
63 b = readbyte(_patch, ioffset, psize);
64 rle = true;
66 uint64_t extra = 0;
67 if(offset >= 0)
68 off += offset;
69 else {
70 uint32_t noffset = static_cast<uint32_t>(-offset);
71 uint32_t fromoff = min(noffset, off);
72 off -= fromoff;
73 extra = min(noffset - fromoff, l);
74 l -= extra;
76 if(off + l >= out.size())
77 out.resize(off + l);
78 if(!rle) {
79 ioffset += extra;
80 for(uint64_t i = 0; i < l; i++)
81 out[off + i] = readbyte(_patch, ioffset, psize);
82 } else
83 for(uint64_t i = 0; i < l; i++)
84 out[off + i] = b;