1/*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is the Netscape security libraries.
13 *
14 * The Initial Developer of the Original Code is Netscape
15 * Communications Corporation.  Portions created by Netscape are
16 * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
17 * Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the
22 * terms of the GNU General Public License Version 2 or later (the
23 * "GPL"), in which case the provisions of the GPL are applicable
24 * instead of those above.  If you wish to allow use of your
25 * version of this file only under the terms of the GPL and not to
26 * allow others to use your version of this file under the MPL,
27 * indicate your decision by deleting the provisions above and
28 * replace them with the notice and other provisions required by
29 * the GPL.  If you do not delete the provisions above, a recipient
30 * may use your version of this file under either the MPL or the
31 * GPL.
32 */
33
34/*
35 * Support routines for SECItem data structure.
36 */
37
38#include "secitem.h"
39#include <security_asn1/seccomon.h>
40#include <security_asn1/secerr.h>
41
42SECItem *
43SECITEM_AllocItem(PRArenaPool *arena, SECItem *item, unsigned int len)
44{
45    SECItem *result = NULL;
46    void *mark = NULL;
47
48    if (arena != NULL) {
49	mark = PORT_ArenaMark(arena);
50    }
51
52    if (item == NULL) {
53	if (arena != NULL) {
54	    result = PORT_ArenaZAlloc(arena, sizeof(SECItem));
55	} else {
56	    result = PORT_ZAlloc(sizeof(SECItem));
57	}
58	if (result == NULL) {
59	    goto loser;
60	}
61    } else {
62	PORT_Assert(item->Data == NULL);
63	result = item;
64    }
65
66    result->Length = len;
67    if (len) {
68	if (arena != NULL) {
69	    result->Data = PORT_ArenaAlloc(arena, len);
70	} else {
71	    result->Data = PORT_Alloc(len);
72	}
73    }
74
75    if (mark) {
76	PORT_ArenaUnmark(arena, mark);
77    }
78    return(result);
79
80loser:
81    if ( arena != NULL ) {
82	if (mark) {
83	    PORT_ArenaRelease(arena, mark);
84	}
85	if (item != NULL) {
86	    item->Data = NULL;
87	    item->Length = 0;
88	}
89    } else {
90	if (result != NULL) {
91	    SECITEM_FreeItem(result, (item == NULL) ? PR_TRUE : PR_FALSE);
92	}
93    }
94    return(NULL);
95}
96
97SECStatus
98SECITEM_ReallocItem(PRArenaPool *arena, SECItem *item, unsigned int oldlen,
99		    unsigned int newlen)
100{
101    PORT_Assert(item != NULL);
102    if (item == NULL) {
103	/* XXX Set error.  But to what? */
104	return SECFailure;
105    }
106
107    /*
108     * If no old length, degenerate to just plain alloc.
109     */
110    if (oldlen == 0) {
111	PORT_Assert(item->Data == NULL || item->Length == 0);
112	if (newlen == 0) {
113	    /* Nothing to do.  Weird, but not a failure.  */
114	    return SECSuccess;
115	}
116	item->Length = newlen;
117	if (arena != NULL) {
118	    item->Data = PORT_ArenaAlloc(arena, newlen);
119	} else {
120	    item->Data = PORT_Alloc(newlen);
121	}
122    } else {
123	if (arena != NULL) {
124	    item->Data = PORT_ArenaGrow(arena, item->Data, oldlen, newlen);
125	} else {
126	    item->Data = PORT_Realloc(item->Data, newlen);
127	}
128    }
129
130    if (item->Data == NULL) {
131	return SECFailure;
132    }
133
134    return SECSuccess;
135}
136
137SECComparison
138SECITEM_CompareItem(const SECItem *a, const SECItem *b)
139{
140    CSSM_SIZE m;
141    SECComparison rv;
142
143    m = ( ( a->Length < b->Length ) ? a->Length : b->Length );
144
145    rv = (SECComparison) PORT_Memcmp(a->Data, b->Data, m);
146    if (rv) {
147	return rv;
148    }
149    if (a->Length < b->Length) {
150	return SECLessThan;
151    }
152    if (a->Length == b->Length) {
153	return SECEqual;
154    }
155    return SECGreaterThan;
156}
157
158Boolean
159SECITEM_ItemsAreEqual(const SECItem *a, const SECItem *b)
160{
161    if (a->Length != b->Length)
162        return PR_FALSE;
163    if (!a->Length)
164    	return PR_TRUE;
165    if (!a->Data || !b->Data) {
166        /* avoid null pointer crash. */
167		return (Boolean)(a->Data == b->Data);
168    }
169    return (Boolean)!PORT_Memcmp(a->Data, b->Data, a->Length);
170}
171
172SECItem *
173SECITEM_DupItem(const SECItem *from)
174{
175    return SECITEM_ArenaDupItem(NULL, from);
176}
177
178SECItem *
179SECITEM_ArenaDupItem(PRArenaPool *arena, const SECItem *from)
180{
181    SECItem *to;
182
183    if ( from == NULL ) {
184		return(NULL);
185    }
186
187    if ( arena != NULL ) {
188		to = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
189    } else {
190		to = (SECItem *)PORT_Alloc(sizeof(SECItem));
191    }
192    if ( to == NULL ) {
193		return(NULL);
194    }
195
196    if ( arena != NULL ) {
197		to->Data = (unsigned char *)PORT_ArenaAlloc(arena, from->Length);
198    } else {
199		to->Data = (unsigned char *)PORT_Alloc(from->Length);
200    }
201    if ( to->Data == NULL ) {
202		PORT_Free(to);
203		return(NULL);
204    }
205
206    to->Length = from->Length;
207    // to->type = from->type;
208    if ( to->Length ) {
209		PORT_Memcpy(to->Data, from->Data, to->Length);
210    }
211
212    return(to);
213}
214
215SECStatus
216SECITEM_CopyItem(PRArenaPool *arena, SECItem *to, const SECItem *from)
217{
218    // to->type = from->type;
219    if (from->Data && from->Length) {
220	if ( arena ) {
221	    to->Data = (unsigned char*) PORT_ArenaAlloc(arena, from->Length);
222	} else {
223	    to->Data = (unsigned char*) PORT_Alloc(from->Length);
224	}
225
226	if (!to->Data) {
227	    return SECFailure;
228	}
229	PORT_Memcpy(to->Data, from->Data, from->Length);
230	to->Length = from->Length;
231    } else {
232	to->Data = 0;
233	to->Length = 0;
234    }
235    return SECSuccess;
236}
237
238void
239SECITEM_FreeItem(SECItem *zap, Boolean freeit)
240{
241    if (zap) {
242	PORT_Free(zap->Data);
243	zap->Data = 0;
244	zap->Length = 0;
245	if (freeit) {
246	    PORT_Free(zap);
247	}
248    }
249}
250
251void
252SECITEM_ZfreeItem(SECItem *zap, Boolean freeit)
253{
254    if (zap) {
255	PORT_ZFree(zap->Data, zap->Length);
256	zap->Data = 0;
257	zap->Length = 0;
258	if (freeit) {
259	    PORT_ZFree(zap, sizeof(SECItem));
260	}
261    }
262}
263
264
265/* these reroutines were taken from pkix oid.c, which is supposed to
266 * replace this file some day */
267/*
268 * This is the hash function.  We simply XOR the encoded form with
269 * itself in sizeof(PLHashNumber)-byte chunks.  Improving this
270 * routine is left as an excercise for the more mathematically
271 * inclined student.
272 */
273PLHashNumber PR_CALLBACK
274SECITEM_Hash ( const void *key)
275{
276    const SECItem *item = (const SECItem *)key;
277    PLHashNumber rv = 0;
278
279    PRUint8 *data = (PRUint8 *)item->Data;
280    PRUint32 i;
281    PRUint8 *rvc = (PRUint8 *)&rv;
282
283    for( i = 0; i < item->Length; i++ ) {
284        rvc[ i % sizeof(rv) ] ^= *data;
285        data++;
286    }
287
288    return rv;
289}
290
291/*
292 * This is the key-compare function.  It simply does a lexical
293 * comparison on the item data.  This does not result in
294 * quite the same ordering as the "sequence of numbers" order,
295 * but heck it's only used internally by the hash table anyway.
296 */
297PRIntn PR_CALLBACK
298SECITEM_HashCompare ( const void *k1, const void *k2)
299{
300    const SECItem *i1 = (const SECItem *)k1;
301    const SECItem *i2 = (const SECItem *)k2;
302
303    return SECITEM_ItemsAreEqual(i1,i2);
304}
305