datasource.cpp (5804B)
1 #include "datasource.h" 2 3 #include <algorithm> 4 #include <sstream> 5 #include <memory> 6 7 #include "db.h" 8 #include "patch.h" 9 10 #include "baseLib/binarystream.h" 11 12 namespace pluginLib::patchDB 13 { 14 bool DataSource::createConsecutiveProgramNumbers() 15 { 16 if(patches.empty()) 17 return false; 18 19 // note that this does NOT sort the patches member, it is a set that cannot be sorted, we only generate consecutive program numbers here 20 21 std::vector<PatchPtr> patchesVector(patches.begin(), patches.end()); 22 23 sortByProgram(patchesVector); 24 25 return createConsecutiveProgramNumbers(patchesVector); 26 } 27 28 bool DataSource::createConsecutiveProgramNumbers(const std::vector<PatchPtr>& _patches) 29 { 30 bool dirty = false; 31 uint32_t program = 0; 32 33 for (const auto& patch : _patches) 34 { 35 const auto p = program++; 36 37 if(patch->program == p) 38 continue; 39 40 patch->program = p; 41 dirty = true; 42 } 43 44 return dirty; 45 } 46 47 bool DataSource::makeSpaceForNewPatches(const uint32_t _insertPosition, const uint32_t _count) const 48 { 49 bool dirty = true; 50 51 for (const auto& patch : patches) 52 { 53 if(patch->program >= _insertPosition) 54 { 55 patch->program += _count; 56 dirty = true; 57 } 58 } 59 return dirty; 60 } 61 62 std::pair<uint32_t, uint32_t> DataSource::getProgramNumberRange() const 63 { 64 if(patches.empty()) 65 return {g_invalidProgram, g_invalidProgram}; 66 67 uint32_t min = std::numeric_limits<uint32_t>::max(); 68 uint32_t max = std::numeric_limits<uint32_t>::min(); 69 70 for (const auto& patch : patches) 71 { 72 min = std::min(patch->program, min); 73 max = std::max(patch->program, max); 74 } 75 76 return {min, max}; 77 } 78 79 uint32_t DataSource::getMaxProgramNumber() const 80 { 81 return getProgramNumberRange().second; 82 } 83 84 void DataSource::sortByProgram(std::vector<PatchPtr>& _patches) 85 { 86 std::sort(_patches.begin(), _patches.end(), [&](const PatchPtr& _a, const PatchPtr& _b) 87 { 88 return _a->program < _b->program; 89 }); 90 } 91 92 bool DataSource::contains(const PatchPtr& _patch) const 93 { 94 return patches.find(_patch) != patches.end(); 95 } 96 97 bool DataSource::movePatchesTo(const uint32_t _position, const std::vector<PatchPtr>& _patches) 98 { 99 std::vector<PatchPtr> patchesVec(patches.begin(), patches.end()); 100 sortByProgram(patchesVec); 101 102 createConsecutiveProgramNumbers(patchesVec); 103 104 uint32_t targetPosition = _position; 105 106 // insert position has to be decremented by 1 for each patch that is reinserted that has a position less than the target position 107 for (const auto& patch : _patches) 108 { 109 if(patch->program < _position) 110 --targetPosition; 111 } 112 113 if(!remove(_patches)) 114 return false; 115 116 patchesVec.assign(patches.begin(), patches.end()); 117 sortByProgram(patchesVec); 118 119 if(targetPosition >= patchesVec.size()) 120 patchesVec.insert(patchesVec.end(), _patches.begin(), _patches.end()); 121 else 122 patchesVec.insert(patchesVec.begin() + targetPosition, _patches.begin(), _patches.end()); 123 124 createConsecutiveProgramNumbers(patchesVec); 125 126 for (const auto& patch : _patches) 127 patches.insert(patch); 128 129 return true; 130 } 131 132 bool DataSource::remove(const PatchPtr& _patch) 133 { 134 return patches.erase(_patch); 135 } 136 137 PatchPtr DataSource::getPatch(const PatchKey& _key) const 138 { 139 for (const auto& patch : patches) 140 { 141 if(*patch == _key) 142 return patch; 143 } 144 return {}; 145 } 146 147 std::string DataSource::toString() const 148 { 149 std::stringstream ss; 150 151 ss << "type|" << patchDB::toString(type); 152 ss << "|name|" << name; 153 if (bank != g_invalidBank) 154 ss << "|bank|" << bank; 155 // if (program != g_invalidProgram) 156 // ss << "|prog|" << program; 157 return ss.str(); 158 } 159 160 void DataSource::write(baseLib::BinaryStream& _outStream) const 161 { 162 baseLib::ChunkWriter cw(_outStream, chunks::g_datasource, 1); 163 164 _outStream.write(static_cast<uint8_t>(type)); 165 _outStream.write(static_cast<uint8_t>(origin)); 166 _outStream.write(name); 167 _outStream.write(bank); 168 169 _outStream.write(static_cast<uint32_t>(patches.size())); 170 171 for (const auto& patch : patches) 172 patch->write(_outStream); 173 } 174 175 bool DataSource::read(baseLib::BinaryStream& _inStream) 176 { 177 auto in = _inStream.tryReadChunk(chunks::g_datasource); 178 if(!in) 179 return false; 180 181 type = static_cast<SourceType>(in.read<uint8_t>()); 182 origin = static_cast<DataSourceOrigin>(in.read<uint8_t>()); 183 name = in.readString(); 184 bank = in.read<uint32_t>(); 185 186 const auto numPatches = in.read<uint32_t>(); 187 188 for(uint32_t i=0; i<numPatches; ++i) 189 { 190 const auto patch = std::make_shared<Patch>(); 191 if(!patch->read(in)) 192 return false; 193 194 DB::assign(patch, patch->modifications); 195 196 patches.insert(patch); 197 } 198 199 return true; 200 } 201 202 DataSourceNode::DataSourceNode(const DataSource& _ds) : DataSource(_ds) 203 { 204 } 205 206 DataSourceNode::~DataSourceNode() 207 { 208 setParent(nullptr); 209 removeAllChildren(); 210 } 211 212 void DataSourceNode::setParent(const DataSourceNodePtr& _parent) 213 { 214 if (getParent() == _parent) 215 return; 216 217 if(m_parent) 218 { 219 // we MUST NOT create a new ptr to this here as we may be called from our destructor, in which case there shouldn't be a pointer in there anyway 220 for(uint32_t i=0; i<static_cast<uint32_t>(m_parent->m_children.size()); ++i) 221 { 222 auto& child = m_parent->m_children[i]; 223 auto ptr = child.lock(); 224 if (ptr && ptr.get() == this) 225 { 226 m_parent->m_children.erase(m_parent->m_children.begin() + i); 227 break; 228 } 229 } 230 } 231 232 m_parent = _parent; 233 234 if(_parent) 235 _parent->m_children.emplace_back(shared_from_this()); 236 } 237 238 bool DataSourceNode::isChildOf(const DataSourceNode* _ds) const 239 { 240 auto node = this; 241 242 while(node) 243 { 244 if (_ds == node) 245 return true; 246 node = node->m_parent.get(); 247 } 248 return false; 249 } 250 251 void DataSourceNode::removeAllChildren() 252 { 253 while(!m_children.empty()) 254 { 255 const auto& c = m_children.back().lock(); 256 if (c) 257 c->setParent(nullptr); 258 else 259 m_children.pop_back(); 260 } 261 } 262 }