Initial import to Git
[profile/ivi/common-api-dbus-runtime.git] / CommonAPI-DBus / src / CommonAPI / DBus / DBusOutputStream.h
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 #ifndef COMMONAPI_DBUS_DBUS_OUTPUT_MESSAGE_STREAM_H_
5 #define COMMONAPI_DBUS_DBUS_OUTPUT_MESSAGE_STREAM_H_
6
7 #include "DBusMessage.h"
8 #include "DBusError.h"
9
10 #include <CommonAPI/OutputStream.h>
11
12 #include <string>
13 #include <cstring>
14 #include <vector>
15 #include <cassert>
16 #include <stack>
17
18 namespace CommonAPI {
19 namespace DBus {
20
21 /**
22  * Used to mark the position of a pointer within an array of bytes.
23  */
24 typedef uint32_t position_t;
25
26
27 /**
28  * @class DBusOutputMessageStream
29  *
30  * Used to serialize and write data into a #DBusMessage. For all data types that may be written to a #DBusMessage, a "<<"-operator should be defined to handle the writing
31  * (this operator is predefined for all basic data types and for vectors). The signature that has to be written to the #DBusMessage separately is assumed
32  * to match the actual data that is inserted via the #DBusOutputMessageStream.
33  */
34 class DBusOutputStream: public OutputStream {
35   public:
36         virtual OutputStream& writeValue(const bool& boolValue) { return writeBasicTypeValue<uint32_t>(boolValue); }
37
38         virtual OutputStream& writeValue(const int8_t& int8Value) { return writeBasicTypeValue(int8Value); }
39         virtual OutputStream& writeValue(const int16_t& int16Value) { return writeBasicTypeValue(int16Value); }
40         virtual OutputStream& writeValue(const int32_t& int32Value) { return writeBasicTypeValue(int32Value); }
41         virtual OutputStream& writeValue(const int64_t& int64Value) { return writeBasicTypeValue(int64Value); }
42
43         virtual OutputStream& writeValue(const uint8_t& uint8Value) { return writeBasicTypeValue(uint8Value); }
44         virtual OutputStream& writeValue(const uint16_t& uint16Value) { return writeBasicTypeValue(uint16Value); }
45         virtual OutputStream& writeValue(const uint32_t& uint32Value) { return writeBasicTypeValue(uint32Value); }
46         virtual OutputStream& writeValue(const uint64_t& uint64Value) { return writeBasicTypeValue(uint64Value); }
47
48         virtual OutputStream& writeValue(const float& floatValue) { return writeBasicTypeValue((double) floatValue); }
49         virtual OutputStream& writeValue(const double& doubleValue) { return writeBasicTypeValue(doubleValue); }
50
51         virtual OutputStream& writeValue(const std::string& stringValue) { return writeString(stringValue.c_str(), stringValue.length()); }
52
53         inline virtual OutputStream& writeValue(const ByteBuffer& byteBufferValue);
54
55         virtual OutputStream& writeEnumValue(const int8_t& int8BackingTypeValue) { return writeValue(int8BackingTypeValue); }
56         virtual OutputStream& writeEnumValue(const int16_t& int16BackingTypeValue) { return writeValue(int16BackingTypeValue); }
57         virtual OutputStream& writeEnumValue(const int32_t& int32BackingTypeValue) { return writeValue(int32BackingTypeValue); }
58         virtual OutputStream& writeEnumValue(const int64_t& int64BackingTypeValue) { return writeValue(int64BackingTypeValue); }
59         virtual OutputStream& writeEnumValue(const uint8_t& uint8BackingTypeValue) { return writeValue(uint8BackingTypeValue); }
60         virtual OutputStream& writeEnumValue(const uint16_t& uint16BackingTypeValue) { return writeValue(uint16BackingTypeValue); }
61         virtual OutputStream& writeEnumValue(const uint32_t& uint32BackingTypeValue) { return writeValue(uint32BackingTypeValue); }
62         virtual OutputStream& writeEnumValue(const uint64_t& uint64BackingTypeValue) { return writeValue(uint64BackingTypeValue); }
63
64     virtual void beginWriteBoolVector(uint32_t sizeOfVector) {
65         beginWriteGenericVector();
66         rememberCurrentStreamPosition();
67     }
68     virtual void beginWriteInt8Vector(uint32_t sizeOfVector) {
69         beginWriteGenericVector();
70         rememberCurrentStreamPosition();
71     }
72     virtual void beginWriteInt16Vector(uint32_t sizeOfVector) {
73         beginWriteGenericVector();
74         rememberCurrentStreamPosition();
75     }
76     virtual void beginWriteInt32Vector(uint32_t sizeOfVector) {
77         beginWriteGenericVector();
78         rememberCurrentStreamPosition();
79     }
80     virtual void beginWriteInt64Vector(uint32_t sizeOfVector) {
81         beginWriteGenericVector();
82         alignToBoundary(8);
83         rememberCurrentStreamPosition();
84     }
85     virtual void beginWriteUInt8Vector(uint32_t sizeOfVector) {
86         beginWriteGenericVector();
87         rememberCurrentStreamPosition();
88     }
89     virtual void beginWriteUInt16Vector(uint32_t sizeOfVector) {
90         beginWriteGenericVector();
91         rememberCurrentStreamPosition();
92     }
93     virtual void beginWriteUInt32Vector(uint32_t sizeOfVector) {
94         beginWriteGenericVector();
95         rememberCurrentStreamPosition();
96     }
97     virtual void beginWriteUInt64Vector(uint32_t sizeOfVector) {
98         beginWriteGenericVector();
99         alignToBoundary(8);
100         rememberCurrentStreamPosition();
101     }
102     virtual void beginWriteFloatVector(uint32_t sizeOfVector) {
103         beginWriteGenericVector();
104         alignToBoundary(8);
105         rememberCurrentStreamPosition();
106     }
107     virtual void beginWriteDoubleVector(uint32_t sizeOfVector) {
108         beginWriteGenericVector();
109         alignToBoundary(8);
110         rememberCurrentStreamPosition();
111     }
112     virtual void beginWriteStringVector(uint32_t sizeOfVector) {
113         beginWriteGenericVector();
114         rememberCurrentStreamPosition();
115     }
116     virtual void beginWriteByteBufferVector(uint32_t sizeOfVector) {
117         beginWriteGenericVector();
118         rememberCurrentStreamPosition();
119     }
120     virtual void beginWriteVersionVector(uint32_t sizeOfVector) {
121         beginWriteGenericVector();
122         alignToBoundary(8);
123         rememberCurrentStreamPosition();
124     }
125     virtual void beginWriteVectorOfSerializableStructs(uint32_t sizeOfVector) {
126         beginWriteGenericVector();
127         alignToBoundary(8);
128         rememberCurrentStreamPosition();
129     }
130     virtual void beginWriteVectorOfVectors(uint32_t sizeOfVector) {
131         beginWriteGenericVector();
132         rememberCurrentStreamPosition();
133     }
134     virtual void beginWriteVectorOfMaps(uint32_t sizeOfVector) {
135         beginWriteGenericVector();
136         alignToBoundary(8);
137         rememberCurrentStreamPosition();
138     }
139
140     virtual void endWriteVector() {
141         uint32_t numOfWrittenBytes = getCurrentStreamPosition() - popRememberedStreamPosition();
142         writeBasicTypeValueAtPosition(popRememberedStreamPosition(), numOfWrittenBytes);
143     }
144
145         virtual OutputStream& writeVersionValue(const Version& versionValue) {
146                 alignToBoundary(8);
147                 writeValue(versionValue.Major);
148                 writeValue(versionValue.Minor);
149                 return *this;
150         }
151
152         virtual void beginWriteSerializableStruct(const SerializableStruct& serializableStruct) { alignToBoundary(8); }
153         virtual void endWriteSerializableStruct(const SerializableStruct& serializableStruct) { }
154
155         virtual void beginWriteMap(size_t elementCount) {
156         alignToBoundary(sizeof(uint32_t));
157         rememberCurrentStreamPosition();
158         writeBasicTypeValue((uint32_t) 0);
159             alignToBoundary(8);
160         rememberCurrentStreamPosition();
161         }
162
163         virtual void endWriteMap() {
164         uint32_t numOfWrittenBytes = getCurrentStreamPosition() - popRememberedStreamPosition();
165         writeBasicTypeValueAtPosition(popRememberedStreamPosition(), numOfWrittenBytes);
166         }
167
168         virtual bool hasError() const {
169                 return dbusError_;
170         }
171
172         /**
173      * Creates a #DBusOutputMessageStream which can be used to serialize and write data into the given #DBusMessage. Any data written is buffered within the stream.
174      * Remember to call flush() when you are done with writing: Only then the data actually is written to the #DBusMessage.
175      *
176      * @param dbusMessage The #DBusMessage any data pushed into this stream should be written to.
177      */
178     DBusOutputStream(DBusMessage dbusMessage);
179
180     /**
181      * Destructor; does not call the destructor of the referred #DBusMessage. Make sure to maintain a reference to the
182      * #DBusMessage outside of the stream if you intend to make further use of the message, e.g. in order to send it,
183      * now that you have written some payload into it.
184      */
185     virtual ~DBusOutputStream();
186
187     /**
188      * Writes the data that was buffered within this #DBusOutputMessageStream to the #DBusMessage that was given to the constructor. Each call to flush()
189      * will completely override the data that currently is contained in the #DBusMessage. The data that is buffered in this #DBusOutputMessageStream is
190      * not deleted by calling flush().
191      */
192     void flush();
193
194     /**
195      * Marks the stream as erroneous.
196      */
197     inline void setError();
198
199     /**
200      * Reserves the given number of bytes for writing, thereby negating the need to dynamically allocate memory while writing.
201      * Use this method for optimization: If possible, reserve as many bytes as you need for your data before doing any writing.
202      *
203      * @param numOfBytes The number of bytes that should be reserved for writing.
204      */
205     void reserveMemory(size_t numOfBytes);
206
207     /**
208      * @return current data position where later writing is possible
209      */
210     size_t getCurrentPosition();
211
212     template<typename _BasicType>
213     DBusOutputStream& writeBasicTypeValue(const _BasicType& basicValue) {
214         if (sizeof(_BasicType) > 1)
215             alignToBoundary(sizeof(_BasicType));
216
217         writeRawData(reinterpret_cast<const char*>(&basicValue), sizeof(_BasicType));
218
219         return *this;
220     }
221
222     template<typename _BasicType>
223     bool writeBasicTypeValueAtPosition(size_t position, const _BasicType& basicValue) {
224         assert(position + sizeof(_BasicType) <= payload_.size());
225
226         return writeRawDataAtPosition(position, reinterpret_cast<const char*>(&basicValue), sizeof(_BasicType));
227     }
228
229     DBusOutputStream& writeString(const char* cString, const uint32_t& length);
230
231     /**
232      * Fills the stream with 0-bytes to make the next value be aligned to the boundary given.
233      * This means that as many 0-bytes are written to the buffer as are necessary
234      * to make the next value start with the given alignment.
235      *
236      * @param alignBoundary The byte-boundary to which the next value should be aligned.
237      */
238     virtual void alignToBoundary(const size_t alignBoundary);
239
240     /**
241      * Takes sizeInByte characters, starting from the character which val points to, and stores them for later writing.
242      * When calling flush(), all values that were written to this stream are copied into the payload of the #DBusMessage.
243      *
244      * The array of characters might be created from a pointer to a given value by using a reinterpret_cast. Example:
245      * @code
246      * ...
247      * int32_t val = 15;
248      * outputMessageStream.alignForBasicType(sizeof(int32_t));
249      * const char* const reinterpreted = reinterpret_cast<const char*>(&val);
250      * outputMessageStream.writeValue(reinterpreted, sizeof(int32_t));
251      * ...
252      * @endcode
253      *
254      * @param val The array of chars that should serve as input
255      * @param sizeInByte The number of bytes that should be written
256      * @return true if writing was successful, false otherwise.
257      *
258      * @see DBusOutputMessageStream()
259      * @see flush()
260      */
261     bool writeRawData(const char* rawDataPtr, const size_t sizeInByte);
262
263     bool writeRawDataAtPosition(size_t position, const char* rawDataPtr, const size_t sizeInByte);
264
265   protected:
266     std::string payload_;
267
268   private:
269     inline void beginWriteGenericVector() {
270         alignToBoundary(sizeof(uint32_t));
271         rememberCurrentStreamPosition();
272         writeBasicTypeValue((uint32_t) 0);
273     }
274
275     inline void rememberCurrentStreamPosition() {
276         savedStreamPositions_.push(payload_.size());
277     }
278
279     inline size_t popRememberedStreamPosition() {
280         size_t val = savedStreamPositions_.top();
281         savedStreamPositions_.pop();
282         return val;
283     }
284
285     inline size_t getCurrentStreamPosition() {
286         return payload_.size();
287     }
288
289     DBusError dbusError_;
290     DBusMessage dbusMessage_;
291
292     std::stack<position_t> savedStreamPositions_;
293 };
294
295
296 //Additional 0-termination, so this is 8 byte of \0
297 static const char* eightByteZeroString = "\0\0\0\0\0\0\0";
298
299 inline void DBusOutputStream::alignToBoundary(const size_t alignBoundary) {
300     assert(alignBoundary > 0 && alignBoundary <= 8 && (alignBoundary % 2 == 0 || alignBoundary == 1));
301
302     size_t alignMask = alignBoundary - 1;
303     size_t necessaryAlignment = ((alignMask - (payload_.size() & alignMask)) + 1) & alignMask;
304
305     writeRawData(eightByteZeroString, necessaryAlignment);
306 }
307
308 inline bool DBusOutputStream::writeRawData(const char* rawDataPtr, const size_t sizeInByte) {
309     assert(sizeInByte >= 0);
310
311     payload_.append(rawDataPtr, sizeInByte);
312
313     return true;
314 }
315
316 inline bool DBusOutputStream::writeRawDataAtPosition(size_t position, const char* rawDataPtr, const size_t sizeInByte) {
317     assert(sizeInByte >= 0);
318
319     payload_ = payload_.replace(position, sizeInByte, rawDataPtr, sizeInByte);
320
321     return true;
322 }
323
324 inline size_t DBusOutputStream::getCurrentPosition() {
325     return payload_.size();
326 }
327
328
329 OutputStream& DBusOutputStream::writeValue(const ByteBuffer& byteBufferValue) {
330         *this << byteBufferValue;
331         return *this;
332 }
333
334 } // namespace DBus
335 } // namespace CommonAPI
336
337 #endif // COMMONAPI_DBUS_DBUS_OUTPUT_MESSAGE_STREAM_H_