00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <ncbi_pch.hpp>
00033 #include <corelib/ncbistd.hpp>
00034 #include <corelib/ncbiargs.hpp>
00035
00036 #include <serial/objistr.hpp>
00037 #include <serial/objostr.hpp>
00038 #include <serial/objcopy.hpp>
00039
00040 #include <memory>
00041
00042 #include "exceptions.hpp"
00043 #include "code.hpp"
00044 #include "lexer.hpp"
00045 #include "dtdlexer.hpp"
00046 #include "parser.hpp"
00047 #include "dtdparser.hpp"
00048 #include "xsdlexer.hpp"
00049 #include "xsdparser.hpp"
00050 #include "wsdllexer.hpp"
00051 #include "wsdlparser.hpp"
00052 #include "moduleset.hpp"
00053 #include "module.hpp"
00054 #include "type.hpp"
00055 #include "generate.hpp"
00056 #include "datatool.hpp"
00057 #include "filecode.hpp"
00058 #include <serial/objistrxml.hpp>
00059 #include <serial/objostrxml.hpp>
00060 #include <serial/error_codes.hpp>
00061
00062
00063 #define NCBI_USE_ERRCODE_X Serial_DataTool
00064
00065
00066 BEGIN_NCBI_SCOPE
00067
00068 int CDataTool::Run(void)
00069 {
00070 if ( !ProcessModules() )
00071 return 1;
00072 if ( !ProcessData() )
00073 return 1;
00074 if ( !GenerateCode() )
00075 return 1;
00076
00077 return 0;
00078 }
00079
00080 CDataTool::CDataTool(void)
00081 {
00082 SetVersion( CVersionInfo(1,9,3) );
00083 }
00084
00085 void CDataTool::Init(void)
00086 {
00087 SetDiagPostLevel(eDiag_Warning);
00088
00089 auto_ptr<CArgDescriptions> d(new CArgDescriptions);
00090
00091 d->SetUsageContext("datatool", "work with ASN.1/XML data");
00092
00093
00094 d->AddKey("m", "moduleFile",
00095 "module file(s)",
00096 CArgDescriptions::eString,
00097 CArgDescriptions::fAllowMultiple);
00098 d->AddDefaultKey("M", "externalModuleFile",
00099 "external module file(s)",
00100 CArgDescriptions::eString, NcbiEmptyString,
00101 CArgDescriptions::fAllowMultiple);
00102 d->AddFlag("i",
00103 "ignore unresolved symbols");
00104 d->AddOptionalKey("f", "moduleFile",
00105 "write ASN.1 module file",
00106 CArgDescriptions::eOutputFile);
00107 d->AddOptionalKey("fx", "dtdFile",
00108 "write DTD file (\"-fx m\" writes modular DTD file)",
00109 CArgDescriptions::eOutputFile);
00110 d->AddOptionalKey("fxs", "XMLSchemaFile",
00111 "write XML Schema file (\"-fxs m\" writes modular Schema file)",
00112 CArgDescriptions::eOutputFile);
00113 d->AddOptionalKey("fd", "SpecificationDump",
00114 "write specification dump file (datatool internal format)",
00115 CArgDescriptions::eOutputFile);
00116 d->AddOptionalKey("ms", "moduleSuffix",
00117 "suffix of modular DTD or Schema file name",
00118 CArgDescriptions::eString);
00119
00120
00121 d->AddOptionalKey("v", "valueFile",
00122 "read value in ASN.1 text format",
00123 CArgDescriptions::eInputFile);
00124 d->AddOptionalKey("vx", "valueFile",
00125 "read value in XML format",
00126 CArgDescriptions::eInputFile);
00127 d->AddOptionalKey("d", "valueFile",
00128 "read value in ASN.1 binary format (-t is required)",
00129 CArgDescriptions::eInputFile);
00130 d->AddOptionalKey("t", "type",
00131 "binary value type (see \"-d\" argument)",
00132 CArgDescriptions::eString);
00133 d->AddOptionalKey("dn", "filename",
00134 "DTD module name in XML header (no extension). "
00135 "If empty, omit DOCTYPE line.",
00136 CArgDescriptions::eString);
00137 d->AddFlag("F",
00138 "read value completely into memory");
00139 d->AddOptionalKey("p", "valueFile",
00140 "write value in ASN.1 text format",
00141 CArgDescriptions::eOutputFile);
00142 d->AddOptionalKey("px", "valueFile",
00143 "write value in XML format",
00144 CArgDescriptions::eOutputFile);
00145 d->AddOptionalKey("pj", "valueFile",
00146 "write value in JSON format",
00147 CArgDescriptions::eOutputFile);
00148 d->AddOptionalKey("xmlns", "namespaceName",
00149 "XML namespace name",
00150 CArgDescriptions::eString);
00151 d->AddOptionalKey("e", "valueFile",
00152 "write value in ASN.1 binary format",
00153 CArgDescriptions::eOutputFile);
00154 d->AddFlag("sxo",
00155 "no scope prefixes in XML output");
00156 d->AddFlag("sxi",
00157 "no scope prefixes in XML input");
00158
00159
00160 d->AddOptionalKey("oex", "exportSpec",
00161 "class export specifier for MSVC",
00162 CArgDescriptions::eString);
00163 d->AddOptionalKey("od", "defFile",
00164 "code definition file",
00165 CArgDescriptions::eInputFile);
00166 d->AddFlag("odi",
00167 "silently ignore absent code definition file");
00168 d->AddFlag("odw",
00169 "issue a warning about absent code definition file");
00170 d->AddFlag("ods",
00171 "generate sample definition file");
00172 d->AddOptionalKey("of", "listFile",
00173 "write list of generated C++ files",
00174 CArgDescriptions::eOutputFile);
00175 d->AddOptionalKey("oc", "basename",
00176 "write combining C++ files",
00177 CArgDescriptions::eString);
00178 d->AddFlag("oA",
00179 "generate C++ files for all types");
00180 d->AddOptionalKey("ot", "types",
00181 "generate C++ files for listed types",
00182 CArgDescriptions::eString);
00183 d->AddOptionalKey("ox", "types",
00184 "exclude listed types from generation",
00185 CArgDescriptions::eString);
00186 d->AddFlag("oX",
00187 "turn off recursive type generation");
00188
00189 d->AddOptionalKey("on", "namespace",
00190 "default namespace",
00191 CArgDescriptions::eString);
00192
00193 d->AddOptionalKey("opm", "directory",
00194 "directory for searching source modules",
00195 CArgDescriptions::eString);
00196 d->AddOptionalKey("oph", "directory",
00197 "directory for generated *.hpp files",
00198 CArgDescriptions::eString);
00199 d->AddOptionalKey("opc", "directory",
00200 "directory for generated *.cpp files",
00201 CArgDescriptions::eString);
00202
00203 d->AddOptionalKey("or", "prefix",
00204 "add prefix to generated file names",
00205 CArgDescriptions::eString);
00206 d->AddFlag("orq",
00207 "use quoted syntax form for generated include files");
00208 d->AddFlag("ors",
00209 "add source file dir to generated file names");
00210 d->AddFlag("orm",
00211 "add module name to generated file names");
00212 d->AddFlag("orA",
00213 "combine all -or* prefixes");
00214 d->AddFlag("ocvs",
00215 "create \".cvsignore\" files");
00216 d->AddOptionalKey("oR", "rootDirectory",
00217 "set \"-o*\" arguments for NCBI directory tree",
00218 CArgDescriptions::eString);
00219
00220 d->AddFlag("oDc",
00221 "turn on generation of DOXYGEN-style comments");
00222 d->AddOptionalKey("odx", "URL",
00223 "URL of documentation root folder (for DOXYGEN)",
00224 CArgDescriptions::eString);
00225 d->AddFlag("lax_syntax",
00226 "allow non-standard ASN.1 syntax accepted by asntool");
00227 d->AddOptionalKey("pch", "file",
00228 "name of the precompiled header to include in all *.cpp files",
00229 CArgDescriptions::eString);
00230
00231 SetupArgDescriptions(d.release());
00232 }
00233
00234 bool CDataTool::ProcessModules(void)
00235 {
00236 const CArgs& args = GetArgs();
00237
00238
00239 if ( const CArgValue& od = args["od"] )
00240 generator.LoadConfig(od.AsString(), args["odi"], args["odw"]);
00241
00242 list<string> modulesPath;
00243 string opt;
00244
00245 if ( generator.GetOpt("oR", &opt) ) {
00246
00247 const string& rootDir = opt;
00248 generator.SetRootDir(rootDir);
00249 generator.SetHPPDir(Path(rootDir, "include"));
00250 string srcDir = Path(rootDir, "src");
00251 generator.SetCPPDir(srcDir);
00252 modulesPath.push_back(srcDir);
00253 generator.SetFileNamePrefixSource(eFileName_FromSourceFileName);
00254 generator.SetDefaultNamespace("NCBI_NS_NCBI::objects");
00255 }
00256
00257 if ( generator.GetOpt("opm", &opt) ) {
00258
00259 NStr::Split(opt, ",", modulesPath);
00260 }
00261
00262 SourceFile::EType srctype =
00263 LoadDefinitions(generator.GetMainModules(),
00264 modulesPath, args["m"].GetStringList(), false);
00265
00266 if (srctype == SourceFile::eASN) {
00267 LoadDefinitions(generator.GetImportModules(),
00268 modulesPath, args["M"].GetStringList(), true, srctype);
00269 }
00270
00271 if ( args["sxo"] ) {
00272 CDataType::SetEnforcedStdXml(true);
00273 }
00274
00275 if ( const CArgValue& f = args["f"] ) {
00276 generator.GetMainModules().PrintASN(f.AsOutputFile());
00277 f.CloseFile();
00278 }
00279 if ( const CArgValue& f = args["fd"] ) {
00280 generator.GetMainModules().PrintSpecDump(f.AsOutputFile());
00281 f.CloseFile();
00282 }
00283
00284 if ( const CArgValue& fx = args["fx"] ) {
00285 if (srctype == SourceFile::eDTD ||
00286 srctype == SourceFile::eXSD ||
00287 srctype == SourceFile::eWSDL) {
00288 CDataType::SetEnforcedStdXml(true);
00289 }
00290 if ( fx.AsString() == "m" ) {
00291 if ( const CArgValue& ms = args["ms"] ) {
00292 CDataTypeModule::SetModuleFileSuffix(ms.AsString());
00293 }
00294 generator.ResolveImportRefs();
00295 CDataType::EnableDTDEntities(true);
00296 generator.GetMainModules().PrintDTDModular();
00297 } else {
00298 generator.GetMainModules().PrintDTD(fx.AsOutputFile());
00299 fx.CloseFile();
00300 }
00301 }
00302
00303 if ( const CArgValue& ax = args["fxs"] ) {
00304 if (srctype == SourceFile::eDTD ||
00305 srctype == SourceFile::eXSD ||
00306 srctype == SourceFile::eWSDL) {
00307 CDataType::SetEnforcedStdXml(true);
00308 }
00309 if ( ax.AsString() == "m" ) {
00310 if ( const CArgValue& ms = args["ms"] ) {
00311 CDataTypeModule::SetModuleFileSuffix(ms.AsString());
00312 }
00313 generator.ResolveImportRefs();
00314 generator.GetMainModules().PrintXMLSchemaModular();
00315 } else {
00316 generator.GetMainModules().PrintXMLSchema(ax.AsOutputFile());
00317 ax.CloseFile();
00318 }
00319 }
00320
00321 if ( !generator.Check() ) {
00322 if ( !args["i"] ) {
00323 ERR_POST_X(1, "some types are unknown");
00324 return false;
00325 }
00326 else {
00327 ERR_POST_X(2, Warning << "some types are unknown: ignoring");
00328 }
00329 }
00330 return true;
00331 }
00332
00333 bool CDataTool::ProcessData(void)
00334 {
00335 const CArgs& args = GetArgs();
00336 bool stdXmlIn = false;
00337 if ( args["sxi"] ) {
00338 stdXmlIn = true;
00339 }
00340 bool stdXmlOut = false;
00341 if ( args["sxo"] ) {
00342 stdXmlOut = true;
00343 }
00344
00345
00346 ESerialDataFormat inFormat;
00347 string inFileName;
00348 const CArgValue& t = args["t"];
00349
00350 if ( const CArgValue& v = args["v"] ) {
00351 inFormat = eSerial_AsnText;
00352 inFileName = v.AsString();
00353 }
00354 else if ( const CArgValue& vx = args["vx"] ) {
00355 inFormat = eSerial_Xml;
00356 inFileName = vx.AsString();
00357 }
00358 else if ( const CArgValue& d = args["d"] ) {
00359 if ( !t ) {
00360 ERR_POST_X(3, "ASN.1 value type must be specified (-t)");
00361 return false;
00362 }
00363 inFormat = eSerial_AsnBinary;
00364 inFileName = d.AsString();
00365 }
00366 else
00367 return true;
00368
00369 auto_ptr<CObjectIStream>
00370 in(CObjectIStream::Open(inFormat, inFileName, eSerial_StdWhenAny));
00371 if (inFormat == eSerial_Xml) {
00372 CObjectIStreamXml *is = dynamic_cast<CObjectIStreamXml*>(in.get());
00373 if (stdXmlIn) {
00374 is->SetEnforcedStdXml(true);
00375 }
00376 is->SetDefaultStringEncoding(eEncoding_Unknown);
00377 }
00378
00379 string typeName;
00380 if ( t ) {
00381 typeName = t.AsString();
00382 in->ReadFileHeader();
00383 }
00384 else {
00385 typeName = in->ReadFileHeader();
00386 }
00387
00388 TTypeInfo typeInfo =
00389 generator.GetMainModules().ResolveInAnyModule(typeName, true)->
00390 GetTypeInfo().Get();
00391
00392
00393 ESerialDataFormat outFormat;
00394 string outFileName;
00395 bool use_nsName = false;
00396 string nsName;
00397
00398 if ( const CArgValue& p = args["p"] ) {
00399 outFormat = eSerial_AsnText;
00400 outFileName = p.AsString();
00401 }
00402 else if ( const CArgValue& px = args["px"] ) {
00403 outFormat = eSerial_Xml;
00404 outFileName = px.AsString();
00405 if ( const CArgValue& px_ns = args["xmlns"] ) {
00406 use_nsName = true;
00407 nsName = px_ns.AsString();
00408 }
00409 }
00410 else if ( const CArgValue& pj = args["pj"] ) {
00411 outFormat = eSerial_Json;
00412 outFileName = pj.AsString();
00413 }
00414 else if ( const CArgValue& e = args["e"] ) {
00415 outFormat = eSerial_AsnBinary;
00416 outFileName = e.AsString();
00417 }
00418 else {
00419
00420 outFormat = eSerial_None;
00421 }
00422
00423 if ( args["F"] ) {
00424
00425 AnyType value;
00426 in->Read(&value, typeInfo, CObjectIStream::eNoFileHeader);
00427 if ( outFormat != eSerial_None ) {
00428
00429 auto_ptr<CObjectOStream>
00430 out(CObjectOStream::Open(outFormat, outFileName,
00431 eSerial_StdWhenAny));
00432 if ( outFormat == eSerial_Xml ) {
00433 CObjectOStreamXml *os = dynamic_cast<CObjectOStreamXml*>(out.get());
00434 if (stdXmlOut) {
00435 os->SetEnforcedStdXml(true);
00436 }
00437 os->SetDefaultStringEncoding(eEncoding_Unknown);
00438 if (use_nsName) {
00439 os->SetReferenceSchema(true);
00440 if (!nsName.empty()) {
00441 os->SetDefaultSchemaNamespace(nsName);
00442 }
00443 }
00444
00445 if( const CArgValue& dn = args["dn"] ) {
00446 const string& name = dn.AsString();
00447 if ( name.empty() ) {
00448 os->SetReferenceDTD(false);
00449 }
00450 else {
00451 os->SetReferenceDTD(true);
00452 os->SetDTDFileName(name);
00453 }
00454 }
00455 }
00456 out->Write(&value, typeInfo);
00457 }
00458 }
00459 else {
00460 if ( outFormat != eSerial_None ) {
00461
00462 auto_ptr<CObjectOStream>
00463 out(CObjectOStream::Open(outFormat, outFileName,
00464 eSerial_StdWhenAny));
00465 if ( outFormat == eSerial_Xml ) {
00466 CObjectOStreamXml *os = dynamic_cast<CObjectOStreamXml*>(out.get());
00467 if (stdXmlOut) {
00468 os->SetEnforcedStdXml(true);
00469 }
00470 os->SetDefaultStringEncoding(eEncoding_Unknown);
00471 if (use_nsName) {
00472 os->SetReferenceSchema(true);
00473 if (!nsName.empty()) {
00474 os->SetDefaultSchemaNamespace(nsName);
00475 }
00476 }
00477
00478 if( const CArgValue& dn = args["dn"] ) {
00479 const string& name = dn.AsString();
00480 if ( name.empty() ) {
00481 os->SetReferenceDTD(false);
00482 }
00483 else {
00484 os->SetReferenceDTD(true);
00485 os->SetDTDFileName(name);
00486 }
00487 }
00488 }
00489 CObjectStreamCopier copier(*in, *out);
00490 copier.Copy(typeInfo, CObjectStreamCopier::eNoFileHeader);
00491
00492
00493 for (bool go=true; go; ) {
00494 try {
00495 copier.Copy(typeInfo);
00496 } catch (CEofException&) {
00497 go = false;
00498 }
00499 }
00500 }
00501 else {
00502
00503 in->Skip(typeInfo, CObjectIStream::eNoFileHeader);
00504 }
00505 }
00506 return true;
00507 }
00508
00509 bool CDataTool::GenerateCode(void)
00510 {
00511 string opt;
00512
00513
00514
00515
00516 if ( generator.GetOpt("oX") )
00517 generator.ExcludeRecursion();
00518 if ( generator.GetOpt("oA") )
00519 generator.IncludeAllMainTypes();
00520 if ( generator.GetOpt("ot", &opt) )
00521 generator.IncludeTypes(opt);
00522 if ( generator.GetOpt("ox", &opt) )
00523 generator.ExcludeTypes(opt);
00524
00525 if ( !generator.HaveGenerateTypes() )
00526 return true;
00527
00528
00529 if ( generator.GetOpt("oex", &opt) ) {
00530 string ex;
00531 ex = generator.GetConfig().Get("-","_export");
00532 if (ex.empty()) {
00533 ex = opt;
00534 }
00535 CClassCode::SetExportSpecifier(ex);
00536 }
00537
00538 {
00539 if ( generator.GetOpt("oDc") ) {
00540 CClassCode::SetDoxygenComments(true);
00541 if ( generator.GetOpt("odx", &opt) ) {
00542 string root = opt;
00543 if (root.empty()) {
00544
00545 root = "http://www.ncbi.nlm.nih.gov/IEB/ToolBox/CPP_DOC/lxr/source";
00546 }
00547 CClassCode::SetDocRootURL(root);
00548 }
00549 string group = generator.GetConfig().Get("-","_addtogroup_name");
00550 CClassCode::SetDoxygenGroup(group);
00551 group = generator.GetConfig().Get("-","_ingroup_name");
00552 generator.SetDoxygenIngroup(group);
00553 group = generator.GetConfig().Get("-","_addtogroup_description");
00554 generator.SetDoxygenGroupDescription(group);
00555 } else {
00556 CClassCode::SetDoxygenComments(false);
00557 }
00558 }
00559
00560
00561
00562
00563 opt = "";
00564 if ( generator.GetOpt("on", &opt) ) {
00565 generator.SetDefaultNamespace(opt);
00566 } else if (opt == "-") {
00567 generator.ResetDefaultNamespace();
00568 }
00569
00570
00571 if ( generator.GetOpt("oc", &opt) ) {
00572 const string& fileName = opt;
00573 generator.SetCombiningFileName(fileName);
00574 generator.SetFileListFileName(fileName+".files");
00575 }
00576 if ( generator.GetOpt("of", &opt) )
00577 generator.SetFileListFileName(opt);
00578
00579
00580 if ( generator.GetOpt("oph", &opt) )
00581 generator.SetHPPDir(opt);
00582 if ( generator.GetOpt("opc", &opt) )
00583 generator.SetCPPDir(opt);
00584
00585
00586 if ( generator.GetOpt("or", &opt) )
00587 generator.SetFileNamePrefix(opt);
00588 if ( generator.GetOpt("orq") )
00589 generator.UseQuotedForm(true);
00590 if ( generator.GetOpt("ocvs") )
00591 generator.CreateCvsignore(true);
00592 if ( generator.GetOpt("ors") )
00593 generator.SetFileNamePrefixSource(eFileName_FromSourceFileName);
00594 if ( generator.GetOpt("orm") )
00595 generator.SetFileNamePrefixSource(eFileName_FromModuleName);
00596 if ( generator.GetOpt("orA") )
00597 generator.SetFileNamePrefixSource(eFileName_UseAllPrefixes);
00598
00599
00600 if ( generator.GetOpt("pch", &opt) )
00601 CFileCode::SetPchHeader(opt);
00602
00603
00604 generator.GenerateCode();
00605
00606 if ( GetArgs()["ods"] ) {
00607 generator.GetMainModules().PrintSampleDEF(generator.GetCPPDir());
00608 }
00609 return true;
00610 }
00611
00612
00613 SourceFile::EType CDataTool::LoadDefinitions(
00614 CFileSet& fileSet, const list<string>& modulesPath,
00615 const CArgValue::TStringArray& nameList,
00616 bool split_names, SourceFile::EType srctype)
00617 {
00618 SourceFile::EType moduleType;
00619 list<string> names;
00620
00621 ITERATE (CArgValue::TStringArray, n, nameList) {
00622 if (split_names) {
00623 list<string> t;
00624 NStr::Split(*n, " ", t);
00625 names.insert(names.end(), t.begin(), t.end());
00626 } else {
00627 names.push_back(*n);
00628 }
00629 }
00630
00631 ITERATE ( list<string>, fi, names ) {
00632 const string& name = *fi;
00633 if ( !name.empty() ) {
00634 SourceFile fName(name, modulesPath);
00635 moduleType = fName.GetType();
00636
00637
00638 if (srctype == SourceFile::eUnknown) {
00639 if (moduleType == SourceFile::eUnknown) {
00640 moduleType = SourceFile::eASN;
00641 }
00642 srctype = moduleType;
00643 }
00644
00645 else {
00646 if (moduleType == SourceFile::eUnknown) {
00647 moduleType = srctype;
00648 }
00649
00650 else if (moduleType != srctype) {
00651 NCBI_THROW(CDatatoolException,eWrongInput,
00652 "Unable to process modules of different types"
00653 " simultaneously: "+name);
00654 }
00655 }
00656
00657 switch (moduleType) {
00658 default:
00659 NCBI_THROW(CDatatoolException,eWrongInput,"Unknown file type: "+name);
00660
00661 case SourceFile::eASN:
00662 {
00663 ASNLexer lexer(fName,name);
00664 lexer.AllowIDsEndingWithMinus(generator.GetOpt("lax_syntax"));
00665 ASNParser parser(lexer);
00666 fileSet.AddFile(parser.Modules(name));
00667 }
00668 break;
00669 case SourceFile::eDTD:
00670 {
00671 DTDLexer lexer(fName,name);
00672 DTDParser parser(lexer);
00673 fileSet.AddFile(parser.Modules(name));
00674 CDataType::SetXmlSourceSpec(true);
00675 }
00676 break;
00677 case SourceFile::eXSD:
00678 {
00679 XSDLexer lexer(fName,name);
00680 XSDParser parser(lexer);
00681 fileSet.AddFile(parser.Modules(name));
00682 CDataType::SetXmlSourceSpec(true);
00683 }
00684 break;
00685 case SourceFile::eWSDL:
00686 {
00687 WSDLLexer lexer(fName,name);
00688 WSDLParser parser(lexer);
00689 fileSet.AddFile(parser.Modules(name));
00690 CDataType::SetXmlSourceSpec(true);
00691 }
00692 break;
00693 }
00694 }
00695 }
00696 return srctype;
00697 }
00698
00699 END_NCBI_SCOPE
00700
00701
00702 int main(int argc, const char* argv[])
00703 {
00704 USING_NCBI_SCOPE;
00705 CException::EnableBackgroundReporting(false);
00706 return CDataTool().AppMain(argc, argv, 0, eDS_Default, 0, "datatool");
00707 }
00708
00709