1 /* 2 * Buffer class 3 * 4 * Copyright (C) 2001 Barnaby Gray <barnaby@beedesign.co.uk> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include "buffer.h" 23 24 #include <algorithm> 25 #include <ctype.h> 26 27 using std::string; 28 using std::endl; 29 using std::ostream; 30 31 namespace ICQ2000 32 { 33 Buffer()34 Buffer::Buffer() 35 : m_data(), m_endn(BIG), m_out_pos(0) 36 { } 37 Buffer(const unsigned char * d,unsigned int size)38 Buffer::Buffer(const unsigned char* d, unsigned int size) 39 : m_data(d, d+size), m_endn(BIG), m_out_pos(0) 40 { } 41 Buffer(Buffer & b,unsigned int start,unsigned int data_len)42 Buffer::Buffer(Buffer& b, unsigned int start, unsigned int data_len) 43 : m_data(b.m_data.begin()+start, b.m_data.begin()+start+data_len), 44 m_endn(BIG), m_out_pos(0) 45 { } 46 operator [](unsigned int p)47 unsigned char& Buffer::operator[](unsigned int p) 48 { 49 return m_data[p]; 50 } 51 clear()52 void Buffer::clear() 53 { 54 m_data.clear(); 55 m_out_pos = 0; 56 } 57 empty()58 bool Buffer::empty() 59 { 60 return m_data.empty(); 61 } 62 chopOffBuffer(Buffer & b,unsigned int sz)63 void Buffer::chopOffBuffer(Buffer& b, unsigned int sz) 64 { 65 copy( m_data.begin(), m_data.begin()+sz, back_inserter(b.m_data) ); 66 m_data.erase( m_data.begin(), m_data.begin()+sz ); 67 m_out_pos = 0; 68 } 69 Pack(const unsigned char * d,unsigned int size)70 void Buffer::Pack(const unsigned char *d, unsigned int size) 71 { 72 copy(d, d+size, back_inserter(m_data)); 73 } 74 PackUint16StringNull(const string & s)75 void Buffer::PackUint16StringNull(const string& s) 76 { 77 (*this) << (unsigned short)(s.size()+1); 78 Pack(s); 79 (*this) << (unsigned char)0x00; 80 } 81 PackByteString(const string & s)82 void Buffer::PackByteString(const string& s) 83 { 84 (*this) << (unsigned char)(s.size()); 85 Pack(s); 86 } 87 UnpackCRLFString(string & s)88 void Buffer::UnpackCRLFString(string& s) 89 { 90 iterator i; 91 92 i = find(m_data.begin()+m_out_pos, m_data.end(), '\n'); 93 94 if (i != m_data.end() ) 95 { 96 Unpack(s, i-m_data.begin()-m_out_pos+1); 97 } 98 } 99 Pack(const string & s)100 void Buffer::Pack(const string& s) 101 { 102 copy(s.begin(), s.end(), back_inserter(m_data)); 103 } 104 UnpackChar()105 unsigned char Buffer::UnpackChar() 106 { 107 if (m_out_pos + 1 > m_data.size()) 108 return 0; 109 else 110 return m_data[m_out_pos++]; 111 } 112 UnpackUint32String(string & s)113 void Buffer::UnpackUint32String(string& s) 114 { 115 unsigned int l; 116 (*this) >> l; 117 Unpack(s, l); 118 } 119 UnpackUint16StringNull(string & s)120 void Buffer::UnpackUint16StringNull(string& s) 121 { 122 unsigned short sh; 123 (*this) >> sh; 124 if (sh > 0) 125 { 126 Unpack(s, sh-1); 127 (*this).advance(1); 128 } 129 } 130 UnpackByteString(string & s)131 void Buffer::UnpackByteString(string& s) 132 { 133 unsigned char c; 134 (*this) >> c; 135 Unpack(s, c); 136 } 137 Unpack(string & s,unsigned int size)138 void Buffer::Unpack(string& s, unsigned int size) 139 { 140 if (m_out_pos >= m_data.size()) 141 return; 142 143 if (m_out_pos+size > m_data.size()) 144 size = m_data.size()-m_out_pos; 145 146 iterator i = m_data.begin()+m_out_pos; 147 iterator end = m_data.begin()+m_out_pos+size; 148 149 while (i != end) 150 { 151 s += *i; 152 ++i; 153 } 154 155 m_out_pos += size; 156 } 157 Unpack(unsigned char * const d,unsigned int size)158 void Buffer::Unpack(unsigned char *const d, unsigned int size) { 159 if (m_out_pos+size > m_data.size()) size = m_data.size()-m_out_pos; 160 copy(m_data.begin()+m_out_pos, m_data.begin()+m_out_pos+size, d); 161 m_out_pos += size; 162 } 163 getAutoSizeShortMarker()164 Buffer::marker Buffer::getAutoSizeShortMarker() 165 { 166 // reserve a short 167 (*this) << (unsigned short)0; 168 169 marker m; 170 m.position = size(); 171 m.endianness = m_endn; 172 m.size = 2; 173 return m; 174 } 175 getAutoSizeIntMarker()176 Buffer::marker Buffer::getAutoSizeIntMarker() 177 { 178 // reserve an int 179 (*this) << (unsigned int)0; 180 181 marker m; 182 m.position = size(); 183 m.endianness = m_endn; 184 m.size = 4; 185 return m; 186 } 187 setAutoSizeMarker(const marker & m)188 void Buffer::setAutoSizeMarker(const marker& m) 189 { 190 unsigned int autosize = size() - m.position; 191 192 if (m.size == 2) 193 { 194 if (m.endianness == BIG) 195 { 196 m_data[ m.position - 2 ] = ((autosize >> 8) & 0xff); 197 m_data[ m.position - 1 ] = ((autosize >> 0) & 0xff); 198 } 199 else 200 { 201 m_data[ m.position - 2 ] = ((autosize >> 0) & 0xff); 202 m_data[ m.position - 1 ] = ((autosize >> 8) & 0xff); 203 } 204 } 205 else if (m.size == 4) 206 { 207 if (m.endianness == BIG) 208 { 209 m_data[ m.position - 4 ] = ((autosize >> 24) & 0xff); 210 m_data[ m.position - 3 ] = ((autosize >> 16) & 0xff); 211 m_data[ m.position - 2 ] = ((autosize >> 8) & 0xff); 212 m_data[ m.position - 1 ] = ((autosize >> 0) & 0xff); 213 } 214 else 215 { 216 m_data[ m.position - 4 ] = ((autosize >> 0) & 0xff); 217 m_data[ m.position - 3 ] = ((autosize >> 8) & 0xff); 218 m_data[ m.position - 2 ] = ((autosize >> 16) & 0xff); 219 m_data[ m.position - 1 ] = ((autosize >> 24) & 0xff); 220 } 221 } 222 } 223 224 // -- Input stream methods -- 225 operator <<(unsigned char l)226 Buffer& Buffer::operator<<(unsigned char l) 227 { 228 m_data.push_back(l); 229 return (*this); 230 } 231 operator <<(unsigned short l)232 Buffer& Buffer::operator<<(unsigned short l) 233 { 234 if (m_endn == BIG) 235 { 236 m_data.push_back((l>>8) & 0xFF); 237 m_data.push_back(l & 0xFF); 238 } 239 else 240 { 241 m_data.push_back(l & 0xFF); 242 m_data.push_back((l>>8) & 0xFF); 243 } 244 return (*this); 245 } 246 operator <<(unsigned int l)247 Buffer& Buffer::operator<<(unsigned int l) 248 { 249 if (m_endn == BIG) 250 { 251 m_data.push_back((l >> 24) & 0xFF); 252 m_data.push_back((l >> 16) & 0xFF); 253 m_data.push_back((l >> 8) & 0xFF); 254 m_data.push_back(l & 0xFF); 255 } 256 else 257 { 258 m_data.push_back(l & 0xFF); 259 m_data.push_back((l >> 8) & 0xFF); 260 m_data.push_back((l >> 16) & 0xFF); 261 m_data.push_back((l >> 24) & 0xFF); 262 } 263 return (*this); 264 } 265 266 // strings stored as length (2 bytes), string m_data, _not_ null-terminated operator <<(const string & s)267 Buffer& Buffer::operator<<(const string& s) 268 { 269 (*this) << (unsigned short)s.size(); 270 Pack(s); 271 return (*this); 272 } 273 274 // -- Output stream methods -- 275 operator >>(unsigned char & l)276 Buffer& Buffer::operator>>(unsigned char& l) 277 { 278 if (m_out_pos + 1 > m_data.size()) l = 0; 279 else l = m_data[m_out_pos++]; 280 return (*this); 281 } 282 operator >>(unsigned short & l)283 Buffer& Buffer::operator>>(unsigned short& l) 284 { 285 if (m_out_pos + 2 > m_data.size()) 286 { 287 l = 0; 288 m_out_pos += 2; 289 } else { 290 if (m_endn == BIG) { 291 l = ((unsigned short)m_data[m_out_pos++] << 8) 292 + ((unsigned short)m_data[m_out_pos++]); 293 } else { 294 l = ((unsigned short)m_data[m_out_pos++]) 295 + ((unsigned short)m_data[m_out_pos++] << 8); 296 } 297 } 298 return (*this); 299 } 300 operator >>(unsigned int & l)301 Buffer& Buffer::operator>>(unsigned int& l) 302 { 303 if (m_out_pos + 4 > m_data.size()) 304 { 305 l = 0; 306 m_out_pos += 4; 307 } 308 else 309 { 310 if (m_endn == BIG) 311 { 312 l = ((unsigned int)m_data[m_out_pos++] << 24) 313 + ((unsigned int)m_data[m_out_pos++] << 16) 314 + ((unsigned int)m_data[m_out_pos++] << 8) 315 + ((unsigned int)m_data[m_out_pos++]); 316 } 317 else 318 { 319 l = ((unsigned int)m_data[m_out_pos++]) 320 + ((unsigned int)m_data[m_out_pos++] << 8) 321 + ((unsigned int)m_data[m_out_pos++] << 16) 322 + ((unsigned int)m_data[m_out_pos++] << 24); 323 } 324 } 325 return (*this); 326 } 327 328 // strings stored as length (2 bytes), string data, _not_ null-terminated operator >>(string & s)329 Buffer& Buffer::operator>>(string& s) 330 { 331 if (m_out_pos + 2 > m_data.size()) 332 { 333 s = ""; // clear() method doesn't seem to exist! 334 m_out_pos += 2; 335 } 336 else 337 { 338 unsigned short sz; 339 (*this) >> sz; 340 Unpack(s, sz); 341 } 342 return (*this); 343 } 344 setEndianness(endian e)345 void Buffer::setEndianness(endian e) 346 { 347 m_endn = e; 348 } 349 setBigEndian()350 void Buffer::setBigEndian() 351 { 352 m_endn = BIG; 353 } 354 setLittleEndian()355 void Buffer::setLittleEndian() 356 { 357 m_endn = LITTLE; 358 } 359 dump(ostream & out)360 void Buffer::dump(ostream& out) 361 { 362 char d[] = "123456789abcdef0"; 363 out << std::hex << std::setfill('0'); 364 unsigned int m = ((m_data.size()+15)/16)*16; 365 366 for (unsigned int a = 0; a < m; a++) 367 { 368 if (a % 16 == 0) out << std::setw(4) << a << " "; 369 370 if (a < m_data.size()) 371 { 372 out << std::setw(2) << (int)m_data[a] << " "; 373 d[a%16] = isprint(m_data[a]) ? (m_data[a] < 0x80 ? m_data[a] : '.') : '.'; 374 // restrict output to a definitely non UTF-8 character set 375 } 376 else 377 { 378 out << " "; 379 d[a%16] = ' '; 380 } 381 382 if (a % 16 == 15) 383 out << " " << d << endl; 384 } 385 } 386 operator <<(ostream & out,Buffer & b)387 ostream& operator<<(ostream& out, Buffer& b) 388 { 389 b.dump(out); 390 return out; 391 } 392 393 } 394