@@@ cython and python 3 wip
[mLib-python] / codec.pyx
CommitLineData
55b42c18
MW
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###--------------------------------------------------------------------------
965caf5f
MW
27### Constants.
28
29CDCF_LOWERC = _CDCF_LOWERC
30CDCF_IGNCASE = _CDCF_IGNCASE
31CDCF_NOEQPAD = _CDCF_NOEQPAD
32CDCF_IGNEQPAD = _CDCF_IGNEQPAD
33CDCF_IGNEQMID = _CDCF_IGNEQMID
34CDCF_IGNZPAD = _CDCF_IGNZPAD
35CDCF_IGNNEWL = _CDCF_IGNNEWL
36CDCF_IGNSPC = _CDCF_IGNSPC
37CDCF_IGNINVCH = _CDCF_IGNINVCH
38CDCF_IGNJUNK = _CDCF_IGNJUNK
55b42c18
MW
39
40class CDCF:
965caf5f
MW
41 ## DEPRECATED. Use the original names at module level.
42 LOWERC = _CDCF_LOWERC
43 IGNCASE = _CDCF_IGNCASE
44 NOEQPAD = _CDCF_NOEQPAD
45 IGNEQPAD = _CDCF_IGNEQPAD
46 IGNEQMID = _CDCF_IGNEQMID
47 IGNZPAD = _CDCF_IGNZPAD
48 IGNNEWL = _CDCF_IGNNEWL
49 IGNSPC = _CDCF_IGNSPC
50 IGNINVCH = _CDCF_IGNINVCH
51 IGNJUNK = _CDCF_IGNJUNK
52
53CDCERR_OK = _CDCERR_OK
54CDCERR_INVCH = _CDCERR_INVCH
55CDCERR_INVEQPAD = _CDCERR_INVEQPAD
56CDCERR_INVZPAD = _CDCERR_INVZPAD
55b42c18
MW
57
58class CDCERR:
965caf5f
MW
59 ## DEPRECATED. Use the original names at module level.
60 OK = _CDCERR_OK
61 INVCH = _CDCERR_INVCH
62 INVEQPAD = _CDCERR_INVEQPAD
63 INVZPAD = _CDCERR_INVZPAD
64
65###--------------------------------------------------------------------------
66### Base classes.
55b42c18
MW
67
68class CodecError (Exception):
addc0c37
MW
69 """
70 Exception from decoding operation.
71
965caf5f 72 Attributes: `err' = `CDCERR_*' code, `msg' = message string
addc0c37 73 """
55b42c18
MW
74 def __init__(me, err):
75 me.err = err
965caf5f 76 me.msg = <str>_codec_strerror(err)
55b42c18
MW
77 def __str__(me):
78 return me.msg
79
80def codec_strerror(err):
965caf5f
MW
81 """codec_strerror(ERR) -> STR: message for `CDCERR_*' code"""
82 return <str>_codec_strerror(err)
55b42c18
MW
83
84cdef class _BaseCodec:
addc0c37 85 """Abstract superclass for codecs."""
55b42c18
MW
86 cdef codec *c
87 def __cinit__(me, *hunoz, **hukairz):
88 me.c = NULL
55b42c18
MW
89 def __dealloc__(me):
90 if me.c is not NULL:
91 me.c.ops.destroy(me.c)
965caf5f
MW
92 def __init__(me, *hunoz, **hukairz):
93 raise TypeError('abstract class')
94 cdef int _code(me, const void *p, Py_ssize_t sz,
95 dstr *d, bint finishp) except -1:
55b42c18
MW
96 cdef int err
97 if me.c is NULL:
965caf5f
MW
98 raise ValueError('Encoding finished')
99 err = me.c.ops.code(me.c, p, sz, d)
100 if err:
101 raise CodecError(err)
102 if finishp:
103 err = me.c.ops.code(me.c, p, sz, d)
104 me.c.ops.destroy(me.c)
105 me.c = NULL
106 if err:
107 raise CodecError(err)
108 return 0
109
55b42c18 110 def done(me):
addc0c37 111 """C.done() -> OUT: final output"""
55b42c18
MW
112 me.code('', True)
113
114cdef class _BaseEncoder (_BaseCodec):
965caf5f 115 def encode(me, input, finishp = False):
addc0c37 116 """C.encode(IN, [finishp = False]) -> OUT: continue/finish encoding"""
965caf5f
MW
117 cdef const void *p
118 cdef Py_ssize_t sz
119 cdef dstr d
120 DCREATE(&d)
121 try:
122 PyObject_AsReadBuffer(input, &p, &sz)
123 me._code(p, sz, &d, finishp)
124 return TEXT_FROMSTRLEN(d.buf, d.len)
125 finally:
126 dstr_destroy(&d)
127 def done(me):
128 """C.done() -> OUT: final output"""
129 cdef dstr d
130 DCREATE(&d)
131 try:
132 me._code(NULL, 0, &d, True)
133 return TEXT_FROMSTRLEN(d.buf, d.len)
134 finally:
135 dstr_destroy(&d)
55b42c18
MW
136
137cdef class _BaseDecoder (_BaseCodec):
965caf5f 138 def decode(me, input, finishp = False):
addc0c37 139 """C.decode(IN, [finishp = False]) -> OUT: continue/finish decoding"""
965caf5f
MW
140 cdef const char *p
141 cdef Py_ssize_t sz
142 cdef dstr d
143 DCREATE(&d)
144 try:
145 TEXT_PTRLEN(input, &p, &sz)
146 me._code(p, sz, &d, finishp)
147 return BIN_FROMSTRLEN(d.buf, d.len)
148 finally:
149 dstr_destroy(&d)
150 def done(me):
151 """C.done() -> OUT: final output"""
152 cdef dstr d
153 DCREATE(&d)
154 try:
155 me._code(NULL, 0, &d, True)
156 return BIN_FROMSTRLEN(d.buf, d.len)
157 finally:
158 dstr_destroy(&d)
55b42c18
MW
159
160###--------------------------------------------------------------------------
161### Base64.
162
163cdef extern from 'mLib/base64.h':
164 codec_class base64_class
165 codec_class file64_class
166 codec_class base64url_class
167
168cdef class Base64Encoder (_BaseEncoder):
addc0c37 169 """
965caf5f 170 Base64Encoder([indent = '\\n'], [maxline = 72], [flags = 0])
addc0c37
MW
171
172 Base64 encoder.
173 """
965caf5f
MW
174 def __init__(me, indent = '\n', maxline = 72, flags = 0):
175 me.c = base64_class.encoder(flags, TEXT_PTR(indent), maxline)
55b42c18
MW
176
177cdef class Base64Decoder (_BaseDecoder):
addc0c37 178 """
965caf5f 179 Base64Decoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL])
addc0c37
MW
180
181 Base64 decoder.
182 """
965caf5f 183 def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL):
55b42c18
MW
184 me.c = base64_class.decoder(flags)
185
186cdef class File64Encoder (_BaseEncoder):
addc0c37 187 """
965caf5f 188 File64Encoder([indent = '\\n'], [maxline = 72], [flags = 0])
addc0c37
MW
189
190 Base64 encoder, using `%' instead of `/', so encoded strings are safe as
191 filenames.
192 """
965caf5f
MW
193 def __init__(me, indent = '\n', maxline = 72, flags = 0):
194 me.c = file64_class.encoder(flags, TEXT_PTR(indent), maxline)
55b42c18
MW
195
196cdef class File64Decoder (_BaseDecoder):
addc0c37 197 """
965caf5f 198 File64Decoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL])
addc0c37
MW
199
200 Base64 encoder, using `%' instead of `/', so encoded strings are safe as
201 filenames.
202 """
965caf5f 203 def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL):
55b42c18
MW
204 me.c = file64_class.decoder(flags)
205
206cdef class Base64URLEncoder (_BaseEncoder):
addc0c37 207 """
965caf5f 208 Base64URLEncoder([indent = '\\n'], [maxline = 72], [flags = 0])
addc0c37
MW
209
210 Base64 encoder, using `-' and `_' instead of `+' and `/', so encoded
211 strings are safe as URL components.
212 """
965caf5f
MW
213 def __init__(me, indent = '\n', maxline = 72, flags = 0):
214 me.c = base64url_class.encoder(flags, TEXT_PTR(indent), maxline)
55b42c18
MW
215
216cdef class Base64URLDecoder (_BaseDecoder):
addc0c37 217 """
965caf5f 218 Base64URLDecoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL])
addc0c37
MW
219
220 Base64 decoder, using `-' and `_' instead of `+' and `/', so encoded
221 strings are safe as URL components.
222 """
965caf5f 223 def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL):
55b42c18
MW
224 me.c = base64url_class.decoder(flags)
225
226###--------------------------------------------------------------------------
227### Base32.
228
229cdef extern from 'mLib/base32.h':
230 codec_class base32_class
231 codec_class base32hex_class
232
233cdef class Base32Encoder (_BaseEncoder):
addc0c37 234 """
965caf5f 235 Base32Encoder([indent = '\\n'], [maxline = 72], [flags = 0])
addc0c37
MW
236
237 Base32 encoder.
238 """
965caf5f
MW
239 def __init__(me, indent = '\n', maxline = 72, flags = 0):
240 me.c = base32_class.encoder(flags, TEXT_PTR(indent), maxline)
55b42c18
MW
241
242cdef class Base32Decoder (_BaseDecoder):
addc0c37 243 """
965caf5f 244 Base32Decoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL | CDCF_IGNCASE])
addc0c37
MW
245
246 Base32 decoder.
247 """
965caf5f 248 def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL | _CDCF_IGNCASE):
55b42c18
MW
249 me.c = base32_class.decoder(flags)
250
251cdef class Base32HexEncoder (_BaseEncoder):
addc0c37 252 """
965caf5f 253 Base32Encoder([indent = '\\n'], [maxline = 72], [flags = 0])
addc0c37
MW
254
255 Base32 encoder, using digits and letters in ascending order, rather than
256 avoiding digits which visually resemble letters.
257 """
965caf5f
MW
258 def __init__(me, indent = '\n', maxline = 72, flags = 0):
259 me.c = base32hex_class.encoder(flags, TEXT_PTR(indent), maxline)
55b42c18
MW
260
261cdef class Base32HexDecoder (_BaseDecoder):
addc0c37 262 """
965caf5f 263 Base32Decoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL | CDCF_IGNCASE])
addc0c37
MW
264
265 Base32 decoder, using digits and letters in ascending order, rather than
266 avoiding digits which visually resemble letters.
267 """
965caf5f 268 def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL | _CDCF_IGNCASE):
55b42c18
MW
269 me.c = base32hex_class.decoder(flags)
270
271###--------------------------------------------------------------------------
272### Hex.
273
274cdef extern from 'mLib/hex.h':
275 codec_class hex_class
276
277cdef class HexEncoder (_BaseEncoder):
addc0c37 278 """
965caf5f 279 HexEncoder([indent = '\\n'], [maxline = 72], [flags = CDCF_LOWERC])
addc0c37
MW
280
281 Hexadecimal encoder.
282 """
965caf5f
MW
283 def __init__(me, indent = '\n', maxline = 72, flags = _CDCF_LOWERC):
284 me.c = hex_class.encoder(flags, TEXT_PTR(indent), maxline)
55b42c18
MW
285
286cdef class HexDecoder (_BaseDecoder):
addc0c37 287 """
965caf5f 288 HexDecoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL | CDCF_IGNCASE])
addc0c37
MW
289
290 Hexadecimal decoder.
291 """
965caf5f 292 def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL | _CDCF_IGNCASE):
55b42c18
MW
293 me.c = hex_class.decoder(flags)
294
295###----- That's all, folks --------------------------------------------------