bfc49deb665aca31e1110e9b2d75274240b4cf44
[gnupg.git] / common / b64enc.c
1 /* b64enc.c - Simple Base64 encoder.
2  *      Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <assert.h>
28
29 #include "i18n.h"
30 #include "util.h"
31
32 #define B64ENC_DID_HEADER   1
33 #define B64ENC_DID_TRAILER  2
34 #define B64ENC_NO_LINEFEEDS 16
35
36
37 /* The base-64 character list */
38 static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
39                                     "abcdefghijklmnopqrstuvwxyz" 
40                                     "0123456789+/"; 
41
42 /* Prepare for base-64 writing to the stream FP.  If TITLE is not NULL
43    and not an empty string, this string will be used as the title for
44    the armor lines, with TITLE being an empty string, we don't write
45    the header lines and furthermore even don't write any linefeeds.
46    With TITLE beeing NULL, we merely don't write header but make sure
47    that lines are not too long. Note, that we don't write any output
48    unless at least one byte get written using b64enc_write. */
49 gpg_error_t
50 b64enc_start (struct b64state *state, FILE *fp, const char *title)
51 {
52   memset (state, 0, sizeof *state);
53   state->fp = fp;
54   if (title && !*title)
55     state->flags |= B64ENC_NO_LINEFEEDS;
56   else if (title)
57     {
58       state->title = xtrystrdup (title);
59       if (!state->title)
60         return  gpg_error_from_errno (errno);
61     }
62   return 0;
63 }
64
65
66 /* Write NBYTES from BUFFER to the Base 64 stream identified by
67    STATE. With BUFFER and NBYTES being 0, merely do a fflush on the
68    stream. */
69 gpg_error_t
70 b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
71 {
72   unsigned char radbuf[4];
73   int idx, quad_count;
74   const unsigned char *p;
75   FILE *fp = state->fp;
76
77
78   if (!nbytes)
79     {
80       if (buffer && fflush (fp))
81         goto write_error;
82       return 0;
83     }
84
85   if (!(state->flags & B64ENC_DID_HEADER))
86     {
87       if (state->title)
88         {
89           if ( fputs ("-----BEGIN ", fp) == EOF
90                || fputs (state->title, fp) == EOF
91                || fputs ("-----\n", fp) == EOF)
92             goto write_error;
93         }
94       state->flags |= B64ENC_DID_HEADER;
95     }
96
97   idx = state->idx;
98   quad_count = state->quad_count;
99   assert (idx < 4);
100   memcpy (radbuf, state->radbuf, idx);
101   
102   for (p=buffer; nbytes; p++, nbytes--)
103     {
104       radbuf[idx++] = *p;
105       if (idx > 2)
106         {
107           char tmp[4];
108
109           tmp[0] = bintoasc[(*radbuf >> 2) & 077];
110           tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
111           tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
112           tmp[3] = bintoasc[radbuf[2]&077];
113           for (idx=0; idx < 4; idx++)
114             putc (tmp[idx], fp);
115           idx = 0;
116           if (ferror (fp))
117             goto write_error;
118           if (++quad_count >= (64/4)) 
119             {
120               quad_count = 0;
121               if (!(state->flags & B64ENC_NO_LINEFEEDS)
122                   && fputs ("\n", fp) == EOF)
123                 goto write_error;
124             }
125         }
126     }
127   memcpy (state->radbuf, radbuf, idx);
128   state->idx = idx;
129   state->quad_count = quad_count;
130   return 0;
131
132  write_error:
133   return gpg_error_from_errno (errno);
134 }
135
136 gpg_error_t
137 b64enc_finish (struct b64state *state)
138 {
139   gpg_error_t err = 0;
140   unsigned char radbuf[4];
141   int idx, quad_count;
142   FILE *fp;
143
144   if (!(state->flags & B64ENC_DID_HEADER))
145     goto cleanup;
146
147   /* Flush the base64 encoding */
148   fp = state->fp;
149   idx = state->idx;
150   quad_count = state->quad_count;
151   assert (idx < 4);
152   memcpy (radbuf, state->radbuf, idx);
153
154   if (idx)
155     {
156       char tmp[4];
157       
158       tmp[0] = bintoasc[(*radbuf>>2)&077];
159       if (idx == 1)
160         {
161           tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077];
162           tmp[2] = '=';
163           tmp[3] = '=';
164         }
165       else 
166         { 
167           tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
168           tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
169           tmp[3] = '=';
170         }
171       for (idx=0; idx < 4; idx++)
172         putc (tmp[idx], fp);
173       idx = 0;
174       if (ferror (fp))
175         goto write_error;
176       
177       if (++quad_count >= (64/4)) 
178         {
179           quad_count = 0;
180           if (!(state->flags & B64ENC_NO_LINEFEEDS)
181               && fputs ("\n", fp) == EOF)
182             goto write_error;
183         }
184     }
185
186   /* Finish the last line and write the trailer. */
187   if (quad_count
188       && !(state->flags & B64ENC_NO_LINEFEEDS)
189       && fputs ("\n", fp) == EOF)
190     goto write_error;
191
192   if (state->title)
193     {
194       if ( fputs ("-----END ", fp) == EOF
195            || fputs (state->title, fp) == EOF
196            || fputs ("-----\n", fp) == EOF)
197         goto write_error;
198     }
199
200   goto cleanup;
201
202  write_error:
203   err = gpg_error_from_errno (errno);
204
205  cleanup:
206   if (state->title)
207     {
208       xfree (state->title);
209       state->title = NULL;
210     }
211   state->fp = NULL;
212   return err;
213 }
214