From 3c49245c0acb2c8b34a6df99f98d480fcad28245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20R=2E=20Gu=C3=A9rin?= Date: Thu, 6 Nov 2025 18:52:40 +0100 Subject: [PATCH 1/2] Use ocamlformat, janestreet profile --- .ocamlformat | 2 + dune | 5 +- examples/elf.ml | 10 +- examples/ext3_superblock.ml | 7 +- examples/gif.ml | 28 +- examples/ipv4_header.ml | 9 +- examples/libpcap.ml | 60 +- examples/make_ipv4_header.ml | 13 +- examples/ping.ml | 13 +- ppx/dune | 3 +- ppx/ppx_bitstring.ml | 1226 ++++++++++++------------- src/bitstring.ml | 1316 +++++++++++++++------------ src/bitstring.mli | 262 +++--- src/bitstring_config.ml | 5 +- src/bitstring_types.ml | 6 +- tests/BitstringConstructorTest.ml | 115 ++- tests/BitstringLegacyTest.ml | 1223 ++++++++++++++----------- tests/BitstringLegacyTest.mli | 2 +- tests/BitstringLetStarSyntaxTest.ml | 12 +- tests/BitstringParserTest.ml | 115 +-- tests/BitstringQualifierTest.ml | 23 +- tests/bitstring_tests.ml | 12 +- 22 files changed, 2385 insertions(+), 2082 deletions(-) create mode 100644 .ocamlformat diff --git a/.ocamlformat b/.ocamlformat new file mode 100644 index 0000000..e67a576 --- /dev/null +++ b/.ocamlformat @@ -0,0 +1,2 @@ +profile = janestreet +version = 0.28.1 diff --git a/dune b/dune index a859e2d..afb0f84 100644 --- a/dune +++ b/dune @@ -1,3 +1,4 @@ (env - (dev - (flags (:standard -w -27-32-33-35)))) + (dev + (flags + (:standard -w -27-32-33-35)))) diff --git a/examples/elf.ml b/examples/elf.ml index 366a67a..3f22834 100644 --- a/examples/elf.ml +++ b/examples/elf.ml @@ -7,14 +7,12 @@ open Printf let () = let filename = "/bin/ls" in let bits = Bitstring.bitstring_of_file filename in - match%bitstring bits with | {| 0x7f : 8; "ELF" : 24 : string; (* ELF magic number *) _ : 12*8 : bitstring; (* ELF identifier *) e_type : 16 : littleendian; (* object file type *) e_machine : 16 : littleendian (* architecture *) - |} -> - printf "%s: ELF binary, type %d, arch %d\n" filename e_type e_machine - - | {| _ |} -> - eprintf "%s: Not an ELF binary\n" filename + |} + -> printf "%s: ELF binary, type %d, arch %d\n" filename e_type e_machine + | {| _ |} -> eprintf "%s: Not an ELF binary\n" filename +;; diff --git a/examples/ext3_superblock.ml b/examples/ext3_superblock.ml index f397f1e..b95c576 100644 --- a/examples/ext3_superblock.ml +++ b/examples/ext3_superblock.ml @@ -63,8 +63,9 @@ let () = s_reserved_word_pad : 16 : littleendian; s_default_mount_opts : 32 : littleendian; s_first_meta_bg : 32 : littleendian; (* First metablock block group *) - _ : 6080 : bitstring |} -> (* Padding to the end of the block *) - + _ : 6080 : bitstring |} + -> + (* Padding to the end of the block *) printf "ext3 superblock:\n"; printf " s_inodes_count = %ld\n" s_inodes_count; printf " s_blocks_count = %ld\n" s_blocks_count; @@ -73,7 +74,7 @@ let () = printf " s_uuid = %S\n" s_uuid; printf " s_volume_name = %S\n" s_volume_name; printf " s_last_mounted = %S\n" s_last_mounted - | {| _ |} -> eprintf "not an ext3 superblock!\n%!"; exit 2 +;; diff --git a/examples/gif.ml b/examples/gif.ml index 033e150..eec566e 100644 --- a/examples/gif.ml +++ b/examples/gif.ml @@ -5,11 +5,9 @@ open Printf let () = - if Array.length Sys.argv <= 1 then - failwith "usage: gif input.gif"; + if Array.length Sys.argv <= 1 then failwith "usage: gif input.gif"; let filename = Sys.argv.(1) in let bits = Bitstring.bitstring_of_file filename in - match%bitstring bits with | {|("GIF87a"|"GIF89a") : 6*8 : string; (* GIF magic. *) width : 16 : littleendian; @@ -19,15 +17,15 @@ let () = sortflag : 1; bps : 3; (* Bits/pixel = bps+1 *) bg : 8; (* Background colour. *) - aspectratio : 8|} -> - printf "%s: GIF image:\n" filename; - printf " size %d %d\n" width height; - printf " has global colormap? %b\n" colormap; - printf " colorbits %d\n" (colorbits+1); - printf " global colormap is sorted? %b\n" sortflag; - printf " bits/pixel %d\n" (bps+1); - printf " background color index %d\n" bg; - printf " aspect ratio %d\n" aspectratio - - | {|_|} -> - eprintf "%s: Not a GIF image\n" filename + aspectratio : 8|} + -> + printf "%s: GIF image:\n" filename; + printf " size %d %d\n" width height; + printf " has global colormap? %b\n" colormap; + printf " colorbits %d\n" (colorbits + 1); + printf " global colormap is sorted? %b\n" sortflag; + printf " bits/pixel %d\n" (bps + 1); + printf " background color index %d\n" bg; + printf " aspect ratio %d\n" aspectratio + | {|_|} -> eprintf "%s: Not a GIF image\n" filename +;; diff --git a/examples/ipv4_header.ml b/examples/ipv4_header.ml index c81c70b..869b15e 100644 --- a/examples/ipv4_header.ml +++ b/examples/ipv4_header.ml @@ -15,8 +15,7 @@ let () = dest : 32; options : (hdrlen-5)*32 : bitstring; payload : -1 : bitstring|} - when version = 4 -> - + when version = 4 -> printf "IPv%d:\n" version; printf " header length: %d * 32 bit words\n" hdrlen; printf " type of service: %d\n" tos; @@ -32,10 +31,8 @@ let () = Bitstring.hexdump_bitstring stdout options; printf " packet payload:\n"; Bitstring.hexdump_bitstring stdout payload - - | {|version : 4|} -> - eprintf "cannot parse IP version %d\n" version - + | {|version : 4|} -> eprintf "cannot parse IP version %d\n" version | {|_|} as header -> eprintf "data is smaller than one nibble:\n"; Bitstring.hexdump_bitstring stderr header +;; diff --git a/examples/libpcap.ml b/examples/libpcap.ml index 79194ed..cca7a0d 100644 --- a/examples/libpcap.ml +++ b/examples/libpcap.ml @@ -18,16 +18,14 @@ let rec main () = if Array.length Sys.argv <= 1 then failwith "libpcap dumpfile"; let bits = Bitstring.bitstring_of_file Sys.argv.(1) in let endian, file_header, bits = libpcap_header bits in - (* Read the packets and print them out. *) let rec loop bits = let pkt_header, pkt_data, bits = libpcap_packet endian file_header bits in decode_and_print_packet file_header pkt_header pkt_data; loop bits in - try loop bits - with - End_of_file -> () + try loop bits with + | End_of_file -> () (* Determine the endianness (at runtime) from the magic number. *) and endian_of = function @@ -45,11 +43,9 @@ and libpcap_header bits = snaplen : 32 : endian (endian_of magic); (* max length of capt pckts *) network : 32 : endian (endian_of magic); (* data link layer type *) rest : -1 : bitstring - |} -> - endian_of magic, (major, minor, timezone, snaplen, network), rest - - | {|_|} -> - failwith "not a libpcap/tcpdump packet capture file" + |} + -> endian_of magic, (major, minor, timezone, snaplen, network), rest + | {|_|} -> failwith "not a libpcap/tcpdump packet capture file" and libpcap_packet e file_header bits = match%bitstring bits with @@ -59,15 +55,13 @@ and libpcap_packet e file_header bits = orig_len : 32 : endian (e); (* packet length originally on wire *) pkt_data : Int32.to_int incl_len*8 : bitstring; rest : -1 : bitstring - |} -> - (ts_sec, ts_usec, incl_len, orig_len), pkt_data, rest - - | {|_|} -> raise End_of_file + |} + -> (ts_sec, ts_usec, incl_len, orig_len), pkt_data, rest + | {|_|} -> raise End_of_file and decode_and_print_packet file_header pkt_header pkt_data = - let (ts_sec, ts_usec, _, orig_len) = pkt_header in + let ts_sec, ts_usec, _, orig_len = pkt_header in printf "%ld.%ld %ldB " ts_sec ts_usec orig_len; - (* Assume an ethernet frame containing an IPv4/6 packet. We ignore * the ethertype field and determine the IP version from the packet * itself. If it doesn't match our assumptions, hexdump it. @@ -77,37 +71,33 @@ and decode_and_print_packet file_header pkt_header pkt_data = s0 : 8; s1 : 8; s2 : 8; s3 : 8; s4 : 8; s5 : 8; (* ether src *) _ : 16; (* ethertype *) packet : -1 : bitstring (* payload *) - |} -> - printf "%x:%x:%x:%x:%x:%x < %x:%x:%x:%x:%x:%x " - d0 d1 d2 d3 d4 d5 s0 s1 s2 s3 s4 s5; - - (match%bitstring packet with - | {|4 : 4; (* IPv4 *) + |} + -> + printf "%x:%x:%x:%x:%x:%x < %x:%x:%x:%x:%x:%x " d0 d1 d2 d3 d4 d5 s0 s1 s2 s3 s4 s5; + (match%bitstring packet with + | {|4 : 4; (* IPv4 *) hdrlen : 4; tos : 8; length : 16; identification : 16; flags : 3; fragoffset : 13; ttl : 8; protocol : 8; checksum : 16; s0 : 8; s1 : 8; s2 : 8; s3 : 8; d0 : 8; d1 : 8; d2 : 8; d3 : 8; _(*options*) : (hdrlen-5)*32 : bitstring; - _(*payload*) : -1 : bitstring|} -> - printf "IPv4 %d.%d.%d.%d < %d.%d.%d.%d " - s0 s1 s2 s3 d0 d1 d2 d3 - - | {|6 : 4; (* IPv6 *) + _(*payload*) : -1 : bitstring|} + -> printf "IPv4 %d.%d.%d.%d < %d.%d.%d.%d " s0 s1 s2 s3 d0 d1 d2 d3 + | {|6 : 4; (* IPv6 *) tclass : 8; flow : 20; length : 16; nexthdr : 8; ttl : 8; _(*source*) : 128 : bitstring; _(*dest*) : 128 : bitstring; - _(*payload*) : -1 : bitstring|} -> - printf "IPv6 "; - - | {|_|} -> - printf "\n"; Bitstring.hexdump_bitstring stdout packet - ) - + _(*payload*) : -1 : bitstring|} + -> printf "IPv6 " + | {|_|} -> + printf "\n"; + Bitstring.hexdump_bitstring stdout packet) | {|_|} -> - printf "\n"; Bitstring.hexdump_bitstring stdout pkt_data - ); + printf "\n"; + Bitstring.hexdump_bitstring stdout pkt_data); printf "\n" +;; let () = main () diff --git a/examples/make_ipv4_header.ml b/examples/make_ipv4_header.ml index f9940d4..6b68121 100644 --- a/examples/make_ipv4_header.ml +++ b/examples/make_ipv4_header.ml @@ -5,19 +5,19 @@ open Printf let version = 4 -let hdrlen = 5 (* no options *) +let hdrlen = 5 (* no options *) let tos = 16 -let length = 64 (* total packet length *) +let length = 64 (* total packet length *) let identification = 0 let flags = 0 let fragoffset = 0 let ttl = 255 -let protocol = 17 (* UDP *) +let protocol = 17 (* UDP *) let checksum = 0 -let source = 0xc0a80202_l (* 192.168.2.2 *) -let dest = 0xc0a80201_l (* 192.168.2.1 *) +let source = 0xc0a80202_l (* 192.168.2.2 *) +let dest = 0xc0a80201_l (* 192.168.2.1 *) let options = Bitstring.empty_bitstring -let payload_length = (length - hdrlen*4) * 8 +let payload_length = (length - (hdrlen * 4)) * 8 let payload = Bitstring.create_bitstring payload_length let%bitstring header = @@ -27,5 +27,6 @@ let%bitstring header = ttl : 8; protocol : 8; checksum : 16; source : 32; dest : 32 |} +;; let () = Bitstring.bitstring_to_file header "ipv4_header_out.dat" diff --git a/examples/ping.ml b/examples/ping.ml index 3d918c9..d4a0aa4 100644 --- a/examples/ping.ml +++ b/examples/ping.ml @@ -13,8 +13,8 @@ let display pkt = source : 32; dest : 32; options : (hdrlen-5)*32 : bitstring; - payload : -1 : bitstring|} -> - + payload : -1 : bitstring|} + -> printf "IPv4:\n"; printf " header length: %d * 32 bit words\n" hdrlen; printf " type of service: %d\n" tos; @@ -30,14 +30,13 @@ let display pkt = Bitstring.hexdump_bitstring stdout options; printf " packet payload:\n"; Bitstring.hexdump_bitstring stdout payload - (* IPv6 packet header *) | {|6 : 4; tclass : 8; flow : 20; length : 16; nexthdr : 8; ttl : 8; source : 128 : bitstring; dest : 128 : bitstring; - payload : -1 : bitstring|} -> - + payload : -1 : bitstring|} + -> printf "IPv6:\n"; printf " traffic class: %d\n" tclass; printf " flow label: %d\n" flow; @@ -50,18 +49,18 @@ let display pkt = Bitstring.hexdump_bitstring stdout dest; printf "packet payload:\n"; Bitstring.hexdump_bitstring stdout payload - | {|version : 4|} -> eprintf "unknown IP version %d\n" version; exit 1 - | {|_|} as pkt -> eprintf "data is smaller than one nibble:\n"; Bitstring.hexdump_bitstring stderr pkt; exit 1 +;; let () = let pkt = Bitstring.bitstring_of_file "ping.ipv4" in display pkt; let pkt = Bitstring.bitstring_of_file "ping.ipv6" in display pkt +;; diff --git a/ppx/dune b/ppx/dune index f0fda4a..f2781f8 100644 --- a/ppx/dune +++ b/ppx/dune @@ -3,4 +3,5 @@ (public_name ppx_bitstring) (kind ppx_rewriter) (libraries str compiler-libs ppxlib) - (preprocess (pps ppxlib.metaquot))) + (preprocess + (pps ppxlib.metaquot))) diff --git a/ppx/ppx_bitstring.ml b/ppx/ppx_bitstring.ml index 3717b63..f1a6033 100644 --- a/ppx/ppx_bitstring.ml +++ b/ppx/ppx_bitstring.ml @@ -20,50 +20,50 @@ open Ast_builder.Default (* Exception *) -let location_exn ~loc msg = - Location.raise_errorf ~loc "%s" msg -;; +let location_exn ~loc msg = Location.raise_errorf ~loc "%s" msg (* Type definition *) module Entity = struct - type t = { - txt : string; - exp : Parsetree.expression; - pat : Parsetree.pattern - } + type t = + { txt : string + ; exp : Parsetree.expression + ; pat : Parsetree.pattern + } let mksym = let i = ref 1000 in fun name -> - incr i; let i = !i in + incr i; + let i = !i in sprintf "__ppxbitstring_%s_%d" name i ;; let make ~loc v = let txt = mksym v in { txt; exp = evar ~loc txt; pat = pvar ~loc txt } + ;; end module Context = struct - type t = { - dat : Entity.t; - off : Entity.t; - len : Entity.t - } + type t = + { dat : Entity.t + ; off : Entity.t + ; len : Entity.t + } let make ~loc = let dat = Entity.make ~loc "dat" and off = Entity.make ~loc "off" - and len = Entity.make ~loc "len" - in + and len = Entity.make ~loc "len" in { dat; off; len } + ;; let next ~loc t = let off = Entity.make ~loc "off" - and len = Entity.make ~loc "len" - in + and len = Entity.make ~loc "len" in { t with off; len } + ;; end module Type = struct @@ -81,6 +81,7 @@ module Sign = struct let to_string = function | Signed -> "signed" | Unsigned -> "unsigned" + ;; end module Endian = struct @@ -95,171 +96,169 @@ module Endian = struct | Big -> "be" | Native -> "ne" | Referred _ -> "ee" + ;; end module Qualifiers = struct - type t = { - value_type : Type.t option; - sign : Sign.t option; - endian : Endian.t option; - check : Parsetree.expression option; - bind : Parsetree.expression option; - map : Parsetree.expression option; - save_offset_to : Parsetree.expression option; - offset : Parsetree.expression option; - } - - let empty = { - value_type = None; - sign = None; - endian = None; - check = None; - bind = None; - map = None; - save_offset_to = None; - offset = None; - } - - let default = { - value_type = Some Type.Int; - sign = Some Sign.Unsigned; - endian = Some Endian.Big; - check = None; - bind = None; - map = None; - save_offset_to = None; - offset = None; - } + type t = + { value_type : Type.t option + ; sign : Sign.t option + ; endian : Endian.t option + ; check : Parsetree.expression option + ; bind : Parsetree.expression option + ; map : Parsetree.expression option + ; save_offset_to : Parsetree.expression option + ; offset : Parsetree.expression option + } + + let empty = + { value_type = None + ; sign = None + ; endian = None + ; check = None + ; bind = None + ; map = None + ; save_offset_to = None + ; offset = None + } + ;; + + let default = + { value_type = Some Type.Int + ; sign = Some Sign.Unsigned + ; endian = Some Endian.Big + ; check = None + ; bind = None + ; map = None + ; save_offset_to = None + ; offset = None + } + ;; let set_value_type_default q = match q.value_type with - | None -> { q with value_type = Some Type.Int } - | _ -> q + | None -> { q with value_type = Some Type.Int } + | _ -> q ;; let set_sign_default q = match q.sign with - | None -> { q with sign = Some Sign.Unsigned } - | _ -> q + | None -> { q with sign = Some Sign.Unsigned } + | _ -> q ;; let set_endian_default q = match q.endian with - | None -> { q with endian = Some Endian.Big } - | _ -> q + | None -> { q with endian = Some Endian.Big } + | _ -> q ;; let set_defaults v = - v - |> set_value_type_default - |> set_sign_default - |> set_endian_default + v |> set_value_type_default |> set_sign_default |> set_endian_default ;; end module MatchField = struct - type bitlen = - (Parsetree.expression * int option) - ;; + type bitlen = Parsetree.expression * int option - type tuple = { - pat : Parsetree.pattern; - len : bitlen; - qls : Qualifiers.t; - opt : bool - } + type tuple = + { pat : Parsetree.pattern + ; len : bitlen + ; qls : Qualifiers.t + ; opt : bool + } type t = | Any of Parsetree.pattern | Tuple of tuple - ;; - let as_evar v = + let as_evar v = match v.pat with - | {ppat_desc = Ppat_var(v); _} -> evar ~loc:v.loc v.txt - | {ppat_loc; _} -> location_exn ~loc:ppat_loc "Pattern is not a variable" + | { ppat_desc = Ppat_var v; _ } -> evar ~loc:v.loc v.txt + | { ppat_loc; _ } -> location_exn ~loc:ppat_loc "Pattern is not a variable" + ;; end (* Helper functions *) -let split_string ~on s = - Str.split (Str.regexp on) s -;; +let split_string ~on s = Str.split (Str.regexp on) s let option_bind opt f = match opt with - | None -> None + | None -> None | Some v -> f v ;; let rec process_expr_loc ~loc expr = match expr with - | { pexp_desc = Pexp_ident(ident); _ } -> + | { pexp_desc = Pexp_ident ident; _ } -> let lident = Loc.make ~loc ident.txt in - { expr with pexp_desc = Pexp_ident(lident); pexp_loc = loc } - | { pexp_desc = Pexp_tuple(ops); _ } -> - let fld = List.fold_left - (fun acc exp -> acc @ [ process_expr_loc ~loc exp ]) - [] - ops - in { expr with pexp_desc = Pexp_tuple(fld); pexp_loc = loc } - | { pexp_desc = Pexp_construct(ident, ops); _ } -> + { expr with pexp_desc = Pexp_ident lident; pexp_loc = loc } + | { pexp_desc = Pexp_tuple ops; _ } -> + let fld = + List.fold_left (fun acc exp -> acc @ [ process_expr_loc ~loc exp ]) [] ops + in + { expr with pexp_desc = Pexp_tuple fld; pexp_loc = loc } + | { pexp_desc = Pexp_construct (ident, ops); _ } -> let lident = Loc.make ident.txt ~loc in - let lops = begin match ops with + let lops = + match ops with | Some o -> Some (process_expr_loc ~loc o) - | None -> None - end in - { expr with pexp_desc = Pexp_construct(lident, lops); pexp_loc = loc } - | { pexp_desc = Pexp_apply(ident, ops); _ } -> + | None -> None + in + { expr with pexp_desc = Pexp_construct (lident, lops); pexp_loc = loc } + | { pexp_desc = Pexp_apply (ident, ops); _ } -> let lident = process_expr_loc ~loc ident in - let fld = List.fold_left - (fun acc (lbl, exp) -> acc @ [ (lbl, (process_expr_loc ~loc exp)) ]) + let fld = + List.fold_left + (fun acc (lbl, exp) -> acc @ [ lbl, process_expr_loc ~loc exp ]) [] ops - in { expr with pexp_desc = Pexp_apply(lident, fld); pexp_loc = loc } - | { pexp_desc = Pexp_function(params, constraint_, Pfunction_body exp); _ } -> - let lparams = List.map (process_param_loc ~loc) params in - let lexp = process_expr_loc ~loc exp in - { expr with pexp_desc = Pexp_function (lparams, constraint_, Pfunction_body lexp); pexp_loc = loc } - | _ -> - { expr with pexp_loc = loc } - -and process_param_loc ~loc (param : function_param) = match param.pparam_desc with - | Pparam_val (ident, ops, { ppat_desc = Ppat_var pid; ppat_attributes; _ }) -> ( + in + { expr with pexp_desc = Pexp_apply (lident, fld); pexp_loc = loc } + | { pexp_desc = Pexp_function (params, constraint_, Pfunction_body exp); _ } -> + let lparams = List.map (process_param_loc ~loc) params in + let lexp = process_expr_loc ~loc exp in + { expr with + pexp_desc = Pexp_function (lparams, constraint_, Pfunction_body lexp) + ; pexp_loc = loc + } + | _ -> { expr with pexp_loc = loc } + +and process_param_loc ~loc (param : function_param) = + match param.pparam_desc with + | Pparam_val (ident, ops, { ppat_desc = Ppat_var pid; ppat_attributes; _ }) -> let lpid = Loc.make pid.txt ~loc in - let lpat = { ppat_desc = Ppat_var lpid; ppat_loc = loc; ppat_attributes; ppat_loc_stack = [] } in - let lops = begin match ops with + let lpat = + { ppat_desc = Ppat_var lpid; ppat_loc = loc; ppat_attributes; ppat_loc_stack = [] } + in + let lops = + match ops with | Some o -> Some (process_expr_loc ~loc o) - | None -> None - end in + | None -> None + in { param with pparam_desc = Pparam_val (ident, lops, lpat) } - ) | _ -> param ;; let parse_expr expr = try - Parse.expression (Lexing.from_string expr.txt) - |> process_expr_loc ~loc:expr.loc + Parse.expression (Lexing.from_string expr.txt) |> process_expr_loc ~loc:expr.loc with - _ -> location_exn ~loc:expr.loc ("Parse expression error: '" ^ expr.txt ^ "'") + | _ -> location_exn ~loc:expr.loc ("Parse expression error: '" ^ expr.txt ^ "'") ;; let process_pat_loc ~loc pat = match pat with - | { ppat_desc = Ppat_var(ident); ppat_loc; ppat_attributes; _ } -> + | { ppat_desc = Ppat_var ident; ppat_loc; ppat_attributes; _ } -> let lident = Loc.make ident.txt ~loc in - { ppat_desc = Ppat_var(lident); ppat_loc = loc; ppat_attributes; ppat_loc_stack = [] } - | _ -> - { pat with ppat_loc = loc } + { ppat_desc = Ppat_var lident; ppat_loc = loc; ppat_attributes; ppat_loc_stack = [] } + | _ -> { pat with ppat_loc = loc } ;; let parse_pattern pat = - try - Parse.pattern (Lexing.from_string pat.txt) - |> process_pat_loc ~loc:pat.loc - with - _ -> location_exn ~loc:pat.loc ("Parse pattern error: '" ^ pat.txt ^ "'") + try Parse.pattern (Lexing.from_string pat.txt) |> process_pat_loc ~loc:pat.loc with + | _ -> location_exn ~loc:pat.loc ("Parse pattern error: '" ^ pat.txt ^ "'") ;; (* Location parser and splitter *) @@ -268,52 +267,49 @@ let find_loc_boundaries ~loc last rem = let open Location in let { loc_start; loc_end; loc_ghost } = loc in let xtr_lines = List.length rem in - let xtr_char = List.fold_left (+) xtr_lines rem in - let ne = { loc_start with - pos_lnum = loc_start.pos_lnum + xtr_lines; - pos_bol = loc_start.pos_bol + xtr_char; - pos_cnum = loc_start.pos_cnum + xtr_char + last - } - and ns = if xtr_lines = 0 - then { loc_start with - pos_cnum = loc_start.pos_cnum + xtr_char + last + 1 - } - else { loc_start with - pos_lnum = loc_start.pos_lnum + xtr_lines; - pos_bol = loc_start.pos_bol + xtr_char; - pos_cnum = loc_start.pos_cnum + xtr_char - } in + let xtr_char = List.fold_left ( + ) xtr_lines rem in + let ne = + { loc_start with + pos_lnum = loc_start.pos_lnum + xtr_lines + ; pos_bol = loc_start.pos_bol + xtr_char + ; pos_cnum = loc_start.pos_cnum + xtr_char + last + } + and ns = + if xtr_lines = 0 + then { loc_start with pos_cnum = loc_start.pos_cnum + xtr_char + last + 1 } + else + { loc_start with + pos_lnum = loc_start.pos_lnum + xtr_lines + ; pos_bol = loc_start.pos_bol + xtr_char + ; pos_cnum = loc_start.pos_cnum + xtr_char + } + in let tloc = { loc_start; loc_end = ne; loc_ghost } in let nloc = { loc_start = ns; loc_end; loc_ghost } in - (tloc, nloc) + tloc, nloc ;; let rec split_loc_rec ~loc = function | [] -> [] | hd :: tl -> - let line_list = split_string ~on:"\n" hd - |> List.rev - |> List.map String.length in - begin - match line_list with - | [] -> [] - | last::rem -> - let (tloc, nloc) = find_loc_boundaries ~loc last rem in - [ tloc ] @ (split_loc_rec ~loc:nloc tl) - end + let line_list = split_string ~on:"\n" hd |> List.rev |> List.map String.length in + (match line_list with + | [] -> [] + | last :: rem -> + let tloc, nloc = find_loc_boundaries ~loc last rem in + [ tloc ] @ split_loc_rec ~loc:nloc tl) ;; let split_loc ~loc lst = - split_loc_rec ~loc lst - |> List.map2 (fun e loc -> Loc.make (String.trim e) ~loc) lst + split_loc_rec ~loc lst |> List.map2 (fun e loc -> Loc.make (String.trim e) ~loc) lst ;; (* Processing qualifiers *) let check_map_functor sub = match sub with - | [%expr (fun [%p? _] -> [%e? _])] -> Some (sub) - | _ -> None + | [%expr fun [%p? _] -> [%e? _]] -> Some sub + | _ -> None ;; let process_qual state qual = @@ -321,85 +317,69 @@ let process_qual state qual = let loc = qual.pexp_loc in match qual with | [%expr int] -> - begin match state.value_type with - | Some v -> location_exn ~loc "Value type redefined" - | None -> { state with value_type = Some Type.Int } - end + (match state.value_type with + | Some v -> location_exn ~loc "Value type redefined" + | None -> { state with value_type = Some Type.Int }) | [%expr string] -> - begin match state.value_type with - | Some v -> location_exn ~loc "Value type redefined" - | None -> { state with value_type = Some Type.String } - end + (match state.value_type with + | Some v -> location_exn ~loc "Value type redefined" + | None -> { state with value_type = Some Type.String }) | [%expr bitstring] -> - begin match state.value_type with - | Some v -> location_exn ~loc "Value type redefined" - | None -> { state with value_type = Some Type.Bitstring } - end + (match state.value_type with + | Some v -> location_exn ~loc "Value type redefined" + | None -> { state with value_type = Some Type.Bitstring }) | [%expr signed] -> - begin match state.sign with - | Some v -> location_exn ~loc "Signedness redefined" - | None -> { state with sign = Some Sign.Signed } - end + (match state.sign with + | Some v -> location_exn ~loc "Signedness redefined" + | None -> { state with sign = Some Sign.Signed }) | [%expr unsigned] -> - begin match state.sign with - | Some v -> location_exn ~loc "Signedness redefined" - | None -> { state with sign = Some Sign.Unsigned } - end + (match state.sign with + | Some v -> location_exn ~loc "Signedness redefined" + | None -> { state with sign = Some Sign.Unsigned }) | [%expr littleendian] -> - begin match state.endian with - | Some v -> location_exn ~loc "Endianness redefined" - | None -> { state with endian = Some Endian.Little } - end + (match state.endian with + | Some v -> location_exn ~loc "Endianness redefined" + | None -> { state with endian = Some Endian.Little }) | [%expr bigendian] -> - begin match state.endian with - | Some v -> location_exn ~loc "Endianness redefined" - | None -> { state with endian = Some Endian.Big } - end + (match state.endian with + | Some v -> location_exn ~loc "Endianness redefined" + | None -> { state with endian = Some Endian.Big }) | [%expr nativeendian] -> - begin match state.endian with - | Some v -> location_exn ~loc "Endianness redefined" - | None -> { state with endian = Some Endian.Native } - end + (match state.endian with + | Some v -> location_exn ~loc "Endianness redefined" + | None -> { state with endian = Some Endian.Native }) | [%expr endian [%e? sub]] -> - begin match state.endian with - | Some v -> location_exn ~loc "Endianness redefined" - | None -> { state with endian = Some (Endian.Referred sub) } - end + (match state.endian with + | Some v -> location_exn ~loc "Endianness redefined" + | None -> { state with endian = Some (Endian.Referred sub) }) | [%expr bind [%e? sub]] -> - begin match state.bind, state.map with - | Some b, None -> location_exn ~loc "Bind expression redefined" - | None, Some m -> location_exn ~loc "Map expression already defined" - | Some b, Some m -> location_exn ~loc "Inconsistent internal state" - | None, None -> { state with bind = Some sub } - end + (match state.bind, state.map with + | Some b, None -> location_exn ~loc "Bind expression redefined" + | None, Some m -> location_exn ~loc "Map expression already defined" + | Some b, Some m -> location_exn ~loc "Inconsistent internal state" + | None, None -> { state with bind = Some sub }) | [%expr map [%e? sub]] -> - begin match state.bind, state.map with - | Some b, None -> location_exn ~loc "Bind expression already defined" - | None, Some m -> location_exn ~loc "Map expression redefined" - | Some b, Some m -> location_exn ~loc "Inconsistent internal state" - | None, None -> begin - match check_map_functor sub with - | Some sub -> { state with map = Some sub } - | None -> location_exn ~loc "Invalid map functor" - end - end + (match state.bind, state.map with + | Some b, None -> location_exn ~loc "Bind expression already defined" + | None, Some m -> location_exn ~loc "Map expression redefined" + | Some b, Some m -> location_exn ~loc "Inconsistent internal state" + | None, None -> + (match check_map_functor sub with + | Some sub -> { state with map = Some sub } + | None -> location_exn ~loc "Invalid map functor")) | [%expr check [%e? sub]] -> - begin match state.check with - | Some v -> location_exn ~loc "Check expression redefined" - | None -> { state with check = Some sub } - end + (match state.check with + | Some v -> location_exn ~loc "Check expression redefined" + | None -> { state with check = Some sub }) | [%expr save_offset_to [%e? sub]] -> - begin match state.save_offset_to with - | Some v -> location_exn ~loc "Save offset expression redefined" - | None -> { state with save_offset_to = Some sub } - end + (match state.save_offset_to with + | Some v -> location_exn ~loc "Save offset expression redefined" + | None -> { state with save_offset_to = Some sub }) | [%expr offset [%e? sub]] -> - begin match state.offset with - | Some v -> location_exn ~loc "Offset expression redefined" - | None -> { state with offset = Some sub } - end - | _ -> - location_exn ~loc "Invalid qualifier" + (match state.offset with + | Some v -> location_exn ~loc "Offset expression redefined" + | None -> { state with offset = Some sub }) + | _ -> location_exn ~loc "Invalid qualifier" ;; let parse_quals quals = @@ -407,79 +387,65 @@ let parse_quals quals = let rec process_quals state = function | [] -> state | hd :: tl -> process_quals (process_qual state hd) tl - in match expr with + in + match expr with (* single named qualifiers *) - | { pexp_desc = Pexp_ident (_); _ } -> - process_qual Qualifiers.empty expr + | { pexp_desc = Pexp_ident _; _ } -> process_qual Qualifiers.empty expr (* single functional qualifiers *) - | { pexp_desc = Pexp_apply (_, _); _ } -> - process_qual Qualifiers.empty expr + | { pexp_desc = Pexp_apply (_, _); _ } -> process_qual Qualifiers.empty expr (* multiple qualifiers *) - | { pexp_desc = Pexp_tuple (e); _ } -> - process_quals Qualifiers.empty e + | { pexp_desc = Pexp_tuple e; _ } -> process_quals Qualifiers.empty e (* Unrecognized expression *) - | expr -> - location_exn ~loc:expr.pexp_loc "Invalid qualifiers list" + | expr -> location_exn ~loc:expr.pexp_loc "Invalid qualifiers list" ;; (* Processing expression *) let rec evaluate_expr = function | [%expr [%e? lhs] + [%e? rhs]] -> - begin match evaluate_expr lhs, evaluate_expr rhs with - | Some l, Some r -> Some (l + r) - | _ -> None - end + (match evaluate_expr lhs, evaluate_expr rhs with + | Some l, Some r -> Some (l + r) + | _ -> None) | [%expr [%e? lhs] - [%e? rhs]] -> - begin match evaluate_expr lhs, evaluate_expr rhs with - | Some l, Some r -> Some (l - r) - | _ -> None - end + (match evaluate_expr lhs, evaluate_expr rhs with + | Some l, Some r -> Some (l - r) + | _ -> None) | [%expr [%e? lhs] * [%e? rhs]] -> - begin match evaluate_expr lhs, evaluate_expr rhs with - | Some l, Some r -> Some (l * r) - | _ -> None - end + (match evaluate_expr lhs, evaluate_expr rhs with + | Some l, Some r -> Some (l * r) + | _ -> None) | [%expr [%e? lhs] / [%e? rhs]] -> - begin match evaluate_expr lhs, evaluate_expr rhs with - | Some l, Some r -> Some (l / r) - | _ -> None - end + (match evaluate_expr lhs, evaluate_expr rhs with + | Some l, Some r -> Some (l / r) + | _ -> None) | [%expr [%e? lhs] land [%e? rhs]] -> - begin match evaluate_expr lhs, evaluate_expr rhs with - | Some l, Some r -> Some (l land r) - | _ -> None - end + (match evaluate_expr lhs, evaluate_expr rhs with + | Some l, Some r -> Some (l land r) + | _ -> None) | [%expr [%e? lhs] lor [%e? rhs]] -> - begin match evaluate_expr lhs, evaluate_expr rhs with - | Some l, Some r -> Some (l lor r) - | _ -> None - end + (match evaluate_expr lhs, evaluate_expr rhs with + | Some l, Some r -> Some (l lor r) + | _ -> None) | [%expr [%e? lhs] lxor [%e? rhs]] -> - begin match evaluate_expr lhs, evaluate_expr rhs with - | Some l, Some r -> Some (l lxor r) - | _ -> None - end + (match evaluate_expr lhs, evaluate_expr rhs with + | Some l, Some r -> Some (l lxor r) + | _ -> None) | [%expr [%e? lhs] lsr [%e? rhs]] -> - begin match evaluate_expr lhs, evaluate_expr rhs with - | Some l, Some r -> Some (l lsr r) - | _ -> None - end + (match evaluate_expr lhs, evaluate_expr rhs with + | Some l, Some r -> Some (l lsr r) + | _ -> None) | [%expr [%e? lhs] asr [%e? rhs]] -> - begin match evaluate_expr lhs, evaluate_expr rhs with - | Some l, Some r -> Some (l asr r) - | _ -> None - end + (match evaluate_expr lhs, evaluate_expr rhs with + | Some l, Some r -> Some (l asr r) + | _ -> None) | [%expr [%e? lhs] mod [%e? rhs]] -> - begin match evaluate_expr lhs, evaluate_expr rhs with - | Some l, Some r -> Some (l mod r) - | _ -> None - end - | { pexp_desc = Pexp_constant (const); _ } -> - begin match const with - | Pconst_integer(i, _) -> Some (int_of_string i) - | _ -> None - end + (match evaluate_expr lhs, evaluate_expr rhs with + | Some l, Some r -> Some (l mod r) + | _ -> None) + | { pexp_desc = Pexp_constant const; _ } -> + (match const with + | Pconst_integer (i, _) -> Some (int_of_string i) + | _ -> None) | _ -> None ;; @@ -490,27 +456,25 @@ let parse_match_fields str = split_string ~on:":" str.txt |> split_loc ~loc:str.loc |> function - | [ { txt = "_" ; loc } as pat ] -> - MatchField.Any (parse_pattern pat) + | [ ({ txt = "_"; loc } as pat) ] -> MatchField.Any (parse_pattern pat) | [ spat; slen ] -> let qls = Qualifiers.default and eln = parse_expr slen and pat = parse_pattern spat and opt = false in - let len = (eln, evaluate_expr eln) in + let len = eln, evaluate_expr eln in MatchField.Tuple { pat; len; qls; opt } | [ spat; slen; sqls ] -> let qls = Qualifiers.set_defaults (parse_quals sqls) and eln = parse_expr slen and pat = parse_pattern spat and opt = false in - let len = (eln, evaluate_expr eln) in + let len = eln, evaluate_expr eln in MatchField.Tuple { pat; len; qls; opt } | [ stmt ] -> let pat_str = stmt.txt in location_exn ~loc:stmt.loc ("Invalid statement: '" ^ pat_str ^ "'") - | _ -> - location_exn ~loc:str.loc "Invalid number of fields in statement" + | _ -> location_exn ~loc:str.loc "Invalid number of fields in statement" ;; (* @@ -525,6 +489,7 @@ let stitch_ambiguous_operators lst = | l -> e :: l in List.fold_right fn lst [] +;; let parse_const_fields str = let open Qualifiers in @@ -532,230 +497,205 @@ let parse_const_fields str = |> stitch_ambiguous_operators |> split_loc ~loc:str.loc |> function - | [ vl; len ] -> - (parse_expr vl, Some (parse_expr len), Some Qualifiers.default) + | [ vl; len ] -> parse_expr vl, Some (parse_expr len), Some Qualifiers.default | [ vl; len; quals ] -> let q = Qualifiers.set_defaults (parse_quals quals) in - begin match q.bind, q.map, q.check, q.save_offset_to with - | Some _, _, _, _ -> - location_exn ~loc:str.loc "Bind meaningless in constructor" - | _, Some _, _, _ -> - location_exn ~loc:str.loc "Map meaningless in constructor" - | _, _, Some _, _ -> - location_exn ~loc:str.loc "Check meaningless in constructor" - | _, _, _, Some _ -> - location_exn ~loc:str.loc "Saving offset meaningless in constructor" - | None, None, None, None -> - (parse_expr vl, Some (parse_expr len), Some (q)) - end + (match q.bind, q.map, q.check, q.save_offset_to with + | Some _, _, _, _ -> location_exn ~loc:str.loc "Bind meaningless in constructor" + | _, Some _, _, _ -> location_exn ~loc:str.loc "Map meaningless in constructor" + | _, _, Some _, _ -> location_exn ~loc:str.loc "Check meaningless in constructor" + | _, _, _, Some _ -> + location_exn ~loc:str.loc "Saving offset meaningless in constructor" + | None, None, None, None -> parse_expr vl, Some (parse_expr len), Some q) | [ stmt ] -> let pat_str = stmt.txt in location_exn ~loc:stmt.loc ("Invalid statement: '" ^ pat_str ^ "'") - | _ -> - location_exn ~loc:str.loc "Invalid number of fields in statement" + | _ -> location_exn ~loc:str.loc "Invalid number of fields in statement" ;; (* Match generators *) let check_field_len ~loc fld = - let (l, v) = fld.MatchField.len - in + let l, v = fld.MatchField.len in match v, fld.MatchField.qls.Qualifiers.value_type with - | Some (n), Some (Type.String) -> - if n < -1 || (n > 0 && (n mod 8) <> 0) then - location_exn ~loc "Length of string must be > 0 and multiple of 8, or the special value -1" + | Some n, Some Type.String -> + if n < -1 || (n > 0 && n mod 8 <> 0) + then + location_exn + ~loc + "Length of string must be > 0 and multiple of 8, or the special value -1" else Some n - | Some (n), Some (Type.Bitstring) -> - if n < -1 then location_exn ~loc "Length of bitstring must be >= 0 or the special value -1" + | Some n, Some Type.Bitstring -> + if n < -1 + then location_exn ~loc "Length of bitstring must be >= 0 or the special value -1" else Some n - | Some (n), Some (Type.Int) -> - if n < 1 || n > 64 then location_exn ~loc "Length of int field must be [1..64]" + | Some n, Some Type.Int -> + if n < 1 || n > 64 + then location_exn ~loc "Length of int field must be [1..64]" else Some n - | None, Some (_) -> None + | None, Some _ -> None | _, None -> location_exn ~loc "No type to check" ;; let get_inttype ~loc ~fastpath = function - | v when v > 8 && v <= 16 -> if fastpath then "int16" else "int" + | v when v > 8 && v <= 16 -> if fastpath then "int16" else "int" | v when v > 16 && v <= 31 -> if fastpath then "int32" else "int" | v when v = 32 -> "int32" | v when v > 32 && v <= 64 -> "int64" | _ -> location_exn ~loc "Invalid integer size" +;; let gen_int_extractor_static ~loc nxt size sign endian = let edat = nxt.Context.dat.Entity.exp - and eoff = nxt.Context.off.Entity.exp - in + and eoff = nxt.Context.off.Entity.exp in let sn = Sign.to_string sign and ft = get_inttype ~loc ~fastpath:true size and en = Endian.to_string endian in - let fp = sprintf "Bitstring.extract_fastpath_%s_%s_%s" ft en sn - in - [%expr - [%e evar ~loc fp] [%e edat] ([%e eoff] lsr 3)] - [@metaloc loc] + let fp = sprintf "Bitstring.extract_fastpath_%s_%s_%s" ft en sn in + ([%expr [%e evar ~loc fp] [%e edat] ([%e eoff] lsr 3)] [@metaloc loc]) ;; let gen_int_extractor_dynamic ~loc nxt size sign endian = let edat = nxt.Context.dat.Entity.exp and eoff = nxt.Context.off.Entity.exp - and elen = nxt.Context.len.Entity.exp - in + and elen = nxt.Context.len.Entity.exp in let sn = Sign.to_string sign and it = get_inttype ~loc ~fastpath:false size and en = Endian.to_string endian in - let ex = sprintf "Bitstring.extract_%s_%s_%s" it en sn - in - [%expr [%e evar ~loc ex] [%e edat] [%e eoff] [%e elen] [%e eint ~loc size]] - [@metaloc loc] + let ex = sprintf "Bitstring.extract_%s_%s_%s" it en sn in + ([%expr [%e evar ~loc ex] [%e edat] [%e eoff] [%e elen] [%e eint ~loc size]] + [@metaloc loc]) ;; let gen_int_extractor ~loc nxt fld = let open Qualifiers in - let (l, v) = fld.MatchField.len - in + let l, v = fld.MatchField.len in let edat = nxt.Context.dat.Entity.exp and eoff = nxt.Context.off.Entity.exp - and elen = nxt.Context.len.Entity.exp - in + and elen = nxt.Context.len.Entity.exp in match v, fld.MatchField.qls.sign, fld.MatchField.qls.endian with - (* 1-bit type *) - | Some (size), Some (_), Some (_) when size = 1 -> - [%expr - Bitstring.extract_bit [%e edat] [%e eoff] [%e elen] [%e l]] - [@metaloc loc] - (* 8-bit type *) - | Some (size), Some (sign), Some (_) when size >= 2 && size <= 8 -> - let ex = sprintf "Bitstring.extract_char_%s" (Sign.to_string sign) - in - [%expr - [%e evar ~loc ex] [%e edat] [%e eoff] [%e elen] [%e eint ~loc size]] - [@metaloc loc] - (* 16|32|64-bit type with referred endianness *) - | Some (size), Some (sign), Some (Endian.Referred r) -> - let ss = Sign.to_string sign - and it = get_inttype ~loc ~fastpath:false size in - let ex = sprintf "Bitstring.extract_%s_ee_%s" it ss - in - [%expr - [%e evar ~loc ex] ([%e r]) [%e edat] [%e eoff] [%e elen] [%e eint ~loc size]] - [@metaloc loc] - (* 16|32|64-bit type with immediate endianness *) - | Some (size), Some (sign), Some (endian) -> - if fld.MatchField.opt then - gen_int_extractor_static ~loc nxt size sign endian - else - gen_int_extractor_dynamic ~loc nxt size sign endian - (* Variable size *) - | None, Some (sign), Some (Endian.Referred r) -> - let ss = Sign.to_string sign in - let ex = sprintf "Bitstring.extract_int64_ee_%s" ss in - [%expr - [%e evar ~loc ex] ([%e r]) [%e edat] [%e eoff] [%e elen] ([%e l])] - [@metaloc loc] - | None, Some (sign), Some (endian) -> - let es = Endian.to_string endian and ss = Sign.to_string sign in - let ex = sprintf "Bitstring.extract_int64_%s_%s" es ss in - [%expr - [%e evar ~loc ex] [%e edat] [%e eoff] [%e elen] ([%e l])] - [@metaloc loc] - (* Invalid type *) - | _, _, _ -> - location_exn ~loc "Invalid type" + (* 1-bit type *) + | Some size, Some _, Some _ when size = 1 -> + [%expr Bitstring.extract_bit [%e edat] [%e eoff] [%e elen] [%e l]] [@metaloc loc] + (* 8-bit type *) + | Some size, Some sign, Some _ when size >= 2 && size <= 8 -> + let ex = sprintf "Bitstring.extract_char_%s" (Sign.to_string sign) in + ([%expr [%e evar ~loc ex] [%e edat] [%e eoff] [%e elen] [%e eint ~loc size]] + [@metaloc loc]) + (* 16|32|64-bit type with referred endianness *) + | Some size, Some sign, Some (Endian.Referred r) -> + let ss = Sign.to_string sign + and it = get_inttype ~loc ~fastpath:false size in + let ex = sprintf "Bitstring.extract_%s_ee_%s" it ss in + ([%expr [%e evar ~loc ex] [%e r] [%e edat] [%e eoff] [%e elen] [%e eint ~loc size]] + [@metaloc loc]) + (* 16|32|64-bit type with immediate endianness *) + | Some size, Some sign, Some endian -> + if fld.MatchField.opt + then gen_int_extractor_static ~loc nxt size sign endian + else gen_int_extractor_dynamic ~loc nxt size sign endian + (* Variable size *) + | None, Some sign, Some (Endian.Referred r) -> + let ss = Sign.to_string sign in + let ex = sprintf "Bitstring.extract_int64_ee_%s" ss in + ([%expr [%e evar ~loc ex] [%e r] [%e edat] [%e eoff] [%e elen] [%e l]] [@metaloc loc]) + | None, Some sign, Some endian -> + let es = Endian.to_string endian + and ss = Sign.to_string sign in + let ex = sprintf "Bitstring.extract_int64_%s_%s" es ss in + ([%expr [%e evar ~loc ex] [%e edat] [%e eoff] [%e elen] [%e l]] [@metaloc loc]) + (* Invalid type *) + | _, _, _ -> location_exn ~loc "Invalid type" ;; let gen_extractor ~loc nxt fld = let open Qualifiers in - let (l, v) = fld.MatchField.len - in + let l, v = fld.MatchField.len in let edat = nxt.Context.dat.Entity.exp and eoff = nxt.Context.off.Entity.exp - and elen = nxt.Context.len.Entity.exp - in + and elen = nxt.Context.len.Entity.exp in match fld.MatchField.qls.value_type with - | Some (Type.Bitstring) -> begin - match v with - | Some (-1) -> - [%expr ([%e edat], [%e eoff], [%e elen])] [@metaloc loc] - | Some (_) | None -> - [%expr ([%e edat], [%e eoff], [%e l])] [@metaloc loc] - end - | Some (Type.String) -> - [%expr - (Bitstring.string_of_bitstring ([%e edat], [%e eoff], [%e l]))] - [@metaloc loc] - | Some (Type.Int) -> - gen_int_extractor ~loc nxt fld - | _ -> - location_exn ~loc "Invalid type" + | Some Type.Bitstring -> + (match v with + | Some -1 -> [%expr [%e edat], [%e eoff], [%e elen]] [@metaloc loc] + | Some _ | None -> [%expr [%e edat], [%e eoff], [%e l]] [@metaloc loc]) + | Some Type.String -> + [%expr Bitstring.string_of_bitstring ([%e edat], [%e eoff], [%e l])] [@metaloc loc] + | Some Type.Int -> gen_int_extractor ~loc nxt fld + | _ -> location_exn ~loc "Invalid type" ;; let gen_value ~loc fld res beh = let open Qualifiers in - match fld.MatchField.qls.bind, fld.MatchField.qls.map with - | Some b, None -> - [%expr let [%p fld.pat] = [%e b] in [%e beh]][@metaloc loc] - | None, Some m -> + match fld.MatchField.qls.bind, fld.MatchField.qls.map with + | Some b, None -> + [%expr + let [%p fld.pat] = [%e b] in + [%e beh]] + [@metaloc loc] + | None, Some m -> let exp = MatchField.as_evar fld in - [%expr let [%p fld.pat] = [%e m] [%e exp] in [%e beh]][@metaloc loc] + ([%expr + let [%p fld.pat] = [%e m] [%e exp] in + [%e beh]] + [@metaloc loc]) | _, _ -> beh ;; let rec gen_next ~loc cur nxt fld beh fields = let open Entity in let open Context in - let (l, v) = fld.MatchField.len in + let l, v = fld.MatchField.len in match v with - | Some (-1) -> + | Some -1 -> [%expr let [%p nxt.off.pat] = [%e nxt.off.exp] + [%e nxt.len.exp] and [%p nxt.len.pat] = 0 in - [%e (gen_fields ~loc cur nxt beh fields)]] - [@metaloc loc] - | Some (_) | None -> + [%e gen_fields ~loc cur nxt beh fields]] + [@metaloc loc] + | Some _ | None -> [%expr let [%p nxt.off.pat] = [%e nxt.off.exp] + [%e l] and [%p nxt.len.pat] = [%e nxt.len.exp] - [%e l] in - [%e (gen_fields ~loc cur nxt beh fields)]] - [@metaloc loc] + [%e gen_fields ~loc cur nxt beh fields]] + [@metaloc loc] and gen_next_all ~loc cur nxt beh fields = let open Entity in let open Context in - [%expr - let [%p nxt.off.pat] = [%e nxt.off.exp] + [%e nxt.len.exp] - and [%p nxt.len.pat] = 0 in - [%e (gen_fields ~loc cur nxt beh fields)]] - [@metaloc loc] + ([%expr + let [%p nxt.off.pat] = [%e nxt.off.exp] + [%e nxt.len.exp] + and [%p nxt.len.pat] = 0 in + [%e gen_fields ~loc cur nxt beh fields]] + [@metaloc loc]) and gen_match_check ~loc = function - | Some chk -> chk - | None -> ebool true ~loc + | Some chk -> chk + | None -> ebool true ~loc and gen_match ~loc cur nxt fld beh fields = let open Entity in let open Context in let open Qualifiers in let value = Entity.make ~loc "val" - and (l, _) = fld.MatchField.len - in + and l, _ = fld.MatchField.len in let mcheck = gen_match_check ~loc fld.MatchField.qls.check and mfields = gen_fields ~loc cur nxt beh fields - and mres = gen_extractor ~loc nxt fld + and mres = gen_extractor ~loc nxt fld in + let mwrap = gen_value ~loc fld value.exp mfields in + let mcase = + ([%expr + match [%e value.exp] with + | [%p fld.MatchField.pat] when [%e mcheck] -> [%e mwrap] + | _ -> ()] + [@metaloc loc]) in - let mwrap = gen_value ~loc fld value.exp mfields - in - let mcase = [%expr - begin match [%e value.exp] with - | [%p fld.MatchField.pat] when [%e mcheck] -> [%e mwrap] - | _ -> () - end][@metaloc loc] - in - [%expr - let [%p value.pat] = [%e mres] - and [%p nxt.off.pat] = [%e nxt.off.exp] + [%e l] - and [%p nxt.len.pat] = [%e nxt.len.exp] - [%e l] in [%e mcase]] - [@metaloc loc] + ([%expr + let [%p value.pat] = [%e mres] + and [%p nxt.off.pat] = [%e nxt.off.exp] + [%e l] + and [%p nxt.len.pat] = [%e nxt.len.exp] - [%e l] in + [%e mcase]] + [@metaloc loc]) and gen_offset ~loc cur nxt fld beh = let open Context in @@ -764,8 +704,9 @@ and gen_offset ~loc cur nxt fld beh = match fld.MatchField.qls.offset with | Some ({ pexp_loc; _ } as off) -> [%expr - let [%p nxt.off.pat] = [%e cur.off.exp] + [%e off] in [%e beh]] - [@metaloc pexp_loc] + let [%p nxt.off.pat] = [%e cur.off.exp] + [%e off] in + [%e beh]] + [@metaloc pexp_loc] | None -> beh and gen_offset_saver ~loc cur nxt fld beh = @@ -773,105 +714,97 @@ and gen_offset_saver ~loc cur nxt fld beh = let open Entity in let open Qualifiers in match fld.MatchField.qls.save_offset_to with - | Some { pexp_desc = Pexp_ident ({ txt; loc = eloc }); _ } -> + | Some { pexp_desc = Pexp_ident { txt; loc = eloc }; _ } -> let ptxt = pvar ~loc:eloc (Longident.last_exn txt) in - [%expr - let [%p ptxt] = [%e nxt.off.exp] - [%e cur.off.exp] in [%e beh]] - [@metaloc eloc] + ([%expr + let [%p ptxt] = [%e nxt.off.exp] - [%e cur.off.exp] in + [%e beh]] + [@metaloc eloc]) | Some _ | None -> beh and gen_unbound_string ~loc cur nxt fld beh fields = - let p = fld.MatchField.pat - in + let p = fld.MatchField.pat in match p with - | { ppat_desc = Ppat_var(_); _ } -> - [%expr - let [%p p] = [%e (gen_extractor ~loc nxt fld)] in - [%e (gen_next_all ~loc cur nxt beh fields)]] - [@metaloc loc] - | [%pat? _ ] -> + | { ppat_desc = Ppat_var _; _ } -> [%expr - [%e (gen_next_all ~loc cur nxt beh fields)]] - [@metaloc loc] + let [%p p] = [%e gen_extractor ~loc nxt fld] in + [%e gen_next_all ~loc cur nxt beh fields]] + [@metaloc loc] + | [%pat? _] -> [%expr [%e gen_next_all ~loc cur nxt beh fields]] [@metaloc loc] | _ -> - location_exn ~loc "Unbound string or bitstring can only be assigned to a variable or skipped" + location_exn + ~loc + "Unbound string or bitstring can only be assigned to a variable or skipped" and gen_bound_bitstring ~loc cur nxt fld beh fields = let open Entity in let open Context in let p = fld.MatchField.pat - and (l, _) = fld.MatchField.len - in + and l, _ = fld.MatchField.len in match p with - | { ppat_desc = Ppat_var(_); _ } -> + | { ppat_desc = Ppat_var _; _ } -> [%expr - if Stdlib.(>=) [%e nxt.len.exp] [%e l] then - let [%p p] = [%e (gen_extractor ~loc nxt fld)] in - [%e (gen_next ~loc cur nxt fld beh fields)] + if Stdlib.( >= ) [%e nxt.len.exp] [%e l] + then ( + let [%p p] = [%e gen_extractor ~loc nxt fld] in + [%e gen_next ~loc cur nxt fld beh fields]) else ()] - [@metaloc loc] - | [%pat? _ ] -> + [@metaloc loc] + | [%pat? _] -> [%expr - if Stdlib.(>=) [%e nxt.len.exp] [%e l] then - [%e (gen_next ~loc cur nxt fld beh fields)] + if Stdlib.( >= ) [%e nxt.len.exp] [%e l] + then [%e gen_next ~loc cur nxt fld beh fields] else ()] - [@metaloc loc] - | _ -> - location_exn ~loc "Bound bitstring can only be assigned to variables or skipped" + [@metaloc loc] + | _ -> location_exn ~loc "Bound bitstring can only be assigned to variables or skipped" and gen_bound_string ~loc cur nxt fld beh fields = let open Entity in let open Context in - let (l, _) = fld.MatchField.len - in - [%expr - if Stdlib.(>=) [%e nxt.len.exp] [%e l] then - [%e (gen_match ~loc cur nxt fld beh fields)] - else ()] - [@metaloc loc] + let l, _ = fld.MatchField.len in + ([%expr + if Stdlib.( >= ) [%e nxt.len.exp] [%e l] + then [%e gen_match ~loc cur nxt fld beh fields] + else ()] + [@metaloc loc]) and gen_bound_int_with_size ~loc cur nxt fld beh fields = let open Entity in let open Context in - let (l, _) = fld.MatchField.len - in - [%expr - if Stdlib.(>=) [%e nxt.len.exp] [%e l] then - [%e (gen_match ~loc cur nxt fld beh fields)] - else ()] - [@metaloc loc] + let l, _ = fld.MatchField.len in + ([%expr + if Stdlib.( >= ) [%e nxt.len.exp] [%e l] + then [%e gen_match ~loc cur nxt fld beh fields] + else ()] + [@metaloc loc]) and gen_bound_int ~loc cur nxt fld beh fields = let open Entity in let open Context in - let (l, _) = fld.MatchField.len - in - [%expr - if Stdlib.(>=) [%e l] 1 && - Stdlib.(<=) [%e l] 64 && - Stdlib.(>=) [%e nxt.len.exp] [%e l] then - [%e (gen_match ~loc cur nxt fld beh fields)] - else ()] - [@metaloc loc] + let l, _ = fld.MatchField.len in + ([%expr + if + Stdlib.( >= ) [%e l] 1 + && Stdlib.( <= ) [%e l] 64 + && Stdlib.( >= ) [%e nxt.len.exp] [%e l] + then [%e gen_match ~loc cur nxt fld beh fields] + else ()] + [@metaloc loc]) and gen_fields_with_quals_by_type ~loc cur nxt fld beh fields = let open Qualifiers in match check_field_len ~loc fld, fld.MatchField.qls.value_type with - | Some (-1), Some (Type.Bitstring | Type.String) -> + | Some -1, Some (Type.Bitstring | Type.String) -> gen_unbound_string ~loc cur nxt fld beh fields - | (Some (_) | None), Some (Type.Bitstring) -> + | (Some _ | None), Some Type.Bitstring -> gen_bound_bitstring ~loc cur nxt fld beh fields - | (Some (_) | None), Some (Type.String) -> - gen_bound_string ~loc cur nxt fld beh fields - | Some (s), Some (Type.Int) -> - if s >= 1 && s <= 64 then - gen_bound_int_with_size ~loc cur nxt fld beh fields - else - location_exn ~loc "Invalid bit length for type Integer" - | None, Some (Type.Int) -> - gen_bound_int ~loc cur nxt fld beh fields - | _, _ -> - location_exn ~loc "No type to generate" + | (Some _ | None), Some Type.String -> gen_bound_string ~loc cur nxt fld beh fields + | Some s, Some Type.Int -> + if s >= 1 && s <= 64 + then gen_bound_int_with_size ~loc cur nxt fld beh fields + else location_exn ~loc "Invalid bit length for type Integer" + | None, Some Type.Int -> gen_bound_int ~loc cur nxt fld beh fields + | _, _ -> location_exn ~loc "No type to generate" and gen_fields_with_quals ~loc cur nxt fld beh fields = gen_fields_with_quals_by_type ~loc cur nxt fld beh fields @@ -879,77 +812,75 @@ and gen_fields_with_quals ~loc cur nxt fld beh fields = |> gen_offset ~loc cur nxt fld and gen_fields ~loc cur nxt beh fields = - let (exp, alias) = beh - in + let exp, alias = beh in match fields with | [] -> - begin match alias with - | None -> exp - | Some a -> [%expr - let [%p pvar ~loc a] = ([%e cur.dat.exp], [%e cur.off.exp], ([%e cur.len.exp] - [%e nxt.len.exp])) - in - [%e exp] - ][@metaloc loc] - end - | MatchField.Any (_) :: tl -> - begin match alias with - | None -> exp - | Some a -> [%expr - let [%p pvar ~loc a] = ([%e cur.dat.exp], [%e cur.off.exp], [%e cur.len.exp]) - in - [%e exp] - ][@metaloc loc] - end - | MatchField.Tuple (fld) :: tl -> gen_fields_with_quals ~loc cur nxt fld beh tl + (match alias with + | None -> exp + | Some a -> + [%expr + let [%p pvar ~loc a] = + [%e cur.dat.exp], [%e cur.off.exp], [%e cur.len.exp] - [%e nxt.len.exp] + in + [%e exp]] + [@metaloc loc]) + | MatchField.Any _ :: tl -> + (match alias with + | None -> exp + | Some a -> + [%expr + let [%p pvar ~loc a] = [%e cur.dat.exp], [%e cur.off.exp], [%e cur.len.exp] in + [%e exp]] + [@metaloc loc]) + | MatchField.Tuple fld :: tl -> gen_fields_with_quals ~loc cur nxt fld beh tl ;; let is_field_size_open_ended = function - | (_, Some (-1)) -> true - | _ -> false + | _, Some -1 -> true + | _ -> false +;; let check_for_open_endedness fields = let check init fld = let p = fld.MatchField.pat and l = fld.MatchField.len in let oe = is_field_size_open_ended l in - if init || (oe && init) then - location_exn ~loc:p.ppat_loc "Pattern is already open-ended" + if init || (oe && init) + then location_exn ~loc:p.ppat_loc "Pattern is already open-ended" else oe in let inspect init = function - | MatchField.Any (_) -> init && false + | MatchField.Any _ -> init && false | MatchField.Tuple fld -> check init fld in let rec scan init = function | [] -> () | hd :: tl -> scan (inspect init hd) tl in - scan false fields; fields + scan false fields; + fields ;; let mark_optimized_fastpath fields = let open Qualifiers in - let open MatchField - in + let open MatchField in let check_field off tuple = match tuple with - | { pat; len = (l, Some (v)); qls = { value_type = Some (Type.Int); _ }; _ } -> - if (off land 7) = 0 && (v = 16 || v = 32 || v = 64) then - (Some (off + v), MatchField.Tuple { tuple with opt = true }) - else - (None, MatchField.Tuple tuple) - | _ -> - (None, MatchField.Tuple tuple) + | { pat; len = l, Some v; qls = { value_type = Some Type.Int; _ }; _ } -> + if off land 7 = 0 && (v = 16 || v = 32 || v = 64) + then Some (off + v), MatchField.Tuple { tuple with opt = true } + else None, MatchField.Tuple tuple + | _ -> None, MatchField.Tuple tuple in let check_offset_and_field offset fld = match offset, fld with - | Some (off), MatchField.Tuple (tuple) -> check_field off tuple - | _, _ -> (None, fld) + | Some off, MatchField.Tuple tuple -> check_field off tuple + | _, _ -> None, fld in let rec scan offset result = function | [] -> result | hd :: tl -> - let (noff, nfld) = check_offset_and_field offset hd in + let noff, nfld = check_offset_and_field offset hd in scan noff (result @ [ nfld ]) tl in scan (Some 0) [] fields @@ -957,14 +888,16 @@ let mark_optimized_fastpath fields = let gen_case_constant ~loc cur nxt res case value alias = let open Entity in - let beh = [%expr - [%e res.exp] := Some ([%e case.pc_rhs]); - raise Exit][@metaloc loc] + let beh = + ([%expr + [%e res.exp] := Some [%e case.pc_rhs]; + raise Exit] + [@metaloc loc]) in let beh = match case.pc_guard with | None -> beh - | Some cond -> [%expr if [%e cond] then [%e beh] else ()][@metaloc loc] + | Some cond -> [%expr if [%e cond] then [%e beh] else ()] [@metaloc loc] in split_string ~on:";" value |> split_loc ~loc @@ -972,209 +905,212 @@ let gen_case_constant ~loc cur nxt res case value alias = |> check_for_open_endedness |> mark_optimized_fastpath |> gen_fields ~loc cur nxt (beh, alias) +;; let gen_case cur nxt res case = let loc = case.pc_lhs.ppat_loc in match case.pc_lhs.ppat_desc with | Ppat_constant (Pconst_string (value, _, _)) -> gen_case_constant ~loc cur nxt res case value None - | Ppat_alias ({ ppat_desc = Ppat_constant (Pconst_string (value, _, _)); _ }, { txt = a; _ }) -> + | Ppat_alias + ({ ppat_desc = Ppat_constant (Pconst_string (value, _, _)); _ }, { txt = a; _ }) -> gen_case_constant ~loc cur nxt res case value (Some a) - | _ -> - location_exn ~loc "Wrong pattern type" + | _ -> location_exn ~loc "Wrong pattern type" ;; let rec gen_cases_sequence ~loc = function - | [] -> location_exn ~loc "Empty case list" - | [hd] -> hd - | hd :: tl -> [%expr [%e hd]; [%e gen_cases_sequence ~loc tl]][@metaloc loc] + | [] -> location_exn ~loc "Empty case list" + | [ hd ] -> hd + | hd :: tl -> + [%expr + [%e hd]; + [%e gen_cases_sequence ~loc tl]] + [@metaloc loc] ;; let gen_cases ~loc ident cases = let open Entity in let open Context in let cur = Context.make ~loc - and res = Entity.make ~loc "res" - in + and res = Entity.make ~loc "res" in let nxt = Context.next ~loc cur - and tupl = [%pat? ([%p cur.dat.pat], [%p cur.off.pat], [%p cur.len.pat])][@metaloc loc] + and tupl = ([%pat? [%p cur.dat.pat], [%p cur.off.pat], [%p cur.len.pat]] [@metaloc loc]) and fnam = estring ~loc loc.Location.loc_start.pos_fname and lpos = eint ~loc loc.Location.loc_start.pos_lnum - and cpos = eint ~loc (loc.Location.loc_start.pos_cnum - loc.Location.loc_start.pos_bol) + and cpos = + eint ~loc (loc.Location.loc_start.pos_cnum - loc.Location.loc_start.pos_bol) in - List.fold_left - (fun acc case -> acc @ [ gen_case cur nxt res case ]) - [] - cases + List.fold_left (fun acc case -> acc @ [ gen_case cur nxt res case ]) [] cases |> gen_cases_sequence ~loc |> fun seq -> - [%expr - let [%p tupl] = [%e ident] in - let [%p nxt.off.pat] = [%e cur.off.exp] - and [%p nxt.len.pat] = [%e cur.len.exp] - and [%p res.pat] = ref None - in - (try [%e seq]; with | Exit -> ()); - match ![%e res.exp] with - | Some x -> x - | None -> raise (Match_failure ([%e fnam], [%e lpos], [%e cpos]))] - [@metaloc loc] + ([%expr + let [%p tupl] = [%e ident] in + let [%p nxt.off.pat] = [%e cur.off.exp] + and [%p nxt.len.pat] = [%e cur.len.exp] + and [%p res.pat] = ref None in + (try [%e seq] with + | Exit -> ()); + match ![%e res.exp] with + | Some x -> x + | None -> raise (Match_failure ([%e fnam], [%e lpos], [%e cpos]))] + [@metaloc loc]) ;; let gen_function ~loc cases = let open Entity in let cas = Entity.make ~loc "case" in - [%expr - (fun [%p cas.pat] -> [%e (gen_cases ~loc cas.exp cases)])] - [@metaloc loc] + ([%expr fun [%p cas.pat] -> [%e gen_cases ~loc cas.exp cases]] [@metaloc loc]) +;; (* Constructor generators *) let gen_constructor_exn ~loc = let open Location in - [%expr Bitstring.Construct_failure ( - [%e estring ~loc "Bad field value"], - [%e estring ~loc loc.loc_start.pos_fname], - [%e eint ~loc loc.loc_start.pos_lnum], - [%e eint ~loc loc.loc_start.pos_cnum])] - [@metaloc loc] + ([%expr + Bitstring.Construct_failure + ( [%e estring ~loc "Bad field value"] + , [%e estring ~loc loc.loc_start.pos_fname] + , [%e eint ~loc loc.loc_start.pos_lnum] + , [%e eint ~loc loc.loc_start.pos_cnum] )] + [@metaloc loc]) ;; -let gen_constructor_bitstring ~loc sym (l, _, _ ) = - [%expr - Bitstring.construct_bitstring [%e sym.Entity.exp] [%e l]] - [@metaloc loc] +let gen_constructor_bitstring ~loc sym (l, _, _) = + [%expr Bitstring.construct_bitstring [%e sym.Entity.exp] [%e l]] [@metaloc loc] ;; let gen_constructor_string ~loc sym (l, _, _) = - [%expr - Bitstring.construct_string [%e sym.Entity.exp] [%e l]] - [@metaloc loc] + [%expr Bitstring.construct_string [%e sym.Entity.exp] [%e l]] [@metaloc loc] ;; let get_1_bit_constr_value ~loc (l, _, _) = - match (evaluate_expr l) with - | Some (1) -> [%expr true][@metaloc loc] - | Some (0) -> [%expr false][@metaloc loc] - | Some (_) | None -> l + match evaluate_expr l with + | Some 1 -> [%expr true] [@metaloc loc] + | Some 0 -> [%expr false] [@metaloc loc] + | Some _ | None -> l ;; let gen_constructor_int ~loc sym fld = let open Qualifiers in - let (l, s, q) = fld in + let l, s, q = fld in let eexc = gen_constructor_exn ~loc and esym = sym.Entity.exp in - let (fnc, vl, sz) = match (evaluate_expr s), q.sign, q.endian with + let fnc, vl, sz = + match evaluate_expr s, q.sign, q.endian with (* 1-bit type *) - | Some (size), Some (_), Some (_) when size = 1 -> - (evar ~loc "Bitstring.construct_bit", get_1_bit_constr_value ~loc fld, [%expr 1]) + | Some size, Some _, Some _ when size = 1 -> + evar ~loc "Bitstring.construct_bit", get_1_bit_constr_value ~loc fld, [%expr 1] (* 8-bit type *) - | Some (size), Some (sign), Some (_) when size >= 2 && size <= 8 -> + | Some size, Some sign, Some _ when size >= 2 && size <= 8 -> let sn = Sign.to_string sign in let ex = sprintf "Bitstring.construct_char_%s" sn in - (evar ~loc ex, l, eint ~loc size) + evar ~loc ex, l, eint ~loc size (* 16|32|64-bit type *) - | Some (size), Some (sign), Some (Endian.Referred r) -> + | Some size, Some sign, Some (Endian.Referred r) -> let ss = Sign.to_string sign and it = get_inttype ~loc ~fastpath:false size in let ex = sprintf "Bitstring.construct_%s_ee_%s" it ss in - ([%expr [%e evar ~loc ex] [%e r]], l, s) - | Some (size), Some (sign), Some (endian) -> + [%expr [%e evar ~loc ex] [%e r]], l, s + | Some size, Some sign, Some endian -> let tp = get_inttype ~loc ~fastpath:false size and en = Endian.to_string endian and sn = Sign.to_string sign in let ex = sprintf "Bitstring.construct_%s_%s_%s" tp en sn in - (evar ~loc ex, l, eint ~loc size) + evar ~loc ex, l, eint ~loc size (* Variable size types *) - | None, Some (sign), Some (Endian.Referred r) -> + | None, Some sign, Some (Endian.Referred r) -> let ss = Sign.to_string sign in let ex = sprintf "Bitstring.construct_int64_ee_%s" ss in - ([%expr [%e evar ~loc ex] [%e r]], l, s) - | None, Some (sign), Some (endian) -> + [%expr [%e evar ~loc ex] [%e r]], l, s + | None, Some sign, Some endian -> let en = Endian.to_string endian and sn = Sign.to_string sign in let ex = sprintf "Bitstring.construct_int64_%s_%s" en sn in - (evar ~loc ex, l, s) + evar ~loc ex, l, s (* Invalid type *) - | _, _, _ -> - location_exn ~loc "Invalid type" + | _, _, _ -> location_exn ~loc "Invalid type" in - [%expr - [%e fnc] [%e esym] [%e vl] [%e sz] [%e eexc]] - [@metaloc loc] + ([%expr [%e fnc] [%e esym] [%e vl] [%e sz] [%e eexc]] [@metaloc loc]) ;; let gen_constructor_complete ~loc sym fld = - let (_, _, q) = fld in + let _, _, q = fld in match q.Qualifiers.value_type with - | Some (Type.Bitstring) -> gen_constructor_bitstring ~loc sym fld - | Some (Type.String) -> gen_constructor_string ~loc sym fld - | Some (Type.Int) -> gen_constructor_int ~loc sym fld - | _ -> location_exn ~loc "Invalid type" + | Some Type.Bitstring -> gen_constructor_bitstring ~loc sym fld + | Some Type.String -> gen_constructor_string ~loc sym fld + | Some Type.Int -> gen_constructor_int ~loc sym fld + | _ -> location_exn ~loc "Invalid type" ;; let gen_constructor ~loc sym = function - | (f, Some (s), Some (q)) -> gen_constructor_complete ~loc sym (f, s, q) + | f, Some s, Some q -> gen_constructor_complete ~loc sym (f, s, q) | _ -> location_exn ~loc "Invalid field format" ;; let gen_assignment_size_of_sized_field ~loc (f, s, q) = - match (evaluate_expr s), option_bind q (fun q -> q.Qualifiers.value_type) with + match evaluate_expr s, option_bind q (fun q -> q.Qualifiers.value_type) with (* Deal with String type *) - | Some (-1), Some (Type.String) -> [%expr (String.length [%e f] * 8)] - | Some (v), Some (Type.String) when v > 0 && (v mod 8) = 0 -> s - | Some (_), Some (Type.String) -> - location_exn ~loc "Length of string must be > 0 and multiple of 8, or the special value -1" + | Some -1, Some Type.String -> [%expr String.length [%e f] * 8] + | Some v, Some Type.String when v > 0 && v mod 8 = 0 -> s + | Some _, Some Type.String -> + location_exn + ~loc + "Length of string must be > 0 and multiple of 8, or the special value -1" (* Deal with Bitstring type *) - | Some (-1), Some (Type.Bitstring) -> [%expr (Bitstring.bitstring_length [%e f])] - | Some (v), Some (Type.Bitstring) when v > 0 -> s - | Some (_), Some (Type.Bitstring) -> - location_exn ~loc "Length of bitstring must be >= 0 or the special value -1" + | Some -1, Some Type.Bitstring -> [%expr Bitstring.bitstring_length [%e f]] + | Some v, Some Type.Bitstring when v > 0 -> s + | Some _, Some Type.Bitstring -> + location_exn ~loc "Length of bitstring must be >= 0 or the special value -1" (* Deal with other types *) - | Some (v), _ when v > 0 -> s - | Some (v), _ -> - location_exn ~loc "Negative or null field size in constructor" + | Some v, _ when v > 0 -> s + | Some v, _ -> location_exn ~loc "Negative or null field size in constructor" (* Unknown field size, arbitrary expression *) | None, _ -> s ;; let gen_assignment_size_of_field ~loc = function - | (_, None, _) -> [%expr 0] - | (f, Some (s), q) -> gen_assignment_size_of_sized_field ~loc (f, s, q) + | _, None, _ -> [%expr 0] + | f, Some s, q -> gen_assignment_size_of_sized_field ~loc (f, s, q) ;; let rec gen_assignment_size ~loc = function | [] -> [%expr 0] | field :: tl -> - let this = gen_assignment_size_of_field ~loc field in - let next = gen_assignment_size ~loc tl in - [%expr [%e this] + ([%e next])][@metaloc loc] + let this = gen_assignment_size_of_field ~loc field in + let next = gen_assignment_size ~loc tl in + ([%expr [%e this] + [%e next]] [@metaloc loc]) ;; let gen_assignment_behavior ~loc sym fields = let size = gen_assignment_size ~loc fields in let res = sym.Entity.exp in - let rep = [%expr Bitstring.Buffer.contents [%e res]][@metaloc loc] in - let len = match (evaluate_expr size) with - | Some (v) -> eint v ~loc - | None -> size + let rep = ([%expr Bitstring.Buffer.contents [%e res]] [@metaloc loc]) in + let len = + match evaluate_expr size with + | Some v -> eint v ~loc + | None -> size in let post = - [%expr - let _res = [%e rep] in - if Stdlib.(=) (Bitstring.bitstring_length _res) [%e len] - then _res else raise Exit] - [@metaloc loc] + ([%expr + let _res = [%e rep] in + if Stdlib.( = ) (Bitstring.bitstring_length _res) [%e len] + then _res + else raise Exit] + [@metaloc loc]) in - let seq = List.fold_right - (fun fld acc -> [%expr [%e (gen_constructor ~loc sym fld)]; [%e acc]]) + let seq = + List.fold_right + (fun fld acc -> + [%expr + [%e gen_constructor ~loc sym fld]; + [%e acc]]) fields post in - [%expr - let [%p sym.Entity.pat] = Bitstring.Buffer.create () in - [%e seq]] - [@metaloc loc] + ([%expr + let [%p sym.Entity.pat] = Bitstring.Buffer.create () in + [%e seq]] + [@metaloc loc]) ;; let parse_assignment_behavior ~loc sym value = @@ -1188,15 +1124,19 @@ let gen_constructor_expr ~loc value = let open Entity in let sym = Entity.make ~loc "constructor" in let beh = parse_assignment_behavior ~loc sym value in - [%expr let [%p sym.pat] = fun () -> [%e beh] in [%e sym.exp] ()] + [%expr + let [%p sym.pat] = fun () -> [%e beh] in + [%e sym.exp] ()] ;; let transform_single_let ~loc ast expr = match ast.pvb_pat.ppat_desc, ast.pvb_expr.pexp_desc with - | Parsetree.Ppat_var (s), Pexp_constant (Pconst_string (value, _, _)) -> + | Parsetree.Ppat_var s, Pexp_constant (Pconst_string (value, _, _)) -> let pat = pvar ~loc s.txt in let constructor_expr = gen_constructor_expr ~loc value in - [%expr let [%p pat] = [%e constructor_expr] in [%e expr]] + [%expr + let [%p pat] = [%e constructor_expr] in + [%e expr]] | _ -> location_exn ~loc "Invalid pattern type" ;; @@ -1210,13 +1150,13 @@ let expression_expander expr = (fun binding expr -> transform_single_let ~loc binding expr) bindings expr - | Pexp_match (ident, cases) -> - gen_cases ~loc ident cases - | Pexp_function ([], _, Pfunction_cases (cases, _, _)) -> - gen_function ~loc cases + | Pexp_match (ident, cases) -> gen_cases ~loc ident cases + | Pexp_function ([], _, Pfunction_cases (cases, _, _)) -> gen_function ~loc cases | _ -> - location_exn ~loc + location_exn + ~loc "'bitstring' can only be used with 'let', 'match', and as '[%bitstring]'" +;; let expression_rule = Extension.V3.declare @@ -1225,21 +1165,27 @@ let expression_rule = Ast_pattern.(single_expr_payload __) (fun ~ctxt -> expression_expander) |> Context_free.Rule.extension +;; let structure_item_rewriter ~(ctxt : Expansion_context.Extension.t) pat expr = let loc = Expansion_context.Extension.extension_point_loc ctxt in [%stri let [%p pat] = [%e expression_expander expr]] +;; let structure_item_rule = Extension.V3.declare "bitstring" Extension.Context.structure_item - Ast_pattern.(pstr (pstr_value nonrecursive (value_binding ~constraint_:drop ~pat:__ ~expr:__ ^:: nil) ^:: nil)) + Ast_pattern.( + pstr + (pstr_value nonrecursive (value_binding ~constraint_:drop ~pat:__ ~expr:__ ^:: nil) + ^:: nil)) structure_item_rewriter |> Context_free.Rule.extension +;; let () = - Driver.register_transformation "bitstring" ~rules:[ - expression_rule ; - structure_item_rule ; - ] + Driver.register_transformation + "bitstring" + ~rules:[ expression_rule; structure_item_rule ] +;; diff --git a/src/bitstring.ml b/src/bitstring.ml index eaf2ffa..00a4d62 100644 --- a/src/bitstring.ml +++ b/src/bitstring.ml @@ -21,7 +21,6 @@ *) open Printf - include Bitstring_types include Bitstring_config @@ -38,25 +37,20 @@ exception Construct_failure of string * string * int * int * are counted in bits, not bytes. *) type bitstring = bytes * int * int - type t = bitstring (* Functions to create and load bitstrings. *) let empty_bitstring = Bytes.create 0, 0, 0 let make_bitstring len c = - if len >= 0 then Bytes.make ((len+7) lsr 3) c, 0, len - else - invalid_arg ( - sprintf "make_bitstring/create_bitstring: len %d < 0" len - ) + if len >= 0 + then Bytes.make ((len + 7) lsr 3) c, 0, len + else invalid_arg (sprintf "make_bitstring/create_bitstring: len %d < 0" len) +;; let create_bitstring len = make_bitstring len '\000' - let zeroes_bitstring = create_bitstring - let ones_bitstring len = make_bitstring len '\xff' - let bitstring_of_string str = Bytes.of_string str, 0, String.length str lsl 3 let bitstring_of_chan chan = @@ -64,10 +58,14 @@ let bitstring_of_chan chan = let buf = Buffer.create tmpsize in let tmp = Bytes.create tmpsize in let n = ref 0 in - while n := input chan tmp 0 tmpsize; !n > 0 do - Buffer.add_subbytes buf tmp 0 !n; + while + n := input chan tmp 0 tmpsize; + !n > 0 + do + Buffer.add_subbytes buf tmp 0 !n done; Buffer.to_bytes buf, 0, Buffer.length buf lsl 3 +;; let bitstring_of_chan_max chan max = let tmpsize = 16384 in @@ -75,28 +73,33 @@ let bitstring_of_chan_max chan max = let tmp = Bytes.create tmpsize in let len = ref 0 in let rec loop () = - if !len < max then ( + if !len < max + then ( let r = min tmpsize (max - !len) in let n = input chan tmp 0 r in - if n > 0 then ( - Buffer.add_subbytes buf tmp 0 n; - len := !len + n; - loop () - ) - ) + if n > 0 + then ( + Buffer.add_subbytes buf tmp 0 n; + len := !len + n; + loop ())) in loop (); Buffer.to_bytes buf, 0, !len lsl 3 +;; let bitstring_of_file_descr fd = let tmpsize = 16384 in let buf = Buffer.create tmpsize in let tmp = Bytes.create tmpsize in let n = ref 0 in - while n := Unix.read fd tmp 0 tmpsize; !n > 0 do - Buffer.add_subbytes buf tmp 0 !n; + while + n := Unix.read fd tmp 0 tmpsize; + !n > 0 + do + Buffer.add_subbytes buf tmp 0 !n done; Buffer.to_bytes buf, 0, Buffer.length buf lsl 3 +;; let bitstring_of_file_descr_max fd max = let tmpsize = 16384 in @@ -104,18 +107,19 @@ let bitstring_of_file_descr_max fd max = let tmp = Bytes.create tmpsize in let len = ref 0 in let rec loop () = - if !len < max then ( + if !len < max + then ( let r = min tmpsize (max - !len) in let n = Unix.read fd tmp 0 r in - if n > 0 then ( - Buffer.add_subbytes buf tmp 0 n; - len := !len + n; - loop () - ) - ) + if n > 0 + then ( + Buffer.add_subbytes buf tmp 0 n; + len := !len + n; + loop ())) in loop (); Buffer.to_bytes buf, 0, !len lsl 3 +;; let bitstring_of_file fname = let chan = open_in_bin fname in @@ -123,26 +127,31 @@ let bitstring_of_file fname = let bs = bitstring_of_chan chan in close_in chan; bs - with exn -> + with + | exn -> close_in chan; raise exn +;; let bitstring_length (_, _, len) = len let subbitstring (data, off, len) off' len' = let off = off + off' in if off' < 0 || len' < 0 || off' > len - len' then invalid_arg "subbitstring"; - (data, off, len') + data, off, len' +;; let dropbits n (data, off, len) = let off = off + n in let len = len - n in if len < 0 || n < 0 then invalid_arg "dropbits"; - (data, off, len) + data, off, len +;; let takebits n (data, off, len) = if len < n || n < 0 then invalid_arg "takebits"; - (data, off, n) + data, off, n +;; (*----------------------------------------------------------------------*) (* Bitwise functions. @@ -152,9 +161,10 @@ let takebits n (data, off, len) = module I = struct (* Bitwise operations on ints. Note that we assume int <= 31 bits. *) - external (<<<) : int -> int -> int = "%lslint" - external (>>>) : int -> int -> int = "%lsrint" + external ( <<< ) : int -> int -> int = "%lslint" + external ( >>> ) : int -> int -> int = "%lsrint" external to_int : int -> int = "%identity" + let zero = 0 let one = 1 let minus_one = -1 @@ -162,82 +172,84 @@ module I = struct (* Create a mask 0-31 bits wide. *) let mask bits = - if bits < 30 || - (bits < 32 && Sys.word_size = 64) then - (one <<< bits) - 1 - else if bits = 30 then - max_int - else if bits = 31 then - minus_one - else - invalid_arg "Bitstring.I.mask" + if bits < 30 || (bits < 32 && Sys.word_size = 64) + then (one <<< bits) - 1 + else if bits = 30 + then max_int + else if bits = 31 + then minus_one + else invalid_arg "Bitstring.I.mask" + ;; (* Byte swap an int of a given size. *) let byteswap v bits = - if bits <= 8 then v - else if bits <= 16 then ( - let shift = bits-8 in + if bits <= 8 + then v + else if bits <= 16 + then ( + let shift = bits - 8 in let v1 = v >>> shift in - let v2 = ((v land (mask shift)) <<< 8) in - v2 lor v1 - ) else if bits <= 24 then ( + let v2 = v land mask shift <<< 8 in + v2 lor v1) + else if bits <= 24 + then ( let shift = bits - 16 in - let v1 = v >>> (8+shift) in - let v2 = ((v >>> shift) land ff) <<< 8 in - let v3 = (v land (mask shift)) <<< 16 in - v3 lor v2 lor v1 - ) else ( + let v1 = v >>> 8 + shift in + let v2 = (v >>> shift) land ff <<< 8 in + let v3 = v land mask shift <<< 16 in + v3 lor v2 lor v1) + else ( let shift = bits - 24 in - let v1 = v >>> (16+shift) in - let v2 = ((v >>> (8+shift)) land ff) <<< 8 in - let v3 = ((v >>> shift) land ff) <<< 16 in - let v4 = (v land (mask shift)) <<< 24 in - v4 lor v3 lor v2 lor v1 - ) + let v1 = v >>> 16 + shift in + let v2 = (v >>> 8 + shift) land ff <<< 8 in + let v3 = (v >>> shift) land ff <<< 16 in + let v4 = v land mask shift <<< 24 in + v4 lor v3 lor v2 lor v1) + ;; (* Check a value is in range 0 .. 2^bits-1. *) let range_unsigned v bits = let mask = lnot (mask bits) in - (v land mask) = zero + v land mask = zero + ;; let range_signed v bits = - if - v >= zero - then - range_unsigned v bits - else - if - bits = 31 && Sys.word_size = 32 - then - v >= min_int - else - pred (minus_one <<< pred bits) < v + if v >= zero + then range_unsigned v bits + else if bits = 31 && Sys.word_size = 32 + then v >= min_int + else pred (minus_one <<< pred bits) < v + ;; (* Call function g on the top bits, then f on each full byte * (big endian - so start at top). *) let rec map_bytes_be g f v bits = - if bits >= 8 then ( - map_bytes_be g f (v >>> 8) (bits-8); + if bits >= 8 + then ( + map_bytes_be g f (v >>> 8) (bits - 8); let lsb = v land ff in - f (to_int lsb) - ) else if bits > 0 then ( - let lsb = v land (mask bits) in - g (to_int lsb) bits - ) + f (to_int lsb)) + else if bits > 0 + then ( + let lsb = v land mask bits in + g (to_int lsb) bits) + ;; (* Call function g on the top bits, then f on each full byte * (little endian - so start at root). *) let rec map_bytes_le g f v bits = - if bits >= 8 then ( + if bits >= 8 + then ( let lsb = v land ff in f (to_int lsb); - map_bytes_le g f (v >>> 8) (bits-8) - ) else if bits > 0 then ( - let lsb = v land (mask bits) in - g (to_int lsb) bits - ) + map_bytes_le g f (v >>> 8) (bits - 8)) + else if bits > 0 + then ( + let lsb = v land mask bits in + g (to_int lsb) bits) + ;; end module I32 = struct @@ -245,10 +257,10 @@ module I32 = struct * as possible to the I module above, to make it easier to track * down bugs. *) - let (<<<) = Int32.shift_left - let (>>>) = Int32.shift_right_logical - let (land) = Int32.logand - let (lor) = Int32.logor + let ( <<< ) = Int32.shift_left + let ( >>> ) = Int32.shift_right_logical + let ( land ) = Int32.logand + let ( lor ) = Int32.logor let lnot = Int32.lognot let pred = Int32.pred let max_int = Int32.max_int @@ -260,68 +272,76 @@ module I32 = struct (* Create a mask so many bits wide. *) let mask bits = - if bits < 31 then - pred (one <<< bits) - else if bits = 31 then - max_int - else if bits = 32 then - minus_one - else - invalid_arg "Bitstring.I32.mask" + if bits < 31 + then pred (one <<< bits) + else if bits = 31 + then max_int + else if bits = 32 + then minus_one + else invalid_arg "Bitstring.I32.mask" + ;; (* Byte swap an int of a given size. *) let byteswap v bits = - if bits <= 8 then v - else if bits <= 16 then ( - let shift = bits-8 in + if bits <= 8 + then v + else if bits <= 16 + then ( + let shift = bits - 8 in let v1 = v >>> shift in - let v2 = (v land (mask shift)) <<< 8 in - v2 lor v1 - ) else if bits <= 24 then ( + let v2 = v land mask shift <<< 8 in + v2 lor v1) + else if bits <= 24 + then ( let shift = bits - 16 in - let v1 = v >>> (8+shift) in - let v2 = ((v >>> shift) land ff) <<< 8 in - let v3 = (v land (mask shift)) <<< 16 in - v3 lor v2 lor v1 - ) else ( + let v1 = v >>> 8 + shift in + let v2 = (v >>> shift) land ff <<< 8 in + let v3 = v land mask shift <<< 16 in + v3 lor v2 lor v1) + else ( let shift = bits - 24 in - let v1 = v >>> (16+shift) in - let v2 = ((v >>> (8+shift)) land ff) <<< 8 in - let v3 = ((v >>> shift) land ff) <<< 16 in - let v4 = (v land (mask shift)) <<< 24 in - v4 lor v3 lor v2 lor v1 - ) + let v1 = v >>> 16 + shift in + let v2 = (v >>> 8 + shift) land ff <<< 8 in + let v3 = (v >>> shift) land ff <<< 16 in + let v4 = v land mask shift <<< 24 in + v4 lor v3 lor v2 lor v1) + ;; (* Check a value is in range 0 .. 2^bits-1. *) let range_unsigned v bits = let mask = lnot (mask bits) in - (v land mask) = zero + v land mask = zero + ;; (* Call function g on the top bits, then f on each full byte * (big endian - so start at top). *) let rec map_bytes_be g f v bits = - if bits >= 8 then ( - map_bytes_be g f (v >>> 8) (bits-8); + if bits >= 8 + then ( + map_bytes_be g f (v >>> 8) (bits - 8); let lsb = v land ff in - f (to_int lsb) - ) else if bits > 0 then ( - let lsb = v land (mask bits) in - g (to_int lsb) bits - ) + f (to_int lsb)) + else if bits > 0 + then ( + let lsb = v land mask bits in + g (to_int lsb) bits) + ;; (* Call function g on the top bits, then f on each full byte * (little endian - so start at root). *) let rec map_bytes_le g f v bits = - if bits >= 8 then ( + if bits >= 8 + then ( let lsb = v land ff in f (to_int lsb); - map_bytes_le g f (v >>> 8) (bits-8) - ) else if bits > 0 then ( - let lsb = v land (mask bits) in - g (to_int lsb) bits - ) + map_bytes_le g f (v >>> 8) (bits - 8)) + else if bits > 0 + then ( + let lsb = v land mask bits in + g (to_int lsb) bits) + ;; end module I64 = struct @@ -329,10 +349,10 @@ module I64 = struct * as possible to the I/I32 modules above, to make it easier to track * down bugs. *) - let (<<<) = Int64.shift_left - let (>>>) = Int64.shift_right_logical - let (land) = Int64.logand - let (lor) = Int64.logor + let ( <<< ) = Int64.shift_left + let ( >>> ) = Int64.shift_right_logical + let ( land ) = Int64.logand + let ( lor ) = Int64.logor let lnot = Int64.lognot let pred = Int64.pred let max_int = Int64.max_int @@ -344,106 +364,118 @@ module I64 = struct (* Create a mask so many bits wide. *) let mask bits = - if bits < 63 then - pred (one <<< bits) - else if bits = 63 then - max_int - else if bits = 64 then - minus_one - else - invalid_arg "Bitstring.I64.mask" + if bits < 63 + then pred (one <<< bits) + else if bits = 63 + then max_int + else if bits = 64 + then minus_one + else invalid_arg "Bitstring.I64.mask" + ;; (* Byte swap an int of a given size. *) let byteswap v bits = - if bits <= 8 then v - else if bits <= 16 then ( - let shift = bits-8 in + if bits <= 8 + then v + else if bits <= 16 + then ( + let shift = bits - 8 in let v1 = v >>> shift in - let v2 = (v land (mask shift)) <<< 8 in - v2 lor v1 - ) else if bits <= 24 then ( + let v2 = v land mask shift <<< 8 in + v2 lor v1) + else if bits <= 24 + then ( let shift = bits - 16 in - let v1 = v >>> (8+shift) in - let v2 = ((v >>> shift) land ff) <<< 8 in - let v3 = (v land (mask shift)) <<< 16 in - v3 lor v2 lor v1 - ) else if bits <= 32 then ( + let v1 = v >>> 8 + shift in + let v2 = (v >>> shift) land ff <<< 8 in + let v3 = v land mask shift <<< 16 in + v3 lor v2 lor v1) + else if bits <= 32 + then ( let shift = bits - 24 in - let v1 = v >>> (16+shift) in - let v2 = ((v >>> (8+shift)) land ff) <<< 8 in - let v3 = ((v >>> shift) land ff) <<< 16 in - let v4 = (v land (mask shift)) <<< 24 in - v4 lor v3 lor v2 lor v1 - ) else if bits <= 40 then ( + let v1 = v >>> 16 + shift in + let v2 = (v >>> 8 + shift) land ff <<< 8 in + let v3 = (v >>> shift) land ff <<< 16 in + let v4 = v land mask shift <<< 24 in + v4 lor v3 lor v2 lor v1) + else if bits <= 40 + then ( let shift = bits - 32 in - let v1 = v >>> (24+shift) in - let v2 = ((v >>> (16+shift)) land ff) <<< 8 in - let v3 = ((v >>> (8+shift)) land ff) <<< 16 in - let v4 = ((v >>> shift) land ff) <<< 24 in - let v5 = (v land (mask shift)) <<< 32 in - v5 lor v4 lor v3 lor v2 lor v1 - ) else if bits <= 48 then ( + let v1 = v >>> 24 + shift in + let v2 = (v >>> 16 + shift) land ff <<< 8 in + let v3 = (v >>> 8 + shift) land ff <<< 16 in + let v4 = (v >>> shift) land ff <<< 24 in + let v5 = v land mask shift <<< 32 in + v5 lor v4 lor v3 lor v2 lor v1) + else if bits <= 48 + then ( let shift = bits - 40 in - let v1 = v >>> (32+shift) in - let v2 = ((v >>> (24+shift)) land ff) <<< 8 in - let v3 = ((v >>> (16+shift)) land ff) <<< 16 in - let v4 = ((v >>> (8+shift)) land ff) <<< 24 in - let v5 = ((v >>> shift) land ff) <<< 32 in - let v6 = (v land (mask shift)) <<< 40 in - v6 lor v5 lor v4 lor v3 lor v2 lor v1 - ) else if bits <= 56 then ( + let v1 = v >>> 32 + shift in + let v2 = (v >>> 24 + shift) land ff <<< 8 in + let v3 = (v >>> 16 + shift) land ff <<< 16 in + let v4 = (v >>> 8 + shift) land ff <<< 24 in + let v5 = (v >>> shift) land ff <<< 32 in + let v6 = v land mask shift <<< 40 in + v6 lor v5 lor v4 lor v3 lor v2 lor v1) + else if bits <= 56 + then ( let shift = bits - 48 in - let v1 = v >>> (40+shift) in - let v2 = ((v >>> (32+shift)) land ff) <<< 8 in - let v3 = ((v >>> (24+shift)) land ff) <<< 16 in - let v4 = ((v >>> (16+shift)) land ff) <<< 24 in - let v5 = ((v >>> (8+shift)) land ff) <<< 32 in - let v6 = ((v >>> shift) land ff) <<< 40 in - let v7 = (v land (mask shift)) <<< 48 in - v7 lor v6 lor v5 lor v4 lor v3 lor v2 lor v1 - ) else ( + let v1 = v >>> 40 + shift in + let v2 = (v >>> 32 + shift) land ff <<< 8 in + let v3 = (v >>> 24 + shift) land ff <<< 16 in + let v4 = (v >>> 16 + shift) land ff <<< 24 in + let v5 = (v >>> 8 + shift) land ff <<< 32 in + let v6 = (v >>> shift) land ff <<< 40 in + let v7 = v land mask shift <<< 48 in + v7 lor v6 lor v5 lor v4 lor v3 lor v2 lor v1) + else ( let shift = bits - 56 in - let v1 = v >>> (48+shift) in - let v2 = ((v >>> (40+shift)) land ff) <<< 8 in - let v3 = ((v >>> (32+shift)) land ff) <<< 16 in - let v4 = ((v >>> (24+shift)) land ff) <<< 24 in - let v5 = ((v >>> (16+shift)) land ff) <<< 32 in - let v6 = ((v >>> (8+shift)) land ff) <<< 40 in - let v7 = ((v >>> shift) land ff) <<< 48 in - let v8 = (v land (mask shift)) <<< 56 in - v8 lor v7 lor v6 lor v5 lor v4 lor v3 lor v2 lor v1 - ) + let v1 = v >>> 48 + shift in + let v2 = (v >>> 40 + shift) land ff <<< 8 in + let v3 = (v >>> 32 + shift) land ff <<< 16 in + let v4 = (v >>> 24 + shift) land ff <<< 24 in + let v5 = (v >>> 16 + shift) land ff <<< 32 in + let v6 = (v >>> 8 + shift) land ff <<< 40 in + let v7 = (v >>> shift) land ff <<< 48 in + let v8 = v land mask shift <<< 56 in + v8 lor v7 lor v6 lor v5 lor v4 lor v3 lor v2 lor v1) + ;; (* Check a value is in range 0 .. 2^bits-1. *) let range_unsigned v bits = let mask = lnot (mask bits) in - (v land mask) = zero + v land mask = zero + ;; (* Call function g on the top bits, then f on each full byte * (big endian - so start at top). *) let rec map_bytes_be g f v bits = - if bits >= 8 then ( - map_bytes_be g f (v >>> 8) (bits-8); + if bits >= 8 + then ( + map_bytes_be g f (v >>> 8) (bits - 8); let lsb = v land ff in - f (to_int lsb) - ) else if bits > 0 then ( - let lsb = v land (mask bits) in - g (to_int lsb) bits - ) + f (to_int lsb)) + else if bits > 0 + then ( + let lsb = v land mask bits in + g (to_int lsb) bits) + ;; (* Call function g on the top bits, then f on each full byte * (little endian - so start at root). *) let rec map_bytes_le g f v bits = - if bits >= 8 then ( + if bits >= 8 + then ( let lsb = v land ff in f (to_int lsb); - map_bytes_le g f (v >>> 8) (bits-8) - ) else if bits > 0 then ( - let lsb = v land (mask bits) in - g (to_int lsb) bits - ) + map_bytes_le g f (v >>> 8) (bits - 8)) + else if bits > 0 + then ( + let lsb = v land mask bits in + g (to_int lsb) bits) + ;; end (*----------------------------------------------------------------------*) @@ -456,304 +488,349 @@ end (* Extract and convert to numeric. A single bit is returned as * a boolean. There are no endianness or signedness considerations. *) -let extract_bit data off len _ = (* final param is always 1 *) +let extract_bit data off len _ = + (* final param is always 1 *) let byteoff = off lsr 3 in let bitmask = 1 lsl (7 - (off land 7)) in let b = Char.code (Bytes.get data byteoff) land bitmask <> 0 in b (*, off+1, len-1*) +;; (* Returns 8 bit unsigned aligned bytes from the string. * If the string ends then this returns 0's. *) let _get_byte data byteoff strlen = if strlen > byteoff then Char.code (Bytes.get data byteoff) else 0 +;; + let _get_byte32 data byteoff strlen = - if strlen > byteoff then - Int32.of_int (Char.code (Bytes.get data byteoff)) - else 0l + if strlen > byteoff then Int32.of_int (Char.code (Bytes.get data byteoff)) else 0l +;; + let _get_byte64 data byteoff strlen = - if strlen > byteoff then - Int64.of_int (Char.code (Bytes.get data byteoff)) - else 0L + if strlen > byteoff then Int64.of_int (Char.code (Bytes.get data byteoff)) else 0L +;; (* Extend signed [2..31] bits int to 31 bits int or 63 bits int for 64 bits platform*) let extend_sign len v = let b = pred Sys.word_size - len in - (v lsl b) asr b + (v lsl b) asr b +;; let extract_and_extend_sign f data off len flen = let w = f data off len flen in - extend_sign flen w + extend_sign flen w +;; (* Extract [2..8] bits. Because the result fits into a single * byte we don't have to worry about endianness, only signedness. *) let extract_char_unsigned data off len flen = let byteoff = off lsr 3 in - (* Optimize the common (byte-aligned) case. *) - if off land 7 = 0 then ( + if off land 7 = 0 + then ( let byte = Char.code (Bytes.get data byteoff) in - byte lsr (8 - flen) (*, off+flen, len-flen*) - ) else ( + byte lsr (8 - flen) (*, off+flen, len-flen*)) + else ( (* Extract the 16 bits at byteoff and byteoff+1 (note that the * second byte might not exist in the original string). *) let strlen = Bytes.length data in - let word = - (_get_byte data byteoff strlen lsl 8) + - _get_byte data (byteoff+1) strlen in - + (_get_byte data byteoff strlen lsl 8) + _get_byte data (byteoff + 1) strlen + in (* Mask off the top bits. *) let bitmask = (1 lsl (16 - (off land 7))) - 1 in let word = word land bitmask in (* Shift right to get rid of the bottom bits. *) let shift = 16 - ((off land 7) + flen) in let word = word lsr shift in + word (*, off+flen, len-flen*)) +;; - word (*, off+flen, len-flen*) - ) - -let extract_char_signed = - extract_and_extend_sign extract_char_unsigned +let extract_char_signed = extract_and_extend_sign extract_char_unsigned (* Extract [9..31] bits. We have to consider endianness and signedness. *) let extract_int_be_unsigned data off len flen = let byteoff = off lsr 3 in - let strlen = Bytes.length data in - let word = (* Optimize the common (byte-aligned) case. *) - if off land 7 = 0 then ( + if off land 7 = 0 + then ( let word = - (_get_byte data byteoff strlen lsl 23) + - (_get_byte data (byteoff+1) strlen lsl 15) + - (_get_byte data (byteoff+2) strlen lsl 7) + - (_get_byte data (byteoff+3) strlen lsr 1) in - word lsr (31 - flen) - ) else if flen <= 24 then ( + (_get_byte data byteoff strlen lsl 23) + + (_get_byte data (byteoff + 1) strlen lsl 15) + + (_get_byte data (byteoff + 2) strlen lsl 7) + + (_get_byte data (byteoff + 3) strlen lsr 1) + in + word lsr (31 - flen)) + else if flen <= 24 + then ( (* Extract the 31 bits at byteoff .. byteoff+3. *) let word = - (_get_byte data byteoff strlen lsl 23) + - (_get_byte data (byteoff+1) strlen lsl 15) + - (_get_byte data (byteoff+2) strlen lsl 7) + - (_get_byte data (byteoff+3) strlen lsr 1) in + (_get_byte data byteoff strlen lsl 23) + + (_get_byte data (byteoff + 1) strlen lsl 15) + + (_get_byte data (byteoff + 2) strlen lsl 7) + + (_get_byte data (byteoff + 3) strlen lsr 1) + in (* Mask off the top bits. *) let bitmask = (1 lsl (31 - (off land 7))) - 1 in let word = word land bitmask in (* Shift right to get rid of the bottom bits. *) let shift = 31 - ((off land 7) + flen) in - word lsr shift - ) else ( + word lsr shift) + else ( (* Extract the next 31 bits, slow method. *) let word = - let c0 = extract_char_unsigned data off len 8 - and off = off + 8 and len = len - 8 in - let c1 = extract_char_unsigned data off len 8 - and off = off + 8 and len = len - 8 in - let c2 = extract_char_unsigned data off len 8 - and off = off + 8 and len = len - 8 in - let c3 = extract_char_unsigned data off len 7 in - (c0 lsl 23) + (c1 lsl 15) + (c2 lsl 7) + c3 in - word lsr (31 - flen) - ) in + let c0 = extract_char_unsigned data off len 8 + and off = off + 8 + and len = len - 8 in + let c1 = extract_char_unsigned data off len 8 + and off = off + 8 + and len = len - 8 in + let c2 = extract_char_unsigned data off len 8 + and off = off + 8 + and len = len - 8 in + let c3 = extract_char_unsigned data off len 7 in + (c0 lsl 23) + (c1 lsl 15) + (c2 lsl 7) + c3 + in + word lsr (31 - flen)) + in word (*, off+flen, len-flen*) +;; -let extract_int_be_signed = - extract_and_extend_sign extract_int_be_unsigned +let extract_int_be_signed = extract_and_extend_sign extract_int_be_unsigned let extract_int_le_unsigned data off len flen = let v = extract_int_be_unsigned data off len flen in let v = I.byteswap v flen in v +;; -let extract_int_le_signed = - extract_and_extend_sign extract_int_le_unsigned +let extract_int_le_signed = extract_and_extend_sign extract_int_le_unsigned let extract_int_ne_unsigned = - if nativeendian = BigEndian - then extract_int_be_unsigned - else extract_int_le_unsigned + if nativeendian = BigEndian then extract_int_be_unsigned else extract_int_le_unsigned +;; -let extract_int_ne_signed = - extract_and_extend_sign extract_int_ne_unsigned +let extract_int_ne_signed = extract_and_extend_sign extract_int_ne_unsigned let extract_int_ee_unsigned = function | BigEndian -> extract_int_be_unsigned | LittleEndian -> extract_int_le_unsigned | NativeEndian -> extract_int_ne_unsigned +;; -let extract_int_ee_signed e = - extract_and_extend_sign (extract_int_ee_unsigned e) +let extract_int_ee_signed e = extract_and_extend_sign (extract_int_ee_unsigned e) let _make_int32_be c0 c1 c2 c3 = Int32.logor (Int32.logor - (Int32.logor - (Int32.shift_left c0 24) - (Int32.shift_left c1 16)) + (Int32.logor (Int32.shift_left c0 24) (Int32.shift_left c1 16)) (Int32.shift_left c2 8)) c3 +;; let _make_int32_le c0 c1 c2 c3 = Int32.logor (Int32.logor - (Int32.logor - (Int32.shift_left c3 24) - (Int32.shift_left c2 16)) + (Int32.logor (Int32.shift_left c3 24) (Int32.shift_left c2 16)) (Int32.shift_left c1 8)) c0 +;; (* Extract exactly 32 bits. We have to consider endianness and signedness. *) let extract_int32_be_unsigned data off len flen = let byteoff = off lsr 3 in - let strlen = Bytes.length data in - let word = (* Optimize the common (byte-aligned) case. *) - if off land 7 = 0 then ( + if off land 7 = 0 + then ( let word = - let c0 = _get_byte32 data byteoff strlen in - let c1 = _get_byte32 data (byteoff+1) strlen in - let c2 = _get_byte32 data (byteoff+2) strlen in - let c3 = _get_byte32 data (byteoff+3) strlen in - _make_int32_be c0 c1 c2 c3 in - Int32.shift_right_logical word (32 - flen) - ) else ( + let c0 = _get_byte32 data byteoff strlen in + let c1 = _get_byte32 data (byteoff + 1) strlen in + let c2 = _get_byte32 data (byteoff + 2) strlen in + let c3 = _get_byte32 data (byteoff + 3) strlen in + _make_int32_be c0 c1 c2 c3 + in + Int32.shift_right_logical word (32 - flen)) + else ( (* Extract the next 32 bits, slow method. *) let word = - let c0 = extract_char_unsigned data off len 8 - and off = off + 8 and len = len - 8 in - let c1 = extract_char_unsigned data off len 8 - and off = off + 8 and len = len - 8 in - let c2 = extract_char_unsigned data off len 8 - and off = off + 8 and len = len - 8 in - let c3 = extract_char_unsigned data off len 8 in - let c0 = Int32.of_int c0 in - let c1 = Int32.of_int c1 in - let c2 = Int32.of_int c2 in - let c3 = Int32.of_int c3 in - _make_int32_be c0 c1 c2 c3 in - Int32.shift_right_logical word (32 - flen) - ) in + let c0 = extract_char_unsigned data off len 8 + and off = off + 8 + and len = len - 8 in + let c1 = extract_char_unsigned data off len 8 + and off = off + 8 + and len = len - 8 in + let c2 = extract_char_unsigned data off len 8 + and off = off + 8 + and len = len - 8 in + let c3 = extract_char_unsigned data off len 8 in + let c0 = Int32.of_int c0 in + let c1 = Int32.of_int c1 in + let c2 = Int32.of_int c2 in + let c3 = Int32.of_int c3 in + _make_int32_be c0 c1 c2 c3 + in + Int32.shift_right_logical word (32 - flen)) + in word (*, off+flen, len-flen*) +;; let extract_int32_le_unsigned data off len flen = let v = extract_int32_be_unsigned data off len flen in let v = I32.byteswap v flen in v +;; let extract_int32_ne_unsigned = if nativeendian = BigEndian then extract_int32_be_unsigned else extract_int32_le_unsigned +;; let extract_int32_ee_unsigned = function | BigEndian -> extract_int32_be_unsigned | LittleEndian -> extract_int32_le_unsigned | NativeEndian -> extract_int32_ne_unsigned +;; let _make_int64_be c0 c1 c2 c3 c4 c5 c6 c7 = Int64.logor (Int64.logor (Int64.logor - (Int64.logor - (Int64.logor - (Int64.logor - (Int64.logor - (Int64.shift_left c0 56) - (Int64.shift_left c1 48)) - (Int64.shift_left c2 40)) - (Int64.shift_left c3 32)) - (Int64.shift_left c4 24)) - (Int64.shift_left c5 16)) + (Int64.logor + (Int64.logor + (Int64.logor + (Int64.logor (Int64.shift_left c0 56) (Int64.shift_left c1 48)) + (Int64.shift_left c2 40)) + (Int64.shift_left c3 32)) + (Int64.shift_left c4 24)) + (Int64.shift_left c5 16)) (Int64.shift_left c6 8)) c7 +;; -let _make_int64_le c0 c1 c2 c3 c4 c5 c6 c7 = - _make_int64_be c7 c6 c5 c4 c3 c2 c1 c0 +let _make_int64_le c0 c1 c2 c3 c4 c5 c6 c7 = _make_int64_be c7 c6 c5 c4 c3 c2 c1 c0 (* Extract [1..64] bits. We have to consider endianness and signedness. *) let extract_int64_be_unsigned data off len flen = let byteoff = off lsr 3 in - let strlen = Bytes.length data in - let word = (* Optimize the common (byte-aligned) case. *) - if off land 7 = 0 then ( + if off land 7 = 0 + then ( let word = - let c0 = _get_byte64 data byteoff strlen in - let c1 = _get_byte64 data (byteoff+1) strlen in - let c2 = _get_byte64 data (byteoff+2) strlen in - let c3 = _get_byte64 data (byteoff+3) strlen in - let c4 = _get_byte64 data (byteoff+4) strlen in - let c5 = _get_byte64 data (byteoff+5) strlen in - let c6 = _get_byte64 data (byteoff+6) strlen in - let c7 = _get_byte64 data (byteoff+7) strlen in - _make_int64_be c0 c1 c2 c3 c4 c5 c6 c7 in - Int64.shift_right_logical word (64 - flen) - ) else ( + let c0 = _get_byte64 data byteoff strlen in + let c1 = _get_byte64 data (byteoff + 1) strlen in + let c2 = _get_byte64 data (byteoff + 2) strlen in + let c3 = _get_byte64 data (byteoff + 3) strlen in + let c4 = _get_byte64 data (byteoff + 4) strlen in + let c5 = _get_byte64 data (byteoff + 5) strlen in + let c6 = _get_byte64 data (byteoff + 6) strlen in + let c7 = _get_byte64 data (byteoff + 7) strlen in + _make_int64_be c0 c1 c2 c3 c4 c5 c6 c7 + in + Int64.shift_right_logical word (64 - flen)) + else ( (* Extract the next 64 bits, slow method. *) let word = - let c0 = extract_char_unsigned data off len 8 - and off = off + 8 and len = len - 8 in - let c1 = extract_char_unsigned data off len 8 - and off = off + 8 and len = len - 8 in - let c2 = extract_char_unsigned data off len 8 - and off = off + 8 and len = len - 8 in - let c3 = extract_char_unsigned data off len 8 - and off = off + 8 and len = len - 8 in - let c4 = extract_char_unsigned data off len 8 - and off = off + 8 and len = len - 8 in - let c5 = extract_char_unsigned data off len 8 - and off = off + 8 and len = len - 8 in - let c6 = extract_char_unsigned data off len 8 - and off = off + 8 and len = len - 8 in - let c7 = extract_char_unsigned data off len 8 in - let c0 = Int64.of_int c0 in - let c1 = Int64.of_int c1 in - let c2 = Int64.of_int c2 in - let c3 = Int64.of_int c3 in - let c4 = Int64.of_int c4 in - let c5 = Int64.of_int c5 in - let c6 = Int64.of_int c6 in - let c7 = Int64.of_int c7 in - _make_int64_be c0 c1 c2 c3 c4 c5 c6 c7 in - Int64.shift_right_logical word (64 - flen) - ) in + let c0 = extract_char_unsigned data off len 8 + and off = off + 8 + and len = len - 8 in + let c1 = extract_char_unsigned data off len 8 + and off = off + 8 + and len = len - 8 in + let c2 = extract_char_unsigned data off len 8 + and off = off + 8 + and len = len - 8 in + let c3 = extract_char_unsigned data off len 8 + and off = off + 8 + and len = len - 8 in + let c4 = extract_char_unsigned data off len 8 + and off = off + 8 + and len = len - 8 in + let c5 = extract_char_unsigned data off len 8 + and off = off + 8 + and len = len - 8 in + let c6 = extract_char_unsigned data off len 8 + and off = off + 8 + and len = len - 8 in + let c7 = extract_char_unsigned data off len 8 in + let c0 = Int64.of_int c0 in + let c1 = Int64.of_int c1 in + let c2 = Int64.of_int c2 in + let c3 = Int64.of_int c3 in + let c4 = Int64.of_int c4 in + let c5 = Int64.of_int c5 in + let c6 = Int64.of_int c6 in + let c7 = Int64.of_int c7 in + _make_int64_be c0 c1 c2 c3 c4 c5 c6 c7 + in + Int64.shift_right_logical word (64 - flen)) + in word (*, off+flen, len-flen*) +;; let extract_int64_le_unsigned data off len flen = let v = extract_int64_be_unsigned data off len flen in let v = I64.byteswap v flen in v +;; let extract_int64_ne_unsigned = if nativeendian = BigEndian then extract_int64_be_unsigned else extract_int64_le_unsigned +;; let extract_int64_ee_unsigned = function | BigEndian -> extract_int64_be_unsigned | LittleEndian -> extract_int64_le_unsigned | NativeEndian -> extract_int64_ne_unsigned - -external extract_fastpath_int16_be_unsigned : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int16_be_unsigned" - -external extract_fastpath_int16_le_unsigned : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int16_le_unsigned" - -external extract_fastpath_int16_ne_unsigned : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int16_ne_unsigned" - -external extract_fastpath_int16_be_signed : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int16_be_signed" - -external extract_fastpath_int16_le_signed : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int16_le_signed" - -external extract_fastpath_int16_ne_signed : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int16_ne_signed" +;; + +external extract_fastpath_int16_be_unsigned + : bytes + -> int + -> int + = "ocaml_bitstring_extract_fastpath_int16_be_unsigned" + +external extract_fastpath_int16_le_unsigned + : bytes + -> int + -> int + = "ocaml_bitstring_extract_fastpath_int16_le_unsigned" + +external extract_fastpath_int16_ne_unsigned + : bytes + -> int + -> int + = "ocaml_bitstring_extract_fastpath_int16_ne_unsigned" + +external extract_fastpath_int16_be_signed + : bytes + -> int + -> int + = "ocaml_bitstring_extract_fastpath_int16_be_signed" + +external extract_fastpath_int16_le_signed + : bytes + -> int + -> int + = "ocaml_bitstring_extract_fastpath_int16_le_signed" + +external extract_fastpath_int16_ne_signed + : bytes + -> int + -> int + = "ocaml_bitstring_extract_fastpath_int16_ne_signed" (* external extract_fastpath_int24_be_unsigned : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int24_be_unsigned" @@ -769,17 +846,41 @@ external extract_fastpath_int24_le_signed : bytes -> int -> int = "ocaml_bitstri external extract_fastpath_int24_ne_signed : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int24_ne_signed" *) -external extract_fastpath_int32_be_unsigned : bytes -> int -> int32 = "ocaml_bitstring_extract_fastpath_int32_be_unsigned" - -external extract_fastpath_int32_le_unsigned : bytes -> int -> int32 = "ocaml_bitstring_extract_fastpath_int32_le_unsigned" - -external extract_fastpath_int32_ne_unsigned : bytes -> int -> int32 = "ocaml_bitstring_extract_fastpath_int32_ne_unsigned" - -external extract_fastpath_int32_be_signed : bytes -> int -> int32 = "ocaml_bitstring_extract_fastpath_int32_be_signed" - -external extract_fastpath_int32_le_signed : bytes -> int -> int32 = "ocaml_bitstring_extract_fastpath_int32_le_signed" - -external extract_fastpath_int32_ne_signed : bytes -> int -> int32 = "ocaml_bitstring_extract_fastpath_int32_ne_signed" +external extract_fastpath_int32_be_unsigned + : bytes + -> int + -> int32 + = "ocaml_bitstring_extract_fastpath_int32_be_unsigned" + +external extract_fastpath_int32_le_unsigned + : bytes + -> int + -> int32 + = "ocaml_bitstring_extract_fastpath_int32_le_unsigned" + +external extract_fastpath_int32_ne_unsigned + : bytes + -> int + -> int32 + = "ocaml_bitstring_extract_fastpath_int32_ne_unsigned" + +external extract_fastpath_int32_be_signed + : bytes + -> int + -> int32 + = "ocaml_bitstring_extract_fastpath_int32_be_signed" + +external extract_fastpath_int32_le_signed + : bytes + -> int + -> int32 + = "ocaml_bitstring_extract_fastpath_int32_le_signed" + +external extract_fastpath_int32_ne_signed + : bytes + -> int + -> int32 + = "ocaml_bitstring_extract_fastpath_int32_ne_signed" (* external extract_fastpath_int40_be_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int40_be_unsigned" @@ -819,51 +920,78 @@ external extract_fastpath_int56_le_signed : bytes -> int -> int64 = "ocaml_bitst external extract_fastpath_int56_ne_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int56_ne_signed" *) -external extract_fastpath_int64_be_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int64_be_unsigned" - -external extract_fastpath_int64_le_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int64_le_unsigned" - -external extract_fastpath_int64_ne_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int64_ne_unsigned" - -external extract_fastpath_int64_be_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int64_be_signed" - -external extract_fastpath_int64_le_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int64_le_signed" - -external extract_fastpath_int64_ne_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int64_ne_signed" +external extract_fastpath_int64_be_unsigned + : bytes + -> int + -> int64 + = "ocaml_bitstring_extract_fastpath_int64_be_unsigned" + +external extract_fastpath_int64_le_unsigned + : bytes + -> int + -> int64 + = "ocaml_bitstring_extract_fastpath_int64_le_unsigned" + +external extract_fastpath_int64_ne_unsigned + : bytes + -> int + -> int64 + = "ocaml_bitstring_extract_fastpath_int64_ne_unsigned" + +external extract_fastpath_int64_be_signed + : bytes + -> int + -> int64 + = "ocaml_bitstring_extract_fastpath_int64_be_signed" + +external extract_fastpath_int64_le_signed + : bytes + -> int + -> int64 + = "ocaml_bitstring_extract_fastpath_int64_le_signed" + +external extract_fastpath_int64_ne_signed + : bytes + -> int + -> int64 + = "ocaml_bitstring_extract_fastpath_int64_ne_signed" (*----------------------------------------------------------------------*) (* Constructor functions. *) module Buffer = struct - type t = { - buf : Buffer.t; - mutable len : int; (* Length in bits. *) - (* Last byte in the buffer (if len is not aligned). We store - * it outside the buffer because buffers aren't mutable. - *) - mutable last : int; - } + type t = + { buf : Buffer.t + ; mutable len : int (* Length in bits. *) + ; (* Last byte in the buffer (if len is not aligned). We store + * it outside the buffer because buffers aren't mutable. + *) + mutable last : int + } let create () = (* XXX We have almost enough information in the generator to * choose a good initial size. *) { buf = Buffer.create 128; len = 0; last = 0 } + ;; - let contents { buf = buf; len = len; last = last } = + let contents { buf; len; last } = let data = - if len land 7 = 0 then - Buffer.to_bytes buf - else - Bytes.cat (Buffer.to_bytes buf) (Bytes.make 1 (Char.chr last)) in + if len land 7 = 0 + then Buffer.to_bytes buf + else Bytes.cat (Buffer.to_bytes buf) (Bytes.make 1 (Char.chr last)) + in data, 0, len + ;; (* Add exactly 8 bits. *) let add_byte t byte = - let {buf; len; last} = t in + let { buf; len; last } = t in if byte < 0 || byte > 255 then invalid_arg "Bitstring.Buffer.add_byte"; let shift = len land 7 in - if shift = 0 then + if shift = 0 + then (* Target buffer is byte-aligned. *) Buffer.add_char buf (Char.chr byte) else ( @@ -871,168 +999,164 @@ module Buffer = struct let first = byte lsr shift in let second = (byte lsl (8 - shift)) land 0xff in Buffer.add_char buf (Char.chr (last lor first)); - t.last <- second - ); + t.last <- second); t.len <- t.len + 8 + ;; (* Add exactly 1 bit. *) let add_bit t bit = - let {buf; len; last} = t in + let { buf; len; last } = t in let shift = 7 - (len land 7) in - if shift > 0 then + if shift > 0 + then (* Somewhere in the middle of 'last'. *) t.last <- last lor ((if bit then 1 else 0) lsl shift) else ( (* Just a single spare bit in 'last'. *) let last = last lor if bit then 1 else 0 in Buffer.add_char buf (Char.chr last); - t.last <- 0 - ); + t.last <- 0); t.len <- len + 1 + ;; (* Add a small number of bits (definitely < 8). This uses a loop * to call add_bit so it's slow. *) let _add_bits t c slen = if slen < 1 || slen >= 8 then invalid_arg "Bitstring.Buffer._add_bits"; - for i = slen-1 downto 0 do + for i = slen - 1 downto 0 do let bit = c land (1 lsl i) <> 0 in add_bit t bit done + ;; let add_bits t str slen = - let {buf; len; _} = t in - if slen > 0 then ( - if len land 7 = 0 then ( - if slen land 7 = 0 then - (* Common case - everything is byte-aligned. *) - Buffer.add_subbytes buf str 0 (slen lsr 3) - else ( - (* Target buffer is aligned. Copy whole bytes then leave the - * remaining bits in last. - *) - let slenbytes = slen lsr 3 in - if slenbytes > 0 then Buffer.add_subbytes buf str 0 slenbytes; - let lastidx = min slenbytes (Bytes.length str - 1) in - let last = Char.code (Bytes.get str lastidx) in (* last char *) - let mask = 0xff lsl (8 - (slen land 7)) in - t.last <- last land mask - ); - t.len <- len + slen - ) else ( - (* Target buffer is unaligned. Copy whole bytes using - * add_byte which knows how to deal with an unaligned - * target buffer, then call add_bit for the remaining < 8 bits. - * - * XXX This is going to be dog-slow. - *) - let slenbytes = slen lsr 3 in - for i = 0 to slenbytes-1 do - let byte = Char.code (Bytes.get str i) in - add_byte t byte - done; - let bitsleft = slen - (slenbytes lsl 3) in - if bitsleft > 0 then ( - let c = Char.code (Bytes.get str slenbytes) in - for i = 0 to bitsleft - 1 do - let bit = c land (0x80 lsr i) <> 0 in - add_bit t bit - done - ) - ); - ) + let { buf; len; _ } = t in + if slen > 0 + then + if len land 7 = 0 + then ( + if slen land 7 = 0 + then + (* Common case - everything is byte-aligned. *) + Buffer.add_subbytes buf str 0 (slen lsr 3) + else ( + (* Target buffer is aligned. Copy whole bytes then leave the + * remaining bits in last. + *) + let slenbytes = slen lsr 3 in + if slenbytes > 0 then Buffer.add_subbytes buf str 0 slenbytes; + let lastidx = min slenbytes (Bytes.length str - 1) in + let last = Char.code (Bytes.get str lastidx) in + (* last char *) + let mask = 0xff lsl (8 - (slen land 7)) in + t.last <- last land mask); + t.len <- len + slen) + else ( + (* Target buffer is unaligned. Copy whole bytes using + * add_byte which knows how to deal with an unaligned + * target buffer, then call add_bit for the remaining < 8 bits. + * + * XXX This is going to be dog-slow. + *) + let slenbytes = slen lsr 3 in + for i = 0 to slenbytes - 1 do + let byte = Char.code (Bytes.get str i) in + add_byte t byte + done; + let bitsleft = slen - (slenbytes lsl 3) in + if bitsleft > 0 + then ( + let c = Char.code (Bytes.get str slenbytes) in + for i = 0 to bitsleft - 1 do + let bit = c land (0x80 lsr i) <> 0 in + add_bit t bit + done)) + ;; end (* Construct a single bit. *) -let construct_bit buf b _ _ = - Buffer.add_bit buf b +let construct_bit buf b _ _ = Buffer.add_bit buf b (* Construct a field, flen = [2..8]. *) let construct_char_unsigned buf v flen exn = let max_val = 1 lsl flen in if v < 0 || v >= max_val then raise exn; - if flen = 8 then - Buffer.add_byte buf v - else - Buffer._add_bits buf v flen + if flen = 8 then Buffer.add_byte buf v else Buffer._add_bits buf v flen +;; let construct_char_signed buf v flen exn = let max_val = 1 lsl flen - and min_val = - (1 lsl pred flen) in - if v < min_val || v >= max_val then - raise exn; - if flen = 8 then - Buffer.add_byte buf (if v >= 0 then v else 256 + v) - else - Buffer._add_bits buf v flen + and min_val = -(1 lsl pred flen) in + if v < min_val || v >= max_val then raise exn; + if flen = 8 + then Buffer.add_byte buf (if v >= 0 then v else 256 + v) + else Buffer._add_bits buf v flen +;; (* Construct a field of up to 31 bits. *) let construct_int check_func map_func buf v flen exn = if not (check_func v flen) then raise exn; map_func (Buffer._add_bits buf) (Buffer.add_byte buf) v flen +;; -let construct_int_be_unsigned = - construct_int I.range_unsigned I.map_bytes_be - -let construct_int_be_signed = - construct_int I.range_signed I.map_bytes_be - -let construct_int_le_unsigned = - construct_int I.range_unsigned I.map_bytes_le - -let construct_int_le_signed = - construct_int I.range_signed I.map_bytes_le +let construct_int_be_unsigned = construct_int I.range_unsigned I.map_bytes_be +let construct_int_be_signed = construct_int I.range_signed I.map_bytes_be +let construct_int_le_unsigned = construct_int I.range_unsigned I.map_bytes_le +let construct_int_le_signed = construct_int I.range_signed I.map_bytes_le let construct_int_ne_unsigned = if nativeendian = BigEndian then construct_int_be_unsigned else construct_int_le_unsigned +;; let construct_int_ne_signed = - if nativeendian = BigEndian - then construct_int_be_signed - else construct_int_le_signed + if nativeendian = BigEndian then construct_int_be_signed else construct_int_le_signed +;; let construct_int_ee_unsigned = function | BigEndian -> construct_int_be_unsigned | LittleEndian -> construct_int_le_unsigned | NativeEndian -> construct_int_ne_unsigned +;; let construct_int_ee_signed = function | BigEndian -> construct_int_be_signed | LittleEndian -> construct_int_le_signed | NativeEndian -> construct_int_ne_signed +;; (* Construct a field of exactly 32 bits. *) let construct_int32_be_unsigned buf v flen _ = - Buffer.add_byte buf - (Int32.to_int (Int32.shift_right_logical v 24)); - Buffer.add_byte buf - (Int32.to_int ((Int32.logand (Int32.shift_right_logical v 16) 0xff_l))); - Buffer.add_byte buf - (Int32.to_int ((Int32.logand (Int32.shift_right_logical v 8) 0xff_l))); - Buffer.add_byte buf - (Int32.to_int (Int32.logand v 0xff_l)) + Buffer.add_byte buf (Int32.to_int (Int32.shift_right_logical v 24)); + Buffer.add_byte + buf + (Int32.to_int (Int32.logand (Int32.shift_right_logical v 16) 0xff_l)); + Buffer.add_byte buf (Int32.to_int (Int32.logand (Int32.shift_right_logical v 8) 0xff_l)); + Buffer.add_byte buf (Int32.to_int (Int32.logand v 0xff_l)) +;; let construct_int32_le_unsigned buf v flen _ = - Buffer.add_byte buf - (Int32.to_int (Int32.logand v 0xff_l)); - Buffer.add_byte buf - (Int32.to_int ((Int32.logand (Int32.shift_right_logical v 8) 0xff_l))); - Buffer.add_byte buf - (Int32.to_int ((Int32.logand (Int32.shift_right_logical v 16) 0xff_l))); - Buffer.add_byte buf - (Int32.to_int (Int32.shift_right_logical v 24)) + Buffer.add_byte buf (Int32.to_int (Int32.logand v 0xff_l)); + Buffer.add_byte buf (Int32.to_int (Int32.logand (Int32.shift_right_logical v 8) 0xff_l)); + Buffer.add_byte + buf + (Int32.to_int (Int32.logand (Int32.shift_right_logical v 16) 0xff_l)); + Buffer.add_byte buf (Int32.to_int (Int32.shift_right_logical v 24)) +;; let construct_int32_ne_unsigned = if nativeendian = BigEndian then construct_int32_be_unsigned else construct_int32_le_unsigned +;; let construct_int32_ee_unsigned = function | BigEndian -> construct_int32_be_unsigned | LittleEndian -> construct_int32_le_unsigned | NativeEndian -> construct_int32_ne_unsigned +;; (* Construct a field of up to 64 bits. *) let construct_int64_be_unsigned buf v flen exn = @@ -1040,6 +1164,7 @@ let construct_int64_be_unsigned buf v flen exn = if not (I64.range_unsigned v flen) then raise exn; (* Add the bytes. *) I64.map_bytes_be (Buffer._add_bits buf) (Buffer.add_byte buf) v flen +;; (* Construct a field of up to 64 bits. *) let construct_int64_le_unsigned buf v flen exn = @@ -1047,16 +1172,19 @@ let construct_int64_le_unsigned buf v flen exn = if not (I64.range_unsigned v flen) then raise exn; (* Add the bytes. *) I64.map_bytes_le (Buffer._add_bits buf) (Buffer.add_byte buf) v flen +;; let construct_int64_ne_unsigned = if nativeendian = BigEndian then construct_int64_be_unsigned else construct_int64_le_unsigned +;; let construct_int64_ee_unsigned = function | BigEndian -> construct_int64_be_unsigned | LittleEndian -> construct_int64_le_unsigned | NativeEndian -> construct_int64_ne_unsigned +;; (* Construct from a string of bytes, exact multiple of 8 bits * in length of course. @@ -1064,6 +1192,7 @@ let construct_int64_ee_unsigned = function let construct_string buf str = let len = String.length str in Buffer.add_bits buf (Bytes.unsafe_of_string str) (len lsl 3) +;; (* Construct from a bitstring. *) let construct_bitstring buf (data, off, len) = @@ -1073,36 +1202,38 @@ let construct_bitstring buf (data, off, len) = let blen = 7 - ((off + 7) land 7) in let blen = min blen len in let rec loop off len blen = - if blen = 0 then (off, len) + if blen = 0 + then off, len else ( let b = extract_bit data off len 1 - and off = off + 1 and len = len - 1 in + and off = off + 1 + and len = len - 1 in Buffer.add_bit buf b; - loop off len (blen-1) - ) + loop off len (blen - 1)) in let off, len = loop off len blen in - assert (len = 0 || (off land 7) = 0); - + assert (len = 0 || off land 7 = 0); (* Add the remaining 'len' bits. *) let data = let off = off lsr 3 in (* XXX dangerous allocation *) - if off = 0 then data - else Bytes.sub data off (Bytes.length data - off) in - + if off = 0 then data else Bytes.sub data off (Bytes.length data - off) + in Buffer.add_bits buf data len +;; (* Concatenate bitstrings. *) let concat bs = let buf = Buffer.create () in List.iter (construct_bitstring buf) bs; Buffer.contents buf +;; (*----------------------------------------------------------------------*) (* Extract a string from a bitstring. *) let string_of_bitstring (data, off, len) = - if off land 7 = 0 && len land 7 = 0 then + if off land 7 = 0 && len land 7 = 0 + then (* Easy case: everything is byte-aligned. *) String.sub (Bytes.unsafe_to_string data) (off lsr 3) (len lsr 3) else ( @@ -1110,43 +1241,47 @@ let string_of_bitstring (data, off, len) = let strlen = (len + 7) lsr 3 in let str = Bytes.make strlen '\000' in let rec loop data off len i = - if len >= 8 then ( - let c = extract_char_unsigned data off len 8 - and off = off + 8 and len = len - 8 in - Bytes.set str i (Char.chr c); - loop data off len (i+1) - ) else if len > 0 then ( - let c = extract_char_unsigned data off len len in - Bytes.set str i (Char.chr (c lsl (8-len))) - ) + if len >= 8 + then ( + let c = extract_char_unsigned data off len 8 + and off = off + 8 + and len = len - 8 in + Bytes.set str i (Char.chr c); + loop data off len (i + 1)) + else if len > 0 + then ( + let c = extract_char_unsigned data off len len in + Bytes.set str i (Char.chr (c lsl (8 - len)))) in loop data off len 0; - Bytes.unsafe_to_string str - ) + Bytes.unsafe_to_string 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 + 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 - ) + 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 -> + with + | exn -> close_out chan; raise exn +;; (*----------------------------------------------------------------------*) (* Comparison. *) @@ -1157,83 +1292,88 @@ let compare ((data1, off1, len1) as bs1) ((data2, off2, len2) as bs2) = (* ... but we have to do that by hand because the bits may * not extend to the full length of the underlying string. *) - let off1 = off1 lsr 3 and off2 = off2 lsr 3 - and len1 = len1 lsr 3 and len2 = len2 lsr 3 in + let off1 = off1 lsr 3 + and off2 = off2 lsr 3 + and len1 = len1 lsr 3 + and len2 = len2 lsr 3 in let rec loop i = - if i < len1 && i < len2 then ( - let c1 = Bytes.unsafe_get data1 (off1 + i) - and c2 = Bytes.unsafe_get data2 (off2 + i) in - let r = compare c1 c2 in - if r <> 0 then r - else loop (i+1) - ) + if i < len1 && i < len2 + then ( + let c1 = Bytes.unsafe_get data1 (off1 + i) + and c2 = Bytes.unsafe_get data2 (off2 + i) in + let r = compare c1 c2 in + if r <> 0 then r else loop (i + 1)) else len1 - len2 in - loop 0 - ) + loop 0) else ( (* Slow/unaligned. *) let str1 = string_of_bitstring bs1 and str2 = string_of_bitstring bs2 in let r = String.compare str1 str2 in - if r <> 0 then r else len1 - len2 - ) + if r <> 0 then r else len1 - len2) +;; let equals ((_, _, len1) as bs1) ((_, _, len2) as bs2) = - if len1 <> len2 then false - else if bs1 = bs2 then true - else 0 = compare bs1 bs2 + if len1 <> len2 then false else if bs1 = bs2 then true else 0 = compare bs1 bs2 +;; let is_zeroes_bitstring ((data, off, len) as bits) = - if off land 7 = 0 && len land 7 = 0 then ( - let off = off lsr 3 and len = len lsr 3 in + if off land 7 = 0 && len land 7 = 0 + then ( + let off = off lsr 3 + and len = len lsr 3 in let rec loop i = - if i < len then ( - if Bytes.unsafe_get data (off + i) <> '\000' then false - else loop (i+1) - ) else true + if i < len + then if Bytes.unsafe_get data (off + i) <> '\000' then false else loop (i + 1) + else true in - loop 0 - ) + loop 0) else ( (* Slow/unaligned case. *) let len = bitstring_length bits in let zeroes = zeroes_bitstring len in - 0 = compare bits zeroes - ) + 0 = compare bits zeroes) +;; let is_ones_bitstring ((data, off, len) as bits) = - if off land 7 = 0 && len land 7 = 0 then ( - let off = off lsr 3 and len = len lsr 3 in + if off land 7 = 0 && len land 7 = 0 + then ( + let off = off lsr 3 + and len = len lsr 3 in let rec loop i = - if i < len then ( - if Bytes.unsafe_get data (off + i) <> '\xff' then false - else loop (i+1) - ) else true + if i < len + then if Bytes.unsafe_get data (off + i) <> '\xff' then false else loop (i + 1) + else true in - loop 0 - ) + loop 0) else ( (* Slow/unaligned case. *) let len = bitstring_length bits in let ones = ones_bitstring len in - 0 = compare bits ones - ) - -external is_prefix_fastpath: bytes -> int -> bytes -> int -> int -> bool + 0 = compare bits ones) +;; + +external is_prefix_fastpath + : bytes + -> int + -> bytes + -> int + -> int + -> bool = "ocaml_bitstring_is_prefix_fastpath" let is_prefix ((b1, o1, l1) as bs1) ((b2, o2, l2) as bs2) = (* Fail if either bitstring is invalid *) - if l2 > l1 || l1 = 0 || l2 = 0 then - false - (* Use the fast path if the bitstrings are aligned *) - else if o1 land 7 = o2 land 7 then - is_prefix_fastpath b1 o1 b2 o2 l2 + if l2 > l1 || l1 = 0 || l2 = 0 + then false (* Use the fast path if the bitstrings are aligned *) + else if o1 land 7 = o2 land 7 + then is_prefix_fastpath b1 o1 b2 o2 l2 (* Bitstrings are unaligned *) - else + else ( let re = Str.regexp_string (string_of_bitstring bs2) in - Str.string_partial_match re (string_of_bitstring bs1) 0 + Str.string_partial_match re (string_of_bitstring bs1) 0) +;; (*----------------------------------------------------------------------*) (* Bit get/set functions. *) @@ -1241,30 +1381,32 @@ let is_prefix ((b1, o1, l1) as bs1) ((b2, o2, l2) as bs2) = let index_out_of_bounds () = invalid_arg "index out of bounds" let put (data, off, len) n v = - if n < 0 || n >= len then index_out_of_bounds () + if n < 0 || n >= len + then index_out_of_bounds () else ( - let i = off+n in - let si = i lsr 3 and mask = 0x80 lsr (i land 7) in + let i = off + n in + let si = i lsr 3 + and mask = 0x80 lsr (i land 7) in let c = Char.code (Bytes.get data si) in - let c = if v <> 0 then c lor mask else c land (lnot mask) in - Bytes.set data si (Char.unsafe_chr c) - ) + let c = if v <> 0 then c lor mask else c land lnot mask in + Bytes.set data si (Char.unsafe_chr c)) +;; let set bits n = put bits n 1 - let clear bits n = put bits n 0 let get (data, off, len) n = - if n < 0 || n >= len then index_out_of_bounds () + if n < 0 || n >= len + then index_out_of_bounds () else ( - let i = off+n in - let si = i lsr 3 and mask = 0x80 lsr (i land 7) in + let i = off + n in + let si = i lsr 3 + and mask = 0x80 lsr (i land 7) in let c = Char.code (Bytes.get data si) in - c land mask - ) + c land mask) +;; let is_set bits n = get bits n <> 0 - let is_clear bits n = get bits n = 0 (*----------------------------------------------------------------------*) @@ -1273,6 +1415,7 @@ let is_clear bits n = get bits n = 0 let isprint c = let c = Char.code c in c >= 32 && c < 127 +;; let hexdump_bitstring chan (data, off, len) = let count = ref 0 in @@ -1280,36 +1423,39 @@ let hexdump_bitstring chan (data, off, len) = let len = ref len in let linelen = ref 0 in let linechars = Bytes.make 16 ' ' in - fprintf chan "00000000 "; - while !len > 0 do let bits = min !len 8 in let byte = extract_char_unsigned data !off !len bits in - off := !off + bits; len := !len - bits; - - let byte = byte lsl (8-bits) in + off := !off + bits; + len := !len - bits; + let byte = byte lsl (8 - bits) in fprintf chan "%02x " byte; - incr count; - Bytes.set linechars !linelen + Bytes.set + linechars + !linelen (let c = Char.chr byte in if isprint c then c else '.'); incr linelen; if !linelen = 8 then fprintf chan " "; - if !linelen = 16 then ( + if !linelen = 16 + then ( fprintf chan " |%s|\n%08x " (Bytes.unsafe_to_string linechars) !count; linelen := 0; - for i = 0 to 15 do Bytes.set linechars i ' ' done - ) + for i = 0 to 15 do + Bytes.set linechars i ' ' + done) done; - - if !linelen > 0 then ( - let skip = (16 - !linelen) * 3 + if !linelen < 8 then 1 else 0 in - for _ = 0 to skip-1 do fprintf chan " " done; - fprintf chan " |%s|\n%!" (Bytes.unsafe_to_string linechars) - ) else - fprintf chan "\n%!" + if !linelen > 0 + then ( + let skip = ((16 - !linelen) * 3) + if !linelen < 8 then 1 else 0 in + for _ = 0 to skip - 1 do + fprintf chan " " + done; + fprintf chan " |%s|\n%!" (Bytes.unsafe_to_string linechars)) + else fprintf chan "\n%!" +;; (*----------------------------------------------------------------------*) (* Alias of functions shadowed by Core. *) diff --git a/src/bitstring.mli b/src/bitstring.mli index 4f06887..395b658 100644 --- a/src/bitstring.mli +++ b/src/bitstring.mli @@ -646,12 +646,14 @@ bitmatch bits with {3 Types} *) -type endian = BigEndian | LittleEndian | NativeEndian +type endian = + | BigEndian + | LittleEndian + | NativeEndian -val string_of_endian : endian -> string (** Endianness. *) +val string_of_endian : endian -> string -type bitstring = bytes * int * int (** [bitstring] is the basic type used to store bitstrings. The type contains the underlying data (a bytes), @@ -667,16 +669,16 @@ type bitstring = bytes * int * int See also {!bitstring_of_string}, {!bitstring_of_file}, {!hexdump_bitstring}, {!bitstring_length}. *) +type bitstring = bytes * int * int -type t = bitstring (** [t] is a synonym for the {!bitstring} type. This allows you to use this module with functors like [Set] and [Map] from the stdlib. *) +type t = bitstring (** {3 Exceptions} *) -exception Construct_failure of string * string * int * int (** [Construct_failure (message, file, line, char)] may be raised by the [BITSTRING] constructor. @@ -689,10 +691,10 @@ exception Construct_failure of string * string * int * int [file], [line] and [char] point to the original source location of the [BITSTRING] constructor that failed. *) +exception Construct_failure of string * string * int * int (** {3 Bitstring comparison} *) -val compare : bitstring -> bitstring -> int (** [compare bs1 bs2] compares two bitstrings and returns zero if they are equal, a negative number if [bs1 < bs2], or a positive number if [bs1 > bs2]. @@ -702,30 +704,30 @@ val compare : bitstring -> bitstring -> int (see {!bitstring}). The ordering is total and lexicographic. *) +val compare : bitstring -> bitstring -> int -val equals : bitstring -> bitstring -> bool (** [equals] returns true if and only if the two bitstrings are semantically equal. It is the same as calling [compare] and testing if the result is [0], but usually more efficient. *) +val equals : bitstring -> bitstring -> bool -val is_zeroes_bitstring : bitstring -> bool (** Tests if the bitstring is all zero bits (cf. {!zeroes_bitstring}) *) +val is_zeroes_bitstring : bitstring -> bool -val is_ones_bitstring : bitstring -> bool (** Tests if the bitstring is all one bits (cf. {!ones_bitstring}). *) +val is_ones_bitstring : bitstring -> bool -val is_prefix: bitstring -> bitstring -> bool (** [is_prefix bs1 bs2] returns true if bs2 is a prefix of bs1 *) +val is_prefix : bitstring -> bitstring -> bool (** {3 Bitstring manipulation} *) -val bitstring_length : bitstring -> int (** [bitstring_length bitstring] returns the length of the bitstring in bits. Note this just returns the third field in the {!bitstring} tuple. *) +val bitstring_length : bitstring -> int -val subbitstring : bitstring -> int -> int -> bitstring (** [subbitstring bits off len] returns a sub-bitstring of the bitstring, starting at offset [off] bits and with length [len] bits. @@ -735,8 +737,8 @@ val subbitstring : bitstring -> int -> int -> bitstring Note that this function just changes the offset and length fields of the {!bitstring} tuple, so is very efficient. *) +val subbitstring : bitstring -> int -> int -> bitstring -val dropbits : int -> bitstring -> bitstring (** Drop the first n bits of the bitstring and return a new bitstring which is shorter by n bits. @@ -745,8 +747,8 @@ val dropbits : int -> bitstring -> bitstring Note that this function just changes the offset and length fields of the {!bitstring} tuple, so is very efficient. *) +val dropbits : int -> bitstring -> bitstring -val takebits : int -> bitstring -> bitstring (** Take the first n bits of the bitstring and return a new bitstring which is exactly n bits long. @@ -755,21 +757,21 @@ val takebits : int -> bitstring -> bitstring Note that this function just changes the offset and length fields of the {!bitstring} tuple, so is very efficient. *) +val takebits : int -> bitstring -> bitstring -val concat : bitstring list -> bitstring (** Concatenate a list of bitstrings together into a single bitstring. *) +val concat : bitstring list -> bitstring (** {3 Constructing bitstrings} *) -val empty_bitstring : bitstring (** [empty_bitstring] is the empty, zero-length bitstring. *) +val empty_bitstring : bitstring -val create_bitstring : int -> bitstring (** [create_bitstring n] creates an [n] bit bitstring containing all zeroes. *) +val create_bitstring : int -> bitstring -val make_bitstring : int -> char -> bitstring (** [make_bitstring n c] creates an [n] bit bitstring containing the repeated 8 bit pattern in [c]. @@ -778,16 +780,16 @@ val make_bitstring : int -> char -> bitstring Note that the length is in bits, not bytes. The length does NOT need to be a multiple of 8. *) +val make_bitstring : int -> char -> bitstring -val zeroes_bitstring : int -> bitstring (** [zeroes_bitstring] creates an [n] bit bitstring of all 0's. Actually this is the same as {!create_bitstring}. *) +val zeroes_bitstring : int -> bitstring -val ones_bitstring : int -> bitstring (** [ones_bitstring] creates an [n] bit bitstring of all 1's. *) +val ones_bitstring : int -> bitstring -val bitstring_of_string : string -> bitstring (** [bitstring_of_string str] creates a bitstring of length [String.length str * 8] (bits) containing the bits in [str]. @@ -795,12 +797,12 @@ val bitstring_of_string : string -> bitstring Note that the bitstring uses [str] as the underlying string (see the representation of {!bitstring}) so you should not change [str] after calling this. *) +val bitstring_of_string : string -> bitstring -val bitstring_of_file : string -> bitstring (** [bitstring_of_file filename] loads the named file into a bitstring. *) +val bitstring_of_file : string -> bitstring -val bitstring_of_chan : in_channel -> bitstring (** [bitstring_of_chan chan] loads the contents of the input channel [chan] as a bitstring. @@ -809,28 +811,28 @@ val bitstring_of_chan : in_channel -> bitstring be a multiple of 8 bits. See also {!bitstring_of_chan_max}. *) +val bitstring_of_chan : in_channel -> bitstring -val bitstring_of_chan_max : in_channel -> int -> bitstring (** [bitstring_of_chan_max chan max] works like {!bitstring_of_chan} but will only read up to [max] bytes from the channel (or fewer if the end of input occurs before that). *) +val bitstring_of_chan_max : in_channel -> int -> bitstring -val bitstring_of_file_descr : Unix.file_descr -> bitstring (** [bitstring_of_file_descr fd] loads the contents of the file descriptor [fd] as a bitstring. See also {!bitstring_of_chan}, {!bitstring_of_file_descr_max}. *) +val bitstring_of_file_descr : Unix.file_descr -> bitstring -val bitstring_of_file_descr_max : Unix.file_descr -> int -> bitstring (** [bitstring_of_file_descr_max fd max] works like {!bitstring_of_file_descr} but will only read up to [max] bytes from the channel (or fewer if the end of input occurs before that). *) +val bitstring_of_file_descr_max : Unix.file_descr -> int -> bitstring (** {3 Converting bitstrings} *) -val string_of_bitstring : bitstring -> string (** [string_of_bitstring bitstring] converts a bitstring to a string (eg. to allow comparison). @@ -842,14 +844,14 @@ val string_of_bitstring : bitstring -> string 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 string_of_bitstring : bitstring -> string -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_file : bitstring -> string -> unit -val bitstring_to_chan : bitstring -> out_channel -> unit (** [bitstring_to_file bits filename] writes the bitstring [bits] to the channel [chan]. @@ -866,27 +868,29 @@ val bitstring_to_chan : bitstring -> out_channel -> unit [BITSTRING] operator and is an exact multiple of 8 bits wide, then this function will always work efficiently. *) +val bitstring_to_chan : bitstring -> out_channel -> unit (** {3 Printing bitstrings} *) -val hexdump_bitstring : out_channel -> bitstring -> unit (** [hexdump_bitstring chan bitstring] prints the bitstring to the output channel in a format similar to the Unix command [hexdump -C]. *) +val hexdump_bitstring : out_channel -> bitstring -> unit (** {3 Bitstring buffer} *) +(** Buffers are mainly used by the [BITSTRING] constructor, but + may also be useful for end users. They work much like the + standard library [Buffer] module. *) module Buffer : sig type t + val create : unit -> t val contents : t -> bitstring val add_bits : t -> bytes -> int -> unit val add_bit : t -> bool -> unit val add_byte : t -> int -> unit end -(** Buffers are mainly used by the [BITSTRING] constructor, but - may also be useful for end users. They work much like the - standard library [Buffer] module. *) (** {3 Get/set bits} @@ -899,32 +903,32 @@ end if the index is out of range of the bitstring. *) +(** [set bits n] sets the [n]th bit in the bitstring to 1. *) val set : bitstring -> int -> unit - (** [set bits n] sets the [n]th bit in the bitstring to 1. *) +(** [clear bits n] sets the [n]th bit in the bitstring to 0. *) val clear : bitstring -> int -> unit - (** [clear bits n] sets the [n]th bit in the bitstring to 0. *) +(** [is_set bits n] is true if the [n]th bit is set to 1. *) val is_set : bitstring -> int -> bool - (** [is_set bits n] is true if the [n]th bit is set to 1. *) +(** [is_clear bits n] is true if the [n]th bit is set to 0. *) val is_clear : bitstring -> int -> bool - (** [is_clear bits n] is true if the [n]th bit is set to 0. *) -val put : bitstring -> int -> int -> unit - (** [put bits n v] sets the [n]th bit in the bitstring to 1 +(** [put bits n v] sets the [n]th bit in the bitstring to 1 if [v] is not zero, or to 0 if [v] is zero. *) +val put : bitstring -> int -> int -> unit +(** [get bits n] returns the [n]th bit (returns non-zero or 0). *) val get : bitstring -> int -> int - (** [get bits n] returns the [n]th bit (returns non-zero or 0). *) (** {3 Miscellaneous} *) -val debug : bool ref (** Set this variable to true to enable extended debugging. This only works if debugging was also enabled in the [pa_bitstring.ml] file at compile time, otherwise it does nothing. *) +val debug : bool ref (**/**) @@ -935,54 +939,60 @@ val debug : bool ref (* 'extract' functions are used in bitmatch statements. *) val extract_bit : bytes -> int -> int -> int -> bool - val extract_char_unsigned : bytes -> int -> int -> int -> int - val extract_char_signed : bytes -> int -> int -> int -> int - val extract_int_be_unsigned : bytes -> int -> int -> int -> int - val extract_int_be_signed : bytes -> int -> int -> int -> int - val extract_int_le_unsigned : bytes -> int -> int -> int -> int - val extract_int_le_signed : bytes -> int -> int -> int -> int - val extract_int_ne_unsigned : bytes -> int -> int -> int -> int - val extract_int_ne_signed : bytes -> int -> int -> int -> int - val extract_int_ee_unsigned : endian -> bytes -> int -> int -> int -> int - val extract_int_ee_signed : endian -> bytes -> int -> int -> int -> int - val extract_int32_be_unsigned : bytes -> int -> int -> int -> int32 - val extract_int32_le_unsigned : bytes -> int -> int -> int -> int32 - val extract_int32_ne_unsigned : bytes -> int -> int -> int -> int32 - val extract_int32_ee_unsigned : endian -> bytes -> int -> int -> int -> int32 - val extract_int64_be_unsigned : bytes -> int -> int -> int -> int64 - val extract_int64_le_unsigned : bytes -> int -> int -> int -> int64 - val extract_int64_ne_unsigned : bytes -> int -> int -> int -> int64 - val extract_int64_ee_unsigned : endian -> bytes -> int -> int -> int -> int64 -external extract_fastpath_int16_be_unsigned : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int16_be_unsigned" - -external extract_fastpath_int16_le_unsigned : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int16_le_unsigned" - -external extract_fastpath_int16_ne_unsigned : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int16_ne_unsigned" - -external extract_fastpath_int16_be_signed : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int16_be_signed" - -external extract_fastpath_int16_le_signed : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int16_le_signed" - -external extract_fastpath_int16_ne_signed : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int16_ne_signed" +external extract_fastpath_int16_be_unsigned + : bytes + -> int + -> int + = "ocaml_bitstring_extract_fastpath_int16_be_unsigned" + +external extract_fastpath_int16_le_unsigned + : bytes + -> int + -> int + = "ocaml_bitstring_extract_fastpath_int16_le_unsigned" + +external extract_fastpath_int16_ne_unsigned + : bytes + -> int + -> int + = "ocaml_bitstring_extract_fastpath_int16_ne_unsigned" + +external extract_fastpath_int16_be_signed + : bytes + -> int + -> int + = "ocaml_bitstring_extract_fastpath_int16_be_signed" + +external extract_fastpath_int16_le_signed + : bytes + -> int + -> int + = "ocaml_bitstring_extract_fastpath_int16_le_signed" + +external extract_fastpath_int16_ne_signed + : bytes + -> int + -> int + = "ocaml_bitstring_extract_fastpath_int16_ne_signed" (* external extract_fastpath_int24_be_unsigned : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int24_be_unsigned" @@ -998,17 +1008,41 @@ external extract_fastpath_int24_le_signed : bytes -> int -> int = "ocaml_bitstri external extract_fastpath_int24_ne_signed : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int24_ne_signed" *) -external extract_fastpath_int32_be_unsigned : bytes -> int -> int32 = "ocaml_bitstring_extract_fastpath_int32_be_unsigned" - -external extract_fastpath_int32_le_unsigned : bytes -> int -> int32 = "ocaml_bitstring_extract_fastpath_int32_le_unsigned" - -external extract_fastpath_int32_ne_unsigned : bytes -> int -> int32 = "ocaml_bitstring_extract_fastpath_int32_ne_unsigned" - -external extract_fastpath_int32_be_signed : bytes -> int -> int32 = "ocaml_bitstring_extract_fastpath_int32_be_signed" - -external extract_fastpath_int32_le_signed : bytes -> int -> int32 = "ocaml_bitstring_extract_fastpath_int32_le_signed" - -external extract_fastpath_int32_ne_signed : bytes -> int -> int32 = "ocaml_bitstring_extract_fastpath_int32_ne_signed" +external extract_fastpath_int32_be_unsigned + : bytes + -> int + -> int32 + = "ocaml_bitstring_extract_fastpath_int32_be_unsigned" + +external extract_fastpath_int32_le_unsigned + : bytes + -> int + -> int32 + = "ocaml_bitstring_extract_fastpath_int32_le_unsigned" + +external extract_fastpath_int32_ne_unsigned + : bytes + -> int + -> int32 + = "ocaml_bitstring_extract_fastpath_int32_ne_unsigned" + +external extract_fastpath_int32_be_signed + : bytes + -> int + -> int32 + = "ocaml_bitstring_extract_fastpath_int32_be_signed" + +external extract_fastpath_int32_le_signed + : bytes + -> int + -> int32 + = "ocaml_bitstring_extract_fastpath_int32_le_signed" + +external extract_fastpath_int32_ne_signed + : bytes + -> int + -> int32 + = "ocaml_bitstring_extract_fastpath_int32_ne_signed" (* external extract_fastpath_int40_be_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int40_be_unsigned" @@ -1048,59 +1082,63 @@ external extract_fastpath_int56_le_signed : bytes -> int -> int64 = "ocaml_bitst external extract_fastpath_int56_ne_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int56_ne_signed" *) -external extract_fastpath_int64_be_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int64_be_unsigned" - -external extract_fastpath_int64_le_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int64_le_unsigned" - -external extract_fastpath_int64_ne_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int64_ne_unsigned" - -external extract_fastpath_int64_be_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int64_be_signed" - -external extract_fastpath_int64_le_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int64_le_signed" - -external extract_fastpath_int64_ne_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int64_ne_signed" +external extract_fastpath_int64_be_unsigned + : bytes + -> int + -> int64 + = "ocaml_bitstring_extract_fastpath_int64_be_unsigned" + +external extract_fastpath_int64_le_unsigned + : bytes + -> int + -> int64 + = "ocaml_bitstring_extract_fastpath_int64_le_unsigned" + +external extract_fastpath_int64_ne_unsigned + : bytes + -> int + -> int64 + = "ocaml_bitstring_extract_fastpath_int64_ne_unsigned" + +external extract_fastpath_int64_be_signed + : bytes + -> int + -> int64 + = "ocaml_bitstring_extract_fastpath_int64_be_signed" + +external extract_fastpath_int64_le_signed + : bytes + -> int + -> int64 + = "ocaml_bitstring_extract_fastpath_int64_le_signed" + +external extract_fastpath_int64_ne_signed + : bytes + -> int + -> int64 + = "ocaml_bitstring_extract_fastpath_int64_ne_signed" (* 'construct' functions are used in BITSTRING constructors. *) val construct_bit : Buffer.t -> bool -> int -> exn -> unit - val construct_char_unsigned : Buffer.t -> int -> int -> exn -> unit - val construct_char_signed : Buffer.t -> int -> int -> exn -> unit - val construct_int_be_unsigned : Buffer.t -> int -> int -> exn -> unit - val construct_int_le_unsigned : Buffer.t -> int -> int -> exn -> unit - val construct_int_ne_unsigned : Buffer.t -> int -> int -> exn -> unit - val construct_int_ee_unsigned : endian -> Buffer.t -> int -> int -> exn -> unit - val construct_int_be_signed : Buffer.t -> int -> int -> exn -> unit - val construct_int_le_signed : Buffer.t -> int -> int -> exn -> unit - val construct_int_ne_signed : Buffer.t -> int -> int -> exn -> unit - val construct_int_ee_signed : endian -> Buffer.t -> int -> int -> exn -> unit - val construct_int32_be_unsigned : Buffer.t -> int32 -> int -> exn -> unit - val construct_int32_le_unsigned : Buffer.t -> int32 -> int -> exn -> unit - val construct_int32_ne_unsigned : Buffer.t -> int32 -> int -> exn -> unit - val construct_int32_ee_unsigned : endian -> Buffer.t -> int32 -> int -> exn -> unit - val construct_int64_be_unsigned : Buffer.t -> int64 -> int -> exn -> unit - val construct_int64_le_unsigned : Buffer.t -> int64 -> int -> exn -> unit - val construct_int64_ne_unsigned : Buffer.t -> int64 -> int -> exn -> unit - val construct_int64_ee_unsigned : endian -> Buffer.t -> int64 -> int -> exn -> unit - val construct_string : Buffer.t -> string -> unit - val construct_bitstring : Buffer.t -> bitstring -> unit (* Alias of functions shadowed by Core. *) diff --git a/src/bitstring_config.ml b/src/bitstring_config.ml index a83fc8b..0fa18d2 100644 --- a/src/bitstring_config.ml +++ b/src/bitstring_config.ml @@ -25,6 +25,5 @@ *) let nativeendian = - if Sys.big_endian - then Bitstring_types.BigEndian - else Bitstring_types.LittleEndian + if Sys.big_endian then Bitstring_types.BigEndian else Bitstring_types.LittleEndian +;; diff --git a/src/bitstring_types.ml b/src/bitstring_types.ml index 6dc7b7b..9613465 100644 --- a/src/bitstring_types.ml +++ b/src/bitstring_types.ml @@ -21,9 +21,13 @@ * *) -type endian = BigEndian | LittleEndian | NativeEndian +type endian = + | BigEndian + | LittleEndian + | NativeEndian let string_of_endian = function | BigEndian -> "bigendian" | LittleEndian -> "littleendian" | NativeEndian -> "nativeendian" +;; diff --git a/tests/BitstringConstructorTest.ml b/tests/BitstringConstructorTest.ml index 7da2303..e3f1bbe 100644 --- a/tests/BitstringConstructorTest.ml +++ b/tests/BitstringConstructorTest.ml @@ -22,45 +22,54 @@ open Bitstring *) let imbricated_bistring_test context = - let result = "\xde\xad\xbe\xef\x42\x0a" in - let magic = "\xde\xad\xbe\xef" in + let result = "\xde\xad\xbe\xef\x42\x0a" in + let magic = "\xde\xad\xbe\xef" in let version = 0x42 in - let data = 10 in - let header = [%bitstring {| version : 8 |}] in - let bits = [%bitstring - {| magic : -1 : string + let data = 10 in + let header = [%bitstring {| version : 8 |}] in + let bits = + [%bitstring + {| magic : -1 : string ; header : -1 : bitstring ; data : 8 - |}] in + |}] + in let dump = Bitstring.string_of_bitstring bits in assert_equal result dump +;; (* * Constructor style test *) let constructor_style_test context = - let%bitstring bits1 = {| "GIF87a" : 6*8 : string - ; 2145 : 16 : littleendian - ; 2145 : 16 : littleendian - ; true : 1 - ; 7 : 3 - ; false : 1 - ; 7 : 3 - ; 0 : 8 - ; 0 : 8 - |} in - let bits2 = [%bitstring {| "GIF87a" : 6*8 : string - ; 2145 : 16 : littleendian - ; 2145 : 16 : littleendian - ; true : 1 - ; 7 : 3 - ; false : 1 - ; 7 : 3 - ; 0 : 8 - ; 0 : 8 - |}] in + let%bitstring bits1 = + {| "GIF87a" : 6*8 : string + ; 2145 : 16 : littleendian + ; 2145 : 16 : littleendian + ; true : 1 + ; 7 : 3 + ; false : 1 + ; 7 : 3 + ; 0 : 8 + ; 0 : 8 + |} + in + let bits2 = + [%bitstring + {| "GIF87a" : 6*8 : string + ; 2145 : 16 : littleendian + ; 2145 : 16 : littleendian + ; true : 1 + ; 7 : 3 + ; false : 1 + ; 7 : 3 + ; 0 : 8 + ; 0 : 8 + |}] + in assert_bool "Bistrings are not equal" (Bitstring.equals bits1 bits2) +;; (* * Swap test @@ -71,14 +80,16 @@ let swap bs = | {| a : 1 : bitstring; b : 1 : bitstring|} -> [%bitstring {| b : 1 : bitstring; a : 1 : bitstring |}] | {| _ |} -> failwith "invalid input" +;; let swap_test context = - let one = [%bitstring {| 1 : 2 |}] in - let two = [%bitstring {| 2 : 2 |}] in + let one = [%bitstring {| 1 : 2 |}] in + let two = [%bitstring {| 2 : 2 |}] in let three = [%bitstring {| 3 : 2 |}] in - assert_bool "Bitstring swap failed" (Bitstring.equals two (swap one)); - assert_bool "Bitstring swap failed" (Bitstring.equals one (swap two)); + assert_bool "Bitstring swap failed" (Bitstring.equals two (swap one)); + assert_bool "Bitstring swap failed" (Bitstring.equals one (swap two)); assert_bool "Bitstring swap failed" (Bitstring.equals three (swap three)) +;; (* * External value test @@ -89,14 +100,18 @@ let external_value_test context = let int16_value = 2 in let int32_value = 1_l in let bool_value = true in - let bits = [%bitstring {| int16_value : 16 - ; int32_value : 32 - ; 1 : 1 - ; bool_value : 1 - ; 0 : 6 - |}] in + let bits = + [%bitstring + {| int16_value : 16 + ; int32_value : 32 + ; 1 : 1 + ; bool_value : 1 + ; 0 : 6 + |}] + in let str = Bitstring.string_of_bitstring bits in assert_equal str result +;; (* * Int for [17,31] bits test @@ -107,6 +122,7 @@ let int_parser_test context = let%bitstring bits = {| 2 : 24 |} in let str = Bitstring.string_of_bitstring bits in assert_equal str result +;; (* * Int32 for 32 bits test @@ -117,6 +133,7 @@ let int32_parser_test context = let%bitstring bits = {| 2_l : 32 |} in let str = Bitstring.string_of_bitstring bits in assert_equal str result +;; (* * Structural let @@ -128,6 +145,7 @@ let str_item_test context = let result = "\x00\x00\x00\x02" in let str = Bitstring.string_of_bitstring ext_bits in assert_equal str result +;; (* * Subtyping. @@ -138,20 +156,23 @@ let subtype_test context = let%bitstring b = {| x : 6 |} in let%bitstring c = {| (x :> int) : 6 |} in assert (Bitstring.equals b c) +;; (* * Test suite definition *) -let suite = "BitstringConstructorTest" >::: [ - "imbricated_bistring_test" >:: imbricated_bistring_test; - "constructor_style_test" >:: constructor_style_test; - "swap_test" >:: swap_test; - "external_value_test" >:: external_value_test; - "int_parser_test" >:: int_parser_test; - "int32_parser_test" >:: int32_parser_test; - "str_item_test" >:: str_item_test; - "subtype_test" >:: subtype_test; - ] +let suite = + "BitstringConstructorTest" + >::: [ "imbricated_bistring_test" >:: imbricated_bistring_test + ; "constructor_style_test" >:: constructor_style_test + ; "swap_test" >:: swap_test + ; "external_value_test" >:: external_value_test + ; "int_parser_test" >:: int_parser_test + ; "int32_parser_test" >:: int32_parser_test + ; "str_item_test" >:: str_item_test + ; "subtype_test" >:: subtype_test + ] +;; let () = run_test_tt_main suite diff --git a/tests/BitstringLegacyTest.ml b/tests/BitstringLegacyTest.ml index 0fded37..0529d92 100644 --- a/tests/BitstringLegacyTest.ml +++ b/tests/BitstringLegacyTest.ml @@ -5,18 +5,16 @@ open Printf * Helper functions *) -let rec range a b = - if a <= b then - a :: range (a+1) b - else - [] +let rec range a b = if a <= b then a :: range (a + 1) b else [] (* * Just check that the extension and library load without error. *) let load_test _ = - let _ = Bitstring.extract_bit in () + let _ = Bitstring.extract_bit in + () +;; (* * Just check that we can run some functions from the library. @@ -25,6 +23,7 @@ let load_test _ = let run_test _ = let bits = Bitstring.create_bitstring 16 in ignore (Bitstring.string_of_bitstring bits) +;; (* * Match random bits. @@ -32,13 +31,11 @@ let run_test _ = let match_random_bits_test _ = Random.self_init (); - for len = 0 to 999 do (* * Create a random string of bits. *) - let expected = List.map (fun _ -> Random.bool ()) (range 0 (len-1)) in - + let expected = List.map (fun _ -> Random.bool ()) (range 0 (len - 1)) in let bits = Bitstring.Buffer.create () in List.iter (Bitstring.Buffer.add_bit bits) expected; let bits = Bitstring.Buffer.contents bits in @@ -52,10 +49,10 @@ let match_random_bits_test _ = | {| b0 : 1; rest : -1 : bitstring |} -> b0 :: loop rest | {| _ |} -> [] in - loop bits in + loop bits + in assert_equal actual expected; - (* - *) + (* *) let actual = let rec loop bits = match%bitstring bits with @@ -63,48 +60,52 @@ let match_random_bits_test _ = | {| b0 : 1; rest : -1 : bitstring |} -> b0 :: loop rest | {| _ |} -> [] in - loop bits in + loop bits + in assert_equal actual expected; - (* - *) + (* *) let actual = let rec loop bits = match%bitstring bits with | {| b0 : 1; b1 : 1; b2 : 1; - rest : -1 : bitstring |} -> b0 :: b1 :: b2 :: loop rest + rest : -1 : bitstring |} + -> b0 :: b1 :: b2 :: loop rest | {| b0 : 1; rest : -1 : bitstring |} -> b0 :: loop rest | {| _ |} -> [] in - loop bits in + loop bits + in assert_equal actual expected; - (* - *) + (* *) let actual = let rec loop bits = match%bitstring bits with | {| b0 : 1; b1 : 1; b2 : 1; b3 : 1; - rest : -1 : bitstring |} -> b0 :: b1 :: b2 :: b3 :: loop rest + rest : -1 : bitstring |} + -> b0 :: b1 :: b2 :: b3 :: loop rest | {| b0 : 1; rest : -1 : bitstring |} -> b0 :: loop rest | {| _ |} -> [] in - loop bits in + loop bits + in assert_equal actual expected; - (* - *) + (* *) let actual = let rec loop bits = match%bitstring bits with | {| b0 : 1; b1 : 1; b2 : 1; b3 : 1; b4 : 1; b5 : 1; b6 : 1; b7 : 1; b8 : 1; - rest : -1 : bitstring |} -> - b0 :: b1 :: b2 :: b3 :: b4 :: b5 :: b6 :: b7 :: b8 :: loop rest + rest : -1 : bitstring |} + -> b0 :: b1 :: b2 :: b3 :: b4 :: b5 :: b6 :: b7 :: b8 :: loop rest | {| b0 : 1; rest : -1 : bitstring |} -> b0 :: loop rest | {| _ |} -> [] in - loop bits in - assert_equal actual expected; + loop bits + in + assert_equal actual expected done +;; (* * Match random bits with integers. @@ -112,21 +113,24 @@ let match_random_bits_test _ = let match_random_bits_with_int_test _ = Random.self_init (); - for len = 1 to 99 do for bitlen = 1 to 63 do (* * Create a random string of ints. *) let expected = - List.map (fun _ -> - Random.int64 (Int64.sub (Int64.shift_left 1L bitlen) 1L)) - (range 0 (len-1)) in - + List.map + (fun _ -> Random.int64 (Int64.sub (Int64.shift_left 1L bitlen) 1L)) + (range 0 (len - 1)) + in let bits = Bitstring.Buffer.create () in - List.iter (fun i -> - Bitstring.construct_int64_be_unsigned bits i bitlen - (Failure "constructing string")) + List.iter + (fun i -> + Bitstring.construct_int64_be_unsigned + bits + i + bitlen + (Failure "constructing string")) expected; let bits = Bitstring.Buffer.contents bits in (* @@ -137,16 +141,17 @@ let match_random_bits_with_int_test _ = let rec loop bits = match%bitstring bits with | {| i : bitlen; rest : -1 : bitstring |} - when Bitstring.bitstring_length rest = 0 -> [i] + when Bitstring.bitstring_length rest = 0 -> [ i ] | {| i : bitlen; rest : -1 : bitstring |} -> i :: loop rest | {| _ |} -> - failwith (sprintf "loop failed with len = %d, bitlen = %d" - len bitlen) + failwith (sprintf "loop failed with len = %d, bitlen = %d" len bitlen) in - loop bits in + loop bits + in assert_equal actual expected done done +;; (* * Check value limits. @@ -156,34 +161,28 @@ let check_value_limits_test _ = let a = Array.init 387 (fun i -> i - 129) in let limits b = Array.fold_left - (fun (mini,maxi) i -> + (fun (mini, maxi) i -> try ignore (b i); - (min mini i, max maxi i) + min mini i, max maxi i with - _ -> (mini, maxi)) - (0,0) + | _ -> mini, maxi) + (0, 0) a in assert_equal - (List.map limits [ - (fun i -> [%bitstring {| i : 2 : signed |}]); - (fun i -> [%bitstring {| i : 3 : signed |}]); - (fun i -> [%bitstring {| i : 4 : signed |}]); - (fun i -> [%bitstring {| i : 5 : signed |}]); - (fun i -> [%bitstring {| i : 6 : signed |}]); - (fun i -> [%bitstring {| i : 7 : signed |}]); - (fun i -> [%bitstring {| i : 8 : signed |}]); - ]) - [ - (-2, 3); - (-4, 7); - (-8, 15); - (-16, 31); - (-32, 63); - (-64, 127); - (-128, 255) - ] + (List.map + limits + [ (fun i -> [%bitstring {| i : 2 : signed |}]) + ; (fun i -> [%bitstring {| i : 3 : signed |}]) + ; (fun i -> [%bitstring {| i : 4 : signed |}]) + ; (fun i -> [%bitstring {| i : 5 : signed |}]) + ; (fun i -> [%bitstring {| i : 6 : signed |}]) + ; (fun i -> [%bitstring {| i : 7 : signed |}]) + ; (fun i -> [%bitstring {| i : 8 : signed |}]) + ]) + [ -2, 3; -4, 7; -8, 15; -16, 31; -32, 63; -64, 127; -128, 255 ] +;; (* * Signed byte create. @@ -191,29 +190,32 @@ let check_value_limits_test _ = let signed_byte_create_test _ = let a n = - let n' = 1 lsl (pred n) in - Array.to_list (Array.init n' (fun i -> -(n'-i), n'+i)) @ - Array.to_list (Array.init (n' lsl 1) (fun i -> i,i)) + let n' = 1 lsl pred n in + Array.to_list (Array.init n' (fun i -> -(n' - i), n' + i)) + @ Array.to_list (Array.init (n' lsl 1) (fun i -> i, i)) in let t s i = List.fold_left - (fun ok (n,c) -> s n = String.make 1 (Char.chr (c lsl (8-i))) && ok ) + (fun ok (n, c) -> s n = String.make 1 (Char.chr (c lsl (8 - i))) && ok) true (a i) in - let ok = fst (List.fold_left (fun (ok,i) s -> - t s i && ok, succ i) (true, 2) - [ - (fun i -> Bitstring.string_of_bitstring [%bitstring {| i : 2 : signed |}]); - (fun i -> Bitstring.string_of_bitstring [%bitstring {| i : 3 : signed |}]); - (fun i -> Bitstring.string_of_bitstring [%bitstring {| i : 4 : signed |}]); - (fun i -> Bitstring.string_of_bitstring [%bitstring {| i : 5 : signed |}]); - (fun i -> Bitstring.string_of_bitstring [%bitstring {| i : 6 : signed |}]); - (fun i -> Bitstring.string_of_bitstring [%bitstring {| i : 7 : signed |}]); - (fun i -> Bitstring.string_of_bitstring [%bitstring {| i : 8 : signed |}]); - ]) + let ok = + fst + (List.fold_left + (fun (ok, i) s -> t s i && ok, succ i) + (true, 2) + [ (fun i -> Bitstring.string_of_bitstring [%bitstring {| i : 2 : signed |}]) + ; (fun i -> Bitstring.string_of_bitstring [%bitstring {| i : 3 : signed |}]) + ; (fun i -> Bitstring.string_of_bitstring [%bitstring {| i : 4 : signed |}]) + ; (fun i -> Bitstring.string_of_bitstring [%bitstring {| i : 5 : signed |}]) + ; (fun i -> Bitstring.string_of_bitstring [%bitstring {| i : 6 : signed |}]) + ; (fun i -> Bitstring.string_of_bitstring [%bitstring {| i : 7 : signed |}]) + ; (fun i -> Bitstring.string_of_bitstring [%bitstring {| i : 8 : signed |}]) + ]) in assert_equal ok true +;; (* * Signed byte create and match @@ -221,29 +223,47 @@ let signed_byte_create_test _ = let signed_byte_create_and_match_test _ = let a n = - let n' = 1 lsl (pred n) in - Array.to_list (Array.init (n' lsl 1) (fun i -> i-n')) + let n' = 1 lsl pred n in + Array.to_list (Array.init (n' lsl 1) (fun i -> i - n')) in - - let t s i = - List.fold_left - (fun ok n -> s n = n && ok ) - true - (a i) - in - let ok = fst (List.fold_left (fun (ok,i) s -> - t s i && ok, succ i) (true, 2) - [ - (fun n -> match%bitstring [%bitstring {| n : 2 : signed |}] with {| i : 2 : signed |} -> i | {| _ |} -> assert false); - (fun n -> match%bitstring [%bitstring {| n : 3 : signed |}] with {| i : 3 : signed |} -> i | {| _ |} -> assert false); - (fun n -> match%bitstring [%bitstring {| n : 4 : signed |}] with {| i : 4 : signed |} -> i | {| _ |} -> assert false); - (fun n -> match%bitstring [%bitstring {| n : 5 : signed |}] with {| i : 5 : signed |} -> i | {| _ |} -> assert false); - (fun n -> match%bitstring [%bitstring {| n : 6 : signed |}] with {| i : 6 : signed |} -> i | {| _ |} -> assert false); - (fun n -> match%bitstring [%bitstring {| n : 7 : signed |}] with {| i : 7 : signed |} -> i | {| _ |} -> assert false); - (fun n -> match%bitstring [%bitstring {| n : 8 : signed |}] with {| i : 8 : signed |} -> i | {| _ |} -> assert false); - ]) + let t s i = List.fold_left (fun ok n -> s n = n && ok) true (a i) in + let ok = + fst + (List.fold_left + (fun (ok, i) s -> t s i && ok, succ i) + (true, 2) + [ (fun n -> + match%bitstring [%bitstring {| n : 2 : signed |}] with + | {| i : 2 : signed |} -> i + | {| _ |} -> assert false) + ; (fun n -> + match%bitstring [%bitstring {| n : 3 : signed |}] with + | {| i : 3 : signed |} -> i + | {| _ |} -> assert false) + ; (fun n -> + match%bitstring [%bitstring {| n : 4 : signed |}] with + | {| i : 4 : signed |} -> i + | {| _ |} -> assert false) + ; (fun n -> + match%bitstring [%bitstring {| n : 5 : signed |}] with + | {| i : 5 : signed |} -> i + | {| _ |} -> assert false) + ; (fun n -> + match%bitstring [%bitstring {| n : 6 : signed |}] with + | {| i : 6 : signed |} -> i + | {| _ |} -> assert false) + ; (fun n -> + match%bitstring [%bitstring {| n : 7 : signed |}] with + | {| i : 7 : signed |} -> i + | {| _ |} -> assert false) + ; (fun n -> + match%bitstring [%bitstring {| n : 8 : signed |}] with + | {| i : 8 : signed |} -> i + | {| _ |} -> assert false) + ]) in assert_equal ok true +;; (* * Signed int limits @@ -251,115 +271,179 @@ let signed_byte_create_and_match_test _ = let signed_int_limits_test _ = Random.self_init (); - let res = List.fold_left + let res = + List.fold_left (fun (ok, i) (b, m) -> let above_maxp = 1 lsl i in let maxp = pred above_maxp in - let minp = - (above_maxp lsr 1) in + let minp = -(above_maxp lsr 1) in let below_minp = pred minp in let gut = - try ignore (b maxp); true - with _ -> false in + try + ignore (b maxp); + true + with + | _ -> false + in let gut2 = - try ignore (b above_maxp); false - with _ -> true in + try + ignore (b above_maxp); + false + with + | _ -> true + in let gut3 = - try ignore (b minp); true - with _ -> false in + try + ignore (b minp); + true + with + | _ -> false + in let gut4 = - try ignore (b below_minp); false - with _ -> true in + try + ignore (b below_minp); + false + with + | _ -> true + in let gut5 = let plage = Int32.shift_left 1l i in let test () = let signed_number = - Int32.to_int (Int32.add (Random.int32 plage) (Int32.of_int minp)) in + Int32.to_int (Int32.add (Random.int32 plage) (Int32.of_int minp)) + in let bits = b signed_number in let number' = m bits in - if signed_number = number' then true - else - begin - Printf.printf "bits:%d n=%x read=%x (%x %x)\n" i signed_number number' minp maxp; - false - end in + if signed_number = number' + then true + else ( + Printf.printf + "bits:%d n=%x read=%x (%x %x)\n" + i + signed_number + number' + minp + maxp; + false) + in let res = ref true in for i = 1 to 10_000 do res := !res && test () done; !res in - (gut && gut2 && gut3 && gut4 && gut5 && ok, succ i) - ) + gut && gut2 && gut3 && gut4 && gut5 && ok, succ i) (true, 9) - [ - (fun n -> [%bitstring {| n : 9 : signed |}]), - (fun b -> match%bitstring b with {| n: 9 : signed |} -> n); - (fun n -> [%bitstring {| n : 10 : signed |}]), - (fun b -> match%bitstring b with {| n : 10 : signed |} -> n); - (fun n -> [%bitstring {| n : 11 : signed |}]), - (fun b -> match%bitstring b with {| n : 11 : signed |} -> n); - (fun n -> [%bitstring {| n : 12 : signed |}]), - (fun b -> match%bitstring b with {| n : 12 : signed |} -> n); - (fun n -> [%bitstring {| n : 13 : signed |}]), - (fun b -> match%bitstring b with {| n : 13 : signed |} -> n); - (fun n -> [%bitstring {| n : 14 : signed |}]), - (fun b -> match%bitstring b with {| n : 14 : signed |} -> n); - (fun n -> [%bitstring {| n : 15 : signed |}]), - (fun b -> match%bitstring b with {| n : 15 : signed |} -> n); - (fun n -> [%bitstring {| n : 16 : signed |}]), - (fun b -> match%bitstring b with {| n : 16 : signed |} -> n); - (fun n -> [%bitstring {| n : 17 : signed |}]), - (fun b -> match%bitstring b with {| n : 17 : signed |} -> n); - (fun n -> [%bitstring {| n : 18 : signed |}]), - (fun b -> match%bitstring b with {| n : 18 : signed |} -> n); - (fun n -> [%bitstring {| n : 19 : signed |}]), - (fun b -> match%bitstring b with {| n : 19 : signed |} -> n); - (fun n -> [%bitstring {| n : 20 : signed |}]), - (fun b -> match%bitstring b with {| n : 20 : signed |} -> n); - (fun n -> [%bitstring {| n : 21 : signed |}]), - (fun b -> match%bitstring b with {| n : 21 : signed |} -> n); - (fun n -> [%bitstring {| n : 22 : signed |}]), - (fun b -> match%bitstring b with {| n : 22 : signed |} -> n); - (fun n -> [%bitstring {| n : 23 : signed |}]), - (fun b -> match%bitstring b with {| n : 23 : signed |} -> n); - (fun n -> [%bitstring {| n : 24 : signed |}]), - (fun b -> match%bitstring b with {| n : 24 : signed |} -> n); - (fun n -> [%bitstring {| n : 25 : signed |}]), - (fun b -> match%bitstring b with {| n : 25 : signed |} -> n); - (fun n -> [%bitstring {| n : 26 : signed |}]), - (fun b -> match%bitstring b with {| n : 26 : signed |} -> n); - (fun n -> [%bitstring {| n : 27 : signed |}]), - (fun b -> match%bitstring b with {| n : 27 : signed |} -> n); - (fun n -> [%bitstring {| n : 28 : signed |}]), - (fun b -> match%bitstring b with {| n : 28 : signed |} -> n); - (fun n -> [%bitstring {| n : 29 : signed |}]), - (fun b -> match%bitstring b with {| n : 29 : signed |} -> n); - (fun n -> [%bitstring {| n : 30 : signed |}]), - (fun b -> match%bitstring b with {| n : 30 : signed |} -> n); + [ ( (fun n -> [%bitstring {| n : 9 : signed |}]) + , fun b -> + match%bitstring b with + | {| n: 9 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 10 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 10 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 11 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 11 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 12 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 12 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 13 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 13 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 14 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 14 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 15 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 15 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 16 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 16 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 17 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 17 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 18 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 18 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 19 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 19 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 20 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 20 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 21 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 21 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 22 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 22 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 23 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 23 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 24 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 24 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 25 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 25 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 26 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 26 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 27 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 27 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 28 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 28 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 29 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 29 : signed |} -> n ) + ; ( (fun n -> [%bitstring {| n : 30 : signed |}]) + , fun b -> + match%bitstring b with + | {| n : 30 : signed |} -> n ) ] in assert_equal (fst res) true; - begin try - if Sys.word_size = 32 then - begin - ignore ([%bitstring {| max_int : 31 : signed |}]); - ignore ([%bitstring {| min_int : 31 : signed |}]); - end - else - begin - ignore ([%bitstring {| pred (1 lsl 31) : 31 : signed |}]); - ignore ([%bitstring {| (-1 lsl 30) : 31 : signed |}]); - end; - with - _ -> assert_failure "Second test failed" - end; - if Sys.word_size = 64 then + (try + if Sys.word_size = 32 + then ( + ignore [%bitstring {| max_int : 31 : signed |}]; + ignore [%bitstring {| min_int : 31 : signed |}]) + else ( + ignore [%bitstring {| pred (1 lsl 31) : 31 : signed |}]; + ignore [%bitstring {| (-1 lsl 30) : 31 : signed |}]) + with + | _ -> assert_failure "Second test failed"); + if Sys.word_size = 64 + then ( try - ignore ([%bitstring {| 1 lsl 31 : 31 : signed |}]); - ignore ([%bitstring {| pred (-1 lsl 30) : 31 : signed |}]); + ignore [%bitstring {| 1 lsl 31 : 31 : signed |}]; + ignore [%bitstring {| pred (-1 lsl 30) : 31 : signed |}]; assert_failure "Third test failed" - with _ -> - () + with + | _ -> ()) +;; (* * Test functions which construct and extract fixed-length ints of various @@ -369,7 +453,8 @@ let signed_int_limits_test _ = let fixed_extraction_test _ = for i = 0 to 129 do let zeroes = Bitstring.zeroes_bitstring i in - let%bitstring bits = {| + let%bitstring bits = + {| zeroes : i : bitstring; true : 1; 2 : 2 : littleendian; @@ -431,62 +516,91 @@ let fixed_extraction_test _ = k0 : 64 : littleendian; k1 : 64 : bigendian; k2 : 64 : nativeendian - |} -> - if a <> true - || b0 <> 2 - || b1 <> 2 - || b2 <> 2 - || c0 <> 3 - || c1 <> 3 - || c2 <> 3 - || d0 <> 0x5a - || d1 <> 0x5a - || d2 <> 0x5a - || e0 <> 0xa5a5 - || e1 <> 0xa5a5 - || e2 <> 0xa5a5 - || f0 <> 0xeeddcc - || f1 <> 0xeeddcc - || f2 <> 0xeeddcc - || g0 <> 0x48888888 - || g1 <> 0x48888888 - || g2 <> 0x48888888 - || h0 <> 0xaabbccdd_l - || h1 <> 0xaabbccdd_l - || h2 <> 0xaabbccdd_l - || j0 <> 0xaabbccddeeff_L - || j1 <> 0xaabbccddeeff_L - || j2 <> 0xaabbccddeeff_L - || k0 <> 0x0011aabbccddeeff_L - || k1 <> 0x0011aabbccddeeff_L - || k2 <> 0x0011aabbccddeeff_L + |} + -> + if + a <> true + || b0 <> 2 + || b1 <> 2 + || b2 <> 2 + || c0 <> 3 + || c1 <> 3 + || c2 <> 3 + || d0 <> 0x5a + || d1 <> 0x5a + || d2 <> 0x5a + || e0 <> 0xa5a5 + || e1 <> 0xa5a5 + || e2 <> 0xa5a5 + || f0 <> 0xeeddcc + || f1 <> 0xeeddcc + || f2 <> 0xeeddcc + || g0 <> 0x48888888 + || g1 <> 0x48888888 + || g2 <> 0x48888888 + || h0 <> 0xaabbccdd_l + || h1 <> 0xaabbccdd_l + || h2 <> 0xaabbccdd_l + || j0 <> 0xaabbccddeeff_L + || j1 <> 0xaabbccddeeff_L + || j2 <> 0xaabbccddeeff_L + || k0 <> 0x0011aabbccddeeff_L + || k1 <> 0x0011aabbccddeeff_L + || k2 <> 0x0011aabbccddeeff_L then ( - eprintf "15_extract_int: match failed %b %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %ld %ld %ld %Ld %Ld %Ld %Ld %Ld %Ld\n" - a b0 b1 b2 c0 c1 c2 d0 d1 d2 e0 e1 e2 f0 f1 f2 g0 g1 g2 h0 h1 h2 j0 j1 j2 k0 k1 k2; - exit 1 - ) - | {| _ |} -> - failwith "15_extract_int" + eprintf + "15_extract_int: match failed %b %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d \ + %d %d %d %ld %ld %ld %Ld %Ld %Ld %Ld %Ld %Ld\n" + a + b0 + b1 + b2 + c0 + c1 + c2 + d0 + d1 + d2 + e0 + e1 + e2 + f0 + f1 + f2 + g0 + g1 + g2 + h0 + h1 + h2 + j0 + j1 + j2 + k0 + k1 + k2; + exit 1) + | {| _ |} -> failwith "15_extract_int" done +;; (* * Test fix for a regression when extracting 32 and 64 bit aligned integers * (discovered / fixed / tested by Hans Ole Rafaelsen). *) -let bitstring_of_int32 i = - [%bitstring {| i : 32 |}] - -let bitstring_of_int64 i = - [%bitstring {| i : 64 |}] +let bitstring_of_int32 i = [%bitstring {| i : 32 |}] +let bitstring_of_int64 i = [%bitstring {| i : 64 |}] let int32_of_bitstring bits = match%bitstring bits with | {| i : 32 |} -> i +;; let int64_of_bitstring bits = match%bitstring bits with | {| i : 64 |} -> i +;; let extract_regression_test _ = let b1 = bitstring_of_int32 1_l in @@ -498,7 +612,6 @@ let extract_regression_test _ = assert (i1 = 1_l); assert (i2 = 2_l); assert (i3 = 3_l); - let b1 = bitstring_of_int64 1_L in let b2 = bitstring_of_int64 2_L in let b3 = bitstring_of_int64 3_L in @@ -508,35 +621,45 @@ let extract_regression_test _ = assert (i1 = 1_L); assert (i2 = 2_L); assert (i3 = 3_L) +;; (* * Construct and match against random variable sized strings. *) let nr_passes = 10000 -let max_size = 8 (* max field size in bits *) +let max_size = 8 (* max field size in bits *) (* let () = Bitstring.debug := true *) (* Return a full 64 bits of randomness. *) let rand64 () = - let r0 = Int64.shift_left (Int64.of_int (Random.bits ())) 34 in (* 30 bits *) - let r1 = Int64.shift_left (Int64.of_int (Random.bits ())) 4 in (* 30 bits *) - let r2 = Int64.of_int (Random.int 16) in (* 4 bits *) + let r0 = Int64.shift_left (Int64.of_int (Random.bits ())) 34 in + (* 30 bits *) + let r1 = Int64.shift_left (Int64.of_int (Random.bits ())) 4 in + (* 30 bits *) + let r2 = Int64.of_int (Random.int 16) in + (* 4 bits *) Int64.logor (Int64.logor r0 r1) r2 +;; (* Return unsigned mask of length bits, bits <= 64. *) let mask64 bits = - if bits < 63 then Int64.pred (Int64.shift_left 1L bits) - else if bits = 63 then Int64.max_int - else if bits = 64 then -1L + if bits < 63 + then Int64.pred (Int64.shift_left 1L bits) + else if bits = 63 + then Int64.max_int + else if bits = 64 + then -1L else invalid_arg "mask64" +;; (* Return a random number between 0 and 2^bits-1 where bits <= 64. *) let rand bits = let r = rand64 () in let m = mask64 bits in Int64.logand r m +;; (* Dump the state in case there is an error. *) let dump n0 n0sz n1 n1sz n2 n2sz n3 n3sz bits r0 r1 r2 r3 = @@ -548,61 +671,58 @@ let dump n0 n0sz n1 n1sz n2 n2sz n3 n3sz bits r0 r1 r2 r3 = eprintf "bits (length = %d):\n" (Bitstring.bitstring_length bits); Bitstring.hexdump_bitstring stderr bits; eprintf "%!" +;; let construct_and_match_random_test _ = Random.self_init (); - - for pass = 0 to nr_passes-1 do - let n0sz = 1 + Random.int (max_size-1) in - let n0 = rand n0sz in - let n1sz = 1 + Random.int (max_size-1) in - let n1 = rand n1sz in - let n2sz = 1 + Random.int (max_size-1) in - let n2 = rand n2sz in - let n3sz = 1 + Random.int (max_size-1) in - let n3 = rand n3sz in - + for pass = 0 to nr_passes - 1 do + let n0sz = 1 + Random.int (max_size - 1) in + let n0 = rand n0sz in + let n1sz = 1 + Random.int (max_size - 1) in + let n1 = rand n1sz in + let n2sz = 1 + Random.int (max_size - 1) in + let n2 = rand n2sz in + let n3sz = 1 + Random.int (max_size - 1) in + let n3 = rand n3sz in (* Construct the bitstring. *) let bits = try - [%bitstring {| + [%bitstring + {| n0 : n0sz; n1 : n1sz; n2 : n2sz; n3 : n3sz |}] with - Bitstring.Construct_failure (msg, _, _, _) -> + | Bitstring.Construct_failure (msg, _, _, _) -> eprintf "FAILED: Construct_failure %s\n%!" msg; - dump n0 n0sz n1 n1sz n2 n2sz n3 n3sz - (Bitstring.empty_bitstring) 0L 0L 0L 0L; + dump n0 n0sz n1 n1sz n2 n2sz n3 n3sz Bitstring.empty_bitstring 0L 0L 0L 0L; exit 2 in - let r0, r1, r2, r3 = match%bitstring bits with | {| r0 : n0sz; r1 : n1sz; r2 : n2sz; r3 : n3sz; rest : -1 : bitstring |} -> let rest_len = Bitstring.bitstring_length rest in - if rest_len <> 0 then ( - eprintf "FAILED: rest is not zero length (length = %d)\n%!" - rest_len; + if rest_len <> 0 + then ( + eprintf "FAILED: rest is not zero length (length = %d)\n%!" rest_len; dump n0 n0sz n1 n1sz n2 n2sz n3 n3sz bits 0L 0L 0L 0L; - exit 2 - ); + exit 2); r0, r1, r2, r3 | {| _ |} -> eprintf "FAILED: match operator did not match\n%!"; dump n0 n0sz n1 n1sz n2 n2sz n3 n3sz bits 0L 0L 0L 0L; - exit 2 in - + exit 2 + in (*dump n0 n0sz n1 n1sz n2 n2sz n3 n3sz bits r0 r1 r2 r3;*) - - if n0 <> r0 || n1 <> r1 || n2 <> r2 || n3 <> r3 then ( + if n0 <> r0 || n1 <> r1 || n2 <> r2 || n3 <> r3 + then ( eprintf "FAILED: numbers returned from match are different\n%!"; dump n0 n0sz n1 n1sz n2 n2sz n3 n3sz bits r0 r1 r2 r3; - exit 2 - ) + exit 2) done +;; (* * Test the Bitstring.Buffer module and string_of_bitstring in nasty non-aligned @@ -611,63 +731,60 @@ let construct_and_match_random_test _ = let nasty_non_aligned_corner_case_test _ = Random.self_init (); - let str1 = Bytes.of_string "012345678" in - for offset = 0 to 65 do for len = 1 to 65 do let expected = - let strlen = (len+7) lsr 3 in + let strlen = (len + 7) lsr 3 in let expected = Bytes.create strlen in - for i = 0 to strlen-1 do + for i = 0 to strlen - 1 do Bytes.set expected i (Char.chr (Random.int 256)) done; - let last = Char.code (Bytes.get expected (strlen-1)) in + let last = Char.code (Bytes.get expected (strlen - 1)) in let last = last land (0xff lsl (8 - (len land 7))) in - Bytes.set expected (strlen-1) (Char.chr last); - expected in - + Bytes.set expected (strlen - 1) (Char.chr last); + expected + in (* Create a random bitstring: * +-------------+-------------------------------------------+ * | (random) | bits that we check (expected) | * +-------------+-------------------------------------------+ * 0 offset offset+len * <---------------- len bits ---------------> - *) + *) let bits = let bits = Bitstring.Buffer.create () in Bitstring.Buffer.add_bits bits str1 offset; Bitstring.Buffer.add_bits bits expected len; - Bitstring.Buffer.contents bits in - + Bitstring.Buffer.contents bits + in (* Create a sub bitstring corresponding to what we want to check. *) let subbits = let bits, bitoffset, bitlen = bits in - (bits, bitoffset+offset, bitlen-offset) in - + bits, bitoffset + offset, bitlen - offset + in assert_equal (Bitstring.bitstring_length subbits) len; - (* Now try to read out the substring using string_of_bitstring. *) let actual = Bitstring.string_of_bitstring subbits in - if Bytes.of_string actual <> expected then ( - eprintf "MISMATCH between actual and expected, offset=%d, len=%d\n" - offset len; + if Bytes.of_string actual <> expected + then ( + eprintf "MISMATCH between actual and expected, offset=%d, len=%d\n" offset len; eprintf "EXPECTED string:\n"; - for i = 0 to Bytes.length expected-1 do + for i = 0 to Bytes.length expected - 1 do eprintf " %02x" (Char.code (Bytes.get expected i)) done; eprintf "\nACTUAL string:\n"; - for i = 0 to String.length actual-1 do + for i = 0 to String.length actual - 1 do eprintf " %02x" (Char.code actual.[i]) done; eprintf "\nBITS:\n"; Bitstring.hexdump_bitstring stderr bits; eprintf "SUBBITS:\n"; Bitstring.hexdump_bitstring stderr subbits; - exit 1 - ); + exit 1) done done +;; (* * Test concat and the bit get functions. @@ -678,24 +795,26 @@ let concat_bit_get_test _ = for j = 0 to 33 do for k = 0 to 33 do let bits = - Bitstring.concat [ - Bitstring.ones_bitstring i; - Bitstring.zeroes_bitstring j; - Bitstring.ones_bitstring k - ] in - assert (Bitstring.bitstring_length bits = i+j+k); - for n = 0 to i-1 do + Bitstring.concat + [ Bitstring.ones_bitstring i + ; Bitstring.zeroes_bitstring j + ; Bitstring.ones_bitstring k + ] + in + assert (Bitstring.bitstring_length bits = i + j + k); + for n = 0 to i - 1 do assert (Bitstring.is_set bits n) done; - for n = i to i+j-1 do + for n = i to i + j - 1 do assert (Bitstring.is_clear bits n) done; - for n = i+j to i+j+k-1 do + for n = i + j to i + j + k - 1 do assert (Bitstring.is_set bits n) done done done done +;; (* * Compare bitstrings. @@ -705,6 +824,7 @@ let sgn = function | 0 -> 0 | i when i > 0 -> 1 | _ -> -1 +;; let compare_test _ = for i = 0 to 33 do @@ -712,10 +832,10 @@ let compare_test _ = let bits1 = Bitstring.ones_bitstring i and bits2 = Bitstring.ones_bitstring j in let r = Bitstring.compare bits1 bits2 in - if sgn r <> sgn (compare i j) then ( + if sgn r <> sgn (compare i j) + then ( eprintf "ones compare failed %d %d %d\n" i j r; - exit 1 - ) + exit 1) done done; for i = 0 to 33 do @@ -723,10 +843,10 @@ let compare_test _ = let bits1 = Bitstring.zeroes_bitstring i and bits2 = Bitstring.zeroes_bitstring j in let r = Bitstring.compare bits1 bits2 in - if sgn r <> sgn (compare i j) then ( + if sgn r <> sgn (compare i j) + then ( eprintf "zeroes compare failed %d %d %d\n" i j r; - exit 1 - ) + exit 1) done done; for i = 0 to 33 do @@ -734,27 +854,28 @@ let compare_test _ = let bits1 = Bitstring.make_bitstring i '\x55' and bits2 = Bitstring.make_bitstring j '\x55' in let r = Bitstring.compare bits1 bits2 in - if sgn r <> sgn (compare i j) then ( + if sgn r <> sgn (compare i j) + then ( eprintf "x55 compare failed %d %d %d\n" i j r; - exit 1 - ) + exit 1) done done; for i = 0 to 33 do for j = 0 to 33 do let bits1 = Bitstring.make_bitstring i '\x55' in let bits2 = Bitstring.make_bitstring i '\x55' in - let bits2 = Bitstring.concat [Bitstring.zeroes_bitstring j; bits2] in - assert (Bitstring.bitstring_length bits2 = j+i); + let bits2 = Bitstring.concat [ Bitstring.zeroes_bitstring j; bits2 ] in + assert (Bitstring.bitstring_length bits2 = j + i); let bits2 = Bitstring.dropbits j bits2 in assert (Bitstring.bitstring_length bits2 = i); let r = Bitstring.compare bits1 bits2 in - if r <> 0 then ( + if r <> 0 + then ( eprintf "x55 non-aligned compare failed %d %d %d\n" i j r; - exit 1 - ) + exit 1) done done +;; (* * Test subbitstring call. @@ -763,16 +884,17 @@ let compare_test _ = let subbitstring_test _ = let bits = Bitstring.make_bitstring 65 '\x5a' in for off = 0 to 65 do - for len = 65-off to 0 do + for len = 65 - off to 0 do let sub = Bitstring.subbitstring bits off len in - for i = 0 to len-1 do - if Bitstring.get bits (off+i) <> Bitstring.get sub i then ( + for i = 0 to len - 1 do + if Bitstring.get bits (off + i) <> Bitstring.get sub i + then ( eprintf "33_substring: failed %d %d %d\n" off len i; - exit 1 - ) + exit 1) done done done +;; (* * Test takebits call. @@ -784,6 +906,7 @@ let takebits_test _ = let sub = Bitstring.takebits len bits in assert (Bitstring.bitstring_length sub = len) done +;; (* * Test the various functions to load bitstrings from files. @@ -792,52 +915,50 @@ let takebits_test _ = let file_load_test _ = let bits1 = let b1 = Bitstring.make_bitstring 800 '\x5a' in - let b2 = Bitstring.make_bitstring 400 '\x88' in ( - [%bitstring {| + let b2 = Bitstring.make_bitstring 400 '\x88' in + [%bitstring + {| b1 : 800 : bitstring; b2 : 400 : bitstring |}] - ) in - let bits2 = ( + in + let bits2 = let b = Bitstring.make_bitstring 800 '\xaa' in - [%bitstring {| + [%bitstring + {| b : 800 : bitstring |}] - ) in - let bits = Bitstring.concat [bits1; bits2] in + in + let bits = Bitstring.concat [ bits1; bits2 ] in let filename, chan = - Filename.open_temp_file ~mode:[Open_binary] "bitstring_test" ".tmp" in + Filename.open_temp_file ~mode:[ Open_binary ] "bitstring_test" ".tmp" + in Bitstring.bitstring_to_chan bits chan; close_out chan; - let bits' = Bitstring.bitstring_of_file filename in assert (Bitstring.equals bits bits'); - let chan = open_in filename in let bits' = Bitstring.bitstring_of_chan chan in close_in chan; assert (Bitstring.equals bits bits'); - let chan = open_in filename in let bits' = Bitstring.bitstring_of_chan_max chan 150 in assert (Bitstring.equals bits1 bits'); let bits' = Bitstring.bitstring_of_chan_max chan 100 in assert (Bitstring.equals bits2 bits'); close_in chan; - - let fd = Unix.openfile filename [Unix.O_RDONLY] 0 in + let fd = Unix.openfile filename [ Unix.O_RDONLY ] 0 in let bits' = Bitstring.bitstring_of_file_descr fd in Unix.close fd; assert (Bitstring.equals bits bits'); - - let fd = Unix.openfile filename [Unix.O_RDONLY] 0 in + let fd = Unix.openfile filename [ Unix.O_RDONLY ] 0 in let bits' = Bitstring.bitstring_of_file_descr_max fd 150 in assert (Bitstring.equals bits1 bits'); let bits' = Bitstring.bitstring_of_file_descr_max fd 100 in assert (Bitstring.equals bits2 bits'); Unix.close fd; - Unix.unlink filename +;; (* * Test if bitstrings are all zeroes or all ones. @@ -846,26 +967,27 @@ let file_load_test _ = let zeroes_ones_test _ = for i = 0 to 33 do let bits = Bitstring.zeroes_bitstring i in - if not (Bitstring.is_zeroes_bitstring bits) then ( + if not (Bitstring.is_zeroes_bitstring bits) + then ( eprintf "is_zeros_bitstring failed %d\n" i; - exit 1 - ); - if i > 0 && Bitstring.is_ones_bitstring bits then ( + exit 1); + if i > 0 && Bitstring.is_ones_bitstring bits + then ( eprintf "false match is_ones_bitstring %d\n" i; - exit 1 - ) + exit 1) done; for i = 0 to 33 do let bits = Bitstring.ones_bitstring i in - if not (Bitstring.is_ones_bitstring bits) then ( + if not (Bitstring.is_ones_bitstring bits) + then ( eprintf "is_ones_bitstring failed %d\n" i; - exit 1 - ); - if i > 0 && Bitstring.is_zeroes_bitstring bits then ( + exit 1); + if i > 0 && Bitstring.is_zeroes_bitstring bits + then ( eprintf "false match is_zeroes_bitstring %d\n" i; - exit 1 - ) + exit 1) done +;; (* * Endianness expressions @@ -874,64 +996,70 @@ let zeroes_ones_test _ = let endianness_test _ = let rec loop = function | (e, expected) :: rest -> - let%bitstring bits = {| + let%bitstring bits = + {| expected : 32 : endian (e); expected : 32 : endian (e); expected : 32 : endian (e) - |} in + |} + in (match%bitstring bits with | {| actual : 32 : endian (e); actual : 32 : endian (e); - actual : 32 : endian (e) |} -> - if actual <> expected then - failwith (sprintf "actual %ld <> expected %ld" actual expected) + actual : 32 : endian (e) |} + -> + if actual <> expected + then failwith (sprintf "actual %ld <> expected %ld" actual expected) | {| _ |} as bits -> - Bitstring.hexdump_bitstring stderr bits; exit 1 - ); + Bitstring.hexdump_bitstring stderr bits; + exit 1); loop rest | [] -> () in - loop [ - Bitstring.BigEndian, 0xa1b2c3d4_l; - Bitstring.BigEndian, 0xa1d4c3b2_l; - Bitstring.LittleEndian, 0xa1b2c3d4_l; - Bitstring.LittleEndian, 0xa1d4c3b2_l; - Bitstring.NativeEndian, 0xa1b2c3d4_l; - Bitstring.NativeEndian, 0xa1d4c3b2_l; - ] + loop + [ Bitstring.BigEndian, 0xa1b2c3d4_l + ; Bitstring.BigEndian, 0xa1d4c3b2_l + ; Bitstring.LittleEndian, 0xa1b2c3d4_l + ; Bitstring.LittleEndian, 0xa1d4c3b2_l + ; Bitstring.NativeEndian, 0xa1b2c3d4_l + ; Bitstring.NativeEndian, 0xa1d4c3b2_l + ] +;; (* * Simple offset test *) let simple_offset_test _ = - let make_bits i n j m k = ( - let pad1 = Bitstring.ones_bitstring (n-8) in - let pad2 = Bitstring.ones_bitstring (m-n-8) in - [%bitstring {| + let make_bits i n j m k = + let pad1 = Bitstring.ones_bitstring (n - 8) in + let pad2 = Bitstring.ones_bitstring (m - n - 8) in + [%bitstring + {| i : 8; pad1 : n-8 : bitstring; j : 8; (* this should be at offset(n) *) pad2 : m-n-8 : bitstring; k : 8 (* this should be at offset(m) *) |}] - ) in let test_bits bits i n j m k = match%bitstring bits with | {| i' : 8; j' : 8 : offset(n); - k' : 8 : offset(m) |} when i = i' && j = j' && k = k' -> () (* ok *) + k' : 8 : offset(m) |} + when i = i' && j = j' && k = k' -> () (* ok *) | {| _ |} -> - failwith (sprintf "60_simple_offset: test_bits: failed %d %d %d %d %d" - i n j m k) + failwith (sprintf "60_simple_offset: test_bits: failed %d %d %d %d %d" i n j m k) in for n = 8 to 128 do - for m = n+8 to 256 do - List.iter (fun (i,j,k) -> test_bits (make_bits i n j m k) i n j m k) - [0x55, 0xaa, 0x33; 0x33, 0xaa, 0x55; 0x12, 0x34, 0x56] - done; + for m = n + 8 to 256 do + List.iter + (fun (i, j, k) -> test_bits (make_bits i n j m k) i n j m k) + [ 0x55, 0xaa, 0x33; 0x33, 0xaa, 0x55; 0x12, 0x34, 0x56 ] + done done +;; (* * Offset string. The rotation functions used for strings are @@ -939,17 +1067,17 @@ let simple_offset_test _ = *) let offset_string_test _ = - let make_bits si n sj m sk = ( - let pad1 = Bitstring.ones_bitstring (n-64) in - let pad2 = Bitstring.ones_bitstring (m-n-8) in - [%bitstring {| + let make_bits si n sj m sk = + let pad1 = Bitstring.ones_bitstring (n - 64) in + let pad2 = Bitstring.ones_bitstring (m - n - 8) in + [%bitstring + {| si : 64 : string; pad1 : n-64 : bitstring; sj : 8 : string; (* this should be at offset(n) *) pad2 : m-n-8 : bitstring; sk : 64 : string (* this should be at offset(m) *) |}] - ) in let test_bits bits si n sj m sk = match%bitstring bits with @@ -958,18 +1086,19 @@ let offset_string_test _ = sk' : 64 : string, offset(m) |} when si = si' && sj = sj' && sk = sk' -> () (* ok *) | {| _ |} -> - failwith (sprintf "61_offset_string: test_bits: failed %S %d %S %d %S" - si n sj m sk) + failwith (sprintf "61_offset_string: test_bits: failed %S %d %S %d %S" si n sj m sk) in for n = 64 to 128 do - for m = n+8 to 256 do - List.iter (fun (si,sj,sk) -> - test_bits (make_bits si n sj m sk) si n sj m sk) - ["ABCDEFGH", "x", "HGFEDCBA"; - "01234567", "0", "76543210"; - "abcdefgh", "\x55", "poiuytre"] - done; + for m = n + 8 to 256 do + List.iter + (fun (si, sj, sk) -> test_bits (make_bits si n sj m sk) si n sj m sk) + [ "ABCDEFGH", "x", "HGFEDCBA" + ; "01234567", "0", "76543210" + ; "abcdefgh", "\x55", "poiuytre" + ] + done done +;; (* * Test computed offsets when original_off <> 0. @@ -978,9 +1107,10 @@ let offset_string_test _ = let computed_offset_test _ = let make_bits p i n j m k = let pad0 = Bitstring.ones_bitstring p in - let pad1 = Bitstring.ones_bitstring (n-8) in - let pad2 = Bitstring.ones_bitstring (m-n-8) in - [%bitstring {| + let pad1 = Bitstring.ones_bitstring (n - 8) in + let pad2 = Bitstring.ones_bitstring (m - n - 8) in + [%bitstring + {| pad0 : p : bitstring; (* will be skipped below *) i : 8; pad1 : n-8 : bitstring; @@ -993,17 +1123,18 @@ let computed_offset_test _ = (* * Skip the 'p' padding bits so the match starts at a non-zero offset. *) - let bits = Bitstring.dropbits p bits - in + let bits = Bitstring.dropbits p bits in match%bitstring bits with | {| i' : 8; j' : 8 : offset(n); k' : 8 : offset(m) - |} when i = i' && j = j' && k = k' -> () (* ok *) + |} + when i = i' && j = j' && k = k' -> () (* ok *) | {| i' : 8; j' : 8 : offset(n); k' : 8 : offset(m) - |} -> + |} + -> Printf.printf "\n%d %d %d\n" p n m; Bitstring.hexdump_bitstring stdout bits; Printf.printf "%x %x\n" i i'; @@ -1012,28 +1143,30 @@ let computed_offset_test _ = assert_equal j j'; Printf.printf "%x %x\n" k k'; assert_equal k k' - | {| _ |} -> - assert_failure "Bitstring parsing failure" + | {| _ |} -> assert_failure "Bitstring parsing failure" in for p = 1 to 4 do for n = 8 to 128 do - for m = n+8 to 256 do - List.iter (fun (i,j,k) -> test_bits (make_bits p i n j m k) p i n j m k) - [0x55, 0xaa, 0x33; 0x33, 0xaa, 0x55; 0x12, 0x34, 0x56] - done; - done; + for m = n + 8 to 256 do + List.iter + (fun (i, j, k) -> test_bits (make_bits p i n j m k) p i n j m k) + [ 0x55, 0xaa, 0x33; 0x33, 0xaa, 0x55; 0x12, 0x34, 0x56 ] + done + done done +;; (* * Test save_offset_to. *) let save_offset_to_test _ = - let make_bits p i n j m k = ( + let make_bits p i n j m k = let pad0 = Bitstring.ones_bitstring p in - let pad1 = Bitstring.ones_bitstring (n-8) in - let pad2 = Bitstring.ones_bitstring (m-n-8) in - [%bitstring {| + let pad1 = Bitstring.ones_bitstring (n - 8) in + let pad2 = Bitstring.ones_bitstring (m - n - 8) in + [%bitstring + {| pad0 : p : bitstring; (* will be skipped below *) i : 8; pad1 : n-8 : bitstring; @@ -1041,99 +1174,101 @@ let save_offset_to_test _ = pad2 : m-n-8 : bitstring; k : 8 (* this should be at offset(m) *) |}] - ) in let test_bits bits p i n j m k = (* Skip the 'p' padding bits so the match starts at a non-zero offset. *) let bits = Bitstring.dropbits p bits in - match%bitstring bits with | {| i' : 8; _ : n-8 : bitstring; j' : 8 : save_offset_to (j_offset); _ : m-n-8 : bitstring; k' : 8 : save_offset_to (k_offset) |} - when i = i' && j = j' && k = k' && j_offset = n && k_offset = m -> - () (* ok *) + when i = i' && j = j' && k = k' && j_offset = n && k_offset = m -> () (* ok *) | {| _ |} -> - failwith (sprintf - "65_save_offset_to: test_bits: failed %d %d %d %d %d %d" - p i n j m k) + failwith + (sprintf "65_save_offset_to: test_bits: failed %d %d %d %d %d %d" p i n j m k) in for p = 0 to 4 do for n = 8 to 64 do - for m = n+8 to 128 do - List.iter (fun (i,j,k) -> test_bits (make_bits p i n j m k) p i n j m k) - [0x55, 0xaa, 0x33; 0x33, 0xaa, 0x55; 0x12, 0x34, 0x56] - done; - done; + for m = n + 8 to 128 do + List.iter + (fun (i, j, k) -> test_bits (make_bits p i n j m k) p i n j m k) + [ 0x55, 0xaa, 0x33; 0x33, 0xaa, 0x55; 0x12, 0x34, 0x56 ] + done + done done +;; (* * Test check() and bind(). *) let check_bind_test _ = - let%bitstring bits = {| 101 : 16; 202 : 16 |} - in + let%bitstring bits = {| 101 : 16; 202 : 16 |} in match%bitstring bits with | {| i : 16 : check (i = 101), bind (i*4); - j : 16 : check (j = 202) |} -> - if i <> 404 || j <> 202 then - failwith (sprintf "70_check_and_bind: failed: %d %d" i j) - | {| _ |} -> - failwith "70_check_and_bind: match failed" + j : 16 : check (j = 202) |} + -> + if i <> 404 || j <> 202 then failwith (sprintf "70_check_and_bind: failed: %d %d" i j) + | {| _ |} -> failwith "70_check_and_bind: match failed" +;; (* * Test hexdump. *) let () = - let diff = "diff" - in + let diff = "diff" in let files = Sys.readdir "../../../tests/data" in let files = Array.to_list files in - let files = List.filter ( - fun filename -> - String.length filename > 3 && - filename.[0] = 'r' && filename.[1] = 'n' && filename.[2] = 'd' - ) files in - let files = List.map ( - fun filename -> - let n = String.sub filename 3 (String.length filename - 3) in - let n = int_of_string n in - let bits = Bitstring.bitstring_of_file ("../../../tests/data/" ^ filename) in - (* - * 'bitstring_of_file' loads whole bytes. Truncate it to - * the real bit-length. - *) - let bits = Bitstring.takebits n bits in - filename, n, bits - ) files in + let files = + List.filter + (fun filename -> + String.length filename > 3 + && filename.[0] = 'r' + && filename.[1] = 'n' + && filename.[2] = 'd') + files + in + let files = + List.map + (fun filename -> + let n = String.sub filename 3 (String.length filename - 3) in + let n = int_of_string n in + let bits = Bitstring.bitstring_of_file ("../../../tests/data/" ^ filename) in + (* + * 'bitstring_of_file' loads whole bytes. Truncate it to + * the real bit-length. + *) + let bits = Bitstring.takebits n bits in + filename, n, bits) + files + in (* * Hexdump the bits, then compare using external 'diff' program. *) - List.iter ( - fun (filename, n, bits) -> - let output_filename = sprintf "../../../tests/data/hex%d.actual" n in - let chan = open_out output_filename in - Bitstring.hexdump_bitstring chan bits; - close_out chan - ) files; - - List.iter ( - fun (filename, n, bits) -> - let actual_filename = sprintf "../../../tests/data/hex%d.actual" n in - let expected_filename = sprintf "../../../tests/data/hex%d.expected" n in - let cmd = - sprintf "%s -u %s %s" - (Filename.quote diff) - (Filename.quote expected_filename) - (Filename.quote actual_filename) in - if Sys.command cmd <> 0 then ( - exit 1 - ) - ) files + List.iter + (fun (filename, n, bits) -> + let output_filename = sprintf "../../../tests/data/hex%d.actual" n in + let chan = open_out output_filename in + Bitstring.hexdump_bitstring chan bits; + close_out chan) + files; + List.iter + (fun (filename, n, bits) -> + let actual_filename = sprintf "../../../tests/data/hex%d.actual" n in + let expected_filename = sprintf "../../../tests/data/hex%d.expected" n in + let cmd = + sprintf + "%s -u %s %s" + (Filename.quote diff) + (Filename.quote expected_filename) + (Filename.quote actual_filename) + in + if Sys.command cmd <> 0 then exit 1) + files +;; (* * Regression test for bug in 'as-binding' found by Matej Kosik. @@ -1145,13 +1280,13 @@ let as_binding_bug_test _ = match%bitstring bits with | {| _ : 1 |} as foo -> let len = Bitstring.bitstring_length foo in - if len <> 1 then ( + if len <> 1 + then ( Bitstring.hexdump_bitstring stderr foo; eprintf "test error: length = %d, expecting 1\n" len; - exit 1 - ) - | {| _ |} -> - assert false + exit 1) + | {| _ |} -> assert false +;; (* * Regression test for bug in concatenation found by Phil Tomson. @@ -1161,65 +1296,74 @@ let concat_regression_test _ = let errors = ref 0 in let bs_256 = Bitstring.ones_bitstring 256 in assert (Bitstring.bitstring_length bs_256 = 256); - - let%bitstring bs2 = {| + let%bitstring bs2 = + {| false : 1; (Bitstring.subbitstring bs_256 0 66) : 66 : bitstring - |} in + |} + in let len = Bitstring.bitstring_length bs2 in - if len <> 67 then ( + if len <> 67 + then ( eprintf "invalid length of bs2: len = %d, expected 67\n" len; Bitstring.hexdump_bitstring stderr bs2; - incr errors - ); - - let%bitstring bs3 = {| + incr errors); + let%bitstring bs3 = + {| false : 1; (Bitstring.subbitstring bs_256 0 66) : 66 : bitstring; (Bitstring.subbitstring bs_256 66 67) : 67 : bitstring - |} in + |} + in let len = Bitstring.bitstring_length bs3 in - if len <> 134 then ( + if len <> 134 + then ( eprintf "invalid length of bs3: len = %d, expected 134\n" len; Bitstring.hexdump_bitstring stderr bs3; - incr errors - ); - - let%bitstring bs4 = {| + incr errors); + let%bitstring bs4 = + {| (Bitstring.subbitstring bs_256 66 67) : 67 : bitstring - |} in + |} + in let len = Bitstring.bitstring_length bs4 in - if len <> 67 then ( + if len <> 67 + then ( eprintf "invalid length of bs4: len = %d, expected 67\n" len; Bitstring.hexdump_bitstring stderr bs4; - incr errors - ); - - let bs5 = Bitstring.concat [Bitstring.subbitstring bs_256 0 66; Bitstring.subbitstring bs_256 66 67] in + incr errors); + let bs5 = + Bitstring.concat + [ Bitstring.subbitstring bs_256 0 66; Bitstring.subbitstring bs_256 66 67 ] + in let len = Bitstring.bitstring_length bs5 in - if len <> 133 then ( + if len <> 133 + then ( eprintf "invalid length of bs5: len = %d, expected 133\n" len; Bitstring.hexdump_bitstring stderr bs5; - incr errors - ); - - let bs6 = Bitstring.concat [ Bitstring.subbitstring bs_256 0 64; Bitstring.subbitstring bs_256 64 64] in + incr errors); + let bs6 = + Bitstring.concat + [ Bitstring.subbitstring bs_256 0 64; Bitstring.subbitstring bs_256 64 64 ] + in let len = Bitstring.bitstring_length bs6 in - if len <> 128 then ( + if len <> 128 + then ( eprintf "invalid length of bs6: len = %d, expected 128\n" len; Bitstring.hexdump_bitstring stderr bs6; - incr errors - ); - - let bs7 = Bitstring.concat [ Bitstring.subbitstring bs_256 0 65; Bitstring.subbitstring bs_256 65 64] in + incr errors); + let bs7 = + Bitstring.concat + [ Bitstring.subbitstring bs_256 0 65; Bitstring.subbitstring bs_256 65 64 ] + in let len = Bitstring.bitstring_length bs7 in - if len <> 129 then ( + if len <> 129 + then ( eprintf "invalid length of bs7: len = %d, expected 129\n" len; Bitstring.hexdump_bitstring stderr bs7; - incr errors - ); - + incr errors); if !errors <> 0 then exit 1 +;; (* * Prefix tests. @@ -1234,32 +1378,31 @@ let is_prefix_basic_aligned_test _ = let%bitstring bs1 = {| 0x1A2 : 11 : bigendian |} in let%bitstring bs2 = {| 0x1A : 7 |} in assert_bool "Prefix failed" (Bitstring.is_prefix bs1 bs2) +;; let is_prefix_nested_aligned_test _ = (* Match mod8 bitstrings *) let%bitstring bs1 = {| 0x12345678l : 32 : bigendian |} in let%bitstring bs2 = {| 0x56 : 8 |} in - begin match%bitstring bs1 with - | {| _ : 16; n : -1 : bitstring |} -> - assert_bool "Prefix failed" (Bitstring.is_prefix n bs2) - | {| _ |} -> - assert_failure "Invalid bitstring" - end; + (match%bitstring bs1 with + | {| _ : 16; n : -1 : bitstring |} -> + assert_bool "Prefix failed" (Bitstring.is_prefix n bs2) + | {| _ |} -> assert_failure "Invalid bitstring"); (* Match other bitstrings *) - begin match%bitstring bs1 with + match%bitstring bs1 with | {| _ : 18; n : -1 : bitstring |} -> - begin match%bitstring bs2 with - | {| _ : 2; m : -1 : bitstring |} -> - assert_bool "Prefix failed" (Bitstring.is_prefix n m) - | {| _ |} -> assert_failure "Invalid bitstring" - end + (match%bitstring bs2 with + | {| _ : 2; m : -1 : bitstring |} -> + assert_bool "Prefix failed" (Bitstring.is_prefix n m) + | {| _ |} -> assert_failure "Invalid bitstring") | {| _ |} -> assert_failure "Invalid bitstring" - end +;; let is_prefix_basic_unaligned_test _ = let%bitstring bs1 = {| 0x1234 : 15 : bigendian |} in let%bitstring bs2 = {| 0x12 : 7 |} in assert_bool "Prefix failed" (Bitstring.is_prefix bs1 bs2) +;; let is_prefix_nested_unaligned_test _ = let%bitstring bs1 = {| 0x12345678l : 32 : bigendian |} in @@ -1267,40 +1410,42 @@ let is_prefix_nested_unaligned_test _ = match%bitstring bs1 with | {| _ : 13; nested : -1 : bitstring - |} -> - assert_bool "Prefix failed" (Bitstring.is_prefix nested bs2) - | {| _ |} -> - assert_failure "Invalid bitstring" - -let suite = "BitstringLegacyTests" >::: [ - "load_test" >:: load_test; - "run_test" >:: run_test; - "match_random_bits_test" >:: match_random_bits_test; - "match_random_bits_with_int_test" >:: match_random_bits_with_int_test; - "check_value_limits_test" >:: check_value_limits_test; - "signed_byte_create_test" >:: signed_byte_create_test; - "signed_byte_create_and_match_test" >:: signed_byte_create_and_match_test; - "signed_int_limits_test" >:: signed_int_limits_test; - "fixed_extraction_test" >:: fixed_extraction_test; - "extract_regression_test" >:: extract_regression_test; - "construct_and_match_random_test" >:: construct_and_match_random_test; - "nasty_non_aligned_corner_case_test" >:: nasty_non_aligned_corner_case_test; - "concat_bit_get_test" >:: concat_bit_get_test; - "compare_test" >:: compare_test; - "subbitstring_test" >:: subbitstring_test; - "takebits_test" >:: takebits_test; - "file_load_test" >:: file_load_test; - "zeroes_ones_test" >:: zeroes_ones_test; - "endianness_test" >:: endianness_test; - "simple_offset_test" >:: simple_offset_test; - "offset_string_test" >:: offset_string_test; - "computed_offset_test" >:: computed_offset_test; - "save_offset_to_test" >:: save_offset_to_test; - "check_bind_test" >:: check_bind_test; - "as_binding_bug_test" >:: as_binding_bug_test; - "concat_regression_test" >:: concat_regression_test; - "is_prefix_basic_aligned_test" >:: is_prefix_basic_aligned_test; - "is_prefix_nested_aligned_test" >:: is_prefix_nested_aligned_test; - "is_prefix_basic_unaligned_test" >:: is_prefix_basic_unaligned_test; - "is_prefix_nested_unaligned_test" >:: is_prefix_nested_unaligned_test; - ] + |} + -> assert_bool "Prefix failed" (Bitstring.is_prefix nested bs2) + | {| _ |} -> assert_failure "Invalid bitstring" +;; + +let suite = + "BitstringLegacyTests" + >::: [ "load_test" >:: load_test + ; "run_test" >:: run_test + ; "match_random_bits_test" >:: match_random_bits_test + ; "match_random_bits_with_int_test" >:: match_random_bits_with_int_test + ; "check_value_limits_test" >:: check_value_limits_test + ; "signed_byte_create_test" >:: signed_byte_create_test + ; "signed_byte_create_and_match_test" >:: signed_byte_create_and_match_test + ; "signed_int_limits_test" >:: signed_int_limits_test + ; "fixed_extraction_test" >:: fixed_extraction_test + ; "extract_regression_test" >:: extract_regression_test + ; "construct_and_match_random_test" >:: construct_and_match_random_test + ; "nasty_non_aligned_corner_case_test" >:: nasty_non_aligned_corner_case_test + ; "concat_bit_get_test" >:: concat_bit_get_test + ; "compare_test" >:: compare_test + ; "subbitstring_test" >:: subbitstring_test + ; "takebits_test" >:: takebits_test + ; "file_load_test" >:: file_load_test + ; "zeroes_ones_test" >:: zeroes_ones_test + ; "endianness_test" >:: endianness_test + ; "simple_offset_test" >:: simple_offset_test + ; "offset_string_test" >:: offset_string_test + ; "computed_offset_test" >:: computed_offset_test + ; "save_offset_to_test" >:: save_offset_to_test + ; "check_bind_test" >:: check_bind_test + ; "as_binding_bug_test" >:: as_binding_bug_test + ; "concat_regression_test" >:: concat_regression_test + ; "is_prefix_basic_aligned_test" >:: is_prefix_basic_aligned_test + ; "is_prefix_nested_aligned_test" >:: is_prefix_nested_aligned_test + ; "is_prefix_basic_unaligned_test" >:: is_prefix_basic_unaligned_test + ; "is_prefix_nested_unaligned_test" >:: is_prefix_nested_unaligned_test + ] +;; diff --git a/tests/BitstringLegacyTest.mli b/tests/BitstringLegacyTest.mli index c09b06e..e3df8d6 100644 --- a/tests/BitstringLegacyTest.mli +++ b/tests/BitstringLegacyTest.mli @@ -1,3 +1,3 @@ open OUnit2 -val suite : OUnit2.test +val suite : OUnit2.test diff --git a/tests/BitstringLetStarSyntaxTest.ml b/tests/BitstringLetStarSyntaxTest.ml index f397d0a..766f6c0 100644 --- a/tests/BitstringLetStarSyntaxTest.ml +++ b/tests/BitstringLetStarSyntaxTest.ml @@ -15,8 +15,8 @@ let match_bits_with_let_star_syntax _ = (let* bits = Some (Bitstring.bitstring_of_string "U") in Some (match%bitstring bits with - | {| hi: 4; lo: 4 |} -> assert_equal hi lo - | {| _ |} -> assert_failure "Something wen't terribly wrong!")) + | {| hi: 4; lo: 4 |} -> assert_equal hi lo + | {| _ |} -> assert_failure "Something wen't terribly wrong!")) |> ignore ;; @@ -33,8 +33,8 @@ let match_bits_with_and_star_syntax _ = and* bits = Some (Bitstring.bitstring_of_string "U") in Some (match%bitstring bits with - | {| hi: 4; lo: 4 |} -> assert_equal lo s - | {| _ |} -> assert_failure "Something wen't terribly wrong!")) + | {| hi: 4; lo: 4 |} -> assert_equal lo s + | {| _ |} -> assert_failure "Something wen't terribly wrong!")) |> ignore ;; @@ -43,8 +43,8 @@ let match_bits_with_and_plus_syntax _ = and+ bits = Some (Bitstring.bitstring_of_string "U") in Some (match%bitstring bits with - | {| hi: 4; lo: 4 |} -> assert_equal lo s - | {| _ |} -> assert_failure "Something wen't terribly wrong!")) + | {| hi: 4; lo: 4 |} -> assert_equal lo s + | {| _ |} -> assert_failure "Something wen't terribly wrong!")) |> ignore ;; diff --git a/tests/BitstringParserTest.ml b/tests/BitstringParserTest.ml index d2bc636..4013e14 100644 --- a/tests/BitstringParserTest.ml +++ b/tests/BitstringParserTest.ml @@ -43,12 +43,13 @@ let ext3_test context = ; _ : 16 : littleendian (* Mount count *) ; _ : 16 : littleendian (* Maximal mount count *) ; 0xef53 : 16 : littleendian (* Magic signature *) - |} -> () + |} + -> () (* * Otherwise, throw an error *) - | {| _ |} -> - failwith "Invalid EXT3 superblock" + | {| _ |} -> failwith "Invalid EXT3 superblock" +;; (* * GIF parser test @@ -69,12 +70,13 @@ let gif_test context = 7 : 3 ; (* Bits/pixel = bps+1 *) 0 : 8 ; (* Background colo *) 0 : 8 - |} -> () + |} + -> () (* * Otherwise, throw an error *) - | {| _ |} -> - failwith "Invalid GIF image" + | {| _ |} -> failwith "Invalid GIF image" +;; (* * PCAP parser test @@ -84,6 +86,7 @@ let to_bitstring_endian = function | 0xa1b2c3d4_l | 0xa1b23c4d_l -> Bitstring.BigEndian | 0xd4c3b2a1_l | 0x4d3cb2a1_l -> Bitstring.LittleEndian | _ -> failwith "Unknown PCAP format" +;; let pcap_ipv4_test context ipv4 = match%bitstring ipv4 with @@ -106,8 +109,10 @@ let pcap_ipv4_test context ipv4 = 0x1F : 8; 0x08 : 8; (* destination IP *) _ : -1 : bitstring - |} -> () + |} + -> () | {| _ |} -> failwith "Not a valid IPv4 layer" +;; let pcap_eth_test context eth = match%bitstring eth with @@ -125,8 +130,10 @@ let pcap_eth_test context eth = 0x97 : 8; (* source MAC *) 0x0800 : 16 : bigendian; (* EtherType *) ipv4 : -1 : bitstring - |} -> pcap_ipv4_test context ipv4 + |} + -> pcap_ipv4_test context ipv4 | {| _ |} -> failwith "Not a valid Ethernet layer" +;; let pcap_packet_test context endian packet = match%bitstring packet with @@ -135,8 +142,10 @@ let pcap_packet_test context endian packet = incl_len : 32 : endian (endian); orig_len : 32 : endian (endian); eth : (Int32.to_int incl_len) * 8 : bitstring - |} -> pcap_eth_test context eth + |} + -> pcap_eth_test context eth | {| _ |} -> failwith "Not a valid packet descriptor" +;; let pcap_test context = let bits = Bitstring.bitstring_of_file "../../../tests/data/net.pcap" in @@ -155,11 +164,13 @@ let pcap_test context = _ : 32; (* snaplen *) _ : 32; (* network *) packet : -1 : bitstring - |} -> pcap_packet_test context (to_bitstring_endian magic) packet + |} + -> pcap_packet_test context (to_bitstring_endian magic) packet (* * Otherwise, throw an error *) | {| _ |} -> failwith "Not a valid PCAP file" +;; (* * Function-style parser test @@ -169,15 +180,14 @@ let function_parser = function%bitstring | {| 1 : 3 ; 2 : 4 ; "hello" : 40 : string - |} -> - assert_bool "Bitstring is valid" true - | {| _ |} -> - assert_bool "Invalid bitstring" false + |} + -> assert_bool "Bitstring is valid" true + | {| _ |} -> assert_bool "Invalid bitstring" false ;; let function_parser_test context = - [%bitstring {| 1 : 3; 2 : 4; "hello" : 40 : string |}] - |> function_parser + [%bitstring {| 1 : 3; 2 : 4; "hello" : 40 : string |}] |> function_parser +;; (* * Function-style parser test, inline @@ -189,10 +199,10 @@ let function_parser_inline_test context = | {| 1 : 3 ; 2 : 4 ; "hello" : 40 : string - |} -> - assert_bool "Bitstring is valid" true - | {| _ |} -> - assert_bool "Invalid bitstring" false + |} + -> assert_bool "Bitstring is valid" true + | {| _ |} -> assert_bool "Invalid bitstring" false +;; (* * parser with a guard (PR#16) @@ -201,66 +211,69 @@ let function_parser_inline_test context = let parser_with_guard_test context = let bits = Bitstring.bitstring_of_string "abc" in match%bitstring bits with - | {| "abc" : 24 : string |} when false -> - assert_bool "Guard was ignored" false - | {| _ |} -> - assert_bool "Guard was honored" true + | {| "abc" : 24 : string |} when false -> assert_bool "Guard was ignored" false + | {| _ |} -> assert_bool "Guard was honored" true +;; (* * Wrong fastpath extraction function #46 *) let wrong_fp_extraction context = - let mb = ((Bytes.of_string "\000\000\145"), 0, 24) in + let mb = Bytes.of_string "\000\000\145", 0, 24 in match%bitstring mb with | {| matched_value : 24 : bigendian |} -> assert_equal matched_value 145 | {| _ |} -> assert_bool "Invalid bitstring" false +;; let wrong_fp_extraction_dynamic context = - let mb = ((Bytes.of_string "\000\000\000\145"), 0, 32) - and on = 8 - in + let mb = Bytes.of_string "\000\000\000\145", 0, 32 + and on = 8 in match%bitstring mb with | {| _ : on ; matched_value : 24 : bigendian |} -> assert_equal matched_value 145 | {| _ |} -> assert_bool "Invalid bitstring" false +;; (* * Wrong LE extraction on partial int64. *) - let wrong_le_partial_int64_extraction context = +let wrong_le_partial_int64_extraction context = (* * Forward. *) - let mb = ((Bytes.of_string "\xA0\x00\x00\x00\x00\x00\x00\x00"), 0, 64) in + let mb = Bytes.of_string "\xA0\x00\x00\x00\x00\x00\x00\x00", 0, 64 in match%bitstring mb with | {| a:4; b:60:littleendian |} -> assert_equal a 10; assert_equal b 0L - | {| _ |} -> assert_bool "Invalid bitstring" false; - (* - * Backward. - *) - let mb = ((Bytes.of_string "\x00\x00\x00\x00\x00\x00\x00\x0A"), 0, 64) in - match%bitstring mb with - | {| b:60:littleendian; a:4 |} -> - assert_equal a 10; - assert_equal b 0L - | {| _ |} -> assert_bool "Invalid bitstring" false + | {| _ |} -> + assert_bool "Invalid bitstring" false; + (* + * Backward. + *) + let mb = Bytes.of_string "\x00\x00\x00\x00\x00\x00\x00\x0A", 0, 64 in + (match%bitstring mb with + | {| b:60:littleendian; a:4 |} -> + assert_equal a 10; + assert_equal b 0L + | {| _ |} -> assert_bool "Invalid bitstring" false) ;; (* * Test suite definition *) -let suite = "BitstringParserTest" >::: [ - "ext3" >:: ext3_test; - "gif" >:: gif_test; - "pcap" >:: pcap_test; - "function" >:: function_parser_test; - "function_inline" >:: function_parser_inline_test; - "parser_with_guard" >:: parser_with_guard_test; - "wrong_fp_extraction" >:: wrong_fp_extraction; - "wrong_fp_extraction_dynamic" >:: wrong_fp_extraction_dynamic; - "wrong_le_partial_int64_extraction" >:: wrong_le_partial_int64_extraction; - ] +let suite = + "BitstringParserTest" + >::: [ "ext3" >:: ext3_test + ; "gif" >:: gif_test + ; "pcap" >:: pcap_test + ; "function" >:: function_parser_test + ; "function_inline" >:: function_parser_inline_test + ; "parser_with_guard" >:: parser_with_guard_test + ; "wrong_fp_extraction" >:: wrong_fp_extraction + ; "wrong_fp_extraction_dynamic" >:: wrong_fp_extraction_dynamic + ; "wrong_le_partial_int64_extraction" >:: wrong_le_partial_int64_extraction + ] +;; diff --git a/tests/BitstringQualifierTest.ml b/tests/BitstringQualifierTest.ml index af76482..03eb649 100644 --- a/tests/BitstringQualifierTest.ml +++ b/tests/BitstringQualifierTest.ml @@ -26,13 +26,14 @@ let map_test context = match%bitstring source with | {| value0 : 16 : map (fun v -> v + 1) ; value1 : 16 : map (fun v -> Some v) - |} -> + |} + -> assert_equal value0 2; - begin match value1 with - | Some v -> assert_equal v 2 - | _ -> assert_bool "Invalid map result" false - end + (match value1 with + | Some v -> assert_equal v 2 + | _ -> assert_bool "Invalid map result" false) | {| _ |} -> assert_bool "Invalid pattern" false +;; (* * Test of the save_offset_to() qualifier @@ -45,20 +46,22 @@ let save_offset_test context = ; _ : 7 : save_offset_to (off1) ; _ : 4 : save_offset_to (off2) ; "abc" : 24 : save_offset_to (off3), string - |} -> + |} + -> assert_equal off0 0; assert_equal off1 3; assert_equal off2 10; assert_equal off3 14 | {| _ |} -> assert_bool "Invalid pattern" false +;; (* * Test suite definition *) -let suite = "BitstringQualifierTest" >::: [ - "map" >:: map_test; - "save_offset_to" >:: save_offset_test - ] +let suite = + "BitstringQualifierTest" + >::: [ "map" >:: map_test; "save_offset_to" >:: save_offset_test ] +;; let () = run_test_tt_main suite diff --git a/tests/bitstring_tests.ml b/tests/bitstring_tests.ml index d2e7143..9e3d94f 100644 --- a/tests/bitstring_tests.ml +++ b/tests/bitstring_tests.ml @@ -1,11 +1,11 @@ open OUnit2 let () = - [ - BitstringLegacyTest.suite; - BitstringParserTest.suite; - BitstringConstructorTest.suite; - BitstringQualifierTest.suite; - BitstringLetStarSyntaxTest.suite; + [ BitstringLegacyTest.suite + ; BitstringParserTest.suite + ; BitstringConstructorTest.suite + ; BitstringQualifierTest.suite + ; BitstringLetStarSyntaxTest.suite ] |> List.iter (fun t -> run_test_tt_main t) +;; From 4083d564b4f6bd722e07e7eacde3a35fce1545b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20R=2E=20Gu=C3=A9rin?= Date: Fri, 7 Nov 2025 16:50:26 +0100 Subject: [PATCH 2/2] Clean-up comments and doc-comments --- docs/examples.md | 18 +- examples/elf.ml | 15 +- examples/ext3_superblock.ml | 108 ++-- examples/gif.ml | 23 +- examples/ipv4_header.ml | 29 +- examples/libpcap.ml | 101 ++-- examples/make_ipv4_header.ml | 17 +- examples/ping.ml | 45 +- ppx/ppx_bitstring.ml | 35 +- src/bitstring.ml | 212 +++----- src/bitstring.mli | 873 ++++++++++++++---------------- src/bitstring_config.ml | 43 +- src/bitstring_types.ml | 38 +- tests/BitstringConstructorTest.ml | 64 +-- tests/BitstringLegacyTest.ml | 228 +++----- tests/BitstringParserTest.ml | 96 +--- tests/BitstringQualifierTest.ml | 40 +- 17 files changed, 865 insertions(+), 1120 deletions(-) diff --git a/docs/examples.md b/docs/examples.md index 316d58a..fdee2ba 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -94,19 +94,17 @@ let () = ## Simple binary message parser ```ocaml -(* - +---------------+---------------+--------------------------+ - | type | subtype | parameter | - +---------------+---------------+--------------------------+ - <-- 16 bits --> <-- 16 bits --> <------- 32 bits --------> +(* +---------------+---------------+--------------------------+ + | type | subtype | parameter | + +---------------+---------------+--------------------------+ + <-- 16 bits --> <-- 16 bits --> <------- 32 bits --------> - All fields are in network byte order. -*) + All fields are in network byte order. *) let%bitstring make_message typ subtype param = {| - typ : 16; - subtype : 16; - param : 32 + typ : 16; + subtype : 16; + param : 32 |};; ``` diff --git a/examples/elf.ml b/examples/elf.ml index 3f22834..e58a8cf 100644 --- a/examples/elf.ml +++ b/examples/elf.ml @@ -1,6 +1,4 @@ -(* Read an ELF (Linux binary) header. - * $Id$ - *) +(* Read an ELF (Linux binary) header. *) open Printf @@ -8,11 +6,12 @@ let () = let filename = "/bin/ls" in let bits = Bitstring.bitstring_of_file filename in match%bitstring bits with - | {| 0x7f : 8; "ELF" : 24 : string; (* ELF magic number *) - _ : 12*8 : bitstring; (* ELF identifier *) - e_type : 16 : littleendian; (* object file type *) - e_machine : 16 : littleendian (* architecture *) - |} + | {| 0x7f : 8 + ; "ELF" : 24 : string (* ELF magic number *) + ; _ : 12*8 : bitstring (* ELF identifier *) + ; e_type : 16 : littleendian (* object file type *) + ; e_machine : 16 : littleendian (* architecture *) + |} -> printf "%s: ELF binary, type %d, arch %d\n" filename e_type e_machine | {| _ |} -> eprintf "%s: Not an ELF binary\n" filename ;; diff --git a/examples/ext3_superblock.ml b/examples/ext3_superblock.ml index b95c576..a3c78bc 100644 --- a/examples/ext3_superblock.ml +++ b/examples/ext3_superblock.ml @@ -1,6 +1,4 @@ -(* Parse an ext3 superblock. - * $Id$ - *) +(* Parse an ext3 superblock. *) open Printf @@ -12,58 +10,58 @@ let bits = Bitstring.bitstring_of_file "ext3_sb" let () = match%bitstring bits with - | {|s_inodes_count : 32 : littleendian; (* Inodes count *) - s_blocks_count : 32 : littleendian; (* Blocks count *) - s_r_blocks_count : 32 : littleendian; (* Reserved blocks count *) - s_free_blocks_count : 32 : littleendian; (* Free blocks count *) - s_free_inodes_count : 32 : littleendian; (* Free inodes count *) - s_first_data_block : 32 : littleendian; (* First Data Block *) - s_log_block_size : 32 : littleendian; (* Block size *) - s_log_frag_size : 32 : littleendian; (* Fragment size *) - s_blocks_per_group : 32 : littleendian; (* # Blocks per group *) - s_frags_per_group : 32 : littleendian; (* # Fragments per group *) - s_inodes_per_group : 32 : littleendian; (* # Inodes per group *) - s_mtime : 32 : littleendian; (* Mount time *) - s_wtime : 32 : littleendian; (* Write time *) - s_mnt_count : 16 : littleendian; (* Mount count *) - s_max_mnt_count : 16 : littleendian; (* Maximal mount count *) - 0xef53 : 16 : littleendian; (* Magic signature *) - s_state : 16 : littleendian; (* File system state *) - s_errors : 16 : littleendian; (* Behaviour when detecting errors *) - s_minor_rev_level : 16 : littleendian; (* minor revision level *) - s_lastcheck : 32 : littleendian; (* time of last check *) - s_checkinterval : 32 : littleendian; (* max. time between checks *) - s_creator_os : 32 : littleendian; (* OS *) - s_rev_level : 32 : littleendian; (* Revision level *) - s_def_resuid : 16 : littleendian; (* Default uid for reserved blocks *) - s_def_resgid : 16 : littleendian; (* Default gid for reserved blocks *) - s_first_ino : 32 : littleendian; (* First non-reserved inode *) - s_inode_size : 16 : littleendian; (* size of inode structure *) - s_block_group_nr : 16 : littleendian; (* block group # of this superblock *) - s_feature_compat : 32 : littleendian; (* compatible feature set *) - s_feature_incompat : 32 : littleendian; (* incompatible feature set *) - s_feature_ro_compat : 32 : littleendian; (* readonly-compatible feature set *) - s_uuid : 128 : string; (* 128-bit uuid for volume *) - s_volume_name : 128 : string; (* volume name *) - s_last_mounted : 512 : string; (* directory where last mounted *) - s_algorithm_usage_bitmap : 32 : littleendian; (* For compression *) - s_prealloc_blocks : 8; (* Nr of blocks to try to preallocate*) - s_prealloc_dir_blocks : 8; (* Nr to preallocate for dirs *) - s_reserved_gdt_blocks : 16 : littleendian;(* Per group desc for online growth *) - s_journal_uuid : 128 : string; (* uuid of journal superblock *) - s_journal_inum : 32 : littleendian; (* inode number of journal file *) - s_journal_dev : 32 : littleendian; (* device number of journal file *) - s_last_orphan : 32 : littleendian; (* start of list of inodes to delete *) - s_hash_seed0 : 32 : littleendian; (* HTREE hash seed *) - s_hash_seed1 : 32 : littleendian; - s_hash_seed2 : 32 : littleendian; - s_hash_seed3 : 32 : littleendian; - s_def_hash_version : 8; (* Default hash version to use *) - s_reserved_char_pad : 8; - s_reserved_word_pad : 16 : littleendian; - s_default_mount_opts : 32 : littleendian; - s_first_meta_bg : 32 : littleendian; (* First metablock block group *) - _ : 6080 : bitstring |} + | {| s_inodes_count : 32 : littleendian (* Inodes count *) + ; s_blocks_count : 32 : littleendian (* Blocks count *) + ; s_r_blocks_count : 32 : littleendian (* Reserved blocks count *) + ; s_free_blocks_count : 32 : littleendian (* Free blocks count *) + ; s_free_inodes_count : 32 : littleendian (* Free inodes count *) + ; s_first_data_block : 32 : littleendian (* First Data Block *) + ; s_log_block_size : 32 : littleendian (* Block size *) + ; s_log_frag_size : 32 : littleendian (* Fragment size *) + ; s_blocks_per_group : 32 : littleendian (* # Blocks per group *) + ; s_frags_per_group : 32 : littleendian (* # Fragments per group *) + ; s_inodes_per_group : 32 : littleendian (* # Inodes per group *) + ; s_mtime : 32 : littleendian (* Mount time *) + ; s_wtime : 32 : littleendian (* Write time *) + ; s_mnt_count : 16 : littleendian (* Mount count *) + ; s_max_mnt_count : 16 : littleendian (* Maximal mount count *) + ; 0xef53 : 16 : littleendian (* Magic signature *) + ; s_state : 16 : littleendian (* File system state *) + ; s_errors : 16 : littleendian (* Behaviour when detecting errors *) + ; s_minor_rev_level : 16 : littleendian (* minor revision level *) + ; s_lastcheck : 32 : littleendian (* time of last check *) + ; s_checkinterval : 32 : littleendian (* max. time between checks *) + ; s_creator_os : 32 : littleendian (* OS *) + ; s_rev_level : 32 : littleendian (* Revision level *) + ; s_def_resuid : 16 : littleendian (* Default uid for reserved blocks *) + ; s_def_resgid : 16 : littleendian (* Default gid for reserved blocks *) + ; s_first_ino : 32 : littleendian (* First non-reserved inode *) + ; s_inode_size : 16 : littleendian (* size of inode structure *) + ; s_block_group_nr : 16 : littleendian (* block group # of this superblock *) + ; s_feature_compat : 32 : littleendian (* compatible feature set *) + ; s_feature_incompat : 32 : littleendian (* incompatible feature set *) + ; s_feature_ro_compat : 32 : littleendian (* readonly-compatible feature set *) + ; s_uuid : 128 : string (* 128-bit uuid for volume *) + ; s_volume_name : 128 : string (* volume name *) + ; s_last_mounted : 512 : string (* directory where last mounted *) + ; s_algorithm_usage_bitmap : 32 : littleendian (* For compression *) + ; s_prealloc_blocks : 8 (* Nr of blocks to try to preallocate*) + ; s_prealloc_dir_blocks : 8 (* Nr to preallocate for dirs *) + ; s_reserved_gdt_blocks : 16 : littleendian (* Per group desc for online growth *) + ; s_journal_uuid : 128 : string (* uuid of journal superblock *) + ; s_journal_inum : 32 : littleendian (* inode number of journal file *) + ; s_journal_dev : 32 : littleendian (* device number of journal file *) + ; s_last_orphan : 32 : littleendian (* start of list of inodes to delete *) + ; s_hash_seed0 : 32 : littleendian (* HTREE hash seed *) + ; s_hash_seed1 : 32 : littleendian + ; s_hash_seed2 : 32 : littleendian + ; s_hash_seed3 : 32 : littleendian + ; s_def_hash_version : 8 (* Default hash version to use *) + ; s_reserved_char_pad : 8 + ; s_reserved_word_pad : 16 : littleendian + ; s_default_mount_opts : 32 : littleendian + ; s_first_meta_bg : 32 : littleendian (* First metablock block group *) + ; _ : 6080 : bitstring |} -> (* Padding to the end of the block *) printf "ext3 superblock:\n"; diff --git a/examples/gif.ml b/examples/gif.ml index eec566e..8fac370 100644 --- a/examples/gif.ml +++ b/examples/gif.ml @@ -1,6 +1,4 @@ -(* GIF header parser. - * $Id$ - *) +(* GIF header parser. *) open Printf @@ -9,15 +7,16 @@ let () = let filename = Sys.argv.(1) in let bits = Bitstring.bitstring_of_file filename in match%bitstring bits with - | {|("GIF87a"|"GIF89a") : 6*8 : string; (* GIF magic. *) - width : 16 : littleendian; - height : 16 : littleendian; - colormap : 1; (* Has colormap? *) - colorbits : 3; (* Color res = colorbits+1 *) - sortflag : 1; - bps : 3; (* Bits/pixel = bps+1 *) - bg : 8; (* Background colour. *) - aspectratio : 8|} + | {| ("GIF87a"|"GIF89a") : 6*8 : string (* GIF magic. *) + ; width : 16 : littleendian + ; height : 16 : littleendian + ; colormap : 1 (* Has colormap? *) + ; colorbits : 3 (* Color res = colorbits+1 *) + ; sortflag : 1 + ; bps : 3 (* Bits/pixel = bps+1 *) + ; bg : 8 (* Background colour. *) + ; aspectratio : 8 + |} -> printf "%s: GIF image:\n" filename; printf " size %d %d\n" width height; diff --git a/examples/ipv4_header.ml b/examples/ipv4_header.ml index 869b15e..edc3a3f 100644 --- a/examples/ipv4_header.ml +++ b/examples/ipv4_header.ml @@ -1,6 +1,4 @@ -(* Parse and display an IPv4 header from a file. - * $Id$ - *) +(* Parse and display an IPv4 header from a file. *) open Printf @@ -8,15 +6,22 @@ let header = Bitstring.bitstring_of_file "ipv4_header.dat" let () = match%bitstring header with - | {|version : 4; hdrlen : 4; tos : 8; length : 16; - identification : 16; flags : 3; fragoffset : 13; - ttl : 8; protocol : 8; checksum : 16; - source : 32; - dest : 32; - options : (hdrlen-5)*32 : bitstring; - payload : -1 : bitstring|} - when version = 4 -> - printf "IPv%d:\n" version; + | {| 4 : 4 + ; hdrlen : 4; tos : 8 + ; length : 16 + ; identification : 16 + ; flags : 3 + ; fragoffset : 13 + ; ttl : 8 + ; protocol : 8 + ; checksum : 16 + ; source : 32 + ; dest : 32 + ; options : (hdrlen-5)*32 : bitstring + ; payload : -1 : bitstring + |} + -> + printf "IPv4:\n"; printf " header length: %d * 32 bit words\n" hdrlen; printf " type of service: %d\n" tos; printf " packet length: %d bytes\n" length; diff --git a/examples/libpcap.ml b/examples/libpcap.ml index cca7a0d..e6c4662 100644 --- a/examples/libpcap.ml +++ b/examples/libpcap.ml @@ -1,16 +1,14 @@ (* Print out packets from a tcpdump / libpcap / wireshark capture file. - * $Id$ - * - * To test this, capture some data using: - * /usr/sbin/tcpdump -s 1500 -w /tmp/dump - * then analyze it using: - * ./libpcap /tmp/dump - * - * The file format is documented here: - * http://wiki.wireshark.org/Development/LibpcapFileFormat - * - * libpcap endianness is determined at runtime. - *) + + To test this, capture some data using: + /usr/sbin/tcpdump -s 1500 -w /tmp/dump + then analyze it using: + ./libpcap /tmp/dump + + The file format is documented here: + http://wiki.wireshark.org/Development/LibpcapFileFormat + + libpcap endianness is determined at runtime. *) open Printf @@ -35,66 +33,67 @@ and endian_of = function and libpcap_header bits = match%bitstring bits with - | {|((0xa1b2c3d4_l|0xd4c3b2a1_l) as magic) : 32; (* magic number *) - major : 16 : endian (endian_of magic); (* version *) - minor : 16 : endian (endian_of magic); - timezone : 32 : endian (endian_of magic); (* timezone correction (secs)*) - _ : 32 : endian (endian_of magic); (* always 0 apparently *) - snaplen : 32 : endian (endian_of magic); (* max length of capt pckts *) - network : 32 : endian (endian_of magic); (* data link layer type *) - rest : -1 : bitstring + | {| ((0xa1b2c3d4_l|0xd4c3b2a1_l) as magic) : 32 (* magic number *) + ; major : 16 : endian (endian_of magic) (* version *) + ; minor : 16 : endian (endian_of magic) + ; timezone : 32 : endian (endian_of magic) (* timezone correction (secs)*) + ; _ : 32 : endian (endian_of magic) (* always 0 apparently *) + ; snaplen : 32 : endian (endian_of magic) (* max length of capt pckts *) + ; network : 32 : endian (endian_of magic) (* data link layer type *) + ; rest : -1 : bitstring |} -> endian_of magic, (major, minor, timezone, snaplen, network), rest | {|_|} -> failwith "not a libpcap/tcpdump packet capture file" and libpcap_packet e file_header bits = match%bitstring bits with - | {|ts_sec : 32 : endian (e); (* packet timestamp seconds *) - ts_usec : 32 : endian (e); (* packet timestamp microseconds *) - incl_len : 32 : endian (e); (* packet length saved in this file *) - orig_len : 32 : endian (e); (* packet length originally on wire *) - pkt_data : Int32.to_int incl_len*8 : bitstring; - rest : -1 : bitstring - |} + | {| ts_sec : 32 : endian (e) (* packet timestamp seconds *) + ; ts_usec : 32 : endian (e) (* packet timestamp microseconds *) + ; incl_len : 32 : endian (e) (* packet length saved in this file *) + ; orig_len : 32 : endian (e) (* packet length originally on wire *) + ; pkt_data : Int32.to_int incl_len*8 : bitstring + ; rest : -1 : bitstring + |} -> (ts_sec, ts_usec, incl_len, orig_len), pkt_data, rest | {|_|} -> raise End_of_file and decode_and_print_packet file_header pkt_header pkt_data = let ts_sec, ts_usec, _, orig_len = pkt_header in printf "%ld.%ld %ldB " ts_sec ts_usec orig_len; - (* Assume an ethernet frame containing an IPv4/6 packet. We ignore - * the ethertype field and determine the IP version from the packet - * itself. If it doesn't match our assumptions, hexdump it. - *) + (* Assume an ethernet frame containing an IPv4/6 packet. We ignore the + ethertype field and determine the IP version from the packet itself. If it + doesn't match our assumptions, hexdump it. *) (match%bitstring pkt_data with - | {|d0 : 8; d1 : 8; d2 : 8; d3 : 8; d4 : 8; d5 : 8; (* ether dest *) - s0 : 8; s1 : 8; s2 : 8; s3 : 8; s4 : 8; s5 : 8; (* ether src *) - _ : 16; (* ethertype *) - packet : -1 : bitstring (* payload *) + | {| d0 : 8; d1 : 8; d2 : 8; d3 : 8; d4 : 8; d5 : 8 (* ether dest *) + ; s0 : 8; s1 : 8; s2 : 8; s3 : 8; s4 : 8; s5 : 8 (* ether src *) + ; _ : 16 (* ethertype *) + ; packet : -1 : bitstring (* payload *) |} -> printf "%x:%x:%x:%x:%x:%x < %x:%x:%x:%x:%x:%x " d0 d1 d2 d3 d4 d5 s0 s1 s2 s3 s4 s5; (match%bitstring packet with - | {|4 : 4; (* IPv4 *) - hdrlen : 4; tos : 8; length : 16; - identification : 16; flags : 3; fragoffset : 13; - ttl : 8; protocol : 8; checksum : 16; - s0 : 8; s1 : 8; s2 : 8; s3 : 8; - d0 : 8; d1 : 8; d2 : 8; d3 : 8; - _(*options*) : (hdrlen-5)*32 : bitstring; - _(*payload*) : -1 : bitstring|} + | {| 4 : 4 + ; hdrlen : 4 ; tos : 8 ; length : 16 + ; identification : 16 ; flags : 3 ; fragoffset : 13 + ; ttl : 8; protocol : 8; checksum : 16 + ; s0 : 8; s1 : 8; s2 : 8; s3 : 8 + ; d0 : 8; d1 : 8; d2 : 8; d3 : 8 + ; _(*options*) : (hdrlen-5)*32 : bitstring + ; _(*payload*) : -1 : bitstring + |} -> printf "IPv4 %d.%d.%d.%d < %d.%d.%d.%d " s0 s1 s2 s3 d0 d1 d2 d3 - | {|6 : 4; (* IPv6 *) - tclass : 8; flow : 20; - length : 16; nexthdr : 8; ttl : 8; - _(*source*) : 128 : bitstring; - _(*dest*) : 128 : bitstring; - _(*payload*) : -1 : bitstring|} + | {| 6 : 4 + ; tclass : 8; flow : 20 + ; length : 16; nexthdr : 8; ttl : 8 + ; _(*source*) : 128 : bitstring + ; _(*dest*) : 128 : bitstring + ; _(*payload*) : -1 : bitstring + |} -> printf "IPv6 " - | {|_|} -> + | {| _ |} -> printf "\n"; Bitstring.hexdump_bitstring stdout packet) - | {|_|} -> + | {| _ |} -> printf "\n"; Bitstring.hexdump_bitstring stdout pkt_data); printf "\n" diff --git a/examples/make_ipv4_header.ml b/examples/make_ipv4_header.ml index 6b68121..5040e25 100644 --- a/examples/make_ipv4_header.ml +++ b/examples/make_ipv4_header.ml @@ -1,6 +1,4 @@ -(* Create an IPv4 header. - * $Id$ - *) +(* Create an IPv4 header. *) open Printf @@ -21,12 +19,11 @@ let payload_length = (length - (hdrlen * 4)) * 8 let payload = Bitstring.create_bitstring payload_length let%bitstring header = - {| - version : 4; hdrlen : 4; tos : 8; length : 16; - identification : 16; flags : 3; fragoffset : 13; - ttl : 8; protocol : 8; checksum : 16; - source : 32; dest : 32 - |} + {| version : 4; hdrlen : 4; tos : 8; length : 16 + ; identification : 16; flags : 3; fragoffset : 13 + ; ttl : 8; protocol : 8; checksum : 16 + ; source : 32; dest : 32 + |} ;; -let () = Bitstring.bitstring_to_file header "ipv4_header_out.dat" +let () = Bitstring.bitstring_to_file header "ipv4_header.dat" diff --git a/examples/ping.ml b/examples/ping.ml index d4a0aa4..bbf4864 100644 --- a/examples/ping.ml +++ b/examples/ping.ml @@ -1,19 +1,25 @@ -(* Read in IPv4 and IPv6 ping packets and display them. - * $Id$ - *) +(* Read in IPv4 and IPv6 ping packets and display them. *) open Printf let display pkt = match%bitstring pkt with (* IPv4 packet header *) - | {|4 : 4; hdrlen : 4; tos : 8; length : 16; - identification : 16; flags : 3; fragoffset : 13; - ttl : 8; protocol : 8; checksum : 16; - source : 32; - dest : 32; - options : (hdrlen-5)*32 : bitstring; - payload : -1 : bitstring|} + | {| 4 : 4 + ; hdrlen : 4 + ; tos : 8 + ; length : 16 + ; identification : 16 + ; flags : 3 + ; fragoffset : 13 + ; ttl : 8 + ; protocol : 8 + ; checksum : 16 + ; source : 32 + ; dest : 32 + ; options : (hdrlen-5)*32 : bitstring + ; payload : -1 : bitstring + |} -> printf "IPv4:\n"; printf " header length: %d * 32 bit words\n" hdrlen; @@ -31,11 +37,16 @@ let display pkt = printf " packet payload:\n"; Bitstring.hexdump_bitstring stdout payload (* IPv6 packet header *) - | {|6 : 4; tclass : 8; flow : 20; - length : 16; nexthdr : 8; ttl : 8; - source : 128 : bitstring; - dest : 128 : bitstring; - payload : -1 : bitstring|} + | {| 6 : 4 + ; tclass : 8 + ; flow : 20 + ; length : 16 + ; nexthdr : 8 + ; ttl : 8 + ; source : 128 : bitstring + ; dest : 128 : bitstring + ; payload : -1 : bitstring + |} -> printf "IPv6:\n"; printf " traffic class: %d\n" tclass; @@ -49,10 +60,10 @@ let display pkt = Bitstring.hexdump_bitstring stdout dest; printf "packet payload:\n"; Bitstring.hexdump_bitstring stdout payload - | {|version : 4|} -> + | {| version : 4 |} -> eprintf "unknown IP version %d\n" version; exit 1 - | {|_|} as pkt -> + | {| _ |} as pkt -> eprintf "data is smaller than one nibble:\n"; Bitstring.hexdump_bitstring stderr pkt; exit 1 diff --git a/ppx/ppx_bitstring.ml b/ppx/ppx_bitstring.ml index f1a6033..01ba1ef 100644 --- a/ppx/ppx_bitstring.ml +++ b/ppx/ppx_bitstring.ml @@ -1,18 +1,16 @@ -(* - * Copyright (c) 2016 Xavier R. Guérin - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - *) +(* Copyright (c) 2016 Xavier R. Guérin + + Permission to use, copy, modify, and distribute this software for any purpose + with or without fee is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. *) open Ppxlib open Printf @@ -477,10 +475,9 @@ let parse_match_fields str = | _ -> location_exn ~loc:str.loc "Invalid number of fields in statement" ;; -(* - * Some operators like the subtype cast operator (:>) can throw off the parser. - * The function below resolve these ambiguities on a case-by-case basis. - *) +(* Some operators like the subtype cast operator (:>) can throw off the parser. + The function below resolve these ambiguities on a case-by-case basis. *) + let stitch_ambiguous_operators lst = let fn e = function | [] -> [ e ] diff --git a/src/bitstring.ml b/src/bitstring.ml index 00a4d62..c47aca7 100644 --- a/src/bitstring.ml +++ b/src/bitstring.ml @@ -1,41 +1,35 @@ -(* - * Bitstring library. - * - * Copyright (C) 2008-2016 Red Hat Inc., Richard W.M. Jones - * Copyright (C) 2016 Red Hat Inc, Richard W.M. Jones, Xavier R. Guerin. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version, - * with the OCaml linking exception described in COPYING.LIB. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *) +(* Bitstring library. + + Copyright (C) 2008-2016 Red Hat Inc., Richard W.M. Jones + Copyright (C) 2016 Red Hat Inc, Richard W.M. Jones, Xavier R. Guerin + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) any + later version, with the OCaml linking exception described in COPYING.LIB. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *) open Printf include Bitstring_types include Bitstring_config -(* Enable runtime debug messages. Must also have been enabled - * in pa_bitstring.ml. - *) +(* Enable runtime debug messages. *) let debug = ref false (* Exceptions. *) exception Construct_failure of string * string * int * int -(* A bitstring is simply the data itself (as a byte sequence), and the - * bitoffset and the bitlength within the byte sequence. Note offset/length - * are counted in bits, not bytes. - *) +(* A bitstring is simply the data itself (as a byte sequence), and the bitoffset + and the bitlength within the byte sequence. Note offset/length are counted + in bits, not bytes. *) type bitstring = bytes * int * int type t = bitstring @@ -154,13 +148,13 @@ let takebits n (data, off, len) = ;; (*----------------------------------------------------------------------*) + (* Bitwise functions. - * - * We try to isolate all bitwise functions within these modules. - *) + + We try to isolate all bitwise functions within these modules. *) module I = struct - (* Bitwise operations on ints. Note that we assume int <= 31 bits. *) + (* Bitwise operations on ints. Note that we assume int <= 31 bits. *) external ( <<< ) : int -> int -> int = "%lslint" external ( >>> ) : int -> int -> int = "%lsrint" external to_int : int -> int = "%identity" @@ -221,9 +215,8 @@ module I = struct else pred (minus_one <<< pred bits) < v ;; - (* Call function g on the top bits, then f on each full byte - * (big endian - so start at top). - *) + (* Call function g on the top bits, then f on each full byte (big endian - so + start at top). *) let rec map_bytes_be g f v bits = if bits >= 8 then ( @@ -236,9 +229,8 @@ module I = struct g (to_int lsb) bits) ;; - (* Call function g on the top bits, then f on each full byte - * (little endian - so start at root). - *) + (* Call function g on the top bits, then f on each full byte (little endian - + so start at root). *) let rec map_bytes_le g f v bits = if bits >= 8 then ( @@ -253,10 +245,8 @@ module I = struct end module I32 = struct - (* Bitwise operations on int32s. Note we try to keep it as similar - * as possible to the I module above, to make it easier to track - * down bugs. - *) + (* Bitwise operations on int32s. Note we try to keep it as similar as + possible to the I module above, to make it easier to track down bugs. *) let ( <<< ) = Int32.shift_left let ( >>> ) = Int32.shift_right_logical let ( land ) = Int32.logand @@ -313,9 +303,8 @@ module I32 = struct v land mask = zero ;; - (* Call function g on the top bits, then f on each full byte - * (big endian - so start at top). - *) + (* Call function g on the top bits, then f on each full byte (big endian - so + start at top). *) let rec map_bytes_be g f v bits = if bits >= 8 then ( @@ -328,9 +317,8 @@ module I32 = struct g (to_int lsb) bits) ;; - (* Call function g on the top bits, then f on each full byte - * (little endian - so start at root). - *) + (* Call function g on the top bits, then f on each full byte (little endian - + so start at root). *) let rec map_bytes_le g f v bits = if bits >= 8 then ( @@ -345,10 +333,8 @@ module I32 = struct end module I64 = struct - (* Bitwise operations on int64s. Note we try to keep it as similar - * as possible to the I/I32 modules above, to make it easier to track - * down bugs. - *) + (* Bitwise operations on int64s. Note we try to keep it as similar as possible + to the I/I32 modules above, to make it easier to track down bugs. *) let ( <<< ) = Int64.shift_left let ( >>> ) = Int64.shift_right_logical let ( land ) = Int64.logand @@ -447,9 +433,8 @@ module I64 = struct v land mask = zero ;; - (* Call function g on the top bits, then f on each full byte - * (big endian - so start at top). - *) + (* Call function g on the top bits, then f on each full byte (big endian - so + start at top). *) let rec map_bytes_be g f v bits = if bits >= 8 then ( @@ -462,9 +447,8 @@ module I64 = struct g (to_int lsb) bits) ;; - (* Call function g on the top bits, then f on each full byte - * (little endian - so start at root). - *) + (* Call function g on the top bits, then f on each full byte (little endian - + so start at root). *) let rec map_bytes_le g f v bits = if bits >= 8 then ( @@ -479,15 +463,14 @@ module I64 = struct end (*----------------------------------------------------------------------*) + (* Extraction functions. - * - * NB: internal functions, called from the generated macros, and - * the parameters should have been checked for sanity already). - *) - -(* Extract and convert to numeric. A single bit is returned as - * a boolean. There are no endianness or signedness considerations. - *) + + NB: internal functions, called from the generated macros, and the parameters + should have been checked for sanity already). *) + +(* Extract and convert to numeric. A single bit is returned as a boolean. + There are no endianness or signedness considerations. *) let extract_bit data off len _ = (* final param is always 1 *) let byteoff = off lsr 3 in @@ -496,9 +479,8 @@ let extract_bit data off len _ = b (*, off+1, len-1*) ;; -(* Returns 8 bit unsigned aligned bytes from the string. - * If the string ends then this returns 0's. - *) +(* Returns 8 bit unsigned aligned bytes from the string. If the string ends then + this returns 0's. *) let _get_byte data byteoff strlen = if strlen > byteoff then Char.code (Bytes.get data byteoff) else 0 ;; @@ -511,8 +493,8 @@ let _get_byte64 data byteoff strlen = if strlen > byteoff then Int64.of_int (Char.code (Bytes.get data byteoff)) else 0L ;; -(* Extend signed [2..31] bits int to 31 bits int or 63 bits int for 64 - bits platform*) +(* Extend signed [2..31] bits int to 31 bits int or 63 bits int for 64 bits + platform. *) let extend_sign len v = let b = pred Sys.word_size - len in (v lsl b) asr b @@ -523,9 +505,8 @@ let extract_and_extend_sign f data off len flen = extend_sign flen w ;; -(* Extract [2..8] bits. Because the result fits into a single - * byte we don't have to worry about endianness, only signedness. - *) +(* Extract [2..8] bits. Because the result fits into a single byte we don't + have to worry about endianness, only signedness. *) let extract_char_unsigned data off len flen = let byteoff = off lsr 3 in (* Optimize the common (byte-aligned) case. *) @@ -534,9 +515,8 @@ let extract_char_unsigned data off len flen = let byte = Char.code (Bytes.get data byteoff) in byte lsr (8 - flen) (*, off+flen, len-flen*)) else ( - (* Extract the 16 bits at byteoff and byteoff+1 (note that the - * second byte might not exist in the original string). - *) + (* Extract the 16 bits at byteoff and byteoff+1 (note that the second byte + might not exist in the original string). *) let strlen = Bytes.length data in let word = (_get_byte data byteoff strlen lsl 8) + _get_byte data (byteoff + 1) strlen @@ -552,7 +532,7 @@ let extract_char_unsigned data off len flen = let extract_char_signed = extract_and_extend_sign extract_char_unsigned -(* Extract [9..31] bits. We have to consider endianness and signedness. *) +(* Extract [9..31] bits. We have to consider endianness and signedness. *) let extract_int_be_unsigned data off len flen = let byteoff = off lsr 3 in let strlen = Bytes.length data in @@ -642,7 +622,7 @@ let _make_int32_le c0 c1 c2 c3 = c0 ;; -(* Extract exactly 32 bits. We have to consider endianness and signedness. *) +(* Extract exactly 32 bits. We have to consider endianness and signedness. *) let extract_int32_be_unsigned data off len flen = let byteoff = off lsr 3 in let strlen = Bytes.length data in @@ -718,7 +698,7 @@ let _make_int64_be c0 c1 c2 c3 c4 c5 c6 c7 = let _make_int64_le c0 c1 c2 c3 c4 c5 c6 c7 = _make_int64_be c7 c6 c5 c4 c3 c2 c1 c0 -(* Extract [1..64] bits. We have to consider endianness and signedness. *) +(* Extract [1..64] bits. We have to consider endianness and signedness. *) let extract_int64_be_unsigned data off len flen = let byteoff = off lsr 3 in let strlen = Bytes.length data in @@ -834,15 +814,10 @@ external extract_fastpath_int16_ne_signed (* external extract_fastpath_int24_be_unsigned : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int24_be_unsigned" - external extract_fastpath_int24_le_unsigned : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int24_le_unsigned" - external extract_fastpath_int24_ne_unsigned : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int24_ne_unsigned" - external extract_fastpath_int24_be_signed : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int24_be_signed" - external extract_fastpath_int24_le_signed : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int24_le_signed" - external extract_fastpath_int24_ne_signed : bytes -> int -> int = "ocaml_bitstring_extract_fastpath_int24_ne_signed" *) @@ -884,39 +859,22 @@ external extract_fastpath_int32_ne_signed (* external extract_fastpath_int40_be_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int40_be_unsigned" - external extract_fastpath_int40_le_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int40_le_unsigned" - external extract_fastpath_int40_ne_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int40_ne_unsigned" - external extract_fastpath_int40_be_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int40_be_signed" - external extract_fastpath_int40_le_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int40_le_signed" - external extract_fastpath_int40_ne_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int40_ne_signed" - external extract_fastpath_int48_be_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int48_be_unsigned" - external extract_fastpath_int48_le_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int48_le_unsigned" - external extract_fastpath_int48_ne_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int48_ne_unsigned" - external extract_fastpath_int48_be_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int48_be_signed" - external extract_fastpath_int48_le_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int48_le_signed" - external extract_fastpath_int48_ne_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int48_ne_signed" - external extract_fastpath_int56_be_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int56_be_unsigned" - external extract_fastpath_int56_le_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int56_le_unsigned" - external extract_fastpath_int56_ne_unsigned : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int56_ne_unsigned" - external extract_fastpath_int56_be_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int56_be_signed" - external extract_fastpath_int56_le_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int56_le_signed" - external extract_fastpath_int56_ne_signed : bytes -> int -> int64 = "ocaml_bitstring_extract_fastpath_int56_ne_signed" *) @@ -957,15 +915,15 @@ external extract_fastpath_int64_ne_signed = "ocaml_bitstring_extract_fastpath_int64_ne_signed" (*----------------------------------------------------------------------*) + (* Constructor functions. *) module Buffer = struct type t = { buf : Buffer.t ; mutable len : int (* Length in bits. *) - ; (* Last byte in the buffer (if len is not aligned). We store - * it outside the buffer because buffers aren't mutable. - *) + ; (* Last byte in the buffer (if len is not aligned). We store it outside + the buffer because buffers aren't mutable. *) mutable last : int } @@ -995,7 +953,7 @@ module Buffer = struct (* Target buffer is byte-aligned. *) Buffer.add_char buf (Char.chr byte) else ( - (* Target buffer is unaligned. 'last' is meaningful. *) + (* Target buffer is unaligned. 'last' is meaningful. *) let first = byte lsr shift in let second = (byte lsl (8 - shift)) land 0xff in Buffer.add_char buf (Char.chr (last lor first)); @@ -1019,9 +977,8 @@ module Buffer = struct t.len <- len + 1 ;; - (* Add a small number of bits (definitely < 8). This uses a loop - * to call add_bit so it's slow. - *) + (* Add a small number of bits (definitely < 8). This uses a loop to call + add_bit so it's slow. *) let _add_bits t c slen = if slen < 1 || slen >= 8 then invalid_arg "Bitstring.Buffer._add_bits"; for i = slen - 1 downto 0 do @@ -1041,9 +998,8 @@ module Buffer = struct (* Common case - everything is byte-aligned. *) Buffer.add_subbytes buf str 0 (slen lsr 3) else ( - (* Target buffer is aligned. Copy whole bytes then leave the - * remaining bits in last. - *) + (* Target buffer is aligned. Copy whole bytes then leave the remaining + bits in last. *) let slenbytes = slen lsr 3 in if slenbytes > 0 then Buffer.add_subbytes buf str 0 slenbytes; let lastidx = min slenbytes (Bytes.length str - 1) in @@ -1053,12 +1009,11 @@ module Buffer = struct t.last <- last land mask); t.len <- len + slen) else ( - (* Target buffer is unaligned. Copy whole bytes using - * add_byte which knows how to deal with an unaligned - * target buffer, then call add_bit for the remaining < 8 bits. - * - * XXX This is going to be dog-slow. - *) + (* Target buffer is unaligned. Copy whole bytes using add_byte which + knows how to deal with an unaligned target buffer, then call add_bit + for the remaining < 8 bits. + + XXX This is going to be dog-slow. *) let slenbytes = slen lsr 3 in for i = 0 to slenbytes - 1 do let byte = Char.code (Bytes.get str i) in @@ -1186,9 +1141,8 @@ let construct_int64_ee_unsigned = function | NativeEndian -> construct_int64_ne_unsigned ;; -(* Construct from a string of bytes, exact multiple of 8 bits - * in length of course. - *) +(* Construct from a string of bytes, exact multiple of 8 bits in length of + course. *) let construct_string buf str = let len = String.length str in Buffer.add_bits buf (Bytes.unsafe_of_string str) (len lsl 3) @@ -1196,9 +1150,8 @@ let construct_string buf str = (* Construct from a bitstring. *) let construct_bitstring buf (data, off, len) = - (* Add individual bits until we get to the next byte boundary of - * the underlying string. - *) + (* Add individual bits until we get to the next byte boundary of the + underlying string. *) let blen = 7 - ((off + 7) land 7) in let blen = min blen len in let rec loop off len blen = @@ -1230,6 +1183,7 @@ let concat bs = ;; (*----------------------------------------------------------------------*) + (* Extract a string from a bitstring. *) let string_of_bitstring (data, off, len) = if off land 7 = 0 && len land 7 = 0 @@ -1258,7 +1212,6 @@ let string_of_bitstring (data, off, len) = ;; (* 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"; @@ -1284,14 +1237,14 @@ let bitstring_to_file bits filename = ;; (*----------------------------------------------------------------------*) + (* Comparison. *) let compare ((data1, off1, len1) as bs1) ((data2, off2, len2) as bs2) = (* In the fully-aligned case, this is reduced to string comparison ... *) if off1 land 7 = 0 && len1 land 7 = 0 && off2 land 7 = 0 && len2 land 7 = 0 then ( - (* ... but we have to do that by hand because the bits may - * not extend to the full length of the underlying string. - *) + (* ... but we have to do that by hand because the bits may not extend to the + full length of the underlying string. *) let off1 = off1 lsr 3 and off2 = off2 lsr 3 and len1 = len1 lsr 3 @@ -1376,6 +1329,7 @@ let is_prefix ((b1, o1, l1) as bs1) ((b2, o2, l2) as bs2) = ;; (*----------------------------------------------------------------------*) + (* Bit get/set functions. *) let index_out_of_bounds () = invalid_arg "index out of bounds" @@ -1410,6 +1364,7 @@ let is_set bits n = get bits n <> 0 let is_clear bits n = get bits n = 0 (*----------------------------------------------------------------------*) + (* Display functions. *) let isprint c = @@ -1458,6 +1413,7 @@ let hexdump_bitstring chan (data, off, len) = ;; (*----------------------------------------------------------------------*) + (* Alias of functions shadowed by Core. *) let char_code = Char.code diff --git a/src/bitstring.mli b/src/bitstring.mli index 395b658..c6165cf 100644 --- a/src/bitstring.mli +++ b/src/bitstring.mli @@ -1,24 +1,21 @@ -(* - * Bitstring library. - * - * Copyright (C) 2008-2016 Red Hat Inc., Richard W.M. Jones - * Copyright (C) 2016 Red Hat Inc, Richard W.M. Jones, Xavier R. Guerin. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version, - * with the OCaml linking exception described in COPYING.LIB. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *) +(* Bitstring library. + + Copyright (C) 2008-2016 Red Hat Inc., Richard W.M. Jones + Copyright (C) 2016 Red Hat Inc, Richard W.M. Jones, Xavier R. Guerin + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) any + later version, with the OCaml linking exception described in COPYING.LIB. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *) (** {{:#reference}Jump straight to the reference section for @@ -26,12 +23,12 @@ {2 Introduction} - Bitstring adds Erlang-style bitstrings and matching over bitstrings - as a syntax extension and library for OCaml. You can use - this module to both parse and generate binary formats, for - example, communications protocols, disk formats and binary files. + Bitstring adds Erlang-style bitstrings and matching over bitstrings as a + syntax extension and library for OCaml. You can use this module to both parse + and generate binary formats, for example, communications protocols, disk + formats and binary files. - {{:http://code.google.com/p/bitstring/}OCaml bitstring website} + {{:https://bitstring.software}OCaml bitstring website} This library used to be called "bitmatch". @@ -41,32 +38,38 @@ {[ let display pkt = - bitmatch pkt with + match%bitstring pkt with (* IPv4 packet header - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | 4 | IHL |Type of Service| Total Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Identification |Flags| Fragment Offset | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Time to Live | Protocol | Header Checksum | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Source Address | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Destination Address | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Options | Padding | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - *) - | { 4 : 4; hdrlen : 4; tos : 8; length : 16; - identification : 16; flags : 3; fragoffset : 13; - ttl : 8; protocol : 8; checksum : 16; - source : 32; - dest : 32; - options : (hdrlen-5)*32 : bitstring; - payload : -1 : bitstring } -> - + 0 1 2 3 + 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 4 | IHL |Type of Service| Total Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Identification |Flags| Fragment Offset | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Time to Live | Protocol | Header Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source Address | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Destination Address | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Options | Padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *) + | {| 4 : 4 + ; hdrlen : 4; tos : 8 + ; length : 16 + ; identification : 16 + ; flags : 3 + ; fragoffset : 13 + ; ttl : 8 + ; protocol : 8 + ; checksum : 16 + ; source : 32 + ; dest : 32 + ; options : (hdrlen-5)*32 : bitstring + ; payload : -1 : bitstring + |} + -> printf "IPv4:\n"; printf " header length: %d * 32 bit words\n" hdrlen; printf " type of service: %d\n" tos; @@ -82,168 +85,159 @@ let display pkt = Bitstring.hexdump_bitstring stdout options; printf " packet payload:\n"; Bitstring.hexdump_bitstring stdout payload - - | { version : 4 } -> + | {| version : 4 |} -> eprintf "unknown IP version %d\n" version; exit 1 - - | { _ } as pkt -> + | {| _ |} as pkt -> eprintf "data is smaller than one nibble:\n"; Bitstring.hexdump_bitstring stderr pkt; exit 1 ]} A program which can parse - {{:http://lxr.linux.no/linux/include/linux/ext3_fs.h}Linux EXT3 filesystem superblocks}: + {{:http://lxr.linux.no/linux/include/linux/ext3_fs.h}Linux EXT3 filesystem + superblocks}: {[ let bits = Bitstring.bitstring_of_file "tests/ext3_sb" let () = - bitmatch bits with - | { s_inodes_count : 32 : littleendian; (* Inodes count *) - s_blocks_count : 32 : littleendian; (* Blocks count *) - s_r_blocks_count : 32 : littleendian; (* Reserved blocks count *) - s_free_blocks_count : 32 : littleendian; (* Free blocks count *) - s_free_inodes_count : 32 : littleendian; (* Free inodes count *) - s_first_data_block : 32 : littleendian; (* First Data Block *) - s_log_block_size : 32 : littleendian; (* Block size *) - s_log_frag_size : 32 : littleendian; (* Fragment size *) - s_blocks_per_group : 32 : littleendian; (* # Blocks per group *) - s_frags_per_group : 32 : littleendian; (* # Fragments per group *) - s_inodes_per_group : 32 : littleendian; (* # Inodes per group *) - s_mtime : 32 : littleendian; (* Mount time *) - s_wtime : 32 : littleendian; (* Write time *) - s_mnt_count : 16 : littleendian; (* Mount count *) - s_max_mnt_count : 16 : littleendian; (* Maximal mount count *) - 0xef53 : 16 : littleendian } -> (* Magic signature *) - + match%bitstring bits with + | {| s_inodes_count : 32 : littleendian (* Inodes count *) + ; s_blocks_count : 32 : littleendian (* Blocks count *) + ; s_r_blocks_count : 32 : littleendian (* Reserved blocks count *) + ; s_free_blocks_count : 32 : littleendian (* Free blocks count *) + ; s_free_inodes_count : 32 : littleendian (* Free inodes count *) + ; s_first_data_block : 32 : littleendian (* First Data Block *) + ; s_log_block_size : 32 : littleendian (* Block size *) + ; s_log_frag_size : 32 : littleendian (* Fragment size *) + ; s_blocks_per_group : 32 : littleendian (* # Blocks per group *) + ; s_frags_per_group : 32 : littleendian (* # Fragments per group *) + ; s_inodes_per_group : 32 : littleendian (* # Inodes per group *) + ; s_mtime : 32 : littleendian (* Mount time *) + ; s_wtime : 32 : littleendian (* Write time *) + ; s_mnt_count : 16 : littleendian (* Mount count *) + ; s_max_mnt_count : 16 : littleendian (* Maximal mount count *) + ; 0xef53 : 16 : littleendian (* Magic signature *) + |} + -> printf "ext3 superblock:\n"; printf " s_inodes_count = %ld\n" s_inodes_count; printf " s_blocks_count = %ld\n" s_blocks_count; printf " s_free_inodes_count = %ld\n" s_free_inodes_count; printf " s_free_blocks_count = %ld\n" s_free_blocks_count - - | { _ } -> + | {| _ |} -> eprintf "not an ext3 superblock!\n%!"; exit 2 ]} - Constructing packets for a simple binary message - protocol: + Constructing packets for a simple binary message protocol: {[ -(* - +---------------+---------------+--------------------------+ - | type | subtype | parameter | - +---------------+---------------+--------------------------+ - <-- 16 bits --> <-- 16 bits --> <------- 32 bits --------> +(* +---------------+---------------+--------------------------+ + | type | subtype | parameter | + +---------------+---------------+--------------------------+ + <-- 16 bits --> <-- 16 bits --> <------- 32 bits --------> - All fields are in network byte order. -*) + All fields are in network byte order. *) let make_message typ subtype param = - (BITSTRING { - typ : 16; - subtype : 16; - param : 32 - }) ;; + [%bitstring + {| typ : 16 + ; subtype : 16 + ; param : 32 + |}] ;; ]} {2 Loading, creating bitstrings} - The basic data type is the {!bitstring}, a string of bits of - arbitrary length. Bitstrings can be any length in bits and - operations do not need to be byte-aligned (although they will - generally be more efficient if they are byte-aligned). + The basic data type is the {!bitstring}, a string of bits of arbitrary + length. Bitstrings can be any length in bits and operations do not need to + be byte-aligned (although they will generally be more efficient if they are + byte-aligned). - Internally a bitstring is stored as a normal OCaml [string] - together with an offset and length, where the offset and length are - measured in bits. Thus one can efficiently form substrings of - bitstrings, overlay a bitstring on existing data, and load and save - bitstrings from files or other external sources. + Internally a bitstring is stored as a normal OCaml [string] together with + an offset and length, where the offset and length are measured in bits. Thus + one can efficiently form substrings of bitstrings, overlay a bitstring on + existing data, and load and save bitstrings from files or other external + sources. To load a bitstring from a file use {!bitstring_of_file} or {!bitstring_of_chan}. - There are also functions to create bitstrings from arbitrary data. - See the {{:#reference}reference} below. + There are also functions to create bitstrings from arbitrary data. See the + {{:#reference}reference} below. {2 Matching bitstrings with patterns} - Use the [bitmatch] operator (part of the syntax extension) to break - apart a bitstring into its fields. [bitmatch] works a lot like the - OCaml [match] operator. + Use the [bitmatch] operator (part of the syntax extension) to break apart + a bitstring into its fields. [bitmatch] works a lot like the OCaml [match] + operator. The general form of [bitmatch] is: - [bitmatch] {i bitstring-expression} [with] + [match%bitstring] {i bitstring-expression} [with] - [| {] {i pattern} [} ->] {i code} + [| {|] {i pattern} [|} ->] {i code} - [| {] {i pattern} [} ->] {i code} + [| {|] {i pattern} [|} ->] {i code} [|] ... - As with normal match, the statement attempts to match the - bitstring against each pattern in turn. If none of the patterns - match then the standard library [Match_failure] exception is - thrown. + As with normal match, the statement attempts to match the bitstring against + each pattern in turn. If none of the patterns match then the standard library + [Match_failure] exception is thrown. - Patterns look a bit different from normal match patterns. They - consist of a list of bitfields separated by [;] where each bitfield - contains a bind variable, the width (in bits) of the field, and - other information. Some example patterns: + Patterns look a bit different from normal match patterns. They consist of + a list of bitfields separated by [;] where each bitfield contains a bind + variable, the width (in bits) of the field, and other information. Some + example patterns: {[ -bitmatch bits with +match%bitstring bits with -| { version : 8; name : 8; param : 8 } -> ... +| {| version : 8; name : 8; param : 8 |} -> ... - (* Bitstring of at least 3 bytes. First byte is the version - number, second byte is a field called name, third byte is - a field called parameter. *) + (* Bitstring of at least 3 bytes. First byte is the version number, second + byte is a field called name, third byte is a field called parameter. *) -| { flag : 1 } -> +| {| flag : 1 |} -> printf "flag is %b\n" flag (* A single flag bit (mapped into an OCaml boolean). *) -| { len : 4; data : 1+len } -> +| {| len : 4; data : 1+len |} -> printf "len = %d, data = 0x%Lx\n" len data - (* A 4-bit length, followed by 1-16 bits of data, where the - length of the data is computed from len. *) + (* A 4-bit length, followed by 1-16 bits of data, where the length of the + data is computed from len. *) -| { ipv6_source : 128 : bitstring; - ipv6_dest : 128 : bitstring } -> ... +| {| ipv6_source : 128 : bitstring ; ipv6_dest : 128 : bitstring |} -> ... - (* IPv6 source and destination addresses. Each is 128 bits - and is mapped into a bitstring type which will be a substring - of the main bitstring expression. *) + (* IPv6 source and destination addresses. Each is 128 bits and is mapped + into a bitstring type which will be a substring of the main bitstring + expression. *) ]} You can also add conditional when-clauses: {[ -| { version : 4 } +| {| version : 4 |} when version = 4 || version = 6 -> ... - (* Only match and run the code when version is 4 or 6. If - it isn't we will drop through to the next case. *) + (* Only match and run the code when version is 4 or 6. If it isn't we will + drop through to the next case. *) ]} - Note that the pattern is only compared against the first part of - the bitstring (there may be more data in the bitstring following - the pattern, which is not matched). In terms of regular - expressions you might say that the pattern matches [^pattern], not - [^pattern$]. To ensure that the bitstring contains only the - pattern, add a length -1 bitstring to the end and test that its - length is zero in the when-clause: + Note that the pattern is only compared against the first part of the + bitstring (there may be more data in the bitstring following the pattern, + which is not matched). In terms of regular expressions you might say that + the pattern matches [^pattern], not [^pattern$]. To ensure that the bitstring + contains only the pattern, add a length -1 bitstring to the end and test that + its length is zero in the when-clause: {[ -| { n : 4; - rest : -1 : bitstring } +| {| n : 4; rest : -1 : bitstring |} when Bitstring.bitstring_length rest = 0 -> ... (* Only matches exactly 4 bits. *) @@ -253,19 +247,18 @@ bitmatch bits with but you can also match a constant, as in: {[ -| { (4|6) : 4 } -> ... +| {| (4|6) : 4 |} -> ... - (* Only matches if the first 4 bits contain either - the integer 4 or the integer 6. *) + (* Only matches if the first 4 bits contain either the integer 4 or the + integer 6. *) ]} One may also match on strings: {[ -| { "MAGIC" : 5*8 : string } -> ... +| {| "MAGIC" : 5*8 : string |} -> ... - (* Only matches if the string "MAGIC" appears at the start - of the input. *) + (* Only matches if the string "MAGIC" appears at the start of the input. *) ]} {3:patternfieldreference Pattern field reference} @@ -274,28 +267,26 @@ bitmatch bits with [pattern : length [: qualifier [,qualifier ...]]] - [pattern] is the pattern, binding variable name, or constant to - match. [length] is the length in bits which may be either a - constant or an expression. The length expression is just an OCaml - expression and can use any values defined in the program, and refer - back to earlier fields (but not to later fields). + [pattern] is the pattern, binding variable name, or constant to match. + [length] is the length in bits which may be either a constant or an + expression. The length expression is just an OCaml expression and can use any + values defined in the program, and refer back to earlier fields (but not to + later fields). - Integers can only have lengths in the range \[1..64\] bits. See the - {{:#integertypes}integer types} section below for how these are - mapped to the OCaml int/int32/int64 types. This is checked - at compile time if the length expression is constant, otherwise it is - checked at runtime and you will get a runtime exception eg. in - the case of a computed length expression. + Integers can only have lengths in the range \[1..64\] bits. See the + {{:#integertypes}integer types} section below for how these are mapped to the + OCaml int/int32/int64 types. This is checked at compile time if the length + expression is constant, otherwise it is checked at runtime and you will get a + runtime exception eg. in the case of a computed length expression. - A bitstring field of length -1 matches all the rest of the - bitstring (thus this is only useful as the last field in a - pattern). + A bitstring field of length -1 matches all the rest of the bitstring (thus + this is only useful as the last field in a pattern). - A bitstring field of length 0 matches an empty bitstring - (occasionally useful when matching optional subfields). + A bitstring field of length 0 matches an empty bitstring (occasionally useful + when matching optional subfields). Qualifiers are a list of identifiers/expressions which control the type, - signedness and endianness of the field. Permissible qualifiers are: + signedness and endianness of the field. Permissible qualifiers are: - [int]: field has an integer type - [string]: field is a string type @@ -313,61 +304,61 @@ bitmatch bits with The default settings are [int], [unsigned], [bigendian], no offset. - Note that many of these qualifiers cannot be used together, - eg. bitstrings do not have endianness. The syntax extension should - give you a compile-time error if you use incompatible qualifiers. + Note that many of these qualifiers cannot be used together, eg. bitstrings + do not have endianness. The syntax extension should give you a compile-time + error if you use incompatible qualifiers. {3 Other cases in bitmatch} - As well as a list of fields, it is possible to name the - bitstring and/or have a default match case: + As well as a list of fields, it is possible to name the bitstring and/or have + a default match case: {[ -| { _ } -> ... +| {| _ |} -> ... (* Default match case. *) -| { _ } as pkt -> ... +| {| _ |} as pkt -> ... (* Default match case, with 'pkt' bound to the whole bitstring. *) ]} {2 Constructing bitstrings} - Bitstrings may be constructed using the [BITSTRING] operator (as an - expression). The [BITSTRING] operator takes a list of fields, - similar to the list of fields for matching: + Bitstrings may be constructed using the [%bitstring] operator (as an + expression). The [%bitstring] operator takes a list of fields, similar to the + list of fields for matching: {[ let version = 1 ;; let data = 10 ;; let bits = - BITSTRING { - version : 4; - data : 12 - } ;; + [%bitstring + {| version : 4 + ; data : 12 + |} ;; - (* Constructs a 16-bit bitstring with the first four bits containing - the integer 1, and the following 12 bits containing the integer 10, - arranged in network byte order. *) + (* Constructs a 16-bit bitstring with the first four bits containing the + integer 1, and the following 12 bits containing the integer 10, arranged + in network byte order. *) Bitstring.hexdump_bitstring stdout bits ;; (* Prints: - 00000000 10 0a |.. | + 00000000 10 0a |.. | *) ]} The format of each field is the same as for pattern fields (see - {{:#patternfieldreference}Pattern field reference section}), and - things like computed length fields, fixed value fields, insertion - of bitstrings within bitstrings, etc. are all supported. + {{:#patternfieldreference}Pattern field reference section}), and things like + computed length fields, fixed value fields, insertion of bitstrings within + bitstrings, etc. are all supported. {3 Construction exception} - The [BITSTRING] operator may throw a {!Construct_failure} - exception at runtime. + The [%bitstring] operator may throw a {!Construct_failure} exception at + runtime. Runtime errors include: @@ -380,115 +371,108 @@ Bitstring.hexdump_bitstring stdout bits ;; {2:integertypes Integer types} - Integer types are mapped to OCaml types [bool], [int], [int32] or - [int64] using a system which tries to ensure that (a) the types are - reasonably predictable and (b) the most efficient type is - preferred. + Integer types are mapped to OCaml types [bool], [int], [int32] or [int64] + using a system which tries to ensure that (a) the types are reasonably + predictable and (b) the most efficient type is preferred. - The rules are slightly different depending on whether the bit - length expression in the field is a compile-time constant or a - computed expression. + The rules are slightly different depending on whether the bit length + expression in the field is a compile-time constant or a computed expression. - Detection of compile-time constants is quite simplistic so only - simple integer literals and simple expressions (eg. [5*8]) are - recognized as constants. + Detection of compile-time constants is quite simplistic so only simple + integer literals and simple expressions (eg. [5*8]) are recognized as + constants. - In any case the bit size of an integer is limited to the range - \[1..64\]. This is detected as a compile-time error if that is - possible, otherwise a runtime check is added which can throw an - [Invalid_argument] exception. + In any case the bit size of an integer is limited to the range \[1..64\]. + This is detected as a compile-time error if that is possible, otherwise a + runtime check is added which can throw an [Invalid_argument] exception. The mapping is thus: {v - Bit size ---- OCaml type ---- - Constant Computed expression + Bit size ---- OCaml type ---- + Constant Computed expression - 1 bool int64 - 2..31 int int64 - 32 int32 int64 - 33..64 int64 int64 + 1 bool int64 + 2..31 int int64 + 32 int32 int64 + 33..64 int64 int64 v} - A possible future extension may allow people with 64 bit computers - to specify a more optimal [int] type for bit sizes in the range - [32..63]. If this was implemented then such code {i could not even - be compiled} on 32 bit platforms, so it would limit portability. + A possible future extension may allow people with 64 bit computers to + specify a more optimal [int] type for bit sizes in the range [32..63]. If + this was implemented then such code {i could not even be compiled} on 32 bit + platforms, so it would limit portability. - Another future extension may be to allow computed - expressions to assert min/max range for the bit size, - allowing a more efficient data type than int64 to be - used. (Of course under such circumstances there would - still need to be a runtime check to enforce the - size). + Another future extension may be to allow computed expressions to assert + min/max range for the bit size, allowing a more efficient data type than + int64 to be used. (Of course under such circumstances there would still need + to be a runtime check to enforce the size). {2 Advanced pattern-matching features} {3:computedoffsets Computed offsets} - You can add an [offset(..)] qualifier to bitmatch patterns in order - to move the current offset within the bitstring forwards. + You can add an [offset(..)] qualifier to bitmatch patterns in order to move + the current offset within the bitstring forwards. For example: {[ -bitmatch bits with -| { field1 : 8; - field2 : 8 : offset(160) } -> ... +match%bitstring bits with +| {| field1 : 8 + ; field2 : 8 : offset(160) + |} -> ... ]} - matches [field1] at the start of the bitstring and [field2] - at 160 bits into the bitstring. The middle 152 bits go - unmatched (ie. can be anything). + matches [field1] at the start of the bitstring and [field2] at 160 bits into + the bitstring. The middle 152 bits go unmatched (ie. can be anything). - The generated code is efficient. If field lengths and offsets - are known to be constant at compile time, then almost all - runtime checks are avoided. Non-constant field lengths and/or - non-constant offsets can result in more runtime checks being added. + The generated code is efficient. If field lengths and offsets are known to + be constant at compile time, then almost all runtime checks are avoided. + Non-constant field lengths and/or non-constant offsets can result in more + runtime checks being added. - Note that moving the offset backwards, and moving the offset in - [BITSTRING] constructors, are both not supported at present. + Note that moving the offset backwards, and moving the offset in [%bitstring] + constructors, are both not supported at present. {3 Check expressions} - You can add a [check(expr)] qualifier to bitmatch patterns. - If the expression evaluates to false then the current match case - fails to match (in other words, we fall through to the next - match case - there is no error). + You can add a [check(expr)] qualifier to bitmatch patterns. If the expression + evaluates to false then the current match case fails to match (in other + words, we fall through to the next match case - there is no error). For example: {[ -bitmatch bits with -| { field : 16 : check (field > 100) } -> ... +match%bitstring bits with +| {| field : 16 : check (field > 100) |} -> ... ]} - Note the difference between a check expression and a when-clause - is that the when-clause is evaluated after all the fields have - been matched. On the other hand a check expression is evaluated - after the individual field has been matched, which means it is - potentially more efficient (if the check expression fails then - we don't waste any time matching later fields). + Note the difference between a check expression and a when-clause is that + the when-clause is evaluated after all the fields have been matched. On the + other hand a check expression is evaluated after the individual field has + been matched, which means it is potentially more efficient (if the check + expression fails then we don't waste any time matching later fields). - We wanted to use the notation [when(expr)] here, but because - [when] is a reserved word we could not do this. + We wanted to use the notation [when(expr)] here, but because [when] is a + reserved word we could not do this. {3 Bind expressions} - A bind expression is used to change the value of a matched - field. For example: + A bind expression is used to change the value of a matched field. For + example: {[ -bitmatch bits with -| { len : 16 : bind (len * 8); - field : len : bitstring } -> ... +match%bitstring bits with +| {| len : 16 : bind (len * 8) + ; field : len : bitstring + |} -> ... ]} - In the example, after 'len' has been matched, its value would - be multiplied by 8, so the width of 'field' is the matched - value multiplied by 8. + In the example, after 'len' has been matched, its value would be multiplied + by 8, so the width of 'field' is the matched value multiplied by 8. In the general case: {[ -| { field : ... : bind (expr) } -> ... +| {| field : ... : bind (expr) |} -> ... ]} evaluates the following after the field has been matched: {[ @@ -498,133 +482,103 @@ bitmatch bits with {3 Order of evaluation of check() and bind()} - The choice is arbitrary, but we have chosen that check expressions - are evaluated first, and bind expressions are evaluated after. + The choice is arbitrary, but we have chosen that check expressions are + evaluated first, and bind expressions are evaluated after. - This means that the result of bind() is {i not} available in - the check expression. + This means that the result of bind() is {i not} available in the check + expression. - Note that this rule applies regardless of the order of check() - and bind() in the source code. + Note that this rule applies regardless of the order of check() and bind() in + the source code. {3 save_offset_to} - Use [save_offset_to(variable)] to save the current bit offset - within the match to a variable (strictly speaking, to a pattern). - This variable is then made available in any [check()] and [bind()] - clauses in the current field, {i and} to any later fields, and - to the code after the [->]. + Use [save_offset_to(variable)] to save the current bit offset within the + match to a variable (strictly speaking, to a pattern). This variable is then + made available in any [check()] and [bind()] clauses in the current field, {i + and} to any later fields, and to the code after the [->]. For example: {[ -bitmatch bits with -| { len : 16; - _ : len : bitstring; - field : 16 : save_offset_to (field_offset) } -> +match%bitstring bits with +| {| len : 16 + ; _ : len : bitstring + ; field : 16 : save_offset_to (field_offset) + |} -> printf "field is at bit offset %d in the match\n" field_offset ]} - (In that example, [field_offset] should always have the value - [len+16]). - - {2 Named patterns and persistent patterns} - - Please see {!Bitstring_persistent} for documentation on this subject. - - {2 Compiling} - - Using the compiler directly you can do: - - {v - ocamlc -I +bitstring \ - -pp "camlp4of bitstring.cma bitstring_persistent.cma \ - `ocamlc -where`/bitstring/pa_bitstring.cmo" \ - unix.cma bitstring.cma test.ml -o test - v} - - Simpler method using findlib: - - {v - ocamlfind ocamlc \ - -package bitstring,bitstring.syntax -syntax bitstring.syntax \ - -linkpkg test.ml -o test - v} + (In that example, [field_offset] should always have the value [len+16]). {2 Security and type safety} {3 Security on input} - The main concerns for input are buffer overflows and denial - of service. + The main concerns for input are buffer overflows and denial of service. It is believed that this library is robust against attempted buffer - overflows. In addition to OCaml's normal bounds checks, we check - that field lengths are >= 0, and many additional checks. + overflows. In addition to OCaml's normal bounds checks, we check that field + lengths are >= 0, and many additional checks. - Denial of service attacks are more problematic. We only work - forwards through the bitstring, thus computation will eventually - terminate. As for computed lengths, code such as this is thought - to be secure: + Denial of service attacks are more problematic. We only work forwards through + the bitstring, thus computation will eventually terminate. As for computed + lengths, code such as this is thought to be secure: {[ - bitmatch bits with - | { len : 64; - buffer : Int64.to_int len : bitstring } -> + match%bitstring bits with + | {| len : 64 + ; buffer : Int64.to_int len : bitstring + |} -> ]} - The [len] field can be set arbitrarily large by an attacker, but - when pattern-matching against the [buffer] field this merely causes - a test such as [if len <= remaining_size] to fail. Even if the - length is chosen so that [buffer] bitstring is allocated, the - allocation of sub-bitstrings is efficient and doesn't involve an - arbitary-sized allocation or any copying. + The [len] field can be set arbitrarily large by an attacker, but when + pattern-matching against the [buffer] field this merely causes a test such + as [if len <= remaining_size] to fail. Even if the length is chosen so + that [buffer] bitstring is allocated, the allocation of sub-bitstrings is + efficient and doesn't involve an arbitary-sized allocation or any copying. - However the above does not necessarily apply to strings used in - matching, since they may cause the library to use the - {!Bitstring.string_of_bitstring} function, which allocates a string. - So you should take care if you use the [string] type particularly - with a computed length that is derived from external input. + However the above does not necessarily apply to strings used in matching, + since they may cause the library to use the {!Bitstring.string_of_bitstring} + function, which allocates a string. So you should take care if you use + the [string] type particularly with a computed length that is derived from + external input. - The main protection against attackers should be to ensure that the - main program will only read input bitstrings up to a certain - length, which is outside the scope of this library. + The main protection against attackers should be to ensure that the main + program will only read input bitstrings up to a certain length, which is + outside the scope of this library. {3 Security on output} - As with the input side, computed lengths are believed to be - safe. For example: + As with the input side, computed lengths are believed to be safe. For + example: {[ let len = read_untrusted_source () in let buffer = allocate_bitstring () in - BITSTRING { - buffer : len : bitstring - } + [%bitstring + {| buffer : len : bitstring |}] ]} - This code merely causes a check that buffer's length is the same as - [len]. However the program function [allocate_bitstring] must - refuse to allocate an oversized buffer (but that is outside the - scope of this library). + This code merely causes a check that buffer's length is the same as [len]. + However the program function [allocate_bitstring] must refuse to allocate an + oversized buffer (but that is outside the scope of this library). {3 Order of evaluation} In [bitmatch] statements, fields are evaluated left to right. - Note that the when-clause is evaluated {i last}, so if you are - relying on the when-clause to filter cases then your code may do a - lot of extra and unncessary pattern-matching work on fields which - may never be needed just to evaluate the when-clause. Either - rearrange the code to do only the first part of the match, - followed by the when-clause, followed by a second inner bitmatch, - or use a [check()] qualifier within fields. + Note that the when-clause is evaluated {i last}, so if you are relying on + the when-clause to filter cases then your code may do a lot of extra and + unncessary pattern-matching work on fields which may never be needed just + to evaluate the when-clause. Either rearrange the code to do only the first + part of the match, followed by the when-clause, followed by a second inner + bitmatch, or use a [check()] qualifier within fields. {3 Safety} - The current implementation is believed to be fully type-safe, - and makes compile and run-time checks where appropriate. If - you find a case where a check is missing please submit a - bug report or a patch. + The current implementation is believed to be fully type-safe, and makes + compile and run-time checks where appropriate. If you find a case where a + check is missing please submit a bug report or a patch. {2 Limits} @@ -632,19 +586,17 @@ bitmatch bits with Integers: \[1..64\] bits. - Bitstrings (32 bit platforms): maximum length is limited - by the string size, ie. 16 MBytes. + Bitstrings (32 bit platforms): maximum length is limited by the string size, + ie. 16 MBytes. - Bitstrings (64 bit platforms): maximum length is thought to be - limited by the string size, ie. effectively unlimited. + Bitstrings (64 bit platforms): maximum length is thought to be limited by the + string size, ie. effectively unlimited. - Bitstrings must be loaded into memory before we can match against - them. Thus available memory may be considered a limit for some - applications. + Bitstrings must be loaded into memory before we can match against them. Thus + available memory may be considered a limit for some applications. {2:reference Reference} - {3 Types} -*) + {3 Types} *) type endian = | BigEndian @@ -656,59 +608,53 @@ val string_of_endian : endian -> string (** [bitstring] is the basic type used to store bitstrings. - The type contains the underlying data (a bytes), - the current bit offset within the string and the - current bit length of the string (counting from the - bit offset). Note that the offset and length are - in {b bits}, not bytes. + The type contains the underlying data (a bytes), the current bit offset + within the string and the current bit length of the string (counting from + the bit offset). Note that the offset and length are in {b bits}, not bytes. - Normally you don't need to use the bitstring type - directly, since there are functions and syntax - extensions which hide the details. + Normally you don't need to use the bitstring type directly, since there are + functions and syntax extensions which hide the details. - See also {!bitstring_of_string}, {!bitstring_of_file}, - {!hexdump_bitstring}, {!bitstring_length}. -*) + See also {!bitstring_of_string}, {!bitstring_of_file}, {!hexdump_bitstring}, + {!bitstring_length}. *) type bitstring = bytes * int * int (** [t] is a synonym for the {!bitstring} type. - This allows you to use this module with functors like - [Set] and [Map] from the stdlib. *) + This allows you to use this module with functors like [Set] and [Map] from + the stdlib. *) type t = bitstring (** {3 Exceptions} *) -(** [Construct_failure (message, file, line, char)] may be - raised by the [BITSTRING] constructor. +(** [Construct_failure (message, file, line, char)] may be raised by the + [%bitstring] constructor. - Common reasons are that values are out of range of - the fields that contain them, or that computed lengths - are impossible (eg. negative length bitfields). + Common reasons are that values are out of range of the fields that + contain them, or that computed lengths are impossible (eg. negative length + bitfields). [message] is the error message. - [file], [line] and [char] point to the original source - location of the [BITSTRING] constructor that failed. -*) + [file], [line] and [char] point to the original source location of the + [%bitstring] constructor that failed. *) exception Construct_failure of string * string * int * int (** {3 Bitstring comparison} *) -(** [compare bs1 bs2] compares two bitstrings and returns zero - if they are equal, a negative number if [bs1 < bs2], or a - positive number if [bs1 > bs2]. +(** [compare bs1 bs2] compares two bitstrings and returns zero if they are + equal, a negative number if [bs1 < bs2], or a positive number if [bs1 + > bs2]. - This tests "semantic equality" which is not affected by - the offset or alignment of the underlying representation - (see {!bitstring}). + This tests "semantic equality" which is not affected by the offset or + alignment of the underlying representation (see {!bitstring}). The ordering is total and lexicographic. *) val compare : bitstring -> bitstring -> int -(** [equals] returns true if and only if the two bitstrings are - semantically equal. It is the same as calling [compare] and - testing if the result is [0], but usually more efficient. *) +(** [equals] returns true if and only if the two bitstrings are semantically + equal. It is the same as calling [compare] and testing if the result is [0], + but usually more efficient. *) val equals : bitstring -> bitstring -> bool (** Tests if the bitstring is all zero bits (cf. {!zeroes_bitstring}) *) @@ -722,45 +668,42 @@ val is_prefix : bitstring -> bitstring -> bool (** {3 Bitstring manipulation} *) -(** [bitstring_length bitstring] returns the length of - the bitstring in bits. +(** [bitstring_length bitstring] returns the length of the bitstring in bits. Note this just returns the third field in the {!bitstring} tuple. *) val bitstring_length : bitstring -> int -(** [subbitstring bits off len] returns a sub-bitstring - of the bitstring, starting at offset [off] bits and - with length [len] bits. +(** [subbitstring bits off len] returns a sub-bitstring of the bitstring, + starting at offset [off] bits and with length [len] bits. - If the original bitstring is not long enough to do this - then the function raises [Invalid_argument "subbitstring"]. + If the original bitstring is not long enough to do this then the function + raises [Invalid_argument "subbitstring"]. - Note that this function just changes the offset and length - fields of the {!bitstring} tuple, so is very efficient. *) + Note that this function just changes the offset and length fields of the + {!bitstring} tuple, so is very efficient. *) val subbitstring : bitstring -> int -> int -> bitstring -(** Drop the first n bits of the bitstring and return a new - bitstring which is shorter by n bits. +(** Drop the first n bits of the bitstring and return a new bitstring which is + shorter by n bits. - If the length of the original bitstring is less than n bits, - this raises [Invalid_argument "dropbits"]. + If the length of the original bitstring is less than n bits, this raises + [Invalid_argument "dropbits"]. - Note that this function just changes the offset and length - fields of the {!bitstring} tuple, so is very efficient. *) + Note that this function just changes the offset and length fields of the + {!bitstring} tuple, so is very efficient. *) val dropbits : int -> bitstring -> bitstring -(** Take the first n bits of the bitstring and return a new - bitstring which is exactly n bits long. +(** Take the first n bits of the bitstring and return a new bitstring which is + exactly n bits long. - If the length of the original bitstring is less than n bits, - this raises [Invalid_argument "takebits"]. + If the length of the original bitstring is less than n bits, this raises + [Invalid_argument "takebits"]. - Note that this function just changes the offset and length - fields of the {!bitstring} tuple, so is very efficient. *) + Note that this function just changes the offset and length fields of the + {!bitstring} tuple, so is very efficient. *) val takebits : int -> bitstring -> bitstring -(** Concatenate a list of bitstrings together into a single - bitstring. *) +(** Concatenate a list of bitstrings together into a single bitstring. *) val concat : bitstring list -> bitstring (** {3 Constructing bitstrings} *) @@ -772,14 +715,14 @@ val empty_bitstring : bitstring containing all zeroes. *) val create_bitstring : int -> bitstring -(** [make_bitstring n c] creates an [n] bit bitstring - containing the repeated 8 bit pattern in [c]. +(** [make_bitstring n c] creates an [n] bit bitstring containing the repeated 8 + bit pattern in [c]. - For example, [make_bitstring 16 '\x5a'] will create - the bitstring [0x5a5a] or in binary [0101 1010 0101 1010]. + For example, [make_bitstring 16 '\x5a'] will create the bitstring [0x5a5a] + or in binary [0101 1010 0101 1010]. - Note that the length is in bits, not bytes. The length does NOT - need to be a multiple of 8. *) + Note that the length is in bits, not bytes. The length does NOT need to be a + multiple of 8. *) val make_bitstring : int -> char -> bitstring (** [zeroes_bitstring] creates an [n] bit bitstring of all 0's. @@ -790,98 +733,92 @@ val zeroes_bitstring : int -> bitstring (** [ones_bitstring] creates an [n] bit bitstring of all 1's. *) val ones_bitstring : int -> bitstring -(** [bitstring_of_string str] creates a bitstring - of length [String.length str * 8] (bits) containing the - bits in [str]. +(** [bitstring_of_string str] creates a bitstring of length [String.length str * + 8] (bits) containing the bits in [str]. - Note that the bitstring uses [str] as the underlying - string (see the representation of {!bitstring}) so you - should not change [str] after calling this. *) + Note that the bitstring uses [str] as the underlying string (see the + representation of {!bitstring}) so you should not change [str] after calling + this. *) val bitstring_of_string : string -> bitstring (** [bitstring_of_file filename] loads the named file into a bitstring. *) val bitstring_of_file : string -> bitstring -(** [bitstring_of_chan chan] loads the contents of - the input channel [chan] as a bitstring. +(** [bitstring_of_chan chan] loads the contents of the input channel [chan] as + a bitstring. - The length of the final bitstring is determined - by the remaining input in [chan], but will always - be a multiple of 8 bits. + The length of the final bitstring is determined by the remaining input in + [chan], but will always be a multiple of 8 bits. See also {!bitstring_of_chan_max}. *) val bitstring_of_chan : in_channel -> bitstring -(** [bitstring_of_chan_max chan max] works like - {!bitstring_of_chan} but will only read up to - [max] bytes from the channel (or fewer if the end of input +(** [bitstring_of_chan_max chan max] works like {!bitstring_of_chan} but will + only read up to [max] bytes from the channel (or fewer if the end of input occurs before that). *) val bitstring_of_chan_max : in_channel -> int -> bitstring -(** [bitstring_of_file_descr fd] loads the contents of - the file descriptor [fd] as a bitstring. +(** [bitstring_of_file_descr fd] loads the contents of the file descriptor [fd] + as a bitstring. See also {!bitstring_of_chan}, {!bitstring_of_file_descr_max}. *) val bitstring_of_file_descr : Unix.file_descr -> bitstring -(** [bitstring_of_file_descr_max fd max] works like - {!bitstring_of_file_descr} but will only read up to - [max] bytes from the channel (or fewer if the end of input - occurs before that). *) +(** [bitstring_of_file_descr_max fd max] works like {!bitstring_of_file_descr} + but will only read up to [max] bytes from the channel (or fewer if the end + of input occurs before that). *) val bitstring_of_file_descr_max : Unix.file_descr -> int -> bitstring (** {3 Converting bitstrings} *) -(** [string_of_bitstring bitstring] converts a bitstring to a string - (eg. to allow comparison). +(** [string_of_bitstring bitstring] converts a bitstring to a string (eg. to + allow comparison). - 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. + 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. - 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. *) + 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 string_of_bitstring : bitstring -> string -(** [bitstring_to_file bits filename] writes the bitstring [bits] - to the file [filename]. It overwrites the output file. +(** [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_file : bitstring -> string -> unit -(** [bitstring_to_file bits filename] writes the bitstring [bits] - to the channel [chan]. +(** [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"]). + 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}. + 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. + 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. *) val bitstring_to_chan : bitstring -> out_channel -> unit (** {3 Printing bitstrings} *) -(** [hexdump_bitstring chan bitstring] prints the bitstring - to the output channel in a format similar to the - Unix command [hexdump -C]. *) +(** [hexdump_bitstring chan bitstring] prints the bitstring to the output + channel in a format similar to the Unix command [hexdump -C]. *) val hexdump_bitstring : out_channel -> bitstring -> unit (** {3 Bitstring buffer} *) -(** Buffers are mainly used by the [BITSTRING] constructor, but - may also be useful for end users. They work much like the - standard library [Buffer] module. *) +(** Buffers are mainly used by the [%bitstring] constructor, but may also be + useful for end users. They work much like the standard library [Buffer] + module. *) module Buffer : sig type t @@ -894,14 +831,12 @@ end (** {3 Get/set bits} - These functions let you manipulate individual bits in the - bitstring. However they are not particularly efficient and you - should generally use the [bitmatch] and [BITSTRING] operators when - building and parsing bitstrings. + These functions let you manipulate individual bits in the bitstring. + However they are not particularly efficient and you should generally use the + [bitmatch] and [%bitstring] operators when building and parsing bitstrings. - These functions all raise [Invalid_argument "index out of bounds"] - if the index is out of range of the bitstring. -*) + These functions all raise [Invalid_argument "index out of bounds"] if the + index is out of range of the bitstring. *) (** [set bits n] sets the [n]th bit in the bitstring to 1. *) val set : bitstring -> int -> unit @@ -924,17 +859,15 @@ val get : bitstring -> int -> int (** {3 Miscellaneous} *) -(** Set this variable to true to enable extended debugging. - This only works if debugging was also enabled in the - [pa_bitstring.ml] file at compile time, otherwise it - does nothing. *) +(** Set this variable to true to enable extended debugging. This only works if + debugging was also enabled in the [pa_bitstring.ml] file at compile time, + otherwise it does nothing. *) val debug : bool ref (**/**) -(* Private functions, called from generated code. Do not use - * these directly - they are not safe. - *) +(* Private functions, called from generated code. Do not use these directly - + they are not safe. *) (* 'extract' functions are used in bitmatch statements. *) @@ -1118,7 +1051,7 @@ external extract_fastpath_int64_ne_signed -> int64 = "ocaml_bitstring_extract_fastpath_int64_ne_signed" -(* 'construct' functions are used in BITSTRING constructors. *) +(* 'construct' functions are used in [%bitstring] constructors. *) val construct_bit : Buffer.t -> bool -> int -> exn -> unit val construct_char_unsigned : Buffer.t -> int -> int -> exn -> unit val construct_char_signed : Buffer.t -> int -> int -> exn -> unit diff --git a/src/bitstring_config.ml b/src/bitstring_config.ml index 0fa18d2..f9ada38 100644 --- a/src/bitstring_config.ml +++ b/src/bitstring_config.ml @@ -1,28 +1,23 @@ -(* - * Bitstring library. - * - * Copyright (C) 2008-2016 Red Hat Inc., Richard W.M. Jones - * Copyright (C) 2016 Red Hat Inc, Richard W.M. Jones, Xavier R. Guerin. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version, - * with the OCaml linking exception described in COPYING.LIB. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *) +(* Bitstring library. + + Copyright (C) 2008-2016 Red Hat Inc., Richard W.M. Jones + Copyright (C) 2016 Red Hat Inc, Richard W.M. Jones, Xavier R. Guerin + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) any + later version, with the OCaml linking exception described in COPYING.LIB. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *) -(* This file contains general configuration settings, set by the - * configure script. - *) +(* This file contains configuration settings, set by the configure script. *) let nativeendian = if Sys.big_endian then Bitstring_types.BigEndian else Bitstring_types.LittleEndian diff --git a/src/bitstring_types.ml b/src/bitstring_types.ml index 9613465..8431d37 100644 --- a/src/bitstring_types.ml +++ b/src/bitstring_types.ml @@ -1,25 +1,21 @@ -(* - * Bitstring library. - * - * Copyright (C) 2008-2016 Red Hat Inc., Richard W.M. Jones - * Copyright (C) 2016 Red Hat Inc, Richard W.M. Jones, Xavier R. Guerin. +(* Bitstring library. + + Copyright (C) 2008-2016 Red Hat Inc., Richard W.M. Jones + Copyright (C) 2016 Red Hat Inc, Richard W.M. Jones, Xavier R. Guerin - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version, - * with the OCaml linking exception described in COPYING.LIB. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - *) + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) any + later version, with the OCaml linking exception described in COPYING.LIB. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *) type endian = | BigEndian diff --git a/tests/BitstringConstructorTest.ml b/tests/BitstringConstructorTest.ml index e3f1bbe..9d5322e 100644 --- a/tests/BitstringConstructorTest.ml +++ b/tests/BitstringConstructorTest.ml @@ -1,25 +1,21 @@ -(* - * Copyright (c) 2016 Xavier R. Guérin - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - *) +(* Copyright (c) 2016 Xavier R. Guérin + + Permission to use, copy, modify, and distribute this software for any purpose + with or without fee is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. *) open OUnit2 open Bitstring -(* - * Imbricated bitstring test - *) +(* Imbricated bitstring test *) let imbricated_bistring_test context = let result = "\xde\xad\xbe\xef\x42\x0a" in @@ -38,9 +34,7 @@ let imbricated_bistring_test context = assert_equal result dump ;; -(* - * Constructor style test - *) +(* Constructor style test *) let constructor_style_test context = let%bitstring bits1 = @@ -71,9 +65,7 @@ let constructor_style_test context = assert_bool "Bistrings are not equal" (Bitstring.equals bits1 bits2) ;; -(* - * Swap test - *) +(* Swap test *) let swap bs = match%bitstring bs with @@ -91,9 +83,7 @@ let swap_test context = assert_bool "Bitstring swap failed" (Bitstring.equals three (swap three)) ;; -(* - * External value test - *) +(* External value test *) let external_value_test context = let result = "\x00\x02\x00\x00\x00\x01\xC0" in @@ -113,9 +103,7 @@ let external_value_test context = assert_equal str result ;; -(* - * Int for [17,31] bits test - *) +(* Int for [17,31] bits test *) let int_parser_test context = let result = "\x00\x00\x02" in @@ -124,9 +112,7 @@ let int_parser_test context = assert_equal str result ;; -(* - * Int32 for 32 bits test - *) +(* Int32 for 32 bits test *) let int32_parser_test context = let result = "\x00\x00\x00\x02" in @@ -135,9 +121,7 @@ let int32_parser_test context = assert_equal str result ;; -(* - * Structural let - *) +(* Structural let *) let%bitstring ext_bits = {| 2_l : 32 |} @@ -147,9 +131,7 @@ let str_item_test context = assert_equal str result ;; -(* - * Subtyping. - *) +(* Subtyping. *) let subtype_test context = let x = 42 in @@ -158,9 +140,7 @@ let subtype_test context = assert (Bitstring.equals b c) ;; -(* - * Test suite definition - *) +(* Test suite definition *) let suite = "BitstringConstructorTest" diff --git a/tests/BitstringLegacyTest.ml b/tests/BitstringLegacyTest.ml index 0529d92..b53e63c 100644 --- a/tests/BitstringLegacyTest.ml +++ b/tests/BitstringLegacyTest.ml @@ -1,48 +1,36 @@ open OUnit2 open Printf -(* - * Helper functions - *) +(* Helper functions *) let rec range a b = if a <= b then a :: range (a + 1) b else [] -(* - * Just check that the extension and library load without error. - *) +(* Just check that the extension and library load without error. *) let load_test _ = let _ = Bitstring.extract_bit in () ;; -(* - * Just check that we can run some functions from the library. - *) +(* Just check that we can run some functions from the library. *) let run_test _ = let bits = Bitstring.create_bitstring 16 in ignore (Bitstring.string_of_bitstring bits) ;; -(* - * Match random bits. - *) +(* Match random bits. *) let match_random_bits_test _ = Random.self_init (); for len = 0 to 999 do - (* - * Create a random string of bits. - *) + (* Create a random string of bits. *) let expected = List.map (fun _ -> Random.bool ()) (range 0 (len - 1)) in let bits = Bitstring.Buffer.create () in List.iter (Bitstring.Buffer.add_bit bits) expected; let bits = Bitstring.Buffer.contents bits in - (* - * Now read the bitstring in groups of 1, 2, 3 .. etc. bits. In each case - * check the result against what we generated ('expected'). - *) + (* Now read the bitstring in groups of 1, 2, 3 .. etc. bits. In each case + check the result against what we generated ('expected'). *) let actual = let rec loop bits = match%bitstring bits with @@ -107,17 +95,13 @@ let match_random_bits_test _ = done ;; -(* - * Match random bits with integers. - *) +(* Match random bits with integers. *) let match_random_bits_with_int_test _ = Random.self_init (); for len = 1 to 99 do for bitlen = 1 to 63 do - (* - * Create a random string of ints. - *) + (* Create a random string of ints. *) let expected = List.map (fun _ -> Random.int64 (Int64.sub (Int64.shift_left 1L bitlen) 1L)) @@ -133,10 +117,8 @@ let match_random_bits_with_int_test _ = (Failure "constructing string")) expected; let bits = Bitstring.Buffer.contents bits in - (* - * Now read the bitstring as integers. - * In each case check the result against what we generated ('expected'). - *) + (* Now read the bitstring as integers. In each case check the result + against what we generated ('expected'). *) let actual = let rec loop bits = match%bitstring bits with @@ -153,9 +135,7 @@ let match_random_bits_with_int_test _ = done ;; -(* - * Check value limits. - *) +(* Check value limits. *) let check_value_limits_test _ = let a = Array.init 387 (fun i -> i - 129) in @@ -184,9 +164,7 @@ let check_value_limits_test _ = [ -2, 3; -4, 7; -8, 15; -16, 31; -32, 63; -64, 127; -128, 255 ] ;; -(* - * Signed byte create. - *) +(* Signed byte create. *) let signed_byte_create_test _ = let a n = @@ -217,9 +195,7 @@ let signed_byte_create_test _ = assert_equal ok true ;; -(* - * Signed byte create and match - *) +(* Signed byte create and match *) let signed_byte_create_and_match_test _ = let a n = @@ -265,9 +241,7 @@ let signed_byte_create_and_match_test _ = assert_equal ok true ;; -(* - * Signed int limits - *) +(* Signed int limits *) let signed_int_limits_test _ = Random.self_init (); @@ -445,10 +419,8 @@ let signed_int_limits_test _ = | _ -> ()) ;; -(* - * Test functions which construct and extract fixed-length ints of various - * sizes. Manquent les tests random pour bits = 31 - *) +(* Test functions which construct and extract fixed-length ints of various + sizes. Manquent les tests random pour bits = 31 *) let fixed_extraction_test _ = for i = 0 to 129 do @@ -623,9 +595,7 @@ let extract_regression_test _ = assert (i3 = 3_L) ;; -(* - * Construct and match against random variable sized strings. - *) +(* Construct and match against random variable sized strings. *) let nr_passes = 10000 let max_size = 8 (* max field size in bits *) @@ -724,10 +694,8 @@ let construct_and_match_random_test _ = done ;; -(* - * Test the Bitstring.Buffer module and string_of_bitstring in nasty non-aligned - * corner cases. - *) +(* Test the Bitstring.Buffer module and string_of_bitstring in nasty non-aligned + corner cases. *) let nasty_non_aligned_corner_case_test _ = Random.self_init (); @@ -746,12 +714,11 @@ let nasty_non_aligned_corner_case_test _ = expected in (* Create a random bitstring: - * +-------------+-------------------------------------------+ - * | (random) | bits that we check (expected) | - * +-------------+-------------------------------------------+ - * 0 offset offset+len - * <---------------- len bits ---------------> - *) + +-------------+-------------------------------------------+ + | (random) | bits that we check (expected) | + +-------------+-------------------------------------------+ + 0 offset offset+len + <---------------- len bits ---------------> *) let bits = let bits = Bitstring.Buffer.create () in Bitstring.Buffer.add_bits bits str1 offset; @@ -786,9 +753,7 @@ let nasty_non_aligned_corner_case_test _ = done ;; -(* - * Test concat and the bit get functions. - *) +(* Test concat and the bit get functions. *) let concat_bit_get_test _ = for i = 0 to 33 do @@ -816,9 +781,7 @@ let concat_bit_get_test _ = done ;; -(* - * Compare bitstrings. - *) +(* Compare bitstrings. *) let sgn = function | 0 -> 0 @@ -896,9 +859,7 @@ let subbitstring_test _ = done ;; -(* - * Test takebits call. - *) +(* Test takebits call. *) let takebits_test _ = let bits = Bitstring.make_bitstring 65 '\x5a' in @@ -908,9 +869,7 @@ let takebits_test _ = done ;; -(* - * Test the various functions to load bitstrings from files. - *) +(* Test the various functions to load bitstrings from files. *) let file_load_test _ = let bits1 = @@ -960,9 +919,7 @@ let file_load_test _ = Unix.unlink filename ;; -(* - * Test if bitstrings are all zeroes or all ones. - *) +(* Test if bitstrings are all zeroes or all ones. *) let zeroes_ones_test _ = for i = 0 to 33 do @@ -989,9 +946,7 @@ let zeroes_ones_test _ = done ;; -(* - * Endianness expressions - *) +(* Endianness expressions *) let endianness_test _ = let rec loop = function @@ -1026,22 +981,19 @@ let endianness_test _ = ] ;; -(* - * Simple offset test - *) +(* Simple offset test *) let simple_offset_test _ = let make_bits i n j m k = let pad1 = Bitstring.ones_bitstring (n - 8) in let pad2 = Bitstring.ones_bitstring (m - n - 8) in [%bitstring - {| - i : 8; - pad1 : n-8 : bitstring; - j : 8; (* this should be at offset(n) *) - pad2 : m-n-8 : bitstring; - k : 8 (* this should be at offset(m) *) - |}] + {| i : 8 + ; pad1 : n-8 : bitstring + ; j : 8 (* this should be at offset(n) *) + ; pad2 : m-n-8 : bitstring + ; k : 8 (* this should be at offset(m) *) + |}] in let test_bits bits i n j m k = match%bitstring bits with @@ -1061,22 +1013,19 @@ let simple_offset_test _ = done ;; -(* - * Offset string. The rotation functions used for strings are - * very complicated so this is worth testing separately. - *) +(* Offset string. The rotation functions used for strings are very complicated + so this is worth testing separately. *) let offset_string_test _ = let make_bits si n sj m sk = let pad1 = Bitstring.ones_bitstring (n - 64) in let pad2 = Bitstring.ones_bitstring (m - n - 8) in [%bitstring - {| - si : 64 : string; - pad1 : n-64 : bitstring; - sj : 8 : string; (* this should be at offset(n) *) - pad2 : m-n-8 : bitstring; - sk : 64 : string (* this should be at offset(m) *) + {| si : 64 : string + ; pad1 : n-64 : bitstring + ; sj : 8 : string (* this should be at offset(n) *) + ; pad2 : m-n-8 : bitstring + ; sk : 64 : string (* this should be at offset(m) *) |}] in let test_bits bits si n sj m sk = @@ -1100,9 +1049,7 @@ let offset_string_test _ = done ;; -(* - * Test computed offsets when original_off <> 0. - *) +(* Test computed offsets when original_off <> 0. *) let computed_offset_test _ = let make_bits p i n j m k = @@ -1110,30 +1057,27 @@ let computed_offset_test _ = let pad1 = Bitstring.ones_bitstring (n - 8) in let pad2 = Bitstring.ones_bitstring (m - n - 8) in [%bitstring - {| - pad0 : p : bitstring; (* will be skipped below *) - i : 8; - pad1 : n-8 : bitstring; - j : 8; (* this should be at offset(n) *) - pad2 : m-n-8 : bitstring; - k : 8 (* this should be at offset(m) *) - |}] + {| pad0 : p : bitstring (* will be skipped below *) + ; i : 8 + ; pad1 : n-8 : bitstring + ; j : 8 (* this should be at offset(n) *) + ; pad2 : m-n-8 : bitstring + ; k : 8 (* this should be at offset(m) *) + |}] in let test_bits bits p i n j m k = - (* - * Skip the 'p' padding bits so the match starts at a non-zero offset. - *) + (* Skip the 'p' padding bits so the match starts at a non-zero offset. *) let bits = Bitstring.dropbits p bits in match%bitstring bits with - | {| i' : 8; - j' : 8 : offset(n); - k' : 8 : offset(m) - |} + | {| i' : 8 + ; j' : 8 : offset(n) + ; k' : 8 : offset(m) + |} when i = i' && j = j' && k = k' -> () (* ok *) - | {| i' : 8; - j' : 8 : offset(n); - k' : 8 : offset(m) - |} + | {| i' : 8 + ; j' : 8 : offset(n) + ; k' : 8 : offset(m) + |} -> Printf.printf "\n%d %d %d\n" p n m; Bitstring.hexdump_bitstring stdout bits; @@ -1156,9 +1100,7 @@ let computed_offset_test _ = done ;; -(* - * Test save_offset_to. - *) +(* Test save_offset_to. *) let save_offset_to_test _ = let make_bits p i n j m k = @@ -1166,13 +1108,12 @@ let save_offset_to_test _ = let pad1 = Bitstring.ones_bitstring (n - 8) in let pad2 = Bitstring.ones_bitstring (m - n - 8) in [%bitstring - {| - pad0 : p : bitstring; (* will be skipped below *) - i : 8; - pad1 : n-8 : bitstring; - j : 8; (* this should be at offset(n) *) - pad2 : m-n-8 : bitstring; - k : 8 (* this should be at offset(m) *) + {| pad0 : p : bitstring (* will be skipped below *) + ; i : 8 + ; pad1 : n-8 : bitstring + ; j : 8 (* this should be at offset(n) *) + ; pad2 : m-n-8 : bitstring + ; k : 8 (* this should be at offset(m) *) |}] in let test_bits bits p i n j m k = @@ -1200,9 +1141,7 @@ let save_offset_to_test _ = done ;; -(* - * Test check() and bind(). - *) +(* Test check() and bind(). *) let check_bind_test _ = let%bitstring bits = {| 101 : 16; 202 : 16 |} in @@ -1214,9 +1153,7 @@ let check_bind_test _ = | {| _ |} -> failwith "70_check_and_bind: match failed" ;; -(* - * Test hexdump. - *) +(* Test hexdump. *) let () = let diff = "diff" in @@ -1237,17 +1174,13 @@ let () = let n = String.sub filename 3 (String.length filename - 3) in let n = int_of_string n in let bits = Bitstring.bitstring_of_file ("../../../tests/data/" ^ filename) in - (* - * 'bitstring_of_file' loads whole bytes. Truncate it to - * the real bit-length. - *) + (* 'bitstring_of_file' loads whole bytes. Truncate it to the real + bit-length. *) let bits = Bitstring.takebits n bits in filename, n, bits) files in - (* - * Hexdump the bits, then compare using external 'diff' program. - *) + (* Hexdump the bits, then compare using external 'diff' program. *) List.iter (fun (filename, n, bits) -> let output_filename = sprintf "../../../tests/data/hex%d.actual" n in @@ -1270,10 +1203,7 @@ let () = files ;; -(* - * Regression test for bug in 'as-binding' found by Matej Kosik. - * $Id$ - *) +(* Regression test for bug in 'as-binding' found by Matej Kosik. *) let as_binding_bug_test _ = let bits = Bitstring.ones_bitstring 1 in @@ -1288,9 +1218,7 @@ let as_binding_bug_test _ = | {| _ |} -> assert false ;; -(* - * Regression test for bug in concatenation found by Phil Tomson. - *) +(* Regression test for bug in concatenation found by Phil Tomson. *) let concat_regression_test _ = let errors = ref 0 in @@ -1365,9 +1293,7 @@ let concat_regression_test _ = if !errors <> 0 then exit 1 ;; -(* - * Prefix tests. - *) +(* Prefix tests. *) let is_prefix_basic_aligned_test _ = (* Match mod8 bitstrings *) diff --git a/tests/BitstringParserTest.ml b/tests/BitstringParserTest.ml index 4013e14..1ac7281 100644 --- a/tests/BitstringParserTest.ml +++ b/tests/BitstringParserTest.ml @@ -1,32 +1,26 @@ -(* - * Copyright (c) 2016 Xavier R. Guérin - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - *) +(* Copyright (c) 2016 Xavier R. Guérin + + Permission to use, copy, modify, and distribute this software for any purpose + with or without fee is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. *) open OUnit2 open Bitstring -(* - * EXT3 superblock parsing test - *) +(* EXT3 superblock parsing test *) let ext3_test context = let bits = Bitstring.bitstring_of_file "../../../tests/data/ext3_sb" in match%bitstring bits with - (* - * Check if the file is an EXT3 superblock - *) + (* Check if the file is an EXT3 superblock *) | {| 50200_l : 32 : littleendian (* Inodes count *) ; _ : 32 : littleendian (* Blocks count *) ; _ : 32 : littleendian (* Reserved blocks count *) @@ -45,22 +39,16 @@ let ext3_test context = ; 0xef53 : 16 : littleendian (* Magic signature *) |} -> () - (* - * Otherwise, throw an error - *) + (* Otherwise, throw an error *) | {| _ |} -> failwith "Invalid EXT3 superblock" ;; -(* - * GIF parser test - *) +(* GIF parser test *) let gif_test context = let bits = Bitstring.bitstring_of_file "../../../tests/data/sad_face.gif" in match%bitstring bits with - (* - * Check if the file is a GIF image - *) + (* Check if the file is a GIF image *) | {| ("GIF87a" | "GIF89a") : 6*8 : string ; (* GIF magic. *) 2145 : 16 : littleendian ; 2145 : 16 : littleendian ; @@ -72,15 +60,11 @@ let gif_test context = 0 : 8 |} -> () - (* - * Otherwise, throw an error - *) + (* Otherwise, throw an error *) | {| _ |} -> failwith "Invalid GIF image" ;; -(* - * PCAP parser test - *) +(* PCAP parser test *) let to_bitstring_endian = function | 0xa1b2c3d4_l | 0xa1b23c4d_l -> Bitstring.BigEndian @@ -150,9 +134,7 @@ let pcap_packet_test context endian packet = let pcap_test context = let bits = Bitstring.bitstring_of_file "../../../tests/data/net.pcap" in match%bitstring bits with - (* - * Check if the file is a PCAP file - *) + (* Check if the file is a PCAP file *) | {| ((0xa1b2c3d4_l | 0xa1b23c4d_l | 0xd4c3b2a1_l | @@ -166,15 +148,11 @@ let pcap_test context = packet : -1 : bitstring |} -> pcap_packet_test context (to_bitstring_endian magic) packet - (* - * Otherwise, throw an error - *) + (* Otherwise, throw an error *) | {| _ |} -> failwith "Not a valid PCAP file" ;; -(* - * Function-style parser test - *) +(* Function-style parser test *) let function_parser = function%bitstring | {| 1 : 3 @@ -189,9 +167,7 @@ let function_parser_test context = [%bitstring {| 1 : 3; 2 : 4; "hello" : 40 : string |}] |> function_parser ;; -(* - * Function-style parser test, inline - *) +(* Function-style parser test, inline *) let function_parser_inline_test context = [%bitstring {| 1 : 3; 2 : 4; "hello" : 40 : string |}] @@ -204,9 +180,7 @@ let function_parser_inline_test context = | {| _ |} -> assert_bool "Invalid bitstring" false ;; -(* - * parser with a guard (PR#16) - *) +(* Parser with a guard (PR#16) *) let parser_with_guard_test context = let bits = Bitstring.bitstring_of_string "abc" in @@ -215,9 +189,7 @@ let parser_with_guard_test context = | {| _ |} -> assert_bool "Guard was honored" true ;; -(* - * Wrong fastpath extraction function #46 - *) +(* Wrong fastpath extraction function #46 *) let wrong_fp_extraction context = let mb = Bytes.of_string "\000\000\145", 0, 24 in @@ -234,14 +206,10 @@ let wrong_fp_extraction_dynamic context = | {| _ |} -> assert_bool "Invalid bitstring" false ;; -(* - * Wrong LE extraction on partial int64. - *) +(* Wrong LE extraction on partial int64. *) let wrong_le_partial_int64_extraction context = - (* - * Forward. - *) + (* Forward. *) let mb = Bytes.of_string "\xA0\x00\x00\x00\x00\x00\x00\x00", 0, 64 in match%bitstring mb with | {| a:4; b:60:littleendian |} -> @@ -249,9 +217,7 @@ let wrong_le_partial_int64_extraction context = assert_equal b 0L | {| _ |} -> assert_bool "Invalid bitstring" false; - (* - * Backward. - *) + (* Backward. *) let mb = Bytes.of_string "\x00\x00\x00\x00\x00\x00\x00\x0A", 0, 64 in (match%bitstring mb with | {| b:60:littleendian; a:4 |} -> @@ -260,9 +226,7 @@ let wrong_le_partial_int64_extraction context = | {| _ |} -> assert_bool "Invalid bitstring" false) ;; -(* - * Test suite definition - *) +(* Test suite definition *) let suite = "BitstringParserTest" diff --git a/tests/BitstringQualifierTest.ml b/tests/BitstringQualifierTest.ml index 03eb649..fa6300b 100644 --- a/tests/BitstringQualifierTest.ml +++ b/tests/BitstringQualifierTest.ml @@ -1,25 +1,21 @@ -(* - * Copyright (c) 2016 Xavier R. Guérin - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - *) +(* Copyright (c) 2016 Xavier R. Guérin + + Permission to use, copy, modify, and distribute this software for any purpose + with or without fee is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. *) open OUnit2 open Bitstring -(* - * Test of the map() qualifier - *) +(* Test of the map() qualifier *) let map_test context = let source = [%bitstring {| 1 : 16 ; 2 : 16 |}] in @@ -35,9 +31,7 @@ let map_test context = | {| _ |} -> assert_bool "Invalid pattern" false ;; -(* - * Test of the save_offset_to() qualifier - *) +(* Test of the save_offset_to() qualifier *) let save_offset_test context = let source = [%bitstring {| 1 : 3 ; 2 : 7; 5 : 4; "abc" : -1 : string |}] in @@ -55,9 +49,7 @@ let save_offset_test context = | {| _ |} -> assert_bool "Invalid pattern" false ;; -(* - * Test suite definition - *) +(* Test suite definition *) let suite = "BitstringQualifierTest"