1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/ds/nsPersistentProperties.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,683 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsArrayEnumerator.h" 1.10 +#include "nsID.h" 1.11 +#include "nsCOMArray.h" 1.12 +#include "nsUnicharInputStream.h" 1.13 +#include "nsPrintfCString.h" 1.14 +#include "nsAutoPtr.h" 1.15 + 1.16 +#define PL_ARENA_CONST_ALIGN_MASK 3 1.17 +#include "nsPersistentProperties.h" 1.18 +#include "nsIProperties.h" 1.19 + 1.20 +struct PropertyTableEntry : public PLDHashEntryHdr 1.21 +{ 1.22 + // both of these are arena-allocated 1.23 + const char *mKey; 1.24 + const char16_t *mValue; 1.25 +}; 1.26 + 1.27 +static char16_t* 1.28 +ArenaStrdup(const nsAFlatString& aString, PLArenaPool* aArena) 1.29 +{ 1.30 + void *mem; 1.31 + // add one to include the null terminator 1.32 + int32_t len = (aString.Length()+1) * sizeof(char16_t); 1.33 + PL_ARENA_ALLOCATE(mem, aArena, len); 1.34 + NS_ASSERTION(mem, "Couldn't allocate space!\n"); 1.35 + if (mem) { 1.36 + memcpy(mem, aString.get(), len); 1.37 + } 1.38 + return static_cast<char16_t*>(mem); 1.39 +} 1.40 + 1.41 +static char* 1.42 +ArenaStrdup(const nsAFlatCString& aString, PLArenaPool* aArena) 1.43 +{ 1.44 + void *mem; 1.45 + // add one to include the null terminator 1.46 + int32_t len = (aString.Length()+1) * sizeof(char); 1.47 + PL_ARENA_ALLOCATE(mem, aArena, len); 1.48 + NS_ASSERTION(mem, "Couldn't allocate space!\n"); 1.49 + if (mem) 1.50 + memcpy(mem, aString.get(), len); 1.51 + return static_cast<char*>(mem); 1.52 +} 1.53 + 1.54 +static const struct PLDHashTableOps property_HashTableOps = { 1.55 + PL_DHashAllocTable, 1.56 + PL_DHashFreeTable, 1.57 + PL_DHashStringKey, 1.58 + PL_DHashMatchStringKey, 1.59 + PL_DHashMoveEntryStub, 1.60 + PL_DHashClearEntryStub, 1.61 + PL_DHashFinalizeStub, 1.62 + nullptr, 1.63 +}; 1.64 + 1.65 +// 1.66 +// parser stuff 1.67 +// 1.68 +enum EParserState { 1.69 + eParserState_AwaitingKey, 1.70 + eParserState_Key, 1.71 + eParserState_AwaitingValue, 1.72 + eParserState_Value, 1.73 + eParserState_Comment 1.74 +}; 1.75 + 1.76 +enum EParserSpecial { 1.77 + eParserSpecial_None, // not parsing a special character 1.78 + eParserSpecial_Escaped, // awaiting a special character 1.79 + eParserSpecial_Unicode // parsing a \Uxxx value 1.80 +}; 1.81 + 1.82 +class nsPropertiesParser 1.83 +{ 1.84 +public: 1.85 + nsPropertiesParser(nsIPersistentProperties* aProps) : 1.86 + mHaveMultiLine(false), mState(eParserState_AwaitingKey), 1.87 + mProps(aProps) {} 1.88 + 1.89 + void FinishValueState(nsAString& aOldValue) { 1.90 + static const char trimThese[] = " \t"; 1.91 + mKey.Trim(trimThese, false, true); 1.92 + 1.93 + // This is really ugly hack but it should be fast 1.94 + char16_t backup_char; 1.95 + uint32_t minLength = mMinLength; 1.96 + if (minLength) 1.97 + { 1.98 + backup_char = mValue[minLength-1]; 1.99 + mValue.SetCharAt('x', minLength-1); 1.100 + } 1.101 + mValue.Trim(trimThese, false, true); 1.102 + if (minLength) 1.103 + mValue.SetCharAt(backup_char, minLength-1); 1.104 + 1.105 + mProps->SetStringProperty(NS_ConvertUTF16toUTF8(mKey), mValue, aOldValue); 1.106 + mSpecialState = eParserSpecial_None; 1.107 + WaitForKey(); 1.108 + } 1.109 + 1.110 + EParserState GetState() { return mState; } 1.111 + 1.112 + static NS_METHOD SegmentWriter(nsIUnicharInputStream* aStream, 1.113 + void* aClosure, 1.114 + const char16_t *aFromSegment, 1.115 + uint32_t aToOffset, 1.116 + uint32_t aCount, 1.117 + uint32_t *aWriteCount); 1.118 + 1.119 + nsresult ParseBuffer(const char16_t* aBuffer, uint32_t aBufferLength); 1.120 + 1.121 +private: 1.122 + bool ParseValueCharacter( 1.123 + char16_t c, // character that is just being parsed 1.124 + const char16_t* cur, // pointer to character c in the buffer 1.125 + const char16_t* &tokenStart, // string copying is done in blocks as big as 1.126 + // possible, tokenStart points to the beginning 1.127 + // of this block 1.128 + nsAString& oldValue); // when duplicate property is found, new value 1.129 + // is stored into hashtable and the old one is 1.130 + // placed in this variable 1.131 + 1.132 + void WaitForKey() { 1.133 + mState = eParserState_AwaitingKey; 1.134 + } 1.135 + 1.136 + void EnterKeyState() { 1.137 + mKey.Truncate(); 1.138 + mState = eParserState_Key; 1.139 + } 1.140 + 1.141 + void WaitForValue() { 1.142 + mState = eParserState_AwaitingValue; 1.143 + } 1.144 + 1.145 + void EnterValueState() { 1.146 + mValue.Truncate(); 1.147 + mMinLength = 0; 1.148 + mState = eParserState_Value; 1.149 + mSpecialState = eParserSpecial_None; 1.150 + } 1.151 + 1.152 + void EnterCommentState() { 1.153 + mState = eParserState_Comment; 1.154 + } 1.155 + 1.156 + nsAutoString mKey; 1.157 + nsAutoString mValue; 1.158 + 1.159 + uint32_t mUnicodeValuesRead; // should be 4! 1.160 + char16_t mUnicodeValue; // currently parsed unicode value 1.161 + bool mHaveMultiLine; // is TRUE when last processed characters form 1.162 + // any of following sequences: 1.163 + // - "\\\r" 1.164 + // - "\\\n" 1.165 + // - "\\\r\n" 1.166 + // - any sequence above followed by any 1.167 + // combination of ' ' and '\t' 1.168 + bool mMultiLineCanSkipN; // TRUE if "\\\r" was detected 1.169 + uint32_t mMinLength; // limit right trimming at the end to not trim 1.170 + // escaped whitespaces 1.171 + EParserState mState; 1.172 + // if we see a '\' then we enter this special state 1.173 + EParserSpecial mSpecialState; 1.174 + nsIPersistentProperties* mProps; 1.175 +}; 1.176 + 1.177 +inline bool IsWhiteSpace(char16_t aChar) 1.178 +{ 1.179 + return (aChar == ' ') || (aChar == '\t') || 1.180 + (aChar == '\r') || (aChar == '\n'); 1.181 +} 1.182 + 1.183 +inline bool IsEOL(char16_t aChar) 1.184 +{ 1.185 + return (aChar == '\r') || (aChar == '\n'); 1.186 +} 1.187 + 1.188 + 1.189 +bool nsPropertiesParser::ParseValueCharacter( 1.190 + char16_t c, const char16_t* cur, const char16_t* &tokenStart, 1.191 + nsAString& oldValue) 1.192 +{ 1.193 + switch (mSpecialState) { 1.194 + 1.195 + // the normal state - look for special characters 1.196 + case eParserSpecial_None: 1.197 + switch (c) { 1.198 + case '\\': 1.199 + if (mHaveMultiLine) 1.200 + // there is nothing to append to mValue yet 1.201 + mHaveMultiLine = false; 1.202 + else 1.203 + mValue += Substring(tokenStart, cur); 1.204 + 1.205 + mSpecialState = eParserSpecial_Escaped; 1.206 + break; 1.207 + 1.208 + case '\n': 1.209 + // if we detected multiline and got only "\\\r" ignore next "\n" if any 1.210 + if (mHaveMultiLine && mMultiLineCanSkipN) { 1.211 + // but don't allow another '\n' to be skipped 1.212 + mMultiLineCanSkipN = false; 1.213 + // Now there is nothing to append to the mValue since we are skipping 1.214 + // whitespaces at the beginning of the new line of the multiline 1.215 + // property. Set tokenStart properly to ensure that nothing is appended 1.216 + // if we find regular line-end or the end of the buffer. 1.217 + tokenStart = cur+1; 1.218 + break; 1.219 + } 1.220 + // no break 1.221 + 1.222 + case '\r': 1.223 + // we're done! We have a key and value 1.224 + mValue += Substring(tokenStart, cur); 1.225 + FinishValueState(oldValue); 1.226 + mHaveMultiLine = false; 1.227 + break; 1.228 + 1.229 + default: 1.230 + // there is nothing to do with normal characters, 1.231 + // but handle multilines correctly 1.232 + if (mHaveMultiLine) { 1.233 + if (c == ' ' || c == '\t') { 1.234 + // don't allow another '\n' to be skipped 1.235 + mMultiLineCanSkipN = false; 1.236 + // Now there is nothing to append to the mValue since we are skipping 1.237 + // whitespaces at the beginning of the new line of the multiline 1.238 + // property. Set tokenStart properly to ensure that nothing is appended 1.239 + // if we find regular line-end or the end of the buffer. 1.240 + tokenStart = cur+1; 1.241 + break; 1.242 + } 1.243 + mHaveMultiLine = false; 1.244 + tokenStart = cur; 1.245 + } 1.246 + break; // from switch on (c) 1.247 + } 1.248 + break; // from switch on (mSpecialState) 1.249 + 1.250 + // saw a \ character, so parse the character after that 1.251 + case eParserSpecial_Escaped: 1.252 + // probably want to start parsing at the next token 1.253 + // other characters, like 'u' might override this 1.254 + tokenStart = cur+1; 1.255 + mSpecialState = eParserSpecial_None; 1.256 + 1.257 + switch (c) { 1.258 + 1.259 + // the easy characters - \t, \n, and so forth 1.260 + case 't': 1.261 + mValue += char16_t('\t'); 1.262 + mMinLength = mValue.Length(); 1.263 + break; 1.264 + case 'n': 1.265 + mValue += char16_t('\n'); 1.266 + mMinLength = mValue.Length(); 1.267 + break; 1.268 + case 'r': 1.269 + mValue += char16_t('\r'); 1.270 + mMinLength = mValue.Length(); 1.271 + break; 1.272 + case '\\': 1.273 + mValue += char16_t('\\'); 1.274 + break; 1.275 + 1.276 + // switch to unicode mode! 1.277 + case 'u': 1.278 + case 'U': 1.279 + mSpecialState = eParserSpecial_Unicode; 1.280 + mUnicodeValuesRead = 0; 1.281 + mUnicodeValue = 0; 1.282 + break; 1.283 + 1.284 + // a \ immediately followed by a newline means we're going multiline 1.285 + case '\r': 1.286 + case '\n': 1.287 + mHaveMultiLine = true; 1.288 + mMultiLineCanSkipN = (c == '\r'); 1.289 + mSpecialState = eParserSpecial_None; 1.290 + break; 1.291 + 1.292 + default: 1.293 + // don't recognize the character, so just append it 1.294 + mValue += c; 1.295 + break; 1.296 + } 1.297 + break; 1.298 + 1.299 + // we're in the middle of parsing a 4-character unicode value 1.300 + // like \u5f39 1.301 + case eParserSpecial_Unicode: 1.302 + 1.303 + if(('0' <= c) && (c <= '9')) 1.304 + mUnicodeValue = 1.305 + (mUnicodeValue << 4) | (c - '0'); 1.306 + else if(('a' <= c) && (c <= 'f')) 1.307 + mUnicodeValue = 1.308 + (mUnicodeValue << 4) | (c - 'a' + 0x0a); 1.309 + else if(('A' <= c) && (c <= 'F')) 1.310 + mUnicodeValue = 1.311 + (mUnicodeValue << 4) | (c - 'A' + 0x0a); 1.312 + else { 1.313 + // non-hex character. Append what we have, and move on. 1.314 + mValue += mUnicodeValue; 1.315 + mMinLength = mValue.Length(); 1.316 + mSpecialState = eParserSpecial_None; 1.317 + 1.318 + // leave tokenStart at this unknown character, so it gets appended 1.319 + tokenStart = cur; 1.320 + 1.321 + // ensure parsing this non-hex character again 1.322 + return false; 1.323 + } 1.324 + 1.325 + if (++mUnicodeValuesRead >= 4) { 1.326 + tokenStart = cur+1; 1.327 + mSpecialState = eParserSpecial_None; 1.328 + mValue += mUnicodeValue; 1.329 + mMinLength = mValue.Length(); 1.330 + } 1.331 + 1.332 + break; 1.333 + } 1.334 + 1.335 + return true; 1.336 +} 1.337 + 1.338 +NS_METHOD nsPropertiesParser::SegmentWriter(nsIUnicharInputStream* aStream, 1.339 + void* aClosure, 1.340 + const char16_t *aFromSegment, 1.341 + uint32_t aToOffset, 1.342 + uint32_t aCount, 1.343 + uint32_t *aWriteCount) 1.344 +{ 1.345 + nsPropertiesParser *parser = 1.346 + static_cast<nsPropertiesParser *>(aClosure); 1.347 + 1.348 + parser->ParseBuffer(aFromSegment, aCount); 1.349 + 1.350 + *aWriteCount = aCount; 1.351 + return NS_OK; 1.352 +} 1.353 + 1.354 +nsresult nsPropertiesParser::ParseBuffer(const char16_t* aBuffer, 1.355 + uint32_t aBufferLength) 1.356 +{ 1.357 + const char16_t* cur = aBuffer; 1.358 + const char16_t* end = aBuffer + aBufferLength; 1.359 + 1.360 + // points to the start/end of the current key or value 1.361 + const char16_t* tokenStart = nullptr; 1.362 + 1.363 + // if we're in the middle of parsing a key or value, make sure 1.364 + // the current token points to the beginning of the current buffer 1.365 + if (mState == eParserState_Key || 1.366 + mState == eParserState_Value) { 1.367 + tokenStart = aBuffer; 1.368 + } 1.369 + 1.370 + nsAutoString oldValue; 1.371 + 1.372 + while (cur != end) { 1.373 + 1.374 + char16_t c = *cur; 1.375 + 1.376 + switch (mState) { 1.377 + case eParserState_AwaitingKey: 1.378 + if (c == '#' || c == '!') 1.379 + EnterCommentState(); 1.380 + 1.381 + else if (!IsWhiteSpace(c)) { 1.382 + // not a comment, not whitespace, we must have found a key! 1.383 + EnterKeyState(); 1.384 + tokenStart = cur; 1.385 + } 1.386 + break; 1.387 + 1.388 + case eParserState_Key: 1.389 + if (c == '=' || c == ':') { 1.390 + mKey += Substring(tokenStart, cur); 1.391 + WaitForValue(); 1.392 + } 1.393 + break; 1.394 + 1.395 + case eParserState_AwaitingValue: 1.396 + if (IsEOL(c)) { 1.397 + // no value at all! mimic the normal value-ending 1.398 + EnterValueState(); 1.399 + FinishValueState(oldValue); 1.400 + } 1.401 + 1.402 + // ignore white space leading up to the value 1.403 + else if (!IsWhiteSpace(c)) { 1.404 + tokenStart = cur; 1.405 + EnterValueState(); 1.406 + 1.407 + // make sure to handle this first character 1.408 + if (ParseValueCharacter(c, cur, tokenStart, oldValue)) 1.409 + cur++; 1.410 + // If the character isn't consumed, don't do cur++ and parse 1.411 + // the character again. This can happen f.e. for char 'X' in sequence 1.412 + // "\u00X". This character can be control character and must be 1.413 + // processed again. 1.414 + continue; 1.415 + } 1.416 + break; 1.417 + 1.418 + case eParserState_Value: 1.419 + if (ParseValueCharacter(c, cur, tokenStart, oldValue)) 1.420 + cur++; 1.421 + // See few lines above for reason of doing this 1.422 + continue; 1.423 + 1.424 + case eParserState_Comment: 1.425 + // stay in this state till we hit EOL 1.426 + if (c == '\r' || c== '\n') 1.427 + WaitForKey(); 1.428 + break; 1.429 + } 1.430 + 1.431 + // finally, advance to the next character 1.432 + cur++; 1.433 + } 1.434 + 1.435 + // if we're still parsing the value and are in eParserSpecial_None, then 1.436 + // append whatever we have.. 1.437 + if (mState == eParserState_Value && tokenStart && 1.438 + mSpecialState == eParserSpecial_None) { 1.439 + mValue += Substring(tokenStart, cur); 1.440 + } 1.441 + // if we're still parsing the key, then append whatever we have.. 1.442 + else if (mState == eParserState_Key && tokenStart) { 1.443 + mKey += Substring(tokenStart, cur); 1.444 + } 1.445 + 1.446 + return NS_OK; 1.447 +} 1.448 + 1.449 +nsPersistentProperties::nsPersistentProperties() 1.450 +: mIn(nullptr) 1.451 +{ 1.452 + mSubclass = static_cast<nsIPersistentProperties*>(this); 1.453 + 1.454 + PL_DHashTableInit(&mTable, &property_HashTableOps, nullptr, 1.455 + sizeof(PropertyTableEntry), 20); 1.456 + 1.457 + PL_INIT_ARENA_POOL(&mArena, "PersistentPropertyArena", 2048); 1.458 +} 1.459 + 1.460 +nsPersistentProperties::~nsPersistentProperties() 1.461 +{ 1.462 + PL_FinishArenaPool(&mArena); 1.463 + if (mTable.ops) 1.464 + PL_DHashTableFinish(&mTable); 1.465 +} 1.466 + 1.467 +nsresult 1.468 +nsPersistentProperties::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) 1.469 +{ 1.470 + if (aOuter) 1.471 + return NS_ERROR_NO_AGGREGATION; 1.472 + nsRefPtr<nsPersistentProperties> props = new nsPersistentProperties(); 1.473 + return props->QueryInterface(aIID, aResult); 1.474 +} 1.475 + 1.476 +NS_IMPL_ISUPPORTS(nsPersistentProperties, nsIPersistentProperties, nsIProperties) 1.477 + 1.478 +NS_IMETHODIMP 1.479 +nsPersistentProperties::Load(nsIInputStream *aIn) 1.480 +{ 1.481 + nsresult rv = nsSimpleUnicharStreamFactory::GetInstance()-> 1.482 + CreateInstanceFromUTF8Stream(aIn, getter_AddRefs(mIn)); 1.483 + 1.484 + if (rv != NS_OK) { 1.485 + NS_WARNING("Error creating UnicharInputStream"); 1.486 + return NS_ERROR_FAILURE; 1.487 + } 1.488 + 1.489 + nsPropertiesParser parser(mSubclass); 1.490 + 1.491 + uint32_t nProcessed; 1.492 + // If this 4096 is changed to some other value, make sure to adjust 1.493 + // the bug121341.properties test file accordingly. 1.494 + while (NS_SUCCEEDED(rv = mIn->ReadSegments(nsPropertiesParser::SegmentWriter, &parser, 4096, &nProcessed)) && 1.495 + nProcessed != 0); 1.496 + mIn = nullptr; 1.497 + if (NS_FAILED(rv)) 1.498 + return rv; 1.499 + 1.500 + // We may have an unprocessed value at this point 1.501 + // if the last line did not have a proper line ending. 1.502 + if (parser.GetState() == eParserState_Value) { 1.503 + nsAutoString oldValue; 1.504 + parser.FinishValueState(oldValue); 1.505 + } 1.506 + 1.507 + return NS_OK; 1.508 +} 1.509 + 1.510 +NS_IMETHODIMP 1.511 +nsPersistentProperties::SetStringProperty(const nsACString& aKey, 1.512 + const nsAString& aNewValue, 1.513 + nsAString& aOldValue) 1.514 +{ 1.515 + const nsAFlatCString& flatKey = PromiseFlatCString(aKey); 1.516 + PropertyTableEntry *entry = 1.517 + static_cast<PropertyTableEntry*> 1.518 + (PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_ADD)); 1.519 + 1.520 + if (entry->mKey) { 1.521 + aOldValue = entry->mValue; 1.522 + NS_WARNING(nsPrintfCString("the property %s already exists\n", 1.523 + flatKey.get()).get()); 1.524 + } 1.525 + else { 1.526 + aOldValue.Truncate(); 1.527 + } 1.528 + 1.529 + entry->mKey = ArenaStrdup(flatKey, &mArena); 1.530 + entry->mValue = ArenaStrdup(PromiseFlatString(aNewValue), &mArena); 1.531 + 1.532 + return NS_OK; 1.533 +} 1.534 + 1.535 +NS_IMETHODIMP 1.536 +nsPersistentProperties::Save(nsIOutputStream* aOut, const nsACString& aHeader) 1.537 +{ 1.538 + return NS_ERROR_NOT_IMPLEMENTED; 1.539 +} 1.540 + 1.541 +NS_IMETHODIMP 1.542 +nsPersistentProperties::Subclass(nsIPersistentProperties* aSubclass) 1.543 +{ 1.544 + if (aSubclass) { 1.545 + mSubclass = aSubclass; 1.546 + } 1.547 + 1.548 + return NS_OK; 1.549 +} 1.550 + 1.551 +NS_IMETHODIMP 1.552 +nsPersistentProperties::GetStringProperty(const nsACString& aKey, 1.553 + nsAString& aValue) 1.554 +{ 1.555 + const nsAFlatCString& flatKey = PromiseFlatCString(aKey); 1.556 + 1.557 + PropertyTableEntry *entry = 1.558 + static_cast<PropertyTableEntry*> 1.559 + (PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_LOOKUP)); 1.560 + 1.561 + if (PL_DHASH_ENTRY_IS_FREE(entry)) 1.562 + return NS_ERROR_FAILURE; 1.563 + 1.564 + aValue = entry->mValue; 1.565 + return NS_OK; 1.566 +} 1.567 + 1.568 +static PLDHashOperator 1.569 +AddElemToArray(PLDHashTable* table, PLDHashEntryHdr *hdr, 1.570 + uint32_t i, void *arg) 1.571 +{ 1.572 + nsCOMArray<nsIPropertyElement>* props = 1.573 + static_cast<nsCOMArray<nsIPropertyElement>*>(arg); 1.574 + PropertyTableEntry* entry = 1.575 + static_cast<PropertyTableEntry*>(hdr); 1.576 + 1.577 + nsPropertyElement *element = 1.578 + new nsPropertyElement(nsDependentCString(entry->mKey), 1.579 + nsDependentString(entry->mValue)); 1.580 + 1.581 + props->AppendObject(element); 1.582 + 1.583 + return PL_DHASH_NEXT; 1.584 +} 1.585 + 1.586 + 1.587 +NS_IMETHODIMP 1.588 +nsPersistentProperties::Enumerate(nsISimpleEnumerator** aResult) 1.589 +{ 1.590 + nsCOMArray<nsIPropertyElement> props; 1.591 + 1.592 + // We know the necessary size; we can avoid growing it while adding elements 1.593 + props.SetCapacity(mTable.entryCount); 1.594 + 1.595 + // Step through hash entries populating a transient array 1.596 + uint32_t n = 1.597 + PL_DHashTableEnumerate(&mTable, AddElemToArray, (void *)&props); 1.598 + if (n < mTable.entryCount) 1.599 + return NS_ERROR_OUT_OF_MEMORY; 1.600 + 1.601 + return NS_NewArrayEnumerator(aResult, props); 1.602 +} 1.603 + 1.604 +//////////////////////////////////////////////////////////////////////////////// 1.605 +// XXX Some day we'll unify the nsIPersistentProperties interface with 1.606 +// nsIProperties, but until now... 1.607 + 1.608 +NS_IMETHODIMP 1.609 +nsPersistentProperties::Get(const char* prop, const nsIID & uuid, void* *result) 1.610 +{ 1.611 + return NS_ERROR_NOT_IMPLEMENTED; 1.612 +} 1.613 + 1.614 +NS_IMETHODIMP 1.615 +nsPersistentProperties::Set(const char* prop, nsISupports* value) 1.616 +{ 1.617 + return NS_ERROR_NOT_IMPLEMENTED; 1.618 +} 1.619 +NS_IMETHODIMP 1.620 +nsPersistentProperties::Undefine(const char* prop) 1.621 +{ 1.622 + return NS_ERROR_NOT_IMPLEMENTED; 1.623 +} 1.624 + 1.625 +NS_IMETHODIMP 1.626 +nsPersistentProperties::Has(const char* prop, bool *result) 1.627 +{ 1.628 + PropertyTableEntry *entry = 1.629 + static_cast<PropertyTableEntry*> 1.630 + (PL_DHashTableOperate(&mTable, prop, PL_DHASH_LOOKUP)); 1.631 + 1.632 + *result = (entry && PL_DHASH_ENTRY_IS_BUSY(entry)); 1.633 + 1.634 + return NS_OK; 1.635 +} 1.636 + 1.637 +NS_IMETHODIMP 1.638 +nsPersistentProperties::GetKeys(uint32_t *count, char ***keys) 1.639 +{ 1.640 + return NS_ERROR_NOT_IMPLEMENTED; 1.641 +} 1.642 + 1.643 +//////////////////////////////////////////////////////////////////////////////// 1.644 +// PropertyElement 1.645 +//////////////////////////////////////////////////////////////////////////////// 1.646 + 1.647 +NS_METHOD 1.648 +nsPropertyElement::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) 1.649 +{ 1.650 + if (aOuter) 1.651 + return NS_ERROR_NO_AGGREGATION; 1.652 + nsRefPtr<nsPropertyElement> propElem = new nsPropertyElement(); 1.653 + return propElem->QueryInterface(aIID, aResult); 1.654 +} 1.655 + 1.656 +NS_IMPL_ISUPPORTS(nsPropertyElement, nsIPropertyElement) 1.657 + 1.658 +NS_IMETHODIMP 1.659 +nsPropertyElement::GetKey(nsACString& aReturnKey) 1.660 +{ 1.661 + aReturnKey = mKey; 1.662 + return NS_OK; 1.663 +} 1.664 + 1.665 +NS_IMETHODIMP 1.666 +nsPropertyElement::GetValue(nsAString& aReturnValue) 1.667 +{ 1.668 + aReturnValue = mValue; 1.669 + return NS_OK; 1.670 +} 1.671 + 1.672 +NS_IMETHODIMP 1.673 +nsPropertyElement::SetKey(const nsACString& aKey) 1.674 +{ 1.675 + mKey = aKey; 1.676 + return NS_OK; 1.677 +} 1.678 + 1.679 +NS_IMETHODIMP 1.680 +nsPropertyElement::SetValue(const nsAString& aValue) 1.681 +{ 1.682 + mValue = aValue; 1.683 + return NS_OK; 1.684 +} 1.685 + 1.686 +////////////////////////////////////////////////////////////////////////////////