nx_gunzip.nx source
↩ module page · 111 lines · 4931 B
1// nx_gunzip.nx -- CLI for the sovereign decompressor: gzip / zlib / raw DEFLATE -> stdout or file.
2//
3// The missing half of our compression story. nx_gzip COMPRESSES; nothing could decompress, so any
4// HTTP body with Content-Encoding: gzip was unreadable by the sovereign fetch path.
5//
6// nx_gunzip <in.gz> [out] -- auto-detects gzip / zlib / raw by magic
7// nx_gunzip --crc <file> -- print the CRC32 of a file (the gzip integrity primitive)
8//
9// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
10import "nx_syscalls.nx"
11import "nx_inflate.nx"
12
13const GU_CAP: i64 = 268435456
14const GU_MODE: i64 = 0x1a4
15
16func gu_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
17func gu_e(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(2, s, n); return 0 }
18func gu_num(v: i64) -> i64 {
19 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 }
20 var m: i64 = v
21 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
22 let t: *u8 = sys_mmap(32)
23 var k: i64 = 0
24 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
25 let o: *u8 = sys_mmap(32)
26 var i: i64 = 0
27 while i < k { o[i] = t[k - 1 - i]; i = i + 1 }
28 sys_write(1, o, k)
29 return 0
30}
31// every error names the wall it hit -- a decompressor that fails silently is the defect this
32// organ exists to end, so the CLI refuses to be vague about why
33func gu_reason(rc: i64) -> i64 {
34 if rc == 0 - 1 { gu_e("INFLATE-RED output exceeds capacity\n" as *u8) }
35 if rc == 0 - 2 { gu_e("INFLATE-RED truncated stream (input exhausted)\n" as *u8) }
36 if rc == 0 - 3 { gu_e("INFLATE-RED invalid huffman symbol\n" as *u8) }
37 if rc == 0 - 4 { gu_e("INFLATE-RED back-reference points before the output buffer\n" as *u8) }
38 if rc == 0 - 5 { gu_e("INFLATE-RED reserved block type\n" as *u8) }
39 if rc == 0 - 6 { gu_e("INFLATE-RED stored block LEN/NLEN mismatch\n" as *u8) }
40 if rc == 0 - 7 { gu_e("INFLATE-RED not a gzip container\n" as *u8) }
41 if rc == 0 - 8 { gu_e("INFLATE-RED unsupported compression method\n" as *u8) }
42 if rc == 0 - 9 { gu_e("INFLATE-RED CRC32 MISMATCH -- output is corrupt, refusing to present it as data\n" as *u8) }
43 if rc == 0 - 10 { gu_e("INFLATE-RED ISIZE mismatch\n" as *u8) }
44 if rc == 0 - 11 { gu_e("INFLATE-RED not a zlib container\n" as *u8) }
45 if rc == 0 - 12 { gu_e("INFLATE-RED code-length run overflows the table\n" as *u8) }
46 return 0
47}
48
49func main(argc: i64, argv: *i64) -> i64 {
50 if argc < 2 {
51 gu_e("usage: nx_gunzip <in.gz> [out] | nx_gunzip --crc <file>\n" as *u8)
52 sys_exit(2)
53 return 2
54 }
55 let a1: *u8 = argv[1] as *u8
56 let lp: *i64 = sys_mmap(16) as *i64
57
58 if a1[0] == (45 as u8) {
59 if argc < 3 { gu_e("--crc needs a file\n" as *u8); sys_exit(2); return 2 }
60 let b2: *u8 = sys_read_file(argv[2] as *u8, lp)
61 if (b2 as i64) == 0 { gu_e("cannot read\n" as *u8); sys_exit(1); return 1 }
62 gu_w("CRC32 " as *u8); gu_num(inf_crc32(b2, lp[0]))
63 gu_w(" bytes " as *u8); gu_num(lp[0]); gu_w("\n" as *u8)
64 sys_exit(0)
65 return 0
66 }
67
68 let b: *u8 = sys_read_file(a1, lp)
69 if (b as i64) == 0 { gu_e("INFLATE-RED cannot read input\n" as *u8); sys_exit(1); return 1 }
70 let n: i64 = lp[0]
71 let out: *u8 = sys_mmap(GU_CAP)
72 if (out as i64) == 0 { gu_e("INFLATE-RED cannot allocate output\n" as *u8); sys_exit(1); return 1 }
73
74 // dispatch on the container's own magic rather than on the filename -- an extension is a
75 // claim by whoever named the file; the magic is the file itself
76 var rc: i64 = 0
77 var kind: *u8 = "raw-deflate" as *u8
78 if n >= 2 {
79 let m0: i64 = (b[0] & 0xff) as i64
80 let m1: i64 = (b[1] & 0xff) as i64
81 if m0 == 0x1f {
82 if m1 == 0x8b { kind = "gzip" as *u8; rc = inf_gunzip(b, n, out, GU_CAP) }
83 }
84 if (m0 & 15) == 8 {
85 if ((m0 * 256 + m1) % 31) == 0 {
86 if m0 != 0x1f { kind = "zlib" as *u8; rc = inf_zlib(b, n, out, GU_CAP) }
87 }
88 }
89 }
90 if kind[0] == (114 as u8) { rc = inf_raw(b, n, out, GU_CAP) }
91
92 if rc < 0 { gu_reason(rc); sys_exit(3); return 3 }
93
94 if argc >= 3 {
95 let fd: i64 = sys_openat_wr(argv[2] as *u8, GU_MODE)
96 if fd < 0 { gu_e("INFLATE-RED cannot open output\n" as *u8); sys_exit(1); return 1 }
97 var w: i64 = 0
98 while w < rc {
99 let k: i64 = sys_write(fd, ((out as i64) + w) as *u8, rc - w)
100 if k <= 0 { sys_close(fd); gu_e("INFLATE-RED short write\n" as *u8); sys_exit(1); return 1 }
101 w = w + k
102 }
103 sys_close(fd)
104 gu_w("INFLATE-GREEN " as *u8); gu_w(kind); gu_w(" " as *u8); gu_num(n)
105 gu_w(" -> " as *u8); gu_num(rc); gu_w(" bytes (CRC32 verified)\n" as *u8)
106 } else {
107 sys_write(1, out, rc)
108 }
109 sys_exit(0)
110 return 0
111}