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-04-28 23:18:46 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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : /*! @cond Doxygen_Suppress */
      30             : 
      31             : #include <vector>
      32             : #include <string>
      33             : 
      34             : #include "cpl_conv.h"
      35             : #include "cpl_string.h"
      36             : #include "cpl_json_streaming_writer.h"
      37             : 
      38          50 : CPLJSonStreamingWriter::CPLJSonStreamingWriter(
      39          50 :     SerializationFuncType pfnSerializationFunc, void *pUserData)
      40          50 :     : m_pfnSerializationFunc(pfnSerializationFunc), m_pUserData(pUserData)
      41             : {
      42          50 : }
      43             : 
      44          50 : CPLJSonStreamingWriter::~CPLJSonStreamingWriter()
      45             : {
      46          50 :     CPLAssert(m_nLevel == 0);
      47          50 :     CPLAssert(m_states.empty());
      48          50 : }
      49             : 
      50        7969 : void CPLJSonStreamingWriter::Print(const std::string &text)
      51             : {
      52        7969 :     if (m_pfnSerializationFunc)
      53             :     {
      54        1411 :         m_pfnSerializationFunc(text.c_str(), m_pUserData);
      55             :     }
      56             :     else
      57             :     {
      58        6558 :         m_osStr += text;
      59             :     }
      60        7969 : }
      61             : 
      62           0 : void CPLJSonStreamingWriter::SetIndentationSize(int nSpaces)
      63             : {
      64           0 :     CPLAssert(m_nLevel == 0);
      65           0 :     m_osIndent.clear();
      66           0 :     m_osIndent.resize(nSpaces, ' ');
      67           0 : }
      68             : 
      69         531 : void CPLJSonStreamingWriter::IncIndent()
      70             : {
      71         531 :     m_nLevel++;
      72         531 :     if (m_bPretty)
      73         529 :         m_osIndentAcc += m_osIndent;
      74         531 : }
      75             : 
      76         531 : void CPLJSonStreamingWriter::DecIndent()
      77             : {
      78         531 :     CPLAssert(m_nLevel > 0);
      79         531 :     m_nLevel--;
      80         531 :     if (m_bPretty)
      81         529 :         m_osIndentAcc.resize(m_osIndentAcc.size() - m_osIndent.size());
      82         531 : }
      83             : 
      84        1408 : std::string CPLJSonStreamingWriter::FormatString(const std::string &str)
      85             : {
      86        1408 :     std::string ret;
      87        1408 :     ret += '"';
      88       18762 :     for (char ch : str)
      89             :     {
      90       17354 :         switch (ch)
      91             :         {
      92         608 :             case '"':
      93         608 :                 ret += "\\\"";
      94         608 :                 break;
      95           2 :             case '\\':
      96           2 :                 ret += "\\\\";
      97           2 :                 break;
      98           2 :             case '\b':
      99           2 :                 ret += "\\b";
     100           2 :                 break;
     101           2 :             case '\f':
     102           2 :                 ret += "\\f";
     103           2 :                 break;
     104         165 :             case '\n':
     105         165 :                 ret += "\\n";
     106         165 :                 break;
     107           2 :             case '\r':
     108           2 :                 ret += "\\r";
     109           2 :                 break;
     110           2 :             case '\t':
     111           2 :                 ret += "\\t";
     112           2 :                 break;
     113       16571 :             default:
     114       16571 :                 if (static_cast<unsigned char>(ch) < ' ')
     115           2 :                     ret += CPLSPrintf("\\u%04X", ch);
     116             :                 else
     117       16569 :                     ret += ch;
     118       16571 :                 break;
     119             :         }
     120             :     }
     121        1408 :     ret += '"';
     122        1408 :     return ret;
     123             : }
     124             : 
     125        2307 : void CPLJSonStreamingWriter::EmitCommaIfNeeded()
     126             : {
     127        2307 :     if (m_bWaitForValue)
     128             :     {
     129         940 :         m_bWaitForValue = false;
     130             :     }
     131        1367 :     else if (!m_states.empty())
     132             :     {
     133        1319 :         if (!m_states.back().bFirstChild)
     134             :         {
     135         797 :             Print(",");
     136         797 :             if (m_bPretty && !m_bNewLineEnabled)
     137          88 :                 Print(" ");
     138             :         }
     139        1319 :         if (m_bPretty && m_bNewLineEnabled)
     140             :         {
     141        1181 :             Print("\n");
     142        1181 :             Print(m_osIndentAcc);
     143             :         }
     144        1319 :         m_states.back().bFirstChild = false;
     145             :     }
     146        2307 : }
     147             : 
     148         307 : void CPLJSonStreamingWriter::StartObj()
     149             : {
     150         307 :     EmitCommaIfNeeded();
     151         307 :     Print("{");
     152         307 :     IncIndent();
     153         307 :     m_states.emplace_back(State(true));
     154         307 : }
     155             : 
     156         307 : void CPLJSonStreamingWriter::EndObj()
     157             : {
     158         307 :     CPLAssert(!m_bWaitForValue);
     159         307 :     CPLAssert(!m_states.empty());
     160         307 :     CPLAssert(m_states.back().bIsObj);
     161         307 :     DecIndent();
     162         307 :     if (!m_states.back().bFirstChild)
     163             :     {
     164         301 :         if (m_bPretty && m_bNewLineEnabled)
     165             :         {
     166         286 :             Print("\n");
     167         286 :             Print(m_osIndentAcc);
     168             :         }
     169             :     }
     170         307 :     m_states.pop_back();
     171         307 :     Print("}");
     172         307 : }
     173             : 
     174         224 : void CPLJSonStreamingWriter::StartArray()
     175             : {
     176         224 :     EmitCommaIfNeeded();
     177         224 :     Print("[");
     178         224 :     IncIndent();
     179         224 :     m_states.emplace_back(State(false));
     180         224 : }
     181             : 
     182         224 : void CPLJSonStreamingWriter::EndArray()
     183             : {
     184         224 :     CPLAssert(!m_states.empty());
     185         224 :     CPLAssert(!m_states.back().bIsObj);
     186         224 :     DecIndent();
     187         224 :     if (!m_states.back().bFirstChild)
     188             :     {
     189         221 :         if (m_bPretty && m_bNewLineEnabled)
     190             :         {
     191         186 :             Print("\n");
     192         186 :             Print(m_osIndentAcc);
     193             :         }
     194             :     }
     195         224 :     m_states.pop_back();
     196         224 :     Print("]");
     197         224 : }
     198             : 
     199         940 : void CPLJSonStreamingWriter::AddObjKey(const std::string &key)
     200             : {
     201         940 :     CPLAssert(!m_states.empty());
     202         940 :     CPLAssert(m_states.back().bIsObj);
     203         940 :     CPLAssert(!m_bWaitForValue);
     204         940 :     EmitCommaIfNeeded();
     205         940 :     Print(FormatString(key));
     206         940 :     Print(m_bPretty ? ": " : ":");
     207         940 :     m_bWaitForValue = true;
     208         940 : }
     209             : 
     210           5 : void CPLJSonStreamingWriter::Add(bool bVal)
     211             : {
     212           5 :     EmitCommaIfNeeded();
     213           5 :     Print(bVal ? "true" : "false");
     214           5 : }
     215             : 
     216         279 : void CPLJSonStreamingWriter::Add(const std::string &str)
     217             : {
     218         279 :     EmitCommaIfNeeded();
     219         279 :     Print(FormatString(str));
     220         279 : }
     221             : 
     222         189 : void CPLJSonStreamingWriter::Add(const char *pszStr)
     223             : {
     224         189 :     EmitCommaIfNeeded();
     225         189 :     Print(FormatString(pszStr));
     226         189 : }
     227             : 
     228         113 : void CPLJSonStreamingWriter::Add(std::int64_t nVal)
     229             : {
     230         113 :     EmitCommaIfNeeded();
     231         113 :     Print(CPLSPrintf(CPL_FRMT_GIB, static_cast<GIntBig>(nVal)));
     232         113 : }
     233             : 
     234         160 : void CPLJSonStreamingWriter::Add(std::uint64_t nVal)
     235             : {
     236         160 :     EmitCommaIfNeeded();
     237         160 :     Print(CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nVal)));
     238         160 : }
     239             : 
     240          18 : void CPLJSonStreamingWriter::Add(float fVal, int nPrecision)
     241             : {
     242          18 :     EmitCommaIfNeeded();
     243          18 :     if (CPLIsNan(fVal))
     244             :     {
     245           3 :         Print("\"NaN\"");
     246             :     }
     247          15 :     else if (CPLIsInf(fVal))
     248             :     {
     249           2 :         Print(fVal > 0 ? "\"Infinity\"" : "\"-Infinity\"");
     250             :     }
     251             :     else
     252             :     {
     253             :         char szFormatting[10];
     254          13 :         snprintf(szFormatting, sizeof(szFormatting), "%%.%dg", nPrecision);
     255          13 :         Print(CPLSPrintf(szFormatting, fVal));
     256             :     }
     257          18 : }
     258             : 
     259          71 : void CPLJSonStreamingWriter::Add(double dfVal, int nPrecision)
     260             : {
     261          71 :     EmitCommaIfNeeded();
     262          71 :     if (CPLIsNan(dfVal))
     263             :     {
     264          35 :         Print("\"NaN\"");
     265             :     }
     266          36 :     else if (CPLIsInf(dfVal))
     267             :     {
     268           2 :         Print(dfVal > 0 ? "\"Infinity\"" : "\"-Infinity\"");
     269             :     }
     270             :     else
     271             :     {
     272             :         char szFormatting[10];
     273          34 :         snprintf(szFormatting, sizeof(szFormatting), "%%.%dg", nPrecision);
     274          34 :         Print(CPLSPrintf(szFormatting, dfVal));
     275             :     }
     276          71 : }
     277             : 
     278           1 : void CPLJSonStreamingWriter::AddNull()
     279             : {
     280           1 :     EmitCommaIfNeeded();
     281           1 :     Print("null");
     282           1 : }
     283             : 
     284             : /*! @endcond */

Generated by: LCOV version 1.14