let zip ?(format=`raw)
?(level=Default.level) ?(zlib_buffer_size=Default.zlib_buffer_size) () =
let zstream = ref (Zlib.deflate_init level false) in
let in_buffer = Buffer.create 42 in
let zlib_write_buffer = String.create zlib_buffer_size in
dbg "zip init: level: %d, zlib_buffer_size: %d" level zlib_buffer_size;
let state =
ref (match format with `raw -> `deflating | `gzip -> `gzip_header) in
let this_is_the_end = ref false in
let update_crc, output_crc =
match format with
| `raw -> ((fun _ _ -> ()), (fun () -> ""))
| `gzip ->
let gzip_crc = ref 0l in
let gzip_size = ref 0l in
((fun buf used_in ->
gzip_crc := Zlib.update_crc !gzip_crc buf 0 used_in;
gzip_size := Int32.(!gzip_size + (of_int_exn used_in));
()),
(fun () ->
let buf = String.create 8 in
dbg "crc: %ld, size: %ld" !gzip_crc !gzip_size;
Binary_packing.pack_signed_32
~byte_order:`Little_endian ~pos:0 ~buf !gzip_crc;
Binary_packing.pack_signed_32
~byte_order:`Little_endian ~pos:4 ~buf !gzip_size;
buf))
in
let next stopped =
match state.contents with
| `gzip_header -> state := `deflating; `output gzip_default_header
| `deflating ->
let buffered = Buffer.contents in_buffer in
begin match String.length buffered with
| 0 ->
if stopped
then begin
if !this_is_the_end then `end_of_stream
else begin
let (_, _, used_out) =
Zlib.deflate !zstream "" 0 0
zlib_write_buffer 0 zlib_buffer_size Zlib.Z_FINISH in
let to_output =
if used_out < zlib_buffer_size then (
this_is_the_end := true;
Zlib.deflate_end !zstream;
String.(sub zlib_write_buffer 0 used_out ^ output_crc ())
) else (
String.(sub zlib_write_buffer 0 used_out)
) in
dbg "at the pseudo-end... used_out: %d, outputting %d bytes"
used_out String.(length to_output);
`output to_output
end
end
else `not_ready
| len ->
Buffer.clear in_buffer;
dbg "zip: len: %d" len;
let (_, used_in, used_out) =
Zlib.deflate !zstream buffered 0 len
zlib_write_buffer 0 zlib_buffer_size
Zlib.Z_SYNC_FLUSH
in
dbg "used_in: %d -- used_out: %d" used_in used_out;
update_crc buffered used_in;
if used_in < len
then (Buffer.add_substring in_buffer
buffered used_in (String.length buffered - used_in));
if used_out > 0 then
`output String.(sub zlib_write_buffer 0 used_out)
else
`not_ready
end
in
Biocaml_transform.make ()
~feed:(fun string -> Buffer.add_string in_buffer string;) ~next