mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-05-01 22:54:26 +02:00
create XMLEncoder
This commit is contained in:
parent
a7424bbf96
commit
0f29fa6596
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
public class EncodeException extends IllegalArgumentException{
|
||||||
|
public EncodeException(String message){
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
public EncodeException(String message, Throwable cause){
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,317 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.apk.APKLogger;
|
||||||
|
import com.reandroid.lib.apk.ResourceIds;
|
||||||
|
import com.reandroid.lib.arsc.chunk.PackageBlock;
|
||||||
|
import com.reandroid.lib.arsc.chunk.TypeBlock;
|
||||||
|
import com.reandroid.lib.arsc.container.SpecTypePair;
|
||||||
|
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
||||||
|
import com.reandroid.lib.arsc.group.EntryGroup;
|
||||||
|
import com.reandroid.lib.arsc.item.SpecString;
|
||||||
|
import com.reandroid.lib.arsc.util.FrameworkTable;
|
||||||
|
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||||
|
import com.reandroid.lib.common.ResourceResolver;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
|
public class EncodeMaterials implements ResourceResolver {
|
||||||
|
private ResourceIds.Table.Package packageIds;
|
||||||
|
private PackageBlock currentPackage;
|
||||||
|
private final Set<FrameworkTable> frameworkTables = new HashSet<>();
|
||||||
|
private APKLogger apkLogger;
|
||||||
|
public EncodeMaterials(){
|
||||||
|
}
|
||||||
|
public SpecString getSpecString(String name){
|
||||||
|
return currentPackage.getSpecStringPool()
|
||||||
|
.get(name)
|
||||||
|
.get(0);
|
||||||
|
}
|
||||||
|
public void addTableStringPool(Collection<String> stringList){
|
||||||
|
getCurrentPackage()
|
||||||
|
.getTableBlock()
|
||||||
|
.getTableStringPool()
|
||||||
|
.addStrings(stringList);
|
||||||
|
}
|
||||||
|
public int resolveAttributeNameReference(String refString){
|
||||||
|
String packageName = null;
|
||||||
|
String type = "attr";
|
||||||
|
String name = refString;
|
||||||
|
int i=refString.lastIndexOf(':');
|
||||||
|
if(i>=0){
|
||||||
|
packageName=refString.substring(0, i);
|
||||||
|
name=refString.substring(i+1);
|
||||||
|
}
|
||||||
|
if(EncodeUtil.isEmpty(packageName)
|
||||||
|
|| packageName.equals(getCurrentPackageName())
|
||||||
|
|| !isFrameworkPackageName(packageName)){
|
||||||
|
|
||||||
|
return resolveLocalResourceId(type, name);
|
||||||
|
}
|
||||||
|
return resolveFrameworkResourceId(packageName, type, name);
|
||||||
|
}
|
||||||
|
public EntryBlock getAttributeBlock(String refString){
|
||||||
|
String packageName = null;
|
||||||
|
String type = "attr";
|
||||||
|
String name = refString;
|
||||||
|
int i=refString.lastIndexOf(':');
|
||||||
|
if(i>=0){
|
||||||
|
packageName=refString.substring(0, i);
|
||||||
|
name=refString.substring(i+1);
|
||||||
|
}
|
||||||
|
if(EncodeUtil.isEmpty(packageName)
|
||||||
|
|| packageName.equals(getCurrentPackageName())
|
||||||
|
|| !isFrameworkPackageName(packageName)){
|
||||||
|
|
||||||
|
return getLocalEntryBlock(type, name);
|
||||||
|
}
|
||||||
|
return getFrameworkEntry(type, name);
|
||||||
|
}
|
||||||
|
public int resolveReference(String refString){
|
||||||
|
if("@null".equals(refString)){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Matcher matcher = ValueDecoder.PATTERN_REFERENCE.matcher(refString);
|
||||||
|
if(!matcher.find()){
|
||||||
|
throw new EncodeException(
|
||||||
|
"Not proper reference string: '"+refString+"'");
|
||||||
|
}
|
||||||
|
String prefix=matcher.group(1);
|
||||||
|
String packageName = matcher.group(2);
|
||||||
|
if(packageName!=null && packageName.endsWith(":")){
|
||||||
|
packageName=packageName.substring(0, packageName.length()-1);
|
||||||
|
}
|
||||||
|
String type = matcher.group(4);
|
||||||
|
String name = matcher.group(5);
|
||||||
|
if(EncodeUtil.isEmpty(packageName)
|
||||||
|
|| packageName.equals(getCurrentPackageName())
|
||||||
|
|| !isFrameworkPackageName(packageName)){
|
||||||
|
return resolveLocalResourceId(type, name);
|
||||||
|
}
|
||||||
|
return resolveFrameworkResourceId(packageName, type, name);
|
||||||
|
}
|
||||||
|
public int resolveLocalResourceId(String type, String name){
|
||||||
|
ResourceIds.Table.Package.Type.Entry entry =
|
||||||
|
this.packageIds.getEntry(type, name);
|
||||||
|
if(entry!=null){
|
||||||
|
return entry.getResourceId();
|
||||||
|
}
|
||||||
|
EntryGroup entryGroup=getLocalEntryGroup(type, name);
|
||||||
|
if(entryGroup!=null){
|
||||||
|
return entryGroup.getResourceId();
|
||||||
|
}
|
||||||
|
throw new EncodeException("Local entry not found: " +
|
||||||
|
"type="+type+
|
||||||
|
", name="+name);
|
||||||
|
}
|
||||||
|
public int resolveFrameworkResourceId(String type, String name){
|
||||||
|
EntryBlock entryBlock = getFrameworkEntry(type, name);
|
||||||
|
if(entryBlock!=null){
|
||||||
|
return entryBlock.getResourceId();
|
||||||
|
}
|
||||||
|
throw new EncodeException("Framework entry not found: " +
|
||||||
|
"type="+type+
|
||||||
|
", name="+name);
|
||||||
|
}
|
||||||
|
public int resolveFrameworkResourceId(String packageName, String type, String name){
|
||||||
|
EntryBlock entryBlock = getFrameworkEntry(packageName, type, name);
|
||||||
|
if(entryBlock!=null){
|
||||||
|
return entryBlock.getResourceId();
|
||||||
|
}
|
||||||
|
throw new EncodeException("Framework entry not found: " +
|
||||||
|
"package="+packageName+
|
||||||
|
", type="+type+
|
||||||
|
", name="+name);
|
||||||
|
}
|
||||||
|
public int resolveFrameworkResourceId(int packageId, String type, String name){
|
||||||
|
EntryBlock entryBlock = getFrameworkEntry(packageId, type, name);
|
||||||
|
if(entryBlock!=null){
|
||||||
|
return entryBlock.getResourceId();
|
||||||
|
}
|
||||||
|
throw new EncodeException("Framework entry not found: " +
|
||||||
|
"packageId="+String.format("0x%02x", packageId)+
|
||||||
|
", type="+type+
|
||||||
|
", name="+name);
|
||||||
|
}
|
||||||
|
public EntryGroup getLocalEntryGroup(String type, String name){
|
||||||
|
for(EntryGroup entryGroup : currentPackage.listEntryGroup()){
|
||||||
|
if(type.equals(entryGroup.getTypeName()) &&
|
||||||
|
name.equals(entryGroup.getSpecName())){
|
||||||
|
return entryGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(PackageBlock packageBlock:currentPackage.getTableBlock().listPackages()){
|
||||||
|
if(packageBlock==currentPackage ||
|
||||||
|
packageBlock.getId()!=currentPackage.getId()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for(EntryGroup entryGroup : currentPackage.listEntryGroup()){
|
||||||
|
if(type.equals(entryGroup.getTypeName()) &&
|
||||||
|
name.equals(entryGroup.getSpecName())){
|
||||||
|
return entryGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public EntryBlock getLocalEntryBlock(String type, String name){
|
||||||
|
for(EntryGroup entryGroup : currentPackage.listEntryGroup()){
|
||||||
|
if(type.equals(entryGroup.getTypeName()) &&
|
||||||
|
name.equals(entryGroup.getSpecName())){
|
||||||
|
return entryGroup.pickOne();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SpecTypePair specTypePair=currentPackage.searchByTypeName(type);
|
||||||
|
if(specTypePair!=null){
|
||||||
|
for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){
|
||||||
|
for(EntryBlock entryBlock:typeBlock.listEntries()){
|
||||||
|
if(name.equals(entryBlock.getName())){
|
||||||
|
return entryBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(PackageBlock packageBlock:currentPackage.getTableBlock().listPackages()){
|
||||||
|
if(packageBlock==currentPackage ||
|
||||||
|
packageBlock.getId()!=currentPackage.getId()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
specTypePair=packageBlock.searchByTypeName(type);
|
||||||
|
if(specTypePair!=null){
|
||||||
|
for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){
|
||||||
|
for(EntryBlock entryBlock:typeBlock.listEntries()){
|
||||||
|
if(name.equals(entryBlock.getName())){
|
||||||
|
return entryBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public EntryBlock getFrameworkEntry(String type, String name){
|
||||||
|
for(FrameworkTable table:frameworkTables){
|
||||||
|
EntryBlock entryBlock = table.searchEntryBlock(type, name);
|
||||||
|
if(entryBlock!=null){
|
||||||
|
return entryBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
private boolean isFrameworkPackageName(String packageName){
|
||||||
|
for(FrameworkTable table:frameworkTables){
|
||||||
|
for(PackageBlock packageBlock:table.listPackages()){
|
||||||
|
if(packageName.equals(packageBlock.getName())){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public EntryBlock getFrameworkEntry(String packageName, String type, String name){
|
||||||
|
for(FrameworkTable table:frameworkTables){
|
||||||
|
for(PackageBlock packageBlock:table.listPackages()){
|
||||||
|
if(packageName.equals(packageBlock.getName())){
|
||||||
|
EntryBlock entryBlock = table.searchEntryBlock(type, name);
|
||||||
|
if(entryBlock!=null){
|
||||||
|
return entryBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public EntryBlock getFrameworkEntry(int packageId, String type, String name){
|
||||||
|
for(FrameworkTable table:frameworkTables){
|
||||||
|
for(PackageBlock packageBlock:table.listPackages()){
|
||||||
|
if(packageId==packageBlock.getId()){
|
||||||
|
EntryBlock entryBlock = table.searchEntryBlock(type, name);
|
||||||
|
if(entryBlock!=null){
|
||||||
|
return entryBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public EncodeMaterials setPackageIds(ResourceIds.Table.Package packageIds) {
|
||||||
|
this.packageIds = packageIds;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public EncodeMaterials setCurrentPackage(PackageBlock currentPackage) {
|
||||||
|
this.currentPackage = currentPackage;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public EncodeMaterials addFramework(FrameworkTable frameworkTable) {
|
||||||
|
frameworkTable.loadResourceNameMap();
|
||||||
|
this.frameworkTables.add(frameworkTable);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public EncodeMaterials setAPKLogger(APKLogger logger) {
|
||||||
|
this.apkLogger = logger;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceIds.Table.Package getPackageIds() {
|
||||||
|
return packageIds;
|
||||||
|
}
|
||||||
|
public PackageBlock getCurrentPackage() {
|
||||||
|
return currentPackage;
|
||||||
|
}
|
||||||
|
public String getCurrentPackageName(){
|
||||||
|
return currentPackage.getName();
|
||||||
|
}
|
||||||
|
public int getCurrentPackageId(){
|
||||||
|
return currentPackage.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int resolveResourceId(String packageName, String type, String name) {
|
||||||
|
if(packageName==null || packageName.equals(getCurrentPackageName())){
|
||||||
|
return resolveLocalResourceId(type, name);
|
||||||
|
}
|
||||||
|
return resolveFrameworkResourceId(packageName, type, name);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int resolveResourceId(int packageId, String type, String name) {
|
||||||
|
if(packageId==getCurrentPackageId()){
|
||||||
|
return resolveLocalResourceId(type, name);
|
||||||
|
}
|
||||||
|
return resolveFrameworkResourceId(packageId, type, name);
|
||||||
|
}
|
||||||
|
public void logMessage(String msg) {
|
||||||
|
if(apkLogger!=null){
|
||||||
|
apkLogger.logMessage(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void logError(String msg, Throwable tr) {
|
||||||
|
if(apkLogger!=null){
|
||||||
|
apkLogger.logError(msg, tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void logVerbose(String msg) {
|
||||||
|
if(apkLogger!=null){
|
||||||
|
apkLogger.logVerbose(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class EncodeUtil {
|
||||||
|
public static boolean isEmpty(String text){
|
||||||
|
if(text==null){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
text=text.trim();
|
||||||
|
return text.length()==0;
|
||||||
|
}
|
||||||
|
public static String getQualifiersFromValuesXml(File valuesXml){
|
||||||
|
String dirName=valuesXml.getParentFile().getName();
|
||||||
|
int i=dirName.indexOf('-');
|
||||||
|
if(i>0){
|
||||||
|
return dirName.substring(i);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
public static String getTypeNameFromValuesXml(File valuesXml){
|
||||||
|
String name=valuesXml.getName();
|
||||||
|
name=name.substring(0, name.length()-4);
|
||||||
|
if(!name.equals("plurals") && name.endsWith("s")){
|
||||||
|
name=name.substring(0, name.length()-1);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public static String sanitizeType(String type){
|
||||||
|
Matcher matcher=PATTERN_TYPE.matcher(type);
|
||||||
|
if(!matcher.find()){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return matcher.group(1);
|
||||||
|
}
|
||||||
|
public static final String NULL_PACKAGE_NAME = "NULL_PACKAGE_NAME";
|
||||||
|
private static final Pattern PATTERN_TYPE=Pattern.compile("^([a-z]+)[^a-z]*.*$");
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.chunk.PackageBlock;
|
||||||
|
import com.reandroid.lib.arsc.chunk.TypeBlock;
|
||||||
|
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
||||||
|
import com.reandroid.lib.arsc.item.SpecString;
|
||||||
|
import com.reandroid.lib.arsc.pool.TypeStringPool;
|
||||||
|
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||||
|
import com.reandroid.lib.arsc.value.ValueType;
|
||||||
|
import com.reandroid.xml.XMLDocument;
|
||||||
|
import com.reandroid.xml.XMLElement;
|
||||||
|
|
||||||
|
public class XMLValuesEncoder {
|
||||||
|
private final EncodeMaterials materials;
|
||||||
|
XMLValuesEncoder(EncodeMaterials materials){
|
||||||
|
this.materials=materials;
|
||||||
|
}
|
||||||
|
public void encode(String type, String qualifiers, XMLDocument xmlDocument){
|
||||||
|
XMLElement documentElement = xmlDocument.getDocumentElement();
|
||||||
|
TypeBlock typeBlock = getTypeBlock(type, qualifiers);
|
||||||
|
|
||||||
|
int count = documentElement.getChildesCount();
|
||||||
|
|
||||||
|
typeBlock.getEntryBlockArray().ensureSize(count);
|
||||||
|
|
||||||
|
for(int i=0;i<count;i++){
|
||||||
|
XMLElement element = documentElement.getChildAt(i);
|
||||||
|
encode(typeBlock, element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void encode(TypeBlock typeBlock, XMLElement element){
|
||||||
|
String name = element.getAttributeValue("name");
|
||||||
|
int resourceId = getMaterials()
|
||||||
|
.resolveLocalResourceId(typeBlock.getTypeName(), name);
|
||||||
|
EntryBlock entryBlock = typeBlock
|
||||||
|
.getOrCreateEntry((short) (0xffff & resourceId));
|
||||||
|
|
||||||
|
encodeValue(entryBlock, element);
|
||||||
|
|
||||||
|
if(!entryBlock.isNull()){
|
||||||
|
SpecString specString = getMaterials().getSpecString(name);
|
||||||
|
entryBlock.setSpecReference(specString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void encodeValue(EntryBlock entryBlock, XMLElement element){
|
||||||
|
String value = getValue(element);
|
||||||
|
encodeValue(entryBlock, value);
|
||||||
|
}
|
||||||
|
void encodeValue(EntryBlock entryBlock, String value){
|
||||||
|
if(EncodeUtil.isEmpty(value)){
|
||||||
|
encodeNullValue(entryBlock);
|
||||||
|
}else if(isLiteralEmpty(value)){
|
||||||
|
encodeLiteralEmptyValue(entryBlock, value);
|
||||||
|
}else if(isBoolean(value)){
|
||||||
|
encodeBooleanValue(entryBlock, value);
|
||||||
|
}else if(ValueDecoder.isReference(value)){
|
||||||
|
encodeReferenceValue(entryBlock, value);
|
||||||
|
}else {
|
||||||
|
encodeStringValue(entryBlock, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void encodeNullValue(EntryBlock entryBlock){
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
void encodeLiteralEmptyValue(EntryBlock entryBlock, String value){
|
||||||
|
entryBlock.setValueAsRaw(ValueType.NULL, 0);
|
||||||
|
}
|
||||||
|
void encodeBooleanValue(EntryBlock entryBlock, String value){
|
||||||
|
entryBlock.setValueAsBoolean("true".equals(value.toLowerCase()));
|
||||||
|
}
|
||||||
|
void encodeReferenceValue(EntryBlock entryBlock, String value){
|
||||||
|
int resourceId = getMaterials().resolveReference(value);
|
||||||
|
entryBlock.setValueAsReference(resourceId);
|
||||||
|
}
|
||||||
|
void encodeStringValue(EntryBlock entryBlock, String value){
|
||||||
|
|
||||||
|
}
|
||||||
|
private TypeBlock getTypeBlock(String type, String qualifiers){
|
||||||
|
PackageBlock packageBlock = getMaterials().getCurrentPackage();
|
||||||
|
TypeStringPool typeStringPool = packageBlock.getTypeStringPool();
|
||||||
|
byte typeId = typeStringPool.idOf(type);
|
||||||
|
return packageBlock.getSpecTypePairArray()
|
||||||
|
.getOrCreateTypeBlock(typeId, qualifiers);
|
||||||
|
}
|
||||||
|
EncodeMaterials getMaterials() {
|
||||||
|
return materials;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static String getValue(XMLElement element){
|
||||||
|
String value=element.getTextContent();
|
||||||
|
if(value!=null){
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return element.getAttributeValue("value");
|
||||||
|
}
|
||||||
|
static boolean isLiteralEmpty(String value){
|
||||||
|
if(value==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value=value.trim().toLowerCase();
|
||||||
|
return value.equals("@empty");
|
||||||
|
}
|
||||||
|
static boolean isBoolean(String value){
|
||||||
|
if(value==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value=value.trim().toLowerCase();
|
||||||
|
return value.equals("true")||value.equals("false");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.array.ResValueBagItemArray;
|
||||||
|
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
||||||
|
import com.reandroid.lib.arsc.value.ResValueBag;
|
||||||
|
import com.reandroid.lib.arsc.value.ResValueBagItem;
|
||||||
|
import com.reandroid.lib.arsc.value.ValueType;
|
||||||
|
import com.reandroid.xml.XMLElement;
|
||||||
|
|
||||||
|
public class XMLValuesEncoderArray extends XMLValuesEncoderBag{
|
||||||
|
XMLValuesEncoderArray(EncodeMaterials materials) {
|
||||||
|
super(materials);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void encodeChildes(XMLElement parentElement, ResValueBag resValueBag){
|
||||||
|
int count = parentElement.getChildesCount();
|
||||||
|
boolean tag_string="string-array".equals(parentElement.getTagName());
|
||||||
|
ResValueBagItemArray itemArray = resValueBag.getResValueBagItemArray();
|
||||||
|
for(int i=0;i<count;i++){
|
||||||
|
XMLElement child=parentElement.getChildAt(i);
|
||||||
|
ResValueBagItem bagItem = itemArray.get(i);
|
||||||
|
bagItem.setIdHigh((short) 0x0100);
|
||||||
|
bagItem.setIdLow((short) (i+1));
|
||||||
|
|
||||||
|
String valueText=child.getTextContent();
|
||||||
|
|
||||||
|
if(ValueDecoder.isReference(valueText)){
|
||||||
|
bagItem.setType(ValueType.REFERENCE);
|
||||||
|
bagItem.setData(getMaterials().resolveReference(valueText));
|
||||||
|
}else if(EncodeUtil.isEmpty(valueText)) {
|
||||||
|
bagItem.setType(ValueType.NULL);
|
||||||
|
bagItem.setData(0);
|
||||||
|
}else if(!tag_string){
|
||||||
|
ValueDecoder.EncodeResult encodeResult =
|
||||||
|
ValueDecoder.encodeGuessAny(valueText);
|
||||||
|
if(encodeResult!=null){
|
||||||
|
bagItem.setType(encodeResult.valueType);
|
||||||
|
bagItem.setData(encodeResult.value);
|
||||||
|
}else {
|
||||||
|
bagItem.setValueAsString(valueText);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
bagItem.setValueAsString(valueText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.array.ResValueBagItemArray;
|
||||||
|
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
||||||
|
import com.reandroid.lib.arsc.value.ResValueBag;
|
||||||
|
import com.reandroid.lib.arsc.value.ResValueBagItem;
|
||||||
|
import com.reandroid.lib.arsc.value.ValueType;
|
||||||
|
import com.reandroid.lib.arsc.value.attribute.AttributeBag;
|
||||||
|
import com.reandroid.lib.arsc.value.attribute.AttributeItemType;
|
||||||
|
import com.reandroid.lib.arsc.value.attribute.AttributeValueType;
|
||||||
|
import com.reandroid.xml.XMLAttribute;
|
||||||
|
import com.reandroid.xml.XMLElement;
|
||||||
|
|
||||||
|
public class XMLValuesEncoderAttr extends XMLValuesEncoderBag{
|
||||||
|
XMLValuesEncoderAttr(EncodeMaterials materials) {
|
||||||
|
super(materials);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
int getChildesCount(XMLElement element){
|
||||||
|
int count = element.getChildesCount() + element.getAttributeCount();
|
||||||
|
if(element.getAttribute("formats")!=null){
|
||||||
|
count = count-1;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void encodeChildes(XMLElement parentElement, ResValueBag resValueBag){
|
||||||
|
encodeAttributes(parentElement, resValueBag);
|
||||||
|
encodeEnumOrFlag(parentElement, resValueBag);
|
||||||
|
AttributeBag attributeBag=AttributeBag.create(resValueBag);
|
||||||
|
getMaterials().logMessage(attributeBag.toString());
|
||||||
|
getMaterials().logMessage(attributeBag.toString());
|
||||||
|
}
|
||||||
|
private void encodeAttributes(XMLElement parentElement, ResValueBag resValueBag){
|
||||||
|
int count=parentElement.getAttributeCount();
|
||||||
|
ResValueBagItemArray bagItemArray = resValueBag.getResValueBagItemArray();
|
||||||
|
|
||||||
|
int bagIndex=0;
|
||||||
|
|
||||||
|
ResValueBagItem bagItem = bagItemArray.get(bagIndex);
|
||||||
|
|
||||||
|
bagItem.setIdHigh((short) 0x0100);
|
||||||
|
bagItem.setIdLow(AttributeItemType.FORMAT.getValue());
|
||||||
|
bagItem.setType(ValueType.INT_DEC);
|
||||||
|
|
||||||
|
AttributeValueType[] valueTypes = AttributeValueType
|
||||||
|
.valuesOf(parentElement.getAttributeValue("formats"));
|
||||||
|
|
||||||
|
bagItem.setDataLow((short) (0xffff &
|
||||||
|
AttributeValueType.getByte(valueTypes)));
|
||||||
|
|
||||||
|
bagIndex++;
|
||||||
|
|
||||||
|
for(int i=0;i<count;i++){
|
||||||
|
XMLAttribute attribute = parentElement.getAttributeAt(i);
|
||||||
|
String name = attribute.getName();
|
||||||
|
if("name".equals(name) || "formats".equals(name)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
AttributeItemType itemType = AttributeItemType.fromName(name);
|
||||||
|
if(itemType==null){
|
||||||
|
throw new EncodeException("Unknown attribute: '"+name
|
||||||
|
+"', on attribute: "+attribute.toString());
|
||||||
|
}
|
||||||
|
bagItem = bagItemArray.get(bagIndex);
|
||||||
|
bagItem.setIdHigh((short) 0x0100);
|
||||||
|
bagItem.setIdLow(itemType.getValue());
|
||||||
|
bagItem.setType(ValueType.INT_DEC);
|
||||||
|
bagItem.setData(ValueDecoder.parseInteger(attribute.getValue()));
|
||||||
|
bagIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void encodeEnumOrFlag(XMLElement element, ResValueBag resValueBag){
|
||||||
|
int count=element.getChildesCount();
|
||||||
|
if(count==0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int offset = element.getAttributeCount();
|
||||||
|
if(element.getAttribute("formats")!=null){
|
||||||
|
offset = offset-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncodeMaterials materials = getMaterials();
|
||||||
|
ResValueBagItemArray bagItemArray = resValueBag.getResValueBagItemArray();
|
||||||
|
|
||||||
|
for(int i=0;i<count;i++){
|
||||||
|
XMLElement child=element.getChildAt(i);
|
||||||
|
|
||||||
|
int resourceId=materials.resolveLocalResourceId("id",
|
||||||
|
child.getAttributeValue("name"));
|
||||||
|
|
||||||
|
ValueDecoder.EncodeResult encodeResult =
|
||||||
|
ValueDecoder.encodeHexOrInt(child.getTextContent());
|
||||||
|
|
||||||
|
if(encodeResult == null){
|
||||||
|
throw new EncodeException("Unknown value for element '"+child.toText()+"'");
|
||||||
|
}
|
||||||
|
|
||||||
|
ResValueBagItem bagItem = bagItemArray.get(i+offset);
|
||||||
|
bagItem.setId(resourceId);
|
||||||
|
bagItem.setType(encodeResult.valueType);
|
||||||
|
bagItem.setData(encodeResult.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||||
|
import com.reandroid.lib.arsc.value.ResValueBag;
|
||||||
|
import com.reandroid.xml.XMLElement;
|
||||||
|
|
||||||
|
public class XMLValuesEncoderBag extends XMLValuesEncoder{
|
||||||
|
XMLValuesEncoderBag(EncodeMaterials materials) {
|
||||||
|
super(materials);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void encodeValue(EntryBlock entryBlock, XMLElement element){
|
||||||
|
ResValueBag resValueBag=new ResValueBag();
|
||||||
|
entryBlock.setResValue(resValueBag);
|
||||||
|
String parent=element.getAttributeValue("parent");
|
||||||
|
if(!EncodeUtil.isEmpty(parent)){
|
||||||
|
int parentId=getMaterials().resolveReference(parent);
|
||||||
|
resValueBag.setParentId(parentId);
|
||||||
|
}
|
||||||
|
resValueBag.setCount(getChildesCount(element));
|
||||||
|
encodeChildes(element, resValueBag);
|
||||||
|
}
|
||||||
|
void encodeChildes(XMLElement element, ResValueBag resValueBag){
|
||||||
|
|
||||||
|
}
|
||||||
|
int getChildesCount(XMLElement element){
|
||||||
|
return element.getChildesCount();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
||||||
|
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||||
|
|
||||||
|
public class XMLValuesEncoderColor extends XMLValuesEncoder{
|
||||||
|
XMLValuesEncoderColor(EncodeMaterials materials) {
|
||||||
|
super(materials);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void encodeStringValue(EntryBlock entryBlock, String value){
|
||||||
|
ValueDecoder.EncodeResult encodeResult=ValueDecoder.encodeColor(value);
|
||||||
|
if(encodeResult!=null){
|
||||||
|
entryBlock.setValueAsRaw(encodeResult.valueType, encodeResult.value);
|
||||||
|
}else {
|
||||||
|
throw new EncodeException("Unknown color value: "+value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||||
|
|
||||||
|
public class XMLValuesEncoderCommon extends XMLValuesEncoder{
|
||||||
|
XMLValuesEncoderCommon(EncodeMaterials materials) {
|
||||||
|
super(materials);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void encodeStringValue(EntryBlock entryBlock, String value){
|
||||||
|
entryBlock.setValueAsString(value);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
||||||
|
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||||
|
|
||||||
|
public class XMLValuesEncoderDimen extends XMLValuesEncoder{
|
||||||
|
XMLValuesEncoderDimen(EncodeMaterials materials) {
|
||||||
|
super(materials);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void encodeStringValue(EntryBlock entryBlock, String value){
|
||||||
|
ValueDecoder.EncodeResult encodeResult =
|
||||||
|
ValueDecoder.encodeDimensionOrFloat(value);
|
||||||
|
if(encodeResult!=null){
|
||||||
|
entryBlock.setValueAsRaw(encodeResult.valueType, encodeResult.value);
|
||||||
|
}else {
|
||||||
|
throw new EncodeException("Unknown dimen value: "+value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||||
|
|
||||||
|
public class XMLValuesEncoderId extends XMLValuesEncoder{
|
||||||
|
public XMLValuesEncoderId(EncodeMaterials materials) {
|
||||||
|
super(materials);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void encodeStringValue(EntryBlock entryBlock, String value){
|
||||||
|
throw new EncodeException("Unexpected value for id: "+value);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void encodeNullValue(EntryBlock entryBlock){
|
||||||
|
entryBlock.setValueAsString("");
|
||||||
|
setVisibility(entryBlock);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void encodeBooleanValue(EntryBlock entryBlock, String value){
|
||||||
|
super.encodeBooleanValue(entryBlock, value);
|
||||||
|
setVisibility(entryBlock);
|
||||||
|
}
|
||||||
|
private void setVisibility(EntryBlock entryBlock){
|
||||||
|
entryBlock.setEntryTypePublic(true);
|
||||||
|
entryBlock.setEntryTypeShared(true);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
||||||
|
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||||
|
import com.reandroid.lib.arsc.value.ValueType;
|
||||||
|
|
||||||
|
public class XMLValuesEncoderInteger extends XMLValuesEncoder{
|
||||||
|
XMLValuesEncoderInteger(EncodeMaterials materials) {
|
||||||
|
super(materials);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void encodeStringValue(EntryBlock entryBlock, String value){
|
||||||
|
value=value.trim();
|
||||||
|
if(ValueDecoder.isInteger(value)){
|
||||||
|
entryBlock.setValueAsRaw(ValueType.INT_DEC, ValueDecoder.parseInteger(value));
|
||||||
|
}else if(ValueDecoder.isHex(value)){
|
||||||
|
entryBlock.setValueAsRaw(ValueType.INT_HEX, ValueDecoder.parseHex(value));
|
||||||
|
}else {
|
||||||
|
throw new EncodeException("Unknown value for type <integer>: '"+value+"'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.array.ResValueBagItemArray;
|
||||||
|
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
||||||
|
import com.reandroid.lib.arsc.value.ResValueBag;
|
||||||
|
import com.reandroid.lib.arsc.value.ResValueBagItem;
|
||||||
|
import com.reandroid.lib.arsc.value.ValueType;
|
||||||
|
import com.reandroid.lib.arsc.value.plurals.PluralsQuantity;
|
||||||
|
import com.reandroid.xml.XMLElement;
|
||||||
|
|
||||||
|
public class XMLValuesEncoderPlurals extends XMLValuesEncoderBag{
|
||||||
|
XMLValuesEncoderPlurals(EncodeMaterials materials) {
|
||||||
|
super(materials);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void encodeChildes(XMLElement parentElement, ResValueBag resValueBag){
|
||||||
|
int count = parentElement.getChildesCount();
|
||||||
|
ResValueBagItemArray itemArray = resValueBag.getResValueBagItemArray();
|
||||||
|
for(int i=0;i<count;i++){
|
||||||
|
XMLElement child=parentElement.getChildAt(i);
|
||||||
|
ResValueBagItem bagItem = itemArray.get(i);
|
||||||
|
PluralsQuantity quantity = PluralsQuantity
|
||||||
|
.value(child.getAttributeValue("quantity"));
|
||||||
|
if(quantity==null){
|
||||||
|
throw new EncodeException("Unknown plurals quantity: "
|
||||||
|
+child.toText());
|
||||||
|
}
|
||||||
|
bagItem.setIdHigh((short) 0x0100);
|
||||||
|
bagItem.setIdLow(quantity.getId());
|
||||||
|
|
||||||
|
String valueText=child.getTextContent();
|
||||||
|
|
||||||
|
if(ValueDecoder.isReference(valueText)){
|
||||||
|
bagItem.setType(ValueType.REFERENCE);
|
||||||
|
bagItem.setData(getMaterials().resolveReference(valueText));
|
||||||
|
}else if(EncodeUtil.isEmpty(valueText)) {
|
||||||
|
bagItem.setType(ValueType.NULL);
|
||||||
|
bagItem.setData(0);
|
||||||
|
}else{
|
||||||
|
bagItem.setValueAsString(valueText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
||||||
|
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||||
|
import com.reandroid.xml.XMLDocument;
|
||||||
|
import com.reandroid.xml.XMLElement;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class XMLValuesEncoderString extends XMLValuesEncoder{
|
||||||
|
XMLValuesEncoderString(EncodeMaterials materials) {
|
||||||
|
super(materials);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void encode(String type, String qualifiers, XMLDocument xmlDocument){
|
||||||
|
preloadStringPool(xmlDocument);
|
||||||
|
super.encode(type, qualifiers, xmlDocument);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void encodeStringValue(EntryBlock entryBlock, String value){
|
||||||
|
entryBlock.setValueAsString(value);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void encodeNullValue(EntryBlock entryBlock){
|
||||||
|
entryBlock.setValueAsString("");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void encodeBooleanValue(EntryBlock entryBlock, String value){
|
||||||
|
entryBlock.setValueAsString(value);
|
||||||
|
}
|
||||||
|
private void preloadStringPool(XMLDocument xmlDocument){
|
||||||
|
XMLElement documentElement = xmlDocument.getDocumentElement();
|
||||||
|
List<String> stringList = new ArrayList<>();
|
||||||
|
int count = documentElement.getChildesCount();
|
||||||
|
for(int i=0;i<count;i++){
|
||||||
|
String value=getValue(documentElement.getChildAt(i));
|
||||||
|
if(value==null || ValueDecoder.isReference(value)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
stringList.add(value);
|
||||||
|
}
|
||||||
|
getMaterials().addTableStringPool(stringList);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.array.ResValueBagItemArray;
|
||||||
|
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
||||||
|
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||||
|
import com.reandroid.lib.arsc.value.ResValueBag;
|
||||||
|
import com.reandroid.lib.arsc.value.ResValueBagItem;
|
||||||
|
import com.reandroid.lib.arsc.value.ValueType;
|
||||||
|
import com.reandroid.lib.arsc.value.attribute.AttributeBag;
|
||||||
|
import com.reandroid.xml.XMLElement;
|
||||||
|
|
||||||
|
|
||||||
|
public class XMLValuesEncoderStyle extends XMLValuesEncoderBag{
|
||||||
|
XMLValuesEncoderStyle(EncodeMaterials materials) {
|
||||||
|
super(materials);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void encodeChildes(XMLElement parentElement, ResValueBag resValueBag){
|
||||||
|
int count = parentElement.getChildesCount();
|
||||||
|
ResValueBagItemArray itemArray = resValueBag.getResValueBagItemArray();
|
||||||
|
EncodeMaterials materials=getMaterials();
|
||||||
|
for(int i=0;i<count;i++){
|
||||||
|
XMLElement child=parentElement.getChildAt(i);
|
||||||
|
ResValueBagItem bagItem = itemArray.get(i);
|
||||||
|
EntryBlock entryBlock=materials
|
||||||
|
.getAttributeBlock(child.getAttributeValue("name"));
|
||||||
|
if(entryBlock==null){
|
||||||
|
throw new EncodeException("Unknown attribute name: '"+child.toText()+"'");
|
||||||
|
}
|
||||||
|
bagItem.setId(entryBlock.getResourceId());
|
||||||
|
AttributeBag attributeBag=AttributeBag
|
||||||
|
.create((ResValueBag) entryBlock.getResValue());
|
||||||
|
|
||||||
|
String valueText=child.getTextContent();
|
||||||
|
ValueDecoder.EncodeResult encodeResult =
|
||||||
|
attributeBag.encodeName(valueText);
|
||||||
|
if(encodeResult!=null){
|
||||||
|
bagItem.setType(encodeResult.valueType);
|
||||||
|
bagItem.setData(encodeResult.value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(ValueDecoder.isReference(valueText)){
|
||||||
|
bagItem.setType(ValueType.REFERENCE);
|
||||||
|
bagItem.setData(getMaterials().resolveReference(valueText));
|
||||||
|
}else if(EncodeUtil.isEmpty(valueText)) {
|
||||||
|
bagItem.setType(ValueType.NULL);
|
||||||
|
bagItem.setData(0);
|
||||||
|
}else{
|
||||||
|
encodeResult=ValueDecoder.encodeGuessAny(valueText);
|
||||||
|
if(encodeResult!=null){
|
||||||
|
bagItem.setType(encodeResult.valueType);
|
||||||
|
bagItem.setData(encodeResult.value);
|
||||||
|
}else {
|
||||||
|
bagItem.setValueAsString(valueText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user