21 using std::string_view;
32 CliComm& cliComm_,
char* bufStart_)
34 , unknownTypes(unknownTypes_)
39 , initialSize(db.
size())
44 void start(string_view tag);
45 void attribute(string_view name, string_view value);
46 void text(string_view txt);
50 [[nodiscard]] string_view
getSystemID()
const {
return systemID; }
53 [[nodiscard]]
String32 cIndex(string_view str);
104 unsigned unknownLevel;
115 assert(!tag.empty());
118 if (tag ==
"softwaredb") {
122 throw MSXException(
"Expected <softwaredb> as root tag.");
124 if (small_compare<'s','o','f','t','w','a','r','e'>(tag)) {
125 system = string_view();
137 switch (tag.front()) {
139 if (small_compare<'s','y','s','t','e','m'>(tag)) {
145 tag.remove_prefix(1);
146 if (small_compare<'i','t','l','e'>(tag)) {
152 if (small_compare<'c','o','m','p','a','n','y'>(tag)) {
155 }
else if (small_compare<'c','o','u','n','t','r','y'>(tag)) {
161 if (small_compare<'y','e','a','r'>(tag)) {
167 if (small_compare<'g','e','n','m','s','x','i','d'>(tag)) {
173 if (small_compare<'d','u','m','p'>(tag)) {
174 dumps.resize(dumps.size() + 1);
176 dumps.back().origValue =
false;
177 toString32(bufStart, bufStart, dumps.back().remark);
178 toString32(bufStart, bufStart, dumps.back().origData);
187 switch (tag.front()) {
189 if (small_compare<'o','r','i','g','i','n','a','l'>(tag)) {
190 dumps.back().origValue =
false;
196 if (small_compare<'m','e','g','a','r','o','m'>(tag)) {
197 type = string_view();
198 startVal = string_view();
204 tag.remove_prefix(1);
205 if (small_compare<'o','m'>(tag)) {
207 startVal = string_view();
216 switch (tag.front()) {
218 if (small_compare<'t','y','p','e'>(tag)) {
224 tag.remove_prefix(1);
225 if (small_compare<'t','a','r','t'>(tag)) {
231 if (small_compare<'r','e','m','a','r','k'>(tag)) {
237 if (small_compare<'h','a','s','h'>(tag)) {
246 if (small_compare<'t','e','x','t'>(tag)) {
276 if (unknownLevel)
return;
280 if (small_compare<'v','a','l','u','e'>(name)) {
309 if (unknownLevel)
return;
319 company = cIndex(txt);
325 country = cIndex(txt);
328 auto g = StringOp::stringToBase<10, unsigned>(txt);
331 "Ignoring bad Generation MSX id (genmsxid) "
339 dumps.back().origData = cIndex(txt);
349 dumps.back().hash =
Sha1Sum(txt);
352 "Ignoring bad dump for '",
fromString32(bufStart, title),
358 dumps.back().remark = cIndex(txt);
372 String32 DBParser::cIndex(string_view str)
374 auto*
begin =
const_cast<char*
>(str.data());
383 void DBParser::addEntries()
386 return std::pair(d.hash,
387 RomInfo(title, year, company, country, d.origValue,
388 d.origData, d.remark, d.type, genMSXid));
393 void DBParser::addAllEntries()
399 const auto first =
begin(db);
400 const auto last =
end (db);
401 const auto mid = first + initialSize;
402 if (mid == last)
return;
412 while (it2 != last) {
413 if (it1->first == it2->first)
break;
417 while (it2 != last) {
418 if (it1->first == it2->first) {
420 "duplicate softwaredb entry SHA1: ",
421 it2->first.toString());
424 *it1 = std::move(*it2);
429 db.erase(it1 + 1, last);
435 if (first == mid)
return;
437 result.reserve(db.size());
441 while (it1 != mid && it2 != last) {
442 if (it1->first < it2->first) {
443 result.push_back(std::move(*it1));
446 if (it1->first != it2->first) {
447 result.push_back(std::move(*it2));
451 result.push_back(std::move(*it1));
457 move(it1, mid, back_inserter(result));
458 move(it2, last, back_inserter(result));
464 static const char* parseStart(string_view s)
495 if (dumps.back().hash.empty()) {
505 string_view
t = type;
507 if (small_compare<'M','i','r','r','o','r','e','d'>(
t)) {
508 if (
const char* s = parseStart(startVal)) {
509 memcpy(buf,
t.data(), 8);
510 memcpy(buf + 8, s, 4);
511 t = string_view(buf, 12);
513 }
else if (small_compare<'N','o','r','m','a','l'>(
t)) {
514 if (
const char* s = parseStart(startVal)) {
515 memcpy(buf,
t.data(), 6);
516 memcpy(buf + 6, s, 4);
517 t = string_view(buf, 10);
522 unknownTypes[string(
t)]++;
524 dumps.back().type = romType;
548 auto pos1 = txt.find(
" SYSTEM \"");
549 if (pos1 == string_view::npos)
return;
550 auto t = txt.substr(pos1 + 9);
551 auto pos2 =
t.find(
'"');
552 if (pos2 == string_view::npos)
return;
553 systemID =
t.substr(0, pos2);
556 static void parseDB(
CliComm& cliComm,
char* buf,
char* bufStart,
559 DBParser handler(db, unknownTypes, cliComm, bufStart);
560 rapidsax::parse<rapidsax::trimWhitespace>(handler, buf);
562 if (handler.getSystemID() !=
"softwaredb1.dtd") {
564 "Missing or wrong systemID.\n"
565 "You're probably using an old incompatible file format.",
577 size_t bufferSize = 0;
578 for (
auto& p : paths) {
580 auto& f = files.emplace_back(p +
"/softwaredb.xml");
589 buffer.
resize(bufferSize);
590 size_t bufferOffset = 0;
591 for (
auto& file : files) {
593 auto size = file.getSize();
594 auto* buf = &buffer[bufferOffset];
596 file.read(buf,
size);
599 parseDB(cliComm, buf, buffer.
data(), db, unknownTypes);
602 "Rom database parsing failed: ", e.
what());
607 if (bufferSize) buffer[0] = 0;
610 "Couldn't load software database.\n"
611 "This may cause incorrect ROM mapper types to be used.");
613 if (!unknownTypes.
empty()) {
614 string output =
"Unknown mapper types in software database: ";
615 for (
const auto& [type,
count] : unknownTypes) {
625 return ((it !=
end(db)) && (it->first == sha1sum))
626 ? &it->second :
nullptr;
void swap(openmsx::MemBuffer< T > &l, openmsx::MemBuffer< T > &r) noexcept
constexpr void toString32(const char *buffer, const char *str, uint32_t &result)
std::conditional_t<(sizeof(char *) > sizeof(uint32_t)), uint32_t, const char * > String32
constexpr const char * fromString32(const char *buffer, uint32_t str32)
void printWarning(std::string_view message)
void doctype(string_view txt)
DBParser(RomDatabase::RomDB &db_, UnknownTypes &unknownTypes_, CliComm &cliComm_, char *bufStart_)
void attribute(string_view name, string_view value)
void start(string_view tag)
string_view getSystemID() const
void text(string_view txt)
const std::vector< std::string > & getPaths() const
const std::string & getMessage() const &
const T * data() const
Returns pointer to the start of the memory buffer.
void resize(size_t size)
Grow or shrink the memory block.
std::vector< std::pair< Sha1Sum, RomInfo > > RomDB
RomDatabase(CliComm &cliComm)
const RomInfo * fetchRomInfo(const Sha1Sum &sha1sum) const
Lookup an entry in the database by sha1sum.
static RomType nameToRomType(std::string_view name)
This class represents the result of a sha1 calculation (a 160-bit value).
const char * what() const
ALWAYS_INLINE unsigned count(const uint8_t *pIn, const uint8_t *pMatch, const uint8_t *pInLimit)
bool stringToBool(string_view str)
bool startsWith(string_view total, string_view part)
constexpr void sort(RAIt first, RAIt last, Compare cmp=Compare{})
This file implemented 3 utility functions:
const FileContext & systemFileContext()
hash_map< string, unsigned, XXHasher > UnknownTypes
auto lower_bound(ForwardRange &&range, const T &value)
constexpr size_t EXTRA_BUFFER_SPACE
size_t size(std::string_view utf8)
constexpr auto transform(Range &&range, UnaryOp op)
void strAppend(std::string &result, Ts &&...ts)
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)