diff --git a/Verovio.xcodeproj/project.pbxproj b/Verovio.xcodeproj/project.pbxproj index 5b3cd36aab3..7bbefe22623 100644 --- a/Verovio.xcodeproj/project.pbxproj +++ b/Verovio.xcodeproj/project.pbxproj @@ -184,6 +184,7 @@ 4D422105199805F800963292 /* att.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4D422103199805F700963292 /* att.cpp */; }; 4D4221061998A8CE00963292 /* atts_mensural.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4DEE29031940BCC100C76319 /* atts_mensural.cpp */; }; 4D4221071998A8CE00963292 /* atts_mensural.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4DEE29031940BCC100C76319 /* atts_mensural.cpp */; }; + 4D4335BD1ECCA366003BE1A9 /* breath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4D4335BC1ECCA366003BE1A9 /* breath.cpp */; }; 4D43C30C1A9BB22A00EA28F3 /* view_mensural.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4D43C30B1A9BB22A00EA28F3 /* view_mensural.cpp */; }; 4D50B53A1C1B40C90081D56E /* atttypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D50B5391C1B40C90081D56E /* atttypes.h */; }; 4D50B53B1C1B47540081D56E /* atts_pagebased.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4D3FF8D919BADD7A00B105B5 /* atts_pagebased.cpp */; }; @@ -496,6 +497,8 @@ 4D4220FF199805E400963292 /* att.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = att.h; path = include/vrv/att.h; sourceTree = ""; }; 4D422100199805E400963292 /* attdef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = attdef.h; path = include/vrv/attdef.h; sourceTree = ""; }; 4D422103199805F700963292 /* att.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = att.cpp; path = src/att.cpp; sourceTree = ""; }; + 4D4335BB1ECCA359003BE1A9 /* breath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = breath.h; path = include/vrv/breath.h; sourceTree = ""; }; + 4D4335BC1ECCA366003BE1A9 /* breath.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = breath.cpp; path = src/breath.cpp; sourceTree = ""; }; 4D43C30B1A9BB22A00EA28F3 /* view_mensural.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = view_mensural.cpp; path = src/view_mensural.cpp; sourceTree = ""; }; 4D50B5391C1B40C90081D56E /* atttypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = atttypes.h; path = libmei/atttypes.h; sourceTree = ""; }; 4D543E211B80AACF004B823C /* view_control.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = view_control.cpp; path = src/view_control.cpp; sourceTree = ""; }; @@ -912,6 +915,8 @@ 4DF28A021A754DE400BA9F7D /* controlelement.h */, 4DB351101C8040B1002DD057 /* anchoredtext.cpp */, 4DB3510D1C80409E002DD057 /* anchoredtext.h */, + 4D4335BC1ECCA366003BE1A9 /* breath.cpp */, + 4D4335BB1ECCA359003BE1A9 /* breath.h */, 4DB351111C8040B1002DD057 /* dir.cpp */, 4DB3510E1C80409E002DD057 /* dir.h */, 4DDBBB591C7AE45900054AFF /* dynam.cpp */, @@ -1466,6 +1471,7 @@ buildActionMask = 2147483647; files = ( 8F086EE2188539540037FD8E /* verticalaligner.cpp in Sources */, + 4D4335BD1ECCA366003BE1A9 /* breath.cpp in Sources */, 8F086EE4188539540037FD8E /* barline.cpp in Sources */, 8F086EE5188539540037FD8E /* bboxdevicecontext.cpp in Sources */, 8F086EE6188539540037FD8E /* beam.cpp in Sources */, diff --git a/data/Bravura.xml b/data/Bravura.xml index 073df64c2cf..43908257ef4 100644 --- a/data/Bravura.xml +++ b/data/Bravura.xml @@ -102,6 +102,8 @@ + + diff --git a/data/Bravura/E08C-timeSigPlus.xml b/data/Bravura/E08C-timeSigPlus.xml new file mode 100644 index 00000000000..63b89c475cf --- /dev/null +++ b/data/Bravura/E08C-timeSigPlus.xml @@ -0,0 +1,4 @@ + + + diff --git a/data/Bravura/E08D-timeSigPlusSmall.xml b/data/Bravura/E08D-timeSigPlusSmall.xml new file mode 100644 index 00000000000..fa29cbdcde3 --- /dev/null +++ b/data/Bravura/E08D-timeSigPlusSmall.xml @@ -0,0 +1,4 @@ + + + diff --git a/data/Leipzig.xml b/data/Leipzig.xml index 71a8e83100d..6d65a94c6c5 100644 --- a/data/Leipzig.xml +++ b/data/Leipzig.xml @@ -302,4 +302,6 @@ + + diff --git a/data/Leipzig/E08C-timeSigPlus.xml b/data/Leipzig/E08C-timeSigPlus.xml new file mode 100644 index 00000000000..f6151fa12f1 --- /dev/null +++ b/data/Leipzig/E08C-timeSigPlus.xml @@ -0,0 +1,4 @@ + + + diff --git a/data/Leipzig/E08D-timeSigPlusSmall.xml b/data/Leipzig/E08D-timeSigPlusSmall.xml new file mode 100644 index 00000000000..1d0febe75e9 --- /dev/null +++ b/data/Leipzig/E08D-timeSigPlusSmall.xml @@ -0,0 +1,4 @@ + + + diff --git a/data/Leipzig/E0A3-noteheadHalf.xml b/data/Leipzig/E0A3-noteheadHalf.xml index 3108b440c88..e10fb10d9c1 100644 --- a/data/Leipzig/E0A3-noteheadHalf.xml +++ b/data/Leipzig/E0A3-noteheadHalf.xml @@ -1,4 +1,4 @@ + d="M98 -102zM200 138l41 -5c-2 0 -41 5 -41 5zM278 64c0 22 -17 39 -43 39c-12 0 -26 -3 -41 -10c-85 -43 -165 -94 -165 -156c5 -25 15 -32 49 -32c67 11 200 95 200 159zM0 -36c0 68 73 174 200 174c66 0 114 -39 114 -97c0 -84 -106 -173 -218 -173c-64 0 -96 32 -96 96z "/> diff --git a/emscripten/emscripten_main.cpp b/emscripten/emscripten_main.cpp index 533be44c105..cac7b4f6cd8 100644 --- a/emscripten/emscripten_main.cpp +++ b/emscripten/emscripten_main.cpp @@ -106,7 +106,7 @@ const char *vrvToolkit_getElementsAtTime(Toolkit *tk, int millisec) void vrvToolkit_setOptions(Toolkit *tk, const char *options) { if (!tk->ParseOptions(options)) { - vrv::LogError("Could not load JSON options."); + LogError("Could not load JSON options."); } } @@ -132,7 +132,7 @@ const char *vrvToolkit_renderData(Toolkit *tk, const char *data, const char *opt bool vrvToolkit_edit(Toolkit *tk, const char *editorAction) { if (!tk->Edit(editorAction)) { - vrv::LogError("Could not perform editor action."); + LogError("Could not perform editor action."); return false; } return true; diff --git a/fonts/Leipzig-5.2.sfd b/fonts/Leipzig-5.2.sfd index 71554e2b1ca..eb05f01c0a6 100644 --- a/fonts/Leipzig-5.2.sfd +++ b/fonts/Leipzig-5.2.sfd @@ -3,9 +3,9 @@ FontName: Leipzig FullName: Leipzig FamilyName: Leipzig Weight: Regular -Copyright: Created by Etienne Darbellay, Jean-Francois Marti and Laurent Pugin. \nThis font is licensed under the SIL Open Font License \\(http://scripts.sil.org/OFL\\).\nVersion 5.2.28 -UComments: "2014-03-21: Created.+AAoA-Version 5.2.0 - adding glyphs (dynamics, ornaments, mensural note heads, etc)+AAoA-Version 5.2.1 - adding repeats+AAoA-Version 5.2.2 - fixing size of some glpyhs+AAoA-Version 5.2.3 - adding mensural clefs+AAoA-Version 5.2.4 - adding more dynam glyphs+AAoA-Version 5.2.5 - adding more dynam glyphs+AAoA-Version 5.2.6 - adding some octaves glyphs+AAoA-Version 5.2.7 - adjusting pedal glyphs+AAoA-Version 5.2.8 - adding perc clef+AAoA-Version 5.2.9 - adding two mensural clefs+AAoA-Version 5.2.10 - adding articulations and two fermatas and bow directions+AAoA-Version 5.2.11 - adding harmonic and reviewing bows+AAoA-Version 5.2.12 - reviewing artic width+AAoA-Version 5.2.13 - adding (very)short/long fermata and breath comma+AAoA-Version 5.2.14 - adding mensural stems+AAoA-Version 5.2.15 - changing ascent/descent to 750/250+AAoA-Version 5.2.16 - adding mensural rests+AAoA-Version 5.2.17 - correcting mensural rests position+AAoA-Version 5.2.18 - adding accid square brackets and reviewing bow directions+AAoA-Version 5.2.19 - adding some quartertone accidentals (Gould and Stein-Zimmermann)+AAoA-Version 5.2.20 - adding some anchor points (accidentals)+AAoA-Version 5.2.21 - adding stem flags (16th to 256th)+AAoA-Version 5.2.22 - fixing anchor point names+AAoA-Version 5.2.23 - adding anchor points to all accidentals+AAoA-Version 5.2.24 - changing 8th flags+AAoA-Version 5.2.25 - reviewing mensural clefs+AAoA-Version 5.2.26 - revising position of some rests+AAoA-Version 5.2.27 - adding some anchor points to note heads+AAoA-Version 5.2.28 - correcting anchor points" -Version: 5.2.28 +Copyright: Created by Etienne Darbellay, Jean-Francois Marti and Laurent Pugin. \nThis font is licensed under the SIL Open Font License \\(http://scripts.sil.org/OFL\\).\nVersion 5.2.29 +UComments: "2014-03-21: Created.+AAoA-Version 5.2.0 - adding glyphs (dynamics, ornaments, mensural note heads, etc)+AAoA-Version 5.2.1 - adding repeats+AAoA-Version 5.2.2 - fixing size of some glpyhs+AAoA-Version 5.2.3 - adding mensural clefs+AAoA-Version 5.2.4 - adding more dynam glyphs+AAoA-Version 5.2.5 - adding more dynam glyphs+AAoA-Version 5.2.6 - adding some octaves glyphs+AAoA-Version 5.2.7 - adjusting pedal glyphs+AAoA-Version 5.2.8 - adding perc clef+AAoA-Version 5.2.9 - adding two mensural clefs+AAoA-Version 5.2.10 - adding articulations and two fermatas and bow directions+AAoA-Version 5.2.11 - adding harmonic and reviewing bows+AAoA-Version 5.2.12 - reviewing artic width+AAoA-Version 5.2.13 - adding (very)short/long fermata and breath comma+AAoA-Version 5.2.14 - adding mensural stems+AAoA-Version 5.2.15 - changing ascent/descent to 750/250+AAoA-Version 5.2.16 - adding mensural rests+AAoA-Version 5.2.17 - correcting mensural rests position+AAoA-Version 5.2.18 - adding accid square brackets and reviewing bow directions+AAoA-Version 5.2.19 - adding some quartertone accidentals (Gould and Stein-Zimmermann)+AAoA-Version 5.2.20 - adding some anchor points (accidentals)+AAoA-Version 5.2.21 - adding stem flags (16th to 256th)+AAoA-Version 5.2.22 - fixing anchor point names+AAoA-Version 5.2.23 - adding anchor points to all accidentals+AAoA-Version 5.2.24 - changing 8th flags+AAoA-Version 5.2.25 - reviewing mensural clefs+AAoA-Version 5.2.26 - revising position of some rests+AAoA-Version 5.2.27 - adding some anchor points to note heads+AAoA-Version 5.2.28 - correcting anchor points+AAoA-Version 5.2.29 - adding plus time signature symbols" +Version: 5.2.29 ItalicAngle: 0 UnderlinePosition: -50 UnderlineWidth: 50 @@ -21,7 +21,7 @@ OS2Version: 0 OS2_WeightWidthSlopeOnly: 0 OS2_UseTypoMetrics: 1 CreationTime: 1395388130 -ModificationTime: 1493532553 +ModificationTime: 1495093021 PfmFamily: 17 TTFWeight: 500 TTFWidth: 5 @@ -50,12 +50,12 @@ NameList: Adobe Glyph List DisplaySize: -128 AntiAlias: 1 FitToEm: 1 -WinInfo: 57940 10 4 +WinInfo: 57470 10 4 BeginPrivate: 0 EndPrivate TeXData: 1 0 0 346030 173015 115343 0 1048576 115343 783286 444596 497025 792723 393216 433062 380633 303038 157286 324010 404750 52429 2506097 1059062 262144 AnchorClass2: "cutOutNW""" "cutOutSW""" "cutOutSE""" "cutOutNE""" -BeginChars: 1114115 229 +BeginChars: 1114115 231 StartChar: uniE0A3 Encoding: 57507 57507 0 @@ -11870,5 +11870,53 @@ VWidth: 2048 Flags: HW LayerCount: 2 EndChar + +StartChar: uniE08D +Encoding: 57485 57485 229 +Width: 253 +VWidth: 2048 +Flags: HW +LayerCount: 2 +Fore +SplineSet +252.799804688 -28 m 5 + 154.400390625 -28 l 5 + 154.400390625 -126.400390625 l 5 + 98.400390625 -126.400390625 l 5 + 98.400390625 -28 l 5 + 0 -28 l 5 + 0 28.7998046875 l 5 + 98.400390625 28.7998046875 l 5 + 98.400390625 126.400390625 l 5 + 154.400390625 126.400390625 l 5 + 154.400390625 28.7998046875 l 5 + 252.799804688 28.7998046875 l 5 + 252.799804688 -28 l 5 +EndSplineSet +EndChar + +StartChar: uniE08C +Encoding: 57484 57484 230 +Width: 342 +VWidth: 2048 +Flags: HW +LayerCount: 2 +Fore +SplineSet +341.279296875 -37.7998046875 m 1 + 208.440429688 -37.7998046875 l 1 + 208.440429688 -170.640625 l 1 + 132.840820312 -170.640625 l 1 + 132.840820312 -37.7998046875 l 1 + 0 -37.7998046875 l 1 + 0 38.87890625 l 1 + 132.840820312 38.87890625 l 1 + 132.840820312 170.640625 l 1 + 208.440429688 170.640625 l 1 + 208.440429688 38.87890625 l 1 + 341.279296875 38.87890625 l 1 + 341.279296875 -37.7998046875 l 1 +EndSplineSet +EndChar EndChars EndSplineFont diff --git a/fonts/Leipzig.svg b/fonts/Leipzig.svg index eb034b068eb..e2f09dce1ed 100644 --- a/fonts/Leipzig.svg +++ b/fonts/Leipzig.svg @@ -29,14 +29,17 @@ Version 5.2.23 - adding anchor points to all accidentals Version 5.2.24 - changing 8th flags Version 5.2.25 - reviewing mensural clefs Version 5.2.26 - revising position of some rests +Version 5.2.27 - adding some anchor points to note heads +Version 5.2.28 - correcting anchor points +Version 5.2.29 - adding plus time signature symbols --> -Created by FontForge 20161003 at Thu Apr 27 21:56:35 2017 +Created by FontForge 20161003 at Thu May 18 09:37:01 2017 By laurent Created by Etienne Darbellay, Jean-Francois Marti and Laurent Pugin. This font is licensed under the SIL Open Font License \(http://scripts.sil.org/OFL\). -Version 5.2.26 +Version 5.2.29 @@ -55,7 +58,7 @@ Version 5.2.26 /> @@ -1071,5 +1074,9 @@ c-10 38 -26 47 -67 53c-39 -6 -62 -27 -70 -62c0 -33 19 -54 58 -62l17 -6c2 -1 8 0 /> + + diff --git a/fonts/json/leipzig-5.2_metadata.json b/fonts/json/leipzig-5.2_metadata.json index bb153fc6610..b9430d29801 100644 --- a/fonts/json/leipzig-5.2_metadata.json +++ b/fonts/json/leipzig-5.2_metadata.json @@ -30,7 +30,7 @@ "tupletBracketThickness": "0.16" }, "fontName": "Leipzig-5.2", - "fontVersion": "5.2.28", + "fontVersion": "5.2.29", "glyphBBoxes": { "uniE003": { "bBoxNE": [ @@ -362,6 +362,26 @@ -1.276 ] }, + "uniE08C": { + "bBoxNE": [ + 1.3651, + 0.6826 + ], + "bBoxSW": [ + 0.0, + -0.6826 + ] + }, + "uniE08D": { + "bBoxNE": [ + 1.0112, + 0.5056 + ], + "bBoxSW": [ + 0.0, + -0.5056 + ] + }, "uniE0A2": { "bBoxNE": [ 1.62, @@ -2393,6 +2413,12 @@ "uniE08B": { "codepoint": "0XE08B" }, + "uniE08C": { + "codepoint": "0XE08C" + }, + "uniE08D": { + "codepoint": "0XE08D" + }, "uniE0A2": { "codepoint": "0XE0A2" }, diff --git a/fonts/supported.xsl b/fonts/supported.xsl index 9d99948a5e7..d39914500b1 100644 --- a/fonts/supported.xsl +++ b/fonts/supported.xsl @@ -145,8 +145,8 @@ - - + + diff --git a/include/pugi/pugiconfig.hpp b/include/pugi/pugiconfig.hpp index 8f610c71f25..fd1dd4fbd55 100644 --- a/include/pugi/pugiconfig.hpp +++ b/include/pugi/pugiconfig.hpp @@ -1,7 +1,7 @@ /** - * pugixml parser - version 1.7 + * pugixml parser - version 1.8 * -------------------------------------------------------- - * Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Copyright (C) 2006-2016, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at http://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end @@ -49,7 +49,7 @@ #endif /** - * Copyright (c) 2006-2015 Arseny Kapoulkine + * Copyright (c) 2006-2016 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -62,7 +62,7 @@ * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND diff --git a/include/pugi/pugixml.hpp b/include/pugi/pugixml.hpp index 3d5b2bced9b..7386f1f2865 100644 --- a/include/pugi/pugixml.hpp +++ b/include/pugi/pugixml.hpp @@ -1,7 +1,7 @@ /** - * pugixml parser - version 1.7 + * pugixml parser - version 1.8 * -------------------------------------------------------- - * Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Copyright (C) 2006-2016, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at http://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end @@ -13,7 +13,7 @@ #ifndef PUGIXML_VERSION // Define version macro; evaluates to major * 100 + minor so that it's safe to use in less-than comparisons -# define PUGIXML_VERSION 170 +# define PUGIXML_VERSION 180 #endif // Include user configuration file (this can define various configuration macros) @@ -72,6 +72,24 @@ # endif #endif +// If the platform is known to have move semantics support, compile move ctor/operator implementation +#ifndef PUGIXML_HAS_MOVE +# if __cplusplus >= 201103 +# define PUGIXML_HAS_MOVE +# elif defined(_MSC_VER) && _MSC_VER >= 1600 +# define PUGIXML_HAS_MOVE +# endif +#endif + +// If C++ is 2011 or higher, add 'override' qualifiers +#ifndef PUGIXML_OVERRIDE +# if __cplusplus >= 201103 +# define PUGIXML_OVERRIDE override +# else +# define PUGIXML_OVERRIDE +# endif +#endif + // Character interface macros #ifdef PUGIXML_WCHAR_MODE # define PUGIXML_TEXT(t) L ## t @@ -133,13 +151,13 @@ namespace pugi // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default. const unsigned int parse_eol = 0x0020; - + // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default. const unsigned int parse_wconv_attribute = 0x0040; // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default. const unsigned int parse_wnorm_attribute = 0x0080; - + // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default. const unsigned int parse_declaration = 0x0100; @@ -158,6 +176,11 @@ namespace pugi // is a valid document. This flag is off by default. const unsigned int parse_fragment = 0x1000; + // This flag determines if plain character data is be stored in the parent element's value. This significantly changes the structure of + // the document; this flag is only recommended for parsing documents with many PCDATA nodes in memory-constrained environments. + // This flag is off by default. + const unsigned int parse_embed_pcdata = 0x2000; + // The default parsing mode. // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded, // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. @@ -184,16 +207,16 @@ namespace pugi }; // Formatting flags - + // Indent the nodes that are written to output stream with as many indentation strings as deep the node is in DOM tree. This flag is on by default. const unsigned int format_indent = 0x01; - + // Write encoding-specific BOM to the output stream. This flag is off by default. const unsigned int format_write_bom = 0x02; // Use raw output mode (no indentation and no line breaks are written). This flag is off by default. const unsigned int format_raw = 0x04; - + // Omit default XML declaration even if there is no declaration in the document. This flag is off by default. const unsigned int format_no_declaration = 0x08; @@ -206,6 +229,9 @@ namespace pugi // Write every attribute on a new line with appropriate indentation. This flag is off by default. const unsigned int format_indent_attributes = 0x40; + // Don't output empty element tags, instead writing an explicit start and end tag even if there are no children. This flag is off by default. + const unsigned int format_no_empty_element_tags = 0x80; + // The default set of formatting flags. // Nodes are indented depending on their depth in DOM tree, a default declaration is output if document has none. const unsigned int format_default = format_indent; @@ -225,7 +251,7 @@ namespace pugi class xml_node; class xml_text; - + #ifndef PUGIXML_NO_XPATH class xpath_node; class xpath_node_set; @@ -268,7 +294,7 @@ namespace pugi // Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio xml_writer_file(void* file); - virtual void write(const void* data, size_t size); + virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE; private: void* file; @@ -283,7 +309,7 @@ namespace pugi xml_writer_stream(std::basic_ostream >& stream); xml_writer_stream(std::basic_ostream >& stream); - virtual void write(const void* data, size_t size); + virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE; private: std::basic_ostream >* narrow_stream; @@ -299,13 +325,13 @@ namespace pugi private: xml_attribute_struct* _attr; - + typedef void (*unspecified_bool_type)(xml_attribute***); public: // Default constructor. Constructs an empty attribute. xml_attribute(); - + // Constructs attribute from internal pointer explicit xml_attribute(xml_attribute_struct* attr); @@ -354,6 +380,8 @@ namespace pugi // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set_value(int rhs); bool set_value(unsigned int rhs); + bool set_value(long rhs); + bool set_value(unsigned long rhs); bool set_value(double rhs); bool set_value(float rhs); bool set_value(bool rhs); @@ -367,6 +395,8 @@ namespace pugi xml_attribute& operator=(const char_t* rhs); xml_attribute& operator=(int rhs); xml_attribute& operator=(unsigned int rhs); + xml_attribute& operator=(long rhs); + xml_attribute& operator=(unsigned long rhs); xml_attribute& operator=(double rhs); xml_attribute& operator=(float rhs); xml_attribute& operator=(bool rhs); @@ -417,7 +447,7 @@ namespace pugi // Borland C++ workaround bool operator!() const; - + // Comparison operators (compares wrapped node pointers) bool operator==(const xml_node& r) const; bool operator!=(const xml_node& r) const; @@ -438,7 +468,7 @@ namespace pugi // Get node value, or "" if node is empty or it has no value // Note: For text node.value() does not return "text"! Use child_value() or text() methods to access text inside nodes. const char_t* value() const; - + // Get attribute list xml_attribute first_attribute() const; xml_attribute last_attribute() const; @@ -450,7 +480,7 @@ namespace pugi // Get next/previous sibling in the children list of the parent node xml_node next_sibling() const; xml_node previous_sibling() const; - + // Get parent node xml_node parent() const; @@ -478,7 +508,7 @@ namespace pugi // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) bool set_name(const char_t* rhs); bool set_value(const char_t* rhs); - + // Add attribute with specified name. Returns added attribute, or empty attribute on errors. xml_attribute append_attribute(const char_t* name); xml_attribute prepend_attribute(const char_t* name); @@ -532,11 +562,11 @@ namespace pugi template xml_attribute find_attribute(Predicate pred) const { if (!_root) return xml_attribute(); - + for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute()) if (pred(attrib)) return attrib; - + return xml_attribute(); } @@ -544,11 +574,11 @@ namespace pugi template xml_node find_child(Predicate pred) const { if (!_root) return xml_node(); - + for (xml_node node = first_child(); node; node = node.next_sibling()) if (pred(node)) return node; - + return xml_node(); } @@ -558,7 +588,7 @@ namespace pugi if (!_root) return xml_node(); xml_node cur = first_child(); - + while (cur._root && cur._root != _root) { if (pred(cur)) return cur; @@ -590,7 +620,7 @@ namespace pugi // Recursively traverse subtree with xml_tree_walker bool traverse(xml_tree_walker& walker); - + #ifndef PUGIXML_NO_XPATH // Select single node by evaluating XPath query. Returns first node from the resulting node set. xpath_node select_node(const char_t* query, xpath_variable_set* variables = 0) const; @@ -605,7 +635,7 @@ namespace pugi xpath_node select_single_node(const xpath_query& query) const; #endif - + // Print subtree using a writer object void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; @@ -701,6 +731,8 @@ namespace pugi // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set(int rhs); bool set(unsigned int rhs); + bool set(long rhs); + bool set(unsigned long rhs); bool set(double rhs); bool set(float rhs); bool set(bool rhs); @@ -714,6 +746,8 @@ namespace pugi xml_text& operator=(const char_t* rhs); xml_text& operator=(int rhs); xml_text& operator=(unsigned int rhs); + xml_text& operator=(long rhs); + xml_text& operator=(unsigned long rhs); xml_text& operator=(double rhs); xml_text& operator=(float rhs); xml_text& operator=(bool rhs); @@ -867,11 +901,11 @@ namespace pugi private: int _depth; - + protected: // Get current traversal depth int depth() const; - + public: xml_tree_walker(); virtual ~xml_tree_walker(); @@ -942,13 +976,13 @@ namespace pugi char_t* _buffer; char _memory[192]; - + // Non-copyable semantics xml_document(const xml_document&); xml_document& operator=(const xml_document&); - void create(); - void destroy(); + void _create(); + void _destroy(); public: // Default constructor, makes empty document @@ -1051,7 +1085,7 @@ namespace pugi // Non-copyable semantics xpath_variable(const xpath_variable&); xpath_variable& operator=(const xpath_variable&); - + public: // Get variable name const char_t* name() const; @@ -1095,7 +1129,7 @@ namespace pugi xpath_variable_set(const xpath_variable_set& rhs); xpath_variable_set& operator=(const xpath_variable_set& rhs); - #if __cplusplus >= 201103 + #ifdef PUGIXML_HAS_MOVE // Move semantics support xpath_variable_set(xpath_variable_set&& rhs); xpath_variable_set& operator=(xpath_variable_set&& rhs); @@ -1139,7 +1173,7 @@ namespace pugi // Destructor ~xpath_query(); - #if __cplusplus >= 201103 + #ifdef PUGIXML_HAS_MOVE // Move semantics support xpath_query(xpath_query&& rhs); xpath_query& operator=(xpath_query&& rhs); @@ -1147,21 +1181,21 @@ namespace pugi // Get query expression return type xpath_value_type return_type() const; - + // Evaluate expression as boolean value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. bool evaluate_boolean(const xpath_node& n) const; - + // Evaluate expression as double value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. double evaluate_number(const xpath_node& n) const; - + #ifndef PUGIXML_NO_STL // Evaluate expression as string value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. string_t evaluate_string(const xpath_node& n) const; #endif - + // Evaluate expression as string value in the specified context; performs type conversion if necessary. // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero). // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. @@ -1188,7 +1222,7 @@ namespace pugi // Borland C++ workaround bool operator!() const; }; - + #ifndef PUGIXML_NO_EXCEPTIONS // XPath exception class class PUGIXML_CLASS xpath_exception: public std::exception @@ -1201,26 +1235,26 @@ namespace pugi explicit xpath_exception(const xpath_parse_result& result); // Get error message - virtual const char* what() const throw(); + virtual const char* what() const throw() PUGIXML_OVERRIDE; // Get parse result const xpath_parse_result& result() const; }; #endif - + // XPath node class (either xml_node or xml_attribute) class PUGIXML_CLASS xpath_node { private: xml_node _node; xml_attribute _attribute; - + typedef void (*unspecified_bool_type)(xpath_node***); public: // Default constructor; constructs empty XPath node xpath_node(); - + // Construct XPath node from XML node/attribute xpath_node(const xml_node& node); xpath_node(const xml_attribute& attribute, const xml_node& parent); @@ -1228,13 +1262,13 @@ namespace pugi // Get node/attribute, if any xml_node node() const; xml_attribute attribute() const; - + // Get parent of contained node/attribute xml_node parent() const; // Safe bool conversion operator operator unspecified_bool_type() const; - + // Borland C++ workaround bool operator!() const; @@ -1260,13 +1294,13 @@ namespace pugi type_sorted, // Sorted by document order (ascending) type_sorted_reverse // Sorted by document order (descending) }; - + // Constant iterator type typedef const xpath_node* const_iterator; // We define non-constant iterator to be the same as constant iterator so that various generic algorithms (i.e. boost foreach) work typedef const xpath_node* iterator; - + // Default constructor. Constructs empty set. xpath_node_set(); @@ -1275,12 +1309,12 @@ namespace pugi // Destructor ~xpath_node_set(); - + // Copy constructor/assignment operator xpath_node_set(const xpath_node_set& ns); xpath_node_set& operator=(const xpath_node_set& ns); - #if __cplusplus >= 201103 + #ifdef PUGIXML_HAS_MOVE // Move semantics support xpath_node_set(xpath_node_set&& rhs); xpath_node_set& operator=(xpath_node_set&& rhs); @@ -1288,31 +1322,31 @@ namespace pugi // Get collection type type_t type() const; - + // Get collection size size_t size() const; // Indexing operator const xpath_node& operator[](size_t index) const; - + // Collection iterators const_iterator begin() const; const_iterator end() const; // Sort the collection in ascending/descending order by document order void sort(bool reverse = false); - + // Get first node in the collection by document order xpath_node first() const; - + // Check if collection is empty bool empty() const; - + private: type_t _type; - + xpath_node _storage; - + xpath_node* _begin; xpath_node* _end; @@ -1325,7 +1359,7 @@ namespace pugi // Convert wide string to UTF8 std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const wchar_t* str); std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const std::basic_string, std::allocator >& str); - + // Convert UTF8 to wide string std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const char* str); std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const std::basic_string, std::allocator >& str); @@ -1333,13 +1367,13 @@ namespace pugi // Memory allocation function interface; returns pointer to allocated memory or NULL on failure typedef void* (*allocation_function)(size_t size); - + // Memory deallocation function interface typedef void (*deallocation_function)(void* ptr); // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions. void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate); - + // Get current memory management functions allocation_function PUGIXML_FUNCTION get_memory_allocation_function(); deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function(); @@ -1375,7 +1409,7 @@ namespace std #endif /** - * Copyright (c) 2006-2015 Arseny Kapoulkine + * Copyright (c) 2006-2016 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -1388,7 +1422,7 @@ namespace std * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND diff --git a/include/vrv/artic.h.orig b/include/vrv/artic.h.orig deleted file mode 100644 index c2c4b1efe48..00000000000 --- a/include/vrv/artic.h.orig +++ /dev/null @@ -1,192 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: artic.h -// Author: Laurent Pugin -// Created: 2016 -// Copyright (c) Authors and others. All rights reserved. -///////////////////////////////////////////////////////////////////////////// - -#ifndef __VRV_ARTIC_H__ -#define __VRV_ARTIC_H__ - -#include "atts_shared.h" -#include "layerelement.h" - -namespace vrv { - -class ArticPart; - -//---------------------------------------------------------------------------- -// Artic -//---------------------------------------------------------------------------- - -class Artic : public LayerElement, public AttArticulation, public AttColor, public AttPlacement { -public: - /** - * @name Constructors, destructors, and other standard methods - * Reset method resets all attribute classes - */ - ///@{ - Artic(); - virtual ~Artic(); - virtual void Reset(); - virtual std::string GetClassName() const { return "Artic"; } - virtual ClassId GetClassId() const { return ARTIC; } - ///@} - - /** - * Add an element (an articPart) to a artic. - */ - virtual void AddChild(Object *object); - - /** - * Split the articulation content into an array with the values to be displayed inside the staff / slur - * and the values to be displayed outside. - * Used by Artic::PrepareArtic that then creates the corresponding ArticPart objects. - */ - void SplitArtic(std::vector *insideSlur, std::vector *outsideSlur); - - /** - * Static method that retrieves the appropriate SMuFL code for a data_ARTICULATION with data_STAFFREL - */ - static wchar_t GetSmuflCode(data_ARTICULATION artic, data_STAFFREL place); - - /** - * Static method that retrieves the vertical correctoin for a SMuFL code for with data_STAFFREL. - * The reason for this is that SMuFL sometimes has the glyph below the line, sometimes above. - * See bow indications for an example where is is always above - */ - static bool VerticalCorr(wchar_t code, data_STAFFREL place); - - /** - * Static method that returns true if the data_ARTICULATION has to be centered between staff lines - */ - static bool IsCentered(data_ARTICULATION artic); - - /** - * Return the inside and outside part of an artic if any (NULL otherwiser) - */ - ///@{ - ArticPart *GetInsidePart(); - ArticPart *GetOutsidePart(); - ///@} - - //----------// - // Functors // - //----------// - - /** - * See Object::AdjustArtic - */ - virtual int AdjustArtic(FunctorParams *functorParams); - - /** - * See Object::PrepareArtic - */ - virtual int PrepareArtic(FunctorParams *functorParams); - - /** - * See Object::ResetDrawing - */ - virtual int ResetDrawing(FunctorParams *functorParams); - -private: - // -public: - /** - * A static array for storing the articulation that have to be placed outside the staff - */ - static std::vector s_outStaffArtic; - /** - * A static array for storing the articulation that have to be place above the staff is possible - */ - static std::vector s_aboveStaffArtic; - -private: -}; - -//---------------------------------------------------------------------------- -// ArticPart -//---------------------------------------------------------------------------- - -/** - * This class models a sub-part of an artic element and has not direct MEI equivlatent. - */ - -class ArticPart : public LayerElement, public AttArticulation, public AttColor, public AttPlacement { -public: - /** - * @name Constructors, destructors, and other standard methods - * Reset method resets all attribute classes - */ - ///@{ - ArticPart(ArticPartType type, Artic *artic); - virtual ~ArticPart(); - virtual void Reset(); - virtual std::string GetClassName() const { return "ArticPart"; } - virtual ClassId GetClassId() const { return ARTIC_PART; } - ///@} - - /** Override the method since alignment is required */ - virtual bool HasToBeAligned() const { return true; } - - /** Override the method since it is align to the staff */ - virtual bool IsRelativeToStaff() const { return true; } - - /** - * @name Set and get the type of the alignment - */ - ///@{ - void SetType(ArticPartType type) { m_type = type; } - ArticPartType GetType() const { return m_type; } - ///@} - - /** - * Check if the articList contains data_ARTICULATION has to be place above staff. - */ - bool AlwaysAbove(); - - void AddSlurPositioner(FloatingPositioner *positioner, bool start); - - //----------// - // Functors // - //----------// - - /** - * Overwritten version of Save that avoids anything to be written - */ -<<<<<<< HEAD - ///@{ - virtual int Save(FunctorParams *functorParams) { return FUNCTOR_CONTINUE; } - virtual int SaveEnd(FunctorParams *functorParams) { return FUNCTOR_CONTINUE; } - ///@} -======= - virtual int Save(FunctorParams *) { return FUNCTOR_CONTINUE; } - virtual int SaveEnd(FunctorParams *) { return FUNCTOR_CONTINUE; } ->>>>>>> develop - - /** - * See Object::AdjustArticWithSlurs - */ - virtual int AdjustArticWithSlurs(FunctorParams *functorParams); - - /** - * See Object::ResetVerticalAlignment - */ - virtual int ResetVerticalAlignment(FunctorParams *functorParams); - -private: - // -public: - // -private: - /** the type of artic part */ - ArticPartType m_type; - -public: - std::vector m_startSlurPositioners; - std::vector m_endSlurPositioners; -}; - -} // namespace vrv - -#endif diff --git a/include/vrv/beam.h b/include/vrv/beam.h index 705a577d9a1..6984000305a 100644 --- a/include/vrv/beam.h +++ b/include/vrv/beam.h @@ -63,7 +63,7 @@ class BeamDrawingParams { // Beam //---------------------------------------------------------------------------- -class Beam : public LayerElement, public ObjectListInterface, public DrawingListInterface { +class Beam : public LayerElement, public ObjectListInterface, public DrawingListInterface, public AttColor { public: /** * @name Constructors, destructors, and other standard methods diff --git a/include/vrv/breath.h b/include/vrv/breath.h new file mode 100644 index 00000000000..dcee1f32184 --- /dev/null +++ b/include/vrv/breath.h @@ -0,0 +1,58 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: breath.h +// Author: Klaus Rettinghaus +// Created: 2017 +// Copyright (c) Authors and others. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#ifndef __VRV_BREATH_H__ +#define __VRV_BREATH_H__ + +#include "atts_cmn.h" +#include "controlelement.h" +#include "timeinterface.h" + +namespace vrv { + +//---------------------------------------------------------------------------- +// Breath +//---------------------------------------------------------------------------- + +class Breath : public ControlElement, public TimePointInterface, public AttColor, public AttPlacement { +public: + /** + * @name Constructors, destructors, and other standard methods + * Reset method reset all attribute classes + */ + ///@{ + Breath(); + virtual ~Breath(); + virtual void Reset(); + virtual std::string GetClassName() const { return "Breath"; } + virtual ClassId GetClassId() const { return BREATH; } + ///@} + + /** + * @name Getter to interfaces + */ + ///@{ + virtual TimePointInterface *GetTimePointInterface() { return dynamic_cast(this); } + ///@} + + //----------// + // Functors // + //----------// + +protected: + // +private: + // +public: + // +private: + // +}; + +} // namespace vrv + +#endif diff --git a/include/vrv/clef.h b/include/vrv/clef.h index 9e8cb579150..d07e4a4319b 100644 --- a/include/vrv/clef.h +++ b/include/vrv/clef.h @@ -22,7 +22,11 @@ class ScoreDefInterface; /** * This class models the MEI element. */ -class Clef : public LayerElement, public AttClefshape, public AttLineloc, public AttOctavedisplacement { +class Clef : public LayerElement, + public AttClefshape, + public AttColor, + public AttLineloc, + public AttOctavedisplacement { public: /** * @name Constructors, destructors, and other standard methods diff --git a/include/vrv/controlelement.h b/include/vrv/controlelement.h index d13a870fe62..145c8a6e3d0 100644 --- a/include/vrv/controlelement.h +++ b/include/vrv/controlelement.h @@ -22,7 +22,7 @@ namespace vrv { * This class represents elements appearing within a measure. * It is not an abstract class but should not be instanciated directly. */ -class ControlElement : public FloatingObject, public AttCommon, public AttTyped { +class ControlElement : public FloatingObject, public AttCommon, public AttCommonPart, public AttTyped { public: /** * @name Constructors, destructors, reset methods diff --git a/include/vrv/custos.h b/include/vrv/custos.h index 9786b245750..daca93bc918 100644 --- a/include/vrv/custos.h +++ b/include/vrv/custos.h @@ -17,7 +17,7 @@ namespace vrv { // Custos //---------------------------------------------------------------------------- -class Custos : public LayerElement, public PositionInterface { +class Custos : public LayerElement, public PositionInterface, public AttColor { public: /** * @name Constructors, destructors, and other standard methods diff --git a/include/vrv/iomei.h b/include/vrv/iomei.h index f562545b2bc..1e4c868e1f8 100644 --- a/include/vrv/iomei.h +++ b/include/vrv/iomei.h @@ -32,6 +32,7 @@ class BarLine; class Beam; class BeatRpt; class BoundaryEnd; +class Breath; class BTrem; class Choice; class Chord; @@ -220,6 +221,7 @@ class MeiOutput : public FileOutputStream { */ ///@{ void WriteMeiAnchoredText(pugi::xml_node currentNode, AnchoredText *anchoredText); + void WriteMeiBreath(pugi::xml_node currentNode, Breath *breath); void WriteMeiDir(pugi::xml_node currentNode, Dir *dir); void WriteMeiDynam(pugi::xml_node currentNode, Dynam *dynam); void WriteMeiFermata(pugi::xml_node currentNode, Fermata *fermata); @@ -450,6 +452,7 @@ class MeiInput : public FileInputStream { */ ///@{ bool ReadMeiAnchoredText(Object *parent, pugi::xml_node anchoredText); + bool ReadMeiBreath(Object *parent, pugi::xml_node breath); bool ReadMeiDir(Object *parent, pugi::xml_node dir); bool ReadMeiDynam(Object *parent, pugi::xml_node dynam); bool ReadMeiFermata(Object *parent, pugi::xml_node fermata); diff --git a/include/vrv/iomusxml.h b/include/vrv/iomusxml.h index ee5ad62d3f7..ae3e897e9dc 100644 --- a/include/vrv/iomusxml.h +++ b/include/vrv/iomusxml.h @@ -26,6 +26,8 @@ namespace vrv { class ControlElement; class Dir; class Dynam; +class F; +class Fb; class Hairpin; class Harm; class Layer; @@ -118,7 +120,7 @@ class MusicXmlInput : public FileInputStream { */ ///@{ bool ReadMusicXmlPart(pugi::xml_node node, Section *section, int nbStaves, int staffOffset); - bool ReadMusicXmlMeasure(pugi::xml_node node, Measure *measure, int nbStaves, int staffOffset); + bool ReadMusicXmlMeasure(pugi::xml_node node, Section *section, Measure *measure, int nbStaves, int staffOffset); ///@} /* @@ -131,14 +133,15 @@ class MusicXmlInput : public FileInputStream { * @name Methods for reading the content of a MusicXml measure. */ ///@{ - void ReadMusicXmlAttributes(pugi::xml_node, Measure *measure, int measureNum); + void ReadMusicXmlAttributes(pugi::xml_node, Section *section, Measure *measure, int measureNum); void ReadMusicXmlBackup(pugi::xml_node, Measure *measure, int measureNum); void ReadMusicXmlBarLine(pugi::xml_node, Measure *measure, int measureNum); void ReadMusicXmlDirection(pugi::xml_node, Measure *measure, int measureNum); + void ReadMusicXmlFigures(pugi::xml_node node, Measure *measure, int measureNum); void ReadMusicXmlForward(pugi::xml_node, Measure *measure, int measureNum); void ReadMusicXmlHarmony(pugi::xml_node, Measure *measure, int measureNum); void ReadMusicXmlNote(pugi::xml_node, Measure *measure, int measureNum); - void ReadMusicXmlPrint(pugi::xml_node, Measure *measure, int measureNum); + void ReadMusicXmlPrint(pugi::xml_node, Section *section); ///@} /* @@ -222,7 +225,7 @@ class MusicXmlInput : public FileInputStream { */ ///@{ ///@} - void FillSpace(vrv::Layer *layer, int dur); + void FillSpace(Layer *layer, int dur); /* * @name Helper method for generating additional IDs @@ -258,8 +261,9 @@ class MusicXmlInput : public FileInputStream { int m_ppq; /* meaure time */ int m_durTotal = 0; - /* meter count */ + /* meter signature */ int m_meterCount = 0; + int m_meterUnit = 0; /* LastElementID **/ std::string m_ID; /* The stack for piling open LayerElements (beams, tuplets, chords, etc.) */ diff --git a/include/vrv/layerelement.h b/include/vrv/layerelement.h index e7366199af7..dce01f9bad5 100644 --- a/include/vrv/layerelement.h +++ b/include/vrv/layerelement.h @@ -29,7 +29,7 @@ class Staff; * This class is a base class for the Layer () content. * It is not an abstract class but should not be instantiated directly. */ -class LayerElement : public Object, public AttCommon, public AttTyped { +class LayerElement : public Object, public AttCommon, public AttCommonPart, public AttTyped { public: /** * @name Constructors, destructors, reset and class name methods diff --git a/include/vrv/mensur.h b/include/vrv/mensur.h index da0e26c9da2..3a7fb8edd46 100644 --- a/include/vrv/mensur.h +++ b/include/vrv/mensur.h @@ -24,6 +24,7 @@ class ScoreDefInterface; * This class models the MEI element. */ class Mensur : public LayerElement, + public AttColor, public AttDurationRatio, public AttMensuralShared, public AttMensurLog, diff --git a/include/vrv/multirest.h b/include/vrv/multirest.h index f6bdf59cd95..74c57a17b6d 100644 --- a/include/vrv/multirest.h +++ b/include/vrv/multirest.h @@ -20,7 +20,7 @@ namespace vrv { /** * This class models the MEI element. */ -class MultiRest : public LayerElement, public AttNumbered { +class MultiRest : public LayerElement, public AttMultiRestVis, public AttNumbered { public: /** * @name Constructors, destructors, reset and class name methods diff --git a/include/vrv/note.h b/include/vrv/note.h index b3a8db2034a..875e9048b27 100644 --- a/include/vrv/note.h +++ b/include/vrv/note.h @@ -43,6 +43,7 @@ class Note : public LayerElement, public StemmedDrawingInterface, public DurationInterface, public PitchInterface, + public PositionInterface, public AttColor, public AttColoration, public AttGraced, @@ -154,7 +155,7 @@ class Note : public LayerElement, virtual Point GetStemUpSE(Doc *doc, int staffSize, bool graceSize); virtual Point GetStemDownNW(Doc *doc, int staffSize, bool graceSize); ///@} - + /** * Return the SMuFL code for a mensural note looking at the staff notation type, the coloration and the duration */ diff --git a/include/vrv/rest.h b/include/vrv/rest.h index 65ba8a8a7cc..6f2f63d2948 100644 --- a/include/vrv/rest.h +++ b/include/vrv/rest.h @@ -65,9 +65,9 @@ class Rest : public LayerElement, wchar_t GetRestGlyph() const; /** - * Get the default loc for a doc when neither oloc or loc are provided. + * Get the vertical offset for each glyph. */ - int GetDefaultLoc(bool hasMultipleLayer, bool isFirstLayer); + int GetRestLocOffset(int loc); //----------// // Functors // diff --git a/include/vrv/scoredefinterface.h b/include/vrv/scoredefinterface.h index b3a49ddcb42..c11f41d869d 100644 --- a/include/vrv/scoredefinterface.h +++ b/include/vrv/scoredefinterface.h @@ -26,6 +26,7 @@ namespace vrv { */ class ScoreDefInterface : public Interface, public AttCleffingLog, + public AttCleffingVis, public AttKeySigDefaultLog, public AttKeySigDefaultVis, public AttLyricstyle, diff --git a/include/vrv/smufl.h b/include/vrv/smufl.h index bca4337d1fb..d423a014c2b 100644 --- a/include/vrv/smufl.h +++ b/include/vrv/smufl.h @@ -55,6 +55,8 @@ enum { SMUFL_E089_timeSig9 = 0xE089, SMUFL_E08A_timeSigCommon = 0xE08A, SMUFL_E08B_timeSigCutCommon = 0xE08B, + SMUFL_E08C_timeSigPlus = 0xE08C, + SMUFL_E08D_timeSigPlusSmall = 0xE08D, SMUFL_E0A2_noteheadWhole = 0xE0A2, SMUFL_E0A3_noteheadHalf = 0xE0A3, SMUFL_E0A4_noteheadBlack = 0xE0A4, @@ -245,7 +247,7 @@ enum { }; /** The number of glyphs for verification **/ -#define SMUFL_COUNT 220 +#define SMUFL_COUNT 222 } // vrv namespace diff --git a/include/vrv/staff.h b/include/vrv/staff.h index 7ea60141e90..f0c3f107362 100644 --- a/include/vrv/staff.h +++ b/include/vrv/staff.h @@ -96,8 +96,8 @@ class Staff : public Object, public AttCommon, public AttTyped { * If necessary creates the ledger line array. */ ///@{ - void AddLegerLineAbove(int count, short left, short right, bool cueSize); - void AddLegerLineBelow(int count, short left, short right, bool cueSize); + void AddLegerLineAbove(int count, int left, int right, bool cueSize); + void AddLegerLineBelow(int count, int left, int right, bool cueSize); ///@} //----------// @@ -143,7 +143,7 @@ class Staff : public Object, public AttCommon, public AttTyped { /** * Add the ledger line dashes to the legderline array. */ - void AddLegerLines(ArrayOfLedgerLines *lines, int count, short left, short right); + void AddLegerLines(ArrayOfLedgerLines *lines, int count, int left, int right); public: /** @@ -216,7 +216,7 @@ class LedgerLine { * Add a dash to the ledger line object. * If necessary merges overlapping dashes. */ - void AddDash(short left, short right); + void AddDash(int left, int right); protected: // @@ -226,7 +226,7 @@ class LedgerLine { /** * A list of dashes relative to the staff position. */ - std::list > m_dashes; + std::list > m_dashes; protected: // diff --git a/include/vrv/tuplet.h b/include/vrv/tuplet.h index f16b6a1a1bb..b7d39ceaf91 100644 --- a/include/vrv/tuplet.h +++ b/include/vrv/tuplet.h @@ -22,6 +22,7 @@ class Note; class Tuplet : public LayerElement, public ObjectListInterface, + public AttColor, public AttDurationRatio, public AttNumberplacement, public AttTupletVis { diff --git a/include/vrv/view.h b/include/vrv/view.h index 6387b91f2f4..9b08bf4cb79 100644 --- a/include/vrv/view.h +++ b/include/vrv/view.h @@ -18,6 +18,7 @@ class Accid; class BarLine; class Beam; class BeamDrawingParams; +class Breath; class Chord; class DeviceContext; class Dir; @@ -328,6 +329,7 @@ class View { DeviceContext *dc, Syl *syl, int x1, int x2, Staff *staff, char spanningType, Object *graphic = NULL); void DrawSylConnectorLines(DeviceContext *dc, int x1, int x2, int y, Syl *syl, Staff *staff); void DrawTimeSpanningElement(DeviceContext *dc, Object *object, System *system); + void DrawBreath(DeviceContext *dc, Breath *dir, Measure *measure, System *system); void DrawDir(DeviceContext *dc, Dir *dir, Measure *measure, System *system); void DrawDynam(DeviceContext *dc, Dynam *dynam, Measure *measure, System *system); void DrawFermata(DeviceContext *dc, Fermata *fermata, Measure *measure, System *system); @@ -432,6 +434,7 @@ class View { std::wstring IntToTimeSigFigures(unsigned short number); std::wstring IntToSmuflFigures(unsigned short number, int offset); bool OneBeamInTuplet(Tuplet *tuplet); + int NestedTuplets(Object *object); int GetSylYRel(Syl *syl, Staff *staff); ///@} diff --git a/include/vrv/vrvdef.h b/include/vrv/vrvdef.h index adcdfc61859..9d8fddb446d 100644 --- a/include/vrv/vrvdef.h +++ b/include/vrv/vrvdef.h @@ -102,6 +102,7 @@ enum ClassId { // Ids for ControlElement child classes CONTROL_ELEMENT, ANCHORED_TEXT, + BREATH, DIR, DYNAM, FERMATA, diff --git a/python/setup.py b/python/setup.py index 150dcaeda93..e02e86223e7 100755 --- a/python/setup.py +++ b/python/setup.py @@ -22,7 +22,7 @@ verovio_module = Extension('_verovio', sources= - glob('../src/*.cpp') + + glob('../src/*.cpp') + glob('../src/hum/*.cpp') + [ '../src/json/jsonxx.cc', '../src/pugi/pugixml.cpp', @@ -31,7 +31,6 @@ '../src/midi/MidiEventList.cpp', '../src/midi/MidiFile.cpp', '../src/midi/MidiMessage.cpp', - '../src/hum/humlib.cpp', '../libmei/attconverter.cpp', '../libmei/atts_cmn.cpp', '../libmei/atts_cmnornaments.cpp', diff --git a/src/artic.cpp b/src/artic.cpp index 557a2df9e4f..8eb8534acd7 100644 --- a/src/artic.cpp +++ b/src/artic.cpp @@ -36,7 +36,6 @@ std::vector Artic::s_aboveStaffArtic Artic::Artic() : LayerElement("artic-"), AttArticulation(), AttColor(), AttPlacement() { - RegisterAttClass(ATT_ARTICULATION); RegisterAttClass(ATT_COLOR); RegisterAttClass(ATT_PLACEMENT); diff --git a/src/barline.cpp b/src/barline.cpp index 753a61b2631..1ff6d9a1676 100644 --- a/src/barline.cpp +++ b/src/barline.cpp @@ -41,7 +41,7 @@ void BarLine::Reset() ResetColor(); } -bool BarLine::SetAlignment(vrv::Alignment *alignment) +bool BarLine::SetAlignment(Alignment *alignment) { m_alignment = alignment; return (m_alignment->AddLayerElementRef(this)); diff --git a/src/beam.cpp b/src/beam.cpp index 9ec664b0fbe..4fa2a251544 100644 --- a/src/beam.cpp +++ b/src/beam.cpp @@ -303,8 +303,10 @@ void BeamDrawingParams::CalcBeam( // Beam //---------------------------------------------------------------------------- -Beam::Beam() : LayerElement("beam-"), ObjectListInterface() +Beam::Beam() : LayerElement("beam-"), ObjectListInterface(), AttColor() { + RegisterAttClass(ATT_COLOR); + Reset(); } @@ -316,6 +318,7 @@ Beam::~Beam() void Beam::Reset() { LayerElement::Reset(); + ResetColor(); ClearCoords(); } diff --git a/src/breath.cpp b/src/breath.cpp new file mode 100644 index 00000000000..2995e0f57b7 --- /dev/null +++ b/src/breath.cpp @@ -0,0 +1,49 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: breath.cpp +// Author: Klaus Rettinghaus +// Created: 2017 +// Copyright (c) Authors and others. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#include "breath.h" + +//---------------------------------------------------------------------------- + +#include + +//---------------------------------------------------------------------------- + +#include "verticalaligner.h" + +namespace vrv { + +//---------------------------------------------------------------------------- +// Breath +//---------------------------------------------------------------------------- + +Breath::Breath() : ControlElement("breath-"), TimePointInterface(), AttColor(), AttPlacement() +{ + RegisterInterface(TimePointInterface::GetAttClasses(), TimePointInterface::IsInterface()); + RegisterAttClass(ATT_COLOR); + RegisterAttClass(ATT_PLACEMENT); + + Reset(); +} + +Breath::~Breath() +{ +} + +void Breath::Reset() +{ + ControlElement::Reset(); + TimePointInterface::Reset(); + ResetColor(); + ResetPlacement(); +} + +//---------------------------------------------------------------------------- +// Breath functor methods +//---------------------------------------------------------------------------- + +} // namespace vrv diff --git a/src/chord.cpp b/src/chord.cpp index 900b008faf6..872d81ebfe6 100644 --- a/src/chord.cpp +++ b/src/chord.cpp @@ -359,9 +359,10 @@ int Chord::CalcStem(FunctorParams *functorParams) this->GetYExtremes(yMax, yMin); params->m_chordStemLength = yMin - yMax; - int staffY = staff->GetDrawingY(); int staffSize = staff->m_drawingStaffSize; - params->m_verticalCenter = staffY - params->m_doc->GetDrawingDoubleUnit(staffSize) * 2; + + params->m_verticalCenter + = staff->GetDrawingY() - params->m_doc->GetDrawingUnit(staffSize) * (staff->m_drawingLines - 1); data_STEMDIRECTION stemDir = STEMDIRECTION_NONE; diff --git a/src/clef.cpp b/src/clef.cpp index 4e253646601..9f4eca2373d 100644 --- a/src/clef.cpp +++ b/src/clef.cpp @@ -14,7 +14,7 @@ namespace vrv { // Clef //---------------------------------------------------------------------------- -Clef::Clef() : LayerElement("clef-"), AttClefshape(), AttLineloc(), AttOctavedisplacement() +Clef::Clef() : LayerElement("clef-"), AttClefshape(), AttColor(), AttLineloc(), AttOctavedisplacement() { Init(); } @@ -27,11 +27,13 @@ Clef::Clef(const ScoreDefInterface *clefAttr) : LayerElement("clef-") this->SetLine(clefAttr->GetClefLine()); this->SetDis(clefAttr->GetClefDis()); this->SetDisPlace(clefAttr->GetClefDisPlace()); + this->SetColor(clefAttr->GetClefColor()); } void Clef::Init() { RegisterAttClass(ATT_CLEFSHAPE); + RegisterAttClass(ATT_COLOR); RegisterAttClass(ATT_LINELOC); RegisterAttClass(ATT_OCTAVEDISPLACEMENT); @@ -46,6 +48,7 @@ void Clef::Reset() { LayerElement::Reset(); ResetClefshape(); + ResetColor(); ResetLineloc(); ResetOctavedisplacement(); } diff --git a/src/controlelement.cpp b/src/controlelement.cpp index ea9df11d168..5b366963c9b 100644 --- a/src/controlelement.cpp +++ b/src/controlelement.cpp @@ -21,9 +21,10 @@ namespace vrv { // ControlElement //---------------------------------------------------------------------------- -ControlElement::ControlElement() : FloatingObject("me"), AttCommon(), AttTyped() +ControlElement::ControlElement() : FloatingObject("me"), AttCommon(), AttCommonPart(), AttTyped() { RegisterAttClass(ATT_COMMON); + RegisterAttClass(ATT_COMMONPART); RegisterAttClass(ATT_TYPED); Reset(); @@ -32,6 +33,7 @@ ControlElement::ControlElement() : FloatingObject("me"), AttCommon(), AttTyped() ControlElement::ControlElement(std::string classid) : FloatingObject(classid), AttCommon(), AttTyped() { RegisterAttClass(ATT_COMMON); + RegisterAttClass(ATT_COMMONPART); RegisterAttClass(ATT_TYPED); Reset(); @@ -45,6 +47,7 @@ void ControlElement::Reset() { FloatingObject::Reset(); ResetCommon(); + ResetCommonPart(); ResetTyped(); } diff --git a/src/custos.cpp b/src/custos.cpp index 2c8f7483a1d..dd06430afbd 100644 --- a/src/custos.cpp +++ b/src/custos.cpp @@ -15,9 +15,10 @@ namespace vrv { // Custos //---------------------------------------------------------------------------- -Custos::Custos() : LayerElement("custos-"), PositionInterface() +Custos::Custos() : LayerElement("custos-"), PositionInterface(), AttColor() { RegisterInterface(PositionInterface::GetAttClasses(), PositionInterface::IsInterface()); + RegisterAttClass(ATT_COLOR); Reset(); } @@ -30,6 +31,7 @@ void Custos::Reset() { LayerElement::Reset(); PositionInterface::Reset(); + ResetColor(); } //---------------------------------------------------------------------------- diff --git a/src/dir.cpp b/src/dir.cpp index 34240b7300f..1f83a2f4c96 100644 --- a/src/dir.cpp +++ b/src/dir.cpp @@ -24,7 +24,7 @@ namespace vrv { // Dir //---------------------------------------------------------------------------- -Dir::Dir() : ControlElement("dir-"), TextListInterface(), TextDirInterface(), TimeSpanningInterface(), vrv::AttLang() +Dir::Dir() : ControlElement("dir-"), TextListInterface(), TextDirInterface(), TimeSpanningInterface(), AttLang() { RegisterInterface(TextDirInterface::GetAttClasses(), TextDirInterface::IsInterface()); RegisterInterface(TimeSpanningInterface::GetAttClasses(), TimeSpanningInterface::IsInterface()); diff --git a/src/editorial.cpp b/src/editorial.cpp index 69fbbd14d53..3ed7798a6db 100644 --- a/src/editorial.cpp +++ b/src/editorial.cpp @@ -40,7 +40,7 @@ EditorialElement::EditorialElement() : Object("ee-"), BoundaryStartInterface(), } EditorialElement::EditorialElement(std::string classid) - : Object(classid), vrv::BoundaryStartInterface(), AttCommon(), AttCommonPart(), AttTyped() + : Object(classid), BoundaryStartInterface(), AttCommon(), AttCommonPart(), AttTyped() { RegisterAttClass(ATT_COMMON); RegisterAttClass(ATT_COMMONPART); diff --git a/src/elementpart.cpp b/src/elementpart.cpp index 4a260b7377c..24d24c0af35 100644 --- a/src/elementpart.cpp +++ b/src/elementpart.cpp @@ -28,7 +28,7 @@ namespace vrv { // Dots //---------------------------------------------------------------------------- -Dots::Dots() : LayerElement("dots-"), vrv::AttAugmentdots() +Dots::Dots() : LayerElement("dots-"), AttAugmentdots() { RegisterAttClass(ATT_AUGMENTDOTS); diff --git a/src/horizontalaligner.cpp b/src/horizontalaligner.cpp index 1178cb0c220..da71c9b4529 100644 --- a/src/horizontalaligner.cpp +++ b/src/horizontalaligner.cpp @@ -58,7 +58,7 @@ Alignment *HorizontalAligner::SearchAlignmentAtTime(double time, AlignmentType t assert(alignment); double alignment_time = alignment->GetTime(); - if (vrv::AreEqual(alignment_time, time)) { + if (AreEqual(alignment_time, time)) { if (alignment->GetType() == type) { return alignment; } @@ -689,7 +689,7 @@ TimestampAttr *TimestampAligner::GetTimestampAtTime(double time) assert(timestampAttr); double alignmentTime = timestampAttr->GetActualDurPos(); - if (vrv::AreEqual(alignmentTime, time)) { + if (AreEqual(alignmentTime, time)) { return timestampAttr; } // nothing found, do not go any further but keep the index diff --git a/src/iomei.cpp b/src/iomei.cpp index 43b7b5909b0..6536513f8ad 100644 --- a/src/iomei.cpp +++ b/src/iomei.cpp @@ -1,4 +1,3 @@ - ///////////////////////////////////////////////////////////////////////////// // Name: iomei.cpp // Author: Laurent Pugin @@ -20,6 +19,7 @@ #include "artic.h" #include "beam.h" #include "boundary.h" +#include "breath.h" #include "chord.h" #include "clef.h" #include "custos.h" @@ -241,6 +241,10 @@ bool MeiOutput::WriteObject(Object *object) m_currentNode = m_currentNode.append_child("anchoredText"); WriteMeiAnchoredText(m_currentNode, dynamic_cast(object)); } + else if (object->Is(BREATH)) { + m_currentNode = m_currentNode.append_child("breath"); + WriteMeiBreath(m_currentNode, dynamic_cast(object)); + } else if (object->Is(DIR)) { m_currentNode = m_currentNode.append_child("dir"); WriteMeiDir(m_currentNode, dynamic_cast(object)); @@ -690,7 +694,6 @@ void MeiOutput::WriteMeiPb(pugi::xml_node currentNode, Pb *pb) assert(pb); WriteSystemElement(currentNode, pb); - pb->WriteCommonPart(currentNode); } void MeiOutput::WriteMeiSb(pugi::xml_node currentNode, Sb *sb) @@ -698,7 +701,6 @@ void MeiOutput::WriteMeiSb(pugi::xml_node currentNode, Sb *sb) assert(sb); WriteSystemElement(currentNode, sb); - sb->WriteCommonPart(currentNode); } void MeiOutput::WriteScoreDefElement(pugi::xml_node currentNode, ScoreDefElement *scoreDefElement) @@ -775,6 +777,7 @@ void MeiOutput::WriteControlElement(pugi::xml_node currentNode, ControlElement * WriteXmlId(currentNode, controlElement); controlElement->WriteCommon(currentNode); + controlElement->WriteCommonPart(currentNode); controlElement->WriteTyped(currentNode); } @@ -786,6 +789,16 @@ void MeiOutput::WriteMeiAnchoredText(pugi::xml_node currentNode, AnchoredText *a WriteTextDirInterface(currentNode, anchoredText); } +void MeiOutput::WriteMeiBreath(pugi::xml_node currentNode, Breath *breath) +{ + assert(breath); + + WriteControlElement(currentNode, breath); + WriteTimePointInterface(currentNode, breath); + breath->WriteColor(currentNode); + breath->WritePlacement(currentNode); +}; + void MeiOutput::WriteMeiDir(pugi::xml_node currentNode, Dir *dir) { assert(dir); @@ -844,6 +857,7 @@ void MeiOutput::WriteMeiMordent(pugi::xml_node currentNode, Mordent *mordent) WriteControlElement(currentNode, mordent); WriteTimePointInterface(currentNode, mordent); mordent->WriteColor(currentNode); + mordent->WriteCommon(currentNode); mordent->WriteOrnamentaccid(currentNode); mordent->WritePlacement(currentNode); mordent->WriteMordentLog(currentNode); @@ -867,6 +881,7 @@ void MeiOutput::WriteMeiPedal(pugi::xml_node currentNode, Pedal *pedal) WriteControlElement(currentNode, pedal); WriteTimePointInterface(currentNode, pedal); pedal->WriteColor(currentNode); + pedal->WriteCommon(currentNode); pedal->WritePedalLog(currentNode); pedal->WritePlacement(currentNode); }; @@ -923,6 +938,7 @@ void MeiOutput::WriteMeiTrill(pugi::xml_node currentNode, Trill *trill) WriteControlElement(currentNode, trill); WriteTimePointInterface(currentNode, trill); trill->WriteColor(currentNode); + trill->WriteCommon(currentNode); trill->WriteOrnamentaccid(currentNode); trill->WritePlacement(currentNode); }; @@ -954,6 +970,7 @@ void MeiOutput::WriteLayerElement(pugi::xml_node currentNode, LayerElement *elem WriteXmlId(currentNode, element); element->WriteCommon(currentNode); + element->WriteCommonPart(currentNode); element->WriteTyped(currentNode); if (element->m_xAbs != VRV_UNSET) { currentNode.append_attribute("ulx") = StringFormat("%d", element->m_xAbs / DEFINITION_FACTOR).c_str(); @@ -1010,6 +1027,7 @@ void MeiOutput::WriteMeiBeam(pugi::xml_node currentNode, Beam *beam) assert(beam); WriteLayerElement(currentNode, beam); + beam->WriteColor(currentNode); } void MeiOutput::WriteMeiBeatRpt(pugi::xml_node currentNode, BeatRpt *beatRpt) @@ -1050,6 +1068,7 @@ void MeiOutput::WriteMeiClef(pugi::xml_node currentNode, Clef *clef) WriteLayerElement(currentNode, clef); clef->WriteClefshape(currentNode); + clef->WriteColor(currentNode); clef->WriteLineloc(currentNode); clef->WriteOctavedisplacement(currentNode); } @@ -1060,6 +1079,7 @@ void MeiOutput::WriteMeiCustos(pugi::xml_node currentNode, Custos *custos) WriteLayerElement(currentNode, custos); WritePositionInterface(currentNode, custos); + custos->WriteColor(currentNode); } void MeiOutput::WriteMeiDot(pugi::xml_node currentNode, Dot *dot) @@ -1095,6 +1115,7 @@ void MeiOutput::WriteMeiMensur(pugi::xml_node currentNode, Mensur *mensur) assert(mensur); WriteLayerElement(currentNode, mensur); + mensur->WriteColor(currentNode); mensur->WriteDurationRatio(currentNode); mensur->WriteMensuralShared(currentNode); mensur->WriteMensurLog(currentNode); @@ -1109,6 +1130,7 @@ void MeiOutput::WriteMeiMeterSig(pugi::xml_node currentNode, MeterSig *meterSig) WriteLayerElement(currentNode, meterSig); meterSig->WriteMeterSigLog(currentNode); + meterSig->WriteMeterSigVis(currentNode); } void MeiOutput::WriteMeiMRest(pugi::xml_node currentNode, MRest *mRest) @@ -1117,9 +1139,9 @@ void MeiOutput::WriteMeiMRest(pugi::xml_node currentNode, MRest *mRest) WriteLayerElement(currentNode, mRest); WritePositionInterface(currentNode, mRest); - mRest->WriteVisibility(currentNode); mRest->WriteFermatapresent(currentNode); mRest->WriteRelativesize(currentNode); + mRest->WriteVisibility(currentNode); } void MeiOutput::WriteMeiMRpt(pugi::xml_node currentNode, MRpt *mRpt) @@ -1141,6 +1163,7 @@ void MeiOutput::WriteMeiMultiRest(pugi::xml_node currentNode, MultiRest *multiRe assert(multiRest); WriteLayerElement(currentNode, multiRest); + multiRest->WriteMultiRestVis(currentNode); multiRest->WriteNumbered(currentNode); } @@ -1159,6 +1182,7 @@ void MeiOutput::WriteMeiNote(pugi::xml_node currentNode, Note *note) WriteLayerElement(currentNode, note); WriteDurationInterface(currentNode, note); WritePitchInterface(currentNode, note); + WritePositionInterface(currentNode, note); note->WriteColor(currentNode); note->WriteColoration(currentNode); note->WriteGraced(currentNode); @@ -1202,6 +1226,7 @@ void MeiOutput::WriteMeiTuplet(pugi::xml_node currentNode, Tuplet *tuplet) assert(tuplet); WriteLayerElement(currentNode, tuplet); + tuplet->WriteColor(currentNode); tuplet->WriteDurationRatio(currentNode); tuplet->WriteNumberplacement(currentNode); tuplet->WriteTupletVis(currentNode); @@ -1265,7 +1290,7 @@ void MeiOutput::WriteMeiText(pugi::xml_node element, Text *text) } } -void MeiOutput::WriteDurationInterface(pugi::xml_node element, vrv::DurationInterface *interface) +void MeiOutput::WriteDurationInterface(pugi::xml_node element, DurationInterface *interface) { assert(interface); @@ -1300,6 +1325,7 @@ void MeiOutput::WriteScoreDefInterface(pugi::xml_node element, ScoreDefInterface assert(interface); interface->WriteCleffingLog(element); + interface->WriteCleffingVis(element); interface->WriteKeySigDefaultLog(element); interface->WriteKeySigDefaultVis(element); interface->WriteLyricstyle(element); @@ -1747,6 +1773,9 @@ bool MeiInput::IsAllowed(std::string element, Object *filterParent) else if (element == "space") { return true; } + else if (element == "tuplet") { + return true; + } else { return false; } @@ -1760,6 +1789,15 @@ bool MeiInput::IsAllowed(std::string element, Object *filterParent) return false; } } + // filter for syl + else if (filterParent->Is(SYL)) { + if (element == "") { + return true; + } + else { + return false; + } + } else { LogDebug("Unknow filter for '%s'", filterParent->GetClassName().c_str()); return true; @@ -1978,8 +2016,6 @@ bool MeiInput::ReadMeiPb(Object *parent, pugi::xml_node pb) Pb *vrvPb = new Pb(); ReadSystemElement(pb, vrvPb); - vrvPb->ReadCommonPart(pb); - parent->AddChild(vrvPb); return true; } @@ -1989,8 +2025,6 @@ bool MeiInput::ReadMeiSb(Object *parent, pugi::xml_node sb) Sb *vrvSb = new Sb(); ReadSystemElement(sb, vrvSb); - vrvSb->ReadCommonPart(sb); - parent->AddChild(vrvSb); return true; } @@ -2333,6 +2367,9 @@ bool MeiInput::ReadMeiMeasureChildren(Object *parent, pugi::xml_node parentNode) else if (std::string(current.name()) == "anchoredText") { success = ReadMeiAnchoredText(parent, current); } + else if (std::string(current.name()) == "breath") { + success = ReadMeiBreath(parent, current); + } else if (std::string(current.name()) == "dir") { success = ReadMeiDir(parent, current); } @@ -2391,6 +2428,7 @@ bool MeiInput::ReadControlElement(pugi::xml_node element, ControlElement *object { SetMeiUuid(element, object); object->ReadCommon(element); + object->ReadCommonPart(element); object->ReadTyped(element); return true; @@ -2407,6 +2445,19 @@ bool MeiInput::ReadMeiAnchoredText(Object *parent, pugi::xml_node anchoredText) return ReadMeiTextChildren(vrvAnchoredText, anchoredText, vrvAnchoredText); } +bool MeiInput::ReadMeiBreath(Object *parent, pugi::xml_node breath) +{ + Breath *vrvBreath = new Breath(); + ReadControlElement(breath, vrvBreath); + + ReadTimePointInterface(breath, vrvBreath); + vrvBreath->ReadColor(breath); + vrvBreath->ReadPlacement(breath); + + parent->AddChild(vrvBreath); + return ReadMeiTextChildren(vrvBreath, breath, vrvBreath); +} + bool MeiInput::ReadMeiDir(Object *parent, pugi::xml_node dir) { Dir *vrvDir = new Dir(); @@ -2508,9 +2559,9 @@ bool MeiInput::ReadMeiPedal(Object *parent, pugi::xml_node pedal) ReadControlElement(pedal, vrvPedal); ReadTimePointInterface(pedal, vrvPedal); + vrvPedal->ReadColor(pedal); vrvPedal->ReadPedalLog(pedal); vrvPedal->ReadPlacement(pedal); - vrvPedal->ReadColor(pedal); parent->AddChild(vrvPedal); return true; @@ -2800,6 +2851,7 @@ bool MeiInput::ReadLayerElement(pugi::xml_node element, LayerElement *object) SetMeiUuid(element, object); object->ReadCommon(element); + object->ReadCommonPart(element); object->ReadTyped(element); return true; @@ -2851,6 +2903,8 @@ bool MeiInput::ReadMeiBeam(Object *parent, pugi::xml_node beam) Beam *vrvBeam = new Beam(); ReadLayerElement(beam, vrvBeam); + vrvBeam->ReadColor(beam); + parent->AddChild(vrvBeam); return ReadMeiLayerChildren(vrvBeam, beam, vrvBeam); @@ -2912,6 +2966,7 @@ bool MeiInput::ReadMeiClef(Object *parent, pugi::xml_node clef) ReadLayerElement(clef, vrvClef); vrvClef->ReadClefshape(clef); + vrvClef->ReadColor(clef); vrvClef->ReadLineloc(clef); vrvClef->ReadOctavedisplacement(clef); @@ -2926,6 +2981,8 @@ bool MeiInput::ReadMeiCustos(Object *parent, pugi::xml_node custos) ReadPositionInterface(custos, vrvCustos); + vrvCustos->ReadColor(custos); + parent->AddChild(vrvCustos); return true; } @@ -2989,6 +3046,7 @@ bool MeiInput::ReadMeiMensur(Object *parent, pugi::xml_node mensur) Mensur *vrvMensur = new Mensur(); ReadLayerElement(mensur, vrvMensur); + vrvMensur->ReadColor(mensur); vrvMensur->ReadDurationRatio(mensur); vrvMensur->ReadMensuralShared(mensur); vrvMensur->ReadMensurLog(mensur); @@ -3006,6 +3064,7 @@ bool MeiInput::ReadMeiMeterSig(Object *parent, pugi::xml_node meterSig) ReadLayerElement(meterSig, vrvMeterSig); vrvMeterSig->ReadMeterSigLog(meterSig); + vrvMeterSig->ReadMeterSigVis(meterSig); parent->AddChild(vrvMeterSig); return true; @@ -3017,9 +3076,9 @@ bool MeiInput::ReadMeiMRest(Object *parent, pugi::xml_node mRest) ReadLayerElement(mRest, vrvMRest); ReadPositionInterface(mRest, vrvMRest); - vrvMRest->ReadVisibility(mRest); vrvMRest->ReadFermatapresent(mRest); vrvMRest->ReadRelativesize(mRest); + vrvMRest->ReadVisibility(mRest); parent->AddChild(vrvMRest); return true; @@ -3048,6 +3107,7 @@ bool MeiInput::ReadMeiMultiRest(Object *parent, pugi::xml_node multiRest) MultiRest *vrvMultiRest = new MultiRest(); ReadLayerElement(multiRest, vrvMultiRest); + vrvMultiRest->ReadMultiRestVis(multiRest); vrvMultiRest->ReadNumbered(multiRest); parent->AddChild(vrvMultiRest); @@ -3072,6 +3132,7 @@ bool MeiInput::ReadMeiNote(Object *parent, pugi::xml_node note) ReadDurationInterface(note, vrvNote); ReadPitchInterface(note, vrvNote); + ReadPositionInterface(note, vrvNote); vrvNote->ReadColor(note); vrvNote->ReadColoration(note); vrvNote->ReadGraced(note); @@ -3162,6 +3223,7 @@ bool MeiInput::ReadMeiTuplet(Object *parent, pugi::xml_node tuplet) Tuplet *vrvTuplet = new Tuplet(); ReadLayerElement(tuplet, vrvTuplet); + vrvTuplet->ReadColor(tuplet); vrvTuplet->ReadDurationRatio(tuplet); vrvTuplet->ReadNumberplacement(tuplet); vrvTuplet->ReadTupletVis(tuplet); @@ -3305,6 +3367,7 @@ bool MeiInput::ReadPositionInterface(pugi::xml_node element, PositionInterface * bool MeiInput::ReadScoreDefInterface(pugi::xml_node element, ScoreDefInterface *interface) { interface->ReadCleffingLog(element); + interface->ReadCleffingVis(element); interface->ReadKeySigDefaultLog(element); interface->ReadKeySigDefaultVis(element); interface->ReadLyricstyle(element); @@ -3832,6 +3895,11 @@ bool MeiInput::ReadTupletSpanAsTuplet(Measure *measure, pugi::xml_node tupletSpa LayerElement *start = NULL; LayerElement *end = NULL; + // label + if (tupletSpan.attribute("label")) { + tuplet->SetLabel(tupletSpan.attribute("label").value()); + } + // Read in the numerator and denominator properties if (tupletSpan.attribute("num")) { tuplet->SetNum(atoi(tupletSpan.attribute("num").value())); diff --git a/src/iomusxml.cpp b/src/iomusxml.cpp index 081ce711228..fe8348513d6 100644 --- a/src/iomusxml.cpp +++ b/src/iomusxml.cpp @@ -21,6 +21,7 @@ #include "dir.h" #include "doc.h" #include "dynam.h" +#include "fb.h" #include "fermata.h" #include "hairpin.h" #include "harm.h" @@ -176,7 +177,8 @@ void MusicXmlInput::AddMeasure(Section *section, Measure *measure, int i) } // otherwise copy the content to the corresponding existing measure else if (section->GetChildCount(MEASURE) > i) { - Measure *existingMeasure = dynamic_cast(section->GetChild(i)); + AttCommonNComparison comparisonMeasure(MEASURE, measure->GetN()); + Measure *existingMeasure = dynamic_cast(section->FindChildByAttComparison(&comparisonMeasure, 1)); assert(existingMeasure); Object *current; for (current = measure->GetFirst(); current; current = measure->GetNext()) { @@ -203,7 +205,7 @@ void MusicXmlInput::AddLayerElement(Layer *layer, LayerElement *element) (m_elementStack.back()->AddChild(element)); } -Layer *MusicXmlInput::SelectLayer(pugi::xml_node node, vrv::Measure *measure) +Layer *MusicXmlInput::SelectLayer(pugi::xml_node node, Measure *measure) { int staffNum = 1; std::string staffNumStr = GetContentOfChild(node, "staff"); @@ -230,7 +232,7 @@ Layer *MusicXmlInput::SelectLayer(pugi::xml_node node, vrv::Measure *measure) return SelectLayer(layerNum, staff); } -Layer *MusicXmlInput::SelectLayer(int staffNum, vrv::Measure *measure) +Layer *MusicXmlInput::SelectLayer(int staffNum, Measure *measure) { staffNum--; Staff *staff = dynamic_cast(measure->GetChild(staffNum)); @@ -274,7 +276,7 @@ void MusicXmlInput::RemoveLastFromStack(ClassId classId) } } -void MusicXmlInput::FillSpace(vrv::Layer *layer, int dur) +void MusicXmlInput::FillSpace(Layer *layer, int dur) { std::string durStr; while (dur != 0) { @@ -735,8 +737,8 @@ int MusicXmlInput::ReadMusicXmlPartAttributesAsStaffDef(pugi::xml_node node, Sta } pugi::xpath_node beatType = time.node().select_single_node("beat-type"); if (beatType && HasContent(beatType.node())) { - staffDef->SetMeterUnit( - staffDef->AttMeterSigDefaultLog::StrToInt(beatType.node().text().as_string())); + m_meterUnit = beatType.node().text().as_int(); + staffDef->SetMeterUnit(m_meterUnit); } } // transpose @@ -774,7 +776,7 @@ bool MusicXmlInput::ReadMusicXmlPart(pugi::xml_node node, Section *section, int for (pugi::xpath_node_set::const_iterator it = measures.begin(); it != measures.end(); ++it) { pugi::xpath_node xmlMeasure = *it; Measure *measure = new Measure(); - ReadMusicXmlMeasure(xmlMeasure.node(), measure, nbStaves, staffOffset); + ReadMusicXmlMeasure(xmlMeasure.node(), section, measure, nbStaves, staffOffset); // Add the measure to the system - if already there from a previous part we'll just merge the content AddMeasure(section, measure, i); i++; @@ -782,7 +784,8 @@ bool MusicXmlInput::ReadMusicXmlPart(pugi::xml_node node, Section *section, int return false; } -bool MusicXmlInput::ReadMusicXmlMeasure(pugi::xml_node node, Measure *measure, int nbStaves, int staffOffset) +bool MusicXmlInput::ReadMusicXmlMeasure( + pugi::xml_node node, Section *section, Measure *measure, int nbStaves, int staffOffset) { assert(node); assert(measure); @@ -810,7 +813,7 @@ bool MusicXmlInput::ReadMusicXmlMeasure(pugi::xml_node node, Measure *measure, i // read the content of the measure for (pugi::xml_node::iterator it = node.begin(); it != node.end(); ++it) { if (IsElement(*it, "attributes")) { - ReadMusicXmlAttributes(*it, measure, measureNum); + ReadMusicXmlAttributes(*it, section, measure, measureNum); } else if (IsElement(*it, "backup")) { ReadMusicXmlBackup(*it, measure, measureNum); @@ -821,6 +824,9 @@ bool MusicXmlInput::ReadMusicXmlMeasure(pugi::xml_node node, Measure *measure, i else if (IsElement(*it, "direction")) { ReadMusicXmlDirection(*it, measure, measureNum); } + else if (IsElement(*it, "figured-bass")) { + ReadMusicXmlFigures(*it, measure, measureNum); + } else if (IsElement(*it, "forward")) { ReadMusicXmlForward(*it, measure, measureNum); } @@ -830,16 +836,21 @@ bool MusicXmlInput::ReadMusicXmlMeasure(pugi::xml_node node, Measure *measure, i else if (IsElement(*it, "note")) { ReadMusicXmlNote(*it, measure, measureNum); } - else if (IsElement(*it, "print")) { - ReadMusicXmlPrint(*it, measure, measureNum); + // for now only check first part + else if (IsElement(*it, "print") && node.select_single_node("parent::part[not(preceding-sibling::part)]")) { + ReadMusicXmlPrint(*it, section); } } return true; } -void MusicXmlInput::ReadMusicXmlAttributes(pugi::xml_node node, Measure *measure, int measureNum) +void MusicXmlInput::ReadMusicXmlAttributes(pugi::xml_node node, Section *section, Measure *measure, int measureNum) { + assert(node); + assert(section); + assert(measure); + // read clef changes as MEI clef pugi::xpath_node clef = node.select_single_node("clef"); if (clef) { @@ -870,6 +881,64 @@ void MusicXmlInput::ReadMusicXmlAttributes(pugi::xml_node node, Measure *measure } } + // key and time change + pugi::xpath_node key = node.select_single_node("key"); + pugi::xpath_node time = node.select_single_node("time"); + // for now only read first part and make it change in scoreDef + if ((key || time) && node.select_single_node("ancestor::part[not(preceding-sibling::part)]")) { + ScoreDef *scoreDef = new ScoreDef(); + if (key.node().select_single_node("fifths")) { + int fifths = atoi(key.node().select_single_node("fifths").node().text().as_string()); + std::string keySig; + if (fifths < 0) + keySig = StringFormat("%df", abs(fifths)); + else if (fifths > 0) + keySig = StringFormat("%ds", fifths); + else + keySig = "0"; + scoreDef->SetKeySig(scoreDef->AttKeySigDefaultLog::StrToKeysignature(keySig)); + } + else if (key.node().select_single_node("key-step")) { + scoreDef->SetKeySig(KEYSIGNATURE_mixed); + } + if (key.node().select_single_node("mode")) { + scoreDef->SetKeyMode(scoreDef->AttKeySigDefaultLog::StrToMode( + key.node().select_single_node("mode").node().text().as_string())); + } + if (time) { + std::string symbol = GetAttributeValue(time.node(), "symbol"); + if (!symbol.empty()) { + if (symbol == "cut" || symbol == "common") + scoreDef->SetMeterSym(scoreDef->AttMeterSigDefaultVis::StrToMetersign(symbol.c_str())); + else if (symbol == "single-number") + scoreDef->SetMeterRend(meterSigDefaultVis_METERREND_num); + else + scoreDef->SetMeterRend(meterSigDefaultVis_METERREND_norm); + } + if (time.node().select_nodes("beats").size() > 1) { + LogWarning("Compound meter signatures are not supported"); + } + pugi::xpath_node beats = time.node().select_single_node("beats"); + if (beats && HasContent(beats.node())) { + m_meterCount = beats.node().text().as_int(); + // staffDef->AttMeterSigDefaultLog::StrToInt(beats.node().text().as_string()); + // this is a little "hack", until libMEI is fixed + std::string compound = beats.node().text().as_string(); + if (compound.find("+") != std::string::npos) { + m_meterCount += atoi(compound.substr(compound.find("+")).c_str()); + LogWarning("Compound time is not supported"); + } + scoreDef->SetMeterCount(m_meterCount); + } + pugi::xpath_node beatType = time.node().select_single_node("beat-type"); + if (beatType && HasContent(beatType.node())) { + m_meterUnit = beatType.node().text().as_int(); + scoreDef->SetMeterUnit(m_meterUnit); + } + } + section->AddChild(scoreDef); + } + pugi::xpath_node measureRepeat = node.select_single_node("measure-style/measure-repeat"); if (measureRepeat) { if (GetAttributeValue(measureRepeat.node(), "type") == "start") @@ -1097,6 +1166,31 @@ void MusicXmlInput::ReadMusicXmlDirection(pugi::xml_node node, Measure *measure, } } +void MusicXmlInput::ReadMusicXmlFigures(pugi::xml_node node, Measure *measure, int measureNum) +{ + assert(node); + assert(measure); + + if (GetAttributeValue(node, "print-object") != "no") { + Harm *harm = new Harm(); + Fb *fb = new Fb(); + + std::string textColor = GetAttributeValue(node, "color"); + std::string textStyle = GetAttributeValue(node, "font-style"); + std::string textWeight = GetAttributeValue(node, "font-weight"); + for (pugi::xml_node figure = node.child("figure"); figure; figure = figure.next_sibling("figure")) { + std::string textStr = GetContent(figure.select_single_node("figure-number").node()); + F *f = new F(); + Text *text = new Text(); + text->SetText(UTF8to16(textStr)); + f->AddChild(text); + fb->AddChild(f); + } + harm->AddChild(fb); + measure->AddChild(harm); + } +} + void MusicXmlInput::ReadMusicXmlForward(pugi::xml_node node, Measure *measure, int measureNum) { assert(node); @@ -1316,11 +1410,12 @@ void MusicXmlInput::ReadMusicXmlNote(pugi::xml_node node, Measure *measure, int note->SetOct(atoi(octaveStr.c_str())); } std::string alterStr = GetContentOfChild(pitch.node(), "alter"); - if (!accidental && !alterStr.empty()) { + if (!alterStr.empty()) { Accid *accid = dynamic_cast(note->GetFirst(ACCID)); if (!accid) { accid = new Accid(); note->AddChild(accid); + accid->IsAttribute(true); } accid->SetAccidGes(ConvertAlterToAccid(std::atof(alterStr.c_str()))); } @@ -1727,19 +1822,19 @@ void MusicXmlInput::ReadMusicXmlNote(pugi::xml_node node, Measure *measure, int } } -void MusicXmlInput::ReadMusicXmlPrint(pugi::xml_node node, Measure *measure, int measureNum) +void MusicXmlInput::ReadMusicXmlPrint(pugi::xml_node node, Section *section) { assert(node); - assert(measure); + assert(section); if (HasAttributeWithValue(node, "new-system", "yes")) { - // LogWarning("System breaks not supported"); - // enter system break + Sb *sb = new Sb(); + section->AddChild(sb); } if (HasAttributeWithValue(node, "new-page", "yes")) { - // LogWarning("Page breaks not supported"); - // enter system break + Pb *pb = new Pb(); + section->AddChild(pb); } } @@ -1748,35 +1843,60 @@ void MusicXmlInput::ReadMusicXmlPrint(pugi::xml_node node, Measure *measure, int data_ACCIDENTAL_EXPLICIT MusicXmlInput::ConvertAccidentalToAccid(std::string value) { - if (value == "sharp") return ACCIDENTAL_EXPLICIT_s; - if (value == "natural") return ACCIDENTAL_EXPLICIT_n; - if (value == "flat") return ACCIDENTAL_EXPLICIT_f; - if (value == "double-sharp") return ACCIDENTAL_EXPLICIT_x; - if (value == "sharp-sharp") return ACCIDENTAL_EXPLICIT_ss; - if (value == "flat-flat") return ACCIDENTAL_EXPLICIT_ff; - if (value == "natural-sharp") return ACCIDENTAL_EXPLICIT_ns; - if (value == "natural-flat") return ACCIDENTAL_EXPLICIT_nf; - if (value == "quarter-flat") return ACCIDENTAL_EXPLICIT_1qf; - if (value == "quarter-sharp") return ACCIDENTAL_EXPLICIT_1qs; - if (value == "three-quarters-flat") return ACCIDENTAL_EXPLICIT_3qf; - if (value == "three-quarters-sharp") return ACCIDENTAL_EXPLICIT_3qs; - LogWarning("Unsupported accidental value '%s'", value.c_str()); - return ACCIDENTAL_EXPLICIT_NONE; + if (value == "sharp") + return ACCIDENTAL_EXPLICIT_s; + else if (value == "natural") + return ACCIDENTAL_EXPLICIT_n; + else if (value == "flat") + return ACCIDENTAL_EXPLICIT_f; + else if (value == "double-sharp") + return ACCIDENTAL_EXPLICIT_x; + else if (value == "sharp-sharp") + return ACCIDENTAL_EXPLICIT_ss; + else if (value == "flat-flat") + return ACCIDENTAL_EXPLICIT_ff; + else if (value == "natural-sharp") + return ACCIDENTAL_EXPLICIT_ns; + else if (value == "natural-flat") + return ACCIDENTAL_EXPLICIT_nf; + else if (value == "quarter-flat") + return ACCIDENTAL_EXPLICIT_1qf; + else if (value == "quarter-sharp") + return ACCIDENTAL_EXPLICIT_1qs; + else if (value == "three-quarters-flat") + return ACCIDENTAL_EXPLICIT_3qf; + else if (value == "three-quarters-sharp") + return ACCIDENTAL_EXPLICIT_3qs; + else { + LogWarning("Unsupported accidental value '%s'", value.c_str()); + return ACCIDENTAL_EXPLICIT_NONE; + } } data_ACCIDENTAL_IMPLICIT MusicXmlInput::ConvertAlterToAccid(float value) { - if (value == -2) return ACCIDENTAL_IMPLICIT_ff; - if (value == -1.5) return ACCIDENTAL_IMPLICIT_fd; - if (value == -1) return ACCIDENTAL_IMPLICIT_f; - if (value == -0.5) return ACCIDENTAL_IMPLICIT_fu; - if (value == 0) return ACCIDENTAL_IMPLICIT_n; - if (value == 0.5) return ACCIDENTAL_IMPLICIT_sd; - if (value == 1) return ACCIDENTAL_IMPLICIT_s; - if (value == 1.5) return ACCIDENTAL_IMPLICIT_su; - if (value == 2) return ACCIDENTAL_IMPLICIT_ss; - LogWarning("Unsupported alter value '%d'", value); - return ACCIDENTAL_IMPLICIT_NONE; + if (value == -2) + return ACCIDENTAL_IMPLICIT_ff; + else if (value == -1.5) + return ACCIDENTAL_IMPLICIT_fd; + else if (value == -1) + return ACCIDENTAL_IMPLICIT_f; + else if (value == -0.5) + return ACCIDENTAL_IMPLICIT_fu; + else if (value == 0) + return ACCIDENTAL_IMPLICIT_n; + else if (value == 0.5) + return ACCIDENTAL_IMPLICIT_sd; + else if (value == 1) + return ACCIDENTAL_IMPLICIT_s; + else if (value == 1.5) + return ACCIDENTAL_IMPLICIT_su; + else if (value == 2) + return ACCIDENTAL_IMPLICIT_ss; + else { + LogWarning("Unsupported alter value '%d'", value); + return ACCIDENTAL_IMPLICIT_NONE; + } } data_BARRENDITION MusicXmlInput::ConvertStyleToRend(std::string value, bool repeat) @@ -1798,70 +1918,110 @@ data_BARRENDITION MusicXmlInput::ConvertStyleToRend(std::string value, bool repe data_BOOLEAN MusicXmlInput::ConvertWordToBool(std::string value) { - if (value == "yes") return BOOLEAN_true; - if (value == "no") return BOOLEAN_false; - return BOOLEAN_NONE; + if (value == "yes") + return BOOLEAN_true; + else if (value == "no") + return BOOLEAN_false; + else + return BOOLEAN_NONE; } data_DURATION MusicXmlInput::ConvertTypeToDur(std::string value) { - if (value == "maxima") return DURATION_maxima; // this is a mensural MEI value - if (value == "long") return DURATION_long; // mensural MEI value longa isn't supported - if (value == "breve") return DURATION_breve; - if (value == "whole") return DURATION_1; - if (value == "half") return DURATION_2; - if (value == "quarter") return DURATION_4; - if (value == "eighth") return DURATION_8; - if (value == "16th") return DURATION_16; - if (value == "32nd") return DURATION_32; - if (value == "64th") return DURATION_64; - if (value == "128th") return DURATION_128; - if (value == "256th") return DURATION_256; - LogWarning("Unsupported type '%s'", value.c_str()); - return DURATION_NONE; + if (value == "maxima") + return DURATION_maxima; // this is a mensural MEI value + else if (value == "long") + return DURATION_long; // mensural MEI value longa isn't supported + else if (value == "breve") + return DURATION_breve; + else if (value == "whole") + return DURATION_1; + else if (value == "half") + return DURATION_2; + else if (value == "quarter") + return DURATION_4; + else if (value == "eighth") + return DURATION_8; + else if (value == "16th") + return DURATION_16; + else if (value == "32nd") + return DURATION_32; + else if (value == "64th") + return DURATION_64; + else if (value == "128th") + return DURATION_128; + else if (value == "256th") + return DURATION_256; + else { + LogWarning("Unsupported type '%s'", value.c_str()); + return DURATION_NONE; + } } data_PITCHNAME MusicXmlInput::ConvertStepToPitchName(std::string value) { - if (value == "C") return PITCHNAME_c; - if (value == "D") return PITCHNAME_d; - if (value == "E") return PITCHNAME_e; - if (value == "F") return PITCHNAME_f; - if (value == "G") return PITCHNAME_g; - if (value == "A") return PITCHNAME_a; - if (value == "B") return PITCHNAME_b; - LogWarning("Unsupported pitch name '%s'", value.c_str()); - return PITCHNAME_NONE; + if (value == "C") + return PITCHNAME_c; + else if (value == "D") + return PITCHNAME_d; + else if (value == "E") + return PITCHNAME_e; + else if (value == "F") + return PITCHNAME_f; + else if (value == "G") + return PITCHNAME_g; + else if (value == "A") + return PITCHNAME_a; + else if (value == "B") + return PITCHNAME_b; + else { + LogWarning("Unsupported pitch name '%s'", value.c_str()); + return PITCHNAME_NONE; + } } curvature_CURVEDIR MusicXmlInput::ConvertOrientationToCurvedir(std::string value) { - if (value == "over") return curvature_CURVEDIR_above; - if (value == "under") return curvature_CURVEDIR_below; - return curvature_CURVEDIR_NONE; + if (value == "over") + return curvature_CURVEDIR_above; + else if (value == "under") + return curvature_CURVEDIR_below; + else + return curvature_CURVEDIR_NONE; } fermataVis_SHAPE MusicXmlInput::ConvertFermataShape(std::string value) { - if (value == "normal") return fermataVis_SHAPE_curved; - if (value == "angled") return fermataVis_SHAPE_angular; - if (value == "square") return fermataVis_SHAPE_square; - return fermataVis_SHAPE_NONE; + if (value == "normal") + return fermataVis_SHAPE_curved; + else if (value == "angled") + return fermataVis_SHAPE_angular; + else if (value == "square") + return fermataVis_SHAPE_square; + else + return fermataVis_SHAPE_NONE; } pedalLog_DIR MusicXmlInput::ConvertPedalTypeToDir(std::string value) { - if (value == "start") return pedalLog_DIR_down; - if (value == "stop") return pedalLog_DIR_up; - LogWarning("Unsupported type '%s' for pedal", value.c_str()); - return pedalLog_DIR_NONE; + if (value == "start") + return pedalLog_DIR_down; + else if (value == "stop") + return pedalLog_DIR_up; + else { + LogWarning("Unsupported type '%s' for pedal", value.c_str()); + return pedalLog_DIR_NONE; + } } tupletVis_NUMFORMAT MusicXmlInput::ConvertTupletNumberValue(std::string value) { - if (value == "actual") return tupletVis_NUMFORMAT_count; - if (value == "both") return tupletVis_NUMFORMAT_ratio; - return tupletVis_NUMFORMAT_NONE; + if (value == "actual") + return tupletVis_NUMFORMAT_count; + else if (value == "both") + return tupletVis_NUMFORMAT_ratio; + else + return tupletVis_NUMFORMAT_NONE; } } // namespace vrv diff --git a/src/layerelement.cpp b/src/layerelement.cpp index 60b3aa1874b..e72454e48a6 100644 --- a/src/layerelement.cpp +++ b/src/layerelement.cpp @@ -55,9 +55,10 @@ namespace vrv { // LayerElement //---------------------------------------------------------------------------- -LayerElement::LayerElement() : Object("le-"), AttCommon(), AttTyped() +LayerElement::LayerElement() : Object("le-"), AttCommon(), AttCommonPart(), AttTyped() { RegisterAttClass(ATT_COMMON); + RegisterAttClass(ATT_COMMONPART); RegisterAttClass(ATT_TYPED); Reset(); @@ -66,6 +67,7 @@ LayerElement::LayerElement() : Object("le-"), AttCommon(), AttTyped() LayerElement::LayerElement(std::string classid) : Object(classid), AttCommon(), AttTyped() { RegisterAttClass(ATT_COMMON); + RegisterAttClass(ATT_COMMONPART); RegisterAttClass(ATT_TYPED); Reset(); @@ -75,6 +77,7 @@ void LayerElement::Reset() { Object::Reset(); ResetCommon(); + ResetCommonPart(); ResetTyped(); m_xAbs = VRV_UNSET; @@ -691,8 +694,9 @@ int LayerElement::SetAlignmentPitchPos(FunctorParams *functorParams) Note *note = chord->GetTopNote(); assert(note); int loc = PitchInterface::CalcLoc(note->GetPname(), note->GetOct(), layerY->GetClefLocOffset(layerElementY)); - // Once we have AttLoc on Note - // if (note->HasLoc()) loc = note->GetLoc(); + if (note->HasLoc()) { + loc = note->GetLoc(); + } this->SetDrawingYRel(staffY->CalcPitchPosYRel(params->m_doc, loc)); } else if (this->Is({ CUSTOS, DOT })) { @@ -704,9 +708,14 @@ int LayerElement::SetAlignmentPitchPos(FunctorParams *functorParams) Note *note = dynamic_cast(this); assert(note); Chord *chord = note->IsChordTone(); - int loc = PitchInterface::CalcLoc(note->GetPname(), note->GetOct(), layerY->GetClefLocOffset(layerElementY)); - // Once we have AttLoc on Note - // if (note->HasLoc()) loc = note->GetLoc(); + int loc = 0; + if (note->HasPname()) { + loc = PitchInterface::CalcLoc(note->GetPname(), note->GetOct(), layerY->GetClefLocOffset(layerElementY)); + } + // should this override pname/oct ? + if (note->HasLoc()) { + loc = note->GetLoc(); + } int yRel = staffY->CalcPitchPosYRel(params->m_doc, loc); // Make it relative to the top note one (see above) but not for cross-staff notes in chords if (chord && !m_crossStaff) { @@ -715,6 +724,40 @@ int LayerElement::SetAlignmentPitchPos(FunctorParams *functorParams) note->SetDrawingLoc(loc); this->SetDrawingYRel(yRel); } + else if (this->Is(MREST)) { + MRest *mRest = dynamic_cast(this); + assert(mRest); + int loc = 0; + if (mRest->HasLoc()) { + loc = mRest->GetLoc(); + } + // Automatically calculate rest position + else { + // set default location to the middle of the staff + Staff *staff = dynamic_cast(this->GetFirstParent(STAFF)); + assert(staff); + loc = staff->m_drawingLines - 1; + // Limitation: GetLayerCount does not take into account editorial markup + // should be refined later + bool hasMultipleLayer = (staffY->GetLayerCount() > 1); + if (hasMultipleLayer) { + Layer *firstLayer = dynamic_cast(staffY->FindChildByType(LAYER)); + assert(firstLayer); + if (firstLayer->GetN() == layerY->GetN()) + loc += 2; + else + loc -= 2; + } + + // add offset + else if (staff->m_drawingLines > 1) + loc += 2; + } + + mRest->SetDrawingLoc(loc); + this->SetDrawingYRel(staffY->CalcPitchPosYRel(params->m_doc, loc)); + } + else if (this->Is(REST)) { Rest *rest = dynamic_cast(this); assert(rest); @@ -727,16 +770,23 @@ int LayerElement::SetAlignmentPitchPos(FunctorParams *functorParams) } // Automatically calculate rest position else { + // set default location to the middle of the staff + Staff *staff = dynamic_cast(this->GetFirstParent(STAFF)); + assert(staff); + loc = staff->m_drawingLines - 1; // Limitation: GetLayerCount does not take into account editorial markup + // should be refined later bool hasMultipleLayer = (staffY->GetLayerCount() > 1); - bool isFirstLayer = false; if (hasMultipleLayer) { Layer *firstLayer = dynamic_cast(staffY->FindChildByType(LAYER)); assert(firstLayer); - if (firstLayer->GetN() == layerY->GetN()) isFirstLayer = true; + if (firstLayer->GetN() == layerY->GetN()) + loc += 2; + else + loc -= 2; } - loc = rest->GetDefaultLoc(hasMultipleLayer, isFirstLayer); } + loc = rest->GetRestLocOffset(loc); rest->SetDrawingLoc(loc); this->SetDrawingYRel(staffY->CalcPitchPosYRel(params->m_doc, loc)); } @@ -809,7 +859,7 @@ int LayerElement::AdjustLayers(FunctorParams *functorParams) // Nothing to do if we have no vertical overlap if (!this->VerticalSelfOverlap(*iter, verticalMargin)) continue; - + // Nothing to do either if we have no horizontal overlap if (!this->HorizontalSelfOverlap(*iter, horizontalMargin)) continue; @@ -1129,14 +1179,11 @@ int LayerElement::GenerateMIDI(FunctorParams *functorParams) GenerateMIDIParams *params = dynamic_cast(functorParams); assert(params); - // Here we need to check if the LayerElement as a duration, otherwise we can continue + // Here we need to check if the LayerElement has a duration, otherwise we can continue if (!this->HasInterface(INTERFACE_DURATION)) return FUNCTOR_CONTINUE; // Now deal with the different elements if (this->Is(REST)) { - // Rest *rest = dynamic_cast(this); - // assert(rest); - // LogMessage("Rest %f", GetAlignmentDuration()); // increase the currentTime accordingly params->m_currentMeasureTime += GetAlignmentDuration() * params->m_currentBpm / (DUR_MAX / DURATION_4); } diff --git a/src/mensur.cpp b/src/mensur.cpp index da5442b23fb..8986cf205a0 100644 --- a/src/mensur.cpp +++ b/src/mensur.cpp @@ -19,6 +19,7 @@ int Mensur::s_numBase = 2; Mensur::Mensur() : LayerElement("mensur-") + , AttColor() , AttDurationRatio() , AttMensuralShared() , AttMensurLog() @@ -33,6 +34,7 @@ Mensur::Mensur(const ScoreDefInterface *mensurAttr) : LayerElement("mensur-") { Init(); + // this->SetColor(mensurAttr->GetMensurColor()); this->SetDot(mensurAttr->GetMensurDot()); this->SetSign(mensurAttr->GetMensurSign()); this->SetSlash(mensurAttr->GetMensurSlash()); @@ -50,6 +52,7 @@ Mensur::Mensur(const ScoreDefInterface *mensurAttr) : LayerElement("mensur-") void Mensur::Init() { + RegisterAttClass(ATT_COLOR); RegisterAttClass(ATT_DURATIONRATIO); RegisterAttClass(ATT_MENSURALSHARED); RegisterAttClass(ATT_MENSURLOG); @@ -67,6 +70,7 @@ Mensur::~Mensur() void Mensur::Reset() { LayerElement::Reset(); + ResetColor(); ResetDurationRatio(); ResetMensuralShared(); ResetMensurLog(); diff --git a/src/multirest.cpp b/src/multirest.cpp index 5568f2cb263..5bc7933d4a3 100644 --- a/src/multirest.cpp +++ b/src/multirest.cpp @@ -13,8 +13,9 @@ namespace vrv { // MultiRest //---------------------------------------------------------------------------- -MultiRest::MultiRest() : LayerElement("multirest-"), AttNumbered() +MultiRest::MultiRest() : LayerElement("multirest-"), AttMultiRestVis(), AttNumbered() { + RegisterAttClass(ATT_MULTIRESTVIS); RegisterAttClass(ATT_NUMBERED); Reset(); } @@ -26,6 +27,7 @@ MultiRest::~MultiRest() void MultiRest::Reset() { LayerElement::Reset(); + ResetMultiRestVis(); ResetNumbered(); } diff --git a/src/note.cpp b/src/note.cpp index ed7af033056..f9943dbb460 100644 --- a/src/note.cpp +++ b/src/note.cpp @@ -40,6 +40,7 @@ Note::Note() , StemmedDrawingInterface() , DurationInterface() , PitchInterface() + , PositionInterface() , AttColor() , AttColoration() , AttGraced() @@ -52,6 +53,7 @@ Note::Note() { RegisterInterface(DurationInterface::GetAttClasses(), DurationInterface::IsInterface()); RegisterInterface(PitchInterface::GetAttClasses(), PitchInterface::IsInterface()); + RegisterInterface(PositionInterface::GetAttClasses(), PositionInterface::IsInterface()); RegisterAttClass(ATT_COLOR); RegisterAttClass(ATT_COLORATION); RegisterAttClass(ATT_GRACED); @@ -81,6 +83,7 @@ void Note::Reset() StemmedDrawingInterface::Reset(); DurationInterface::Reset(); PitchInterface::Reset(); + PositionInterface::Reset(); ResetColor(); ResetColoration(); ResetGraced(); @@ -245,7 +248,7 @@ Point Note::GetStemUpSE(Doc *doc, int staffSize, bool graceSize) // Here we should get the notehead value wchar_t code = SMUFL_E0A4_noteheadBlack; - + // This is never called for now because mensural notes do not have stem/flag children // For changingg this, change Note::CalcStem and Note::PrepareLayerElementParts if (this->IsMensural()) { @@ -284,7 +287,7 @@ Point Note::GetStemDownNW(Doc *doc, int staffSize, bool graceSize) // Here we should get the notehead value wchar_t code = SMUFL_E0A4_noteheadBlack; - + // This is never called for now because mensural notes do not have stem/flag children // See comment above if (this->IsMensural()) { @@ -314,11 +317,11 @@ Point Note::GetStemDownNW(Doc *doc, int staffSize, bool graceSize) wchar_t Note::GetMensuralSmuflNoteHead() { assert(this->IsMensural()); - - Staff *staff = dynamic_cast(this->GetFirstParent(STAFF)); + + Staff *staff = dynamic_cast(this->GetFirstParent(STAFF)); assert(staff); bool mensural_black = (staff->m_drawingNotationType == NOTATIONTYPE_mensural_black); - + wchar_t code = 0; if (mensural_black) { code = SMUFL_E93D_mensuralNoteheadSemiminimaWhite; @@ -394,9 +397,9 @@ int Note::CalcStem(FunctorParams *functorParams) params->m_isGraceNote = this->IsGraceNote(); int staffSize = staff->m_drawingStaffSize; - int staffY = staff->GetDrawingY(); - params->m_verticalCenter = staffY - params->m_doc->GetDrawingDoubleUnit(staffSize) * 2; + params->m_verticalCenter + = staff->GetDrawingY() - params->m_doc->GetDrawingUnit(staffSize) * (staff->m_drawingLines - 1); /************ Set the direction ************/ @@ -725,6 +728,7 @@ int Note::ResetDrawing(FunctorParams *functorParams) { // Call parent one too LayerElement::ResetDrawing(functorParams); + PositionInterface::InterfaceResetDrawing(functorParams, this); this->ResetDrawingTieAttr(); @@ -737,6 +741,7 @@ int Note::ResetDrawing(FunctorParams *functorParams) int Note::ResetHorizontalAlignment(FunctorParams *functorParams) { LayerElement::ResetHorizontalAlignment(functorParams); + PositionInterface::InterfaceResetHorizontalAlignment(functorParams, this); m_drawingLoc = 0; m_flippedNotehead = false; diff --git a/src/pugi/pugixml.cpp b/src/pugi/pugixml.cpp index 90e7cb600e4..6a0b54e1f0a 100644 --- a/src/pugi/pugixml.cpp +++ b/src/pugi/pugixml.cpp @@ -1,7 +1,7 @@ /** - * pugixml parser - version 1.7 + * pugixml parser - version 1.8 * -------------------------------------------------------- - * Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Copyright (C) 2006-2016, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at http://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end @@ -54,7 +54,7 @@ #endif #ifdef __INTEL_COMPILER -# pragma warning(disable: 177) // function was declared but never referenced +# pragma warning(disable: 177) // function was declared but never referenced # pragma warning(disable: 279) // controlling expression is constant # pragma warning(disable: 1478 1786) // function was declared "deprecated" # pragma warning(disable: 1684) // conversion from pointer to same-sized integral type @@ -82,7 +82,7 @@ #elif defined(__GNUC__) # define PUGI__NO_INLINE __attribute__((noinline)) #else -# define PUGI__NO_INLINE +# define PUGI__NO_INLINE #endif // Branch weight controls @@ -109,6 +109,13 @@ using std::memmove; using std::memset; #endif +// Some MinGW versions have headers that erroneously omit LLONG_MIN/LLONG_MAX/ULLONG_MAX definitions in strict ANSI mode +#if defined(PUGIXML_HAS_LONG_LONG) && defined(__MINGW32__) && defined(__STRICT_ANSI__) && !defined(LLONG_MAX) && !defined(LLONG_MIN) && !defined(ULLONG_MAX) +# define LLONG_MAX 9223372036854775807LL +# define LLONG_MIN (-LLONG_MAX-1) +# define ULLONG_MAX (2ULL*LLONG_MAX+1) +#endif + // In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features #if defined(_MSC_VER) && !defined(__S3E__) # define PUGI__MSVC_CRT_VERSION _MSC_VER @@ -132,9 +139,7 @@ using std::memset; #endif // uintptr_t -#if !defined(_MSC_VER) || _MSC_VER >= 1600 -# include -#else +#if (defined(_MSC_VER) && _MSC_VER < 1600) || (defined(__BORLANDC__) && __BORLANDC__ < 0x561) namespace pugi { # ifndef _UINTPTR_T_DEFINED @@ -145,6 +150,8 @@ namespace pugi typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; } +#else +# include #endif // Memory allocation @@ -206,7 +213,7 @@ PUGI__NS_BEGIN for (size_t i = 0; i < count; ++i) if (lhs[i] != rhs[i]) return false; - + return lhs[count] == 0; } @@ -227,8 +234,10 @@ PUGI__NS_END // auto_ptr-like object for exception recovery PUGI__NS_BEGIN - template struct auto_deleter + template struct auto_deleter { + typedef void (*D)(T*); + T* data; D deleter; @@ -293,7 +302,7 @@ PUGI__NS_BEGIN bucket = (bucket + probe + 1) & hashmod; } - assert(!"Hash table is full"); + assert(false && "Hash table is full"); return 0; } @@ -323,7 +332,7 @@ PUGI__NS_BEGIN bucket = (bucket + probe + 1) & hashmod; } - assert(!"Hash table is full"); + assert(false && "Hash table is full"); return 0; } @@ -394,43 +403,33 @@ PUGI__NS_END #endif PUGI__NS_BEGIN - static const size_t xml_memory_page_size = - #ifdef PUGIXML_MEMORY_PAGE_SIZE - PUGIXML_MEMORY_PAGE_SIZE - #else - 32768 - #endif - ; - #ifdef PUGIXML_COMPACT static const uintptr_t xml_memory_block_alignment = 4; - - static const uintptr_t xml_memory_page_alignment = sizeof(void*); #else static const uintptr_t xml_memory_block_alignment = sizeof(void*); - - static const uintptr_t xml_memory_page_alignment = 64; - static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1); #endif // extra metadata bits - static const uintptr_t xml_memory_page_contents_shared_mask = 32; - static const uintptr_t xml_memory_page_name_allocated_mask = 16; - static const uintptr_t xml_memory_page_value_allocated_mask = 8; - static const uintptr_t xml_memory_page_type_mask = 7; + static const uintptr_t xml_memory_page_contents_shared_mask = 64; + static const uintptr_t xml_memory_page_name_allocated_mask = 32; + static const uintptr_t xml_memory_page_value_allocated_mask = 16; + static const uintptr_t xml_memory_page_type_mask = 15; // combined masks for string uniqueness static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask; static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask; #ifdef PUGIXML_COMPACT + #define PUGI__GETHEADER_IMPL(object, page, flags) // unused #define PUGI__GETPAGE_IMPL(header) (header).get_page() #else - #define PUGI__GETPAGE_IMPL(header) reinterpret_cast((header) & impl::xml_memory_page_pointer_mask) + #define PUGI__GETHEADER_IMPL(object, page, flags) (((reinterpret_cast(object) - reinterpret_cast(page)) << 8) | (flags)) + // this macro casts pointers through void* to avoid 'cast increases required alignment of target type' warnings + #define PUGI__GETPAGE_IMPL(header) static_cast(const_cast(static_cast(reinterpret_cast(&header) - (header >> 8)))) #endif #define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header) - #define PUGI__NODETYPE(n) static_cast(((n)->header & impl::xml_memory_page_type_mask) + 1) + #define PUGI__NODETYPE(n) static_cast((n)->header & impl::xml_memory_page_type_mask) struct xml_allocator; @@ -470,6 +469,14 @@ PUGI__NS_BEGIN #endif }; + static const size_t xml_memory_page_size = + #ifdef PUGIXML_MEMORY_PAGE_SIZE + (PUGIXML_MEMORY_PAGE_SIZE) + #else + 32768 + #endif + - sizeof(xml_memory_page); + struct xml_memory_string_header { uint16_t page_offset; // offset from page->data @@ -490,30 +497,21 @@ PUGI__NS_BEGIN size_t size = sizeof(xml_memory_page) + data_size; // allocate block with some alignment, leaving memory for worst-case padding - void* memory = xml_memory::allocate(size + xml_memory_page_alignment); + void* memory = xml_memory::allocate(size); if (!memory) return 0; - // align to next page boundary (note: this guarantees at least 1 usable byte before the page) - char* page_memory = reinterpret_cast((reinterpret_cast(memory) + xml_memory_page_alignment) & ~(xml_memory_page_alignment - 1)); - // prepare page structure - xml_memory_page* page = xml_memory_page::construct(page_memory); + xml_memory_page* page = xml_memory_page::construct(memory); assert(page); page->allocator = _root->allocator; - // record the offset for freeing the memory block - assert(page_memory > memory && page_memory - static_cast(memory) <= 127); - page_memory[-1] = static_cast(page_memory - static_cast(memory)); - return page; } static void deallocate_page(xml_memory_page* page) { - char* page_memory = reinterpret_cast(page); - - xml_memory::deallocate(page_memory - page_memory[-1]); + xml_memory::deallocate(page); } void* allocate_memory_oob(size_t size, xml_memory_page*& out_page); @@ -622,7 +620,7 @@ PUGI__NS_BEGIN // allocate memory for string and header block size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); - + // round size up to block alignment boundary size_t full_size = (size + (xml_memory_block_alignment - 1)) & ~(xml_memory_block_alignment - 1); @@ -1046,7 +1044,7 @@ namespace pugi struct xml_node_struct { - xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type - 1), namevalue_base(0) + xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0) { PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12); } @@ -1073,8 +1071,9 @@ namespace pugi { struct xml_attribute_struct { - xml_attribute_struct(impl::xml_memory_page* page): header(reinterpret_cast(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0) + xml_attribute_struct(impl::xml_memory_page* page): name(0), value(0), prev_attribute_c(0), next_attribute(0) { + header = PUGI__GETHEADER_IMPL(this, page, 0); } uintptr_t header; @@ -1088,8 +1087,9 @@ namespace pugi struct xml_node_struct { - xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(reinterpret_cast(page) | (type - 1)), name(0), value(0), parent(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) + xml_node_struct(impl::xml_memory_page* page, xml_node_type type): name(0), value(0), parent(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) { + header = PUGI__GETHEADER_IMPL(this, page, type); } uintptr_t header; @@ -1120,9 +1120,6 @@ PUGI__NS_BEGIN { xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0), extra_buffers(0) { - #ifdef PUGIXML_COMPACT - _hash = &hash; - #endif } const char_t* buffer; @@ -1188,7 +1185,7 @@ PUGI__NS_BEGIN if (n->header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value); - for (xml_attribute_struct* attr = n->first_attribute; attr;) + for (xml_attribute_struct* attr = n->first_attribute; attr; ) { xml_attribute_struct* next = attr->next_attribute; @@ -1197,7 +1194,7 @@ PUGI__NS_BEGIN attr = next; } - for (xml_node_struct* child = n->first_child; child;) + for (xml_node_struct* child = n->first_child; child; ) { xml_node_struct* next = child->next_sibling; @@ -1847,7 +1844,7 @@ PUGI__NS_BEGIN ctx_digit = 8, // 0-9 ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . }; - + static const unsigned char chartypex_table[256] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15 @@ -1869,7 +1866,7 @@ PUGI__NS_BEGIN 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 }; - + #ifdef PUGIXML_WCHAR_MODE #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast(c) < 128 ? table[static_cast(c)] : table[128]) & (ct)) #else @@ -1892,12 +1889,71 @@ PUGI__NS_BEGIN if (sizeof(wchar_t) == 2) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - else + else return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; } - PUGI__FN xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) + PUGI__FN bool parse_declaration_encoding(const uint8_t* data, size_t size, const uint8_t*& out_encoding, size_t& out_length) { + #define PUGI__SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; } + #define PUGI__SCANCHARTYPE(ct) { while (offset < size && PUGI__IS_CHARTYPE(data[offset], ct)) offset++; } + + // check if we have a non-empty XML declaration + if (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI__IS_CHARTYPE(data[5], ct_space))) + return false; + + // scan XML declaration until the encoding field + for (size_t i = 6; i + 1 < size; ++i) + { + // declaration can not contain ? in quoted values + if (data[i] == '?') + return false; + + if (data[i] == 'e' && data[i + 1] == 'n') + { + size_t offset = i; + + // encoding follows the version field which can't contain 'en' so this has to be the encoding if XML is well formed + PUGI__SCANCHAR('e'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('c'); PUGI__SCANCHAR('o'); + PUGI__SCANCHAR('d'); PUGI__SCANCHAR('i'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('g'); + + // S? = S? + PUGI__SCANCHARTYPE(ct_space); + PUGI__SCANCHAR('='); + PUGI__SCANCHARTYPE(ct_space); + + // the only two valid delimiters are ' and " + uint8_t delimiter = (offset < size && data[offset] == '"') ? '"' : '\''; + + PUGI__SCANCHAR(delimiter); + + size_t start = offset; + + out_encoding = data + offset; + + PUGI__SCANCHARTYPE(ct_symbol); + + out_length = offset - start; + + PUGI__SCANCHAR(delimiter); + + return true; + } + } + + return false; + + #undef PUGI__SCANCHAR + #undef PUGI__SCANCHARTYPE + } + + PUGI__FN xml_encoding guess_buffer_encoding(const uint8_t* data, size_t size) + { + // skip encoding autodetection if input buffer is too small + if (size < 4) return encoding_utf8; + + uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; + // look for BOM in first few bytes if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le; @@ -1910,13 +1966,32 @@ PUGI__NS_BEGIN if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0) return encoding_utf32_le; if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be; if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le; - if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d) return encoding_utf8; // look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early) if (d0 == 0 && d1 == 0x3c) return encoding_utf16_be; if (d0 == 0x3c && d1 == 0) return encoding_utf16_le; - // no known BOM detected, assume utf8 + // no known BOM detected; parse declaration + const uint8_t* enc = 0; + size_t enc_length = 0; + + if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d && parse_declaration_encoding(data, size, enc, enc_length)) + { + // iso-8859-1 (case-insensitive) + if (enc_length == 10 + && (enc[0] | ' ') == 'i' && (enc[1] | ' ') == 's' && (enc[2] | ' ') == 'o' + && enc[3] == '-' && enc[4] == '8' && enc[5] == '8' && enc[6] == '5' && enc[7] == '9' + && enc[8] == '-' && enc[9] == '1') + return encoding_latin1; + + // latin1 (case-insensitive) + if (enc_length == 6 + && (enc[0] | ' ') == 'l' && (enc[1] | ' ') == 'a' && (enc[2] | ' ') == 't' + && (enc[3] | ' ') == 'i' && (enc[4] | ' ') == 'n' + && enc[5] == '1') + return encoding_latin1; + } + return encoding_utf8; } @@ -1934,15 +2009,10 @@ PUGI__NS_BEGIN // only do autodetection if no explicit encoding is requested if (encoding != encoding_auto) return encoding; - // skip encoding autodetection if input buffer is too small - if (size < 4) return encoding_utf8; - // try to guess encoding (based on XML specification, Appendix F.1) const uint8_t* data = static_cast(contents); - PUGI__DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; - - return guess_buffer_encoding(d0, d1, d2, d3); + return guess_buffer_encoding(data, size); } PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) @@ -2075,7 +2145,7 @@ PUGI__NS_BEGIN if (encoding == encoding_latin1) return convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder()); - assert(!"Invalid encoding"); + assert(false && "Invalid encoding"); return false; } #else @@ -2180,7 +2250,7 @@ PUGI__NS_BEGIN if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable); - assert(!"Invalid encoding"); + assert(false && "Invalid encoding"); return false; } #endif @@ -2196,12 +2266,12 @@ PUGI__NS_BEGIN // convert to utf8 uint8_t* begin = reinterpret_cast(buffer); uint8_t* end = wchar_decoder::process(str, length, begin, utf8_writer()); - + assert(begin + size == end); (void)!end; (void)!size; } - + #ifndef PUGIXML_NO_STL PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length) { @@ -2269,7 +2339,7 @@ PUGI__NS_BEGIN xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; if (header & header_mask) alloc->deallocate_string(dest); - + // mark the string as not allocated dest = 0; header &= ~header_mask; @@ -2281,7 +2351,7 @@ PUGI__NS_BEGIN // we can reuse old buffer, so just copy the new data (including zero terminator) memcpy(dest, source, source_length * sizeof(char_t)); dest[source_length] = 0; - + return true; } else @@ -2300,7 +2370,7 @@ PUGI__NS_BEGIN // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) if (header & header_mask) alloc->deallocate_string(dest); - + // the string is now allocated, so set the flag dest = buf; header |= header_mask; @@ -2313,11 +2383,11 @@ PUGI__NS_BEGIN { char_t* end; size_t size; - + gap(): end(0), size(0) { } - + // Push new gap, move s count bytes further (skipping the gap). // Collapse previous gap. void push(char_t*& s, size_t count) @@ -2328,14 +2398,14 @@ PUGI__NS_BEGIN assert(s >= end); memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); } - + s += count; // end of current gap - + // "merge" two gaps end = s; size += count; } - + // Collapse all gaps, return past-the-end pointer char_t* flush(char_t* s) { @@ -2350,7 +2420,7 @@ PUGI__NS_BEGIN else return s; } }; - + PUGI__FN char_t* strconv_escape(char_t* s, gap& g) { char_t* stre = s + 1; @@ -2382,7 +2452,7 @@ PUGI__NS_BEGIN ch = *++stre; } - + ++stre; } else // &#... (dec code) @@ -2402,7 +2472,7 @@ PUGI__NS_BEGIN ch = *++stre; } - + ++stre; } @@ -2411,7 +2481,7 @@ PUGI__NS_BEGIN #else s = reinterpret_cast(utf8_writer::any(reinterpret_cast(s), ucsc)); #endif - + g.push(s, stre - s); return stre; } @@ -2426,7 +2496,7 @@ PUGI__NS_BEGIN { *s++ = '&'; ++stre; - + g.push(s, stre - s); return stre; } @@ -2451,7 +2521,7 @@ PUGI__NS_BEGIN { *s++ = '>'; ++stre; - + g.push(s, stre - s); return stre; } @@ -2464,7 +2534,7 @@ PUGI__NS_BEGIN { *s++ = '<'; ++stre; - + g.push(s, stre - s); return stre; } @@ -2477,7 +2547,7 @@ PUGI__NS_BEGIN { *s++ = '"'; ++stre; - + g.push(s, stre - s); return stre; } @@ -2487,15 +2557,15 @@ PUGI__NS_BEGIN default: break; } - + return stre; } // Parser utilities #define PUGI__ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; } - #define PUGI__OPTSET(OPT) (optmsk & (OPT)) - #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); } + #define PUGI__OPTSET(OPT) ( optmsk & (OPT) ) + #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); } #define PUGI__POPNODE() { cursor = cursor->parent; } #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; } #define PUGI__SCANWHILE(X) { while (X) ++s; } @@ -2507,21 +2577,21 @@ PUGI__NS_BEGIN PUGI__FN char_t* strconv_comment(char_t* s, char_t endch) { gap g; - + while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment)); - + if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a - + if (*s == '\n') g.push(s, 1); } else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here { *g.flush(s) = 0; - + return s + (s[2] == '>' ? 3 : 2); } else if (*s == 0) @@ -2535,21 +2605,21 @@ PUGI__NS_BEGIN PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch) { gap g; - + while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata)); - + if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a - + if (*s == '\n') g.push(s, 1); } else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here { *g.flush(s) = 0; - + return s + 1; } else if (*s == 0) @@ -2559,9 +2629,9 @@ PUGI__NS_BEGIN else ++s; } } - + typedef char_t* (*strconv_pcdata_t)(char_t*); - + template struct strconv_pcdata_impl { static char_t* parse(char_t* s) @@ -2583,13 +2653,13 @@ PUGI__NS_BEGIN --end; *end = 0; - + return s + 1; } else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a - + if (*s == '\n') g.push(s, 1); } else if (opt_escape::value && *s == '&') @@ -2612,7 +2682,7 @@ PUGI__NS_BEGIN } } }; - + PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) { PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800); @@ -2632,7 +2702,7 @@ PUGI__NS_BEGIN } typedef char_t* (*strconv_attribute_t)(char_t*, char_t); - + template struct strconv_attribute_impl { static char_t* parse_wnorm(char_t* s, char_t end_quote) @@ -2643,35 +2713,35 @@ PUGI__NS_BEGIN if (PUGI__IS_CHARTYPE(*s, ct_space)) { char_t* str = s; - + do ++str; while (PUGI__IS_CHARTYPE(*str, ct_space)); - + g.push(s, str - s); } while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space)); - + if (*s == end_quote) { char_t* str = g.flush(s); - + do *str-- = 0; while (PUGI__IS_CHARTYPE(*str, ct_space)); - + return s + 1; } else if (PUGI__IS_CHARTYPE(*s, ct_space)) { *s++ = ' '; - + if (PUGI__IS_CHARTYPE(*s, ct_space)) { char_t* str = s + 1; while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str; - + g.push(s, str - s); } } @@ -2694,11 +2764,11 @@ PUGI__NS_BEGIN while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws)); - + if (*s == end_quote) { *g.flush(s) = 0; - + return s + 1; } else if (PUGI__IS_CHARTYPE(*s, ct_space)) @@ -2706,7 +2776,7 @@ PUGI__NS_BEGIN if (*s == '\r') { *s++ = ' '; - + if (*s == '\n') g.push(s, 1); } else *s++ = ' '; @@ -2730,17 +2800,17 @@ PUGI__NS_BEGIN while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); - + if (*s == end_quote) { *g.flush(s) = 0; - + return s + 1; } else if (*s == '\r') { *s++ = '\n'; - + if (*s == '\n') g.push(s, 1); } else if (opt_escape::value && *s == '&') @@ -2762,11 +2832,11 @@ PUGI__NS_BEGIN while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); - + if (*s == end_quote) { *g.flush(s) = 0; - + return s + 1; } else if (opt_escape::value && *s == '&') @@ -2785,7 +2855,7 @@ PUGI__NS_BEGIN PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask) { PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); - + switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes) { case 0: return strconv_attribute_impl::parse_simple; @@ -2819,18 +2889,12 @@ PUGI__NS_BEGIN struct xml_parser { - xml_allocator alloc; - xml_allocator* alloc_state; + xml_allocator* alloc; char_t* error_offset; xml_parse_status error_status; - - xml_parser(xml_allocator* alloc_): alloc(*alloc_), alloc_state(alloc_), error_offset(0), error_status(status_ok) - { - } - ~xml_parser() + xml_parser(xml_allocator* alloc_): alloc(alloc_), error_offset(0), error_status(status_ok) { - *alloc_state = alloc; } // DOCTYPE consists of nested sections of the following possible types: @@ -3157,7 +3221,7 @@ PUGI__NS_BEGIN { strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); - + char_t ch = 0; xml_node_struct* cursor = root; char_t* mark = s; @@ -3188,10 +3252,10 @@ PUGI__NS_BEGIN while (true) { PUGI__SKIPWS(); // Eat any whitespace. - + if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #... { - xml_attribute_struct* a = append_new_attribute(cursor, alloc); // Make space for this attribute. + xml_attribute_struct* a = append_new_attribute(cursor, *alloc); // Make space for this attribute. if (!a) PUGI__THROW_ERROR(status_out_of_memory, s); a->name = s; // Save the offset. @@ -3206,7 +3270,7 @@ PUGI__NS_BEGIN ch = *s; ++s; } - + if (ch == '=') // '<... #=...' { PUGI__SKIPWS(); // Eat any whitespace. @@ -3218,7 +3282,7 @@ PUGI__NS_BEGIN a->value = s; // Save the offset. s = strconv_attribute(s, ch); - + if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value); // After this line the loop continues from the start; @@ -3233,7 +3297,7 @@ PUGI__NS_BEGIN else if (*s == '/') { ++s; - + if (*s == '>') { PUGI__POPNODE(); @@ -3274,7 +3338,7 @@ PUGI__NS_BEGIN { // we stepped over null terminator, backtrack & handle closing tag --s; - + if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s); } else PUGI__THROW_ERROR(status_bad_start_element, s); @@ -3283,20 +3347,22 @@ PUGI__NS_BEGIN { ++s; + mark = s; + char_t* name = cursor->name; - if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, s); - + if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, mark); + while (PUGI__IS_CHARTYPE(*s, ct_symbol)) { - if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, s); + if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, mark); } if (*name) { if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s); - else PUGI__THROW_ERROR(status_end_element_mismatch, s); + else PUGI__THROW_ERROR(status_end_element_mismatch, mark); } - + PUGI__POPNODE(); // Pop. PUGI__SKIPWS(); @@ -3350,23 +3416,31 @@ PUGI__NS_BEGIN if (!PUGI__OPTSET(parse_trim_pcdata)) s = mark; - + if (cursor->parent || PUGI__OPTSET(parse_fragment)) { - PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. - cursor->value = s; // Save the offset. + if (PUGI__OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value) + { + cursor->value = s; // Save the offset. + } + else + { + PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. + + cursor->value = s; // Save the offset. + + PUGI__POPNODE(); // Pop since this is a standalone. + } s = strconv_pcdata(s); - - PUGI__POPNODE(); // Pop since this is a standalone. - + if (!*s) break; } else { PUGI__SCANFOR(*s == '<'); // '...<' if (!*s) break; - + ++s; } @@ -3414,14 +3488,14 @@ PUGI__NS_BEGIN // get last child of the root before parsing xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0; - + // create parser on stack xml_parser parser(static_cast(xmldoc)); // save last character and make buffer zero-terminated (speeds up parsing) char_t endch = buffer[length - 1]; buffer[length - 1] = 0; - + // skip BOM to make sure it does not end up as part of parse output char_t* buffer_data = parse_skip_bom(buffer); @@ -3511,7 +3585,7 @@ PUGI__NS_BEGIN { if (length < 1) return 0; - // discard last character if it's the lead of a surrogate pair + // discard last character if it's the lead of a surrogate pair return (sizeof(wchar_t) == 2 && static_cast(static_cast(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; } @@ -3524,7 +3598,7 @@ PUGI__NS_BEGIN return length * sizeof(char_t); } - + // convert to utf8 if (encoding == encoding_utf8) return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer()); @@ -3549,7 +3623,7 @@ PUGI__NS_BEGIN if (encoding == encoding_latin1) return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer()); - assert(!"Invalid encoding"); + assert(false && "Invalid encoding"); return 0; } #else @@ -3588,7 +3662,7 @@ PUGI__NS_BEGIN if (encoding == encoding_latin1) return convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer()); - assert(!"Invalid encoding"); + assert(false && "Invalid encoding"); return 0; } #endif @@ -3812,10 +3886,10 @@ PUGI__NS_BEGIN while (*s) { const char_t* prev = s; - + // While *s is a usual symbol PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPEX(ss, type)); - + writer.write_buffer(prev, static_cast(s - prev)); switch (*s) @@ -4002,17 +4076,54 @@ PUGI__NS_BEGIN if (node->first_attribute) node_output_attributes(writer, node, indent, indent_length, flags, depth); - if (!node->first_child) + // element nodes can have value if parse_embed_pcdata was used + if (!node->value) { - writer.write(' ', '/', '>'); + if (!node->first_child) + { + if (flags & format_no_empty_element_tags) + { + writer.write('>', '<', '/'); + writer.write_string(name); + writer.write('>'); - return false; + return false; + } + else + { + if ((flags & format_raw) == 0) + writer.write(' '); + + writer.write('/', '>'); + + return false; + } + } + else + { + writer.write('>'); + + return true; + } } else { writer.write('>'); - return true; + text_output(writer, node->value, ctx_special_pcdata, flags); + + if (!node->first_child) + { + writer.write('<', '/'); + writer.write_string(name); + writer.write('>'); + + return false; + } + else + { + return true; + } } } @@ -4078,7 +4189,7 @@ PUGI__NS_BEGIN break; default: - assert(!"Invalid node type"); + assert(false && "Invalid node type"); } } @@ -4120,6 +4231,10 @@ PUGI__NS_BEGIN if (node_output_start(writer, node, indent, indent_length, flags, depth)) { + // element nodes can have value if parse_embed_pcdata was used + if (node->value) + indent_flags = 0; + node = node->first_child; depth++; continue; @@ -4460,8 +4575,7 @@ PUGI__NS_BEGIN } #endif - template - PUGI__FN char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative) + template PUGI__FN char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative) { char_t* result = end - 1; U rest = negative ? 0 - value : value; @@ -4498,22 +4612,12 @@ PUGI__NS_BEGIN #endif } - template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, int value) - { - char_t buf[64]; - char_t* end = buf + sizeof(buf) / sizeof(buf[0]); - char_t* begin = integer_to_string(buf, end, value, value < 0); - - return strcpy_insitu(dest, header, header_mask, begin, end - begin); - } - - template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, unsigned int value) + template + PUGI__FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative) { char_t buf[64]; char_t* end = buf + sizeof(buf) / sizeof(buf[0]); - char_t* begin = integer_to_string(buf, end, value, false); + char_t* begin = integer_to_string(buf, end, value, negative); return strcpy_insitu(dest, header, header_mask, begin, end - begin); } @@ -4535,34 +4639,12 @@ PUGI__NS_BEGIN return set_value_ascii(dest, header, header_mask, buf); } - - template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, bool value) - { - return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5); - } - -#ifdef PUGIXML_HAS_LONG_LONG - template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, long long value) - { - char_t buf[64]; - char_t* end = buf + sizeof(buf) / sizeof(buf[0]); - char_t* begin = integer_to_string(buf, end, value, value < 0); - - return strcpy_insitu(dest, header, header_mask, begin, end - begin); - } template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, unsigned long long value) + PUGI__FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value) { - char_t buf[64]; - char_t* end = buf + sizeof(buf) / sizeof(buf[0]); - char_t* begin = integer_to_string(buf, end, value, false); - - return strcpy_insitu(dest, header, header_mask, begin, end - begin); + return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5); } -#endif PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) { @@ -4624,7 +4706,7 @@ PUGI__NS_BEGIN // check for I/O errors if (length < 0) return status_io_error; - + // check for overflow size_t result = static_cast(length); @@ -4637,7 +4719,7 @@ PUGI__NS_BEGIN } // This function assumes that buffer has extra sizeof(char_t) writable bytes after size - PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding) + PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding) { // We only need to zero-terminate if encoding conversion does not do it for us #ifdef PUGIXML_WCHAR_MODE @@ -4669,7 +4751,7 @@ PUGI__NS_BEGIN size_t size = 0; xml_parse_status size_status = get_file_size(file, size); if (size_status != status_ok) return make_parse_result(size_status); - + size_t max_suffix_size = sizeof(char_t); // allocate buffer for the whole file @@ -4690,6 +4772,11 @@ PUGI__NS_BEGIN return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer); } + PUGI__FN void close_file(FILE* file) + { + fclose(file); + } + #ifndef PUGIXML_NO_STL template struct xml_stream_chunk { @@ -4697,7 +4784,7 @@ PUGI__NS_BEGIN { void* memory = xml_memory::allocate(sizeof(xml_stream_chunk)); if (!memory) return 0; - + return new (memory) xml_stream_chunk(); } @@ -4807,7 +4894,7 @@ PUGI__NS_BEGIN // return buffer size_t actual_length = static_cast(stream.gcount()); assert(actual_length <= read_length); - + *out_buffer = buffer.release(); *out_size = actual_length * sizeof(T); @@ -4835,7 +4922,7 @@ PUGI__NS_BEGIN if (status != status_ok) return make_parse_result(status); xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size); - + return load_buffer_impl(doc, doc, buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding, true, true, out_buffer); } #endif @@ -4955,7 +5042,7 @@ namespace pugi PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0) { } - + PUGI__FN xml_tree_walker::~xml_tree_walker() { } @@ -5001,7 +5088,7 @@ namespace pugi { return (_attr == r._attr); } - + PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const { return (_attr != r._attr); @@ -5011,17 +5098,17 @@ namespace pugi { return (_attr < r._attr); } - + PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const { return (_attr > r._attr); } - + PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const { return (_attr <= r._attr); } - + PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const { return (_attr >= r._attr); @@ -5109,7 +5196,7 @@ namespace pugi set_value(rhs); return *this; } - + PUGI__FN xml_attribute& xml_attribute::operator=(int rhs) { set_value(rhs); @@ -5122,12 +5209,24 @@ namespace pugi return *this; } + PUGI__FN xml_attribute& xml_attribute::operator=(long rhs) + { + set_value(rhs); + return *this; + } + + PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long rhs) + { + set_value(rhs); + return *this; + } + PUGI__FN xml_attribute& xml_attribute::operator=(double rhs) { set_value(rhs); return *this; } - + PUGI__FN xml_attribute& xml_attribute::operator=(float rhs) { set_value(rhs); @@ -5157,10 +5256,10 @@ namespace pugi PUGI__FN bool xml_attribute::set_name(const char_t* rhs) { if (!_attr) return false; - + return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); } - + PUGI__FN bool xml_attribute::set_value(const char_t* rhs) { if (!_attr) return false; @@ -5172,14 +5271,28 @@ namespace pugi { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI__FN bool xml_attribute::set_value(unsigned int rhs) { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); + } + + PUGI__FN bool xml_attribute::set_value(long rhs) + { + if (!_attr) return false; + + return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); + } + + PUGI__FN bool xml_attribute::set_value(unsigned long rhs) + { + if (!_attr) return false; + + return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } PUGI__FN bool xml_attribute::set_value(double rhs) @@ -5188,7 +5301,7 @@ namespace pugi return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } - + PUGI__FN bool xml_attribute::set_value(float rhs) { if (!_attr) return false; @@ -5200,7 +5313,7 @@ namespace pugi { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::set_value_bool(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } #ifdef PUGIXML_HAS_LONG_LONG @@ -5208,14 +5321,14 @@ namespace pugi { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI__FN bool xml_attribute::set_value(unsigned long long rhs) { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } #endif @@ -5238,7 +5351,7 @@ namespace pugi PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p) { } - + PUGI__FN static void unspecified_bool_xml_node(xml_node***) { } @@ -5262,7 +5375,7 @@ namespace pugi { return iterator(0, _root); } - + PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const { return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root); @@ -5272,7 +5385,7 @@ namespace pugi { return attribute_iterator(0, _root); } - + PUGI__FN xml_object_range xml_node::children() const { return xml_object_range(begin(), end()); @@ -5302,17 +5415,17 @@ namespace pugi { return (_root < r._root); } - + PUGI__FN bool xml_node::operator>(const xml_node& r) const { return (_root > r._root); } - + PUGI__FN bool xml_node::operator<=(const xml_node& r) const { return (_root <= r._root); } - + PUGI__FN bool xml_node::operator>=(const xml_node& r) const { return (_root >= r._root); @@ -5322,7 +5435,7 @@ namespace pugi { return !_root; } - + PUGI__FN const char_t* xml_node::name() const { return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT(""); @@ -5332,12 +5445,12 @@ namespace pugi { return _root ? PUGI__NODETYPE(_root) : node_null; } - + PUGI__FN const char_t* xml_node::value() const { return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT(""); } - + PUGI__FN xml_node xml_node::child(const char_t* name_) const { if (!_root) return xml_node(); @@ -5355,14 +5468,14 @@ namespace pugi for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) if (i->name && impl::strequal(name_, i->name)) return xml_attribute(i); - + return xml_attribute(); } - + PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const { if (!_root) return xml_node(); - + for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) if (i->name && impl::strequal(name_, i->name)) return xml_node(i); @@ -5377,7 +5490,7 @@ namespace pugi PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const { if (!_root) return xml_node(); - + for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) if (i->name && impl::strequal(name_, i->name)) return xml_node(i); @@ -5420,7 +5533,7 @@ namespace pugi PUGI__FN xml_node xml_node::previous_sibling() const { if (!_root) return xml_node(); - + if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c); else return xml_node(); } @@ -5443,7 +5556,11 @@ namespace pugi PUGI__FN const char_t* xml_node::child_value() const { if (!_root) return PUGIXML_TEXT(""); - + + // element nodes can have value if parse_embed_pcdata was used + if (PUGI__NODETYPE(_root) == node_element && _root->value) + return _root->value; + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) if (impl::is_text_node(i) && i->value) return i->value; @@ -5485,7 +5602,7 @@ namespace pugi return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); } - + PUGI__FN bool xml_node::set_value(const char_t* rhs) { xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; @@ -5499,7 +5616,7 @@ namespace pugi PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); - + impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); @@ -5509,14 +5626,14 @@ namespace pugi impl::append_attribute(a._attr, _root); a.set_name(name_); - + return a; } PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); - + impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); @@ -5534,7 +5651,7 @@ namespace pugi { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); - + impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); @@ -5552,7 +5669,7 @@ namespace pugi { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); - + impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); @@ -5639,7 +5756,7 @@ namespace pugi PUGI__FN xml_node xml_node::append_child(xml_node_type type_) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); - + impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); @@ -5659,12 +5776,12 @@ namespace pugi impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); - + xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::prepend_node(n._root, _root); - + if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); return n; @@ -5677,7 +5794,7 @@ namespace pugi impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); - + xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); @@ -5695,7 +5812,7 @@ namespace pugi impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); - + xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); @@ -5927,7 +6044,7 @@ namespace pugi // disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense doc->header |= impl::xml_memory_page_contents_shared_mask; - + // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later) impl::xml_memory_page* page = 0; impl::xml_extra_buffer* extra = static_cast(doc->allocate_memory(sizeof(impl::xml_extra_buffer), page)); @@ -5949,7 +6066,7 @@ namespace pugi PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const { if (!_root) return xml_node(); - + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) if (i->name && impl::strequal(name_, i->name)) { @@ -5964,7 +6081,7 @@ namespace pugi PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const { if (!_root) return xml_node(); - + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(""))) @@ -6059,22 +6176,22 @@ namespace pugi PUGI__FN bool xml_node::traverse(xml_tree_walker& walker) { walker._depth = -1; - + xml_node arg_begin = *this; if (!walker.begin(arg_begin)) return false; xml_node cur = first_child(); - + if (cur) { ++walker._depth; - do + do { xml_node arg_for_each = cur; if (!walker.for_each(arg_for_each)) return false; - + if (cur.first_child()) { ++walker._depth; @@ -6090,7 +6207,7 @@ namespace pugi --walker._depth; cur = cur.parent(); } - + if (cur != *this) cur = cur.next_sibling(); } @@ -6191,6 +6308,10 @@ namespace pugi { if (!_root || impl::is_text_node(_root)) return _root; + // element nodes can have value if parse_embed_pcdata was used + if (PUGI__NODETYPE(_root) == node_element && _root->value) + return _root; + for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling) if (impl::is_text_node(node)) return node; @@ -6305,14 +6426,28 @@ namespace pugi { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI__FN bool xml_text::set(unsigned int rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; + } + + PUGI__FN bool xml_text::set(long rhs) + { + xml_node_struct* dn = _data_new(); + + return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; + } + + PUGI__FN bool xml_text::set(unsigned long rhs) + { + xml_node_struct* dn = _data_new(); + + return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } PUGI__FN bool xml_text::set(float rhs) @@ -6333,7 +6468,7 @@ namespace pugi { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + return dn ? impl::set_value_bool(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } #ifdef PUGIXML_HAS_LONG_LONG @@ -6341,14 +6476,14 @@ namespace pugi { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI__FN bool xml_text::set(unsigned long long rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } #endif @@ -6370,6 +6505,18 @@ namespace pugi return *this; } + PUGI__FN xml_text& xml_text::operator=(long rhs) + { + set(rhs); + return *this; + } + + PUGI__FN xml_text& xml_text::operator=(unsigned long rhs) + { + set(rhs); + return *this; + } + PUGI__FN xml_text& xml_text::operator=(double rhs) { set(rhs); @@ -6435,7 +6582,7 @@ namespace pugi { return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; } - + PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const { return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; @@ -6450,7 +6597,7 @@ namespace pugi PUGI__FN xml_node* xml_node_iterator::operator->() const { assert(_wrap._root); - return const_cast(&_wrap); // BCC32 workaround + return const_cast(&_wrap); // BCC5 workaround } PUGI__FN const xml_node_iterator& xml_node_iterator::operator++() @@ -6496,7 +6643,7 @@ namespace pugi { return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; } - + PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const { return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; @@ -6511,7 +6658,7 @@ namespace pugi PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const { assert(_wrap._attr); - return const_cast(&_wrap); // BCC32 workaround + return const_cast(&_wrap); // BCC5 workaround } PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++() @@ -6572,7 +6719,7 @@ namespace pugi PUGI__FN xml_node* xml_named_node_iterator::operator->() const { assert(_wrap._root); - return const_cast(&_wrap); // BCC32 workaround + return const_cast(&_wrap); // BCC5 workaround } PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++() @@ -6653,18 +6800,18 @@ namespace pugi PUGI__FN xml_document::xml_document(): _buffer(0) { - create(); + _create(); } PUGI__FN xml_document::~xml_document() { - destroy(); + _destroy(); } PUGI__FN void xml_document::reset() { - destroy(); - create(); + _destroy(); + _create(); } PUGI__FN void xml_document::reset(const xml_document& proto) @@ -6675,7 +6822,7 @@ namespace pugi append_copy(cur); } - PUGI__FN void xml_document::create() + PUGI__FN void xml_document::_create() { assert(!_root); @@ -6686,13 +6833,10 @@ namespace pugi #endif // initialize sentinel page - PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + impl::xml_memory_page_alignment - sizeof(void*) + page_offset <= sizeof(_memory)); - - // align upwards to page boundary - void* page_memory = reinterpret_cast((reinterpret_cast(_memory) + (impl::xml_memory_page_alignment - 1)) & ~(impl::xml_memory_page_alignment - 1)); + PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory)); // prepare page structure - impl::xml_memory_page* page = impl::xml_memory_page::construct(page_memory); + impl::xml_memory_page* page = impl::xml_memory_page::construct(_memory); assert(page); page->busy_size = impl::xml_memory_page_size; @@ -6711,11 +6855,16 @@ namespace pugi // setup sentinel page page->allocator = static_cast(_root); + // setup hash table pointer in allocator + #ifdef PUGIXML_COMPACT + page->allocator->_hash = &static_cast(_root)->hash; + #endif + // verify the document allocation assert(reinterpret_cast(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory)); } - PUGI__FN void xml_document::destroy() + PUGI__FN void xml_document::_destroy() { assert(_root); @@ -6737,7 +6886,7 @@ namespace pugi assert(root_page && !root_page->prev); assert(reinterpret_cast(root_page) >= _memory && reinterpret_cast(root_page) < _memory + sizeof(_memory)); - for (impl::xml_memory_page* page = root_page->next; page;) + for (impl::xml_memory_page* page = root_page->next; page; ) { impl::xml_memory_page* next = page->next; @@ -6792,7 +6941,7 @@ namespace pugi reset(); using impl::auto_deleter; // MSVC7 workaround - auto_deleter file(fopen(path_, "rb"), fclose); + auto_deleter file(fopen(path_, "rb"), impl::close_file); return impl::load_file_impl(static_cast(_root), file.data, options, encoding, &_buffer); } @@ -6802,7 +6951,7 @@ namespace pugi reset(); using impl::auto_deleter; // MSVC7 workaround - auto_deleter file(impl::open_file_wide(path_, L"rb"), fclose); + auto_deleter file(impl::open_file_wide(path_, L"rb"), impl::close_file); return impl::load_file_impl(static_cast(_root), file.data, options, encoding, &_buffer); } @@ -6875,7 +7024,7 @@ namespace pugi PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const { using impl::auto_deleter; // MSVC7 workaround - auto_deleter file(fopen(path_, (flags & format_save_file_text) ? "w" : "wb"), fclose); + auto_deleter file(fopen(path_, (flags & format_save_file_text) ? "w" : "wb"), impl::close_file); return impl::save_file_impl(*this, file.data, indent, flags, encoding); } @@ -6883,7 +7032,7 @@ namespace pugi PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const { using impl::auto_deleter; // MSVC7 workaround - auto_deleter file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), fclose); + auto_deleter file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), impl::close_file); return impl::save_file_impl(*this, file.data, indent, flags, encoding); } @@ -6911,14 +7060,14 @@ namespace pugi { return impl::as_utf8_impl(str.c_str(), str.size()); } - + PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const char* str) { assert(str); return impl::as_wide_impl(str, strlen(str)); } - + PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const std::string& str) { return impl::as_wide_impl(str.c_str(), str.size()); @@ -7050,7 +7199,7 @@ PUGI__NS_BEGIN if (begin == end) return begin; // last written element - I write = begin++; + I write = begin++; // merge unique elements while (begin != end) @@ -7225,7 +7374,7 @@ PUGI__NS_BEGIN static const uintptr_t xpath_memory_block_alignment = sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*); struct xpath_memory_block - { + { xpath_memory_block* next; size_t capacity; @@ -7235,7 +7384,7 @@ PUGI__NS_BEGIN double alignment; }; }; - + class xpath_allocator { xpath_memory_block* _root; @@ -7252,7 +7401,7 @@ PUGI__NS_BEGIN error_handler = 0; #endif } - + void* allocate_nothrow(size_t size) { // round size up to block alignment boundary @@ -7275,13 +7424,13 @@ PUGI__NS_BEGIN xpath_memory_block* block = static_cast(xml_memory::allocate(block_size)); if (!block) return 0; - + block->next = _root; block->capacity = block_capacity; - + _root = block; _root_size = size; - + return block->data; } } @@ -7529,7 +7678,7 @@ PUGI__NS_BEGIN { return _uses_heap ? _length_heap : strlength(_buffer); } - + char_t* data(xpath_allocator* alloc) { // make private heap copy @@ -7619,14 +7768,18 @@ PUGI__NS_BEGIN case node_comment: case node_pi: return xpath_string::from_const(n.value()); - + case node_document: case node_element: { xpath_string result; + // element nodes can have value if parse_embed_pcdata was used + if (n.value()[0]) + result.append(xpath_string::from_const(n.value()), alloc); + xml_node cur = n.first_child(); - + while (cur && cur != n) { if (cur.type() == node_pcdata || cur.type() == node_cdata) @@ -7644,16 +7797,16 @@ PUGI__NS_BEGIN if (cur != n) cur = cur.next_sibling(); } } - + return result; } - + default: return xpath_string(); } } } - + PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn) { assert(ln->parent == rn->parent); @@ -7677,7 +7830,7 @@ PUGI__NS_BEGIN // if rn sibling chain ended ln must be before rn return !rs; } - + PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn) { // find common ancestor at the same depth, if any @@ -7758,7 +7911,7 @@ PUGI__NS_BEGIN return 0; } - + struct document_order_comparator { bool operator()(const xpath_node& lhs, const xpath_node& rhs) const @@ -7782,10 +7935,10 @@ PUGI__NS_BEGIN for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) if (a == rhs.attribute()) return true; - + return false; } - + // compare attribute parents ln = lhs.parent(); rn = rhs.parent(); @@ -7794,21 +7947,21 @@ PUGI__NS_BEGIN { // attributes go after the parent element if (lhs.parent() == rhs.node()) return false; - + ln = lhs.parent(); } else if (rhs.attribute()) { // attributes go after the parent element if (rhs.parent() == lhs.node()) return true; - + rn = rhs.parent(); } if (ln == rn) return false; if (!ln || !rn) return ln < rn; - + return node_is_before(ln.internal_object(), rn.internal_object()); } }; @@ -7821,20 +7974,22 @@ PUGI__NS_BEGIN else return rhs.attribute() ? false : lhs.node() < rhs.node(); } }; - + PUGI__FN double gen_nan() { #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) - union { float f; uint32_t i; } u[sizeof(float) == sizeof(uint32_t) ? 1 : -1]; - u[0].i = 0x7fc00000; - return u[0].f; + PUGI__STATIC_ASSERT(sizeof(float) == sizeof(uint32_t)); + typedef uint32_t UI; // BCC5 workaround + union { float f; UI i; } u; + u.i = 0x7fc00000; + return u.f; #else // fallback const volatile double zero = 0.0; return zero / zero; #endif } - + PUGI__FN bool is_nan(double value) { #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) @@ -7847,7 +8002,7 @@ PUGI__NS_BEGIN return v != v; #endif } - + PUGI__FN const char_t* convert_number_to_string_special(double value) { #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) @@ -7879,12 +8034,12 @@ PUGI__NS_BEGIN return 0; #endif } - + PUGI__FN bool convert_number_to_boolean(double value) { return (value != 0 && !is_nan(value)); } - + PUGI__FN void truncate_zeros(char* begin, char* end) { while (begin != end && end[-1] == '0') end--; @@ -8005,7 +8160,7 @@ PUGI__NS_BEGIN return xpath_string::from_heap_preallocated(result, s); } - + PUGI__FN bool check_string_to_number_format(const char_t* string) { // parse leading whitespace @@ -8072,7 +8227,7 @@ PUGI__NS_BEGIN return true; } - + PUGI__FN double round_nearest(double value) { return floor(value + 0.5); @@ -8084,17 +8239,17 @@ PUGI__NS_BEGIN // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); } - + PUGI__FN const char_t* qualified_name(const xpath_node& node) { return node.attribute() ? node.attribute().name() : node.node().name(); } - + PUGI__FN const char_t* local_name(const xpath_node& node) { const char_t* name = qualified_name(node); const char_t* p = find_char(name, ':'); - + return p ? p + 1 : name; } @@ -8124,39 +8279,39 @@ PUGI__NS_BEGIN PUGI__FN const char_t* namespace_uri(xml_node node) { namespace_uri_predicate pred = node.name(); - + xml_node p = node; - + while (p) { xml_attribute a = p.find_attribute(pred); - + if (a) return a.value(); - + p = p.parent(); } - + return PUGIXML_TEXT(""); } PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent) { namespace_uri_predicate pred = attr.name(); - + // Default namespace does not apply to attributes if (!pred.prefix) return PUGIXML_TEXT(""); - + xml_node p = parent; - + while (p) { xml_attribute a = p.find_attribute(pred); - + if (a) return a.value(); - + p = p.parent(); } - + return PUGIXML_TEXT(""); } @@ -8169,7 +8324,7 @@ PUGI__NS_BEGIN { char_t* write = buffer; - for (char_t* it = buffer; *it;) + for (char_t* it = buffer; *it; ) { char_t ch = *it++; @@ -8342,11 +8497,11 @@ PUGI__NS_BEGIN result += result << 10; result ^= result >> 6; } - + result += result << 3; result ^= result >> 11; result += result << 15; - + return result; } @@ -8414,7 +8569,7 @@ PUGI__NS_BEGIN break; default: - assert(!"Invalid variable type"); + assert(false && "Invalid variable type"); } } @@ -8435,7 +8590,7 @@ PUGI__NS_BEGIN return lhs->set(static_cast(rhs)->value); default: - assert(!"Invalid variable type"); + assert(false && "Invalid variable type"); return false; } } @@ -8500,9 +8655,9 @@ PUGI__NS_BEGIN else type = sorted; } - + if (type != order) reverse(begin, end); - + return order; } @@ -8522,7 +8677,7 @@ PUGI__NS_BEGIN return *min_element(begin, end, document_order_comparator()); default: - assert(!"Invalid node set type"); + assert(false && "Invalid node set type"); return xpath_node(); } } @@ -8615,7 +8770,7 @@ PUGI__NS_BEGIN { if (_type == xpath_node_set::type_unsorted) sort(_begin, _end, duplicate_comparator()); - + _end = unique(_begin, _end); } @@ -8723,12 +8878,12 @@ PUGI__NS_BEGIN { next(); } - + const char_t* state() const { return _cur; } - + void next() { const char_t* cur = _cur; @@ -8743,7 +8898,7 @@ PUGI__NS_BEGIN case 0: _cur_lexeme = lex_eof; break; - + case '>': if (*(cur+1) == '=') { @@ -8787,7 +8942,7 @@ PUGI__NS_BEGIN _cur_lexeme = lex_equal; break; - + case '+': cur += 1; _cur_lexeme = lex_plus; @@ -8811,7 +8966,7 @@ PUGI__NS_BEGIN _cur_lexeme = lex_union; break; - + case '$': cur += 1; @@ -8829,7 +8984,7 @@ PUGI__NS_BEGIN } _cur_lexeme_contents.end = cur; - + _cur_lexeme = lex_var_ref; } else @@ -8850,7 +9005,7 @@ PUGI__NS_BEGIN _cur_lexeme = lex_close_brace; break; - + case '[': cur += 1; _cur_lexeme = lex_open_square_brace; @@ -8881,7 +9036,7 @@ PUGI__NS_BEGIN _cur_lexeme = lex_slash; } break; - + case '.': if (*(cur+1) == '.') { @@ -8897,7 +9052,7 @@ PUGI__NS_BEGIN while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; _cur_lexeme_contents.end = cur; - + _cur_lexeme = lex_number; } else @@ -8923,7 +9078,7 @@ PUGI__NS_BEGIN _cur_lexeme_contents.begin = cur; while (*cur && *cur != terminator) cur++; _cur_lexeme_contents.end = cur; - + if (!*cur) _cur_lexeme = lex_none; else @@ -8953,7 +9108,7 @@ PUGI__NS_BEGIN _cur_lexeme_contents.begin = cur; while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; - + if (*cur == '.') { cur++; @@ -8986,7 +9141,7 @@ PUGI__NS_BEGIN } _cur_lexeme_contents.end = cur; - + _cur_lexeme = lex_string; } else @@ -9097,7 +9252,7 @@ PUGI__NS_BEGIN axis_preceding_sibling, axis_self }; - + enum nodetest_t { nodetest_none, @@ -9132,7 +9287,7 @@ PUGI__NS_BEGIN }; template const axis_t axis_to_type::axis = N; - + class xpath_ast_node { private: @@ -9252,7 +9407,7 @@ PUGI__NS_BEGIN } } - assert(!"Wrong types"); + assert(false && "Wrong types"); return false; } @@ -9327,7 +9482,7 @@ PUGI__NS_BEGIN } else { - assert(!"Wrong types"); + assert(false && "Wrong types"); return false; } } @@ -9451,7 +9606,7 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_type_node: case nodetest_all: if (is_xpath_attribute(name)) @@ -9460,7 +9615,7 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_all_in_namespace: if (starts_with(name, _data.nodetest) && is_xpath_attribute(name)) { @@ -9468,14 +9623,14 @@ PUGI__NS_BEGIN return true; } break; - + default: ; } return false; } - + bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc) { assert(n); @@ -9491,11 +9646,11 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_type_node: ns.push_back(xml_node(n), alloc); return true; - + case nodetest_type_comment: if (type == node_comment) { @@ -9503,7 +9658,7 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_type_text: if (type == node_pcdata || type == node_cdata) { @@ -9511,7 +9666,7 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_type_pi: if (type == node_pi) { @@ -9519,7 +9674,7 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_pi: if (type == node_pi && n->name && strequal(n->name, _data.nodetest)) { @@ -9527,7 +9682,7 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_all: if (type == node_element) { @@ -9535,7 +9690,7 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_all_in_namespace: if (type == node_element && n->name && starts_with(n->name, _data.nodetest)) { @@ -9545,7 +9700,7 @@ PUGI__NS_BEGIN break; default: - assert(!"Unknown axis"); + assert(false && "Unknown axis"); } return false; @@ -9562,33 +9717,33 @@ PUGI__NS_BEGIN for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute) if (step_push(ns, a, n, alloc) & once) return; - + break; } - + case axis_child: { for (xml_node_struct* c = n->first_child; c; c = c->next_sibling) if (step_push(ns, c, alloc) & once) return; - + break; } - + case axis_descendant: case axis_descendant_or_self: { if (axis == axis_descendant_or_self) if (step_push(ns, n, alloc) & once) return; - + xml_node_struct* cur = n->first_child; - + while (cur) { if (step_push(ns, cur, alloc) & once) return; - + if (cur->first_child) cur = cur->first_child; else @@ -9599,32 +9754,32 @@ PUGI__NS_BEGIN if (cur == n) return; } - + cur = cur->next_sibling; } } - + break; } - + case axis_following_sibling: { for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling) if (step_push(ns, c, alloc) & once) return; - + break; } - + case axis_preceding_sibling: { for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c) if (step_push(ns, c, alloc) & once) return; - + break; } - + case axis_following: { xml_node_struct* cur = n; @@ -9703,7 +9858,7 @@ PUGI__NS_BEGIN break; } - + case axis_ancestor: case axis_ancestor_or_self: { @@ -9712,15 +9867,15 @@ PUGI__NS_BEGIN return; xml_node_struct* cur = n->parent; - + while (cur) { if (step_push(ns, cur, alloc) & once) return; - + cur = cur->parent; } - + break; } @@ -9738,12 +9893,12 @@ PUGI__NS_BEGIN break; } - + default: - assert(!"Unimplemented axis"); + assert(false && "Unimplemented axis"); } } - + template void step_fill(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* p, xpath_allocator* alloc, bool once, T v) { const axis_t axis = T::axis; @@ -9758,15 +9913,15 @@ PUGI__NS_BEGIN return; xml_node_struct* cur = p; - + while (cur) { if (step_push(ns, cur, alloc) & once) return; - + cur = cur->parent; } - + break; } @@ -9782,7 +9937,7 @@ PUGI__NS_BEGIN case axis_following: { xml_node_struct* cur = p; - + while (cur) { if (cur->first_child) @@ -9819,9 +9974,9 @@ PUGI__NS_BEGIN step_fill(ns, p, alloc, once, v); break; } - + default: - assert(!"Unimplemented axis"); + assert(false && "Unimplemented axis"); } } @@ -9863,7 +10018,7 @@ PUGI__NS_BEGIN // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); - + step_fill(ns, *it, stack.result, once, v); if (_right) apply_predicates(ns, size, stack, eval); } @@ -9881,7 +10036,7 @@ PUGI__NS_BEGIN return ns; } - + public: xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) @@ -9896,14 +10051,14 @@ PUGI__NS_BEGIN assert(type == ast_number_constant); _data.number = value; } - + xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) { assert(type == ast_variable); _data.variable = value; } - + xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0) { @@ -9938,25 +10093,25 @@ PUGI__NS_BEGIN { case ast_op_or: return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack); - + case ast_op_and: return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack); - + case ast_op_equal: return compare_eq(_left, _right, c, stack, equal_to()); case ast_op_not_equal: return compare_eq(_left, _right, c, stack, not_equal_to()); - + case ast_op_less: return compare_rel(_left, _right, c, stack, less()); - + case ast_op_greater: return compare_rel(_right, _left, c, stack, less()); case ast_op_less_or_equal: return compare_rel(_left, _right, c, stack, less_equal()); - + case ast_op_greater_or_equal: return compare_rel(_right, _left, c, stack, less_equal()); @@ -9982,43 +10137,43 @@ PUGI__NS_BEGIN case ast_func_boolean: return _left->eval_boolean(c, stack); - + case ast_func_not: return !_left->eval_boolean(c, stack); - + case ast_func_true: return true; - + case ast_func_false: return false; case ast_func_lang: { if (c.n.attribute()) return false; - + xpath_allocator_capture cr(stack.result); xpath_string lang = _left->eval_string(c, stack); - + for (xml_node n = c.n.node(); n; n = n.parent()) { xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); - + if (a) { const char_t* value = a.value(); - + // strnicmp / strncasecmp is not portable for (const char_t* lit = lang.c_str(); *lit; ++lit) { if (tolower_ascii(*lit) != tolower_ascii(*value)) return false; ++value; } - + return *value == 0 || *value == '-'; } } - + return false; } @@ -10047,15 +10202,15 @@ PUGI__NS_BEGIN { case xpath_type_number: return convert_number_to_boolean(eval_number(c, stack)); - + case xpath_type_string: { xpath_allocator_capture cr(stack.result); return !eval_string(c, stack).empty(); } - - case xpath_type_node_set: + + case xpath_type_node_set: { xpath_allocator_capture cr(stack.result); @@ -10063,7 +10218,7 @@ PUGI__NS_BEGIN } default: - assert(!"Wrong expression for return type boolean"); + assert(false && "Wrong expression for return type boolean"); return false; } } @@ -10076,7 +10231,7 @@ PUGI__NS_BEGIN { case ast_op_add: return _left->eval_number(c, stack) + _right->eval_number(c, stack); - + case ast_op_subtract: return _left->eval_number(c, stack) - _right->eval_number(c, stack); @@ -10097,7 +10252,7 @@ PUGI__NS_BEGIN case ast_func_last: return static_cast(c.size); - + case ast_func_position: return static_cast(c.position); @@ -10107,28 +10262,28 @@ PUGI__NS_BEGIN return static_cast(_left->eval_node_set(c, stack, nodeset_eval_all).size()); } - + case ast_func_string_length_0: { xpath_allocator_capture cr(stack.result); return static_cast(string_value(c.n, stack.result).length()); } - + case ast_func_string_length_1: { xpath_allocator_capture cr(stack.result); return static_cast(_left->eval_string(c, stack).length()); } - + case ast_func_number_0: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(string_value(c.n, stack.result).c_str()); } - + case ast_func_number_1: return _left->eval_number(c, stack); @@ -10137,36 +10292,36 @@ PUGI__NS_BEGIN xpath_allocator_capture cr(stack.result); double r = 0; - + xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_all); - + for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) { xpath_allocator_capture cri(stack.result); r += convert_string_to_number(string_value(*it, stack.result).c_str()); } - + return r; } case ast_func_floor: { double r = _left->eval_number(c, stack); - + return r == r ? floor(r) : r; } case ast_func_ceiling: { double r = _left->eval_number(c, stack); - + return r == r ? ceil(r) : r; } case ast_func_round: return round_nearest_nzero(_left->eval_number(c, stack)); - + case ast_variable: { assert(_rettype == _data.variable->type()); @@ -10183,30 +10338,30 @@ PUGI__NS_BEGIN { case xpath_type_boolean: return eval_boolean(c, stack) ? 1 : 0; - + case xpath_type_string: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(eval_string(c, stack).c_str()); } - + case xpath_type_node_set: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(eval_string(c, stack).c_str()); } - + default: - assert(!"Wrong expression for return type number"); + assert(false && "Wrong expression for return type number"); return 0; } - + } } } - + xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack) { assert(_type == ast_func_concat); @@ -10262,11 +10417,11 @@ PUGI__NS_BEGIN { case ast_string_constant: return xpath_string::from_const(_data.string); - + case ast_func_local_name_0: { xpath_node na = c.n; - + return xpath_string::from_const(local_name(na)); } @@ -10276,14 +10431,14 @@ PUGI__NS_BEGIN xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); - + return xpath_string::from_const(local_name(na)); } case ast_func_name_0: { xpath_node na = c.n; - + return xpath_string::from_const(qualified_name(na)); } @@ -10293,14 +10448,14 @@ PUGI__NS_BEGIN xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); - + return xpath_string::from_const(qualified_name(na)); } case ast_func_namespace_uri_0: { xpath_node na = c.n; - + return xpath_string::from_const(namespace_uri(na)); } @@ -10310,7 +10465,7 @@ PUGI__NS_BEGIN xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); - + return xpath_string::from_const(namespace_uri(na)); } @@ -10333,10 +10488,10 @@ PUGI__NS_BEGIN xpath_string p = _right->eval_string(c, swapped_stack); const char_t* pos = find_substring(s.c_str(), p.c_str()); - + return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string(); } - + case ast_func_substring_after: { xpath_allocator_capture cr(stack.temp); @@ -10345,7 +10500,7 @@ PUGI__NS_BEGIN xpath_string s = _left->eval_string(c, swapped_stack); xpath_string p = _right->eval_string(c, swapped_stack); - + const char_t* pos = find_substring(s.c_str(), p.c_str()); if (!pos) return xpath_string(); @@ -10365,19 +10520,19 @@ PUGI__NS_BEGIN size_t s_length = s.length(); double first = round_nearest(_right->eval_number(c, stack)); - + if (is_nan(first)) return xpath_string(); // NaN else if (first >= s_length + 1) return xpath_string(); - + size_t pos = first < 1 ? 1 : static_cast(first); assert(1 <= pos && pos <= s_length + 1); const char_t* rbegin = s.c_str() + (pos - 1); const char_t* rend = s.c_str() + s.length(); - + return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); } - + case ast_func_substring_3: { xpath_allocator_capture cr(stack.temp); @@ -10389,12 +10544,12 @@ PUGI__NS_BEGIN double first = round_nearest(_right->eval_number(c, stack)); double last = first + round_nearest(_right->_next->eval_number(c, stack)); - + if (is_nan(first) || is_nan(last)) return xpath_string(); else if (first >= s_length + 1) return xpath_string(); else if (first >= last) return xpath_string(); else if (last < 1) return xpath_string(); - + size_t pos = first < 1 ? 1 : static_cast(first); size_t end = last >= s_length + 1 ? s_length + 1 : static_cast(last); @@ -10421,7 +10576,7 @@ PUGI__NS_BEGIN char_t* begin = s.data(stack.result); char_t* end = normalize_space(begin); - + return xpath_string::from_heap_preallocated(begin, end); } @@ -10467,10 +10622,10 @@ PUGI__NS_BEGIN { case xpath_type_boolean: return xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); - + case xpath_type_number: return convert_number_to_string(eval_number(c, stack), stack.result); - + case xpath_type_node_set: { xpath_allocator_capture cr(stack.temp); @@ -10480,9 +10635,9 @@ PUGI__NS_BEGIN xpath_node_set_raw ns = eval_node_set(c, swapped_stack, nodeset_eval_first); return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result); } - + default: - assert(!"Wrong expression for return type string"); + assert(false && "Wrong expression for return type string"); return xpath_string(); } } @@ -10521,20 +10676,20 @@ PUGI__NS_BEGIN bool once = eval_once(set.type(), eval); apply_predicate(set, 0, stack, once); - + return set; } - + case ast_func_id: return xpath_node_set_raw(); - + case ast_step: { switch (_axis) { case axis_ancestor: return step_do(c, stack, eval, axis_to_type()); - + case axis_ancestor_or_self: return step_do(c, stack, eval, axis_to_type()); @@ -10543,7 +10698,7 @@ PUGI__NS_BEGIN case axis_child: return step_do(c, stack, eval, axis_to_type()); - + case axis_descendant: return step_do(c, stack, eval, axis_to_type()); @@ -10552,28 +10707,28 @@ PUGI__NS_BEGIN case axis_following: return step_do(c, stack, eval, axis_to_type()); - + case axis_following_sibling: return step_do(c, stack, eval, axis_to_type()); - + case axis_namespace: // namespaced axis is not supported return xpath_node_set_raw(); - + case axis_parent: return step_do(c, stack, eval, axis_to_type()); - + case axis_preceding: return step_do(c, stack, eval, axis_to_type()); case axis_preceding_sibling: return step_do(c, stack, eval, axis_to_type()); - + case axis_self: return step_do(c, stack, eval, axis_to_type()); default: - assert(!"Unknown axis"); + assert(false && "Unknown axis"); return xpath_node_set_raw(); } } @@ -10612,16 +10767,21 @@ PUGI__NS_BEGIN } default: - assert(!"Wrong expression for return type node set"); + assert(false && "Wrong expression for return type node set"); return xpath_node_set_raw(); } } void optimize(xpath_allocator* alloc) { - if (_left) _left->optimize(alloc); - if (_right) _right->optimize(alloc); - if (_next) _next->optimize(alloc); + if (_left) + _left->optimize(alloc); + + if (_right) + _right->optimize(alloc); + + if (_next) + _next->optimize(alloc); optimize_self(alloc); } @@ -10685,7 +10845,7 @@ PUGI__NS_BEGIN _type = ast_opt_compare_attribute; } } - + bool is_posinv_expr() const { switch (_type) @@ -10709,10 +10869,10 @@ PUGI__NS_BEGIN default: if (_left && !_left->is_posinv_expr()) return false; - + for (xpath_ast_node* n = _right; n; n = n->_next) if (!n->is_posinv_expr()) return false; - + return true; } } @@ -10806,7 +10966,8 @@ PUGI__NS_BEGIN { assert(argc <= 1); - if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); + if (argc == 1 && args[0]->rettype() != xpath_type_node_set) + throw_error("Function has to be applied to node set"); return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]); } @@ -10818,13 +10979,15 @@ PUGI__NS_BEGIN case 'b': if (name == PUGIXML_TEXT("boolean") && argc == 1) return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]); - + break; - + case 'c': if (name == PUGIXML_TEXT("count") && argc == 1) { - if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); + if (args[0]->rettype() != xpath_type_node_set) + throw_error("Function has to be applied to node set"); + return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]); } else if (name == PUGIXML_TEXT("contains") && argc == 2) @@ -10833,23 +10996,23 @@ PUGI__NS_BEGIN return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("ceiling") && argc == 1) return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]); - + break; - + case 'f': if (name == PUGIXML_TEXT("false") && argc == 0) return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean); else if (name == PUGIXML_TEXT("floor") && argc == 1) return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]); - + break; - + case 'i': if (name == PUGIXML_TEXT("id") && argc == 1) return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]); - + break; - + case 'l': if (name == PUGIXML_TEXT("last") && argc == 0) return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number); @@ -10857,9 +11020,9 @@ PUGI__NS_BEGIN return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]); else if (name == PUGIXML_TEXT("local-name") && argc <= 1) return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args); - + break; - + case 'n': if (name == PUGIXML_TEXT("name") && argc <= 1) return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args); @@ -10871,21 +11034,21 @@ PUGI__NS_BEGIN return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]); else if (name == PUGIXML_TEXT("number") && argc <= 1) return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); - + break; - + case 'p': if (name == PUGIXML_TEXT("position") && argc == 0) return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number); - + break; - + case 'r': if (name == PUGIXML_TEXT("round") && argc == 1) return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]); break; - + case 's': if (name == PUGIXML_TEXT("string") && argc <= 1) return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); @@ -10906,13 +11069,13 @@ PUGI__NS_BEGIN } break; - + case 't': if (name == PUGIXML_TEXT("translate") && argc == 3) return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("true") && argc == 0) return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean); - + break; default: @@ -10937,37 +11100,37 @@ PUGI__NS_BEGIN return axis_ancestor_or_self; else if (name == PUGIXML_TEXT("attribute")) return axis_attribute; - + break; - + case 'c': if (name == PUGIXML_TEXT("child")) return axis_child; - + break; - + case 'd': if (name == PUGIXML_TEXT("descendant")) return axis_descendant; else if (name == PUGIXML_TEXT("descendant-or-self")) return axis_descendant_or_self; - + break; - + case 'f': if (name == PUGIXML_TEXT("following")) return axis_following; else if (name == PUGIXML_TEXT("following-sibling")) return axis_following_sibling; - + break; - + case 'n': if (name == PUGIXML_TEXT("namespace")) return axis_namespace; - + break; - + case 'p': if (name == PUGIXML_TEXT("parent")) return axis_parent; @@ -10975,13 +11138,13 @@ PUGI__NS_BEGIN return axis_preceding; else if (name == PUGIXML_TEXT("preceding-sibling")) return axis_preceding_sibling; - + break; - + case 's': if (name == PUGIXML_TEXT("self")) return axis_self; - + break; default: @@ -11019,7 +11182,7 @@ PUGI__NS_BEGIN return nodetest_type_text; break; - + default: break; } @@ -11092,12 +11255,12 @@ PUGI__NS_BEGIN { xpath_ast_node* args[2] = {0}; size_t argc = 0; - + xpath_lexer_string function = _lexer.contents(); _lexer.next(); - + xpath_ast_node* last_arg = 0; - + if (_lexer.current() != lex_open_brace) throw_error("Unrecognized function call"); _lexer.next(); @@ -11110,16 +11273,16 @@ PUGI__NS_BEGIN if (_lexer.current() != lex_comma) throw_error("No comma between function arguments"); _lexer.next(); - + xpath_ast_node* n = parse_expression(); - + if (argc < 2) args[argc] = n; else last_arg->set_next(n); argc++; last_arg = n; } - + _lexer.next(); return parse_function(function, argc, args); @@ -11131,7 +11294,7 @@ PUGI__NS_BEGIN return 0; } } - + // FilterExpr ::= PrimaryExpr | FilterExpr Predicate // Predicate ::= '[' PredicateExpr ']' // PredicateExpr ::= Expr @@ -11145,19 +11308,20 @@ PUGI__NS_BEGIN xpath_ast_node* expr = parse_expression(); - if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set"); + if (n->rettype() != xpath_type_node_set) + throw_error("Predicate has to be applied to node set"); n = new (alloc_node()) xpath_ast_node(ast_filter, n, expr, predicate_default); if (_lexer.current() != lex_close_square_brace) throw_error("Unmatched square brace"); - + _lexer.next(); } - + return n; } - + // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep // AxisSpecifier ::= AxisName '::' | '@'? // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' @@ -11175,25 +11339,25 @@ PUGI__NS_BEGIN { axis = axis_attribute; axis_specified = true; - + _lexer.next(); } else if (_lexer.current() == lex_dot) { _lexer.next(); - + return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0); } else if (_lexer.current() == lex_double_dot) { _lexer.next(); - + return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0); } - + nodetest_t nt_type = nodetest_none; xpath_lexer_string nt_name; - + if (_lexer.current() == lex_string) { // node name test @@ -11204,11 +11368,13 @@ PUGI__NS_BEGIN if (_lexer.current() == lex_double_colon) { // parse axis name - if (axis_specified) throw_error("Two axis specifiers in one step"); + if (axis_specified) + throw_error("Two axis specifiers in one step"); axis = parse_axis_name(nt_name, axis_specified); - if (!axis_specified) throw_error("Unknown axis"); + if (!axis_specified) + throw_error("Unknown axis"); // read actual node test _lexer.next(); @@ -11226,40 +11392,42 @@ PUGI__NS_BEGIN } else throw_error("Unrecognized node test"); } - + if (nt_type == nodetest_none) { // node type test or processing-instruction if (_lexer.current() == lex_open_brace) { _lexer.next(); - + if (_lexer.current() == lex_close_brace) { _lexer.next(); nt_type = parse_node_test_type(nt_name); - if (nt_type == nodetest_none) throw_error("Unrecognized node type"); - + if (nt_type == nodetest_none) + throw_error("Unrecognized node type"); + nt_name = xpath_lexer_string(); } else if (nt_name == PUGIXML_TEXT("processing-instruction")) { if (_lexer.current() != lex_quoted_string) throw_error("Only literals are allowed as arguments to processing-instruction()"); - + nt_type = nodetest_pi; nt_name = _lexer.contents(); _lexer.next(); - + if (_lexer.current() != lex_close_brace) throw_error("Unmatched brace near processing-instruction()"); _lexer.next(); } else + { throw_error("Unmatched brace near node type test"); - + } } // QName or NCName:* else @@ -11267,10 +11435,13 @@ PUGI__NS_BEGIN if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:* { nt_name.end--; // erase * - + nt_type = nodetest_all_in_namespace; } - else nt_type = nodetest_name; + else + { + nt_type = nodetest_name; + } } } } @@ -11279,38 +11450,42 @@ PUGI__NS_BEGIN nt_type = nodetest_all; _lexer.next(); } - else throw_error("Unrecognized node test"); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name)); - + else + { + throw_error("Unrecognized node test"); + } + + const char_t* nt_name_copy = alloc_string(nt_name); + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, nt_name_copy); + xpath_ast_node* last = 0; - + while (_lexer.current() == lex_open_square_brace) { _lexer.next(); - + xpath_ast_node* expr = parse_expression(); xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, 0, expr, predicate_default); - + if (_lexer.current() != lex_close_square_brace) throw_error("Unmatched square brace"); _lexer.next(); - + if (last) last->set_next(pred); else n->set_right(pred); - + last = pred; } return n; } - + // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) { xpath_ast_node* n = parse_step(set); - + while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) { lexeme_t l = _lexer.current(); @@ -11318,13 +11493,13 @@ PUGI__NS_BEGIN if (l == lex_double_slash) n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); - + n = parse_step(n); } - + return n; } - + // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath xpath_ast_node* parse_location_path() @@ -11332,7 +11507,7 @@ PUGI__NS_BEGIN if (_lexer.current() == lex_slash) { _lexer.next(); - + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path @@ -11346,17 +11521,17 @@ PUGI__NS_BEGIN else if (_lexer.current() == lex_double_slash) { _lexer.next(); - + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); - + return parse_relative_location_path(n); } // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 return parse_relative_location_path(0); } - + // PathExpr ::= LocationPath // | FilterExpr // | FilterExpr '/' RelativeLocationPath @@ -11372,7 +11547,7 @@ PUGI__NS_BEGIN // '(' in case of it being an expression, string literal, number constant or // function call. - if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || + if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || _lexer.current() == lex_quoted_string || _lexer.current() == lex_number || _lexer.current() == lex_string) { @@ -11380,29 +11555,31 @@ PUGI__NS_BEGIN { // This is either a function call, or not - if not, we shall proceed with location path const char_t* state = _lexer.state(); - + while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state; - + if (*state != '(') return parse_location_path(); // This looks like a function call; however this still can be a node-test. Check it. - if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path(); + if (parse_node_test_type(_lexer.contents()) != nodetest_none) + return parse_location_path(); } - + xpath_ast_node* n = parse_filter_expression(); if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) { lexeme_t l = _lexer.current(); _lexer.next(); - + if (l == lex_double_slash) { - if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set"); + if (n->rettype() != xpath_type_node_set) + throw_error("Step has to be applied to node set"); n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); } - + // select from location path return parse_relative_location_path(n); } @@ -11419,7 +11596,9 @@ PUGI__NS_BEGIN return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr); } else + { return parse_location_path(); + } } struct binary_op_t @@ -11548,13 +11727,11 @@ PUGI__NS_BEGIN xpath_ast_node* parse() { xpath_ast_node* result = parse_expression(); - + + // check if there are unparsed tokens left if (_lexer.current() != lex_eof) - { - // there are still unparsed tokens left, error throw_error("Incorrect query"); - } - + return result; } @@ -11642,7 +11819,7 @@ namespace pugi { assert(_result.error); } - + PUGI__FN const char* xpath_exception::what() const throw() { return _result.error; @@ -11653,15 +11830,15 @@ namespace pugi return _result; } #endif - + PUGI__FN xpath_node::xpath_node() { } - + PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_) { } - + PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_) { } @@ -11670,12 +11847,12 @@ namespace pugi { return _attribute ? xml_node() : _node; } - + PUGI__FN xml_attribute xpath_node::attribute() const { return _attribute; } - + PUGI__FN xml_node xpath_node::parent() const { return _attribute ? _node : _node.parent(); @@ -11689,7 +11866,7 @@ namespace pugi { return (_node || _attribute) ? unspecified_bool_xpath_node : 0; } - + PUGI__FN bool xpath_node::operator!() const { return !(_node || _attribute); @@ -11699,7 +11876,7 @@ namespace pugi { return _node == n._node && _attribute == n._attribute; } - + PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const { return _node != n._node || _attribute != n._attribute; @@ -11750,7 +11927,7 @@ namespace pugi } memcpy(storage, begin_, size_ * sizeof(xpath_node)); - + // deallocate old buffer if (_begin != &_storage) impl::xml_memory::deallocate(_begin); @@ -11761,7 +11938,7 @@ namespace pugi } } -#if __cplusplus >= 201103 +#ifdef PUGIXML_HAS_MOVE PUGI__FN void xpath_node_set::_move(xpath_node_set& rhs) { _type = rhs._type; @@ -11789,12 +11966,12 @@ namespace pugi if (_begin != &_storage) impl::xml_memory::deallocate(_begin); } - + PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(&_storage), _end(&_storage) { _assign(ns._begin, ns._end, ns._type); } - + PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) { if (this == &ns) return *this; @@ -11804,7 +11981,7 @@ namespace pugi return *this; } -#if __cplusplus >= 201103 +#ifdef PUGIXML_HAS_MOVE PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs): _type(type_unsorted), _begin(&_storage), _end(&_storage) { _move(rhs); @@ -11827,17 +12004,17 @@ namespace pugi { return _type; } - + PUGI__FN size_t xpath_node_set::size() const { return _end - _begin; } - + PUGI__FN bool xpath_node_set::empty() const { return _begin == _end; } - + PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const { assert(index < size()); @@ -11848,12 +12025,12 @@ namespace pugi { return _begin; } - + PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const { return _end; } - + PUGI__FN void xpath_node_set::sort(bool reverse) { _type = impl::xpath_sort(_begin, _end, _type, reverse); @@ -11899,7 +12076,7 @@ namespace pugi return static_cast(this)->name; default: - assert(!"Invalid variable type"); + assert(false && "Invalid variable type"); return 0; } } @@ -12004,7 +12181,7 @@ namespace pugi return *this; } -#if __cplusplus >= 201103 +#ifdef PUGIXML_HAS_MOVE PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) @@ -12198,7 +12375,7 @@ namespace pugi impl::xpath_query_impl::destroy(static_cast(_impl)); } -#if __cplusplus >= 201103 +#ifdef PUGIXML_HAS_MOVE PUGI__FN xpath_query::xpath_query(xpath_query&& rhs) { _impl = rhs._impl; @@ -12233,21 +12410,21 @@ namespace pugi PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const { if (!_impl) return false; - + impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; #ifdef PUGIXML_NO_EXCEPTIONS if (setjmp(sd.error_handler)) return false; #endif - + return static_cast(_impl)->root->eval_boolean(c, sd.stack); } - + PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const { if (!_impl) return impl::gen_nan(); - + impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; @@ -12276,7 +12453,7 @@ namespace pugi impl::xpath_string r = impl::evaluate_string_impl(static_cast(_impl), n, sd); size_t full_size = r.length() + 1; - + if (capacity > 0) { size_t size = (full_size < capacity) ? full_size : capacity; @@ -12285,7 +12462,7 @@ namespace pugi memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); buffer[size - 1] = 0; } - + return full_size; } @@ -12398,6 +12575,7 @@ namespace pugi #undef PUGI__NS_END #undef PUGI__FN #undef PUGI__FN_NO_INLINE +#undef PUGI__GETHEADER_IMPL #undef PUGI__GETPAGE_IMPL #undef PUGI__GETPAGE #undef PUGI__NODETYPE @@ -12419,7 +12597,7 @@ namespace pugi #endif /** - * Copyright (c) 2006-2015 Arseny Kapoulkine + * Copyright (c) 2006-2016 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -12432,7 +12610,7 @@ namespace pugi * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND diff --git a/src/rest.cpp b/src/rest.cpp index 1746de1c6cb..0f484c2ffc2 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -96,10 +96,8 @@ wchar_t Rest::GetRestGlyph() const return symc; } -int Rest::GetDefaultLoc(bool hasMultipleLayer, bool isFirstLayer) +int Rest::GetRestLocOffset(int loc) { - int loc = 4; - switch (this->GetActualDur()) { case DUR_MX: loc -= 0; break; case DUR_LG: loc -= 0; break; @@ -115,12 +113,6 @@ int Rest::GetDefaultLoc(bool hasMultipleLayer, bool isFirstLayer) case DUR_256: loc -= 2; break; default: loc -= 1; break; } - if (hasMultipleLayer) { - if (isFirstLayer) - loc += 2; - else - loc -= 2; - } return loc; } diff --git a/src/scoredefinterface.cpp b/src/scoredefinterface.cpp index 58a26407418..6966f2cbc7e 100644 --- a/src/scoredefinterface.cpp +++ b/src/scoredefinterface.cpp @@ -26,6 +26,7 @@ namespace vrv { ScoreDefInterface::ScoreDefInterface() : Interface() , AttCleffingLog() + , AttCleffingVis() , AttKeySigDefaultLog() , AttKeySigDefaultVis() , AttLyricstyle() @@ -37,6 +38,7 @@ ScoreDefInterface::ScoreDefInterface() , AttMultinummeasures() { RegisterInterfaceAttClass(ATT_CLEFFINGLOG); + RegisterInterfaceAttClass(ATT_CLEFFINGVIS); RegisterInterfaceAttClass(ATT_KEYSIGDEFAULTLOG); RegisterInterfaceAttClass(ATT_KEYSIGDEFAULTVIS); RegisterInterfaceAttClass(ATT_LYRICSTYLE); @@ -57,6 +59,7 @@ ScoreDefInterface::~ScoreDefInterface() void ScoreDefInterface::Reset() { ResetCleffingLog(); + ResetCleffingVis(); ResetKeySigDefaultLog(); ResetKeySigDefaultVis(); ResetLyricstyle(); diff --git a/src/section.cpp b/src/section.cpp index 932f28433a8..bd46506b422 100644 --- a/src/section.cpp +++ b/src/section.cpp @@ -76,10 +76,8 @@ void Section::AddChild(Object *child) // Pb //---------------------------------------------------------------------------- -Pb::Pb() : SystemElement("pb-"), AttCommonPart() +Pb::Pb() : SystemElement("pb-") { - RegisterAttClass(ATT_COMMONPART); - Reset(); } @@ -90,17 +88,15 @@ Pb::~Pb() void Pb::Reset() { SystemElement::Reset(); - ResetCommonPart(); } //---------------------------------------------------------------------------- // Sb //---------------------------------------------------------------------------- -Sb::Sb() : SystemElement("pb-"), AttCommonPart() -{ - RegisterAttClass(ATT_COMMONPART); +Sb::Sb() : SystemElement("sb-") +{ Reset(); } @@ -111,7 +107,6 @@ Sb::~Sb() void Sb::Reset() { SystemElement::Reset(); - ResetCommonPart(); } //---------------------------------------------------------------------------- diff --git a/src/staff.cpp b/src/staff.cpp index 6e382d37ddf..c687ea23571 100644 --- a/src/staff.cpp +++ b/src/staff.cpp @@ -140,7 +140,7 @@ int Staff::CalcPitchPosYRel(Doc *doc, int loc) return (loc - staffLocOffset) * doc->GetDrawingUnit(this->m_drawingStaffSize); } -void Staff::AddLegerLineAbove(int count, short left, short right, bool cueSize) +void Staff::AddLegerLineAbove(int count, int left, int right, bool cueSize) { if (cueSize) { if (m_ledgerLinesAboveCue == NULL) m_ledgerLinesAboveCue = new ArrayOfLedgerLines; @@ -152,7 +152,7 @@ void Staff::AddLegerLineAbove(int count, short left, short right, bool cueSize) } } -void Staff::AddLegerLineBelow(int count, short left, short right, bool cueSize) +void Staff::AddLegerLineBelow(int count, int left, int right, bool cueSize) { if (cueSize) { if (m_ledgerLinesBelowCue == NULL) m_ledgerLinesBelowCue = new ArrayOfLedgerLines; @@ -164,7 +164,7 @@ void Staff::AddLegerLineBelow(int count, short left, short right, bool cueSize) } } -void Staff::AddLegerLines(ArrayOfLedgerLines *lines, int count, short left, short right) +void Staff::AddLegerLines(ArrayOfLedgerLines *lines, int count, int left, int right) { assert(lines); @@ -193,11 +193,11 @@ void LedgerLine::Reset() m_dashes.clear(); } -void LedgerLine::AddDash(short left, short right) +void LedgerLine::AddDash(int left, int right) { assert(left < right); - std::list >::iterator iter; + std::list >::iterator iter; // First add the dash for (iter = m_dashes.begin(); iter != m_dashes.end(); iter++) { @@ -206,7 +206,7 @@ void LedgerLine::AddDash(short left, short right) m_dashes.insert(iter, std::make_pair(left, right)); // Merge overlapping dashes - std::list >::iterator previous = m_dashes.begin(); + std::list >::iterator previous = m_dashes.begin(); iter = m_dashes.begin(); iter++; while (iter != m_dashes.end()) { diff --git a/src/svgdevicecontext.cpp b/src/svgdevicecontext.cpp index e62b28e43d2..75baa4eba35 100644 --- a/src/svgdevicecontext.cpp +++ b/src/svgdevicecontext.cpp @@ -200,7 +200,16 @@ void SvgDeviceContext::StartGraphic(Object *object, std::string gClass, std::str assert(att); if (att->HasColor()) { m_currentNode.append_attribute("fill") = att->GetColor().c_str(); - m_currentNode.append_attribute("stroke") = att->GetColor().c_str(); + } + } + + if (object->HasAttClass(ATT_COMMONPART)) { + AttCommonPart *att = dynamic_cast(object); + assert(att); + if (att->HasLabel()) { + pugi::xml_node svgTitle = m_currentNode.prepend_child("title"); + svgTitle.append_attribute("class") = "labelAttr"; + svgTitle.append_child(pugi::node_pcdata).set_value(att->GetLabel().c_str()); } } @@ -346,8 +355,7 @@ void SvgDeviceContext::StartPage() m_currentNode = m_currentNode.append_child("style"); m_currentNode.append_attribute("type") = "text/css"; m_currentNode.append_child(pugi::node_pcdata) - .set_value( - "g.page-margin{font-family:Times;} g.tempo{font-weight:bold;} g.dir, g.dynam {font-style:italic;}"); + .set_value("g.page-margin{font-family:Times;} g.tempo{font-weight:bold;} g.dir, g.dynam {font-style:italic;}"); m_currentNode = m_svgNodeStack.back(); // a graphic for definition scaling @@ -426,7 +434,7 @@ pugi::xml_node SvgDeviceContext::AppendChild(std::string name) return m_currentNode.append_child(name.c_str()); } -// Drawing mething +// Drawing methods void SvgDeviceContext::DrawComplexBezierPath(Point bezier1[4], Point bezier2[4]) { pugi::xml_node pathChild = AppendChild("path"); diff --git a/src/system.cpp b/src/system.cpp index 56e6c82eaad..354fd3cb715 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -367,6 +367,8 @@ int System::AdjustFloatingPostioners(FunctorParams *functorParams) m_systemAligner.Process(params->m_functor, params); params->m_classId = TRILL; m_systemAligner.Process(params->m_functor, params); + params->m_classId = BREATH; + m_systemAligner.Process(params->m_functor, params); params->m_classId = FERMATA; m_systemAligner.Process(params->m_functor, params); params->m_classId = TEMPO; diff --git a/src/trill.cpp b/src/trill.cpp index 0d73bf847dd..e40eba11e59 100644 --- a/src/trill.cpp +++ b/src/trill.cpp @@ -25,7 +25,6 @@ Trill::Trill() : ControlElement("trill-"), TimePointInterface(), AttColor(), Att { RegisterInterface(TimePointInterface::GetAttClasses(), TimePointInterface::IsInterface()); RegisterAttClass(ATT_COLOR); - RegisterAttClass(ATT_ORNAMENTACCID); RegisterAttClass(ATT_PLACEMENT); Reset(); diff --git a/src/tuplet.cpp b/src/tuplet.cpp index 2367d5a2f0a..f49b83fdbf2 100644 --- a/src/tuplet.cpp +++ b/src/tuplet.cpp @@ -28,8 +28,14 @@ namespace vrv { //---------------------------------------------------------------------------- Tuplet::Tuplet() - : LayerElement("tuplet-"), ObjectListInterface(), AttDurationRatio(), AttNumberplacement(), AttTupletVis() + : LayerElement("tuplet-") + , ObjectListInterface() + , AttColor() + , AttDurationRatio() + , AttNumberplacement() + , AttTupletVis() { + RegisterAttClass(ATT_COLOR); RegisterAttClass(ATT_DURATIONRATIO); RegisterAttClass(ATT_NUMBERPLACEMENT); RegisterAttClass(ATT_TUPLETVIS); @@ -44,6 +50,7 @@ Tuplet::~Tuplet() void Tuplet::Reset() { LayerElement::Reset(); + ResetColor(); ResetDurationRatio(); ResetNumberplacement(); ResetTupletVis(); diff --git a/src/view_control.cpp b/src/view_control.cpp index a45b9f86a06..dea4e6f06f2 100644 --- a/src/view_control.cpp +++ b/src/view_control.cpp @@ -19,6 +19,7 @@ #include "attcomparison.h" #include "bboxdevicecontext.h" +#include "breath.h" #include "devicecontext.h" #include "dir.h" #include "doc.h" @@ -71,6 +72,11 @@ void View::DrawControlElement(DeviceContext *dc, ControlElement *element, Measur dc->EndGraphic(element, this); system->AddToDrawingList(element); } + else if (element->Is(BREATH)) { + Breath *breath = dynamic_cast(element); + assert(breath); + DrawBreath(dc, breath, measure, system); + } else if (element->Is(DIR)) { Dir *dir = dynamic_cast(element); assert(dir); @@ -542,6 +548,11 @@ void View::DrawSlur(DeviceContext *dc, Slur *slur, int x1, int x2, Staff *staff, // no start and end, obviously nothing to do... return; } + + if (start->Is(TIMESTAMP_ATTR) || end->Is(TIMESTAMP_ATTR)) { + // fow now ignore slur using tstamps + return; + } if (start->Is(NOTE)) { startNote = dynamic_cast(start); @@ -570,16 +581,16 @@ void View::DrawSlur(DeviceContext *dc, Slur *slur, int x1, int x2, Staff *staff, Layer *layer2 = NULL; // For now, with timestamps, get the first layer. We should eventually look at the @layerident (not implemented) - if (start->Is(TIMESTAMP_ATTR)) - layer1 = dynamic_cast(staff->FindChildByType(LAYER)); - else - layer1 = dynamic_cast(start->GetFirstParent(LAYER)); + //if (start->Is(TIMESTAMP_ATTR)) + // layer1 = dynamic_cast(staff->FindChildByType(LAYER)); + //else + layer1 = dynamic_cast(start->GetFirstParent(LAYER)); // idem - if (end->Is(TIMESTAMP_ATTR)) - layer2 = dynamic_cast(staff->FindChildByType(LAYER)); - else - layer2 = dynamic_cast(end->GetFirstParent(LAYER)); + //if (end->Is(TIMESTAMP_ATTR)) + // layer2 = dynamic_cast(staff->FindChildByType(LAYER)); + //else + layer2 = dynamic_cast(end->GetFirstParent(LAYER)); assert(layer1 && layer2); @@ -1521,6 +1532,43 @@ void View::DrawSylConnectorLines(DeviceContext *dc, int x1, int x2, int y, Syl * } } +void View::DrawBreath(DeviceContext *dc, Breath *breath, Measure *measure, System *system) +{ + assert(dc); + assert(system); + assert(measure); + assert(breath); + + // Cannot draw a breath that has no start position + if (!breath->GetStart()) return; + + dc->StartGraphic(breath, "", breath->GetUuid()); + + int x = breath->GetStart()->GetDrawingX(); + + // use breath mark comma glyph + int code = SMUFL_E4CE_breathMarkComma; + + std::wstring str; + str.push_back(code); + + std::vector::iterator staffIter; + std::vector staffList = breath->GetTstampStaves(measure); + for (staffIter = staffList.begin(); staffIter != staffList.end(); staffIter++) { + system->SetCurrentFloatingPositioner((*staffIter)->GetN(), breath, breath->GetStart(), *staffIter); + int y = breath->GetDrawingY(); + + // Adjust the x position + int drawingX = x - m_doc->GetGlyphWidth(code, (*staffIter)->m_drawingStaffSize, false) / 2; + + dc->SetFont(m_doc->GetDrawingSmuflFont((*staffIter)->m_drawingStaffSize, false)); + DrawSmuflString(dc, drawingX, y, str, false, (*staffIter)->m_drawingStaffSize); + dc->ResetFont(); + } + + dc->EndGraphic(breath, this); +} + void View::DrawDir(DeviceContext *dc, Dir *dir, Measure *measure, System *system) { assert(dc); diff --git a/src/view_element.cpp b/src/view_element.cpp index 112ac1327a6..7ffb7c1445c 100644 --- a/src/view_element.cpp +++ b/src/view_element.cpp @@ -307,7 +307,7 @@ void View::DrawArticPart(DeviceContext *dc, LayerElement *element, Layer *layer, xCorr = m_doc->GetGlyphWidth(code, staff->m_drawingStaffSize, drawingCueSize) / 2; // The position of the next glyph (and for correcting the baseline if necessary int glyphHeight = m_doc->GetGlyphHeight(code, staff->m_drawingStaffSize, drawingCueSize); - + // Center the glyh if necessary if (Artic::IsCentered(*articIter)) { y += (articPart->GetPlace() == STAFFREL_above) ? -(glyphHeight / 2) : (glyphHeight / 2); @@ -883,7 +883,7 @@ void View::DrawMeterSig(DeviceContext *dc, LayerElement *element, Layer *layer, dc->StartGraphic(element, "", element->GetUuid()); - int y = staff->GetDrawingY() - (m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * 4); + int y = staff->GetDrawingY() - m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * (staff->m_drawingLines - 1); int x = element->GetDrawingX(); if (meterSig->GetForm() == meterSigVis_FORM_invis) { @@ -901,7 +901,7 @@ void View::DrawMeterSig(DeviceContext *dc, LayerElement *element, Layer *layer, else if (meterSig->GetForm() == meterSigVis_FORM_num) { DrawMeterSigFigures(dc, x, staff->GetDrawingY(), meterSig->GetCount(), NONE, staff); } - else if (meterSig->GetCount()) { + else if (meterSig->HasCount()) { DrawMeterSigFigures(dc, x, staff->GetDrawingY(), meterSig->GetCount(), meterSig->GetUnit(), staff); } @@ -925,10 +925,6 @@ void View::DrawMRest(DeviceContext *dc, LayerElement *element, Layer *layer, Sta int y = element->GetDrawingY(); - // move it down according to the number of line in the staff - y -= staff->m_drawingLines / 2 * m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize) - - m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize); - if (measure->m_measureAligner.GetMaxTime() >= (DUR_MAX * 2)) { y -= m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize); DrawRestBreve(dc, mRest->GetDrawingX(), y, staff); @@ -1006,7 +1002,7 @@ void View::DrawMultiRest(DeviceContext *dc, LayerElement *element, Layer *layer, // We do not support more than three chars int num = std::min(multiRest->GetNum(), 999); - if (num > 2) { + if (num > 2 || multiRest->GetBlock() == true) { // This is 1/2 the length of the black rectangle length = width - 2 * m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize); @@ -1014,30 +1010,34 @@ void View::DrawMultiRest(DeviceContext *dc, LayerElement *element, Layer *layer, x1 = xCentered - length / 2; x2 = xCentered + length / 2; - // Position centered in third line - y1 = staff->GetDrawingY() - (m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize) / 2) * 5; - y2 = y1 + m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize); + // Position centered in staff + y2 = staff->GetDrawingY() - m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * staff->m_drawingLines; + y1 = y2 + m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize); // Draw the base rect - // make it 8 pixels smaller than the interline space - // these are the two 4 substracted and added - DrawFilledRectangle(dc, x1, y2, x2, y1); + DrawFilledRectangle(dc, x1, y1, x2, y2); // Draw two lines at beginning and end - // make it 8 pixels longer, and 4 pixels width int border = m_doc->GetDrawingUnit(staff->m_drawingStaffSize); - DrawVerticalLine(dc, y1 - border, y2 + border, x1, m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize) * 2); - DrawVerticalLine(dc, y1 - border, y2 + border, x2, m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize) * 2); + DrawFilledRectangle( + dc, x1, y1 + border, x1 + m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize) * 2, y2 - border); + DrawFilledRectangle( + dc, x2 - m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize) * 2, y1 + border, x2, y2 - border); } else { // Draw the base rect x1 = xCentered - m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize) / 3; x2 = xCentered + m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize) / 3; - // Position centered in third line - y1 = staff->GetDrawingY() - (m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize) / 2) * 4; - y2 = y1 + m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize); - DrawFilledRectangle(dc, x1, y2 - 4, x2, y1 + 4); + // Position centered in staff + y1 = staff->GetDrawingY() + - m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize) * int((staff->m_drawingLines) / 2); + if (staff->m_drawingLines > 1) y1 += m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize); + y2 = y1 - m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize); + if (num == 2) + DrawFilledRectangle(dc, x1, y1 + 4, x2, y2 - 4); + else + DrawRestWhole(dc, xCentered, y1, DUR_1, false, staff); } // Draw the text above @@ -1050,8 +1050,9 @@ void View::DrawMultiRest(DeviceContext *dc, LayerElement *element, Layer *layer, TextExtend extend; dc->GetSmuflTextExtent(wtext, &extend); start_offset = (x2 - x1 - extend.m_width) / 2; // calculate offset to center text - DrawSmuflString(dc, x1 + start_offset, staff->GetDrawingY() + 3 * m_doc->GetDrawingUnit(staff->m_drawingStaffSize), - wtext, false); + int y = (staff->GetDrawingY() > y1) ? staff->GetDrawingY() + 3 * m_doc->GetDrawingUnit(staff->m_drawingStaffSize) + : y1 + 3 * m_doc->GetDrawingUnit(staff->m_drawingStaffSize); + DrawSmuflString(dc, x1 + start_offset, y, wtext, false); dc->ResetFont(); dc->EndGraphic(element, this); @@ -1227,8 +1228,9 @@ void View::DrawStem(DeviceContext *dc, LayerElement *element, Layer *layer, Staf dc->StartGraphic(element, "", element->GetUuid()); - DrawVerticalLine(dc, stem->GetDrawingY(), stem->GetDrawingY() - stem->GetDrawingStemLen(), stem->GetDrawingX(), - m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize)); + DrawFilledRectangle(dc, stem->GetDrawingX() - m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize) / 2, + stem->GetDrawingY(), stem->GetDrawingX() + m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize) / 2, + stem->GetDrawingY() - stem->GetDrawingStemLen()); DrawLayerChildren(dc, stem, layer, staff, measure); @@ -1512,8 +1514,10 @@ void View::DrawMRptPart(DeviceContext *dc, int xCentered, wchar_t smuflCode, int TextExtend extend; std::wstring figures = IntToTupletFigures(num); dc->GetSmuflTextExtent(figures, &extend); - dc->DrawMusicText(figures, ToDeviceContextX(xCentered - extend.m_width / 2), - ToDeviceContextY(staff->GetDrawingY() + m_doc->GetDrawingUnit(staff->m_drawingStaffSize))); + int y = (staff->GetDrawingY() > ySymbol) + ? staff->GetDrawingY() + m_doc->GetDrawingUnit(staff->m_drawingStaffSize) + : ySymbol + 3 * m_doc->GetDrawingUnit(staff->m_drawingStaffSize); + dc->DrawMusicText(figures, ToDeviceContextX(xCentered - extend.m_width / 2), ToDeviceContextY(y)); dc->ResetFont(); } } @@ -1563,7 +1567,7 @@ void View::DrawRestWhole(DeviceContext *dc, int x, int y, int valeur, bool cueSi if (valeur == DUR_1) vertic = -vertic; - // look if one line or between line + // look if on line or between line if ((y - staff->GetDrawingY()) % m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize)) { if (valeur == DUR_2) y1 -= vertic; @@ -1571,17 +1575,15 @@ void View::DrawRestWhole(DeviceContext *dc, int x, int y, int valeur, bool cueSi y1 += vertic; } - y2 = y1 + vertic; - DrawFilledRectangle(dc, x1, y1, x2, y2); - - off /= 2; - x1 -= off; - x2 += off; - // legder line if (y > (int)staff->GetDrawingY() - || y < staff->GetDrawingY() - m_doc->GetDrawingStaffSize(staff->m_drawingStaffSize)) - DrawHorizontalLine(dc, x1, x2, y1, m_doc->GetDrawingStaffLineWidth(staff->m_drawingStaffSize)); + || y < staff->GetDrawingY() + - (staff->m_drawingLines - 1) * m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize)) + DrawHorizontalLine( + dc, x1 - off / 2, x2 + off / 2, y1, m_doc->GetDrawingStaffLineWidth(staff->m_drawingStaffSize) * 1.75); + + y2 = y1 + vertic; + DrawFilledRectangle(dc, x1, y1, x2, y2); } //---------------------------------------------------------------------------- diff --git a/src/view_mensural.cpp b/src/view_mensural.cpp index 56af571f785..450fccaffaf 100644 --- a/src/view_mensural.cpp +++ b/src/view_mensural.cpp @@ -128,6 +128,11 @@ void View::DrawMensuralNote(DeviceContext *dc, LayerElement *element, Layer *lay DrawMensuralStem(dc, note, staff, stemDir, radius, xStem, noteY); } + + /************ Draw children (verse / syl) ************/ + + DrawLayerChildren(dc, note, layer, staff, measure); + } void View::DrawMensuralRest(DeviceContext *dc, LayerElement *element, Layer *layer, Staff *staff, Measure *measure) diff --git a/src/view_page.cpp b/src/view_page.cpp index 5dd810ce969..739455e5943 100644 --- a/src/view_page.cpp +++ b/src/view_page.cpp @@ -252,7 +252,7 @@ void View::DrawStaffGrp( StaffDef *lastDef = dynamic_cast(staffDefs->back()); if (!firstDef || !lastDef) { - LogDebug("Could not get staffDef while drawing staffGrp - Vrv::DrawStaffGrp"); + LogDebug("Could not get staffDef while drawing staffGrp - DrawStaffGrp"); return; } @@ -263,7 +263,7 @@ void View::DrawStaffGrp( Staff *last = dynamic_cast(measure->FindChildByAttComparison(&comparisonLast, 1)); if (!first || !last) { - LogDebug("Could not get staff (%d; %d) while drawing staffGrp - Vrv::DrawStaffGrp", firstDef->GetN(), + LogDebug("Could not get staff (%d; %d) while drawing staffGrp - DrawStaffGrp", firstDef->GetN(), lastDef->GetN()); return; } @@ -546,7 +546,7 @@ void View::DrawBarLines(DeviceContext *dc, Measure *measure, StaffGrp *staffGrp, Staff *staff = dynamic_cast(measure->FindChildByAttComparison(&comparison, 1)); if (!staff) { LogDebug( - "Could not get staff (%d) while drawing staffGrp - Vrv::DrawBarLines", childStaffDef->GetN()); + "Could not get staff (%d) while drawing staffGrp - DrawBarLines", childStaffDef->GetN()); continue; } int y_top = staff->GetDrawingY(); @@ -571,7 +571,7 @@ void View::DrawBarLines(DeviceContext *dc, Measure *measure, StaffGrp *staffGrp, StaffDef *lastDef = dynamic_cast(staffDefs->back()); if (!firstDef || !lastDef) { - LogDebug("Could not get staffDef while drawing staffGrp - Vrv::DrawStaffGrp"); + LogDebug("Could not get staffDef while drawing staffGrp - DrawStaffGrp"); return; } @@ -582,7 +582,7 @@ void View::DrawBarLines(DeviceContext *dc, Measure *measure, StaffGrp *staffGrp, Staff *last = dynamic_cast(measure->FindChildByAttComparison(&comparisonLast, 1)); if (!first || !last) { - LogDebug("Could not get staff (%d; %d) while drawing staffGrp - Vrv::DrawStaffGrp", firstDef->GetN(), + LogDebug("Could not get staff (%d; %d) while drawing staffGrp - DrawStaffGrp", firstDef->GetN(), lastDef->GetN()); return; } @@ -604,7 +604,7 @@ void View::DrawBarLines(DeviceContext *dc, Measure *measure, StaffGrp *staffGrp, AttCommonNComparison comparison(STAFF, childStaffDef->GetN()); Staff *staff = dynamic_cast(measure->FindChildByAttComparison(&comparison, 1)); if (!staff) { - LogDebug("Could not get staff (%d) while drawing staffGrp - Vrv::DrawBarLines", + LogDebug("Could not get staff (%d) while drawing staffGrp - DrawBarLines", childStaffDef->GetN()); continue; } @@ -830,7 +830,7 @@ void View::DrawLedgerLines(DeviceContext *dc, Staff *staff, ArrayOfLedgerLines * dc->SetBrush(m_currentColour, AxSOLID); ArrayOfLedgerLines::iterator iter; - std::list >::iterator iterDashes; + std::list >::iterator iterDashes; // First add the dash for (iter = lines->begin(); iter != lines->end(); iter++) { diff --git a/src/view_text.cpp b/src/view_text.cpp index 79f8f6a48e7..4c66731b835 100644 --- a/src/view_text.cpp +++ b/src/view_text.cpp @@ -19,6 +19,7 @@ #include "devicecontext.h" #include "doc.h" #include "fb.h" +#include "smufl.h" #include "style.h" #include "text.h" #include "vrv.h" @@ -47,7 +48,7 @@ void View::DrawHarmString(DeviceContext *dc, int x, int y, std::wstring s) std::size_t prev_pos = 0, pos; while ((pos = s.find_first_of(L"\u266D\u266E\u266F", prev_pos)) != std::wstring::npos) { - // If pos if > than the previous, it is the substring to exctrace + // If pos is > than the previous, it is the substring to extract if (pos > prev_pos) { std::wstring substr = s.substr(prev_pos, pos - prev_pos); dc->DrawText(UTF16to8(substr), substr); @@ -59,13 +60,13 @@ void View::DrawHarmString(DeviceContext *dc, int x, int y, std::wstring s) std::wstring accid = s.substr(pos, 1); std::wstring smufl_accid; if (accid == L"\u266D") { // MUSIC FLAT SIGN - smufl_accid.push_back(0xE260); + smufl_accid.push_back(SMUFL_E260_accidentalFlat); } - else if (accid == L"\u266E") { // MUSIC FLAT SIGN - smufl_accid.push_back(0xE261); + else if (accid == L"\u266E") { // MUSIC NATURAL SIGN + smufl_accid.push_back(SMUFL_E261_accidentalNatural); } else if (accid == L"\u266F") { // MUSIC SHARP SIGN - smufl_accid.push_back(0xE262); + smufl_accid.push_back(SMUFL_E262_accidentalSharp); } else { smufl_accid.push_back(0xE26D); diff --git a/src/view_tuplet.cpp b/src/view_tuplet.cpp index bdc1b35ab7b..1211530e6bc 100644 --- a/src/view_tuplet.cpp +++ b/src/view_tuplet.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // Name: view_tuplet.cpp -// Author: Rodolfo Zitellini +// Author: Rodolfo Zitellini and Klaus Rettinghaus // Created: 21/08/2012 // Copyright (c) Authors and others. All rights reserved. ///////////////////////////////////////////////////////////////////////////// @@ -38,19 +38,40 @@ bool View::OneBeamInTuplet(Tuplet *tuplet) ArrayOfObjects elems; // Are we contained in a beam? - if (tuplet->GetFirstParent(BEAM, MAX_BEAM_DEPTH) && (tuplet->GetNoteCount() != 0)) return true; + if (tuplet->GetFirstParent(BEAM, 1) && (tuplet->GetNoteCount() != 0)) { + // is only the tuplet beamed and no other tuplet contained? + currentBeam = dynamic_cast(tuplet->GetFirstParent(BEAM, MAX_BEAM_DEPTH)); + if ((currentBeam->GetChildCount() == 1) && (tuplet->GetChildCount(TUPLET) == 0)) return true; + } + + // Do we contain a beam? + if ((tuplet->GetChildCount() == 1) && (tuplet->GetChildCount(BEAM) == 1)) return true; - // No we contain a beam? Go on and search for it in the children - for (int i = 0; i < tuplet->GetChildCount(); i++) { - currentBeam = dynamic_cast(tuplet->GetChild(i)); + return false; +} + +int View::NestedTuplets(Object *object) +{ + assert(object); - // first child is not a beam, or it is a beam but we have more than one child - if (!currentBeam || tuplet->GetChildCount() > 1) { - return false; + int tupletDepth = 1; + + for (int i = 0; i < object->GetChildCount(); i++) { + int tupletCount = 1; + + // check how many nested tuplets there are + if ((object->GetChild(i))->Is(TUPLET)) { + tupletCount += NestedTuplets(object->GetChild(i)); } + // and don't forget beams + if ((object->GetChild(i))->Is(BEAM)) { + tupletCount = NestedTuplets(object->GetChild(i)); + } + + tupletDepth = tupletCount > tupletDepth ? tupletCount : tupletDepth; } - return true; + return tupletDepth; } /** @@ -96,160 +117,145 @@ data_STEMDIRECTION View::GetTupletCoordinates(Tuplet *tuplet, Layer *layer, Poin LayerElement *firstElement = dynamic_cast(tupletChildren->front()); LayerElement *lastElement = dynamic_cast(tupletChildren->back()); - // AllNotesBeamed tries to figure out if all the notes are in the same beam - if (OneBeamInTuplet(tuplet)) { + // There are unbeamed notes of two different beams + // treat all the notes as unbeamed + int ups = 0, downs = 0; // quantity of up- and down-stems + + // In this case use the center of the notehead to calculate the exact center + // as it looks better + x = firstElement->GetDrawingX() + + (lastElement->GetDrawingX() - firstElement->GetDrawingX() + lastElement->GetSelfX2()) / 2; + + // Return the start and end position for the brackets + // starting from the first edge and last of the BBoxes + start->x = firstElement->GetSelfX1() + firstElement->GetDrawingX(); + end->x = lastElement->GetSelfX2() + lastElement->GetDrawingX(); + + // The first step is to calculate all the stem directions + // cycle into the elements and count the up and down dirs + ListOfObjects::iterator iter = tupletChildren->begin(); + while (iter != tupletChildren->end()) { + if ((*iter)->Is(NOTE)) { + Note *currentNote = dynamic_cast(*iter); + assert(currentNote); + if (currentNote->GetDrawingStemDir() == STEMDIRECTION_up) + ups++; + else if (currentNote->GetDrawingStemDir() == STEMDIRECTION_down) + downs++; + } + ++iter; + } + // true means up + direction = ups > downs ? STEMDIRECTION_up : STEMDIRECTION_down; - // yes they are in a beam - x = firstElement->GetDrawingX() - + (lastElement->GetDrawingX() - firstElement->GetDrawingX() + lastElement->GetSelfX2()) / 2; + // if ups or downs are 0, it means all the stems go in the same direction + if (ups == 0 || downs == 0) { - // align the center point at the exact center of the first an last stem - // TUPLET_OFFSET is summed so it does not collide with the stem Note *firstNote = dynamic_cast(tuplet->FindChildByType(NOTE)); Note *lastNote = dynamic_cast(tuplet->FindChildByType(NOTE, UNLIMITED_DEPTH, BACKWARD)); + // Calculate the average between the first and last stem + // set center, start and end too. y = firstElement->GetDrawingY(); if (firstNote && lastNote) { - if (firstNote->GetDrawingStemDir() == STEMDIRECTION_up) + if (direction == STEMDIRECTION_up) { // up y = lastNote->GetDrawingStemEnd(lastNote).y + (firstNote->GetDrawingStemEnd(firstNote).y - lastNote->GetDrawingStemEnd(lastNote).y) / 2 - + TUPLET_OFFSET; - else + + TUPLET_OFFSET * NestedTuplets(tuplet); + start->y = firstNote->GetDrawingStemEnd(firstNote).y + TUPLET_OFFSET * NestedTuplets(tuplet); + end->y = lastNote->GetDrawingStemEnd(lastNote).y + TUPLET_OFFSET * NestedTuplets(tuplet); + } + else { y = lastNote->GetDrawingStemEnd(lastNote).y + (firstNote->GetDrawingStemEnd(firstNote).y - lastNote->GetDrawingStemEnd(lastNote).y) / 2 - - TUPLET_OFFSET; + - TUPLET_OFFSET * NestedTuplets(tuplet); + start->y = firstNote->GetDrawingStemEnd(firstNote).y - TUPLET_OFFSET * NestedTuplets(tuplet); + end->y = lastNote->GetDrawingStemEnd(lastNote).y - TUPLET_OFFSET * NestedTuplets(tuplet); + } + } + // or there are only rests and spaces + else { + // it should take the glyph height into account + y = lastElement->GetDrawingY() + (firstElement->GetDrawingY() - lastElement->GetDrawingY()) / 2 + + 2.5 * TUPLET_OFFSET; + start->y = firstElement->GetDrawingY() + 2.5 * TUPLET_OFFSET; + end->y = lastElement->GetDrawingY() + 2.5 * TUPLET_OFFSET; + // set it back to up + direction = STEMDIRECTION_up; } - // Copy the generated coordinates - center->x = x; - center->y = y; - if (firstNote) direction = firstNote->GetDrawingStemDir(); // stem direction is the same for all notes - } - else { - // There are unbeamed notes of two different beams - // treat all the notes as unbeamed - int ups = 0, downs = 0; // quantity of up- and down-stems - - // In this case use the center of the notehead to calculate the exact center - // as it looks better - x = firstElement->GetDrawingX() - + (lastElement->GetDrawingX() - firstElement->GetDrawingX() + lastElement->GetSelfX2()) / 2; - - // Return the start and end position for the brackes - // starting from the first edge and last of the BBoxes - start->x = firstElement->GetSelfX1() + firstElement->GetDrawingX(); - end->x = lastElement->GetSelfX2() + lastElement->GetDrawingX(); - - // The first step is to calculate all the stem directions - // cycle into the elements and count the up and down dirs - ListOfObjects::iterator iter = tupletChildren->begin(); + // Now we cycle again in all the intermediate notes (i.e. we start from the second note + // and stop at last -1) + // We will see if the position of the note is more (or less for down stems) of the calculated + // average. In this case we offset down or up all the points + iter = tupletChildren->begin(); while (iter != tupletChildren->end()) { if ((*iter)->Is(NOTE)) { Note *currentNote = dynamic_cast(*iter); assert(currentNote); - if (currentNote->GetDrawingStemDir() == STEMDIRECTION_up) - ups++; - else - downs++; - } - ++iter; - } - // true means up - direction = ups > downs ? STEMDIRECTION_up : STEMDIRECTION_down; - - // if ups or downs are 0, it means all the stems go in the same direction - if (ups == 0 || downs == 0) { - - Note *firstNote = dynamic_cast(tuplet->FindChildByType(NOTE)); - Note *lastNote = dynamic_cast(tuplet->FindChildByType(NOTE, UNLIMITED_DEPTH, BACKWARD)); - - // Calculate the average between the first and last stem - // set center, start and end too. - y = firstElement->GetDrawingY(); - if (firstNote && lastNote) { - if (direction == STEMDIRECTION_up) { // up - y = lastNote->GetDrawingStemEnd(lastNote).y - + (firstNote->GetDrawingStemEnd(firstNote).y - lastNote->GetDrawingStemEnd(lastNote).y) / 2 - + TUPLET_OFFSET; - start->y = firstNote->GetDrawingStemEnd(firstNote).y + TUPLET_OFFSET; - end->y = lastNote->GetDrawingStemEnd(lastNote).y + TUPLET_OFFSET; + + if (direction == STEMDIRECTION_up) { + // The note is more than the avg, adjust to y the difference + // from this note to the avg + if (currentNote->GetDrawingStemEnd(currentNote).y + TUPLET_OFFSET > y) { + int offset = y + - (currentNote->GetDrawingStemEnd(currentNote).y + TUPLET_OFFSET * NestedTuplets(tuplet)); + y -= offset; + end->y -= offset; + start->y -= offset; + } } else { - y = lastNote->GetDrawingStemEnd(lastNote).y - + (firstNote->GetDrawingStemEnd(firstNote).y - lastNote->GetDrawingStemEnd(lastNote).y) / 2 - - TUPLET_OFFSET; - start->y = firstNote->GetDrawingStemEnd(firstNote).y - TUPLET_OFFSET; - end->y = lastNote->GetDrawingStemEnd(lastNote).y - TUPLET_OFFSET; + if (currentNote->GetDrawingStemEnd(currentNote).y - TUPLET_OFFSET < y) { + int offset = y + - (currentNote->GetDrawingStemEnd(currentNote).y - TUPLET_OFFSET * NestedTuplets(tuplet)); + y -= offset; + end->y -= offset; + start->y -= offset; + } } } + ++iter; + } + } + else { + // two-directional beams + // this case is similar to the above, but the bracket is only horizontal + // y is 0 because the final y pos is above the tallest stem + y = 0; - // Now we cycle again in all the intermediate notes (i.e. we start from the second note - // and stop at last -1) - // We will see if the position of the note is more (or less for down stems) of the calculated - // average. In this case we offset down or up all the points - iter = tupletChildren->begin(); - while (iter != tupletChildren->end()) { - if ((*iter)->Is(NOTE)) { - Note *currentNote = dynamic_cast(*iter); - assert(currentNote); + // Find the tallest stem and set y to it (with the offset distance) + iter = tupletChildren->begin(); + while (iter != tupletChildren->end()) { + if ((*iter)->Is(NOTE)) { + Note *currentNote = dynamic_cast(*iter); + assert(currentNote); + if (currentNote->GetDrawingStemDir() == direction) { if (direction == STEMDIRECTION_up) { - // The note is more than the avg, adjust to y the difference - // from this note to the avg - if (currentNote->GetDrawingStemEnd(currentNote).y + TUPLET_OFFSET > y) { - int offset = y - (currentNote->GetDrawingStemEnd(currentNote).y + TUPLET_OFFSET); - y -= offset; - end->y -= offset; - start->y -= offset; - } + if (y == 0 + || currentNote->GetDrawingStemEnd(currentNote).y + TUPLET_OFFSET * NestedTuplets(tuplet) + >= y) + y = currentNote->GetDrawingStemEnd(currentNote).y + TUPLET_OFFSET * NestedTuplets(tuplet); } else { - if (currentNote->GetDrawingStemEnd(currentNote).y - TUPLET_OFFSET < y) { - int offset = y - (currentNote->GetDrawingStemEnd(currentNote).y - TUPLET_OFFSET); - y -= offset; - end->y -= offset; - start->y -= offset; - } + if (y == 0 + || currentNote->GetDrawingStemEnd(currentNote).y - TUPLET_OFFSET * NestedTuplets(tuplet) + <= y) + y = currentNote->GetDrawingStemEnd(currentNote).y - TUPLET_OFFSET * NestedTuplets(tuplet); } } - ++iter; - } - } - else { - // two-directional beams - // this case is similar to the above, but the bracket is only horizontal - // y is 0 because the final y pos is above the tallest stem - y = 0; - - // Find the tallest stem and set y to it (with the offset distance) - iter = tupletChildren->begin(); - while (iter != tupletChildren->end()) { - if ((*iter)->Is(NOTE)) { - Note *currentNote = dynamic_cast(*iter); - assert(currentNote); - - if (currentNote->GetDrawingStemDir() == direction) { - if (direction == STEMDIRECTION_up) { - if (y == 0 || currentNote->GetDrawingStemEnd(currentNote).y + TUPLET_OFFSET >= y) - y = currentNote->GetDrawingStemEnd(currentNote).y + TUPLET_OFFSET; - } - else { - if (y == 0 || currentNote->GetDrawingStemEnd(currentNote).y - TUPLET_OFFSET <= y) - y = currentNote->GetDrawingStemEnd(currentNote).y - TUPLET_OFFSET; - } - } - else { - // do none for now - // but if a notehead with a reversed stem is taller that the last - // calculated y, we need to offset - } + else { + // do none for now + // but if a notehead with a reversed stem is taller that the last + // calculated y, we need to offset } - ++iter; } - - // end and start are on the same line (and so il center when set later) - end->y = start->y = y; + ++iter; } + + // end and start are on the same line (and so il center when set later) + end->y = start->y = y; } center->x = x; @@ -274,77 +280,84 @@ void View::DrawTupletPostponed(DeviceContext *dc, Tuplet *tuplet, Layer *layer, TextExtend extend; std::wstring notes; - bool drawingCueSize = tuplet->IsCueSize(); - - dc->SetFont(m_doc->GetDrawingSmuflFont(staff->m_drawingStaffSize, drawingCueSize)); + Point start, end, center; + data_STEMDIRECTION direction = GetTupletCoordinates(tuplet, layer, &start, &end, ¢er); + int x1 = center.x, x2 = center.x; - if (tuplet->GetNum() > 0) { + // draw tuplet numerator + if ((tuplet->GetNum() > 0) && (tuplet->GetNumVisible() != BOOLEAN_false)) { + bool drawingCueSize = tuplet->IsCueSize(); + dc->SetFont(m_doc->GetDrawingSmuflFont(staff->m_drawingStaffSize, drawingCueSize)); notes = IntToTupletFigures((short int)tuplet->GetNum()); + if (tuplet->GetNumFormat() == tupletVis_NUMFORMAT_ratio) { + notes.push_back(SMUFL_E88A_tupletColon); + notes = notes + IntToTupletFigures((short int)tuplet->GetNumbase()); + } dc->GetSmuflTextExtent(notes, &extend); - } - - Point start, end, center; - data_STEMDIRECTION direction = GetTupletCoordinates(tuplet, layer, &start, &end, ¢er); - // Calculate position for number 0x82 - // since the number is slanted, move the center left - // by 4 pixels so it seems more centered to the eye - int txt_x = center.x - (extend.m_width / 2); - // we need to move down the figure of half of it height, which is about an accid width; - // also, cue size is not supported. Does it has to? - int txt_y = center.y - m_doc->GetGlyphWidth(SMUFL_E262_accidentalSharp, staff->m_drawingStaffSize, drawingCueSize); + // Calculate position for number 0x82 + // since the number is slanted, move the center left + int txt_x = x1 - (extend.m_width / 2); + // and move it further, when it is under the stave + if (direction == STEMDIRECTION_down) { + txt_x -= staff->m_drawingStaffSize; + } + // we need to move down the figure of half of it height, which is about an accid width; + // also, cue size is not supported. Does it has to? + int txt_y + = center.y - m_doc->GetGlyphWidth(SMUFL_E262_accidentalSharp, staff->m_drawingStaffSize, drawingCueSize); - if (tuplet->GetNum() && (tuplet->GetNumVisible() != BOOLEAN_false)) { DrawSmuflString(dc, txt_x, txt_y, notes, false, staff->m_drawingStaffSize); - } - dc->ResetFont(); + // x1 = 10 pixels before the number + x1 = txt_x - 40; + // x2 = just after, the number is abundant so I do not add anything + x2 = txt_x + extend.m_width + 20; + + dc->ResetFont(); + } // Nothing to do if the bracket is not visible if (tuplet->GetBracketVisible() == BOOLEAN_false) { return; } + // If all tuplets beamed draw no bracket by default + if (OneBeamInTuplet(tuplet) && !(tuplet->GetBracketVisible() == BOOLEAN_true)) { + return; + } int verticalLine = m_doc->GetDrawingUnit(100); dc->SetPen(m_currentColour, m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize), AxSOLID); - // Start is 0 when no line is necessary (i.e. beamed notes) - if (start.x > 0) { - // Draw the bracket, interrupt where the number is + // Draw the bracket, interrupt where the number is - // get the slope - double m = (double)(start.y - end.y) / (double)(start.x - end.x); + // get the slope + double m = (double)(start.y - end.y) / (double)(start.x - end.x); - // x = 10 pixels before the number - int x = txt_x - 40; - // xa = just after, the number is abundant so I do not add anything - int xa = txt_x + extend.m_width + 20; + // calculate the y coords in the slope + double y1 = (double)start.y + m * (x1 - (double)start.x); + double y2 = (double)start.y + m * (x2 - (double)start.x); - // calculate the y coords in the slope - double y1 = (double)start.y + m * (x - (double)start.x); - double y2 = (double)start.y + m * (xa - (double)start.x); - - if (tuplet->GetNumVisible() == BOOLEAN_false) { - // one single line - dc->DrawLine(start.x, ToDeviceContextY(start.y), end.x, ToDeviceContextY((int)y1)); - } - else { - // first line - dc->DrawLine(start.x, ToDeviceContextY(start.y), (int)x, ToDeviceContextY((int)y1)); - // second line after gap - dc->DrawLine((int)xa, ToDeviceContextY((int)y2), end.x, ToDeviceContextY(end.y)); - } + if (tuplet->GetNumVisible() == BOOLEAN_false) { + // one single line + dc->DrawLine(start.x, ToDeviceContextY(start.y), end.x, ToDeviceContextY(end.y)); + } + else { + // first line + dc->DrawLine(start.x, ToDeviceContextY(start.y), (int)x1, ToDeviceContextY((int)y1)); + // second line after gap + dc->DrawLine((int)x2, ToDeviceContextY((int)y2), end.x, ToDeviceContextY(end.y)); + } - // vertical bracket lines - if (direction == STEMDIRECTION_up) { - dc->DrawLine(start.x, ToDeviceContextY(start.y), start.x, ToDeviceContextY(start.y - verticalLine)); - dc->DrawLine(end.x, ToDeviceContextY(end.y), end.x, ToDeviceContextY(end.y - verticalLine)); - } - else { - dc->DrawLine(start.x, ToDeviceContextY(start.y), start.x, ToDeviceContextY(start.y + verticalLine)); - dc->DrawLine(end.x, ToDeviceContextY(end.y), end.x, ToDeviceContextY(end.y + verticalLine)); - } + // vertical bracket lines + if (direction == STEMDIRECTION_up) { + dc->DrawLine(start.x, ToDeviceContextY(start.y), start.x, ToDeviceContextY(start.y - verticalLine)); + dc->DrawLine(end.x, ToDeviceContextY(end.y), end.x, ToDeviceContextY(end.y - verticalLine)); + } + else { + dc->DrawLine(start.x, ToDeviceContextY(start.y), start.x, ToDeviceContextY(start.y + verticalLine)); + dc->DrawLine(end.x, ToDeviceContextY(end.y), end.x, ToDeviceContextY(end.y + verticalLine)); } dc->ResetPen(); diff --git a/tools/main.cpp b/tools/main.cpp index b727a43b135..eb08707212b 100644 --- a/tools/main.cpp +++ b/tools/main.cpp @@ -57,7 +57,7 @@ bool dir_exists(string dir) void display_version() { - cerr << "Verovio " << vrv::GetVersion() << endl; + cerr << "Verovio " << GetVersion() << endl; } void display_usage()