diff --git a/src/main/java/com/reandroid/archive2/Archive.java b/src/main/java/com/reandroid/archive2/Archive.java index 425f3cb..7ef397b 100644 --- a/src/main/java/com/reandroid/archive2/Archive.java +++ b/src/main/java/com/reandroid/archive2/Archive.java @@ -120,12 +120,4 @@ public class Archive { String name = archiveEntry.getName().replace('/', File.separatorChar); return new File(dir, name); } - // for test - public void writeSignatureData(File dir) throws IOException{ - ApkSignatureBlock apkSignatureBlock = getApkSignatureBlock(); - if(apkSignatureBlock == null){ - throw new IOException("Does not have signature block"); - } - apkSignatureBlock.writeSignatureData(dir); - } } diff --git a/src/main/java/com/reandroid/archive2/block/ApkSignatureBlock.java b/src/main/java/com/reandroid/archive2/block/ApkSignatureBlock.java index 0cfd348..e9d41d0 100644 --- a/src/main/java/com/reandroid/archive2/block/ApkSignatureBlock.java +++ b/src/main/java/com/reandroid/archive2/block/ApkSignatureBlock.java @@ -16,21 +16,61 @@ package com.reandroid.archive2.block; +import com.reandroid.archive2.block.pad.SchemePadding; +import com.reandroid.arsc.io.BlockReader; + import java.io.File; +import java.io.FileFilter; +import java.io.FileOutputStream; import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; import java.util.List; -public class ApkSignatureBlock extends LengthPrefixedList { +public class ApkSignatureBlock extends LengthPrefixedList + implements Comparator { public ApkSignatureBlock(SignatureFooter signatureFooter){ super(true); setBottomBlock(signatureFooter); } + public ApkSignatureBlock(){ + this(new SignatureFooter()); + } public List getSignatures(){ return super.getElements(); } public int countSignatures(){ return super.getElementsCount(); } + public void sortSignatures(){ + sort(this); + } + public void updatePadding(){ + SchemePadding schemePadding = getOrCreateSchemePadding(); + schemePadding.setPadding(0); + sortSignatures(); + refresh(); + int size = countBytes(); + int alignment = 4096; + int padding = (alignment - (size % alignment)) % alignment; + schemePadding.setPadding(padding); + refresh(); + } + private SchemePadding getOrCreateSchemePadding(){ + SignatureInfo signatureInfo = getSignature(SignatureId.PADDING); + if(signatureInfo == null){ + signatureInfo = new SignatureInfo(); + signatureInfo.setId(SignatureId.PADDING); + signatureInfo.setSignatureScheme(new SchemePadding()); + add(signatureInfo); + } + SignatureScheme scheme = signatureInfo.getSignatureScheme(); + if(!(scheme instanceof SchemePadding)){ + scheme = new SchemePadding(); + signatureInfo.setSignatureScheme(scheme); + } + return (SchemePadding) scheme; + } public SignatureInfo getSignature(SignatureId signatureId){ for(SignatureInfo signatureInfo:getSignatures()){ if(signatureInfo.getId().equals(signatureId)){ @@ -53,26 +93,69 @@ public class ApkSignatureBlock extends LengthPrefixedList { super.onRefreshed(); footer.setSignatureSize(getDataSize()); } - // for test - public void writeSignatureData(File dir) throws IOException{ - for(SignatureInfo signatureInfo:getElements()){ - signatureInfo.writeToDir(dir); + + public void writeRaw(File file) throws IOException{ + refresh(); + File dir = file.getParentFile(); + if(dir != null && !dir.exists()){ + dir.mkdirs(); } + FileOutputStream outputStream = new FileOutputStream(file); + writeBytes(outputStream); + outputStream.close(); + } + public List writeSplitRawToDirectory(File dir) throws IOException{ + refresh(); + List signatureInfoList = getElements(); + List writtenFiles = new ArrayList<>(signatureInfoList.size()); + for(SignatureInfo signatureInfo:signatureInfoList){ + File file = signatureInfo.writeRawToDirectory(dir); + writtenFiles.add(file); + } + return writtenFiles; + } + public void read(File file) throws IOException { + super.readBytes(new BlockReader(file)); + } + public void scanSplitFiles(File dir) throws IOException { + if(!dir.isDirectory()){ + throw new IOException("No such directory"); + } + FileFilter filter = new FileFilter() { + @Override + public boolean accept(File file) { + if(!file.isFile()){ + return false; + } + String name = file.getName().toLowerCase(); + return name.endsWith(SignatureId.FILE_EXT_RAW); + } + }; + File[] files = dir.listFiles(filter); + if(files == null){ + return; + } + for(File file:files){ + addSplitRaw(file); + } + sortSignatures(); + } + public SignatureInfo addSplitRaw(File signatureInfoFile) throws IOException { + SignatureInfo signatureInfo = new SignatureInfo(); + signatureInfo.read(signatureInfoFile); + add(signatureInfo); + return signatureInfo; + } + @Override + public int compare(SignatureInfo info1, SignatureInfo info2) { + if(SignatureId.PADDING.equals(info1.getId())){ + return 0; + } + if(SignatureId.PADDING.equals(info2.getId())){ + return 1; + } + return 0; } - private static final long CONTENT_DIGESTED_CHUNK_MAX_SIZE_BYTES = 1024 * 1024; - public static final int ANDROID_COMMON_PAGE_ALIGNMENT_BYTES = 4096; - - private static final byte[] APK_SIGNING_BLOCK_MAGIC = new byte[] { - 0x41, 0x50, 0x4b, 0x20, 0x53, 0x69, 0x67, 0x20, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x34, 0x32, - }; - - public static final int VERSION_SOURCE_STAMP = 0; - public static final int VERSION_JAR_SIGNATURE_SCHEME = 1; - public static final int VERSION_APK_SIGNATURE_SCHEME_V2 = 2; - public static final int VERSION_APK_SIGNATURE_SCHEME_V3 = 3; - public static final int VERSION_APK_SIGNATURE_SCHEME_V31 = 31; - public static final int VERSION_APK_SIGNATURE_SCHEME_V4 = 4; - + public static final String FILE_EXT = ".signature.block.bin"; } diff --git a/src/main/java/com/reandroid/archive2/block/LengthPrefixedList.java b/src/main/java/com/reandroid/archive2/block/LengthPrefixedList.java index 922fe50..11cf1c2 100644 --- a/src/main/java/com/reandroid/archive2/block/LengthPrefixedList.java +++ b/src/main/java/com/reandroid/archive2/block/LengthPrefixedList.java @@ -25,6 +25,7 @@ import com.reandroid.arsc.item.IntegerItem; import com.reandroid.arsc.item.LongItem; import java.io.IOException; +import java.util.Comparator; import java.util.List; public abstract class LengthPrefixedList extends FixedBlockContainer @@ -75,6 +76,9 @@ public abstract class LengthPrefixedList extends FixedBlockCont public boolean remove(T element){ return this.elements.remove(element); } + public void sort(Comparator comparator){ + this.elements.sort(comparator); + } @Override public void onReadBytes(BlockReader reader) throws IOException{ if(!reader.isAvailable()){ diff --git a/src/main/java/com/reandroid/archive2/block/SignatureId.java b/src/main/java/com/reandroid/archive2/block/SignatureId.java index 616e7be..501fc04 100644 --- a/src/main/java/com/reandroid/archive2/block/SignatureId.java +++ b/src/main/java/com/reandroid/archive2/block/SignatureId.java @@ -35,9 +35,9 @@ public class SignatureId { } public String toFileName() { if (this.name != null) { - return name + FILE_EXTENSION; + return name + FILE_EXT_RAW; } - return String.format("0x%08x", id) + FILE_EXTENSION; + return String.format("0x%08x", id) + FILE_EXT_RAW; } @Override public boolean equals(Object obj) { @@ -66,7 +66,7 @@ public class SignatureId { if (name == null) { return null; } - String ext = FILE_EXTENSION; + String ext = FILE_EXT_RAW; if (name.endsWith(ext)) { name = name.substring(0, name.length() - ext.length()); } @@ -105,5 +105,5 @@ public class SignatureId { V2, V3, V31, STAMP_V1, STAMP_V2, PADDING, NULL }; - private static final String FILE_EXTENSION = ".bin"; + public static final String FILE_EXT_RAW = ".signature.info.bin"; } diff --git a/src/main/java/com/reandroid/archive2/block/SignatureInfo.java b/src/main/java/com/reandroid/archive2/block/SignatureInfo.java index 4451961..94f59ba 100644 --- a/src/main/java/com/reandroid/archive2/block/SignatureInfo.java +++ b/src/main/java/com/reandroid/archive2/block/SignatureInfo.java @@ -28,6 +28,7 @@ import com.reandroid.arsc.io.BlockReader; import com.reandroid.arsc.item.IntegerItem; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; @@ -87,8 +88,7 @@ public class SignatureInfo extends LengthPrefixedBlock implements BlockLoad { } schemeContainer.setItem(scheme); } - // for test - public void writeData(File file) throws IOException{ + public void writeRaw(File file) throws IOException{ File dir = file.getParentFile(); if(dir != null && !dir.exists()){ dir.mkdirs(); @@ -97,12 +97,15 @@ public class SignatureInfo extends LengthPrefixedBlock implements BlockLoad { writeBytes(outputStream); outputStream.close(); } - // for test - public File writeToDir(File dir) throws IOException{ - File file = new File(dir, getId().toFileName()); - writeData(file); + public File writeRawToDirectory(File dir) throws IOException{ + String name = getIndex() + "_" + getId().toFileName(); + File file = new File(dir, name); + writeRaw(file); return file; } + public void read(File file) throws IOException { + super.readBytes(new BlockReader(file)); + } @Override public String toString() { return getId() + ", scheme: " + getSignatureScheme(); diff --git a/src/main/java/com/reandroid/archive2/block/pad/SchemePadding.java b/src/main/java/com/reandroid/archive2/block/pad/SchemePadding.java index b088c18..f726ef3 100644 --- a/src/main/java/com/reandroid/archive2/block/pad/SchemePadding.java +++ b/src/main/java/com/reandroid/archive2/block/pad/SchemePadding.java @@ -30,6 +30,19 @@ public class SchemePadding extends SignatureScheme { this.byteArray = new ByteArray(); addChild(this.byteArray); } + public int getPadding(){ + return byteArray.size(); + } + public void setPadding(int padding){ + byteArray.setSize(padding); + } + public byte[] getPaddingBytes() { + return byteArray.getBytes(); + } + public void setPadding(byte[] bytes){ + byteArray.set(bytes); + } + @Override public void onReadBytes(BlockReader reader) throws IOException{ SignatureInfo signatureInfo = getSignatureInfo(); @@ -37,4 +50,8 @@ public class SchemePadding extends SignatureScheme { byteArray.setSize(size); super.onReadBytes(reader); } + @Override + public String toString(){ + return "padding = " + getPadding(); + } } diff --git a/src/main/java/com/reandroid/archive2/writer/ApkWriter.java b/src/main/java/com/reandroid/archive2/writer/ApkWriter.java index 9d80baa..d90b1c5 100644 --- a/src/main/java/com/reandroid/archive2/writer/ApkWriter.java +++ b/src/main/java/com/reandroid/archive2/writer/ApkWriter.java @@ -99,13 +99,13 @@ public class ApkWriter extends ZipFileOutput { logMessage("Writing signature block ..."); long offset = position(); int alignment = 4096; - int padding = (int) ((alignment - (offset % alignment)) % alignment); + int filesPadding = (int) ((alignment - (offset % alignment)) % alignment); OutputStream outputStream = getOutputStream(); - if(padding > 0){ - outputStream.write(new byte[padding]); + if(filesPadding > 0){ + outputStream.write(new byte[filesPadding]); } - signatureBlock.refresh(); - logVerbose("padding = " + padding + ", signatures = " + signatureBlock.countBytes()); + logMessage("files padding = " + filesPadding); + signatureBlock.updatePadding(); signatureBlock.writeBytes(outputStream); } private BufferFileInput writeBuffer(List outputList) throws IOException {