From 7389358a18f9fc5c8c0428d59f6f6581c41e7f43 Mon Sep 17 00:00:00 2001 From: REAndroid Date: Wed, 4 Jan 2023 10:51:58 -0500 Subject: [PATCH] fix XML encode errors --- .../lib/apk/ApkModuleXmlDecoder.java | 16 +++ .../java/com/reandroid/lib/apk/ApkUtil.java | 35 ++--- .../lib/apk/xmlencoder/EncodeMaterials.java | 10 ++ .../lib/apk/xmlencoder/EncodeUtil.java | 5 + .../lib/apk/xmlencoder/XMLEncodeSource.java | 4 +- .../lib/apk/xmlencoder/XMLFileEncoder.java | 38 +++++- .../lib/apk/xmlencoder/XMLValuesEncoder.java | 6 +- .../apk/xmlencoder/XMLValuesEncoderStyle.java | 2 +- .../lib/arsc/array/TypeBlockArray.java | 2 +- .../lib/arsc/chunk/xml/ResXmlElement.java | 6 + .../lib/arsc/decoder/ValueDecoder.java | 2 +- .../reandroid/lib/arsc/group/EntryGroup.java | 23 ++-- .../reandroid/lib/arsc/value/EntryBlock.java | 127 ++++++++++-------- .../arsc/value/attribute/AttributeBag.java | 3 + .../value/attribute/AttributeBagItem.java | 8 ++ .../com/reandroid/xml/XMLTextAttribute.java | 6 - .../com/reandroid/xml/parser/MXParser.java | 37 ++--- .../xml/parser/XmlPullParserException.java | 19 ++- 18 files changed, 220 insertions(+), 129 deletions(-) diff --git a/src/main/java/com/reandroid/lib/apk/ApkModuleXmlDecoder.java b/src/main/java/com/reandroid/lib/apk/ApkModuleXmlDecoder.java index 4d3e2fa..55da65a 100644 --- a/src/main/java/com/reandroid/lib/apk/ApkModuleXmlDecoder.java +++ b/src/main/java/com/reandroid/lib/apk/ApkModuleXmlDecoder.java @@ -42,9 +42,11 @@ import java.util.*; private final ApkModule apkModule; private final Map> decodedEntries; private XMLBagDecoder xmlBagDecoder; + private final Set mDecodedPaths; public ApkModuleXmlDecoder(ApkModule apkModule){ this.apkModule=apkModule; this.decodedEntries = new HashMap<>(); + this.mDecodedPaths = new HashSet<>(); } public void decodeTo(File outDir) throws IOException, XMLException { @@ -60,6 +62,8 @@ import java.util.*; decodeAndroidManifest(entryStore, outDir); + addDecodedPath(TableBlock.FILE_NAME); + logMessage("Decoding resource files ..."); List resFileList=apkModule.listResFiles(); for(ResFile resFile:resFileList){ @@ -76,6 +80,7 @@ import java.util.*; }else { decodeResRaw(outDir, resFile); } + addDecodedPath(resFile.getFilePath()); } private void decodeResRaw(File outDir, ResFile resFile) throws IOException { @@ -147,6 +152,7 @@ import java.util.*; int currentPackageId= manifestBlock.guessCurrentPackageId(); XMLDocument xmlDocument=manifestBlock.decodeToXml(entryStore, currentPackageId); xmlDocument.save(file, true); + addDecodedPath(AndroidManifestBlock.FILE_NAME); } private void addDecodedEntry(Collection entryBlockList){ for(EntryBlock entryBlock:entryBlockList){ @@ -245,7 +251,11 @@ import java.util.*; logMessage("Extracting root files"); File rootDir = new File(outDir, "root"); for(InputSource inputSource:apkModule.getApkArchive().listInputSources()){ + if(containsDecodedPath(inputSource.getAlias())){ + continue; + } extractRootFiles(rootDir, inputSource); + addDecodedPath(inputSource.getAlias()); } } private void extractRootFiles(File rootDir, InputSource inputSource) throws IOException { @@ -260,6 +270,12 @@ import java.util.*; inputSource.write(outputStream); outputStream.close(); } + private boolean containsDecodedPath(String path){ + return mDecodedPaths.contains(path); + } + private void addDecodedPath(String path){ + mDecodedPaths.add(path); + } private void logMessage(String msg) { APKLogger apkLogger=apkModule.getApkLogger(); diff --git a/src/main/java/com/reandroid/lib/apk/ApkUtil.java b/src/main/java/com/reandroid/lib/apk/ApkUtil.java index 6699e49..0f11bf2 100644 --- a/src/main/java/com/reandroid/lib/apk/ApkUtil.java +++ b/src/main/java/com/reandroid/lib/apk/ApkUtil.java @@ -49,7 +49,7 @@ public class ApkUtil { public static List recursiveFiles(File dir, String ext){ List results=new ArrayList<>(); if(dir.isFile()){ - if(ext==null || dir.getName().endsWith(ext)){ + if(hasExtension(dir, ext)){ results.add(dir); } return results; @@ -63,7 +63,7 @@ public class ApkUtil { } for(File file:files){ if(file.isFile()){ - if(ext!=null && !file.getName().endsWith(ext)){ + if(!hasExtension(file, ext)){ continue; } results.add(file); @@ -74,26 +74,7 @@ public class ApkUtil { return results; } public static List recursiveFiles(File dir){ - List results=new ArrayList<>(); - if(dir.isFile()){ - results.add(dir); - return results; - } - if(!dir.isDirectory()){ - return results; - } - File[] files=dir.listFiles(); - if(files==null){ - return results; - } - for(File file:files){ - if(file.isFile()){ - results.add(file); - continue; - } - results.addAll(recursiveFiles(file)); - } - return results; + return recursiveFiles(dir, null); } public static List listDirectories(File dir){ List results=new ArrayList<>(); @@ -116,7 +97,7 @@ public class ApkUtil { } for(File file:files){ if(file.isFile()){ - if(ext!=null && !file.getName().endsWith(ext)){ + if(!hasExtension(file, ext)){ continue; } results.add(file); @@ -124,6 +105,14 @@ public class ApkUtil { } return results; } + private static boolean hasExtension(File file, String ext){ + if(ext==null){ + return true; + } + String name=file.getName().toLowerCase(); + ext=ext.toLowerCase(); + return name.endsWith(ext); + } public static String toModuleName(File file){ String name=file.getName(); int i=name.lastIndexOf('.'); diff --git a/src/main/java/com/reandroid/lib/apk/xmlencoder/EncodeMaterials.java b/src/main/java/com/reandroid/lib/apk/xmlencoder/EncodeMaterials.java index 984c497..0d09041 100644 --- a/src/main/java/com/reandroid/lib/apk/xmlencoder/EncodeMaterials.java +++ b/src/main/java/com/reandroid/lib/apk/xmlencoder/EncodeMaterials.java @@ -39,6 +39,7 @@ private PackageBlock currentPackage; private final Set frameworkTables = new HashSet<>(); private APKLogger apkLogger; + private boolean mForceCreateNamespaces = true; public EncodeMaterials(){ } public SpecString getSpecString(String name){ @@ -278,6 +279,11 @@ } return null; } + + public EncodeMaterials setForceCreateNamespaces(boolean force) { + this.mForceCreateNamespaces = force; + return this; + } public EncodeMaterials setPackageIds(ResourceIds.Table.Package packageIds) { this.packageIds = packageIds; return this; @@ -302,6 +308,10 @@ public PackageBlock getCurrentPackage() { return currentPackage; } + public boolean isForceCreateNamespaces() { + return mForceCreateNamespaces; + } + public String getCurrentPackageName(){ return currentPackage.getName(); } diff --git a/src/main/java/com/reandroid/lib/apk/xmlencoder/EncodeUtil.java b/src/main/java/com/reandroid/lib/apk/xmlencoder/EncodeUtil.java index 3027cb7..6a46992 100644 --- a/src/main/java/com/reandroid/lib/apk/xmlencoder/EncodeUtil.java +++ b/src/main/java/com/reandroid/lib/apk/xmlencoder/EncodeUtil.java @@ -113,4 +113,9 @@ package com.reandroid.lib.apk.xmlencoder; } public static final String NULL_PACKAGE_NAME = "NULL_PACKAGE_NAME"; private static final Pattern PATTERN_TYPE=Pattern.compile("^([a-z]+)[^a-z]*.*$"); + + public static final String URI_ANDROID = "http://schemas.android.com/apk/res/android"; + public static final String URI_APP = "http://schemas.android.com/apk/res-auto"; + public static final String PREFIX_ANDROID = "android"; + public static final String PREFIX_APP = "app"; } diff --git a/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLEncodeSource.java b/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLEncodeSource.java index ad73bc1..5e6f071 100644 --- a/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLEncodeSource.java +++ b/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLEncodeSource.java @@ -63,10 +63,12 @@ public class XMLEncodeSource extends ByteInputSource { } try { XMLFileEncoder xmlFileEncoder=new XMLFileEncoder(encodeMaterials); + xmlFileEncoder.setCurrentPath(xmlSource.getPath()); encodeMaterials.logVerbose("Encoding xml: "+xmlSource.getPath()); resXmlBlock = xmlFileEncoder.encode(xmlSource.getXMLDocument()); } catch (XMLException ex) { - throw new IOException(ex.getMessage(), ex); + throw new EncodeException("XMLException on: '"+xmlSource.getPath() + +"'\n '"+ex.getMessage()+"'"); } return resXmlBlock; } diff --git a/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLFileEncoder.java b/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLFileEncoder.java index ddba2ac..4013df2 100644 --- a/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLFileEncoder.java +++ b/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLFileEncoder.java @@ -30,9 +30,15 @@ import java.io.InputStream; public class XMLFileEncoder { private final EncodeMaterials materials; private ResXmlBlock resXmlBlock; + private String mCurrentPath; public XMLFileEncoder(EncodeMaterials materials){ this.materials=materials; } + + // Just for logging purpose + public void setCurrentPath(String path) { + this.mCurrentPath = path; + } public ResXmlBlock encode(String xmlString){ try { return encode(XMLDocument.load(xmlString)); @@ -50,6 +56,7 @@ public class XMLFileEncoder { return null; } public ResXmlBlock encode(File xmlFile){ + setCurrentPath(xmlFile.getAbsolutePath()); try { return encode(XMLDocument.load(xmlFile)); } catch (XMLException ex) { @@ -100,6 +107,14 @@ public class XMLFileEncoder { String prefix=attribute.getNamePrefix(); if(prefix!=null){ ResXmlStartNamespace ns = resXmlElement.getStartNamespaceByPrefix(prefix); + if(ns==null){ + ns=forceCreateNamespace(resXmlElement, resourceId, prefix); + } + if(ns==null){ + throw new EncodeException("Namespace not found: " + +attribute.toString() + +", path="+mCurrentPath); + } xmlAttribute.setNamespaceReference(ns.getUriReference()); } @@ -125,15 +140,14 @@ public class XMLFileEncoder { xmlAttribute.setRawValue(encodeResult.value); continue; } - if(attributeBag.contains(AttributeValueType.STRING)) { + if(attributeBag.isEqualType(AttributeValueType.STRING)) { xmlAttribute.setValueAsString(valueText); continue; } } if(EncodeUtil.isEmpty(valueText)) { - xmlAttribute.setValueType(ValueType.NULL); - xmlAttribute.setRawValue(0); + xmlAttribute.setValueAsString(""); }else{ ValueDecoder.EncodeResult encodeResult = ValueDecoder.encodeGuessAny(valueText); @@ -145,6 +159,7 @@ public class XMLFileEncoder { } } } + resXmlElement.calculatePositions(); } private void ensureNamespaces(XMLElement element, ResXmlElement resXmlElement){ int count=element.getAttributeCount(); @@ -181,4 +196,21 @@ public class XMLFileEncoder { idBuilder.add(entryBlock.getResourceId(), entryBlock.getName()); } } + private ResXmlStartNamespace forceCreateNamespace(ResXmlElement resXmlElement, + int resourceId, String prefix){ + if(!materials.isForceCreateNamespaces()){ + return null; + } + int pkgId = (resourceId>>24) & 0xff; + String uri; + if(pkgId==materials.getCurrentPackageId()){ + uri=EncodeUtil.URI_APP; + }else { + uri=EncodeUtil.URI_ANDROID; + } + ResXmlElement root=resXmlElement.getRootResXmlElement(); + ResXmlStartNamespace ns=root.getOrCreateNamespace(uri, prefix); + materials.logMessage("Force created ns: "+prefix+":"+uri); + return ns; + } } diff --git a/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLValuesEncoder.java b/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLValuesEncoder.java index c2a3919..16fb738 100644 --- a/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLValuesEncoder.java +++ b/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLValuesEncoder.java @@ -52,10 +52,8 @@ class XMLValuesEncoder { encodeValue(entryBlock, element); - if(!entryBlock.isNull()){ - SpecString specString = getMaterials().getSpecString(name); - entryBlock.setSpecReference(specString); - } + SpecString specString = getMaterials().getSpecString(name); + entryBlock.setSpecReference(specString); } void encodeValue(EntryBlock entryBlock, XMLElement element){ String value = getValue(element); diff --git a/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLValuesEncoderStyle.java b/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLValuesEncoderStyle.java index 391ccd1..2becc91 100644 --- a/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLValuesEncoderStyle.java +++ b/src/main/java/com/reandroid/lib/apk/xmlencoder/XMLValuesEncoderStyle.java @@ -65,7 +65,7 @@ class XMLValuesEncoderStyle extends XMLValuesEncoderBag{ bagItem.setType(ValueType.REFERENCE); } bagItem.setData(getMaterials().resolveReference(valueText)); - }else if(attributeBag.contains(AttributeValueType.STRING)) { + }else if(attributeBag.isEqualType(AttributeValueType.STRING)) { bagItem.setValueAsString(valueText); }else if(EncodeUtil.isEmpty(valueText)) { bagItem.setTypeAndData(ValueType.NULL, 0); diff --git a/src/main/java/com/reandroid/lib/arsc/array/TypeBlockArray.java b/src/main/java/com/reandroid/lib/arsc/array/TypeBlockArray.java index 1bf7260..f5781e1 100755 --- a/src/main/java/com/reandroid/lib/arsc/array/TypeBlockArray.java +++ b/src/main/java/com/reandroid/lib/arsc/array/TypeBlockArray.java @@ -247,7 +247,7 @@ public class TypeBlockArray extends BlockArray public int getHighestEntryCount(){ int result=0; for(TypeBlock typeBlock:getChildes()){ - int count=typeBlock.getEntryCount(); + int count=typeBlock.getEntryBlockArray().childesCount(); if(count>result){ result=count; } diff --git a/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlElement.java b/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlElement.java index 85c3ba9..60ed283 100755 --- a/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlElement.java +++ b/src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlElement.java @@ -60,6 +60,12 @@ import java.util.*; addChild(4, mEndElementContainer); addChild(5, mEndNamespaceList); } + public void calculatePositions(){ + ResXmlStartElement start = getStartElement(); + if(start!=null){ + start.calculatePositions(); + } + } public ResXmlAttribute newAttribute(){ return getStartElement().newAttribute(); } diff --git a/src/main/java/com/reandroid/lib/arsc/decoder/ValueDecoder.java b/src/main/java/com/reandroid/lib/arsc/decoder/ValueDecoder.java index 5b7333a..eba9aed 100755 --- a/src/main/java/com/reandroid/lib/arsc/decoder/ValueDecoder.java +++ b/src/main/java/com/reandroid/lib/arsc/decoder/ValueDecoder.java @@ -123,7 +123,7 @@ import java.util.regex.Pattern; return new EncodeResult(ValueType.INT_HEX, parseHex(numString)); } if(isInteger(numString)){ - return new EncodeResult(ValueType.INT_DEC, parseHex(numString)); + return new EncodeResult(ValueType.INT_DEC, parseInteger(numString)); } return null; } diff --git a/src/main/java/com/reandroid/lib/arsc/group/EntryGroup.java b/src/main/java/com/reandroid/lib/arsc/group/EntryGroup.java index bb936f4..7fe05ad 100755 --- a/src/main/java/com/reandroid/lib/arsc/group/EntryGroup.java +++ b/src/main/java/com/reandroid/lib/arsc/group/EntryGroup.java @@ -75,7 +75,7 @@ public class EntryGroup extends ItemGroup { } boolean renameOk=false; for(EntryBlock block:items){ - if(block==null||block.isNull()){ + if(block==null){ continue; } if(block.getSpecReference()==specReference){ @@ -87,15 +87,22 @@ public class EntryGroup extends ItemGroup { return renameOk; } public EntryBlock pickOne(){ - EntryBlock defEntryBlock=getDefault(); - if(defEntryBlock!=null){ - return defEntryBlock; + EntryBlock[] items=getItems(); + if(items==null){ + return null; } - Iterator itr=iterator(true); - while (itr.hasNext()){ - return itr.next(); + EntryBlock result = null; + for(EntryBlock entryBlock:items){ + if(entryBlock==null){ + continue; + } + if(result==null || result.isNull()){ + result=entryBlock; + }else if(entryBlock.isDefault()){ + return entryBlock; + } } - return null; + return result; } public EntryBlock getDefault(){ Iterator itr=iterator(true); diff --git a/src/main/java/com/reandroid/lib/arsc/value/EntryBlock.java b/src/main/java/com/reandroid/lib/arsc/value/EntryBlock.java index 5e2ecde..c8a982e 100755 --- a/src/main/java/com/reandroid/lib/arsc/value/EntryBlock.java +++ b/src/main/java/com/reandroid/lib/arsc/value/EntryBlock.java @@ -278,28 +278,45 @@ public class EntryBlock extends Block implements JSONConvert { private void setByteFlagsB(byte b){ mByteFlagsB.set(b); } - public IntegerItem getSpecReferenceBlock(){ + private IntegerItem getSpecReferenceBlock(){ return mSpecReference; } public int getSpecReference(){ + if(mSpecReference==null){ + return -1; + } return mSpecReference.get(); } public void setSpecReference(int ref){ - if(mSpecReference==null){ - return; - } + boolean created = createNullSpecReference(); int old=mSpecReference.get(); if(ref==old){ return; } mSpecReference.set(ref); updateSpecRef(old, ref); + if(created){ + updatePackage(); + } } public void setSpecReference(SpecString specString){ removeSpecRef(); - if(mSpecReference!=null){ - mSpecReference.set(specString.getIndex()); + if(specString==null){ + return; } + boolean created = createNullSpecReference(); + mSpecReference.set(specString.getIndex()); + if(created){ + updatePackage(); + } + } + private boolean createNullSpecReference(){ + if(mSpecReference==null){ + mSpecReference = new IntegerItem(); + mSpecReference.setNull(true); + return true; + } + return false; } public BaseResValue getResValue(){ return mResValue; @@ -352,6 +369,13 @@ public class EntryBlock extends Block implements JSONConvert { } return specString.get(); } + public String getNameOrHex(){ + String name = getName(); + if(name==null){ + name = String.format("@0x%08x", getResourceId()); + } + return name; + } private void setName(String name){ PackageBlock packageBlock=getPackageBlock(); EntryGroup entryGroup = packageBlock.getEntryGroup(getResourceId()); @@ -378,6 +402,9 @@ public class EntryBlock extends Block implements JSONConvert { return packageBlock.getName(); } public SpecString getSpecString(){ + if(mSpecReference==null){ + return null; + } PackageBlock packageBlock=getPackageBlock(); if(packageBlock==null){ return null; @@ -486,7 +513,11 @@ public class EntryBlock extends Block implements JSONConvert { this.mHeaderSize =new ShortItem(); this.mFlagEntryType =new ByteItem(); this.mByteFlagsB=new ByteItem(); - this.mSpecReference = new IntegerItem(); + if(mSpecReference==null){ + this.mSpecReference = new IntegerItem(); + }else if(mSpecReference.isNull()){ + mSpecReference.setNull(false); + } mHeaderSize.setIndex(0); mFlagEntryType.setIndex(1); @@ -625,11 +656,7 @@ public class EntryBlock extends Block implements JSONConvert { updateSpecRef(-1, getSpecReference()); } private void updateSpecRef(int oldRef, int newNef){ - TypeBlock typeBlock=getTypeBlock(); - if(typeBlock==null){ - return; - } - PackageBlock packageBlock=typeBlock.getPackageBlock(); + PackageBlock packageBlock=getPackageBlock(); if(packageBlock==null){ return; } @@ -647,11 +674,7 @@ public class EntryBlock extends Block implements JSONConvert { if(mSpecReference==null){ return; } - TypeBlock typeBlock=getTypeBlock(); - if(typeBlock==null){ - return; - } - PackageBlock packageBlock=typeBlock.getPackageBlock(); + PackageBlock packageBlock=getPackageBlock(); if(packageBlock==null){ return; } @@ -662,11 +685,7 @@ public class EntryBlock extends Block implements JSONConvert { } } private void updatePackage(){ - TypeBlock typeBlock=getTypeBlock(); - if(typeBlock==null){ - return; - } - PackageBlock packageBlock=typeBlock.getPackageBlock(); + PackageBlock packageBlock=getPackageBlock(); if(packageBlock==null){ return; } @@ -761,37 +780,6 @@ public class EntryBlock extends Block implements JSONConvert { } return new ResValueInt(); } - @Override - public String toString(){ - StringBuilder builder=new StringBuilder(); - builder.append(getClass().getSimpleName()); - builder.append(": "); - ResConfig resConfig=getResConfig(); - if(resConfig!=null){ - builder.append(resConfig.toString()); - builder.append(", "); - } - builder.append(" resId="); - builder.append(String.format("0x%08x", getResourceId())); - if(isNull()){ - builder.append(", null entry"); - return builder.toString(); - } - String name=getResourceName(); - if(name!=null){ - builder.append('('); - builder.append(name); - builder.append(')'); - } - BaseResValue baseResValue=getResValue(); - if(baseResValue instanceof ResValueInt){ - ResValueInt resValueInt=(ResValueInt)baseResValue; - builder.append(" '"); - builder.append(resValueInt.toString()); - builder.append(" '"); - } - return builder.toString(); - } public static String buildResourceName(char prefix, String packageName, String type, String name){ if(name==null){ return null; @@ -811,6 +799,39 @@ public class EntryBlock extends Block implements JSONConvert { builder.append(name); return builder.toString(); } + @Override + public String toString(){ + StringBuilder builder=new StringBuilder(); + builder.append(getClass().getSimpleName()); + builder.append(": "); + ResConfig resConfig=getResConfig(); + if(resConfig!=null){ + builder.append(resConfig.toString()); + builder.append(", "); + } + String name=getResourceName(); + if(name==null){ + name=getNameOrHex(); + }else{ + builder.append(" id="); + builder.append(String.format("0x%08x", getResourceId())); + } + builder.append('('); + builder.append(name); + builder.append(')'); + if(isNull()){ + builder.append(", null entry"); + return builder.toString(); + } + BaseResValue baseResValue=getResValue(); + if(baseResValue instanceof ResValueInt){ + ResValueInt resValueInt=(ResValueInt)baseResValue; + builder.append(" '"); + builder.append(resValueInt.toString()); + builder.append(" '"); + } + return builder.toString(); + } private final static short HEADER_SIZE_BAG = 0x0010; private final static short HEADER_SIZE_INT = 0x0008; diff --git a/src/main/java/com/reandroid/lib/arsc/value/attribute/AttributeBag.java b/src/main/java/com/reandroid/lib/arsc/value/attribute/AttributeBag.java index 35c8107..0980f2e 100755 --- a/src/main/java/com/reandroid/lib/arsc/value/attribute/AttributeBag.java +++ b/src/main/java/com/reandroid/lib/arsc/value/attribute/AttributeBag.java @@ -31,6 +31,9 @@ public class AttributeBag { public boolean contains(AttributeValueType valueType){ return getFormat().contains(valueType); } + public boolean isEqualType(AttributeValueType valueType){ + return getFormat().isEqualType(valueType); + } public ValueDecoder.EncodeResult encodeEnumOrFlagValue(String valueString){ if(valueString==null || !isEnumOrFlag()){ return null; diff --git a/src/main/java/com/reandroid/lib/arsc/value/attribute/AttributeBagItem.java b/src/main/java/com/reandroid/lib/arsc/value/attribute/AttributeBagItem.java index 38d6fc1..95d555a 100755 --- a/src/main/java/com/reandroid/lib/arsc/value/attribute/AttributeBagItem.java +++ b/src/main/java/com/reandroid/lib/arsc/value/attribute/AttributeBagItem.java @@ -92,6 +92,14 @@ public class AttributeBagItem { int dataLow = 0xffff & getBagItem().getDataLow(); return (dataLow & value) == value; } + public boolean isEqualType(AttributeValueType valueType){ + if(valueType == null || getItemType()!=AttributeItemType.FORMAT){ + return false; + } + int value = 0xff & valueType.getByte(); + int dataLow = 0xffff & getBagItem().getDataLow(); + return (dataLow == value); + } public AttributeValueType[] getValueTypes(){ AttributeItemType type=getItemType(); if(type!=AttributeItemType.FORMAT){ diff --git a/src/main/java/com/reandroid/xml/XMLTextAttribute.java b/src/main/java/com/reandroid/xml/XMLTextAttribute.java index 8bef741..da45d78 100755 --- a/src/main/java/com/reandroid/xml/XMLTextAttribute.java +++ b/src/main/java/com/reandroid/xml/XMLTextAttribute.java @@ -33,12 +33,6 @@ public class XMLTextAttribute extends XMLAttribute { if(unEscape){ return XMLUtil.unEscapeXmlChars(mText); } - if(mText!=null){ - String junk= XMLUtil.unEscapeXmlChars(mText); - if(!mText.equals(junk)){ - junk.trim(); - } - } return mText; } @Override diff --git a/src/main/java/com/reandroid/xml/parser/MXParser.java b/src/main/java/com/reandroid/xml/parser/MXParser.java index 451125d..5b1ad6c 100644 --- a/src/main/java/com/reandroid/xml/parser/MXParser.java +++ b/src/main/java/com/reandroid/xml/parser/MXParser.java @@ -530,30 +530,17 @@ public class MXParser implements XmlPullParser } return i; } - public String getPositionDescription () + @Override + public String getPositionDescription() { - String fragment = null; - if(posStart <= pos) { - final int start = findFragment(0, buf, posStart, pos); - - if(start < pos) { - fragment = new String(buf, start, pos - start); - } - if(bufAbsoluteStart > 0 || start > 0) { - fragment = "..." + fragment; - } - } - return " "+TYPES[ eventType ] + - (fragment != null ? " seen "+printable(fragment)+"..." : "") - +" "+(location != null ? location : "") - +"@"+getLineNumber()+":"+getColumnNumber(); + return "line="+getLineNumber()+", col="+getColumnNumber(); } - + @Override public int getLineNumber() { return lineNumber; } - + @Override public int getColumnNumber() { return columnNumber; @@ -740,11 +727,13 @@ public class MXParser implements XmlPullParser return attributeValue[ index ]; } - public String getAttributeValue(String namespace, - String name) + @Override + public String getAttributeValue(String namespace, String name) { - if(eventType != START_TAG) throw new IndexOutOfBoundsException( - "only START_TAG can have attributes"+getPositionDescription()); + if(eventType != START_TAG) { + throw new IndexOutOfBoundsException("only START_TAG can have attributes " + +getPositionDescription()); + } if(name == null) { throw new IllegalArgumentException("attribute name can not be null"); } @@ -1651,7 +1640,7 @@ public class MXParser implements XmlPullParser } // skip additional spaces if(ch != '=') { throw new XmlPullParserException( - "expected = after attribute name", this, null); + "expected = after attribute name '"+name+processNamespaces+"'", this, null); } ch = more(); while(isS(ch)) { @@ -2689,7 +2678,7 @@ public class MXParser implements XmlPullParser return (ch < LOOKUP_MAX_CHAR && lookupNameChar[ ch ]) || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027') || (ch >= '\u202A' && ch <= '\u218F') - || (ch >= '\u2800' && ch <= '\uFFEF'); + || (ch >= '\u2800' && ch <= '\uFFEF') || ch=='@'; } protected boolean isS(char ch) { diff --git a/src/main/java/com/reandroid/xml/parser/XmlPullParserException.java b/src/main/java/com/reandroid/xml/parser/XmlPullParserException.java index 11a27a3..1e9a48b 100644 --- a/src/main/java/com/reandroid/xml/parser/XmlPullParserException.java +++ b/src/main/java/com/reandroid/xml/parser/XmlPullParserException.java @@ -17,10 +17,7 @@ public class XmlPullParserException extends Exception { super(s); } public XmlPullParserException(String msg, XmlPullParser parser, Throwable chain) { - super ((msg == null ? "" : msg+" ") - + (parser == null ? "" : "(position:"+parser.getPositionDescription()+") ") - + (chain == null ? "" : "caused by: "+chain)); - + super(buildMessage(msg, parser)); if (parser != null) { this.row = parser.getLineNumber(); this.column = parser.getColumnNumber(); @@ -30,5 +27,19 @@ public class XmlPullParserException extends Exception { public Throwable getDetail() { return detail; } public int getLineNumber() { return row; } public int getColumnNumber() { return column; } + private static String buildMessage(String msg, XmlPullParser parser){ + StringBuilder builder=new StringBuilder(); + if(parser!=null){ + builder.append("[line="); + builder.append(parser.getLineNumber()); + builder.append(", col="); + builder.append(parser.getColumnNumber()); + builder.append("] "); + } + if(msg!=null){ + builder.append(msg); + } + return builder.toString(); + } }