/**
   * Open the next entry from the zip archive, and return its description. If the previous entry
   * wasn't closed, this method will close it.
   */
  public ZipEntry getNextEntry() throws IOException {
    if (crc == null) throw new IOException("Stream closed.");
    if (entry != null) closeEntry();

    int header = readLeInt();
    if (header == CENSIG) {
      /* Central Header reached. */
      close();
      return null;
    }
    if (header != LOCSIG)
      throw new ZipException("Wrong Local header signature: " + Integer.toHexString(header));
    /* skip version */
    readLeShort();
    flags = readLeShort();
    method = readLeShort();
    int dostime = readLeInt();
    int crc = readLeInt();
    csize = readLeInt();
    size = readLeInt();
    int nameLen = readLeShort();
    int extraLen = readLeShort();

    if (method == ZipOutputStream.STORED && csize != size)
      throw new ZipException("Stored, but compressed != uncompressed");

    byte[] buffer = new byte[nameLen];
    readFully(buffer);
    String name;
    try {
      name = new String(buffer, "UTF-8");
    } catch (UnsupportedEncodingException uee) {
      throw new AssertionError(uee);
    }

    entry = createZipEntry(name);
    entryAtEOF = false;
    entry.setMethod(method);
    if ((flags & 8) == 0) {
      entry.setCrc(crc & 0xffffffffL);
      entry.setSize(size & 0xffffffffL);
      entry.setCompressedSize(csize & 0xffffffffL);
    }
    entry.setDOSTime(dostime);
    if (extraLen > 0) {
      byte[] extra = new byte[extraLen];
      readFully(extra);
      entry.setExtra(extra);
    }

    if (method == ZipOutputStream.DEFLATED && avail > 0) {
      System.arraycopy(buf, len - avail, buf, 0, avail);
      len = avail;
      avail = 0;
      inf.setInput(buf, 0, len);
    }
    return entry;
  }