Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/security/nss/lib/util/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 24 kB image not shown  

Quelle  pkcs11uri.c   Sprache: C

 
/* 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 "pkcs11.h"
#include "pkcs11uri.h"
#include "plarena.h"
#include "prprf.h"
#include "secport.h"

/* Character sets used in the ABNF rules in RFC7512. */
#define PK11URI_DIGIT "0123456789"
#define PK11URI_ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define PK11URI_HEXDIG PK11URI_DIGIT "abcdefABCDEF"
#define PK11URI_UNRESERVED PK11URI_ALPHA PK11URI_DIGIT "-._~"
#define PK11URI_RES_AVAIL ":[]@!$'()*+,="
#define PK11URI_PATH_RES_AVAIL PK11URI_RES_AVAIL "&"
#define PK11URI_QUERY_RES_AVAIL PK11URI_RES_AVAIL "/?|"
#define PK11URI_ATTR_NM_CHAR PK11URI_ALPHA PK11URI_DIGIT "-_"
#define PK11URI_PCHAR PK11URI_UNRESERVED PK11URI_PATH_RES_AVAIL
#define PK11URI_QCHAR PK11URI_UNRESERVED PK11URI_QUERY_RES_AVAIL

/* Path attributes defined in RFC7512. */
static const char *pattr_names[] = {
    PK11URI_PATTR_TOKEN,
    PK11URI_PATTR_MANUFACTURER,
    PK11URI_PATTR_SERIAL,
    PK11URI_PATTR_MODEL,
    PK11URI_PATTR_LIBRARY_MANUFACTURER,
    PK11URI_PATTR_LIBRARY_DESCRIPTION,
    PK11URI_PATTR_LIBRARY_VERSION,
    PK11URI_PATTR_OBJECT,
    PK11URI_PATTR_TYPE,
    PK11URI_PATTR_ID,
    PK11URI_PATTR_SLOT_MANUFACTURER,
    PK11URI_PATTR_SLOT_DESCRIPTION,
    PK11URI_PATTR_SLOT_ID
};

/* Query attributes defined in RFC7512. */
static const char *qattr_names[] = {
    PK11URI_QATTR_PIN_SOURCE,
    PK11URI_QATTR_PIN_VALUE,
    PK11URI_QATTR_MODULE_NAME,
    PK11URI_QATTR_MODULE_PATH
};

struct PK11URIBufferStr {
    PLArenaPool *arena;
    unsigned char *data;
    size_t size;
    size_t allocated;
};
typedef struct PK11URIBufferStr PK11URIBuffer;

struct PK11URIAttributeListEntryStr {
    char *name;
    SECItem value;
};
typedef struct PK11URIAttributeListEntryStr PK11URIAttributeListEntry;

struct PK11URIAttributeListStr {
    PLArenaPool *arena;
    PK11URIAttributeListEntry *attrs;
    size_t num_attrs;
};
typedef struct PK11URIAttributeListStr PK11URIAttributeList;

struct PK11URIStr {
    PLArenaPool *arena;

    PK11URIAttributeList pattrs;
    PK11URIAttributeList vpattrs;

    PK11URIAttributeList qattrs;
    PK11URIAttributeList vqattrs;
};

#define PK11URI_ARENA_SIZE 1024

typedef int (*PK11URIAttributeCompareNameFunc)(const char *a, const char *b);

/* This belongs in secport.h */
#define PORT_ArenaGrowArray(poolp, oldptr, type, oldnum, newnum) \
    (type *)PORT_ArenaGrow((poolp), (oldptr),                    \
                           (oldnum) * sizeof(type), (newnum) * sizeof(type))
#define PORT_ReallocArray(oldptr, type, newnum) \
    (type *)PORT_Realloc((oldptr), (newnum) * sizeof(type))

/* Functions for resizable buffer. */
static SECStatus
pk11uri_AppendBuffer(PK11URIBuffer *buffer, const unsigned char *data,
                     size_t size)
{
    /* Check overflow. */
    if (buffer->size + size < buffer->size)
        return SECFailure;

    if (buffer->size + size > buffer->allocated) {
        size_t allocated = buffer->allocated * 2 + size;
        if (allocated < buffer->allocated)
            return SECFailure;
        if (buffer->arena)
            buffer->data = PORT_ArenaGrow(buffer->arena, buffer->data,
                                          buffer->allocated, allocated);
        else
            buffer->data = PORT_Realloc(buffer->data, allocated);
        if (buffer->data == NULL)
            return SECFailure;
        buffer->allocated = allocated;
    }

    memcpy(&buffer->data[buffer->size], data, size);
    buffer->size += size;

    return SECSuccess;
}

