/*
 * Decompiled with CFR 0.152.
 */
package org.jivesoftware.smack.util;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.compress.packet.Compress;
import org.jivesoftware.smack.packet.DefaultExtensionElement;
import org.jivesoftware.smack.packet.EmptyResultIQ;
import org.jivesoftware.smack.packet.ErrorIQ;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Session;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.packet.StartTls;
import org.jivesoftware.smack.packet.StreamError;
import org.jivesoftware.smack.packet.UnparsedIQ;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.sasl.packet.SaslStreamElements;
import org.jivesoftware.smack.util.ParserUtils;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jxmpp.jid.Jid;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

public class PacketParserUtils {
    private static final Logger LOGGER = Logger.getLogger(PacketParserUtils.class.getName());
    public static final String FEATURE_XML_ROUNDTRIP = "http://xmlpull.org/v1/doc/features.html#xml-roundtrip";
    private static final XmlPullParserFactory XML_PULL_PARSER_FACTORY;
    public static final boolean XML_PULL_PARSER_SUPPORTS_ROUNDTRIP;

    public static XmlPullParser getParserFor(String stanza) throws XmlPullParserException, IOException {
        return PacketParserUtils.getParserFor(new StringReader(stanza));
    }

    public static XmlPullParser getParserFor(Reader reader) throws XmlPullParserException, IOException {
        XmlPullParser parser = PacketParserUtils.newXmppParser(reader);
        int event = parser.getEventType();
        while (event != 2) {
            if (event == 1) {
                throw new IllegalArgumentException("Document contains no start tag");
            }
            event = parser.next();
        }
        return parser;
    }

    public static XmlPullParser getParserFor(String stanza, String startTag) throws XmlPullParserException, IOException {
        XmlPullParser parser = PacketParserUtils.getParserFor(stanza);
        while (true) {
            int event = parser.getEventType();
            String name = parser.getName();
            if (event == 2 && name.equals(startTag)) break;
            if (event == 1) {
                throw new IllegalArgumentException("Could not find start tag '" + startTag + "' in stanza: " + stanza);
            }
            parser.next();
        }
        return parser;
    }

    public static Stanza parseStanza(String stanza) throws XmlPullParserException, IOException, SmackException {
        return PacketParserUtils.parseStanza(PacketParserUtils.getParserFor(stanza));
    }

    public static Stanza parseStanza(XmlPullParser parser) throws XmlPullParserException, IOException, SmackException {
        String name;
        ParserUtils.assertAtStartTag(parser);
        switch (name = parser.getName()) {
            case "message": {
                return PacketParserUtils.parseMessage(parser);
            }
            case "iq": {
                return PacketParserUtils.parseIQ(parser);
            }
            case "presence": {
                return PacketParserUtils.parsePresence(parser);
            }
        }
        throw new IllegalArgumentException("Can only parse message, iq or presence, not " + name);
    }

    public static XmlPullParser newXmppParser() throws XmlPullParserException {
        XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
        parser.setFeature("http://xmlpull.org/v1/doc/features.html#process-namespaces", true);
        if (XML_PULL_PARSER_SUPPORTS_ROUNDTRIP) {
            try {
                parser.setFeature(FEATURE_XML_ROUNDTRIP, true);
            }
            catch (XmlPullParserException e) {
                LOGGER.log(Level.SEVERE, "XmlPullParser does not support XML_ROUNDTRIP, although it was first determined to be supported", e);
            }
        }
        return parser;
    }

    public static XmlPullParser newXmppParser(Reader reader) throws XmlPullParserException {
        XmlPullParser parser = PacketParserUtils.newXmppParser();
        parser.setInput(reader);
        return parser;
    }

