chiark / gitweb /
Perly full service thing, before simple thing.
[chiark-tcl.git] / hbytes / hbytes.c
1 /*
2  *
3  */
4
5 #include "hbytes.h"
6
7 int staticerr(Tcl_Interp *ip, const char *m) {
8   Tcl_SetResult(ip, (char*)m, TCL_STATIC);
9   return TCL_ERROR;
10 }
11
12 static void hbytes_setintern(Tcl_Obj *o, const Byte *array, int l) {
13   Byte *np;
14     
15   HBYTES(o)->start= np= l ? TALLOC(l) : 0;
16   memcpy(np, array, l);
17   HBYTES(o)->end= np + l;
18   o->typePtr = &hbytes_type;
19 }
20
21 static void hbytes_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
22   hbytes_setintern(src, HBYTES(src)->start, HBYTES_LEN(src));
23 }
24
25 Tcl_Obj *hbytes_set(Tcl_Obj *overwrite, const Byte *array, int l) {
26   if (!overwrite) overwrite= Tcl_NewObj();
27   objfreeir(overwrite);
28   Tcl_InvalidateStringRep(overwrite);
29   hbytes_setintern(overwrite, array, l);
30   return overwrite;
31 }
32
33 static void hbytes_t_free(Tcl_Obj *o) {
34   TFREE(HBYTES(o)->start);
35 }
36
37 static void hbytes_t_ustr(Tcl_Obj *o) {
38   int l;
39   char *str;
40   const Byte *byte;
41
42   l= HBYTES_LEN(o);
43   byte= HBYTES(o)->start;
44   str= o->bytes= TALLOC(l*2+1);
45   o->length= l*2;
46   while (l>0) {
47     sprintf(str,"%02x",*byte);
48     str+=2; byte++; l--;
49   }
50 }
51
52 void objfreeir(Tcl_Obj *o) {
53   if (o->typePtr && o->typePtr->freeIntRepProc)
54     o->typePtr->freeIntRepProc(o);
55 }  
56
57 static int hbytes_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
58   char *str, *ep, *os;
59   Byte *startbytes, *bytes;
60   int l;
61   char cbuf[3];
62
63   os= str= Tcl_GetStringFromObj(o,&l);  assert(str);
64   if (l & 1) return staticerr(ip, "hbytes: conversion from hex:"
65                               " odd length in hex");
66
67   startbytes= bytes= l ? TALLOC(l*2) : 0;
68   cbuf[2]= 0;
69   while (l>0) {
70     cbuf[0]= *str++;
71     cbuf[1]= *str++;
72     *bytes++= strtoul(cbuf,&ep,16);
73     if (ep != cbuf+2) {
74       TFREE(startbytes);
75 fprintf(stderr,">%d|%s|%s<\n",l,os,cbuf);
76       return staticerr(ip, "hbytes: conversion from hex:"
77                        " bad hex digit");
78     }
79     l -= 2;
80   }
81   objfreeir(o);
82
83   HBYTES(o)->start= startbytes;
84   HBYTES(o)->end= bytes;
85   o->typePtr = &hbytes_type;
86   return TCL_OK;
87 }
88
89 Tcl_ObjType hbytes_type = {
90   "hbytes",
91   hbytes_t_free, hbytes_t_dup, hbytes_t_ustr, hbytes_t_sfa
92 };
93
94 static Tcl_Obj *hb_getvar(Tcl_Interp *ip, Tcl_Obj *varname) {
95   int ec;
96   Tcl_Obj *value;
97   
98   value= Tcl_ObjGetVar2(ip,varname,0,TCL_LEAVE_ERR_MSG);
99   if (!value) return 0;
100
101   ec= Tcl_ConvertToType(ip,value,&hbytes_type);
102   if (ec) return 0;
103
104   return value;
105 }
106
107 HC_DEFINE(raw2h) {
108   HC_DECLS;
109   Tcl_Obj *raw, *value;
110   const char *str;
111   int l;
112
113   HC_ARG_O(raw);
114   HC_ARGS_E;
115   str= Tcl_GetStringFromObj(raw,&l);
116   value= hbytes_set(0,str,l);
117   Tcl_SetObjResult(ip,value);
118   HC_FINI;
119 }
120
121 HC_DEFINE(h2raw) {
122   Tcl_Obj *value, *result;
123   
124   HC_ARG_H(value);
125   HC_ARGS_E;
126   result= Tcl_NewStringObj(HBYTES(value)->start, HBYTES_LEN(value));
127   Tcl_SetObjResult(ip,result);
128   HC_FINI;
129 }
130
131 HC_DEFINE(pkcs5) {
132   typedef struct {
133     const char *spec;
134     int pad, algname;
135   } PadKindInfo;
136   static const PadKindInfo padkindinfos[0]= {
137     { "pa", 1, 1 },
138     { "pn", 1, 0 },
139     { "ua", 0, 1 },
140     { "un", 0, 0 },
141     { 0 }
142   };
143
144   HC_DECLS_HBV;
145   Tcl_Obj *v;
146   int blocksize;
147   const PadKindInfo *pk;
148   const BlockCipherInfo *bc;
149
150   HC_ARG_ENUM(pk, padkindinfos);
151   HC_ARG_HBV;
152   if (!pk->algname) HC_ARG_INTRANGE(blocksize, 1,255);
153   else { HC_ARG_ENUM(bc, blockciphers); blocksize= bc->blocksize; }
154   HC_ARGS_E;
155
156   /* do nothing :-) */
157
158   HC_FINI_HBV;
159 }
160   
161 static int hc_raw2h(ClientData cd, Tcl_Interp *ip, int objc,
162                     Tcl_Obj *const *objv) {
163   
164   Tcl_Obj *varname, *value, *result;
165
166   varname= objv[0];
167   switch (objc) {
168   case 1:
169     value= hb_getvar(ip,varname);  if (!value) return TCL_ERROR;
170     assert(result);
171     Tcl_SetObjResult(ip,result);
172     return TCL_OK;
173   case 2:
174     value= objv[1];
175       HC_MINARGS(1);
176
177     value= Tcl_ObjSetVar2(ip,varname,0, value, TCL_LEAVE_ERR_MSG);
178     if (!value) return TCL_ERROR;
179     Tcl_ResetResult(ip);
180     return TCL_OK;
181   }
182   abort();
183 }
184
185 typedef struct {
186   const char *name;
187   int minargs, maxargs;
188   Tcl_ObjCmdProc *func;
189 } SubCommand;
190
191 #define SUBCOMMANDS                             \
192     DO(raw2h)                                   \
193     DO(h2raw)                                   \
194     DO(pkcs5)
195
196 static const SubCommand subcommands[] = {
197 #define DO(c) { #c, hc_##c },
198   SUBCOMMANDS
199   { 0 }
200 };
201
202 static int hb_proc(ClientData cd, Tcl_Interp *ip, int objc,
203                    Tcl_Obj *const *objv) {
204   const SubCommand *sc;
205
206   if (objc<2) return staticerr(ip, "hbytes: need subcommand");
207   sc= enum_lookup_cached(ip,objv[1],subcommands,"hbytes subcommand");
208   if (!sc) return TCL_ERROR;
209   objc -= 2;
210   objv += 2;
211   if (objc < sc->minargs)
212     return staticerr(ip, "too few args");
213   if (sc->maxargs >=0 && objc > sc->maxargs)
214     return staticerr(ip,"too many args");
215   return sc->func((void*)sc,ip,objc,objv);
216 }
217
218 int Hbytes_Init(Tcl_Interp *ip) {
219   Tcl_RegisterObjType(&hbytes_type);
220   Tcl_RegisterObjType(&enum_nearlytype);
221   Tcl_CreateObjCommand(ip,"hbytes", hb_proc,0,0);
222   return TCL_OK;
223 }