Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libcodex/code-qp.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 2003-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* David Korn <[email protected]> *
19
* Phong Vo <[email protected]> *
20
* *
21
***********************************************************************/
22
#pragma prototyped
23
24
/*
25
* quoted printable coder
26
*/
27
28
#include <codex.h>
29
#include <ctype.h>
30
#include <ccode.h>
31
32
#define LINE 76
33
#define BUFFER SF_BUFSIZE
34
35
typedef struct State_s
36
{
37
Codex_t* codex;
38
39
unsigned char* bp;
40
unsigned char* be;
41
42
unsigned char* pp;
43
unsigned char prv[5];
44
45
short xxx;
46
short xeh[UCHAR_MAX+1];
47
48
int col;
49
50
unsigned char buf[LINE + BUFFER + 1];
51
} State_t;
52
53
static const char hex[] = "0123456789ABCDEFabcdef";
54
55
#define GETCHAR(p) ((p)->bp < (p)->be ? (int)*(p)->bp++ : fill(p))
56
#define PUTCHAR(p,c) ((p)->bp < (p)->be ? (int)(*(p)->bp++=(c)) : flush(p,c))
57
58
static int
59
fill(State_t* state)
60
{
61
ssize_t r;
62
63
state->bp = state->buf + LINE;
64
if ((r = sfrd(state->codex->sp, state->bp, BUFFER, &state->codex->sfdisc)) <= 0)
65
{
66
state->be = state->bp;
67
return EOF;
68
}
69
state->be = state->bp + r;
70
return *state->bp++;
71
}
72
73
static int
74
flush(register State_t* state, int c)
75
{
76
size_t n;
77
78
if (c < 0 && state->col)
79
{
80
state->col = 0;
81
PUTCHAR(state, '=');
82
PUTCHAR(state, '\n');
83
}
84
if (state->bp && (n = state->bp - state->buf) && sfwr(state->codex->sp, state->buf, n, &state->codex->sfdisc) != n)
85
return EOF;
86
state->be = (state->bp = state->buf) + sizeof(state->buf);
87
if (c >= 0)
88
*state->bp++ = c;
89
return 0;
90
}
91
92
static int
93
qp_open(Codex_t* p, char* const args[], Codexnum_t flags)
94
{
95
register State_t* state;
96
register int i;
97
98
if (!(state = newof(0, State_t, 1, 0)))
99
{
100
if (p->disc->errorf)
101
(*p->disc->errorf)(NiL, p->disc, 2, "out of space");
102
return -1;
103
}
104
if (flags & CODEX_DECODE)
105
{
106
for (i = -1; i < elementsof(state->xeh); i++)
107
state->xeh[i] = -1;
108
for (i = 0; i < elementsof(hex) - 1; i++)
109
state->xeh[hex[i]] = i >= 16 ? (i - 6) : i;
110
}
111
p->data = state;
112
state->codex = p;
113
return 0;
114
}
115
116
static ssize_t
117
qp_read(Sfio_t* sp, void* buf, size_t n, Sfdisc_t* disc)
118
{
119
register State_t* state = (State_t*)CODEX(disc)->data;
120
register char* s = (char*)buf;
121
register char* e = s + n;
122
register char* x;
123
register int c;
124
register int d;
125
126
x = 0;
127
while (s < e)
128
{
129
switch (c = GETCHAR(state))
130
{
131
case '=':
132
if ((c = GETCHAR(state)) == '\n')
133
continue;
134
if ((d = state->xeh[c]) != EOF && (c = state->xeh[GETCHAR(state)]) != EOF)
135
{
136
c |= (d << 4);
137
x = 0;
138
break;
139
}
140
/*FALLTHROUGH*/
141
case EOF:
142
return s - (char*)buf;
143
case '\n':
144
if (x)
145
{
146
s = x;
147
x = 0;
148
}
149
break;
150
case ' ':
151
case '\t':
152
case '\r':
153
if (!x)
154
x = s;
155
break;
156
default:
157
x = 0;
158
break;
159
}
160
*s++ = c;
161
}
162
if (x)
163
while (s > x && state->bp > state->buf)
164
*--state->bp = *--s;
165
return s - (char*)buf;
166
}
167
168
static ssize_t
169
qp_write(Sfio_t* sp, const void* buf, size_t n, Sfdisc_t* disc)
170
{
171
register State_t* state = (State_t*)CODEX(disc)->data;
172
register unsigned char* s;
173
register unsigned char* e;
174
register int c;
175
register int col;
176
177
again:
178
if (state->pp)
179
{
180
s = state->prv;
181
e = state->pp;
182
state->col = 0;
183
}
184
else
185
{
186
s = (unsigned char*)buf;
187
e = s + n;
188
col = state->col;
189
}
190
for (;;)
191
{
192
if (s >= e)
193
{
194
if (state->pp)
195
{
196
state->pp = 0;
197
state->col = col;
198
goto again;
199
}
200
break;
201
}
202
c = *s++;
203
if (!col++)
204
{
205
if (c == 'F')
206
{
207
if ((e - s) < 4)
208
{
209
s--;
210
col--;
211
state->pp = state->prv;
212
for (c = 0; c < (e - s); ++c)
213
*state->pp++ = s[c];
214
break;
215
}
216
else if (s[0] == 'r' && s[1] == 'o' && s[2] == 'm' && s[3] == ' ')
217
goto quote;
218
}
219
else if (c == '.')
220
{
221
if ((e - s) < 1)
222
{
223
s--;
224
col--;
225
state->pp = state->prv;
226
*state->pp++ = c;
227
break;
228
}
229
else if (s[0] == '\r' || s[0] == '\n')
230
goto quote;
231
}
232
}
233
if (c == '\n')
234
{
235
col = 0;
236
PUTCHAR(state, c);
237
continue;
238
}
239
else if (col >= (LINE - 4))
240
{
241
col = 0;
242
PUTCHAR(state, '=');
243
PUTCHAR(state, '\n');
244
}
245
if (c == ' ' || c == '\t')
246
{
247
if ((e - s) < 1)
248
{
249
s--;
250
col--;
251
state->pp = state->prv;
252
*state->pp++ = c;
253
break;
254
}
255
else if (s[0] == '\r' || s[0] == '\n')
256
goto quote;
257
else
258
{
259
if (c == '\t')
260
col |= 7;
261
PUTCHAR(state, c);
262
continue;
263
}
264
}
265
#if CC_NATIVE == CC_ASCII
266
else if (c >= 0x21 && c <= 0x7e && c != '=')
267
#else
268
else if (isprint(c) && !iscntrl(c) && c != '=')
269
#endif
270
{
271
PUTCHAR(state, c);
272
continue;
273
}
274
quote:
275
col += 2;
276
PUTCHAR(state, '=');
277
PUTCHAR(state, hex[(c >> 4) & 0xF]);
278
PUTCHAR(state, hex[c & 0xF]);
279
}
280
state->col = col;
281
return n;
282
}
283
284
static int
285
qp_sync(Codex_t* p)
286
{
287
return flush((State_t*)p->data, -1);
288
}
289
290
Codexmeth_t codex_qp =
291
{
292
"qp",
293
"quoted printable encoding.",
294
"[+(version)?codex-qp (AT&T Research) 1998-11-11]"
295
"[+(author)?Glenn Fowler <[email protected]>]",
296
CODEX_DECODE|CODEX_ENCODE|CODEX_UU,
297
0,
298
0,
299
qp_open,
300
0,
301
0,
302
0,
303
qp_read,
304
qp_write,
305
qp_sync,
306
0,
307
0,
308
0,
309
0,
310
CODEXNEXT(qp)
311
};
312
313
CODEXLIB(qp)
314
315