public InputStream getInputStream(final ZipEntry ze) throws IOException, ZipException {
   if (!(ze instanceof Entry)) {
     return null;
   }
   final OffsetEntry offsetEntry = ((Entry) ze).getOffsetEntry();
   ZipUtil.checkRequestedFeatures(ze);
   final long start = offsetEntry.dataOffset;
   final BoundedInputStream bis = new BoundedInputStream(start, ze.getCompressedSize());
   switch (ze.getMethod()) {
     case 0:
       {
         return bis;
       }
     case 8:
       {
         bis.addDummy();
         final Inflater inflater = new Inflater(true);
         return new InflaterInputStream(bis, inflater) {
           public void close() throws IOException {
             super.close();
             inflater.end();
           }
         };
       }
     default:
       {
         throw new ZipException("Found unsupported compression method " + ze.getMethod());
       }
   }
 }
  // TODO - zipEntry might use extended local header
  protected void add(ZipEntry zipEntry, ZipFileEntryInputStream zipData, String password)
      throws IOException, UnsupportedEncodingException {
    AESEncrypter aesEncrypter = new AESEncrypterBC(password.getBytes("iso-8859-1"));

    ExtZipEntry entry = new ExtZipEntry(zipEntry.getName());
    entry.setMethod(zipEntry.getMethod());
    entry.setSize(zipEntry.getSize());
    entry.setCompressedSize(zipEntry.getCompressedSize() + 28);
    entry.setTime(zipEntry.getTime());
    entry.initEncryptedEntry();

    zipOS.putNextEntry(entry);
    // ZIP-file data contains: 1. salt 2. pwVerification 3. encryptedContent 4. authenticationCode
    zipOS.writeBytes(aesEncrypter.getSalt());
    zipOS.writeBytes(aesEncrypter.getPwVerification());

    byte[] data = new byte[1024];
    int read = zipData.read(data);
    while (read != -1) {
      aesEncrypter.encrypt(data, read);
      zipOS.writeBytes(data, 0, read);
      read = zipData.read(data);
    }

    byte[] finalAuthentication = aesEncrypter.getFinalAuthentication();
    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine(
          "finalAuthentication="
              + Arrays.toString(finalAuthentication)
              + " at pos="
              + zipOS.getWritten());
    }

    zipOS.writeBytes(finalAuthentication);
  }
  public ZipRepository(final InputStream in, final MimeRegistry mimeRegistry) throws IOException {
    this(mimeRegistry);

    final ZipInputStream zipIn = new ZipInputStream(in);
    try {
      ZipEntry nextEntry = zipIn.getNextEntry();
      while (nextEntry != null) {
        final String[] buildName = RepositoryUtilities.splitPath(nextEntry.getName(), "/");
        if (nextEntry.isDirectory()) {
          root.updateDirectoryEntry(buildName, 0, nextEntry);
        } else {
          final ByteArrayOutputStream bos = new ByteArrayOutputStream();
          final Deflater def = new Deflater(nextEntry.getMethod());
          try {
            final DeflaterOutputStream dos = new DeflaterOutputStream(bos, def);
            try {
              IOUtils.getInstance().copyStreams(zipIn, dos);
              dos.flush();
            } finally {
              dos.close();
            }
          } finally {
            def.end();
          }

          root.updateEntry(buildName, 0, nextEntry, bos.toByteArray());
        }

        zipIn.closeEntry();
        nextEntry = zipIn.getNextEntry();
      }
    } finally {
      zipIn.close();
    }
  }
Beispiel #4
0
  /**
   * Returns the options of an archive.
   *
   * @param ctx query context
   * @return entries
   * @throws QueryException query exception
   */
  private FElem options(final QueryContext ctx) throws QueryException {
    final B64 archive = (B64) checkType(checkItem(expr[0], ctx), AtomType.B64);
    String format = null;
    int level = -1;

    final ArchiveIn arch = ArchiveIn.get(archive.input(info), info);
    try {
      format = arch.format();
      while (arch.more()) {
        final ZipEntry ze = arch.entry();
        if (ze.isDirectory()) continue;
        level = ze.getMethod();
        break;
      }
    } catch (final IOException ex) {
      Util.debug(ex);
      ARCH_FAIL.thrw(info, ex);
    } finally {
      arch.close();
    }

    // create result element
    final FElem e = new FElem(Q_OPTIONS, NS);
    if (format != null) e.add(new FElem(Q_FORMAT).add(Q_VALUE, format));
    if (level >= 0) {
      final byte[] lvl = level == 8 ? DEFLATE : level == 0 ? STORED : UNKNOWN;
      e.add(new FElem(Q_ALGORITHM).add(Q_VALUE, lvl));
    }
    return e;
  }
