diff --git a/zip.ml b/zip.ml index 1b1ac3c..fc1aa9c 100644 --- a/zip.ml +++ b/zip.ml @@ -418,8 +418,9 @@ let read_entry ifile e = "wrong size for deflated entry (too much data)")); Bytes.blit buf 0 res !out_pos len; out_pos := !out_pos + len) - with Zlib.Error(_, _) -> - raise (Error(ifile.if_filename, e.filename, "decompression error")) + with Zlib.Error(_, msg) -> + raise (Error(ifile.if_filename, e.filename, + "decompression error: " ^ msg)) end; if !out_pos <> Bytes.length res then raise (Error(ifile.if_filename, e.filename, @@ -463,8 +464,9 @@ let copy_entry_to_channel ifile e oc = (fun buf len -> output oc buf 0 len; crc := Zlib.update_crc !crc buf 0 len) - with Zlib.Error(_, _) -> - raise (Error(ifile.if_filename, e.filename, "decompression error")) + with Zlib.Error(_, msg) -> + raise (Error(ifile.if_filename, e.filename, + "decompression error: " ^ msg)) end; if !crc <> e.crc then raise (Error(ifile.if_filename, e.filename, "CRC mismatch")) @@ -677,8 +679,9 @@ let add_entry data ofile ?(comment = "") output ofile.of_channel buf 0 n; out_pos := !out_pos + n); !out_pos - with Zlib.Error(_, _) -> - raise (Error(ofile.of_filename, name, "compression error")) in + with Zlib.Error(_, msg) -> + raise (Error(ofile.of_filename, name, + "compression error: " ^ msg)) in let e' = update_entry ofile crc compr_size (String.length data) e in ofile.of_entries <- e' :: ofile.of_entries @@ -715,8 +718,9 @@ let copy_channel_to_entry ic ofile ?(comment = "") output ofile.of_channel buf 0 n; out_pos := !out_pos + n); (!out_pos, !in_pos) - with Zlib.Error(_, _) -> - raise (Error(ofile.of_filename, name, "compression error")) in + with Zlib.Error(_, msg) -> + raise (Error(ofile.of_filename, name, + "compression error: " ^ msg)) in let e' = update_entry ofile !crc compr_size uncompr_size e in ofile.of_entries <- e' :: ofile.of_entries @@ -781,14 +785,16 @@ let add_entry_generator ofile ?(comment = "") send buf pos len; uncompr_size := !uncompr_size + len; crc := Zlib.update_crc !crc buf pos len - with Zlib.Error(_, _) -> - raise (Error(ofile.of_filename, name, "compression error")) + with Zlib.Error(_, msg) -> + raise (Error(ofile.of_filename, name, + "compression error: " ^ msg)) ), (fun () -> check (); try flush (); finish () - with Zlib.Error(_, _) -> - raise (Error(ofile.of_filename, name, "compression error")) + with Zlib.Error(_, msg) -> + raise (Error(ofile.of_filename, name, + "compression error: " ^ msg)) ) diff --git a/zlib.ml b/zlib.ml index 2053536..c5a1f5f 100644 --- a/zlib.ml +++ b/zlib.ml @@ -106,22 +106,30 @@ let uncompress ?(header = true) refill flush = let rec uncompr inpos inavail = if inavail = 0 then begin let incount = refill inbuf in - if incount = 0 then uncompr_finish true else uncompr 0 incount + if incount = 0 then uncompr_finish 0 else uncompr 0 incount end else begin let (finished, used_in, used_out) = inflate zs inbuf inpos inavail outbuf 0 buffer_size Z_SYNC_FLUSH in flush outbuf used_out; if not finished then uncompr (inpos + used_in) (inavail - used_in) end - and uncompr_finish first_finish = + and uncompr_finish num_round = (* Gotcha: if there is no header, inflate requires an extra "dummy" byte after the compressed stream in order to complete decompression and return finished = true. *) - let dummy_byte = if first_finish && not header then 1 else 0 in + let dummy_byte = if num_round = 0 && not header then 1 else 0 in let (finished, _, used_out) = inflate zs inbuf 0 dummy_byte outbuf 0 buffer_size Z_SYNC_FLUSH in flush outbuf used_out; - if not finished then uncompr_finish false + if finished then () + else if used_out > 0 then uncompr_finish 1 + else if num_round < 10 then uncompr_finish (num_round + 1) + else + (* Gotcha: truncated input can cause an infinite loop where + [inflate] doesn't produce output and never returns "finished". + Raise an error after too many calls to [inflate] that produced + no output. *) + raise(Error("Zlib.uncompress", "truncated input data")) in uncompr 0 0; inflate_end zs