diff --git a/src/main/java/com/reandroid/archive2/writer/ApkWriter.java b/src/main/java/com/reandroid/archive2/writer/ApkWriter.java index fde5109..377b976 100644 --- a/src/main/java/com/reandroid/archive2/writer/ApkWriter.java +++ b/src/main/java/com/reandroid/archive2/writer/ApkWriter.java @@ -30,20 +30,30 @@ import java.util.List; public class ApkWriter extends ZipFileOutput { private final Collection sourceList; + private ZipAligner zipAligner; + public ApkWriter(File file, Collection sourceList) throws IOException { super(file); this.sourceList = sourceList; + this.zipAligner = ZipAligner.apkAligner(); } public void write()throws IOException { List outputList = buildOutputEntry(); BufferFileInput buffer = writeBuffer(outputList); buffer.unlock(); - ZipAligner aligner = new ZipAligner(); - align(aligner, outputList); + align(outputList); writeApk(outputList); writeCEH(outputList); buffer.close(); + this.close(); } + public ZipAligner getZipAligner() { + return zipAligner; + } + public void setZipAligner(ZipAligner zipAligner) { + this.zipAligner = zipAligner; + } + private void writeCEH(List outputList) throws IOException{ EndRecord endRecord = new EndRecord(); endRecord.setSignature(ZipSignature.END_RECORD); @@ -73,7 +83,8 @@ public class ApkWriter extends ZipFileOutput { output.close(); return input; } - private void align(ZipAligner aligner, List outputList) throws IOException{ + private void align(List outputList){ + ZipAligner aligner = getZipAligner(); for(OutputSource outputSource:outputList){ outputSource.align(aligner); } diff --git a/src/main/java/com/reandroid/archive2/writer/OutputSource.java b/src/main/java/com/reandroid/archive2/writer/OutputSource.java index c21e945..ee664e6 100644 --- a/src/main/java/com/reandroid/archive2/writer/OutputSource.java +++ b/src/main/java/com/reandroid/archive2/writer/OutputSource.java @@ -29,18 +29,23 @@ import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import java.util.zip.ZipEntry; -public class OutputSource { +class OutputSource { private final InputSource inputSource; private LocalFileHeader lfh; private EntryBuffer entryBuffer; - public OutputSource(InputSource inputSource){ + OutputSource(InputSource inputSource){ this.inputSource = inputSource; } - public void align(ZipAligner aligner){ - aligner.align(getInputSource(), getLocalFileHeader()); + void align(ZipAligner aligner){ + LocalFileHeader lfh = getLocalFileHeader(); + if(aligner == null){ + lfh.setExtra(null); + }else { + aligner.align(getInputSource(), lfh); + } } - public void makeBuffer(BufferFileInput input, BufferFileOutput output) throws IOException { + void makeBuffer(BufferFileInput input, BufferFileOutput output) throws IOException { EntryBuffer entryBuffer = this.entryBuffer; if(entryBuffer != null){ return; @@ -62,7 +67,7 @@ public class OutputSource { return null; } - public void writeApk(ApkWriter apkWriter) throws IOException{ + void writeApk(ApkWriter apkWriter) throws IOException{ EntryBuffer entryBuffer = this.entryBuffer; FileChannel input = entryBuffer.getZipFileInput().getFileChannel(); input.position(entryBuffer.getOffset()); @@ -71,7 +76,7 @@ public class OutputSource { writeData(input, entryBuffer.getLength(), apkWriter); writeDD(lfh.getDataDescriptor(), apkWriter); } - public void writeCEH(ApkWriter apkWriter) throws IOException{ + void writeCEH(ApkWriter apkWriter) throws IOException{ LocalFileHeader lfh = getLocalFileHeader(); CentralEntryHeader ceh = CentralEntryHeader.fromLocalFileHeader(lfh); ceh.writeBytes(apkWriter.getOutputStream()); @@ -127,10 +132,10 @@ public class OutputSource { } } - public InputSource getInputSource() { + InputSource getInputSource() { return inputSource; } - public LocalFileHeader getLocalFileHeader(){ + LocalFileHeader getLocalFileHeader(){ if(lfh == null){ lfh = createLocalFileHeader(); clearAlignment(lfh); diff --git a/src/main/java/com/reandroid/archive2/writer/ZipAligner.java b/src/main/java/com/reandroid/archive2/writer/ZipAligner.java index 388ef66..4152d22 100644 --- a/src/main/java/com/reandroid/archive2/writer/ZipAligner.java +++ b/src/main/java/com/reandroid/archive2/writer/ZipAligner.java @@ -19,21 +19,56 @@ import com.reandroid.archive.InputSource; import com.reandroid.archive2.block.DataDescriptor; import com.reandroid.archive2.block.LocalFileHeader; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.zip.ZipEntry; public class ZipAligner { + private final Map alignmentMap; + private int defaultAlignment; + private boolean enableDataDescriptor; private long mTotalPadding; private long mCurrentOffset; - private boolean enableDataDescriptor = true; + public ZipAligner(){ + alignmentMap = new HashMap<>(); } - public void align(InputSource inputSource, LocalFileHeader lfh){ + + public void setFileAlignment(Pattern patternFileName, int alignment){ + if(patternFileName == null){ + return; + } + alignmentMap.remove(patternFileName); + if(alignment >= 0){ + alignmentMap.put(patternFileName, alignment); + } + } + public void clearFileAlignment(){ + alignmentMap.clear(); + } + public void setDefaultAlignment(int defaultAlignment) { + if(defaultAlignment < 0){ + defaultAlignment = 0; + } + this.defaultAlignment = defaultAlignment; + } + public void reset(){ + mTotalPadding = 0; + mCurrentOffset = 0; + } + public void setEnableDataDescriptor(boolean enableDataDescriptor) { + this.enableDataDescriptor = enableDataDescriptor; + } + + void align(InputSource inputSource, LocalFileHeader lfh){ int padding; if(inputSource.getMethod() != ZipEntry.STORED){ padding = 0; createDataDescriptor(lfh); }else { - int alignment = getAlignment(inputSource); + int alignment = getAlignment(inputSource.getAlias()); long newOffset = mCurrentOffset + mTotalPadding; padding = (int) ((alignment - (newOffset % alignment)) % alignment); mTotalPadding += padding; @@ -54,21 +89,23 @@ public class ZipAligner { } lfh.setDataDescriptor(dataDescriptor); } - public void reset(){ - mTotalPadding = 0; - mCurrentOffset = 0; - } - public void setEnableDataDescriptor(boolean enableDataDescriptor) { - this.enableDataDescriptor = enableDataDescriptor; + private int getAlignment(String name){ + for(Map.Entry entry:alignmentMap.entrySet()){ + Matcher matcher = entry.getKey().matcher(name); + if(matcher.matches()){ + return entry.getValue(); + } + } + return defaultAlignment; } - private int getAlignment(InputSource inputSource){ - String name = inputSource.getAlias(); - if(name.startsWith("lib/") && name.endsWith(".so")){ - return ALIGNMENT_PAGE; - }else { - return ALIGNMENT_4; - } + public static ZipAligner apkAligner(){ + ZipAligner zipAligner = new ZipAligner(); + zipAligner.setDefaultAlignment(ALIGNMENT_4); + Pattern patternNativeLib = Pattern.compile("^lib/.+\\.so$"); + zipAligner.setFileAlignment(patternNativeLib, ALIGNMENT_PAGE); + zipAligner.setEnableDataDescriptor(true); + return zipAligner; } private static final int ALIGNMENT_4 = 4;