001/* 002 * 003 * Copyright © 2018 Paul Schaub 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.message_markup.provider; 018 019import java.io.IOException; 020import java.util.ArrayList; 021import java.util.HashSet; 022import java.util.List; 023import java.util.Set; 024 025import org.jivesoftware.smack.packet.XmlEnvironment; 026import org.jivesoftware.smack.provider.ExtensionElementProvider; 027import org.jivesoftware.smack.util.ParserUtils; 028import org.jivesoftware.smack.xml.XmlPullParser; 029import org.jivesoftware.smack.xml.XmlPullParserException; 030 031import org.jivesoftware.smackx.message_markup.element.BlockQuoteElement; 032import org.jivesoftware.smackx.message_markup.element.CodeBlockElement; 033import org.jivesoftware.smackx.message_markup.element.ListElement; 034import org.jivesoftware.smackx.message_markup.element.MarkupElement; 035import org.jivesoftware.smackx.message_markup.element.MarkupElement.MarkupChildElement; 036import org.jivesoftware.smackx.message_markup.element.SpanElement; 037 038import org.jxmpp.JxmppContext; 039 040public class MarkupElementProvider extends ExtensionElementProvider<MarkupElement> { 041 042 @Override 043 public MarkupElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment, JxmppContext jxmppContext) throws IOException, XmlPullParserException { 044 045 MarkupElement.Builder markup = MarkupElement.getBuilder(); 046 047 int spanStart = -1, spanEnd = -1; 048 Set<SpanElement.SpanStyle> spanStyles = new HashSet<>(); 049 050 int listStart = -1, listEnd = -1; 051 List<ListElement.ListEntryElement> lis = new ArrayList<>(); 052 053 while (true) { 054 XmlPullParser.Event tag = parser.next(); 055 String name; 056 int start, end; 057 switch (tag) { 058 case START_ELEMENT: 059 name = parser.getName(); 060 switch (name) { 061 case BlockQuoteElement.ELEMENT: 062 start = ParserUtils.getIntegerAttributeOrThrow(parser, MarkupChildElement.ATTR_START, 063 "Message Markup BlockQuoteElement MUST contain a 'start' attribute."); 064 end = ParserUtils.getIntegerAttributeOrThrow(parser, MarkupChildElement.ATTR_END, 065 "Message Markup BlockQuoteElement MUST contain a 'end' attribute."); 066 markup.setBlockQuote(start, end); 067 break; 068 069 case CodeBlockElement.ELEMENT: 070 start = ParserUtils.getIntegerAttributeOrThrow(parser, MarkupChildElement.ATTR_START, 071 "Message Markup CodeBlockElement MUST contain a 'start' attribute."); 072 end = ParserUtils.getIntegerAttributeOrThrow(parser, MarkupChildElement.ATTR_END, 073 "Message Markup CodeBlockElement MUST contain a 'end' attribute."); 074 markup.setCodeBlock(start, end); 075 break; 076 077 case SpanElement.ELEMENT: 078 spanStyles = new HashSet<>(); 079 spanStart = ParserUtils.getIntegerAttributeOrThrow(parser, MarkupChildElement.ATTR_START, 080 "Message Markup SpanElement MUST contain a 'start' attribute."); 081 spanEnd = ParserUtils.getIntegerAttributeOrThrow(parser, MarkupChildElement.ATTR_END, 082 "Message Markup SpanElement MUST contain a 'end' attribute."); 083 break; 084 085 case SpanElement.code: 086 spanStyles.add(SpanElement.SpanStyle.code); 087 break; 088 089 case SpanElement.emphasis: 090 spanStyles.add(SpanElement.SpanStyle.emphasis); 091 break; 092 093 case SpanElement.deleted: 094 spanStyles.add(SpanElement.SpanStyle.deleted); 095 break; 096 097 case ListElement.ELEMENT: 098 lis = new ArrayList<>(); 099 listStart = ParserUtils.getIntegerAttributeOrThrow(parser, MarkupChildElement.ATTR_START, 100 "Message Markup ListElement MUST contain a 'start' attribute."); 101 listEnd = ParserUtils.getIntegerAttributeOrThrow(parser, MarkupChildElement.ATTR_END, 102 "Message Markup ListElement MUST contain a 'end' attribute."); 103 break; 104 105 case ListElement.ListEntryElement.ELEMENT: 106 start = ParserUtils.getIntegerAttributeOrThrow(parser, MarkupChildElement.ATTR_START, 107 "Message Markup ListElement 'li' MUST contain a 'start' attribute."); 108 lis.add(new ListElement.ListEntryElement(start)); 109 break; 110 } 111 break; 112 113 case END_ELEMENT: 114 if (parser.getDepth() == initialDepth) { 115 return markup.build(); 116 } 117 118 name = parser.getName(); 119 switch (name) { 120 case SpanElement.ELEMENT: 121 markup.addSpan(spanStart, spanEnd, spanStyles); 122 spanStart = -1; spanEnd = -1; 123 break; 124 125 case ListElement.ELEMENT: 126 MarkupElement.Builder.ListBuilder listBuilder = markup.beginList(); 127 if (lis.size() > 0 && lis.get(0).getStart() != listStart) { 128 // TODO: Should be SmackParseException. 129 throw new IOException("Error while parsing incoming MessageMarkup ListElement: " + 130 "'start' attribute of first 'li' element must equal 'start' attribute of list."); 131 } 132 for (int i = 0; i < lis.size(); i++) { 133 int elemStart = lis.get(i).getStart(); 134 int elemEnd = i < lis.size() - 1 ? lis.get(i + 1).getStart() : listEnd; 135 listBuilder.addEntry(elemStart, elemEnd); 136 } 137 listBuilder.endList(); 138 break; 139 } 140 break; 141 142 default: 143 // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement. 144 break; 145 } 146 } 147 } 148 149}