LCOV - code coverage report
Current view: directory - xpcom/ds - nsPersistentProperties.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 293 222 75.8 %
Date: 2012-06-02 Functions: 43 26 60.5 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       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                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsID.h"
      40                 : #include "nsCRT.h"
      41                 : #include "nsReadableUtils.h"
      42                 : #include "nsIInputStream.h"
      43                 : #include "nsUnicharInputStream.h"
      44                 : #include "pratom.h"
      45                 : #include "nsEnumeratorUtils.h"
      46                 : #include "nsReadableUtils.h"
      47                 : #include "nsPrintfCString.h"
      48                 : #include "nsDependentString.h"
      49                 : 
      50                 : #define PL_ARENA_CONST_ALIGN_MASK 3
      51                 : #include "nsPersistentProperties.h"
      52                 : #include "nsIProperties.h"
      53                 : #include "nsISupportsArray.h"
      54                 : #include "nsProperties.h"
      55                 : 
      56                 : struct PropertyTableEntry : public PLDHashEntryHdr
      57                 : {
      58                 :   // both of these are arena-allocated
      59                 :   const char *mKey;
      60                 :   const PRUnichar *mValue;
      61                 : };
      62                 : 
      63                 : static PRUnichar*
      64          308798 : ArenaStrdup(const nsAFlatString& aString, PLArenaPool* aArena)
      65                 : {
      66                 :   void *mem;
      67                 :   // add one to include the null terminator
      68          308798 :   PRInt32 len = (aString.Length()+1) * sizeof(PRUnichar);
      69          308798 :   PL_ARENA_ALLOCATE(mem, aArena, len);
      70          308798 :   NS_ASSERTION(mem, "Couldn't allocate space!\n");
      71          308798 :   if (mem) {
      72          308798 :     memcpy(mem, aString.get(), len);
      73                 :   }
      74          308798 :   return static_cast<PRUnichar*>(mem);
      75                 : }
      76                 : 
      77                 : static char*
      78          308798 : ArenaStrdup(const nsAFlatCString& aString, PLArenaPool* aArena)
      79                 : {
      80                 :   void *mem;
      81                 :   // add one to include the null terminator
      82          308798 :   PRInt32 len = (aString.Length()+1) * sizeof(char);
      83          308798 :   PL_ARENA_ALLOCATE(mem, aArena, len);
      84          308798 :   NS_ASSERTION(mem, "Couldn't allocate space!\n");
      85          308798 :   if (mem)
      86          308798 :     memcpy(mem, aString.get(), len);
      87          308798 :   return static_cast<char*>(mem);
      88                 : }
      89                 : 
      90                 : static const struct PLDHashTableOps property_HashTableOps = {
      91                 :   PL_DHashAllocTable,
      92                 :   PL_DHashFreeTable,
      93                 :   PL_DHashStringKey,
      94                 :   PL_DHashMatchStringKey,
      95                 :   PL_DHashMoveEntryStub,
      96                 :   PL_DHashClearEntryStub,
      97                 :   PL_DHashFinalizeStub,
      98                 :   nsnull,
      99                 : };
     100                 : 
     101                 : //
     102                 : // parser stuff
     103                 : //
     104                 : enum EParserState {
     105                 :   eParserState_AwaitingKey,
     106                 :   eParserState_Key,
     107                 :   eParserState_AwaitingValue,
     108                 :   eParserState_Value,
     109                 :   eParserState_Comment
     110                 : };
     111                 : 
     112                 : enum EParserSpecial {
     113                 :   eParserSpecial_None,          // not parsing a special character
     114                 :   eParserSpecial_Escaped,       // awaiting a special character
     115                 :   eParserSpecial_Unicode        // parsing a \Uxxx value
     116                 : };
     117                 : 
     118                 : class nsPropertiesParser
     119            2297 : {
     120                 : public:
     121            2297 :   nsPropertiesParser(nsIPersistentProperties* aProps) :
     122                 :     mHaveMultiLine(false), mState(eParserState_AwaitingKey),
     123            2297 :     mProps(aProps) {}
     124                 : 
     125          308798 :   void FinishValueState(nsAString& aOldValue) {
     126                 :     static const char trimThese[] = " \t";
     127          308798 :     mKey.Trim(trimThese, false, true);
     128                 : 
     129                 :     // This is really ugly hack but it should be fast
     130                 :     PRUnichar backup_char;
     131          308798 :     PRUint32 minLength = mMinLength;
     132          308798 :     if (minLength)
     133                 :     {
     134            1184 :       backup_char = mValue[minLength-1];
     135            1184 :       mValue.SetCharAt('x', minLength-1);
     136                 :     }
     137          308798 :     mValue.Trim(trimThese, false, true);
     138          308798 :     if (minLength)
     139            1184 :       mValue.SetCharAt(backup_char, minLength-1);
     140                 : 
     141          308798 :     mProps->SetStringProperty(NS_ConvertUTF16toUTF8(mKey), mValue, aOldValue);
     142          308798 :     mSpecialState = eParserSpecial_None;
     143          308798 :     WaitForKey();
     144          308798 :   }
     145                 : 
     146            2295 :   EParserState GetState() { return mState; }
     147                 : 
     148                 :   static NS_METHOD SegmentWriter(nsIUnicharInputStream* aStream,
     149                 :                                  void* aClosure,
     150                 :                                  const PRUnichar *aFromSegment,
     151                 :                                  PRUint32 aToOffset,
     152                 :                                  PRUint32 aCount,
     153                 :                                  PRUint32 *aWriteCount);
     154                 : 
     155                 :   nsresult ParseBuffer(const PRUnichar* aBuffer, PRUint32 aBufferLength);
     156                 : 
     157                 : private:
     158                 :   bool ParseValueCharacter(
     159                 :     PRUnichar c,                  // character that is just being parsed
     160                 :     const PRUnichar* cur,         // pointer to character c in the buffer
     161                 :     const PRUnichar* &tokenStart, // string copying is done in blocks as big as
     162                 :                                   // possible, tokenStart points to the beginning
     163                 :                                   // of this block
     164                 :     nsAString& oldValue);         // when duplicate property is found, new value
     165                 :                                   // is stored into hashtable and the old one is
     166                 :                                   // placed in this variable
     167                 : 
     168          386881 :   void WaitForKey() {
     169          386881 :     mState = eParserState_AwaitingKey;
     170          386881 :   }
     171                 : 
     172          308798 :   void EnterKeyState() {
     173          308798 :     mKey.Truncate();
     174          308798 :     mState = eParserState_Key;
     175          308798 :   }
     176                 : 
     177          308798 :   void WaitForValue() {
     178          308798 :     mState = eParserState_AwaitingValue;
     179          308798 :   }
     180                 : 
     181          308798 :   void EnterValueState() {
     182          308798 :     mValue.Truncate();
     183          308798 :     mMinLength = 0;
     184          308798 :     mState = eParserState_Value;
     185          308798 :     mSpecialState = eParserSpecial_None;
     186          308798 :   }
     187                 : 
     188           78083 :   void EnterCommentState() {
     189           78083 :     mState = eParserState_Comment;
     190           78083 :   }
     191                 : 
     192                 :   nsAutoString mKey;
     193                 :   nsAutoString mValue;
     194                 : 
     195                 :   PRUint32  mUnicodeValuesRead; // should be 4!
     196                 :   PRUnichar mUnicodeValue;      // currently parsed unicode value
     197                 :   bool      mHaveMultiLine;     // is TRUE when last processed characters form
     198                 :                                 // any of following sequences:
     199                 :                                 //  - "\\\r"
     200                 :                                 //  - "\\\n"
     201                 :                                 //  - "\\\r\n"
     202                 :                                 //  - any sequence above followed by any
     203                 :                                 //    combination of ' ' and '\t'
     204                 :   bool      mMultiLineCanSkipN; // TRUE if "\\\r" was detected
     205                 :   PRUint32  mMinLength;         // limit right trimming at the end to not trim
     206                 :                                 // escaped whitespaces
     207                 :   EParserState mState;
     208                 :   // if we see a '\' then we enter this special state
     209                 :   EParserSpecial mSpecialState;
     210                 :   nsIPersistentProperties* mProps;
     211                 : };
     212                 : 
     213          715299 : inline bool IsWhiteSpace(PRUnichar aChar)
     214                 : {
     215                 :   return (aChar == ' ') || (aChar == '\t') ||
     216          715299 :          (aChar == '\r') || (aChar == '\n');
     217                 : }
     218                 : 
     219          395822 : inline bool IsEOL(PRUnichar aChar)
     220                 : {
     221          395822 :   return (aChar == '\r') || (aChar == '\n');
     222                 : }
     223                 : 
     224                 : 
     225         9900711 : bool nsPropertiesParser::ParseValueCharacter(
     226                 :     PRUnichar c, const PRUnichar* cur, const PRUnichar* &tokenStart,
     227                 :     nsAString& oldValue)
     228                 : {
     229         9900711 :   switch (mSpecialState) {
     230                 : 
     231                 :     // the normal state - look for special characters
     232                 :   case eParserSpecial_None:
     233         9897539 :     switch (c) {
     234                 :     case '\\':
     235            2999 :       if (mHaveMultiLine)
     236                 :         // there is nothing to append to mValue yet
     237               1 :         mHaveMultiLine = false;
     238                 :       else
     239            2998 :         mValue += Substring(tokenStart, cur);
     240                 : 
     241            2999 :       mSpecialState = eParserSpecial_Escaped;
     242            2999 :       break;
     243                 : 
     244                 :     case '\n':
     245                 :       // if we detected multiline and got only "\\\r" ignore next "\n" if any
     246          307425 :       if (mHaveMultiLine && mMultiLineCanSkipN) {
     247                 :         // but don't allow another '\n' to be skipped
     248               1 :         mMultiLineCanSkipN = false;
     249                 :         // Now there is nothing to append to the mValue since we are skipping
     250                 :         // whitespaces at the beginning of the new line of the multiline
     251                 :         // property. Set tokenStart properly to ensure that nothing is appended
     252                 :         // if we find regular line-end or the end of the buffer.
     253               1 :         tokenStart = cur+1;
     254               1 :         break;
     255                 :       }
     256                 :       // no break
     257                 : 
     258                 :     case '\r':
     259                 :       // we're done! We have a key and value
     260          307426 :       mValue += Substring(tokenStart, cur);
     261          307426 :       FinishValueState(oldValue);
     262          307426 :       mHaveMultiLine = false;
     263          307426 :       break;
     264                 : 
     265                 :     default:
     266                 :       // there is nothing to do with normal characters,
     267                 :       // but handle multilines correctly
     268         9587113 :       if (mHaveMultiLine) {
     269              11 :         if (c == ' ' || c == '\t') {
     270                 :           // don't allow another '\n' to be skipped
     271               8 :           mMultiLineCanSkipN = false;
     272                 :           // Now there is nothing to append to the mValue since we are skipping
     273                 :           // whitespaces at the beginning of the new line of the multiline
     274                 :           // property. Set tokenStart properly to ensure that nothing is appended
     275                 :           // if we find regular line-end or the end of the buffer.
     276               8 :           tokenStart = cur+1;
     277               8 :           break;
     278                 :         }
     279               3 :         mHaveMultiLine = false;
     280               3 :         tokenStart = cur;
     281                 :       }
     282         9587105 :       break; // from switch on (c)
     283                 :     }
     284         9897539 :     break; // from switch on (mSpecialState)
     285                 : 
     286                 :     // saw a \ character, so parse the character after that
     287                 :   case eParserSpecial_Escaped:
     288                 :     // probably want to start parsing at the next token
     289                 :     // other characters, like 'u' might override this
     290            2999 :     tokenStart = cur+1;
     291            2999 :     mSpecialState = eParserSpecial_None;
     292                 : 
     293            2999 :     switch (c) {
     294                 : 
     295                 :       // the easy characters - \t, \n, and so forth
     296                 :     case 't':
     297               3 :       mValue += PRUnichar('\t');
     298               3 :       mMinLength = mValue.Length();
     299               3 :       break;
     300                 :     case 'n':
     301            2946 :       mValue += PRUnichar('\n');
     302            2946 :       mMinLength = mValue.Length();
     303            2946 :       break;
     304                 :     case 'r':
     305               1 :       mValue += PRUnichar('\r');
     306               1 :       mMinLength = mValue.Length();
     307               1 :       break;
     308                 :     case '\\':
     309               0 :       mValue += PRUnichar('\\');
     310               0 :       break;
     311                 : 
     312                 :       // switch to unicode mode!
     313                 :     case 'u':
     314                 :     case 'U':
     315              44 :       mSpecialState = eParserSpecial_Unicode;
     316              44 :       mUnicodeValuesRead = 0;
     317              44 :       mUnicodeValue = 0;
     318              44 :       break;
     319                 : 
     320                 :       // a \ immediately followed by a newline means we're going multiline
     321                 :     case '\r':
     322                 :     case '\n':
     323               4 :       mHaveMultiLine = true;
     324               4 :       mMultiLineCanSkipN = (c == '\r');
     325               4 :       mSpecialState = eParserSpecial_None;
     326               4 :       break;
     327                 : 
     328                 :     default:
     329                 :       // don't recognize the character, so just append it
     330               1 :       mValue += c;
     331               1 :       break;
     332                 :     }
     333            2999 :     break;
     334                 : 
     335                 :     // we're in the middle of parsing a 4-character unicode value
     336                 :     // like \u5f39
     337                 :   case eParserSpecial_Unicode:
     338                 : 
     339             173 :     if(('0' <= c) && (c <= '9'))
     340                 :       mUnicodeValue =
     341             157 :         (mUnicodeValue << 4) | (c - '0');
     342              16 :     else if(('a' <= c) && (c <= 'f'))
     343                 :       mUnicodeValue =
     344               4 :         (mUnicodeValue << 4) | (c - 'a' + 0x0a);
     345              12 :     else if(('A' <= c) && (c <= 'F'))
     346                 :       mUnicodeValue =
     347              10 :         (mUnicodeValue << 4) | (c - 'A' + 0x0a);
     348                 :     else {
     349                 :       // non-hex character. Append what we have, and move on.
     350               2 :       mValue += mUnicodeValue;
     351               2 :       mMinLength = mValue.Length();
     352               2 :       mSpecialState = eParserSpecial_None;
     353                 : 
     354                 :       // leave tokenStart at this unknown character, so it gets appended
     355               2 :       tokenStart = cur;
     356                 : 
     357                 :       // ensure parsing this non-hex character again
     358               2 :       return false;
     359                 :     }
     360                 : 
     361             171 :     if (++mUnicodeValuesRead >= 4) {
     362              42 :       tokenStart = cur+1;
     363              42 :       mSpecialState = eParserSpecial_None;
     364              42 :       mValue += mUnicodeValue;
     365              42 :       mMinLength = mValue.Length();
     366                 :     }
     367                 : 
     368             171 :     break;
     369                 :   }
     370                 : 
     371         9900709 :   return true;
     372                 : }
     373                 : 
     374            6772 : NS_METHOD nsPropertiesParser::SegmentWriter(nsIUnicharInputStream* aStream,
     375                 :                                             void* aClosure,
     376                 :                                             const PRUnichar *aFromSegment,
     377                 :                                             PRUint32 aToOffset,
     378                 :                                             PRUint32 aCount,
     379                 :                                             PRUint32 *aWriteCount)
     380                 : {
     381                 :   nsPropertiesParser *parser = 
     382            6772 :     static_cast<nsPropertiesParser *>(aClosure);
     383                 :   
     384            6772 :   parser->ParseBuffer(aFromSegment, aCount);
     385                 : 
     386            6772 :   *aWriteCount = aCount;
     387            6772 :   return NS_OK;
     388                 : }
     389                 : 
     390            6772 : nsresult nsPropertiesParser::ParseBuffer(const PRUnichar* aBuffer,
     391                 :                                          PRUint32 aBufferLength)
     392                 : {
     393            6772 :   const PRUnichar* cur = aBuffer;
     394            6772 :   const PRUnichar* end = aBuffer + aBufferLength;
     395                 : 
     396                 :   // points to the start/end of the current key or value
     397            6772 :   const PRUnichar* tokenStart = nsnull;
     398                 : 
     399                 :   // if we're in the middle of parsing a key or value, make sure
     400                 :   // the current token points to the beginning of the current buffer
     401            6772 :   if (mState == eParserState_Key ||
     402                 :       mState == eParserState_Value) {
     403            3885 :     tokenStart = aBuffer;
     404                 :   }
     405                 : 
     406           13544 :   nsAutoString oldValue;
     407                 : 
     408        22743452 :   while (cur != end) {
     409                 : 
     410        22729908 :     PRUnichar c = *cur;
     411                 : 
     412        22729908 :     switch (mState) {
     413                 :     case eParserState_AwaitingKey:
     414          398932 :       if (c == '#' || c == '!')
     415           78083 :         EnterCommentState();
     416                 : 
     417          320849 :       else if (!IsWhiteSpace(c)) {
     418                 :         // not a comment, not whitespace, we must have found a key!
     419          308798 :         EnterKeyState();
     420          308798 :         tokenStart = cur;
     421                 :       }
     422          398932 :       break;
     423                 : 
     424                 :     case eParserState_Key:
     425         8658058 :       if (c == '=' || c == ':') {
     426          308798 :         mKey += Substring(tokenStart, cur);
     427          308798 :         WaitForValue();
     428                 :       }
     429         8658058 :       break;
     430                 : 
     431                 :     case eParserState_AwaitingValue:
     432          395822 :       if (IsEOL(c)) {
     433                 :         // no value at all! mimic the normal value-ending
     434            1372 :         EnterValueState();
     435            1372 :         FinishValueState(oldValue);
     436                 :       }
     437                 : 
     438                 :       // ignore white space leading up to the value
     439          394450 :       else if (!IsWhiteSpace(c)) {
     440          307426 :         tokenStart = cur;
     441          307426 :         EnterValueState();
     442                 : 
     443                 :         // make sure to handle this first character
     444          307426 :         if (ParseValueCharacter(c, cur, tokenStart, oldValue))
     445          307426 :           cur++;
     446                 :         // If the character isn't consumed, don't do cur++ and parse
     447                 :         // the character again. This can happen f.e. for char 'X' in sequence
     448                 :         // "\u00X". This character can be control character and must be
     449                 :         // processed again.
     450          307426 :         continue;
     451                 :       }
     452           88396 :       break;
     453                 : 
     454                 :     case eParserState_Value:
     455         9593285 :       if (ParseValueCharacter(c, cur, tokenStart, oldValue))
     456         9593283 :         cur++;
     457                 :       // See few lines above for reason of doing this
     458         9593285 :       continue;
     459                 : 
     460                 :     case eParserState_Comment:
     461                 :       // stay in this state till we hit EOL
     462         3683811 :       if (c == '\r' || c== '\n')
     463           78083 :         WaitForKey();
     464         3683811 :       break;
     465                 :     }
     466                 : 
     467                 :     // finally, advance to the next character
     468        12829197 :     cur++;
     469                 :   }
     470                 : 
     471                 :   // if we're still parsing the value and are in eParserSpecial_None, then
     472                 :   // append whatever we have..
     473            6772 :   if (mState == eParserState_Value && tokenStart &&
     474                 :       mSpecialState == eParserSpecial_None) {
     475            1990 :     mValue += Substring(tokenStart, cur);
     476                 :   }
     477                 :   // if we're still parsing the key, then append whatever we have..
     478            4782 :   else if (mState == eParserState_Key && tokenStart) {
     479            1894 :     mKey += Substring(tokenStart, cur);
     480                 :   }
     481                 : 
     482            6772 :   return NS_OK;
     483                 : }
     484                 : 
     485            2297 : nsPersistentProperties::nsPersistentProperties()
     486            2297 : : mIn(nsnull)
     487                 : {
     488            2297 :   mSubclass = static_cast<nsIPersistentProperties*>(this);
     489            2297 :   mTable.ops = nsnull;
     490            2297 :   PL_INIT_ARENA_POOL(&mArena, "PersistentPropertyArena", 2048);
     491            2297 : }
     492                 : 
     493            4594 : nsPersistentProperties::~nsPersistentProperties()
     494                 : {
     495            2297 :   PL_FinishArenaPool(&mArena);
     496            2297 :   if (mTable.ops)
     497            2297 :     PL_DHashTableFinish(&mTable);
     498            2297 : }
     499                 : 
     500                 : nsresult
     501            2297 : nsPersistentProperties::Init()
     502                 : {
     503            2297 :   if (!PL_DHashTableInit(&mTable, &property_HashTableOps, nsnull,
     504            2297 :                          sizeof(PropertyTableEntry), 20)) {
     505               0 :     mTable.ops = nsnull;
     506               0 :     return NS_ERROR_OUT_OF_MEMORY;
     507                 :   }
     508            2297 :   return NS_OK;
     509                 : }
     510                 : 
     511                 : nsresult
     512            2297 : nsPersistentProperties::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
     513                 : {
     514            2297 :   if (aOuter)
     515               0 :     return NS_ERROR_NO_AGGREGATION;
     516            2297 :   nsPersistentProperties* props = new nsPersistentProperties();
     517            2297 :   if (props == nsnull)
     518               0 :     return NS_ERROR_OUT_OF_MEMORY;
     519                 : 
     520            2297 :   NS_ADDREF(props);
     521            2297 :   nsresult rv = props->Init();
     522            2297 :   if (NS_SUCCEEDED(rv))
     523            2297 :     rv = props->QueryInterface(aIID, aResult);
     524                 : 
     525            2297 :   NS_RELEASE(props);
     526            2297 :   return rv;
     527                 : }
     528                 : 
     529           20691 : NS_IMPL_THREADSAFE_ISUPPORTS2(nsPersistentProperties, nsIPersistentProperties, nsIProperties)
     530                 : 
     531                 : NS_IMETHODIMP
     532            2297 : nsPersistentProperties::Load(nsIInputStream *aIn)
     533                 : {
     534            2297 :   nsresult rv = nsSimpleUnicharStreamFactory::GetInstance()->
     535            2297 :     CreateInstanceFromUTF8Stream(aIn, getter_AddRefs(mIn));
     536                 : 
     537            2297 :   if (rv != NS_OK) {
     538               0 :     NS_WARNING("Error creating UnicharInputStream");
     539               0 :     return NS_ERROR_FAILURE;
     540                 :   }
     541                 : 
     542            4594 :   nsPropertiesParser parser(mSubclass);
     543                 : 
     544                 :   PRUint32 nProcessed;
     545                 :   // If this 4096 is changed to some other value, make sure to adjust
     546                 :   // the bug121341.properties test file accordingly.
     547            2297 :   while (NS_SUCCEEDED(rv = mIn->ReadSegments(nsPropertiesParser::SegmentWriter, &parser, 4096, &nProcessed)) &&
     548                 :          nProcessed != 0);
     549            2297 :   mIn = nsnull;
     550            2297 :   if (NS_FAILED(rv))
     551               2 :     return rv;
     552                 : 
     553                 :   // We may have an unprocessed value at this point
     554                 :   // if the last line did not have a proper line ending.
     555            2295 :   if (parser.GetState() == eParserState_Value) {
     556               0 :     nsAutoString oldValue;  
     557               0 :     parser.FinishValueState(oldValue);
     558                 :   }
     559                 : 
     560            2295 :   return NS_OK;
     561                 : }
     562                 : 
     563                 : NS_IMETHODIMP
     564          308798 : nsPersistentProperties::SetStringProperty(const nsACString& aKey,
     565                 :                                           const nsAString& aNewValue,
     566                 :                                           nsAString& aOldValue)
     567                 : {
     568          617596 :   const nsAFlatCString&  flatKey = PromiseFlatCString(aKey);
     569                 :   PropertyTableEntry *entry =
     570                 :     static_cast<PropertyTableEntry*>
     571          308798 :                (PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_ADD));
     572                 : 
     573          308798 :   if (entry->mKey) {
     574               2 :     aOldValue = entry->mValue;
     575               4 :     NS_WARNING(nsPrintfCString(aKey.Length() + 30,
     576                 :                                "the property %s already exists\n",
     577               2 :                                flatKey.get()).get());
     578                 :   }
     579                 :   else {
     580          308796 :     aOldValue.Truncate();
     581                 :   }
     582                 : 
     583          308798 :   entry->mKey = ArenaStrdup(flatKey, &mArena);
     584          308798 :   entry->mValue = ArenaStrdup(PromiseFlatString(aNewValue), &mArena);
     585                 : 
     586          308798 :   return NS_OK;
     587                 : }
     588                 : 
     589                 : NS_IMETHODIMP
     590               0 : nsPersistentProperties::Save(nsIOutputStream* aOut, const nsACString& aHeader)
     591                 : {
     592               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     593                 : }
     594                 : 
     595                 : NS_IMETHODIMP
     596               0 : nsPersistentProperties::Subclass(nsIPersistentProperties* aSubclass)
     597                 : {
     598               0 :   if (aSubclass) {
     599               0 :     mSubclass = aSubclass;
     600                 :   }
     601                 : 
     602               0 :   return NS_OK;
     603                 : }
     604                 : 
     605                 : NS_IMETHODIMP
     606           23416 : nsPersistentProperties::GetStringProperty(const nsACString& aKey,
     607                 :                                           nsAString& aValue)
     608                 : {
     609           46832 :   const nsAFlatCString&  flatKey = PromiseFlatCString(aKey);
     610                 : 
     611                 :   PropertyTableEntry *entry =
     612                 :     static_cast<PropertyTableEntry*>
     613           23416 :                (PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_LOOKUP));
     614                 : 
     615           23416 :   if (PL_DHASH_ENTRY_IS_FREE(entry))
     616           16251 :     return NS_ERROR_FAILURE;
     617                 : 
     618            7165 :   aValue = entry->mValue;
     619            7165 :   return NS_OK;
     620                 : }
     621                 : 
     622                 : static PLDHashOperator
     623               0 : AddElemToArray(PLDHashTable* table, PLDHashEntryHdr *hdr,
     624                 :                PRUint32 i, void *arg)
     625                 : {
     626               0 :   nsISupportsArray  *propArray = (nsISupportsArray *) arg;
     627                 :   PropertyTableEntry* entry =
     628               0 :     static_cast<PropertyTableEntry*>(hdr);
     629                 : 
     630                 :   nsPropertyElement *element =
     631               0 :     new nsPropertyElement(nsDependentCString(entry->mKey),
     632               0 :                           nsDependentString(entry->mValue));
     633               0 :   if (!element)
     634               0 :      return PL_DHASH_STOP;
     635                 : 
     636               0 :   propArray->InsertElementAt(element, i);
     637                 : 
     638               0 :   return PL_DHASH_NEXT;
     639                 : }
     640                 : 
     641                 : 
     642                 : NS_IMETHODIMP
     643               0 : nsPersistentProperties::Enumerate(nsISimpleEnumerator** aResult)
     644                 : {
     645               0 :   nsCOMPtr<nsISupportsArray> propArray;
     646               0 :   nsresult rv = NS_NewISupportsArray(getter_AddRefs(propArray));
     647               0 :   if (NS_FAILED(rv))
     648               0 :     return rv;
     649                 : 
     650                 :   // We know the necessary size; we can avoid growing it while adding elements
     651               0 :   if (!propArray->SizeTo(mTable.entryCount))
     652               0 :     return NS_ERROR_OUT_OF_MEMORY;
     653                 : 
     654                 :   // Step through hash entries populating a transient array
     655                 :   PRUint32 n =
     656               0 :     PL_DHashTableEnumerate(&mTable, AddElemToArray, (void *)propArray);
     657               0 :   if (n < mTable.entryCount)
     658               0 :     return NS_ERROR_OUT_OF_MEMORY;
     659                 : 
     660               0 :   return NS_NewArrayEnumerator(aResult, propArray);
     661                 : }
     662                 : 
     663                 : ////////////////////////////////////////////////////////////////////////////////
     664                 : // XXX Some day we'll unify the nsIPersistentProperties interface with
     665                 : // nsIProperties, but until now...
     666                 : 
     667                 : NS_IMETHODIMP
     668               0 : nsPersistentProperties::Get(const char* prop, const nsIID & uuid, void* *result)
     669                 : {
     670               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     671                 : }
     672                 : 
     673                 : NS_IMETHODIMP
     674               0 : nsPersistentProperties::Set(const char* prop, nsISupports* value)
     675                 : {
     676               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     677                 : }
     678                 : NS_IMETHODIMP
     679               0 : nsPersistentProperties::Undefine(const char* prop)
     680                 : {
     681               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     682                 : }
     683                 : 
     684                 : NS_IMETHODIMP
     685               0 : nsPersistentProperties::Has(const char* prop, bool *result)
     686                 : {
     687                 :   PropertyTableEntry *entry =
     688                 :     static_cast<PropertyTableEntry*>
     689               0 :                (PL_DHashTableOperate(&mTable, prop, PL_DHASH_LOOKUP));
     690                 : 
     691               0 :   *result = (entry && PL_DHASH_ENTRY_IS_BUSY(entry));
     692                 : 
     693               0 :   return NS_OK;
     694                 : }
     695                 : 
     696                 : NS_IMETHODIMP
     697               0 : nsPersistentProperties::GetKeys(PRUint32 *count, char ***keys)
     698                 : {
     699               0 :     return NS_ERROR_NOT_IMPLEMENTED;
     700                 : }
     701                 : 
     702                 : ////////////////////////////////////////////////////////////////////////////////
     703                 : // PropertyElement
     704                 : ////////////////////////////////////////////////////////////////////////////////
     705                 : 
     706                 : NS_METHOD
     707               0 : nsPropertyElement::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
     708                 : {
     709               0 :   if (aOuter)
     710               0 :     return NS_ERROR_NO_AGGREGATION;
     711               0 :   nsPropertyElement* propElem = new nsPropertyElement();
     712               0 :   if (propElem == nsnull)
     713               0 :     return NS_ERROR_OUT_OF_MEMORY;
     714               0 :   NS_ADDREF(propElem);
     715               0 :   nsresult rv = propElem->QueryInterface(aIID, aResult);
     716               0 :   NS_RELEASE(propElem);
     717               0 :   return rv;
     718                 : }
     719                 : 
     720               0 : NS_IMPL_ISUPPORTS1(nsPropertyElement, nsIPropertyElement)
     721                 : 
     722                 : NS_IMETHODIMP
     723               0 : nsPropertyElement::GetKey(nsACString& aReturnKey)
     724                 : {
     725               0 :   aReturnKey = mKey;
     726               0 :   return NS_OK;
     727                 : }
     728                 : 
     729                 : NS_IMETHODIMP
     730               0 : nsPropertyElement::GetValue(nsAString& aReturnValue)
     731                 : {
     732               0 :   aReturnValue = mValue;
     733               0 :   return NS_OK;
     734                 : }
     735                 : 
     736                 : NS_IMETHODIMP
     737               0 : nsPropertyElement::SetKey(const nsACString& aKey)
     738                 : {
     739               0 :   mKey = aKey;
     740               0 :   return NS_OK;
     741                 : }
     742                 : 
     743                 : NS_IMETHODIMP
     744               0 : nsPropertyElement::SetValue(const nsAString& aValue)
     745                 : {
     746               0 :   mValue = aValue;
     747               0 :   return NS_OK;
     748                 : }
     749                 : 
     750                 : ////////////////////////////////////////////////////////////////////////////////
     751                 : 

Generated by: LCOV version 1.7