Beispiel #5
0
  /**
   * Appends a zip64 extended info record to the extras contained in {@code ze}. If {@code ze}
   * contains no extras, a new extras array is created.
   */
  public static void insertZip64ExtendedInfoToExtras(ZipEntry ze) throws ZipException {
    final byte[] output;
    // We always write the size, uncompressed size and local rel header offset in all our
    // Zip64 extended info headers (in both the local file header as well as the central
    // directory). We always omit the disk number because we don't support spanned
    // archives anyway.
    //
    //  2 bytes : Zip64 Extended Info Header ID
    //  2 bytes : Zip64 Extended Info Field Size.
    //  8 bytes : Uncompressed size
    //  8 bytes : Compressed size
    //  8 bytes : Local header rel offset.
    // ----------
    // 28 bytes : total
    final int extendedInfoSize = 28;

    if (ze.extra == null) {
      output = new byte[extendedInfoSize];
    } else {
      // If the existing extras are already too big, we have no choice but to throw
      // an error.
      if (ze.extra.length + extendedInfoSize > 65535) {
        throw new ZipException("No space in extras for zip64 extended entry info");
      }

      // We copy existing extras over and put the zip64 extended info at the beginning. This
      // is to avoid breakages in the presence of "old style" extras which don't contain
      // headers and lengths. The spec is again silent about these inconsistencies.
      //
      // This means that people that for ZipOutputStream users, the value ZipEntry.getExtra
      // after an entry is written will be different from before. This shouldn't be an issue
      // in practice.
      output = new byte[ze.extra.length + extendedInfoSize];
      System.arraycopy(ze.extra, 0, output, extendedInfoSize, ze.extra.length);
    }

    ByteBuffer bb = ByteBuffer.wrap(output).order(ByteOrder.LITTLE_ENDIAN);
    bb.putShort(ZIP64_EXTENDED_INFO_HEADER_ID);
    // We subtract four because extendedInfoSize includes the ID and field
    // size itself.
    bb.putShort((short) (extendedInfoSize - 4));

    if (ze.getMethod() == ZipEntry.STORED) {
      bb.putLong(ze.size);
      bb.putLong(ze.compressedSize);
    } else {
      // Store these fields in the data descriptor instead.
      bb.putLong(0); // size.
      bb.putLong(0); // compressed size.
    }

    // The offset is only relevant in the central directory entry, but we write it out here
    // anyway, since we know what it is.
    bb.putLong(ze.localHeaderRelOffset);

    ze.extra = output;
  }
Beispiel #6
0
  public AesZipEntry(ZipEntry zipEntry) {
    super(zipEntry.getName());
    super.setMethod(zipEntry.getMethod());
    super.setSize(zipEntry.getSize());
    super.setCompressedSize(zipEntry.getCompressedSize() + 28);
    super.setTime(zipEntry.getTime());

    flag |= 1; // bit0 - encrypted
    // flag |= 8;  // bit3 - use data descriptor
  }
 /**
  * Dumps a zip entry into a string.
  *
  * @param ze a ZipEntry
  */
 private String dumpZipEntry(ZipEntry ze) {
   StringBuffer sb = new StringBuffer();
   if (ze.isDirectory()) {
     sb.append("d ");
   } else {
     sb.append("f ");
   }
   if (ze.getMethod() == ZipEntry.STORED) {
     sb.append("stored   ");
   } else {
     sb.append("defalted ");
   }
   sb.append(ze.getName());
   sb.append("\t");
   sb.append("" + ze.getSize());
   if (ze.getMethod() == ZipEntry.DEFLATED) {
     sb.append("/" + ze.getCompressedSize());
   }
   return (sb.toString());
 }
