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