Extract the xml parser from carddatabase (#3223)

This commit is contained in:
ctrlaltca 2018-05-04 09:46:08 +02:00 committed by Zach H
parent 9727699e26
commit a7f4aace9c
10 changed files with 510 additions and 384 deletions

View file

@ -120,6 +120,7 @@ SET(cockatrice_SOURCES
src/userconnection_information.cpp src/userconnection_information.cpp
src/spoilerbackgroundupdater.cpp src/spoilerbackgroundupdater.cpp
src/handle_public_servers.cpp src/handle_public_servers.cpp
src/carddbparser/cockatricexml3.cpp
${VERSION_STRING_CPP} ${VERSION_STRING_CPP}
) )

View file

@ -1,4 +1,5 @@
#include "carddatabase.h" #include "carddatabase.h"
#include "carddbparser/cockatricexml3.h"
#include "pictureloader.h" #include "pictureloader.h"
#include "settingscache.h" #include "settingscache.h"
#include "spoilerbackgroundupdater.h" #include "spoilerbackgroundupdater.h"
@ -10,26 +11,8 @@
#include <QMessageBox> #include <QMessageBox>
#include <utility> #include <utility>
const int CardDatabase::versionNeeded = 3;
const char *CardDatabase::TOKENS_SETNAME = "TK"; 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, CardSet::CardSet(const QString &_shortName,
const QString &_longName, const QString &_longName,
const QString &_setType, 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<CardRelation *> 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<CardRelation *> 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) CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoaded)
{ {
qRegisterMetaType<CardInfoPtr>("CardInfoPtr"); qRegisterMetaType<CardInfoPtr>("CardInfoPtr");
qRegisterMetaType<CardInfoPtr>("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())); connect(settingsCache, SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabases()));
} }
CardDatabase::~CardDatabase() CardDatabase::~CardDatabase()
{ {
qDeleteAll(availableParsers);
clear(); 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 CardDatabase::getSetList() const
{ {
SetList result; SetList result;
@ -620,159 +510,6 @@ SetList CardDatabase::getSetList() const
return result; 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<CardRelation *> 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<bool>(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 CardInfoPtr CardDatabase::getCardFromMap(const CardNameMap &cardMap, const QString &cardName) const
{ {
if (cardMap.contains(cardName)) if (cardMap.contains(cardName))
@ -789,81 +526,16 @@ LoadStatus CardDatabase::loadFromFile(const QString &fileName)
return FileError; return FileError;
} }
QXmlStreamReader xml(&file); for (auto parser : availableParsers) {
while (!xml.atEnd()) { file.reset();
if (xml.readNext() == QXmlStreamReader::StartElement) { if (parser->getCanParseFile(fileName, file)) {
if (xml.name() != "cockatrice_carddatabase") { file.reset();
return Invalid; parser->parseFile(file);
}
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();
}
}
}
}
if (cards.isEmpty()) {
return NoCards;
}
return Ok; 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<QString, CardSetPtr> setIterator(sets);
while (setIterator.hasNext()) {
xml << setIterator.next().value();
}
xml.writeEndElement(); // sets
}
xml.writeStartElement("cards");
QHashIterator<QString, CardInfoPtr> cardIterator(cards);
while (cardIterator.hasNext()) {
CardInfoPtr card = cardIterator.next().value();
if (tokens == card->getIsToken()) {
xml << card;
} }
} }
xml.writeEndElement(); // cards
xml.writeEndElement(); // cockatrice_carddatabase return Invalid;
xml.writeEndDocument();
return true;
} }
LoadStatus CardDatabase::loadCardDatabase(const QString &path) LoadStatus CardDatabase::loadCardDatabase(const QString &path)
@ -1031,33 +703,20 @@ void CardDatabase::notifyEnabledSetsChanged()
bool CardDatabase::saveCustomTokensToFile() bool CardDatabase::saveCustomTokensToFile()
{ {
CardSetPtr customTokensSet = getSet(CardDatabase::TOKENS_SETNAME);
QString fileName = settingsCache->getCustomCardDatabasePath() + "/" + CardDatabase::TOKENS_SETNAME + ".xml"; 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); CardNameMap tmpCards;
xml.writeStartDocument(); for (CardInfoPtr card : cards) {
xml.writeStartElement("cockatrice_carddatabase");
xml.writeAttribute("version", QString::number(versionNeeded));
xml.writeStartElement("cards");
QHashIterator<QString, CardInfoPtr> cardIterator(cards);
while (cardIterator.hasNext()) {
CardInfoPtr card = cardIterator.next().value();
if (card->getSets().contains(customTokensSet)) { 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; return true;
} }

View file

@ -2,19 +2,20 @@
#define CARDDATABASE_H #define CARDDATABASE_H
#include <QBasicMutex> #include <QBasicMutex>
#include <QDataStream>
#include <QDate> #include <QDate>
#include <QHash> #include <QHash>
#include <QList> #include <QList>
#include <QMap> #include <QMap>
#include <QMetaType> #include <QMetaType>
#include <QPixmap> #include <QSharedPointer>
#include <QXmlStreamReader> #include <QStringList>
#include <QVector>
class CardDatabase; class CardDatabase;
class CardInfo; class CardInfo;
class CardSet; class CardSet;
class CardRelation; class CardRelation;
class ICardDatabaseParser;
typedef QMap<QString, QString> QStringMap; typedef QMap<QString, QString> QStringMap;
typedef QMap<QString, int> MuidMap; typedef QMap<QString, int> MuidMap;
@ -58,15 +59,15 @@ public:
{ {
return releaseDate; return releaseDate;
} }
void setLongName(QString &_longName) void setLongName(const QString &_longName)
{ {
longName = _longName; longName = _longName;
} }
void setSetType(QString &_setType) void setSetType(const QString &_setType)
{ {
setType = _setType; setType = _setType;
} }
void setReleaseDate(QDate &_releaseDate) void setReleaseDate(const QDate &_releaseDate)
{ {
releaseDate = _releaseDate; releaseDate = _releaseDate;
} }
@ -398,11 +399,9 @@ protected:
LoadStatus loadStatus; LoadStatus loadStatus;
private: QVector<ICardDatabaseParser *> availableParsers;
static const int versionNeeded;
void loadCardsFromXml(QXmlStreamReader &xml);
void loadSetsFromXml(QXmlStreamReader &xml);
private:
CardInfoPtr getCardFromMap(const CardNameMap &cardMap, const QString &cardName) const; CardInfoPtr getCardFromMap(const CardNameMap &cardMap, const QString &cardName) const;
void checkUnknownSets(); void checkUnknownSets();
void refreshCachedReverseRelatedCards(); void refreshCachedReverseRelatedCards();
@ -417,7 +416,6 @@ public:
explicit CardDatabase(QObject *parent = nullptr); explicit CardDatabase(QObject *parent = nullptr);
~CardDatabase() override; ~CardDatabase() override;
void clear(); void clear();
void addCard(CardInfoPtr card);
void removeCard(CardInfoPtr card); void removeCard(CardInfoPtr card);
CardInfoPtr getCard(const QString &cardName) const; CardInfoPtr getCard(const QString &cardName) const;
QList<CardInfoPtr> getCards(const QStringList &cardNames) const; QList<CardInfoPtr> getCards(const QStringList &cardNames) const;
@ -435,7 +433,6 @@ public:
} }
SetList getSetList() const; SetList getSetList() const;
LoadStatus loadFromFile(const QString &fileName); LoadStatus loadFromFile(const QString &fileName);
bool saveToFile(const QString &fileName, bool tokens = false);
bool saveCustomTokensToFile(); bool saveCustomTokensToFile();
QStringList getAllColors() const; QStringList getAllColors() const;
QStringList getAllMainCardTypes() const; QStringList getAllMainCardTypes() const;
@ -449,6 +446,8 @@ public:
public slots: public slots:
LoadStatus loadCardDatabases(); LoadStatus loadCardDatabases();
void addCard(CardInfoPtr card);
void addSet(CardSetPtr set);
private slots: private slots:
LoadStatus loadCardDatabase(const QString &path); LoadStatus loadCardDatabase(const QString &path);
signals: signals:

View file

@ -0,0 +1,24 @@
#ifndef CARDDATABASE_PARSER_H
#define CARDDATABASE_PARSER_H
#include <QIODevice>
#include <QString>
#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

View file

@ -0,0 +1,396 @@
#include "cockatricexml3.h"
#include <QDebug>
#include <QFile>
#include <QXmlStreamReader>
#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<CardRelation *> 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<bool>(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<CardRelation *> 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<CardRelation *> 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;
}

