1 /* 2 * Copyright (C) 2016 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 17 package com.android.voicemail.impl.utils; 18 19 import android.util.ArrayMap; 20 import java.io.IOException; 21 import java.util.ArrayList; 22 import java.util.List; 23 import org.xmlpull.v1.XmlPullParser; 24 import org.xmlpull.v1.XmlPullParserException; 25 26 public class XmlUtils { 27 readThisArrayMapXml( XmlPullParser parser, String endTag, String[] name, ReadMapCallback callback)28 public static final ArrayMap<String, ?> readThisArrayMapXml( 29 XmlPullParser parser, String endTag, String[] name, ReadMapCallback callback) 30 throws XmlPullParserException, java.io.IOException { 31 ArrayMap<String, Object> map = new ArrayMap<>(); 32 33 int eventType = parser.getEventType(); 34 do { 35 if (eventType == XmlPullParser.START_TAG) { 36 Object val = readThisValueXml(parser, name, callback, true); 37 map.put(name[0], val); 38 } else if (eventType == XmlPullParser.END_TAG) { 39 if (parser.getName().equals(endTag)) { 40 return map; 41 } 42 throw new XmlPullParserException("Expected " + endTag + " end tag at: " + parser.getName()); 43 } 44 eventType = parser.next(); 45 } while (eventType != XmlPullParser.END_DOCUMENT); 46 47 throw new XmlPullParserException("Document ended before " + endTag + " end tag"); 48 } 49 50 /** 51 * Read an ArrayList object from an XmlPullParser. The XML data could previously have been 52 * generated by writeListXml(). The XmlPullParser must be positioned <em>after</em> the tag that 53 * begins the list. 54 * 55 * @param parser The XmlPullParser from which to read the list data. 56 * @param endTag Name of the tag that will end the list, usually "list". 57 * @param name An array of one string, used to return the name attribute of the list's tag. 58 * @return HashMap The newly generated list. 59 */ readThisListXml( XmlPullParser parser, String endTag, String[] name, ReadMapCallback callback, boolean arrayMap)60 public static final ArrayList readThisListXml( 61 XmlPullParser parser, 62 String endTag, 63 String[] name, 64 ReadMapCallback callback, 65 boolean arrayMap) 66 throws XmlPullParserException, java.io.IOException { 67 ArrayList list = new ArrayList(); 68 69 int eventType = parser.getEventType(); 70 do { 71 if (eventType == XmlPullParser.START_TAG) { 72 Object val = readThisValueXml(parser, name, callback, arrayMap); 73 list.add(val); 74 } else if (eventType == XmlPullParser.END_TAG) { 75 if (parser.getName().equals(endTag)) { 76 return list; 77 } 78 throw new XmlPullParserException("Expected " + endTag + " end tag at: " + parser.getName()); 79 } 80 eventType = parser.next(); 81 } while (eventType != XmlPullParser.END_DOCUMENT); 82 83 throw new XmlPullParserException("Document ended before " + endTag + " end tag"); 84 } 85 86 /** 87 * Read a String[] object from an XmlPullParser. The XML data could previously have been generated 88 * by writeStringArrayXml(). The XmlPullParser must be positioned <em>after</em> the tag that 89 * begins the list. 90 * 91 * @param parser The XmlPullParser from which to read the list data. 92 * @param endTag Name of the tag that will end the list, usually "string-array". 93 * @param name An array of one string, used to return the name attribute of the list's tag. 94 * @return Returns a newly generated String[]. 95 */ readThisStringArrayXml(XmlPullParser parser, String endTag, String[] name)96 public static String[] readThisStringArrayXml(XmlPullParser parser, String endTag, String[] name) 97 throws XmlPullParserException, java.io.IOException { 98 99 parser.next(); 100 101 List<String> array = new ArrayList<>(); 102 103 int eventType = parser.getEventType(); 104 do { 105 if (eventType == XmlPullParser.START_TAG) { 106 if (parser.getName().equals("item")) { 107 try { 108 array.add(parser.getAttributeValue(null, "value")); 109 } catch (NullPointerException e) { 110 throw new XmlPullParserException("Need value attribute in item"); 111 } catch (NumberFormatException e) { 112 throw new XmlPullParserException("Not a number in value attribute in item"); 113 } 114 } else { 115 throw new XmlPullParserException("Expected item tag at: " + parser.getName()); 116 } 117 } else if (eventType == XmlPullParser.END_TAG) { 118 if (parser.getName().equals(endTag)) { 119 return array.toArray(new String[0]); 120 } else if (parser.getName().equals("item")) { 121 122 } else { 123 throw new XmlPullParserException( 124 "Expected " + endTag + " end tag at: " + parser.getName()); 125 } 126 } 127 eventType = parser.next(); 128 } while (eventType != XmlPullParser.END_DOCUMENT); 129 130 throw new XmlPullParserException("Document ended before " + endTag + " end tag"); 131 } 132 readThisValueXml( XmlPullParser parser, String[] name, ReadMapCallback callback, boolean arrayMap)133 private static Object readThisValueXml( 134 XmlPullParser parser, String[] name, ReadMapCallback callback, boolean arrayMap) 135 throws XmlPullParserException, java.io.IOException { 136 final String valueName = parser.getAttributeValue(null, "name"); 137 final String tagName = parser.getName(); 138 139 Object res; 140 141 if (tagName.equals("null")) { 142 res = null; 143 } else if (tagName.equals("string")) { 144 String value = ""; 145 int eventType; 146 while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) { 147 if (eventType == XmlPullParser.END_TAG) { 148 if (parser.getName().equals("string")) { 149 name[0] = valueName; 150 return value; 151 } 152 throw new XmlPullParserException("Unexpected end tag in <string>: " + parser.getName()); 153 } else if (eventType == XmlPullParser.TEXT) { 154 value += parser.getText(); 155 } else if (eventType == XmlPullParser.START_TAG) { 156 throw new XmlPullParserException("Unexpected start tag in <string>: " + parser.getName()); 157 } 158 } 159 throw new XmlPullParserException("Unexpected end of document in <string>"); 160 } else if ((res = readThisPrimitiveValueXml(parser, tagName)) != null) { 161 // all work already done by readThisPrimitiveValueXml 162 } else if (tagName.equals("string-array")) { 163 res = readThisStringArrayXml(parser, "string-array", name); 164 name[0] = valueName; 165 return res; 166 } else if (tagName.equals("list")) { 167 parser.next(); 168 res = readThisListXml(parser, "list", name, callback, arrayMap); 169 name[0] = valueName; 170 return res; 171 } else if (callback != null) { 172 res = callback.readThisUnknownObjectXml(parser, tagName); 173 name[0] = valueName; 174 return res; 175 } else { 176 throw new XmlPullParserException("Unknown tag: " + tagName); 177 } 178 179 // Skip through to end tag. 180 int eventType; 181 while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) { 182 if (eventType == XmlPullParser.END_TAG) { 183 if (parser.getName().equals(tagName)) { 184 name[0] = valueName; 185 return res; 186 } 187 throw new XmlPullParserException( 188 "Unexpected end tag in <" + tagName + ">: " + parser.getName()); 189 } else if (eventType == XmlPullParser.TEXT) { 190 throw new XmlPullParserException( 191 "Unexpected text in <" + tagName + ">: " + parser.getName()); 192 } else if (eventType == XmlPullParser.START_TAG) { 193 throw new XmlPullParserException( 194 "Unexpected start tag in <" + tagName + ">: " + parser.getName()); 195 } 196 } 197 throw new XmlPullParserException("Unexpected end of document in <" + tagName + ">"); 198 } 199 readThisPrimitiveValueXml(XmlPullParser parser, String tagName)200 private static final Object readThisPrimitiveValueXml(XmlPullParser parser, String tagName) 201 throws XmlPullParserException, java.io.IOException { 202 try { 203 if (tagName.equals("int")) { 204 return Integer.parseInt(parser.getAttributeValue(null, "value")); 205 } else if (tagName.equals("long")) { 206 return Long.valueOf(parser.getAttributeValue(null, "value")); 207 } else if (tagName.equals("float")) { 208 return Float.valueOf(parser.getAttributeValue(null, "value")); 209 } else if (tagName.equals("double")) { 210 return Double.valueOf(parser.getAttributeValue(null, "value")); 211 } else if (tagName.equals("boolean")) { 212 return Boolean.valueOf(parser.getAttributeValue(null, "value")); 213 } else { 214 return null; 215 } 216 } catch (NullPointerException e) { 217 throw new XmlPullParserException("Need value attribute in <" + tagName + ">"); 218 } catch (NumberFormatException e) { 219 throw new XmlPullParserException("Not a number in value attribute in <" + tagName + ">"); 220 } 221 } 222 223 public interface ReadMapCallback { 224 225 /** 226 * Called from readThisMapXml when a START_TAG is not recognized. The input stream is positioned 227 * within the start tag so that attributes can be read using in.getAttribute. 228 * 229 * @param in the XML input stream 230 * @param tag the START_TAG that was not recognized. 231 * @return the Object parsed from the stream which will be put into the map. 232 * @throws XmlPullParserException if the START_TAG is not recognized. 233 * @throws IOException on XmlPullParser serialization errors. 234 */ readThisUnknownObjectXml(XmlPullParser in, String tag)235 Object readThisUnknownObjectXml(XmlPullParser in, String tag) 236 throws XmlPullParserException, IOException; 237 } 238 } 239