Blame src/unzip.ml

rpm-build 0f2925
(*
rpm-build 0f2925
 * Unzip - inflate format decompression algorithm
rpm-build 0f2925
 * Copyright (C) 2004 Nicolas Cannasse
rpm-build 0f2925
 * Compliant with RFC 1950 and 1951
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 huffman =
rpm-build 0f2925
  | Found of int
rpm-build 0f2925
  | NeedBit of huffman * huffman
rpm-build 0f2925
  | NeedBits of int * huffman array
rpm-build 0f2925
rpm-build 0f2925
rpm-build 0f2925
type adler32 = {
rpm-build 0f2925
  mutable a1 : int;
rpm-build 0f2925
  mutable a2 : int;
rpm-build 0f2925
}
rpm-build 0f2925
rpm-build 0f2925
type window = {
rpm-build 0f2925
  mutable wbuffer : Bytes.t;
rpm-build 0f2925
  mutable wpos : int;
rpm-build 0f2925
  wcrc : adler32;
rpm-build 0f2925
}
rpm-build 0f2925
rpm-build 0f2925
type state =
rpm-build 0f2925
  | Head
rpm-build 0f2925
  | Block
rpm-build 0f2925
  | CData
rpm-build 0f2925
  | Flat
rpm-build 0f2925
  | Crc
rpm-build 0f2925
  | Dist
rpm-build 0f2925
  | DistOne
rpm-build 0f2925
  | Done
rpm-build 0f2925
rpm-build 0f2925
type t = {
rpm-build 0f2925
  mutable znbits : int;
rpm-build 0f2925
  mutable zbits : int;
rpm-build 0f2925
  mutable zstate : state;
rpm-build 0f2925
  mutable zfinal : bool;
rpm-build 0f2925
  mutable zhuffman : huffman;
rpm-build 0f2925
  mutable zhuffdist : huffman option;
rpm-build 0f2925
  mutable zlen : int;
rpm-build 0f2925
  mutable zdist : int;
rpm-build 0f2925
  mutable zneeded : int;
rpm-build 0f2925
  mutable zoutput : Bytes.t;
rpm-build 0f2925
  mutable zoutpos : int;
rpm-build 0f2925
  zinput : IO.input;
rpm-build 0f2925
  zlengths : int array;
rpm-build 0f2925
  zwindow : window;
rpm-build 0f2925
}
rpm-build 0f2925
rpm-build 0f2925
type error_msg =
rpm-build 0f2925
  | Invalid_huffman
rpm-build 0f2925
  | Invalid_data
rpm-build 0f2925
  | Invalid_crc
rpm-build 0f2925
  | Truncated_data
rpm-build 0f2925
  | Unsupported_dictionary
rpm-build 0f2925
rpm-build 0f2925
exception Error of error_msg
rpm-build 0f2925
rpm-build 0f2925
let error msg = raise (Error msg)
rpm-build 0f2925
rpm-build 0f2925
(* ************************************************************************ *)
rpm-build 0f2925
(* HUFFMAN TREES *)
rpm-build 0f2925
rpm-build 0f2925
let rec tree_depth = function
rpm-build 0f2925
  | Found _ -> 0
rpm-build 0f2925
  | NeedBits _ -> assert false
rpm-build 0f2925
  | NeedBit (a,b) ->
rpm-build 0f2925
    1 + min (tree_depth a) (tree_depth b)
rpm-build 0f2925
rpm-build 0f2925
let rec tree_compress t =
rpm-build 0f2925
  match tree_depth t with
rpm-build 0f2925
  | 0 -> t
rpm-build 0f2925
  | 1 ->
rpm-build 0f2925
    (match t with
rpm-build 0f2925
    | NeedBit (a,b) -> NeedBit (tree_compress a,tree_compress b)
rpm-build 0f2925
    | _ -> assert false)
rpm-build 0f2925
  | d ->
rpm-build 0f2925
    let size = 1 lsl d in
rpm-build 0f2925
    let tbl = Array.make size (Found (-1)) in
rpm-build 0f2925
    tree_walk tbl 0 0 d t;
rpm-build 0f2925
    NeedBits (d,tbl)
rpm-build 0f2925
rpm-build 0f2925
and tree_walk tbl p cd d = function
rpm-build 0f2925
  | NeedBit (a,b) when d > 0 ->
rpm-build 0f2925
    tree_walk tbl p (cd + 1) (d-1) a;
rpm-build 0f2925
    tree_walk tbl (p lor (1 lsl cd)) (cd + 1) (d-1) b;
rpm-build 0f2925
  | t ->
rpm-build 0f2925
    Array.set tbl p (tree_compress t)
rpm-build 0f2925
rpm-build 0f2925
let make_huffman lengths pos nlengths maxbits =
rpm-build 0f2925
  let counts = Array.make maxbits 0 in
rpm-build 0f2925
  for i = 0 to nlengths - 1 do
rpm-build 0f2925
    let p = Array.unsafe_get lengths (i + pos) in
rpm-build 0f2925
    if p >= maxbits then error Invalid_huffman;
rpm-build 0f2925
    Array.unsafe_set counts p (Array.unsafe_get counts p + 1);
rpm-build 0f2925
  done;
rpm-build 0f2925
  let code = ref 0 in
rpm-build 0f2925
  let tmp = Array.make maxbits 0 in
rpm-build 0f2925
  for i = 1 to maxbits - 2 do
rpm-build 0f2925
    code := (!code + Array.unsafe_get counts i) lsl 1;
rpm-build 0f2925
    Array.unsafe_set tmp i !code;
rpm-build 0f2925
  done;
rpm-build 0f2925
  let bits = Hashtbl.create 0 in
rpm-build 0f2925
  for i = 0 to nlengths - 1 do
rpm-build 0f2925
    let l = Array.unsafe_get lengths (i + pos) in
rpm-build 0f2925
    if l <> 0 then begin
rpm-build 0f2925
      let n = Array.unsafe_get tmp (l - 1) in
rpm-build 0f2925
      Array.unsafe_set tmp (l - 1) (n + 1);
rpm-build 0f2925
      Hashtbl.add bits (n,l) i;
rpm-build 0f2925
    end;
rpm-build 0f2925
  done;
rpm-build 0f2925
  let rec tree_make v l =
rpm-build 0f2925
    if l > maxbits then error Invalid_huffman;
rpm-build 0f2925
    try
rpm-build 0f2925
      Found (Hashtbl.find bits (v,l))
rpm-build 0f2925
    with
rpm-build 0f2925
      Not_found ->
rpm-build 0f2925
        NeedBit (tree_make (v lsl 1) (l + 1) , tree_make (v lsl 1 lor 1) (l + 1))
rpm-build 0f2925
  in
rpm-build 0f2925
  tree_compress (NeedBit (tree_make 0 1 , tree_make 1 1))
rpm-build 0f2925
rpm-build 0f2925
(* ************************************************************************ *)
rpm-build 0f2925
(* ADLER32 (CRC) *)
rpm-build 0f2925
rpm-build 0f2925
let adler32_create() = {
rpm-build 0f2925
  a1 = 1;
rpm-build 0f2925
  a2 = 0;
rpm-build 0f2925
}
rpm-build 0f2925
rpm-build 0f2925
let adler32_update a s p l =
rpm-build 0f2925
  let p = ref p in
rpm-build 0f2925
  for i = 0 to l - 1 do
rpm-build 0f2925
    let c = int_of_char (Bytes.unsafe_get s !p) in
rpm-build 0f2925
    a.a1 <- (a.a1 + c) mod 65521;
rpm-build 0f2925
    a.a2 <- (a.a2 + a.a1) mod 65521;
rpm-build 0f2925
    incr p;
rpm-build 0f2925
  done
rpm-build 0f2925
rpm-build 0f2925
let adler32_read ch =
rpm-build 0f2925
  let a2a = IO.read_byte ch in
rpm-build 0f2925
  let a2b = IO.read_byte ch in
rpm-build 0f2925
  let a1a = IO.read_byte ch in
rpm-build 0f2925
  let a1b = IO.read_byte ch in
rpm-build 0f2925
  {
rpm-build 0f2925
    a1 = (a1a lsl 8) lor a1b;
rpm-build 0f2925
    a2 = (a2a lsl 8) lor a2b;
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
(* ************************************************************************ *)
rpm-build 0f2925
(* WINDOW *)
rpm-build 0f2925
rpm-build 0f2925
let window_size = 1 lsl 15
rpm-build 0f2925
let buffer_size = 1 lsl 16
rpm-build 0f2925
rpm-build 0f2925
let window_create size = {
rpm-build 0f2925
    wbuffer = Bytes.create buffer_size;
rpm-build 0f2925
    wpos = 0;
rpm-build 0f2925
    wcrc = adler32_create()
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let window_slide w = 
rpm-build 0f2925
  adler32_update w.wcrc w.wbuffer 0 window_size;
rpm-build 0f2925
  let b = Bytes.create buffer_size in
rpm-build 0f2925
  w.wpos <- w.wpos - window_size;
rpm-build 0f2925
  Bytes.unsafe_blit w.wbuffer window_size b 0 w.wpos;
rpm-build 0f2925
  w.wbuffer <- b
rpm-build 0f2925
rpm-build 0f2925
let window_add_bytes w s p len =
rpm-build 0f2925
  if w.wpos + len > buffer_size then window_slide w;
rpm-build 0f2925
  Bytes.unsafe_blit s p w.wbuffer w.wpos len;
rpm-build 0f2925
  w.wpos <- w.wpos + len
rpm-build 0f2925
rpm-build 0f2925
let window_add_char w c =
rpm-build 0f2925
  if w.wpos = buffer_size then window_slide w;
rpm-build 0f2925
  Bytes.unsafe_set w.wbuffer w.wpos c;
rpm-build 0f2925
  w.wpos <- w.wpos + 1
rpm-build 0f2925
rpm-build 0f2925
let window_get_last_char w =
rpm-build 0f2925
  Bytes.unsafe_get w.wbuffer (w.wpos - 1)
rpm-build 0f2925
rpm-build 0f2925
let window_available w =
rpm-build 0f2925
  w.wpos
rpm-build 0f2925
rpm-build 0f2925
let window_checksum w =
rpm-build 0f2925
  adler32_update w.wcrc w.wbuffer 0 w.wpos;
rpm-build 0f2925
  w.wcrc
rpm-build 0f2925
rpm-build 0f2925
(* ************************************************************************ *)
rpm-build 0f2925
rpm-build 0f2925
let len_extra_bits_tbl = [|0;0;0;0;0;0;0;0;1;1;1;1;2;2;2;2;3;3;3;3;4;4;4;4;5;5;5;5;0;-1;-1|]
rpm-build 0f2925
let len_base_val_tbl = [|3;4;5;6;7;8;9;10;11;13;15;17;19;23;27;31;35;43;51;59;67;83;99;115;131;163;195;227;258|]
rpm-build 0f2925
let dist_extra_bits_tbl = [|0;0;0;0;1;1;2;2;3;3;4;4;5;5;6;6;7;7;8;8;9;9;10;10;11;11;12;12;13;13;-1;-1|]
rpm-build 0f2925
let dist_base_val_tbl = [|1;2;3;4;5;7;9;13;17;25;33;49;65;97;129;193;257;385;513;769;1025;1537;2049;3073;4097;6145;8193;12289;16385;24577|]
rpm-build 0f2925
let code_lengths_pos = [|16;17;18;0;8;7;9;6;10;5;11;4;12;3;13;2;14;1;15|]
rpm-build 0f2925
rpm-build 0f2925
let fixed_huffman = make_huffman (Array.init 288 (fun n ->
rpm-build 0f2925
                  if n <= 143 then 8
rpm-build 0f2925
                  else if n <= 255 then 9
rpm-build 0f2925
                  else if n <= 279 then 7
rpm-build 0f2925
                  else 8
rpm-build 0f2925
                )) 0 288 10
rpm-build 0f2925
rpm-build 0f2925
let get_bits z n =
rpm-build 0f2925
  while z.znbits < n do
rpm-build 0f2925
    z.zbits <- z.zbits lor ((IO.read_byte z.zinput) lsl z.znbits);
rpm-build 0f2925
    z.znbits <- z.znbits + 8;
rpm-build 0f2925
  done;
rpm-build 0f2925
  let b = z.zbits land (1 lsl n - 1) in
rpm-build 0f2925
  z.znbits <- z.znbits - n;
rpm-build 0f2925
  z.zbits <- z.zbits lsr n;
rpm-build 0f2925
  b
rpm-build 0f2925
rpm-build 0f2925
let get_bit z =
rpm-build 0f2925
  if z.znbits = 0 then begin
rpm-build 0f2925
    z.znbits <- 8;
rpm-build 0f2925
    z.zbits <- IO.read_byte z.zinput;
rpm-build 0f2925
  end;
rpm-build 0f2925
  let b = z.zbits land 1 = 1 in
rpm-build 0f2925
  z.znbits <- z.znbits - 1;
rpm-build 0f2925
  z.zbits <- z.zbits lsr 1;
rpm-build 0f2925
  b
rpm-build 0f2925
rpm-build 0f2925
let rec get_rev_bits z n =
rpm-build 0f2925
  if n = 0 then
rpm-build 0f2925
    0
rpm-build 0f2925
  else if get_bit z then
rpm-build 0f2925
    (1 lsl (n - 1)) lor (get_rev_bits z (n-1))
rpm-build 0f2925
  else
rpm-build 0f2925
    get_rev_bits z (n-1)
rpm-build 0f2925
rpm-build 0f2925
let reset_bits z =
rpm-build 0f2925
  z.zbits <- 0;
rpm-build 0f2925
  z.znbits <- 0
rpm-build 0f2925
rpm-build 0f2925
let add_bytes z s p l =
rpm-build 0f2925
  window_add_bytes z.zwindow s p l;
rpm-build 0f2925
  Bytes.unsafe_blit s p z.zoutput z.zoutpos l;
rpm-build 0f2925
  z.zneeded <- z.zneeded - l;
rpm-build 0f2925
  z.zoutpos <- z.zoutpos + l
rpm-build 0f2925
rpm-build 0f2925
let add_char z c =
rpm-build 0f2925
  window_add_char z.zwindow c;
rpm-build 0f2925
  Bytes.unsafe_set z.zoutput z.zoutpos c;
rpm-build 0f2925
  z.zneeded <- z.zneeded - 1;
rpm-build 0f2925
  z.zoutpos <- z.zoutpos + 1
rpm-build 0f2925
rpm-build 0f2925
let add_dist_one z n =
rpm-build 0f2925
  let c = window_get_last_char z.zwindow in
rpm-build 0f2925
  let s = Bytes.make n c in
rpm-build 0f2925
  add_bytes z s 0 n
rpm-build 0f2925
rpm-build 0f2925
let add_dist z d l =
rpm-build 0f2925
  add_bytes z z.zwindow.wbuffer (z.zwindow.wpos - d) l
rpm-build 0f2925
rpm-build 0f2925
let rec apply_huffman z = function
rpm-build 0f2925
  | Found n -> n
rpm-build 0f2925
  | NeedBit (a,b) -> apply_huffman z (if get_bit z then b else a)
rpm-build 0f2925
  | NeedBits (n,t) -> apply_huffman z (Array.unsafe_get t (get_bits z n))
rpm-build 0f2925
rpm-build 0f2925
let inflate_lengths z a max =
rpm-build 0f2925
  let i = ref 0 in
rpm-build 0f2925
  let prev = ref 0 in
rpm-build 0f2925
  while !i < max do
rpm-build 0f2925
    match apply_huffman z z.zhuffman with
rpm-build 0f2925
    | n when n <= 15 ->
rpm-build 0f2925
      prev := n;
rpm-build 0f2925
      Array.unsafe_set a !i n;
rpm-build 0f2925
      incr i
rpm-build 0f2925
    | 16 ->
rpm-build 0f2925
      let n = 3 + get_bits z 2 in
rpm-build 0f2925
      if !i + n > max then error Invalid_data;
rpm-build 0f2925
      for k = 0 to n - 1 do
rpm-build 0f2925
        Array.unsafe_set a !i !prev;
rpm-build 0f2925
        incr i;
rpm-build 0f2925
      done;
rpm-build 0f2925
    | 17 ->
rpm-build 0f2925
      let n = 3 + get_bits z 3 in
rpm-build 0f2925
      i := !i + n;
rpm-build 0f2925
      if !i > max then error Invalid_data;
rpm-build 0f2925
    | 18 ->
rpm-build 0f2925
      let n = 11 + get_bits z 7 in
rpm-build 0f2925
      i := !i + n;
rpm-build 0f2925
      if !i > max then error Invalid_data;
rpm-build 0f2925
    | _ ->
rpm-build 0f2925
      error Invalid_data
rpm-build 0f2925
  done
rpm-build 0f2925
rpm-build 0f2925
let rec inflate_loop z =
rpm-build 0f2925
  match z.zstate with
rpm-build 0f2925
  | Head ->
rpm-build 0f2925
    let cmf = IO.read_byte z.zinput in
rpm-build 0f2925
    let cm = cmf land 15 in
rpm-build 0f2925
    let cinfo = cmf lsr 4 in
rpm-build 0f2925
    if cm <> 8 || cinfo <> 7 then error Invalid_data;
rpm-build 0f2925
    let flg = IO.read_byte z.zinput in
rpm-build 0f2925
    (*let fcheck = flg land 31 in*)
rpm-build 0f2925
    let fdict = flg land 32 <> 0 in
rpm-build 0f2925
    (*let flevel = flg lsr 6 in*)
rpm-build 0f2925
    if (cmf lsl 8 + flg) mod 31 <> 0 then error Invalid_data;
rpm-build 0f2925
    if fdict then error Unsupported_dictionary;
rpm-build 0f2925
    z.zstate <- Block;
rpm-build 0f2925
    inflate_loop z
rpm-build 0f2925
  | Crc ->
rpm-build 0f2925
    let calc = window_checksum z.zwindow in
rpm-build 0f2925
    let crc = adler32_read z.zinput in
rpm-build 0f2925
    if calc <> crc then error Invalid_crc;
rpm-build 0f2925
    z.zstate <- Done;
rpm-build 0f2925
    inflate_loop z
rpm-build 0f2925
  | Done ->
rpm-build 0f2925
    ()
rpm-build 0f2925
  | Block ->
rpm-build 0f2925
    z.zfinal <- get_bit z;
rpm-build 0f2925
    let btype = get_bits z 2 in
rpm-build 0f2925
    (match btype with
rpm-build 0f2925
    | 0 -> (* no compression *)
rpm-build 0f2925
      z.zlen <- IO.read_ui16 z.zinput;
rpm-build 0f2925
      let nlen = IO.read_ui16 z.zinput in
rpm-build 0f2925
      if nlen <> 0xffff - z.zlen then error Invalid_data;
rpm-build 0f2925
      z.zstate <- Flat;
rpm-build 0f2925
      inflate_loop z;
rpm-build 0f2925
      reset_bits z
rpm-build 0f2925
    | 1 -> (* fixed Huffman *)
rpm-build 0f2925
      z.zhuffman <- fixed_huffman;
rpm-build 0f2925
      z.zhuffdist <- None;
rpm-build 0f2925
      z.zstate <- CData;
rpm-build 0f2925
      inflate_loop z
rpm-build 0f2925
    | 2 -> (* dynamic Huffman *)
rpm-build 0f2925
      let hlit = get_bits z 5 + 257 in
rpm-build 0f2925
      let hdist = get_bits z 5 + 1 in
rpm-build 0f2925
      let hclen = get_bits z 4 + 4 in
rpm-build 0f2925
      for i = 0 to hclen - 1 do
rpm-build 0f2925
        Array.unsafe_set z.zlengths (Array.unsafe_get code_lengths_pos i) (get_bits z 3);
rpm-build 0f2925
      done;
rpm-build 0f2925
      for i = hclen to 18 do
rpm-build 0f2925
        Array.unsafe_set z.zlengths (Array.unsafe_get code_lengths_pos i) 0;
rpm-build 0f2925
      done;
rpm-build 0f2925
      z.zhuffman <- make_huffman z.zlengths 0 19 8;
rpm-build 0f2925
      let lengths = Array.make (hlit + hdist) 0 in
rpm-build 0f2925
      inflate_lengths z lengths (hlit + hdist);
rpm-build 0f2925
      z.zhuffdist <- Some (make_huffman lengths hlit hdist 16);
rpm-build 0f2925
      z.zhuffman <- make_huffman lengths 0 hlit 16;      
rpm-build 0f2925
      z.zstate <- CData;
rpm-build 0f2925
      inflate_loop z
rpm-build 0f2925
    | _ ->
rpm-build 0f2925
      error Invalid_data)
rpm-build 0f2925
  | Flat ->
rpm-build 0f2925
    let rlen = min z.zlen z.zneeded in
rpm-build 0f2925
    let str = IO.nread z.zinput rlen in
rpm-build 0f2925
    let len = Bytes.length str in
rpm-build 0f2925
    z.zlen <- z.zlen - len;
rpm-build 0f2925
    add_bytes z str 0 len;
rpm-build 0f2925
    if z.zlen = 0 then z.zstate <- (if z.zfinal then Crc else Block);
rpm-build 0f2925
    if z.zneeded > 0 then inflate_loop z
rpm-build 0f2925
  | DistOne ->
rpm-build 0f2925
    let len = min z.zlen z.zneeded in
rpm-build 0f2925
    add_dist_one z len;
rpm-build 0f2925
    z.zlen <- z.zlen - len;
rpm-build 0f2925
    if z.zlen = 0 then z.zstate <- CData;
rpm-build 0f2925
    if z.zneeded > 0 then inflate_loop z
rpm-build 0f2925
  | Dist ->
rpm-build 0f2925
    while z.zlen > 0 && z.zneeded > 0 do
rpm-build 0f2925
      let len = min z.zneeded (min z.zlen z.zdist) in
rpm-build 0f2925
      add_dist z z.zdist len;
rpm-build 0f2925
      z.zlen <- z.zlen - len;
rpm-build 0f2925
    done;
rpm-build 0f2925
    if z.zlen = 0 then z.zstate <- CData;
rpm-build 0f2925
    if z.zneeded > 0 then inflate_loop z
rpm-build 0f2925
  | CData ->
rpm-build 0f2925
    match apply_huffman z z.zhuffman with
rpm-build 0f2925
    | n when n < 256 ->
rpm-build 0f2925
      add_char z (Char.unsafe_chr n);
rpm-build 0f2925
      if z.zneeded > 0 then inflate_loop z
rpm-build 0f2925
    | 256 ->
rpm-build 0f2925
      z.zstate <- if z.zfinal then Crc else Block;
rpm-build 0f2925
      inflate_loop z
rpm-build 0f2925
    | n ->
rpm-build 0f2925
      let n = n - 257 in
rpm-build 0f2925
      let extra_bits = Array.unsafe_get len_extra_bits_tbl n in
rpm-build 0f2925
      if extra_bits = -1 then error Invalid_data;
rpm-build 0f2925
      z.zlen <- (Array.unsafe_get len_base_val_tbl n) + (get_bits z extra_bits);
rpm-build 0f2925
      let dist_code = (match z.zhuffdist with None -> get_rev_bits z 5 | Some h -> apply_huffman z h) in
rpm-build 0f2925
      let extra_bits = Array.unsafe_get dist_extra_bits_tbl dist_code in
rpm-build 0f2925
      if extra_bits = -1 then error Invalid_data;
rpm-build 0f2925
      z.zdist <- (Array.unsafe_get dist_base_val_tbl dist_code) + (get_bits z extra_bits);
rpm-build 0f2925
      if z.zdist > window_available z.zwindow then error Invalid_data;
rpm-build 0f2925
      z.zstate <- (if z.zdist = 1 then DistOne else Dist);
rpm-build 0f2925
      inflate_loop z
rpm-build 0f2925
rpm-build 0f2925
let inflate_data z s pos len =
rpm-build 0f2925
  if pos < 0 || len < 0 || pos + len > Bytes.length s then invalid_arg "inflate_data";
rpm-build 0f2925
  z.zneeded <- len;
rpm-build 0f2925
  z.zoutpos <- pos;
rpm-build 0f2925
  z.zoutput <- s;
rpm-build 0f2925
  try
rpm-build 0f2925
    if len > 0 then inflate_loop z;
rpm-build 0f2925
    len - z.zneeded
rpm-build 0f2925
  with
rpm-build 0f2925
    IO.No_more_input -> error Truncated_data
rpm-build 0f2925
rpm-build 0f2925
let inflate_init ?(header=true) ch = 
rpm-build 0f2925
  {
rpm-build 0f2925
    zfinal = false;
rpm-build 0f2925
    zhuffman = fixed_huffman;
rpm-build 0f2925
    zhuffdist = None;
rpm-build 0f2925
    zlen = 0;
rpm-build 0f2925
    zdist = 0;
rpm-build 0f2925
    zstate = (if header then Head else Block);
rpm-build 0f2925
    zinput = ch;
rpm-build 0f2925
    zbits = 0;
rpm-build 0f2925
    znbits = 0;
rpm-build 0f2925
    zneeded = 0;
rpm-build 0f2925
    zoutput = Bytes.empty;
rpm-build 0f2925
    zoutpos = 0;
rpm-build 0f2925
    zlengths = Array.make 19 (-1);
rpm-build 0f2925
    zwindow = window_create (1 lsl 15)
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let inflate ?(header=true) ch =
rpm-build 0f2925
  let z = inflate_init ~header ch in
rpm-build 0f2925
  let s = Bytes.create 1 in
rpm-build 0f2925
  IO.create_in
rpm-build 0f2925
    ~read:(fun() ->
rpm-build 0f2925
      let l = inflate_data z s 0 1 in
rpm-build 0f2925
      if l = 1 then Bytes.unsafe_get s 0 else raise IO.No_more_input
rpm-build 0f2925
    )
rpm-build 0f2925
    ~input:(fun s p l ->
rpm-build 0f2925
      let n = inflate_data z s p l in
rpm-build 0f2925
      if n = 0 then raise IO.No_more_input;
rpm-build 0f2925
      n
rpm-build 0f2925
    )
rpm-build 0f2925
    ~close:(fun () ->
rpm-build 0f2925
      IO.close_in ch
rpm-build 0f2925
    )