LCOV - code coverage report
Current view: top level - xpcom/base - nsINIParser.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 68 114 59.6 %
Date: 2017-07-14 16:53:18 Functions: 7 12 58.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : // Moz headers (alphabetical)
       8             : #include "nsCRTGlue.h"
       9             : #include "nsError.h"
      10             : #include "nsIFile.h"
      11             : #include "nsINIParser.h"
      12             : #include "mozilla/FileUtils.h" // AutoFILE
      13             : 
      14             : // System headers (alphabetical)
      15             : #include <stdio.h>
      16             : #include <stdlib.h>
      17             : #ifdef XP_WIN
      18             : #include <windows.h>
      19             : #endif
      20             : 
      21             : #if defined(XP_WIN)
      22             : #define READ_BINARYMODE L"rb"
      23             : #else
      24             : #define READ_BINARYMODE "r"
      25             : #endif
      26             : 
      27             : using namespace mozilla;
      28             : 
      29             : #ifdef XP_WIN
      30             : inline FILE*
      31             : TS_tfopen(const char* aPath, const wchar_t* aMode)
      32             : {
      33             :   wchar_t wPath[MAX_PATH];
      34             :   MultiByteToWideChar(CP_UTF8, 0, aPath, -1, wPath, MAX_PATH);
      35             :   return _wfopen(wPath, aMode);
      36             : }
      37             : #else
      38             : inline FILE*
      39           0 : TS_tfopen(const char* aPath, const char* aMode)
      40             : {
      41           0 :   return fopen(aPath, aMode);
      42             : }
      43             : #endif
      44             : 
      45             : // Stack based FILE wrapper to ensure that fclose is called, copied from
      46             : // toolkit/mozapps/update/updater/readstrings.cpp
      47             : 
      48             : class AutoFILE
      49             : {
      50             : public:
      51           2 :   explicit AutoFILE(FILE* aFp = nullptr) : fp_(aFp) {}
      52           2 :   ~AutoFILE()
      53           2 :   {
      54           2 :     if (fp_) {
      55           2 :       fclose(fp_);
      56             :     }
      57           2 :   }
      58           4 :   operator FILE*() { return fp_; }
      59             :   FILE** operator&() { return &fp_; }
      60           2 :   void operator=(FILE* aFp) { fp_ = aFp; }
      61             : private:
      62             :   FILE* fp_;
      63             : };
      64             : 
      65             : nsresult
      66           2 : nsINIParser::Init(nsIFile* aFile)
      67             : {
      68             :   /* open the file. Don't use OpenANSIFileDesc, because you mustn't
      69             :      pass FILE* across shared library boundaries, which may be using
      70             :      different CRTs */
      71             : 
      72           4 :   AutoFILE fd;
      73             : 
      74             : #ifdef XP_WIN
      75             :   nsAutoString path;
      76             :   nsresult rv = aFile->GetPath(path);
      77             :   if (NS_WARN_IF(NS_FAILED(rv))) {
      78             :     return rv;
      79             :   }
      80             : 
      81             :   fd = _wfopen(path.get(), READ_BINARYMODE);
      82             : #else
      83           4 :   nsAutoCString path;
      84           2 :   aFile->GetNativePath(path);
      85             : 
      86           2 :   fd = fopen(path.get(), READ_BINARYMODE);
      87             : #endif
      88             : 
      89           2 :   if (!fd) {
      90           0 :     return NS_ERROR_FAILURE;
      91             :   }
      92             : 
      93           2 :   return InitFromFILE(fd);
      94             : }
      95             : 
      96             : nsresult
      97           0 : nsINIParser::Init(const char* aPath)
      98             : {
      99             :   /* open the file */
     100           0 :   AutoFILE fd(TS_tfopen(aPath, READ_BINARYMODE));
     101           0 :   if (!fd) {
     102           0 :     return NS_ERROR_FAILURE;
     103             :   }
     104             : 
     105           0 :   return InitFromFILE(fd);
     106             : }
     107             : 
     108             : static const char kNL[] = "\r\n";
     109             : static const char kEquals[] = "=";
     110             : static const char kWhitespace[] = " \t";
     111             : static const char kRBracket[] = "]";
     112             : 
     113             : nsresult
     114           2 : nsINIParser::InitFromFILE(FILE* aFd)
     115             : {
     116             :   /* get file size */
     117           2 :   if (fseek(aFd, 0, SEEK_END) != 0) {
     118           0 :     return NS_ERROR_FAILURE;
     119             :   }
     120             : 
     121           2 :   long flen = ftell(aFd);
     122             :   /* zero-sized file, or an error */
     123           2 :   if (flen <= 0) {
     124           0 :     return NS_ERROR_FAILURE;
     125             :   }
     126             : 
     127             :   /* malloc an internal buf the size of the file */
     128           2 :   mFileContents = MakeUnique<char[]>(flen + 2);
     129           2 :   if (!mFileContents) {
     130           0 :     return NS_ERROR_OUT_OF_MEMORY;
     131             :   }
     132             : 
     133             :   /* read the file in one swoop */
     134           2 :   if (fseek(aFd, 0, SEEK_SET) != 0) {
     135           0 :     return NS_BASE_STREAM_OSERROR;
     136             :   }
     137             : 
     138           2 :   int rd = fread(mFileContents.get(), sizeof(char), flen, aFd);
     139           2 :   if (rd != flen) {
     140           0 :     return NS_BASE_STREAM_OSERROR;
     141             :   }
     142             : 
     143             :   // We write a UTF16 null so that the file is easier to convert to UTF8
     144           2 :   mFileContents[flen] = mFileContents[flen + 1] = '\0';
     145             : 
     146           2 :   char* buffer = &mFileContents[0];
     147             : 
     148           4 :   if (flen >= 3 &&
     149           2 :       mFileContents[0] == '\xEF' &&
     150           2 :       mFileContents[1] == '\xBB' &&
     151           0 :       mFileContents[2] == '\xBF') {
     152             :     // Someone set us up the Utf-8 BOM
     153             :     // This case is easy, since we assume that BOM-less
     154             :     // files are Utf-8 anyway.  Just skip the BOM and process as usual.
     155           0 :     buffer = &mFileContents[3];
     156             :   }
     157             : 
     158             : #ifdef XP_WIN
     159             :   if (flen >= 2 &&
     160             :       mFileContents[0] == '\xFF' &&
     161             :       mFileContents[1] == '\xFE') {
     162             :     // Someone set us up the Utf-16LE BOM
     163             :     buffer = &mFileContents[2];
     164             :     // Get the size required for our Utf8 buffer
     165             :     flen = WideCharToMultiByte(CP_UTF8,
     166             :                                0,
     167             :                                reinterpret_cast<LPWSTR>(buffer),
     168             :                                -1,
     169             :                                nullptr,
     170             :                                0,
     171             :                                nullptr,
     172             :                                nullptr);
     173             :     if (flen == 0) {
     174             :       return NS_ERROR_FAILURE;
     175             :     }
     176             : 
     177             :     UniquePtr<char[]> utf8Buffer(new char[flen]);
     178             :     if (WideCharToMultiByte(CP_UTF8, 0, reinterpret_cast<LPWSTR>(buffer), -1,
     179             :                             utf8Buffer.get(), flen, nullptr, nullptr) == 0) {
     180             :       return NS_ERROR_FAILURE;
     181             :     }
     182             :     mFileContents = Move(utf8Buffer);
     183             :     buffer = mFileContents.get();
     184             :   }
     185             : #endif
     186             : 
     187           2 :   char* currSection = nullptr;
     188             : 
     189             :   // outer loop tokenizes into lines
     190          13 :   while (char* token = NS_strtok(kNL, &buffer)) {
     191          11 :     if (token[0] == '#' || token[0] == ';') { // it's a comment
     192           6 :       continue;
     193             :     }
     194             : 
     195          11 :     token = (char*)NS_strspnp(kWhitespace, token);
     196          11 :     if (!*token) { // empty line
     197           0 :       continue;
     198             :     }
     199             : 
     200          11 :     if (token[0] == '[') { // section header!
     201           3 :       ++token;
     202           3 :       currSection = token;
     203             : 
     204           3 :       char* rb = NS_strtok(kRBracket, &token);
     205           3 :       if (!rb || NS_strtok(kWhitespace, &token)) {
     206             :         // there's either an unclosed [Section or a [Section]Moretext!
     207             :         // we could frankly decide that this INI file is malformed right
     208             :         // here and stop, but we won't... keep going, looking for
     209             :         // a well-formed [section] to continue working with
     210           0 :         currSection = nullptr;
     211             :       }
     212             : 
     213           3 :       continue;
     214             :     }
     215             : 
     216           8 :     if (!currSection) {
     217             :       // If we haven't found a section header (or we found a malformed
     218             :       // section header), don't bother parsing this line.
     219           0 :       continue;
     220             :     }
     221             : 
     222           8 :     char* key = token;
     223           8 :     char* e = NS_strtok(kEquals, &token);
     224           8 :     if (!e || !token) {
     225           0 :       continue;
     226             :     }
     227             : 
     228             :     INIValue* v;
     229           8 :     if (!mSections.Get(currSection, &v)) {
     230           3 :       v = new INIValue(key, token);
     231           3 :       if (!v) {
     232           0 :         return NS_ERROR_OUT_OF_MEMORY;
     233             :       }
     234             : 
     235           3 :       mSections.Put(currSection, v);
     236           3 :       continue;
     237             :     }
     238             : 
     239             :     // Check whether this key has already been specified; overwrite
     240             :     // if so, or append if not.
     241          13 :     while (v) {
     242           9 :       if (!strcmp(key, v->key)) {
     243           0 :         v->value = token;
     244           0 :         break;
     245             :       }
     246           9 :       if (!v->next) {
     247           5 :         v->next = MakeUnique<INIValue>(key, token);
     248           5 :         if (!v->next) {
     249           0 :           return NS_ERROR_OUT_OF_MEMORY;
     250             :         }
     251           5 :         break;
     252             :       }
     253           4 :       v = v->next.get();
     254             :     }
     255           5 :     NS_ASSERTION(v, "v should never be null coming out of this loop");
     256          11 :   }
     257             : 
     258           2 :   return NS_OK;
     259             : }
     260             : 
     261             : nsresult
     262          11 : nsINIParser::GetString(const char* aSection, const char* aKey,
     263             :                        nsACString& aResult)
     264             : {
     265             :   INIValue* val;
     266          11 :   mSections.Get(aSection, &val);
     267             : 
     268          43 :   while (val) {
     269          24 :     if (strcmp(val->key, aKey) == 0) {
     270           8 :       aResult.Assign(val->value);
     271           8 :       return NS_OK;
     272             :     }
     273             : 
     274          16 :     val = val->next.get();
     275             :   }
     276             : 
     277           3 :   return NS_ERROR_FAILURE;
     278             : }
     279             : 
     280             : nsresult
     281           0 : nsINIParser::GetString(const char* aSection, const char* aKey,
     282             :                        char* aResult, uint32_t aResultLen)
     283             : {
     284             :   INIValue* val;
     285           0 :   mSections.Get(aSection, &val);
     286             : 
     287           0 :   while (val) {
     288           0 :     if (strcmp(val->key, aKey) == 0) {
     289           0 :       strncpy(aResult, val->value, aResultLen);
     290           0 :       aResult[aResultLen - 1] = '\0';
     291           0 :       if (strlen(val->value) >= aResultLen) {
     292           0 :         return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
     293             :       }
     294             : 
     295           0 :       return NS_OK;
     296             :     }
     297             : 
     298           0 :     val = val->next.get();
     299             :   }
     300             : 
     301           0 :   return NS_ERROR_FAILURE;
     302             : }
     303             : 
     304             : nsresult
     305           0 : nsINIParser::GetSections(INISectionCallback aCB, void* aClosure)
     306             : {
     307           0 :   for (auto iter = mSections.Iter(); !iter.Done(); iter.Next()) {
     308           0 :     if (!aCB(iter.Key(), aClosure)) {
     309           0 :       break;
     310             :     }
     311             :   }
     312           0 :   return NS_OK;
     313             : }
     314             : 
     315             : nsresult
     316           0 : nsINIParser::GetStrings(const char* aSection,
     317             :                         INIStringCallback aCB, void* aClosure)
     318             : {
     319             :   INIValue* val;
     320             : 
     321           0 :   for (mSections.Get(aSection, &val);
     322           0 :        val;
     323           0 :        val = val->next.get()) {
     324             : 
     325           0 :     if (!aCB(val->key, val->value, aClosure)) {
     326           0 :       return NS_OK;
     327             :     }
     328             :   }
     329             : 
     330           0 :   return NS_OK;
     331             : }

Generated by: LCOV version 1.13