monotone

monotone Mtn Source Tree

Root/vocab.cc

1// Copyright (C) 2002 Graydon Hoare <graydon@pobox.com>
2//
3// This program is made available under the GNU GPL version 2.0 or
4// greater. See the accompanying file COPYING for details.
5//
6// This program is distributed WITHOUT ANY WARRANTY; without even the
7// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8// PURPOSE.
9
10
11#include "base.hh"
12#include "constants.hh"
13#include "hash_map.hh"
14#include "sanity.hh"
15#include "vocab.hh"
16#include "char_classifiers.hh"
17#include "transforms.hh"
18
19using std::string;
20
21// verifiers for various types of data
22
23// Every ENCODING and ATOMIC type not defined with the _NOVERIFY variant in
24// vocab_terms.hh must have a verify function defined here. DECORATE types
25// use the verify function of their inner type.
26
27// ENCODING types ... hexenc<id> has a fixed size, hexenc<other> doesn't.
28template <typename INNER>
29inline void
30verify(hexenc<INNER> const & val)
31{
32 made_from_t made_from(val.made_from);
33 for (string::const_iterator i = val().begin(); i != val().end(); ++i)
34 {
35 N(is_xdigit(*i),
36 F("bad character '%c' in '%s'") % *i % val);
37 }
38}
39
40template <>
41inline void
42verify(hexenc<id> const & val)
43{
44 if (val().empty())
45 return;
46
47 made_from_t made_from(val.made_from);
48 N(val().size() == constants::idlen,
49 F("hex encoded ID '%s' size != %d") % val % constants::idlen);
50 for (string::const_iterator i = val().begin(); i != val().end(); ++i)
51 {
52 N(is_xdigit(*i),
53 F("bad character '%c' in id name '%s'") % *i % val);
54 }
55}
56
57// ATOMIC types ...
58inline void
59verify(id & val)
60{
61 if (val().empty())
62 return;
63
64 made_from_t made_from(val.made_from);
65 N(val().size() == constants::idlen_bytes,
66 F("invalid ID '%s'") % val);
67}
68
69inline void
70verify(symbol const & val)
71{
72 made_from_t made_from(val.made_from);
73 for (string::const_iterator i = val().begin(); i != val().end(); ++i)
74 {
75 N(is_alnum(*i) || *i == '_',
76 F("bad character '%c' in symbol '%s'") % *i % val);
77 }
78}
79
80inline void
81verify(cert_name const & val)
82{
83 made_from_t made_from(val.made_from);
84 string::size_type pos = val().find_first_not_of(constants::legal_cert_name_bytes);
85 N(pos == string::npos,
86 F("bad character '%c' in cert name '%s'") % val().at(pos) % val);
87}
88
89inline void
90verify(rsa_keypair_id const & val)
91{
92 made_from_t made_from(val.made_from);
93 string::size_type pos = val().find_first_not_of(constants::legal_key_name_bytes);
94 N(pos == string::npos,
95 F("bad character '%c' in key name '%s'") % val().at(pos) % val);
96}
97
98// These two may modify their argument, to set a more sensible value when
99// initializing from the empty string or the default constructor; therefore
100// they cannot take a const argument and must be friends with their class.
101
102inline void
103verify(netsync_session_key & val)
104{
105 if (val().empty())
106 {
107 val.s = std::string(constants::netsync_session_key_length_in_bytes, 0);
108 return;
109 }
110
111 made_from_t made_from(val.made_from);
112 N(val().size() == constants::netsync_session_key_length_in_bytes,
113 F("Invalid key length of %d bytes") % val().length());
114}
115
116inline void
117verify(netsync_hmac_value & val)
118{
119 if (val().empty())
120 {
121 val.s = std::string(constants::netsync_hmac_value_length_in_bytes, 0);
122 return;
123 }
124
125 made_from_t made_from(val.made_from);
126 N(val().size() == constants::netsync_hmac_value_length_in_bytes,
127 F("Invalid hmac length of %d bytes") % val().length());
128}
129
130
131// Note that ATOMIC types each keep a static symbol-table object and a
132// counter of activations, and when there is an activation, the
133// members of the ATOMIC type initialize their internal string using a
134// copy of the string found in the symtab. Since some (all?) C++
135// string implementations are copy-on-write, this has the affect
136// of making the ATOMIC(foo) values constructed within a symbol table
137// scope share string storage.
138struct
139symtab_impl
140{
141 typedef hashmap::hash_set<string> hset;
142 hset vals;
143 symtab_impl() : vals() {}
144 void clear() { vals.clear(); }
145 string const & unique(string const & in)
146 {
147 // This produces a pair <iter,bool> where iter points to an
148 // element of the table; the bool indicates whether the element is
149 // new, but we don't actually care. We just want the iter.
150 return *(vals.insert(in).first);
151 }
152};
153
154// Sometimes it's handy to have a non-colliding, meaningless id.
155
156id
157fake_id()
158{
159 static u32 counter = 0;
160 ++counter;
161 I(counter >= 1); // detect overflow
162 string s((FL("00000000000000000000000000000000%08x") % counter).str());
163 return id(decode_hexenc(s));
164}
165
166// instantiation of various vocab functions
167
168
169
170#include "vocab_macros.hh"
171#define ENCODING(enc) cc_ENCODING(enc)
172#define ENCODING_NOVERIFY(enc) cc_ENCODING_NOVERIFY(enc)
173#define DECORATE(dec) cc_DECORATE(dec)
174#define ATOMIC(ty) cc_ATOMIC(ty)
175#define ATOMIC_HOOKED(ty,hook) cc_ATOMIC(ty)
176#define ATOMIC_NOVERIFY(ty) cc_ATOMIC_NOVERIFY(ty)
177#define ATOMIC_BINARY(ty) cc_ATOMIC_BINARY(ty)
178
179#undef EXTERN
180#define EXTERN
181
182#include "vocab_terms.hh"
183
184#undef EXTERN
185#undef ATOMIC
186#undef ATOMIC_HOOKED
187#undef ATOMIC_NOVERIFY
188#undef DECORATE
189#undef ENCODING
190#undef ENCODING_NOVERIFY
191
192template void dump(revision_id const & r, string &);
193template void dump(manifest_id const & r, string &);
194template void dump(file_id const & r, string &);
195template void dump(hexenc<id> const & r, string &);
196template void dump(rsa_pub_key const&, string &);
197template void dump(roster_data const & d, string &);
198template void dump(roster_delta const & d, string &);
199template void dump(manifest_data const & d, string &);
200template void dump(revision_data const & d, string &);
201
202template std::ostream & operator<< <>(std::ostream &, epoch<id> const &);
203template std::ostream & operator<< <>(std::ostream &, file<id> const &);
204template std::ostream & operator<< <>(std::ostream &, hexenc<id> const &);
205template std::ostream & operator<< <>(std::ostream &, key<id> const &);
206template std::ostream & operator<< <>(std::ostream &, manifest<id> const &);
207template std::ostream & operator<< <>(std::ostream &, revision<id> const &);
208template std::ostream & operator<< <>(std::ostream &, roster<id> const &);
209
210template std::ostream & operator<< <>(std::ostream &, epoch<data> const &);
211template std::ostream & operator<< <>(std::ostream &, file<data> const &);
212template std::ostream & operator<< <>(std::ostream &, manifest<data> const &);
213template std::ostream & operator<< <>(std::ostream &, revision<data> const &);
214template std::ostream & operator<< <>(std::ostream &, roster<data> const &);
215
216/*
217 * specializations for id, which allows the encoded id
218 * to be dumped out as a human readable, hex encoded
219 * string.
220 */
221template <>
222void dump (id const & obj, std::string & out)
223{
224 out = encode_hexenc(obj());
225}
226
227#ifdef BUILD_UNIT_TESTS
228
229#include "unit_tests.hh"
230
231UNIT_TEST(vocab, verify_hexenc_id)
232{
233 // -------- magic empty string and default constructor are okay:
234 UNIT_TEST_CHECK(hexenc<id>("")() == "");
235 hexenc<id> my_default_id;
236 UNIT_TEST_CHECK(my_default_id() == "");
237
238 // -------- wrong length:
239 UNIT_TEST_CHECK_THROW(hexenc<id>("a"), informative_failure);
240 // 39 letters
241 UNIT_TEST_CHECK_THROW(hexenc<id>("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
242 informative_failure);
243 // 41 letters
244 UNIT_TEST_CHECK_THROW(hexenc<id>("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
245 informative_failure);
246 // but 40 is okay
247 UNIT_TEST_CHECK(hexenc<id>("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")()
248 == "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
249
250 // -------- bad characters:
251 UNIT_TEST_CHECK_THROW(hexenc<id>("g000000000000000000000000000000000000000"), informative_failure);
252 UNIT_TEST_CHECK_THROW(hexenc<id>("h000000000000000000000000000000000000000"), informative_failure);
253 UNIT_TEST_CHECK_THROW(hexenc<id>("G000000000000000000000000000000000000000"), informative_failure);
254 UNIT_TEST_CHECK_THROW(hexenc<id>("H000000000000000000000000000000000000000"), informative_failure);
255 UNIT_TEST_CHECK_THROW(hexenc<id>("*000000000000000000000000000000000000000"), informative_failure);
256 UNIT_TEST_CHECK_THROW(hexenc<id>("`000000000000000000000000000000000000000"), informative_failure);
257 UNIT_TEST_CHECK_THROW(hexenc<id>("z000000000000000000000000000000000000000"), informative_failure);
258 UNIT_TEST_CHECK_THROW(hexenc<id>("Z000000000000000000000000000000000000000"), informative_failure);
259 // different positions:
260 UNIT_TEST_CHECK_THROW(hexenc<id>("g000000000000000000000000000000000000000"), informative_failure);
261 UNIT_TEST_CHECK_THROW(hexenc<id>("0g00000000000000000000000000000000000000"), informative_failure);
262 UNIT_TEST_CHECK_THROW(hexenc<id>("00g0000000000000000000000000000000000000"), informative_failure);
263 UNIT_TEST_CHECK_THROW(hexenc<id>("000g000000000000000000000000000000000000"), informative_failure);
264 UNIT_TEST_CHECK_THROW(hexenc<id>("0000g00000000000000000000000000000000000"), informative_failure);
265 UNIT_TEST_CHECK_THROW(hexenc<id>("000000000000000000000g000000000000000000"), informative_failure);
266 UNIT_TEST_CHECK_THROW(hexenc<id>("0000000000000000000000g00000000000000000"), informative_failure);
267 UNIT_TEST_CHECK_THROW(hexenc<id>("000000000000000000000000000000g000000000"), informative_failure);
268 UNIT_TEST_CHECK_THROW(hexenc<id>("000000000000000000000000000000000000g000"), informative_failure);
269 UNIT_TEST_CHECK_THROW(hexenc<id>("0000000000000000000000000000000000000g00"), informative_failure);
270 UNIT_TEST_CHECK_THROW(hexenc<id>("00000000000000000000000000000000000000g0"), informative_failure);
271 UNIT_TEST_CHECK_THROW(hexenc<id>("000000000000000000000000000000000000000g"), informative_failure);
272 // uppercase hex is bad too!
273 UNIT_TEST_CHECK_THROW(hexenc<id>("A000000000000000000000000000000000000000"), informative_failure);
274 UNIT_TEST_CHECK_THROW(hexenc<id>("B000000000000000000000000000000000000000"), informative_failure);
275 UNIT_TEST_CHECK_THROW(hexenc<id>("C000000000000000000000000000000000000000"), informative_failure);
276 UNIT_TEST_CHECK_THROW(hexenc<id>("D000000000000000000000000000000000000000"), informative_failure);
277 UNIT_TEST_CHECK_THROW(hexenc<id>("E000000000000000000000000000000000000000"), informative_failure);
278 UNIT_TEST_CHECK_THROW(hexenc<id>("F000000000000000000000000000000000000000"), informative_failure);
279 // but lowercase and digits are all fine
280 UNIT_TEST_CHECK(hexenc<id>("0123456789abcdef0123456789abcdef01234567")()
281 == "0123456789abcdef0123456789abcdef01234567");
282}
283
284#endif // BUILD_UNIT_TESTS
285
286// Local Variables:
287// mode: C++
288// fill-column: 76
289// c-file-style: "gnu"
290// indent-tabs-mode: nil
291// End:
292// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

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