import.cc
Go to the documentation of this file.
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 // Helpers
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 // Core function for loading
00031 // Loading is done in two passes:
00032 //  - first, we register all type names present and the associated xml nodes and loading functions
00033 //    by calling readNodes
00034 //  - second, we load the Type objects in dependency order by calling load
00035 namespace
00036 {
00037     // A factory function that builds a type object from a node description
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 // load loads the \c name type using the type nodes in \c remaining, which holds 
00060 // types defined in the tlb file that aren't loaded yet
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         // Do NOT pass name by reference. It could be destroyed by the
00088         // m_map.erase(it)
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                 // TODO check that the definition in the file
00112                 // TODO and the definition in the registry 
00113                 // TODO match
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 // Loading nodes
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         // We use zero size to indicate that the natural platform size should be
00185         // used
00186         if (has_size && size != 0)
00187         {
00188             // Update the size to match the one saved in the registry. This is to
00189             // allow a proper call to resize() later if needed.
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             //checkNodeName<UnexpectedElement>    (xml, "field");
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     // libXML is not really iostream-compatible :(
00318     // Get the whole document
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     // Loading from files seams to be broken on some distro's libxml2-packages, 
00350     // so we load the whole file into memory before parsing
00351     std::ifstream stream(path.c_str());
00352     load(stream, config, registry);
00353 }
00354 


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Thu Jan 2 2014 11:38:41