Skip to content

Commit 4ea8c8b

Browse files
authored
Fix parsing partial int64 with little endian encoding (#39)
1 parent 0b667be commit 4ea8c8b

5 files changed

Lines changed: 99 additions & 60 deletions

File tree

bitstring.opam

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This file is generated by dune, edit dune-project instead
22
opam-version: "2.0"
3-
version: "5.0.0"
3+
version: "5.0.1"
44
synopsis: "Bitstrings and bitstring matching for OCaml"
55
description: """
66
The ocaml-bitstring project adds Erlang-style bitstrings and matching over bitstrings as a syntax extension and library for OCaml.

dune-project

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
(name bitstring)
44

5-
(version 5.0.0)
5+
(version 5.0.1)
66

77
(generate_opam_files true)
88

ppx_bitstring.opam

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This file is generated by dune, edit dune-project instead
22
opam-version: "2.0"
3-
version: "5.0.0"
3+
version: "5.0.1"
44
synopsis: "Bitstrings and bitstring matching for OCaml - PPX extension"
55
description: """
66
The ocaml-bitstring project adds Erlang-style bitstrings and matching over bitstrings as a syntax extension and library for OCaml.

src/bitstring.ml

Lines changed: 62 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,65 @@ module I64 = struct
354354
invalid_arg "Bitstring.I64.mask"
355355

356356
(* Byte swap an int of a given size. *)
357-
(* let byteswap v bits = *)
357+
let byteswap v bits =
358+
if bits <= 8 then v
359+
else if bits <= 16 then (
360+
let shift = bits-8 in
361+
let v1 = v >>> shift in
362+
let v2 = (v land (mask shift)) <<< 8 in
363+
v2 lor v1
364+
) else if bits <= 24 then (
365+
let shift = bits - 16 in
366+
let v1 = v >>> (8+shift) in
367+
let v2 = ((v >>> shift) land ff) <<< 8 in
368+
let v3 = (v land (mask shift)) <<< 16 in
369+
v3 lor v2 lor v1
370+
) else if bits <= 32 then (
371+
let shift = bits - 24 in
372+
let v1 = v >>> (16+shift) in
373+
let v2 = ((v >>> (8+shift)) land ff) <<< 8 in
374+
let v3 = ((v >>> shift) land ff) <<< 16 in
375+
let v4 = (v land (mask shift)) <<< 24 in
376+
v4 lor v3 lor v2 lor v1
377+
) else if bits <= 40 then (
378+
let shift = bits - 32 in
379+
let v1 = v >>> (24+shift) in
380+
let v2 = ((v >>> (16+shift)) land ff) <<< 8 in
381+
let v3 = ((v >>> (8+shift)) land ff) <<< 16 in
382+
let v4 = ((v >>> shift) land ff) <<< 24 in
383+
let v5 = (v land (mask shift)) <<< 32 in
384+
v5 lor v4 lor v3 lor v2 lor v1
385+
) else if bits <= 48 then (
386+
let shift = bits - 40 in
387+
let v1 = v >>> (32+shift) in
388+
let v2 = ((v >>> (24+shift)) land ff) <<< 8 in
389+
let v3 = ((v >>> (16+shift)) land ff) <<< 16 in
390+
let v4 = ((v >>> (8+shift)) land ff) <<< 24 in
391+
let v5 = ((v >>> shift) land ff) <<< 32 in
392+
let v6 = (v land (mask shift)) <<< 40 in
393+
v6 lor v5 lor v4 lor v3 lor v2 lor v1
394+
) else if bits <= 56 then (
395+
let shift = bits - 48 in
396+
let v1 = v >>> (40+shift) in
397+
let v2 = ((v >>> (32+shift)) land ff) <<< 8 in
398+
let v3 = ((v >>> (24+shift)) land ff) <<< 16 in
399+
let v4 = ((v >>> (16+shift)) land ff) <<< 24 in
400+
let v5 = ((v >>> (8+shift)) land ff) <<< 32 in
401+
let v6 = ((v >>> shift) land ff) <<< 40 in
402+
let v7 = (v land (mask shift)) <<< 48 in
403+
v7 lor v6 lor v5 lor v4 lor v3 lor v2 lor v1
404+
) else (
405+
let shift = bits - 56 in
406+
let v1 = v >>> (48+shift) in
407+
let v2 = ((v >>> (40+shift)) land ff) <<< 8 in
408+
let v3 = ((v >>> (32+shift)) land ff) <<< 16 in
409+
let v4 = ((v >>> (24+shift)) land ff) <<< 24 in
410+
let v5 = ((v >>> (16+shift)) land ff) <<< 32 in
411+
let v6 = ((v >>> (8+shift)) land ff) <<< 40 in
412+
let v7 = ((v >>> shift) land ff) <<< 48 in
413+
let v8 = (v land (mask shift)) <<< 56 in
414+
v8 lor v7 lor v6 lor v5 lor v4 lor v3 lor v2 lor v1
415+
)
358416

359417
(* Check a value is in range 0 .. 2^bits-1. *)
360418
let range_unsigned v bits =
@@ -671,54 +729,9 @@ let extract_int64_be_unsigned data off len flen =
671729
word (*, off+flen, len-flen*)
672730

673731
let extract_int64_le_unsigned data off len flen =
674-
let byteoff = off lsr 3 in
675-
676-
let strlen = Bytes.length data in
677-
678-
let word =
679-
(* Optimize the common (byte-aligned) case. *)
680-
if off land 7 = 0 then (
681-
let word =
682-
let c0 = _get_byte64 data byteoff strlen in
683-
let c1 = _get_byte64 data (byteoff+1) strlen in
684-
let c2 = _get_byte64 data (byteoff+2) strlen in
685-
let c3 = _get_byte64 data (byteoff+3) strlen in
686-
let c4 = _get_byte64 data (byteoff+4) strlen in
687-
let c5 = _get_byte64 data (byteoff+5) strlen in
688-
let c6 = _get_byte64 data (byteoff+6) strlen in
689-
let c7 = _get_byte64 data (byteoff+7) strlen in
690-
_make_int64_le c0 c1 c2 c3 c4 c5 c6 c7 in
691-
Int64.logand word (I64.mask flen)
692-
) else (
693-
(* Extract the next 64 bits, slow method. *)
694-
let word =
695-
let c0 = extract_char_unsigned data off len 8
696-
and off = off + 8 and len = len - 8 in
697-
let c1 = extract_char_unsigned data off len 8
698-
and off = off + 8 and len = len - 8 in
699-
let c2 = extract_char_unsigned data off len 8
700-
and off = off + 8 and len = len - 8 in
701-
let c3 = extract_char_unsigned data off len 8
702-
and off = off + 8 and len = len - 8 in
703-
let c4 = extract_char_unsigned data off len 8
704-
and off = off + 8 and len = len - 8 in
705-
let c5 = extract_char_unsigned data off len 8
706-
and off = off + 8 and len = len - 8 in
707-
let c6 = extract_char_unsigned data off len 8
708-
and off = off + 8 and len = len - 8 in
709-
let c7 = extract_char_unsigned data off len 8 in
710-
let c0 = Int64.of_int c0 in
711-
let c1 = Int64.of_int c1 in
712-
let c2 = Int64.of_int c2 in
713-
let c3 = Int64.of_int c3 in
714-
let c4 = Int64.of_int c4 in
715-
let c5 = Int64.of_int c5 in
716-
let c6 = Int64.of_int c6 in
717-
let c7 = Int64.of_int c7 in
718-
_make_int64_le c0 c1 c2 c3 c4 c5 c6 c7 in
719-
Int64.logand word (I64.mask flen)
720-
) in
721-
word (*, off+flen, len-flen*)
732+
let v = extract_int64_be_unsigned data off len flen in
733+
let v = I64.byteswap v flen in
734+
v
722735

723736
let extract_int64_ne_unsigned =
724737
if nativeendian = BigEndian

tests/BitstringParserTest.ml

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -224,17 +224,43 @@ let wrong_fp_extraction_dynamic context =
224224
| {| _ : on ; matched_value : 24 : bigendian |} -> assert_equal matched_value 145
225225
| {| _ |} -> assert_bool "Invalid bitstring" false
226226

227+
(*
228+
* Wrong LE extraction on partial int64.
229+
*)
230+
231+
let wrong_le_partial_int64_extraction context =
232+
(*
233+
* Forward.
234+
*)
235+
let mb = ((Bytes.of_string "\xA0\x00\x00\x00\x00\x00\x00\x00"), 0, 64) in
236+
match%bitstring mb with
237+
| {| a:4; b:60:littleendian |} ->
238+
assert_equal a 10;
239+
assert_equal b 0L
240+
| {| _ |} -> assert_bool "Invalid bitstring" false;
241+
(*
242+
* Backward.
243+
*)
244+
let mb = ((Bytes.of_string "\x00\x00\x00\x00\x00\x00\x00\x0A"), 0, 64) in
245+
match%bitstring mb with
246+
| {| b:60:littleendian; a:4 |} ->
247+
assert_equal a 10;
248+
assert_equal b 0L
249+
| {| _ |} -> assert_bool "Invalid bitstring" false
250+
;;
251+
227252
(*
228253
* Test suite definition
229254
*)
230255

231256
let suite = "BitstringParserTest" >::: [
232-
"ext3" >:: ext3_test;
233-
"gif" >:: gif_test;
234-
"pcap" >:: pcap_test;
235-
"function" >:: function_parser_test;
236-
"function_inline" >:: function_parser_inline_test;
237-
"parser_with_guard" >:: parser_with_guard_test;
238-
"wrong_fp_extraction" >:: wrong_fp_extraction;
239-
"wrong_fp_extraction_dynamic" >:: wrong_fp_extraction_dynamic;
257+
"ext3" >:: ext3_test;
258+
"gif" >:: gif_test;
259+
"pcap" >:: pcap_test;
260+
"function" >:: function_parser_test;
261+
"function_inline" >:: function_parser_inline_test;
262+
"parser_with_guard" >:: parser_with_guard_test;
263+
"wrong_fp_extraction" >:: wrong_fp_extraction;
264+
"wrong_fp_extraction_dynamic" >:: wrong_fp_extraction_dynamic;
265+
"wrong_le_partial_int64_extraction" >:: wrong_le_partial_int64_extraction;
240266
]

0 commit comments

Comments
 (0)