    /*
     * Enabled aggressive block sorting
     */
    public static Message parseMessage(XmlPullParser parser) throws XmlPullParserException, IOException, SmackException {
        ParserUtils.assertAtStartTag(parser);
        assert (parser.getName().equals("message"));
        int initialDepth = parser.getDepth();
        Message message = new Message();
        message.setStanzaId(parser.getAttributeValue("", "id"));
        message.setTo(ParserUtils.getJidAttribute(parser, "to"));
        message.setFrom(ParserUtils.getJidAttribute(parser, "from"));
        String typeString = parser.getAttributeValue("", "type");
        if (typeString != null) {
            message.setType(Message.Type.fromString(typeString));
        }
        String language = PacketParserUtils.getLanguageAttribute(parser);
        String defaultLanguage = null;
        if (language != null && !"".equals(language.trim())) {
            message.setLanguage(language);
            defaultLanguage = language;
        } else {
            defaultLanguage = Stanza.getDefaultLanguage();
        }
        String thread = null;
        block16: while (true) {
            int eventType = parser.next();
            switch (eventType) {
                case 2: {
                    String elementName = parser.getName();
                    String namespace = parser.getNamespace();
                    switch (elementName) {
                        case "subject": {
                            String xmlLangSubject = PacketParserUtils.getLanguageAttribute(parser);
                            if (xmlLangSubject == null) {
                                xmlLangSubject = defaultLanguage;
                            }
                            String subject = PacketParserUtils.parseElementText(parser);
                            if (message.getSubject(xmlLangSubject) != null) break;
                            message.addSubject(xmlLangSubject, subject);
                            break;
                        }
                        case "body": {
                            String xmlLang = PacketParserUtils.getLanguageAttribute(parser);
                            if (xmlLang == null) {
                                xmlLang = defaultLanguage;
                            }
                            String body = PacketParserUtils.parseElementText(parser);
                            if (message.getBody(xmlLang) != null) break;
                            message.addBody(xmlLang, body);
                            break;
                        }
                        case "thread": {
                            if (thread != null) break;
                            thread = parser.nextText();
                            break;
                        }
                        case "error": {
                            message.setError(PacketParserUtils.parseError(parser));
                            break;
                        }
                        default: {
                            PacketParserUtils.addExtensionElement(message, parser, elementName, namespace);
                            break;
                        }
                    }
                    break;
                }
                case 3: {
                    if (parser.getDepth() == initialDepth) break block16;
                }
            }
        }
        message.setThread(thread);
        return message;
    }

    public static String parseElementText(XmlPullParser parser) throws XmlPullParserException, IOException {
        String res;
        assert (parser.getEventType() == 2);
        if (parser.isEmptyElementTag()) {
            res = "";
        } else {
            int event = parser.next();
            if (event != 4) {
                if (event == 3) {
                    return "";
                }
                throw new XmlPullParserException("Non-empty element tag not followed by text, while Mixed Content (XML 3.2.2) is disallowed");
            }
            res = parser.getText();
            event = parser.next();
            if (event != 3) {
                throw new XmlPullParserException("Non-empty element tag contains child-elements, while Mixed Content (XML 3.2.2) is disallowed");
            }
        }
        return res;
    }

    public static CharSequence parseElement(XmlPullParser parser) throws XmlPullParserException, IOException {
        return PacketParserUtils.parseElement(parser, false);
    }

    public static CharSequence parseElement(XmlPullParser parser, boolean fullNamespaces) throws XmlPullParserException, IOException {
        assert (parser.getEventType() == 2);
        return PacketParserUtils.parseContentDepth(parser, parser.getDepth(), fullNamespaces);
    }

    public static CharSequence parseContent(XmlPullParser parser) throws XmlPullParserException, IOException {
        assert (parser.getEventType() == 2);
        if (parser.isEmptyElementTag()) {
            return "";
        }
        parser.next();
        return PacketParserUtils.parseContentDepth(parser, parser.getDepth(), false);
    }

    public static CharSequence parseContentDepth(XmlPullParser parser, int depth) throws XmlPullParserException, IOException {
        return PacketParserUtils.parseContentDepth(parser, depth, false);
    }

