/*
   * Internal constructor.  Creates a new ZipEntry by reading the
   * Central Directory Entry (CDE) from "in", which must be positioned
   * at the CDE signature.
   *
   * On exit, "in" will be positioned at the start of the next entry
   * in the Central Directory.
   */
  ZipEntry(byte[] cdeHdrBuf, InputStream cdStream) throws IOException {
    Streams.readFully(cdStream, cdeHdrBuf, 0, cdeHdrBuf.length);

    BufferIterator it =
        HeapBufferIterator.iterator(cdeHdrBuf, 0, cdeHdrBuf.length, ByteOrder.LITTLE_ENDIAN);

    int sig = it.readInt();
    if (sig != CENSIG) {
      ZipFile.throwZipException("Central Directory Entry", sig);
    }

    it.seek(8);
    int gpbf = it.readShort() & 0xffff;

    if ((gpbf & ZipFile.GPBF_UNSUPPORTED_MASK) != 0) {
      throw new ZipException("Invalid General Purpose Bit Flag: " + gpbf);
    }

    compressionMethod = it.readShort() & 0xffff;
    time = it.readShort() & 0xffff;
    modDate = it.readShort() & 0xffff;

    // These are 32-bit values in the file, but 64-bit fields in this object.
    crc = ((long) it.readInt()) & 0xffffffffL;
    compressedSize = ((long) it.readInt()) & 0xffffffffL;
    size = ((long) it.readInt()) & 0xffffffffL;

    nameLength = it.readShort() & 0xffff;
    int extraLength = it.readShort() & 0xffff;
    int commentByteCount = it.readShort() & 0xffff;

    // This is a 32-bit value in the file, but a 64-bit field in this object.
    it.seek(42);
    localHeaderRelOffset = ((long) it.readInt()) & 0xffffffffL;

    byte[] nameBytes = new byte[nameLength];
    Streams.readFully(cdStream, nameBytes, 0, nameBytes.length);
    if (containsNulByte(nameBytes)) {
      throw new ZipException("Filename contains NUL byte: " + Arrays.toString(nameBytes));
    }
    name = new String(nameBytes, 0, nameBytes.length, StandardCharsets.UTF_8);

    if (extraLength > 0) {
      extra = new byte[extraLength];
      Streams.readFully(cdStream, extra, 0, extraLength);
    }

    // The RI has always assumed UTF-8. (If GPBF_UTF8_FLAG isn't set, the encoding is
    // actually IBM-437.)
    if (commentByteCount > 0) {
      byte[] commentBytes = new byte[commentByteCount];
      Streams.readFully(cdStream, commentBytes, 0, commentByteCount);
      comment = new String(commentBytes, 0, commentBytes.length, StandardCharsets.UTF_8);
    }
  }
 /** Copy a {@link Resources#openRawResource(int)} into {@link File} for testing purposes. */
 private void stageFile(int rawId, File file) throws Exception {
   new File(file.getParent()).mkdirs();
   InputStream in = null;
   OutputStream out = null;
   try {
     in = getContext().getResources().openRawResource(rawId);
     out = new FileOutputStream(file);
     Streams.copy(in, out);
   } finally {
     IoUtils.closeQuietly(in);
     IoUtils.closeQuietly(out);
   }
 }
 public void write(int oneByte) throws IOException {
   Streams.writeSingleByte(this, oneByte);
 }
 /**
  * Skip up to {@code byteCount} bytes of data on the underlying input stream. Any skipped bytes
  * are added to the running checksum value.
  *
  * @param byteCount the number of bytes to skip.
  * @throws IOException if this stream is closed or another I/O error occurs.
  * @return the number of bytes skipped.
  */
 @Override
 public long skip(long byteCount) throws IOException {
   return Streams.skipByReading(this, byteCount);
 }