/* from hbytes.c */
+/* Internal representation details: */
+#define HBYTES_ISEMPTY(hb) (!(hb)->begin_complex && !(hb)->end_0)
+#define HBYTES_ISSENTINEL(hb) (!(hb)->begin_complex && (hb)->end_0)
+#define HBYTES_ISSIMPLE(hb) ((hb)->begin_complex && (hb)->end_0)
+#define HBYTES_ISCOMPLEX(hb) ((hb)->begin_complex && !(hb)->end_0)
+
typedef struct {
- Byte *start, *end; /* always allocated dynamically */
+ void *begin_complex, *end_0;
} HBytes_Value; /* overlays internalRep */
+typedef struct {
+ Byte *dstart; /* always allocated dynamically */
+ int prespace, len, avail;
+ /*
+ * | SPARE | USED | SPARE |
+ * |<-prespace->|<-len->| |
+ * | |<----avail---->|
+ * ^start
+ */
+} HBytes_ComplexValue; /* pointed to from internalRep.otherValuePtr */
+
+/* Public interfaces: */
+
extern Tcl_ObjType hbytes_type;
+int hbytes_len(const HBytes_Value *v);
+Byte *hbytes_data(const HBytes_Value *v); /* caller may then modify data! */
+int hbytes_issentinel(const HBytes_Value *v);
+
+Byte *hbytes_prepend(HBytes_Value *upd, int el);
+Byte *hbytes_append(HBytes_Value *upd, int el);
+ /* return value is where to put the data */
+
+const Byte *hbytes_unprepend(HBytes_Value *upd, int rl);
+const Byte *hbytes_unappend(HBytes_Value *upd, int rl);
+ /* return value points to the removed data, which remains valid
+ * until next op on the HBytes_Value. If original value is
+ * shorter than rl or negative, returns 0 and does nothing. */
+
+void hbytes_empty(HBytes_Value *returns);
+void hbytes_sentinel(HBytes_Value *returns);
+void hbytes_array(HBytes_Value *returns, const Byte *array, int l);
+Byte *hbytes_arrayspace(HBytes_Value *returns, int l);
+void hbytes_free(HBytes_Value *frees);
+ /* _empty, _sentinel and _array do not free or read the old value;
+ * _free it first if needed. _free leaves it garbage, so you
+ * have to call _empty to reuse it. _arrayspace doesn't fill
+ * the array; you get a pointer and must fill it with data
+ * yourself. */
+
+/* The value made by hbytes_sentinel should not be passed to
+ * anything except HBYTES_IS..., and hbytes_free. */
+
+/* from hook.c */
+
int staticerr(Tcl_Interp *ip, const char *m);
void objfreeir(Tcl_Obj *o);
-void hbytes_set(HBytes_Value *upd, const Byte *array, int l);
-Tcl_Obj *hbytes_set_obj(Tcl_Obj *overwrite, const Byte *array, int l);
-
/* from parse.c */
typedef struct {
void fini_hbv(Tcl_Interp *ip, int rc, HBytes_Var *agg);
+/* from chop.c */
+
/* from enum.c */
extern Tcl_ObjType enum_nearlytype;
/* useful macros */
-#define HBYTES(o) (*(HBytes_Value*)&(o)->internalRep.twoPtrValue)
-#define HBYTES_LEN(hb) ((hb).end - (hb).start)
+#define OBJ_HBYTES(o) ((HBytes_Value*)&(o)->internalRep.twoPtrValue)
#define TALLOC(s) ((void*)Tcl_Alloc((s)))
#define TFREE(f) (Tcl_Free((void*)(f)))
--- /dev/null
+/*
+ */
+
+#include "hbytes.h"
+#include "tables.h"
+
+int staticerr(Tcl_Interp *ip, const char *m) {
+ Tcl_SetResult(ip, (char*)m, TCL_STATIC);
+ return TCL_ERROR;
+}
+
+void objfreeir(Tcl_Obj *o) {
+ if (o->typePtr && o->typePtr->freeIntRepProc)
+ o->typePtr->freeIntRepProc(o);
+ o->typePtr= 0;
+}
+
+int do_hbytes_rep_info(ClientData cd, Tcl_Interp *ip,
+ HBytes_Value v, Tcl_Obj **result) {
+ const char *tn;
+ int nums[3], i;
+ Tcl_Obj *objl[4];
+
+ memset(nums,0,sizeof(nums));
+ nums[1]= hbytes_len(&v);
+
+ if (HBYTES_ISEMPTY(&v)) tn= "empty";
+ else if (HBYTES_ISSENTINEL(&v)) tn= "sentinel!";
+ else if (HBYTES_ISSIMPLE(&v)) tn= "simple";
+ else {
+ HBytes_ComplexValue *cx= v.begin_complex;
+ tn= "complex";
+ nums[0]= cx->prespace;
+ nums[2]= cx->avail - cx->len;
+ }
+
+ objl[0]= Tcl_NewStringObj((char*)tn,-1);
+ for (i=0; i<3; i++) objl[i+1]= Tcl_NewIntObj(nums[i]);
+ *result= Tcl_NewListObj(4,objl);
+ return TCL_OK;
+}
+
+static void hbytes_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
+ objfreeir(dup);
+ hbytes_array(OBJ_HBYTES(dup),
+ hbytes_data(OBJ_HBYTES(src)),
+ hbytes_len(OBJ_HBYTES(src)));
+}
+
+static void hbytes_t_free(Tcl_Obj *o) {
+ hbytes_free(OBJ_HBYTES(o));
+}
+
+static void hbytes_t_ustr(Tcl_Obj *o) {
+ int l;
+ char *str;
+ const Byte *byte;
+
+ byte= hbytes_data(OBJ_HBYTES(o));
+ l= hbytes_len(OBJ_HBYTES(o));
+ str= o->bytes= TALLOC(l*2+1);
+ o->length= l*2;
+ while (l>0) {
+ sprintf(str,"%02x",*byte);
+ str+=2; byte++; l--;
+ }
+ *str= 0;
+}
+
+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);
+ objfreeir(o);
+
+ if (l & 1) return staticerr(ip, "hbytes: conversion from hex:"
+ " odd length in hex");
+
+ startbytes= bytes= hbytes_arrayspace(OBJ_HBYTES(o), l/2);
+
+ cbuf[2]= 0;
+ while (l>0) {
+ cbuf[0]= *str++;
+ cbuf[1]= *str++;
+ *bytes++= strtoul(cbuf,&ep,16);
+ if (ep != cbuf+2) {
+ hbytes_free(OBJ_HBYTES(o));
+ return staticerr(ip, "hbytes: conversion from hex:"
+ " bad hex digit");
+ }
+ l -= 2;
+ }
+
+ o->typePtr = &hbytes_type;
+ return TCL_OK;
+}
+
+Tcl_ObjType hbytes_type = {
+ "hbytes",
+ hbytes_t_free, hbytes_t_dup, hbytes_t_ustr, hbytes_t_sfa
+};
+
+int do_hbytes_raw2h(ClientData cd, Tcl_Interp *ip,
+ Tcl_Obj *binary, HBytes_Value *result) {
+ const char *str;
+ int l;
+
+ str= Tcl_GetStringFromObj(binary,&l);
+ hbytes_array(result, str, l);
+ return TCL_OK;
+}
+
+int do_hbytes_h2raw(ClientData cd, Tcl_Interp *ip,
+ HBytes_Value hex, Tcl_Obj **result) {
+ *result= Tcl_NewStringObj(hbytes_data(&hex), hbytes_len(&hex));
+ return TCL_OK;
+}
+
+#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;
+}
+#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);
+}
+
+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;
+}
rc= Tcl_ConvertToType(ip,val,&hbytes_type);
if (rc) return rc;
- agg->hb= &HBYTES(val);
+ agg->hb= OBJ_HBYTES(val);
return TCL_OK;
}
int pat_hb(Tcl_Interp *ip, Tcl_Obj *obj, HBytes_Value *val) {
int rc;
rc= Tcl_ConvertToType(ip,obj,&hbytes_type); if (rc) return rc;
- *val= HBYTES(obj);
+ *val= *OBJ_HBYTES(obj);
return TCL_OK;
}
Tcl_Obj *ret_hb(Tcl_Interp *ip, HBytes_Value val) {
- return hbytes_set_obj(0, val.start, HBYTES_LEN(val));
+ Tcl_Obj *obj;
+ obj= Tcl_NewObj();
+ Tcl_InvalidateStringRep(obj);
+ *OBJ_HBYTES(obj)= val;
+ obj->typePtr= &hbytes_type;
+ return obj;
}
Tcl_Obj *ret_obj(Tcl_Interp *ip, Tcl_Obj *val) {
Type hb: HBytes_Value @
-Init hb @.start=0; @.end=0;
+Init hb hbytes_sentinel(&@);
Type hbv: HBytes_Var @
Init hbv @.hb=0; @.obj=0; @.var=0;
Fini hbv fini_hbv(ip, rc, &@);
append
v hbv
str ...
+ rep-info
+ v hb
+ => obj
concat
str ...
=> hb
-# unprepend
-# v hbv
-# length int
-# => hb
-# unappend
-# v hbv
-# length int
-# => hb
-# chopto
-# v hbv
-# length int
-# => hb
+ unprepend
+ v hbv
+ length int
+ => hb
+ unappend
+ v hbv
+ length int
+ => hb
+ chopto
+ v hbv
+ length int
+ => hb
# pkcs5
# meth enum(PadMethod, "hbytes pad subcommand")
# obj ...
} elsif (@i>=1 && defined $c_entryextra) {
$entrytype_x{$c_entryextra} .= " $_\n";
} elsif (@i==1 && m/^[a-z].*$/ && defined $c_table) {
- if (m/^\w+$/) {
+ if (m/^[-_0-9A-Za-z]+$/) {
$c_entry= $_;
- } elsif (m/^(\w+)\s+(\S.*)$/) {
+ } elsif (m/^([-_0-9A-Za-z]+)\s+(\S.*)$/) {
$c_entry= $1;
$tables{$c_table}{$c_entry}{I} .= ", $2";
} else {
$x_table= $table_x{$c_table};
$op_tab= '';
- foreach $c_entry (keys %$r_table) {
+ foreach $c_entry (sort keys %$r_table) {
+ $c_entry_c= $c_entry; $c_entry_c =~ y/-/_/;
$r_entry= $r_table->{$c_entry};
- $pa_decl= "int pa_${c_table}_${c_entry}(ClientData cd,".
+ $pa_decl= "int pa_${c_table}_${c_entry_c}(ClientData cd,".
" Tcl_Interp *ip, int objc, Tcl_Obj *const *objv)";
- $do_decl= "int do_${c_table}_${c_entry}(";
+ $do_decl= "int do_${c_table}_${c_entry_c}(";
@do_al= ('ClientData cd', 'Tcl_Interp *ip');
@do_aa= qw(cd ip);
$pa_init= '';
$pa_rslt .= " Tcl_SetObjResult(ip, ret_$t(ip, result));\n";
}
$pa_body .= "\n";
- $pa_body .= " rc= do_${c_table}_${c_entry}(";
+ $pa_body .= " rc= do_${c_table}_${c_entry_c}(";
$pa_body .= join ', ', @do_aa;
$pa_body .= ");\n";
$pa_body .= " if (rc) goto rc_err;\n";
$op_tab .= sprintf(" { %-20s %-40s%s },\n",
"\"$c_entry\",",
- "pa_${c_table}_${c_entry}",
+ "pa_${c_table}_${c_entry_c}",
$r_entry->{I});
}
if (length $c_table) {
hbytes.o \
enum.o \
chop.o \
+ hook.o \
parse.o
HDRS= hbytes.h \
#include "hbytes.h"
-static int strs(Tcl_Interp *ip, int strc, Tcl_Obj *const *strv, int *l_r) {
+static int strs1(Tcl_Interp *ip, int strc, Tcl_Obj *const *strv, int *l_r) {
int rc, l, i;
l= 0;
for (i=1; i<strc; i++) {
rc= Tcl_ConvertToType(ip,strv[i],&hbytes_type);
if (rc) return rc;
- l += HBYTES_LEN(HBYTES(strv[i]));
-fprintf(stderr,"strs #%d %d %02x\n",i,l,
- HBYTES(strv[i]).start ? HBYTES(strv[i]).start[0] : 0xff);
+ l += hbytes_len(OBJ_HBYTES(strv[i]));
}
*l_r= l;
return TCL_OK;
}
-int app_pre(ClientData cd, Tcl_Interp *ip, int begin,
- HBytes_Var v, int strc, Tcl_Obj *const *strv) {
- int ol, rc, al, i, tl;
-
- rc= strs(ip,strc,strv,&al); if (rc) return rc;
-
- ol= HBYTES_LEN(*v.hb);
- v.hb->start= v.hb->end= Tcl_Realloc(v.hb->start, ol + al);
-
- if (begin) v.hb->end += ol;
- else memmove(v.hb->start + al, v.hb->start, ol);
+static void strs2(Byte *dest, int strc, Tcl_Obj *const *strv) {
+ int tl, i;
for (i=1; i<strc; i++) {
- tl= HBYTES_LEN(HBYTES(strv[i]));
- memcpy(v.hb->end, HBYTES(strv[i]).start, tl);
- v.hb->end += tl;
+ tl= hbytes_len(OBJ_HBYTES(strv[i]));
+ memcpy(dest, hbytes_data(OBJ_HBYTES(strv[i])), tl);
+ dest += tl;
}
- return TCL_OK;
-}
-
-int do_hbytes_append(ClientData cd, Tcl_Interp *ip,
- HBytes_Var v, int strc, Tcl_Obj *const *strv) {
- return app_pre(cd,ip,0,v,strc,strv);
}
-
+
int do_hbytes_prepend(ClientData cd, Tcl_Interp *ip,
HBytes_Var v, int strc, Tcl_Obj *const *strv) {
- return app_pre(cd,ip,1,v,strc,strv);
+ int rc, el;
+ Byte *dest;
+
+ rc= strs1(ip,strc,strv,&el); if (rc) return rc;
+ dest= hbytes_prepend(v.hb, el);
+ strs2(dest, strc,strv);
+ return TCL_OK;
+}
+
+int do_hbytes_append(ClientData cd, Tcl_Interp *ip,
+ HBytes_Var v, int strc, Tcl_Obj *const *strv) {
+ int rc, el;
+ Byte *dest;
+
+ rc= strs1(ip,strc,strv,&el); if (rc) return rc;
+ dest= hbytes_append(v.hb, el);
+ strs2(dest, strc,strv);
+ return TCL_OK;
}
int do_hbytes_concat(ClientData cd, Tcl_Interp *ip,
int strc, Tcl_Obj *const *strv, HBytes_Value *result) {
- HBytes_Var fake;
+ int rc, l;
+ Byte *dest;
- result->start= result->end= 0;
- fake.hb= result;
- return app_pre(cd,ip,1,fake,strc,strv);
+ rc= strs1(ip,strc,strv,&l); if (rc) return rc;
+ dest= hbytes_arrayspace(result,l);
+ strs2(dest, strc,strv);
+ return TCL_OK;
}
+static int underrun(Tcl_Interp *ip) { return staticerr(ip,"data underrun"); }
+
+int do_hbytes_unprepend(ClientData cd, Tcl_Interp *ip,
+ HBytes_Var v, int preflength, HBytes_Value *result) {
+ const Byte *rdata= hbytes_unprepend(v.hb, preflength);
+ if (!rdata) return underrun(ip);
+ hbytes_array(result, rdata, preflength);
+ return TCL_OK;
+}
+
+int do_hbytes_unappend(ClientData cd, Tcl_Interp *ip,
+ HBytes_Var v, int suflength, HBytes_Value *result) {
+ const Byte *rdata= hbytes_unappend(v.hb, suflength);
+ if (!rdata) return underrun(ip);
+ hbytes_array(result, rdata, suflength);
+ return TCL_OK;
+}
+
+int do_hbytes_chopto(ClientData cd, Tcl_Interp *ip,
+ HBytes_Var v, int newlength, HBytes_Value *result) {
+ int suflength= hbytes_len(v.hb) - newlength;
+ return do_hbytes_unappend(0,ip,v, suflength, result);
+}
*
*/
+#include <string.h>
+
#include "hbytes.h"
#include "tables.h"
+#include "hbintern.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 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) {
- hbytes_set(&HBYTES(o), array, 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(HBYTES(src)));
+int hbytes_issentinel(const HBytes_Value *hb) {
+ return HBYTES_ISCOMPLEX(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 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(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 *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(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;
+
+ if (HBYTES_ISCOMPLEX(hb)) return hb->begin_complex;
-int do_hbytes_raw2h(ClientData cd, Tcl_Interp *ip,
- Tcl_Obj *binary, HBytes_Value *result) {
- const char *str;
- int l;
+ cx= TALLOC(sizeof(*cx));
+ cx->dstart= hb->begin_complex;
+ cx->len= cx->avail= SIMPLE_LEN(hb);
+ cx->prespace= 0;
- str= Tcl_GetStringFromObj(binary,&l);
- hbytes_set(result, str, l);
- return TCL_OK;
+ hb->begin_complex= cx;
+ hb->end_0= 0;
+
+ return cx;
}
-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 *hbytes_prepend(HBytes_Value *hb, int el) {
+ HBytes_ComplexValue *cx;
+ int new_prespace;
+ Byte *old_block, *new_block, *new_dstart;
+
+ cx= complex(hb);
+
+ 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;
}
-#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;
+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;
}
-#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);
+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; }
+
+ cx= complex(hb);
+ if (cl > cx->len) { *rv=0; return 0; }
+ return cx;
+}
+
+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_RegisterObjType(&enum1_nearlytype);
- Tcl_CreateObjCommand(ip,"hbytes", pa__hbytes,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;
}
/* from hbytes.c */
+/* Internal representation details: */
+#define HBYTES_ISEMPTY(hb) (!(hb)->begin_complex && !(hb)->end_0)
+#define HBYTES_ISSENTINEL(hb) (!(hb)->begin_complex && (hb)->end_0)
+#define HBYTES_ISSIMPLE(hb) ((hb)->begin_complex && (hb)->end_0)
+#define HBYTES_ISCOMPLEX(hb) ((hb)->begin_complex && !(hb)->end_0)
+
typedef struct {
- Byte *start, *end; /* always allocated dynamically */
+ void *begin_complex, *end_0;
} HBytes_Value; /* overlays internalRep */
+typedef struct {
+ Byte *dstart; /* always allocated dynamically */
+ int prespace, len, avail;
+ /*
+ * | SPARE | USED | SPARE |
+ * |<-prespace->|<-len->| |
+ * | |<----avail---->|
+ * ^start
+ */
+} HBytes_ComplexValue; /* pointed to from internalRep.otherValuePtr */
+
+/* Public interfaces: */
+
extern Tcl_ObjType hbytes_type;
+int hbytes_len(const HBytes_Value *v);
+Byte *hbytes_data(const HBytes_Value *v); /* caller may then modify data! */
+int hbytes_issentinel(const HBytes_Value *v);
+
+Byte *hbytes_prepend(HBytes_Value *upd, int el);
+Byte *hbytes_append(HBytes_Value *upd, int el);
+ /* return value is where to put the data */
+
+const Byte *hbytes_unprepend(HBytes_Value *upd, int rl);
+const Byte *hbytes_unappend(HBytes_Value *upd, int rl);
+ /* return value points to the removed data, which remains valid
+ * until next op on the HBytes_Value. If original value is
+ * shorter than rl or negative, returns 0 and does nothing. */
+
+void hbytes_empty(HBytes_Value *returns);
+void hbytes_sentinel(HBytes_Value *returns);
+void hbytes_array(HBytes_Value *returns, const Byte *array, int l);
+Byte *hbytes_arrayspace(HBytes_Value *returns, int l);
+void hbytes_free(HBytes_Value *frees);
+ /* _empty, _sentinel and _array do not free or read the old value;
+ * _free it first if needed. _free leaves it garbage, so you
+ * have to call _empty to reuse it. _arrayspace doesn't fill
+ * the array; you get a pointer and must fill it with data
+ * yourself. */
+
+/* The value made by hbytes_sentinel should not be passed to
+ * anything except HBYTES_IS..., and hbytes_free. */
+
+/* from hook.c */
+
int staticerr(Tcl_Interp *ip, const char *m);
void objfreeir(Tcl_Obj *o);
-void hbytes_set(HBytes_Value *upd, const Byte *array, int l);
-Tcl_Obj *hbytes_set_obj(Tcl_Obj *overwrite, const Byte *array, int l);
-
/* from parse.c */
typedef struct {
void fini_hbv(Tcl_Interp *ip, int rc, HBytes_Var *agg);
+/* from chop.c */
+
/* from enum.c */
extern Tcl_ObjType enum_nearlytype;
/* useful macros */
-#define HBYTES(o) (*(HBytes_Value*)&(o)->internalRep.twoPtrValue)
-#define HBYTES_LEN(hb) ((hb).end - (hb).start)
+#define OBJ_HBYTES(o) ((HBytes_Value*)&(o)->internalRep.twoPtrValue)
#define TALLOC(s) ((void*)Tcl_Alloc((s)))
#define TFREE(f) (Tcl_Free((void*)(f)))
--- /dev/null
+/*
+ */
+
+#include "hbytes.h"
+#include "tables.h"
+
+int staticerr(Tcl_Interp *ip, const char *m) {
+ Tcl_SetResult(ip, (char*)m, TCL_STATIC);
+ return TCL_ERROR;
+}
+
+void objfreeir(Tcl_Obj *o) {
+ if (o->typePtr && o->typePtr->freeIntRepProc)
+ o->typePtr->freeIntRepProc(o);
+ o->typePtr= 0;
+}
+
+int do_hbytes_rep_info(ClientData cd, Tcl_Interp *ip,
+ HBytes_Value v, Tcl_Obj **result) {
+ const char *tn;
+ int nums[3], i;
+ Tcl_Obj *objl[4];
+
+ memset(nums,0,sizeof(nums));
+ nums[1]= hbytes_len(&v);
+
+ if (HBYTES_ISEMPTY(&v)) tn= "empty";
+ else if (HBYTES_ISSENTINEL(&v)) tn= "sentinel!";
+ else if (HBYTES_ISSIMPLE(&v)) tn= "simple";
+ else {
+ HBytes_ComplexValue *cx= v.begin_complex;
+ tn= "complex";
+ nums[0]= cx->prespace;
+ nums[2]= cx->avail - cx->len;
+ }
+
+ objl[0]= Tcl_NewStringObj((char*)tn,-1);
+ for (i=0; i<3; i++) objl[i+1]= Tcl_NewIntObj(nums[i]);
+ *result= Tcl_NewListObj(4,objl);
+ return TCL_OK;
+}
+
+static void hbytes_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
+ objfreeir(dup);
+ hbytes_array(OBJ_HBYTES(dup),
+ hbytes_data(OBJ_HBYTES(src)),
+ hbytes_len(OBJ_HBYTES(src)));
+}
+
+static void hbytes_t_free(Tcl_Obj *o) {
+ hbytes_free(OBJ_HBYTES(o));
+}
+
+static void hbytes_t_ustr(Tcl_Obj *o) {
+ int l;
+ char *str;
+ const Byte *byte;
+
+ byte= hbytes_data(OBJ_HBYTES(o));
+ l= hbytes_len(OBJ_HBYTES(o));
+ str= o->bytes= TALLOC(l*2+1);
+ o->length= l*2;
+ while (l>0) {
+ sprintf(str,"%02x",*byte);
+ str+=2; byte++; l--;
+ }
+ *str= 0;
+}
+
+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);
+ objfreeir(o);
+
+ if (l & 1) return staticerr(ip, "hbytes: conversion from hex:"
+ " odd length in hex");
+
+ startbytes= bytes= hbytes_arrayspace(OBJ_HBYTES(o), l/2);
+
+ cbuf[2]= 0;
+ while (l>0) {
+ cbuf[0]= *str++;
+ cbuf[1]= *str++;
+ *bytes++= strtoul(cbuf,&ep,16);
+ if (ep != cbuf+2) {
+ hbytes_free(OBJ_HBYTES(o));
+ return staticerr(ip, "hbytes: conversion from hex:"
+ " bad hex digit");
+ }
+ l -= 2;
+ }
+
+ o->typePtr = &hbytes_type;
+ return TCL_OK;
+}
+
+Tcl_ObjType hbytes_type = {
+ "hbytes",
+ hbytes_t_free, hbytes_t_dup, hbytes_t_ustr, hbytes_t_sfa
+};
+
+int do_hbytes_raw2h(ClientData cd, Tcl_Interp *ip,
+ Tcl_Obj *binary, HBytes_Value *result) {
+ const char *str;
+ int l;
+
+ str= Tcl_GetStringFromObj(binary,&l);
+ hbytes_array(result, str, l);
+ return TCL_OK;
+}
+
+int do_hbytes_h2raw(ClientData cd, Tcl_Interp *ip,
+ HBytes_Value hex, Tcl_Obj **result) {
+ *result= Tcl_NewStringObj(hbytes_data(&hex), hbytes_len(&hex));
+ return TCL_OK;
+}
+
+#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;
+}
+#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);
+}
+
+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;
+}
rc= Tcl_ConvertToType(ip,val,&hbytes_type);
if (rc) return rc;
- agg->hb= &HBYTES(val);
+ agg->hb= OBJ_HBYTES(val);
return TCL_OK;
}
int pat_hb(Tcl_Interp *ip, Tcl_Obj *obj, HBytes_Value *val) {
int rc;
rc= Tcl_ConvertToType(ip,obj,&hbytes_type); if (rc) return rc;
- *val= HBYTES(obj);
+ *val= *OBJ_HBYTES(obj);
return TCL_OK;
}
Tcl_Obj *ret_hb(Tcl_Interp *ip, HBytes_Value val) {
- return hbytes_set_obj(0, val.start, HBYTES_LEN(val));
+ Tcl_Obj *obj;
+ obj= Tcl_NewObj();
+ Tcl_InvalidateStringRep(obj);
+ *OBJ_HBYTES(obj)= val;
+ obj->typePtr= &hbytes_type;
+ return obj;
}
Tcl_Obj *ret_obj(Tcl_Interp *ip, Tcl_Obj *val) {