From d1a0c941abf13a0af2704180aab6340b0f8b73da Mon Sep 17 00:00:00 2001 From: Connor Tumbleson Date: Sun, 23 Jul 2023 17:25:25 -0400 Subject: [PATCH] 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 --- .../androlib/res/data/ResConfigFlags.java | 13 ++++++++- .../androlib/res/decoder/ARSCDecoder.java | 28 +++++++++---------- .../androlib/aapt2/BuildAndDecodeTest.java | 11 ++++++++ .../values-b+ast+Hant+IT+ARABEXT/strings.xml | 4 +++ .../values-b+ast+Latn+IT+AREVELA/strings.xml | 4 +++ .../res/values-b+de+CH+1901/strings.xml | 4 +++ .../testapp/res/values-b+iw+660/strings.xml | 4 +++ 7 files changed, 53 insertions(+), 15 deletions(-) create mode 100644 brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+ast+Hant+IT+ARABEXT/strings.xml create mode 100644 brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+ast+Latn+IT+AREVELA/strings.xml create mode 100644 brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+de+CH+1901/strings.xml create mode 100644 brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+iw+660/strings.xml diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java index 18399add..2c4ae0f8 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java @@ -51,6 +51,8 @@ public class ResConfigFlags { private final byte screenLayout2; private final byte colorMode; + private final char[] localeNumberingSystem; + public final boolean isInvalid; private final String mQualifiers; @@ -80,6 +82,7 @@ public class ResConfigFlags { localeVariant = null; screenLayout2 = 0; colorMode = COLOR_WIDE_UNDEFINED; + localeNumberingSystem = null; isInvalid = false; mQualifiers = ""; size = 0; @@ -92,7 +95,8 @@ public class ResConfigFlags { short sdkVersion, byte screenLayout, byte uiMode, short smallestScreenWidthDp, short screenWidthDp, 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) { LOGGER.warning("Invalid orientation value: " + orientation); orientation = 0; @@ -157,6 +161,7 @@ public class ResConfigFlags { this.localeVariant = localeVariant; this.screenLayout2 = screenLayout2; this.colorMode = colorMode; + this.localeNumberingSystem = localeNumberingSystem; this.isInvalid = isInvalid; this.size = size; mQualifiers = generateQualifiers(); @@ -466,6 +471,12 @@ public class ResConfigFlags { if (localeVariant != null && localeVariant.length >= 5) { 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(); } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java index 88fc3af6..b117780a 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java @@ -497,8 +497,8 @@ public class ARSCDecoder { char[] localeScript = null; char[] localeVariant = null; if (size >= 48) { - localeScript = readScriptOrVariantChar(4).toCharArray(); - localeVariant = readScriptOrVariantChar(8).toCharArray(); + localeScript = readVariantLengthString(4).toCharArray(); + localeVariant = readVariantLengthString(8).toCharArray(); read = 48; } @@ -511,16 +511,16 @@ public class ARSCDecoder { read = 52; } - if (size > 52) { - int length = size - read; - mIn.skipBytes(length); // localeNumberingSystem - read += length; + char[] localeNumberingSystem = null; + if (size >= 60) { + localeNumberingSystem = readVariantLengthString(8).toCharArray(); + read = 60; } - int exceedingSize = size - KNOWN_CONFIG_BYTES; - if (exceedingSize > 0) { - byte[] buf = new byte[exceedingSize]; - read += exceedingSize; + int exceedingKnownSize = size - KNOWN_CONFIG_BYTES; + if (exceedingKnownSize > 0) { + byte[] buf = new byte[exceedingKnownSize]; + read += exceedingKnownSize; mIn.readFully(buf); BigInteger exceedingBI = new BigInteger(1, buf); @@ -545,7 +545,7 @@ public class ARSCDecoder { inputFlags, screenWidth, screenHeight, sdkVersion, screenLayout, uiMode, smallestScreenWidthDp, screenWidthDp, screenHeightDp, localeScript, localeVariant, screenLayout2, - colorMode, isInvalid, size); + colorMode, localeNumberingSystem, isInvalid, size); } private char[] unpackLanguageOrRegion(byte in0, byte in1, char base) { @@ -562,17 +562,17 @@ public class ARSCDecoder { 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); - while (length-- != 0) { + while (maxLength-- != 0) { short ch = mIn.readByte(); if (ch == 0) { break; } string.append((char) ch); } - mIn.skipBytes(length); + mIn.skipBytes(maxLength); return string.toString(); } diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt2/BuildAndDecodeTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt2/BuildAndDecodeTest.java index 248452fc..9f1d972b 100644 --- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt2/BuildAndDecodeTest.java +++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt2/BuildAndDecodeTest.java @@ -76,6 +76,17 @@ public class BuildAndDecodeTest extends BaseTest { 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 public void confirmZeroByteFileExtensionIsNotStored() throws BrutException { ApkInfo apkInfo = ApkInfo.load(sTestNewDir); diff --git a/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+ast+Hant+IT+ARABEXT/strings.xml b/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+ast+Hant+IT+ARABEXT/strings.xml new file mode 100644 index 00000000..8a56a54a --- /dev/null +++ b/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+ast+Hant+IT+ARABEXT/strings.xml @@ -0,0 +1,4 @@ + + + testapp + diff --git a/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+ast+Latn+IT+AREVELA/strings.xml b/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+ast+Latn+IT+AREVELA/strings.xml new file mode 100644 index 00000000..8a56a54a --- /dev/null +++ b/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+ast+Latn+IT+AREVELA/strings.xml @@ -0,0 +1,4 @@ + + + testapp + diff --git a/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+de+CH+1901/strings.xml b/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+de+CH+1901/strings.xml new file mode 100644 index 00000000..8a56a54a --- /dev/null +++ b/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+de+CH+1901/strings.xml @@ -0,0 +1,4 @@ + + + testapp + diff --git a/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+iw+660/strings.xml b/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+iw+660/strings.xml new file mode 100644 index 00000000..8a56a54a --- /dev/null +++ b/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-b+iw+660/strings.xml @@ -0,0 +1,4 @@ + + + testapp +