Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
WriterUtils.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Foundation/StroikaPreComp.h"
5
6#include <ostream>
7
10#include "Stroika/Foundation/Containers/Support/ReserveTweaks.h"
11
12#include "WriterUtils.h"
13
14using namespace Stroika::Foundation;
17using namespace Stroika::Foundation::DataExchange::XML;
18
19/*
20 ********************************************************************************
21 ****************************** QuoteForXMLAttribute ****************************
22 ********************************************************************************
23 */
24string XML::QuoteForXMLAttribute (const string& s)
25{
26 string r;
27 r.reserve (Containers::Support::ReserveTweaks::GetScaledUpCapacity (6 * s.size () / 5)); // most chars just written as character, but some take 5 characters, so WAG about percentage
28 for (auto i = s.begin (); i != s.end (); ++i) {
29 switch (*i) {
30 case '&':
31 r += "&amp;";
32 break;
33 case '<':
34 r += "&lt;";
35 break;
36 case '>':
37 r += "&gt;";
38 break;
39 case '\"':
40 r += "&quot;";
41 break;
42 case '\'':
43 r += "&apos;";
44 break;
45 default:
46 r.push_back (*i);
47 break;
48 }
49 }
50 return r;
51}
52
53string XML::QuoteForXMLAttribute (const wstring& s)
54{
55 string r;
56 r.reserve (Containers::Support::ReserveTweaks::GetScaledUpCapacity (6 * s.size () / 5)); // most chars just written as character, but some take 5 characters, so WAG about percentage
57 for (auto i = s.begin (); i != s.end (); ++i) {
58 switch (*i) {
59 case '&':
60 r += "&amp;";
61 break;
62 case '<':
63 r += "&lt;";
64 break;
65 case '>':
66 r += "&gt;";
67 break;
68 case '\"':
69 r += "&quot;";
70 break;
71 case '\'':
72 r += "&apos;";
73 break;
74 default: {
75 wchar_t ccode = *i;
76 if (ccode != '\t' and ccode != '\n' and ccode != '\r' and (ccode < 32 or ccode > 127)) {
77 r += CString::Format ("&#%d;", ccode);
78 }
79 else {
80 r.push_back (static_cast<char> (ccode));
81 }
82 } break;
83 }
84 }
85 return r;
86}
87
88string XML::QuoteForXMLAttribute (const String& s)
89{
90 return QuoteForXMLAttribute (s.As<wstring> ());
91}
92
93string XML::QuoteForXMLAttribute (const optional<String>& s)
94{
95 if (not s.has_value ()) {
96 return string{};
97 }
98 return QuoteForXMLAttribute (*s);
99}
100
101String XML::QuoteForXMLAttributeW (const String& s)
102{
103 string tmp = QuoteForXMLAttribute (s);
104 return String::FromNarrowSDKString (tmp);
105}
106
107/*
108 ********************************************************************************
109 ******************************** QuoteForXML ***********************************
110 ********************************************************************************
111 */
112string XML::QuoteForXML (const string& s)
113{
114 string r;
115 r.reserve (s.size () * 6 / 5); // wild guess about good estimate
116 for (auto i = s.begin (); i != s.end (); ++i) {
117 switch (*i) {
118 case '&':
119 r += "&amp;";
120 break;
121 case '<':
122 r += "&lt;";
123 break;
124 case '>':
125 r += "&gt;";
126 break;
127 case '-': {
128 // A 'dash' or 'minus-sign' can be dangerous in XML - if you get two in a row (start/end comment designator).
129 // So avoid any leading/trailing dash, and any double-dashes.
130 //
131 // NB: This code WOULD be simpler if we just always mapped, but then much ordinary and safe text with dashes becomes
132 // less readable (and produces huge diffs in my regression tests - but thats a one-time annoyance).
133 //
134 if ((i == s.begin ()) or (i + 1 == s.end ()) or (*(i - 1) == '-')) {
135 r += "&#45;";
136 }
137 else {
138 r.push_back ('-');
139 }
140 } break;
141 default:
142 r.push_back (*i);
143 break;
144 }
145 }
146 return r;
147}
148
149string XML::QuoteForXML (const wstring& s)
150{
151 string r;
152 r.reserve (Containers::Support::ReserveTweaks::GetScaledUpCapacity (6 * s.size () / 5)); // most chars just written as character, but some take 5 characters, so WAG about percentage
153 for (auto i = s.begin (); i != s.end (); ++i) {
154 switch (*i) {
155 case '&':
156 r += "&amp;";
157 break;
158 case '<':
159 r += "&lt;";
160 break;
161 case '>':
162 r += "&gt;";
163 break;
164 case '-': {
165 // A 'dash' or 'minus-sign' can be dangerous in XML - if you get two in a row (start/end comment designator).
166 // So avoid any leading/trailing dash, and any double-dashes.
167 //
168 // NB: This code WOULD be simpler if we just always mapped, but then much ordinary and safe text with dashes becomes
169 // less readable (and produces huge diffs in my regression tests - but thats a one-time annoyance).
170 //
171 if ((i == s.begin ()) or (i + 1 == s.end ()) or (*(i - 1) == '-')) {
172 r += "&#45;";
173 }
174 else {
175 r.push_back ('-');
176 }
177 } break;
178 default: {
179 wchar_t ccode = *i;
180 if (ccode != '\t' and ccode != '\n' and ccode != '\r' and (ccode < 32 or ccode > 127)) {
181 r += CString::Format ("&#%d;", ccode);
182 }
183 else {
184 r.push_back (static_cast<char> (ccode));
185 }
186 } break;
187 }
188 }
189 return r;
190}
191
192String XML::QuoteForXMLW (const String& s)
193{
194 string tmp = QuoteForXML (s);
195 return String::FromNarrowSDKString (tmp);
196}
197
198string XML::QuoteForXML (const String& s)
199{
200 return QuoteForXML (s.As<wstring> ());
201}
202
203string XML::QuoteForXML (const optional<String>& s)
204{
205 if (not s.has_value ()) {
206 return string{};
207 }
208 return QuoteForXML (*s);
209}
210
211/*
212 ********************************************************************************
213 ****************************** XML::Indenter ***********************************
214 ********************************************************************************
215 */
216Indenter::Indenter (const String& indentText)
217 : fTabS_{indentText.AsUTF8<string> ()}
218 , fTabW_{indentText.As<wstring> ()}
219{
220}
221
222void Indenter::Indent (unsigned indentLevel, ostream& out) const
223{
224 for (unsigned int i = 0; i < indentLevel; ++i) {
225 out << fTabS_;
226 }
227}
228
229void Indenter::Indent (unsigned int indentLevel, wostream& out) const
230{
231 for (unsigned int i = 0; i < indentLevel; ++i) {
232 out << fTabW_;
233 }
234}
235
236string XML::Format4XML (bool v)
237{
238 return v ? "true" : "false";
239}
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201