1 : /* -*- c++ -*- */
2 : /*
3 : * Copyright (c) 2013 The Native Client Authors. All rights reserved.
4 : * Use of this source code is governed by a BSD-style license that can be
5 : * found in the LICENSE file.
6 : */
7 :
8 : #ifndef NATIVE_CLIENT_SRC_SHARED_SERIALIZATION_SERIALIZATION_H_
9 : #define NATIVE_CLIENT_SRC_SHARED_SERIALIZATION_SERIALIZATION_H_
10 :
11 : #include <vector>
12 : #include <string>
13 :
14 : #include "native_client/src/include/portability.h"
15 : #include "native_client/src/include/nacl_compiler_annotations.h"
16 : #include "native_client/src/shared/platform/nacl_check.h"
17 :
18 : // SerializationBuffer enables serializing basic types and vectors
19 :
20 : namespace nacl {
21 :
22 : class SerializationBuffer;
23 :
24 : template<typename T> class SerializationTraits;
25 :
26 : enum {
27 : kIllegalTag = -1,
28 :
29 : kUint8 = 0,
30 : kInt8 = 1,
31 : kUint16 = 2,
32 : kInt16 = 3,
33 : kUint32 = 4,
34 : kInt32 = 5,
35 : kUint64 = 6,
36 : kInt64 = 7,
37 :
38 : kCString = 11,
39 : kString = 12,
40 :
41 : kRecursiveVector = 31,
42 : kVectorOffset = 32
43 : };
44 :
45 : class SerializationBuffer {
46 : public:
47 : SerializationBuffer();
48 :
49 : // This initializes the Serialization buffer from |data_buffer|
50 : // containing |nbytes| of data. A copy of the data is made rather
51 : // than transferring ownership, which is suboptimal.
52 : SerializationBuffer(uint8_t const *data_buffer, size_t nbytes);
53 :
54 : template<typename T> bool Serialize(T basic) NACL_WUR;
55 :
56 : template<typename T> bool Serialize(std::vector<T> const& v) NACL_WUR;
57 :
58 : bool Serialize(char const *cstr) NACL_WUR;
59 : bool Serialize(char const *cstr, size_t char_count) NACL_WUR;
60 :
61 : bool Serialize(std::string str) NACL_WUR;
62 :
63 1 : int ReadTag() {
64 1 : if (bytes_unread() < kTagBytes) {
65 0 : return kIllegalTag;
66 : }
67 1 : return buffer_[read_ix_++];
68 1 : }
69 :
70 : template<typename T> bool Deserialize(T *basic) NACL_WUR;
71 :
72 : template<typename T> bool Deserialize(std::vector<T> *v) NACL_WUR;
73 :
74 : // This function deserializes into the provided buffer at |cstr|.
75 : // The parameter *buffer_size is an in-out parameter, initially
76 : // containing the available space at |cstr|. If there are decoding
77 : // errors, this function returns false. If it returns true, the
78 : // caller should check *buffer_size -- if there were insufficient
79 : // space, the read position is unchanged and *buffer_size is updated
80 : // to reflect the amount of space that is required; otherwise
81 : // *buffer_size is updated to reflect the actual number of bytes
82 : // written to |cstr|.
83 : bool Deserialize(char *cstr, size_t *buffer_size) NACL_WUR;
84 : // caller provides buffer
85 :
86 : // This method deserializes a NUL-terminated C-style string. The
87 : // caller receives ownnership of the memory allocated via new[] and
88 : // is responsible for delete[]ing it to release the storage.
89 : bool Deserialize(char **cstr_out) NACL_WUR;
90 :
91 : bool Deserialize(std::string *str) NACL_WUR;
92 :
93 1 : size_t num_bytes() const {
94 1 : return in_use_;
95 1 : }
96 :
97 1 : uint8_t const *data() const {
98 : // return buffer_.data(); // C++11 only, not available on windows
99 1 : return &buffer_[0];
100 1 : }
101 :
102 1 : void rewind() {
103 1 : read_ix_ = 0;
104 1 : }
105 :
106 1 : void reset() {
107 1 : in_use_ = 0;
108 1 : buffer_.clear();
109 1 : nbytes_ = 0;
110 1 : read_ix_ = 0;
111 1 : }
112 :
113 : static const size_t kTagBytes = 1;
114 :
115 : protected:
116 : template<typename T> void AddTag();
117 :
118 : template<typename T> bool CheckTag();
119 :
120 : void AddUint8(uint8_t value);
121 : void AddUint16(uint16_t value);
122 : void AddUint32(uint32_t value);
123 : void AddUint64(uint64_t value);
124 :
125 : bool GetUint8(uint8_t *val);
126 : bool GetUint16(uint16_t *val);
127 : bool GetUint32(uint32_t *val);
128 : bool GetUint64(uint64_t *val);
129 :
130 8 : template<typename T> void AddVal(T value) {
131 : int T_must_be_integral_type[static_cast<T>(1)];
132 : UNREFERENCED_PARAMETER(T_must_be_integral_type);
133 8 : if (sizeof(T) == 1) {
134 2 : AddUint8(static_cast<uint8_t>(value));
135 6 : } else if (sizeof(T) == 2) {
136 2 : AddUint16(static_cast<uint16_t>(value));
137 4 : } else if (sizeof(T) == 4) {
138 2 : AddUint32(static_cast<uint32_t>(value));
139 2 : } else if (sizeof(T) == 8) {
140 2 : AddUint64(static_cast<uint64_t>(value));
141 : }
142 8 : }
143 :
144 8 : template<typename T> bool GetVal(T *basic) {
145 : int T_must_be_integral_type[static_cast<T>(1)];
146 : UNREFERENCED_PARAMETER(T_must_be_integral_type);
147 8 : if (sizeof(T) == 1) {
148 : uint8_t val;
149 2 : return GetUint8(&val) ? ((*basic = static_cast<T>(val)), true) : false;
150 6 : } else if (sizeof(T) == 2) {
151 : uint16_t val;
152 2 : return GetUint16(&val) ? ((*basic = static_cast<T>(val)), true) : false;
153 4 : } else if (sizeof(T) == 4) {
154 : uint32_t val;
155 2 : return GetUint32(&val) ? ((*basic = static_cast<T>(val)), true) : false;
156 2 : } else if (sizeof(T) == 8) {
157 : uint64_t val;
158 2 : return GetUint64(&val) ? ((*basic = static_cast<T>(val)), true) : false;
159 : }
160 0 : return false;
161 8 : }
162 :
163 : template<typename T, bool nested_tagging>
164 : bool Serialize(std::vector<T> const& v);
165 :
166 : // Template metaprogramming to determine at compile time, based on
167 : // whether the type T is a container type or not, whether to tag the
168 : // elements with their own type tag, or to just write the elements
169 : // sans type tag. For vector containers of simple types such as
170 : // int8_t, tagging every byte is excessive overhead. NB: see the
171 : // definition below of kTag for vectors.
172 : template<typename T, bool nested_tagging> class SerializeHelper {
173 : public:
174 : static bool DoSerialize(SerializationBuffer *buf,
175 2 : std::vector<T> const& v) {
176 2 : size_t orig = buf->cur_write_pos();
177 2 : size_t num_elt = v.size();
178 2 : if (num_elt > ~(uint32_t) 0) {
179 0 : return false;
180 : }
181 2 : buf->AddTag<std::vector<T> >();
182 2 : buf->AddVal(static_cast<uint32_t>(num_elt));
183 :
184 2 : for (size_t ix = 0; ix < v.size(); ++ix) {
185 2 : if (!buf->Serialize(v[ix])) {
186 0 : buf->reset_write_pos(orig);
187 0 : return false;
188 : }
189 2 : }
190 2 : return true;
191 2 : }
192 : };
193 :
194 : template<typename T> class SerializeHelper<T, false> {
195 : public:
196 : static bool DoSerialize(SerializationBuffer *buf,
197 1 : std::vector<T> const& v) {
198 1 : size_t num_elt = v.size();
199 1 : if (num_elt > ~(uint32_t) 0) {
200 0 : return false;
201 : }
202 1 : buf->AddTag<std::vector<T> >();
203 1 : buf->AddVal(static_cast<uint32_t>(num_elt));
204 :
205 1 : for (size_t ix = 0; ix < v.size(); ++ix) {
206 1 : buf->AddVal(v[ix]);
207 1 : }
208 1 : return true;
209 1 : }
210 : };
211 :
212 : template<typename T, bool b> friend class SerializeHelper;
213 :
214 : template<typename T, bool nested_tagging> class DeserializeHelper {
215 : public:
216 : static bool DoDeserialize(SerializationBuffer *buf,
217 1 : std::vector<T> *v) {
218 1 : size_t orig = buf->cur_read_pos();
219 1 : if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
220 0 : buf->reset_read_pos(orig);
221 0 : return false;
222 : }
223 : uint32_t num_elt;
224 1 : if (!buf->GetVal(&num_elt)) {
225 0 : buf->reset_read_pos(orig);
226 0 : return false;
227 : }
228 1 : for (size_t ix = 0; ix < num_elt; ++ix) {
229 1 : T val;
230 1 : if (!buf->Deserialize(&val)) {
231 0 : buf->reset_read_pos(orig);
232 0 : return false;
233 : }
234 1 : v->push_back(val);
235 1 : }
236 1 : return true;
237 1 : }
238 : };
239 :
240 : template<typename T> class DeserializeHelper<T, false> {
241 : public:
242 : static bool DoDeserialize(SerializationBuffer *buf,
243 1 : std::vector<T> *v) {
244 1 : size_t orig = buf->cur_read_pos();
245 1 : if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
246 0 : buf->reset_read_pos(orig);
247 0 : return false;
248 : }
249 : uint32_t num_elt;
250 1 : if (!buf->GetVal(&num_elt)) {
251 0 : buf->reset_read_pos(orig);
252 0 : return false;
253 : }
254 1 : for (size_t ix = 0; ix < num_elt; ++ix) {
255 : T val;
256 1 : if (!buf->GetVal(&val)) {
257 0 : buf->reset_read_pos(orig);
258 0 : return false;
259 : }
260 1 : v->push_back(val);
261 1 : }
262 1 : return true;
263 1 : }
264 : };
265 :
266 : template<typename T, bool b> friend class DeserializeHelper;
267 :
268 : // TODO(bsy): consider doing something along the lines of
269 : //
270 : // template<typename T> Serialize(T stl_container) {
271 : // AddTag<T>(); // how?
272 : // for (T::const_iterator it = stl_container.begin();
273 : // it != stl_container.end();
274 : // ++it) {
275 : // Serialize(*it);
276 : // // Or AddVal, when SerializationTraits<T::value_type>::kNestedTag
277 : // // is false.
278 : // }
279 : // }
280 : //
281 : // This means that the container type would probably be omitted or a
282 : // generic stl_container type tag would be used -- or we'd have to
283 : // enumerate all container types.
284 :
285 : private:
286 : std::vector<uint8_t> buffer_;
287 : size_t nbytes_;
288 : size_t in_use_;
289 : size_t read_ix_;
290 :
291 : void EnsureTotalSize(size_t req_size);
292 : void EnsureAvailableSpace(size_t req_space);
293 :
294 1 : size_t bytes_unread() const {
295 1 : return in_use_ - read_ix_;
296 1 : }
297 :
298 1 : size_t cur_read_pos() const {
299 1 : return read_ix_;
300 1 : }
301 :
302 1 : void reset_read_pos(size_t pos) {
303 1 : read_ix_ = pos;
304 1 : }
305 :
306 1 : size_t cur_write_pos() const {
307 1 : return in_use_;
308 1 : }
309 :
310 0 : void reset_write_pos(size_t pos) {
311 0 : in_use_ = pos;
312 0 : }
313 : };
314 :
315 13 : template<typename T> void SerializationBuffer::AddTag() {
316 13 : AddUint8(SerializationTraits<T>::kTag);
317 13 : }
318 :
319 8 : template<typename T> bool SerializationBuffer::Serialize(T basic) {
320 8 : AddTag<T>();
321 8 : AddVal(basic);
322 8 : return true;
323 8 : }
324 :
325 : template<typename T> bool SerializationBuffer::Serialize(
326 3 : std::vector<T> const& v) {
327 : return SerializeHelper<T, SerializationTraits<T>::kNestedTag>::
328 3 : DoSerialize(this, v);
329 3 : }
330 :
331 8 : template<typename T> bool SerializationBuffer::Deserialize(T *basic) {
332 8 : size_t orig = cur_read_pos();
333 8 : if (bytes_unread() < kTagBytes + SerializationTraits<T>::kBytes) {
334 1 : return false;
335 : }
336 : uint8_t tag;
337 8 : if ((tag = ReadTag()) != SerializationTraits<T>::kTag) {
338 0 : reset_read_pos(orig);
339 0 : return false;
340 : }
341 : // if BytesAvail >= tag + serialization_size
342 8 : (void) GetVal(basic);
343 8 : return true;
344 8 : }
345 :
346 : template<typename T> bool SerializationBuffer::Deserialize(
347 2 : std::vector<T> *v) {
348 : return DeserializeHelper<T, SerializationTraits<T>::kNestedTag>::
349 2 : DoDeserialize(this, v);
350 2 : }
351 :
352 : template<> class SerializationTraits<uint8_t> {
353 : public:
354 : static const int kTag = kUint8;
355 : static const int kBytes = 1;
356 : static const bool kNestedTag = false;
357 : };
358 :
359 : template<> class SerializationTraits<int8_t> {
360 : public:
361 : static const int kTag = kInt8;
362 : static const int kBytes = 1;
363 : static const bool kNestedTag = false;
364 : };
365 :
366 : template<> class SerializationTraits<uint16_t> {
367 : public:
368 : static const int kTag = kUint16;
369 : static const int kBytes = 2;
370 : static const bool kNestedTag = false;
371 : };
372 :
373 : template<> class SerializationTraits<int16_t> {
374 : public:
375 : static const int kTag = kInt16;
376 : static const int kBytes = 2;
377 : static const bool kNestedTag = false;
378 : };
379 :
380 : template<> class SerializationTraits<uint32_t> {
381 : public:
382 : static const int kTag = kUint32;
383 : static const int kBytes = 4;
384 : static const bool kNestedTag = false;
385 : };
386 :
387 : template<> class SerializationTraits<int32_t> {
388 : public:
389 : static const int kTag = kInt32;
390 : static const int kBytes = 4;
391 : static const bool kNestedTag = false;
392 : };
393 :
394 : template<> class SerializationTraits<uint64_t> {
395 : public:
396 : static const int kTag = kUint64;
397 : static const int kBytes = 8;
398 : static const bool kNestedTag = false;
399 : };
400 :
401 : template<> class SerializationTraits<int64_t> {
402 : public:
403 : static const int kTag = kInt64;
404 : static const int kBytes = 8;
405 : static const bool kNestedTag = false;
406 : };
407 :
408 : template<> class SerializationTraits<char *> {
409 : public:
410 : static const int kTag = kCString;
411 : static const bool kNestedTag = true;
412 : };
413 :
414 : template<> class SerializationTraits<std::string> {
415 : public:
416 : static const int kTag = kString;
417 : static const bool kNestedTag = true;
418 : };
419 :
420 : // We want the type tag for vector<T>, when the type T is a basic
421 : // type, to incorporate the type tag for T. This way, we do not tag
422 : // each vector element (see SerializeHelper etc above), and yet the
423 : // type information is present. When T is not a basic type (e.g., it
424 : // is a string, a vector<U>, or some other container to be added), we
425 : // don't want to just add the kVectorOffset to the type tag for T,
426 : // since deep nesting of containers could cause the tag to overflow.
427 : // Assuming that the type T nested containers are not empty, paying
428 : // the cost of tagging each element of the vector is not a huge
429 : // overhead.
430 : template<typename T> class SerializationTraits<std::vector<T> > {
431 : private:
432 : template<typename S, bool b> class RecursiveOrNotTag {
433 : public:
434 : static const int kVectorTag = kRecursiveVector;
435 : };
436 : template<typename S> class RecursiveOrNotTag<S, false> {
437 : public:
438 : static const int kVectorTag = kVectorOffset + SerializationTraits<S>::kTag;
439 : };
440 : public:
441 : static const int kTag =
442 : RecursiveOrNotTag<T, SerializationTraits<T>::kNestedTag>::kVectorTag;
443 : static const bool kNestedTag = true;
444 : };
445 :
446 : } // namespace nacl
447 :
448 : #endif
|