diff options
Diffstat (limited to 'ipc/chromium/src/base/pickle.h')
-rw-r--r-- | ipc/chromium/src/base/pickle.h | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/ipc/chromium/src/base/pickle.h b/ipc/chromium/src/base/pickle.h new file mode 100644 index 0000000000..5f64880848 --- /dev/null +++ b/ipc/chromium/src/base/pickle.h @@ -0,0 +1,284 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_PICKLE_H__ +#define BASE_PICKLE_H__ + +#include <string> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/string16.h" + +#include "mozilla/Attributes.h" +#include "mozilla/BufferList.h" +#include "mozilla/mozalloc.h" +#include "mozilla/TimeStamp.h" +#if !defined(FUZZING) && (!defined(RELEASE_OR_BETA) || defined(DEBUG)) +# define MOZ_PICKLE_SENTINEL_CHECKING +#endif +class Pickle; +class PickleIterator { + public: + explicit PickleIterator(const Pickle& pickle); + + private: + friend class Pickle; + + mozilla::BufferList<InfallibleAllocPolicy>::IterImpl iter_; + + template <typename T> + void CopyInto(T* dest); +}; + +// This class provides facilities for basic binary value packing and unpacking. +// +// The Pickle class supports appending primitive values (ints, strings, etc.) +// to a pickle instance. The Pickle instance grows its internal memory buffer +// dynamically to hold the sequence of primitive values. The internal memory +// buffer is exposed as the "data" of the Pickle. This "data" can be passed +// to a Pickle object to initialize it for reading. +// +// When reading from a Pickle object, it is important for the consumer to know +// what value types to read and in what order to read them as the Pickle does +// not keep track of the type of data written to it. +// +// The Pickle's data has a header which contains the size of the Pickle's +// payload. It can optionally support additional space in the header. That +// space is controlled by the header_size parameter passed to the Pickle +// constructor. +// +class Pickle { + public: + ~Pickle(); + + Pickle() = delete; + + // Initialize a Pickle object with the specified header size in bytes, which + // must be greater-than-or-equal-to sizeof(Pickle::Header). The header size + // will be rounded up to ensure that the header size is 32bit-aligned. + explicit Pickle(uint32_t header_size, size_t segment_capacity = 0); + + Pickle(uint32_t header_size, const char* data, uint32_t length); + + Pickle(const Pickle& other) = delete; + + Pickle(Pickle&& other); + + // Performs a deep copy. + Pickle& operator=(const Pickle& other) = delete; + + Pickle& operator=(Pickle&& other); + + void CopyFrom(const Pickle& other); + + // Returns the size of the Pickle's data. + uint32_t size() const { return header_size_ + header_->payload_size; } + + typedef mozilla::BufferList<InfallibleAllocPolicy> BufferList; + + const BufferList& Buffers() const { return buffers_; } + + uint32_t CurrentSize() const { return buffers_.Size(); } + + // Methods for reading the payload of the Pickle. To read from the start of + // the Pickle, initialize *iter to NULL. If successful, these methods return + // true. Otherwise, false is returned to indicate that the result could not + // be extracted. + [[nodiscard]] bool ReadBool(PickleIterator* iter, bool* result) const; + [[nodiscard]] bool ReadInt16(PickleIterator* iter, int16_t* result) const; + [[nodiscard]] bool ReadUInt16(PickleIterator* iter, uint16_t* result) const; + [[nodiscard]] bool ReadShort(PickleIterator* iter, short* result) const; + [[nodiscard]] bool ReadInt(PickleIterator* iter, int* result) const; + [[nodiscard]] bool ReadLong(PickleIterator* iter, long* result) const; + [[nodiscard]] bool ReadULong(PickleIterator* iter, + unsigned long* result) const; + [[nodiscard]] bool ReadInt32(PickleIterator* iter, int32_t* result) const; + [[nodiscard]] bool ReadUInt32(PickleIterator* iter, uint32_t* result) const; + [[nodiscard]] bool ReadInt64(PickleIterator* iter, int64_t* result) const; + [[nodiscard]] bool ReadUInt64(PickleIterator* iter, uint64_t* result) const; + [[nodiscard]] bool ReadDouble(PickleIterator* iter, double* result) const; + [[nodiscard]] bool ReadIntPtr(PickleIterator* iter, intptr_t* result) const; + [[nodiscard]] bool ReadUnsignedChar(PickleIterator* iter, + unsigned char* result) const; + [[nodiscard]] bool ReadString(PickleIterator* iter, + std::string* result) const; + [[nodiscard]] bool ReadWString(PickleIterator* iter, + std::wstring* result) const; + [[nodiscard]] bool ReadBytesInto(PickleIterator* iter, void* data, + uint32_t length) const; + + // Safer version of ReadInt() checks for the result not being negative. + // Use it for reading the object sizes. + [[nodiscard]] bool ReadLength(PickleIterator* iter, int* result) const; + + [[nodiscard]] bool IgnoreBytes(PickleIterator* iter, uint32_t length) const; + + [[nodiscard]] bool ReadSentinel(PickleIterator* iter, uint32_t sentinel) const +#ifdef MOZ_PICKLE_SENTINEL_CHECKING + ; +#else + { + return true; + } +#endif + + template <class T> + [[nodiscard]] bool ReadScalar(PickleIterator* iter, T* result) const { + DCHECK(iter); + + if (!IteratorHasRoomFor(*iter, sizeof(*result))) + return ReadBytesInto(iter, result, sizeof(*result)); + + iter->CopyInto(result); + + UpdateIter(iter, sizeof(*result)); + return true; + } + + bool IgnoreSentinel(PickleIterator* iter) const +#ifdef MOZ_PICKLE_SENTINEL_CHECKING + ; +#else + { + return true; + } +#endif + + // NOTE: The message type optional parameter should _only_ be called from + // generated IPDL code, as it is used to trigger the IPC_READ_LATENCY_MS + // telemetry probe. + void EndRead(PickleIterator& iter, uint32_t ipcMessageType = 0) const; + + // Returns true if the given iterator has at least |len| bytes remaining it, + // across all segments. If there is not that much data available, returns + // false. Generally used when reading a (len, data) pair from the message, + // before allocating |len| bytes of space, to ensure that reading |len| bytes + // will succeed. + bool HasBytesAvailable(const PickleIterator* iter, uint32_t len) const; + + // Truncate the message at the current point, discarding any data after this + // point in the message. + void Truncate(PickleIterator* iter); + + // Methods for adding to the payload of the Pickle. These values are + // appended to the end of the Pickle's payload. When reading values from a + // Pickle, it is important to read them in the order in which they were added + // to the Pickle. + bool WriteBool(bool value); + bool WriteInt16(int16_t value); + bool WriteUInt16(uint16_t value); + bool WriteInt(int value); + bool WriteLong(long value); + bool WriteULong(unsigned long value); + bool WriteInt32(int32_t value); + bool WriteUInt32(uint32_t value); + bool WriteInt64(int64_t value); + bool WriteUInt64(uint64_t value); + bool WriteDouble(double value); + bool WriteIntPtr(intptr_t value); + bool WriteUnsignedChar(unsigned char value); + bool WriteString(const std::string& value); + bool WriteWString(const std::wstring& value); + bool WriteData(const char* data, uint32_t length); + bool WriteBytes(const void* data, uint32_t data_len); + // Takes ownership of data + bool WriteBytesZeroCopy(void* data, uint32_t data_len, uint32_t capacity); + + bool WriteSentinel(uint32_t sentinel) +#ifdef MOZ_PICKLE_SENTINEL_CHECKING + ; +#else + { + return true; + } +#endif + + int32_t* GetInt32PtrForTest(uint32_t offset); + + void InputBytes(const char* data, uint32_t length); + + // Payload follows after allocation of Header (header size is customizable). + struct Header { + uint32_t payload_size; // Specifies the size of the payload. + }; + + // Returns the header, cast to a user-specified type T. The type T must be a + // subclass of Header and its size must correspond to the header_size passed + // to the Pickle constructor. + template <class T> + T* headerT() { + DCHECK(sizeof(T) == header_size_); + return static_cast<T*>(header_); + } + template <class T> + const T* headerT() const { + DCHECK(sizeof(T) == header_size_); + return static_cast<const T*>(header_); + } + + typedef uint32_t memberAlignmentType; + + protected: + uint32_t payload_size() const { return header_->payload_size; } + + // Resizes the buffer for use when writing the specified amount of data. Call + // EndWrite with the given length to pad out for the next write. + void BeginWrite(uint32_t length); + + // Completes the write operation by padding the data with poison bytes. Should + // be paired with BeginWrite, but it does not necessarily have to be called + // after the data is written. + void EndWrite(uint32_t length); + + // Round 'bytes' up to the next multiple of 'alignment'. 'alignment' must be + // a power of 2. + template <uint32_t alignment> + struct ConstantAligner { + static uint32_t align(int bytes) { + static_assert((alignment & (alignment - 1)) == 0, + "alignment must be a power of two"); + return (bytes + (alignment - 1)) & ~static_cast<uint32_t>(alignment - 1); + } + }; + + static uint32_t AlignInt(int bytes) { + return ConstantAligner<sizeof(memberAlignmentType)>::align(bytes); + } + + static uint32_t AlignCapacity(int bytes) { + return ConstantAligner<kSegmentAlignment>::align(bytes); + } + + // Returns true if the given iterator could point to data with the given + // length. If there is no room for the given data before the end of the + // payload, returns false. + bool IteratorHasRoomFor(const PickleIterator& iter, uint32_t len) const; + + // Moves the iterator by the given number of bytes, making sure it is aligned. + // Pointer (iterator) is NOT aligned, but the change in the pointer + // is guaranteed to be a multiple of sizeof(memberAlignmentType). + void UpdateIter(PickleIterator* iter, uint32_t bytes) const; + + // Figure out how big the message starting at range_start is. Returns 0 if + // there's no enough data to determine (i.e., if [range_start, range_end) does + // not contain enough of the message header to know the size). + static uint32_t MessageSize(uint32_t header_size, const char* range_start, + const char* range_end); + + // Segments capacities are aligned to 8 bytes to ensure that all reads/writes + // at 8-byte aligned offsets will be on 8-byte aligned pointers. + static const uint32_t kSegmentAlignment = 8; + + private: + friend class PickleIterator; + + BufferList buffers_; + Header* header_; + uint32_t header_size_; +}; + +#endif // BASE_PICKLE_H__ |