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