1 /*******************************************************************************
2  * This file is part of BOINC.
3  * http://boinc.berkeley.edu
4  * Copyright (C) 2012 University of California
5  *
6  * BOINC is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation,
9  * either version 3 of the License, or (at your option) any later version.
10  *
11  * BOINC is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
18  ******************************************************************************/
19 
20 package edu.berkeley.boinc.rpc;
21 
22 import java.util.ArrayList;
23 
24 import org.xml.sax.Attributes;
25 import org.xml.sax.SAXException;
26 import org.xml.sax.helpers.DefaultHandler;
27 import android.util.Xml;
28 
29 
30 public class AppVersionsParser extends DefaultHandler {
31 
32 	private ArrayList<AppVersion> mAppVersions = new ArrayList<AppVersion>();
33 	private AppVersion mAppVersion = null;
34 	private StringBuilder mCurrentElement = new StringBuilder();
35 
36 
getAppVersions()37 	public final ArrayList<AppVersion> getAppVersions() {
38 		return mAppVersions;
39 	}
40 
41 	/**
42 	 * Parse the RPC result (app_version) and generate corresponding vector
43 	 * @param rpcResult String returned by RPC call of core client
44 	 * @return vector of application version
45 	 */
parse(String rpcResult)46 	public static ArrayList<AppVersion> parse(String rpcResult) {
47 		try {
48 			AppVersionsParser parser = new AppVersionsParser();
49 			Xml.parse(rpcResult, parser);
50 			return parser.getAppVersions();
51 		}
52 		catch (SAXException e) {
53 			return null;
54 		}
55 	}
56 
57 	@Override
startElement(String uri, String localName, String qName, Attributes attributes)58 	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
59 		super.startElement(uri, localName, qName, attributes);
60 		if (localName.equalsIgnoreCase("app_version")) {
61 			mAppVersion = new AppVersion();
62 		}
63 	}
64 
65 	@Override
characters(char[] ch, int start, int length)66 	public void characters(char[] ch, int start, int length) throws SAXException {
67 		super.characters(ch, start, length);
68 		// put it into StringBuilder
69 		int myStart = start;
70 		int myLength = length;
71 		if (mCurrentElement.length() == 0) {
72 			// still empty - trim leading white-spaces
73 			for ( ; myStart < length; ++myStart, --myLength) {
74 				if (!Character.isWhitespace(ch[myStart])) {
75 					// First non-white-space character
76 					break;
77 				}
78 			}
79 		}
80 		mCurrentElement.append(ch, myStart, myLength);
81 	}
82 
83 	@Override
endElement(String uri, String localName, String qName)84 	public void endElement(String uri, String localName, String qName) throws SAXException {
85 		super.endElement(uri, localName, qName);
86 		try {
87 			trimEnd();
88 			if (mAppVersion != null) {
89 				// We are inside <app_version>
90 				if (localName.equalsIgnoreCase("app_version")) {
91 					// Closing tag of <app_version> - add to vector and be ready for next one
92 					if (!mAppVersion.app_name.equals("")) {
93 						// app_name is a must
94 						mAppVersions.add(mAppVersion);
95 					}
96 					mAppVersion = null;
97 				}
98 				else {
99 					// Not the closing tag - we decode possible inner tags
100 					if (localName.equalsIgnoreCase("app_name")) {
101 						mAppVersion.app_name = mCurrentElement.toString();
102 					}
103 					else if (localName.equalsIgnoreCase("version_num")) {
104 						mAppVersion.version_num = Integer.parseInt(mCurrentElement.toString());
105 					}
106 				}
107 			}
108 		}
109 		catch (NumberFormatException e) {
110 		}
111 		mCurrentElement.setLength(0); // to be clean for next one
112 	}
113 
trimEnd()114 	private void trimEnd() {
115 		int length = mCurrentElement.length();
116 		int i;
117 		// Trim trailing spaces
118 		for (i = length - 1; i >= 0; --i) {
119 			if (!Character.isWhitespace(mCurrentElement.charAt(i))) {
120 				// All trailing white-spaces are skipped, i is position of last character
121 				break;
122 			}
123 		}
124 		// i is position of last character
125 		mCurrentElement.setLength(i+1);
126 	}
127 }
128