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