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 170 91.8 %
Date: 2025-02-20 10:14:44 Functions: 20 22 90.9 %

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

Generated by: LCOV version 1.14