From c4b71435d9afdb67450f320f54fb7aa99dcae85e Mon Sep 17 00:00:00 2001 From: polwex Date: Sun, 5 Oct 2025 22:57:55 +0700 Subject: fixed jamcue --- ocaml/lib/bitstream.ml | 102 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 ocaml/lib/bitstream.ml (limited to 'ocaml/lib/bitstream.ml') diff --git a/ocaml/lib/bitstream.ml b/ocaml/lib/bitstream.ml new file mode 100644 index 0000000..cfe094c --- /dev/null +++ b/ocaml/lib/bitstream.ml @@ -0,0 +1,102 @@ +(** Bitstream utilities for jam/cue serialization *) + +(** A bitstream writer *) +type writer = { + buf: bytes ref; (** Buffer for bits *) + mutable bit_pos: int; (** Current bit position *) +} + +(** A bitstream reader *) +type reader = { + buf: bytes; (** Buffer to read from *) + mutable bit_pos: int; (** Current bit position *) + len: int; (** Length in bits *) +} + +(** Create a new bitstream writer *) +let writer_create () = { + buf = ref (Bytes.create 1024); + bit_pos = 0; +} + +(** Grow the writer buffer if needed *) +let writer_ensure (w : writer) (bits_needed : int) : unit = + let bytes_needed : int = (w.bit_pos + bits_needed + 7) / 8 in + let buf_ref : bytes ref = w.buf in + let current_buf : bytes = !buf_ref in + if bytes_needed > (Bytes.length current_buf) then begin + let old_buf : bytes = current_buf in + let new_size : int = max (bytes_needed * 2) (Bytes.length old_buf * 2) in + let new_buf : bytes = Bytes.create new_size in + Bytes.blit old_buf 0 new_buf 0 (Bytes.length old_buf); + buf_ref := new_buf + end + +(** Write a single bit *) +let write_bit w bit = + writer_ensure w 1; + let byte_pos = w.bit_pos / 8 in + let bit_off = w.bit_pos mod 8 in + if bit then begin + let buf = !(w.buf) in + let old_byte = Bytes.get_uint8 buf byte_pos in + Bytes.set_uint8 buf byte_pos (old_byte lor (1 lsl bit_off)) + end; + w.bit_pos <- w.bit_pos + 1 + +(** Write multiple bits from a Z.t value *) +let write_bits w value nbits = + writer_ensure w nbits; + for i = 0 to nbits - 1 do + let bit = Z.testbit value i in + write_bit w bit + done + +(** Get the final bytes from a writer *) +let writer_to_bytes (w : writer) : bytes = + let byte_len = (w.bit_pos + 7) / 8 in + let buf_ref : bytes ref = w.buf in + let buf : bytes = !buf_ref in + Bytes.sub buf 0 byte_len + +(** Create a bitstream reader *) +let reader_create buf = + { + buf; + bit_pos = 0; + len = Bytes.length buf * 8; + } + +(** Read a single bit *) +let read_bit r = + if r.bit_pos >= r.len then + raise (Invalid_argument "read_bit: end of stream"); + let byte_pos = r.bit_pos / 8 in + let bit_off = r.bit_pos mod 8 in + let byte_val = Bytes.get_uint8 r.buf byte_pos in + r.bit_pos <- r.bit_pos + 1; + (byte_val lsr bit_off) land 1 = 1 + +(** Read multiple bits as a Z.t *) +let read_bits r nbits = + let result = ref Z.zero in + for i = 0 to nbits - 1 do + if read_bit r then + result := Z.logor !result (Z.shift_left Z.one i) + done; + !result + +(** Peek at a bit without advancing *) +let peek_bit r = + if r.bit_pos >= r.len then + raise (Invalid_argument "peek_bit: end of stream"); + let byte_pos = r.bit_pos / 8 in + let bit_off = r.bit_pos mod 8 in + let byte_val = Bytes.get_uint8 r.buf byte_pos in + (byte_val lsr bit_off) land 1 = 1 + +(** Get current bit position *) +let reader_pos r = r.bit_pos + +(** Check if at end of stream *) +let reader_at_end r = r.bit_pos >= r.len -- cgit v1.2.3