@Test
  public void testUnshrinkEntry() throws Exception {
    ZipArchiveInputStream in =
        new ZipArchiveInputStream(new FileInputStream(getFile("SHRUNK.ZIP")));

    ZipArchiveEntry entry = in.getNextZipEntry();
    assertEquals("method", ZipMethod.UNSHRINKING.getCode(), entry.getMethod());
    assertTrue(in.canReadEntryData(entry));

    FileInputStream original = new FileInputStream(getFile("test1.xml"));
    try {
      assertArrayEquals(IOUtils.toByteArray(original), IOUtils.toByteArray(in));
    } finally {
      original.close();
    }

    entry = in.getNextZipEntry();
    assertEquals("method", ZipMethod.UNSHRINKING.getCode(), entry.getMethod());
    assertTrue(in.canReadEntryData(entry));

    original = new FileInputStream(getFile("test2.xml"));
    try {
      assertArrayEquals(IOUtils.toByteArray(original), IOUtils.toByteArray(in));
    } finally {
      original.close();
    }
  }
Beispiel #2
0
  /** extract zip file */
  public void extract(String outputDir) throws IOException {
    org.apache.commons.compress.archivers.zip.ZipFile file = null;
    InputStream in = null;
    OutputStream out = null;

    try {
      file = new org.apache.commons.compress.archivers.zip.ZipFile(fileName, fileEncoding);
      Enumeration<ZipArchiveEntry> entries = file.getEntries();
      while (entries.hasMoreElements()) {
        ZipArchiveEntry entry = entries.nextElement();
        String entryName = entry.getName();
        if (entry.isDirectory()) {
          forceMkdir(new File(outputDir + File.separator + entryName));
          continue;
        }
        out = openOutputStream(new File(outputDir + File.separator + entryName));
        in = file.getInputStream(entry);
        copy(in, out);
        closeQuietly(in);
        closeQuietly(out);
      }
    } finally {
      closeQuietly(in);
      closeQuietly(out);
      org.apache.commons.compress.archivers.zip.ZipFile.closeQuietly(file);
    }
  }
