~svn/ubuntu/raring/subversion/ppa

« back to all changes in this revision

Viewing changes to subversion/libsvn_subr/quoprint.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-12-05 01:26:14 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051205012614-qom4xfypgtsqc2xq
Tags: 1.2.3dfsg1-3ubuntu1
Merge with the final Debian release of 1.2.3dfsg1-3, bringing in
fixes to the clean target, better documentation of the libdb4.3
upgrade and build fixes to work with swig1.3_1.3.27.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * quoprint.c:  quoted-printable encoding and decoding functions
 
3
 *
 
4
 * ====================================================================
 
5
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 
6
 *
 
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.
 
12
 *
 
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
 * ====================================================================
 
17
 */
 
18
 
 
19
 
 
20
 
 
21
#include <string.h>
 
22
 
 
23
#include <apr.h>
 
24
#include <apr_pools.h>
 
25
#include <apr_general.h>        /* for APR_INLINE */
 
26
 
 
27
#include "svn_pools.h"
 
28
#include "svn_io.h"
 
29
#include "svn_error.h"
 
30
#include "svn_quoprint.h"
 
31
 
 
32
 
 
33
/* Caveats:
 
34
 
 
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.
 
39
 
 
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.
 
43
 
 
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).
 
49
 
 
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.  */
 
53
 
 
54
#define QUOPRINT_LINELEN 76
 
55
#define VALID_LITERAL(c) ((c) == '\t' || ((c) >= ' ' && (c) <= '~' \
 
56
                                          && (c) != '='))
 
57
#define ENCODE_AS_LITERAL(c) (VALID_LITERAL(c) && (c) != '\t' && (c) != '<' \
 
58
                              && (c) != '>' && (c) != '\'' && (c) != '"' \
 
59
                              && (c) != '&')
 
60
static const char hextab[] = "0123456789ABCDEF";
 
61
 
 
62
 
 
63
 
 
64
/* Binary input --> quoted-printable-encoded output */
 
65
 
 
66
struct encode_baton {
 
67
  svn_stream_t *output;
 
68
  int linelen;                  /* Bytes output so far on this line */
 
69
  apr_pool_t *pool;
 
70
};
 
71
 
 
72
 
 
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
 
76
   appended to STR.  */
 
77
static void
 
78
encode_bytes (svn_stringbuf_t *str, const char *data, apr_size_t len,
 
79
              int *linelen)
 
80
{
 
81
  char buf[3];
 
82
  const char *p;
 
83
 
 
84
  /* Keep encoding three-byte groups until we run out.  */
 
85
  for (p = data; p < data + len; p++)
 
86
    {
 
87
      /* Encode this character.  */
 
88
      if (ENCODE_AS_LITERAL(*p))
 
89
        {
 
90
          svn_stringbuf_appendbytes (str, p, 1);
 
91
          (*linelen)++;
 
92
        }
 
93
      else
 
94
        {
 
95
          buf[0] = '=';
 
96
          buf[1] = hextab[(*p >> 4) & 0xf];
 
97
          buf[2] = hextab[*p & 0xf];
 
98
          svn_stringbuf_appendbytes (str, buf, 3);
 
99
          *linelen += 3;
 
100
        }
 
101
 
 
102
      /* Make sure our output lines don't exceed QUOPRINT_LINELEN.  */
 
103
      if (*linelen + 3 > QUOPRINT_LINELEN)
 
104
        {
 
105
          svn_stringbuf_appendcstr (str, "=\n");
 
106
          *linelen = 0;
 
107
        }
 
108
    }
 
109
}
 
110
 
 
111
 
 
112
/* Write handler for svn_quoprint_encode.  */
 
113
static svn_error_t *
 
114
encode_data (void *baton, const char *data, apr_size_t *len)
 
115
{
 
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);
 
119
  apr_size_t enclen;
 
120
  svn_error_t *err = SVN_NO_ERROR;
 
121
 
 
122
  /* Encode this block of data and write it out.  */
 
123
  encode_bytes (encoded, data, *len, &eb->linelen);
 
124
  enclen = encoded->len;
 
125
  if (enclen != 0)
 
126
    err = svn_stream_write (eb->output, encoded->data, &enclen);
 
127
  svn_pool_destroy (subpool);
 
128
  return err;
 
129
}
 
130
 
 
131
 
 
132
/* Close handler for svn_quoprint_encode().  */
 
133
static svn_error_t *
 
134
finish_encoding_data (void *baton)
 
135
{
 
136
  struct encode_baton *eb = baton;
 
137
  svn_error_t *err = SVN_NO_ERROR;
 
138
  apr_size_t len;
 
139
 
 
140
  /* Terminate the current output line if it's not empty.  */
 
141
  if (eb->linelen > 0)
 
142
    {
 
143
      len = 2;
 
144
      err = svn_stream_write (eb->output, "=\n", &len);
 
145
    }
 
146
 
 
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);
 
151
  return err;
 
152
}
 
153
 
 
154
 
 
155
svn_stream_t *
 
156
svn_quoprint_encode (svn_stream_t *output, apr_pool_t *pool)
 
