    //=============================================================================
    //  MuseScore
    //  Linux Music Score Editor
    //
    //  Copyright (C) 2013 Werner Schweer and others
    //
    //  This program is free software; you can redistribute it and/or modify
    //  it under the terms of the GNU General Public License version 2.
    //
    //  This program is distributed in the hope that it will be useful,
    //  but WITHOUT ANY WARRANTY; without even the implied warranty of
    //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    //  GNU General Public License for more details.
    //
    //  You should have received a copy of the GNU General Public License
    //  along with this program; if not, write to the Free Software
    //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    //=============================================================================

    //    CapXML import filter
    //    Supports the CapXML 1.0 file format version 1.0.8 (capella 2008)
    //    The implementation shares as much code as possible with the capella
    //    (.cap) importer (capella.cpp and capella.h)
    //    If statements in the parser match the element order in the schema definition

    #include <assert.h>
    #include "libmscore/score.h"
    #include "thirdparty/qzip/qzipreader_p.h"
    #include "capella.h"

    namespace Ms {

    //---------------------------------------------------------
    //   capxReadFont
    //---------------------------------------------------------

    static QFont capxReadFont(XmlReader& e)
          {
          QFont f;
          QString family = e.attribute("face");
          if (family != "")
                f.setFamily(family);
          qreal pointSize = e.doubleAttribute("height", 0);
          if (pointSize > 0.5)
                f.setPointSizeF(pointSize);
          int weight = e.intAttribute("weight");
          if (weight < 200)
                f.setWeight(QFont::Light);
          else if (weight < 550)
                f.setWeight(QFont::Normal);
          else
                f.setWeight(QFont::Bold);
          f.setItalic(e.attribute("italic", "false") == "true");
          // qDebug("capxReadFont family '%s' ps %g w %d it '%s'", qPrintable(family), pointSize, weight, qPrintable(italic));
          e.readNext();
          return f;
          }

    //---------------------------------------------------------
    //   qstring2timestep -- convert string to TIMESTEP
    //---------------------------------------------------------

    static bool qstring2timestep(QString& str, TIMESTEP& tstp)
          {
          if      (str == "1/1")   { tstp = TIMESTEP::D1;      return true; }
          else if (str == "1/2")   { tstp = TIMESTEP::D2;      return true; }
          else if (str == "1/4")   { tstp = TIMESTEP::D4;      return true; }
          else if (str == "1/8")   { tstp = TIMESTEP::D8;      return true; }
          else if (str == "1/16")  { tstp = TIMESTEP::D16;     return true; }
          else if (str == "1/32")  { tstp = TIMESTEP::D32;     return true; }
          else if (str == "1/64")  { tstp = TIMESTEP::D64;     return true; }
          else if (str == "1/128") { tstp = TIMESTEP::D128;    return true; }
          else if (str == "2/1")   { tstp = TIMESTEP::D_BREVE; return true; }
          return false;
          }

    //---------------------------------------------------------
    //   BasicDrawObj::readCapx -- capx equivalent of BasicDrawObj::read
    //---------------------------------------------------------

    void BasicDrawObj::readCapx(XmlReader& e)
          {
          nNotes = e.intAttribute("noteRange", 0);
          qDebug("nNotes %d", nNotes);
          e.readNext();
          }

    //---------------------------------------------------------
    //   BasicDurationalObj::readCapxDisplay -- capx equivalent of BasicDurationalObj::read
    //   reads the <display> element only
    //---------------------------------------------------------

    void BasicDurationalObj::readCapxDisplay(XmlReader& e)
          {
          invisible = e.attribute("invisible") == "true";
          e.readNext();
          }

    //---------------------------------------------------------
    //   BasicDurationalObj::readCapx -- capx equivalent of BasicDurationalObj::read
    //---------------------------------------------------------

    void BasicDurationalObj::readCapx(XmlReader& e, unsigned int& fullm)
          {
          nDots      = 0;
          noDuration = false;
          postGrace  = false;
          bSmall     = false;
          invisible  = false;
          notBlack   = false;
          color = Qt::black;
          t = TIMESTEP::D1;
          horizontalShift = 0;
          count = 0;
          tripartite   = 0;
          isProlonging = 0;
          QString base = e.attribute("base");
          bool res = false;
          // try to convert base to timestep ("first pattern")
          res = qstring2timestep(base, t);
          if (!res) {
                // try multi-measure rest ("second pattern")
                int i = base.toInt();
                if (i > 0)
                      fullm = i;
                else
                      qDebug("BasicDurationalObj::readCapx: invalid base: '%s'", qPrintable(base));
                }
          nDots = e.intAttribute("dots", 0);
          noDuration = e.attribute("noDuration", "false") == "true";
          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());
                if (tag == "tuplet") {
                      count = e.attribute("count").toInt();
                      tripartite = e.attribute("tripartite", "false") == "true";
                      isProlonging = e.attribute("prolong", "false") == "true";
                      e.readNext();
                      }
                else
                      e.unknown();
                }
          qDebug("DurationObj ndots %d nodur %d postgr %d bsm %d inv %d notbl %d t %d hsh %d cnt %d trp %d ispro %d fullm %d",
                 nDots, noDuration, postGrace, bSmall, invisible, notBlack, int(t), horizontalShift, count, tripartite, isProlonging, fullm
                 );
          }

    //---------------------------------------------------------
    //   BasicDurationalObj::readCapxObjectArray
    //---------------------------------------------------------

    void BasicDurationalObj::readCapxObjectArray(XmlReader& e)
          {
          objects = cap->readCapxDrawObjectArray(e);
          }

    //---------------------------------------------------------
    //   CapExplicitBarline::readCapx -- capx equivalent of CapExplicitBarline::read
    //---------------------------------------------------------

    void CapExplicitBarline::readCapx(XmlReader& e)
          {
          QString type = e.attribute("type", "single");
          if (type == "single") _type = BarLineType::NORMAL;
          else if (type == "double") _type = BarLineType::DOUBLE;
          else if (type == "end") _type = BarLineType::END;
          else if (type == "repEnd") _type = BarLineType::END_REPEAT;
          else if (type == "repBegin") _type = BarLineType::START_REPEAT;
    //TODO      else if (type == "repEndBegin") _type = BarLineType::END_START_REPEAT;
          else if (type == "dashed") _type = BarLineType::BROKEN;
          else _type = BarLineType::NORMAL; // default
          _barMode = 0;
          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());
                if (tag == "drawObjects") {
                      e.skipCurrentElement();
                      }
                else
                      e.unknown();
                }
          e.readNext();
          }

    //---------------------------------------------------------
    //   CapClef::readCapx -- capx equivalent of CapClef::read
    //---------------------------------------------------------

    void CapClef::readCapx(XmlReader& e)
          {
          QString clef = e.attribute("clef");
          if (clef == "G2-") {
                form = Form::G;
                line = ClefLine::L2;
                oct = Oct::OCT_BASSA;
                }
          else if (clef == "treble") {
                form = Form::G;
                line = ClefLine::L2;
                oct = Oct::OCT_NULL;
                }
          else if (clef == "bass") {
                form = Form::F;
                line = ClefLine::L4;
                oct = Oct::OCT_NULL;
                }
          else {
                /* default */ form = Form::G;
                line = ClefLine::L2;
                oct = Oct::OCT_NULL;
                }
          qDebug("Clef::read '%s' -> form %d line %d oct %d", qPrintable(clef), int(form), int(line), int(oct));
          e.readNext();
          }

    //---------------------------------------------------------
    //   CapKey::readCapx -- capx equivalent of CapKey::read
    //---------------------------------------------------------

    void CapKey::readCapx(XmlReader& e)
          {
          signature = e.intAttribute("fifths", 0);
          qDebug("Key %d", signature);
          e.readNext();
          }

    //---------------------------------------------------------
    //   qstring2timesig -- convert string to timesig
    //   return true on success
    //---------------------------------------------------------

    static void qstring2timesig(QString& time, uchar& numerator, int& log2Denom, bool& allaBreve)
          {
          bool res = true;
          numerator = 4; log2Denom = 2; allaBreve = false; // set default
          if (time == "allaBreve") { numerator = 2; log2Denom = 1; allaBreve = true; }
          else if (time == "longAllaBreve") { numerator = 4; log2Denom = 1; allaBreve = true; }
          else if (time == "C") { numerator = 4; log2Denom = 2; allaBreve = false; }
          else if (time == "infinite") { qDebug("Meter infinite"); } // not supported by MuseScore ?
          else {
                QStringList splitTime = time.split("/");
                if (splitTime.size() == 2) {
                      numerator = splitTime.at(0).toInt();
                      QString denom = splitTime.at(1);
                      if (denom == "1") log2Denom = 0;
                      else if (denom == "2") log2Denom = 1;
                      else if (denom == "4") log2Denom = 2;
                      else if (denom == "8") log2Denom = 3;
                      else if (denom == "16") log2Denom = 4;
                      else if (denom == "32") log2Denom = 5;
                      else if (denom == "64") log2Denom = 6;
                      else if (denom == "128") log2Denom = 7;
                      else res = false;
                      }
                else res = false;
                }
          // TODO: recovery required if decoding the timesig failed ?
          qDebug("Meter '%s' res %d %d/%d allaBreve %d", qPrintable(time), res, numerator, log2Denom, allaBreve);
          }

    //---------------------------------------------------------
    //   CapMeter::readCapx -- capx equivalent of CapMeter::read
    //---------------------------------------------------------

    void CapMeter::readCapx(XmlReader& e)
          {
          qDebug("CapMeter::readCapx");
          QString time = e.attribute("time");
          qstring2timesig(time, numerator, log2Denom, allaBreve);
          e.readNext();
          }

    //---------------------------------------------------------
    //   ChordObj::readCapxStem -- read <stem> element
    //---------------------------------------------------------

    void ChordObj::readCapxStem(XmlReader& e)
          {
          QString dir = e.attribute("dir");
          if (dir == "up") stemDir = StemDir::UP;
          else if (dir == "down") stemDir = StemDir::DOWN;
          else if (dir == "none") stemDir = StemDir::NONE;
          e.readNext();
          }

    //---------------------------------------------------------
    //   ChordObj::readCapxArticulation -- read <articulation> element
    //---------------------------------------------------------

    void ChordObj::readCapxArticulation(XmlReader& e)
          {
          QString art = e.attribute("type");
          if      (art == "staccato")        articulation = 1;
          else if (art == "tenuto")          articulation = 2;
          else if (art == "staccato tenuto") articulation = 3;
          else if (art == "staccatissimo")   articulation = 4;
          else if (art == "normalAccent")    articulation = 5;
          else if (art == "strongAccent")    articulation = 6;
          else if (art == "weakBeat")        articulation = 7;
          else if (art == "strongBeat")      articulation = 8;
          else                               articulation = 0;
          e.readNext();
          }

    //---------------------------------------------------------
    //   ChordObj::readCapx -- capx equivalent of ChordObj::read
    //---------------------------------------------------------

    void ChordObj::readCapx(XmlReader& e)
          {
          stemDir      = StemDir::AUTO;
          dStemLength  = 0;
          nTremoloBars = 0;
          articulation = 0;
          leftTie      = false;
          rightTie     = false;
          beamShift    = 0;
          beamSlope    = 0;
          beamMode      = BeamMode::AUTO;
          notationStave = 0;

          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());
                if (tag == "duration") {
                      unsigned int dummy;
                      BasicDurationalObj::readCapx(e, dummy);
                      }
                else if (tag == "display") {
                      BasicDurationalObj::readCapxDisplay(e);
                      }
                else if (tag == "stem") {
                      readCapxStem(e);
                      }
                else if (tag == "beam") {
                      qDebug("ChordObj::readCapx: found beam (skipping)");
                      e.skipCurrentElement();
                      }
                else if (tag == "articulation") {
                      readCapxArticulation(e);
                      }
                else if (tag == "lyric") {
                      readCapxLyrics(e);
                      }
                else if (tag == "drawObjects") {
                      readCapxObjectArray(e);
                      }
                else if (tag == "heads") {
                      readCapxNotes(e);
                      }
                else
                      e.unknown();
                }
          }

    //---------------------------------------------------------
    //   pitchStr2Char -- convert pitch string ("[A-G][0-9]") to signed char
    //   notes:
    //   - in .capx middle C is called C5 (which is C4 in MusicXML)
    //   - middle C is MIDI note number 60
    //   - in .cap, pitch contains the diatonic note number relative to clef and key
    //   - as .capx contains absolute notes, store the MIDI note number instead
    //---------------------------------------------------------

    static signed char pitchStr2Char(QString& strPitch)
          {
          QRegExp pitchRegExp("[A-G][0-9]");

          if (!pitchRegExp.exactMatch(strPitch)) {
                qDebug("pitchStr2Char: illegal pitch '%s'", qPrintable(strPitch));
                return 0;
                }

          QString steps("C.D.EF.G.A.B");
          int istep  = steps.indexOf(strPitch.left(1));
          int octave = strPitch.right(1).toInt();
          int pitch  = istep + 12 * octave;

          if (pitch < 0)
                pitch = -1;
          if (pitch > 127)
                pitch = -1;

          qDebug("pitchStr2Char: '%s' -> %d", qPrintable(strPitch), pitch);

          return static_cast<signed char>(pitch);
          }

    //---------------------------------------------------------
    //   ChordObj::readCapxLyrics -- read the lyrics in a capx chord
    //---------------------------------------------------------

    void ChordObj::readCapxLyrics(XmlReader& e)
          {
          while (e.readNextStartElement()) {
                if (e.name() == "verse") {
                      Verse v;
                      v.leftAlign = true;        // not used by capella.cpp
                      v.extender  = false;       // not used by capella.cpp
                      v.hyphen    = e.attribute("hyphen") == "true";
                      v.num       = e.intAttribute("i", 0);
                      v.verseNumber = e.attribute("verseNumber"); // not used by capella.cpp
                      v.text = e.readElementText();
                      verse.append(v);
                      }
                else
                      e.unknown();
                }
          }

    //---------------------------------------------------------
    //   ChordObj::readCapxNotes -- read the notes in a capx chord
    //---------------------------------------------------------

    void ChordObj::readCapxNotes(XmlReader& e)
          {
          while (e.readNextStartElement()) {
                if (e.name() == "head") {
                      QString pitch = e.attribute("pitch");
                      QString sstep;
                      while (e.readNextStartElement()) {
                            const QStringRef& tag(e.name());
                            if (tag == "alter") {
                                  sstep = e.attribute("step");
                                  e.readNext();
                                  }
                            else if (tag == "tie") {
                                  rightTie = e.attribute("begin") == "true";
                                  e.readNext();
                                  }
                            else
                                  e.unknown();
                            }
                      qDebug("ChordObj::readCapxNotes: pitch '%s' altstep '%s'",
                             qPrintable(pitch), qPrintable(sstep));
                      int istep = sstep.toInt();
                      CNote n;
                      n.pitch = pitchStr2Char(pitch);
                      n.explAlteration = 0;
                      n.headType = 0;
                      n.alteration = istep;
                      n.silent = 0;
                      notes.append(n);
                      }
                else
                      e.unknown();
                }
          }

    //---------------------------------------------------------
    //   RestObj::readCapx -- capx equivalent of RestObj::read
    //---------------------------------------------------------

    void RestObj::readCapx(XmlReader& e)
          {
          bVerticalCentered = false;
          fullMeasures = 0;
          vertShift    = 0;
          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());
                if (tag == "duration") {
                      BasicDurationalObj::readCapx(e, fullMeasures);
                      }
                else if (tag == "display") {
                      BasicDurationalObj::readCapxDisplay(e);
                      }
                else if (tag == "verticalPos") {
                      qDebug("RestObj::readCapx: found verticalPos (skipping)");
                      e.skipCurrentElement();
                      }
                else if (tag == "drawObjects") {
                      readCapxObjectArray(e);
                      }
                else
                      e.unknown();
                }
          }

    //---------------------------------------------------------
    //   SimpleTextObj::readCapx -- capx equivalent of SimpleTextObj::read
    //---------------------------------------------------------

    void SimpleTextObj::readCapx(XmlReader& e)
          {
          double x = e.doubleAttribute("x");
          double y = e.doubleAttribute("y");
          QString stralign = e.attribute("align", "left");
          align = 0;
          if (stralign == "center")
                align = 1;
          else if (stralign == "right")
                align = 2;
          relPos = QPointF(x, y);
          relPos *= 32.0;
          // qDebug("x %g y %g align %s", x, y, qPrintable(align));
          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());
                if (tag == "font") {
                      _font = capxReadFont(e);
                      }
                else if (tag == "content") {
                      _text = e.readElementText();
                      // qDebug("SimpleTextObj::readCapx: found content '%s'", qPrintable(_text));
                      }
                else
                      e.unknown();
                }
          }

    //---------------------------------------------------------
    //   SlurObj::readCapx -- capx equivalent of SlurObj::read
    //---------------------------------------------------------

    void SlurObj::readCapx(XmlReader& e)
          {
          // nothing to be done yet
          e.skipCurrentElement();
          }

    //---------------------------------------------------------
    //   VoltaObj::readCapx -- capx equivalent of VoltaObj::read
    //---------------------------------------------------------

    void VoltaObj::readCapx(XmlReader& e)
          {
          bLeft           = e.attribute("leftBent", "true") == "true";
          bRight          = e.attribute("rightBent", "true") == "true";
          bDotted         = e.attribute("dotted", "false") == "true";
          allNumbers      = e.attribute("allNumbers", "false") == "true";
          int firstNumber = e.intAttribute("firstNumber", 0);
          int lastNumber  = e.intAttribute("lastNumber", 0);
          if (firstNumber == 0) {
                // don't know what this means (spec: no number)
                // cap status equivalent to no first or last number
                from = 1;
                to   = 0;
                }
          else {
                from = firstNumber;
                to   = (lastNumber == 0) ? firstNumber : lastNumber;
                }
          qDebug("VoltaObj::read firstNumber %d lastNumber %d", firstNumber, lastNumber);
          qDebug("VoltaObj::read x0 %d x1 %d y %d bLeft %d bRight %d bDotted %d allNumbers %d from %d to %d",
                 x0, x1, y, bLeft, bRight, bDotted, allNumbers, from, to);
          e.readNext();
          }

    //---------------------------------------------------------
    //   TrillObj::readCapx -- capx equivalent of TrillObj::read
    //---------------------------------------------------------

    void TrillObj::readCapx(XmlReader& e)
          {
          double x0d  = e.doubleAttribute("x1", 0.0);
          double x1d  = e.doubleAttribute("x2", 0.0);
          double yd   = e.doubleAttribute("y", 0.0);
          trillSign   = e.attribute("tr", "true") == "true";
          x0 = (int)round(x0d * 32.0);
          x1 = (int)round(x1d * 32.0);
          y  = (int)round(yd * 32.0);
          // color       -> skipped
          qDebug("TrillObj::read x0 %d x1 %d y %d trillSign %d", x0, x1, y, trillSign);
          e.readNext();
          }

    //---------------------------------------------------------
    //   WedgeObj::readCapx -- capx equivalent of WedgeObj::read
    //---------------------------------------------------------

    void WedgeObj::readCapx(XmlReader& e)
          {
          // TODO: read LineObj properties
          decresc          = e.attribute("decrescendo", "false") == "true";
          double dheight   = e.doubleAttribute("span", 1.0);
          height = (int)round(dheight * 32.0);
          e.readNext();
          }

    //---------------------------------------------------------
    //   readCapxDrawObjectArray -- capx equivalent of readDrawObjectArray()
    //---------------------------------------------------------

    QList<BasicDrawObj*> Capella::readCapxDrawObjectArray(XmlReader& e)
          {
          QList<BasicDrawObj*> ol;
          while (e.readNextStartElement()) {
                if (e.name() == "drawObj") {
                      BasicDrawObj* bdo = 0;
                      while (e.readNextStartElement()) {
                            const QStringRef& tag(e.name());
                            if (tag == "basic") {
                                  // note: the <basic> element always follows the DrawObject it applies to
                                  if (bdo)
                                        bdo->readCapx(e);
                                  else
                                        e.skipCurrentElement();
                                  }
                            else if (tag == "line") {
                                  qDebug("readCapxDrawObjectArray: found line (skipping)");
                                  e.skipCurrentElement();
                                  }
                            else if (tag == "rectangle") {
                                  qDebug("readCapxDrawObjectArray: found rectangle (skipping)");
                                  e.skipCurrentElement();
                                  }
                            else if (tag == "ellipse") {
                                  qDebug("readCapxDrawObjectArray: found ellipse (skipping)");
                                  e.skipCurrentElement();
                                  }
                            else if (tag == "polygon") {
                                  qDebug("readCapxDrawObjectArray: found polygon (skipping)");
                                  e.skipCurrentElement();
                                  }
                            else if (tag == "metafile") {
                                  qDebug("readCapxDrawObjectArray: found metafile (skipping)");
                                  e.skipCurrentElement();
                                  }
                            else if (tag == "text") {
                                  SimpleTextObj* o = new SimpleTextObj(this);
                                  bdo = o; // save o to handle the "basic" tag (which sometimes follows)
                                  o->readCapx(e);
                                  ol.append(o);
                                  }
                            else if (tag == "richText") {
                                  qDebug("readCapxDrawObjectArray: found richText (skipping)");
                                  e.skipCurrentElement();
                                  }
                            else if (tag == "guitar") {
                                  qDebug("readCapxDrawObjectArray: found guitar (skipping)");
                                  e.skipCurrentElement();
                                  }
                            else if (tag == "slur") {
                                  SlurObj* o = new SlurObj(this);
                                  bdo = o; // save o to handle the "basic" tag (which sometimes follows)
                                  o->readCapx(e);
                                  ol.append(o);
                                  }
                            else if (tag == "wavyLine") {
                                  qDebug("readCapxDrawObjectArray: found wavyLine (skipping)");
                                  e.skipCurrentElement();
                                  }
                            else if (tag == "bracket") {
                                  qDebug("readCapxDrawObjectArray: found bracket (skipping)");
                                  e.skipCurrentElement();
                                  }
                            else if (tag == "wedge") {
                                  WedgeObj* o = new WedgeObj(this);
                                  bdo = o; // save o to handle the "basic" tag (which sometimes follows)
                                  o->readCapx(e);
                                  ol.append(o);
                                  }
                            else if (tag == "notelines") {
                                  qDebug("readCapxDrawObjectArray: found notelines (skipping)");
                                  e.skipCurrentElement();
                                  }
                            else if (tag == "volta") {
                                  VoltaObj* o = new VoltaObj(this);
                                  bdo = o; // save o to handle the "basic" tag (which sometimes follows)
                                  o->readCapx(e);
                                  ol.append(o);
                                  }
                            else if (tag == "trill") {
                                  TrillObj* o = new TrillObj(this);
                                  bdo = o; // save o to handle the "basic" tag (which sometimes follows)
                                  o->readCapx(e);
                                  ol.append(o);
                                  }
                            else if (tag == "transposable") {
                                  qDebug("readCapxDrawObjectArray: found transposable (skipping)");
                                  e.skipCurrentElement();
                                  }
                            else if (tag == "group") {
                                  qDebug("readCapxDrawObjectArray: found group (skipping)");
                                  e.skipCurrentElement();
                                  }
                            else
                                  e.unknown();
                            }
                      }
                else
                      e.unknown();
                }
          return ol;
          }

    //---------------------------------------------------------
    //   readCapxVoice -- capx equivalent of readVoice(CapStaff* cs, int idx)
    //---------------------------------------------------------

    void Capella::readCapxVoice(XmlReader& e, CapStaff* cs, int idx)
          {
          CapVoice* v   = new CapVoice;
          v->voiceNo    = idx;
          v->y0Lyrics   = 0;
          v->dyLyrics   = 0;
          // v->lyricsFont = 0;
          v->stemDir    = 0;

          while (e.readNextStartElement()) {
                if (e.name() == "lyricsSettings") {
                      qDebug("readCapxVoice: found lyricsSettings (skipping)");
                      e.skipCurrentElement();
                      }
                else if (e.name() == "noteObjects") {
                      while (e.readNextStartElement()) {
                            const QStringRef& tag(e.name());
                            if (tag == "clefSign") {
                                  CapClef* clef = new CapClef(this);
                                  clef->readCapx(e);
                                  v->objects.append(clef);
                                  }
                            else if (tag == "keySign") {
                                  CapKey* key = new CapKey(this);
                                  key->readCapx(e);
                                  v->objects.append(key);
                                  }
                            else if (tag == "timeSign") {
                                  CapMeter* meter = new CapMeter(this);
                                  meter->readCapx(e);
                                  v->objects.append(meter);
                                  }
                            else if (tag == "barline") {
                                  CapExplicitBarline* bl = new CapExplicitBarline(this);
                                  bl->readCapx(e);
                                  v->objects.append(bl);
                                  }
                            else if (tag == "chord") {
                                  ChordObj* chord = new ChordObj(this);
                                  chord->readCapx(e);
                                  v->objects.append(chord);
                                  }
                            else if (tag == "rest") {
                                  RestObj* rest = new RestObj(this);
                                  rest->readCapx(e);
                                  v->objects.append(rest);
                                  }
                            else
                                  e.unknown();
                            }
                      }
                else
                      e.unknown();
                }

          cs->voices.append(v);
          }

    //---------------------------------------------------------
    //   readCapxStaff -- capx equivalent of readStaff(CapSystem* system)
    //---------------------------------------------------------

    void Capella::readCapxStaff(XmlReader& e, CapSystem* system, int iStave)
          {
          qDebug("Capella::readCapxStaff");
          CapStaff* staff = new CapStaff;
          //Meter
          QString time = e.attribute("defaultTime");
          qstring2timesig(time, staff->numerator, staff->log2Denom, staff->allaBreve);

          staff->iLayout   = iStave;
          staff->topDistX  = 0;
          staff->btmDistX  = 0;
          staff->color     = Qt::black;

          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());
                if (tag == "extraDistance") {
                      qDebug("readCapxStaff: found extraDistance (skipping)");
                      e.skipCurrentElement();
                      }
                else if (tag == "voices") {
                      int i = 0;
                      while (e.readNextStartElement()) {
                            if (e.name() == "voice") {
                                  readCapxVoice(e, staff, i);
                                  ++i;
                                  }
                            else
                                  e.unknown();
                            }
                      }
                else
                      e.unknown();
                }

          system->staves.append(staff);
          }

    //---------------------------------------------------------
    //   readCapxSystem -- capx equivalent of readSystem()
    //---------------------------------------------------------

    void Capella::readCapxSystem(XmlReader& e)
          {
          CapSystem* s = new CapSystem;
          s->nAddBarCount   = 0;
          s->bBarCountReset = 0;
          s->explLeftIndent = 0; // ?? TODO ?? use in capella.cpp commented out

          s->beamMode = BeamMode::AUTO;
          s->tempo    = 0;
          s->color    = Qt::black;

          unsigned char b  = 0;
          s->bJustified    = b & 2;
          s->bPageBreak    = (b & 4) != 0;
          s->instrNotation = (b >> 3) & 7;

          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());
                if (tag == "barCount") {
                      qDebug("readCapxSystem: found barCount (skipping)");
                      e.skipCurrentElement();
                      }
                else if (tag == "staves") {
                      int iStave = 0;
                      while (e.readNextStartElement()) {
                            if (e.name() == "staff") {
                                  readCapxStaff(e, s, iStave);
                                  ++iStave;
                                  }
                            else
                                  e.unknown();
                            }
                      }
                else
                      e.unknown();
                }

          systems.append(s);
          }

    //---------------------------------------------------------
    //   capxSystems -- read the capx <systems> element
    //---------------------------------------------------------

    void Capella::capxSystems(XmlReader& e)
          {
          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());
                if (tag == "system") {
                      readCapxSystem(e);
                      }
                else
                      e.unknown();
                }
          }

    //---------------------------------------------------------
    //   capxNotation -- read the capx <notation> element
    //---------------------------------------------------------

    static void capxNotation(XmlReader& e, uchar& barlineMode, uchar& barlineFrom, uchar& barlineTo)
          {
          while (e.readNextStartElement()) {
                if (e.name() == "barlines") {
                      QString mode = e.attribute("mode", "full");
                      if (mode == "full") barlineMode = 3;
                      else if (mode == "none") barlineMode = 2;     // correct ? not handled by capella.cpp anyway
                      else if (mode == "internal") barlineMode = 1;
                      else if (mode == "external") barlineMode = 0; // correct ? not handled by capella.cpp anyway
                      else barlineMode = 1;
                      barlineFrom = e.intAttribute("from");
                      barlineTo   = e.intAttribute("to");
                      e.readNext();
                      }
                else
                      e.unknown();
                }
          }

    //---------------------------------------------------------
    //   readCapxStaveLayout -- capx equivalent of readStaveLayout(CapStaffLayout*, int)
    //   read the staffLayout element
    //---------------------------------------------------------

    void Capella::readCapxStaveLayout(XmlReader& e, CapStaffLayout* sl, int /*idx*/)
          {
          // initialize same variables as readStaveLayout(CapStaffLayout*, int)

          sl->barlineMode = 0;
          sl->noteLines   = 0;

          sl->bSmall      = 0; // TODO (unclear where this is in the capx file)

          sl->topDist      = 0;
          sl->btmDist      = 0;
          sl->groupDist    = 0;
          sl->barlineFrom = 0;
          sl->barlineTo   = 0;

          unsigned char clef = 0;
          sl->form = Form(clef & 7);
          sl->line = ClefLine((clef >> 3) & 7);
          sl->oct  = Oct((clef >> 6));
          // qDebug("   clef %x  form %d, line %d, oct %d", clef, sl->form, sl->line, sl->oct);

          // Schlagzeuginformation
          unsigned char b   = 0; // ?? TODO ?? sl->soundMapIn and sl->soundMapOut are not used
          sl->bPercussion  = b & 1;    // Schlagzeugkanal verwenden
          sl->bSoundMapIn  = b & 2;
          sl->bSoundMapOut = b & 4;
          /*
          if (sl->bSoundMapIn) {      // Umleitungstabelle fr Eingabe vom Keyboard
                uchar iMin = readByte();
                Q_UNUSED(iMin);
                uchar n    = readByte();
                Q_ASSERT(n > 0 and iMin + n <= 128);
                f->read(sl->soundMapIn, n);
                curPos += n;
                }
          if (sl->bSoundMapOut) {     // Umleitungstabelle fr das Vorspielen
                unsigned char iMin = readByte();
                unsigned char n    = readByte();
                Q_ASSERT(n > 0 and iMin + n <= 128);
                f->read(sl->soundMapOut, n);
                curPos += n;
                }
          */
          sl->sound  = 0;
          sl->volume = 0;
          sl->transp = 0;

          qDebug("readCapxStaveLayout");
          sl->descr = e.attribute("description");
          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());
                if (tag == "notation") {
                      capxNotation(e, sl->barlineMode, sl->barlineFrom, sl->barlineTo);
                      }
                else if (tag == "distances") {
                      qDebug("readCapxStaveLayout: found distances (skipping)");
                      e.skipCurrentElement();
                      }
                else if (tag == "instrument") {
                      sl->name = e.attribute("name");
                      sl->abbrev = e.attribute("abbrev");
                      // elements name and abbrev overrule attributes name and abbrev
                      while (e.readNextStartElement()) {
                            const QStringRef& tag(e.name());
                            if (tag == "name")
                                  sl->name = e.readElementText();
                            else if (tag == "abbrev")
                                  sl->abbrev = e.readElementText();
                            else
                                  e.unknown();
                            }
                      }
                else if (tag == "sound") {
                      sl->sound = e.intAttribute("instr", 0);
                      sl->volume = e.intAttribute("volume", 0);
                      sl->transp = e.intAttribute("transpose", 0);
                      e.readNext();
                      }
                else
                      e.unknown();
                }
          qDebug("   descr '%s' name '%s' abbrev '%s'",
                 qPrintable(sl->descr), qPrintable(sl->name), qPrintable(sl->abbrev));
          qDebug("   sound %d vol %d transp %d", sl->sound, sl->volume, sl->transp);
          qDebug("readCapxStaveLayout done");
          }

    //---------------------------------------------------------
    //   capxLayoutBrackets -- read the capx <brackets> element (when child of <layout)
    //---------------------------------------------------------

    static void capxLayoutBrackets(XmlReader& e, QList<CapBracket>& bracketList)
          {
          int i = 0; // bracket count
          while (e.readNextStartElement()) {
                if (e.name() == "bracket") {
                      CapBracket b;
                      b.from  = e.intAttribute("from");
                      b.to    = e.intAttribute("to");
                      b.curly = e.attribute("curly") == "true";
                      // qDebug("Bracket%d %d-%d curly %d", i, b.from, b.to, b.curly);
                      bracketList.append(b);
                      e.readNext();
                      ++i;
                      }
                else
                      e.unknown();
                }
          }

    //---------------------------------------------------------
    //   capxLayoutDistances -- read the capx <Distances> element (when child of <layout)
    //---------------------------------------------------------

    static void capxLayoutDistances(XmlReader& e, double& smallLineDist, double& normalLineDist, int& topDist)
          {
          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());
                if (tag == "staffLines") {
                      smallLineDist = e.doubleAttribute("small");
                      normalLineDist = e.doubleAttribute("normal");
                      e.readNext();
                      }
                else if (tag == "systems") {
                      topDist = e.intAttribute("top");
                      e.readNext();
                      }
                else
                      e.unknown();
                }
          }

    //---------------------------------------------------------
    //   capxLayoutStaves -- read the capx <staves> element (when child of <layout)
    //---------------------------------------------------------

    void Capella::capxLayoutStaves(XmlReader& e)
          {
          int iStave = 0;
          while (e.readNextStartElement()) {
                if (e.name() == "staffLayout") {
                      CapStaffLayout* sl = new CapStaffLayout;
                      readCapxStaveLayout(e, sl, iStave);
                      _staffLayouts.append(sl);
                      ++iStave;
                      }
                else
                      e.unknown();
                }
          }

    //---------------------------------------------------------
    //   capxLayout -- read the capx <layout> element
    //   rough equivalent of readLayout() read part
    //---------------------------------------------------------

    void Capella::capxLayout(XmlReader& e)
          {
          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());
                if (tag == "pages") {
                      qDebug("capxLayout: found pages (skipping)");
                      e.skipCurrentElement();
                      }
                else if (tag == "distances") {
                      capxLayoutDistances(e, smallLineDist, normalLineDist, topDist);
                      // qDebug("Capella::capxLayout(): smallLineDist %g normalLineDist %g topDist %d",
                      //        smallLineDist, normalLineDist, topDist);
                      }
                else if (tag == "instrumentNames") {
                      qDebug("capxLayout: found instrumentNames (skipping)");
                      e.skipCurrentElement();
                      }
                else if (tag == "style") {
                      qDebug("capxLayout: found style (skipping)");
                      e.skipCurrentElement();
                      }
                else if (tag == "staves") {
                      capxLayoutStaves(e);
                      }
                else if (tag == "brackets") {
                      capxLayoutBrackets(e, brackets);
                      }
                else if (tag == "spacing") {
                      qDebug("capxLayout: found spacing (skipping)");
                      e.skipCurrentElement();
                      }
                else if (tag == "beamFlattening") {
                      qDebug("capxLayout: found beamFlattening (skipping)");
                      e.skipCurrentElement();
                      }
                else
                      e.unknown();
                }
          }

    //---------------------------------------------------------
    //   initCapxLayout -- capx equivalent of readLayout() initialize part
    //---------------------------------------------------------

    void Capella::initCapxLayout()
          {
          // initialize same variables as readLayout()

          smallLineDist  = 1.2;  // TODO verify default
          normalLineDist = 1.76; // TODO verify default

          topDist        = 14;   // TODO verify default
          interDist      = 0;    // TODO verify default

          txtAlign   = 0;
          adjustVert = 0;

          unsigned char b          = 0;
          redundantKeys    = b & 1;
          modernDoubleNote = b & 2;
          Q_ASSERT((b & 0xFC) == 0); // bits 2...7 reserviert

          bSystemSeparators = 0;
          nUnnamed           = 0;

          // namesFont = ... // ?? not used ??

          // Note: readLayout() also reads stave layout (using readStaveLayout(sl, iStave))
          // and system brackets. Here this is handled by readCapx(XmlReader& e).
          }

    //---------------------------------------------------------
    //   readCapx -- capx equivalent of read(QFile* fp)
    //---------------------------------------------------------

    void Capella::readCapx(XmlReader& e)
          {
          // initialize same variables as read(QFile* fp)

          f      = 0;
          curPos = 0;

          author   = 0;
          keywords = 0;
          comment  = 0;

          nRel   = 0;
          nAbs   = 0;
          unsigned char b   = 0;
          bUseRealSize      = b & 1;
          bAllowCompression = b & 2;
          bPrintLandscape   = b & 16;

          beamRelMin0 = 0;
          beamRelMin1 = 0;
          beamRelMax0 = 0;
          beamRelMax1 = 0;

          backgroundChord = new ChordObj(this);         // contains graphic objects on the page background
          bShowBarCount    = 0;
          barNumberFrame   = 0;
          nBarDistX        = 0;
          nBarDistY        = 0;
          // QFont barNumFont = ... // not used ?
          nFirstPage       = 0;
          leftPageMargins  = 0;
          topPageMargins   = 0;
          rightPageMargins = 0;
          btmPageMargins   = 0;

          // Now do the equivalent of:
          // readLayout(); (called only once)
          // readExtra();  (this is a NOP)
          // readDrawObjectArray();
          // for (unsigned i = 0; i < nSystems; i++)
          //       readSystem();

          initCapxLayout();

          // read stave layout
          // read systems
          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());
                if (tag == "info") {
                      qDebug("importCapXml: found info (skipping)");
                      e.skipCurrentElement();
                      }
                else if (tag == "layout") {
                      capxLayout(e);
                      }
                else if (tag == "gallery") {
                      qDebug("capxLayout: found gallery (skipping)");
                      e.skipCurrentElement();
                      }
                else if (tag == "pageObjects") {
                      backgroundChord->readCapxObjectArray(e);
                      }
                else if (tag == "barCount") {
                      qDebug("importCapXml: found barCount (skipping)");
                      e.skipCurrentElement();
                      }
                else if (tag == "systems") {
                      capxSystems(e);
                      }
                else
                      e.unknown();
                }
          }

    //---------------------------------------------------------
    //   importCapXml
    //---------------------------------------------------------

    void convertCapella(Score* score, Capella* cap, bool capxMode);

    Score::FileError importCapXml(MasterScore* score, const QString& name)
          {
          qDebug("importCapXml(score %p, name %s)", score, qPrintable(name));
          MQZipReader uz(name);
          if (!uz.exists()) {
                qDebug("importCapXml: <%s> not found", qPrintable(name));
                return Score::FileError::FILE_NOT_FOUND;
                }

          QByteArray dbuf = uz.fileData("score.xml");
          XmlReader e(score, dbuf);
          e.setDocName(name);
          Capella cf;

          while (e.readNextStartElement()) {
                if (e.name() == "score") {
                      const QString& xmlns = e.attribute("xmlns", "<none>"); // doesn't work ???
                      qDebug("importCapXml: found score, namespace '%s'", qPrintable(xmlns));
                      cf.readCapx(e);
                      }
                else
                      e.unknown();
                }

          convertCapella(score, &cf, true);
          return Score::FileError::FILE_NO_ERROR;
          }
    }

↑ V547 Expression 'b & 2' is always false.

↑ V547 Expression '(b & 4) != 0' is always false.

↑ V547 Expression 'b & 1' is always false.

↑ V547 Expression 'b & 2' is always false.

↑ V547 Expression 'b & 4' is always false.

↑ V547 Expression 'b & 1' is always false.

↑ V547 Expression 'b & 2' is always false.

↑ V547 Expression 'b & 1' is always false.

↑ V547 Expression 'b & 2' is always false.

↑ V547 Expression 'b & 16' is always false.