accessible ZipAligner

This commit is contained in:
REAndroid 2023-04-25 15:47:41 +02:00
parent c517505cbf
commit 61b3b6aee5
3 changed files with 81 additions and 28 deletions

View File

@ -30,20 +30,30 @@ import java.util.List;
public class ApkWriter extends ZipFileOutput { public class ApkWriter extends ZipFileOutput {
private final Collection<? extends InputSource> sourceList; private final Collection<? extends InputSource> sourceList;
private ZipAligner zipAligner;
public ApkWriter(File file, Collection<? extends InputSource> sourceList) throws IOException { public ApkWriter(File file, Collection<? extends InputSource> sourceList) throws IOException {
super(file); super(file);
this.sourceList = sourceList; this.sourceList = sourceList;
this.zipAligner = ZipAligner.apkAligner();
} }
public void write()throws IOException { public void write()throws IOException {
List<OutputSource> outputList = buildOutputEntry(); List<OutputSource> outputList = buildOutputEntry();
BufferFileInput buffer = writeBuffer(outputList); BufferFileInput buffer = writeBuffer(outputList);
buffer.unlock(); buffer.unlock();
ZipAligner aligner = new ZipAligner(); align(outputList);
align(aligner, outputList);
writeApk(outputList); writeApk(outputList);
writeCEH(outputList); writeCEH(outputList);
buffer.close(); buffer.close();
this.close();
} }
public ZipAligner getZipAligner() {
return zipAligner;
}
public void setZipAligner(ZipAligner zipAligner) {
this.zipAligner = zipAligner;
}
private void writeCEH(List<OutputSource> outputList) throws IOException{ private void writeCEH(List<OutputSource> outputList) throws IOException{
EndRecord endRecord = new EndRecord(); EndRecord endRecord = new EndRecord();
endRecord.setSignature(ZipSignature.END_RECORD); endRecord.setSignature(ZipSignature.END_RECORD);
@ -73,7 +83,8 @@ public class ApkWriter extends ZipFileOutput {
output.close(); output.close();
return input; return input;
} }
private void align(ZipAligner aligner, List<OutputSource> outputList) throws IOException{ private void align(List<OutputSource> outputList){
ZipAligner aligner = getZipAligner();
for(OutputSource outputSource:outputList){ for(OutputSource outputSource:outputList){
outputSource.align(aligner); outputSource.align(aligner);
} }

View File

@ -29,18 +29,23 @@ import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream; import java.util.zip.DeflaterOutputStream;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
public class OutputSource { class OutputSource {
private final InputSource inputSource; private final InputSource inputSource;
private LocalFileHeader lfh; private LocalFileHeader lfh;
private EntryBuffer entryBuffer; private EntryBuffer entryBuffer;
public OutputSource(InputSource inputSource){ OutputSource(InputSource inputSource){
this.inputSource = inputSource; this.inputSource = inputSource;
} }
public void align(ZipAligner aligner){ void align(ZipAligner aligner){
aligner.align(getInputSource(), getLocalFileHeader()); 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; EntryBuffer entryBuffer = this.entryBuffer;
if(entryBuffer != null){ if(entryBuffer != null){
return; return;
@ -62,7 +67,7 @@ public class OutputSource {
return null; return null;
} }
public void writeApk(ApkWriter apkWriter) throws IOException{ void writeApk(ApkWriter apkWriter) throws IOException{
EntryBuffer entryBuffer = this.entryBuffer; EntryBuffer entryBuffer = this.entryBuffer;
FileChannel input = entryBuffer.getZipFileInput().getFileChannel(); FileChannel input = entryBuffer.getZipFileInput().getFileChannel();
input.position(entryBuffer.getOffset()); input.position(entryBuffer.getOffset());
@ -71,7 +76,7 @@ public class OutputSource {
writeData(input, entryBuffer.getLength(), apkWriter); writeData(input, entryBuffer.getLength(), apkWriter);
writeDD(lfh.getDataDescriptor(), apkWriter); writeDD(lfh.getDataDescriptor(), apkWriter);
} }
public void writeCEH(ApkWriter apkWriter) throws IOException{ void writeCEH(ApkWriter apkWriter) throws IOException{
LocalFileHeader lfh = getLocalFileHeader(); LocalFileHeader lfh = getLocalFileHeader();
CentralEntryHeader ceh = CentralEntryHeader.fromLocalFileHeader(lfh); CentralEntryHeader ceh = CentralEntryHeader.fromLocalFileHeader(lfh);
ceh.writeBytes(apkWriter.getOutputStream()); ceh.writeBytes(apkWriter.getOutputStream());
@ -127,10 +132,10 @@ public class OutputSource {
} }
} }
public InputSource getInputSource() { InputSource getInputSource() {
return inputSource; return inputSource;
} }
public LocalFileHeader getLocalFileHeader(){ LocalFileHeader getLocalFileHeader(){
if(lfh == null){ if(lfh == null){
lfh = createLocalFileHeader(); lfh = createLocalFileHeader();
clearAlignment(lfh); clearAlignment(lfh);

View File

@ -19,21 +19,56 @@ import com.reandroid.archive.InputSource;
import com.reandroid.archive2.block.DataDescriptor; import com.reandroid.archive2.block.DataDescriptor;
import com.reandroid.archive2.block.LocalFileHeader; 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; import java.util.zip.ZipEntry;
public class ZipAligner { public class ZipAligner {
private final Map<Pattern, Integer> alignmentMap;
private int defaultAlignment;
private boolean enableDataDescriptor;
private long mTotalPadding; private long mTotalPadding;
private long mCurrentOffset; private long mCurrentOffset;
private boolean enableDataDescriptor = true;
public ZipAligner(){ 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; int padding;
if(inputSource.getMethod() != ZipEntry.STORED){ if(inputSource.getMethod() != ZipEntry.STORED){
padding = 0; padding = 0;
createDataDescriptor(lfh); createDataDescriptor(lfh);
}else { }else {
int alignment = getAlignment(inputSource); int alignment = getAlignment(inputSource.getAlias());
long newOffset = mCurrentOffset + mTotalPadding; long newOffset = mCurrentOffset + mTotalPadding;
padding = (int) ((alignment - (newOffset % alignment)) % alignment); padding = (int) ((alignment - (newOffset % alignment)) % alignment);
mTotalPadding += padding; mTotalPadding += padding;
@ -54,21 +89,23 @@ public class ZipAligner {
} }
lfh.setDataDescriptor(dataDescriptor); lfh.setDataDescriptor(dataDescriptor);
} }
public void reset(){ private int getAlignment(String name){
mTotalPadding = 0; for(Map.Entry<Pattern, Integer> entry:alignmentMap.entrySet()){
mCurrentOffset = 0; Matcher matcher = entry.getKey().matcher(name);
} if(matcher.matches()){
public void setEnableDataDescriptor(boolean enableDataDescriptor) { return entry.getValue();
this.enableDataDescriptor = enableDataDescriptor; }
}
return defaultAlignment;
} }
private int getAlignment(InputSource inputSource){ public static ZipAligner apkAligner(){
String name = inputSource.getAlias(); ZipAligner zipAligner = new ZipAligner();
if(name.startsWith("lib/") && name.endsWith(".so")){ zipAligner.setDefaultAlignment(ALIGNMENT_4);
return ALIGNMENT_PAGE; Pattern patternNativeLib = Pattern.compile("^lib/.+\\.so$");
}else { zipAligner.setFileAlignment(patternNativeLib, ALIGNMENT_PAGE);
return ALIGNMENT_4; zipAligner.setEnableDataDescriptor(true);
} return zipAligner;
} }
private static final int ALIGNMENT_4 = 4; private static final int ALIGNMENT_4 = 4;