From d34aea63785d3efdd77b30b7ecd164a439bf3912 Mon Sep 17 00:00:00 2001 From: Konstantin Vukolov Date: Sat, 17 Jan 2026 01:32:59 +0300 Subject: [PATCH 1/8] Fix OPDS browser OOM --- lib/OpdsParser/OpdsParser.cpp | 44 ++++++++++++------- lib/OpdsParser/OpdsParser.h | 17 ++++--- lib/OpdsParser/OpdsStream.cpp | 30 +++++++++++++ lib/OpdsParser/OpdsStream.h | 23 ++++++++++ .../browser/OpdsBookBrowserActivity.cpp | 25 +++++++---- src/network/HttpDownloader.cpp | 18 ++++++-- src/network/HttpDownloader.h | 2 + 7 files changed, 121 insertions(+), 38 deletions(-) create mode 100644 lib/OpdsParser/OpdsStream.cpp create mode 100644 lib/OpdsParser/OpdsStream.h diff --git a/lib/OpdsParser/OpdsParser.cpp b/lib/OpdsParser/OpdsParser.cpp index da4042f0..77a1c055 100644 --- a/lib/OpdsParser/OpdsParser.cpp +++ b/lib/OpdsParser/OpdsParser.cpp @@ -4,6 +4,14 @@ #include +OpdsParser::OpdsParser() { + parser = XML_ParserCreate(nullptr); + if (!parser) { + errorOccured = true; + Serial.printf("[%lu] [OPDS] Couldn't allocate memory for parser\n", millis()); + } +} + OpdsParser::~OpdsParser() { if (parser) { XML_StopParser(parser, XML_FALSE); @@ -14,14 +22,10 @@ OpdsParser::~OpdsParser() { } } -bool OpdsParser::parse(const char* xmlData, const size_t length) { - clear(); - - parser = XML_ParserCreate(nullptr); - if (!parser) { - Serial.printf("[%lu] [OPDS] Couldn't allocate memory for parser\n", millis()); - return false; - } +void OpdsParser::push(const char* xmlData, const size_t length) { + if (errorOccured) { + return; + } XML_SetUserData(parser, this); XML_SetElementHandler(parser, startElement, endElement); @@ -35,34 +39,40 @@ bool OpdsParser::parse(const char* xmlData, const size_t length) { while (remaining > 0) { void* const buf = XML_GetBuffer(parser, chunkSize); if (!buf) { + errorOccured = true; Serial.printf("[%lu] [OPDS] Couldn't allocate memory for buffer\n", millis()); XML_ParserFree(parser); parser = nullptr; - return false; + return; } const size_t toRead = remaining < chunkSize ? remaining : chunkSize; memcpy(buf, currentPos, toRead); - const bool isFinal = (remaining == toRead); - if (XML_ParseBuffer(parser, static_cast(toRead), isFinal) == XML_STATUS_ERROR) { + if (XML_ParseBuffer(parser, static_cast(toRead), 0) == XML_STATUS_ERROR) { + errorOccured = true; Serial.printf("[%lu] [OPDS] Parse error at line %lu: %s\n", millis(), XML_GetCurrentLineNumber(parser), XML_ErrorString(XML_GetErrorCode(parser))); XML_ParserFree(parser); parser = nullptr; - return false; + return; } currentPos += toRead; remaining -= toRead; } +} - // Clean up parser - XML_ParserFree(parser); - parser = nullptr; +void OpdsParser::finish() { + if (XML_Parse(parser, nullptr, 0, XML_TRUE) != XML_STATUS_OK) { + errorOccured = true; + XML_ParserFree(parser); + parser = nullptr; + } +} - Serial.printf("[%lu] [OPDS] Parsed %zu entries\n", millis(), entries.size()); - return true; +bool OpdsParser::error() const { + return errorOccured; } void OpdsParser::clear() { diff --git a/lib/OpdsParser/OpdsParser.h b/lib/OpdsParser/OpdsParser.h index acb4b694..93d310a9 100644 --- a/lib/OpdsParser/OpdsParser.h +++ b/lib/OpdsParser/OpdsParser.h @@ -44,26 +44,23 @@ using OpdsBook = OpdsEntry; */ class OpdsParser { public: - OpdsParser() = default; + OpdsParser(); ~OpdsParser(); // Disable copy OpdsParser(const OpdsParser&) = delete; OpdsParser& operator=(const OpdsParser&) = delete; - /** - * Parse an OPDS XML feed. - * @param xmlData Pointer to the XML data - * @param length Length of the XML data - * @return true if parsing succeeded, false on error - */ - bool parse(const char* xmlData, size_t length); + void push(const char* xmlData, size_t length); + void finish(); + bool error() const; /** * Get the parsed entries (both navigation and book entries). * @return Vector of OpdsEntry entries */ - const std::vector& getEntries() const { return entries; } + const std::vector& getEntries() const & { return entries; } + std::vector getEntries() && { return std::move(entries); } /** * Get only book entries (legacy compatibility). @@ -96,4 +93,6 @@ class OpdsParser { bool inAuthor = false; bool inAuthorName = false; bool inId = false; + + bool errorOccured = false; }; diff --git a/lib/OpdsParser/OpdsStream.cpp b/lib/OpdsParser/OpdsStream.cpp new file mode 100644 index 00000000..d23405f2 --- /dev/null +++ b/lib/OpdsParser/OpdsStream.cpp @@ -0,0 +1,30 @@ +#include "OpdsStream.h" + +OpdsParserStream::OpdsParserStream(OpdsParser& parser) : parser(parser) {} + + +int OpdsParserStream::available() { + return 0; +} + +int OpdsParserStream::peek() { + abort(); +} + +int OpdsParserStream::read() { + abort(); +} + +size_t OpdsParserStream::write(uint8_t c) { + parser.push(reinterpret_cast(&c), 1); + return 1; +} + +size_t OpdsParserStream::write(const uint8_t *buffer, size_t size) { + parser.push(reinterpret_cast(buffer), size); + return size; +} + +OpdsParserStream::~OpdsParserStream() { + parser.finish(); +} diff --git a/lib/OpdsParser/OpdsStream.h b/lib/OpdsParser/OpdsStream.h new file mode 100644 index 00000000..184ae1f0 --- /dev/null +++ b/lib/OpdsParser/OpdsStream.h @@ -0,0 +1,23 @@ +#pragma once + +#include "OpdsParser.h" + +#include + +class OpdsParserStream : public Stream { +public: + OpdsParserStream(OpdsParser& parser); + + // That functions are not implimented for that stream + int available() override; + int peek() override; + int read() override; + + virtual size_t write(uint8_t c) override; + virtual size_t write(const uint8_t *buffer, size_t size) override; + + ~OpdsParserStream() override; + +private: + OpdsParser& parser; +}; diff --git a/src/activities/browser/OpdsBookBrowserActivity.cpp b/src/activities/browser/OpdsBookBrowserActivity.cpp index 4e0a08d2..4a33baf6 100644 --- a/src/activities/browser/OpdsBookBrowserActivity.cpp +++ b/src/activities/browser/OpdsBookBrowserActivity.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include "CrossPointSettings.h" #include "MappedInputManager.h" #include "ScreenComponents.h" @@ -264,23 +266,28 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) { std::string url = UrlUtils::buildUrl(serverUrl, path); Serial.printf("[%lu] [OPDS] Fetching: %s\n", millis(), url.c_str()); - std::string content; - if (!HttpDownloader::fetchUrl(url, content)) { - state = BrowserState::ERROR; - errorMessage = "Failed to fetch feed"; - updateRequired = true; - return; + OpdsParser parser; + + { + OpdsParserStream stream{parser}; + if (!HttpDownloader::fetchUrl(url, stream)) { + state = BrowserState::ERROR; + errorMessage = "Failed to fetch feed"; + updateRequired = true; + return; + } } - OpdsParser parser; - if (!parser.parse(content.c_str(), content.size())) { + + if (parser.error()) { state = BrowserState::ERROR; errorMessage = "Failed to parse feed"; updateRequired = true; return; } - entries = parser.getEntries(); + entries = std::move(parser).getEntries(); + Serial.printf("[%lu] [OPDS] Found %d entries\n", millis(), entries.size()); selectorIndex = 0; if (entries.empty()) { diff --git a/src/network/HttpDownloader.cpp b/src/network/HttpDownloader.cpp index c4de3a05..93826976 100644 --- a/src/network/HttpDownloader.cpp +++ b/src/network/HttpDownloader.cpp @@ -5,11 +5,13 @@ #include #include +#include + #include #include "util/UrlUtils.h" -bool HttpDownloader::fetchUrl(const std::string& url, std::string& outContent) { +bool HttpDownloader::fetchUrl(const std::string& url, Stream& outContent) { // Use WiFiClientSecure for HTTPS, regular WiFiClient for HTTP std::unique_ptr client; if (UrlUtils::isHttpsUrl(url)) { @@ -34,10 +36,20 @@ bool HttpDownloader::fetchUrl(const std::string& url, std::string& outContent) { return false; } - outContent = http.getString().c_str(); + http.writeToStream(&outContent); + http.end(); - Serial.printf("[%lu] [HTTP] Fetched %zu bytes\n", millis(), outContent.size()); + Serial.printf("[%lu] [HTTP] Fetch success\n", millis()); + return true; +} + +bool HttpDownloader::fetchUrl(const std::string& url, std::string& outContent) { + StreamString stream; + if (!fetchUrl(url, stream)) { + return false; + } + outContent = stream.c_str(); return true; } diff --git a/src/network/HttpDownloader.h b/src/network/HttpDownloader.h index e6e0f163..ac520a42 100644 --- a/src/network/HttpDownloader.h +++ b/src/network/HttpDownloader.h @@ -27,6 +27,8 @@ class HttpDownloader { */ static bool fetchUrl(const std::string& url, std::string& outContent); + static bool fetchUrl(const std::string& url, Stream& stream); + /** * Download a file to the SD card. * @param url The URL to download From a89a33b595ae5648a4a26382f49df32c100c0b59 Mon Sep 17 00:00:00 2001 From: Konstantin Vukolov Date: Sat, 17 Jan 2026 01:41:51 +0300 Subject: [PATCH 2/8] Fix check --- lib/OpdsParser/OpdsStream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/OpdsParser/OpdsStream.h b/lib/OpdsParser/OpdsStream.h index 184ae1f0..2b234e33 100644 --- a/lib/OpdsParser/OpdsStream.h +++ b/lib/OpdsParser/OpdsStream.h @@ -6,7 +6,7 @@ class OpdsParserStream : public Stream { public: - OpdsParserStream(OpdsParser& parser); + explicit OpdsParserStream(OpdsParser& parser); // That functions are not implimented for that stream int available() override; From 5cd56af350f58339e6fe83a7d034353dfc034922 Mon Sep 17 00:00:00 2001 From: Konstantin Vukolov Date: Sat, 17 Jan 2026 01:46:52 +0300 Subject: [PATCH 3/8] Fix format --- lib/OpdsParser/OpdsParser.cpp | 20 +++++++------- lib/OpdsParser/OpdsParser.h | 2 +- lib/OpdsParser/OpdsStream.cpp | 27 +++++++------------ lib/OpdsParser/OpdsStream.h | 26 +++++++++--------- .../browser/OpdsBookBrowserActivity.cpp | 18 ++++++------- src/network/HttpDownloader.cpp | 3 +-- 6 files changed, 41 insertions(+), 55 deletions(-) diff --git a/lib/OpdsParser/OpdsParser.cpp b/lib/OpdsParser/OpdsParser.cpp index 77a1c055..c95d2951 100644 --- a/lib/OpdsParser/OpdsParser.cpp +++ b/lib/OpdsParser/OpdsParser.cpp @@ -23,9 +23,9 @@ OpdsParser::~OpdsParser() { } void OpdsParser::push(const char* xmlData, const size_t length) { - if (errorOccured) { - return; - } + if (errorOccured) { + return; + } XML_SetUserData(parser, this); XML_SetElementHandler(parser, startElement, endElement); @@ -64,16 +64,14 @@ void OpdsParser::push(const char* xmlData, const size_t length) { } void OpdsParser::finish() { - if (XML_Parse(parser, nullptr, 0, XML_TRUE) != XML_STATUS_OK) { - errorOccured = true; - XML_ParserFree(parser); - parser = nullptr; - } + if (XML_Parse(parser, nullptr, 0, XML_TRUE) != XML_STATUS_OK) { + errorOccured = true; + XML_ParserFree(parser); + parser = nullptr; + } } -bool OpdsParser::error() const { - return errorOccured; -} +bool OpdsParser::error() const { return errorOccured; } void OpdsParser::clear() { entries.clear(); diff --git a/lib/OpdsParser/OpdsParser.h b/lib/OpdsParser/OpdsParser.h index 93d310a9..5d508366 100644 --- a/lib/OpdsParser/OpdsParser.h +++ b/lib/OpdsParser/OpdsParser.h @@ -59,7 +59,7 @@ class OpdsParser { * Get the parsed entries (both navigation and book entries). * @return Vector of OpdsEntry entries */ - const std::vector& getEntries() const & { return entries; } + const std::vector& getEntries() const& { return entries; } std::vector getEntries() && { return std::move(entries); } /** diff --git a/lib/OpdsParser/OpdsStream.cpp b/lib/OpdsParser/OpdsStream.cpp index d23405f2..68a2676b 100644 --- a/lib/OpdsParser/OpdsStream.cpp +++ b/lib/OpdsParser/OpdsStream.cpp @@ -2,29 +2,20 @@ OpdsParserStream::OpdsParserStream(OpdsParser& parser) : parser(parser) {} +int OpdsParserStream::available() { return 0; } -int OpdsParserStream::available() { - return 0; -} +int OpdsParserStream::peek() { abort(); } -int OpdsParserStream::peek() { - abort(); -} - -int OpdsParserStream::read() { - abort(); -} +int OpdsParserStream::read() { abort(); } size_t OpdsParserStream::write(uint8_t c) { - parser.push(reinterpret_cast(&c), 1); - return 1; + parser.push(reinterpret_cast(&c), 1); + return 1; } -size_t OpdsParserStream::write(const uint8_t *buffer, size_t size) { - parser.push(reinterpret_cast(buffer), size); - return size; +size_t OpdsParserStream::write(const uint8_t* buffer, size_t size) { + parser.push(reinterpret_cast(buffer), size); + return size; } -OpdsParserStream::~OpdsParserStream() { - parser.finish(); -} +OpdsParserStream::~OpdsParserStream() { parser.finish(); } diff --git a/lib/OpdsParser/OpdsStream.h b/lib/OpdsParser/OpdsStream.h index 2b234e33..c72f2b6b 100644 --- a/lib/OpdsParser/OpdsStream.h +++ b/lib/OpdsParser/OpdsStream.h @@ -1,23 +1,23 @@ #pragma once -#include "OpdsParser.h" - #include +#include "OpdsParser.h" + class OpdsParserStream : public Stream { -public: - explicit OpdsParserStream(OpdsParser& parser); + public: + explicit OpdsParserStream(OpdsParser& parser); - // That functions are not implimented for that stream - int available() override; - int peek() override; - int read() override; + // That functions are not implimented for that stream + int available() override; + int peek() override; + int read() override; - virtual size_t write(uint8_t c) override; - virtual size_t write(const uint8_t *buffer, size_t size) override; + virtual size_t write(uint8_t c) override; + virtual size_t write(const uint8_t* buffer, size_t size) override; - ~OpdsParserStream() override; + ~OpdsParserStream() override; -private: - OpdsParser& parser; + private: + OpdsParser& parser; }; diff --git a/src/activities/browser/OpdsBookBrowserActivity.cpp b/src/activities/browser/OpdsBookBrowserActivity.cpp index 4a33baf6..104eaac0 100644 --- a/src/activities/browser/OpdsBookBrowserActivity.cpp +++ b/src/activities/browser/OpdsBookBrowserActivity.cpp @@ -2,9 +2,8 @@ #include #include -#include - #include +#include #include "CrossPointSettings.h" #include "MappedInputManager.h" @@ -269,16 +268,15 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) { OpdsParser parser; { - OpdsParserStream stream{parser}; - if (!HttpDownloader::fetchUrl(url, stream)) { - state = BrowserState::ERROR; - errorMessage = "Failed to fetch feed"; - updateRequired = true; - return; - } + OpdsParserStream stream{parser}; + if (!HttpDownloader::fetchUrl(url, stream)) { + state = BrowserState::ERROR; + errorMessage = "Failed to fetch feed"; + updateRequired = true; + return; + } } - if (parser.error()) { state = BrowserState::ERROR; errorMessage = "Failed to parse feed"; diff --git a/src/network/HttpDownloader.cpp b/src/network/HttpDownloader.cpp index 93826976..fe65ea6b 100644 --- a/src/network/HttpDownloader.cpp +++ b/src/network/HttpDownloader.cpp @@ -2,11 +2,10 @@ #include #include +#include #include #include -#include - #include #include "util/UrlUtils.h" From c22a2b56fbe1fcbe751e46070fb43943d7d8d690 Mon Sep 17 00:00:00 2001 From: Konstantin Vukolov Date: Tue, 20 Jan 2026 16:27:45 +0300 Subject: [PATCH 4/8] Change opds parser interface --- lib/OpdsParser/OpdsParser.cpp | 17 +++++++++++------ lib/OpdsParser/OpdsParser.h | 14 +++++++++++--- lib/OpdsParser/OpdsStream.cpp | 8 +++----- .../browser/OpdsBookBrowserActivity.cpp | 4 ++-- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/lib/OpdsParser/OpdsParser.cpp b/lib/OpdsParser/OpdsParser.cpp index c95d2951..7c3f3091 100644 --- a/lib/OpdsParser/OpdsParser.cpp +++ b/lib/OpdsParser/OpdsParser.cpp @@ -22,9 +22,14 @@ OpdsParser::~OpdsParser() { } } -void OpdsParser::push(const char* xmlData, const size_t length) { +size_t OpdsParser::write(uint8_t c) { + return write(&c, 1); +} + +size_t OpdsParser::write(const uint8_t* xmlData, const size_t length) { + Serial.printf("Got %d bytes to parse\n", length); if (errorOccured) { - return; + return length; } XML_SetUserData(parser, this); @@ -32,7 +37,7 @@ void OpdsParser::push(const char* xmlData, const size_t length) { XML_SetCharacterDataHandler(parser, characterData); // Parse in chunks to avoid large buffer allocations - const char* currentPos = xmlData; + const char* currentPos = reinterpret_cast(xmlData); size_t remaining = length; constexpr size_t chunkSize = 1024; @@ -43,7 +48,7 @@ void OpdsParser::push(const char* xmlData, const size_t length) { Serial.printf("[%lu] [OPDS] Couldn't allocate memory for buffer\n", millis()); XML_ParserFree(parser); parser = nullptr; - return; + return length; } const size_t toRead = remaining < chunkSize ? remaining : chunkSize; @@ -55,7 +60,7 @@ void OpdsParser::push(const char* xmlData, const size_t length) { XML_ErrorString(XML_GetErrorCode(parser))); XML_ParserFree(parser); parser = nullptr; - return; + return length; } currentPos += toRead; @@ -63,7 +68,7 @@ void OpdsParser::push(const char* xmlData, const size_t length) { } } -void OpdsParser::finish() { +void OpdsParser::flush() { if (XML_Parse(parser, nullptr, 0, XML_TRUE) != XML_STATUS_OK) { errorOccured = true; XML_ParserFree(parser); diff --git a/lib/OpdsParser/OpdsParser.h b/lib/OpdsParser/OpdsParser.h index 5d508366..aa898f7a 100644 --- a/lib/OpdsParser/OpdsParser.h +++ b/lib/OpdsParser/OpdsParser.h @@ -3,6 +3,7 @@ #include #include +#include "Print.h" /** * Type of OPDS entry. @@ -42,7 +43,7 @@ using OpdsBook = OpdsEntry; * } * } */ -class OpdsParser { +class OpdsParser final : public Print { public: OpdsParser(); ~OpdsParser(); @@ -51,10 +52,17 @@ class OpdsParser { OpdsParser(const OpdsParser&) = delete; OpdsParser& operator=(const OpdsParser&) = delete; - void push(const char* xmlData, size_t length); - void finish(); + 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 diff --git a/lib/OpdsParser/OpdsStream.cpp b/lib/OpdsParser/OpdsStream.cpp index 68a2676b..8fa9a0e2 100644 --- a/lib/OpdsParser/OpdsStream.cpp +++ b/lib/OpdsParser/OpdsStream.cpp @@ -9,13 +9,11 @@ int OpdsParserStream::peek() { abort(); } int OpdsParserStream::read() { abort(); } size_t OpdsParserStream::write(uint8_t c) { - parser.push(reinterpret_cast(&c), 1); - return 1; + return parser.write(c); } size_t OpdsParserStream::write(const uint8_t* buffer, size_t size) { - parser.push(reinterpret_cast(buffer), size); - return size; + return parser.write(buffer, size); } -OpdsParserStream::~OpdsParserStream() { parser.finish(); } +OpdsParserStream::~OpdsParserStream() { parser.flush(); } diff --git a/src/activities/browser/OpdsBookBrowserActivity.cpp b/src/activities/browser/OpdsBookBrowserActivity.cpp index 104eaac0..8eb83aad 100644 --- a/src/activities/browser/OpdsBookBrowserActivity.cpp +++ b/src/activities/browser/OpdsBookBrowserActivity.cpp @@ -17,7 +17,7 @@ namespace { constexpr int PAGE_ITEMS = 23; constexpr int SKIP_PAGE_MS = 700; -constexpr char OPDS_ROOT_PATH[] = "opds"; // No leading slash - relative to server URL +constexpr char OPDS_ROOT_PATH[] = "api/opds/c7f8522c-5539-4f60-b978-3626a33245b6"; // No leading slash - relative to server URL } // namespace void OpdsBookBrowserActivity::taskTrampoline(void* param) { @@ -277,7 +277,7 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) { } } - if (parser.error()) { + if (!parser) { state = BrowserState::ERROR; errorMessage = "Failed to parse feed"; updateRequired = true; From 1bcc9068c15886e1daa897d22f86ec570331974d Mon Sep 17 00:00:00 2001 From: Konstantin Vukolov Date: Wed, 21 Jan 2026 15:11:26 +0300 Subject: [PATCH 5/8] Fix --- lib/OpdsParser/OpdsParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/OpdsParser/OpdsParser.cpp b/lib/OpdsParser/OpdsParser.cpp index 7c3f3091..67300607 100644 --- a/lib/OpdsParser/OpdsParser.cpp +++ b/lib/OpdsParser/OpdsParser.cpp @@ -27,7 +27,6 @@ size_t OpdsParser::write(uint8_t c) { } size_t OpdsParser::write(const uint8_t* xmlData, const size_t length) { - Serial.printf("Got %d bytes to parse\n", length); if (errorOccured) { return length; } @@ -66,6 +65,7 @@ size_t OpdsParser::write(const uint8_t* xmlData, const size_t length) { currentPos += toRead; remaining -= toRead; } + return length; } void OpdsParser::flush() { From a4242ab11e7c638eced644e5109e50170b25ed08 Mon Sep 17 00:00:00 2001 From: Konstantin Vukolov Date: Wed, 21 Jan 2026 15:13:26 +0300 Subject: [PATCH 6/8] Fix style --- lib/OpdsParser/OpdsParser.cpp | 4 +--- lib/OpdsParser/OpdsParser.h | 5 ++--- lib/OpdsParser/OpdsStream.cpp | 8 ++------ src/activities/browser/OpdsBookBrowserActivity.cpp | 2 +- 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/lib/OpdsParser/OpdsParser.cpp b/lib/OpdsParser/OpdsParser.cpp index 67300607..4b58d8f8 100644 --- a/lib/OpdsParser/OpdsParser.cpp +++ b/lib/OpdsParser/OpdsParser.cpp @@ -22,9 +22,7 @@ OpdsParser::~OpdsParser() { } } -size_t OpdsParser::write(uint8_t c) { - return write(&c, 1); -} +size_t OpdsParser::write(uint8_t c) { return write(&c, 1); } size_t OpdsParser::write(const uint8_t* xmlData, const size_t length) { if (errorOccured) { diff --git a/lib/OpdsParser/OpdsParser.h b/lib/OpdsParser/OpdsParser.h index aa898f7a..05ebd582 100644 --- a/lib/OpdsParser/OpdsParser.h +++ b/lib/OpdsParser/OpdsParser.h @@ -3,6 +3,7 @@ #include #include + #include "Print.h" /** @@ -59,9 +60,7 @@ class OpdsParser final : public Print { bool error() const; - operator bool() { - return !error(); - } + operator bool() { return !error(); } /** * Get the parsed entries (both navigation and book entries). diff --git a/lib/OpdsParser/OpdsStream.cpp b/lib/OpdsParser/OpdsStream.cpp index 8fa9a0e2..742624a8 100644 --- a/lib/OpdsParser/OpdsStream.cpp +++ b/lib/OpdsParser/OpdsStream.cpp @@ -8,12 +8,8 @@ int OpdsParserStream::peek() { abort(); } int OpdsParserStream::read() { abort(); } -size_t OpdsParserStream::write(uint8_t c) { - return parser.write(c); -} +size_t OpdsParserStream::write(uint8_t c) { return parser.write(c); } -size_t OpdsParserStream::write(const uint8_t* buffer, size_t size) { - return parser.write(buffer, size); -} +size_t OpdsParserStream::write(const uint8_t* buffer, size_t size) { return parser.write(buffer, size); } OpdsParserStream::~OpdsParserStream() { parser.flush(); } diff --git a/src/activities/browser/OpdsBookBrowserActivity.cpp b/src/activities/browser/OpdsBookBrowserActivity.cpp index 8eb83aad..62555aa8 100644 --- a/src/activities/browser/OpdsBookBrowserActivity.cpp +++ b/src/activities/browser/OpdsBookBrowserActivity.cpp @@ -17,7 +17,7 @@ namespace { constexpr int PAGE_ITEMS = 23; constexpr int SKIP_PAGE_MS = 700; -constexpr char OPDS_ROOT_PATH[] = "api/opds/c7f8522c-5539-4f60-b978-3626a33245b6"; // No leading slash - relative to server URL +constexpr char OPDS_ROOT_PATH[] = "opds"; // No leading slash - relative to server URL } // namespace void OpdsBookBrowserActivity::taskTrampoline(void* param) { From 05d1a03fe44b63d97b0d360333b6d88c3c913a9a Mon Sep 17 00:00:00 2001 From: Konstantin Vukolov Date: Wed, 21 Jan 2026 15:19:31 +0300 Subject: [PATCH 7/8] Fix cppcheck --- lib/OpdsParser/OpdsParser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/OpdsParser/OpdsParser.h b/lib/OpdsParser/OpdsParser.h index 05ebd582..6ff873a9 100644 --- a/lib/OpdsParser/OpdsParser.h +++ b/lib/OpdsParser/OpdsParser.h @@ -4,7 +4,7 @@ #include #include -#include "Print.h" +#include /** * Type of OPDS entry. From 3a49a3d343a7733f6692ecf96be37e94b89a524a Mon Sep 17 00:00:00 2001 From: Konstantin Vukolov Date: Wed, 21 Jan 2026 15:25:06 +0300 Subject: [PATCH 8/8] Fix style --- lib/OpdsParser/OpdsParser.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/OpdsParser/OpdsParser.h b/lib/OpdsParser/OpdsParser.h index 6ff873a9..570ac4cc 100644 --- a/lib/OpdsParser/OpdsParser.h +++ b/lib/OpdsParser/OpdsParser.h @@ -1,11 +1,10 @@ #pragma once +#include #include #include #include -#include - /** * Type of OPDS entry. */