LCOV - code coverage report
Current view: top level - source/simulation2/serialization - DebugSerializer.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 87 90 96.7 %
Date: 2023-01-19 00:18:29 Functions: 21 22 95.5 %

          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 "DebugSerializer.h"
      21             : 
      22             : #include "scriptinterface/FunctionWrapper.h"
      23             : #include "scriptinterface/Object.h"
      24             : #include "scriptinterface/ScriptRequest.h"
      25             : #include "scriptinterface/JSON.h"
      26             : 
      27             : #include "lib/secure_crt.h"
      28             : #include "lib/utf8.h"
      29             : #include "ps/CStr.h"
      30             : 
      31             : #include <sstream>
      32             : #include <iomanip>
      33             : 
      34             : /*
      35             :  * The output format here is intended to be compatible with YAML,
      36             :  * so it is human readable and usable in diff and can also be parsed with
      37             :  * external tools.
      38             :  */
      39             : 
      40             : // MSVC and GCC give slightly different serializations of floats
      41             : // (e.g. "1e+010" vs "1e+10"). To make the debug serialization easily comparable
      42             : // across platforms, we want to convert to a canonical form.
      43             : // TODO: we just do e+0xx now; ought to handle varying precisions and inf and nan etc too
      44             : template<typename T>
      45          20 : std::string canonfloat(T value, int prec)
      46             : {
      47          40 :     std::stringstream str;
      48          20 :     str << std::setprecision(prec) << value;
      49          20 :     std::string r = str.str();
      50          20 :     size_t e = r.find('e');
      51          20 :     if (e == r.npos) // no "e"
      52           8 :         return r;
      53          12 :     if (e == r.length() - 5 && r[e + 2] == '0') // e.g. "1e+010"
      54           0 :         r.erase(e + 2, 1);
      55          12 :     return r;
      56             : }
      57             : 
      58          21 : CDebugSerializer::CDebugSerializer(const ScriptInterface& scriptInterface, std::ostream& stream, bool includeDebugInfo) :
      59          21 :     m_ScriptInterface(scriptInterface), m_Stream(stream), m_IsDebug(includeDebugInfo), m_Indent(0)
      60             : {
      61          21 : }
      62             : 
      63           8 : void CDebugSerializer::Indent(int spaces)
      64             : {
      65           8 :     m_Indent += spaces;
      66           8 : }
      67             : 
      68           8 : void CDebugSerializer::Dedent(int spaces)
      69             : {
      70           8 :     ENSURE(spaces <= m_Indent);
      71           8 :     m_Indent -= spaces;
      72           8 : }
      73             : 
      74             : #define INDENT std::string(m_Indent, ' ')
      75             : 
      76           1 : void CDebugSerializer::Comment(const std::string& comment)
      77             : {
      78           1 :     m_Stream << INDENT << "# " << comment << "\n";
      79           1 : }
      80             : 
      81          25 : void CDebugSerializer::TextLine(const std::string& text)
      82             : {
      83          25 :     m_Stream << INDENT << text << "\n";
      84          25 : }
      85             : 
      86           1 : void CDebugSerializer::PutNumber(const char* name, uint8_t value)
      87             : {
      88           1 :     m_Stream << INDENT << name << ": " << (int)value << "\n";
      89           1 : }
      90             : 
      91           1 : void CDebugSerializer::PutNumber(const char* name, int8_t value)
      92             : {
      93           1 :     m_Stream << INDENT << name << ": " << (int)value << "\n";
      94           1 : }
      95             : 
      96           9 : void CDebugSerializer::PutNumber(const char* name, uint16_t value)
      97             : {
      98           9 :     m_Stream << INDENT << name << ": " << value << "\n";
      99           9 : }
     100             : 
     101           1 : void CDebugSerializer::PutNumber(const char* name, int16_t value)
     102             : {
     103           1 :     m_Stream << INDENT << name << ": " << value << "\n";
     104           1 : }
     105             : 
     106          43 : void CDebugSerializer::PutNumber(const char* name, uint32_t value)
     107             : {
     108          43 :     m_Stream << INDENT << name << ": " << value << "\n";
     109          43 : }
     110             : 
     111          19 : void CDebugSerializer::PutNumber(const char* name, int32_t value)
     112             : {
     113          19 :     m_Stream << INDENT << name << ": " << value << "\n";
     114          19 : }
     115             : 
     116           9 : void CDebugSerializer::PutNumber(const char* name, float value)
     117             : {
     118           9 :     m_Stream << INDENT << name << ": " << canonfloat(value, 8) << "\n";
     119           9 : }
     120             : 
     121          11 : void CDebugSerializer::PutNumber(const char* name, double value)
     122             : {
     123          11 :     m_Stream << INDENT << name << ": " << canonfloat(value, 17) << "\n";
     124          11 : }
     125             : 
     126          56 : void CDebugSerializer::PutNumber(const char* name, fixed value)
     127             : {
     128          56 :     m_Stream << INDENT << name << ": " << value.ToString() << "\n";
     129          56 : }
     130             : 
     131          20 : void CDebugSerializer::PutBool(const char* name, bool value)
     132             : {
     133          20 :     m_Stream << INDENT << name << ": " << (value ? "true" : "false") << "\n";
     134          20 : }
     135             : 
     136          12 : void CDebugSerializer::PutString(const char* name, const std::string& value)
     137             : {
     138          24 :     std::string escaped;
     139          12 :     escaped.reserve(value.size());
     140          99 :     for (size_t i = 0; i < value.size(); ++i)
     141          87 :         if (value[i] == '"')
     142           2 :             escaped += "\\\"";
     143          85 :         else if (value[i] == '\\')
     144           1 :             escaped += "\\\\";
     145          84 :         else if (value[i] == '\n')
     146           2 :             escaped += "\\n";
     147             :         else
     148          82 :             escaped += value[i];
     149             : 
     150          12 :     m_Stream << INDENT << name << ": " << "\"" << escaped << "\"\n";
     151          12 : }
     152             : 
     153           9 : void CDebugSerializer::PutScriptVal(const char* name, JS::MutableHandleValue value)
     154             : {
     155          18 :     ScriptRequest rq(m_ScriptInterface);
     156             : 
     157          18 :     JS::RootedValue serialize(rq.cx);
     158           9 :     if (Script::GetProperty(rq, value, "Serialize", &serialize) && !serialize.isNullOrUndefined())
     159             :     {
     160             :         // If the value has a Serialize property, pretty-parse that instead.
     161             :         // (this gives more accurate OOS reports).
     162           1 :         ScriptFunction::Call(rq, value, "Serialize", &serialize);
     163           2 :         std::string serialized_source = Script::ToString(rq, &serialize, true);
     164           1 :         m_Stream << INDENT << name << ": " << serialized_source << "\n";
     165             :     }
     166             :     else
     167             :     {
     168          16 :         std::string source = Script::ToString(rq, value, true);
     169           8 :         m_Stream << INDENT << name << ": " << source << "\n";
     170             :     }
     171           9 : }
     172             : 
     173           1 : void CDebugSerializer::PutRaw(const char* name, const u8* data, size_t len)
     174             : {
     175           1 :     m_Stream << INDENT << name << ": (" << len << " bytes)";
     176             : 
     177             :     char buf[4];
     178           7 :     for (size_t i = 0; i < len; ++i)
     179             :     {
     180           6 :         sprintf_s(buf, ARRAY_SIZE(buf), " %02x", (unsigned int)data[i]);
     181           6 :         m_Stream << buf;
     182             :     }
     183             : 
     184           1 :     m_Stream << "\n";
     185           1 : }
     186             : 
     187           6 : bool CDebugSerializer::IsDebug() const
     188             : {
     189           6 :     return m_IsDebug;
     190             : }
     191             : 
     192           0 : std::ostream& CDebugSerializer::GetStream()
     193             : {
     194           0 :     return m_Stream;
     195             : }

Generated by: LCOV version 1.13