mirror of
https://github.com/revanced/Apktool.git
synced 2025-01-20 16:57:34 +01:00
Merge pull request #100 from iBotPeaches/bcp47-support
[WIP] Initial support for BCP47 tags
This commit is contained in:
commit
4638c06de4
@ -26,9 +26,7 @@ public class ResConfigFlags {
|
||||
public final short mnc;
|
||||
|
||||
public final char[] language;
|
||||
public final char[] country;
|
||||
|
||||
public final short layoutDirection;
|
||||
public final char[] region;
|
||||
|
||||
public final byte orientation;
|
||||
public final byte touchscreen;
|
||||
@ -50,6 +48,9 @@ public class ResConfigFlags {
|
||||
public final short screenWidthDp;
|
||||
public final short screenHeightDp;
|
||||
|
||||
private final char[] localeScript;
|
||||
private final char[] localeVariant;
|
||||
|
||||
public final boolean isInvalid;
|
||||
|
||||
private final String mQualifiers;
|
||||
@ -58,8 +59,7 @@ public class ResConfigFlags {
|
||||
mcc = 0;
|
||||
mnc = 0;
|
||||
language = new char[] { '\00', '\00' };
|
||||
country = new char[] { '\00', '\00' };
|
||||
layoutDirection = SCREENLAYOUT_LAYOUTDIR_ANY;
|
||||
region = new char[] { '\00', '\00' };
|
||||
orientation = ORIENTATION_ANY;
|
||||
touchscreen = TOUCHSCREEN_ANY;
|
||||
density = DENSITY_DEFAULT;
|
||||
@ -74,17 +74,20 @@ public class ResConfigFlags {
|
||||
smallestScreenWidthDp = 0;
|
||||
screenWidthDp = 0;
|
||||
screenHeightDp = 0;
|
||||
localeScript = new char[] { '\00', '\00', '\00', '\00' };
|
||||
localeVariant = new char[] { '\00', '\00', '\00', '\00', '\00', '\00', '\00', '\00' };
|
||||
isInvalid = false;
|
||||
mQualifiers = "";
|
||||
}
|
||||
|
||||
public ResConfigFlags(short mcc, short mnc, char[] language,
|
||||
char[] country, short layoutDirection, byte orientation,
|
||||
char[] region, byte orientation,
|
||||
byte touchscreen, int density, byte keyboard, byte navigation,
|
||||
byte inputFlags, short screenWidth, short screenHeight,
|
||||
short sdkVersion, byte screenLayout, byte uiMode,
|
||||
short smallestScreenWidthDp, short screenWidthDp,
|
||||
short screenHeightDp, boolean isInvalid) {
|
||||
short screenHeightDp, char[] localeScript, char[] localeVariant,
|
||||
boolean isInvalid) {
|
||||
if (orientation < 0 || orientation > 3) {
|
||||
LOGGER.warning("Invalid orientation value: " + orientation);
|
||||
orientation = 0;
|
||||
@ -114,8 +117,7 @@ public class ResConfigFlags {
|
||||
this.mcc = mcc;
|
||||
this.mnc = mnc;
|
||||
this.language = language;
|
||||
this.country = country;
|
||||
this.layoutDirection = layoutDirection;
|
||||
this.region = region;
|
||||
this.orientation = orientation;
|
||||
this.touchscreen = touchscreen;
|
||||
this.density = density;
|
||||
@ -130,6 +132,8 @@ public class ResConfigFlags {
|
||||
this.smallestScreenWidthDp = smallestScreenWidthDp;
|
||||
this.screenWidthDp = screenWidthDp;
|
||||
this.screenHeightDp = screenHeightDp;
|
||||
this.localeScript = localeScript;
|
||||
this.localeVariant = localeVariant;
|
||||
this.isInvalid = isInvalid;
|
||||
mQualifiers = generateQualifiers();
|
||||
}
|
||||
@ -155,12 +159,8 @@ public class ResConfigFlags {
|
||||
ret.append("-mnc00");
|
||||
}
|
||||
}
|
||||
if (language[0] != '\00') {
|
||||
ret.append('-').append(language);
|
||||
if (country[0] != '\00') {
|
||||
ret.append("-r").append(country);
|
||||
}
|
||||
}
|
||||
ret.append(getLocaleString());
|
||||
|
||||
switch (screenLayout & MASK_LAYOUTDIR) {
|
||||
case SCREENLAYOUT_LAYOUTDIR_RTL:
|
||||
ret.append("-ldrtl");
|
||||
@ -369,6 +369,51 @@ public class ResConfigFlags {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private String getLocaleString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
// check for old style non BCP47 tags
|
||||
// allows values-xx-rXX, values-xx, values-xxx-rXX
|
||||
// denies values-xxx, anything else
|
||||
if (language[0] != '\00' && localeScript.length == 0 && localeVariant.length == 0 &&
|
||||
(region.length != 3 && language.length != 3) ||
|
||||
(language.length == 3 && region.length == 2 && region[0] != '\00' &&
|
||||
localeScript.length == 0 && localeVariant.length == 0)) {
|
||||
|
||||
sb.append("-").append(language);
|
||||
if (region[0] != '\00') {
|
||||
sb.append("-r").append(region);
|
||||
}
|
||||
} else { // BCP47
|
||||
if (language[0] == '\00' && region[0] == '\00') {
|
||||
return sb.toString(); // early return, no language or region
|
||||
}
|
||||
sb.append("-b+");
|
||||
if (language[0] != '\00') {
|
||||
sb.append(language);
|
||||
}
|
||||
if (localeScript.length == 4) {
|
||||
sb.append("+").append(localeScript);
|
||||
}
|
||||
if ((region.length == 2 || region.length == 3) && region[0] != '\00') {
|
||||
sb.append("+").append(region);
|
||||
}
|
||||
if (localeVariant.length >= 5) {
|
||||
sb.append("+").append(toUpper(localeVariant));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String toUpper(char[] character) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (char ch: character) {
|
||||
sb.append(Character.toUpperCase(ch));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return !getQualifiers().equals("") ? getQualifiers() : "[DEFAULT]";
|
||||
|
@ -256,8 +256,8 @@ public class ARSCDecoder {
|
||||
short mcc = mIn.readShort();
|
||||
short mnc = mIn.readShort();
|
||||
|
||||
char[] language = new char[] { (char) mIn.readByte(), (char) mIn.readByte() };
|
||||
char[] country = new char[] { (char) mIn.readByte(), (char) mIn.readByte() };
|
||||
char[] language = this.unpackLanguageOrRegion(mIn.readByte(), mIn.readByte(), 'a');
|
||||
char[] country = this.unpackLanguageOrRegion(mIn.readByte(), mIn.readByte(), '0');
|
||||
|
||||
byte orientation = mIn.readByte();
|
||||
byte touchscreen = mIn.readByte();
|
||||
@ -291,9 +291,11 @@ public class ARSCDecoder {
|
||||
screenHeightDp = mIn.readShort();
|
||||
}
|
||||
|
||||
short layoutDirection = 0;
|
||||
if (size >= 38) {
|
||||
layoutDirection = mIn.readShort();
|
||||
char[] localeScript = {'\00'};
|
||||
char[] localeVariant = {'\00'};
|
||||
if (size >= 48) {
|
||||
localeScript = this.readScriptOrVariantChar(4).toCharArray();
|
||||
localeVariant = this.readScriptOrVariantChar(8).toCharArray();
|
||||
}
|
||||
|
||||
int exceedingSize = size - KNOWN_CONFIG_BYTES;
|
||||
@ -313,11 +315,40 @@ public class ARSCDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
return new ResConfigFlags(mcc, mnc, language, country, layoutDirection,
|
||||
return new ResConfigFlags(mcc, mnc, language, country,
|
||||
orientation, touchscreen, density, keyboard, navigation,
|
||||
inputFlags, screenWidth, screenHeight, sdkVersion,
|
||||
screenLayout, uiMode, smallestScreenWidthDp, screenWidthDp,
|
||||
screenHeightDp, isInvalid);
|
||||
screenHeightDp, localeScript, localeVariant, isInvalid);
|
||||
}
|
||||
|
||||
private char[] unpackLanguageOrRegion(byte in0, byte in1, char base) throws AndrolibException {
|
||||
// check high bit, if so we have a packed 3 letter code
|
||||
if (((in0 >> 7) & 1) == 1) {
|
||||
int first = in1 & 0x1F;
|
||||
int second = ((in1 & 0xE0) >> 5) + ((in0 & 0x03) << 3);
|
||||
int third = (in0 & 0x7C) >> 2;
|
||||
|
||||
// since this function handles languages & regions, we add the value(s) to the base char
|
||||
// which is usually 'a' or '0' depending on language or region.
|
||||
return new char[] { (char) (first + base), (char) (second + base), (char) (third + base) };
|
||||
}
|
||||
return new char[] { (char) in0, (char) in1 };
|
||||
}
|
||||
|
||||
private String readScriptOrVariantChar(int length) throws AndrolibException, IOException {
|
||||
StringBuilder string = new StringBuilder(16);
|
||||
|
||||
while(length-- != 0) {
|
||||
short ch = mIn.readByte();
|
||||
if (ch == 0) {
|
||||
break;
|
||||
}
|
||||
string.append((char) ch);
|
||||
}
|
||||
mIn.skipBytes(length);
|
||||
|
||||
return string.toString();
|
||||
}
|
||||
|
||||
private void addMissingResSpecs() throws AndrolibException {
|
||||
@ -416,7 +447,7 @@ public class ARSCDecoder {
|
||||
}
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(ARSCDecoder.class.getName());
|
||||
private static final int KNOWN_CONFIG_BYTES = 38;
|
||||
private static final int KNOWN_CONFIG_BYTES = 48;
|
||||
|
||||
public static class ARSCData {
|
||||
|
||||
|
@ -182,6 +182,51 @@ public class BuildAndDecodeTest {
|
||||
compareValuesFiles("values-watch/strings.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packed3CharsTest() throws BrutException, IOException {
|
||||
compareValuesFiles("values-ast-rES/strings.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rightToLeftTest() throws BrutException, IOException {
|
||||
compareValuesFiles("values-ldrtl/strings.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scriptBcp47Test() throws BrutException, IOException {
|
||||
compareValuesFiles("values-b+en+Latn+US/strings.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void threeLetterLangBcp47Test() throws BrutException, IOException {
|
||||
compareValuesFiles("values-b+ast/strings.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void twoLetterLangBcp47Test() throws BrutException, IOException {
|
||||
compareValuesFiles("values-en-rUS/strings.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void variantBcp47Test() throws BrutException, IOException {
|
||||
compareValuesFiles("values-b+en+US+POSIX/strings.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fourpartBcp47Test() throws BrutException, IOException {
|
||||
compareValuesFiles("values-b+ast+Latn+IT+AREVELA/strings.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void RegionLocaleBcp47Test() throws BrutException, IOException {
|
||||
compareValuesFiles("values-b+en+Latn+419/strings.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void numericalRegionBcp47Test() throws BrutException, IOException {
|
||||
compareValuesFiles("values-b+eng+419/strings.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void drawableNoDpiTest() throws BrutException, IOException {
|
||||
compareResFolder("drawable-nodpi");
|
||||
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="test1">test1</string>
|
||||
</resources>
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="test1">test1</string>
|
||||
</resources>
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="test1">test1</string>
|
||||
</resources>
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="test1">test1</string>
|
||||
</resources>
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="test1">test1</string>
|
||||
</resources>
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="test1">test1</string>
|
||||
</resources>
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="test1">test1</string>
|
||||
</resources>
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="test1">test1</string>
|
||||
</resources>
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="test1">test1</string>
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user