+void *ptrfromsvdflt(SV *sv, const char *type, void *dflt, const char *what)
+{
+ if (!SvOK(sv))
+ return (dflt);
+ else
+ return (ptrfromsv(sv, type, "%s", what));
+}
+
+/*----- Cursor reading stuff ----------------------------------------------*/
+
+void c_init(cursor *c, SV *sv)
+{
+ if (!SvROK(sv))
+ croak("not a reference");
+ sv = SvRV(sv);
+ switch (SvTYPE(sv)) {
+ case SVt_PVAV:
+ c->f = CF_ARRAY;
+ c->u.a.av = (AV *)sv;
+ c->u.a.i = 0;
+ break;
+ case SVt_PVHV:
+ c->f = CF_HASH;
+ c->u.hv = (HV *)sv;
+ break;
+ default:
+ croak("must be hash ref or array ref");
+ }
+}
+
+void c_skip(cursor *c)
+{
+ if (!(c->f & CF_HASH))
+ c->u.a.i++;
+}
+
+SV *c_get(cursor *c, const char *tag, unsigned f)
+{
+ SV **sv;
+
+ if (c->f & CF_HASH)
+ sv = hv_fetch(c->u.hv, tag, strlen(tag), 0);
+ else {
+ sv = av_fetch(c->u.a.av, c->u.a.i, 0);
+ if (sv) c->u.a.i++;
+ }
+ if ((f & CF_MUST) && !sv)
+ croak("missing entry `%s'", tag);
+ return (sv ? *sv : &PL_sv_undef);
+}
+
+void hvput(HV *hv, const char *k, SV *val)
+{
+ SV **sv = hv_fetch(hv, k, strlen(k), 1);
+ if (!sv)
+ croak("couldn't set hash key %s", k);
+ *sv = val;
+}
+
+/*----- Wrapped objects ---------------------------------------------------*/
+
+static SV *firstelt(SV *sv, const char *what)
+{
+ AV *av;
+ SV **svp;
+
+ if (!SvROK(sv))
+ croak("%s is not a reference", what);
+ sv = SvRV(sv);
+ if (SvTYPE(sv) != SVt_PVAV)
+ croak("%s is not an array reference", what);
+ av = (AV *)sv;
+ svp = av_fetch(av, 0, 0);
+ if (!svp)
+ croak("%s is empty", what);
+ return (*svp);
+}
+
+ge *groupelt(SV *sv, const char *what)
+{
+ if (sv_derived_from(sv, "Catacomb::Group::Elt"))
+ sv = firstelt(sv, what);
+ return (ptrfromsv(sv, "Catacomb::Group::Element", what));
+}
+
+mp *fieldelt(SV *sv, const char *what)
+{
+ if (sv_derived_from(sv, "Catacomb::Field::Elt"))
+ sv = firstelt(sv, what);
+ return (mp_fromsv(sv, what, 0, 0));
+}
+
+ec *ecpt(SV *sv, const char *what)
+{
+ if (sv_derived_from(sv, "Catacomb::EC::Pt"))
+ sv = firstelt(sv, what);
+ return (ptrfromsv(sv, "Catacomb::EC::Point", what));
+}
+
+/*----- DSA contexts ------------------------------------------------------*/
+
+void gdsa_privfromsv(gdsa *g, SV *sv)
+{
+ cursor c;
+
+ c_init(&c, sv);
+ g->g = C_PTR(&c, "G", "Catacomb::Group");
+ g->p = C_GE(&c, "p");
+ g->u = C_MP(&c, "u");
+ g->h = C_PTR(&c, "h", "Catacomb::HashClass");
+ g->r = C_PTRDFLT(&c, "rng", "Catacomb::Rand", &rand_global);
+}
+
+void gdsa_pubfromsv(gdsa *g, SV *sv)
+{
+ cursor c;
+
+ c_init(&c, sv);
+ g->g = C_PTR(&c, "G", "Catacomb::Group");
+ g->p = C_GE(&c, "p");
+ c_skip(&c);
+ g->h = C_PTR(&c, "h", "Catacomb::HashClass");
+ g->r = C_PTRDFLT(&c, "rng", "Catacomb::Rand", &rand_global);
+}
+
+/*----- RSA padding contexts ----------------------------------------------*/
+
+void pkcs1_fromsv(pkcs1 *p, SV *sv)
+{
+ cursor c;
+ STRLEN len;
+ SV *t;
+
+ c_init(&c, sv);
+ t = c_get(&c, "ep", 0);
+ if (SvOK(t)) {
+ p->ep = SvPV(t, len);
+ p->epsz = len;
+ } else {
+ p->ep = 0;
+ p->epsz = 0;
+ }
+ p->r = C_PTRDFLT(&c, "rng", "Catacomb::Rand", &rand_global);
+}
+
+void oaep_fromsv(oaep *p, SV *sv)
+{
+ cursor c;
+ STRLEN len;
+ SV *t;
+
+ c_init(&c, sv);
+ p->cc = C_PTR(&c, "c", "Catacomb::CipherClass");
+ p->ch = C_PTR(&c, "h", "Catacomb::HashClass");
+ t = c_get(&c, "ep", 0);
+ if (SvOK(t)) {
+ p->ep = SvPV(t, len);
+ p->epsz = len;
+ } else {
+ p->ep = 0;
+ p->epsz = 0;
+ }
+ p->r = C_PTRDFLT(&c, "rng", "Catacomb::Rand", &rand_global);
+}
+
+void pss_fromsv(pss *p, SV *sv)
+{
+ cursor c;
+ STRLEN len;
+ SV *t;
+
+ c_init(&c, sv);
+ p->cc = C_PTR(&c, "c", "Catacomb::CipherClass");
+ p->ch = C_PTR(&c, "h", "Catacomb::HashClass");
+ t = c_get(&c, "ssz", 0);
+ p->ssz = SvOK(t) ? SvUV(t) : p->ch->hashsz;
+ p->r = C_PTRDFLT(&c, "rng", "Catacomb::Rand", &rand_global);
+}
+