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

Archive Download this file

Branches

Tags

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