import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,11 @@
#
# 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/.
include manifest.mn
include $(CORE_DEPTH)/coreconf/config.mk
include config.mk
include $(CORE_DEPTH)/coreconf/rules.mk
export:: private_export

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,32 @@
# 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/.
{
'includes': [
'../../coreconf/config.gypi'
],
'targets': [
{
'target_name': 'nssb',
'type': 'static_library',
'sources': [
'arena.c',
'error.c',
'errorval.c',
'hash.c',
'hashops.c',
'item.c',
'libc.c',
'list.c',
'tracker.c',
'utf8.c'
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports'
]
}
],
'variables': {
'module': 'nss'
}
}

1106
security/nss/lib/base/base.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,124 @@
/* 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/. */
#ifndef BASET_H
#define BASET_H
/*
* baset.h
*
* This file contains definitions for the basic types used throughout
* nss but not available publicly.
*/
#ifndef NSSBASET_H
#include "nssbaset.h"
#endif /* NSSBASET_H */
#include "plhash.h"
PR_BEGIN_EXTERN_C
/*
* nssArenaMark
*
* This type is used to mark the current state of an NSSArena.
*/
struct nssArenaMarkStr;
typedef struct nssArenaMarkStr nssArenaMark;
#ifdef DEBUG
/*
* ARENA_THREADMARK
*
* Optionally, this arena implementation can be compiled with some
* runtime checking enabled, which will catch the situation where
* one thread "marks" the arena, another thread allocates memory,
* and then the mark is released. Usually this is a surprise to
* the second thread, and this leads to weird runtime errors.
* Define ARENA_THREADMARK to catch these cases; we define it for all
* (internal and external) debug builds.
*/
#define ARENA_THREADMARK
/*
* ARENA_DESTRUCTOR_LIST
*
* Unfortunately, our pointer-tracker facility, used in debug
* builds to agressively fight invalid pointers, requries that
* pointers be deregistered when objects are destroyed. This
* conflicts with the standard arena usage where "memory-only"
* objects (that don't hold onto resources outside the arena)
* can be allocated in an arena, and never destroyed other than
* when the arena is destroyed. Therefore we have added a
* destructor-registratio facility to our arenas. This was not
* a simple decision, since we're getting ever-further away from
* the original arena philosophy. However, it was felt that
* adding this in debug builds wouldn't be so bad; as it would
* discourage them from being used for "serious" purposes.
* This facility requires ARENA_THREADMARK to be defined.
*/
#ifdef ARENA_THREADMARK
#define ARENA_DESTRUCTOR_LIST
#endif /* ARENA_THREADMARK */
#endif /* DEBUG */
typedef struct nssListStr nssList;
typedef struct nssListIteratorStr nssListIterator;
typedef PRBool (*nssListCompareFunc)(void *a, void *b);
typedef PRIntn (*nssListSortFunc)(void *a, void *b);
typedef void (*nssListElementDestructorFunc)(void *el);
typedef struct nssHashStr nssHash;
typedef void(PR_CALLBACK *nssHashIterator)(const void *key, void *value,
void *arg);
/*
* nssPointerTracker
*
* This type is used in debug builds (both external and internal) to
* track our object pointers. Objects of this type must be statically
* allocated, which means the structure size must be available to the
* compiler. Therefore we must expose the contents of this structure.
* But please don't access elements directly; use the accessors.
*/
#ifdef DEBUG
struct nssPointerTrackerStr {
PRCallOnceType once;
PZLock *lock;
PLHashTable *table;
};
typedef struct nssPointerTrackerStr nssPointerTracker;
#endif /* DEBUG */
/*
* nssStringType
*
* There are several types of strings in the real world. We try to
* use only UTF8 and avoid the rest, but that's not always possible.
* So we have a couple converter routines to go to and from the other
* string types. We have to be able to specify those string types,
* so we have this enumeration.
*/
enum nssStringTypeEnum {
nssStringType_DirectoryString,
nssStringType_TeletexString, /* Not "teletext" with trailing 't' */
nssStringType_PrintableString,
nssStringType_UniversalString,
nssStringType_BMPString,
nssStringType_UTF8String,
nssStringType_PHGString,
nssStringType_GeneralString,
nssStringType_Unknown = -1
};
typedef enum nssStringTypeEnum nssStringType;
PR_END_EXTERN_C
#endif /* BASET_H */

View file

@ -0,0 +1,19 @@
#
# 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/.
ifdef BUILD_IDG
DEFINES += -DNSSDEBUG
endif
#
# Override TARGETS variable so that only static libraries
# are specifed as dependencies within rules.mk.
#
TARGETS = $(LIBRARY)
SHARED_LIBRARY =
IMPORT_LIBRARY =
PROGRAM =

View file

@ -0,0 +1,269 @@
/* 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/. */
/*
* error.c
*
* This file contains the code implementing the per-thread error
* stacks upon which most NSS routines report their errors.
*/
#ifndef BASE_H
#include "base.h"
#endif /* BASE_H */
#include <limits.h> /* for UINT_MAX */
#include <string.h> /* for memmove */
#define NSS_MAX_ERROR_STACK_COUNT 16 /* error codes */
/*
* The stack itself has a header, and a sequence of integers.
* The header records the amount of space (as measured in stack
* slots) already allocated for the stack, and the count of the
* number of records currently being used.
*/
struct stack_header_str {
PRUint16 space;
PRUint16 count;
};
struct error_stack_str {
struct stack_header_str header;
PRInt32 stack[1];
};
typedef struct error_stack_str error_stack;
/*
* error_stack_index
*
* Thread-private data must be indexed. This is that index.
* See PR_NewThreadPrivateIndex for more information.
*
* Thread-private data indexes are in the range [0, 127].
*/
#define INVALID_TPD_INDEX UINT_MAX
static PRUintn error_stack_index = INVALID_TPD_INDEX;
/*
* call_once
*
* The thread-private index must be obtained (once!) at runtime.
* This block is used for that one-time call.
*/
static PRCallOnceType error_call_once;
/*
* error_once_function
*
* This is the once-called callback.
*/
static PRStatus
error_once_function(void)
{
return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free);
}
/*
* error_get_my_stack
*
* This routine returns the calling thread's error stack, creating
* it if necessary. It may return NULL upon error, which implicitly
* means that it ran out of memory.
*/
static error_stack *
error_get_my_stack(void)
{
PRStatus st;
error_stack *rv;
PRUintn new_size;
PRUint32 new_bytes;
error_stack *new_stack;
if (INVALID_TPD_INDEX == error_stack_index) {
st = PR_CallOnce(&error_call_once, error_once_function);
if (PR_SUCCESS != st) {
return (error_stack *)NULL;
}
}
rv = (error_stack *)PR_GetThreadPrivate(error_stack_index);
if ((error_stack *)NULL == rv) {
/* Doesn't exist; create one */
new_size = 16;
} else if (rv->header.count == rv->header.space &&
rv->header.count < NSS_MAX_ERROR_STACK_COUNT) {
/* Too small, expand it */
new_size = PR_MIN(rv->header.space * 2, NSS_MAX_ERROR_STACK_COUNT);
} else {
/* Okay, return it */
return rv;
}
new_bytes = (new_size * sizeof(PRInt32)) + sizeof(error_stack);
/* Use NSPR's calloc/realloc, not NSS's, to avoid loops! */
new_stack = PR_Calloc(1, new_bytes);
if ((error_stack *)NULL != new_stack) {
if ((error_stack *)NULL != rv) {
(void)nsslibc_memcpy(new_stack, rv, rv->header.space);
}
new_stack->header.space = new_size;
}
/* Set the value, whether or not the allocation worked */
PR_SetThreadPrivate(error_stack_index, new_stack);
return new_stack;
}
/*
* The error stack
*
* The public methods relating to the error stack are:
*
* NSS_GetError
* NSS_GetErrorStack
*
* The nonpublic methods relating to the error stack are:
*
* nss_SetError
* nss_ClearErrorStack
*
*/
/*
* NSS_GetError
*
* This routine returns the highest-level (most general) error set
* by the most recent NSS library routine called by the same thread
* calling this routine.
*
* This routine cannot fail. However, it may return zero, which
* indicates that the previous NSS library call did not set an error.
*
* Return value:
* 0 if no error has been set
* A nonzero error number
*/
NSS_IMPLEMENT PRInt32
NSS_GetError(void)
{
error_stack *es = error_get_my_stack();
if ((error_stack *)NULL == es) {
return NSS_ERROR_NO_MEMORY; /* Good guess! */
}
if (0 == es->header.count) {
return 0;
}
return es->stack[es->header.count - 1];
}
/*
* NSS_GetErrorStack
*
* This routine returns a pointer to an array of integers, containing
* the entire sequence or "stack" of errors set by the most recent NSS
* library routine called by the same thread calling this routine.
* NOTE: the caller DOES NOT OWN the memory pointed to by the return
* value. The pointer will remain valid until the calling thread
* calls another NSS routine. The lowest-level (most specific) error
* is first in the array, and the highest-level is last. The array is
* zero-terminated. This routine may return NULL upon error; this
* indicates a low-memory situation.
*
* Return value:
* NULL upon error, which is an implied NSS_ERROR_NO_MEMORY
* A NON-caller-owned pointer to an array of integers
*/
NSS_IMPLEMENT PRInt32 *
NSS_GetErrorStack(void)
{
error_stack *es = error_get_my_stack();
if ((error_stack *)NULL == es) {
return (PRInt32 *)NULL;
}
/* Make sure it's terminated */
es->stack[es->header.count] = 0;
return es->stack;
}
/*
* nss_SetError
*
* This routine places a new error code on the top of the calling
* thread's error stack. Calling this routine wiht an error code
* of zero will clear the error stack.
*/
NSS_IMPLEMENT void
nss_SetError(PRUint32 error)
{
error_stack *es;
if (0 == error) {
nss_ClearErrorStack();
return;
}
es = error_get_my_stack();
if ((error_stack *)NULL == es) {
/* Oh, well. */
return;
}
if (es->header.count < es->header.space) {
es->stack[es->header.count++] = error;
} else {
memmove(es->stack, es->stack + 1,
(es->header.space - 1) * (sizeof es->stack[0]));
es->stack[es->header.space - 1] = error;
}
return;
}
/*
* nss_ClearErrorStack
*
* This routine clears the calling thread's error stack.
*/
NSS_IMPLEMENT void
nss_ClearErrorStack(void)
{
error_stack *es = error_get_my_stack();
if ((error_stack *)NULL == es) {
/* Oh, well. */
return;
}
es->header.count = 0;
es->stack[0] = 0;
return;
}
/*
* nss_DestroyErrorStack
*
* This routine frees the calling thread's error stack.
*/
NSS_IMPLEMENT void
nss_DestroyErrorStack(void)
{
if (INVALID_TPD_INDEX != error_stack_index) {
PR_SetThreadPrivate(error_stack_index, NULL);
}
return;
}

