openMSX
IPSPatch.cc
Go to the documentation of this file.
1 #include "IPSPatch.hh"
2 #include "File.hh"
3 #include "Filename.hh"
4 #include "MSXException.hh"
5 #include "ranges.hh"
6 #include "stl.hh"
7 #include "xrange.hh"
8 #include <cstring>
9 #include <cassert>
10 
11 using std::vector;
12 
13 namespace openmsx {
14 
15 static size_t getStop(const IPSPatch::PatchMap::const_iterator& it)
16 {
17  return it->first + it->second.size();
18 }
19 
21  std::unique_ptr<const PatchInterface> parent_)
22  : filename(std::move(filename_))
23  , parent(std::move(parent_))
24 {
25  File ipsFile(filename);
26 
27  byte buf[5];
28  ipsFile.read(buf, 5);
29  if (memcmp(buf, "PATCH", 5) != 0) {
30  throw MSXException("Invalid IPS file: ", filename.getOriginal());
31  }
32  ipsFile.read(buf, 3);
33  while (memcmp(buf, "EOF", 3) != 0) {
34  size_t offset = 0x10000 * buf[0] + 0x100 * buf[1] + buf[2];
35  ipsFile.read(buf, 2);
36  size_t length = 0x100 * buf[0] + buf[1];
37  vector<byte> v;
38  if (length == 0) {
39  // RLE encoded
40  ipsFile.read(buf, 3);
41  length = 0x100 * buf[0] + buf[1];
42  v.resize(length, buf[2]);
43  } else {
44  // patch bytes
45  v.resize(length);
46  ipsFile.read(&v.front(), length);
47  }
48  // find overlapping or adjacent patch regions
49  auto b = ranges::lower_bound(patchMap, offset, LessTupleElement<0>());
50  if (b != begin(patchMap)) {
51  --b;
52  if (getStop(b) < offset) ++b;
53  }
54  auto e = ranges::upper_bound(patchMap, offset + v.size(), LessTupleElement<0>());
55  if (b != e) {
56  // remove operlapping regions, merge adjacent regions
57  --e;
58  auto start = std::min(b->first, offset);
59  auto stop = std::max(offset + length, getStop(e));
60  auto length2 = stop - start;
61  ++e;
62  vector<byte> tmp(length2);
63  for (auto it : xrange(b, e)) {
64  memcpy(&tmp[it->first - start], &it->second[0],
65  it->second.size());
66  }
67  memcpy(&tmp[offset - start], v.data(), v.size());
68  *b = std::pair(start, std::move(tmp));
69  patchMap.erase(b + 1, e);
70  } else {
71  // add new region
72  patchMap.emplace(b, offset, std::move(v));
73  }
74 
75  ipsFile.read(buf, 3);
76  }
77  if (patchMap.empty()) {
78  size = parent->getSize();
79  } else {
80  auto it = --end(patchMap);
81  size = std::max(parent->getSize(), getStop(it));
82  }
83 }
84 
85 void IPSPatch::copyBlock(size_t src, byte* dst, size_t num) const
86 {
87  parent->copyBlock(src, dst, num);
88 
89  auto b = ranges::lower_bound(patchMap, src, LessTupleElement<0>());
90  if (b != begin(patchMap)) --b;
91  auto e = ranges::upper_bound(patchMap, src + num - 1, LessTupleElement<0>());
92  for (auto it : xrange(b, e)) {
93  auto chunkStart = it->first;
94  int chunkSize = int(it->second.size());
95  // calc chunkOffset, chunkStart
96  int chunkOffset = int(src - chunkStart);
97  if (chunkOffset < 0) {
98  // start after src
99  assert(-chunkOffset < int(num)); // dont start past end
100  chunkOffset = 0;
101  } else if (chunkOffset >= chunkSize) {
102  // chunk completely before src, skip
103  continue;
104  } else {
105  // start before src
106  chunkSize -= chunkOffset;
107  chunkStart += chunkOffset;
108  }
109  // calc chunkSize
110  assert(src <= chunkStart);
111  int overflow = int(chunkStart - src + chunkSize - num);
112  if (overflow > 0) {
113  assert(chunkSize > overflow);
114  chunkSize -= overflow;
115  }
116  // copy
117  assert(chunkOffset < int(it->second.size()));
118  assert((chunkOffset + chunkSize) <= int(it->second.size()));
119  assert(src <= chunkStart);
120  assert((chunkStart + chunkSize) <= (src + num));
121  memcpy(dst + chunkStart - src, &it->second[chunkOffset],
122  chunkSize);
123  }
124 }
125 
126 size_t IPSPatch::getSize() const
127 {
128  return size;
129 }
130 
131 std::vector<Filename> IPSPatch::getFilenames() const
132 {
133  auto result = parent->getFilenames();
134  result.push_back(filename);
135  return result;
136 }
137 
138 } // namespace openmsx
void read(void *buffer, size_t num)
Read from file.
Definition: File.cc:93
This class represents a filename.
Definition: Filename.hh:18
const std::string & getOriginal() const
Definition: Filename.hh:46
IPSPatch(Filename filename, std::unique_ptr< const PatchInterface > parent)
Definition: IPSPatch.cc:20
size_t getSize() const override
Definition: IPSPatch.cc:126
std::vector< Filename > getFilenames() const override
Definition: IPSPatch.cc:131
void copyBlock(size_t src, byte *dst, size_t num) const override
Definition: IPSPatch.cc:85
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:269
T length(const vecN< N, T > &x)
Definition: gl_vec.hh:343
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:287
constexpr T length2(const vecN< N, T > &x)
Definition: gl_vec.hh:336
This file implemented 3 utility functions:
Definition: Autofire.cc:9
constexpr const char *const filename
auto lower_bound(ForwardRange &&range, const T &value)
Definition: ranges.hh:71
auto upper_bound(ForwardRange &&range, const T &value)
Definition: ranges.hh:83
constexpr auto xrange(T e)
Definition: xrange.hh:155
constexpr auto begin(const zstring_view &x)
Definition: zstring_view.hh:82
constexpr auto end(const zstring_view &x)
Definition: zstring_view.hh:83