Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
decompressor.ml1 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 175let log2 x = log x /. log 2.0 |> int_of_float module Context = struct type t = { dctx : Bindings.decompression_context; mutex : Mutex.t } let create () = { dctx = Bindings.create_decompression_context (); mutex = Mutex.create () } let set_size_limit context size = Bindings.set_decompression_context_parameter context.dctx 100 (log2 @@ float_of_int size) let load_dictionary context dict = Bindings.load_decompression_dictionary context.dctx dict end let decompress_string_into_bytes ?context ?dictionary compressed_string uncompressed_output_bytes = match (context, dictionary) with | None, None -> Bindings.decompress_string compressed_string uncompressed_output_bytes | Some context, None -> Mutex.protect context.Context.mutex @@ fun () -> Bindings.decompress_string_with_context context.dctx compressed_string uncompressed_output_bytes | Some context, Some dictionary -> Mutex.protect context.Context.mutex @@ fun () -> Bindings.decompress_string_with_context_and_dictionary context.dctx dictionary compressed_string uncompressed_output_bytes | None, Some dictionary -> Bindings.decompress_string_with_context_and_dictionary Context.(create ()).dctx dictionary compressed_string uncompressed_output_bytes let decompress_string ?context ?dictionary compressed_string = let uncompressed_output_bytes = Bytes.create @@ Bindings.get_decompression_size_of_string compressed_string in decompress_string_into_bytes ?context ?dictionary compressed_string uncompressed_output_bytes |> ignore; Bytes.unsafe_to_string uncompressed_output_bytes let decompress_bigstring_into ?context ?dictionary compressed_bigstring uncompressed_output_bigstring = match (context, dictionary) with | None, None -> Bindings.decompress_bigstring compressed_bigstring uncompressed_output_bigstring | Some context, None -> Mutex.protect context.Context.mutex @@ fun () -> Bindings.decompress_bigstring_with_context context.dctx compressed_bigstring uncompressed_output_bigstring | Some context, Some dictionary -> Mutex.protect context.mutex @@ fun () -> Bindings.decompress_bigstring_with_context_and_dictionary context.dctx dictionary compressed_bigstring uncompressed_output_bigstring | None, Some dictionary -> Bindings.decompress_bigstring_with_context_and_dictionary Context.(create ()).dctx dictionary compressed_bigstring uncompressed_output_bigstring let decompress_bigstring ?context ?dictionary compressed_bigstring = let uncompressed_output_bigstring = Bstr.create @@ Bindings.get_decompression_size_of_bigstring compressed_bigstring in decompress_bigstring_into ?context ?dictionary compressed_bigstring uncompressed_output_bigstring |> ignore; uncompressed_output_bigstring module Stream = struct type t = { dstream : Bindings.decompression_stream; mutex : Mutex.t; mutable closed : bool; } let load_dictionary (dstream : Bindings.decompression_stream) dict = Bindings.load_decompression_dictionary (Obj.magic dstream) dict let create ?dictionary ?size_limit () = let dstream = Bindings.create_decompression_stream () in Option.iter (fun size -> Bindings.set_decompression_stream_parameter dstream 100 @@ log2 @@ float_of_int size) size_limit; Option.iter (load_dictionary dstream) dictionary; { dstream; mutex = Mutex.create (); closed = false } let in_size () = Bindings.get_decompression_stream_in_size () and out_size () = Bindings.get_decompression_stream_out_size () exception Already_closed let decompress ~in_slice ~out_slice stream = if stream.closed then raise Already_closed; let remaining, consumed, decompressed = Mutex.protect stream.mutex @@ fun () -> Bindings.decompress_stream stream.dstream in_slice out_slice in (~remaining, ~consumed, ~decompressed) let close stream = if stream.closed then raise Already_closed else stream.closed <- true end module State = struct type t = { stream : Stream.t; out_buf : Bstr.t } let make ?out_buf ?stream () = { stream = (match stream with None -> Stream.create () | Some stream -> stream); out_buf = (match out_buf with | None -> Bstr.create @@ Stream.out_size () | Some out_buf -> out_buf); } let create ?dictionary ?size_limit () = { stream = Stream.create ?dictionary ?size_limit (); out_buf = Bstr.create @@ Stream.out_size (); } let feed state slice = let rec aux in_slice = let out_slice = Slice_bstr.make state.out_buf in let ~remaining, ~consumed, ~decompressed = Stream.decompress ~in_slice ~out_slice state.stream in let in_slice_len = Slice_bstr.length in_slice in if (remaining > 0 || consumed > 0) && consumed < in_slice_len then aux @@ Slice_bstr.sub ~off:consumed ~len:(in_slice_len - consumed) in_slice else Slice_bstr.sub ~off:0 ~len:decompressed out_slice in aux slice end let decompress_channel ?dictionary ?size_limit ic oc = let state = State.create ?dictionary ?size_limit () in let in_buf = Bstr.create @@ Stream.in_size () in let rec loop () = match In_channel.input_bigarray ic in_buf 0 (Bstr.length in_buf) with | 0 -> () | len -> let Slice.{ buf; off; len } = State.feed state Slice_bstr.(make ~off:0 ~len in_buf) in Out_channel.output_bigarray oc buf off len; loop () in loop (); (* State.finish state; *) Out_channel.flush oc