20using std::string_view;
30 CliComm& cliComm_,
char* bufStart_)
32 , unknownTypes(unknownTypes_)
35 , initialSize(db.
size())
40 void start(string_view tag);
41 void attribute(string_view name, string_view value);
42 void text(string_view txt);
46 [[nodiscard]] string_view
getSystemID()
const {
return systemID; }
49 [[nodiscard]]
String32 cIndex(string_view str);
91 std::vector<Dump> dumps;
100 unsigned unknownLevel = 0;
111 assert(!tag.empty());
114 if (tag ==
"softwaredb") {
118 throw MSXException(
"Expected <softwaredb> as root tag.");
120 if (small_compare<"software">(tag)) {
121 system = string_view();
133 switch (tag.front()) {
135 if (small_compare<"system">(tag)) {
141 tag.remove_prefix(1);
142 if (small_compare<"itle">(tag)) {
148 if (small_compare<"company">(tag)) {
151 }
else if (small_compare<"country">(tag)) {
157 if (small_compare<"year">(tag)) {
163 if (small_compare<"genmsxid">(tag)) {
169 if (small_compare<"dump">(tag)) {
170 dumps.resize(dumps.size() + 1);
172 dumps.back().origValue =
false;
173 toString32(bufStart, bufStart, dumps.back().remark);
174 toString32(bufStart, bufStart, dumps.back().origData);
183 switch (tag.front()) {
185 if (small_compare<"original">(tag)) {
186 dumps.back().origValue =
false;
192 if (small_compare<"megarom">(tag)) {
193 type = string_view();
194 startVal = string_view();
200 tag.remove_prefix(1);
201 if (small_compare<"om">(tag)) {
203 startVal = string_view();
212 switch (tag.front()) {
214 if (small_compare<"type">(tag)) {
220 tag.remove_prefix(1);
221 if (small_compare<"tart">(tag)) {
227 if (small_compare<"remark">(tag)) {
233 if (small_compare<"hash">(tag)) {
242 if (small_compare<"text">(tag)) {
272 if (unknownLevel)
return;
276 if (small_compare<"value">(name)) {
305 if (unknownLevel)
return;
315 company = cIndex(txt);
321 country = cIndex(txt);
324 if (
auto g = StringOp::stringToBase<10, unsigned>(txt)) {
328 "Ignoring bad Generation MSX id (genmsxid) "
335 dumps.back().origData = cIndex(txt);
345 dumps.back().hash =
Sha1Sum(txt);
348 "Ignoring bad dump for '",
fromString32(bufStart, title),
349 "': ",
e.getMessage());
354 dumps.back().remark = cIndex(txt);
368String32 DBParser::cIndex(string_view str)
370 auto*
begin =
const_cast<char*
>(str.data());
379void DBParser::addEntries()
382 return RomDatabase::Entry{
384 RomInfo(title, year, company, country, d.origValue,
385 d.origData, d.remark, d.type, genMSXid)};
390void DBParser::addAllEntries()
396 const auto first =
begin(db);
397 const auto last =
end (db);
398 const auto mid = first + narrow<ptrdiff_t>(initialSize);
399 if (mid == last)
return;
409 while (it2 != last) {
410 if (it1->sha1 == it2->sha1)
break;
414 while (it2 != last) {
415 if (it1->sha1 == it2->sha1) {
417 "duplicate softwaredb entry SHA1: ",
418 it2->sha1.toString());
421 *it1 = std::move(*it2);
426 db.erase(it1 + 1, last);
432 if (first == mid)
return;
434 result.reserve(db.size());
438 while (it1 != mid && it2 != last) {
439 if (it1->sha1 < it2->sha1) {
440 result.push_back(std::move(*it1));
443 if (it1->sha1 != it2->sha1) {
444 result.push_back(std::move(*it2));
448 result.push_back(std::move(*it1));
454 move(it1, mid, back_inserter(result));
455 move(it2, last, back_inserter(result));
461static const char* parseStart(string_view s)
464 return ((s.size() == 6) && s.starts_with(
"0x")) ? (s.data() + 2) :
nullptr;
492 if (dumps.back().hash.empty()) {
502 string_view
t = type;
503 std::array<char, 8 + 4> buf;
504 if (small_compare<"Mirrored">(
t)) {
505 if (
const char* s = parseStart(startVal)) {
507 ranges::copy(std::string_view(s, 4), subspan<4>(buf, 8));
508 t = string_view(buf.data(), 8 + 4);
510 }
else if (small_compare<"Normal">(
t)) {
511 if (
const char* s = parseStart(startVal)) {
513 ranges::copy(std::string_view(s, 4), subspan<4>(buf, 6));
514 t = string_view(buf.data(), 6 + 4);
519 unknownTypes[std::string(
t)]++;
521 dumps.back().type = romType;
545 auto pos1 = txt.find(
" SYSTEM \"");
546 if (pos1 == string_view::npos)
return;
547 auto t = txt.substr(pos1 + 9);
548 auto pos2 =
t.find(
'"');
549 if (pos2 == string_view::npos)
return;
550 systemID =
t.substr(0, pos2);
553static void parseDB(
CliComm& cliComm,
char* buf,
char* bufStart,
556 DBParser handler(db, unknownTypes, cliComm, bufStart);
557 rapidsax::parse<rapidsax::trimWhitespace>(handler, buf);
559 if (handler.getSystemID() !=
"softwaredb1.dtd") {
561 "Missing or wrong systemID.\n"
562 "You're probably using an old incompatible file format.",
572 std::vector<File> files;
573 size_t bufferSize = 0;
576 auto& f = files.emplace_back(p +
"/softwaredb.xml");
585 buffer.
resize(bufferSize);
586 size_t bufferOffset = 0;
587 for (
auto& file : files) {
589 auto size = file.getSize();
590 auto* buf = &buffer[bufferOffset];
592 file.read(std::span{buf,
size});
595 parseDB(cliComm, buf, buffer.
data(), db, unknownTypes);
598 "Rom database parsing failed: ",
e.what());
603 if (bufferSize) buffer[0] = 0;
606 "Couldn't load software database.\n"
607 "This may cause incorrect ROM mapper types to be used.");
609 if (!unknownTypes.
empty()) {
610 std::string output =
"Unknown mapper types in software database: ";
611 for (
const auto& [type,
count] : unknownTypes) {
621 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)
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).
ALWAYS_INLINE unsigned count(const uint8_t *pIn, const uint8_t *pMatch, const uint8_t *pInLimit)
bool stringToBool(string_view str)
This file implemented 3 utility functions:
const FileContext & systemFileContext()
hash_map< std::string, unsigned, XXHasher > UnknownTypes
auto copy(InputRange &&range, OutputIter out)
constexpr void sort(RandomAccessRange &&range)
constexpr size_t EXTRA_BUFFER_SPACE
void swap(openmsx::MemBuffer< T > &l, openmsx::MemBuffer< T > &r) noexcept
size_t size(std::string_view utf8)
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)