fix multi-package xml compiling #40

This commit is contained in:
REAndroid 2023-05-09 18:03:02 +02:00
parent e136a8d570
commit ada5aaf17d
6 changed files with 497 additions and 341 deletions

View File

@ -18,8 +18,11 @@ package com.reandroid.apk;
import com.reandroid.archive.APKArchive;
import com.reandroid.archive.FileInputSource;
import com.reandroid.apk.xmlencoder.RESEncoder;
import com.reandroid.archive.InputSource;
import com.reandroid.archive.InputSourceUtil;
import com.reandroid.archive2.block.ApkSignatureBlock;
import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.chunk.xml.AndroidManifestBlock;
import com.reandroid.json.JSONArray;
import com.reandroid.xml.XMLException;
@ -43,6 +46,7 @@ public class ApkModuleXmlEncoder {
scanRootDir(rootDir);
restorePathMap(mainDirectory);
restoreSignatures(mainDirectory);
sortFiles();
}
private void restoreSignatures(File dir) throws IOException {
File sigDir = new File(dir, ApkUtil.SIGNATURE_DIR_NAME);
@ -79,6 +83,24 @@ public class ApkModuleXmlEncoder {
archive.add(inputSource);
}
}
private void sortFiles(){
APKArchive archive=getApkModule().getApkArchive();
int i = 1;
for(InputSource inputSource:archive.listInputSources()){
if(inputSource.getSort() == 0){
inputSource.setSort(i);
i++;
}
}
InputSource manifest = archive.getInputSource(AndroidManifestBlock.FILE_NAME);
if(manifest != null){
manifest.setSort(0);
}
List<InputSource> sourceList = archive.listInputSources();
InputSourceUtil.sort(sourceList);
archive.clear();
archive.addAll(sourceList);
}
private void loadUncompressedFiles(File mainDirectory) throws IOException, XMLException {
File file=new File(mainDirectory, UncompressedFiles.JSON_FILE);
UncompressedFiles uncompressedFiles = getApkModule().getUncompressedFiles();

View File

@ -29,7 +29,6 @@ import com.reandroid.arsc.util.FrameworkTable;
import com.reandroid.arsc.util.HexUtil;
import com.reandroid.arsc.util.ResNameMap;
import com.reandroid.arsc.value.Entry;
import com.reandroid.common.Frameworks;
import java.util.HashSet;
import java.util.Set;
@ -38,6 +37,7 @@ import java.util.regex.Matcher;
public class EncodeMaterials {
private final Set<ResourceIds.Table.Package> packageIdSet = new HashSet<>();
private PackageBlock currentPackage;
private ResourceIds.Table.Package currentLocalPackage;
private final Set<FrameworkTable> frameworkTables = new HashSet<>();
private APKLogger apkLogger;
private boolean mForceCreateNamespaces = true;
@ -99,6 +99,10 @@ public class EncodeMaterials {
}
String type = matcher.group(4);
String name = matcher.group(5);
if(isLocalPackageName(packageName)){
return resolveLocalResourceId(packageName, type, name);
}
if(EncodeUtil.isEmpty(packageName)
|| packageName.equals(getCurrentPackageName())
|| !isFrameworkPackageName(packageName)){
@ -106,13 +110,36 @@ public class EncodeMaterials {
}
return resolveFrameworkResourceId(packageName, type, name);
}
private int resolveLocalResourceId(String packageName, String type, String name){
ResourceIds.Table.Package pkg = getLocalPackage(packageName);
Integer resourceId = pkg.getResourceId(type, name);
if(resourceId != null){
return resourceId;
}
EntryGroup entryGroup=getLocalEntryGroup(type, name);
if(entryGroup!=null){
return entryGroup.getResourceId();
}
throw new EncodeException("Local entry not found: " +
"package=" + packageName +
", type=" + type +
", name=" + name);
}
public int resolveLocalResourceId(String type, String name){
ResourceIds.Table.Package current = this.currentLocalPackage;
if(current != null){
Integer resId = current.getResourceId(type, name);
if(resId != null){
return resId;
}
}else {
for(ResourceIds.Table.Package pkg:packageIdSet){
Integer resId = pkg.getResourceId(type, name);
if(resId!=null){
return resId;
}
}
}
EntryGroup entryGroup=getLocalEntryGroup(type, name);
if(entryGroup!=null){
return entryGroup.getResourceId();
@ -286,8 +313,73 @@ public class EncodeMaterials {
}
public EncodeMaterials setCurrentPackage(PackageBlock currentPackage) {
this.currentPackage = currentPackage;
onCurrentPackageChanged(currentPackage);
return this;
}
public EncodeMaterials setCurrentLocalPackage(ResourceIds.Table.Package currentLocalPackage) {
this.currentLocalPackage = currentLocalPackage;
return this;
}
private void onCurrentPackageChanged(PackageBlock currentPackage){
if(currentPackage == null){
return;
}
ResourceIds.Table.Package current = null;
if(isUniquePackageIds()){
current = getLocalPackage(currentPackage.getId());
}
if(current == null && isUniquePackageNames()){
current = getLocalPackage(currentPackage.getName());
}
if(current != null){
this.currentLocalPackage = current;
}
}
private ResourceIds.Table.Package getLocalPackage(int packageId){
byte id = (byte) packageId;
for(ResourceIds.Table.Package pkg : packageIdSet){
if(id == pkg.id){
return pkg;
}
}
return null;
}
private ResourceIds.Table.Package getLocalPackage(String name){
if(name == null){
return null;
}
for(ResourceIds.Table.Package pkg : packageIdSet){
if(name.equals(pkg.name)){
return pkg;
}
}
return null;
}
private boolean isLocalPackageName(String packageName){
if(packageName == null){
return false;
}
for(ResourceIds.Table.Package pkg : packageIdSet){
if(packageName.equals(pkg.name)){
return true;
}
}
return false;
}
private boolean isUniquePackageNames(){
Set<String> names = new HashSet<>();
for(ResourceIds.Table.Package pkg : packageIdSet){
names.add(pkg.name);
}
return names.size() == packageIdSet.size();
}
private boolean isUniquePackageIds(){
Set<Byte> ids = new HashSet<>();
for(ResourceIds.Table.Package pkg : packageIdSet){
ids.add(pkg.id);
}
return ids.size() == packageIdSet.size();
}
public EncodeMaterials addFramework(FrameworkApk frameworkApk) {
if(frameworkApk!=null){
addFramework(frameworkApk.getTableBlock());

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -15,21 +15,21 @@
*/
package com.reandroid.apk.xmlencoder;
import com.reandroid.archive.APKArchive;
import com.reandroid.archive.FileInputSource;
import com.reandroid.archive.InputSource;
import com.reandroid.apk.ApkUtil;
import com.reandroid.apk.UncompressedFiles;
import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.chunk.TypeBlock;
import com.reandroid.arsc.value.Entry;
import com.reandroid.xml.source.XMLFileSource;
import com.reandroid.xml.source.XMLSource;
import com.reandroid.archive.APKArchive;
import com.reandroid.archive.FileInputSource;
import com.reandroid.archive.InputSource;
import com.reandroid.apk.ApkUtil;
import com.reandroid.apk.UncompressedFiles;
import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.chunk.TypeBlock;
import com.reandroid.arsc.value.Entry;
import com.reandroid.xml.source.XMLFileSource;
import com.reandroid.xml.source.XMLSource;
import java.io.File;
import java.util.List;
import java.io.File;
import java.util.List;
public class FilePathEncoder {
public class FilePathEncoder {
private final EncodeMaterials materials;
private APKArchive apkArchive;
private UncompressedFiles uncompressedFiles;
@ -78,6 +78,9 @@ package com.reandroid.apk.xmlencoder;
entry.setValueAsString(path);
entry.setSpecReference(materials.getSpecString(name));
InputSource inputSource=createInputSource(path, resFile);
if(inputSource instanceof XMLEncodeSource){
((XMLEncodeSource)inputSource).setEntry(entry);
}
addInputSource(inputSource);
return inputSource;
}

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -45,14 +45,13 @@ class PackageCreator {
}
public PackageBlock createNew(TableBlock tableBlock, ResourceIds.Table.Package pkgResourceIds){
loadNames(pkgResourceIds);
PackageBlock packageBlock=new PackageBlock();
PackageBlock packageBlock = tableBlock.getPackageArray().createNext();
packageBlock.setName(mPackageName);
packageBlock.setId(mPackageId);
loadPackageInfoJson(packageBlock);
this.mPackageName = packageBlock.getName();
tableBlock.getPackageArray()
.add(packageBlock);
packageBlock.getSpecStringPool()
.addStrings(mSpecNames);

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -13,24 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.apk.xmlencoder;
package com.reandroid.apk.xmlencoder;
import com.reandroid.apk.*;
import com.reandroid.archive.APKArchive;
import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.chunk.xml.AndroidManifestBlock;
import com.reandroid.xml.XMLDocument;
import com.reandroid.xml.XMLException;
import com.reandroid.xml.source.XMLFileSource;
import com.reandroid.xml.source.XMLSource;
import com.reandroid.apk.*;
import com.reandroid.archive.APKArchive;
import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.chunk.xml.AndroidManifestBlock;
import com.reandroid.xml.XMLDocument;
import com.reandroid.xml.XMLException;
import com.reandroid.xml.source.XMLFileSource;
import com.reandroid.xml.source.XMLSource;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.zip.ZipEntry;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.zip.ZipEntry;
public class RESEncoder {
public class RESEncoder {
private APKLogger apkLogger;
private final TableBlock tableBlock;
private final Set<File> parsedFiles = new HashSet<>();
@ -75,7 +75,7 @@
Map<File, PackageBlock> packageBlockMap=new HashMap<>();
for(File pubXmlFile:pubXmlFileList){
ResourceIds.Table.Package pkgResourceIds=map.get(pubXmlFile);
ResourceIds.Table.Package pkgResourceIds = map.get(pubXmlFile);
if(pkgResourceIds==null){
continue;
}
@ -83,6 +83,7 @@
PackageBlock packageBlock = createPackage(pkgResourceIds, pubXmlFile);
encodeMaterials.setCurrentPackage(packageBlock);
encodeMaterials.setCurrentLocalPackage(pkgResourceIds);
packageBlockMap.put(pubXmlFile, packageBlock);
ValuesEncoder valuesEncoder = new ValuesEncoder(encodeMaterials);
@ -101,12 +102,16 @@
addParsedFiles(fileAttrs);
}
}
File manifestFile = null;
for(File pubXmlFile:pubXmlFileList){
ResourceIds.Table.Package pkgResourceIds=map.get(pubXmlFile);
ResourceIds.Table.Package pkgResourceIds = map.get(pubXmlFile);
if(pkgResourceIds==null){
continue;
}
addParsedFiles(pubXmlFile);
if(manifestFile == null){
manifestFile = toAndroidManifest(pubXmlFile);
}
PackageBlock packageBlock=packageBlockMap.get(pubXmlFile);
@ -114,6 +119,7 @@
packageBlock = createPackage(pkgResourceIds, pubXmlFile);
}
encodeMaterials.setCurrentPackage(packageBlock);
encodeMaterials.setCurrentLocalPackage(pkgResourceIds);
File resDir=toResDirectory(pubXmlFile);
encodeResDir(encodeMaterials, resDir);
@ -124,16 +130,19 @@
packageBlock.sortTypes();
packageBlock.refresh();
File manifestFile=toAndroidManifest(pubXmlFile);
}
tableBlock.refresh();
PackageBlock packageBlock = tableBlock.pickOne();
if(manifestFile != null){
if(packageBlock != null){
encodeMaterials.setCurrentPackage(packageBlock);
}
XMLSource xmlSource =
new XMLFileSource(AndroidManifestBlock.FILE_NAME, manifestFile);
XMLEncodeSource xmlEncodeSource =
new XMLEncodeSource(encodeMaterials, xmlSource);
getApkModule().getApkArchive().add(xmlEncodeSource);
}
tableBlock.refresh();
}
private PackageBlock createPackage(ResourceIds.Table.Package pkgResourceIds
, File pubXmlFile){
@ -303,4 +312,4 @@
apkLogger.logVerbose(msg);
}
}
}
}

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -17,7 +17,9 @@ package com.reandroid.apk.xmlencoder;
import com.reandroid.archive.ByteInputSource;
import com.reandroid.apk.CrcOutputStream;
import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.chunk.xml.ResXmlDocument;
import com.reandroid.arsc.value.Entry;
import com.reandroid.xml.XMLException;
import com.reandroid.xml.source.XMLSource;
@ -28,11 +30,27 @@ public class XMLEncodeSource extends ByteInputSource {
private final EncodeMaterials encodeMaterials;
private final XMLSource xmlSource;
private ResXmlDocument resXmlDocument;
public XMLEncodeSource(EncodeMaterials encodeMaterials, XMLSource xmlSource){
private Entry mEntry;
public XMLEncodeSource(EncodeMaterials encodeMaterials, XMLSource xmlSource, Entry entry){
super(new byte[0], xmlSource.getPath());
this.encodeMaterials=encodeMaterials;
this.xmlSource=xmlSource;
this.encodeMaterials = encodeMaterials;
this.xmlSource = xmlSource;
this.mEntry = entry;
}
public XMLEncodeSource(EncodeMaterials encodeMaterials, XMLSource xmlSource){
this(encodeMaterials, xmlSource, null);
}
public XMLSource getXmlSource() {
return xmlSource;
}
public Entry getEntry(){
return mEntry;
}
public void setEntry(Entry entry) {
this.mEntry = entry;
}
@Override
public long getLength() throws IOException{
return getResXmlBlock().countBytes();
@ -64,7 +82,13 @@ public class XMLEncodeSource extends ByteInputSource {
try {
XMLFileEncoder xmlFileEncoder=new XMLFileEncoder(encodeMaterials);
xmlFileEncoder.setCurrentPath(xmlSource.getPath());
encodeMaterials.logVerbose("Encoding xml: "+xmlSource.getPath());
EncodeMaterials encodeMaterials = this.encodeMaterials;
encodeMaterials.logVerbose("Encoding xml: " + xmlSource.getPath());
PackageBlock currentPackage = encodeMaterials.getCurrentPackage();
PackageBlock packageBlock = getEntryPackageBlock();
if(packageBlock != null && packageBlock != currentPackage){
encodeMaterials.setCurrentPackage(packageBlock);
}
resXmlDocument = xmlFileEncoder.encode(xmlSource.getXMLDocument());
} catch (XMLException ex) {
throw new EncodeException("XMLException on: '"+xmlSource.getPath()
@ -72,6 +96,13 @@ public class XMLEncodeSource extends ByteInputSource {
}
return resXmlDocument;
}
private PackageBlock getEntryPackageBlock(){
Entry entry = getEntry();
if(entry != null){
return entry.getPackageBlock();
}
return null;
}
@Override
public void disposeInputSource(){
this.xmlSource.disposeXml();