From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- comm/mailnews/mime/src/mimetric.cpp | 356 ++++++++++++++++++++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100644 comm/mailnews/mime/src/mimetric.cpp (limited to 'comm/mailnews/mime/src/mimetric.cpp') diff --git a/comm/mailnews/mime/src/mimetric.cpp b/comm/mailnews/mime/src/mimetric.cpp new file mode 100644 index 0000000000..79eedea75d --- /dev/null +++ b/comm/mailnews/mime/src/mimetric.cpp @@ -0,0 +1,356 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "mimetric.h" +#include "mimebuf.h" +#include "prmem.h" +#include "plstr.h" +#include "prlog.h" +#include "msgCore.h" +#include + +#define MIME_SUPERCLASS mimeInlineTextClass +MimeDefClass(MimeInlineTextRichtext, MimeInlineTextRichtextClass, + mimeInlineTextRichtextClass, &MIME_SUPERCLASS); + +static int MimeInlineTextRichtext_parse_line(const char*, int32_t, MimeObject*); +static int MimeInlineTextRichtext_parse_begin(MimeObject*); +static int MimeInlineTextRichtext_parse_eof(MimeObject*, bool); + +static int MimeInlineTextRichtextClassInitialize( + MimeInlineTextRichtextClass* clazz) { + MimeObjectClass* oclass = (MimeObjectClass*)clazz; + PR_ASSERT(!oclass->class_initialized); + oclass->parse_begin = MimeInlineTextRichtext_parse_begin; + oclass->parse_line = MimeInlineTextRichtext_parse_line; + oclass->parse_eof = MimeInlineTextRichtext_parse_eof; + return 0; +} + +/* This function has this clunky interface because it needs to be called + from outside this module (no MimeObject, etc.) + */ +int MimeRichtextConvert(const char* line, int32_t length, MimeObject* obj, + char** obufferP, int32_t* obuffer_sizeP, + bool enriched_p) { + /* RFC 1341 (the original MIME spec) defined text/richtext. + RFC 1563 superseded text/richtext with text/enriched. + The changes from text/richtext to text/enriched are: + - CRLF semantics are different + - << maps to < + - These tags were added: + , , , + - These tags were removed: + , , , , , + , , , , , + , , + This method implements them both. + + draft-resnick-text-enriched-03.txt is a proposed update to 1563. + - These tags were added: + , , , . + However, all of these rely on the magic tag, which we + don't implement, so we're ignoring all of these. + Interesting fact: it's by Peter W. Resnick from Qualcomm (Eudora). + And it also says "It is fully expected that other text formatting + standards like HTML and SGML will supplant text/enriched in + Internet mail." + */ + int status = 0; + char* out; + const char* data_end; + const char* last_end; + const char* this_start; + const char* this_end; + unsigned int desired_size; + + // The code below must never expand the input by more than 5x; + // if it does, the desired_size multiplier (5) below must be changed too +#define BGROWTH 5 + if ((uint32_t)length >= ((uint32_t)0xfffffffe) / BGROWTH) return -1; + desired_size = (length * BGROWTH) + 1; +#undef BGROWTH + if (desired_size >= (uint32_t)*obuffer_sizeP) + status = mime_GrowBuffer(desired_size, sizeof(char), 1024, obufferP, + obuffer_sizeP); + if (status < 0) return status; + + if (enriched_p) { + for (this_start = line; this_start < line + length; this_start++) + if (!IS_SPACE(*this_start)) break; + if (this_start >= line + length) /* blank line */ + { + PL_strncpyz(*obufferP, "
", *obuffer_sizeP); + return MimeObject_write(obj, *obufferP, strlen(*obufferP), true); + } + } + + uint32_t outlen = (uint32_t)*obuffer_sizeP; + out = *obufferP; + *out = 0; + + data_end = line + length; + last_end = line; + this_start = last_end; + this_end = this_start; + uint32_t addedlen = 0; + while (this_end < data_end) { + /* Skip forward to next special character. */ + while (this_start < data_end && *this_start != '<' && *this_start != '>' && + *this_start != '&') + this_start++; + + this_end = this_start; + + /* Skip to the end of the tag. */ + if (this_start < data_end && *this_start == '<') { + this_end++; + while (this_end < data_end && !IS_SPACE(*this_end) && *this_end != '<' && + *this_end != '>' && *this_end != '&') + this_end++; + } + + this_end++; + + /* Push out the text preceding the tag. */ + if (last_end && last_end != this_start) { + memcpy(out, last_end, this_start - last_end); + out += this_start - last_end; + *out = 0; + outlen -= (this_start - last_end); + } + + if (this_start >= data_end) + break; + else if (*this_start == '&') { + PL_strncpyz(out, "&", outlen); + addedlen = strlen(out); + outlen -= addedlen; + out += addedlen; + } else if (*this_start == '>') { + PL_strncpyz(out, ">", outlen); + addedlen = strlen(out); + outlen -= addedlen; + out += addedlen; + } else if (enriched_p && this_start < data_end + 1 && + this_start[0] == '<' && this_start[1] == '<') { + PL_strncpyz(out, "<", outlen); + addedlen = strlen(out); + outlen -= addedlen; + out += addedlen; + } else if (this_start != this_end) { + /* Push out this ID. */ + const char* old = this_start + 1; + const char* tag_open = 0; + const char* tag_close = 0; + if (*old == '/') { + /* This is */ + old++; + } + + switch (*old) { + case 'b': + case 'B': + if (!PL_strncasecmp("BIGGER>", old, 7)) { + tag_open = ""; + tag_close = ""; + } else if (!PL_strncasecmp("BLINK>", old, 6)) + // Of course, both text/richtext and text/enriched must be + // enhanced *somehow*... Or else what would people think. + { + tag_open = ""; + tag_close = ""; + } else if (!PL_strncasecmp("BOLD>", old, 5)) { + tag_open = ""; + tag_close = ""; + } + break; + + case 'c': + case 'C': + if (!PL_strncasecmp("CENTER>", old, 7)) { + tag_open = "
"; + tag_close = "
"; + } else if (!enriched_p && !PL_strncasecmp("COMMENT>", old, 8)) { + tag_open = ""; + } + break; + + case 'e': + case 'E': + if (!PL_strncasecmp("EXCERPT>", old, 8)) { + tag_open = "
"; + tag_close = "
"; + } + break; + + case 'f': + case 'F': + if (!PL_strncasecmp("FIXED>", old, 6)) { + tag_open = ""; + tag_close = ""; + } else if (enriched_p && !PL_strncasecmp("FLUSHBOTH>", old, 10)) { + tag_open = "