View file

@ -0,0 +1,36 @@
#ifndef COCKATRICE_XML3_H
#define COCKATRICE_XML3_H
#include <QXmlStreamReader>
#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

View file

@ -13,6 +13,7 @@ SET(oracle_SOURCES
src/oracleimporter.cpp src/oracleimporter.cpp
../cockatrice/src/carddatabase.cpp ../cockatrice/src/carddatabase.cpp
../cockatrice/src/pictureloader.cpp ../cockatrice/src/pictureloader.cpp
../cockatrice/src/carddbparser/cockatricexml3.cpp
../cockatrice/src/settingscache.cpp ../cockatrice/src/settingscache.cpp
../cockatrice/src/shortcutssettings.cpp ../cockatrice/src/shortcutssettings.cpp
../cockatrice/src/settings/carddatabasesettings.cpp ../cockatrice/src/settings/carddatabasesettings.cpp

View file

@ -1,4 +1,5 @@
#include "oracleimporter.h" #include "oracleimporter.h"
#include "carddbparser/cockatricexml3.h"
#include <QDebug> #include <QDebug>
#include <QtWidgets> #include <QtWidgets>
@ -174,6 +175,7 @@ int OracleImporter::importTextSpoiler(CardSetPtr set, const QVariant &data)
QString layout = map.value("layout").toString(); QString layout = map.value("layout").toString();
// don't import tokens from the json file
if (layout == "token") if (layout == "token")
continue; continue;
@ -362,3 +364,9 @@ int OracleImporter::startImport()
// total number of sets // total number of sets
return setIndex; return setIndex;
} }
bool OracleImporter::saveToFile(const QString &fileName)
{
CockatriceXml3Parser parser;
return parser.saveToFile(sets, cards, fileName);
}

View file

@ -81,6 +81,7 @@ public:
OracleImporter(const QString &_dataDir, QObject *parent = 0); OracleImporter(const QString &_dataDir, QObject *parent = 0);
bool readSetsFromByteArray(const QByteArray &data); bool readSetsFromByteArray(const QByteArray &data);
int startImport(); int startImport();
bool saveToFile(const QString &fileName);
int importTextSpoiler(CardSetPtr set, const QVariant &data); int importTextSpoiler(CardSetPtr set, const QVariant &data);
QList<SetToDownload> &getSets() QList<SetToDownload> &getSets()
{ {

View file

@ -2,6 +2,7 @@ ADD_DEFINITIONS("-DCARDDB_DATADIR=\"${CMAKE_CURRENT_SOURCE_DIR}/data/\"")
add_executable(carddatabase_test add_executable(carddatabase_test
carddatabase_test.cpp carddatabase_test.cpp
../../cockatrice/src/carddatabase.cpp ../../cockatrice/src/carddatabase.cpp
../../cockatrice/src/carddbparser/cockatricexml3.cpp
) )
if(NOT GTEST_FOUND) if(NOT GTEST_FOUND)