Make it build on W32 again.
[gnupg.git] / dirmngr / 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27
28 #include "i18n.h"
29 #include "util.h"
30
31 #define B64ENC_DID_HEADER   1
32 #define B64ENC_DID_TRAILER  2
33 #define B64ENC_NO_LINEFEEDS 16
34
35
36 /* The base-64 character list */
37 static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
38                                     "abcdefghijklmnopqrstuvwxyz" 
39                                     "0123456789+/"; 
40
41 /* Prepare for base-64 writing to the stream FP.  If TITLE is not NULL
42    and not an empty string, this string will be used as the title for
43    the armor lines, with TITLE being an empty string, we don't write
44    the header lines and furthermore even don't write any linefeeds.
45    With TITLE beeing NULL, we merely don't write header but make sure
46    that lines are not too long. Note, that we don't write any output
47    unless at least one byte get written using b64enc_write. */
48 gpg_error_t
49 b64enc_start (struct b64state *state, FILE *fp, const char *title)
50 {
51   memset (state, 0, sizeof *state);
52   state->fp = fp;
53   if (title && !*title)
54     state->flags |= B64ENC_NO_LINEFEEDS;
55   else if (title)
56     {
57       state->title = strdup (title);
58       if (!state->title)
59         return  gpg_error_from_errno (errno);
60     }
61   return 0;
62 }
63
64
65 /* Write NBYTES from BUFFER to the Base 64 stream identified by
66    STATE. With BUFFER and NBYTES being 0, merely do a fflush on the
67    stream. */
68 gpg_error_t
69 b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
70 {
71   unsigned char radbuf[4];
72   int idx, quad_count;
73   const unsigned char *p;
74   FILE *fp = state->fp;
75
76
77   if (!nbytes)
78     {
79       if (buffer && fflush (fp))
80         goto write_error;
81       return 0;
82     }
83
84   if (!(state->flags & B64ENC_DID_HEADER))
85     {
86       if (state->title)
87         {
88           if ( fputs ("-----BEGIN ", fp) == EOF
89                || fputs (state->title, fp) == EOF
90                || fputs ("-----\n", fp) == EOF)
91             goto write_error;
92         }
93       state->flags |= B64ENC_DID_HEADER;
94     }
95
96   idx = state->idx;
97   quad_count = state->quad_count;
98   assert (idx < 4);
99   memcpy (radbuf, state->radbuf, idx);
100   
101   for (p=buffer; nbytes; p++, nbytes--)
102     {
103       radbuf[idx++] = *p;
104       if (idx > 2)
105         {
106           char tmp[4];
107
108           tmp[0] = bintoasc[(*radbuf >> 2) & 077];
109           tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
110           tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
111           tmp[3] = bintoasc[radbuf[2]&077];
112           for (idx=0; idx < 4; idx++)
113             putc (tmp[idx], fp);
114           idx = 0;
115           if (ferror (fp))
116             goto write_error;
117           if (++quad_count >= (64/4)) 
118             {
119               quad_count = 0;
120               if (!(state->flags & B64ENC_NO_LINEFEEDS)
121                   && fputs ("\n", fp) == EOF)
122                 goto write_error;
123             }
124         }
125     }
126   memcpy (state->radbuf, radbuf, idx);
127   state->idx = idx;
128   state->quad_count = quad_count;
129   return 0;
130
131  write_error:
132   return gpg_error_from_errno (errno);
133 }
134
135 gpg_error_t
136 b64enc_finish (struct b64state *state)
137 {
138   gpg_error_t err = 0;
139   unsigned char radbuf[4];
140   int idx, quad_count;
141   FILE *fp;
142
143   if (!(state->flags & B64ENC_DID_HEADER))
144     goto cleanup;
145
146   /* Flush the base64 encoding */
147   fp = state->fp;
148   idx = state->idx;
149   quad_count = state->quad_count;
150   assert (idx < 4);
151   memcpy (radbuf, state->radbuf, idx);
152
153   if (idx)
154     {
155       char tmp[4];
156       
157       tmp[0] = bintoasc[(*radbuf>>2)&077];
158       if (idx == 1)
159         {
160           tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077];
161           tmp[2] = '=';
162           tmp[3] = '=';
163         }
164       else 
165         { 
166           tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
167           tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
168           tmp[3] = '=';
169         }
170       for (idx=0; idx < 4; idx++)
171         putc (tmp[idx], fp);
172       idx = 0;
173       if (ferror (fp))
174         goto write_error;
175       
176       if (++quad_count >= (64/4)) 
177         {
178           quad_count = 0;
179           if (!(state->flags & B64ENC_NO_LINEFEEDS)
180               && fputs ("\n", fp) == EOF)
181             goto write_error;
182         }
183     }
184
185   /* Finish the last line and write the trailer. */
186   if (quad_count
187       && !(state->flags & B64ENC_NO_LINEFEEDS)
188       && fputs ("\n", fp) == EOF)
189     goto write_error;
190
191   if (state->title)
192     {
193       if ( fputs ("-----END ", fp) == EOF
194            || fputs (state->title, fp) == EOF
195            || fputs ("-----\n", fp) == EOF)
196         goto write_error;
197     }
198
199   goto cleanup;
200
201  write_error:
202   err = gpg_error_from_errno (errno);
203
204  cleanup:
205   if (state->title)
206     {
207       free (state->title);
208       state->title = NULL;
209     }
210   state->fp = NULL;
211   return err;
212 }
213