"; + tag_close = "

"; + } else if (!PL_strncasecmp("FLUSHLEFT>", old, 10)) { + tag_open = "

"; + tag_close = "

"; + } else if (!PL_strncasecmp("FLUSHRIGHT>", old, 11)) { + tag_open = "

"; + tag_close = "

"; + } else if (!enriched_p && !PL_strncasecmp("FOOTING>", old, 8)) { + tag_open = "
"; + tag_close = "
"; + } + break; + + case 'h': + case 'H': + if (!enriched_p && !PL_strncasecmp("HEADING>", old, 8)) { + tag_open = "
"; + tag_close = "
"; + } + break; + + case 'i': + case 'I': + if (!PL_strncasecmp("INDENT>", old, 7)) { + tag_open = "
    "; + tag_close = "
"; + } else if (!PL_strncasecmp("INDENTRIGHT>", old, 12)) { + tag_open = 0; + tag_close = 0; + } else if (!PL_strncasecmp("ITALIC>", old, 7)) { + tag_open = ""; + tag_close = ""; + } + break; + + case 'l': + case 'L': + if (!enriched_p && !PL_strncasecmp("LT>", old, 3)) { + tag_open = "<"; + tag_close = 0; + } + break; + + case 'n': + case 'N': + if (!enriched_p && !PL_strncasecmp("NL>", old, 3)) { + tag_open = "
"; + tag_close = 0; + } + if (enriched_p && !PL_strncasecmp("NOFILL>", old, 7)) { + tag_open = ""; + tag_close = ""; + } + break; + + case 'o': + case 'O': + if (!enriched_p && !PL_strncasecmp("OUTDENT>", old, 8)) { + tag_open = 0; + tag_close = 0; + } else if (!enriched_p && !PL_strncasecmp("OUTDENTRIGHT>", old, 13)) { + tag_open = 0; + tag_close = 0; + } + break; + + case 'p': + case 'P': + if (enriched_p && !PL_strncasecmp("PARAM>", old, 6)) { + tag_open = ""; + } else if (!enriched_p && !PL_strncasecmp("PARAGRAPH>", old, 10)) { + tag_open = "

"; + tag_close = 0; + } + break; + + case 's': + case 'S': + if (!enriched_p && !PL_strncasecmp("SAMEPAGE>", old, 9)) { + tag_open = 0; + tag_close = 0; + } else if (!enriched_p && !PL_strncasecmp("SIGNATURE>", old, 10)) { + tag_open = ""; + tag_close = ""; + } else if (!PL_strncasecmp("SMALLER>", old, 8)) { + tag_open = ""; + tag_close = ""; + } else if (!enriched_p && !PL_strncasecmp("SUBSCRIPT>", old, 10)) { + tag_open = ""; + tag_close = ""; + } else if (!enriched_p && !PL_strncasecmp("SUPERSCRIPT>", old, 12)) { + tag_open = ""; + tag_close = ""; + } + break; + + case 'u': + case 'U': + if (!PL_strncasecmp("UNDERLINE>", old, 10)) { + tag_open = ""; + tag_close = ""; + } + break; + + case 'v': + case 'V': + if (enriched_p && !PL_strncasecmp("VERBATIM>", old, 9)) { + tag_open = "

";
+            tag_close = "
"; + } + break; + } + + if (this_start[1] == '/') { + if (tag_close) PL_strncpyz(out, tag_close, outlen); + addedlen = strlen(out); + outlen -= addedlen; + out += addedlen; + } else { + if (tag_open) PL_strncpyz(out, tag_open, outlen); + addedlen = strlen(out); + outlen -= addedlen; + out += addedlen; + } + } + + /* now go around again */ + last_end = this_end; + this_start = last_end; + } + *out = 0; + + return MimeObject_write(obj, *obufferP, out - *obufferP, true); +} + +static int MimeInlineTextRichtext_parse_line(const char* line, int32_t length, + MimeObject* obj) { + bool enriched_p = (((MimeInlineTextRichtextClass*)obj->clazz)->enriched_p); + + return MimeRichtextConvert(line, length, obj, &obj->obuffer, + &obj->obuffer_size, enriched_p); +} + +static int MimeInlineTextRichtext_parse_begin(MimeObject* obj) { + int status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj); + char s[] = ""; + if (status < 0) return status; + return MimeObject_write(obj, s, 0, true); /* force out any separators... */ +} + +static int MimeInlineTextRichtext_parse_eof(MimeObject* obj, bool abort_p) { + int status; + if (obj->closed_p) return 0; + + /* Run parent method first, to flush out any buffered data. */ + status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p); + if (status < 0) return status; + + return 0; +} -- cgit v1.2.3