1package eu.siacs.conversations.xml;
2
3import android.util.Log;
4import android.util.Xml;
5
6import org.xmlpull.v1.XmlPullParser;
7import org.xmlpull.v1.XmlPullParserException;
8
9import java.io.Closeable;
10import java.io.IOException;
11import java.io.InputStream;
12import java.io.InputStreamReader;
13
14import eu.siacs.conversations.Config;
15
16public class XmlReader implements Closeable {
17 private final XmlPullParser parser;
18 private InputStream is;
19
20 public XmlReader() {
21 this.parser = Xml.newPullParser();
22 try {
23 this.parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
24 } catch (XmlPullParserException e) {
25 Log.d(Config.LOGTAG, "error setting namespace feature on parser");
26 }
27 }
28
29 public void setInputStream(InputStream inputStream) throws IOException {
30 if (inputStream == null) {
31 throw new IOException();
32 }
33 this.is = inputStream;
34 try {
35 parser.setInput(new InputStreamReader(this.is));
36 } catch (XmlPullParserException e) {
37 throw new IOException("error resetting parser");
38 }
39 }
40
41 public void reset() throws IOException {
42 if (this.is == null) {
43 throw new IOException();
44 }
45 try {
46 parser.setInput(new InputStreamReader(this.is));
47 } catch (XmlPullParserException e) {
48 throw new IOException("error resetting parser");
49 }
50 }
51
52 @Override
53 public void close() {
54 this.is = null;
55 }
56
57 public Tag readTag() throws IOException {
58 try {
59 while (this.is != null && parser.next() != XmlPullParser.END_DOCUMENT) {
60 if (parser.getEventType() == XmlPullParser.START_TAG) {
61 Tag tag = Tag.start(parser.getName());
62 final String xmlns = parser.getNamespace();
63 for (int i = 0; i < parser.getAttributeCount(); ++i) {
64 final String prefix = parser.getAttributePrefix(i);
65 String name;
66 if (prefix != null && !prefix.isEmpty()) {
67 name = prefix+":"+parser.getAttributeName(i);
68 } else {
69 name = parser.getAttributeName(i);
70 }
71 tag.setAttribute(name,parser.getAttributeValue(i));
72 }
73 if (xmlns != null) {
74 tag.setAttribute("xmlns", xmlns);
75 }
76 return tag;
77 } else if (parser.getEventType() == XmlPullParser.END_TAG) {
78 return Tag.end(parser.getName());
79 } else if (parser.getEventType() == XmlPullParser.TEXT) {
80 return Tag.no(parser.getText());
81 }
82 }
83
84 } catch (Throwable throwable) {
85 throw new IOException("xml parser mishandled "+throwable.getClass().getSimpleName()+"("+throwable.getMessage()+")", throwable);
86 }
87 return null;
88 }
89
90 public Element readElement(Tag currentTag) throws IOException {
91 Element element = new Element(currentTag.getName());
92 element.setAttributes(currentTag.getAttributes());
93 Tag nextTag = this.readTag();
94 if (nextTag == null) {
95 throw new IOException("interrupted mid tag");
96 }
97 while (!nextTag.isEnd(element.getName())) {
98 if (nextTag.isNo()) {
99 if (nextTag.getName() != null) element.addChild(new TextNode(nextTag.getName()));
100 } else {
101 Element child = this.readElement(nextTag);
102 element.addChild(child);
103 }
104 nextTag = this.readTag();
105 if (nextTag == null) {
106 throw new IOException("interrupted mid tag");
107 }
108 }
109 return element;
110 }
111}