mirror of
https://github.com/revanced/Apktool.git
synced 2025-01-21 01:07: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 short mnc;
|
||||||
|
|
||||||
public final char[] language;
|
public final char[] language;
|
||||||
public final char[] country;
|
public final char[] region;
|
||||||
|
|
||||||
public final short layoutDirection;
|
|
||||||
|
|
||||||
public final byte orientation;
|
public final byte orientation;
|
||||||
public final byte touchscreen;
|
public final byte touchscreen;
|
||||||
@ -50,6 +48,9 @@ public class ResConfigFlags {
|
|||||||
public final short screenWidthDp;
|
public final short screenWidthDp;
|
||||||
public final short screenHeightDp;
|
public final short screenHeightDp;
|
||||||
|
|
||||||
|
private final char[] localeScript;
|
||||||
|
private final char[] localeVariant;
|
||||||
|
|
||||||
public final boolean isInvalid;
|
public final boolean isInvalid;
|
||||||
|
|
||||||
private final String mQualifiers;
|
private final String mQualifiers;
|
||||||
@ -58,8 +59,7 @@ public class ResConfigFlags {
|
|||||||
mcc = 0;
|
mcc = 0;
|
||||||
mnc = 0;
|
mnc = 0;
|
||||||
language = new char[] { '\00', '\00' };
|
language = new char[] { '\00', '\00' };
|
||||||
country = new char[] { '\00', '\00' };
|
region = new char[] { '\00', '\00' };
|
||||||
layoutDirection = SCREENLAYOUT_LAYOUTDIR_ANY;
|
|
||||||
orientation = ORIENTATION_ANY;
|
orientation = ORIENTATION_ANY;
|
||||||
touchscreen = TOUCHSCREEN_ANY;
|
touchscreen = TOUCHSCREEN_ANY;
|
||||||
density = DENSITY_DEFAULT;
|
density = DENSITY_DEFAULT;
|
||||||
@ -74,17 +74,20 @@ public class ResConfigFlags {
|
|||||||
smallestScreenWidthDp = 0;
|
smallestScreenWidthDp = 0;
|
||||||
screenWidthDp = 0;
|
screenWidthDp = 0;
|
||||||
screenHeightDp = 0;
|
screenHeightDp = 0;
|
||||||
|
localeScript = new char[] { '\00', '\00', '\00', '\00' };
|
||||||
|
localeVariant = new char[] { '\00', '\00', '\00', '\00', '\00', '\00', '\00', '\00' };
|
||||||
isInvalid = false;
|
isInvalid = false;
|
||||||
mQualifiers = "";
|
mQualifiers = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResConfigFlags(short mcc, short mnc, char[] language,
|
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 touchscreen, int density, byte keyboard, byte navigation,
|
||||||
byte inputFlags, short screenWidth, short screenHeight,
|
byte inputFlags, short screenWidth, short screenHeight,
|
||||||
short sdkVersion, byte screenLayout, byte uiMode,
|
short sdkVersion, byte screenLayout, byte uiMode,
|
||||||
short smallestScreenWidthDp, short screenWidthDp,
|
short smallestScreenWidthDp, short screenWidthDp,
|
||||||
short screenHeightDp, boolean isInvalid) {
|
short screenHeightDp, char[] localeScript, char[] localeVariant,
|
||||||
|
boolean isInvalid) {
|
||||||
if (orientation < 0 || orientation > 3) {
|
if (orientation < 0 || orientation > 3) {
|
||||||
LOGGER.warning("Invalid orientation value: " + orientation);
|
LOGGER.warning("Invalid orientation value: " + orientation);
|
||||||
orientation = 0;
|
orientation = 0;
|
||||||
@ -114,8 +117,7 @@ public class ResConfigFlags {
|
|||||||
this.mcc = mcc;
|
this.mcc = mcc;
|
||||||
this.mnc = mnc;
|
this.mnc = mnc;
|
||||||
this.language = language;
|
this.language = language;
|
||||||
this.country = country;
|
this.region = region;
|
||||||
this.layoutDirection = layoutDirection;
|
|
||||||
this.orientation = orientation;
|
this.orientation = orientation;
|
||||||
this.touchscreen = touchscreen;
|
this.touchscreen = touchscreen;
|
||||||
this.density = density;
|
this.density = density;
|
||||||
@ -130,6 +132,8 @@ public class ResConfigFlags {
|
|||||||
this.smallestScreenWidthDp = smallestScreenWidthDp;
|
this.smallestScreenWidthDp = smallestScreenWidthDp;
|
||||||
this.screenWidthDp = screenWidthDp;
|
this.screenWidthDp = screenWidthDp;
|
||||||
this.screenHeightDp = screenHeightDp;
|
this.screenHeightDp = screenHeightDp;
|
||||||
|
this.localeScript = localeScript;
|
||||||
|
this.localeVariant = localeVariant;
|
||||||
this.isInvalid = isInvalid;
|
this.isInvalid = isInvalid;
|
||||||
mQualifiers = generateQualifiers();
|
mQualifiers = generateQualifiers();
|
||||||
}
|
}
|
||||||
@ -155,12 +159,8 @@ public class ResConfigFlags {
|
|||||||
ret.append("-mnc00");
|
ret.append("-mnc00");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (language[0] != '\00') {
|
ret.append(getLocaleString());
|
||||||
ret.append('-').append(language);
|
|
||||||
if (country[0] != '\00') {
|
|
||||||
ret.append("-r").append(country);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (screenLayout & MASK_LAYOUTDIR) {
|
switch (screenLayout & MASK_LAYOUTDIR) {
|
||||||
case SCREENLAYOUT_LAYOUTDIR_RTL:
|
case SCREENLAYOUT_LAYOUTDIR_RTL:
|
||||||
ret.append("-ldrtl");
|
ret.append("-ldrtl");
|
||||||
@ -369,6 +369,51 @@ public class ResConfigFlags {
|
|||||||
return 0;
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return !getQualifiers().equals("") ? getQualifiers() : "[DEFAULT]";
|
return !getQualifiers().equals("") ? getQualifiers() : "[DEFAULT]";
|
||||||
|
@ -256,8 +256,8 @@ public class ARSCDecoder {
|
|||||||
short mcc = mIn.readShort();
|
short mcc = mIn.readShort();
|
||||||
short mnc = mIn.readShort();
|
short mnc = mIn.readShort();
|
||||||
|
|
||||||
char[] language = new char[] { (char) mIn.readByte(), (char) mIn.readByte() };
|
char[] language = this.unpackLanguageOrRegion(mIn.readByte(), mIn.readByte(), 'a');
|
||||||
char[] country = new char[] { (char) mIn.readByte(), (char) mIn.readByte() };
|
char[] country = this.unpackLanguageOrRegion(mIn.readByte(), mIn.readByte(), '0');
|
||||||
|
|
||||||
byte orientation = mIn.readByte();
|
byte orientation = mIn.readByte();
|
||||||
byte touchscreen = mIn.readByte();
|
byte touchscreen = mIn.readByte();
|
||||||
@ -291,9 +291,11 @@ public class ARSCDecoder {
|
|||||||
screenHeightDp = mIn.readShort();
|
screenHeightDp = mIn.readShort();
|
||||||
}
|
}
|
||||||
|
|
||||||
short layoutDirection = 0;
|
char[] localeScript = {'\00'};
|
||||||
if (size >= 38) {
|
char[] localeVariant = {'\00'};
|
||||||
layoutDirection = mIn.readShort();
|
if (size >= 48) {
|
||||||
|
localeScript = this.readScriptOrVariantChar(4).toCharArray();
|
||||||
|
localeVariant = this.readScriptOrVariantChar(8).toCharArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
int exceedingSize = size - KNOWN_CONFIG_BYTES;
|
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,
|
orientation, touchscreen, density, keyboard, navigation,
|
||||||
inputFlags, screenWidth, screenHeight, sdkVersion,
|
inputFlags, screenWidth, screenHeight, sdkVersion,
|
||||||
screenLayout, uiMode, smallestScreenWidthDp, screenWidthDp,
|
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 {
|
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 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 {
|
public static class ARSCData {
|
||||||
|
|
||||||
|
@ -182,6 +182,51 @@ public class BuildAndDecodeTest {
|
|||||||
compareValuesFiles("values-watch/strings.xml");
|
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
|
@Test
|
||||||
public void drawableNoDpiTest() throws BrutException, IOException {
|
public void drawableNoDpiTest() throws BrutException, IOException {
|
||||||
compareResFolder("drawable-nodpi");
|
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