mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-04-30 06:14:25 +02:00
fix: encode and decode DIMENSION/FRACTION values correctly
This commit is contained in:
parent
c56c90d3e0
commit
3d4fe269a5
206
src/main/java/com/reandroid/arsc/decoder/ComplexUtil.java
Normal file
206
src/main/java/com/reandroid/arsc/decoder/ComplexUtil.java
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* 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.decoder;
|
||||
|
||||
public class ComplexUtil {
|
||||
|
||||
public static String decodeComplex(boolean fraction, int complex_value){
|
||||
int radixFlag = (complex_value >> COMPLEX_RADIX_SHIFT) & COMPLEX_RADIX_MASK;
|
||||
Radix radix = Radix.forFlag(radixFlag);
|
||||
long mantissa = (complex_value >> COMPLEX_MANTISSA_SHIFT) & COMPLEX_MANTISSA_MASK;
|
||||
mantissa = mantissa << radix.getShift();
|
||||
float value = mantissa * MANTISSA_MULTIPLIER;
|
||||
int unit_type = (complex_value >> COMPLEX_UNIT_SHIFT) & COMPLEX_UNIT_MASK;
|
||||
Unit unit = Unit.fromFlag(fraction, unit_type);
|
||||
return radix.formatFloat(fraction, value) + unit.getSymbol();
|
||||
}
|
||||
public static int encodeComplex(float value, String unit){
|
||||
return encodeComplex(value, Unit.fromSymbol(unit));
|
||||
}
|
||||
public static int encodeComplex(float value, Unit unit){
|
||||
boolean neg = value < 0;
|
||||
if (neg) {
|
||||
value = -value;
|
||||
}
|
||||
long bits = (long)(value*(1<<23) + 0.5f);
|
||||
|
||||
Radix radix = Radix.getRadix(bits);
|
||||
int mantissa = (int)((bits>>radix.getShift()) & COMPLEX_MANTISSA_MASK);
|
||||
if (neg) {
|
||||
mantissa = (-mantissa) & COMPLEX_MANTISSA_MASK;
|
||||
}
|
||||
int result = (radix.getFlag()<<COMPLEX_RADIX_SHIFT)
|
||||
| (mantissa<<COMPLEX_MANTISSA_SHIFT);
|
||||
|
||||
result = result | unit.getFlag();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public enum Unit {
|
||||
PX(0, "px"),
|
||||
DP(1, "dp"),
|
||||
DIP(1, "dip"),
|
||||
SP(2, "sp"),
|
||||
PT(3, "pt"),
|
||||
IN(4, "in"),
|
||||
MM(5, "mm"),
|
||||
FRACTION(0, "%"),
|
||||
FRACTION_PARENT(1, "%p");
|
||||
|
||||
private final int flag;
|
||||
private final String symbol;
|
||||
Unit(int flag, String symbol) {
|
||||
this.flag = flag;
|
||||
this.symbol = symbol;
|
||||
}
|
||||
public int getFlag() {
|
||||
return flag;
|
||||
}
|
||||
public String getSymbol(){
|
||||
return symbol;
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
return getSymbol();
|
||||
}
|
||||
public static Unit fromFlag(boolean fraction, int flag){
|
||||
Unit unit;
|
||||
if(fraction){
|
||||
unit = fromFlag(FRACTIONS, flag);
|
||||
}else {
|
||||
unit = fromFlag(DIMENSIONS, flag);
|
||||
}
|
||||
if(unit!=null){
|
||||
return unit;
|
||||
}
|
||||
throw new NumberFormatException("Unknown unit flag = "+flag
|
||||
+" for"+(fraction?"fraction":"dimension"));
|
||||
}
|
||||
private static Unit fromFlag(Unit[] units, int flag){
|
||||
for(Unit unit: units){
|
||||
if(flag == unit.getFlag()){
|
||||
return unit;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static Unit fromSymbol(String symbol){
|
||||
if(symbol == null){
|
||||
return null;
|
||||
}
|
||||
Unit unit = fromSymbol(DIMENSIONS, symbol);
|
||||
if(unit == null){
|
||||
unit = fromSymbol(FRACTIONS, symbol);
|
||||
}
|
||||
return unit;
|
||||
}
|
||||
private static Unit fromSymbol(Unit[] units, String symbol){
|
||||
for(Unit unit: units){
|
||||
if(unit.getSymbol().equals(symbol)){
|
||||
return unit;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final Unit[] DIMENSIONS = new Unit[]{
|
||||
PX,
|
||||
DP,
|
||||
DIP,
|
||||
SP,
|
||||
PT,
|
||||
IN,
|
||||
MM
|
||||
};
|
||||
private static final Unit[] FRACTIONS = new Unit[]{
|
||||
FRACTION,
|
||||
FRACTION_PARENT
|
||||
};
|
||||
}
|
||||
public enum Radix{
|
||||
RADIX_23p0(0, 23),
|
||||
RADIX_16p7(1, 16),
|
||||
RADIX_8p15(2, 8),
|
||||
RADIX_0p23(3, 0);
|
||||
|
||||
private final int flag;
|
||||
private final int shift;
|
||||
Radix(int flag, int shift) {
|
||||
this.flag = flag;
|
||||
this.shift = shift;
|
||||
}
|
||||
public String formatFloat(boolean scale, float value){
|
||||
if(this.flag == 0){
|
||||
if(scale){
|
||||
value = value * 100.0f;
|
||||
}
|
||||
return String.format("%.1f", value);
|
||||
}
|
||||
String result = String.format("%.6f", value);
|
||||
// To trim ending zeros
|
||||
value = Float.parseFloat(result);
|
||||
if(scale){
|
||||
value = value * 100.0f;
|
||||
}
|
||||
result = Float.toString(value);
|
||||
return result;
|
||||
}
|
||||
public static Radix forFlag(int flag){
|
||||
if(flag == 0){
|
||||
return RADIX_23p0;
|
||||
}
|
||||
if(flag == 1){
|
||||
return RADIX_16p7;
|
||||
}
|
||||
if(flag == 2){
|
||||
return RADIX_8p15;
|
||||
}
|
||||
if(flag == 3){
|
||||
return RADIX_0p23;
|
||||
}
|
||||
throw new NumberFormatException("Unknown radix flag = "+flag);
|
||||
}
|
||||
public static Radix getRadix(long bits){
|
||||
if ((bits&0x7fffff) == 0) {
|
||||
return RADIX_23p0;
|
||||
}
|
||||
if ((bits&0xffffffffff800000L) == 0) {
|
||||
return RADIX_0p23;
|
||||
}
|
||||
if ((bits&0xffffffff80000000L) == 0) {
|
||||
return RADIX_8p15;
|
||||
}
|
||||
if ((bits&0xffffff8000000000L) == 0) {
|
||||
return RADIX_16p7;
|
||||
}
|
||||
throw new NumberFormatException("Radix bits out of range bits = "+bits);
|
||||
}
|
||||
public int getFlag() {
|
||||
return flag;
|
||||
}
|
||||
public int getShift() {
|
||||
return shift;
|
||||
}
|
||||
}
|
||||
private static final int COMPLEX_RADIX_SHIFT = 4;
|
||||
private static final int COMPLEX_RADIX_MASK = 0x3;
|
||||
private static final int COMPLEX_MANTISSA_SHIFT = 8;
|
||||
private static final int COMPLEX_MANTISSA_MASK = 0xffffff;
|
||||
private static final float MANTISSA_MULTIPLIER = (1.0f / (1 << 23));
|
||||
private static final int COMPLEX_UNIT_SHIFT = 0;
|
||||
private static final int COMPLEX_UNIT_MASK = 0xf;
|
||||
}
|
@ -250,31 +250,16 @@ import java.util.regex.Pattern;
|
||||
float fraction = Float.parseFloat(number);
|
||||
return encodeDimensionOrFraction(fraction, unit);
|
||||
}
|
||||
// TODO: This method should be revised
|
||||
private static EncodeResult encodeDimensionOrFraction(float val, String unit){
|
||||
ValueType valueType = ValueType.DIMENSION;
|
||||
if(unit.charAt(0) == '%'){
|
||||
val=val/100.0f;
|
||||
private static EncodeResult encodeDimensionOrFraction(float value, String unitSymbol){
|
||||
ComplexUtil.Unit unit = ComplexUtil.Unit.fromSymbol(unitSymbol);
|
||||
ValueType valueType;
|
||||
if(unit == ComplexUtil.Unit.FRACTION || unit == ComplexUtil.Unit.FRACTION_PARENT){
|
||||
valueType = ValueType.FRACTION;
|
||||
value = value / 100.0f;
|
||||
}else {
|
||||
valueType = ValueType.DIMENSION;
|
||||
}
|
||||
int index = ValueDecoder.getDimensionIndex(unit);
|
||||
int result = 0;
|
||||
int shift = 0;
|
||||
if(val!=0.0f){
|
||||
for(int i=0;i<4;i++){
|
||||
float fl = val/ValueDecoder.RADIX_MULTS[i];
|
||||
int fl_int = (int)fl;
|
||||
int last = (fl_int&0xff);
|
||||
if(fl_int!=0 && last==0){
|
||||
shift = i;
|
||||
result = fl_int;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
shift = shift<<4;
|
||||
result = result | shift;
|
||||
result = result | index;
|
||||
int result = ComplexUtil.encodeComplex(value, unit);
|
||||
return new EncodeResult(valueType, result);
|
||||
}
|
||||
|
||||
@ -714,93 +699,11 @@ import java.util.regex.Pattern;
|
||||
return String.format("#%08x", rawVal);
|
||||
}
|
||||
private static String decodeDimensionOrFloat(ValueType valueType, int rawVal){
|
||||
return decodeFloat(rawVal, valueType);
|
||||
}
|
||||
private static String decodeFloat(int val, ValueType valueType){
|
||||
if(valueType==ValueType.FLOAT){
|
||||
float f=Float.intBitsToFloat(val);
|
||||
float f=Float.intBitsToFloat(rawVal);
|
||||
return Float.toString(f);
|
||||
}
|
||||
float f=complexToFloat(val);
|
||||
String unit="";
|
||||
switch (valueType){
|
||||
case FRACTION:
|
||||
f=f*100;
|
||||
if((val & 0x3)==0){
|
||||
unit="%";
|
||||
}else {
|
||||
unit="%p";
|
||||
}
|
||||
break;
|
||||
case DIMENSION:
|
||||
int i=(val & 0xf);
|
||||
unit=getDimensionUnit(i);
|
||||
break;
|
||||
}
|
||||
return Float.toString(f)+unit;
|
||||
}
|
||||
private static float complexToFloat(int complex) {
|
||||
int y=(complex >> 4) & 0x3;
|
||||
float result=complex & 0xffffff00;
|
||||
float y2=RADIX_MULTS[y];
|
||||
result=result * y2;
|
||||
return result;
|
||||
}
|
||||
static String getDimensionUnit(int index){
|
||||
if(index<0 || index>DIMENSION_UNIT_STRS.length){
|
||||
index=1;
|
||||
}
|
||||
return DIMENSION_UNIT_STRS[index];
|
||||
}
|
||||
private static int getDimensionIndex(String unit){
|
||||
if("%".equals(unit)){
|
||||
return 0;
|
||||
}
|
||||
if("%p".equals(unit)){
|
||||
return 1;
|
||||
}
|
||||
if("dip".equals(unit)){
|
||||
unit = "dp";
|
||||
}
|
||||
String[] dims=DIMENSION_UNIT_STRS;
|
||||
for(int i=0;i<dims.length;i++){
|
||||
if(dims[i].equals(unit)){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Will not happen, we are are confident of {@link PATTERN_DIMEN}
|
||||
* and NOT fraction checked
|
||||
* */
|
||||
throw new IllegalArgumentException("Unexpected dimension unit: '"+unit+"'");
|
||||
}
|
||||
private static String getResourceName(EntryStore store, Entry entry, int resourceId){
|
||||
if(entry !=null){
|
||||
EntryGroup group=searchEntryGroup(entry, resourceId);
|
||||
if(group!=null){
|
||||
String name=group.getSpecName();
|
||||
if(name!=null){
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(store==null){
|
||||
return null;
|
||||
}
|
||||
Collection<EntryGroup> foundGroups = store.getEntryGroups(resourceId);
|
||||
return pickResourceName(foundGroups);
|
||||
}
|
||||
private static String pickResourceName(Collection<EntryGroup> groups){
|
||||
if(groups==null){
|
||||
return null;
|
||||
}
|
||||
for(EntryGroup entryGroup:groups){
|
||||
String name=entryGroup.getSpecName();
|
||||
if(name!=null){
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return ComplexUtil.decodeComplex(valueType == ValueType.FRACTION, rawVal);
|
||||
}
|
||||
private static AttributeBag getAttributeBag(EntryStore store, int resourceId){
|
||||
ResTableMapEntry mapEntry=getAttributeValueBag(store, resourceId);
|
||||
@ -884,11 +787,6 @@ import java.util.regex.Pattern;
|
||||
return valueType+": "+String.format("0x%08x", value);
|
||||
}
|
||||
}
|
||||
private static final String[] DIMENSION_UNIT_STRS = new String[] { "px", "dp", "sp", "pt", "in", "mm" };
|
||||
private static final float MANTISSA_MULT = 1.0f / (1 << 8);
|
||||
static final float[] RADIX_MULTS = new float[] {
|
||||
1.0f * MANTISSA_MULT, 1.0f / (1 << 7) * MANTISSA_MULT,
|
||||
1.0f / (1 << 15) * MANTISSA_MULT, 1.0f / (1 << 23) * MANTISSA_MULT };
|
||||
|
||||
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?)$");
|
||||
|
Loading…
x
Reference in New Issue
Block a user