/[debian]/mimetic/branches/upstream/current/mimetic/codec/qp.h
ViewVC logotype

Annotation of /mimetic/branches/upstream/current/mimetic/codec/qp.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 128 - (hide annotations)
Sat Feb 25 16:49:20 2006 UTC (15 years, 6 months ago) by gregoa
File MIME type: text/plain
File size: 13686 byte(s)
[svn-inject] Installing original source of mimetic
1 gregoa 128 /***************************************************************************
2     copyright : (C) 2002-2005 by Stefano Barbato
3     email : stefano@codesink.org
4    
5     $Id: qp.h,v 1.16 2005/02/23 11:48:15 tat Exp $
6     ***************************************************************************/
7    
8     /***************************************************************************
9     * *
10     * This program is free software; you can redistribute it and/or modify *
11     * it under the terms of the GNU General Public License as published by *
12     * the Free Software Foundation; either version 2 of the License, or *
13     * (at your option) any later version. *
14     * *
15     ***************************************************************************/
16     #ifndef _MIMETIC_CODEC_QP_H_
17     #define _MIMETIC_CODEC_QP_H_
18     #include <iostream>
19     #include <string>
20     #include <sstream>
21     #include <cassert>
22     #include <mimetic/libconfig.h>
23     #include <mimetic/circular_buffer.h>
24     #include <mimetic/codec/codec_base.h>
25     #include <mimetic/codec/codec_chain.h>
26    
27     namespace mimetic
28     {
29    
30     class QP
31     {
32     friend class test_qp;
33     enum { LF = 0xA, CR = 0xD, NL = LF, TAB = 9, SP = 32 };
34     enum { default_maxlen = 76 };
35     enum {
36     printable, /* print as-is */
37     tab, /* print if !isBinary */
38     sp, /* ' ' */
39     newline, /* cr or lf; encode if isBinary*/
40     binary, /* rest of the ascii map */
41     unsafe /* "!\"#$@[]\\^`{}|~" */
42     };
43     static char sTb[256];
44    
45     public:
46    
47     /// quoted-printable encoder
48     /*!
49    
50     \sa encode decode
51     */
52     class Encoder: public buffered_codec, public chainable_codec<Encoder>
53     {
54     enum { laBufSz = 5 }; // look-ahead buffer
55     size_t m_pos, m_maxlen;
56     bool m_binary;
57     circular_buffer<char_type> m_cbuf;
58    
59     template<typename OutIt>
60     void hardLineBrk(OutIt& out)
61     {
62     *out = NL; ++out;
63     m_pos = 1;
64     }
65     template<typename OutIt>
66     void softLineBrk(OutIt& out)
67     {
68     *out = '='; ++out;
69     hardLineBrk(out);
70     }
71     template<typename OutIt>
72     void write(char_type ch, OutIt& out)
73     {
74     bool is_last_ch = m_cbuf.empty();
75     if(!is_last_ch && m_pos == m_maxlen)
76     softLineBrk(out);
77     *out = ch; ++out;
78     m_pos++;
79     }
80     template<typename OutIt>
81     void writeHex(char_type ch, OutIt& out)
82     {
83     static char_type hexc[] =
84     {
85     '0', '1', '2', '3', '4', '5' ,'6', '7', '8', '9',
86     'A', 'B', 'C', 'D', 'E', 'F'
87     };
88     bool is_last_ch = m_cbuf.empty();
89     if(m_pos + (is_last_ch ? 1 : 2) >= m_maxlen)
90     softLineBrk(out);
91     // write out =HH
92     *out = '='; ++out;
93     *out = hexc[ch >> 4]; ++out;
94     *out = hexc[ch & 0xf]; ++out;
95     m_pos += 3;
96     }
97     template<typename OutIt>
98     void encodeChar(char_type c, OutIt& out)
99     {
100     int cnt = m_cbuf.count();
101     switch(sTb[c])
102     {
103     case printable:
104     if(m_pos == 1)
105     {
106     switch(c)
107     {
108     case 'F': // hex enc on "^From .*"
109     if(cnt>=4 && m_cbuf.compare(0,4,"rom "))
110     {
111     writeHex(c,out);
112     return;
113     }
114     break;
115     case '.': // hex encode if "^.[\r\n]" or on eof
116     if(!cnt || sTb[ m_cbuf[0] ] == newline)
117     {
118     writeHex(c,out);
119     return;
120     }
121     break;
122     }
123     }
124     write(c,out);
125     break;
126     case tab:
127     case sp:
128     // on binary encoding, or last input ch or newline
129     if(m_binary || !cnt || sTb[ m_cbuf[0] ] == newline)
130     writeHex(c,out);
131     else
132     write(c,out);
133     break;
134     case newline:
135     if(m_binary)
136     writeHex(c, out);
137     else {
138     if(cnt && m_cbuf[0] == (c == CR ? LF : CR))
139     m_cbuf.pop_front(); // eat it
140     hardLineBrk(out);
141     }
142     break;
143     case binary:
144     if(!m_binary) m_binary = 1; // switch to binary mode
145     writeHex(c, out);
146     break;
147     case unsafe:
148     writeHex(c, out);
149     break;
150     }
151     }
152     public:
153     /*!
154     Constructor
155     \param isBinary if true all space and newline characters will be
156     treated like binary chars and will be hex encoded (useful if you
157     want to encode a binary file).
158     */
159     Encoder(bool isBinary = false)
160     : m_pos(1), m_maxlen(default_maxlen),
161     m_binary(isBinary), m_cbuf(laBufSz)
162     {
163     }
164     /*! Returns the name of the codec ("Quoted-Printable") */
165     const char* name() const { return "Quoted-Printable"; }
166     /*! Returns the max line length */
167     size_t maxlen()
168     {
169     return m_maxlen;
170     }
171     /*!
172     Set the max line length. No more then \p i chars will be
173     printed on one line.
174     */
175     void maxlen(size_t i)
176     {
177     m_maxlen = i;
178     }
179     /*!
180     Encodes [\p bit,\p eit) and write any encoded char to \p out.
181     */
182     template<typename InIt, typename OutIt>
183     void process(InIt bit, InIt eit, OutIt out)
184     {
185     for(; bit != eit; ++bit)
186     process(*bit, out);
187     flush(out);
188     }
189     /*!
190     Encodes \p ic and write any encoded output char to \p out.
191     \warning You must call flush() when all chars have been
192     processed by the encode funcion.
193     \n
194     \code
195     while( (c = getchar()) != EOF )
196     qp.process(c, out);
197     qp.flush();
198     \endcode
199     \n
200     \sa flush()
201     */
202     template<typename OutIt>
203     void process(char_type ic, OutIt& out)
204     {
205     m_cbuf.push_back(ic);
206     if(m_cbuf.count() < laBufSz)
207     return;
208     char_type c = m_cbuf.front();
209     m_cbuf.pop_front();
210     encodeChar(c, out);
211     }
212     /*!
213     Write to \p out any buffered encoded char.
214     */
215     template<typename OutIt>
216     void flush(OutIt& out)
217     {
218     char_type c;
219     while(!m_cbuf.empty())
220     {
221     c = m_cbuf.front();
222     m_cbuf.pop_front();
223     encodeChar(c, out);
224     }
225     }
226     };
227    
228     /// quoted-printable decoder
229     /*!
230    
231     \sa encode decode
232     */
233     class Decoder: public buffered_codec, public chainable_codec<Encoder>
234     {
235     enum { laBufSz = 80 }; // look-ahead buffer
236     enum {
237     sWaitingChar,
238     sAfterEq,
239     sWaitingFirstHex,
240     sWaitingSecondHex,
241     sBlank,
242     sNewline,
243     sOtherChar
244     };
245     size_t m_pos, m_maxlen;
246    
247    
248     int m_state, m_nl;
249     std::string m_prev;
250    
251     template<typename OutIt>
252     void hardLineBrk(OutIt& out) const
253     {
254     *out = NL; ++out;
255     }
256     template<typename OutIt>
257     void write(char_type ch, OutIt& out) const
258     {
259     *out = ch; ++out;
260     }
261     bool isnl(char_type c) const
262     {
263     return (c == CR || c == LF);
264     }
265     template<typename OutIt>
266     void flushPrev(OutIt& out)
267     {
268     copy(m_prev.begin(), m_prev.end(), out);
269     m_prev.clear();
270     }
271     int hex_to_int(char_type c) const
272     {
273     if( c >= '0' && c <='9') return c - '0';
274     else if( c >= 'A' && c <='F') return c - 'A' + 10;
275     else if( c >= 'a' && c <='f') return c - 'a' + 10;
276     else return 0;
277     }
278     bool ishex(char_type c) const
279     {
280     return (c >= '0' && c <= '9') ||
281     (c >= 'A' && c <= 'F') ||
282     (c >= 'a' && c <= 'f');
283     }
284     template<typename OutIt>
285     void decodeChar(char_type c, OutIt& out)
286     {
287     for(;;)
288     {
289     switch(m_state)
290     {
291     case sBlank:
292     if(isblank(c))
293     m_prev.append(1,c);
294     else if(isnl(c)) {
295     // soft linebrk & ignore trailing blanks
296     m_prev.clear();
297     m_state = sWaitingChar;
298     } else {
299     flushPrev(out);
300     m_state = sWaitingChar;
301     continue;
302     }
303     return;
304     case sAfterEq:
305     if(isblank(c))
306     m_prev.append(1,c);
307     else if(isnl(c)) {
308     // soft linebrk
309     m_state = sNewline;
310     continue;
311     } else {
312     if(m_prev.length() > 1)
313     {
314     // there're blanks after =
315     flushPrev(out);
316     m_state = sWaitingChar;
317     } else
318     m_state = sWaitingFirstHex;
319     continue;
320     }
321     return;
322     case sWaitingFirstHex:
323     if(!ishex(c))
324     {
325     // malformed: =[not-hexch]
326     flushPrev(out);
327     write(c, out);
328     m_state = sWaitingChar;
329     return;
330     } else {
331     m_prev.append(1,c);
332     m_state = sWaitingSecondHex;
333     }
334     return;
335     case sWaitingSecondHex:
336     if(!ishex(c))
337     { // malformed (=[hexch][not-hexch])
338     flushPrev(out);
339     write(c, out);
340     } else {
341     char_type oc, last;
342     assert(m_prev.length());
343     last = m_prev[m_prev.length()-1];
344     oc = hex_to_int(last) << 4 |
345     hex_to_int(c) ;
346     write(oc,out);
347     m_prev.clear();
348     }
349     m_state = sWaitingChar;
350     return;
351     case sNewline:
352     if(m_nl == 0)
353     {
354     m_nl = c;
355     return;
356     } else {
357     int len = m_prev.length();
358     if(!len || m_prev[0] != '=')
359     hardLineBrk(out);
360     m_prev.clear();
361     m_state = sWaitingChar;
362     bool is2Ch;
363     is2Ch = (c == (m_nl == CR ? LF : CR));
364     m_nl = 0;
365     if(is2Ch)
366     return;
367     continue;
368     }
369     case sWaitingChar:
370     if(isblank(c))
371     {
372     m_state = sBlank;
373     continue;
374     } else if(isnl(c)) {
375     m_state = sNewline;
376     continue;
377     } else if(c == '=') {
378     m_state = sAfterEq;
379     m_prev.append(1, c);
380     return;
381     } else {
382     // WARNING: NOT ignoring chars > 126
383     // as suggested in rfc2045 6.7 note 4
384     if(c < 32 && c != TAB)
385     {
386     // malformed, CTRL ch found
387     // ignore (rfc2045 6.7 note 4)
388     return;
389     }
390     write(c,out);
391     }
392     return;
393     }
394     }
395     }
396     public:
397     /*! Constructor */
398     Decoder()
399     : m_state(sWaitingChar), m_nl(0)
400     {
401     }
402     /*! Returns the name of the codec ("Quoted-Printable") */
403     const char* name() const { return "Quoted-Printable"; }
404     /*! Returns the max line length */
405     size_t maxlen()
406     {
407     return m_maxlen;
408     }
409     /*!
410     Set the max line length. No more then \p i chars will be
411     printed on one line.
412     */
413     void maxlen(size_t i)
414     {
415     m_maxlen = i;
416     }
417     /*!
418     Decodes [\p bit,\p eit) and write any decoded char to \p out.
419     */
420     template<typename InIt, typename OutIt>
421     void process(InIt bit, InIt eit, OutIt out)
422     {
423     for(;bit != eit; ++bit)
424     decodeChar(*bit, out);
425     flush(out);
426     }
427     /*!
428     Decodes \p ic and write any decoded output char to \p out.
429    
430     \warning You must call flush() when all chars have been
431     processed by the code(...) funcion.
432     \n
433     \code
434     while( (c = getchar()) != EOF )
435     qp.process(c, out);
436     qp.flush();
437     \endcode
438     \n
439     \sa flush()
440     */
441     template<typename OutIt>
442     void process(char_type ic, OutIt& out)
443     {
444     decodeChar(ic, out);
445     }
446     /*!
447     Write to \p out any buffered decoded char.
448     */
449     template<typename OutIt>
450     void flush(OutIt& out)
451     {
452     /* m_prev can be (regex):
453     empty:
454     ok
455     '=' :
456     malformed, '=' is last stream char, print as is
457     (rfc2045 6.7 note 3)
458     '=[a-zA-Z]'
459     malformed, print as is
460     (rfc2045 6.7 note 2)
461     '= +'
462     malformed, just print '=' and ignore trailing
463     blanks (rfc2045 6.7 (3) )
464     */
465     int len = m_prev.length();
466     if(len)
467     {
468     if(len == 1)
469     {
470     assert(m_prev[0] == '=');
471     write('=', out);
472     } else {
473     write('=', out);
474     if(m_prev[1] != ' ')
475     write(m_prev[1], out);
476     }
477     } else if(m_nl != 0) // stream ends with newline
478     hardLineBrk(out);
479    
480     }
481     };
482    
483     };
484    
485    
486     } // namespace
487    
488     #endif
489    

  ViewVC Help
Powered by ViewVC 1.1.26