Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2006-2008 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 #ifndef BASE_PICKLE_H__
      6 #define BASE_PICKLE_H__
      7 
      8 #include <string>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/logging.h"
     12 #include "base/string16.h"
     13 #include "testing/gtest/include/gtest/gtest_prod.h"
     14 
     15 // This class provides facilities for basic binary value packing and unpacking.
     16 //
     17 // The Pickle class supports appending primitive values (ints, strings, etc.)
     18 // to a pickle instance.  The Pickle instance grows its internal memory buffer
     19 // dynamically to hold the sequence of primitive values.   The internal memory
     20 // buffer is exposed as the "data" of the Pickle.  This "data" can be passed
     21 // to a Pickle object to initialize it for reading.
     22 //
     23 // When reading from a Pickle object, it is important for the consumer to know
     24 // what value types to read and in what order to read them as the Pickle does
     25 // not keep track of the type of data written to it.
     26 //
     27 // The Pickle's data has a header which contains the size of the Pickle's
     28 // payload.  It can optionally support additional space in the header.  That
     29 // space is controlled by the header_size parameter passed to the Pickle
     30 // constructor.
     31 //
     32 class Pickle {
     33  public:
     34   virtual ~Pickle();
     35 
     36   // Initialize a Pickle object using the default header size.
     37   Pickle();
     38 
     39   // Initialize a Pickle object with the specified header size in bytes, which
     40   // must be greater-than-or-equal-to sizeof(Pickle::Header).  The header size
     41   // will be rounded up to ensure that the header size is 32bit-aligned.
     42   explicit Pickle(int header_size);
     43 
     44   // Initializes a Pickle from a const block of data.  The data is not copied;
     45   // instead the data is merely referenced by this Pickle.  Only const methods
     46   // should be used on the Pickle when initialized this way.  The header
     47   // padding size is deduced from the data length.
     48   Pickle(const char* data, int data_len);
     49 
     50   // Initializes a Pickle as a deep copy of another Pickle.
     51   Pickle(const Pickle& other);
     52 
     53   // Performs a deep copy.
     54   Pickle& operator=(const Pickle& other);
     55 
     56   // Returns the size of the Pickle's data.
     57   int size() const { return static_cast<int>(header_size_ +
     58                                              header_->payload_size); }
     59 
     60   // Returns the data for this Pickle.
     61   const void* data() const { return header_; }
     62 
     63   // Methods for reading the payload of the Pickle.  To read from the start of
     64   // the Pickle, initialize *iter to NULL.  If successful, these methods return
     65   // true.  Otherwise, false is returned to indicate that the result could not
     66   // be extracted.
     67   bool ReadBool(void** iter, bool* result) const;
     68   bool ReadInt(void** iter, int* result) const;
     69   bool ReadLong(void** iter, long* result) const;
     70   bool ReadSize(void** iter, size_t* result) const;
     71   bool ReadUInt32(void** iter, uint32* result) const;
     72   bool ReadInt64(void** iter, int64* result) const;
     73   bool ReadUInt64(void** iter, uint64* result) const;
     74   bool ReadIntPtr(void** iter, intptr_t* result) const;
     75   bool ReadString(void** iter, std::string* result) const;
     76   bool ReadWString(void** iter, std::wstring* result) const;
     77   bool ReadString16(void** iter, string16* result) const;
     78   bool ReadData(void** iter, const char** data, int* length) const;
     79   bool ReadBytes(void** iter, const char** data, int length) const;
     80 
     81   // Safer version of ReadInt() checks for the result not being negative.
     82   // Use it for reading the object sizes.
     83   bool ReadLength(void** iter, int* result) const;
     84 
     85   // Methods for adding to the payload of the Pickle.  These values are
     86   // appended to the end of the Pickle's payload.  When reading values from a
     87   // Pickle, it is important to read them in the order in which they were added
     88   // to the Pickle.
     89   bool WriteBool(bool value) {
     90     return WriteInt(value ? 1 : 0);
     91   }
     92   bool WriteInt(int value) {
     93     return WriteBytes(&value, sizeof(value));
     94   }
     95   bool WriteLong(long value) {
     96     return WriteBytes(&value, sizeof(value));
     97   }
     98   bool WriteSize(size_t value) {
     99     return WriteBytes(&value, sizeof(value));
    100   }
    101   bool WriteUInt32(uint32 value) {
    102     return WriteBytes(&value, sizeof(value));
    103   }
    104   bool WriteInt64(int64 value) {
    105     return WriteBytes(&value, sizeof(value));
    106   }
    107   bool WriteUInt64(uint64 value) {
    108     return WriteBytes(&value, sizeof(value));
    109   }
    110   bool WriteIntPtr(intptr_t value) {
    111     return WriteBytes(&value, sizeof(value));
    112   }
    113   bool WriteString(const std::string& value);
    114   bool WriteWString(const std::wstring& value);
    115   bool WriteString16(const string16& value);
    116   bool WriteData(const char* data, int length);
    117   bool WriteBytes(const void* data, int data_len);
    118 
    119   // Same as WriteData, but allows the caller to write directly into the
    120   // Pickle. This saves a copy in cases where the data is not already
    121   // available in a buffer. The caller should take care to not write more
    122   // than the length it declares it will. Use ReadData to get the data.
    123   // Returns NULL on failure.
    124   //
    125   // The returned pointer will only be valid until the next write operation
    126   // on this Pickle.
    127   char* BeginWriteData(int length);
    128 
    129   // For Pickles which contain variable length buffers (e.g. those created
    130   // with BeginWriteData), the Pickle can
    131   // be 'trimmed' if the amount of data required is less than originally
    132   // requested.  For example, you may have created a buffer with 10K of data,
    133   // but decided to only fill 10 bytes of that data.  Use this function
    134   // to trim the buffer so that we don't send 9990 bytes of unused data.
    135   // You cannot increase the size of the variable buffer; only shrink it.
    136   // This function assumes that the length of the variable buffer has
    137   // not been changed.
    138   void TrimWriteData(int length);
    139 
    140   // Payload follows after allocation of Header (header size is customizable).
    141   struct Header {
    142     uint32 payload_size;  // Specifies the size of the payload.
    143   };
    144 
    145   // Returns the header, cast to a user-specified type T.  The type T must be a
    146   // subclass of Header and its size must correspond to the header_size passed
    147   // to the Pickle constructor.
    148   template <class T>
    149   T* headerT() {
    150     DCHECK(sizeof(T) == header_size_);
    151     return static_cast<T*>(header_);
    152   }
    153   template <class T>
    154   const T* headerT() const {
    155     DCHECK(sizeof(T) == header_size_);
    156     return static_cast<const T*>(header_);
    157   }
    158 
    159   // Returns true if the given iterator could point to data with the given
    160   // length. If there is no room for the given data before the end of the
    161   // payload, returns false.
    162   bool IteratorHasRoomFor(const void* iter, int len) const {
    163     if ((len < 0) || (iter < header_) || iter > end_of_payload())
    164       return false;
    165     const char* end_of_region = reinterpret_cast<const char*>(iter) + len;
    166     // Watch out for overflow in pointer calculation, which wraps.
    167     return (iter <= end_of_region) && (end_of_region <= end_of_payload());
    168   }
    169 
    170  protected:
    171   size_t payload_size() const { return header_->payload_size; }
    172 
    173   char* payload() {
    174     return reinterpret_cast<char*>(header_) + header_size_;
    175   }
    176   const char* payload() const {
    177     return reinterpret_cast<const char*>(header_) + header_size_;
    178   }
    179 
    180   // Returns the address of the byte immediately following the currently valid
    181   // header + payload.
    182   char* end_of_payload() {
    183     return payload() + payload_size();
    184   }
    185   const char* end_of_payload() const {
    186     return payload() + payload_size();
    187   }
    188 
    189   size_t capacity() const {
    190     return capacity_;
    191   }
    192 
    193   // Resizes the buffer for use when writing the specified amount of data. The
    194   // location that the data should be written at is returned, or NULL if there
    195   // was an error. Call EndWrite with the returned offset and the given length
    196   // to pad out for the next write.
    197   char* BeginWrite(size_t length);
    198 
    199   // Completes the write operation by padding the data with NULL bytes until it
    200   // is padded. Should be paired with BeginWrite, but it does not necessarily
    201   // have to be called after the data is written.
    202   void EndWrite(char* dest, int length);
    203 
    204   // Resize the capacity, note that the input value should include the size of
    205   // the header: new_capacity = sizeof(Header) + desired_payload_capacity.
    206   // A realloc() failure will cause a Resize failure... and caller should check
    207   // the return result for true (i.e., successful resizing).
    208   bool Resize(size_t new_capacity);
    209 
    210   // Aligns 'i' by rounding it up to the next multiple of 'alignment'
    211   static size_t AlignInt(size_t i, int alignment) {
    212     return i + (alignment - (i % alignment)) % alignment;
    213   }
    214 
    215   // Moves the iterator by the given number of bytes, making sure it is aligned.
    216   // Pointer (iterator) is NOT aligned, but the change in the pointer
    217   // is guaranteed to be a multiple of sizeof(uint32).
    218   static void UpdateIter(void** iter, int bytes) {
    219     *iter = static_cast<char*>(*iter) + AlignInt(bytes, sizeof(uint32));
    220   }
    221 
    222   // Find the end of the pickled data that starts at range_start.  Returns NULL
    223   // if the entire Pickle is not found in the given data range.
    224   static const char* FindNext(size_t header_size,
    225                               const char* range_start,
    226                               const char* range_end);
    227 
    228   // The allocation granularity of the payload.
    229   static const int kPayloadUnit;
    230 
    231  private:
    232   Header* header_;
    233   size_t header_size_;  // Supports extra data between header and payload.
    234   // Allocation size of payload (or -1 if allocation is const).
    235   size_t capacity_;
    236   size_t variable_buffer_offset_;  // IF non-zero, then offset to a buffer.
    237 
    238   FRIEND_TEST(PickleTest, Resize);
    239   FRIEND_TEST(PickleTest, FindNext);
    240   FRIEND_TEST(PickleTest, IteratorHasRoom);
    241 };
    242 
    243 #endif  // BASE_PICKLE_H__
    244