Beispiel #8
0
  /** Adds a new file entry to the ZIP output stream. */
  void addFile(ZipOutputStream zos, File file) throws IOException {
    String name = file.getPath();
    boolean isDir = file.isDirectory();
    if (isDir) {
      name = name.endsWith(File.separator) ? name : (name + File.separator);
    }
    name = entryName(name);

    if (name.equals("") || name.equals(".") || name.equals(zname)) {
      return;
    } else if ((name.equals(MANIFEST_DIR) || name.equals(MANIFEST_NAME)) && !Mflag) {
      if (vflag) {
        output(formatMsg("out.ignore.entry", name));
      }
      return;
    }

    long size = isDir ? 0 : file.length();

    if (vflag) {
      out.print(formatMsg("out.adding", name));
    }
    ZipEntry e = new ZipEntry(name);
    e.setTime(file.lastModified());
    if (size == 0) {
      e.setMethod(ZipEntry.STORED);
      e.setSize(0);
      e.setCrc(0);
    } else if (flag0) {
      crc32File(e, file);
    }
    zos.putNextEntry(e);
    if (!isDir) {
      copy(file, zos);
    }
    zos.closeEntry();
    /* report how much compression occurred. */
    if (vflag) {
      size = e.getSize();
      long csize = e.getCompressedSize();
      out.print(formatMsg2("out.size", String.valueOf(size), String.valueOf(csize)));
      if (e.getMethod() == ZipEntry.DEFLATED) {
        long ratio = 0;
        if (size != 0) {
          ratio = ((size - csize) * 100) / size;
        }
        output(formatMsg("out.deflated", String.valueOf(ratio)));
      } else {
        output(getMsg("out.stored"));
      }
    }
  }
 /**
  * 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(java.util.zip.ZipEntry entry) throws ZipException {
   super(entry);
   setName(entry.getName());
   byte[] extra = entry.getExtra();
   if (extra != null) {
     setExtraFields(
         ExtraFieldUtils.parse(extra, true, ExtraFieldUtils.UnparseableExtraField.READ));
   } else {
     // initializes extra data to an empty byte array
     setExtra();
   }
   setMethod(entry.getMethod());
   this.size = entry.getSize();
 }
Beispiel #10
0
  /**
   * Extracts next entry from JAR file, creating directories as needed. If the entry is for a
   * directory which doesn't exist prior to this invocation, returns that entry, otherwise returns
   * null.
   */
  ZipEntry extractFile(InputStream is, ZipEntry e) throws IOException {
    ZipEntry rc = null;
    String name = e.getName();
    File f = new File(e.getName().replace('/', File.separatorChar));
    if (e.isDirectory()) {
      if (f.exists()) {
        if (!f.isDirectory()) {
          throw new IOException(formatMsg("error.create.dir", f.getPath()));
        }
      } else {
        if (!f.mkdirs()) {
          throw new IOException(formatMsg("error.create.dir", f.getPath()));
        } else {
          rc = e;
        }
      }

      if (vflag) {
        output(formatMsg("out.create", name));
      }
    } else {
      if (f.getParent() != null) {
        File d = new File(f.getParent());
        if (!d.exists() && !d.mkdirs() || !d.isDirectory()) {
          throw new IOException(formatMsg("error.create.dir", d.getPath()));
        }
      }
      try {
        copy(is, f);
      } finally {
        if (is instanceof ZipInputStream) ((ZipInputStream) is).closeEntry();
        else is.close();
      }
      if (vflag) {
        if (e.getMethod() == ZipEntry.DEFLATED) {
          output(formatMsg("out.inflated", name));
        } else {
          output(formatMsg("out.extracted", name));
        }
      }
    }
    if (!useExtractionTime) {
      long lastModified = e.getTime();
      if (lastModified != -1) {
        f.setLastModified(lastModified);
      }
    }
    return rc;
  }
  public void decodeUnknownFiles(ExtFile apkFile, File outDir, ResTable resTable)
      throws AndrolibException {
    LOGGER.info("Copying unknown files...");
    File unknownOut = new File(outDir, UNK_DIRNAME);
    ZipEntry invZipFile;

    // have to use container of ZipFile to help identify compression type
    // with regular looping of apkFile for easy copy
    try {
      Directory unk = apkFile.getDirectory();
      ZipFile apkZipFile = new ZipFile(apkFile.getAbsolutePath());

      // loop all items in container recursively, ignoring any that are pre-defined by aapt
      Set<String> files = unk.getFiles(true);
      for (String file : files) {
        if (!isAPKFileNames(file) && !file.endsWith(".dex")) {

          // copy file out of archive into special "unknown" folder
          unk.copyToDir(unknownOut, file);
          try {
            invZipFile = apkZipFile.getEntry(file);

            // lets record the name of the file, and its compression type
            // so that we may re-include it the same way
            if (invZipFile != null) {
              mResUnknownFiles.addUnknownFileInfo(
                  invZipFile.getName(), String.valueOf(invZipFile.getMethod()));
            }
          } catch (NullPointerException ignored) {
          }
        }
      }
      apkZipFile.close();
    } catch (DirectoryException | IOException ex) {
      throw new AndrolibException(ex);
    }
  }
