LCOV - code coverage report
Current view: directory - netwerk/streamconv/converters - nsIndexedToHTML.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 449 0 0.0 %
Date: 2012-06-02 Functions: 19 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Bradley Baetz <bbaetz@cs.mcgill.ca>
      24                 :  *   Christopher A. Aillon <christopher@aillon.com>
      25                 :  *   Dão Gottwald <dao@design-noir.de>
      26                 :  *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      30                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : 
      42                 : #include "nsIndexedToHTML.h"
      43                 : #include "nsNetUtil.h"
      44                 : #include "netCore.h"
      45                 : #include "nsStringStream.h"
      46                 : #include "nsIFileURL.h"
      47                 : #include "nsEscape.h"
      48                 : #include "nsIDirIndex.h"
      49                 : #include "prtime.h"
      50                 : #include "nsDateTimeFormatCID.h"
      51                 : #include "nsURLHelper.h"
      52                 : #include "nsCRT.h"
      53                 : #include "nsIPlatformCharset.h"
      54                 : #include "nsIPrefService.h"
      55                 : #include "nsIPrefBranch.h"
      56                 : #include "nsIPrefLocalizedString.h"
      57                 : #include "nsIChromeRegistry.h"
      58                 : 
      59               0 : NS_IMPL_ISUPPORTS4(nsIndexedToHTML,
      60                 :                    nsIDirIndexListener,
      61                 :                    nsIStreamConverter,
      62                 :                    nsIRequestObserver,
      63                 :                    nsIStreamListener)
      64                 : 
      65               0 : static void AppendNonAsciiToNCR(const nsAString& in, nsAFlatString& out)
      66                 : {
      67               0 :   nsAString::const_iterator start, end;
      68                 : 
      69               0 :   in.BeginReading(start);
      70               0 :   in.EndReading(end);
      71                 : 
      72               0 :   while (start != end) {
      73               0 :     if (*start < 128) {
      74               0 :       out.Append(*start++);
      75                 :     } else {
      76               0 :       out.AppendLiteral("&#x");
      77               0 :       nsAutoString hex;
      78               0 :       hex.AppendInt(*start++, 16);
      79               0 :       out.Append(hex);
      80               0 :       out.Append((PRUnichar)';');
      81                 :     }
      82                 :   }
      83               0 : }
      84                 : 
      85                 : nsresult
      86               0 : nsIndexedToHTML::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) {
      87                 :     nsresult rv;
      88               0 :     if (aOuter)
      89               0 :         return NS_ERROR_NO_AGGREGATION;
      90                 :     
      91               0 :     nsIndexedToHTML* _s = new nsIndexedToHTML();
      92               0 :     if (_s == nsnull)
      93               0 :         return NS_ERROR_OUT_OF_MEMORY;
      94                 :     
      95               0 :     rv = _s->QueryInterface(aIID, aResult);
      96               0 :     return rv;
      97                 : }
      98                 : 
      99                 : nsresult
     100               0 : nsIndexedToHTML::Init(nsIStreamListener* aListener) {
     101                 : 
     102               0 :     nsXPIDLString ellipsis;
     103               0 :     nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
     104               0 :     if (prefs) {
     105               0 :       nsCOMPtr<nsIPrefLocalizedString> prefVal;
     106               0 :       prefs->GetComplexValue("intl.ellipsis",
     107                 :                            NS_GET_IID(nsIPrefLocalizedString),
     108               0 :                            getter_AddRefs(prefVal));
     109               0 :       if (prefVal)
     110               0 :         prefVal->ToString(getter_Copies(ellipsis));
     111                 :     }
     112               0 :     if (ellipsis.IsEmpty())
     113               0 :       mEscapedEllipsis.AppendLiteral("&#8230;");
     114                 :     else
     115               0 :       mEscapedEllipsis.Adopt(nsEscapeHTML2(ellipsis.get(), ellipsis.Length()));
     116                 : 
     117               0 :     nsresult rv = NS_OK;
     118                 : 
     119               0 :     mListener = aListener;
     120                 : 
     121               0 :     mDateTime = do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &rv);
     122               0 :     if (NS_FAILED(rv))
     123               0 :       return rv;
     124                 : 
     125                 :     nsCOMPtr<nsIStringBundleService> sbs =
     126               0 :         do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
     127               0 :     if (NS_FAILED(rv)) return rv;
     128               0 :     rv = sbs->CreateBundle(NECKO_MSGS_URL, getter_AddRefs(mBundle));
     129                 : 
     130               0 :     mExpectAbsLoc = false;
     131                 : 
     132               0 :     return rv;
     133                 : }
     134                 : 
     135                 : NS_IMETHODIMP
     136               0 : nsIndexedToHTML::Convert(nsIInputStream* aFromStream,
     137                 :                          const char* aFromType,
     138                 :                          const char* aToType,
     139                 :                          nsISupports* aCtxt,
     140                 :                          nsIInputStream** res) {
     141               0 :     return NS_ERROR_NOT_IMPLEMENTED;
     142                 : }
     143                 : 
     144                 : NS_IMETHODIMP
     145               0 : nsIndexedToHTML::AsyncConvertData(const char *aFromType,
     146                 :                                   const char *aToType,
     147                 :                                   nsIStreamListener *aListener,
     148                 :                                   nsISupports *aCtxt) {
     149               0 :     return Init(aListener);
     150                 : }
     151                 : 
     152                 : NS_IMETHODIMP
     153               0 : nsIndexedToHTML::OnStartRequest(nsIRequest* request, nsISupports *aContext) {
     154               0 :     nsString buffer;
     155               0 :     nsresult rv = DoOnStartRequest(request, aContext, buffer);
     156               0 :     if (NS_FAILED(rv)) {
     157               0 :         request->Cancel(rv);
     158                 :     }
     159                 :     
     160               0 :     rv = mListener->OnStartRequest(request, aContext);
     161               0 :     if (NS_FAILED(rv)) return rv;
     162                 : 
     163                 :     // The request may have been canceled, and if that happens, we want to
     164                 :     // suppress calls to OnDataAvailable.
     165               0 :     request->GetStatus(&rv);
     166               0 :     if (NS_FAILED(rv)) return rv;
     167                 : 
     168                 :     // Push our buffer to the listener.
     169                 : 
     170               0 :     rv = FormatInputStream(request, aContext, buffer);
     171               0 :     return rv;
     172                 : }
     173                 : 
     174                 : nsresult
     175               0 : nsIndexedToHTML::DoOnStartRequest(nsIRequest* request, nsISupports *aContext,
     176                 :                                   nsString& aBuffer) {
     177                 :     nsresult rv;
     178                 : 
     179               0 :     nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
     180               0 :     nsCOMPtr<nsIURI> uri;
     181               0 :     rv = channel->GetURI(getter_AddRefs(uri));
     182               0 :     if (NS_FAILED(rv)) return rv;
     183                 : 
     184               0 :     channel->SetContentType(NS_LITERAL_CSTRING("text/html"));
     185                 : 
     186               0 :     mParser = do_CreateInstance("@mozilla.org/dirIndexParser;1",&rv);
     187               0 :     if (NS_FAILED(rv)) return rv;
     188                 : 
     189               0 :     rv = mParser->SetListener(this);
     190               0 :     if (NS_FAILED(rv)) return rv;
     191                 :     
     192               0 :     rv = mParser->OnStartRequest(request, aContext);
     193               0 :     if (NS_FAILED(rv)) return rv;
     194                 : 
     195               0 :     nsCAutoString baseUri, titleUri;
     196               0 :     rv = uri->GetAsciiSpec(baseUri);
     197               0 :     if (NS_FAILED(rv)) return rv;
     198               0 :     titleUri = baseUri;
     199                 : 
     200               0 :     nsCString parentStr;
     201                 : 
     202                 :     // XXX - should be using the 300: line from the parser.
     203                 :     // We can't guarantee that that comes before any entry, so we'd have to
     204                 :     // buffer, and do other painful stuff.
     205                 :     // I'll deal with this when I make the changes to handle welcome messages
     206                 :     // The .. stuff should also come from the lower level protocols, but that
     207                 :     // would muck up the XUL display
     208                 :     // - bbaetz
     209                 : 
     210               0 :     bool isScheme = false;
     211               0 :     bool isSchemeFile = false;
     212               0 :     if (NS_SUCCEEDED(uri->SchemeIs("ftp", &isScheme)) && isScheme) {
     213                 : 
     214                 :         // strip out the password here, so it doesn't show in the page title
     215                 :         // This is done by the 300: line generation in ftp, but we don't use
     216                 :         // that - see above
     217                 :         
     218               0 :         nsCAutoString pw;
     219               0 :         rv = uri->GetPassword(pw);
     220               0 :         if (NS_FAILED(rv)) return rv;
     221               0 :         if (!pw.IsEmpty()) {
     222               0 :              nsCOMPtr<nsIURI> newUri;
     223               0 :              rv = uri->Clone(getter_AddRefs(newUri));
     224               0 :              if (NS_FAILED(rv)) return rv;
     225               0 :              rv = newUri->SetPassword(EmptyCString());
     226               0 :              if (NS_FAILED(rv)) return rv;
     227               0 :              rv = newUri->GetAsciiSpec(titleUri);
     228               0 :              if (NS_FAILED(rv)) return rv;
     229                 :         }
     230                 : 
     231               0 :         nsCAutoString path;
     232               0 :         rv = uri->GetPath(path);
     233               0 :         if (NS_FAILED(rv)) return rv;
     234                 : 
     235               0 :         if (!path.EqualsLiteral("//") && !path.LowerCaseEqualsLiteral("/%2f")) {
     236               0 :             rv = uri->Resolve(NS_LITERAL_CSTRING(".."),parentStr);
     237               0 :             if (NS_FAILED(rv)) return rv;
     238                 :         }
     239               0 :     } else if (NS_SUCCEEDED(uri->SchemeIs("file", &isSchemeFile)) && isSchemeFile) {
     240               0 :         nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri);
     241               0 :         nsCOMPtr<nsIFile> file;
     242               0 :         rv = fileUrl->GetFile(getter_AddRefs(file));
     243               0 :         if (NS_FAILED(rv)) return rv;
     244               0 :         nsCOMPtr<nsILocalFile> lfile = do_QueryInterface(file, &rv);
     245               0 :         if (NS_FAILED(rv)) return rv;
     246               0 :         lfile->SetFollowLinks(true);
     247                 :         
     248               0 :         nsCAutoString url;
     249               0 :         rv = net_GetURLSpecFromFile(file, url);
     250               0 :         if (NS_FAILED(rv)) return rv;
     251               0 :         baseUri.Assign(url);
     252                 :         
     253               0 :         nsCOMPtr<nsIFile> parent;
     254               0 :         rv = file->GetParent(getter_AddRefs(parent));
     255                 :         
     256               0 :         if (parent && NS_SUCCEEDED(rv)) {
     257               0 :             net_GetURLSpecFromDir(parent, url);
     258               0 :             if (NS_FAILED(rv)) return rv;
     259               0 :             parentStr.Assign(url);
     260                 :         }
     261                 : 
     262                 :         // Directory index will be always encoded in UTF-8 if this is file url
     263               0 :         rv = mParser->SetEncoding("UTF-8");
     264               0 :         NS_ENSURE_SUCCESS(rv, rv);
     265                 : 
     266               0 :     } else if (NS_SUCCEEDED(uri->SchemeIs("jar", &isScheme)) && isScheme) {
     267               0 :         nsCAutoString path;
     268               0 :         rv = uri->GetPath(path);
     269               0 :         if (NS_FAILED(rv)) return rv;
     270                 : 
     271                 :         // a top-level jar directory URL is of the form jar:foo.zip!/
     272                 :         // path will be of the form foo.zip!/, and its last two characters
     273                 :         // will be "!/"
     274                 :         //XXX this won't work correctly when the name of the directory being
     275                 :         //XXX displayed ends with "!", but then again, jar: URIs don't deal
     276                 :         //XXX particularly well with such directories anyway
     277               0 :         if (!StringEndsWith(path, NS_LITERAL_CSTRING("!/"))) {
     278               0 :             rv = uri->Resolve(NS_LITERAL_CSTRING(".."), parentStr);
     279               0 :             if (NS_FAILED(rv)) return rv;
     280                 :         }
     281                 :     }
     282                 :     else {
     283                 :         // default behavior for other protocols is to assume the channel's
     284                 :         // URL references a directory ending in '/' -- fixup if necessary.
     285               0 :         nsCAutoString path;
     286               0 :         rv = uri->GetPath(path);
     287               0 :         if (NS_FAILED(rv)) return rv;
     288               0 :         if (baseUri.Last() != '/') {
     289               0 :             baseUri.Append('/');
     290               0 :             path.Append('/');
     291               0 :             uri->SetPath(path);
     292                 :         }
     293               0 :         if (!path.EqualsLiteral("/")) {
     294               0 :             rv = uri->Resolve(NS_LITERAL_CSTRING(".."), parentStr);
     295               0 :             if (NS_FAILED(rv)) return rv;
     296                 :         }
     297                 :     }
     298                 : 
     299               0 :     nsString buffer;
     300                 :     buffer.AppendLiteral("<!DOCTYPE html>\n"
     301                 :                          "<html>\n<head>\n"
     302               0 :                          "<meta http-equiv=\"content-type\" content=\"text/html; charset=");
     303                 :     
     304                 :     // Get the encoding from the parser
     305                 :     // XXX - this won't work for any encoding set via a 301: line in the
     306                 :     // format - this output stuff would need to move to OnDataAvailable
     307                 :     // for that.
     308                 : 
     309               0 :     nsXPIDLCString encoding;
     310               0 :     rv = mParser->GetEncoding(getter_Copies(encoding));
     311               0 :     if (NS_FAILED(rv)) return rv;
     312                 : 
     313               0 :     AppendASCIItoUTF16(encoding, buffer);
     314                 :     buffer.AppendLiteral("\">\n"
     315                 :                          "<style type=\"text/css\">\n"
     316                 :                          ":root {\n"
     317                 :                          "  font-family: sans-serif;\n"
     318                 :                          "}\n"
     319                 :                          "img {\n"
     320                 :                          "  border: 0;\n"
     321                 :                          "}\n"
     322                 :                          "th {\n"
     323                 :                          "  text-align: start;\n"
     324                 :                          "  white-space: nowrap;\n"
     325                 :                          "}\n"
     326                 :                          "th > a {\n"
     327                 :                          "  color: inherit;\n"
     328                 :                          "}\n"
     329                 :                          "table[order] > thead > tr > th {\n"
     330                 :                          "  cursor: pointer;\n"
     331                 :                          "}\n"
     332                 :                          "table[order] > thead > tr > th::after {\n"
     333                 :                          "  display: none;\n"
     334                 :                          "  width: .8em;\n"
     335                 :                          "  -moz-margin-end: -.8em;\n"
     336                 :                          "  text-align: end;\n"
     337                 :                          "}\n"
     338                 :                          "table[order=\"asc\"] > thead > tr > th::after {\n"
     339                 :                          "  content: \"\\2193\"; /* DOWNWARDS ARROW (U+2193) */\n"
     340                 :                          "}\n"
     341                 :                          "table[order=\"desc\"] > thead > tr > th::after {\n"
     342                 :                          "  content: \"\\2191\"; /* UPWARDS ARROW (U+2191) */\n"
     343                 :                          "}\n"
     344                 :                          "table[order][order-by=\"0\"] > thead > tr > th:first-child > a ,\n"
     345                 :                          "table[order][order-by=\"1\"] > thead > tr > th:first-child + th > a ,\n"
     346                 :                          "table[order][order-by=\"2\"] > thead > tr > th:first-child + th + th > a {\n"
     347                 :                          "  text-decoration: underline;\n"
     348                 :                          "}\n"
     349                 :                          "table[order][order-by=\"0\"] > thead > tr > th:first-child::after ,\n"
     350                 :                          "table[order][order-by=\"1\"] > thead > tr > th:first-child + th::after ,\n"
     351                 :                          "table[order][order-by=\"2\"] > thead > tr > th:first-child + th + th::after {\n"
     352                 :                          "  display: inline-block;\n"
     353                 :                          "}\n"
     354                 :                          "table.remove-hidden > tbody > tr.hidden-object {\n"
     355                 :                          "  display: none;\n"
     356                 :                          "}\n"
     357                 :                          "td > a {\n"
     358                 :                          "  display: inline-block;\n"
     359                 :                          "}\n"
     360                 :                          "/* name */\n"
     361                 :                          "th:first-child {\n"
     362                 :                          "  -moz-padding-end: 2em;\n"
     363                 :                          "}\n"
     364                 :                          "/* size */\n"
     365                 :                          "th:first-child + th {\n"
     366                 :                          "  -moz-padding-end: 1em;\n"
     367                 :                          "}\n"
     368                 :                          "td:first-child + td {\n"
     369                 :                          "  text-align: end;\n"
     370                 :                          "  -moz-padding-end: 1em;\n"
     371                 :                          "  white-space: nowrap;\n"
     372                 :                          "}\n"
     373                 :                          "/* date */\n"
     374                 :                          "td:first-child + td + td {\n"
     375                 :                          "  -moz-padding-start: 1em;\n"
     376                 :                          "  -moz-padding-end: .5em;\n"
     377                 :                          "  white-space: nowrap;\n"
     378                 :                          "}\n"
     379                 :                          "/* time */\n"
     380                 :                          "td:last-child {\n"
     381                 :                          "  -moz-padding-start: .5em;\n"
     382                 :                          "  white-space: nowrap;\n"
     383                 :                          "}\n"
     384                 :                          ".symlink {\n"
     385                 :                          "  font-style: italic;\n"
     386                 :                          "}\n"
     387                 :                          ".dir ,\n"
     388                 :                          ".symlink ,\n"
     389                 :                          ".file {\n"
     390                 :                          "  -moz-margin-start: 20px;\n"
     391                 :                          "}\n"
     392                 :                          ".dir::before ,\n"
     393                 :                          ".file > img {\n"
     394                 :                          "  -moz-margin-end: 4px;\n"
     395                 :                          "  -moz-margin-start: -20px;\n"
     396                 :                          "  vertical-align: middle;\n"
     397                 :                          "}\n"
     398                 :                          ".dir::before {\n"
     399                 :                          "  content: url(resource://gre/res/html/folder.png);\n"
     400                 :                          "}\n"
     401                 :                          "</style>\n"
     402                 :                          "<link rel=\"stylesheet\" media=\"screen, projection\" type=\"text/css\""
     403                 :                          " href=\"chrome://global/skin/dirListing/dirListing.css\">\n"
     404                 :                          "<script type=\"application/javascript\">\n"
     405                 :                          "var gTable, gOrderBy, gTBody, gRows, gUI_showHidden;\n"
     406                 :                          "document.addEventListener(\"DOMContentLoaded\", function() {\n"
     407                 :                          "  gTable = document.getElementsByTagName(\"table\")[0];\n"
     408                 :                          "  gTBody = gTable.tBodies[0];\n"
     409                 :                          "  if (gTBody.rows.length < 2)\n"
     410                 :                          "    return;\n"
     411                 :                          "  gUI_showHidden = document.getElementById(\"UI_showHidden\");\n"
     412                 :                          "  var headCells = gTable.tHead.rows[0].cells,\n"
     413                 :                          "      hiddenObjects = false;\n"
     414                 :                          "  function rowAction(i) {\n"
     415                 :                          "    return function(event) {\n"
     416                 :                          "      event.preventDefault();\n"
     417                 :                          "      orderBy(i);\n"
     418                 :                          "    }\n"
     419                 :                          "  }\n"
     420                 :                          "  for (var i = headCells.length - 1; i >= 0; i--) {\n"
     421                 :                          "    var anchor = document.createElement(\"a\");\n"
     422                 :                          "    anchor.href = \"\";\n"
     423                 :                          "    anchor.appendChild(headCells[i].firstChild);\n"
     424                 :                          "    headCells[i].appendChild(anchor);\n"
     425                 :                          "    headCells[i].addEventListener(\"click\", rowAction(i), true);\n"
     426                 :                          "  }\n"
     427                 :                          "  if (gUI_showHidden) {\n"
     428                 :                          "    gRows = Array.slice(gTBody.rows);\n"
     429                 :                          "    hiddenObjects = gRows.some(function (row) row.className == \"hidden-object\");\n"
     430                 :                          "  }\n"
     431                 :                          "  gTable.setAttribute(\"order\", \"\");\n"
     432                 :                          "  if (hiddenObjects) {\n"
     433                 :                          "    gUI_showHidden.style.display = \"block\";\n"
     434                 :                          "    updateHidden();\n"
     435                 :                          "  }\n"
     436                 :                          "}, \"false\");\n"
     437                 :                          "function compareRows(rowA, rowB) {\n"
     438                 :                          "  var a = rowA.cells[gOrderBy].getAttribute(\"sortable-data\") || \"\";\n"
     439                 :                          "  var b = rowB.cells[gOrderBy].getAttribute(\"sortable-data\") || \"\";\n"
     440                 :                          "  var intA = +a;\n"
     441                 :                          "  var intB = +b;\n"
     442                 :                          "  if (a == intA && b == intB) {\n"
     443                 :                          "    a = intA;\n"
     444                 :                          "    b = intB;\n"
     445                 :                          "  } else {\n"
     446                 :                          "    a = a.toLowerCase();\n"
     447                 :                          "    b = b.toLowerCase();\n"
     448                 :                          "  }\n"
     449                 :                          "  if (a < b)\n"
     450                 :                          "    return -1;\n"
     451                 :                          "  if (a > b)\n"
     452                 :                          "    return 1;\n"
     453                 :                          "  return 0;\n"
     454                 :                          "}\n"
     455                 :                          "function orderBy(column) {\n"
     456                 :                          "  if (!gRows)\n"
     457                 :                          "    gRows = Array.slice(gTBody.rows);\n"
     458                 :                          "  var order;\n"
     459                 :                          "  if (gOrderBy == column) {\n"
     460                 :                          "    order = gTable.getAttribute(\"order\") == \"asc\" ? \"desc\" : \"asc\";\n"
     461                 :                          "  } else {\n"
     462                 :                          "    order = \"asc\";\n"
     463                 :                          "    gOrderBy = column;\n"
     464                 :                          "    gTable.setAttribute(\"order-by\", column);\n"
     465                 :                          "    gRows.sort(compareRows);\n"
     466                 :                          "  }\n"
     467                 :                          "  gTable.removeChild(gTBody);\n"
     468                 :                          "  gTable.setAttribute(\"order\", order);\n"
     469                 :                          "  if (order == \"asc\")\n"
     470                 :                          "    for (var i = 0; i < gRows.length; i++)\n"
     471                 :                          "      gTBody.appendChild(gRows[i]);\n"
     472                 :                          "  else\n"
     473                 :                          "    for (var i = gRows.length - 1; i >= 0; i--)\n"
     474                 :                          "      gTBody.appendChild(gRows[i]);\n"
     475                 :                          "  gTable.appendChild(gTBody);\n"
     476                 :                          "}\n"
     477                 :                          "function updateHidden() {\n"
     478                 :                          "  gTable.className = gUI_showHidden.getElementsByTagName(\"input\")[0].checked ?\n"
     479                 :                          "                     \"\" :\n"
     480                 :                          "                     \"remove-hidden\";\n"
     481                 :                          "}\n"
     482               0 :                          "</script>\n");
     483                 : 
     484               0 :     buffer.AppendLiteral("<link rel=\"icon\" type=\"image/png\" href=\"");
     485               0 :     nsCOMPtr<nsIURI> innerUri = NS_GetInnermostURI(uri);
     486               0 :     if (!innerUri)
     487               0 :         return NS_ERROR_UNEXPECTED;
     488               0 :     nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(innerUri));
     489                 :     //XXX bug 388553: can't use skinnable icons here due to security restrictions
     490               0 :     if (fileURL) {
     491                 :         //buffer.AppendLiteral("chrome://global/skin/dirListing/local.png");
     492                 :         buffer.AppendLiteral("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB"
     493                 :                              "AAAAAQCAYAAAAf8%2F9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9i"
     494                 :                              "ZSBJbWFnZVJlYWR5ccllPAAAAjFJREFUeNqsU8uOElEQPffR"
     495                 :                              "3XQ3ONASdBJCSBxHos5%2B3Bg3rvkCv8PElS78gPkO%2FATj"
     496                 :                              "QoUdO2ftrJiRh6aneTb9sOpC4weMN6lcuFV16pxDIfI8x12O"
     497                 :                              "YIDhcPiu2Wx%2B%2FHF5CW1Z6Jyegt%2FTNEWSJIjjGFEUIQ"
     498                 :                              "xDrFYrWFSzXC4%2FdLvd95pRKpXKy%2BpRFZ7nwaWo1%2BsG"
     499                 :                              "nQG2260BKJfLKJVKGI1GEEJw7ateryd0v993W63WEwjgxfn5"
     500                 :                              "obGYzgCbzcaEbdsIggDj8Riu6z6iUk9SYZMSx8W0LMsM%2FS"
     501                 :                              "KK75xnJlIq80anQXdbEp0OhcPJ0eiaJnGRMEyyPDsAKKUM9c"
     502                 :                              "lkYoDo3SZJzzSdp0VSKYmfV1co%2Bz580kw5KDIM8RbRfEnU"
     503                 :                              "f1HzxtQyMAGcaGruTKczMzEIaqhKifV6jd%2BzGQQB5llunF"
     504                 :                              "%2FM52BizC2K5sYPYvZcu653tjOM9O93wnYc08gmkgg4VAxi"
     505                 :                              "xfqFUJT36AYBZGd6PJkFCZnnlBxMp38gqIgLpZB0y4Nph18l"
     506                 :                              "yWh5FFbrOSxbl3V4G%2BVB7T4ajYYxTyuLtO%2BCvWGgJE1M"
     507                 :                              "c7JNsJEhvgw%2FQV4fo%2F24nbEsX2u1d5sVyn8sJO0ZAQiI"
     508                 :                              "YnFh%2BxrfLz%2Fj29cBS%2FO14zg3i8XigW3ZkErDtmKoeM"
     509                 :                              "%2BAJGRMnXeEPGKf0nCD1ydvkDzU9Jbc6OpR7WIw6L8lQ%2B"
     510                 :                              "4pQ1%2FlPF0RGM9Ns91Wmptk0GfB4EJkt77vXYj%2F8m%2B8"
     511               0 :                              "y%2FkrwABHbz2H9V68DQAAAABJRU5ErkJggg%3D%3D");
     512                 :     } else {
     513                 :         //buffer.AppendLiteral("chrome://global/skin/dirListing/remote.png");
     514                 :         buffer.AppendLiteral("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB"
     515                 :                              "AAAAAQCAYAAAAf8%2F9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9i"
     516                 :                              "ZSBJbWFnZVJlYWR5ccllPAAAAeBJREFUeNqcU81O20AQ%2Ft"
     517                 :                              "Z2AgQSYQRqL1UPVG2hAUQkxLEStz4DrXpLpD5Drz31Cajax%"
     518                 :                              "2Bghhx6qHIJURBTxIwQRwopCBbZjHMcOTrzermPipsSt1Iw0"
     519                 :                              "3p3ZmW%2B%2B2R0TxhgOD34wjCHZlQ0iDYz9yvEfhxMTCYhE"
     520                 :                              "QDIZhkxKd2sqzX2TOD2vBQCQhpPefng1ZP2dVPlLLdpL8SEM"
     521                 :                              "cxng%2Fbs0RIHhtgs4twxOh%2BHjZxvzDx%2F3GQQiDFISiR"
     522                 :                              "BLFMPKTRMollzcWECrDVhtxtdRVsL9youPxGj%2FbdfFlUZh"
     523                 :                              "tDyYbYqWRUdai1oQRZ5oHeHl2gNM%2B01Uqio8RlH%2Bnsaz"
     524                 :                              "JzNwXcq1B%2BiXPHprlEEymeBfXs1w8XxxihfyuXqoHqpoGj"
     525                 :                              "ZM04bddgG%2F9%2B8WGj87qDdsrK9m%2BoA%2BpbhQTDh2l1"
     526                 :                              "%2Bi2weNbSHMZyjvNXmVbqh9Fj5Oz27uEoP%2BSTxANruJs9"
     527                 :                              "L%2FT6P0ewqPx5nmiAG5f6AoCtN1PbJzuRyJAyDBzzSQYvEr"
     528                 :                              "f06yYxhGXlEa8H2KVGoasjwLx3Ewk858opQWXm%2B%2Fib9E"
     529                 :                              "QrBzclLLLy89xYvlpchvtixcX6uo1y%2FzsiwHrkIsgKbp%2"
     530                 :                              "BYWFOWicuqppoNTnStHzPFCPQhBEBOyGAX4JMADFetubi4BS"
     531               0 :                              "YAAAAABJRU5ErkJggg%3D%3D");
     532                 :     }
     533               0 :     buffer.AppendLiteral("\">\n<title>");
     534                 : 
     535                 :     // Everything needs to end in a /,
     536                 :     // otherwise we end up linking to file:///foo/dirfile
     537                 : 
     538               0 :     if (!mTextToSubURI) {
     539               0 :         mTextToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
     540               0 :         if (NS_FAILED(rv)) return rv;
     541                 :     }
     542                 : 
     543               0 :     nsXPIDLString unEscapeSpec;
     544               0 :     rv = mTextToSubURI->UnEscapeAndConvert(encoding, titleUri.get(),
     545               0 :                                            getter_Copies(unEscapeSpec));
     546                 :     // unescape may fail because
     547                 :     // 1. file URL may be encoded in platform charset for backward compatibility
     548                 :     // 2. query part may not be encoded in UTF-8 (see bug 261929)
     549                 :     // so try the platform's default if this is file url
     550               0 :     if (NS_FAILED(rv) && isSchemeFile) {
     551               0 :         nsCOMPtr<nsIPlatformCharset> platformCharset(do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv));
     552               0 :         NS_ENSURE_SUCCESS(rv, rv);
     553               0 :         nsCAutoString charset;
     554               0 :         rv = platformCharset->GetCharset(kPlatformCharsetSel_FileName, charset);
     555               0 :         NS_ENSURE_SUCCESS(rv, rv);
     556                 : 
     557               0 :         rv = mTextToSubURI->UnEscapeAndConvert(charset.get(), titleUri.get(),
     558               0 :                                                getter_Copies(unEscapeSpec));
     559                 :     }
     560               0 :     if (NS_FAILED(rv)) return rv;
     561                 : 
     562               0 :     nsXPIDLString htmlEscSpec;
     563                 :     htmlEscSpec.Adopt(nsEscapeHTML2(unEscapeSpec.get(),
     564               0 :                                     unEscapeSpec.Length()));
     565                 : 
     566               0 :     nsXPIDLString title;
     567                 :     const PRUnichar* formatTitle[] = {
     568               0 :         htmlEscSpec.get()
     569               0 :     };
     570                 : 
     571               0 :     rv = mBundle->FormatStringFromName(NS_LITERAL_STRING("DirTitle").get(),
     572                 :                                        formatTitle,
     573                 :                                        sizeof(formatTitle)/sizeof(PRUnichar*),
     574               0 :                                        getter_Copies(title));
     575               0 :     if (NS_FAILED(rv)) return rv;
     576                 : 
     577                 :     // we want to convert string bundle to NCR
     578                 :     // to ensure they're shown in any charsets
     579               0 :     AppendNonAsciiToNCR(title, buffer);
     580                 : 
     581               0 :     buffer.AppendLiteral("</title>\n");    
     582                 : 
     583                 :     // If there is a quote character in the baseUri, then
     584                 :     // lets not add a base URL.  The reason for this is that
     585                 :     // if we stick baseUri containing a quote into a quoted
     586                 :     // string, the quote character will prematurely close
     587                 :     // the base href string.  This is a fall-back check;
     588                 :     // that's why it is OK to not use a base rather than
     589                 :     // trying to play nice and escaping the quotes.  See bug
     590                 :     // 358128.
     591                 : 
     592               0 :     if (baseUri.FindChar('"') == kNotFound)
     593                 :     {
     594                 :         // Great, the baseUri does not contain a char that
     595                 :         // will prematurely close the string.  Go ahead an
     596                 :         // add a base href.
     597               0 :         buffer.AppendLiteral("<base href=\"");
     598               0 :         NS_ConvertUTF8toUTF16 utf16BaseURI(baseUri);
     599               0 :         nsString htmlEscapedUri;
     600               0 :         htmlEscapedUri.Adopt(nsEscapeHTML2(utf16BaseURI.get(), utf16BaseURI.Length()));
     601               0 :         buffer.Append(htmlEscapedUri);
     602               0 :         buffer.AppendLiteral("\" />\n");
     603                 :     }
     604                 :     else
     605                 :     {
     606               0 :         NS_ERROR("broken protocol handler didn't escape double-quote.");
     607                 :     }
     608                 : 
     609               0 :     nsAutoString direction(NS_LITERAL_STRING("ltr"));
     610                 :     nsCOMPtr<nsIXULChromeRegistry> reg =
     611               0 :       mozilla::services::GetXULChromeRegistryService();
     612               0 :     if (reg) {
     613               0 :       bool isRTL = false;
     614               0 :       reg->IsLocaleRTL(NS_LITERAL_CSTRING("global"), &isRTL);
     615               0 :       if (isRTL) {
     616               0 :         direction.AssignLiteral("rtl");
     617                 :       }
     618                 :     }
     619                 : 
     620               0 :     buffer.AppendLiteral("</head>\n<body dir=\"");
     621               0 :     buffer.Append(direction);
     622               0 :     buffer.AppendLiteral("\">\n<h1>");
     623                 :     
     624                 :     const PRUnichar* formatHeading[] = {
     625               0 :         htmlEscSpec.get()
     626               0 :     };
     627                 : 
     628               0 :     rv = mBundle->FormatStringFromName(NS_LITERAL_STRING("DirTitle").get(),
     629                 :                                        formatHeading,
     630                 :                                        sizeof(formatHeading)/sizeof(PRUnichar*),
     631               0 :                                        getter_Copies(title));
     632               0 :     if (NS_FAILED(rv)) return rv;
     633                 :     
     634               0 :     AppendNonAsciiToNCR(title, buffer);
     635               0 :     buffer.AppendLiteral("</h1>\n");
     636                 : 
     637               0 :     if (!parentStr.IsEmpty()) {
     638               0 :         nsXPIDLString parentText;
     639               0 :         rv = mBundle->GetStringFromName(NS_LITERAL_STRING("DirGoUp").get(),
     640               0 :                                         getter_Copies(parentText));
     641               0 :         if (NS_FAILED(rv)) return rv;
     642                 : 
     643               0 :         buffer.AppendLiteral("<p id=\"UI_goUp\"><a class=\"up\" href=\"");
     644                 : 
     645               0 :         NS_ConvertUTF8toUTF16 utf16ParentStr(parentStr);
     646               0 :         nsString htmlParentStr;
     647               0 :         htmlParentStr.Adopt(nsEscapeHTML2(utf16ParentStr.get(), utf16ParentStr.Length()));
     648               0 :         buffer.Append(htmlParentStr);
     649               0 :         buffer.AppendLiteral("\">");
     650               0 :         AppendNonAsciiToNCR(parentText, buffer);
     651               0 :         buffer.AppendLiteral("</a></p>\n");
     652                 :     }
     653                 : 
     654               0 :     if (isSchemeFile) {
     655               0 :         nsXPIDLString showHiddenText;
     656               0 :         rv = mBundle->GetStringFromName(NS_LITERAL_STRING("ShowHidden").get(),
     657               0 :                                         getter_Copies(showHiddenText));
     658               0 :         if (NS_FAILED(rv)) return rv;
     659                 : 
     660               0 :         buffer.AppendLiteral("<p id=\"UI_showHidden\" style=\"display:none\"><label><input type=\"checkbox\" checked onchange=\"updateHidden()\">");
     661               0 :         AppendNonAsciiToNCR(showHiddenText, buffer);
     662               0 :         buffer.AppendLiteral("</label></p>\n");
     663                 :     }
     664                 : 
     665               0 :     buffer.AppendLiteral("<table>\n");
     666                 : 
     667               0 :     nsXPIDLString columnText;
     668                 : 
     669                 :     buffer.AppendLiteral(" <thead>\n"
     670                 :                          "  <tr>\n"
     671               0 :                          "   <th>");
     672                 : 
     673               0 :     rv = mBundle->GetStringFromName(NS_LITERAL_STRING("DirColName").get(),
     674               0 :                                     getter_Copies(columnText));
     675               0 :     if (NS_FAILED(rv)) return rv;
     676               0 :     AppendNonAsciiToNCR(columnText, buffer);
     677                 :     buffer.AppendLiteral("</th>\n"
     678               0 :                          "   <th>");
     679                 : 
     680               0 :     rv = mBundle->GetStringFromName(NS_LITERAL_STRING("DirColSize").get(),
     681               0 :                                     getter_Copies(columnText));
     682               0 :     if (NS_FAILED(rv)) return rv;
     683               0 :     AppendNonAsciiToNCR(columnText, buffer);
     684                 :     buffer.AppendLiteral("</th>\n"
     685               0 :                          "   <th colspan=\"2\">");
     686                 : 
     687               0 :     rv = mBundle->GetStringFromName(NS_LITERAL_STRING("DirColMTime").get(),
     688               0 :                                     getter_Copies(columnText));
     689               0 :     if (NS_FAILED(rv)) return rv;
     690               0 :     AppendNonAsciiToNCR(columnText, buffer);
     691                 :     buffer.AppendLiteral("</th>\n"
     692                 :                          "  </tr>\n"
     693               0 :                          " </thead>\n");
     694               0 :     buffer.AppendLiteral(" <tbody>\n");
     695                 : 
     696               0 :     aBuffer = buffer;
     697               0 :     return rv;
     698                 : }
     699                 : 
     700                 : NS_IMETHODIMP
     701               0 : nsIndexedToHTML::OnStopRequest(nsIRequest* request, nsISupports *aContext,
     702                 :                                nsresult aStatus) {
     703               0 :     if (NS_SUCCEEDED(aStatus)) {
     704               0 :         nsString buffer;
     705               0 :         buffer.AssignLiteral("</tbody></table></body></html>\n");
     706                 : 
     707               0 :         aStatus = FormatInputStream(request, aContext, buffer);
     708                 :     }
     709                 : 
     710               0 :     mParser->OnStopRequest(request, aContext, aStatus);
     711               0 :     mParser = 0;
     712                 :     
     713               0 :     return mListener->OnStopRequest(request, aContext, aStatus);
     714                 : }
     715                 : 
     716                 : nsresult
     717               0 : nsIndexedToHTML::FormatInputStream(nsIRequest* aRequest, nsISupports *aContext, const nsAString &aBuffer) 
     718                 : {
     719               0 :     nsresult rv = NS_OK;
     720                 : 
     721                 :     // set up unicode encoder
     722               0 :     if (!mUnicodeEncoder) {
     723               0 :       nsXPIDLCString encoding;
     724               0 :       rv = mParser->GetEncoding(getter_Copies(encoding));
     725               0 :       if (NS_SUCCEEDED(rv)) {
     726               0 :         nsCOMPtr<nsICharsetConverterManager> charsetConverterManager;
     727               0 :         charsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
     728               0 :         rv = charsetConverterManager->GetUnicodeEncoder(encoding.get(), 
     729               0 :                                                           getter_AddRefs(mUnicodeEncoder));
     730               0 :         if (NS_SUCCEEDED(rv))
     731               0 :             rv = mUnicodeEncoder->SetOutputErrorBehavior(nsIUnicodeEncoder::kOnError_Replace, 
     732               0 :                                                        nsnull, (PRUnichar)'?');
     733                 :       }
     734                 :     }
     735                 : 
     736                 :     // convert the data with unicode encoder
     737               0 :     char *buffer = nsnull;
     738                 :     PRInt32 dstLength;
     739               0 :     if (NS_SUCCEEDED(rv)) {
     740               0 :       PRInt32 unicharLength = aBuffer.Length();
     741               0 :       rv = mUnicodeEncoder->GetMaxLength(PromiseFlatString(aBuffer).get(), 
     742               0 :                                          unicharLength, &dstLength);
     743               0 :       if (NS_SUCCEEDED(rv)) {
     744               0 :         buffer = (char *) nsMemory::Alloc(dstLength);
     745               0 :         NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
     746                 : 
     747               0 :         rv = mUnicodeEncoder->Convert(PromiseFlatString(aBuffer).get(), &unicharLength, 
     748               0 :                                       buffer, &dstLength);
     749               0 :         if (NS_SUCCEEDED(rv)) {
     750               0 :           PRInt32 finLen = 0;
     751               0 :           rv = mUnicodeEncoder->Finish(buffer + dstLength, &finLen);
     752               0 :           if (NS_SUCCEEDED(rv))
     753               0 :             dstLength += finLen;
     754                 :         }
     755                 :       }
     756                 :     }
     757                 : 
     758                 :     // if conversion error then fallback to UTF-8
     759               0 :     if (NS_FAILED(rv)) {
     760               0 :       rv = NS_OK;
     761               0 :       if (buffer) {
     762               0 :         nsMemory::Free(buffer);
     763               0 :         buffer = nsnull;
     764                 :       }
     765                 :     }
     766                 : 
     767               0 :     nsCOMPtr<nsIInputStream> inputData;
     768               0 :     if (buffer) {
     769               0 :       rv = NS_NewCStringInputStream(getter_AddRefs(inputData), Substring(buffer, dstLength));
     770               0 :       nsMemory::Free(buffer);
     771               0 :       NS_ENSURE_SUCCESS(rv, rv);
     772               0 :       rv = mListener->OnDataAvailable(aRequest, aContext,
     773               0 :                                       inputData, 0, dstLength);
     774                 :     }
     775                 :     else {
     776               0 :       NS_ConvertUTF16toUTF8 utf8Buffer(aBuffer);
     777               0 :       rv = NS_NewCStringInputStream(getter_AddRefs(inputData), utf8Buffer);
     778               0 :       NS_ENSURE_SUCCESS(rv, rv);
     779               0 :       rv = mListener->OnDataAvailable(aRequest, aContext,
     780               0 :                                       inputData, 0, utf8Buffer.Length());
     781                 :     }
     782               0 :     return (rv);
     783                 : }
     784                 : 
     785                 : NS_IMETHODIMP
     786               0 : nsIndexedToHTML::OnDataAvailable(nsIRequest *aRequest,
     787                 :                                  nsISupports *aCtxt,
     788                 :                                  nsIInputStream* aInput,
     789                 :                                  PRUint32 aOffset,
     790                 :                                  PRUint32 aCount) {
     791               0 :     return mParser->OnDataAvailable(aRequest, aCtxt, aInput, aOffset, aCount);
     792                 : }
     793                 : 
     794                 : NS_IMETHODIMP
     795               0 : nsIndexedToHTML::OnIndexAvailable(nsIRequest *aRequest,
     796                 :                                   nsISupports *aCtxt,
     797                 :                                   nsIDirIndex *aIndex) {
     798                 :     nsresult rv;
     799               0 :     if (!aIndex)
     800               0 :         return NS_ERROR_NULL_POINTER;
     801                 : 
     802               0 :     nsString pushBuffer;
     803               0 :     pushBuffer.AppendLiteral("<tr");
     804                 : 
     805               0 :     nsXPIDLString description;
     806               0 :     aIndex->GetDescription(getter_Copies(description));
     807               0 :     if (description.First() == PRUnichar('.'))
     808               0 :         pushBuffer.AppendLiteral(" class=\"hidden-object\"");
     809                 : 
     810               0 :     pushBuffer.AppendLiteral(">\n <td sortable-data=\"");
     811                 : 
     812                 :     // The sort key is the name of the item, prepended by either 0, 1 or 2
     813                 :     // in order to group items.
     814                 :     PRUint32 type;
     815               0 :     aIndex->GetType(&type);
     816               0 :     switch (type) {
     817                 :         case nsIDirIndex::TYPE_SYMLINK:
     818               0 :             pushBuffer.AppendInt(0);
     819               0 :             break;
     820                 :         case nsIDirIndex::TYPE_DIRECTORY:
     821               0 :             pushBuffer.AppendInt(1);
     822               0 :             break;
     823                 :         case nsIDirIndex::TYPE_FILE:
     824                 :         case nsIDirIndex::TYPE_UNKNOWN:
     825               0 :             pushBuffer.AppendInt(2);
     826               0 :             break;
     827                 :     }
     828               0 :     PRUnichar* escaped = nsEscapeHTML2(description.get(), description.Length());
     829               0 :     pushBuffer.Append(escaped);
     830                 : 
     831               0 :     pushBuffer.AppendLiteral("\"><a class=\"");
     832               0 :     switch (type) {
     833                 :         case nsIDirIndex::TYPE_DIRECTORY:
     834               0 :             pushBuffer.AppendLiteral("dir");
     835               0 :             break;
     836                 :         case nsIDirIndex::TYPE_SYMLINK:
     837               0 :             pushBuffer.AppendLiteral("symlink");
     838               0 :             break;
     839                 :         case nsIDirIndex::TYPE_FILE:
     840                 :         case nsIDirIndex::TYPE_UNKNOWN:
     841               0 :             pushBuffer.AppendLiteral("file");
     842               0 :             break;
     843                 :     }
     844               0 :     pushBuffer.AppendLiteral("\"");
     845                 : 
     846                 :     // Truncate long names to not stretch the table
     847                 :     //XXX this should be left to the stylesheet (bug 391471)
     848               0 :     nsString escapedShort;
     849               0 :     if (description.Length() > 71) {
     850               0 :         nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
     851               0 :         nsCOMPtr<nsIURI> uri;
     852               0 :         rv = channel->GetURI(getter_AddRefs(uri));
     853               0 :         if (NS_FAILED(rv)) return rv;
     854                 : 
     855                 :         //XXX this potentially truncates after a combining char (bug 391472)
     856               0 :         nsXPIDLString descriptionAffix;
     857               0 :         descriptionAffix.Assign(description);
     858               0 :         descriptionAffix.Cut(0, descriptionAffix.Length() - 25);
     859               0 :         if (NS_IS_LOW_SURROGATE(descriptionAffix.First()))
     860               0 :             descriptionAffix.Cut(0, 1);
     861               0 :         description.Truncate(NS_MIN<PRUint32>(71, description.Length() - 28));
     862               0 :         if (NS_IS_HIGH_SURROGATE(description.Last()))
     863               0 :             description.Truncate(description.Length() - 1);
     864                 : 
     865               0 :         escapedShort.Adopt(nsEscapeHTML2(description.get(), description.Length()));
     866                 : 
     867               0 :         escapedShort.Append(mEscapedEllipsis);
     868                 :         // add ZERO WIDTH SPACE (U+200B) for wrapping
     869               0 :         escapedShort.AppendLiteral("&#8203;");
     870               0 :         nsString tmp;
     871               0 :         tmp.Adopt(nsEscapeHTML2(descriptionAffix.get(), descriptionAffix.Length()));
     872               0 :         escapedShort.Append(tmp);
     873                 : 
     874               0 :         pushBuffer.AppendLiteral(" title=\"");
     875               0 :         pushBuffer.Append(escaped);
     876               0 :         pushBuffer.AppendLiteral("\"");
     877                 :     }
     878               0 :     if (escapedShort.IsEmpty())
     879               0 :         escapedShort.Assign(escaped);
     880               0 :     nsMemory::Free(escaped);
     881                 : 
     882               0 :     pushBuffer.AppendLiteral(" href=\"");
     883               0 :     nsXPIDLCString loc;
     884               0 :     aIndex->GetLocation(getter_Copies(loc));
     885                 : 
     886               0 :     if (!mTextToSubURI) {
     887               0 :         mTextToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
     888               0 :         if (NS_FAILED(rv)) return rv;
     889                 :     }
     890                 : 
     891               0 :     nsXPIDLCString encoding;
     892               0 :     rv = mParser->GetEncoding(getter_Copies(encoding));
     893               0 :     if (NS_FAILED(rv)) return rv;
     894                 : 
     895               0 :     nsXPIDLString unEscapeSpec;
     896               0 :     rv = mTextToSubURI->UnEscapeAndConvert(encoding, loc,
     897               0 :                                            getter_Copies(unEscapeSpec));
     898               0 :     if (NS_FAILED(rv)) return rv;
     899                 : 
     900                 :     // need to escape links
     901               0 :     nsCAutoString escapeBuf;
     902                 : 
     903               0 :     NS_ConvertUTF16toUTF8 utf8UnEscapeSpec(unEscapeSpec);
     904                 : 
     905                 :     // Adding trailing slash helps to recognize whether the URL points to a file
     906                 :     // or a directory (bug #214405).
     907               0 :     if ((type == nsIDirIndex::TYPE_DIRECTORY) &&
     908               0 :         (utf8UnEscapeSpec.Last() != '/')) {
     909               0 :         utf8UnEscapeSpec.Append('/');
     910                 :     }
     911                 : 
     912                 :     // now minimally re-escape the location...
     913                 :     PRUint32 escFlags;
     914                 :     // for some protocols, we expect the location to be absolute.
     915                 :     // if so, and if the location indeed appears to be a valid URI, then go
     916                 :     // ahead and treat it like one.
     917               0 :     if (mExpectAbsLoc &&
     918               0 :         NS_SUCCEEDED(net_ExtractURLScheme(utf8UnEscapeSpec, nsnull, nsnull, nsnull))) {
     919                 :         // escape as absolute 
     920               0 :         escFlags = esc_Forced | esc_OnlyASCII | esc_AlwaysCopy | esc_Minimal;
     921                 :     }
     922                 :     else {
     923                 :         // escape as relative
     924                 :         // esc_Directory is needed because directories have a trailing slash.
     925                 :         // Without it, the trailing '/' will be escaped, and links from within
     926                 :         // that directory will be incorrect
     927               0 :         escFlags = esc_Forced | esc_OnlyASCII | esc_AlwaysCopy | esc_FileBaseName | esc_Colon | esc_Directory;
     928                 :     }
     929               0 :     NS_EscapeURL(utf8UnEscapeSpec.get(), utf8UnEscapeSpec.Length(), escFlags, escapeBuf);
     930                 :     // esc_Directory does not escape the semicolons, so if a filename
     931                 :     // contains semicolons we need to manually escape them.
     932                 :     // This replacement should be removed in bug #473280
     933               0 :     escapeBuf.ReplaceSubstring(";", "%3b");
     934               0 :     NS_ConvertUTF8toUTF16 utf16URI(escapeBuf);
     935               0 :     nsString htmlEscapedURL;
     936               0 :     htmlEscapedURL.Adopt(nsEscapeHTML2(utf16URI.get(), utf16URI.Length()));
     937               0 :     pushBuffer.Append(htmlEscapedURL);
     938                 : 
     939               0 :     pushBuffer.AppendLiteral("\">");
     940                 : 
     941               0 :     if (type == nsIDirIndex::TYPE_FILE || type == nsIDirIndex::TYPE_UNKNOWN) {
     942               0 :         pushBuffer.AppendLiteral("<img src=\"moz-icon://");
     943               0 :         PRInt32 lastDot = escapeBuf.RFindChar('.');
     944               0 :         if (lastDot != kNotFound) {
     945               0 :             escapeBuf.Cut(0, lastDot);
     946               0 :             NS_ConvertUTF8toUTF16 utf16EscapeBuf(escapeBuf);
     947               0 :             nsString htmlFileExt;
     948               0 :             htmlFileExt.Adopt(nsEscapeHTML2(utf16EscapeBuf.get(), utf16EscapeBuf.Length()));
     949               0 :             pushBuffer.Append(htmlFileExt);
     950                 :         } else {
     951               0 :             pushBuffer.AppendLiteral("unknown");
     952                 :         }
     953               0 :         pushBuffer.AppendLiteral("?size=16\" alt=\"");
     954                 : 
     955               0 :         nsXPIDLString altText;
     956               0 :         rv = mBundle->GetStringFromName(NS_LITERAL_STRING("DirFileLabel").get(),
     957               0 :                                         getter_Copies(altText));
     958               0 :         if (NS_FAILED(rv)) return rv;
     959               0 :         AppendNonAsciiToNCR(altText, pushBuffer);
     960               0 :         pushBuffer.AppendLiteral("\">");
     961                 :     }
     962                 : 
     963               0 :     pushBuffer.Append(escapedShort);
     964               0 :     pushBuffer.AppendLiteral("</a></td>\n <td");
     965                 : 
     966               0 :     if (type == nsIDirIndex::TYPE_DIRECTORY || type == nsIDirIndex::TYPE_SYMLINK) {
     967               0 :         pushBuffer.AppendLiteral(">");
     968                 :     } else {
     969                 :         PRInt64 size;
     970               0 :         aIndex->GetSize(&size);
     971                 : 
     972               0 :         if (PRUint64(size) != LL_MAXUINT) {
     973               0 :             pushBuffer.AppendLiteral(" sortable-data=\"");
     974               0 :             pushBuffer.AppendInt(size);
     975               0 :             pushBuffer.AppendLiteral("\">");
     976               0 :             nsAutoString  sizeString;
     977               0 :             FormatSizeString(size, sizeString);
     978               0 :             pushBuffer.Append(sizeString);
     979                 :         } else {
     980               0 :             pushBuffer.AppendLiteral(">");
     981                 :         }
     982                 :     }
     983               0 :     pushBuffer.AppendLiteral("</td>\n <td");
     984                 : 
     985                 :     PRTime t;
     986               0 :     aIndex->GetLastModified(&t);
     987                 : 
     988               0 :     if (t == -1) {
     989               0 :         pushBuffer.AppendLiteral("></td>\n <td>");
     990                 :     } else {
     991               0 :         pushBuffer.AppendLiteral(" sortable-data=\"");
     992               0 :         pushBuffer.AppendInt(t);
     993               0 :         pushBuffer.AppendLiteral("\">");
     994               0 :         nsAutoString formatted;
     995               0 :         mDateTime->FormatPRTime(nsnull,
     996                 :                                 kDateFormatShort,
     997                 :                                 kTimeFormatNone,
     998                 :                                 t,
     999               0 :                                 formatted);
    1000               0 :         AppendNonAsciiToNCR(formatted, pushBuffer);
    1001               0 :         pushBuffer.AppendLiteral("</td>\n <td>");
    1002               0 :         mDateTime->FormatPRTime(nsnull,
    1003                 :                                 kDateFormatNone,
    1004                 :                                 kTimeFormatSeconds,
    1005                 :                                 t,
    1006               0 :                                 formatted);
    1007                 :         // use NCR to show date in any doc charset
    1008               0 :         AppendNonAsciiToNCR(formatted, pushBuffer);
    1009                 :     }
    1010                 : 
    1011               0 :     pushBuffer.AppendLiteral("</td>\n</tr>");
    1012                 : 
    1013               0 :     return FormatInputStream(aRequest, aCtxt, pushBuffer);
    1014                 : }
    1015                 : 
    1016                 : NS_IMETHODIMP
    1017               0 : nsIndexedToHTML::OnInformationAvailable(nsIRequest *aRequest,
    1018                 :                                         nsISupports *aCtxt,
    1019                 :                                         const nsAString& aInfo) {
    1020               0 :     nsAutoString pushBuffer;
    1021               0 :     PRUnichar* escaped = nsEscapeHTML2(PromiseFlatString(aInfo).get());
    1022               0 :     if (!escaped)
    1023               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1024               0 :     pushBuffer.AppendLiteral("<tr>\n <td>");
    1025               0 :     pushBuffer.Append(escaped);
    1026               0 :     nsMemory::Free(escaped);
    1027               0 :     pushBuffer.AppendLiteral("</td>\n <td></td>\n <td></td>\n <td></td>\n</tr>\n");
    1028                 :     
    1029               0 :     return FormatInputStream(aRequest, aCtxt, pushBuffer);
    1030                 : }
    1031                 : 
    1032               0 : void nsIndexedToHTML::FormatSizeString(PRInt64 inSize, nsString& outSizeString)
    1033                 : {
    1034               0 :     outSizeString.Truncate();
    1035               0 :     if (inSize > PRInt64(0)) {
    1036                 :         // round up to the nearest Kilobyte
    1037               0 :         PRInt64  upperSize = (inSize + PRInt64(1023)) / PRInt64(1024);
    1038               0 :         outSizeString.AppendInt(upperSize);
    1039               0 :         outSizeString.AppendLiteral(" KB");
    1040                 :     }
    1041               0 : }
    1042                 : 
    1043               0 : nsIndexedToHTML::nsIndexedToHTML() {
    1044               0 : }
    1045                 : 
    1046               0 : nsIndexedToHTML::~nsIndexedToHTML() {
    1047               0 : }

Generated by: LCOV version 1.7