static void
pk11uri_InitBuffer(PK11URIBuffer *buffer, PLArenaPool *arena)
{
    memset(buffer, 0, sizeof(PK11URIBuffer));
    buffer->arena = arena;
}

static void
pk11uri_DestroyBuffer(PK11URIBuffer *buffer)
{
    if (buffer->arena == NULL) {
        PORT_Free(buffer->data);
    }
}

/* URI encoding functions. */
static char *
pk11uri_Escape(PLArenaPool *arena, const unsigned char *value, size_t length,
               const char *available)
{
    PK11URIBuffer buffer;
    const unsigned char *p;
    unsigned char buf[4];
    char *result = NULL;
    SECStatus ret;

    pk11uri_InitBuffer(&buffer, arena);

    for (p = value; p < value + length; p++) {
        if (strchr(available, *p) == NULL) {
            if (PR_snprintf((char *)buf, sizeof(buf), "%%%02X", *p) == (PRUint32)-1) {
                goto fail;
            }
            ret = pk11uri_AppendBuffer(&buffer, buf, 3);
            if (ret != SECSuccess) {
                goto fail;
            }
        } else {
            ret = pk11uri_AppendBuffer(&buffer, p, 1);
            if (ret != SECSuccess) {
                goto fail;
            }
        }
    }
    buf[0] = '\0';
    ret = pk11uri_AppendBuffer(&buffer, buf, 1);
    if (ret != SECSuccess) {
        goto fail;
    }

    /* Steal the memory allocated in buffer. */
    result = (char *)buffer.data;
    buffer.data = NULL;

fail:
    pk11uri_DestroyBuffer(&buffer);

    return result;
}

static unsigned char *
pk11uri_Unescape(PLArenaPool *arena, const char *value, size_t *length)
{
    PK11URIBuffer buffer;
    const char *p;
    unsigned char buf[1];
    unsigned char *result = NULL;
    SECStatus ret;

    pk11uri_InitBuffer(&buffer, arena);

    for (p = value; p < value + *length; p++) {
        if (*p == '%') {
            int c;
            size_t i;

            p++;
            for (c = 0, i = 0; i < 2; i++) {
                int h = *(p + i);
                if ('0' <= h && h <= '9') {
                    c = (c << 4) | (h - '0');
                } else if ('a' <= h && h <= 'f') {
                    c = (c << 4) | (h - 'a' + 10);
                } else if ('A' <= h && h <= 'F') {
                    c = (c << 4) | (h - 'A' + 10);
                } else {
                    break;
                }
            }
            if (i != 2) {
                goto fail;
            }
            p++;
            buf[0] = c;
        } else {
            buf[0] = *p;
        }
        ret = pk11uri_AppendBuffer(&buffer, buf, 1);
        if (ret != SECSuccess) {
            goto fail;
        }
    }
    *length = buffer.size;
    buf[0] = '\0';
    ret = pk11uri_AppendBuffer(&buffer, buf, 1);
    if (ret != SECSuccess) {
        goto fail;
    }

    result = buffer.data;
    buffer.data = NULL;

fail:
    pk11uri_DestroyBuffer(&buffer);

    return result;
}

/* Functions for manipulating attributes array. */

/* Compare two attribute names by the array index in attr_names.  Both
 * attribute names must be present in attr_names, otherwise it is a
 * programming error. */

static int
pk11uri_CompareByPosition(const char *a, const char *b,
                          const char **attr_names, size_t num_attr_names)
{
    size_t i, j;

    for (i = 0; i < num_attr_names; i++) {
        if (strcmp(a, attr_names[i]) == 0) {
            break;
        }
    }
    PR_ASSERT(i < num_attr_names);

    for (j = 0; j < num_attr_names; j++) {
        if (strcmp(b, attr_names[j]) == 0) {
            break;
        }
    }
    PR_ASSERT(j < num_attr_names);

    return i - j;
}

