Update To 11.40.268.0
[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 #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   int ReadTag() {
64     if (bytes_unread() < kTagBytes) {
65       return kIllegalTag;
66     }
67     return buffer_[read_ix_++];
68   }
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   size_t num_bytes() const {
94     return in_use_;
95   }
96
97   uint8_t const *data() const {
98     // return buffer_.data();  // C++11 only, not available on windows
99     return &buffer_[0];
100   }
101
102   void rewind() {
103     read_ix_ = 0;
104   }
105
106   void reset() {
107     in_use_ = 0;
108     buffer_.clear();
109     nbytes_ = 0;
110     read_ix_ = 0;
111   }
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   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     if (sizeof(T) == 1) {
134       AddUint8(static_cast<uint8_t>(value));
135     } else if (sizeof(T) == 2) {
136       AddUint16(static_cast<uint16_t>(value));
137     } else if (sizeof(T) == 4) {
138       AddUint32(static_cast<uint32_t>(value));
139     } else if (sizeof(T) == 8) {
140       AddUint64(static_cast<uint64_t>(value));
141     }
142   }
143
144   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     if (sizeof(T) == 1) {
148       uint8_t val;
149       return GetUint8(&val) ? ((*basic = static_cast<T>(val)), true) : false;
150     } else if (sizeof(T) == 2) {
151       uint16_t val;
152       return GetUint16(&val) ? ((*basic = static_cast<T>(val)), true) : false;
153     } else if (sizeof(T) == 4) {
154       uint32_t val;
155       return GetUint32(&val) ? ((*basic = static_cast<T>(val)), true) : false;
156     } else if (sizeof(T) == 8) {
157       uint64_t val;
158       return GetUint64(&val) ? ((*basic = static_cast<T>(val)), true) : false;
159     }
160     return false;
161   }
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                             std::vector<T> const& v) {
176       size_t orig = buf->cur_write_pos();
177       size_t num_elt = v.size();
178       if (num_elt > ~(uint32_t) 0) {
179         return false;
180       }
181       buf->AddTag<std::vector<T> >();
182       buf->AddVal(static_cast<uint32_t>(num_elt));
183
184       for (size_t ix = 0; ix < v.size(); ++ix) {
185         if (!buf->Serialize(v[ix])) {
186           buf->reset_write_pos(orig);
187           return false;
188         }
189       }
190       return true;
191     }
192   };
193
194   template<typename T> class SerializeHelper<T, false> {
195    public:
196     static bool DoSerialize(SerializationBuffer *buf,
197                             std::vector<T> const& v) {
198       size_t num_elt = v.size();
199       if (num_elt > ~(uint32_t) 0) {
200         return false;
201       }
202       buf->AddTag<std::vector<T> >();
203       buf->AddVal(static_cast<uint32_t>(num_elt));
204
205       for (size_t ix = 0; ix < v.size(); ++ix) {
206         buf->AddVal(v[ix]);
207       }
208       return true;
209     }
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                               std::vector<T> *v) {
218       size_t orig = buf->cur_read_pos();
219       if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
220         buf->reset_read_pos(orig);
221         return false;
222       }
223       uint32_t num_elt;
224       if (!buf->GetVal(&num_elt)) {
225         buf->reset_read_pos(orig);
226         return false;
227       }
228       for (size_t ix = 0; ix < num_elt; ++ix) {
229         T val;
230         if (!buf->Deserialize(&val)) {
231           buf->reset_read_pos(orig);
232           return false;
233         }
234         v->push_back(val);
235       }
236       return true;
237     }
238   };
239
240   template<typename T> class DeserializeHelper<T, false> {
241    public:
242     static bool DoDeserialize(SerializationBuffer *buf,
243                               std::vector<T> *v) {
244       size_t orig = buf->cur_read_pos();
245       if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
246         buf->reset_read_pos(orig);
247         return false;
248       }
249       uint32_t num_elt;
250       if (!buf->GetVal(&num_elt)) {
251         buf->reset_read_pos(orig);
252         return false;
253       }
254       for (size_t ix = 0; ix < num_elt; ++ix) {
255         T val;
256         if (!buf->GetVal(&val)) {
257           buf->reset_read_pos(orig);
258           return false;
259         }
260         v->push_back(val);
261       }
262       return true;
263     }
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   size_t bytes_unread() const {
295     return in_use_ - read_ix_;
296   }
297
298   size_t cur_read_pos() const {
299     return read_ix_;
300   }
301
302   void reset_read_pos(size_t pos) {
303     read_ix_ = pos;
304   }
305
306   size_t cur_write_pos() const {
307     return in_use_;
308   }
309
310   void reset_write_pos(size_t pos) {
311     in_use_ = pos;
312   }
313 };
314
315 template<typename T> void SerializationBuffer::AddTag() {
316   AddUint8(SerializationTraits<T>::kTag);
317 }
318
319 template<typename T> bool SerializationBuffer::Serialize(T basic) {
320   AddTag<T>();
321   AddVal(basic);
322   return true;
323 }
324
325 template<typename T> bool SerializationBuffer::Serialize(
326     std::vector<T> const& v) {
327   return SerializeHelper<T, SerializationTraits<T>::kNestedTag>::
328       DoSerialize(this, v);
329 }
330
331 template<typename T> bool SerializationBuffer::Deserialize(T *basic) {
332   size_t orig = cur_read_pos();
333   if (bytes_unread() < kTagBytes + SerializationTraits<T>::kBytes) {
334     return false;
335   }
336   uint8_t tag;
337   if ((tag = ReadTag()) != SerializationTraits<T>::kTag) {
338     reset_read_pos(orig);
339     return false;
340   }
341   // if BytesAvail >= tag + serialization_size
342   (void) GetVal(basic);
343   return true;
344 }
345
346 template<typename T> bool SerializationBuffer::Deserialize(
347     std::vector<T> *v) {
348   return DeserializeHelper<T, SerializationTraits<T>::kNestedTag>::
349       DoDeserialize(this, v);
350 }
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