chiark / gitweb /
Debian package wip
[chiark-tcl.git] / hbytes / hbytes.c
index d4a33f5082c056a1df90a0464e7323c5138cb1cf..5daecd1c5038437357fb896f1bd9d4e4b9044005 100644 (file)
 /*
+ * 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++;
 }