23using std::string_view;
33 CliComm& cliComm_,
char* bufStart_)
35 , unknownTypes(unknownTypes_)
38 , initialSize(db.size())
43 void start(string_view tag);
44 void attribute(string_view name, string_view value);
45 void text(string_view txt);
49 [[nodiscard]] string_view
getSystemID()
const {
return systemID; }
52 [[nodiscard]]
String32 cIndex(string_view str)
const;
94 std::vector<Dump> dumps;
103 unsigned unknownLevel = 0;
114 assert(!tag.empty());
117 if (tag ==
"softwaredb") {
121 throw MSXException(
"Expected <softwaredb> as root tag.");
123 if (small_compare<"software">(tag)) {
124 system = string_view();
136 switch (tag.front()) {
138 if (small_compare<"system">(tag)) {
144 tag.remove_prefix(1);
145 if (small_compare<"itle">(tag)) {
151 if (small_compare<"company">(tag)) {
154 }
else if (small_compare<"country">(tag)) {
160 if (small_compare<"year">(tag)) {
166 if (small_compare<"genmsxid">(tag)) {
172 if (small_compare<"dump">(tag)) {
173 dumps.resize(dumps.size() + 1);
175 dumps.back().origValue =
false;
176 toString32(bufStart, bufStart, dumps.back().remark);
177 toString32(bufStart, bufStart, dumps.back().origData);
186 switch (tag.front()) {
188 if (small_compare<"original">(tag)) {
189 dumps.back().origValue =
false;
195 if (small_compare<"megarom">(tag)) {
196 type = string_view();
197 startVal = string_view();
203 tag.remove_prefix(1);
204 if (small_compare<"om">(tag)) {
206 startVal = string_view();
215 switch (tag.front()) {
217 if (small_compare<"type">(tag)) {
223 tag.remove_prefix(1);
224 if (small_compare<"tart">(tag)) {
230 if (small_compare<"remark">(tag)) {
236 if (small_compare<"hash">(tag)) {
245 if (small_compare<"text">(tag)) {
275 if (unknownLevel)
return;
279 if (small_compare<"value">(name)) {
308 if (unknownLevel)
return;
318 company = cIndex(txt);
324 country = cIndex(txt);
327 if (
auto g = StringOp::stringToBase<10, unsigned>(txt)) {
331 "Ignoring bad Generation MSX id (genmsxid) "
338 dumps.back().origData = cIndex(txt);
348 dumps.back().hash =
Sha1Sum(txt);
351 "Ignoring bad dump for '",
fromString32(bufStart, title),
352 "': ", e.getMessage());
357 dumps.back().remark = cIndex(txt);
371String32 DBParser::cIndex(string_view str)
const
373 auto*
begin =
const_cast<char*
>(str.data());
382void DBParser::addEntries()
385 return RomDatabase::Entry{
387 RomInfo(title, year, company, country, d.origValue,
388 d.origData, d.remark, d.type, genMSXid)};
393void DBParser::addAllEntries()
399 const auto first =
begin(db);
400 const auto last =
end (db);
401 const auto mid = first + narrow<ptrdiff_t>(initialSize);
402 if (mid == last)
return;
412 while (it2 != last) {
413 if (it1->sha1 == it2->sha1)
break;
417 while (it2 != last) {
418 if (it1->sha1 == it2->sha1) {
420 "duplicate softwaredb entry SHA1: ",
421 it2->sha1.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->sha1 < it2->sha1) {
443 result.push_back(std::move(*it1));
446 if (it1->sha1 != it2->sha1) {
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));
464static const char* parseStart(string_view s)
467 return ((s.size() == 6) && s.starts_with(
"0x")) ? (s.data() + 2) : nullptr;
495 if (dumps.back().hash.empty()) {
505 string_view
t = type;
506 std::array<char, 8 + 4> buf;
507 if (small_compare<"Mirrored">(
t)) {
508 if (
const char* s = parseStart(startVal)) {
510 ranges::copy(std::string_view(s, 4), subspan<4>(buf, 8));
511 t = string_view(buf.data(), 8 + 4);
513 }
else if (small_compare<"Normal">(
t)) {
514 if (
const char* s = parseStart(startVal)) {
516 ranges::copy(std::string_view(s, 4), subspan<4>(buf, 6));
517 t = string_view(buf.data(), 6 + 4);
522 unknownTypes[std::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);
556static 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.",
575 std::vector<File> files;
576 size_t bufferSize = 0;
579 auto& f = files.emplace_back(p +
"/softwaredb.xml");
588 buffer.
resize(bufferSize);
589 size_t bufferOffset = 0;
590 for (
auto& file : files) {
592 auto size = file.getSize();
593 auto* buf = &buffer[bufferOffset];
595 file.read(std::span{buf, size});
598 parseDB(cliComm, buf, buffer.
data(), db, unknownTypes);
601 "Rom database parsing failed: ", e.what());
606 if (bufferSize) buffer[0] = 0;
609 "Couldn't load software database.\n"
610 "This may cause incorrect ROM mapper types to be used.");
612 if (!unknownTypes.
empty()) {
613 std::string output =
"Unknown mapper types in software database: ";
614 for (
const auto& [type, count] : unknownTypes) {
615 strAppend(output, type,
" (", count,
"x); ");
624 return d ? &d->romInfo :
nullptr;
constexpr const char * fromString32(const char *buffer, uint32_t str32)
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
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)
std::span< const std::string > getPaths() const
void resize(size_t size)
Grow or shrink the memory block.
const T * data() const
Returns pointer to the start of the memory buffer.
RomDatabase(CliComm &cliComm)
std::vector< Entry > RomDB
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).
bool stringToBool(string_view str)
This file implemented 3 utility functions:
const FileContext & systemFileContext()
hash_map< std::string, unsigned, XXHasher > UnknownTypes
constexpr auto copy(InputRange &&range, OutputIter out)
constexpr void sort(RandomAccessRange &&range)
constexpr size_t EXTRA_BUFFER_SPACE
constexpr auto transform(Range &&range, UnaryOp op)
auto * binary_find(ForwardRange &&range, const T &value, Compare comp={}, Proj proj={})
void strAppend(std::string &result, Ts &&...ts)
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)