]> git.deb.at Git - pkg/abook.git/blob - ldif.c
custom output format (3/4): added the --outformatstr option
[pkg/abook.git] / ldif.c
1
2 /*
3  * $Id$
4  * adapted to use with abook by JH <jheinonen@users.sourceforge.net>
5  */
6
7 /*
8  *
9  * Copyright (c) 1992-1996 Regents of the University of Michigan.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms are permitted
13  * provided that this notice is preserved and that due credit is given
14  * to the University of Michigan at Ann Arbor. The name of the University
15  * may not be used to endorse or promote products derived from this
16  * software without specific prior written permission. This software
17  * is provided ``as is'' without express or implied warranty.
18  *
19  */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include "ldif.h"
28
29 #define ISSPACE(c) isspace((unsigned char)c)
30
31 #define LDAP_DEBUG_PARSE        0x800
32 #define LDAP_DEBUG_ANY          0xffff
33 #define LDIF_LINE_WIDTH         76      /* maximum length of LDIF lines */
34 #define LDIF_BASE64_LEN(vlen)   (((vlen) * 4 / 3 ) + 3)
35
36 #define LDIF_SIZE_NEEDED(tlen,vlen) \
37         ((tlen) + 4 + LDIF_BASE64_LEN(vlen) \
38      + ((LDIF_BASE64_LEN(vlen) + tlen + 3) / LDIF_LINE_WIDTH * 2 ))
39
40
41 #define Debug( level, fmt, arg1, arg2, arg3 )
42
43 #define RIGHT2                  0x03
44 #define RIGHT4                  0x0f
45 #define CONTINUED_LINE_MARKER   '\001'
46
47 static char nib2b64[0x40f] =
48     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
49
50 static unsigned char b642nib[0x80] = {
51         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
52         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56         0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
57         0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
58         0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59         0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
60         0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
61         0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
62         0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
63         0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
64         0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
65         0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
66         0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
67 };
68
69 /*
70  * str_parse_line - takes a line of the form "type:[:] value" and splits it
71  * into components "type" and "value".  if a double colon separates type from
72  * value, then value is encoded in base 64, and parse_line un-decodes it
73  * (in place) before returning.
74  */
75
76 int
77 str_parse_line(char *line, char **type, char **value, int *vlen)
78 {
79         char *p, *s, *d, *byte, *stop;
80         char nib;
81         int i, b64;
82
83         /* skip any leading space */
84         while(ISSPACE(*line)) {
85                 line++;
86         }
87         *type = line;
88
89         for(s = line; *s && *s != ':'; s++);    /* NULL */
90         if(*s == '\0') {
91                 Debug(LDAP_DEBUG_PARSE, "parse_line missing ':'\n", 0, 0,
92                       0);
93                 return (-1);
94         }
95
96         /* trim any space between type and : */
97         for(p = s - 1; p > line && ISSPACE(*p); p--) {
98                 *p = '\0';
99         }
100         *s++ = '\0';
101
102         /* check for double : - indicates base 64 encoded value */
103         if(*s == ':') {
104                 s++;
105                 b64 = 1;
106
107                 /* single : - normally encoded value */
108         } else {
109                 b64 = 0;
110         }
111
112         /* skip space between : and value */
113         while(ISSPACE(*s)) {
114                 s++;
115         }
116
117         /* if no value is present, error out */
118         if(*s == '\0') {
119                 Debug(LDAP_DEBUG_PARSE, "parse_line missing value\n", 0, 0,
120                       0);
121                 return (-1);
122         }
123
124         /* check for continued line markers that should be deleted */
125         for(p = s, d = s; *p; p++) {
126                 if(*p != CONTINUED_LINE_MARKER)
127                         *d++ = *p;
128         }
129         *d = '\0';
130
131         *value = s;
132         if(b64) {
133                 stop = strchr(s, '\0');
134                 byte = s;
135                 for(p = s, *vlen = 0; p < stop; p += 4, *vlen += 3) {
136                         for(i = 0; i < 3; i++) {
137                                 if(p[i] != '=' && (p[i] & 0x80 ||
138                                                    b642nib[p[i] & 0x7f] >
139                                                    0x3f)) {
140                                         Debug(LDAP_DEBUG_ANY,
141                                               "invalid base 64 encoding char (%c) 0x%x\n",
142                                               p[i], p[i], 0);
143                                         return (-1);
144                                 }
145                         }
146
147                         /* first digit */
148                         nib = b642nib[p[0] & 0x7f];
149                         byte[0] = nib << 2;
150                         /* second digit */
151                         nib = b642nib[p[1] & 0x7f];
152                         byte[0] |= nib >> 4;
153                         byte[1] = (nib & RIGHT4) << 4;
154                         /* third digit */
155                         if(p[2] == '=') {
156                                 *vlen += 1;
157                                 break;
158                         }
159                         nib = b642nib[p[2] & 0x7f];
160                         byte[1] |= nib >> 2;
161                         byte[2] = (nib & RIGHT2) << 6;
162                         /* fourth digit */
163                         if(p[3] == '=') {
164                                 *vlen += 2;
165                                 break;
166                         }
167                         nib = b642nib[p[3] & 0x7f];
168                         byte[2] |= nib;
169
170                         byte += 3;
171                 }
172                 s[*vlen] = '\0';
173         } else {
174                 *vlen = (int) (d - s);
175         }
176
177         return (0);
178 }
179
180 #if 0
181
182 /*
183  * str_getline - return the next "line" (minus newline) of input from a
184  * string buffer of lines separated by newlines, terminated by \n\n
185  * or \0.  this routine handles continued lines, bundling them into
186  * a single big line before returning.  if a line begins with a white
187  * space character, it is a continuation of the previous line. the white
188  * space character (nb: only one char), and preceeding newline are changed
189  * into CONTINUED_LINE_MARKER chars, to be deleted later by the
190  * str_parse_line() routine above.
191  *
192  * it takes a pointer to a pointer to the buffer on the first call,
193  * which it updates and must be supplied on subsequent calls.
194  */
195
196 char *
197 str_getline(char **next)
198 {
199         char *l;
200         char c;
201
202         if(*next == NULL || **next == '\n' || **next == '\0') {
203                 return (NULL);
204         }
205
206         l = *next;
207         while((*next = strchr(*next, '\n')) != NULL) {
208                 c = *(*next + 1);
209                 if(ISSPACE(c) && c != '\n') {
210                         **next = CONTINUED_LINE_MARKER;
211                         *(*next + 1) = CONTINUED_LINE_MARKER;
212                 } else {
213                         *(*next)++ = '\0';
214                         break;
215                 }
216                 (*next)++;
217         }
218
219         return (l);
220 }
221
222 #endif
223
224 void
225 put_type_and_value(char **out, char *t, char *val, int vlen)
226 {
227         unsigned char *byte, *p, *stop;
228         unsigned char buf[3];
229         unsigned long bits;
230         char *save;
231         int i, b64, pad, len, savelen;
232         len = 0;
233
234         /* put the type + ": " */
235         for(p = (unsigned char *) t; *p; p++, len++) {
236                 *(*out)++ = *p;
237         }
238         *(*out)++ = ':';
239         len++;
240         save = *out;
241         savelen = len;
242         *(*out)++ = ' ';
243         b64 = 0;
244
245         stop = (unsigned char *) (val + vlen);
246         if(isascii(val[0]) && (ISSPACE(val[0]) || val[0] == ':')) {
247                 b64 = 1;
248         } else {
249                 for(byte = (unsigned char *) val; byte < stop;
250                     byte++, len++) {
251                         if(!isascii(*byte) || !isprint(*byte)) {
252                                 b64 = 1;
253                                 break;
254                         }
255                         if(len > LDIF_LINE_WIDTH) {
256                                 *(*out)++ = '\n';
257                                 *(*out)++ = ' ';
258                                 len = 1;
259                         }
260                         *(*out)++ = *byte;
261                 }
262         }
263         if(b64) {
264                 *out = save;
265                 *(*out)++ = ':';
266                 *(*out)++ = ' ';
267                 len = savelen + 2;
268                 /* convert to base 64 (3 bytes => 4 base 64 digits) */
269                 for(byte = (unsigned char *) val; byte < stop - 2;
270                     byte += 3) {
271                         bits = (byte[0] & 0xff) << 16;
272                         bits |= (byte[1] & 0xff) << 8;
273                         bits |= (byte[2] & 0xff);
274
275                         for(i = 0; i < 4; i++, len++, bits <<= 6) {
276                                 if(len > LDIF_LINE_WIDTH) {
277                                         *(*out)++ = '\n';
278                                         *(*out)++ = ' ';
279                                         len = 1;
280                                 }
281
282                                 /* get b64 digit from high order 6 bits */
283                                 *(*out)++ =
284                                     nib2b64[(bits & 0xfc0000L) >> 18];
285                         }
286                 }
287
288                 /* add padding if necessary */
289                 if(byte < stop) {
290                         for(i = 0; byte + i < stop; i++) {
291                                 buf[i] = byte[i];
292                         }
293                         for(pad = 0; i < 3; i++, pad++) {
294                                 buf[i] = '\0';
295                         }
296                         byte = buf;
297                         bits = (byte[0] & 0xff) << 16;
298                         bits |= (byte[1] & 0xff) << 8;
299                         bits |= (byte[2] & 0xff);
300
301                         for(i = 0; i < 4; i++, len++, bits <<= 6) {
302                                 if(len > LDIF_LINE_WIDTH) {
303                                         *(*out)++ = '\n';
304                                         *(*out)++ = ' ';
305                                         len = 1;
306                                 }
307
308                                 /* get b64 digit from low order 6 bits */
309                                 *(*out)++ =
310                                     nib2b64[(bits & 0xfc0000L) >> 18];
311                         }
312
313                         for(; pad > 0; pad--) {
314                                 *(*out - pad) = '=';
315                         }
316                 }
317         }
318         *(*out)++ = '\n';
319 }
320
321
322 char *
323 ldif_type_and_value(char *type, char *val, int vlen)
324 /*
325  * return malloc'd, zero-terminated LDIF line
326  */
327 {
328         char *buf, *p;
329         int tlen;
330         size_t bufsize, t;
331
332         tlen = strlen(type);
333
334         t = LDIF_SIZE_NEEDED(tlen, vlen);
335         if((bufsize = t + 1) <= t)
336                 return NULL;
337
338         if((buf = malloc(bufsize)) == NULL) {
339                 return NULL;
340         }
341
342         p = buf;
343         put_type_and_value(&p, type, val, vlen);
344         *p = '\0';
345
346         return (buf);
347 }