View file

@ -0,0 +1,65 @@
/* 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/. */
/*
* errorval.c
*
* This file contains the actual error constants used in NSS.
*/
#ifndef NSSBASET_H
#include "nssbaset.h"
#endif /* NSSBASET_H */
/* clang-format off */
const NSSError NSS_ERROR_NO_ERROR = 0;
const NSSError NSS_ERROR_INTERNAL_ERROR = 1;
const NSSError NSS_ERROR_NO_MEMORY = 2;
const NSSError NSS_ERROR_INVALID_POINTER = 3;
const NSSError NSS_ERROR_INVALID_ARENA = 4;
const NSSError NSS_ERROR_INVALID_ARENA_MARK = 5;
const NSSError NSS_ERROR_DUPLICATE_POINTER = 6;
const NSSError NSS_ERROR_POINTER_NOT_REGISTERED = 7;
const NSSError NSS_ERROR_TRACKER_NOT_EMPTY = 8;
const NSSError NSS_ERROR_TRACKER_NOT_INITIALIZED = 9;
const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD = 10;
const NSSError NSS_ERROR_VALUE_TOO_LARGE = 11;
const NSSError NSS_ERROR_UNSUPPORTED_TYPE = 12;
const NSSError NSS_ERROR_BUFFER_TOO_SHORT = 13;
const NSSError NSS_ERROR_INVALID_ATOB_CONTEXT = 14;
const NSSError NSS_ERROR_INVALID_BASE64 = 15;
const NSSError NSS_ERROR_INVALID_BTOA_CONTEXT = 16;
const NSSError NSS_ERROR_INVALID_ITEM = 17;
const NSSError NSS_ERROR_INVALID_STRING = 18;
const NSSError NSS_ERROR_INVALID_ASN1ENCODER = 19;
const NSSError NSS_ERROR_INVALID_ASN1DECODER = 20;
const NSSError NSS_ERROR_INVALID_BER = 21;
const NSSError NSS_ERROR_INVALID_ATAV = 22;
const NSSError NSS_ERROR_INVALID_ARGUMENT = 23;
const NSSError NSS_ERROR_INVALID_UTF8 = 24;
const NSSError NSS_ERROR_INVALID_NSSOID = 25;
const NSSError NSS_ERROR_UNKNOWN_ATTRIBUTE = 26;
const NSSError NSS_ERROR_NOT_FOUND = 27;
const NSSError NSS_ERROR_INVALID_PASSWORD = 28;
const NSSError NSS_ERROR_USER_CANCELED = 29;
const NSSError NSS_ERROR_MAXIMUM_FOUND = 30;
const NSSError NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND = 31;
const NSSError NSS_ERROR_CERTIFICATE_IN_CACHE = 32;
const NSSError NSS_ERROR_HASH_COLLISION = 33;
const NSSError NSS_ERROR_DEVICE_ERROR = 34;
const NSSError NSS_ERROR_INVALID_CERTIFICATE = 35;
const NSSError NSS_ERROR_BUSY = 36;
const NSSError NSS_ERROR_ALREADY_INITIALIZED = 37;
const NSSError NSS_ERROR_PKCS11 = 38;
/* clang-format on */

View file

@ -0,0 +1,33 @@
# 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/.
{
'includes': [
'../../coreconf/config.gypi'
],
'targets': [
{
'target_name': 'lib_base_exports',
'type': 'none',
'copies': [
{
'files': [
'nssbase.h',
'nssbaset.h'
],
'destination': '<(nss_public_dist_dir)/<(module)'
},
{
'files': [
'base.h',
'baset.h'
],
'destination': '<(nss_private_dist_dir)/<(module)'
}
]
}
],
'variables': {
'module': 'nss'
}
}

View file

@ -0,0 +1,314 @@
/* 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/. */
/*
* hash.c
*
* This is merely a couple wrappers around NSPR's PLHashTable, using
* the identity hash and arena-aware allocators.
* This is a copy of ckfw/hash.c, with modifications to use NSS types
* (not Cryptoki types). Would like for this to be a single implementation,
* but doesn't seem like it will work.
*/
#ifndef BASE_H
#include "base.h"
#endif /* BASE_H */
#include "prbit.h"
/*
* nssHash
*
* nssHash_Create
* nssHash_Destroy
* nssHash_Add
* nssHash_Remove
* nssHash_Count
* nssHash_Exists
* nssHash_Lookup
* nssHash_Iterate
*/
struct nssHashStr {
NSSArena *arena;
PRBool i_alloced_arena;
PRLock *mutex;
/*
* The invariant that mutex protects is:
* The count accurately reflects the hashtable state.
*/
PLHashTable *plHashTable;
PRUint32 count;
};
static PLHashNumber
nss_identity_hash(const void *key)
{
return (PLHashNumber)((char *)key - (char *)NULL);
}
static PLHashNumber
nss_item_hash(const void *key)
{
unsigned int i;
PLHashNumber h;
NSSItem *it = (NSSItem *)key;
h = 0;
for (i = 0; i < it->size; i++)
h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)it->data)[i];
return h;
}
static int
nss_compare_items(const void *v1, const void *v2)
{
PRStatus ignore;
return (int)nssItem_Equal((NSSItem *)v1, (NSSItem *)v2, &ignore);
}
/*
* nssHash_create
*
*/
NSS_IMPLEMENT nssHash *
nssHash_Create(NSSArena *arenaOpt, PRUint32 numBuckets, PLHashFunction keyHash,
PLHashComparator keyCompare, PLHashComparator valueCompare)
{
nssHash *rv;
NSSArena *arena;
PRBool i_alloced;
#ifdef NSSDEBUG
if (arenaOpt && PR_SUCCESS != nssArena_verifyPointer(arenaOpt)) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
return (nssHash *)NULL;
}
#endif /* NSSDEBUG */
if (arenaOpt) {
arena = arenaOpt;
i_alloced = PR_FALSE;
} else {
arena = nssArena_Create();
i_alloced = PR_TRUE;
}
rv = nss_ZNEW(arena, nssHash);
if ((nssHash *)NULL == rv) {
goto loser;
}
rv->mutex = PZ_NewLock(nssILockOther);
if ((PZLock *)NULL == rv->mutex) {
goto loser;
}
rv->plHashTable =
PL_NewHashTable(numBuckets, keyHash, keyCompare, valueCompare,
&nssArenaHashAllocOps, arena);
if ((PLHashTable *)NULL == rv->plHashTable) {
(void)PZ_DestroyLock(rv->mutex);
goto loser;
}
rv->count = 0;
rv->arena = arena;
rv->i_alloced_arena = i_alloced;
return rv;
loser:
(void)nss_ZFreeIf(rv);
return (nssHash *)NULL;
}
/*
* nssHash_CreatePointer
*
*/
NSS_IMPLEMENT nssHash *
nssHash_CreatePointer(NSSArena *arenaOpt, PRUint32 numBuckets)
{
return nssHash_Create(arenaOpt, numBuckets, nss_identity_hash,
PL_CompareValues, PL_CompareValues);
}
/*
* nssHash_CreateString
*
*/
NSS_IMPLEMENT nssHash *
nssHash_CreateString(NSSArena *arenaOpt, PRUint32 numBuckets)
{
return nssHash_Create(arenaOpt, numBuckets, PL_HashString,
PL_CompareStrings, PL_CompareStrings);
}
/*
* nssHash_CreateItem
*
*/
NSS_IMPLEMENT nssHash *
nssHash_CreateItem(NSSArena *arenaOpt, PRUint32 numBuckets)
{
return nssHash_Create(arenaOpt, numBuckets, nss_item_hash,
nss_compare_items, PL_CompareValues);
}
/*
* nssHash_Destroy
*
*/
NSS_IMPLEMENT void
nssHash_Destroy(nssHash *hash)
{
(void)PZ_DestroyLock(hash->mutex);
PL_HashTableDestroy(hash->plHashTable);
if (hash->i_alloced_arena) {
nssArena_Destroy(hash->arena);
} else {
nss_ZFreeIf(hash);
}
}
/*
* nssHash_Add
*
*/
NSS_IMPLEMENT PRStatus
nssHash_Add(nssHash *hash, const void *key, const void *value)
{
PRStatus error = PR_FAILURE;
PLHashEntry *he;
PZ_Lock(hash->mutex);
he = PL_HashTableAdd(hash->plHashTable, key, (void *)value);
if ((PLHashEntry *)NULL == he) {
nss_SetError(NSS_ERROR_NO_MEMORY);
} else if (he->value != value) {
nss_SetError(NSS_ERROR_HASH_COLLISION);
} else {
hash->count++;
error = PR_SUCCESS;
}
(void)PZ_Unlock(hash->mutex);
return error;
}
/*
* nssHash_Remove
*
*/
NSS_IMPLEMENT void
nssHash_Remove(nssHash *hash, const void *it)
{
PRBool found;
PZ_Lock(hash->mutex);
found = PL_HashTableRemove(hash->plHashTable, it);
if (found) {
hash->count--;
}
(void)PZ_Unlock(hash->mutex);
return;
}
/*
* nssHash_Count
*
*/
NSS_IMPLEMENT PRUint32
nssHash_Count(nssHash *hash)
{
PRUint32 count;
PZ_Lock(hash->mutex);
count = hash->count;
(void)PZ_Unlock(hash->mutex);
return count;
}
/*
* nssHash_Exists
*
*/
NSS_IMPLEMENT PRBool
nssHash_Exists(nssHash *hash, const void *it)
{
void *value;
PZ_Lock(hash->mutex);
value = PL_HashTableLookup(hash->plHashTable, it);
(void)PZ_Unlock(hash->mutex);
if ((void *)NULL == value) {
return PR_FALSE;
} else {
return PR_TRUE;
}
}
/*
* nssHash_Lookup
*
*/
NSS_IMPLEMENT void *
nssHash_Lookup(nssHash *hash, const void *it)
{
void *rv;
PZ_Lock(hash->mutex);
rv = PL_HashTableLookup(hash->plHashTable, it);
(void)PZ_Unlock(hash->mutex);
return rv;
}
struct arg_str {
nssHashIterator fcn;
void *closure;
};
static PRIntn
nss_hash_enumerator(PLHashEntry *he, PRIntn index, void *arg)
{
struct arg_str *as = (struct arg_str *)arg;
as->fcn(he->key, he->value, as->closure);
return HT_ENUMERATE_NEXT;
}
/*
* nssHash_Iterate
*
* NOTE that the iteration function will be called with the hashtable locked.
*/
NSS_IMPLEMENT void
nssHash_Iterate(nssHash *hash, nssHashIterator fcn, void *closure)
{
struct arg_str as;
as.fcn = fcn;
as.closure = closure;
PZ_Lock(hash->mutex);
PL_HashTableEnumerateEntries(hash->plHashTable, nss_hash_enumerator, &as);
(void)PZ_Unlock(hash->mutex);
return;
}

