mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-04-29 22:04:25 +02:00
fix multi-package xml compiling #40
This commit is contained in:
parent
e136a8d570
commit
ada5aaf17d
@ -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();
|
||||
|
@ -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,12 +110,35 @@ 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){
|
||||
for(ResourceIds.Table.Package pkg:packageIdSet){
|
||||
Integer resId = pkg.getResourceId(type, name);
|
||||
if(resId!=null){
|
||||
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){
|
||||
@ -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());
|
||||
|
@ -1,35 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.reandroid.apk.xmlencoder;
|
||||
|
||||
import com.reandroid.apk.APKLogger;
|
||||
@ -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);
|
||||
|
||||
|
@ -1,306 +1,315 @@
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.reandroid.apk.xmlencoder;
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
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 {
|
||||
private APKLogger apkLogger;
|
||||
private final TableBlock tableBlock;
|
||||
private final Set<File> parsedFiles = new HashSet<>();
|
||||
private final ApkModule apkModule;
|
||||
public RESEncoder(){
|
||||
this(new ApkModule("encoded",
|
||||
new APKArchive()), new TableBlock());
|
||||
}
|
||||
public RESEncoder(ApkModule module, TableBlock block){
|
||||
this.apkModule = module;
|
||||
this.tableBlock = block;
|
||||
if(!module.hasTableBlock()){
|
||||
BlockInputSource<TableBlock> inputSource=
|
||||
new BlockInputSource<>(TableBlock.FILE_NAME, block);
|
||||
inputSource.setMethod(ZipEntry.STORED);
|
||||
this.apkModule.getUncompressedFiles().addPath(inputSource);
|
||||
this.apkModule.getApkArchive().add(inputSource);
|
||||
}
|
||||
}
|
||||
public TableBlock getTableBlock(){
|
||||
return tableBlock;
|
||||
}
|
||||
public ApkModule getApkModule(){
|
||||
return apkModule;
|
||||
}
|
||||
public void scanDirectory(File mainDir) throws IOException, XMLException {
|
||||
scanResourceFiles(mainDir);
|
||||
}
|
||||
private void scanResourceFiles(File mainDir) throws IOException, XMLException {
|
||||
List<File> pubXmlFileList = searchPublicXmlFiles(mainDir);
|
||||
if(pubXmlFileList.size()==0){
|
||||
throw new IOException("No .*/values/"
|
||||
+ ApkUtil.FILE_NAME_PUBLIC_XML+" file found in '"+mainDir);
|
||||
}
|
||||
preloadStringPool(pubXmlFileList);
|
||||
public class RESEncoder {
|
||||
private APKLogger apkLogger;
|
||||
private final TableBlock tableBlock;
|
||||
private final Set<File> parsedFiles = new HashSet<>();
|
||||
private final ApkModule apkModule;
|
||||
public RESEncoder(){
|
||||
this(new ApkModule("encoded",
|
||||
new APKArchive()), new TableBlock());
|
||||
}
|
||||
public RESEncoder(ApkModule module, TableBlock block){
|
||||
this.apkModule = module;
|
||||
this.tableBlock = block;
|
||||
if(!module.hasTableBlock()){
|
||||
BlockInputSource<TableBlock> inputSource=
|
||||
new BlockInputSource<>(TableBlock.FILE_NAME, block);
|
||||
inputSource.setMethod(ZipEntry.STORED);
|
||||
this.apkModule.getUncompressedFiles().addPath(inputSource);
|
||||
this.apkModule.getApkArchive().add(inputSource);
|
||||
}
|
||||
}
|
||||
public TableBlock getTableBlock(){
|
||||
return tableBlock;
|
||||
}
|
||||
public ApkModule getApkModule(){
|
||||
return apkModule;
|
||||
}
|
||||
public void scanDirectory(File mainDir) throws IOException, XMLException {
|
||||
scanResourceFiles(mainDir);
|
||||
}
|
||||
private void scanResourceFiles(File mainDir) throws IOException, XMLException {
|
||||
List<File> pubXmlFileList = searchPublicXmlFiles(mainDir);
|
||||
if(pubXmlFileList.size()==0){
|
||||
throw new IOException("No .*/values/"
|
||||
+ ApkUtil.FILE_NAME_PUBLIC_XML+" file found in '"+mainDir);
|
||||
}
|
||||
preloadStringPool(pubXmlFileList);
|
||||
|
||||
EncodeMaterials encodeMaterials=new EncodeMaterials();
|
||||
EncodeMaterials encodeMaterials=new EncodeMaterials();
|
||||
|
||||
Map<File, ResourceIds.Table.Package> map =
|
||||
initializeEncodeMaterials(pubXmlFileList, encodeMaterials);
|
||||
Map<File, ResourceIds.Table.Package> map =
|
||||
initializeEncodeMaterials(pubXmlFileList, encodeMaterials);
|
||||
|
||||
Map<File, PackageBlock> packageBlockMap=new HashMap<>();
|
||||
Map<File, PackageBlock> packageBlockMap=new HashMap<>();
|
||||
|
||||
for(File pubXmlFile:pubXmlFileList){
|
||||
ResourceIds.Table.Package pkgResourceIds=map.get(pubXmlFile);
|
||||
if(pkgResourceIds==null){
|
||||
continue;
|
||||
}
|
||||
addParsedFiles(pubXmlFile);
|
||||
for(File pubXmlFile:pubXmlFileList){
|
||||
ResourceIds.Table.Package pkgResourceIds = map.get(pubXmlFile);
|
||||
if(pkgResourceIds==null){
|
||||
continue;
|
||||
}
|
||||
addParsedFiles(pubXmlFile);
|
||||
|
||||
PackageBlock packageBlock = createPackage(pkgResourceIds, pubXmlFile);
|
||||
encodeMaterials.setCurrentPackage(packageBlock);
|
||||
packageBlockMap.put(pubXmlFile, packageBlock);
|
||||
PackageBlock packageBlock = createPackage(pkgResourceIds, pubXmlFile);
|
||||
encodeMaterials.setCurrentPackage(packageBlock);
|
||||
encodeMaterials.setCurrentLocalPackage(pkgResourceIds);
|
||||
packageBlockMap.put(pubXmlFile, packageBlock);
|
||||
|
||||
ValuesEncoder valuesEncoder = new ValuesEncoder(encodeMaterials);
|
||||
File fileIds = toId(pubXmlFile);
|
||||
if(fileIds.isFile()){
|
||||
valuesEncoder.encodeValuesXml(fileIds);
|
||||
packageBlock.sortTypes();
|
||||
packageBlock.refresh();
|
||||
addParsedFiles(fileIds);
|
||||
}
|
||||
File fileAttrs = toAttr(pubXmlFile);
|
||||
if(fileAttrs.isFile()){
|
||||
valuesEncoder.encodeValuesXml(fileAttrs);
|
||||
packageBlock.sortTypes();
|
||||
packageBlock.refresh();
|
||||
addParsedFiles(fileAttrs);
|
||||
}
|
||||
}
|
||||
for(File pubXmlFile:pubXmlFileList){
|
||||
ResourceIds.Table.Package pkgResourceIds=map.get(pubXmlFile);
|
||||
if(pkgResourceIds==null){
|
||||
continue;
|
||||
}
|
||||
addParsedFiles(pubXmlFile);
|
||||
ValuesEncoder valuesEncoder = new ValuesEncoder(encodeMaterials);
|
||||
File fileIds = toId(pubXmlFile);
|
||||
if(fileIds.isFile()){
|
||||
valuesEncoder.encodeValuesXml(fileIds);
|
||||
packageBlock.sortTypes();
|
||||
packageBlock.refresh();
|
||||
addParsedFiles(fileIds);
|
||||
}
|
||||
File fileAttrs = toAttr(pubXmlFile);
|
||||
if(fileAttrs.isFile()){
|
||||
valuesEncoder.encodeValuesXml(fileAttrs);
|
||||
packageBlock.sortTypes();
|
||||
packageBlock.refresh();
|
||||
addParsedFiles(fileAttrs);
|
||||
}
|
||||
}
|
||||
File manifestFile = null;
|
||||
for(File pubXmlFile:pubXmlFileList){
|
||||
ResourceIds.Table.Package pkgResourceIds = map.get(pubXmlFile);
|
||||
if(pkgResourceIds==null){
|
||||
continue;
|
||||
}
|
||||
addParsedFiles(pubXmlFile);
|
||||
if(manifestFile == null){
|
||||
manifestFile = toAndroidManifest(pubXmlFile);
|
||||
}
|
||||
|
||||
PackageBlock packageBlock=packageBlockMap.get(pubXmlFile);
|
||||
PackageBlock packageBlock=packageBlockMap.get(pubXmlFile);
|
||||
|
||||
if(packageBlock==null){
|
||||
packageBlock = createPackage(pkgResourceIds, pubXmlFile);
|
||||
}
|
||||
encodeMaterials.setCurrentPackage(packageBlock);
|
||||
if(packageBlock==null){
|
||||
packageBlock = createPackage(pkgResourceIds, pubXmlFile);
|
||||
}
|
||||
encodeMaterials.setCurrentPackage(packageBlock);
|
||||
encodeMaterials.setCurrentLocalPackage(pkgResourceIds);
|
||||
|
||||
File resDir=toResDirectory(pubXmlFile);
|
||||
encodeResDir(encodeMaterials, resDir);
|
||||
FilePathEncoder filePathEncoder = new FilePathEncoder(encodeMaterials);
|
||||
filePathEncoder.setApkArchive(getApkModule().getApkArchive());
|
||||
filePathEncoder.setUncompressedFiles(getApkModule().getUncompressedFiles());
|
||||
filePathEncoder.encodeResDir(resDir);
|
||||
File resDir=toResDirectory(pubXmlFile);
|
||||
encodeResDir(encodeMaterials, resDir);
|
||||
FilePathEncoder filePathEncoder = new FilePathEncoder(encodeMaterials);
|
||||
filePathEncoder.setApkArchive(getApkModule().getApkArchive());
|
||||
filePathEncoder.setUncompressedFiles(getApkModule().getUncompressedFiles());
|
||||
filePathEncoder.encodeResDir(resDir);
|
||||
|
||||
packageBlock.sortTypes();
|
||||
packageBlock.refresh();
|
||||
packageBlock.sortTypes();
|
||||
packageBlock.refresh();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
private PackageBlock createPackage(ResourceIds.Table.Package pkgResourceIds
|
||||
, File pubXmlFile){
|
||||
PackageCreator packageCreator = new PackageCreator();
|
||||
packageCreator.setPackageName(pkgResourceIds.name);
|
||||
packageCreator.setAPKLogger(apkLogger);
|
||||
packageCreator.setPackageDirectory(toPackageDirectory(pubXmlFile));
|
||||
return packageCreator.createNew(this.tableBlock, pkgResourceIds);
|
||||
}
|
||||
private void preloadStringPool(List<File> pubXmlFileList){
|
||||
logMessage("Loading string pool ...");
|
||||
ValuesStringPoolBuilder poolBuilder=new ValuesStringPoolBuilder();
|
||||
for(File pubXml:pubXmlFileList){
|
||||
File resDir=toResDirectory(pubXml);
|
||||
List<File> valuesDirList = listValuesDir(resDir);
|
||||
for(File dir:valuesDirList){
|
||||
logVerbose(poolBuilder.size()+" building pool: "+dir.getName());
|
||||
poolBuilder.scanValuesDirectory(dir);
|
||||
}
|
||||
}
|
||||
poolBuilder.addTo(tableBlock.getTableStringPool());
|
||||
}
|
||||
|
||||
File manifestFile=toAndroidManifest(pubXmlFile);
|
||||
XMLSource xmlSource =
|
||||
new XMLFileSource(AndroidManifestBlock.FILE_NAME, manifestFile);
|
||||
XMLEncodeSource xmlEncodeSource =
|
||||
new XMLEncodeSource(encodeMaterials, xmlSource);
|
||||
private Map<File, ResourceIds.Table.Package> initializeEncodeMaterials(
|
||||
List<File> pubXmlFileList, EncodeMaterials encodeMaterials)
|
||||
throws IOException, XMLException {
|
||||
|
||||
getApkModule().getApkArchive().add(xmlEncodeSource);
|
||||
}
|
||||
tableBlock.refresh();
|
||||
}
|
||||
private PackageBlock createPackage(ResourceIds.Table.Package pkgResourceIds
|
||||
, File pubXmlFile){
|
||||
PackageCreator packageCreator = new PackageCreator();
|
||||
packageCreator.setPackageName(pkgResourceIds.name);
|
||||
packageCreator.setAPKLogger(apkLogger);
|
||||
packageCreator.setPackageDirectory(toPackageDirectory(pubXmlFile));
|
||||
return packageCreator.createNew(this.tableBlock, pkgResourceIds);
|
||||
}
|
||||
private void preloadStringPool(List<File> pubXmlFileList){
|
||||
logMessage("Loading string pool ...");
|
||||
ValuesStringPoolBuilder poolBuilder=new ValuesStringPoolBuilder();
|
||||
for(File pubXml:pubXmlFileList){
|
||||
File resDir=toResDirectory(pubXml);
|
||||
List<File> valuesDirList = listValuesDir(resDir);
|
||||
for(File dir:valuesDirList){
|
||||
logVerbose(poolBuilder.size()+" building pool: "+dir.getName());
|
||||
poolBuilder.scanValuesDirectory(dir);
|
||||
}
|
||||
}
|
||||
poolBuilder.addTo(tableBlock.getTableStringPool());
|
||||
}
|
||||
encodeMaterials.setAPKLogger(apkLogger);
|
||||
|
||||
private Map<File, ResourceIds.Table.Package> initializeEncodeMaterials(
|
||||
List<File> pubXmlFileList, EncodeMaterials encodeMaterials)
|
||||
throws IOException, XMLException {
|
||||
Map<File, ResourceIds.Table.Package> results = new HashMap<>();
|
||||
|
||||
encodeMaterials.setAPKLogger(apkLogger);
|
||||
String packageName=null;
|
||||
for(File pubXmlFile:pubXmlFileList){
|
||||
if(packageName==null){
|
||||
File manifestFile = toAndroidManifest(pubXmlFile);
|
||||
packageName=readManifestPackageName(manifestFile);
|
||||
FrameworkApk frameworkApk = getApkModule()
|
||||
.initializeAndroidFramework(XMLDocument.load(manifestFile));
|
||||
encodeMaterials.addFramework(frameworkApk);
|
||||
}
|
||||
ResourceIds resourceIds=new ResourceIds();
|
||||
resourceIds.fromXml(pubXmlFile);
|
||||
List<ResourceIds.Table.Package> pkgList = resourceIds.getTable()
|
||||
.listPackages();
|
||||
if(pkgList.size()==0){
|
||||
continue;
|
||||
}
|
||||
ResourceIds.Table.Package pkg = pkgList.get(0);
|
||||
if(pkg.name==null){
|
||||
pkg.name=packageName;
|
||||
}
|
||||
encodeMaterials.addPackageIds(pkg);
|
||||
results.put(pubXmlFile, pkg);
|
||||
}
|
||||
|
||||
Map<File, ResourceIds.Table.Package> results = new HashMap<>();
|
||||
encodeMaterials.setAPKLogger(apkLogger);
|
||||
return results;
|
||||
}
|
||||
private String readManifestPackageName(File manifestFile) throws XMLException {
|
||||
XMLDocument manifestDocument = XMLDocument.load(manifestFile);
|
||||
return manifestDocument
|
||||
.getDocumentElement().getAttributeValue("package");
|
||||
}
|
||||
private void encodeResDir(EncodeMaterials materials, File resDir) throws XMLException {
|
||||
|
||||
String packageName=null;
|
||||
for(File pubXmlFile:pubXmlFileList){
|
||||
if(packageName==null){
|
||||
File manifestFile = toAndroidManifest(pubXmlFile);
|
||||
packageName=readManifestPackageName(manifestFile);
|
||||
FrameworkApk frameworkApk = getApkModule()
|
||||
.initializeAndroidFramework(XMLDocument.load(manifestFile));
|
||||
encodeMaterials.addFramework(frameworkApk);
|
||||
}
|
||||
ResourceIds resourceIds=new ResourceIds();
|
||||
resourceIds.fromXml(pubXmlFile);
|
||||
List<ResourceIds.Table.Package> pkgList = resourceIds.getTable()
|
||||
.listPackages();
|
||||
if(pkgList.size()==0){
|
||||
continue;
|
||||
}
|
||||
ResourceIds.Table.Package pkg = pkgList.get(0);
|
||||
if(pkg.name==null){
|
||||
pkg.name=packageName;
|
||||
}
|
||||
encodeMaterials.addPackageIds(pkg);
|
||||
results.put(pubXmlFile, pkg);
|
||||
}
|
||||
List<File> valuesDirList = listValuesDir(resDir);
|
||||
for(File valuesDir:valuesDirList){
|
||||
encodeValuesDir(materials, valuesDir);
|
||||
}
|
||||
}
|
||||
private void encodeValuesDir(EncodeMaterials materials, File valuesDir) throws XMLException {
|
||||
ValuesEncoder valuesEncoder = new ValuesEncoder(materials);
|
||||
List<File> xmlFiles = ApkUtil.listFiles(valuesDir, ".xml");
|
||||
EncodeUtil.sortValuesXml(xmlFiles);
|
||||
for(File file:xmlFiles){
|
||||
if(isAlreadyParsed(file)){
|
||||
continue;
|
||||
}
|
||||
addParsedFiles(file);
|
||||
valuesEncoder.encodeValuesXml(file);
|
||||
}
|
||||
}
|
||||
private File toAndroidManifest(File pubXmlFile){
|
||||
File resDirectory = toResDirectory(pubXmlFile);
|
||||
File packageDirectory = resDirectory.getParentFile();
|
||||
File root = packageDirectory.getParentFile();
|
||||
return new File(root, AndroidManifestBlock.FILE_NAME);
|
||||
}
|
||||
private File toPackageDirectory(File pubXmlFile){
|
||||
return toResDirectory(pubXmlFile)
|
||||
.getParentFile();
|
||||
}
|
||||
private File toResDirectory(File pubXmlFile){
|
||||
return pubXmlFile
|
||||
.getParentFile()
|
||||
.getParentFile();
|
||||
}
|
||||
private File toId(File pubXmlFile){
|
||||
return new File(pubXmlFile.getParentFile(), "ids.xml");
|
||||
}
|
||||
private File toAttr(File pubXmlFile){
|
||||
return new File(pubXmlFile.getParentFile(), "attrs.xml");
|
||||
}
|
||||
private List<File> listValuesDir(File resDir){
|
||||
List<File> results=new ArrayList<>();
|
||||
File def=new File(resDir, "values");
|
||||
results.add(def);
|
||||
File[] dirList=resDir.listFiles();
|
||||
if(dirList!=null){
|
||||
for(File dir:dirList){
|
||||
if(def.equals(dir) || !dir.isDirectory()){
|
||||
continue;
|
||||
}
|
||||
if(dir.getName().startsWith("values-")){
|
||||
results.add(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
private List<File> searchPublicXmlFiles(File mainDir){
|
||||
logVerbose("Searching public.xml: "+mainDir);
|
||||
List<File> dirList=ApkUtil.listDirectories(mainDir);
|
||||
List<File> xmlFiles = new ArrayList<>();
|
||||
for(File dir:dirList){
|
||||
if(dir.getName().equals("root")){
|
||||
continue;
|
||||
}
|
||||
xmlFiles.addAll(
|
||||
ApkUtil.recursiveFiles(dir, ApkUtil.FILE_NAME_PUBLIC_XML));
|
||||
}
|
||||
List<File> results = new ArrayList<>();
|
||||
for(File file:xmlFiles){
|
||||
if(!EncodeUtil.isPublicXml(file)){
|
||||
continue;
|
||||
}
|
||||
if(toAndroidManifest(file).isFile()){
|
||||
results.add(file);
|
||||
}
|
||||
}
|
||||
EncodeUtil.sortPublicXml(results);
|
||||
return results;
|
||||
}
|
||||
|
||||
encodeMaterials.setAPKLogger(apkLogger);
|
||||
return results;
|
||||
}
|
||||
private String readManifestPackageName(File manifestFile) throws XMLException {
|
||||
XMLDocument manifestDocument = XMLDocument.load(manifestFile);
|
||||
return manifestDocument
|
||||
.getDocumentElement().getAttributeValue("package");
|
||||
}
|
||||
private void encodeResDir(EncodeMaterials materials, File resDir) throws XMLException {
|
||||
|
||||
List<File> valuesDirList = listValuesDir(resDir);
|
||||
for(File valuesDir:valuesDirList){
|
||||
encodeValuesDir(materials, valuesDir);
|
||||
}
|
||||
}
|
||||
private void encodeValuesDir(EncodeMaterials materials, File valuesDir) throws XMLException {
|
||||
ValuesEncoder valuesEncoder = new ValuesEncoder(materials);
|
||||
List<File> xmlFiles = ApkUtil.listFiles(valuesDir, ".xml");
|
||||
EncodeUtil.sortValuesXml(xmlFiles);
|
||||
for(File file:xmlFiles){
|
||||
if(isAlreadyParsed(file)){
|
||||
continue;
|
||||
}
|
||||
addParsedFiles(file);
|
||||
valuesEncoder.encodeValuesXml(file);
|
||||
}
|
||||
}
|
||||
private File toAndroidManifest(File pubXmlFile){
|
||||
File resDirectory = toResDirectory(pubXmlFile);
|
||||
File packageDirectory = resDirectory.getParentFile();
|
||||
File root = packageDirectory.getParentFile();
|
||||
return new File(root, AndroidManifestBlock.FILE_NAME);
|
||||
}
|
||||
private File toPackageDirectory(File pubXmlFile){
|
||||
return toResDirectory(pubXmlFile)
|
||||
.getParentFile();
|
||||
}
|
||||
private File toResDirectory(File pubXmlFile){
|
||||
return pubXmlFile
|
||||
.getParentFile()
|
||||
.getParentFile();
|
||||
}
|
||||
private File toId(File pubXmlFile){
|
||||
return new File(pubXmlFile.getParentFile(), "ids.xml");
|
||||
}
|
||||
private File toAttr(File pubXmlFile){
|
||||
return new File(pubXmlFile.getParentFile(), "attrs.xml");
|
||||
}
|
||||
private List<File> listValuesDir(File resDir){
|
||||
List<File> results=new ArrayList<>();
|
||||
File def=new File(resDir, "values");
|
||||
results.add(def);
|
||||
File[] dirList=resDir.listFiles();
|
||||
if(dirList!=null){
|
||||
for(File dir:dirList){
|
||||
if(def.equals(dir) || !dir.isDirectory()){
|
||||
continue;
|
||||
}
|
||||
if(dir.getName().startsWith("values-")){
|
||||
results.add(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
private List<File> searchPublicXmlFiles(File mainDir){
|
||||
logVerbose("Searching public.xml: "+mainDir);
|
||||
List<File> dirList=ApkUtil.listDirectories(mainDir);
|
||||
List<File> xmlFiles = new ArrayList<>();
|
||||
for(File dir:dirList){
|
||||
if(dir.getName().equals("root")){
|
||||
continue;
|
||||
}
|
||||
xmlFiles.addAll(
|
||||
ApkUtil.recursiveFiles(dir, ApkUtil.FILE_NAME_PUBLIC_XML));
|
||||
}
|
||||
List<File> results = new ArrayList<>();
|
||||
for(File file:xmlFiles){
|
||||
if(!EncodeUtil.isPublicXml(file)){
|
||||
continue;
|
||||
}
|
||||
if(toAndroidManifest(file).isFile()){
|
||||
results.add(file);
|
||||
}
|
||||
}
|
||||
EncodeUtil.sortPublicXml(results);
|
||||
return results;
|
||||
}
|
||||
|
||||
private boolean isAlreadyParsed(File file){
|
||||
return parsedFiles.contains(file);
|
||||
}
|
||||
private void addParsedFiles(File file){
|
||||
parsedFiles.add(file);
|
||||
}
|
||||
public void setAPKLogger(APKLogger logger) {
|
||||
this.apkLogger = logger;
|
||||
this.apkModule.setAPKLogger(logger);
|
||||
}
|
||||
private void logMessage(String msg) {
|
||||
if(apkLogger!=null){
|
||||
apkLogger.logMessage(msg);
|
||||
}
|
||||
}
|
||||
private void logError(String msg, Throwable tr) {
|
||||
if(apkLogger!=null){
|
||||
apkLogger.logError(msg, tr);
|
||||
}
|
||||
}
|
||||
private void logVerbose(String msg) {
|
||||
if(apkLogger!=null){
|
||||
apkLogger.logVerbose(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
private boolean isAlreadyParsed(File file){
|
||||
return parsedFiles.contains(file);
|
||||
}
|
||||
private void addParsedFiles(File file){
|
||||
parsedFiles.add(file);
|
||||
}
|
||||
public void setAPKLogger(APKLogger logger) {
|
||||
this.apkLogger = logger;
|
||||
this.apkModule.setAPKLogger(logger);
|
||||
}
|
||||
private void logMessage(String msg) {
|
||||
if(apkLogger!=null){
|
||||
apkLogger.logMessage(msg);
|
||||
}
|
||||
}
|
||||
private void logError(String msg, Throwable tr) {
|
||||
if(apkLogger!=null){
|
||||
apkLogger.logError(msg, tr);
|
||||
}
|
||||
}
|
||||
private void logVerbose(String msg) {
|
||||
if(apkLogger!=null){
|
||||
apkLogger.logVerbose(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user