let input iz buf pos len =
  let n = String.length buf in
  if pos < 0 || len < 0 || pos + len > n then raise (Invalid_argument "Biocaml_bgzf.input") ;
  if iz.in_eof then 0
  else (
    let rec loop pos len read =
      if len = 0 then read
      else (
        let reached_eof =
          if iz.in_avail = 0 then (
            try read_block iz ; false
            with End_of_file -> true
          )
          else false
        in
        if reached_eof then read
        else (
          let (finished, used_in, used_out) =
            try Zlib.inflate iz.in_stream iz.in_block iz.in_pos iz.in_avail buf pos len Zlib.Z_SYNC_FLUSH
            with Zlib.Error(_, _) -> raise(Parse_error("error during decompression"))
          in
          iz.in_pos <- iz.in_pos + used_in;
          iz.in_avail <- iz.in_avail - used_in;
          iz.in_block_crc32 <- Zlib.update_crc iz.in_block_crc32 buf pos used_out;
          iz.in_block_isize <- Int32.add iz.in_block_isize (Int32.of_int used_out);
          if finished then (
            Zlib.inflate_end iz.in_stream ;
            if iz.in_block_crc32 <> iz.in_crc32 then raise(Parse_error(sprintf "CRC mismatch, data corrupted: %ld %ld" iz.in_block_crc32 iz.in_crc32));
            if iz.in_block_isize <> iz.in_block_isize then raise(Parse_error("size mismatch, data corrupted"));
            iz.in_stream <- Zlib.inflate_init false
          ) ;
          loop (pos + used_out) (len - used_out) (read + used_out)
        )
      )
    in
    loop pos len 0
  )