1/*
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
30#include <algorithm>
31#include <cassert>
32#include <cstring>
33
34#include "talk/base/basictypes.h"
35#include "talk/base/byteorder.h"
36
37namespace talk_base {
38
39static const int DEFAULT_SIZE = 4096;
40
41ByteBuffer::ByteBuffer() {
42  start_ = 0;
43  end_   = 0;
44  size_  = DEFAULT_SIZE;
45  bytes_ = new char[size_];
46}
47
48ByteBuffer::ByteBuffer(const char* bytes, size_t len) {
49  start_ = 0;
50  end_   = len;
51  size_  = len;
52  bytes_ = new char[size_];
53  memcpy(bytes_, bytes, end_);
54}
55
56ByteBuffer::ByteBuffer(const char* bytes) {
57  start_ = 0;
58  end_   = strlen(bytes);
59  size_  = end_;
60  bytes_ = new char[size_];
61  memcpy(bytes_, bytes, end_);
62}
63
64ByteBuffer::~ByteBuffer() {
65  delete[] bytes_;
66}
67
68bool ByteBuffer::ReadUInt8(uint8* val) {
69  if (!val) return false;
70
71  return ReadBytes(reinterpret_cast<char*>(val), 1);
72}
73
74bool ByteBuffer::ReadUInt16(uint16* val) {
75  if (!val) return false;
76
77  uint16 v;
78  if (!ReadBytes(reinterpret_cast<char*>(&v), 2)) {
79    return false;
80  } else {
81    *val = NetworkToHost16(v);
82    return true;
83  }
84}
85
86bool ByteBuffer::ReadUInt24(uint32* val) {
87  if (!val) return false;
88
89  uint32 v = 0;
90  if (!ReadBytes(reinterpret_cast<char*>(&v) + 1, 3)) {
91    return false;
92  } else {
93    *val = NetworkToHost32(v);
94    return true;
95  }
96}
97
98bool ByteBuffer::ReadUInt32(uint32* val) {
99  if (!val) return false;
100
101  uint32 v;
102  if (!ReadBytes(reinterpret_cast<char*>(&v), 4)) {
103    return false;
104  } else {
105    *val = NetworkToHost32(v);
106    return true;
107  }
108}
109
110bool ByteBuffer::ReadUInt64(uint64* val) {
111  if (!val) return false;
112
113  uint64 v;
114  if (!ReadBytes(reinterpret_cast<char*>(&v), 8)) {
115    return false;
116  } else {
117    *val = NetworkToHost64(v);
118    return true;
119  }
120}
121
122bool ByteBuffer::ReadString(std::string* val, size_t len) {
123  if (!val) return false;
124
125  if (len > Length()) {
126    return false;
127  } else {
128    val->append(bytes_ + start_, len);
129    start_ += len;
130    return true;
131  }
132}
133
134bool ByteBuffer::ReadBytes(char* val, size_t len) {
135  if (len > Length()) {
136    return false;
137  } else {
138    memcpy(val, bytes_ + start_, len);
139    start_ += len;
140    return true;
141  }
142}
143
144void ByteBuffer::WriteUInt8(uint8 val) {
145  WriteBytes(reinterpret_cast<const char*>(&val), 1);
146}
147
148void ByteBuffer::WriteUInt16(uint16 val) {
149  uint16 v = HostToNetwork16(val);
150  WriteBytes(reinterpret_cast<const char*>(&v), 2);
151}
152
153void ByteBuffer::WriteUInt24(uint32 val) {
154  uint32 v = HostToNetwork32(val);
155  WriteBytes(reinterpret_cast<const char*>(&v) + 1, 3);
156}
157
158void ByteBuffer::WriteUInt32(uint32 val) {
159  uint32 v = HostToNetwork32(val);
160  WriteBytes(reinterpret_cast<const char*>(&v), 4);
161}
162
163void ByteBuffer::WriteUInt64(uint64 val) {
164  uint64 v = HostToNetwork64(val);
165  WriteBytes(reinterpret_cast<const char*>(&v), 8);
166}
167
168void ByteBuffer::WriteString(const std::string& val) {
169  WriteBytes(val.c_str(), val.size());
170}
171
172void ByteBuffer::WriteBytes(const char* val, size_t len) {
173  if (Length() + len > Capacity())
174    Resize(Length() + len);
175
176  memcpy(bytes_ + end_, val, len);
177  end_ += len;
178}
179
180void ByteBuffer::Resize(size_t size) {
181  if (size > size_)
182    size = _max(size, 3 * size_ / 2);
183
184  size_t len = _min(end_ - start_, size);
185  char* new_bytes = new char[size];
186  memcpy(new_bytes, bytes_ + start_, len);
187  delete [] bytes_;
188
189  start_ = 0;
190  end_   = len;
191  size_  = size;
192  bytes_ = new_bytes;
193}
194
195void ByteBuffer::Consume(size_t size) {
196  if (size > Length())
197    return;
198
199  start_ += size;
200}
201
202void ByteBuffer::Shift(size_t size) {
203  if (size > Length())
204    return;
205
206  end_ = Length() - size;
207  memmove(bytes_, bytes_ + start_ + size, end_);
208  start_ = 0;
209}
210
211}  // namespace talk_base
212