From cc8d8db279d521c89957402f9766dbcf50ddaa26 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Sun, 18 May 2008 19:02:54 +0000 Subject: [PATCH] Implement bitstring_to_chan, bitstring_to_file. --- bitmatch.ml | 37 ++++++++++++++++++++++++++++++++++--- bitmatch.mli | 30 +++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/bitmatch.ml b/bitmatch.ml index f16d490..c9dba77 100644 --- a/bitmatch.ml +++ b/bitmatch.ml @@ -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. *) diff --git a/bitmatch.mli b/bitmatch.mli index 979e591..672cb39 100644 --- a/bitmatch.mli +++ b/bitmatch.mli @@ -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} *) -- 1.8.3.1