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 <limits>
16
17#include "numeric_vocab.hh"
18#include "sanity.hh"
19
20struct bad_decode {
21 bad_decode(boost::format const & fmt) : what(fmt.str()) {}
22 std::string what;
23};
24
25BOOST_STATIC_ASSERT(sizeof(char) == 1);
26BOOST_STATIC_ASSERT(CHAR_BIT == 8);
27
28template <typename T, typename V>
29inline T
30widen(V const & v)
31{
32 BOOST_STATIC_ASSERT(sizeof(T) >= sizeof(V));
33 if (std::numeric_limits<T>::is_signed)
34 return static_cast<T>(v);
35 else
36 {
37 T mask = std::numeric_limits<T>::max();
38 size_t shift = (sizeof(T) - sizeof(V)) * 8;
39 mask >>= shift;
40 return static_cast<T>(v) & mask;
41 }
42}
43
44inline void
45require_bytes(std::string const & str,
46 size_t pos,
47 size_t len,
48 std::string const & name)
49{
50 // if you've gone past the end of the buffer, there's a logic error,
51 // and this program is not safe to keep running. shut down.
52 I(pos < str.size());
53 // otherwise make sure there's room for this decode operation, but
54 // use a recoverable exception type.
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 T
97extract_datum_uleb128(std::string const & in,
98 size_t & pos,
99 std::string const & name)
100{
101 T out;
102 size_t tpos = pos;
103 if (! try_extract_datum_uleb128(in, tpos, name, out))
104 throw bad_decode(F("ran out of bytes reading uleb128 value for '%s' at pos %d")
105 % name % pos);
106 pos = tpos;
107 return out;
108}
109
110template <typename T>
111inline void
112insert_datum_uleb128(T in, std::string & out)
113{
114 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_signed == false);
115 size_t maxbytes = sizeof(T) + 1 + (sizeof(T) / 8);
116 while (maxbytes > 0)
117 {
118 u8 item = (static_cast<u8>(in) & static_cast<u8>(0x7f));
119 T remainder = in >> 7;
120 bool finished = ! static_cast<bool>(remainder);
121 if (finished)
122{
123 out += item;
124 break;
125}
126 else
127{
128 out += (item | static_cast<u8>(0x80));
129 --maxbytes;
130 in = remainder;
131}
132 }
133}
134
135template <typename T>
136inline T
137extract_datum_lsb(std::string const & in,
138 size_t & pos,
139 std::string const & name)
140{
141 size_t nbytes = sizeof(T);
142 T out = 0;
143 size_t shift = 0;
144
145 require_bytes(in, pos, nbytes, name);
146
147 while (nbytes > 0)
148 {
149 out |= widen<T,u8>(in[pos++]) << shift;
150 shift += 8;
151 --nbytes;
152 }
153 return out;
154}
155
156template <typename T>
157inline void
158insert_datum_lsb(T in, std::string & out)
159{
160 size_t const nbytes = sizeof(T);
161 char tmp[nbytes];
162 for (size_t i = 0; i < nbytes; ++i)
163 {
164 tmp[i] = static_cast<u8>(in) & static_cast<u8>(0xff);
165 in >>= 8;
166 }
167 out.append(std::string(tmp, tmp+nbytes));
168}
169
170inline void
171extract_variable_length_string(std::string const & buf,
172 std::string & out,
173 size_t & pos,
174 std::string const & name,
175 size_t maxlen = std::numeric_limits<size_t>::max())
176{
177 BOOST_STATIC_ASSERT(sizeof(std::string::size_type) == sizeof(size_t));
178 size_t len = extract_datum_uleb128<size_t>(buf, pos, name);
179 if (len > maxlen)
180 throw bad_decode(F("decoding variable length string of %d bytes for '%s', maximum is %d")
181 % len % name % maxlen);
182 require_bytes(buf, pos, len, name);
183 out.assign(buf, pos, len);
184 pos += len;
185}
186
187inline void
188insert_variable_length_string(std::string const & in,
189 std::string & buf)
190{
191 size_t len = in.size();
192 insert_datum_uleb128<size_t>(len, buf);
193 buf.append(in);
194}
195
196
197inline std::string
198extract_substring(std::string const & buf,
199 size_t & pos,
200 size_t len,
201 std::string const & name)
202{
203 require_bytes(buf, pos, len, name);
204 std::string tmp = buf.substr(pos, len);
205 pos += len;
206 return tmp;
207}
208
209inline void
210assert_end_of_buffer(std::string const & str,
211 size_t pos,
212 std::string const & name)
213{
214 if (str.size() != pos)
215 throw bad_decode(F("expected %s to end at %d, have %d bytes")
216 % name % pos % str.size());
217}
218
219#endif // __NETIO_HH__

Archive Download this file

Branches

Tags

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