1 /*  $Id: moduleset.cpp 545959 2017-09-12 17:04:06Z 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 *   Set of modules: equivalent of ASN.1 source file
30 *
31 */
32 
33 #include <ncbi_pch.hpp>
34 #include <corelib/ncbiapp.hpp>
35 #include <corelib/ncbiargs.hpp>
36 #include <corelib/ncbifile.hpp>
37 #include <typeinfo>
38 #include "moduleset.hpp"
39 #include "module.hpp"
40 #include "type.hpp"
41 #include "exceptions.hpp"
42 #include "fileutil.hpp"
43 #include <serial/error_codes.hpp>
44 
45 
46 #define NCBI_USE_ERRCODE_X   Serial_Modules
47 
48 BEGIN_NCBI_SCOPE
49 
CFileModules(const string & name)50 CFileModules::CFileModules(const string& name)
51     : m_SourceFileName(name)
52 {
53 }
54 
AddModule(const AutoPtr<CDataTypeModule> & module)55 void CFileModules::AddModule(const AutoPtr<CDataTypeModule>& module)
56 {
57     module->SetModuleContainer(this);
58     CDataTypeModule*& mptr = m_ModulesByName[module->GetName()];
59     if ( mptr ) {
60         ERR_POST_X(4, GetSourceFileName() << ": duplicate module: " <<
61                       module->GetName());
62     }
63     else {
64         mptr = module.get();
65         m_Modules.push_back(module);
66     }
67 }
68 
Check(void) const69 bool CFileModules::Check(void) const
70 {
71     bool ok = true;
72     ITERATE ( TModules, mi, m_Modules ) {
73         if ( !(*mi)->Check() )
74             ok = false;
75     }
76     return ok;
77 }
78 
CheckNames(void) const79 bool CFileModules::CheckNames(void) const
80 {
81     bool ok = true;
82     ITERATE ( TModules, mi, m_Modules ) {
83         if ( !(*mi)->CheckNames() )
84             ok = false;
85     }
86     return ok;
87 }
88 
PrintSampleDEF(const string & rootdir) const89 void CFileModules::PrintSampleDEF(const string& rootdir) const
90 {
91     ITERATE ( TModules, mi, m_Modules ) {
92         string fileName = MakeAbsolutePath(
93             Path(rootdir, Path(GetFileNamePrefix(), (*mi)->GetName() + "._sample_def")));
94         CNcbiOfstream out(fileName.c_str());
95         (*mi)->PrintSampleDEF(out);
96         if ( !out )
97             ERR_POST_X(5, Fatal << "Cannot write to file "<<fileName);
98     }
99 }
100 
PrintASN(CNcbiOstream & out) const101 void CFileModules::PrintASN(CNcbiOstream& out) const
102 {
103     ITERATE ( TModules, mi, m_Modules ) {
104         PrintASNRefInfo(out);
105         (*mi)->PrintASN(out);
106     }
107     m_LastComments.PrintASN(out, 0, CComments::eMultiline);
108 }
109 
PrintSpecDump(CNcbiOstream & out) const110 void CFileModules::PrintSpecDump(CNcbiOstream& out) const
111 {
112     ITERATE ( TModules, mi, m_Modules ) {
113         out << "M," << mi->get()->GetSourceLine() << ',';
114         out << CDirEntry(m_SourceFileName).GetName() << ':'
115             << (*mi)->GetName();
116         (*mi)->PrintSpecDump(out);
117     }
118 }
119 
PrintJSONSchema(CNcbiOstream & out) const120 void CFileModules::PrintJSONSchema(CNcbiOstream& out) const
121 {
122     ITERATE ( TModules, mi, m_Modules ) {
123         (*mi)->PrintJSONSchema(out);
124     }
125 }
126 
127 // XML schema generator submitted by
128 // Marc Dumontier, Blueprint initiative, dumontier@mshri.on.ca
PrintXMLSchema(CNcbiOstream & out) const129 void CFileModules::PrintXMLSchema(CNcbiOstream& out) const
130 {
131     BeginXMLSchema(out);
132     ITERATE ( TModules, mi, m_Modules ) {
133         (*mi)->PrintXMLSchema(out);
134     }
135     m_LastComments.PrintDTD(out, CComments::eMultiline);
136     EndXMLSchema(out);
137 }
138 
GetRefInfo(list<string> & info) const139 void CFileModules::GetRefInfo(list<string>& info) const
140 {
141     info.clear();
142     string s, h("::DATATOOL:: ");
143     s = h + "Generated from \"" + GetSourceFileName() + "\"";
144     info.push_back(s);
145     s = h + "by application DATATOOL version ";
146     s += CNcbiApplication::Instance()->GetVersion().Print();
147     info.push_back(s);
148     s = h + "on " + CTime(CTime::eCurrent).AsString();
149     info.push_back(s);
150 }
151 
PrintASNRefInfo(CNcbiOstream & out) const152 void CFileModules::PrintASNRefInfo(CNcbiOstream& out) const
153 {
154     list<string> info;
155     GetRefInfo(info);
156     out << "-- ============================================\n";
157     ITERATE(list<string>, i, info) {
158         out << "-- " << *i << "\n";
159     }
160     out << "-- ============================================\n\n";
161 }
162 
PrintXMLRefInfo(CNcbiOstream & out) const163 void CFileModules::PrintXMLRefInfo(CNcbiOstream& out) const
164 {
165     list<string> info;
166     GetRefInfo(info);
167     out << "<!-- ============================================\n";
168     ITERATE(list<string>, i, info) {
169         out << "     " << *i << "\n";
170     }
171     out << "     ============================================ -->\n\n";
172 }
173 
PrintDTD(CNcbiOstream & out) const174 void CFileModules::PrintDTD(CNcbiOstream& out) const
175 {
176     ITERATE ( TModules, mi, m_Modules ) {
177         PrintXMLRefInfo(out);
178         (*mi)->PrintDTD(out);
179     }
180     m_LastComments.PrintDTD(out, CComments::eMultiline);
181 }
182 
PrintDTDModular(void) const183 void CFileModules::PrintDTDModular(void) const
184 {
185     ITERATE ( TModules, mi, m_Modules ) {
186         string fileNameBase = MakeAbsolutePath(
187             (*mi)->GetDTDFileNameBase() + (*mi)->GetModuleFileSuffix());
188         {
189             string fileName = fileNameBase + ".mod.dtd";
190             CNcbiOfstream out(fileName.c_str());
191             PrintXMLRefInfo(out);
192             (*mi)->PrintDTD(out);
193             if ( !out )
194                 ERR_POST_X(5, Fatal << "Cannot write to file "<<fileName);
195         }
196         {
197             string fileName = fileNameBase + ".dtd";
198             CNcbiOfstream out(fileName.c_str());
199             PrintXMLRefInfo(out);
200             (*mi)->PrintDTDModular(out);
201             if ( !out )
202                 ERR_POST_X(6, Fatal << "Cannot write to file "<<fileName);
203         }
204     }
205 }
206 
PrintXMLSchemaModular(void) const207 void CFileModules::PrintXMLSchemaModular(void) const
208 {
209     ITERATE ( TModules, mi, m_Modules ) {
210         string fileNameBase = MakeAbsolutePath(
211             (*mi)->GetDTDFileNameBase() + (*mi)->GetModuleFileSuffix());
212         {
213             string fileName = fileNameBase + ".mod.xsd";
214             CNcbiOfstream out(fileName.c_str());
215             if ( !out )
216                 ERR_POST_X(7, Fatal << "Cannot write to file "<<fileName);
217             BeginXMLSchema(out);
218             (*mi)->PrintXMLSchema(out);
219             EndXMLSchema(out);
220         }
221         {
222             string fileName = fileNameBase + ".xsd";
223             CNcbiOfstream out(fileName.c_str());
224             if ( !out )
225                 ERR_POST_X(8, Fatal << "Cannot write to file "<<fileName);
226             BeginXMLSchema(out);
227             (*mi)->PrintXMLSchemaModular(out);
228             EndXMLSchema(out);
229         }
230     }
231 }
232 
BeginXMLSchema(CNcbiOstream & out) const233 void CFileModules::BeginXMLSchema(CNcbiOstream& out) const
234 {
235     string nsName("http://www.ncbi.nlm.nih.gov");
236     string nsNcbi(nsName);
237     string elementForm("qualified");
238     string attributeForm("unqualified");
239     if (!m_Modules.empty()) {
240         const CDataTypeModule::TDefinitions& defs =
241             m_Modules.front()->GetDefinitions();
242         if (!defs.empty()) {
243             const string& ns = defs.front().second->GetNamespaceName();
244             if (!ns.empty()) {
245                 nsName = ns;
246             }
247             if (defs.front().second->IsNsQualified() == eNSUnqualified) {
248                 elementForm = "unqualified";
249             }
250         }
251     }
252     const CArgs& args = CNcbiApplication::Instance()->GetArgs();
253     if ( const CArgValue& px_ns = args["xmlns"] ) {
254         nsName = px_ns.AsString();
255     }
256     out << "<?xml version=\"1.0\" ?>\n";
257     PrintXMLRefInfo(out);
258     out << "<xs:schema\n"
259         << "  xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"\n"
260         << "  xmlns:ncbi=\"" << nsNcbi << "\"\n";
261     if (!nsName.empty()) {
262         out << "  xmlns=\"" << nsName << "\"\n"
263             << "  targetNamespace=\"" << nsName << "\"\n";
264     }
265     out << "  elementFormDefault=\"" << elementForm << "\"\n"
266         << "  attributeFormDefault=\"" << attributeForm << "\">\n\n";
267 }
268 
EndXMLSchema(CNcbiOstream & out) const269 void CFileModules::EndXMLSchema(CNcbiOstream& out) const
270 {
271     out << "</xs:schema>\n";
272 }
273 
GetSourceFileName(void) const274 const string& CFileModules::GetSourceFileName(void) const
275 {
276     return m_SourceFileName;
277 }
278 
GetFileNamePrefix(void) const279 string CFileModules::GetFileNamePrefix(void) const
280 {
281     if ( MakeFileNamePrefixFromSourceFileName() ) {
282         if ( m_PrefixFromSourceFileName.empty() ) {
283             m_PrefixFromSourceFileName = DirName(m_SourceFileName);
284             if ( !IsLocalPath(m_PrefixFromSourceFileName) ) {
285                 // path absent or non local
286                 m_PrefixFromSourceFileName.erase();
287                 return GetModuleContainer().GetFileNamePrefix();
288             }
289         }
290         _TRACE("file " << m_SourceFileName << ": \"" << m_PrefixFromSourceFileName << "\"");
291         if ( UseAllFileNamePrefixes() ) {
292             return Path(GetModuleContainer().GetFileNamePrefix(),
293                         m_PrefixFromSourceFileName);
294         }
295         else {
296             return m_PrefixFromSourceFileName;
297         }
298     }
299     return GetModuleContainer().GetFileNamePrefix();
300 }
301 
ExternalResolve(const string & moduleName,const string & typeName,bool allowInternal) const302 CDataType* CFileModules::ExternalResolve(const string& moduleName,
303                                          const string& typeName,
304                                          bool allowInternal) const
305 {
306     // find module definition
307     TModulesByName::const_iterator mi = m_ModulesByName.find(moduleName);
308     if ( mi == m_ModulesByName.end() ) {
309         // no such module
310         NCBI_THROW(CNotFoundException,eModule,
311                      "module not found: "+moduleName+" for type "+typeName);
312     }
313     return mi->second->ExternalResolve(typeName, allowInternal);
314 }
315 
ResolveInAnyModule(const string & typeName,bool allowInternal) const316 CDataType* CFileModules::ResolveInAnyModule(const string& typeName,
317                                             bool allowInternal) const
318 {
319     CResolvedTypeSet types(typeName);
320     ITERATE ( TModules, i, m_Modules ) {
321         try {
322             types.Add((*i)->ExternalResolve(typeName, allowInternal));
323         }
324         catch ( CAmbiguiousTypes& exc ) {
325             types.Add(exc);
326         }
327         catch ( CNotFoundException& /* ignored */) {
328         }
329     }
330     return types.GetType();
331 }
332 
CollectAllTypeinfo(set<TTypeInfo> & types) const333 void CFileModules::CollectAllTypeinfo(set<TTypeInfo>& types) const
334 {
335     ITERATE ( TModules, i, m_Modules ) {
336         (*i)->CollectAllTypeinfo(types);
337     }
338 }
339 
AddFile(const AutoPtr<CFileModules> & moduleSet)340 void CFileSet::AddFile(const AutoPtr<CFileModules>& moduleSet)
341 {
342     moduleSet->SetModuleContainer(this);
343     m_ModuleSets.push_back(moduleSet);
344 }
345 
PrintSampleDEF(const string & rootdir) const346 void CFileSet::PrintSampleDEF(const string& rootdir) const
347 {
348     ITERATE ( TModuleSets, i, m_ModuleSets ) {
349         (*i)->PrintSampleDEF(rootdir);
350     }
351 }
352 
PrintASN(CNcbiOstream & out) const353 void CFileSet::PrintASN(CNcbiOstream& out) const
354 {
355     ITERATE ( TModuleSets, i, m_ModuleSets ) {
356         (*i)->PrintASN(out);
357     }
358 }
359 
PrintSpecDump(CNcbiOstream & out) const360 void CFileSet::PrintSpecDump(CNcbiOstream& out) const
361 {
362     ITERATE ( TModuleSets, i, m_ModuleSets ) {
363         (*i)->PrintSpecDump(out);
364     }
365 }
366 
PrintJSONSchema(CNcbiOstream & out) const367 void CFileSet::PrintJSONSchema(CNcbiOstream& out) const
368 {
369     ITERATE ( TModuleSets, i, m_ModuleSets ) {
370         (*i)->PrintJSONSchema(out);
371     }
372 }
373 
374 // XML schema generator submitted by
375 // Marc Dumontier, Blueprint initiative, dumontier@mshri.on.ca
PrintXMLSchema(CNcbiOstream & out) const376 void CFileSet::PrintXMLSchema(CNcbiOstream& out) const
377 {
378     ITERATE ( TModuleSets, i, m_ModuleSets ) {
379         (*i)->PrintXMLSchema(out);
380     }
381 }
382 
PrintDTD(CNcbiOstream & out) const383 void CFileSet::PrintDTD(CNcbiOstream& out) const
384 {
385 #if 0
386     out <<
387         "<!-- ======================== -->\n"
388         "<!-- NCBI DTD                 -->\n"
389         "<!-- NCBI ASN.1 mapped to XML -->\n"
390         "<!-- ======================== -->\n"
391         "\n"
392         "<!-- Entities used to give specificity to #PCDATA -->\n"
393         "<!ENTITY % INTEGER '#PCDATA'>\n"
394         "<!ENTITY % ENUM 'EMPTY'>\n"
395         "<!ENTITY % BOOLEAN 'EMPTY'>\n"
396         "<!ENTITY % NULL 'EMPTY'>\n"
397         "<!ENTITY % REAL '#PCDATA'>\n"
398         "<!ENTITY % OCTETS '#PCDATA'>\n"
399         "<!-- ============================================ -->\n"
400         "\n";
401 #endif
402     ITERATE ( TModuleSets, i, m_ModuleSets ) {
403         (*i)->PrintDTD(out);
404     }
405 }
406 
PrintDTDModular(void) const407 void CFileSet::PrintDTDModular(void) const
408 {
409     ITERATE ( TModuleSets, i, m_ModuleSets ) {
410         (*i)->PrintDTDModular();
411     }
412 }
413 
PrintXMLSchemaModular(void) const414 void CFileSet::PrintXMLSchemaModular(void) const
415 {
416     ITERATE ( TModuleSets, i, m_ModuleSets ) {
417         (*i)->PrintXMLSchemaModular();
418     }
419 }
420 
ExternalResolve(const string & module,const string & name,bool allowInternal) const421 CDataType* CFileSet::ExternalResolve(const string& module, const string& name,
422                                      bool allowInternal) const
423 {
424     CResolvedTypeSet types(module, name);
425     ITERATE ( TModuleSets, i, m_ModuleSets ) {
426         try {
427             types.Add((*i)->ExternalResolve(module, name, allowInternal));
428         }
429         catch ( CAmbiguiousTypes& exc ) {
430             types.Add(exc);
431         }
432         catch ( CNotFoundException& /* ignored */) {
433         }
434     }
435     return types.GetType();
436 }
437 
ResolveInAnyModule(const string & name,bool allowInternal) const438 CDataType* CFileSet::ResolveInAnyModule(const string& name,
439                                         bool allowInternal) const
440 {
441     CResolvedTypeSet types(name);
442     ITERATE ( TModuleSets, i, m_ModuleSets ) {
443         try {
444             types.Add((*i)->ResolveInAnyModule(name, allowInternal));
445         }
446         catch ( CAmbiguiousTypes& exc ) {
447             types.Add(exc);
448         }
449         catch ( CNotFoundException& /* ignored */) {
450         }
451     }
452     return types.GetType();
453 }
454 
Check(void) const455 bool CFileSet::Check(void) const
456 {
457     bool ok = true;
458     ITERATE ( TModuleSets, mi, m_ModuleSets ) {
459         if ( !(*mi)->Check() )
460             ok = false;
461     }
462     return ok;
463 }
464 
CheckNames(void) const465 bool CFileSet::CheckNames(void) const
466 {
467     bool ok = true;
468     ITERATE ( TModuleSets, mi, m_ModuleSets ) {
469         if ( !(*mi)->CheckNames() )
470             ok = false;
471     }
472     return ok;
473 }
474 
CollectAllTypeinfo(set<TTypeInfo> & types) const475 void CFileSet::CollectAllTypeinfo(set<TTypeInfo>& types) const
476 {
477     ITERATE ( TModuleSets, i, m_ModuleSets ) {
478         (*i)->CollectAllTypeinfo(types);
479     }
480 }
481 
482 END_NCBI_SCOPE
483