void RTFGenParser::tag_end(const QString &tagName) { // Roll back until we find our tag. bool found = false; for(Tag* pTag = m_tags.peek(); pTag != NULL && !found; pTag = m_tags.peek()) { if (pTag->name == tagName) { found = true; } if (pTag->hasCharStyle()) { CharStyle style = *(pTag->pCharStyle); // We must pop here, so that getTopTagWithCharStyle will find a parent tag. m_tags.pop(); pTag = NULL; // to avoid confusion Tag* pParentTag = m_tags.getTopTagWithCharStyle(); if (pParentTag != NULL) { if (pParentTag->hasCharStyle()) { CharStyle* pParentStyle = pParentTag->pCharStyle; // Roll back the character style. This is regardless of whether // we found the closed tag; we just collapse all styles on our way. QString rtf = pParentStyle->getDiffRTF(style); if (!rtf.isEmpty()) { res += rtf.utf8(); m_bSpace = true; } } } } else // if this tag has no char style attached { m_tags.pop(); // just pop the tag out pTag = NULL; // to avoid confusion } if (found) { if (tagName.lower() == "p") { res += "\\par"; m_bSpace = true; } } } }
void RTFGenParser::tag_start(const QString &tagName, const list<QString> &attrs) { if (m_res_size) return; CharStyle parentStyle, style; { Tag* pParentTag = m_tags.getTopTagWithCharStyle(); if (pParentTag != NULL) { parentStyle = *(pParentTag->pCharStyle); } } style = parentStyle; if ((tagName == "b") || (tagName == "i") || (tagName == "u") || (tagName == "font") || (tagName == "p") || (tagName == "span")){ QString tag = tagName; QString option; for (list<QString>::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ QString key = *it; ++it; QString value = *it; option += " "; option += key; if (!value.isEmpty()){ option += "=\""; option += value; option += "\""; } } tags.push(tag); options.push(option); } if (tagName == "b"){ style.bold = true; } else if (tagName == "i"){ style.italic = true; } else if (tagName == "u"){ style.underline = true; } else if (tagName == "font"){ for (list<QString>::const_iterator it = attrs.begin(); it != attrs.end(); it++){ QString name = (*it); ++it; QString value = (*it); if (name == "color") { style.colorIdx = getColorIdx(value); } else if (name == "face") { style.faceIdx = getFontFaceIdx(value); } else if (name == "size") { int logicalSize = value.toInt(); if (value[0] == '+' || value[0] == '-') logicalSize += 3; if (logicalSize < 1) logicalSize = 1; else if (logicalSize > 7) logicalSize = 7; style.sizePt = htmlFontSizeToPt(logicalSize); } } } else if (tagName == "p"){ m_paragraphDir = DirUnknown; m_lastParagraphPos = res.length(); m_bSpace = true; for (list<QString>::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ QString name = (*it).lower(); ++it; QString value = (*it); if (name == "dir") { QString dir = value.lower(); if (dir == "ltr") { res += "\\ltrpar"; m_paragraphDir = DirLTR; } if (dir == "rtl") { res += "\\rtlpar"; m_paragraphDir = DirRTL; } } } } else if (tagName == "br"){ res += "\\line"; m_bSpace = true; } else if (tagName == "img"){ QString src; QString alt; for (list<QString>::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ QString name = (*it); ++it; QString value = (*it); if (name == "src"){ src = value; break; } if (name == "alt"){ alt = value; break; } } if (src.left(5) == "icon:"){ list<string> smiles = getIcons()->getSmile(src.mid(5).toLatin1()); for (list<string>::iterator its = smiles.begin(); its != smiles.end(); ++its){ string s = *its; for (unsigned nSmile = 0; nSmile < 26; nSmile++){ if (s != def_smiles[nSmile]) continue; res += "<##icqimage00"; char buf[4]; sprintf(buf, "%02X", nSmile); res += buf; res += ">"; return; } } if (!smiles.empty()){ text(QString::fromUtf8(smiles.front().c_str())); return; } } text(alt); return; } // Process attributes which all tags share. for (list<QString>::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ QString name = (*it).lower(); ++it; QString value = (*it); // Any tag might have a STYLE. if (name == "style"){ // A really crude CSS parser goes here: QRegExp cssReNum("[0-9]+"); list<QString> cssProp = parseStyle(value); for (list<QString>::iterator it = cssProp.begin(); it != cssProp.end(); ++it){ QString cssPropName = *it; ++it; if (it == cssProp.end()) break; QString cssPropValue = *it; if (cssPropName == "font-family") { style.faceIdx = getFontFaceIdx(cssPropValue); } else if (cssPropName == "font-size") { cssPropValue = cssPropValue.lower(); int length; if (cssReNum.indexIn(cssPropValue, 0) == 0){ length = cssReNum.matchedLength(); float number = cssPropValue.left(length).toFloat(); QString type = cssPropValue.mid(length); if (type == "pt") { style.sizePt = static_cast<int>(number); } else if (type == "px") { // for now, handle like 'pt', though it's wrong style.sizePt = static_cast<int>(number); } else if (type == "%") { style.sizePt = static_cast<int>(parentStyle.sizePt * (number/100)); } // We don't handle 'cm', 'em' etc. } else if (cssPropValue == "smaller") { // FONT SIZE=3 is 'normal', 2 is 'smaller' style.sizePt = htmlFontSizeToPt(2, parentStyle.sizePt); } else if (cssPropValue == "larger") { // FONT SIZE=3 is 'normal', 4 is 'larger' style.sizePt = htmlFontSizeToPt(4, parentStyle.sizePt); } // We don't handle 'small', 'medium' etc. It goes too far // beyond our basic implementation. // Also, empty 'type' would be invalid CSS, thus ignored. } else if (cssPropName == "font-style") { style.italic = (cssPropValue.lower() == "italic"); } else if (cssPropName == "font-weight") { style.bold = (cssPropValue.toInt() >= 600); } else if (cssPropName == "text-decoration") { style.underline = (cssPropValue.lower() == "underline"); } else if (cssPropName == "color") { style.colorIdx = getColorIdx(cssPropValue); } else if (cssPropName == "background-color") { style.bgColorIdx = getColorIdx(cssPropValue); } } } } Tag& tag = *(m_tags.pushNew()); tag.name = tagName; // Check if anything changed in the style. // Only then the tag deserves getting a charStyle. if (parentStyle != style) { QString rtf = style.getDiffRTF(parentStyle); if (!rtf.isEmpty()) { res += static_cast<string>(rtf.toUtf8()); m_bSpace = true; } tag.setCharStyle(style); } }
string RTFGenParser::parse(const QString &text) { res = ""; m_res_size = 0; m_codec = getContacts()->getCodec(m_contact); int charset = 0; for (const ENCODING *c = getContacts()->getEncodings(); c->language; c++){ if (!strcasecmp(c->codec, m_codec->name())){ charset = c->rtf_code; break; } } #ifdef WIN32 if ((charset == 0) && !strcasecmp(m_codec->name(), "system")){ char buff[256]; int res = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE, (char*)&buff, sizeof(buff)); if (res){ unsigned codepage = atol(buff); if (codepage){ for (const rtf_cp *c = rtf_cps; c->cp; c++){ if (c->cp == codepage) charset = c->charset; } } } } #endif unsigned ansicpg = 0; const char *send_encoding = 0; m_codec = NULL; if (charset){ for (const ENCODING *c = getContacts()->getEncodings(); c->language; c++){ if ((c->rtf_code == charset) && c->bMain){ send_encoding = c->codec; m_codec = getContacts()->getCodecByName(send_encoding); ansicpg = c->cp_code; break; } } } // Add defaults to the tables m_fontFaces.push_back("MS Sans Serif"); m_colors.push_back(m_foreColor); // Create a "fake" tag which'll serve as the default style CharStyle style; style.faceIdx = 0; style.colorIdx = 1; // colors are 1-based (0 = default) style.sizePt = 12; // default according to Microsoft Tag& tag = *(m_tags.pushNew()); tag.setCharStyle(style); // Assume we go immediately after a tag. m_bSpace = true; HTMLParser::parse(text); string s; s = "{\\rtf1\\ansi"; if (ansicpg){ s += "\\ansicpg"; s += number(ansicpg); } s += "\\deff0\r\n"; s += "{\\fonttbl"; unsigned n = 0; for (list<QString>::iterator it_face = m_fontFaces.begin(); it_face != m_fontFaces.end(); it_face++, n++){ s += "{\\f"; s += number(n); QString face = (*it_face); if (face.find("Times") >= 0){ s += "\\froman"; }else if (face.find("Courier") >= 0){ s += "\\fmodern"; }else{ s += "\\fswiss"; } if (charset){ s += "\\fcharset"; s += number(charset); } s += " "; int pos = face.find(QRegExp(" +[")); if (pos > 0) face = face.left(pos); s += static_cast<string>(face.toLatin1()); s += ";}"; } s += "}\r\n"; s += "{\\colortbl ;"; for (list<QColor>::iterator it_colors = m_colors.begin(); it_colors != m_colors.end(); ++it_colors){ QColor c = *it_colors; s += "\\red"; s += number(c.red()); s += "\\green"; s += number(c.green()); s += "\\blue"; s += number(c.blue()); s += ";"; } s += "}\r\n"; s += "\\viewkind4\\pard"; s += static_cast<string>(style.getDiffRTF(CharStyle()).toUtf8()); s += res; s += "\r\n}\r\n"; log(L_DEBUG, "Resulting RTF: %s", s.c_str()); return s; }
void RTFGenParser::tag_start(const QString &tagName, const list<QString> &attrs) { CharStyle parentStyle, style; { Tag* pParentTag = m_tags.getTopTagWithCharStyle(); if (pParentTag != NULL) { parentStyle = *(pParentTag->pCharStyle); } } style = parentStyle; if (tagName == "b"){ style.bold = true; } else if (tagName == "i"){ style.italic = true; } else if (tagName == "u"){ style.underline = true; } else if (tagName == "font"){ for (list<QString>::const_iterator it = attrs.begin(); it != attrs.end(); it++){ QString name = (*it); ++it; QString value = (*it); if (name == "color") { style.colorIdx = getColorIdx(value); } else if (name == "face") { style.faceIdx = getFontFaceIdx(value); } else if (name == "size") { int logicalSize = value.toInt(); if (value[0] == '+' || value[0] == '-') logicalSize += 3; if (logicalSize < 1) logicalSize = 1; else if (logicalSize > 7) logicalSize = 7; style.sizePt = htmlFontSizeToPt(logicalSize); } } } else if (tagName == "p"){ m_paragraphDir = DirUnknown; m_lastParagraphPos = res.length(); m_bSpace = true; for (list<QString>::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ QString name = (*it).lower(); ++it; QString value = (*it); if (name == "dir") { QString dir = value.lower(); if (dir == "ltr") { res += "\\ltrpar"; m_paragraphDir = DirLTR; } if (dir == "rtl") { res += "\\rtlpar"; m_paragraphDir = DirRTL; } } } } else if (tagName == "br"){ res += "\\line"; m_bSpace = true; } else if (tagName == "img"){ QString src; for (list<QString>::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ QString name = (*it); ++it; QString value = (*it); if (name == "src"){ src = value; break; } } if (src.left(10) != "icon:smile") return; bool bOK; unsigned nSmile = src.mid(10).toUInt(&bOK, 16); if (!bOK) return; if (nSmile < 16){ res += "<##icqimage000"; if (nSmile < 10){ res += (char)(nSmile + '0'); }else{ res += (char)(nSmile - 10 + 'A'); } res += ">"; return; } const smile *p = smiles(nSmile); if (p) res += p->paste; return; } // Process attributes which all tags share. for (list<QString>::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ QString name = (*it).lower(); ++it; QString value = (*it); // Any tag might have a STYLE. if (name == "style"){ // A really crude CSS parser goes here: QRegExp cssReNum("[0-9]+"); list<QString> cssProp = parseStyle(value); for (list<QString>::iterator it = cssProp.begin(); it != cssProp.end(); ++it){ QString cssPropName = *it; ++it; if (it == cssProp.end()) break; QString cssPropValue = *it; if (cssPropName == "font-family") { style.faceIdx = getFontFaceIdx(cssPropValue); } else if (cssPropName == "font-size") { cssPropValue = cssPropValue.lower(); int length; if (cssReNum.match(cssPropValue, 0, &length) == 0){ float number = cssPropValue.left(length).toFloat(); QString type = cssPropValue.mid(length); if (type == "pt") { style.sizePt = static_cast<int>(number); } else if (type == "px") { // for now, handle like 'pt', though it's wrong style.sizePt = static_cast<int>(number); } else if (type == "%") { style.sizePt = static_cast<int>(parentStyle.sizePt * (number/100)); } // We don't handle 'cm', 'em' etc. } else if (cssPropValue == "smaller") { // FONT SIZE=3 is 'normal', 2 is 'smaller' style.sizePt = htmlFontSizeToPt(2, parentStyle.sizePt); } else if (cssPropValue == "larger") { // FONT SIZE=3 is 'normal', 4 is 'larger' style.sizePt = htmlFontSizeToPt(4, parentStyle.sizePt); } // We don't handle 'small', 'medium' etc. It goes too far // beyond our basic implementation. // Also, empty 'type' would be invalid CSS, thus ignored. } else if (cssPropName == "font-style") { style.italic = (cssPropValue.lower() == "italic"); } else if (cssPropName == "font-weight") { style.bold = (cssPropValue.toInt() >= 600); } else if (cssPropName == "text-decoration") { style.underline = (cssPropValue.lower() == "underline"); } else if (cssPropName == "color") { style.colorIdx = getColorIdx(cssPropValue); } else if (cssPropName == "background-color") { style.bgColorIdx = getColorIdx(cssPropValue); } } } } Tag& tag = *(m_tags.pushNew()); tag.name = tagName; // Check if anything changed in the style. // Only then the tag deserves getting a charStyle. if (parentStyle != style) { QString rtf = style.getDiffRTF(parentStyle); if (!rtf.isEmpty()) { res += rtf.utf8(); m_bSpace = true; } tag.setCharStyle(style); } }