    public static CharSequence parseContentDepth(XmlPullParser parser, int depth, boolean fullNamespaces) throws XmlPullParserException, IOException {
        if (parser.getFeature(FEATURE_XML_ROUNDTRIP)) {
            return PacketParserUtils.parseContentDepthWithRoundtrip(parser, depth, fullNamespaces);
        }
        return PacketParserUtils.parseContentDepthWithoutRoundtrip(parser, depth, fullNamespaces);
    }

    /*
     * Enabled aggressive block sorting
     */
    private static CharSequence parseContentDepthWithoutRoundtrip(XmlPullParser parser, int depth, boolean fullNamespaces) throws XmlPullParserException, IOException {
        XmlStringBuilder xml = new XmlStringBuilder();
        int event = parser.getEventType();
        boolean isEmptyElement = false;
        String namespaceElement = null;
        while (true) {
            switch (event) {
                case 2: {
                    String namespace;
                    xml.halfOpenElement(parser.getName());
                    if ((namespaceElement == null || fullNamespaces) && StringUtils.isNotEmpty(namespace = parser.getNamespace())) {
                        xml.attribute("xmlns", namespace);
                        namespaceElement = parser.getName();
                    }
                    for (int i = 0; i < parser.getAttributeCount(); ++i) {
                        xml.attribute(parser.getAttributeName(i), parser.getAttributeValue(i));
                    }
                    if (parser.isEmptyElementTag()) {
                        xml.closeEmptyElement();
                        isEmptyElement = true;
                        break;
                    }
                    xml.rightAngleBracket();
                    break;
                }
                case 3: {
                    if (isEmptyElement) {
                        isEmptyElement = false;
                    } else {
                        xml.closeElement(parser.getName());
                    }
                    if (namespaceElement != null && namespaceElement.equals(parser.getName())) {
                        namespaceElement = null;
                    }
                    if (parser.getDepth() > depth) break;
                    return xml;
                }
                case 4: {
                    xml.append(parser.getText());
                }
            }
            event = parser.next();
        }
    }

    private static CharSequence parseContentDepthWithRoundtrip(XmlPullParser parser, int depth, boolean fullNamespaces) throws XmlPullParserException, IOException {
        StringBuilder sb = new StringBuilder();
        int event = parser.getEventType();
        while (true) {
            if (event != 2 || !parser.isEmptyElementTag()) {
                sb.append(parser.getText());
            }
            if (event == 3 && parser.getDepth() <= depth) break;
            event = parser.next();
        }
        return sb;
    }

    public static Presence parsePresence(XmlPullParser parser) throws XmlPullParserException, IOException, SmackException {
        ParserUtils.assertAtStartTag(parser);
        int initialDepth = parser.getDepth();
        Presence.Type type = Presence.Type.available;
        String typeString = parser.getAttributeValue("", "type");
        if (typeString != null && !typeString.equals("")) {
            type = Presence.Type.fromString(typeString);
        }
        Presence presence = new Presence(type);
        presence.setTo(ParserUtils.getJidAttribute(parser, "to"));
        presence.setFrom(ParserUtils.getJidAttribute(parser, "from"));
        presence.setStanzaId(parser.getAttributeValue("", "id"));
        String language = PacketParserUtils.getLanguageAttribute(parser);
        if (language != null && !"".equals(language.trim())) {
            presence.setLanguage(language);
        }
        block18: while (true) {
            int eventType = parser.next();
            switch (eventType) {
                case 2: {
                    String elementName = parser.getName();
                    String namespace = parser.getNamespace();
                    switch (elementName) {
                        case "status": {
                            presence.setStatus(parser.nextText());
                            break;
                        }
                        case "priority": {
                            int priority = Integer.parseInt(parser.nextText());
                            presence.setPriority(priority);
                            break;
                        }
                        case "show": {
                            String modeText = parser.nextText();
                            if (StringUtils.isNotEmpty(modeText)) {
                                presence.setMode(Presence.Mode.fromString(modeText));
                                break;
                            }
                            LOGGER.warning("Empty or null mode text in presence show element form " + presence.getFrom() + " with id '" + presence.getStanzaId() + "' which is invalid according to RFC6121 4.7.2.1");
                            break;
                        }
                        case "error": {
                            presence.setError(PacketParserUtils.parseError(parser));
                            break;
                        }
                        default: {
                            try {
                                PacketParserUtils.addExtensionElement(presence, parser, elementName, namespace);
                                break;
                            }
                            catch (Exception e) {
                                LOGGER.log(Level.WARNING, "Failed to parse extension packet in Presence packet.", e);
                            }
                        }
                    }
                }
                case 3: {
                    if (parser.getDepth() == initialDepth) break block18;
                }
                default: {
                    continue block18;
                }
            }
            break;
        }
        return presence;
    }

