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