source: trunk/src/core/RpBuffer.cc @ 1731

Last change on this file since 1731 was 1527, checked in by dkearney, 15 years ago

various code cleanups, mainly tabs. adding units ohms and amps, adding appendf interface to the simple buffer so we can append formatted strings.

File size: 11.5 KB
Line 
1/*
2 * ======================================================================
3 *  Rappture::Buffer
4 *
5 *  AUTHOR:  Derrick Kearney, Purdue University
6 *
7 *  Copyright (c) 2004-2008  Purdue Research Foundation
8 * ----------------------------------------------------------------------
9 *  See the file "license.terms" for information on usage and
10 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 * ======================================================================
12 */
13
14#include <assert.h>
15#include <errno.h>
16#include <stdio.h>
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <unistd.h>
20#include <fstream>
21#include <zlib.h>
22#include "b64/encode.h"
23#include "b64/decode.h"
24#include "RpBuffer.h"
25#include "RpEncode.h"
26
27namespace Rappture {
28
29/**
30 * Construct an empty Buffer.
31 */
32Buffer::Buffer()
33  : SimpleCharBuffer(),
34    _level(6),
35    _compressionType(RPCOMPRESS_GZIP),
36    _windowBits(15)
37{}
38
39
40/**
41 * Construct an empty Buffer of specified size.
42 */
43Buffer::Buffer(int nbytes)
44  : SimpleCharBuffer(nbytes),
45    _level(6),
46    _compressionType(RPCOMPRESS_GZIP),
47    _windowBits(15)
48{}
49
50
51/**
52 * Construct a Buffer loaded with initial data.
53 *
54 * @param bytes pointer to bytes being stored.
55 * @param nbytes number of bytes being stored.
56 */
57Buffer::Buffer(const char* bytes, int nbytes)
58  : SimpleCharBuffer(bytes,nbytes),
59    _level(6),
60    _compressionType(RPCOMPRESS_GZIP),
61    _windowBits(15)
62{}
63
64/**
65 * Copy constructor
66 * @param Buffer object to copy
67 */
68Buffer::Buffer(const Buffer& b)
69  : SimpleCharBuffer(b),
70    _level(b._level),
71    _compressionType(b._compressionType),
72    _windowBits(b._windowBits)
73{}
74
75/**
76 * Assignment operator
77 * @param Buffer object to copy
78 */
79Buffer&
80Buffer::operator=(const Buffer& b)
81{
82    SimpleCharBuffer::operator=(b);
83
84    _level = b._level;
85    _compressionType = b._compressionType;
86    _windowBits = b._windowBits;
87
88    return *this;
89}
90
91
92Buffer
93Buffer::operator+(const Buffer& b) const
94{
95    Buffer newBuffer(*this);
96    newBuffer.operator+=(b);
97    return newBuffer;
98}
99
100
101Buffer&
102Buffer::operator+=(const Buffer& b)
103{
104    SimpleCharBuffer::operator+=(b);
105    return *this;
106}
107
108
109Buffer::~Buffer()
110{}
111
112
113bool
114Buffer::load (Outcome &status, const char* filePath)
115{
116    status.addContext("Rappture::Buffer::load()");
117
118    FILE *f;
119    f = fopen(filePath, "rb");
120    if (f == NULL) {
121        status.addError("can't open \"%s\": %s", filePath, strerror(errno));
122        return false;
123    }
124    struct stat stat;
125    if (fstat(fileno(f), &stat) < 0) {
126        status.addError("can't stat \"%s\": %s", filePath, strerror(errno));
127        return false;
128    }
129    off_t size;
130    size = stat.st_size;
131    char* memblock;
132    memblock = new char [size];
133    if (memblock == NULL) {
134        status.addError("can't allocate %d bytes for file \"%s\": %s",
135                        size, filePath, strerror(errno));
136        fclose(f);
137        return false;
138    }
139
140    // FIXME: better yet, create an "extend" method in the buffer and returns
141    //             the address of the char buffer so I can read the data directly
142    //             into the buffer.  This eliminates memory new/copy/delete ops.
143
144    size_t nRead;
145    nRead = fread(memblock, sizeof(char), size, f);
146    fclose(f);                        // Close the file.
147
148    if (nRead != (size_t)size) {
149        status.addError("can't read %d bytes from \"%s\": %s", size, filePath,
150                        strerror(errno));
151        return false;
152    }
153
154    int nBytes;
155    nBytes = append(memblock, size);
156    delete [] memblock;
157
158    if (nBytes != size) {
159        status.addError("can't append %d bytes from \"%s\" to buffer: %s",
160                size, filePath, strerror(errno));
161        return false;
162    }
163    return true;
164}
165
166
167bool
168Buffer::dump (Outcome &status, const char* filePath)
169{
170    status.addContext("Rappture::Buffer::dump()");
171
172    FILE *f;
173    f = fopen(filePath, "wb");
174    if (f != NULL) {
175        status.addError("can't open \"%s\": %s\n", filePath, strerror(errno));
176        return false;
177    }
178    ssize_t nWritten;
179    nWritten = fwrite(bytes(), size(), sizeof(char), f);
180    fclose(f);                        // Close the file.
181
182    if (nWritten != (ssize_t)size()) {
183        status.addError("can't write %d bytes to \"%s\": %s\n", size(),
184                        filePath, strerror(errno));
185        return false;
186    }
187    return true;
188}
189
190
191bool
192Buffer::encode(Outcome &status, unsigned int flags)
193{
194    SimpleCharBuffer bout;
195
196    rewind();
197
198    switch (flags & (RPENC_Z | RPENC_B64)) {
199    case 0:
200        break;
201
202    case RPENC_Z:                // Compress only
203        if (!do_compress(status, *this, bout)) {
204            return false;
205        }
206        move(bout);
207        break;
208
209    case RPENC_B64:                // Encode only
210        if (!do_base64_enc(status, *this, bout)) {
211            return false;
212        }
213        move(bout);
214        break;
215
216    case (RPENC_B64 | RPENC_Z):
217
218        // It's always compress then encode
219        if (!do_compress(status, *this, bout)) {
220            return false;
221        }
222        if (!do_base64_enc(status, bout, *this)) {
223            return false;
224        }
225        break;
226    }
227    return true;
228}
229
230
231bool
232Buffer::decode(Outcome &status, unsigned int flags)
233{
234    SimpleCharBuffer bout;
235
236    rewind();
237
238    switch (flags & (RPENC_Z | RPENC_B64)) {
239    case 0:
240        if (encoding::isBase64(bytes(), size())) {
241            if (!do_base64_dec(status, *this, bout)) {
242                return false;
243            }
244            move(bout);
245        }
246        bout.clear();
247        if (encoding::isBinary(bytes(), size())) {
248            if (!do_decompress(status, *this, bout)) {
249                return false;
250            }
251            move(bout);
252        }
253        break;
254
255    case RPENC_Z:                // Decompress only
256        if (!do_decompress(status, *this, bout)) {
257            return false;
258        }
259        move(bout);
260        break;
261
262    case RPENC_B64:                // Decode only
263        if (!do_base64_dec(status, *this, bout)) {
264            return false;
265        }
266        move(bout);
267        break;
268
269    case (RPENC_B64 | RPENC_Z):
270
271        // It's always decode then decompress
272        if (!do_base64_dec(status, *this, bout)) {
273            return false;
274        }
275        clear();
276        if (!do_decompress(status, bout, *this)) {
277            return false;
278        }
279        break;
280    }
281    return true;
282}
283
284
285bool
286Buffer::do_compress(Outcome& status, SimpleCharBuffer& bin,
287                    SimpleCharBuffer& bout)
288{
289    int ret=0, flush=0;
290    unsigned have=0;
291    z_stream strm;
292
293    char in[CHUNK];
294    char out[CHUNK];
295
296    int bytesWritten = 0;
297
298    /* allocate deflate state */
299    strm.zalloc = Z_NULL;
300    strm.zfree = Z_NULL;
301    strm.opaque = Z_NULL;
302
303    status.addContext("Rappture::Buffer::do_compress()");
304
305    ret = deflateInit2( &strm, _level, Z_DEFLATED,
306                        _windowBits+_compressionType,
307                        8, Z_DEFAULT_STRATEGY);
308
309    if (ret != Z_OK) {
310        status.addError("error while initializing zlib stream object");
311        return false;
312    }
313
314    /* compress until end of file */
315    do {
316        strm.avail_in = bin.read(in, CHUNK);
317        if (bin.bad() == true) {
318            (void)deflateEnd(&strm);
319            // return Z_ERRNO;
320            status.addError("error while compressing");
321            return false;
322        }
323        flush = bin.eof() ? Z_FINISH : Z_NO_FLUSH;
324        strm.next_in = (Bytef*) in;
325        /* run deflate() on input until output buffer not full, finish
326           compression if all of source has been read in */
327        do {
328            strm.avail_out = CHUNK;
329            strm.next_out = (Bytef*) out;
330            ret = deflate(&strm, flush);    /* no bad return value */
331            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
332            have = CHUNK - strm.avail_out;
333            /* write to file and check for error */
334            bytesWritten = bout.append(out, have);
335            if ( ( (unsigned) bytesWritten != have ) ) {
336                (void)deflateEnd(&strm);
337                bout.clear();
338                // return Z_ERRNO;
339                status.addError("error writing compressed data to temp buffer");
340                return false;
341            }
342
343        } while (strm.avail_out == 0);
344        assert(strm.avail_in == 0);     /* all input will be used */
345
346        /* done when last data in file processed */
347    } while (flush != Z_FINISH);
348
349    assert(ret == Z_STREAM_END);        /* stream will be complete */
350
351    /* clean up and return */
352    (void)deflateEnd(&strm);
353    // return Z_OK;
354    return true;
355}
356
357bool
358Buffer::do_decompress(Outcome& status, SimpleCharBuffer& bin,
359                      SimpleCharBuffer& bout)
360{
361    int ret;
362    unsigned have;
363    z_stream strm;
364
365    char in[CHUNK];
366    char out[CHUNK];
367
368    int bytesWritten = 0;
369
370    status.addContext("Rappture::Buffer::do_decompress()");
371
372    /* allocate inflate state */
373    strm.zalloc = Z_NULL;
374    strm.zfree = Z_NULL;
375    strm.opaque = Z_NULL;
376    strm.avail_in = 0;
377    strm.next_in = Z_NULL;
378    ret = inflateInit2(&strm,_windowBits+_compressionType);
379    if (ret != Z_OK) {
380        status.addError("error while initializing zlib stream object");
381        return false;
382    }
383
384    /* decompress until deflate stream ends or end of file */
385    do {
386        strm.avail_in = bin.read(in, CHUNK);
387        if (bin.bad() == true) {
388            (void)inflateEnd(&strm);
389            // return Z_ERRNO;
390            status.addError("error while compressing");
391            return false;
392        }
393        if (strm.avail_in == 0)
394            break;
395        strm.next_in = (unsigned char*) in;
396        /* run inflate() on input until output buffer not full */
397        do {
398            strm.avail_out = CHUNK;
399            strm.next_out = (unsigned char*) out;
400            ret = inflate(&strm, Z_NO_FLUSH);
401            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
402            switch (ret) {
403            case Z_NEED_DICT:
404                ret = Z_DATA_ERROR;     /* and fall through */
405            case Z_DATA_ERROR:
406            case Z_MEM_ERROR:
407                (void)inflateEnd(&strm);
408                bout.clear();
409                status.addError("memory error while inflating data");
410                return false;
411            }
412            have = CHUNK - strm.avail_out;
413            bytesWritten = bout.append(out, have);
414            if ( ( (unsigned) bytesWritten != have) ) {
415                (void)inflateEnd(&strm);
416                bout.clear();
417                // return Z_ERRNO;
418                status.addError("error writing compressed data to temp buffer");
419                return false;
420            }
421        } while (strm.avail_out == 0);
422
423        /* done when inflate() says it's done */
424    } while (ret != Z_STREAM_END);
425
426    /* clean up and return */
427    (void)inflateEnd(&strm);
428    // return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
429    return true;
430}
431
432
433bool
434Buffer::do_base64_enc(Outcome& status, const SimpleCharBuffer& bin,
435                      SimpleCharBuffer& bout )
436{
437    int tBufSize = 0;
438    unsigned int tBufAvl = 2*bin.size();
439    char* tBuf = new char[tBufAvl];
440
441    base64::encoder E;
442
443    tBufSize = E.encode(bin.bytes(),bin.size(),tBuf);
444    tBufSize += E.encode_end(tBuf+tBufSize);
445
446    bout = SimpleCharBuffer(tBuf,tBufSize);
447    delete [] tBuf;
448
449    return true;
450}
451
452
453bool
454Buffer::do_base64_dec(Outcome& status, const SimpleCharBuffer& bin,
455                      SimpleCharBuffer& bout )
456{
457    int tBufSize = 0;
458    unsigned int tBufAvl = bin.size();
459    char* tBuf = new char[tBufAvl];
460
461    base64::decoder D;
462
463    tBufSize = D.decode(bin.bytes(),bin.size(),tBuf);
464
465    bout = SimpleCharBuffer(tBuf,tBufSize);
466    delete [] tBuf;
467
468    return true;
469}
470
471
472}
473
474
475
Note: See TracBrowser for help on using the repository browser.