    /*
     * Enabled aggressive block sorting
     */
    public static IQ parseIQ(XmlPullParser parser) throws XmlPullParserException, IOException, SmackException {
        ParserUtils.assertAtStartTag(parser);
        int initialDepth = parser.getDepth();
        Stanza iqPacket = null;
        XMPPError error = null;
        String id = parser.getAttributeValue("", "id");
        Jid to = ParserUtils.getJidAttribute(parser, "to");
        Jid from = ParserUtils.getJidAttribute(parser, "from");
        IQ.Type type = IQ.Type.fromString(parser.getAttributeValue("", "type"));
        block14: while (true) {
            int eventType = parser.next();
            block0 : switch (eventType) {
                case 2: {
                    String elementName = parser.getName();
                    String namespace = parser.getNamespace();
                    switch (elementName) {
                        case "error": {
                            error = PacketParserUtils.parseError(parser);
                            break block0;
                        }
                    }
                    IQProvider<IQ> provider = ProviderManager.getIQProvider(elementName, namespace);
                    if (provider != null) {
                        iqPacket = (IQ)provider.parse(parser);
                        break;
                    }
                    iqPacket = new UnparsedIQ(elementName, namespace, PacketParserUtils.parseElement(parser));
                    break;
                }
                case 3: {
                    if (parser.getDepth() == initialDepth) break block14;
                }
            }
        }
        if (iqPacket == null) {
            switch (type) {
                case error: {
                    iqPacket = new ErrorIQ(error);
                    break;
                }
                case result: {
                    iqPacket = new EmptyResultIQ();
                    break;
                }
            }
        }
        iqPacket.setStanzaId(id);
        iqPacket.setTo(to);
        iqPacket.setFrom(from);
        ((IQ)iqPacket).setType(type);
        iqPacket.setError(error);
        return iqPacket;
    }

    public static Collection<String> parseMechanisms(XmlPullParser parser) throws XmlPullParserException, IOException {
        ArrayList<String> mechanisms = new ArrayList<String>();
        boolean done = false;
        while (!done) {
            int eventType = parser.next();
            if (eventType == 2) {
                String elementName = parser.getName();
                if (!elementName.equals("mechanism")) continue;
                mechanisms.add(parser.nextText());
                continue;
            }
            if (eventType != 3 || !parser.getName().equals("mechanisms")) continue;
            done = true;
        }
        return mechanisms;
    }

