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-05-24 03:54:53 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         168 : CPLJSonStreamingWriter::CPLJSonStreamingWriter(
      25         168 :     SerializationFuncType pfnSerializationFunc, void *pUserData)
      26         168 :     : m_pfnSerializationFunc(pfnSerializationFunc), m_pUserData(pUserData)
      27             : {
      28         168 : }
      29             : 
      30         168 : CPLJSonStreamingWriter::~CPLJSonStreamingWriter()
      31             : {
      32         168 :     CPLAssert(m_nLevel == 0);
      33         168 :     CPLAssert(m_states.empty());
      34         168 : }
      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       16525 : void CPLJSonStreamingWriter::Serialize(const std::string_view &str)
      46             : {
      47       16525 :     if (m_pfnSerializationFunc)
      48             :     {
      49        4376 :         m_osTmpForSerialize = str;
      50        4376 :         m_pfnSerializationFunc(m_osTmpForSerialize.c_str(), m_pUserData);
      51             :     }
      52             :     else
      53             :     {
      54       12149 :         m_osStr.append(str);
      55             :     }
      56       16525 : }
      57             : 
      58       12763 : void CPLJSonStreamingWriter::Serialize(const char *pszStr, size_t nLength)
      59             : {
      60       12763 :     Serialize(std::string_view(pszStr, nLength));
      61       12763 : }
      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        1086 : void CPLJSonStreamingWriter::IncIndent()
      71             : {
      72        1086 :     m_nLevel++;
      73        1086 :     if (m_bPretty)
      74         953 :         m_osIndentAcc += m_osIndent;
      75        1086 : }
      76             : 
      77        1076 : void CPLJSonStreamingWriter::DecIndent()
      78             : {
      79        1076 :     CPLAssert(m_nLevel > 0);
      80        1076 :     m_nLevel--;
      81        1076 :     if (m_bPretty)
      82         943 :         m_osIndentAcc.resize(m_osIndentAcc.size() - m_osIndent.size());
      83        1076 : }
      84             : 
      85             : const std::string &
      86        3115 : CPLJSonStreamingWriter::FormatString(const std::string_view &str)
      87             : {
      88        3115 :     m_osTmpForFormatString.clear();
      89        3115 :     m_osTmpForFormatString += '"';
      90       46848 :     for (char ch : str)
      91             :     {
      92       43733 :         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       42764 :             default:
     116       42764 :                 if (static_cast<unsigned char>(ch) < ' ')
     117           2 :                     m_osTmpForFormatString += CPLSPrintf("\\u%04X", ch);
     118             :                 else
     119       42762 :                     m_osTmpForFormatString += ch;
     120       42764 :                 break;
     121             :         }
     122             :     }
     123        3115 :     m_osTmpForFormatString += '"';
     124        3115 :     return m_osTmpForFormatString;
     125             : }
     126             : 
     127        4919 : void CPLJSonStreamingWriter::EmitCommaIfNeeded()
     128             : {
     129        4919 :     if (m_bWaitForValue)
     130             :     {
     131        1868 :         m_bWaitForValue = false;
     132             :     }
     133        3051 :     else if (!m_states.empty())
     134             :     {
     135        2869 :         if (!m_states.back().bFirstChild)
     136             :         {
     137        1823 :             Serialize(",", 1);
     138        1823 :             if (m_bPretty && !m_bNewLineEnabled)
     139         129 :                 Serialize(" ", 1);
     140             :         }
     141        2869 :         if (m_bPretty && m_bNewLineEnabled)
     142             :         {
     143        2485 :             Serialize("\n", 1);
     144        2485 :             Serialize(m_osIndentAcc.c_str(), m_osIndentAcc.size());
     145             :         }
     146        2869 :         m_states.back().bFirstChild = false;
     147             :     }
     148        4919 : }
     149             : 
     150         666 : void CPLJSonStreamingWriter::StartObj()
     151             : {
     152         666 :     EmitCommaIfNeeded();
     153         666 :     Serialize("{", 1);
     154         666 :     IncIndent();
     155         666 :     m_states.emplace_back(State(true));
     156         666 : }
     157             : 
     158         656 : void CPLJSonStreamingWriter::EndObj()
     159             : {
     160         656 :     CPLAssert(!m_bWaitForValue);
     161         656 :     CPLAssert(!m_states.empty());
     162         656 :     CPLAssert(m_states.back().bIsObj);
     163         656 :     DecIndent();
     164         656 :     if (!m_states.back().bFirstChild)
     165             :     {
     166         634 :         if (m_bPretty && m_bNewLineEnabled)
     167             :         {
     168         540 :             Serialize("\n", 1);
     169         540 :             Serialize(m_osIndentAcc.c_str(), m_osIndentAcc.size());
     170             :         }
     171             :     }
     172         656 :     m_states.pop_back();
     173         656 :     Serialize("}", 1);
     174         656 : }
     175             : 
     176         420 : void CPLJSonStreamingWriter::StartArray()
     177             : {
     178         420 :     EmitCommaIfNeeded();
     179         420 :     Serialize("[", 1);
     180         420 :     IncIndent();
     181         420 :     m_states.emplace_back(State(false));
     182         420 : }
     183             : 
     184         420 : void CPLJSonStreamingWriter::EndArray()
     185             : {
     186         420 :     CPLAssert(!m_states.empty());
     187         420 :     CPLAssert(!m_states.back().bIsObj);
     188         420 :     DecIndent();
     189         420 :     if (!m_states.back().bFirstChild)
     190             :     {
     191         402 :         if (m_bPretty && m_bNewLineEnabled)
     192             :         {
     193         330 :             Serialize("\n", 1);
     194         330 :             Serialize(m_osIndentAcc.c_str(), m_osIndentAcc.size());
     195             :         }
     196             :     }
     197         420 :     m_states.pop_back();
     198         420 :     Serialize("]", 1);
     199         420 : }
     200             : 
     201        1868 : void CPLJSonStreamingWriter::AddObjKey(const std::string_view &key)
     202             : {
     203        1868 :     CPLAssert(!m_states.empty());
     204        1868 :     CPLAssert(m_states.back().bIsObj);
     205        1868 :     CPLAssert(!m_bWaitForValue);
     206        1868 :     EmitCommaIfNeeded();
     207        1868 :     Serialize(FormatString(key));
     208        1868 :     if (m_bPretty)
     209        1704 :         Serialize(": ", 2);
     210             :     else
     211         164 :         Serialize(":", 1);
     212        1868 :     m_bWaitForValue = true;
     213        1868 : }
     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         482 : void CPLJSonStreamingWriter::Add(const char *pszStr)
     222             : {
     223         482 :     EmitCommaIfNeeded();
     224         482 :     Serialize(FormatString(std::string_view(pszStr)));
     225         482 : }
     226             : 
     227          24 : void CPLJSonStreamingWriter::Add(const std::string_view &str)
     228             : {
     229          24 :     EmitCommaIfNeeded();
     230          24 :     Serialize(FormatString(str));
     231          24 : }
     232             : 
     233         741 : void CPLJSonStreamingWriter::Add(const std::string &str)
     234             : {
     235         741 :     EmitCommaIfNeeded();
     236         741 :     Serialize(FormatString(str));
     237         741 : }
     238             : 
     239         135 : void CPLJSonStreamingWriter::AddSerializedValue(const std::string_view &str)
     240             : {
     241         135 :     EmitCommaIfNeeded();
     242         135 :     Serialize(str);
     243         135 : }
     244             : 
     245         165 : void CPLJSonStreamingWriter::Add(std::int64_t nVal)
     246             : {
     247         165 :     EmitCommaIfNeeded();
     248         165 :     Serialize(CPLSPrintf(CPL_FRMT_GIB, static_cast<GIntBig>(nVal)));
     249         165 : }
     250             : 
     251         282 : void CPLJSonStreamingWriter::Add(std::uint64_t nVal)
     252             : {
     253         282 :     EmitCommaIfNeeded();
     254         282 :     Serialize(CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nVal)));
     255         282 : }
     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