Split 'pyke/' into commit 'c80de12d8d0827e0553fed2e4d392cb9bf3a378f'
[catacomb-python] / buffer.c
index ea114c1..0d3d165 100644 (file)
--- a/buffer.c
+++ b/buffer.c
 
 #include "catacomb-python.h"
 
-/*----- Data structures ---------------------------------------------------*/
-
-typedef struct buf_pyobj {
-  PyObject_HEAD
-  buf b;
-  PyObject *sub;
-} buf_pyobj;
-
-static PyTypeObject *rbuf_pytype, *wbuf_pytype;
-#define RBUF_PYCHECK(o) PyObject_TypeCheck((o), rbuf_pytype)
-#define WBUF_PYCHECK(o) PyObject_TypeCheck((o), wbuf_pytype)
-#define BUF_B(o) (&((buf_pyobj *)(o))->b)
-#define BUF_SUB(o) (((buf_pyobj *)(o))->sub)
-
-/*----- Exceptions --------------------------------------------------------*/
-
-static PyObject *buferr;
-
-#define BUFERR(str) do { PyErr_SetString(buferr, str); goto end; } while (0)
-
 /*----- Read buffers ------------------------------------------------------*/
 
+PyTypeObject *rbuf_pytype;
+
 static PyObject *rbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
-  char *p, *q;
-  Py_ssize_t n;
+  struct bin in;
+  void *q;
   buf_pyobj *me = 0;
   static const char *const kwlist[] = { "data", 0 };
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", KWLIST, &p, &n))
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST, convbin, &in))
     goto end;
-  q = xmalloc(n);
-  memcpy(q, p, n);
+  q = xmalloc(in.sz);
+  memcpy(q, in.p, in.sz);
   me = (buf_pyobj *)ty->tp_alloc(ty, 0);
-  me->sub = 0;
-  buf_init(&me->b, q, n);
+  me->sub = 0; me->lk = 0;
+  buf_init(&me->b, q, in.sz);
 end:
   return ((PyObject *)me);
 }
 
 static void buf_pydealloc(PyObject *me)
 {
-  if (BUF_SUB(me))
-    Py_DECREF(BUF_SUB(me));
-  else
-    xfree(BBASE(BUF_B(me)));
+  assert(!BUF_LK(me));
+  if (BUF_SUB(me)) Py_DECREF(BUF_SUB(me));
+  else xfree(BBASE(BUF_B(me)));
   FREEOBJ(me);
 }
 
