libdap  Updated for version 3.17.0
chunked_istream.h
00001 // -*- mode: c++; c-basic-offset:4 -*-
00002 
00003 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00004 // Access Protocol.
00005 
00006 // Copyright (c) 2013 OPeNDAP, Inc.
00007 // Author: James Gallagher <jgallagher@opendap.org>
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Lesser General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //
00023 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00024 //
00025 // Portions of this code were taken verbatim from Josuttis,
00026 // "The C++ Standard Library," p.672
00027 
00028 #ifndef _chunked_istream_h
00029 #define _chunked_istream_h
00030 
00031 #include "chunked_stream.h"
00032 
00033 #include <stdint.h>
00034 
00035 #include <streambuf>
00036 #include <istream>
00037 #include <stdexcept>
00038 #include <string>
00039 
00040 namespace libdap {
00041 
00042 class chunked_inbuf: public std::streambuf {
00043 private:
00044         std::istream &d_is;
00045 
00046         uint32_t d_buf_size;    // Size of the data buffer
00047         char *d_buffer;                 // data buffer
00048 
00049         // In the original implementation of this class, the byte order of the data stream
00050         // was passed in via constructors. When BYTE_ORDER_PREFIX is defined that is the
00051         // case. However, when it is not defined, the byte order is read from the chunk
00052         // header's high order byte (in bit position 2 - see chunked_stream.h). jhrg 11/24/13
00053 
00054         bool d_twiddle_bytes;   // receiver-makes-right encoding (byte order)...
00055         bool d_set_twiddle;
00056 
00057         // If an error chunk is read, save the message here
00058         std::string d_error_message;
00059         bool d_error;
00060 
00067         void m_buffer_alloc() {
00068                 delete d_buffer;
00069                 d_buffer = new char[d_buf_size];
00070                 setg(d_buffer,  // beginning of put back area
00071                          d_buffer,      // read position
00072                      d_buffer); // end position
00073         }
00074 
00075 public:
00098 #if BYTE_ORDER_PREFIX
00099         chunked_inbuf(std::istream &is, int size, bool twiddle_bytes = false)
00100         : d_is(is), d_buf_size(size), d_buffer(0), d_twiddle_bytes(twiddle_bytes), d_error(false) {
00101                 if (d_buf_size & CHUNK_TYPE_MASK)
00102                         throw std::out_of_range("A chunked_outbuf (or chunked_ostream) was built using a buffer larger than 0x00ffffff");
00103 
00104                 m_buffer_alloc();
00105         }
00106 #else
00107     chunked_inbuf(std::istream &is, int size)
00108         : d_is(is), d_buf_size(size), d_buffer(0), d_twiddle_bytes(false), d_set_twiddle(false), d_error(false) {
00109         if (d_buf_size & CHUNK_TYPE_MASK)
00110             throw std::out_of_range("A chunked_outbuf (or chunked_ostream) was built using a buffer larger than 0x00ffffff");
00111 
00112         m_buffer_alloc();
00113     }
00114 #endif
00115 
00116         virtual ~chunked_inbuf() {
00117                 delete d_buffer;
00118         }
00119 
00120         int_type read_next_chunk();
00121 
00122         int bytes_in_buffer() const { return (egptr() - gptr()); }
00123 
00124         // d_twiddle_bytes is false initially and is set to the correct value
00125         // once the first chunk is read.
00126         bool twiddle_bytes() const { return d_twiddle_bytes; }
00127 
00128         bool error() const { return d_error; }
00129         std::string error_message() const { return d_error_message; }
00130 
00131 protected:
00132         virtual int_type underflow();
00133 
00134         virtual std::streamsize xsgetn(char* s, std::streamsize num);
00135 };
00136 
00137 class chunked_istream: public std::istream {
00138 protected:
00139         chunked_inbuf d_cbuf;
00140 public:
00141 #if BYTE_ORDER_PREFIX
00142         chunked_istream(std::istream &is, int size, bool twiddle_bytes = false) : std::istream(&d_cbuf), d_cbuf(is, size, twiddle_bytes) { }
00143 #else
00144     chunked_istream(std::istream &is, int size) : std::istream(&d_cbuf), d_cbuf(is, size) { }
00145 #endif
00146 
00147         int read_next_chunk() { return d_cbuf.read_next_chunk(); }
00148 
00153         int bytes_in_buffer() const { return d_cbuf.bytes_in_buffer(); }
00154 
00165         bool twiddle_bytes() const { return d_cbuf.twiddle_bytes(); }
00166         bool error() const { return d_cbuf.error(); }
00167         std::string error_message() const { return d_cbuf.error_message(); }
00168 };
00169 
00170 }
00171 
00172 #endif  // _chunked_istream_h