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#include <string>
11
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
52inline void
53verify_full(path_component & val)
54{
55 // FIXME: probably ought to do something here?
56 val.ok = true;
57}
58
59// NOTE: _not_ verify_full; you use verify_full for ATOMICs, verify() for
60// everything else.
61inline void
62verify(hexenc<id> & val)
63{
64 if (val.ok)
65 return;
66
67 if (val().empty())
68 return;
69
70 N(val().size() == constants::idlen,
71 F("hex encoded ID '%s' size != %d") % val % constants::idlen);
72 for (string::const_iterator i = val().begin(); i != val().end(); ++i)
73 {
74 N(is_xdigit(*i),
75 F("bad character '%c' in id name '%s'") % *i % val);
76 }
77 val.ok = true;
78}
79
80inline void
81verify_full(ace & val)
82{
83 string::size_type pos = val().find_first_not_of(constants::legal_ace_bytes);
84 N(pos == string::npos,
85 F("bad character '%c' in ace string '%s'") % val().at(pos) % val);
86
87 val.ok = true;
88}
89
90inline void
91verify_full(symbol & val)
92{
93 for (string::const_iterator i = val().begin(); i != val().end(); ++i)
94 {
95 N(is_alnum(*i) || *i == '_',
96 F("bad character '%c' in symbol '%s'") % *i % val);
97 }
98
99 val.ok = true;
100}
101
102inline void
103verify_full(cert_name & val)
104{
105 string::size_type pos = val().find_first_not_of(constants::legal_cert_name_bytes);
106 N(pos == string::npos,
107 F("bad character '%c' in cert name '%s'") % val().at(pos) % val);
108
109 val.ok = true;
110}
111
112inline void
113verify_full(rsa_keypair_id & val)
114{
115 string::size_type pos = val().find_first_not_of(constants::legal_key_name_bytes);
116 N(pos == string::npos,
117 F("bad character '%c' in key name '%s'") % val().at(pos) % val);
118
119 val.ok = true;
120}
121
122inline void
123verify_full(netsync_session_key & val)
124{
125 if (val().size() == 0)
126 {
127 val.s.append(constants::netsync_session_key_length_in_bytes, 0);
128 return;
129 }
130
131 N(val().size() == constants::netsync_session_key_length_in_bytes,
132 F("Invalid key length of %d bytes") % val().length());
133
134 val.ok = true;
135}
136
137inline void
138verify_full(netsync_hmac_value & val)
139{
140 if (val().size() == 0)
141 {
142 val.s.append(constants::netsync_hmac_value_length_in_bytes, 0);
143 return;
144 }
145
146 N(val().size() == constants::netsync_hmac_value_length_in_bytes,
147 F("Invalid hmac length of %d bytes") % val().length());
148
149 val.ok = true;
150}
151
152
153// Note that ATOMIC types each keep a static symbol-table object and a
154// counter of activations, and when there is an activation, the
155// members of the ATOMIC type initialize their internal string using a
156// copy of the string found in the symtab. Since some (all?) C++
157// string implementations are copy-on-write, this has the affect
158// of making the ATOMIC(foo) values constructed within a symbol table
159// scope share string storage.
160struct
161symtab_impl
162{
163 typedef hashmap::hash_set<string> hset;
164 hset vals;
165 symtab_impl() : vals() {}
166 void clear() { vals.clear(); }
167 string const & unique(string const & in)
168 {
169 // This produces a pair <iter,bool> where iter points to an
170 // element of the table; the bool indicates whether the element is
171 // new, but we don't actually care. We just want the iter.
172 return *(vals.insert(in).first);
173 }
174};
175
176// Sometimes it's handy to have a non-colliding, meaningless id.
177
178hexenc<id>
179fake_id()
180{
181 static u32 counter = 0;
182 ++counter;
183 I(counter >= 1); // detect overflow
184 return hexenc<id>((FL("00000000000000000000000000000000%08x") % counter).str());
185}
186
187// instantiation of various vocab functions
188
189
190
191#include "vocab_macros.hh"
192#define ENCODING(enc) cc_ENCODING(enc)
193#define DECORATE(dec) cc_DECORATE(dec)
194#define ATOMIC(ty) cc_ATOMIC(ty)
195#define ATOMIC_NOVERIFY(ty) cc_ATOMIC_NOVERIFY(ty)
196
197#ifdef EXTERN
198#undef EXTERN
199#endif
200#define EXTERN
201
202#include "vocab_terms.hh"
203
204#undef EXTERN
205#undef ATOMIC
206#undef DECORATE
207
208
209template
210void dump<rsa_pub_key>(base64<rsa_pub_key> const&, string &);
211
212template
213void dump(revision_id const & r, string &);
214
215template
216void dump(manifest_id const & r, string &);
217
218template
219void dump(file_id const & r, string &);
220
221template
222void dump(hexenc<id> const & r, string &);
223
224template
225void dump(roster_data const & d, string &);
226
227template
228void dump(roster_delta const & d, string &);
229
230template
231void dump(manifest_data const & d, string &);
232
233#ifdef BUILD_UNIT_TESTS
234
235#include "unit_tests.hh"
236
237UNIT_TEST(vocab, verify_hexenc_id)
238{
239 // -------- magic empty string and default constructor are okay:
240 BOOST_CHECK(hexenc<id>("")() == "");
241 hexenc<id> my_default_id;
242 BOOST_CHECK(my_default_id() == "");
243
244 // -------- wrong length:
245 BOOST_CHECK_THROW(hexenc<id>("a"), informative_failure);
246 // 39 letters
247 BOOST_CHECK_THROW(hexenc<id>("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
248 informative_failure);
249 // 41 letters
250 BOOST_CHECK_THROW(hexenc<id>("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
251 informative_failure);
252 // but 40 is okay
253 BOOST_CHECK(hexenc<id>("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")()
254 == "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
255
256 // -------- bad characters:
257 BOOST_CHECK_THROW(hexenc<id>("g000000000000000000000000000000000000000"), informative_failure);
258 BOOST_CHECK_THROW(hexenc<id>("h000000000000000000000000000000000000000"), informative_failure);
259 BOOST_CHECK_THROW(hexenc<id>("G000000000000000000000000000000000000000"), informative_failure);
260 BOOST_CHECK_THROW(hexenc<id>("H000000000000000000000000000000000000000"), informative_failure);
261 BOOST_CHECK_THROW(hexenc<id>("*000000000000000000000000000000000000000"), informative_failure);
262 BOOST_CHECK_THROW(hexenc<id>("`000000000000000000000000000000000000000"), informative_failure);
263 BOOST_CHECK_THROW(hexenc<id>("z000000000000000000000000000000000000000"), informative_failure);
264 BOOST_CHECK_THROW(hexenc<id>("Z000000000000000000000000000000000000000"), informative_failure);
265 // different positions:
266 BOOST_CHECK_THROW(hexenc<id>("g000000000000000000000000000000000000000"), informative_failure);
267 BOOST_CHECK_THROW(hexenc<id>("0g00000000000000000000000000000000000000"), informative_failure);
268 BOOST_CHECK_THROW(hexenc<id>("00g0000000000000000000000000000000000000"), informative_failure);
269 BOOST_CHECK_THROW(hexenc<id>("000g000000000000000000000000000000000000"), informative_failure);
270 BOOST_CHECK_THROW(hexenc<id>("0000g00000000000000000000000000000000000"), informative_failure);
271 BOOST_CHECK_THROW(hexenc<id>("000000000000000000000g000000000000000000"), informative_failure);
272 BOOST_CHECK_THROW(hexenc<id>("0000000000000000000000g00000000000000000"), informative_failure);
273 BOOST_CHECK_THROW(hexenc<id>("000000000000000000000000000000g000000000"), informative_failure);
274 BOOST_CHECK_THROW(hexenc<id>("000000000000000000000000000000000000g000"), informative_failure);
275 BOOST_CHECK_THROW(hexenc<id>("0000000000000000000000000000000000000g00"), informative_failure);
276 BOOST_CHECK_THROW(hexenc<id>("00000000000000000000000000000000000000g0"), informative_failure);
277 BOOST_CHECK_THROW(hexenc<id>("000000000000000000000000000000000000000g"), informative_failure);
278 // uppercase hex is bad too!
279 BOOST_CHECK_THROW(hexenc<id>("A000000000000000000000000000000000000000"), informative_failure);
280 BOOST_CHECK_THROW(hexenc<id>("B000000000000000000000000000000000000000"), informative_failure);
281 BOOST_CHECK_THROW(hexenc<id>("C000000000000000000000000000000000000000"), informative_failure);
282 BOOST_CHECK_THROW(hexenc<id>("D000000000000000000000000000000000000000"), informative_failure);
283 BOOST_CHECK_THROW(hexenc<id>("E000000000000000000000000000000000000000"), informative_failure);
284 BOOST_CHECK_THROW(hexenc<id>("F000000000000000000000000000000000000000"), informative_failure);
285 // but lowercase and digits are all fine
286 BOOST_CHECK(hexenc<id>("0123456789abcdef0123456789abcdef01234567")()
287 == "0123456789abcdef0123456789abcdef01234567");
288}
289
290#endif // BUILD_UNIT_TESTS
291
292// Local Variables:
293// mode: C++
294// fill-column: 76
295// c-file-style: "gnu"
296// indent-tabs-mode: nil
297// End:
298// 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