/* Those pk11uri_Compare{Path,Query}AttributeName functions are used
 * to reorder attributes when inserting. */

static int
pk11uri_ComparePathAttributeName(const char *a, const char *b)
{
    return pk11uri_CompareByPosition(a, b, pattr_names, PR_ARRAY_SIZE(pattr_names));
}

static int
pk11uri_CompareQueryAttributeName(const char *a, const char *b)
{
    return pk11uri_CompareByPosition(a, b, qattr_names, PR_ARRAY_SIZE(qattr_names));
}

static SECStatus
pk11uri_InsertToAttributeList(PK11URIAttributeList *attrs,
                              char *name, unsigned char *value, size_t size,
                              PK11URIAttributeCompareNameFunc compare_name,
                              PRBool allow_duplicate)
{
    size_t i;

    if (attrs->arena) {
        attrs->attrs = PORT_ArenaGrowArray(attrs->arena, attrs->attrs,
                                           PK11URIAttributeListEntry,
                                           attrs->num_attrs,
                                           attrs->num_attrs + 1);
    } else {
        attrs->attrs = PORT_ReallocArray(attrs->attrs,
                                         PK11URIAttributeListEntry,
                                         attrs->num_attrs + 1);
    }
    if (attrs->attrs == NULL) {
        return SECFailure;
    }

    for (i = 0; i < attrs->num_attrs; i++) {
        if (!allow_duplicate && strcmp(name, attrs->attrs[i].name) == 0) {
            return SECFailure;
        }
        if (compare_name(name, attrs->attrs[i].name) < 0) {
            memmove(&attrs->attrs[i + 1], &attrs->attrs[i],
                    sizeof(PK11URIAttributeListEntry) * (attrs->num_attrs - i));
            break;
        }
    }

    attrs->attrs[i].name = name;
    attrs->attrs[i].value.type = siBuffer;
    attrs->attrs[i].value.data = value;
    attrs->attrs[i].value.len = size;

    attrs->num_attrs++;

    return SECSuccess;
}

static SECStatus
pk11uri_InsertToAttributeListEscaped(PK11URIAttributeList *attrs,
                                     const char *name, size_t name_size,
                                     const char *value, size_t value_size,
                                     PK11URIAttributeCompareNameFunc compare_name,
                                     PRBool allow_duplicate)
{
    char *name_copy = NULL;
    unsigned char *value_copy = NULL;
    SECStatus ret;

    if (attrs->arena) {
        name_copy = PORT_ArenaNewArray(attrs->arena, char, name_size + 1);
    } else {
        name_copy = PORT_Alloc(name_size + 1);
    }
    if (name_copy == NULL) {
        goto fail;
    }
    memcpy(name_copy, name, name_size);
    name_copy[name_size] = '\0';

    value_copy = pk11uri_Unescape(attrs->arena, value, &value_size);
    if (value_copy == NULL) {
        goto fail;
    }

    ret = pk11uri_InsertToAttributeList(attrs, name_copy, value_copy, value_size,
                                        compare_name, allow_duplicate);
    if (ret != SECSuccess) {
        goto fail;
    }

    return ret;

fail:
    if (attrs->arena == NULL) {
        PORT_Free(name_copy);
        PORT_Free(value_copy);
    }

    return SECFailure;
}

static void
pk11uri_InitAttributeList(PK11URIAttributeList *attrs, PLArenaPool *arena)
{
    memset(attrs, 0, sizeof(PK11URIAttributeList));
    attrs->arena = arena;
}

static void
pk11uri_DestroyAttributeList(PK11URIAttributeList *attrs)
{
    if (attrs->arena == NULL) {
        size_t i;

        for (i = 0; i < attrs->num_attrs; i++) {
            PORT_Free(attrs->attrs[i].name);
            PORT_Free(attrs->attrs[i].value.data);
        }
        PORT_Free(attrs->attrs);
    }
}