-static Py_ssize_t rbuf_pysegcount(PyObject *me, Py_ssize_t *nn)
-  { if (nn) *nn = BSZ(BUF_B(me)); return (1); }
-
-static Py_ssize_t rbuf_pyreadbuf(PyObject *me, Py_ssize_t seg, void **q)
-  { assert(seg == 0); *q = BCUR(BUF_B(me)); return (BLEFT(BUF_B(me))); }
+#ifdef PY3
+  static int rbuf_pygetbuf(PyObject *me, Py_buffer *vw, int f)
+  {
+    buf *b = BUF_B(me);
+    return (PyBuffer_FillInfo(vw, me, BCUR(b), BLEFT(b), 1, f));
+  }
+#else
+  static Py_ssize_t rbuf_pysegcount(PyObject *me, Py_ssize_t *nn)
+    { if (nn) *nn = BSZ(BUF_B(me)); return (1); }
+  static Py_ssize_t rbuf_pyreadbuf(PyObject *me, Py_ssize_t seg, void **q)
+    { assert(seg == 0); *q = BCUR(BUF_B(me)); return (BLEFT(BUF_B(me))); }
+#endif
 
 static PyObject *rbmeth_skip(PyObject *me, PyObject *arg)
 {
@@ -140,6 +128,7 @@ BUF_DOSUFFIXES(RBMETH_GETBLK_)
     b = PyObject_NEW(buf_pyobj, rbuf_pytype);                          \
     b->b = bb;                                                         \
     b->sub = me;                                                       \
+    b->lk = 0;                                                         \
     Py_INCREF(me);                                                     \
     return ((PyObject *)b);                                            \
   end:                                                                 \
@@ -184,14 +173,15 @@ end:
 
 static PyObject *rbmeth_getecptraw(PyObject *me, PyObject *arg)
 {
-  PyTypeObject *cobj = ecpt_pytype;
+  PyObject *cobj;
   ec pt = EC_INIT;
+  PyObject *rc = 0;
   if (!PyArg_ParseTuple(arg, "O!:getecptraw", eccurve_pytype, &cobj))
     goto end;
   if (ec_getraw(ECCURVE_C(cobj), BUF_B(me), &pt)) BUFERR("buffer exhausted");
-  return (ecpt_pywrapout(cobj, &pt));
+  rc = ecpt_pywrapout(cobj, &pt);
 end:
-  return (0);
+  return (rc);
 }
 
 static PyObject *rbmeth_getge(PyObject *me, PyObject *arg)
@@ -274,10 +264,15 @@ static const PyMethodDef rbuf_pymethods[] = {
 };
 
 static const PyBufferProcs rbuf_pybuffer = {
+#ifdef PY3
+  rbuf_pygetbuf,                       /* @bf_getbuffer@ */
+  0,                                   /* @bf_releasebuffer@ */
+#else
   rbuf_pyreadbuf,                      /* @bf_getreadbuffer@ */
   0,                                   /* @bf_getwritebuffer@ */
   rbuf_pysegcount,                     /* @bf_getsegcount@ */
   0                                    /* @bf_getcharbuffer@ */
+#endif
 };
 
 static const PyTypeObject rbuf_pytype_skel = {
@@ -330,20 +325,29 @@ static const PyTypeObject rbuf_pytype_skel = {
 
 /*----- Write buffers -----------------------------------------------------*/
 
-static void ensure(PyObject *me, size_t n)
+PyTypeObject *wbuf_pytype;
+
+int ensurebuf(PyObject *me, size_t n)
 {
   buf *b = BUF_B(me);
+  size_t nn = BSZ(b);
+  octet *p;
+  size_t want = BLEN(b) + n;
 
-  if (BLEFT(b) < n) {
-    size_t nn = BSZ(b);
-    octet *p;
-    size_t want = BLEN(b) + n;
+  if (BLEFT(b) >= n)
+    return (0);
+  else if (BUF_LK(me))
+    BUFERR("buffer locked");
+  else {
     while (nn < want) nn <<= 1;
     p = xrealloc(BBASE(b), nn, BSZ(b));
     BCUR(b) = p + BLEN(b);
     BLIM(b) = p + nn;
     BBASE(b) = p;
+    return (0);
   }
+end:
+  return (-1);
 }
 
 static PyObject *wbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
@@ -358,24 +362,34 @@ static PyObject *wbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
     goto end;
   me = (buf_pyobj *)ty->tp_alloc(ty, 0);
   p = xmalloc(n);
-  me->sub = 0;
+  me->sub = 0; me->lk = 0;
   buf_init(&me->b, p, n);
 end:
   return ((PyObject *)me);
 }
 
-static Py_ssize_t wbuf_pysegcount(PyObject *me, Py_ssize_t *nn)
-  { if (nn) *nn = BLEN(BUF_B(me)); return (1); }
-
-static Py_ssize_t wbuf_pyreadbuf(PyObject *me, Py_ssize_t seg, void **q)
-  { assert(seg == 0); *q = BBASE(BUF_B(me)); return (BLEN(BUF_B(me))); }
+#ifdef PY3
+  static int wbuf_pygetbuf(PyObject *me, Py_buffer *vw, int f)
+  {
+    buf *b = BUF_B(me);
+    if (PyBuffer_FillInfo(vw, me, BBASE(b), BLEN(b), 0, f)) return (-1);
+    BUF_LK(me)++; return (0);
+  }
+  static void wbuf_pyrlsbuf(PyObject *me, Py_buffer *vw)
+    { BUF_LK(me)--; }
+#else
+  static Py_ssize_t wbuf_pysegcount(PyObject *me, Py_ssize_t *nn)
+    { if (nn) *nn = BLEN(BUF_B(me)); return (1); }
+  static Py_ssize_t wbuf_pyreadbuf(PyObject *me, Py_ssize_t seg, void **q)
+    { assert(seg == 0); *q = BBASE(BUF_B(me)); return (BLEN(BUF_B(me))); }
+#endif
 
 static PyObject *wbmeth_zero(PyObject *me, PyObject *arg)
 {
   void *p;
   size_t n;
   if (!PyArg_ParseTuple(arg, "O&:zero", convszt, &n)) return (0);
-  ensure(me, n);
+  if (ensurebuf(me, n)) return (0);
   p = buf_get(BUF_B(me), n); assert(p && BOK(BUF_B(me)));
   memset(p, 0, n);
   RETURN_ME;
@@ -383,11 +397,10 @@ static PyObject *wbmeth_zero(PyObject *me, PyObject *arg)
 
 static PyObject *wbmeth_put(PyObject *me, PyObject *arg)
 {
-  void *p;
-  Py_ssize_t n;
-  if (!PyArg_ParseTuple(arg, "s#:put", &p, &n)) return (0);
-  ensure(me, n);
-  buf_put(BUF_B(me), p, n); assert(BOK(BUF_B(me)));
+  struct bin in;
+  if (!PyArg_ParseTuple(arg, "O&:put", convbin, &in)) return (0);
+  if (ensurebuf(me, in.sz)) return (0);
+  buf_put(BUF_B(me), in.p, in.sz); assert(BOK(BUF_B(me)));
   RETURN_ME;
 }
 
@@ -396,7 +409,7 @@ static PyObject *wbmeth_put(PyObject *me, PyObject *arg)
   {                                                                    \
     uint##n i;                                                         \
     if (!PyArg_ParseTuple(arg, "O&:putu" #w, convu##n, &i)) return (0);        \
-    ensure(me, SZ_##n);                                                        \
+    if (ensurebuf(me, SZ_##n)) return (0);                             \
     buf_putu##w(BUF_B(me), i); assert(BOK(BUF_B(me)));                 \
     RETURN_ME;                                                         \
   }
@@ -407,12 +420,11 @@ DOUINTCONV(WBMETH_PUTU_)
 #define WBMETH_PUTBLK_(n, W, w)                                                \
   static PyObject *wbmeth_putblk##w(PyObject *me, PyObject *arg)       \
   {                                                                    \
-    char *p;                                                           \
-    Py_ssize_t sz;                                                     \
-    if (!PyArg_ParseTuple(arg, "s#:putblk" #w, &p, &sz)) goto end;     \
-    if (MASK##W && sz > MASK##W) VALERR("too large");                  \
-    ensure(me, sz + SZ_##n);                                           \
-    buf_putmem##w(BUF_B(me), p, sz); assert(BOK(BUF_B(me)));           \
+    struct bin in;                                                     \
+    if (!PyArg_ParseTuple(arg, "O&:putblk" #w, convbin, &in)) goto end;        \
+    if (MASK##W && in.sz > MASK##W) VALERR("too large");               \
+    if (ensurebuf(me, in.sz + SZ_##n)) return (0);                     \
+    buf_putmem##w(BUF_B(me), in.p, in.sz); assert(BOK(BUF_B(me)));     \
     RETURN_ME;                                                         \
   end:                                                                 \
     return (0);                                                                \
@@ -423,7 +435,7 @@ static PyObject *wbmeth_putmp(PyObject *me, PyObject *arg)
 {
   mp *x = 0;
   if (!PyArg_ParseTuple(arg, "O&:putmp", convmp, &x)) return (0);
-  ensure(me, mp_octets(x) + 2);
+  if (ensurebuf(me, mp_octets(x) + 2)) return (0);
   buf_putmp(BUF_B(me), x); assert(BOK(BUF_B(me)));
   RETURN_ME;
 }
@@ -432,7 +444,7 @@ static PyObject *wbmeth_putgf(PyObject *me, PyObject *arg)
 {
   mp *x = 0;
   if (!PyArg_ParseTuple(arg, "O&:putgf", convgf, &x)) return (0);
-  ensure(me, mp_octets(x) + 2);
+  if (ensurebuf(me, mp_octets(x) + 2)) return (0);
   buf_putmp(BUF_B(me), x); assert(BOK(BUF_B(me)));
   MP_DROP(x);
   RETURN_ME;
@@ -442,7 +454,9 @@ static PyObject *wbmeth_putecpt(PyObject *me, PyObject *arg)
 {
   ec pt = EC_INIT;
   if (!PyArg_ParseTuple(arg, "O&:putecpt", convecpt, &pt)) return (0);
-  ensure(me, EC_ATINF(&pt) ? 2 : 6 + mp_octets(pt.x) + mp_octets(pt.y));
+  if (ensurebuf(me, EC_ATINF(&pt) ? 2 :
+               6 + mp_octets(pt.x) + mp_octets(pt.y)))
+    return (0);
   buf_putec(BUF_B(me), &pt); assert(BOK(BUF_B(me)));
   EC_DESTROY(&pt);
   RETURN_ME;
@@ -455,7 +469,7 @@ static PyObject *wbmeth_putecptraw(PyObject *me, PyObject *arg)
   if (!PyArg_ParseTuple(arg, "O!:putecptraw", ecptcurve_pytype, &ptobj))
     return (0);
   EC_OUT(ECPT_C(ptobj), &pt, ECPT_P(ptobj));
-  ensure(me, ECPT_C(ptobj)->f->noctets * 2 + 1);
+  if (ensurebuf(me, ECPT_C(ptobj)->f->noctets * 2 + 1)) return (0);
   ec_putraw(ECPT_C(ptobj), BUF_B(me), &pt); assert(BOK(BUF_B(me)));
   EC_DESTROY(&pt);
   RETURN_ME;
@@ -465,7 +479,7 @@ static PyObject *wbmeth_putge(PyObject *me, PyObject *arg)
 {
   PyObject *geobj;
   if (!PyArg_ParseTuple(arg, "O!:putge", ge_pytype, &geobj)) return (0);
-  ensure(me, GE_G(geobj)->noctets);
+  if (ensurebuf(me, GE_G(geobj)->noctets)) return (0);
   G_TOBUF(GE_G(geobj), BUF_B(me), GE_X(geobj)); assert(BOK(BUF_B(me)));
   RETURN_ME;
 }
@@ -474,7 +488,7 @@ static PyObject *wbmeth_putgeraw(PyObject *me, PyObject *arg)
 {
   PyObject *geobj;
   if (!PyArg_ParseTuple(arg, "O!:putgeraw", ge_pytype, &geobj)) return (0);
-  ensure(me, GE_G(geobj)->noctets);
+  if (ensurebuf(me, GE_G(geobj)->noctets)) return (0);
   G_TORAW(GE_G(geobj), BUF_B(me), GE_X(geobj)); assert(BOK(BUF_B(me)));
   RETURN_ME;
 }
@@ -514,10 +528,15 @@ static const PyMethodDef wbuf_pymethods[] = {
 };
 
 static const PyBufferProcs wbuf_pybuffer = {
+#ifdef PY3
+  wbuf_pygetbuf,                       /* @bf_getbuffer@ */
+  wbuf_pyrlsbuf                                /* @bf_releasebuffer@ */
+#else
   wbuf_pyreadbuf,                      /* @bf_getreadbuffer@ */
   0,                                   /* @bf_getwritebuffer@ */
   wbuf_pysegcount,                     /* @bf_getsegcount@ */
   0                                    /* @bf_getcharbuffer@ */
+#endif
 };
 
 static const PyTypeObject wbuf_pytype_skel = {
@@ -570,6 +589,8 @@ static const PyTypeObject wbuf_pytype_skel = {
 
 /*----- Initialization ----------------------------------------------------*/
 
+PyObject *buferr;
+
 void buffer_pyinit(void)
 {
   INITTYPE(rbuf, root);