001/** 002 * 003 * Copyright © 2014-2019 Florian Schmaus 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smack.util; 018 019import java.io.IOException; 020import java.net.URI; 021import java.net.URISyntaxException; 022import java.text.ParseException; 023import java.util.Date; 024import java.util.Locale; 025 026import javax.xml.namespace.QName; 027 028import org.jivesoftware.smack.datatypes.UInt16; 029import org.jivesoftware.smack.datatypes.UInt32; 030import org.jivesoftware.smack.packet.XmlEnvironment; 031import org.jivesoftware.smack.parsing.SmackParsingException; 032import org.jivesoftware.smack.parsing.SmackParsingException.RequiredAttributeMissingException; 033import org.jivesoftware.smack.parsing.SmackParsingException.SmackTextParseException; 034import org.jivesoftware.smack.parsing.SmackParsingException.SmackUriSyntaxParsingException; 035import org.jivesoftware.smack.xml.XmlPullParser; 036import org.jivesoftware.smack.xml.XmlPullParserException; 037 038import org.jxmpp.jid.EntityBareJid; 039import org.jxmpp.jid.EntityFullJid; 040import org.jxmpp.jid.EntityJid; 041import org.jxmpp.jid.Jid; 042import org.jxmpp.jid.impl.JidCreate; 043import org.jxmpp.jid.parts.Resourcepart; 044import org.jxmpp.stringprep.XmppStringprepException; 045import org.jxmpp.util.XmppDateTime; 046 047public class ParserUtils { 048 049 /** 050 * The constant String "jid". 051 */ 052 public static final String JID = "jid"; 053 054 public static void assertAtStartTag(XmlPullParser parser) throws XmlPullParserException { 055 assert parser.getEventType() == XmlPullParser.Event.START_ELEMENT; 056 } 057 058 public static void assertAtStartTag(XmlPullParser parser, String name) throws XmlPullParserException { 059 assertAtStartTag(parser); 060 assert name.equals(parser.getName()); 061 } 062 063 public static void assertAtEndTag(XmlPullParser parser) throws XmlPullParserException { 064 assert parser.getEventType() == XmlPullParser.Event.END_ELEMENT; 065 } 066 067 public static void forwardToStartElement(XmlPullParser parser) throws XmlPullParserException, IOException { 068 // Wind the parser forward to the first start tag 069 XmlPullParser.Event event = parser.getEventType(); 070 while (event != XmlPullParser.Event.START_ELEMENT) { 071 if (event == XmlPullParser.Event.END_DOCUMENT) { 072 throw new IllegalArgumentException("Document contains no start tag"); 073 } 074 event = parser.next(); 075 } 076 } 077 078 public static void forwardToEndTagOfDepth(XmlPullParser parser, int depth) 079 throws XmlPullParserException, IOException { 080 XmlPullParser.Event event = parser.getEventType(); 081 while (!(event == XmlPullParser.Event.END_ELEMENT && parser.getDepth() == depth)) { 082 event = parser.next(); 083 } 084 } 085 086 public static Jid getJidAttribute(XmlPullParser parser) throws XmppStringprepException { 087 return getJidAttribute(parser, JID); 088 } 089 090 public static Jid getJidAttribute(XmlPullParser parser, String name) throws XmppStringprepException { 091 final String jidString = parser.getAttributeValue("", name); 092 if (jidString == null) { 093 return null; 094 } 095 return JidCreate.from(jidString); 096 } 097 098 public static EntityBareJid getBareJidAttribute(XmlPullParser parser) throws XmppStringprepException { 099 return getBareJidAttribute(parser, JID); 100 } 101 102 public static EntityBareJid getBareJidAttribute(XmlPullParser parser, String name) throws XmppStringprepException { 103 final String jidString = parser.getAttributeValue("", name); 104 if (jidString == null) { 105 return null; 106 } 107 return JidCreate.entityBareFrom(jidString); 108 } 109 110 public static EntityFullJid getFullJidAttribute(XmlPullParser parser) throws XmppStringprepException { 111 return getFullJidAttribute(parser, JID); 112 } 113 114 public static EntityFullJid getFullJidAttribute(XmlPullParser parser, String name) throws XmppStringprepException { 115 final String jidString = parser.getAttributeValue("", name); 116 if (jidString == null) { 117 return null; 118 } 119 return JidCreate.entityFullFrom(jidString); 120 } 121 122 public static EntityJid getEntityJidAttribute(XmlPullParser parser, String name) throws XmppStringprepException { 123 final String jidString = parser.getAttributeValue("", name); 124 if (jidString == null) { 125 return null; 126 } 127 Jid jid = JidCreate.from(jidString); 128 129 if (!jid.hasLocalpart()) return null; 130 131 EntityFullJid fullJid = jid.asEntityFullJidIfPossible(); 132 if (fullJid != null) { 133 return fullJid; 134 } 135 136 EntityBareJid bareJid = jid.asEntityBareJidIfPossible(); 137 return bareJid; 138 } 139 140 public static Resourcepart getResourcepartAttribute(XmlPullParser parser, String name) throws XmppStringprepException { 141 final String resourcepartString = parser.getAttributeValue("", name); 142 if (resourcepartString == null) { 143 return null; 144 } 145 return Resourcepart.from(resourcepartString); 146 } 147 148 /** 149 * Prase a string to a boolean value as per "xs:boolean". Valid input strings are "true", "1" for true, and "false", "0" for false. 150 * 151 * @param booleanString the input string. 152 * @return the boolean representation of the input string 153 * @throws IllegalArgumentException if the input string is not valid. 154 * @since 4.3.2 155 */ 156 public static boolean parseXmlBoolean(String booleanString) { 157 switch (booleanString) { 158 case "true": 159 case "1": 160 return true; 161 case "false": 162 case "0": 163 return false; 164 default: 165 throw new IllegalArgumentException(booleanString + " is not a valid boolean string"); 166 } 167 } 168 169 /** 170 * Get the boolean value of an argument. 171 * 172 * @param parser TODO javadoc me please 173 * @param name TODO javadoc me please 174 * @return the boolean value or null of no argument of the given name exists 175 */ 176 public static Boolean getBooleanAttribute(XmlPullParser parser, String name) { 177 String valueString = parser.getAttributeValue("", name); 178 if (valueString == null) 179 return null; 180 valueString = valueString.toLowerCase(Locale.US); 181 return parseXmlBoolean(valueString); 182 } 183 184 public static boolean getBooleanAttribute(XmlPullParser parser, String name, 185 boolean defaultValue) { 186 Boolean bool = getBooleanAttribute(parser, name); 187 if (bool == null) { 188 return defaultValue; 189 } 190 else { 191 return bool; 192 } 193 } 194 195 public static Byte getByteAttributeFromNextText(XmlPullParser parser) throws IOException, XmlPullParserException { 196 String nextText = parser.nextText(); 197 return Byte.valueOf(nextText); 198 } 199 200 public static int getIntegerAttributeOrThrow(XmlPullParser parser, String name, String throwMessage) 201 throws IOException { 202 Integer res = getIntegerAttribute(parser, name); 203 if (res == null) { 204 // TODO Should be SmackParseException. 205 throw new IOException(throwMessage); 206 } 207 return res; 208 } 209 210 public static Integer getIntegerAttribute(XmlPullParser parser, String name) { 211 String valueString = parser.getAttributeValue("", name); 212 if (valueString == null) 213 return null; 214 return Integer.valueOf(valueString); 215 } 216 217 public static int getIntegerAttribute(XmlPullParser parser, String name, int defaultValue) { 218 Integer integer = getIntegerAttribute(parser, name); 219 if (integer == null) { 220 return defaultValue; 221 } 222 else { 223 return integer; 224 } 225 } 226 227 public static UInt16 getUInt16Attribute(XmlPullParser parser, String name) { 228 Integer integer = getIntegerAttribute(parser, name); 229 if (integer == null) { 230 return null; 231 } 232 return UInt16.from(integer); 233 } 234 235 public static UInt16 getRequiredUInt16Attribute(XmlPullParser parser, String name) throws RequiredAttributeMissingException { 236 UInt16 uint16 = getUInt16Attribute(parser, name); 237 if (uint16 == null) { 238 throw new SmackParsingException.RequiredAttributeMissingException(name); 239 } 240 return uint16; 241 } 242 243 public static int getIntegerFromNextText(XmlPullParser parser) throws XmlPullParserException, IOException { 244 String intString = parser.nextText(); 245 return Integer.valueOf(intString); 246 } 247 248 public static Long getLongAttribute(XmlPullParser parser, String name) { 249 String valueString = parser.getAttributeValue("", name); 250 if (valueString == null) 251 return null; 252 return Long.valueOf(valueString); 253 } 254 255 public static long getLongAttribute(XmlPullParser parser, String name, long defaultValue) { 256 Long l = getLongAttribute(parser, name); 257 if (l == null) { 258 return defaultValue; 259 } 260 else { 261 return l; 262 } 263 } 264 265 public static UInt32 getUInt32Attribute(XmlPullParser parser, String name) { 266 Long l = getLongAttribute(parser, name); 267 if (l == null) { 268 return null; 269 } 270 return UInt32.from(l); 271 } 272 273 public static double getDoubleFromNextText(XmlPullParser parser) throws XmlPullParserException, IOException { 274 String doubleString = parser.nextText(); 275 return Double.valueOf(doubleString); 276 } 277 278 public static Double getDoubleAttribute(XmlPullParser parser, String name) { 279 String valueString = parser.getAttributeValue("", name); 280 if (valueString == null) 281 return null; 282 return Double.valueOf(valueString); 283 } 284 285 public static double getDoubleAttribute(XmlPullParser parser, String name, long defaultValue) { 286 Double d = getDoubleAttribute(parser, name); 287 if (d == null) { 288 return defaultValue; 289 } 290 else { 291 return d; 292 } 293 } 294 295 public static Short getShortAttribute(XmlPullParser parser, String name) { 296 String valueString = parser.getAttributeValue("", name); 297 if (valueString == null) { 298 return null; 299 } 300 return Short.valueOf(valueString); 301 } 302 303 public static short getShortAttribute(XmlPullParser parser, String name, short defaultValue) { 304 Short s = getShortAttribute(parser, name); 305 if (s == null) { 306 return defaultValue; 307 } 308 return s; 309 } 310 311 public static Date getDateFromOptionalXep82String(String dateString) throws SmackTextParseException { 312 if (dateString == null) { 313 return null; 314 } 315 return getDateFromXep82String(dateString); 316 } 317 318 public static Date getDateFromXep82String(String dateString) throws SmackTextParseException { 319 try { 320 return XmppDateTime.parseXEP0082Date(dateString); 321 } catch (ParseException e) { 322 throw new SmackParsingException.SmackTextParseException(e); 323 } 324 } 325 326 public static Date getDateFromString(String dateString) throws SmackTextParseException { 327 try { 328 return XmppDateTime.parseDate(dateString); 329 } catch (ParseException e) { 330 throw new SmackParsingException.SmackTextParseException(e); 331 } 332 } 333 334 public static Date getDateFromNextText(XmlPullParser parser) throws XmlPullParserException, IOException, SmackTextParseException { 335 String dateString = parser.nextText(); 336 return getDateFromString(dateString); 337 } 338 339 public static URI getUriFromNextText(XmlPullParser parser) throws XmlPullParserException, IOException, SmackUriSyntaxParsingException { 340 String uriString = parser.nextText(); 341 try { 342 return new URI(uriString); 343 } 344 catch (URISyntaxException e) { 345 throw new SmackParsingException.SmackUriSyntaxParsingException(e); 346 } 347 } 348 349 public static String getRequiredAttribute(XmlPullParser parser, String name) throws IOException { 350 String value = parser.getAttributeValue("", name); 351 if (StringUtils.isNullOrEmpty(value)) { 352 throw new IOException("Attribute " + name + " is null or empty (" + value + ')'); 353 } 354 return value; 355 } 356 357 public static String getRequiredNextText(XmlPullParser parser) throws XmlPullParserException, IOException { 358 String text = parser.nextText(); 359 if (StringUtils.isNullOrEmpty(text)) { 360 throw new IOException("Next text is null or empty (" + text + ')'); 361 } 362 return text; 363 } 364 365 public static String getXmlLang(XmlPullParser parser, XmlEnvironment xmlEnvironment) { 366 String currentXmlLang = getXmlLang(parser); 367 if (currentXmlLang != null) { 368 return currentXmlLang; 369 } 370 return xmlEnvironment.getEffectiveLanguage(); 371 } 372 373 public static String getXmlLang(XmlPullParser parser) { 374 return parser.getAttributeValue("http://www.w3.org/XML/1998/namespace", "lang"); 375 } 376 377 /** 378 * Get the QName of the current element. 379 * 380 * @param parser the parser. 381 * @return the Qname. 382 * @deprecated use {@link XmlPullParser#getQName()} instead. 383 */ 384 @Deprecated 385 // TODO: Remove in Smack 4.5 386 public static QName getQName(XmlPullParser parser) { 387 return parser.getQName(); 388 } 389}