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 static org.xmlpull.v1.XmlPullParser.END_TAG; 020import static org.xmlpull.v1.XmlPullParser.START_TAG; 021 022import java.util.ArrayList; 023import java.util.HashSet; 024import java.util.List; 025import java.util.Set; 026 027import org.jivesoftware.smack.SmackException; 028import org.jivesoftware.smack.provider.ExtensionElementProvider; 029import org.jivesoftware.smack.util.ParserUtils; 030import org.jivesoftware.smackx.message_markup.element.BlockQuoteElement; 031import org.jivesoftware.smackx.message_markup.element.CodeBlockElement; 032import org.jivesoftware.smackx.message_markup.element.ListElement; 033import org.jivesoftware.smackx.message_markup.element.MarkupElement; 034import org.jivesoftware.smackx.message_markup.element.SpanElement; 035 036import org.xmlpull.v1.XmlPullParser; 037 038public class MarkupElementProvider extends ExtensionElementProvider<MarkupElement> { 039 040 @Override 041 public MarkupElement parse(XmlPullParser parser, int initialDepth) throws Exception { 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 int tag = parser.next(); 053 String name = parser.getName(); 054 int start, end; 055 switch (tag) { 056 case START_TAG: 057 switch (name) { 058 case BlockQuoteElement.ELEMENT: 059 start = ParserUtils.getIntegerAttributeOrThrow(parser, BlockQuoteElement.ATTR_START, 060 "Message Markup BlockQuoteElement MUST contain a 'start' attribute."); 061 end = ParserUtils.getIntegerAttributeOrThrow(parser, BlockQuoteElement.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, CodeBlockElement.ATTR_START, 068 "Message Markup CodeBlockElement MUST contain a 'start' attribute."); 069 end = ParserUtils.getIntegerAttributeOrThrow(parser, CodeBlockElement.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, SpanElement.ATTR_START, 077 "Message Markup SpanElement MUST contain a 'start' attribute."); 078 spanEnd = ParserUtils.getIntegerAttributeOrThrow(parser, SpanElement.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, ListElement.ATTR_START, 097 "Message Markup ListElement MUST contain a 'start' attribute."); 098 listEnd = ParserUtils.getIntegerAttributeOrThrow(parser, ListElement.ATTR_END, 099 "Message Markup ListElement MUST contain a 'end' attribute."); 100 break; 101 102 case ListElement.ELEM_LI: 103 start = ParserUtils.getIntegerAttributeOrThrow(parser, ListElement.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_TAG: 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 throw new SmackException("Error while parsing incoming MessageMarkup ListElement: " + 121 "'start' attribute of first 'li' element must equal 'start' attribute of list."); 122 } 123 for (int i = 0; i < lis.size(); i++) { 124 int elemStart = lis.get(i).getStart(); 125 int elemEnd = i < lis.size() - 1 ? lis.get(i + 1).getStart() : listEnd; 126 listBuilder.addEntry(elemStart, elemEnd); 127 } 128 listBuilder.endList(); 129 break; 130 131 case MarkupElement.ELEMENT: 132 return markup.build(); 133 } 134 135 } 136 } 137 } 138 139}