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
18struct bad_decode {
19 bad_decode(boost::format const & fmt) : what(fmt.str()) {}
20 std::string what;
21};
22
23inline void
24require_bytes(std::string const & str,
25 size_t pos,
26 size_t len,
27 std::string const & name)
28{
29 // if you've gone past the end of the buffer, there's a logic error,
30 // and this program is not safe to keep running. shut down.
31 I(pos < str.size() || (pos == str.size() && len == 0));
32 // otherwise make sure there's room for this decode operation, but
33 // use a recoverable exception type.
34 if (len == 0)
35 return;
36 if (str.size() < pos + len)
37 throw bad_decode(F("need %d bytes to decode %s at %d, only have %d")
38 % len % name % pos % (str.size() - pos));
39}
40
41template <typename T>
42inline bool
43try_extract_datum_uleb128(std::string const & in,
44 size_t & pos,
45 std::string const & name,
46 T & out)
47{
48 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_signed == false);
49 size_t shift = 0;
50 size_t maxbytes = sizeof(T) + 1 + (sizeof(T) / 8);
51 out = 0;
52 while (maxbytes > 0)
53 {
54 if (pos >= in.size())
55return false;
56 T curr = widen<T,u8>(in[pos]);
57 ++pos;
58 out |= ((static_cast<u8>(curr)
59 & static_cast<u8>(0x7f)) << shift);
60 bool finished = ! static_cast<bool>(static_cast<u8>(curr)
61 & static_cast<u8>(0x80));
62 if (finished)
63break;
64 else if (maxbytes == 1)
65throw bad_decode(F("uleb128 decode for '%s' into %d-byte datum overflowed")
66 % name % maxbytes);
67 else
68{
69 --maxbytes;
70 shift += 7;
71}
72 }
73 return true;
74}
75
76template <typename T>
77inline T
78extract_datum_uleb128(std::string const & in,
79 size_t & pos,
80 std::string const & name)
81{
82 T out;
83 size_t tpos = pos;
84 if (! try_extract_datum_uleb128(in, tpos, name, out))
85 throw bad_decode(F("ran out of bytes reading uleb128 value for '%s' at pos %d")
86 % name % pos);
87 pos = tpos;
88 return out;
89}
90
91template <typename T>
92inline void
93insert_datum_uleb128(T in, std::string & out)
94{
95 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_signed == false);
96 size_t maxbytes = sizeof(T) + 1 + (sizeof(T) / 8);
97 while (maxbytes > 0)
98 {
99 u8 item = (static_cast<u8>(in) & static_cast<u8>(0x7f));
100 T remainder = in >> 7;
101 bool finished = ! static_cast<bool>(remainder);
102 if (finished)
103{
104 out += item;
105 break;
106}
107 else
108{
109 out += (item | static_cast<u8>(0x80));
110 --maxbytes;
111 in = remainder;
112}
113 }
114}
115
116template <typename T>
117inline T
118extract_datum_lsb(std::string const & in,
119 size_t & pos,
120 std::string const & name)
121{
122 size_t nbytes = sizeof(T);
123 T out = 0;
124 size_t shift = 0;
125
126 require_bytes(in, pos, nbytes, name);
127
128 while (nbytes > 0)
129 {
130 out |= widen<T,u8>(in[pos++]) << shift;
131 shift += 8;
132 --nbytes;
133 }
134 return out;
135}
136
137template <typename T>
138inline void
139insert_datum_lsb(T in, std::string & out)
140{
141 size_t const nbytes = sizeof(T);
142 char tmp[nbytes];
143 for (size_t i = 0; i < nbytes; ++i)
144 {
145 tmp[i] = static_cast<u8>(in) & static_cast<u8>(0xff);
146 in >>= 8;
147 }
148 out.append(std::string(tmp, tmp+nbytes));
149}
150
151inline void
152extract_variable_length_string(std::string const & buf,
153 std::string & out,
154 size_t & pos,
155 std::string const & name,
156 size_t maxlen = std::numeric_limits<size_t>::max())
157{
158 BOOST_STATIC_ASSERT(sizeof(std::string::size_type) == sizeof(size_t));
159 size_t len = extract_datum_uleb128<size_t>(buf, pos, name);
160 if (len > maxlen)
161 throw bad_decode(F("decoding variable length string of %d bytes for '%s', maximum is %d")
162 % len % name % maxlen);
163 require_bytes(buf, pos, len, name);
164 out.assign(buf, pos, len);
165 pos += len;
166}
167
168inline void
169insert_variable_length_string(std::string const & in,
170 std::string & buf)
171{
172 size_t len = in.size();
173 insert_datum_uleb128<size_t>(len, buf);
174 buf.append(in);
175}
176
177
178inline std::string
179extract_substring(std::string const & buf,
180 size_t & pos,
181 size_t len,
182 std::string const & name)
183{
184 require_bytes(buf, pos, len, name);
185 std::string tmp = buf.substr(pos, len);
186 pos += len;
187 return tmp;
188}
189
190inline void
191assert_end_of_buffer(std::string const & str,
192 size_t pos,
193 std::string const & name)
194{
195 if (str.size() != pos)
196 throw bad_decode(F("expected %s to end at %d, have %d bytes")
197 % name % pos % str.size());
198}
199
200#endif // __NETIO_HH__

Archive Download this file

Branches

Tags

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