Implement bitstring_to_chan, bitstring_to_file.
authorRichard W.M. Jones <rich@annexia.org>
Sun, 18 May 2008 19:02:54 +0000 (19:02 +0000)
committerRichard W.M. Jones <rich@annexia.org>
Sun, 18 May 2008 19:02:54 +0000 (19:02 +0000)
bitmatch.ml
bitmatch.mli

index f16d490..c9dba77 100644 (file)
@@ -106,9 +106,13 @@ let bitstring_of_file_descr_max fd max =
 
 let bitstring_of_file fname =
   let chan = open_in_bin fname in
-  let bs = bitstring_of_chan chan in
-  close_in chan;
-  bs
+  try
+    let bs = bitstring_of_chan chan in
+    close_in chan;
+    bs
+  with exn ->
+    close_in chan;
+    raise exn
 
 let bitstring_length (_, _, len) = len
 
@@ -767,6 +771,9 @@ let string_of_bitstring (data, off, len) =
        str.[i] <- Char.chr c;
        loop data off len (i+1)
       ) else if len > 0 then (
+       (* XXX Is this correct?  It should write into the high bits
+        * of the last byte.
+        *)
        let c, off, len = extract_char_unsigned data off len len in
        str.[i] <- Char.chr c
       )
@@ -775,6 +782,30 @@ let string_of_bitstring (data, off, len) =
     str
   )
 
+(* To channel. *)
+
+let bitstring_to_chan ((data, off, len) as bits) chan =
+  (* Fail if the bitstring length isn't a multiple of 8. *)
+  if len land 7 <> 0 then invalid_arg "bitstring_to_chan";
+
+  if off land 7 = 0 then
+    (* Easy case: string is byte-aligned. *)
+    output chan data (off lsr 3) (len lsr 3)
+  else (
+    (* Bit-twiddling case: reuse string_of_bitstring *)
+    let str = string_of_bitstring bits in
+    output_string chan str
+  )
+
+let bitstring_to_file bits filename =
+  let chan = open_out_bin filename in
+  try
+    bitstring_to_chan bits chan;
+    close_out chan
+  with exn ->
+    close_out chan;
+    raise exn
+
 (*----------------------------------------------------------------------*)
 (* Display functions. *)
 
index 979e591..672cb39 100644 (file)
@@ -634,7 +634,35 @@ val string_of_bitstring : bitstring -> string
     This function is inefficient.  In the best case when the bitstring
     is nicely byte-aligned we do a [String.sub] operation.  If the
     bitstring isn't aligned then this involves a lot of bit twiddling
-    and is particularly inefficient. *)
+    and is particularly inefficient.
+
+    If the bitstring is not a multiple of 8 bits wide then the
+    final byte of the string contains the high bits set to the
+    remaining bits and the low bits set to 0. *)
+
+val bitstring_to_file : bitstring -> string -> unit
+(** [bitstring_to_file bits filename] writes the bitstring [bits]
+    to the file [filename].  It overwrites the output file.
+
+    Some restrictions apply, see {!bitstring_to_chan}. *)
+
+val bitstring_to_chan : bitstring -> out_channel -> unit
+(** [bitstring_to_file bits filename] writes the bitstring [bits]
+    to the channel [chan].
+
+    Channels are made up of bytes, bitstrings can be any bit length
+    including fractions of bytes.  So this function only works
+    if the length of the bitstring is an exact multiple of 8 bits
+    (otherwise it raises [Invalid_argument "bitstring_to_chan"]).
+
+    Furthermore the function is efficient only in the case where
+    the bitstring is stored fully aligned, otherwise it has to
+    do inefficient bit twiddling like {!string_of_bitstring}.
+
+    In the common case where the bitstring was generated by the
+    [BITSTRING] operator and is an exact multiple of 8 bits wide,
+    then this function will always work efficiently.
+*)
 
 (** {3 Printing bitstrings} *)