Commit | Line | Data |
---|---|---|
970ed795 | 1 | /////////////////////////////////////////////////////////////////////////////// |
3abe9331 | 2 | // Copyright (c) 2000-2015 Ericsson Telecom AB |
970ed795 EL |
3 | // All rights reserved. This program and the accompanying materials |
4 | // are made available under the terms of the Eclipse Public License v1.0 | |
5 | // which accompanies this distribution, and is available at | |
6 | // http://www.eclipse.org/legal/epl-v10.html | |
7 | /////////////////////////////////////////////////////////////////////////////// | |
8 | #include "Tag.hh" | |
9 | #include "../Type.hh" | |
10 | #include "../Value.hh" | |
11 | #include <limits.h> | |
12 | ||
13 | namespace Asn { | |
14 | ||
15 | // ================================= | |
16 | // ===== Tag | |
17 | // ================================= | |
18 | ||
19 | Tag::Tag(tagplicit_t p_plicit, tagclass_t p_tagclass, Value *p_tagvalue) | |
20 | : Node(), Location(), | |
21 | plicit(p_plicit), tagclass(p_tagclass), tagvalue(p_tagvalue), | |
22 | is_auto(false) | |
23 | { | |
24 | if(!p_tagvalue) | |
25 | FATAL_ERROR("NULL parameter: Asn::Tag::Tag()"); | |
26 | } | |
27 | ||
28 | Tag::Tag(tagplicit_t p_plicit, tagclass_t p_tagclass, Int p_tagval) | |
29 | : Node(), Location(), | |
30 | plicit(p_plicit), tagclass(p_tagclass), tagvalue(0), | |
31 | tagval(p_tagval), is_auto(false) | |
32 | { | |
33 | if(tagval<0) FATAL_ERROR("Asn::Tag::Tag(): negative value"); | |
34 | } | |
35 | ||
36 | Tag::Tag(const Tag& p) | |
37 | : Node(p), Location(p), | |
38 | plicit(p.plicit), tagclass(p.tagclass), | |
39 | is_auto(p.is_auto) | |
40 | { | |
41 | if (p.tagvalue) tagvalue = p.tagvalue->clone(); | |
42 | else { | |
43 | tagvalue = NULL; | |
44 | tagval = p.tagval; | |
45 | } | |
46 | } | |
47 | ||
48 | Tag::~Tag() | |
49 | { | |
50 | delete tagvalue; | |
51 | } | |
52 | ||
53 | Tag& Tag::operator=(const Tag& p) | |
54 | { | |
55 | if (&p != this) { | |
56 | delete tagvalue; | |
57 | plicit = p.plicit; | |
58 | tagclass = p.tagclass; | |
59 | if (p.tagvalue) tagvalue = p.tagvalue->clone(); | |
60 | else { | |
61 | tagvalue = NULL; | |
62 | tagval = p.tagval; | |
63 | } | |
64 | is_auto = p.is_auto; | |
65 | } | |
66 | return *this; | |
67 | } | |
68 | ||
69 | bool Tag::operator==(const Tag& p) const | |
70 | { | |
71 | if (tagvalue || p.tagvalue) FATAL_ERROR("Comparison of unchecked tags."); | |
72 | return tagclass == p.tagclass && tagval == p.tagval; | |
73 | } | |
74 | ||
75 | bool Tag::operator<(const Tag& p) const | |
76 | { | |
77 | if (tagvalue || p.tagvalue) FATAL_ERROR("Comparison of unchecked tags."); | |
78 | if (tagclass < p.tagclass) return true; | |
79 | else if (tagclass > p.tagclass) return false; | |
80 | else return tagval < p.tagval; | |
81 | } | |
82 | ||
83 | const char *Tag::get_tagclass_str() const | |
84 | { | |
85 | switch (tagclass) { | |
86 | case TAG_UNIVERSAL: | |
87 | return "ASN_TAG_UNIV"; | |
88 | case TAG_APPLICATION: | |
89 | return "ASN_TAG_APPL"; | |
90 | case TAG_CONTEXT: | |
91 | return "ASN_TAG_CONT"; | |
92 | case TAG_PRIVATE: | |
93 | return "ASN_TAG_PRIV"; | |
94 | default: | |
95 | FATAL_ERROR("Tag::get_tagclass_str()"); | |
96 | return NULL; | |
97 | } | |
98 | } | |
99 | ||
100 | Int Tag::get_tagvalue() | |
101 | { | |
102 | chk(); | |
103 | return tagval; | |
104 | } | |
105 | ||
106 | void Tag::set_tagvalue(const Int& p_tagval) | |
107 | { | |
108 | if(tagvalue) {delete tagvalue; tagvalue=0;} | |
109 | tagval=p_tagval; | |
110 | } | |
111 | ||
112 | void Tag::set_my_scope(Scope *p_scope) | |
113 | { | |
114 | if (tagvalue) tagvalue->set_my_scope(p_scope); | |
115 | } | |
116 | ||
117 | void Tag::chk() | |
118 | { | |
119 | if (!tagvalue) return; | |
120 | Error_Context cntxt(this, "In tag"); | |
121 | Value *v = tagvalue->get_value_refd_last(); | |
122 | switch (v->get_valuetype()) { | |
123 | case Value::V_INT: { | |
124 | const int_val_t *tagval_int = tagvalue->get_val_Int(); | |
125 | if (*tagval_int < 0 || *tagval_int > INT_MAX) { | |
126 | error("Integer value in range 0..%d was expected instead of `%s' " | |
127 | "for tag value", INT_MAX, (tagval_int->t_str()).c_str()); | |
128 | goto error; | |
129 | } | |
130 | tagval = tagval_int->get_val(); | |
131 | break; } | |
132 | case Value::V_ERROR: | |
133 | goto error; | |
134 | break; | |
135 | default: | |
136 | error("INTEGER value was expected for tag value"); | |
137 | goto error; | |
138 | } | |
139 | goto end; | |
140 | error: | |
141 | tagclass=TAG_ERROR; | |
142 | tagval=0; | |
143 | end: | |
144 | delete tagvalue; | |
145 | tagvalue = 0; | |
146 | } | |
147 | ||
148 | void Tag::dump(unsigned level) const | |
149 | { | |
150 | string s('['); | |
151 | switch(tagclass) { | |
152 | case TAG_ERROR: | |
153 | s+="<ERROR> "; break; | |
154 | case TAG_NONE: | |
155 | s+="<NONE> "; break; | |
156 | case TAG_ALL: | |
157 | s+="<ALL> "; break; | |
158 | case TAG_UNIVERSAL: | |
159 | s+="UNIVERSAL "; break; | |
160 | case TAG_APPLICATION: | |
161 | s+="APPLICATION "; break; | |
162 | case TAG_CONTEXT: | |
163 | break; | |
164 | case TAG_PRIVATE: | |
165 | s+="PRIVATE "; break; | |
166 | default: | |
167 | s+=" <UNKNOWN CLASS>"; break; | |
168 | } // switch tagclass | |
169 | if(!tagvalue) s+=Int2string(tagval); | |
170 | else s+="<value>"; | |
171 | s+="]"; | |
172 | switch(plicit) { | |
173 | case TAG_DEFPLICIT: | |
174 | break; | |
175 | case TAG_EXPLICIT: | |
176 | s+=" EXPLICIT"; break; | |
177 | case TAG_IMPLICIT: | |
178 | s+=" IMPLICIT"; break; | |
179 | default: | |
180 | s+=" <UNKNOWN PLICIT>"; break; | |
181 | } // switch plicit | |
182 | if(is_auto) s+=" (auto)"; | |
183 | DEBUG(level, "Tag: %s", s.c_str()); | |
184 | if(tagvalue) tagvalue->dump(level+1); | |
185 | } | |
186 | ||
187 | // ================================= | |
188 | // ===== Tags | |
189 | // ================================= | |
190 | ||
191 | Tags::Tags() : Node() | |
192 | { | |
193 | set_fullname(string("<tags>")); | |
194 | my_scope=0; | |
195 | } | |
196 | ||
197 | Tags::Tags(const Tags& p) : Node(p) | |
198 | { | |
199 | for(size_t i=0; i<p.tags.size(); i++) | |
200 | add_tag(p.tags[i]->clone()); | |
201 | my_scope=0; | |
202 | } | |
203 | ||
204 | Tags::~Tags() | |
205 | { | |
206 | for(size_t i=0; i<tags.size(); i++) delete tags[i]; | |
207 | tags.clear(); | |
208 | } | |
209 | ||
210 | void Tags::set_fullname(const string& p_fullname) | |
211 | { | |
212 | Node::set_fullname(p_fullname); | |
213 | for(size_t i=0; i<tags.size(); i++) | |
214 | tags[i]->set_fullname(get_fullname()+"."+Int2string(i)); | |
215 | } | |
216 | ||
217 | void Tags::set_my_scope(Scope *p_scope) | |
218 | { | |
219 | my_scope=p_scope; | |
220 | for(size_t i=0; i<tags.size(); i++) | |
221 | tags[i]->set_my_scope(p_scope); | |
222 | } | |
223 | ||
224 | void Tags::add_tag(Tag *p_tag) | |
225 | { | |
226 | if(!p_tag) | |
227 | FATAL_ERROR("NULL parameter: Asn::Tags::add_tag()"); | |
228 | tags.add(p_tag); | |
229 | p_tag->set_fullname(get_fullname()+"."+Int2string(tags.size())); | |
230 | p_tag->set_my_scope(my_scope); | |
231 | } | |
232 | ||
233 | void Tags::chk() | |
234 | { | |
235 | for(size_t i=0; i<tags.size(); i++) | |
236 | tags[i]->chk(); | |
237 | } | |
238 | ||
239 | void Tags::set_plicit(Type *p_type) | |
240 | { | |
241 | if (!p_type) FATAL_ERROR("NULL parameter: Asn::Tags::set_plicit()"); | |
242 | Asn::Module *m = dynamic_cast<Asn::Module*> | |
243 | (p_type->get_my_scope()->get_scope_mod()); | |
244 | if (!m) FATAL_ERROR("Asn::Tags::set_plicit()"); | |
245 | bool type_needs_explicit = p_type->needs_explicit_tag(); | |
246 | bool module_uses_explicit = (m->get_tagdef() == TagDefault::EXPLICIT); | |
247 | Tag *innermost = tags[0]; | |
248 | switch (innermost->get_plicit()) { | |
249 | case Tag::TAG_DEFPLICIT: | |
250 | if (module_uses_explicit || type_needs_explicit) | |
251 | innermost->set_plicit(Tag::TAG_EXPLICIT); | |
252 | else innermost->set_plicit(Tag::TAG_IMPLICIT); | |
253 | break; | |
254 | case Tag::TAG_IMPLICIT: | |
255 | if (type_needs_explicit) { | |
256 | p_type->error("Type cannot have IMPLICIT tag"); | |
257 | innermost->set_plicit(Tag::TAG_EXPLICIT); | |
258 | } | |
259 | default: | |
260 | break; | |
261 | } | |
262 | for (size_t i = 1; i < tags.size(); i++) { | |
263 | Tag *tag = tags[i]; | |
264 | if (tag->get_plicit() == Tag::TAG_DEFPLICIT) { | |
265 | if (module_uses_explicit) tag->set_plicit(Tag::TAG_EXPLICIT); | |
266 | else tag->set_plicit(Tag::TAG_IMPLICIT); | |
267 | } | |
268 | } | |
269 | } | |
270 | ||
271 | void Tags::cut_auto_tags() | |
272 | { | |
273 | size_t i = 0; | |
274 | while (i < tags.size()) { | |
275 | Tag *tag = tags[i]; | |
276 | if (tag->is_automatic()) { | |
277 | delete tag; | |
278 | tags.replace(i, 1, NULL); | |
279 | } else i++; | |
280 | } | |
281 | } | |
282 | ||
283 | void Tags::dump(unsigned level) const | |
284 | { | |
285 | for(size_t i=0; i<tags.size(); i++) | |
286 | tags[i]->dump(level); | |
287 | } | |
288 | ||
289 | // ================================= | |
290 | // ===== TagCollection | |
291 | // ================================= | |
292 | ||
293 | TagCollection::TagCollection() | |
294 | : has_all(NULL), is_extensible(false) | |
295 | { | |
296 | } | |
297 | ||
298 | TagCollection::TagCollection(const TagCollection& p) | |
299 | : Node(p), Location(p), | |
300 | has_all(p.has_all), is_extensible(p.is_extensible) | |
301 | { | |
302 | for (size_t i = 0; i < p.tag_map.size(); i++) | |
303 | tag_map.add(p.tag_map.get_nth_key(i), 0); | |
304 | } | |
305 | ||
306 | TagCollection::~TagCollection() | |
307 | { | |
308 | tag_map.clear(); | |
309 | } | |
310 | ||
311 | void TagCollection::addTag(const Tag *p_tag) | |
312 | { | |
313 | if (!p_tag) | |
314 | FATAL_ERROR("Asn::TagCollection::addTag()"); | |
315 | if (p_tag->get_tagclass() == Tag::TAG_ALL) { | |
316 | if (has_all) | |
317 | FATAL_ERROR("Asn::TagCollection::addTag(): tag 'all'"); | |
318 | has_all = p_tag; | |
319 | } | |
320 | else if(p_tag->get_tagclass() == Tag::TAG_ERROR) | |
321 | return; | |
322 | else if(!tag_map.has_key(*p_tag)) | |
323 | tag_map.add(*p_tag, 0); | |
324 | else | |
325 | FATAL_ERROR("Asn::TagCollection::addTag(): tag is already in collection"); | |
326 | } | |
327 | ||
328 | bool TagCollection::hasTag(const Tag *p_tag) const | |
329 | { | |
330 | if (!p_tag) FATAL_ERROR("NULL parameter: Asn::TagCollection::hasTag()"); | |
331 | if (has_all) return true; | |
332 | else if (p_tag->get_tagclass() == Tag::TAG_ALL) return !tag_map.empty(); | |
333 | else if (p_tag->get_tagclass() == Tag::TAG_ERROR) return false; | |
334 | else return tag_map.has_key(*p_tag); | |
335 | } | |
336 | ||
337 | void TagCollection::addTags(const TagCollection *p_tags) | |
338 | { | |
339 | if (!p_tags) FATAL_ERROR("NULL parameter: Asn::TagCollection::addTags()"); | |
340 | if (p_tags->is_extensible) setExtensible(); | |
341 | if (p_tags->has_all) { | |
342 | if (has_all) FATAL_ERROR("Asn::TagCollection::addTags(): tag 'all'"); | |
343 | has_all = p_tags->has_all; | |
344 | } | |
345 | for (size_t i = 0; i < p_tags->tag_map.size(); i++) { | |
346 | const Tag& tag = p_tags->tag_map.get_nth_key(i); | |
347 | if (!tag_map.has_key(tag)) tag_map.add(tag, 0); | |
348 | else FATAL_ERROR("Asn::TagCollection::addTags(): tag is already in collection"); | |
349 | } | |
350 | } | |
351 | ||
352 | bool TagCollection::hasTags(const TagCollection *p_tags) const | |
353 | { | |
354 | if (!p_tags) FATAL_ERROR("NULL parameter: Asn::TagCollection::hasTags()"); | |
355 | if (has_all) return !p_tags->isEmpty(); | |
356 | else if (p_tags->has_all) return !isEmpty(); | |
357 | for (size_t i = 0; i < p_tags->tag_map.size(); i++) | |
358 | if (tag_map.has_key(p_tags->tag_map.get_nth_key(i))) return true; | |
359 | return false; | |
360 | } | |
361 | ||
362 | bool TagCollection::greaterTags(const TagCollection *p_tags) const | |
363 | { | |
364 | if (!p_tags) | |
365 | FATAL_ERROR("NULL parameter: Asn::TagCollection::greaterTags()"); | |
366 | if (has_all) return !p_tags->isEmpty(); | |
367 | else if (p_tags->has_all) return !isEmpty(); | |
368 | else if (tag_map.empty() || p_tags->tag_map.empty()) return true; | |
369 | else return tag_map.get_nth_key(tag_map.size() - 1) < | |
370 | p_tags->tag_map.get_nth_key(0); | |
371 | } | |
372 | ||
373 | const Tag *TagCollection::getSmallestTag() const | |
374 | { | |
375 | if (has_all) return has_all; | |
376 | if (tag_map.empty()) FATAL_ERROR("TagCollection::getSmallestTag()"); | |
377 | return &tag_map.get_nth_key(0); | |
378 | } | |
379 | ||
380 | const Tag *TagCollection::getGreatestTag() const | |
381 | { | |
382 | if (has_all) return has_all; | |
383 | if (tag_map.empty()) FATAL_ERROR("TagCollection::getGreatestTag()"); | |
384 | return &tag_map.get_nth_key(tag_map.size() - 1); | |
385 | } | |
386 | ||
387 | void TagCollection::setExtensible() | |
388 | { | |
389 | if(is_extensible) | |
390 | error("Illegal use of extensibility notation (possible tag conflict)"); | |
391 | else is_extensible=true; | |
392 | } | |
393 | ||
394 | bool TagCollection::isEmpty() const | |
395 | { | |
396 | if (has_all || is_extensible) return false; | |
397 | else return tag_map.empty(); | |
398 | } | |
399 | ||
400 | void TagCollection::clear() | |
401 | { | |
402 | tag_map.clear(); | |
403 | has_all = NULL; | |
404 | is_extensible = false; | |
405 | } | |
406 | ||
407 | } // namespace Asn |