source: branches/1.3/lang/tcl/src/RpEncodeTclInterface.cc @ 5675

Last change on this file since 5675 was 5675, checked in by ldelgass, 9 years ago

merge r5673 from trunk (eol-style)

  • Property svn:eol-style set to native
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 "Switch.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    if (objc < 1) {
182        Tcl_AppendResult(interp, "wrong # args: should be \"",
183                Tcl_GetString(objv[0]),
184                " ?-as z|b64|zb64? ?-noheader? ?--? string\"", (char*)NULL);
185        return TCL_ERROR;
186    }
187    EncodeSwitches switches;
188    switches.flags = 0;
189    int n;
190    n = Rp_ParseSwitches(interp, encodeSwitches, objc - 1, objv + 1, &switches,
191                         SWITCH_OBJV_PARTIAL);
192    if (n < 0) {
193        return TCL_ERROR;
194    }
195    int last;
196    last = n + 1;
197    if ((objc - last) != 1) {
198        Tcl_AppendResult(interp, "wrong # args: should be \"",
199                Tcl_GetString(objv[0]),
200                " ?-as z|b64|zb64? ?-noheader? ?--? string\"", (char*)NULL);
201        return TCL_ERROR;
202    }
203    int nBytes;
204    const char* string;
205    string = (const char*)Tcl_GetByteArrayFromObj(objv[last], &nBytes);
206    if (nBytes <= 0) {
207        return TCL_OK;                // Nothing to encode.
208    }
209    Rappture::Buffer buf(string, nBytes);
210    Rappture::Outcome status;
211    if (!Rappture::encoding::encode(status, buf, switches.flags)) {
212        Tcl_AppendResult(interp, status.remark(), "\n", status.context(), NULL);
213        return TCL_ERROR;
214    }
215    Tcl_SetByteArrayObj(Tcl_GetObjResult(interp),
216                (const unsigned char*)buf.bytes(), buf.size());
217    return TCL_OK;
218}
219
220/**********************************************************************/
221// FUNCTION: DecodeCmd()
222/// Rappture::encoding::decode function in Tcl, decodes provided string
223/**
224 * Decode a string by uncompressing it with zlib and base64 decoding it.
225 * If binary data is provided, the data is base64 decoded and uncompressed.
226 * RpTclEncodingIs is used to qualify binary data.
227 *
228 * Full function call:
229 * ::Rappture::encoding::decode ?-as z|b64|zb64? <string>
230 *
231 *        I'd rather the interface be
232 *       
233 *                decode -b64 -z string
234 */
235
236typedef struct {
237    unsigned int flags;
238} DecodeSwitches;
239
240static SwitchSpec decodeSwitches[] =
241{
242    {SWITCH_CUSTOM, "-as", "z|b64|zb64",
243        offsetof(DecodeSwitches, flags), 0, 0, &asSwitch},
244    {SWITCH_BITMASK, "-noheader", "",
245        offsetof(DecodeSwitches, flags), 0, RPENC_RAW},
246    {SWITCH_END}
247};
248
249static int
250DecodeCmd(ClientData clientData, Tcl_Interp *interp, int objc,
251          Tcl_Obj *const *objv)
252{
253    if (objc < 1) {
254        Tcl_AppendResult(interp, "wrong # args: should be \"",
255                Tcl_GetString(objv[0]),
256                " ?-as z|b64|zb64? ?--? <string>\"", (char*)NULL);
257        return TCL_ERROR;
258    }
259
260    DecodeSwitches switches;
261    switches.flags = 0;
262    int n;
263    n = Rp_ParseSwitches(interp, decodeSwitches, objc - 1, objv + 1, &switches,
264        SWITCH_OBJV_PARTIAL);
265    if (n < 0) {
266        return TCL_ERROR;
267    }
268    int last;
269    last = n + 1;
270    if ((objc - last) != 1) {
271        Tcl_AppendResult(interp, "wrong # args: should be \"",
272                Tcl_GetString(objv[0]),
273                " ?-as z|b64|zb64? ?--? string\"", (char*)NULL);
274        return TCL_ERROR;
275    }
276    int numBytes;
277    const char *string;
278
279    string = Tcl_GetStringFromObj(objv[last], &numBytes);
280    if ((switches.flags == 0) && (strncmp(string, "@@RP-ENC:", 9) != 0)) {
281        /* This string doesn't have a header, so it's not encoded.
282         * Just return the string as-is. */
283        Tcl_SetObjResult(interp, objv[last]);
284        return TCL_OK;
285    }
286    Rappture::Buffer buf(string, numBytes);
287    Rappture::Outcome status;
288    if (!Rappture::encoding::decode(status, buf, switches.flags)) {
289        Tcl_AppendResult(interp, status.remark(), "\n", status.context(), NULL);
290        return TCL_ERROR;
291    }
292    Tcl_SetByteArrayObj(Tcl_GetObjResult(interp),
293                        (const unsigned char *)buf.bytes(), buf.size());
294    return TCL_OK;
295}
296
297static int
298DebugCmd(ClientData clientData, Tcl_Interp *interp, int objc,
299          Tcl_Obj *const *objv)
300{
301    if (objc < 1) {
302        Tcl_AppendResult(interp, "wrong # args: should be \"",
303                Tcl_GetString(objv[0]), " string\"", (char*)NULL);
304        return TCL_ERROR;
305    }
306    int numBytes;
307    const char* string;
308    int i;
309    string = Tcl_GetStringFromObj(objv[objc-1], &numBytes);
310    fprintf(stderr, "string=%s, bytes=", string);
311    for (i = 0; i < numBytes; i++) {
312        fprintf(stderr, "%02x ", string[i]);
313    }
314    fprintf(stderr, "\n");
315    return TCL_OK;
316}
Note: See TracBrowser for help on using the repository browser.