com.reandroid.arsc.coder.ValueCoder Maven / Gradle / Ivy
/*
* 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.arsc.coder;
import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.model.ResourceEntry;
import com.reandroid.arsc.value.Value;
import com.reandroid.arsc.value.attribute.AttributeBag;
import com.reandroid.utils.HexUtil;
import com.reandroid.arsc.value.AttributeDataFormat;
import com.reandroid.arsc.value.ValueType;
import com.reandroid.utils.StringsUtil;
import java.util.HashMap;
import java.util.Map;
public class ValueCoder {
public static EncodeResult encodeAttributeValue(boolean validate, Value output, ResourceEntry name, String value){
PackageBlock context = output.getPackageBlock();
EncodeResult encodeResult = encodeReference(context, value);
if(encodeResult != null){
if(encodeResult.isError()){
return encodeResult;
}
output.setValue(encodeResult);
return encodeResult;
}
if(name != null){
name = name.resolveReference();
AttributeBag attributeBag = AttributeBag.create(name.get());
if(attributeBag != null){
encodeResult = attributeBag.encode(value);
if(encodeResult != null){
if(encodeResult.valueType == ValueType.STRING){
output.setValueAsString(XmlSanitizer.unEscapeSpecialCharacter(value));
return new EncodeResult(ValueType.STRING, output.getData());
}
if(encodeResult.isError()){
if(validate){
return encodeResult;
}
encodeResult = null;
}
}
}
}
if(encodeResult == null){
encodeResult = ValueCoder.encode(value);
}
if(encodeResult != null){
output.setValue(encodeResult);
return encodeResult;
}
output.setValueAsString(XmlSanitizer.unEscapeSpecialCharacter(value));
return new EncodeResult(ValueType.STRING, output.getData());
}
public static String decodeReference(PackageBlock packageBlock, ValueType referenceType, int resourceId){
if(resourceId == 0){
if(referenceType == ValueType.REFERENCE){
return CoderNullReference.INS.decode(resourceId);
}
return CoderNullAttribute.INS.decode(resourceId);
}
TableBlock tableBlock = packageBlock.getTableBlock();
ResourceEntry resourceEntry = tableBlock.getResource(packageBlock, resourceId);
if(resourceEntry != null){
return resourceEntry.buildReference(packageBlock, referenceType);
}
return decodeUnknownResourceId(referenceType == ValueType.REFERENCE, resourceId);
}
public static EncodeResult encodeReference(PackageBlock packageBlock, String value){
if(value == null || value.length() < 3){
return null;
}
EncodeResult encodeResult = encodeUnknownResourceId(value);
if(encodeResult != null){
return encodeResult;
}
ReferenceString referenceString = ReferenceString.parseReference(value);
if(referenceString != null){
encodeResult = referenceString.encode(packageBlock, EncodeResult.RESOURCE_NOT_FOUND);
if(encodeResult.isError()){
encodeResult = new EncodeResult(
buildResourceNotFoundMessage(packageBlock, value));
}
return encodeResult;
}
return null;
}
public static EncodeResult encodeReference(TableBlock tableBlock, String value){
if(value == null || value.length() < 3){
return null;
}
EncodeResult encodeResult = encodeUnknownResourceId(value);
if(encodeResult != null){
return encodeResult;
}
ReferenceString referenceString = ReferenceString.parseReference(value);
if(referenceString != null){
encodeResult = referenceString.encode(tableBlock, EncodeResult.RESOURCE_NOT_FOUND);
if(encodeResult.isError()){
encodeResult = new EncodeResult(
buildResourceNotFoundMessage(tableBlock, value));
}
return encodeResult;
}
return null;
}
private static String buildResourceNotFoundMessage(PackageBlock packageBlock, String value){
TableBlock tableBlock = packageBlock.getTableBlock();
if(tableBlock == null){
return "Resource not found for: '" + value +
"', package " + packageBlock + ", parent table = null";
}
return buildResourceNotFoundMessage(tableBlock, value);
}
private static String buildResourceNotFoundMessage(TableBlock tableBlock, String value){
return "Resource not found for: '" + value +
"', frameworks " +
StringsUtil.toString(tableBlock.getFrameWorks());
}
public static String decodeUnknownNameId(int referenceId){
return CoderUnknownNameId.INS.decode(referenceId);
}
public static String decodeUnknownResourceId(boolean is_reference, int referenceId){
if(is_reference){
return CoderUnknownReferenceId.INS.decode(referenceId);
}
return CoderUnknownAttributeId.INS.decode(referenceId);
}
public static EncodeResult encodeUnknownNameId(String text){
return CoderUnknownNameId.INS.encode(text);
}
public static EncodeResult encodeUnknownResourceId(String text){
if(text == null || text.length() == 0){
return null;
}
EncodeResult encodeResult = encodeNull(text);
if(encodeResult != null){
return encodeResult;
}
return encodeUnknown(text);
}
public static EncodeResult encodeHexOrInteger(String text){
if(text == null){
return null;
}
EncodeResult encodeResult = CoderHex.INS.encode(text);
if(encodeResult == null){
encodeResult = CoderInteger.INS.encode(text);
}
return encodeResult;
}
public static EncodeResult encode(String text, AttributeDataFormat... expectedDataFormats){
if(isEmpty(expectedDataFormats)){
return encodeAny(text);
}
if(text == null || text.length() == 0){
return null;
}
EncodeResult encodeResult = encodeUnknown(text);
if(encodeResult != null){
return encodeResult;
}
return encodeWithin(text, expectedDataFormats);
}
public static EncodeResult encode(String text, ValueType... expectedTypes){
if(isEmpty(expectedTypes)){
return encodeAny(text);
}
if(text == null || text.length() == 0){
return null;
}
EncodeResult encodeResult = encodeUnknown(text);
if(encodeResult != null){
return encodeResult;
}
return encodeWithin(text, expectedTypes);
}
public static EncodeResult encode(String text){
return encodeAny(text);
}
private static boolean isEmpty(Object[] objects){
if(objects == null || objects.length == 0){
return true;
}
for(Object obj : objects){
if(obj != null){
return false;
}
}
return true;
}
private static EncodeResult encodeWithin(String text, AttributeDataFormat... expectedDataFormats){
if(text == null || text.length() == 0){
return null;
}
for(AttributeDataFormat dataFormat : expectedDataFormats){
EncodeResult encodeResult = encodeWithin(text, dataFormat.valueTypes());
if(encodeResult != null){
return encodeResult;
}
}
return null;
}
private static EncodeResult encodeWithin(String text, ValueType... expectedTypes){
if(text == null || text.length() == 0){
return null;
}
EncodeResult encodeResult;
char first = text.charAt(0);
for(ValueType valueType : expectedTypes){
Coder coder = getCoder(valueType);
if(coder == null){
continue;
}
if(!coder.canStartWith(first)){
continue;
}
encodeResult = coder.encode(text);
if(encodeResult != null){
return encodeResult;
}
}
return null;
}
private static EncodeResult encodeAny(String text){
if(text == null || text.length() == 0){
return null;
}
EncodeResult encodeResult = encodeUnknown(text);
if(encodeResult != null){
return encodeResult;
}
char first = text.charAt(0);
for(Coder coder : CODERS){
if(!coder.canStartWith(first)){
continue;
}
encodeResult = coder.encode(text);
if(encodeResult != null){
return encodeResult;
}
}
return null;
}
private static EncodeResult encodeUnknown(String text){
char first = text.charAt(0);
Coder unknown = CoderUnknownReferenceId.INS;
EncodeResult encodeResult;
if(unknown.canStartWith(first)){
encodeResult = unknown.encode(text);
if(encodeResult != null){
return encodeResult;
}
}
unknown = CoderUnknownAttributeId.INS;
if(unknown.canStartWith(first)){
encodeResult = unknown.encode(text);
if(encodeResult != null){
return encodeResult;
}
}
unknown = CoderUnknownStringRef.INS;
if(unknown.canStartWith(first)){
return unknown.encode(text);
}
return null;
}
public static String decode(ValueType valueType, int data){
String decoded = decodeNull(valueType, data);
if(decoded != null){
return decoded;
}
Coder coder = CODER_MAP.get(valueType);
if(coder == null){
return null;
}
return coder.decode(data);
}
private static EncodeResult encodeNull(String text){
if(text == null){
return null;
}
int length = text.length();
if(length != 5 && length != 6){
return null;
}
char first = text.charAt(0);
for(Coder coder : CODERS_NULL){
if(!coder.canStartWith(first)){
continue;
}
EncodeResult encodeResult = coder.encode(text);
if(encodeResult != null){
return encodeResult;
}
}
return null;
}
private static String decodeNull(ValueType valueType, int data){
if(data != 0 && data != 1){
return null;
}
if(valueType == ValueType.NULL){
return CoderNull.INS.decode(data);
}
if(data != 0){
return null;
}
if(valueType == ValueType.ATTRIBUTE){
return CoderNullAttribute.INS.decode(data);
}
if(valueType == ValueType.REFERENCE){
return CoderNullReference.INS.decode(data);
}
return null;
}
public static Coder getCoder(ValueType valueType){
return CODER_MAP.get(valueType);
}
public static final Coder[] CODERS;
private static final Map CODER_MAP;
private static final Coder[] CODERS_NULL;
static {
CODERS = new Coder[]{
CoderNull.INS,
CoderBoolean.INS,
CoderDimension.INS,
CoderFraction.INS,
CoderColorARGB4.INS,
CoderColorRGB4.INS,
CoderColorRGB8.INS,
CoderColorARGB8.INS,
CoderFloat.INS,
CoderHex.INS,
CoderInteger.INS
};
Map map = new HashMap<>();
map.put(CoderNull.INS.getValueType(), CoderNull.INS);
map.put(CoderBoolean.INS.getValueType(), CoderBoolean.INS);
map.put(CoderDimension.INS.getValueType(), CoderDimension.INS);
map.put(CoderFraction.INS.getValueType(), CoderFraction.INS);
map.put(CoderColorRGB4.INS.getValueType(), CoderColorRGB4.INS);
map.put(CoderColorARGB4.INS.getValueType(), CoderColorARGB4.INS);
map.put(CoderColorRGB8.INS.getValueType(), CoderColorRGB8.INS);
map.put(CoderColorARGB8.INS.getValueType(), CoderColorARGB8.INS);
map.put(CoderFloat.INS.getValueType(), CoderFloat.INS);
map.put(CoderHex.INS.getValueType(), CoderHex.INS);
map.put(CoderInteger.INS.getValueType(), CoderInteger.INS);
CODER_MAP = map;
CODERS_NULL = new Coder[]{
CoderNullReference.INS,
CoderNullAttribute.INS,
CoderNull.INS,
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy