1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/common/buffer_writer.h"
16 :
17 : #include "base/logging.h"
18 : #include "syzygy/common/align.h"
19 :
20 : namespace common {
21 :
22 : BufferWriter::BufferWriter(void* buffer, size_t buffer_length)
23 : : buffer_(reinterpret_cast<uint8*>(buffer)),
24 : buffer_length_(buffer_length),
25 E : pos_(0) {
26 E : if (buffer_length_ == 0) {
27 E : buffer_ = NULL;
28 E : } else {
29 E : DCHECK(buffer_ != NULL);
30 : }
31 E : }
32 :
33 E : size_t BufferWriter::RemainingBytes() const {
34 : // Be careful with overflow.
35 E : if (pos_ >= buffer_length_)
36 E : return 0;
37 E : return buffer_length_ - pos_;
38 E : }
39 :
40 E : bool BufferWriter::Consume(size_t bytes) {
41 E : size_t new_pos = pos_ + bytes;
42 E : if (!EnsureCanWriteFromCurrentPosition(new_pos))
43 E : return false;
44 E : pos_ = new_pos;
45 E : return true;
46 E : }
47 :
48 E : bool BufferWriter::Align(size_t bytes) {
49 E : DCHECK(IsPowerOfTwo(bytes));
50 E : size_t new_pos = AlignUp(pos_, bytes);
51 E : if (!EnsureCanWriteFromCurrentPosition(new_pos))
52 E : return false;
53 E : pos_ = new_pos;
54 E : return true;
55 E : }
56 :
57 E : bool BufferWriter::IsAligned(size_t bytes) const {
58 E : DCHECK(IsPowerOfTwo(bytes));
59 E : return common::IsAligned(pos_, bytes);
60 E : }
61 :
62 E : bool BufferWriter::Write(size_t data_len, const void* data) {
63 E : size_t new_pos = pos_ + data_len;
64 E : if (!EnsureCanWriteFromCurrentPosition(new_pos))
65 E : return false;
66 E : ::memcpy(buffer_ + pos_, data, data_len);
67 E : pos_ = new_pos;
68 E : return true;
69 E : }
70 :
71 E : bool BufferWriter::WriteString(const base::StringPiece& string) {
72 E : return Write(string.size() + 1, string.data());
73 E : }
74 :
75 E : bool BufferWriter::WriteString(const base::StringPiece16& string) {
76 E : return Write(string.size() + 1, string.data());
77 E : }
78 :
79 E : bool BufferWriter::EnsureCanWriteFromCurrentPosition(size_t new_length) {
80 : // Does this overflow our position counter?
81 E : if (new_length < pos_)
82 E : return false;
83 :
84 : // Already room for it?
85 E : if (new_length <= buffer_length_)
86 E : return true;
87 :
88 : // Attempt to grow.
89 E : uint8* new_buffer = GrowBuffer(new_length);
90 E : if (new_buffer == NULL)
91 E : return false;
92 :
93 E : buffer_ = new_buffer;
94 E : buffer_length_ = new_length;
95 :
96 E : return true;
97 E : }
98 :
99 E : void BufferWriter::SetBuffer(uint8* buffer, size_t buffer_length) {
100 E : buffer_length_ = buffer_length;
101 E : if (buffer_length_ == 0) {
102 i : buffer_ = NULL;
103 i : } else {
104 E : DCHECK(buffer != NULL);
105 E : buffer_ = buffer;
106 : }
107 E : }
108 :
109 E : uint8* BufferWriter::GrowBuffer(size_t new_length) {
110 : // Growing a fixed sized buffer is impossible.
111 E : return NULL;
112 E : }
113 :
114 : VectorBufferWriter::VectorBufferWriter(std::vector<uint8>* vector)
115 E : : BufferWriter(NULL, 0), vector_(vector) {
116 E : DCHECK(vector != NULL);
117 :
118 E : if (!vector_->empty())
119 E : SetBuffer(&(*vector_)[0], vector_->size());
120 E : }
121 :
122 E : uint8* VectorBufferWriter::GrowBuffer(size_t new_length) {
123 : // NOTE: While this may appear to be O(N^2), it's actually not. vector is
124 : // smart enough to double the size of the allocation when a resize causes
125 : // a reallocation, so it is amortized O(N).
126 E : vector_->resize(new_length);
127 E : return &(*vector_)[0];
128 E : }
129 :
130 : } // namespace common
|