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

Generated on Thu Jan 24 14:59:34 2008 for SMBIOS Library by  doxygen 1.5.4