SmbiosXml_xerces.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_xerces.h"
00027 #include "StdSmbiosXml.h"
00028 #include "../common/FactoryImpl2.h"
00029 #include "../smbios/SmbiosImpl.h"
00030 #include "../common/XmlUtils.h"
00031 
00032 // message.h should be included last.
00033 #include "smbios/message.h"
00034 
00035 XERCES_CPP_NAMESPACE_USE;
00036 using namespace std;
00037 using namespace smbiosLowlevel;
00038 using namespace xmlutils;
00039 
00040 namespace smbios
00041 {
00042     //
00043     // FACTORY
00044     //
00045 
00046     class SmbiosXmlFactoryImpl: public SmbiosFactoryImpl
00047     {
00048     public:
00049         virtual ISmbiosTable *makeNew();
00050         SmbiosXmlFactoryImpl() : SmbiosFactoryImpl() {};
00051         virtual ~SmbiosXmlFactoryImpl() throw () {};
00052     };
00053 
00054     SmbiosFactory *SmbiosXmlFactory::getFactory()
00055     {
00056         // reinterpret_cast<...>(0) to ensure template parameter is correct
00057         // this is a workaround for VC6 which cannot use explicit member template
00058         // funciton initialization.
00059         return SmbiosFactoryImpl::getFactory(reinterpret_cast<SmbiosXmlFactoryImpl *>(0));
00060     }
00061 
00062     ISmbiosTable *SmbiosXmlFactoryImpl::makeNew()
00063     {
00064         // stupid, ugly hack to supress (C4800) warning on msvc++
00065         bool strict = getParameterNum("strictValidation") ? 1 : 0;
00066 
00067         SmbiosTableXml *table = 0;
00068 
00069         std::vector<SmbiosStrategy *> strategies;
00070 
00071         if (mode == AutoDetectMode)
00072         {
00073             strategies.push_back( new SmbiosMemoryStrategy(getParameterNum("offset")) );
00074 #ifdef LIBSMBIOS_PLATFORM_WIN32
00075             strategies.push_back( new SmbiosWinGetFirmwareTableStrategy() );
00076             strategies.push_back( new SmbiosWinWMIStrategy() );
00077 #endif
00078         }
00079         else if (mode == UnitTestMode)
00080         {
00081             strategies.push_back( new SmbiosMemoryStrategy(getParameterNum("offset")) );
00082         }
00083         else
00084         {
00085         throw NotImplementedImpl(_("Unknown smbios factory mode requested"));
00086         }
00087 
00088 
00089         table = new SmbiosTableXml( 
00090                 strategies,
00091                 strict 
00092             );
00093         table->setXmlFilePath( getParameterString("xmlFile") );
00094         table->initializeWorkaround();
00095         return table;
00096     }
00097 
00098 
00099     // if user give us a file with smbios xml information, use that
00100     // if there are any problems parsing the doc, or if they do not give us a
00101     // filename, use the built-in xml stuff.
00102     DOMDocument *getSmbiosXmlDoc( DOMBuilder *parser, std::string &xmlFile )
00103     {
00104         DOMDocument *doc = 0;
00105 
00106         try
00107         {
00108             doc = parser->parseURI( xmlFile.c_str() );
00109         }
00110         // catch std::exception and below. Anything else is likely very
00111         // serious and should pass up raw.
00112         catch( const std::exception & )
00113         {
00114             cerr << "Error during Xerces-c parsing.\n";
00115             cerr << "Falling back to builtin XML." << endl;
00116         }
00117 
00118         // fall back to built-in xml file on any kind of error
00119         if( doc == 0 )
00120         {
00121             try
00122             {
00123                 // create SAX input source
00124                 size_t fileLen = strlen(stdXml);
00125                 unsigned int *lenPtr = reinterpret_cast<unsigned int *>(&fileLen);
00126                 MemBufInputSource* memBufIs = new MemBufInputSource(
00127                                                   reinterpret_cast<const XMLByte*>(stdXml),
00128                                                   *lenPtr,
00129                                                   "standard_xml",
00130                                                   false
00131                                               );
00132 
00133                 // wrap it with a DOM input source. DOM wrapper adopts the
00134                 // SAX, no need to delete.
00135                 DOMInputSource* Is = new Wrapper4InputSource( memBufIs );
00136 
00137                 doc = parser->parse( *Is );
00138 
00139                 delete Is;
00140             }
00141             // catch std::exception and below. Anything else is likely very
00142             // serious and should pass up raw.
00143             catch( const std::exception & )
00144             {
00145                 cerr << "Error during Xerces-c parsing builin XML.\n";
00146                 cerr << "This is really bad and probably not recoverable." << endl;
00147                 throw ParseExceptionImpl("problem parsing xml file.");
00148             }
00149 
00150         }
00151 
00152         return doc;
00153     }
00154 
00155     void validateSmbiosXmlDoc( DOMDocument *doc )
00156     {
00157         if( doc )
00158         {
00159             DOMElement *root = doc->getDocumentElement();
00160 
00161             // This is pretty much the only checking we do
00162             // to ensure that the XML is valid.
00163             // maybe add some kind of schema validation in the future.
00164             string name = safeXMLChToString( root->getNodeName() );
00165             if ( ! (name == "STRUCTUREDEFS") )
00166                 throw ParseExceptionImpl("problem parsing xml file. root doc name not STRUCTUREDEFS.");
00167         }
00168     }
00169 
00170     unsigned int parseLengthStr(string size)
00171     {
00172        if (size == "BYTE")
00173            return 1;
00174        else if (size == "WORD")
00175            return 2;
00176        else if (size == "DWORD")
00177            return 4;
00178        else if (size == "QWORD")
00179            return 8;
00180 
00181        return strtol(size.c_str(), NULL, 0);
00182        //throw ParseExceptionImpl("Error parsing length information xml file. Invalid value." );
00183        //return 0;
00184     }
00185 
00186     void verifyElementAttr( DOMElement *element, const string elementName, const string value )
00187     {
00188         string xmlValue = safeGetAttribute( element, elementName );
00189         if( value != xmlValue )
00190             throw ParseExceptionImpl("could not verify element attribute.");
00191     }
00192 
00193     // sneaky... :-)
00194     void verifyElementAttr( DOMElement *element, const string elementName, unsigned int size )
00195     {
00196         string xmlValue = safeGetAttribute( element, elementName );
00197         if( size != parseLengthStr(xmlValue) )
00198             throw ParseExceptionImpl("could not verify element attribute was correct size.");
00199     }
00200 
00201     int getTypeForString( DOMDocument *doc, const string searchForDesc )
00202     {
00203         // find element with this description
00204         DOMElement *elem = findElement( doc->getDocumentElement(), "STRUCTURE", "description", searchForDesc );
00205 
00206         // return the type as an INT.
00207         return strtol( safeGetAttribute( elem, "type" ).c_str(), 0, 0);
00208     }
00209 
00210     const string getStringForType(const DOMDocument *doc, const int searchForType )
00211     {
00212         // find matching element
00213         DOMElement *elem = 0;
00214         try
00215         {
00216             elem = findElementWithNumericAttr( doc->getDocumentElement(), "STRUCTURE", "type", searchForType);
00217         }
00218         catch(const NotFound &)
00219         {
00220             elem = findElement( doc->getDocumentElement(), "STRUCTURE", "type", "unknown");
00221         }
00222 
00223         // extract the description
00224         return safeGetAttribute( elem, "description");
00225     }
00226 
00227     //
00228     // MEMBER FUNCTIONS
00229     //
00230 
00231     // CONSTRUCTORS
00232     //
00233     // REGULAR CONSTRUCTOR
00234     SmbiosTableXml::SmbiosTableXml()
00235             : SmbiosTable(), xmlFile(""), parser(0), doc(0), xmlInitialized(false)
00236     {
00237         setXmlFilePath(xmlFile);
00238     }
00239 
00240     SmbiosTableXml::SmbiosTableXml(std::vector<SmbiosStrategy *> initStrategyList, bool strictValidation)
00241             : SmbiosTable(initStrategyList, strictValidation), xmlFile(""), parser(0), doc(0), xmlInitialized(false)
00242     {
00243         setXmlFilePath(xmlFile);
00244     }
00245 
00246     // DESTRUCTOR
00247     SmbiosTableXml::~SmbiosTableXml()
00248     {
00249         if(parser)
00250         {
00251             parser->resetDocumentPool();
00252             parser->release();
00253             parser = 0;
00254             doc = 0;
00255         }
00256         if( xmlInitialized )
00257             XMLPlatformUtils::Terminate();
00258     }
00259 
00260     ISmbiosItem &SmbiosTableXml::makeItem(const void *header) const
00261     {
00262         // not exception safe yet.
00263         const smbios_structure_header *structure =
00264             reinterpret_cast<const smbios_structure_header *>(header);
00265         SmbiosItemXml *item = new SmbiosItemXml( structure );
00266         item->setXmlFilePath( xmlFile, doc );
00267         if( ! initializing )
00268         {
00269             dynamic_cast<SmbiosItem*>(item)->fixup( workaround.get() );
00270         }
00271         return *item;
00272     }
00273 
00274 
00275     // good exception guarantee.
00276     // either we allocate new stuff, the new stuff validates, and we
00277     // set ourselves up with the new stuff, or we keep whatever we
00278     // used to have and raise the exception.
00279     void SmbiosTableXml::setXmlFilePath( std::string newFile )
00280     {
00281         try
00282         {
00283             // Initialize XML DOM subsystem
00284             if( ! xmlInitialized )
00285                 XMLPlatformUtils::Initialize();
00286 
00287             xmlInitialized = true;
00288 
00289             DOMBuilder *newParser = getParser();
00290             DOMDocument *newdoc = getSmbiosXmlDoc( newParser, newFile );
00291             validateSmbiosXmlDoc( newdoc );
00292             // if we get to this point, that means the
00293             // new doc exists and is valid.
00294 
00295             // clean up any old messes we may have laying around.
00296             // release old parser if one is allocated.
00297             DOMBuilder *oldParser = parser;
00298 
00299             parser = newParser;
00300             xmlFile = newFile;
00301             doc = newdoc;
00302 
00303             if( oldParser )
00304             {
00305                 oldParser->resetDocumentPool();
00306                 oldParser->release();
00307             }
00308         }
00309         catch(const XMLException &toCatch)
00310         {
00311             cerr << "Error during Xerces-c Initialization.\n"
00312             << "  Exception message:"
00313             << toCatch.getMessage() << endl;
00314             throw ParseExceptionImpl("xerces initialization failed.");
00315         }
00316     }
00317 
00318     const DOMDocument *SmbiosTableXml::getXmlDoc() const
00319     {
00320         return doc;
00321     }
00322 
00323     int SmbiosTableXml::getTypeForString( const string searchForDesc ) const
00324     {
00325         return smbios::getTypeForString( doc, searchForDesc );
00326     }
00327 
00328     // only used by unit test code.
00329     const string SmbiosTableXml::getStringForType( const int searchForType ) const
00330     {
00331         return smbios::getStringForType( doc, searchForType );
00332     }
00333 
00334     // we were passed a string. convert to a number by looking up the
00335     // type for this string in the XML File
00336     // forward to base class operator[]
00337     SmbiosTable::iterator SmbiosTableXml::operator[] (const string &searchFor)
00338     {
00339         int type = getTypeForString( searchFor );
00340         return SmbiosTable::iterator (this, type);
00341     }
00342 
00343     // we were passed a string. convert to a number by looking up the
00344     // type for this string in the XML File
00345     // forward to base class operator[]
00346     SmbiosTable::const_iterator SmbiosTableXml::operator[](const string &searchFor) const
00347     {
00348         // this == const SmbiosTable();
00349         int type = getTypeForString( searchFor );
00350         return SmbiosTable::const_iterator (this, type);
00351     }
00352 
00353 
00354     //
00355     // SmbiosItemXml members
00356     //
00357     void SmbiosItemXml::setXmlFilePath( const std::string newFile,  XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *newDoc )
00358     {
00359         xmlFile = newFile;
00360         doc = newDoc;
00361     }
00362 
00363     u8 SmbiosItemXml::getU8( const string fieldName ) const
00364     {
00365         DOMElement *element = 0;
00366 
00367         // get the element corresponding to the STRUCTURE user specified
00368         DOMElement *Structure = findElementWithNumericAttr( doc->getDocumentElement(), "STRUCTURE", "type", getType() );
00369         element = findElement( Structure, "FIELD", "name", fieldName );
00370 
00371         // Is this the correct length?
00372         verifyElementAttr( element, "length", 1 );
00373 
00374         // call parent method to get actual data. :-)
00375         return SmbiosItem::getU8( getNumberFromXmlAttr(element, "offset", 0) );
00376     }
00377 
00378     u16 SmbiosItemXml::getU16( const string fieldName ) const
00379     {
00380         DOMElement *element = 0;
00381 
00382         // get the element corresponding to the STRUCTURE user specified
00383         DOMElement *Structure = findElementWithNumericAttr( doc->getDocumentElement(), "STRUCTURE", "type", getType() );
00384         element = findElement( Structure, "FIELD", "name", fieldName );
00385 
00386         // Is this the correct length?
00387         verifyElementAttr( element, "length", 2 );
00388 
00389         // call parent method to get actual data. :-)
00390         return SmbiosItem::getU16( getNumberFromXmlAttr(element, "offset", 0) );
00391     }
00392 
00393     u32 SmbiosItemXml::getU32( const string fieldName ) const
00394     {
00395         DOMElement *element = 0;
00396 
00397         // get the element corresponding to the STRUCTURE user specified
00398         DOMElement *Structure = findElementWithNumericAttr( doc->getDocumentElement(), "STRUCTURE", "type", getType() );
00399         element = findElement( Structure, "FIELD", "name", fieldName );
00400 
00401         // Is this the correct length?
00402         verifyElementAttr( element, "length", 4 );
00403 
00404         // call parent method to get actual data. :-)
00405         return SmbiosItem::getU32( getNumberFromXmlAttr(element, "offset", 0) );
00406     }
00407 
00408     u64 SmbiosItemXml::getU64( const string fieldName ) const
00409     {
00410         DOMElement *element = 0;
00411 
00412         // get the element corresponding to the STRUCTURE user specified
00413         DOMElement *Structure = findElementWithNumericAttr( doc->getDocumentElement(), "STRUCTURE", "type", getType() );
00414         element = findElement( Structure, "FIELD", "name", fieldName );
00415 
00416         // Is this the correct length?
00417         verifyElementAttr( element, "length", 8 );
00418 
00419         // call parent method to get actual data. :-)
00420         return SmbiosItem::getU64( getNumberFromXmlAttr(element, "offset", 0) );
00421     }
00422 
00423     u32 SmbiosItemXml::getBitfield( const string field, const string bitField) const
00424     {
00425         DOMElement *bitElement = 0;
00426         DOMElement *fieldElement = 0;
00427 
00428         try
00429         {
00430             DOMElement *Structure = findElementWithNumericAttr( doc->getDocumentElement(), "STRUCTURE", "type", getType() );
00431             fieldElement = findElement( Structure, "FIELD", "name", field );
00432             bitElement = findElement( fieldElement, "BITS", "name", bitField );
00433         }
00434         catch (const NotFound & )
00435         {
00436             throw ParseExceptionImpl("could not fine bitfield name in xml file.");
00437         }
00438 
00439         // Is this the correct length?
00440         string length = safeGetAttribute( fieldElement, "length" );
00441         unsigned int lengthVal = 0;
00442         lengthVal = parseLengthStr(length);
00443 
00444         // call parent method to get actual data. :-)
00445         return SmbiosItem::getBitfield(
00446                    getNumberFromXmlAttr(fieldElement, "offset", 0),
00447                    lengthVal,
00448                    getNumberFromXmlAttr(bitElement, "lsb", 0),
00449                    getNumberFromXmlAttr(bitElement, "msb", 0)
00450                );
00451     }
00452 
00453     const char* SmbiosItemXml::getString( const string fieldName ) const
00454     {
00455         DOMElement *element = 0;
00456 
00457         // get the element corresponding to the STRUCTURE user specified
00458         DOMElement *Structure = findElementWithNumericAttr( doc->getDocumentElement(), "STRUCTURE", "type", getType() );
00459         element = findElement( Structure, "FIELD", "name", fieldName );
00460 
00461         // Is this the correct length?
00462         verifyElementAttr( element, "length", 1 );
00463 
00464         // Is this an actual string?
00465         verifyElementAttr( element, "usage", "STRING" );
00466 
00467         // call parent method to get actual data. :-)
00468         return SmbiosItem::getString( getNumberFromXmlAttr(element, "offset", 0) );
00469     }
00470 
00471     bool isBitSet(const ISmbiosItem *itemPtr, unsigned int offset, unsigned int bitToTest)
00472     {
00473         bool retval = false;
00474 
00475         unsigned int byte = bitToTest / 8;
00476         u8 fieldValue = itemPtr->getU8( offset + byte );
00477         if (fieldValue & (1 << (bitToTest%8)))
00478             retval = true;
00479 
00480         return retval;
00481     }
00482 
00483 
00484     void printStructureField( std::ostream &cout, const DOMNode *node, const ISmbiosItem &item )
00485     {
00486         std::ios::fmtflags old_opts = cout.flags ();
00487         try
00488         {
00489             unsigned int length = parseLengthStr(safeGetAttribute( node, "length" ));
00490             string strOffset = safeGetAttribute( node, "offset" );
00491             unsigned int offset = strtol( strOffset.c_str(), 0, 0 );
00492 
00493             string usage = safeGetAttribute( node, "usage" );
00494             if (usage == "STRING")
00495             {
00496                 try
00497                 {
00498                     cout << item.getString( offset );
00499                 }
00500                 catch(const StringUnavailable &)
00501                 {
00502                 }
00503             }
00504             else
00505             {
00506                 cout << hex << "0x";
00507                 for(unsigned int i=0;i<length; i++)
00508                 {
00509                     cout << setfill('0') << setw(2) << 
00510                         static_cast<int>(item.getU8(offset + length - i - 1));
00511                 }
00512             }
00513         }
00514         catch( const std::exception & )
00515         {
00516             cout.flags (old_opts);
00517             throw;
00518         }
00519         cout.flags (old_opts);
00520     }
00521 
00522     std::ostream &SmbiosItemXml::streamify( std::ostream &cout ) const
00523     {
00524         // If we don't have a ref to XML file, we cannot find this info
00525         if( ! doc )
00526             return SmbiosItem::streamify(cout);
00527 
00528         if (header == 0)
00529         {
00530             // TODO: this should be an exception...
00531             cout << "operator << on an uninitialized SmbiosItem!";
00532             return cout;
00533         }
00534 
00535         std::ios::fmtflags old_opts = cout.flags ();
00536 
00537         DOMElement *Structure = 0;
00538         cout << "DMI BLOCK: " << flush;
00539         try
00540         {
00541             cout << smbios::getStringForType( doc, getType() ) << endl;;
00542             Structure = findElementWithNumericAttr( doc->getDocumentElement(), "STRUCTURE", "type", getType());
00543         }
00544         catch ( const NotFound & )
00545         {
00546             Structure = findElement(doc->getDocumentElement(), "STRUCTURE", "type", "unknown");
00547         }
00548 
00549         XMLCh *tagName = X("FIELD"); // NEED TO 'release' !!!
00550         DOMNodeList *fieldList = Structure->getElementsByTagName(tagName);
00551         XMLString::release(&tagName);
00552 
00553         if( !fieldList )
00554             return cout;
00555 
00556         int length = fieldList->getLength();
00557         for( int index = 0; index < length; ++index )
00558         {
00559             DOMNode *node = fieldList->item( index );
00560             if( node->getNodeType() == DOMNode::ELEMENT_NODE )
00561             {
00562                 ostringstream tmpBuf("");
00563                 tmpBuf << "\t";
00564                 tmpBuf << safeGetAttribute( node, "name" );
00565                 tmpBuf << ": \t" ;
00566                 try
00567                 {
00568                     printStructureField( tmpBuf, node, *this );
00569                 }
00570                 catch(const exception &)
00571                 {
00572                     continue;
00573                 }
00574                 cout << tmpBuf.str() << endl;
00575             }
00576         }
00577 
00578         cout.flags (old_opts);
00579         return cout;
00580     }
00581 
00582     std::ostream &SmbiosTableXml::streamify(ostream & cout) const
00583     {
00584         cout << "\nSMBIOS table " << endl;
00585         cout << "\tversion    : ";
00586         cout << static_cast<int>(table_header.major_ver) << ".";
00587         cout << static_cast<int>(table_header.minor_ver) << endl;
00588         cout << hex ;
00589         cout << "\taddress    : " << table_header.table_address << endl;
00590         cout << dec;
00591         cout << "\tlength     : " << table_header.table_length << endl;
00592         cout << "\tnum structs: " << table_header.table_num_structs << endl;
00593         cout << endl;
00594 
00595         SmbiosTable::const_iterator position = begin();
00596         while (position != end())
00597         {
00598              cout << *position << endl;
00599             ++position;
00600         }
00601         return cout;
00602     }
00603 
00604 
00605     /*********************************
00606       XML OUTPUT FUNCTIONS
00607       *******************************/
00608 
00609     std::ostream &toXmlString(const ISmbiosTable &table, ostream & cout)
00610     {
00611         UNREFERENCED_PARAMETER(table);
00612         cout << "XML output not yet supported in std lib." << endl;
00613         return cout;
00614     }
00615 
00616 }

Generated on Tue Jan 17 02:59:08 2006 for SMBIOS Library by  doxygen 1.4.6