mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-04-29 22:04:25 +02:00
fix: decode null / empty values
This commit is contained in:
parent
d5c3f7563e
commit
fea0583f61
@ -1,18 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2022 github.com/REAndroid
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.reandroid.arsc.decoder;
|
package com.reandroid.arsc.decoder;
|
||||||
|
|
||||||
import com.reandroid.arsc.chunk.PackageBlock;
|
import com.reandroid.arsc.chunk.PackageBlock;
|
||||||
@ -29,244 +29,244 @@ import java.util.Iterator;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class ValueDecoder {
|
public class ValueDecoder {
|
||||||
|
|
||||||
public static String escapeSpecialCharacter(String text){
|
public static String escapeSpecialCharacter(String text){
|
||||||
if(text==null || text.length()==0){
|
if(text==null || text.length()==0){
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
if(isSpecialCharacter(text.charAt(0))){
|
if(isSpecialCharacter(text.charAt(0))){
|
||||||
return '\\' +text;
|
return '\\' +text;
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
public static String unEscapeSpecialCharacter(String text){
|
public static String unEscapeSpecialCharacter(String text){
|
||||||
if(text==null || text.length()<2){
|
if(text==null || text.length()<2){
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
if(text.charAt(0)!='\\' || !isSpecialCharacter(text.charAt(1))){
|
if(text.charAt(0)!='\\' || !isSpecialCharacter(text.charAt(1))){
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
return text.substring(1);
|
return text.substring(1);
|
||||||
}
|
}
|
||||||
private static boolean isSpecialCharacter(char ch){
|
private static boolean isSpecialCharacter(char ch){
|
||||||
switch (ch){
|
switch (ch){
|
||||||
case '@':
|
case '@':
|
||||||
case '?':
|
case '?':
|
||||||
case '#':
|
case '#':
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static EncodeResult encodeGuessAny(String txt){
|
public static EncodeResult encodeGuessAny(String txt){
|
||||||
if(txt==null){
|
if(txt==null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if("@empty".equals(txt)){
|
if("@empty".equals(txt)){
|
||||||
return new EncodeResult(ValueType.NULL, 0);
|
return new EncodeResult(ValueType.NULL, 1);
|
||||||
}
|
}
|
||||||
if("@null".equals(txt)){
|
if("@null".equals(txt)){
|
||||||
return new EncodeResult(ValueType.REFERENCE, 0);
|
return new EncodeResult(ValueType.REFERENCE, 0);
|
||||||
}
|
}
|
||||||
if("?null".equals(txt)){
|
if("?null".equals(txt)){
|
||||||
return new EncodeResult(ValueType.ATTRIBUTE, 0);
|
return new EncodeResult(ValueType.ATTRIBUTE, 0);
|
||||||
}
|
}
|
||||||
EncodeResult result=encodeColor(txt);
|
EncodeResult result=encodeColor(txt);
|
||||||
if(result!=null){
|
if(result!=null){
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
result=encodeDimensionOrFloat(txt);
|
result=encodeDimensionOrFloat(txt);
|
||||||
if(result!=null){
|
if(result!=null){
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
result=encodeHexOrInt(txt);
|
result=encodeHexOrInt(txt);
|
||||||
if(result!=null){
|
if(result!=null){
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return encodeBoolean(txt);
|
return encodeBoolean(txt);
|
||||||
}
|
}
|
||||||
public static EncodeResult encodeBoolean(String txt){
|
public static EncodeResult encodeBoolean(String txt){
|
||||||
if(txt==null){
|
if(txt==null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
txt=txt.trim().toLowerCase();
|
txt=txt.trim().toLowerCase();
|
||||||
if(txt.equals("true")){
|
if(txt.equals("true")){
|
||||||
return new EncodeResult(ValueType.INT_BOOLEAN, 0xffffffff);
|
return new EncodeResult(ValueType.INT_BOOLEAN, 0xffffffff);
|
||||||
}
|
}
|
||||||
if(txt.equals("false")){
|
if(txt.equals("false")){
|
||||||
return new EncodeResult(ValueType.INT_BOOLEAN, 0);
|
return new EncodeResult(ValueType.INT_BOOLEAN, 0);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public static EncodeResult encodeHexReference(String txt){
|
public static EncodeResult encodeHexReference(String txt){
|
||||||
if(txt==null){
|
if(txt==null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
txt=txt.trim().toLowerCase();
|
txt=txt.trim().toLowerCase();
|
||||||
Matcher matcher = PATTERN_HEX_REFERENCE.matcher(txt);
|
Matcher matcher = PATTERN_HEX_REFERENCE.matcher(txt);
|
||||||
if(!matcher.find()){
|
if(!matcher.find()){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String prefix = matcher.group(1);
|
String prefix = matcher.group(1);
|
||||||
int value = parseHex(matcher.group(2));
|
int value = parseHex(matcher.group(2));
|
||||||
ValueType valueType;
|
ValueType valueType;
|
||||||
if("?".equals(prefix)){
|
if("?".equals(prefix)){
|
||||||
valueType = ValueType.ATTRIBUTE;
|
valueType = ValueType.ATTRIBUTE;
|
||||||
}else {
|
}else {
|
||||||
valueType = ValueType.REFERENCE;
|
valueType = ValueType.REFERENCE;
|
||||||
}
|
}
|
||||||
return new EncodeResult(valueType, value);
|
return new EncodeResult(valueType, value);
|
||||||
}
|
}
|
||||||
public static boolean isInteger(String txt){
|
public static boolean isInteger(String txt){
|
||||||
if(txt==null){
|
if(txt==null){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return PATTERN_INTEGER.matcher(txt).matches();
|
return PATTERN_INTEGER.matcher(txt).matches();
|
||||||
}
|
}
|
||||||
public static boolean isHex(String txt){
|
public static boolean isHex(String txt){
|
||||||
if(txt==null){
|
if(txt==null){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return PATTERN_HEX.matcher(txt).matches();
|
return PATTERN_HEX.matcher(txt).matches();
|
||||||
}
|
}
|
||||||
public static boolean isReference(String txt){
|
public static boolean isReference(String txt){
|
||||||
if(txt==null){
|
if(txt==null){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(isNullReference(txt)){
|
if(isNullReference(txt)){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(isHexReference(txt)){
|
if(isHexReference(txt)){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return PATTERN_REFERENCE.matcher(txt).matches();
|
return PATTERN_REFERENCE.matcher(txt).matches();
|
||||||
}
|
}
|
||||||
private static boolean isHexReference(String txt){
|
private static boolean isHexReference(String txt){
|
||||||
return PATTERN_HEX_REFERENCE.matcher(txt).matches();
|
return PATTERN_HEX_REFERENCE.matcher(txt).matches();
|
||||||
}
|
}
|
||||||
private static boolean isNullReference(String txt){
|
private static boolean isNullReference(String txt){
|
||||||
if("@null".equals(txt)||"?null".equals(txt)){
|
if("@null".equals(txt)||"?null".equals(txt)){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if("@empty".equals(txt)){
|
if("@empty".equals(txt)){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
public static EncodeResult encodeColor(String value){
|
public static EncodeResult encodeColor(String value){
|
||||||
if(value==null){
|
if(value==null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Matcher matcher = PATTERN_COLOR.matcher(value);
|
Matcher matcher = PATTERN_COLOR.matcher(value);
|
||||||
if(!matcher.find()){
|
if(!matcher.find()){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
value=matcher.group(1);
|
value=matcher.group(1);
|
||||||
ValueType valueType;
|
ValueType valueType;
|
||||||
if(value.length()==6){
|
if(value.length()==6){
|
||||||
valueType=ValueType.INT_COLOR_RGB8;
|
valueType=ValueType.INT_COLOR_RGB8;
|
||||||
}else {
|
}else {
|
||||||
valueType=ValueType.INT_COLOR_ARGB8;
|
valueType=ValueType.INT_COLOR_ARGB8;
|
||||||
}
|
}
|
||||||
return new EncodeResult(valueType, parseHex(value));
|
return new EncodeResult(valueType, parseHex(value));
|
||||||
}
|
}
|
||||||
public static EncodeResult encodeHexOrInt(String numString){
|
public static EncodeResult encodeHexOrInt(String numString){
|
||||||
if(numString==null){
|
if(numString==null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if(isHex(numString)){
|
if(isHex(numString)){
|
||||||
return new EncodeResult(ValueType.INT_HEX, parseHex(numString));
|
return new EncodeResult(ValueType.INT_HEX, parseHex(numString));
|
||||||
}
|
}
|
||||||
if(isInteger(numString)){
|
if(isInteger(numString)){
|
||||||
return new EncodeResult(ValueType.INT_DEC, parseInteger(numString));
|
return new EncodeResult(ValueType.INT_DEC, parseInteger(numString));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public static int parseHex(String hexString){
|
public static int parseHex(String hexString){
|
||||||
boolean negative=false;
|
boolean negative=false;
|
||||||
hexString=hexString.trim().toLowerCase();
|
hexString=hexString.trim().toLowerCase();
|
||||||
if(hexString.startsWith("-")){
|
if(hexString.startsWith("-")){
|
||||||
negative=true;
|
negative=true;
|
||||||
hexString=hexString.substring(1);
|
hexString=hexString.substring(1);
|
||||||
}
|
}
|
||||||
if(!hexString.startsWith("0x")){
|
if(!hexString.startsWith("0x")){
|
||||||
hexString="0x"+hexString;
|
hexString="0x"+hexString;
|
||||||
}
|
}
|
||||||
long l=Long.decode(hexString);
|
long l=Long.decode(hexString);
|
||||||
if(negative){
|
if(negative){
|
||||||
l=-l;
|
l=-l;
|
||||||
}
|
}
|
||||||
return (int) l;
|
return (int) l;
|
||||||
}
|
}
|
||||||
public static int parseInteger(String intString){
|
public static int parseInteger(String intString){
|
||||||
intString=intString.trim();
|
intString=intString.trim();
|
||||||
boolean negative=false;
|
boolean negative=false;
|
||||||
if(intString.startsWith("-")){
|
if(intString.startsWith("-")){
|
||||||
negative=true;
|
negative=true;
|
||||||
intString=intString.substring(1);
|
intString=intString.substring(1);
|
||||||
}
|
}
|
||||||
long l=Long.parseLong(intString);
|
long l=Long.parseLong(intString);
|
||||||
if(negative){
|
if(negative){
|
||||||
l=-l;
|
l=-l;
|
||||||
}
|
}
|
||||||
return (int) l;
|
return (int) l;
|
||||||
}
|
}
|
||||||
public static EncodeResult encodeDimensionOrFloat(String value){
|
public static EncodeResult encodeDimensionOrFloat(String value){
|
||||||
if(value==null){
|
if(value==null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
EncodeResult result = encodeFloat(value);
|
EncodeResult result = encodeFloat(value);
|
||||||
if(result == null){
|
if(result == null){
|
||||||
result = encodeDimensionOrFraction(value);
|
result = encodeDimensionOrFraction(value);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public static EncodeResult encodeFloat(String txt){
|
public static EncodeResult encodeFloat(String txt){
|
||||||
Float value = parseFloat(txt);
|
Float value = parseFloat(txt);
|
||||||
if(value==null){
|
if(value==null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new EncodeResult(ValueType.FLOAT,
|
return new EncodeResult(ValueType.FLOAT,
|
||||||
Float.floatToIntBits(value));
|
Float.floatToIntBits(value));
|
||||||
}
|
}
|
||||||
public static Float parseFloat(String txt){
|
public static Float parseFloat(String txt){
|
||||||
if(txt==null || txt.indexOf('.')<0){
|
if(txt==null || txt.indexOf('.')<0){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try{
|
try{
|
||||||
return Float.parseFloat(txt);
|
return Float.parseFloat(txt);
|
||||||
}catch (NumberFormatException ignored){
|
}catch (NumberFormatException ignored){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static EncodeResult encodeDimensionOrFraction(String value){
|
public static EncodeResult encodeDimensionOrFraction(String value){
|
||||||
if(value==null){
|
if(value==null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Matcher matcher = PATTERN_DIMEN.matcher(value);
|
Matcher matcher = PATTERN_DIMEN.matcher(value);
|
||||||
if(!matcher.find()){
|
if(!matcher.find()){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String number = matcher.group(1);
|
String number = matcher.group(1);
|
||||||
String unit = matcher.group(4);
|
String unit = matcher.group(4);
|
||||||
float fraction = Float.parseFloat(number);
|
float fraction = Float.parseFloat(number);
|
||||||
return encodeDimensionOrFraction(fraction, unit);
|
return encodeDimensionOrFraction(fraction, unit);
|
||||||
}
|
}
|
||||||
private static EncodeResult encodeDimensionOrFraction(float value, String unitSymbol){
|
private static EncodeResult encodeDimensionOrFraction(float value, String unitSymbol){
|
||||||
ComplexUtil.Unit unit = ComplexUtil.Unit.fromSymbol(unitSymbol);
|
ComplexUtil.Unit unit = ComplexUtil.Unit.fromSymbol(unitSymbol);
|
||||||
ValueType valueType;
|
ValueType valueType;
|
||||||
if(unit == ComplexUtil.Unit.FRACTION || unit == ComplexUtil.Unit.FRACTION_PARENT){
|
if(unit == ComplexUtil.Unit.FRACTION || unit == ComplexUtil.Unit.FRACTION_PARENT){
|
||||||
valueType = ValueType.FRACTION;
|
valueType = ValueType.FRACTION;
|
||||||
value = value / 100.0f;
|
value = value / 100.0f;
|
||||||
}else {
|
}else {
|
||||||
valueType = ValueType.DIMENSION;
|
valueType = ValueType.DIMENSION;
|
||||||
}
|
}
|
||||||
int result = ComplexUtil.encodeComplex(value, unit);
|
int result = ComplexUtil.encodeComplex(value, unit);
|
||||||
return new EncodeResult(valueType, result);
|
return new EncodeResult(valueType, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String decodeAttributeName(EntryStore store, PackageBlock currentPackage, int resourceId){
|
public static String decodeAttributeName(EntryStore store, PackageBlock currentPackage, int resourceId){
|
||||||
EntryGroup entryGroup=searchEntryGroup(store, currentPackage, resourceId);
|
EntryGroup entryGroup=searchEntryGroup(store, currentPackage, resourceId);
|
||||||
if(entryGroup==null){
|
if(entryGroup==null){
|
||||||
return String.format("@0x%08x", resourceId);
|
return String.format("@0x%08x", resourceId);
|
||||||
@ -354,8 +354,8 @@ import java.util.regex.Pattern;
|
|||||||
return decodeIntEntry(store, parentEntry, valueType, data);
|
return decodeIntEntry(store, parentEntry, valueType, data);
|
||||||
}
|
}
|
||||||
public static String decodeIntEntry(EntryStore store, Entry parentEntry, ValueType valueType, int data){
|
public static String decodeIntEntry(EntryStore store, Entry parentEntry, ValueType valueType, int data){
|
||||||
if(valueType==ValueType.NULL){
|
if(valueType == ValueType.NULL){
|
||||||
return "@empty";
|
return decodeNull(data);
|
||||||
}
|
}
|
||||||
if(valueType==ValueType.STRING){
|
if(valueType==ValueType.STRING){
|
||||||
return decodeIntEntryString(parentEntry, data);
|
return decodeIntEntryString(parentEntry, data);
|
||||||
@ -474,6 +474,8 @@ import java.util.regex.Pattern;
|
|||||||
return decodeHex(data);
|
return decodeHex(data);
|
||||||
case INT_DEC:
|
case INT_DEC:
|
||||||
return decodeInt(data);
|
return decodeInt(data);
|
||||||
|
case NULL:
|
||||||
|
return decodeNull(data);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -713,6 +715,12 @@ import java.util.regex.Pattern;
|
|||||||
private static String decodeInt(int rawVal){
|
private static String decodeInt(int rawVal){
|
||||||
return String.valueOf(rawVal);
|
return String.valueOf(rawVal);
|
||||||
}
|
}
|
||||||
|
private static String decodeNull(int data){
|
||||||
|
if(data == 1){
|
||||||
|
return "@empty";
|
||||||
|
}
|
||||||
|
return "@null";
|
||||||
|
}
|
||||||
|
|
||||||
private static String decodeBoolean(int data){
|
private static String decodeBoolean(int data){
|
||||||
if(data == 0xFFFFFFFF){
|
if(data == 0xFFFFFFFF){
|
||||||
@ -818,10 +826,10 @@ import java.util.regex.Pattern;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Pattern PATTERN_COLOR = Pattern.compile("^#([0-9a-fA-F]{6,8})$");
|
public static final Pattern PATTERN_COLOR = Pattern.compile("^#([0-9a-fA-F]{6,8})$");
|
||||||
public static final Pattern PATTERN_DIMEN = Pattern.compile("^([+\\-]?[0-9]+(\\.[0-9]+(E\\+?-?[0-9]+)?)?)(px|di?p|sp|pt|in|mm|%p?)$");
|
public static final Pattern PATTERN_DIMEN = Pattern.compile("^([+\\-]?[0-9]+(\\.[0-9]+(E\\+?-?[0-9]+)?)?)(px|di?p|sp|pt|in|mm|%p?)$");
|
||||||
private static final Pattern PATTERN_INTEGER = Pattern.compile("^(-?)([0-9]+)$");
|
private static final Pattern PATTERN_INTEGER = Pattern.compile("^(-?)([0-9]+)$");
|
||||||
private static final Pattern PATTERN_HEX = Pattern.compile("^0x[0-9a-fA-F]+$");
|
private static final Pattern PATTERN_HEX = Pattern.compile("^0x[0-9a-fA-F]+$");
|
||||||
public static final Pattern PATTERN_REFERENCE = Pattern.compile("^([?@])(([^\\s:@?/]+:)?)([^\\s:@?/]+)/([^\\s:@?/]+)$");
|
public static final Pattern PATTERN_REFERENCE = Pattern.compile("^([?@])(([^\\s:@?/]+:)?)([^\\s:@?/]+)/([^\\s:@?/]+)$");
|
||||||
public static final Pattern PATTERN_HEX_REFERENCE = Pattern.compile("^([?@])(0x[0-9a-f]{7,8})$");
|
public static final Pattern PATTERN_HEX_REFERENCE = Pattern.compile("^([?@])(0x[0-9a-f]{7,8})$");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user