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