Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2012 The Chromium Authors |
license.bot | bf09a50 | 2008-08-24 00:55:55 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 4 | |
tfarina | a3116351 | 2015-05-13 22:10:15 | [diff] [blame] | 5 | #ifndef BASE_PICKLE_H_ |
| 6 | #define BASE_PICKLE_H_ |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 7 | |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 8 | #include <stddef.h> |
avi | c027914 | 2015-12-04 22:38:52 | [diff] [blame] | 9 | #include <stdint.h> |
| 10 | |
Arthur Sonzogni | e5fff99c | 2024-02-21 15:58:24 | [diff] [blame] | 11 | #include <optional> |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 12 | #include <string> |
Austin Sullivan | 31fcd06b | 2024-01-10 22:18:29 | [diff] [blame] | 13 | #include <string_view> |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 14 | |
[email protected] | 0bea725 | 2011-08-05 15:34:00 | [diff] [blame] | 15 | #include "base/base_export.h" |
Hans Wennborg | 7b53371 | 2020-06-22 20:52:27 | [diff] [blame] | 16 | #include "base/check_op.h" |
Peter Kasting | 62b937d | 2024-10-09 20:47:44 | [diff] [blame] | 17 | #include "base/compiler_specific.h" |
Peter Kasting | 4acf706 | 2024-10-15 21:41:28 | [diff] [blame] | 18 | #include "base/containers/checked_iterators.h" |
Jeremy Roman | 2d8d780 | 2020-06-11 22:08:20 | [diff] [blame] | 19 | #include "base/containers/span.h" |
[email protected] | a918f87 | 2010-06-01 14:30:51 | [diff] [blame] | 20 | #include "base/gtest_prod_util.h" |
Keishi Hattori | 488b760 | 2022-05-02 13:09:31 | [diff] [blame] | 21 | #include "base/memory/raw_ptr_exclusion.h" |
rockot | 502c94f | 2016-02-03 20:20:16 | [diff] [blame] | 22 | #include "base/memory/ref_counted.h" |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 23 | |
brettw | 05cfd8ddb | 2015-06-02 07:02:47 | [diff] [blame] | 24 | namespace base { |
| 25 | |
[email protected] | ce208f87 | 2012-03-07 20:42:56 | [diff] [blame] | 26 | class Pickle; |
| 27 | |
| 28 | // PickleIterator reads data from a Pickle. The Pickle object must remain valid |
| 29 | // while the PickleIterator object is in use. |
| 30 | class BASE_EXPORT PickleIterator { |
| 31 | public: |
Raul Tambre | f191b59 | 2019-01-21 23:56:29 | [diff] [blame] | 32 | PickleIterator() : payload_(nullptr), read_index_(0), end_index_(0) {} |
[email protected] | ce208f87 | 2012-03-07 20:42:56 | [diff] [blame] | 33 | explicit PickleIterator(const Pickle& pickle); |
| 34 | |
| 35 | // Methods for reading the payload of the Pickle. To read from the start of |
| 36 | // the Pickle, create a PickleIterator from a Pickle. If successful, these |
| 37 | // methods return true. Otherwise, false is returned to indicate that the |
avi | 48fc13b | 2014-12-28 23:31:48 | [diff] [blame] | 38 | // result could not be extracted. It is not possible to read from the iterator |
[email protected] | a15016f | 2014-06-02 23:23:49 | [diff] [blame] | 39 | // after that. |
Daniel Cheng | 4455c984 | 2022-01-13 23:26:37 | [diff] [blame] | 40 | [[nodiscard]] bool ReadBool(bool* result); |
| 41 | [[nodiscard]] bool ReadInt(int* result); |
| 42 | [[nodiscard]] bool ReadLong(long* result); |
| 43 | [[nodiscard]] bool ReadUInt16(uint16_t* result); |
| 44 | [[nodiscard]] bool ReadUInt32(uint32_t* result); |
| 45 | [[nodiscard]] bool ReadInt64(int64_t* result); |
| 46 | [[nodiscard]] bool ReadUInt64(uint64_t* result); |
| 47 | [[nodiscard]] bool ReadFloat(float* result); |
| 48 | [[nodiscard]] bool ReadDouble(double* result); |
| 49 | [[nodiscard]] bool ReadString(std::string* result); |
Helmut Januschka | 1dce9dc | 2024-06-11 13:05:35 | [diff] [blame] | 50 | // The std::string_view data will only be valid for the lifetime of the |
| 51 | // message. |
| 52 | [[nodiscard]] bool ReadStringPiece(std::string_view* result); |
Daniel Cheng | 4455c984 | 2022-01-13 23:26:37 | [diff] [blame] | 53 | [[nodiscard]] bool ReadString16(std::u16string* result); |
Helmut Januschka | 1dce9dc | 2024-06-11 13:05:35 | [diff] [blame] | 54 | // The std::u16string_view data will only be valid for the lifetime of the |
| 55 | // message. |
| 56 | [[nodiscard]] bool ReadStringPiece16(std::u16string_view* result); |
avi | 48fc13b | 2014-12-28 23:31:48 | [diff] [blame] | 57 | |
| 58 | // A pointer to the data will be placed in |*data|, and the length will be |
| 59 | // placed in |*length|. The pointer placed into |*data| points into the |
| 60 | // message's buffer so it will be scoped to the lifetime of the message (or |
| 61 | // until the message data is mutated). Do not keep the pointer around! |
Peter Kasting | 28b51cf | 2022-06-28 15:02:43 | [diff] [blame] | 62 | [[nodiscard]] bool ReadData(const char** data, size_t* length); |
avi | 48fc13b | 2014-12-28 23:31:48 | [diff] [blame] | 63 | |
Peter Kasting | 4acf706 | 2024-10-15 21:41:28 | [diff] [blame] | 64 | // Similar, but using span for convenience. |
| 65 | [[nodiscard]] std::optional<span<const uint8_t>> ReadData(); |
Jeremy Roman | 2d8d780 | 2020-06-11 22:08:20 | [diff] [blame] | 66 | |
avi | 48fc13b | 2014-12-28 23:31:48 | [diff] [blame] | 67 | // A pointer to the data will be placed in |*data|. The caller specifies the |
| 68 | // number of bytes to read, and ReadBytes will validate this length. The |
| 69 | // pointer placed into |*data| points into the message's buffer so it will be |
| 70 | // scoped to the lifetime of the message (or until the message data is |
| 71 | // mutated). Do not keep the pointer around! |
Peter Kasting | 28b51cf | 2022-06-28 15:02:43 | [diff] [blame] | 72 | [[nodiscard]] bool ReadBytes(const char** data, size_t length); |
[email protected] | ce208f87 | 2012-03-07 20:42:56 | [diff] [blame] | 73 | |
Matt Menke | 4e486db | 2025-04-07 13:51:43 | [diff] [blame] | 74 | // Similar, but using span for convenience. |
| 75 | [[nodiscard]] std::optional<span<const uint8_t>> ReadBytes(size_t length); |
| 76 | |
Peter Kasting | 28b51cf | 2022-06-28 15:02:43 | [diff] [blame] | 77 | // A version of ReadInt() that checks for the result not being negative. Use |
| 78 | // it for reading the object sizes. |
| 79 | [[nodiscard]] bool ReadLength(size_t* result) { |
| 80 | int result_int; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 81 | if (!ReadInt(&result_int) || result_int < 0) { |
Peter Kasting | 28b51cf | 2022-06-28 15:02:43 | [diff] [blame] | 82 | return false; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 83 | } |
Peter Kasting | 28b51cf | 2022-06-28 15:02:43 | [diff] [blame] | 84 | *result = static_cast<size_t>(result_int); |
| 85 | return true; |
[email protected] | ce208f87 | 2012-03-07 20:42:56 | [diff] [blame] | 86 | } |
| 87 | |
| 88 | // Skips bytes in the read buffer and returns true if there are at least |
| 89 | // num_bytes available. Otherwise, does nothing and returns false. |
Peter Kasting | 28b51cf | 2022-06-28 15:02:43 | [diff] [blame] | 90 | [[nodiscard]] bool SkipBytes(size_t num_bytes) { |
[email protected] | ce208f87 | 2012-03-07 20:42:56 | [diff] [blame] | 91 | return !!GetReadPointerAndAdvance(num_bytes); |
| 92 | } |
| 93 | |
Adam Rice | 2e8d92c | 2025-03-07 08:26:55 | [diff] [blame] | 94 | // Returns true if all the data in the Pickle has been consumed. |
Daniel Cheng | ea877be | 2020-03-06 22:56:31 | [diff] [blame] | 95 | bool ReachedEnd() const { return read_index_ == end_index_; } |
| 96 | |
Adam Rice | 2e8d92c | 2025-03-07 08:26:55 | [diff] [blame] | 97 | // Returns the number of unused bytes remaining in the Pickle. Most code |
| 98 | // should not use this. Just call a Read* method and check the return value. |
| 99 | // Where this is useful is if you need to allocate space for a container |
| 100 | // before reading the data that will fill the container. In that case, this |
| 101 | // method can be used to check if the size is plausible before attempting the |
| 102 | // allocation. |
| 103 | size_t RemainingBytes() const { return end_index_ - read_index_; } |
| 104 | |
[email protected] | ce208f87 | 2012-03-07 20:42:56 | [diff] [blame] | 105 | private: |
[email protected] | ce208f87 | 2012-03-07 20:42:56 | [diff] [blame] | 106 | // Read Type from Pickle. |
| 107 | template <typename Type> |
[email protected] | a15016f | 2014-06-02 23:23:49 | [diff] [blame] | 108 | bool ReadBuiltinType(Type* result); |
| 109 | |
| 110 | // Advance read_index_ but do not allow it to exceed end_index_. |
| 111 | // Keeps read_index_ aligned. |
| 112 | void Advance(size_t size); |
[email protected] | ce208f87 | 2012-03-07 20:42:56 | [diff] [blame] | 113 | |
| 114 | // Get read pointer for Type and advance read pointer. |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 115 | template <typename Type> |
[email protected] | a15016f | 2014-06-02 23:23:49 | [diff] [blame] | 116 | const char* GetReadPointerAndAdvance(); |
[email protected] | ce208f87 | 2012-03-07 20:42:56 | [diff] [blame] | 117 | |
| 118 | // Get read pointer for |num_bytes| and advance read pointer. This method |
Peter Kasting | 28b51cf | 2022-06-28 15:02:43 | [diff] [blame] | 119 | // checks num_bytes for wrapping. |
| 120 | const char* GetReadPointerAndAdvance(size_t num_bytes); |
[email protected] | ce208f87 | 2012-03-07 20:42:56 | [diff] [blame] | 121 | |
| 122 | // Get read pointer for (num_elements * size_element) bytes and advance read |
Peter Kasting | 28b51cf | 2022-06-28 15:02:43 | [diff] [blame] | 123 | // pointer. This method checks for overflow and wrapping. |
| 124 | const char* GetReadPointerAndAdvance(size_t num_elements, |
[email protected] | a15016f | 2014-06-02 23:23:49 | [diff] [blame] | 125 | size_t size_element); |
[email protected] | ce208f87 | 2012-03-07 20:42:56 | [diff] [blame] | 126 | |
[email protected] | a15016f | 2014-06-02 23:23:49 | [diff] [blame] | 127 | const char* payload_; // Start of our pickle's payload. |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 128 | size_t read_index_; // Offset of the next readable byte in payload. |
| 129 | size_t end_index_; // Payload size. |
[email protected] | ce208f87 | 2012-03-07 20:42:56 | [diff] [blame] | 130 | |
| 131 | FRIEND_TEST_ALL_PREFIXES(PickleTest, GetReadPointerAndAdvance); |
| 132 | }; |
| 133 | |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 134 | // This class provides facilities for basic binary value packing and unpacking. |
| 135 | // |
| 136 | // The Pickle class supports appending primitive values (ints, strings, etc.) |
| 137 | // to a pickle instance. The Pickle instance grows its internal memory buffer |
| 138 | // dynamically to hold the sequence of primitive values. The internal memory |
| 139 | // buffer is exposed as the "data" of the Pickle. This "data" can be passed |
| 140 | // to a Pickle object to initialize it for reading. |
| 141 | // |
| 142 | // When reading from a Pickle object, it is important for the consumer to know |
| 143 | // what value types to read and in what order to read them as the Pickle does |
| 144 | // not keep track of the type of data written to it. |
| 145 | // |
| 146 | // The Pickle's data has a header which contains the size of the Pickle's |
| 147 | // payload. It can optionally support additional space in the header. That |
| 148 | // space is controlled by the header_size parameter passed to the Pickle |
| 149 | // constructor. |
| 150 | // |
[email protected] | 0bea725 | 2011-08-05 15:34:00 | [diff] [blame] | 151 | class BASE_EXPORT Pickle { |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 152 | public: |
rockot | 502c94f | 2016-02-03 20:20:16 | [diff] [blame] | 153 | // Auxiliary data attached to a Pickle. Pickle must be subclassed along with |
| 154 | // this interface in order to provide a concrete implementation of support |
| 155 | // for attachments. The base Pickle implementation does not accept |
| 156 | // attachments. |
| 157 | class BASE_EXPORT Attachment : public RefCountedThreadSafe<Attachment> { |
| 158 | public: |
| 159 | Attachment(); |
David Bienvenu | 5f4d4f0 | 2020-09-27 16:55:03 | [diff] [blame] | 160 | Attachment(const Attachment&) = delete; |
| 161 | Attachment& operator=(const Attachment&) = delete; |
rockot | 502c94f | 2016-02-03 20:20:16 | [diff] [blame] | 162 | |
| 163 | protected: |
| 164 | friend class RefCountedThreadSafe<Attachment>; |
| 165 | virtual ~Attachment(); |
rockot | 502c94f | 2016-02-03 20:20:16 | [diff] [blame] | 166 | }; |
| 167 | |
Peter Kasting | 4acf706 | 2024-10-15 21:41:28 | [diff] [blame] | 168 | using iterator = CheckedContiguousIterator<const uint8_t>; |
| 169 | |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 170 | // Initialize a Pickle object using the default header size. |
| 171 | Pickle(); |
| 172 | |
| 173 | // Initialize a Pickle object with the specified header size in bytes, which |
Avi Drissman | 516e192 | 2024-03-21 18:11:28 | [diff] [blame] | 174 | // must be greater-than-or-equal-to `sizeof(Pickle::Header)`. The header size |
| 175 | // will be rounded up to ensure that the header size is 32bit-aligned. Note |
| 176 | // that the extra memory allocated due to the size difference between the |
| 177 | // requested header size and the size of a standard header is not initialized. |
Peter Kasting | 28b51cf | 2022-06-28 15:02:43 | [diff] [blame] | 178 | explicit Pickle(size_t header_size); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 179 | |
Avi Drissman | 516e192 | 2024-03-21 18:11:28 | [diff] [blame] | 180 | // Returns a Pickle initialized from a block of data. The Pickle obtained by |
| 181 | // this call makes a copy of the data from which it is initialized, so it is |
| 182 | // safe to pass around without concern for the pointer to the original data |
| 183 | // dangling. The header padding size is deduced from the data length. |
| 184 | static Pickle WithData(span<const uint8_t> data); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 185 | |
Avi Drissman | 516e192 | 2024-03-21 18:11:28 | [diff] [blame] | 186 | // Returns a Pickle initialized from a const block of data. The data is not |
| 187 | // copied, only referenced, which can be dangerous; please only use this |
| 188 | // initialization when the speed gain of not copying the data outweighs the |
| 189 | // danger of dangling pointers. If a Pickle is obtained from this call, it is |
| 190 | // a requirement that only const methods be called. The header padding size is |
| 191 | // deduced from the data length. |
| 192 | static Pickle WithUnownedBuffer(span<const uint8_t> data); |
| 193 | |
Avi Drissman | 516e192 | 2024-03-21 18:11:28 | [diff] [blame] | 194 | // Initializes a Pickle as a copy of another Pickle. If the original Pickle's |
| 195 | // data is unowned, the copy will have its own internalized copy of the data. |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 196 | Pickle(const Pickle& other); |
| 197 | |
Tom Sepez | 7baba4e | 2023-11-22 04:52:15 | [diff] [blame] | 198 | // Note: Other classes are derived from this class, and they may well |
Avi Drissman | 516e192 | 2024-03-21 18:11:28 | [diff] [blame] | 199 | // delete through this parent class, e.g. std::unique_ptr<Pickle> exists |
Tom Sepez | 7baba4e | 2023-11-22 04:52:15 | [diff] [blame] | 200 | // in several places the code. |
[email protected] | a502bbe7 | 2011-01-07 18:06:45 | [diff] [blame] | 201 | virtual ~Pickle(); |
| 202 | |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 203 | // Performs a deep copy. |
| 204 | Pickle& operator=(const Pickle& other); |
| 205 | |
primiano | 9882cf34 | 2015-06-11 21:40:10 | [diff] [blame] | 206 | // Returns the number of bytes written in the Pickle, including the header. |
David Sanders | 4252759 | 2021-06-16 07:20:38 | [diff] [blame] | 207 | size_t size() const { |
| 208 | return header_ ? header_size_ + header_->payload_size : 0; |
| 209 | } |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 210 | |
Peter Kasting | 62b937d | 2024-10-09 20:47:44 | [diff] [blame] | 211 | bool empty() const { return !size(); } |
| 212 | |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 213 | // Returns the data for this Pickle. |
Claudio DeSouza | c537f85d | 2023-03-02 18:42:52 | [diff] [blame] | 214 | const uint8_t* data() const { |
| 215 | return reinterpret_cast<const uint8_t*>(header_); |
| 216 | } |
| 217 | |
| 218 | // Handy method to simplify calling data() with a reinterpret_cast. |
| 219 | const char* data_as_char() const { |
| 220 | return reinterpret_cast<const char*>(data()); |
| 221 | } |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 222 | |
Peter Kasting | 62b937d | 2024-10-09 20:47:44 | [diff] [blame] | 223 | // Iteration. These allow `Pickle` to satisfy `std::ranges::contiguous_range`, |
| 224 | // which in turn allow it to be implicitly converted to a `span`. |
Peter Kasting | 4acf706 | 2024-10-15 21:41:28 | [diff] [blame] | 225 | iterator begin() const { |
Peter Kasting | 62b937d | 2024-10-09 20:47:44 | [diff] [blame] | 226 | // SAFETY: `data()` always points to at least `size()` valid bytes, so this |
| 227 | // pointer is no further than just-past-the-end of the allocation. |
Peter Kasting | 4acf706 | 2024-10-15 21:41:28 | [diff] [blame] | 228 | return UNSAFE_BUFFERS(iterator(data(), data() + size())); |
| 229 | } |
| 230 | iterator end() const { |
| 231 | // SAFETY: As in `begin()` above. |
| 232 | return UNSAFE_BUFFERS(iterator(data(), data() + size(), data() + size())); |
Peter Kasting | 62b937d | 2024-10-09 20:47:44 | [diff] [blame] | 233 | } |
| 234 | |
primiano | 9882cf34 | 2015-06-11 21:40:10 | [diff] [blame] | 235 | // Returns the effective memory capacity of this Pickle, that is, the total |
| 236 | // number of bytes currently dynamically allocated or 0 in the case of a |
| 237 | // read-only Pickle. This should be used only for diagnostic / profiling |
| 238 | // purposes. |
| 239 | size_t GetTotalAllocatedSize() const; |
| 240 | |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 241 | // Methods for adding to the payload of the Pickle. These values are |
| 242 | // appended to the end of the Pickle's payload. When reading values from a |
| 243 | // Pickle, it is important to read them in the order in which they were added |
| 244 | // to the Pickle. |
avi | 48fc13b | 2014-12-28 23:31:48 | [diff] [blame] | 245 | |
Daniel Cheng | 0d89f922 | 2017-09-22 05:05:07 | [diff] [blame] | 246 | void WriteBool(bool value) { WriteInt(value ? 1 : 0); } |
| 247 | void WriteInt(int value) { WritePOD(value); } |
| 248 | void WriteLong(long value) { |
jam | 03d8a78 | 2016-02-10 20:13:39 | [diff] [blame] | 249 | // Always write long as a 64-bit value to ensure compatibility between |
| 250 | // 32-bit and 64-bit processes. |
Daniel Cheng | 0d89f922 | 2017-09-22 05:05:07 | [diff] [blame] | 251 | WritePOD(static_cast<int64_t>(value)); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 252 | } |
Daniel Cheng | 0d89f922 | 2017-09-22 05:05:07 | [diff] [blame] | 253 | void WriteUInt16(uint16_t value) { WritePOD(value); } |
| 254 | void WriteUInt32(uint32_t value) { WritePOD(value); } |
| 255 | void WriteInt64(int64_t value) { WritePOD(value); } |
| 256 | void WriteUInt64(uint64_t value) { WritePOD(value); } |
| 257 | void WriteFloat(float value) { WritePOD(value); } |
| 258 | void WriteDouble(double value) { WritePOD(value); } |
Helmut Januschka | 1dce9dc | 2024-06-11 13:05:35 | [diff] [blame] | 259 | void WriteString(std::string_view value); |
| 260 | void WriteString16(std::u16string_view value); |
[email protected] | 34d4861 | 2012-06-29 00:05:04 | [diff] [blame] | 261 | // "Data" is a blob with a length. When you read it out you will be given the |
| 262 | // length. See also WriteBytes. |
Avi Drissman | 516e192 | 2024-03-21 18:11:28 | [diff] [blame] | 263 | // TODO(https://crbug.com/40284755): Migrate callers to the span versions. |
Peter Kasting | 28b51cf | 2022-06-28 15:02:43 | [diff] [blame] | 264 | void WriteData(const char* data, size_t length); |
Tom Sepez | 311d878 | 2024-02-14 09:30:52 | [diff] [blame] | 265 | void WriteData(span<const uint8_t> data); |
Austin Sullivan | 31fcd06b | 2024-01-10 22:18:29 | [diff] [blame] | 266 | void WriteData(std::string_view data); |
[email protected] | d1b319fc | 2013-10-31 04:03:02 | [diff] [blame] | 267 | // "Bytes" is a blob with no length. The caller must specify the length both |
[email protected] | 34d4861 | 2012-06-29 00:05:04 | [diff] [blame] | 268 | // when reading and writing. It is normally used to serialize PoD types of a |
| 269 | // known size. See also WriteData. |
Avi Drissman | 516e192 | 2024-03-21 18:11:28 | [diff] [blame] | 270 | // TODO(https://crbug.com/40284755): Migrate callers to the span version. |
Peter Kasting | 28b51cf | 2022-06-28 15:02:43 | [diff] [blame] | 271 | void WriteBytes(const void* data, size_t length); |
Austin Sullivan | 31fcd06b | 2024-01-10 22:18:29 | [diff] [blame] | 272 | void WriteBytes(span<const uint8_t> data); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 273 | |
rockot | 502c94f | 2016-02-03 20:20:16 | [diff] [blame] | 274 | // WriteAttachment appends |attachment| to the pickle. It returns |
| 275 | // false iff the set is full or if the Pickle implementation does not support |
| 276 | // attachments. |
| 277 | virtual bool WriteAttachment(scoped_refptr<Attachment> attachment); |
| 278 | |
| 279 | // ReadAttachment parses an attachment given the parsing state |iter| and |
| 280 | // writes it to |*attachment|. It returns true on success. |
Peter Kasting | 4acf706 | 2024-10-15 21:41:28 | [diff] [blame] | 281 | virtual bool ReadAttachment(PickleIterator* iter, |
rockot | 502c94f | 2016-02-03 20:20:16 | [diff] [blame] | 282 | scoped_refptr<Attachment>* attachment) const; |
| 283 | |
| 284 | // Indicates whether the pickle has any attachments. |
| 285 | virtual bool HasAttachments() const; |
| 286 | |
[email protected] | 032bfc4 | 2013-10-29 22:23:52 | [diff] [blame] | 287 | // Reserves space for upcoming writes when multiple writes will be made and |
| 288 | // their sizes are computed in advance. It can be significantly faster to call |
| 289 | // Reserve() before calling WriteFoo() multiple times. |
| 290 | void Reserve(size_t additional_capacity); |
| 291 | |
[email protected] | c9046af | 2008-08-06 20:35:17 | [diff] [blame] | 292 | // Payload follows after allocation of Header (header size is customizable). |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 293 | struct Header { |
avi | c027914 | 2015-12-04 22:38:52 | [diff] [blame] | 294 | uint32_t payload_size; // Specifies the size of the payload. |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 295 | }; |
| 296 | |
| 297 | // Returns the header, cast to a user-specified type T. The type T must be a |
| 298 | // subclass of Header and its size must correspond to the header_size passed |
| 299 | // to the Pickle constructor. |
| 300 | template <class T> |
| 301 | T* headerT() { |
[email protected] | 5d2b449 | 2011-03-01 02:48:05 | [diff] [blame] | 302 | DCHECK_EQ(header_size_, sizeof(T)); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 303 | return static_cast<T*>(header_); |
| 304 | } |
| 305 | template <class T> |
| 306 | const T* headerT() const { |
[email protected] | 5d2b449 | 2011-03-01 02:48:05 | [diff] [blame] | 307 | DCHECK_EQ(header_size_, sizeof(T)); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 308 | return static_cast<const T*>(header_); |
| 309 | } |
| 310 | |
[email protected] | 73d96dc | 2012-03-30 22:35:27 | [diff] [blame] | 311 | // The payload is the pickle data immediately following the header. |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 312 | size_t payload_size() const { return header_ ? header_->payload_size : 0; } |
[email protected] | e00a6c0a | 2013-01-18 18:20:57 | [diff] [blame] | 313 | |
Peter Kasting | 4acf706 | 2024-10-15 21:41:28 | [diff] [blame] | 314 | span<const uint8_t> payload_bytes() const { |
Tom Sepez | ade7239 | 2025-01-07 00:47:11 | [diff] [blame] | 315 | return as_bytes(UNSAFE_TODO(span(payload(), payload_size()))); |
Lukasz Anforowicz | 0d6a164c | 2024-02-05 21:58:08 | [diff] [blame] | 316 | } |
| 317 | |
Tom Sepez | 311d878 | 2024-02-14 09:30:52 | [diff] [blame] | 318 | protected: |
Avi Drissman | 516e192 | 2024-03-21 18:11:28 | [diff] [blame] | 319 | // The protected constructor. Note that this creates a Pickle that does not |
| 320 | // own its own data. |
| 321 | enum UnownedData { kUnownedData }; |
Lei Zhang | b39481fd | 2025-06-26 01:03:40 | [diff] [blame] | 322 | Pickle(UnownedData, span<const uint8_t> data); |
Avi Drissman | 516e192 | 2024-03-21 18:11:28 | [diff] [blame] | 323 | |
Tom Sepez | 311d878 | 2024-02-14 09:30:52 | [diff] [blame] | 324 | // Returns size of the header, which can have default value, set by user or |
| 325 | // calculated by passed raw data. |
| 326 | size_t header_size() const { return header_size_; } |
| 327 | |
| 328 | const char* payload() const { |
Tom Sepez | ade7239 | 2025-01-07 00:47:11 | [diff] [blame] | 329 | return UNSAFE_TODO(reinterpret_cast<const char*>(header_) + header_size_); |
Tom Sepez | 311d878 | 2024-02-14 09:30:52 | [diff] [blame] | 330 | } |
| 331 | |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 332 | // Returns the address of the byte immediately following the currently valid |
| 333 | // header + payload. |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 334 | const char* end_of_payload() const { |
[email protected] | d87f8e6f | 2010-11-15 19:31:23 | [diff] [blame] | 335 | // This object may be invalid. |
Tom Sepez | ade7239 | 2025-01-07 00:47:11 | [diff] [blame] | 336 | return header_ ? UNSAFE_TODO(payload() + payload_size()) : NULL; |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 337 | } |
| 338 | |
[email protected] | e00a6c0a | 2013-01-18 18:20:57 | [diff] [blame] | 339 | char* mutable_payload() { |
Tom Sepez | ade7239 | 2025-01-07 00:47:11 | [diff] [blame] | 340 | return UNSAFE_TODO(reinterpret_cast<char*>(header_) + header_size_); |
[email protected] | e00a6c0a | 2013-01-18 18:20:57 | [diff] [blame] | 341 | } |
| 342 | |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 343 | size_t capacity_after_header() const { return capacity_after_header_; } |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 344 | |
[email protected] | d1b319fc | 2013-10-31 04:03:02 | [diff] [blame] | 345 | // Resize the capacity, note that the input value should not include the size |
| 346 | // of the header. |
| 347 | void Resize(size_t new_capacity); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 348 | |
rockot | 0776a50 | 2015-12-17 06:19:49 | [diff] [blame] | 349 | // Claims |num_bytes| bytes of payload. This is similar to Reserve() in that |
| 350 | // it may grow the capacity, but it also advances the write offset of the |
| 351 | // pickle by |num_bytes|. Claimed memory, including padding, is zeroed. |
| 352 | // |
| 353 | // Returns the address of the first byte claimed. |
| 354 | void* ClaimBytes(size_t num_bytes); |
| 355 | |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 356 | // Find the end of the pickled data that starts at range_start. Returns NULL |
| 357 | // if the entire Pickle is not found in the given data range. |
| 358 | static const char* FindNext(size_t header_size, |
| 359 | const char* range_start, |
| 360 | const char* range_end); |
| 361 | |
dskiba | 6f3790a | 2015-09-30 17:24:30 | [diff] [blame] | 362 | // Parse pickle header and return total size of the pickle. Data range |
| 363 | // doesn't need to contain entire pickle. |
| 364 | // Returns true if pickle header was found and parsed. Callers must check |
| 365 | // returned |pickle_size| for sanity (against maximum message size, etc). |
| 366 | // NOTE: when function successfully parses a header, but encounters an |
| 367 | // overflow during pickle size calculation, it sets |pickle_size| to the |
| 368 | // maximum size_t value and returns true. |
| 369 | static bool PeekNext(size_t header_size, |
| 370 | const char* range_start, |
| 371 | const char* range_end, |
| 372 | size_t* pickle_size); |
| 373 | |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 374 | // The allocation granularity of the payload. |
Peter Kasting | 28b51cf | 2022-06-28 15:02:43 | [diff] [blame] | 375 | static const size_t kPayloadUnit; |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 376 | |
| 377 | private: |
[email protected] | ce208f87 | 2012-03-07 20:42:56 | [diff] [blame] | 378 | friend class PickleIterator; |
| 379 | |
Keishi Hattori | 7ccb88c | 2022-01-18 16:48:45 | [diff] [blame] | 380 | // `header_` is not a raw_ptr<...> for performance reasons (based on analysis |
| 381 | // of sampling profiler data). |
Keishi Hattori | 488b760 | 2022-05-02 13:09:31 | [diff] [blame] | 382 | RAW_PTR_EXCLUSION Header* header_; |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 383 | size_t header_size_; // Supports extra data between header and payload. |
[email protected] | d1b319fc | 2013-10-31 04:03:02 | [diff] [blame] | 384 | // Allocation size of payload (or -1 if allocation is const). Note: this |
| 385 | // doesn't count the header. |
| 386 | size_t capacity_after_header_; |
| 387 | // The offset at which we will write the next field. Note: this doesn't count |
| 388 | // the header. |
| 389 | size_t write_offset_; |
| 390 | |
| 391 | // Just like WriteBytes, but with a compile-time size, for performance. |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 392 | template <size_t length> |
| 393 | void BASE_EXPORT WriteBytesStatic(const void* data); |
[email protected] | d1b319fc | 2013-10-31 04:03:02 | [diff] [blame] | 394 | |
| 395 | // Writes a POD by copying its bytes. |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 396 | template <typename T> |
| 397 | bool WritePOD(const T& data) { |
[email protected] | d1b319fc | 2013-10-31 04:03:02 | [diff] [blame] | 398 | WriteBytesStatic<sizeof(data)>(&data); |
| 399 | return true; |
| 400 | } |
rockot | 0776a50 | 2015-12-17 06:19:49 | [diff] [blame] | 401 | |
| 402 | inline void* ClaimUninitializedBytesInternal(size_t num_bytes); |
Austin Sullivan | 31fcd06b | 2024-01-10 22:18:29 | [diff] [blame] | 403 | inline void WriteBytesCommon(span<const uint8_t> data); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 404 | |
erikchen | f9ca8f5f0 | 2015-09-08 23:36:29 | [diff] [blame] | 405 | FRIEND_TEST_ALL_PREFIXES(PickleTest, DeepCopyResize); |
[email protected] | a918f87 | 2010-06-01 14:30:51 | [diff] [blame] | 406 | FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize); |
dskiba | 6f3790a | 2015-09-30 17:24:30 | [diff] [blame] | 407 | FRIEND_TEST_ALL_PREFIXES(PickleTest, PeekNext); |
| 408 | FRIEND_TEST_ALL_PREFIXES(PickleTest, PeekNextOverflow); |
[email protected] | a918f87 | 2010-06-01 14:30:51 | [diff] [blame] | 409 | FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNext); |
[email protected] | 137d237 | 2011-01-26 13:02:27 | [diff] [blame] | 410 | FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextWithIncompleteHeader); |
[email protected] | 33a38dd | 2013-11-01 09:06:26 | [diff] [blame] | 411 | FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextOverflow); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 412 | }; |
| 413 | |
brettw | 05cfd8ddb | 2015-06-02 07:02:47 | [diff] [blame] | 414 | } // namespace base |
| 415 | |
tfarina | a3116351 | 2015-05-13 22:10:15 | [diff] [blame] | 416 | #endif // BASE_PICKLE_H_ |