public int read() throws IOException {
   dieIfClosed();
   if (atEOD()) {
     return EOF;
   }
   int result = _currentBlock.readUByte();
   _current_offset++;
   if (_currentBlock.available() < 1) {
     _currentBlock = getDataInputBlock(_current_offset);
   }
   return result;
 }
 public int read(byte[] b, int off, int len) throws IOException {
   dieIfClosed();
   if (b == null) {
     throw new IllegalArgumentException("buffer must not be null");
   }
   if (off < 0 || len < 0 || b.length < off + len) {
     throw new IndexOutOfBoundsException("can't read past buffer boundaries");
   }
   if (len == 0) {
     return 0;
   }
   if (atEOD()) {
     return EOF;
   }
   int limit = Math.min(available(), len);
   readFully(b, off, limit);
   return limit;
 }
  public long skip(long n) throws IOException {
    dieIfClosed();
    if (n < 0) {
      return 0;
    }
    int new_offset = _current_offset + (int) n;

    if (new_offset < _current_offset) {

      // wrap around in converting a VERY large long to an int
      new_offset = _document_size;
    } else if (new_offset > _document_size) {
      new_offset = _document_size;
    }
    long rval = new_offset - _current_offset;

    _current_offset = new_offset;
    _currentBlock = getDataInputBlock(_current_offset);
    return rval;
  }