• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "base/pickle.h"
6 
7 #include <stdlib.h>
8 
9 #include <algorithm>  // for max()
10 #include <limits>
11 
12 //------------------------------------------------------------------------------
13 
14 // static
15 const int Pickle::kPayloadUnit = 64;
16 
17 // We mark a read only pickle with a special capacity_.
18 static const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max();
19 
20 // Payload is uint32 aligned.
21 
Pickle()22 Pickle::Pickle()
23     : header_(NULL),
24       header_size_(sizeof(Header)),
25       capacity_(0),
26       variable_buffer_offset_(0) {
27   Resize(kPayloadUnit);
28   header_->payload_size = 0;
29 }
30 
Pickle(int header_size)31 Pickle::Pickle(int header_size)
32     : header_(NULL),
33       header_size_(AlignInt(header_size, sizeof(uint32))),
34       capacity_(0),
35       variable_buffer_offset_(0) {
36   DCHECK(static_cast<size_t>(header_size) >= sizeof(Header));
37   DCHECK(header_size <= kPayloadUnit);
38   Resize(kPayloadUnit);
39   header_->payload_size = 0;
40 }
41 
Pickle(const char * data,int data_len)42 Pickle::Pickle(const char* data, int data_len)
43     : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
44       header_size_(data_len - header_->payload_size),
45       capacity_(kCapacityReadOnly),
46       variable_buffer_offset_(0) {
47   DCHECK(header_size_ >= sizeof(Header));
48   DCHECK(header_size_ == AlignInt(header_size_, sizeof(uint32)));
49 }
50 
Pickle(const Pickle & other)51 Pickle::Pickle(const Pickle& other)
52     : header_(NULL),
53       header_size_(other.header_size_),
54       capacity_(0),
55       variable_buffer_offset_(other.variable_buffer_offset_) {
56   size_t payload_size = header_size_ + other.header_->payload_size;
57   bool resized = Resize(payload_size);
58   CHECK(resized);  // Realloc failed.
59   memcpy(header_, other.header_, payload_size);
60 }
61 
~Pickle()62 Pickle::~Pickle() {
63   if (capacity_ != kCapacityReadOnly)
64     free(header_);
65 }
66 
operator =(const Pickle & other)67 Pickle& Pickle::operator=(const Pickle& other) {
68   if (this == &other) {
69     NOTREACHED();
70     return *this;
71   }
72   if (capacity_ == kCapacityReadOnly) {
73     header_ = NULL;
74     capacity_ = 0;
75   }
76   if (header_size_ != other.header_size_) {
77     free(header_);
78     header_ = NULL;
79     header_size_ = other.header_size_;
80   }
81   bool resized = Resize(other.header_size_ + other.header_->payload_size);
82   CHECK(resized);  // Realloc failed.
83   memcpy(header_, other.header_,
84          other.header_size_ + other.header_->payload_size);
85   variable_buffer_offset_ = other.variable_buffer_offset_;
86   return *this;
87 }
88 
ReadBool(void ** iter,bool * result) const89 bool Pickle::ReadBool(void** iter, bool* result) const {
90   DCHECK(iter);
91 
92   int tmp;
93   if (!ReadInt(iter, &tmp))
94     return false;
95   DCHECK(0 == tmp || 1 == tmp);
96   *result = tmp ? true : false;
97   return true;
98 }
99 
ReadInt(void ** iter,int * result) const100 bool Pickle::ReadInt(void** iter, int* result) const {
101   DCHECK(iter);
102   if (!*iter)
103     *iter = const_cast<char*>(payload());
104 
105   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
106     return false;
107 
108   // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not
109   // dependent on alignment.
110   // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result));
111   *result = *reinterpret_cast<int*>(*iter);
112 
113   UpdateIter(iter, sizeof(*result));
114   return true;
115 }
116 
ReadLong(void ** iter,long * result) const117 bool Pickle::ReadLong(void** iter, long* result) const {
118   DCHECK(iter);
119   if (!*iter)
120     *iter = const_cast<char*>(payload());
121 
122   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
123     return false;
124 
125   // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not
126   // dependent on alignment.
127   memcpy(result, *iter, sizeof(*result));
128 
129   UpdateIter(iter, sizeof(*result));
130   return true;
131 }
132 
ReadLength(void ** iter,int * result) const133 bool Pickle::ReadLength(void** iter, int* result) const {
134   if (!ReadInt(iter, result))
135     return false;
136   return ((*result) >= 0);
137 }
138 
ReadSize(void ** iter,size_t * result) const139 bool Pickle::ReadSize(void** iter, size_t* result) const {
140   DCHECK(iter);
141   if (!*iter)
142     *iter = const_cast<char*>(payload());
143 
144   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
145     return false;
146 
147   // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not
148   // dependent on alignment.
149   // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result));
150   *result = *reinterpret_cast<size_t*>(*iter);
151 
152   UpdateIter(iter, sizeof(*result));
153   return true;
154 }
155 
ReadUInt32(void ** iter,uint32 * result) const156 bool Pickle::ReadUInt32(void** iter, uint32* result) const {
157   DCHECK(iter);
158   if (!*iter)
159     *iter = const_cast<char*>(payload());
160 
161   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
162     return false;
163 
164   memcpy(result, *iter, sizeof(*result));
165 
166   UpdateIter(iter, sizeof(*result));
167   return true;
168 }
169 
ReadInt64(void ** iter,int64 * result) const170 bool Pickle::ReadInt64(void** iter, int64* result) const {
171   DCHECK(iter);
172   if (!*iter)
173     *iter = const_cast<char*>(payload());
174 
175   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
176     return false;
177 
178   memcpy(result, *iter, sizeof(*result));
179 
180   UpdateIter(iter, sizeof(*result));
181   return true;
182 }
183 
ReadUInt64(void ** iter,uint64 * result) const184 bool Pickle::ReadUInt64(void** iter, uint64* result) const {
185   DCHECK(iter);
186   if (!*iter)
187     *iter = const_cast<char*>(payload());
188 
189   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
190     return false;
191 
192   memcpy(result, *iter, sizeof(*result));
193 
194   UpdateIter(iter, sizeof(*result));
195   return true;
196 }
197 
ReadIntPtr(void ** iter,intptr_t * result) const198 bool Pickle::ReadIntPtr(void** iter, intptr_t* result) const {
199   DCHECK(iter);
200   if (!*iter)
201     *iter = const_cast<char*>(payload());
202 
203   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
204     return false;
205 
206   memcpy(result, *iter, sizeof(*result));
207 
208   UpdateIter(iter, sizeof(*result));
209   return true;
210 }
211 
ReadString(void ** iter,std::string * result) const212 bool Pickle::ReadString(void** iter, std::string* result) const {
213   DCHECK(iter);
214 
215   int len;
216   if (!ReadLength(iter, &len))
217     return false;
218   if (!IteratorHasRoomFor(*iter, len))
219     return false;
220 
221   char* chars = reinterpret_cast<char*>(*iter);
222   result->assign(chars, len);
223 
224   UpdateIter(iter, len);
225   return true;
226 }
227 
ReadWString(void ** iter,std::wstring * result) const228 bool Pickle::ReadWString(void** iter, std::wstring* result) const {
229   DCHECK(iter);
230 
231   int len;
232   if (!ReadLength(iter, &len))
233     return false;
234   // Avoid integer overflow.
235   if (len > INT_MAX / static_cast<int>(sizeof(wchar_t)))
236     return false;
237   if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t)))
238     return false;
239 
240   wchar_t* chars = reinterpret_cast<wchar_t*>(*iter);
241   result->assign(chars, len);
242 
243   UpdateIter(iter, len * sizeof(wchar_t));
244   return true;
245 }
246 
ReadString16(void ** iter,string16 * result) const247 bool Pickle::ReadString16(void** iter, string16* result) const {
248   DCHECK(iter);
249 
250   int len;
251   if (!ReadLength(iter, &len))
252     return false;
253   if (!IteratorHasRoomFor(*iter, len * sizeof(char16)))
254     return false;
255 
256   char16* chars = reinterpret_cast<char16*>(*iter);
257   result->assign(chars, len);
258 
259   UpdateIter(iter, len * sizeof(char16));
260   return true;
261 }
262 
ReadBytes(void ** iter,const char ** data,int length) const263 bool Pickle::ReadBytes(void** iter, const char** data, int length) const {
264   DCHECK(iter);
265   DCHECK(data);
266   *data = 0;
267 
268   if (!IteratorHasRoomFor(*iter, length))
269     return false;
270 
271   *data = reinterpret_cast<const char*>(*iter);
272 
273   UpdateIter(iter, length);
274   return true;
275 }
276 
ReadData(void ** iter,const char ** data,int * length) const277 bool Pickle::ReadData(void** iter, const char** data, int* length) const {
278   DCHECK(iter);
279   DCHECK(data);
280   DCHECK(length);
281   *length = 0;
282   *data = 0;
283 
284   if (!ReadLength(iter, length))
285     return false;
286 
287   return ReadBytes(iter, data, *length);
288 }
289 
BeginWrite(size_t length)290 char* Pickle::BeginWrite(size_t length) {
291   // write at a uint32-aligned offset from the beginning of the header
292   size_t offset = AlignInt(header_->payload_size, sizeof(uint32));
293 
294   size_t new_size = offset + length;
295   size_t needed_size = header_size_ + new_size;
296   if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
297     return NULL;
298 
299 #ifdef ARCH_CPU_64_BITS
300   DCHECK_LE(length, std::numeric_limits<uint32>::max());
301 #endif
302 
303   header_->payload_size = static_cast<uint32>(new_size);
304   return payload() + offset;
305 }
306 
EndWrite(char * dest,int length)307 void Pickle::EndWrite(char* dest, int length) {
308   // Zero-pad to keep tools like purify from complaining about uninitialized
309   // memory.
310   if (length % sizeof(uint32))
311     memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32)));
312 }
313 
WriteBytes(const void * data,int data_len)314 bool Pickle::WriteBytes(const void* data, int data_len) {
315   DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly";
316 
317   char* dest = BeginWrite(data_len);
318   if (!dest)
319     return false;
320 
321   memcpy(dest, data, data_len);
322 
323   EndWrite(dest, data_len);
324   return true;
325 }
326 
WriteString(const std::string & value)327 bool Pickle::WriteString(const std::string& value) {
328   if (!WriteInt(static_cast<int>(value.size())))
329     return false;
330 
331   return WriteBytes(value.data(), static_cast<int>(value.size()));
332 }
333 
WriteWString(const std::wstring & value)334 bool Pickle::WriteWString(const std::wstring& value) {
335   if (!WriteInt(static_cast<int>(value.size())))
336     return false;
337 
338   return WriteBytes(value.data(),
339                     static_cast<int>(value.size() * sizeof(wchar_t)));
340 }
341 
WriteString16(const string16 & value)342 bool Pickle::WriteString16(const string16& value) {
343   if (!WriteInt(static_cast<int>(value.size())))
344     return false;
345 
346   return WriteBytes(value.data(),
347                     static_cast<int>(value.size()) * sizeof(char16));
348 }
349 
WriteData(const char * data,int length)350 bool Pickle::WriteData(const char* data, int length) {
351   return length >= 0 && WriteInt(length) && WriteBytes(data, length);
352 }
353 
BeginWriteData(int length)354 char* Pickle::BeginWriteData(int length) {
355   DCHECK_EQ(variable_buffer_offset_, 0U) <<
356     "There can only be one variable buffer in a Pickle";
357 
358   if (length < 0 || !WriteInt(length))
359     return NULL;
360 
361   char *data_ptr = BeginWrite(length);
362   if (!data_ptr)
363     return NULL;
364 
365   variable_buffer_offset_ =
366       data_ptr - reinterpret_cast<char*>(header_) - sizeof(int);
367 
368   // EndWrite doesn't necessarily have to be called after the write operation,
369   // so we call it here to pad out what the caller will eventually write.
370   EndWrite(data_ptr, length);
371   return data_ptr;
372 }
373 
TrimWriteData(int new_length)374 void Pickle::TrimWriteData(int new_length) {
375   DCHECK_NE(variable_buffer_offset_, 0U);
376 
377   // Fetch the the variable buffer size
378   int* cur_length = reinterpret_cast<int*>(
379       reinterpret_cast<char*>(header_) + variable_buffer_offset_);
380 
381   if (new_length < 0 || new_length > *cur_length) {
382     NOTREACHED() << "Invalid length in TrimWriteData.";
383     return;
384   }
385 
386   // Update the payload size and variable buffer size
387   header_->payload_size -= (*cur_length - new_length);
388   *cur_length = new_length;
389 }
390 
Resize(size_t new_capacity)391 bool Pickle::Resize(size_t new_capacity) {
392   new_capacity = AlignInt(new_capacity, kPayloadUnit);
393 
394   CHECK(capacity_ != kCapacityReadOnly);
395   void* p = realloc(header_, new_capacity);
396   if (!p)
397     return false;
398 
399   header_ = reinterpret_cast<Header*>(p);
400   capacity_ = new_capacity;
401   return true;
402 }
403 
404 // static
FindNext(size_t header_size,const char * start,const char * end)405 const char* Pickle::FindNext(size_t header_size,
406                              const char* start,
407                              const char* end) {
408   DCHECK(header_size == AlignInt(header_size, sizeof(uint32)));
409   DCHECK(header_size <= static_cast<size_t>(kPayloadUnit));
410 
411   const Header* hdr = reinterpret_cast<const Header*>(start);
412   const char* payload_base = start + header_size;
413   const char* payload_end = payload_base + hdr->payload_size;
414   if (payload_end < payload_base)
415     return NULL;
416 
417   return (payload_end > end) ? NULL : payload_end;
418 }
419