VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.cpp@ 4837

Last change on this file since 4837 was 1, checked in by vboxsync, 54 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.6 KB
Line 
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 "nsIUnicharInputStream.h"
44#include "pratom.h"
45#include "nsEnumeratorUtils.h"
46#include "nsReadableUtils.h"
47#include "nsPrintfCString.h"
48
49#define PL_ARENA_CONST_ALIGN_MASK 3
50#include "nsPersistentProperties.h"
51#include "nsIProperties.h"
52#include "nsProperties.h"
53
54struct PropertyTableEntry : public PLDHashEntryHdr
55{
56 // both of these are arena-allocated
57 const char *mKey;
58 const PRUnichar *mValue;
59};
60
61static PRUnichar*
62ArenaStrdup(const nsAFlatString& aString, PLArenaPool* aArena)
63{
64 void *mem;
65 // add one to include the null terminator
66 PRInt32 len = (aString.Length()+1) * sizeof(PRUnichar);
67 PL_ARENA_ALLOCATE(mem, aArena, len);
68 NS_ASSERTION(mem, "Couldn't allocate space!\n");
69 if (mem) {
70 memcpy(mem, aString.get(), len);
71 }
72 return NS_STATIC_CAST(PRUnichar*, mem);
73}
74
75static char*
76ArenaStrdup(const nsAFlatCString& aString, PLArenaPool* aArena)
77{
78 void *mem;
79 // add one to include the null terminator
80 PRInt32 len = (aString.Length()+1) * sizeof(char);
81 PL_ARENA_ALLOCATE(mem, aArena, len);
82 NS_ASSERTION(mem, "Couldn't allocate space!\n");
83 if (mem)
84 memcpy(mem, aString.get(), len);
85 return NS_STATIC_CAST(char*, mem);
86}
87
88static const struct PLDHashTableOps property_HashTableOps = {
89 PL_DHashAllocTable,
90 PL_DHashFreeTable,
91 PL_DHashGetKeyStub,
92 PL_DHashStringKey,
93 PL_DHashMatchStringKey,
94 PL_DHashMoveEntryStub,
95 PL_DHashClearEntryStub,
96 PL_DHashFinalizeStub,
97 nsnull,
98};
99
100nsPersistentProperties::nsPersistentProperties()
101: mIn(nsnull)
102{
103 mSubclass = NS_STATIC_CAST(nsIPersistentProperties*, this);
104 mTable.ops = nsnull;
105 PL_INIT_ARENA_POOL(&mArena, "PersistentPropertyArena", 2048);
106}
107
108nsPersistentProperties::~nsPersistentProperties()
109{
110 PL_FinishArenaPool(&mArena);
111 if (mTable.ops)
112 PL_DHashTableFinish(&mTable);
113}
114
115nsresult
116nsPersistentProperties::Init()
117{
118 if (!PL_DHashTableInit(&mTable, &property_HashTableOps, nsnull,
119 sizeof(PropertyTableEntry), 20)) {
120 mTable.ops = nsnull;
121 return NS_ERROR_OUT_OF_MEMORY;
122 }
123 return NS_OK;
124}
125
126NS_METHOD
127nsPersistentProperties::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
128{
129 if (aOuter)
130 return NS_ERROR_NO_AGGREGATION;
131 nsPersistentProperties* props = new nsPersistentProperties();
132 if (props == nsnull)
133 return NS_ERROR_OUT_OF_MEMORY;
134
135 NS_ADDREF(props);
136 nsresult rv = props->Init();
137 if (NS_SUCCEEDED(rv))
138 rv = props->QueryInterface(aIID, aResult);
139
140 NS_RELEASE(props);
141 return rv;
142}
143
144NS_IMPL_THREADSAFE_ISUPPORTS2(nsPersistentProperties, nsIPersistentProperties, nsIProperties)
145
146NS_IMETHODIMP
147nsPersistentProperties::Load(nsIInputStream *aIn)
148{
149 PRInt32 c;
150 nsresult ret = NS_NewUTF8ConverterStream(&mIn, aIn, 0);
151
152 if (ret != NS_OK) {
153 NS_WARNING("NS_NewUTF8ConverterStream failed");
154 return NS_ERROR_FAILURE;
155 }
156 c = Read();
157 while (1) {
158 c = SkipWhiteSpace(c);
159 if (c < 0) {
160 break;
161 }
162 else if ((c == '#') || (c == '!')) {
163 c = SkipLine(c);
164 continue;
165 }
166 else {
167 nsAutoString key;
168 while ((c >= 0) && (c != '=') && (c != ':')) {
169 key.Append(PRUnichar(c));
170 c = Read();
171 }
172 if (c < 0) {
173 break;
174 }
175 static const char trimThese[] = " \t";
176 key.Trim(trimThese, PR_FALSE, PR_TRUE);
177 c = Read();
178 nsAutoString value;
179 PRUint32 state = 0;
180 PRUnichar uchar = 0;
181 while ((c >= 0) && (c != '\r') && (c != '\n')) {
182 switch(state) {
183 case 0:
184 if (c == '\\') {
185 c = Read();
186 switch(c) {
187 case '\r':
188 case '\n':
189 // Only skip first EOL characters and then next line's
190 // whitespace characters. Skipping all EOL characters
191 // and all upcoming whitespace is too agressive.
192 if (c == '\r')
193 c = Read();
194 if (c == '\n')
195 c = Read();
196 while (c == ' ' || c == '\t')
197 c = Read();
198 continue;
199 case 'u':
200 case 'U':
201 state = 1;
202 uchar=0;
203 break;
204 case 't':
205 value.Append(PRUnichar('\t'));
206 break;
207 case 'n':
208 value.Append(PRUnichar('\n'));
209 break;
210 case 'r':
211 value.Append(PRUnichar('\r'));
212 break;
213 default:
214 value.Append((PRUnichar) c);
215 } // switch(c)
216 } else {
217 value.Append((PRUnichar) c);
218 }
219 c = Read();
220 break;
221 case 1:
222 case 2:
223 case 3:
224 case 4:
225 if (('0' <= c) && (c <= '9')) {
226 uchar = (uchar << 4) | (c - '0');
227 state++;
228 c = Read();
229 } else if (('a' <= c) && (c <= 'f')) {
230 uchar = (uchar << 4) | (c - 'a' + 0x0a);
231 state++;
232 c = Read();
233 } else if (('A' <= c) && (c <= 'F')) {
234 uchar = (uchar << 4) | (c - 'A' + 0x0a);
235 state++;
236 c = Read();
237 } else {
238 value.Append((PRUnichar) uchar);
239 state = 0;
240 }
241 break;
242 case 5:
243 value.Append((PRUnichar) uchar);
244 state = 0;
245 }
246 }
247 if (state != 0) {
248 value.Append((PRUnichar) uchar);
249 state = 0;
250 }
251
252 value.Trim(trimThese, PR_TRUE, PR_TRUE);
253 nsAutoString oldValue;
254 mSubclass->SetStringProperty(NS_ConvertUCS2toUTF8(key), value, oldValue);
255 }
256 }
257 mIn->Close();
258 NS_RELEASE(mIn);
259
260 return NS_OK;
261}
262
263NS_IMETHODIMP
264nsPersistentProperties::SetStringProperty(const nsACString& aKey,
265 const nsAString& aNewValue,
266 nsAString& aOldValue)
267{
268#if 0
269 cout << "will add " << aKey.get() << "=" <<
270 NS_LossyConvertUCS2ToASCII(aNewValue).get() << endl;
271#endif
272
273 const nsAFlatCString& flatKey = PromiseFlatCString(aKey);
274 PropertyTableEntry *entry =
275 NS_STATIC_CAST(PropertyTableEntry*,
276 PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_ADD));
277
278 if (entry->mKey) {
279 aOldValue = entry->mValue;
280 NS_WARNING(nsPrintfCString(aKey.Length() + 30,
281 "the property %s already exists\n",
282 flatKey.get()).get());
283 }
284
285 entry->mKey = ArenaStrdup(flatKey, &mArena);
286 entry->mValue = ArenaStrdup(PromiseFlatString(aNewValue), &mArena);
287
288 return NS_OK;
289}
290
291NS_IMETHODIMP
292nsPersistentProperties::Save(nsIOutputStream* aOut, const nsACString& aHeader)
293{
294 return NS_ERROR_NOT_IMPLEMENTED;
295}
296
297NS_IMETHODIMP
298nsPersistentProperties::Subclass(nsIPersistentProperties* aSubclass)
299{
300 if (aSubclass) {
301 mSubclass = aSubclass;
302 }
303
304 return NS_OK;
305}
306
307NS_IMETHODIMP
308nsPersistentProperties::GetStringProperty(const nsACString& aKey,
309 nsAString& aValue)
310{
311 const nsAFlatCString& flatKey = PromiseFlatCString(aKey);
312
313 PropertyTableEntry *entry =
314 NS_STATIC_CAST(PropertyTableEntry*,
315 PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_LOOKUP));
316
317 if (PL_DHASH_ENTRY_IS_FREE(entry))
318 return NS_ERROR_FAILURE;
319
320 aValue = entry->mValue;
321 return NS_OK;
322}
323
324PR_STATIC_CALLBACK(PLDHashOperator)
325AddElemToArray(PLDHashTable* table, PLDHashEntryHdr *hdr,
326 PRUint32 i, void *arg)
327{
328 nsISupportsArray *propArray = (nsISupportsArray *) arg;
329 PropertyTableEntry* entry =
330 NS_STATIC_CAST(PropertyTableEntry*, hdr);
331
332 nsPropertyElement *element =
333 new nsPropertyElement(nsDependentCString(entry->mKey),
334 nsDependentString(entry->mValue));
335 if (!element)
336 return PL_DHASH_STOP;
337
338 NS_ADDREF(element);
339 propArray->InsertElementAt(element, i);
340
341 return PL_DHASH_NEXT;
342}
343
344
345NS_IMETHODIMP
346nsPersistentProperties::Enumerate(nsISimpleEnumerator** aResult)
347{
348 nsCOMPtr<nsIBidirectionalEnumerator> iterator;
349
350 nsISupportsArray* propArray;
351 nsresult rv = NS_NewISupportsArray(&propArray);
352 if (rv != NS_OK)
353 return rv;
354
355 // Step through hash entries populating a transient array
356 PRUint32 n =
357 PL_DHashTableEnumerate(&mTable, AddElemToArray, (void *)propArray);
358 if (n < mTable.entryCount)
359 return NS_ERROR_OUT_OF_MEMORY;
360
361 return NS_NewArrayEnumerator(aResult, propArray);
362}
363
364
365PRInt32
366nsPersistentProperties::Read()
367{
368 PRUnichar c;
369 PRUint32 nRead;
370 nsresult ret;
371
372 ret = mIn->Read(&c, 1, &nRead);
373 if (ret == NS_OK && nRead == 1) {
374 return c;
375 }
376
377 return -1;
378}
379
380#define IS_WHITE_SPACE(c) \
381 (((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n'))
382
383PRInt32
384nsPersistentProperties::SkipWhiteSpace(PRInt32 c)
385{
386 while (IS_WHITE_SPACE(c)) {
387 c = Read();
388 }
389
390 return c;
391}
392
393PRInt32
394nsPersistentProperties::SkipLine(PRInt32 c)
395{
396 while ((c >= 0) && (c != '\r') && (c != '\n')) {
397 c = Read();
398 }
399 if (c == '\r') {
400 c = Read();
401 }
402 if (c == '\n') {
403 c = Read();
404 }
405
406 return c;
407}
408
409////////////////////////////////////////////////////////////////////////////////
410// XXX Some day we'll unify the nsIPersistentProperties interface with
411// nsIProperties, but until now...
412
413NS_IMETHODIMP
414nsPersistentProperties::Get(const char* prop, const nsIID & uuid, void* *result)
415{
416 return NS_ERROR_NOT_IMPLEMENTED;
417}
418
419NS_IMETHODIMP
420nsPersistentProperties::Set(const char* prop, nsISupports* value)
421{
422 return NS_ERROR_NOT_IMPLEMENTED;
423}
424NS_IMETHODIMP
425nsPersistentProperties::Undefine(const char* prop)
426{
427 return NS_ERROR_NOT_IMPLEMENTED;
428}
429
430NS_IMETHODIMP
431nsPersistentProperties::Has(const char* prop, PRBool *result)
432{
433 return NS_ERROR_NOT_IMPLEMENTED;
434}
435
436NS_IMETHODIMP
437nsPersistentProperties::GetKeys(PRUint32 *count, char ***keys)
438{
439 return NS_ERROR_NOT_IMPLEMENTED;
440}
441
442////////////////////////////////////////////////////////////////////////////////
443// PropertyElement
444////////////////////////////////////////////////////////////////////////////////
445
446
447NS_METHOD
448nsPropertyElement::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
449{
450 if (aOuter)
451 return NS_ERROR_NO_AGGREGATION;
452 nsPropertyElement* propElem = new nsPropertyElement();
453 if (propElem == nsnull)
454 return NS_ERROR_OUT_OF_MEMORY;
455 NS_ADDREF(propElem);
456 nsresult rv = propElem->QueryInterface(aIID, aResult);
457 NS_RELEASE(propElem);
458 return rv;
459}
460
461NS_IMPL_ISUPPORTS1(nsPropertyElement, nsIPropertyElement)
462
463NS_IMETHODIMP
464nsPropertyElement::GetKey(nsACString& aReturnKey)
465{
466 aReturnKey = mKey;
467 return NS_OK;
468}
469
470NS_IMETHODIMP
471nsPropertyElement::GetValue(nsAString& aReturnValue)
472{
473 aReturnValue = mValue;
474 return NS_OK;
475}
476
477NS_IMETHODIMP
478nsPropertyElement::SetKey(const nsACString& aKey)
479{
480 mKey = aKey;
481 return NS_OK;
482}
483
484NS_IMETHODIMP
485nsPropertyElement::SetValue(const nsAString& aValue)
486{
487 mValue = aValue;
488 return NS_OK;
489}
490
491////////////////////////////////////////////////////////////////////////////////
492
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use