chiark / gitweb /
debian/copyright, .mailmap: Convert to machine-readable format.
[mLib-python] / codec.pyx
1 ### -*-pyrex-*-
2 ###
3 ### Generic encoder/decoder
4 ###
5 ### (c) 2005 Straylight/Edgeware
6 ###
7
8 ###----- Licensing notice ---------------------------------------------------
9 ###
10 ### This file is part of the Python interface to mLib.
11 ###
12 ### mLib/Python is free software; you can redistribute it and/or modify
13 ### it under the terms of the GNU General Public License as published by
14 ### the Free Software Foundation; either version 2 of the License, or
15 ### (at your option) any later version.
16 ###
17 ### mLib/Python is distributed in the hope that it will be useful,
18 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ### GNU General Public License for more details.
21 ###
22 ### You should have received a copy of the GNU General Public License
23 ### along with mLib/Python; if not, write to the Free Software Foundation,
24 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26 ###--------------------------------------------------------------------------
27 ### Base classes.
28
29 cdef extern from 'mLib/codec.h':
30
31   ctypedef struct codec
32
33   ctypedef struct codec_class:
34     char *name
35     codec *(*encoder)(unsigned f, char *ind, unsigned max)
36     codec *(*decoder)(unsigned f)
37
38   ctypedef struct codec_ops:
39     codec_class *c
40     int (*code)(codec *c, void *p, size_t, dstr *d)
41     void (*destroy)(codec *c)
42   ctypedef struct codec:
43     codec_ops *ops
44
45   enum:
46     CDCF_LOWERC
47     CDCF_IGNCASE
48     CDCF_NOEQPAD
49     CDCF_IGNEQPAD
50     CDCF_IGNEQMID
51     CDCF_IGNZPAD
52     CDCF_IGNNEWL
53     CDCF_IGNSPC
54     CDCF_IGNINVCH
55     CDCF_IGNJUNK
56
57   enum:
58     CDCERR_OK
59     CDCERR_INVCH
60     CDCERR_INVEQPAD
61     CDCERR_INVZPAD
62
63   char *_codec_strerror "codec_strerror"(int err)
64
65 class CDCF:
66   LOWERC = CDCF_LOWERC
67   IGNCASE = CDCF_IGNCASE
68   NOEQPAD = CDCF_NOEQPAD
69   IGNEQPAD = CDCF_IGNEQPAD
70   IGNEQMID = CDCF_IGNEQMID
71   IGNZPAD = CDCF_IGNZPAD
72   IGNNEWL = CDCF_IGNNEWL
73   IGNSPC = CDCF_IGNSPC
74   IGNINVCH = CDCF_IGNINVCH
75   IGNJUNK = CDCF_IGNJUNK
76
77 class CDCERR:
78   OK = CDCERR_OK
79   INVCH = CDCERR_INVCH
80   INVEQPAD = CDCERR_INVEQPAD
81   INVZPAD = CDCERR_INVZPAD
82
83 class CodecError (Exception):
84   """
85   Exception from decoding operation.
86
87   Attributes: err = CDCERR.* code, msg = message string
88   """
89   def __init__(me, err):
90     me.err = err
91     me.msg = _codec_strerror(err)
92   def __str__(me):
93     return me.msg
94
95 def codec_strerror(err):
96   """codec_strerror(ERR) -> STR: message for CDCERR.* code"""
97   return _codec_strerror(err)
98
99 cdef int code(codec *c, void *p, size_t len, dstr *d) except -1:
100   cdef int err
101   err = c.ops.code(c, p, len, d)
102   if err:
103     raise CodecError(err)
104   return 0
105
106 cdef class _BaseCodec:
107   """Abstract superclass for codecs."""
108   cdef codec *c
109   def __cinit__(me, *hunoz, **hukairz):
110     me.c = NULL
111   def __init__(me, *hunoz, **hukairz):
112     raise TypeError, 'abstract class'
113   def __dealloc__(me):
114     if me.c is not NULL:
115       me.c.ops.destroy(me.c)
116   cdef code(me, text, int finishp):
117     cdef void *p
118     cdef Py_ssize_t len
119     cdef dstr d
120     cdef int err
121     if me.c is NULL:
122       raise ValueError, 'Encoding finished'
123     DCREATE(&d)
124     try:
125       PyObject_AsReadBuffer(text, <cvp *>&p, &len)
126       code(me.c, p, len, &d)
127       if finishp:
128         code(me.c, NULL, 0, &d)
129         me.c.ops.destroy(me.c)
130         me.c = NULL
131       return PyString_FromStringAndSize(d.buf, d.len)
132     finally:
133       dstr_destroy(&d)
134   def done(me):
135     """C.done() -> OUT: final output"""
136     me.code('', True)
137
138 cdef class _BaseEncoder (_BaseCodec):
139   def encode(me, text, finishp = False):
140     """C.encode(IN, [finishp = False]) -> OUT: continue/finish encoding"""
141     return me.code(text, finishp)
142
143 cdef class _BaseDecoder (_BaseCodec):
144   def decode(me, text, finishp = False):
145     """C.decode(IN, [finishp = False]) -> OUT: continue/finish decoding"""
146     return me.code(text, finishp)
147
148 ###--------------------------------------------------------------------------
149 ### Base64.
150
151 cdef extern from 'mLib/base64.h':
152   codec_class base64_class
153   codec_class file64_class
154   codec_class base64url_class
155
156 cdef class Base64Encoder (_BaseEncoder):
157   """
158   Base64Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
159
160   Base64 encoder.
161   """
162   def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
163     me.c = base64_class.encoder(flags, indent, maxline)
164
165 cdef class Base64Decoder (_BaseDecoder):
166   """
167   Base64Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
168
169   Base64 decoder.
170   """
171   def __init__(me, flags = CDCF_IGNJUNK):
172     me.c = base64_class.decoder(flags)
173
174 cdef class File64Encoder (_BaseEncoder):
175   """
176   File64Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
177
178   Base64 encoder, using `%' instead of `/', so encoded strings are safe as
179   filenames.
180   """
181   def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
182     me.c = file64_class.encoder(flags, indent, maxline)
183
184 cdef class File64Decoder (_BaseDecoder):
185   """
186   File64Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
187
188   Base64 encoder, using `%' instead of `/', so encoded strings are safe as
189   filenames.
190   """
191   def __init__(me, flags = CDCF_IGNJUNK):
192     me.c = file64_class.decoder(flags)
193
194 cdef class Base64URLEncoder (_BaseEncoder):
195   """
196   Base64URLEncoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
197
198   Base64 encoder, using `-' and `_' instead of `+' and `/', so encoded
199   strings are safe as URL components.
200   """
201   def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
202     me.c = base64url_class.encoder(flags, indent, maxline)
203
204 cdef class Base64URLDecoder (_BaseDecoder):
205   """
206   Base64URLDecoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
207
208   Base64 decoder, using `-' and `_' instead of `+' and `/', so encoded
209   strings are safe as URL components.
210   """
211   def __init__(me, flags = CDCF_IGNJUNK):
212     me.c = base64url_class.decoder(flags)
213
214 ###--------------------------------------------------------------------------
215 ### Base32.
216
217 cdef extern from 'mLib/base32.h':
218   codec_class base32_class
219   codec_class base32hex_class
220
221 cdef class Base32Encoder (_BaseEncoder):
222   """
223   Base32Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
224
225   Base32 encoder.
226   """
227   def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
228     me.c = base32_class.encoder(flags, indent, maxline)
229
230 cdef class Base32Decoder (_BaseDecoder):
231   """
232   Base32Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
233
234   Base32 decoder.
235   """
236   def __init__(me, flags = CDCF_IGNJUNK):
237     me.c = base32_class.decoder(flags)
238
239 cdef class Base32HexEncoder (_BaseEncoder):
240   """
241   Base32Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
242
243   Base32 encoder, using digits and letters in ascending order, rather than
244   avoiding digits which visually resemble letters.
245   """
246   def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
247     me.c = base32hex_class.encoder(flags, indent, maxline)
248
249 cdef class Base32HexDecoder (_BaseDecoder):
250   """
251   Base32Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
252
253   Base32 decoder, using digits and letters in ascending order, rather than
254   avoiding digits which visually resemble letters.
255   """
256   def __init__(me, flags = CDCF_IGNJUNK):
257     me.c = base32hex_class.decoder(flags)
258
259 ###--------------------------------------------------------------------------
260 ### Hex.
261
262 cdef extern from 'mLib/hex.h':
263   codec_class hex_class
264
265 cdef class HexEncoder (_BaseEncoder):
266   """
267   HexEncoder([indent = '\\n'], [maxline = 72],
268              [flags = CDCF.IGNJUNK | CDCF.LOWERC])
269
270   Hexadecimal encoder.
271   """
272   def __init__(me, indent = '\n', maxline = 72,
273                flags = CDCF_IGNJUNK | CDCF_LOWERC):
274     me.c = hex_class.encoder(flags, indent, maxline)
275
276 cdef class HexDecoder (_BaseDecoder):
277   """
278   HexDecoder([indent = '\\n'], [maxline = 72],
279              [flags = CDCF.IGNJUNK | CDCF.LOWERC])
280
281   Hexadecimal decoder.
282   """
283   def __init__(me, flags = CDCF_IGNJUNK | CDCF_LOWERC):
284     me.c = hex_class.decoder(flags)
285
286 ###----- That's all, folks --------------------------------------------------