View file

@ -0,0 +1,64 @@
/* 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/. */
/*
* hashops.c
*
* This file includes a set of PLHashAllocOps that use NSSArenas.
*/
#ifndef BASE_H
#include "base.h"
#endif /* BASE_H */
static void *PR_CALLBACK
nss_arena_hash_alloc_table(void *pool, PRSize size)
{
NSSArena *arena = (NSSArena *)NULL;
#ifdef NSSDEBUG
if ((void *)NULL != arena) {
if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
return (void *)NULL;
}
}
#endif /* NSSDEBUG */
return nss_ZAlloc(arena, size);
}
static void PR_CALLBACK
nss_arena_hash_free_table(void *pool, void *item)
{
(void)nss_ZFreeIf(item);
}
static PLHashEntry *PR_CALLBACK
nss_arena_hash_alloc_entry(void *pool, const void *key)
{
NSSArena *arena = NULL;
#ifdef NSSDEBUG
if ((void *)NULL != arena) {
if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
return (void *)NULL;
}
}
#endif /* NSSDEBUG */
return nss_ZNEW(arena, PLHashEntry);
}
static void PR_CALLBACK
nss_arena_hash_free_entry(void *pool, PLHashEntry *he, PRUintn flag)
{
if (HT_FREE_ENTRY == flag) {
(void)nss_ZFreeIf(he);
}
}
NSS_IMPLEMENT_DATA PLHashAllocOps nssArenaHashAllocOps = {
nss_arena_hash_alloc_table, nss_arena_hash_free_table,
nss_arena_hash_alloc_entry, nss_arena_hash_free_entry
};

View file

@ -0,0 +1,186 @@
/* 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/. */
/*
* item.c
*
* This contains some item-manipulation code.
*/
#ifndef BASE_H
#include "base.h"
#endif /* BASE_H */
/*
* nssItem_Create
*
* -- fgmr comments --
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ARENA
* NSS_ERROR_NO_MEMORY
* NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
* NSS_ERROR_INVALID_POINTER
*
* Return value:
* A pointer to an NSSItem upon success
* NULL upon failure
*/
NSS_IMPLEMENT NSSItem *
nssItem_Create(NSSArena *arenaOpt, NSSItem *rvOpt, PRUint32 length,
const void *data)
{
NSSItem *rv = (NSSItem *)NULL;
#ifdef DEBUG
if ((NSSArena *)NULL != arenaOpt) {
if (PR_SUCCESS != nssArena_verifyPointer(arenaOpt)) {
return (NSSItem *)NULL;
}
}
if ((const void *)NULL == data) {
if (length > 0) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
return (NSSItem *)NULL;
}
}
#endif /* DEBUG */
if ((NSSItem *)NULL == rvOpt) {
rv = (NSSItem *)nss_ZNEW(arenaOpt, NSSItem);
if ((NSSItem *)NULL == rv) {
goto loser;
}
} else {
rv = rvOpt;
}
rv->size = length;
rv->data = nss_ZAlloc(arenaOpt, length);
if ((void *)NULL == rv->data) {
goto loser;
}
if (length > 0) {
(void)nsslibc_memcpy(rv->data, data, length);
}
return rv;
loser:
if (rv != rvOpt) {
nss_ZFreeIf(rv);
}
return (NSSItem *)NULL;
}
NSS_IMPLEMENT void
nssItem_Destroy(NSSItem *item)
{
nss_ClearErrorStack();
nss_ZFreeIf(item->data);
nss_ZFreeIf(item);
}
/*
* nssItem_Duplicate
*
* -- fgmr comments --
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ARENA
* NSS_ERROR_NO_MEMORY
* NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
* NSS_ERROR_INVALID_ITEM
*
* Return value:
* A pointer to an NSSItem upon success
* NULL upon failure
*/
NSS_IMPLEMENT NSSItem *
nssItem_Duplicate(NSSItem *obj, NSSArena *arenaOpt, NSSItem *rvOpt)
{
#ifdef DEBUG
if ((NSSArena *)NULL != arenaOpt) {
if (PR_SUCCESS != nssArena_verifyPointer(arenaOpt)) {
return (NSSItem *)NULL;
}
}
if ((NSSItem *)NULL == obj) {
nss_SetError(NSS_ERROR_INVALID_ITEM);
return (NSSItem *)NULL;
}
#endif /* DEBUG */
return nssItem_Create(arenaOpt, rvOpt, obj->size, obj->data);
}
#ifdef DEBUG
/*
* nssItem_verifyPointer
*
* -- fgmr comments --
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ITEM
*
* Return value:
* PR_SUCCESS upon success
* PR_FAILURE upon failure
*/
NSS_IMPLEMENT PRStatus
nssItem_verifyPointer(const NSSItem *item)
{
if (((const NSSItem *)NULL == item) ||
(((void *)NULL == item->data) && (item->size > 0))) {
nss_SetError(NSS_ERROR_INVALID_ITEM);
return PR_FAILURE;
}
return PR_SUCCESS;
}
#endif /* DEBUG */
/*
* nssItem_Equal
*
* -- fgmr comments --
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ITEM
*
* Return value:
* PR_TRUE if the items are identical
* PR_FALSE if they aren't
* PR_FALSE upon error
*/
NSS_IMPLEMENT PRBool
nssItem_Equal(const NSSItem *one, const NSSItem *two, PRStatus *statusOpt)
{
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_SUCCESS;
}
if (((const NSSItem *)NULL == one) && ((const NSSItem *)NULL == two)) {
return PR_TRUE;
}
if (((const NSSItem *)NULL == one) || ((const NSSItem *)NULL == two)) {
return PR_FALSE;
}
if (one->size != two->size) {
return PR_FALSE;
}
return nsslibc_memequal(one->data, two->data, one->size, statusOpt);
}

View file

