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