diff --git a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java index faf8667a2..c2a1624be 100755 --- a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java +++ b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java @@ -722,7 +722,11 @@ public ResourceEntry encodeAttributeName(String uri, String prefix, String name) setName(name, 0); return null; } - ResourceEntry resourceEntry = super.encodeAttrName(prefix, name); + String lookupPrefix = prefix; + if (Namespace.URI_ANDROID.equals(uri)) { + lookupPrefix = Namespace.PREFIX_ANDROID; + } + ResourceEntry resourceEntry = super.encodeAttrName(lookupPrefix, name); if (resourceEntry != null) { return resourceEntry; } diff --git a/src/test/java/com/reandroid/arsc/chunk/xml/Pr111NamespaceRegressionTest.java b/src/test/java/com/reandroid/arsc/chunk/xml/Pr111NamespaceRegressionTest.java new file mode 100644 index 000000000..7ebf63ba2 --- /dev/null +++ b/src/test/java/com/reandroid/arsc/chunk/xml/Pr111NamespaceRegressionTest.java @@ -0,0 +1,79 @@ +package com.reandroid.arsc.chunk.xml; + +import com.reandroid.apk.AndroidFrameworks; +import com.reandroid.apk.ApkModule; +import com.reandroid.arsc.chunk.TableBlock; +import com.reandroid.xml.XMLFactory; +import org.junit.Assert; +import org.junit.Test; + +public class Pr111NamespaceRegressionTest { + + private ResXmlDocument parse(String xml) throws Exception { + TableBlock table = new TableBlock(); + table.addFramework( + AndroidFrameworks.getLatest().getTableBlock()); + table.refresh(); + + ApkModule apk = new ApkModule(); + apk.setTableBlock(table); + + ResXmlDocument doc = new ResXmlDocument(); + doc.setApkFile(apk); + doc.parse(XMLFactory.newPullParser(xml)); + return doc; + } + + @Test + public void standardAndroidPrefix() throws Exception { + ResXmlDocument doc = parse( + ""); + + ResXmlAttribute attr = doc.getDocumentElement() + .searchAttributeByName("versionCode"); + + Assert.assertNotNull(attr); + Assert.assertEquals("android", attr.getPrefix()); + Assert.assertTrue(attr.getNameId() != 0); + Assert.assertEquals(123, attr.getData()); + } + + @Test + public void alternateAndroidPrefix() throws Exception { + ResXmlDocument doc = parse( + ""); + + ResXmlAttribute attr = doc.getDocumentElement() + .searchAttributeByName("versionCode"); + + Assert.assertNotNull(attr); + Assert.assertEquals( + "http://schemas.android.com/apk/res/android", + attr.getUri()); + // Prefix may be normalized internally. + // Verify namespace URI, resource ID and value instead. + Assert.assertTrue(attr.getNameId() != 0); + Assert.assertEquals(456, attr.getData()); + } + + @Test + public void externalNamespaceMustNotBecomeAndroid() + throws Exception { + ResXmlDocument doc = parse( + ""); + + ResXmlAttribute attr = doc.getDocumentElement() + .searchAttributeByName("versionCode"); + + Assert.assertNotNull(attr); + Assert.assertEquals( + "https://example.com/custom", + attr.getUri()); + Assert.assertEquals(0, attr.getNameId()); + } +} diff --git a/src/test/java/com/reandroid/arsc/chunk/xml/ResXmlDocumentTest.java b/src/test/java/com/reandroid/arsc/chunk/xml/ResXmlDocumentTest.java index bfa2aa710..854370eaf 100644 --- a/src/test/java/com/reandroid/arsc/chunk/xml/ResXmlDocumentTest.java +++ b/src/test/java/com/reandroid/arsc/chunk/xml/ResXmlDocumentTest.java @@ -142,6 +142,83 @@ public void testEncodeDecodeXml() throws XmlPullParserException, IOException { decoded = decoded.replaceAll("\\s+", ""); Assert.assertEquals(org, decoded); } + + @Test + public void testIssue202AlternateAndroidNamespace() + throws Exception { + + String xml = + "" + + "" + + ""; + + ResXmlDocument document = new ResXmlDocument(); + document.setApkFile(createEmptyApkModule()); + document.parse(XMLFactory.newPullParser(xml)); + + ResXmlElement root = document.getDocumentElement(); + Assert.assertNotNull(root); + + ResXmlAttribute version = + root.searchAttributeByName("versionCode"); + Assert.assertNotNull(version); + Assert.assertEquals("http://schemas.android.com/apk/res/android", version.getUri()); + + ResXmlElement sdk = root.getElement("uses-sdk"); + Assert.assertNotNull(sdk); + Assert.assertNotNull( + sdk.searchAttributeByName("targetSdkVersion")); + + document.refreshFull(); + + StringWriter writer = new StringWriter(); + XmlSerializer serializer = XMLFactory.newSerializer(writer); + document.serialize(serializer); + + String output = writer.toString(); + Assert.assertTrue(output.contains("733700004")); + Assert.assertTrue(output.contains("137.0.7337.0")); + } + + + @Test + public void testIssue202JsonNamespaceRoundTrip() + throws Exception { + + String xml = + ""; + + ResXmlDocument original = new ResXmlDocument(); + original.setApkFile(createEmptyApkModule()); + original.parse(XMLFactory.newPullParser(xml)); + + com.reandroid.json.JSONObject json = original.toJson(); + + ResXmlDocument restored = new ResXmlDocument(); + restored.setApkFile(createEmptyApkModule()); + restored.fromJson(json); + + ResXmlElement root = restored.getDocumentElement(); + Assert.assertNotNull(root); + + ResXmlAttribute version = + root.searchAttributeByName("versionCode"); + + Assert.assertNotNull(version); + Assert.assertEquals( + "http://schemas.android.com/apk/res/android", + version.getUri()); + Assert.assertEquals(733700004, version.getData()); + } + private static ApkModule createEmptyApkModule() throws IOException { ApkModule apkModule = new ApkModule(); apkModule.setTableBlock(createEmptyTable());