code wiki / _hdl_build / nx_mobi_inspect.nx

nx_mobi_inspect.nx source

↩ module page · 104 lines · 6742 B

1// nx_mobi_inspect.nx -- diagnostic: dump a MOBI's PDB/PalmDOC/MOBI-header structure + LOCATE the HUFF/CDIC records 2// by scanning every PDB record for the "HUFF"/"CDIC" magics, so we can see why the Huffman Record Offset field read 3// disagrees with reality on a real kindlegen file. Usage: nx_mobi_inspect <mobi-path>. license_tier: ORIGINAL 4import "nx_syscalls.nx" 5 6func ip(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 7func inum(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 } 8func be16(b: *u8, o: i64) -> i64 { return ((b[o] as i64)<<8)|(b[o+1] as i64) } 9func be32(b: *u8, o: i64) -> i64 { return ((b[o] as i64)<<24)|((b[o+1] as i64)<<16)|((b[o+2] as i64)<<8)|(b[o+3] as i64) } 10func tag4(z: *u8, o: i64) -> i64 { sys_write(1, (z as i64 + o) as *u8, 4); return 0 } 11func islen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 12func find_sub(hay: *u8, hl: i64, needle: *u8) -> i64 { 13 let nl: i64 = islen(needle); if nl==0 { return 0-1 } 14 var i: i64 = 0 15 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 i} i=i+1 } 16 return 0-1 17} 18 19func main(argc: i64, argv: *i64) -> i64 { 20 var path: *u8 = "knowledge/benchmarks/refs/libmobi-sample-huffdic.ref" as *u8 21 if argc >= 2 { path = argv[1] as *u8 } 22 let lp: *i64 = sys_mmap(8) as *i64; lp[0]=0 23 let z: *u8 = sys_read_file(path, lp) 24 if (z as i64)==0 { ip("INSPECT-FAIL read\n" as *u8); sys_exit(1); return 1 } 25 let zl: i64 = lp[0] 26 let numRec: i64 = be16(z, 76) 27 let rec0off: i64 = be32(z, 78) 28 ip("file=" as *u8); ip(path); ip(" bytes=" as *u8); inum(zl); ip(" numRec=" as *u8); inum(numRec); ip(" rec0off=" as *u8); inum(rec0off); ip("\n" as *u8) 29 ip("PDB name=\"" as *u8); var nn: i64=0; while nn<32 { if z[nn]==(0 as u8) { nn=32 } else { sys_write(1,(z as i64+nn) as *u8,1); nn=nn+1 } } ip("\" type/creator=" as *u8); tag4(z,60); tag4(z,64); ip("\n" as *u8) 30 let comp: i64 = be16(z, rec0off+0) 31 let textLen: i64 = be32(z, rec0off+4) 32 let recCount: i64 = be16(z, rec0off+8) 33 let enc: i64 = be16(z, rec0off+12) 34 ip("PalmDOC: comp=" as *u8); inum(comp); ip(" textLen=" as *u8); inum(textLen); ip(" textRecCount=" as *u8); inum(recCount); ip(" enc=" as *u8); inum(enc); ip("\n" as *u8) 35 ip("MOBI hdr @" as *u8); inum(rec0off+16); ip(" magic=" as *u8); tag4(z, rec0off+16); ip(" hdrLen=" as *u8); inum(be32(z, rec0off+20)); ip("\n" as *u8) 36 ip(" Huffman Record Offset(0x70)=" as *u8); inum(be32(z, rec0off+16+112)); ip(" Count(0x74)=" as *u8); inum(be32(z, rec0off+16+116)); ip("\n" as *u8) 37 38 // dump MOBI-header dwords to LOCATE the real Huffman Record Offset field (looking for the value 32) 39 ip("MOBI hdr dwords (offset=value):\n" as *u8) 40 var d: i64 = 96 41 while d <= 160 { 42 ip(" +" as *u8); inum(d); ip("=" as *u8); inum(be32(z, rec0off+16+d)); ip("\n" as *u8) 43 d = d + 4 44 } 45 46 // scan EVERY record for the HUFF/CDIC magics -> the ground truth 47 ip("scan: records with HUFF/CDIC magic:\n" as *u8) 48 var i: i64 = 0 49 while i < numRec { 50 let ro: i64 = be32(z, 78 + i*8) 51 if ro + 4 <= zl { 52 let isH: i64 = 1; if z[ro]!=(0x48 as u8){ } 53 var hh: i64 = 0 54 if z[ro]==(0x48 as u8) { if z[ro+1]==(0x55 as u8) { if z[ro+2]==(0x46 as u8) { if z[ro+3]==(0x46 as u8) { hh=1 } } } } 55 var cc: i64 = 0 56 if z[ro]==(0x43 as u8) { if z[ro+1]==(0x44 as u8) { if z[ro+2]==(0x49 as u8) { if z[ro+3]==(0x43 as u8) { cc=1 } } } } 57 if hh==1 { ip(" rec[" as *u8); inum(i); ip("] @" as *u8); inum(ro); ip(" = HUFF hdrsize=" as *u8); inum(be32(z, ro+4)); ip("\n" as *u8) } 58 if cc==1 { ip(" rec[" as *u8); inum(i); ip("] @" as *u8); inum(ro); ip(" = CDIC\n" as *u8) } 59 } 60 i = i + 1 61 } 62 // EXTH records (looking for type 121 = KF8 Boundary -> the PDB record where the KF8 part begins) 63 let rec1off: i64 = be32(z, 78 + 8) 64 var r0ext: i64 = rec1off - rec0off 65 if r0ext <= 0 { r0ext = zl - rec0off } 66 let exrel: i64 = find_sub((z as i64 + rec0off) as *u8, r0ext, "EXTH" as *u8) 67 if exrel >= 0 { 68 let exth: i64 = rec0off + exrel 69 let cnt: i64 = be32(z, exth + 8) 70 ip("EXTH @" as *u8); inum(exth); ip(" records=" as *u8); inum(cnt); ip(":\n" as *u8) 71 var p: i64 = exth + 12; var ci: i64 = 0 72 while ci < cnt { 73 if p + 8 > zl { ci = cnt } else { 74 let rtype: i64 = be32(z, p); let rlen: i64 = be32(z, p+4) 75 if rlen < 8 { ci = cnt } else { 76 if rtype == 121 { ip(" *** EXTH 121 (KF8 boundary) value=" as *u8); inum(be32(z, p+8)); ip("\n" as *u8) } 77 if rtype == 116 { ip(" EXTH 116 (startReading) value=" as *u8); inum(be32(z, p+8)); ip("\n" as *u8) } 78 p = p + rlen; ci = ci + 1 79 } 80 } 81 } 82 } 83 // if a KF8 boundary record was identified, dump its PalmDOC header 84 ip("mobiType@(rec0+16+8)=" as *u8); inum(be32(z, rec0off+16+8)); ip(" (8 => KF8)\n" as *u8) 85 // dump records around the KF8 boundary (looking for "BOUNDARY" marker + the KF8 MOBI header) 86 ip("records 44..51 (idx @off first8 | +16tag):\n" as *u8) 87 var rr: i64 = 44 88 while rr <= 51 { 89 if rr < numRec { let ro: i64 = be32(z, 78 + rr*8) 90 ip(" [" as *u8); inum(rr); ip("] @" as *u8); inum(ro); ip(" \"" as *u8) 91 var b: i64=0; while b<8 { let cb: i64 = z[ro+b] as i64; if cb>=32 { if cb<127 { sys_write(1,(z as i64+ro+b) as *u8,1) } else { ip("." as *u8) } } else { ip("." as *u8) } b=b+1 } 92 ip("\" +16=" as *u8); tag4(z, ro+16); ip("\n" as *u8) } 93 rr = rr + 1 94 } 95 // dump the KF8 header (boundary record 46) PalmDOC + MOBI-hdr dwords (looking for the HUFF record index 86) 96 let kf: i64 = be32(z, 78 + 46*8) 97 ip("KF8 hdr @rec46 off=" as *u8); inum(kf); ip(" comp=" as *u8); inum(be16(z, kf)); ip(" recCount=" as *u8); inum(be16(z, kf+8)); ip(" MOBImagic=" as *u8); tag4(z, kf+16); ip(" hdrLen=" as *u8); inum(be32(z, kf+20)); ip("\n" as *u8) 98 ip("KF8 MOBI-hdr dwords:\n" as *u8) 99 var kd: i64 = 88 100 while kd <= 124 { ip(" +" as *u8); inum(kd); ip("=" as *u8); inum(be32(z, kf+16+kd)); ip("\n" as *u8); kd = kd + 4 } 101 ip(" also rec0-relative +112=" as *u8); inum(be32(z, kf+112)); ip(" +116=" as *u8); inum(be32(z, kf+116)); ip("\n" as *u8) 102 ip("INSPECT-OK\n" as *u8) 103 sys_exit(0); return 0 104}