@ -0,0 +1,143 @@
/* 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/. */
/*
* libc.c
*
* This file contains our wrappers/reimplementations for "standard"
* libc functions. Things like "memcpy." We add to this as we need
* it. Oh, and let's keep it in alphabetical order, should it ever
* get large. Most string/character stuff should be in utf8.c, not
* here. This file (and maybe utf8.c) should be the only ones in
* NSS to include files with angle brackets.
*/
#ifndef BASE_H
#include "base.h"
#endif /* BASE_H */
#include <string.h> /* memcpy, memset */
/*
* nsslibc_memcpy
* nsslibc_memset
* nsslibc_offsetof
* nsslibc_memequal
*/
/*
* nsslibc_memcpy
*
* Errors:
* NSS_ERROR_INVALID_POINTER
*
* Return value:
* NULL on error
* The destination pointer on success
*/
NSS_IMPLEMENT void *
nsslibc_memcpy(void *dest, const void *source, PRUint32 n)
{
#ifdef NSSDEBUG
if (((void *)NULL == dest) || ((const void *)NULL == source)) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
return (void *)NULL;
}
#endif /* NSSDEBUG */
return memcpy(dest, source, (size_t)n);
}
/*
* nsslibc_memset
*
* Errors:
* NSS_ERROR_INVALID_POINTER
*
* Return value:
* NULL on error
* The destination pointer on success
*/
NSS_IMPLEMENT void *
nsslibc_memset(void *dest, PRUint8 byte, PRUint32 n)
{
#ifdef NSSDEBUG
if (((void *)NULL == dest)) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
return (void *)NULL;
}
#endif /* NSSDEBUG */
return memset(dest, (int)byte, (size_t)n);
}
/*
* nsslibc_memequal
*
* Errors:
* NSS_ERROR_INVALID_POINTER
*
* Return value:
* PR_TRUE if they match
* PR_FALSE if they don't
* PR_FALSE upon error
*/
NSS_IMPLEMENT PRBool
nsslibc_memequal(const void *a, const void *b, PRUint32 len,
PRStatus *statusOpt)
{
#ifdef NSSDEBUG
if ((((void *)NULL == a) || ((void *)NULL == b))) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_FAILURE;
}
return PR_FALSE;
}
#endif /* NSSDEBUG */
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_SUCCESS;
}
if (0 == memcmp(a, b, len)) {
return PR_TRUE;
} else {
return PR_FALSE;
}
}
/*
* nsslibc_memcmp
*/
NSS_IMPLEMENT PRInt32
nsslibc_memcmp(const void *a, const void *b, PRUint32 len, PRStatus *statusOpt)
{
int v;
#ifdef NSSDEBUG
if ((((void *)NULL == a) || ((void *)NULL == b))) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_FAILURE;
}
return -2;
}
#endif /* NSSDEBUG */
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_SUCCESS;
}
v = memcmp(a, b, len);
return (PRInt32)v;
}
/*
* offsetof is a preprocessor definition
*/

View file

@ -0,0 +1,405 @@
/* 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/. */
/*
* list.c
*
* This contains the implementation of NSS's thread-safe linked list.
*/
#ifndef BASE_H
#include "base.h"
#endif /* BASE_H */
struct nssListElementStr {
PRCList link;
void *data;
};
typedef struct nssListElementStr nssListElement;
struct nssListStr {
NSSArena *arena;
PZLock *lock;
nssListElement *head;
PRUint32 count;
nssListCompareFunc compareFunc;
nssListSortFunc sortFunc;
PRBool i_alloced_arena;
};
struct nssListIteratorStr {
PZLock *lock;
nssList *list;
nssListElement *current;
};
#define NSSLIST_LOCK_IF(list) \
if ((list)->lock) \
PZ_Lock((list)->lock)
#define NSSLIST_UNLOCK_IF(list) \
if ((list)->lock) \
PZ_Unlock((list)->lock)
static PRBool
pointer_compare(void *a, void *b)
{
return (PRBool)(a == b);
}
static nssListElement *
nsslist_get_matching_element(nssList *list, void *data)
{
nssListElement *node;
node = list->head;
if (!node) {
return NULL;
}
while (node) {
/* using a callback slows things down when it's just compare ... */
if (list->compareFunc(node->data, data)) {
break;
}
if (&node->link == PR_LIST_TAIL(&list->head->link)) {
node = NULL;
break;
}
node = (nssListElement *)PR_NEXT_LINK(&node->link);
}
return node;
}
NSS_IMPLEMENT nssList *
nssList_Create(NSSArena *arenaOpt, PRBool threadSafe)
{
NSSArena *arena;
nssList *list;
PRBool i_alloced;
if (arenaOpt) {
arena = arenaOpt;
i_alloced = PR_FALSE;
} else {
arena = nssArena_Create();
i_alloced = PR_TRUE;
}
if (!arena) {
return (nssList *)NULL;
}
list = nss_ZNEW(arena, nssList);
if (!list) {
if (!arenaOpt) {
NSSArena_Destroy(arena);
}
return (nssList *)NULL;
}
if (threadSafe) {
list->lock = PZ_NewLock(nssILockOther);
if (!list->lock) {
if (arenaOpt) {
nss_ZFreeIf(list);
} else {
NSSArena_Destroy(arena);
}
return (nssList *)NULL;
}
}
list->arena = arena;
list->i_alloced_arena = i_alloced;
list->compareFunc = pointer_compare;
return list;
}
NSS_IMPLEMENT PRStatus
nssList_Destroy(nssList *list)
{
if (!list) {
return PR_SUCCESS;
}
if (!list->i_alloced_arena) {
nssList_Clear(list, NULL);
}
if (list->lock) {
(void)PZ_DestroyLock(list->lock);
}
if (list->i_alloced_arena) {
NSSArena_Destroy(list->arena);
list = NULL;
}
nss_ZFreeIf(list);
return PR_SUCCESS;
}
NSS_IMPLEMENT void
nssList_SetCompareFunction(nssList *list, nssListCompareFunc compareFunc)
{
list->compareFunc = compareFunc;
}
NSS_IMPLEMENT void
nssList_SetSortFunction(nssList *list, nssListSortFunc sortFunc)
{
/* XXX if list already has elements, sort them */
list->sortFunc = sortFunc;
}
NSS_IMPLEMENT nssListCompareFunc
nssList_GetCompareFunction(nssList *list)
{
return list->compareFunc;
}
NSS_IMPLEMENT void
nssList_Clear(nssList *list, nssListElementDestructorFunc destructor)
{
PRCList *link;
nssListElement *node, *tmp;
if (!list) {
return;
}
NSSLIST_LOCK_IF(list);
node = list->head;
list->head = NULL;
while (node && list->count > 0) {
if (destructor)
(*destructor)(node->data);
link = &node->link;
tmp = (nssListElement *)PR_NEXT_LINK(link);
PR_REMOVE_LINK(link);
nss_ZFreeIf(node);
node = tmp;
--list->count;
}
NSSLIST_UNLOCK_IF(list);
}
static PRStatus
nsslist_add_element(nssList *list, void *data)
{
nssListElement *node = nss_ZNEW(list->arena, nssListElement);
if (!node) {
return PR_FAILURE;
}
PR_INIT_CLIST(&node->link);
node->data = data;
if (list->head) {
if (list->sortFunc) {
PRCList *link;
nssListElement *currNode;
currNode = list->head;
/* insert in ordered list */
while (currNode) {
link = &currNode->link;
if (list->sortFunc(data, currNode->data) <= 0) {
/* new element goes before current node */
PR_INSERT_BEFORE(&node->link, link);
/* reset head if this is first */
if (currNode == list->head)
list->head = node;
break;
}
if (link == PR_LIST_TAIL(&list->head->link)) {
/* reached end of list, append */
PR_INSERT_AFTER(&node->link, link);
break;
}
currNode = (nssListElement *)PR_NEXT_LINK(&currNode->link);
}
} else {
/* not sorting */
PR_APPEND_LINK(&node->link, &list->head->link);
}
} else {
list->head = node;
}
++list->count;
return PR_SUCCESS;
}
NSS_IMPLEMENT PRStatus
nssList_Add(nssList *list, void *data)
{
NSSLIST_LOCK_IF(list);
(void)nsslist_add_element(list, data);
NSSLIST_UNLOCK_IF(list);
return PR_SUCCESS;
}
NSS_IMPLEMENT PRStatus
nssList_AddUnique(nssList *list, void *data)
{
PRStatus nssrv;
nssListElement *node;
NSSLIST_LOCK_IF(list);
node = nsslist_get_matching_element(list, data);
if (node) {
/* already in, finish */
NSSLIST_UNLOCK_IF(list);
return PR_SUCCESS;
}
nssrv = nsslist_add_element(list, data);
NSSLIST_UNLOCK_IF(list);
return nssrv;
}
NSS_IMPLEMENT PRStatus
nssList_Remove(nssList *list, void *data)
{
nssListElement *node;
NSSLIST_LOCK_IF(list);
node = nsslist_get_matching_element(list, data);
if (node) {
if (node == list->head) {
list->head = (nssListElement *)PR_NEXT_LINK(&node->link);
}
PR_REMOVE_LINK(&node->link);
nss_ZFreeIf(node);
if (--list->count == 0) {
list->head = NULL;
}
}
NSSLIST_UNLOCK_IF(list);
return PR_SUCCESS;
}
NSS_IMPLEMENT void *
nssList_Get(nssList *list, void *data)
{
nssListElement *node;
NSSLIST_LOCK_IF(list);
node = nsslist_get_matching_element(list, data);
NSSLIST_UNLOCK_IF(list);
return (node) ? node->data : NULL;
}
NSS_IMPLEMENT PRUint32
nssList_Count(nssList *list)
{
return list->count;
}
NSS_IMPLEMENT PRStatus
nssList_GetArray(nssList *list, void **rvArray, PRUint32 maxElements)
{
nssListElement *node;
PRUint32 i = 0;
PR_ASSERT(maxElements > 0);
node = list->head;
if (!node) {
return PR_SUCCESS;
}
NSSLIST_LOCK_IF(list);
while (node) {
rvArray[i++] = node->data;
if (i == maxElements)
break;
node = (nssListElement *)PR_NEXT_LINK(&node->link);
if (node == list->head) {
break;
}
}
NSSLIST_UNLOCK_IF(list);
return PR_SUCCESS;
}
NSS_IMPLEMENT nssList *
nssList_Clone(nssList *list)
{
nssList *rvList;
nssListElement *node;
rvList = nssList_Create(NULL, (list->lock != NULL));
if (!rvList) {
return NULL;
}
NSSLIST_LOCK_IF(list);
if (list->count > 0) {
node = list->head;
while (PR_TRUE) {
nssList_Add(rvList, node->data);
node = (nssListElement *)PR_NEXT_LINK(&node->link);
if (node == list->head) {
break;
}
}
}
NSSLIST_UNLOCK_IF(list);
return rvList;
}
NSS_IMPLEMENT nssListIterator *
nssList_CreateIterator(nssList *list)
{
nssListIterator *rvIterator;
rvIterator = nss_ZNEW(NULL, nssListIterator);
if (!rvIterator) {
return NULL;
}
rvIterator->list = nssList_Clone(list);
if (!rvIterator->list) {
nss_ZFreeIf(rvIterator);
return NULL;
}
rvIterator->current = rvIterator->list->head;
if (list->lock) {
rvIterator->lock = PZ_NewLock(nssILockOther);
if (!rvIterator->lock) {
nssList_Destroy(rvIterator->list);
nss_ZFreeIf(rvIterator);
rvIterator = NULL;
}
}
return rvIterator;
}
NSS_IMPLEMENT void
nssListIterator_Destroy(nssListIterator *iter)
{
if (iter->lock) {
(void)PZ_DestroyLock(iter->lock);
}
if (iter->list) {
nssList_Destroy(iter->list);
}
nss_ZFreeIf(iter);
}
NSS_IMPLEMENT void *
nssListIterator_Start(nssListIterator *iter)
{
NSSLIST_LOCK_IF(iter);
if (iter->list->count == 0) {
return NULL;
}
iter->current = iter->list->head;
return iter->current->data;
}
NSS_IMPLEMENT void *
nssListIterator_Next(nssListIterator *iter)
{
nssListElement *node;
PRCList *link;
if (iter->list->count == 1 || iter->current == NULL) {
/* Reached the end of the list. Don't change the state, force to
* user to call nssList_Finish to clean up.
*/
return NULL;
}
node = (nssListElement *)PR_NEXT_LINK(&iter->current->link);
link = &node->link;
if (link == PR_LIST_TAIL(&iter->list->head->link)) {
/* Signal the end of the list. */
iter->current = NULL;
return node->data;
}
iter->current = node;
return node->data;
}
NSS_IMPLEMENT PRStatus
nssListIterator_Finish(nssListIterator *iter)
{
iter->current = iter->list->head;
return (iter->lock) ? PZ_Unlock(iter->lock) : PR_SUCCESS;
}

