package com.github.nukc.plugin.helper; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.io.ZipUtil; import java.io.*; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Enumeration; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; /** * Created by Nukc. */ public class ZipHelper { public static void extractAndroidManifestXml(String zipPath, String outputDir) { File file = new File(zipPath); File tempFile = deleteTemp(outputDir); tempFile.mkdirs(); int buffer = 2048; BufferedInputStream bis = null; BufferedOutputStream bos = null; try { ZipFile zip = new ZipFile(file); Enumeration entries = zip.entries(); while (entries.hasMoreElements()) { ZipEntry entry = (ZipEntry) entries.nextElement(); File entryFile = new File(outputDir, entry.getName()); File parentFile = entryFile.getParentFile(); if (!"AndroidManifest.xml".equals(entry.getName())) { continue; } if (!parentFile.exists()) { parentFile.mkdirs(); } if (!entryFile.isDirectory()) { bis = new BufferedInputStream(zip.getInputStream(entry)); int currentByte; // establish buffer for writing file byte[] data = new byte[buffer]; // write the current file to disk FileOutputStream fos = new FileOutputStream(entryFile); bos = new BufferedOutputStream(fos, buffer); // read and write until last byte is encountered while ((currentByte = bis.read(data, 0, buffer)) != -1) { bos.write(data, 0, currentByte); } bos.flush(); } } } catch (IOException e) { e.printStackTrace(); } finally { try { if (bos != null) { bos.close(); } if (bis != null) { bis.close(); } } catch (IOException e) { e.printStackTrace(); } } } public static File deleteTemp(String tempPath) { File tempFile = new File(tempPath); if (tempFile.exists()) { deleteFile(tempFile); } return tempFile; } private static void deleteFile(File file) { if (file.exists()) { if (file.isFile()) { file.delete(); } else if (file.isDirectory()) { File[] files = file.listFiles(); if (files != null) { for (File file1 : files) { deleteFile(file1); } } file.delete(); } } } public static boolean update(InputStream in, OutputStream out, Map<String, File> relpathToFile) { try { update(in, out, relpathToFile, true); return true; } catch (IOException e) { e.printStackTrace(); return false; } } /** * update an existing jar file. Adds/replace files specified in relpathToFile map */ public static void update(InputStream in, OutputStream out, Map<String, File> relpathToFile, boolean except) throws IOException { ZipInputStream zis = new ZipInputStream(in); ZipOutputStream zos = new ZipOutputStream(out); try { // put the old entries first, replace if necessary ZipEntry e; while ((e = zis.getNextEntry()) != null) { String name = e.getName(); //except signature file if (except && name.contains("META-INF") && (name.endsWith("RSA") || name.contains("SF") || name.contains("MANIFEST.MF"))) { continue; } if (!relpathToFile.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); FileUtil.copy(zis, zos); } else { // replace with the new files final File file = relpathToFile.get(name); //addFile(file, name, zos); relpathToFile.remove(name); ZipUtil.addFileToZip(zos, file, name, null, null); } } // add the remaining new files for (final String path : relpathToFile.keySet()) { File file = relpathToFile.get(path); ZipUtil.addFileToZip(zos, file, path, null, null); } } finally { zis.close(); zos.close(); } } private static final byte[] COMMENT_SIGN = new byte[]{99, 104, 97, 110, 110, 101, 108}; //channel public static void writeComment(File zipFile, String comment) throws IOException { // {@see java.util.zip.ZipOutputStream.writeEND} byte[] data = comment.getBytes("utf-8"); final RandomAccessFile raf = new RandomAccessFile(zipFile, "rw"); raf.seek(zipFile.length() - 2); // write zip comment length // (content field length + length field length + sign field length) writeShort(data.length + 2 + COMMENT_SIGN.length, raf); // write content writeBytes(data, raf); // write content length writeShort(data.length, raf); // write sign bytes writeBytes(COMMENT_SIGN, raf); raf.close(); } private static void writeBytes(byte[] data, DataOutput out) throws IOException { out.write(data); } private static void writeShort(int i, DataOutput out) throws IOException { ByteBuffer bb = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN); bb.putShort((short) i); out.write(bb.array()); } public static boolean hasCommentSign(File file) throws IOException { RandomAccessFile raf = null; try { raf = new RandomAccessFile(file, "r"); long index = raf.length(); byte[] buffer = new byte[COMMENT_SIGN.length]; index -= COMMENT_SIGN.length; // read comment sign bytes raf.seek(index); raf.readFully(buffer); return Arrays.equals(COMMENT_SIGN, buffer); } finally { if (raf != null) { raf.close(); } } } public static String readZipComment(File file) throws IOException { RandomAccessFile raf = null; try { raf = new RandomAccessFile(file, "r"); long index = raf.length(); byte[] buffer = new byte[COMMENT_SIGN.length]; index -= COMMENT_SIGN.length; // read sign bytes raf.seek(index); raf.readFully(buffer); // if sign bytes matched if (Arrays.equals(buffer, COMMENT_SIGN)) { index -= 2; raf.seek(index); // read content length field int length = readShort(raf); if (length > 0) { index -= length; raf.seek(index); // read content bytes byte[] bytesComment = new byte[length]; raf.readFully(bytesComment); return new String(bytesComment, "utf-8"); } else { throw new IOException("Zip comment content not found"); } } else { throw new IOException("Zip comment sign bytes not found"); } } finally { if (raf != null) { raf.close(); } } } private static short readShort(DataInput input) throws IOException { byte[] buf = new byte[2]; input.readFully(buf); ByteBuffer bb = ByteBuffer.wrap(buf).order(ByteOrder.LITTLE_ENDIAN); return bb.getShort(0); } }