From 4b7b78545213f5d750e494a6ab40e0cd32a2aa9b Mon Sep 17 00:00:00 2001 From: ebbit1q Date: Sat, 29 Aug 2026 15:21:04 +0200 Subject: [PATCH] add a limit to the size of deckfiles cockatrice can load (#7163) * add a limit to the size of deckfiles cockatrice can load the limit is 99999 or 100k -1 right now, which is kind of the limit of what looks acceptable in the player * format * up limit to 100k because that's what the tests do --- .../deck_list/deck_list_node_tree.cpp | 6 ++++- .../deck_list/deck_list_node_tree.h | 1 + .../tree/abstract_deck_list_card_node.cpp | 8 +++---- .../tree/abstract_deck_list_card_node.h | 2 +- .../deck_list/tree/abstract_deck_list_node.h | 2 +- .../deck_list/tree/inner_deck_list_node.cpp | 24 +++++++++++-------- .../deck_list/tree/inner_deck_list_node.h | 5 ++-- 7 files changed, 29 insertions(+), 19 deletions(-) diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.cpp b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.cpp index 21f628f9d..91fe1874b 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.cpp +++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.cpp @@ -5,6 +5,8 @@ #include #include +static constexpr int MAX_DECK_SIZE = 1e5; + DecklistNodeTree::DecklistNodeTree() : root(new InnerDecklistNode()) { } @@ -113,7 +115,7 @@ void DecklistNodeTree::readZoneElement(QXmlStreamReader *xml) { QString zoneName = xml->attributes().value("name").toString(); InnerDecklistNode *newZone = getZoneObjFromName(zoneName); - newZone->readElement(xml); + totalCards += newZone->readElement(xml, MAX_DECK_SIZE - totalCards); } DecklistCardNode *DecklistNodeTree::addCard(const QString &cardName, @@ -125,6 +127,8 @@ DecklistCardNode *DecklistNodeTree::addCard(const QString &cardName, const QString &cardProviderId, const bool formatLegal) { + amount = qMin(amount, MAX_DECK_SIZE - totalCards); + totalCards += amount; auto *zoneNode = getZoneObjFromName(zoneName); auto *node = new DecklistCardNode(cardName, amount, zoneNode, position, cardSetName, cardSetCollectorNumber, cardProviderId, formatLegal); diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.h b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.h index 1012d5919..af1193f26 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.h +++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.h @@ -10,6 +10,7 @@ class DecklistNodeTree { InnerDecklistNode *root; ///< Root of the deck tree (zones + cards). + int totalCards = 0; public: /** @brief Constructs an empty DecklistNodeTree. */ diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/tree/abstract_deck_list_card_node.cpp b/libcockatrice_deck_list/libcockatrice/deck_list/tree/abstract_deck_list_card_node.cpp index 705dfae4c..7200ede5f 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/tree/abstract_deck_list_card_node.cpp +++ b/libcockatrice_deck_list/libcockatrice/deck_list/tree/abstract_deck_list_card_node.cpp @@ -34,15 +34,15 @@ bool AbstractDecklistCardNode::compareName(AbstractDecklistNode *other) const } } -bool AbstractDecklistCardNode::readElement(QXmlStreamReader *xml) +int AbstractDecklistCardNode::readElement(QXmlStreamReader *xml, int /* limit */) { while (!xml->atEnd()) { xml->readNext(); if (xml->isEndElement() && xml->name().toString() == "card") { - return false; + return 0; } } - return true; + return 0; } void AbstractDecklistCardNode::writeElement(QXmlStreamWriter *xml) @@ -60,4 +60,4 @@ void AbstractDecklistCardNode::writeElement(QXmlStreamWriter *xml) if (!getCardProviderId().isEmpty()) { xml->writeAttribute("uuid", getCardProviderId()); } -} \ No newline at end of file +} diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/tree/abstract_deck_list_card_node.h b/libcockatrice_deck_list/libcockatrice/deck_list/tree/abstract_deck_list_card_node.h index df903a168..52dd56529 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/tree/abstract_deck_list_card_node.h +++ b/libcockatrice_deck_list/libcockatrice/deck_list/tree/abstract_deck_list_card_node.h @@ -141,7 +141,7 @@ public: * * This supports loading deck files from Cockatrice’s XML format. */ - bool readElement(QXmlStreamReader *xml) override; + int readElement(QXmlStreamReader *xml, int limit) override; /** * @brief Serialize this node’s properties to XML. diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/tree/abstract_deck_list_node.h b/libcockatrice_deck_list/libcockatrice/deck_list/tree/abstract_deck_list_node.h index c5cb25d8f..9c4290db0 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/tree/abstract_deck_list_node.h +++ b/libcockatrice_deck_list/libcockatrice/deck_list/tree/abstract_deck_list_node.h @@ -183,7 +183,7 @@ public: * Cockatrice deck XML format. * @{ */ - virtual bool readElement(QXmlStreamReader *xml) = 0; + virtual int readElement(QXmlStreamReader *xml, int limit) = 0; virtual void writeElement(QXmlStreamWriter *xml) = 0; /// @} }; diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.cpp b/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.cpp index 1f470695d..ec860dc56 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.cpp +++ b/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.cpp @@ -141,27 +141,31 @@ bool InnerDecklistNode::compareName(AbstractDecklistNode *other) const } } -bool InnerDecklistNode::readElement(QXmlStreamReader *xml) +int InnerDecklistNode::readElement(QXmlStreamReader *xml, int limit) { + int totalCards = 0; while (!xml->atEnd()) { xml->readNext(); const QString childName = xml->name().toString(); if (xml->isStartElement()) { if (childName == "zone") { auto *newZone = new InnerDecklistNode(xml->attributes().value("name").toString(), this); - newZone->readElement(xml); + totalCards += newZone->readElement(xml, limit - totalCards); } else if (childName == "card") { - auto *newCard = new DecklistCardNode( - xml->attributes().value("name").toString(), xml->attributes().value("number").toString().toInt(), - this, -1, xml->attributes().value("setShortName").toString(), - xml->attributes().value("collectorNumber").toString(), xml->attributes().value("uuid").toString()); - newCard->readElement(xml); + int amount = xml->attributes().value("number").toString().toInt(); + amount = qMin(amount, limit - totalCards); + auto *newCard = new DecklistCardNode(xml->attributes().value("name").toString(), amount, this, -1, + xml->attributes().value("setShortName").toString(), + xml->attributes().value("collectorNumber").toString(), + xml->attributes().value("uuid").toString()); + totalCards += amount; + totalCards += newCard->readElement(xml, limit - totalCards); } } else if (xml->isEndElement() && (childName == "zone")) { - return false; + return totalCards; } } - return true; + return totalCards; } void InnerDecklistNode::writeElement(QXmlStreamWriter *xml) @@ -201,4 +205,4 @@ QVector> InnerDecklistNode::sort(Qt::SortOrder order) } return result; -} \ No newline at end of file +} diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.h b/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.h index f8fdedf30..906ed6cb5 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.h +++ b/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.h @@ -216,9 +216,10 @@ public: /** * @brief Deserialize this node and its children from XML. * @param xml Reader positioned at this element. - * @return true if parsing succeeded. + * @param limit The maximum amount of cards to read + * @return the amount of cards found */ - bool readElement(QXmlStreamReader *xml) override; + int readElement(QXmlStreamReader *xml, int limit) override; /** * @brief Serialize this node and its children to XML.