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