1//
2// BinaryWriter.h
3//
4// Library: Foundation
5// Package: Streams
6// Module: BinaryReaderWriter
7//
8// Definition of the BinaryWriter class.
9//
10// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// SPDX-License-Identifier: BSL-1.0
14//
15
16
17#ifndef Foundation_BinaryWriter_INCLUDED
18#define Foundation_BinaryWriter_INCLUDED
19
20
21#include "Poco/Foundation.h"
22#include "Poco/Buffer.h"
23#include "Poco/MemoryStream.h"
24#include "Poco/ByteOrder.h"
25#include <vector>
26#include <ostream>
27
28
29namespace Poco {
30
31
32class TextEncoding;
33class TextConverter;
34
35
36class Foundation_API BinaryWriter
37 /// This class writes basic types (and std::vectors of these)
38 /// in binary form into an output stream.
39 /// It provides an inserter-based interface similar to ostream.
40 /// The writer also supports automatic conversion from big-endian
41 /// (network byte order) to little-endian and vice-versa.
42 /// Use a BinaryReader to read from a stream created by a BinaryWriter.
43 /// Be careful when exchanging data between systems with different
44 /// data type sizes (e.g., 32-bit and 64-bit architectures), as the sizes
45 /// of some of the basic types may be different. For example, writing a
46 /// long integer on a 64-bit system and reading it on a 32-bit system
47 /// may yield an incorrect result. Use fixed-size types (Int32, Int64, etc.)
48 /// in such a case.
49{
50public:
51 enum StreamByteOrder
52 {
53 NATIVE_BYTE_ORDER = 1, /// the host's native byte-order
54 BIG_ENDIAN_BYTE_ORDER = 2, /// big-endian (network) byte-order
55 NETWORK_BYTE_ORDER = 2, /// big-endian (network) byte-order
56 LITTLE_ENDIAN_BYTE_ORDER = 3 /// little-endian byte-order
57 };
58
59 BinaryWriter(std::ostream& ostr, StreamByteOrder order = NATIVE_BYTE_ORDER);
60 /// Creates the BinaryWriter.
61
62 BinaryWriter(std::ostream& ostr, TextEncoding& encoding, StreamByteOrder order = NATIVE_BYTE_ORDER);
63 /// Creates the BinaryWriter using the given TextEncoding.
64 ///
65 /// Strings will be converted from the currently set global encoding
66 /// (see Poco::TextEncoding::global()) to the specified encoding.
67
68 ~BinaryWriter();
69 /// Destroys the BinaryWriter.
70
71 BinaryWriter& operator << (bool value);
72 BinaryWriter& operator << (char value);
73 BinaryWriter& operator << (unsigned char value);
74 BinaryWriter& operator << (signed char value);
75 BinaryWriter& operator << (short value);
76 BinaryWriter& operator << (unsigned short value);
77 BinaryWriter& operator << (int value);
78 BinaryWriter& operator << (unsigned int value);
79#ifndef POCO_LONG_IS_64_BIT
80 BinaryWriter& operator << (long value);
81 BinaryWriter& operator << (unsigned long value);
82#endif // POCO_LONG_IS_64_BIT
83 BinaryWriter& operator << (float value);
84 BinaryWriter& operator << (double value);
85 BinaryWriter& operator << (Int64 value);
86 BinaryWriter& operator << (UInt64 value);
87 BinaryWriter& operator << (const std::string& value);
88 BinaryWriter& operator << (const char* value);
89
90 template <typename T>
91 BinaryWriter& operator << (const std::vector<T>& value)
92 {
93 Poco::UInt32 size(static_cast<Poco::UInt32>(value.size()));
94
95 *this << size;
96 for (typename std::vector<T>::const_iterator it = value.begin(); it != value.end(); ++it)
97 {
98 *this << *it;
99 }
100
101 return *this;
102 }
103
104 void write7BitEncoded(UInt32 value);
105 /// Writes a 32-bit unsigned integer in a compressed format.
106 /// The value is written out seven bits at a time, starting
107 /// with the seven least-significant bits.
108 /// The high bit of a byte indicates whether there are more bytes to be
109 /// written after this one.
110 /// If value will fit in seven bits, it takes only one byte of space.
111 /// If value will not fit in seven bits, the high bit is set on the first byte and
112 /// written out. value is then shifted by seven bits and the next byte is written.
113 /// This process is repeated until the entire integer has been written.
114
115 void write7BitEncoded(UInt64 value);
116 /// Writes a 64-bit unsigned integer in a compressed format.
117 /// The value written out seven bits at a time, starting
118 /// with the seven least-significant bits.
119 /// The high bit of a byte indicates whether there are more bytes to be
120 /// written after this one.
121 /// If value will fit in seven bits, it takes only one byte of space.
122 /// If value will not fit in seven bits, the high bit is set on the first byte and
123 /// written out. value is then shifted by seven bits and the next byte is written.
124 /// This process is repeated until the entire integer has been written.
125
126 void writeRaw(const std::string& rawData);
127 /// Writes the string as-is to the stream.
128
129 void writeRaw(const char* buffer, std::streamsize length);
130 /// Writes length raw bytes from the given buffer to the stream.
131
132 void writeBOM();
133 /// Writes a byte-order mark to the stream. A byte order mark is
134 /// a 16-bit integer with a value of 0xFEFF, written in host byte-order.
135 /// A BinaryReader uses the byte-order mark to determine the byte-order
136 /// of the stream.
137
138 void flush();
139 /// Flushes the underlying stream.
140
141 bool good();
142 /// Returns _ostr.good();
143
144 bool fail();
145 /// Returns _ostr.fail();
146
147 bool bad();
148 /// Returns _ostr.bad();
149
150 std::ostream& stream() const;
151 /// Returns the underlying stream.
152
153 StreamByteOrder byteOrder() const;
154 /// Returns the byte ordering used by the writer, which is
155 /// either BIG_ENDIAN_BYTE_ORDER or LITTLE_ENDIAN_BYTE_ORDER.
156
157private:
158
159#ifdef POCO_OS_FAMILY_WINDOWS
160#pragma warning(push)
161#pragma warning(disable : 4800) // forcing value to bool 'true' or 'false' (performance warning)
162#endif
163
164 template<typename T>
165 BinaryWriter& write(T value, bool flipBytes)
166 {
167 if (flipBytes)
168 {
169 T fValue = static_cast<T>(ByteOrder::flipBytes(value));
170 _ostr.write((const char*) &fValue, sizeof(fValue));
171 }
172 else
173 {
174 _ostr.write((const char*) &value, sizeof(value));
175 }
176 return *this;
177 }
178
179#ifdef POCO_OS_FAMILY_WINDOWS
180#pragma warning(pop)
181#endif
182
183 template<typename T>
184 void write7BitEncoded(T value)
185 {
186 do
187 {
188 unsigned char c = (unsigned char) (value & 0x7F);
189 value >>= 7;
190 if (value) c |= 0x80;
191 _ostr.write((const char*) &c, 1);
192 }
193 while (value);
194 }
195
196 BinaryWriter& write(const char* value, std::size_t length);
197
198 std::ostream& _ostr;
199 bool _flipBytes;
200 TextConverter* _pTextConverter;
201};
202
203
204template <typename T>
205class BasicMemoryBinaryWriter: public BinaryWriter
206 /// A convenient wrapper for using Buffer and MemoryStream with BinarWriter.
207{
208public:
209 BasicMemoryBinaryWriter(Buffer<T>& dataBuffer, StreamByteOrder order = NATIVE_BYTE_ORDER):
210 BinaryWriter(_ostr, order),
211 _data(dataBuffer),
212 _ostr(dataBuffer.begin(), dataBuffer.capacity())
213 {
214 }
215
216 BasicMemoryBinaryWriter(Buffer<T>& dataBuffer, TextEncoding& encoding, StreamByteOrder order = NATIVE_BYTE_ORDER):
217 BinaryWriter(_ostr, encoding, order),
218 _data(dataBuffer),
219 _ostr(dataBuffer.begin(), dataBuffer.capacity())
220 {
221 }
222
223 ~BasicMemoryBinaryWriter()
224 {
225 try
226 {
227 flush();
228 }
229 catch (...)
230 {
231 poco_unexpected();
232 }
233 }
234
235 Buffer<T>& data()
236 {
237 return _data;
238 }
239
240 const Buffer<T>& data() const
241 {
242 return _data;
243 }
244
245 const MemoryOutputStream& stream() const
246 {
247 return _ostr;
248 }
249
250 MemoryOutputStream& stream()
251 {
252 return _ostr;
253 }
254
255private:
256 Buffer<T>& _data;
257 MemoryOutputStream _ostr;
258};
259
260
261typedef BasicMemoryBinaryWriter<char> MemoryBinaryWriter;
262
263
264//
265// inlines
266//
267
268
269inline std::ostream& BinaryWriter::stream() const
270{
271 return _ostr;
272}
273
274
275inline bool BinaryWriter::good()
276{
277 return _ostr.good();
278}
279
280
281inline bool BinaryWriter::fail()
282{
283 return _ostr.fail();
284}
285
286
287inline bool BinaryWriter::bad()
288{
289 return _ostr.bad();
290}
291
292
293inline BinaryWriter::StreamByteOrder BinaryWriter::byteOrder() const
294{
295#if defined(POCO_ARCH_BIG_ENDIAN)
296 return _flipBytes ? LITTLE_ENDIAN_BYTE_ORDER : BIG_ENDIAN_BYTE_ORDER;
297#else
298 return _flipBytes ? BIG_ENDIAN_BYTE_ORDER : LITTLE_ENDIAN_BYTE_ORDER;
299#endif
300}
301
302
303} // namespace Poco
304
305
306#endif // Foundation_BinaryWriter_INCLUDED
307