code wiki / _hdl_build / nx_nxfh_lib.nx

nx_nxfh_lib.nx source

↩ module page · 169 lines · 6098 B

1// nx_nxfh_lib.nx -- shared NXFH1 text-hex framebuffer codec (LIB, no main). license_tier: ORIGINAL 2// WHY A LIB (DRY, rule 15): the NXFH1 parser lived ONLY inside nx_frame_score.nx (an organ with a 3// main, so nothing could import it); the moment a second consumer existed (nx_frame_score2 + gates) 4// copies #2 and #3 were about to happen. This is the extraction. The DEPLOYED nx_frame_score keeps 5// its private copy untouched -- this task builds a new instrument, it does not touch the live one. 6// FORMAT NXFH1 (deliberately TEXT so it travels the fs-write lane safely; raw binary through 7// JSON-string tooling is the proven corruption path): 8// line 1: "NXFH1 <w> <h>\n" then w*h pixels as 6 lowercase hex chars each (rrggbb), any 9// whitespace between pixels ignored. Decoded pixel layout r | g<<8 | b<<16 = the critic fb layout. 10// CONTRACT: nxl_load REFUSES (returns 0) on missing file, bad magic, junk bytes, short/overlong 11// pixel stream -- a truncated capture must never be scored as a dark frame. nxl_dump is the writer; 12// a writer is only tested by a read-back (banked law), which nx_craft_capture_gate enforces. 13import "nx_syscalls.nx" 14 15const NXL_MAXW: i64 = 1024 16const NXL_MAXH: i64 = 1024 17const NXL_MAGIC_65536: i64 = 65536 18const NXL_MODE_644: i64 = 420 19const NXL_HDRMIN: i64 = 12 20 21func nxl_isws(c: i64) -> i64 { if c==32 { return 1 } if c==10 { return 1 } if c==13 { return 1 } if c==9 { return 1 } return 0 } 22func nxl_nib(c: i64) -> i64 { 23 if c >= 48 { if c <= 57 { return c - 48 } } 24 if c >= 97 { if c <= 102 { return c - 87 } } 25 if c >= 65 { if c <= 70 { return c - 55 } } 26 return 0-1 27} 28 29// Load an NXFH1 file into a freshly mmapped packed fb (r | g<<8 | b<<16). On success writes w,h to 30// whp[0],whp[1] and returns the fb ptr; on ANY malformation returns 0 (refuse loudly, never guess). 31func nxl_load(path: *u8, whp: *i64) -> *i64 { 32 let lenp: *i64 = sys_mmap(8) as *i64 33 lenp[0] = 0 34 let b: *u8 = sys_read_file(path, lenp) 35 if (b as i64)==0 { return 0 as *i64 } 36 let n: i64 = lenp[0] 37 if n < NXL_HDRMIN { return 0 as *i64 } 38 if b[0]!=(78 as u8) { return 0 as *i64 } 39 if b[1]!=(88 as u8) { return 0 as *i64 } 40 if b[2]!=(70 as u8) { return 0 as *i64 } 41 if b[3]!=(72 as u8) { return 0 as *i64 } 42 if b[4]!=(49 as u8) { return 0 as *i64 } 43 var p: i64 = 5 44 var run: i64 = 1 45 while run==1 { 46 if p >= n { run = 0 } else { 47 if nxl_isws(b[p] as i64)==1 { p = p + 1 } else { run = 0 } 48 } 49 } 50 var w: i64 = 0 51 run = 1 52 while run==1 { 53 if p >= n { run = 0 } else { 54 let c: i64 = b[p] as i64 55 if c < 48 { run = 0 } else { 56 if c > 57 { run = 0 } else { w = w*10 + (c-48); p = p + 1 } 57 } 58 } 59 } 60 run = 1 61 while run==1 { 62 if p >= n { run = 0 } else { 63 if nxl_isws(b[p] as i64)==1 { p = p + 1 } else { run = 0 } 64 } 65 } 66 var h: i64 = 0 67 run = 1 68 while run==1 { 69 if p >= n { run = 0 } else { 70 let c2: i64 = b[p] as i64 71 if c2 < 48 { run = 0 } else { 72 if c2 > 57 { run = 0 } else { h = h*10 + (c2-48); p = p + 1 } 73 } 74 } 75 } 76 if w < 8 { return 0 as *i64 } 77 if h < 8 { return 0 as *i64 } 78 if w > NXL_MAXW { return 0 as *i64 } 79 if h > NXL_MAXH { return 0 as *i64 } 80 let need: i64 = w*h 81 let fb: *i64 = sys_mmap(need*8) as *i64 82 var px: i64 = 0 83 var acc: i64 = 0 84 var nyb: i64 = 0 85 var bad: i64 = 0 86 while p < n { 87 let c3: i64 = b[p] as i64 88 if nxl_isws(c3)==0 { 89 let v: i64 = nxl_nib(c3) 90 if v < 0 { bad = 1; p = n } else { 91 acc = acc*16 + v 92 nyb = nyb + 1 93 if nyb == 6 { 94 if px >= need { bad = 1; p = n } else { 95 let r: i64 = (acc / NXL_MAGIC_65536) % 256 96 let g: i64 = (acc / 256) % 256 97 let bb: i64 = acc % 256 98 fb[px] = r + g*256 + bb*NXL_MAGIC_65536 99 px = px + 1 100 acc = 0 101 nyb = 0 102 } 103 } 104 } 105 } 106 if p < n { p = p + 1 } 107 } 108 if bad == 1 { return 0 as *i64 } 109 if px != need { return 0 as *i64 } 110 if nyb != 0 { return 0 as *i64 } 111 whp[0] = w 112 whp[1] = h 113 return fb 114} 115 116func nxl_cat(d: *u8, at: i64, s: *u8) -> i64 { var i: i64=0; var a: i64=at; while s[i]!=(0 as u8) { d[a]=s[i]; a=a+1; i=i+1 } return a } 117func nxl_catn(d: *u8, at: i64, v: i64) -> i64 { 118 var a: i64 = at 119 var m: i64 = v 120 if m == 0 { d[a] = 48 as u8; return a + 1 } 121 if m < 0 { d[a] = 45 as u8; a = a + 1; m = 0 - m } 122 let t: *u8 = sys_mmap(32) 123 var k: i64 = 0 124 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 125 var q: i64 = k - 1 126 while q >= 0 { d[a] = t[q]; a = a + 1; q = q - 1 } 127 return a 128} 129func nxl_hex2(d: *u8, at: i64, v: i64) -> i64 { 130 let hi: i64 = (v / 16) % 16 131 let lo: i64 = v % 16 132 var c1: i64 = 48 + hi 133 if hi > 9 { c1 = 87 + hi } 134 var c2: i64 = 48 + lo 135 if lo > 9 { c2 = 87 + lo } 136 d[at] = c1 as u8 137 d[at+1] = c2 as u8 138 return at + 2 139} 140 141// Write fb as NXFH1 text. Returns bytes written (>0) or -1 on open failure. 142func nxl_dump(path: *u8, fb: *i64, w: i64, h: i64) -> i64 { 143 let cap: i64 = 64 + w*h*6 + h 144 let d: *u8 = sys_mmap(cap) 145 var o: i64 = nxl_cat(d, 0, "NXFH1 " as *u8) 146 o = nxl_catn(d, o, w) 147 d[o] = 32 as u8; o = o + 1 148 o = nxl_catn(d, o, h) 149 d[o] = 10 as u8; o = o + 1 150 var y: i64 = 0 151 while y < h { 152 var x: i64 = 0 153 while x < w { 154 let v: i64 = fb[y*w+x] 155 o = nxl_hex2(d, o, v % 256) 156 o = nxl_hex2(d, o, (v / 256) % 256) 157 o = nxl_hex2(d, o, (v / NXL_MAGIC_65536) % 256) 158 x = x + 1 159 } 160 d[o] = 10 as u8 161 o = o + 1 162 y = y + 1 163 } 164 let fd: i64 = sys_openat_wr(path, NXL_MODE_644) 165 if fd < 0 { return 0-1 } 166 sys_write(fd, d, o) 167 sys_close(fd) 168 return o 169}