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: 117 124 94.4 %
Date: 2023-01-19 00:18:29 Functions: 24 24 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       20543 : static inline T read(const void* ptr)
      26             : {
      27             :     T ret;
      28       20543 :     memcpy(&ret, ptr, sizeof(T));
      29       20543 :     return ret;
      30             : }
      31             : 
      32         425 : bool XMBData::Initialise(const XMBStorage& doc)
      33             : {
      34         425 :     const char* start = reinterpret_cast<const char*>(doc.m_Buffer.get());
      35         425 :     m_Pointer = start;
      36         425 :     char Header[5] = { 0 };
      37         425 :     strncpy_s(Header, 5, m_Pointer, 4);
      38         425 :     m_Pointer += 4;
      39             : 
      40         425 :     if (strcmp(Header, XMBStorage::UnfinishedHeaderMagicStr) == 0)
      41           0 :         return false;
      42         425 :     ENSURE(strcmp(Header, XMBStorage::HeaderMagicStr) == 0 && "Invalid XMB header!");
      43             : 
      44         425 :     u32 Version = read<u32>(m_Pointer);
      45         425 :     m_Pointer += 4;
      46         425 :     if (Version != XMBStorage::XMBVersion)
      47           0 :         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         425 :     m_ElementPointer = start + read<u32>(m_Pointer); m_Pointer += 4;
      55         425 :     m_ElementNameCount = read<int>(m_Pointer); m_Pointer += 4;
      56         425 :     m_AttributePointer = start + read<u32>(m_Pointer); m_Pointer += 4;
      57         425 :     m_AttributeNameCount = read<int>(m_Pointer); m_Pointer += 4;
      58             :     // At this point m_Pointer points to the element start, as expected.
      59         425 :     return true;    // success
      60             : }
      61             : 
      62         457 : XMBElement XMBData::GetRoot() const
      63             : {
      64         457 :     return XMBElement(m_Pointer);
      65             : }
      66             : 
      67          82 : int XMBData::GetElementID(const char* Name) const
      68             : {
      69          82 :     const char* Pos = m_ElementPointer;
      70             : 
      71          82 :     int len = (int)strlen(Name)+1; // count bytes, including null terminator
      72             : 
      73             :     // Loop through each string to find a match
      74         230 :     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         196 :         if (read<int>(Pos) == len && strncasecmp(Pos+4, Name, len) == 0)
      79          48 :             return static_cast<int>(Pos - m_ElementPointer);
      80             :         // If not, jump to the next string
      81         148 :         Pos += 4 + read<int>(Pos);
      82             :     }
      83             :     // Failed
      84          34 :     return -1;
      85             : }
      86             : 
      87        3251 : int XMBData::GetAttributeID(const char* Name) const
      88             : {
      89        3251 :     const char* Pos = m_AttributePointer;
      90             : 
      91        3251 :     int len = (int)strlen(Name)+1; // count bytes, including null terminator
      92             : 
      93             :     // Loop through each string to find a match
      94        7092 :     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        4326 :         if (read<int>(Pos) == len && strncasecmp(Pos+4, Name, len) == 0)
      99         485 :             return static_cast<int>(Pos - m_AttributePointer);
     100             :         // If not, jump to the next string
     101        3841 :         Pos += 4 + read<int>(Pos);
     102             :     }
     103             :     // Failed
     104        2766 :     return -1;
     105             : }
     106             : 
     107         512 : const char* XMBData::GetElementString(const int ID) const
     108             : {
     109         512 :     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           8 :     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           5 :     return std::string_view(reinterpret_cast<const char*>(m_AttributePointer + ID + 4), read<int>(m_AttributePointer + ID) - 1);
     125             : }
     126             : 
     127         556 : int XMBElement::GetNodeName() const
     128             : {
     129         556 :     if (m_Pointer == NULL)
     130           3 :         return -1;
     131             : 
     132         553 :     return read<int>(m_Pointer + 4); // == ElementName
     133             : }
     134             : 
     135         497 : XMBElementList XMBElement::GetChildNodes() const
     136             : {
     137         497 :     if (m_Pointer == NULL)
     138           3 :         return XMBElementList(NULL, 0, NULL);
     139             : 
     140             :     return XMBElementList(
     141         494 :         m_Pointer + 20 + read<int>(m_Pointer + 16), // == Children[]
     142         494 :         read<int>(m_Pointer + 12), // == ChildCount
     143         494 :         m_Pointer + read<int>(m_Pointer) // == &Children[ChildCount]
     144        1482 :     );
     145             : }
     146             : 
     147        1747 : XMBAttributeList XMBElement::GetAttributes() const
     148             : {
     149        1747 :     if (m_Pointer == NULL)
     150           3 :         return XMBAttributeList(NULL, 0, NULL);
     151             : 
     152             :     return XMBAttributeList(
     153        1744 :         m_Pointer + 24 + read<int>(m_Pointer + 20), // == Attributes[]
     154        1744 :         read<int>(m_Pointer + 8), // == AttributeCount
     155        1744 :         m_Pointer + 20 + read<int>(m_Pointer + 16) // == &Attributes[AttributeCount] ( == &Children[])
     156        5232 :     );
     157             : }
     158             : 
     159         517 : CStr8 XMBElement::GetText() const
     160             : {
     161             :     // Return empty string if there's no text
     162         517 :     if (m_Pointer == NULL || read<int>(m_Pointer + 20) == 0)
     163         289 :         return CStr8();
     164             : 
     165         228 :     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           2 :         return -1;
     173             :     else
     174           2 :         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         402 : XMBElementList::iterator& XMBElementList::iterator::operator++()
     197             : {
     198         402 :     m_CurPointer += read<int>(m_CurPointer);
     199         402 :     ++m_CurItemID;
     200         402 :     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             :     const char* Pos;
     207             :     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           6 :     for (; i < id; ++i)
     224           1 :         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         631 :         if (read<int>(Pos) == AttributeName)
     242         316 :             return CStr8(Pos+8);
     243         315 :         Pos += 8 + read<int>(Pos+4); // Skip over the string
     244             :     }
     245             : 
     246             :     // Can't find attribute
     247          35 :     return CStr8();
     248             : }
     249             : 
     250         369 : XMBAttribute XMBAttributeList::iterator::operator*() const
     251             : {
     252         369 :     return XMBAttribute(read<int>(m_CurPointer), CStr8(m_CurPointer+8));
     253             : }
     254             : 
     255         337 : XMBAttributeList::iterator& XMBAttributeList::iterator::operator++()
     256             : {
     257         337 :     m_CurPointer += 8 + read<int>(m_CurPointer+4); // skip ID, length, and string data
     258         337 :     ++m_CurItemID;
     259         337 :     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             :     const char* Pos;
     266             :     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           3 : }

Generated by: LCOV version 1.13