*
*/
+#include <string.h>
+
#include "hbytes.h"
+#include "tables.h"
+
+#define COMPLEX(hb) ((HBytes_ComplexValue*)hb->begin_complex)
+#define SIMPLE_LEN(hb) ((Byte*)(hb)->end_0 - (Byte*)(hb)->begin_complex)
+
+/* enquirers */
-int staticerr(Tcl_Interp *ip, const char *m) {
- Tcl_SetResult(ip, (char*)m, TCL_STATIC);
- return TCL_ERROR;
+int hbytes_len(const HBytes_Value *hb) {
+ if (HBYTES_ISEMPTY(hb)) return 0;
+ else if (HBYTES_ISCOMPLEX(hb)) return COMPLEX(hb)->len;
+ else return SIMPLE_LEN(hb);
}
-static void hbytes_setintern(Tcl_Obj *o, const Byte *array, int l) {
- Byte *np;
-
- HBYTES(o)->start= np= l ? TALLOC(l) : 0;
- memcpy(np, array, l);
- HBYTES(o)->end= np + l;
- o->typePtr = &hbytes_type;
+Byte *hbytes_data(const HBytes_Value *hb) {
+ if (HBYTES_ISEMPTY(hb)) return 0;
+ else if (HBYTES_ISCOMPLEX(hb)) return COMPLEX(hb)->dstart;
+ else return hb->begin_complex;
}
-static void hbytes_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
- hbytes_setintern(src, HBYTES(src)->start, HBYTES_LEN(src));
+int hbytes_issentinel(const HBytes_Value *hb) {
+ return HBYTES_ISSENTINEL(hb);
}
-Tcl_Obj *hbytes_set(Tcl_Obj *overwrite, const Byte *array, int l) {
- if (!overwrite) overwrite= Tcl_NewObj();
- objfreeir(overwrite);
- Tcl_InvalidateStringRep(overwrite);
- hbytes_setintern(overwrite, array, l);
- return overwrite;
+/* constructors */
+
+void hbytes_empty(HBytes_Value *returns) {
+ returns->begin_complex= returns->end_0= 0;
}
-static void hbytes_t_free(Tcl_Obj *o) {
- TFREE(HBYTES(o)->start);
+void hbytes_sentinel(HBytes_Value *returns) {
+ returns->begin_complex= 0;
+ returns->end_0= (void*)&hbytes_type;
}
-static void hbytes_t_ustr(Tcl_Obj *o) {
- int l;
- char *str;
- const Byte *byte;
-
- l= HBYTES_LEN(o);
- byte= HBYTES(o)->start;
- str= o->bytes= TALLOC(l*2+1);
- o->length= l*2;
- while (l>0) {
- sprintf(str,"%02x",*byte);
- str+=2; byte++; l--;
- }
+Byte *hbytes_arrayspace(HBytes_Value *returns, int l) {
+ if (!l) { hbytes_empty(returns); return 0; }
+ returns->begin_complex= TALLOC(l);
+ returns->end_0= returns->begin_complex + l;
+ return returns->begin_complex;
+}
+
+void hbytes_array(HBytes_Value *returns, const Byte *array, int l) {
+ memcpy(hbytes_arrayspace(returns,l), array, l);
}
-void objfreeir(Tcl_Obj *o) {
- if (o->typePtr && o->typePtr->freeIntRepProc)
- o->typePtr->freeIntRepProc(o);
-}
-
-static int hbytes_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
- char *str, *ep, *os;
- Byte *startbytes, *bytes;
- int l;
- char cbuf[3];
-
- os= str= Tcl_GetStringFromObj(o,&l); assert(str);
- if (l & 1) return staticerr(ip, "hbytes: conversion from hex:"
- " odd length in hex");
-
- startbytes= bytes= l ? TALLOC(l*2) : 0;
- cbuf[2]= 0;
- while (l>0) {
- cbuf[0]= *str++;
- cbuf[1]= *str++;
- *bytes++= strtoul(cbuf,&ep,16);
- if (ep != cbuf+2) {
- TFREE(startbytes);
-fprintf(stderr,">%d|%s|%s<\n",l,os,cbuf);
- return staticerr(ip, "hbytes: conversion from hex:"
- " bad hex digit");
- }
- l -= 2;
- }
- objfreeir(o);
+/* destructor */
- HBYTES(o)->start= startbytes;
- HBYTES(o)->end= bytes;
- o->typePtr = &hbytes_type;
- return TCL_OK;
+void hbytes_free(const HBytes_Value *frees) {
+ if (HBYTES_ISCOMPLEX(frees)) {
+ HBytes_ComplexValue *cx= COMPLEX(frees);
+ TFREE(cx->dstart - cx->prespace);
+ }
+ TFREE(frees->begin_complex);
}
-Tcl_ObjType hbytes_type = {
- "hbytes",
- hbytes_t_free, hbytes_t_dup, hbytes_t_ustr, hbytes_t_sfa
-};
+/* mutators */
-static Tcl_Obj *hb_getvar(Tcl_Interp *ip, Tcl_Obj *varname) {
- int ec;
- Tcl_Obj *value;
-
- value= Tcl_ObjGetVar2(ip,varname,0,TCL_LEAVE_ERR_MSG);
- if (!value) return 0;
+static HBytes_ComplexValue *complex(HBytes_Value *hb) {
+ HBytes_ComplexValue *cx;
- ec= Tcl_ConvertToType(ip,value,&hbytes_type);
- if (ec) return 0;
+ if (HBYTES_ISCOMPLEX(hb)) return hb->begin_complex;
- return value;
-}
+ cx= TALLOC(sizeof(*cx));
+ cx->dstart= hb->begin_complex;
+ cx->len= cx->avail= SIMPLE_LEN(hb);
+ cx->prespace= 0;
-HC_DEFINE(raw2h) {
- HC_DECLS;
- Tcl_Obj *raw, *value;
- const char *str;
- int l;
-
- HC_ARG_O(raw);
- HC_ARGS_E;
- str= Tcl_GetStringFromObj(raw,&l);
- value= hbytes_set(0,str,l);
- Tcl_SetObjResult(ip,value);
- HC_FINI;
+ hb->begin_complex= cx;
+ hb->end_0= 0;
+
+ return cx;
}
-HC_DEFINE(h2raw) {
- Tcl_Obj *value, *result;
+Byte *hbytes_prepend(HBytes_Value *hb, int el) {
+ HBytes_ComplexValue *cx;
+ int new_prespace;
+ Byte *old_block, *new_block, *new_dstart;
+
+ cx= complex(hb);
- HC_ARG_H(value);
- HC_ARGS_E;
- result= Tcl_NewStringObj(HBYTES(value)->start, HBYTES_LEN(value));
- Tcl_SetObjResult(ip,result);
- HC_FINI;
+ if (cx->prespace < el) {
+ new_prespace= el*2 + cx->len;
+ old_block= cx->dstart - cx->prespace;
+ new_block= Tcl_Realloc(old_block, new_prespace + cx->avail);
+ new_dstart= new_block + new_prespace;
+ memmove(new_dstart, new_block + cx->prespace, cx->len);
+ cx->prespace= new_prespace;
+ cx->dstart= new_dstart;
+ }
+ cx->dstart -= el;
+ cx->prespace -= el;
+ cx->len += el;
+ cx->avail += el;
+ return cx->dstart;
}
-HC_DEFINE(pkcs5) {
- typedef struct {
- const char *spec;
- int pad, algname;
- } PadKindInfo;
- static const PadKindInfo padkindinfos[0]= {
- { "pa", 1, 1 },
- { "pn", 1, 0 },
- { "ua", 0, 1 },
- { "un", 0, 0 },
- { 0 }
- };
-
- HC_DECLS_HBV;
- Tcl_Obj *v;
- int blocksize;
- const PadKindInfo *pk;
- const BlockCipherInfo *bc;
-
- HC_ARG_ENUM(pk, padkindinfos);
- HC_ARG_HBV;
- if (!pk->algname) HC_ARG_INTRANGE(blocksize, 1,255);
- else { HC_ARG_ENUM(bc, blockciphers); blocksize= bc->blocksize; }
- HC_ARGS_E;
-
- /* do nothing :-) */
-
- HC_FINI_HBV;
+Byte *hbytes_append(HBytes_Value *hb, int el) {
+ HBytes_ComplexValue *cx;
+ int new_len, new_avail;
+ Byte *newpart, *new_block, *old_block;
+
+ cx= complex(hb);
+
+ new_len= cx->len + el;
+ if (new_len > cx->avail) {
+ new_avail= new_len*2;
+ old_block= cx->dstart - cx->prespace;
+ new_block= Tcl_Realloc(old_block, cx->prespace + new_avail);
+ cx->dstart= new_block + cx->prespace;
+ cx->avail= new_avail;
+ }
+ newpart= cx->dstart + cx->len;
+ cx->len= new_len;
+ return newpart;
}
+
+static HBytes_ComplexValue*
+prechop(HBytes_Value *hb, int cl, const Byte **rv) {
+ HBytes_ComplexValue *cx;
+
+ if (cl<0) { *rv=0; return 0; }
+ if (cl==0) { *rv= (const void*)&hbytes_type; return 0; }
-static int hc_raw2h(ClientData cd, Tcl_Interp *ip, int objc,
- Tcl_Obj *const *objv) {
-
- Tcl_Obj *varname, *value, *result;
-
- varname= objv[0];
- switch (objc) {
- case 1:
- value= hb_getvar(ip,varname); if (!value) return TCL_ERROR;
- assert(result);
- Tcl_SetObjResult(ip,result);
- return TCL_OK;
- case 2:
- value= objv[1];
- HC_MINARGS(1);
-
- value= Tcl_ObjSetVar2(ip,varname,0, value, TCL_LEAVE_ERR_MSG);
- if (!value) return TCL_ERROR;
- Tcl_ResetResult(ip);
- return TCL_OK;
- }
- abort();
+ cx= complex(hb);
+ if (cl > cx->len) { *rv=0; return 0; }
+ return cx;
}
-typedef struct {
- const char *name;
- int minargs, maxargs;
- Tcl_ObjCmdProc *func;
-} SubCommand;
-
-#define SUBCOMMANDS \
- DO(raw2h) \
- DO(h2raw) \
- DO(pkcs5)
-
-static const SubCommand subcommands[] = {
-#define DO(c) { #c, hc_##c },
- SUBCOMMANDS
- { 0 }
-};
-
-static int hb_proc(ClientData cd, Tcl_Interp *ip, int objc,
- Tcl_Obj *const *objv) {
- const SubCommand *sc;
-
- if (objc<2) return staticerr(ip, "hbytes: need subcommand");
- sc= enum_lookup_cached(ip,objv[1],subcommands,"hbytes subcommand");
- if (!sc) return TCL_ERROR;
- objc -= 2;
- objv += 2;
- if (objc < sc->minargs)
- return staticerr(ip, "too few args");
- if (sc->maxargs >=0 && objc > sc->maxargs)
- return staticerr(ip,"too many args");
- return sc->func((void*)sc,ip,objc,objv);
+const Byte *hbytes_unprepend(HBytes_Value *hb, int pl) {
+ const Byte *chopped;
+ HBytes_ComplexValue *cx= prechop(hb,pl,&chopped);
+ if (!cx) return chopped;
+
+ chopped= cx->dstart;
+ cx->dstart += pl;
+ cx->prespace += pl;
+ cx->len -= pl;
+ cx->avail -= pl;
+ return chopped;
}
-int Hbytes_Init(Tcl_Interp *ip) {
- Tcl_RegisterObjType(&hbytes_type);
- Tcl_RegisterObjType(&enum_nearlytype);
- Tcl_CreateObjCommand(ip,"hbytes", hb_proc,0,0);
- return TCL_OK;
+const Byte *hbytes_unappend(HBytes_Value *hb, int sl) {
+ const Byte *chopped;
+ HBytes_ComplexValue *cx= prechop(hb,sl,&chopped);
+ if (!cx) return chopped;
+
+ cx->len -= sl;
+ return cx->dstart + cx->len;
}