LCOV - code coverage report
Current view: top level - source/lib/sysdep - smbios.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 1 228 0.4 %
Date: 2023-01-19 00:18:29 Functions: 2 222 0.9 %

          Line data    Source code
       1             : /* Copyright (C) 2020 Wildfire Games.
       2             :  *
       3             :  * Permission is hereby granted, free of charge, to any person obtaining
       4             :  * a copy of this software and associated documentation files (the
       5             :  * "Software"), to deal in the Software without restriction, including
       6             :  * without limitation the rights to use, copy, modify, merge, publish,
       7             :  * distribute, sublicense, and/or sell copies of the Software, and to
       8             :  * permit persons to whom the Software is furnished to do so, subject to
       9             :  * the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included
      12             :  * in all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      15             :  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      16             :  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      17             :  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
      18             :  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
      19             :  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      20             :  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      21             :  */
      22             : 
      23             : /*
      24             :  * provide access to System Management BIOS information
      25             :  */
      26             : 
      27             : #include "precompiled.h"
      28             : #include "lib/sysdep/smbios.h"
      29             : 
      30             : #include "lib/bits.h"
      31             : #include "lib/alignment.h"
      32             : #include "lib/byte_order.h"   // FOURCC_BE
      33             : #include "lib/module_init.h"
      34             : 
      35             : #if OS_WIN
      36             : # include "lib/sysdep/os/win/wutil.h"
      37             : # include "lib/sysdep/os/win/wfirmware.h"
      38             : #endif
      39             : 
      40             : #include <cstring>
      41             : #include <sstream>
      42             : #include <vector>
      43             : 
      44             : namespace SMBIOS {
      45             : 
      46             : //-----------------------------------------------------------------------------
      47             : // GetTable
      48             : 
      49             : #if OS_WIN
      50             : 
      51             : static Status GetTable(wfirmware::Table& table)
      52             : {
      53             :     // (MSDN mentions 'RSMB', but multi-character literals are implementation-defined.)
      54             :     const DWORD provider = FOURCC_BE('R','S','M','B');
      55             : 
      56             :     // (MSDN says this will be 0, but we'll retrieve it for 100% correctness.)
      57             :     wfirmware::TableIds tableIds = wfirmware::GetTableIDs(provider);
      58             :     if(tableIds.empty())
      59             :         return ERR::_1; // NOWARN (happens on 32-bit XP)
      60             : 
      61             :     table = wfirmware::GetTable(provider, tableIds[0]);
      62             :     if(table.empty())
      63             :         WARN_RETURN(ERR::_2);
      64             : 
      65             :     // strip the WmiHeader
      66             :     struct WmiHeader
      67             :     {
      68             :         u8 used20CallingMethod;
      69             :         u8 majorVersion;
      70             :         u8 minorVersion;
      71             :         u8 dmiRevision;
      72             :         u32 length;
      73             :     };
      74             :     const WmiHeader* wmiHeader = (const WmiHeader*)&table[0];
      75             :     ENSURE(table.size() == sizeof(WmiHeader) + wmiHeader->length);
      76             :     memmove(&table[0], &table[sizeof(WmiHeader)], table.size()-sizeof(WmiHeader));
      77             : 
      78             :     return INFO::OK;
      79             : }
      80             : 
      81             : #endif  // OS_WIN
      82             : 
      83             : 
      84             : //-----------------------------------------------------------------------------
      85             : // strings
      86             : 
      87             : // pointers to the strings (if any) at the end of an SMBIOS structure
      88             : typedef std::vector<const char*> Strings;
      89             : 
      90           0 : static Strings ExtractStrings(const Header* header, const char* end, const Header*& next)
      91             : {
      92           0 :     Strings strings;
      93             : 
      94           0 :     const char* pos = ((const char*)header) + header->length;
      95           0 :     while(pos <= end-2)
      96             :     {
      97           0 :         if(*pos == '\0')
      98             :         {
      99           0 :             pos++;
     100           0 :             if(*pos == 0)
     101             :             {
     102           0 :                 pos++;
     103           0 :                 break;
     104             :             }
     105             :         }
     106             : 
     107           0 :         strings.push_back(pos);
     108           0 :         pos += strlen(pos);
     109             :     }
     110             : 
     111           0 :     next = (const Header*)pos;
     112           0 :     return strings;
     113             : }
     114             : 
     115             : 
     116             : // storage for all structures' strings (must be copied from the original
     117             : // wfirmware table since its std::vector container cannot be stored in a
     118             : // static variable because we may be called before _cinit)
     119             : static char* stringStorage;
     120             : static char* stringStoragePos;
     121             : 
     122             : // pointers to dynamically allocated structures
     123             : static Structures g_Structures;
     124             : 
     125           0 : static void Cleanup()   // called via atexit
     126             : {
     127           0 :     SAFE_FREE(stringStorage);
     128           0 :     stringStoragePos = 0;
     129             : 
     130             :     // free each allocated structure
     131             : #define STRUCTURE(name, id)\
     132             :     while(g_Structures.name##_)\
     133             :     {\
     134             :         name* next = g_Structures.name##_->next;\
     135             :         SAFE_FREE(g_Structures.name##_);\
     136             :         g_Structures.name##_ = next;\
     137             :     }
     138           0 :     STRUCTURES
     139             : #undef STRUCTURE
     140           0 : }
     141             : 
     142             : 
     143             : //-----------------------------------------------------------------------------
     144             : // FieldInitializer
     145             : 
     146             : // define function templates that invoke a Visitor for each of a structure's fields
     147             : #define FIELD(flags, type, name, units) visitor(flags, p.name, #name, units);
     148             : #define STRUCTURE(name, id) template<class Visitor> void VisitFields(name& p, Visitor& visitor) { name##_FIELDS }
     149           0 : STRUCTURES
     150             : #undef STRUCTURE
     151             : #undef FIELD
     152             : 
     153             : 
     154             : // initialize each of a structure's fields by copying from the SMBIOS data
     155             : class FieldInitializer
     156             : {
     157             :     NONCOPYABLE(FieldInitializer);  // reference member
     158             : public:
     159             :     FieldInitializer(const Header* header, const Strings& strings)
     160             :         : data((const u8*)(header+1))
     161             :         , end((const u8*)header + header->length)
     162             :         , strings(strings)
     163             :     {
     164             :     }
     165             : 
     166             :     template<typename Field>
     167           0 :     void operator()(size_t flags, Field& field, const char* UNUSED(name), const char* UNUSED(units))
     168             :     {
     169           0 :         if((flags & F_DERIVED) || data >= end)
     170             :         {
     171           0 :             field = Field();
     172           0 :             return;
     173             :         }
     174             : 
     175           0 :         Read(field, 0); // SFINAE
     176             :     }
     177             : 
     178             : private:
     179             :     template<typename T>
     180           0 :     T ReadValue()
     181             :     {
     182             :         T value;
     183           0 :         memcpy(&value, data, sizeof(value));
     184           0 :         data += sizeof(value);
     185           0 :         return value;
     186             :     }
     187             : 
     188             :     // construct from SMBIOS representations that don't match the
     189             :     // actual type (e.g. enum)
     190             :     template<typename Field>
     191             :     void Read(Field& field, typename Field::T*)
     192             :     {
     193             :         field = Field(ReadValue<typename Field::T>());
     194             :     }
     195             : 
     196             :     template<typename Field>
     197           0 :     void Read(Field& field, ...)
     198             :     {
     199           0 :         field = ReadValue<Field>();
     200           0 :     }
     201             : 
     202             :     const u8* data;
     203             :     const u8* end;
     204             :     const Strings& strings;
     205             : };
     206             : 
     207             : 
     208             : // C++03 14.7.3(2): "An explicit specialization shall be declared [..] in the
     209             : // namespace of which the enclosing class [..] is a member.
     210             : 
     211             : // (this specialization avoids a "forcing value to bool true or false" warning)
     212             : template<>
     213           0 : void FieldInitializer::operator()<bool>(size_t flags, bool& UNUSED(t), const char* UNUSED(name), const char* UNUSED(units))
     214             : {
     215             :     // SMBIOS doesn't specify any individual booleans, so we're only called for
     216             :     // derived fields and don't need to do anything.
     217           0 :     ENSURE(flags & F_DERIVED);
     218           0 : }
     219             : 
     220             : template<>
     221           0 : void FieldInitializer::operator()<const char*>(size_t flags, const char*& t, const char* UNUSED(name), const char* UNUSED(units))
     222             : {
     223           0 :     t = 0;  // (allow immediate `return' when the string is found to be invalid)
     224             : 
     225             :     u8 number;
     226           0 :     operator()(flags, number, 0, 0);
     227           0 :     if(number == 0) // no string given
     228           0 :         return;
     229             : 
     230           0 :     if(number > strings.size())
     231             :     {
     232           0 :         debug_printf("SMBIOS: invalid string number %d (count=%d)\n", number, (int)strings.size());
     233           0 :         return;
     234             :     }
     235             : 
     236             :     // copy to stringStorage
     237           0 :     strcpy(stringStoragePos, strings[number-1]);
     238           0 :     t = stringStoragePos;
     239           0 :     stringStoragePos += strlen(t)+1;
     240             : }
     241             : 
     242             : 
     243             : //-----------------------------------------------------------------------------
     244             : // Fixup (e.g. compute derived fields)
     245             : 
     246             : template<class Structure>
     247             : void Fixup(Structure& UNUSED(structure))
     248             : {
     249             :     // primary template: do nothing
     250             : }
     251             : 
     252             : template<>
     253           0 : void Fixup<Bios>(Bios& p)
     254             : {
     255           0 :     p.size = size_t(p.encodedSize+1) * 64*KiB;
     256           0 : }
     257             : 
     258             : template<>
     259           0 : void Fixup<Processor>(Processor& p)
     260             : {
     261           0 :     p.populated = (p.status & 0x40) != 0;
     262           0 :     p.status = (ProcessorStatus)bits(p.status, 0, 2);
     263             : 
     264           0 :     if(p.voltage & 0x80)
     265           0 :         p.voltage &= ~0x80;
     266             :     else
     267             :     {
     268             :         // (arbitrarily) report the lowest supported value
     269           0 :         if(IsBitSet(p.voltage, 0))
     270           0 :             p.voltage = 50;
     271           0 :         if(IsBitSet(p.voltage, 1))
     272           0 :             p.voltage = 33;
     273           0 :         if(IsBitSet(p.voltage, 2))
     274           0 :             p.voltage = 29;
     275             :     }
     276           0 : }
     277             : 
     278             : template<>
     279           0 : void Fixup<Cache>(Cache& p)
     280             : {
     281             :     struct DecodeSize
     282             :     {
     283           0 :         u64 operator()(u16 size) const
     284             :         {
     285           0 :             const size_t granularity = IsBitSet(size, 15)? 64*KiB : 1*KiB;
     286           0 :             return u64(bits(size, 0, 14)) * granularity;
     287             :         }
     288             :     };
     289           0 :     p.maxSize = DecodeSize()(p.maxSize16);
     290           0 :     p.installedSize = DecodeSize()(p.installedSize16);
     291           0 :     p.level = bits(p.configuration, 0, 2)+1;
     292           0 :     p.location = (CacheLocation)bits(p.configuration, 5, 6);
     293           0 :     p.mode = (CacheMode)bits(p.configuration, 8, 9);
     294           0 :     p.configuration = (CacheConfigurationFlags)(p.configuration & ~0x367);
     295           0 : }
     296             : 
     297             : template<>
     298           0 : void Fixup<SystemSlot>(SystemSlot& p)
     299             : {
     300             :     // (only initialize function and device numbers if functionAndDeviceNumber is valid)
     301           0 :     if(p.functionAndDeviceNumber != 0xFF)
     302             :     {
     303           0 :         p.functionNumber = bits(p.functionAndDeviceNumber, 0, 2);
     304           0 :         p.deviceNumber = bits(p.functionAndDeviceNumber, 3, 7);
     305             :     }
     306           0 : }
     307             : 
     308             : template<>
     309           0 : void Fixup<OnBoardDevices>(OnBoardDevices& p)
     310             : {
     311           0 :     p.enabled = (p.type.value & 0x80) != 0;
     312           0 :     p.type = (OnBoardDeviceType)(p.type & ~0x80);
     313           0 : }
     314             : 
     315             : template<>
     316           0 : void Fixup<MemoryArray>(MemoryArray& p)
     317             : {
     318           0 :     if(p.maxCapacity32 != (u32)INT32_MIN)
     319           0 :         p.maxCapacity = u64(p.maxCapacity32) * KiB;
     320           0 : }
     321             : 
     322             : template<>
     323           0 : void Fixup<MemoryDevice>(MemoryDevice& p)
     324             : {
     325           0 :     if(p.size16 != INT16_MAX)
     326           0 :         p.size = u64(bits(p.size16, 0, 14)) * (IsBitSet(p.size16, 15)? 1*KiB : 1*MiB);
     327             :     else
     328           0 :         p.size = u64(bits(p.size32, 0, 30)) * MiB;
     329           0 :     p.rank = bits(p.attributes, 0, 3);
     330           0 : }
     331             : 
     332             : template<>
     333           0 : void Fixup<MemoryArrayMappedAddress>(MemoryArrayMappedAddress& p)
     334             : {
     335           0 :     if(p.startAddress32 != UINT32_MAX)
     336           0 :         p.startAddress = u64(p.startAddress32) * KiB;
     337           0 :     if(p.endAddress32 != UINT32_MAX)
     338           0 :         p.endAddress = u64(p.endAddress32) * KiB;
     339           0 : }
     340             : 
     341             : template<>
     342           0 : void Fixup<MemoryDeviceMappedAddress>(MemoryDeviceMappedAddress& p)
     343             : {
     344           0 :     if(p.startAddress32 != UINT32_MAX)
     345           0 :         p.startAddress = u64(p.startAddress32) * KiB;
     346           0 :     if(p.endAddress32 != UINT32_MAX)
     347           0 :         p.endAddress = u64(p.endAddress32) * KiB;
     348           0 : }
     349             : 
     350             : template<>
     351           0 : void Fixup<VoltageProbe>(VoltageProbe& p)
     352             : {
     353           0 :     p.location = (VoltageProbeLocation)bits(p.locationAndStatus, 0, 4);
     354           0 :     p.status = (State)bits(p.locationAndStatus, 5, 7);
     355           0 : }
     356             : 
     357             : template<>
     358           0 : void Fixup<CoolingDevice>(CoolingDevice& p)
     359             : {
     360           0 :     p.type = (CoolingDeviceType)bits(p.typeAndStatus, 0, 4);
     361           0 :     p.status = (State)bits(p.typeAndStatus, 5, 7);
     362           0 : }
     363             : 
     364             : template<>
     365           0 : void Fixup<TemperatureProbe>(TemperatureProbe& p)
     366             : {
     367           0 :     p.location = (TemperatureProbeLocation)bits(p.locationAndStatus, 0, 4);
     368           0 :     p.status = (State)bits(p.locationAndStatus, 5, 7);
     369           0 : }
     370             : 
     371             : template<>
     372           0 : void Fixup<SystemPowerSupply>(SystemPowerSupply& p)
     373             : {
     374           0 :     p.type = (SystemPowerSupplyType)bits(p.characteristics, 10, 13);
     375           0 :     p.status = (State)bits(p.characteristics, 7, 9);
     376           0 :     p.inputSwitching = (SystemPowerSupplyInputSwitching)bits(p.characteristics, 3, 6);
     377           0 :     p.characteristics = bits(p.characteristics, 0, 2);
     378           0 : }
     379             : 
     380             : template<>
     381           0 : void Fixup<OnboardDevices2>(OnboardDevices2& p)
     382             : {
     383           0 :     p.enabled = IsBitSet(p.type, 7);
     384           0 :     p.type = (OnBoardDeviceType)bits(p.type, 0, 6);
     385           0 :     p.deviceNumber = bits(p.functionAndDeviceNumber, 3, 7);
     386           0 :     p.functionNumber = bits(p.functionAndDeviceNumber, 0, 2);
     387           0 : }
     388             : 
     389             : 
     390             : //-----------------------------------------------------------------------------
     391             : // InitStructures
     392             : 
     393             : template<class Structure>
     394             : void AddStructure(const Header* header, const Strings& strings, Structure*& listHead)
     395             : {
     396             :     Structure* const p = (Structure*)calloc(1, sizeof(Structure));  // freed in Cleanup
     397             :     p->header = *header;
     398             : 
     399             :     if(listHead)
     400             :     {
     401             :         // insert at end of list to preserve order of caches/slots
     402             :         Structure* last = listHead;
     403             :         while(last->next)
     404             :             last = last->next;
     405             :         last->next = p;
     406             :     }
     407             :     else
     408             :         listHead = p;
     409             : 
     410             :     FieldInitializer fieldInitializer(header, strings);
     411             :     VisitFields(*p, fieldInitializer);
     412             : 
     413             :     Fixup(*p);
     414             : }
     415             : 
     416             : 
     417           0 : static Status InitStructures()
     418             : {
     419             : #if OS_WIN
     420             :     wfirmware::Table table;
     421             :     RETURN_STATUS_IF_ERR(GetTable(table));
     422             : #else
     423           0 :     std::vector<u8> table;
     424           0 :     return ERR::NOT_SUPPORTED;
     425             : #endif
     426             : 
     427             :     // (instead of counting the total string size, just use the
     428             :     // SMBIOS size - typically 1-2 KB - as an upper bound.)
     429             :     stringStoragePos = stringStorage = (char*)calloc(table.size(), sizeof(char));   // freed in Cleanup
     430             :     if(!stringStorage)
     431             :         WARN_RETURN(ERR::NO_MEM);
     432             : 
     433             :     atexit(Cleanup);
     434             : 
     435             :     const Header* header = (const Header*)&table[0];
     436             :     const Header* const end = (const Header*)(&table[0] + table.size());
     437             :     for(;;)
     438             :     {
     439             :         if(header+1 > end)
     440             :         {
     441             :             debug_printf("SMBIOS: table not terminated\n");
     442             :             break;
     443             :         }
     444             :         if(header->id == 127)    // end
     445             :             break;
     446             :         if(header->length < sizeof(Header))
     447             :             return ERR::_3; // NOWARN (happens on some unknown BIOS, see http://trac.wildfiregames.com/ticket/2985)
     448             : 
     449             :         const Header* next;
     450             :         const Strings strings = ExtractStrings(header, (const char*)end, next);
     451             : 
     452             :         switch(header->id)
     453             :         {
     454             : #define STRUCTURE(name, id) case id: AddStructure(header, strings, g_Structures.name##_); break;
     455             :             STRUCTURES
     456             : #undef STRUCTURE
     457             : 
     458             :         default:
     459             :             if(32 < header->id && header->id < 126) // only mention non-proprietary structures of which we are not aware
     460             :                 debug_printf("SMBIOS: unknown structure type %d\n", header->id);
     461             :             break;
     462             :         }
     463             : 
     464             :         header = next;
     465             :     }
     466             : 
     467             :     return INFO::OK;
     468             : }
     469             : 
     470             : 
     471             : //-----------------------------------------------------------------------------
     472             : // StringFromEnum
     473             : 
     474             : template<class Enum>
     475             : std::string StringFromEnum(Enum UNUSED(field))
     476             : {
     477             :     return "(unknown enumeration)";
     478             : }
     479             : 
     480             : #define ENUM(enumerator, VALUE)\
     481             :     if(field.value == VALUE) /* single bit flag or matching enumerator */\
     482             :         return #enumerator;\
     483             :     if(!is_pow2(VALUE)) /* these aren't bit flags */\
     484             :     {\
     485             :         allowFlags = false;\
     486             :         string.clear();\
     487             :     }\
     488             :     if(allowFlags && (field.value & (VALUE)))\
     489             :     {\
     490             :         if(!string.empty())\
     491             :             string += "|";\
     492             :         string += #enumerator;\
     493             :     }
     494             : #define ENUMERATION(name, type)\
     495             :     template<>\
     496             :     std::string StringFromEnum<name>(name field)\
     497             :     {\
     498             :         std::string string;\
     499             :         bool allowFlags = true;\
     500             :         name##_ENUMERATORS\
     501             :         /* (don't warn about the value 0, e.g. optional fields) */\
     502             :         if(string.empty() && field != 0)\
     503             :         {\
     504             :             std::stringstream ss;\
     505             :             ss << "(unknown " << #name << " " << field.value << ")";\
     506             :             return ss.str();\
     507             :         }\
     508             :         return string;\
     509             :     }
     510           0 : ENUMERATIONS
     511             : #undef ENUMERATION
     512             : #undef ENUM
     513             : 
     514             : 
     515             : //-----------------------------------------------------------------------------
     516             : // FieldStringizer
     517             : 
     518             : class FieldStringizer
     519             : {
     520             :     NONCOPYABLE(FieldStringizer);   // reference member
     521             : public:
     522           0 :     FieldStringizer(std::stringstream& ss)
     523           0 :         : ss(ss)
     524             :     {
     525           0 :     }
     526             : 
     527             :     template<typename Field>
     528           0 :     void operator()(size_t flags, Field& field, const char* name, const char* units)
     529             :     {
     530           0 :         if(flags & F_INTERNAL)
     531           0 :             return;
     532             : 
     533           0 :         Write(flags, field, name, units, 0);    // SFINAE
     534             :     }
     535             : 
     536             :     // special case for sizes [bytes]
     537             :     template<typename T>
     538           0 :     void operator()(size_t flags, Size<T>& size, const char* name, const char* units)
     539             :     {
     540           0 :         if(flags & F_INTERNAL)
     541           0 :             return;
     542             : 
     543           0 :         const u64 value = (u64)size.value;
     544           0 :         if(value == 0)
     545           0 :             return;
     546             : 
     547             :         u64 divisor;
     548           0 :         if(value > GiB)
     549             :         {
     550           0 :             divisor = GiB;
     551           0 :             units = " GiB";
     552             :         }
     553           0 :         else if(value > MiB)
     554             :         {
     555           0 :             divisor = MiB;
     556           0 :             units = " MiB";
     557             :         }
     558           0 :         else if(value > KiB)
     559             :         {
     560           0 :             divisor = KiB;
     561           0 :             units = " KiB";
     562             :         }
     563             :         else
     564             :         {
     565           0 :             divisor = 1;
     566           0 :             units = " bytes";
     567             :         }
     568             : 
     569           0 :         WriteName(name);
     570             : 
     571             :         // (avoid floating-point output unless division would truncate the value)
     572           0 :         if(value % divisor == 0)
     573           0 :             ss << (value/divisor);
     574             :         else
     575           0 :             ss << (double(value)/divisor);
     576             : 
     577           0 :         WriteUnits(units);
     578             :     }
     579             : 
     580             : private:
     581           0 :     void WriteName(const char* name)
     582             :     {
     583           0 :         ss << "  "; // indent
     584           0 :         ss << name << ": ";
     585           0 :     }
     586             : 
     587           0 :     void WriteUnits(const char* units)
     588             :     {
     589           0 :         ss << units;
     590           0 :         ss << "\n";
     591           0 :     }
     592             : 
     593             :     // enumerations and bit flags
     594             :     template<typename Field>
     595           0 :     void Write(size_t UNUSED(flags), Field& field, const char* name, const char* units, typename Field::Enum*)
     596             :     {
     597             :         // 0 usually means "not included in structure", but some packed
     598             :         // enumerations actually use that value. therefore, only skip this
     599             :         // field if it is zero AND no matching enumerator is found.
     600           0 :         const std::string string = StringFromEnum(field);
     601           0 :         if(string.empty())
     602           0 :             return;
     603             : 
     604           0 :         WriteName(name);
     605           0 :         ss << StringFromEnum(field);
     606           0 :         WriteUnits(units);
     607             :     }
     608             : 
     609             :     // all other field types
     610             :     template<typename Field>
     611           0 :     void Write(size_t flags, Field& field, const char* name, const char* units, ...)
     612             :     {
     613             :         // SMBIOS uses the smallest and sometimes also largest representable
     614             :         // signed/unsigned value to indicate `unknown' (except enumerators -
     615             :         // but those are handled in the other function overload), so skip them.
     616           0 :         if(field == std::numeric_limits<Field>::min() || field == std::numeric_limits<Field>::max())
     617           0 :             return;
     618             : 
     619           0 :         WriteName(name);
     620             : 
     621           0 :         if(flags & F_HEX)
     622           0 :             ss << std::hex << std::uppercase;
     623             : 
     624             :         if(sizeof(field) == 1)  // avoid printing as a character
     625           0 :             ss << unsigned(field);
     626             :         else
     627           0 :             ss << field;
     628             : 
     629           0 :         if(flags & F_HEX)
     630           0 :             ss << std::dec;   // (revert to decimal, e.g. for displaying sizes)
     631             : 
     632           0 :         WriteUnits(units);
     633             :     }
     634             : 
     635             :     std::stringstream& ss;
     636             : };
     637             : 
     638             : template<>
     639           0 : void FieldStringizer::operator()<bool>(size_t flags, bool& value, const char* name, const char* units)
     640             : {
     641           0 :     if(flags & F_INTERNAL)
     642           0 :         return;
     643             : 
     644           0 :     WriteName(name);
     645           0 :     ss << (value? "true" : "false");
     646           0 :     WriteUnits(units);
     647             : }
     648             : 
     649             : template<>
     650           0 : void FieldStringizer::operator()<Handle>(size_t flags, Handle& handle, const char* name, const char* units)
     651             : {
     652           0 :     if(flags & F_INTERNAL)
     653           0 :         return;
     654             : 
     655             :     // don't display useless handles
     656           0 :     if(handle.value == 0 || handle.value == 0xFFFE || handle.value == 0xFFFF)
     657           0 :         return;
     658             : 
     659           0 :     WriteName(name);
     660           0 :     ss << handle.value;
     661           0 :     WriteUnits(units);
     662             : }
     663             : 
     664             : 
     665             : template<>
     666           0 : void FieldStringizer::operator()<const char*>(size_t flags, const char*& value, const char* name, const char* units)
     667             : {
     668           0 :     if(flags & F_INTERNAL)
     669           0 :         return;
     670             : 
     671             :     // don't display useless strings
     672           0 :     if(value == 0)
     673           0 :         return;
     674           0 :     std::string string(value);
     675           0 :     const size_t lastChar = string.find_last_not_of(' ');
     676           0 :     if(lastChar == std::string::npos)   // nothing but spaces
     677           0 :         return;
     678           0 :     string.resize(lastChar+1);  // strip trailing spaces
     679           0 :     if(!strcasecmp(value, "To Be Filled By O.E.M."))
     680           0 :         return;
     681             : 
     682           0 :     WriteName(name);
     683           0 :     ss << "\"" << string << "\"";
     684           0 :     WriteUnits(units);
     685             : }
     686             : 
     687             : 
     688             : //-----------------------------------------------------------------------------
     689             : // public interface
     690             : 
     691           0 : const Structures* GetStructures()
     692             : {
     693             :     static ModuleInitState initState;
     694           0 :     Status ret = ModuleInit(&initState, InitStructures);
     695             :     // (callers have to check if member pointers are nonzero anyway, so
     696             :     // we always return a valid pointer to simplify most use cases.)
     697             :     UNUSED2(ret);
     698           0 :     return &g_Structures;
     699             : }
     700             : 
     701             : 
     702             : template<class Structure>
     703           0 : void StringizeStructure(const char* name, Structure* p, std::stringstream& ss)
     704             : {
     705           0 :     for(; p; p = p->next)
     706             :     {
     707           0 :         ss << "\n[" << name << "]\n";
     708           0 :         FieldStringizer fieldStringizer(ss);
     709           0 :         VisitFields(*p, fieldStringizer);
     710             :     }
     711           0 : }
     712             : 
     713           0 : std::string StringizeStructures(const Structures* structures)
     714             : {
     715           0 :     std::stringstream ss;
     716             : #define STRUCTURE(name, id) StringizeStructure(#name, structures->name##_, ss);
     717           0 :     STRUCTURES
     718             : #undef STRUCTURE
     719             : 
     720           0 :     return ss.str();
     721             : }
     722             : 
     723           3 : }   // namespace SMBIOS

Generated by: LCOV version 1.13