pickle.h revision dc0f95d653279beabeb9817299e2902918ba123e
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/basictypes.h"
12#include "base/gtest_prod_util.h"
13#include "base/logging.h"
14#include "base/string16.h"
15
16// This class provides facilities for basic binary value packing and unpacking.
17//
18// The Pickle class supports appending primitive values (ints, strings, etc.)
19// to a pickle instance.  The Pickle instance grows its internal memory buffer
20// dynamically to hold the sequence of primitive values.   The internal memory
21// buffer is exposed as the "data" of the Pickle.  This "data" can be passed
22// to a Pickle object to initialize it for reading.
23//
24// When reading from a Pickle object, it is important for the consumer to know
25// what value types to read and in what order to read them as the Pickle does
26// not keep track of the type of data written to it.
27//
28// The Pickle's data has a header which contains the size of the Pickle's
29// payload.  It can optionally support additional space in the header.  That
30// space is controlled by the header_size parameter passed to the Pickle
31// constructor.
32//
33class Pickle {
34 public:
35  // Initialize a Pickle object using the default header size.
36  Pickle();
37
38  // Initialize a Pickle object with the specified header size in bytes, which
39  // must be greater-than-or-equal-to sizeof(Pickle::Header).  The header size
40  // will be rounded up to ensure that the header size is 32bit-aligned.
41  explicit Pickle(int header_size);
42
43  // Initializes a Pickle from a const block of data.  The data is not copied;
44  // instead the data is merely referenced by this Pickle.  Only const methods
45  // should be used on the Pickle when initialized this way.  The header
46  // padding size is deduced from the data length.
47  Pickle(const char* data, int data_len);
48
49  // Initializes a Pickle as a deep copy of another Pickle.
50  Pickle(const Pickle& other);
51
52  virtual ~Pickle();
53
54  // Performs a deep copy.
55  Pickle& operator=(const Pickle& other);
56
57  // Returns the size of the Pickle's data.
58  size_t size() const { return header_size_ + 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 ReadUInt16(void** iter, uint16* result) const;
72  bool ReadUInt32(void** iter, uint32* result) const;
73  bool ReadInt64(void** iter, int64* result) const;
74  bool ReadUInt64(void** iter, uint64* 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 WriteUInt16(uint16 value) {
102    return WriteBytes(&value, sizeof(value));
103  }
104  bool WriteUInt32(uint32 value) {
105    return WriteBytes(&value, sizeof(value));
106  }
107  bool WriteInt64(int64 value) {
108    return WriteBytes(&value, sizeof(value));
109  }
110  bool WriteUInt64(uint64 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_EQ(header_size_, sizeof(T));
151    return static_cast<T*>(header_);
152  }
153  template <class T>
154  const T* headerT() const {
155    DCHECK_EQ(header_size_, sizeof(T));
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    // We must have a valid header_.
184    return payload() + payload_size();
185  }
186  const char* end_of_payload() const {
187    // This object may be invalid.
188    return header_ ? payload() + payload_size() : NULL;
189  }
190
191  size_t capacity() const {
192    return capacity_;
193  }
194
195  // Resizes the buffer for use when writing the specified amount of data. The
196  // location that the data should be written at is returned, or NULL if there
197  // was an error. Call EndWrite with the returned offset and the given length
198  // to pad out for the next write.
199  char* BeginWrite(size_t length);
200
201  // Completes the write operation by padding the data with NULL bytes until it
202  // is padded. Should be paired with BeginWrite, but it does not necessarily
203  // have to be called after the data is written.
204  void EndWrite(char* dest, int length);
205
206  // Resize the capacity, note that the input value should include the size of
207  // the header: new_capacity = sizeof(Header) + desired_payload_capacity.
208  // A realloc() failure will cause a Resize failure... and caller should check
209  // the return result for true (i.e., successful resizing).
210  bool Resize(size_t new_capacity);
211
212  // Aligns 'i' by rounding it up to the next multiple of 'alignment'
213  static size_t AlignInt(size_t i, int alignment) {
214    return i + (alignment - (i % alignment)) % alignment;
215  }
216
217  // Moves the iterator by the given number of bytes, making sure it is aligned.
218  // Pointer (iterator) is NOT aligned, but the change in the pointer
219  // is guaranteed to be a multiple of sizeof(uint32).
220  static void UpdateIter(void** iter, int bytes) {
221    *iter = static_cast<char*>(*iter) + AlignInt(bytes, sizeof(uint32));
222  }
223
224  // Find the end of the pickled data that starts at range_start.  Returns NULL
225  // if the entire Pickle is not found in the given data range.
226  static const char* FindNext(size_t header_size,
227                              const char* range_start,
228                              const char* range_end);
229
230  // The allocation granularity of the payload.
231  static const int kPayloadUnit;
232
233 private:
234  Header* header_;
235  size_t header_size_;  // Supports extra data between header and payload.
236  // Allocation size of payload (or -1 if allocation is const).
237  size_t capacity_;
238  size_t variable_buffer_offset_;  // IF non-zero, then offset to a buffer.
239
240  FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize);
241  FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNext);
242  FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextWithIncompleteHeader);
243  FRIEND_TEST_ALL_PREFIXES(PickleTest, IteratorHasRoom);
244};
245
246#endif  // BASE_PICKLE_H__
247