LCOV - code coverage report
Current view: top level - xpcom/ds - nsPersistentProperties.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 165 249 66.3 %
Date: 2017-07-14 16:53:18 Functions: 22 38 57.9 %
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             : #include "nsArrayEnumerator.h"
       8             : #include "nsID.h"
       9             : #include "nsCOMArray.h"
      10             : #include "nsUnicharInputStream.h"
      11             : #include "nsPrintfCString.h"
      12             : #include "nsAutoPtr.h"
      13             : 
      14             : #include "nsPersistentProperties.h"
      15             : #include "nsIProperties.h"
      16             : 
      17             : #include "mozilla/ArenaAllocatorExtensions.h"
      18             : 
      19             : using mozilla::ArenaStrdup;
      20             : 
      21             : struct PropertyTableEntry : public PLDHashEntryHdr
      22             : {
      23             :   // both of these are arena-allocated
      24             :   const char* mKey;
      25             :   const char16_t* mValue;
      26             : };
      27             : 
      28             : static const struct PLDHashTableOps property_HashTableOps = {
      29             :   PLDHashTable::HashStringKey,
      30             :   PLDHashTable::MatchStringKey,
      31             :   PLDHashTable::MoveEntryStub,
      32             :   PLDHashTable::ClearEntryStub,
      33             :   nullptr,
      34             : };
      35             : 
      36             : //
      37             : // parser stuff
      38             : //
      39             : enum EParserState
      40             : {
      41             :   eParserState_AwaitingKey,
      42             :   eParserState_Key,
      43             :   eParserState_AwaitingValue,
      44             :   eParserState_Value,
      45             :   eParserState_Comment
      46             : };
      47             : 
      48             : enum EParserSpecial
      49             : {
      50             :   eParserSpecial_None,          // not parsing a special character
      51             :   eParserSpecial_Escaped,       // awaiting a special character
      52             :   eParserSpecial_Unicode        // parsing a \Uxxx value
      53             : };
      54             : 
      55          21 : class MOZ_STACK_CLASS nsPropertiesParser
      56             : {
      57             : public:
      58          21 :   explicit nsPropertiesParser(nsIPersistentProperties* aProps)
      59          21 :     : mHaveMultiLine(false)
      60             :     , mState(eParserState_AwaitingKey)
      61          21 :     , mProps(aProps)
      62             :   {
      63          21 :   }
      64             : 
      65        1300 :   void FinishValueState(nsAString& aOldValue)
      66             :   {
      67             :     static const char trimThese[] = " \t";
      68        1300 :     mKey.Trim(trimThese, false, true);
      69             : 
      70             :     // This is really ugly hack but it should be fast
      71             :     char16_t backup_char;
      72        1300 :     uint32_t minLength = mMinLength;
      73        1300 :     if (minLength) {
      74           6 :       backup_char = mValue[minLength - 1];
      75           6 :       mValue.SetCharAt('x', minLength - 1);
      76             :     }
      77        1300 :     mValue.Trim(trimThese, false, true);
      78        1300 :     if (minLength) {
      79           6 :       mValue.SetCharAt(backup_char, minLength - 1);
      80             :     }
      81             : 
      82        1300 :     mProps->SetStringProperty(NS_ConvertUTF16toUTF8(mKey), mValue, aOldValue);
      83        1300 :     mSpecialState = eParserSpecial_None;
      84        1300 :     WaitForKey();
      85        1300 :   }
      86             : 
      87          21 :   EParserState GetState() { return mState; }
      88             : 
      89             :   static nsresult SegmentWriter(nsIUnicharInputStream* aStream,
      90             :                                 void* aClosure,
      91             :                                 const char16_t* aFromSegment,
      92             :                                 uint32_t aToOffset,
      93             :                                 uint32_t aCount,
      94             :                                 uint32_t* aWriteCount);
      95             : 
      96             :   nsresult ParseBuffer(const char16_t* aBuffer, uint32_t aBufferLength);
      97             : 
      98             : private:
      99             :   bool ParseValueCharacter(
     100             :     char16_t aChar,               // character that is just being parsed
     101             :     const char16_t* aCur,         // pointer to character aChar in the buffer
     102             :     const char16_t*& aTokenStart, // string copying is done in blocks as big as
     103             :                                   // possible, aTokenStart points to the beginning
     104             :                                   // of this block
     105             :     nsAString& aOldValue);        // when duplicate property is found, new value
     106             :                                   // is stored into hashtable and the old one is
     107             :                                   // placed in this variable
     108             : 
     109        1952 :   void WaitForKey()
     110             :   {
     111        1952 :     mState = eParserState_AwaitingKey;
     112        1952 :   }
     113             : 
     114        1300 :   void EnterKeyState()
     115             :   {
     116        1300 :     mKey.Truncate();
     117        1300 :     mState = eParserState_Key;
     118        1300 :   }
     119             : 
     120        1300 :   void WaitForValue()
     121             :   {
     122        1300 :     mState = eParserState_AwaitingValue;
     123        1300 :   }
     124             : 
     125        1300 :   void EnterValueState()
     126             :   {
     127        1300 :     mValue.Truncate();
     128        1300 :     mMinLength = 0;
     129        1300 :     mState = eParserState_Value;
     130        1300 :     mSpecialState = eParserSpecial_None;
     131        1300 :   }
     132             : 
     133         652 :   void EnterCommentState()
     134             :   {
     135         652 :     mState = eParserState_Comment;
     136         652 :   }
     137             : 
     138             :   nsAutoString mKey;
     139             :   nsAutoString mValue;
     140             : 
     141             :   uint32_t  mUnicodeValuesRead; // should be 4!
     142             :   char16_t mUnicodeValue;      // currently parsed unicode value
     143             :   bool      mHaveMultiLine;     // is TRUE when last processed characters form
     144             :                                 // any of following sequences:
     145             :                                 //  - "\\\r"
     146             :                                 //  - "\\\n"
     147             :                                 //  - "\\\r\n"
     148             :                                 //  - any sequence above followed by any
     149             :                                 //    combination of ' ' and '\t'
     150             :   bool      mMultiLineCanSkipN; // TRUE if "\\\r" was detected
     151             :   uint32_t  mMinLength;         // limit right trimming at the end to not trim
     152             :                                 // escaped whitespaces
     153             :   EParserState mState;
     154             :   // if we see a '\' then we enter this special state
     155             :   EParserSpecial mSpecialState;
     156             :   nsCOMPtr<nsIPersistentProperties> mProps;
     157             : };
     158             : 
     159             : inline bool
     160        3075 : IsWhiteSpace(char16_t aChar)
     161             : {
     162        2835 :   return (aChar == ' ') || (aChar == '\t') ||
     163        5910 :          (aChar == '\r') || (aChar == '\n');
     164             : }
     165             : 
     166             : inline bool
     167        1540 : IsEOL(char16_t aChar)
     168             : {
     169        1540 :   return (aChar == '\r') || (aChar == '\n');
     170             : }
     171             : 
     172             : 
     173             : bool
     174       42640 : nsPropertiesParser::ParseValueCharacter(char16_t aChar, const char16_t* aCur,
     175             :                                         const char16_t*& aTokenStart,
     176             :                                         nsAString& aOldValue)
     177             : {
     178       42640 :   switch (mSpecialState) {
     179             :     // the normal state - look for special characters
     180             :     case eParserSpecial_None:
     181       42623 :       switch (aChar) {
     182             :         case '\\':
     183          13 :           if (mHaveMultiLine) {
     184             :             // there is nothing to append to mValue yet
     185           0 :             mHaveMultiLine = false;
     186             :           } else {
     187          13 :             mValue += Substring(aTokenStart, aCur);
     188             :           }
     189             : 
     190          13 :           mSpecialState = eParserSpecial_Escaped;
     191          13 :           break;
     192             : 
     193             :         case '\n':
     194             :           // if we detected multiline and got only "\\\r" ignore next "\n" if any
     195        1296 :           if (mHaveMultiLine && mMultiLineCanSkipN) {
     196             :             // but don't allow another '\n' to be skipped
     197           0 :             mMultiLineCanSkipN = false;
     198             :             // Now there is nothing to append to the mValue since we are skipping
     199             :             // whitespaces at the beginning of the new line of the multiline
     200             :             // property. Set aTokenStart properly to ensure that nothing is appended
     201             :             // if we find regular line-end or the end of the buffer.
     202           0 :             aTokenStart = aCur + 1;
     203           0 :             break;
     204             :           }
     205             :           MOZ_FALLTHROUGH;
     206             : 
     207             :         case '\r':
     208             :           // we're done! We have a key and value
     209        1296 :           mValue += Substring(aTokenStart, aCur);
     210        1296 :           FinishValueState(aOldValue);
     211        1296 :           mHaveMultiLine = false;
     212        1296 :           break;
     213             : 
     214             :         default:
     215             :           // there is nothing to do with normal characters,
     216             :           // but handle multilines correctly
     217       41314 :           if (mHaveMultiLine) {
     218           0 :             if (aChar == ' ' || aChar == '\t') {
     219             :               // don't allow another '\n' to be skipped
     220           0 :               mMultiLineCanSkipN = false;
     221             :               // Now there is nothing to append to the mValue since we are skipping
     222             :               // whitespaces at the beginning of the new line of the multiline
     223             :               // property. Set aTokenStart properly to ensure that nothing is appended
     224             :               // if we find regular line-end or the end of the buffer.
     225           0 :               aTokenStart = aCur + 1;
     226           0 :               break;
     227             :             }
     228           0 :             mHaveMultiLine = false;
     229           0 :             aTokenStart = aCur;
     230             :           }
     231       41314 :           break; // from switch on (aChar)
     232             :       }
     233       42623 :       break; // from switch on (mSpecialState)
     234             : 
     235             :     // saw a \ character, so parse the character after that
     236             :     case eParserSpecial_Escaped:
     237             :       // probably want to start parsing at the next token
     238             :       // other characters, like 'u' might override this
     239          13 :       aTokenStart = aCur + 1;
     240          13 :       mSpecialState = eParserSpecial_None;
     241             : 
     242          13 :       switch (aChar) {
     243             :         // the easy characters - \t, \n, and so forth
     244             :         case 't':
     245           0 :           mValue += char16_t('\t');
     246           0 :           mMinLength = mValue.Length();
     247           0 :           break;
     248             :         case 'n':
     249          12 :           mValue += char16_t('\n');
     250          12 :           mMinLength = mValue.Length();
     251          12 :           break;
     252             :         case 'r':
     253           0 :           mValue += char16_t('\r');
     254           0 :           mMinLength = mValue.Length();
     255           0 :           break;
     256             :         case '\\':
     257           0 :           mValue += char16_t('\\');
     258           0 :           break;
     259             : 
     260             :         // switch to unicode mode!
     261             :         case 'u':
     262             :         case 'U':
     263           1 :           mSpecialState = eParserSpecial_Unicode;
     264           1 :           mUnicodeValuesRead = 0;
     265           1 :           mUnicodeValue = 0;
     266           1 :           break;
     267             : 
     268             :         // a \ immediately followed by a newline means we're going multiline
     269             :         case '\r':
     270             :         case '\n':
     271           0 :           mHaveMultiLine = true;
     272           0 :           mMultiLineCanSkipN = (aChar == '\r');
     273           0 :           mSpecialState = eParserSpecial_None;
     274           0 :           break;
     275             : 
     276             :         default:
     277             :           // don't recognize the character, so just append it
     278           0 :           mValue += aChar;
     279           0 :           break;
     280             :       }
     281          13 :       break;
     282             : 
     283             :     // we're in the middle of parsing a 4-character unicode value
     284             :     // like \u5f39
     285             :     case eParserSpecial_Unicode:
     286           4 :       if ('0' <= aChar && aChar <= '9') {
     287           2 :         mUnicodeValue =
     288           4 :           (mUnicodeValue << 4) | (aChar - '0');
     289           2 :       } else if ('a' <= aChar && aChar <= 'f') {
     290           2 :         mUnicodeValue =
     291           4 :           (mUnicodeValue << 4) | (aChar - 'a' + 0x0a);
     292           0 :       } else if ('A' <= aChar && aChar <= 'F') {
     293           0 :         mUnicodeValue =
     294           0 :           (mUnicodeValue << 4) | (aChar - 'A' + 0x0a);
     295             :       } else {
     296             :         // non-hex character. Append what we have, and move on.
     297           0 :         mValue += mUnicodeValue;
     298           0 :         mMinLength = mValue.Length();
     299           0 :         mSpecialState = eParserSpecial_None;
     300             : 
     301             :         // leave aTokenStart at this unknown character, so it gets appended
     302           0 :         aTokenStart = aCur;
     303             : 
     304             :         // ensure parsing this non-hex character again
     305           0 :         return false;
     306             :       }
     307             : 
     308           4 :       if (++mUnicodeValuesRead >= 4) {
     309           1 :         aTokenStart = aCur + 1;
     310           1 :         mSpecialState = eParserSpecial_None;
     311           1 :         mValue += mUnicodeValue;
     312           1 :         mMinLength = mValue.Length();
     313             :       }
     314             : 
     315           4 :       break;
     316             :   }
     317             : 
     318       42640 :   return true;
     319             : }
     320             : 
     321             : nsresult
     322          42 : nsPropertiesParser::SegmentWriter(nsIUnicharInputStream* aStream,
     323             :                                   void* aClosure,
     324             :                                   const char16_t* aFromSegment,
     325             :                                   uint32_t aToOffset,
     326             :                                   uint32_t aCount,
     327             :                                   uint32_t* aWriteCount)
     328             : {
     329          42 :   nsPropertiesParser* parser = static_cast<nsPropertiesParser*>(aClosure);
     330          42 :   parser->ParseBuffer(aFromSegment, aCount);
     331             : 
     332          42 :   *aWriteCount = aCount;
     333          42 :   return NS_OK;
     334             : }
     335             : 
     336             : nsresult
     337          42 : nsPropertiesParser::ParseBuffer(const char16_t* aBuffer,
     338             :                                 uint32_t aBufferLength)
     339             : {
     340          42 :   const char16_t* cur = aBuffer;
     341          42 :   const char16_t* end = aBuffer + aBufferLength;
     342             : 
     343             :   // points to the start/end of the current key or value
     344          42 :   const char16_t* tokenStart = nullptr;
     345             : 
     346             :   // if we're in the middle of parsing a key or value, make sure
     347             :   // the current token points to the beginning of the current buffer
     348          75 :   if (mState == eParserState_Key ||
     349          33 :       mState == eParserState_Value) {
     350          18 :     tokenStart = aBuffer;
     351             :   }
     352             : 
     353          84 :   nsAutoString oldValue;
     354             : 
     355      230026 :   while (cur != end) {
     356             : 
     357      114992 :     char16_t c = *cur;
     358             : 
     359      114992 :     switch (mState) {
     360             :       case eParserState_AwaitingKey:
     361        2191 :         if (c == '#' || c == '!') {
     362         652 :           EnterCommentState();
     363             :         }
     364             : 
     365        1539 :         else if (!IsWhiteSpace(c)) {
     366             :           // not a comment, not whitespace, we must have found a key!
     367        1300 :           EnterKeyState();
     368        1300 :           tokenStart = cur;
     369             :         }
     370        2191 :         break;
     371             : 
     372             :       case eParserState_Key:
     373       30684 :         if (c == '=' || c == ':') {
     374        1300 :           mKey += Substring(tokenStart, cur);
     375        1300 :           WaitForValue();
     376             :         }
     377       30684 :         break;
     378             : 
     379             :       case eParserState_AwaitingValue:
     380        1540 :         if (IsEOL(c)) {
     381             :           // no value at all! mimic the normal value-ending
     382           4 :           EnterValueState();
     383           4 :           FinishValueState(oldValue);
     384             :         }
     385             : 
     386             :         // ignore white space leading up to the value
     387        1536 :         else if (!IsWhiteSpace(c)) {
     388        1296 :           tokenStart = cur;
     389        1296 :           EnterValueState();
     390             : 
     391             :           // make sure to handle this first character
     392        1296 :           if (ParseValueCharacter(c, cur, tokenStart, oldValue)) {
     393        1296 :             cur++;
     394             :           }
     395             :           // If the character isn't consumed, don't do cur++ and parse
     396             :           // the character again. This can happen f.e. for char 'X' in sequence
     397             :           // "\u00X". This character can be control character and must be
     398             :           // processed again.
     399        1296 :           continue;
     400             :         }
     401         244 :         break;
     402             : 
     403             :       case eParserState_Value:
     404       41344 :         if (ParseValueCharacter(c, cur, tokenStart, oldValue)) {
     405       41344 :           cur++;
     406             :         }
     407             :         // See few lines above for reason of doing this
     408       41344 :         continue;
     409             : 
     410             :       case eParserState_Comment:
     411             :         // stay in this state till we hit EOL
     412       39233 :         if (c == '\r' || c == '\n') {
     413         652 :           WaitForKey();
     414             :         }
     415       39233 :         break;
     416             :     }
     417             : 
     418             :     // finally, advance to the next character
     419       72352 :     cur++;
     420             :   }
     421             : 
     422             :   // if we're still parsing the value and are in eParserSpecial_None, then
     423             :   // append whatever we have..
     424          51 :   if (mState == eParserState_Value && tokenStart &&
     425           9 :       mSpecialState == eParserSpecial_None) {
     426           9 :     mValue += Substring(tokenStart, cur);
     427             :   }
     428             :   // if we're still parsing the key, then append whatever we have..
     429          33 :   else if (mState == eParserState_Key && tokenStart) {
     430           9 :     mKey += Substring(tokenStart, cur);
     431             :   }
     432             : 
     433          84 :   return NS_OK;
     434             : }
     435             : 
     436          21 : nsPersistentProperties::nsPersistentProperties()
     437             :   : mIn(nullptr)
     438             :   , mTable(&property_HashTableOps, sizeof(PropertyTableEntry), 16)
     439          21 :   , mArena()
     440             : {
     441          21 : }
     442             : 
     443           0 : nsPersistentProperties::~nsPersistentProperties()
     444             : {
     445           0 : }
     446             : 
     447             : nsresult
     448          21 : nsPersistentProperties::Create(nsISupports* aOuter, REFNSIID aIID,
     449             :                                void** aResult)
     450             : {
     451          21 :   if (aOuter) {
     452           0 :     return NS_ERROR_NO_AGGREGATION;
     453             :   }
     454          42 :   RefPtr<nsPersistentProperties> props = new nsPersistentProperties();
     455          21 :   return props->QueryInterface(aIID, aResult);
     456             : }
     457             : 
     458         252 : NS_IMPL_ISUPPORTS(nsPersistentProperties, nsIPersistentProperties, nsIProperties)
     459             : 
     460             : NS_IMETHODIMP
     461          21 : nsPersistentProperties::Load(nsIInputStream* aIn)
     462             : {
     463          21 :   nsresult rv = NS_NewUnicharInputStream(aIn, getter_AddRefs(mIn));
     464             : 
     465          21 :   if (rv != NS_OK) {
     466           0 :     NS_WARNING("Error creating UnicharInputStream");
     467           0 :     return NS_ERROR_FAILURE;
     468             :   }
     469             : 
     470          42 :   nsPropertiesParser parser(this);
     471             : 
     472             :   uint32_t nProcessed;
     473             :   // If this 4096 is changed to some other value, make sure to adjust
     474             :   // the bug121341.properties test file accordingly.
     475         189 :   while (NS_SUCCEEDED(rv = mIn->ReadSegments(nsPropertiesParser::SegmentWriter,
     476         189 :                                              &parser, 4096, &nProcessed)) &&
     477          63 :          nProcessed != 0);
     478          21 :   mIn = nullptr;
     479          21 :   if (NS_FAILED(rv)) {
     480           0 :     return rv;
     481             :   }
     482             : 
     483             :   // We may have an unprocessed value at this point
     484             :   // if the last line did not have a proper line ending.
     485          21 :   if (parser.GetState() == eParserState_Value) {
     486           0 :     nsAutoString oldValue;
     487           0 :     parser.FinishValueState(oldValue);
     488             :   }
     489             : 
     490          21 :   return NS_OK;
     491             : }
     492             : 
     493             : NS_IMETHODIMP
     494        1300 : nsPersistentProperties::SetStringProperty(const nsACString& aKey,
     495             :                                           const nsAString& aNewValue,
     496             :                                           nsAString& aOldValue)
     497             : {
     498        2600 :   const nsCString& flatKey = PromiseFlatCString(aKey);
     499             :   auto entry = static_cast<PropertyTableEntry*>
     500        1300 :                           (mTable.Add(flatKey.get()));
     501             : 
     502        1300 :   if (entry->mKey) {
     503           0 :     aOldValue = entry->mValue;
     504           0 :     NS_WARNING(nsPrintfCString("the property %s already exists",
     505           0 :                                flatKey.get()).get());
     506             :   } else {
     507        1300 :     aOldValue.Truncate();
     508             :   }
     509             : 
     510        1300 :   entry->mKey = ArenaStrdup(flatKey, mArena);
     511        1300 :   entry->mValue = ArenaStrdup(aNewValue, mArena);
     512             : 
     513        2600 :   return NS_OK;
     514             : }
     515             : 
     516             : NS_IMETHODIMP
     517           0 : nsPersistentProperties::Save(nsIOutputStream* aOut, const nsACString& aHeader)
     518             : {
     519           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     520             : }
     521             : 
     522             : NS_IMETHODIMP
     523         155 : nsPersistentProperties::GetStringProperty(const nsACString& aKey,
     524             :                                           nsAString& aValue)
     525             : {
     526         310 :   const nsCString& flatKey = PromiseFlatCString(aKey);
     527             : 
     528         155 :   auto entry = static_cast<PropertyTableEntry*>(mTable.Search(flatKey.get()));
     529         155 :   if (!entry) {
     530           7 :     return NS_ERROR_FAILURE;
     531             :   }
     532             : 
     533         148 :   aValue = entry->mValue;
     534         148 :   return NS_OK;
     535             : }
     536             : 
     537             : NS_IMETHODIMP
     538           0 : nsPersistentProperties::Enumerate(nsISimpleEnumerator** aResult)
     539             : {
     540           0 :   nsCOMArray<nsIPropertyElement> props;
     541             : 
     542             :   // We know the necessary size; we can avoid growing it while adding elements
     543           0 :   props.SetCapacity(mTable.EntryCount());
     544             : 
     545             :   // Step through hash entries populating a transient array
     546           0 :   for (auto iter = mTable.Iter(); !iter.Done(); iter.Next()) {
     547           0 :     auto entry = static_cast<PropertyTableEntry*>(iter.Get());
     548             : 
     549             :     RefPtr<nsPropertyElement> element =
     550           0 :       new nsPropertyElement(nsDependentCString(entry->mKey),
     551           0 :                             nsDependentString(entry->mValue));
     552             : 
     553           0 :     if (!props.AppendObject(element)) {
     554           0 :       return NS_ERROR_OUT_OF_MEMORY;
     555             :     }
     556             :   }
     557             : 
     558           0 :   return NS_NewArrayEnumerator(aResult, props);
     559             : }
     560             : 
     561             : ////////////////////////////////////////////////////////////////////////////////
     562             : // XXX Some day we'll unify the nsIPersistentProperties interface with
     563             : // nsIProperties, but until now...
     564             : 
     565             : NS_IMETHODIMP
     566           0 : nsPersistentProperties::Get(const char* aProp, const nsIID& aUUID,
     567             :                             void** aResult)
     568             : {
     569           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     570             : }
     571             : 
     572             : NS_IMETHODIMP
     573           0 : nsPersistentProperties::Set(const char* aProp, nsISupports* value)
     574             : {
     575           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     576             : }
     577             : NS_IMETHODIMP
     578           0 : nsPersistentProperties::Undefine(const char* aProp)
     579             : {
     580           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     581             : }
     582             : 
     583             : NS_IMETHODIMP
     584           0 : nsPersistentProperties::Has(const char* aProp, bool* aResult)
     585             : {
     586           0 :   *aResult = !!mTable.Search(aProp);
     587           0 :   return NS_OK;
     588             : }
     589             : 
     590             : NS_IMETHODIMP
     591           0 : nsPersistentProperties::GetKeys(uint32_t* aCount, char*** aKeys)
     592             : {
     593           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     594             : }
     595             : 
     596             : ////////////////////////////////////////////////////////////////////////////////
     597             : // PropertyElement
     598             : ////////////////////////////////////////////////////////////////////////////////
     599             : 
     600             : nsresult
     601           0 : nsPropertyElement::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
     602             : {
     603           0 :   if (aOuter) {
     604           0 :     return NS_ERROR_NO_AGGREGATION;
     605             :   }
     606           0 :   RefPtr<nsPropertyElement> propElem = new nsPropertyElement();
     607           0 :   return propElem->QueryInterface(aIID, aResult);
     608             : }
     609             : 
     610           0 : NS_IMPL_ISUPPORTS(nsPropertyElement, nsIPropertyElement)
     611             : 
     612             : NS_IMETHODIMP
     613           0 : nsPropertyElement::GetKey(nsACString& aReturnKey)
     614             : {
     615           0 :   aReturnKey = mKey;
     616           0 :   return NS_OK;
     617             : }
     618             : 
     619             : NS_IMETHODIMP
     620           0 : nsPropertyElement::GetValue(nsAString& aReturnValue)
     621             : {
     622           0 :   aReturnValue = mValue;
     623           0 :   return NS_OK;
     624             : }
     625             : 
     626             : NS_IMETHODIMP
     627           0 : nsPropertyElement::SetKey(const nsACString& aKey)
     628             : {
     629           0 :   mKey = aKey;
     630           0 :   return NS_OK;
     631             : }
     632             : 
     633             : NS_IMETHODIMP
     634           0 : nsPropertyElement::SetValue(const nsAString& aValue)
     635             : {
     636           0 :   mValue = aValue;
     637           0 :   return NS_OK;
     638             : }
     639             : 
     640             : ////////////////////////////////////////////////////////////////////////////////

Generated by: LCOV version 1.13