/** * Copyright (c) 2013, Redsolution LTD. All rights reserved. * * This file is part of Xabber project; you can redistribute it and/or * modify it under the terms of the GNU General Public License, Version 3. * * Xabber is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License, * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.xabber.xmpp; import com.xabber.android.data.log.LogManager; import org.jxmpp.util.XmppDateTime; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.math.BigDecimal; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.LinkedList; import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Set of functions commonly used by packet providers. * * @author alexander.ivanov */ public class ProviderUtils { private ProviderUtils() { } /** * Pattern to remove microseconds. */ private static final Pattern pattern = Pattern .compile("^(\\d+-\\d+-\\d+T\\d+:\\d+:\\d+\\.\\d{1,3})\\d+(Z)$"); /** * Date format without milliseconds. */ private static final DateFormat XEP_0082_UTC_FORMAT_WITHOUT_MILLIS = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss'Z'"); static { XEP_0082_UTC_FORMAT_WITHOUT_MILLIS.setTimeZone(TimeZone .getTimeZone("UTC")); } /** * Parse date time from string. * * @param dateString * @return <code>null</code> if dateString is null or contains invalid data. */ public static Date parseDateTime(String dateString) { if (dateString == null) return null; Matcher matcher = pattern.matcher(dateString); if (matcher.matches()) dateString = matcher.group(1) + matcher.group(2); try { return XmppDateTime.parseXEP0082Date(dateString); } catch (ParseException e) { synchronized (XEP_0082_UTC_FORMAT_WITHOUT_MILLIS) { try { return XEP_0082_UTC_FORMAT_WITHOUT_MILLIS.parse(dateString); } catch (ParseException e2) { return null; } } } } /** * Parse integer. * * @param value * @return <code>null</code> if inner value is <code>null</code> or invalid. */ public static Integer parseInteger(String value) { try { return Integer.valueOf(value); } catch (NumberFormatException e) { return null; } } /** * Parse boolean from string. * * @param value * @return <code>null</code> if value is null or invalid. */ public static Boolean parseBoolean(String value) { if ("1".equals(value) || "true".equalsIgnoreCase(value)) return true; if ("0".equals(value) || "false".equalsIgnoreCase(value)) return false; return null; } /** * Returns string with text from all inner elements. * * @param parser * @return Empty string if there is no inner text elements. * @throws Exception */ public static String parseText(XmlPullParser parser) throws IOException, XmlPullParserException { return parseText(parser, -1); } /** * Returns string with text from all inner elements. * * @param parser * @param maximum maximum length of returned value. Use <code>-1</code> to * disable limits. * @return Empty string if there is no inner text elements. * @throws OverflowReceiverBufferException If more than maximum chars have been read. Though parser * position will be at the and of the tag. * @throws Exception */ public static String parseText(XmlPullParser parser, int maximum) throws IOException, XmlPullParserException { final StringBuilder text = new StringBuilder(); int inner = 1; boolean overflow = false; while (inner > 0) { int eventType; try { eventType = parser.next(); } catch (OutOfMemoryError e) { LogManager.exception(parser, new RuntimeException(e)); overflow = true; continue; } if (eventType == XmlPullParser.TEXT) { if (overflow) continue; String next = parser.getText(); if (maximum != -1 && (text.length() + next.length()) > maximum) { overflow = true; continue; } try { text.append(next); } catch (OutOfMemoryError e) { LogManager.exception(parser, new RuntimeException(e)); overflow = true; } } else if (eventType == XmlPullParser.START_TAG) { inner += 1; } else if (eventType == XmlPullParser.END_TAG) { inner -= 1; } else if (eventType == XmlPullParser.END_DOCUMENT) break; } if (overflow) throw new IOException("Overflow"); return text.toString(); } /** * Skip tag and its descendants. * * @param parser * @throws IllegalStateException If closed tags are incompatible with opened one. * @throws Exception */ public static void skipTag(XmlPullParser parser) throws IOException, XmlPullParserException { LinkedList<String> tags = new LinkedList<String>(); tags.add(parser.getName()); while (!tags.isEmpty()) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { tags.add(parser.getName()); } else if (eventType == XmlPullParser.END_TAG) { if (!tags.removeLast().equals(parser.getName())) throw new IllegalStateException(); } else if (eventType == XmlPullParser.END_DOCUMENT) break; } } /** * Parse big decimal. * * @param parser * @return <code>null</code> if inner text elements contains no or invalid * data. * @throws Exception */ public static BigDecimal parseBigDecimal(XmlPullParser parser) throws Exception { try { return new BigDecimal(parseText(parser, -1)); } catch (NumberFormatException e) { return null; } } /** * Parse integer. * * @param parser * @return <code>null</code> if inner text elements contains no or invalid * data. * @throws Exception */ public static Integer parseInteger(XmlPullParser parser) throws IOException, XmlPullParserException { return parseInteger(parseText(parser, -1)); } /** * Parse boolean. * * @param parser * @return <code>null</code> if inner text elements contains no or invalid * data. * @throws Exception */ public static Integer parseBoolean(XmlPullParser parser) throws IOException, XmlPullParserException { return parseInteger(parseText(parser, -1)); } /** * Parse date time. * * @param parser * @return <code>null</code> if inner text elements contains no or invalid * data. * @throws Exception */ public static Date parseDateTime(XmlPullParser parser) throws IOException, XmlPullParserException { return parseDateTime(parseText(parser, -1)); } }