File: chunked_istream.h

package info (click to toggle)
libdap 3.20.3-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 22,116 kB
  • sloc: cpp: 52,168; sh: 40,006; xml: 23,505; ansic: 20,020; yacc: 2,452; exp: 1,544; makefile: 1,068; lex: 305; perl: 52; fortran: 8
file content (172 lines) | stat: -rw-r--r-- 6,370 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2013 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
//
// Portions of this code were taken verbatim from Josuttis,
// "The C++ Standard Library," p.672

#ifndef _chunked_istream_h
#define _chunked_istream_h

#include "chunked_stream.h"

#include <stdint.h>

#include <streambuf>
#include <istream>
#include <stdexcept>
#include <string>

namespace libdap {

class chunked_inbuf: public std::streambuf {
private:
	std::istream &d_is;

	uint32_t d_buf_size;	// Size of the data buffer
	char *d_buffer;			// data buffer

	// In the original implementation of this class, the byte order of the data stream
	// was passed in via constructors. When BYTE_ORDER_PREFIX is defined that is the
	// case. However, when it is not defined, the byte order is read from the chunk
	// header's high order byte (in bit position 2 - see chunked_stream.h). jhrg 11/24/13

	bool d_twiddle_bytes; 	// receiver-makes-right encoding (byte order)...
	bool d_set_twiddle;

	// If an error chunk is read, save the message here
	std::string d_error_message;
	bool d_error;

	/**
	 * @brief allocate the internal buffer.
	 * Allocate d_buf_size + putBack characters for the read buffer.
	 * @param size How much can the buffer hold? Does not include the putBack
	 * chars.
	 */
	void m_buffer_alloc() {
		delete[] d_buffer;
		d_buffer = new char[d_buf_size];
		setg(d_buffer, 	// beginning of put back area
			 d_buffer, 	// read position
		     d_buffer); // end position
	}

public:
	/**
	 * @brief Build a chunked input buffer.
	 *
	 * This reads from a chunked stream, extracting an entire chunk and storing it in a
	 * buffer in one operation. If the chunked_inbuf reads a chunk header that indicates
	 * the next chunk is going  be bigger than its current buffer size, the object will
	 * make the buffer larger. This object support 128 characters of 'put back' space. Since
	 * DAP4 uses receiver makes right, the buffer must be told if it should 'twiddle' the
	 * header size information. In DAP4 the byte order is sent using a one-byte code _before_
	 * the chunked transmission starts.
	 *
	 * @note In the current implementation, the byte order of the sender is read from the
	 * first chunk header. The method twiddle_bytes() returns false until the first chunk is
	 * read, then it returns the correct value. Only the first chunk_header is tested for the
	 * byte order flag; all subsequent chunks are assumed to use the same byte order.
	 *
	 * @param is Use this as a data source
	 * @param size The size of the input buffer. This should match the likely chunk size.
	 * If it is smaller than a chunk, it will be resized.
	 * @param twiddle_bytes Should the header bytes be twiddled? True if this host and the
	 * send use a different byte-order. The sender's byte order must be sent out-of-band.
	 */
#if BYTE_ORDER_PREFIX
	chunked_inbuf(std::istream &is, int size, bool twiddle_bytes = false)
        : d_is(is), d_buf_size(size), d_buffer(0), d_twiddle_bytes(twiddle_bytes), d_error(false) {
		if (d_buf_size & CHUNK_TYPE_MASK)
			throw std::out_of_range("A chunked_outbuf (or chunked_ostream) was built using a buffer larger than 0x00ffffff");

		m_buffer_alloc();
	}
#else
    chunked_inbuf(std::istream &is, int size)
        : d_is(is), d_buf_size(size), d_buffer(0), d_twiddle_bytes(false), d_set_twiddle(false), d_error(false) {
        if (d_buf_size & CHUNK_TYPE_MASK)
            throw std::out_of_range("A chunked_outbuf (or chunked_ostream) was built using a buffer larger than 0x00ffffff");

        m_buffer_alloc();
    }
#endif

	virtual ~chunked_inbuf() {
		delete[] d_buffer;
	}

	int_type read_next_chunk();

	int bytes_in_buffer() const { return (egptr() - gptr()); }

	// d_twiddle_bytes is false initially and is set to the correct value
	// once the first chunk is read.
	bool twiddle_bytes() const { return d_twiddle_bytes; }

	bool error() const { return d_error; }
	std::string error_message() const { return d_error_message; }

protected:
	virtual int_type underflow();

	virtual std::streamsize xsgetn(char* s, std::streamsize num);
};

class chunked_istream: public std::istream {
protected:
	chunked_inbuf d_cbuf;
public:
#if BYTE_ORDER_PREFIX
	chunked_istream(std::istream &is, int size, bool twiddle_bytes = false) : std::istream(&d_cbuf), d_cbuf(is, size, twiddle_bytes) { }
#else
    chunked_istream(std::istream &is, int size) : std::istream(&d_cbuf), d_cbuf(is, size) { }
#endif

	int read_next_chunk() { return d_cbuf.read_next_chunk(); }

	/**
	 * How many bytes have been read from the stream and are now in the internal buffer?
	 * @return Number of buffered bytes.
	 */
	int bytes_in_buffer() const { return d_cbuf.bytes_in_buffer(); }

	/**
	 * Should the receiver twiddle the bytes to match the local machine's byte order?
	 * Since DAP4 uses 'receiver makes right' encoding, the onus is on the client to
	 * reorder the bytes if it is, e.g., a big endian machine reading data from a little
	 * endian server.
	 *
	 * @return True if the client (caller) should swap bytes in multi-byte integers, etc.,
	 * and false if not. This does not directly tell the endian nature of the remote server,
	 * although that can be inferred.
	 */
	bool twiddle_bytes() const { return d_cbuf.twiddle_bytes(); }
	bool error() const { return d_cbuf.error(); }
	std::string error_message() const { return d_cbuf.error_message(); }
};

}

#endif	// _chunked_istream_h