@@@ cython and python 3 wip
[mLib-python] / codec.pyx
index 1274afd..0bef296 100644 (file)
--- a/codec.pyx
+++ b/codec.pyx
 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 ###--------------------------------------------------------------------------
-### Base classes.
-
-cdef extern from 'mLib/codec.h':
-
-  ctypedef struct codec
-
-  ctypedef struct codec_class:
-    char *name
-    codec *(*encoder)(unsigned f, char *ind, unsigned max)
-    codec *(*decoder)(unsigned f)
-
-  ctypedef struct codec_ops:
-    codec_class *c
-    int (*code)(codec *c, void *p, size_t, dstr *d)
-    void (*destroy)(codec *c)
-  ctypedef struct codec:
-    codec_ops *ops
-
-  enum:
-    CDCF_LOWERC
-    CDCF_IGNCASE
-    CDCF_NOEQPAD
-    CDCF_IGNEQPAD
-    CDCF_IGNEQMID
-    CDCF_IGNZPAD
-    CDCF_IGNNEWL
-    CDCF_IGNSPC
-    CDCF_IGNINVCH
-    CDCF_IGNJUNK
-
-  enum:
-    CDCERR_OK
-    CDCERR_INVCH
-    CDCERR_INVEQPAD
-    CDCERR_INVZPAD
-
-  char *_codec_strerror "codec_strerror"(int err)
+### Constants.
+
+CDCF_LOWERC = _CDCF_LOWERC
+CDCF_IGNCASE = _CDCF_IGNCASE
+CDCF_NOEQPAD = _CDCF_NOEQPAD
+CDCF_IGNEQPAD = _CDCF_IGNEQPAD
+CDCF_IGNEQMID = _CDCF_IGNEQMID
+CDCF_IGNZPAD = _CDCF_IGNZPAD
+CDCF_IGNNEWL = _CDCF_IGNNEWL
+CDCF_IGNSPC = _CDCF_IGNSPC
+CDCF_IGNINVCH = _CDCF_IGNINVCH
+CDCF_IGNJUNK = _CDCF_IGNJUNK
 
 class CDCF:
-  LOWERC = CDCF_LOWERC
-  IGNCASE = CDCF_IGNCASE
-  NOEQPAD = CDCF_NOEQPAD
-  IGNEQPAD = CDCF_IGNEQPAD
-  IGNEQMID = CDCF_IGNEQMID
-  IGNZPAD = CDCF_IGNZPAD
-  IGNNEWL = CDCF_IGNNEWL
-  IGNSPC = CDCF_IGNSPC
-  IGNINVCH = CDCF_IGNINVCH
-  IGNJUNK = CDCF_IGNJUNK
+  ## DEPRECATED.  Use the original names at module level.
+  LOWERC = _CDCF_LOWERC
+  IGNCASE = _CDCF_IGNCASE
+  NOEQPAD = _CDCF_NOEQPAD
+  IGNEQPAD = _CDCF_IGNEQPAD
+  IGNEQMID = _CDCF_IGNEQMID
+  IGNZPAD = _CDCF_IGNZPAD
+  IGNNEWL = _CDCF_IGNNEWL
+  IGNSPC = _CDCF_IGNSPC
+  IGNINVCH = _CDCF_IGNINVCH
+  IGNJUNK = _CDCF_IGNJUNK
+
+CDCERR_OK = _CDCERR_OK
+CDCERR_INVCH = _CDCERR_INVCH
+CDCERR_INVEQPAD = _CDCERR_INVEQPAD
+CDCERR_INVZPAD = _CDCERR_INVZPAD
 
 class CDCERR:
-  OK = CDCERR_OK
-  INVCH = CDCERR_INVCH
-  INVEQPAD = CDCERR_INVEQPAD
-  INVZPAD = CDCERR_INVZPAD
+  ## DEPRECATED.  Use the original names at module level.
+  OK = _CDCERR_OK
+  INVCH = _CDCERR_INVCH
+  INVEQPAD = _CDCERR_INVEQPAD
+  INVZPAD = _CDCERR_INVZPAD
+
+###--------------------------------------------------------------------------
+### Base classes.
 
 class CodecError (Exception):
   """
   Exception from decoding operation.
 
-  Attributes: err = CDCERR.* code, msg = message string
+  Attributes: `err' = `CDCERR_*' code, `msg' = message string
   """
   def __init__(me, err):
     me.err = err
-    me.msg = _codec_strerror(err)
+    me.msg = <str>_codec_strerror(err)
   def __str__(me):
     return me.msg
 
 def codec_strerror(err):
