X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=chiark-tcl.git;a=blobdiff_plain;f=hbytes%2Fhbytes.c;h=5daecd1c5038437357fb896f1bd9d4e4b9044005;hp=d4a33f5082c056a1df90a0464e7323c5138cb1cf;hb=5dca360f2da544c9b6baf9d18ad8cd0b0e073e60;hpb=bdab939bce799bf55ccd401543f5f13a3203b047 diff --git a/hbytes/hbytes.c b/hbytes/hbytes.c index d4a33f5..5daecd1 100644 --- a/hbytes/hbytes.c +++ b/hbytes/hbytes.c @@ -1,223 +1,174 @@ /* + * hbytes - hex-stringrep efficient byteblocks for Tcl + * Copyright 2006 Ian Jackson * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301, USA. */ + #include "hbytes.h" -int staticerr(Tcl_Interp *ip, const char *m) { - Tcl_SetResult(ip, (char*)m, TCL_STATIC); - return TCL_ERROR; +#define COMPLEX(hb) ((HBytes_ComplexValue*)hb->begin_complex) +#define SIMPLE_LEN(hb) ((Byte*)(hb)->end_0 - (Byte*)(hb)->begin_complex) + +/* enquirers */ + +int cht_hb_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 *cht_hb_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 cht_hb_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 cht_hb_empty(HBytes_Value *returns) { + returns->begin_complex= returns->end_0= 0; } -static void hbytes_t_free(Tcl_Obj *o) { - TFREE(HBYTES(o)->start); +void cht_hb_sentinel(HBytes_Value *returns) { + returns->begin_complex= 0; + returns->end_0= (void*)&cht_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 *cht_hb_arrayspace(HBytes_Value *returns, int l) { + if (!l) { cht_hb_empty(returns); return 0; } + returns->begin_complex= TALLOC(l); + returns->end_0= returns->begin_complex + l; + return returns->begin_complex; +} + +void cht_hb_array(HBytes_Value *returns, const Byte *array, int l) { + memcpy(cht_hb_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 cht_hb_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 *cht_hb_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 *cht_hb_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*)&cht_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 *cht_hb_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; +} + +const Byte *cht_hb_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; } -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; +void memxor(Byte *dest, const Byte *src, int l) { + while (l--) *dest++ ^= *src++; }