netwerk/streamconv/converters/mozTXTToHTMLConv.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozTXTToHTMLConv.h"
     7 #include "nsNetUtil.h"
     8 #include "nsUnicharUtils.h"
     9 #include "nsCRT.h"
    10 #include "nsIExternalProtocolHandler.h"
    11 #include "nsIIOService.h"
    13 #include <algorithm>
    15 #ifdef DEBUG_BenB_Perf
    16 #include "prtime.h"
    17 #include "prinrval.h"
    18 #endif
    20 const double growthRate = 1.2;
    22 // Bug 183111, editor now replaces multiple spaces with leading
    23 // 0xA0's and a single ending space, so need to treat 0xA0's as spaces.
    24 // 0xA0 is the Latin1/Unicode character for "non-breaking space (nbsp)"
    25 // Also recognize the Japanese ideographic space 0x3000 as a space.
    26 static inline bool IsSpace(const char16_t aChar)
    27 {
    28   return (nsCRT::IsAsciiSpace(aChar) || aChar == 0xA0 || aChar == 0x3000);
    29 }
    31 // Escape Char will take ch, escape it and append the result to 
    32 // aStringToAppendTo
    33 void
    34 mozTXTToHTMLConv::EscapeChar(const char16_t ch, nsString& aStringToAppendTo,
    35                              bool inAttribute)
    36 {
    37     switch (ch)
    38     {
    39     case '<':
    40       aStringToAppendTo.AppendLiteral("&lt;");
    41       break;
    42     case '>':
    43       aStringToAppendTo.AppendLiteral("&gt;");
    44       break;
    45     case '&':
    46       aStringToAppendTo.AppendLiteral("&amp;");
    47       break;
    48     case '"':
    49       if (inAttribute)
    50       {
    51         aStringToAppendTo.AppendLiteral("&quot;");
    52         break;
    53       }
    54       // else fall through
    55     default:
    56       aStringToAppendTo += ch;
    57     }
    59     return;
    60 }
    62 // EscapeStr takes the passed in string and
    63 // escapes it IN PLACE.
    64 void
    65 mozTXTToHTMLConv::EscapeStr(nsString& aInString, bool inAttribute)
    66 {
    67   // the replace substring routines
    68   // don't seem to work if you have a character
    69   // in the in string that is also in the replacement
    70   // string! =(
    71   //aInString.ReplaceSubstring("&", "&amp;");
    72   //aInString.ReplaceSubstring("<", "&lt;");
    73   //aInString.ReplaceSubstring(">", "&gt;");
    74   for (uint32_t i = 0; i < aInString.Length();)
    75   {
    76     switch (aInString[i])
    77     {
    78     case '<':
    79       aInString.Cut(i, 1);
    80       aInString.Insert(NS_LITERAL_STRING("&lt;"), i);
    81       i += 4; // skip past the integers we just added
    82       break;
    83     case '>':
    84       aInString.Cut(i, 1);
    85       aInString.Insert(NS_LITERAL_STRING("&gt;"), i);
    86       i += 4; // skip past the integers we just added
    87       break;
    88     case '&':
    89       aInString.Cut(i, 1);
    90       aInString.Insert(NS_LITERAL_STRING("&amp;"), i);
    91       i += 5; // skip past the integers we just added
    92       break;
    93     case '"':
    94       if (inAttribute)
    95       {
    96         aInString.Cut(i, 1);
    97         aInString.Insert(NS_LITERAL_STRING("&quot;"), i);
    98         i += 6;
    99         break;
   100       }
   101       // else fall through
   102     default:
   103       i++;
   104     }
   105   }
   106 }
   108 void 
   109 mozTXTToHTMLConv::UnescapeStr(const char16_t * aInString, int32_t aStartPos, int32_t aLength, nsString& aOutString)
   110 {
   111   const char16_t * subString = nullptr;
   112   for (uint32_t i = aStartPos; int32_t(i) - aStartPos < aLength;)
   113   {
   114     int32_t remainingChars = i - aStartPos;
   115     if (aInString[i] == '&')
   116     {
   117       subString = &aInString[i];
   118       if (!nsCRT::strncmp(subString, MOZ_UTF16("&lt;"), std::min(4, aLength - remainingChars)))
   119       {
   120         aOutString.Append(char16_t('<'));
   121         i += 4;
   122       }
   123       else if (!nsCRT::strncmp(subString, MOZ_UTF16("&gt;"), std::min(4, aLength - remainingChars)))
   124       {
   125         aOutString.Append(char16_t('>'));
   126         i += 4;
   127       }
   128       else if (!nsCRT::strncmp(subString, MOZ_UTF16("&amp;"), std::min(5, aLength - remainingChars)))
   129       {
   130         aOutString.Append(char16_t('&'));
   131         i += 5;
   132       }
   133       else if (!nsCRT::strncmp(subString, MOZ_UTF16("&quot;"), std::min(6, aLength - remainingChars)))
   134       {
   135         aOutString.Append(char16_t('"'));
   136         i += 6;
   137       }
   138       else
   139       {
   140         aOutString += aInString[i];
   141         i++;
   142       }
   143     }
   144     else
   145     {
   146       aOutString += aInString[i];
   147       i++;
   148     }
   149   }
   150 }
   152 void
   153 mozTXTToHTMLConv::CompleteAbbreviatedURL(const char16_t * aInString, int32_t aInLength, 
   154                                          const uint32_t pos, nsString& aOutString)
   155 {
   156   NS_ASSERTION(int32_t(pos) < aInLength, "bad args to CompleteAbbreviatedURL, see bug #190851");
   157   if (int32_t(pos) >= aInLength)
   158     return;
   160   if (aInString[pos] == '@')
   161   {
   162     // only pre-pend a mailto url if the string contains a .domain in it..
   163     //i.e. we want to linkify johndoe@foo.com but not "let's meet @8pm"
   164     nsDependentString inString(aInString, aInLength);
   165     if (inString.FindChar('.', pos) != kNotFound) // if we have a '.' after the @ sign....
   166     {
   167       aOutString.AssignLiteral("mailto:");
   168       aOutString += aInString;
   169     }
   170   }
   171   else if (aInString[pos] == '.')
   172   {
   173     if (ItMatchesDelimited(aInString, aInLength,
   174                            MOZ_UTF16("www."), 4, LT_IGNORE, LT_IGNORE))
   175     {
   176       aOutString.AssignLiteral("http://");
   177       aOutString += aInString;
   178     }
   179     else if (ItMatchesDelimited(aInString,aInLength, MOZ_UTF16("ftp."), 4, LT_IGNORE, LT_IGNORE))
   180     { 
   181       aOutString.AssignLiteral("ftp://");
   182       aOutString += aInString;
   183     }
   184   }
   185 }
   187 bool
   188 mozTXTToHTMLConv::FindURLStart(const char16_t * aInString, int32_t aInLength,
   189                                const uint32_t pos, const modetype check,
   190                                uint32_t& start)
   191 {
   192   switch(check)
   193   { // no breaks, because end of blocks is never reached
   194   case RFC1738:
   195   {
   196     if (!nsCRT::strncmp(&aInString[std::max(int32_t(pos - 4), 0)], MOZ_UTF16("<URL:"), 5))
   197     {
   198       start = pos + 1;
   199       return true;
   200     }
   201     else
   202       return false;
   203   }
   204   case RFC2396E:
   205   {
   206     nsString temp(aInString, aInLength);
   207     int32_t i = pos <= 0 ? kNotFound : temp.RFindCharInSet(MOZ_UTF16("<>\""), pos - 1);
   208     if (i != kNotFound && (temp[uint32_t(i)] == '<' ||
   209                            temp[uint32_t(i)] == '"'))
   210     {
   211       start = uint32_t(++i);
   212       return start < pos;
   213     }
   214     else
   215       return false;
   216   }
   217   case freetext:
   218   {
   219     int32_t i = pos - 1;
   220     for (; i >= 0 && (
   221          nsCRT::IsAsciiAlpha(aInString[uint32_t(i)]) ||
   222          nsCRT::IsAsciiDigit(aInString[uint32_t(i)]) ||
   223          aInString[uint32_t(i)] == '+' ||
   224          aInString[uint32_t(i)] == '-' ||
   225          aInString[uint32_t(i)] == '.'
   226          ); i--)
   227       ;
   228     if (++i >= 0 && uint32_t(i) < pos && nsCRT::IsAsciiAlpha(aInString[uint32_t(i)]))
   229     {
   230       start = uint32_t(i);
   231       return true;
   232     }
   233     else
   234       return false;
   235   }
   236   case abbreviated:
   237   {
   238     int32_t i = pos - 1;
   239     // This disallows non-ascii-characters for email.
   240     // Currently correct, but revisit later after standards changed.
   241     bool isEmail = aInString[pos] == (char16_t)'@';
   242     // These chars mark the start of the URL
   243     for (; i >= 0
   244              && aInString[uint32_t(i)] != '>' && aInString[uint32_t(i)] != '<'
   245              && aInString[uint32_t(i)] != '"' && aInString[uint32_t(i)] != '\''
   246              && aInString[uint32_t(i)] != '`' && aInString[uint32_t(i)] != ','
   247              && aInString[uint32_t(i)] != '{' && aInString[uint32_t(i)] != '['
   248              && aInString[uint32_t(i)] != '(' && aInString[uint32_t(i)] != '|'
   249              && aInString[uint32_t(i)] != '\\'
   250              && !IsSpace(aInString[uint32_t(i)])
   251              && (!isEmail || nsCRT::IsAscii(aInString[uint32_t(i)]))
   252          ; i--)
   253       ;
   254     if
   255       (
   256         ++i >= 0 && uint32_t(i) < pos
   257           &&
   258           (
   259             nsCRT::IsAsciiAlpha(aInString[uint32_t(i)]) ||
   260             nsCRT::IsAsciiDigit(aInString[uint32_t(i)])
   261           )
   262       )
   263     {
   264       start = uint32_t(i);
   265       return true;
   266     }
   267     else
   268       return false;
   269   }
   270   default:
   271     return false;
   272   } //switch
   273 }
   275 bool
   276 mozTXTToHTMLConv::FindURLEnd(const char16_t * aInString, int32_t aInStringLength, const uint32_t pos,
   277            const modetype check, const uint32_t start, uint32_t& end)
   278 {
   279   switch(check)
   280   { // no breaks, because end of blocks is never reached
   281   case RFC1738:
   282   case RFC2396E:
   283   {
   284     nsString temp(aInString, aInStringLength);
   286     int32_t i = temp.FindCharInSet(MOZ_UTF16("<>\""), pos + 1);
   287     if (i != kNotFound && temp[uint32_t(i--)] ==
   288         (check == RFC1738 || temp[start - 1] == '<' ? '>' : '"'))
   289     {
   290       end = uint32_t(i);
   291       return end > pos;
   292     }
   293     return false;
   294   }
   295   case freetext:
   296   case abbreviated:
   297   {
   298     uint32_t i = pos + 1;
   299     bool isEmail = aInString[pos] == (char16_t)'@';
   300     bool seenOpeningParenthesis = false; // there is a '(' earlier in the URL
   301     bool seenOpeningSquareBracket = false; // there is a '[' earlier in the URL
   302     for (; int32_t(i) < aInStringLength; i++)
   303     {
   304       // These chars mark the end of the URL
   305       if (aInString[i] == '>' || aInString[i] == '<' ||
   306           aInString[i] == '"' || aInString[i] == '`' ||
   307           aInString[i] == '}' || aInString[i] == '{' ||
   308           aInString[i] == '|' ||
   309           (aInString[i] == ')' && !seenOpeningParenthesis) ||
   310           (aInString[i] == ']' && !seenOpeningSquareBracket) ||
   311           // Allow IPv6 adresses like http://[1080::8:800:200C:417A]/foo.
   312           (aInString[i] == '[' && i > 2 &&
   313            (aInString[i - 1] != '/' || aInString[i - 2] != '/')) ||
   314           IsSpace(aInString[i]))
   315           break;
   316       // Disallow non-ascii-characters for email.
   317       // Currently correct, but revisit later after standards changed.
   318       if (isEmail && (
   319             aInString[i] == '(' || aInString[i] == '\'' ||
   320             !nsCRT::IsAscii(aInString[i])))
   321           break;
   322       if (aInString[i] == '(')
   323         seenOpeningParenthesis = true;
   324       if (aInString[i] == '[')
   325         seenOpeningSquareBracket = true;
   326     }
   327     // These chars are allowed in the middle of the URL, but not at end.
   328     // Technically they are, but are used in normal text after the URL.
   329     while (--i > pos && (
   330              aInString[i] == '.' || aInString[i] == ',' || aInString[i] == ';' ||
   331              aInString[i] == '!' || aInString[i] == '?' || aInString[i] == '-' ||
   332              aInString[i] == ':' || aInString[i] == '\''
   333              ))
   334         ;
   335     if (i > pos)
   336     {
   337       end = i;
   338       return true;
   339     }
   340     return false;
   341   }
   342   default:
   343     return false;
   344   } //switch
   345 }
   347 void
   348 mozTXTToHTMLConv::CalculateURLBoundaries(const char16_t * aInString, int32_t aInStringLength, 
   349      const uint32_t pos, const uint32_t whathasbeendone,
   350      const modetype check, const uint32_t start, const uint32_t end,
   351      nsString& txtURL, nsString& desc,
   352      int32_t& replaceBefore, int32_t& replaceAfter)
   353 {
   354   uint32_t descstart = start;
   355   switch(check)
   356   {
   357   case RFC1738:
   358   {
   359     descstart = start - 5;
   360     desc.Append(&aInString[descstart], end - descstart + 2);  // include "<URL:" and ">"
   361     replaceAfter = end - pos + 1;
   362   } break;
   363   case RFC2396E:
   364   {
   365     descstart = start - 1;
   366     desc.Append(&aInString[descstart], end - descstart + 2); // include brackets
   367     replaceAfter = end - pos + 1;
   368   } break;
   369   case freetext:
   370   case abbreviated:
   371   {
   372     descstart = start;
   373     desc.Append(&aInString[descstart], end - start + 1); // don't include brackets  
   374     replaceAfter = end - pos;
   375   } break;
   376   default: break;
   377   } //switch
   379   EscapeStr(desc, false);
   381   txtURL.Append(&aInString[start], end - start + 1);
   382   txtURL.StripWhitespace();
   384   // FIX ME
   385   nsAutoString temp2;
   386   ScanTXT(&aInString[descstart], pos - descstart, ~kURLs /*prevents loop*/ & whathasbeendone, temp2);
   387   replaceBefore = temp2.Length();
   388   return;
   389 }
   391 bool mozTXTToHTMLConv::ShouldLinkify(const nsCString& aURL)
   392 {
   393   if (!mIOService)
   394     return false;
   396   nsAutoCString scheme;
   397   nsresult rv = mIOService->ExtractScheme(aURL, scheme);
   398   if(NS_FAILED(rv))
   399     return false;
   401   // Get the handler for this scheme.
   402   nsCOMPtr<nsIProtocolHandler> handler;    
   403   rv = mIOService->GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
   404   if(NS_FAILED(rv))
   405     return false;
   407   // Is it an external protocol handler? If not, linkify it.
   408   nsCOMPtr<nsIExternalProtocolHandler> externalHandler = do_QueryInterface(handler);
   409   if (!externalHandler)
   410    return true; // handler is built-in, linkify it!
   412   // If external app exists for the scheme then linkify it.
   413   bool exists;
   414   rv = externalHandler->ExternalAppExistsForScheme(scheme, &exists);
   415   return(NS_SUCCEEDED(rv) && exists);
   416 }
   418 bool
   419 mozTXTToHTMLConv::CheckURLAndCreateHTML(
   420      const nsString& txtURL, const nsString& desc, const modetype mode,
   421      nsString& outputHTML)
   422 {
   423   // Create *uri from txtURL
   424   nsCOMPtr<nsIURI> uri;
   425   nsresult rv;
   426   // Lazily initialize mIOService
   427   if (!mIOService)
   428   {
   429     mIOService = do_GetIOService();
   431     if (!mIOService)
   432       return false;
   433   }
   435   // See if the url should be linkified.
   436   NS_ConvertUTF16toUTF8 utf8URL(txtURL);
   437   if (!ShouldLinkify(utf8URL))
   438     return false;
   440   // it would be faster if we could just check to see if there is a protocol
   441   // handler for the url and return instead of actually trying to create a url...
   442   rv = mIOService->NewURI(utf8URL, nullptr, nullptr, getter_AddRefs(uri));
   444   // Real work
   445   if (NS_SUCCEEDED(rv) && uri)
   446   {
   447     outputHTML.AssignLiteral("<a class=\"moz-txt-link-");
   448     switch(mode)
   449     {
   450     case RFC1738:
   451       outputHTML.AppendLiteral("rfc1738");
   452       break;
   453     case RFC2396E:
   454       outputHTML.AppendLiteral("rfc2396E");
   455       break;
   456     case freetext:
   457       outputHTML.AppendLiteral("freetext");
   458       break;
   459     case abbreviated:
   460       outputHTML.AppendLiteral("abbreviated");
   461       break;
   462     default: break;
   463     }
   464     nsAutoString escapedURL(txtURL);
   465     EscapeStr(escapedURL, true);
   467     outputHTML.AppendLiteral("\" href=\"");
   468     outputHTML += escapedURL;
   469     outputHTML.AppendLiteral("\">");
   470     outputHTML += desc;
   471     outputHTML.AppendLiteral("</a>");
   472     return true;
   473   }
   474   else
   475     return false;
   476 }
   478 NS_IMETHODIMP mozTXTToHTMLConv::FindURLInPlaintext(const char16_t * aInString, int32_t aInLength, int32_t aPos, int32_t * aStartPos, int32_t * aEndPos)
   479 {
   480   // call FindURL on the passed in string
   481   nsAutoString outputHTML; // we'll ignore the generated output HTML
   483   *aStartPos = -1;
   484   *aEndPos = -1;
   486   FindURL(aInString, aInLength, aPos, kURLs, outputHTML, *aStartPos, *aEndPos);
   488   return NS_OK;
   489 }
   491 bool
   492 mozTXTToHTMLConv::FindURL(const char16_t * aInString, int32_t aInLength, const uint32_t pos,
   493      const uint32_t whathasbeendone,
   494      nsString& outputHTML, int32_t& replaceBefore, int32_t& replaceAfter)
   495 {
   496   enum statetype {unchecked, invalid, startok, endok, success};
   497   static const modetype ranking[] = {RFC1738, RFC2396E, freetext, abbreviated};
   499   statetype state[mozTXTToHTMLConv_lastMode + 1]; // 0(=unknown)..lastMode
   500   /* I don't like this abuse of enums as index for the array,
   501      but I don't know a better method */
   503   // Define, which modes to check
   504   /* all modes but abbreviated are checked for text[pos] == ':',
   505      only abbreviated for '.', RFC2396E and abbreviated for '@' */
   506   for (modetype iState = unknown; iState <= mozTXTToHTMLConv_lastMode;
   507        iState = modetype(iState + 1))
   508     state[iState] = aInString[pos] == ':' ? unchecked : invalid;
   509   switch (aInString[pos])
   510   {
   511   case '@':
   512     state[RFC2396E] = unchecked;
   513     // no break here
   514   case '.':
   515     state[abbreviated] = unchecked;
   516     break;
   517   case ':':
   518     state[abbreviated] = invalid;
   519     break;
   520   default:
   521     break;
   522   }
   524   // Test, first successful mode wins, sequence defined by |ranking|
   525   int32_t iCheck = 0;  // the currently tested modetype
   526   modetype check = ranking[iCheck];
   527   for (; iCheck < mozTXTToHTMLConv_numberOfModes && state[check] != success;
   528        iCheck++)
   529     /* check state from last run.
   530        If this is the first, check this one, which isn't = success yet */
   531   {
   532     check = ranking[iCheck];
   534     uint32_t start, end;
   536     if (state[check] == unchecked)
   537       if (FindURLStart(aInString, aInLength, pos, check, start))
   538         state[check] = startok;
   540     if (state[check] == startok)
   541       if (FindURLEnd(aInString, aInLength, pos, check, start, end))
   542         state[check] = endok;
   544     if (state[check] == endok)
   545     {
   546       nsAutoString txtURL, desc;
   547       int32_t resultReplaceBefore, resultReplaceAfter;
   549       CalculateURLBoundaries(aInString, aInLength, pos, whathasbeendone, check, start, end,
   550                              txtURL, desc,
   551                              resultReplaceBefore, resultReplaceAfter);
   553       if (aInString[pos] != ':')
   554       {
   555         nsAutoString temp = txtURL;
   556         txtURL.SetLength(0);
   557         CompleteAbbreviatedURL(temp.get(),temp.Length(), pos - start, txtURL);
   558       }
   560       if (!txtURL.IsEmpty() && CheckURLAndCreateHTML(txtURL, desc, check,
   561                                                      outputHTML))
   562       {
   563         replaceBefore = resultReplaceBefore;
   564         replaceAfter = resultReplaceAfter;
   565         state[check] = success;
   566       }
   567     } // if
   568   } // for
   569   return state[check] == success;
   570 }
   572 bool
   573 mozTXTToHTMLConv::ItMatchesDelimited(const char16_t * aInString,
   574     int32_t aInLength, const char16_t* rep, int32_t aRepLen,
   575     LIMTYPE before, LIMTYPE after)
   576 {
   578   // this little method gets called a LOT. I found we were spending a
   579   // lot of time just calculating the length of the variable "rep"
   580   // over and over again every time we called it. So we're now passing
   581   // an integer in here.
   582   int32_t textLen = aInLength;
   584   if
   585     (
   586       ((before == LT_IGNORE && (after == LT_IGNORE || after == LT_DELIMITER))
   587         && textLen < aRepLen) ||
   588       ((before != LT_IGNORE || (after != LT_IGNORE && after != LT_DELIMITER))
   589         && textLen < aRepLen + 1) ||
   590       (before != LT_IGNORE && after != LT_IGNORE && after != LT_DELIMITER
   591         && textLen < aRepLen + 2)
   592     )
   593     return false;
   595   char16_t text0 = aInString[0];
   596   char16_t textAfterPos = aInString[aRepLen + (before == LT_IGNORE ? 0 : 1)];
   598   if
   599     (
   600       (before == LT_ALPHA
   601         && !nsCRT::IsAsciiAlpha(text0)) ||
   602       (before == LT_DIGIT
   603         && !nsCRT::IsAsciiDigit(text0)) ||
   604       (before == LT_DELIMITER
   605         &&
   606         (
   607           nsCRT::IsAsciiAlpha(text0) ||
   608           nsCRT::IsAsciiDigit(text0) ||
   609           text0 == *rep
   610         )) ||
   611       (after == LT_ALPHA
   612         && !nsCRT::IsAsciiAlpha(textAfterPos)) ||
   613       (after == LT_DIGIT
   614         && !nsCRT::IsAsciiDigit(textAfterPos)) ||
   615       (after == LT_DELIMITER
   616         &&
   617         (
   618           nsCRT::IsAsciiAlpha(textAfterPos) ||
   619           nsCRT::IsAsciiDigit(textAfterPos) ||
   620           textAfterPos == *rep
   621         )) ||
   622         !Substring(Substring(aInString, aInString+aInLength),
   623                    (before == LT_IGNORE ? 0 : 1),
   624                    aRepLen).Equals(Substring(rep, rep+aRepLen),
   625                                    nsCaseInsensitiveStringComparator())
   626     )
   627     return false;
   629   return true;
   630 }
   632 uint32_t
   633 mozTXTToHTMLConv::NumberOfMatches(const char16_t * aInString, int32_t aInStringLength, 
   634      const char16_t* rep, int32_t aRepLen, LIMTYPE before, LIMTYPE after)
   635 {
   636   uint32_t result = 0;
   638   for (int32_t i = 0; i < aInStringLength; i++)
   639   {
   640     const char16_t * indexIntoString = &aInString[i];
   641     if (ItMatchesDelimited(indexIntoString, aInStringLength - i, rep, aRepLen, before, after))
   642       result++;
   643   }
   644   return result;
   645 }
   648 // NOTE: the converted html for the phrase is appended to aOutString
   649 // tagHTML and attributeHTML are plain ASCII (literal strings, in fact)
   650 bool
   651 mozTXTToHTMLConv::StructPhraseHit(const char16_t * aInString, int32_t aInStringLength, bool col0,
   652      const char16_t* tagTXT, int32_t aTagTXTLen, 
   653      const char* tagHTML, const char* attributeHTML,
   654      nsString& aOutString, uint32_t& openTags)
   655 {
   656   /* We're searching for the following pattern:
   657      LT_DELIMITER - "*" - ALPHA -
   658      [ some text (maybe more "*"-pairs) - ALPHA ] "*" - LT_DELIMITER.
   659      <strong> is only inserted, if existence of a pair could be verified
   660      We use the first opening/closing tag, if we can choose */
   662   const char16_t * newOffset = aInString;
   663   int32_t newLength = aInStringLength;
   664   if (!col0) // skip the first element?
   665   {
   666     newOffset = &aInString[1];
   667     newLength = aInStringLength - 1;
   668   }
   670   // opening tag
   671   if
   672     (
   673       ItMatchesDelimited(aInString, aInStringLength, tagTXT, aTagTXTLen, 
   674            (col0 ? LT_IGNORE : LT_DELIMITER), LT_ALPHA) // is opening tag
   675         && NumberOfMatches(newOffset, newLength, tagTXT, aTagTXTLen, 
   676               LT_ALPHA, LT_DELIMITER)  // remaining closing tags
   677               > openTags
   678     )
   679   {
   680     openTags++;
   681     aOutString.AppendLiteral("<");
   682     aOutString.AppendASCII(tagHTML);
   683     aOutString.Append(char16_t(' '));
   684     aOutString.AppendASCII(attributeHTML);
   685     aOutString.AppendLiteral("><span class=\"moz-txt-tag\">");
   686     aOutString.Append(tagTXT);
   687     aOutString.AppendLiteral("</span>");
   688     return true;
   689   }
   691   // closing tag
   692   else if (openTags > 0
   693        && ItMatchesDelimited(aInString, aInStringLength, tagTXT, aTagTXTLen, LT_ALPHA, LT_DELIMITER))
   694   {
   695     openTags--;
   696     aOutString.AppendLiteral("<span class=\"moz-txt-tag\">");
   697     aOutString.Append(tagTXT);
   698     aOutString.AppendLiteral("</span></");
   699     aOutString.AppendASCII(tagHTML);
   700     aOutString.Append(char16_t('>'));
   701     return true;
   702   }
   704   return false;
   705 }
   708 bool
   709 mozTXTToHTMLConv::SmilyHit(const char16_t * aInString, int32_t aLength, bool col0,
   710          const char* tagTXT, const char* imageName,
   711          nsString& outputHTML, int32_t& glyphTextLen)
   712 {
   713   if ( !aInString || !tagTXT || !imageName )
   714       return false;
   716   int32_t tagLen = strlen(tagTXT);
   718   uint32_t delim = (col0 ? 0 : 1) + tagLen;
   720   if
   721     (
   722       (col0 || IsSpace(aInString[0]))
   723         &&
   724         (
   725           aLength <= int32_t(delim) ||
   726           IsSpace(aInString[delim]) ||
   727           (aLength > int32_t(delim + 1)
   728             &&
   729             (
   730               aInString[delim] == '.' ||
   731               aInString[delim] == ',' ||
   732               aInString[delim] == ';' ||
   733               aInString[delim] == '8' ||
   734               aInString[delim] == '>' ||
   735               aInString[delim] == '!' ||
   736               aInString[delim] == '?'
   737             )
   738             && IsSpace(aInString[delim + 1]))
   739         )
   740         && ItMatchesDelimited(aInString, aLength, NS_ConvertASCIItoUTF16(tagTXT).get(), tagLen, 
   741                               col0 ? LT_IGNORE : LT_DELIMITER, LT_IGNORE)
   742 	        // Note: tests at different pos for LT_IGNORE and LT_DELIMITER
   743     )
   744   {
   745     if (!col0)
   746     {
   747       outputHTML.Truncate();
   748       outputHTML.Append(char16_t(' '));
   749     }
   751     outputHTML.AppendLiteral("<span class=\""); // <span class="
   752     AppendASCIItoUTF16(imageName, outputHTML);  // e.g. smiley-frown
   753     outputHTML.AppendLiteral("\" title=\"");    // " title="     
   754     AppendASCIItoUTF16(tagTXT, outputHTML);     // smiley tooltip
   755     outputHTML.AppendLiteral("\"><span>");      // "><span>      
   756     AppendASCIItoUTF16(tagTXT, outputHTML);     // original text 
   757     outputHTML.AppendLiteral("</span></span>"); // </span></span>
   758     glyphTextLen = (col0 ? 0 : 1) + tagLen;
   759     return true;
   760   }
   762   return false;
   763 }
   765 // the glyph is appended to aOutputString instead of the original string...
   766 bool
   767 mozTXTToHTMLConv::GlyphHit(const char16_t * aInString, int32_t aInLength, bool col0,
   768          nsString& aOutputString, int32_t& glyphTextLen)
   769 {
   770   char16_t text0 = aInString[0]; 
   771   char16_t text1 = aInString[1];
   772   char16_t firstChar = (col0 ? text0 : text1);
   774   // temporary variable used to store the glyph html text
   775   nsAutoString outputHTML;
   776   bool bTestSmilie;
   777   bool bArg = false;
   778   int i;
   780   // refactor some of this mess to avoid code duplication and speed execution a bit
   781   // there are two cases that need to be tried one after another. To avoid a lot of
   782   // duplicate code, rolling into a loop
   784   i = 0;
   785   while ( i < 2 )
   786   {
   787     bTestSmilie = false;
   788     if ( !i && (firstChar == ':' || firstChar == ';' || firstChar == '=' || firstChar == '>' || firstChar == '8' || firstChar == 'O'))
   789     {
   790         // first test passed
   792         bTestSmilie = true;
   793         bArg = col0;
   794     }
   795     if ( i && col0 && ( text1 == ':' || text1 == ';' || text1 == '=' || text1 == '>' || text1 == '8' || text1 == 'O' ) )
   796     {
   797         // second test passed
   799         bTestSmilie = true;
   800         bArg = false;
   801     }
   802     if ( bTestSmilie && (
   803           SmilyHit(aInString, aInLength, bArg,
   804                    ":-)",
   805                    "moz-smiley-s1", // smile
   806                    outputHTML, glyphTextLen) ||
   808           SmilyHit(aInString, aInLength, bArg,
   809                    ":)",
   810                    "moz-smiley-s1", // smile
   811                    outputHTML, glyphTextLen) ||
   813           SmilyHit(aInString, aInLength, bArg,
   814                    ":-D",
   815                    "moz-smiley-s5", // laughing
   816                    outputHTML, glyphTextLen) ||
   818           SmilyHit(aInString, aInLength, bArg,
   819                    ":-(",
   820                    "moz-smiley-s2", // frown
   821                    outputHTML, glyphTextLen) ||
   823           SmilyHit(aInString, aInLength, bArg,
   824                    ":(",
   825                    "moz-smiley-s2", // frown
   826                    outputHTML, glyphTextLen) ||
   828           SmilyHit(aInString, aInLength, bArg,
   829                    ":-[",
   830                    "moz-smiley-s6", // embarassed
   831                    outputHTML, glyphTextLen) ||
   833           SmilyHit(aInString, aInLength, bArg,
   834                    ";-)",
   835                    "moz-smiley-s3", // wink
   836                    outputHTML, glyphTextLen) ||
   838           SmilyHit(aInString, aInLength, col0,
   839                    ";)",
   840                    "moz-smiley-s3", // wink
   841                    outputHTML, glyphTextLen) ||
   843           SmilyHit(aInString, aInLength, bArg,
   844                    ":-\\",
   845                    "moz-smiley-s7", // undecided
   846                    outputHTML, glyphTextLen) ||
   848           SmilyHit(aInString, aInLength, bArg,
   849                    ":-P",
   850                    "moz-smiley-s4", // tongue
   851                    outputHTML, glyphTextLen) ||
   853           SmilyHit(aInString, aInLength, bArg,
   854                    ";-P",
   855                    "moz-smiley-s4", // tongue
   856                    outputHTML, glyphTextLen) ||  
   858           SmilyHit(aInString, aInLength, bArg,
   859                    "=-O",
   860                    "moz-smiley-s8", // surprise
   861                    outputHTML, glyphTextLen) ||
   863           SmilyHit(aInString, aInLength, bArg,
   864                    ":-*",
   865                    "moz-smiley-s9", // kiss
   866                    outputHTML, glyphTextLen) ||
   868           SmilyHit(aInString, aInLength, bArg,
   869                    ">:o",
   870                    "moz-smiley-s10", // yell
   871                    outputHTML, glyphTextLen) ||
   873           SmilyHit(aInString, aInLength, bArg,
   874                    ">:-o",
   875                    "moz-smiley-s10", // yell
   876                    outputHTML, glyphTextLen) ||
   878           SmilyHit(aInString, aInLength, bArg,
   879                    "8-)",
   880                    "moz-smiley-s11", // cool
   881                    outputHTML, glyphTextLen) ||
   883           SmilyHit(aInString, aInLength, bArg,
   884                    ":-$",
   885                    "moz-smiley-s12", // money
   886                    outputHTML, glyphTextLen) ||
   888           SmilyHit(aInString, aInLength, bArg,
   889                    ":-!",
   890                    "moz-smiley-s13", // foot
   891                    outputHTML, glyphTextLen) ||
   893           SmilyHit(aInString, aInLength, bArg,
   894                    "O:-)",
   895                    "moz-smiley-s14", // innocent
   896                    outputHTML, glyphTextLen) ||
   898           SmilyHit(aInString, aInLength, bArg,
   899                    ":'(",
   900                    "moz-smiley-s15", // cry
   901                    outputHTML, glyphTextLen) ||
   903           SmilyHit(aInString, aInLength, bArg,
   904                    ":-X",
   905                    "moz-smiley-s16", // sealed
   906                    outputHTML, glyphTextLen) 
   907         )
   908     )
   909     {
   910         aOutputString.Append(outputHTML);
   911         return true;
   912     }
   913     i++;
   914   }
   915   if (text0 == '\f')
   916   {
   917       aOutputString.AppendLiteral("<span class='moz-txt-formfeed'></span>");
   918       glyphTextLen = 1;
   919       return true;
   920   }
   921   if (text0 == '+' || text1 == '+')
   922   {
   923     if (ItMatchesDelimited(aInString, aInLength,
   924                            MOZ_UTF16(" +/-"), 4,
   925                            LT_IGNORE, LT_IGNORE))
   926     {
   927       aOutputString.AppendLiteral(" &plusmn;");
   928       glyphTextLen = 4;
   929       return true;
   930     }
   931     if (col0 && ItMatchesDelimited(aInString, aInLength,
   932                                    MOZ_UTF16("+/-"), 3,
   933                                    LT_IGNORE, LT_IGNORE))
   934     {
   935       aOutputString.AppendLiteral("&plusmn;");
   936       glyphTextLen = 3;
   937       return true;
   938     }
   939   }
   941   // x^2  =>  x<sup>2</sup>,   also handle powers x^-2,  x^0.5
   942   // implement regular expression /[\dA-Za-z\)\]}]\^-?\d+(\.\d+)*[^\dA-Za-z]/
   943   if    
   944     (
   945       text1 == '^'
   946       && 
   947       (
   948         nsCRT::IsAsciiDigit(text0) || nsCRT::IsAsciiAlpha(text0) || 
   949         text0 == ')' || text0 == ']' || text0 == '}'
   950       )
   951       &&
   952       (
   953         (2 < aInLength && nsCRT::IsAsciiDigit(aInString[2])) ||
   954         (3 < aInLength && aInString[2] == '-' && nsCRT::IsAsciiDigit(aInString[3]))
   955       )
   956     )
   957   {
   958     // Find first non-digit
   959     int32_t delimPos = 3;  // skip "^" and first digit (or '-')
   960     for (; delimPos < aInLength
   961            &&
   962            (
   963              nsCRT::IsAsciiDigit(aInString[delimPos]) || 
   964              (aInString[delimPos] == '.' && delimPos + 1 < aInLength &&
   965                nsCRT::IsAsciiDigit(aInString[delimPos + 1]))
   966            );
   967          delimPos++)
   968       ;
   970     if (delimPos < aInLength && nsCRT::IsAsciiAlpha(aInString[delimPos]))
   971     {
   972       return false;
   973     }
   975     outputHTML.Truncate();
   976     outputHTML += text0;
   977     outputHTML.AppendLiteral(
   978       "<sup class=\"moz-txt-sup\">"
   979       "<span style=\"display:inline-block;width:0;height:0;overflow:hidden\">"
   980       "^</span>");
   982     aOutputString.Append(outputHTML);
   983     aOutputString.Append(&aInString[2], delimPos - 2);
   984     aOutputString.AppendLiteral("</sup>");
   986     glyphTextLen = delimPos /* - 1 + 1 */ ;
   987     return true;
   988   }
   989   /*
   990    The following strings are not substituted:
   991    |TXT   |HTML     |Reason
   992    +------+---------+----------
   993     ->     &larr;    Bug #454
   994     =>     &lArr;    dito
   995     <-     &rarr;    dito
   996     <=     &rArr;    dito
   997     (tm)   &trade;   dito
   998     1/4    &frac14;  is triggered by 1/4 Part 1, 2/4 Part 2, ...
   999     3/4    &frac34;  dito
  1000     1/2    &frac12;  similar
  1001   */
  1002   return false;
  1005 /***************************************************************************
  1006   Library-internal Interface
  1007 ****************************************************************************/
  1009 mozTXTToHTMLConv::mozTXTToHTMLConv()
  1013 mozTXTToHTMLConv::~mozTXTToHTMLConv() 
  1017 NS_IMPL_ISUPPORTS(mozTXTToHTMLConv,
  1018                   mozITXTToHTMLConv,
  1019                   nsIStreamConverter,
  1020                   nsIStreamListener,
  1021                   nsIRequestObserver)
  1023 int32_t
  1024 mozTXTToHTMLConv::CiteLevelTXT(const char16_t *line,
  1025 				    uint32_t& logLineStart)
  1027   int32_t result = 0;
  1028   int32_t lineLength = NS_strlen(line);
  1030   bool moreCites = true;
  1031   while (moreCites)
  1033     /* E.g. the following lines count as quote:
  1035        > text
  1036        //#ifdef QUOTE_RECOGNITION_AGGRESSIVE
  1037        >text
  1038        //#ifdef QUOTE_RECOGNITION_AGGRESSIVE
  1039            > text
  1040        ] text
  1041        USER> text
  1042        USER] text
  1043        //#endif
  1045        logLineStart is the position of "t" in this example
  1046     */
  1047     uint32_t i = logLineStart;
  1049 #ifdef QUOTE_RECOGNITION_AGGRESSIVE
  1050     for (; int32_t(i) < lineLength && IsSpace(line[i]); i++)
  1052     for (; int32_t(i) < lineLength && nsCRT::IsAsciiAlpha(line[i])
  1053                                    && nsCRT::IsUpper(line[i])   ; i++)
  1055     if (int32_t(i) < lineLength && (line[i] == '>' || line[i] == ']'))
  1056 #else
  1057     if (int32_t(i) < lineLength && line[i] == '>')
  1058 #endif
  1060       i++;
  1061       if (int32_t(i) < lineLength && line[i] == ' ')
  1062         i++;
  1063       // sendmail/mbox
  1064       // Placed here for performance increase
  1065       const char16_t * indexString = &line[logLineStart];
  1066            // here, |logLineStart < lineLength| is always true
  1067       uint32_t minlength = std::min(uint32_t(6), NS_strlen(indexString));
  1068       if (Substring(indexString,
  1069                     indexString+minlength).Equals(Substring(NS_LITERAL_STRING(">From "), 0, minlength),
  1070                                                   nsCaseInsensitiveStringComparator()))
  1071         //XXX RFC2646
  1072         moreCites = false;
  1073       else
  1075         result++;
  1076         logLineStart = i;
  1079     else
  1080       moreCites = false;
  1083   return result;
  1086 void
  1087 mozTXTToHTMLConv::ScanTXT(const char16_t * aInString, int32_t aInStringLength, uint32_t whattodo, nsString& aOutString)
  1089   bool doURLs = 0 != (whattodo & kURLs);
  1090   bool doGlyphSubstitution = 0 != (whattodo & kGlyphSubstitution);
  1091   bool doStructPhrase = 0 != (whattodo & kStructPhrase);
  1093   uint32_t structPhrase_strong = 0;  // Number of currently open tags
  1094   uint32_t structPhrase_underline = 0;
  1095   uint32_t structPhrase_italic = 0;
  1096   uint32_t structPhrase_code = 0;
  1098   nsAutoString outputHTML;  // moved here for performance increase
  1100   for(uint32_t i = 0; int32_t(i) < aInStringLength;)
  1102     if (doGlyphSubstitution)
  1104       int32_t glyphTextLen;
  1105       if (GlyphHit(&aInString[i], aInStringLength - i, i == 0, aOutString, glyphTextLen))
  1107         i += glyphTextLen;
  1108         continue;
  1112     if (doStructPhrase)
  1114       const char16_t * newOffset = aInString;
  1115       int32_t newLength = aInStringLength;
  1116       if (i > 0 ) // skip the first element?
  1118         newOffset = &aInString[i-1];
  1119         newLength = aInStringLength - i + 1;
  1122       switch (aInString[i]) // Performance increase
  1124       case '*':
  1125         if (StructPhraseHit(newOffset, newLength, i == 0,
  1126                             MOZ_UTF16("*"), 1,
  1127                             "b", "class=\"moz-txt-star\"",
  1128                             aOutString, structPhrase_strong))
  1130           i++;
  1131           continue;
  1133         break;
  1134       case '/':
  1135         if (StructPhraseHit(newOffset, newLength, i == 0,
  1136                             MOZ_UTF16("/"), 1,
  1137                             "i", "class=\"moz-txt-slash\"",
  1138                             aOutString, structPhrase_italic))
  1140           i++;
  1141           continue;
  1143         break;
  1144       case '_':
  1145         if (StructPhraseHit(newOffset, newLength, i == 0,
  1146                             MOZ_UTF16("_"), 1,
  1147                             "span" /* <u> is deprecated */,
  1148                             "class=\"moz-txt-underscore\"",
  1149                             aOutString, structPhrase_underline))
  1151           i++;
  1152           continue;
  1154         break;
  1155       case '|':
  1156         if (StructPhraseHit(newOffset, newLength, i == 0,
  1157                             MOZ_UTF16("|"), 1,
  1158                             "code", "class=\"moz-txt-verticalline\"",
  1159                             aOutString, structPhrase_code))
  1161           i++;
  1162           continue;
  1164         break;
  1168     if (doURLs)
  1170       switch (aInString[i])
  1172       case ':':
  1173       case '@':
  1174       case '.':
  1175         if ( (i == 0 || ((i > 0) && aInString[i - 1] != ' ')) && aInString[i +1] != ' ') // Performance increase
  1177           int32_t replaceBefore;
  1178           int32_t replaceAfter;
  1179           if (FindURL(aInString, aInStringLength, i, whattodo,
  1180                       outputHTML, replaceBefore, replaceAfter)
  1181                   && structPhrase_strong + structPhrase_italic +
  1182                        structPhrase_underline + structPhrase_code == 0
  1183                        /* workaround for bug #19445 */ )
  1185             aOutString.Cut(aOutString.Length() - replaceBefore, replaceBefore);
  1186             aOutString += outputHTML;
  1187             i += replaceAfter + 1;
  1188             continue;
  1191         break;
  1192       } //switch
  1195     switch (aInString[i])
  1197     // Special symbols
  1198     case '<':
  1199     case '>':
  1200     case '&':
  1201       EscapeChar(aInString[i], aOutString, false);
  1202       i++;
  1203       break;
  1204     // Normal characters
  1205     default:
  1206       aOutString += aInString[i];
  1207       i++;
  1208       break;
  1213 void
  1214 mozTXTToHTMLConv::ScanHTML(nsString& aInString, uint32_t whattodo, nsString &aOutString)
  1216   // some common variables we were recalculating
  1217   // every time inside the for loop...
  1218   int32_t lengthOfInString = aInString.Length();
  1219   const char16_t * uniBuffer = aInString.get();
  1221 #ifdef DEBUG_BenB_Perf
  1222   PRTime parsing_start = PR_IntervalNow();
  1223 #endif
  1225   // Look for simple entities not included in a tags and scan them.
  1226   /* Skip all tags ("<[...]>") and content in an a tag ("<a[...]</a>")
  1227      or in a tag ("<!--[...]-->").
  1228      Unescape the rest (text between tags) and pass it to ScanTXT. */
  1229   for (int32_t i = 0; i < lengthOfInString;)
  1231     if (aInString[i] == '<')  // html tag
  1233       uint32_t start = uint32_t(i);
  1234       if (nsCRT::ToLower((char)aInString[uint32_t(i) + 1]) == 'a')
  1235            // if a tag, skip until </a>
  1237         i = aInString.Find("</a>", true, i);
  1238         if (i == kNotFound)
  1239           i = lengthOfInString;
  1240         else
  1241           i += 4;
  1243       else if (aInString[uint32_t(i) + 1] == '!' && aInString[uint32_t(i) + 2] == '-' &&
  1244         aInString[uint32_t(i) + 3] == '-')
  1245           //if out-commended code, skip until -->
  1247         i = aInString.Find("-->", false, i);
  1248         if (i == kNotFound)
  1249           i = lengthOfInString;
  1250         else
  1251           i += 3;
  1254       else  // just skip tag (attributes etc.)
  1256         i = aInString.FindChar('>', i);
  1257         if (i == kNotFound)
  1258           i = lengthOfInString;
  1259         else
  1260           i++;
  1262       aOutString.Append(&uniBuffer[start], uint32_t(i) - start);
  1264     else
  1266       uint32_t start = uint32_t(i);
  1267       i = aInString.FindChar('<', i);
  1268       if (i == kNotFound)
  1269         i = lengthOfInString;
  1271       nsString tempString;     
  1272       tempString.SetCapacity(uint32_t((uint32_t(i) - start) * growthRate));
  1273       UnescapeStr(uniBuffer, start, uint32_t(i) - start, tempString);
  1274       ScanTXT(tempString.get(), tempString.Length(), whattodo, aOutString);
  1278 #ifdef DEBUG_BenB_Perf
  1279   printf("ScanHTML time:    %d ms\n", PR_IntervalToMilliseconds(PR_IntervalNow() - parsing_start));
  1280 #endif
  1283 /****************************************************************************
  1284   XPCOM Interface
  1285 *****************************************************************************/
  1287 NS_IMETHODIMP
  1288 mozTXTToHTMLConv::Convert(nsIInputStream *aFromStream,
  1289                           const char *aFromType,
  1290                           const char *aToType,
  1291                           nsISupports *aCtxt, nsIInputStream **_retval)
  1293   return NS_ERROR_NOT_IMPLEMENTED;
  1296 NS_IMETHODIMP
  1297 mozTXTToHTMLConv::AsyncConvertData(const char *aFromType,
  1298                                    const char *aToType,
  1299                                    nsIStreamListener *aListener, nsISupports *aCtxt) {
  1300   return NS_ERROR_NOT_IMPLEMENTED;
  1303 NS_IMETHODIMP
  1304 mozTXTToHTMLConv::OnDataAvailable(nsIRequest* request, nsISupports *ctxt,
  1305                                  nsIInputStream *inStr, uint64_t sourceOffset,
  1306                                  uint32_t count)
  1308   return NS_ERROR_NOT_IMPLEMENTED;
  1311 NS_IMETHODIMP
  1312 mozTXTToHTMLConv::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
  1314   return NS_ERROR_NOT_IMPLEMENTED;
  1317 NS_IMETHODIMP
  1318 mozTXTToHTMLConv::OnStopRequest(nsIRequest* request, nsISupports *ctxt,
  1319                                 nsresult aStatus)
  1321   return NS_ERROR_NOT_IMPLEMENTED;
  1324 NS_IMETHODIMP
  1325 mozTXTToHTMLConv::CiteLevelTXT(const char16_t *line, uint32_t *logLineStart,
  1326 				uint32_t *_retval)
  1328    if (!logLineStart || !_retval || !line)
  1329      return NS_ERROR_NULL_POINTER;
  1330    *_retval = CiteLevelTXT(line, *logLineStart);
  1331    return NS_OK;
  1334 NS_IMETHODIMP
  1335 mozTXTToHTMLConv::ScanTXT(const char16_t *text, uint32_t whattodo,
  1336 			   char16_t **_retval)
  1338   NS_ENSURE_ARG(text);
  1340   // FIX ME!!!
  1341   nsString outString;
  1342   int32_t inLength = NS_strlen(text);
  1343   // by setting a large capacity up front, we save time
  1344   // when appending characters to the output string because we don't
  1345   // need to reallocate and re-copy the characters already in the out String.
  1346   NS_ASSERTION(inLength, "ScanTXT passed 0 length string");
  1347   if (inLength == 0) {
  1348     *_retval = NS_strdup(text);
  1349     return NS_OK;
  1352   outString.SetCapacity(uint32_t(inLength * growthRate));
  1353   ScanTXT(text, inLength, whattodo, outString);
  1355   *_retval = ToNewUnicode(outString);
  1356   return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
  1359 NS_IMETHODIMP
  1360 mozTXTToHTMLConv::ScanHTML(const char16_t *text, uint32_t whattodo,
  1361 			    char16_t **_retval)
  1363   NS_ENSURE_ARG(text);
  1365   // FIX ME!!!
  1366   nsString outString;
  1367   nsString inString (text); // look at this nasty extra copy of the entire input buffer!
  1368   outString.SetCapacity(uint32_t(inString.Length() * growthRate));
  1370   ScanHTML(inString, whattodo, outString);
  1371   *_retval = ToNewUnicode(outString);
  1372   return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
  1375 nsresult
  1376 MOZ_NewTXTToHTMLConv(mozTXTToHTMLConv** aConv)
  1378     NS_PRECONDITION(aConv != nullptr, "null ptr");
  1379     if (!aConv)
  1380       return NS_ERROR_NULL_POINTER;
  1382     *aConv = new mozTXTToHTMLConv();
  1383     if (!*aConv)
  1384       return NS_ERROR_OUT_OF_MEMORY;
  1386     NS_ADDREF(*aConv);
  1387     //    return (*aConv)->Init();
  1388     return NS_OK;

mercurial