1 // Copyright (c) 2009 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 <limits>
6
7 #include "flip_frame_builder.h" // cross-google3 directory naming.
8 #include "flip_protocol.h"
9
10 namespace flip {
11
12 // We mark a read only FlipFrameBuilder with a special capacity_.
13 static const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max();
14
FlipFrameBuilder()15 FlipFrameBuilder::FlipFrameBuilder()
16 : buffer_(NULL),
17 capacity_(0),
18 length_(0),
19 variable_buffer_offset_(0) {
20 Resize(kInitialPayload);
21 }
22
FlipFrameBuilder(const char * data,int data_len)23 FlipFrameBuilder::FlipFrameBuilder(const char* data, int data_len)
24 : buffer_(const_cast<char*>(data)),
25 capacity_(kCapacityReadOnly),
26 length_(data_len),
27 variable_buffer_offset_(0) {
28 }
29
~FlipFrameBuilder()30 FlipFrameBuilder::~FlipFrameBuilder() {
31 if (capacity_ != kCapacityReadOnly)
32 delete[] buffer_;
33 }
34
ReadUInt16(void ** iter,uint16 * result) const35 bool FlipFrameBuilder::ReadUInt16(void** iter, uint16* result) const {
36 DCHECK(iter);
37 if (!*iter)
38 *iter = const_cast<char*>(buffer_);
39
40 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
41 return false;
42
43 *result = ntohs(*(reinterpret_cast<uint16*>(*iter)));
44
45 UpdateIter(iter, sizeof(*result));
46 return true;
47 }
48
ReadUInt32(void ** iter,uint32 * result) const49 bool FlipFrameBuilder::ReadUInt32(void** iter, uint32* result) const {
50 DCHECK(iter);
51 if (!*iter)
52 *iter = const_cast<char*>(buffer_);
53
54 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
55 return false;
56
57 *result = ntohl(*(reinterpret_cast<uint32*>(*iter)));
58
59 UpdateIter(iter, sizeof(*result));
60 return true;
61 }
62
ReadString(void ** iter,std::string * result) const63 bool FlipFrameBuilder::ReadString(void** iter, std::string* result) const {
64 DCHECK(iter);
65
66 uint16 len;
67 if (!ReadUInt16(iter, &len))
68 return false;
69
70 if (!IteratorHasRoomFor(*iter, len))
71 return false;
72
73 char* chars = reinterpret_cast<char*>(*iter);
74 result->assign(chars, len);
75
76 UpdateIter(iter, len);
77 return true;
78 }
79
ReadBytes(void ** iter,const char ** data,uint16 length) const80 bool FlipFrameBuilder::ReadBytes(void** iter, const char** data,
81 uint16 length) const {
82 DCHECK(iter);
83 DCHECK(data);
84
85 if (!IteratorHasRoomFor(*iter, length))
86 return false;
87
88 *data = reinterpret_cast<const char*>(*iter);
89
90 UpdateIter(iter, length);
91 return true;
92 }
93
ReadData(void ** iter,const char ** data,uint16 * length) const94 bool FlipFrameBuilder::ReadData(void** iter, const char** data,
95 uint16* length) const {
96 DCHECK(iter);
97 DCHECK(data);
98 DCHECK(length);
99
100 if (!ReadUInt16(iter, length))
101 return false;
102
103 return ReadBytes(iter, data, *length);
104 }
105
BeginWrite(size_t length)106 char* FlipFrameBuilder::BeginWrite(size_t length) {
107 size_t offset = length_;
108 size_t needed_size = length_ + length;
109 if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
110 return NULL;
111
112 #ifdef ARCH_CPU_64_BITS
113 DCHECK_LE(length, std::numeric_limits<uint32>::max());
114 #endif
115
116 return buffer_ + offset;
117 }
118
EndWrite(char * dest,int length)119 void FlipFrameBuilder::EndWrite(char* dest, int length) {
120 }
121
WriteBytes(const void * data,uint16 data_len)122 bool FlipFrameBuilder::WriteBytes(const void* data, uint16 data_len) {
123 DCHECK(capacity_ != kCapacityReadOnly);
124
125 char* dest = BeginWrite(data_len);
126 if (!dest)
127 return false;
128
129 memcpy(dest, data, data_len);
130
131 EndWrite(dest, data_len);
132 length_ += data_len;
133 return true;
134 }
135
WriteString(const std::string & value)136 bool FlipFrameBuilder::WriteString(const std::string& value) {
137 if (value.size() > 0xffff)
138 return false;
139
140 if (!WriteUInt16(static_cast<int>(value.size())))
141 return false;
142
143 return WriteBytes(value.data(), static_cast<uint16>(value.size()));
144 }
145
BeginWriteData(uint16 length)146 char* FlipFrameBuilder::BeginWriteData(uint16 length) {
147 DCHECK_EQ(variable_buffer_offset_, 0U) <<
148 "There can only be one variable buffer in a FlipFrameBuilder";
149
150 if (!WriteUInt16(length))
151 return false;
152
153 char *data_ptr = BeginWrite(length);
154 if (!data_ptr)
155 return NULL;
156
157 variable_buffer_offset_ = data_ptr - buffer_ - sizeof(int);
158
159 // EndWrite doesn't necessarily have to be called after the write operation,
160 // so we call it here to pad out what the caller will eventually write.
161 EndWrite(data_ptr, length);
162 return data_ptr;
163 }
164
Resize(size_t new_capacity)165 bool FlipFrameBuilder::Resize(size_t new_capacity) {
166 if (new_capacity < capacity_)
167 return true;
168
169 char* p = new char[new_capacity];
170 if (buffer_) {
171 memcpy(p, buffer_, capacity_);
172 delete[] buffer_;
173 }
174 if (!p && new_capacity > 0)
175 return false;
176 buffer_ = p;
177 capacity_ = new_capacity;
178 return true;
179 }
180
181 } // namespace flip
182