1 /***************************************************************************
2 begin : Sat Feb 20 2010
3 copyright : (C) 2010 by Martin Preuss
4 email : martin@libchipcard.de
5
6 ***************************************************************************
7 * Please see toplevel file COPYING for license details *
8 ***************************************************************************/
9
10
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
14
15 #define DISABLE_DEBUGLOG
16
17
18 #include "g_box_p.h"
19 #include "g_generic_l.h"
20 #include "g_table_l.h"
21 #include "g_unorderedlist_l.h"
22 #include "htmlctx_l.h"
23 #include "o_box_l.h"
24 #include "o_word_l.h"
25 #include "o_grid_l.h"
26 #include "o_image_be.h"
27
28 #include <gwenhywfar/misc.h>
29 #include <gwenhywfar/debug.h>
30
31 #include <ctype.h>
32
33
34
35
HtmlGroup_Box_new(const char * groupName,HTML_GROUP * parent,GWEN_XML_CONTEXT * ctx)36 HTML_GROUP *HtmlGroup_Box_new(const char *groupName,
37 HTML_GROUP *parent,
38 GWEN_XML_CONTEXT *ctx)
39 {
40 HTML_GROUP *g;
41
42 /* create base group */
43 g=HtmlGroup_Generic_new(groupName, parent, ctx);
44 assert(g);
45
46 /* set virtual functions */
47 HtmlGroup_SetStartTagFn(g, HtmlGroup_Box_StartTag);
48 HtmlGroup_SetAddDataFn(g, HtmlGroup_Box_AddData);
49
50 return g;
51 }
52
53
54
HtmlGroup_Box_StartTag(HTML_GROUP * g,const char * tagName)55 int HtmlGroup_Box_StartTag(HTML_GROUP *g, const char *tagName)
56 {
57 HTML_GROUP *gNew=NULL;
58 GWEN_XML_CONTEXT *ctx;
59 GWEN_DB_NODE *dbAttribs;
60
61 assert(g);
62
63 ctx=HtmlGroup_GetXmlContext(g);
64 dbAttribs=HtmlCtx_GetCurrentAttributes(ctx);
65
66 if (strcasecmp(tagName, "b")==0) {
67 /* Create new parser group with new properties but use the same object */
68 HTML_PROPS *pr;
69 HTML_FONT *fnt;
70
71 gNew=HtmlGroup_Box_new(tagName, g, ctx);
72 pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
73 fnt=HtmlProps_GetFont(pr);
74 fnt=HtmlCtx_GetFont(ctx,
75 HtmlFont_GetFontName(fnt),
76 HtmlFont_GetFontSize(fnt),
77 HtmlFont_GetFontFlags(fnt) | HTML_FONT_FLAGS_STRONG);
78 if (fnt) {
79 HtmlProps_SetFont(pr, fnt);
80 //HtmlFont_free(fnt);
81 }
82 HtmlGroup_SetProperties(gNew, pr);
83 HtmlProps_free(pr);
84 HtmlGroup_SetObject(gNew, HtmlGroup_GetObject(g));
85 }
86 else if (strcasecmp(tagName, "i")==0) {
87 /* Create new parser group with new properties but use the same object */
88 HTML_PROPS *pr;
89 HTML_FONT *fnt;
90
91 gNew=HtmlGroup_Box_new(tagName, g, ctx);
92 pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
93 fnt=HtmlProps_GetFont(pr);
94 fnt=HtmlCtx_GetFont(ctx,
95 HtmlFont_GetFontName(fnt),
96 HtmlFont_GetFontSize(fnt),
97 HtmlFont_GetFontFlags(fnt) | HTML_FONT_FLAGS_ITALIC);
98 if (fnt) {
99 HtmlProps_SetFont(pr, fnt);
100 //HtmlFont_free(fnt);
101 }
102 HtmlGroup_SetProperties(gNew, pr);
103 HtmlProps_free(pr);
104 HtmlGroup_SetObject(gNew, HtmlGroup_GetObject(g));
105 }
106 else if (strcasecmp(tagName, "u")==0) {
107 /* Create new parser group with new properties but use the same object */
108 HTML_PROPS *pr;
109 HTML_FONT *fnt;
110
111 gNew=HtmlGroup_Box_new(tagName, g, ctx);
112 pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
113 fnt=HtmlProps_GetFont(pr);
114 fnt=HtmlCtx_GetFont(ctx,
115 HtmlFont_GetFontName(fnt),
116 HtmlFont_GetFontSize(fnt),
117 HtmlFont_GetFontFlags(fnt) | HTML_FONT_FLAGS_UNDERLINE);
118 if (fnt) {
119 HtmlProps_SetFont(pr, fnt);
120 //HtmlFont_free(fnt);
121 }
122 HtmlGroup_SetProperties(gNew, pr);
123 HtmlProps_free(pr);
124 HtmlGroup_SetObject(gNew, HtmlGroup_GetObject(g));
125 }
126 else if (strcasecmp(tagName, "p")==0) {
127 HTML_OBJECT *o;
128
129 gNew=HtmlGroup_Box_new(tagName, g, ctx);
130 HtmlGroup_SetProperties(gNew, HtmlGroup_GetProperties(g));
131 o=HtmlObject_Box_new(ctx);
132 HtmlObject_AddFlags(o,
133 HTML_OBJECT_FLAGS_START_ON_NEWLINE |
134 HTML_OBJECT_FLAGS_END_WITH_NEWLINE);
135 if (dbAttribs) {
136 const char *s;
137
138 s=GWEN_DB_GetCharValue(dbAttribs, "align", 0, "left");
139 if (s) {
140 if (strcasecmp(s, "right")==0)
141 HtmlObject_AddFlags(o, HTML_OBJECT_FLAGS_JUSTIFY_RIGHT);
142 else if (strcasecmp(s, "center")==0)
143 HtmlObject_AddFlags(o, HTML_OBJECT_FLAGS_JUSTIFY_HCENTER);
144 }
145 }
146 HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
147 HtmlObject_SetProperties(o, HtmlGroup_GetProperties(g));
148 HtmlGroup_SetObject(gNew, o);
149 }
150 else if (strcasecmp(tagName, "right")==0) {
151 HTML_OBJECT *o;
152
153 gNew=HtmlGroup_Box_new(tagName, g, ctx);
154 HtmlGroup_SetProperties(gNew, HtmlGroup_GetProperties(g));
155 o=HtmlObject_Box_new(ctx);
156 HtmlObject_AddFlags(o,
157 HTML_OBJECT_FLAGS_START_ON_NEWLINE |
158 HTML_OBJECT_FLAGS_END_WITH_NEWLINE |
159 HTML_OBJECT_FLAGS_JUSTIFY_RIGHT);
160 HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
161 HtmlObject_SetProperties(o, HtmlGroup_GetProperties(g));
162 HtmlGroup_SetObject(gNew, o);
163 }
164 else if (strcasecmp(tagName, "br")==0) {
165 HTML_OBJECT *o;
166
167 /* just create and add a control object */
168 o=HtmlObject_new(ctx, HtmlObjectType_Control);
169 HtmlObject_AddFlags(o, HTML_OBJECT_FLAGS_END_WITH_NEWLINE);
170 HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
171 HtmlObject_SetProperties(o, HtmlGroup_GetProperties(g));
172 }
173 else if (strcasecmp(tagName, "img")==0) {
174 HTML_OBJECT *o;
175 GWEN_DB_NODE *dbAttribs;
176
177 o=HtmlObject_Image_new(ctx);
178 HtmlObject_AddFlags(o,
179 HTML_OBJECT_FLAGS_START_ON_NEWLINE |
180 HTML_OBJECT_FLAGS_END_WITH_NEWLINE);
181 dbAttribs=HtmlCtx_GetCurrentAttributes(ctx);
182 if (dbAttribs) {
183 const char *s;
184 int w;
185 int h;
186
187 w=GWEN_DB_GetIntValue(dbAttribs, "width", 0, -1);
188 h=GWEN_DB_GetIntValue(dbAttribs, "height", 0, -1);
189
190 /* preset */
191 if (w!=-1)
192 HtmlObject_Image_SetScaledWidth(o, w);
193 if (h!=-1)
194 HtmlObject_Image_SetScaledHeight(o, w);
195
196 s=GWEN_DB_GetCharValue(dbAttribs, "src", 0, NULL);
197 if (s && *s) {
198 HTML_IMAGE *img;
199
200 img=HtmlCtx_GetImage(ctx, s);
201 if (img) {
202 HtmlObject_Image_SetImage(o, img);
203 /* adjust scaled width and height if not set by attributes */
204 if (w==-1)
205 HtmlObject_Image_SetScaledWidth(o, HtmlImage_GetWidth(img));
206 if (h==-1)
207 HtmlObject_Image_SetScaledHeight(o, HtmlImage_GetHeight(img));
208 }
209 else {
210 DBG_ERROR(GWEN_LOGDOMAIN, "Image [%s] not found", s);
211 }
212 }
213 else {
214 DBG_ERROR(GWEN_LOGDOMAIN, "Missing image name in IMG element");
215 }
216 }
217
218 HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
219 HtmlObject_SetProperties(o, HtmlGroup_GetProperties(g));
220 }
221 else if (strcasecmp(tagName, "table")==0) {
222 HTML_OBJECT *o;
223
224 gNew=HtmlGroup_Table_new(tagName, g, ctx);
225 HtmlGroup_SetProperties(gNew, HtmlGroup_GetProperties(g));
226 o=HtmlObject_Grid_new(ctx);
227 HtmlObject_SetProperties(o, HtmlGroup_GetProperties(g));
228 HtmlGroup_SetObject(gNew, o);
229 HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
230 }
231 else if (strcasecmp(tagName, "ul")==0) {
232 HTML_OBJECT *o;
233
234 gNew=HtmlGroup_UnorderedList_new(tagName, g, ctx);
235 HtmlGroup_SetProperties(gNew, HtmlGroup_GetProperties(g));
236 o=HtmlObject_Grid_new(ctx);
237 HtmlObject_Grid_SetColumns(o, 2);
238 HtmlObject_SetProperties(o, HtmlGroup_GetProperties(g));
239 HtmlGroup_SetObject(gNew, o);
240 HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
241 }
242 else if (strcasecmp(tagName, "font")==0) {
243 /* Create new parser group with new properties but use the same object */
244 HTML_PROPS *pr;
245 GWEN_DB_NODE *dbAttribs;
246
247 gNew=HtmlGroup_Box_new(tagName, g, ctx);
248 pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
249
250 dbAttribs=HtmlCtx_GetCurrentAttributes(ctx);
251 if (dbAttribs) {
252 HTML_FONT *fnt;
253 const char *s;
254 const char *fontName;
255 int fontSize;
256 uint32_t fontFlags;
257
258 fnt=HtmlProps_GetFont(pr);
259 fontName=GWEN_DB_GetCharValue(dbAttribs, "face", 0, NULL);
260 if (fontName==NULL)
261 fontName=HtmlFont_GetFontName(fnt);
262 fontFlags=HtmlFont_GetFontFlags(fnt);
263 fontSize=HtmlFont_GetFontSize(fnt);
264 s=GWEN_DB_GetCharValue(dbAttribs, "size", 0, NULL);
265 if (s && *s) {
266 if (*s=='+') {
267 int i;
268
269 sscanf(s, "%d", &i);
270 fontSize+=i*4;
271 }
272 else if (*s=='-') {
273 int i;
274
275 sscanf(s, "%d", &i);
276 fontSize+=i*4;
277 }
278 else
279 sscanf(s, "%d", &fontSize);
280 }
281
282 s=GWEN_DB_GetCharValue(dbAttribs, "color", 0, NULL);
283 if (s && *s) {
284 uint32_t color;
285
286 color=HtmlCtx_GetColorFromName(ctx, s);
287 HtmlProps_SetForegroundColor(pr, color);
288 }
289
290 fnt=HtmlCtx_GetFont(ctx, fontName, fontSize, fontFlags);
291 if (fnt) {
292 HtmlProps_SetFont(pr, fnt);
293 //HtmlFont_free(fnt);
294 }
295 }
296
297 HtmlGroup_SetProperties(gNew, pr);
298 HtmlProps_free(pr);
299 HtmlGroup_SetObject(gNew, HtmlGroup_GetObject(g));
300 }
301 else if (strcasecmp(tagName, "h1")==0) {
302 /* Create new parser group with new properties but use the same object */
303 HTML_PROPS *pr;
304 HTML_FONT *fnt;
305 HTML_OBJECT *o;
306
307 gNew=HtmlGroup_Box_new(tagName, g, ctx);
308 pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
309 fnt=HtmlProps_GetFont(pr);
310 fnt=HtmlCtx_GetFont(ctx,
311 HtmlFont_GetFontName(fnt),
312 HtmlFont_GetFontSize(fnt)*1.8,
313 HtmlFont_GetFontFlags(fnt) | HTML_FONT_FLAGS_STRONG);
314 if (fnt) {
315 HtmlProps_SetFont(pr, fnt);
316 //HtmlFont_free(fnt);
317 }
318 HtmlGroup_SetProperties(gNew, pr);
319
320 o=HtmlObject_Box_new(ctx);
321 HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
322 HtmlObject_AddFlags(o,
323 HTML_OBJECT_FLAGS_START_ON_NEWLINE |
324 HTML_OBJECT_FLAGS_END_WITH_NEWLINE);
325 HtmlObject_SetProperties(o, pr);
326 HtmlGroup_SetObject(gNew, o);
327 HtmlProps_free(pr);
328 }
329 else if (strcasecmp(tagName, "h2")==0) {
330 /* Create new parser group with new properties but use the same object */
331 HTML_PROPS *pr;
332 HTML_FONT *fnt;
333 HTML_OBJECT *o;
334
335 gNew=HtmlGroup_Box_new(tagName, g, ctx);
336 pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
337 fnt=HtmlProps_GetFont(pr);
338 fnt=HtmlCtx_GetFont(ctx,
339 HtmlFont_GetFontName(fnt),
340 HtmlFont_GetFontSize(fnt)*1.5,
341 HtmlFont_GetFontFlags(fnt) | HTML_FONT_FLAGS_STRONG);
342 if (fnt) {
343 HtmlProps_SetFont(pr, fnt);
344 //HtmlFont_free(fnt);
345 }
346 HtmlGroup_SetProperties(gNew, pr);
347
348 o=HtmlObject_Box_new(ctx);
349 HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
350 HtmlObject_AddFlags(o,
351 HTML_OBJECT_FLAGS_START_ON_NEWLINE |
352 HTML_OBJECT_FLAGS_END_WITH_NEWLINE);
353 HtmlObject_SetProperties(o, pr);
354 HtmlGroup_SetObject(gNew, o);
355 HtmlProps_free(pr);
356 }
357 else if (strcasecmp(tagName, "h3")==0) {
358 /* Create new parser group with new properties but use the same object */
359 HTML_PROPS *pr;
360 HTML_FONT *fnt;
361 HTML_OBJECT *o;
362
363 gNew=HtmlGroup_Box_new(tagName, g, ctx);
364 pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
365 fnt=HtmlProps_GetFont(pr);
366 fnt=HtmlCtx_GetFont(ctx,
367 HtmlFont_GetFontName(fnt),
368 HtmlFont_GetFontSize(fnt),
369 HtmlFont_GetFontFlags(fnt) | HTML_FONT_FLAGS_STRONG);
370 if (fnt) {
371 HtmlProps_SetFont(pr, fnt);
372 //HtmlFont_free(fnt);
373 }
374 HtmlGroup_SetProperties(gNew, pr);
375
376 o=HtmlObject_Box_new(ctx);
377 HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
378 HtmlObject_AddFlags(o,
379 HTML_OBJECT_FLAGS_START_ON_NEWLINE |
380 HTML_OBJECT_FLAGS_END_WITH_NEWLINE);
381 HtmlObject_SetProperties(o, pr);
382 HtmlGroup_SetObject(gNew, o);
383 HtmlProps_free(pr);
384 }
385 else if (strcasecmp(tagName, "h4")==0) {
386 /* Create new parser group with new properties but use the same object */
387 HTML_PROPS *pr;
388 HTML_FONT *fnt;
389 HTML_OBJECT *o;
390
391 gNew=HtmlGroup_Box_new(tagName, g, ctx);
392 pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
393 fnt=HtmlProps_GetFont(pr);
394 fnt=HtmlCtx_GetFont(ctx,
395 HtmlFont_GetFontName(fnt),
396 HtmlFont_GetFontSize(fnt),
397 HtmlFont_GetFontFlags(fnt) | HTML_FONT_FLAGS_ITALIC);
398 if (fnt) {
399 HtmlProps_SetFont(pr, fnt);
400 //HtmlFont_free(fnt);
401 }
402 HtmlGroup_SetProperties(gNew, pr);
403
404 o=HtmlObject_Box_new(ctx);
405 HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
406 HtmlObject_AddFlags(o,
407 HTML_OBJECT_FLAGS_START_ON_NEWLINE |
408 HTML_OBJECT_FLAGS_END_WITH_NEWLINE);
409 HtmlObject_SetProperties(o, pr);
410 HtmlGroup_SetObject(gNew, o);
411 HtmlProps_free(pr);
412 }
413 else if (strcasecmp(tagName, "html")==0 ||
414 strcasecmp(tagName, "body")==0) {
415 }
416 else {
417 DBG_WARN(GWEN_LOGDOMAIN,
418 "Unknown group [%s], handling as normal box", tagName);
419 gNew=HtmlGroup_Box_new(tagName, g, ctx);
420 HtmlGroup_SetProperties(gNew, HtmlGroup_GetProperties(g));
421 HtmlGroup_SetObject(gNew, HtmlGroup_GetObject(g));
422 }
423
424 if (gNew) {
425 HtmlCtx_SetCurrentGroup(ctx, gNew);
426 GWEN_XmlCtx_IncDepth(ctx);
427 }
428
429 return 0;
430 }
431
432
433
HtmlGroup_Box_AddData(HTML_GROUP * g,const char * data)434 int HtmlGroup_Box_AddData(HTML_GROUP *g, const char *data)
435 {
436 GWEN_XML_CONTEXT *ctx;
437 GWEN_BUFFER *buf;
438 int rv;
439 uint8_t *s;
440 HTML_OBJECT *o;
441
442 assert(g);
443
444 ctx=HtmlGroup_GetXmlContext(g);
445 if (data && *data) {
446 buf=GWEN_Buffer_new(0, strlen(data), 0, 1);
447 rv=HtmlCtx_SanitizeData(ctx, data, buf);
448 if (rv<0) {
449 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
450 GWEN_Buffer_free(buf);
451 return rv;
452 }
453 if (GWEN_Buffer_GetUsedBytes(buf)) {
454 s=(uint8_t *)GWEN_Buffer_GetStart(buf);
455
456 while (*s) {
457 uint8_t *t;
458 uint8_t c;
459
460 /* find begin of word */
461 while (*s && isspace(*s))
462 s++;
463
464 /* find end of word */
465 t=s;
466 while (*t && !isspace(*t))
467 t++;
468 c=*t;
469 *t=0;
470 o=HtmlObject_Word_new(ctx, (const char *) s);
471 HtmlObject_SetProperties(o, HtmlGroup_GetProperties(g));
472 HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
473 *t=c;
474 s=t;
475 }
476 }
477 GWEN_Buffer_free(buf);
478 }
479
480 return 0;
481 }
482
483
484
485