code wiki / (root) / nx_bgzf.nx

nx_bgzf.nx source

↩ module page · 151 lines · 5872 B

1// nx_bgzf.nx -- BGZF (Blocked GZIP Format) container per SAMv1 §4.1. 2// 3// BGZF wraps each block in a gzip member with an extra "BC" subfield 4// carrying BSIZE = total block bytes - 1, allowing random access 5// (a reader can advance exactly one block without inflating). 6// 7// G6.0e.1: nx_bgzf_eof_marker -- the canonical 28-byte EOF marker 8// that every BAM file MUST end with (SAMv1 §4.1.2; htslib uses 9// the literal byte sequence). This is a well-known fixed 10// sequence; encoded as a fixed-Huffman empty DEFLATE block. 11// 12// G6.0e.2: nx_bgzf_write_stored_block -- write a single BGZF block 13// carrying `data` of length `len` using DEFLATE BTYPE=00 14// (stored / no compression). Always succeeds for len up to the 15// stored-block limit (65504 bytes; keeps total ≤ 65535). 16// Composes nx_crc32 (CRC-32 of the uncompressed payload) and 17// nx_le_write_u16/u32 (all multi-byte fields little-endian). 18// 19// Compressed BGZF blocks (BTYPE=01/10) require a DEFLATE ENCODER 20// which the substrate does not yet ship (nx_deflate is decode-only). 21// Stored-block BGZF is a fully spec-conformant BAM container and 22// htslib will read it without warning. 23// 24// expect_exit: 0 25// 26// license_tier: ORIGINAL 27 28import "nx_syscalls.nx" 29import "nx_const.nx" 30import "nx_le.nx" 31import "nx_crc32.nx" 32 33// Stored-block max payload to keep block_size ≤ 65535. 34// block = 12 (gzip hdr+xlen) + 6 (BC extra) + 5 (BTYPE=00 hdr) 35// + L (payload) + 4 (CRC32) + 4 (ISIZE) = 31 + L 36// limit L ≤ 65504 37const NX_BGZF_STORED_PAYLOAD_MAX: i64 = 65504 38const NX_BGZF_STORED_OVERHEAD: i64 = 31 // bytes added around payload 39const NX_BGZF_EOF_MARKER_LEN: i64 = 28 40 41// G6.0e.1 -- canonical 28-byte EOF marker. 42// Wire bytes per SAMv1 §4.1.2 / htslib EOF block: 43// 1f 8b 08 04 00 00 00 00 00 ff gzip hdr (FEXTRA flag set) 44// 06 00 XLEN = 6 45// 42 43 02 00 1b 00 'BC' subfield, SLEN=2, BSIZE=27 46// 03 00 empty fixed-Huffman DEFLATE block 47// 00 00 00 00 CRC32 of empty = 0 48// 00 00 00 00 ISIZE = 0 49// Returns 28 on success, or -1 on capacity error. 50func nx_bgzf_eof_marker(out_bytes: *u8, max_out: i64) -> i64 { 51 if max_out < NX_BGZF_EOF_MARKER_LEN { return -1 } 52 out_bytes[0] = 0x1F as u8 53 out_bytes[1] = 0x8B as u8 54 out_bytes[2] = 0x08 as u8 55 out_bytes[3] = 0x04 as u8 56 out_bytes[4] = 0x00 as u8 57 out_bytes[5] = 0x00 as u8 58 out_bytes[6] = 0x00 as u8 59 out_bytes[7] = 0x00 as u8 60 out_bytes[8] = 0x00 as u8 61 out_bytes[9] = 0xFF as u8 62 out_bytes[10] = 0x06 as u8 63 out_bytes[11] = 0x00 as u8 64 out_bytes[12] = 0x42 as u8 // 'B' 65 out_bytes[13] = 0x43 as u8 // 'C' 66 out_bytes[14] = 0x02 as u8 67 out_bytes[15] = 0x00 as u8 68 out_bytes[16] = 0x1B as u8 // BSIZE = 27 69 out_bytes[17] = 0x00 as u8 70 out_bytes[18] = 0x03 as u8 // empty fixed-Huffman block 71 out_bytes[19] = 0x00 as u8 72 out_bytes[20] = 0x00 as u8 // CRC32 = 0 73 out_bytes[21] = 0x00 as u8 74 out_bytes[22] = 0x00 as u8 75 out_bytes[23] = 0x00 as u8 76 out_bytes[24] = 0x00 as u8 // ISIZE = 0 77 out_bytes[25] = 0x00 as u8 78 out_bytes[26] = 0x00 as u8 79 out_bytes[27] = 0x00 as u8 80 return NX_BGZF_EOF_MARKER_LEN 81} 82 83// G6.0e.2 -- write one BGZF block carrying `data` of length `len` 84// using DEFLATE BTYPE=00 (stored / no compression). 85// 86// Layout (total = 31 + len bytes; BSIZE = total - 1): 87// [0..10) gzip header : 1f 8b 08 04 00 00 00 00 00 ff 88// [10..12) XLEN = 6 : 06 00 89// [12..18) BC extra : 42 43 02 00 BSIZE_LE 90// [18..23) stored hdr : 01 LEN_LE NLEN_LE (BFINAL=1, BTYPE=00) 91// [23..23+len) : payload bytes (verbatim) 92// [+0..+4) : CRC32 LE of payload 93// [+4..+8) : ISIZE LE = len 94// 95// Returns total bytes written, or -1 on payload-overflow or 96// out-buffer-overflow. 97func nx_bgzf_write_stored_block(data: *u8, len: i64, 98 out_bytes: *u8, max_out: i64) -> i64 { 99 if len < 0 { return -1 } 100 if len > NX_BGZF_STORED_PAYLOAD_MAX { return -1 } 101 let total: i64 = NX_BGZF_STORED_OVERHEAD + len 102 if total > max_out { return -1 } 103 let bsize: i64 = total - 1 104 105 // gzip header (10 bytes). 106 out_bytes[0] = 0x1F as u8 107 out_bytes[1] = 0x8B as u8 108 out_bytes[2] = 0x08 as u8 // CM = deflate 109 out_bytes[3] = 0x04 as u8 // FLG = FEXTRA 110 out_bytes[4] = 0x00 as u8 // MTIME = 0 111 out_bytes[5] = 0x00 as u8 112 out_bytes[6] = 0x00 as u8 113 out_bytes[7] = 0x00 as u8 114 out_bytes[8] = 0x00 as u8 // XFL = 0 115 out_bytes[9] = 0xFF as u8 // OS = unknown 116 117 // XLEN = 6 (LE). 118 if nx_le_write_u16(out_bytes, 10, 6) < 0 { return -1 } 119 120 // BC extra subfield: 'B' 'C' SLEN=2 BSIZE. 121 out_bytes[12] = 0x42 as u8 // 'B' 122 out_bytes[13] = 0x43 as u8 // 'C' 123 if nx_le_write_u16(out_bytes, 14, 2) < 0 { return -1 } 124 if nx_le_write_u16(out_bytes, 16, bsize) < 0 { return -1 } 125 126 // DEFLATE stored block header: 01 LEN_LE NLEN_LE. 127 // bit 0 (BFINAL) = 1, bits 1-2 (BTYPE) = 00. 128 // First byte therefore 0x01. Remaining bits skipped to next 129 // byte boundary per RFC 1951 §3.2.4. 130 out_bytes[18] = 0x01 as u8 131 if nx_le_write_u16(out_bytes, 19, len) < 0 { return -1 } 132 let nlen: i64 = (~len) & 0xffff 133 if nx_le_write_u16(out_bytes, 21, nlen) < 0 { return -1 } 134 135 // payload (copy data verbatim). 136 var i: i64 = 0 137 while i < len { 138 out_bytes[23 + i] = data[i] 139 i = i + 1 140 } 141 142 // CRC32 of payload. 143 let crc: i64 = nx_crc32(data, len) 144 let crc_off: i64 = 23 + len 145 if nx_le_write_u32(out_bytes, crc_off, crc) < 0 { return -1 } 146 147 // ISIZE = len. 148 if nx_le_write_u32(out_bytes, crc_off + 4, len) < 0 { return -1 } 149 150 return total 151}