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 {
private final Collection<? extends InputSource> sourceList;
private ZipAligner zipAligner;
public ApkWriter(File file, Collection<? extends InputSource> sourceList) throws IOException {
super(file);
this.sourceList = sourceList;
this.zipAligner = ZipAligner.apkAligner();
}
public void write()throws IOException {
List<OutputSource> 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<OutputSource> 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<OutputSource> outputList) throws IOException{
private void align(List<OutputSource> outputList){
ZipAligner aligner = getZipAligner();
for(OutputSource outputSource:outputList){
outputSource.align(aligner);
}

View File

@ -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);

View File

@ -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<Pattern, Integer> 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<Pattern, Integer> 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;