Stroika Library 3.0d23x
 
Loading...
Searching...
No Matches
Variant/XML/Writer.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#include "Stroika/Foundation/StroikaPreComp.h"
5
6#include "Stroika/Foundation/DataExchange/XML/WriterUtils.h"
8#include "Stroika/Foundation/Streams/TextToBinary.h"
9
10#include "Writer.h"
11
12using std::byte;
13
14using namespace Stroika::Foundation;
17using namespace Stroika::Foundation::DataExchange::XML;
18using namespace Stroika::Foundation::Streams;
19
20using Memory::MakeSharedPtr;
21
22namespace {
23 void Indent_ (const OutputStream::Ptr<Character>& out, int indentLevel)
24 {
25 for (int i = 0; i < indentLevel; ++i) {
26 out.Write (" "sv);
27 }
28 }
29}
30namespace {
31 static const String kTrueLbl_ = "true"sv;
32 static const String kFalseLbl_ = "false"sv;
33 void PrettyPrint_ (const VariantValue& v, const OutputStream::Ptr<Character>& out, int indentLevel);
34 void PrettyPrint_ (bool v, const OutputStream::Ptr<Character>& out)
35 {
36 if (v) {
37 out.Write (kTrueLbl_);
38 }
39 else {
40 out.Write (kFalseLbl_);
41 }
42 }
43 void PrettyPrint_ (long long int v, const OutputStream::Ptr<Character>& out)
44 {
45 wchar_t buf[1024];
46 ::swprintf (buf, std::size (buf), L"%lld", v);
47 out.Write (buf);
48 }
49 void PrettyPrint_ (unsigned long long int v, const OutputStream::Ptr<Character>& out)
50 {
51 wchar_t buf[1024];
52 ::swprintf (buf, std::size (buf), L"%llu", v);
53 out.Write (buf);
54 }
55 void PrettyPrint_ (long double v, const OutputStream::Ptr<Character>& out)
56 {
57 wchar_t buf[1024];
58 ::swprintf (buf, std::size (buf), L"%Lf", v);
59 Assert (::wcslen (buf) >= 1);
60 // trim trailing 0
61 for (size_t i = ::wcslen (buf) - 1; buf[i] == '0'; --i) {
62 if (i != 0 and buf[i - 1] != '.') {
63 buf[i] = '\0';
64 }
65 }
66 out.Write (buf);
67 }
68 void PrettyPrint_ (const String& v, const OutputStream::Ptr<Character>& out)
69 {
70 // @todo need variant of QuoteForXML that ONLY quotes special cahracters, and not fancy (eg japaense, etc)
71 // characters
72 //
73 // then can clean this up
74 out.Write (String{QuoteForXML (v)});
75 }
76 void PrettyPrint_ (const vector<VariantValue>& v, const OutputStream::Ptr<Character>& out, int indentLevel)
77 {
78 for (auto i = v.begin (); i != v.end (); ++i) {
79 PrettyPrint_ (*i, out, indentLevel + 1);
80 out.Write ("\n"sv);
81 }
82 Indent_ (out, indentLevel);
83 }
84 void PrettyPrint_ (const map<wstring, VariantValue>& v, const OutputStream::Ptr<Character>& out, int indentLevel)
85 {
86 //@@@@TODO - must validate first legit xml elt args
87 out.Write ("\n"sv);
88 for (auto i = v.begin (); i != v.end ();) {
89 Indent_ (out, indentLevel);
90 out.Write ("<"sv);
91 out.Write (i->first.c_str ());
92 out.Write (">"sv);
93 PrettyPrint_ (i->second, out, indentLevel + 1);
94 out.Write ("</"sv);
95 out.Write (i->first.c_str ());
96 out.Write (">"sv);
97 ++i;
98 out.Write ("\n"sv);
99 }
100 }
101 void PrettyPrint_ (const VariantValue& v, const OutputStream::Ptr<Character>& out, int indentLevel)
102 {
103 switch (v.GetType ()) {
104 case VariantValue::eNull:
105 break;
106 case VariantValue::eBoolean:
107 PrettyPrint_ (v.As<bool> (), out);
108 break;
109 case VariantValue::eDate:
110 PrettyPrint_ (v.As<String> (), out);
111 break;
112 case VariantValue::eDateTime:
113 PrettyPrint_ (v.As<String> (), out);
114 break;
115 case VariantValue::eInteger:
116 PrettyPrint_ (v.As<long long int> (), out);
117 break;
118 case VariantValue::eUnsignedInteger:
119 PrettyPrint_ (v.As<unsigned long long int> (), out);
120 break;
121 case VariantValue::eFloat:
122 PrettyPrint_ (v.As<long double> (), out);
123 break;
124 case VariantValue::eString:
125 PrettyPrint_ (v.As<String> (), out);
126 break;
127 case VariantValue::eMap:
128 PrettyPrint_ (v.As<map<wstring, VariantValue>> (), out, indentLevel);
129 break;
130 case VariantValue::eArray:
131 PrettyPrint_ (v.As<vector<VariantValue>> (), out, indentLevel);
132 break;
133 default:
134 RequireNotReached (); // only certain types allowed
135 }
136 }
137}
138
139/*
140 ********************************************************************************
141 ************************** Variant::XML::Writer ********************************
142 ********************************************************************************
143 */
144class Variant::XML::Writer::Rep_ final : public Variant::Writer::_IRep, public Memory::UseBlockAllocationIfAppropriate<Rep_> {
145public:
146 Rep_ (const SerializationConfiguration& config)
147 : fSerializationConfiguration_{config}
148 , fDocumentElementName_{config.GetDocumentElementName ().value_or (String{})}
149 {
150 }
151 virtual _SharedPtrIRep Clone () const override
152 {
153 return MakeSharedPtr<Rep_> (fSerializationConfiguration_);
154 }
155 virtual optional<filesystem::path> GetDefaultFileSuffix () const override
156 {
157 return ".xml"sv;
158 }
159 virtual void Write (const VariantValue& v, const Streams::OutputStream::Ptr<byte>& out) const override
160 {
161 if (fDocumentElementName_.empty ()) {
162 Require (v.GetType () == VariantValue::eMap);
163 PrettyPrint_ (v, TextToBinary::Writer::New (out, UnicodeExternalEncodings::eUTF8, ByteOrderMark::eDontInclude), 0);
164 }
165 else {
167 v2.Add (fDocumentElementName_, v);
168 PrettyPrint_ (VariantValue{v2}, TextToBinary::Writer::New (out, UnicodeExternalEncodings::eUTF8, ByteOrderMark::eDontInclude), 0);
169 }
170 }
171 virtual void Write (const VariantValue& v, const Streams::OutputStream::Ptr<Character>& out) const override
172 {
173 if (fDocumentElementName_.empty ()) {
174 Require (v.GetType () == VariantValue::eMap);
175 PrettyPrint_ (v, out, 0);
176 }
177 else {
179 v2.Add (fDocumentElementName_, v);
180 PrettyPrint_ (VariantValue{v2}, out, 0);
181 }
182 }
183 nonvirtual SerializationConfiguration GetConfiguration () const
184 {
185 return fSerializationConfiguration_;
186 }
187 nonvirtual void SetConfiguration (const SerializationConfiguration& config)
188 {
189 fSerializationConfiguration_ = config;
190 fDocumentElementName_ = config.GetDocumentElementName ().value_or (String{});
191 }
192
193private:
194 SerializationConfiguration fSerializationConfiguration_;
195 String fDocumentElementName_;
196};
197
198Variant::XML::Writer::Writer (const SerializationConfiguration& config)
199 : inherited{MakeSharedPtr<Rep_> (config)}
200{
201}
202
203Variant::XML::Writer::Rep_& Variant::XML::Writer::GetRep_ ()
204{
205 EnsureMember (&inherited::_GetRep (), Rep_);
206 return reinterpret_cast<Rep_&> (inherited::_GetRep ());
207}
208
209const Variant::XML::Writer::Rep_& Variant::XML::Writer::GetRep_ () const
210{
211 EnsureMember (&inherited::_GetRep (), Rep_);
212 return reinterpret_cast<const Rep_&> (inherited::_GetRep ());
213}
214
215SerializationConfiguration Variant::XML::Writer::GetConfiguration () const
216{
217 return GetRep_ ().GetConfiguration ();
218}
219
220void Variant::XML::Writer::SetConfiguration (const SerializationConfiguration& config)
221{
222 GetRep_ ().SetConfiguration (config);
223}
#define RequireNotReached()
Definition Assertions.h:385
#define EnsureMember(p, c)
Definition Assertions.h:319
auto MakeSharedPtr(ARGS_TYPE &&... args) -> shared_ptr< T >
same as make_shared, but if type T has block allocation, then use block allocation for the 'shared pa...
conditional_t< qStroika_Foundation_Memory_PreferBlockAllocation and andTrueCheck, BlockAllocationUseHelper< T >, Common::Empty > UseBlockAllocationIfAppropriate
Use this to enable block allocation for a particular class. Beware of subclassing.
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
Definition Mapping.inl:188
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
OutputStream<>::Ptr is Smart pointer to a stream-based sink of data.
nonvirtual void Write(span< ELEMENT_TYPE2, EXTENT_2 > elts) const
Ptr New(const Streams::OutputStream::Ptr< byte > &src, const Characters::CodeCvt<> &char2OutputConverter)