fix: Erroneous navigation with long filenames in footnote links (#1723)

## Summary

* **What is the goal of this PR?** 
* Increase the allowed link length for footnotes
* **What changes are included?** 
* Un-magic-numbers parts of the footnote parser
* Increases max href length

## Additional Context

* Additional RAM usage was not noticable to me, worst case 16 * 128 * 2
= 4KB instead of previously 16 * 88 * 2 ~ 2.8KB, see #1031
* Motivation: My book navigated me to the start of the footnote chapter,
which required manual navigating for every footnote due to ungodly file
name choices which pushed the required href length to 72, which caused
truncating, which caused Crosspoint to not find the anchor (Sacred and
Terrible Air, available via reddit)

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
This commit is contained in:
CSCMe
2026-04-21 18:34:17 +03:00
committed by GitHub
parent 56d3ab929c
commit 8154f88dbe
4 changed files with 16 additions and 14 deletions
+5 -2
View File
@@ -2,9 +2,12 @@
#include <cstring>
#define FOOTNOTE_NUMBER_LEN 32
#define FOOTNOTE_HREF_LEN 96
struct FootnoteEntry {
char number[24];
char href[64];
char number[FOOTNOTE_NUMBER_LEN];
char href[FOOTNOTE_HREF_LEN];
FootnoteEntry() {
number[0] = '\0';
+1 -1
View File
@@ -10,7 +10,7 @@
#include "parsers/ChapterHtmlSlimParser.h"
namespace {
constexpr uint8_t SECTION_FILE_VERSION = 20;
constexpr uint8_t SECTION_FILE_VERSION = 21;
constexpr uint32_t HEADER_SIZE = sizeof(uint8_t) + sizeof(int) + sizeof(float) + sizeof(bool) + sizeof(uint8_t) +
sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(bool) + sizeof(bool) +
sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t);
@@ -539,9 +539,9 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
}
self->insideFootnoteLink = true;
self->footnoteLinkDepth = self->depth;
strncpy(self->currentFootnoteLinkHref, href, sizeof(self->currentFootnoteLinkHref) - 1);
self->currentFootnoteLinkHref[sizeof(self->currentFootnoteLinkHref) - 1] = '\0';
self->currentFootnoteLinkText[0] = '\0';
strncpy(self->currentFootnote.href, href, sizeof(self->currentFootnote.href) - 1);
self->currentFootnote.href[sizeof(self->currentFootnote.href) - 1] = '\0';
self->currentFootnote.number[0] = '\0';
self->currentFootnoteLinkTextLen = 0;
// Apply underline style to visually indicate the link
@@ -720,11 +720,11 @@ void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char
}
// Extract footnote link text
for (int i = start; (self->currentFootnoteLinkTextLen < sizeof(self->currentFootnoteLinkText) - 1) && (i <= end);
for (int i = start; (self->currentFootnoteLinkTextLen < sizeof(self->currentFootnote.number) - 1) && (i <= end);
++i) {
self->currentFootnoteLinkText[self->currentFootnoteLinkTextLen++] = s[i];
self->currentFootnote.number[self->currentFootnoteLinkTextLen++] = s[i];
}
self->currentFootnoteLinkText[self->currentFootnoteLinkTextLen] = '\0';
self->currentFootnote.number[self->currentFootnoteLinkTextLen] = '\0';
}
for (int i = 0; i < len; i++) {
@@ -915,11 +915,11 @@ void XMLCALL ChapterHtmlSlimParser::endElement(void* userData, const XML_Char* n
// Closing a footnote link — create entry from collected text and href
if (self->insideFootnoteLink && self->depth == self->footnoteLinkDepth) {
if (self->currentFootnoteLinkText[0] != '\0' && self->currentFootnoteLinkHref[0] != '\0') {
if (self->currentFootnote.number[0] != '\0' && self->currentFootnote.href[0] != '\0') {
FootnoteEntry entry;
strncpy(entry.number, self->currentFootnoteLinkText, sizeof(entry.number) - 1);
strncpy(entry.number, self->currentFootnote.number, sizeof(entry.number) - 1);
entry.number[sizeof(entry.number) - 1] = '\0';
strncpy(entry.href, self->currentFootnoteLinkHref, sizeof(entry.href) - 1);
strncpy(entry.href, self->currentFootnote.href, sizeof(entry.href) - 1);
entry.href[sizeof(entry.href) - 1] = '\0';
int wordIndex =
self->wordsExtractedInBlock + (self->currentTextBlock ? static_cast<int>(self->currentTextBlock->size()) : 0);
@@ -79,9 +79,8 @@ class ChapterHtmlSlimParser {
// Footnote link tracking
bool insideFootnoteLink = false;
int footnoteLinkDepth = -1;
char currentFootnoteLinkText[24] = {};
FootnoteEntry currentFootnote = {};
int currentFootnoteLinkTextLen = 0;
char currentFootnoteLinkHref[64] = {};
std::vector<std::pair<int, FootnoteEntry>> pendingFootnotes; // <wordIndex, entry>
int wordsExtractedInBlock = 0;