LCOV - app.info - xpcom/ds/nsPersistentProperties.cpp

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-04-21 | 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          307770 : ArenaStrdup(const nsAFlatString& aString, PLArenaPool* aArena)
          65                 : {
          66                 :   void *mem;
          67                 :   // add one to include the null terminator
          68          307770 :   PRInt32 len = (aString.Length()+1) * sizeof(PRUnichar);
          69          307770 :   PL_ARENA_ALLOCATE(mem, aArena, len);
          70          307770 :   NS_ASSERTION(mem, "Couldn't allocate space!\n");
          71          307770 :   if (mem) {
          72          307770 :     memcpy(mem, aString.get(), len);
          73                 :   }
          74          307770 :   return static_cast<PRUnichar*>(mem);
          75                 : }
          76                 :
          77                 : static char*
          78          307770 : ArenaStrdup(const nsAFlatCString& aString, PLArenaPool* aArena)
          79                 : {
          80                 :   void *mem;
          81                 :   // add one to include the null terminator
          82          307770 :   PRInt32 len = (aString.Length()+1) * sizeof(char);
          83          307770 :   PL_ARENA_ALLOCATE(mem, aArena, len);
          84          307770 :   NS_ASSERTION(mem, "Couldn't allocate space!\n");
          85          307770 :   if (mem)
          86          307770 :     memcpy(mem, aString.get(), len);
          87          307770 :   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            2285 : {
         120                 : public:
         121            2285 :   nsPropertiesParser(nsIPersistentProperties* aProps) :
         122                 :     mHaveMultiLine(false), mState(eParserState_AwaitingKey),
         123            2285 :     mProps(aProps) {}
         124                 :
         125          307770 :   void FinishValueState(nsAString& aOldValue) {
         126                 :     static const char trimThese[] = " \t";
         127          307770 :     mKey.Trim(trimThese, false, true);
         128                 :
         129                 :     // This is really ugly hack but it should be fast
         130                 :     PRUnichar backup_char;
         131          307770 :     PRUint32 minLength = mMinLength;
         132          307770 :     if (minLength)
         133                 :     {
         134            1180 :       backup_char = mValue[minLength-1];
         135            1180 :       mValue.SetCharAt('x', minLength-1);
         136                 :     }
         137          307770 :     mValue.Trim(trimThese, false, true);
         138          307770 :     if (minLength)
         139            1180 :       mValue.SetCharAt(backup_char, minLength-1);
         140                 :
         141          307770 :     mProps->SetStringProperty(NS_ConvertUTF16toUTF8(mKey), mValue, aOldValue);
         142          307770 :     mSpecialState = eParserSpecial_None;
         143          307770 :     WaitForKey();
         144          307770 :   }
         145                 :
         146            2283 :   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          385485 :   void WaitForKey() {
         169          385485 :     mState = eParserState_AwaitingKey;
         170          385485 :   }
         171                 :
         172          307770 :   void EnterKeyState() {
         173          307770 :     mKey.Truncate();
         174          307770 :     mState = eParserState_Key;
         175          307770 :   }
         176                 :
         177          307770 :   void WaitForValue() {
         178          307770 :     mState = eParserState_AwaitingValue;
         179          307770 :   }
         180                 :
         181          307770 :   void EnterValueState() {
         182          307770 :     mValue.Truncate();
         183          307770 :     mMinLength = 0;
         184          307770 :     mState = eParserState_Value;
         185          307770 :     mSpecialState = eParserSpecial_None;
         186          307770 :   }
         187                 :
         188           77715 :   void EnterCommentState() {
         189           77715 :     mState = eParserState_Comment;
         190           77715 :   }
         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          712871 : inline bool IsWhiteSpace(PRUnichar aChar)
         214                 : {
         215                 :   return (aChar == ' ') || (aChar == '\t') ||
         216          712871 :          (aChar == '\r') || (aChar == '\n');
         217                 : }
         218                 :
         219          394459 : inline bool IsEOL(PRUnichar aChar)
         220                 : {
         221          394459 :   return (aChar == '\r') || (aChar == '\n');
         222                 : }
         223                 :
         224                 :
         225         9868319 : bool nsPropertiesParser::ParseValueCharacter(
         226                 :     PRUnichar c, const PRUnichar* cur, const PRUnichar* &tokenStart,
         227                 :     nsAString& oldValue)
         228                 : {
         229         9868319 :   switch (mSpecialState) {
         230                 :
         231                 :     // the normal state - look for special characters
         232                 :   case eParserSpecial_None:
         233         9865157 :     switch (c) {
         234                 :     case '\\':
         235            2989 :       if (mHaveMultiLine)
         236                 :         // there is nothing to append to mValue yet
         237               1 :         mHaveMultiLine = false;
         238                 :       else
         239            2988 :         mValue += Substring(tokenStart, cur);
         240                 :
         241            2989 :       mSpecialState = eParserSpecial_Escaped;
         242            2989 :       break;
         243                 :
         244                 :     case '\n':
         245                 :       // if we detected multiline and got only "\\\r" ignore next "\n" if any
         246          306409 :       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          306410 :       mValue += Substring(tokenStart, cur);
         261          306410 :       FinishValueState(oldValue);
         262          306410 :       mHaveMultiLine = false;
         263          306410 :       break;
         264                 :
         265                 :     default:
         266                 :       // there is nothing to do with normal characters,
         267                 :       // but handle multilines correctly
         268         9555757 :       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         9555749 :       break; // from switch on (c)
         283                 :     }
         284         9865157 :     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            2989 :     tokenStart = cur+1;
         291            2989 :     mSpecialState = eParserSpecial_None;
         292                 :
         293            2989 :     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            2936 :       mValue += PRUnichar('\n');
         302            2936 :       mMinLength = mValue.Length();
         303            2936 :       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            2989 :     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         9868317 :   return true;
         372                 : }
         373                 :
         374            6746 : 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            6746 :     static_cast<nsPropertiesParser *>(aClosure);
         383                 :
         384            6746 :   parser->ParseBuffer(aFromSegment, aCount);
         385                 :
         386            6746 :   *aWriteCount = aCount;
         387            6746 :   return NS_OK;
         388                 : }
         389                 :
         390            6746 : nsresult nsPropertiesParser::ParseBuffer(const PRUnichar* aBuffer,
         391                 :                                          PRUint32 aBufferLength)
         392                 : {
         393            6746 :   const PRUnichar* cur = aBuffer;
         394            6746 :   const PRUnichar* end = aBuffer + aBufferLength;
         395                 :
         396                 :   // points to the start/end of the current key or value
         397            6746 :   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            6746 :   if (mState == eParserState_Key ||
         402                 :       mState == eParserState_Value) {
         403            3873 :     tokenStart = aBuffer;
         404                 :   }
         405                 :
         406           13492 :   nsAutoString oldValue;
         407                 :
         408        22661947 :   while (cur != end) {
         409                 :
         410        22648455 :     PRUnichar c = *cur;
         411                 :
         412        22648455 :     switch (mState) {
         413                 :     case eParserState_AwaitingKey:
         414          397487 :       if (c == '#' || c == '!')
         415           77715 :         EnterCommentState();
         416                 :
         417          319772 :       else if (!IsWhiteSpace(c)) {
         418                 :         // not a comment, not whitespace, we must have found a key!
         419          307770 :         EnterKeyState();
         420          307770 :         tokenStart = cur;
         421                 :       }
         422          397487 :       break;
         423                 :
         424                 :     case eParserState_Key:
         425         8629383 :       if (c == '=' || c == ':') {
         426          307770 :         mKey += Substring(tokenStart, cur);
         427          307770 :         WaitForValue();
         428                 :       }
         429         8629383 :       break;
         430                 :
         431                 :     case eParserState_AwaitingValue:
         432          394459 :       if (IsEOL(c)) {
         433                 :         // no value at all! mimic the normal value-ending
         434            1360 :         EnterValueState();
         435            1360 :         FinishValueState(oldValue);
         436                 :       }
         437                 :
         438                 :       // ignore white space leading up to the value
         439          393099 :       else if (!IsWhiteSpace(c)) {
         440          306410 :         tokenStart = cur;
         441          306410 :         EnterValueState();
         442                 :
         443                 :         // make sure to handle this first character
         444          306410 :         if (ParseValueCharacter(c, cur, tokenStart, oldValue))
         445          306410 :           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          306410 :         continue;
         451                 :       }
         452           88049 :       break;
         453                 :
         454                 :     case eParserState_Value:
         455         9561909 :       if (ParseValueCharacter(c, cur, tokenStart, oldValue))
         456         9561907 :         cur++;
         457                 :       // See few lines above for reason of doing this
         458         9561909 :       continue;
         459                 :
         460                 :     case eParserState_Comment:
         461                 :       // stay in this state till we hit EOL
         462         3665217 :       if (c == '\r' || c== '\n')
         463           77715 :         WaitForKey();
         464         3665217 :       break;
         465                 :     }
         466                 :
         467                 :     // finally, advance to the next character
         468        12780136 :     cur++;
         469                 :   }
         470                 :
         471                 :   // if we're still parsing the value and are in eParserSpecial_None, then
         472                 :   // append whatever we have..
         473            6746 :   if (mState == eParserState_Value && tokenStart &&
         474                 :       mSpecialState == eParserSpecial_None) {
         475            1984 :     mValue += Substring(tokenStart, cur);
         476                 :   }
         477                 :   // if we're still parsing the key, then append whatever we have..
         478            4762 :   else if (mState == eParserState_Key && tokenStart) {
         479            1888 :     mKey += Substring(tokenStart, cur);
         480                 :   }
         481                 :
         482            6746 :   return NS_OK;
         483                 : }
         484                 :
         485            2285 : nsPersistentProperties::nsPersistentProperties()
         486            2285 : : mIn(nsnull)
         487                 : {
         488            2285 :   mSubclass = static_cast<nsIPersistentProperties*>(this);
         489            2285 :   mTable.ops = nsnull;
         490            2285 :   PL_INIT_ARENA_POOL(&mArena, "PersistentPropertyArena", 2048);
         491            2285 : }
         492                 :
         493            4570 : nsPersistentProperties::~nsPersistentProperties()
         494                 : {
         495            2285 :   PL_FinishArenaPool(&mArena);
         496            2285 :   if (mTable.ops)
         497            2285 :     PL_DHashTableFinish(&mTable);
         498            2285 : }
         499                 :
         500                 : nsresult
         501            2285 : nsPersistentProperties::Init()
         502                 : {
         503            2285 :   if (!PL_DHashTableInit(&mTable, &property_HashTableOps, nsnull,
         504            2285 :                          sizeof(PropertyTableEntry), 20)) {
         505               0 :     mTable.ops = nsnull;
         506               0 :     return NS_ERROR_OUT_OF_MEMORY;
         507                 :   }
         508            2285 :   return NS_OK;
         509                 : }
         510                 :
         511                 : nsresult
         512            2285 : nsPersistentProperties::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
         513                 : {
         514            2285 :   if (aOuter)
         515               0 :     return NS_ERROR_NO_AGGREGATION;
         516            2285 :   nsPersistentProperties* props = new nsPersistentProperties();
         517            2285 :   if (props == nsnull)
         518               0 :     return NS_ERROR_OUT_OF_MEMORY;
         519                 :
         520            2285 :   NS_ADDREF(props);
         521            2285 :   nsresult rv = props->Init();
         522            2285 :   if (NS_SUCCEEDED(rv))
         523            2285 :     rv = props->QueryInterface(aIID, aResult);
         524                 :
         525            2285 :   NS_RELEASE(props);
         526            2285 :   return rv;
         527                 : }
         528                 :
         529           20583 : NS_IMPL_THREADSAFE_ISUPPORTS2(nsPersistentProperties, nsIPersistentProperties, nsIProperties)
         530                 :
         531                 : NS_IMETHODIMP
         532            2285 : nsPersistentProperties::Load(nsIInputStream *aIn)
         533                 : {
         534            2285 :   nsresult rv = nsSimpleUnicharStreamFactory::GetInstance()->
         535            2285 :     CreateInstanceFromUTF8Stream(aIn, getter_AddRefs(mIn));
         536                 :
         537            2285 :   if (rv != NS_OK) {
         538               0 :     NS_WARNING("Error creating UnicharInputStream");
         539               0 :     return NS_ERROR_FAILURE;
         540                 :   }
         541                 :
         542            4570 :   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            2285 :   while (NS_SUCCEEDED(rv = mIn->ReadSegments(nsPropertiesParser::SegmentWriter, &parser, 4096, &nProcessed)) &&
         548                 :          nProcessed != 0);
         549            2285 :   mIn = nsnull;
         550            2285 :   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            2283 :   if (parser.GetState() == eParserState_Value) {
         556               0 :     nsAutoString oldValue;
         557               0 :     parser.FinishValueState(oldValue);
         558                 :   }
         559                 :
         560            2283 :   return NS_OK;
         561                 : }
         562                 :
         563                 : NS_IMETHODIMP
         564          307770 : nsPersistentProperties::SetStringProperty(const nsACString& aKey,
         565                 :                                           const nsAString& aNewValue,
         566                 :                                           nsAString& aOldValue)
         567                 : {
         568          615540 :   const nsAFlatCString&  flatKey = PromiseFlatCString(aKey);
         569                 :   PropertyTableEntry *entry =
         570                 :     static_cast<PropertyTableEntry*>
         571          307770 :                (PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_ADD));
         572                 :
         573          307770 :   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          307768 :     aOldValue.Truncate();
         581                 :   }
         582                 :
         583          307770 :   entry->mKey = ArenaStrdup(flatKey, &mArena);
         584          307770 :   entry->mValue = ArenaStrdup(PromiseFlatString(aNewValue), &mArena);
         585                 :
         586          307770 :   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           23059 : nsPersistentProperties::GetStringProperty(const nsACString& aKey,
         607                 :                                           nsAString& aValue)
         608                 : {
         609           46118 :   const nsAFlatCString&  flatKey = PromiseFlatCString(aKey);
         610                 :
         611                 :   PropertyTableEntry *entry =
         612                 :     static_cast<PropertyTableEntry*>
         613           23059 :                (PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_LOOKUP));
         614                 :
         615           23059 :   if (PL_DHASH_ENTRY_IS_FREE(entry))
         616           15882 :     return NS_ERROR_FAILURE;
         617                 :
         618            7177 :   aValue = entry->mValue;
         619            7177 :   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