package metadata

  1. Overview
  2. Docs

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
OCaml

Innovation. Community. Security.