Fix LocaleNumberSystem + ConfigFlag reading (#3205)

* fix: prevent over-reading config flags

* fix: properly read localeNumberingSystem

* test: adjust test for bcp47 aapt2 test

* fix: properly add 8 to 'read' on parser

* test: add test for aapt2 bcp47 tag

* test: add additional bcp47 test

* fix: handle numbering system parsing

* fix: add comment about localeNumber usage
This commit is contained in:
Connor Tumbleson 2023-07-23 17:25:25 -04:00 committed by GitHub
parent 54836509ed
commit d1a0c941ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 53 additions and 15 deletions

View File

@ -51,6 +51,8 @@ public class ResConfigFlags {
private final byte screenLayout2; private final byte screenLayout2;
private final byte colorMode; private final byte colorMode;
private final char[] localeNumberingSystem;
public final boolean isInvalid; public final boolean isInvalid;
private final String mQualifiers; private final String mQualifiers;
@ -80,6 +82,7 @@ public class ResConfigFlags {
localeVariant = null; localeVariant = null;
screenLayout2 = 0; screenLayout2 = 0;
colorMode = COLOR_WIDE_UNDEFINED; colorMode = COLOR_WIDE_UNDEFINED;
localeNumberingSystem = null;
isInvalid = false; isInvalid = false;
mQualifiers = ""; mQualifiers = "";
size = 0; size = 0;
@ -92,7 +95,8 @@ public class ResConfigFlags {
short sdkVersion, byte screenLayout, byte uiMode, short sdkVersion, byte screenLayout, byte uiMode,
short smallestScreenWidthDp, short screenWidthDp, short smallestScreenWidthDp, short screenWidthDp,
short screenHeightDp, char[] localeScript, char[] localeVariant, short screenHeightDp, char[] localeScript, char[] localeVariant,
byte screenLayout2, byte colorMode, boolean isInvalid, int size) { byte screenLayout2, byte colorMode, char[] localeNumberingSystem,
boolean isInvalid, int size) {
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;
@ -157,6 +161,7 @@ public class ResConfigFlags {
this.localeVariant = localeVariant; this.localeVariant = localeVariant;
this.screenLayout2 = screenLayout2; this.screenLayout2 = screenLayout2;
this.colorMode = colorMode; this.colorMode = colorMode;
this.localeNumberingSystem = localeNumberingSystem;
this.isInvalid = isInvalid; this.isInvalid = isInvalid;
this.size = size; this.size = size;
mQualifiers = generateQualifiers(); mQualifiers = generateQualifiers();
@ -466,6 +471,12 @@ public class ResConfigFlags {
if (localeVariant != null && localeVariant.length >= 5) { if (localeVariant != null && localeVariant.length >= 5) {
sb.append("+").append(toUpper(localeVariant)); sb.append("+").append(toUpper(localeVariant));
} }
// If we have a numbering system - it isn't used in qualifiers for build tools, but AOSP understands it
// So chances are - this may be valid, but aapt 1/2 will not like it.
if (localeNumberingSystem != null && localeNumberingSystem.length > 0) {
sb.append("+u+nu+").append(localeNumberingSystem);
}
} }
return sb.toString(); return sb.toString();
} }

View File

@ -497,8 +497,8 @@ public class ARSCDecoder {
char[] localeScript = null; char[] localeScript = null;
char[] localeVariant = null; char[] localeVariant = null;
if (size >= 48) { if (size >= 48) {
localeScript = readScriptOrVariantChar(4).toCharArray(); localeScript = readVariantLengthString(4).toCharArray();
localeVariant = readScriptOrVariantChar(8).toCharArray(); localeVariant = readVariantLengthString(8).toCharArray();
read = 48; read = 48;
} }
@ -511,16 +511,16 @@ public class ARSCDecoder {
read = 52; read = 52;
} }
if (size > 52) { char[] localeNumberingSystem = null;
int length = size - read; if (size >= 60) {
mIn.skipBytes(length); // localeNumberingSystem localeNumberingSystem = readVariantLengthString(8).toCharArray();
read += length; read = 60;
} }
int exceedingSize = size - KNOWN_CONFIG_BYTES; int exceedingKnownSize = size - KNOWN_CONFIG_BYTES;
if (exceedingSize > 0) { if (exceedingKnownSize > 0) {
byte[] buf = new byte[exceedingSize]; byte[] buf = new byte[exceedingKnownSize];
read += exceedingSize; read += exceedingKnownSize;
mIn.readFully(buf); mIn.readFully(buf);
BigInteger exceedingBI = new BigInteger(1, buf); BigInteger exceedingBI = new BigInteger(1, buf);
@ -545,7 +545,7 @@ public class ARSCDecoder {
inputFlags, screenWidth, screenHeight, sdkVersion, inputFlags, screenWidth, screenHeight, sdkVersion,
screenLayout, uiMode, smallestScreenWidthDp, screenWidthDp, screenLayout, uiMode, smallestScreenWidthDp, screenWidthDp,
screenHeightDp, localeScript, localeVariant, screenLayout2, screenHeightDp, localeScript, localeVariant, screenLayout2,
colorMode, isInvalid, size); colorMode, localeNumberingSystem, isInvalid, size);
} }
private char[] unpackLanguageOrRegion(byte in0, byte in1, char base) { private char[] unpackLanguageOrRegion(byte in0, byte in1, char base) {
@ -562,17 +562,17 @@ public class ARSCDecoder {
return new char[] { (char) in0, (char) in1 }; return new char[] { (char) in0, (char) in1 };
} }
private String readScriptOrVariantChar(int length) throws IOException { private String readVariantLengthString(int maxLength) throws IOException {
StringBuilder string = new StringBuilder(16); StringBuilder string = new StringBuilder(16);
while (length-- != 0) { while (maxLength-- != 0) {
short ch = mIn.readByte(); short ch = mIn.readByte();
if (ch == 0) { if (ch == 0) {
break; break;
} }
string.append((char) ch); string.append((char) ch);
} }
mIn.skipBytes(length); mIn.skipBytes(maxLength);
return string.toString(); return string.toString();
} }

View File

@ -76,6 +76,17 @@ public class BuildAndDecodeTest extends BaseTest {
compareValuesFiles("values-es/strings.xml"); compareValuesFiles("values-es/strings.xml");
} }
@Test
public void valuesBcp47LanguageVariantTest() throws BrutException {
compareValuesFiles("values-b+iw+660/strings.xml");
}
@Test
public void valuesBcp47LanguageScriptRegionVariantTest() throws BrutException {
compareValuesFiles("values-b+ast+Latn+IT+AREVELA/strings.xml");
compareValuesFiles("values-b+ast+Hant+IT+ARABEXT/strings.xml");
}
@Test @Test
public void confirmZeroByteFileExtensionIsNotStored() throws BrutException { public void confirmZeroByteFileExtensionIsNotStored() throws BrutException {
ApkInfo apkInfo = ApkInfo.load(sTestNewDir); ApkInfo apkInfo = ApkInfo.load(sTestNewDir);

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">testapp</string>
</resources>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">testapp</string>
</resources>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">testapp</string>
</resources>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">testapp</string>
</resources>