View file

@ -0,0 +1,38 @@
#
# 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/.
CORE_DEPTH = ../..
PRIVATE_EXPORTS = \
baset.h \
base.h \
$(NULL)
EXPORTS = \
nssbaset.h \
nssbase.h \
$(NULL)
MODULE = nss
CSRCS = \
arena.c \
error.c \
errorval.c \
hashops.c \
libc.c \
tracker.c \
item.c \
utf8.c \
list.c \
hash.c \
$(NULL)
REQUIRES = nspr
LIBRARY_NAME = nssb
# This part of the code, including all sub-dirs, can be optimized for size
export ALLOW_OPT_CODE_SIZE = 1

View file

@ -0,0 +1,233 @@
/* 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/. */
#ifndef NSSBASE_H
#define NSSBASE_H
/*
* nssbase.h
*
* This header file contains the prototypes of the basic public
* NSS routines.
*/
#ifndef NSSBASET_H
#include "nssbaset.h"
#endif /* NSSBASET_H */
PR_BEGIN_EXTERN_C
/*
* NSSArena
*
* The public methods relating to this type are:
*
* NSSArena_Create -- constructor
* NSSArena_Destroy
* NSS_ZAlloc
* NSS_ZRealloc
* NSS_ZFreeIf
*/
/*
* NSSArena_Create
*
* This routine creates a new memory arena. This routine may return
* NULL upon error, in which case it will have created an error stack.
*
* The top-level error may be one of the following values:
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* A pointer to an NSSArena upon success
*/
NSS_EXTERN NSSArena *NSSArena_Create(void);
extern const NSSError NSS_ERROR_NO_MEMORY;
/*
* NSSArena_Destroy
*
* This routine will destroy the specified arena, freeing all memory
* allocated from it. This routine returns a PRStatus value; if
* successful, it will return PR_SUCCESS. If unsuccessful, it will
* create an error stack and return PR_FAILURE.
*
* The top-level error may be one of the following values:
* NSS_ERROR_INVALID_ARENA
*
* Return value:
* PR_SUCCESS upon success
* PR_FAILURE upon failure
*/
NSS_EXTERN PRStatus NSSArena_Destroy(NSSArena *arena);
extern const NSSError NSS_ERROR_INVALID_ARENA;
/*
* The error stack
*
* The public methods relating to the error stack are:
*
* NSS_GetError
* NSS_GetErrorStack
*/
/*
* NSS_GetError
*
* This routine returns the highest-level (most general) error set
* by the most recent NSS library routine called by the same thread
* calling this routine.
*
* This routine cannot fail. It may return NSS_ERROR_NO_ERROR, which
* indicates that the previous NSS library call did not set an error.
*
* Return value:
* 0 if no error has been set
* A nonzero error number
*/
NSS_EXTERN NSSError NSS_GetError(void);
extern const NSSError NSS_ERROR_NO_ERROR;
/*
* NSS_GetErrorStack
*
* This routine returns a pointer to an array of NSSError values,
* containingthe entire sequence or "stack" of errors set by the most
* recent NSS library routine called by the same thread calling this
* routine. NOTE: the caller DOES NOT OWN the memory pointed to by
* the return value. The pointer will remain valid until the calling
* thread calls another NSS routine. The lowest-level (most specific)
* error is first in the array, and the highest-level is last. The
* array is zero-terminated. This routine may return NULL upon error;
* this indicates a low-memory situation.
*
* Return value:
* NULL upon error, which is an implied NSS_ERROR_NO_MEMORY
* A NON-caller-owned pointer to an array of NSSError values
*/
NSS_EXTERN NSSError *NSS_GetErrorStack(void);
/*
* NSS_ZNEW
*
* This preprocessor macro will allocate memory for a new object
* of the specified type with nss_ZAlloc, and will cast the
* return value appropriately. If the optional arena argument is
* non-null, the memory will be obtained from that arena; otherwise,
* the memory will be obtained from the heap. This routine may
* return NULL upon error, in which case it will have set an error
* upon the error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ARENA
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* A pointer to the new segment of zeroed memory
*/
#define NSS_ZNEW(arenaOpt, type) ((type *)NSS_ZAlloc((arenaOpt), sizeof(type)))
/*
* NSS_ZNEWARRAY
*
* This preprocessor macro will allocate memory for an array of
* new objects, and will cast the return value appropriately.
* If the optional arena argument is non-null, the memory will
* be obtained from that arena; otherwise, the memory will be
* obtained from the heap. This routine may return NULL upon
* error, in which case it will have set an error upon the error
* stack. The array size may be specified as zero.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ARENA
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* A pointer to the new segment of zeroed memory
*/
#define NSS_ZNEWARRAY(arenaOpt, type, quantity) \
((type *)NSS_ZAlloc((arenaOpt), sizeof(type) * (quantity)))
/*
* NSS_ZAlloc
*
* This routine allocates and zeroes a section of memory of the
* size, and returns to the caller a pointer to that memory. If
* the optional arena argument is non-null, the memory will be
* obtained from that arena; otherwise, the memory will be obtained
* from the heap. This routine may return NULL upon error, in
* which case it will have set an error upon the error stack. The
* value specified for size may be zero; in which case a valid
* zero-length block of memory will be allocated. This block may
* be expanded by calling NSS_ZRealloc.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ARENA
* NSS_ERROR_NO_MEMORY
* NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
*
* Return value:
* NULL upon error
* A pointer to the new segment of zeroed memory
*/
NSS_EXTERN void *NSS_ZAlloc(NSSArena *arenaOpt, PRUint32 size);
/*
* NSS_ZRealloc
*
* This routine reallocates a block of memory obtained by calling
* nss_ZAlloc or nss_ZRealloc. The portion of memory
* between the new and old sizes -- which is either being newly
* obtained or released -- is in either case zeroed. This routine
* may return NULL upon failure, in which case it will have placed
* an error on the error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_POINTER
* NSS_ERROR_NO_MEMORY
* NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
*
* Return value:
* NULL upon error
* A pointer to the replacement segment of memory
*/
NSS_EXTERN void *NSS_ZRealloc(void *pointer, PRUint32 newSize);
/*
* NSS_ZFreeIf
*
* If the specified pointer is non-null, then the region of memory
* to which it points -- which must have been allocated with
* nss_ZAlloc -- will be zeroed and released. This routine
* returns a PRStatus value; if successful, it will return PR_SUCCESS.
* If unsuccessful, it will set an error on the error stack and return
* PR_FAILURE.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_POINTER
*
* Return value:
* PR_SUCCESS
* PR_FAILURE
*/
NSS_EXTERN PRStatus NSS_ZFreeIf(void *pointer);
PR_END_EXTERN_C
#endif /* NSSBASE_H */

View file

