00001 #include "export.hh"
00002 #include <iostream>
00003
00004 #include <typelib/typevisitor.hh>
00005 #include <typelib/plugins.hh>
00006
00007 #include <boost/algorithm/string/join.hpp>
00008 #include <boost/algorithm/string/split.hpp>
00009 #include <boost/algorithm/string/classification.hpp>
00010 #include <boost/algorithm/string/replace.hpp>
00011
00012 namespace
00013 {
00014 using namespace std;
00015 using namespace Typelib;
00016 using boost::split;
00017 using boost::join;
00018 using boost::is_any_of;
00019
00020 static list<string> nameSplit(std::string const& name)
00021 {
00022 list<string> separators;
00023 split(separators, name, is_any_of("/"), boost::token_compress_on);
00024 while(!separators.empty() && separators.front().empty())
00025 separators.pop_front();
00026 while(!separators.empty() && separators.back().empty())
00027 separators.pop_back();
00028 return separators;
00029 }
00030
00031 static size_t namespaceIndentLevel(std::string const& ns)
00032 {
00033 return nameSplit(ns).size();
00034 }
00035
00036 static string normalizeIDLName(std::string const& name)
00037 {
00038 unsigned int template_mark;
00039 string result = name;
00040 while ((template_mark = result.find_first_of("<>/,")) < result.length())
00041 result.replace(template_mark, 1, "_");
00042 return result;
00043 }
00044
00045 static string getIDLAbsoluteNamespace(std::string const& type_ns, IDLExport const& exporter)
00046 {
00047 string ns = type_ns;
00048 string prefix = exporter.getNamespacePrefix();
00049 string suffix = exporter.getNamespaceSuffix();
00050 if (!prefix.empty())
00051 ns = prefix + ns;
00052 if (!suffix.empty())
00053 ns += suffix;
00054 return ns;
00055 }
00056
00057 class IDLTypeIdentifierVisitor : public TypeVisitor
00058 {
00059 public:
00060 IDLExport const& m_exporter;
00061 string m_front, m_back;
00062 string m_namespace;
00063
00064 bool visit_(OpaqueType const& type);
00065 bool visit_(NullType const& type);
00066 bool visit_(Container const& type);
00067 bool visit_(Compound const& type);
00068
00069 bool visit_(Numeric const& type);
00070
00071 bool visit_(Pointer const& type);
00072 bool visit_(Array const& type);
00073
00074 bool visit_(Enum const& type);
00075
00076 IDLTypeIdentifierVisitor(IDLExport const& exporter)
00077 : m_exporter(exporter) {}
00078 string getTargetNamespace() const { return m_namespace; }
00079 std::string getIDLAbsolute(Type const& type, std::string const& field_name = "");
00080 std::string getIDLRelative(Type const& type, std::string const& field_name = "");
00081 pair<string, string> getIDLBase(Type const& type, std::string const& field_name = "");
00082 void apply(Type const& type)
00083 {
00084 m_namespace = getIDLAbsoluteNamespace(type.getNamespace(), m_exporter);
00085 TypeVisitor::apply(type);
00086 m_front = normalizeIDLName(m_front);
00087 }
00088 };
00089
00090 static bool isIDLBuiltinType(Type const& type)
00091 {
00092 if (type.getCategory() == Type::Numeric || type.getName() == "/std/string")
00093 return true;
00094 else if (type.getCategory() == Type::Array)
00095 {
00096 Type const& element_type = static_cast<Array const&>(type).getIndirection();
00097 return isIDLBuiltinType(element_type);
00098 }
00099 return false;
00100 }
00101
00105 static pair<string, string> getIDLBase(Type const& type, IDLExport const& exporter, std::string const& field_name = std::string())
00106 {
00107 std::string type_name;
00108 IDLTypeIdentifierVisitor visitor(exporter);
00109 visitor.apply(type);
00110 if (field_name.empty())
00111 return make_pair(visitor.getTargetNamespace(), visitor.m_front + visitor.m_back);
00112 else
00113 return make_pair(visitor.getTargetNamespace(), visitor.m_front + " " + field_name + visitor.m_back);
00114 }
00115
00119 static string getIDLRelative(Type const& type, std::string const& relative_to, IDLExport const& exporter, std::string const& field_name = std::string())
00120 {
00121 pair<string, string> base = getIDLBase(type, exporter, field_name);
00122 if (!base.first.empty())
00123 {
00124 std::string ns = getMinimalPathTo(base.first + type.getBasename(), relative_to);
00125 boost::replace_all(ns, Typelib::NamespaceMarkString, "::");
00126 return normalizeIDLName(ns) + base.second;
00127 }
00128 else return base.second;
00129 }
00130
00134 static string getIDLAbsolute(Type const& type, IDLExport const& exporter, std::string const& field_name = std::string())
00135 {
00136 pair<string, string> base = getIDLBase(type, exporter, field_name);
00137 if (!base.first.empty())
00138 {
00139 std::string ns = base.first;
00140 boost::replace_all(ns, Typelib::NamespaceMarkString, "::");
00141 return normalizeIDLName(ns) + base.second;
00142 }
00143 else return base.second;
00144 }
00145
00146 std::string IDLTypeIdentifierVisitor::getIDLAbsolute(Type const& type, std::string const& field_name)
00147 {
00148 return ::getIDLAbsolute(type, m_exporter, field_name);
00149 }
00150 std::string IDLTypeIdentifierVisitor::getIDLRelative(Type const& type, std::string const& field_name)
00151 {
00152 return ::getIDLRelative(type, m_namespace, m_exporter, field_name);
00153 }
00154 pair<string, string> IDLTypeIdentifierVisitor::getIDLBase(Type const& type, std::string const& field_name)
00155 {
00156 return ::getIDLBase(type, m_exporter, field_name);
00157 }
00158
00159 bool IDLTypeIdentifierVisitor::visit_(OpaqueType const& type)
00160 {
00161 if (m_exporter.marshalOpaquesAsAny())
00162 {
00163 m_namespace = "";
00164 m_front = "any";
00165 }
00166 else
00167 throw UnsupportedType(type, "opaque types are not allowed in IDL");
00168
00169 return true;
00170 }
00171 bool IDLTypeIdentifierVisitor::visit_(NullType const& type)
00172 { throw UnsupportedType(type, "null types are not supported for export in IDL, found " + type.getName()); }
00173 bool IDLTypeIdentifierVisitor::visit_(Container const& type)
00174 {
00175 if (type.getName() == "/std/string")
00176 {
00177 m_namespace = "";
00178 m_front = "string";
00179 }
00180 else
00181 {
00182
00183 m_namespace = getIDLBase(type.getIndirection()).first;
00184
00185
00186 if (m_namespace.empty())
00187 m_namespace = getIDLAbsoluteNamespace("/", m_exporter);
00188
00189 std::string container_kind = Typelib::getTypename(type.kind());
00190 std::string element_name = type.getIndirection().getName();
00191 boost::replace_all(element_name, Typelib::NamespaceMarkString, "_");
00192 boost::replace_all(element_name, " ", "_");
00193 m_front = container_kind + "_" + element_name + "_";
00194 }
00195
00196 return true;
00197 }
00198 bool IDLTypeIdentifierVisitor::visit_(Compound const& type)
00199 { m_front = type.getBasename();
00200 return true; }
00201 bool IDLTypeIdentifierVisitor::visit_(Numeric const& type)
00202 {
00203 m_namespace = "";
00204 if (type.getName() == "/bool")
00205 {
00206 m_front = "boolean";
00207 }
00208 else if (type.getNumericCategory() != Numeric::Float)
00209 {
00210 if (type.getNumericCategory() == Numeric::UInt && type.getSize() != 1)
00211 m_front = "unsigned ";
00212 switch (type.getSize())
00213 {
00214 case 1: m_front += "octet"; break;
00215 case 2: m_front += "short"; break;
00216 case 4: m_front += "long"; break;
00217 case 8: m_front += "long long"; break;
00218 }
00219 }
00220 else
00221 {
00222 if (type.getSize() == 4)
00223 m_front = "float";
00224 else
00225 m_front = "double";
00226 }
00227 return true;
00228 }
00229 bool IDLTypeIdentifierVisitor::visit_(Pointer const& type)
00230 { throw UnsupportedType(type, "pointer types are not supported for export in IDL"); }
00231 bool IDLTypeIdentifierVisitor::visit_(Array const& type)
00232 {
00233 if (type.getIndirection().getCategory() == Type::Array)
00234 throw UnsupportedType(type, "multi-dimensional arrays are not supported in IDL");
00235
00236 pair<string, string> element_t = getIDLBase(type.getIndirection());
00237 m_namespace = element_t.first;
00238 m_front = element_t.second;
00239 m_back = "[" + boost::lexical_cast<string>(type.getDimension()) + "]";
00240 return true;
00241 }
00242 bool IDLTypeIdentifierVisitor::visit_(Enum const& type)
00243 { m_front = type.getBasename();
00244 return true; }
00245
00246 class IDLExportVisitor : public TypeVisitor
00247 {
00248 public:
00249 IDLExport const& m_exporter;
00250 ostringstream m_stream;
00251 string m_indent;
00252 string m_namespace;
00253 std::map<std::string, Type const*>& m_exported_typedefs;
00254
00255 bool visit_(OpaqueType const& type);
00256 bool visit_(Container const& type);
00257 bool visit_(Compound const& type);
00258 bool visit_(Compound const& type, Field const& field);
00259
00260 bool visit_(Numeric const& type);
00261
00262 bool visit_(Pointer const& type);
00263 bool visit_(Array const& type);
00264
00265 bool visit_(Enum const& type);
00266
00267 IDLExportVisitor(Registry const& registry, IDLExport const& exporter, std::map<std::string, Type const*>& exported_typedefs);
00268 std::string getResult() const { return m_stream.str(); }
00269 std::string getTargetNamespace() const { return m_namespace; }
00270 void setTargetNamespace(std::string const& target_namespace)
00271 {
00272 size_t ns_size = namespaceIndentLevel(target_namespace);
00273 m_indent = string(ns_size * 4, ' ');
00274 m_namespace = target_namespace;
00275 }
00276 std::string getIDLAbsolute(Type const& type, std::string const& field_name = "");
00277 std::string getIDLRelative(Type const& type, std::string const& field_name = "");
00278 pair<string, string> getIDLBase(Type const& type, std::string const& field_name = "");
00279 void apply(Type const& type)
00280 {
00281 setTargetNamespace(getIDLAbsoluteNamespace(type.getNamespace(), m_exporter));
00282 TypeVisitor::apply(type);
00283 }
00284 };
00285
00286 std::string IDLExportVisitor::getIDLAbsolute(Type const& type,
00287 std::string const& field_name)
00288 {
00289 return ::getIDLAbsolute(type, m_exporter, field_name);
00290 }
00291 std::string IDLExportVisitor::getIDLRelative(Type const& type,
00292 std::string const& field_name)
00293 {
00294 return ::getIDLRelative(type, m_namespace, m_exporter, field_name);
00295 }
00296 pair<string, string> IDLExportVisitor::getIDLBase(Type const& type,
00297 std::string const& field_name)
00298 {
00299 return ::getIDLBase(type, m_exporter, field_name);
00300 }
00301
00302 struct Indent
00303 {
00304 string& m_indent;
00305 string m_save;
00306 Indent(string& current)
00307 : m_indent(current), m_save(current)
00308 { m_indent += " "; }
00309 ~Indent() { m_indent = m_save; }
00310 };
00311
00312 IDLExportVisitor::IDLExportVisitor(Registry const& registry, IDLExport const& exporter,
00313 std::map<std::string, Type const*>& exported_typedefs)
00314 : m_exporter(exporter)
00315 , m_exported_typedefs(exported_typedefs) {}
00316
00317 bool IDLExportVisitor::visit_(Compound const& type)
00318 {
00319 m_stream << m_indent << "struct " << normalizeIDLName(type.getBasename()) << " {\n";
00320
00321 { Indent indenter(m_indent);
00322 TypeVisitor::visit_(type);
00323 }
00324
00325 m_stream << m_indent
00326 << "};\n";
00327
00328 return true;
00329 }
00330 bool IDLExportVisitor::visit_(Compound const& type, Field const& field)
00331 {
00332 m_stream
00333 << m_indent
00334 << getIDLAbsolute(field.getType(), field.getName())
00335 << ";\n";
00336
00337 return true;
00338 }
00339
00340 bool IDLExportVisitor::visit_(Numeric const& type)
00341 {
00342
00343
00344 return true;
00345 }
00346
00347 bool IDLExportVisitor::visit_ (Pointer const& type)
00348 {
00349 throw UnsupportedType(type, "pointers are not allowed in IDL");
00350 return true;
00351 }
00352 bool IDLExportVisitor::visit_ (Array const& type)
00353 {
00354 throw UnsupportedType(type, "top-level arrays are not handled by the IDLExportVisitor");
00355 return true;
00356 }
00357
00358 bool IDLExportVisitor::visit_ (Enum const& type)
00359 {
00360 m_stream << m_indent << "enum " << type.getBasename() << " { ";
00361
00362 list<string> symbols;
00363 Enum::ValueMap const& values = type.values();
00364 Enum::ValueMap::const_iterator it, end = values.end();
00365 for (it = values.begin(); it != end; ++it)
00366 symbols.push_back(it->first);
00367 m_stream << join(symbols, ", ") << " };\n";
00368
00369 return true;
00370 }
00371
00372 bool IDLExportVisitor::visit_(Container const& type)
00373 {
00374 if (type.getName() == "/std/string")
00375 return true;
00376
00377
00378
00379
00380 string target_namespace = getIDLBase(type.getIndirection()).first;
00381
00382
00383 if (target_namespace.empty())
00384 target_namespace = getIDLAbsoluteNamespace("/", m_exporter);
00385 setTargetNamespace(target_namespace);
00386
00387 std::string element_name = getIDLAbsolute(type.getIndirection());
00388 std::string typedef_name = getIDLBase(type).second;
00389 boost::replace_all(typedef_name, "::", "_");
00390 m_stream << m_indent << "typedef sequence<" << element_name << "> " << typedef_name << ";\n";
00391 m_exported_typedefs.insert(make_pair(type.getIndirection().getNamespace() + typedef_name, &type));
00392
00393 return true;
00394 }
00395 bool IDLExportVisitor::visit_(OpaqueType const& type)
00396 {
00397 if (m_exporter.marshalOpaquesAsAny())
00398 return true;
00399
00400 throw UnsupportedType(type, "opaque types are not supported for export in IDL");
00401 }
00402 }
00403
00404 using namespace std;
00405 IDLExport::IDLExport()
00406 : m_namespace("/"), m_opaque_as_any(false) {}
00407
00408 bool IDLExport::marshalOpaquesAsAny() const { return m_opaque_as_any; }
00409
00410 void IDLExport::end
00411 ( ostream& stream
00412 , Typelib::Registry const& )
00413 {
00414 generateTypedefs(stream);
00415
00416
00417 closeNamespaces(stream, namespaceIndentLevel(m_namespace));
00418 }
00419
00420 void IDLExport::closeNamespaces(ostream& stream, int levels)
00421 {
00422 for (int i = 0; i < levels; ++i)
00423 {
00424 m_indent = std::string(m_indent, 0, m_indent.size() - 4);
00425 stream << "\n" << m_indent << "};\n";
00426 }
00427 }
00428
00429 void IDLExport::checkType(Type const& type)
00430 {
00431 if (type.getCategory() == Type::Pointer)
00432 throw UnsupportedType(type, "pointers are not allowed in IDL");
00433 if (type.getCategory() == Type::Array)
00434 {
00435 Type::Category pointed_to = static_cast<Indirect const&>(type).getIndirection().getCategory();
00436 if (pointed_to == Type::Array || pointed_to == Type::Pointer)
00437 throw UnsupportedType(type, "multi-dimensional arrays are not supported yet");
00438 }
00439
00440 }
00441
00442 void IDLExport::adaptNamespace(ostream& stream, string const& ns)
00443 {
00444 if (m_namespace != ns)
00445 {
00446 list<string>
00447 old_namespace = nameSplit(m_namespace),
00448 new_namespace = nameSplit(ns);
00449
00450 while(!old_namespace.empty() && !new_namespace.empty() && old_namespace.front() == new_namespace.front())
00451 {
00452 old_namespace.pop_front();
00453 new_namespace.pop_front();
00454 }
00455
00456 closeNamespaces(stream, old_namespace.size());
00457
00458 while (!new_namespace.empty())
00459 {
00460 stream << m_indent << "module " << normalizeIDLName(new_namespace.front()) << " {\n";
00461 m_indent += " ";
00462 new_namespace.pop_front();
00463 }
00464 }
00465 m_namespace = ns;
00466 }
00467
00468 std::string IDLExport::getIDLAbsolute(Type const& type) const
00469 {
00470 return ::getIDLAbsolute(type, *this);
00471 }
00472
00473 std::string IDLExport::getIDLRelative(Type const& type, std::string const& relative_to) const
00474 {
00475 return ::getIDLRelative(type, relative_to, *this);
00476 }
00477
00478 void IDLExport::save
00479 ( ostream& stream
00480 , utilmm::config_set const& config
00481 , Typelib::Registry const& type )
00482 {
00483 m_ns_prefix = config.get<std::string>("namespace_prefix", "");
00484 if (!m_ns_prefix.empty() && string(m_ns_prefix, 0, 1) != Typelib::NamespaceMarkString)
00485 m_ns_prefix = Typelib::NamespaceMarkString + m_ns_prefix;
00486 m_ns_suffix = config.get<std::string>("namespace_suffix", "");
00487 if (!m_ns_suffix.empty() && string(m_ns_suffix, m_ns_suffix.length() - 1, 1) != Typelib::NamespaceMarkString)
00488 m_ns_suffix += Typelib::NamespaceMarkString;
00489 m_blob_threshold = config.get<int>("blob_threshold", 0);
00490 m_opaque_as_any = config.get<bool>("opaque_as_any", false);
00491 list<string> selection = config.get< list<string> >("selected");
00492 m_selected_types = set<string>(selection.begin(), selection.end());
00493 return Exporter::save(stream, config, type);
00494 }
00495
00496 void IDLExport::generateTypedefs(ostream& stream)
00497 {
00498 for (TypedefMap::const_iterator it = m_typedefs.begin();
00499 it != m_typedefs.end(); ++it)
00500 {
00501 adaptNamespace(stream, it->first);
00502
00503 list<string> const& lines = it->second;
00504 for (list<string>::const_iterator str_it = lines.begin(); str_it != lines.end(); ++str_it)
00505 stream << m_indent << "typedef " << *str_it << std::endl;
00506 }
00507 }
00508
00509 std::string IDLExport::getNamespacePrefix() const
00510 {
00511 return m_ns_prefix;
00512 }
00513 std::string IDLExport::getNamespaceSuffix() const
00514 {
00515 return m_ns_suffix;
00516 }
00517
00518 bool IDLExport::save
00519 ( ostream& stream
00520 , Typelib::RegistryIterator const& type )
00521 {
00522 if (! m_selected_types.empty())
00523 {
00524 if (m_selected_types.count(type->getName()) == 0)
00525 {
00526 return false;
00527 }
00528 }
00529
00530 if (type.isAlias())
00531 {
00532
00533 if (type->getNamespace() != type.getNamespace()
00534 || (type->getBasename() != "struct " + type.getBasename()
00535 && type->getBasename() != "enum " + type.getBasename()
00536 && type.getBasename() != "struct " + type->getBasename()
00537 && type.getBasename() != "enum " + type->getBasename()))
00538 {
00539 IDLExport::checkType(*type);
00540 ostringstream stream;
00541
00542 std::string type_namespace = getIDLAbsoluteNamespace(type.getNamespace(), *this);
00543
00544 map<string, Type const*>::const_iterator already_exported =
00545 m_exported_typedefs.find(type.getName());
00546 if (already_exported != m_exported_typedefs.end())
00547 {
00548 if (*already_exported->second != *type)
00549 throw UnsupportedType(*type, "the typedef name " + type.getName() + " is reserved by the IDL exporter");
00550 return false;
00551 }
00552 else if (type.getBasename().find_first_of("/<>") != std::string::npos)
00553 {
00554 return false;
00555 }
00556
00557
00558
00559 if (type->getCategory() == Type::Array)
00560 {
00561 Array const& array_t = dynamic_cast<Array const&>(*type);
00562 stream
00563 << getIDLAbsolute(array_t.getIndirection())
00564 << " " << type.getBasename() << "[" << array_t.getDimension() << "];";
00565 }
00566 else if (type->getCategory() == Type::Container && type->getName() != "/std/string")
00567 {
00568
00569 Container const& container_t = dynamic_cast<Container const&>(*type);
00570 stream << "sequence<" << getIDLAbsolute(container_t.getIndirection()) << "> " << type.getBasename() << ";";
00571 }
00572 else if (type->getCategory() == Type::Opaque)
00573 {
00574 if (marshalOpaquesAsAny())
00575 stream << "any " << type.getBasename() << ";";
00576 }
00577 else if (type.getBasename().find_first_of(" ") == string::npos)
00578 stream << getIDLAbsolute(*type) << " " << type.getBasename() << ";";
00579
00580 std::string def = stream.str();
00581 if (!def.empty())
00582 m_typedefs[type_namespace].push_back(def);
00583 return true;
00584 }
00585 else return false;
00586 }
00587 else
00588 {
00589
00590
00591
00592
00593
00594
00595
00596
00597 if (m_blob_threshold && static_cast<int>(type->getSize()) > m_blob_threshold)
00598 {
00599 string target_namespace = getIDLAbsoluteNamespace(type.getNamespace(), *this);
00600 size_t ns_size = namespaceIndentLevel(target_namespace);
00601 string indent_string = string(ns_size * 4, ' ');
00602
00603 adaptNamespace(stream, target_namespace);
00604 stream << indent_string << "typedef sequence<octet> " << type->getBasename() << ";\n";
00605 return true;
00606 }
00607 else
00608 {
00609 IDLExportVisitor exporter(type.getRegistry(), *this, m_exported_typedefs);
00610 exporter.apply(*type);
00611
00612 string result = exporter.getResult();
00613 if (result.empty())
00614 return false;
00615 else
00616 {
00617 adaptNamespace(stream, exporter.getTargetNamespace());
00618 stream << result;
00619 return true;
00620 }
00621 }
00622 }
00623 }
00624
00625 TYPELIB_REGISTER_IO1(idl, IDLExport)
00626