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     void loadMetaData(xmlNodePtr node, MetaData& metadata)
00064     {
00065         for(xmlNodePtr xml = xmlFirstElementChild(node); xml; xml=xmlNextElementSibling(xml))
00066         {
00067             if (xmlStrcmp(xml->name, reinterpret_cast<const xmlChar*>("metadata")))
00068                 continue;
00069             string key = getAttribute<string>(xml, "key");
00070             string value;
00071             // Look at a child CDATA block
00072             xmlNodePtr cdata = xml->children;
00073             for(; cdata; cdata=cdata->next)
00074             {
00075                 if (cdata->type == XML_CDATA_SECTION_NODE)
00076                 {
00077                     value = reinterpret_cast<char const*>(cdata->content);
00078                     break;
00079                 }
00080             }
00081 
00082             metadata.add(key, value);
00083         }
00084     }
00085 
00086     void loadMetaData(TypeNode const& node, MetaData& metadata)
00087     {
00088         loadMetaData(node.xml, metadata);
00089     }
00090 
00091     class Factory
00092     {
00093         TypeMap   m_map;
00094         Registry& m_registry;
00095 
00096     public:
00097         Factory(Registry& registry)
00098             : m_registry(registry) {}
00099 
00100         Registry& getRegistry() { return m_registry; }
00101 
00102         void insert(TypeNode const& type, Type* object)
00103         {
00104             loadMetaData(type, object->getMetaData());
00105             m_registry.add(object, type.file);
00106         }
00107 
00108         void alias (TypeNode const& type, string const& new_name)
00109         { m_registry.alias(new_name, type.name); }
00110 
00111         void build(TypeMap const& map)
00112         {
00113             m_map = map;
00114             while(! m_map.empty())
00115                 build(m_map.begin()->first);
00116         }
00117 
00118         // Do NOT pass name by reference. It could be destroyed by the
00119         // m_map.erase(it)
00120         Type const* build(string const name)
00121         {
00122             string basename = TypeBuilder::getBaseTypename(name);
00123 
00124             Type const* base = m_registry.get(basename);
00125             TypeMap::iterator it = m_map.find(basename);
00126 
00127             if (! base)
00128             {
00129                 if (it == m_map.end())
00130                     throw Undefined(basename);
00131 
00132                 TypeNode    type(it->second);
00133                 m_map.erase(it);
00134 
00135                 base = type.loader(type, *this);
00136 
00137                 if (base->getName() != basename && !m_registry.has(basename, false))
00138                     m_registry.alias(base->getName(), basename);
00139             }
00140             else if (it != m_map.end())
00141             {
00142                 // TODO check that the definition in the file
00143                 // TODO and the definition in the registry 
00144                 // TODO match
00145                 m_map.erase(it);
00146             }
00147 
00148             if (basename == name)
00149                 return base;
00150 
00151             Type const* derived = m_registry.build(name);
00152             if (derived->getName() != name && !m_registry.has(name, false))
00153                 m_registry.alias(derived->getName(), name);
00154 
00155             it = m_map.find(name);
00156             if (it != m_map.end())
00157                 m_map.erase(it);
00158             return derived;
00159         }
00160     };
00161 }
00162 
00163 // Loading nodes
00164 namespace
00165 {
00166     struct NumericCategory
00167     {
00168         const xmlChar* name;
00169         Numeric::NumericCategory  type;
00170     };
00171     NumericCategory numeric_categories[] = {
00172         { reinterpret_cast<const xmlChar*>("sint"),  Numeric::SInt },
00173         { reinterpret_cast<const xmlChar*>("uint"),  Numeric::UInt },
00174         { reinterpret_cast<const xmlChar*>("float"), Numeric::Float },
00175         { 0, Numeric::SInt }
00176     };
00177     Type const* load_numeric(TypeNode const& node, Factory& factory)
00178     {
00179         NumericCategory category = getCategoryFromNode
00180             ( numeric_categories
00181             , reinterpret_cast<xmlChar const*>(getAttribute<string>(node.xml, "category").c_str()) );
00182         size_t      size = getAttribute<size_t>(node.xml, "size");
00183 
00184         Type* type = new Numeric(node.name, size, category.type);
00185         factory.insert(node, type);
00186         return type;
00187     }
00188     Type const* load_null(TypeNode const& node, Factory& factory)
00189     {
00190         Type* type = new NullType(node.name);
00191         factory.insert(node, type);
00192         return type;
00193     }
00194     Type const* load_opaque(TypeNode const& node, Factory& factory)
00195     {
00196         size_t size = getAttribute<size_t>(node.xml, "size");
00197         Type* type = new OpaqueType(node.name, size);
00198         factory.insert(node, type);
00199         return type;
00200     }
00201     Type const* load_container(TypeNode const& node, Factory& factory)
00202     {
00203         string indirect_name = getAttribute<string>(node.xml, "of");
00204         Type const* indirect = factory.build(indirect_name);
00205         string kind          = getAttribute<string>(node.xml, "kind");
00206         bool has_size = false;
00207         int size = 0;
00208         try { 
00209             size = getAttribute<int>(node.xml, "size");
00210             has_size = true;
00211         }
00212         catch(Parsing::MissingAttribute) {}
00213 
00214         Type const* container = &Container::createContainer(factory.getRegistry(), kind, *indirect);
00215         // We use zero size to indicate that the natural platform size should be
00216         // used
00217         if (has_size && size != 0)
00218         {
00219             // Update the size to match the one saved in the registry. This is to
00220             // allow a proper call to resize() later if needed.
00221             factory.getRegistry().get_(*container).setSize(size);
00222         }
00223         loadMetaData(node, container->getMetaData());
00224         return container;
00225     }
00226     Type const* load_enum(TypeNode const& node, Factory& factory)
00227     { 
00228         Enum* type = new Enum(node.name);
00229         for(xmlNodePtr xml = xmlFirstElementChild(node.xml); xml; xml=xmlNextElementSibling(xml))
00230         {
00231             if (xmlStrcmp(xml->name, reinterpret_cast<const xmlChar*>("value")))
00232                 continue;
00233 
00234             string symbol = getAttribute<string>(xml, "symbol");
00235             Enum::integral_type value  = getAttribute<Enum::integral_type>(xml, "value");
00236             type->add(symbol, value);
00237         }
00238 
00239         factory.insert(node, type); 
00240         return type;
00241     }
00242     Type const* load_alias(TypeNode const& node, Factory& factory)
00243     {
00244         string source = getAttribute<string>(node.xml, "source");
00245         Type const* type = factory.build(source);
00246         factory.alias(node, source);
00247         return type;
00248     }
00249 
00250     
00251     Type const* load_compound(TypeNode const& node, Factory& factory)
00252     {
00253         Compound* compound = new Compound(node.name);
00254         size_t size = getAttribute<size_t>(node.xml, "size");
00255 
00256         for(xmlNodePtr xml = xmlFirstElementChild(node.xml); xml; xml=xmlNextElementSibling(xml))
00257         {
00258             if (xmlStrcmp(xml->name, reinterpret_cast<const xmlChar*>("field")))
00259                 continue;
00260 
00261             //checkNodeName<UnexpectedElement>    (xml, "field");
00262             string name   = getAttribute<string>(xml, "name");
00263             string tname  = getAttribute<string>(xml, "type");
00264             size_t offset = getAttribute<size_t>(xml, "offset");
00265 
00266             Type const* type = factory.build(tname);
00267             Field const& field = compound->addField(name, *type, offset);
00268             loadMetaData(xml, field.getMetaData());
00269         }
00270 
00271         compound->setSize(size);
00272         factory.insert(node, compound);
00273         return compound;
00274     }
00275 }
00276 
00277 
00278 namespace
00279 {
00280     struct NodeCategories
00281     {
00282         const xmlChar* name;
00283         NodeLoader  loader;
00284     };
00285 
00286     NodeCategories node_categories[] = {
00287         { reinterpret_cast<const xmlChar*>("alias"),     load_alias },
00288         { reinterpret_cast<const xmlChar*>("numeric"),   load_numeric },
00289         { reinterpret_cast<const xmlChar*>("null"),      load_null },
00290         { reinterpret_cast<const xmlChar*>("opaque"),    load_opaque },
00291         { reinterpret_cast<const xmlChar*>("enum"),      load_enum },
00292         { reinterpret_cast<const xmlChar*>("compound"),  load_compound },
00293         { reinterpret_cast<const xmlChar*>("container"),  load_container },
00294         { 0, 0 }
00295     };
00296 
00297     void load(string const& file, TypeMap& map, xmlNodePtr type_node)
00298     {
00299         string name   = getStringAttribute(type_node, "name");
00300         NodeCategories cat = getCategoryFromNode(node_categories, type_node->name);
00301 
00302         TypeMap::iterator it = map.find(name);
00303         if (it != map.end())
00304         {
00305             string old_file = it->second.file;
00306             std::clog << "Type " << name << " has already been defined in " << old_file << endl;
00307             std::clog << "\tThe definition found in " << file << " will be ignored" << endl;
00308         }
00309         else
00310         {
00311             string type_file = file;
00312             try { type_file = getStringAttribute(type_node, "source_id"); }
00313             catch(Parsing::MissingAttribute) {}
00314             map[name] = TypeNode(type_node, name, type_file, cat.loader);
00315         }
00316     }
00317 
00318     void parse(std::string const& source_id, xmlDocPtr doc, Registry& registry)
00319     {
00320         if (!doc) 
00321             throw Parsing::MalformedXML("error parsing '"+source_id+"'");
00322 
00323         xmlNodePtr root_node = xmlDocGetRootElement(doc);
00324         if (!root_node) 
00325             return;
00326 
00327         checkNodeName<Parsing::BadRootElement>(root_node, "typelib");
00328 
00329         TypeMap all_types;
00330         for(xmlNodePtr node = root_node -> xmlChildrenNode; node; node=node->next)
00331         {
00332             if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar*>("comment")))
00333                 continue;
00334             if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar*>("text")))
00335                 continue;
00336 
00337             ::load(source_id, all_types, node);
00338         }
00339 
00340         Factory factory(registry);
00341         factory.build(all_types);
00342     }
00343 }
00344 
00345 void TlbImport::load
00346     ( std::istream& stream
00347     , utilmm::config_set const& config
00348     , Typelib::Registry& registry)
00349 {
00350     // libXML is not really iostream-compatible :(
00351     // Get the whole document
00352     std::string document;
00353 
00354     while (stream.good())
00355     {
00356         std::stringbuf buffer;
00357         stream >> &buffer;
00358         document += buffer.str();
00359     }
00360     xmlDocPtr doc = xmlParseMemory(document.c_str(), document.length());
00361     if (!doc) 
00362         throw Parsing::MalformedXML();
00363 
00364     try
00365     {
00366         // giving "" as source_id is rather counterproductive... later
00367         // errormessages are not informative anymore...
00368         parse("", doc, registry);
00369         xmlFreeDoc(doc);
00370     }
00371     catch(...)
00372     { 
00373         xmlFreeDoc(doc); 
00374         throw;
00375     }
00376 }
00377 
00378 
00379 void TlbImport::load
00380     ( std::string const& path
00381     , utilmm::config_set const& config
00382     , Typelib::Registry& registry)
00383 {
00384     // Loading from files seams to be broken on some distro's libxml2-packages, 
00385     // so we load the whole file into memory before parsing
00386     std::ifstream stream(path.c_str());
00387     if (!stream.good())
00388         throw Parsing::ImportError("problem opening '"+path+"' for import");
00389     load(stream, config, registry);
00390 }
00391 


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Sat Jun 8 2019 18:49:22