static SECStatus
pk11uri_AppendAttributeListToBuffer(PK11URIBuffer *buffer,
                                    PK11URIAttributeList *attrs,
                                    int separator,
                                    const char *unescaped)
{
    size_t i;
    SECStatus ret;

    for (i = 0; i < attrs->num_attrs; i++) {
        unsigned char sep[1];
        char *escaped;
        PK11URIAttributeListEntry *attr = &attrs->attrs[i];

        if (i > 0) {
            sep[0] = separator;
            ret = pk11uri_AppendBuffer(buffer, sep, 1);
            if (ret != SECSuccess) {
                return ret;
            }
        }

        ret = pk11uri_AppendBuffer(buffer, (unsigned char *)attr->name,
                                   strlen(attr->name));
        if (ret != SECSuccess) {
            return ret;
        }

        sep[0] = '=';
        ret = pk11uri_AppendBuffer(buffer, sep, 1);
        if (ret != SECSuccess) {
            return ret;
        }

        escaped = pk11uri_Escape(buffer->arena, attr->value.data, attr->value.len,
                                 unescaped);
        if (escaped == NULL) {
            return ret;
        }
        ret = pk11uri_AppendBuffer(buffer, (unsigned char *)escaped,
                                   strlen(escaped));
        if (buffer->arena == NULL) {
            PORT_Free(escaped);
        }
        if (ret != SECSuccess) {
            return ret;
        }
    }

    return SECSuccess;
}

/* Creation of PK11URI object. */
static PK11URI *
pk11uri_AllocURI(void)
{
    PLArenaPool *arena;
    PK11URI *result;

    arena = PORT_NewArena(PK11URI_ARENA_SIZE);
    if (arena == NULL) {
        return NULL;
    }

    result = PORT_ArenaZAlloc(arena, sizeof(PK11URI));
    if (result == NULL) {
        PORT_FreeArena(arena, PR_FALSE);
        return NULL;
    }

    result->arena = arena;
    pk11uri_InitAttributeList(&result->pattrs, arena);
    pk11uri_InitAttributeList(&result->vpattrs, arena);
    pk11uri_InitAttributeList(&result->qattrs, arena);
    pk11uri_InitAttributeList(&result->vqattrs, arena);

    return result;
}

static SECStatus
pk11uri_InsertAttributes(PK11URIAttributeList *dest_attrs,
                         PK11URIAttributeList *dest_vattrs,
                         const PK11URIAttribute *attrs,
                         size_t num_attrs,
                         const char **attr_names,
                         size_t num_attr_names,
                         PK11URIAttributeCompareNameFunc compare_name,
                         PRBool allow_duplicate,
                         PRBool vendor_allow_duplicate)
{
    SECStatus ret;
    size_t i;

    for (i = 0; i < num_attrs; i++) {
        char *name, *value;
        const char *p;
        size_t j;

        p = attrs[i].name;

        /* The attribute must not be empty. */
        if (*p == '\0') {
            return SECFailure;
        }

        /* Check that the name doesn't contain invalid character. */
        for (; *p != '\0'; p++) {
            if (strchr(PK11URI_ATTR_NM_CHAR, *p) == NULL) {
                return SECFailure;
            }
        }

        name = PORT_ArenaStrdup(dest_attrs->arena, attrs[i].name);
        if (name == NULL) {
            return SECFailure;
        }

        value = PORT_ArenaStrdup(dest_attrs->arena, attrs[i].value);
        if (value == NULL) {
            return SECFailure;
        }

        for (j = 0; j < num_attr_names; j++) {
            if (strcmp(name, attr_names[j]) == 0) {
                break;
            }
        }
        if (j < num_attr_names) {
            /* Named attribute. */
            ret = pk11uri_InsertToAttributeList(dest_attrs,
                                                name,
                                                (unsigned char *)value,
                                                strlen(value),
                                                compare_name,
                                                allow_duplicate);
            if (ret != SECSuccess) {
                return ret;
            }
        } else {
            /* Vendor attribute. */
            ret = pk11uri_InsertToAttributeList(dest_vattrs,
                                                name,
                                                (unsigned char *)value,
                                                strlen(value),
                                                strcmp,
                                                vendor_allow_duplicate);
            if (ret != SECSuccess) {
                return ret;
            }
        }
    }

    return SECSuccess;
}

PK11URI *
PK11URI_CreateURI(const PK11URIAttribute *pattrs,
                  size_t num_pattrs,
                  const PK11URIAttribute *qattrs,
                  size_t num_qattrs)
{
    PK11URI *result;
    SECStatus ret;

    result = pk11uri_AllocURI();

    ret = pk11uri_InsertAttributes(&result->pattrs, &result->vpattrs,
                                   pattrs, num_pattrs,
                                   pattr_names, PR_ARRAY_SIZE(pattr_names),
                                   pk11uri_ComparePathAttributeName,
                                   PR_FALSE, PR_FALSE);
    if (ret != SECSuccess) {
        goto fail;
    }

    ret = pk11uri_InsertAttributes(&result->qattrs, &result->vqattrs,
                                   qattrs, num_qattrs,
                                   qattr_names, PR_ARRAY_SIZE(qattr_names),
                                   pk11uri_CompareQueryAttributeName,
                                   PR_FALSE, PR_TRUE);
    if (ret != SECSuccess) {
        goto fail;
    }

    return result;

fail:
    PK11URI_DestroyURI(result);

    return NULL;
}

/* Parsing. */
static SECStatus
pk11uri_ParseAttributes(const char **string,
                        const char *stop_chars,
                        int separator,
                        const char *accept_chars,
                        const char **attr_names, size_t num_attr_names,
                        PK11URIAttributeList *attrs,
                        PK11URIAttributeList *vattrs,
                        PK11URIAttributeCompareNameFunc compare_name,
                        PRBool allow_duplicate,
                        PRBool vendor_allow_duplicate)
{
    const char *p = *string;

    for (; *p != '\0'; p++) {
        const char *name_start, *name_end, *value_start, *value_end;
        size_t name_length, value_length, i;
        SECStatus ret;

        if (strchr(stop_chars, *p) != NULL) {
            break;
        }
        for (name_start = p; *p != '=' && *p != '\0'; p++) {
            if (strchr(PK11URI_ATTR_NM_CHAR, *p) != NULL)
                continue;

            return SECFailure;
        }
        if (*p == '\0') {
            return SECFailure;
        }
        name_end = p++;

        /* The attribute name must not be empty. */
        if (name_end == name_start) {
            return SECFailure;
        }

        for (value_start = p; *p != separator && *p != '\0'; p++) {
            if (strchr(stop_chars, *p) != NULL) {
                break;
            }
            if (strchr(accept_chars, *p) != NULL) {
                continue;
            }
            if (*p == '%') {
                const char ch2 = *++p;
                if (strchr(PK11URI_HEXDIG, ch2) != NULL) {
                    const char ch3 = *++p;
                    if (strchr(PK11URI_HEXDIG, ch3) != NULL)
                        continue;
                }
            }

            return SECFailure;
        }
        value_end = p;

        name_length = name_end - name_start;
        value_length = value_end - value_start;

        for (i = 0; i < num_attr_names; i++) {
            if (name_length == strlen(attr_names[i]) &&
                memcmp(name_start, attr_names[i], name_length) == 0) {
                break;
            }
        }
        if (i < num_attr_names) {
            /* Named attribute. */
            ret = pk11uri_InsertToAttributeListEscaped(attrs,
                                                       name_start, name_length,
                                                       value_start, value_length,
                                                       compare_name,
                                                       allow_duplicate);
            if (ret != SECSuccess) {
                return ret;
            }
        } else {
            /* Vendor attribute. */
            ret = pk11uri_InsertToAttributeListEscaped(vattrs,
                                                       name_start, name_length,
                                                       value_start, value_length,
                                                       strcmp,
                                                       vendor_allow_duplicate);
            if (ret != SECSuccess) {
                return ret;
            }
        }

        if (*p == '?' || *p == '\0') {
            break;
        }
    }

    *string = p;
    return SECSuccess;
}

PK11URI *
PK11URI_ParseURI(const char *string)
{
    PK11URI *result;
    const char *p = string;
    SECStatus ret;

    if (PORT_Strncasecmp("pkcs11:", p, 7) != 0) {
        return NULL;
    }
    p += 7;

    result = pk11uri_AllocURI();
    if (result == NULL) {
        return NULL;
    }

    /* Parse the path component and its attributes. */
    ret = pk11uri_ParseAttributes(&p, "?"';', PK11URI_PCHAR,
                                  pattr_names, PR_ARRAY_SIZE(pattr_names),
                                  &result->pattrs, &result->vpattrs,
                                  pk11uri_ComparePathAttributeName,
                                  PR_FALSE, PR_FALSE);
    if (ret != SECSuccess) {
        goto fail;
    }

    /* Parse the query component and its attributes. */
    if (*p == '?') {
        p++;
        ret = pk11uri_ParseAttributes(&p, ""'&', PK11URI_QCHAR,
                                      qattr_names, PR_ARRAY_SIZE(qattr_names),
                                      &result->qattrs, &result->vqattrs,
                                      pk11uri_CompareQueryAttributeName,
                                      PR_FALSE, PR_TRUE);
        if (ret != SECSuccess) {
            goto fail;
        }
    }

    return result;

fail:
    PK11URI_DestroyURI(result);

    return NULL;
}

/* Formatting. */
char *
PK11URI_FormatURI(PLArenaPool *arena, PK11URI *uri)
{
    PK11URIBuffer buffer;
    SECStatus ret;
    char *result = NULL;

    pk11uri_InitBuffer(&buffer, arena);

    ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"pkcs11:", 7);
    if (ret != SECSuccess)
        goto fail;

    ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->pattrs, ';', PK11URI_PCHAR);
    if (ret != SECSuccess) {
        goto fail;
    }

    if (uri->pattrs.num_attrs > 0 && uri->vpattrs.num_attrs > 0) {
        ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)";", 1);
        if (ret != SECSuccess) {
            goto fail;
        }
    }

    ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->vpattrs, ';',
                                              PK11URI_PCHAR);
    if (ret != SECSuccess) {
        goto fail;
    }

    if (uri->qattrs.num_attrs > 0 || uri->vqattrs.num_attrs > 0) {
        ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"?", 1);
        if (ret != SECSuccess) {
            goto fail;
        }
    }

    ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->qattrs, '&', PK11URI_QCHAR);
    if (ret != SECSuccess) {
        goto fail;
    }

    if (uri->qattrs.num_attrs > 0 && uri->vqattrs.num_attrs > 0) {
        ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"&", 1);
        if (ret != SECSuccess) {
            goto fail;
        }
    }

    ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->vqattrs, '&',
                                              PK11URI_QCHAR);
    if (ret != SECSuccess) {
        goto fail;
    }

    ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"\0", 1);
    if (ret != SECSuccess) {
        goto fail;
    }

    result = (char *)buffer.data;
    buffer.data = NULL;

fail:
    pk11uri_DestroyBuffer(&buffer);

    return result;
}

/* Deallocating. */
void
PK11URI_DestroyURI(PK11URI *uri)
{
    pk11uri_DestroyAttributeList(&uri->pattrs);
    pk11uri_DestroyAttributeList(&uri->vpattrs);
    pk11uri_DestroyAttributeList(&uri->qattrs);
    pk11uri_DestroyAttributeList(&uri->vqattrs);
    PORT_FreeArena(uri->arena, PR_FALSE);
}

/* Accessors. */
static const SECItem *
pk11uri_GetAttribute(PK11URIAttributeList *attrs,
                     PK11URIAttributeList *vattrs,
                     const char *name)
{
    size_t i;

    for (i = 0; i < attrs->num_attrs; i++) {
        if (strcmp(name, attrs->attrs[i].name) == 0) {
            return &attrs->attrs[i].value;
        }
    }

    for (i = 0; i < vattrs->num_attrs; i++) {
        if (strcmp(name, vattrs->attrs[i].name) == 0) {
            return &vattrs->attrs[i].value;
        }
    }

    return NULL;
}

const SECItem *
PK11URI_GetPathAttributeItem(PK11URI *uri, const char *name)
{
    return pk11uri_GetAttribute(&uri->pattrs, &uri->vpattrs, name);
}

const char *
PK11URI_GetPathAttribute(PK11URI *uri, const char *name)
{
    const SECItem *value;

    value = PK11URI_GetPathAttributeItem(uri, name);
    if (!value) {
        return NULL;
    }

    return (const char *)value->data;
}

const SECItem *
PK11URI_GetQueryAttributeItem(PK11URI *uri, const char *name)
{
    return pk11uri_GetAttribute(&uri->qattrs, &uri->vqattrs, name);
}

const char *
PK11URI_GetQueryAttribute(PK11URI *uri, const char *name)
{
    const SECItem *value;

    value = PK11URI_GetQueryAttributeItem(uri, name);
    if (!value) {
        return NULL;
    }

    return (const char *)value->data;
}

Messung V0.5
C=98 H=80 G=89

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.