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)