xpcom/ds/nsPersistentProperties.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial