1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5/*
6 * Support routines for SECItemArray data structure.
7 */
8
9#include "nssutil.h"
10#include "seccomon.h"
11#include "secitem.h"
12#include "secerr.h"
13#include "secport.h"
14
15#define NSSUTIL_VERSION_NUM \
16    (NSSUTIL_VMAJOR * 10000 + NSSUTIL_VMINOR * 100 + NSSUTIL_VPATCH)
17#if NSSUTIL_VERSION_NUM < 31500
18// Added in NSS 3.15.
19typedef struct SECItemArrayStr SECItemArray;
20
21struct SECItemArrayStr {
22    SECItem *items;
23    unsigned int len;
24};
25#endif
26
27SECItemArray *
28SECITEM_AllocArray(PLArenaPool *arena, SECItemArray *array, unsigned int len)
29{
30    SECItemArray *result = NULL;
31    void *mark = NULL;
32
33    if (arena != NULL) {
34        mark = PORT_ArenaMark(arena);
35    }
36
37    if (array == NULL) {
38        if (arena != NULL) {
39            result = PORT_ArenaZAlloc(arena, sizeof(SECItemArray));
40        } else {
41            result = PORT_ZAlloc(sizeof(SECItemArray));
42        }
43        if (result == NULL) {
44            goto loser;
45        }
46    } else {
47        PORT_Assert(array->items == NULL);
48        result = array;
49    }
50
51    result->len = len;
52    if (len) {
53        if (arena != NULL) {
54            result->items = PORT_ArenaZNewArray(arena, SECItem, len);
55        } else {
56            result->items = PORT_ZNewArray(SECItem, len);
57        }
58        if (result->items == NULL) {
59            goto loser;
60        }
61    } else {
62        result->items = NULL;
63    }
64
65    if (mark) {
66        PORT_ArenaUnmark(arena, mark);
67    }
68    return(result);
69
70loser:
71    if ( arena != NULL ) {
72        if (mark) {
73            PORT_ArenaRelease(arena, mark);
74        }
75        if (array != NULL) {
76            array->items = NULL;
77            array->len = 0;
78        }
79    } else {
80        if (result != NULL && array == NULL) {
81            PORT_Free(result);
82        }
83        /*
84         * If array is not NULL, the above has set array->data and
85         * array->len to 0.
86         */
87    }
88    return(NULL);
89}
90
91static void
92secitem_FreeArray(SECItemArray *array, PRBool zero_items, PRBool freeit)
93{
94    unsigned int i;
95
96    if (!array || !array->len || !array->items)
97        return;
98
99    for (i=0; i<array->len; ++i) {
100        SECItem *item = &array->items[i];
101
102        if (item->data) {
103            if (zero_items) {
104                SECITEM_ZfreeItem(item, PR_FALSE);
105            } else {
106                SECITEM_FreeItem(item, PR_FALSE);
107            }
108        }
109    }
110    PORT_Free(array->items);
111    array->items = NULL;
112    array->len = 0;
113
114    if (freeit)
115        PORT_Free(array);
116}
117
118void SECITEM_FreeArray(SECItemArray *array, PRBool freeit)
119{
120    secitem_FreeArray(array, PR_FALSE, freeit);
121}
122
123void SECITEM_ZfreeArray(SECItemArray *array, PRBool freeit)
124{
125    secitem_FreeArray(array, PR_TRUE, freeit);
126}
127
128SECItemArray *
129SECITEM_DupArray(PLArenaPool *arena, const SECItemArray *from)
130{
131    SECItemArray *result;
132    unsigned int i;
133
134    if (!from || !from->items || !from->len)
135        return NULL;
136
137    result = SECITEM_AllocArray(arena, NULL, from->len);
138    if (!result)
139        return NULL;
140
141    for (i=0; i<from->len; ++i) {
142        SECStatus rv = SECITEM_CopyItem(arena,
143                                        &result->items[i], &from->items[i]);
144        if (rv != SECSuccess) {
145            SECITEM_ZfreeArray(result, PR_TRUE);
146            return NULL;
147        }
148    }
149
150    return result;
151}
152