netwerk/streamconv/converters/nsTXTToHTMLConv.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: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     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 "nsTXTToHTMLConv.h"
     7 #include "nsEscape.h"
     8 #include "nsStringStream.h"
     9 #include "nsAutoPtr.h"
    10 #include "nsIChannel.h"
    11 #include <algorithm>
    13 #define TOKEN_DELIMITERS MOZ_UTF16("\t\r\n ")
    15 // nsISupports methods
    16 NS_IMPL_ISUPPORTS(nsTXTToHTMLConv,
    17                   nsIStreamConverter,
    18                   nsITXTToHTMLConv,
    19                   nsIRequestObserver,
    20                   nsIStreamListener)
    23 // nsIStreamConverter methods
    24 NS_IMETHODIMP
    25 nsTXTToHTMLConv::Convert(nsIInputStream *aFromStream,
    26                          const char *aFromType, const char *aToType,
    27                          nsISupports *aCtxt, nsIInputStream * *_retval)
    28 {
    29     return NS_ERROR_NOT_IMPLEMENTED;
    30 }
    32 NS_IMETHODIMP
    33 nsTXTToHTMLConv::AsyncConvertData(const char *aFromType,
    34                                   const char *aToType,
    35                                   nsIStreamListener *aListener,
    36                                   nsISupports *aCtxt)
    37 {
    38     NS_ASSERTION(aListener, "null pointer");
    39     mListener = aListener;
    40     return NS_OK;
    41 }
    44 // nsIRequestObserver methods
    45 NS_IMETHODIMP
    46 nsTXTToHTMLConv::OnStartRequest(nsIRequest* request, nsISupports *aContext)
    47 {
    48     mBuffer.AssignLiteral("<html>\n<head><title>");
    49     mBuffer.Append(mPageTitle);
    50     mBuffer.AppendLiteral("</title></head>\n<body>\n");
    51     if (mPreFormatHTML) {     // Use <pre> tags
    52         mBuffer.AppendLiteral("<pre>\n");
    53     }
    55     // Push mBuffer to the listener now, so the initial HTML will not
    56     // be parsed in OnDataAvailable().
    58     nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
    59     if (channel)
    60         channel->SetContentType(NS_LITERAL_CSTRING("text/html"));
    61     // else, assume there is a channel somewhere that knows what it is doing!
    63     nsresult rv = mListener->OnStartRequest(request, aContext);
    64     if (NS_FAILED(rv)) return rv;
    66     // The request may have been canceled, and if that happens, we want to
    67     // suppress calls to OnDataAvailable.
    68     request->GetStatus(&rv);
    69     if (NS_FAILED(rv)) return rv;
    71     nsCOMPtr<nsIInputStream> inputData;
    72     rv = NS_NewStringInputStream(getter_AddRefs(inputData), mBuffer);
    73     if (NS_FAILED(rv)) return rv;
    75     rv = mListener->OnDataAvailable(request, aContext,
    76                                     inputData, 0, mBuffer.Length());
    77     if (NS_FAILED(rv)) return rv;
    78     mBuffer.Truncate();
    79     return rv;
    80 }
    82 NS_IMETHODIMP
    83 nsTXTToHTMLConv::OnStopRequest(nsIRequest* request, nsISupports *aContext,
    84                                nsresult aStatus)
    85 {
    86     nsresult rv = NS_OK;
    87     if (mToken) {
    88         // we still have an outstanding token
    89         NS_ASSERTION(mToken->prepend,
    90                      "Non prepending tokens should be handled in "
    91                      "OnDataAvailable. There should only be a single "
    92                      "prepending token left to be processed.");
    93         (void)CatHTML(0, mBuffer.Length());
    94     }
    95     if (mPreFormatHTML) {
    96         mBuffer.AppendLiteral("</pre>\n");
    97     }
    98     mBuffer.AppendLiteral("\n</body></html>");
   100     nsCOMPtr<nsIInputStream> inputData;
   102     rv = NS_NewStringInputStream(getter_AddRefs(inputData), mBuffer);
   103     if (NS_FAILED(rv)) return rv;
   105     rv = mListener->OnDataAvailable(request, aContext,
   106                                     inputData, 0, mBuffer.Length());
   107     if (NS_FAILED(rv)) return rv;
   109     return mListener->OnStopRequest(request, aContext, aStatus);
   110 }
   112 // nsITXTToHTMLConv methods
   113 NS_IMETHODIMP
   114 nsTXTToHTMLConv::SetTitle(const char16_t *aTitle)
   115 {
   116     mPageTitle.Assign(aTitle);
   117     return NS_OK;
   118 }
   120 NS_IMETHODIMP
   121 nsTXTToHTMLConv::PreFormatHTML(bool value)
   122 {
   123     mPreFormatHTML = value;
   124     return NS_OK;
   125 }
   127 // nsIStreamListener method
   128 NS_IMETHODIMP
   129 nsTXTToHTMLConv::OnDataAvailable(nsIRequest* request, nsISupports *aContext,
   130                                  nsIInputStream *aInStream,
   131                                  uint64_t aOffset, uint32_t aCount)
   132 {
   133     nsresult rv = NS_OK;
   134     nsString pushBuffer;
   135     uint32_t amtRead = 0;
   136     nsAutoArrayPtr<char> buffer(new char[aCount+1]);
   137     if (!buffer) return NS_ERROR_OUT_OF_MEMORY;
   139     do {
   140         uint32_t read = 0;
   141         // XXX readSegments, to avoid the first copy?
   142         rv = aInStream->Read(buffer, aCount-amtRead, &read);
   143         if (NS_FAILED(rv)) return rv;
   145         buffer[read] = '\0';
   146         // XXX charsets?? non-latin1 characters?? utf-16??
   147         AppendASCIItoUTF16(buffer, mBuffer);
   148         amtRead += read;
   150         int32_t front = -1, back = -1, tokenLoc = -1, cursor = 0;
   152         while ( (tokenLoc = FindToken(cursor, &mToken)) > -1) {
   153             if (mToken->prepend) {
   154                 front = mBuffer.RFindCharInSet(TOKEN_DELIMITERS, tokenLoc);
   155                 front++;
   156                 back = mBuffer.FindCharInSet(TOKEN_DELIMITERS, tokenLoc);
   157             } else {
   158                 front = tokenLoc;
   159                 back = front + mToken->token.Length();
   160             }
   161             if (back == -1) {
   162                 // didn't find an ending, buffer up.
   163                 mBuffer.Left(pushBuffer, front);
   164                 cursor = front;
   165                 break;
   166             }
   167             // found the end of the token.
   168             cursor = CatHTML(front, back);
   169         }
   171         int32_t end = mBuffer.RFind(TOKEN_DELIMITERS, mBuffer.Length());
   172         mBuffer.Left(pushBuffer, std::max(cursor, end));
   173         mBuffer.Cut(0, std::max(cursor, end));
   174         cursor = 0;
   176         if (!pushBuffer.IsEmpty()) {
   177             nsCOMPtr<nsIInputStream> inputData;
   179             rv = NS_NewStringInputStream(getter_AddRefs(inputData), pushBuffer);
   180             if (NS_FAILED(rv))
   181                 return rv;
   183             rv = mListener->OnDataAvailable(request, aContext,
   184                                             inputData, 0, pushBuffer.Length());
   185             if (NS_FAILED(rv))
   186                 return rv;
   187         }
   188     } while (amtRead < aCount);
   190     return rv;
   191 }
   193 // nsTXTToHTMLConv methods
   194 nsTXTToHTMLConv::nsTXTToHTMLConv()
   195 {
   196     mToken = nullptr;
   197     mPreFormatHTML = false;
   198 }
   200 nsTXTToHTMLConv::~nsTXTToHTMLConv()
   201 {
   202     mTokens.Clear();
   203 }
   205 nsresult
   206 nsTXTToHTMLConv::Init()
   207 {
   208     nsresult rv = NS_OK;
   210     // build up the list of tokens to handle
   211     convToken *token = new convToken;
   212     if (!token) return NS_ERROR_OUT_OF_MEMORY;
   213     token->prepend = false;
   214     token->token.Assign(char16_t('<'));
   215     token->modText.AssignLiteral("&lt;");
   216     mTokens.AppendElement(token);
   218     token = new convToken;
   219     if (!token) return NS_ERROR_OUT_OF_MEMORY;
   220     token->prepend = false;
   221     token->token.Assign(char16_t('>'));
   222     token->modText.AssignLiteral("&gt;");
   223     mTokens.AppendElement(token);
   225     token = new convToken;
   226     if (!token) return NS_ERROR_OUT_OF_MEMORY;
   227     token->prepend = false;
   228     token->token.Assign(char16_t('&'));
   229     token->modText.AssignLiteral("&amp;");
   230     mTokens.AppendElement(token);
   232     token = new convToken;
   233     if (!token) return NS_ERROR_OUT_OF_MEMORY;
   234     token->prepend = true;
   235     token->token.AssignLiteral("http://"); // XXX need to iterate through all protos
   236     mTokens.AppendElement(token);
   238     token = new convToken;
   239     if (!token) return NS_ERROR_OUT_OF_MEMORY;
   240     token->prepend = true;
   241     token->token.Assign(char16_t('@'));
   242     token->modText.AssignLiteral("mailto:");
   243     mTokens.AppendElement(token);
   245     return rv;
   246 }
   248 int32_t
   249 nsTXTToHTMLConv::FindToken(int32_t cursor, convToken* *_retval)
   250 {
   251     int32_t loc = -1, firstToken = mBuffer.Length();
   252     int8_t token = -1;
   253     for (uint8_t i=0; i < mTokens.Length(); i++) {
   254         loc = mBuffer.Find(mTokens[i]->token, cursor);
   255         if (loc != -1)
   256             if (loc < firstToken) {
   257                 firstToken = loc;
   258                 token = i;
   259             }
   260     }
   261     if (token == -1)
   262         return -1;
   264     *_retval = mTokens[token];
   265     return firstToken;
   266 }
   268 int32_t
   269 nsTXTToHTMLConv::CatHTML(int32_t front, int32_t back)
   270 {
   271     int32_t cursor = 0;
   272     int32_t modLen = mToken->modText.Length();
   273     if (!mToken->prepend) {
   274         // replace the entire token (from delimiter to delimiter)
   275         mBuffer.Cut(front, back - front);
   276         mBuffer.Insert(mToken->modText, front);
   277         cursor = front+modLen;
   278     } else {
   279         nsString linkText;
   280         // href is implied
   281         mBuffer.Mid(linkText, front, back-front);
   283         mBuffer.Insert(NS_LITERAL_STRING("<a href=\""), front);
   284         cursor += front+9;
   285         if (modLen) {
   286             mBuffer.Insert(mToken->modText, cursor);
   287             cursor += modLen;
   288         }
   290         NS_ConvertUTF16toUTF8 linkTextUTF8(linkText);
   291         nsCString escaped;
   292         if (NS_EscapeURL(linkTextUTF8.Data(), linkTextUTF8.Length(), esc_Minimal, escaped)) {
   293             mBuffer.Cut(cursor, back - front);
   294             CopyUTF8toUTF16(escaped, linkText);
   295             mBuffer.Insert(linkText, cursor);
   296             back = front + linkText.Length();
   297         }
   299         cursor += back-front;
   300         mBuffer.Insert(NS_LITERAL_STRING("\">"), cursor);
   301         cursor += 2;
   302         mBuffer.Insert(linkText, cursor);
   303         cursor += linkText.Length();
   304         mBuffer.Insert(NS_LITERAL_STRING("</a>"), cursor);
   305         cursor += 4;
   306     }
   307     mToken = nullptr; // indicates completeness
   308     return cursor;
   309 }

mercurial