-  """codec_strerror(ERR) -> STR: message for CDCERR.* code"""
-  return _codec_strerror(err)
-
-cdef int code(codec *c, void *p, size_t len, dstr *d) except -1:
-  cdef int err
-  err = c.ops.code(c, p, len, d)
-  if err:
-    raise CodecError(err)
-  return 0
+  """codec_strerror(ERR) -> STR: message for `CDCERR_*' code"""
+  return <str>_codec_strerror(err)
 
 cdef class _BaseCodec:
   """Abstract superclass for codecs."""
   cdef codec *c
   def __cinit__(me, *hunoz, **hukairz):
     me.c = NULL
-  def __init__(me, *hunoz, **hukairz):
-    raise TypeError, 'abstract class'
   def __dealloc__(me):
     if me.c is not NULL:
       me.c.ops.destroy(me.c)
-  cdef code(me, text, int finishp):
-    cdef void *p
-    cdef Py_ssize_t len
-    cdef dstr d
+  def __init__(me, *hunoz, **hukairz):
+    raise TypeError('abstract class')
+  cdef int _code(me, const void *p, Py_ssize_t sz,
+                 dstr *d, bint finishp) except -1:
     cdef int err
     if me.c is NULL:
-      raise ValueError, 'Encoding finished'
-    DCREATE(&d)
-    try:
-      PyObject_AsReadBuffer(text, <cvp *>&p, &len)
-      code(me.c, p, len, &d)
-      if finishp:
-        code(me.c, NULL, 0, &d)
-        me.c.ops.destroy(me.c)
-        me.c = NULL
-      return PyString_FromStringAndSize(d.buf, d.len)
-    finally:
-      dstr_destroy(&d)
+      raise ValueError('Encoding finished')
+    err = me.c.ops.code(me.c, p, sz, d)
+    if err:
+      raise CodecError(err)
+    if finishp:
+      err = me.c.ops.code(me.c, p, sz, d)
+      me.c.ops.destroy(me.c)
+      me.c = NULL
+      if err:
+        raise CodecError(err)
+    return 0
+
   def done(me):
     """C.done() -> OUT: final output"""
     me.code('', True)
 
 cdef class _BaseEncoder (_BaseCodec):
-  def encode(me, text, finishp = False):
+  def encode(me, input, finishp = False):
     """C.encode(IN, [finishp = False]) -> OUT: continue/finish encoding"""
-    return me.code(text, finishp)
+    cdef const void *p
+    cdef Py_ssize_t sz
+    cdef dstr d
+    DCREATE(&d)
+    try:
+      PyObject_AsReadBuffer(input, &p, &sz)
+      me._code(p, sz, &d, finishp)
+      return TEXT_FROMSTRLEN(d.buf, d.len)
+    finally:
+      dstr_destroy(&d)
+  def done(me):
+    """C.done() -> OUT: final output"""
+    cdef dstr d
+    DCREATE(&d)
+    try:
+      me._code(NULL, 0, &d, True)
+      return TEXT_FROMSTRLEN(d.buf, d.len)
+    finally:
+      dstr_destroy(&d)
 
 cdef class _BaseDecoder (_BaseCodec):
-  def decode(me, text, finishp = False):
+  def decode(me, input, finishp = False):
     """C.decode(IN, [finishp = False]) -> OUT: continue/finish decoding"""
-    return me.code(text, finishp)
+    cdef const char *p
+    cdef Py_ssize_t sz
+    cdef dstr d
+    DCREATE(&d)
+    try:
+      TEXT_PTRLEN(input, &p, &sz)
+      me._code(p, sz, &d, finishp)
+      return BIN_FROMSTRLEN(d.buf, d.len)
+    finally:
+      dstr_destroy(&d)
+  def done(me):
+    """C.done() -> OUT: final output"""
+    cdef dstr d
+    DCREATE(&d)
+    try:
+      me._code(NULL, 0, &d, True)
+      return BIN_FROMSTRLEN(d.buf, d.len)
+    finally:
+      dstr_destroy(&d)
 
 ###--------------------------------------------------------------------------
 ### Base64.
@@ -155,60 +167,60 @@ cdef extern from 'mLib/base64.h':
 
 cdef class Base64Encoder (_BaseEncoder):
   """
-  Base64Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+  Base64Encoder([indent = '\\n'], [maxline = 72], [flags = 0])
 
   Base64 encoder.
   """
-  def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
-    me.c = base64_class.encoder(flags, indent, maxline)
+  def __init__(me, indent = '\n', maxline = 72, flags = 0):
+    me.c = base64_class.encoder(flags, TEXT_PTR(indent), maxline)
 
 cdef class Base64Decoder (_BaseDecoder):
   """
-  Base64Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+  Base64Decoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL])
 
   Base64 decoder.
   """
-  def __init__(me, flags = CDCF_IGNJUNK):
+  def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL):
     me.c = base64_class.decoder(flags)
 
 cdef class File64Encoder (_BaseEncoder):
   """
-  File64Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+  File64Encoder([indent = '\\n'], [maxline = 72], [flags = 0])
 
   Base64 encoder, using `%' instead of `/', so encoded strings are safe as
   filenames.
   """
