|
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 |
)
|