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.)

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

mercurial