summaryrefslogtreecommitdiff
path: root/java/com/android/voicemail/impl/utils/XmlUtils.java
blob: f5703f30f8476adca6e1e43f8b7cb4f758e3390c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.voicemail.impl.utils;

import android.util.ArrayMap;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

public class XmlUtils {

  public static final ArrayMap<String, ?> readThisArrayMapXml(
      XmlPullParser parser, String endTag, String[] name, ReadMapCallback callback)
      throws XmlPullParserException, java.io.IOException {
    ArrayMap<String, Object> map = new ArrayMap<>();

    int eventType = parser.getEventType();
    do {
      if (eventType == XmlPullParser.START_TAG) {
        Object val = readThisValueXml(parser, name, callback, true);
        map.put(name[0], val);
      } else if (eventType == XmlPullParser.END_TAG) {
        if (parser.getName().equals(endTag)) {
          return map;
        }
        throw new XmlPullParserException("Expected " + endTag + " end tag at: " + parser.getName());
      }
      eventType = parser.next();
    } while (eventType != XmlPullParser.END_DOCUMENT);

    throw new XmlPullParserException("Document ended before " + endTag + " end tag");
  }

  /**
   * Read an ArrayList object from an XmlPullParser. The XML data could previously have been
   * generated by writeListXml(). The XmlPullParser must be positioned <em>after</em> the tag that
   * begins the list.
   *
   * @param parser The XmlPullParser from which to read the list data.
   * @param endTag Name of the tag that will end the list, usually "list".
   * @param name An array of one string, used to return the name attribute of the list's tag.
   * @return HashMap The newly generated list.
   */
  public static final ArrayList readThisListXml(
      XmlPullParser parser,
      String endTag,
      String[] name,
      ReadMapCallback callback,
      boolean arrayMap)
      throws XmlPullParserException, java.io.IOException {
    ArrayList list = new ArrayList();

    int eventType = parser.getEventType();
    do {
      if (eventType == XmlPullParser.START_TAG) {
        Object val = readThisValueXml(parser, name, callback, arrayMap);
        list.add(val);
      } else if (eventType == XmlPullParser.END_TAG) {
        if (parser.getName().equals(endTag)) {
          return list;
        }
        throw new XmlPullParserException("Expected " + endTag + " end tag at: " + parser.getName());
      }
      eventType = parser.next();
    } while (eventType != XmlPullParser.END_DOCUMENT);

    throw new XmlPullParserException("Document ended before " + endTag + " end tag");
  }

  /**
   * Read a String[] object from an XmlPullParser. The XML data could previously have been generated
   * by writeStringArrayXml(). The XmlPullParser must be positioned <em>after</em> the tag that
   * begins the list.
   *
   * @param parser The XmlPullParser from which to read the list data.
   * @param endTag Name of the tag that will end the list, usually "string-array".
   * @param name An array of one string, used to return the name attribute of the list's tag.
   * @return Returns a newly generated String[].
   */
  public static String[] readThisStringArrayXml(XmlPullParser parser, String endTag, String[] name)
      throws XmlPullParserException, java.io.IOException {

    parser.next();

    List<String> array = new ArrayList<>();

    int eventType = parser.getEventType();
    do {
      if (eventType == XmlPullParser.START_TAG) {
        if (parser.getName().equals("item")) {
          try {
            array.add(parser.getAttributeValue(null, "value"));
          } catch (NullPointerException e) {
            throw new XmlPullParserException("Need value attribute in item");
          } catch (NumberFormatException e) {
            throw new XmlPullParserException("Not a number in value attribute in item");
          }
        } else {
          throw new XmlPullParserException("Expected item tag at: " + parser.getName());
        }
      } else if (eventType == XmlPullParser.END_TAG) {
        if (parser.getName().equals(endTag)) {
          return array.toArray(new String[0]);
        } else if (parser.getName().equals("item")) {

        } else {
          throw new XmlPullParserException(
              "Expected " + endTag + " end tag at: " + parser.getName());
        }
      }
      eventType = parser.next();
    } while (eventType != XmlPullParser.END_DOCUMENT);

    throw new XmlPullParserException("Document ended before " + endTag + " end tag");
  }

