1 /* $Id: blocktype.cpp 569649 2018-08-27 14:47:05Z gouriano $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Eugene Vasilchenko
27 *
28 * File Description:
29 * Type description for compound types: SET, SEQUENCE and CHOICE
30 */
31
32 #include <ncbi_pch.hpp>
33 #include "exceptions.hpp"
34 #include "blocktype.hpp"
35 #include "unitype.hpp"
36 #include "reftype.hpp"
37 #include "statictype.hpp"
38 #include <serial/impl/autoptrinfo.hpp>
39 #include "value.hpp"
40 #include "classstr.hpp"
41 #include "module.hpp"
42 #include "srcutil.hpp"
43 #include <serial/impl/classinfo.hpp>
44 #include <typeinfo>
45 #include "aliasstr.hpp"
46
47 BEGIN_NCBI_SCOPE
48
49 class CAnyTypeClassInfo : public CClassTypeInfo
50 {
51 public:
CAnyTypeClassInfo(const string & name,size_t count)52 CAnyTypeClassInfo(const string& name, size_t count)
53 : CClassTypeInfo(sizeof(AnyType) * count, name,
54 TObjectPtr(0), &CreateAnyTypeClass,
55 typeid(bool), &GetAnyTypeClassId)
56 {
57 }
58
GetAnyTypePtr(size_t index) const59 const AnyType* GetAnyTypePtr(size_t index) const
60 {
61 return &static_cast<AnyType*>(0)[index];
62 }
GetSetFlagPtr(size_t index)63 const bool* GetSetFlagPtr(size_t index)
64 {
65 return &GetAnyTypePtr(index)->booleanValue;
66 }
67
68 protected:
CreateAnyTypeClass(TTypeInfo objectType,CObjectMemoryPool *)69 static TObjectPtr CreateAnyTypeClass(TTypeInfo objectType,
70 CObjectMemoryPool* /*memoryPool*/)
71 {
72 size_t size = objectType->GetSize();
73 TObjectPtr obj = new char[size];
74 memset(obj, 0, size);
75 return obj;
76 }
GetAnyTypeClassId(TConstObjectPtr)77 static const type_info* GetAnyTypeClassId(TConstObjectPtr /*objectPtr*/)
78 {
79 return 0;
80 }
81 };
82
AddMember(const AutoPtr<CDataMember> & member)83 void CDataMemberContainerType::AddMember(const AutoPtr<CDataMember>& member)
84 {
85 m_Members.push_back(member);
86 }
87
PrintASN(CNcbiOstream & out,int indent) const88 void CDataMemberContainerType::PrintASN(CNcbiOstream& out, int indent) const
89 {
90 PrintASNTag(out);
91 out << GetASNKeyword() << " {";
92 ++indent;
93 ITERATE ( TMembers, i, m_Members ) {
94 PrintASNNewLine(out, indent);
95 const CDataMember& member = **i;
96 TMembers::const_iterator next = i;
97 bool last = ++next == m_Members.end();
98 member.PrintASN(out, indent, last);
99 }
100 --indent;
101 PrintASNNewLine(out, indent);
102 m_LastComments.PrintASN(out, indent, CComments::eMultiline);
103 out << "}";
104 }
105
PrintSpecDumpExtra(CNcbiOstream & out,int indent) const106 void CDataMemberContainerType::PrintSpecDumpExtra(CNcbiOstream& out, int indent) const
107 {
108 bool isAttlist = GetDataMember() && GetDataMember()->Attlist();
109 if (!GetParentType() || !isAttlist) {
110 ++indent;
111 }
112 ITERATE ( TMembers, i, m_Members ) {
113 i->get()->PrintSpecDump(out, indent, isAttlist ? "A" : "F");
114 }
115 m_LastComments.PrintASN(out, indent, CComments::eNoEOL);
116 }
117
PrintJSONSchema(CNcbiOstream & out,int indent,list<string> & required,bool contents_only) const118 void CDataMemberContainerType::PrintJSONSchema(CNcbiOstream& out, int indent, list<string>& required, bool contents_only) const
119 {
120 const CDataMember* data = GetDataMember();
121 bool hasNotag = data && data->Notag();
122 list<string> this_req;
123 list<string>& req = (hasNotag || contents_only) ? required : this_req;
124 bool hasAttlist = find_if(m_Members.begin(), m_Members.end(),
125 [](const TMembers::value_type& e) { return e->Attlist();}) != m_Members.end();
126 bool first = true;
127
128 if (!contents_only && m_Members.size()==1 &&
129 (m_Members.front()->GetType()->IsContainer() || m_Members.front()->GetType()->IsUniSeq())) {
130 m_Members.front()->PrintJSONSchema(out, indent, required);
131 return;
132 }
133
134 #if 0
135 // allOf is kind of... wrong...
136 // it is impossible to restrict additionalProperties
137 // so, instance validation either fails or allows undefined elements
138 // I do not know...
139 // I leave this code for future, in a hope that JSON schema will be improved.
140
141 bool hasUnnamedContainer = find_if(m_Members.begin(), m_Members.end(),
142 [](const TMembers::value_type& e) { return e->Notag() && e->GetType()->IsContainer();}) != m_Members.end();
143 if (hasUnnamedContainer) {
144 first = true;
145 PrintASNNewLine(out, indent++) << "\"definitions\": {";
146 ITERATE ( TMembers, i, m_Members ) {
147 const CDataMember& member = **i;
148 if (member.Notag() && member.GetType()->IsContainer()) {
149 if (!first) {
150 out << ",";
151 } else {
152 first = false;
153 }
154 PrintASNNewLine(out, indent++) << "\"" << "$" << member.GetName() << "\": {";
155 member.PrintJSONSchema(out, indent, req, true);
156 PrintASNNewLine(out, --indent) << "}";
157 }
158 }
159 PrintASNNewLine(out, --indent) << "},";
160 PrintASNNewLine(out, indent++) << "\"allOf\": [";
161 first = true;
162 ITERATE ( TMembers, i, m_Members ) {
163 const CDataMember& member = **i;
164 if (member.Notag() && member.GetType()->IsContainer()) {
165 if (!first) {
166 out << ",";
167 } else {
168 first = false;
169 }
170 PrintASNNewLine(out, indent) << "{\"$ref\": \"#/definitions/" << GetMemberName() << "/definitions/$" << member.GetName() << "\"}";
171 }
172 }
173 out << ",";
174 PrintASNNewLine(out, indent++) << "{";
175 }
176 #endif
177
178 if (!contents_only) {
179 PrintASNNewLine(out, indent) << "\"type\": \"object\",";
180 PrintASNNewLine(out, indent++) << "\"properties\": {";
181 }
182
183 first = true;
184 ITERATE ( TMembers, i, m_Members ) {
185 const CDataMember& member = **i;
186 if (hasAttlist && member.Notag() && dynamic_cast<const CNullDataType*>(member.GetType()) != nullptr) {
187 // special case: null with attributes
188 continue;
189 }
190 #if 0
191 if (member.Notag() && member.GetType()->IsContainer()) {
192 continue;
193 }
194 #endif
195 if (!first) {
196 out << ",";
197 } else {
198 first = false;
199 }
200 if (member.Attlist()) {
201 member.PrintJSONSchema(out, indent, req, true);
202 }
203 else if (member.Notag()) {
204 if (member.GetType()->IsContainer()) {
205 member.PrintJSONSchema(out, indent, req, true);
206 } else {
207 PrintASNNewLine(out, indent++) << "\"" << "#" << member.GetName() << "\": {";
208 member.PrintJSONSchema(out, indent, req);
209 PrintASNNewLine(out, --indent) << "}";
210 }
211 }
212 else { //if (!member.Notag() && !member.Attlist()) {
213 PrintASNNewLine(out, indent++) << "\"" << member.GetName() << "\": {";
214 member.PrintJSONSchema(out, indent, req);
215 PrintASNNewLine(out, --indent) << "}";
216 }
217 }
218
219 if (!contents_only) {
220 PrintASNNewLine(out, --indent) << "}";
221 if (!req.empty()) {
222 out << ',';
223 PrintASNNewLine(out, indent) << "\"required\": [";
224 transform(req.begin(), req.end(), Dt_ostream_iterator<string>(out, ", "),
225 [](const string& e) {
226 return string("\"").append(e).append("\"");
227 });
228 req.clear();
229 out << "]";
230 }
231 out << ",";
232 PrintASNNewLine(out, indent) << "\"additionalProperties\": false";
233 }
234
235 #if 0
236 if (hasUnnamedContainer) {
237 PrintASNNewLine(out, --indent) << "}";
238 PrintASNNewLine(out, --indent) << "]";
239 }
240 #endif
241 if (data && !data->Notag() && !data->Optional() && !data->Attlist()) {
242 required.push_back(data->GetName());
243 }
244 }
245
246 // XML schema generator submitted by
247 // Marc Dumontier, Blueprint initiative, dumontier@mshri.on.ca
248 // modified by Andrei Gourianov, gouriano@ncbi
PrintXMLSchema(CNcbiOstream & out,int indent,bool contents_only) const249 void CDataMemberContainerType::PrintXMLSchema(CNcbiOstream& out,
250 int indent, bool contents_only) const
251 {
252 string tag = XmlTagName();
253 string asnk = GetASNKeyword();
254 string xsdk, tmp;
255 bool hasAttlist= false, isAttlist= false;
256 bool hasNotag= false, isOptionalMember= false, isOptionalContent= false;
257 bool isSimple= false, isSimpleSeq= false, isSeq= false, isMixed=false;
258 bool isSimpleContainer= false, parent_isSeq= false;
259 bool defineAsType = false;
260 bool isGlobalType = GetGlobalType() == CDataType::eType;
261 bool isGlobalGroup = GetGlobalType() == CDataType::eGroup;
262 string simpleType;
263 list<string> opentag, closetag1, closetag2;
264 CNcbiOstream* os = &out;
265 CNcbiOstrstream otype;
266
267 parent_isSeq = (dynamic_cast<const CUniSequenceDataType*>(GetParentType()) != 0);
268 if (GetEnforcedStdXml()) {
269 defineAsType = GetParentType() && IsReferenced() &&
270 GetReferences().front()->IsRefToParent();
271
272 ITERATE ( TMembers, i, m_Members ) {
273 if (i->get()->Attlist()) {
274 hasAttlist = true;
275 break;
276 }
277 }
278 if (( hasAttlist && GetMembers().size() > 2) ||
279 (!hasAttlist && GetMembers().size() > 1)) {
280 ITERATE ( TMembers, i, m_Members ) {
281 if (i->get()->Notag()) {
282 const CStringDataType* str =
283 dynamic_cast<const CStringDataType*>(i->get()->GetType());
284 if (str != 0) {
285 isMixed = true;
286 break;
287 }
288 }
289 }
290 }
291 if (GetDataMember()) {
292 isAttlist = GetDataMember()->Attlist();
293 hasNotag = GetDataMember()->Notag();
294 isOptionalMember= GetDataMember()->Optional();
295 }
296 if (hasNotag && GetMembers().size()==1) {
297 const CDataMember* member = GetMembers().front().get();
298 isOptionalMember = member->Optional();
299 const CUniSequenceDataType* typeSeq =
300 dynamic_cast<const CUniSequenceDataType*>(member->GetType());
301 isSeq = (typeSeq != 0);
302 if (isSeq) {
303 const CDataMemberContainerType* data =
304 dynamic_cast<const CDataMemberContainerType*>(typeSeq->GetElementType());
305 if (data) {
306 asnk = data->GetASNKeyword();
307 }
308 }
309 }
310 if ((hasAttlist && GetMembers().size()==2) ||
311 (!hasAttlist && GetMembers().size()==1)) {
312 ITERATE ( TMembers, i, GetMembers() ) {
313 if (i->get()->Attlist()) {
314 continue;
315 }
316 if (i->get()->SimpleType()) {
317 isSimple = true;
318 simpleType = i->get()->GetType()->GetSchemaTypeString();
319 } else {
320 const CUniSequenceDataType* typeSeq =
321 dynamic_cast<const CUniSequenceDataType*>(i->get()->GetType());
322 bool any = (typeSeq != 0) &&
323 dynamic_cast<const CAnyContentDataType*>(
324 typeSeq->GetElementType()) != 0;
325 const CDataMemberContainerType* data =
326 dynamic_cast<const CDataMemberContainerType*>(i->get()->GetType());
327 isSimpleSeq = !any && (typeSeq != 0 || data != 0);
328 isSimpleContainer = data != 0;
329 if (isSimpleSeq) {
330 isSeq = typeSeq != 0;
331 const CDataMember *mem = i->get()->GetType()->GetDataMember();
332 if (mem) {
333 if (typeSeq) {
334 data = dynamic_cast<const CDataMemberContainerType*>(typeSeq->GetElementType());
335 }
336 if (data) {
337 asnk = data->GetASNKeyword();
338 ITERATE ( TMembers, m, data->m_Members ) {
339 if (m->get()->Notag()) {
340 const CStringDataType* str =
341 dynamic_cast<const CStringDataType*>(m->get()->GetType());
342 if (str != 0) {
343 isMixed = true;
344 break;
345 }
346 }
347 }
348 }
349 if (mem->Notag()) {
350 isOptionalContent = mem->Optional();
351 } else {
352 isSeq = isSimpleSeq = false;
353 }
354 }
355 } else {
356 if (i->get()->Notag()) {
357 const CStringDataType* str =
358 dynamic_cast<const CStringDataType*>(i->get()->GetType());
359 if (str != 0) {
360 isMixed = true;
361 }
362 }
363 }
364 }
365 }
366 }
367 } else {
368 if (GetDataMember()) {
369 isOptionalMember= GetDataMember()->Optional();
370 }
371 }
372
373
374 if (!isAttlist && !parent_isSeq) {
375 if (!hasNotag) {
376 if (!contents_only) {
377 string tname;
378 if (isGlobalType || isGlobalGroup) {
379 tname = tag;
380 } else {
381 tmp = "<xs:element name=\"" + tag + "\"";
382 if (isOptionalMember) {
383 tmp += " minOccurs=\"0\"";
384 }
385 if (IsNillable()) {
386 tmp += " nillable=\"true\"";
387 }
388 if (defineAsType) {
389 const CDataType* par = GetParentType();
390 while ( par->GetParentType() ) {
391 par = par->GetParentType();
392 }
393 tname = par->GetMemberName() + tag + "_Type";
394 tmp += " type=\"" + tname + "\"/>";
395 PrintASNNewLine(out, indent) << tmp;
396 } else {
397 #if _DATATOOL_USE_SCHEMA_STYLE_COMMENTS
398 PrintASNNewLine(out, indent) << tmp;
399 if (!Comments().PrintSchemaComments(out, indent+1)) {
400 out << '>';
401 }
402 ++indent;
403 #else
404 tmp += ">";
405 opentag.push_back(tmp);
406 #endif
407 closetag2.push_front("</xs:element>");
408 }
409 }
410
411 tmp = isGlobalGroup ? "<xs:group" : "<xs:complexType";
412 if (isMixed) {
413 tmp += " mixed=\"true\"";
414 }
415 if (defineAsType || isGlobalType || isGlobalGroup) {
416 tmp += " name=\"" + tname + "\"";
417 if (!isGlobalType && !isGlobalGroup) {
418 os = &otype;
419 }
420 indent = 0;
421 }
422 opentag.push_back(tmp + ">");
423 closetag2.push_front(isGlobalGroup ? "</xs:group" : "</xs:complexType>");
424 }
425 }
426 if (!isGlobalGroup) {
427 if (!isSimple && !isSimpleContainer) {
428 if (!contents_only || hasNotag) {
429 if(NStr::CompareCase(asnk,"CHOICE")==0) {
430 xsdk = "choice";
431 } else if(NStr::CompareCase(asnk,"SEQUENCE")==0) {
432 xsdk = "sequence";
433 } else if(NStr::CompareCase(asnk,"SET")==0) {
434 xsdk = "all";
435 }
436 tmp = "<xs:" + xsdk;
437 if (isOptionalContent || (hasNotag && isOptionalMember)) {
438 tmp += " minOccurs=\"0\"";
439 }
440 if (isSeq) {
441 tmp += " maxOccurs=\"unbounded\"";
442 }
443 opentag.push_back(tmp + ">");
444 closetag1.push_front("</xs:" + xsdk + ">");
445 }
446 } else if (!simpleType.empty()) {
447 opentag.push_back("<xs:simpleContent>");
448 closetag2.push_front("</xs:simpleContent>");
449 opentag.push_back("<xs:extension base=\"" + simpleType + "\">");
450 closetag2.push_front("</xs:extension>");
451 }
452 }
453 }
454 ITERATE ( list<string>, s, opentag ) {
455 PrintASNNewLine(*os, indent++) << *s;
456 }
457 if (isAttlist) {
458 ITERATE ( TMembers, i, m_Members ) {
459 const CDataMember& member = **i;
460 member.PrintXMLSchema(*os, indent);
461 }
462 } else if (!isSimple) {
463 ITERATE ( TMembers, i, m_Members ) {
464 const CDataMember& member = **i;
465 if (member.Attlist()) {
466 continue;
467 }
468 if (isMixed && member.Notag()) {
469 if (dynamic_cast<const CStringDataType*>(member.GetType())) {
470 continue;
471 }
472 }
473 member.PrintXMLSchema(*os, indent, isSimpleSeq);
474 }
475 }
476 ITERATE ( list<string>, s, closetag1 ) {
477 PrintASNNewLine(*os, --indent) << *s;
478 }
479 if (hasAttlist) {
480 ITERATE ( TMembers, i, m_Members ) {
481 const CDataMember& member = **i;
482 if (member.Attlist()) {
483 member.PrintXMLSchema(*os, indent);
484 }
485 }
486 }
487 ITERATE ( list<string>, s, closetag2 ) {
488 PrintASNNewLine(*os, --indent) << *s;
489 }
490 if (defineAsType) {
491 GetModule()->AddExtraSchemaOutput( CNcbiOstrstreamToString(otype) );
492 }
493 m_LastComments.PrintDTD(out, CComments::eMultiline);
494 }
495
PrintDTDElement(CNcbiOstream & out,bool contents_only) const496 void CDataMemberContainerType::PrintDTDElement(CNcbiOstream& out, bool contents_only) const
497 {
498 string tag = XmlTagName();
499 bool hasAttlist= false, isAttlist= false;
500 bool isSimple= false, isSeq= false;
501
502 if (GetEnforcedStdXml()) {
503 ITERATE ( TMembers, i, m_Members ) {
504 if (i->get()->Attlist()) {
505 hasAttlist = true;
506 break;
507 }
508 }
509 if (GetDataMember()) {
510 isAttlist = GetDataMember()->Attlist();
511 }
512 if (GetMembers().size()==1) {
513 const CDataMember* member = GetMembers().front().get();
514 const CUniSequenceDataType* uniType =
515 dynamic_cast<const CUniSequenceDataType*>(member->GetType());
516 if (uniType && member->Notag()) {
517 isSeq = true;
518 }
519 }
520 if (hasAttlist && GetMembers().size()==2) {
521 ITERATE ( TMembers, i, GetMembers() ) {
522 if (i->get()->Attlist()) {
523 continue;
524 }
525 if (i->get()->SimpleType()) {
526 isSimple = true;
527 i->get()->GetType()->PrintDTDElement(out);
528 } else {
529 const CUniSequenceDataType* uniType =
530 dynamic_cast<const CUniSequenceDataType*>(i->get()->GetType());
531 if (uniType && i->get()->Notag()) {
532 isSeq = true;
533 }
534 }
535 }
536 }
537 }
538
539 if (isAttlist) {
540 ITERATE ( TMembers, i, m_Members ) {
541 (*i)->Comments().PrintDTD(out,CComments::eNoEOL);
542 i->get()->GetType()->PrintDTDElement(out);
543 }
544 return;
545 }
546 if (!isSimple) {
547 if (!contents_only) {
548 out << "\n<!ELEMENT " << tag << " ";
549 if (!isSeq) {
550 out << "(";
551 }
552 }
553 bool need_separator = false;
554 ITERATE ( TMembers, i, m_Members ) {
555 if (need_separator) {
556 out << XmlMemberSeparator();
557 }
558 need_separator = true;
559 const CDataMember& member = **i;
560 string member_name( member.GetType()->XmlTagName());
561 const CUniSequenceDataType* uniType =
562 dynamic_cast<const CUniSequenceDataType*>(member.GetType());
563 bool isOptional = member.Optional();
564 if (GetEnforcedStdXml()) {
565 if (member.Attlist()) {
566 need_separator = false;
567 continue;
568 }
569 if (member.Notag()) {
570 const CStaticDataType* statType =
571 dynamic_cast<const CStaticDataType*>(member.GetType());
572 bool need_open = !statType;
573 bool need_newline = !need_open;
574 const CDataMemberContainerType* data =
575 dynamic_cast<const CDataMemberContainerType*>(member.GetType());
576 if (data) {
577 const CDataMember* data_member = data->GetMembers().front().get();
578 if (data_member && data_member->Notag() &&
579 data_member->GetType()->IsUniSeq()) {
580 isOptional = false;
581 need_open = false;
582 need_newline = false;
583 }
584 }
585 if (need_open) {
586 out << "(";
587 }
588 if (need_newline) {
589 out << "\n ";
590 }
591 member.GetType()->PrintDTDElement(out,true);
592 if (need_open) {
593 out << ")";
594 }
595 } else {
596 out << "\n " << member_name;
597 }
598 } else {
599 out << "\n " << member_name;
600 }
601 if (uniType) {
602 const CStaticDataType* elemType =
603 dynamic_cast<const CStaticDataType*>(uniType->GetElementType());
604 if ((elemType || member.NoPrefix()) && GetEnforcedStdXml()) {
605 if ( isOptional ) {
606 out << '*';
607 } else {
608 out << '+';
609 }
610 } else {
611 if ( isOptional ) {
612 out << '?';
613 }
614 }
615 } else {
616 if ( isOptional ) {
617 out << '?';
618 }
619 }
620 }
621 if (!contents_only) {
622 if (!isSeq) {
623 out << ")";
624 }
625 out << ">";
626 }
627 }
628 if (hasAttlist) {
629 ITERATE ( TMembers, i, m_Members ) {
630 const CDataMember& member = **i;
631 if (member.Attlist()) {
632 member.GetComments().PrintDTD(out, CComments::eNoEOL);
633 out << "\n<!ATTLIST " << tag;
634 member.GetType()->PrintDTDElement(out);
635 break;
636 }
637 }
638 out << ">";
639 }
640 }
641
PrintDTDExtra(CNcbiOstream & out) const642 void CDataMemberContainerType::PrintDTDExtra(CNcbiOstream& out) const
643 {
644 ITERATE ( TMembers, i, m_Members ) {
645 const CDataMember& member = **i;
646 if (member.Notag()) {
647 member.GetType()->PrintDTDExtra(out);
648 } else {
649 member.PrintDTD(out);
650 }
651 }
652 m_LastComments.PrintDTD(out, CComments::eMultiline);
653 }
654
FixTypeTree(void) const655 void CDataMemberContainerType::FixTypeTree(void) const
656 {
657 CParent::FixTypeTree();
658 ITERATE ( TMembers, i, m_Members ) {
659 (*i)->GetType()->SetParent(this, (*i)->GetName());
660 }
661 }
662
CheckType(void) const663 bool CDataMemberContainerType::CheckType(void) const
664 {
665 bool ok = true;
666 ITERATE ( TMembers, i, m_Members ) {
667 if ( !(*i)->Check() )
668 ok = false;
669 }
670
671 //check tags
672 // All tags must be different
673 bool hasUntagged = false;
674 set< pair< CAsnBinaryDefs::TLongTag, CAsnBinaryDefs::ETagClass> > tag_inuse;
675 CAsnBinaryDefs::ETagType tagtype = GetTagType();
676 bool ischoice = NStr::CompareCase(GetASNKeyword(),"CHOICE")==0;
677
678 if (tagtype == CAsnBinaryDefs::eAutomatic ||
679 ischoice) {
680
681 ITERATE ( TMembers, i, m_Members ) {
682 const CDataType* itype = (*i)->GetType();
683 bool hastag = itype->HasTag();
684 CAsnBinaryDefs::TLongTag itag = itype->GetTag();
685 CAsnBinaryDefs::ETagClass tagclass = itype->GetTagClass();
686 if (!hastag && itype->IsReference()) {
687 const CDataType* rtype = itype->Resolve();
688 if (rtype) {
689 hastag = rtype->HasTag();
690 itag = rtype->GetTag();
691 tagclass = rtype->GetTagClass();
692 }
693 }
694 if (hastag) {
695 pair< CAsnBinaryDefs::TLongTag, CAsnBinaryDefs::ETagClass>
696 tag = make_pair(itag, tagclass);
697 if (tag_inuse.find(tag) != tag_inuse.end()) {
698 NCBI_THROW(CDatatoolException,eInvalidData,
699 "Duplicate tag: " + itype->IdName() +
700 " [" + NStr::NumericToString(itag) + "] in " +
701 GetModule()->GetName());
702 }
703 tag_inuse.insert(tag);
704 if (hasUntagged) {
705 NCBI_THROW(CDatatoolException,eInvalidData,
706 "No explicit tag for " + itype->IdName() + " in " +
707 GetModule()->GetName());
708 }
709 }
710 else {
711 hasUntagged = true;
712 if (!tag_inuse.empty()) {
713 NCBI_THROW(CDatatoolException,eInvalidData,
714 "No explicit tag for " + itype->IdName() + " in " +
715 GetModule()->GetName());
716 }
717 }
718 }
719 }
720 return ok;
721 }
722
CreateDefault(const CDataValue &) const723 TObjectPtr CDataMemberContainerType::CreateDefault(const CDataValue& ) const
724 {
725 NCBI_THROW(CDatatoolException,eNotImplemented,
726 GetASNKeyword() + string(" default not implemented"));
727 }
728
UniElementNameExists(const string & name) const729 bool CDataMemberContainerType::UniElementNameExists(const string& name) const
730 {
731 bool res = false;
732 for (TMembers::const_iterator i = m_Members.begin();
733 !res && i != m_Members.end(); ++i) {
734 const CUniSequenceDataType* mem =
735 dynamic_cast<const CUniSequenceDataType*>((*i)->GetType());
736 if (mem != 0) {
737 const CDataMemberContainerType* elem =
738 dynamic_cast<const CDataMemberContainerType*>(mem->GetElementType());
739 res = (elem != 0 && elem->GetMemberName() == name);
740 }
741 }
742 return res;
743 }
744
XmlMemberSeparator(void) const745 const char* CDataContainerType::XmlMemberSeparator(void) const
746 {
747 return ", ";
748 }
749
CreateTypeInfo(void)750 CTypeInfo* CDataContainerType::CreateTypeInfo(void)
751 {
752 return CreateClassInfo();
753 }
754
CreateClassInfo(void)755 CClassTypeInfo* CDataContainerType::CreateClassInfo(void)
756 {
757 size_t itemCount = 0;
758 // add place for 'isSet' flags
759 ITERATE ( TMembers, i, GetMembers() ) {
760 ++itemCount;
761 CDataMember* mem = i->get();
762 if ( mem->Optional() || mem->GetDefault() || mem->Nillable() )
763 ++itemCount;
764 }
765 unique_ptr<CAnyTypeClassInfo> typeInfo(new CAnyTypeClassInfo(
766 HasExternalName() ? GlobalName() : kEmptyStr, itemCount));
767 size_t index = 0;
768 for ( TMembers::const_iterator i = GetMembers().begin();
769 i != GetMembers().end(); ++i ) {
770 CDataMember* mem = i->get();
771 CDataType* memType = mem->GetType();
772 TConstObjectPtr memberPtr = typeInfo->GetAnyTypePtr(index++);
773 CMemberInfo* memInfo =
774 typeInfo->AddMember(mem->GetName(), memberPtr,
775 memType->GetTypeInfo());
776 if ( mem->GetDefault() ) {
777 TObjectPtr defPtr = memType->CreateDefault(*mem->GetDefault());
778 memInfo->SetDefault(defPtr);
779 }
780 if ( mem->Optional() ) {
781 memInfo->SetOptional();
782 }
783 if ( mem->Optional() || mem->GetDefault() || mem->Nillable() ) {
784 memInfo->SetSetFlag(typeInfo->GetSetFlagPtr(index++));
785 }
786 if (!IsASNDataSpec()) {
787 memInfo->SetNoPrefix();
788 }
789 if (mem->Attlist()) {
790 memInfo->SetAttlist();
791 }
792 if (mem->Notag()) {
793 memInfo->SetNotag();
794 }
795 if (dynamic_cast<const CAnyContentDataType*>(mem->GetType()) != 0) {
796 memInfo->SetAnyContent();
797 }
798 if (mem->Nillable()) {
799 memInfo->SetNillable();
800 }
801 }
802 typeInfo->AssignItemsTags();
803 if ( HaveModuleName() )
804 typeInfo->SetModuleName(GetModule()->GetName());
805 return typeInfo.release();
806 }
807
GenerateCode(void) const808 AutoPtr<CTypeStrings> CDataContainerType::GenerateCode(void) const
809 {
810 #if 0
811 return GetFullCType();
812 #else
813 string alias = GetVar("_fullalias");
814 if (alias.empty()) {
815 return GetFullCType();
816 }
817 const CDataType* aliastype = ResolveGlobal(alias);
818 if (!aliastype) {
819 NCBI_THROW(CDatatoolException,eWrongInput,
820 "cannot create type info of _fullalias " + alias);
821 }
822 AutoPtr<CTypeStrings> dType = aliastype->GetRefCType();
823 dType->SetDataType(aliastype);
824 AutoPtr<CAliasTypeStrings> code(new CAliasTypeStrings(GlobalName(),
825 ClassName(),
826 *dType.release(),
827 Comments()));
828 code->SetNamespaceName( GetNamespaceName());
829 code->SetFullAlias();
830 return AutoPtr<CTypeStrings>(code.release());
831 #endif
832 }
833
GetFullCType(void) const834 AutoPtr<CTypeStrings> CDataContainerType::GetFullCType(void) const
835 {
836 AutoPtr<CClassTypeStrings> code(new CClassTypeStrings(
837 GlobalName(), ClassName(), GetNamespaceName(), this, Comments()));
838 return AddMembers(code);
839 }
840
AddMembers(AutoPtr<CClassTypeStrings> & code) const841 AutoPtr<CTypeStrings> CDataContainerType::AddMembers(
842 AutoPtr<CClassTypeStrings>& code) const
843 {
844 bool isRootClass = GetParentType() == 0;
845 bool haveUserClass = isRootClass;
846 /*
847 bool isObject;
848 if ( haveUserClass ) {
849 isObject = true;
850 }
851 else {
852 isObject = GetBoolVar("_object");
853 }
854 */
855 code->SetHaveUserClass(haveUserClass);
856 code->SetObject(true /*isObject*/ );
857 ITERATE ( TMembers, i, GetMembers() ) {
858 string defaultCode;
859 bool optional = (*i)->Optional();
860 const CDataValue* defaultValue = (*i)->GetDefault();
861 if ( defaultValue ) {
862 defaultCode = (*i)->GetType()->GetDefaultString(*defaultValue);
863 _ASSERT(!defaultCode.empty());
864 }
865
866 bool delayed = GetBoolVar((*i)->GetName()+"._delay");
867 AutoPtr<CTypeStrings> memberType = (*i)->GetType()->GetFullCType();
868 string external_name = (*i)->GetName();
869 string member_name = (*i)->GetType()->DefClassMemberName();
870 if (member_name.empty()) {
871 member_name = external_name;
872 }
873 code->AddMember(external_name, member_name, memberType,
874 (*i)->GetType()->GetVar("_pointer"),
875 optional, defaultCode, delayed,
876 (*i)->GetType()->GetTag(),
877 !IsASNDataSpec(), (*i)->Attlist(), (*i)->Notag(),
878 (*i)->SimpleType(),(*i)->GetType(),false,
879 (*i)->Comments());
880 (*i)->GetType()->SetTypeStr(&(*code));
881 }
882 SetTypeStr(&(*code));
883 SetParentClassTo(*code);
884 return AutoPtr<CTypeStrings>(code.release());
885 }
886
GetRefCType(void) const887 AutoPtr<CTypeStrings> CDataContainerType::GetRefCType(void) const
888 {
889 return AutoPtr<CTypeStrings>(new CClassRefTypeStrings(ClassName(),
890 Namespace(),
891 FileName(),
892 Comments()));
893 }
894
GetSpecKeyword(void) const895 string CDataContainerType::GetSpecKeyword(void) const
896 {
897 bool hasAttlist = !m_Members.empty() && m_Members.front()->Attlist();
898 if (( hasAttlist && m_Members.size() == 2) ||
899 (!hasAttlist && m_Members.size() == 1)) {
900 const CDataMember* member = m_Members.back().get();
901 if (!GetParentType() && (member->SimpleType() || member->Notag())) {
902 return member->GetType()->GetSpecKeyword();
903 }
904 }
905 return GetASNKeyword();
906 }
907
908
GetASNKeyword(void) const909 const char* CDataSetType::GetASNKeyword(void) const
910 {
911 return "SET";
912 }
913
GetDEFKeyword(void) const914 const char* CDataSetType::GetDEFKeyword(void) const
915 {
916 return "_SET_";
917 }
918
CheckValue(const CDataValue & value) const919 bool CDataSetType::CheckValue(const CDataValue& value) const
920 {
921 const CBlockDataValue* block =
922 dynamic_cast<const CBlockDataValue*>(&value);
923 if ( !block ) {
924 value.Warning("block of values expected", 2);
925 return false;
926 }
927
928 typedef map<string, const CDataMember*> TReadValues;
929 TReadValues mms;
930 for ( TMembers::const_iterator m = GetMembers().begin();
931 m != GetMembers().end(); ++m ) {
932 mms[m->get()->GetName()] = m->get();
933 }
934
935 ITERATE ( CBlockDataValue::TValues, v, block->GetValues() ) {
936 const CNamedDataValue* currvalue =
937 dynamic_cast<const CNamedDataValue*>(v->get());
938 if ( !currvalue ) {
939 v->get()->Warning("named value expected", 3);
940 return false;
941 }
942 TReadValues::iterator member = mms.find(currvalue->GetName());
943 if ( member == mms.end() ) {
944 currvalue->Warning("unexpected member", 4);
945 return false;
946 }
947 if ( !member->second->GetType()->CheckValue(currvalue->GetValue()) ) {
948 return false;
949 }
950 mms.erase(member);
951 }
952
953 for ( TReadValues::const_iterator member = mms.begin();
954 member != mms.end(); ++member ) {
955 if ( !member->second->Optional() ) {
956 value.Warning(member->first + " member expected", 5);
957 return false;
958 }
959 }
960 return true;
961 }
962
CreateClassInfo(void)963 CClassTypeInfo* CDataSetType::CreateClassInfo(void)
964 {
965 return CParent::CreateClassInfo()->SetRandomOrder();
966 }
967
GetASNKeyword(void) const968 const char* CDataSequenceType::GetASNKeyword(void) const
969 {
970 return "SEQUENCE";
971 }
972
GetDEFKeyword(void) const973 const char* CDataSequenceType::GetDEFKeyword(void) const
974 {
975 return "_SEQUENCE_";
976 }
977
CheckValue(const CDataValue & value) const978 bool CDataSequenceType::CheckValue(const CDataValue& value) const
979 {
980 const CBlockDataValue* block =
981 dynamic_cast<const CBlockDataValue*>(&value);
982 if ( !block ) {
983 value.Warning("block of values expected", 6);
984 return false;
985 }
986 TMembers::const_iterator member = GetMembers().begin();
987 CBlockDataValue::TValues::const_iterator cvalue =
988 block->GetValues().begin();
989 while ( cvalue != block->GetValues().end() ) {
990 const CNamedDataValue* currvalue =
991 dynamic_cast<const CNamedDataValue*>(cvalue->get());
992 if ( !currvalue ) {
993 cvalue->get()->Warning("named value expected", 7);
994 return false;
995 }
996 for (;;) {
997 if ( member == GetMembers().end() ) {
998 currvalue->Warning("unexpected value", 8);
999 return false;
1000 }
1001 if ( (*member)->GetName() == currvalue->GetName() )
1002 break;
1003 if ( !(*member)->Optional() ) {
1004 currvalue->GetValue().Warning((*member)->GetName() +
1005 " member expected", 9);
1006 return false;
1007 }
1008 ++member;
1009 }
1010 if ( !(*member)->GetType()->CheckValue(currvalue->GetValue()) ) {
1011 return false;
1012 }
1013 ++member;
1014 ++cvalue;
1015 }
1016 while ( member != GetMembers().end() ) {
1017 if ( !(*member)->Optional() ) {
1018 value.Warning((*member)->GetName() + " member expected", 10);
1019 return false;
1020 }
1021 }
1022 return true;
1023 }
1024
GetFullCType(void) const1025 AutoPtr<CTypeStrings> CWsdlDataType::GetFullCType(void) const
1026 {
1027 AutoPtr<CClassTypeStrings> code(new CWsdlTypeStrings(
1028 GlobalName(), ClassName(), GetNamespaceName(), this, Comments()));
1029 code->SetHaveTypeInfo(false);
1030 return AddMembers(code);
1031 }
1032
1033
CDataMember(const string & name,const AutoPtr<CDataType> & type)1034 CDataMember::CDataMember(const string& name, const AutoPtr<CDataType>& type)
1035 : m_Name(name), m_Type(type), m_Optional(false),
1036 m_NoPrefix(false), m_Attlist(false), m_Notag(false), m_SimpleType(false),
1037 m_Nillable(false)
1038 {
1039 if ( m_Name.empty() ) {
1040 m_Notag = true;
1041 /*
1042 string loc("Invalid identifier name in ASN.1 specification");
1043 if (type) {
1044 loc += " (line " + NStr::IntToString(type->GetSourceLine()) + ")";
1045 }
1046 NCBI_THROW(CDatatoolException,eInvalidData, loc);
1047 */
1048 }
1049 m_Type->SetDataMember(this);
1050 }
1051
~CDataMember(void)1052 CDataMember::~CDataMember(void)
1053 {
1054 }
1055
PrintASN(CNcbiOstream & out,int indent,bool last) const1056 void CDataMember::PrintASN(CNcbiOstream& out, int indent, bool last) const
1057 {
1058 GetType()->PrintASNTypeComments(out, indent);
1059 bool oneLineComment = m_Comments.OneLine();
1060 if ( !oneLineComment )
1061 m_Comments.PrintASN(out, indent);
1062 out << CDataTypeModule::ToAsnId(GetName()) << ' ';
1063 GetType()->PrintASN(out, indent);
1064 if ( GetDefault() ) {
1065 GetDefault()->PrintASN(out << " DEFAULT ", indent + 1);
1066 }
1067 else if ( Optional() ) {
1068 out << " OPTIONAL";
1069 }
1070 if ( !last )
1071 out << ',';
1072 if ( oneLineComment ) {
1073 out << ' ';
1074 m_Comments.PrintASN(out, indent, CComments::eOneLine);
1075 }
1076 }
1077
PrintSpecDump(CNcbiOstream & out,int indent,const char * tag) const1078 void CDataMember::PrintSpecDump(CNcbiOstream& out, int indent, const char* tag) const
1079 {
1080 if (!SimpleType()) {
1081 const CDataType* type = GetType();
1082 if (!Attlist()) {
1083 bool needTitle= !Notag() || (type->IsStdType() || type->IsPrimitive());
1084 if (!needTitle) {
1085 const CDataMemberContainerType* cont =
1086 dynamic_cast<const CDataMemberContainerType*>(type);
1087 if (cont) {
1088 needTitle=true;
1089 const CDataMemberContainerType::TMembers& members = cont->GetMembers();
1090 bool hasAttlist = !members.empty() && members.front()->Attlist();
1091 if (( hasAttlist && members.size() == 2) ||
1092 (!hasAttlist && members.size() == 1)) {
1093 const CDataMember* member = members.back().get();
1094 needTitle = !member->GetType()->IsUniSeq();
1095 if (!needTitle) {
1096 --indent;
1097 }
1098 }
1099 } else if (type->IsUniSeq()) {
1100 const CDataType* parent = type->GetParentType();
1101 needTitle = parent->GetDataMember() != 0;
1102 if (!needTitle && parent->IsContainer()) {
1103 cont = dynamic_cast<const CDataMemberContainerType*>(parent);
1104 needTitle = cont->GetMembers().size() == 1;
1105 }
1106 if (!needTitle) {
1107 const CUniSequenceDataType* uni =
1108 dynamic_cast<const CUniSequenceDataType*>(type);
1109 if (uni->GetElementType()->IsContainer()) {
1110 --indent;
1111 }
1112 }
1113 }
1114 }
1115 if (needTitle) {
1116 PrintASNNewLine(out, indent);
1117 out << tag << ',' <<
1118 type->GetSourceLine() <<",";
1119 out << type->GetFullName() << ',' << type->GetSpecKeyword();
1120 if ( GetDefault() ) {
1121 GetDefault()->PrintASN(out << ",DEFAULT,", indent + 1);
1122 }
1123 else if ( Optional() ) {
1124 out << ",OPTIONAL";
1125 }
1126 type->Comments().PrintASN(out, indent,CComments::eNoEOL);
1127 m_Comments.PrintASN(out, indent,CComments::eNoEOL);
1128 }
1129 }
1130 type->PrintSpecDump(out, indent);
1131 }
1132 }
1133
PrintJSONSchema(CNcbiOstream & out,int indent,list<string> & required,bool contents_only) const1134 void CDataMember::PrintJSONSchema(CNcbiOstream& out, int indent, list<string>& required, bool contents_only) const
1135 {
1136 GetType()->PrintJSONSchema(out, indent, required, contents_only);
1137 }
1138
PrintXMLSchema(CNcbiOstream & out,int indent,bool contents_only) const1139 void CDataMember::PrintXMLSchema(CNcbiOstream& out, int indent, bool contents_only) const
1140 {
1141 #if !_DATATOOL_USE_SCHEMA_STYLE_COMMENTS
1142 m_Comments.PrintDTD(out, CComments::eNoEOL);
1143 #endif
1144 GetType()->PrintXMLSchema(out, indent, contents_only);
1145 }
1146
PrintDTD(CNcbiOstream & out) const1147 void CDataMember::PrintDTD(CNcbiOstream& out) const
1148 {
1149 GetType()->PrintDTD(out, m_Comments);
1150 }
1151
Check(void) const1152 bool CDataMember::Check(void) const
1153 {
1154 if ( !m_Type->Check() )
1155 return false;
1156 if ( !m_Default )
1157 return true;
1158 return GetType()->CheckValue(*m_Default);
1159 }
1160
SetDefault(const AutoPtr<CDataValue> & value)1161 void CDataMember::SetDefault(const AutoPtr<CDataValue>& value)
1162 {
1163 m_Default = value;
1164 }
1165
SetOptional(void)1166 void CDataMember::SetOptional(void)
1167 {
1168 m_Optional = true;
1169 }
1170
SetNoPrefix(void)1171 void CDataMember::SetNoPrefix(void)
1172 {
1173 // m_NoPrefix = true;
1174 }
1175
SetAttlist(void)1176 void CDataMember::SetAttlist(void)
1177 {
1178 m_Attlist = true;
1179 }
SetNotag(void)1180 void CDataMember::SetNotag(void)
1181 {
1182 m_Notag = true;
1183 }
SetSimpleType(void)1184 void CDataMember::SetSimpleType(void)
1185 {
1186 m_SimpleType = true;
1187 }
SetNillable(void)1188 void CDataMember::SetNillable(void)
1189 {
1190 m_Nillable = true;
1191 }
1192
1193 END_NCBI_SCOPE
1194