[Libguestfs] [PATCH v6 12/41] common/mlstdutils: Implement complete set of byte swapping functions.

Richard W.M. Jones
Thu, 15 Jun 2017 17:06:02 -0000

This implements all of:

 val int_of_le16 : string -> int64
 val le16_of_int : int64 -> string
 val int_of_be16 : string -> int64
 val be16_of_int : int64 -> string
 val int_of_le32 : string -> int64
 val le32_of_int : int64 -> string
 val int_of_be32 : string -> int64
 val be32_of_int : int64 -> string
 val int_of_le64 : string -> int64
 val le64_of_int : int64 -> string
 val int_of_be64 : string -> int64
 val be64_of_int : int64 -> string

and tests.
---
 common/mlstdutils/std_utils.ml       | 131 +++++++++++++++++++++++++++++++++++
 common/mlstdutils/std_utils.mli      |  23 +++++-
 common/mlstdutils/std_utils_tests.ml |  22 ++++--
 3 files changed, 169 insertions(+), 7 deletions(-)

diff --git a/common/mlstdutils/std_utils.ml b/common/mlstdutils/std_utils.ml
index 7b8d65f66..f545c6f7a 100644
--- a/common/mlstdutils/std_utils.ml
+++ b/common/mlstdutils/std_utils.ml
@@ -272,6 +272,21 @@ external identity : 'a -> 'a =
"%identity"
 let roundup64 i a = let a = a -^ 1L in (i +^ a) &^ (~^ a)
 let div_roundup64 i a = (i +^ a -^ 1L) /^ a

+let int_of_le16 str +  assert (String.length str = 2);
+  let c0 = Char.code (String.unsafe_get str 0) in
+  let c1 = Char.code (String.unsafe_get str 1) in
+  Int64.of_int c0 +^
+    (Int64.shift_left (Int64.of_int c1) 8)
+
+let le16_of_int i +  let c0 = i &^ 0xffL in
+  let c1 = Int64.shift_right (i &^ 0xff00L) 8 in
+  let b = Bytes.create 2 in
+  Bytes.unsafe_set b 0 (Char.unsafe_chr (Int64.to_int c0));
+  Bytes.unsafe_set b 1 (Char.unsafe_chr (Int64.to_int c1));
+  Bytes.to_string b
+
 let int_of_le32 str    assert (String.length str = 4);
   let c0 = Char.code (String.unsafe_get str 0) in
@@ -295,6 +310,122 @@ let le32_of_int i    Bytes.unsafe_set b 3 (Char.unsafe_chr
(Int64.to_int c3));
   Bytes.to_string b

