LCOV - code coverage report
Current view: top level - src/engraving/rw - xmlwriter.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 80.7 % 243 196
Test Date: 2026-11-05 04:07:02

            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              : }
        

Generated by: LCOV version 2.0-1