diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index 00c5a03d..b372a888 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -120,6 +120,7 @@ SET(cockatrice_SOURCES src/userconnection_information.cpp src/spoilerbackgroundupdater.cpp src/handle_public_servers.cpp + src/carddbparser/cockatricexml3.cpp ${VERSION_STRING_CPP} ) diff --git a/cockatrice/src/carddatabase.cpp b/cockatrice/src/carddatabase.cpp index 393ed898..431544f8 100644 --- a/cockatrice/src/carddatabase.cpp +++ b/cockatrice/src/carddatabase.cpp @@ -1,4 +1,5 @@ #include "carddatabase.h" +#include "carddbparser/cockatricexml3.h" #include "pictureloader.h" #include "settingscache.h" #include "spoilerbackgroundupdater.h" @@ -10,26 +11,8 @@ #include #include -const int CardDatabase::versionNeeded = 3; const char *CardDatabase::TOKENS_SETNAME = "TK"; -static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardSetPtr &set) -{ - if (set.isNull()) { - qDebug() << "&operator<< set is nullptr"; - return xml; - } - - xml.writeStartElement("set"); - xml.writeTextElement("name", set->getShortName()); - xml.writeTextElement("longname", set->getLongName()); - xml.writeTextElement("settype", set->getSetType()); - xml.writeTextElement("releasedate", set->getReleaseDate().toString(Qt::ISODate)); - xml.writeEndElement(); - - return xml; -} - CardSet::CardSet(const QString &_shortName, const QString &_longName, const QString &_setType, @@ -396,123 +379,25 @@ const QChar CardInfo::getColorChar() const } } -static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &info) -{ - if (info.isNull()) { - qDebug() << "operator<< info is nullptr"; - return xml; - } - - xml.writeStartElement("card"); - xml.writeTextElement("name", info->getName()); - - const SetList &sets = info->getSets(); - QString tmpString; - QString tmpSet; - for (int i = 0; i < sets.size(); i++) { - xml.writeStartElement("set"); - - tmpSet = sets[i]->getShortName(); - xml.writeAttribute("rarity", info->getRarity(tmpSet)); - xml.writeAttribute("muId", QString::number(info->getMuId(tmpSet))); - - tmpString = info->getCollectorNumber(tmpSet); - if (!tmpString.isEmpty()) { - xml.writeAttribute("num", info->getCollectorNumber(tmpSet)); - } - - tmpString = info->getCustomPicURL(tmpSet); - if (!tmpString.isEmpty()) { - xml.writeAttribute("picURL", tmpString); - } - - xml.writeCharacters(tmpSet); - xml.writeEndElement(); - } - const QStringList &colors = info->getColors(); - for (int i = 0; i < colors.size(); i++) { - xml.writeTextElement("color", colors[i]); - } - - const QList related = info->getRelatedCards(); - for (auto i : related) { - xml.writeStartElement("related"); - if (i->getDoesAttach()) { - xml.writeAttribute("attach", "attach"); - } - if (i->getIsCreateAllExclusion()) { - xml.writeAttribute("exclude", "exclude"); - } - - if (i->getIsVariable()) { - if (1 == i->getDefaultCount()) { - xml.writeAttribute("count", "x"); - } else { - xml.writeAttribute("count", "x=" + QString::number(i->getDefaultCount())); - } - } else if (1 != i->getDefaultCount()) { - xml.writeAttribute("count", QString::number(i->getDefaultCount())); - } - xml.writeCharacters(i->getName()); - xml.writeEndElement(); - } - const QList reverseRelated = info->getReverseRelatedCards(); - for (auto i : reverseRelated) { - xml.writeStartElement("reverse-related"); - if (i->getDoesAttach()) { - xml.writeAttribute("attach", "attach"); - } - - if (i->getIsCreateAllExclusion()) { - xml.writeAttribute("exclude", "exclude"); - } - - if (i->getIsVariable()) { - if (1 == i->getDefaultCount()) { - xml.writeAttribute("count", "x"); - } else { - xml.writeAttribute("count", "x=" + QString::number(i->getDefaultCount())); - } - } else if (1 != i->getDefaultCount()) { - xml.writeAttribute("count", QString::number(i->getDefaultCount())); - } - xml.writeCharacters(i->getName()); - xml.writeEndElement(); - } - xml.writeTextElement("manacost", info->getManaCost()); - xml.writeTextElement("cmc", info->getCmc()); - xml.writeTextElement("type", info->getCardType()); - if (!info->getPowTough().isEmpty()) { - xml.writeTextElement("pt", info->getPowTough()); - } - xml.writeTextElement("tablerow", QString::number(info->getTableRow())); - xml.writeTextElement("text", info->getText()); - if (info->getMainCardType() == "Planeswalker") { - xml.writeTextElement("loyalty", info->getLoyalty()); - } - if (info->getCipt()) { - xml.writeTextElement("cipt", "1"); - } - if (info->getIsToken()) { - xml.writeTextElement("token", "1"); - } - if (info->getUpsideDownArt()) { - xml.writeTextElement("upsidedown", "1"); - } - - xml.writeEndElement(); // card - - return xml; -} - CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoaded) { qRegisterMetaType("CardInfoPtr"); + qRegisterMetaType("CardSetPtr"); + + // add new parsers here + availableParsers << new CockatriceXml3Parser; + + for (auto &parser : availableParsers) { + connect(parser, SIGNAL(addCard(CardInfoPtr)), this, SLOT(addCard(CardInfoPtr))); + connect(parser, SIGNAL(addSet(CardSetPtr)), this, SLOT(addSet(CardSetPtr))); + } + connect(settingsCache, SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabases())); } CardDatabase::~CardDatabase() { + qDeleteAll(availableParsers); clear(); } @@ -609,6 +494,11 @@ CardSetPtr CardDatabase::getSet(const QString &setName) } } +void CardDatabase::addSet(CardSetPtr set) +{ + sets.insert(set->getShortName(), set); +} + SetList CardDatabase::getSetList() const { SetList result; @@ -620,159 +510,6 @@ SetList CardDatabase::getSetList() const return result; } -void CardDatabase::loadSetsFromXml(QXmlStreamReader &xml) -{ - while (!xml.atEnd()) { - if (xml.readNext() == QXmlStreamReader::EndElement) { - break; - } - - if (xml.name() == "set") { - QString shortName, longName, setType; - QDate releaseDate; - while (!xml.atEnd()) { - if (xml.readNext() == QXmlStreamReader::EndElement) { - break; - } - - if (xml.name() == "name") { - shortName = xml.readElementText(); - } else if (xml.name() == "longname") { - longName = xml.readElementText(); - } else if (xml.name() == "settype") { - setType = xml.readElementText(); - } else if (xml.name() == "releasedate") { - releaseDate = QDate::fromString(xml.readElementText(), Qt::ISODate); - } else if (xml.name() != "") { - qDebug() << "[XMLReader] Unknown set property" << xml.name() << ", trying to continue anyway"; - xml.skipCurrentElement(); - } - } - - CardSetPtr newSet = getSet(shortName); - newSet->setLongName(longName); - newSet->setSetType(setType); - newSet->setReleaseDate(releaseDate); - } - } -} - -void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml) -{ - while (!xml.atEnd()) { - if (xml.readNext() == QXmlStreamReader::EndElement) { - break; - } - - if (xml.name() == "card") { - QString name, manacost, cmc, type, pt, text, loyalty; - QStringList colors; - QList relatedCards, reverseRelatedCards; - QStringMap customPicURLs; - MuidMap muids; - QStringMap collectorNumbers, rarities; - SetList sets; - int tableRow = 0; - bool cipt = false; - bool isToken = false; - bool upsideDown = false; - while (!xml.atEnd()) { - if (xml.readNext() == QXmlStreamReader::EndElement) { - break; - } - - if (xml.name() == "name") { - name = xml.readElementText(); - } else if (xml.name() == "manacost") { - manacost = xml.readElementText(); - } else if (xml.name() == "cmc") { - cmc = xml.readElementText(); - } else if (xml.name() == "type") { - type = xml.readElementText(); - } else if (xml.name() == "pt") { - pt = xml.readElementText(); - } else if (xml.name() == "text") { - text = xml.readElementText(); - } else if (xml.name() == "set") { - QXmlStreamAttributes attrs = xml.attributes(); - QString setName = xml.readElementText(); - sets.append(getSet(setName)); - if (attrs.hasAttribute("muId")) { - muids[setName] = attrs.value("muId").toString().toInt(); - } - - if (attrs.hasAttribute("picURL")) { - customPicURLs[setName] = attrs.value("picURL").toString(); - } - - if (attrs.hasAttribute("num")) { - collectorNumbers[setName] = attrs.value("num").toString(); - } - - if (attrs.hasAttribute("rarity")) { - rarities[setName] = attrs.value("rarity").toString(); - } - } else if (xml.name() == "color") { - colors << xml.readElementText(); - } else if (xml.name() == "related" || xml.name() == "reverse-related") { - bool attach = false; - bool exclude = false; - bool variable = false; - int count = 1; - QXmlStreamAttributes attrs = xml.attributes(); - QString cardName = xml.readElementText(); - if (attrs.hasAttribute("count")) { - if (attrs.value("count").toString().indexOf("x=") == 0) { - variable = true; - count = attrs.value("count").toString().remove(0, 2).toInt(); - } else if (attrs.value("count").toString().indexOf("x") == 0) { - variable = true; - } else { - count = attrs.value("count").toString().toInt(); - } - - if (count < 1) { - count = 1; - } - } - - if (attrs.hasAttribute("attach")) { - attach = true; - } - - if (attrs.hasAttribute("exclude")) { - exclude = true; - } - - auto *relation = new CardRelation(cardName, attach, exclude, variable, count); - if (xml.name() == "reverse-related") { - reverseRelatedCards << relation; - } else { - relatedCards << relation; - } - } else if (xml.name() == "tablerow") { - tableRow = xml.readElementText().toInt(); - } else if (xml.name() == "cipt") { - cipt = (xml.readElementText() == "1"); - } else if (xml.name() == "upsidedown") { - upsideDown = (xml.readElementText() == "1"); - } else if (xml.name() == "loyalty") { - loyalty = xml.readElementText(); - } else if (xml.name() == "token") { - isToken = static_cast(xml.readElementText().toInt()); - } else if (xml.name() != "") { - qDebug() << "[XMLReader] Unknown card property" << xml.name() << ", trying to continue anyway"; - xml.skipCurrentElement(); - } - } - - addCard(CardInfo::newInstance(name, isToken, manacost, cmc, type, pt, text, colors, relatedCards, - reverseRelatedCards, upsideDown, loyalty, cipt, tableRow, sets, customPicURLs, - muids, collectorNumbers, rarities)); - } - } -} - CardInfoPtr CardDatabase::getCardFromMap(const CardNameMap &cardMap, const QString &cardName) const { if (cardMap.contains(cardName)) @@ -789,81 +526,16 @@ LoadStatus CardDatabase::loadFromFile(const QString &fileName) return FileError; } - QXmlStreamReader xml(&file); - while (!xml.atEnd()) { - if (xml.readNext() == QXmlStreamReader::StartElement) { - if (xml.name() != "cockatrice_carddatabase") { - return Invalid; - } - - int version = xml.attributes().value("version").toString().toInt(); - if (version < versionNeeded) { - qDebug() << "[XMLReader] Version too old: " << version; - return VersionTooOld; - } - - while (!xml.atEnd()) { - if (xml.readNext() == QXmlStreamReader::EndElement) { - break; - } - - if (xml.name() == "sets") { - loadSetsFromXml(xml); - } else if (xml.name() == "cards") { - loadCardsFromXml(xml); - } else if (xml.name() != "") { - qDebug() << "[XMLReader] Unknown item" << xml.name() << ", trying to continue anyway"; - xml.skipCurrentElement(); - } - } + for (auto parser : availableParsers) { + file.reset(); + if (parser->getCanParseFile(fileName, file)) { + file.reset(); + parser->parseFile(file); + return Ok; } } - if (cards.isEmpty()) { - return NoCards; - } - - return Ok; -} - -bool CardDatabase::saveToFile(const QString &fileName, bool tokens) -{ - QFile file(fileName); - if (!file.open(QIODevice::WriteOnly)) { - return false; - } - - QXmlStreamWriter xml(&file); - - xml.setAutoFormatting(true); - xml.writeStartDocument(); - xml.writeStartElement("cockatrice_carddatabase"); - xml.writeAttribute("version", QString::number(versionNeeded)); - - if (!tokens) { - xml.writeStartElement("sets"); - QHashIterator setIterator(sets); - while (setIterator.hasNext()) { - xml << setIterator.next().value(); - } - - xml.writeEndElement(); // sets - } - - xml.writeStartElement("cards"); - QHashIterator cardIterator(cards); - while (cardIterator.hasNext()) { - CardInfoPtr card = cardIterator.next().value(); - if (tokens == card->getIsToken()) { - xml << card; - } - } - xml.writeEndElement(); // cards - - xml.writeEndElement(); // cockatrice_carddatabase - xml.writeEndDocument(); - - return true; + return Invalid; } LoadStatus CardDatabase::loadCardDatabase(const QString &path) @@ -1031,33 +703,20 @@ void CardDatabase::notifyEnabledSetsChanged() bool CardDatabase::saveCustomTokensToFile() { - CardSetPtr customTokensSet = getSet(CardDatabase::TOKENS_SETNAME); QString fileName = settingsCache->getCustomCardDatabasePath() + "/" + CardDatabase::TOKENS_SETNAME + ".xml"; - QFile file(fileName); - if (!file.open(QIODevice::WriteOnly)) { - return false; - } - QXmlStreamWriter xml(&file); + SetNameMap tmpSets; + CardSetPtr customTokensSet = getSet(CardDatabase::TOKENS_SETNAME); + tmpSets.insert(CardDatabase::TOKENS_SETNAME, customTokensSet); - xml.setAutoFormatting(true); - xml.writeStartDocument(); - xml.writeStartElement("cockatrice_carddatabase"); - xml.writeAttribute("version", QString::number(versionNeeded)); - - xml.writeStartElement("cards"); - QHashIterator cardIterator(cards); - while (cardIterator.hasNext()) { - CardInfoPtr card = cardIterator.next().value(); + CardNameMap tmpCards; + for (CardInfoPtr card : cards) { if (card->getSets().contains(customTokensSet)) { - xml << card; + tmpCards.insert(card->getName(), card); } } - xml.writeEndElement(); // cards - - xml.writeEndElement(); // cockatrice_carddatabase - xml.writeEndDocument(); + availableParsers.first()->saveToFile(tmpSets, tmpCards, fileName); return true; } diff --git a/cockatrice/src/carddatabase.h b/cockatrice/src/carddatabase.h index 50a71f34..3451684b 100644 --- a/cockatrice/src/carddatabase.h +++ b/cockatrice/src/carddatabase.h @@ -2,19 +2,20 @@ #define CARDDATABASE_H #include -#include #include #include #include #include #include -#include -#include +#include +#include +#include class CardDatabase; class CardInfo; class CardSet; class CardRelation; +class ICardDatabaseParser; typedef QMap QStringMap; typedef QMap MuidMap; @@ -58,15 +59,15 @@ public: { return releaseDate; } - void setLongName(QString &_longName) + void setLongName(const QString &_longName) { longName = _longName; } - void setSetType(QString &_setType) + void setSetType(const QString &_setType) { setType = _setType; } - void setReleaseDate(QDate &_releaseDate) + void setReleaseDate(const QDate &_releaseDate) { releaseDate = _releaseDate; } @@ -398,11 +399,9 @@ protected: LoadStatus loadStatus; -private: - static const int versionNeeded; - void loadCardsFromXml(QXmlStreamReader &xml); - void loadSetsFromXml(QXmlStreamReader &xml); + QVector availableParsers; +private: CardInfoPtr getCardFromMap(const CardNameMap &cardMap, const QString &cardName) const; void checkUnknownSets(); void refreshCachedReverseRelatedCards(); @@ -417,7 +416,6 @@ public: explicit CardDatabase(QObject *parent = nullptr); ~CardDatabase() override; void clear(); - void addCard(CardInfoPtr card); void removeCard(CardInfoPtr card); CardInfoPtr getCard(const QString &cardName) const; QList getCards(const QStringList &cardNames) const; @@ -435,7 +433,6 @@ public: } SetList getSetList() const; LoadStatus loadFromFile(const QString &fileName); - bool saveToFile(const QString &fileName, bool tokens = false); bool saveCustomTokensToFile(); QStringList getAllColors() const; QStringList getAllMainCardTypes() const; @@ -449,6 +446,8 @@ public: public slots: LoadStatus loadCardDatabases(); + void addCard(CardInfoPtr card); + void addSet(CardSetPtr set); private slots: LoadStatus loadCardDatabase(const QString &path); signals: diff --git a/cockatrice/src/carddbparser/carddatabaseparser.h b/cockatrice/src/carddbparser/carddatabaseparser.h new file mode 100644 index 00000000..71e3366d --- /dev/null +++ b/cockatrice/src/carddbparser/carddatabaseparser.h @@ -0,0 +1,24 @@ +#ifndef CARDDATABASE_PARSER_H +#define CARDDATABASE_PARSER_H + +#include +#include + +#include "../carddatabase.h" + +class ICardDatabaseParser : public QObject +{ +public: + virtual ~ICardDatabaseParser() + { + } + virtual bool getCanParseFile(const QString &name, QIODevice &device) = 0; + virtual void parseFile(QIODevice &device) = 0; + virtual bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) = 0; +signals: + virtual void addCard(CardInfoPtr card) = 0; +}; + +Q_DECLARE_INTERFACE(ICardDatabaseParser, "ICardDatabaseParser") + +#endif \ No newline at end of file diff --git a/cockatrice/src/carddbparser/cockatricexml3.cpp b/cockatrice/src/carddbparser/cockatricexml3.cpp new file mode 100644 index 00000000..0f5ac821 --- /dev/null +++ b/cockatrice/src/carddbparser/cockatricexml3.cpp @@ -0,0 +1,396 @@ +#include "cockatricexml3.h" + +#include +#include +#include + +#define COCKATRICE_XML3_TAGNAME "cockatrice_carddatabase" +#define COCKATRICE_XML3_TAGVER 3 + +bool CockatriceXml3Parser::getCanParseFile(const QString &fileName, QIODevice &device) +{ + qDebug() << "[CockatriceXml3Parser] Trying to parse: " << fileName; + + if (!fileName.endsWith(".xml", Qt::CaseInsensitive)) { + qDebug() << "[CockatriceXml3Parser] Parsing failed: wrong extension"; + return false; + } + + QXmlStreamReader xml(&device); + while (!xml.atEnd()) { + if (xml.readNext() == QXmlStreamReader::StartElement) { + if (xml.name() == COCKATRICE_XML3_TAGNAME) { + int version = xml.attributes().value("version").toString().toInt(); + if (version == COCKATRICE_XML3_TAGVER) { + return true; + } else { + qDebug() << "[CockatriceXml3Parser] Parsing failed: wrong version" << version; + return false; + } + + } else { + qDebug() << "[CockatriceXml3Parser] Parsing failed: wrong element tag" << xml.name(); + return false; + } + } + } + + return true; +} + +void CockatriceXml3Parser::parseFile(QIODevice &device) +{ + QXmlStreamReader xml(&device); + while (!xml.atEnd()) { + if (xml.readNext() == QXmlStreamReader::StartElement) { + while (!xml.atEnd()) { + if (xml.readNext() == QXmlStreamReader::EndElement) { + break; + } + + if (xml.name() == "sets") { + loadSetsFromXml(xml); + } else if (xml.name() == "cards") { + loadCardsFromXml(xml); + } else if (xml.name() != "") { + qDebug() << "[CockatriceXml3Parser] Unknown item" << xml.name() << ", trying to continue anyway"; + xml.skipCurrentElement(); + } + } + } + } +} + +CardSetPtr CockatriceXml3Parser::internalAddSet(const QString &setName, + const QString &longName, + const QString &setType, + const QDate &releaseDate) +{ + if (sets.contains(setName)) { + return sets.value(setName); + } + + CardSetPtr newSet = CardSet::newInstance(setName); + newSet->setLongName(longName); + newSet->setSetType(setType); + newSet->setReleaseDate(releaseDate); + + sets.insert(setName, newSet); + emit addSet(newSet); + return newSet; +} + +void CockatriceXml3Parser::loadSetsFromXml(QXmlStreamReader &xml) +{ + while (!xml.atEnd()) { + if (xml.readNext() == QXmlStreamReader::EndElement) { + break; + } + + if (xml.name() == "set") { + QString shortName, longName, setType; + QDate releaseDate; + while (!xml.atEnd()) { + if (xml.readNext() == QXmlStreamReader::EndElement) { + break; + } + + if (xml.name() == "name") { + shortName = xml.readElementText(); + } else if (xml.name() == "longname") { + longName = xml.readElementText(); + } else if (xml.name() == "settype") { + setType = xml.readElementText(); + } else if (xml.name() == "releasedate") { + releaseDate = QDate::fromString(xml.readElementText(), Qt::ISODate); + } else if (xml.name() != "") { + qDebug() << "[CockatriceXml3Parser] Unknown set property" << xml.name() + << ", trying to continue anyway"; + xml.skipCurrentElement(); + } + } + + internalAddSet(shortName, longName, setType, releaseDate); + } + } +} + +void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml) +{ + while (!xml.atEnd()) { + if (xml.readNext() == QXmlStreamReader::EndElement) { + break; + } + + if (xml.name() == "card") { + QString name, manacost, cmc, type, pt, text, loyalty; + QStringList colors; + QList relatedCards, reverseRelatedCards; + QStringMap customPicURLs; + MuidMap muids; + QStringMap collectorNumbers, rarities; + SetList sets; + int tableRow = 0; + bool cipt = false; + bool isToken = false; + bool upsideDown = false; + while (!xml.atEnd()) { + if (xml.readNext() == QXmlStreamReader::EndElement) { + break; + } + + if (xml.name() == "name") { + name = xml.readElementText(); + } else if (xml.name() == "manacost") { + manacost = xml.readElementText(); + } else if (xml.name() == "cmc") { + cmc = xml.readElementText(); + } else if (xml.name() == "type") { + type = xml.readElementText(); + } else if (xml.name() == "pt") { + pt = xml.readElementText(); + } else if (xml.name() == "text") { + text = xml.readElementText(); + } else if (xml.name() == "set") { + QXmlStreamAttributes attrs = xml.attributes(); + QString setName = xml.readElementText(); + sets.append(internalAddSet(setName)); + if (attrs.hasAttribute("muId")) { + muids[setName] = attrs.value("muId").toString().toInt(); + } + + if (attrs.hasAttribute("picURL")) { + customPicURLs[setName] = attrs.value("picURL").toString(); + } + + if (attrs.hasAttribute("num")) { + collectorNumbers[setName] = attrs.value("num").toString(); + } + + if (attrs.hasAttribute("rarity")) { + rarities[setName] = attrs.value("rarity").toString(); + } + } else if (xml.name() == "color") { + colors << xml.readElementText(); + } else if (xml.name() == "related" || xml.name() == "reverse-related") { + bool attach = false; + bool exclude = false; + bool variable = false; + int count = 1; + QXmlStreamAttributes attrs = xml.attributes(); + QString cardName = xml.readElementText(); + if (attrs.hasAttribute("count")) { + if (attrs.value("count").toString().indexOf("x=") == 0) { + variable = true; + count = attrs.value("count").toString().remove(0, 2).toInt(); + } else if (attrs.value("count").toString().indexOf("x") == 0) { + variable = true; + } else { + count = attrs.value("count").toString().toInt(); + } + + if (count < 1) { + count = 1; + } + } + + if (attrs.hasAttribute("attach")) { + attach = true; + } + + if (attrs.hasAttribute("exclude")) { + exclude = true; + } + + auto *relation = new CardRelation(cardName, attach, exclude, variable, count); + if (xml.name() == "reverse-related") { + reverseRelatedCards << relation; + } else { + relatedCards << relation; + } + } else if (xml.name() == "tablerow") { + tableRow = xml.readElementText().toInt(); + } else if (xml.name() == "cipt") { + cipt = (xml.readElementText() == "1"); + } else if (xml.name() == "upsidedown") { + upsideDown = (xml.readElementText() == "1"); + } else if (xml.name() == "loyalty") { + loyalty = xml.readElementText(); + } else if (xml.name() == "token") { + isToken = static_cast(xml.readElementText().toInt()); + } else if (xml.name() != "") { + qDebug() << "[CockatriceXml3Parser] Unknown card property" << xml.name() + << ", trying to continue anyway"; + xml.skipCurrentElement(); + } + } + + CardInfoPtr newCard = CardInfo::newInstance( + name, isToken, manacost, cmc, type, pt, text, colors, relatedCards, reverseRelatedCards, upsideDown, + loyalty, cipt, tableRow, sets, customPicURLs, muids, collectorNumbers, rarities); + emit addCard(newCard); + } + } +} + +static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardSetPtr &set) +{ + if (set.isNull()) { + qDebug() << "&operator<< set is nullptr"; + return xml; + } + + xml.writeStartElement("set"); + xml.writeTextElement("name", set->getShortName()); + xml.writeTextElement("longname", set->getLongName()); + xml.writeTextElement("settype", set->getSetType()); + xml.writeTextElement("releasedate", set->getReleaseDate().toString(Qt::ISODate)); + xml.writeEndElement(); + + return xml; +} + +static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &info) +{ + if (info.isNull()) { + qDebug() << "operator<< info is nullptr"; + return xml; + } + + xml.writeStartElement("card"); + xml.writeTextElement("name", info->getName()); + + const SetList &sets = info->getSets(); + QString tmpString; + QString tmpSet; + for (int i = 0; i < sets.size(); i++) { + xml.writeStartElement("set"); + + tmpSet = sets[i]->getShortName(); + xml.writeAttribute("rarity", info->getRarity(tmpSet)); + xml.writeAttribute("muId", QString::number(info->getMuId(tmpSet))); + + tmpString = info->getCollectorNumber(tmpSet); + if (!tmpString.isEmpty()) { + xml.writeAttribute("num", info->getCollectorNumber(tmpSet)); + } + + tmpString = info->getCustomPicURL(tmpSet); + if (!tmpString.isEmpty()) { + xml.writeAttribute("picURL", tmpString); + } + + xml.writeCharacters(tmpSet); + xml.writeEndElement(); + } + const QStringList &colors = info->getColors(); + for (int i = 0; i < colors.size(); i++) { + xml.writeTextElement("color", colors[i]); + } + + const QList related = info->getRelatedCards(); + for (auto i : related) { + xml.writeStartElement("related"); + if (i->getDoesAttach()) { + xml.writeAttribute("attach", "attach"); + } + if (i->getIsCreateAllExclusion()) { + xml.writeAttribute("exclude", "exclude"); + } + + if (i->getIsVariable()) { + if (1 == i->getDefaultCount()) { + xml.writeAttribute("count", "x"); + } else { + xml.writeAttribute("count", "x=" + QString::number(i->getDefaultCount())); + } + } else if (1 != i->getDefaultCount()) { + xml.writeAttribute("count", QString::number(i->getDefaultCount())); + } + xml.writeCharacters(i->getName()); + xml.writeEndElement(); + } + const QList reverseRelated = info->getReverseRelatedCards(); + for (auto i : reverseRelated) { + xml.writeStartElement("reverse-related"); + if (i->getDoesAttach()) { + xml.writeAttribute("attach", "attach"); + } + + if (i->getIsCreateAllExclusion()) { + xml.writeAttribute("exclude", "exclude"); + } + + if (i->getIsVariable()) { + if (1 == i->getDefaultCount()) { + xml.writeAttribute("count", "x"); + } else { + xml.writeAttribute("count", "x=" + QString::number(i->getDefaultCount())); + } + } else if (1 != i->getDefaultCount()) { + xml.writeAttribute("count", QString::number(i->getDefaultCount())); + } + xml.writeCharacters(i->getName()); + xml.writeEndElement(); + } + xml.writeTextElement("manacost", info->getManaCost()); + xml.writeTextElement("cmc", info->getCmc()); + xml.writeTextElement("type", info->getCardType()); + if (!info->getPowTough().isEmpty()) { + xml.writeTextElement("pt", info->getPowTough()); + } + xml.writeTextElement("tablerow", QString::number(info->getTableRow())); + xml.writeTextElement("text", info->getText()); + if (info->getMainCardType() == "Planeswalker") { + xml.writeTextElement("loyalty", info->getLoyalty()); + } + if (info->getCipt()) { + xml.writeTextElement("cipt", "1"); + } + if (info->getIsToken()) { + xml.writeTextElement("token", "1"); + } + if (info->getUpsideDownArt()) { + xml.writeTextElement("upsidedown", "1"); + } + + xml.writeEndElement(); // card + + return xml; +} + +bool CockatriceXml3Parser::saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) +{ + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly)) { + return false; + } + + QXmlStreamWriter xml(&file); + + xml.setAutoFormatting(true); + xml.writeStartDocument(); + xml.writeStartElement(COCKATRICE_XML3_TAGNAME); + xml.writeAttribute("version", QString::number(COCKATRICE_XML3_TAGVER)); + + if (sets.count() > 0) { + xml.writeStartElement("sets"); + for (CardSetPtr set : sets) { + xml << set; + } + xml.writeEndElement(); + } + + if (cards.count() > 0) { + xml.writeStartElement("cards"); + for (CardInfoPtr card : cards) { + xml << card; + } + xml.writeEndElement(); + } + + xml.writeEndElement(); // cockatrice_carddatabase + xml.writeEndDocument(); + + return true; +} \ No newline at end of file diff --git a/cockatrice/src/carddbparser/cockatricexml3.h b/cockatrice/src/carddbparser/cockatricexml3.h new file mode 100644 index 00000000..1e95b7e8 --- /dev/null +++ b/cockatrice/src/carddbparser/cockatricexml3.h @@ -0,0 +1,36 @@ +#ifndef COCKATRICE_XML3_H +#define COCKATRICE_XML3_H + +#include + +#include "carddatabaseparser.h" + +class CockatriceXml3Parser : public ICardDatabaseParser +{ + Q_OBJECT + Q_INTERFACES(ICardDatabaseParser) +public: + CockatriceXml3Parser() = default; + ~CockatriceXml3Parser() = default; + bool getCanParseFile(const QString &name, QIODevice &device); + void parseFile(QIODevice &device); + bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName); + +private: + /* + * A cached list of the available sets, needed to cross-reference sets from cards. + */ + SetNameMap sets; + + CardSetPtr internalAddSet(const QString &setName, + const QString &longName = "", + const QString &setType = "", + const QDate &releaseDate = QDate()); + void loadCardsFromXml(QXmlStreamReader &xml); + void loadSetsFromXml(QXmlStreamReader &xml); +signals: + void addCard(CardInfoPtr card); + void addSet(CardSetPtr set); +}; + +#endif \ No newline at end of file diff --git a/oracle/CMakeLists.txt b/oracle/CMakeLists.txt index 5c8cac94..b35a5679 100644 --- a/oracle/CMakeLists.txt +++ b/oracle/CMakeLists.txt @@ -13,6 +13,7 @@ SET(oracle_SOURCES src/oracleimporter.cpp ../cockatrice/src/carddatabase.cpp ../cockatrice/src/pictureloader.cpp + ../cockatrice/src/carddbparser/cockatricexml3.cpp ../cockatrice/src/settingscache.cpp ../cockatrice/src/shortcutssettings.cpp ../cockatrice/src/settings/carddatabasesettings.cpp diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp index 7103c39d..90c908f9 100644 --- a/oracle/src/oracleimporter.cpp +++ b/oracle/src/oracleimporter.cpp @@ -1,4 +1,5 @@ #include "oracleimporter.h" +#include "carddbparser/cockatricexml3.h" #include #include @@ -174,6 +175,7 @@ int OracleImporter::importTextSpoiler(CardSetPtr set, const QVariant &data) QString layout = map.value("layout").toString(); + // don't import tokens from the json file if (layout == "token") continue; @@ -362,3 +364,9 @@ int OracleImporter::startImport() // total number of sets return setIndex; } + +bool OracleImporter::saveToFile(const QString &fileName) +{ + CockatriceXml3Parser parser; + return parser.saveToFile(sets, cards, fileName); +} \ No newline at end of file diff --git a/oracle/src/oracleimporter.h b/oracle/src/oracleimporter.h index 84f7b4c2..538a327e 100644 --- a/oracle/src/oracleimporter.h +++ b/oracle/src/oracleimporter.h @@ -81,6 +81,7 @@ public: OracleImporter(const QString &_dataDir, QObject *parent = 0); bool readSetsFromByteArray(const QByteArray &data); int startImport(); + bool saveToFile(const QString &fileName); int importTextSpoiler(CardSetPtr set, const QVariant &data); QList &getSets() { diff --git a/tests/carddatabase/CMakeLists.txt b/tests/carddatabase/CMakeLists.txt index e1b48b7b..e204f241 100644 --- a/tests/carddatabase/CMakeLists.txt +++ b/tests/carddatabase/CMakeLists.txt @@ -2,6 +2,7 @@ ADD_DEFINITIONS("-DCARDDB_DATADIR=\"${CMAKE_CURRENT_SOURCE_DIR}/data/\"") add_executable(carddatabase_test carddatabase_test.cpp ../../cockatrice/src/carddatabase.cpp + ../../cockatrice/src/carddbparser/cockatricexml3.cpp ) if(NOT GTEST_FOUND)