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