Blame src/IO.ml

rpm-build 0f2925
(*
rpm-build 0f2925
 * IO - Abstract input/output
rpm-build 0f2925
 * Copyright (C) 2003 Nicolas Cannasse
rpm-build 0f2925
 *
rpm-build 0f2925
 * This library is free software; you can redistribute it and/or
rpm-build 0f2925
 * modify it under the terms of the GNU Lesser General Public
rpm-build 0f2925
 * License as published by the Free Software Foundation; either
rpm-build 0f2925
 * version 2.1 of the License, or (at your option) any later version,
rpm-build 0f2925
 * with the special exception on linking described in file LICENSE.
rpm-build 0f2925
 *
rpm-build 0f2925
 * This library is distributed in the hope that it will be useful,
rpm-build 0f2925
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rpm-build 0f2925
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
rpm-build 0f2925
 * Lesser General Public License for more details.
rpm-build 0f2925
 *
rpm-build 0f2925
 * You should have received a copy of the GNU Lesser General Public
rpm-build 0f2925
 * License along with this library; if not, write to the Free Software
rpm-build 0f2925
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
rpm-build 0f2925
 *)
rpm-build 0f2925
rpm-build 0f2925
open ExtBytes
rpm-build 0f2925
rpm-build 0f2925
type input = {
rpm-build 0f2925
  mutable in_read : unit -> char;
rpm-build 0f2925
  mutable in_input : Bytes.t -> int -> int -> int;
rpm-build 0f2925
  mutable in_close : unit -> unit;
rpm-build 0f2925
}
rpm-build 0f2925
rpm-build 0f2925
type 'a output = {
rpm-build 0f2925
  mutable out_write : char -> unit;
rpm-build 0f2925
  mutable out_output : Bytes.t -> int -> int -> int;
rpm-build 0f2925
  mutable out_close : unit -> 'a;
rpm-build 0f2925
  mutable out_flush : unit -> unit;
