LCOV - code coverage report
Current view: top level - port - cpl_json_streaming_writer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 156 161 96.9 %
Date: 2024-11-21 22:18:42 Functions: 20 21 95.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  CPL - Common Portability Library
       4             :  * Purpose:  JSon streaming writer
       5             :  * Author:   Even Rouault, even.rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2019, Even Rouault <even.rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : /*! @cond Doxygen_Suppress */
      14             : 
      15             : #include <cmath>
      16             : #include <vector>
      17             : #include <string>
      18             : 
      19             : #include "cpl_conv.h"
      20             : #include "cpl_string.h"
      21             : #include "cpl_json_streaming_writer.h"
      22             : 
      23          50 : CPLJSonStreamingWriter::CPLJSonStreamingWriter(
      24          50 :     SerializationFuncType pfnSerializationFunc, void *pUserData)
      25          50 :     : m_pfnSerializationFunc(pfnSerializationFunc), m_pUserData(pUserData)
      26             : {
      27          50 : }
      28             : 
      29          50 : CPLJSonStreamingWriter::~CPLJSonStreamingWriter()
      30             : {
      31          50 :     CPLAssert(m_nLevel == 0);
      32          50 :     CPLAssert(m_states.empty());
      33          50 : }
      34             : 
      35        7969 : void CPLJSonStreamingWriter::Print(const std::string &text)
      36             : {
      37        7969 :     if (m_pfnSerializationFunc)
      38             :     {
      39        1411 :         m_pfnSerializationFunc(text.c_str(), m_pUserData);
      40             :     }
      41             :     else
      42             :     {
      43        6558 :         m_osStr += text;
      44             :     }
      45        7969 : }
      46             : 
      47           0 : void CPLJSonStreamingWriter::SetIndentationSize(int nSpaces)
      48             : {
      49           0 :     CPLAssert(m_nLevel == 0);
      50           0 :     m_osIndent.clear();
      51           0 :     m_osIndent.resize(nSpaces, ' ');
      52           0 : }
      53             : 
      54         531 : void CPLJSonStreamingWriter::IncIndent()
      55             : {
      56         531 :     m_nLevel++;
      57         531 :     if (m_bPretty)
      58         529 :         m_osIndentAcc += m_osIndent;
      59         531 : }
      60             : 
      61         531 : void CPLJSonStreamingWriter::DecIndent()
      62             : {
      63         531 :     CPLAssert(m_nLevel > 0);
      64         531 :     m_nLevel--;
      65         531 :     if (m_bPretty)
      66         529 :         m_osIndentAcc.resize(m_osIndentAcc.size() - m_osIndent.size());
      67         531 : }
      68             : 
      69        1408 : std::string CPLJSonStreamingWriter::FormatString(const std::string &str)
      70             : {
      71        1408 :     std::string ret;
      72        1408 :     ret += '"';
      73       18762 :     for (char ch : str)
      74             :     {
      75       17354 :         switch (ch)
      76             :         {
      77         608 :             case '"':
      78         608 :                 ret += "\\\"";
      79         608 :                 break;
      80           2 :             case '\\':
      81           2 :                 ret += "\\\\";
      82           2 :                 break;
      83           2 :             case '\b':
      84           2 :                 ret += "\\b";
      85           2 :                 break;
      86           2 :             case '\f':
      87           2 :                 ret += "\\f";
      88           2 :                 break;
      89         165 :             case '\n':
      90         165 :                 ret += "\\n";
      91         165 :                 break;
      92           2 :             case '\r':
      93           2 :                 ret += "\\r";
      94           2 :                 break;
      95           2 :             case '\t':
      96           2 :                 ret += "\\t";
      97           2 :                 break;
      98       16571 :             default:
      99       16571 :                 if (static_cast<unsigned char>(ch) < ' ')
     100           2 :                     ret += CPLSPrintf("\\u%04X", ch);
     101             :                 else
     102       16569 :                     ret += ch;
     103       16571 :                 break;
     104             :         }
     105             :     }
     106        1408 :     ret += '"';
     107        1408 :     return ret;
     108             : }
     109             : 
     110        2307 : void CPLJSonStreamingWriter::EmitCommaIfNeeded()
     111             : {
     112        2307 :     if (m_bWaitForValue)
     113             :     {
     114         940 :         m_bWaitForValue = false;
     115             :     }
     116        1367 :     else if (!m_states.empty())
     117             :     {
     118        1319 :         if (!m_states.back().bFirstChild)
     119             :         {
     120         797 :             Print(",");
     121         797 :             if (m_bPretty && !m_bNewLineEnabled)
     122          88 :                 Print(" ");
     123             :         }
     124        1319 :         if (m_bPretty && m_bNewLineEnabled)
     125             :         {
     126        1181 :             Print("\n");
     127        1181 :             Print(m_osIndentAcc);
     128             :         }
     129        1319 :         m_states.back().bFirstChild = false;
     130             :     }
     131        2307 : }
     132             : 
     133         307 : void CPLJSonStreamingWriter::StartObj()
     134             : {
     135         307 :     EmitCommaIfNeeded();
     136         307 :     Print("{");
     137         307 :     IncIndent();
     138         307 :     m_states.emplace_back(State(true));
     139         307 : }
     140             : 
     141         307 : void CPLJSonStreamingWriter::EndObj()
     142             : {
     143         307 :     CPLAssert(!m_bWaitForValue);
     144         307 :     CPLAssert(!m_states.empty());
     145         307 :     CPLAssert(m_states.back().bIsObj);
     146         307 :     DecIndent();
     147         307 :     if (!m_states.back().bFirstChild)
     148             :     {
     149         301 :         if (m_bPretty && m_bNewLineEnabled)
     150             :         {
     151         286 :             Print("\n");
     152         286 :             Print(m_osIndentAcc);
     153             :         }
     154             :     }
     155         307 :     m_states.pop_back();
     156         307 :     Print("}");
     157         307 : }
     158             : 
     159         224 : void CPLJSonStreamingWriter::StartArray()
     160             : {
     161         224 :     EmitCommaIfNeeded();
     162         224 :     Print("[");
     163         224 :     IncIndent();
     164         224 :     m_states.emplace_back(State(false));
     165         224 : }
     166             : 
     167         224 : void CPLJSonStreamingWriter::EndArray()
     168             : {
     169         224 :     CPLAssert(!m_states.empty());
     170         224 :     CPLAssert(!m_states.back().bIsObj);
     171         224 :     DecIndent();
     172         224 :     if (!m_states.back().bFirstChild)
     173             :     {
     174         221 :         if (m_bPretty && m_bNewLineEnabled)
     175             :         {
     176         186 :             Print("\n");
     177         186 :             Print(m_osIndentAcc);
     178             :         }
     179             :     }
     180         224 :     m_states.pop_back();
     181         224 :     Print("]");
     182         224 : }
     183             : 
     184         940 : void CPLJSonStreamingWriter::AddObjKey(const std::string &key)
     185             : {
     186         940 :     CPLAssert(!m_states.empty());
     187         940 :     CPLAssert(m_states.back().bIsObj);
     188         940 :     CPLAssert(!m_bWaitForValue);
     189         940 :     EmitCommaIfNeeded();
     190         940 :     Print(FormatString(key));
     191         940 :     Print(m_bPretty ? ": " : ":");
     192         940 :     m_bWaitForValue = true;
     193         940 : }
     194             : 
     195           5 : void CPLJSonStreamingWriter::Add(bool bVal)
     196             : {
     197           5 :     EmitCommaIfNeeded();
     198           5 :     Print(bVal ? "true" : "false");
     199           5 : }
     200             : 
     201         279 : void CPLJSonStreamingWriter::Add(const std::string &str)
     202             : {
     203         279 :     EmitCommaIfNeeded();
     204         279 :     Print(FormatString(str));
     205         279 : }
     206             : 
     207         189 : void CPLJSonStreamingWriter::Add(const char *pszStr)
     208             : {
     209         189 :     EmitCommaIfNeeded();
     210         189 :     Print(FormatString(pszStr));
     211         189 : }
     212             : 
     213         119 : void CPLJSonStreamingWriter::Add(std::int64_t nVal)
     214             : {
     215         119 :     EmitCommaIfNeeded();
     216         119 :     Print(CPLSPrintf(CPL_FRMT_GIB, static_cast<GIntBig>(nVal)));
     217         119 : }
     218             : 
     219         160 : void CPLJSonStreamingWriter::Add(std::uint64_t nVal)
     220             : {
     221         160 :     EmitCommaIfNeeded();
     222         160 :     Print(CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nVal)));
     223         160 : }
     224             : 
     225          18 : void CPLJSonStreamingWriter::Add(float fVal, int nPrecision)
     226             : {
     227          18 :     EmitCommaIfNeeded();
     228          18 :     if (std::isnan(fVal))
     229             :     {
     230           3 :         Print("\"NaN\"");
     231             :     }
     232          15 :     else if (std::isinf(fVal))
     233             :     {
     234           2 :         Print(fVal > 0 ? "\"Infinity\"" : "\"-Infinity\"");
     235             :     }
     236             :     else
     237             :     {
     238             :         char szFormatting[10];
     239          13 :         snprintf(szFormatting, sizeof(szFormatting), "%%.%dg", nPrecision);
     240          13 :         Print(CPLSPrintf(szFormatting, fVal));
     241             :     }
     242          18 : }
     243             : 
     244          65 : void CPLJSonStreamingWriter::Add(double dfVal, int nPrecision)
     245             : {
     246          65 :     EmitCommaIfNeeded();
     247          65 :     if (std::isnan(dfVal))
     248             :     {
     249          35 :         Print("\"NaN\"");
     250             :     }
     251          30 :     else if (std::isinf(dfVal))
     252             :     {
     253           2 :         Print(dfVal > 0 ? "\"Infinity\"" : "\"-Infinity\"");
     254             :     }
     255             :     else
     256             :     {
     257             :         char szFormatting[10];
     258          28 :         snprintf(szFormatting, sizeof(szFormatting), "%%.%dg", nPrecision);
     259          28 :         Print(CPLSPrintf(szFormatting, dfVal));
     260             :     }
     261          65 : }
     262             : 
     263           1 : void CPLJSonStreamingWriter::AddNull()
     264             : {
     265           1 :     EmitCommaIfNeeded();
     266           1 :     Print("null");
     267           1 : }
     268             : 
     269             : /*! @endcond */

Generated by: LCOV version 1.14