44 [[nodiscard]]
unsigned getSize()
const override;
46 [[nodiscard]]
byte read(
unsigned address)
override;
47 void write(
unsigned address,
byte value)
override;
57 : name(
std::move(name_)), description(description_)
62 if (c->getAttributeValue(
"id", {}) ==
id) {
68 if (!errors.empty() && (errors.back() !=
'\n')) {
71 errors += e.getMessage();
77 string err =
"Missing <rom> tag";
96 bool checkResolvedSha1 =
false;
100 const auto* resolvedFilenameElem = config.
findChild(
"resolvedFilename");
101 const auto* resolvedSha1Elem = config.
findChild(
"resolvedSha1");
118 checkResolvedSha1 =
false;
120 }
else if (resolvedFilenameElem || resolvedSha1Elem ||
121 !sums.empty() || !filenames.empty()) {
124 if (resolvedFilenameElem) {
126 file = File(std::string(resolvedFilenameElem->getData()));
127 }
catch (FileException&) {
132 auto fileType =
context.isUserContext()
134 if (!file.
is_open() && resolvedSha1Elem) {
135 Sha1Sum sha1(resolvedSha1Elem->getData());
136 file = filePool.getFile(fileType, sha1);
144 for (
auto& f : filenames) {
146 file = File(
Filename(f->getData(), context));
148 }
catch (FileException&) {
156 for (
auto& s : sums) {
157 Sha1Sum sha1(s->getData());
158 file = filePool.getFile(fileType, sha1);
168 string error =
strCat(
"Couldn't find ROM file for \"", name,
'"');
169 if (!filenames.empty()) {
170 strAppend(error,
' ', filenames.front()->getData());
172 if (resolvedSha1Elem) {
173 strAppend(error,
" (sha1: ", resolvedSha1Elem->getData(),
')');
174 }
else if (!sums.empty()) {
175 strAppend(error,
" (sha1: ", sums.front()->getData(),
')');
178 throw MSXException(std::move(error));
185 "The <filesize> and <skip_headerbytes> tags "
186 "inside a <rom> section are no longer "
190 auto mmap = file.
mmap();
192 }
catch (FileException&) {
193 throw MSXException(
"Error reading ROM image: ", file.
getURL());
198 if (originalSha1.
empty()) {
199 originalSha1 = filePool.getSha1Sum(file);
203 if (!checkSHA1(config)) {
205 "SHA1 sum for '", name,
206 "' does not match with sum of '",
211 checkResolvedSha1 =
true;
221 rom = std::span{extendedRom};
224 checkResolvedSha1 =
false;
228 if (
const auto* patchesElem = config.
findChild(
"patches")) {
232 std::unique_ptr<PatchInterface> patch =
233 std::make_unique<EmptyPatch>(rom);
235 for (
const auto* p : patchesElem->getChildren(
"ips")) {
236 patch = std::make_unique<IPSPatch>(
240 auto patchSize = patch->getSize();
241 if (patchSize <= rom.size()) {
242 patch->copyBlock(0, std::span{
const_cast<uint8_t*
>(rom.data()), rom.size()});
244 MemBuffer<byte> extendedRom2(patchSize);
245 patch->copyBlock(0, std::span{extendedRom2});
246 extendedRom = std::move(extendedRom2);
247 rom = std::span{extendedRom};
254 checkResolvedSha1 =
true;
260 if (name.starts_with(
"MSXRom")) {
262 std::string_view title;
264 title = romInfo->getTitle(db.getBufferStart());
266 if (!title.empty()) {
276 if (!rom.empty() && debugger.findDebuggable(name)) {
280 tmp =
strCat(name,
" (", ++n,
')');
281 }
while (debugger.findDebuggable(tmp));
282 name = std::move(tmp);
285 if (checkResolvedSha1) {
288 const auto* actualSha1Elem = doc.getOrCreateChild(
289 const_cast<XMLElement&
>(config),
290 "resolvedSha1", doc.allocateString(patchedSha1Str));
291 if (actualSha1Elem->getData() != patchedSha1Str) {
292 std::string_view tmp = file.
is_open() ? file.
getURL() : name;
295 "The content of the rom ", tmp,
" has "
296 "changed since the time this savestate was "
297 "created. This might result in emulation "
304 if (
const auto* windowElem = config.
findChild(
"window")) {
305 unsigned windowBase = windowElem->getAttributeValueAsInt(
"base", 0);
306 unsigned windowSize = windowElem->getAttributeValueAsInt(
"size", narrow_cast<int>(rom.size()));
307 if ((windowBase + windowSize) > rom.size()) {
309 "The specified window [", windowBase,
',',
310 windowBase + windowSize,
") falls outside "
311 "the rom (with size ", rom.size(),
").");
313 rom = rom.subspan(windowBase, windowSize);
318 romDebuggable = std::make_unique<RomDebuggable>(debugger, *
this);
322bool Rom::checkSHA1(
const XMLElement& config)
const
324 auto sums =
to_vector(config.getChildren(
"sha1"));
325 return sums.empty() ||
327 [](
const auto* s) {
return Sha1Sum(s->getData()); });
332 , extendedRom (std::move(r.extendedRom))
333 , file (std::move(r.file))
334 , originalSha1 (r.originalSha1)
335 , actualSha1 (r.actualSha1)
336 , name (std::move(r.name))
337 , description (r.description)
338 , romDebuggable(std::move(r.romDebuggable))
340 if (romDebuggable) romDebuggable->moved(*
this);
352 if (originalSha1.
empty()) {
360 if (actualSha1.
empty())
369 assert(newSize >= rom.size());
370 if (newSize == rom.size())
return;
376 rom = std::span{tmp};
377 extendedRom = std::move(tmp);
389 : debugger(debugger_), rom(&rom_)
401 return narrow<unsigned>(rom->
size());
412 return (*rom)[address];
void printWarning(std::string_view message)
void unregisterDebuggable(std::string_view name, Debuggable &debuggable)
void registerDebuggable(std::string name, Debuggable &debuggable)
const FileContext & getFileContext() const
MSXMotherBoard & getMotherBoard() const
const XMLElement * getXML() const
std::span< const uint8_t > mmap()
Map file in memory.
std::string_view getOriginalName()
Get Original filename for this object.
bool is_open() const
Return true iff this file handle refers to an open file.
const std::string & getURL() const
Returns the URL of this file object.
XMLDocument & getXMLDocument()
const HardwareConfig * getMachineConfig() const
MSXCliComm & getMSXCliComm()
PanasonicMemory & getPanasonicMemory()
This class manages the lifetime of a block of memory.
std::span< const T > subspan(size_t offset, size_t n=std::dynamic_extent) const
void resize(size_t size)
Grow or shrink the memory block.
std::span< const byte > getRomRange(unsigned first, unsigned last) const
RomDatabase & getSoftwareDatabase()
RomDebuggable(RomDebuggable &&)=delete
RomDebuggable & operator=(const RomDebuggable &)=delete
unsigned getSize() const override
byte read(unsigned address) override
void write(unsigned address, byte value) override
RomDebuggable(const RomDebuggable &)=delete
RomDebuggable(Debugger &debugger, Rom &rom)
RomDebuggable & operator=(RomDebuggable &&)=delete
std::string_view getDescription() const override
std::string_view getDescription() const
const Sha1Sum & getSHA1() const
const Sha1Sum & getOriginalSHA1() const
std::string_view getFilename() const
void getInfo(TclObject &result) const
Add dict values with info to result.
const std::string & getName() const
Rom(std::string name, static_string_view description, const DeviceConfig &config, std::string_view id={})
void addPadding(size_t newSize, byte filler=0xff)
static Sha1Sum calc(std::span< const uint8_t > data)
Easier to use interface, if you can pass all data in one go.
This class represents the result of a sha1 calculation (a 160-bit value).
std::string toString() const
void addDictKeyValues(Args &&... args)
int getChildDataAsInt(std::string_view childName, int defaultValue) const
const XMLElement * findChild(std::string_view childName) const
ChildRange getChildren() const
std::optional< Context > context
This file implemented 3 utility functions:
std::string toString(const BooleanInput &input)
constexpr void fill(ForwardRange &&range, const T &value)
constexpr auto copy(InputRange &&range, OutputIter out)
auto to_vector(Range &&range) -> std::vector< detail::ToVectorType< T, decltype(std::begin(range))> >
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
void strAppend(std::string &result, Ts &&...ts)