Beispiel #3
0
  @Test
  public void testThatExternalAttributesFieldIsFunctional() throws IOException {

    // Prepare some sample modes to write into the zip file.
    final ImmutableList<String> samples =
        ImmutableList.of("rwxrwxrwx", "rw-r--r--", "--x--x--x", "---------");

    for (String stringMode : samples) {
      long mode = MorePosixFilePermissions.toMode(PosixFilePermissions.fromString(stringMode));

      // Write a tiny sample zip file, which sets the external attributes per the
      // permission sample above.
      try (CustomZipOutputStream out =
          ZipOutputStreams.newOutputStream(output, OVERWRITE_EXISTING)) {
        CustomZipEntry entry = new CustomZipEntry("test");
        entry.setTime(System.currentTimeMillis());
        entry.setExternalAttributes(mode << 16);
        out.putNextEntry(entry);
        out.write(new byte[0]);
      }

      // Now re-read the zip file using apache's commons-compress, which supports parsing
      // the external attributes field.
      try (ZipFile in = new ZipFile(output.toFile())) {
        Enumeration<ZipArchiveEntry> entries = in.getEntries();
        ZipArchiveEntry entry = entries.nextElement();
        assertEquals(mode, entry.getExternalAttributes() >> 16);
        assertFalse(entries.hasMoreElements());
      }
    }
  }
  /**
   * Overwrite clone.
   *
   * @return a cloned copy of this ZipArchiveEntry
   */
  @Override
  public Object clone() {
    ZipArchiveEntry e = (ZipArchiveEntry) super.clone();

    e.setInternalAttributes(getInternalAttributes());
    e.setExternalAttributes(getExternalAttributes());
    e.setExtraFields(getAllExtraFieldsNoCopy());
    return e;
  }
 /**
  * Creates a new zip entry with fields taken from the specified zip entry.
  *
  * <p>Assumes the entry represents a directory if and only if the name ends with a forward slash
  * "/".
  *
  * @param entry the entry to get fields from
  * @throws ZipException on error
  */
 public ZipArchiveEntry(ZipArchiveEntry entry) throws ZipException {
   this((java.util.zip.ZipEntry) entry);
   setInternalAttributes(entry.getInternalAttributes());
   setExternalAttributes(entry.getExternalAttributes());
   setExtraFields(getAllExtraFieldsNoCopy());
   setPlatform(entry.getPlatform());
   GeneralPurposeBit other = entry.getGeneralPurposeBit();
   setGeneralPurposeBit(other == null ? null : (GeneralPurposeBit) other.clone());
 }
  /** Provides default values for compression method and last modification time. */
  private void setDefaults(ZipArchiveEntry entry) {
    if (entry.getMethod() == -1) { // not specified
      entry.setMethod(method);
    }

    if (entry.getTime() == -1) { // not specified
      entry.setTime(System.currentTimeMillis());
    }
  }
 private void extractZipInputStream(final ZipArchiveInputStream in) throws IOException {
   ZipArchiveEntry zae = in.getNextZipEntry();
   while (zae != null) {
     if (zae.getName().endsWith(".zip")) {
       extractZipInputStream(new ZipArchiveInputStream(in));
     }
     zae = in.getNextZipEntry();
   }
 }
 /**
  * If the mode is AsNeeded and the entry is a compressed entry of unknown size that gets written
  * to a non-seekable stream the change the default to Never.
  *
  * @since 1.3
  */
 private Zip64Mode getEffectiveZip64Mode(ZipArchiveEntry ze) {
   if (zip64Mode != Zip64Mode.AsNeeded
       || raf != null
       || ze.getMethod() != DEFLATED
       || ze.getSize() != ArchiveEntry.SIZE_UNKNOWN) {
     return zip64Mode;
   }
   return Zip64Mode.Never;
 }
 /**
  * Whether this stream is able to write the given entry.
  *
  * <p>May return false if it is set up to use encryption or a compression method that hasn't been
  * implemented yet.
  *
  * @since 1.1
  */
 @Override
 public boolean canWriteEntryData(ArchiveEntry ae) {
   if (ae instanceof ZipArchiveEntry) {
     ZipArchiveEntry zae = (ZipArchiveEntry) ae;
     return zae.getMethod() != ZipMethod.IMPLODING.getCode()
         && zae.getMethod() != ZipMethod.UNSHRINKING.getCode()
         && ZipUtil.canHandleEntryData(zae);
   }
   return false;
 }
Beispiel #10
0
  public ZipDirResource(File file) throws IOException {
    this.zipFile = new ZipFile(file);

    initialize();

    Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
    while (entries.hasMoreElements()) {
      ZipArchiveEntry zipArchiveEntry = entries.nextElement();
      String entryPath = zipArchiveEntry.getName();

      createResource(entryPath, zipArchiveEntry);
    }
  }
  /**
   * Test case for <a href="https://issues.apache.org/jira/browse/COMPRESS-264" >COMPRESS-264</a>.
   */
  @Test
  public void testReadingOfFirstStoredEntry() throws Exception {
    ZipArchiveInputStream in =
        new ZipArchiveInputStream(new FileInputStream(getFile("COMPRESS-264.zip")));

    try {
      ZipArchiveEntry ze = in.getNextZipEntry();
      assertEquals(5, ze.getSize());
      assertArrayEquals(new byte[] {'d', 'a', 't', 'a', '\n'}, IOUtils.toByteArray(in));
    } finally {
      in.close();
    }
  }
  public void testImplicitPermissions() throws IOException {
    File zipFile = getTestFile("target/output/zip-with-implicit-dirmode.zip");

    ZipArchiver archiver = getZipArchiver(zipFile);

    archiver.setDefaultDirectoryMode(0777);
    archiver.setDirectoryMode(0641);
    archiver.setFileMode(0222);
    archiver.addFile(new File("pom.xml"), "fizz/buzz/pom.xml");
    archiver.setDefaultDirectoryMode(0530);
    archiver.setDirectoryMode(-1); // Not forced mode
    archiver.setFileMode(0111);
    archiver.addFile(new File("pom.xml"), "fazz/bazz/pam.xml");
    archiver.createArchive();

    assertTrue(zipFile.exists());
    ZipFile zf = new ZipFile(zipFile);
    ZipArchiveEntry fizz = zf.getEntry("fizz/");
    assertEquals(040641, fizz.getUnixMode());
    ZipArchiveEntry pom = zf.getEntry("fizz/buzz/pom.xml");
    assertEquals(0100222, pom.getUnixMode());

    ZipArchiveEntry fazz = zf.getEntry("fazz/");
    assertEquals(040530, fazz.getUnixMode());
    ZipArchiveEntry pam = zf.getEntry("fazz/bazz/pam.xml");
    assertEquals(0100111, pam.getUnixMode());
  }
 /** @see "https://issues.apache.org/jira/browse/COMPRESS-176" */
 @Test
 public void winzipBackSlashWorkaround() throws Exception {
   ZipArchiveInputStream in = null;
   try {
     in = new ZipArchiveInputStream(new FileInputStream(getFile("test-winzip.zip")));
     ZipArchiveEntry zae = in.getNextZipEntry();
     zae = in.getNextZipEntry();
     zae = in.getNextZipEntry();
     assertEquals("\u00e4/", zae.getName());
   } finally {
     if (in != null) {
       in.close();
     }
   }
 }
  @Test
  public void testUnzipBZip2CompressedEntry() throws Exception {
    ZipArchiveInputStream in =
        new ZipArchiveInputStream(new FileInputStream(getFile("bzip2-zip.zip")));

    try {
      ZipArchiveEntry ze = in.getNextZipEntry();
      assertEquals(42, ze.getSize());
      byte[] expected = new byte[42];
      Arrays.fill(expected, (byte) 'a');
      assertArrayEquals(expected, IOUtils.toByteArray(in));
    } finally {
      in.close();
    }
  }
