Source file util.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
exception Truncated_input

let read_raw_byte bytes ~pos_ref =
  if !pos_ref >= Bytes.length bytes then raise Truncated_input;
  let b = Char.code (Bytes.unsafe_get bytes !pos_ref) in
  pos_ref := !pos_ref + 1;
  b

let read_raw_varint bytes ~pos_ref =
  let result = ref 0 in
  let shift = ref 0 in
  let continue = ref true in
  while !continue do
    if !pos_ref >= Bytes.length bytes then raise Truncated_input;
    let b = Char.code (Bytes.unsafe_get bytes !pos_ref) in
    pos_ref := !pos_ref + 1;
    result := !result lor ((b land 0x7F) lsl !shift);
    shift := !shift + 7;
    if b land 0x80 = 0 then continue := false
  done;
  !result

(** [check_available bytes ~pos_ref ~n] raises [Truncated_input] if there are
    fewer than [n] bytes remaining from [!pos_ref] in [bytes]. *)
let check_available bytes ~pos_ref ~n =
  if !pos_ref + n > Bytes.length bytes then raise Truncated_input

(** [read_raw_int32_be bytes ~pos_ref] reads a big-endian 32-bit integer from
    [bytes] at [!pos_ref], advances [pos_ref] by 4, and returns the value.
    @raise Truncated_input if fewer than 4 bytes remain. *)
let read_raw_int32_be bytes ~pos_ref =
  check_available bytes ~pos_ref ~n:4;
  let v = Bytes.get_int32_be bytes !pos_ref in
  pos_ref := !pos_ref + 4;
  v

(** [read_raw_int64_be bytes ~pos_ref] reads a big-endian 64-bit integer from
    [bytes] at [!pos_ref], advances [pos_ref] by 8, and returns the value.
    @raise Truncated_input if fewer than 8 bytes remain. *)
let read_raw_int64_be bytes ~pos_ref =
  check_available bytes ~pos_ref ~n:8;
  let v = Bytes.get_int64_be bytes !pos_ref in
  pos_ref := !pos_ref + 8;
  v

(** [read_raw_bytes bytes ~pos_ref ~n] returns a fresh [bytes] value containing
    the next [n] bytes from [bytes] starting at [!pos_ref], and advances
    [pos_ref] by [n].
    @raise Truncated_input if fewer than [n] bytes remain. *)
let read_raw_bytes bytes ~pos_ref ~n =
  check_available bytes ~pos_ref ~n;
  let v = Bytes.sub bytes !pos_ref n in
  pos_ref := !pos_ref + n;
  v

(** [read_raw_string bytes ~pos_ref ~n] returns a fresh [string] containing the
    next [n] bytes from [bytes] starting at [!pos_ref], and advances
    [pos_ref] by [n].
    @raise Truncated_input if fewer than [n] bytes remain. *)
let read_raw_string bytes ~pos_ref ~n =
  check_available bytes ~pos_ref ~n;
  let v = Bytes.sub_string bytes !pos_ref n in
  pos_ref := !pos_ref + n;
  v

(** [blit_advance src ~pos_ref dst ~n] copies [n] bytes from [src] starting
    at [!pos_ref] into [dst] at offset 0, and advances [pos_ref] by [n].
    @raise Truncated_input if fewer than [n] bytes remain in [src]. *)
let blit_advance src ~pos_ref dst ~n =
  check_available src ~pos_ref ~n;
  Bytes.blit src !pos_ref dst 0 n;
  pos_ref := !pos_ref + n

(**
  A hashtable that checks for physical equality.

  We maintain a different hashtable for each type to limit collisions.
*)
module Obj_tbl = Hashtbl.Make (struct
  type t = Obj.t
  let equal a b = a == b
  let hash = Hashtbl.hash
end)