code wiki / _hdl_build / nx_book_mojibake_e2e_gate.nx

nx_book_mojibake_e2e_gate.nx source

↩ module page · 101 lines · 10141 B

1// nx_book_mojibake_e2e_gate.nx -- END-TO-END liar-kill gate for the library mojibake fix, through the REAL 2// compiled nx_epub_book.elf (not a unit). Builds a valid EPUB whose CHAPTER BODY + TITLE carry raw Windows-1252 3// bytes -- the curly apostrophe 0x92 ("there<0x92>s"), the em-dash 0x97 -- alongside a &#8217; numeric ref and a 4// GENUINE UTF-8 apostrophe (E2 80 99) to prove idempotency end-to-end. Runs the extractor, then reads the emitted 5// chap0.txt + book.json and asserts: the smart-punctuation arrived as clean UTF-8, NO raw 0x92/0x97 survived, and 6// NO U+FFFD (EF BF BD) was produced. This is the operator's exact "there<>s" bug, proven fixed on a real book. 7// Sovereign: opc_write builds the epub, fork/exec runs the extractor, no shell. expect_exit: 0 license_tier: ORIGINAL 8import "nx_syscalls.nx" 9import "nx_opc.nx" 10 11func e_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 12func e_n(v0: i64) -> i64 { var v: i64=v0; if v<0 { sys_write(1,"-" as *u8,1); v=0-v } let b: *u8=sys_mmap(24); var k: i64=0; if v==0 {b[0]=48 as u8;k=1} while v>0 {b[k]=(48+(v%10)) as u8; v=v/10; k=k+1} let o: *u8=sys_mmap(24); var j: i64=0; while j<k {o[j]=b[k-1-j];j=j+1} sys_write(1,o,k); return 0 } 13func e_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 14func ensure_dir(path: *u8) -> i64 { __syscall(258, 0-100, path, 0x1ed, 0, 0, 0); return 0 } 15 16// does buf[0..n) contain the 3-byte sequence a,b,c ? 17func has3(buf: *u8, n: i64, a: i64, b: i64, c: i64) -> i64 { 18 var i: i64 = 0 19 while i + 3 <= n { if (buf[i]&0xff)==a { if (buf[i+1]&0xff)==b { if (buf[i+2]&0xff)==c { return 1 } } } i = i + 1 } 20 return 0 21} 22// does buf[0..n) contain the single byte a ? 23func has1(buf: *u8, n: i64, a: i64) -> i64 { var i: i64=0; while i < n { if (buf[i]&0xff)==a { return 1 } i=i+1 } return 0 } 24 25// fork/exec extractor <path> <slug>, child output -> redir, wait, return child exit code. 26func run2(path: *u8, a0: *u8, a1: *u8, redir: *u8) -> i64 { 27 let pid: i64 = sys_fork() 28 if pid == 0 { 29 let fd: i64 = sys_openat_wr(redir, 420) 30 if fd >= 0 { sys_dup3(fd, 1, 0); sys_dup3(fd, 2, 0) } 31 let argv: *i64 = sys_mmap(64) as *i64 32 argv[0] = path as i64; argv[1] = a0 as i64; argv[2] = a1 as i64; argv[3] = 0 33 sys_execve(path, argv, 0 as *i64) 34 sys_exit(127) 35 } 36 let st: *i64 = sys_mmap(16) as *i64 37 sys_wait4(pid, st, 0) 38 return (st[0] >> 8) & 0xff 39} 40 41func main() -> i64 { 42 e_p("=== nx_book_mojibake_e2e_gate: real epub w/ stray CP1252 bytes -> nx_epub_book -> clean UTF-8 ===\n" as *u8) 43 ensure_dir("knowledge/fixtures" as *u8) 44 45 let names: *i64 = sys_mmap(8 * 8) as *i64 46 let datap: *i64 = sys_mmap(8 * 8) as *i64 47 let lens: *i64 = sys_mmap(8 * 8) as *i64 48 49 let mimetype: *u8 = "application/epub+zip" as *u8 50 let container: *u8 = "<?xml version=\"1.0\"?>\n<container version=\"1.0\" xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\">\n<rootfiles><rootfile full-path=\"OEBPS/content.opf\" media-type=\"application/oebps-package+xml\"/></rootfiles>\n</container>\n" as *u8 51 // TITLE carries a stray 0x92 ("Don<0x92>t Panic") -> proves er_wjson repairs metadata too. 52 let opf: *u8 = "<?xml version=\"1.0\"?>\n<package xmlns=\"http://www.idpf.org/2007/opf\" version=\"3.0\" unique-identifier=\"bookid\">\n<metadata xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n<dc:title>Don\x92t Panic</dc:title>\n<dc:creator>Caf\x92 Tester</dc:creator>\n<dc:identifier id=\"bookid\">moji-1</dc:identifier>\n</metadata>\n<manifest>\n<item id=\"ch1\" href=\"ch1.xhtml\" media-type=\"application/xhtml+xml\"/>\n</manifest>\n<spine>\n<itemref idref=\"ch1\"/>\n</spine>\n</package>\n" as *u8 53 // CHAPTER BODY: the reported "there<0x92>s"; an em-dash 0x97; a &#8217; numeric ref; a GENUINE UTF-8 ' (E2 80 99) 54 // for idempotency; plus enough public-domain prose to clear the extractor's 2000-char prose floor. 55 let ch1: *u8 = "<?xml version=\"1.0\"?>\n<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>One</title></head><body>\n<h1>The Curly Quote Test</h1>\n<p>So there\x92s the apostrophe, and here is an em \x97 dash, and an entity apostrophe&#8217;s tail, and a genuine pre-encoded \xe2\x80\x99 mark that must survive unchanged.</p>\n<p>Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, and what is the use of a book, thought Alice, without pictures or conversations? So she was considering in her own mind, as well as she could, for the hot day made her feel very sleepy and stupid, whether the pleasure of making a daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly a White Rabbit with pink eyes ran close by her. There was nothing so very remarkable in that; nor did Alice think it so very much out of the way to hear the Rabbit say to itself, oh dear, oh dear, I shall be late! When the Rabbit actually took a watch out of its waistcoat-pocket, and looked at it, and then hurried on, Alice started to her feet, for it flashed across her mind that she had never before seen a rabbit with either a waistcoat-pocket, or a watch to take out of it, and burning with curiosity, she ran across the field after it, and fortunately was just in time to see it pop down a large rabbit-hole under the hedge. In another moment down went Alice after it, never once considering how in the world she was to get out again.</p>\n<p>The rabbit-hole went straight on like a tunnel for some way, and then dipped suddenly down, so suddenly that Alice had not a moment to think about stopping herself before she found herself falling down what seemed to be a very deep well. Either the well was very deep, or she fell very slowly, for she had plenty of time as she went down to look about her, and to wonder what was going to happen next. First, she tried to look down and make out what she was coming to, but it was too dark to see anything; then she looked at the sides of the well, and noticed that they were filled with cupboards and book-shelves; here and there she saw maps and pictures hung upon pegs. She took down a jar from one of the shelves as she passed; it was labelled Orange Marmalade, but to her great disappointment it was empty: she did not like to drop the jar for fear of killing somebody underneath, so managed to put it into one of the cupboards as she fell past it.</p>\n</body></html>\n" as *u8 56 57 names[0] = ("mimetype" as *u8) as i64; datap[0] = mimetype as i64; lens[0] = e_slen(mimetype) 58 names[1] = ("META-INF/container.xml" as *u8) as i64; datap[1] = container as i64; lens[1] = e_slen(container) 59 names[2] = ("OEBPS/content.opf" as *u8) as i64; datap[2] = opf as i64; lens[2] = e_slen(opf) 60 names[3] = ("OEBPS/ch1.xhtml" as *u8) as i64; datap[3] = ch1 as i64; lens[3] = e_slen(ch1) 61 62 let w: i64 = opc_write("knowledge/fixtures/nishi_mojibake.epub" as *u8, names, datap, lens, 4) 63 if w <= 0 { e_p("E2E verdict=RED reason=fixture-write-fail\n" as *u8); sys_exit(1); return 1 } 64 e_p(" fixture epub bytes="); e_n(w); e_p("\n" as *u8) 65 66 // rebuild nx_epub_book first so this gate ALWAYS tests the current source (not a stale elf). 67 run2("_offc/nx_sov_build_run.elf\x00" as *u8, "nx_epub_book\x00" as *u8, 0 as *u8, "knowledge/status/mojibake_e2e_scratch.log\x00" as *u8) 68 let rc: i64 = run2("_offc/nx_epub_book.elf\x00" as *u8, "knowledge/fixtures/nishi_mojibake.epub\x00" as *u8, "mojibake_e2e\x00" as *u8, "knowledge/status/mojibake_e2e_scratch.log\x00" as *u8) 69 e_p(" nx_epub_book exit="); e_n(rc); e_p("\n" as *u8) 70 71 let lp: *i64 = sys_mmap(8) as *i64; lp[0] = 0 72 let chap: *u8 = sys_read_file("knowledge/staging/media/reader/mojibake_e2e/chap0.txt\x00" as *u8, lp) 73 if (chap as i64) == 0 { e_p("E2E verdict=RED reason=chap0-missing\n" as *u8); sys_exit(1); return 1 } 74 let cn: i64 = lp[0] 75 e_p(" chap0.txt bytes="); e_n(cn); e_p("\n" as *u8) 76 77 var pass: i64 = 0; var fail: i64 = 0 78 // apostrophe present as clean UTF-8 (E2 80 99) -- from 0x92, &#8217;, AND the genuine one 79 if has3(chap, cn, 0xe2, 0x80, 0x99) == 1 { pass=pass+1; e_p(" PASS apostrophe U+2019 present\n" as *u8) } else { fail=fail+1; e_p(" FAIL apostrophe U+2019 absent\n" as *u8) } 80 // em-dash present as clean UTF-8 (E2 80 94) -- from 0x97 81 if has3(chap, cn, 0xe2, 0x80, 0x94) == 1 { pass=pass+1; e_p(" PASS em-dash U+2014 present\n" as *u8) } else { fail=fail+1; e_p(" FAIL em-dash U+2014 absent\n" as *u8) } 82 // NO raw 0x92 survived 83 if has1(chap, cn, 0x92) == 0 { pass=pass+1; e_p(" PASS no raw 0x92\n" as *u8) } else { fail=fail+1; e_p(" FAIL raw 0x92 survived\n" as *u8) } 84 // NO raw 0x97 survived 85 if has1(chap, cn, 0x97) == 0 { pass=pass+1; e_p(" PASS no raw 0x97\n" as *u8) } else { fail=fail+1; e_p(" FAIL raw 0x97 survived\n" as *u8) } 86 // NO U+FFFD replacement char (EF BF BD) produced 87 if has3(chap, cn, 0xef, 0xbf, 0xbd) == 0 { pass=pass+1; e_p(" PASS no U+FFFD\n" as *u8) } else { fail=fail+1; e_p(" FAIL U+FFFD produced\n" as *u8) } 88 89 // book.json TITLE repaired: "Don" + U+2019 + "t" present, no raw 0x92 90 let jp: *i64 = sys_mmap(8) as *i64; jp[0] = 0 91 let jb: *u8 = sys_read_file("knowledge/staging/media/reader/mojibake_e2e/book.json\x00" as *u8, jp) 92 if (jb as i64) == 0 { fail=fail+1; e_p(" FAIL book.json missing\n" as *u8) } else { 93 let jn: i64 = jp[0] 94 if has3(jb, jn, 0xe2, 0x80, 0x99) == 1 { pass=pass+1; e_p(" PASS title/meta apostrophe repaired\n" as *u8) } else { fail=fail+1; e_p(" FAIL title/meta apostrophe absent\n" as *u8) } 95 if has1(jb, jn, 0x92) == 0 { pass=pass+1; e_p(" PASS book.json no raw 0x92\n" as *u8) } else { fail=fail+1; e_p(" FAIL book.json raw 0x92 survived\n" as *u8) } 96 } 97 98 e_p("MOJIBAKE-E2E pass="); e_n(pass); e_p(" fail="); e_n(fail) 99 if fail == 0 { e_p(" verdict=GREEN\n" as *u8); sys_exit(0); return 0 } 100 e_p(" verdict=RED\n" as *u8); sys_exit(1); return 1 101}