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