    /*
     * Exception decompiling
     */
    public static Compress.Feature parseCompressionFeature(XmlPullParser parser) throws IOException, XmlPullParserException {
        /*
         * This method has failed to decompile.  When submitting a bug report, please provide this stack trace, and (if you hold appropriate legal rights) the relevant class file.
         * 
         * org.benf.cfr.reader.util.ConfusedCFRException: Tried to end blocks [2[CASE]], but top level block is 13[SWITCH]
         *     at org.benf.cfr.reader.bytecode.analysis.opgraph.Op04StructuredStatement.processEndingBlocks(Op04StructuredStatement.java:435)
         *     at org.benf.cfr.reader.bytecode.analysis.opgraph.Op04StructuredStatement.buildNestedBlocks(Op04StructuredStatement.java:484)
         *     at org.benf.cfr.reader.bytecode.analysis.opgraph.Op03SimpleStatement.createInitialStructuredBlock(Op03SimpleStatement.java:736)
         *     at org.benf.cfr.reader.bytecode.CodeAnalyser.getAnalysisInner(CodeAnalyser.java:850)
         *     at org.benf.cfr.reader.bytecode.CodeAnalyser.getAnalysisOrWrapFail(CodeAnalyser.java:278)
         *     at org.benf.cfr.reader.bytecode.CodeAnalyser.getAnalysis(CodeAnalyser.java:201)
         *     at org.benf.cfr.reader.entities.attributes.AttributeCode.analyse(AttributeCode.java:94)
         *     at org.benf.cfr.reader.entities.Method.analyse(Method.java:531)
         *     at org.benf.cfr.reader.entities.ClassFile.analyseMid(ClassFile.java:1055)
         *     at org.benf.cfr.reader.entities.ClassFile.analyseTop(ClassFile.java:942)
         *     at org.benf.cfr.reader.Driver.doClass(Driver.java:84)
         *     at org.benf.cfr.reader.CfrDriverImpl.analyse(CfrDriverImpl.java:78)
         *     at org.benf.cfr.reader.Main.main(Main.java:54)
         */
        throw new IllegalStateException("Decompilation failed");
    }

    public static Map<String, String> parseDescriptiveTexts(XmlPullParser parser, Map<String, String> descriptiveTexts) throws XmlPullParserException, IOException {
        if (descriptiveTexts == null) {
            descriptiveTexts = new HashMap<String, String>();
        }
        String xmllang = PacketParserUtils.getLanguageAttribute(parser);
        String text = parser.nextText();
        String previousValue = descriptiveTexts.put(xmllang, text);
        assert (previousValue == null);
        return descriptiveTexts;
    }

    /*
     * Enabled aggressive block sorting
     */
    public static SaslStreamElements.SASLFailure parseSASLFailure(XmlPullParser parser) throws XmlPullParserException, IOException {
        int initialDepth = parser.getDepth();
        String condition = null;
        Map<String, String> descriptiveTexts = null;
        while (true) {
            int eventType = parser.next();
            switch (eventType) {
                case 2: {
                    String name = parser.getName();
                    if (name.equals("text")) {
                        descriptiveTexts = PacketParserUtils.parseDescriptiveTexts(parser, descriptiveTexts);
                        break;
                    }
                    assert (condition == null);
                    condition = parser.getName();
                    break;
                }
                case 3: {
                    if (parser.getDepth() != initialDepth) break;
                    return new SaslStreamElements.SASLFailure(condition, descriptiveTexts);
                }
            }
        }
    }

    /*
     * Enabled aggressive block sorting
     */
    public static StreamError parseStreamError(XmlPullParser parser) throws IOException, XmlPullParserException, SmackException {
        int initialDepth = parser.getDepth();
        ArrayList<ExtensionElement> extensions = new ArrayList<ExtensionElement>();
        Map<String, String> descriptiveTexts = null;
        StreamError.Condition condition = null;
        String conditionText = null;
        while (true) {
            int eventType = parser.next();
            switch (eventType) {
                case 2: {
                    String namespace;
                    String name = parser.getName();
                    block7 : switch (namespace = parser.getNamespace()) {
                        case "urn:ietf:params:xml:ns:xmpp-streams": {
                            switch (name) {
                                case "text": {
                                    descriptiveTexts = PacketParserUtils.parseDescriptiveTexts(parser, descriptiveTexts);
                                    break block7;
                                }
                            }
                            condition = StreamError.Condition.fromString(name);
                            if (parser.isEmptyElementTag()) break;
                            conditionText = parser.nextText();
                            break;
                        }
                        default: {
                            PacketParserUtils.addExtensionElement(extensions, parser, name, namespace);
                            break;
                        }
                    }
                    break;
                }
                case 3: {
                    if (parser.getDepth() != initialDepth) break;
                    return new StreamError(condition, conditionText, descriptiveTexts, extensions);
                }
            }
        }
    }

