| 371 |
371 |
| 372 /** |
372 /** |
| 373 * \internal Zamienia tekst z formatowaniem Gadu-Gadu na HTML. |
373 * \internal Zamienia tekst z formatowaniem Gadu-Gadu na HTML. |
| 374 * |
374 * |
| 375 * \param dst Bufor wynikowy (może być \c NULL) |
375 * \param dst Bufor wynikowy (może być \c NULL) |
| 376 * \param src Tekst źródłowy w UTF-8 |
376 * \param src Tekst źródłowy |
| |
377 * \param encoding Kodowanie tekstu źródłowego oraz wynikowego |
| 377 * \param format Atrybuty tekstu źródłowego |
378 * \param format Atrybuty tekstu źródłowego |
| 378 * \param format_len Długość bloku atrybutów tekstu źródłowego |
379 * \param format_len Długość bloku atrybutów tekstu źródłowego |
| 379 * |
380 * |
| 380 * \note Wynikowy tekst nie jest idealnym kodem HTML, ponieważ ma jak |
381 * \note Wynikowy tekst nie jest idealnym kodem HTML, ponieważ ma jak |
| 381 * dokładniej odzwierciedlać to, co wygenerowałby oryginalny klient. |
382 * dokładniej odzwierciedlać to, co wygenerowałby oryginalny klient. |
| 382 * |
383 * |
| 383 * \note Dokleja \c \\0 na końcu bufora wynikowego. |
384 * \note Dokleja \c \\0 na końcu bufora wynikowego. |
| 384 * |
385 * |
| 385 * \return Długość tekstu wynikowego bez \c \\0 (nawet jeśli \c dst to \c NULL). |
386 * \return Długość tekstu wynikowego bez \c \\0 (nawet jeśli \c dst to \c NULL). |
| 386 */ |
387 */ |
| 387 size_t gg_message_text_to_html(char *dst, const char *src, const char *format, size_t format_len) |
388 size_t gg_message_text_to_html(char *dst, const char *src, gg_encoding_t encoding, const unsigned char *format, size_t format_len) |
| 388 { |
389 { |
| 389 const char span_fmt[] = "<span style=\"color:#%02x%02x%02x; font-family:'MS Shell Dlg 2'; font-size:9pt; \">"; |
390 const char span_fmt[] = "<span style=\"color:#%02x%02x%02x; font-family:'MS Shell Dlg 2'; font-size:9pt; \">"; |
| 390 const int span_len = 75; |
391 const size_t span_len = 75; |
| 391 const char img_fmt[] = "<img name=\"%02x%02x%02x%02x%02x%02x%02x%02x\">"; |
392 const char img_fmt[] = "<img name=\"%02x%02x%02x%02x%02x%02x%02x%02x\">"; |
| 392 const int img_len = 29; |
393 const size_t img_len = 29; |
| 393 int char_pos = 0; |
394 size_t char_pos = 0; |
| 394 int format_idx = 0; |
|
| 395 unsigned char old_attr = 0; |
395 unsigned char old_attr = 0; |
| 396 const unsigned char *color = (const unsigned char*) "\x00\x00\x00"; |
396 const unsigned char default_color[] = {'\x00', '\x00', '\x00'}; |
| 397 int i; |
397 const unsigned char *old_color = NULL; |
| 398 size_t len; |
398 int in_span = 0; |
| 399 const unsigned char *format_ = (const unsigned char*) format; |
399 unsigned int i; |
| 400 |
400 size_t len = 0; |
| 401 len = 0; |
|
| 402 |
|
| 403 /* Nie mamy atrybutów dla pierwsze znaku, a tekst nie jest pusty, więc |
|
| 404 * tak czy inaczej trzeba otworzyć <span>. */ |
|
| 405 |
|
| 406 if (src[0] != 0 && (format_idx + 3 > format_len || (format_[format_idx] | (format_[format_idx + 1] << 8)) != 0)) { |
|
| 407 if (dst != NULL) |
|
| 408 sprintf(&dst[len], span_fmt, 0, 0, 0); |
|
| 409 |
|
| 410 len += span_len; |
|
| 411 } |
|
| 412 |
401 |
| 413 /* Pętla przechodzi też przez kończące \0, żeby móc dokleić obrazek |
402 /* Pętla przechodzi też przez kończące \0, żeby móc dokleić obrazek |
| 414 * na końcu tekstu. */ |
403 * na końcu tekstu. */ |
| 415 |
404 |
| 416 for (i = 0; ; i++) { |
405 for (i = 0; ; i++) { |
| 417 /* Analizuj atrybuty tak długo jak dotyczą aktualnego znaku. */ |
406 int in_char = 0; |
| |
407 size_t format_idx = 0; |
| |
408 |
| |
409 /* Sprawdź, czy bajt jest kontynuacją znaku UTF-8. */ |
| |
410 if (encoding == GG_ENCODING_UTF8 && (src[i] & 0xc0) == 0x80) |
| |
411 in_char = 1; |
| |
412 |
| |
413 /* GG_FONT_IMAGE powinno dotyczyć tylko jednego znaku, więc czyścimy stary atrybut */ |
| |
414 |
| |
415 if (!in_char && (old_attr & GG_FONT_IMAGE) != 0) |
| |
416 old_attr &= ~GG_FONT_IMAGE; |
| |
417 |
| |
418 /* Analizuj wszystkie atrybuty dotyczące aktualnego znaku. */ |
| 418 for (;;) { |
419 for (;;) { |
| 419 unsigned char attr; |
420 unsigned char attr; |
| 420 int attr_pos; |
421 size_t attr_pos; |
| |
422 |
| |
423 /* Nie wstawiamy niczego wewnątrz wielobajtowego znaku UTF-8. */ |
| |
424 if (in_char) |
| |
425 break; |
| 421 |
426 |
| 422 if (format_idx + 3 > format_len) |
427 if (format_idx + 3 > format_len) |
| 423 break; |
428 break; |
| 424 |
429 |
| 425 attr_pos = format_[format_idx] | (format_[format_idx + 1] << 8); |
430 attr_pos = format[format_idx] | (format[format_idx + 1] << 8); |
| 426 |
431 attr = format[format_idx + 2]; |
| 427 if (attr_pos != char_pos) |
|
| 428 break; |
|
| 429 |
|
| 430 attr = format_[format_idx + 2]; |
|
| 431 |
432 |
| 432 /* Nie doklejaj atrybutów na końcu, co najwyżej obrazki. */ |
433 /* Nie doklejaj atrybutów na końcu, co najwyżej obrazki. */ |
| 433 |
434 |
| 434 if (src[i] == 0) |
435 if (src[i] == 0) |
| 435 attr &= ~(GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR); |
436 attr &= ~(GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR); |
| 436 |
437 |
| 437 format_idx += 3; |
438 format_idx += 3; |
| 438 |
439 |
| 439 if ((attr & (GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR)) != 0 || (attr == 0 && old_attr != 0)) { |
440 if (attr_pos != char_pos) { |
| 440 if (char_pos != 0) { |
441 if ((attr & GG_FONT_COLOR) != 0) |
| 441 if ((old_attr & GG_FONT_UNDERLINE) != 0) |
442 format_idx += 3; |
| 442 gg_append(dst, &len, "</u>", 4); |
443 if ((attr & GG_FONT_IMAGE) != 0) |
| 443 |
444 format_idx += 10; |
| 444 if ((old_attr & GG_FONT_ITALIC) != 0) |
445 |
| 445 gg_append(dst, &len, "</i>", 4); |
446 continue; |
| 446 |
447 } |
| 447 if ((old_attr & GG_FONT_BOLD) != 0) |
448 |
| 448 gg_append(dst, &len, "</b>", 4); |
449 if ((old_attr & GG_FONT_UNDERLINE) != 0) |
| 449 |
450 gg_append(dst, &len, "</u>", 4); |
| 450 if (src[i] != 0) |
451 |
| 451 gg_append(dst, &len, "</span>", 7); |
452 if ((old_attr & GG_FONT_ITALIC) != 0) |
| 452 } |
453 gg_append(dst, &len, "</i>", 4); |
| |
454 |
| |
455 if ((old_attr & GG_FONT_BOLD) != 0) |
| |
456 gg_append(dst, &len, "</b>", 4); |
| |
457 |
| |
458 if ((attr & (GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR)) != 0) { |
| |
459 const unsigned char *color; |
| 453 |
460 |
| 454 if (((attr & GG_FONT_COLOR) != 0) && (format_idx + 3 <= format_len)) { |
461 if (((attr & GG_FONT_COLOR) != 0) && (format_idx + 3 <= format_len)) { |
| 455 color = &format_[format_idx]; |
462 color = &format[format_idx]; |
| 456 format_idx += 3; |
463 format_idx += 3; |
| 457 } else { |
464 } else { |
| 458 color = (unsigned char*) "\x00\x00\x00"; |
465 color = default_color; |
| 459 } |
466 } |
| 460 |
467 |
| 461 if (src[i] != 0) { |
468 if (old_color == NULL || memcmp(color, old_color, 3) != 0) { |
| 462 if (dst != NULL) |
469 if (in_span) { |
| 463 sprintf(&dst[len], span_fmt, color[0], color[1], color[2]); |
470 gg_append(dst, &len, "</span>", 7); |
| 464 len += span_len; |
471 in_span = 0; |
| |
472 } |
| |
473 |
| |
474 if (src[i] != 0) { |
| |
475 if (dst != NULL) |
| |
476 sprintf(&dst[len], span_fmt, color[0], color[1], color[2]); |
| |
477 |
| |
478 len += span_len; |
| |
479 in_span = 1; |
| |
480 old_color = color; |
| |
481 } |
| 465 } |
482 } |
| 466 } else if (char_pos == 0 && src[0] != 0) { |
|
| 467 if (dst != NULL) |
|
| 468 sprintf(&dst[len], span_fmt, 0, 0, 0); |
|
| 469 len += span_len; |
|
| 470 } |
483 } |
| 471 |
484 |
| 472 if ((attr & GG_FONT_BOLD) != 0) |
485 if ((attr & GG_FONT_BOLD) != 0) |
| 473 gg_append(dst, &len, "<b>", 3); |
486 gg_append(dst, &len, "<b>", 3); |
| 474 |
487 |
| 479 gg_append(dst, &len, "<u>", 3); |
492 gg_append(dst, &len, "<u>", 3); |
| 480 |
493 |
| 481 if (((attr & GG_FONT_IMAGE) != 0) && (format_idx + 10 <= format_len)) { |
494 if (((attr & GG_FONT_IMAGE) != 0) && (format_idx + 10 <= format_len)) { |
| 482 if (dst != NULL) { |
495 if (dst != NULL) { |
| 483 sprintf(&dst[len], img_fmt, |
496 sprintf(&dst[len], img_fmt, |
| 484 format_[format_idx + 9], |
497 format[format_idx + 9], |
| 485 format_[format_idx + 8], |
498 format[format_idx + 8], |
| 486 format_[format_idx + 7], |
499 format[format_idx + 7], |
| 487 format_[format_idx + 6], |
500 format[format_idx + 6], |
| 488 format_[format_idx + 5], |
501 format[format_idx + 5], |
| 489 format_[format_idx + 4], |
502 format[format_idx + 4], |
| 490 format_[format_idx + 3], |
503 format[format_idx + 3], |
| 491 format_[format_idx + 2]); |
504 format[format_idx + 2]); |
| 492 } |
505 } |
| 493 |
506 |
| 494 len += img_len; |
507 len += img_len; |
| 495 format_idx += 10; |
508 format_idx += 10; |
| 496 } |
509 } |
| 497 |
510 |
| 498 old_attr = attr; |
511 old_attr = attr; |
| |
512 } |
| |
513 |
| |
514 if (src[i] == 0) |
| |
515 break; |
| |
516 |
| |
517 /* Znaki oznaczone jako GG_FONT_IMAGE nie są częścią wiadomości. */ |
| |
518 |
| |
519 if ((old_attr & GG_FONT_IMAGE) != 0) { |
| |
520 if (!in_char) |
| |
521 char_pos++; |
| |
522 |
| |
523 continue; |
| |
524 } |
| |
525 |
| |
526 /* Jesteśmy na początku tekstu i choć nie było atrybutów dla pierwszego |
| |
527 * znaku, ponieważ tekst nie jest pusty, trzeba otworzyć <span>. */ |
| |
528 |
| |
529 if (!in_span) { |
| |
530 if (dst != NULL) |
| |
531 sprintf(&dst[len], span_fmt, default_color[0], default_color[1], default_color[2]); |
| |
532 |
| |
533 len += span_len; |
| |
534 in_span = 1; |
| |
535 old_color = default_color; |
| 499 } |
536 } |
| 500 |
537 |
| 501 /* Doklej znak zachowując htmlowe escapowanie. */ |
538 /* Doklej znak zachowując htmlowe escapowanie. */ |
| 502 |
539 |
| 503 switch (src[i]) { |
540 switch (src[i]) { |
| 546 gg_append(dst, &len, "</i>", 4); |
577 gg_append(dst, &len, "</i>", 4); |
| 547 |
578 |
| 548 if ((old_attr & GG_FONT_BOLD) != 0) |
579 if ((old_attr & GG_FONT_BOLD) != 0) |
| 549 gg_append(dst, &len, "</b>", 4); |
580 gg_append(dst, &len, "</b>", 4); |
| 550 |
581 |
| 551 if (src[0] != 0) |
582 if (in_span) |
| 552 gg_append(dst, &len, "</span>", 7); |
583 gg_append(dst, &len, "</span>", 7); |
| 553 |
584 |
| 554 if (dst != NULL) |
585 if (dst != NULL) |
| 555 dst[len] = 0; |
586 dst[len] = 0; |
| 556 |
587 |
| 557 return len; |
588 return len; |
| 558 } |
589 } |
| 559 |
590 |
| 560 /** |
591 /** |
| |
592 * \internal Dokleja nowe atrybuty formatowania, jeśli konieczne, oraz inkrementuje pozycję znaku w tekście. |
| |
593 * |
| |
594 * \param pos Wskaźnik na zmienną przechowującą pozycję znaku w tekście |
| |
595 * \param attr_flag Aktualna flaga atrybutu formatowania |
| |
596 * \param old_attr_flag Wskaźnik na poprzednią flagę atrybutu formatowania |
| |
597 * \param color Wskaźnik na tablicę z aktualnym kolorem RGB (jeśli \p attr_flag nie zawiera flagi \c GG_FONT_COLOR, ignorowane) |
| |
598 * \param old_color Wskaźnik na tablicę z poprzednim kolorem RGB |
| |
599 * \param imgs_size Rozmiar atrybutów formatowania obrazków znajdujących się obecnie w tablicy atrybutów formatowania, w bajtach |
| |
600 * \param format Wskaźnik na wskaźnik do tablicy atrybutów formatowania |
| |
601 * \param format_len Wskaźnik na zmienną zawierającą długość tablicy atrybutów formatowania, w bajtach (może być \c NULL) |
| |
602 */ |
| |
603 static void gg_after_append_formatted_char(uint16_t *pos, unsigned char attr_flag, unsigned char *old_attr_flag, const unsigned char *color, unsigned char *old_color, size_t imgs_size, unsigned char **format, size_t *format_len) |
| |
604 { |
| |
605 const size_t color_size = 3; |
| |
606 int has_color = 0; |
| |
607 |
| |
608 if ((attr_flag & GG_FONT_COLOR) != 0) |
| |
609 has_color = 1; |
| |
610 |
| |
611 if (*old_attr_flag != attr_flag || (has_color && memcmp(old_color, color, color_size) != 0)) { |
| |
612 size_t attr_size = sizeof(*pos) + sizeof(attr_flag) + (has_color ? color_size : 0); |
| |
613 |
| |
614 if (*format != NULL) { |
| |
615 /* Staramy się naśladować oryginalnego klienta i atrybuty obrazków trzymamy na końcu */ |
| |
616 |
| |
617 *format -= imgs_size; |
| |
618 memmove(*format + attr_size, *format, imgs_size); |
| |
619 |
| |
620 **format = (unsigned char) (*pos & (uint16_t) 0x00ffU); |
| |
621 *format += 1; |
| |
622 **format = (unsigned char) ((*pos & (uint16_t) 0xff00U) >> 8); |
| |
623 *format += 1; |
| |
624 |
| |
625 **format = attr_flag; |
| |
626 *format += 1; |
| |
627 |
| |
628 if (has_color) { |
| |
629 memcpy(*format, color, color_size); |
| |
630 *format += color_size; |
| |
631 } |
| |
632 |
| |
633 *format += imgs_size; |
| |
634 } |
| |
635 |
| |
636 if (format_len != NULL) |
| |
637 *format_len += attr_size; |
| |
638 |
| |
639 *old_attr_flag = attr_flag; |
| |
640 if (has_color) |
| |
641 memcpy(old_color, color, color_size); |
| |
642 } |
| |
643 |
| |
644 *pos += 1; |
| |
645 } |
| |
646 |
| |
647 /** |
| 561 * \internal Zamienia tekst w formacie HTML na czysty tekst. |
648 * \internal Zamienia tekst w formacie HTML na czysty tekst. |
| 562 * |
649 * |
| 563 * \param dst Bufor wynikowy (może być \c NULL) |
650 * \param dst Bufor wynikowy (może być \c NULL) |
| |
651 * \param format Bufor wynikowy z atrybutami formatowania (może być \c NULL) |
| |
652 * \param format_len Wskaźnik na zmienną, do której zostanie zapisana potrzebna wielkość bufora wynikowego z atrybutami formatowania, w bajtach (może być \c NULL) |
| 564 * \param html Tekst źródłowy |
653 * \param html Tekst źródłowy |
| |
654 * \param encoding Kodowanie tekstu źródłowego oraz wynikowego |
| 565 * |
655 * |
| 566 * \note Dokleja \c \\0 na końcu bufora wynikowego. |
656 * \note Dokleja \c \\0 na końcu bufora wynikowego. |
| 567 * |
657 * |
| 568 * \note Funkcja służy do zachowania kompatybilności przy przesyłaniu |
658 * \return Długość bufora wynikowego bez \c \\0 (nawet jeśli \c dst to \c NULL). |
| 569 * wiadomości HTML do klientów, które tego formatu nie obsługują. Z tego |
|
| 570 * powodu funkcja nie zachowuje formatowania, a jedynie usuwa tagi i |
|
| 571 * zamienia podstawowe encje na ich odpowiedniki ASCII. |
|
| 572 * |
|
| 573 * \return Długość tekstu wynikowego bez \c \\0 (nawet jeśli \c dst to \c NULL). |
|
| 574 */ |
659 */ |
| 575 size_t gg_message_html_to_text(char *dst, const char *html) |
660 size_t gg_message_html_to_text(char *dst, unsigned char *format, size_t *format_len, const char *html, gg_encoding_t encoding) |
| 576 { |
661 { |
| 577 const char *src, *entity, *tag; |
662 const char *src, *entity = NULL, *tag = NULL; |
| 578 int in_tag, in_entity; |
663 int in_tag = 0, in_entity = 0, in_bold = 0, in_italic = 0, in_underline = 0; |
| 579 size_t len; |
664 unsigned char color[3] = { 0 }, old_color[3] = { 0 }; |
| 580 |
665 unsigned char attr_flag = 0, old_attr_flag = 0; |
| 581 len = 0; |
666 uint16_t pos = 0; |
| 582 in_tag = 0; |
667 size_t len = 0, imgs_size = 0; |
| 583 tag = NULL; |
668 |
| 584 in_entity = 0; |
669 if (format_len != NULL) |
| 585 entity = NULL; |
670 *format_len = 0; |
| 586 |
671 |
| 587 for (src = html; *src != 0; src++) { |
672 for (src = html; *src != 0; src++) { |
| 588 if (in_entity && !(isalnum(*src) || *src == '#' || *src == ';')) { |
673 if (in_entity && !(isalnum(*src) || *src == '#' || *src == ';')) { |
| |
674 int first = 1; |
| |
675 size_t i, append_len = src - entity; |
| |
676 |
| |
677 gg_append(dst, &len, entity, append_len); |
| |
678 for (i = 0; i < append_len; i++) { |
| |
679 if (encoding != GG_ENCODING_UTF8 || (entity[i] & 0xc0) != 0x80) { |
| |
680 if (first) { |
| |
681 gg_after_append_formatted_char(&pos, attr_flag, &old_attr_flag, color, old_color, imgs_size, &format, format_len); |
| |
682 first = 0; |
| |
683 } else { |
| |
684 pos++; |
| |
685 } |
| |
686 } |
| |
687 } |
| |
688 |
| 589 in_entity = 0; |
689 in_entity = 0; |
| 590 gg_append(dst, &len, entity, src - entity); |
|
| 591 } |
690 } |
| 592 |
691 |
| 593 if (*src == '<') { |
692 if (*src == '<') { |
| 594 tag = src; |
693 tag = src; |
| 595 in_tag = 1; |
694 in_tag = 1; |
| 599 if (in_tag && (*src == '>')) { |
698 if (in_tag && (*src == '>')) { |
| 600 if (strncmp(tag, "<br", 3) == 0) { |
699 if (strncmp(tag, "<br", 3) == 0) { |
| 601 if (dst != NULL) |
700 if (dst != NULL) |
| 602 dst[len] = '\n'; |
701 dst[len] = '\n'; |
| 603 len++; |
702 len++; |
| |
703 |
| |
704 gg_after_append_formatted_char(&pos, attr_flag, &old_attr_flag, color, old_color, imgs_size, &format, format_len); |
| |
705 } else if (strncmp(tag, "<img name=\"", 11) == 0 || strncmp(tag, "<img name=\'", 11) == 0) { |
| |
706 tag += 11; |
| |
707 |
| |
708 /* 17 bo jeszcze cudzysłów musi być zamknięty */ |
| |
709 if (tag + 17 <= src) { |
| |
710 int i, ok = 1; |
| |
711 |
| |
712 for (i = 0; i < 16; i++) { |
| |
713 if ((tag[i] < '0' || tag[i] > '9') && (tolower(tag[i]) < 'a' || tolower(tag[i]) > 'f')) { |
| |
714 ok = 0; |
| |
715 break; |
| |
716 } |
| |
717 } |
| |
718 |
| |
719 if (ok) { |
| |
720 unsigned char img_attr[13]; |
| |
721 |
| |
722 if (format != NULL) { |
| |
723 char buf[3] = { 0 }; |
| |
724 |
| |
725 img_attr[0] = (unsigned char) (pos & (uint16_t) 0x00ffU); |
| |
726 img_attr[1] = (unsigned char) ((pos & (uint16_t) 0xff00U) >> 8); |
| |
727 img_attr[2] = GG_FONT_IMAGE; |
| |
728 img_attr[3] = '\x09'; |
| |
729 img_attr[4] = '\x01'; |
| |
730 for (i = 0; i < 16; i += 2) { |
| |
731 buf[0] = tag[i]; |
| |
732 buf[1] = tag[i + 1]; |
| |
733 /* buf[2] to '\0' */ |
| |
734 img_attr[12 - i / 2] = (unsigned char) strtoul(buf, NULL, 16); |
| |
735 } |
| |
736 |
| |
737 memcpy(format, img_attr, sizeof(img_attr)); |
| |
738 format += sizeof(img_attr); |
| |
739 } |
| |
740 |
| |
741 if (format_len != NULL) |
| |
742 *format_len += sizeof(img_attr); |
| |
743 imgs_size += sizeof(img_attr); |
| |
744 |
| |
745 if (dst != NULL) { |
| |
746 if (encoding == GG_ENCODING_UTF8) |
| |
747 dst[len++] = '\xc2'; |
| |
748 dst[len++] = '\xa0'; |
| |
749 } else { |
| |
750 len += 2; |
| |
751 } |
| |
752 |
| |
753 /* Nie używamy tutaj gg_after_append_formatted_char(). Po pierwsze to praktycznie niczego |
| |
754 * by nie zmieniło, a po drugie nie wszystkim klientom mogłaby się spodobać redefinicja |
| |
755 * atrybutów formatowania dla jednego znaku (bo np. najpierw byśmy zdefiniowali bolda od |
| |
756 * znaku 10, a potem by się okazało, że znak 10 to obrazek). |
| |
757 */ |
| |
758 |
| |
759 pos++; |
| |
760 |
| |
761 /* Resetujemy atrybuty, aby je w razie czego redefiniować od następnego znaku, co by sobie |
| |
762 * nikt przypadkiem nie pomyślał, że GG_FONT_IMAGE dotyczy więcej, niż jednego znaku. |
| |
763 * Tak samo robi oryginalny klient. |
| |
764 */ |
| |
765 |
| |
766 old_attr_flag = -1; |
| |
767 } |
| |
768 } |
| |
769 } else if (strncmp(tag, "<b>", 3) == 0) { |
| |
770 in_bold++; |
| |
771 attr_flag |= GG_FONT_BOLD; |
| |
772 } else if (strncmp(tag, "</b>", 4) == 0) { |
| |
773 if (in_bold > 0) { |
| |
774 in_bold--; |
| |
775 if (in_bold == 0) |
| |
776 attr_flag &= ~GG_FONT_BOLD; |
| |
777 } |
| |
778 } else if (strncmp(tag, "<i>", 3) == 0) { |
| |
779 in_italic++; |
| |
780 attr_flag |= GG_FONT_ITALIC; |
| |
781 } else if (strncmp(tag, "</i>", 4) == 0) { |
| |
782 if (in_italic > 0) { |
| |
783 in_italic--; |
| |
784 if (in_italic == 0) |
| |
785 attr_flag &= ~GG_FONT_ITALIC; |
| |
786 } |
| |
787 } else if (strncmp(tag, "<u>", 3) == 0) { |
| |
788 in_underline++; |
| |
789 attr_flag |= GG_FONT_UNDERLINE; |
| |
790 } else if (strncmp(tag, "</u>", 4) == 0) { |
| |
791 if (in_underline > 0) { |
| |
792 in_underline--; |
| |
793 if (in_underline == 0) |
| |
794 attr_flag &= ~GG_FONT_UNDERLINE; |
| |
795 } |
| |
796 } else if (strncmp(tag, "<span ", 6) == 0) { |
| |
797 for (tag += 6; tag < src - 8; tag++) { |
| |
798 if (*tag == '\"' || *tag == '\'' || *tag == ' ') { |
| |
799 if (strncmp(tag + 1, "color:#", 7) == 0) { |
| |
800 int i, ok = 1; |
| |
801 char buf[3] = { 0 }; |
| |
802 |
| |
803 tag += 8; |
| |
804 if (tag + 6 > src) |
| |
805 break; |
| |
806 |
| |
807 for (i = 0; i < 6; i++) { |
| |
808 if ((tag[i] < '0' || tag[i] > '9') && (tolower(tag[i]) < 'a' || tolower(tag[i]) > 'f')) { |
| |
809 ok = 0; |
| |
810 break; |
| |
811 } |
| |
812 } |
| |
813 |
| |
814 if (!ok) |
| |
815 break; |
| |
816 |
| |
817 for (i = 0; i < 6; i += 2) { |
| |
818 buf[0] = tag[i]; |
| |
819 buf[1] = tag[i + 1]; |
| |
820 /* buf[2] to '\0' */ |
| |
821 color[i / 2] = (unsigned char) strtoul(buf, NULL, 16); |
| |
822 } |
| |
823 |
| |
824 attr_flag |= GG_FONT_COLOR; |
| |
825 } |
| |
826 } |
| |
827 } |
| |
828 } else if (strncmp(tag, "</span", 6) == 0) { |
| |
829 /* Można by trzymać kolory na stosie i tutaj przywracać poprzedni, ale to raczej zbędne */ |
| |
830 |
| |
831 attr_flag &= ~GG_FONT_COLOR; |
| 604 } |
832 } |
| |
833 |
| |
834 tag = NULL; |
| 605 in_tag = 0; |
835 in_tag = 0; |
| 606 continue; |
836 continue; |
| 607 } |
837 } |
| 608 |
838 |
| 609 if (in_tag) |
839 if (in_tag) |
| 649 if (in_entity) |
883 if (in_entity) |
| 650 continue; |
884 continue; |
| 651 |
885 |
| 652 if (dst != NULL) |
886 if (dst != NULL) |
| 653 dst[len] = *src; |
887 dst[len] = *src; |
| 654 |
|
| 655 len++; |
888 len++; |
| |
889 |
| |
890 if (encoding != GG_ENCODING_UTF8 || (*src & 0xc0) != 0x80) |
| |
891 gg_after_append_formatted_char(&pos, attr_flag, &old_attr_flag, color, old_color, imgs_size, &format, format_len); |
| 656 } |
892 } |
| 657 |
893 |
| 658 if (dst != NULL) |
894 if (dst != NULL) |
| 659 dst[len] = 0; |
895 dst[len] = '\0'; |
| 660 |
896 |
| 661 return len; |
897 return len; |
| 662 } |
898 } |
| 663 |
899 |
| |
900 static size_t gg_message_html_to_text_110_buff(char *dst, const char *html) |
| |
901 { |
| |
902 return gg_message_html_to_text(dst, NULL, NULL, html, GG_ENCODING_UTF8); |
| |
903 } |
| |
904 |
| |
905 static size_t gg_message_text_to_html_110_buff(char *dst, const char *text, |
| |
906 ssize_t text_len) |
| |
907 { |
| |
908 size_t i, dst_len; |
| |
909 |
| |
910 if (text_len == -1) |
| |
911 text_len = strlen(text); |
| |
912 dst_len = 0; |
| |
913 |
| |
914 gg_append(dst, &dst_len, "<span>", 6); |
| |
915 |
| |
916 for (i = 0; i < (size_t)text_len; i++) |
| |
917 { |
| |
918 char c = text[i]; |
| |
919 if (c == '<') |
| |
920 gg_append(dst, &dst_len, "<", 4); |
| |
921 else if (c == '>') |
| |
922 gg_append(dst, &dst_len, ">", 4); |
| |
923 else if (c == '&') |
| |
924 gg_append(dst, &dst_len, "&", 5); |
| |
925 else if (c == '"') |
| |
926 gg_append(dst, &dst_len, """, 6); |
| |
927 else if (c == '\'') |
| |
928 gg_append(dst, &dst_len, "'", 6); |
| |
929 else if (c == '\n') |
| |
930 gg_append(dst, &dst_len, "<br>", 4); |
| |
931 else if (c == '\r') |
| |
932 continue; |
| |
933 else if (c == '\xc2' && text[i + 1] == '\xa0') { |
| |
934 gg_append(dst, &dst_len, " ", 6); |
| |
935 i++; |
| |
936 } else { |
| |
937 if (dst) |
| |
938 dst[dst_len] = c; |
| |
939 dst_len++; |
| |
940 } |
| |
941 } |
| |
942 |
| |
943 gg_append(dst, &dst_len, "</span>", 7); |
| |
944 |
| |
945 if (dst) |
| |
946 dst[dst_len] = '\0'; |
| |
947 |
| |
948 return dst_len; |
| |
949 } |
| |
950 |
| |
951 char *gg_message_html_to_text_110(const char *html) |
| |
952 { |
| |
953 size_t dst_len; |
| |
954 char *dst; |
| |
955 |
| |
956 dst_len = gg_message_html_to_text_110_buff(NULL, html) + 1; |
| |
957 dst = malloc(dst_len); |
| |
958 if (!dst) |
| |
959 return NULL; |
| |
960 gg_message_html_to_text_110_buff(dst, html); |
| |
961 |
| |
962 return dst; |
| |
963 } |
| |
964 |
| |
965 char *gg_message_text_to_html_110(const char *text, ssize_t text_len) |
| |
966 { |
| |
967 size_t dst_len; |
| |
968 char *dst; |
| |
969 |
| |
970 dst_len = gg_message_text_to_html_110_buff(NULL, text, text_len) + 1; |
| |
971 dst = malloc(dst_len); |
| |
972 if (!dst) |
| |
973 return NULL; |
| |
974 gg_message_text_to_html_110_buff(dst, text, text_len); |
| |
975 |
| |
976 return dst; |
| |
977 } |
| |
978 |