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
17using std::string;
18
19// verifiers for various types of data
20
21// the verify() stuff gets a little complicated; there doesn't seem to be a
22// really nice way to achieve what we want with c++'s type system. the
23// problem is this: we want to give verify(file_path) and verify(local_path)
24// access to the internals of file_path and local_path, i.e. make them
25// friends, so they can normalize the file paths they're given. this means
26// that verify() needs to be declared publically, so that the definition of
27// these classes can refer to them. it also means that they -- and all other
28// ATOMIC types -- cannot fall back on a templated version of verify if no
29// other version is defined, because, well, the friend thing and the template
30// thing just don't work out, as far as I can tell. So, every ATOMIC type
31// needs an explicitly defined verify() function, so we have both ATOMIC() and
32// ATOMIC_NOVERIFY() macros, the latter of which defines a type-specific noop
33// verify function. DECORATE and ENCODING, on the other hand, cannot make use
34// of a trick like these, because they are template types themselves, and we
35// want to be able to define verify(hexenc<id>) without defining
36// verify(hexenc<data>) at the same time, for instance. Fortunately, these
37// types never need to be friends with their verify functions (yet...), so we
38// _can_ use a templated fallback function. This templated function is used
39// _only_ by DECORATE and ENCODING; it would be nice to make it take an
40// argument of type T1<T2> to document that, but for some reason that doesn't
41// work either.
42template <typename T>
43static inline void
44verify(T & val)
45{}
46
47template <typename T>
48static inline void
49verify_full(T & val)
50{ val.ok = true; }
51
52// NOTE: _not_ verify_full; you use verify_full for ATOMICs, verify() for
53// everything else.
54inline void
55verify(hexenc<id> & val)
56{
57 if (val.ok)
58 return;
59
60 if (val().empty())
61 return;
62
63 N(val().size() == constants::idlen,
64 F("hex encoded ID '%s' size != %d") % val % constants::idlen);
65 for (string::const_iterator i = val().begin(); i != val().end(); ++i)
66 {
67 N(is_xdigit(*i),
68 F("bad character '%c' in id name '%s'") % *i % val);
69 }
70 val.ok = true;
71}
72
73inline void
74verify_full(symbol & val)
75{
76 for (string::const_iterator i = val().begin(); i != val().end(); ++i)
77 {
78 N(is_alnum(*i) || *i == '_',
79 F("bad character '%c' in symbol '%s'") % *i % val);
80 }
81
82 val.ok = true;
83}
84
85inline void
86verify_full(cert_name & val)
87{
88 string::size_type pos = val().find_first_not_of(constants::legal_cert_name_bytes);
89 N(pos == string::npos,
90 F("bad character '%c' in cert name '%s'") % val().at(pos) % val);
91
92 val.ok = true;
93}
94
95inline void
96verify_full(rsa_keypair_id & val)
97{
98 string::size_type pos = val().find_first_not_of(constants::legal_key_name_bytes);
99 N(pos == string::npos,
100 F("bad character '%c' in key name '%s'") % val().at(pos) % val);
101
102 val.ok = true;
103}
104
105inline void
106verify_full(netsync_session_key & val)
107{
108 if (val().size() == 0)
109 {
110 val.s = std::string(constants::netsync_session_key_length_in_bytes, 0);
111 return;
112 }
113
114 N(val().size() == constants::netsync_session_key_length_in_bytes,
115 F("Invalid key length of %d bytes") % val().length());
116
117 val.ok = true;
118}
119
120inline void
121verify_full(netsync_hmac_value & val)
122{
123 if (val().size() == 0)
124 {
125 val.s = std::string(constants::netsync_hmac_value_length_in_bytes, 0);
126 return;
127 }
128
129 N(val().size() == constants::netsync_hmac_value_length_in_bytes,
130 F("Invalid hmac length of %d bytes") % val().length());
131
132 val.ok = true;
133}
134
135
136// Note that ATOMIC types each keep a static symbol-table object and a
137// counter of activations, and when there is an activation, the
138// members of the ATOMIC type initialize their internal string using a
139// copy of the string found in the symtab. Since some (all?) C++
140// string implementations are copy-on-write, this has the affect
141// of making the ATOMIC(foo) values constructed within a symbol table
142// scope share string storage.
143struct
144symtab_impl
145{
146 typedef hashmap::hash_set<string> hset;
147 hset vals;
148 symtab_impl() : vals() {}
149 void clear() { vals.clear(); }
150 string const & unique(string const & in)
151 {
152 // This produces a pair <iter,bool> where iter points to an
153 // element of the table; the bool indicates whether the element is
154 // new, but we don't actually care. We just want the iter.
155 return *(vals.insert(in).first);
156 }
157};
158
159// Sometimes it's handy to have a non-colliding, meaningless id.
160
161hexenc<id>
162fake_id()
163{
164 static u32 counter = 0;
165 ++counter;
166 I(counter >= 1); // detect overflow
167 return hexenc<id>((FL("00000000000000000000000000000000%08x") % counter).str());
168}
169
170// instantiation of various vocab functions
171
172
173
174#include "vocab_macros.hh"
175#define ENCODING(enc) cc_ENCODING(enc)
176#define DECORATE(dec) cc_DECORATE(dec)
177#define ATOMIC(ty) cc_ATOMIC(ty)
178#define ATOMIC_NOVERIFY(ty) cc_ATOMIC_NOVERIFY(ty)
179
180#ifdef EXTERN
181#undef EXTERN
182#endif
183#define EXTERN
184
185#include "vocab_terms.hh"
186
187#undef EXTERN
188#undef ATOMIC
189#undef DECORATE
190
191
192template
193void dump<rsa_pub_key>(base64<rsa_pub_key> const&, string &);
194
195template
196void dump(revision_id const & r, string &);
197
198template
199void dump(manifest_id const & r, string &);
200
201template
202void dump(file_id const & r, string &);
203
204template
205void dump(hexenc<id> const & r, string &);
206
207template
208void dump(roster_data const & d, string &);
209
210template
211void dump(roster_delta const & d, string &);
212
213template
214void dump(manifest_data const & d, string &);
215
216#ifdef BUILD_UNIT_TESTS
217
218#include "unit_tests.hh"
219
220UNIT_TEST(vocab, verify_hexenc_id)
221{
222 // -------- magic empty string and default constructor are okay:
223 UNIT_TEST_CHECK(hexenc<id>("")() == "");
224 hexenc<id> my_default_id;
225 UNIT_TEST_CHECK(my_default_id() == "");
226
227 // -------- wrong length:
228 UNIT_TEST_CHECK_THROW(hexenc<id>("a"), informative_failure);
229 // 39 letters
230 UNIT_TEST_CHECK_THROW(hexenc<id>("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
231 informative_failure);
232 // 41 letters
233 UNIT_TEST_CHECK_THROW(hexenc<id>("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
234 informative_failure);
235 // but 40 is okay
236 UNIT_TEST_CHECK(hexenc<id>("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")()
237 == "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
238
239 // -------- bad characters:
240 UNIT_TEST_CHECK_THROW(hexenc<id>("g000000000000000000000000000000000000000"), informative_failure);
241 UNIT_TEST_CHECK_THROW(hexenc<id>("h000000000000000000000000000000000000000"), informative_failure);
242 UNIT_TEST_CHECK_THROW(hexenc<id>("G000000000000000000000000000000000000000"), informative_failure);
243 UNIT_TEST_CHECK_THROW(hexenc<id>("H000000000000000000000000000000000000000"), informative_failure);
244 UNIT_TEST_CHECK_THROW(hexenc<id>("*000000000000000000000000000000000000000"), informative_failure);
245 UNIT_TEST_CHECK_THROW(hexenc<id>("`000000000000000000000000000000000000000"), informative_failure);
246 UNIT_TEST_CHECK_THROW(hexenc<id>("z000000000000000000000000000000000000000"), informative_failure);
247 UNIT_TEST_CHECK_THROW(hexenc<id>("Z000000000000000000000000000000000000000"), informative_failure);
248 // different positions:
249 UNIT_TEST_CHECK_THROW(hexenc<id>("g000000000000000000000000000000000000000"), informative_failure);
250 UNIT_TEST_CHECK_THROW(hexenc<id>("0g00000000000000000000000000000000000000"), informative_failure);
251 UNIT_TEST_CHECK_THROW(hexenc<id>("00g0000000000000000000000000000000000000"), informative_failure);
252 UNIT_TEST_CHECK_THROW(hexenc<id>("000g000000000000000000000000000000000000"), informative_failure);
253 UNIT_TEST_CHECK_THROW(hexenc<id>("0000g00000000000000000000000000000000000"), informative_failure);
254 UNIT_TEST_CHECK_THROW(hexenc<id>("000000000000000000000g000000000000000000"), informative_failure);
255 UNIT_TEST_CHECK_THROW(hexenc<id>("0000000000000000000000g00000000000000000"), informative_failure);
256 UNIT_TEST_CHECK_THROW(hexenc<id>("000000000000000000000000000000g000000000"), informative_failure);
257 UNIT_TEST_CHECK_THROW(hexenc<id>("000000000000000000000000000000000000g000"), informative_failure);
258 UNIT_TEST_CHECK_THROW(hexenc<id>("0000000000000000000000000000000000000g00"), informative_failure);
259 UNIT_TEST_CHECK_THROW(hexenc<id>("00000000000000000000000000000000000000g0"), informative_failure);
260 UNIT_TEST_CHECK_THROW(hexenc<id>("000000000000000000000000000000000000000g"), informative_failure);
261 // uppercase hex is bad too!
262 UNIT_TEST_CHECK_THROW(hexenc<id>("A000000000000000000000000000000000000000"), informative_failure);
263 UNIT_TEST_CHECK_THROW(hexenc<id>("B000000000000000000000000000000000000000"), informative_failure);
264 UNIT_TEST_CHECK_THROW(hexenc<id>("C000000000000000000000000000000000000000"), informative_failure);
265 UNIT_TEST_CHECK_THROW(hexenc<id>("D000000000000000000000000000000000000000"), informative_failure);
266 UNIT_TEST_CHECK_THROW(hexenc<id>("E000000000000000000000000000000000000000"), informative_failure);
267 UNIT_TEST_CHECK_THROW(hexenc<id>("F000000000000000000000000000000000000000"), informative_failure);
268 // but lowercase and digits are all fine
269 UNIT_TEST_CHECK(hexenc<id>("0123456789abcdef0123456789abcdef01234567")()
270 == "0123456789abcdef0123456789abcdef01234567");
271}
272
273#endif // BUILD_UNIT_TESTS
274
275// Local Variables:
276// mode: C++
277// fill-column: 76
278// c-file-style: "gnu"
279// indent-tabs-mode: nil
280// End:
281// 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