Beispiel #12
0
  /**
   * Parse the zip64 extended info record from the extras present in {@code ze}.
   *
   * <p>If {@code fromCentralDirectory} is true, we assume we're parsing a central directory record.
   * We assume a local file header otherwise. The difference between the two is that a central
   * directory entry is required to be complete, whereas a local file header isn't. This is due to
   * the presence of an optional data descriptor after the file content.
   *
   * @return {@code} true iff. a zip64 extended info record was found.
   */
  public static boolean parseZip64ExtendedInfo(ZipEntry ze, boolean fromCentralDirectory)
      throws ZipException {
    int extendedInfoSize = -1;
    int extendedInfoStart = -1;
    // If this file contains a zip64 central directory locator, entries might
    // optionally contain a zip64 extended information extra entry.
    if (ze.extra != null && ze.extra.length > 0) {
      // Extensible data fields are of the form header1+data1 + header2+data2 and so
      // on, where each header consists of a 2 byte header ID followed by a 2 byte size.
      // We need to iterate through the entire list of headers to find the header ID
      // for the zip64 extended information extra field (0x0001).
      final ByteBuffer buf = ByteBuffer.wrap(ze.extra).order(ByteOrder.LITTLE_ENDIAN);
      extendedInfoSize = getZip64ExtendedInfoSize(buf);
      if (extendedInfoSize != -1) {
        extendedInfoStart = buf.position();
        try {
          // The size & compressed size only make sense in the central directory *or* if
          // we know them beforehand. If we don't know them beforehand, they're stored in
          // the data descriptor and should be read from there.
          //
          // Note that the spec says that the local file header "MUST" contain the
          // original and compressed size fields. We don't care too much about that.
          // The spec claims that the order of fields is fixed anyway.
          if (fromCentralDirectory || (ze.getMethod() == ZipEntry.STORED)) {
            if (ze.size == MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE) {
              ze.size = buf.getLong();
            }

            if (ze.compressedSize == MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE) {
              ze.compressedSize = buf.getLong();
            }
          }

          // The local header offset is significant only in the central directory. It makes no
          // sense within the local header itself.
          if (fromCentralDirectory) {
            if (ze.localHeaderRelOffset == MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE) {
              ze.localHeaderRelOffset = buf.getLong();
            }
          }
        } catch (BufferUnderflowException bue) {
          ZipException zipException = new ZipException("Error parsing extended info");
          zipException.initCause(bue);
          throw zipException;
        }
      }
    }

    // This entry doesn't contain a zip64 extended information data entry header.
    // We have to check that the compressedSize / size / localHeaderRelOffset values
    // are valid and don't require the presence of the extended header.
    if (extendedInfoSize == -1) {
      if (ze.compressedSize == MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE
          || ze.size == MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE
          || ze.localHeaderRelOffset == MAX_ZIP_ENTRY_AND_ARCHIVE_SIZE) {
        throw new ZipException(
            "File contains no zip64 extended information: "
                + "name="
                + ze.name
                + "compressedSize="
                + ze.compressedSize
                + ", size="
                + ze.size
                + ", localHeader="
                + ze.localHeaderRelOffset);
      }

      return false;
    } else {
      // If we're parsed the zip64 extended info header, we remove it from the extras
      // so that applications that set their own extras will see the data they set.

      // This is an unfortunate workaround needed due to a gap in the spec. The spec demands
      // that extras are present in the "extensible" format, which means that each extra field
      // must be prefixed with a header ID and a length. However, earlier versions of the spec
      // made no mention of this, nor did any existing API enforce it. This means users could
      // set "free form" extras without caring very much whether the implementation wanted to
      // extend or add to them.

      // The start of the extended info header.
      final int extendedInfoHeaderStart = extendedInfoStart - 4;
      // The total size of the extended info, including the header.
      final int extendedInfoTotalSize = extendedInfoSize + 4;

      final int extrasLen = ze.extra.length - extendedInfoTotalSize;
      byte[] extrasWithoutZip64 = new byte[extrasLen];

      System.arraycopy(ze.extra, 0, extrasWithoutZip64, 0, extendedInfoHeaderStart);
      System.arraycopy(
          ze.extra,
          extendedInfoHeaderStart + extendedInfoTotalSize,
          extrasWithoutZip64,
          extendedInfoHeaderStart,
          (extrasLen - extendedInfoHeaderStart));

      ze.extra = extrasWithoutZip64;
      return true;
    }
  }
