1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
40 * Object Construction, Destruction and Callback Functions
44 #include "pkix_pl_object.h"
46 /* --Debugging---------------------------------------------------- */
48 static PKIX_UInt32 refCountTotal
= 0;
50 /* --Class-Table-Initializers------------------------------------ */
53 * Create storage space for 20 Class Table buckets.
54 * These are only for user-defined types. System types are registered
55 * separately by PKIX_PL_Initialize.
58 static pkix_pl_HT_Elem
*
59 pkix_Raw_ClassTable_Buckets
[] = {
60 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
61 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
65 * Allocate static memory for a ClassTable.
66 * XXX This assumes the bucket pointer will fit into a PKIX_UInt32
68 static pkix_pl_PrimHashTable pkix_Raw_ClassTable
= {
69 (void *)pkix_Raw_ClassTable_Buckets
, /* Buckets */
70 20 /* Number of Buckets */
72 static pkix_pl_PrimHashTable
* classTable
= &pkix_Raw_ClassTable
;
74 /* --Private-Functions-------------------------------------------- */
77 * FUNCTION: pkix_pl_Object_GetHeader
80 * Shifts Object pointed to by "object" by the sizeof(PKIX_PL_Object) and
81 * stores the value at "pObjectHeader".
85 * Address of Object to shift. Must be non-NULL.
87 * Address where object pointer will be stored. Must be non-NULL.
89 * Platform-specific context pointer.
91 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
93 * Returns NULL if the function succeeds.
94 * Returns a Fatal Error if the function fails in an unrecoverable way.
97 pkix_pl_Object_GetHeader(
98 PKIX_PL_Object
*object
,
99 PKIX_PL_Object
**pObjectHeader
,
102 PKIX_PL_Object
*header
= NULL
;
103 pkix_ClassTable_Entry
*ctEntry
= NULL
;
106 PKIX_ENTER(OBJECT
, "pkix_pl_Object_GetHeader");
107 PKIX_NULLCHECK_TWO(object
, pObjectHeader
);
109 PKIX_OBJECT_DEBUG("\tShifting object pointer).\n");
111 /* The header is sizeof(PKIX_PL_Object) before the object pointer */
112 header
= (PKIX_PL_Object
*)((char *)object
- sizeof(PKIX_PL_Object
));
114 myType
= header
->type
;
116 if (myType
>= PKIX_NUMTYPES
) { /* if this is a user-defined type */
117 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
118 PR_Lock(classTableLock
);
120 PKIX_CHECK(pkix_pl_PrimHashTable_Lookup
127 PKIX_ERRORGETTINGCLASSTABLEENTRY
);
129 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
130 PR_Unlock(classTableLock
);
132 if (ctEntry
== NULL
) {
133 PKIX_ERROR_FATAL(PKIX_UNKNOWNOBJECTTYPE
);
137 if ((header
== NULL
)||
138 (header
->magicHeader
!= PKIX_MAGIC_HEADER
)) {
139 return (PKIX_ALLOC_ERROR());
142 *pObjectHeader
= header
;
150 * FUNCTION: pkix_Destroy_Object
153 * Destroys and deallocates Object pointed to by "object". The caller is
154 * assumed to hold the Object's lock, which is acquired in
155 * PKIX_PL_Object_DecRef().
159 * Address of Object to destroy. Must be non-NULL.
161 * Platform-specific context pointer.
163 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
165 * Returns NULL if the function succeeds.
166 * Returns a Fatal Error if the function fails in an unrecoverable way.
169 pkix_pl_Object_Destroy(
170 PKIX_PL_Object
*object
,
173 PKIX_PL_Object
*objectHeader
= NULL
;
175 PKIX_ENTER(OBJECT
, "pkix_pl_Object_Destroy");
176 PKIX_NULLCHECK_ONE(object
);
178 PKIX_CHECK(pkix_pl_Object_GetHeader(object
, &objectHeader
, plContext
),
179 PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT
);
181 /* Attempt to delete an object still being used */
182 if (objectHeader
->references
!= 0) {
183 PKIX_ERROR_FATAL(PKIX_OBJECTSTILLREFERENCED
);
186 objectHeader
->magicHeader
= 0;
187 PKIX_DECREF(objectHeader
->stringRep
);
189 PKIX_CHECK(pkix_UnlockObject(object
, plContext
),
190 PKIX_ERRORUNLOCKINGOBJECT
);
192 /* Destroy this object's lock */
193 PKIX_OBJECT_DEBUG("\tCalling PR_DestroyLock).\n");
194 PR_DestroyLock(objectHeader
->lock
);
195 objectHeader
->lock
= NULL
;
198 PKIX_FREE(objectHeader
);
205 /* --Default-Callbacks-------------------------------------------- */
208 * FUNCTION: pkix_pl_Object_Equals_Default
211 * Default Object_Equals callback: Compares the address of the Object pointed
212 * to by "firstObject" with the address of the Object pointed to by
213 * "secondObject" and stores the Boolean result at "pResult".
217 * Address of first Object to compare. Must be non-NULL.
219 * Address of second Object to compare. Must be non-NULL.
221 * Address where Boolean result will be stored. Must be non-NULL.
223 * Platform-specific context pointer.
225 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
227 * Returns NULL if the function succeeds.
228 * Returns a Fatal Error if the function fails in an unrecoverable way.
231 pkix_pl_Object_Equals_Default(
232 PKIX_PL_Object
*firstObject
,
233 PKIX_PL_Object
*secondObject
,
234 PKIX_Boolean
*pResult
,
237 PKIX_ENTER(OBJECT
, "pkix_pl_Object_Equals_Default");
238 PKIX_NULLCHECK_THREE(firstObject
, secondObject
, pResult
);
240 /* Just compare pointer values */
241 *pResult
= (firstObject
== secondObject
)?PKIX_TRUE
:PKIX_FALSE
;
247 * FUNCTION: pkix_pl_Object_ToString_Default
250 * Default Object_ToString callback: Creates a string consisting of the
251 * typename and address of the Object pointed to by "object" and stores
252 * the result at "pString". The format for the string is
253 * "TypeName@Address: <address>", where the default typename is "Object".
257 * Address of Object to convert to a string. Must be non-NULL.
259 * Address where object pointer will be stored. Must be non-NULL.
261 * Platform-specific context pointer.
263 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
265 * Returns NULL if the function succeeds.
266 * Returns an Object Error if the function fails in a non-fatal way.
267 * Returns a Fatal Error if the function fails in an unrecoverable way.
270 pkix_pl_Object_ToString_Default(
271 PKIX_PL_Object
*object
,
272 PKIX_PL_String
**pString
,
275 extern pkix_ClassTable_Entry systemClasses
[PKIX_NUMTYPES
];
276 pkix_ClassTable_Entry
*ctEntry
= NULL
;
277 PKIX_PL_String
*formatString
= NULL
;
278 PKIX_PL_String
*descString
= NULL
;
279 char *format
= "%s@Address: %x";
280 char *description
= NULL
;
283 PKIX_ENTER(OBJECT
, "pkix_pl_Object_ToString_Default");
284 PKIX_NULLCHECK_TWO(object
, pString
);
286 PKIX_CHECK(PKIX_PL_Object_GetType(object
, &type
, plContext
),
287 PKIX_OBJECTGETTYPEFAILED
);
289 /* Ensure that type code is known. Otherwise, default to Object */
290 /* See pkixt.h for all known types. */
291 /* XXX Throw an illegal type error here? */
292 if (type
>= PKIX_NUMTYPES
) {
296 /* first, special handling for system types */
297 if (type
< PKIX_NUMTYPES
){
298 description
= systemClasses
[type
].description
;
300 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
301 PR_Lock(classTableLock
);
302 pkixErrorResult
= pkix_pl_PrimHashTable_Lookup
309 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
310 PR_Unlock(classTableLock
);
311 if (pkixErrorResult
){
312 PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY
);
315 if (ctEntry
== NULL
){
316 PKIX_ERROR_FATAL(PKIX_UNDEFINEDCLASSTABLEENTRY
);
318 description
= ctEntry
->description
;
322 PKIX_CHECK(PKIX_PL_String_Create
328 PKIX_STRINGCREATEFAILED
);
330 PKIX_CHECK(PKIX_PL_String_Create
336 PKIX_STRINGCREATEFAILED
);
338 PKIX_CHECK(PKIX_PL_Sprintf
348 PKIX_DECREF(formatString
);
349 PKIX_DECREF(descString
);
355 * FUNCTION: pkix_pl_Object_Hashcode_Default
358 * Default Object_Hashcode callback. Creates the a hashcode value using the
359 * address of the Object pointed to by "object" and stores the result at
362 * XXX This isn't great since addresses are not uniformly distributed.
366 * Address of Object to compute hashcode for. Must be non-NULL.
368 * Address where PKIX_UInt32 will be stored. Must be non-NULL.
370 * Platform-specific context pointer.
372 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
374 * Returns NULL if the function succeeds.
375 * Returns a Fatal Error if the function fails in an unrecoverable way.
378 pkix_pl_Object_Hashcode_Default(
379 PKIX_PL_Object
*object
,
390 PKIX_ENTER(OBJECT
, "pkix_pl_Object_Hashcode_Default");
391 PKIX_NULLCHECK_TWO(object
, pValue
);
394 extracter
.pointer
= object
;
395 *pValue
= extracter
.hilo
[1];
397 *pValue
= (PKIX_UInt32
)object
;
404 * FUNCTION: pkix_pl_Object_RetrieveEqualsCallback
407 * Retrieves Equals callback function of Object pointed to by "object and
408 * stores it at "pEqualsCallback". If the object's type is one of the system
409 * types, its callback function is retrieved from the systemClasses array;
410 * otherwise, its callback function is retrieve from the classTable hash
411 * table where user-defined types are stored.
415 * Address of Object whose equals callback is desired. Must be non-NULL.
417 * Address where EqualsCallback function pointer will be stored.
420 * Platform-specific context pointer.
422 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
424 * Returns NULL if the function succeeds.
425 * Returns an Object Error if the function fails in a non-fatal way.
426 * Returns a Fatal Error if the function fails in an unrecoverable way.
429 pkix_pl_Object_RetrieveEqualsCallback(
430 PKIX_PL_Object
*object
,
431 PKIX_PL_EqualsCallback
*pEqualsCallback
,
434 extern pkix_ClassTable_Entry systemClasses
[PKIX_NUMTYPES
];
435 PKIX_PL_Object
*objectHeader
= NULL
;
436 pkix_ClassTable_Entry
*ctEntry
= NULL
;
437 PKIX_PL_EqualsCallback func
= NULL
;
438 pkix_ClassTable_Entry entry
;
440 PKIX_ENTER(OBJECT
, "pkix_pl_Object_RetrieveEqualsCallback");
441 PKIX_NULLCHECK_TWO(object
, pEqualsCallback
);
443 PKIX_CHECK(pkix_pl_Object_GetHeader
444 (object
, &objectHeader
, plContext
),
445 PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT
);
447 /* first, special handling for system types */
448 if (objectHeader
->type
< PKIX_NUMTYPES
){
449 entry
= systemClasses
[objectHeader
->type
];
450 func
= entry
.equalsFunction
;
452 func
= pkix_pl_Object_Equals_Default
;
454 *pEqualsCallback
= func
;
456 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
457 PR_Lock(classTableLock
);
458 pkixErrorResult
= pkix_pl_PrimHashTable_Lookup
460 (void *)&objectHeader
->type
,
465 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
466 PR_Unlock(classTableLock
);
467 if (pkixErrorResult
){
468 PKIX_ERROR(PKIX_ERRORGETTINGCLASSTABLEENTRY
);
471 if ((ctEntry
== NULL
) || (ctEntry
->equalsFunction
== NULL
)) {
472 PKIX_ERROR(PKIX_UNDEFINEDEQUALSCALLBACK
);
474 *pEqualsCallback
= ctEntry
->equalsFunction
;
483 /* --Public-Functions------------------------------------------------------- */
486 * FUNCTION: PKIX_PL_Object_Alloc (see comments in pkix_pl_system.h)
489 PKIX_PL_Object_Alloc(
492 PKIX_PL_Object
**pObject
,
495 PKIX_PL_Object
*object
= NULL
;
496 pkix_ClassTable_Entry
*ctEntry
= NULL
;
497 PKIX_Boolean typeRegistered
;
499 PKIX_ENTER(OBJECT
, "PKIX_PL_Object_Alloc");
500 PKIX_NULLCHECK_ONE(pObject
);
503 * We need to ensure that user-defined types have been registered.
504 * All system types have already been registered by PKIX_PL_Initialize.
507 if (type
>= PKIX_NUMTYPES
) { /* i.e. if this is a user-defined type */
508 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
509 PR_Lock(classTableLock
);
510 pkixErrorResult
= pkix_pl_PrimHashTable_Lookup
517 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
518 PR_Unlock(classTableLock
);
519 if (pkixErrorResult
){
520 PKIX_ERROR_FATAL(PKIX_COULDNOTLOOKUPINHASHTABLE
);
523 typeRegistered
= (ctEntry
!= NULL
);
525 if (!typeRegistered
) {
526 PKIX_ERROR_FATAL(PKIX_UNKNOWNTYPEARGUMENT
);
530 /* Allocate space for the object header and the requested size */
531 PKIX_CHECK(PKIX_PL_Malloc
532 (((PKIX_UInt32
)sizeof (PKIX_PL_Object
))+size
,
537 /* Initialize all object fields */
538 object
->magicHeader
= PKIX_MAGIC_HEADER
;
540 object
->references
= 1; /* Default to a single reference */
541 object
->stringRep
= NULL
;
542 object
->hashcode
= 0;
543 object
->hashcodeCached
= 0;
545 /* XXX Debugging - not thread safe */
548 PKIX_REF_COUNT_DEBUG_ARG("PKIX_PL_Object_Alloc: refCountTotal == %d \n",
551 /* Cannot use PKIX_PL_Mutex because it depends on Object */
552 /* Using NSPR Locks instead */
553 PKIX_OBJECT_DEBUG("\tCalling PR_NewLock).\n");
554 object
->lock
= PR_NewLock();
555 if (object
->lock
== NULL
) {
557 return (PKIX_ALLOC_ERROR());
560 PKIX_OBJECT_DEBUG("\tShifting object pointer).\n");
562 /* Return a pointer to the user data. Need to offset by object size */
563 *pObject
= object
+ 1;
571 * FUNCTION: PKIX_PL_Object_IsTypeRegistered (see comments in pkix_pl_system.h)
574 PKIX_PL_Object_IsTypeRegistered(
579 pkix_ClassTable_Entry
*ctEntry
= NULL
;
581 PKIX_ENTER(OBJECT
, "PKIX_PL_Object_IsTypeRegistered");
582 PKIX_NULLCHECK_ONE(pBool
);
584 /* first, we handle the system types */
585 if (type
< PKIX_NUMTYPES
) {
590 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
591 PR_Lock(classTableLock
);
592 pkixErrorResult
= pkix_pl_PrimHashTable_Lookup
599 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
600 PR_Unlock(classTableLock
);
602 if (pkixErrorResult
){
603 PKIX_ERROR_FATAL(PKIX_COULDNOTLOOKUPINHASHTABLE
);
606 *pBool
= (ctEntry
!= NULL
);
614 * FUNCTION: PKIX_PL_Object_RegisterType (see comments in pkix_pl_system.h)
617 PKIX_PL_Object_RegisterType(
620 PKIX_PL_DestructorCallback destructor
,
621 PKIX_PL_EqualsCallback equalsFunction
,
622 PKIX_PL_HashcodeCallback hashcodeFunction
,
623 PKIX_PL_ToStringCallback toStringFunction
,
624 PKIX_PL_ComparatorCallback comparator
,
625 PKIX_PL_DuplicateCallback duplicateFunction
,
628 pkix_ClassTable_Entry
*ctEntry
= NULL
;
629 pkix_pl_Integer
*key
= NULL
;
631 PKIX_ENTER(OBJECT
, "PKIX_PL_Object_RegisterType");
634 * System types are registered on startup by PKIX_PL_Initialize.
635 * These can not be overwritten.
638 if (type
< PKIX_NUMTYPES
) { /* if this is a system type */
639 PKIX_ERROR(PKIX_CANTREREGISTERSYSTEMTYPE
);
642 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
643 PR_Lock(classTableLock
);
644 PKIX_CHECK(pkix_pl_PrimHashTable_Lookup
651 PKIX_PRIMHASHTABLELOOKUPFAILED
);
653 /* If the type is already registered, throw an error */
655 PKIX_ERROR(PKIX_TYPEALREADYREGISTERED
);
658 PKIX_CHECK(PKIX_PL_Malloc
659 (((PKIX_UInt32
)sizeof (pkix_ClassTable_Entry
)),
664 /* Set Default Values if none specified */
666 if (description
== NULL
){
667 description
= "Object";
670 if (equalsFunction
== NULL
) {
671 equalsFunction
= pkix_pl_Object_Equals_Default
;
674 if (toStringFunction
== NULL
) {
675 toStringFunction
= pkix_pl_Object_ToString_Default
;
678 if (hashcodeFunction
== NULL
) {
679 hashcodeFunction
= pkix_pl_Object_Hashcode_Default
;
682 ctEntry
->destructor
= destructor
;
683 ctEntry
->equalsFunction
= equalsFunction
;
684 ctEntry
->toStringFunction
= toStringFunction
;
685 ctEntry
->hashcodeFunction
= hashcodeFunction
;
686 ctEntry
->comparator
= comparator
;
687 ctEntry
->duplicateFunction
= duplicateFunction
;
688 ctEntry
->description
= description
;
690 PKIX_CHECK(PKIX_PL_Malloc
691 (((PKIX_UInt32
)sizeof (pkix_pl_Integer
)),
694 PKIX_COULDNOTMALLOCNEWKEY
);
698 PKIX_CHECK(pkix_pl_PrimHashTable_Add
705 PKIX_PRIMHASHTABLEADDFAILED
);
708 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
709 PR_Unlock(classTableLock
);
715 * FUNCTION: PKIX_PL_Object_IncRef (see comments in pkix_pl_system.h)
718 PKIX_PL_Object_IncRef(
719 PKIX_PL_Object
*object
,
722 PKIX_Boolean refCountError
= PKIX_FALSE
;
723 PKIX_PL_Object
*objectHeader
= NULL
;
724 PKIX_PL_NssContext
*context
= NULL
;
726 PKIX_ENTER(OBJECT
, "PKIX_PL_Object_IncRef");
727 PKIX_NULLCHECK_ONE(object
);
731 * PKIX_PL_NssContext is not a complete PKIX Type, it doesn't
732 * have a header therefore we cannot verify its type before
735 context
= (PKIX_PL_NssContext
*) plContext
;
736 if (context
->arena
!= NULL
) {
741 if (object
== (PKIX_PL_Object
*)PKIX_ALLOC_ERROR()) {
742 PKIX_ERROR_FATAL(PKIX_ATTEMPTTOINCREFALLOCERROR
);
745 /* Shift pointer from user data to object header */
746 PKIX_CHECK(pkix_pl_Object_GetHeader(object
, &objectHeader
, plContext
),
747 PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT
);
749 /* Lock the test and increment */
750 PKIX_OBJECT_DEBUG("\tAcquiring object lock).\n");
751 PKIX_CHECK(pkix_LockObject(object
, plContext
),
752 PKIX_ERRORLOCKINGOBJECT
);
754 /* This object should never have zero references */
755 refCountError
= (objectHeader
->references
== 0);
757 if (!refCountError
) {
758 objectHeader
->references
++;
760 PKIX_REF_COUNT_DEBUG_ARG("PKIX_PL_Object_IncRef: "
761 "refCountTotal == %d \n", refCountTotal
);
764 PKIX_CHECK(pkix_UnlockObject(object
, plContext
),
765 PKIX_ERRORUNLOCKINGOBJECT
);
770 PKIX_ErrorText
[PKIX_OBJECTWITHNONPOSITIVEREFERENCES
]);
779 * FUNCTION: PKIX_PL_Object_DecRef (see comments in pkix_pl_system.h)
782 PKIX_PL_Object_DecRef(
783 PKIX_PL_Object
*object
,
786 extern pkix_ClassTable_Entry systemClasses
[PKIX_NUMTYPES
];
787 PKIX_PL_DestructorCallback destructor
= NULL
;
788 pkix_ClassTable_Entry
*ctEntry
= NULL
;
789 PKIX_PL_DestructorCallback func
= NULL
;
790 PKIX_PL_Object
*objectHeader
= NULL
;
791 pkix_ClassTable_Entry entry
;
792 PKIX_PL_NssContext
*context
= NULL
;
793 PKIX_Boolean refCountError
= PKIX_FALSE
;
795 PKIX_ENTER(OBJECT
, "PKIX_PL_Object_DecRef");
796 PKIX_NULLCHECK_ONE(object
);
800 * PKIX_PL_NssContext is not a complete PKIX Type, it doesn't
801 * have a header therefore we cannot verify its type before
804 context
= (PKIX_PL_NssContext
*) plContext
;
805 if (context
->arena
!= NULL
) {
810 if (object
== (PKIX_PL_Object
*)PKIX_ALLOC_ERROR()) {
811 PKIX_ERROR_FATAL(PKIX_ATTEMPTTODECREFALLOCERROR
);
814 /* Shift pointer from user data to object header */
815 PKIX_CHECK(pkix_pl_Object_GetHeader(object
, &objectHeader
, plContext
),
816 PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT
);
818 /* Lock the test for the reference count and the decrement */
819 PKIX_OBJECT_DEBUG("\tAcquiring object lock).\n");
820 PKIX_CHECK(pkix_LockObject(object
, plContext
),
821 PKIX_ERRORLOCKINGOBJECT
);
823 refCountError
= (objectHeader
->references
== 0);
825 if (!refCountError
) {
826 objectHeader
->references
--;
829 PKIX_REF_COUNT_DEBUG_ARG("PKIX_PL_Object_DecRef: "
830 "refCountTotal == %d \n", refCountTotal
);
832 if (objectHeader
->references
== 0) {
833 /* first, special handling for system types */
834 if (objectHeader
->type
< PKIX_NUMTYPES
){
835 entry
= systemClasses
[objectHeader
->type
];
836 func
= entry
.destructor
;
838 /* Call destructor on user data if necessary */
839 PKIX_CHECK_FATAL(func(object
, plContext
),
840 PKIX_ERRORINOBJECTDEFINEDESTROY
);
843 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
844 PR_Lock(classTableLock
);
845 pkixErrorResult
= pkix_pl_PrimHashTable_Lookup
847 (void *)&objectHeader
->type
,
853 ("\tCalling PR_Unlock).\n");
854 PR_Unlock(classTableLock
);
855 if (pkixErrorResult
){
857 (PKIX_ERRORINGETTINGDESTRUCTOR
);
860 if (ctEntry
!= NULL
){
861 destructor
= ctEntry
->destructor
;
864 if (destructor
!= NULL
) {
865 /* Call destructor on user data if necessary */
866 PKIX_CHECK_FATAL(destructor
868 PKIX_ERRORINOBJECTDEFINEDESTROY
);
872 /* pkix_pl_Object_Destroy assumes the lock is held */
873 /* It will call unlock and destroy the object */
874 return (pkix_pl_Object_Destroy(object
, plContext
));
879 PKIX_OBJECT_DEBUG("\tReleasing object lock).\n");
880 PKIX_CHECK(pkix_UnlockObject(object
, plContext
),
881 PKIX_ERRORUNLOCKINGOBJECT
);
883 /* if a reference count was already zero, throw an error */
885 return (PKIX_ALLOC_ERROR());
896 * FUNCTION: PKIX_PL_Object_Equals (see comments in pkix_pl_system.h)
899 PKIX_PL_Object_Equals(
900 PKIX_PL_Object
*firstObject
,
901 PKIX_PL_Object
*secondObject
,
902 PKIX_Boolean
*pResult
,
905 extern pkix_ClassTable_Entry systemClasses
[PKIX_NUMTYPES
];
906 PKIX_PL_Object
*firstObjectHeader
= NULL
;
907 PKIX_PL_Object
*secondObjectHeader
= NULL
;
908 pkix_ClassTable_Entry
*ctEntry
= NULL
;
909 PKIX_PL_EqualsCallback func
= NULL
;
910 pkix_ClassTable_Entry entry
;
912 PKIX_ENTER(OBJECT
, "PKIX_PL_Object_Equals");
913 PKIX_NULLCHECK_THREE(firstObject
, secondObject
, pResult
);
915 PKIX_CHECK(pkix_pl_Object_GetHeader
916 (firstObject
, &firstObjectHeader
, plContext
),
917 PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT
);
919 PKIX_CHECK(pkix_pl_Object_GetHeader
920 (secondObject
, &secondObjectHeader
, plContext
),
921 PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT
);
923 /* if hashcodes are cached but not equal, objects can't be equal */
924 if (firstObjectHeader
->hashcodeCached
&&
925 secondObjectHeader
->hashcodeCached
){
926 if (firstObjectHeader
->hashcode
!=
927 secondObjectHeader
->hashcode
){
928 *pResult
= PKIX_FALSE
;
933 /* first, special handling for system types */
934 if (firstObjectHeader
->type
< PKIX_NUMTYPES
){
935 entry
= systemClasses
[firstObjectHeader
->type
];
936 func
= entry
.equalsFunction
;
938 func
= pkix_pl_Object_Equals_Default
;
941 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
942 PR_Lock(classTableLock
);
943 pkixErrorResult
= pkix_pl_PrimHashTable_Lookup
945 (void *)&firstObjectHeader
->type
,
946 firstObjectHeader
->type
,
950 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
951 PR_Unlock(classTableLock
);
953 if (pkixErrorResult
){
954 PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY
);
957 if ((ctEntry
== NULL
) || (ctEntry
->equalsFunction
== NULL
)) {
958 PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK
);
960 func
= ctEntry
->equalsFunction
;
964 PKIX_CHECK(func(firstObject
, secondObject
, pResult
, plContext
),
965 PKIX_OBJECTSPECIFICFUNCTIONFAILED
);
973 * FUNCTION: PKIX_PL_Object_Duplicate (see comments in pkix_pl_system.h)
976 PKIX_PL_Object_Duplicate(
977 PKIX_PL_Object
*firstObject
,
978 PKIX_PL_Object
**pNewObject
,
981 extern pkix_ClassTable_Entry systemClasses
[PKIX_NUMTYPES
];
982 PKIX_PL_Object
*firstObjectHeader
= NULL
;
983 pkix_ClassTable_Entry
*ctEntry
= NULL
;
984 PKIX_PL_DuplicateCallback func
= NULL
;
985 pkix_ClassTable_Entry entry
;
987 PKIX_ENTER(OBJECT
, "PKIX_PL_Object_Duplicate");
988 PKIX_NULLCHECK_TWO(firstObject
, pNewObject
);
990 PKIX_CHECK(pkix_pl_Object_GetHeader
991 (firstObject
, &firstObjectHeader
, plContext
),
992 PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT
);
994 /* first, special handling for system types */
995 if (firstObjectHeader
->type
< PKIX_NUMTYPES
){
996 entry
= systemClasses
[firstObjectHeader
->type
];
997 func
= entry
.duplicateFunction
;
999 PKIX_ERROR_FATAL(PKIX_UNDEFINEDDUPLICATEFUNCTION
);
1002 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
1003 PR_Lock(classTableLock
);
1004 pkixErrorResult
= pkix_pl_PrimHashTable_Lookup
1006 (void *)&firstObjectHeader
->type
,
1007 firstObjectHeader
->type
,
1011 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
1012 PR_Unlock(classTableLock
);
1014 if (pkixErrorResult
){
1015 PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY
);
1018 if ((ctEntry
== NULL
) || (ctEntry
->duplicateFunction
== NULL
)) {
1019 PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK
);
1021 func
= ctEntry
->duplicateFunction
;
1025 PKIX_CHECK(func(firstObject
, pNewObject
, plContext
),
1026 PKIX_OBJECTSPECIFICFUNCTIONFAILED
);
1030 PKIX_RETURN(OBJECT
);
1034 * FUNCTION: PKIX_PL_Object_Hashcode (see comments in pkix_pl_system.h)
1037 PKIX_PL_Object_Hashcode(
1038 PKIX_PL_Object
*object
,
1039 PKIX_UInt32
*pValue
,
1042 extern pkix_ClassTable_Entry systemClasses
[PKIX_NUMTYPES
];
1043 PKIX_PL_Object
*objectHeader
= NULL
;
1044 pkix_ClassTable_Entry
*ctEntry
= NULL
;
1045 PKIX_PL_HashcodeCallback func
= NULL
;
1046 pkix_ClassTable_Entry entry
;
1047 PKIX_Boolean objectLocked
= PKIX_FALSE
;
1048 PKIX_UInt32 objectHash
;
1050 PKIX_ENTER(OBJECT
, "PKIX_PL_Object_Hashcode");
1051 PKIX_NULLCHECK_TWO(object
, pValue
);
1053 /* Shift pointer from user data to object header */
1054 PKIX_CHECK(pkix_pl_Object_GetHeader(object
, &objectHeader
, plContext
),
1055 PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT
);
1057 /* if we don't have a cached copy from before, we create one */
1058 if (!objectHeader
->hashcodeCached
){
1060 /* first, special handling for system types */
1061 if (objectHeader
->type
< PKIX_NUMTYPES
){
1062 entry
= systemClasses
[objectHeader
->type
];
1063 func
= entry
.hashcodeFunction
;
1065 func
= pkix_pl_Object_Hashcode_Default
;
1068 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
1069 PR_Lock(classTableLock
);
1070 pkixErrorResult
= pkix_pl_PrimHashTable_Lookup
1072 (void *)&objectHeader
->type
,
1077 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
1078 PR_Unlock(classTableLock
);
1080 if (pkixErrorResult
){
1082 (PKIX_ERRORGETTINGCLASSTABLEENTRY
);
1085 if ((ctEntry
== NULL
) ||
1086 (ctEntry
->hashcodeFunction
== NULL
)) {
1087 PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK
);
1090 func
= ctEntry
->hashcodeFunction
;
1093 PKIX_CHECK(func(object
, &objectHash
, plContext
),
1094 PKIX_OBJECTSPECIFICFUNCTIONFAILED
);
1096 if (!objectHeader
->hashcodeCached
){
1098 PKIX_CHECK(pkix_LockObject(object
, plContext
),
1099 PKIX_ERRORLOCKINGOBJECT
);
1100 objectLocked
= PKIX_TRUE
;
1102 if (!objectHeader
->hashcodeCached
){
1103 /* save cached copy in case we need it again */
1104 objectHeader
->hashcode
= objectHash
;
1105 objectHeader
->hashcodeCached
= PKIX_TRUE
;
1108 PKIX_CHECK(pkix_UnlockObject(object
, plContext
),
1109 PKIX_ERRORUNLOCKINGOBJECT
);
1110 objectLocked
= PKIX_FALSE
;
1114 *pValue
= objectHeader
->hashcode
;
1119 pkixTempResult
= pkix_UnlockObject(object
, plContext
);
1120 if (pkixTempResult
) return pkixTempResult
;
1123 PKIX_RETURN(OBJECT
);
1127 * FUNCTION: PKIX_PL_Object_ToString (see comments in pkix_pl_system.h)
1130 PKIX_PL_Object_ToString(
1131 PKIX_PL_Object
*object
,
1132 PKIX_PL_String
**pString
,
1135 extern pkix_ClassTable_Entry systemClasses
[PKIX_NUMTYPES
];
1136 PKIX_PL_Object
*objectHeader
= NULL
;
1137 pkix_ClassTable_Entry
*ctEntry
= NULL
;
1138 PKIX_PL_ToStringCallback func
= NULL
;
1139 pkix_ClassTable_Entry entry
;
1140 PKIX_Boolean objectLocked
= PKIX_FALSE
;
1141 PKIX_PL_String
*objectString
;
1143 PKIX_ENTER(OBJECT
, "PKIX_PL_Object_ToString");
1144 PKIX_NULLCHECK_TWO(object
, pString
);
1146 /* Shift pointer from user data to object header */
1147 PKIX_CHECK(pkix_pl_Object_GetHeader(object
, &objectHeader
, plContext
),
1148 PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT
);
1150 /* if we don't have a cached copy from before, we create one */
1151 if (!objectHeader
->stringRep
){
1153 /* first, special handling for system types */
1154 if (objectHeader
->type
< PKIX_NUMTYPES
){
1155 entry
= systemClasses
[objectHeader
->type
];
1156 func
= entry
.toStringFunction
;
1158 func
= pkix_pl_Object_ToString_Default
;
1161 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
1162 PR_Lock(classTableLock
);
1163 pkixErrorResult
= pkix_pl_PrimHashTable_Lookup
1165 (void *)&objectHeader
->type
,
1170 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
1171 PR_Unlock(classTableLock
);
1172 if (pkixErrorResult
){
1174 (PKIX_ERRORGETTINGCLASSTABLEENTRY
);
1177 if ((ctEntry
== NULL
) ||
1178 (ctEntry
->toStringFunction
== NULL
)) {
1179 PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK
);
1182 func
= ctEntry
->toStringFunction
;
1185 PKIX_CHECK(func(object
, &objectString
, plContext
),
1186 PKIX_OBJECTSPECIFICFUNCTIONFAILED
);
1188 if (!objectHeader
->stringRep
){
1190 PKIX_CHECK(pkix_LockObject(object
, plContext
),
1191 PKIX_ERRORLOCKINGOBJECT
);
1192 objectLocked
= PKIX_TRUE
;
1194 if (!objectHeader
->stringRep
){
1195 /* save a cached copy */
1196 objectHeader
->stringRep
= objectString
;
1199 PKIX_CHECK(pkix_UnlockObject(object
, plContext
),
1200 PKIX_ERRORUNLOCKINGOBJECT
);
1201 objectLocked
= PKIX_FALSE
;
1205 PKIX_INCREF(objectHeader
->stringRep
);
1206 *pString
= objectHeader
->stringRep
;
1210 PKIX_RETURN(OBJECT
);
1214 * FUNCTION: PKIX_PL_Object_InvalidateCache (see comments in pkix_pl_system.h)
1217 PKIX_PL_Object_InvalidateCache(
1218 PKIX_PL_Object
*object
,
1221 PKIX_PL_Object
*objectHeader
= NULL
;
1222 PKIX_Boolean objectLocked
= PKIX_FALSE
;
1224 PKIX_ENTER(OBJECT
, "PKIX_PL_Object_InvalidateCache");
1225 PKIX_NULLCHECK_ONE(object
);
1227 /* Shift pointer from user data to object header */
1228 PKIX_CHECK(pkix_pl_Object_GetHeader(object
, &objectHeader
, plContext
),
1229 PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT
);
1231 PKIX_CHECK(pkix_LockObject(object
, plContext
),
1232 PKIX_ERRORLOCKINGOBJECT
);
1233 objectLocked
= PKIX_TRUE
;
1235 /* invalidate hashcode */
1236 objectHeader
->hashcode
= 0;
1237 objectHeader
->hashcodeCached
= PKIX_FALSE
;
1239 PKIX_DECREF(objectHeader
->stringRep
);
1241 PKIX_CHECK(pkix_UnlockObject(object
, plContext
),
1242 PKIX_ERRORUNLOCKINGOBJECT
);
1243 objectLocked
= PKIX_FALSE
;
1248 PKIX_RETURN(OBJECT
);
1252 * FUNCTION: PKIX_PL_Object_Compare (see comments in pkix_pl_system.h)
1255 PKIX_PL_Object_Compare(
1256 PKIX_PL_Object
*firstObject
,
1257 PKIX_PL_Object
*secondObject
,
1258 PKIX_Int32
*pResult
,
1261 extern pkix_ClassTable_Entry systemClasses
[PKIX_NUMTYPES
];
1262 PKIX_PL_Object
*firstObjectHeader
= NULL
;
1263 PKIX_PL_Object
*secondObjectHeader
= NULL
;
1264 pkix_ClassTable_Entry
*ctEntry
= NULL
;
1265 PKIX_PL_ComparatorCallback func
= NULL
;
1266 pkix_ClassTable_Entry entry
;
1268 PKIX_ENTER(OBJECT
, "PKIX_PL_Object_Compare");
1269 PKIX_NULLCHECK_THREE(firstObject
, secondObject
, pResult
);
1271 /* Shift pointer from user data to object header */
1272 PKIX_CHECK(pkix_pl_Object_GetHeader
1273 (firstObject
, &firstObjectHeader
, plContext
),
1274 PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT
);
1276 /* Shift pointer from user data to object header */
1277 PKIX_CHECK(pkix_pl_Object_GetHeader
1278 (secondObject
, &secondObjectHeader
, plContext
),
1279 PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT
);
1281 /* first, special handling for system types */
1282 if (firstObjectHeader
->type
< PKIX_NUMTYPES
){
1283 entry
= systemClasses
[firstObjectHeader
->type
];
1284 func
= entry
.comparator
;
1286 PKIX_ERROR(PKIX_UNDEFINEDCOMPARATOR
);
1289 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
1290 PR_Lock(classTableLock
);
1291 pkixErrorResult
= pkix_pl_PrimHashTable_Lookup
1293 (void *)&firstObjectHeader
->type
,
1294 firstObjectHeader
->type
,
1298 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
1299 PR_Unlock(classTableLock
);
1300 if (pkixErrorResult
){
1301 PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY
);
1304 if ((ctEntry
== NULL
) || (ctEntry
->comparator
== NULL
)) {
1305 PKIX_ERROR_FATAL(PKIX_UNDEFINEDCOMPARATOR
);
1308 func
= ctEntry
->comparator
;
1311 PKIX_CHECK(func(firstObject
, secondObject
, pResult
, plContext
),
1312 PKIX_OBJECTSPECIFICFUNCTIONFAILED
);
1316 PKIX_RETURN(OBJECT
);
1320 * FUNCTION: PKIX_PL_Object_Lock (see comments in pkix_pl_system.h)
1323 PKIX_PL_Object_Lock(
1324 PKIX_PL_Object
*object
,
1327 PKIX_ENTER(OBJECT
, "PKIX_PL_Object_Lock");
1328 PKIX_NULLCHECK_ONE(object
);
1330 PKIX_CHECK(pkix_LockObject(object
, plContext
),
1331 PKIX_LOCKOBJECTFAILED
);
1335 PKIX_RETURN(OBJECT
);
1339 * FUNCTION: PKIX_PL_Object_Unlock (see comments in pkix_pl_system.h)
1342 PKIX_PL_Object_Unlock(
1343 PKIX_PL_Object
*object
,
1346 PKIX_ENTER(OBJECT
, "PKIX_PL_Object_Unlock");
1347 PKIX_NULLCHECK_ONE(object
);
1349 PKIX_CHECK(pkix_UnlockObject(object
, plContext
),
1350 PKIX_UNLOCKOBJECTFAILED
);
1354 PKIX_RETURN(OBJECT
);
1359 * FUNCTION: PKIX_PL_Object_GetType (see comments in pkix_pl_system.h)
1362 PKIX_PL_Object_GetType(
1363 PKIX_PL_Object
*object
,
1367 PKIX_PL_Object
*objectHeader
= NULL
;
1369 PKIX_ENTER(OBJECT
, "PKIX_PL_Object_GetType");
1370 PKIX_NULLCHECK_TWO(object
, pType
);
1372 /* Shift pointer from user data to object header */
1373 PKIX_CHECK(pkix_pl_Object_GetHeader(object
, &objectHeader
, plContext
),
1374 PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT
);
1376 *pType
= objectHeader
->type
;
1380 PKIX_RETURN(OBJECT
);