source: branches/r9/lang/tcl/src/RpEncodeTclInterface.cc @ 4867

Last change on this file since 4867 was 4867, checked in by gah, 7 years ago
File size: 9.8 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  Rappture::encoding
4 *
5 *  The encoding module for rappture used to zip and b64 encode data.
6 * ======================================================================
7 *  AUTHOR:  Derrick Kearney, Purdue University
8 *  Copyright (c) 2004-2012  HUBzero Foundation, LLC
9 *
10 *  See the file "license.terms" for information on usage and
11 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 * ======================================================================
13 */
14#include <tcl.h>
15#include "RpEncode.h"
16extern "C" {
17#include "RpSwitch.h"
18extern Tcl_AppInitProc RpEncoding_Init;
19}
20
21static Tcl_ObjCmdProc IsCmd;
22static Tcl_ObjCmdProc EncodeCmd;
23static Tcl_ObjCmdProc DecodeCmd;
24static Tcl_ObjCmdProc DebugCmd;
25
26/**********************************************************************/
27// FUNCTION: RpEncoding_Init()
28/// Initializes the Rappture Encoding module and commands defined below
29/**
30 * Called in RapptureGUI_Init() to initialize the Rappture Units module.
31 * Initialized commands include:
32 * ::Rappture::encoding::is
33 * ::Rappture::encoding::encode
34 * ::Rappture::encoding::decode
35 */
36
37int
38RpEncoding_Init(Tcl_Interp *interp)
39{
40    Tcl_CreateObjCommand(interp, "::Rappture::encoding::is",
41        IsCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
42
43    Tcl_CreateObjCommand(interp, "::Rappture::encoding::encode",
44        EncodeCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
45
46    Tcl_CreateObjCommand(interp, "::Rappture::encoding::decode",
47        DecodeCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
48
49    Tcl_CreateObjCommand(interp, "::Rappture::encoding::debug",
50        DebugCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
51    return TCL_OK;
52}
53
54/**********************************************************************/
55// FUNCTION: IsCmd()
56/// Rappture::encoding::is checks to see if given string is binary.
57/**
58 * Checks to see <string> is binary
59 * Full function call:
60 * ::Rappture::encoding::is binary <string>
61 *
62 */
63
64static int
65IsCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
66{
67    Tcl_ResetResult(interp);
68
69    // parse through command line options
70    if (objc != 3) {
71        Tcl_AppendResult(interp,
72            "wrong # args: should be \"",
73            Tcl_GetString(objv[0])," binary|encoded <string>\"",
74            (char*)NULL);
75        return TCL_ERROR;
76    }
77
78
79    int bufLen;
80    const char *buf;
81    const char *string;
82    buf = (const char *)Tcl_GetByteArrayFromObj(objv[2], &bufLen);
83    const char *type = Tcl_GetString(objv[1]);
84    if (('b' == *type) && (strcmp(type, "binary") == 0)) {
85        string = (Rappture::encoding::isBinary(buf, bufLen)) ? "yes" : "no";
86    } else if (('e' == *type) && (strcmp(type,"encoded") == 0)) {
87        bool isEncoded;
88
89        isEncoded = (Rappture::encoding::headerFlags(buf, bufLen) != 0);
90        string = (isEncoded) ? "yes" : "no" ;
91    } else {
92        Tcl_AppendResult(interp, "bad option \"", type,
93                "\": should be binary or encoded", (char*)NULL);
94        return TCL_ERROR;
95    }
96    Tcl_SetResult(interp, (char *)string, TCL_STATIC);
97    return TCL_OK;
98}
99
100/**********************************************************************/
101// FUNCTION: EncodeCmd --
102/// Rappture::encoding::encode function in Tcl, encodes provided string
103/**
104 * Encode a string by compressing it with zlib and then base64 encoding it.
105 * If binary data is provided, the data is compressed and base64 encoded.
106 * RpTclEncodingIs is used to qualify binary data.
107 *
108 * If the -as option is not set, zlib compression and base64 encoding
109 * is performed by default
110 *
111 * Full function call:
112 * ::Rappture::encoding::encode ?-as z|b64|zb64? ?-no-header? <string>
113 */
114
115/*
116 *---------------------------------------------------------------------------
117 *
118 * AsSwitch --
119 *
120 *        Convert a string represent a node number into its integer
121 *        value.
122 *
123 * Results:
124 *        The return value is a standard Tcl result.
125 *
126 *---------------------------------------------------------------------------
127 */
128/*ARGSUSED*/
129static int
130AsSwitch(
131    ClientData clientData,        /* Not used. */
132    Tcl_Interp *interp,                /* Interpreter to send results back to */
133    const char *switchName,        /* Not used. */
134    Tcl_Obj *objPtr,                /* String representation */
135    char *record,                /* Structure record */
136    int offset,                        /* Offset to field in structure */
137    int flags)                        /* Not used. */
138{
139    int *flagsPtr = (int *)(record + offset);
140    char c;
141    char *string;
142
143    string = Tcl_GetString(objPtr);
144    c = string[0];
145    if ((c == 'b') && (strcmp(string, "b64") == 0)) {
146        *flagsPtr = RPENC_B64;
147    } else if ((c == 'z') && (strcmp(string, "zb64") == 0)) {
148        *flagsPtr = RPENC_Z  | RPENC_B64;
149    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
150        *flagsPtr = RPENC_Z;
151    } else {
152        Tcl_AppendResult(interp, "bad value \"", string,
153                 "\": should be b64, zb64, or z", (char *)NULL);
154        return TCL_ERROR;
155    }
156    return TCL_OK;
157}
158
159static SwitchParseProc AsSwitch;
160static SwitchCustom asSwitch = {
161    AsSwitch, NULL, 0,
162};
163
164typedef struct {
165    unsigned int flags;
166} EncodeSwitches;
167
168static SwitchSpec encodeSwitches[] =
169{
170    {SWITCH_CUSTOM, "-as", "z|b64|zb64",
171        offsetof(EncodeSwitches, flags), 0, 0, &asSwitch},
172    {SWITCH_BITMASK, "-noheader", "",
173        offsetof(EncodeSwitches, flags), 0, RPENC_RAW},
174    {SWITCH_END}
175};
176
177static int
178EncodeCmd(ClientData clientData, Tcl_Interp *interp, int objc,
179          Tcl_Obj *const *objv)
180{
181    EncodeSwitches switches;
182    const char* string;
183    int last;
184    int n;
185    int nBytes;
186
187    if (objc < 1) {
188        Tcl_AppendResult(interp, "wrong # args: should be \"",
189                Tcl_GetString(objv[0]),
190                " ?-as z|b64|zb64? ?-noheader? ?--? string\"", (char*)NULL);
191        return TCL_ERROR;
192    }
193    switches.flags = 0;
194    n = RpParseSwitches(interp, encodeSwitches, objc - 1, objv + 1, &switches,
195                         SWITCH_OBJV_PARTIAL);
196    if (n < 0) {
197        return TCL_ERROR;
198    }
199    last = n + 1;
200    if ((objc - last) != 1) {
201        Tcl_AppendResult(interp, "wrong # args: should be \"",
202                Tcl_GetString(objv[0]),
203                " ?-as z|b64|zb64? ?-noheader? ?--? string\"", (char*)NULL);
204        return TCL_ERROR;
205    }
206    string = (const char*)Tcl_GetByteArrayFromObj(objv[last], &nBytes);
207    if (nBytes <= 0) {
208        return TCL_OK;                // Nothing to encode.
209    }
210    Rappture::Buffer buf(string, nBytes);
211    Rappture::Outcome status;
212    if (!Rappture::encoding::encode(status, buf, switches.flags)) {
213        Tcl_AppendResult(interp, status.remark(), "\n", status.context(), NULL);
214        return TCL_ERROR;
215    }
216    Tcl_SetByteArrayObj(Tcl_GetObjResult(interp),
217                (const unsigned char*)buf.bytes(), buf.size());
218    return TCL_OK;
219}
220
221/**********************************************************************/
222// FUNCTION: DecodeCmd()
223/// Rappture::encoding::decode function in Tcl, decodes provided string
224/**
225 * Decode a string by uncompressing it with zlib and base64 decoding it.
226 * If binary data is provided, the data is base64 decoded and uncompressed.
227 * RpTclEncodingIs is used to qualify binary data.
228 *
229 * Full function call:
230 * ::Rappture::encoding::decode ?-as z|b64|zb64? <string>
231 *
232 *        I'd rather the interface be
233 *       
234 *                decode -b64 -z string
235 */
236
237typedef struct {
238    unsigned int flags;
239} DecodeSwitches;
240
241static SwitchSpec decodeSwitches[] =
242{
243    {SWITCH_CUSTOM, "-as", "z|b64|zb64",
244        offsetof(DecodeSwitches, flags), 0, 0, &asSwitch},
245    {SWITCH_BITMASK, "-noheader", "",
246        offsetof(DecodeSwitches, flags), 0, RPENC_RAW},
247    {SWITCH_END}
248};
249
250static int
251DecodeCmd(ClientData clientData, Tcl_Interp *interp, int objc,
252          Tcl_Obj *const *objv)
253{
254    DecodeSwitches switches;
255    int n;
256    int numBytes;
257    const char *string;
258    int last;
259
260    if (objc < 1) {
261        Tcl_AppendResult(interp, "wrong # args: should be \"",
262                Tcl_GetString(objv[0]),
263                " ?-as z|b64|zb64? ?--? <string>\"", (char*)NULL);
264        return TCL_ERROR;
265    }
266
267    switches.flags = 0;
268    n = RpParseSwitches(interp, decodeSwitches, objc - 1, objv + 1, &switches,
269        SWITCH_OBJV_PARTIAL);
270    if (n < 0) {
271        return TCL_ERROR;
272    }
273    last = n + 1;
274    if ((objc - last) != 1) {
275        Tcl_AppendResult(interp, "wrong # args: should be \"",
276                Tcl_GetString(objv[0]),
277                " ?-as z|b64|zb64? ?--? string\"", (char*)NULL);
278        return TCL_ERROR;
279    }
280
281    string = Tcl_GetStringFromObj(objv[last], &numBytes);
282    if ((switches.flags == 0) && (strncmp(string, "@@RP-ENC:", 9) != 0)) {
283        /* This string doesn't have a header, so it's not encoded.
284         * Just return the string as-is. */
285        Tcl_SetObjResult(interp, objv[last]);
286        return TCL_OK;
287    }
288    Rappture::Buffer buf(string, numBytes);
289    Rappture::Outcome status;
290    if (!Rappture::encoding::decode(status, buf, switches.flags)) {
291        Tcl_AppendResult(interp, status.remark(), "\n", status.context(), NULL);
292        return TCL_ERROR;
293    }
294    Tcl_SetByteArrayObj(Tcl_GetObjResult(interp),
295                        (const unsigned char *)buf.bytes(), buf.size());
296    return TCL_OK;
297}
298
299static int
300DebugCmd(ClientData clientData, Tcl_Interp *interp, int objc,
301          Tcl_Obj *const *objv)
302{
303    if (objc < 1) {
304        Tcl_AppendResult(interp, "wrong # args: should be \"",
305                Tcl_GetString(objv[0]), " string\"", (char*)NULL);
306        return TCL_ERROR;
307    }
308    int numBytes;
309    const char* string;
310    int i;
311    string = Tcl_GetStringFromObj(objv[objc-1], &numBytes);
312    fprintf(stderr, "string=%s, bytes=", string);
313    for (i = 0; i < numBytes; i++) {
314        fprintf(stderr, "%02x ", string[i]);
315    }
316    fprintf(stderr, "\n");
317    return TCL_OK;
318}
Note: See TracBrowser for help on using the repository browser.