Convert minimime to use the proper uint*_t types, rather than u_int*_t
[asterisk/asterisk.git] / main / minimime / mm_base64.c
1 /*
2  * Copyright (C) 2003 Jann Fischer <jfi@openbsd.de>
3  * All rights reserved.
4  *
5  * XXX: This piece of software is not nearly MIME compatible as it should be.
6  *
7  * This is based on third-party code, see the copyright notice below.
8  *
9  */
10
11 /* $Id$ */
12
13 /***********************************************************
14         Copyright 1998 by Carnegie Mellon University
15
16                       All Rights Reserved
17
18 Permission to use, copy, modify, and distribute this software and its
19 documentation for any purpose and without fee is hereby granted,
20 provided that the above copyright notice appear in all copies and that
21 both that copyright notice and this permission notice appear in
22 supporting documentation, and that the name of Carnegie Mellon
23 University not be used in advertising or publicity pertaining to
24 distribution of the software without specific, written prior
25 permission.
26
27 CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
28 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
29 FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
30 ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
31 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
32 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
33 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
34 ******************************************************************/
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <assert.h>
38
39 #include "mm_internal.h"
40
41 #define XX 127
42
43 static int _mm_base64_decode(char *);
44 static char *_mm_base64_encode(char *, uint32_t);
45
46 /*
47  * Tables for encoding/decoding base64
48  */
49 static const char basis_64[] =
50    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
51 static const char index_64[256] = {
52         XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
53         XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
54         XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63,
55         52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,XX,XX,XX,
56         XX, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
57         15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX,
58         XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
59         41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
60         XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
61         XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
62         XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
63         XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
64         XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
65         XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
66         XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
67         XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
68 };
69 #define CHAR64(c)  (index_64[(unsigned char)(c)])
70
71 /*
72  * mm_base64_decode()
73  *
74  * Decodes the data pointed to by 'data' from the BASE64 encoding to the data
75  * format it was encoded from. Returns a pointer to a string on success or
76  * NULL on error. The string returned needs to be freed by the caller at some
77  * later point.
78  *
79  */
80 char *
81 mm_base64_decode(char *data)
82 {
83         char *buf;
84
85         assert(data != NULL);
86
87         buf = mm_stripchars(data, "\r\n");
88         assert(buf != NULL);
89
90         _mm_base64_decode(buf);
91         assert(buf != NULL);
92         return(buf);
93 }
94
95 /*
96  * mm_base64_encode()
97  *
98  * Encodes the data pointed to by 'data', which is of the length specified in
99  * 'len' to the BASE64 format. Returns a pointer to a string containing the
100  * BASE64 encoding, whose lines are broken at the MIME recommended linelength
101  * of 76 characters. If an error occured, returns NULL. The string returned
102  * needs to be freed by the caller at some later point.
103  *
104  */
105 char *
106 mm_base64_encode(char *data, uint32_t len) {
107         char *buf;
108         char *ret;
109
110         assert(data != NULL);
111
112         buf = _mm_base64_encode(data, len);
113         assert(buf != NULL);
114
115         ret = mm_addchars(buf, "\r\n", MM_BASE64_LINELEN);
116         xfree(buf);
117         assert(ret != NULL);
118         return ret;
119 }
120
121 /*
122  * Decode in-place the base64 data in 'input'.  Returns the length
123  * of the decoded data, or -1 if there was an error.
124  */
125 static int
126 _mm_base64_decode(char *input)
127 {
128         uint32_t len = 0;
129         unsigned char *output = (unsigned char *)input;
130         int c1, c2, c3, c4;
131
132         while (*input) {
133                 c1 = *input++;
134                 if (CHAR64(c1) == XX) return -1;
135                 c2 = *input++;
136                 if (CHAR64(c2) == XX) return -1;
137                 c3 = *input++;
138                 if (c3 != '=' && CHAR64(c3) == XX) return -1; 
139                 c4 = *input++;
140                 if (c4 != '=' && CHAR64(c4) == XX) return -1;
141                 *output++ = (CHAR64(c1) << 2) | (CHAR64(c2) >> 4);
142                 ++len;
143                 if (c3 == '=') break;
144                 *output++ = ((CHAR64(c2) << 4) & 0xf0) | (CHAR64(c3) >> 2);
145                 ++len;
146                 if (c4 == '=') break;
147                 *output++ = ((CHAR64(c3) << 6) & 0xc0) | CHAR64(c4);
148                 ++len;
149         }
150         *output = 0;
151
152         return len;
153 }
154
155 /*
156  * Encode the given binary string of length 'len' and return Base64
157  * in a char buffer.  It allocates the space for buffer.
158  * caller must free the space.
159  */
160 static char *
161 _mm_base64_encode(char *data, uint32_t len)
162 {
163         char *buf;
164         uint32_t buflen;
165         int c1;
166         int c2;
167         int c3;
168         uint32_t maxbuf;
169
170         buflen = 0;
171
172 #ifdef RUBBISH
173         maxbuf = len*4/3 + 1;  /* size after expantion */
174 #endif
175         maxbuf = len*2 + 20;  /* size after expantion */
176
177         buf = (char *)xmalloc(maxbuf);
178
179         while (len && buflen < (maxbuf - 6)) {
180
181                 c1 = (unsigned char)*data++;
182                 buf[buflen++] = basis_64[c1>>2];
183
184                 if (--len == 0) c2 = 0;
185                 else c2 = (unsigned char)*data++;
186                 buf[buflen++] = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
187
188                 if (len == 0) {
189                         buf[buflen++] = '=';
190                         buf[buflen++] = '=';
191                         break;
192                 }
193
194                 if (--len == 0) c3 = 0;
195                 else c3 = (unsigned char)*data++;
196
197                 buf[buflen++] = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
198                 if (len == 0) {
199                         buf[buflen++] = '=';
200
201                         break;
202                 }
203
204                 --len;
205                 buf[buflen++] = basis_64[c3 & 0x3F];
206         }
207
208         buf[buflen]=0;
209         return buf;
210 }