source: trunk/third/mozilla/caps/src/nsPrincipal.cpp @ 20014

Revision 20014, 18.9 KB checked in by rbasch, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20013, which included commits to RCS files with non-trunk default branches.
  • Property svn:executable set to *
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) 2003
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *   Christopher A. Aillon <christopher@aillon.com>
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * 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 "nscore.h"
40#include "nsScriptSecurityManager.h"
41#include "nsString.h"
42#include "nsReadableUtils.h"
43#include "plstr.h"
44#include "nsCRT.h"
45#include "nsIURI.h"
46#include "nsNetUtil.h"
47#include "nsJSPrincipals.h"
48#include "nsVoidArray.h"
49#include "nsHashtable.h"
50#include "nsIObjectInputStream.h"
51#include "nsIObjectOutputStream.h"
52
53#include "nsPrincipal.h"
54
55
56// Static member variables
57PRInt32 nsPrincipal::sCapabilitiesOrdinal = 0;
58const char nsPrincipal::sInvalid[] = "Invalid";
59
60
61nsPrincipal::nsPrincipal()
62  : mCapabilities(7),
63    mSecurityPolicy(nsnull)
64{
65}
66
67
68NS_IMPL_QUERY_INTERFACE2_CI(nsPrincipal,
69                            nsIPrincipal,
70                            nsISerializable)
71NS_IMPL_CI_INTERFACE_GETTER2(nsPrincipal,
72                             nsIPrincipal,
73                             nsISerializable)
74
75NS_IMETHODIMP_(nsrefcnt)
76nsPrincipal::AddRef()
77{
78  NS_PRECONDITION(PRInt32(mJSPrincipals.refcount) >= 0, "illegal refcnt");
79  // XXXcaa does this need to be threadsafe?  See bug 143559.
80  nsrefcnt count = PR_AtomicIncrement((PRInt32 *)&mJSPrincipals.refcount);
81  NS_LOG_ADDREF(this, count, "nsPrincipal", sizeof(*this));
82  return count;
83}
84
85NS_IMETHODIMP_(nsrefcnt)
86nsPrincipal::Release()
87{
88  NS_PRECONDITION(0 != mJSPrincipals.refcount, "dup release");
89  nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount);
90  NS_LOG_RELEASE(this, count, "nsPrincipal");
91  if (count == 0) {
92    NS_DELETEXPCOM(this);
93  }
94
95  return count;
96}
97
98nsPrincipal::nsPrincipal(nsIURI *aURI)
99  : mSecurityPolicy(nsnull),
100    mCodebase(aURI)
101{
102}
103
104
105PR_STATIC_CALLBACK(PRBool)
106deleteElement(void* aElement, void *aData)
107{
108  nsHashtable *ht = (nsHashtable *) aElement;
109  delete ht;
110  return PR_TRUE;
111}
112
113nsPrincipal::~nsPrincipal(void)
114{
115  mAnnotations.EnumerateForwards(deleteElement, nsnull);
116}
117
118NS_IMETHODIMP
119nsPrincipal::GetJsPrincipals(JSPrincipals **jsprin)
120{
121  if (!mJSPrincipals.nsIPrincipalPtr) {
122    // Don't addref here, since we are referencing each other.
123    mJSPrincipals.nsIPrincipalPtr = this;
124  }
125
126  *jsprin = &mJSPrincipals;
127
128  // JSPRINCIPALS_HOLD does not use its first argument.
129  // Just use a dummy cx to save the codesize.
130  JSPRINCIPALS_HOLD(cx, *jsprin);
131
132  return NS_OK;
133}
134
135NS_IMETHODIMP
136nsPrincipal::GetOrigin(char **aOrigin)
137{
138  nsIURI* uri = mDomain ? mDomain : mCodebase;
139  NS_ASSERTION(uri, "No Domain or Codebase");
140
141  nsCAutoString hostPort;
142
143  // chrome: URLs don't have a meaningful origin, so make
144  // sure we just get the full spec for them.
145  // XXX this should be removed in favor of the solution in
146  // bug 160042.
147  PRBool isChrome;
148  nsresult rv = uri->SchemeIs("chrome", &isChrome);
149  if (NS_SUCCEEDED(rv) && !isChrome) {
150    rv = uri->GetHostPort(hostPort);
151  }
152
153  if (NS_SUCCEEDED(rv) && !isChrome) {
154    nsCAutoString scheme;
155    rv = uri->GetScheme(scheme);
156    NS_ENSURE_SUCCESS(rv, rv);
157    *aOrigin = ToNewCString(scheme + NS_LITERAL_CSTRING("://") + hostPort);
158  }
159  else {
160    // Some URIs (e.g., nsSimpleURI) don't support host. Just
161    // get the full spec.
162    nsCAutoString spec;
163    rv = uri->GetSpec(spec);
164    NS_ENSURE_SUCCESS(rv, rv);
165    *aOrigin = ToNewCString(spec);
166  }
167
168  return *aOrigin ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
169}
170
171NS_IMETHODIMP
172nsPrincipal::GetSecurityPolicy(void** aSecurityPolicy)
173{
174  *aSecurityPolicy = mSecurityPolicy;
175  return NS_OK;
176}
177
178NS_IMETHODIMP
179nsPrincipal::SetSecurityPolicy(void* aSecurityPolicy)
180{
181  mSecurityPolicy = aSecurityPolicy;
182  return NS_OK;
183}
184
185NS_IMETHODIMP
186nsPrincipal::Equals(nsIPrincipal *aOther, PRBool *aResult)
187{
188  *aResult = PR_FALSE;
189
190  if (!aOther) {
191    NS_WARNING("Need a principal to compare this to!");
192    return NS_OK;
193  }
194
195  if (this != aOther) {
196    if (mCert) {
197      PRBool otherHasCert;
198      aOther->GetHasCertificate(&otherHasCert);
199      if (!otherHasCert) {
200        return NS_OK;
201      }
202
203      nsXPIDLCString otherCertID;
204      aOther->GetCertificateID(getter_Copies(otherCertID));
205      if (!otherCertID.Equals(mCert->certificateID)) {
206        return NS_OK;
207      }
208    }
209
210    // Codebases are equal if they have the same origin.
211    nsIURI *origin = mDomain ? mDomain : mCodebase;
212    nsCOMPtr<nsIURI> otherOrigin;
213    aOther->GetDomain(getter_AddRefs(otherOrigin));
214    if (!otherOrigin) {
215      aOther->GetURI(getter_AddRefs(otherOrigin));
216    }
217
218    return nsScriptSecurityManager::GetScriptSecurityManager()
219           ->SecurityCompareURIs(origin, otherOrigin, aResult);
220  }
221
222  *aResult = PR_TRUE;
223  return NS_OK;
224}
225
226
227NS_IMETHODIMP
228nsPrincipal::CanEnableCapability(const char *capability, PRInt16 *result)
229{
230  // If this principal is marked invalid, can't enable any capabilities
231  nsCStringKey invalidKey(sInvalid);
232  if (mCapabilities.Exists(&invalidKey)) {
233    *result = nsIPrincipal::ENABLE_DENIED;
234
235    return NS_OK;
236  }
237
238  const char *start = capability;
239  *result = nsIPrincipal::ENABLE_GRANTED;
240  for(;;) {
241    const char *space = PL_strchr(start, ' ');
242    PRInt32 len = space ? space - start : strlen(start);
243    nsCAutoString capString(start, len);
244    nsCStringKey key(capString);
245    PRInt16 value = (PRInt16)NS_PTR_TO_INT32(mCapabilities.Get(&key));
246    if (value == 0 || value == nsIPrincipal::ENABLE_UNKNOWN) {
247      // We don't know whether we can enable this capability,
248      // so we should ask the user.
249      value = nsIPrincipal::ENABLE_WITH_USER_PERMISSION;
250    }
251
252    if (value < *result) {
253      *result = value;
254    }
255
256    if (!space) {
257      break;
258    }
259
260    start = space + 1;
261  }
262
263  return NS_OK;
264}
265
266NS_IMETHODIMP
267nsPrincipal::SetCanEnableCapability(const char *capability,
268                                    PRInt16 canEnable)
269{
270  // If this principal is marked invalid, can't enable any capabilities
271
272  nsCStringKey invalidKey(sInvalid);
273  if (mCapabilities.Exists(&invalidKey)) {
274    return NS_OK;
275  }
276
277  if (PL_strcmp(capability, sInvalid) == 0) {
278    mCapabilities.Reset();
279  }
280
281  const char *start = capability;
282  for(;;) {
283    const char *space = PL_strchr(start, ' ');
284    int len = space ? space - start : strlen(start);
285    nsCAutoString capString(start, len);
286    nsCStringKey key(capString);
287    mCapabilities.Put(&key, NS_INT32_TO_PTR(canEnable));
288    if (!space) {
289      break;
290    }
291
292    start = space + 1;
293  }
294
295  return NS_OK;
296}
297
298NS_IMETHODIMP
299nsPrincipal::IsCapabilityEnabled(const char *capability, void *annotation,
300                                 PRBool *result)
301{
302  *result = PR_FALSE;
303  nsHashtable *ht = (nsHashtable *) annotation;
304  if (!ht) {
305    return NS_OK;
306  }
307  const char *start = capability;
308  for(;;) {
309    const char *space = PL_strchr(start, ' ');
310    int len = space ? space - start : strlen(start);
311    nsCAutoString capString(start, len);
312    nsCStringKey key(capString);
313    *result = (ht->Get(&key) == (void *) AnnotationEnabled);
314    if (!*result) {
315      // If any single capability is not enabled, then return false.
316      return NS_OK;
317    }
318
319    if (!space) {
320      return NS_OK;
321    }
322
323    start = space + 1;
324  }
325
326  return NS_OK;
327}
328
329NS_IMETHODIMP
330nsPrincipal::EnableCapability(const char *capability, void **annotation)
331{
332  return SetCapability(capability, annotation, AnnotationEnabled);
333}
334
335NS_IMETHODIMP
336nsPrincipal::DisableCapability(const char *capability, void **annotation)
337{
338  return SetCapability(capability, annotation, AnnotationDisabled);
339}
340
341NS_IMETHODIMP
342nsPrincipal::RevertCapability(const char *capability, void **annotation)
343{
344  if (*annotation) {
345    nsHashtable *ht = (nsHashtable *) *annotation;
346    const char *start = capability;
347    for(;;) {
348      const char *space = PL_strchr(start, ' ');
349      int len = space ? space - start : strlen(start);
350      nsCAutoString capString(start, len);
351      nsCStringKey key(capString);
352      ht->Remove(&key);
353      if (!space) {
354        return NS_OK;
355      }
356
357      start = space + 1;
358    }
359  }
360  return NS_OK;
361}
362
363nsresult
364nsPrincipal::SetCapability(const char *capability, void **annotation,
365                           AnnotationValue value)
366{
367  if (*annotation == nsnull) {
368    *annotation = new nsHashtable(5);
369    if (!*annotation) {
370       return NS_ERROR_OUT_OF_MEMORY;
371     }
372
373    // This object owns its annotations. Save them so we can release
374    // them when we destroy this object.
375    mAnnotations.AppendElement(*annotation);
376  }
377
378  const char *start = capability;
379  for(;;) {
380    const char *space = PL_strchr(start, ' ');
381    int len = space ? space - start : strlen(start);
382    nsCAutoString capString(start, len);
383    nsCStringKey key(capString);
384    nsHashtable *ht = (nsHashtable *) *annotation;
385    ht->Put(&key, (void *) value);
386    if (!space) {
387      break;
388    }
389
390    start = space + 1;
391  }
392
393  return NS_OK;
394}
395
396NS_IMETHODIMP
397nsPrincipal::GetHasCertificate(PRBool* aResult)
398{
399  *aResult = (mCert != nsnull);
400
401  return NS_OK;
402}
403
404NS_IMETHODIMP
405nsPrincipal::GetURI(nsIURI** aURI)
406{
407  NS_IF_ADDREF(*aURI = mCodebase);
408
409  return NS_OK;
410}
411
412NS_IMETHODIMP
413nsPrincipal::SetURI(nsIURI* aURI)
414{
415  mCodebase = aURI;
416  mDomain = nsnull;
417  // Codebase has changed, forget cached security policy
418  mSecurityPolicy = nsnull;
419
420  return NS_OK;
421}
422
423NS_IMETHODIMP
424nsPrincipal::SetCertificateID(const char* aID)
425{
426  if (!aID) {
427    mCert = nsnull;
428    return NS_OK;
429  }
430
431  if (!mCert) {
432    mCert = new Certificate(aID, "");
433    if (!mCert) {
434      return NS_ERROR_OUT_OF_MEMORY;
435    }
436  }
437
438  return NS_OK;
439}
440
441NS_IMETHODIMP
442nsPrincipal::GetCertificateID(char** aID)
443{
444  NS_ENSURE_STATE(mCert);
445
446  *aID = ToNewCString(mCert->certificateID);
447  if (!*aID) {
448    return NS_ERROR_OUT_OF_MEMORY;
449  }
450
451  return NS_OK;
452}
453
454NS_IMETHODIMP
455nsPrincipal::GetCommonName(char** aName)
456{
457  NS_ENSURE_STATE(mCert);
458
459  *aName = ToNewCString(mCert->commonName);
460  if (!*aName) {
461    return NS_ERROR_OUT_OF_MEMORY;
462  }
463
464  return NS_OK;
465}
466
467NS_IMETHODIMP
468nsPrincipal::SetCommonName(const char* aName)
469{
470  if (!mCert) {
471    NS_ERROR("You must first initialize the certificate with an ID");
472    return NS_ERROR_FAILURE;
473  }
474
475  mCert->commonName = aName;
476
477  return NS_OK;
478}
479
480
481NS_IMETHODIMP
482nsPrincipal::GetHashValue(PRUint32* aValue)
483{
484  NS_PRECONDITION(mCert || mCodebase, "Need a cert or codebase");
485
486  // If there is a certificate, it takes precendence over the codebase.
487  if (mCert) {
488    *aValue = nsCRT::HashCode(mCert->certificateID.get(), nsnull);
489  }
490  else {
491    nsCAutoString str;
492    mCodebase->GetSpec(str);
493    *aValue = nsCRT::HashCode(str.get(), nsnull);
494  }
495
496  return NS_OK;
497}
498
499NS_IMETHODIMP
500nsPrincipal::GetDomain(nsIURI** aDomain)
501{
502  NS_IF_ADDREF(*aDomain = mDomain);
503
504  return NS_OK;
505}
506
507NS_IMETHODIMP
508nsPrincipal::SetDomain(nsIURI* aDomain)
509{
510  mDomain = aDomain;
511  // Domain has changed, forget cached security policy
512  mSecurityPolicy = nsnull;
513
514  return NS_OK;
515}
516
517nsresult
518nsPrincipal::InitFromPersistent(const char* aPrefName,
519                                const char* aToken,
520                                const char* aGrantedList,
521                                const char* aDeniedList,
522                                PRBool aIsCert,
523                                PRBool aTrusted)
524{
525  NS_PRECONDITION(mCapabilities.Count() == 0,
526                  "mCapabilities was already initialized?");
527  NS_PRECONDITION(mAnnotations.Count() == 0,
528                  "mAnnotations was already initialized?");
529
530  if (aIsCert) {
531    SetCertificateID(aToken);
532  }
533  else {
534    nsresult rv = NS_NewURI(getter_AddRefs(mCodebase), aToken, nsnull);
535    if (NS_FAILED(rv)) {
536      NS_ERROR("Malformed URI in capability.principal preference.");
537      return rv;
538    }
539
540    nsCAutoString token;
541    rv = mCodebase->GetSpec(token);
542    if (NS_FAILED(rv)) {
543      return rv;
544    }
545
546    rv = mJSPrincipals.Init(PL_strdup(token.get()));
547    if (NS_FAILED(rv)) {
548      return rv;
549    }
550
551    mTrusted = aTrusted;
552  }
553
554  //-- Save the preference name
555  mPrefName = aPrefName;
556
557  const char* ordinalBegin = PL_strpbrk(aPrefName, "1234567890");
558  if (ordinalBegin) {
559    PRIntn n = atoi(ordinalBegin);
560    if (sCapabilitiesOrdinal <= n) {
561      sCapabilitiesOrdinal = n + 1;
562    }
563  }
564
565  //-- Store the capabilities
566  nsresult rv = NS_OK;
567  if (aGrantedList) {
568    rv = SetCanEnableCapability(aGrantedList, nsIPrincipal::ENABLE_GRANTED);
569  }
570
571  if (NS_SUCCEEDED(rv) && aDeniedList) {
572    rv = SetCanEnableCapability(aDeniedList, nsIPrincipal::ENABLE_DENIED);
573  }
574
575  return rv;
576}
577
578struct CapabilityList
579{
580  nsCString* granted;
581  nsCString* denied;
582};
583
584PR_STATIC_CALLBACK(PRBool)
585AppendCapability(nsHashKey *aKey, void *aData, void *capListPtr)
586{
587  CapabilityList* capList = (CapabilityList*)capListPtr;
588  PRInt16 value = (PRInt16)NS_PTR_TO_INT32(aData);
589  nsCStringKey* key = (nsCStringKey *)aKey;
590  if (value == nsIPrincipal::ENABLE_GRANTED) {
591    capList->granted->Append(key->GetString(), key->GetStringLength());
592    capList->granted->Append(' ');
593  }
594  else if (value == nsIPrincipal::ENABLE_DENIED) {
595    capList->denied->Append(key->GetString(), key->GetStringLength());
596    capList->denied->Append(' ');
597  }
598
599  return PR_TRUE;
600}
601
602NS_IMETHODIMP
603nsPrincipal::GetPreferences(char** aPrefName, char** aID,
604                            char** aGrantedList, char** aDeniedList)
605{
606  if (mPrefName.IsEmpty()) {
607    if (mCert) {
608      mPrefName.Assign("capability.principal.certificate.p");
609    }
610    else {
611      mPrefName.Assign("capability.principal.codebase.p");
612    }
613
614    mPrefName.AppendInt(sCapabilitiesOrdinal++);
615    mPrefName.Append(".id");
616  }
617
618  *aPrefName = nsnull;
619  *aID = nsnull;
620  *aGrantedList = nsnull;
621  *aDeniedList = nsnull;
622
623  char *prefName = nsnull;
624  char *id = nsnull;
625  char *granted = nsnull;
626  char *denied = nsnull;
627
628  //-- Preference name
629  prefName = ToNewCString(mPrefName);
630  if (!prefName) {
631    return NS_ERROR_OUT_OF_MEMORY;
632  }
633
634  //-- ID
635  nsresult rv;
636  if (mCert) {
637    rv = GetCertificateID(&id);
638  }
639  else {
640    rv = GetOrigin(&id);
641  }
642
643  if (NS_FAILED(rv)) {
644    nsMemory::Free(prefName);
645    return rv;
646  }
647
648  //-- Capabilities
649  nsCAutoString grantedListStr, deniedListStr;
650  CapabilityList capList = CapabilityList();
651  capList.granted = &grantedListStr;
652  capList.denied = &deniedListStr;
653  mCapabilities.Enumerate(AppendCapability, (void*)&capList);
654
655  if (!grantedListStr.IsEmpty()) {
656    grantedListStr.Truncate(grantedListStr.Length() - 1);
657    granted = ToNewCString(grantedListStr);
658    if (!granted) {
659      nsMemory::Free(prefName);
660      nsMemory::Free(id);
661      return NS_ERROR_OUT_OF_MEMORY;
662    }
663  }
664
665  if (!deniedListStr.IsEmpty()) {
666    deniedListStr.Truncate(deniedListStr.Length() - 1);
667    denied = ToNewCString(deniedListStr);
668    if (!denied) {
669      nsMemory::Free(prefName);
670      nsMemory::Free(id);
671      if (granted) {
672        nsMemory::Free(granted);
673      }
674      return NS_ERROR_OUT_OF_MEMORY;
675    }
676  }
677
678  *aPrefName = prefName;
679  *aID = id;
680  *aGrantedList = granted;
681  *aDeniedList = denied;
682
683  return NS_OK;
684}
685
686PR_STATIC_CALLBACK(nsresult)
687ReadAnnotationEntry(nsIObjectInputStream* aStream, nsHashKey** aKey,
688                    void** aData)
689{
690  nsresult rv;
691  nsCStringKey* key = new nsCStringKey(aStream, &rv);
692  if (NS_FAILED(rv)) {
693    return rv;
694  }
695
696  PRUint32 value;
697  rv = aStream->Read32(&value);
698  if (NS_FAILED(rv)) {
699    delete key;
700    return rv;
701  }
702
703  *aKey = key;
704  *aData = (void*) value;
705  return NS_OK;
706}
707
708PR_STATIC_CALLBACK(void)
709FreeAnnotationEntry(nsIObjectInputStream* aStream, nsHashKey* aKey,
710                    void* aData)
711{
712  delete aKey;
713}
714
715NS_IMETHODIMP
716nsPrincipal::Read(nsIObjectInputStream* aStream)
717{
718  PRUint32 annotationCount;
719  nsresult rv = aStream->Read32(&annotationCount);
720  if (NS_FAILED(rv)) {
721    return rv;
722  }
723
724  for (PRInt32 i = 0, n = PRInt32(annotationCount); i < n; i++) {
725    nsHashtable *ht = new nsHashtable(aStream,
726                                      ReadAnnotationEntry,
727                                      FreeAnnotationEntry,
728                                      &rv);
729    if (!ht) {
730      return NS_ERROR_OUT_OF_MEMORY;
731    }
732
733    if (NS_FAILED(rv)) {
734      delete ht;
735      return rv;
736    }
737
738    if (!mAnnotations.InsertElementAt(NS_REINTERPRET_CAST(void*, ht), i)) {
739      delete ht;
740      return NS_ERROR_OUT_OF_MEMORY;
741    }
742  }
743
744  PRBool hasCapabilities;
745  rv = aStream->ReadBoolean(&hasCapabilities);
746  if (NS_SUCCEEDED(rv) && hasCapabilities) {
747    mCapabilities = nsHashtable(aStream,
748                                ReadAnnotationEntry,
749                                FreeAnnotationEntry,
750                                &rv);
751  }
752
753  if (NS_FAILED(rv)) {
754    return rv;
755  }
756
757  rv = NS_ReadOptionalCString(aStream, mPrefName);
758  if (NS_FAILED(rv)) {
759    return rv;
760  }
761
762  return NS_OK;
763}
764
765PR_STATIC_CALLBACK(nsresult)
766WriteScalarValue(nsIObjectOutputStream* aStream, void* aData)
767{
768  PRUint32 value = NS_PTR_TO_INT32(aData);
769
770  return aStream->Write32(value);
771}
772
773NS_IMETHODIMP
774nsPrincipal::Write(nsIObjectOutputStream* aStream)
775{
776  PRUint32 annotationCount = PRUint32(mAnnotations.Count());
777  nsresult rv = aStream->Write32(annotationCount);
778  if (NS_FAILED(rv)) {
779    return rv;
780  }
781
782  for (PRInt32 i = 0, n = PRInt32(annotationCount); i < n; i++) {
783    nsHashtable *ht = NS_REINTERPRET_CAST(nsHashtable *, mAnnotations[i]);
784    rv = ht->Write(aStream, WriteScalarValue);
785    if (NS_FAILED(rv)) {
786      return rv;
787    }
788  }
789
790  PRBool hasCapabilities = (mCapabilities.Count() > 0);
791  rv = aStream->WriteBoolean(hasCapabilities);
792  if (NS_SUCCEEDED(rv) && hasCapabilities) {
793    rv = mCapabilities.Write(aStream, WriteScalarValue);
794  }
795
796  if (NS_FAILED(rv)) {
797    return rv;
798  }
799
800  rv = NS_WriteOptionalStringZ(aStream, mPrefName.get());
801  if (NS_FAILED(rv)) {
802    return rv;
803  }
804
805  return NS_OK;
806}
Note: See TracBrowser for help on using the repository browser.