LCOV - code coverage report
Current view: top level - core/data - SPDataEncodeJson.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 129 167 77.2 %
Date: 2024-05-12 00:16:13 Functions: 66 76 86.8 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2017-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #ifndef STAPPLER_DATA_SPDATAENCODEJSON_H_
      25             : #define STAPPLER_DATA_SPDATAENCODEJSON_H_
      26             : 
      27             : #include "SPDataValue.h"
      28             : #include "SPFilesystem.h"
      29             : 
      30             : namespace STAPPLER_VERSIONIZED stappler::data::json {
      31             : 
      32             : template <typename StringType>
      33    14618450 : inline void encodeString(const Callback<void(StringView)> &stream, const StringType &str) {
      34    14618450 :         stream << '"';
      35   842064500 :         for (auto &i : str) {
      36   827446050 :                 switch (i) {
      37       85800 :                 case '\n' : stream << "\\n"; break;
      38           0 :                 case '\r' : stream << "\\r"; break;
      39           0 :                 case '\t' : stream << "\\t"; break;
      40           0 :                 case '\f' : stream << "\\f"; break;
      41           0 :                 case '\b' : stream << "\\b"; break;
      42          25 :                 case '\\' : stream << "\\\\"; break;
      43     1053025 :                 case '\"' : stream << "\\\""; break;
      44    51577900 :                 case ' ' : stream << ' '; break;
      45   774729300 :                 default:
      46   774729300 :                         if (i >= 0 && i <= 0x20) {
      47           0 :                                 stream << "\\u00" << base16::charToHex(i, true);
      48             :                         } else {
      49   774729300 :                                 stream << i;
      50             :                         }
      51   774729300 :                         break;
      52             :                 }
      53             :         }
      54    14618450 :         stream << '"';
      55    14618450 : }
      56             : 
      57             : template <typename Interface>
      58             : struct RawEncoder : public Interface::AllocBaseType {
      59             :         using InterfaceType = Interface;
      60             :         using ValueType = ValueTemplate<Interface>;
      61             : 
      62       13350 :         inline RawEncoder(const Callback<void(StringView)> *s) : stream(s) { }
      63             : 
      64      932100 :         inline void writeData(const char *data, size_t size) {
      65      932100 :                 (*stream) << StringView(data, size);
      66      932100 :         }
      67             : 
      68      927825 :         inline void writeData(const char *data) {
      69      927825 :                 writeData(data, strlen(data));
      70      927825 :         }
      71             : 
      72             :         inline void writeChar(char c) {
      73             :                 (*stream) << c;
      74             :         }
      75             : 
      76        4275 :         inline void write(nullptr_t) { writeData("null", "null"_len); }
      77      927825 :         inline void write(bool value) { writeData((value)?"true":"false"); }
      78      556125 :         inline void write(int64_t value) { (*stream) << value; }
      79        6425 :         inline void write(double value) {
      80        6425 :                 (*stream) << value;
      81        6425 :         }
      82             : 
      83    12617575 :         inline void write(const typename ValueType::StringType &str) {
      84    12617575 :                 encodeString(*stream, str);
      85    12617575 :         }
      86             : 
      87        4900 :         inline void write(const typename ValueType::BytesType &data) {
      88        4900 :                 (*stream) << '"' << "BASE64:";
      89      158250 :                 base64url::encode([&] (char c) {
      90       77975 :                         *stream << c;
      91             :                 }, data);
      92        4900 :                 (*stream) << '"';
      93        4900 :         }
      94      481775 :         inline void onBeginArray(const typename ValueType::ArrayType &arr) { (*stream) << '['; }
      95      481775 :         inline void onEndArray(const typename ValueType::ArrayType &arr) { (*stream) << ']'; }
      96     1176025 :         inline void onBeginDict(const typename ValueType::DictionaryType &dict) { (*stream) << '{'; }
      97     1176025 :         inline void onEndDict(const typename ValueType::DictionaryType &dict) { (*stream) << '}'; }
      98     7084700 :         inline void onKey(const typename ValueType::StringType &str) { write(str); (*stream) << ':'; }
      99     7025425 :         inline void onNextValue() { (*stream) << ','; }
     100             : 
     101             :         const Callback<void(StringView)> *stream = nullptr;
     102             : };
     103             : 
     104             : template <typename Interface>
     105             : struct PrettyEncoder : public Interface::AllocBaseType {
     106             :         using InterfaceType = Interface;
     107             :         using ValueType = ValueTemplate<Interface>;
     108             : 
     109         675 :         PrettyEncoder(const Callback<void(StringView)> *s, bool tM = false) : timeMarkers(tM), stream(s) { }
     110             : 
     111         675 :         void write(nullptr_t) { (*stream) << "null"; offsetted = false; }
     112      147425 :         void write(bool value) { (*stream) << ((value)?"true":"false"); offsetted = false; }
     113       83400 :         void write(int64_t value) {
     114       83400 :                 (*stream) << value; offsetted = false;
     115      166800 :                 if (timeMarkers
     116           0 :                         && (lastKey.find("time") != maxOf<size_t>()
     117           0 :                                         || lastKey.find("Time") != maxOf<size_t>()
     118           0 :                                         || lastKey.find("TIME") != maxOf<size_t>()
     119           0 :                                         || lastKey.find("date") != maxOf<size_t>()
     120           0 :                                         || lastKey.find("Date") != maxOf<size_t>())
     121       83400 :                         && (value > 1000000000000000 && value < 10000000000000000)) {
     122           0 :                         (*stream) << " /* " << Time::microseconds(value).toHttp<Interface>() << " */";
     123             :                 }
     124       83400 :         }
     125           0 :         void write(double value) {
     126           0 :                 (*stream) << value;
     127           0 :                 offsetted = false;
     128           0 :         }
     129             : 
     130     2000875 :         void write(const typename ValueType::StringType &str) {
     131     2000875 :                 encodeString(*stream, str);
     132     2000875 :                 offsetted = false;
     133     2000875 :         }
     134             : 
     135           0 :         void write(const typename ValueType::BytesType &data) {
     136           0 :                 (*stream) << '"'  << "BASE64:";
     137           0 :                 base64url::encode([&] (char c) {
     138           0 :                         *stream << c;
     139             :                 }, data);
     140           0 :                 (*stream) << '"';
     141           0 :                 offsetted = false;
     142           0 :         }
     143             : 
     144       76050 :         bool isObjectArray(const typename ValueType::ArrayType &arr) {
     145      158125 :                 for (auto &it : arr) {
     146       95125 :                         if (!it.isDictionary()) {
     147       13050 :                                 return false;
     148             :                         }
     149             :                 }
     150       63000 :                 return true;
     151             :         }
     152             : 
     153       76050 :         void onBeginArray(const typename ValueType::ArrayType &arr) {
     154       76050 :                 (*stream) << '[';
     155       76050 :                 if (!isObjectArray(arr)) {
     156       13050 :                         ++ depth;
     157       13050 :                         bstack.push_back(false);
     158       13050 :                         offsetted = false;
     159             :                 } else {
     160       63000 :                         bstack.push_back(true);
     161             :                 }
     162       76050 :         }
     163             : 
     164       76050 :         void onEndArray(const typename ValueType::ArrayType &arr) {
     165       76050 :                 if (!bstack.empty()) {
     166       76050 :                         if (!bstack.back()) {
     167       13050 :                                 -- depth;
     168       13050 :                                 (*stream) << '\n';
     169       39200 :                                 for (size_t i = 0; i < depth; i++) {
     170       26150 :                                         (*stream) << '\t';
     171             :                                 }
     172             :                         }
     173       76050 :                         bstack.pop_back();
     174             :                 } else {
     175           0 :                         -- depth;
     176           0 :                         (*stream) << '\n';
     177           0 :                         for (size_t i = 0; i < depth; i++) {
     178           0 :                                 (*stream) << '\t';
     179             :                         }
     180             :                 }
     181       76050 :                 (*stream) << ']';
     182       76050 :                 popComplex = true;
     183       76050 :         }
     184             : 
     185      185425 :         void onBeginDict(const typename ValueType::DictionaryType &dict) {
     186      185425 :                 lastKey = StringView();
     187      185425 :                 (*stream) << '{';
     188      185425 :                 ++ depth;
     189      185425 :         }
     190             : 
     191      185425 :         void onEndDict(const typename ValueType::DictionaryType &dict) {
     192      185425 :                 lastKey = StringView();
     193      185425 :                 -- depth;
     194      185425 :                 (*stream) << '\n';
     195     2282225 :                 for (size_t i = 0; i < depth; i++) {
     196     2096800 :                         (*stream) << '\t';
     197             :                 }
     198      185425 :                 (*stream) << '}';
     199      185425 :                 popComplex = true;
     200      185425 :         }
     201             : 
     202     1120950 :         void onKey(const typename ValueType::StringType &str) {
     203     1120950 :                 lastKey = str;
     204     1120950 :                 (*stream) << '\n';
     205    14600200 :                 for (size_t i = 0; i < depth; i++) {
     206    13479250 :                         (*stream) << '\t';
     207             :                 }
     208     1120950 :                 write(str);
     209     1120950 :                 offsetted = true;
     210     1120950 :                 (*stream) << ':' << ' ';
     211     1120950 :         }
     212             : 
     213     1111750 :         void onNextValue() {
     214     1111750 :                 lastKey = StringView();
     215     1111750 :                 (*stream) << ',';
     216     1111750 :         }
     217             : 
     218     1372900 :         void onValue(const ValueType &val) {
     219     1372900 :                 if (depth > 0) {
     220     1371900 :                         if (popComplex && (val.isArray() || val.isDictionary())) {
     221       36500 :                                 (*stream) << ' ';
     222             :                         } else {
     223     1335400 :                                 if (!offsetted) {
     224      169200 :                                         (*stream) << '\n';
     225      676900 :                                         for (size_t i = 0; i < depth; i++) {
     226      507700 :                                                 (*stream) << '\t';
     227             :                                         }
     228      169200 :                                         offsetted = true;
     229             :                                 }
     230             :                         }
     231     1371900 :                         popComplex = false;
     232             :                 }
     233     1372900 :         }
     234             : 
     235             :         size_t depth = 0;
     236             :         bool popComplex = false;
     237             :         bool offsetted = false;
     238             :         bool timeMarkers = false;
     239             :         const Callback<void(StringView)> *stream = nullptr;
     240             :         StringView lastKey;
     241             :         typename Interface::template ArrayType<bool> bstack;
     242             : };
     243             : 
     244             : template <typename Interface>
     245       14025 : inline void write(const Callback<void(StringView)> &stream, const ValueTemplate<Interface> &val, bool pretty, bool timeMarkers = false) {
     246       14025 :         if (pretty) {
     247         675 :                 PrettyEncoder<Interface> encoder(&stream, timeMarkers);
     248         675 :                 val.encode(encoder);
     249         675 :         } else {
     250       13350 :                 RawEncoder<Interface> encoder(&stream);
     251       13350 :                 val.encode(encoder);
     252             :         }
     253       14025 : }
     254             : 
     255             : template <typename Interface>
     256        9950 : inline auto write(const ValueTemplate<Interface> &val, bool pretty = false, bool timeMarkers = false) -> typename Interface::StringType {
     257        9950 :         typename Interface::StringType stream;
     258   986918050 :         write<Interface>([&] (StringView str) {
     259   896099300 :                 stream.append(str.data(), str.size());
     260             :         }, val, pretty, timeMarkers);
     261        9950 :         return stream;
     262           0 : }
     263             : 
     264             : template <typename Interface>
     265           0 : bool save(const ValueTemplate<Interface> &val, StringView ipath, bool pretty, bool timeMarkers = false) {
     266           0 :         auto path = filesystem::native::posixToNative<Interface>(ipath);
     267           0 :         std::ofstream stream(path.data());
     268           0 :         if (stream.is_open()) {
     269           0 :                 write([&] (StringView str) {
     270           0 :                         stream.write(str.data(), str.size());
     271             :                 }, val, pretty, timeMarkers);
     272           0 :                 stream.flush();
     273           0 :                 stream.close();
     274           0 :                 return true;
     275             :         }
     276           0 :         return false;
     277           0 : }
     278             : 
     279             : template <typename Interface>
     280             : auto toString(const ValueTemplate<Interface> &data, bool pretty) -> typename Interface::StringType {
     281             :         return write(data, pretty);
     282             : }
     283             : 
     284             : }
     285             : 
     286             : #endif /* STAPPLER_DATA_SPDATAENCODEJSON_H_ */

Generated by: LCOV version 1.14