#pragma once #include #include #include #include /** * Type of OPDS entry. */ enum class OpdsEntryType { NAVIGATION, // Link to another catalog BOOK // Downloadable book }; /** * Represents an entry from an OPDS feed (either a navigation link or a book). */ struct OpdsEntry { OpdsEntryType type = OpdsEntryType::NAVIGATION; std::string title; std::string author; // Only for books std::string href; // Navigation URL or epub download URL std::string id; }; // Legacy alias for backward compatibility using OpdsBook = OpdsEntry; /** * Parser for OPDS (Open Publication Distribution System) Atom feeds. * Uses the Expat XML parser to parse OPDS catalog entries. * * Usage: * OpdsParser parser; * if (parser.parse(xmlData, xmlLength)) { * for (const auto& entry : parser.getEntries()) { * if (entry.type == OpdsEntryType::BOOK) { * // Downloadable book * } else { * // Navigation link to another catalog * } * } * } */ class OpdsParser final : public Print { public: OpdsParser(); ~OpdsParser(); // Disable copy OpdsParser(const OpdsParser&) = delete; OpdsParser& operator=(const OpdsParser&) = delete; size_t write(uint8_t) override; size_t write(const uint8_t*, size_t) override; void flush() override; bool error() const; operator bool() { return !error(); } /** * Get the parsed entries (both navigation and book entries). * @return Vector of OpdsEntry entries */ const std::vector& getEntries() const& { return entries; } std::vector getEntries() && { return std::move(entries); } /** * Get only book entries (legacy compatibility). * @return Vector of book entries */ std::vector getBooks() const; /** * Clear all parsed entries. */ void clear(); private: // Expat callbacks static void XMLCALL startElement(void* userData, const XML_Char* name, const XML_Char** atts); static void XMLCALL endElement(void* userData, const XML_Char* name); static void XMLCALL characterData(void* userData, const XML_Char* s, int len); // Helper to find attribute value static const char* findAttribute(const XML_Char** atts, const char* name); XML_Parser parser = nullptr; std::vector entries; OpdsEntry currentEntry; std::string currentText; // Parser state bool inEntry = false; bool inTitle = false; bool inAuthor = false; bool inAuthorName = false; bool inId = false; bool errorOccured = false; };