    /*
     * Enabled aggressive block sorting
     */
    public static XMPPError parseError(XmlPullParser parser) throws XmlPullParserException, IOException, SmackException {
        int initialDepth = parser.getDepth();
        Map<String, String> descriptiveTexts = null;
        XMPPError.Condition condition = null;
        String conditionText = null;
        ArrayList<ExtensionElement> extensions = new ArrayList<ExtensionElement>();
        XMPPError.Type errorType = XMPPError.Type.fromString(parser.getAttributeValue("", "type"));
        String errorGenerator = parser.getAttributeValue("", "by");
        while (true) {
            int eventType = parser.next();
            switch (eventType) {
                case 2: {
                    String namespace;
                    String name = parser.getName();
                    block7 : switch (namespace = parser.getNamespace()) {
                        case "urn:ietf:params:xml:ns:xmpp-stanzas": {
                            switch (name) {
                                case "text": {
                                    descriptiveTexts = PacketParserUtils.parseDescriptiveTexts(parser, descriptiveTexts);
                                    break block7;
                                }
                            }
                            condition = XMPPError.Condition.fromString(name);
                            if (parser.isEmptyElementTag()) break;
                            conditionText = parser.nextText();
                            break;
                        }
                        default: {
                            PacketParserUtils.addExtensionElement(extensions, parser, name, namespace);
                            break;
                        }
                    }
                    break;
                }
                case 3: {
                    if (parser.getDepth() != initialDepth) break;
                    return new XMPPError(condition, conditionText, errorGenerator, errorType, descriptiveTexts, extensions);
                }
            }
        }
    }

    @Deprecated
    public static ExtensionElement parsePacketExtension(String elementName, String namespace, XmlPullParser parser) throws XmlPullParserException, IOException, SmackException {
        return PacketParserUtils.parseExtensionElement(elementName, namespace, parser);
    }

    /*
     * Enabled aggressive block sorting
     */
    public static ExtensionElement parseExtensionElement(String elementName, String namespace, XmlPullParser parser) throws XmlPullParserException, IOException, SmackException {
        ParserUtils.assertAtStartTag(parser);
        ExtensionElementProvider<ExtensionElement> provider = ProviderManager.getExtensionProvider(elementName, namespace);
        if (provider != null) {
            return (ExtensionElement)provider.parse(parser);
        }
        int initialDepth = parser.getDepth();
        DefaultExtensionElement extension = new DefaultExtensionElement(elementName, namespace);
        while (true) {
            int eventType = parser.next();
            switch (eventType) {
                case 2: {
                    String name = parser.getName();
                    if (parser.isEmptyElementTag()) {
                        extension.setValue(name, "");
                        break;
                    }
                    eventType = parser.next();
                    if (eventType != 4) break;
                    String value = parser.getText();
                    extension.setValue(name, value);
                    break;
                }
                case 3: {
                    if (parser.getDepth() != initialDepth) break;
                    return extension;
                }
            }
        }
    }

    /*
     * Enabled aggressive block sorting
     */
    public static StartTls parseStartTlsFeature(XmlPullParser parser) throws XmlPullParserException, IOException {
        assert (parser.getEventType() == 2);
        assert (parser.getNamespace().equals("urn:ietf:params:xml:ns:xmpp-tls"));
        int initalDepth = parser.getDepth();
        boolean required = false;
        block10: while (true) {
            int event = parser.next();
            block0 : switch (event) {
                case 2: {
                    String name;
                    switch (name = parser.getName()) {
                        case "required": {
                            required = true;
                            break block0;
                        }
                    }
                    break;
                }
                case 3: {
                    if (parser.getDepth() == initalDepth) break block10;
                }
            }
        }
        assert (parser.getEventType() == 3);
        return new StartTls(required);
    }

