Mercurial Hosting > luan
annotate src/luan/modules/parsers/BBCode.java @ 1247:728d8e75f476
html encode bbcode
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Tue, 17 Jul 2018 22:17:01 -0600 |
parents | 88b5b81cad4a |
children | 475905984870 |
rev | line source |
---|---|
585 | 1 package luan.modules.parsers; |
2 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
3 import java.util.List; |
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
4 import java.util.ArrayList; |
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
5 import luan.Luan; |
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
6 import luan.LuanState; |
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
7 import luan.LuanFunction; |
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
8 import luan.LuanException; |
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
9 import luan.modules.Utils; |
1247 | 10 import luan.modules.HtmlLuan; |
1111
88b5b81cad4a
move Parser to luan.lib.parser
Franklin Schmidt <fschmidt@gmail.com>
parents:
777
diff
changeset
|
11 import luan.lib.parser.Parser; |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
12 |
585 | 13 |
14 public final class BBCode { | |
15 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
16 public static String toHtml(LuanState luan,String bbcode,LuanFunction quoter) throws LuanException { |
638 | 17 return new BBCode(luan,bbcode,quoter,true).parse(); |
585 | 18 } |
19 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
20 public static String toText(LuanState luan,String bbcode,LuanFunction quoter) throws LuanException { |
638 | 21 return new BBCode(luan,bbcode,quoter,false).parse(); |
585 | 22 } |
23 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
24 private final LuanState luan; |
585 | 25 private final Parser parser; |
638 | 26 private final LuanFunction quoter; |
585 | 27 private final boolean toHtml; |
28 | |
638 | 29 private BBCode(LuanState luan,String text,LuanFunction quoter,boolean toHtml) throws LuanException { |
646
cdc70de628b5
simplify LuanException
Franklin Schmidt <fschmidt@gmail.com>
parents:
638
diff
changeset
|
30 Utils.checkNotNull(text,1); |
777
1460d297e960
add bbcode to blog example
Franklin Schmidt <fschmidt@gmail.com>
parents:
775
diff
changeset
|
31 // Utils.checkNotNull(quoter,2); |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
32 this.luan = luan; |
585 | 33 this.parser = new Parser(text); |
638 | 34 this.quoter = quoter; |
585 | 35 this.toHtml = toHtml; |
36 } | |
37 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
38 private String parse() throws LuanException { |
585 | 39 StringBuilder sb = new StringBuilder(); |
1247 | 40 StringBuilder text = new StringBuilder(); |
585 | 41 while( !parser.endOfInput() ) { |
42 String block = parseBlock(); | |
1247 | 43 if( block != null ) { |
44 sb.append( textToString(text) ); | |
585 | 45 sb.append(block); |
1247 | 46 } else { |
47 text.append( parser.currentChar() ); | |
585 | 48 parser.anyChar(); |
49 } | |
50 } | |
1247 | 51 sb.append( textToString(text) ); |
585 | 52 return sb.toString(); |
53 } | |
54 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
55 private String parseWellFormed() throws LuanException { |
585 | 56 StringBuilder sb = new StringBuilder(); |
1247 | 57 StringBuilder text = new StringBuilder(); |
585 | 58 while( !parser.endOfInput() ) { |
59 String block = parseBlock(); | |
60 if( block != null ) { | |
1247 | 61 sb.append( textToString(text) ); |
585 | 62 sb.append(block); |
63 continue; | |
64 } | |
65 if( couldBeTag() ) | |
66 break; | |
1247 | 67 text.append( parser.currentChar() ); |
585 | 68 parser.anyChar(); |
69 } | |
1247 | 70 sb.append( textToString(text) ); |
585 | 71 return sb.toString(); |
72 } | |
73 | |
1247 | 74 private String textToString(StringBuilder text) throws LuanException { |
75 String s = text.toString(); | |
76 text.setLength(0); | |
77 if( toHtml ) | |
78 s = HtmlLuan.encode(s); | |
79 return s; | |
80 } | |
81 | |
585 | 82 private boolean couldBeTag() { |
83 if( parser.currentChar() != '[' ) | |
84 return false; | |
85 return parser.testIgnoreCase("[b]") | |
86 || parser.testIgnoreCase("[/b]") | |
87 || parser.testIgnoreCase("[i]") | |
88 || parser.testIgnoreCase("[/i]") | |
89 || parser.testIgnoreCase("[u]") | |
90 || parser.testIgnoreCase("[/u]") | |
91 || parser.testIgnoreCase("[url]") | |
92 || parser.testIgnoreCase("[url=") | |
93 || parser.testIgnoreCase("[/url]") | |
94 || parser.testIgnoreCase("[code]") | |
95 || parser.testIgnoreCase("[/code]") | |
96 || parser.testIgnoreCase("[img]") | |
97 || parser.testIgnoreCase("[/img]") | |
98 || parser.testIgnoreCase("[color=") | |
99 || parser.testIgnoreCase("[/color]") | |
100 || parser.testIgnoreCase("[size=") | |
101 || parser.testIgnoreCase("[/size]") | |
102 || parser.testIgnoreCase("[youtube]") | |
103 || parser.testIgnoreCase("[/youtube]") | |
104 || parser.testIgnoreCase("[quote]") | |
105 || parser.testIgnoreCase("[quote=") | |
106 || parser.testIgnoreCase("[/quote]") | |
107 ; | |
108 } | |
109 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
110 private String parseBlock() throws LuanException { |
585 | 111 if( parser.currentChar() != '[' ) |
112 return null; | |
113 String s; | |
114 s = parseB(); if(s!=null) return s; | |
115 s = parseI(); if(s!=null) return s; | |
116 s = parseU(); if(s!=null) return s; | |
117 s = parseUrl1(); if(s!=null) return s; | |
118 s = parseUrl2(); if(s!=null) return s; | |
119 s = parseCode(); if(s!=null) return s; | |
120 s = parseImg(); if(s!=null) return s; | |
121 s = parseColor(); if(s!=null) return s; | |
122 s = parseSize(); if(s!=null) return s; | |
123 s = parseYouTube(); if(s!=null) return s; | |
124 s = parseQuote1(); if(s!=null) return s; | |
125 s = parseQuote2(); if(s!=null) return s; | |
126 return null; | |
127 } | |
128 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
129 private String parseB() throws LuanException { |
585 | 130 parser.begin(); |
131 if( !parser.matchIgnoreCase("[b]") ) | |
132 return parser.failure(null); | |
133 String content = parseWellFormed(); | |
134 if( !parser.matchIgnoreCase("[/b]") ) | |
135 return parser.failure(null); | |
136 String rtn = toHtml ? "<b>"+content+"</b>" : content; | |
137 return parser.success(rtn); | |
138 } | |
139 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
140 private String parseI() throws LuanException { |
585 | 141 parser.begin(); |
142 if( !parser.matchIgnoreCase("[i]") ) | |
143 return parser.failure(null); | |
144 String content = parseWellFormed(); | |
145 if( !parser.matchIgnoreCase("[/i]") ) | |
146 return parser.failure(null); | |
147 String rtn = toHtml ? "<i>"+content+"</i>" : content; | |
148 return parser.success(rtn); | |
149 } | |
150 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
151 private String parseU() throws LuanException { |
585 | 152 parser.begin(); |
153 if( !parser.matchIgnoreCase("[u]") ) | |
154 return parser.failure(null); | |
155 String content = parseWellFormed(); | |
156 if( !parser.matchIgnoreCase("[/u]") ) | |
157 return parser.failure(null); | |
158 String rtn = toHtml ? "<u>"+content+"</u>" : content; | |
159 return parser.success(rtn); | |
160 } | |
161 | |
162 private String parseUrl1() { | |
163 parser.begin(); | |
164 if( !parser.matchIgnoreCase("[url]") ) | |
165 return parser.failure(null); | |
166 String url = parseRealUrl(); | |
167 if( !parser.matchIgnoreCase("[/url]") ) | |
168 return parser.failure(null); | |
169 String rtn = toHtml ? "<a href='"+url+"'>"+url+"</u>" : url; | |
170 return parser.success(rtn); | |
171 } | |
172 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
173 private String parseUrl2() throws LuanException { |
585 | 174 parser.begin(); |
175 if( !parser.matchIgnoreCase("[url=") ) | |
176 return parser.failure(null); | |
177 String url = parseRealUrl(); | |
178 if( !parser.match(']') ) | |
179 return parser.failure(null); | |
180 String content = parseWellFormed(); | |
181 if( !parser.matchIgnoreCase("[/url]") ) | |
182 return parser.failure(null); | |
183 String rtn = toHtml ? "<a href='"+url+"'>"+content+"</u>" : content; | |
184 return parser.success(rtn); | |
185 } | |
186 | |
187 private String parseRealUrl() { | |
188 parser.begin(); | |
189 while( parser.match(' ') ); | |
190 int start = parser.currentIndex(); | |
191 if( !parser.matchIgnoreCase("http") ) | |
192 return parser.failure(null); | |
193 parser.matchIgnoreCase("s"); | |
194 if( !parser.matchIgnoreCase("://") ) | |
195 return parser.failure(null); | |
196 while( parser.noneOf(" []'") ); | |
197 String url = parser.textFrom(start); | |
198 while( parser.match(' ') ); | |
199 return parser.success(url); | |
200 } | |
201 | |
202 private String parseCode() { | |
203 parser.begin(); | |
204 if( !parser.matchIgnoreCase("[code]") ) | |
205 return parser.failure(null); | |
206 int start = parser.currentIndex(); | |
207 while( !parser.testIgnoreCase("[/code]") ) { | |
208 if( !parser.anyChar() ) | |
209 return parser.failure(null); | |
210 } | |
211 String content = parser.textFrom(start); | |
212 if( !parser.matchIgnoreCase("[/code]") ) throw new RuntimeException(); | |
213 String rtn = toHtml ? "<code>"+content+"</code>" : content; | |
214 return parser.success(rtn); | |
215 } | |
216 | |
217 private String parseImg() { | |
218 parser.begin(); | |
219 if( !parser.matchIgnoreCase("[img]") ) | |
220 return parser.failure(null); | |
221 String url = parseRealUrl(); | |
222 if( !parser.matchIgnoreCase("[/img]") ) | |
223 return parser.failure(null); | |
224 String rtn = toHtml ? "<img src='"+url+"'>" : ""; | |
225 return parser.success(rtn); | |
226 } | |
227 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
228 private String parseColor() throws LuanException { |
585 | 229 parser.begin(); |
230 if( !parser.matchIgnoreCase("[color=") ) | |
231 return parser.failure(null); | |
232 int start = parser.currentIndex(); | |
233 parser.match('#'); | |
234 while( parser.inCharRange('0','9') | |
235 || parser.inCharRange('a','z') | |
236 || parser.inCharRange('A','Z') | |
237 ); | |
238 String color = parser.textFrom(start); | |
239 if( !parser.match(']') ) | |
240 return parser.failure(null); | |
241 String content = parseWellFormed(); | |
242 if( !parser.matchIgnoreCase("[/color]") ) | |
243 return parser.failure(null); | |
244 String rtn = toHtml ? "<span style='color: "+color+"'>"+content+"</span>" : content; | |
245 return parser.success(rtn); | |
246 } | |
247 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
248 private String parseSize() throws LuanException { |
585 | 249 parser.begin(); |
250 if( !parser.matchIgnoreCase("[size=") ) | |
251 return parser.failure(null); | |
252 int start = parser.currentIndex(); | |
253 while( parser.match('.') || parser.inCharRange('0','9') ); | |
254 String size = parser.textFrom(start); | |
255 if( !parser.match(']') ) | |
256 return parser.failure(null); | |
257 String content = parseWellFormed(); | |
258 if( !parser.matchIgnoreCase("[/size]") ) | |
259 return parser.failure(null); | |
260 String rtn = toHtml ? "<span style='font-size: "+size+"em'>"+content+"</span>" : content; | |
261 return parser.success(rtn); | |
262 } | |
263 | |
264 private String parseYouTube() { | |
265 parser.begin(); | |
266 if( !parser.matchIgnoreCase("[youtube]") ) | |
267 return parser.failure(null); | |
268 int start = parser.currentIndex(); | |
269 while( parser.inCharRange('0','9') | |
270 || parser.inCharRange('a','z') | |
271 || parser.inCharRange('A','Z') | |
272 || parser.match('-') | |
273 || parser.match('_') | |
274 ); | |
275 String id = parser.textFrom(start); | |
276 if( id.length()==0 || !parser.matchIgnoreCase("[/youtube]") ) | |
277 return parser.failure(null); | |
278 String rtn = toHtml ? "<iframe width='420' height='315' src='https://www.youtube.com/embed/"+id+"' frameborder='0' allowfullscreen></iframe>" : ""; | |
279 return parser.success(rtn); | |
280 } | |
281 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
282 private String quote(Object... args) throws LuanException { |
777
1460d297e960
add bbcode to blog example
Franklin Schmidt <fschmidt@gmail.com>
parents:
775
diff
changeset
|
283 if( quoter==null ) |
1460d297e960
add bbcode to blog example
Franklin Schmidt <fschmidt@gmail.com>
parents:
775
diff
changeset
|
284 throw new LuanException("BBCode quoter function not defined"); |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
285 Object obj = quoter.call(luan,args); |
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
286 if( !(obj instanceof String) ) |
646
cdc70de628b5
simplify LuanException
Franklin Schmidt <fschmidt@gmail.com>
parents:
638
diff
changeset
|
287 throw new LuanException("BBCode quoter function returned "+Luan.type(obj)+" but string required"); |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
288 return (String)obj; |
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
289 } |
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
290 |
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
291 private String parseQuote1() throws LuanException { |
585 | 292 parser.begin(); |
293 if( !parser.matchIgnoreCase("[quote]") ) | |
294 return parser.failure(null); | |
295 String content = parseWellFormed(); | |
296 if( !parser.matchIgnoreCase("[/quote]") ) | |
297 return parser.failure(null); | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
298 String rtn = quote(content); |
585 | 299 return parser.success(rtn); |
300 } | |
301 | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
302 private String parseQuote2() throws LuanException { |
585 | 303 parser.begin(); |
304 if( !parser.matchIgnoreCase("[quote=") ) | |
305 return parser.failure(null); | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
306 List args = new ArrayList(); |
585 | 307 int start = parser.currentIndex(); |
308 while( parser.noneOf("[];") ); | |
309 String name = parser.textFrom(start).trim(); | |
310 if( name.length() == 0 ) | |
311 return parser.failure(null); | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
312 args.add(name); |
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
313 while( parser.match(';') ) { |
585 | 314 start = parser.currentIndex(); |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
315 while( parser.noneOf("[];'") ); |
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
316 String src = parser.textFrom(start).trim(); |
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
317 args.add(src); |
585 | 318 } |
319 if( !parser.match(']') ) | |
320 return parser.failure(null); | |
321 String content = parseWellFormed(); | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
322 args.add(0,content); |
585 | 323 if( !parser.matchIgnoreCase("[/quote]") ) |
324 return parser.failure(null); | |
637
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
325 String rtn = quote(args.toArray()); |
6ea90dc10375
bbcode parser now takes a quoter function
Franklin Schmidt <fschmidt@gmail.com>
parents:
588
diff
changeset
|
326 return parser.success(rtn); |
585 | 327 } |
328 | |
329 } |