001/*
002 *
003 * Copyright 2017 Paul Schaub, 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.smackx.jingle_filetransfer.provider;
018
019import java.io.IOException;
020import java.text.ParseException;
021import java.util.ArrayList;
022
023import org.jivesoftware.smack.packet.XmlEnvironment;
024import org.jivesoftware.smack.parsing.SmackParsingException;
025import org.jivesoftware.smack.util.ParserUtils;
026import org.jivesoftware.smack.xml.XmlPullParser;
027import org.jivesoftware.smack.xml.XmlPullParserException;
028
029import org.jivesoftware.smackx.hashes.element.HashElement;
030import org.jivesoftware.smackx.hashes.provider.HashElementProvider;
031import org.jivesoftware.smackx.jingle.element.JingleContentDescription;
032import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionChildElement;
033import org.jivesoftware.smackx.jingle.provider.JingleContentDescriptionProvider;
034import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransfer;
035import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChild;
036import org.jivesoftware.smackx.jingle_filetransfer.element.Range;
037
038import org.jxmpp.JxmppContext;
039import org.jxmpp.util.XmppDateTime;
040
041/**
042 * Provider for JingleContentDescriptionFileTransfer elements.
043 */
044public class JingleFileTransferProvider
045        extends JingleContentDescriptionProvider<JingleFileTransfer> {
046
047    @Override
048    public JingleFileTransfer parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment, JxmppContext jxmppContext) throws XmlPullParserException, IOException, SmackParsingException, ParseException {
049        ArrayList<JingleContentDescriptionChildElement> payloads = new ArrayList<>();
050        JingleFileTransferChild.Builder builder = JingleFileTransferChild.getBuilder();
051
052
053        String elementName;
054        while (true) {
055
056            XmlPullParser.TagEvent tag = parser.nextTag();
057
058            switch (tag) {
059            case START_ELEMENT:
060                elementName = parser.getName();
061                switch (elementName) {
062                    case JingleFileTransferChild.ELEM_DATE:
063                        builder.setDate(XmppDateTime.parseXEP0082Date(parser.nextText()));
064                        break;
065
066                    case JingleFileTransferChild.ELEM_DESC:
067                        builder.setDescription(parser.nextText());
068                        break;
069
070                    case JingleFileTransferChild.ELEM_MEDIA_TYPE:
071                        builder.setMediaType(parser.nextText());
072                        break;
073
074                    case JingleFileTransferChild.ELEM_NAME:
075                        builder.setName(parser.nextText());
076                        break;
077
078                    case JingleFileTransferChild.ELEM_SIZE:
079                        builder.setSize(Integer.parseInt(parser.nextText()));
080                        break;
081
082                    case Range.ELEMENT:
083                        Range range = parseRangeElement(parser);
084                        builder.setRange(range);
085
086                        break;
087
088                    case HashElement.ELEMENT:
089                        HashElement hashElement = HashElementProvider.INSTANCE.parse(parser);
090                        builder.setHash(hashElement);
091                        break;
092                }
093                break;
094            case END_ELEMENT:
095                elementName = parser.getName();
096                switch (elementName) {
097                    case JingleFileTransferChild.ELEMENT:
098                        payloads.add(builder.build());
099                        builder = JingleFileTransferChild.getBuilder();
100                        break;
101
102                    case JingleContentDescription.ELEMENT:
103                        return new JingleFileTransfer(payloads);
104                }
105                break;
106            }
107        }
108    }
109
110    public static Range parseRangeElement(XmlPullParser parser) throws IOException, XmlPullParserException, SmackParsingException {
111        final int initialDepth = parser.getDepth();
112        final Integer offset = ParserUtils.getIntegerAttribute(parser, Range.ATTR_OFFSET);
113        final Integer length = ParserUtils.getIntegerAttribute(parser, Range.ATTR_LENGTH);
114
115        HashElement hashElement = null;
116        outerloop: while (true) {
117            String element;
118            XmlPullParser.Event event = parser.next();
119            switch (event) {
120            case START_ELEMENT:
121                element = parser.getName();
122                switch (element) {
123                case HashElement.ELEMENT:
124                    hashElement = HashElementProvider.INSTANCE.parse(parser);
125                    break;
126                }
127                break;
128            case END_ELEMENT:
129                element = parser.getName();
130                if (element.equals(Range.ELEMENT) && parser.getDepth() == initialDepth) {
131                    break outerloop;
132                }
133                break;
134            default:
135                // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
136                break;
137            }
138        }
139
140        return new Range(offset, length, hashElement);
141    }
142
143}