Beispiel #15
0
  @SuppressWarnings("unchecked")
  private static void unzipFolder(File uncompressFile, File descPathFile, boolean override) {

    ZipFile zipFile = null;
    try {
      zipFile = new ZipFile(uncompressFile, "GBK");

      Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
      while (entries.hasMoreElements()) {
        ZipArchiveEntry zipEntry = entries.nextElement();
        String name = zipEntry.getName();
        name = name.replace("\\", "/");

        File currentFile = new File(descPathFile, name);

        // 非覆盖 跳过
        if (currentFile.isFile() && currentFile.exists() && !override) {
          continue;
        }

        if (name.endsWith("/")) {
          currentFile.mkdirs();
          continue;
        } else {
          currentFile.getParentFile().mkdirs();
        }

        FileOutputStream fos = null;
        try {
          fos = new FileOutputStream(currentFile);
          InputStream is = zipFile.getInputStream(zipEntry);
          IOUtils.copy(is, fos);
        } finally {
          IOUtils.closeQuietly(fos);
        }
      }
    } catch (IOException e) {
      throw new RuntimeException("解压缩失败", e);
    } finally {
      if (zipFile != null) {
        try {
          zipFile.close();
        } catch (IOException e) {
        }
      }
    }
  }
 /**
  * If the entry needs Zip64 extra information inside the central directory then configure its
  * data.
  */
 private void handleZip64Extra(ZipArchiveEntry ze, long lfhOffset, boolean needsZip64Extra) {
   if (needsZip64Extra) {
     Zip64ExtendedInformationExtraField z64 = getZip64Extra(ze);
     if (ze.getCompressedSize() >= ZIP64_MAGIC || ze.getSize() >= ZIP64_MAGIC) {
       z64.setCompressedSize(new ZipEightByteInteger(ze.getCompressedSize()));
       z64.setSize(new ZipEightByteInteger(ze.getSize()));
     } else {
       // reset value that may have been set for LFH
       z64.setCompressedSize(null);
       z64.setSize(null);
     }
     if (lfhOffset >= ZIP64_MAGIC) {
       z64.setRelativeHeaderOffset(new ZipEightByteInteger(lfhOffset));
     }
     ze.setExtra();
   }
 }
  public void testOverddidenPermissions() throws IOException {
    File zipFile = getTestFile("target/output/zip-with-overriden-modes.zip");

    ZipArchiver archiver = getZipArchiver(zipFile);
    archiver.setDefaultDirectoryMode(0777);
    archiver.setDirectoryMode(0641);
    archiver.setFileMode(0777);
    archiver.addDirectory(new File("src/test/resources/symlinks/src"));
    archiver.createArchive();

    assertTrue(zipFile.exists());
    ZipFile zf = new ZipFile(zipFile);
    ZipArchiveEntry fizz = zf.getEntry("symDir");
    assertTrue(fizz.isUnixSymlink());
    ZipArchiveEntry symR = zf.getEntry("symR");
    assertTrue(symR.isUnixSymlink());
  }