  private static Object readThisValueXml(
      XmlPullParser parser, String[] name, ReadMapCallback callback, boolean arrayMap)
      throws XmlPullParserException, java.io.IOException {
    final String valueName = parser.getAttributeValue(null, "name");
    final String tagName = parser.getName();

    Object res;

    if (tagName.equals("null")) {
      res = null;
    } else if (tagName.equals("string")) {
      String value = "";
      int eventType;
      while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
        if (eventType == XmlPullParser.END_TAG) {
          if (parser.getName().equals("string")) {
            name[0] = valueName;
            return value;
          }
          throw new XmlPullParserException("Unexpected end tag in <string>: " + parser.getName());
        } else if (eventType == XmlPullParser.TEXT) {
          value += parser.getText();
        } else if (eventType == XmlPullParser.START_TAG) {
          throw new XmlPullParserException("Unexpected start tag in <string>: " + parser.getName());
        }
      }
      throw new XmlPullParserException("Unexpected end of document in <string>");
    } else if ((res = readThisPrimitiveValueXml(parser, tagName)) != null) {
      // all work already done by readThisPrimitiveValueXml
    } else if (tagName.equals("string-array")) {
      res = readThisStringArrayXml(parser, "string-array", name);
      name[0] = valueName;
      return res;
    } else if (tagName.equals("list")) {
      parser.next();
      res = readThisListXml(parser, "list", name, callback, arrayMap);
      name[0] = valueName;
      return res;
    } else if (callback != null) {
      res = callback.readThisUnknownObjectXml(parser, tagName);
      name[0] = valueName;
      return res;
    } else {
      throw new XmlPullParserException("Unknown tag: " + tagName);
    }

    // Skip through to end tag.
    int eventType;
    while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
      if (eventType == XmlPullParser.END_TAG) {
        if (parser.getName().equals(tagName)) {
          name[0] = valueName;
          return res;
        }
        throw new XmlPullParserException(
            "Unexpected end tag in <" + tagName + ">: " + parser.getName());
      } else if (eventType == XmlPullParser.TEXT) {
        throw new XmlPullParserException(
            "Unexpected text in <" + tagName + ">: " + parser.getName());
      } else if (eventType == XmlPullParser.START_TAG) {
        throw new XmlPullParserException(
            "Unexpected start tag in <" + tagName + ">: " + parser.getName());
      }
    }
    throw new XmlPullParserException("Unexpected end of document in <" + tagName + ">");
  }

  private static final Object readThisPrimitiveValueXml(XmlPullParser parser, String tagName)
      throws XmlPullParserException, java.io.IOException {
    try {
      if (tagName.equals("int")) {
        return Integer.parseInt(parser.getAttributeValue(null, "value"));
      } else if (tagName.equals("long")) {
        return Long.valueOf(parser.getAttributeValue(null, "value"));
      } else if (tagName.equals("float")) {
        return Float.valueOf(parser.getAttributeValue(null, "value"));
      } else if (tagName.equals("double")) {
        return Double.valueOf(parser.getAttributeValue(null, "value"));
      } else if (tagName.equals("boolean")) {
        return Boolean.valueOf(parser.getAttributeValue(null, "value"));
      } else {
        return null;
      }
    } catch (NullPointerException e) {
      throw new XmlPullParserException("Need value attribute in <" + tagName + ">");
    } catch (NumberFormatException e) {
      throw new XmlPullParserException("Not a number in value attribute in <" + tagName + ">");
    }
  }

  public interface ReadMapCallback {

    /**
     * Called from readThisMapXml when a START_TAG is not recognized. The input stream is positioned
     * within the start tag so that attributes can be read using in.getAttribute.
     *
     * @param in the XML input stream
     * @param tag the START_TAG that was not recognized.
     * @return the Object parsed from the stream which will be put into the map.
     * @throws XmlPullParserException if the START_TAG is not recognized.
     * @throws IOException on XmlPullParser serialization errors.
     */
    Object readThisUnknownObjectXml(XmlPullParser in, String tag)
        throws XmlPullParserException, IOException;
  }
}