source: trunk/lang/tcl/src/RpEncodeTclInterface.cc @ 1383

Last change on this file since 1383 was 1383, checked in by gah, 15 years ago

add switch parser to encoding routines

File size: 8.6 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-2007  Purdue Research Foundation
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 RpTclEncodingIs;
22static Tcl_ObjCmdProc RpTclEncodingEncode;
23static Tcl_ObjCmdProc RpTclEncodingDecode;
24
25/**********************************************************************/
26// FUNCTION: RpEncoding_Init()
27/// Initializes the Rappture Encoding module and commands defined below
28/**
29 * Called in RapptureGUI_Init() to initialize the Rappture Units module.
30 * Initialized commands include:
31 * ::Rappture::encoding::is
32 * ::Rappture::encoding::encode
33 * ::Rappture::encoding::decode
34 */
35
36int
37RpEncoding_Init(Tcl_Interp *interp)
38{
39
40    Tcl_CreateObjCommand(interp, "::Rappture::encoding::is",
41        RpTclEncodingIs, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
42
43    Tcl_CreateObjCommand(interp, "::Rappture::encoding::encode",
44        RpTclEncodingEncode, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
45
46    Tcl_CreateObjCommand(interp, "::Rappture::encoding::decode",
47        RpTclEncodingDecode, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
48
49    return TCL_OK;
50}
51
52/**********************************************************************/
53// FUNCTION: RpTclEncodingIs()
54/// Rappture::encoding::is checks to see if given string is binary.
55/**
56 * Checks to see <string> is binary
57 * Full function call:
58 * ::Rappture::encoding::is binary <string>
59 *
60 */
61
62static int
63RpTclEncodingIs (ClientData cdata, Tcl_Interp *interp,
64    int objc, Tcl_Obj *const objv[])
65{
66    Tcl_ResetResult(interp);
67
68    // parse through command line options
69    if (objc != 3) {
70        Tcl_AppendResult(interp,
71            "wrong # args: should be \"",
72            Tcl_GetString(objv[0])," binary|encoded <string>\"",
73            (char*)NULL);
74        return TCL_ERROR;
75    }
76
77
78    int bufLen;
79    const char *buf;
80    const char *string;
81    buf = (const char*) Tcl_GetByteArrayFromObj(objv[2], &bufLen);
82    const char *type = Tcl_GetString(objv[1]);
83    if (('b' == *type) && (strcmp(type,"binary") == 0)) {
84        bool isBinary;
85
86        isBinary = (Rappture::encoding::isbinary(buf,bufLen) != 0);
87        string = (isBinary) ? "yes" : "no" ;
88    } else if (('e' == *type) && (strcmp(type,"encoded") == 0)) {
89        bool isEncoded;
90
91        isEncoded = (Rappture::encoding::headerFlags(buf, bufLen) != 0);
92        string = (isEncoded) ? "yes" : "no" ;
93    } else {
94        Tcl_AppendResult(interp, "bad option \"", type,
95                "\": should be binary or encoded", (char*)NULL);
96        return TCL_ERROR;
97    }
98    Tcl_SetResult(interp, (char *)string, TCL_STATIC);
99    return TCL_OK;
100}
101
102/**********************************************************************/
103// FUNCTION: RpTclEncodingEncode()
104/// Rappture::encoding::encode function in Tcl, encodes provided string
105/**
106 * Encode a string by compressing it with zlib and then base64 encoding it.
107 * If binary data is provided, the data is compressed and base64 encoded.
108 * RpTclEncodingIs is used to qualify binary data.
109 *
110 * If the -as option is not set, zlib compression and base64 encoding
111 * is performed by default
112 *
113 * Full function call:
114 * ::Rappture::encoding::encode ?-as z|b64|zb64? ?-no-header? <string>
115 */
116
117/*
118 *---------------------------------------------------------------------------
119 *
120 * AsSwitch --
121 *
122 *      Convert a string represent a node number into its integer
123 *      value.
124 *
125 * Results:
126 *      The return value is a standard Tcl result.
127 *
128 *---------------------------------------------------------------------------
129 */
130/*ARGSUSED*/
131static int
132AsSwitch(
133    ClientData clientData,      /* Not used. */
134    Tcl_Interp *interp,         /* Interpreter to send results back to */
135    const char *switchName,     /* Not used. */
136    Tcl_Obj *objPtr,            /* String representation */
137    char *record,               /* Structure record */
138    int offset,                 /* Offset to field in structure */
139    int flags)                  /* Not used. */
140{
141    int *flagsPtr = (int *)(record + offset);
142    char c;
143    char *string;
144
145    string = Tcl_GetString(objPtr);
146    c = string[0];
147    if ((c == 'b') && (strcmp(string, "b64") == 0)) {
148        *flagsPtr = RPENC_B64;
149    } else if ((c == 'z') && (strcmp(string, "zb64") == 0)) {
150        *flagsPtr = RPENC_Z  | RPENC_B64;
151    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
152        *flagsPtr = RPENC_Z;
153    } else {
154        Tcl_AppendResult(interp, "bad order \"", string,
155                 "\": should be breadthfirst, inorder, preorder, or postorder",
156                 (char *)NULL);
157        return TCL_ERROR;
158    }
159    return TCL_OK;
160}
161
162static SwitchParseProc AsSwitch;
163static SwitchCustom asSwitch = {
164    AsSwitch, NULL, 0,
165};
166
167typedef struct {
168    unsigned int flags;
169    unsigned int noheader;
170} EncodeSwitches;
171
172static SwitchSpec encodeSwitches[] =
173{
174    {SWITCH_CUSTOM, "-as", "z|b64|zb64",
175        offsetof(EncodeSwitches, flags), 0, 0, &asSwitch},
176    {SWITCH_VALUE, "-no-header", "",
177        offsetof(EncodeSwitches, noheader), 0, true},
178    {SWITCH_END}
179};
180
181static int
182RpTclEncodingEncode (ClientData cdata, Tcl_Interp *interp, int objc,
183                     Tcl_Obj *const *objv)
184{
185    if (objc < 1) {
186        Tcl_AppendResult(interp, "wrong # args: should be \"",
187                Tcl_GetString(objv[0]),
188                " ?-as z|b64|zb64? ?-no-header? ?--? string\"", (char*)NULL);
189        return TCL_ERROR;
190    }
191    EncodeSwitches switches;
192    switches.flags = 0;
193    switches.noheader = 0;
194    int n;
195    n = Rp_ParseSwitches(interp, encodeSwitches, objc - 1, objv + 1, &switches,
196                         SWITCH_OBJV_PARTIAL);
197    if (n < 0) {
198        return TCL_ERROR;
199    }
200    int last;
201    last = n + 1;
202    if ((objc - last) != 1) {
203        Tcl_AppendResult(interp, "wrong # args: should be \"",
204                Tcl_GetString(objv[0]),
205                " ?-as z|b64|zb64? ?-no-header? ?--? string\"", (char*)NULL);
206        return TCL_ERROR;
207    }
208    int nBytes;
209    const char* string;
210    string = (const char*)Tcl_GetByteArrayFromObj(objv[last], &nBytes);
211    if (nBytes <= 0) {
212        return TCL_OK;          // Nothing to encode.
213    }
214    Rappture::Buffer buf(string, nBytes);
215    if (!switches.noheader) {
216        switches.flags |= RPENC_HDR;
217    }
218    Rappture::Outcome status;
219    if (!Rappture::encoding::encode(status, buf, switches.flags)) {
220        Tcl_AppendResult(interp, status.remark(), "\n", status.context(), NULL);
221        return TCL_ERROR;
222    }
223    Tcl_SetByteArrayObj(Tcl_GetObjResult(interp),
224                (const unsigned char*)buf.bytes(), buf.size());
225    return TCL_OK;
226}
227
228/**********************************************************************/
229// FUNCTION: RpTclEncodingDecode()
230/// Rappture::encoding::decode function in Tcl, decodes provided string
231/**
232 * Decode a string by uncompressing it with zlib and base64 decoding it.
233 * If binary data is provided, the data is base64 decoded and uncompressed.
234 * RpTclEncodingIs is used to qualify binary data.
235 *
236 * Full function call:
237 * ::Rappture::encoding::decode ?-as z|b64|zb64? <string>
238 */
239
240typedef struct {
241    unsigned int flags;
242} DecodeSwitches;
243
244static SwitchSpec decodeSwitches[] =
245{
246    {SWITCH_CUSTOM, "-as", "z|b64|zb64",
247        offsetof(DecodeSwitches, flags), 0, 0, &asSwitch},
248    {SWITCH_END}
249};
250
251static int
252RpTclEncodingDecode(ClientData clientData, Tcl_Interp *interp, int objc,
253                    Tcl_Obj *const *objv)
254{
255    if (objc < 1) {
256        Tcl_AppendResult(interp, "wrong # args: should be \"",
257                Tcl_GetString(objv[0]),
258                " ?-as z|b64|zb64? ?--? <string>\"", (char*)NULL);
259        return TCL_ERROR;
260    }
261
262    DecodeSwitches switches;
263    switches.flags = 0;
264    int n;
265    n = Rp_ParseSwitches(interp, decodeSwitches, objc - 1, objv + 1, &switches,
266                         SWITCH_OBJV_PARTIAL);
267    if (n < 0) {
268        return TCL_ERROR;
269    }
270    int last;
271    last = n + 1;
272    if ((objc - last) != 1) {
273        Tcl_AppendResult(interp, "wrong # args: should be \"",
274                Tcl_GetString(objv[0]),
275                " ?-as z|b64|zb64? ?--? string\"", (char*)NULL);
276        return TCL_ERROR;
277    }
278    int nBytes;
279    const char* string;
280    string = (const char*)Tcl_GetByteArrayFromObj(objv[last], &nBytes);
281    if (nBytes <= 0) {
282        return TCL_OK;          // Nothing to decode.
283    }
284    Rappture::Buffer buf(string, nBytes);
285    Rappture::Outcome status;
286    if (!Rappture::encoding::decode(status, buf, switches.flags)) {
287        Tcl_AppendResult(interp, status.remark(), "\n", status.context(), NULL);
288        return TCL_ERROR;
289    }
290    Tcl_SetByteArrayObj(Tcl_GetObjResult(interp),
291                (const unsigned char*)buf.bytes(), buf.size());
292    return TCL_OK;
293}
Note: See TracBrowser for help on using the repository browser.