LCOV - code coverage report
Current view: top level - source/ps/XMB - XMBData.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 116 121 95.9 %
Date: 2021-09-24 14:46:47 Functions: 20 20 100.0 %

          Line data    Source code
       1             : /* Copyright (C) 2021 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "lib/byte_order.h"   // FOURCC_LE
      21             : #include "ps/XMB/XMBStorage.h"
      22             : #include "ps/XML/Xeromyces.h"
      23             : 
      24             : template<typename T>
      25             : static inline T read(const void* ptr)
      26             : {
      27             :     T ret;
      28      267764 :     memcpy(&ret, ptr, sizeof(T));
      29             :     return ret;
      30             : }
      31             : 
      32        1726 : bool XMBData::Initialise(const XMBStorage& doc)
      33             : {
      34        1726 :     const char* start = reinterpret_cast<const char*>(doc.m_Buffer.get());
      35        1726 :     m_Pointer = start;
      36        1726 :     char Header[5] = { 0 };
      37        1726 :     strncpy_s(Header, 5, m_Pointer, 4);
      38        1726 :     m_Pointer += 4;
      39             : 
      40        1726 :     if (strcmp(Header, XMBStorage::UnfinishedHeaderMagicStr) == 0)
      41             :         return false;
      42        1726 :     ENSURE(strcmp(Header, XMBStorage::HeaderMagicStr) == 0 && "Invalid XMB header!");
      43             : 
      44        1726 :     u32 Version = read<u32>(m_Pointer);
      45        1726 :     m_Pointer += 4;
      46        1726 :     if (Version != XMBStorage::XMBVersion)
      47             :         return false;
      48             : 
      49             :     // FIXME Check that m_Pointer doesn't end up past the end of the buffer
      50             :     // (it shouldn't be all that dangerous since we're only doing read-only
      51             :     // access, but it might crash on an invalid file, reading a couple of
      52             :     // billion random element names from RAM)
      53             : 
      54        1726 :     m_ElementPointer = start + read<u32>(m_Pointer); m_Pointer += 4;
      55        1726 :     m_ElementNameCount = read<int>(m_Pointer); m_Pointer += 4;
      56        1726 :     m_AttributePointer = start + read<u32>(m_Pointer); m_Pointer += 4;
      57        1726 :     m_AttributeNameCount = read<int>(m_Pointer); m_Pointer += 4;
      58             :     // At this point m_Pointer points to the element start, as expected.
      59        1726 :     return true;    // success
      60             : }
      61             : 
      62        1758 : XMBElement XMBData::GetRoot() const
      63             : {
      64        1758 :     return XMBElement(m_Pointer);
      65             : }
      66             : 
      67        8860 : int XMBData::GetElementID(const char* Name) const
      68             : {
      69        8860 :     const char* Pos = m_ElementPointer;
      70             : 
      71        8860 :     int len = (int)strlen(Name)+1; // count bytes, including null terminator
      72             : 
      73             :     // Loop through each string to find a match
      74       32172 :     for (int i = 0; i < m_ElementNameCount; ++i)
      75             :     {
      76             :         // See if this could be the right string, checking its
      77             :         // length and then its contents
      78       57480 :         if (read<int>(Pos) == len && strncasecmp(Pos+4, Name, len) == 0)
      79        5428 :             return static_cast<int>(Pos - m_ElementPointer);
      80             :         // If not, jump to the next string
      81       46624 :         Pos += 4 + read<int>(Pos);
      82             :     }
      83             :     // Failed
      84             :     return -1;
      85             : }
      86             : 
      87        7717 : int XMBData::GetAttributeID(const char* Name) const
      88             : {
      89        7717 :     const char* Pos = m_AttributePointer;
      90             : 
      91        7717 :     int len = (int)strlen(Name)+1; // count bytes, including null terminator
      92             : 
      93             :     // Loop through each string to find a match
      94       18100 :     for (int i = 0; i < m_AttributeNameCount; ++i)
      95             :     {
      96             :         // See if this could be the right string, checking its
      97             :         // length and then its contents
      98       27740 :         if (read<int>(Pos) == len && strncasecmp(Pos+4, Name, len) == 0)
      99        3487 :             return static_cast<int>(Pos - m_AttributePointer);
     100             :         // If not, jump to the next string
     101       20766 :         Pos += 4 + read<int>(Pos);
     102             :     }
     103             :     // Failed
     104             :     return -1;
     105             : }
     106             : 
     107         567 : const char* XMBData::GetElementString(const int ID) const
     108             : {
     109         567 :     return reinterpret_cast<const char*>(m_ElementPointer + ID + 4);
     110             : }
     111             : 
     112          91 : const char* XMBData::GetAttributeString(const int ID) const
     113             : {
     114          91 :     return reinterpret_cast<const char*>(m_AttributePointer + ID + 4);
     115             : }
     116             : 
     117           8 : std::string_view XMBData::GetElementStringView(const int ID) const
     118             : {
     119          16 :     return std::string_view(reinterpret_cast<const char*>(m_ElementPointer + ID + 4), read<int>(m_ElementPointer + ID) - 1);
     120             : }
     121             : 
     122           5 : std::string_view XMBData::GetAttributeStringView(const int ID) const
     123             : {
     124          10 :     return std::string_view(reinterpret_cast<const char*>(m_AttributePointer + ID + 4), read<int>(m_AttributePointer + ID) - 1);
     125             : }
     126             : 
     127        7071 : int XMBElement::GetNodeName() const
     128             : {
     129        7071 :     if (m_Pointer == NULL)
     130             :         return -1;
     131             : 
     132       14136 :     return read<int>(m_Pointer + 4); // == ElementName
     133             : }
     134             : 
     135        3044 : XMBElementList XMBElement::GetChildNodes() const
     136             : {
     137        3044 :     if (m_Pointer == NULL)
     138           3 :         return XMBElementList(NULL, 0, NULL);
     139             : 
     140        3041 :     return XMBElementList(
     141        6082 :         m_Pointer + 20 + read<int>(m_Pointer + 16), // == Children[]
     142        6082 :         read<int>(m_Pointer + 12), // == ChildCount
     143        3041 :         m_Pointer + read<int>(m_Pointer) // == &Children[ChildCount]
     144        9123 :     );
     145             : }
     146             : 
     147        4466 : XMBAttributeList XMBElement::GetAttributes() const
     148             : {
     149        4466 :     if (m_Pointer == NULL)
     150           3 :         return XMBAttributeList(NULL, 0, NULL);
     151             : 
     152        4463 :     return XMBAttributeList(
     153        8926 :         m_Pointer + 24 + read<int>(m_Pointer + 20), // == Attributes[]
     154        8926 :         read<int>(m_Pointer + 8), // == AttributeCount
     155        4463 :         m_Pointer + 20 + read<int>(m_Pointer + 16) // == &Attributes[AttributeCount] ( == &Children[])
     156       13389 :     );
     157             : }
     158             : 
     159        1762 : CStr8 XMBElement::GetText() const
     160             : {
     161             :     // Return empty string if there's no text
     162        1762 :     if (m_Pointer == NULL || read<int>(m_Pointer + 20) == 0)
     163         288 :         return CStr8();
     164             : 
     165        1474 :     return CStr8(m_Pointer + 28);
     166             : }
     167             : 
     168           4 : int XMBElement::GetLineNumber() const
     169             : {
     170             :     // Make sure there actually was some text to record the line of
     171           4 :     if (m_Pointer == NULL || read<int>(m_Pointer + 20) == 0)
     172             :         return -1;
     173             :     else
     174           4 :         return read<int>(m_Pointer + 24);
     175             : }
     176             : 
     177           9 : XMBElement XMBElementList::GetFirstNamedItem(const int ElementName) const
     178             : {
     179           9 :     const char* Pos = m_Pointer;
     180             : 
     181             :     // Maybe not the cleverest algorithm, but it should be
     182             :     // fast enough with half a dozen attributes:
     183          27 :     for (size_t i = 0; i < m_Size; ++i)
     184             :     {
     185          24 :         int Length = read<int>(Pos);
     186          24 :         int Name = read<int>(Pos+4);
     187          24 :         if (Name == ElementName)
     188           6 :             return XMBElement(Pos);
     189          18 :         Pos += Length;
     190             :     }
     191             : 
     192             :     // Can't find element
     193           3 :     return XMBElement();
     194             : }
     195             : 
     196        5560 : XMBElementList::iterator& XMBElementList::iterator::operator++()
     197             : {
     198       11120 :     m_CurPointer += read<int>(m_CurPointer);
     199        5560 :     ++m_CurItemID;
     200        5560 :     return (*this);
     201             : }
     202             : 
     203           4 : XMBElement XMBElementList::operator[](size_t id)
     204             : {
     205           4 :     ENSURE(id < m_Size && "Element ID out of range");
     206           4 :     const char* Pos;
     207           4 :     size_t i;
     208             : 
     209           4 :     if (id < m_CurItemID)
     210             :     {
     211           0 :         Pos = m_Pointer;
     212           0 :         i = 0;
     213             :     }
     214             :     else
     215             :     {
     216             :         // If access is sequential, don't bother scanning
     217             :         // through all the nodes to find the next one
     218           4 :         Pos = m_CurPointer;
     219           4 :         i = m_CurItemID;
     220             :     }
     221             : 
     222             :     // Skip over each preceding node
     223           5 :     for (; i < id; ++i)
     224           2 :         Pos += read<int>(Pos);
     225             : 
     226             :     // Cache information about this node
     227           4 :     m_CurItemID = id;
     228           4 :     m_CurPointer = Pos;
     229             : 
     230           4 :     return XMBElement(Pos);
     231             : }
     232             : 
     233         351 : CStr8 XMBAttributeList::GetNamedItem(const int AttributeName) const
     234             : {
     235         351 :     const char* Pos = m_Pointer;
     236             : 
     237             :     // Maybe not the cleverest algorithm, but it should be
     238             :     // fast enough with half a dozen attributes:
     239         666 :     for (size_t i = 0; i < m_Size; ++i)
     240             :     {
     241        1262 :         if (read<int>(Pos) == AttributeName)
     242         316 :             return CStr8(Pos+8);
     243         630 :         Pos += 8 + read<int>(Pos+4); // Skip over the string
     244             :     }
     245             : 
     246             :     // Can't find attribute
     247          35 :     return CStr8();
     248             : }
     249             : 
     250        5531 : XMBAttribute XMBAttributeList::iterator::operator*() const
     251             : {
     252        7841 :     return XMBAttribute(read<int>(m_CurPointer), CStr8(m_CurPointer+8));
     253             : }
     254             : 
     255        5499 : XMBAttributeList::iterator& XMBAttributeList::iterator::operator++()
     256             : {
     257       10998 :     m_CurPointer += 8 + read<int>(m_CurPointer+4); // skip ID, length, and string data
     258        5499 :     ++m_CurItemID;
     259        5499 :     return (*this);
     260             : }
     261             : 
     262           5 : XMBAttribute XMBAttributeList::operator[](size_t id)
     263             : {
     264           5 :     ENSURE(id < m_Size && "Attribute ID out of range");
     265           5 :     const char* Pos;
     266           5 :     size_t i;
     267             : 
     268           5 :     if (id < m_CurItemID)
     269             :     {
     270           0 :         Pos = m_Pointer;
     271           0 :         i = 0;
     272             :     }
     273             :     else
     274             :     {
     275             :         // If access is sequential, don't bother scanning
     276             :         // through all the nodes to find the next one
     277           5 :         Pos = m_CurPointer;
     278           5 :         i = m_CurItemID;
     279             :     }
     280             : 
     281             :     // Skip over each preceding attribute
     282           5 :     for (; i < id; ++i)
     283           0 :         Pos += 8 + read<int>(Pos+4); // skip ID, length, and string data
     284             : 
     285             :     // Cache information about this attribute
     286           5 :     m_CurItemID = id;
     287           5 :     m_CurPointer = Pos;
     288             : 
     289           5 :     return XMBAttribute(read<int>(Pos), CStr8(Pos+8));
     290             : }

Generated by: LCOV version 1.13