157
{
 
158
  apr_pool_t *subpool = svn_pool_create (pool);
 
159
  struct encode_baton *eb = apr_palloc (subpool, sizeof (*eb));
 
160
  svn_stream_t *stream;
 
161
 
 
162
  eb->output = output;
 
163
  eb->linelen = 0;
 
164
  eb->pool = subpool;
 
165
  stream = svn_stream_create (eb, pool);
 
166
  svn_stream_set_write (stream, encode_data);
 
167
  svn_stream_set_close (stream, finish_encoding_data);
 
168
  return stream;
 
169
}
 
170
 
 
171
 
 
172
svn_stringbuf_t *
 
173
svn_quoprint_encode_string (svn_stringbuf_t *str, apr_pool_t *pool)
 
174
{
 
175
  svn_stringbuf_t *encoded = svn_stringbuf_create ("", pool);
 
176
  int linelen = 0;
 
177
 
 
178
  encode_bytes (encoded, str->data, str->len, &linelen);
 
179
  if (linelen > 0)
 
180
    svn_stringbuf_appendcstr (encoded, "=\n");
 
181
  return encoded;
 
182
}
 
183
 
 
184
 
 
185
 
 
186
/* Quoted-printable-encoded input --> binary output */
 
187
 
 
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 */
 
192
  apr_pool_t *pool;
 
193
};
 
194
 
 
195
 
 
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
 
200
   appended to STR.  */
 
201
static void
 
202
decode_bytes (svn_stringbuf_t *str, const char *data, apr_size_t len,
 
203
              char *inbuf, int *inbuflen)
 
204
{
 
205
  const char *p, *find1, *find2;
 
206
  char c;
 
207
 
 
208
  for (p = data; p <= data + len; p++)
 
209
    {
 
210
      /* Append this byte to the buffer and see what we have.  */
 
211
      inbuf[(*inbuflen)++] = *p;
 
212
      if (*inbuf != '=')
 
213
        {
 
214
          /* Literal character; append it if it's valid as such.  */
 
215
          if (VALID_LITERAL(*inbuf))
 
216
            svn_stringbuf_appendbytes (str, inbuf, 1);
 
217
          *inbuflen = 0;
 
218
        }
 
219
      else if (*inbuf == '=' && *inbuflen == 2 && inbuf[1] == '\n')
 
220
        {
 
221
          /* Soft newline; ignore.  */
 
222
          *inbuflen = 0;
 
223
        }
 
224
      else if (*inbuf == '=' && *inbuflen == 3)
 
225
        {
 
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)
 
230
            {
 
231
              c = ((find1 - hextab) << 4) | (find2 - hextab);
 
232
              svn_stringbuf_appendbytes (str, &c, 1);
 
233
            }
 
234
          *inbuflen = 0;
 
235
        }
 
236
    }
 
237
}
 
238
 
 
239
 
 
240
/* Write handler for svn_quoprint_decode.  */
 
241
static svn_error_t *
 
242
decode_data (void *baton, const char *data, apr_size_t *len)
 
243
{
 
244
  struct decode_baton *db = baton;
 
245
  apr_pool_t *subpool;
 
246
  svn_stringbuf_t *decoded;
 
247
  apr_size_t declen;
 
248
  svn_error_t *err = SVN_NO_ERROR;
 
249
 
 
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);
 
254
 
 
255
  /* Write the output, clean up, go home.  */
 
256
  declen = decoded->len;
 
257
  if (declen != 0)
 
258
    err = svn_stream_write (db->output, decoded->data, &declen);
 
259
  svn_pool_destroy (subpool);
 
260
  return err;
 
261
}
 
262
 
 
263
 
 
264
/* Close handler for svn_quoprint_decode().  */
 
265
static svn_error_t *
 
266
finish_decoding_data (void *baton)
 
267
{
 
268
  struct decode_baton *db = baton;
 
269
  svn_error_t *err;
 
270
 
 
271
  /* Pass on the close request and clean up the baton.  */
 
272
  err = svn_stream_close (db->output);
 
273
  svn_pool_destroy (db->pool);
 
274
  return err;
 
275
}
 
276
 
 
277
 
 
278
svn_stream_t *
 
279
svn_quoprint_decode (svn_stream_t *output, apr_pool_t *pool)
 
280
{
 
281
  apr_pool_t *subpool = svn_pool_create (pool);
 
282
  struct decode_baton *db = apr_palloc (subpool, sizeof (*db));
 
283
  svn_stream_t *stream;
 
284
 
 
285
  db->output = output;
 
286
  db->buflen = 0;
 
287
  db->pool = subpool;
 
288
  stream = svn_stream_create (db, pool);
 
289
  svn_stream_set_write (stream, decode_data);
 
290
  svn_stream_set_close (stream, finish_decoding_data);
 
291
  return stream;
 
292
}
 
293
 
 
294
 
 
295
svn_stringbuf_t *
 
296
svn_quoprint_decode_string (svn_stringbuf_t *str, apr_pool_t *pool)
 
297
{
 
298
  svn_stringbuf_t *decoded = svn_stringbuf_create ("", pool);
 
299
  char ingroup[4];
 
300
  int ingrouplen = 0;
 
301
 
 
302
  decode_bytes (decoded, str->data, str->len, ingroup, &ingrouplen);
 
303
  return decoded;
 
304
}