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 {
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                    try {
063                        builder.setDate(XmppDateTime.parseXEP0082Date(parser.nextText()));
064                    } catch (ParseException e) {
065                        throw new SmackParsingException.SmackTextParseException(e);
066                    }
067                        break;
068
069                    case JingleFileTransferChild.ELEM_DESC:
070                        builder.setDescription(parser.nextText());
071                        break;
072
073                    case JingleFileTransferChild.ELEM_MEDIA_TYPE:
074                        builder.setMediaType(parser.nextText());
075                        break;
076
077                    case JingleFileTransferChild.ELEM_NAME:
078                        builder.setName(parser.nextText());
079                        break;
080
081                    case JingleFileTransferChild.ELEM_SIZE:
082                        builder.setSize(Integer.parseInt(parser.nextText()));
083                        break;
084
085                    case Range.ELEMENT:
086                        Range range = parseRangeElement(parser);
087                        builder.setRange(range);
088
089                        break;
090
091                    case HashElement.ELEMENT:
092                        HashElement hashElement = HashElementProvider.INSTANCE.parse(parser);
093                        builder.setHash(hashElement);
094                        break;
095                }
096                break;
097            case END_ELEMENT:
098                elementName = parser.getName();
099                switch (elementName) {
100                    case JingleFileTransferChild.ELEMENT:
101                        payloads.add(builder.build());
102                        builder = JingleFileTransferChild.getBuilder();
103                        break;
104
105                    case JingleContentDescription.ELEMENT:
106                        return new JingleFileTransfer(payloads);
107                }
108                break;
109            }
110        }
111    }
112
113    public static Range parseRangeElement(XmlPullParser parser) throws IOException, XmlPullParserException, SmackParsingException {
114        final int initialDepth = parser.getDepth();
115        final Integer offset = ParserUtils.getIntegerAttribute(parser, Range.ATTR_OFFSET);
116        final Integer length = ParserUtils.getIntegerAttribute(parser, Range.ATTR_LENGTH);
117
118        HashElement hashElement = null;
119        outerloop: while (true) {
120            String element;
121            XmlPullParser.Event event = parser.next();
122            switch (event) {
123            case START_ELEMENT:
124                element = parser.getName();
125                switch (element) {
126                case HashElement.ELEMENT:
127                    hashElement = HashElementProvider.INSTANCE.parse(parser);
128                    break;
129                }
130                break;
131            case END_ELEMENT:
132                element = parser.getName();
133                if (element.equals(Range.ELEMENT) && parser.getDepth() == initialDepth) {
134                    break outerloop;
135                }
136                break;
137            default:
138                // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
139                break;
140            }
141        }
142
143        return new Range(offset, length, hashElement);
144    }
145
146}