LCOV - code coverage report
Current view: top level - source/ps/XML - XeroXMB.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 121 132 91.7 %
Date: 2021-04-16 20:41:45 Functions: 18 19 94.7 %

          Line data    Source code
       1             : /* Copyright (C) 2015 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 "Xeromyces.h"
      21             : 
      22             : #include "lib/byte_order.h"   // FOURCC_LE
      23             : 
      24             : // external linkage (also used by Xeromyces.cpp)
      25             : const char* HeaderMagicStr = "XMB0";
      26             : const char* UnfinishedHeaderMagicStr = "XMBu";
      27             : // Arbitrary version number - change this if we update the code and
      28             : // need to invalidate old users' caches
      29             : const u32 XMBVersion = 3;
      30             : 
      31             : template<typename T>
      32             : static inline T read(const void* ptr)
      33             : {
      34             :     T ret;
      35      198618 :     memcpy(&ret, ptr, sizeof(T));
      36             :     return ret;
      37             : }
      38             : 
      39        1402 : bool XMBFile::Initialise(const char* FileData)
      40             : {
      41        1402 :     m_Pointer = FileData;
      42        1402 :     char Header[5] = { 0 };
      43        1402 :     strncpy_s(Header, 5, m_Pointer, 4);
      44        1402 :     m_Pointer += 4;
      45             :     // (c.f. @return documentation of this function)
      46        1402 :     if(!strcmp(Header, UnfinishedHeaderMagicStr))
      47             :         return false;
      48        1402 :     ENSURE(!strcmp(Header, HeaderMagicStr) && "Invalid XMB header!");
      49             : 
      50        1402 :     u32 Version = read<u32>(m_Pointer);
      51        1402 :     m_Pointer += 4;
      52        1402 :     if (Version != XMBVersion)
      53             :         return false;
      54             : 
      55        1402 :     int i;
      56             : 
      57             :     // FIXME Check that m_Pointer doesn't end up past the end of the buffer
      58             :     // (it shouldn't be all that dangerous since we're only doing read-only
      59             :     // access, but it might crash on an invalid file, reading a couple of
      60             :     // billion random element names from RAM)
      61             : 
      62             : #ifdef XERO_USEMAP
      63             :     // Build a std::map of all the names->ids
      64             :     u32 ElementNameCount = read<u32>(m_Pointer); m_Pointer += 4;
      65             :     for (i = 0; i < ElementNameCount; ++i)
      66             :         m_ElementNames[ReadZStr8()] = i;
      67             : 
      68             :     u32 AttributeNameCount = read<u32>(m_Pointer); m_Pointer += 4;
      69             :     for (i = 0; i < AttributeNameCount; ++i)
      70             :         m_AttributeNames[ReadZStr8()] = i;
      71             : #else
      72             :     // Ignore all the names for now, and skip over them
      73             :     // (remembering the position of the first)
      74        1402 :     m_ElementNameCount = read<int>(m_Pointer); m_Pointer += 4;
      75        1402 :     m_ElementPointer = m_Pointer;
      76        6085 :     for (i = 0; i < m_ElementNameCount; ++i)
      77        9366 :         m_Pointer += 4 + read<int>(m_Pointer); // skip over the string
      78             : 
      79        1402 :     m_AttributeNameCount = read<int>(m_Pointer); m_Pointer += 4;
      80        1402 :     m_AttributePointer = m_Pointer;
      81        4160 :     for (i = 0; i < m_AttributeNameCount; ++i)
      82        5516 :         m_Pointer += 4 + read<int>(m_Pointer); // skip over the string
      83             : #endif
      84             : 
      85             :     return true;    // success
      86             : }
      87             : 
      88           0 : std::string XMBFile::ReadZStr8()
      89             : {
      90           0 :     int Length = read<int>(m_Pointer);
      91           0 :     m_Pointer += 4;
      92           0 :     std::string String (m_Pointer); // reads up until the first NULL
      93           0 :     m_Pointer += Length;
      94           0 :     return String;
      95             : }
      96             : 
      97        1434 : XMBElement XMBFile::GetRoot() const
      98             : {
      99        1434 :     return XMBElement(m_Pointer);
     100             : }
     101             : 
     102             : 
     103             : #ifdef XERO_USEMAP
     104             : 
     105             : int XMBFile::GetElementID(const char* Name) const
     106             : {
     107             :     return m_ElementNames[Name];
     108             : }
     109             : 
     110             : int XMBFile::GetAttributeID(const char* Name) const
     111             : {
     112             :     return m_AttributeNames[Name];
     113             : }
     114             : 
     115             : #else // #ifdef XERO_USEMAP
     116             : 
     117        6771 : int XMBFile::GetElementID(const char* Name) const
     118             : {
     119        6771 :     const char* Pos = m_ElementPointer;
     120             : 
     121        6771 :     int len = (int)strlen(Name)+1; // count bytes, including null terminator
     122             : 
     123             :     // Loop through each string to find a match
     124       24162 :     for (int i = 0; i < m_ElementNameCount; ++i)
     125             :     {
     126             :         // See if this could be the right string, checking its
     127             :         // length and then its contents
     128       42648 :         if (read<int>(Pos) == len && strncasecmp(Pos+4, Name, len) == 0)
     129        3933 :             return i;
     130             :         // If not, jump to the next string
     131       34782 :         Pos += 4 + read<int>(Pos);
     132             :     }
     133             :     // Failed
     134             :     return -1;
     135             : }
     136             : 
     137        5235 : int XMBFile::GetAttributeID(const char* Name) const
     138             : {
     139        5235 :     const char* Pos = m_AttributePointer;
     140             : 
     141        5235 :     int len = (int)strlen(Name)+1; // count bytes, including null terminator
     142             : 
     143             :     // Loop through each string to find a match
     144       10361 :     for (int i = 0; i < m_AttributeNameCount; ++i)
     145             :     {
     146             :         // See if this could be the right string, checking its
     147             :         // length and then its contents
     148       15352 :         if (read<int>(Pos) == len && strncasecmp(Pos+4, Name, len) == 0)
     149        2550 :             return i;
     150             :         // If not, jump to the next string
     151       10252 :         Pos += 4 + read<int>(Pos);
     152             :     }
     153             :     // Failed
     154             :     return -1;
     155             : }
     156             : #endif // #ifdef XERO_USEMAP / #else
     157             : 
     158             : 
     159             : // Relatively inefficient, so only use when
     160             : // laziness overcomes the need for speed
     161         491 : std::string XMBFile::GetElementString(const int ID) const
     162             : {
     163         491 :     const char* Pos = m_ElementPointer;
     164        2552 :     for (int i = 0; i < ID; ++i)
     165        4122 :         Pos += 4 + read<int>(Pos);
     166         982 :     return std::string(Pos+4);
     167             : }
     168             : 
     169          74 : std::string XMBFile::GetAttributeString(const int ID) const
     170             : {
     171          74 :     const char* Pos = m_AttributePointer;
     172         112 :     for (int i = 0; i < ID; ++i)
     173          76 :         Pos += 4 + read<int>(Pos);
     174         148 :     return std::string(Pos+4);
     175             : }
     176             : 
     177             : 
     178             : 
     179        4913 : int XMBElement::GetNodeName() const
     180             : {
     181        4913 :     if (m_Pointer == NULL)
     182             :         return -1;
     183             : 
     184        9824 :     return read<int>(m_Pointer + 4); // == ElementName
     185             : }
     186             : 
     187        2356 : XMBElementList XMBElement::GetChildNodes() const
     188             : {
     189        2356 :     if (m_Pointer == NULL)
     190           1 :         return XMBElementList(NULL, 0, NULL);
     191             : 
     192        2355 :     return XMBElementList(
     193        4710 :         m_Pointer + 20 + read<int>(m_Pointer + 16), // == Children[]
     194        4710 :         read<int>(m_Pointer + 12), // == ChildCount
     195        2355 :         m_Pointer + read<int>(m_Pointer) // == &Children[ChildCount]
     196        7065 :     );
     197             : }
     198             : 
     199        3087 : XMBAttributeList XMBElement::GetAttributes() const
     200             : {
     201        3087 :     if (m_Pointer == NULL)
     202           1 :         return XMBAttributeList(NULL, 0, NULL);
     203             : 
     204        3086 :     return XMBAttributeList(
     205        6172 :         m_Pointer + 24 + read<int>(m_Pointer + 20), // == Attributes[]
     206        6172 :         read<int>(m_Pointer + 8), // == AttributeCount
     207        3086 :         m_Pointer + 20 + read<int>(m_Pointer + 16) // == &Attributes[AttributeCount] ( == &Children[])
     208        9258 :     );
     209             : }
     210             : 
     211        1386 : CStr8 XMBElement::GetText() const
     212             : {
     213             :     // Return empty string if there's no text
     214        1386 :     if (m_Pointer == NULL || read<int>(m_Pointer + 20) == 0)
     215         247 :         return CStr8();
     216             : 
     217        1139 :     return CStr8(m_Pointer + 28);
     218             : }
     219             : 
     220           4 : int XMBElement::GetLineNumber() const
     221             : {
     222             :     // Make sure there actually was some text to record the line of
     223           4 :     if (m_Pointer == NULL || read<int>(m_Pointer + 20) == 0)
     224             :         return -1;
     225             :     else
     226           4 :         return read<int>(m_Pointer + 24);
     227             : }
     228             : 
     229           3 : XMBElement XMBElementList::GetFirstNamedItem(const int ElementName) const
     230             : {
     231           3 :     const char* Pos = m_Pointer;
     232             : 
     233             :     // Maybe not the cleverest algorithm, but it should be
     234             :     // fast enough with half a dozen attributes:
     235           9 :     for (size_t i = 0; i < m_Size; ++i)
     236             :     {
     237           8 :         int Length = read<int>(Pos);
     238           8 :         int Name = read<int>(Pos+4);
     239           8 :         if (Name == ElementName)
     240           2 :             return XMBElement(Pos);
     241           6 :         Pos += Length;
     242             :     }
     243             : 
     244             :     // Can't find element
     245           1 :     return XMBElement();
     246             : }
     247             : 
     248        3744 : XMBElementList::iterator& XMBElementList::iterator::operator++()
     249             : {
     250        7488 :     m_CurPointer += read<int>(m_CurPointer);
     251        3744 :     ++m_CurItemID;
     252        3744 :     return (*this);
     253             : }
     254             : 
     255           2 : XMBElement XMBElementList::operator[](size_t id)
     256             : {
     257           2 :     ENSURE(id < m_Size && "Element ID out of range");
     258           2 :     const char* Pos;
     259           2 :     size_t i;
     260             : 
     261           2 :     if (id < m_CurItemID)
     262             :     {
     263           0 :         Pos = m_Pointer;
     264           0 :         i = 0;
     265             :     }
     266             :     else
     267             :     {
     268             :         // If access is sequential, don't bother scanning
     269             :         // through all the nodes to find the next one
     270           2 :         Pos = m_CurPointer;
     271           2 :         i = m_CurItemID;
     272             :     }
     273             : 
     274             :     // Skip over each preceding node
     275           3 :     for (; i < id; ++i)
     276           2 :         Pos += read<int>(Pos);
     277             : 
     278             :     // Cache information about this node
     279           2 :     m_CurItemID = id;
     280           2 :     m_CurPointer = Pos;
     281             : 
     282           2 :     return XMBElement(Pos);
     283             : }
     284             : 
     285         349 : CStr8 XMBAttributeList::GetNamedItem(const int AttributeName) const
     286             : {
     287         349 :     const char* Pos = m_Pointer;
     288             : 
     289             :     // Maybe not the cleverest algorithm, but it should be
     290             :     // fast enough with half a dozen attributes:
     291         663 :     for (size_t i = 0; i < m_Size; ++i)
     292             :     {
     293        1258 :         if (read<int>(Pos) == AttributeName)
     294         315 :             return CStr8(Pos+8);
     295         628 :         Pos += 8 + read<int>(Pos+4); // Skip over the string
     296             :     }
     297             : 
     298             :     // Can't find attribute
     299          34 :     return CStr8();
     300             : }
     301             : 
     302        3373 : XMBAttribute XMBAttributeList::iterator::operator*() const
     303             : {
     304        4799 :     return XMBAttribute(read<int>(m_CurPointer), CStr8(m_CurPointer+8));
     305             : }
     306             : 
     307        3341 : XMBAttributeList::iterator& XMBAttributeList::iterator::operator++()
     308             : {
     309        6682 :     m_CurPointer += 8 + read<int>(m_CurPointer+4); // skip ID, length, and string data
     310        3341 :     ++m_CurItemID;
     311        3341 :     return (*this);
     312             : }
     313             : 
     314           3 : XMBAttribute XMBAttributeList::operator[](size_t id)
     315             : {
     316           3 :     ENSURE(id < m_Size && "Attribute ID out of range");
     317           3 :     const char* Pos;
     318           3 :     size_t i;
     319             : 
     320           3 :     if (id < m_CurItemID)
     321             :     {
     322           0 :         Pos = m_Pointer;
     323           0 :         i = 0;
     324             :     }
     325             :     else
     326             :     {
     327             :         // If access is sequential, don't bother scanning
     328             :         // through all the nodes to find the next one
     329           3 :         Pos = m_CurPointer;
     330           3 :         i = m_CurItemID;
     331             :     }
     332             : 
     333             :     // Skip over each preceding attribute
     334           3 :     for (; i < id; ++i)
     335           0 :         Pos += 8 + read<int>(Pos+4); // skip ID, length, and string data
     336             : 
     337             :     // Cache information about this attribute
     338           3 :     m_CurItemID = id;
     339           3 :     m_CurPointer = Pos;
     340             : 
     341           3 :     return XMBAttribute(read<int>(Pos), CStr8(Pos+8));
     342             : }

Generated by: LCOV version 1.13