blob: 396a1d342829d63fc20425697510b2e6d7b18b4b [file] [log] [blame]
henrike@webrtc.org0e118e72013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/base/bytebuffer.h"
29
pbos@webrtc.orgb9518272014-03-07 15:22:04 +000030#include <assert.h>
31#include <string.h>
32
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000033#include <algorithm>
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000034
35#include "talk/base/basictypes.h"
36#include "talk/base/byteorder.h"
37
38namespace talk_base {
39
40static const int DEFAULT_SIZE = 4096;
41
42ByteBuffer::ByteBuffer() {
43 Construct(NULL, DEFAULT_SIZE, ORDER_NETWORK);
44}
45
46ByteBuffer::ByteBuffer(ByteOrder byte_order) {
47 Construct(NULL, DEFAULT_SIZE, byte_order);
48}
49
50ByteBuffer::ByteBuffer(const char* bytes, size_t len) {
51 Construct(bytes, len, ORDER_NETWORK);
52}
53
54ByteBuffer::ByteBuffer(const char* bytes, size_t len, ByteOrder byte_order) {
55 Construct(bytes, len, byte_order);
56}
57
58ByteBuffer::ByteBuffer(const char* bytes) {
59 Construct(bytes, strlen(bytes), ORDER_NETWORK);
60}
61
62void ByteBuffer::Construct(const char* bytes, size_t len,
63 ByteOrder byte_order) {
64 version_ = 0;
65 start_ = 0;
66 size_ = len;
67 byte_order_ = byte_order;
68 bytes_ = new char[size_];
69
70 if (bytes) {
71 end_ = len;
72 memcpy(bytes_, bytes, end_);
73 } else {
74 end_ = 0;
75 }
76}
77
78ByteBuffer::~ByteBuffer() {
79 delete[] bytes_;
80}
81
82bool ByteBuffer::ReadUInt8(uint8* val) {
83 if (!val) return false;
84
85 return ReadBytes(reinterpret_cast<char*>(val), 1);
86}
87
88bool ByteBuffer::ReadUInt16(uint16* val) {
89 if (!val) return false;
90
91 uint16 v;
92 if (!ReadBytes(reinterpret_cast<char*>(&v), 2)) {
93 return false;
94 } else {
95 *val = (byte_order_ == ORDER_NETWORK) ? NetworkToHost16(v) : v;
96 return true;
97 }
98}
99
100bool ByteBuffer::ReadUInt24(uint32* val) {
101 if (!val) return false;
102
103 uint32 v = 0;
104 char* read_into = reinterpret_cast<char*>(&v);
105 if (byte_order_ == ORDER_NETWORK || IsHostBigEndian()) {
106 ++read_into;
107 }
108
109 if (!ReadBytes(read_into, 3)) {
110 return false;
111 } else {
112 *val = (byte_order_ == ORDER_NETWORK) ? NetworkToHost32(v) : v;
113 return true;
114 }
115}
116
117bool ByteBuffer::ReadUInt32(uint32* val) {
118 if (!val) return false;
119
120 uint32 v;
121 if (!ReadBytes(reinterpret_cast<char*>(&v), 4)) {
122 return false;
123 } else {
124 *val = (byte_order_ == ORDER_NETWORK) ? NetworkToHost32(v) : v;
125 return true;
126 }
127}
128
129bool ByteBuffer::ReadUInt64(uint64* val) {
130 if (!val) return false;
131
132 uint64 v;
133 if (!ReadBytes(reinterpret_cast<char*>(&v), 8)) {
134 return false;
135 } else {
136 *val = (byte_order_ == ORDER_NETWORK) ? NetworkToHost64(v) : v;
137 return true;
138 }
139}
140
141bool ByteBuffer::ReadString(std::string* val, size_t len) {
142 if (!val) return false;
143
144 if (len > Length()) {
145 return false;
146 } else {
147 val->append(bytes_ + start_, len);
148 start_ += len;
149 return true;
150 }
151}
152
153bool ByteBuffer::ReadBytes(char* val, size_t len) {
154 if (len > Length()) {
155 return false;
156 } else {
157 memcpy(val, bytes_ + start_, len);
158 start_ += len;
159 return true;
160 }
161}
162
163void ByteBuffer::WriteUInt8(uint8 val) {
164 WriteBytes(reinterpret_cast<const char*>(&val), 1);
165}
166
167void ByteBuffer::WriteUInt16(uint16 val) {
168 uint16 v = (byte_order_ == ORDER_NETWORK) ? HostToNetwork16(val) : val;
169 WriteBytes(reinterpret_cast<const char*>(&v), 2);
170}
171
172void ByteBuffer::WriteUInt24(uint32 val) {
173 uint32 v = (byte_order_ == ORDER_NETWORK) ? HostToNetwork32(val) : val;
174 char* start = reinterpret_cast<char*>(&v);
175 if (byte_order_ == ORDER_NETWORK || IsHostBigEndian()) {
176 ++start;
177 }
178 WriteBytes(start, 3);
179}
180
181void ByteBuffer::WriteUInt32(uint32 val) {
182 uint32 v = (byte_order_ == ORDER_NETWORK) ? HostToNetwork32(val) : val;
183 WriteBytes(reinterpret_cast<const char*>(&v), 4);
184}
185
186void ByteBuffer::WriteUInt64(uint64 val) {
187 uint64 v = (byte_order_ == ORDER_NETWORK) ? HostToNetwork64(val) : val;
188 WriteBytes(reinterpret_cast<const char*>(&v), 8);
189}
190
191void ByteBuffer::WriteString(const std::string& val) {
192 WriteBytes(val.c_str(), val.size());
193}
194
195void ByteBuffer::WriteBytes(const char* val, size_t len) {
196 memcpy(ReserveWriteBuffer(len), val, len);
197}
198
199char* ByteBuffer::ReserveWriteBuffer(size_t len) {
200 if (Length() + len > Capacity())
201 Resize(Length() + len);
202
203 char* start = bytes_ + end_;
204 end_ += len;
205 return start;
206}
207
208void ByteBuffer::Resize(size_t size) {
209 size_t len = _min(end_ - start_, size);
210 if (size <= size_) {
211 // Don't reallocate, just move data backwards
212 memmove(bytes_, bytes_ + start_, len);
213 } else {
214 // Reallocate a larger buffer.
215 size_ = _max(size, 3 * size_ / 2);
216 char* new_bytes = new char[size_];
217 memcpy(new_bytes, bytes_ + start_, len);
218 delete [] bytes_;
219 bytes_ = new_bytes;
220 }
221 start_ = 0;
222 end_ = len;
223 ++version_;
224}
225
226bool ByteBuffer::Consume(size_t size) {
227 if (size > Length())
228 return false;
229 start_ += size;
230 return true;
231}
232
233ByteBuffer::ReadPosition ByteBuffer::GetReadPosition() const {
234 return ReadPosition(start_, version_);
235}
236
237bool ByteBuffer::SetReadPosition(const ReadPosition &position) {
238 if (position.version_ != version_) {
239 return false;
240 }
241 start_ = position.start_;
242 return true;
243}
244
245void ByteBuffer::Clear() {
246 memset(bytes_, 0, size_);
247 start_ = end_ = 0;
248 ++version_;
249}
250
251} // namespace talk_base