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