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