chiark / gitweb /
algorithms.c: Add bindings for STROBE.
[catacomb-python] / buffer.c
index f615858594faa74f004df7f7445ecef33ccbcbb3..d0df068b9a87aff37a349a9f23db0e6aac7cb691 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)
 {
   struct bin in;
@@ -62,7 +44,7 @@ static PyObject *rbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
   q = xmalloc(in.sz);
   memcpy(q, in.p, in.sz);
   me = (buf_pyobj *)ty->tp_alloc(ty, 0);
-  me->sub = 0;
+  me->sub = 0; me->lk = 0;
   buf_init(&me->b, q, in.sz);
 end:
   return ((PyObject *)me);
@@ -70,18 +52,24 @@ end:
 
 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:                                                                 \
@@ -186,12 +175,29 @@ static PyObject *rbmeth_getecptraw(PyObject *me, PyObject *arg)
 {
   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_os2ecp(PyObject *me, PyObject *arg, PyObject *kw)
+{
+  PyObject *cobj;
+  ec pt = EC_INIT;
+  unsigned f = EC_XONLY | EC_LSB | EC_SORT | EC_EXPLY;
+  PyObject *rc = 0;
+  static const char *const kwlist[] = { "curve", "flags", 0 };
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!|O&:os2ecp", KWLIST,
+                                  eccurve_pytype, &cobj, convuint, &f))
+    goto end;
+  if (ec_os2ecp(ECCURVE_C(cobj), f, BUF_B(me), &pt)) VALERR("bad point");
+  rc = ecpt_pywrapout(cobj, &pt);
+end:
+  return (rc);
 }
 
 static PyObject *rbmeth_getge(PyObject *me, PyObject *arg)
@@ -267,6 +273,7 @@ static const PyMethodDef rbuf_pymethods[] = {
   NAMETH(getgf,                "RBUF.getgf() -> X")
   KWMETH(getecpt,      "RBUF.getecpt([curve = None]) -> P")
   METH (getecptraw,    "RBUF.getecptraw(CURVE) -> P")
+  KWMETH(os2ecp,       "RBUF.os2ecp(CURVE, [flags = ...]) -> P")
   METH (getge,         "RBUF.getge(GROUP) -> X")
   METH (getgeraw,      "RBUF.getgeraw(GROUP) -> X")
 #undef METHNAME
@@ -274,10 +281,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 +342,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 +379,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;
@@ -385,7 +416,7 @@ static PyObject *wbmeth_put(PyObject *me, PyObject *arg)
 {
   struct bin in;
   if (!PyArg_ParseTuple(arg, "O&:put", convbin, &in)) return (0);
-  ensure(me, in.sz);
+  if (ensurebuf(me, in.sz)) return (0);
   buf_put(BUF_B(me), in.p, in.sz); assert(BOK(BUF_B(me)));
   RETURN_ME;
 }
@@ -395,7 +426,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;                                                         \
   }
@@ -409,7 +440,7 @@ DOUINTCONV(WBMETH_PUTU_)
     struct bin in;                                                     \
     if (!PyArg_ParseTuple(arg, "O&:putblk" #w, convbin, &in)) goto end;        \
     if (MASK##W && in.sz > MASK##W) VALERR("too large");               \
-    ensure(me, in.sz + SZ_##n);                                                \
+    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:                                                                 \
@@ -421,7 +452,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;
 }
@@ -430,7 +461,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;
@@ -440,7 +471,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;
@@ -449,21 +482,42 @@ static PyObject *wbmeth_putecpt(PyObject *me, PyObject *arg)
 static PyObject *wbmeth_putecptraw(PyObject *me, PyObject *arg)
 {
   PyObject *ptobj;
+  ec_curve *cc;
   ec pt = EC_INIT;
   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);
-  ec_putraw(ECPT_C(ptobj), BUF_B(me), &pt); assert(BOK(BUF_B(me)));
+  cc = ECPT_C(ptobj);
+  EC_OUT(cc, &pt, ECPT_P(ptobj));
+  if (ensurebuf(me, 2*cc->f->noctets + 1)) return (0);
+  ec_putraw(cc, BUF_B(me), &pt); assert(BOK(BUF_B(me)));
   EC_DESTROY(&pt);
   RETURN_ME;
 }
 
+static PyObject *wbmeth_ec2osp(PyObject *me, PyObject *arg, PyObject *kw)
+{
+  PyTypeObject *ptobj;
+  ec_curve *cc;
+  ec pt = EC_INIT;
+  unsigned f = EC_EXPLY;
+  static const char *const kwlist[] = { "point", "flags", 0 };
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!|O&:os2ecp", KWLIST,
+                                  ecptcurve_pytype, &ptobj, convuint, &f))
+    goto end;
+  cc = ECPT_C(ptobj);
+  EC_OUT(cc, &pt, ECPT_P(ptobj));
+  if (ensurebuf(me, 2*cc->f->noctets + 1)) return (0);
+  if (ec_ec2osp(cc, f, BUF_B(me), &pt)) VALERR("invalid flags");
+  RETURN_ME;
+end:
+  return (0);
+}
+
 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;
 }
@@ -472,7 +526,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;
 }
@@ -505,6 +559,7 @@ static const PyMethodDef wbuf_pymethods[] = {
   METH (putgf,         "WBUF.putgf(X)")
   METH (putecpt,       "WBUF.putecpt(P)")
   METH (putecptraw,    "WBUF.putecptraw(P)")
+  KWMETH(ec2osp,       "WBUF.ec2osp(P, [flags = EC_EXPLY])")
   METH (putge,         "WBUF.putge(X)")
   METH (putgeraw,      "WBUF.putgeraw(X)")
 #undef METHNAME
@@ -512,10 +567,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 = {
@@ -568,6 +628,8 @@ static const PyTypeObject wbuf_pytype_skel = {
 
 /*----- Initialization ----------------------------------------------------*/
 
+PyObject *buferr;
+
 void buffer_pyinit(void)
 {
   INITTYPE(rbuf, root);