- add third_party src.
[platform/framework/web/crosswalk.git] / src / native_client / src / shared / serialization / serialization.h
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
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   int ReadTag() {
80     if (bytes_unread() < kTagBytes) {
81       return kIllegalTag;
82     }
83     return buffer_[read_ix_++];
84   }
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   size_t num_bytes() const {
110     return in_use_;
111   }
112
113   uint8_t const *data() const {
114     // return buffer_.data();  // C++11 only, not available on windows
115     return &buffer_[0];
116   }
117
118   void rewind() {
119     read_ix_ = 0;
120   }
121
122   void reset() {
123     in_use_ = 0;
124     buffer_.clear();
125     nbytes_ = 0;
126     read_ix_ = 0;
127   }
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   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     if (sizeof(T) == 1) {
160       AddUint8(static_cast<uint8_t>(value));
161     } else if (sizeof(T) == 2) {
162       AddUint16(static_cast<uint16_t>(value));
163     } else if (sizeof(T) == 4) {
164       AddUint32(static_cast<uint32_t>(value));
165     } else if (sizeof(T) == 8) {
166       AddUint64(static_cast<uint64_t>(value));
167     }
168   }
169
170   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     if (sizeof(T) == 1) {
174       uint8_t val;
175       return GetUint8(&val) ? ((*basic = static_cast<T>(val)), true) : false;
176     } else if (sizeof(T) == 2) {
177       uint16_t val;
178       return GetUint16(&val) ? ((*basic = static_cast<T>(val)), true) : false;
179     } else if (sizeof(T) == 4) {
180       uint32_t val;
181       return GetUint32(&val) ? ((*basic = static_cast<T>(val)), true) : false;
182     } else if (sizeof(T) == 8) {
183       uint64_t val;
184       return GetUint64(&val) ? ((*basic = static_cast<T>(val)), true) : false;
185     }
186     return false;
187   }
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                             std::vector<T> const& v) {
228       size_t orig = buf->cur_write_pos();
229       size_t num_elt = v.size();
230       if (num_elt > ~(uint32_t) 0) {
231         return false;
232       }
233       buf->AddTag<std::vector<T> >();
234       buf->AddVal(static_cast<uint32_t>(num_elt));
235
236       for (size_t ix = 0; ix < v.size(); ++ix) {
237         if (!buf->Serialize(v[ix])) {
238           buf->reset_write_pos(orig);
239           return false;
240         }
241       }
242       return true;
243     }
244   };
245
246   template<typename T> class SerializeHelper<T, false> {
247    public:
248     static bool DoSerialize(SerializationBuffer *buf,
249                             std::vector<T> const& v) {
250       size_t num_elt = v.size();
251       if (num_elt > ~(uint32_t) 0) {
252         return false;
253       }
254       buf->AddTag<std::vector<T> >();
255       buf->AddVal(static_cast<uint32_t>(num_elt));
256
257       for (size_t ix = 0; ix < v.size(); ++ix) {
258         buf->AddVal(v[ix]);
259       }
260       return true;
261     }
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                               std::vector<T> *v) {
270       size_t orig = buf->cur_read_pos();
271       if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
272         buf->reset_read_pos(orig);
273         return false;
274       }
275       uint32_t num_elt;
276       if (!buf->GetVal(&num_elt)) {
277         buf->reset_read_pos(orig);
278         return false;
279       }
280       for (size_t ix = 0; ix < num_elt; ++ix) {
281         T val;
282         if (!buf->Deserialize(&val)) {
283           buf->reset_read_pos(orig);
284           return false;
285         }
286         v->push_back(val);
287       }
288       return true;
289     }
290   };
291
292   template<typename T> class DeserializeHelper<T, false> {
293    public:
294     static bool DoDeserialize(SerializationBuffer *buf,
295                               std::vector<T> *v) {
296       size_t orig = buf->cur_read_pos();
297       if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
298         buf->reset_read_pos(orig);
299         return false;
300       }
301       uint32_t num_elt;
302       if (!buf->GetVal(&num_elt)) {
303         buf->reset_read_pos(orig);
304         return false;
305       }
306       for (size_t ix = 0; ix < num_elt; ++ix) {
307         T val;
308         if (!buf->GetVal(&val)) {
309           buf->reset_read_pos(orig);
310           return false;
311         }
312         v->push_back(val);
313       }
314       return true;
315     }
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   size_t bytes_unread() const {
347     return in_use_ - read_ix_;
348   }
349
350   size_t cur_read_pos() const {
351     return read_ix_;
352   }
353
354   void reset_read_pos(size_t pos) {
355     read_ix_ = pos;
356   }
357
358   size_t cur_write_pos() const {
359     return in_use_;
360   }
361
362   void reset_write_pos(size_t pos) {
363     in_use_ = pos;
364   }
365 };
366
367 template<typename T> void SerializationBuffer::AddTag() {
368   AddUint8(SerializationTraits<T>::kTag);
369 }
370
371 template<typename T> bool SerializationBuffer::Serialize(T basic) {
372   AddTag<T>();
373   AddVal(basic);
374   return true;
375 }
376
377 template<typename T> bool SerializationBuffer::Serialize(
378     std::vector<T> const& v) {
379   return SerializeHelper<T, SerializationTraits<T>::kNestedTag>::
380       DoSerialize(this, v);
381 }
382
383 template<typename T> bool SerializationBuffer::Deserialize(T *basic) {
384   size_t orig = cur_read_pos();
385   if (bytes_unread() < kTagBytes + SerializationTraits<T>::kBytes) {
386     return false;
387   }
388   uint8_t tag;
389   if ((tag = ReadTag()) != SerializationTraits<T>::kTag) {
390     reset_read_pos(orig);
391     return false;
392   }
393   // if BytesAvail >= tag + serialization_size
394   (void) GetVal(basic);
395   return true;
396 }
397
398 template<typename T> bool SerializationBuffer::Deserialize(
399     std::vector<T> *v) {
400   return DeserializeHelper<T, SerializationTraits<T>::kNestedTag>::
401       DoDeserialize(this, v);
402 }
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