don't crash when loading images > 65kB (fixes #13529)
[swfdec.git] / libswfdec / swfdec_text_field_movie_html.c
blob1a007a997c7c8de88ac867ab6992cb5c49f072c3
1 /* Swfdec
2 * Copyright (C) 2007 Pekka Lampila <pekka.lampila@iki.fi>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include <stdlib.h>
25 #include <string.h>
27 #include "swfdec_text_field_movie.h"
28 #include "swfdec_as_strings.h"
29 #include "swfdec_style_sheet.h"
30 #include "swfdec_xml.h"
31 #include "swfdec_debug.h"
34 * Parsing
36 typedef struct {
37 const char * name;
38 int name_length;
39 guint index;
40 guint end_index;
41 SwfdecTextFormat *format;
42 } ParserTag;
44 typedef struct {
45 SwfdecAsContext *cx;
46 gboolean multiline;
47 gboolean condense_white;
48 SwfdecStyleSheet *style_sheet;
49 GString * text;
50 GSList * tags_open;
51 GSList * tags_closed;
52 } ParserData;
54 static void
55 swfdec_text_field_movie_html_parse_close_tag (ParserData *data, ParserTag *tag)
57 g_return_if_fail (data != NULL);
58 g_return_if_fail (tag != NULL);
60 if (data->multiline &&
61 ((tag->name_length == 1 && !g_strncasecmp (tag->name, "p", 1)) ||
62 (tag->name_length == 2 && !g_strncasecmp (tag->name, "li", 2))))
64 GSList *iter;
66 for (iter = data->tags_closed; iter != NULL; iter = iter->next) {
67 ParserTag *f = iter->data;
68 if (f->end_index < tag->index)
69 break;
70 if (f->name_length == 4 && !g_strncasecmp (f->name, "font", 4)) {
71 ParserTag *n = g_new0 (ParserTag, 1);
72 n->name = f->name;
73 n->name_length = f->name_length;
74 n->index = data->text->len;
75 n->end_index = n->index + 1;
76 if (f->format != NULL) {
77 n->format = swfdec_text_format_copy (f->format);
78 } else {
79 n->format = NULL;
81 data->tags_closed = g_slist_prepend (data->tags_closed, n);
82 break;
85 data->text = g_string_append_c (data->text, '\n');
88 tag->end_index = data->text->len;
90 data->tags_open = g_slist_remove (data->tags_open, tag);
91 data->tags_closed = g_slist_prepend (data->tags_closed, tag);
94 static const char *
95 swfdec_text_field_movie_html_parse_comment (ParserData *data, const char *p)
97 const char *end;
99 g_return_val_if_fail (data != NULL, NULL);
100 g_return_val_if_fail (p != NULL, NULL);
101 g_return_val_if_fail (strncmp (p, "<!--", strlen ("<!--")) == 0, NULL);
103 end = strstr (p + strlen ("<!--"), "-->");
104 if (end != NULL)
105 end += strlen("-->");
107 // return NULL if no end found
108 return end;
111 static void
112 swfdec_text_field_movie_html_tag_set_attribute (ParserData *data,
113 ParserTag *tag, const char *name, int name_length, const char *value,
114 int value_length)
116 SwfdecAsValue val;
117 SwfdecAsObject *object;
119 g_return_if_fail (data != NULL);
120 g_return_if_fail (tag != NULL);
121 g_return_if_fail (name != NULL);
122 g_return_if_fail (name_length >= 0);
123 g_return_if_fail (value != NULL);
124 g_return_if_fail (value_length >= 0);
126 if (!tag->format)
127 return;
129 object = SWFDEC_AS_OBJECT (tag->format);
130 SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_give_string (
131 object->context, g_strndup (value, value_length)));
133 if (tag->name_length == 10 && !g_strncasecmp (tag->name, "textformat", 10))
135 if (name_length == 10 && !g_strncasecmp (name, "leftmargin", 10))
137 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_leftMargin, &val);
139 else if (name_length == 11 && !g_strncasecmp (name, "rightmargin", 11))
141 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_rightMargin, &val);
143 else if (name_length == 6 && !g_strncasecmp (name, "indent", 6))
145 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_indent, &val);
147 else if (name_length == 11 && !g_strncasecmp (name, "blockindent", 11))
149 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_blockIndent, &val);
151 else if (name_length == 8 && !g_strncasecmp (name, "tabstops", 8))
153 // FIXME
154 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_tabStops, &val);
157 else if (tag->name_length == 1 && !g_strncasecmp (tag->name, "p", 1))
159 if (name_length == 5 && !g_strncasecmp (name, "align", 5))
161 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_align, &val);
164 else if (tag->name_length == 4 && !g_strncasecmp (tag->name, "font", 4))
166 if (name_length == 4 && !g_strncasecmp (name, "face", 4))
168 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_font, &val);
170 else if (name_length == 4 && !g_strncasecmp (name, "size", 4))
172 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_size, &val);
174 else if (name_length == 5 && !g_strncasecmp (name, "color", 5))
176 SwfdecAsValue val_number;
178 if (value_length != 7 || *value != '#') {
179 SWFDEC_AS_VALUE_SET_NUMBER (&val_number, 0);
180 } else {
181 int number;
182 char *tail;
184 number = g_ascii_strtoll (value + 1, &tail, 16);
185 if (tail != value + 7)
186 number = 0;
187 SWFDEC_AS_VALUE_SET_NUMBER (&val_number, number);
190 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_color, &val_number);
192 else if (name_length == 13 && !g_strncasecmp (name, "letterspacing", 13))
194 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_letterSpacing,
195 &val);
197 // special case: Don't parse kerning
199 else if (tag->name_length == 1 && !g_strncasecmp (tag->name, "a", 1))
201 if (name_length == 4 && !g_strncasecmp (name, "href", 4))
203 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_url, &val);
205 else if (name_length == 6 && !g_strncasecmp (name, "target", 6))
207 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_target, &val);
211 if (data->style_sheet &&
212 ((tag->name_length == 2 && !g_strncasecmp (tag->name, "li", 2)) ||
213 (tag->name_length == 4 && !g_strncasecmp (tag->name, "span", 4)) ||
214 (tag->name_length == 1 && !g_strncasecmp (tag->name, "p", 1))))
216 if (name_length == 5 && !g_strncasecmp (name, "class", 5)) {
217 SwfdecTextFormat *format = swfdec_style_sheet_get_class_format (
218 data->style_sheet, swfdec_as_context_give_string (data->cx,
219 g_strndup (value, value_length)));
220 if (format != NULL)
221 swfdec_text_format_add (tag->format, format);
226 static const char *
227 swfdec_text_field_movie_html_parse_attribute (ParserData *data, ParserTag *tag,
228 const char *p)
230 const char *end, *name, *value;
231 int name_length, value_length;
233 g_return_val_if_fail (data != NULL, NULL);
234 g_return_val_if_fail (tag != NULL, NULL);
235 g_return_val_if_fail ((*p != '>' && *p != '\0'), NULL);
237 end = p + strcspn (p, "=> \r\n\t");
238 if (end - p <= 0)
239 return NULL; // Correct?
241 name = p;
242 name_length = end - p;
244 p = end + strspn (end, " \r\n\t");
245 if (*p != '=')
246 return NULL; // FIXME: Correct?
247 p = p + 1;
248 p = p + strspn (p, " \r\n\t");
250 if (*p != '"' && *p != '\'')
251 return NULL; // FIXME: Correct?
253 end = p + 1;
254 do {
255 end = strchr (end, *p);
256 } while (end != NULL && *(end - 1) == '\\');
258 if (end == NULL)
259 return NULL; // FIXME: Correct?
261 value = p + 1;
262 value_length = end - (p + 1);
264 if (tag != NULL) {
265 swfdec_text_field_movie_html_tag_set_attribute (data, tag, name,
266 name_length, value, value_length);
269 g_return_val_if_fail (end + 1 > p, NULL);
271 return end + 1;
274 static const char *
275 swfdec_text_field_movie_html_parse_tag (ParserData *data, const char *p)
277 ParserTag *tag;
278 const char *name, *end;
279 int name_length;
280 gboolean close;
282 g_return_val_if_fail (data != NULL, NULL);
283 g_return_val_if_fail (p != NULL, NULL);
284 g_return_val_if_fail (*p == '<', NULL);
286 p++;
288 // closing tag or opening tag?
289 if (*p == '/') {
290 close = TRUE;
291 p++;
292 } else {
293 close = FALSE;
296 // find the end of the name
297 end = p + strcspn (p, "> \r\n\t");
299 if (*end == '\0')
300 return NULL;
302 // don't count trailing / as part of the name if it's followed by >
303 // we still act like it's a normal opening tag even if it has /
304 if (*end == '>' && *(end - 1) == '/')
305 end = end - 1;
307 if (end == p) // empty name
308 return NULL;
310 name = p;
311 name_length = end - p;
313 if (close)
315 if (data->tags_open != NULL) {
316 tag = data->tags_open->data;
317 if (name_length == tag->name_length &&
318 !g_strncasecmp (name, tag->name, name_length))
319 swfdec_text_field_movie_html_parse_close_tag (data, tag);
322 end = strchr (end, '>');
323 if (end != NULL)
324 end += 1;
326 else
328 SwfdecAsObject *object;
329 SwfdecAsValue val;
331 if (data->multiline) {
332 if (name_length == 2 && !g_strncasecmp (name, "br", 2))
334 data->text = g_string_append_c (data->text, '\n');
336 else if ((name_length == 1 && !g_strncasecmp (name, "p", 1)) ||
337 (name_length == 2 && !g_strncasecmp (name, "li", 2)) ||
338 (name_length == 2 && !g_strncasecmp (name, "br", 2)))
340 GSList *iter;
342 for (iter = data->tags_open; iter != NULL; iter = iter->next) {
343 ParserTag *f = iter->data;
344 if ((f->name_length == 1 && !g_strncasecmp (f->name, "p", 1)) ||
345 (f->name_length == 2 && !g_strncasecmp (f->name, "li", 2))) {
346 data->text = g_string_append_c (data->text, '\n');
347 break;
353 tag = g_new0 (ParserTag, 1);
354 tag->name = name;
355 tag->name_length = name_length;
356 tag->format = SWFDEC_TEXT_FORMAT (swfdec_text_format_new (data->cx));
357 tag->index = data->text->len;
359 data->tags_open = g_slist_prepend (data->tags_open, tag);
361 // set format based on tag
362 if (tag->format != NULL) {
363 object = SWFDEC_AS_OBJECT (tag->format);
364 SWFDEC_AS_VALUE_SET_BOOLEAN (&val, TRUE);
366 if (tag->name_length == 2 && !g_strncasecmp (tag->name, "li", 2)) {
367 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_bullet, &val);
368 } else if (tag->name_length == 1 && !g_strncasecmp (tag->name, "b", 1)) {
369 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_bold, &val);
370 } else if (tag->name_length == 1 && !g_strncasecmp (tag->name, "i", 1)) {
371 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_italic, &val);
372 } else if (tag->name_length == 1 && !g_strncasecmp (tag->name, "u", 1)) {
373 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_underline, &val);
375 else if (tag->name_length == 3 && !g_strncasecmp (tag->name, "img", 3))
377 SWFDEC_FIXME ("IMG tag support for TextField's HTML input missing");
381 if (data->style_sheet &&
382 ((tag->name_length == 2 && !g_strncasecmp (tag->name, "li", 2)) ||
383 (tag->name_length == 1 && !g_strncasecmp (tag->name, "p", 1)))) {
384 SwfdecTextFormat *format = swfdec_style_sheet_get_tag_format (
385 data->style_sheet, swfdec_as_context_give_string (data->cx,
386 g_strndup (tag->name, tag->name_length)));
387 if (format != NULL)
388 swfdec_text_format_add (tag->format, format);
391 // parse attributes
392 end = end + strspn (end, " \r\n\t");
393 while (*end != '\0' && *end != '>' && (*end != '/' || *(end + 1) != '>')) {
394 end = swfdec_text_field_movie_html_parse_attribute (data, tag, end);
395 if (end == NULL)
396 break;
397 end = end + strspn (end, " \r\n\t");
399 if (end != NULL) {
400 if (*end == '/')
401 end += 1;
402 if (*end == '>')
403 end += 1;
407 return end;
410 static const char *
411 swfdec_text_field_movie_html_parse_text (ParserData *data, const char *p)
413 const char *end;
414 char *unescaped;
416 g_return_val_if_fail (data != NULL, NULL);
417 g_return_val_if_fail (p != NULL, NULL);
418 g_return_val_if_fail (*p != '\0' && *p != '<', NULL);
420 // get the text
421 // if condense_white: all whitespace blocks are converted to a single space
422 while (*p != '\0' && *p != '<') {
423 if (data->condense_white) {
424 end = p + strcspn (p, "< \n\r\t");
425 } else {
426 end = strchr (p, '<');
427 if (end == NULL)
428 end = strchr (p, '\0');
431 unescaped = swfdec_xml_unescape_len (data->cx, p, end - p);
432 data->text = g_string_append (data->text, unescaped);
433 g_free (unescaped);
435 if (data->condense_white && g_ascii_isspace (*end)) {
436 data->text = g_string_append_c (data->text, ' ');
437 p = end + strspn (end, " \n\r\t");
438 } else {
439 p = end;
443 return p;
446 void
447 swfdec_text_field_movie_html_parse (SwfdecTextFieldMovie *text, const char *str)
449 ParserData data;
450 const char *p;
452 g_return_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text));
453 g_return_if_fail (str != NULL);
455 text->input = g_string_assign (text->input, "");
457 data.cx = SWFDEC_AS_OBJECT (text)->context;
458 data.multiline = (data.cx->version < 7 || text->text->multiline);
459 data.condense_white = text->condense_white;
460 if (text->style_sheet != NULL && SWFDEC_IS_STYLESHEET (text->style_sheet)) {
461 data.style_sheet = SWFDEC_STYLESHEET (text->style_sheet);
462 } else {
463 data.style_sheet = NULL;
465 data.text = text->input;
466 data.tags_open = NULL;
467 data.tags_closed = NULL;
469 p = str;
470 while (p != NULL && *p != '\0') {
471 if (*p == '<') {
472 if (strncmp (p + 1, "!--", strlen ("!--")) == 0) {
473 p = swfdec_text_field_movie_html_parse_comment (&data, p);
474 } else {
475 p = swfdec_text_field_movie_html_parse_tag (&data, p);
477 } else {
478 p = swfdec_text_field_movie_html_parse_text (&data, p);
482 // close remaining tags
483 while (data.tags_open != NULL) {
484 swfdec_text_field_movie_html_parse_close_tag (&data,
485 (ParserTag *)data.tags_open->data);
488 // add parsed styles
489 while (data.tags_closed != NULL) {
490 ParserTag *tag = (ParserTag *)data.tags_closed->data;
492 if (tag->index != tag->end_index && tag->format != NULL) {
493 swfdec_text_field_movie_set_text_format (text, tag->format, tag->index,
494 tag->end_index);
497 g_free (tag);
498 data.tags_closed = g_slist_remove (data.tags_closed, tag);
503 * Generating
505 static const char *
506 swfdec_text_field_movie_html_text_align_to_string (SwfdecTextAlign align)
508 switch (align) {
509 case SWFDEC_TEXT_ALIGN_LEFT:
510 return "LEFT";
511 case SWFDEC_TEXT_ALIGN_RIGHT:
512 return "RIGHT";
513 case SWFDEC_TEXT_ALIGN_CENTER:
514 return "CENTER";
515 case SWFDEC_TEXT_ALIGN_JUSTIFY:
516 return "JUSTIFY";
517 default:
518 g_assert_not_reached ();
523 * Order of tags:
524 * TEXTFORMAT / P or LI / FONT / A / B / I / U
526 * Order of attributes:
527 * TEXTFORMAT:
528 * LEFTMARGIN / RIGHTMARGIN / INDENT / LEADING / BLOCKINDENT / TABSTOPS
529 * P: ALIGN
530 * LI: none
531 * FONT: FACE / SIZE / COLOR / LETTERSPACING / KERNING
532 * A: HREF / TARGET
533 * B: none
534 * I: none
535 * U: none
537 static GString *
538 swfdec_text_field_movie_html_text_append_paragraph (SwfdecTextFieldMovie *text,
539 GString *string, guint start_index, guint end_index)
541 SwfdecTextFormat *format, *format_prev, *format_font;
542 GSList *iter, *fonts, *iter_font;
543 guint index_, index_prev;
544 gboolean textformat, bullet, font;
545 char *escaped;
547 g_return_val_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text), string);
548 g_return_val_if_fail (string != NULL, string);
549 g_return_val_if_fail (start_index <= end_index, string);
551 g_return_val_if_fail (text->formats != NULL, string);
552 for (iter = text->formats; iter->next != NULL &&
553 ((SwfdecFormatIndex *)(iter->next->data))->index_ <= start_index;
554 iter = iter->next);
556 index_ = start_index;
557 format = ((SwfdecFormatIndex *)(iter->data))->format;
559 if (format->left_margin != 0 || format->right_margin != 0 ||
560 format->indent != 0 || format->leading != 0 ||
561 format->block_indent != 0 ||
562 swfdec_as_array_get_length (format->tab_stops) > 0)
564 string = g_string_append (string, "<TEXTFORMAT");
565 if (format->left_margin) {
566 g_string_append_printf (string, " LEFTMARGIN=\"%i\"",
567 format->left_margin);
569 if (format->right_margin) {
570 g_string_append_printf (string, " RIGHTMARGIN=\"%i\"",
571 format->right_margin);
573 if (format->indent)
574 g_string_append_printf (string, " INDENT=\"%i\"", format->indent);
575 if (format->leading)
576 g_string_append_printf (string, " LEADING=\"%i\"", format->leading);
577 if (format->block_indent) {
578 g_string_append_printf (string, " BLOCKINDENT=\"%i\"",
579 format->block_indent);
581 if (swfdec_as_array_get_length (format->tab_stops) > 0) {
582 SwfdecAsValue val;
583 SWFDEC_AS_VALUE_SET_OBJECT (&val, SWFDEC_AS_OBJECT (format->tab_stops));
584 g_string_append_printf (string, " TABSTOPS=\"%s\"",
585 swfdec_as_value_to_string (SWFDEC_AS_OBJECT
586 (format->tab_stops)->context, &val));
588 string = g_string_append (string, ">");
590 textformat = TRUE;
592 else
594 textformat = FALSE;
597 if (format->bullet) {
598 string = g_string_append (string, "<LI>");
599 bullet = TRUE;
600 } else {
601 g_string_append_printf (string, "<P ALIGN=\"%s\">",
602 swfdec_text_field_movie_html_text_align_to_string (format->align));
603 bullet = FALSE;
606 // note we don't escape format->font, even thought it can have evil chars
607 g_string_append_printf (string, "<FONT FACE=\"%s\" SIZE=\"%i\" COLOR=\"#%06X\" LETTERSPACING=\"%i\" KERNING=\"%i\">",
608 format->font, format->size, format->color, (int)format->letter_spacing,
609 (format->kerning ? 1 : 0));
610 fonts = g_slist_prepend (NULL, format);
612 if (format->url != SWFDEC_AS_STR_EMPTY)
613 g_string_append_printf (string, "<A HREF=\"%s\" TARGET=\"%s\">",
614 format->url, format->target);
615 if (format->bold)
616 string = g_string_append (string, "<B>");
617 if (format->italic)
618 string = g_string_append (string, "<I>");
619 if (format->underline)
620 string = g_string_append (string, "<U>");
622 // special case: use <= instead of < to add some extra markup
623 for (iter = iter->next;
624 iter != NULL && ((SwfdecFormatIndex *)(iter->data))->index_ <= end_index;
625 iter = iter->next)
627 index_prev = index_;
628 format_prev = format;
629 index_ = ((SwfdecFormatIndex *)(iter->data))->index_;
630 format = ((SwfdecFormatIndex *)(iter->data))->format;
632 escaped = swfdec_xml_escape_len (text->input->str + index_prev,
633 index_ - index_prev);
634 string = g_string_append (string, escaped);
635 g_free (escaped);
636 escaped = NULL;
638 // Figure out what tags need to be rewritten
639 if (format->font != format_prev->font ||
640 format->size != format_prev->size ||
641 format->color != format_prev->color ||
642 (int)format->letter_spacing != (int)format_prev->letter_spacing ||
643 format->kerning != format_prev->kerning) {
644 font = TRUE;
645 } else if (format->url == format_prev->url &&
646 format->target == format_prev->target &&
647 format->bold == format_prev->bold &&
648 format->italic == format_prev->italic &&
649 format->underline == format_prev->underline) {
650 continue;
653 // Close tags
654 for (iter_font = fonts; iter_font != NULL; iter_font = iter_font->next)
656 format_font = (SwfdecTextFormat *)iter_font->data;
657 if (format->font == format_font->font &&
658 format->size == format_font->size &&
659 format->color == format_font->color &&
660 (int)format->letter_spacing == (int)format_font->letter_spacing &&
661 format->kerning == format_font->kerning) {
662 break;
665 if (format_prev->underline)
666 string = g_string_append (string, "</U>");
667 if (format_prev->italic)
668 string = g_string_append (string, "</I>");
669 if (format_prev->bold)
670 string = g_string_append (string, "</B>");
671 if (format_prev->url != SWFDEC_AS_STR_EMPTY)
672 string = g_string_append (string, "</A>");
673 if (iter_font != NULL) {
674 while (fonts != iter_font) {
675 string = g_string_append (string, "</FONT>");
676 fonts = g_slist_remove (fonts, fonts->data);
680 // Open tags
681 format_font = (SwfdecTextFormat *)fonts->data;
682 if (font && (format->font != format_font->font ||
683 format->size != format_font->size ||
684 format->color != format_font->color ||
685 (int)format->letter_spacing != (int)format_font->letter_spacing ||
686 format->kerning != format_font->kerning))
688 fonts = g_slist_prepend (fonts, format);
690 string = g_string_append (string, "<FONT");
691 // note we don't escape format->font, even thought it can have evil chars
692 if (format->font != format_font->font)
693 g_string_append_printf (string, " FACE=\"%s\"", format->font);
694 if (format->size != format_font->size)
695 g_string_append_printf (string, " SIZE=\"%i\"", format->size);
696 if (format->color != format_font->color)
697 g_string_append_printf (string, " COLOR=\"#%06X\"", format->color);
698 if ((int)format->letter_spacing != (int)format_font->letter_spacing) {
699 g_string_append_printf (string, " LETTERSPACING=\"%i\"",
700 (int)format->letter_spacing);
702 if (format->kerning != format_font->kerning) {
703 g_string_append_printf (string, " KERNING=\"%i\"",
704 (format->kerning ? 1 : 0));
706 string = g_string_append (string, ">");
708 if (format->url != SWFDEC_AS_STR_EMPTY) {
709 g_string_append_printf (string, "<A HREF=\"%s\" TARGET=\"%s\">",
710 format->url, format->target);
712 if (format->bold)
713 string = g_string_append (string, "<B>");
714 if (format->italic)
715 string = g_string_append (string, "<I>");
716 if (format->underline)
717 string = g_string_append (string, "<U>");
720 escaped = swfdec_xml_escape_len (text->input->str + index_,
721 end_index - index_);
722 string = g_string_append (string, escaped);
723 g_free (escaped);
725 if (format->underline)
726 string = g_string_append (string, "</U>");
727 if (format->italic)
728 string = g_string_append (string, "</I>");
729 if (format->bold)
730 string = g_string_append (string, "</B>");
731 if (format->url != SWFDEC_AS_STR_EMPTY)
732 string = g_string_append (string, "</A>");
733 for (iter = fonts; iter != NULL; iter = iter->next)
734 string = g_string_append (string, "</FONT>");
735 g_slist_free (fonts);
736 if (bullet) {
737 string = g_string_append (string, "</LI>");
738 } else {
739 string = g_string_append (string, "</P>");
741 if (textformat)
742 string = g_string_append (string, "</TEXTFORMAT>");
744 return string;
747 const char *
748 swfdec_text_field_movie_get_html_text (SwfdecTextFieldMovie *text)
750 const char *p, *end;
751 GString *string;
753 g_return_val_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text),
754 SWFDEC_AS_STR_EMPTY);
756 if (text->input == NULL)
757 return SWFDEC_AS_STR_EMPTY;
759 string = g_string_new ("");
761 p = text->input->str;
762 while (*p != '\0') {
763 end = strpbrk (p, "\r\n");
764 if (end == NULL)
765 end = strchr (p, '\0');
767 string = swfdec_text_field_movie_html_text_append_paragraph (text, string,
768 p - text->input->str, end - text->input->str);
770 p = end;
771 if (*p != '\0') p++;
774 return swfdec_as_context_give_string (SWFDEC_AS_OBJECT (text)->context,
775 g_string_free (string, FALSE));