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

Last change on this file since 2408 was 2408, checked in by dkearney, 11 years ago

adding a getFile function for rappture library and fortran bindings so fortran users no longer need to know the length of a string a user provides them as input, before compile time. they can now just dump the string into a file, and read the file as they are probably already used to doing. also fixed a bug in teh Rappture::Buffer dump function where it would correctly open a file pointer, but failed the check to see if the file pointer was opened.

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.