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         if( doc )
00142         {
00143             DOMElement *root = xmlDocGetRootElement(doc);
00144 
00145             // This is pretty much the only checking we do
00146             // to ensure that the XML is valid.
00147             // maybe add some kind of schema validation in the future.
00148             string name = safeXMLChToString( root->getNodeName() );
00149             if ( ! (name == "STRUCTUREDEFS") )
00150                 throw ParseExceptionImpl("problem parsing xml file. root doc name not STRUCTUREDEFS.");
00151         }
00152     }
00153 
00154     unsigned int parseLengthStr(string size)
00155     {
00156        if (size == "BYTE")
00157            return 1;
00158        else if (size == "WORD")
00159            return 2;
00160        else if (size == "DWORD")
00161            return 4;
00162        else if (size == "QWORD")
00163            return 8;
00164 
00165        return strtol(size.c_str(), NULL, 0);
00166        //throw ParseExceptionImpl("Error parsing length information xml file. Invalid value." );
00167        //return 0;
00168     }
00169 
00170     void verifyElementAttr( const DOMElement *element, const string elementName, const string value )
00171     {
00172         string xmlValue = safeGetAttribute( element, elementName );
00173         if( value != xmlValue )
00174             throw ParseExceptionImpl("could not verify element attribute.");
00175     }
00176 
00177     // sneaky... :-)
00178     void verifyElementAttr( const DOMElement *element, const string elementName, unsigned int size )
00179     {
00180         string xmlValue = safeGetAttribute( element, elementName );
00181         if( size != parseLengthStr(xmlValue) )
00182             throw ParseExceptionImpl("could not verify element attribute was correct size.");
00183     }
00184 
00185     int getTypeForString( DOMDocument *doc, const string searchForDesc )
00186     {
00187         // find element with this description
00188         DOMElement *elem = findElement( xmlDocGetRootElement(doc), "STRUCTURE", "description", searchForDesc );
00189 
00190         // return the type as an INT.
00191         return strtol( safeGetAttribute( elem, "type" ).c_str(), 0, 0);
00192     }
00193 
00194     const string getStringForType(const DOMDocument *doc, const int searchForType )
00195     {
00196         // find matching element
00197         DOMElement *elem = 0;
00198         try
00199         {
00200             elem = findElementWithNumericAttr( xmlDocGetRootElement(doc), "STRUCTURE", "type", searchForType);
00201         }
00202         catch(const NotFound &)
00203         {
00204             elem = findElement( xmlDocGetRootElement(doc), "STRUCTURE", "type", "unknown");
00205         }
00206 
00207         // extract the description
00208         return safeGetAttribute( elem, "description");
00209     }
00210 
00211     //
00212     // MEMBER FUNCTIONS
00213     //
00214 
00215     // CONSTRUCTORS
00216     //
00217     // REGULAR CONSTRUCTOR
00218     SmbiosTableXml::SmbiosTableXml()
00219             : SmbiosTable(), xmlFile(""), parser(0), doc(0), xmlInitialized(false)
00220     {
00221         CHECK_VERSION_COMPAT;
00222         setXmlFilePath(xmlFile);
00223     }
00224 
00225     SmbiosTableXml::SmbiosTableXml(std::vector<SmbiosStrategy *> initStrategyList, bool strictValidation)
00226             : SmbiosTable(initStrategyList, strictValidation), xmlFile(""), parser(0), doc(0), xmlInitialized(false)
00227     {
00228         CHECK_VERSION_COMPAT;
00229         setXmlFilePath(xmlFile);
00230     }
00231 
00232     // DESTRUCTOR
00233     SmbiosTableXml::~SmbiosTableXml()
00234     {
00235         if (parser)
00236             xmlFreeParser(parser);
00237 
00238         if (doc)
00239             xmlFreeDoc(doc);
00240 
00241         if( xmlInitialized )
00242             FiniXML();
00243     }
00244 
00245 
00246     // good exception guarantee.
00247     // either we allocate new stuff, the new stuff validates, and we
00248     // set ourselves up with the new stuff, or we keep whatever we
00249     // used to have and raise the exception.
00250     void SmbiosTableXml::setXmlFilePath( std::string newFile )
00251     {
00252         try
00253         {
00254             // Initialize XML DOM subsystem
00255             if( ! xmlInitialized )
00256                 InitXML();
00257 
00258             xmlInitialized = true;
00259 
00260             DOMBuilder *newParser = getParser();
00261             DOMDocument *newdoc = getSmbiosXmlDoc( newParser, newFile );
00262             validateSmbiosXmlDoc( newdoc );
00263             // if we get to this point, that means the
00264             // new doc exists and is valid.
00265 
00266             if (parser)
00267                 xmlFreeParser(parser);
00268 
00269             if (doc)
00270                 xmlFreeDoc(doc);
00271 
00272             parser = newParser;
00273             xmlFile = newFile;
00274             doc = newdoc;
00275         }
00276         catch(const exception &toCatch)
00277         {
00278             cerr << "Error during XML Initialization.\n"
00279             << "  Exception message:"
00280             << toCatch.what() << endl;
00281             throw ParseExceptionImpl("XML initialization failed.");
00282         }
00283     }
00284 
00285     const DOMDocument *SmbiosTableXml::getXmlDoc() const
00286     {
00287         return doc;
00288     }
00289 
00290     int SmbiosTableXml::getTypeForString( const string searchForDesc ) const
00291     {
00292         return smbios::getTypeForString( doc, searchForDesc );
00293     }
00294 
00295     // only used by unit test code.
00296     const string SmbiosTableXml::getStringForType( const int searchForType ) const
00297     {
00298         return smbios::getStringForType( doc, searchForType );
00299     }
00300 
00301     // we were passed a string. convert to a number by looking up the
00302     // type for this string in the XML File
00303     // forward to base class operator[]
00304     SmbiosTable::iterator SmbiosTableXml::operator[] (const string &searchFor)
00305     {
00306         int type = getTypeForString( searchFor );
00307         return SmbiosTable::iterator (this, type);
00308     }
00309 
00310     // we were passed a string. convert to a number by looking up the
00311     // type for this string in the XML File
00312     // forward to base class operator[]
00313     SmbiosTable::const_iterator SmbiosTableXml::operator[](const string &searchFor) const
00314     {
00315         // this == const SmbiosTable();
00316         int type = getTypeForString( searchFor );
00317         return SmbiosTable::const_iterator (this, type);
00318     }
00319 
00320 
00321     static void getData_UsingXml(const ISmbiosItem &item, const string fieldName, void *out, size_t size )
00322     {
00323         DOMElement *element = 0;
00324 
00325         smbios::ISmbiosTable *table =
00326                     smbios::SmbiosFactory::getFactory()->getSingleton();
00327 
00328         const SmbiosTableXml *tableXml = dynamic_cast<const SmbiosTableXml *>(table);
00329         if(!tableXml)
00330             throw NotImplementedImpl();
00331 
00332         const DOMDocument *doc = tableXml->getXmlDoc();
00333 
00334         // get the element corresponding to the STRUCTURE user specified
00335         DOMElement *Structure = findElementWithNumericAttr( xmlDocGetRootElement(doc), "STRUCTURE", "type", item.getType() );
00336         element = findElement( Structure, "FIELD", "name", fieldName );
00337 
00338         // Is this the correct length?
00339         verifyElementAttr( element, "length", size );
00340 
00341         // call parent method to get actual data. :-)
00342         item.getData( getNumberFromXmlAttr(element, "offset", 0), out, size );
00343     }
00344 
00345     u8 getU8_FromItem(const ISmbiosItem &item, std::string field)
00346     {
00347         u8 retval = 0;
00348         getData_UsingXml(item, field, reinterpret_cast<u8 *>(&retval), sizeof(retval));
00349         return retval;
00350     }
00351 
00352     u16 getU16_FromItem(const ISmbiosItem &item, std::string field)
00353     {
00354         u16 retval = 0;
00355         getData_UsingXml(item, field, reinterpret_cast<u8 *>(&retval), sizeof(retval));
00356         return retval;
00357     }
00358 
00359     u32 getU32_FromItem(const ISmbiosItem &item, std::string field)
00360     {
00361         u32 retval = 0;
00362         getData_UsingXml(item, field, reinterpret_cast<u8 *>(&retval), sizeof(retval));
00363         return retval;
00364     }
00365 
00366     u64 getU64_FromItem(const ISmbiosItem &item, std::string field)
00367     {
00368         u64 retval = 0;
00369         getData_UsingXml(item, field, reinterpret_cast<u8 *>(&retval), sizeof(retval));
00370         return retval;
00371     }
00372 
00373     const char *getString_FromItem(const ISmbiosItem &item, std::string field)
00374     {
00375         DOMElement *element = 0;
00376 
00377         smbios::ISmbiosTable *table =
00378                     smbios::SmbiosFactory::getFactory()->getSingleton();
00379 
00380         const SmbiosTableXml *tableXml = dynamic_cast<const SmbiosTableXml *>(table);
00381         if(!tableXml)
00382             throw NotImplementedImpl();
00383 
00384         const DOMDocument *doc = tableXml->getXmlDoc();
00385 
00386         // get the element corresponding to the STRUCTURE user specified
00387         DOMElement *Structure = findElementWithNumericAttr( xmlDocGetRootElement(doc), "STRUCTURE", "type", item.getType() );
00388         element = findElement( Structure, "FIELD", "name", field );
00389 
00390         // Is this the correct length?
00391         verifyElementAttr( element, "length", 1 );
00392 
00393         // Is this an actual string?
00394         verifyElementAttr( element, "usage", "STRING" );
00395 
00396         // call parent method to get actual data. :-)
00397         return getString_FromItem(item, getNumberFromXmlAttr(element, "offset", 0) );
00398     }
00399 
00400     void *getBits_FromItem(const ISmbiosItem &item, const string field, const string bitField, void *out)
00401     {
00402         DOMElement *bitElement = 0;
00403         DOMElement *fieldElement = 0;
00404 
00405         smbios::ISmbiosTable *table =
00406                     smbios::SmbiosFactory::getFactory()->getSingleton();
00407 
00408         const SmbiosTableXml *tableXml = dynamic_cast<const SmbiosTableXml *>(table);
00409         if(!tableXml)
00410             throw NotImplementedImpl();
00411 
00412         const DOMDocument *doc = tableXml->getXmlDoc();
00413 
00414         try
00415         {
00416             DOMElement *Structure = findElementWithNumericAttr( xmlDocGetRootElement(doc), "STRUCTURE", "type", item.getType() );
00417             fieldElement = findElement( Structure, "FIELD", "name", field );
00418             bitElement = findElement( fieldElement, "BITS", "name", bitField );
00419         }
00420         catch (const NotFound & )
00421         {
00422             throw ParseExceptionImpl("could not fine bitfield name in xml file.");
00423         }
00424 
00425         // call parent method to get actual data. :-)
00426         return getBits_FromItem(item,
00427                    getNumberFromXmlAttr(fieldElement, "offset", 0),
00428                    out,
00429                    getNumberFromXmlAttr(bitElement, "lsb", 0),
00430                    getNumberFromXmlAttr(bitElement, "msb", 0)
00431                );
00432     }
00433 
00434     void printStructureField( std::ostream &cout, const DOMNode *node, const ISmbiosItem &item )
00435     {
00436         std::ios::fmtflags old_opts = cout.flags ();
00437         try
00438         {
00439             unsigned int length = parseLengthStr(safeGetAttribute( node, "length" ));
00440             string strOffset = safeGetAttribute( node, "offset" );
00441             unsigned int offset = strtol( strOffset.c_str(), 0, 0 );
00442 
00443             string usage = safeGetAttribute( node, "usage" );
00444             if (usage == "STRING")
00445             {
00446                 try
00447                 {
00448                     cout << getString_FromItem(item, offset);
00449                 }
00450                 catch(const StringUnavailable &)
00451                 {
00452                 }
00453             }
00454             else
00455             {
00456                 cout << hex << "0x";
00457                 for(unsigned int i=0;i<length; i++)
00458                 {
00459                     cout << setfill('0') << setw(2) << 
00460                         static_cast<int>(getU8_FromItem(item, offset + length - i - 1));
00461                 }
00462             }
00463         }
00464         catch( const std::exception & )
00465         {
00466             cout.flags (old_opts);
00467             throw;
00468         }
00469         cout.flags (old_opts);
00470     }
00471 
00472     std::ostream &SmbiosTableXml::streamify(ostream & cout) const
00473     {
00474         cout << "\nSMBIOS table " << endl;
00475         cout << "\tversion    : ";
00476         cout << static_cast<int>(table_header.major_ver) << ".";
00477         cout << static_cast<int>(table_header.minor_ver) << endl;
00478         cout << hex ;
00479         cout << "\taddress    : " << table_header.table_address << endl;
00480         cout << dec;
00481         cout << "\tlength     : " << table_header.table_length << endl;
00482         cout << "\tnum structs: " << table_header.table_num_structs << endl;
00483         cout << endl;
00484 
00485         SmbiosTable::const_iterator position = begin();
00486         while (position != end())
00487         {
00488              cout << *position << endl;
00489             ++position;
00490         }
00491         return cout;
00492     }
00493 
00494 
00495     /*********************************
00496       XML OUTPUT FUNCTIONS
00497       *******************************/
00498 
00499     std::ostream &toXmlString(const ISmbiosTable &table, ostream & cout)
00500     {
00501         UNREFERENCED_PARAMETER(table);
00502         cout << "XML output not yet supported in std lib." << endl;
00503         return cout;
00504     }
00505 
00506 }

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