Beispiel #18
0
 /**
  * Grab lists of all root-level files and all directories contained in the given archive.
  *
  * @param file .
  * @param files .
  * @param dirs .
  * @throws java.io.IOException .
  */
 protected static void grabFilesAndDirs(String file, List<String> dirs, List<String> files)
     throws IOException {
   File zipFile = new File(file);
   if (!zipFile.exists()) {
     Logger logger = new ConsoleLogger(Logger.LEVEL_INFO, "console");
     logger.error("JarArchive skipping non-existing file: " + zipFile.getAbsolutePath());
   } else if (zipFile.isDirectory()) {
     Logger logger = new ConsoleLogger(Logger.LEVEL_INFO, "console");
     logger.info("JarArchiver skipping indexJar " + zipFile + " because it is not a jar");
   } else {
     org.apache.commons.compress.archivers.zip.ZipFile zf = null;
     try {
       zf = new org.apache.commons.compress.archivers.zip.ZipFile(file, "utf-8");
       Enumeration<ZipArchiveEntry> entries = zf.getEntries();
       HashSet<String> dirSet = new HashSet<String>();
       while (entries.hasMoreElements()) {
         ZipArchiveEntry ze = entries.nextElement();
         String name = ze.getName();
         // avoid index for manifest-only jars.
         if (!name.equals(META_INF_NAME)
             && !name.equals(META_INF_NAME + '/')
             && !name.equals(INDEX_NAME)
             && !name.equals(MANIFEST_NAME)) {
           if (ze.isDirectory()) {
             dirSet.add(name);
           } else if (!name.contains("/")) {
             files.add(name);
           } else {
             // a file, not in the root
             // since the jar may be one without directory
             // entries, add the parent dir of this file as
             // well.
             dirSet.add(name.substring(0, name.lastIndexOf("/") + 1));
           }
         }
       }
       dirs.addAll(dirSet);
     } finally {
       if (zf != null) {
         zf.close();
       }
     }
   }
 }
 private void moveNext() {
   if (in != null) {
     try {
       entry = (ZipArchiveEntry) in.getNextEntry();
       while (entry != null) {
         if (!entry.getName().startsWith("_")
             && !entry.getName().startsWith(".")
             && isValid(entry.getName())) {
           next = new FileInputStreamWrapper(FilenameUtils.getName(entry.getName()), in);
           return;
         }
         entry = (ZipArchiveEntry) in.getNextEntry();
       }
     } catch (IOException e) {
       LOG.warn("Error in zip: " + e);
     }
     in.forceClose();
   }
 }
  @Override
  public List<XarEntry> getEntries(File xarFile) throws IOException {
    List<XarEntry> documents = null;

    FileInputStream fis = new FileInputStream(xarFile);
    ZipArchiveInputStream zis = new ZipArchiveInputStream(fis);

    try {
      for (ZipArchiveEntry zipEntry = zis.getNextZipEntry();
          zipEntry != null;
          zipEntry = zis.getNextZipEntry()) {
        if (!zipEntry.isDirectory()) {
          try {
            XarPageLimitedHandler documentHandler =
                new XarPageLimitedHandler(this.componentManager);

            parseDocument(zis, documentHandler);

            if (documents == null) {
              documents = new ArrayList<XarEntry>();
            }

            XarEntry xarEntry = documentHandler.getXarEntry();
            xarEntry.setEntryName(zipEntry.getName());

            documents.add(xarEntry);
          } catch (NotADocumentException e) {
            // Impossible to know that before parsing
          } catch (Exception e) {
            this.logger.error("Failed to parse document [" + zipEntry.getName() + "]", e);
          }
        }
      }
    } finally {
      zis.close();
    }

    return documents != null ? documents : Collections.<XarEntry>emptyList();
  }
 /** @see "https://issues.apache.org/jira/browse/COMPRESS-189" */
 @Test
 public void properUseOfInflater() throws Exception {
   ZipFile zf = null;
   ZipArchiveInputStream in = null;
   try {
     zf = new ZipFile(getFile("COMPRESS-189.zip"));
     ZipArchiveEntry zae = zf.getEntry("USD0558682-20080101.ZIP");
     in = new ZipArchiveInputStream(new BufferedInputStream(zf.getInputStream(zae)));
     ZipArchiveEntry innerEntry;
     while ((innerEntry = in.getNextZipEntry()) != null) {
       if (innerEntry.getName().endsWith("XML")) {
         assertTrue(0 < in.read());
       }
     }
   } finally {
     if (zf != null) {
       zf.close();
     }
     if (in != null) {
       in.close();
     }
   }
 }
  /**
   * 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;
  }
  /**
   * Adds UnicodeExtra fields for name and file comment if mode is ALWAYS or the data cannot be
   * encoded using the configured encoding.
   */
  private void addUnicodeExtraFields(ZipArchiveEntry ze, boolean encodable, ByteBuffer name)
      throws IOException {
    if (createUnicodeExtraFields == UnicodeExtraFieldPolicy.ALWAYS || !encodable) {
      ze.addExtraField(
          new UnicodePathExtraField(
              ze.getName(), name.array(), name.arrayOffset(), name.limit() - name.position()));
    }

    String comm = ze.getComment();
    if (comm != null && !"".equals(comm)) {

      boolean commentEncodable = zipEncoding.canEncode(comm);

      if (createUnicodeExtraFields == UnicodeExtraFieldPolicy.ALWAYS || !commentEncodable) {
        ByteBuffer commentB = getEntryEncoding(ze).encode(comm);
        ze.addExtraField(
            new UnicodeCommentExtraField(
                comm,
                commentB.array(),
                commentB.arrayOffset(),
                commentB.limit() - commentB.position()));
      }
    }
  }
 /**
  * Writes the data descriptor entry.
  *
  * @param ze the entry to write
  * @throws IOException on error
  */
 protected void writeDataDescriptor(ZipArchiveEntry ze) throws IOException {
   if (ze.getMethod() != DEFLATED || raf != null) {
     return;
   }
   writeOut(DD_SIG);
   writeOut(ZipLong.getBytes(ze.getCrc()));
   int sizeFieldSize = WORD;
   if (!hasZip64Extra(ze)) {
     writeOut(ZipLong.getBytes(ze.getCompressedSize()));
     writeOut(ZipLong.getBytes(ze.getSize()));
   } else {
     sizeFieldSize = DWORD;
     writeOut(ZipEightByteInteger.getBytes(ze.getCompressedSize()));
     writeOut(ZipEightByteInteger.getBytes(ze.getSize()));
   }
   written += 2 * WORD + 2 * sizeFieldSize;
 }