@ -0,0 +1,118 @@
/* 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/. */
#ifndef NSSBASET_H
#define NSSBASET_H
/*
* nssbaset.h
*
* This file contains the most low-level, fundamental public types.
*/
#include "nspr.h"
#include "nssilock.h"
/*
* NSS_EXTERN, NSS_IMPLEMENT, NSS_EXTERN_DATA, NSS_IMPLEMENT_DATA
*
* NSS has its own versions of these NSPR macros, in a form which
* does not confuse ctags and other related utilities. NSPR
* defines these macros to take the type as an argument, because
* of certain OS requirements on platforms not supported by NSS.
*/
#define DUMMY /* dummy */
#define NSS_EXTERN extern
#define NSS_EXTERN_DATA extern
#define NSS_IMPLEMENT
#define NSS_IMPLEMENT_DATA
PR_BEGIN_EXTERN_C
/*
* NSSError
*
* Calls to NSS routines may result in one or more errors being placed
* on the calling thread's "error stack." Every possible error that
* may be returned from a function is declared where the function is
* prototyped. All errors are of the following type.
*/
typedef PRInt32 NSSError;
/*
* NSSArena
*
* Arenas are logical sets of heap memory, from which memory may be
* allocated. When an arena is destroyed, all memory allocated within
* that arena is implicitly freed. These arenas are thread-safe:
* an arena pointer may be used by multiple threads simultaneously.
* However, as they are not backed by shared memory, they may only be
* used within one process.
*/
struct NSSArenaStr;
typedef struct NSSArenaStr NSSArena;
/*
* NSSItem
*
* This is the basic type used to refer to an unconstrained datum of
* arbitrary size.
*/
struct NSSItemStr {
void *data;
PRUint32 size;
};
typedef struct NSSItemStr NSSItem;
/*
* NSSBER
*
* Data packed according to the Basic Encoding Rules of ASN.1.
*/
typedef NSSItem NSSBER;
/*
* NSSDER
*
* Data packed according to the Distinguished Encoding Rules of ASN.1;
* this form is also known as the Canonical Encoding Rules form (CER).
*/
typedef NSSBER NSSDER;
/*
* NSSBitString
*
* Some ASN.1 types use "bit strings," which are passed around as
* octet strings but whose length is counted in bits. We use this
* typedef of NSSItem to point out the occasions when the length
* is counted in bits, not octets.
*/
typedef NSSItem NSSBitString;
/*
* NSSUTF8
*
* Character strings encoded in UTF-8, as defined by RFC 2279.
*/
typedef char NSSUTF8;
/*
* NSSASCII7
*
* Character strings guaranteed to be 7-bit ASCII.
*/
typedef char NSSASCII7;
PR_END_EXTERN_C
#endif /* NSSBASET_H */

View file

@ -0,0 +1,378 @@
/* 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/. */
/*
* tracker.c
*
* This file contains the code used by the pointer-tracking calls used
* in the debug builds to catch bad pointers. The entire contents are
* only available in debug builds (both internal and external builds).
*/
#ifndef BASE_H
#include "base.h"
#endif /* BASE_H */
#ifdef DEBUG
/*
* identity_hash
*
* This static callback is a PLHashFunction as defined in plhash.h
* It merely returns the value of the object pointer as its hash.
* There are no possible errors.
*/
static PLHashNumber PR_CALLBACK
identity_hash(const void *key)
{
return (PLHashNumber)((char *)key - (char *)NULL);
}
/*
* trackerOnceFunc
*
* This function is called once, using the nssCallOnce function above.
* It creates a new pointer tracker object; initialising its hash
* table and protective lock.
*/
static PRStatus
trackerOnceFunc(void *arg)
{
nssPointerTracker *tracker = (nssPointerTracker *)arg;
tracker->lock = PZ_NewLock(nssILockOther);
if ((PZLock *)NULL == tracker->lock) {
return PR_FAILURE;
}
tracker->table =
PL_NewHashTable(0, identity_hash, PL_CompareValues, PL_CompareValues,
(PLHashAllocOps *)NULL, (void *)NULL);
if ((PLHashTable *)NULL == tracker->table) {
PZ_DestroyLock(tracker->lock);
tracker->lock = (PZLock *)NULL;
return PR_FAILURE;
}
return PR_SUCCESS;
}
/*
* nssPointerTracker_initialize
*
* This method is only present in debug builds.
*
* This routine initializes an nssPointerTracker object. Note that
* the object must have been declared *static* to guarantee that it
* is in a zeroed state initially. This routine is idempotent, and
* may even be safely called by multiple threads simultaneously with
* the same argument. This routine returns a PRStatus value; if
* successful, it will return PR_SUCCESS. On failure it will set an
* error on the error stack and return PR_FAILURE.
*
* The error may be one of the following values:
* NSS_ERROR_NO_MEMORY
*
* Return value:
* PR_SUCCESS
* PR_FAILURE
*/
NSS_IMPLEMENT PRStatus
nssPointerTracker_initialize(nssPointerTracker *tracker)
{
PRStatus rv = PR_CallOnceWithArg(&tracker->once, trackerOnceFunc, tracker);
if (PR_SUCCESS != rv) {
nss_SetError(NSS_ERROR_NO_MEMORY);
}
return rv;
}
#ifdef DONT_DESTROY_EMPTY_TABLES
/* See same #ifdef below */
/*
* count_entries
*
* This static routine is a PLHashEnumerator, as defined in plhash.h.
* It merely causes the enumeration function to count the number of
* entries.
*/
static PRIntn PR_CALLBACK
count_entries(PLHashEntry *he, PRIntn index, void *arg)
{
return HT_ENUMERATE_NEXT;
}
#endif /* DONT_DESTROY_EMPTY_TABLES */
/*
* zero_once
*
* This is a guaranteed zeroed once block. It's used to help clear
* the tracker.
*/
static const PRCallOnceType zero_once;
/*
* nssPointerTracker_finalize
*
* This method is only present in debug builds.
*
* This routine returns the nssPointerTracker object to the pre-
* initialized state, releasing all resources used by the object.
* It will *NOT* destroy the objects being tracked by the pointer
* (should any remain), and therefore cannot be used to "sweep up"
* remaining objects. This routine returns a PRStatus value; if
* successful, it will return PR_SUCCES. On failure it will set an
* error on the error stack and return PR_FAILURE. If any objects
* remain in the tracker when it is finalized, that will be treated
* as an error.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_POINTER
* NSS_ERROR_TRACKER_NOT_INITIALIZED
* NSS_ERROR_TRACKER_NOT_EMPTY
*
* Return value:
* PR_SUCCESS
* PR_FAILURE
*/
NSS_IMPLEMENT PRStatus
nssPointerTracker_finalize(nssPointerTracker *tracker)
{
PZLock *lock;
if ((nssPointerTracker *)NULL == tracker) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
return PR_FAILURE;
}
if ((PZLock *)NULL == tracker->lock) {
nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
return PR_FAILURE;
}
lock = tracker->lock;
PZ_Lock(lock);
if ((PLHashTable *)NULL == tracker->table) {
PZ_Unlock(lock);
nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
return PR_FAILURE;
}
#ifdef DONT_DESTROY_EMPTY_TABLES
/*
* I changed my mind; I think we don't want this after all.
* Comments?
*/
count = PL_HashTableEnumerateEntries(tracker->table, count_entries,
(void *)NULL);
if (0 != count) {
PZ_Unlock(lock);
nss_SetError(NSS_ERROR_TRACKER_NOT_EMPTY);
return PR_FAILURE;
}
#endif /* DONT_DESTROY_EMPTY_TABLES */
PL_HashTableDestroy(tracker->table);
/* memset(tracker, 0, sizeof(nssPointerTracker)); */
tracker->once = zero_once;
tracker->lock = (PZLock *)NULL;
tracker->table = (PLHashTable *)NULL;
PZ_Unlock(lock);
PZ_DestroyLock(lock);
return PR_SUCCESS;
}
/*
* nssPointerTracker_add
*
* This method is only present in debug builds.
*
* This routine adds the specified pointer to the nssPointerTracker
* object. It should be called in constructor objects to register
* new valid objects. The nssPointerTracker is threadsafe, but this
* call is not idempotent. This routine returns a PRStatus value;
* if successful it will return PR_SUCCESS. On failure it will set
* an error on the error stack and return PR_FAILURE.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_POINTER
* NSS_ERROR_NO_MEMORY
* NSS_ERROR_TRACKER_NOT_INITIALIZED
* NSS_ERROR_DUPLICATE_POINTER
*
* Return value:
* PR_SUCCESS
* PR_FAILURE
*/
NSS_IMPLEMENT PRStatus
nssPointerTracker_add(nssPointerTracker *tracker, const void *pointer)
{
void *check;
PLHashEntry *entry;
if ((nssPointerTracker *)NULL == tracker) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
return PR_FAILURE;
}
if ((PZLock *)NULL == tracker->lock) {
nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
return PR_FAILURE;
}
PZ_Lock(tracker->lock);
if ((PLHashTable *)NULL == tracker->table) {
PZ_Unlock(tracker->lock);
nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
return PR_FAILURE;
}
check = PL_HashTableLookup(tracker->table, pointer);
if ((void *)NULL != check) {
PZ_Unlock(tracker->lock);
nss_SetError(NSS_ERROR_DUPLICATE_POINTER);
return PR_FAILURE;
}
entry = PL_HashTableAdd(tracker->table, pointer, (void *)pointer);
PZ_Unlock(tracker->lock);
if ((PLHashEntry *)NULL == entry) {
nss_SetError(NSS_ERROR_NO_MEMORY);
return PR_FAILURE;
}
return PR_SUCCESS;
}
/*
* nssPointerTracker_remove
*
* This method is only present in debug builds.
*
* This routine removes the specified pointer from the
* nssPointerTracker object. It does not call any destructor for the
* object; rather, this should be called from the object's destructor.
* The nssPointerTracker is threadsafe, but this call is not
* idempotent. This routine returns a PRStatus value; if successful
* it will return PR_SUCCESS. On failure it will set an error on the
* error stack and return PR_FAILURE.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_POINTER
* NSS_ERROR_TRACKER_NOT_INITIALIZED
* NSS_ERROR_POINTER_NOT_REGISTERED
*
* Return value:
* PR_SUCCESS
* PR_FAILURE
*/
NSS_IMPLEMENT PRStatus
nssPointerTracker_remove(nssPointerTracker *tracker, const void *pointer)
{
PRBool registered;
if ((nssPointerTracker *)NULL == tracker) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
return PR_FAILURE;
}
if ((PZLock *)NULL == tracker->lock) {
nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
return PR_FAILURE;
}
PZ_Lock(tracker->lock);
if ((PLHashTable *)NULL == tracker->table) {
PZ_Unlock(tracker->lock);
nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
return PR_FAILURE;
}
registered = PL_HashTableRemove(tracker->table, pointer);
PZ_Unlock(tracker->lock);
if (!registered) {
nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED);
return PR_FAILURE;
}
return PR_SUCCESS;
}
/*
* nssPointerTracker_verify
*
* This method is only present in debug builds.
*
* This routine verifies that the specified pointer has been registered
* with the nssPointerTracker object. The nssPointerTracker object is
* threadsafe, and this call may be safely called from multiple threads
* simultaneously with the same arguments. This routine returns a
* PRStatus value; if the pointer is registered this will return
* PR_SUCCESS. Otherwise it will set an error on the error stack and
* return PR_FAILURE. Although the error is suitable for leaving on
* the stack, callers may wish to augment the information available by
* placing a more type-specific error on the stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_POINTER
* NSS_ERROR_TRACKER_NOT_INITIALIZED
* NSS_ERROR_POINTER_NOT_REGISTERED
*
* Return value:
* PR_SUCCESS
* PR_FAILRUE
*/
NSS_IMPLEMENT PRStatus
nssPointerTracker_verify(nssPointerTracker *tracker, const void *pointer)
{
void *check;
if ((nssPointerTracker *)NULL == tracker) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
return PR_FAILURE;
}
if ((PZLock *)NULL == tracker->lock) {
nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
return PR_FAILURE;
}
PZ_Lock(tracker->lock);
if ((PLHashTable *)NULL == tracker->table) {
PZ_Unlock(tracker->lock);
nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
return PR_FAILURE;
}
check = PL_HashTableLookup(tracker->table, pointer);
PZ_Unlock(tracker->lock);
if ((void *)NULL == check) {
nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED);
return PR_FAILURE;
}
return PR_SUCCESS;
}
#endif /* DEBUG */

