fixed wrong left padding in the books with different and sometimes wrong inner structure

This commit is contained in:
sergeych committed 2026-05-25 09:13:05 +03:00
1 parent 65925f2a07
commit 3e83185e4f
6 files changed
+204 -10

No files matched your search

@@ -6,6 +6,7 @@ internal object Fb2XmlEncoding {
fun decodeXml(bytes: ByteArray): String =
when (declaredEncoding(bytes)?.lowercase()) {
"windows-1251" -> decodeWindows1251(bytes)
"windows-1252" -> decodeWindows1252(bytes)
else -> bytes.decodeToString()
}
@@ -30,6 +31,12 @@ internal object Fb2XmlEncoding {
}
}
private fun decodeWindows1252(bytes: ByteArray): String = buildString(bytes.size) {
bytes.forEach { byte ->
append(windows1252Char(byte.toInt() and 0xff))
}
}
private fun windows1251Char(value: Int): Char =
when (value) {
in 0x00..0x7f -> value.toChar()
@@ -100,4 +107,43 @@ internal object Fb2XmlEncoding {
in 0xc0..0xff -> (0x0410 + value - 0xc0).toChar()
else -> '\uFFFD'
}
private fun windows1252Char(value: Int): Char =
when (value) {
in 0x00..0x7f -> value.toChar()
0x80 -> '\u20ac'
0x81 -> '\uFFFD'
0x82 -> '\u201a'
0x83 -> '\u0192'
0x84 -> '\u201e'
0x85 -> '\u2026'
0x86 -> '\u2020'
0x87 -> '\u2021'
0x88 -> '\u02c6'
0x89 -> '\u2030'
0x8a -> '\u0160'
0x8b -> '\u2039'
0x8c -> '\u0152'
0x8d -> '\uFFFD'
0x8e -> '\u017d'
0x8f -> '\uFFFD'
0x90 -> '\uFFFD'
0x91 -> '\u2018'
0x92 -> '\u2019'
0x93 -> '\u201c'
0x94 -> '\u201d'
0x95 -> '\u2022'
0x96 -> '\u2013'
0x97 -> '\u2014'
0x98 -> '\u02dc'
0x99 -> '\u2122'
0x9a -> '\u0161'
0x9b -> '\u203a'
0x9c -> '\u0153'
0x9d -> '\uFFFD'
0x9e -> '\u017e'
0x9f -> '\u0178'
in 0xa0..0xff -> value.toChar()
else -> '\uFFFD'
}
}
@@ -60,6 +60,23 @@ class Fb2FormatTest {
assertEquals("Привет, мир.", book.sections.single().paragraphs.single())
}
@Test
fun parsesWindows1252PlainXml() {
val book = Fb2Format.parse(windows1252Xml.encodeWindows1252(), "legacy.fb2")
assertEquals("The “Test” Book", book.title)
assertEquals("It’s 25€ for café — OK.", book.sections.single().paragraphs.single())
}
@Test
fun parsesWindows1252StoredZip() {
val zip = Fb2Zip.createStoredZip("legacy.fb2", windows1252Xml.encodeWindows1252())
val book = Fb2Format.parse(zip, "legacy.fb2.zip")
assertEquals("The “Test” Book", book.title)
assertEquals("It’s 25€ for café — OK.", book.sections.single().paragraphs.single())
}
@Test
fun fallsBackToUtf8ForUnknownEncoding() {
val xml = sampleXml.replace("encoding=\"UTF-8\"", "encoding=\"KOI8-R\"")
@@ -273,6 +290,26 @@ class Fb2FormatTest {
</FictionBook>
""".trimIndent()
private val windows1252Xml = """
<?xml version="1.0" encoding="windows-1252"?>
<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:xlink="http://www.w3.org/1999/xlink">
<description>
<title-info>
<author><nickname>Author</nickname></author>
<book-title>The “Test” Book</book-title>
<lang>en</lang>
</title-info>
<document-info>
<author><nickname>Toread</nickname></author>
<date>2026-05-12</date>
<id>legacy-1252</id>
<version>1.0</version>
</document-info>
</description>
<body><section><p>It’s 25€ for café — OK.</p></section></body>
</FictionBook>
""".trimIndent()
private val notesXml = """
<?xml version="1.0" encoding="UTF-8"?>
<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink">
@@ -314,4 +351,23 @@ class Fb2FormatTest {
}
value.toByte()
}
private fun String.encodeWindows1252(): ByteArray =
ByteArray(length) { index ->
val char = this[index]
val value = when {
char.code <= 0x7f -> char.code
char.code in 0xa0..0xff -> char.code
char == '€' -> 0x80
char == '‘' -> 0x91
char == '’' -> 0x92
char == '“' -> 0x93
char == '”' -> 0x94
char == '–' -> 0x96
char == '—' -> 0x97
char == '™' -> 0x99
else -> error("Test character $char is not mapped to windows-1252")
}
value.toByte()
}
}