Source file metadataBase.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
(** Raised when the format is invalid. *)
exception Invalid
type bigarray =
(char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
type metadata = (string * string) list
type endianness = Big_endian | Little_endian
type parser_handler = {
label : string;
length : int;
read : unit -> string;
read_ba : (unit -> bigarray) option;
skip : unit -> unit;
}
type custom_parser = parser_handler -> unit
module Reader = struct
(** A function to read taking the buffer to fill the offset and the length and
returning the number of bytes actually read. *)
type t = {
read : bytes -> int -> int -> int;
read_ba : (int -> bigarray) option;
custom_parser : custom_parser option;
seek : int -> unit;
size : unit -> int option;
reset : unit -> unit;
}
(** Make a reading function retry until buffer is filled (or an error
occurs). *)
let retry read buf off len =
let r = ref 0 in
let loop = ref true in
while !loop do
let n = read buf (off + !r) (len - !r) in
r := !r + n;
loop := !r <> 0 && !r < len && n <> 0
done;
!r
let read f n =
let s = Bytes.create n in
let k = retry f.read s 0 n in
if k <> n then raise Invalid;
Bytes.unsafe_to_string s
let read_tag ~length ~label f =
let is_custom =
match f.custom_parser with
| None -> false
| Some custom_parser ->
let is_custom = ref false in
let skip () =
is_custom := true;
f.seek length
in
let read () =
is_custom := true;
read f length
in
let read_ba =
Option.map
(fun read_ba () ->
is_custom := true;
read_ba length)
f.read_ba
in
custom_parser { read_ba; read; skip; length; label };
!is_custom
in
if is_custom then None else Some (read f length)
let drop f n = f.seek n
let byte f = int_of_char (read f 1).[0]
let uint8 f = byte f
let int16_be f =
let b0 = byte f in
let b1 = byte f in
(b0 lsl 8) + b1
let int16_le f =
let b0 = byte f in
let b1 = byte f in
(b1 lsl 8) + b0
let uint16_le = int16_le
let int16 = function Big_endian -> int16_be | Little_endian -> int16_le
let int24_be f =
let b0 = byte f in
let b1 = byte f in
let b2 = byte f in
(b0 lsl 16) + (b1 lsl 8) + b2
let int32_le f =
let b0 = byte f in
let b1 = byte f in
let b2 = byte f in
let b3 = byte f in
(b3 lsl 24) + (b2 lsl 16) + (b1 lsl 8) + b0
let uint32_le = int32_le
let int32_be f =
let b0 = byte f in
let b1 = byte f in
let b2 = byte f in
let b3 = byte f in
(b0 lsl 24) + (b1 lsl 16) + (b2 lsl 8) + b3
let size f = f.size ()
let reset f = f.reset ()
let with_file ?custom_parser f fname =
let fd = Unix.openfile fname [Unix.O_RDONLY; Unix.O_CLOEXEC] 0o644 in
let file =
let read = Unix.read fd in
let read_ba len =
let pos = Int64.of_int (Unix.lseek fd 0 Unix.SEEK_CUR) in
let ba =
Bigarray.array1_of_genarray
(Unix.map_file ~pos fd Bigarray.char Bigarray.c_layout false
[| len |])
in
ignore (Unix.lseek fd len Unix.SEEK_CUR);
ba
in
let seek n = ignore (Unix.lseek fd n Unix.SEEK_CUR) in
let size () =
try
let p = Unix.lseek fd 0 Unix.SEEK_CUR in
let n = Unix.lseek fd 0 Unix.SEEK_END in
ignore (Unix.lseek fd p Unix.SEEK_SET);
Some n
with _ -> None
in
let reset () = ignore (Unix.lseek fd 0 Unix.SEEK_SET) in
{ read; read_ba = Some read_ba; seek; size; reset; custom_parser }
in
try
let ans = f file in
Unix.close fd;
ans
with e ->
let bt = Printexc.get_raw_backtrace () in
Unix.close fd;
Printexc.raise_with_backtrace e bt
let with_string ?custom_parser f s =
let len = String.length s in
let pos = ref 0 in
let read b ofs n =
let n = min (len - !pos) n in
String.blit s !pos b ofs n;
pos := !pos + n;
n
in
let seek n = pos := !pos + n in
let reset () = pos := 0 in
let size () = Some len in
f { read; read_ba = None; seek; size; reset; custom_parser }
end
module Int = struct
include Int
let find p =
let ans = ref 0 in
try
while true do
if p !ans then raise Exit else incr ans
done;
assert false
with Exit -> !ans
end