netwerk/streamconv/converters/nsIndexedToHTML.cpp

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

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 "nsIndexedToHTML.h"
michael@0 7 #include "mozilla/dom/EncodingUtils.h"
michael@0 8 #include "nsNetUtil.h"
michael@0 9 #include "netCore.h"
michael@0 10 #include "nsStringStream.h"
michael@0 11 #include "nsIFileURL.h"
michael@0 12 #include "nsEscape.h"
michael@0 13 #include "nsIDirIndex.h"
michael@0 14 #include "nsDateTimeFormatCID.h"
michael@0 15 #include "nsURLHelper.h"
michael@0 16 #include "nsIPlatformCharset.h"
michael@0 17 #include "nsIPrefService.h"
michael@0 18 #include "nsIPrefBranch.h"
michael@0 19 #include "nsIPrefLocalizedString.h"
michael@0 20 #include "nsIChromeRegistry.h"
michael@0 21 #include "nsICharsetConverterManager.h"
michael@0 22 #include "nsIDateTimeFormat.h"
michael@0 23 #include "nsIStringBundle.h"
michael@0 24 #include "nsITextToSubURI.h"
michael@0 25 #include "nsXPIDLString.h"
michael@0 26 #include <algorithm>
michael@0 27
michael@0 28 NS_IMPL_ISUPPORTS(nsIndexedToHTML,
michael@0 29 nsIDirIndexListener,
michael@0 30 nsIStreamConverter,
michael@0 31 nsIRequestObserver,
michael@0 32 nsIStreamListener)
michael@0 33
michael@0 34 static void AppendNonAsciiToNCR(const nsAString& in, nsCString& out)
michael@0 35 {
michael@0 36 nsAString::const_iterator start, end;
michael@0 37
michael@0 38 in.BeginReading(start);
michael@0 39 in.EndReading(end);
michael@0 40
michael@0 41 while (start != end) {
michael@0 42 if (*start < 128) {
michael@0 43 out.Append(*start++);
michael@0 44 } else {
michael@0 45 out.AppendLiteral("&#x");
michael@0 46 out.AppendInt(*start++, 16);
michael@0 47 out.Append(';');
michael@0 48 }
michael@0 49 }
michael@0 50 }
michael@0 51
michael@0 52 nsresult
michael@0 53 nsIndexedToHTML::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) {
michael@0 54 nsresult rv;
michael@0 55 if (aOuter)
michael@0 56 return NS_ERROR_NO_AGGREGATION;
michael@0 57
michael@0 58 nsIndexedToHTML* _s = new nsIndexedToHTML();
michael@0 59 if (_s == nullptr)
michael@0 60 return NS_ERROR_OUT_OF_MEMORY;
michael@0 61
michael@0 62 rv = _s->QueryInterface(aIID, aResult);
michael@0 63 return rv;
michael@0 64 }
michael@0 65
michael@0 66 nsresult
michael@0 67 nsIndexedToHTML::Init(nsIStreamListener* aListener) {
michael@0 68 nsresult rv = NS_OK;
michael@0 69
michael@0 70 mListener = aListener;
michael@0 71
michael@0 72 mDateTime = do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &rv);
michael@0 73 if (NS_FAILED(rv))
michael@0 74 return rv;
michael@0 75
michael@0 76 nsCOMPtr<nsIStringBundleService> sbs =
michael@0 77 do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
michael@0 78 if (NS_FAILED(rv)) return rv;
michael@0 79 rv = sbs->CreateBundle(NECKO_MSGS_URL, getter_AddRefs(mBundle));
michael@0 80
michael@0 81 mExpectAbsLoc = false;
michael@0 82
michael@0 83 return rv;
michael@0 84 }
michael@0 85
michael@0 86 NS_IMETHODIMP
michael@0 87 nsIndexedToHTML::Convert(nsIInputStream* aFromStream,
michael@0 88 const char* aFromType,
michael@0 89 const char* aToType,
michael@0 90 nsISupports* aCtxt,
michael@0 91 nsIInputStream** res) {
michael@0 92 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 93 }
michael@0 94
michael@0 95 NS_IMETHODIMP
michael@0 96 nsIndexedToHTML::AsyncConvertData(const char *aFromType,
michael@0 97 const char *aToType,
michael@0 98 nsIStreamListener *aListener,
michael@0 99 nsISupports *aCtxt) {
michael@0 100 return Init(aListener);
michael@0 101 }
michael@0 102
michael@0 103 NS_IMETHODIMP
michael@0 104 nsIndexedToHTML::OnStartRequest(nsIRequest* request, nsISupports *aContext) {
michael@0 105 nsCString buffer;
michael@0 106 nsresult rv = DoOnStartRequest(request, aContext, buffer);
michael@0 107 if (NS_FAILED(rv)) {
michael@0 108 request->Cancel(rv);
michael@0 109 }
michael@0 110
michael@0 111 rv = mListener->OnStartRequest(request, aContext);
michael@0 112 if (NS_FAILED(rv)) return rv;
michael@0 113
michael@0 114 // The request may have been canceled, and if that happens, we want to
michael@0 115 // suppress calls to OnDataAvailable.
michael@0 116 request->GetStatus(&rv);
michael@0 117 if (NS_FAILED(rv)) return rv;
michael@0 118
michael@0 119 // Push our buffer to the listener.
michael@0 120
michael@0 121 rv = SendToListener(request, aContext, buffer);
michael@0 122 return rv;
michael@0 123 }
michael@0 124
michael@0 125 nsresult
michael@0 126 nsIndexedToHTML::DoOnStartRequest(nsIRequest* request, nsISupports *aContext,
michael@0 127 nsCString& aBuffer) {
michael@0 128 nsresult rv;
michael@0 129
michael@0 130 nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
michael@0 131 nsCOMPtr<nsIURI> uri;
michael@0 132 rv = channel->GetURI(getter_AddRefs(uri));
michael@0 133 if (NS_FAILED(rv)) return rv;
michael@0 134
michael@0 135 channel->SetContentType(NS_LITERAL_CSTRING("text/html"));
michael@0 136
michael@0 137 mParser = do_CreateInstance("@mozilla.org/dirIndexParser;1",&rv);
michael@0 138 if (NS_FAILED(rv)) return rv;
michael@0 139
michael@0 140 rv = mParser->SetListener(this);
michael@0 141 if (NS_FAILED(rv)) return rv;
michael@0 142
michael@0 143 rv = mParser->OnStartRequest(request, aContext);
michael@0 144 if (NS_FAILED(rv)) return rv;
michael@0 145
michael@0 146 nsAutoCString baseUri, titleUri;
michael@0 147 rv = uri->GetAsciiSpec(baseUri);
michael@0 148 if (NS_FAILED(rv)) return rv;
michael@0 149 titleUri = baseUri;
michael@0 150
michael@0 151 nsCString parentStr;
michael@0 152
michael@0 153 nsCString buffer;
michael@0 154 buffer.AppendLiteral("<!DOCTYPE html>\n<html>\n<head>\n");
michael@0 155
michael@0 156 // XXX - should be using the 300: line from the parser.
michael@0 157 // We can't guarantee that that comes before any entry, so we'd have to
michael@0 158 // buffer, and do other painful stuff.
michael@0 159 // I'll deal with this when I make the changes to handle welcome messages
michael@0 160 // The .. stuff should also come from the lower level protocols, but that
michael@0 161 // would muck up the XUL display
michael@0 162 // - bbaetz
michael@0 163
michael@0 164 bool isScheme = false;
michael@0 165 bool isSchemeFile = false;
michael@0 166 if (NS_SUCCEEDED(uri->SchemeIs("ftp", &isScheme)) && isScheme) {
michael@0 167
michael@0 168 // strip out the password here, so it doesn't show in the page title
michael@0 169 // This is done by the 300: line generation in ftp, but we don't use
michael@0 170 // that - see above
michael@0 171
michael@0 172 nsAutoCString pw;
michael@0 173 rv = uri->GetPassword(pw);
michael@0 174 if (NS_FAILED(rv)) return rv;
michael@0 175 if (!pw.IsEmpty()) {
michael@0 176 nsCOMPtr<nsIURI> newUri;
michael@0 177 rv = uri->Clone(getter_AddRefs(newUri));
michael@0 178 if (NS_FAILED(rv)) return rv;
michael@0 179 rv = newUri->SetPassword(EmptyCString());
michael@0 180 if (NS_FAILED(rv)) return rv;
michael@0 181 rv = newUri->GetAsciiSpec(titleUri);
michael@0 182 if (NS_FAILED(rv)) return rv;
michael@0 183 }
michael@0 184
michael@0 185 nsAutoCString path;
michael@0 186 rv = uri->GetPath(path);
michael@0 187 if (NS_FAILED(rv)) return rv;
michael@0 188
michael@0 189 if (!path.EqualsLiteral("//") && !path.LowerCaseEqualsLiteral("/%2f")) {
michael@0 190 rv = uri->Resolve(NS_LITERAL_CSTRING(".."),parentStr);
michael@0 191 if (NS_FAILED(rv)) return rv;
michael@0 192 }
michael@0 193 } else if (NS_SUCCEEDED(uri->SchemeIs("file", &isSchemeFile)) && isSchemeFile) {
michael@0 194 nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri);
michael@0 195 nsCOMPtr<nsIFile> file;
michael@0 196 rv = fileUrl->GetFile(getter_AddRefs(file));
michael@0 197 if (NS_FAILED(rv)) return rv;
michael@0 198 file->SetFollowLinks(true);
michael@0 199
michael@0 200 nsAutoCString url;
michael@0 201 rv = net_GetURLSpecFromFile(file, url);
michael@0 202 if (NS_FAILED(rv)) return rv;
michael@0 203 baseUri.Assign(url);
michael@0 204
michael@0 205 nsCOMPtr<nsIFile> parent;
michael@0 206 rv = file->GetParent(getter_AddRefs(parent));
michael@0 207
michael@0 208 if (parent && NS_SUCCEEDED(rv)) {
michael@0 209 net_GetURLSpecFromDir(parent, url);
michael@0 210 if (NS_FAILED(rv)) return rv;
michael@0 211 parentStr.Assign(url);
michael@0 212 }
michael@0 213
michael@0 214 // Directory index will be always encoded in UTF-8 if this is file url
michael@0 215 buffer.AppendLiteral("<meta charset=\"UTF-8\">\n");
michael@0 216
michael@0 217 } else if (NS_SUCCEEDED(uri->SchemeIs("jar", &isScheme)) && isScheme) {
michael@0 218 nsAutoCString path;
michael@0 219 rv = uri->GetPath(path);
michael@0 220 if (NS_FAILED(rv)) return rv;
michael@0 221
michael@0 222 // a top-level jar directory URL is of the form jar:foo.zip!/
michael@0 223 // path will be of the form foo.zip!/, and its last two characters
michael@0 224 // will be "!/"
michael@0 225 //XXX this won't work correctly when the name of the directory being
michael@0 226 //XXX displayed ends with "!", but then again, jar: URIs don't deal
michael@0 227 //XXX particularly well with such directories anyway
michael@0 228 if (!StringEndsWith(path, NS_LITERAL_CSTRING("!/"))) {
michael@0 229 rv = uri->Resolve(NS_LITERAL_CSTRING(".."), parentStr);
michael@0 230 if (NS_FAILED(rv)) return rv;
michael@0 231 }
michael@0 232 }
michael@0 233 else {
michael@0 234 // default behavior for other protocols is to assume the channel's
michael@0 235 // URL references a directory ending in '/' -- fixup if necessary.
michael@0 236 nsAutoCString path;
michael@0 237 rv = uri->GetPath(path);
michael@0 238 if (NS_FAILED(rv)) return rv;
michael@0 239 if (baseUri.Last() != '/') {
michael@0 240 baseUri.Append('/');
michael@0 241 path.Append('/');
michael@0 242 uri->SetPath(path);
michael@0 243 }
michael@0 244 if (!path.EqualsLiteral("/")) {
michael@0 245 rv = uri->Resolve(NS_LITERAL_CSTRING(".."), parentStr);
michael@0 246 if (NS_FAILED(rv)) return rv;
michael@0 247 }
michael@0 248 }
michael@0 249
michael@0 250 buffer.AppendLiteral("<style type=\"text/css\">\n"
michael@0 251 ":root {\n"
michael@0 252 " font-family: sans-serif;\n"
michael@0 253 "}\n"
michael@0 254 "img {\n"
michael@0 255 " border: 0;\n"
michael@0 256 "}\n"
michael@0 257 "th {\n"
michael@0 258 " text-align: start;\n"
michael@0 259 " white-space: nowrap;\n"
michael@0 260 "}\n"
michael@0 261 "th > a {\n"
michael@0 262 " color: inherit;\n"
michael@0 263 "}\n"
michael@0 264 "table[order] > thead > tr > th {\n"
michael@0 265 " cursor: pointer;\n"
michael@0 266 "}\n"
michael@0 267 "table[order] > thead > tr > th::after {\n"
michael@0 268 " display: none;\n"
michael@0 269 " width: .8em;\n"
michael@0 270 " -moz-margin-end: -.8em;\n"
michael@0 271 " text-align: end;\n"
michael@0 272 "}\n"
michael@0 273 "table[order=\"asc\"] > thead > tr > th::after {\n"
michael@0 274 " content: \"\\2193\"; /* DOWNWARDS ARROW (U+2193) */\n"
michael@0 275 "}\n"
michael@0 276 "table[order=\"desc\"] > thead > tr > th::after {\n"
michael@0 277 " content: \"\\2191\"; /* UPWARDS ARROW (U+2191) */\n"
michael@0 278 "}\n"
michael@0 279 "table[order][order-by=\"0\"] > thead > tr > th:first-child > a ,\n"
michael@0 280 "table[order][order-by=\"1\"] > thead > tr > th:first-child + th > a ,\n"
michael@0 281 "table[order][order-by=\"2\"] > thead > tr > th:first-child + th + th > a {\n"
michael@0 282 " text-decoration: underline;\n"
michael@0 283 "}\n"
michael@0 284 "table[order][order-by=\"0\"] > thead > tr > th:first-child::after ,\n"
michael@0 285 "table[order][order-by=\"1\"] > thead > tr > th:first-child + th::after ,\n"
michael@0 286 "table[order][order-by=\"2\"] > thead > tr > th:first-child + th + th::after {\n"
michael@0 287 " display: inline-block;\n"
michael@0 288 "}\n"
michael@0 289 "table.remove-hidden > tbody > tr.hidden-object {\n"
michael@0 290 " display: none;\n"
michael@0 291 "}\n"
michael@0 292 "td {\n"
michael@0 293 " white-space: nowrap;\n"
michael@0 294 "}\n"
michael@0 295 "table.ellipsis {\n"
michael@0 296 " width: 100%;\n"
michael@0 297 " table-layout: fixed;\n"
michael@0 298 " border-spacing: 0;\n"
michael@0 299 "}\n"
michael@0 300 "table.ellipsis > tbody > tr > td {\n"
michael@0 301 " padding: 0;\n"
michael@0 302 " overflow: hidden;\n"
michael@0 303 " text-overflow: ellipsis;\n"
michael@0 304 "}\n"
michael@0 305 "/* name */\n"
michael@0 306 "/* name */\n"
michael@0 307 "th:first-child {\n"
michael@0 308 " -moz-padding-end: 2em;\n"
michael@0 309 "}\n"
michael@0 310 "/* size */\n"
michael@0 311 "th:first-child + th {\n"
michael@0 312 " -moz-padding-end: 1em;\n"
michael@0 313 "}\n"
michael@0 314 "td:first-child + td {\n"
michael@0 315 " text-align: end;\n"
michael@0 316 " -moz-padding-end: 1em;\n"
michael@0 317 "}\n"
michael@0 318 "/* date */\n"
michael@0 319 "td:first-child + td + td {\n"
michael@0 320 " -moz-padding-start: 1em;\n"
michael@0 321 " -moz-padding-end: .5em;\n"
michael@0 322 "}\n"
michael@0 323 "/* time */\n"
michael@0 324 "td:first-child + td + td + td {\n"
michael@0 325 " -moz-padding-start: .5em;\n"
michael@0 326 "}\n"
michael@0 327 ".symlink {\n"
michael@0 328 " font-style: italic;\n"
michael@0 329 "}\n"
michael@0 330 ".dir ,\n"
michael@0 331 ".symlink ,\n"
michael@0 332 ".file {\n"
michael@0 333 " -moz-margin-start: 20px;\n"
michael@0 334 "}\n"
michael@0 335 ".dir::before ,\n"
michael@0 336 ".file > img {\n"
michael@0 337 " -moz-margin-end: 4px;\n"
michael@0 338 " -moz-margin-start: -20px;\n"
michael@0 339 " max-width: 16px;\n"
michael@0 340 " max-height: 16px;\n"
michael@0 341 " vertical-align: middle;\n"
michael@0 342 "}\n"
michael@0 343 ".dir::before {\n"
michael@0 344 " content: url(resource://gre/res/html/folder.png);\n"
michael@0 345 "}\n"
michael@0 346 "</style>\n"
michael@0 347 "<link rel=\"stylesheet\" media=\"screen, projection\" type=\"text/css\""
michael@0 348 " href=\"chrome://global/skin/dirListing/dirListing.css\">\n"
michael@0 349 "<script type=\"application/javascript\">\n"
michael@0 350 "var gTable, gOrderBy, gTBody, gRows, gUI_showHidden;\n"
michael@0 351 "document.addEventListener(\"DOMContentLoaded\", function() {\n"
michael@0 352 " gTable = document.getElementsByTagName(\"table\")[0];\n"
michael@0 353 " gTBody = gTable.tBodies[0];\n"
michael@0 354 " if (gTBody.rows.length < 2)\n"
michael@0 355 " return;\n"
michael@0 356 " gUI_showHidden = document.getElementById(\"UI_showHidden\");\n"
michael@0 357 " var headCells = gTable.tHead.rows[0].cells,\n"
michael@0 358 " hiddenObjects = false;\n"
michael@0 359 " function rowAction(i) {\n"
michael@0 360 " return function(event) {\n"
michael@0 361 " event.preventDefault();\n"
michael@0 362 " orderBy(i);\n"
michael@0 363 " }\n"
michael@0 364 " }\n"
michael@0 365 " for (var i = headCells.length - 1; i >= 0; i--) {\n"
michael@0 366 " var anchor = document.createElement(\"a\");\n"
michael@0 367 " anchor.href = \"\";\n"
michael@0 368 " anchor.appendChild(headCells[i].firstChild);\n"
michael@0 369 " headCells[i].appendChild(anchor);\n"
michael@0 370 " headCells[i].addEventListener(\"click\", rowAction(i), true);\n"
michael@0 371 " }\n"
michael@0 372 " if (gUI_showHidden) {\n"
michael@0 373 " gRows = Array.slice(gTBody.rows);\n"
michael@0 374 " hiddenObjects = gRows.some(function (row) row.className == \"hidden-object\");\n"
michael@0 375 " }\n"
michael@0 376 " gTable.setAttribute(\"order\", \"\");\n"
michael@0 377 " if (hiddenObjects) {\n"
michael@0 378 " gUI_showHidden.style.display = \"block\";\n"
michael@0 379 " updateHidden();\n"
michael@0 380 " }\n"
michael@0 381 "}, \"false\");\n"
michael@0 382 "function compareRows(rowA, rowB) {\n"
michael@0 383 " var a = rowA.cells[gOrderBy].getAttribute(\"sortable-data\") || \"\";\n"
michael@0 384 " var b = rowB.cells[gOrderBy].getAttribute(\"sortable-data\") || \"\";\n"
michael@0 385 " var intA = +a;\n"
michael@0 386 " var intB = +b;\n"
michael@0 387 " if (a == intA && b == intB) {\n"
michael@0 388 " a = intA;\n"
michael@0 389 " b = intB;\n"
michael@0 390 " } else {\n"
michael@0 391 " a = a.toLowerCase();\n"
michael@0 392 " b = b.toLowerCase();\n"
michael@0 393 " }\n"
michael@0 394 " if (a < b)\n"
michael@0 395 " return -1;\n"
michael@0 396 " if (a > b)\n"
michael@0 397 " return 1;\n"
michael@0 398 " return 0;\n"
michael@0 399 "}\n"
michael@0 400 "function orderBy(column) {\n"
michael@0 401 " if (!gRows)\n"
michael@0 402 " gRows = Array.slice(gTBody.rows);\n"
michael@0 403 " var order;\n"
michael@0 404 " if (gOrderBy == column) {\n"
michael@0 405 " order = gTable.getAttribute(\"order\") == \"asc\" ? \"desc\" : \"asc\";\n"
michael@0 406 " } else {\n"
michael@0 407 " order = \"asc\";\n"
michael@0 408 " gOrderBy = column;\n"
michael@0 409 " gTable.setAttribute(\"order-by\", column);\n"
michael@0 410 " gRows.sort(compareRows);\n"
michael@0 411 " }\n"
michael@0 412 " gTable.removeChild(gTBody);\n"
michael@0 413 " gTable.setAttribute(\"order\", order);\n"
michael@0 414 " if (order == \"asc\")\n"
michael@0 415 " for (var i = 0; i < gRows.length; i++)\n"
michael@0 416 " gTBody.appendChild(gRows[i]);\n"
michael@0 417 " else\n"
michael@0 418 " for (var i = gRows.length - 1; i >= 0; i--)\n"
michael@0 419 " gTBody.appendChild(gRows[i]);\n"
michael@0 420 " gTable.appendChild(gTBody);\n"
michael@0 421 "}\n"
michael@0 422 "function updateHidden() {\n"
michael@0 423 " gTable.className = gUI_showHidden.getElementsByTagName(\"input\")[0].checked ?\n"
michael@0 424 " \"\" :\n"
michael@0 425 " \"remove-hidden\";\n"
michael@0 426 "}\n"
michael@0 427 "</script>\n");
michael@0 428
michael@0 429 buffer.AppendLiteral("<link rel=\"icon\" type=\"image/png\" href=\"");
michael@0 430 nsCOMPtr<nsIURI> innerUri = NS_GetInnermostURI(uri);
michael@0 431 if (!innerUri)
michael@0 432 return NS_ERROR_UNEXPECTED;
michael@0 433 nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(innerUri));
michael@0 434 //XXX bug 388553: can't use skinnable icons here due to security restrictions
michael@0 435 if (fileURL) {
michael@0 436 //buffer.AppendLiteral("chrome://global/skin/dirListing/local.png");
michael@0 437 buffer.AppendLiteral("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB"
michael@0 438 "AAAAAQCAYAAAAf8%2F9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9i"
michael@0 439 "ZSBJbWFnZVJlYWR5ccllPAAAAjFJREFUeNqsU8uOElEQPffR"
michael@0 440 "3XQ3ONASdBJCSBxHos5%2B3Bg3rvkCv8PElS78gPkO%2FATj"
michael@0 441 "QoUdO2ftrJiRh6aneTb9sOpC4weMN6lcuFV16pxDIfI8x12O"
michael@0 442 "YIDhcPiu2Wx%2B%2FHF5CW1Z6Jyegt%2FTNEWSJIjjGFEUIQ"
michael@0 443 "xDrFYrWFSzXC4%2FdLvd95pRKpXKy%2BpRFZ7nwaWo1%2BsG"
michael@0 444 "nQG2260BKJfLKJVKGI1GEEJw7ateryd0v993W63WEwjgxfn5"
michael@0 445 "obGYzgCbzcaEbdsIggDj8Riu6z6iUk9SYZMSx8W0LMsM%2FS"
michael@0 446 "KK75xnJlIq80anQXdbEp0OhcPJ0eiaJnGRMEyyPDsAKKUM9c"
michael@0 447 "lkYoDo3SZJzzSdp0VSKYmfV1co%2Bz580kw5KDIM8RbRfEnU"
michael@0 448 "f1HzxtQyMAGcaGruTKczMzEIaqhKifV6jd%2BzGQQB5llunF"
michael@0 449 "%2FM52BizC2K5sYPYvZcu653tjOM9O93wnYc08gmkgg4VAxi"
michael@0 450 "xfqFUJT36AYBZGd6PJkFCZnnlBxMp38gqIgLpZB0y4Nph18l"
michael@0 451 "yWh5FFbrOSxbl3V4G%2BVB7T4ajYYxTyuLtO%2BCvWGgJE1M"
michael@0 452 "c7JNsJEhvgw%2FQV4fo%2F24nbEsX2u1d5sVyn8sJO0ZAQiI"
michael@0 453 "YnFh%2BxrfLz%2Fj29cBS%2FO14zg3i8XigW3ZkErDtmKoeM"
michael@0 454 "%2BAJGRMnXeEPGKf0nCD1ydvkDzU9Jbc6OpR7WIw6L8lQ%2B"
michael@0 455 "4pQ1%2FlPF0RGM9Ns91Wmptk0GfB4EJkt77vXYj%2F8m%2B8"
michael@0 456 "y%2FkrwABHbz2H9V68DQAAAABJRU5ErkJggg%3D%3D");
michael@0 457 } else {
michael@0 458 //buffer.AppendLiteral("chrome://global/skin/dirListing/remote.png");
michael@0 459 buffer.AppendLiteral("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB"
michael@0 460 "AAAAAQCAYAAAAf8%2F9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9i"
michael@0 461 "ZSBJbWFnZVJlYWR5ccllPAAAAeBJREFUeNqcU81O20AQ%2Ft"
michael@0 462 "Z2AgQSYQRqL1UPVG2hAUQkxLEStz4DrXpLpD5Drz31Cajax%"
michael@0 463 "2Bghhx6qHIJURBTxIwQRwopCBbZjHMcOTrzermPipsSt1Iw0"
michael@0 464 "3p3ZmW%2B%2B2R0TxhgOD34wjCHZlQ0iDYz9yvEfhxMTCYhE"
michael@0 465 "QDIZhkxKd2sqzX2TOD2vBQCQhpPefng1ZP2dVPlLLdpL8SEM"
michael@0 466 "cxng%2Fbs0RIHhtgs4twxOh%2BHjZxvzDx%2F3GQQiDFISiR"
michael@0 467 "BLFMPKTRMollzcWECrDVhtxtdRVsL9youPxGj%2FbdfFlUZh"
michael@0 468 "tDyYbYqWRUdai1oQRZ5oHeHl2gNM%2B01Uqio8RlH%2Bnsaz"
michael@0 469 "JzNwXcq1B%2BiXPHprlEEymeBfXs1w8XxxihfyuXqoHqpoGj"
michael@0 470 "ZM04bddgG%2F9%2B8WGj87qDdsrK9m%2BoA%2BpbhQTDh2l1"
michael@0 471 "%2Bi2weNbSHMZyjvNXmVbqh9Fj5Oz27uEoP%2BSTxANruJs9"
michael@0 472 "L%2FT6P0ewqPx5nmiAG5f6AoCtN1PbJzuRyJAyDBzzSQYvEr"
michael@0 473 "f06yYxhGXlEa8H2KVGoasjwLx3Ewk858opQWXm%2B%2Fib9E"
michael@0 474 "QrBzclLLLy89xYvlpchvtixcX6uo1y%2FzsiwHrkIsgKbp%2"
michael@0 475 "BYWFOWicuqppoNTnStHzPFCPQhBEBOyGAX4JMADFetubi4BS"
michael@0 476 "YAAAAABJRU5ErkJggg%3D%3D");
michael@0 477 }
michael@0 478 buffer.AppendLiteral("\">\n<title>");
michael@0 479
michael@0 480 // Everything needs to end in a /,
michael@0 481 // otherwise we end up linking to file:///foo/dirfile
michael@0 482
michael@0 483 if (!mTextToSubURI) {
michael@0 484 mTextToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
michael@0 485 if (NS_FAILED(rv)) return rv;
michael@0 486 }
michael@0 487
michael@0 488 nsXPIDLCString encoding;
michael@0 489 rv = uri->GetOriginCharset(encoding);
michael@0 490 if (NS_FAILED(rv)) return rv;
michael@0 491 if (encoding.IsEmpty()) {
michael@0 492 encoding.AssignLiteral("UTF-8");
michael@0 493 }
michael@0 494
michael@0 495 nsXPIDLString unEscapeSpec;
michael@0 496 rv = mTextToSubURI->UnEscapeAndConvert(encoding, titleUri.get(),
michael@0 497 getter_Copies(unEscapeSpec));
michael@0 498 // unescape may fail because
michael@0 499 // 1. file URL may be encoded in platform charset for backward compatibility
michael@0 500 // 2. query part may not be encoded in UTF-8 (see bug 261929)
michael@0 501 // so try the platform's default if this is file url
michael@0 502 if (NS_FAILED(rv) && isSchemeFile) {
michael@0 503 nsCOMPtr<nsIPlatformCharset> platformCharset(do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv));
michael@0 504 NS_ENSURE_SUCCESS(rv, rv);
michael@0 505 nsAutoCString charset;
michael@0 506 rv = platformCharset->GetCharset(kPlatformCharsetSel_FileName, charset);
michael@0 507 NS_ENSURE_SUCCESS(rv, rv);
michael@0 508
michael@0 509 rv = mTextToSubURI->UnEscapeAndConvert(charset.get(), titleUri.get(),
michael@0 510 getter_Copies(unEscapeSpec));
michael@0 511 }
michael@0 512 if (NS_FAILED(rv)) return rv;
michael@0 513
michael@0 514 nsXPIDLString htmlEscSpec;
michael@0 515 htmlEscSpec.Adopt(nsEscapeHTML2(unEscapeSpec.get(),
michael@0 516 unEscapeSpec.Length()));
michael@0 517
michael@0 518 nsXPIDLString title;
michael@0 519 const char16_t* formatTitle[] = {
michael@0 520 htmlEscSpec.get()
michael@0 521 };
michael@0 522
michael@0 523 rv = mBundle->FormatStringFromName(MOZ_UTF16("DirTitle"),
michael@0 524 formatTitle,
michael@0 525 sizeof(formatTitle)/sizeof(char16_t*),
michael@0 526 getter_Copies(title));
michael@0 527 if (NS_FAILED(rv)) return rv;
michael@0 528
michael@0 529 // we want to convert string bundle to NCR
michael@0 530 // to ensure they're shown in any charsets
michael@0 531 AppendNonAsciiToNCR(title, buffer);
michael@0 532
michael@0 533 buffer.AppendLiteral("</title>\n");
michael@0 534
michael@0 535 // If there is a quote character in the baseUri, then
michael@0 536 // lets not add a base URL. The reason for this is that
michael@0 537 // if we stick baseUri containing a quote into a quoted
michael@0 538 // string, the quote character will prematurely close
michael@0 539 // the base href string. This is a fall-back check;
michael@0 540 // that's why it is OK to not use a base rather than
michael@0 541 // trying to play nice and escaping the quotes. See bug
michael@0 542 // 358128.
michael@0 543
michael@0 544 if (baseUri.FindChar('"') == kNotFound)
michael@0 545 {
michael@0 546 // Great, the baseUri does not contain a char that
michael@0 547 // will prematurely close the string. Go ahead an
michael@0 548 // add a base href.
michael@0 549 buffer.AppendLiteral("<base href=\"");
michael@0 550 nsAdoptingCString htmlEscapedUri(nsEscapeHTML(baseUri.get()));
michael@0 551 buffer.Append(htmlEscapedUri);
michael@0 552 buffer.AppendLiteral("\" />\n");
michael@0 553 }
michael@0 554 else
michael@0 555 {
michael@0 556 NS_ERROR("broken protocol handler didn't escape double-quote.");
michael@0 557 }
michael@0 558
michael@0 559 nsCString direction(NS_LITERAL_CSTRING("ltr"));
michael@0 560 nsCOMPtr<nsIXULChromeRegistry> reg =
michael@0 561 mozilla::services::GetXULChromeRegistryService();
michael@0 562 if (reg) {
michael@0 563 bool isRTL = false;
michael@0 564 reg->IsLocaleRTL(NS_LITERAL_CSTRING("global"), &isRTL);
michael@0 565 if (isRTL) {
michael@0 566 direction.AssignLiteral("rtl");
michael@0 567 }
michael@0 568 }
michael@0 569
michael@0 570 buffer.AppendLiteral("</head>\n<body dir=\"");
michael@0 571 buffer.Append(direction);
michael@0 572 buffer.AppendLiteral("\">\n<h1>");
michael@0 573
michael@0 574 const char16_t* formatHeading[] = {
michael@0 575 htmlEscSpec.get()
michael@0 576 };
michael@0 577
michael@0 578 rv = mBundle->FormatStringFromName(MOZ_UTF16("DirTitle"),
michael@0 579 formatHeading,
michael@0 580 sizeof(formatHeading)/sizeof(char16_t*),
michael@0 581 getter_Copies(title));
michael@0 582 if (NS_FAILED(rv)) return rv;
michael@0 583
michael@0 584 AppendNonAsciiToNCR(title, buffer);
michael@0 585 buffer.AppendLiteral("</h1>\n");
michael@0 586
michael@0 587 if (!parentStr.IsEmpty()) {
michael@0 588 nsXPIDLString parentText;
michael@0 589 rv = mBundle->GetStringFromName(MOZ_UTF16("DirGoUp"),
michael@0 590 getter_Copies(parentText));
michael@0 591 if (NS_FAILED(rv)) return rv;
michael@0 592
michael@0 593 buffer.AppendLiteral("<p id=\"UI_goUp\"><a class=\"up\" href=\"");
michael@0 594
michael@0 595 nsAdoptingCString htmlParentStr(nsEscapeHTML(parentStr.get()));
michael@0 596 buffer.Append(htmlParentStr);
michael@0 597 buffer.AppendLiteral("\">");
michael@0 598 AppendNonAsciiToNCR(parentText, buffer);
michael@0 599 buffer.AppendLiteral("</a></p>\n");
michael@0 600 }
michael@0 601
michael@0 602 if (isSchemeFile) {
michael@0 603 nsXPIDLString showHiddenText;
michael@0 604 rv = mBundle->GetStringFromName(MOZ_UTF16("ShowHidden"),
michael@0 605 getter_Copies(showHiddenText));
michael@0 606 if (NS_FAILED(rv)) return rv;
michael@0 607
michael@0 608 buffer.AppendLiteral("<p id=\"UI_showHidden\" style=\"display:none\"><label><input type=\"checkbox\" checked onchange=\"updateHidden()\">");
michael@0 609 AppendNonAsciiToNCR(showHiddenText, buffer);
michael@0 610 buffer.AppendLiteral("</label></p>\n");
michael@0 611 }
michael@0 612
michael@0 613 buffer.AppendLiteral("<table>\n");
michael@0 614
michael@0 615 nsXPIDLString columnText;
michael@0 616
michael@0 617 buffer.AppendLiteral(" <thead>\n"
michael@0 618 " <tr>\n"
michael@0 619 " <th>");
michael@0 620
michael@0 621 rv = mBundle->GetStringFromName(MOZ_UTF16("DirColName"),
michael@0 622 getter_Copies(columnText));
michael@0 623 if (NS_FAILED(rv)) return rv;
michael@0 624 AppendNonAsciiToNCR(columnText, buffer);
michael@0 625 buffer.AppendLiteral("</th>\n"
michael@0 626 " <th>");
michael@0 627
michael@0 628 rv = mBundle->GetStringFromName(MOZ_UTF16("DirColSize"),
michael@0 629 getter_Copies(columnText));
michael@0 630 if (NS_FAILED(rv)) return rv;
michael@0 631 AppendNonAsciiToNCR(columnText, buffer);
michael@0 632 buffer.AppendLiteral("</th>\n"
michael@0 633 " <th colspan=\"2\">");
michael@0 634
michael@0 635 rv = mBundle->GetStringFromName(MOZ_UTF16("DirColMTime"),
michael@0 636 getter_Copies(columnText));
michael@0 637 if (NS_FAILED(rv)) return rv;
michael@0 638 AppendNonAsciiToNCR(columnText, buffer);
michael@0 639 buffer.AppendLiteral("</th>\n"
michael@0 640 " </tr>\n"
michael@0 641 " </thead>\n");
michael@0 642 buffer.AppendLiteral(" <tbody>\n");
michael@0 643
michael@0 644 aBuffer = buffer;
michael@0 645 return rv;
michael@0 646 }
michael@0 647
michael@0 648 NS_IMETHODIMP
michael@0 649 nsIndexedToHTML::OnStopRequest(nsIRequest* request, nsISupports *aContext,
michael@0 650 nsresult aStatus) {
michael@0 651 if (NS_SUCCEEDED(aStatus)) {
michael@0 652 nsCString buffer;
michael@0 653 buffer.AssignLiteral("</tbody></table></body></html>\n");
michael@0 654
michael@0 655 aStatus = SendToListener(request, aContext, buffer);
michael@0 656 }
michael@0 657
michael@0 658 mParser->OnStopRequest(request, aContext, aStatus);
michael@0 659 mParser = 0;
michael@0 660
michael@0 661 return mListener->OnStopRequest(request, aContext, aStatus);
michael@0 662 }
michael@0 663
michael@0 664 nsresult
michael@0 665 nsIndexedToHTML::SendToListener(nsIRequest* aRequest, nsISupports *aContext, const nsACString &aBuffer)
michael@0 666 {
michael@0 667 nsCOMPtr<nsIInputStream> inputData;
michael@0 668 nsresult rv = NS_NewCStringInputStream(getter_AddRefs(inputData), aBuffer);
michael@0 669 NS_ENSURE_SUCCESS(rv, rv);
michael@0 670 return mListener->OnDataAvailable(aRequest, aContext,
michael@0 671 inputData, 0, aBuffer.Length());
michael@0 672 }
michael@0 673
michael@0 674 NS_IMETHODIMP
michael@0 675 nsIndexedToHTML::OnDataAvailable(nsIRequest *aRequest,
michael@0 676 nsISupports *aCtxt,
michael@0 677 nsIInputStream* aInput,
michael@0 678 uint64_t aOffset,
michael@0 679 uint32_t aCount) {
michael@0 680 return mParser->OnDataAvailable(aRequest, aCtxt, aInput, aOffset, aCount);
michael@0 681 }
michael@0 682
michael@0 683 NS_IMETHODIMP
michael@0 684 nsIndexedToHTML::OnIndexAvailable(nsIRequest *aRequest,
michael@0 685 nsISupports *aCtxt,
michael@0 686 nsIDirIndex *aIndex) {
michael@0 687 nsresult rv;
michael@0 688 if (!aIndex)
michael@0 689 return NS_ERROR_NULL_POINTER;
michael@0 690
michael@0 691 nsCString pushBuffer;
michael@0 692 pushBuffer.AppendLiteral("<tr");
michael@0 693
michael@0 694 // We don't know the file's character set yet, so retrieve the raw bytes
michael@0 695 // which will be decoded by the HTML parser.
michael@0 696 nsXPIDLCString loc;
michael@0 697 aIndex->GetLocation(getter_Copies(loc));
michael@0 698
michael@0 699 // Adjust the length in case unescaping shortened the string.
michael@0 700 loc.Truncate(nsUnescapeCount(loc.BeginWriting()));
michael@0 701 if (loc.First() == PRUnichar('.'))
michael@0 702 pushBuffer.AppendLiteral(" class=\"hidden-object\"");
michael@0 703
michael@0 704 pushBuffer.AppendLiteral(">\n <td sortable-data=\"");
michael@0 705
michael@0 706 // The sort key is the name of the item, prepended by either 0, 1 or 2
michael@0 707 // in order to group items.
michael@0 708 uint32_t type;
michael@0 709 aIndex->GetType(&type);
michael@0 710 switch (type) {
michael@0 711 case nsIDirIndex::TYPE_SYMLINK:
michael@0 712 pushBuffer.Append('0');
michael@0 713 break;
michael@0 714 case nsIDirIndex::TYPE_DIRECTORY:
michael@0 715 pushBuffer.Append('1');
michael@0 716 break;
michael@0 717 default:
michael@0 718 pushBuffer.Append('2');
michael@0 719 break;
michael@0 720 }
michael@0 721 nsAdoptingCString escaped(nsEscapeHTML(loc));
michael@0 722 pushBuffer.Append(escaped);
michael@0 723
michael@0 724 pushBuffer.AppendLiteral("\"><table class=\"ellipsis\"><tbody><tr><td><a class=\"");
michael@0 725 switch (type) {
michael@0 726 case nsIDirIndex::TYPE_DIRECTORY:
michael@0 727 pushBuffer.AppendLiteral("dir");
michael@0 728 break;
michael@0 729 case nsIDirIndex::TYPE_SYMLINK:
michael@0 730 pushBuffer.AppendLiteral("symlink");
michael@0 731 break;
michael@0 732 default:
michael@0 733 pushBuffer.AppendLiteral("file");
michael@0 734 break;
michael@0 735 }
michael@0 736
michael@0 737 pushBuffer.AppendLiteral("\" href=\"");
michael@0 738
michael@0 739 // need to escape links
michael@0 740 nsAutoCString locEscaped;
michael@0 741
michael@0 742 // Adding trailing slash helps to recognize whether the URL points to a file
michael@0 743 // or a directory (bug #214405).
michael@0 744 if ((type == nsIDirIndex::TYPE_DIRECTORY) && (loc.Last() != '/')) {
michael@0 745 loc.Append('/');
michael@0 746 }
michael@0 747
michael@0 748 // now minimally re-escape the location...
michael@0 749 uint32_t escFlags;
michael@0 750 // for some protocols, we expect the location to be absolute.
michael@0 751 // if so, and if the location indeed appears to be a valid URI, then go
michael@0 752 // ahead and treat it like one.
michael@0 753 if (mExpectAbsLoc &&
michael@0 754 NS_SUCCEEDED(net_ExtractURLScheme(loc, nullptr, nullptr, nullptr))) {
michael@0 755 // escape as absolute
michael@0 756 escFlags = esc_Forced | esc_AlwaysCopy | esc_Minimal;
michael@0 757 }
michael@0 758 else {
michael@0 759 // escape as relative
michael@0 760 // esc_Directory is needed because directories have a trailing slash.
michael@0 761 // Without it, the trailing '/' will be escaped, and links from within
michael@0 762 // that directory will be incorrect
michael@0 763 escFlags = esc_Forced | esc_AlwaysCopy | esc_FileBaseName | esc_Colon | esc_Directory;
michael@0 764 }
michael@0 765 NS_EscapeURL(loc.get(), loc.Length(), escFlags, locEscaped);
michael@0 766 // esc_Directory does not escape the semicolons, so if a filename
michael@0 767 // contains semicolons we need to manually escape them.
michael@0 768 // This replacement should be removed in bug #473280
michael@0 769 locEscaped.ReplaceSubstring(";", "%3b");
michael@0 770 nsAdoptingCString htmlEscapedURL(nsEscapeHTML(locEscaped.get()));
michael@0 771 pushBuffer.Append(htmlEscapedURL);
michael@0 772
michael@0 773 pushBuffer.AppendLiteral("\">");
michael@0 774
michael@0 775 if (type == nsIDirIndex::TYPE_FILE || type == nsIDirIndex::TYPE_UNKNOWN) {
michael@0 776 pushBuffer.AppendLiteral("<img src=\"moz-icon://");
michael@0 777 int32_t lastDot = locEscaped.RFindChar('.');
michael@0 778 if (lastDot != kNotFound) {
michael@0 779 locEscaped.Cut(0, lastDot);
michael@0 780 nsAdoptingCString htmlFileExt(nsEscapeHTML(locEscaped.get()));
michael@0 781 pushBuffer.Append(htmlFileExt);
michael@0 782 } else {
michael@0 783 pushBuffer.AppendLiteral("unknown");
michael@0 784 }
michael@0 785 pushBuffer.AppendLiteral("?size=16\" alt=\"");
michael@0 786
michael@0 787 nsXPIDLString altText;
michael@0 788 rv = mBundle->GetStringFromName(MOZ_UTF16("DirFileLabel"),
michael@0 789 getter_Copies(altText));
michael@0 790 if (NS_FAILED(rv)) return rv;
michael@0 791 AppendNonAsciiToNCR(altText, pushBuffer);
michael@0 792 pushBuffer.AppendLiteral("\">");
michael@0 793 }
michael@0 794
michael@0 795 pushBuffer.Append(escaped);
michael@0 796 pushBuffer.AppendLiteral("</a></td></tr></tbody></table></td>\n <td");
michael@0 797
michael@0 798 if (type == nsIDirIndex::TYPE_DIRECTORY || type == nsIDirIndex::TYPE_SYMLINK) {
michael@0 799 pushBuffer.AppendLiteral(">");
michael@0 800 } else {
michael@0 801 int64_t size;
michael@0 802 aIndex->GetSize(&size);
michael@0 803
michael@0 804 if (uint64_t(size) != UINT64_MAX) {
michael@0 805 pushBuffer.AppendLiteral(" sortable-data=\"");
michael@0 806 pushBuffer.AppendInt(size);
michael@0 807 pushBuffer.AppendLiteral("\">");
michael@0 808 nsAutoCString sizeString;
michael@0 809 FormatSizeString(size, sizeString);
michael@0 810 pushBuffer.Append(sizeString);
michael@0 811 } else {
michael@0 812 pushBuffer.AppendLiteral(">");
michael@0 813 }
michael@0 814 }
michael@0 815 pushBuffer.AppendLiteral("</td>\n <td");
michael@0 816
michael@0 817 PRTime t;
michael@0 818 aIndex->GetLastModified(&t);
michael@0 819
michael@0 820 if (t == -1) {
michael@0 821 pushBuffer.AppendLiteral("></td>\n <td>");
michael@0 822 } else {
michael@0 823 pushBuffer.AppendLiteral(" sortable-data=\"");
michael@0 824 pushBuffer.AppendInt(static_cast<int64_t>(t));
michael@0 825 pushBuffer.AppendLiteral("\">");
michael@0 826 nsAutoString formatted;
michael@0 827 mDateTime->FormatPRTime(nullptr,
michael@0 828 kDateFormatShort,
michael@0 829 kTimeFormatNone,
michael@0 830 t,
michael@0 831 formatted);
michael@0 832 AppendNonAsciiToNCR(formatted, pushBuffer);
michael@0 833 pushBuffer.AppendLiteral("</td>\n <td>");
michael@0 834 mDateTime->FormatPRTime(nullptr,
michael@0 835 kDateFormatNone,
michael@0 836 kTimeFormatSeconds,
michael@0 837 t,
michael@0 838 formatted);
michael@0 839 // use NCR to show date in any doc charset
michael@0 840 AppendNonAsciiToNCR(formatted, pushBuffer);
michael@0 841 }
michael@0 842
michael@0 843 pushBuffer.AppendLiteral("</td>\n</tr>");
michael@0 844
michael@0 845 return SendToListener(aRequest, aCtxt, pushBuffer);
michael@0 846 }
michael@0 847
michael@0 848 NS_IMETHODIMP
michael@0 849 nsIndexedToHTML::OnInformationAvailable(nsIRequest *aRequest,
michael@0 850 nsISupports *aCtxt,
michael@0 851 const nsAString& aInfo) {
michael@0 852 nsAutoCString pushBuffer;
michael@0 853 nsAdoptingString escaped(nsEscapeHTML2(PromiseFlatString(aInfo).get()));
michael@0 854 if (!escaped)
michael@0 855 return NS_ERROR_OUT_OF_MEMORY;
michael@0 856 pushBuffer.AppendLiteral("<tr>\n <td>");
michael@0 857 // escaped is provided in Unicode, so write hex NCRs as necessary
michael@0 858 // to prevent the HTML parser from applying a character set.
michael@0 859 AppendNonAsciiToNCR(escaped, pushBuffer);
michael@0 860 pushBuffer.AppendLiteral("</td>\n <td></td>\n <td></td>\n <td></td>\n</tr>\n");
michael@0 861
michael@0 862 return SendToListener(aRequest, aCtxt, pushBuffer);
michael@0 863 }
michael@0 864
michael@0 865 void nsIndexedToHTML::FormatSizeString(int64_t inSize, nsCString& outSizeString)
michael@0 866 {
michael@0 867 outSizeString.Truncate();
michael@0 868 if (inSize > int64_t(0)) {
michael@0 869 // round up to the nearest Kilobyte
michael@0 870 int64_t upperSize = (inSize + int64_t(1023)) / int64_t(1024);
michael@0 871 outSizeString.AppendInt(upperSize);
michael@0 872 outSizeString.AppendLiteral(" KB");
michael@0 873 }
michael@0 874 }
michael@0 875
michael@0 876 nsIndexedToHTML::nsIndexedToHTML() {
michael@0 877 }
michael@0 878
michael@0 879 nsIndexedToHTML::~nsIndexedToHTML() {
michael@0 880 }

mercurial