LCOV - code coverage report
Current view: top level - port - cpl_json_streaming_writer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 177 192 92.2 %
Date: 2025-07-09 17:50:03 Functions: 24 27 88.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         169 : CPLJSonStreamingWriter::CPLJSonStreamingWriter(
      25         169 :     SerializationFuncType pfnSerializationFunc, void *pUserData)
      26         169 :     : m_pfnSerializationFunc(pfnSerializationFunc), m_pUserData(pUserData)
      27             : {
      28         169 : }
      29             : 
      30         169 : CPLJSonStreamingWriter::~CPLJSonStreamingWriter()
      31             : {
      32         169 :     CPLAssert(m_nLevel == 0);
      33         169 :     CPLAssert(m_states.empty());
      34         169 : }
      35             : 
      36         200 : void CPLJSonStreamingWriter::clear()
      37             : {
      38         200 :     m_nLevel = 0;
      39         200 :     m_osStr.clear();
      40         200 :     m_osIndentAcc.clear();
      41         200 :     m_states.clear();
      42         200 :     m_bWaitForValue = false;
      43         200 : }
      44             : 
      45       16818 : void CPLJSonStreamingWriter::Serialize(const std::string_view &str)
      46             : {
      47       16818 :     if (m_pfnSerializationFunc)
      48             :     {
      49        4388 :         m_osTmpForSerialize = str;
      50        4388 :         m_pfnSerializationFunc(m_osTmpForSerialize.c_str(), m_pUserData);
      51             :     }
      52             :     else
      53             :     {
      54       12430 :         m_osStr.append(str);
      55             :     }
      56       16818 : }
      57             : 
      58       12988 : void CPLJSonStreamingWriter::Serialize(const char *pszStr, size_t nLength)
      59             : {
      60       12988 :     Serialize(std::string_view(pszStr, nLength));
      61       12988 : }
      62             : 
      63           0 : void CPLJSonStreamingWriter::SetIndentationSize(int nSpaces)
      64             : {
      65           0 :     CPLAssert(m_nLevel == 0);
      66           0 :     m_osIndent.clear();
      67           0 :     m_osIndent.resize(nSpaces, ' ');
      68           0 : }
      69             : 
      70        1101 : void CPLJSonStreamingWriter::IncIndent()
      71             : {
      72        1101 :     m_nLevel++;
      73        1101 :     if (m_bPretty)
      74         968 :         m_osIndentAcc += m_osIndent;
      75        1101 : }
      76             : 
      77        1091 : void CPLJSonStreamingWriter::DecIndent()
      78             : {
      79        1091 :     CPLAssert(m_nLevel > 0);
      80        1091 :     m_nLevel--;
      81        1091 :     if (m_bPretty)
      82         958 :         m_osIndentAcc.resize(m_osIndentAcc.size() - m_osIndent.size());
      83        1091 : }
      84             : 
      85             : const std::string &
      86        3172 : CPLJSonStreamingWriter::FormatString(const std::string_view &str)
      87             : {
      88        3172 :     m_osTmpForFormatString.clear();
      89        3172 :     m_osTmpForFormatString += '"';
      90       47320 :     for (char ch : str)
      91             :     {
      92       44148 :         switch (ch)
      93             :         {
      94         794 :             case '"':
      95         794 :                 m_osTmpForFormatString += "\\\"";
      96         794 :                 break;
      97           2 :             case '\\':
      98           2 :                 m_osTmpForFormatString += "\\\\";
      99           2 :                 break;
     100           2 :             case '\b':
     101           2 :                 m_osTmpForFormatString += "\\b";
     102           2 :                 break;
     103           2 :             case '\f':
     104           2 :                 m_osTmpForFormatString += "\\f";
     105           2 :                 break;
     106         165 :             case '\n':
     107         165 :                 m_osTmpForFormatString += "\\n";
     108         165 :                 break;
     109           2 :             case '\r':
     110           2 :                 m_osTmpForFormatString += "\\r";
     111           2 :                 break;
     112           2 :             case '\t':
     113           2 :                 m_osTmpForFormatString += "\\t";
     114           2 :                 break;
     115       43179 :             default:
     116       43179 :                 if (static_cast<unsigned char>(ch) < ' ')
     117           2 :                     m_osTmpForFormatString += CPLSPrintf("\\u%04X", ch);
     118             :                 else
     119       43177 :                     m_osTmpForFormatString += ch;
     120       43179 :                 break;
     121             :         }
     122             :     }
     123        3172 :     m_osTmpForFormatString += '"';
     124        3172 :     return m_osTmpForFormatString;
     125             : }
     126             : 
     127        5002 : void CPLJSonStreamingWriter::EmitCommaIfNeeded()
     128             : {
     129        5002 :     if (m_bWaitForValue)
     130             :     {
     131        1903 :         m_bWaitForValue = false;
     132             :     }
     133        3099 :     else if (!m_states.empty())
     134             :     {
     135        2917 :         if (!m_states.back().bFirstChild)
     136             :         {
     137        1855 :             Serialize(",", 1);
     138        1855 :             if (m_bPretty && !m_bNewLineEnabled)
     139         129 :                 Serialize(" ", 1);
     140             :         }
     141        2917 :         if (m_bPretty && m_bNewLineEnabled)
     142             :         {
     143        2533 :             Serialize("\n", 1);
     144        2533 :             Serialize(m_osIndentAcc.c_str(), m_osIndentAcc.size());
     145             :         }
     146        2917 :         m_states.back().bFirstChild = false;
     147             :     }
     148        5002 : }
     149             : 
     150         678 : void CPLJSonStreamingWriter::StartObj()
     151             : {
     152         678 :     EmitCommaIfNeeded();
     153         678 :     Serialize("{", 1);
     154         678 :     IncIndent();
     155         678 :     m_states.emplace_back(State(true));
     156         678 : }
     157             : 
     158         668 : void CPLJSonStreamingWriter::EndObj()
     159             : {
     160         668 :     CPLAssert(!m_bWaitForValue);
     161         668 :     CPLAssert(!m_states.empty());
     162         668 :     CPLAssert(m_states.back().bIsObj);
     163         668 :     DecIndent();
     164         668 :     if (!m_states.back().bFirstChild)
     165             :     {
     166         647 :         if (m_bPretty && m_bNewLineEnabled)
     167             :         {
     168         553 :             Serialize("\n", 1);
     169         553 :             Serialize(m_osIndentAcc.c_str(), m_osIndentAcc.size());
     170             :         }
     171             :     }
     172         668 :     m_states.pop_back();
     173         668 :     Serialize("}", 1);
     174         668 : }
     175             : 
     176         423 : void CPLJSonStreamingWriter::StartArray()
     177             : {
     178         423 :     EmitCommaIfNeeded();
     179         423 :     Serialize("[", 1);
     180         423 :     IncIndent();
     181         423 :     m_states.emplace_back(State(false));
     182         423 : }
     183             : 
     184         423 : void CPLJSonStreamingWriter::EndArray()
     185             : {
     186         423 :     CPLAssert(!m_states.empty());
     187         423 :     CPLAssert(!m_states.back().bIsObj);
     188         423 :     DecIndent();
     189         423 :     if (!m_states.back().bFirstChild)
     190             :     {
     191         405 :         if (m_bPretty && m_bNewLineEnabled)
     192             :         {
     193         333 :             Serialize("\n", 1);
     194         333 :             Serialize(m_osIndentAcc.c_str(), m_osIndentAcc.size());
     195             :         }
     196             :     }
     197         423 :     m_states.pop_back();
     198         423 :     Serialize("]", 1);
     199         423 : }
     200             : 
     201        1903 : void CPLJSonStreamingWriter::AddObjKey(const std::string_view &key)
     202             : {
     203        1903 :     CPLAssert(!m_states.empty());
     204        1903 :     CPLAssert(m_states.back().bIsObj);
     205        1903 :     CPLAssert(!m_bWaitForValue);
     206        1903 :     EmitCommaIfNeeded();
     207        1903 :     Serialize(FormatString(key));
     208        1903 :     if (m_bPretty)
     209        1739 :         Serialize(": ", 2);
     210             :     else
     211         164 :         Serialize(":", 1);
     212        1903 :     m_bWaitForValue = true;
     213        1903 : }
     214             : 
     215           5 : void CPLJSonStreamingWriter::Add(bool bVal)
     216             : {
     217           5 :     EmitCommaIfNeeded();
     218           5 :     Serialize(bVal ? "true" : "false", bVal ? 4 : 5);
     219           5 : }
     220             : 
     221         490 : void CPLJSonStreamingWriter::Add(const char *pszStr)
     222             : {
     223         490 :     EmitCommaIfNeeded();
     224         490 :     Serialize(FormatString(std::string_view(pszStr)));
     225         490 : }
     226             : 
     227          24 : void CPLJSonStreamingWriter::Add(const std::string_view &str)
     228             : {
     229          24 :     EmitCommaIfNeeded();
     230          24 :     Serialize(FormatString(str));
     231          24 : }
     232             : 
     233         755 : void CPLJSonStreamingWriter::Add(const std::string &str)
     234             : {
     235         755 :     EmitCommaIfNeeded();
     236         755 :     Serialize(FormatString(str));
     237         755 : }
     238             : 
     239         135 : void CPLJSonStreamingWriter::AddSerializedValue(const std::string_view &str)
     240             : {
     241         135 :     EmitCommaIfNeeded();
     242         135 :     Serialize(str);
     243         135 : }
     244             : 
     245         174 : void CPLJSonStreamingWriter::Add(std::int64_t nVal)
     246             : {
     247         174 :     EmitCommaIfNeeded();
     248         174 :     Serialize(CPLSPrintf(CPL_FRMT_GIB, static_cast<GIntBig>(nVal)));
     249         174 : }
     250             : 
     251         284 : void CPLJSonStreamingWriter::Add(std::uint64_t nVal)
     252             : {
     253         284 :     EmitCommaIfNeeded();
     254         284 :     Serialize(CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nVal)));
     255         284 : }
     256             : 
     257           0 : void CPLJSonStreamingWriter::Add(GFloat16 hfVal, int nPrecision)
     258             : {
     259           0 :     EmitCommaIfNeeded();
     260           0 :     if (CPLIsNan(hfVal))
     261             :     {
     262           0 :         Serialize("\"NaN\"", 5);
     263             :     }
     264           0 :     else if (CPLIsInf(hfVal))
     265             :     {
     266           0 :         Serialize(hfVal > 0 ? "\"Infinity\"" : "\"-Infinity\"",
     267           0 :                   hfVal > 0 ? 10 : 11);
     268             :     }
     269             :     else
     270             :     {
     271             :         char szFormatting[10];
     272           0 :         snprintf(szFormatting, sizeof(szFormatting), "%%.%dg", nPrecision);
     273           0 :         Serialize(CPLSPrintf(szFormatting, float(hfVal)));
     274             :     }
     275           0 : }
     276             : 
     277          18 : void CPLJSonStreamingWriter::Add(float fVal, int nPrecision)
     278             : {
     279          18 :     EmitCommaIfNeeded();
     280          18 :     if (std::isnan(fVal))
     281             :     {
     282           3 :         Serialize("\"NaN\"", 5);
     283             :     }
     284          15 :     else if (std::isinf(fVal))
     285             :     {
     286           2 :         Serialize(fVal > 0 ? "\"Infinity\"" : "\"-Infinity\"",
     287             :                   fVal > 0 ? 10 : 11);
     288             :     }
     289             :     else
     290             :     {
     291             :         char szFormatting[10];
     292          13 :         snprintf(szFormatting, sizeof(szFormatting), "%%.%dg", nPrecision);
     293          13 :         Serialize(CPLSPrintf(szFormatting, fVal));
     294             :     }
     295          18 : }
     296             : 
     297          87 : void CPLJSonStreamingWriter::Add(double dfVal, int nPrecision)
     298             : {
     299          87 :     EmitCommaIfNeeded();
     300          87 :     if (std::isnan(dfVal))
     301             :     {
     302          35 :         Serialize("\"NaN\"", 5);
     303             :     }
     304          52 :     else if (std::isinf(dfVal))
     305             :     {
     306           2 :         Serialize(dfVal > 0 ? "\"Infinity\"" : "\"-Infinity\"");
     307             :     }
     308             :     else
     309             :     {
     310             :         char szFormatting[10];
     311          50 :         snprintf(szFormatting, sizeof(szFormatting), "%%.%dg", nPrecision);
     312          50 :         Serialize(CPLSPrintf(szFormatting, dfVal));
     313             :     }
     314          87 : }
     315             : 
     316          26 : void CPLJSonStreamingWriter::AddNull()
     317             : {
     318          26 :     EmitCommaIfNeeded();
     319          26 :     Serialize("null", 4);
     320          26 : }
     321             : 
     322             : /*! @endcond */

Generated by: LCOV version 1.14