/**
* 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));
}
}