2
* quoprint.c: quoted-printable encoding and decoding functions
4
* ====================================================================
5
* Copyright (c) 2000-2004 CollabNet. All rights reserved.
7
* This software is licensed as described in the file COPYING, which
8
* you should have received as part of this distribution. The terms
9
* are also available at http://subversion.tigris.org/license-1.html.
10
* If newer versions of this license are posted there, you may use a
11
* newer version instead, at your option.
13
* This software consists of voluntary contributions made by many
14
* individuals. For exact contribution history, see the revision
15
* history and logs, available at http://subversion.tigris.org/.
16
* ====================================================================
24
#include <apr_pools.h>
25
#include <apr_general.h> /* for APR_INLINE */
27
#include "svn_pools.h"
29
#include "svn_error.h"
30
#include "svn_quoprint.h"
35
(1) This code is for the encoding and decoding of binary data
36
only. Thus, CRLF sequences are encoded as =0D=0A, and we
37
don't have to worry about tabs and spaces coming before
38
hard newlines, since there aren't any.
40
(2) The decoder does no error reporting, and instead throws
41
away invalid sequences. It also discards CRLF sequences,
42
since those can only appear in the encoding of text data.
44
(3) The decoder does not strip whitespace at the end of a
45
line, so it is not actually compliant with RFC 2045.
46
(Such whitespace should never occur, even in the encoding
47
of text data, but RFC 2045 requires a decoder to detect
48
that a transport agent has added trailing whitespace).
50
(4) The encoder is tailored to make output embeddable in XML,
51
which means it quotes <>'"& as well as the characters
52
required by RFC 2045. */
54
#define QUOPRINT_LINELEN 76
55
#define VALID_LITERAL(c) ((c) == '\t' || ((c) >= ' ' && (c) <= '~' \
57
#define ENCODE_AS_LITERAL(c) (VALID_LITERAL(c) && (c) != '\t' && (c) != '<' \
58
&& (c) != '>' && (c) != '\'' && (c) != '"' \
60
static const char hextab[] = "0123456789ABCDEF";
64
/* Binary input --> quoted-printable-encoded output */
68
int linelen; /* Bytes output so far on this line */
73
/* Quoted-printable-encode a byte string which may or may not be the
74
totality of the data being encoded. *LINELEN carries the length of
75
the current output line; initialize it to 0. Output will be
78
encode_bytes (svn_stringbuf_t *str, const char *data, apr_size_t len,
84
/* Keep encoding three-byte groups until we run out. */
85
for (p = data; p < data + len; p++)
87
/* Encode this character. */
88
if (ENCODE_AS_LITERAL(*p))
90
svn_stringbuf_appendbytes (str, p, 1);
96
buf[1] = hextab[(*p >> 4) & 0xf];
97
buf[2] = hextab[*p & 0xf];
98
svn_stringbuf_appendbytes (str, buf, 3);
102
/* Make sure our output lines don't exceed QUOPRINT_LINELEN. */
103
if (*linelen + 3 > QUOPRINT_LINELEN)
105
svn_stringbuf_appendcstr (str, "=\n");
112
/* Write handler for svn_quoprint_encode. */
114
encode_data (void *baton, const char *data, apr_size_t *len)
116
struct encode_baton *eb = baton;
117
apr_pool_t *subpool = svn_pool_create (eb->pool);
118
svn_stringbuf_t *encoded = svn_stringbuf_create ("", subpool);
120
svn_error_t *err = SVN_NO_ERROR;
122
/* Encode this block of data and write it out. */
123
encode_bytes (encoded, data, *len, &eb->linelen);
124
enclen = encoded->len;
126
err = svn_stream_write (eb->output, encoded->data, &enclen);
127
svn_pool_destroy (subpool);
132
/* Close handler for svn_quoprint_encode(). */
134
finish_encoding_data (void *baton)
136
struct encode_baton *eb = baton;
137
svn_error_t *err = SVN_NO_ERROR;
140
/* Terminate the current output line if it's not empty. */
144
err = svn_stream_write (eb->output, "=\n", &len);
147
/* Pass on the close request and clean up the baton. */
148
if (err == SVN_NO_ERROR)
149
err = svn_stream_close (eb->output);
150
svn_pool_destroy (eb->pool);
156
svn_quoprint_encode (svn_stream_t *output, apr_pool_t *pool)
158
apr_pool_t *subpool = svn_pool_create (pool);
159
struct encode_baton *eb = apr_palloc (subpool, sizeof (*eb));
160
svn_stream_t *stream;
165
stream = svn_stream_create (eb, pool);
166
svn_stream_set_write (stream, encode_data);
167
svn_stream_set_close (stream, finish_encoding_data);
173
svn_quoprint_encode_string (svn_stringbuf_t *str, apr_pool_t *pool)
175
svn_stringbuf_t *encoded = svn_stringbuf_create ("", pool);
178
encode_bytes (encoded, str->data, str->len, &linelen);
180
svn_stringbuf_appendcstr (encoded, "=\n");
186
/* Quoted-printable-encoded input --> binary output */
188
struct decode_baton {
189
svn_stream_t *output;
190
char buf[3]; /* Bytes waiting to be decoded */
191
int buflen; /* Number of bytes waiting */
196
/* Decode a byte string which may or may not be the total amount of
197
data being decoded. INBUF and *INBUFLEN carry the leftover bytes
198
from call to call. Have room for four bytes in INBUF and
199
initialize *INBUFLEN to 0 and *DONE to FALSE. Output will be
202
decode_bytes (svn_stringbuf_t *str, const char *data, apr_size_t len,
203
char *inbuf, int *inbuflen)
205
const char *p, *find1, *find2;
208
for (p = data; p <= data + len; p++)
210
/* Append this byte to the buffer and see what we have. */
211
inbuf[(*inbuflen)++] = *p;
214
/* Literal character; append it if it's valid as such. */
215
if (VALID_LITERAL(*inbuf))
216
svn_stringbuf_appendbytes (str, inbuf, 1);
219
else if (*inbuf == '=' && *inbuflen == 2 && inbuf[1] == '\n')
221
/* Soft newline; ignore. */
224
else if (*inbuf == '=' && *inbuflen == 3)
226
/* Encoded character; decode it and append. */
227
find1 = strchr(hextab, inbuf[1]);
228
find2 = strchr(hextab, inbuf[2]);
229
if (find1 != NULL && find2 != NULL)
231
c = ((find1 - hextab) << 4) | (find2 - hextab);
232
svn_stringbuf_appendbytes (str, &c, 1);
240
/* Write handler for svn_quoprint_decode. */
242
decode_data (void *baton, const char *data, apr_size_t *len)
244
struct decode_baton *db = baton;
246
svn_stringbuf_t *decoded;
248
svn_error_t *err = SVN_NO_ERROR;
250
/* Decode this block of data. */
251
subpool = svn_pool_create (db->pool);
252
decoded = svn_stringbuf_create ("", subpool);
253
decode_bytes (decoded, data, *len, db->buf, &db->buflen);
255
/* Write the output, clean up, go home. */
256
declen = decoded->len;
258
err = svn_stream_write (db->output, decoded->data, &declen);
259
svn_pool_destroy (subpool);
264
/* Close handler for svn_quoprint_decode(). */
266
finish_decoding_data (void *baton)
268
struct decode_baton *db = baton;
271
/* Pass on the close request and clean up the baton. */
272
err = svn_stream_close (db->output);
273
svn_pool_destroy (db->pool);
279
svn_quoprint_decode (svn_stream_t *output, apr_pool_t *pool)
281
apr_pool_t *subpool = svn_pool_create (pool);
282
struct decode_baton *db = apr_palloc (subpool, sizeof (*db));
283
svn_stream_t *stream;
288
stream = svn_stream_create (db, pool);
289
svn_stream_set_write (stream, decode_data);
290
svn_stream_set_close (stream, finish_decoding_data);
296
svn_quoprint_decode_string (svn_stringbuf_t *str, apr_pool_t *pool)
298
svn_stringbuf_t *decoded = svn_stringbuf_create ("", pool);
302
decode_bytes (decoded, str->data, str->len, ingroup, &ingrouplen);