2 * hbytes - hex-stringrep efficient byteblocks for Tcl
3 * Copyright 2006 Ian Jackson
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 #include "chiark_tcl_hbytes.h"
26 int cht_do_hbytes_rep_info(ClientData cd, Tcl_Interp *ip,
27 Tcl_Obj *obj, Tcl_Obj **result) {
32 if (obj->typePtr == &cht_hbytes_type) {
33 HBytes_Value *v= OBJ_HBYTES(obj);
34 memset(nums,0,sizeof(nums));
35 nums[1]= cht_hb_len(v);
37 if (HBYTES_ISEMPTY(v)) tn= "empty";
38 else if (HBYTES_ISSENTINEL(v)) tn= "sentinel!";
39 else if (HBYTES_ISSIMPLE(v)) tn= "simple";
41 HBytes_ComplexValue *cx= v->begin_complex;
43 nums[0]= cx->prespace;
44 nums[2]= cx->avail - cx->len;
52 objl[0]= Tcl_NewStringObj((char*)tn,-1);
53 for (i=0; i<lnl; i++) objl[i+1]= Tcl_NewIntObj(nums[i]);
54 *result= Tcl_NewListObj(lnl+1,objl);
59 static void hbytes_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
60 cht_hb_array(OBJ_HBYTES(dup),
61 cht_hb_data(OBJ_HBYTES(src)),
62 cht_hb_len(OBJ_HBYTES(src)));
63 dup->typePtr= &cht_hbytes_type;
66 static void hbytes_t_free(Tcl_Obj *o) {
67 cht_hb_free(OBJ_HBYTES(o));
70 void obj_updatestr_array_prefix(Tcl_Obj *o, const Byte *byte,
71 int l, const char *prefix) {
77 str= o->bytes= TALLOC(o->length+1);
79 memcpy(str,prefix,pl);
83 sprintf(str,"%02x",*byte);
89 void obj_updatestr_array(Tcl_Obj *o, const Byte *byte, int l) {
90 obj_updatestr_array_prefix(o,byte,l,"");
93 static void hbytes_t_ustr(Tcl_Obj *o) {
94 obj_updatestr_array(o,
95 cht_hb_data(OBJ_HBYTES(o)),
96 cht_hb_len(OBJ_HBYTES(o)));
99 static int hbytes_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
101 Byte *startbytes, *bytes;
105 if (o->typePtr == &cht_ulong_type) {
108 ul= htonl(*(const uint32_t*)&o->internalRep.longValue);
109 cht_hb_array(OBJ_HBYTES(o), (const Byte*)&ul, 4);
113 os= str= Tcl_GetStringFromObj(o,&l); assert(str);
116 if (l & 1) return cht_staticerr(ip, "hbytes: conversion from hex:"
117 " odd length in hex", "HBYTES SYNTAX");
119 startbytes= bytes= cht_hb_arrayspace(OBJ_HBYTES(o), l/2);
125 *bytes++= strtoul(cbuf,&ep,16);
127 cht_hb_free(OBJ_HBYTES(o));
128 return cht_staticerr(ip, "hbytes: conversion from hex:"
129 " bad hex digit", "HBYTES SYNTAX");
136 o->typePtr = &cht_hbytes_type;
140 Tcl_ObjType cht_hbytes_type = {
142 hbytes_t_free, hbytes_t_dup, hbytes_t_ustr, hbytes_t_sfa
145 int cht_do_hbytes_raw2h(ClientData cd, Tcl_Interp *ip,
146 Tcl_Obj *binary, HBytes_Value *result) {
147 const unsigned char *str;
150 str= Tcl_GetByteArrayFromObj(binary,&l);
151 cht_hb_array(result, str, l);
155 int cht_do_hbytes_h2raw(ClientData cd, Tcl_Interp *ip,
156 HBytes_Value hex, Tcl_Obj **result) {
157 *result= Tcl_NewByteArrayObj(cht_hb_data(&hex), cht_hb_len(&hex));
161 int cht_do_hbytes_length(ClientData cd, Tcl_Interp *ip,
162 HBytes_Value v, int *result) {
163 *result= cht_hb_len(&v);
167 int cht_do_hbytes_random(ClientData cd, Tcl_Interp *ip,
168 int length, HBytes_Value *result) {
172 space= cht_hb_arrayspace(result, length);
173 rc= cht_get_urandom(ip, space, length);
174 if (rc) { cht_hb_free(result); return rc; }
178 int cht_do_hbytes_overwrite(ClientData cd, Tcl_Interp *ip,
179 HBytes_Var v, int start, HBytes_Value sub) {
182 sub_l= cht_hb_len(&sub);
184 return cht_staticerr(ip, "hbytes overwrite start -ve",
185 "HBYTES LENGTH RANGE");
186 if (start + sub_l > cht_hb_len(v.hb))
187 return cht_staticerr(ip, "hbytes overwrite out of range",
188 "HBYTES LENGTH UNDERRUN");
189 memcpy(cht_hb_data(v.hb) + start, cht_hb_data(&sub), sub_l);
193 int cht_do_hbytes_trimleft(ClientData cd, Tcl_Interp *ip, HBytes_Var v) {
194 const Byte *o, *p, *e;
195 o= p= cht_hb_data(v.hb);
196 e= p + cht_hb_len(v.hb);
198 while (p<e && !*p) p++;
200 cht_hb_unprepend(v.hb, p-o);
205 int cht_do_hbytes_repeat(ClientData cd, Tcl_Interp *ip,
206 HBytes_Value sub, int count, HBytes_Value *result) {
211 sub_l= cht_hb_len(&sub);
212 if (count < 0) return cht_staticerr(ip, "hbytes repeat count -ve",
213 "HBYTES LENGTH RANGE");
214 if (count > INT_MAX/sub_l) return cht_staticerr(ip, "hbytes repeat too long", 0);
216 data= cht_hb_arrayspace(result, sub_l*count);
217 sub_d= cht_hb_data(&sub);
219 memcpy(data, sub_d, sub_l);
220 count--; data += sub_l;
225 int cht_do_hbytes_xor(ClientData cd, Tcl_Interp *ip,
226 HBytes_Var v, HBytes_Value d) {
232 if (cht_hb_len(&d) != l) return
233 cht_staticerr(ip, "hbytes xor lengths do not match", "HBYTES LENGTH MISMATCH");
235 dest= cht_hb_data(v.hb);
236 source= cht_hb_data(&d);
237 memxor(dest,source,l);
241 int cht_do_hbytes_zeroes(ClientData cd, Tcl_Interp *ip,
242 int length, HBytes_Value *result) {
244 space= cht_hb_arrayspace(result, length);
245 memset(space,0,length);
249 int cht_do_hbytes_compare(ClientData cd, Tcl_Interp *ip,
250 HBytes_Value a, HBytes_Value b, int *result) {
255 minl= al<bl ? al : bl;
257 r= memcmp(cht_hb_data(&a), cht_hb_data(&b), minl);
259 if (r<0) *result= -2;
260 else if (r>0) *result= +2;
262 if (al<bl) *result= -1;
263 else if (al>bl) *result= +1;
269 int cht_do_hbytes_range(ClientData cd, Tcl_Interp *ip,
270 HBytes_Value v, int start, int size,
271 HBytes_Value *result) {
276 if (start<0 || size<0)
277 return cht_staticerr(ip,"hbytes range subscript(s) -ve","HBYTES LENGTH RANGE");
279 return cht_staticerr(ip, "hbytes range subscripts too big",
280 "HBYTES LENGTH UNDERRUN");
282 data= cht_hb_data(&v);
283 cht_hb_array(result, data+start, size);
287 /* hbytes representing uint16_t's */
289 int cht_do_hbytes_h2ushort(ClientData cd, Tcl_Interp *ip,
290 HBytes_Value hex, long *result) {
296 return cht_staticerr(ip, "hbytes h2ushort input more than 4 hex digits",
297 "HBYTES VALUE OVERFLOW");
299 data= cht_hb_data(&hex);
300 *result= data[l-1] | (l>1 ? data[0]<<8 : 0);
304 int cht_do_hbytes_ushort2h(ClientData cd, Tcl_Interp *ip,
305 long input, HBytes_Value *result) {
309 return cht_staticerr(ip, "hbytes ushort2h input >2^16",
310 "HBYTES VALUE OVERFLOW");
313 cht_hb_array(result,(const Byte*)&us,2);
317 /* toplevel functions */
319 int cht_do_hbytestoplevel_hbytes(ClientData cd, Tcl_Interp *ip,
320 const HBytes_SubCommand *subcmd,
321 int objc, Tcl_Obj *const *objv) {
322 return subcmd->func(0,ip,objc,objv);
325 int cht_do_hbytestoplevel_ulong(ClientData cd, Tcl_Interp *ip,
326 const ULong_SubCommand *subcmd,
327 int objc, Tcl_Obj *const *objv) {
328 return subcmd->func(0,ip,objc,objv);
331 int Chiark_tcl_hbytes_Init(Tcl_Interp *ip) {
334 return cht_initextension(ip, cht_hbytestoplevel_entries, &initd,