Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "xmlwriter.h"
24 :
25 : #include "types/typesconv.h"
26 :
27 : #include "dom/engravingitem.h"
28 : #include "dom/property.h"
29 :
30 : #include "log.h"
31 :
32 : using namespace mu;
33 : using namespace mu::engraving;
34 :
35 : namespace mu::engraving {
36 1943 : XmlWriter::XmlWriter(muse::io::IODevice* device)
37 1943 : : XmlStreamWriter(device)
38 : {
39 1943 : }
40 :
41 2236 : XmlWriter::~XmlWriter()
42 : {
43 2236 : }
44 :
45 12536 : void XmlWriter::startElementRaw(const String& s)
46 : {
47 12536 : XmlStreamWriter::startElementRaw(s);
48 12536 : }
49 :
50 49517 : void XmlWriter::startElement(const AsciiStringView& name, const Attributes& attrs)
51 : {
52 49517 : XmlStreamWriter::startElement(name, attrs);
53 49517 : }
54 :
55 100593 : void XmlWriter::startElement(const EngravingObject* se, const Attributes& attrs)
56 : {
57 100593 : startElement(se->typeName(), se, attrs);
58 100593 : }
59 :
60 101199 : void XmlWriter::startElement(const AsciiStringView& name, const EngravingObject* se, const Attributes& attrs)
61 : {
62 101199 : XmlStreamWriter::startElement(name, attrs);
63 :
64 101199 : if (_recordElements) {
65 0 : _elements.emplace_back(se, name);
66 : }
67 101199 : }
68 :
69 6631 : void XmlWriter::tag(const AsciiStringView& name, const Attributes& attrs)
70 : {
71 6631 : XmlStreamWriter::element(name, attrs);
72 6631 : }
73 :
74 244432 : void XmlWriter::tag(const AsciiStringView& name, const Value& body)
75 : {
76 244432 : XmlStreamWriter::element(name, body);
77 244432 : }
78 :
79 7113 : void XmlWriter::tag(const AsciiStringView& name, const Value& val, const Value& def)
80 : {
81 7113 : if (val == def) {
82 7069 : return;
83 : }
84 44 : tag(name, val);
85 : }
86 :
87 17653 : void XmlWriter::tag(const AsciiStringView& name, const Attributes& attrs, const Value& body)
88 : {
89 17653 : XmlStreamWriter::element(name, attrs, body);
90 17653 : }
91 :
92 8295 : void XmlWriter::tagRaw(const String& elementWithAttrs, const Value& body)
93 : {
94 8295 : XmlStreamWriter::elementRaw(elementWithAttrs, body);
95 8295 : }
96 :
97 : //---------------------------------------------------------
98 : // tag
99 : //---------------------------------------------------------
100 :
101 1449455 : void XmlWriter::tagProperty(Pid id, const PropertyValue& val, const PropertyValue& def)
102 : {
103 1449455 : if (val == def) {
104 1369939 : return;
105 : }
106 :
107 79516 : const char* name = propertyName(id);
108 79516 : if (name == 0) {
109 0 : return;
110 : }
111 :
112 79516 : P_TYPE valType = val.type();
113 79516 : P_TYPE propType = propertyType(id);
114 79516 : if (valType != propType) {
115 7 : LOGD() << "property value type mismatch, prop: " << name;
116 : }
117 :
118 79516 : const String writableVal(propertyToString(id, val, /* mscx */ true));
119 79516 : if (writableVal.isEmpty()) {
120 : //! NOTE The data type is ABSOLUTE, but we write SPATIUM
121 : //! (the conversion from Absolute to Spatium occurred higher up the stack)
122 76629 : if (propType == P_TYPE::ABSOLUTE) {
123 0 : propType = P_TYPE::SPATIUM;
124 : }
125 :
126 : //! HACK Temporary hack. We used to have some kind of property with property type BOOL,
127 : //! but the used value type is INT (not just 1 and 0)
128 : //! TODO: remove if deemed safe
129 76629 : IF_ASSERT_FAILED(!(propType == P_TYPE::BOOL && valType == P_TYPE::INT)) {
130 0 : propType = P_TYPE::INT;
131 : }
132 :
133 76629 : tagProperty(name, propType, val);
134 : } else {
135 2887 : tagProperty(name, P_TYPE::STRING, PropertyValue(writableVal));
136 : }
137 79516 : }
138 :
139 11644 : void XmlWriter::tagProperty(const AsciiStringView& name, const PropertyValue& val, const PropertyValue& def)
140 : {
141 11644 : if (val == def) {
142 45 : return;
143 : }
144 :
145 11599 : tagProperty(name, val.type(), val);
146 : }
147 :
148 91115 : void XmlWriter::tagProperty(const AsciiStringView& name, P_TYPE type, const PropertyValue& data)
149 : {
150 91115 : switch (type) {
151 0 : case P_TYPE::UNDEFINED:
152 0 : UNREACHABLE;
153 : break;
154 : // base
155 5255 : case P_TYPE::BOOL:
156 5255 : element(name, int(data.value<bool>()));
157 5255 : break;
158 62280 : case P_TYPE::INT:
159 : case P_TYPE::SIZE_T:
160 62280 : element(name, data.value<int>());
161 62280 : break;
162 4570 : case P_TYPE::REAL:
163 4570 : element(name, data.value<double>());
164 4570 : break;
165 5676 : case P_TYPE::STRING:
166 5676 : element(name, data.value<String>());
167 5676 : break;
168 : // geometry
169 843 : case P_TYPE::POINT: {
170 843 : PointF p = data.value<PointF>();
171 3372 : element(name, { { "x", p.x() }, { "y", p.y() } });
172 : }
173 843 : break;
174 19 : case P_TYPE::SIZE: {
175 19 : SizeF s = data.value<SizeF>();
176 76 : element(name, { { "w", s.width() }, { "h", s.height() } });
177 : }
178 19 : break;
179 0 : case P_TYPE::DRAW_PATH:
180 0 : UNREACHABLE; //! TODO
181 : break;
182 9 : case P_TYPE::SCALE: {
183 9 : ScaleF s = data.value<ScaleF>();
184 36 : element(name, { { "w", s.width() }, { "h", s.height() } });
185 9 : } break;
186 1014 : case P_TYPE::SPATIUM:
187 1014 : element(name, data.value<Spatium>().val());
188 1014 : break;
189 0 : case P_TYPE::ABSOLUTE:
190 0 : element(name, data.value<double>());
191 0 : break;
192 :
193 : // draw
194 64 : case P_TYPE::SYMID: {
195 64 : element(name, TConv::toXml(data.value<SymId>()));
196 64 : } break;
197 746 : case P_TYPE::COLOR: {
198 746 : Color color(data.value<Color>());
199 4476 : element(name, { { "r", color.red() }, { "g", color.green() }, { "b", color.blue() }, { "a", color.alpha() } });
200 : }
201 746 : break;
202 3 : case P_TYPE::ORNAMENT_STYLE: {
203 3 : element(name, TConv::toXml(data.value<OrnamentStyle>()));
204 3 : } break;
205 0 : case P_TYPE::ORNAMENT_SHOW_ACCIDENTAL:
206 0 : element(name, static_cast<int>(data.value<OrnamentShowAccidental>()));
207 0 : break;
208 1 : case P_TYPE::GLISS_STYLE: {
209 1 : element(name, TConv::toXml(data.value<GlissandoStyle>()));
210 1 : } break;
211 0 : case P_TYPE::GLISS_TYPE: {
212 0 : element(name, TConv::toXml(data.value<GlissandoType>()));
213 0 : } break;
214 64 : case P_TYPE::ALIGN: {
215 64 : element(name, TConv::toXml(data.value<Align>()));
216 : }
217 64 : break;
218 60 : case P_TYPE::ALIGN_H: {
219 60 : element(name, TConv::toXml(data.value<AlignH>()));
220 : }
221 60 : break;
222 100 : case P_TYPE::PLACEMENT_V: {
223 100 : element(name, TConv::toXml(data.value<PlacementV>()));
224 : }
225 100 : break;
226 0 : case P_TYPE::PLACEMENT_H: {
227 0 : element(name, TConv::toXml(data.value<PlacementH>()));
228 : }
229 0 : break;
230 125 : case P_TYPE::TEXT_PLACE: {
231 125 : element(name, TConv::toXml(data.value<TextPlace>()));
232 : }
233 125 : break;
234 2277 : case P_TYPE::DIRECTION_V: {
235 2277 : element(name, TConv::toXml(data.value<DirectionV>()));
236 : }
237 2277 : break;
238 155 : case P_TYPE::DIRECTION_H: {
239 155 : element(name, TConv::toXml(data.value<DirectionH>()));
240 : }
241 155 : break;
242 0 : case P_TYPE::ORIENTATION: {
243 0 : element(name, TConv::toXml(data.value<Orientation>()));
244 : }
245 0 : break;
246 : // time
247 29 : case P_TYPE::FRACTION: {
248 29 : tagFraction(name, data.value<Fraction>());
249 : }
250 29 : break;
251 531 : case P_TYPE::LAYOUTBREAK_TYPE: {
252 531 : element(name, TConv::toXml(data.value<LayoutBreakType>()));
253 531 : } break;
254 606 : case P_TYPE::BARLINE_TYPE: {
255 606 : element(name, TConv::toXml(data.value<BarLineType>()));
256 606 : } break;
257 195 : case P_TYPE::NOTEHEAD_TYPE: {
258 195 : element(name, TConv::toXml(data.value<NoteHeadType>()));
259 195 : } break;
260 25 : case P_TYPE::NOTEHEAD_SCHEME: {
261 25 : element(name, TConv::toXml(data.value<NoteHeadScheme>()));
262 25 : } break;
263 812 : case P_TYPE::NOTEHEAD_GROUP: {
264 812 : element(name, TConv::toXml(data.value<NoteHeadGroup>()));
265 812 : } break;
266 2186 : case P_TYPE::CLEF_TYPE: {
267 2186 : element(name, TConv::toXml(data.value<ClefType>()));
268 2186 : } break;
269 1 : case P_TYPE::CLEF_TO_BARLINE_POS:
270 1 : element(name, static_cast<int>(data.value<ClefToBarlinePosition>()));
271 1 : break;
272 588 : case P_TYPE::DYNAMIC_TYPE: {
273 588 : element(name, TConv::toXml(data.value<DynamicType>()));
274 588 : } break;
275 0 : case P_TYPE::DYNAMIC_SPEED: {
276 0 : element(name, TConv::toXml(data.value<DynamicSpeed>()));
277 0 : } break;
278 69 : case P_TYPE::LINE_TYPE: {
279 69 : element(name, TConv::toXml(data.value<LineType>()));
280 69 : } break;
281 107 : case P_TYPE::HOOK_TYPE: {
282 107 : element(name, TConv::toXml(data.value<HookType>()));
283 107 : } break;
284 0 : case P_TYPE::KEY_MODE: {
285 0 : element(name, TConv::toXml(data.value<KeyMode>()));
286 0 : } break;
287 1912 : case P_TYPE::TEXT_STYLE: {
288 1912 : element(name, TConv::toXml(data.value<TextStyleType>()));
289 1912 : } break;
290 27 : case P_TYPE::SLUR_STYLE_TYPE:
291 27 : element(name, static_cast<int>(data.value<SlurStyleType>()));
292 27 : break;
293 0 : case P_TYPE::CHANGE_METHOD: {
294 0 : element(name, TConv::toXml(data.value<ChangeMethod>()));
295 0 : } break;
296 367 : case P_TYPE::ACCIDENTAL_ROLE: {
297 367 : element(name, TConv::toXml(data.value<AccidentalRole>()));
298 367 : } break;
299 4 : case P_TYPE::PLAYTECH_TYPE: {
300 4 : element(name, TConv::toXml(data.value<PlayingTechniqueType>()));
301 4 : } break;
302 10 : case P_TYPE::TEMPOCHANGE_TYPE: {
303 10 : element(name, TConv::toXml(data.value<GradualTempoChangeType>()));
304 10 : } break;
305 15 : case P_TYPE::ORNAMENT_INTERVAL: {
306 15 : element(name, TConv::toXml(data.value<OrnamentInterval>()));
307 15 : } break;
308 0 : case P_TYPE::TIE_PLACEMENT: {
309 0 : element(name, TConv::toXml(data.value<TiePlacement>()));
310 0 : } break;
311 41 : case P_TYPE::VOICE_ASSIGNMENT: {
312 41 : element(name, TConv::toXml(data.value<VoiceAssignment>()));
313 41 : } break;
314 54 : case P_TYPE::AUTO_ON_OFF: {
315 54 : element(name, TConv::toXml(data.value<AutoOnOff>()));
316 54 : } break;
317 0 : case P_TYPE::AUTO_CUSTOM_HIDE: {
318 0 : element(name, TConv::toXml(data.value<AutoCustomHide>()));
319 0 : } break;
320 0 : case P_TYPE::INT_VEC: {
321 0 : element(name, TConv::toXml(data.value<std::vector<int> >()));
322 0 : } break;
323 51 : case P_TYPE::PARTIAL_SPANNER_DIRECTION: {
324 51 : element(name, TConv::toXml(data.value<PartialSpannerDirection>()));
325 51 : } break;
326 157 : case P_TYPE::PARENTHESES_MODE: {
327 157 : element(name, TConv::toXml(data.value<ParenthesesMode>()));
328 157 : } break;
329 67 : case P_TYPE::MARKER_TYPE: {
330 67 : element(name, TConv::toXml(data.value<MarkerType>()));
331 67 : } break;
332 0 : default: {
333 0 : UNREACHABLE; //! TODO
334 : }
335 : break;
336 : }
337 92732 : }
338 :
339 6 : void XmlWriter::tagPoint(const AsciiStringView& name, const PointF& p)
340 : {
341 24 : tag(name, { { "x", p.x() }, { "y", p.y() } });
342 12 : }
343 :
344 12505 : void XmlWriter::tagFraction(const AsciiStringView& name, const Fraction& v, const Fraction& def)
345 : {
346 12505 : if (v == def) {
347 423 : return;
348 : }
349 :
350 12082 : element(name, v.toString());
351 : }
352 :
353 5643 : void XmlWriter::writeXml(const String& name, String s)
354 : {
355 63049 : for (size_t i = 0; i < s.size(); ++i) {
356 57406 : char16_t c = s.at(i).unicode();
357 57406 : if (c < 0x20 && c != 0x09 && c != 0x0A && c != 0x0D) {
358 0 : s[i] = u'?';
359 : }
360 : }
361 :
362 5643 : elementStringRaw(name, s);
363 5643 : }
364 :
365 0 : void XmlWriter::comment(const String& text)
366 : {
367 0 : XmlStreamWriter::comment(text);
368 0 : }
369 :
370 38396 : String XmlWriter::xmlString(const String& s)
371 : {
372 38396 : return s.toXmlEscaped();
373 : }
374 : }
|