mirror of
https://github.com/pelgraine/Meck.git
synced 2026-08-07 09:12:44 +02:00
fixed epub processor so it renders " ' correctly
This commit is contained in:
@@ -547,6 +547,71 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle UTF-8 multi-byte sequences (smart quotes, em dashes, etc.)
|
||||||
|
// These appear as raw bytes in XHTML and must be mapped to ASCII
|
||||||
|
// since the e-ink font only supports ASCII characters.
|
||||||
|
if ((uint8_t)c >= 0xC0) {
|
||||||
|
uint32_t codepoint = 0;
|
||||||
|
int extraBytes = 0;
|
||||||
|
|
||||||
|
if (((uint8_t)c & 0xE0) == 0xC0) {
|
||||||
|
// 2-byte sequence: 110xxxxx 10xxxxxx
|
||||||
|
codepoint = (uint8_t)c & 0x1F;
|
||||||
|
extraBytes = 1;
|
||||||
|
} else if (((uint8_t)c & 0xF0) == 0xE0) {
|
||||||
|
// 3-byte sequence: 1110xxxx 10xxxxxx 10xxxxxx
|
||||||
|
codepoint = (uint8_t)c & 0x0F;
|
||||||
|
extraBytes = 2;
|
||||||
|
} else if (((uint8_t)c & 0xF8) == 0xF0) {
|
||||||
|
// 4-byte sequence: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
codepoint = (uint8_t)c & 0x07;
|
||||||
|
extraBytes = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read continuation bytes
|
||||||
|
bool valid = true;
|
||||||
|
for (int b = 0; b < extraBytes && p + 1 + b < end; b++) {
|
||||||
|
uint8_t cb = *(p + 1 + b);
|
||||||
|
if ((cb & 0xC0) != 0x80) { valid = false; break; }
|
||||||
|
codepoint = (codepoint << 6) | (cb & 0x3F);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid && extraBytes > 0) {
|
||||||
|
p += extraBytes; // Skip continuation bytes (loop increments past lead byte)
|
||||||
|
|
||||||
|
// Map Unicode codepoints to ASCII equivalents
|
||||||
|
char mapped = 0;
|
||||||
|
switch (codepoint) {
|
||||||
|
case 0x2018: case 0x2019: mapped = '\''; break; // Smart single quotes
|
||||||
|
case 0x201C: case 0x201D: mapped = '"'; break; // Smart double quotes
|
||||||
|
case 0x2013: case 0x2014: mapped = '-'; break; // En/em dash
|
||||||
|
case 0x2026: mapped = '.'; break; // Ellipsis
|
||||||
|
case 0x2022: mapped = '*'; break; // Bullet
|
||||||
|
case 0x00A0: mapped = ' '; break; // Non-breaking space
|
||||||
|
case 0x00AB: case 0x00BB: mapped = '"'; break; // Guillemets
|
||||||
|
case 0x2032: mapped = '\''; break; // Prime
|
||||||
|
case 0x2033: mapped = '"'; break; // Double prime
|
||||||
|
case 0x2010: case 0x2011: mapped = '-'; break; // Hyphens
|
||||||
|
case 0x2012: mapped = '-'; break; // Figure dash
|
||||||
|
case 0x2015: mapped = '-'; break; // Horizontal bar
|
||||||
|
case 0x2039: case 0x203A: mapped = '\''; break; // Single guillemets
|
||||||
|
default:
|
||||||
|
if (codepoint >= 0x20 && codepoint < 0x7F) {
|
||||||
|
mapped = (char)codepoint; // Basic ASCII range
|
||||||
|
} else {
|
||||||
|
continue; // Skip unmappable characters
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c = mapped;
|
||||||
|
} else {
|
||||||
|
continue; // Skip malformed UTF-8
|
||||||
|
}
|
||||||
|
} else if ((uint8_t)c >= 0x80) {
|
||||||
|
// Stray continuation byte (0x80-0xBF) — skip
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Whitespace collapsing
|
// Whitespace collapsing
|
||||||
if (c == '\n' || c == '\r') {
|
if (c == '\n' || c == '\r') {
|
||||||
if (!lastWasNewline && outPos > 0) {
|
if (!lastWasNewline && outPos > 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user