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