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-03-28 11:40:40 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          57 : CPLJSonStreamingWriter::CPLJSonStreamingWriter(
      25          57 :     SerializationFuncType pfnSerializationFunc, void *pUserData)
      26          57 :     : m_pfnSerializationFunc(pfnSerializationFunc), m_pUserData(pUserData)
      27             : {
      28          57 : }
      29             : 
      30          57 : CPLJSonStreamingWriter::~CPLJSonStreamingWriter()
      31             : {
      32          57 :     CPLAssert(m_nLevel == 0);
      33          57 :     CPLAssert(m_states.empty());
      34          57 : }
      35             : 
      36       12581 : void CPLJSonStreamingWriter::Print(const std::string &text)
      37             : {
      38       12581 :     if (m_pfnSerializationFunc)
      39             :     {
      40        1411 :         m_pfnSerializationFunc(text.c_str(), m_pUserData);
      41             :     }
      42             :     else
      43             :     {
      44       11170 :         m_osStr += text;
      45             :     }
      46       12581 : }
      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         833 : void CPLJSonStreamingWriter::IncIndent()
      56             : {
      57         833 :     m_nLevel++;
      58         833 :     if (m_bPretty)
      59         831 :         m_osIndentAcc += m_osIndent;
      60         833 : }
      61             : 
      62         833 : void CPLJSonStreamingWriter::DecIndent()
      63             : {
      64         833 :     CPLAssert(m_nLevel > 0);
      65         833 :     m_nLevel--;
      66         833 :     if (m_bPretty)
      67         831 :         m_osIndentAcc.resize(m_osIndentAcc.size() - m_osIndent.size());
      68         833 : }
      69             : 
      70        2231 : std::string CPLJSonStreamingWriter::FormatString(const std::string &str)
      71             : {
      72        2231 :     std::string ret;
      73        2231 :     ret += '"';
      74       30032 :     for (char ch : str)
      75             :     {
      76       27801 :         switch (ch)
      77             :         {
      78         794 :             case '"':
      79         794 :                 ret += "\\\"";
      80         794 :                 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       26832 :             default:
     100       26832 :                 if (static_cast<unsigned char>(ch) < ' ')
     101           2 :                     ret += CPLSPrintf("\\u%04X", ch);
     102             :                 else
     103       26830 :                     ret += ch;
     104       26832 :                 break;
     105             :         }
     106             :     }
     107        2231 :     ret += '"';
     108        2231 :     return ret;
     109             : }
     110             : 
     111        3598 : void CPLJSonStreamingWriter::EmitCommaIfNeeded()
     112             : {
     113        3598 :     if (m_bWaitForValue)
     114             :     {
     115        1461 :         m_bWaitForValue = false;
     116             :     }
     117        2137 :     else if (!m_states.empty())
     118             :     {
     119        2082 :         if (!m_states.back().bFirstChild)
     120             :         {
     121        1258 :             Print(",");
     122        1258 :             if (m_bPretty && !m_bNewLineEnabled)
     123         129 :                 Print(" ");
     124             :         }
     125        2082 :         if (m_bPretty && m_bNewLineEnabled)
     126             :         {
     127        1890 :             Print("\n");
     128        1890 :             Print(m_osIndentAcc);
     129             :         }
     130        2082 :         m_states.back().bFirstChild = false;
     131             :     }
     132        3598 : }
     133             : 
     134         474 : void CPLJSonStreamingWriter::StartObj()
     135             : {
     136         474 :     EmitCommaIfNeeded();
     137         474 :     Print("{");
     138         474 :     IncIndent();
     139         474 :     m_states.emplace_back(State(true));
     140         474 : }
     141             : 
     142         474 : void CPLJSonStreamingWriter::EndObj()
     143             : {
     144         474 :     CPLAssert(!m_bWaitForValue);
     145         474 :     CPLAssert(!m_states.empty());
     146         474 :     CPLAssert(m_states.back().bIsObj);
     147         474 :     DecIndent();
     148         474 :     if (!m_states.back().bFirstChild)
     149             :     {
     150         468 :         if (m_bPretty && m_bNewLineEnabled)
     151             :         {
     152         453 :             Print("\n");
     153         453 :             Print(m_osIndentAcc);
     154             :         }
     155             :     }
     156         474 :     m_states.pop_back();
     157         474 :     Print("}");
     158         474 : }
     159             : 
     160         359 : void CPLJSonStreamingWriter::StartArray()
     161             : {
     162         359 :     EmitCommaIfNeeded();
     163         359 :     Print("[");
     164         359 :     IncIndent();
     165         359 :     m_states.emplace_back(State(false));
     166         359 : }
     167             : 
     168         359 : void CPLJSonStreamingWriter::EndArray()
     169             : {
     170         359 :     CPLAssert(!m_states.empty());
     171         359 :     CPLAssert(!m_states.back().bIsObj);
     172         359 :     DecIndent();
     173         359 :     if (!m_states.back().bFirstChild)
     174             :     {
     175         356 :         if (m_bPretty && m_bNewLineEnabled)
     176             :         {
     177         308 :             Print("\n");
     178         308 :             Print(m_osIndentAcc);
     179             :         }
     180             :     }
     181         359 :     m_states.pop_back();
     182         359 :     Print("]");
     183         359 : }
     184             : 
     185        1461 : void CPLJSonStreamingWriter::AddObjKey(const std::string &key)
     186             : {
     187        1461 :     CPLAssert(!m_states.empty());
     188        1461 :     CPLAssert(m_states.back().bIsObj);
     189        1461 :     CPLAssert(!m_bWaitForValue);
     190        1461 :     EmitCommaIfNeeded();
     191        1461 :     Print(FormatString(key));
     192        1461 :     Print(m_bPretty ? ": " : ":");
     193        1461 :     m_bWaitForValue = true;
     194        1461 : }
     195             : 
     196           5 : void CPLJSonStreamingWriter::Add(bool bVal)
     197             : {
     198           5 :     EmitCommaIfNeeded();
     199           5 :     Print(bVal ? "true" : "false");
     200           5 : }
     201             : 
     202         448 : void CPLJSonStreamingWriter::Add(const std::string &str)
     203             : {
     204         448 :     EmitCommaIfNeeded();
     205         448 :     Print(FormatString(str));
     206         448 : }
     207             : 
     208         322 : void CPLJSonStreamingWriter::Add(const char *pszStr)
     209             : {
     210         322 :     EmitCommaIfNeeded();
     211         322 :     Print(FormatString(pszStr));
     212         322 : }
     213             : 
     214         156 : void CPLJSonStreamingWriter::Add(std::int64_t nVal)
     215             : {
     216         156 :     EmitCommaIfNeeded();
     217         156 :     Print(CPLSPrintf(CPL_FRMT_GIB, static_cast<GIntBig>(nVal)));
     218         156 : }
     219             : 
     220         267 : void CPLJSonStreamingWriter::Add(std::uint64_t nVal)
     221             : {
     222         267 :     EmitCommaIfNeeded();
     223         267 :     Print(CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nVal)));
     224         267 : }
     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          87 : void CPLJSonStreamingWriter::Add(double dfVal, int nPrecision)
     265             : {
     266          87 :     EmitCommaIfNeeded();
     267          87 :     if (std::isnan(dfVal))
     268             :     {
     269          35 :         Print("\"NaN\"");
     270             :     }
     271          52 :     else if (std::isinf(dfVal))
     272             :     {
     273           2 :         Print(dfVal > 0 ? "\"Infinity\"" : "\"-Infinity\"");
     274             :     }
     275             :     else
     276             :     {
     277             :         char szFormatting[10];
     278          50 :         snprintf(szFormatting, sizeof(szFormatting), "%%.%dg", nPrecision);
     279          50 :         Print(CPLSPrintf(szFormatting, dfVal));
     280             :     }
     281          87 : }
     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