Beispiel #25
0
  private void createResource(String path, ZipArchiveEntry entry) {
    String[] childs = StringUtils.split(path, "/\\");

    ZipDirResource res = this;
    for (int i = 0; i < childs.length - 1; i++) {
      String name = childs[i];

      ZipDirResource child = (ZipDirResource) res.getDir(name);
      if (child == null) child = new ZipDirResource(res, zipFile);

      res.addResource(name, child);
      res = child;
    }

    if (entry.isDirectory()) {
      ZipDirResource child = new ZipDirResource(res, zipFile);
      child.setEntry(entry);
      res.addResource(childs[childs.length - 1], child);
    } else {
      ZipFileResource child = new ZipFileResource(res, zipFile, entry);
      res.addResource(childs[childs.length - 1], child);
    }
  }
Beispiel #26
0
 @Override
 public String getPath() {
   return entry.getName();
 }
  /**
   * Writes the central file header entry.
   *
   * @param ze the entry to write
   * @throws IOException on error
   * @throws Zip64RequiredException if the archive's size exceeds 4 GByte and {@link Zip64Mode
   *     #setUseZip64} is {@link Zip64Mode#Never}.
   */
  protected void writeCentralFileHeader(ZipArchiveEntry ze) throws IOException {
    writeOut(CFH_SIG);
    written += WORD;

    final long lfhOffset = offsets.get(ze).longValue();
    final boolean needsZip64Extra =
        hasZip64Extra(ze)
            || ze.getCompressedSize() >= ZIP64_MAGIC
            || ze.getSize() >= ZIP64_MAGIC
            || lfhOffset >= ZIP64_MAGIC;

    if (needsZip64Extra && zip64Mode == Zip64Mode.Never) {
      // must be the offset that is too big, otherwise an
      // exception would have been throw in putArchiveEntry or
      // closeArchiveEntry
      throw new Zip64RequiredException(Zip64RequiredException.ARCHIVE_TOO_BIG_MESSAGE);
    }

    handleZip64Extra(ze, lfhOffset, needsZip64Extra);

    // version made by
    // CheckStyle:MagicNumber OFF
    writeOut(
        ZipShort.getBytes(
            (ze.getPlatform() << 8)
                | (!hasUsedZip64 ? DATA_DESCRIPTOR_MIN_VERSION : ZIP64_MIN_VERSION)));
    written += SHORT;

    final int zipMethod = ze.getMethod();
    final boolean encodable = zipEncoding.canEncode(ze.getName());
    writeVersionNeededToExtractAndGeneralPurposeBits(
        zipMethod, !encodable && fallbackToUTF8, needsZip64Extra);
    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
    writeOut(ZipLong.getBytes(ze.getCrc()));
    if (ze.getCompressedSize() >= ZIP64_MAGIC || ze.getSize() >= ZIP64_MAGIC) {
      writeOut(ZipLong.ZIP64_MAGIC.getBytes());
      writeOut(ZipLong.ZIP64_MAGIC.getBytes());
    } else {
      writeOut(ZipLong.getBytes(ze.getCompressedSize()));
      writeOut(ZipLong.getBytes(ze.getSize()));
    }
    // CheckStyle:MagicNumber OFF
    written += 12;
    // CheckStyle:MagicNumber ON

    ByteBuffer name = getName(ze);

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

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

    // file comment length
    String comm = ze.getComment();
    if (comm == null) {
      comm = "";
    }

    ByteBuffer commentB = getEntryEncoding(ze).encode(comm);

    writeOut(ZipShort.getBytes(commentB.limit()));
    written += SHORT;

    // disk number start
    writeOut(ZERO);
    written += SHORT;

    // internal file attributes
    writeOut(ZipShort.getBytes(ze.getInternalAttributes()));
    written += SHORT;

    // external file attributes
    writeOut(ZipLong.getBytes(ze.getExternalAttributes()));
    written += WORD;

    // relative offset of LFH
    writeOut(ZipLong.getBytes(Math.min(lfhOffset, ZIP64_MAGIC)));
    written += WORD;

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

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

    // file comment
    writeOut(commentB.array(), commentB.arrayOffset(), commentB.limit() - commentB.position());
    written += commentB.limit();
  }
  /**
   * 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;
  }
 /**
  * Whether to addd a Zip64 extended information extra field to the local file header.
  *
  * <p>Returns true if
  *
  * <ul>
  *   <li>mode is Always
  *   <li>or we already know it is going to be needed
  *   <li>or the size is unknown and we can ensure it won't hurt other implementations if we add it
  *       (i.e. we can erase its usage
  * </ul>
  */
 private boolean shouldAddZip64Extra(ZipArchiveEntry entry, Zip64Mode mode) {
   return mode == Zip64Mode.Always
       || entry.getSize() >= ZIP64_MAGIC
       || entry.getCompressedSize() >= ZIP64_MAGIC
       || (entry.getSize() == ArchiveEntry.SIZE_UNKNOWN && raf != null && mode != Zip64Mode.Never);
 }
 private ByteBuffer getName(ZipArchiveEntry ze) throws IOException {
   return getEntryEncoding(ze).encode(ze.getName());
 }