+let int_of_le64 str +  assert (String.length str = 8);
+  let c0 = Char.code (String.unsafe_get str 0) in
+  let c1 = Char.code (String.unsafe_get str 1) in
+  let c2 = Char.code (String.unsafe_get str 2) in
+  let c3 = Char.code (String.unsafe_get str 3) in
+  let c4 = Char.code (String.unsafe_get str 4) in
+  let c5 = Char.code (String.unsafe_get str 5) in
+  let c6 = Char.code (String.unsafe_get str 6) in
+  let c7 = Char.code (String.unsafe_get str 7) in
+  Int64.of_int c0 +^
+    (Int64.shift_left (Int64.of_int c1) 8) +^
+    (Int64.shift_left (Int64.of_int c2) 16) +^
+    (Int64.shift_left (Int64.of_int c3) 24) +^
+    (Int64.shift_left (Int64.of_int c4) 32) +^
+    (Int64.shift_left (Int64.of_int c5) 40) +^
+    (Int64.shift_left (Int64.of_int c6) 48) +^
+    (Int64.shift_left (Int64.of_int c7) 56)
+
+let le64_of_int i +  let c0 = i &^ 0xffL in
+  let c1 = Int64.shift_right (i &^ 0xff00L) 8 in
+  let c2 = Int64.shift_right (i &^ 0xff0000L) 16 in
+  let c3 = Int64.shift_right (i &^ 0xff000000L) 24 in
+  let c4 = Int64.shift_right (i &^ 0xff00000000L) 32 in
+  let c5 = Int64.shift_right (i &^ 0xff0000000000L) 40 in
+  let c6 = Int64.shift_right (i &^ 0xff000000000000L) 48 in
+  let c7 = Int64.shift_right (i &^ 0xff00000000000000L) 56 in
+  let b = Bytes.create 8 in
+  Bytes.unsafe_set b 0 (Char.unsafe_chr (Int64.to_int c0));
+  Bytes.unsafe_set b 1 (Char.unsafe_chr (Int64.to_int c1));
+  Bytes.unsafe_set b 2 (Char.unsafe_chr (Int64.to_int c2));
+  Bytes.unsafe_set b 3 (Char.unsafe_chr (Int64.to_int c3));
+  Bytes.unsafe_set b 4 (Char.unsafe_chr (Int64.to_int c4));
+  Bytes.unsafe_set b 5 (Char.unsafe_chr (Int64.to_int c5));
+  Bytes.unsafe_set b 6 (Char.unsafe_chr (Int64.to_int c6));
+  Bytes.unsafe_set b 7 (Char.unsafe_chr (Int64.to_int c7));
+  Bytes.to_string b
+
+let int_of_be16 str +  assert (String.length str = 2);
+  let c0 = Char.code (String.unsafe_get str 0) in
+  let c1 = Char.code (String.unsafe_get str 1) in
+  Int64.of_int c1 +^
+    (Int64.shift_left (Int64.of_int c0) 8)
+
+let be16_of_int i +  let c0 = i &^ 0xffL in
+  let c1 = Int64.shift_right (i &^ 0xff00L) 8 in
+  let b = Bytes.create 2 in
+  Bytes.unsafe_set b 0 (Char.unsafe_chr (Int64.to_int c1));
+  Bytes.unsafe_set b 1 (Char.unsafe_chr (Int64.to_int c0));
+  Bytes.to_string b
+
+let int_of_be32 str +  assert (String.length str = 4);
+  let c0 = Char.code (String.unsafe_get str 0) in
+  let c1 = Char.code (String.unsafe_get str 1) in
+  let c2 = Char.code (String.unsafe_get str 2) in
+  let c3 = Char.code (String.unsafe_get str 3) in
+  Int64.of_int c3 +^
+    (Int64.shift_left (Int64.of_int c2) 8) +^
+    (Int64.shift_left (Int64.of_int c1) 16) +^
+    (Int64.shift_left (Int64.of_int c0) 24)
+
+let be32_of_int i +  let c0 = i &^ 0xffL in
+  let c1 = Int64.shift_right (i &^ 0xff00L) 8 in
+  let c2 = Int64.shift_right (i &^ 0xff0000L) 16 in
+  let c3 = Int64.shift_right (i &^ 0xff000000L) 24 in
+  let b = Bytes.create 4 in
+  Bytes.unsafe_set b 0 (Char.unsafe_chr (Int64.to_int c3));
+  Bytes.unsafe_set b 1 (Char.unsafe_chr (Int64.to_int c2));
+  Bytes.unsafe_set b 2 (Char.unsafe_chr (Int64.to_int c1));
+  Bytes.unsafe_set b 3 (Char.unsafe_chr (Int64.to_int c0));
+  Bytes.to_string b
+
+let int_of_be64 str +  assert (String.length str = 8);
+  let c0 = Char.code (String.unsafe_get str 0) in
+  let c1 = Char.code (String.unsafe_get str 1) in
+  let c2 = Char.code (String.unsafe_get str 2) in
+  let c3 = Char.code (String.unsafe_get str 3) in
+  let c4 = Char.code (String.unsafe_get str 4) in
+  let c5 = Char.code (String.unsafe_get str 5) in
+  let c6 = Char.code (String.unsafe_get str 6) in
+  let c7 = Char.code (String.unsafe_get str 7) in
+  Int64.of_int c7 +^
+    (Int64.shift_left (Int64.of_int c6) 8) +^
+    (Int64.shift_left (Int64.of_int c5) 16) +^
+    (Int64.shift_left (Int64.of_int c4) 24) +^
+    (Int64.shift_left (Int64.of_int c3) 32) +^
+    (Int64.shift_left (Int64.of_int c2) 40) +^
+    (Int64.shift_left (Int64.of_int c1) 48) +^
+    (Int64.shift_left (Int64.of_int c0) 56)
+
+let be64_of_int i +  let c0 = i &^ 0xffL in
+  let c1 = Int64.shift_right (i &^ 0xff00L) 8 in
+  let c2 = Int64.shift_right (i &^ 0xff0000L) 16 in
+  let c3 = Int64.shift_right (i &^ 0xff000000L) 24 in
+  let c4 = Int64.shift_right (i &^ 0xff00000000L) 32 in
+  let c5 = Int64.shift_right (i &^ 0xff0000000000L) 40 in
+  let c6 = Int64.shift_right (i &^ 0xff000000000000L) 48 in
+  let c7 = Int64.shift_right (i &^ 0xff00000000000000L) 56 in
+  let b = Bytes.create 8 in
+  Bytes.unsafe_set b 0 (Char.unsafe_chr (Int64.to_int c7));
+  Bytes.unsafe_set b 1 (Char.unsafe_chr (Int64.to_int c6));
+  Bytes.unsafe_set b 2 (Char.unsafe_chr (Int64.to_int c5));
+  Bytes.unsafe_set b 3 (Char.unsafe_chr (Int64.to_int c4));
+  Bytes.unsafe_set b 4 (Char.unsafe_chr (Int64.to_int c3));
+  Bytes.unsafe_set b 5 (Char.unsafe_chr (Int64.to_int c2));
+  Bytes.unsafe_set b 6 (Char.unsafe_chr (Int64.to_int c1));
+  Bytes.unsafe_set b 7 (Char.unsafe_chr (Int64.to_int c0));
+  Bytes.to_string b
+
 type wrap_break_t = WrapEOS | WrapSpace | WrapNL

 let rec wrap ?(chan = stdout) ?(indent = 0) str diff --git
