Function combination
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -374,24 +375,23 @@ void XMLCALL onDefaultHandlerExpand(void* userData, const XML_Char* text, const
|
|||||||
state->onCharacterData(text, len);
|
state->onCharacterData(text, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
// Parse one spine item and return a fully populated ParserState.
|
||||||
|
// Returns std::nullopt if validation, I/O, or XML parse fails.
|
||||||
std::string ChapterXPathIndexer::findXPathForProgress(const std::shared_ptr<Epub>& epub, const int spineIndex,
|
static std::optional<ParserState> parseSpineItem(const std::shared_ptr<Epub>& epub, const int spineIndex) {
|
||||||
const float intraSpineProgress) {
|
|
||||||
if (!epub || spineIndex < 0 || spineIndex >= epub->getSpineItemsCount()) {
|
if (!epub || spineIndex < 0 || spineIndex >= epub->getSpineItemsCount()) {
|
||||||
return "";
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto spineItem = epub->getSpineItem(spineIndex);
|
const auto spineItem = epub->getSpineItem(spineIndex);
|
||||||
if (spineItem.href.empty()) {
|
if (spineItem.href.empty()) {
|
||||||
return "";
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t chapterSize = 0;
|
size_t chapterSize = 0;
|
||||||
uint8_t* chapterBytes = epub->readItemContentsToBytes(spineItem.href, &chapterSize, false);
|
uint8_t* chapterBytes = epub->readItemContentsToBytes(spineItem.href, &chapterSize, false);
|
||||||
if (!chapterBytes || chapterSize == 0) {
|
if (!chapterBytes || chapterSize == 0) {
|
||||||
free(chapterBytes);
|
free(chapterBytes);
|
||||||
return "";
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParserState state(spineIndex);
|
ParserState state(spineIndex);
|
||||||
@@ -400,7 +400,7 @@ std::string ChapterXPathIndexer::findXPathForProgress(const std::shared_ptr<Epub
|
|||||||
if (!parser) {
|
if (!parser) {
|
||||||
free(chapterBytes);
|
free(chapterBytes);
|
||||||
LOG_ERR("KOX", "Failed to allocate XML parser for spine=%d", spineIndex);
|
LOG_ERR("KOX", "Failed to allocate XML parser for spine=%d", spineIndex);
|
||||||
return "";
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
XML_SetUserData(parser, &state);
|
XML_SetUserData(parser, &state);
|
||||||
@@ -420,12 +420,24 @@ std::string ChapterXPathIndexer::findXPathForProgress(const std::shared_ptr<Epub
|
|||||||
free(chapterBytes);
|
free(chapterBytes);
|
||||||
|
|
||||||
if (!parseOk) {
|
if (!parseOk) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::string ChapterXPathIndexer::findXPathForProgress(const std::shared_ptr<Epub>& epub, const int spineIndex,
|
||||||
|
const float intraSpineProgress) {
|
||||||
|
const auto state = parseSpineItem(epub, spineIndex);
|
||||||
|
if (!state) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string result = state.chooseXPath(intraSpineProgress);
|
const std::string result = state->chooseXPath(intraSpineProgress);
|
||||||
LOG_DBG("KOX", "Forward: spine=%d progress=%.3f anchors=%zu textBytes=%zu -> %s", spineIndex, intraSpineProgress,
|
LOG_DBG("KOX", "Forward: spine=%d progress=%.3f anchors=%zu textBytes=%zu -> %s", spineIndex, intraSpineProgress,
|
||||||
state.anchors.size(), state.totalTextBytes, result.c_str());
|
state->anchors.size(), state->totalTextBytes, result.c_str());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,53 +447,18 @@ bool ChapterXPathIndexer::findProgressForXPath(const std::shared_ptr<Epub>& epub
|
|||||||
outIntraSpineProgress = 0.0f;
|
outIntraSpineProgress = 0.0f;
|
||||||
outExactMatch = false;
|
outExactMatch = false;
|
||||||
|
|
||||||
if (!epub || spineIndex < 0 || spineIndex >= epub->getSpineItemsCount() || xpath.empty()) {
|
if (xpath.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto spineItem = epub->getSpineItem(spineIndex);
|
const auto state = parseSpineItem(epub, spineIndex);
|
||||||
if (spineItem.href.empty()) {
|
if (!state) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t chapterSize = 0;
|
LOG_DBG("KOX", "Reverse: spine=%d anchors=%zu textBytes=%zu for '%s'", spineIndex, state->anchors.size(),
|
||||||
uint8_t* chapterBytes = epub->readItemContentsToBytes(spineItem.href, &chapterSize, false);
|
state->totalTextBytes, xpath.c_str());
|
||||||
if (!chapterBytes || chapterSize == 0) {
|
return state->chooseProgressForXPath(xpath, outIntraSpineProgress, outExactMatch);
|
||||||
free(chapterBytes);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ParserState state(spineIndex);
|
|
||||||
XML_Parser parser = XML_ParserCreate(nullptr);
|
|
||||||
if (!parser) {
|
|
||||||
free(chapterBytes);
|
|
||||||
LOG_ERR("KOX", "Failed to allocate XML parser for reverse lookup spine=%d", spineIndex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
XML_SetUserData(parser, &state);
|
|
||||||
XML_SetElementHandler(parser, onStartElement, onEndElement);
|
|
||||||
XML_SetCharacterDataHandler(parser, onCharacterData);
|
|
||||||
XML_SetDefaultHandlerExpand(parser, onDefaultHandlerExpand);
|
|
||||||
|
|
||||||
const bool parseOk = XML_Parse(parser, reinterpret_cast<const char*>(chapterBytes), static_cast<int>(chapterSize),
|
|
||||||
XML_TRUE) != XML_STATUS_ERROR;
|
|
||||||
|
|
||||||
if (!parseOk) {
|
|
||||||
LOG_ERR("KOX", "Reverse XPath parse failed for spine=%d at line %lu: %s", spineIndex,
|
|
||||||
XML_GetCurrentLineNumber(parser), XML_ErrorString(XML_GetErrorCode(parser)));
|
|
||||||
}
|
|
||||||
|
|
||||||
XML_ParserFree(parser);
|
|
||||||
free(chapterBytes);
|
|
||||||
|
|
||||||
if (!parseOk) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DBG("KOX", "Reverse: spine=%d anchors=%zu textBytes=%zu for '%s'", spineIndex, state.anchors.size(),
|
|
||||||
state.totalTextBytes, xpath.c_str());
|
|
||||||
return state.chooseProgressForXPath(xpath, outIntraSpineProgress, outExactMatch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChapterXPathIndexer::tryExtractSpineIndexFromXPath(const std::string& xpath, int& outSpineIndex) {
|
bool ChapterXPathIndexer::tryExtractSpineIndexFromXPath(const std::string& xpath, int& outSpineIndex) {
|
||||||
|
|||||||
Reference in New Issue
Block a user