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 else if (it != m_map.end())
00107 {
00108
00109
00110
00111 m_map.erase(it);
00112 }
00113
00114 if (basename == name)
00115 return base;
00116
00117 Type const* derived = m_registry.build(name);
00118 if (derived->getName() != name && !m_registry.has(name, false))
00119 m_registry.alias(derived->getName(), name);
00120
00121 it = m_map.find(name);
00122 if (it != m_map.end())
00123 m_map.erase(it);
00124 return derived;
00125 }
00126 };
00127 }
00128
00129
00130 namespace
00131 {
00132 struct NumericCategory
00133 {
00134 const xmlChar* name;
00135 Numeric::NumericCategory type;
00136 };
00137 NumericCategory numeric_categories[] = {
00138 { reinterpret_cast<const xmlChar*>("sint"), Numeric::SInt },
00139 { reinterpret_cast<const xmlChar*>("uint"), Numeric::UInt },
00140 { reinterpret_cast<const xmlChar*>("float"), Numeric::Float },
00141 { 0, Numeric::SInt }
00142 };
00143 Type const* load_numeric(TypeNode const& node, Factory& factory)
00144 {
00145 NumericCategory category = getCategoryFromNode
00146 ( numeric_categories
00147 , reinterpret_cast<xmlChar const*>(getAttribute<string>(node.xml, "category").c_str()) );
00148 size_t size = getAttribute<size_t>(node.xml, "size");
00149
00150 Type* type = new Numeric(node.name, size, category.type);
00151 factory.insert(node, type);
00152 return type;
00153 }
00154 Type const* load_null(TypeNode const& node, Factory& factory)
00155 {
00156 Type* type = new NullType(node.name);
00157 factory.insert(node, type);
00158 return type;
00159 }
00160 Type const* load_opaque(TypeNode const& node, Factory& factory)
00161 {
00162 size_t size = getAttribute<size_t>(node.xml, "size");
00163 Type* type = new OpaqueType(node.name, size);
00164 factory.insert(node, type);
00165 return type;
00166 }
00167 Type const* load_container(TypeNode const& node, Factory& factory)
00168 {
00169 string indirect_name = getAttribute<string>(node.xml, "of");
00170 Type const* indirect = factory.build(indirect_name);
00171 string kind = getAttribute<string>(node.xml, "kind");
00172 bool has_size = false;
00173 int size = 0;
00174 try {
00175 size = getAttribute<int>(node.xml, "size");
00176 has_size = true;
00177 }
00178 catch(Parsing::MissingAttribute) {}
00179
00180 Type const* container = &Container::createContainer(factory.getRegistry(), kind, *indirect);
00181
00182
00183 if (has_size && size != 0)
00184 {
00185
00186
00187 factory.getRegistry().get_(*container).setSize(size);
00188 }
00189 return container;
00190 }
00191 Type const* load_enum(TypeNode const& node, Factory& factory)
00192 {
00193 Enum* type = new Enum(node.name);
00194 for(xmlNodePtr xml = node.xml->xmlChildrenNode; xml; xml=xml->next)
00195 {
00196 if (!xmlStrcmp(xml->name, reinterpret_cast<const xmlChar*>("text")))
00197 continue;
00198
00199 string symbol = getAttribute<string>(xml, "symbol");
00200 Enum::integral_type value = getAttribute<Enum::integral_type>(xml, "value");
00201 type->add(symbol, value);
00202 }
00203
00204 factory.insert(node, type);
00205 return type;
00206 }
00207 Type const* load_alias(TypeNode const& node, Factory& factory)
00208 {
00209 string source = getAttribute<string>(node.xml, "source");
00210 Type const* type = factory.build(source);
00211 factory.alias(node, source);
00212 return type;
00213 }
00214
00215
00216 Type const* load_compound(TypeNode const& node, Factory& factory)
00217 {
00218 Compound* compound = new Compound(node.name);
00219 size_t size = getAttribute<size_t>(node.xml, "size");
00220
00221 for(xmlNodePtr xml = node.xml->xmlChildrenNode; xml; xml=xml->next)
00222 {
00223 if (!xmlStrcmp(xml->name, reinterpret_cast<const xmlChar*>("text")))
00224 continue;
00225
00226
00227 string name = getAttribute<string>(xml, "name");
00228 string tname = getAttribute<string>(xml, "type");
00229 size_t offset = getAttribute<size_t>(xml, "offset");
00230
00231 Type const* type = factory.build(tname);
00232 compound->addField(name, *type, offset);
00233 }
00234
00235 compound->setSize(size);
00236 factory.insert(node, compound);
00237 return compound;
00238 }
00239 }
00240
00241
00242 namespace
00243 {
00244 struct NodeCategories
00245 {
00246 const xmlChar* name;
00247 NodeLoader loader;
00248 };
00249
00250 NodeCategories node_categories[] = {
00251 { reinterpret_cast<const xmlChar*>("alias"), load_alias },
00252 { reinterpret_cast<const xmlChar*>("numeric"), load_numeric },
00253 { reinterpret_cast<const xmlChar*>("null"), load_null },
00254 { reinterpret_cast<const xmlChar*>("opaque"), load_opaque },
00255 { reinterpret_cast<const xmlChar*>("enum"), load_enum },
00256 { reinterpret_cast<const xmlChar*>("compound"), load_compound },
00257 { reinterpret_cast<const xmlChar*>("container"), load_container },
00258 { 0, 0 }
00259 };
00260
00261 void load(string const& file, TypeMap& map, xmlNodePtr type_node)
00262 {
00263 string name = getStringAttribute(type_node, "name");
00264 NodeCategories cat = getCategoryFromNode(node_categories, type_node->name);
00265
00266 TypeMap::iterator it = map.find(name);
00267 if (it != map.end())
00268 {
00269 string old_file = it->second.file;
00270 std::clog << "Type " << name << " has already been defined in " << old_file << endl;
00271 std::clog << "\tThe definition found in " << file << " will be ignored" << endl;
00272 }
00273 else
00274 {
00275 string type_file = file;
00276 try { type_file = getStringAttribute(type_node, "source_id"); }
00277 catch(Parsing::MissingAttribute) {}
00278 map[name] = TypeNode(type_node, name, type_file, cat.loader);
00279 }
00280 }
00281
00282 void parse(std::string const& source_id, xmlDocPtr doc, Registry& registry)
00283 {
00284 if (!doc)
00285 throw Parsing::MalformedXML();
00286
00287 try
00288 {
00289 xmlNodePtr root_node = xmlDocGetRootElement(doc);
00290 if (!root_node)
00291 return;
00292
00293 checkNodeName<Parsing::BadRootElement>(root_node, "typelib");
00294
00295 TypeMap all_types;
00296 for(xmlNodePtr node = root_node -> xmlChildrenNode; node; node=node->next)
00297 {
00298 if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar*>("comment")))
00299 continue;
00300 if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar*>("text")))
00301 continue;
00302
00303 ::load(source_id, all_types, node);
00304 }
00305
00306 Factory factory(registry);
00307 factory.build(all_types);
00308 }
00309 catch(...) {
00310 xmlFreeDoc(doc);
00311 throw;
00312 }
00313 }
00314 }
00315
00316 void TlbImport::load
00317 ( std::istream& stream
00318 , utilmm::config_set const& config
00319 , Typelib::Registry& registry)
00320 {
00321
00322
00323 std::string document;
00324
00325 while (stream.good())
00326 {
00327 std::stringbuf buffer;
00328 stream >> &buffer;
00329 document += buffer.str();
00330 }
00331 parse("", xmlParseMemory(document.c_str(), document.length()), registry);
00332 }
00333
00334
00335 void TlbImport::load
00336 ( std::string const& path
00337 , utilmm::config_set const& config
00338 , Typelib::Registry& registry)
00339 {
00340
00341
00342 std::ifstream stream(path.c_str());
00343 load(stream, config, registry);
00344 }
00345