a/common/mlstdutils/std_utils.mli b/common/mlstdutils/std_utils.mli
index 820673764..686d4193f 100644
--- a/common/mlstdutils/std_utils.mli
+++ b/common/mlstdutils/std_utils.mli
@@ -143,10 +143,29 @@ val roundup64 : int64 -> int64 -> int64
 val div_roundup64 : int64 -> int64 -> int64
 (** [div_roundup64 i a] returns [i] rounded up to the next multiple of [a],
     with the result divided by [a]. *)
+
+val int_of_le16 : string -> int64
+val le16_of_int : int64 -> string
+val int_of_be16 : string -> int64
+val be16_of_int : int64 -> string
 val int_of_le32 : string -> int64
-(** Unpack a 4 byte string as a little endian 32 bit integer. *)
 val le32_of_int : int64 -> string
-(** Pack a 32 bit integer a 4 byte string stored little endian. *)
+val int_of_be32 : string -> int64
+val be32_of_int : int64 -> string
+val int_of_le64 : string -> int64
+val le64_of_int : int64 -> string
+val int_of_be64 : string -> int64
+val be64_of_int : int64 -> string
+(** [int_of_X] functions unpack a string and return the equivalent integer.
+
+    [X_of_int] functions pack an integer into a string.
+
+    The value of [X] encodes whether the string is stored as
+    little endian [le] or big endian [be] and the size in bits
+    [16], [32] or [64].
+
+    On the OCaml side, 64 bit integers are always used so that you
+    can use the [.^] operators on them for bit manipulation. *)

 val wrap : ?chan:out_channel -> ?indent:int -> string -> unit
 (** Wrap text. *)
diff --git a/common/mlstdutils/std_utils_tests.ml
b/common/mlstdutils/std_utils_tests.ml
index 1003f931c..6bc74fb63 100644
--- a/common/mlstdutils/std_utils_tests.ml
+++ b/common/mlstdutils/std_utils_tests.ml
@@ -33,10 +33,22 @@ let test_subdirectory ctx    assert_equal_string
"bar" (subdirectory "/foo" "/foo/bar");
   assert_equal_string "bar/baz" (subdirectory "/foo"
"/foo/bar/baz")

-(* Test Common_utils.int_of_le32 and Common_utils.le32_of_int. *)
-let test_le32 ctx -  assert_equal_int64 0x20406080L (int_of_le32
"\x80\x60\x40\x20");
-  assert_equal_string "\x80\x60\x40\x20" (le32_of_int 0x20406080L)
+(* Test Std_utils.int_of_X and Std_utils.X_of_int byte swapping
+ * functions.
+ *)
+let rec test_byteswap ctx +  test_swap int_of_le16 le16_of_int 0x2040L
"\x40\x20";
+  test_swap int_of_le32 le32_of_int 0x20406080L "\x80\x60\x40\x20";
+  test_swap int_of_le64 le64_of_int
+            0x20406080A0C0E0F0L "\xF0\xE0\xC0\xA0\x80\x60\x40\x20";
+  test_swap int_of_be16 be16_of_int 0x2040L "\x20\x40";
+  test_swap int_of_be32 be32_of_int 0x20406080L "\x20\x40\x60\x80";
+  test_swap int_of_be64 be64_of_int
+            0x20406080A0C0E0F0L "\x20\x40\x60\x80\xA0\xC0\xE0\xF0"
+
+and test_swap int_of_x x_of_int i s +  assert_equal_int64 i (int_of_x s);
+  assert_equal_string s (x_of_int i)

 (* Test Std_utils.String.is_prefix. *)
 let test_string_is_prefix ctx @@ -84,7 +96,7 @@ let suite    "mllib
Std_utils" >:::
     [
       "subdirectory" >:: test_subdirectory;
-      "numeric.le32" >:: test_le32;
+      "numeric.byteswap" >:: test_byteswap;
       "strings.is_prefix" >:: test_string_is_prefix;
       "strings.is_suffix" >:: test_string_is_suffix;
       "strings.find" >:: test_string_find;
--
2.13.0