    /*
     * Enabled aggressive block sorting
     */
    public static Session.Feature parseSessionFeature(XmlPullParser parser) throws XmlPullParserException, IOException {
        ParserUtils.assertAtStartTag(parser);
        int initialDepth = parser.getDepth();
        boolean optional = false;
        if (parser.isEmptyElementTag()) return new Session.Feature(optional);
        while (true) {
            int event = parser.next();
            block0 : switch (event) {
                case 2: {
                    String name;
                    switch (name = parser.getName()) {
                        case "optional": {
                            optional = true;
                            break block0;
                        }
                    }
                    break;
                }
                case 3: {
                    if (parser.getDepth() != initialDepth) break;
                    return new Session.Feature(optional);
                }
            }
        }
    }

    private static String getLanguageAttribute(XmlPullParser parser) {
        for (int i = 0; i < parser.getAttributeCount(); ++i) {
            String attributeName = parser.getAttributeName(i);
            if (!"xml:lang".equals(attributeName) && (!"lang".equals(attributeName) || !"xml".equals(parser.getAttributePrefix(i)))) continue;
            return parser.getAttributeValue(i);
        }
        return null;
    }

    @Deprecated
    public static void addPacketExtension(Stanza packet, XmlPullParser parser) throws XmlPullParserException, IOException, SmackException {
        PacketParserUtils.addExtensionElement(packet, parser);
    }

    @Deprecated
    public static void addPacketExtension(Stanza packet, XmlPullParser parser, String elementName, String namespace) throws XmlPullParserException, IOException, SmackException {
        PacketParserUtils.addExtensionElement(packet, parser, elementName, namespace);
    }

    @Deprecated
    public static void addPacketExtension(Collection<ExtensionElement> collection, XmlPullParser parser) throws XmlPullParserException, IOException, SmackException {
        PacketParserUtils.addExtensionElement(collection, parser, parser.getName(), parser.getNamespace());
    }

    @Deprecated
    public static void addPacketExtension(Collection<ExtensionElement> collection, XmlPullParser parser, String elementName, String namespace) throws XmlPullParserException, IOException, SmackException {
        PacketParserUtils.addExtensionElement(collection, parser, elementName, namespace);
    }

    public static void addExtensionElement(Stanza packet, XmlPullParser parser) throws XmlPullParserException, IOException, SmackException {
        ParserUtils.assertAtStartTag(parser);
        PacketParserUtils.addExtensionElement(packet, parser, parser.getName(), parser.getNamespace());
    }

    public static void addExtensionElement(Stanza packet, XmlPullParser parser, String elementName, String namespace) throws XmlPullParserException, IOException, SmackException {
        ExtensionElement packetExtension = PacketParserUtils.parseExtensionElement(elementName, namespace, parser);
        packet.addExtension(packetExtension);
    }

    public static void addExtensionElement(Collection<ExtensionElement> collection, XmlPullParser parser) throws XmlPullParserException, IOException, SmackException {
        PacketParserUtils.addExtensionElement(collection, parser, parser.getName(), parser.getNamespace());
    }

    public static void addExtensionElement(Collection<ExtensionElement> collection, XmlPullParser parser, String elementName, String namespace) throws XmlPullParserException, IOException, SmackException {
        ExtensionElement packetExtension = PacketParserUtils.parseExtensionElement(elementName, namespace, parser);
        collection.add(packetExtension);
    }

    static {
        boolean roundtrip = false;
        try {
            XML_PULL_PARSER_FACTORY = XmlPullParserFactory.newInstance();
            XmlPullParser xmlPullParser = XML_PULL_PARSER_FACTORY.newPullParser();
            try {
                xmlPullParser.setFeature(FEATURE_XML_ROUNDTRIP, true);
                roundtrip = true;
            }
            catch (XmlPullParserException e) {
                LOGGER.log(Level.FINEST, "XmlPullParser does not support XML_ROUNDTRIP", e);
            }
        }
        catch (XmlPullParserException e) {
            throw new AssertionError((Object)e);
        }
        XML_PULL_PARSER_SUPPORTS_ROUNDTRIP = roundtrip;
    }
}
