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