monotone

monotone Mtn Source Tree

Root/netio.hh

1#ifndef __NETIO_HH__
2#define __NETIO_HH__
3
4// copyright (C) 2004 graydon hoare <graydon@pobox.com>
5// all rights reserved.
6// licensed to the public under the terms of the GNU GPL (>= 2)
7// see the file COPYING for details
8
9// all network i/o decoding and encoding in netcmd and merkle is done using
10// the primitives in this header. it has to be very correct.
11
12#include <boost/format.hpp>
13#include <boost/static_assert.hpp>
14
15#include "numeric_vocab.hh"
16#include "sanity.hh"
17#include "string_queue.hh"
18
19struct bad_decode {
20 bad_decode(boost::format const & fmt) : what(fmt.str()) {}
21 std::string what;
22};
23
24inline void
25require_bytes(std::string const & str,
26 size_t pos,
27 size_t len,
28 std::string const & name)
29{
30 // if you've gone past the end of the buffer, there's a logic error,
31 // and this program is not safe to keep running. shut down.
32 I(pos < str.size() || (pos == str.size() && len == 0));
33 // otherwise make sure there's room for this decode operation, but
34 // use a recoverable exception type.
35 if (len == 0)
36 return;
37 if (str.size() < pos + len)
38 throw bad_decode(F("need %d bytes to decode %s at %d, only have %d")
39 % len % name % pos % (str.size() - pos));
40}
41
42inline void
43require_bytes(string_queue const & str,
44 size_t pos,
45 size_t len,
46 std::string const & name)
47{
48 // if you've gone past the end of the buffer, there's a logic error,
49 // and this program is not safe to keep running. shut down.
50 I(pos < str.size() || (pos == str.size() && len == 0));
51 // otherwise make sure there's room for this decode operation, but
52 // use a recoverable exception type.
53 if (len == 0)
54 return;
55 if (str.size() < pos + len)
56 throw bad_decode(F("need %d bytes to decode %s at %d, only have %d")
57 % len % name % pos % (str.size() - pos));
58}
59
60template <typename T>
61inline bool
62try_extract_datum_uleb128(std::string const & in,
63 size_t & pos,
64 std::string const & name,
65 T & out)
66{
67 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_signed == false);
68 size_t shift = 0;
69 size_t maxbytes = sizeof(T) + 1 + (sizeof(T) / 8);
70 out = 0;
71 while (maxbytes > 0)
72 {
73 if (pos >= in.size())
74return false;
75 T curr = widen<T,u8>(in[pos]);
76 ++pos;
77 out |= ((static_cast<u8>(curr)
78 & static_cast<u8>(0x7f)) << shift);
79 bool finished = ! static_cast<bool>(static_cast<u8>(curr)
80 & static_cast<u8>(0x80));
81 if (finished)
82break;
83 else if (maxbytes == 1)
84throw bad_decode(F("uleb128 decode for '%s' into %d-byte datum overflowed")
85 % name % maxbytes);
86 else
87{
88 --maxbytes;
89 shift += 7;
90}
91 }
92 return true;
93}
94
95template <typename T>
96inline bool
97try_extract_datum_uleb128(string_queue const & in,
98 size_t & pos,
99 std::string const & name,
100 T & out)
101{
102 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_signed == false);
103 size_t shift = 0;
104 size_t maxbytes = sizeof(T) + 1 + (sizeof(T) / 8);
105 out = 0;
106 while (maxbytes > 0)
107 {
108 if (pos >= in.size())
109 return false;
110 T curr = widen<T,u8>(in[pos]);
111 ++pos;
112 out |= ((static_cast<u8>(curr)
113 & static_cast<u8>(0x7f)) << shift);
114 bool finished = ! static_cast<bool>(static_cast<u8>(curr)
115 & static_cast<u8>(0x80));
116 if (finished)
117 break;
118 else if (maxbytes == 1)
119 throw bad_decode(F("uleb128 decode for '%s' into %d-byte datum overflowed")
120 % name % maxbytes);
121 else
122 {
123 --maxbytes;
124 shift += 7;
125 }
126 }
127 return true;
128}
129
130template <typename T>
131inline T
132extract_datum_uleb128(std::string const & in,
133 size_t & pos,
134 std::string const & name)
135{
136 T out;
137 size_t tpos = pos;
138 if (! try_extract_datum_uleb128(in, tpos, name, out))
139 throw bad_decode(F("ran out of bytes reading uleb128 value for '%s' at pos %d")
140 % name % pos);
141 pos = tpos;
142 return out;
143}
144
145template <typename T>
146inline void
147insert_datum_uleb128(T in, std::string & out)
148{
149 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_signed == false);
150 size_t maxbytes = sizeof(T) + 1 + (sizeof(T) / 8);
151 while (maxbytes > 0)
152 {
153 u8 item = (static_cast<u8>(in) & static_cast<u8>(0x7f));
154 T remainder = in >> 7;
155 bool finished = ! static_cast<bool>(remainder);
156 if (finished)
157{
158 out += item;
159 break;
160}
161 else
162{
163 out += (item | static_cast<u8>(0x80));
164 --maxbytes;
165 in = remainder;
166}
167 }
168}
169
170template <typename T>
171inline void
172insert_datum_uleb128(T in, string_queue & out)
173{
174 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_signed == false);
175 size_t maxbytes = sizeof(T) + 1 + (sizeof(T) / 8);
176 while (maxbytes > 0)
177 {
178 u8 item = (static_cast<u8>(in) & static_cast<u8>(0x7f));
179 T remainder = in >> 7;
180 bool finished = ! static_cast<bool>(remainder);
181 if (finished)
182 {
183 out += item;
184 break;
185 }
186 else
187 {
188 out += (item | static_cast<u8>(0x80));
189 --maxbytes;
190 in = remainder;
191 }
192 }
193}
194
195template <typename T>
196inline T
197extract_datum_lsb(std::string const & in,
198 size_t & pos,
199 std::string const & name)
200{
201 size_t nbytes = sizeof(T);
202 T out = 0;
203 size_t shift = 0;
204
205 require_bytes(in, pos, nbytes, name);
206
207 while (nbytes > 0)
208 {
209 out |= widen<T,u8>(in[pos++]) << shift;
210 shift += 8;
211 --nbytes;
212 }
213 return out;
214}
215
216template <typename T>
217inline T
218extract_datum_lsb(string_queue const & in,
219 size_t & pos,
220 std::string const & name)
221{
222 size_t nbytes = sizeof(T);
223 T out = 0;
224 size_t shift = 0;
225
226 require_bytes(in, pos, nbytes, name);
227
228 while (nbytes > 0)
229 {
230 out |= widen<T,u8>(in[pos++]) << shift;
231 shift += 8;
232 --nbytes;
233 }
234 return out;
235}
236
237template <typename T>
238inline void
239insert_datum_lsb(T in, std::string & out)
240{
241 size_t const nbytes = sizeof(T);
242 char tmp[nbytes];
243 for (size_t i = 0; i < nbytes; ++i)
244 {
245 tmp[i] = static_cast<u8>(in) & static_cast<u8>(0xff);
246 in >>= 8;
247 }
248 out.append(std::string(tmp, tmp+nbytes));
249}
250
251template <typename T>
252inline void
253insert_datum_lsb(T in, string_queue & out)
254{
255 size_t const nbytes = sizeof(T);
256 char tmp[nbytes];
257 for (size_t i = 0; i < nbytes; ++i)
258 {
259 tmp[i] = static_cast<u8>(in) & static_cast<u8>(0xff);
260 in >>= 8;
261 }
262 out.append(std::string(tmp, tmp+nbytes));
263}
264
265inline void
266extract_variable_length_string(std::string const & buf,
267 std::string & out,
268 size_t & pos,
269 std::string const & name,
270 size_t maxlen = std::numeric_limits<size_t>::max())
271{
272 BOOST_STATIC_ASSERT(sizeof(std::string::size_type) == sizeof(size_t));
273 size_t len = extract_datum_uleb128<size_t>(buf, pos, name);
274 if (len > maxlen)
275 throw bad_decode(F("decoding variable length string of %d bytes for '%s', maximum is %d")
276 % len % name % maxlen);
277 require_bytes(buf, pos, len, name);
278 out.assign(buf, pos, len);
279 pos += len;
280}
281
282inline void
283insert_variable_length_string(std::string const & in,
284 std::string & buf)
285{
286 size_t len = in.size();
287 insert_datum_uleb128<size_t>(len, buf);
288 buf.append(in);
289}
290
291inline void
292insert_variable_length_string(std::string const & in,
293 string_queue & buf)
294{
295 size_t len = in.size();
296 insert_datum_uleb128<size_t>(len, buf);
297 buf.append(in);
298}
299
300inline std::string
301extract_substring(std::string const & buf,
302 size_t & pos,
303 size_t len,
304 std::string const & name)
305{
306 require_bytes(buf, pos, len, name);
307 std::string tmp = buf.substr(pos, len);
308 pos += len;
309 return tmp;
310}
311
312inline std::string
313extract_substring(string_queue const & buf,
314 size_t & pos,
315 size_t len,
316 std::string const & name)
317{
318 require_bytes(buf, pos, len, name);
319 std::string tmp = buf.substr(pos, len);
320 pos += len;
321 return tmp;
322}
323
324inline void
325assert_end_of_buffer(std::string const & str,
326 size_t pos,
327 std::string const & name)
328{
329 if (str.size() != pos)
330 throw bad_decode(F("expected %s to end at %d, have %d bytes")
331 % name % pos % str.size());
332}
333
334#endif // __NETIO_HH__

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status