1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.support.v7.mms;
18
19import android.util.Log;
20
21import org.xmlpull.v1.XmlPullParser;
22import org.xmlpull.v1.XmlPullParserException;
23
24import java.io.IOException;
25
26/**
27 * Base class for a parser of XML resources
28 */
29abstract class MmsXmlResourceParser {
30    /**
31     * Parse the content
32     *
33     * @throws IOException
34     * @throws XmlPullParserException
35     */
36    protected abstract void parseRecord() throws IOException, XmlPullParserException;
37
38    /**
39     * Get the root tag of the content
40     *
41     * @return the text of root tag
42     */
43    protected abstract String getRootTag();
44
45    private final StringBuilder mLogStringBuilder = new StringBuilder();
46
47    protected final XmlPullParser mInputParser;
48
49    protected MmsXmlResourceParser(XmlPullParser parser) {
50        mInputParser = parser;
51    }
52
53    void parse() {
54        try {
55            // Find the first element
56            if (advanceToNextEvent(XmlPullParser.START_TAG) != XmlPullParser.START_TAG) {
57                throw new XmlPullParserException("ApnsXmlProcessor: expecting start tag @"
58                        + xmlParserDebugContext());
59            }
60            if (!getRootTag().equals(mInputParser.getName())) {
61                Log.w(MmsService.TAG, "Carrier config does not start with " + getRootTag());
62                return;
63            }
64            // We are at the start tag
65            for (;;) {
66                int nextEvent;
67                // Skipping spaces
68                while ((nextEvent = mInputParser.next()) == XmlPullParser.TEXT);
69                if (nextEvent == XmlPullParser.START_TAG) {
70                    // Parse one record
71                    parseRecord();
72                } else if (nextEvent == XmlPullParser.END_TAG) {
73                    break;
74                } else {
75                    throw new XmlPullParserException("Expecting start or end tag @"
76                            + xmlParserDebugContext());
77                }
78            }
79        } catch (IOException e) {
80            Log.w(MmsService.TAG, "XmlResourceParser: I/O failure", e);
81        } catch (XmlPullParserException e) {
82            Log.w(MmsService.TAG, "XmlResourceParser: parsing failure", e);
83        }
84    }
85
86    /**
87     * Move XML parser forward to next event type or the end of doc
88     *
89     * @param eventType
90     * @return The final event type we meet
91     * @throws XmlPullParserException
92     * @throws IOException
93     */
94    protected int advanceToNextEvent(int eventType) throws XmlPullParserException, IOException {
95        for (;;) {
96            int nextEvent = mInputParser.next();
97            if (nextEvent == eventType
98                    || nextEvent == XmlPullParser.END_DOCUMENT) {
99                return nextEvent;
100            }
101        }
102    }
103
104    /**
105     * @return The debugging information of the parser's current position
106     */
107    protected String xmlParserDebugContext() {
108        mLogStringBuilder.setLength(0);
109        if (mInputParser != null) {
110            try {
111                final int eventType = mInputParser.getEventType();
112                mLogStringBuilder.append(xmlParserEventString(eventType));
113                if (eventType == XmlPullParser.START_TAG
114                        || eventType == XmlPullParser.END_TAG
115                        || eventType == XmlPullParser.TEXT) {
116                    mLogStringBuilder.append('<').append(mInputParser.getName());
117                    for (int i = 0; i < mInputParser.getAttributeCount(); i++) {
118                        mLogStringBuilder.append(' ')
119                                .append(mInputParser.getAttributeName(i))
120                                .append('=')
121                                .append(mInputParser.getAttributeValue(i));
122                    }
123                    mLogStringBuilder.append("/>");
124                }
125                return mLogStringBuilder.toString();
126            } catch (XmlPullParserException e) {
127                Log.w(MmsService.TAG, "XmlResourceParser exception", e);
128            }
129        }
130        return "Unknown";
131    }
132
133    private static String xmlParserEventString(int event) {
134        switch (event) {
135            case XmlPullParser.START_DOCUMENT: return "START_DOCUMENT";
136            case XmlPullParser.END_DOCUMENT: return "END_DOCUMENT";
137            case XmlPullParser.START_TAG: return "START_TAG";
138            case XmlPullParser.END_TAG: return "END_TAG";
139            case XmlPullParser.TEXT: return "TEXT";
140        }
141        return Integer.toString(event);
142    }
143}
144