00001 #include "import.hh"
00002 #include "xmltools.hh"
00003 #include <limits.h>
00004
00005 #include <typelib/typemodel.hh>
00006 #include <typelib/typebuilder.hh>
00007 #include <typelib/registry.hh>
00008
00009 #include <iostream>
00010 #include <fstream>
00011
00012
00013 namespace
00014 {
00015 using namespace std;
00016 using namespace Typelib;
00017
00018 template<typename Cat>
00019 Cat getCategoryFromNode(Cat* categories, xmlChar const* name )
00020 {
00021 for(const Cat* cur_cat = categories; cur_cat->name; ++cur_cat)
00022 {
00023 if (!xmlStrcmp(name, cur_cat->name))
00024 return *cur_cat;
00025 }
00026 throw std::runtime_error(string("unrecognized XML node '") + reinterpret_cast<char const*>(name) + "'");
00027 }
00028 }
00029
00030
00031
00032
00033
00034
00035 namespace
00036 {
00037
00038 struct TypeNode;
00039 class Factory;
00040 typedef Type const* (*NodeLoader) (TypeNode const& type, Factory& factory);
00041
00042 struct TypeNode
00043 {
00044 xmlNodePtr xml;
00045 string name;
00046 string file;
00047 NodeLoader loader;
00048
00049 TypeNode
00050 ( xmlNodePtr node = 0
00051 , string const& name_ = string()
00052 , string const& file_ = string()
00053 , NodeLoader loader_ = 0 )
00054 : xml(node), name(name_), file(file_), loader(loader_) {}
00055 };
00056 typedef std::map<string, TypeNode> TypeMap;
00057 }
00058
00059
00060
00061 namespace
00062 {
00063 class Factory
00064 {
00065 TypeMap m_map;
00066 Registry& m_registry;
00067
00068 public:
00069 Factory(Registry& registry)
00070 : m_registry(registry) {}
00071
00072 Registry& getRegistry() { return m_registry; }
00073
00074 void insert(TypeNode const& type, Type* object)
00075 { m_registry.add(object, type.file); }
00076
00077 void alias (TypeNode const& type, string const& new_name)
00078 { m_registry.alias(new_name, type.name); }
00079
00080 void build(TypeMap const& map)
00081 {
00082 m_map = map;
00083 while(! m_map.empty())
00084 build(m_map.begin()->first);
00085 }
00086
00087
00088
00089 Type const* build(string const name)
00090 {
00091 string basename = TypeBuilder::getBaseTypename(name);
00092
00093 Type const* base = m_registry.get(basename);
00094 TypeMap::iterator it = m_map.find(basename);
00095
00096 if (! base)
00097 {
00098 if (it == m_map.end())
00099 throw Undefined(basename);
00100
00101 TypeNode type(it->second);
00102 m_map.erase(it);
00103
00104 base = type.loader(type, *this);
00105
00106 if (base->getName() != basename && !m_registry.has(basename, false))
00107 m_registry.alias(base->getName(), basename);
00108 }
00109 else if (it != m_map.end())
00110 {
00111
00112
00113
00114 m_map.erase(it);
00115 }
00116
00117 if (basename == name)
00118 return base;
00119
00120 Type const* derived = m_registry.build(name);
00121 if (derived->getName() != name && !m_registry.has(name, false))
00122 m_registry.alias(derived->getName(), name);
00123
00124 it = m_map.find(name);
00125 if (it != m_map.end())
00126 m_map.erase(it);
00127 return derived;
00128 }
00129 };
00130 }
00131
00132
00133 namespace
00134 {
00135 struct NumericCategory
00136 {
00137 const xmlChar* name;
00138 Numeric::NumericCategory type;
00139 };
00140 NumericCategory numeric_categories[] = {
00141 { reinterpret_cast<const xmlChar*>("sint"), Numeric::SInt },
00142 { reinterpret_cast<const xmlChar*>("uint"), Numeric::UInt },
00143 { reinterpret_cast<const xmlChar*>("float"), Numeric::Float },
00144 { 0, Numeric::SInt }
00145 };
00146 Type const* load_numeric(TypeNode const& node, Factory& factory)
00147 {
00148 NumericCategory category = getCategoryFromNode
00149 ( numeric_categories
00150 , reinterpret_cast<xmlChar const*>(getAttribute<string>(node.xml, "category").c_str()) );
00151 size_t size = getAttribute<size_t>(node.xml, "size");
00152
00153 Type* type = new Numeric(node.name, size, category.type);
00154 factory.insert(node, type);
00155 return type;
00156 }
00157 Type const* load_null(TypeNode const& node, Factory& factory)
00158 {
00159 Type* type = new NullType(node.name);
00160 factory.insert(node, type);
00161 return type;
00162 }
00163 Type const* load_opaque(TypeNode const& node, Factory& factory)
00164 {
00165 size_t size = getAttribute<size_t>(node.xml, "size");
00166 Type* type = new OpaqueType(node.name, size);
00167 factory.insert(node, type);
00168 return type;
00169 }
00170 Type const* load_container(TypeNode const& node, Factory& factory)
00171 {
00172 string indirect_name = getAttribute<string>(node.xml, "of");
00173 Type const* indirect = factory.build(indirect_name);
00174 string kind = getAttribute<string>(node.xml, "kind");
00175 bool has_size = false;
00176 int size = 0;
00177 try {
00178 size = getAttribute<int>(node.xml, "size");
00179 has_size = true;
00180 }
00181 catch(Parsing::MissingAttribute) {}
00182
00183 Type const* container = &Container::createContainer(factory.getRegistry(), kind, *indirect);
00184
00185
00186 if (has_size && size != 0)
00187 {
00188
00189
00190 factory.getRegistry().get_(*container).setSize(size);
00191 }
00192 return container;
00193 }
00194 Type const* load_enum(TypeNode const& node, Factory& factory)
00195 {
00196 Enum* type = new Enum(node.name);
00197 for(xmlNodePtr xml = node.xml->xmlChildrenNode; xml; xml=xml->next)
00198 {
00199 if (!xmlStrcmp(xml->name, reinterpret_cast<const xmlChar*>("text")))
00200 continue;
00201
00202 string symbol = getAttribute<string>(xml, "symbol");
00203 Enum::integral_type value = getAttribute<Enum::integral_type>(xml, "value");
00204 type->add(symbol, value);
00205 }
00206
00207 factory.insert(node, type);
00208 return type;
00209 }
00210 Type const* load_alias(TypeNode const& node, Factory& factory)
00211 {
00212 string source = getAttribute<string>(node.xml, "source");
00213 Type const* type = factory.build(source);
00214 factory.alias(node, source);
00215 return type;
00216 }
00217
00218
00219 Type const* load_compound(TypeNode const& node, Factory& factory)
00220 {
00221 Compound* compound = new Compound(node.name);
00222 size_t size = getAttribute<size_t>(node.xml, "size");
00223
00224 for(xmlNodePtr xml = node.xml->xmlChildrenNode; xml; xml=xml->next)
00225 {
00226 if (!xmlStrcmp(xml->name, reinterpret_cast<const xmlChar*>("text")))
00227 continue;
00228
00229
00230 string name = getAttribute<string>(xml, "name");
00231 string tname = getAttribute<string>(xml, "type");
00232 size_t offset = getAttribute<size_t>(xml, "offset");
00233
00234 Type const* type = factory.build(tname);
00235 compound->addField(name, *type, offset);
00236 }
00237
00238 compound->setSize(size);
00239 factory.insert(node, compound);
00240 return compound;
00241 }
00242 }
00243
00244
00245 namespace
00246 {
00247 struct NodeCategories
00248 {
00249 const xmlChar* name;
00250 NodeLoader loader;
00251 };
00252
00253 NodeCategories node_categories[] = {
00254 { reinterpret_cast<const xmlChar*>("alias"), load_alias },
00255 { reinterpret_cast<const xmlChar*>("numeric"), load_numeric },
00256 { reinterpret_cast<const xmlChar*>("null"), load_null },
00257 { reinterpret_cast<const xmlChar*>("opaque"), load_opaque },
00258 { reinterpret_cast<const xmlChar*>("enum"), load_enum },
00259 { reinterpret_cast<const xmlChar*>("compound"), load_compound },
00260 { reinterpret_cast<const xmlChar*>("container"), load_container },
00261 { 0, 0 }
00262 };
00263
00264 void load(string const& file, TypeMap& map, xmlNodePtr type_node)
00265 {
00266 string name = getStringAttribute(type_node, "name");
00267 NodeCategories cat = getCategoryFromNode(node_categories, type_node->name);
00268
00269 TypeMap::iterator it = map.find(name);
00270 if (it != map.end())
00271 {
00272 string old_file = it->second.file;
00273 std::clog << "Type " << name << " has already been defined in " << old_file << endl;
00274 std::clog << "\tThe definition found in " << file << " will be ignored" << endl;
00275 }
00276 else
00277 {
00278 string type_file = file;
00279 try { type_file = getStringAttribute(type_node, "source_id"); }
00280 catch(Parsing::MissingAttribute) {}
00281 map[name] = TypeNode(type_node, name, type_file, cat.loader);
00282 }
00283 }
00284
00285 void parse(std::string const& source_id, xmlDocPtr doc, Registry& registry)
00286 {
00287 if (!doc)
00288 throw Parsing::MalformedXML();
00289
00290 xmlNodePtr root_node = xmlDocGetRootElement(doc);
00291 if (!root_node)
00292 return;
00293
00294 checkNodeName<Parsing::BadRootElement>(root_node, "typelib");
00295
00296 TypeMap all_types;
00297 for(xmlNodePtr node = root_node -> xmlChildrenNode; node; node=node->next)
00298 {
00299 if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar*>("comment")))
00300 continue;
00301 if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar*>("text")))
00302 continue;
00303
00304 ::load(source_id, all_types, node);
00305 }
00306
00307 Factory factory(registry);
00308 factory.build(all_types);
00309 }
00310 }
00311
00312 void TlbImport::load
00313 ( std::istream& stream
00314 , utilmm::config_set const& config
00315 , Typelib::Registry& registry)
00316 {
00317
00318
00319 std::string document;
00320
00321 while (stream.good())
00322 {
00323 std::stringbuf buffer;
00324 stream >> &buffer;
00325 document += buffer.str();
00326 }
00327 xmlDocPtr doc = xmlParseMemory(document.c_str(), document.length());
00328 if (!doc)
00329 throw Parsing::MalformedXML();
00330
00331 try
00332 {
00333 parse("", doc, registry);
00334 xmlFreeDoc(doc);
00335 }
00336 catch(...)
00337 {
00338 xmlFreeDoc(doc);
00339 throw;
00340 }
00341 }
00342
00343
00344 void TlbImport::load
00345 ( std::string const& path
00346 , utilmm::config_set const& config
00347 , Typelib::Registry& registry)
00348 {
00349
00350
00351 std::ifstream stream(path.c_str());
00352 load(stream, config, registry);
00353 }
00354