rpm-build 0f2925
}
rpm-build 0f2925
rpm-build 0f2925
exception No_more_input
rpm-build 0f2925
exception Input_closed
rpm-build 0f2925
exception Output_closed
rpm-build 0f2925
rpm-build 0f2925
(* -------------------------------------------------------------- *)
rpm-build 0f2925
(* API *)
rpm-build 0f2925
rpm-build 0f2925
let default_close = (fun () -> ())
rpm-build 0f2925
rpm-build 0f2925
let create_in ~read ~input ~close =
rpm-build 0f2925
  {
rpm-build 0f2925
    in_read = read;
rpm-build 0f2925
    in_input = input;
rpm-build 0f2925
    in_close = close;
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let create_out ~write ~output ~flush ~close =
rpm-build 0f2925
  {
rpm-build 0f2925
    out_write = write;
rpm-build 0f2925
    out_output = output;
rpm-build 0f2925
    out_close = close;
rpm-build 0f2925
    out_flush = flush;
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let read i = i.in_read()
rpm-build 0f2925
rpm-build 0f2925
let nread i n =
rpm-build 0f2925
  if n < 0 then invalid_arg "IO.nread";
rpm-build 0f2925
  if n = 0 then Bytes.empty
rpm-build 0f2925
  else
rpm-build 0f2925
  let s = Bytes.create n in
rpm-build 0f2925
  let l = ref n in
rpm-build 0f2925
  let p = ref 0 in
rpm-build 0f2925
  try
rpm-build 0f2925
    while !l > 0 do
rpm-build 0f2925
      let r = i.in_input s !p !l in
rpm-build 0f2925
      if r = 0 then raise No_more_input;
rpm-build 0f2925
      p := !p + r;
rpm-build 0f2925
      l := !l - r;
rpm-build 0f2925
    done;
rpm-build 0f2925
    s
rpm-build 0f2925
  with
rpm-build 0f2925
    No_more_input as e ->
rpm-build 0f2925
      if !p = 0 then raise e;
rpm-build 0f2925
      Bytes.sub s 0 !p
rpm-build 0f2925
rpm-build 0f2925
let nread_string i n =
rpm-build 0f2925
  (* [nread] transfers ownership of the returned string, so
rpm-build 0f2925
     [unsafe_to_string] is safe here *)
rpm-build 0f2925
 Bytes.unsafe_to_string (nread i n)
rpm-build 0f2925
rpm-build 0f2925
let really_output o s p l' =
rpm-build 0f2925
  let sl = Bytes.length s in
rpm-build 0f2925
  if p + l' > sl || p < 0 || l' < 0 then invalid_arg "IO.really_output";
rpm-build 0f2925
     let l = ref l' in
rpm-build 0f2925
  let p = ref p in
rpm-build 0f2925
  while !l > 0 do
rpm-build 0f2925
    let w = o.out_output s !p !l in
rpm-build 0f2925
    if w = 0 then raise Sys_blocked_io;
rpm-build 0f2925
    p := !p + w;
rpm-build 0f2925
    l := !l - w;
rpm-build 0f2925
  done;
rpm-build 0f2925
  l'
rpm-build 0f2925
rpm-build 0f2925
let input i s p l =
rpm-build 0f2925
  let sl = Bytes.length s in
rpm-build 0f2925
  if p + l > sl || p < 0 || l < 0 then invalid_arg "IO.input";
rpm-build 0f2925
  if l = 0 then
rpm-build 0f2925
    0
rpm-build 0f2925
  else
rpm-build 0f2925
    i.in_input s p l
rpm-build 0f2925
rpm-build 0f2925
let really_input i s p l' =
rpm-build 0f2925
  let sl = Bytes.length s in
rpm-build 0f2925
  if p + l' > sl || p < 0 || l' < 0 then invalid_arg "IO.really_input";
rpm-build 0f2925
  let l = ref l' in
rpm-build 0f2925
  let p = ref p in
rpm-build 0f2925
  while !l > 0 do
rpm-build 0f2925
    let r = i.in_input s !p !l in
rpm-build 0f2925
    if r = 0 then raise Sys_blocked_io;
rpm-build 0f2925
    p := !p + r;
rpm-build 0f2925
    l := !l - r;
rpm-build 0f2925
  done;
rpm-build 0f2925
  l'
rpm-build 0f2925
rpm-build 0f2925
let really_nread i n =
rpm-build 0f2925
  if n < 0 then invalid_arg "IO.really_nread";
rpm-build 0f2925
  if n = 0 then Bytes.empty
rpm-build 0f2925
  else
rpm-build 0f2925
  let s = Bytes.create n
rpm-build 0f2925
  in
rpm-build 0f2925
  ignore(really_input i s 0 n);
rpm-build 0f2925
  s
rpm-build 0f2925
rpm-build 0f2925
let really_nread_string i n =
rpm-build 0f2925
  (* [really_nread] transfers ownership of the returned string,
rpm-build 0f2925
     so [unsafe_to_string] is safe here *)
rpm-build 0f2925
  Bytes.unsafe_to_string (really_nread i n)
rpm-build 0f2925
rpm-build 0f2925
let close_in i =
rpm-build 0f2925
  let f _ = raise Input_closed in
rpm-build 0f2925
  i.in_close();
rpm-build 0f2925
  i.in_read <- f;
rpm-build 0f2925
  i.in_input <- f;
rpm-build 0f2925
  i.in_close <- f
rpm-build 0f2925
rpm-build 0f2925
let write o x = o.out_write x
rpm-build 0f2925
rpm-build 0f2925
let nwrite o s =
rpm-build 0f2925
  let p = ref 0 in
rpm-build 0f2925
        let l = ref (Bytes.length s) in
rpm-build 0f2925
  while !l > 0 do
rpm-build 0f2925
    let w = o.out_output s !p !l in
rpm-build 0f2925
    if w = 0 then raise Sys_blocked_io;
rpm-build 0f2925
    p := !p + w;
rpm-build 0f2925
    l := !l - w;
rpm-build 0f2925
  done
rpm-build 0f2925
rpm-build 0f2925
let nwrite_string o s =
rpm-build 0f2925
  (* [nwrite] does not mutate or capture its [bytes] input,
rpm-build 0f2925
     so using [Bytes.unsafe_of_string] is safe here *)
rpm-build 0f2925
  nwrite o (Bytes.unsafe_of_string s)
rpm-build 0f2925
rpm-build 0f2925
let output o s p l =
rpm-build 0f2925
  let sl = Bytes.length s in
rpm-build 0f2925
  if p + l > sl || p < 0 || l < 0 then invalid_arg "IO.output";
rpm-build 0f2925
  o.out_output s p l
rpm-build 0f2925
rpm-build 0f2925
let scanf i fmt =
rpm-build 0f2925
  let ib = Scanf.Scanning.from_function (fun () -> try read i with No_more_input -> raise End_of_file) in
rpm-build 0f2925
  Scanf.kscanf ib (fun _ exn -> raise exn) fmt
rpm-build 0f2925
rpm-build 0f2925
let printf o fmt =
rpm-build 0f2925
  Printf.kprintf (fun s -> nwrite_string o s) fmt
rpm-build 0f2925
rpm-build 0f2925
let flush o = o.out_flush()
rpm-build 0f2925
rpm-build 0f2925
let close_out o =
rpm-build 0f2925
  let f _ = raise Output_closed in
rpm-build 0f2925
  let r = o.out_close() in
rpm-build 0f2925
  o.out_write <- f;
rpm-build 0f2925
  o.out_output <- f;
rpm-build 0f2925
  o.out_close <- f;
rpm-build 0f2925
  o.out_flush <- f;
rpm-build 0f2925
  r
rpm-build 0f2925
rpm-build 0f2925
let read_all i =
rpm-build 0f2925
  let maxlen = 1024 in
rpm-build 0f2925
  let str = ref [] in
rpm-build 0f2925
  let pos = ref 0 in
rpm-build 0f2925
  let rec loop() =
rpm-build 0f2925
    let s = nread i maxlen in
rpm-build 0f2925
    str := (s,!pos) :: !str;
rpm-build 0f2925
    pos := !pos + Bytes.length s;
rpm-build 0f2925
    loop()
rpm-build 0f2925
  in
rpm-build 0f2925
  try
rpm-build 0f2925
    loop()
rpm-build 0f2925
  with
rpm-build 0f2925
    No_more_input ->
rpm-build 0f2925
      let buf = Bytes.create !pos in
rpm-build 0f2925
      List.iter (fun (s,p) ->
rpm-build 0f2925
        Bytes.blit s 0 buf p (Bytes.length s)
rpm-build 0f2925
      ) !str;
rpm-build 0f2925
                        (* 'buf' doesn't escape, it won't be mutated again *)
rpm-build 0f2925
      Bytes.unsafe_to_string buf
rpm-build 0f2925
rpm-build 0f2925
let pos_in i =
rpm-build 0f2925
  let p = ref 0 in
rpm-build 0f2925
  {
rpm-build 0f2925
    in_read = (fun () ->
rpm-build 0f2925
      let c = i.in_read() in
rpm-build 0f2925
      incr p;
rpm-build 0f2925
      c
rpm-build 0f2925
    );
rpm-build 0f2925
    in_input = (fun s sp l ->
rpm-build 0f2925
      let n = i.in_input s sp l in
rpm-build 0f2925
      p := !p + n;
rpm-build 0f2925
      n
rpm-build 0f2925
    );
rpm-build 0f2925
    in_close = i.in_close
rpm-build 0f2925
  } , (fun () -> !p)
rpm-build 0f2925
rpm-build 0f2925
let pos_out o =
rpm-build 0f2925
  let p = ref 0 in
rpm-build 0f2925
  {
rpm-build 0f2925
    out_write = (fun c ->
rpm-build 0f2925
      o.out_write c;
rpm-build 0f2925
      incr p
rpm-build 0f2925
    );
rpm-build 0f2925
    out_output = (fun s sp l ->
rpm-build 0f2925
      let n = o.out_output s sp l in
rpm-build 0f2925
      p := !p + n;
rpm-build 0f2925
      n
rpm-build 0f2925
    );
rpm-build 0f2925
    out_close = o.out_close;
rpm-build 0f2925
    out_flush = o.out_flush;
rpm-build 0f2925
  } , (fun () -> !p)
rpm-build 0f2925
rpm-build 0f2925
(* -------------------------------------------------------------- *)
rpm-build 0f2925
(* Standard IO *)
rpm-build 0f2925
rpm-build 0f2925
let input_bytes s =
rpm-build 0f2925
  let pos = ref 0 in
rpm-build 0f2925
  let len = Bytes.length s in
rpm-build 0f2925
  {
rpm-build 0f2925
    in_read = (fun () ->
rpm-build 0f2925
      if !pos >= len then raise No_more_input;
rpm-build 0f2925
      let c = Bytes.unsafe_get s !pos in
rpm-build 0f2925
      incr pos;
rpm-build 0f2925
      c
rpm-build 0f2925
    );
rpm-build 0f2925
    in_input = (fun sout p l ->
rpm-build 0f2925
      if !pos >= len then raise No_more_input;
rpm-build 0f2925
      let n = (if !pos + l > len then len - !pos else l) in
rpm-build 0f2925
      Bytes.unsafe_blit s !pos sout p n;
rpm-build 0f2925
      pos := !pos + n;
rpm-build 0f2925
      n
rpm-build 0f2925
    );
rpm-build 0f2925
    in_close = (fun () -> ());
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let input_string s =
rpm-build 0f2925
  (* Bytes.unsafe_of_string is safe here as input_bytes does not
rpm-build 0f2925
     mutate the byte sequence *)
rpm-build 0f2925
  input_bytes (Bytes.unsafe_of_string s)
rpm-build 0f2925
rpm-build 0f2925
open ExtBuffer
rpm-build 0f2925
rpm-build 0f2925
let output_buffer close =
rpm-build 0f2925
  let b = Buffer.create 0 in
rpm-build 0f2925
  {
rpm-build 0f2925
    out_write = (fun c -> Buffer.add_char b c);
rpm-build 0f2925
    out_output = (fun s p l -> Buffer.add_subbytes b s p l; l);
rpm-build 0f2925
    out_close = (fun () -> close b);
rpm-build 0f2925
    out_flush = (fun () -> ());
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let output_string () = output_buffer Buffer.contents
rpm-build 0f2925
let output_bytes () = output_buffer Buffer.to_bytes
rpm-build 0f2925
rpm-build 0f2925
let output_strings() =
rpm-build 0f2925
  let sl = ref [] in
rpm-build 0f2925
  let size = ref 0 in
rpm-build 0f2925
  let b = Buffer.create 0 in
rpm-build 0f2925
  {
rpm-build 0f2925
    out_write = (fun c ->
rpm-build 0f2925
      if !size = Sys.max_string_length then begin
rpm-build 0f2925
        sl := Buffer.contents b :: !sl;
rpm-build 0f2925
        Buffer.clear b;
rpm-build 0f2925
        size := 0;
rpm-build 0f2925
      end else incr size;
rpm-build 0f2925
      Buffer.add_char b c
rpm-build 0f2925
    );
rpm-build 0f2925
    out_output = (fun s p l ->
rpm-build 0f2925
      if !size + l > Sys.max_string_length then begin
rpm-build 0f2925
        sl := Buffer.contents b :: !sl;
rpm-build 0f2925
        Buffer.clear b;
rpm-build 0f2925
        size := 0;
rpm-build 0f2925
      end else size := !size + l;
rpm-build 0f2925
      Buffer.add_subbytes b s p l;
rpm-build 0f2925
      l
rpm-build 0f2925
    );
rpm-build 0f2925
    out_close = (fun () -> sl := Buffer.contents b :: !sl; List.rev (!sl));
rpm-build 0f2925
    out_flush = (fun () -> ());
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
rpm-build 0f2925
let input_channel ch =
rpm-build 0f2925
  {
rpm-build 0f2925
    in_read = (fun () ->
rpm-build 0f2925
      try
rpm-build 0f2925
        input_char ch
rpm-build 0f2925
      with
rpm-build 0f2925
        End_of_file -> raise No_more_input
rpm-build 0f2925
    );
rpm-build 0f2925
    in_input = (fun s p l ->
rpm-build 0f2925
      let n = Pervasives.input ch s p l in
rpm-build 0f2925
      if n = 0 then raise No_more_input;
rpm-build 0f2925
      n
rpm-build 0f2925
    );
rpm-build 0f2925
    in_close = (fun () -> Pervasives.close_in ch);
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let output_channel ch =
rpm-build 0f2925
  {
rpm-build 0f2925
    out_write = (fun c -> output_char ch c);
rpm-build 0f2925
    out_output = (fun s p l -> Pervasives.output ch s p l; l);
rpm-build 0f2925
    out_close = (fun () -> Pervasives.close_out ch);
rpm-build 0f2925
    out_flush = (fun () -> Pervasives.flush ch);
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let input_enum e =
rpm-build 0f2925
  let pos = ref 0 in
rpm-build 0f2925
  {
rpm-build 0f2925
    in_read = (fun () ->
rpm-build 0f2925
      match Enum.get e with
rpm-build 0f2925
      | None -> raise No_more_input
rpm-build 0f2925
      | Some c ->
rpm-build 0f2925
        incr pos;
rpm-build 0f2925
        c
rpm-build 0f2925
    );
rpm-build 0f2925
    in_input = (fun s p l ->
rpm-build 0f2925
      let rec loop p l =
rpm-build 0f2925
        if l = 0 then
rpm-build 0f2925
          0
rpm-build 0f2925
        else
rpm-build 0f2925
          match Enum.get e with
rpm-build 0f2925
          | None -> l
rpm-build 0f2925
          | Some c ->
rpm-build 0f2925
            Bytes.unsafe_set s p c;
rpm-build 0f2925
            loop (p + 1) (l - 1)
rpm-build 0f2925
      in
rpm-build 0f2925
      let k = loop p l in
rpm-build 0f2925
      if k = l then raise No_more_input;
rpm-build 0f2925
      l - k
rpm-build 0f2925
    );
rpm-build 0f2925
    in_close = (fun () -> ());
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let output_enum() =
rpm-build 0f2925
  let b = Buffer.create 0 in
rpm-build 0f2925
  {
rpm-build 0f2925
    out_write = (fun x ->
rpm-build 0f2925
      Buffer.add_char b x
rpm-build 0f2925
    );
rpm-build 0f2925
    out_output = (fun s p l ->
rpm-build 0f2925
      Buffer.add_subbytes b s p l;
rpm-build 0f2925
      l
rpm-build 0f2925
    );
rpm-build 0f2925
    out_close = (fun () ->
rpm-build 0f2925
      let s = Buffer.contents b in
rpm-build 0f2925
      ExtString.String.enum s
rpm-build 0f2925
    );
rpm-build 0f2925
    out_flush = (fun () -> ());
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let pipe() =
rpm-build 0f2925
  let input = ref "" in
rpm-build 0f2925
  let inpos = ref 0 in
rpm-build 0f2925
  let output = Buffer.create 0 in
rpm-build 0f2925
  let flush() =
rpm-build 0f2925
    input := Buffer.contents output;
rpm-build 0f2925
    inpos := 0;
rpm-build 0f2925
    Buffer.reset output;
rpm-build 0f2925
    if String.length !input = 0 then raise No_more_input
rpm-build 0f2925
  in
rpm-build 0f2925
  let read() =
rpm-build 0f2925
    if !inpos = String.length !input then flush();
rpm-build 0f2925
    let c = String.unsafe_get !input !inpos in
rpm-build 0f2925
    incr inpos;
rpm-build 0f2925
    c
rpm-build 0f2925
  in
rpm-build 0f2925
  let input s p l =
rpm-build 0f2925
    if !inpos = String.length !input then flush();
rpm-build 0f2925
    let r = (if !inpos + l > String.length !input then String.length !input - !inpos else l) in
rpm-build 0f2925
    String.unsafe_blit !input !inpos s p r;
rpm-build 0f2925
    inpos := !inpos + r;
rpm-build 0f2925
    r
rpm-build 0f2925
  in
rpm-build 0f2925
  let write c =
rpm-build 0f2925
    Buffer.add_char output c
rpm-build 0f2925
  in
rpm-build 0f2925
  let output s p l =
rpm-build 0f2925
    Buffer.add_subbytes output s p l;
rpm-build 0f2925
    l
rpm-build 0f2925
  in
rpm-build 0f2925
  let input = {
rpm-build 0f2925
    in_read = read;
rpm-build 0f2925
    in_input = input;
rpm-build 0f2925
    in_close = (fun () -> ());
rpm-build 0f2925
  } in
rpm-build 0f2925
  let output = {
rpm-build 0f2925
    out_write = write;
rpm-build 0f2925
    out_output = output;
rpm-build 0f2925
    out_close = (fun () -> ());
rpm-build 0f2925
    out_flush = (fun () -> ());
rpm-build 0f2925
  } in
rpm-build 0f2925
  input , output
rpm-build 0f2925
rpm-build 0f2925
external cast_output : 'a output -> unit output = "%identity"
rpm-build 0f2925
rpm-build 0f2925
(* -------------------------------------------------------------- *)
rpm-build 0f2925
(* BINARY APIs *)
rpm-build 0f2925
rpm-build 0f2925
exception Overflow of string
rpm-build 0f2925
rpm-build 0f2925
let read_byte i = int_of_char (i.in_read())
rpm-build 0f2925
rpm-build 0f2925
let read_signed_byte i =
rpm-build 0f2925
  let c = int_of_char (i.in_read()) in
rpm-build 0f2925
  if c land 128 <> 0 then
rpm-build 0f2925
    c - 256
rpm-build 0f2925
  else
rpm-build 0f2925
    c
rpm-build 0f2925
rpm-build 0f2925
let read_string_into_buffer i =
rpm-build 0f2925
  let b = Buffer.create 8 in
rpm-build 0f2925
  let rec loop() =
rpm-build 0f2925
    let c = i.in_read() in
rpm-build 0f2925
    if c <> '\000' then begin
rpm-build 0f2925
      Buffer.add_char b c;
rpm-build 0f2925
      loop();
rpm-build 0f2925
    end;
rpm-build 0f2925
  in
rpm-build 0f2925
  loop();
rpm-build 0f2925
  b
rpm-build 0f2925
rpm-build 0f2925
let read_string i =
rpm-build 0f2925
  Buffer.contents
rpm-build 0f2925
    (read_string_into_buffer i)
rpm-build 0f2925
rpm-build 0f2925
let read_bytes i =
rpm-build 0f2925
  Buffer.to_bytes
rpm-build 0f2925
    (read_string_into_buffer i)
rpm-build 0f2925
rpm-build 0f2925
let read_line i =
rpm-build 0f2925
  let b = Buffer.create 8 in
rpm-build 0f2925
  let cr = ref false in
rpm-build 0f2925
  let rec loop() =
rpm-build 0f2925
    let c = i.in_read() in
rpm-build 0f2925
    match c with
rpm-build 0f2925
    | '\n' ->
rpm-build 0f2925
      ()
rpm-build 0f2925
    | '\r' ->
rpm-build 0f2925
      cr := true;
rpm-build 0f2925
      loop()
rpm-build 0f2925
    | _ when !cr ->
rpm-build 0f2925
      cr := false;
rpm-build 0f2925
      Buffer.add_char b '\r';
rpm-build 0f2925
      Buffer.add_char b c;
rpm-build 0f2925
      loop();
rpm-build 0f2925
    | _ ->
rpm-build 0f2925
      Buffer.add_char b c;
rpm-build 0f2925
      loop();
rpm-build 0f2925
  in
rpm-build 0f2925
  try
rpm-build 0f2925
    loop();
rpm-build 0f2925
    Buffer.contents b
rpm-build 0f2925
  with
rpm-build 0f2925
    No_more_input ->
rpm-build 0f2925
      if !cr then Buffer.add_char b '\r';
rpm-build 0f2925
      if Buffer.length b > 0 then
rpm-build 0f2925
        Buffer.contents b
rpm-build 0f2925
      else
rpm-build 0f2925
        raise No_more_input
rpm-build 0f2925
rpm-build 0f2925
let read_ui16 i =
rpm-build 0f2925
  let ch1 = read_byte i in
rpm-build 0f2925
  let ch2 = read_byte i in
rpm-build 0f2925
  ch1 lor (ch2 lsl 8)
rpm-build 0f2925
rpm-build 0f2925
let read_i16 i =
rpm-build 0f2925
  let ch1 = read_byte i in
rpm-build 0f2925
  let ch2 = read_byte i in
rpm-build 0f2925
  let n = ch1 lor (ch2 lsl 8) in
rpm-build 0f2925
  if ch2 land 128 <> 0 then
rpm-build 0f2925
    n - 65536
rpm-build 0f2925
  else
rpm-build 0f2925
    n
rpm-build 0f2925
rpm-build 0f2925
let sign_bit_i32 = lnot 0x7FFF_FFFF
rpm-build 0f2925
rpm-build 0f2925
let read_32 ~i31 ch =
rpm-build 0f2925
  let ch1 = read_byte ch in
rpm-build 0f2925
  let ch2 = read_byte ch in
rpm-build 0f2925
  let ch3 = read_byte ch in
rpm-build 0f2925
  let ch4 = read_byte ch in
rpm-build 0f2925
  if ch4 land 128 <> 0 then begin
rpm-build 0f2925
    if i31 && ch4 land 64 = 0 then raise (Overflow "read_i31");
rpm-build 0f2925
    ch1 lor (ch2 lsl 8) lor (ch3 lsl 16) lor ((ch4 land 127) lsl 24) lor sign_bit_i32
rpm-build 0f2925
  end else begin
rpm-build 0f2925
    if i31 && ch4 land 64 <> 0 then raise (Overflow "read_i31");
rpm-build 0f2925
    ch1 lor (ch2 lsl 8) lor (ch3 lsl 16) lor (ch4 lsl 24)
rpm-build 0f2925
  end
rpm-build 0f2925
rpm-build 0f2925
let read_i31 ch = read_32 ~i31:true ch
rpm-build 0f2925
let read_i32_as_int ch = read_32 ~i31:false ch
rpm-build 0f2925
rpm-build 0f2925
let read_i32 = read_i31
rpm-build 0f2925
rpm-build 0f2925
let read_real_i32 ch =
rpm-build 0f2925
  let ch1 = read_byte ch in
rpm-build 0f2925
  let ch2 = read_byte ch in
rpm-build 0f2925
  let ch3 = read_byte ch in
rpm-build 0f2925
  let base = Int32.of_int (ch1 lor (ch2 lsl 8) lor (ch3 lsl 16)) in
rpm-build 0f2925
  let big = Int32.shift_left (Int32.of_int (read_byte ch)) 24 in
rpm-build 0f2925
  Int32.logor base big
rpm-build 0f2925
rpm-build 0f2925
let read_i64 ch =
rpm-build 0f2925
  let ch1 = read_byte ch in
rpm-build 0f2925
  let ch2 = read_byte ch in
rpm-build 0f2925
  let ch3 = read_byte ch in
rpm-build 0f2925
  let ch4 = read_byte ch in
rpm-build 0f2925
  let base = Int64.of_int (ch1 lor (ch2 lsl 8) lor (ch3 lsl 16)) in
rpm-build 0f2925
  let small = Int64.logor base (Int64.shift_left (Int64.of_int ch4) 24) in
rpm-build 0f2925
  let big = Int64.of_int32 (read_real_i32 ch) in
rpm-build 0f2925
  Int64.logor (Int64.shift_left big 32) small
rpm-build 0f2925
rpm-build 0f2925
let read_float32 ch =
rpm-build 0f2925
  Int32.float_of_bits (read_real_i32 ch)
rpm-build 0f2925
rpm-build 0f2925
let read_double ch =
rpm-build 0f2925
  Int64.float_of_bits (read_i64 ch)
rpm-build 0f2925
rpm-build 0f2925
let write_byte o n =
rpm-build 0f2925
  (* doesn't test bounds of n in order to keep semantics of Pervasives.output_byte *)
rpm-build 0f2925
  write o (Char.unsafe_chr (n land 0xFF))
rpm-build 0f2925
rpm-build 0f2925
let write_string o s =
rpm-build 0f2925
  nwrite_string o s;
rpm-build 0f2925
  write o '\000'
rpm-build 0f2925
rpm-build 0f2925
let write_bytes o s =
rpm-build 0f2925
  nwrite o s;
rpm-build 0f2925
  write o '\000'
rpm-build 0f2925
rpm-build 0f2925
let write_line o s =
rpm-build 0f2925
  nwrite_string o s;
rpm-build 0f2925
  write o '\n'
rpm-build 0f2925
rpm-build 0f2925
let write_ui16 ch n =
rpm-build 0f2925
  if n < 0 || n > 0xFFFF then raise (Overflow "write_ui16");
rpm-build 0f2925
  write_byte ch n;
rpm-build 0f2925
  write_byte ch (n lsr 8)
rpm-build 0f2925
rpm-build 0f2925
let write_i16 ch n =
rpm-build 0f2925
  if n < -0x8000 || n > 0x7FFF then raise (Overflow "write_i16");
rpm-build 0f2925
  if n < 0 then
rpm-build 0f2925
    write_ui16 ch (65536 + n)
rpm-build 0f2925
  else
rpm-build 0f2925
    write_ui16 ch n
rpm-build 0f2925
rpm-build 0f2925
let write_32 ch n =
rpm-build 0f2925
  write_byte ch n;
rpm-build 0f2925
  write_byte ch (n lsr 8);
rpm-build 0f2925
  write_byte ch (n lsr 16);
rpm-build 0f2925
  write_byte ch (n asr 24)
rpm-build 0f2925
rpm-build 0f2925
let write_i31 ch n =
rpm-build 0f2925
#ifndef WORD_SIZE_32
rpm-build 0f2925
  if n < -0x4000_0000 || n > 0x3FFF_FFFF then raise (Overflow "write_i31");
rpm-build 0f2925
#endif
rpm-build 0f2925
  write_32 ch n
rpm-build 0f2925
rpm-build 0f2925
let write_i32 ch n =
rpm-build 0f2925
#ifndef WORD_SIZE_32
rpm-build 0f2925
  if n < -0x8000_0000 || n > 0x7FFF_FFFF then raise (Overflow "write_i32");
rpm-build 0f2925
#endif
rpm-build 0f2925
  write_32 ch n
rpm-build 0f2925
rpm-build 0f2925
let write_real_i32 ch n =
rpm-build 0f2925
  let base = Int32.to_int n in
rpm-build 0f2925
  let big = Int32.to_int (Int32.shift_right_logical n 24) in
rpm-build 0f2925
  write_byte ch base;
rpm-build 0f2925
  write_byte ch (base lsr 8);
rpm-build 0f2925
  write_byte ch (base lsr 16);
rpm-build 0f2925
  write_byte ch big
rpm-build 0f2925
rpm-build 0f2925
let write_i64 ch n =
rpm-build 0f2925
  write_real_i32 ch (Int64.to_int32 n);
rpm-build 0f2925
  write_real_i32 ch (Int64.to_int32 (Int64.shift_right_logical n 32))
rpm-build 0f2925
rpm-build 0f2925
let write_float32 ch f =
rpm-build 0f2925
  write_real_i32 ch (Int32.bits_of_float f)
rpm-build 0f2925
rpm-build 0f2925
let write_double ch f =
rpm-build 0f2925
  write_i64 ch (Int64.bits_of_float f)
rpm-build 0f2925
rpm-build 0f2925
(* -------------------------------------------------------------- *)
rpm-build 0f2925
(* Big Endians *)
rpm-build 0f2925
rpm-build 0f2925
module BigEndian = struct
rpm-build 0f2925
rpm-build 0f2925
let read_ui16 i =
rpm-build 0f2925
  let ch2 = read_byte i in
rpm-build 0f2925
  let ch1 = read_byte i in
rpm-build 0f2925
  ch1 lor (ch2 lsl 8)
rpm-build 0f2925
rpm-build 0f2925
let read_i16 i =
rpm-build 0f2925
  let ch2 = read_byte i in
rpm-build 0f2925
  let ch1 = read_byte i in
rpm-build 0f2925
  let n = ch1 lor (ch2 lsl 8) in
rpm-build 0f2925
  if ch2 land 128 <> 0 then
rpm-build 0f2925
    n - 65536
rpm-build 0f2925
  else
rpm-build 0f2925
    n
rpm-build 0f2925
rpm-build 0f2925
let sign_bit_i32 = lnot 0x7FFF_FFFF
rpm-build 0f2925
rpm-build 0f2925
let read_32 ~i31 ch =
rpm-build 0f2925
  let ch4 = read_byte ch in
rpm-build 0f2925
  let ch3 = read_byte ch in
rpm-build 0f2925
  let ch2 = read_byte ch in
rpm-build 0f2925
  let ch1 = read_byte ch in
rpm-build 0f2925
  if ch4 land 128 <> 0 then begin
rpm-build 0f2925
    if i31 && ch4 land 64 = 0 then raise (Overflow "read_i31");
rpm-build 0f2925
    ch1 lor (ch2 lsl 8) lor (ch3 lsl 16) lor ((ch4 land 127) lsl 24) lor sign_bit_i32
rpm-build 0f2925
  end else begin
rpm-build 0f2925
    if i31 && ch4 land 64 <> 0 then raise (Overflow "read_i31");
rpm-build 0f2925
    ch1 lor (ch2 lsl 8) lor (ch3 lsl 16) lor (ch4 lsl 24)
rpm-build 0f2925
  end
rpm-build 0f2925
rpm-build 0f2925
let read_i31 ch = read_32 ~i31:true ch
rpm-build 0f2925
let read_i32_as_int ch = read_32 ~i31:false ch
rpm-build 0f2925
rpm-build 0f2925
let read_i32 = read_i31
rpm-build 0f2925
rpm-build 0f2925
let read_real_i32 ch =
rpm-build 0f2925
  let big = Int32.shift_left (Int32.of_int (read_byte ch)) 24 in
rpm-build 0f2925
  let ch3 = read_byte ch in
rpm-build 0f2925
  let ch2 = read_byte ch in
rpm-build 0f2925
  let ch1 = read_byte ch in
rpm-build 0f2925
  let base = Int32.of_int (ch1 lor (ch2 lsl 8) lor (ch3 lsl 16)) in
rpm-build 0f2925
  Int32.logor base big
rpm-build 0f2925
rpm-build 0f2925
let read_i64 ch =
rpm-build 0f2925
  let big = Int64.of_int32 (read_real_i32 ch) in
rpm-build 0f2925
  let ch4 = read_byte ch in
rpm-build 0f2925
  let ch3 = read_byte ch in
rpm-build 0f2925
  let ch2 = read_byte ch in
rpm-build 0f2925
  let ch1 = read_byte ch in
rpm-build 0f2925
  let base = Int64.of_int (ch1 lor (ch2 lsl 8) lor (ch3 lsl 16)) in
rpm-build 0f2925
  let small = Int64.logor base (Int64.shift_left (Int64.of_int ch4) 24) in
rpm-build 0f2925
  Int64.logor (Int64.shift_left big 32) small
rpm-build 0f2925
rpm-build 0f2925
let read_float32 ch =
rpm-build 0f2925
  Int32.float_of_bits (read_real_i32 ch)
rpm-build 0f2925
rpm-build 0f2925
let read_double ch =
rpm-build 0f2925
  Int64.float_of_bits (read_i64 ch)
rpm-build 0f2925
rpm-build 0f2925
let write_ui16 ch n =
rpm-build 0f2925
  if n < 0 || n > 0xFFFF then raise (Overflow "write_ui16");
rpm-build 0f2925
  write_byte ch (n lsr 8);
rpm-build 0f2925
  write_byte ch n
rpm-build 0f2925
rpm-build 0f2925
let write_i16 ch n =
rpm-build 0f2925
  if n < -0x8000 || n > 0x7FFF then raise (Overflow "write_i16");
rpm-build 0f2925
  if n < 0 then
rpm-build 0f2925
    write_ui16 ch (65536 + n)
rpm-build 0f2925
  else
rpm-build 0f2925
    write_ui16 ch n
rpm-build 0f2925
rpm-build 0f2925
let write_32 ch n =
rpm-build 0f2925
  write_byte ch (n asr 24);
rpm-build 0f2925
  write_byte ch (n lsr 16);
rpm-build 0f2925
  write_byte ch (n lsr 8);
rpm-build 0f2925
  write_byte ch n
rpm-build 0f2925
rpm-build 0f2925
let write_i31 ch n =
rpm-build 0f2925
#ifndef WORD_SIZE_32
rpm-build 0f2925
  if n < -0x4000_0000 || n > 0x3FFF_FFFF then raise (Overflow "write_i31");
rpm-build 0f2925
#endif
rpm-build 0f2925
  write_32 ch n
rpm-build 0f2925
rpm-build 0f2925
let write_i32 ch n =
rpm-build 0f2925
#ifndef WORD_SIZE_32
rpm-build 0f2925
  if n < -0x8000_0000 || n > 0x7FFF_FFFF then raise (Overflow "write_i32");
rpm-build 0f2925
#endif
rpm-build 0f2925
  write_32 ch n
rpm-build 0f2925
rpm-build 0f2925
let write_real_i32 ch n =
rpm-build 0f2925
  let base = Int32.to_int n in
rpm-build 0f2925
  let big = Int32.to_int (Int32.shift_right_logical n 24) in
rpm-build 0f2925
  write_byte ch big;
rpm-build 0f2925
  write_byte ch (base lsr 16);
rpm-build 0f2925
  write_byte ch (base lsr 8);
rpm-build 0f2925
  write_byte ch base
rpm-build 0f2925
rpm-build 0f2925
let write_i64 ch n =
rpm-build 0f2925
  write_real_i32 ch (Int64.to_int32 (Int64.shift_right_logical n 32));
rpm-build 0f2925
  write_real_i32 ch (Int64.to_int32 n)
rpm-build 0f2925
rpm-build 0f2925
let write_float32 ch f =
rpm-build 0f2925
  write_real_i32 ch (Int32.bits_of_float f)
rpm-build 0f2925
rpm-build 0f2925
let write_double ch f =
rpm-build 0f2925
  write_i64 ch (Int64.bits_of_float f)
rpm-build 0f2925
rpm-build 0f2925
end
rpm-build 0f2925
rpm-build 0f2925
(* -------------------------------------------------------------- *)
rpm-build 0f2925
(* Bits API *)
rpm-build 0f2925
rpm-build 0f2925
type 'a bc = {
rpm-build 0f2925
  ch : 'a;
rpm-build 0f2925
  mutable nbits : int;
rpm-build 0f2925
  mutable bits : int;
rpm-build 0f2925
}
rpm-build 0f2925
rpm-build 0f2925
type in_bits = input bc
rpm-build 0f2925
type out_bits = unit output bc
rpm-build 0f2925
rpm-build 0f2925
exception Bits_error
rpm-build 0f2925
rpm-build 0f2925
let input_bits ch =
rpm-build 0f2925
  {
rpm-build 0f2925
    ch = ch;
rpm-build 0f2925
    nbits = 0;
rpm-build 0f2925
    bits = 0;
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let output_bits ch =
rpm-build 0f2925
  {
rpm-build 0f2925
    ch = cast_output ch;
rpm-build 0f2925
    nbits = 0;
rpm-build 0f2925
    bits = 0;
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let rec read_bits b n =
rpm-build 0f2925
  if b.nbits >= n then begin
rpm-build 0f2925
    let c = b.nbits - n in
rpm-build 0f2925
    let k = (b.bits asr c) land ((1 lsl n) - 1) in
rpm-build 0f2925
    b.nbits <- c;
rpm-build 0f2925
    k
rpm-build 0f2925
  end else begin
rpm-build 0f2925
    let k = read_byte b.ch in
rpm-build 0f2925
    if b.nbits >= 24 then begin
rpm-build 0f2925
      if n >= 31 then raise Bits_error;
rpm-build 0f2925
      let c = 8 + b.nbits - n in
rpm-build 0f2925
      let d = b.bits land ((1 lsl b.nbits) - 1) in
rpm-build 0f2925
      let d = (d lsl (8 - c)) lor (k lsr c) in
rpm-build 0f2925
      b.bits <- k;
rpm-build 0f2925
      b.nbits <- c;
rpm-build 0f2925
      d
rpm-build 0f2925
    end else begin
rpm-build 0f2925
      b.bits <- (b.bits lsl 8) lor k;
rpm-build 0f2925
      b.nbits <- b.nbits + 8;
rpm-build 0f2925
      read_bits b n;
rpm-build 0f2925
    end
rpm-build 0f2925
  end
rpm-build 0f2925
rpm-build 0f2925
let drop_bits b =
rpm-build 0f2925
  b.nbits <- 0
rpm-build 0f2925
rpm-build 0f2925
let rec write_bits b ~nbits x =
rpm-build 0f2925
  let n = nbits in
rpm-build 0f2925
  if n + b.nbits >= 32 then begin
rpm-build 0f2925
    if n > 31 then raise Bits_error;
rpm-build 0f2925
    let n2 = 32 - b.nbits - 1 in
rpm-build 0f2925
    let n3 = n - n2 in
rpm-build 0f2925
    write_bits b ~nbits:n2 (x asr n3);
rpm-build 0f2925
    write_bits b ~nbits:n3 (x land ((1 lsl n3) - 1));
rpm-build 0f2925
  end else begin
rpm-build 0f2925
    if n < 0 then raise Bits_error;
rpm-build 0f2925
    if (x < 0 || x > (1 lsl n - 1)) && n <> 31 then raise Bits_error;
rpm-build 0f2925
    b.bits <- (b.bits lsl n) lor x;
rpm-build 0f2925
    b.nbits <- b.nbits + n;
rpm-build 0f2925
    while b.nbits >= 8 do
rpm-build 0f2925
      b.nbits <- b.nbits - 8;
rpm-build 0f2925
      write_byte b.ch (b.bits asr b.nbits)
rpm-build 0f2925
    done
rpm-build 0f2925
  end
rpm-build 0f2925
rpm-build 0f2925
let flush_bits b =
rpm-build 0f2925
  if b.nbits > 0 then write_bits b (8 - b.nbits) 0
rpm-build 0f2925
rpm-build 0f2925
(* -------------------------------------------------------------- *)
rpm-build 0f2925
(* Generic IO *)
rpm-build 0f2925
rpm-build 0f2925
class in_channel ch =
rpm-build 0f2925
  object
rpm-build 0f2925
  method input s pos len = input ch s pos len
rpm-build 0f2925
  method close_in() = close_in ch
rpm-build 0f2925
  end
rpm-build 0f2925
rpm-build 0f2925
class out_channel ch =
rpm-build 0f2925
  object
rpm-build 0f2925
  method output s pos len = output ch s pos len
rpm-build 0f2925
  method flush() = flush ch
rpm-build 0f2925
  method close_out() = ignore(close_out ch)
rpm-build 0f2925
  end
rpm-build 0f2925
rpm-build 0f2925
class in_chars ch =
rpm-build 0f2925
  object
rpm-build 0f2925
  method get() = try read ch with No_more_input -> raise End_of_file
rpm-build 0f2925
  method close_in() = close_in ch
rpm-build 0f2925
  end
rpm-build 0f2925
rpm-build 0f2925
class out_chars ch =
rpm-build 0f2925
  object
rpm-build 0f2925
  method put t = write ch t
rpm-build 0f2925
  method flush() = flush ch
rpm-build 0f2925
  method close_out() = ignore(close_out ch)
rpm-build 0f2925
  end
rpm-build 0f2925
rpm-build 0f2925
let from_in_channel ch =
rpm-build 0f2925
  let cbuf = Bytes.create 1 in
rpm-build 0f2925
  let read() =
rpm-build 0f2925
    try
rpm-build 0f2925
      if ch#input cbuf 0 1 = 0 then raise Sys_blocked_io;
rpm-build 0f2925
      Bytes.unsafe_get cbuf 0
rpm-build 0f2925
    with
rpm-build 0f2925
      End_of_file -> raise No_more_input
rpm-build 0f2925
  in
rpm-build 0f2925
  let input s p l =
rpm-build 0f2925
    ch#input s p l
rpm-build 0f2925
  in
rpm-build 0f2925
  create_in
rpm-build 0f2925
    ~read
rpm-build 0f2925
    ~input
rpm-build 0f2925
    ~close:ch#close_in
rpm-build 0f2925
rpm-build 0f2925
let from_out_channel ch =
rpm-build 0f2925
  let cbuf = Bytes.create 1 in
rpm-build 0f2925
  let write c =
rpm-build 0f2925
    Bytes.unsafe_set cbuf 0 c;
rpm-build 0f2925
    if ch#output cbuf 0 1 = 0 then raise Sys_blocked_io;
rpm-build 0f2925
  in
rpm-build 0f2925
  let output s p l =
rpm-build 0f2925
    ch#output s p l
rpm-build 0f2925
  in
rpm-build 0f2925
  create_out
rpm-build 0f2925
    ~write
rpm-build 0f2925
    ~output
rpm-build 0f2925
    ~flush:ch#flush
rpm-build 0f2925
    ~close:ch#close_out
rpm-build 0f2925
rpm-build 0f2925
let from_in_chars ch =
rpm-build 0f2925
  let input s p l =
rpm-build 0f2925
    let i = ref 0 in
rpm-build 0f2925
    try
rpm-build 0f2925
      while !i < l do
rpm-build 0f2925
        Bytes.unsafe_set s (p + !i) (ch#get());
rpm-build 0f2925
        incr i
rpm-build 0f2925
      done;
rpm-build 0f2925
      l
rpm-build 0f2925
    with
rpm-build 0f2925
      End_of_file when !i > 0 ->
rpm-build 0f2925
        !i
rpm-build 0f2925
  in
rpm-build 0f2925
  create_in
rpm-build 0f2925
    ~read:ch#get
rpm-build 0f2925
    ~input
rpm-build 0f2925
    ~close:ch#close_in
rpm-build 0f2925
rpm-build 0f2925
let from_out_chars ch =
rpm-build 0f2925
  let output s p l =
rpm-build 0f2925
    for i = p to p + l - 1 do
rpm-build 0f2925
      ch#put (Bytes.unsafe_get s i)
rpm-build 0f2925
    done;
rpm-build 0f2925
    l
rpm-build 0f2925
  in
rpm-build 0f2925
  create_out
rpm-build 0f2925
    ~write:ch#put
rpm-build 0f2925
    ~output
rpm-build 0f2925
    ~flush:ch#flush
rpm-build 0f2925
    ~close:ch#close_out