1/* crypto/txt_db/txt_db.c */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved.
4 *
5 * This package is an SSL implementation written
6 * by Eric Young (eay@cryptsoft.com).
7 * The implementation was written so as to conform with Netscapes SSL.
8 *
9 * This library is free for commercial and non-commercial use as long as
10 * the following conditions are aheared to.  The following conditions
11 * apply to all code found in this distribution, be it the RC4, RSA,
12 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13 * included with this distribution is covered by the same copyright terms
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15 *
16 * Copyright remains Eric Young's, and as such any Copyright notices in
17 * the code are not to be removed.
18 * If this package is used in a product, Eric Young should be given attribution
19 * as the author of the parts of the library used.
20 * This can be in the form of a textual message at program startup or
21 * in documentation (online or textual) provided with the package.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the copyright
27 *    notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 *    notice, this list of conditions and the following disclaimer in the
30 *    documentation and/or other materials provided with the distribution.
31 * 3. All advertising materials mentioning features or use of this software
32 *    must display the following acknowledgement:
33 *    "This product includes cryptographic software written by
34 *     Eric Young (eay@cryptsoft.com)"
35 *    The word 'cryptographic' can be left out if the rouines from the library
36 *    being used are not cryptographic related :-).
37 * 4. If you include any Windows specific code (or a derivative thereof) from
38 *    the apps directory (application code) you must include an acknowledgement:
39 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40 *
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 *
53 * The licence and distribution terms for any publically available version or
54 * derivative of this code cannot be changed.  i.e. this code cannot simply be
55 * copied and put under another distribution licence
56 * [including the GNU Public Licence.]
57 */
58
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include "cryptlib.h"
63#include <openssl/buffer.h>
64#include <openssl/txt_db.h>
65
66#undef BUFSIZE
67#define BUFSIZE	512
68
69const char TXT_DB_version[]="TXT_DB" OPENSSL_VERSION_PTEXT;
70
71TXT_DB *TXT_DB_read(BIO *in, int num)
72	{
73	TXT_DB *ret=NULL;
74	int er=1;
75	int esc=0;
76	long ln=0;
77	int i,add,n;
78	int size=BUFSIZE;
79	int offset=0;
80	char *p,**pp,*f;
81	BUF_MEM *buf=NULL;
82
83	if ((buf=BUF_MEM_new()) == NULL) goto err;
84	if (!BUF_MEM_grow(buf,size)) goto err;
85
86	if ((ret=(TXT_DB *)OPENSSL_malloc(sizeof(TXT_DB))) == NULL)
87		goto err;
88	ret->num_fields=num;
89	ret->index=NULL;
90	ret->qual=NULL;
91	if ((ret->data=sk_new_null()) == NULL)
92		goto err;
93	if ((ret->index=(LHASH **)OPENSSL_malloc(sizeof(LHASH *)*num)) == NULL)
94		goto err;
95	if ((ret->qual=(int (**)(char **))OPENSSL_malloc(sizeof(int (**)(char **))*num)) == NULL)
96		goto err;
97	for (i=0; i<num; i++)
98		{
99		ret->index[i]=NULL;
100		ret->qual[i]=NULL;
101		}
102
103	add=(num+1)*sizeof(char *);
104	buf->data[size-1]='\0';
105	offset=0;
106	for (;;)
107		{
108		if (offset != 0)
109			{
110			size+=BUFSIZE;
111			if (!BUF_MEM_grow_clean(buf,size)) goto err;
112			}
113		buf->data[offset]='\0';
114		BIO_gets(in,&(buf->data[offset]),size-offset);
115		ln++;
116		if (buf->data[offset] == '\0') break;
117		if ((offset == 0) && (buf->data[0] == '#')) continue;
118		i=strlen(&(buf->data[offset]));
119		offset+=i;
120		if (buf->data[offset-1] != '\n')
121			continue;
122		else
123			{
124			buf->data[offset-1]='\0'; /* blat the '\n' */
125			if (!(p=(char *)OPENSSL_malloc(add+offset))) goto err;
126			offset=0;
127			}
128		pp=(char **)p;
129		p+=add;
130		n=0;
131		pp[n++]=p;
132		i=0;
133		f=buf->data;
134
135		esc=0;
136		for (;;)
137			{
138			if (*f == '\0') break;
139			if (*f == '\t')
140				{
141				if (esc)
142					p--;
143				else
144					{
145					*(p++)='\0';
146					f++;
147					if (n >=  num) break;
148					pp[n++]=p;
149					continue;
150					}
151				}
152			esc=(*f == '\\');
153			*(p++)= *(f++);
154			}
155		*(p++)='\0';
156		if ((n != num) || (*f != '\0'))
157			{
158#if !defined(OPENSSL_NO_STDIO) && !defined(OPENSSL_SYS_WIN16)	/* temporaty fix :-( */
159			fprintf(stderr,"wrong number of fields on line %ld (looking for field %d, got %d, '%s' left)\n",ln,num,n,f);
160#endif
161			er=2;
162			goto err;
163			}
164		pp[n]=p;
165		if (!sk_push(ret->data,(char *)pp))
166			{
167#if !defined(OPENSSL_NO_STDIO) && !defined(OPENSSL_SYS_WIN16)	/* temporaty fix :-( */
168			fprintf(stderr,"failure in sk_push\n");
169#endif
170			er=2;
171			goto err;
172			}
173		}
174	er=0;
175err:
176	BUF_MEM_free(buf);
177	if (er)
178		{
179#if !defined(OPENSSL_NO_STDIO) && !defined(OPENSSL_SYS_WIN16)
180		if (er == 1) fprintf(stderr,"OPENSSL_malloc failure\n");
181#endif
182		if (ret != NULL)
183			{
184			if (ret->data != NULL) sk_free(ret->data);
185			if (ret->index != NULL) OPENSSL_free(ret->index);
186			if (ret->qual != NULL) OPENSSL_free(ret->qual);
187			if (ret != NULL) OPENSSL_free(ret);
188			}
189		return(NULL);
190		}
191	else
192		return(ret);
193	}
194
195char **TXT_DB_get_by_index(TXT_DB *db, int idx, char **value)
196	{
197	char **ret;
198	LHASH *lh;
199
200	if (idx >= db->num_fields)
201		{
202		db->error=DB_ERROR_INDEX_OUT_OF_RANGE;
203		return(NULL);
204		}
205	lh=db->index[idx];
206	if (lh == NULL)
207		{
208		db->error=DB_ERROR_NO_INDEX;
209		return(NULL);
210		}
211	ret=(char **)lh_retrieve(lh,value);
212	db->error=DB_ERROR_OK;
213	return(ret);
214	}
215
216int TXT_DB_create_index(TXT_DB *db, int field, int (*qual)(char **),
217		LHASH_HASH_FN_TYPE hash, LHASH_COMP_FN_TYPE cmp)
218	{
219	LHASH *idx;
220	char **r;
221	int i,n;
222
223	if (field >= db->num_fields)
224		{
225		db->error=DB_ERROR_INDEX_OUT_OF_RANGE;
226		return(0);
227		}
228	if ((idx=lh_new(hash,cmp)) == NULL)
229		{
230		db->error=DB_ERROR_MALLOC;
231		return(0);
232		}
233	n=sk_num(db->data);
234	for (i=0; i<n; i++)
235		{
236		r=(char **)sk_value(db->data,i);
237		if ((qual != NULL) && (qual(r) == 0)) continue;
238		if ((r=lh_insert(idx,r)) != NULL)
239			{
240			db->error=DB_ERROR_INDEX_CLASH;
241			db->arg1=sk_find(db->data,(char *)r);
242			db->arg2=i;
243			lh_free(idx);
244			return(0);
245			}
246		}
247	if (db->index[field] != NULL) lh_free(db->index[field]);
248	db->index[field]=idx;
249	db->qual[field]=qual;
250	return(1);
251	}
252
253long TXT_DB_write(BIO *out, TXT_DB *db)
254	{
255	long i,j,n,nn,l,tot=0;
256	char *p,**pp,*f;
257	BUF_MEM *buf=NULL;
258	long ret= -1;
259
260	if ((buf=BUF_MEM_new()) == NULL)
261		goto err;
262	n=sk_num(db->data);
263	nn=db->num_fields;
264	for (i=0; i<n; i++)
265		{
266		pp=(char **)sk_value(db->data,i);
267
268		l=0;
269		for (j=0; j<nn; j++)
270			{
271			if (pp[j] != NULL)
272				l+=strlen(pp[j]);
273			}
274		if (!BUF_MEM_grow_clean(buf,(int)(l*2+nn))) goto err;
275
276		p=buf->data;
277		for (j=0; j<nn; j++)
278			{
279			f=pp[j];
280			if (f != NULL)
281				for (;;)
282					{
283					if (*f == '\0') break;
284					if (*f == '\t') *(p++)='\\';
285					*(p++)= *(f++);
286					}
287			*(p++)='\t';
288			}
289		p[-1]='\n';
290		j=p-buf->data;
291		if (BIO_write(out,buf->data,(int)j) != j)
292			goto err;
293		tot+=j;
294		}
295	ret=tot;
296err:
297	if (buf != NULL) BUF_MEM_free(buf);
298	return(ret);
299	}
300
301int TXT_DB_insert(TXT_DB *db, char **row)
302	{
303	int i;
304	char **r;
305
306	for (i=0; i<db->num_fields; i++)
307		{
308		if (db->index[i] != NULL)
309			{
310			if ((db->qual[i] != NULL) &&
311				(db->qual[i](row) == 0)) continue;
312			r=(char **)lh_retrieve(db->index[i],row);
313			if (r != NULL)
314				{
315				db->error=DB_ERROR_INDEX_CLASH;
316				db->arg1=i;
317				db->arg_row=r;
318				goto err;
319				}
320			}
321		}
322	/* We have passed the index checks, now just append and insert */
323	if (!sk_push(db->data,(char *)row))
324		{
325		db->error=DB_ERROR_MALLOC;
326		goto err;
327		}
328
329	for (i=0; i<db->num_fields; i++)
330		{
331		if (db->index[i] != NULL)
332			{
333			if ((db->qual[i] != NULL) &&
334				(db->qual[i](row) == 0)) continue;
335			lh_insert(db->index[i],row);
336			}
337		}
338	return(1);
339err:
340	return(0);
341	}
342
343void TXT_DB_free(TXT_DB *db)
344	{
345	int i,n;
346	char **p,*max;
347
348	if(db == NULL)
349	    return;
350
351	if (db->index != NULL)
352		{
353		for (i=db->num_fields-1; i>=0; i--)
354			if (db->index[i] != NULL) lh_free(db->index[i]);
355		OPENSSL_free(db->index);
356		}
357	if (db->qual != NULL)
358		OPENSSL_free(db->qual);
359	if (db->data != NULL)
360		{
361		for (i=sk_num(db->data)-1; i>=0; i--)
362			{
363			/* check if any 'fields' have been allocated
364			 * from outside of the initial block */
365			p=(char **)sk_value(db->data,i);
366			max=p[db->num_fields]; /* last address */
367			if (max == NULL) /* new row */
368				{
369				for (n=0; n<db->num_fields; n++)
370					if (p[n] != NULL) OPENSSL_free(p[n]);
371				}
372			else
373				{
374				for (n=0; n<db->num_fields; n++)
375					{
376					if (((p[n] < (char *)p) || (p[n] > max))
377						&& (p[n] != NULL))
378						OPENSSL_free(p[n]);
379					}
380				}
381			OPENSSL_free(sk_value(db->data,i));
382			}
383		sk_free(db->data);
384		}
385	OPENSSL_free(db);
386	}
387