| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| /* |
| * pkix_pl_object.c |
| * |
| * Object Construction, Destruction and Callback Functions |
| * |
| */ |
| |
| #include "pkix_pl_object.h" |
| |
| #ifdef PKIX_USER_OBJECT_TYPE |
| /* --Class-Table-Initializers------------------------------------ */ |
| |
| /* |
| * Create storage space for 20 Class Table buckets. |
| * These are only for user-defined types. System types are registered |
| * separately by PKIX_PL_Initialize. |
| */ |
| |
| static pkix_pl_HT_Elem* |
| pkix_Raw_ClassTable_Buckets[] = { |
| NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
| NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL |
| }; |
| |
| /* |
| * Allocate static memory for a ClassTable. |
| * XXX This assumes the bucket pointer will fit into a PKIX_UInt32 |
| */ |
| static pkix_pl_PrimHashTable pkix_Raw_ClassTable = { |
| (void *)pkix_Raw_ClassTable_Buckets, /* Buckets */ |
| 20 /* Number of Buckets */ |
| }; |
| static pkix_pl_PrimHashTable * classTable = &pkix_Raw_ClassTable; |
| #endif /* PKIX_USER_OBJECT_TYPE */ |
| |
| /* --Private-Functions-------------------------------------------- */ |
| |
| /* |
| * FUNCTION: pkix_pl_Object_GetHeader |
| * DESCRIPTION: |
| * |
| * Shifts Object pointed to by "object" by the sizeof(PKIX_PL_Object) and |
| * stores the value at "pObjectHeader". |
| * |
| * PARAMETERS: |
| * "object" |
| * Address of Object to shift. Must be non-NULL. |
| * "pObjectHeader" |
| * Address where object pointer will be stored. Must be non-NULL. |
| * "plContext" |
| * Platform-specific context pointer. |
| * THREAD SAFETY: |
| * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
| * RETURNS: |
| * Returns NULL if the function succeeds. |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_pl_Object_GetHeader( |
| PKIX_PL_Object *object, |
| PKIX_PL_Object **pObjectHeader, |
| void *plContext) |
| { |
| PKIX_PL_Object *header = NULL; |
| PKIX_UInt32 objType; |
| |
| PKIX_ENTER(OBJECT, "pkix_pl_Object_GetHeader"); |
| PKIX_NULLCHECK_TWO(object, pObjectHeader); |
| |
| PKIX_OBJECT_DEBUG("\tShifting object pointer).\n"); |
| |
| /* The header is sizeof(PKIX_PL_Object) before the object pointer */ |
| header = (PKIX_PL_Object *)((char *)object - sizeof(PKIX_PL_Object)); |
| |
| objType = header->type; |
| |
| if (objType >= PKIX_NUMTYPES) { /* if this is a user-defined type */ |
| #ifdef PKIX_USER_OBJECT_TYPE |
| pkix_ClassTable_Entry *ctEntry = NULL; |
| |
| PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); |
| PR_Lock(classTableLock); |
| |
| PKIX_CHECK(pkix_pl_PrimHashTable_Lookup |
| (classTable, |
| (void *)&objType, |
| objType, |
| NULL, |
| (void **)&ctEntry, |
| plContext), |
| PKIX_ERRORGETTINGCLASSTABLEENTRY); |
| |
| PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); |
| PR_Unlock(classTableLock); |
| |
| if (ctEntry == NULL) { |
| PKIX_ERROR_FATAL(PKIX_UNKNOWNOBJECTTYPE); |
| } |
| #else |
| PORT_Assert(objType < PKIX_NUMTYPES); |
| pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| goto cleanup; |
| #endif /* PKIX_USER_OBJECT_TYPE */ |
| } |
| |
| #ifdef PKIX_OBJECT_LEAK_TEST |
| PORT_Assert(header && header->magicHeader == PKIX_MAGIC_HEADER); |
| #endif /* PKIX_OBJECT_LEAK_TEST */ |
| |
| if ((header == NULL)|| |
| (header->magicHeader != PKIX_MAGIC_HEADER)) { |
| PKIX_ERROR_ALLOC_ERROR(); |
| } |
| |
| *pObjectHeader = header; |
| |
| cleanup: |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* |
| * FUNCTION: pkix_Destroy_Object |
| * DESCRIPTION: |
| * |
| * Destroys and deallocates Object pointed to by "object". The caller is |
| * assumed to hold the Object's lock, which is acquired in |
| * PKIX_PL_Object_DecRef(). |
| * |
| * PARAMETERS: |
| * "object" |
| * Address of Object to destroy. Must be non-NULL. |
| * "plContext" |
| * Platform-specific context pointer. |
| * THREAD SAFETY: |
| * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
| * RETURNS: |
| * Returns NULL if the function succeeds. |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_pl_Object_Destroy( |
| PKIX_PL_Object *object, |
| void *plContext) |
| { |
| PKIX_PL_Object *objectHeader = NULL; |
| |
| PKIX_ENTER(OBJECT, "pkix_pl_Object_Destroy"); |
| PKIX_NULLCHECK_ONE(object); |
| |
| #ifdef PKIX_OBJECT_LEAK_TEST |
| PKIX_CHECK_FATAL(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), |
| PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); |
| #else |
| PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), |
| PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); |
| #endif /* PKIX_OBJECT_LEAK_TEST */ |
| |
| /* Attempt to delete an object still being used */ |
| if (objectHeader->references != 0) { |
| PKIX_ERROR_FATAL(PKIX_OBJECTSTILLREFERENCED); |
| } |
| |
| PKIX_DECREF(objectHeader->stringRep); |
| |
| /* Destroy this object's lock */ |
| PKIX_OBJECT_DEBUG("\tCalling PR_DestroyLock).\n"); |
| PR_DestroyLock(objectHeader->lock); |
| objectHeader->lock = NULL; |
| object = NULL; |
| |
| objectHeader->magicHeader = PKIX_MAGIC_HEADER_DESTROYED; |
| |
| #ifdef PKIX_OBJECT_LEAK_TEST |
| memset(objectHeader, 0xbf, systemClasses[PKIX_OBJECT_TYPE].typeObjectSize); |
| #endif |
| |
| PKIX_FREE(objectHeader); |
| |
| cleanup: |
| #ifdef PKIX_OBJECT_LEAK_TEST |
| fatal: |
| #endif |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* --Default-Callbacks-------------------------------------------- */ |
| |
| /* |
| * FUNCTION: pkix_pl_Object_Equals_Default |
| * DESCRIPTION: |
| * |
| * Default Object_Equals callback: Compares the address of the Object pointed |
| * to by "firstObject" with the address of the Object pointed to by |
| * "secondObject" and stores the Boolean result at "pResult". |
| * |
| * PARAMETERS: |
| * "firstObject" |
| * Address of first Object to compare. Must be non-NULL. |
| * "secondObject" |
| * Address of second Object to compare. Must be non-NULL. |
| * "pResult" |
| * Address where Boolean result will be stored. Must be non-NULL. |
| * "plContext" |
| * Platform-specific context pointer. |
| * THREAD SAFETY: |
| * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
| * RETURNS: |
| * Returns NULL if the function succeeds. |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_pl_Object_Equals_Default( |
| PKIX_PL_Object *firstObject, |
| PKIX_PL_Object *secondObject, |
| PKIX_Boolean *pResult, |
| void *plContext) |
| { |
| PKIX_ENTER(OBJECT, "pkix_pl_Object_Equals_Default"); |
| PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); |
| |
| /* Just compare pointer values */ |
| *pResult = (firstObject == secondObject)?PKIX_TRUE:PKIX_FALSE; |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_Object_ToString_Default |
| * DESCRIPTION: |
| * |
| * Default Object_ToString callback: Creates a string consisting of the |
| * typename and address of the Object pointed to by "object" and stores |
| * the result at "pString". The format for the string is |
| * "TypeName@Address: <address>", where the default typename is "Object". |
| * |
| * PARAMETERS: |
| * "object" |
| * Address of Object to convert to a string. Must be non-NULL. |
| * "pString" |
| * Address where object pointer will be stored. Must be non-NULL. |
| * "plContext" |
| * Platform-specific context pointer. |
| * THREAD SAFETY: |
| * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
| * RETURNS: |
| * Returns NULL if the function succeeds. |
| * Returns an Object Error if the function fails in a non-fatal way. |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_pl_Object_ToString_Default( |
| PKIX_PL_Object *object, |
| PKIX_PL_String **pString, |
| void *plContext) |
| { |
| PKIX_PL_String *formatString = NULL; |
| PKIX_PL_String *descString = NULL; |
| char *format = "%s@Address: %x"; |
| char *description = NULL; |
| PKIX_UInt32 objType; |
| |
| PKIX_ENTER(OBJECT, "pkix_pl_Object_ToString_Default"); |
| PKIX_NULLCHECK_TWO(object, pString); |
| |
| PKIX_CHECK(PKIX_PL_Object_GetType(object, &objType, plContext), |
| PKIX_OBJECTGETTYPEFAILED); |
| |
| if (objType >= PKIX_NUMTYPES){ |
| #ifdef PKIX_USER_OBJECT_TYPE |
| pkix_ClassTable_Entry *ctEntry = NULL; |
| |
| PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); |
| PR_Lock(classTableLock); |
| pkixErrorResult = pkix_pl_PrimHashTable_Lookup |
| (classTable, |
| (void *)&objType, |
| objType, |
| NULL, |
| (void **)&ctEntry, |
| plContext); |
| PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); |
| PR_Unlock(classTableLock); |
| if (pkixErrorResult){ |
| PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY); |
| } |
| |
| if (ctEntry == NULL){ |
| PKIX_ERROR_FATAL(PKIX_UNDEFINEDCLASSTABLEENTRY); |
| } else { |
| description = ctEntry->description; |
| if (description == NULL) { |
| description = "User Type Object"; |
| } |
| } |
| #else |
| PORT_Assert (0); |
| pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| goto cleanup; |
| #endif /* PKIX_USER_OBJECT_TYPE */ |
| } else { |
| description = systemClasses[objType].description; |
| } |
| PKIX_CHECK(PKIX_PL_String_Create |
| (PKIX_ESCASCII, |
| (void *)format, |
| 0, |
| &formatString, |
| plContext), |
| PKIX_STRINGCREATEFAILED); |
| |
| PKIX_CHECK(PKIX_PL_String_Create |
| (PKIX_ESCASCII, |
| (void *)description, |
| 0, |
| &descString, |
| plContext), |
| PKIX_STRINGCREATEFAILED); |
| |
| PKIX_CHECK(PKIX_PL_Sprintf |
| (pString, |
| plContext, |
| formatString, |
| descString, |
| object), |
| PKIX_SPRINTFFAILED); |
| |
| cleanup: |
| |
| PKIX_DECREF(formatString); |
| PKIX_DECREF(descString); |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_Object_Hashcode_Default |
| * DESCRIPTION: |
| * |
| * Default Object_Hashcode callback. Creates the a hashcode value using the |
| * address of the Object pointed to by "object" and stores the result at |
| * "pValue". |
| * |
| * XXX This isn't great since addresses are not uniformly distributed. |
| * |
| * PARAMETERS: |
| * "object" |
| * Address of Object to compute hashcode for. Must be non-NULL. |
| * "pValue" |
| * Address where PKIX_UInt32 will be stored. Must be non-NULL. |
| * "plContext" |
| * Platform-specific context pointer. |
| * THREAD SAFETY: |
| * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
| * RETURNS: |
| * Returns NULL if the function succeeds. |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_pl_Object_Hashcode_Default( |
| PKIX_PL_Object *object, |
| PKIX_UInt32 *pValue, |
| void *plContext) |
| { |
| PKIX_ENTER(OBJECT, "pkix_pl_Object_Hashcode_Default"); |
| PKIX_NULLCHECK_TWO(object, pValue); |
| |
| *pValue = (PKIX_UInt32)((char *)object - (char *)NULL); |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_Object_RetrieveEqualsCallback |
| * DESCRIPTION: |
| * |
| * Retrieves Equals callback function of Object pointed to by "object and |
| * stores it at "pEqualsCallback". If the object's type is one of the system |
| * types, its callback function is retrieved from the systemClasses array; |
| * otherwise, its callback function is retrieve from the classTable hash |
| * table where user-defined types are stored. |
| * |
| * PARAMETERS: |
| * "object" |
| * Address of Object whose equals callback is desired. Must be non-NULL. |
| * "pEqualsCallback" |
| * Address where EqualsCallback function pointer will be stored. |
| * Must be non-NULL. |
| * "plContext" |
| * Platform-specific context pointer. |
| * THREAD SAFETY: |
| * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
| * RETURNS: |
| * Returns NULL if the function succeeds. |
| * Returns an Object Error if the function fails in a non-fatal way. |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| PKIX_Error * |
| pkix_pl_Object_RetrieveEqualsCallback( |
| PKIX_PL_Object *object, |
| PKIX_PL_EqualsCallback *pEqualsCallback, |
| void *plContext) |
| { |
| PKIX_PL_Object *objectHeader = NULL; |
| PKIX_PL_EqualsCallback func = NULL; |
| pkix_ClassTable_Entry entry; |
| PKIX_UInt32 objType; |
| |
| PKIX_ENTER(OBJECT, "pkix_pl_Object_RetrieveEqualsCallback"); |
| PKIX_NULLCHECK_TWO(object, pEqualsCallback); |
| |
| PKIX_CHECK(pkix_pl_Object_GetHeader |
| (object, &objectHeader, plContext), |
| PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); |
| |
| objType = objectHeader->type; |
| |
| if (objType >= PKIX_NUMTYPES){ |
| #ifdef PKIX_USER_OBJECT_TYPE |
| pkix_ClassTable_Entry *ctEntry = NULL; |
| |
| PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); |
| PR_Lock(classTableLock); |
| pkixErrorResult = pkix_pl_PrimHashTable_Lookup |
| (classTable, |
| (void *)&objType, |
| objType, |
| NULL, |
| (void **)&ctEntry, |
| plContext); |
| PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); |
| PR_Unlock(classTableLock); |
| if (pkixErrorResult){ |
| PKIX_ERROR(PKIX_ERRORGETTINGCLASSTABLEENTRY); |
| } |
| |
| if ((ctEntry == NULL) || (ctEntry->equalsFunction == NULL)) { |
| PKIX_ERROR(PKIX_UNDEFINEDEQUALSCALLBACK); |
| } else { |
| *pEqualsCallback = ctEntry->equalsFunction; |
| } |
| #else |
| PORT_Assert (0); |
| pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| goto cleanup; |
| #endif /* PKIX_USER_OBJECT_TYPE */ |
| } else { |
| entry = systemClasses[objType]; |
| func = entry.equalsFunction; |
| if (func == NULL){ |
| func = pkix_pl_Object_Equals_Default; |
| } |
| *pEqualsCallback = func; |
| } |
| |
| cleanup: |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_Object_RegisterSelf |
| * DESCRIPTION: |
| * Registers PKIX_OBJECT_TYPE and its related functions with systemClasses[] |
| * THREAD SAFETY: |
| * Not Thread Safe - for performance and complexity reasons |
| * |
| * Since this function is only called by PKIX_PL_Initialize, which should |
| * only be called once, it is acceptable that this function is not |
| * thread-safe. |
| * |
| * PKIX_PL_Object should have all function pointes to be to NULL: they |
| * work as proxy function to a real objects. |
| * |
| */ |
| PKIX_Error * |
| pkix_pl_Object_RegisterSelf(void *plContext) |
| { |
| pkix_ClassTable_Entry entry; |
| |
| PKIX_ENTER(ERROR, "pkix_pl_Object_RegisterSelf"); |
| |
| entry.description = "Object"; |
| entry.objCounter = 0; |
| entry.typeObjectSize = sizeof(PKIX_PL_Object); |
| entry.destructor = NULL; |
| entry.equalsFunction = NULL; |
| entry.hashcodeFunction = NULL; |
| entry.toStringFunction = NULL; |
| entry.comparator = NULL; |
| entry.duplicateFunction = NULL; |
| |
| systemClasses[PKIX_OBJECT_TYPE] = entry; |
| |
| PKIX_RETURN(ERROR); |
| } |
| |
| /* --Public-Functions------------------------------------------------------- */ |
| |
| /* |
| * FUNCTION: PKIX_PL_Object_Alloc (see comments in pkix_pl_system.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_Object_Alloc( |
| PKIX_TYPENUM objType, |
| PKIX_UInt32 size, |
| PKIX_PL_Object **pObject, |
| void *plContext) |
| { |
| PKIX_PL_Object *object = NULL; |
| pkix_ClassTable_Entry *ctEntry = NULL; |
| |
| PKIX_ENTER(OBJECT, "PKIX_PL_Object_Alloc"); |
| PKIX_NULLCHECK_ONE(pObject); |
| |
| /* |
| * We need to ensure that user-defined types have been registered. |
| * All system types have already been registered by PKIX_PL_Initialize. |
| */ |
| |
| if (objType >= PKIX_NUMTYPES) { /* i.e. if this is a user-defined type */ |
| #ifdef PKIX_USER_OBJECT_TYPE |
| PKIX_Boolean typeRegistered; |
| PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); |
| PR_Lock(classTableLock); |
| pkixErrorResult = pkix_pl_PrimHashTable_Lookup |
| (classTable, |
| (void *)&objType, |
| objType, |
| NULL, |
| (void **)&ctEntry, |
| plContext); |
| PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); |
| PR_Unlock(classTableLock); |
| if (pkixErrorResult){ |
| PKIX_ERROR_FATAL(PKIX_COULDNOTLOOKUPINHASHTABLE); |
| } |
| |
| typeRegistered = (ctEntry != NULL); |
| |
| if (!typeRegistered) { |
| PKIX_ERROR_FATAL(PKIX_UNKNOWNTYPEARGUMENT); |
| } |
| #else |
| PORT_Assert (0); |
| pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| goto cleanup; |
| #endif /* PKIX_USER_OBJECT_TYPE */ |
| } else { |
| ctEntry = &systemClasses[objType]; |
| } |
| |
| PORT_Assert(size == ctEntry->typeObjectSize); |
| |
| /* Allocate space for the object header and the requested size */ |
| #ifdef PKIX_OBJECT_LEAK_TEST |
| PKIX_CHECK(PKIX_PL_Calloc |
| (1, |
| ((PKIX_UInt32)sizeof (PKIX_PL_Object))+size, |
| (void **)&object, |
| plContext), |
| PKIX_MALLOCFAILED); |
| #else |
| PKIX_CHECK(PKIX_PL_Malloc |
| (((PKIX_UInt32)sizeof (PKIX_PL_Object))+size, |
| (void **)&object, |
| plContext), |
| PKIX_MALLOCFAILED); |
| #endif /* PKIX_OBJECT_LEAK_TEST */ |
| |
| /* Initialize all object fields */ |
| object->magicHeader = PKIX_MAGIC_HEADER; |
| object->type = objType; |
| object->references = 1; /* Default to a single reference */ |
| object->stringRep = NULL; |
| object->hashcode = 0; |
| object->hashcodeCached = 0; |
| |
| /* Cannot use PKIX_PL_Mutex because it depends on Object */ |
| /* Using NSPR Locks instead */ |
| PKIX_OBJECT_DEBUG("\tCalling PR_NewLock).\n"); |
| object->lock = PR_NewLock(); |
| if (object->lock == NULL) { |
| PKIX_ERROR_ALLOC_ERROR(); |
| } |
| |
| PKIX_OBJECT_DEBUG("\tShifting object pointer).\n"); |
| |
| |
| /* Return a pointer to the user data. Need to offset by object size */ |
| *pObject = object + 1; |
| object = NULL; |
| |
| /* Atomically increment object counter */ |
| PR_ATOMIC_INCREMENT((PRInt32*)&ctEntry->objCounter); |
| |
| cleanup: |
| |
| PKIX_FREE(object); |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* |
| * FUNCTION: PKIX_PL_Object_IsTypeRegistered (see comments in pkix_pl_system.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_Object_IsTypeRegistered( |
| PKIX_UInt32 objType, |
| PKIX_Boolean *pBool, |
| void *plContext) |
| { |
| #ifdef PKIX_USER_OBJECT_TYPE |
| pkix_ClassTable_Entry *ctEntry = NULL; |
| #endif |
| |
| PKIX_ENTER(OBJECT, "PKIX_PL_Object_IsTypeRegistered"); |
| PKIX_NULLCHECK_ONE(pBool); |
| |
| /* first, we handle the system types */ |
| if (objType < PKIX_NUMTYPES) { |
| *pBool = PKIX_TRUE; |
| goto cleanup; |
| } |
| |
| #ifndef PKIX_USER_OBJECT_TYPE |
| PORT_Assert (0); |
| pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| #else |
| PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); |
| PR_Lock(classTableLock); |
| pkixErrorResult = pkix_pl_PrimHashTable_Lookup |
| (classTable, |
| (void *)&objType, |
| objType, |
| NULL, |
| (void **)&ctEntry, |
| plContext); |
| PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); |
| PR_Unlock(classTableLock); |
| |
| if (pkixErrorResult){ |
| PKIX_ERROR_FATAL(PKIX_COULDNOTLOOKUPINHASHTABLE); |
| } |
| |
| *pBool = (ctEntry != NULL); |
| #endif /* PKIX_USER_OBJECT_TYPE */ |
| |
| cleanup: |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| #ifdef PKIX_USER_OBJECT_TYPE |
| /* |
| * FUNCTION: PKIX_PL_Object_RegisterType (see comments in pkix_pl_system.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_Object_RegisterType( |
| PKIX_UInt32 objType, |
| char *description, |
| PKIX_PL_DestructorCallback destructor, |
| PKIX_PL_EqualsCallback equalsFunction, |
| PKIX_PL_HashcodeCallback hashcodeFunction, |
| PKIX_PL_ToStringCallback toStringFunction, |
| PKIX_PL_ComparatorCallback comparator, |
| PKIX_PL_DuplicateCallback duplicateFunction, |
| void *plContext) |
| { |
| pkix_ClassTable_Entry *ctEntry = NULL; |
| pkix_pl_Integer *key = NULL; |
| |
| PKIX_ENTER(OBJECT, "PKIX_PL_Object_RegisterType"); |
| |
| /* |
| * System types are registered on startup by PKIX_PL_Initialize. |
| * These can not be overwritten. |
| */ |
| |
| if (objType < PKIX_NUMTYPES) { /* if this is a system type */ |
| PKIX_ERROR(PKIX_CANTREREGISTERSYSTEMTYPE); |
| } |
| |
| PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); |
| PR_Lock(classTableLock); |
| PKIX_CHECK(pkix_pl_PrimHashTable_Lookup |
| (classTable, |
| (void *)&objType, |
| objType, |
| NULL, |
| (void **)&ctEntry, |
| plContext), |
| PKIX_PRIMHASHTABLELOOKUPFAILED); |
| |
| /* If the type is already registered, throw an error */ |
| if (ctEntry) { |
| PKIX_ERROR(PKIX_TYPEALREADYREGISTERED); |
| } |
| |
| PKIX_CHECK(PKIX_PL_Malloc |
| (((PKIX_UInt32)sizeof (pkix_ClassTable_Entry)), |
| (void **)&ctEntry, |
| plContext), |
| PKIX_MALLOCFAILED); |
| |
| /* Set Default Values if none specified */ |
| |
| if (description == NULL){ |
| description = "Object"; |
| } |
| |
| if (equalsFunction == NULL) { |
| equalsFunction = pkix_pl_Object_Equals_Default; |
| } |
| |
| if (toStringFunction == NULL) { |
| toStringFunction = pkix_pl_Object_ToString_Default; |
| } |
| |
| if (hashcodeFunction == NULL) { |
| hashcodeFunction = pkix_pl_Object_Hashcode_Default; |
| } |
| |
| ctEntry->destructor = destructor; |
| ctEntry->equalsFunction = equalsFunction; |
| ctEntry->toStringFunction = toStringFunction; |
| ctEntry->hashcodeFunction = hashcodeFunction; |
| ctEntry->comparator = comparator; |
| ctEntry->duplicateFunction = duplicateFunction; |
| ctEntry->description = description; |
| |
| PKIX_CHECK(PKIX_PL_Malloc |
| (((PKIX_UInt32)sizeof (pkix_pl_Integer)), |
| (void **)&key, |
| plContext), |
| PKIX_COULDNOTMALLOCNEWKEY); |
| |
| key->ht_int = objType; |
| |
| PKIX_CHECK(pkix_pl_PrimHashTable_Add |
| (classTable, |
| (void *)key, |
| (void *)ctEntry, |
| objType, |
| NULL, |
| plContext), |
| PKIX_PRIMHASHTABLEADDFAILED); |
| |
| cleanup: |
| PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); |
| PR_Unlock(classTableLock); |
| |
| PKIX_RETURN(OBJECT); |
| } |
| #endif /* PKIX_USER_OBJECT_TYPE */ |
| |
| /* |
| * FUNCTION: PKIX_PL_Object_IncRef (see comments in pkix_pl_system.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_Object_IncRef( |
| PKIX_PL_Object *object, |
| void *plContext) |
| { |
| PKIX_PL_Object *objectHeader = NULL; |
| PKIX_PL_NssContext *context = NULL; |
| PKIX_Int32 refCount = 0; |
| |
| PKIX_ENTER(OBJECT, "PKIX_PL_Object_IncRef"); |
| PKIX_NULLCHECK_ONE(object); |
| |
| if (plContext){ |
| /* |
| * PKIX_PL_NssContext is not a complete PKIX Type, it doesn't |
| * have a header therefore we cannot verify its type before |
| * casting. |
| */ |
| context = (PKIX_PL_NssContext *) plContext; |
| if (context->arena != NULL) { |
| goto cleanup; |
| } |
| } |
| |
| if (object == (PKIX_PL_Object*)PKIX_ALLOC_ERROR()) { |
| goto cleanup; |
| } |
| |
| /* Shift pointer from user data to object header */ |
| PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), |
| PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); |
| |
| /* This object should never have zero references */ |
| refCount = PR_ATOMIC_INCREMENT(&objectHeader->references); |
| |
| if (refCount <= 1) { |
| PKIX_THROW(FATAL, PKIX_OBJECTWITHNONPOSITIVEREFERENCES); |
| } |
| |
| cleanup: |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* |
| * FUNCTION: PKIX_PL_Object_DecRef (see comments in pkix_pl_system.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_Object_DecRef( |
| PKIX_PL_Object *object, |
| void *plContext) |
| { |
| PKIX_Int32 refCount = 0; |
| PKIX_PL_Object *objectHeader = NULL; |
| PKIX_PL_NssContext *context = NULL; |
| |
| PKIX_ENTER(OBJECT, "PKIX_PL_Object_DecRef"); |
| PKIX_NULLCHECK_ONE(object); |
| |
| if (plContext){ |
| /* |
| * PKIX_PL_NssContext is not a complete PKIX Type, it doesn't |
| * have a header therefore we cannot verify its type before |
| * casting. |
| */ |
| context = (PKIX_PL_NssContext *) plContext; |
| if (context->arena != NULL) { |
| goto cleanup; |
| } |
| } |
| |
| if (object == (PKIX_PL_Object*)PKIX_ALLOC_ERROR()) { |
| goto cleanup; |
| } |
| |
| /* Shift pointer from user data to object header */ |
| PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), |
| PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); |
| |
| refCount = PR_ATOMIC_DECREMENT(&objectHeader->references); |
| |
| if (refCount == 0) { |
| PKIX_PL_DestructorCallback destructor = NULL; |
| pkix_ClassTable_Entry *ctEntry = NULL; |
| PKIX_UInt32 objType = objectHeader->type; |
| |
| /* first, special handling for system types */ |
| if (objType >= PKIX_NUMTYPES){ |
| #ifdef PKIX_USER_OBJECT_TYPE |
| PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); |
| PR_Lock(classTableLock); |
| pkixErrorResult = pkix_pl_PrimHashTable_Lookup |
| (classTable, |
| (void *)&objType, |
| objType, |
| NULL, |
| (void **)&ctEntry, |
| plContext); |
| PKIX_OBJECT_DEBUG |
| ("\tCalling PR_Unlock).\n"); |
| PR_Unlock(classTableLock); |
| if (pkixErrorResult){ |
| PKIX_ERROR_FATAL |
| (PKIX_ERRORINGETTINGDESTRUCTOR); |
| } |
| |
| if (ctEntry != NULL){ |
| destructor = ctEntry->destructor; |
| } |
| #else |
| PORT_Assert (0); |
| pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| goto cleanup; |
| #endif /* PKIX_USER_OBJECT_TYPE */ |
| } else { |
| ctEntry = &systemClasses[objType]; |
| destructor = ctEntry->destructor; |
| } |
| |
| if (destructor != NULL){ |
| /* Call destructor on user data if necessary */ |
| pkixErrorResult = destructor(object, plContext); |
| if (pkixErrorResult) { |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| PKIX_DoAddError(stdVarsPtr, pkixErrorResult, plContext); |
| pkixErrorResult = NULL; |
| } |
| } |
| |
| /* Atomically decrement object counter */ |
| PR_ATOMIC_DECREMENT((PRInt32*)&ctEntry->objCounter); |
| |
| /* pkix_pl_Object_Destroy assumes the lock is held */ |
| /* It will call unlock and destroy the object */ |
| pkixErrorResult = pkix_pl_Object_Destroy(object, plContext); |
| goto cleanup; |
| } |
| |
| if (refCount < 0) { |
| PKIX_ERROR_ALLOC_ERROR(); |
| } |
| |
| cleanup: |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| |
| |
| /* |
| * FUNCTION: PKIX_PL_Object_Equals (see comments in pkix_pl_system.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_Object_Equals( |
| PKIX_PL_Object *firstObject, |
| PKIX_PL_Object *secondObject, |
| PKIX_Boolean *pResult, |
| void *plContext) |
| { |
| PKIX_PL_Object *firstObjectHeader = NULL; |
| PKIX_PL_Object *secondObjectHeader = NULL; |
| PKIX_PL_EqualsCallback func = NULL; |
| pkix_ClassTable_Entry entry; |
| PKIX_UInt32 objType; |
| |
| PKIX_ENTER(OBJECT, "PKIX_PL_Object_Equals"); |
| PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); |
| |
| PKIX_CHECK(pkix_pl_Object_GetHeader |
| (firstObject, &firstObjectHeader, plContext), |
| PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); |
| |
| PKIX_CHECK(pkix_pl_Object_GetHeader |
| (secondObject, &secondObjectHeader, plContext), |
| PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); |
| |
| /* if hashcodes are cached but not equal, objects can't be equal */ |
| if (firstObjectHeader->hashcodeCached && |
| secondObjectHeader->hashcodeCached){ |
| if (firstObjectHeader->hashcode != |
| secondObjectHeader->hashcode){ |
| *pResult = PKIX_FALSE; |
| goto cleanup; |
| } |
| } |
| |
| objType = firstObjectHeader->type; |
| |
| if (objType >= PKIX_NUMTYPES) { |
| #ifdef PKIX_USER_OBJECT_TYPE |
| pkix_ClassTable_Entry *ctEntry = NULL; |
| PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); |
| PR_Lock(classTableLock); |
| pkixErrorResult = pkix_pl_PrimHashTable_Lookup |
| (classTable, |
| (void *)&firstObjectHeader->type, |
| firstObjectHeader->type, |
| NULL, |
| (void **)&ctEntry, |
| plContext); |
| PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); |
| PR_Unlock(classTableLock); |
| |
| if (pkixErrorResult){ |
| PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY); |
| } |
| |
| if ((ctEntry == NULL) || (ctEntry->equalsFunction == NULL)) { |
| PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK); |
| } else { |
| func = ctEntry->equalsFunction; |
| } |
| #else |
| PORT_Assert (0); |
| pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| goto cleanup; |
| #endif /* PKIX_USER_OBJECT_TYPE */ |
| } else { |
| entry = systemClasses[objType]; |
| func = entry.equalsFunction; |
| if (func == NULL){ |
| func = pkix_pl_Object_Equals_Default; |
| } |
| } |
| |
| PKIX_CHECK(func(firstObject, secondObject, pResult, plContext), |
| PKIX_OBJECTSPECIFICFUNCTIONFAILED); |
| |
| cleanup: |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* |
| * FUNCTION: PKIX_PL_Object_Duplicate (see comments in pkix_pl_system.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_Object_Duplicate( |
| PKIX_PL_Object *firstObject, |
| PKIX_PL_Object **pNewObject, |
| void *plContext) |
| { |
| PKIX_PL_Object *firstObjectHeader = NULL; |
| PKIX_PL_DuplicateCallback func = NULL; |
| pkix_ClassTable_Entry entry; |
| PKIX_UInt32 objType; |
| |
| PKIX_ENTER(OBJECT, "PKIX_PL_Object_Duplicate"); |
| PKIX_NULLCHECK_TWO(firstObject, pNewObject); |
| |
| PKIX_CHECK(pkix_pl_Object_GetHeader |
| (firstObject, &firstObjectHeader, plContext), |
| PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); |
| |
| objType = firstObjectHeader->type; |
| |
| if (objType >= PKIX_NUMTYPES) { |
| #ifdef PKIX_USER_OBJECT_TYPE |
| pkix_ClassTable_Entry *ctEntry = NULL; |
| |
| PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); |
| PR_Lock(classTableLock); |
| pkixErrorResult = pkix_pl_PrimHashTable_Lookup |
| (classTable, |
| (void *)&objType, |
| objType, |
| NULL, |
| (void **)&ctEntry, |
| plContext); |
| PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); |
| PR_Unlock(classTableLock); |
| |
| if (pkixErrorResult){ |
| PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY); |
| } |
| |
| if ((ctEntry == NULL) || (ctEntry->duplicateFunction == NULL)) { |
| PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK); |
| } else { |
| func = ctEntry->duplicateFunction; |
| } |
| #else |
| PORT_Assert (0); |
| pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| goto cleanup; |
| #endif /* PKIX_USER_OBJECT_TYPE */ |
| } else { |
| entry = systemClasses[objType]; |
| func = entry.duplicateFunction; |
| if (!func){ |
| PKIX_ERROR_FATAL(PKIX_UNDEFINEDDUPLICATEFUNCTION); |
| } |
| } |
| |
| PKIX_CHECK(func(firstObject, pNewObject, plContext), |
| PKIX_OBJECTSPECIFICFUNCTIONFAILED); |
| |
| cleanup: |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* |
| * FUNCTION: PKIX_PL_Object_Hashcode (see comments in pkix_pl_system.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_Object_Hashcode( |
| PKIX_PL_Object *object, |
| PKIX_UInt32 *pValue, |
| void *plContext) |
| { |
| PKIX_PL_Object *objectHeader = NULL; |
| PKIX_PL_HashcodeCallback func = NULL; |
| pkix_ClassTable_Entry entry; |
| PKIX_UInt32 objectHash; |
| |
| PKIX_ENTER(OBJECT, "PKIX_PL_Object_Hashcode"); |
| PKIX_NULLCHECK_TWO(object, pValue); |
| |
| /* Shift pointer from user data to object header */ |
| PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), |
| PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); |
| |
| /* if we don't have a cached copy from before, we create one */ |
| if (!objectHeader->hashcodeCached){ |
| |
| PKIX_UInt32 objType = objectHeader->type; |
| |
| /* first, special handling for system types */ |
| if (objType >= PKIX_NUMTYPES){ |
| #ifdef PKIX_USER_OBJECT_TYPE |
| pkix_ClassTable_Entry *ctEntry = NULL; |
| |
| PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); |
| PR_Lock(classTableLock); |
| pkixErrorResult = pkix_pl_PrimHashTable_Lookup |
| (classTable, |
| (void *)&objType, |
| objType, |
| NULL, |
| (void **)&ctEntry, |
| plContext); |
| PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); |
| PR_Unlock(classTableLock); |
| |
| if (pkixErrorResult){ |
| PKIX_ERROR_FATAL |
| (PKIX_ERRORGETTINGCLASSTABLEENTRY); |
| } |
| |
| if ((ctEntry == NULL) || |
| (ctEntry->hashcodeFunction == NULL)) { |
| PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK); |
| } |
| |
| func = ctEntry->hashcodeFunction; |
| #else |
| PORT_Assert (0); |
| pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| goto cleanup; |
| #endif /* PKIX_USER_OBJECT_TYPE */ |
| } else { |
| entry = systemClasses[objType]; |
| func = entry.hashcodeFunction; |
| if (func == NULL){ |
| func = pkix_pl_Object_Hashcode_Default; |
| } |
| } |
| |
| PKIX_CHECK(func(object, &objectHash, plContext), |
| PKIX_OBJECTSPECIFICFUNCTIONFAILED); |
| |
| if (!objectHeader->hashcodeCached){ |
| |
| PKIX_CHECK(pkix_LockObject(object, plContext), |
| PKIX_ERRORLOCKINGOBJECT); |
| |
| if (!objectHeader->hashcodeCached){ |
| /* save cached copy in case we need it again */ |
| objectHeader->hashcode = objectHash; |
| objectHeader->hashcodeCached = PKIX_TRUE; |
| } |
| |
| PKIX_CHECK(pkix_UnlockObject(object, plContext), |
| PKIX_ERRORUNLOCKINGOBJECT); |
| } |
| } |
| |
| *pValue = objectHeader->hashcode; |
| |
| cleanup: |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* |
| * FUNCTION: PKIX_PL_Object_ToString (see comments in pkix_pl_system.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_Object_ToString( |
| PKIX_PL_Object *object, |
| PKIX_PL_String **pString, |
| void *plContext) |
| { |
| PKIX_PL_Object *objectHeader = NULL; |
| PKIX_PL_ToStringCallback func = NULL; |
| pkix_ClassTable_Entry entry; |
| PKIX_PL_String *objectString = NULL; |
| |
| PKIX_ENTER(OBJECT, "PKIX_PL_Object_ToString"); |
| PKIX_NULLCHECK_TWO(object, pString); |
| |
| /* Shift pointer from user data to object header */ |
| PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), |
| PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); |
| |
| /* if we don't have a cached copy from before, we create one */ |
| if (!objectHeader->stringRep){ |
| |
| PKIX_UInt32 objType = objectHeader->type; |
| |
| if (objType >= PKIX_NUMTYPES){ |
| #ifdef PKIX_USER_OBJECT_TYPE |
| pkix_ClassTable_Entry *ctEntry = NULL; |
| |
| PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); |
| PR_Lock(classTableLock); |
| pkixErrorResult = pkix_pl_PrimHashTable_Lookup |
| (classTable, |
| (void *)&objType, |
| objType, |
| NULL, |
| (void **)&ctEntry, |
| plContext); |
| PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); |
| PR_Unlock(classTableLock); |
| if (pkixErrorResult){ |
| PKIX_ERROR_FATAL |
| (PKIX_ERRORGETTINGCLASSTABLEENTRY); |
| } |
| |
| if ((ctEntry == NULL) || |
| (ctEntry->toStringFunction == NULL)) { |
| PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK); |
| } |
| |
| func = ctEntry->toStringFunction; |
| #else |
| PORT_Assert (0); |
| pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| goto cleanup; |
| #endif /* PKIX_USER_OBJECT_TYPE */ |
| } else { |
| entry = systemClasses[objType]; |
| func = entry.toStringFunction; |
| if (func == NULL){ |
| func = pkix_pl_Object_ToString_Default; |
| } |
| } |
| |
| PKIX_CHECK(func(object, &objectString, plContext), |
| PKIX_OBJECTSPECIFICFUNCTIONFAILED); |
| |
| if (!objectHeader->stringRep){ |
| |
| PKIX_CHECK(pkix_LockObject(object, plContext), |
| PKIX_ERRORLOCKINGOBJECT); |
| |
| if (!objectHeader->stringRep){ |
| /* save a cached copy */ |
| objectHeader->stringRep = objectString; |
| objectString = NULL; |
| } |
| |
| PKIX_CHECK(pkix_UnlockObject(object, plContext), |
| PKIX_ERRORUNLOCKINGOBJECT); |
| } |
| } |
| |
| |
| *pString = objectHeader->stringRep; |
| objectHeader->stringRep = NULL; |
| |
| cleanup: |
| if (objectHeader) { |
| PKIX_DECREF(objectHeader->stringRep); |
| } |
| PKIX_DECREF(objectString); |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* |
| * FUNCTION: PKIX_PL_Object_InvalidateCache (see comments in pkix_pl_system.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_Object_InvalidateCache( |
| PKIX_PL_Object *object, |
| void *plContext) |
| { |
| PKIX_PL_Object *objectHeader = NULL; |
| |
| PKIX_ENTER(OBJECT, "PKIX_PL_Object_InvalidateCache"); |
| PKIX_NULLCHECK_ONE(object); |
| |
| /* Shift pointer from user data to object header */ |
| PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), |
| PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); |
| |
| PKIX_CHECK(pkix_LockObject(object, plContext), |
| PKIX_ERRORLOCKINGOBJECT); |
| |
| /* invalidate hashcode */ |
| objectHeader->hashcode = 0; |
| objectHeader->hashcodeCached = PKIX_FALSE; |
| |
| PKIX_DECREF(objectHeader->stringRep); |
| |
| PKIX_CHECK(pkix_UnlockObject(object, plContext), |
| PKIX_ERRORUNLOCKINGOBJECT); |
| |
| cleanup: |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* |
| * FUNCTION: PKIX_PL_Object_Compare (see comments in pkix_pl_system.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_Object_Compare( |
| PKIX_PL_Object *firstObject, |
| PKIX_PL_Object *secondObject, |
| PKIX_Int32 *pResult, |
| void *plContext) |
| { |
| PKIX_PL_Object *firstObjectHeader = NULL; |
| PKIX_PL_Object *secondObjectHeader = NULL; |
| PKIX_PL_ComparatorCallback func = NULL; |
| pkix_ClassTable_Entry entry; |
| PKIX_UInt32 objType; |
| |
| PKIX_ENTER(OBJECT, "PKIX_PL_Object_Compare"); |
| PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); |
| |
| /* Shift pointer from user data to object header */ |
| PKIX_CHECK(pkix_pl_Object_GetHeader |
| (firstObject, &firstObjectHeader, plContext), |
| PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); |
| |
| /* Shift pointer from user data to object header */ |
| PKIX_CHECK(pkix_pl_Object_GetHeader |
| (secondObject, &secondObjectHeader, plContext), |
| PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); |
| |
| objType = firstObjectHeader->type; |
| |
| if (objType >= PKIX_NUMTYPES){ |
| #ifdef PKIX_USER_OBJECT_TYPE |
| pkix_ClassTable_Entry *ctEntry = NULL; |
| |
| PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); |
| PR_Lock(classTableLock); |
| pkixErrorResult = pkix_pl_PrimHashTable_Lookup |
| (classTable, |
| (void *)&objType, |
| objType, |
| NULL, |
| (void **)&ctEntry, |
| plContext); |
| PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); |
| PR_Unlock(classTableLock); |
| if (pkixErrorResult){ |
| PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY); |
| } |
| |
| if ((ctEntry == NULL) || (ctEntry->comparator == NULL)) { |
| PKIX_ERROR_FATAL(PKIX_UNDEFINEDCOMPARATOR); |
| } |
| |
| func = ctEntry->comparator; |
| #else |
| PORT_Assert (0); |
| pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| goto cleanup; |
| #endif /* PKIX_USER_OBJECT_TYPE */ |
| } else { |
| /* special handling for system types */ |
| entry = systemClasses[objType]; |
| func = entry.comparator; |
| if (!func){ |
| PKIX_ERROR(PKIX_UNDEFINEDCOMPARATOR); |
| } |
| } |
| |
| PKIX_CHECK(func(firstObject, secondObject, pResult, plContext), |
| PKIX_OBJECTSPECIFICFUNCTIONFAILED); |
| |
| cleanup: |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* |
| * FUNCTION: PKIX_PL_Object_Lock (see comments in pkix_pl_system.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_Object_Lock( |
| PKIX_PL_Object *object, |
| void *plContext) |
| { |
| PKIX_ENTER(OBJECT, "PKIX_PL_Object_Lock"); |
| PKIX_NULLCHECK_ONE(object); |
| |
| PKIX_CHECK(pkix_LockObject(object, plContext), |
| PKIX_LOCKOBJECTFAILED); |
| |
| cleanup: |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| /* |
| * FUNCTION: PKIX_PL_Object_Unlock (see comments in pkix_pl_system.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_Object_Unlock( |
| PKIX_PL_Object *object, |
| void *plContext) |
| { |
| PKIX_ENTER(OBJECT, "PKIX_PL_Object_Unlock"); |
| PKIX_NULLCHECK_ONE(object); |
| |
| PKIX_CHECK(pkix_UnlockObject(object, plContext), |
| PKIX_UNLOCKOBJECTFAILED); |
| |
| cleanup: |
| |
| PKIX_RETURN(OBJECT); |
| } |
| |
| |
| /* |
| * FUNCTION: PKIX_PL_Object_GetType (see comments in pkix_pl_system.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_Object_GetType( |
| PKIX_PL_Object *object, |
| PKIX_UInt32 *pType, |
| void *plContext) |
| { |
| PKIX_PL_Object *objectHeader = NULL; |
| |
| PKIX_ENTER(OBJECT, "PKIX_PL_Object_GetType"); |
| PKIX_NULLCHECK_TWO(object, pType); |
| |
| /* Shift pointer from user data to object header */ |
| PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), |
| PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); |
| |
| *pType = objectHeader->type; |
| |
| cleanup: |
| |
| PKIX_RETURN(OBJECT); |
| } |