2 * hbytes - hex-stringrep efficient byteblocks for Tcl
3 * Copyright 2006-2012 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, see <http://www.gnu.org/licenses/>.
22 #include "chiark_tcl_hbytes.h"
24 int cht_do_hbytes_rep_info(ClientData cd, Tcl_Interp *ip,
25 Tcl_Obj *obj, Tcl_Obj **result) {
30 if (obj->typePtr == &cht_hbytes_type) {
31 HBytes_Value *v= OBJ_HBYTES(obj);
32 memset(nums,0,sizeof(nums));
33 nums[1]= cht_hb_len(v);
35 if (HBYTES_ISEMPTY(v)) tn= "empty";
36 else if (HBYTES_ISSENTINEL(v)) tn= "sentinel!";
37 else if (HBYTES_ISSIMPLE(v)) tn= "simple";
39 HBytes_ComplexValue *cx= v->begin_complex;
41 nums[0]= cx->prespace;
42 nums[2]= cx->avail - cx->len;
50 objl[0]= Tcl_NewStringObj((char*)tn,-1);
51 for (i=0; i<lnl; i++) objl[i+1]= Tcl_NewIntObj(nums[i]);
52 *result= Tcl_NewListObj(lnl+1,objl);
57 static void hbytes_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
58 cht_hb_array(OBJ_HBYTES(dup),
59 cht_hb_data(OBJ_HBYTES(src)),
60 cht_hb_len(OBJ_HBYTES(src)));
61 dup->typePtr= &cht_hbytes_type;
64 static void hbytes_t_free(Tcl_Obj *o) {
65 cht_hb_free(OBJ_HBYTES(o));
68 void cht_obj_updatestr_array_prefix(Tcl_Obj *o, const Byte *byte,
69 int l, const char *prefix) {
74 assert(l < INT_MAX/2 - 1 - pl);
76 str= o->bytes= TALLOC(o->length+1);
78 memcpy(str,prefix,pl);
82 sprintf(str,"%02x",*byte);
88 void cht_obj_updatestr_array(Tcl_Obj *o, const Byte *byte, int l) {
89 cht_obj_updatestr_array_prefix(o,byte,l,"");
92 static void hbytes_t_ustr(Tcl_Obj *o) {
93 cht_obj_updatestr_array(o,
94 cht_hb_data(OBJ_HBYTES(o)),
95 cht_hb_len(OBJ_HBYTES(o)));
98 static int hbytes_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
104 if (o->typePtr == &cht_ulong_type) {
107 ul= htonl(*(const uint32_t*)&o->internalRep.longValue);
108 cht_hb_array(OBJ_HBYTES(o), (const Byte*)&ul, 4);
112 str= Tcl_GetStringFromObj(o,&l); assert(str);
115 if (l & 1) return cht_staticerr(ip, "hbytes: conversion from hex:"
116 " odd length in hex", "HBYTES SYNTAX");
118 bytes= cht_hb_arrayspace(OBJ_HBYTES(o), l/2);
124 *bytes++= strtoul(cbuf,&ep,16);
126 cht_hb_free(OBJ_HBYTES(o));
127 return cht_staticerr(ip, "hbytes: conversion from hex:"
128 " bad hex digit", "HBYTES SYNTAX");
135 o->typePtr = &cht_hbytes_type;
139 Tcl_ObjType cht_hbytes_type = {
141 hbytes_t_free, hbytes_t_dup, hbytes_t_ustr, hbytes_t_sfa
144 int cht_do_hbytes_raw2h(ClientData cd, Tcl_Interp *ip,
145 Tcl_Obj *binary, HBytes_Value *result) {
146 const unsigned char *str;
149 str= Tcl_GetByteArrayFromObj(binary,&l);
150 cht_hb_array(result, str, l);
154 int cht_do_hbytes_h2raw(ClientData cd, Tcl_Interp *ip,
155 HBytes_Value hex, Tcl_Obj **result) {
156 *result= Tcl_NewByteArrayObj(cht_hb_data(&hex), cht_hb_len(&hex));
160 int cht_do_hbytes_length(ClientData cd, Tcl_Interp *ip,
161 HBytes_Value v, int *result) {
162 *result= cht_hb_len(&v);
166 int cht_do_hbytes_random(ClientData cd, Tcl_Interp *ip,
167 int length, HBytes_Value *result) {
171 space= cht_hb_arrayspace(result, length);
172 rc= cht_get_urandom(ip, space, length);
173 if (rc) { cht_hb_free(result); return rc; }
177 int cht_do_hbytes_overwrite(ClientData cd, Tcl_Interp *ip,
178 HBytes_Var v, int start, HBytes_Value sub) {
181 sub_l= cht_hb_len(&sub);
183 return cht_staticerr(ip, "hbytes overwrite start -ve",
184 "HBYTES LENGTH RANGE");
185 if (start + sub_l > cht_hb_len(v.hb))
186 return cht_staticerr(ip, "hbytes overwrite out of range",
187 "HBYTES LENGTH UNDERRUN");
188 memcpy(cht_hb_data(v.hb) + start, cht_hb_data(&sub), sub_l);
192 int cht_do_hbytes_trimleft(ClientData cd, Tcl_Interp *ip, HBytes_Var v) {
193 const Byte *o, *p, *e;
194 o= p= cht_hb_data(v.hb);
195 e= p + cht_hb_len(v.hb);
197 while (p<e && !*p) p++;
199 cht_hb_unprepend(v.hb, p-o);
204 int cht_do_hbytes_repeat(ClientData cd, Tcl_Interp *ip,
205 HBytes_Value sub, int count, HBytes_Value *result) {
210 sub_l= cht_hb_len(&sub);
211 if (count < 0) return cht_staticerr(ip, "hbytes repeat count -ve",
212 "HBYTES LENGTH RANGE");
213 if (count > INT_MAX/sub_l) return cht_staticerr(ip, "hbytes repeat too long", 0);
215 data= cht_hb_arrayspace(result, sub_l*count);
216 sub_d= cht_hb_data(&sub);
218 memcpy(data, sub_d, sub_l);
219 count--; data += sub_l;
224 int cht_do_hbytes_xor(ClientData cd, Tcl_Interp *ip,
225 HBytes_Var v, HBytes_Value d) {
231 if (cht_hb_len(&d) != l) return
232 cht_staticerr(ip, "hbytes xor lengths do not match", "HBYTES LENGTH MISMATCH");
234 dest= cht_hb_data(v.hb);
235 source= cht_hb_data(&d);
236 memxor(dest,source,l);
240 int cht_do_hbytes_zeroes(ClientData cd, Tcl_Interp *ip,
241 int length, HBytes_Value *result) {
243 space= cht_hb_arrayspace(result, length);
244 memset(space,0,length);
248 int cht_do_hbytes_compare(ClientData cd, Tcl_Interp *ip,
249 HBytes_Value a, HBytes_Value b, int *result) {
254 minl= al<bl ? al : bl;
256 r= memcmp(cht_hb_data(&a), cht_hb_data(&b), minl);
258 if (r<0) *result= -2;
259 else if (r>0) *result= +2;
261 if (al<bl) *result= -1;
262 else if (al>bl) *result= +1;
268 int cht_do_hbytes_range(ClientData cd, Tcl_Interp *ip,
269 HBytes_Value v, int start, int size,
270 HBytes_Value *result) {
275 if (start<0 || size<0)
276 return cht_staticerr(ip,"hbytes range subscript(s) -ve","HBYTES LENGTH RANGE");
278 return cht_staticerr(ip, "hbytes range subscripts too big",
279 "HBYTES LENGTH UNDERRUN");
281 data= cht_hb_data(&v);
282 cht_hb_array(result, data+start, size);
286 /* hbytes representing uint16_t's */
288 int cht_do_hbytes_h2ushort(ClientData cd, Tcl_Interp *ip,
289 HBytes_Value hex, long *result) {
295 return cht_staticerr(ip, "hbytes h2ushort input more than 4 hex digits",
296 "HBYTES VALUE OVERFLOW");
298 data= cht_hb_data(&hex);
299 *result= data[l-1] | (l>1 ? data[0]<<8 : 0);
303 int cht_do_hbytes_ushort2h(ClientData cd, Tcl_Interp *ip,
304 long input, HBytes_Value *result) {
308 return cht_staticerr(ip, "hbytes ushort2h input >2^16",
309 "HBYTES VALUE OVERFLOW");
312 cht_hb_array(result,(const Byte*)&us,2);
316 /* toplevel functions */
319 CHTI_TYPE(cht_hbytes_type) CHTI_TYPE(cht_ulong_type),
320 CHTI_COMMANDS(cht_hbytestoplevel_entries))