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