View file

@ -0,0 +1,679 @@
/* 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/. */
/*
* utf8.c
*
* This file contains some additional utility routines required for
* handling UTF8 strings.
*/
#ifndef BASE_H
#include "base.h"
#endif /* BASE_H */
#include "plstr.h"
/*
* NOTES:
*
* There's an "is hex string" function in pki1/atav.c. If we need
* it in more places, pull that one out.
*/
/*
* nssUTF8_CaseIgnoreMatch
*
* Returns true if the two UTF8-encoded strings pointed to by the
* two specified NSSUTF8 pointers differ only in typcase.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_POINTER
*
* Return value:
* PR_TRUE if the strings match, ignoring case
* PR_FALSE if they don't
* PR_FALSE upon error
*/
NSS_IMPLEMENT PRBool
nssUTF8_CaseIgnoreMatch(const NSSUTF8 *a, const NSSUTF8 *b, PRStatus *statusOpt)
{
#ifdef NSSDEBUG
if (((const NSSUTF8 *)NULL == a) || ((const NSSUTF8 *)NULL == b)) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_FAILURE;
}
return PR_FALSE;
}
#endif /* NSSDEBUG */
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_SUCCESS;
}
/*
* XXX fgmr
*
* This is, like, so wrong!
*/
if (0 == PL_strcasecmp((const char *)a, (const char *)b)) {
return PR_TRUE;
} else {
return PR_FALSE;
}
}
/*
* nssUTF8_PrintableMatch
*
* Returns true if the two Printable strings pointed to by the
* two specified NSSUTF8 pointers match when compared with the
* rules for Printable String (leading and trailing spaces are
* disregarded, extents of whitespace match irregardless of length,
* and case is not significant), then PR_TRUE will be returned.
* Otherwise, PR_FALSE will be returned. Upon failure, PR_FALSE
* will be returned. If the optional statusOpt argument is not
* NULL, then PR_SUCCESS or PR_FAILURE will be stored in that
* location.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_POINTER
*
* Return value:
* PR_TRUE if the strings match, ignoring case
* PR_FALSE if they don't
* PR_FALSE upon error
*/
NSS_IMPLEMENT PRBool
nssUTF8_PrintableMatch(const NSSUTF8 *a, const NSSUTF8 *b, PRStatus *statusOpt)
{
PRUint8 *c;
PRUint8 *d;
#ifdef NSSDEBUG
if (((const NSSUTF8 *)NULL == a) || ((const NSSUTF8 *)NULL == b)) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_FAILURE;
}
return PR_FALSE;
}
#endif /* NSSDEBUG */
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_SUCCESS;
}
c = (PRUint8 *)a;
d = (PRUint8 *)b;
while (' ' == *c) {
c++;
}
while (' ' == *d) {
d++;
}
while (('\0' != *c) && ('\0' != *d)) {
PRUint8 e, f;
e = *c;
f = *d;
if (('a' <= e) && (e <= 'z')) {
e -= ('a' - 'A');
}
if (('a' <= f) && (f <= 'z')) {
f -= ('a' - 'A');
}
if (e != f) {
return PR_FALSE;
}
c++;
d++;
if (' ' == *c) {
while (' ' == *c) {
c++;
}
c--;
}
if (' ' == *d) {
while (' ' == *d) {
d++;
}
d--;
}
}
while (' ' == *c) {
c++;
}
while (' ' == *d) {
d++;
}
if (*c == *d) {
/* And both '\0', btw */
return PR_TRUE;
} else {
return PR_FALSE;
}
}
/*
* nssUTF8_Duplicate
*
* This routine duplicates the UTF8-encoded string pointed to by the
* specified NSSUTF8 pointer. If the optional arenaOpt argument is
* not null, the memory required will be obtained from that arena;
* otherwise, the memory required will be obtained from the heap.
* A pointer to the new string will be returned. In case of error,
* an error will be placed on the error stack and NULL will be
* returned.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_POINTER
* NSS_ERROR_INVALID_ARENA
* NSS_ERROR_NO_MEMORY
*/
NSS_IMPLEMENT NSSUTF8 *
nssUTF8_Duplicate(const NSSUTF8 *s, NSSArena *arenaOpt)
{
NSSUTF8 *rv;
PRUint32 len;
#ifdef NSSDEBUG
if ((const NSSUTF8 *)NULL == s) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
return (NSSUTF8 *)NULL;
}
if ((NSSArena *)NULL != arenaOpt) {
if (PR_SUCCESS != nssArena_verifyPointer(arenaOpt)) {
return (NSSUTF8 *)NULL;
}
}
#endif /* NSSDEBUG */
len = PL_strlen((const char *)s);
#ifdef PEDANTIC
if ('\0' != ((const char *)s)[len]) {
/* must have wrapped, e.g., too big for PRUint32 */
nss_SetError(NSS_ERROR_NO_MEMORY);
return (NSSUTF8 *)NULL;
}
#endif /* PEDANTIC */
len++; /* zero termination */
rv = nss_ZAlloc(arenaOpt, len);
if ((void *)NULL == rv) {
return (NSSUTF8 *)NULL;
}
(void)nsslibc_memcpy(rv, s, len);
return rv;
}
/*
* nssUTF8_Size
*
* This routine returns the length in bytes (including the terminating
* null) of the UTF8-encoded string pointed to by the specified
* NSSUTF8 pointer. Zero is returned on error.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_POINTER
* NSS_ERROR_VALUE_TOO_LARGE
*
* Return value:
* 0 on error
* nonzero length of the string.
*/
NSS_IMPLEMENT PRUint32
nssUTF8_Size(const NSSUTF8 *s, PRStatus *statusOpt)
{
PRUint32 sv;
#ifdef NSSDEBUG
if ((const NSSUTF8 *)NULL == s) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_FAILURE;
}
return 0;
}
#endif /* NSSDEBUG */
sv = PL_strlen((const char *)s) + 1;
#ifdef PEDANTIC
if ('\0' != ((const char *)s)[sv - 1]) {
/* wrapped */
nss_SetError(NSS_ERROR_VALUE_TOO_LARGE);
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_FAILURE;
}
return 0;
}
#endif /* PEDANTIC */
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_SUCCESS;
}
return sv;
}
/*
* nssUTF8_Length
*
* This routine returns the length in characters (not including the
* terminating null) of the UTF8-encoded string pointed to by the
* specified NSSUTF8 pointer.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_POINTER
* NSS_ERROR_VALUE_TOO_LARGE
* NSS_ERROR_INVALID_STRING
*
* Return value:
* length of the string (which may be zero)
* 0 on error
*/
NSS_IMPLEMENT PRUint32
nssUTF8_Length(const NSSUTF8 *s, PRStatus *statusOpt)
{
PRUint32 l = 0;
const PRUint8 *c = (const PRUint8 *)s;
#ifdef NSSDEBUG
if ((const NSSUTF8 *)NULL == s) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
goto loser;
}
#endif /* NSSDEBUG */
/*
* From RFC 2044:
*
* UCS-4 range (hex.) UTF-8 octet sequence (binary)
* 0000 0000-0000 007F 0xxxxxxx
* 0000 0080-0000 07FF 110xxxxx 10xxxxxx
* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx
*/
while (0 != *c) {
PRUint32 incr;
if ((*c & 0x80) == 0) {
incr = 1;
} else if ((*c & 0xE0) == 0xC0) {
incr = 2;
} else if ((*c & 0xF0) == 0xE0) {
incr = 3;
} else if ((*c & 0xF8) == 0xF0) {
incr = 4;
} else if ((*c & 0xFC) == 0xF8) {
incr = 5;
} else if ((*c & 0xFE) == 0xFC) {
incr = 6;
} else {
nss_SetError(NSS_ERROR_INVALID_STRING);
goto loser;
}
l += incr;
#ifdef PEDANTIC
if (l < incr) {
/* Wrapped-- too big */
nss_SetError(NSS_ERROR_VALUE_TOO_LARGE);
goto loser;
}
{
PRUint8 *d;
for (d = &c[1]; d < &c[incr]; d++) {
if ((*d & 0xC0) != 0xF0) {
nss_SetError(NSS_ERROR_INVALID_STRING);
goto loser;
}
}
}
#endif /* PEDANTIC */
c += incr;
}
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_SUCCESS;
}
return l;
loser:
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_FAILURE;
}
return 0;
}
/*
* nssUTF8_Create
*
* This routine creates a UTF8 string from a string in some other
* format. Some types of string may include embedded null characters,
* so for them the length parameter must be used. For string types
* that are null-terminated, the length parameter is optional; if it
* is zero, it will be ignored. If the optional arena argument is
* non-null, the memory used for the new string will be obtained from
* that arena, otherwise it will be obtained from the heap. This
* routine may return NULL upon error, in which case it will have
* placed an error on the error stack.
*
* The error may be one of the following:
* NSS_ERROR_INVALID_POINTER
* NSS_ERROR_NO_MEMORY
* NSS_ERROR_UNSUPPORTED_TYPE
*
* Return value:
* NULL upon error
* A non-null pointer to a new UTF8 string otherwise
*/
extern const NSSError NSS_ERROR_INTERNAL_ERROR; /* XXX fgmr */
NSS_IMPLEMENT NSSUTF8 *
nssUTF8_Create(NSSArena *arenaOpt, nssStringType type, const void *inputString,
PRUint32 size /* in bytes, not characters */
)
{
NSSUTF8 *rv = NULL;
#ifdef NSSDEBUG
if ((NSSArena *)NULL != arenaOpt) {
if (PR_SUCCESS != nssArena_verifyPointer(arenaOpt)) {
return (NSSUTF8 *)NULL;
}
}
if ((const void *)NULL == inputString) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
return (NSSUTF8 *)NULL;
}
#endif /* NSSDEBUG */
switch (type) {
case nssStringType_DirectoryString:
/* This is a composite type requiring BER */
nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
break;
case nssStringType_TeletexString:
/*
* draft-ietf-pkix-ipki-part1-11 says in part:
*
* In addition, many legacy implementations support names encoded
* in the ISO 8859-1 character set (Latin1String) but tag them as
* TeletexString. The Latin1String includes characters used in
* Western European countries which are not part of the
* TeletexString charcter set. Implementations that process
* TeletexString SHOULD be prepared to handle the entire ISO
* 8859-1 character set.[ISO 8859-1].
*/
nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
break;
case nssStringType_PrintableString:
/*
* PrintableString consists of A-Za-z0-9 ,()+,-./:=?
* This is a subset of ASCII, which is a subset of UTF8.
* So we can just duplicate the string over.
*/
if (0 == size) {
rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt);
} else {
rv = nss_ZAlloc(arenaOpt, size + 1);
if ((NSSUTF8 *)NULL == rv) {
return (NSSUTF8 *)NULL;
}
(void)nsslibc_memcpy(rv, inputString, size);
}
break;
case nssStringType_UniversalString:
/* 4-byte unicode */
nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
break;
case nssStringType_BMPString:
/* Base Multilingual Plane of Unicode */
nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
break;
case nssStringType_UTF8String:
if (0 == size) {
rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt);
} else {
rv = nss_ZAlloc(arenaOpt, size + 1);
if ((NSSUTF8 *)NULL == rv) {
return (NSSUTF8 *)NULL;
}
(void)nsslibc_memcpy(rv, inputString, size);
}
break;
case nssStringType_PHGString:
/*
* PHGString is an IA5String (with case-insensitive comparisons).
* IA5 is ~almost~ ascii; ascii has dollar-sign where IA5 has
* currency symbol.
*/
nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
break;
case nssStringType_GeneralString:
nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
break;
default:
nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
break;
}
return rv;
}
NSS_IMPLEMENT NSSItem *
nssUTF8_GetEncoding(NSSArena *arenaOpt, NSSItem *rvOpt, nssStringType type,
NSSUTF8 *string)
{
NSSItem *rv = (NSSItem *)NULL;
PRStatus status = PR_SUCCESS;
#ifdef NSSDEBUG
if ((NSSArena *)NULL != arenaOpt) {
if (PR_SUCCESS != nssArena_verifyPointer(arenaOpt)) {
return (NSSItem *)NULL;
}
}
if ((NSSUTF8 *)NULL == string) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
return (NSSItem *)NULL;
}
#endif /* NSSDEBUG */
switch (type) {
case nssStringType_DirectoryString:
nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
break;
case nssStringType_TeletexString:
nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
break;
case nssStringType_PrintableString:
nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
break;
case nssStringType_UniversalString:
nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
break;
case nssStringType_BMPString:
nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
break;
case nssStringType_UTF8String: {
NSSUTF8 *dup = nssUTF8_Duplicate(string, arenaOpt);
if ((NSSUTF8 *)NULL == dup) {
return (NSSItem *)NULL;
}
if ((NSSItem *)NULL == rvOpt) {
rv = nss_ZNEW(arenaOpt, NSSItem);
if ((NSSItem *)NULL == rv) {
(void)nss_ZFreeIf(dup);
return (NSSItem *)NULL;
}
} else {
rv = rvOpt;
}
rv->data = dup;
dup = (NSSUTF8 *)NULL;
rv->size = nssUTF8_Size(rv->data, &status);
if ((0 == rv->size) && (PR_SUCCESS != status)) {
if ((NSSItem *)NULL == rvOpt) {
(void)nss_ZFreeIf(rv);
}
return (NSSItem *)NULL;
}
} break;
case nssStringType_PHGString:
nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
break;
default:
nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
break;
}
return rv;
}
/*
* nssUTF8_CopyIntoFixedBuffer
*
* This will copy a UTF8 string into a fixed-length buffer, making
* sure that the all characters are valid. Any remaining space will
* be padded with the specified ASCII character, typically either
* null or space.
*
* Blah, blah, blah.
*/
NSS_IMPLEMENT PRStatus
nssUTF8_CopyIntoFixedBuffer(NSSUTF8 *string, char *buffer, PRUint32 bufferSize,
char pad)
{
PRUint32 stringSize = 0;
#ifdef NSSDEBUG
if ((char *)NULL == buffer) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
return PR_FALSE;
}
if (0 == bufferSize) {
nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
return PR_FALSE;
}
if ((pad & 0x80) != 0x00) {
nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
return PR_FALSE;
}
#endif /* NSSDEBUG */
if ((NSSUTF8 *)NULL == string) {
string = (NSSUTF8 *)"";
}
stringSize = nssUTF8_Size(string, (PRStatus *)NULL);
stringSize--; /* don't count the trailing null */
if (stringSize > bufferSize) {
PRUint32 bs = bufferSize;
(void)nsslibc_memcpy(buffer, string, bufferSize);
if ((((buffer[bs - 1] & 0x80) == 0x00)) ||
((bs > 1) && ((buffer[bs - 2] & 0xE0) == 0xC0)) ||
((bs > 2) && ((buffer[bs - 3] & 0xF0) == 0xE0)) ||
((bs > 3) && ((buffer[bs - 4] & 0xF8) == 0xF0)) ||
((bs > 4) && ((buffer[bs - 5] & 0xFC) == 0xF8)) ||
((bs > 5) && ((buffer[bs - 6] & 0xFE) == 0xFC))) {
/* It fit exactly */
return PR_SUCCESS;
}
/* Too long. We have to trim the last character */
for (/*bs*/; bs != 0; bs--) {
if ((buffer[bs - 1] & 0xC0) != 0x80) {
buffer[bs - 1] = pad;
break;
} else {
buffer[bs - 1] = pad;
}
}
} else {
(void)nsslibc_memset(buffer, pad, bufferSize);
(void)nsslibc_memcpy(buffer, string, stringSize);
}
return PR_SUCCESS;
}
/*
* nssUTF8_Equal
*
*/
NSS_IMPLEMENT PRBool
nssUTF8_Equal(const NSSUTF8 *a, const NSSUTF8 *b, PRStatus *statusOpt)
{
PRUint32 la, lb;
#ifdef NSSDEBUG
if (((const NSSUTF8 *)NULL == a) || ((const NSSUTF8 *)NULL == b)) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
if ((PRStatus *)NULL != statusOpt) {
*statusOpt = PR_FAILURE;
}
return PR_FALSE;
}
#endif /* NSSDEBUG */
la = nssUTF8_Size(a, statusOpt);
if (0 == la) {
return PR_FALSE;
}
lb = nssUTF8_Size(b, statusOpt);
if (0 == lb) {
return PR_FALSE;
}
if (la != lb) {
return PR_FALSE;
}
return nsslibc_memequal(a, b, la, statusOpt);
}