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, 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 cht_obj_updatestr_array_prefix(Tcl_Obj *o, const Byte *byte,
71 int l, const char *prefix) {
76 assert(l < INT_MAX/2 - 1 - pl);
78 str= o->bytes= TALLOC(o->length+1);
80 memcpy(str,prefix,pl);
84 sprintf(str,"%02x",*byte);
90 void cht_obj_updatestr_array(Tcl_Obj *o, const Byte *byte, int l) {
91 cht_obj_updatestr_array_prefix(o,byte,l,"");
94 static void hbytes_t_ustr(Tcl_Obj *o) {
95 cht_obj_updatestr_array(o,
96 cht_hb_data(OBJ_HBYTES(o)),
97 cht_hb_len(OBJ_HBYTES(o)));
100 static int hbytes_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
102 Byte *startbytes, *bytes;
106 if (o->typePtr == &cht_ulong_type) {
109 ul= htonl(*(const uint32_t*)&o->internalRep.longValue);
110 cht_hb_array(OBJ_HBYTES(o), (const Byte*)&ul, 4);
114 os= str= Tcl_GetStringFromObj(o,&l); assert(str);
117 if (l & 1) return cht_staticerr(ip, "hbytes: conversion from hex:"
118 " odd length in hex", "HBYTES SYNTAX");
120 startbytes= bytes= cht_hb_arrayspace(OBJ_HBYTES(o), l/2);
126 *bytes++= strtoul(cbuf,&ep,16);
128 cht_hb_free(OBJ_HBYTES(o));
129 return cht_staticerr(ip, "hbytes: conversion from hex:"
130 " bad hex digit", "HBYTES SYNTAX");
137 o->typePtr = &cht_hbytes_type;
141 Tcl_ObjType cht_hbytes_type = {
143 hbytes_t_free, hbytes_t_dup, hbytes_t_ustr, hbytes_t_sfa
146 int cht_do_hbytes_raw2h(ClientData cd, Tcl_Interp *ip,
147 Tcl_Obj *binary, HBytes_Value *result) {
148 const unsigned char *str;
151 str= Tcl_GetByteArrayFromObj(binary,&l);
152 cht_hb_array(result, str, l);
156 int cht_do_hbytes_h2raw(ClientData cd, Tcl_Interp *ip,
157 HBytes_Value hex, Tcl_Obj **result) {
158 *result= Tcl_NewByteArrayObj(cht_hb_data(&hex), cht_hb_len(&hex));
162 int cht_do_hbytes_length(ClientData cd, Tcl_Interp *ip,
163 HBytes_Value v, int *result) {
164 *result= cht_hb_len(&v);
168 int cht_do_hbytes_random(ClientData cd, Tcl_Interp *ip,
169 int length, HBytes_Value *result) {
173 space= cht_hb_arrayspace(result, length);
174 rc= cht_get_urandom(ip, space, length);
175 if (rc) { cht_hb_free(result); return rc; }
179 int cht_do_hbytes_overwrite(ClientData cd, Tcl_Interp *ip,
180 HBytes_Var v, int start, HBytes_Value sub) {
183 sub_l= cht_hb_len(&sub);
185 return cht_staticerr(ip, "hbytes overwrite start -ve",
186 "HBYTES LENGTH RANGE");
187 if (start + sub_l > cht_hb_len(v.hb))
188 return cht_staticerr(ip, "hbytes overwrite out of range",
189 "HBYTES LENGTH UNDERRUN");
190 memcpy(cht_hb_data(v.hb) + start, cht_hb_data(&sub), sub_l);
194 int cht_do_hbytes_trimleft(ClientData cd, Tcl_Interp *ip, HBytes_Var v) {
195 const Byte *o, *p, *e;
196 o= p= cht_hb_data(v.hb);
197 e= p + cht_hb_len(v.hb);
199 while (p<e && !*p) p++;
201 cht_hb_unprepend(v.hb, p-o);
206 int cht_do_hbytes_repeat(ClientData cd, Tcl_Interp *ip,
207 HBytes_Value sub, int count, HBytes_Value *result) {
212 sub_l= cht_hb_len(&sub);
213 if (count < 0) return cht_staticerr(ip, "hbytes repeat count -ve",
214 "HBYTES LENGTH RANGE");
215 if (count > INT_MAX/sub_l) return cht_staticerr(ip, "hbytes repeat too long", 0);
217 data= cht_hb_arrayspace(result, sub_l*count);
218 sub_d= cht_hb_data(&sub);
220 memcpy(data, sub_d, sub_l);
221 count--; data += sub_l;
226 int cht_do_hbytes_xor(ClientData cd, Tcl_Interp *ip,
227 HBytes_Var v, HBytes_Value d) {
233 if (cht_hb_len(&d) != l) return
234 cht_staticerr(ip, "hbytes xor lengths do not match", "HBYTES LENGTH MISMATCH");
236 dest= cht_hb_data(v.hb);
237 source= cht_hb_data(&d);
238 memxor(dest,source,l);
242 int cht_do_hbytes_zeroes(ClientData cd, Tcl_Interp *ip,
243 int length, HBytes_Value *result) {
245 space= cht_hb_arrayspace(result, length);
246 memset(space,0,length);
250 int cht_do_hbytes_compare(ClientData cd, Tcl_Interp *ip,
251 HBytes_Value a, HBytes_Value b, int *result) {
256 minl= al<bl ? al : bl;
258 r= memcmp(cht_hb_data(&a), cht_hb_data(&b), minl);
260 if (r<0) *result= -2;
261 else if (r>0) *result= +2;
263 if (al<bl) *result= -1;
264 else if (al>bl) *result= +1;
270 int cht_do_hbytes_range(ClientData cd, Tcl_Interp *ip,
271 HBytes_Value v, int start, int size,
272 HBytes_Value *result) {
277 if (start<0 || size<0)
278 return cht_staticerr(ip,"hbytes range subscript(s) -ve","HBYTES LENGTH RANGE");
280 return cht_staticerr(ip, "hbytes range subscripts too big",
281 "HBYTES LENGTH UNDERRUN");
283 data= cht_hb_data(&v);
284 cht_hb_array(result, data+start, size);
288 /* hbytes representing uint16_t's */
290 int cht_do_hbytes_h2ushort(ClientData cd, Tcl_Interp *ip,
291 HBytes_Value hex, long *result) {
297 return cht_staticerr(ip, "hbytes h2ushort input more than 4 hex digits",
298 "HBYTES VALUE OVERFLOW");
300 data= cht_hb_data(&hex);
301 *result= data[l-1] | (l>1 ? data[0]<<8 : 0);
305 int cht_do_hbytes_ushort2h(ClientData cd, Tcl_Interp *ip,
306 long input, HBytes_Value *result) {
310 return cht_staticerr(ip, "hbytes ushort2h input >2^16",
311 "HBYTES VALUE OVERFLOW");
314 cht_hb_array(result,(const Byte*)&us,2);
318 /* toplevel functions */
321 CHTI_TYPE(cht_hbytes_type) CHTI_TYPE(cht_ulong_type),
322 CHTI_COMMANDS(cht_hbytestoplevel_entries))