diff --git a/src/main/java/com/reandroid/apk/xmldecoder/XMLCommonBagDecoder.java b/src/main/java/com/reandroid/apk/xmldecoder/XMLCommonBagDecoder.java index 874104a3c..ad58bb57e 100644 --- a/src/main/java/com/reandroid/apk/xmldecoder/XMLCommonBagDecoder.java +++ b/src/main/java/com/reandroid/apk/xmldecoder/XMLCommonBagDecoder.java @@ -51,7 +51,6 @@ public void decode(ResTableMapEntry mapEntry, XMLElement parentElement) { EntryStore entryStore = getEntryStore(); for(int i=0;i< bagItems.length;i++){ ResValueMap item=bagItems[i]; - int resourceId=item.getName(); XMLElement child=new XMLElement("item"); String name = ValueDecoder.decodeAttributeName( entryStore, currentPackage, item.getName()); @@ -63,7 +62,7 @@ public void decode(ResTableMapEntry mapEntry, XMLElement parentElement) { XmlHelper.setTextContent(child, item.getDataAsPoolString()); }else { String value = ValueDecoder.decode(entryStore, currentPackageId, - resourceId, item.getValueType(), item.getData()); + item); child.setTextContent(value); } parentElement.addChild(child); 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 d5bacdc1c..4d2970d75 100755 --- a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java +++ b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java @@ -416,16 +416,7 @@ public XMLAttribute decodeToXml(EntryStore entryStore, int currentPackageId) thr } ValueType valueType = getValueType(); int raw = getData(); - String value; - if(valueType==ValueType.STRING){ - value = ValueDecoder.escapeSpecialCharacter(getValueAsString()); - }else { - value = ValueDecoder.decode(entryStore, - currentPackageId, - resourceId, - valueType, - raw); - } + String value = ValueDecoder.decode(entryStore, currentPackageId, (AttributeValue) this); XMLAttribute attribute = new XMLAttribute(name, value); attribute.setNameId(resourceId); if(valueType==ValueType.REFERENCE||valueType==ValueType.ATTRIBUTE){ diff --git a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlDocument.java b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlDocument.java index 12ae9f8d7..b6c7cb93c 100755 --- a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlDocument.java +++ b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlDocument.java @@ -356,6 +356,14 @@ private Set recursiveStrings(JSONObject elementJson){ } return results; } + void addEvents(ParserEventList parserEventList){ + ResXmlElement xmlElement = getResXmlElement(); + parserEventList.add(new ParserEvent(ParserEvent.START_DOCUMENT, xmlElement)); + if(xmlElement!=null){ + xmlElement.addEvents(parserEventList); + } + parserEventList.add(new ParserEvent(ParserEvent.END_DOCUMENT, xmlElement)); + } public static boolean isResXmlBlock(File file){ if(file==null){ diff --git a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlElement.java b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlElement.java index f1bcc1531..673775994 100755 --- a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlElement.java +++ b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlElement.java @@ -103,9 +103,33 @@ public void setAttributesUnitSize(int size, boolean setToAll){ } } } - @Override - public String getComment(){ - return getStartElement().getComment(); + public String getStartComment(){ + ResXmlStartElement start = getStartElement(); + if(start!=null){ + return start.getComment(); + } + return null; + } + public String getEndComment(){ + ResXmlEndElement end = getEndElement(); + if(end!=null){ + return end.getComment(); + } + return null; + } + public int getStartLineNumber(){ + ResXmlStartElement start = getStartElement(); + if(start!=null){ + return start.getLineNumber(); + } + return 0; + } + public int getEndLineNumber(){ + ResXmlEndElement end = getEndElement(); + if(end!=null){ + return end.getLineNumber(); + } + return 0; } public void setComment(String comment){ getStartElement().setComment(comment); @@ -338,6 +362,24 @@ public int getDepth(){ } return depth; } + @Override + void addEvents(ParserEventList parserEventList){ + String comment = getStartComment(); + if(comment!=null){ + parserEventList.add( + new ParserEvent(ParserEvent.COMMENT, this, comment, false)); + } + parserEventList.add(new ParserEvent(ParserEvent.START_TAG, this)); + for(ResXmlNode xmlNode:getXmlNodes()){ + xmlNode.addEvents(parserEventList); + } + comment = getEndComment(); + if(comment!=null){ + parserEventList.add( + new ParserEvent(ParserEvent.COMMENT, this, comment, true)); + } + parserEventList.add(new ParserEvent(ParserEvent.END_TAG, this)); + } public int getLevel(){ return mLevel; } @@ -908,7 +950,11 @@ public XMLElement decodeToXml(EntryStore entryStore, int currentPackageId) throw resXmlAttribute.decodeToXml(entryStore, currentPackageId); xmlElement.addAttribute(xmlAttribute); } - String comment=getComment(); + String comment=getStartComment(); + if(comment!=null){ + xmlElement.addComment(new XMLComment(comment)); + } + comment=getEndComment(); if(comment!=null){ xmlElement.addComment(new XMLComment(comment)); } diff --git a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlNode.java b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlNode.java index 458ba0444..e402f0073 100644 --- a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlNode.java +++ b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlNode.java @@ -25,8 +25,8 @@ public abstract class ResXmlNode extends FixedBlockContainer implements JSONCon } void onRemove(){ } - public abstract String getComment(); public abstract int getDepth(); + abstract void addEvents(ParserEventList parserEventList); public static final String NAME_node_type="node_type"; } diff --git a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlPullParser.java b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlPullParser.java index bfd54d9f9..475335f94 100644 --- a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlPullParser.java +++ b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlPullParser.java @@ -16,6 +16,7 @@ package com.reandroid.arsc.chunk.xml; import android.content.res.XmlResourceParser; +import com.reandroid.arsc.decoder.Decoder; import com.reandroid.arsc.value.ValueType; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; @@ -27,11 +28,10 @@ import java.util.Objects; public class ResXmlPullParser implements XmlResourceParser { + private Decoder mDecoder; + private final ParserEventList mEventList = new ParserEventList(); private ResXmlDocument mDocument; private boolean mDocumentCreatedHere; - private ResXmlElement mCurrentElement; - private ResXmlTextNode mCurrentText; - private int mEvent = -1; public ResXmlPullParser(){ @@ -40,15 +40,28 @@ public ResXmlPullParser(){ public void setResXmlDocument(ResXmlDocument xmlDocument){ closeDocument(); this.mDocument = xmlDocument; + initializeDecoder(xmlDocument); + xmlDocument.addEvents(mEventList); } public ResXmlDocument getResXmlDocument() { return mDocument; } + public void setDecoder(Decoder decoder) { + this.mDecoder = decoder; + } + public Decoder getDecoder(){ + return mDecoder; + } + private void initializeDecoder(ResXmlDocument xmlDocument){ + if(mDecoder!=null){ + return; + } + mDecoder = Decoder.create(xmlDocument); + } + public void closeDocument(){ - mCurrentElement = null; - mCurrentText = null; - mEvent = -1; + mEventList.clear(); destroyDocument(); } private void destroyDocument(){ @@ -69,31 +82,23 @@ public void close(){ } @Override public int getAttributeCount() { - return mCurrentElement.getAttributeCount(); + ResXmlElement element = getCurrentElement(); + if(element!=null){ + return element.getAttributeCount(); + } + return 0; } @Override public String getAttributeName(int index) { - ResXmlAttribute xmlAttribute = mCurrentElement.getAttributeAt(index); - if(xmlAttribute!=null){ - return xmlAttribute.getName(); - } - return null; + return decodeAttributeName(getResXmlAttributeAt(index)); } @Override public String getAttributeValue(int index) { - ResXmlAttribute xmlAttribute = geResXmlAttributeAt(index); - if(xmlAttribute!=null){ - return xmlAttribute.getValueString(); - } - return null; + return decodeAttributeValue(getResXmlAttributeAt(index)); } @Override public String getAttributeValue(String namespace, String name) { - ResXmlAttribute attribute = getAttribute(namespace, name); - if(attribute != null){ - return attribute.getValueString(); - } - return null; + return decodeAttributeValue(getAttribute(namespace, name)); } @Override public String getPositionDescription() { @@ -101,7 +106,7 @@ public String getPositionDescription() { } @Override public int getAttributeNameResource(int index) { - ResXmlAttribute attribute = geResXmlAttributeAt(index); + ResXmlAttribute attribute = getResXmlAttributeAt(index); if(attribute!=null){ return attribute.getNameResourceID(); } @@ -114,7 +119,7 @@ public int getAttributeListValue(String namespace, String attribute, String[] op return 0; } List list = Arrays.asList(options); - int index = list.indexOf(xmlAttribute.getValueString()); + int index = list.indexOf(decodeAttributeValue(xmlAttribute)); if(index==-1){ return defaultValue; } @@ -183,12 +188,12 @@ public float getAttributeFloatValue(String namespace, String attribute, float de @Override public int getAttributeListValue(int index, String[] options, int defaultValue) { - ResXmlAttribute xmlAttribute = geResXmlAttributeAt(index); + ResXmlAttribute xmlAttribute = getResXmlAttributeAt(index); if(xmlAttribute == null){ return 0; } List list = Arrays.asList(options); - int i = list.indexOf(xmlAttribute.getValueString()); + int i = list.indexOf(decodeAttributeValue(xmlAttribute)); if(i==-1){ return defaultValue; } @@ -196,7 +201,7 @@ public int getAttributeListValue(int index, String[] options, int defaultValue) } @Override public boolean getAttributeBooleanValue(int index, boolean defaultValue) { - ResXmlAttribute xmlAttribute = geResXmlAttributeAt(index); + ResXmlAttribute xmlAttribute = getResXmlAttributeAt(index); if(xmlAttribute == null || xmlAttribute.getValueType() != ValueType.INT_BOOLEAN){ return defaultValue; } @@ -204,7 +209,7 @@ public boolean getAttributeBooleanValue(int index, boolean defaultValue) { } @Override public int getAttributeResourceValue(int index, int defaultValue) { - ResXmlAttribute xmlAttribute = geResXmlAttributeAt(index); + ResXmlAttribute xmlAttribute = getResXmlAttributeAt(index); if(xmlAttribute == null){ return 0; } @@ -219,32 +224,23 @@ public int getAttributeResourceValue(int index, int defaultValue) { } @Override public int getAttributeIntValue(int index, int defaultValue) { - ResXmlAttribute xmlAttribute = geResXmlAttributeAt(index); + ResXmlAttribute xmlAttribute = getResXmlAttributeAt(index); if(xmlAttribute == null){ - return 0; - } - ValueType valueType=xmlAttribute.getValueType(); - if(valueType==ValueType.INT_DEC - ||valueType==ValueType.INT_HEX){ - return xmlAttribute.getData(); + return defaultValue; } - return defaultValue; + return xmlAttribute.getData(); } @Override public int getAttributeUnsignedIntValue(int index, int defaultValue) { - ResXmlAttribute xmlAttribute = geResXmlAttributeAt(index); + ResXmlAttribute xmlAttribute = getResXmlAttributeAt(index); if(xmlAttribute == null){ return 0; } - ValueType valueType=xmlAttribute.getValueType(); - if(valueType==ValueType.INT_DEC){ - return xmlAttribute.getData(); - } - return defaultValue; + return xmlAttribute.getData(); } @Override public float getAttributeFloatValue(int index, float defaultValue) { - ResXmlAttribute xmlAttribute = geResXmlAttributeAt(index); + ResXmlAttribute xmlAttribute = getResXmlAttributeAt(index); if(xmlAttribute == null){ return 0; } @@ -337,7 +333,8 @@ public void setInput(InputStream inputStream, String inputEncoding) throws XmlPu } @Override public String getInputEncoding() { - return null; + // Not applicable but let not return null + return "UTF-8"; } @Override public void defineEntityReplacementText(String entityName, String replacementText) throws XmlPullParserException { @@ -355,7 +352,7 @@ public int getNamespaceCount(int depth) throws XmlPullParserException { } @Override public String getNamespacePrefix(int pos) throws XmlPullParserException { - ResXmlAttribute attribute = mCurrentElement.getAttributeAt(pos); + ResXmlAttribute attribute = getResXmlAttributeAt(pos); if(attribute!=null){ return attribute.getNamePrefix(); } @@ -363,7 +360,7 @@ public String getNamespacePrefix(int pos) throws XmlPullParserException { } @Override public String getNamespaceUri(int pos) throws XmlPullParserException { - ResXmlAttribute attribute = mCurrentElement.getAttributeAt(pos); + ResXmlAttribute attribute = getResXmlAttributeAt(pos); if(attribute!=null){ return attribute.getUri(); } @@ -371,44 +368,26 @@ public String getNamespaceUri(int pos) throws XmlPullParserException { } @Override public String getNamespace(String prefix) { - ResXmlStartNamespace startNamespace = mCurrentElement.getStartNamespaceByPrefix(prefix); - if(startNamespace!=null){ - return startNamespace.getUri(); + ResXmlElement element = getCurrentElement(); + if(element!=null){ + ResXmlStartNamespace startNamespace = element.getStartNamespaceByPrefix(prefix); + if(startNamespace!=null){ + return startNamespace.getUri(); + } } return null; } @Override public int getDepth() { - int event = mEvent; - if(event == START_TAG || event == END_TAG){ - return mCurrentElement.getDepth(); - } - if(event == TEXT){ - return mCurrentText.getDepth(); + int event = mEventList.getType(); + if(event == START_TAG || event == END_TAG || event == TEXT){ + return mEventList.getXmlNode().getDepth(); } return 0; } @Override public int getLineNumber() { - int event = mEvent; - if(event == START_TAG){ - ResXmlStartElement startElement = mCurrentElement.getStartElement(); - if(startElement!=null){ - return startElement.getLineNumber(); - } - return 0; - } - if(event == END_TAG){ - ResXmlEndElement endElement = mCurrentElement.getEndElement(); - if(endElement!=null){ - return endElement.getLineNumber(); - } - return 0; - } - if(event == TEXT){ - return mCurrentText.getLineNumber(); - } - return 0; + return mEventList.getLineNumber(); } @Override public int getColumnNumber() { @@ -416,18 +395,16 @@ public int getColumnNumber() { } @Override public boolean isWhitespace() throws XmlPullParserException { - return false; + String text = getText(); + if(text == null){ + return true; + } + text = text.trim(); + return text.length() == 0; } @Override public String getText() { - int event = mEvent; - if(event == TEXT){ - return mCurrentText.getText(); - } - if(event == START_TAG || event == END_TAG){ - return mCurrentElement.getTag(); - } - return null; + return mEventList.getText(); } @Override public char[] getTextCharacters(int[] holderForStartAndLength) { @@ -476,7 +453,7 @@ public boolean isEmptyElementTag() throws XmlPullParserException { } @Override public String getAttributeNamespace(int index) { - ResXmlAttribute attribute = geResXmlAttributeAt(index); + ResXmlAttribute attribute = getResXmlAttributeAt(index); if(attribute != null){ return attribute.getUri(); } @@ -484,7 +461,7 @@ public String getAttributeNamespace(int index) { } @Override public String getAttributePrefix(int index) { - ResXmlAttribute attribute = geResXmlAttributeAt(index); + ResXmlAttribute attribute = getResXmlAttributeAt(index); if(attribute != null){ return attribute.getNamePrefix(); } @@ -498,14 +475,30 @@ public String getAttributeType(int index) { public boolean isAttributeDefault(int index) { return false; } - private ResXmlAttribute geResXmlAttributeAt(int index){ + private String decodeAttributeName(ResXmlAttribute attribute){ + if(attribute==null){ + return null; + } + String name = mDecoder.decodeResourceName(attribute.getNameResourceID()); + if(name == null){ + name = attribute.getName(); + } + return name; + } + private String decodeAttributeValue(ResXmlAttribute attribute){ + if(attribute==null){ + return null; + } + return mDecoder.decodeAttributeValue(attribute); + } + public ResXmlAttribute getResXmlAttributeAt(int index){ ResXmlElement element = getCurrentElement(); if(element == null){ return null; } return element.getAttributeAt(index); } - private ResXmlAttribute getAttribute(String namespace, String name) { + public ResXmlAttribute getAttribute(String namespace, String name) { ResXmlElement element = getCurrentElement(); if(element == null){ return null; @@ -525,143 +518,21 @@ private ResXmlStartElement getResXmlStartElement(){ } return null; } - private ResXmlElement getCurrentElement() { - int event = mEvent; - if(event!=START_TAG && event!=END_TAG){ - return null; + public ResXmlElement getCurrentElement() { + int type = mEventList.getType(); + if(type==START_TAG||type==END_TAG){ + return mEventList.getElement(); } - return mCurrentElement; + return null; } @Override public int getEventType() throws XmlPullParserException { - return mEvent; + return mEventList.getType(); } @Override public int next() throws XmlPullParserException, IOException { - checkNotEnded(); - int event = calculateNextEvent(mEvent); - if(event == START_DOCUMENT){ - onStartDocument(); - }else if(event == END_DOCUMENT){ - onEndDocument(); - }else if(event == START_TAG){ - onStartTag(); - }else if(event == END_TAG){ - onEndTag(); - }else if(event == TEXT){ - onText(); - } - this.mEvent = event; - return event; - } - private void onEndTag() throws XmlPullParserException { - int previous = mEvent; - if(previous == END_TAG){ - mCurrentElement = mCurrentElement.getParentResXmlElement(); - } - mCurrentText = null; - } - private void onText() throws XmlPullParserException { - int previous = mEvent; - if(previous == END_TAG){ - int position = mCurrentElement.getIndex(); - ResXmlElement parent = mCurrentElement.getParentResXmlElement(); - position++; - mCurrentText = (ResXmlTextNode) parent.getResXmlNode(position); - mCurrentElement = parent; - }else if(previous == START_TAG){ - ResXmlElement parent = mCurrentElement; - mCurrentText = (ResXmlTextNode) parent.getResXmlNode(0); - }else if(previous == TEXT){ - int position = mCurrentText.getIndex(); - ResXmlElement parent = mCurrentElement; - position++; - mCurrentText = (ResXmlTextNode) parent.getResXmlNode(position); - mCurrentText = (ResXmlTextNode) parent.getResXmlNode(0); - }else { - throw new XmlPullParserException("Unknown state at onText() prev="+previous); - } - } - private void onStartTag() throws XmlPullParserException { - int previous = mEvent; - if(previous == START_DOCUMENT){ - mCurrentElement = mDocument.getResXmlElement(); - mCurrentText = null; - }else if(previous == END_TAG){ - int position = mCurrentElement.getIndex(); - ResXmlElement parent = mCurrentElement.getParentResXmlElement(); - position++; - mCurrentElement = (ResXmlElement) parent.getResXmlNode(position); - }else if(previous == TEXT){ - int position = mCurrentText.getIndex(); - ResXmlElement parent = mCurrentText.getResXmlText().getParentResXmlElement(); - position++; - mCurrentElement = (ResXmlElement) parent.getResXmlNode(position); - }else if(previous == START_TAG){ - mCurrentElement = (ResXmlElement) mCurrentElement.getResXmlNode(0); - }else { - throw new XmlPullParserException("Unknown state at onStartTag() prev="+previous); - } - mCurrentText = null; - - } - private void onStartDocument(){ - } - private void onEndDocument() throws XmlPullParserException { - mCurrentElement = null; - mCurrentText = null; - close(); - } - private void checkNotEnded() throws XmlPullParserException { - if(mEvent == END_DOCUMENT){ - throw new XmlPullParserException("Document reached to end"); - } - } - private int calculateNextEvent(int previous) throws XmlPullParserException { - if(previous < 0){ - if(mDocument == null){ - return previous; - } - return START_DOCUMENT; - } - if(previous == START_DOCUMENT){ - ResXmlElement element = mDocument.getResXmlElement(); - if(element==null){ - return END_DOCUMENT; - } - return START_TAG; - } - if(previous == END_DOCUMENT){ - return END_DOCUMENT; - } - if(previous == START_TAG){ - ResXmlElement element = mCurrentElement; - ResXmlNode firstChild = element.getResXmlNode(0); - if(firstChild == null){ - return END_TAG; - } - if(firstChild instanceof ResXmlTextNode){ - return TEXT; - } - return START_TAG; - } - if(previous == END_TAG || previous==TEXT){ - ResXmlElement element = mCurrentElement; - ResXmlElement parent = element.getParentResXmlElement(); - if(parent == null){ - return END_DOCUMENT; - } - int position = element.getIndex() + 1; - ResXmlNode nextNode = parent.getResXmlNode(position); - if(nextNode==null){ - return END_TAG; - } - if(nextNode instanceof ResXmlTextNode){ - return TEXT; - } - return START_TAG; - } - throw new XmlPullParserException("Unknown state at calculateNextEvent() prev="+previous); + mEventList.next(); + return mEventList.getType(); } @Override public int nextToken() throws XmlPullParserException, IOException { @@ -669,14 +540,38 @@ public int nextToken() throws XmlPullParserException, IOException { } @Override public void require(int type, String namespace, String name) throws XmlPullParserException, IOException { + if (type != this.getEventType() + || (namespace != null && !namespace.equals(getNamespace())) + || (name != null && !name.equals(getName()))) { + throw new XmlPullParserException( + "expected: " + TYPES[type] + " {" + namespace + "}" + name, this, null); + } } @Override public String nextText() throws XmlPullParserException, IOException { - return null; + int event = getEventType(); + if (event != START_TAG) { + throw new XmlPullParserException("precondition: START_TAG", this, null); + } + while (event!=TEXT && event!=END_TAG && event!=END_DOCUMENT){ + event=next(); + } + if(event==TEXT){ + return getText(); + } + return ""; } @Override public int nextTag() throws XmlPullParserException, IOException { - return 0; + int event = getEventType(); + if (event != START_TAG) { + throw new XmlPullParserException("precondition: START_TAG", this, null); + } + event = next(); + while (event!=START_TAG && event!=END_DOCUMENT){ + event=next(); + } + return event; } private static InputStream getFromLock(Reader reader){ @@ -692,9 +587,4 @@ private static InputStream getFromLock(Reader reader){ return null; } - /** - * This non-final re-declaration is to force compiler from using literal int value on this class - * */ - - } diff --git a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlTextNode.java b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlTextNode.java index 4218846dd..417d138e0 100644 --- a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlTextNode.java +++ b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlTextNode.java @@ -35,7 +35,6 @@ public ResXmlText getResXmlText() { public int getLineNumber(){ return getResXmlText().getLineNumber(); } - @Override public String getComment() { return getResXmlText().getComment(); } @@ -47,6 +46,15 @@ public int getDepth(){ } return 0; } + @Override + void addEvents(ParserEventList parserEventList){ + String comment = getComment(); + if(comment!=null){ + parserEventList.add( + new ParserEvent(ParserEvent.COMMENT, this, comment, false)); + } + parserEventList.add(new ParserEvent(ParserEvent.TEXT, this)); + } public ResXmlElement getParentResXmlElement(){ return getResXmlText().getParentResXmlElement(); }