-  def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
-    me.c = file64_class.encoder(flags, indent, maxline)
+  def __init__(me, indent = '\n', maxline = 72, flags = 0):
+    me.c = file64_class.encoder(flags, TEXT_PTR(indent), maxline)
 
 cdef class File64Decoder (_BaseDecoder):
   """
-  File64Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+  File64Decoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL])
 
   Base64 encoder, using `%' instead of `/', so encoded strings are safe as
   filenames.
   """
-  def __init__(me, flags = CDCF_IGNJUNK):
+  def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL):
     me.c = file64_class.decoder(flags)
 
 cdef class Base64URLEncoder (_BaseEncoder):
   """
-  Base64URLEncoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+  Base64URLEncoder([indent = '\\n'], [maxline = 72], [flags = 0])
 
   Base64 encoder, using `-' and `_' instead of `+' and `/', so encoded
   strings are safe as URL components.
   """
-  def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
-    me.c = base64url_class.encoder(flags, indent, maxline)
+  def __init__(me, indent = '\n', maxline = 72, flags = 0):
+    me.c = base64url_class.encoder(flags, TEXT_PTR(indent), maxline)
 
 cdef class Base64URLDecoder (_BaseDecoder):
   """
-  Base64URLDecoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+  Base64URLDecoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL])
 
   Base64 decoder, using `-' and `_' instead of `+' and `/', so encoded
   strings are safe as URL components.
   """
-  def __init__(me, flags = CDCF_IGNJUNK):
+  def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL):
     me.c = base64url_class.decoder(flags)
 
 ###--------------------------------------------------------------------------
@@ -220,40 +232,40 @@ cdef extern from 'mLib/base32.h':
 
 cdef class Base32Encoder (_BaseEncoder):
   """
-  Base32Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+  Base32Encoder([indent = '\\n'], [maxline = 72], [flags = 0])
 
   Base32 encoder.
   """
-  def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
-    me.c = base32_class.encoder(flags, indent, maxline)
+  def __init__(me, indent = '\n', maxline = 72, flags = 0):
+    me.c = base32_class.encoder(flags, TEXT_PTR(indent), maxline)
 
 cdef class Base32Decoder (_BaseDecoder):
   """
-  Base32Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+  Base32Decoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL | CDCF_IGNCASE])
 
   Base32 decoder.
   """
-  def __init__(me, flags = CDCF_IGNJUNK):
+  def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL | _CDCF_IGNCASE):
     me.c = base32_class.decoder(flags)
 
 cdef class Base32HexEncoder (_BaseEncoder):
   """
-  Base32Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+  Base32Encoder([indent = '\\n'], [maxline = 72], [flags = 0])
 
   Base32 encoder, using digits and letters in ascending order, rather than
   avoiding digits which visually resemble letters.
   """
-  def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
-    me.c = base32hex_class.encoder(flags, indent, maxline)
+  def __init__(me, indent = '\n', maxline = 72, flags = 0):
+    me.c = base32hex_class.encoder(flags, TEXT_PTR(indent), maxline)
 
 cdef class Base32HexDecoder (_BaseDecoder):
   """
-  Base32Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+  Base32Decoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL | CDCF_IGNCASE])
 
   Base32 decoder, using digits and letters in ascending order, rather than
   avoiding digits which visually resemble letters.
   """
-  def __init__(me, flags = CDCF_IGNJUNK):
+  def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL | _CDCF_IGNCASE):
     me.c = base32hex_class.decoder(flags)
 
 ###--------------------------------------------------------------------------
@@ -264,23 +276,20 @@ cdef extern from 'mLib/hex.h':
 
 cdef class HexEncoder (_BaseEncoder):
   """
-  HexEncoder([indent = '\\n'], [maxline = 72],
-             [flags = CDCF.IGNJUNK | CDCF.LOWERC])
+  HexEncoder([indent = '\\n'], [maxline = 72], [flags = CDCF_LOWERC])
 
   Hexadecimal encoder.
   """
-  def __init__(me, indent = '\n', maxline = 72,
-               flags = CDCF_IGNJUNK | CDCF_LOWERC):
-    me.c = hex_class.encoder(flags, indent, maxline)
+  def __init__(me, indent = '\n', maxline = 72, flags = _CDCF_LOWERC):
+    me.c = hex_class.encoder(flags, TEXT_PTR(indent), maxline)
 
 cdef class HexDecoder (_BaseDecoder):
   """
-  HexDecoder([indent = '\\n'], [maxline = 72],
-             [flags = CDCF.IGNJUNK | CDCF.LOWERC])
+  HexDecoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL | CDCF_IGNCASE])
 
   Hexadecimal decoder.
   """
-  def __init__(me, flags = CDCF_IGNJUNK | CDCF_LOWERC):
+  def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL | _CDCF_IGNCASE):
     me.c = hex_class.decoder(flags)
 
 ###----- That's all, folks --------------------------------------------------