Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/pickle.h"
      6 
      7 #include <stdlib.h>
      8 
      9 #include <algorithm>  // for max()
     10 
     11 //------------------------------------------------------------------------------
     12 
     13 using base::char16;
     14 using base::string16;
     15 
     16 // static
     17 const int Pickle::kPayloadUnit = 64;
     18 
     19 static const size_t kCapacityReadOnly = static_cast<size_t>(-1);
     20 
     21 PickleIterator::PickleIterator(const Pickle& pickle)
     22     : payload_(pickle.payload()),
     23       read_index_(0),
     24       end_index_(pickle.payload_size()) {
     25 }
     26 
     27 template <typename Type>
     28 inline bool PickleIterator::ReadBuiltinType(Type* result) {
     29   const char* read_from = GetReadPointerAndAdvance<Type>();
     30   if (!read_from)
     31     return false;
     32   if (sizeof(Type) > sizeof(uint32))
     33     memcpy(result, read_from, sizeof(*result));
     34   else
     35     *result = *reinterpret_cast<const Type*>(read_from);
     36   return true;
     37 }
     38 
     39 inline void PickleIterator::Advance(size_t size) {
     40   size_t aligned_size = AlignInt(size, sizeof(uint32_t));
     41   if (end_index_ - read_index_ < aligned_size) {
     42     read_index_ = end_index_;
     43   } else {
     44     read_index_ += aligned_size;
     45   }
     46 }
     47 
     48 template<typename Type>
     49 inline const char* PickleIterator::GetReadPointerAndAdvance() {
     50   if (sizeof(Type) > end_index_ - read_index_) {
     51     read_index_ = end_index_;
     52     return NULL;
     53   }
     54   const char* current_read_ptr = payload_ + read_index_;
     55   Advance(sizeof(Type));
     56   return current_read_ptr;
     57 }
     58 
     59 const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) {
     60   if (num_bytes < 0 ||
     61       end_index_ - read_index_ < static_cast<size_t>(num_bytes)) {
     62     read_index_ = end_index_;
     63     return NULL;
     64   }
     65   const char* current_read_ptr = payload_ + read_index_;
     66   Advance(num_bytes);
     67   return current_read_ptr;
     68 }
     69 
     70 inline const char* PickleIterator::GetReadPointerAndAdvance(
     71     int num_elements,
     72     size_t size_element) {
     73   // Check for int32 overflow.
     74   int64 num_bytes = static_cast<int64>(num_elements) * size_element;
     75   int num_bytes32 = static_cast<int>(num_bytes);
     76   if (num_bytes != static_cast<int64>(num_bytes32))
     77     return NULL;
     78   return GetReadPointerAndAdvance(num_bytes32);
     79 }
     80 
     81 bool PickleIterator::ReadBool(bool* result) {
     82   return ReadBuiltinType(result);
     83 }
     84 
     85 bool PickleIterator::ReadInt(int* result) {
     86   return ReadBuiltinType(result);
     87 }
     88 
     89 bool PickleIterator::ReadLong(long* result) {
     90   return ReadBuiltinType(result);
     91 }
     92 
     93 bool PickleIterator::ReadUInt16(uint16* result) {
     94   return ReadBuiltinType(result);
     95 }
     96 
     97 bool PickleIterator::ReadUInt32(uint32* result) {
     98   return ReadBuiltinType(result);
     99 }
    100 
    101 bool PickleIterator::ReadInt64(int64* result) {
    102   return ReadBuiltinType(result);
    103 }
    104 
    105 bool PickleIterator::ReadUInt64(uint64* result) {
    106   return ReadBuiltinType(result);
    107 }
    108 
    109 bool PickleIterator::ReadFloat(float* result) {
    110   // crbug.com/315213
    111   // The source data may not be properly aligned, and unaligned float reads
    112   // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data
    113   // into the result.
    114   const char* read_from = GetReadPointerAndAdvance<float>();
    115   if (!read_from)
    116     return false;
    117   memcpy(result, read_from, sizeof(*result));
    118   return true;
    119 }
    120 
    121 bool PickleIterator::ReadDouble(double* result) {
    122   // crbug.com/315213
    123   // The source data may not be properly aligned, and unaligned double reads
    124   // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data
    125   // into the result.
    126   const char* read_from = GetReadPointerAndAdvance<double>();
    127   if (!read_from)
    128     return false;
    129   memcpy(result, read_from, sizeof(*result));
    130   return true;
    131 }
    132 
    133 bool PickleIterator::ReadString(std::string* result) {
    134   int len;
    135   if (!ReadInt(&len))
    136     return false;
    137   const char* read_from = GetReadPointerAndAdvance(len);
    138   if (!read_from)
    139     return false;
    140 
    141   result->assign(read_from, len);
    142   return true;
    143 }
    144 
    145 bool PickleIterator::ReadWString(std::wstring* result) {
    146   int len;
    147   if (!ReadInt(&len))
    148     return false;
    149   const char* read_from = GetReadPointerAndAdvance(len, sizeof(wchar_t));
    150   if (!read_from)
    151     return false;
    152 
    153   result->assign(reinterpret_cast<const wchar_t*>(read_from), len);
    154   return true;
    155 }
    156 
    157 bool PickleIterator::ReadString16(string16* result) {
    158   int len;
    159   if (!ReadInt(&len))
    160     return false;
    161   const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16));
    162   if (!read_from)
    163     return false;
    164 
    165   result->assign(reinterpret_cast<const char16*>(read_from), len);
    166   return true;
    167 }
    168 
    169 bool PickleIterator::ReadData(const char** data, int* length) {
    170   *length = 0;
    171   *data = 0;
    172 
    173   if (!ReadInt(length))
    174     return false;
    175 
    176   return ReadBytes(data, *length);
    177 }
    178 
    179 bool PickleIterator::ReadBytes(const char** data, int length) {
    180   const char* read_from = GetReadPointerAndAdvance(length);
    181   if (!read_from)
    182     return false;
    183   *data = read_from;
    184   return true;
    185 }
    186 
    187 // Payload is uint32 aligned.
    188 
    189 Pickle::Pickle()
    190     : header_(NULL),
    191       header_size_(sizeof(Header)),
    192       capacity_after_header_(0),
    193       write_offset_(0) {
    194   Resize(kPayloadUnit);
    195   header_->payload_size = 0;
    196 }
    197 
    198 Pickle::Pickle(int header_size)
    199     : header_(NULL),
    200       header_size_(AlignInt(header_size, sizeof(uint32))),
    201       capacity_after_header_(0),
    202       write_offset_(0) {
    203   DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
    204   DCHECK_LE(header_size, kPayloadUnit);
    205   Resize(kPayloadUnit);
    206   header_->payload_size = 0;
    207 }
    208 
    209 Pickle::Pickle(const char* data, int data_len)
    210     : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
    211       header_size_(0),
    212       capacity_after_header_(kCapacityReadOnly),
    213       write_offset_(0) {
    214   if (data_len >= static_cast<int>(sizeof(Header)))
    215     header_size_ = data_len - header_->payload_size;
    216 
    217   if (header_size_ > static_cast<unsigned int>(data_len))
    218     header_size_ = 0;
    219 
    220   if (header_size_ != AlignInt(header_size_, sizeof(uint32)))
    221     header_size_ = 0;
    222 
    223   // If there is anything wrong with the data, we're not going to use it.
    224   if (!header_size_)
    225     header_ = NULL;
    226 }
    227 
    228 Pickle::Pickle(const Pickle& other)
    229     : header_(NULL),
    230       header_size_(other.header_size_),
    231       capacity_after_header_(0),
    232       write_offset_(other.write_offset_) {
    233   size_t payload_size = header_size_ + other.header_->payload_size;
    234   Resize(payload_size);
    235   memcpy(header_, other.header_, payload_size);
    236 }
    237 
    238 Pickle::~Pickle() {
    239   if (capacity_after_header_ != kCapacityReadOnly)
    240     free(header_);
    241 }
    242 
    243 Pickle& Pickle::operator=(const Pickle& other) {
    244   if (this == &other) {
    245     NOTREACHED();
    246     return *this;
    247   }
    248   if (capacity_after_header_ == kCapacityReadOnly) {
    249     header_ = NULL;
    250     capacity_after_header_ = 0;
    251   }
    252   if (header_size_ != other.header_size_) {
    253     free(header_);
    254     header_ = NULL;
    255     header_size_ = other.header_size_;
    256   }
    257   Resize(other.header_->payload_size);
    258   memcpy(header_, other.header_,
    259          other.header_size_ + other.header_->payload_size);
    260   write_offset_ = other.write_offset_;
    261   return *this;
    262 }
    263 
    264 bool Pickle::WriteString(const std::string& value) {
    265   if (!WriteInt(static_cast<int>(value.size())))
    266     return false;
    267 
    268   return WriteBytes(value.data(), static_cast<int>(value.size()));
    269 }
    270 
    271 bool Pickle::WriteWString(const std::wstring& value) {
    272   if (!WriteInt(static_cast<int>(value.size())))
    273     return false;
    274 
    275   return WriteBytes(value.data(),
    276                     static_cast<int>(value.size() * sizeof(wchar_t)));
    277 }
    278 
    279 bool Pickle::WriteString16(const string16& value) {
    280   if (!WriteInt(static_cast<int>(value.size())))
    281     return false;
    282 
    283   return WriteBytes(value.data(),
    284                     static_cast<int>(value.size()) * sizeof(char16));
    285 }
    286 
    287 bool Pickle::WriteData(const char* data, int length) {
    288   return length >= 0 && WriteInt(length) && WriteBytes(data, length);
    289 }
    290 
    291 bool Pickle::WriteBytes(const void* data, int length) {
    292   WriteBytesCommon(data, length);
    293   return true;
    294 }
    295 
    296 void Pickle::Reserve(size_t length) {
    297   size_t data_len = AlignInt(length, sizeof(uint32));
    298   DCHECK_GE(data_len, length);
    299 #ifdef ARCH_CPU_64_BITS
    300   DCHECK_LE(data_len, kuint32max);
    301 #endif
    302   DCHECK_LE(write_offset_, kuint32max - data_len);
    303   size_t new_size = write_offset_ + data_len;
    304   if (new_size > capacity_after_header_)
    305     Resize(capacity_after_header_ * 2 + new_size);
    306 }
    307 
    308 void Pickle::Resize(size_t new_capacity) {
    309   new_capacity = AlignInt(new_capacity, kPayloadUnit);
    310 
    311   CHECK_NE(capacity_after_header_, kCapacityReadOnly);
    312   void* p = realloc(header_, header_size_ + new_capacity);
    313   CHECK(p);
    314   header_ = reinterpret_cast<Header*>(p);
    315   capacity_after_header_ = new_capacity;
    316 }
    317 
    318 // static
    319 const char* Pickle::FindNext(size_t header_size,
    320                              const char* start,
    321                              const char* end) {
    322   DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32)));
    323   DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
    324 
    325   size_t length = static_cast<size_t>(end - start);
    326   if (length < sizeof(Header))
    327     return NULL;
    328 
    329   const Header* hdr = reinterpret_cast<const Header*>(start);
    330   if (length < header_size || length - header_size < hdr->payload_size)
    331     return NULL;
    332   return start + header_size + hdr->payload_size;
    333 }
    334 
    335 template <size_t length> void Pickle::WriteBytesStatic(const void* data) {
    336   WriteBytesCommon(data, length);
    337 }
    338 
    339 template void Pickle::WriteBytesStatic<2>(const void* data);
    340 template void Pickle::WriteBytesStatic<4>(const void* data);
    341 template void Pickle::WriteBytesStatic<8>(const void* data);
    342 
    343 inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
    344   DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
    345       << "oops: pickle is readonly";
    346   size_t data_len = AlignInt(length, sizeof(uint32));
    347   DCHECK_GE(data_len, length);
    348 #ifdef ARCH_CPU_64_BITS
    349   DCHECK_LE(data_len, kuint32max);
    350 #endif
    351   DCHECK_LE(write_offset_, kuint32max - data_len);
    352   size_t new_size = write_offset_ + data_len;
    353   if (new_size > capacity_after_header_) {
    354     Resize(std::max(capacity_after_header_ * 2, new_size));
    355   }
    356 
    357   char* write = mutable_payload() + write_offset_;
    358   memcpy(write, data, length);
    359   memset(write + length, 0, data_len - length);
    360   header_->payload_size = static_cast<uint32>(new_size);
    361   write_offset_ = new_size;
    362 }
    363