X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=chiark-tcl.git;a=blobdiff_plain;f=hbytes%2Fhbytes.c;h=f9c02a75f8e7279def7743010f27720017eb282f;hp=626b2da6cdd497dfbece6a6ef8cc8d51f183ed5a;hb=ca8b96bf81245f21fe3906c71dc2994bfc5e516f;hpb=b740135c3efcb63e0c7741384e5fa8ff229d2919 diff --git a/hbytes/hbytes.c b/hbytes/hbytes.c index 626b2da..f9c02a7 100644 --- a/hbytes/hbytes.c +++ b/hbytes/hbytes.c @@ -1,155 +1,177 @@ /* + * hbytes - hex-stringrep efficient byteblocks for Tcl + * Copyright 2006-2012 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" -#include "tables.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) -void hbytes_set(HBytes_Value *upd, const Byte *array, int l) { - Byte *np; +/* enquirers */ - upd->start= np= l ? TALLOC(l) : 0; - memcpy(np, array, l); - upd->end= np + l; +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) { - hbytes_set(&HBYTES(o), array, 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(HBYTES(src))); +int cht_hb_issentinel(const HBytes_Value *hb) { + return HBYTES_ISSENTINEL(hb); } -Tcl_Obj *hbytes_set_obj(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(HBYTES(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 HBytes_ComplexValue *complex(HBytes_Value *hb) { + HBytes_ComplexValue *cx; -int do_hbytes_raw2h(ClientData cd, Tcl_Interp *ip, - Tcl_Obj *binary, HBytes_Value *result) { - const char *str; - int l; + if (HBYTES_ISCOMPLEX(hb)) return hb->begin_complex; - str= Tcl_GetStringFromObj(binary,&l); - hbytes_set(result, str, l); - return TCL_OK; + cx= TALLOC(sizeof(*cx)); + cx->dstart= hb->begin_complex; + cx->len= cx->avail= SIMPLE_LEN(hb); + cx->prespace= 0; + + hb->begin_complex= cx; + hb->end_0= 0; + + return cx; +} + +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); + + assert(el < INT_MAX/4 && cx->len < INT_MAX/2); + + 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; } -int do_hbytes_h2raw(ClientData cd, Tcl_Interp *ip, - HBytes_Value hex, Tcl_Obj **result) { - *result= Tcl_NewStringObj(hex.start, HBYTES_LEN(hex)); - return TCL_OK; +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); + assert(el < INT_MAX/4 && cx->len < INT_MAX/4); + + 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; } -#if 0 -HC_DEFINE(pkcs5) { - 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; +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; } + + cx= complex(hb); + if (cl > cx->len) { *rv=0; return 0; } + return cx; } -#endif -int do__hbytes(ClientData cd, Tcl_Interp *ip, - const HBytes_SubCommand *subcmd, - int objc, Tcl_Obj *const *objv) { - return subcmd->func(0,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_RegisterObjType(&enum1_nearlytype); - Tcl_CreateObjCommand(ip,"hbytes", pa__hbytes,0,0); - return TCL_OK; +void memxor(Byte *dest, const Byte *src, int l) { + while (l--) *dest++ ^= *src++; }