code wiki / _hdl_build / nx_mobi_cover_gate.nx

nx_mobi_cover_gate.nx source

↩ module page · 100 lines · 8256 B

1// nx_mobi_cover_gate.nx -- gate the EMBEDDED-cover extraction (operator: "we dont need it generate ... how does 2// calibre get all the book info ... i dont want to have internet connection"). The cover comes from the file ITSELF, 3// offline -- never generated, never downloaded. Grounded on the registered MOBI spec (mobileread-mobi-spec.ref): 4// First Image index @ MOBI-hdr 0x6c (rec0off+108); EXTH 201 coveroffset is ADDED to it to find the cover PDB record. 5// GREEN proves: (1) a MOBI carrying an embedded cover -> reader/<slug>/cover.gif extracted BYTE-EXACT (all 35 6// bytes of the real GIF, incl our navy color = it's THAT image, not random), (2) book.json cover wired to it, 7// (3) LIAR-KILL: a MOBI with NO embedded cover -> cover field stays "" and NO cover file is fabricated. 8// expect_exit: 0 license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "nx_gate_verdict.nx" 11 12func gp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 13func gnum(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 } 14func ghas(hay: *u8, hl: i64, needle: *u8) -> i64 { 15 var nl: i64=0; while needle[nl]!=(0 as u8){nl=nl+1} 16 if nl == 0 { return 0 } 17 var i: i64 = 0 18 while i + nl <= hl { var k: i64=0; var hit: i64=1; while k<nl { if hay[i+k]!=needle[k]{hit=0;k=nl}else{k=k+1} } if hit==1 {return 1} i=i+1 } 19 return 0 20} 21func rd(path: *u8, lenp: *i64) -> *u8 { lenp[0]=0; return sys_read_file(path, lenp) } 22func spawn(path: *u8, a0: *u8, a1: *u8, redir: *u8) -> i64 { 23 let pid: i64 = sys_fork() 24 if pid == 0 { 25 let fd: i64 = sys_openat_wr(redir, 420) 26 if fd >= 0 { sys_dup3(fd, 1, 0); sys_dup3(fd, 2, 0) } 27 let argv: *i64 = sys_mmap(64) as *i64 28 var n: i64 = 0 29 argv[0] = path as i64; n = 1 30 if (a0 as i64) != 0 { argv[n] = a0 as i64; n = n + 1 } 31 if (a1 as i64) != 0 { argv[n] = a1 as i64; n = n + 1 } 32 argv[n] = 0 33 let envp: *i64 = sys_mmap(16) as *i64 34 envp[0] = "PATH=/usr/bin:/bin\x00" as *u8 as i64; envp[1] = 0 35 sys_execve(path, argv, envp) 36 sys_exit(127) 37 } 38 let st: *i64 = sys_mmap(16) as *i64 39 sys_wait4(pid, st, 0) 40 return (st[0] >> 8) & 0xff 41} 42 43func main() -> i64 { 44 gp("=== nx_mobi_cover_gate: EMBEDDED cover extracted from the file itself (offline, no generation, no download) ===\n" as *u8) 45 let RUNNER: *u8 = "_offc/nx_sov_build_run.elf\x00" as *u8 46 let MB: *u8 = "_offc/nx_mobi_book.elf\x00" as *u8 47 let SC: *u8 = "knowledge/status/mobi_cover_scratch.log\x00" as *u8 48 49 spawn(RUNNER, "nx_mobi_fixture_build\x00" as *u8, 0 as *u8, SC) // build nishi_mobi_cover.mobi 50 let rcc: i64 = spawn(MB, "knowledge/fixtures/nishi_mobi_cover.mobi\x00" as *u8, "nishi_mobi_cover_fixture\x00" as *u8, SC) 51 let rcn: i64 = spawn(MB, "knowledge/fixtures/nishi_mobi_fixture.mobi\x00" as *u8, "nishi_mobi_nocover_g\x00" as *u8, SC) // no embedded cover 52 53 // expected 35-byte embedded GIF (the cover the fixture wrote): GIF89a 1x1, color 0 = navy 1a2238, trailer 3b 54 let exp: *u8 = sys_mmap(64) 55 exp[0]=0x47 as u8;exp[1]=0x49 as u8;exp[2]=0x46 as u8;exp[3]=0x38 as u8;exp[4]=0x39 as u8;exp[5]=0x61 as u8 56 exp[6]=0x01 as u8;exp[7]=0x00 as u8;exp[8]=0x01 as u8;exp[9]=0x00 as u8;exp[10]=0x80 as u8;exp[11]=0x00 as u8;exp[12]=0x00 as u8 57 exp[13]=0x1a as u8;exp[14]=0x22 as u8;exp[15]=0x38 as u8;exp[16]=0xff as u8;exp[17]=0xff as u8;exp[18]=0xff as u8 58 exp[19]=0x2c as u8;exp[20]=0x00 as u8;exp[21]=0x00 as u8;exp[22]=0x00 as u8;exp[23]=0x00 as u8;exp[24]=0x01 as u8;exp[25]=0x00 as u8;exp[26]=0x01 as u8;exp[27]=0x00 as u8;exp[28]=0x00 as u8 59 exp[29]=0x02 as u8;exp[30]=0x02 as u8;exp[31]=0x44 as u8;exp[32]=0x01 as u8;exp[33]=0x00 as u8;exp[34]=0x3b as u8 60 61 let lc: *i64 = sys_mmap(8) as *i64; let gif: *u8 = rd("knowledge/staging/media/reader/nishi_mobi_cover_fixture/cover.gif\x00" as *u8, lc); let gn: i64 = lc[0] 62 let lj: *i64 = sys_mmap(8) as *i64; let bj: *u8 = rd("knowledge/staging/media/reader/nishi_mobi_cover_fixture/book.json\x00" as *u8, lj); let bn: i64 = lj[0] 63 let ln: *i64 = sys_mmap(8) as *i64; let nbj: *u8 = rd("knowledge/staging/media/reader/nishi_mobi_nocover_g/book.json\x00" as *u8, ln); let nbn: i64 = ln[0] 64 let lx: *i64 = sys_mmap(8) as *i64; let nogif: *u8 = rd("knowledge/staging/media/reader/nishi_mobi_nocover_g/cover.gif\x00" as *u8, lx); let nogn: i64 = lx[0] 65 66 var bytexact: i64 = 0 67 if (gif as i64) != 0 { if gn == 35 { bytexact = 1; var i: i64=0; while i<35 { if gif[i]!=exp[i] { bytexact=0; i=35 } else { i=i+1 } } } } 68 69 gp(" rc_cover=" as *u8); gnum(rcc); gp(" cover.gif=" as *u8); gnum(gn); gp("B byte_exact=" as *u8); gnum(bytexact) 70 gp(" | rc_nocover=" as *u8); gnum(rcn); gp(" nocover.gif_bytes=" as *u8); gnum(nogn); gp("\n" as *u8) 71 72 var pass: i64 = 0; var fail: i64 = 0 73 if rcc == 0 { pass=pass+1 } else { fail=fail+1; gp(" FAIL cover-decode-nonzero\n" as *u8) } 74 if (gif as i64) != 0 { if gn > 0 { pass=pass+1 } else { fail=fail+1; gp(" FAIL cover.gif-empty\n" as *u8) } } else { fail=fail+1; gp(" FAIL no-cover.gif-file\n" as *u8) } 75 if gn == 35 { pass=pass+1 } else { fail=fail+1; gp(" FAIL cover-wrong-length (extraction off)\n" as *u8) } 76 if bytexact == 1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL cover NOT byte-exact (not the embedded image)\n" as *u8) } 77 if (gif as i64) != 0 { if gn >= 6 { if gif[0]==(0x47 as u8) { if gif[1]==(0x49 as u8) { if gif[2]==(0x46 as u8) { pass=pass+1 } else { fail=fail+1; gp(" FAIL no-GIF-magic\n" as *u8) } } else { fail=fail+1 } } else { fail=fail+1 } } } 78 if (bj as i64) != 0 { if ghas(bj, bn, "\"cover\":\"cover.gif\"" as *u8)==1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL book.json cover not wired to cover.gif\n" as *u8) } } else { fail=fail+1; gp(" FAIL no-cover-book.json\n" as *u8) } 79 // richer EXTH metadata ("all the book info") extracted from the file into book.json 80 if (bj as i64) != 0 { if ghas(bj, bn, "\"publisher\":\"Nishi Press\"" as *u8)==1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL publisher (EXTH 101) not extracted\n" as *u8) } } 81 if (bj as i64) != 0 { if ghas(bj, bn, "\"pubdate\":\"2026-06-23\"" as *u8)==1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL pubdate (EXTH 106) not extracted\n" as *u8) } } 82 // description (EXTH 103) extracted + HTML STRIPPED (html_to_text), not dumped raw 83 if (bj as i64) != 0 { if ghas(bj, bn, "sample" as *u8)==1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL description (EXTH 103) not extracted\n" as *u8) } } 84 if (bj as i64) != 0 { if ghas(bj, bn, "cover demo" as *u8)==1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL description text incomplete\n" as *u8) } } 85 if (bj as i64) != 0 { if ghas(bj, bn, "<i>sample</i>" as *u8)==0 { pass=pass+1 } else { fail=fail+1; gp(" FAIL description HTML tags NOT stripped\n" as *u8) } } 86 // LIAR-KILL: a MOBI with no embedded cover must NOT fabricate one 87 if (nbj as i64) != 0 { if ghas(nbj, nbn, "\"cover\":\"\"" as *u8)==1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL no-cover book got a FABRICATED cover (should be empty)\n" as *u8) } } else { fail=fail+1; gp(" FAIL no-cover-book.json\n" as *u8) } 88 if nogn <= 0 { pass=pass+1 } else { fail=fail+1; gp(" FAIL no-cover book wrote a cover.gif file (fabrication)\n" as *u8) } 89 90 gp("MOBI-COVER-GATE pass=" as *u8); gnum(pass); gp(" fail=" as *u8); gnum(fail) 91 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 92 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 93 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 94 let ctr__dry: *i64 = gv_ctr() 95 ctr__dry[0] = pass 96 ctr__dry[1] = pass + fail 97 let rc__dry: i64 = gv_verdict("MOBI-COVER-GATE" as *u8, ctr__dry, "embedded cover read out of the file byte-exact + wired into book.json; no cover -> no fabrication; fully offline)" as *u8) 98 sys_exit(rc__dry) 99 return rc__dry 100}