Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

SmbiosXml.cpp

Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=c:cindent:textwidth=0:
00003  *
00004  * Copyright (C) 2005 Dell Inc.
00005  *  by Michael Brown <Michael_E_Brown@dell.com>
00006  * Licensed under the Open Software License version 2.1
00007  *
00008  * Alternatively, you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published
00010  * by the Free Software Foundation; either version 2 of the License,
00011  * or (at your option) any later version.
00012 
00013  * This program is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00016  * See the GNU General Public License for more details.
00017  */
00018 
00019 // compat header should always be first header if including system headers
00020 #define LIBSMBIOS_SOURCE
00021 #include "smbios/compat.h"
00022 
00023 #include <sstream>
00024 #include <iomanip>
00025 
00026 #include "SmbiosXmlImpl.h"
00027 #include "StdSmbiosXml.h"
00028 #include "FactoryImpl2.h"
00029 #include "XmlUtils.h"
00030 
00031 // message.h should be included last.
00032 #include "smbios/message.h"
00033 
00034 // no trailing ';' because macro already has one
00035 SETUP_XML_NAMESPACE
00036 
00037 using namespace std;
00038 using namespace smbiosLowlevel;
00039 using namespace xmlutils;
00040 
00041 #if defined(DEBUG_SMBIOSXML)
00042 #   define DCOUT(line) do { cout << line; } while(0)
00043 #   define DCERR(line) do { cerr << line; } while(0)
00044 #else
00045 #   define DCOUT(line) do {} while(0)
00046 #   define DCERR(line) do {} while(0)
00047 #endif
00048 
00049 namespace smbios
00050 {
00051     //
00052     // FACTORY
00053     //
00054     SmbiosXmlFactory::~SmbiosXmlFactory() throw()
00055     {}
00056 
00057     class SmbiosXmlFactoryImpl: public SmbiosFactoryImpl
00058     {
00059     public:
00060         virtual ISmbiosTable *makeNew();
00061         SmbiosXmlFactoryImpl() : SmbiosFactoryImpl() {};
00062         virtual ~SmbiosXmlFactoryImpl() throw () {};
00063     };
00064 
00065     SmbiosFactory *SmbiosXmlFactory::getFactory()
00066     {
00067         // reinterpret_cast<...>(0) to ensure template parameter is correct
00068         // this is a workaround for VC6 which cannot use explicit member template
00069         // funciton initialization.
00070         return SmbiosFactoryImpl::getFactory(reinterpret_cast<SmbiosXmlFactoryImpl *>(0));
00071     }
00072 
00073     ISmbiosTable *SmbiosXmlFactoryImpl::makeNew()
00074     {
00075         // stupid, ugly hack to supress (C4800) warning on msvc++
00076         bool strict = getParameterNum("strictValidation") ? 1 : 0;
00077 
00078         SmbiosTableXml *table = 0;
00079 
00080         std::vector<SmbiosStrategy *> strategies;
00081 
00082         if (mode == AutoDetectMode)
00083         {
00084             strategies.push_back( new SmbiosMemoryStrategy(getParameterNum("offset")) );
00085 #ifdef LIBSMBIOS_PLATFORM_WIN32
00086             strategies.push_back( new SmbiosWinGetFirmwareTableStrategy() );
00087             strategies.push_back( new SmbiosWinWMIStrategy() );
00088 #endif
00089         }
00090         else if (mode == UnitTestMode)
00091         {
00092             strategies.push_back( new SmbiosMemoryStrategy(getParameterNum("offset")) );
00093         }
00094         else
00095         {
00096         throw NotImplementedImpl(_("Unknown smbios factory mode requested"));
00097         }
00098 
00099 
00100         table = new SmbiosTableXml( 
00101                 strategies,
00102                 strict 
00103             );
00104         table->setXmlFilePath( getParameterString("xmlFile") );
00105         table->initializeWorkaround();
00106         return table;
00107     }
00108 
00109 
00110     // if user give us a file with smbios xml information, use that
00111     // if there are any problems parsing the doc, or if they do not give us a
00112     // filename, use the built-in xml stuff.
00113     DOMDocument *getSmbiosXmlDoc( DOMBuilder *parser, std::string &xmlFile )
00114     {
00115         DOMDocument *doc = 0;
00116 
00117         // parse
00118         DCERR("Trying to parse file: '" << xmlFile << "'" << endl);
00119         // this is a macro that sets doc.
00120         compatXmlReadFile(parser, doc, xmlFile.c_str());
00121 
00122         if (!doc)
00123         {
00124             DCERR("Parse failed, no valid doc. Trying internal XML." << endl);
00125             // this is a macro that sets doc.
00126             compatXmlReadMemory(parser, doc, stdXml, strlen(stdXml));
00127         }
00128 
00129         if (!doc)
00130         {
00131             DCERR("Bad stuff... file parse failed and internal failed." << endl);
00132             throw ParseExceptionImpl("problem parsing xml file.");
00133         }
00134 
00135         DCERR("Returning doc."<< endl);
00136         return doc;
00137     }
00138 
00139     void validateSmbiosXmlDoc( DOMDocument *doc )
00140     {
00141         xmlNodePtr cur = xmlDocGetRootElement(doc);
00142     
00143         if (cur == NULL) 
00144         {
00145             fprintf(stderr,"empty document\n");
00146             xmlFreeDoc(doc);
00147             throw ParseExceptionImpl("problem parsing xml file. empty document.");
00148         }
00149         
00150         if (xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>("STRUCTUREDEFS"))) 
00151         {
00152             fprintf(stderr,"document of the wrong type, root node != story");
00153             xmlFreeDoc(doc);
00154             throw ParseExceptionImpl("problem parsing xml file. root doc name not STRUCTUREDEFS.");
00155         }
00156     }
00157 
00158     unsigned int parseLengthStr(string size)
00159     {
00160        if (size == "BYTE")
00161            return 1;
00162        else if (size == "WORD")
00163            return 2;
00164        else if (size == "DWORD")
00165            return 4;
00166        else if (size == "QWORD")
00167            return 8;
00168 
00169        return strtol(size.c_str(), NULL, 0);
00170        //throw ParseExceptionImpl("Error parsing length information xml file. Invalid value." );
00171        //return 0;
00172     }
00173 
00174     void verifyElementAttr( const DOMElement *element, const string elementName, const string value )
00175     {
00176         string xmlValue = safeGetAttribute( element, elementName );
00177         if( value != xmlValue )
00178             throw ParseExceptionImpl("could not verify element attribute.");
00179     }
00180 
00181     // sneaky... :-)
00182     void verifyElementAttr( const DOMElement *element, const string elementName, unsigned int size )
00183     {
00184         string xmlValue = safeGetAttribute( element, elementName );
00185         if( size != parseLengthStr(xmlValue) )
00186             throw ParseExceptionImpl("could not verify element attribute was correct size.");
00187     }
00188 
00189     int getTypeForString( DOMDocument *doc, const string searchForDesc )
00190     {
00191         // find element with this description
00192         DOMElement *elem = findElement( xmlDocGetRootElement(doc), "STRUCTURE", "description", searchForDesc );
00193 
00194         // return the type as an INT.
00195         return strtol( safeGetAttribute( elem, "type" ).c_str(), 0, 0);
00196     }
00197 
00198     const string getStringForType(const DOMDocument *doc, const int searchForType )
00199     {
00200         // find matching element
00201         DOMElement *elem = 0;
00202         try
00203         {
00204             elem = findElementWithNumericAttr( xmlDocGetRootElement(doc), "STRUCTURE", "type", searchForType);
00205         }
00206         catch(const NotFound &)
00207         {
00208             elem = findElement( xmlDocGetRootElement(doc), "STRUCTURE", "type", "unknown");
00209         }
00210 
00211         // extract the description
00212         return safeGetAttribute( elem, "description");
00213     }
00214 
00215     //
00216     // MEMBER FUNCTIONS
00217     //
00218 
00219     // CONSTRUCTORS
00220     //
00221     // REGULAR CONSTRUCTOR
00222     SmbiosTableXml::SmbiosTableXml()
00223             : SmbiosTable(), xmlFile(""), parser(0), doc(0), xmlInitialized(false)
00224     {
00225         CHECK_VERSION_COMPAT;
00226         setXmlFilePath(xmlFile);
00227     }
00228 
00229     SmbiosTableXml::SmbiosTableXml(std::vector<SmbiosStrategy *> initStrategyList, bool strictValidation)
00230             : SmbiosTable(initStrategyList, strictValidation), xmlFile(""), parser(0), doc(0), xmlInitialized(false)
00231     {
00232         CHECK_VERSION_COMPAT;
00233         setXmlFilePath(xmlFile);
00234     }
00235 
00236     // DESTRUCTOR
00237     SmbiosTableXml::~SmbiosTableXml()
00238     {
00239         if (parser)
00240             xmlFreeParser(parser);
00241 
00242         if (doc)
00243             xmlFreeDoc(doc);
00244 
00245         if( xmlInitialized )
00246             FiniXML();
00247     }
00248 
00249 
00250     // good exception guarantee.
00251     // either we allocate new stuff, the new stuff validates, and we
00252     // set ourselves up with the new stuff, or we keep whatever we
00253     // used to have and raise the exception.
00254     void SmbiosTableXml::setXmlFilePath( std::string newFile )
00255     {
00256         try
00257         {
00258             // Initialize XML DOM subsystem
00259             if( ! xmlInitialized )
00260                 InitXML();
00261 
00262             xmlInitialized = true;
00263 
00264             DOMBuilder *newParser = getParser();
00265             DOMDocument *newdoc = getSmbiosXmlDoc( newParser, newFile );
00266             validateSmbiosXmlDoc( newdoc );
00267             // if we get to this point, that means the
00268             // new doc exists and is valid.
00269 
00270             if (parser)
00271                 xmlFreeParser(parser);
00272 
00273             if (doc)
00274                 xmlFreeDoc(doc);
00275 
00276             parser = newParser;
00277             xmlFile = newFile;
00278             doc = newdoc;
00279         }
00280         catch(const exception &toCatch)
00281         {
00282             cerr << "Error during XML Initialization.\n"
00283             << "  Exception message:"
00284             << toCatch.what() << endl;
00285             throw ParseExceptionImpl("XML initialization failed.");
00286         }
00287     }
00288 
00289     const DOMDocument *SmbiosTableXml::getXmlDoc() const
00290     {
00291         return doc;
00292     }
00293 
00294     int SmbiosTableXml::getTypeForString( const string searchForDesc ) const
00295     {
00296         return smbios::getTypeForString( doc, searchForDesc );
00297     }
00298 
00299     // only used by unit test code.
00300     const string SmbiosTableXml::getStringForType( const int searchForType ) const
00301     {
00302         return smbios::getStringForType( doc, searchForType );
00303     }
00304 
00305     // we were passed a string. convert to a number by looking up the
00306     // type for this string in the XML File
00307     // forward to base class operator[]
00308     SmbiosTable::iterator SmbiosTableXml::operator[] (const string &searchFor)
00309     {
00310         int type = getTypeForString( searchFor );
00311         return SmbiosTable::iterator (this, type);
00312     }
00313 
00314     // we were passed a string. convert to a number by looking up the
00315     // type for this string in the XML File
00316     // forward to base class operator[]
00317     SmbiosTable::const_iterator SmbiosTableXml::operator[](const string &searchFor) const
00318     {
00319         // this == const SmbiosTable();
00320         int type = getTypeForString( searchFor );
00321         return SmbiosTable::const_iterator (this, type);
00322     }
00323 
00324 
00325     static void getData_UsingXml(const ISmbiosItem &item, const string fieldName, void *out, size_t size )
00326     {
00327         DOMElement *element = 0;
00328 
00329         smbios::ISmbiosTable *table =
00330                     smbios::SmbiosFactory::getFactory()->getSingleton();
00331 
00332         const SmbiosTableXml *tableXml = dynamic_cast<const SmbiosTableXml *>(table);
00333         if(!tableXml)
00334             throw NotImplementedImpl();
00335 
00336         const DOMDocument *doc = tableXml->getXmlDoc();
00337 
00338         // get the element corresponding to the STRUCTURE user specified
00339         DOMElement *Structure = findElementWithNumericAttr( xmlDocGetRootElement(doc), "STRUCTURE", "type", item.getType() );
00340         element = findElement( Structure, "FIELD", "name", fieldName );
00341 
00342         // Is this the correct length?
00343         verifyElementAttr( element, "length", size );
00344 
00345         // call parent method to get actual data. :-)
00346         item.getData( getNumberFromXmlAttr(element, "offset", 0), out, size );
00347     }
00348 
00349     u8 getU8_FromItem(const ISmbiosItem &item, std::string field)
00350     {
00351         u8 retval = 0;
00352         getData_UsingXml(item, field, reinterpret_cast<u8 *>(&retval), sizeof(retval));
00353         return retval;
00354     }
00355 
00356     u16 getU16_FromItem(const ISmbiosItem &item, std::string field)
00357     {
00358         u16 retval = 0;
00359         getData_UsingXml(item, field, reinterpret_cast<u8 *>(&retval), sizeof(retval));
00360         return retval;
00361     }
00362 
00363     u32 getU32_FromItem(const ISmbiosItem &item, std::string field)
00364     {
00365         u32 retval = 0;
00366         getData_UsingXml(item, field, reinterpret_cast<u8 *>(&retval), sizeof(retval));
00367         return retval;
00368     }
00369 
00370     u64 getU64_FromItem(const ISmbiosItem &item, std::string field)
00371     {
00372         u64 retval = 0;
00373         getData_UsingXml(item, field, reinterpret_cast<u8 *>(&retval), sizeof(retval));
00374         return retval;
00375     }
00376 
00377     const char *getString_FromItem(const ISmbiosItem &item, std::string field)
00378     {
00379         DOMElement *element = 0;
00380 
00381         smbios::ISmbiosTable *table =
00382                     smbios::SmbiosFactory::getFactory()->getSingleton();
00383 
00384         const SmbiosTableXml *tableXml = dynamic_cast<const SmbiosTableXml *>(table);
00385         if(!tableXml)
00386             throw NotImplementedImpl();
00387 
00388         const DOMDocument *doc = tableXml->getXmlDoc();
00389 
00390         // get the element corresponding to the STRUCTURE user specified
00391         DOMElement *Structure = findElementWithNumericAttr( xmlDocGetRootElement(doc), "STRUCTURE", "type", item.getType() );
00392         element = findElement( Structure, "FIELD", "name", field );
00393 
00394         // Is this the correct length?
00395         verifyElementAttr( element, "length", 1 );
00396 
00397         // Is this an actual string?
00398         verifyElementAttr( element, "usage", "STRING" );
00399 
00400         // call parent method to get actual data. :-)
00401         return getString_FromItem(item, getNumberFromXmlAttr(element, "offset", 0) );
00402     }
00403 
00404     void *getBits_FromItem(const ISmbiosItem &item, const string field, const string bitField, void *out)
00405     {
00406         DOMElement *bitElement = 0;
00407         DOMElement *fieldElement = 0;
00408 
00409         smbios::ISmbiosTable *table =
00410                     smbios::SmbiosFactory::getFactory()->getSingleton();
00411 
00412         const SmbiosTableXml *tableXml = dynamic_cast<const SmbiosTableXml *>(table);
00413         if(!tableXml)
00414             throw NotImplementedImpl();
00415 
00416         const DOMDocument *doc = tableXml->getXmlDoc();
00417 
00418         try
00419         {
00420             DOMElement *Structure = findElementWithNumericAttr( xmlDocGetRootElement(doc), "STRUCTURE", "type", item.getType() );
00421             fieldElement = findElement( Structure, "FIELD", "name", field );
00422             bitElement = findElement( fieldElement, "BITS", "name", bitField );
00423         }
00424         catch (const NotFound & )
00425         {
00426             throw ParseExceptionImpl("could not fine bitfield name in xml file.");
00427         }
00428 
00429         // call parent method to get actual data. :-)
00430         return getBits_FromItem(item,
00431                    getNumberFromXmlAttr(fieldElement, "offset", 0),
00432                    out,
00433                    getNumberFromXmlAttr(bitElement, "lsb", 0),
00434                    getNumberFromXmlAttr(bitElement, "msb", 0)
00435                );
00436     }
00437 
00438     void printStructureField( std::ostream &cout, const DOMNode *node, const ISmbiosItem &item )
00439     {
00440         std::ios::fmtflags old_opts = cout.flags ();
00441         try
00442         {
00443             unsigned int length = parseLengthStr(safeGetAttribute( node, "length" ));
00444             string strOffset = safeGetAttribute( node, "offset" );
00445             unsigned int offset = strtol( strOffset.c_str(), 0, 0 );
00446 
00447             string usage = safeGetAttribute( node, "usage" );
00448             if (usage == "STRING")
00449             {
00450                 try
00451                 {
00452                     cout << getString_FromItem(item, offset);
00453                 }
00454                 catch(const StringUnavailable &)
00455                 {
00456                 }
00457             }
00458             else
00459             {
00460                 cout << hex << "0x";
00461                 for(unsigned int i=0;i<length; i++)
00462                 {
00463                     cout << setfill('0') << setw(2) << 
00464                         static_cast<int>(getU8_FromItem(item, offset + length - i - 1));
00465                 }
00466             }
00467         }
00468         catch( const std::exception & )
00469         {
00470             cout.flags (old_opts);
00471             throw;
00472         }
00473         cout.flags (old_opts);
00474     }
00475 
00476     std::ostream &SmbiosTableXml::streamify(ostream & cout) const
00477     {
00478         cout << "\nSMBIOS table " << endl;
00479         cout << "\tversion    : ";
00480         cout << static_cast<int>(table_header.major_ver) << ".";
00481         cout << static_cast<int>(table_header.minor_ver) << endl;
00482         cout << hex ;
00483         cout << "\taddress    : " << table_header.table_address << endl;
00484         cout << dec;
00485         cout << "\tlength     : " << table_header.table_length << endl;
00486         cout << "\tnum structs: " << table_header.table_num_structs << endl;
00487         cout << endl;
00488 
00489         SmbiosTable::const_iterator position = begin();
00490         while (position != end())
00491         {
00492              cout << *position << endl;
00493             ++position;
00494         }
00495         return cout;
00496     }
00497 
00498 
00499     /*********************************
00500       XML OUTPUT FUNCTIONS
00501       *******************************/
00502 
00503     std::ostream &toXmlString(const ISmbiosTable &table, ostream & cout)
00504     {
00505         UNREFERENCED_PARAMETER(table);
00506         cout << "XML output not yet supported in std lib." << endl;
00507         return cout;
00508     }
00509 
00510 }

Generated on Wed Apr 11 16:25:10 2007 for SMBIOS Library by doxygen 1.3.5