Beispiel #13
0
// =============================================================================
Beispiel #14
0
  /** Updates an existing jar file. */
  boolean update(InputStream in, OutputStream out, InputStream newManifest, JarIndex jarIndex)
      throws IOException {
    ZipInputStream zis = new ZipInputStream(in);
    ZipOutputStream zos = new JarOutputStream(out);
    ZipEntry e = null;
    boolean foundManifest = false;
    boolean updateOk = true;

    if (jarIndex != null) {
      addIndex(jarIndex, zos);
    }

    // put the old entries first, replace if necessary
    while ((e = zis.getNextEntry()) != null) {
      String name = e.getName();

      boolean isManifestEntry = equalsIgnoreCase(name, MANIFEST_NAME);

      if ((jarIndex != null && equalsIgnoreCase(name, INDEX_NAME)) || (Mflag && isManifestEntry)) {
        continue;
      } else if (isManifestEntry && ((newManifest != null) || (ename != null) || (pname != null))) {
        foundManifest = true;
        if (newManifest != null) {
          // Don't read from the newManifest InputStream, as we
          // might need it below, and we can't re-read the same data
          // twice.
          FileInputStream fis = new FileInputStream(mname);
          boolean ambiguous = isAmbiguousMainClass(new Manifest(fis));
          fis.close();
          if (ambiguous) {
            return false;
          }
        }

        // Update the manifest.
        Manifest old = new Manifest(zis);
        if (newManifest != null) {
          old.read(newManifest);
        }
        if (!updateManifest(old, zos)) {
          return false;
        }
      } else {
        if (!entryMap.containsKey(name)) { // copy the old stuff
          // do our own compression
          ZipEntry e2 = new ZipEntry(name);
          e2.setMethod(e.getMethod());
          e2.setTime(e.getTime());
          e2.setComment(e.getComment());
          e2.setExtra(e.getExtra());
          if (e.getMethod() == ZipEntry.STORED) {
            e2.setSize(e.getSize());
            e2.setCrc(e.getCrc());
          }
          zos.putNextEntry(e2);
          copy(zis, zos);
        } else { // replace with the new files
          File f = entryMap.get(name);
          addFile(zos, f);
          entryMap.remove(name);
          entries.remove(f);
        }
      }
    }

    // add the remaining new files
    for (File f : entries) {
      addFile(zos, f);
    }
    if (!foundManifest) {
      if (newManifest != null) {
        Manifest m = new Manifest(newManifest);
        updateOk = !isAmbiguousMainClass(m);
        if (updateOk) {
          if (!updateManifest(m, zos)) {
            updateOk = false;
          }
        }
      } else if (ename != null || pname != null) {
        if (!updateManifest(new Manifest(), zos)) {
          updateOk = false;
        }
      }
    }
    zis.close();
    zos.close();
    return updateOk;
  }
  protected void processJarFile(final File file) throws Exception {

    if (verbose) {
      log("processing " + file.toURI());
    }

    final File tempFile =
        File.createTempFile(file.getName(), null, new File(file.getAbsoluteFile().getParent()));
    try {

      final ZipInputStream zip = new ZipInputStream(new FileInputStream(file));
      try {
        final FileOutputStream fout = new FileOutputStream(tempFile);
        try {
          final ZipOutputStream out = new ZipOutputStream(fout);

          ZipEntry entry;
          while ((entry = zip.getNextEntry()) != null) {

            byte bytes[] = getBytes(zip);

            if (!entry.isDirectory()) {

              final DataInputStream din = new DataInputStream(new ByteArrayInputStream(bytes));

              if (din.readInt() == CLASS_MAGIC) {

                bytes = process(bytes);

              } else {
                if (verbose) {
                  log("ignoring " + entry.toString());
                }
              }
            }

            final ZipEntry outEntry = new ZipEntry(entry.getName());
            outEntry.setMethod(entry.getMethod());
            outEntry.setComment(entry.getComment());
            outEntry.setSize(bytes.length);

            if (outEntry.getMethod() == ZipEntry.STORED) {
              final CRC32 crc = new CRC32();
              crc.update(bytes);
              outEntry.setCrc(crc.getValue());
              outEntry.setCompressedSize(bytes.length);
            }
            out.putNextEntry(outEntry);
            out.write(bytes);
            out.closeEntry();
            zip.closeEntry();
          }
          out.close();
        } finally {
          fout.close();
        }
      } finally {
        zip.close();
      }

      if (file.delete()) {

        final File newFile = new File(tempFile.getAbsolutePath());

        if (!newFile.renameTo(file)) {
          throw new IOException("can not rename " + tempFile + " to " + file);
        }

      } else {
        throw new IOException("can not delete " + file);
      }

    } finally {

      tempFile.delete();
    }
  }