LCOV - code coverage report
Current view: top level - netwerk/streamconv/converters - nsDirIndexParser.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 204 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 18 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : /* This parsing code originally lived in xpfe/components/directory/ - bbaetz */
       7             : 
       8             : #include "nsDirIndexParser.h"
       9             : 
      10             : #include "mozilla/ArrayUtils.h"
      11             : #include "mozilla/dom/FallbackEncoding.h"
      12             : #include "mozilla/Encoding.h"
      13             : #include "prprf.h"
      14             : #include "nsCRT.h"
      15             : #include "nsEscape.h"
      16             : #include "nsIDirIndex.h"
      17             : #include "nsIInputStream.h"
      18             : #include "nsITextToSubURI.h"
      19             : #include "nsServiceManagerUtils.h"
      20             : 
      21             : using namespace mozilla;
      22             : 
      23           0 : NS_IMPL_ISUPPORTS(nsDirIndexParser,
      24             :                   nsIRequestObserver,
      25             :                   nsIStreamListener,
      26             :                   nsIDirIndexParser)
      27             : 
      28           0 : nsDirIndexParser::nsDirIndexParser() {
      29           0 : }
      30             : 
      31             : nsresult
      32           0 : nsDirIndexParser::Init() {
      33           0 :   mLineStart = 0;
      34           0 :   mHasDescription = false;
      35           0 :   mFormat[0] = -1;
      36           0 :   auto encoding = mozilla::dom::FallbackEncoding::FromLocale();
      37           0 :   encoding->Name(mEncoding);
      38             : 
      39             :   nsresult rv;
      40             :   // XXX not threadsafe
      41           0 :   if (gRefCntParser++ == 0)
      42           0 :     rv = CallGetService(NS_ITEXTTOSUBURI_CONTRACTID, &gTextToSubURI);
      43             :   else
      44           0 :     rv = NS_OK;
      45             : 
      46           0 :   return rv;
      47             : }
      48             : 
      49           0 : nsDirIndexParser::~nsDirIndexParser() {
      50             :   // XXX not threadsafe
      51           0 :   if (--gRefCntParser == 0) {
      52           0 :     NS_IF_RELEASE(gTextToSubURI);
      53             :   }
      54           0 : }
      55             : 
      56             : NS_IMETHODIMP
      57           0 : nsDirIndexParser::SetListener(nsIDirIndexListener* aListener) {
      58           0 :   mListener = aListener;
      59           0 :   return NS_OK;
      60             : }
      61             : 
      62             : NS_IMETHODIMP
      63           0 : nsDirIndexParser::GetListener(nsIDirIndexListener** aListener) {
      64           0 :   NS_IF_ADDREF(*aListener = mListener.get());
      65           0 :   return NS_OK;
      66             : }
      67             : 
      68             : NS_IMETHODIMP
      69           0 : nsDirIndexParser::GetComment(char** aComment) {
      70           0 :   *aComment = ToNewCString(mComment);
      71             : 
      72           0 :   if (!*aComment)
      73           0 :     return NS_ERROR_OUT_OF_MEMORY;
      74             : 
      75           0 :   return NS_OK;
      76             : }
      77             : 
      78             : NS_IMETHODIMP
      79           0 : nsDirIndexParser::SetEncoding(const char* aEncoding) {
      80           0 :   mEncoding.Assign(aEncoding);
      81           0 :   return NS_OK;
      82             : }
      83             : 
      84             : NS_IMETHODIMP
      85           0 : nsDirIndexParser::GetEncoding(char** aEncoding) {
      86           0 :   *aEncoding = ToNewCString(mEncoding);
      87             : 
      88           0 :   if (!*aEncoding)
      89           0 :     return NS_ERROR_OUT_OF_MEMORY;
      90             : 
      91           0 :   return NS_OK;
      92             : }
      93             : 
      94             : NS_IMETHODIMP
      95           0 : nsDirIndexParser::OnStartRequest(nsIRequest* aRequest, nsISupports* aCtxt) {
      96           0 :   return NS_OK;
      97             : }
      98             : 
      99             : NS_IMETHODIMP
     100           0 : nsDirIndexParser::OnStopRequest(nsIRequest *aRequest, nsISupports *aCtxt,
     101             :                                 nsresult aStatusCode) {
     102             :   // Finish up
     103           0 :   if (mBuf.Length() > (uint32_t) mLineStart) {
     104           0 :     ProcessData(aRequest, aCtxt);
     105             :   }
     106             : 
     107           0 :   return NS_OK;
     108             : }
     109             : 
     110             : nsDirIndexParser::Field
     111             : nsDirIndexParser::gFieldTable[] = {
     112             :   { "Filename", FIELD_FILENAME },
     113             :   { "Description", FIELD_DESCRIPTION },
     114             :   { "Content-Length", FIELD_CONTENTLENGTH },
     115             :   { "Last-Modified", FIELD_LASTMODIFIED },
     116             :   { "Content-Type", FIELD_CONTENTTYPE },
     117             :   { "File-Type", FIELD_FILETYPE },
     118             :   { nullptr, FIELD_UNKNOWN }
     119             : };
     120             : 
     121             : nsrefcnt nsDirIndexParser::gRefCntParser = 0;
     122             : nsITextToSubURI *nsDirIndexParser::gTextToSubURI;
     123             : 
     124             : nsresult
     125           0 : nsDirIndexParser::ParseFormat(const char* aFormatStr)
     126             : {
     127             :   // Parse a "200" format line, and remember the fields and their
     128             :   // ordering in mFormat. Multiple 200 lines stomp on each other.
     129           0 :   unsigned int formatNum = 0;
     130           0 :   mFormat[0] = -1;
     131             : 
     132           0 :   do {
     133           0 :     while (*aFormatStr && nsCRT::IsAsciiSpace(char16_t(*aFormatStr)))
     134           0 :       ++aFormatStr;
     135             : 
     136           0 :     if (! *aFormatStr)
     137           0 :       break;
     138             : 
     139           0 :     nsAutoCString name;
     140           0 :     int32_t     len = 0;
     141           0 :     while (aFormatStr[len] && !nsCRT::IsAsciiSpace(char16_t(aFormatStr[len])))
     142           0 :       ++len;
     143           0 :     name.SetCapacity(len + 1);
     144           0 :     name.Append(aFormatStr, len);
     145           0 :     aFormatStr += len;
     146             : 
     147             :     // Okay, we're gonna monkey with the nsStr. Bold!
     148           0 :     name.SetLength(nsUnescapeCount(name.BeginWriting()));
     149             : 
     150             :     // All tokens are case-insensitive - http://www.mozilla.org/projects/netlib/dirindexformat.html
     151           0 :     if (name.LowerCaseEqualsLiteral("description"))
     152           0 :       mHasDescription = true;
     153             : 
     154           0 :     for (Field* i = gFieldTable; i->mName; ++i) {
     155           0 :       if (name.EqualsIgnoreCase(i->mName)) {
     156           0 :         mFormat[formatNum] = i->mType;
     157           0 :         mFormat[++formatNum] = -1;
     158           0 :         break;
     159             :       }
     160             :     }
     161             : 
     162           0 :   } while (*aFormatStr && (formatNum < (ArrayLength(mFormat)-1)));
     163             : 
     164           0 :   return NS_OK;
     165             : }
     166             : 
     167             : nsresult
     168           0 : nsDirIndexParser::ParseData(nsIDirIndex *aIdx, char* aDataStr, int32_t aLineLen)
     169             : {
     170             :   // Parse a "201" data line, using the field ordering specified in
     171             :   // mFormat.
     172             : 
     173           0 :   if(mFormat[0] == -1) {
     174             :     // Ignore if we haven't seen a format yet.
     175           0 :     return NS_OK;
     176             :   }
     177             : 
     178           0 :   nsresult rv = NS_OK;
     179           0 :   nsAutoCString filename;
     180           0 :   int32_t lineLen = aLineLen;
     181             : 
     182           0 :   for (int32_t i = 0; mFormat[i] != -1; ++i) {
     183             :     // If we've exhausted the data before we run out of fields, just bail.
     184           0 :     if (!*aDataStr || (lineLen < 1)) {
     185           0 :       return NS_OK;
     186             :     }
     187             : 
     188           0 :     while ((lineLen > 0) && nsCRT::IsAsciiSpace(*aDataStr)) {
     189           0 :       ++aDataStr;
     190           0 :       --lineLen;
     191             :     }
     192             : 
     193           0 :     if (lineLen < 1) {
     194             :       // invalid format, bail
     195           0 :       return NS_OK;
     196             :     }
     197             : 
     198           0 :     char    *value = aDataStr;
     199           0 :     if (*aDataStr == '"' || *aDataStr == '\'') {
     200             :       // it's a quoted string. snarf everything up to the next quote character
     201           0 :       const char quotechar = *(aDataStr++);
     202           0 :       lineLen--;
     203           0 :       ++value;
     204           0 :       while ((lineLen > 0) && *aDataStr != quotechar) {
     205           0 :         ++aDataStr;
     206           0 :         --lineLen;
     207             :       }
     208           0 :       if (lineLen > 0) {
     209           0 :         *aDataStr++ = '\0';
     210           0 :         --lineLen;
     211             :       }
     212             : 
     213           0 :       if (!lineLen) {
     214             :         // invalid format, bail
     215           0 :         return NS_OK;
     216           0 :       }
     217             :     } else {
     218             :       // it's unquoted. snarf until we see whitespace.
     219           0 :       value = aDataStr;
     220           0 :       while ((lineLen > 0) && (!nsCRT::IsAsciiSpace(*aDataStr))) {
     221           0 :         ++aDataStr;
     222           0 :         --lineLen;
     223             :       }
     224           0 :       if (lineLen > 0) {
     225           0 :         *aDataStr++ = '\0';
     226           0 :         --lineLen;
     227             :       }
     228             :       // even if we ran out of line length here, there's still a trailing zero
     229             :       // byte afterwards
     230             :     }
     231             : 
     232           0 :     fieldType t = fieldType(mFormat[i]);
     233           0 :     switch (t) {
     234             :     case FIELD_FILENAME: {
     235             :       // don't unescape at this point, so that UnEscapeAndConvert() can
     236           0 :       filename = value;
     237             : 
     238           0 :       bool    success = false;
     239             : 
     240           0 :       nsAutoString entryuri;
     241             : 
     242           0 :       if (gTextToSubURI) {
     243           0 :         nsAutoString result;
     244           0 :         if (NS_SUCCEEDED(rv = gTextToSubURI->UnEscapeAndConvert(
     245             :                            mEncoding, filename, result))) {
     246           0 :           if (!result.IsEmpty()) {
     247           0 :             aIdx->SetLocation(filename.get());
     248           0 :             if (!mHasDescription)
     249           0 :               aIdx->SetDescription(result.get());
     250           0 :             success = true;
     251             :           }
     252             :         } else {
     253           0 :           NS_WARNING("UnEscapeAndConvert error");
     254             :         }
     255             :       }
     256             : 
     257           0 :       if (!success) {
     258             :         // if unsuccessfully at charset conversion, then
     259             :         // just fallback to unescape'ing in-place
     260             :         // XXX - this shouldn't be using UTF8, should it?
     261             :         // when can we fail to get the service, anyway? - bbaetz
     262           0 :         aIdx->SetLocation(filename.get());
     263           0 :         if (!mHasDescription) {
     264           0 :           aIdx->SetDescription(NS_ConvertUTF8toUTF16(value).get());
     265             :         }
     266             :       }
     267             :     }
     268           0 :       break;
     269             :     case FIELD_DESCRIPTION:
     270           0 :       nsUnescape(value);
     271           0 :       aIdx->SetDescription(NS_ConvertUTF8toUTF16(value).get());
     272           0 :       break;
     273             :     case FIELD_CONTENTLENGTH:
     274             :       {
     275             :         int64_t len;
     276           0 :         int32_t status = PR_sscanf(value, "%lld", &len);
     277           0 :         if (status == 1)
     278           0 :           aIdx->SetSize(len);
     279             :         else
     280           0 :           aIdx->SetSize(UINT64_MAX); // UINT64_MAX means unknown
     281             :       }
     282           0 :       break;
     283             :     case FIELD_LASTMODIFIED:
     284             :       {
     285             :         PRTime tm;
     286           0 :         nsUnescape(value);
     287           0 :         if (PR_ParseTimeString(value, false, &tm) == PR_SUCCESS) {
     288           0 :           aIdx->SetLastModified(tm);
     289             :         }
     290             :       }
     291           0 :       break;
     292             :     case FIELD_CONTENTTYPE:
     293           0 :       aIdx->SetContentType(value);
     294           0 :       break;
     295             :     case FIELD_FILETYPE:
     296             :       // unescape in-place
     297           0 :       nsUnescape(value);
     298           0 :       if (!nsCRT::strcasecmp(value, "directory")) {
     299           0 :         aIdx->SetType(nsIDirIndex::TYPE_DIRECTORY);
     300           0 :       } else if (!nsCRT::strcasecmp(value, "file")) {
     301           0 :         aIdx->SetType(nsIDirIndex::TYPE_FILE);
     302           0 :       } else if (!nsCRT::strcasecmp(value, "symbolic-link")) {
     303           0 :         aIdx->SetType(nsIDirIndex::TYPE_SYMLINK);
     304             :       } else {
     305           0 :         aIdx->SetType(nsIDirIndex::TYPE_UNKNOWN);
     306             :       }
     307           0 :       break;
     308             :     case FIELD_UNKNOWN:
     309             :       // ignore
     310           0 :       break;
     311             :     }
     312             :   }
     313             : 
     314           0 :   return NS_OK;
     315             : }
     316             : 
     317             : NS_IMETHODIMP
     318           0 : nsDirIndexParser::OnDataAvailable(nsIRequest *aRequest, nsISupports *aCtxt,
     319             :                                   nsIInputStream *aStream,
     320             :                                   uint64_t aSourceOffset,
     321             :                                   uint32_t aCount) {
     322           0 :   if (aCount < 1)
     323           0 :     return NS_OK;
     324             : 
     325           0 :   int32_t len = mBuf.Length();
     326             : 
     327             :   // Ensure that our mBuf has capacity to hold the data we're about to
     328             :   // read.
     329           0 :   if (!mBuf.SetLength(len + aCount, fallible))
     330           0 :     return NS_ERROR_OUT_OF_MEMORY;
     331             : 
     332             :   // Now read the data into our buffer.
     333             :   nsresult rv;
     334             :   uint32_t count;
     335           0 :   rv = aStream->Read(mBuf.BeginWriting() + len, aCount, &count);
     336           0 :   if (NS_FAILED(rv)) return rv;
     337             : 
     338             :   // Set the string's length according to the amount of data we've read.
     339             :   // Note: we know this to work on nsCString. This isn't guaranteed to
     340             :   //       work on other strings.
     341           0 :   mBuf.SetLength(len + count);
     342             : 
     343           0 :   return ProcessData(aRequest, aCtxt);
     344             : }
     345             : 
     346             : nsresult
     347           0 : nsDirIndexParser::ProcessData(nsIRequest *aRequest, nsISupports *aCtxt) {
     348           0 :   if (!mListener)
     349           0 :     return NS_ERROR_FAILURE;
     350             : 
     351           0 :   int32_t     numItems = 0;
     352             : 
     353             :   while(true) {
     354           0 :     ++numItems;
     355             : 
     356           0 :     int32_t             eol = mBuf.FindCharInSet("\n\r", mLineStart);
     357           0 :     if (eol < 0)        break;
     358           0 :     mBuf.SetCharAt(char16_t('\0'), eol);
     359             : 
     360           0 :     const char  *line = mBuf.get() + mLineStart;
     361             : 
     362           0 :     int32_t lineLen = eol - mLineStart;
     363           0 :     mLineStart = eol + 1;
     364             : 
     365           0 :     if (lineLen >= 4) {
     366             :       nsresult  rv;
     367           0 :       const char        *buf = line;
     368             : 
     369           0 :       if (buf[0] == '1') {
     370           0 :         if (buf[1] == '0') {
     371           0 :           if (buf[2] == '0' && buf[3] == ':') {
     372             :             // 100. Human-readable comment line. Ignore
     373           0 :           } else if (buf[2] == '1' && buf[3] == ':') {
     374             :             // 101. Human-readable information line.
     375           0 :             mComment.Append(buf + 4);
     376             : 
     377           0 :             char    *value = ((char *)buf) + 4;
     378           0 :             nsUnescape(value);
     379           0 :             mListener->OnInformationAvailable(aRequest, aCtxt, NS_ConvertUTF8toUTF16(value));
     380             : 
     381           0 :           } else if (buf[2] == '2' && buf[3] == ':') {
     382             :             // 102. Human-readable information line, HTML.
     383           0 :             mComment.Append(buf + 4);
     384             :           }
     385             :         }
     386           0 :       } else if (buf[0] == '2') {
     387           0 :         if (buf[1] == '0') {
     388           0 :           if (buf[2] == '0' && buf[3] == ':') {
     389             :             // 200. Define field names
     390           0 :             rv = ParseFormat(buf + 4);
     391           0 :             if (NS_FAILED(rv)) {
     392           0 :               return rv;
     393             :             }
     394           0 :           } else if (buf[2] == '1' && buf[3] == ':') {
     395             :             // 201. Field data
     396           0 :             nsCOMPtr<nsIDirIndex> idx = do_CreateInstance("@mozilla.org/dirIndex;1",&rv);
     397           0 :             if (NS_FAILED(rv))
     398           0 :               return rv;
     399             : 
     400           0 :             rv = ParseData(idx, ((char *)buf) + 4, lineLen - 4);
     401           0 :             if (NS_FAILED(rv)) {
     402           0 :               return rv;
     403             :             }
     404             : 
     405           0 :             mListener->OnIndexAvailable(aRequest, aCtxt, idx);
     406             :           }
     407             :         }
     408           0 :       } else if (buf[0] == '3') {
     409           0 :         if (buf[1] == '0') {
     410           0 :           if (buf[2] == '0' && buf[3] == ':') {
     411             :             // 300. Self-referring URL
     412           0 :           } else if (buf[2] == '1' && buf[3] == ':') {
     413             :             // 301. OUR EXTENSION - encoding
     414           0 :             int i = 4;
     415           0 :             while (buf[i] && nsCRT::IsAsciiSpace(buf[i]))
     416           0 :               ++i;
     417             : 
     418           0 :             if (buf[i])
     419           0 :               SetEncoding(buf+i);
     420             :           }
     421             :         }
     422             :       }
     423             :     }
     424           0 :   }
     425             : 
     426           0 :   return NS_OK;
     427             : }

Generated by: LCOV version 1.13