annotate base/PropertyContainer.cpp @ 979:c598b1d880f2

Fix potential null pointer deref
author Chris Cannam
date Wed, 03 Sep 2014 13:10:19 +0100
parents 6a94bb528e9d
children a54016762f77
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@202 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@0 8
Chris@52 9 This program is free software; you can redistribute it and/or
Chris@52 10 modify it under the terms of the GNU General Public License as
Chris@52 11 published by the Free Software Foundation; either version 2 of the
Chris@52 12 License, or (at your option) any later version. See the file
Chris@52 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "PropertyContainer.h"
Chris@199 17 #include "RangeMapper.h"
Chris@199 18 #include "UnitDatabase.h"
Chris@46 19
Chris@46 20 #include <iostream>
Chris@0 21
Chris@0 22 PropertyContainer::PropertyList
Chris@0 23 PropertyContainer::getProperties() const
Chris@0 24 {
Chris@0 25 return PropertyList();
Chris@0 26 }
Chris@0 27
Chris@0 28 PropertyContainer::PropertyType
Chris@0 29 PropertyContainer::getPropertyType(const PropertyName &) const
Chris@0 30 {
Chris@0 31 return InvalidProperty;
Chris@0 32 }
Chris@0 33
Chris@0 34 QString
Chris@340 35 PropertyContainer::getPropertyIconName(const PropertyName &) const
Chris@340 36 {
Chris@340 37 return QString();
Chris@340 38 }
Chris@340 39
Chris@340 40 QString
Chris@0 41 PropertyContainer::getPropertyGroupName(const PropertyName &) const
Chris@0 42 {
Chris@0 43 return QString();
Chris@0 44 }
Chris@0 45
Chris@0 46 int
Chris@245 47 PropertyContainer::getPropertyRangeAndValue(const PropertyName &,
Chris@245 48 int *min, int *max, int *deflt) const
Chris@0 49 {
Chris@0 50 if (min) *min = 0;
Chris@0 51 if (max) *max = 0;
Chris@245 52 if (deflt) *deflt = 0;
Chris@0 53 return 0;
Chris@0 54 }
Chris@0 55
Chris@0 56 QString
Chris@928 57 PropertyContainer::getPropertyValueLabel(const PropertyName &, int) const
Chris@0 58 {
Chris@0 59 return QString();
Chris@0 60 }
Chris@0 61
Chris@190 62 RangeMapper *
Chris@190 63 PropertyContainer::getNewPropertyRangeMapper(const PropertyName &) const
Chris@190 64 {
Chris@190 65 return 0;
Chris@190 66 }
Chris@190 67
Chris@0 68 void
Chris@46 69 PropertyContainer::setProperty(const PropertyName &name, int)
Chris@46 70 {
Chris@843 71 cerr << "WARNING: PropertyContainer[" << getPropertyContainerName() << "]::setProperty(" << name << "): no implementation in subclass!" << endl;
Chris@46 72 }
Chris@46 73
Chris@387 74 Command *
Chris@387 75 PropertyContainer::getSetPropertyCommand(const PropertyName &name, int value)
Chris@46 76 {
Chris@245 77 int currentValue = getPropertyRangeAndValue(name, 0, 0, 0);
Chris@387 78 if (value == currentValue) return 0;
Chris@387 79 return new SetPropertyCommand(this, name, value);
Chris@46 80 }
Chris@199 81
Chris@199 82 void
Chris@528 83 PropertyContainer::setPropertyFuzzy(QString nameString, QString valueString)
Chris@199 84 {
Chris@199 85 PropertyName name;
Chris@199 86 int value;
Chris@199 87 if (!convertPropertyStrings(nameString, valueString, name, value)) {
Chris@843 88 cerr << "WARNING: PropertyContainer::setProperty(\""
Chris@686 89 << nameString << "\", \""
Chris@844 90 << valueString
Chris@843 91 << "\"): Name and value conversion failed" << endl;
Chris@199 92 return;
Chris@199 93 }
Chris@199 94 setProperty(name, value);
Chris@199 95 }
Chris@199 96
Chris@387 97 Command *
Chris@387 98 PropertyContainer::getSetPropertyCommand(QString nameString, QString valueString)
Chris@199 99 {
Chris@199 100 PropertyName name;
Chris@199 101 int value;
Chris@199 102 if (!convertPropertyStrings(nameString, valueString, name, value)) {
Chris@843 103 cerr << "WARNING: PropertyContainer::getSetPropertyCommand(\""
Chris@686 104 << nameString << "\", \""
Chris@844 105 << valueString
Chris@843 106 << "\"): Name and value conversion failed" << endl;
Chris@387 107 return 0;
Chris@199 108 }
Chris@387 109 return getSetPropertyCommand(name, value);
Chris@199 110 }
Chris@199 111
Chris@199 112 bool
Chris@199 113 PropertyContainer::convertPropertyStrings(QString nameString, QString valueString,
Chris@199 114 PropertyName &name, int &value)
Chris@199 115 {
Chris@199 116 PropertyList pl = getProperties();
Chris@199 117
Chris@199 118 QString adjusted = nameString.trimmed();
Chris@199 119 adjusted.replace('_', ' ');
Chris@199 120 adjusted.replace('-', ' ');
Chris@199 121
Chris@199 122 name = "";
Chris@199 123
Chris@199 124 for (PropertyList::iterator pli = pl.begin(); pli != pl.end(); ++pli) {
Chris@199 125
Chris@199 126 QString label = getPropertyLabel(*pli);
Chris@199 127
Chris@199 128 if (label != "" && (nameString == label || adjusted == label)) {
Chris@199 129 name = *pli;
Chris@199 130 break;
Chris@199 131 } else if (nameString == *pli) {
Chris@199 132 name = *pli;
Chris@199 133 break;
Chris@199 134 }
Chris@199 135 }
Chris@199 136
Chris@199 137 if (name == "") {
Chris@843 138 cerr << "PropertyContainer::convertPropertyStrings: Unable to match name string \"" << nameString << "\"" << endl;
Chris@199 139 return false;
Chris@199 140 }
Chris@199 141
Chris@199 142 value = 0;
Chris@199 143 bool success = false;
Chris@199 144
Chris@199 145 bool isDouble = false;
Chris@199 146 double dval = valueString.toDouble(&isDouble);
Chris@199 147
Chris@199 148 switch (getPropertyType(name)) {
Chris@199 149
Chris@199 150 case ToggleProperty:
Chris@199 151 if (valueString == tr("yes") ||
Chris@199 152 valueString == tr("on") ||
Chris@199 153 valueString == tr("true")) {
Chris@199 154 value = 1; success = true;
Chris@199 155 } else if (valueString == tr("no") ||
Chris@199 156 valueString == tr("off") ||
Chris@199 157 valueString == tr("false")) {
Chris@199 158 value = 0; success = true;
Chris@199 159 }
Chris@199 160 break;
Chris@199 161
Chris@199 162 case RangeProperty:
Chris@199 163 if (isDouble) {
Chris@199 164 RangeMapper *mapper = getNewPropertyRangeMapper(name);
Chris@199 165 if (mapper) {
Chris@199 166 value = mapper->getPositionForValue(dval);
Chris@199 167 delete mapper;
Chris@199 168 success = true;
Chris@199 169 }
Chris@199 170 }
Chris@199 171 break;
Chris@199 172
Chris@199 173 case ValueProperty:
Chris@387 174 case ColourProperty:
Chris@199 175 {
Chris@199 176 int min, max;
Chris@245 177 getPropertyRangeAndValue(name, &min, &max, 0);
Chris@199 178 for (int i = min; i <= max; ++i) {
Chris@199 179 if (valueString == getPropertyValueLabel(name, i)) {
Chris@199 180 value = i;
Chris@199 181 success = true;
Chris@199 182 break;
Chris@199 183 }
Chris@199 184 }
Chris@199 185 break;
Chris@199 186 }
Chris@199 187
Chris@199 188 case UnitsProperty:
Chris@199 189 value = UnitDatabase::getInstance()->getUnitId(valueString, false);
Chris@199 190 if (value >= 0) success = true;
Chris@199 191 else value = 0;
Chris@199 192 break;
Chris@199 193
Chris@199 194 case InvalidProperty:
Chris@690 195 SVDEBUG << "PropertyContainer::convertPropertyStrings: Invalid property name \"" << name << "\"" << endl;
Chris@199 196 return false;
Chris@199 197 }
Chris@199 198
Chris@199 199 if (success) return true;
Chris@199 200
Chris@199 201 int min, max;
Chris@245 202 getPropertyRangeAndValue(name, &min, &max, 0);
Chris@199 203
Chris@199 204 bool ok = false;
Chris@199 205 int i = valueString.toInt(&ok);
Chris@199 206 if (!ok) {
Chris@843 207 cerr << "PropertyContainer::convertPropertyStrings: Unable to parse value string \"" << valueString << "\"" << endl;
Chris@199 208 return false;
Chris@199 209 } else if (i < min || i > max) {
Chris@690 210 SVDEBUG << "PropertyContainer::convertPropertyStrings: Property value \"" << i << "\" outside valid range " << min << " to " << max << endl;
Chris@199 211 return false;
Chris@199 212 }
Chris@199 213
Chris@199 214 value = i;
Chris@199 215 return true;
Chris@199 216 }
Chris@46 217
Chris@46 218 PropertyContainer::SetPropertyCommand::SetPropertyCommand(PropertyContainer *pc,
Chris@46 219 const PropertyName &pn,
Chris@46 220 int value) :
Chris@46 221 m_pc(pc),
Chris@46 222 m_pn(pn),
Chris@46 223 m_value(value),
Chris@46 224 m_oldValue(0)
Chris@0 225 {
Chris@0 226 }
Chris@0 227
Chris@46 228 void
Chris@46 229 PropertyContainer::SetPropertyCommand::execute()
Chris@46 230 {
Chris@245 231 m_oldValue = m_pc->getPropertyRangeAndValue(m_pn, 0, 0, 0);
Chris@46 232 m_pc->setProperty(m_pn, m_value);
Chris@46 233 }
Chris@46 234
Chris@46 235 void
Chris@46 236 PropertyContainer::SetPropertyCommand::unexecute()
Chris@46 237 {
Chris@46 238 m_pc->setProperty(m_pn, m_oldValue);
Chris@46 239 }
Chris@46 240
Chris@46 241 QString
Chris@46 242 PropertyContainer::SetPropertyCommand::getName() const
Chris@46 243 {
Chris@247 244 return tr("Set %1 Property").arg(m_pn);
Chris@46 245 }
Chris@46 246