source: trunk/src/core/RpEncode.cc @ 1413

Last change on this file since 1413 was 1413, checked in by gah, 15 years ago
File size: 7.1 KB
Line 
1
2/*
3 * ----------------------------------------------------------------------
4 *  Rappture::encoding
5 *
6 *  The encoding module for rappture used to zip and b64 encode data.
7 * ======================================================================
8 *  AUTHOR:  Derrick Kearney, Purdue University
9 *  Copyright (c) 2004-2007  Purdue Research Foundation
10 *
11 *  See the file "license.terms" for information on usage and
12 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 * ======================================================================
14 */
15#include "RpEncode.h"
16#include <cstring>
17
18/**********************************************************************/
19// FUNCTION: Rappture::encoding::isbinary()
20/// isbinary checks to see if given string is binary.
21/**
22 * Checks to see if any of size characters in *buf are binary
23 * Full function call:
24 * Rappture::encoding::isbinary(buf,size);
25 *
26 */
27
28bool
29Rappture::encoding::isBinary(const char* buf, int size)
30{
31    if (buf == NULL) {
32        return 0;
33    }
34    if (size < 0) {
35        size = strlen(buf);
36    }
37    const char *cp, *endPtr;
38    for (cp = buf, endPtr = buf + size; cp < endPtr; cp++) {
39        if (!isprint(*cp)) {
40            return true;
41        }
42    }
43    return false;
44}
45
46bool
47Rappture::encoding::isBase64(const char* buf, int size)
48{
49    if (buf == NULL) {
50        return 0;
51    }
52    if (size < 0) {
53        size = strlen(buf);
54    }
55    const char *cp, *endPtr;
56    for (cp = buf, endPtr = buf + size; cp < endPtr; cp++) {
57        if (((*cp < 'A') || (*cp > '/')) && (!isspace(*cp)) && (*cp != '=')) {
58            return false;
59        }
60    }
61    return true;
62}
63
64/**********************************************************************/
65// FUNCTION: Rappture::encoding::headerFlags()
66/// checks header of given string to determine if it was encoded by rappture.
67/**
68 * Checks to see if the string buf was encoded by rappture
69 * and contains the proper "@@RP-ENC:" header.
70 * rappture encoded strings start with the string "@@RP-ENC:X\n"
71 * where X is one of z, b64, zb64
72 * This function will not work for strings that do not have the header.
73 * Full function call:
74 * Rappture::encoding::headerFlags(buf,size);
75 *
76 */
77
78unsigned int
79Rappture::encoding::headerFlags(const char* buf, int size)
80{
81    size_t flags = 0;
82    size_t len = 0;
83
84    if (buf == NULL) {
85        return flags;
86    }
87
88    if (size < 0) {
89        len = strlen(buf);
90    } else {
91        len = size;
92    }
93
94    // check the following for valid rappture encoded string:
95    // all strings encoded by rappture are at least 11 characters
96    // rappture encoded strings start with the '@' character
97    // rappture encoded strings start with the string "@@RP-ENC:X\n"
98    // where X is one of z, b64, zb64
99    if ((len >= 11) &&  ('@' == *buf) &&  (strncmp("@@RP-ENC:",buf,9) == 0) ) {
100
101        size_t idx = 9;
102
103        // check the string length and if the z flag was specified
104        // add 1 for \n
105        if (    (len >= (idx + 1))
106            &&  (buf[idx] == 'z') ) {
107            flags |= RPENC_Z;
108            ++idx;
109        }
110        // check the string length and if the b64 flag was specified
111        // add 1 for \n
112        if (    (len >= (idx + 2 + 1))
113            &&  (buf[idx]   == 'b')
114            &&  (buf[idx+1] == '6')
115            &&  (buf[idx+2] == '4') ) {
116            flags |= RPENC_B64;
117            idx += 3;
118        }
119        // check for the '\n' at the end of the header
120        if (buf[idx] != '\n') {
121            flags = 0;
122        }
123    }
124    return flags;
125}
126
127/**********************************************************************/
128// FUNCTION: Rappture::encoding::encode()
129/// Rappture::encoding::encode function encodes provided string
130/**
131 * Encode a string by compressing it with zlib and then base64 encoding it.
132 *
133 * Full function call:
134 * Rappture::encoding::encode(buf,flags)
135 */
136
137bool
138Rappture::encoding::encode(Rappture::Outcome &status, Rappture::Buffer& buf,
139                           unsigned int flags)
140{
141    Rappture::Buffer outData;
142
143    if (buf.size() <= 0) {
144        return true;            // Nothing to encode.
145    }
146    if ((flags & (RPENC_Z | RPENC_B64)) == 0) {
147        // By default compress and encode the string.
148        flags |= RPENC_Z | RPENC_B64;
149    }
150    if (outData.append(buf.bytes(), buf.size()) != (int)buf.size()) {
151        status.addError("can't append %lu bytes", buf.size());
152        return false;
153    }
154    if (!outData.encode(status, flags)) {
155        return false;
156    }
157    buf.clear();
158    if ((flags & RPENC_RAW) == 0) {
159        switch (flags & (RPENC_Z | RPENC_B64)) {
160        case RPENC_Z:
161            buf.append("@@RP-ENC:z\n", 11);
162            break;
163        case RPENC_B64:
164            buf.append("@@RP-ENC:b64\n", 13);
165            break;
166        case (RPENC_B64 | RPENC_Z):
167            buf.append("@@RP-ENC:zb64\n", 14);
168            break;
169        default:
170            break;
171        }
172    }
173    if (buf.append(outData.bytes(),outData.size()) != (int)outData.size()) {
174        status.addError("can't append %d bytes", outData.size());
175        return false;
176    }
177    return true;
178}
179
180/**********************************************************************/
181// FUNCTION: Rappture::encoding::decode()
182/// Rappture::encoding::decode function decodes provided string
183/**
184 * Decode a string by uncompressing it with zlib and base64 decoding it.
185 * If binary data is provided, the data is base64 decoded and uncompressed.
186 * Rappture::encoding::isbinary is used to qualify binary data.
187 *
188 * Full function call:
189 * Rappture::encoding::decode(context, buf,flags)
190 *
191 * The check header flag is confusing here.
192 */
193
194bool
195Rappture::encoding::decode(Rappture::Outcome &status, Rappture::Buffer& buf,
196                           unsigned int flags)
197{
198    Rappture::Buffer outData;
199
200    const char *bytes;
201
202    size_t size;
203    size = buf.size();
204    if (size == 0) {
205        return true;            // Nothing to decode.
206    }
207    bytes = buf.bytes();
208    if ((flags & RPENC_RAW) == 0) {
209        unsigned int headerFlags = 0;
210        if ((size > 11) && (strncmp(bytes, "@@RP-ENC:z\n", 11) == 0)) {
211            bytes += 11;
212            size -= 11;
213            headerFlags |= RPENC_Z;
214        } else if ((size > 13) && (strncmp(bytes, "@@RP-ENC:b64\n", 13) == 0)){
215            bytes += 13;
216            size -= 13;
217            headerFlags |= RPENC_B64;
218        } else if ((size > 14) && (strncmp(bytes, "@@RP-ENC:zb64\n", 14) == 0)){
219            bytes += 14;
220            size -= 14;
221            headerFlags |= (RPENC_B64 | RPENC_Z);
222        }
223        if (headerFlags != 0) {
224            unsigned int reqFlags;
225
226            reqFlags = flags & (RPENC_B64 | RPENC_Z);
227            /*
228             * If there's a header and the programmer also requested decoding
229             * flags, verify that the two are the same.  We don't want to
230             * penalize the programmer for over-specifying.  But we need to
231             * catch cases when they don't match.  If you really want to
232             * override the header, you should also specify the RPENC_RAW flag
233             * (-noheader).
234             */
235            if ((reqFlags != 0) && (reqFlags != headerFlags)) {
236                status.addError("decode flags don't match the header");
237                return false;
238            }
239            flags |= headerFlags;
240        }
241    }
242    if ((flags & (RPENC_B64 | RPENC_Z)) == 0) {
243        return true;            /* No decode or decompress flags present. */
244    }
245    if (outData.append(bytes, size) != (int)size) {
246        status.addError("can't append %d bytes to buffer", size);
247        return false;
248    }
249    if (!outData.decode(status, flags)) {
250        return false;
251    }
252    buf.move(outData);
253    return true;
254}
Note: See TracBrowser for help on using the repository browser.