Commit | Line | Data |
---|---|---|
970ed795 EL |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // Copyright (c) 2000-2014 Ericsson Telecom AB | |
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 "Objid.hh" | |
9 | ||
10 | #include "../common/dbgnew.hh" | |
11 | #include <errno.h> | |
12 | #include <limits.h> | |
13 | #include "../common/static_check.h" | |
14 | #include "Integer.hh" | |
15 | ||
16 | static const size_t MIN_COMPONENTS = 2; | |
17 | ||
18 | struct OBJID::objid_struct { | |
19 | unsigned int ref_count; | |
20 | int n_components; ///< number of elements in \a components_ptr (min. 2) | |
21 | int overflow_idx; ///< index of the first overflow, or -1 | |
22 | objid_element components_ptr[MIN_COMPONENTS]; | |
23 | }; | |
24 | ||
25 | #define OBJID_FMT "%u" | |
26 | //#define OBJID_FMT "%lu" | |
27 | ||
28 | void OBJID::init_struct(int n_components) | |
29 | { | |
30 | if (n_components < 0) { | |
31 | val_ptr = NULL; | |
32 | TTCN_error("Initializing an objid value with a negative number of " | |
33 | "components."); | |
34 | } | |
35 | // TODO check n_components >= 2 | |
36 | val_ptr = (objid_struct*)Malloc(sizeof(objid_struct) | |
37 | + (n_components - MIN_COMPONENTS) * sizeof(objid_element)); | |
38 | val_ptr->ref_count = 1; | |
39 | val_ptr->n_components = n_components; | |
40 | val_ptr->overflow_idx = -1; | |
41 | } | |
42 | ||
43 | void OBJID::copy_value() | |
44 | { | |
45 | if (val_ptr != NULL && val_ptr->ref_count > 1) { | |
46 | objid_struct *old_ptr = val_ptr; | |
47 | old_ptr->ref_count--; | |
48 | init_struct(old_ptr->n_components); // val_ptr reallocated | |
49 | memcpy(val_ptr->components_ptr, old_ptr->components_ptr, | |
50 | old_ptr->n_components * sizeof(objid_element)); | |
51 | val_ptr->overflow_idx = old_ptr->overflow_idx; | |
52 | } | |
53 | } | |
54 | ||
55 | void OBJID::clean_up() | |
56 | { | |
57 | if (val_ptr != NULL) { | |
58 | if (val_ptr->ref_count > 1) val_ptr->ref_count--; | |
59 | else if (val_ptr->ref_count == 1) Free(val_ptr); | |
60 | else TTCN_error("Internal error: Invalid reference counter in an objid " | |
61 | "value."); | |
62 | val_ptr = NULL; | |
63 | } | |
64 | } | |
65 | ||
66 | OBJID::OBJID() | |
67 | { | |
68 | val_ptr = NULL; // unbound | |
69 | } | |
70 | ||
71 | OBJID::OBJID(int init_n_components, ...) | |
72 | { | |
73 | init_struct(init_n_components); | |
74 | va_list ap; | |
75 | va_start(ap, init_n_components); | |
76 | for (int i = 0; i < init_n_components; i++) { | |
77 | val_ptr->components_ptr[i] = va_arg(ap, objid_element); | |
78 | } | |
79 | va_end(ap); | |
80 | } | |
81 | ||
82 | ||
83 | OBJID::OBJID(int init_n_components, const objid_element *init_components) | |
84 | { | |
85 | init_struct(init_n_components); | |
86 | memcpy(val_ptr->components_ptr, init_components, init_n_components * | |
87 | sizeof(objid_element)); | |
88 | } | |
89 | ||
90 | OBJID::OBJID(const OBJID& other_value) | |
91 | : Base_Type(other_value) | |
92 | { | |
93 | if (other_value.val_ptr == NULL) | |
94 | TTCN_error("Copying an unbound objid value."); | |
95 | val_ptr = other_value.val_ptr; | |
96 | val_ptr->ref_count++; | |
97 | } | |
98 | ||
99 | OBJID::~OBJID() | |
100 | { | |
101 | clean_up(); | |
102 | } | |
103 | ||
104 | OBJID& OBJID::operator=(const OBJID& other_value) | |
105 | { | |
106 | if (other_value.val_ptr == NULL) | |
107 | TTCN_error("Assignment of an unbound objid value."); | |
108 | if (&other_value != this) { | |
109 | clean_up(); | |
110 | val_ptr = other_value.val_ptr; | |
111 | val_ptr->ref_count++; | |
112 | } | |
113 | return *this; | |
114 | } | |
115 | ||
116 | boolean OBJID::operator==(const OBJID& other_value) const | |
117 | { | |
118 | if (val_ptr == NULL) TTCN_error("The left operand of comparison is an " | |
119 | "unbound objid value."); | |
120 | if (other_value.val_ptr == NULL) TTCN_error("The right operand of comparison " | |
121 | "is an unbound objid value."); | |
122 | if (val_ptr->n_components != other_value.val_ptr->n_components) return FALSE; | |
123 | if (val_ptr->overflow_idx != other_value.val_ptr->overflow_idx) return FALSE; | |
124 | return !memcmp(val_ptr->components_ptr, | |
125 | other_value.val_ptr->components_ptr, | |
126 | val_ptr->n_components * sizeof(objid_element)); | |
127 | } | |
128 | ||
129 | OBJID::objid_element& OBJID::operator[](int index_value) | |
130 | { | |
131 | if (val_ptr == NULL) { | |
132 | if (index_value != 0) | |
133 | TTCN_error("Accessing a component of an unbound objid value."); | |
134 | init_struct(1); | |
135 | return val_ptr->components_ptr[0]; | |
136 | } else { | |
137 | if (index_value < 0) TTCN_error("Accessing an objid component using " | |
138 | "a negative index (%d).", index_value); | |
139 | int n_components = val_ptr->n_components; | |
140 | if (index_value > n_components) TTCN_error("Index overflow when accessing " | |
141 | "an objid component: the index is %d, but the value has only %d " | |
142 | "components.", index_value, n_components); | |
143 | else if (index_value == n_components) { | |
144 | if (val_ptr->ref_count == 1) { | |
145 | val_ptr = (objid_struct*) | |
146 | Realloc(val_ptr, sizeof(objid_struct) | |
147 | + n_components * sizeof(objid_element)); | |
148 | val_ptr->n_components++; | |
149 | } else { | |
150 | objid_struct *old_ptr = val_ptr; | |
151 | old_ptr->ref_count--; | |
152 | init_struct(n_components + 1); | |
153 | memcpy(val_ptr->components_ptr, old_ptr->components_ptr, | |
154 | n_components * sizeof(objid_element)); | |
155 | } | |
156 | } | |
157 | return val_ptr->components_ptr[index_value]; | |
158 | } | |
159 | } | |
160 | ||
161 | OBJID::objid_element OBJID::operator[](int index_value) const | |
162 | { | |
163 | if (val_ptr == NULL) | |
164 | TTCN_error("Accessing a component of an unbound objid value."); | |
165 | if (index_value < 0) | |
166 | TTCN_error("Accessing an objid component using a negative index (%d).", | |
167 | index_value); | |
168 | if (index_value >= val_ptr->n_components) TTCN_error("Index overflow when " | |
169 | "accessing an objid component: the index is %d, but the value has only %d " | |
170 | "components.", index_value, val_ptr->n_components); | |
171 | return val_ptr->components_ptr[index_value]; | |
172 | } | |
173 | ||
174 | int OBJID::size_of() const | |
175 | { | |
176 | if (val_ptr == NULL) | |
177 | TTCN_error("Getting the size of an unbound objid value."); | |
178 | return val_ptr->n_components; | |
179 | } | |
180 | ||
181 | OBJID::operator const objid_element*() const | |
182 | { | |
183 | if (val_ptr == NULL) | |
184 | TTCN_error("Casting an unbound objid value to const int*."); | |
185 | return val_ptr->components_ptr; | |
186 | } | |
187 | ||
188 | OBJID::objid_element OBJID::from_INTEGER(const INTEGER& p_int) | |
189 | { | |
190 | int_val_t i_val = p_int.get_val(); | |
191 | if (i_val.is_negative()) { | |
192 | TTCN_error("An OBJECT IDENTIFIER component cannot be negative"); | |
193 | } | |
194 | if (!i_val.is_native()) { | |
195 | TTCN_error("The value of an OBJECT IDENTIFIER component cannot exceed %u", | |
196 | INT_MAX); | |
197 | } | |
198 | return (OBJID::objid_element)i_val.get_val(); | |
199 | } | |
200 | ||
201 | void OBJID::log() const | |
202 | { | |
203 | if (val_ptr != NULL) { | |
204 | TTCN_Logger::log_event_str("objid { "); | |
205 | for (int i = 0; i < val_ptr->n_components; i++) { | |
206 | if (i == val_ptr->overflow_idx) { | |
207 | TTCN_Logger::log_event_str("overflow:"); | |
208 | } | |
209 | ||
210 | TTCN_Logger::log_event(OBJID_FMT " ", val_ptr->components_ptr[i]); | |
211 | } | |
212 | TTCN_Logger::log_char('}'); | |
213 | } else TTCN_Logger::log_event_unbound(); | |
214 | } | |
215 | ||
216 | void OBJID::set_param(Module_Param& param) { | |
217 | param.basic_check(Module_Param::BC_VALUE, "objid value"); | |
218 | if (param.get_type()!=Module_Param::MP_Objid) param.type_error("objid value"); | |
219 | if (sizeof(objid_element)!=sizeof(int)) TTCN_error("Internal error: OBJID::set_param()"); | |
220 | clean_up(); | |
221 | init_struct(param.get_string_size()); | |
222 | memcpy(val_ptr->components_ptr, param.get_string_data(), val_ptr->n_components * sizeof(objid_element)); | |
223 | } | |
224 | ||
225 | void OBJID::encode_text(Text_Buf& text_buf) const | |
226 | { | |
227 | if (val_ptr == NULL) | |
228 | TTCN_error("Text encoder: Encoding an unbound objid value."); | |
229 | text_buf.push_int(val_ptr->n_components); | |
230 | for (int i = 0; i < val_ptr->n_components; i++) | |
231 | text_buf.push_int(val_ptr->components_ptr[i]); | |
232 | } | |
233 | ||
234 | void OBJID::decode_text(Text_Buf& text_buf) | |
235 | { | |
236 | int n_components = text_buf.pull_int().get_val(); | |
237 | if (n_components < 0) TTCN_error("Text decoder: Negative number of " | |
238 | "components was received for an objid value."); | |
239 | clean_up(); | |
240 | init_struct(n_components); | |
241 | for (int i = 0; i < n_components; i++) | |
242 | val_ptr->components_ptr[i] = text_buf.pull_int().get_val(); | |
243 | } | |
244 | ||
245 | void OBJID::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, | |
246 | TTCN_EncDec::coding_t p_coding, ...) const | |
247 | { | |
248 | va_list pvar; | |
249 | va_start(pvar, p_coding); | |
250 | switch(p_coding) { | |
251 | case TTCN_EncDec::CT_BER: { | |
252 | TTCN_EncDec_ErrorContext ec("While BER-encoding type '%s': ", p_td.name); | |
253 | unsigned BER_coding=va_arg(pvar, unsigned); | |
254 | BER_encode_chk_coding(BER_coding); | |
255 | ASN_BER_TLV_t *tlv=BER_encode_TLV(p_td, BER_coding); | |
256 | tlv->put_in_buffer(p_buf); | |
257 | ASN_BER_TLV_t::destruct(tlv); | |
258 | break;} | |
259 | case TTCN_EncDec::CT_RAW: { | |
260 | TTCN_EncDec_ErrorContext ec("While RAW-encoding type '%s': ", p_td.name); | |
261 | TTCN_EncDec_ErrorContext::error_internal | |
262 | ("No RAW descriptor available for type '%s'.", p_td.name); | |
263 | break;} | |
264 | case TTCN_EncDec::CT_XER: { | |
265 | TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); | |
266 | unsigned XER_coding=va_arg(pvar, unsigned); | |
af710487 | 267 | XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0); |
268 | break;} | |
269 | case TTCN_EncDec::CT_JSON: { | |
270 | TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name); | |
271 | if(!p_td.json) | |
272 | TTCN_EncDec_ErrorContext::error_internal | |
273 | ("No JSON descriptor available for type '%s'.", p_td.name); | |
274 | JSON_Tokenizer tok(va_arg(pvar, int) != 0); | |
275 | JSON_encode(p_td, tok); | |
276 | p_buf.put_s(tok.get_buffer_length(), (const unsigned char*)tok.get_buffer()); | |
970ed795 EL |
277 | break;} |
278 | default: | |
279 | TTCN_error("Unknown coding method requested to encode type '%s'", | |
280 | p_td.name); | |
281 | } | |
282 | va_end(pvar); | |
283 | } | |
284 | ||
285 | void OBJID::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, | |
286 | TTCN_EncDec::coding_t p_coding, ...) | |
287 | { | |
288 | va_list pvar; | |
289 | va_start(pvar, p_coding); | |
290 | switch(p_coding) { | |
291 | case TTCN_EncDec::CT_BER: { | |
292 | TTCN_EncDec_ErrorContext ec("While BER-decoding type '%s': ", p_td.name); | |
293 | unsigned L_form=va_arg(pvar, unsigned); | |
294 | ASN_BER_TLV_t tlv; | |
295 | BER_decode_str2TLV(p_buf, tlv, L_form); | |
296 | BER_decode_TLV(p_td, tlv, L_form); | |
297 | if(tlv.isComplete) p_buf.increase_pos(tlv.get_len()); | |
298 | break;} | |
299 | case TTCN_EncDec::CT_RAW: { | |
300 | TTCN_EncDec_ErrorContext ec("While RAW-decoding type '%s': ", p_td.name); | |
301 | TTCN_EncDec_ErrorContext::error_internal | |
302 | ("No RAW descriptor available for type '%s'.", p_td.name); | |
303 | break;} | |
304 | case TTCN_EncDec::CT_XER: { | |
af710487 | 305 | TTCN_EncDec_ErrorContext ec("While XER-decoding type '%s': ", p_td.name); |
970ed795 EL |
306 | unsigned XER_coding=va_arg(pvar, unsigned); |
307 | XmlReaderWrap reader(p_buf); | |
308 | int success = reader.Read(); | |
309 | for (; success==1; success=reader.Read()) { | |
310 | int type = reader.NodeType(); | |
311 | if (type==XML_READER_TYPE_ELEMENT) | |
312 | break; | |
313 | } | |
af710487 | 314 | XER_decode(*p_td.xer, reader, XER_coding, 0); |
970ed795 EL |
315 | size_t bytes = reader.ByteConsumed(); |
316 | p_buf.set_pos(bytes); | |
317 | break;} | |
af710487 | 318 | case TTCN_EncDec::CT_JSON: { |
319 | TTCN_EncDec_ErrorContext ec("While JSON-decoding type '%s': ", p_td.name); | |
320 | if(!p_td.json) | |
321 | TTCN_EncDec_ErrorContext::error_internal | |
322 | ("No JSON descriptor available for type '%s'.", p_td.name); | |
323 | JSON_Tokenizer tok((const char*)p_buf.get_data(), p_buf.get_len()); | |
324 | if(JSON_decode(p_td, tok, false)<0) | |
325 | ec.error(TTCN_EncDec::ET_INCOMPL_MSG, | |
326 | "Can not decode type '%s', because invalid or incomplete" | |
327 | " message was received" | |
328 | , p_td.name); | |
329 | p_buf.set_pos(tok.get_buf_pos()); | |
330 | break;} | |
970ed795 EL |
331 | default: |
332 | TTCN_error("Unknown coding method requested to decode type '%s'", | |
333 | p_td.name); | |
334 | } | |
335 | va_end(pvar); | |
336 | } | |
337 | ||
338 | ASN_BER_TLV_t* | |
339 | OBJID::BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, | |
340 | unsigned p_coding) const | |
341 | { | |
342 | BER_chk_descr(p_td); | |
343 | ASN_BER_TLV_t *new_tlv=BER_encode_chk_bound(is_bound()); | |
344 | if(!new_tlv) { | |
345 | size_t V_len=0; | |
346 | switch(p_td.asnbasetype) { | |
347 | case TTCN_Typedescriptor_t::OBJID: | |
348 | if(val_ptr->n_components<2) | |
349 | TTCN_EncDec_ErrorContext::error_internal | |
350 | ("OBJID must have at least 2 components."); | |
351 | V_len=(min_needed_bits(val_ptr->components_ptr[0]*40 | |
352 | +val_ptr->components_ptr[1])+6)/7; | |
353 | for(int i=2; i<val_ptr->n_components; i++) | |
354 | V_len+=(min_needed_bits(val_ptr->components_ptr[i])+6)/7; | |
355 | break; | |
356 | case TTCN_Typedescriptor_t::ROID: | |
357 | for(int i=0; i<val_ptr->n_components; i++) | |
358 | V_len+=(min_needed_bits(val_ptr->components_ptr[i])+6)/7; | |
359 | break; | |
360 | default: | |
361 | TTCN_EncDec_ErrorContext::error_internal | |
362 | ("Missing/wrong basetype info for type '%s'.", p_td.name); | |
363 | } // switch | |
364 | new_tlv=ASN_BER_TLV_t::construct(V_len, NULL); | |
365 | unsigned char *Vptr=new_tlv->V.str.Vstr; | |
366 | for(int i=0; i<val_ptr->n_components; i++) { | |
367 | unsigned long ul; | |
368 | if(i==0 && p_td.asnbasetype==TTCN_Typedescriptor_t::OBJID) { | |
369 | ul=val_ptr->components_ptr[0]*40+val_ptr->components_ptr[1]; | |
370 | i++; | |
371 | } | |
372 | else ul=val_ptr->components_ptr[i]; | |
373 | size_t noo=(min_needed_bits(ul)+6)/7; | |
374 | for(size_t j=noo; j>0; j--) { | |
375 | Vptr[j-1]=(ul & 0x7F) | 0x80; | |
376 | ul>>=7; | |
377 | } | |
378 | Vptr[noo-1]&=0x7F; | |
379 | Vptr+=noo; | |
380 | } // for i | |
381 | } | |
382 | new_tlv=ASN_BER_V2TLV(new_tlv, p_td, p_coding); | |
383 | return new_tlv; | |
384 | } | |
385 | ||
386 | ||
387 | boolean OBJID::BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, | |
388 | const ASN_BER_TLV_t& p_tlv, | |
389 | unsigned L_form) | |
390 | { | |
391 | clean_up(); | |
392 | BER_chk_descr(p_td); | |
393 | ASN_BER_TLV_t stripped_tlv; | |
394 | BER_decode_strip_tags(*p_td.ber, p_tlv, L_form, stripped_tlv); | |
395 | TTCN_EncDec_ErrorContext ec("While decoding OBJID type: "); | |
396 | stripped_tlv.chk_constructed_flag(FALSE); | |
397 | if (!stripped_tlv.isComplete) return FALSE; | |
398 | if (!stripped_tlv.V_tlvs_selected && stripped_tlv.V.str.Vlen==0) { | |
399 | ec.error(TTCN_EncDec::ET_INVAL_MSG, "Length of V-part is 0."); | |
400 | return FALSE; | |
401 | } | |
402 | switch(p_td.asnbasetype) { | |
403 | case TTCN_Typedescriptor_t::OBJID: | |
404 | case TTCN_Typedescriptor_t::ROID: | |
405 | break; | |
406 | default: | |
407 | TTCN_EncDec_ErrorContext::error_internal | |
408 | ("Missing/wrong basetype info for type '%s'.", p_td.name); | |
409 | } // switch | |
410 | unsigned char *Vptr=stripped_tlv.V.str.Vstr; | |
411 | boolean eoc=FALSE; // end-of-component | |
412 | int i=0; | |
413 | unsigned long long ull=0; | |
414 | STATIC_ASSERT(sizeof(ull) > sizeof(objid_element)); | |
415 | ||
416 | boolean err_repr=FALSE; | |
417 | while (Vptr < stripped_tlv.V.str.Vstr + stripped_tlv.V.str.Vlen) { | |
418 | ull |= *Vptr & 0x7F; | |
419 | if ((*Vptr & 0x80) && err_repr==FALSE) { // not-eoc | |
420 | if (ull & unsigned_llong_7msb) { | |
421 | ec.error(TTCN_EncDec::ET_REPR, | |
422 | "Value of the #%d component is too big.", i+1); | |
423 | err_repr=TRUE; | |
424 | } | |
425 | ull<<=7; | |
426 | eoc=FALSE; | |
427 | } | |
428 | else { // eoc | |
429 | if (i==0 && p_td.asnbasetype==TTCN_Typedescriptor_t::OBJID) { | |
430 | // first two component of objid | |
431 | switch(ull/40ul) { | |
432 | case 0: | |
433 | (*this)[0]=0; break; | |
434 | case 1: | |
435 | (*this)[0]=1; break; | |
436 | default: | |
437 | (*this)[0]=2; break; | |
438 | } | |
439 | (*this)[1]=(int)(ull-40*(*this)[0]); | |
440 | i=1; | |
441 | } | |
442 | else { // other components (>2) | |
443 | // objid_element is UINT/ULONG; the result of the cast is Uxxx_MAX. | |
444 | // It's computed at compile time. | |
445 | if(ull > ((objid_element)-1)) { | |
446 | if(err_repr==FALSE) | |
447 | ec.error(TTCN_EncDec::ET_REPR, | |
448 | "Value of the #%d component is too big.", i+1); | |
449 | (*this)[i]=(objid_element)-1; | |
450 | // remember the first overflow | |
451 | if (val_ptr->overflow_idx < 0) val_ptr->overflow_idx = i; | |
452 | } // if ul too big | |
453 | else | |
454 | (*this)[i]=(objid_element)ull; | |
455 | } | |
456 | err_repr=FALSE; | |
457 | ull=0; | |
458 | eoc=TRUE; | |
459 | i++; | |
460 | } // eoc | |
461 | Vptr++; | |
462 | } // while Vptr... | |
463 | if(eoc==FALSE) | |
464 | ec.error(TTCN_EncDec::ET_INVAL_MSG, | |
465 | "The last component (#%d) is unterminated.", i+1); | |
466 | return TRUE; | |
467 | } | |
468 | ||
469 | ||
470 | int OBJID::XER_encode(const XERdescriptor_t& p_td, | |
af710487 | 471 | TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const |
970ed795 EL |
472 | { |
473 | if(!is_bound()) { | |
474 | TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND, | |
475 | "Encoding an unbound object identifier value."); | |
476 | } | |
477 | int encoded_length=(int)p_buf.get_len(); | |
478 | ||
479 | flavor |= SIMPLE_TYPE; | |
480 | flavor &= ~XER_RECOF; // object identifier doesn't care | |
481 | begin_xml(p_td, p_buf, flavor, indent, false); | |
482 | ||
483 | static char str_buf[64]; | |
484 | for (int i = 0; i < val_ptr->n_components; ++i ) { | |
485 | // output dot before the second and subsequent components | |
486 | if (i > 0) p_buf.put_c('.'); | |
487 | // output current component | |
488 | int str_len = snprintf(str_buf, sizeof(str_buf), OBJID_FMT, | |
489 | val_ptr->components_ptr[i]); | |
490 | if (str_len < 0 || str_len >= (int)sizeof(str_buf)) { | |
491 | TTCN_error("Internal error: system call snprintf() returned " | |
492 | "unexpected status code %d when converting value " OBJID_FMT, | |
493 | str_len, val_ptr->components_ptr[i]); | |
494 | } | |
495 | else p_buf.put_s(str_len, (const unsigned char*)str_buf); | |
496 | } | |
497 | ||
498 | end_xml(p_td, p_buf, flavor, indent, false); | |
499 | ||
500 | return (int)p_buf.get_len() - encoded_length; | |
501 | } | |
502 | ||
af710487 | 503 | void OBJID::from_string(char* p_str) |
504 | { | |
505 | // Count dots to find number of components. (1 dot = 2 components, etc.) | |
506 | unsigned comps = 1; | |
507 | const char *p; | |
508 | for (p = p_str; *p != 0; ++p) { | |
509 | if (*p == '.') ++comps; | |
510 | } | |
511 | // p now points at the end of the string. If it was empty, then there were | |
512 | // no components; compensate the fact that we started at 1. | |
513 | init_struct((p != p_str) ? comps : 0); | |
514 | ||
515 | char *beg, *end = 0; | |
516 | comps = 0; | |
517 | for (beg = p_str; beg < p; ++beg) { | |
518 | errno = 0; | |
519 | long ret = strtol(beg, &end, 10); | |
520 | if (errno) break; | |
521 | ||
522 | // TODO check value for too big ? | |
523 | (*this)[comps++] = ret; | |
524 | beg = end; // move to the dot; will move past it when incremented | |
525 | } | |
526 | } | |
527 | ||
970ed795 | 528 | int OBJID::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, |
af710487 | 529 | unsigned int flavor, embed_values_dec_struct_t*) |
970ed795 EL |
530 | { |
531 | int exer = is_exer(flavor); | |
532 | int success = reader.Ok(), depth = -1; | |
533 | for (; success == 1; success = reader.Read()) { | |
534 | int type = reader.NodeType(); | |
535 | if (XML_READER_TYPE_ELEMENT == type) { | |
536 | verify_name(reader, p_td, exer); | |
537 | depth = reader.Depth(); | |
538 | break; | |
539 | } | |
540 | } | |
541 | if (success == 1) { | |
542 | char * val = (char *)reader.ReadString(); // We own this (writable) string | |
543 | if (0 == val) { | |
544 | TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG, "Bogus object identifier"); | |
545 | return 0; | |
546 | } | |
af710487 | 547 | |
548 | from_string(val); | |
970ed795 EL |
549 | |
550 | xmlFree(val); | |
551 | } | |
552 | for (success = reader.Read(); success == 1; success = reader.Read()) { | |
553 | int type = reader.NodeType(); | |
554 | if (XML_READER_TYPE_END_ELEMENT == type) { | |
555 | verify_end(reader, p_td, depth, exer); | |
556 | reader.Read(); | |
557 | break; | |
558 | } | |
559 | } | |
560 | return 1; // decode successful | |
561 | } | |
562 | ||
af710487 | 563 | int OBJID::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok) const |
564 | { | |
565 | if (!is_bound()) { | |
566 | TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND, | |
567 | "Encoding an unbound object identifier value."); | |
568 | return -1; | |
569 | } | |
570 | ||
571 | char* objid_str = mcopystrn("\"", 1); | |
572 | for (int i = 0; i < val_ptr->n_components; ++i) { | |
573 | objid_str = mputprintf(objid_str, "%s" OBJID_FMT, (i > 0 ? "." : ""), val_ptr->components_ptr[i]); | |
574 | } | |
575 | objid_str = mputstrn(objid_str, "\"", 1); | |
576 | int enc_len = p_tok.put_next_token(JSON_TOKEN_STRING, objid_str); | |
577 | Free(objid_str); | |
578 | return enc_len; | |
579 | } | |
580 | ||
581 | int OBJID::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent) | |
582 | { | |
583 | json_token_t token = JSON_TOKEN_NONE; | |
584 | char* value = 0; | |
585 | size_t value_len = 0; | |
586 | boolean error = false; | |
587 | int dec_len = 0; | |
588 | boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length(); | |
589 | if (use_default) { | |
590 | // No JSON data in the buffer -> use default value | |
591 | value = (char*)p_td.json->default_value; | |
592 | value_len = strlen(value); | |
593 | } else { | |
594 | dec_len = p_tok.get_next_token(&token, &value, &value_len); | |
595 | } | |
596 | if (JSON_TOKEN_ERROR == token) { | |
597 | JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, ""); | |
598 | return JSON_ERROR_FATAL; | |
599 | } | |
600 | else if (JSON_TOKEN_STRING == token || use_default) { | |
601 | if (use_default || (value_len > 2 && value[0] == '\"' && value[value_len - 1] == '\"')) { | |
602 | if (!use_default) { | |
603 | // The default value doesn't have quotes around it | |
604 | value_len -= 2; | |
605 | ++value; | |
606 | } | |
607 | // need a null-terminated string | |
608 | char* value2 = mcopystrn(value, value_len); | |
609 | from_string(value2); | |
610 | Free(value2); | |
611 | } | |
612 | } | |
613 | else { | |
614 | return JSON_ERROR_INVALID_TOKEN; | |
615 | } | |
616 | ||
617 | if (error) { | |
618 | JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_FORMAT_ERROR, "string", "object identifier"); | |
619 | if (p_silent) { | |
620 | clean_up(); | |
621 | } | |
622 | return JSON_ERROR_FATAL; | |
623 | } | |
624 | return dec_len; | |
625 | } | |
970ed795 EL |
626 | |
627 | void OBJID_template::clean_up() | |
628 | { | |
629 | if (template_selection == VALUE_LIST || | |
630 | template_selection == COMPLEMENTED_LIST) delete [] value_list.list_value; | |
631 | template_selection = UNINITIALIZED_TEMPLATE; | |
632 | } | |
633 | ||
634 | void OBJID_template::copy_template(const OBJID_template& other_value) | |
635 | { | |
636 | switch (other_value.template_selection) { | |
637 | case SPECIFIC_VALUE: | |
638 | single_value = other_value.single_value; | |
639 | break; | |
640 | case OMIT_VALUE: | |
641 | case ANY_VALUE: | |
642 | case ANY_OR_OMIT: | |
643 | break; | |
644 | case VALUE_LIST: | |
645 | case COMPLEMENTED_LIST: | |
646 | value_list.n_values = other_value.value_list.n_values; | |
647 | value_list.list_value = new OBJID_template[value_list.n_values]; | |
648 | for (unsigned int i = 0; i < value_list.n_values; i++) | |
649 | value_list.list_value[i].copy_template( | |
650 | other_value.value_list.list_value[i]); | |
651 | break; | |
652 | default: | |
653 | TTCN_error("Copying an uninitialized/unsupported objid template."); | |
654 | } | |
655 | set_selection(other_value); | |
656 | } | |
657 | ||
658 | OBJID_template::OBJID_template() | |
659 | { | |
660 | ||
661 | } | |
662 | ||
663 | OBJID_template::OBJID_template(template_sel other_value) | |
664 | : Base_Template(other_value) | |
665 | { | |
666 | check_single_selection(other_value); | |
667 | } | |
668 | ||
669 | OBJID_template::OBJID_template(const OBJID& other_value) | |
670 | : Base_Template(SPECIFIC_VALUE), single_value(other_value) | |
671 | { | |
672 | ||
673 | } | |
674 | ||
675 | OBJID_template::OBJID_template(const OPTIONAL<OBJID>& other_value) | |
676 | { | |
677 | switch (other_value.get_selection()) { | |
678 | case OPTIONAL_PRESENT: | |
679 | set_selection(SPECIFIC_VALUE); | |
680 | single_value = (const OBJID&)other_value; | |
681 | break; | |
682 | case OPTIONAL_OMIT: | |
683 | set_selection(OMIT_VALUE); | |
684 | break; | |
685 | default: | |
686 | TTCN_error("Creating an objid template from an unbound optional field."); | |
687 | } | |
688 | } | |
689 | ||
690 | OBJID_template::OBJID_template(const OBJID_template& other_value) | |
691 | : Base_Template() | |
692 | { | |
693 | copy_template(other_value); | |
694 | } | |
695 | ||
696 | OBJID_template::~OBJID_template() | |
697 | { | |
698 | clean_up(); | |
699 | } | |
700 | ||
701 | OBJID_template& OBJID_template::operator=(template_sel other_value) | |
702 | { | |
703 | check_single_selection(other_value); | |
704 | clean_up(); | |
705 | set_selection(other_value); | |
706 | return *this; | |
707 | } | |
708 | ||
709 | OBJID_template& OBJID_template::operator=(const OBJID& other_value) | |
710 | { | |
711 | if (!other_value.is_bound()) | |
712 | TTCN_error("Assignment of an unbound objid value to a template."); | |
713 | clean_up(); | |
714 | set_selection(SPECIFIC_VALUE); | |
715 | single_value = other_value; | |
716 | return *this; | |
717 | } | |
718 | ||
719 | OBJID_template& OBJID_template::operator=(const OPTIONAL<OBJID>& other_value) | |
720 | { | |
721 | clean_up(); | |
722 | switch (other_value.get_selection()) { | |
723 | case OPTIONAL_PRESENT: | |
724 | set_selection(SPECIFIC_VALUE); | |
725 | single_value = (const OBJID&)other_value; | |
726 | break; | |
727 | case OPTIONAL_OMIT: | |
728 | set_selection(OMIT_VALUE); | |
729 | break; | |
730 | default: | |
731 | TTCN_error("Assignment of an unbound optional field to an objid template."); | |
732 | } | |
733 | return *this; | |
734 | } | |
735 | ||
736 | OBJID_template& OBJID_template::operator=(const OBJID_template& other_value) | |
737 | { | |
738 | if (&other_value != this) { | |
739 | clean_up(); | |
740 | copy_template(other_value); | |
741 | } | |
742 | return *this; | |
743 | } | |
744 | ||
745 | boolean OBJID_template::match(const OBJID& other_value) const | |
746 | { | |
747 | if (!other_value.is_bound()) return FALSE; | |
748 | switch (template_selection) { | |
749 | case SPECIFIC_VALUE: | |
750 | return single_value == other_value; | |
751 | case OMIT_VALUE: | |
752 | return FALSE; | |
753 | case ANY_VALUE: | |
754 | case ANY_OR_OMIT: | |
755 | return TRUE; | |
756 | case VALUE_LIST: | |
757 | case COMPLEMENTED_LIST: | |
758 | for (unsigned int i = 0; i < value_list.n_values; i++) | |
759 | if (value_list.list_value[i].match(other_value)) | |
760 | return template_selection == VALUE_LIST; | |
761 | return template_selection == COMPLEMENTED_LIST; | |
762 | default: | |
763 | TTCN_error("Matching with an uninitialized/unsupported objid template."); | |
764 | } | |
765 | return FALSE; | |
766 | } | |
767 | ||
768 | const OBJID& OBJID_template::valueof() const | |
769 | { | |
770 | if (template_selection != SPECIFIC_VALUE || is_ifpresent) | |
771 | TTCN_error("Performing a valueof " | |
772 | "or send operation on a non-specific objid template."); | |
773 | return single_value; | |
774 | } | |
775 | ||
776 | int OBJID_template::size_of() const | |
777 | { | |
778 | switch (template_selection) | |
779 | { | |
780 | case SPECIFIC_VALUE: | |
781 | return single_value.size_of(); | |
782 | case OMIT_VALUE: | |
783 | TTCN_error("Performing sizeof() operation on an objid template " | |
784 | "containing omit value."); | |
785 | case ANY_VALUE: | |
786 | case ANY_OR_OMIT: | |
787 | TTCN_error("Performing sizeof() operation on a */? objid template."); | |
788 | case VALUE_LIST: | |
789 | { | |
790 | if (value_list.n_values<1) | |
791 | TTCN_error("Internal error: " | |
792 | "Performing sizeof() operation on an objid template " | |
793 | "containing an empty list."); | |
794 | int item_size = value_list.list_value[0].size_of(); | |
795 | for (unsigned int i = 1; i < value_list.n_values; i++) { | |
796 | if (value_list.list_value[i].size_of()!=item_size) | |
797 | TTCN_error("Performing sizeof() operation on an objid template " | |
798 | "containing a value list with different sizes."); | |
799 | } | |
800 | return item_size; | |
801 | } | |
802 | case COMPLEMENTED_LIST: | |
803 | TTCN_error("Performing sizeof() operation on an objid template " | |
804 | "containing complemented list."); | |
805 | default: | |
806 | TTCN_error("Performing sizeof() operation on an " | |
807 | "uninitialized/unsupported objid template."); | |
808 | } | |
809 | return 0; | |
810 | } | |
811 | ||
812 | void OBJID_template::set_type(template_sel template_type, | |
813 | unsigned int list_length) | |
814 | { | |
815 | if (template_type != VALUE_LIST && template_type != COMPLEMENTED_LIST) | |
816 | TTCN_error("Setting an invalid list type for an objid template."); | |
817 | clean_up(); | |
818 | set_selection(template_type); | |
819 | value_list.n_values = list_length; | |
820 | value_list.list_value = new OBJID_template[list_length]; | |
821 | } | |
822 | ||
823 | OBJID_template& OBJID_template::list_item(unsigned int list_index) | |
824 | { | |
825 | if (template_selection != VALUE_LIST && | |
826 | template_selection != COMPLEMENTED_LIST) | |
827 | TTCN_error("Accessing a list element of a non-list objid template."); | |
828 | if (list_index >= value_list.n_values) | |
829 | TTCN_error("Index overflow in an objid value list template."); | |
830 | return value_list.list_value[list_index]; | |
831 | } | |
832 | ||
833 | void OBJID_template::log() const | |
834 | { | |
835 | switch (template_selection) { | |
836 | case SPECIFIC_VALUE: | |
837 | single_value.log(); | |
838 | break; | |
839 | case COMPLEMENTED_LIST: | |
840 | TTCN_Logger::log_event_str("complement "); | |
841 | // no break | |
842 | case VALUE_LIST: | |
843 | TTCN_Logger::log_char('('); | |
844 | for(unsigned int i = 0; i < value_list.n_values; i++) { | |
845 | if (i > 0) TTCN_Logger::log_event_str(", "); | |
846 | value_list.list_value[i].log(); | |
847 | } | |
848 | TTCN_Logger::log_char(')'); | |
849 | break; | |
850 | default: | |
851 | log_generic(); | |
852 | break; | |
853 | } | |
854 | log_ifpresent(); | |
855 | } | |
856 | ||
857 | void OBJID_template::log_match(const OBJID& match_value) const | |
858 | { | |
859 | if (TTCN_Logger::VERBOSITY_COMPACT == TTCN_Logger::get_matching_verbosity() | |
860 | && TTCN_Logger::get_logmatch_buffer_len() != 0) { | |
861 | TTCN_Logger::print_logmatch_buffer(); | |
862 | TTCN_Logger::log_event_str(" := "); | |
863 | } | |
864 | match_value.log(); | |
865 | TTCN_Logger::log_event_str(" with "); | |
866 | log(); | |
867 | if (match(match_value)) TTCN_Logger::log_event_str(" matched"); | |
868 | else TTCN_Logger::log_event_str(" unmatched"); | |
869 | } | |
870 | ||
871 | void OBJID_template::set_param(Module_Param& param) { | |
872 | param.basic_check(Module_Param::BC_TEMPLATE, "objid template"); | |
873 | switch (param.get_type()) { | |
874 | case Module_Param::MP_Omit: | |
875 | *this = OMIT_VALUE; | |
876 | break; | |
877 | case Module_Param::MP_Any: | |
878 | *this = ANY_VALUE; | |
879 | break; | |
880 | case Module_Param::MP_AnyOrNone: | |
881 | *this = ANY_OR_OMIT; | |
882 | break; | |
883 | case Module_Param::MP_List_Template: | |
884 | case Module_Param::MP_ComplementList_Template: | |
885 | set_type(param.get_type()==Module_Param::MP_List_Template ? VALUE_LIST : COMPLEMENTED_LIST, param.get_size()); | |
886 | for (size_t i=0; i<param.get_size(); i++) { | |
887 | list_item(i).set_param(*param.get_elem(i)); | |
888 | } | |
889 | break; | |
890 | case Module_Param::MP_Objid: | |
891 | if (sizeof(OBJID::objid_element)!=sizeof(int)) TTCN_error("Internal error: OBJID_template::set_param()"); | |
892 | *this = OBJID(param.get_string_size(), (OBJID::objid_element*)param.get_string_data()); | |
893 | break; | |
894 | //case Module_Param::MP_Objid_Template: | |
895 | // TODO | |
896 | //break; | |
897 | default: | |
898 | param.type_error("objid template"); | |
899 | } | |
900 | is_ifpresent = param.get_ifpresent(); | |
901 | } | |
902 | ||
903 | void OBJID_template::encode_text(Text_Buf& text_buf) const | |
904 | { | |
905 | encode_text_base(text_buf); | |
906 | switch (template_selection) { | |
907 | case OMIT_VALUE: | |
908 | case ANY_VALUE: | |
909 | case ANY_OR_OMIT: | |
910 | break; | |
911 | case SPECIFIC_VALUE: | |
912 | single_value.encode_text(text_buf); | |
913 | break; | |
914 | case VALUE_LIST: | |
915 | case COMPLEMENTED_LIST: | |
916 | text_buf.push_int(value_list.n_values); | |
917 | for (unsigned int i = 0; i < value_list.n_values; i++) | |
918 | value_list.list_value[i].encode_text(text_buf); | |
919 | break; | |
920 | default: | |
921 | TTCN_error("Text encoder: Encoding an undefined/unsupported objid " | |
922 | "template."); | |
923 | } | |
924 | } | |
925 | ||
926 | void OBJID_template::decode_text(Text_Buf& text_buf) | |
927 | { | |
928 | clean_up(); | |
929 | decode_text_base(text_buf); | |
930 | switch (template_selection) { | |
931 | case OMIT_VALUE: | |
932 | case ANY_VALUE: | |
933 | case ANY_OR_OMIT: | |
934 | break; | |
935 | case SPECIFIC_VALUE: | |
936 | single_value.decode_text(text_buf); | |
937 | break; | |
938 | case VALUE_LIST: | |
939 | case COMPLEMENTED_LIST: | |
940 | value_list.n_values = text_buf.pull_int().get_val(); | |
941 | value_list.list_value = new OBJID_template[value_list.n_values]; | |
942 | for (unsigned int i = 0; i < value_list.n_values; i++) | |
943 | value_list.list_value[i].decode_text(text_buf); | |
944 | break; | |
945 | default: | |
946 | TTCN_error("Text decoder: An unknown/unsupported selection was " | |
947 | "received for an objid template."); | |
948 | } | |
949 | } | |
950 | ||
951 | boolean OBJID_template::is_present() const | |
952 | { | |
953 | if (template_selection==UNINITIALIZED_TEMPLATE) return FALSE; | |
954 | return !match_omit(); | |
955 | } | |
956 | ||
957 | boolean OBJID_template::match_omit() const | |
958 | { | |
959 | if (is_ifpresent) return TRUE; | |
960 | switch (template_selection) { | |
961 | case OMIT_VALUE: | |
962 | case ANY_OR_OMIT: | |
963 | return TRUE; | |
964 | case VALUE_LIST: | |
965 | case COMPLEMENTED_LIST: | |
966 | for (unsigned int i=0; i<value_list.n_values; i++) | |
967 | if (value_list.list_value[i].match_omit()) | |
968 | return template_selection==VALUE_LIST; | |
969 | return template_selection==COMPLEMENTED_LIST; | |
970 | default: | |
971 | return FALSE; | |
972 | } | |
973 | return FALSE; | |
974 | } | |
975 | ||
976 | #ifndef TITAN_RUNTIME_2 | |
977 | void OBJID_template::check_restriction(template_res t_res, const char* t_name) const | |
978 | { | |
979 | if (template_selection==UNINITIALIZED_TEMPLATE) return; | |
980 | switch ((t_name&&(t_res==TR_VALUE))?TR_OMIT:t_res) { | |
981 | case TR_VALUE: | |
982 | if (!is_ifpresent && template_selection==SPECIFIC_VALUE) return; | |
983 | break; | |
984 | case TR_OMIT: | |
985 | if (!is_ifpresent && (template_selection==OMIT_VALUE || | |
986 | template_selection==SPECIFIC_VALUE)) return; | |
987 | break; | |
988 | case TR_PRESENT: | |
989 | if (!match_omit()) return; | |
990 | break; | |
991 | default: | |
992 | return; | |
993 | } | |
994 | TTCN_error("Restriction `%s' on template of type %s violated.", | |
995 | get_res_name(t_res), t_name ? t_name : "objid"); | |
996 | } | |
997 | #endif |