blob: d0efbf81a4eabe8467a697102f8811b86fdf6e4d [file] [log] [blame]
Maarten Derks8d5a7132016-06-07 15:51:53 +02001package com.fairphone.updater.tools;
2
3import android.util.Xml;
4
5import com.fairphone.updater.data.Store;
6import com.fairphone.updater.data.UpdaterData;
7import com.fairphone.updater.data.Version;
8
9import org.xmlpull.v1.XmlPullParser;
10import org.xmlpull.v1.XmlPullParserException;
11
12import java.io.FileInputStream;
13import java.io.IOException;
14import java.util.Locale;
15
16/**
17 * A helper class for parsing the XML received from the server into a data structure.
18 *
19 * @author Maarten Derks
20 */
21public class XmlParser {
22
23 private static final String ns = null;
24
25 /**
26 * Parse the content of the specified file input stream into an UpdaterData object.
27 *
28 * @param fis A FileInputStream containing the XML to be parsed
29 * @return an UpdaterData object
30 * @throws XmlPullParserException This exception is thrown to signal XML Pull Parser related faults.
31 * @throws IOException Signals a general, I/O-related error.
32 */
33 public UpdaterData parse(FileInputStream fis) throws XmlPullParserException, IOException {
34 try {
35 XmlPullParser parser = Xml.newPullParser();
36 parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
37 parser.setInput(fis, null);
38 parser.nextTag();
39 return readUpdaterXml(parser);
40 } finally {
41 fis.close();
42 }
43 }
44
45 private UpdaterData readUpdaterXml(XmlPullParser parser) throws XmlPullParserException, IOException {
46 UpdaterData updaterData = UpdaterData.getInstance();
47 updaterData.resetUpdaterData();
48
49 parser.require(XmlPullParser.START_TAG, ns, "updater");
50 while (parser.next() != XmlPullParser.END_TAG) {
51 if (parser.getEventType() != XmlPullParser.START_TAG) {
52 continue;
53 }
54 String tagName = parser.getName();
55 if (tagName.equals("releases")) {
56 parser.require(XmlPullParser.START_TAG, ns, "releases");
57 while (parser.next() != XmlPullParser.END_TAG) {
58 if (parser.getEventType() != XmlPullParser.START_TAG) {
59 continue;
60 }
61 String releaseType = parser.getName();
62 if (releaseType.equals("fairphone")) {
63 parser.require(XmlPullParser.START_TAG, ns, "fairphone");
64 updaterData.setLatestFairphoneVersionNumber(parser.getAttributeValue(ns, "latest"));
65 while (parser.next() != XmlPullParser.END_TAG) {
66 if (parser.getEventType() != XmlPullParser.START_TAG) {
67 continue;
68 }
69 String name = parser.getName();
70 if (name.equals("version")) {
71 updaterData.addFairphoneVersion(readVersion(parser, Version.IMAGE_TYPE_FAIRPHONE));
72 } else {
73 skip(parser);
74 }
75 }
76 }
77
78 if (releaseType.equals("aosp")) {
79 parser.require(XmlPullParser.START_TAG, ns, "aosp");
80 updaterData.setLatestAOSPVersionNumber(parser.getAttributeValue(ns, "latest"));
81 while (parser.next() != XmlPullParser.END_TAG) {
82 if (parser.getEventType() != XmlPullParser.START_TAG) {
83 continue;
84 }
85 String name = parser.getName();
86 if (name.equals("version")) {
87 updaterData.addAOSPVersion(readVersion(parser, Version.IMAGE_TYPE_AOSP));
88 } else {
89 skip(parser);
90 }
91 }
92 }
93 }
94 }
95
96 if (tagName.equals("stores")) {
97 parser.require(XmlPullParser.START_TAG, ns, "stores");
98 while (parser.next() != XmlPullParser.END_TAG) {
99 if (parser.getEventType() != XmlPullParser.START_TAG) {
100 continue;
101 }
102 String name = parser.getName();
103 if (name.equals("store")) {
104 updaterData.addAppStore(readStore(parser));
105 } else {
106 skip(parser);
107 }
108 }
109 }
110 }
111 return updaterData;
112 }
113
114 private Version readVersion(XmlPullParser parser, String imageType) throws XmlPullParserException, IOException {
115 parser.require(XmlPullParser.START_TAG, ns, "version");
116
117 Version version = new Version();
118
119 version.setId(parser.getAttributeValue(ns, "number"));
120 version.setImageType(imageType);
121
122 while (parser.next() != XmlPullParser.END_TAG) {
123 if (parser.getEventType() != XmlPullParser.START_TAG) {
124 continue;
125 }
126 String tagName = parser.getName();
127 if (tagName.equals("name")) {
128 version.setName(readName(parser));
129 } else if (tagName.equals("build_number")) {
130 version.setBuildNumber(readBuildNumber(parser));
131 } else if (tagName.equals("android_version")) {
132 version.setAndroidVersion(readAndroidVersion(parser));
133 } else if (tagName.equals("release_notes")) {
134 version.setReleaseNotes(Version.DEFAULT_NOTES_LANG, readReleaseNotes(parser));
135 } else if (tagName.equals("release_notes" + "_" + Locale.getDefault().getLanguage())) {
136 version.setReleaseNotes(Locale.getDefault().getLanguage(), readLocalizedReleaseNotes(parser));
137 } else if (tagName.equals("release_date")) {
138 version.setReleaseDate(readReleaseDate(parser));
139 } else if (tagName.equals("md5sum")) {
140 version.setMd5Sum(readMd5sum(parser));
141 } else if(tagName.equals("thumbnail_link")) {
142 version.setThumbnailLink(readThumbnailLink(parser));
143 } else if (tagName.equals("update_link")) {
144 version.setDownloadLink(readUpdateLink(parser));
145 } else if (tagName.equals("dependencies")) {
146 version.setVersionDependencies(readDependencies(parser));
147 } else if (tagName.equals("erase_data_warning")) {
148 version.setEraseAllPartitionWarning();
149 } else {
150 skip(parser);
151 }
152 }
153 return version;
154 }
155
156 private Store readStore(XmlPullParser parser) throws XmlPullParserException, IOException {
157 parser.require(XmlPullParser.START_TAG, ns, "store");
158
159 Store store = new Store();
160
161 store.setId(parser.getAttributeValue(ns, "number"));
162
163 while (parser.next() != XmlPullParser.END_TAG) {
164 if (parser.getEventType() != XmlPullParser.START_TAG) {
165 continue;
166 }
167 String tagName = parser.getName();
168 if (tagName.equals("name")) {
169 store.setName(readName(parser));
170 } else if (tagName.equals("build_number")) {
171 store.setBuildNumber(readBuildNumber(parser));
172 } else if (tagName.equals("release_notes")) {
173 store.setReleaseNotes(Version.DEFAULT_NOTES_LANG, readReleaseNotes(parser));
174 } else if (tagName.equals("release_notes" + "_" + Locale.getDefault().getLanguage())) {
175 store.setReleaseNotes(Locale.getDefault().getLanguage(), readLocalizedReleaseNotes(parser));
176 } else if (tagName.equals("release_date")) {
177 store.setReleaseDate(readReleaseDate(parser));
178 } else if (tagName.equals("md5sum")) {
179 store.setMd5Sum(readMd5sum(parser));
180 } else if (tagName.equals("update_link")) {
181 store.setDownloadLink(readUpdateLink(parser));
182 } else if (tagName.equals("show_disclaimer")) {
183 store.setShowDisclaimer();
184 } else {
185 skip(parser);
186 }
187 }
188 return store;
189 }
190
191 private String readName(XmlPullParser parser) throws IOException, XmlPullParserException {
192 parser.require(XmlPullParser.START_TAG, ns, "name");
193 String name = readText(parser);
194 parser.require(XmlPullParser.END_TAG, ns, "name");
195 return name;
196 }
197
198 private String readBuildNumber(XmlPullParser parser) throws IOException, XmlPullParserException {
199 parser.require(XmlPullParser.START_TAG, ns, "build_number");
200 String buildNumber = readText(parser);
201 parser.require(XmlPullParser.END_TAG, ns, "build_number");
202 return buildNumber;
203 }
204
205 private String readAndroidVersion(XmlPullParser parser) throws IOException, XmlPullParserException {
206 parser.require(XmlPullParser.START_TAG, ns, "android_version");
207 String androidVersion = readText(parser);
208 parser.require(XmlPullParser.END_TAG, ns, "android_version");
209 return androidVersion;
210 }
211
212 private String readReleaseNotes(XmlPullParser parser) throws IOException, XmlPullParserException {
213 parser.require(XmlPullParser.START_TAG, ns, "release_notes");
214 String releaseNotes = readText(parser);
215 parser.require(XmlPullParser.END_TAG, ns, "release_notes");
216 return releaseNotes;
217 }
218
219 private String readLocalizedReleaseNotes(XmlPullParser parser) throws IOException, XmlPullParserException {
220 parser.require(XmlPullParser.START_TAG, ns, "release_notes" + "_" + Locale.getDefault().getLanguage());
221 String releaseNotes = readText(parser);
222 parser.require(XmlPullParser.END_TAG, ns, "release_notes" + "_" + Locale.getDefault().getLanguage());
223 return releaseNotes;
224 }
225
226 private String readReleaseDate(XmlPullParser parser) throws IOException, XmlPullParserException {
227 parser.require(XmlPullParser.START_TAG, ns, "release_date");
228 String releaseDate = readText(parser);
229 parser.require(XmlPullParser.END_TAG, ns, "release_date");
230 return releaseDate;
231 }
232
233 private String readMd5sum(XmlPullParser parser) throws IOException, XmlPullParserException {
234 parser.require(XmlPullParser.START_TAG, ns, "md5sum");
235 String md5sum = readText(parser);
236 parser.require(XmlPullParser.END_TAG, ns, "md5sum");
237 return md5sum;
238 }
239
240 private String readThumbnailLink(XmlPullParser parser) throws IOException, XmlPullParserException {
241 parser.require(XmlPullParser.START_TAG, ns, "thumbnail_link");
242 String thumbnailLink = readText(parser);
243 parser.require(XmlPullParser.END_TAG, ns, "thumbnail_link");
244 return thumbnailLink;
245 }
246
247 private String readUpdateLink(XmlPullParser parser) throws IOException, XmlPullParserException {
248 parser.require(XmlPullParser.START_TAG, ns, "update_link");
249 String updateLink = readText(parser);
250 parser.require(XmlPullParser.END_TAG, ns, "update_link");
251 return updateLink;
252 }
253
254 private String readDependencies(XmlPullParser parser) throws IOException, XmlPullParserException {
255 parser.require(XmlPullParser.START_TAG, ns, "dependencies");
256 String dependencies = readText(parser);
257 parser.require(XmlPullParser.END_TAG, ns, "dependencies");
258 return dependencies;
259 }
260
261 private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
262 String result = "";
263 if (parser.next() == XmlPullParser.TEXT) {
264 result = parser.getText();
265 parser.nextTag();
266 }
267 return result;
268 }
269
270 private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
271 if (parser.getEventType() != XmlPullParser.START_TAG) {
272 throw new IllegalStateException();
273 }
274 int depth = 1;
275 while (depth != 0) {
276 switch (parser.next()) {
277 case XmlPullParser.END_TAG:
278 depth--;
279 break;
280 case XmlPullParser.START_TAG:
281 depth++;
282 break;
283 }
284 }
285 }
286}