| OLD | NEW |
| (Empty) | |
| 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 |
| OLD | NEW |