/**
  * Writes bytes to ZIP entry.
  *
  * @param b the byte array to write
  * @param offset the start position to write from
  * @param length the number of bytes to write
  * @throws IOException on error
  */
 @Override
 public void write(byte[] b, int offset, int length) throws IOException {
   if (entry == null) {
     throw new IllegalStateException("No current entry");
   }
   ZipUtil.checkRequestedFeatures(entry.entry);
   entry.hasWritten = true;
   if (entry.entry.getMethod() == DEFLATED) {
     writeDeflated(b, offset, length);
   } else {
     writeOut(b, offset, length);
     written += length;
   }
   crc.update(b, offset, length);
   count(length);
 }
 /** write implementation for DEFLATED entries. */
 private void writeDeflated(byte[] b, int offset, int length) throws IOException {
   if (length > 0 && !def.finished()) {
     entry.bytesRead += length;
     if (length <= DEFLATER_BLOCK_SIZE) {
       def.setInput(b, offset, length);
       deflateUntilInputIsNeeded();
     } else {
       final int fullblocks = length / DEFLATER_BLOCK_SIZE;
       for (int i = 0; i < fullblocks; i++) {
         def.setInput(b, offset + i * DEFLATER_BLOCK_SIZE, DEFLATER_BLOCK_SIZE);
         deflateUntilInputIsNeeded();
       }
       final int done = fullblocks * DEFLATER_BLOCK_SIZE;
       if (done < length) {
         def.setInput(b, offset + done, length - done);
         deflateUntilInputIsNeeded();
       }
     }
   }
 }
  /**
   * Get the existing ZIP64 extended information extra field or create a new one and add it to the
   * entry.
   *
   * @since 1.3
   */
  private Zip64ExtendedInformationExtraField getZip64Extra(ZipArchiveEntry ze) {
    if (entry != null) {
      entry.causedUseOfZip64 = !hasUsedZip64;
    }
    hasUsedZip64 = true;
    Zip64ExtendedInformationExtraField z64 =
        (Zip64ExtendedInformationExtraField)
            ze.getExtraField(Zip64ExtendedInformationExtraField.HEADER_ID);
    if (z64 == null) {
      /*
        System.err.println("Adding z64 for " + ze.getName()
        + ", method: " + ze.getMethod()
        + " (" + (ze.getMethod() == STORED) + ")"
        + ", raf: " + (raf != null));
      */
      z64 = new Zip64ExtendedInformationExtraField();
    }

    // even if the field is there already, make sure it is the first one
    ze.addAsFirstExtraField(z64);

    return z64;
  }
  /**
   * Writes the local file header entry
   *
   * @param ze the entry to write
   * @throws IOException on error
   */
  protected void writeLocalFileHeader(ZipArchiveEntry ze) throws IOException {

    boolean encodable = zipEncoding.canEncode(ze.getName());
    ByteBuffer name = getName(ze);

    if (createUnicodeExtraFields != UnicodeExtraFieldPolicy.NEVER) {
      addUnicodeExtraFields(ze, encodable, name);
    }

    offsets.put(ze, Long.valueOf(written));

    writeOut(LFH_SIG);
    written += WORD;

    // store method in local variable to prevent multiple method calls
    final int zipMethod = ze.getMethod();

    writeVersionNeededToExtractAndGeneralPurposeBits(
        zipMethod, !encodable && fallbackToUTF8, hasZip64Extra(ze));
    written += WORD;

    // compression method
    writeOut(ZipShort.getBytes(zipMethod));
    written += SHORT;

    // last mod. time and date
    writeOut(ZipUtil.toDosTime(ze.getTime()));
    written += WORD;

    // CRC
    // compressed length
    // uncompressed length
    entry.localDataStart = written;
    if (zipMethod == DEFLATED || raf != null) {
      writeOut(LZERO);
      if (hasZip64Extra(entry.entry)) {
        // point to ZIP64 extended information extra field for
        // sizes, may get rewritten once sizes are known if
        // stream is seekable
        writeOut(ZipLong.ZIP64_MAGIC.getBytes());
        writeOut(ZipLong.ZIP64_MAGIC.getBytes());
      } else {
        writeOut(LZERO);
        writeOut(LZERO);
      }
    } else {
      writeOut(ZipLong.getBytes(ze.getCrc()));
      byte[] size = ZipLong.ZIP64_MAGIC.getBytes();
      if (!hasZip64Extra(ze)) {
        size = ZipLong.getBytes(ze.getSize());
      }
      writeOut(size);
      writeOut(size);
    }
    // CheckStyle:MagicNumber OFF
    written += 12;
    // CheckStyle:MagicNumber ON

    // file name length
    writeOut(ZipShort.getBytes(name.limit()));
    written += SHORT;

    // extra field length
    byte[] extra = ze.getLocalFileDataExtra();
    writeOut(ZipShort.getBytes(extra.length));
    written += SHORT;

    // file name
    writeOut(name.array(), name.arrayOffset(), name.limit() - name.position());
    written += name.limit();

    // extra field
    writeOut(extra);
    written += extra.length;

    entry.dataStart = written;
  }