/[svn]/linuxsampler/trunk/src/db/InstrumentsDb.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/db/InstrumentsDb.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3290 - (show annotations) (download)
Fri Jun 23 12:24:58 2017 UTC (6 years, 10 months ago) by schoenebeck
File size: 71935 byte(s)
* Revised fundamental C++ classes "Thread", "Mutex" and
  "Condition" which fixes potential undefined behavior
  (note: this addresses mainly the POSIX implementation,
   Win32 is untested yet and would also need an update).
* Bumped version (2.0.0.svn64).

1 /***************************************************************************
2 * *
3 * Copyright (C) 2007-2013 Grigor Iliev, Benno Senoner *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software *
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, *
18 * MA 02110-1301 USA *
19 ***************************************************************************/
20
21 #include "InstrumentsDb.h"
22
23 #include "../common/File.h"
24 #include "../common/Path.h"
25 #include "../common/global_private.h"
26
27 #include <iostream>
28 #include <sstream>
29 #include <vector>
30 #include <algorithm>
31 #include <errno.h>
32 #ifndef WIN32
33 #include <fnmatch.h>
34 #else
35 #include <direct.h>
36 #endif
37 #include "../common/Exception.h"
38
39 namespace LinuxSampler {
40
41 InstrumentsDb InstrumentsDb::instance;
42
43 void InstrumentsDb::CreateInstrumentsDb(String FilePath) {
44 if (FilePath.empty()) {
45 FilePath = GetDefaultDBLocation();
46 dmsg(0,("InstrumentsDb: Creating database at default location '%s'\n", FilePath.c_str()));
47 }
48
49 File f = File(FilePath);
50 if (f.Exist()) {
51 throw Exception("File exists: " + FilePath);
52 }
53
54 SetDbFile(FilePath);
55
56 String sql =
57 " CREATE TABLE instr_dirs ( "
58 " dir_id INTEGER PRIMARY KEY AUTOINCREMENT, "
59 " parent_dir_id INTEGER DEFAULT 0, "
60 " dir_name TEXT, "
61 " created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
62 " modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
63 " description TEXT, "
64 " FOREIGN KEY(parent_dir_id) REFERENCES instr_dirs(dir_id), "
65 " UNIQUE (parent_dir_id,dir_name) "
66 " ); ";
67
68 ExecSql(sql);
69
70 sql = "INSERT INTO instr_dirs (dir_id, parent_dir_id, dir_name) VALUES (0, -2, '/');";
71 ExecSql(sql);
72
73 sql =
74 " CREATE TABLE instruments ( "
75 " instr_id INTEGER PRIMARY KEY AUTOINCREMENT, "
76 " dir_id INTEGER DEFAULT 0, "
77 " instr_name TEXT, "
78 " instr_file TEXT, "
79 " instr_nr INTEGER, "
80 " format_family TEXT, "
81 " format_version TEXT, "
82 " instr_size INTEGER, "
83 " created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
84 " modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
85 " description TEXT, "
86 " is_drum INTEGER(1), "
87 " product TEXT, "
88 " artists TEXT, "
89 " keywords TEXT, "
90 " FOREIGN KEY(dir_id) REFERENCES instr_dirs(dir_id), "
91 " UNIQUE (dir_id,instr_name) "
92 " ); ";
93
94 ExecSql(sql);
95 }
96
97 InstrumentsDb::InstrumentsDb() {
98 db = NULL;
99 InTransaction = false;
100 }
101
102 InstrumentsDb::~InstrumentsDb() {
103 InstrumentsDbThread.StopThread();
104 if (db != NULL) sqlite3_close(db);
105 }
106
107 void InstrumentsDb::AddInstrumentsDbListener(InstrumentsDb::Listener* l) {
108 llInstrumentsDbListeners.AddListener(l);
109 }
110
111 void InstrumentsDb::RemoveInstrumentsDbListener(InstrumentsDb::Listener* l) {
112 llInstrumentsDbListeners.RemoveListener(l);
113 }
114
115 InstrumentsDb* InstrumentsDb::GetInstrumentsDb() {
116 return &instance;
117 }
118
119 void InstrumentsDb::SetDbFile(String File) {
120 LockGuard lock(DbInstrumentsMutex);
121 if (File.empty() || DbFile.length() > 0) {
122 throw Exception("Failed to set the database file");
123 }
124 DbFile = File;
125 }
126
127 String InstrumentsDb::GetDefaultDBLocation() {
128 #ifdef WIN32
129 char* userprofile = getenv("USERPROFILE");
130 if (userprofile) {
131 String s = userprofile;
132 s += "\\.linuxsampler\\instruments.db";
133 return s;
134 } else {
135 // in case USERPROFILE is not set (which should not occur)
136 return "instruments.db";
137 }
138 #else // POSIX ...
139 String s = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
140 # if defined(__APPLE__)
141 if (s.find("~") == 0)
142 s.replace(0, 1, getenv("HOME"));
143 # endif
144 return s;
145 #endif
146 }
147
148 void InstrumentsDb::EnsureDBFileExists() {
149 if (DbFile.empty())
150 DbFile = GetDefaultDBLocation();
151 #if defined(__APPLE__) /* 20071224 Toshi Nagata */
152 if (DbFile.find("~") == 0)
153 DbFile.replace(0, 1, getenv("HOME"));
154 #endif
155 Path DbPath(DbFile);
156 String DbDir = DbPath.stripLastName();
157 // create directory if it does not exist yet
158 if (!DbPath.nodes().empty()) {
159 File d(DbDir);
160 if (!d.Exist()) {
161 #ifdef WIN32
162 if (_mkdir(DbDir.c_str()))
163 throw Exception("Could not create instruments DB directory '" + DbDir + "'");
164 #else
165 if (mkdir(DbDir.c_str(), S_IRWXU))
166 throw Exception("Could not create instruments DB directory '" + DbDir + "'");
167 #endif
168 }
169 }
170 // create database file if it does not exist yet
171 File f(DbFile);
172 if (!f.Exist()) {
173 // formats the DB, which creates a new instruments.db file
174 Format();
175 }
176 }
177
178 sqlite3* InstrumentsDb::GetDb() {
179 if ( db != NULL) return db;
180
181 if (DbFile.empty())
182 DbFile = GetDefaultDBLocation();
183
184 {
185 // first check if the instruments DB's directory exists, if not give up
186 Path path(DbFile);
187 String sDir = path.stripLastName();
188 File d(sDir);
189 if (!d.Exist())
190 throw Exception("Instruments DB directory '" + sDir + "' does not exist!");
191
192 // just to give the user a notice about the DB file being created in case it does not exist yet
193 File f(DbFile);
194 if (!f.Exist())
195 dmsg(0,("Instruments DB file '%s' does not exist yet. Trying to create it now.\n", DbFile.c_str()));
196 }
197
198 dmsg(0,("Opening instruments DB at '%s'\n", DbFile.c_str()));
199 int rc = sqlite3_open(DbFile.c_str(), &db);
200 if (rc) {
201 sqlite3_close(db);
202 db = NULL;
203 throw Exception("Cannot open instruments database: " + DbFile);
204 }
205 #ifndef WIN32
206 rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, NULL, Regexp, NULL, NULL);
207 if (rc) { throw Exception("Failed to add user function for handling regular expressions."); }
208 #endif
209
210 // TODO: remove this in the next version
211 try {
212 int i = ExecSqlInt("SELECT parent_dir_id FROM instr_dirs WHERE dir_id=0");
213 // The parent ID of the root directory should be -2 now.
214 if(i != -2) ExecSql("UPDATE instr_dirs SET parent_dir_id=-2 WHERE dir_id=0");
215 } catch(Exception e) { }
216 ////////////////////////////////////////
217
218 return db;
219 }
220
221 int InstrumentsDb::GetDirectoryCount(int DirId) {
222 dmsg(2,("InstrumentsDb: GetDirectoryCount(DirId=%d)\n", DirId));
223 if(DirId == -1) return -1;
224
225 std::stringstream sql;
226 sql << "SELECT COUNT(*) FROM instr_dirs WHERE parent_dir_id=" << DirId;
227
228 int count = ExecSqlInt(sql.str());
229
230 return count;
231 }
232
233 int InstrumentsDb::GetDirectoryCount(String Dir, bool Recursive) {
234 dmsg(2,("InstrumentsDb: GetDirectoryCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
235 int i;
236
237 BeginTransaction();
238 try {
239 if (Recursive) {
240 DirectoryCounter directoryCounter;
241 DirectoryTreeWalk(Dir, &directoryCounter);
242 i = directoryCounter.GetDirectoryCount();
243 } else {
244 i = GetDirectoryCount(GetDirectoryId(Dir));
245 }
246 } catch (Exception e) {
247 EndTransaction();
248 throw e;
249 }
250 EndTransaction();
251 if (i == -1) throw Exception("Unkown DB directory: " + toEscapedPath(Dir));
252
253 return i;
254 }
255
256 IntListPtr InstrumentsDb::GetDirectoryIDs(int DirId) {
257 std::stringstream sql;
258 sql << "SELECT dir_id FROM instr_dirs ";
259 sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
260
261 return ExecSqlIntList(sql.str());
262 }
263
264 StringListPtr InstrumentsDb::GetDirectories(String Dir, bool Recursive) {
265 dmsg(2,("InstrumentsDb: GetDirectories(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
266
267 BeginTransaction();
268 try {
269 int dirId = GetDirectoryId(Dir);
270 if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
271
272 StringListPtr pDirs;
273 if (Recursive) {
274 SearchQuery q;
275 DirectoryFinder directoryFinder(&q);
276 DirectoryTreeWalk(Dir, &directoryFinder);
277 pDirs = directoryFinder.GetDirectories();
278 } else {
279 pDirs = GetDirectories(dirId);
280 }
281 EndTransaction();
282 return pDirs;
283 } catch (Exception e) {
284 EndTransaction();
285 throw e;
286 }
287 }
288
289 StringListPtr InstrumentsDb::GetDirectories(int DirId) {
290 std::stringstream sql;
291 sql << "SELECT dir_name FROM instr_dirs ";
292 sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
293 StringListPtr dirs = ExecSqlStringList(sql.str());
294
295 for (int i = 0; i < dirs->size(); i++) {
296 for (int j = 0; j < dirs->at(i).length(); j++) {
297 if (dirs->at(i).at(j) == '/') dirs->at(i).at(j) = '\0';
298 }
299 }
300
301 return dirs;
302 }
303
304 int InstrumentsDb::GetDirectoryId(String Dir) {
305 dmsg(2,("InstrumentsDb: GetDirectoryId(Dir=%s)\n", Dir.c_str()));
306 CheckPathName(Dir);
307
308 if (Dir.empty() || Dir.at(0) != '/') {
309 return -1;
310 } else if (Dir.length() == 1) {
311 // We expect the root directory id to be always 0.
312 return 0;
313 }
314
315 int id = 0, i = 1;
316 int j = (int) Dir.find('/', i);
317
318 while(j != std::string::npos) {
319 id = GetDirectoryId(id, Dir.substr(i, j - i));
320 i = j + 1;
321 if (i >= Dir.length()) return id;
322 j = (int) Dir.find('/', i);
323 }
324
325 return GetDirectoryId(id, Dir.substr(i));
326 }
327
328 int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {
329 dmsg(2,("InstrumentsDb: GetDirectoryId(ParentDirId=%d, DirName=%s)\n", ParentDirId, DirName.c_str()));
330 DirName = toDbName(DirName);
331 std::stringstream sql;
332 sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";
333 sql << ParentDirId << " AND dir_name=?";
334 return ExecSqlInt(sql.str(), DirName);
335 }
336
337 int InstrumentsDb::GetDirectoryId(int InstrId) {
338 dmsg(2,("InstrumentsDb: GetDirectoryId(InstrId=%d)\n", InstrId));
339 std::stringstream sql;
340 sql << "SELECT dir_id FROM instruments WHERE instr_id=" << InstrId;
341 return ExecSqlInt(sql.str());
342 }
343
344 String InstrumentsDb::GetDirectoryName(int DirId) {
345 String sql = "SELECT dir_name FROM instr_dirs WHERE dir_id=" + ToString(DirId);
346 String name = ExecSqlString(sql);
347 if (name.empty()) throw Exception("Directory ID not found");
348 return name;
349 }
350
351 int InstrumentsDb::GetParentDirectoryId(int DirId) {
352 if (DirId == 0) throw Exception("The root directory is specified");
353 String sql = "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" + ToString(DirId);
354 int parentId = ExecSqlInt(sql);
355 if (parentId == -1) throw Exception("DB directory not found");
356 return parentId;
357 }
358
359 String InstrumentsDb::GetDirectoryPath(int DirId) {
360 String path = "";
361 int count = 1000; // used to prevent infinite loops
362
363 while(--count) {
364 if (DirId == 0) {
365 path = "/" + path;
366 break;
367 }
368 path = GetDirectoryName(DirId) + "/" + path;
369 DirId = GetParentDirectoryId(DirId);
370 }
371
372 if (!count) throw Exception("Possible infinite loop detected");
373
374 return path;
375 }
376
377 StringListPtr InstrumentsDb::GetInstrumentsByFile(String File) {
378 dmsg(2,("InstrumentsDb: GetInstrumentsByFile(File=%s)\n", File.c_str()));
379
380 StringListPtr instrs(new std::vector<String>);
381
382 BeginTransaction();
383 try {
384 File = toEscapedFsPath(File);
385 IntListPtr ids = ExecSqlIntList("SELECT instr_id FROM instruments WHERE instr_file=?", File);
386
387 for (int i = 0; i < ids->size(); i++) {
388 String name = GetInstrumentName(ids->at(i));
389 String dir = GetDirectoryPath(GetDirectoryId(ids->at(i)));
390 instrs->push_back(dir + name);
391 }
392 } catch (Exception e) {
393 EndTransaction();
394 throw e;
395 }
396 EndTransaction();
397
398 return instrs;
399 }
400
401 void InstrumentsDb::AddDirectory(String Dir) {
402 dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));
403 CheckPathName(Dir);
404 String ParentDir = GetParentDirectory(Dir);
405
406 BeginTransaction();
407 try {
408 if (Dir.length() > 1) {
409 if (Dir.at(Dir.length() - 1) == '/') Dir.erase(Dir.length() - 1);
410 }
411
412 String dirName = GetFileName(Dir);
413 if(ParentDir.empty() || dirName.empty()) {
414 throw Exception("Failed to add DB directory: " + toEscapedPath(Dir));
415 }
416
417 int id = GetDirectoryId(ParentDir);
418 if (id == -1) throw Exception("DB directory doesn't exist: " + toEscapedPath(ParentDir));
419 int id2 = GetDirectoryId(id, dirName);
420 if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(Dir));
421 id2 = GetInstrumentId(id, dirName);
422 if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(Dir));
423
424 std::stringstream sql;
425 sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";
426 sql << id << ", ?)";
427
428 ExecSql(sql.str(), toDbName(dirName));
429 } catch (Exception e) {
430 EndTransaction();
431 throw e;
432 }
433
434 EndTransaction();
435
436 FireDirectoryCountChanged(ParentDir);
437 }
438
439 void InstrumentsDb::RemoveDirectory(String Dir, bool Force) {
440 dmsg(2,("InstrumentsDb: RemoveDirectory(Dir=%s,Force=%d)\n", Dir.c_str(), Force));
441
442 String ParentDir = GetParentDirectory(Dir);
443
444 BeginTransaction();
445 try {
446 int dirId = GetDirectoryId(Dir);
447 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
448 if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);
449 if(ParentDir.empty()) throw Exception("Unknown parent directory");
450 if (Force) RemoveDirectoryContent(dirId);
451 RemoveDirectory(dirId);
452 } catch (Exception e) {
453 EndTransaction();
454 throw e;
455 }
456
457 EndTransaction();
458 FireDirectoryCountChanged(ParentDir);
459 }
460
461 void InstrumentsDb::RemoveDirectoryContent(int DirId, int Level) {
462 dmsg(2,("InstrumentsDb: RemoveDirectoryContent(DirId=%d,Level=%d)\n", DirId, Level));
463 if (Level > 1000) throw Exception("Directory level too deep: " + ToString(Level));
464 IntListPtr dirIds = GetDirectoryIDs(DirId);
465
466 for (int i = 0; i < dirIds->size(); i++) {
467 RemoveDirectoryContent(dirIds->at(i), Level + 1);
468 }
469
470 RemoveAllDirectories(DirId);
471 RemoveAllInstruments(DirId);
472 }
473
474 void InstrumentsDb::RemoveDirectory(int DirId) {
475 dmsg(2,("InstrumentsDb: RemoveDirectory(DirId=%d)\n", DirId));
476 if (GetInstrumentCount(DirId) > 0 || GetDirectoryCount(DirId) > 0) {
477 throw Exception("The specified DB directory is not empty");
478 }
479
480 std::stringstream sql;
481 sql << "DELETE FROM instr_dirs WHERE dir_id=" << DirId;
482
483 ExecSql(sql.str());
484 }
485
486 void InstrumentsDb::RemoveAllDirectories(int DirId) {
487 dmsg(2,("InstrumentsDb: RemoveAllDirectories(DirId=%d)\n", DirId));
488 IntListPtr dirIds = GetDirectoryIDs(DirId);
489
490 for (int i = 0; i < dirIds->size(); i++) {
491 if (!IsDirectoryEmpty(dirIds->at(i))) {
492 throw Exception("DB directory not empty!");
493 }
494 }
495 std::stringstream sql;
496 sql << "DELETE FROM instr_dirs WHERE parent_dir_id=" << DirId;
497 sql << " AND dir_id!=0";
498
499 ExecSql(sql.str());
500 }
501
502 bool InstrumentsDb::IsDirectoryEmpty(int DirId) {
503 dmsg(2,("InstrumentsDb: IsDirectoryEmpty(DirId=%d)\n", DirId));
504 int dirCount = GetDirectoryCount(DirId);
505 int instrCount = GetInstrumentCount(DirId);
506 dmsg(3,("InstrumentsDb: IsDirectoryEmpty: dirCount=%d,instrCount=%d\n", dirCount, instrCount));
507 if (dirCount == -1 || instrCount == -1) return false;
508 return dirCount == 0 && instrCount == 0;
509 }
510
511 bool InstrumentsDb::DirectoryExist(String Dir) {
512 dmsg(2,("InstrumentsDb: DirectoryExist(Dir=%s)\n", Dir.c_str()));
513 {
514 LockGuard lock(DbInstrumentsMutex);
515 return GetDirectoryId(Dir) != -1;
516 }
517 }
518
519 DbDirectory InstrumentsDb::GetDirectoryInfo(String Dir) {
520 dmsg(2,("InstrumentsDb: GetDirectoryInfo(Dir=%s)\n", Dir.c_str()));
521 DbDirectory d;
522
523 BeginTransaction();
524
525 try {
526 int id = GetDirectoryId(Dir);
527 if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
528
529 sqlite3_stmt *pStmt = NULL;
530 std::stringstream sql;
531 sql << "SELECT created,modified,description FROM instr_dirs ";
532 sql << "WHERE dir_id=" << id;
533
534 int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
535 if (res != SQLITE_OK) {
536 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
537 }
538
539 res = sqlite3_step(pStmt);
540 if(res == SQLITE_ROW) {
541 d.Created = ToString(sqlite3_column_text(pStmt, 0));
542 d.Modified = ToString(sqlite3_column_text(pStmt, 1));
543 d.Description = ToString(sqlite3_column_text(pStmt, 2));
544 } else {
545 sqlite3_finalize(pStmt);
546
547 if (res != SQLITE_DONE) {
548 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
549 } else {
550 throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
551 }
552 }
553
554 sqlite3_finalize(pStmt);
555 } catch (Exception e) {
556 EndTransaction();
557 throw e;
558 }
559
560 EndTransaction();
561 return d;
562 }
563
564 void InstrumentsDb::RenameDirectory(String Dir, String Name) {
565 dmsg(2,("InstrumentsDb: RenameDirectory(Dir=%s,Name=%s)\n", Dir.c_str(), Name.c_str()));
566 CheckFileName(Name);
567 String dbName = toDbName(Name);
568
569 BeginTransaction();
570 try {
571 int dirId = GetDirectoryId(Dir);
572 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedText(Dir));
573
574 std::stringstream sql;
575 sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" << dirId;
576
577 int parent = ExecSqlInt(sql.str());
578 if (parent == -1) throw Exception("Unknown parent directory: " + toEscapedPath(Dir));
579
580 if (GetDirectoryId(parent, dbName) != -1) {
581 String s = toEscapedPath(Name);
582 throw Exception("Cannot rename. Directory with that name already exists: " + s);
583 }
584
585 if (GetInstrumentId(parent, dbName) != -1) {
586 throw Exception("Cannot rename. Instrument with that name exist: " + toEscapedPath(Dir));
587 }
588
589 sql.str("");
590 sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;
591 ExecSql(sql.str(), dbName);
592 } catch (Exception e) {
593 EndTransaction();
594 throw e;
595 }
596
597 EndTransaction();
598 FireDirectoryNameChanged(Dir, toAbstractName(Name));
599 }
600
601 void InstrumentsDb::MoveDirectory(String Dir, String Dst) {
602 dmsg(2,("InstrumentsDb: MoveDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
603
604 if(Dir.compare("/") == 0) throw Exception("Cannot move the root directory");
605 String ParentDir = GetParentDirectory(Dir);
606 if(ParentDir.empty()) throw Exception("Unknown parent directory");
607
608 BeginTransaction();
609 try {
610 int dirId = GetDirectoryId(Dir);
611 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
612 int dstId = GetDirectoryId(Dst);
613 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
614 if (dirId == dstId) {
615 throw Exception("Cannot move directory to itself");
616 }
617
618 if (Dir.at(Dir.length() - 1) != '/') Dir.append("/");
619 if (Dst.length() > Dir.length()) {
620 if (Dir.compare(Dst.substr(0, Dir.length())) == 0) {
621 throw Exception("Cannot move a directory to a subdirectory of itself.");
622 }
623 }
624
625 Dir.erase(Dir.length() - 1);
626 String dirName = GetFileName(Dir);
627
628 int id2 = GetDirectoryId(dstId, dirName);
629 if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
630 id2 = GetInstrumentId(dstId, dirName);
631 if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
632
633 std::stringstream sql;
634 sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;
635 sql << " WHERE dir_id=" << dirId;
636 ExecSql(sql.str());
637 } catch (Exception e) {
638 EndTransaction();
639 throw e;
640 }
641
642 EndTransaction();
643 FireDirectoryCountChanged(ParentDir);
644 FireDirectoryCountChanged(Dst);
645 }
646
647 void InstrumentsDb::CopyDirectory(String Dir, String Dst) {
648 dmsg(2,("InstrumentsDb: CopyDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
649
650 if(Dir.compare("/") == 0) throw Exception("Cannot copy the root directory");
651 String ParentDir = GetParentDirectory(Dir);
652 if(ParentDir.empty()) throw Exception("Unknown parent directory");
653
654 BeginTransaction();
655 try {
656 int dirId = GetDirectoryId(Dir);
657 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
658 int dstId = GetDirectoryId(Dst);
659 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
660 if (dirId == dstId) {
661 throw Exception("Cannot copy directory to itself");
662 }
663
664 if (Dir.at(Dir.length() - 1) != '/') Dir.append("/");
665 if (Dst.length() > Dir.length()) {
666 if (Dir.compare(Dst.substr(0, Dir.length())) == 0) {
667 throw Exception("Cannot copy a directory to a subdirectory of itself.");
668 }
669 }
670
671 Dir.erase(Dir.length() - 1);
672 String dirName = GetFileName(Dir);
673
674 int id2 = GetDirectoryId(dstId, dirName);
675 if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
676 id2 = GetInstrumentId(dstId, dirName);
677 if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
678
679 DirectoryCopier directoryCopier(ParentDir, Dst);
680 DirectoryTreeWalk(Dir, &directoryCopier);
681 } catch (Exception e) {
682 EndTransaction();
683 throw e;
684 }
685
686 EndTransaction();
687 }
688
689 void InstrumentsDb::SetDirectoryDescription(String Dir, String Desc) {
690 dmsg(2,("InstrumentsDb: SetDirectoryDescription(Dir=%s,Desc=%s)\n", Dir.c_str(), Desc.c_str()));
691
692 BeginTransaction();
693 try {
694 int id = GetDirectoryId(Dir);
695 if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
696
697 std::stringstream sql;
698 sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";
699 sql << "WHERE dir_id="<< id;
700
701 ExecSql(sql.str(), Desc);
702 } catch (Exception e) {
703 EndTransaction();
704 throw e;
705 }
706 EndTransaction();
707
708 FireDirectoryInfoChanged(Dir);
709 }
710
711 int InstrumentsDb::AddInstruments(ScanMode Mode, String DbDir, String FsDir, bool bBackground, bool insDir) {
712 dmsg(2,("InstrumentsDb: AddInstruments(Mode=%d,DbDir=%s,FsDir=%s,bBackground=%d,insDir=%d)\n", Mode, DbDir.c_str(), FsDir.c_str(), bBackground, insDir));
713 if(!bBackground) {
714 switch (Mode) {
715 case NON_RECURSIVE:
716 AddInstrumentsNonrecursive(DbDir, FsDir, insDir);
717 break;
718 case RECURSIVE:
719 AddInstrumentsRecursive(DbDir, FsDir, false, insDir);
720 break;
721 case FLAT:
722 AddInstrumentsRecursive(DbDir, FsDir, true, insDir);
723 break;
724 default:
725 throw Exception("Unknown scan mode");
726 }
727
728 return -1;
729 }
730
731 ScanJob job;
732 int jobId = Jobs.AddJob(job);
733 InstrumentsDbThread.Execute(new AddInstrumentsJob(jobId, Mode, DbDir, FsDir, insDir));
734
735 return jobId;
736 }
737
738 int InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, bool bBackground) {
739 dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d,bBackground=%d)\n", DbDir.c_str(), FilePath.c_str(), Index, bBackground));
740 if(!bBackground) {
741 AddInstruments(DbDir, false, FilePath, Index);
742 return -1;
743 }
744
745 ScanJob job;
746 int jobId = Jobs.AddJob(job);
747 InstrumentsDbThread.Execute(new AddInstrumentsFromFileJob(jobId, DbDir, FilePath, Index, false));
748
749 return jobId;
750 }
751
752 void InstrumentsDb::AddInstruments(String DbDir, bool insDir, String FilePath, int Index, ScanProgress* pProgress) {
753 dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,insDir=%d,FilePath=%s,Index=%d)\n", DbDir.c_str(), insDir, FilePath.c_str(), Index));
754 if (DbDir.empty() || FilePath.empty()) return;
755
756 {
757 LockGuard lock(DbInstrumentsMutex);
758
759 int dirId = GetDirectoryId(DbDir);
760 if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedText(DbDir));
761
762 File f = File(FilePath);
763 if (!f.Exist()) {
764 std::stringstream ss;
765 ss << "Fail to stat `" << FilePath << "`: " << f.GetErrorMsg();
766 throw Exception(ss.str());
767 }
768
769 if (!f.IsFile()) {
770 std::stringstream ss;
771 ss << "`" << FilePath << "` is not an instrument file";
772 throw Exception(ss.str());
773 }
774
775 String dir = insDir ? PrepareSubdirectory(DbDir, FilePath) : DbDir;
776 AddInstrumentsFromFile(dir, FilePath, Index, pProgress);
777 }
778 }
779
780 void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, bool insDir, ScanProgress* pProgress) {
781 dmsg(2,("InstrumentsDb: AddInstrumentsNonrecursive(DbDir=%s,FsDir=%s,insDir=%d)\n", DbDir.c_str(), FsDir.c_str(), insDir));
782 if (DbDir.empty() || FsDir.empty()) return;
783
784 {
785 LockGuard lock(DbInstrumentsMutex);
786
787 int dirId = GetDirectoryId(DbDir);
788 if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
789
790 File f = File(FsDir);
791 if (!f.Exist()) {
792 std::stringstream ss;
793 ss << "Fail to stat `" << FsDir << "`: " << f.GetErrorMsg();
794 throw Exception(ss.str());
795 }
796
797 if (!f.IsDirectory()) {
798 throw Exception("Directory expected: " + FsDir);
799 }
800
801 if (FsDir.at(FsDir.length() - 1) != File::DirSeparator) {
802 FsDir.push_back(File::DirSeparator);
803 }
804
805 try {
806 FileListPtr fileList = File::GetFiles(FsDir);
807 for (int i = 0; i < fileList->size(); i++) {
808 String dir = insDir ? PrepareSubdirectory(DbDir, fileList->at(i)) : DbDir;
809 AddInstrumentsFromFile(dir, FsDir + fileList->at(i), -1, pProgress);
810 }
811 } catch(Exception e) {
812 e.PrintMessage();
813 }
814 }
815 }
816
817 void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, bool insDir, ScanProgress* pProgress) {
818 dmsg(2,("InstrumentsDb: AddInstrumentsRecursive(DbDir=%s,FsDir=%s,Flat=%d,insDir=%d)\n", DbDir.c_str(), FsDir.c_str(), Flat, insDir));
819 if (pProgress != NULL) {
820 InstrumentFileCounter c;
821 pProgress->SetTotalFileCount(c.Count(FsDir));
822 }
823
824 DirectoryScanner d;
825 d.Scan(DbDir, FsDir, Flat, insDir, pProgress);
826 }
827
828 int InstrumentsDb::GetInstrumentCount(int DirId) {
829 dmsg(2,("InstrumentsDb: GetInstrumentCount(DirId=%d)\n", DirId));
830 if(DirId == -1) return -1;
831
832 std::stringstream sql;
833 sql << "SELECT COUNT(*) FROM instruments WHERE dir_id=" << DirId;
834
835 return ExecSqlInt(sql.str());
836 }
837
838 int InstrumentsDb::GetInstrumentCount(String Dir, bool Recursive) {
839 dmsg(2,("InstrumentsDb: GetInstrumentCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
840 int i;
841
842 BeginTransaction();
843 try {
844 if (Recursive) {
845 InstrumentCounter instrumentCounter;
846 DirectoryTreeWalk(Dir, &instrumentCounter);
847 i = instrumentCounter.GetInstrumentCount();
848 } else {
849 i = GetInstrumentCount(GetDirectoryId(Dir));
850 }
851 } catch (Exception e) {
852 EndTransaction();
853 throw e;
854 }
855 EndTransaction();
856
857 if (i == -1) throw Exception("Unknown Db directory: " + toEscapedPath(Dir));
858 return i;
859 }
860
861 IntListPtr InstrumentsDb::GetInstrumentIDs(int DirId) {
862 std::stringstream sql;
863 sql << "SELECT instr_id FROM instruments WHERE dir_id=" << DirId;
864
865 return ExecSqlIntList(sql.str());
866 }
867
868 StringListPtr InstrumentsDb::GetInstruments(String Dir, bool Recursive) {
869 dmsg(2,("InstrumentsDb: GetInstruments(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
870 BeginTransaction();
871 try {
872 int dirId = GetDirectoryId(Dir);
873 if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
874
875 StringListPtr pInstrs;
876
877 if(Recursive) {
878 SearchQuery q;
879 InstrumentFinder instrumentFinder(&q);
880 DirectoryTreeWalk(Dir, &instrumentFinder);
881 pInstrs = instrumentFinder.GetInstruments();
882 } else {
883 std::stringstream sql;
884 sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;
885
886 pInstrs = ExecSqlStringList(sql.str());
887 // Converting to abstract names
888 for (int i = 0; i < pInstrs->size(); i++) {
889 for (int j = 0; j < pInstrs->at(i).length(); j++) {
890 if (pInstrs->at(i).at(j) == '/') pInstrs->at(i).at(j) = '\0';
891 }
892 }
893 }
894 EndTransaction();
895 return pInstrs;
896 } catch (Exception e) {
897 EndTransaction();
898 throw e;
899 }
900 }
901
902 int InstrumentsDb::GetInstrumentId(String Instr) {
903 dmsg(2,("InstrumentsDb: GetInstrumentId(Instr=%s)\n", Instr.c_str()));
904 String Dir = GetDirectoryPath(Instr);
905 if (Dir.empty()) return -1;
906
907 return GetInstrumentId(GetDirectoryId(Dir), GetFileName(Instr));
908 }
909
910 int InstrumentsDb::GetInstrumentId(int DirId, String InstrName) {
911 dmsg(2,("InstrumentsDb: GetInstrumentId(DirId=%d,InstrName=%s)\n", DirId, InstrName.c_str()));
912 if (DirId == -1 || InstrName.empty()) return -1;
913
914 std::stringstream sql;
915 sql << "SELECT instr_id FROM instruments WHERE dir_id=";
916 sql << DirId << " AND instr_name=?";
917 return ExecSqlInt(sql.str(), toDbName(InstrName));
918 }
919
920 String InstrumentsDb::GetInstrumentName(int InstrId) {
921 dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));
922 std::stringstream sql;
923 sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;
924 return toAbstractName(ExecSqlString(sql.str()));
925 }
926
927 void InstrumentsDb::RemoveInstrument(String Instr) {
928 dmsg(2,("InstrumentsDb: RemoveInstrument(Instr=%s)\n", Instr.c_str()));
929 String ParentDir = GetDirectoryPath(Instr);
930 if(ParentDir.empty()) throw Exception("Unknown parent directory");
931
932 BeginTransaction();
933 try {
934 int instrId = GetInstrumentId(Instr);
935 if(instrId == -1) {
936 throw Exception("The specified instrument does not exist: " + toEscapedPath(Instr));
937 }
938 RemoveInstrument(instrId);
939 } catch (Exception e) {
940 EndTransaction();
941 throw e;
942 }
943 EndTransaction();
944 FireInstrumentCountChanged(ParentDir);
945 }
946
947 void InstrumentsDb::RemoveInstrument(int InstrId) {
948 dmsg(2,("InstrumentsDb: RemoveInstrument(InstrId=%d)\n", InstrId));
949
950 std::stringstream sql;
951 sql << "DELETE FROM instruments WHERE instr_id=" << InstrId;
952
953 ExecSql(sql.str());
954 }
955
956 void InstrumentsDb::RemoveAllInstruments(int DirId) {
957 dmsg(2,("InstrumentsDb: RemoveAllInstruments(DirId=%d)\n", DirId));
958
959 std::stringstream sql;
960 sql << "DELETE FROM instruments WHERE dir_id=" << DirId;
961 ExecSql(sql.str());
962 }
963
964 DbInstrument InstrumentsDb::GetInstrumentInfo(String Instr) {
965 dmsg(2,("InstrumentsDb: GetInstrumentInfo(Instr=%s)\n", Instr.c_str()));
966 DbInstrument i;
967
968 BeginTransaction();
969 try {
970 int id = GetInstrumentId(Instr);
971 if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
972 i = GetInstrumentInfo(id);
973 } catch (Exception e) {
974 EndTransaction();
975 throw e;
976 }
977 EndTransaction();
978
979 return i;
980 }
981
982 DbInstrument InstrumentsDb::GetInstrumentInfo(int InstrId) {
983 sqlite3_stmt *pStmt = NULL;
984 std::stringstream sql;
985 sql << "SELECT instr_file,instr_nr,format_family,format_version,";
986 sql << "instr_size,created,modified,description,is_drum,product,";
987 sql << "artists,keywords FROM instruments WHERE instr_id=" << InstrId;
988
989 int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
990 if (res != SQLITE_OK) {
991 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
992 }
993
994 DbInstrument i;
995 res = sqlite3_step(pStmt);
996 if(res == SQLITE_ROW) {
997 i.InstrFile = ToString(sqlite3_column_text(pStmt, 0));
998 i.InstrNr = sqlite3_column_int(pStmt, 1);
999 i.FormatFamily = ToString(sqlite3_column_text(pStmt, 2));
1000 i.FormatVersion = ToString(sqlite3_column_text(pStmt, 3));
1001 i.Size = sqlite3_column_int64(pStmt, 4);
1002 i.Created = ToString(sqlite3_column_text(pStmt, 5));
1003 i.Modified = ToString(sqlite3_column_text(pStmt, 6));
1004 i.Description = ToString(sqlite3_column_text(pStmt, 7));
1005 i.IsDrum = sqlite3_column_int(pStmt, 8);
1006 i.Product = ToString(sqlite3_column_text(pStmt, 9));
1007 i.Artists = ToString(sqlite3_column_text(pStmt, 10));
1008 i.Keywords = ToString(sqlite3_column_text(pStmt, 11));
1009 } else {
1010 sqlite3_finalize(pStmt);
1011
1012 if (res != SQLITE_DONE) {
1013 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1014 } else {
1015 throw Exception("Unknown DB instrument");
1016 }
1017 }
1018
1019 sqlite3_finalize(pStmt);
1020 return i;
1021 }
1022
1023 void InstrumentsDb::RenameInstrument(String Instr, String Name) {
1024 dmsg(2,("InstrumentsDb: RenameInstrument(Instr=%s,Name=%s)\n", Instr.c_str(), Name.c_str()));
1025 CheckFileName(Name);
1026
1027 BeginTransaction();
1028 try {
1029 int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1030 if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1031
1032 int instrId = GetInstrumentId(dirId, GetFileName(Instr));
1033 if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1034
1035 if (GetInstrumentId(dirId, Name) != -1) {
1036 String s = toEscapedPath(Name);
1037 throw Exception("Cannot rename. Instrument with that name already exists: " + s);
1038 }
1039
1040 if (GetDirectoryId(dirId, Name) != -1) {
1041 String s = toEscapedPath(Name);
1042 throw Exception("Cannot rename. Directory with that name already exists: " + s);
1043 }
1044
1045 std::stringstream sql;
1046 sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;
1047 ExecSql(sql.str(), toDbName(Name));
1048 } catch (Exception e) {
1049 EndTransaction();
1050 throw e;
1051 }
1052 EndTransaction();
1053 FireInstrumentNameChanged(Instr, toAbstractName(Name));
1054 }
1055
1056 void InstrumentsDb::MoveInstrument(String Instr, String Dst) {
1057 dmsg(2,("InstrumentsDb: MoveInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
1058 String ParentDir = GetDirectoryPath(Instr);
1059 if(ParentDir.empty()) throw Exception("Unknown parent directory");
1060
1061 BeginTransaction();
1062 try {
1063 int dirId = GetDirectoryId(ParentDir);
1064 if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1065
1066 String instrName = GetFileName(Instr);
1067 int instrId = GetInstrumentId(dirId, instrName);
1068 if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1069
1070 int dstId = GetDirectoryId(Dst);
1071 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1072 if (dirId == dstId) {
1073 EndTransaction();
1074 return;
1075 }
1076
1077 if (GetInstrumentId(dstId, instrName) != -1) {
1078 String s = toEscapedPath(instrName);
1079 throw Exception("Cannot move. Instrument with that name already exists: " + s);
1080 }
1081
1082 if (GetDirectoryId(dstId, instrName) != -1) {
1083 String s = toEscapedPath(instrName);
1084 throw Exception("Cannot move. Directory with that name already exists: " + s);
1085 }
1086
1087 std::stringstream sql;
1088 sql << "UPDATE instruments SET dir_id=" << dstId;
1089 sql << " WHERE instr_id=" << instrId;
1090 ExecSql(sql.str());
1091 } catch (Exception e) {
1092 EndTransaction();
1093 throw e;
1094 }
1095 EndTransaction();
1096 FireInstrumentCountChanged(ParentDir);
1097 FireInstrumentCountChanged(Dst);
1098 }
1099
1100 void InstrumentsDb::CopyInstrument(String Instr, String Dst) {
1101 dmsg(2,("InstrumentsDb: CopyInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
1102 String ParentDir = GetDirectoryPath(Instr);
1103 if(ParentDir.empty()) throw Exception("Unknown parent directory");
1104
1105 BeginTransaction();
1106 try {
1107 int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1108 if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1109
1110 String instrName = GetFileName(Instr);
1111 int instrId = GetInstrumentId(dirId, instrName);
1112 if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1113
1114 int dstId = GetDirectoryId(Dst);
1115 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1116 if (dirId == dstId) {
1117 EndTransaction();
1118 return;
1119 }
1120
1121 CopyInstrument(instrId, instrName, dstId, Dst);
1122 } catch (Exception e) {
1123 EndTransaction();
1124 throw e;
1125 }
1126 EndTransaction();
1127
1128 }
1129
1130 void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {
1131 if (GetInstrumentId(DstDirId, InstrName) != -1) {
1132 String s = toEscapedPath(InstrName);
1133 throw Exception("Cannot copy. Instrument with that name already exists: " + s);
1134 }
1135
1136 if (GetDirectoryId(DstDirId, InstrName) != -1) {
1137 String s = toEscapedPath(InstrName);
1138 throw Exception("Cannot copy. Directory with that name already exists: " + s);
1139 }
1140
1141 DbInstrument i = GetInstrumentInfo(InstrId);
1142 sqlite3_stmt *pStmt = NULL;
1143 std::stringstream sql;
1144 sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,instr_nr,format_family,";
1145 sql << "format_version,instr_size,description,is_drum,product,artists,keywords) ";
1146 sql << "VALUES (" << DstDirId << ",?,?," << i.InstrNr << ",?,?," << i.Size << ",?,";
1147 sql << i.IsDrum << ",?,?,?)";
1148
1149 int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
1150 if (res != SQLITE_OK) {
1151 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1152 }
1153
1154 String s = toDbName(InstrName);
1155 BindTextParam(pStmt, 1, s);
1156 BindTextParam(pStmt, 2, i.InstrFile);
1157 BindTextParam(pStmt, 3, i.FormatFamily);
1158 BindTextParam(pStmt, 4, i.FormatVersion);
1159 BindTextParam(pStmt, 5, i.Description);
1160 BindTextParam(pStmt, 6, i.Product);
1161 BindTextParam(pStmt, 7, i.Artists);
1162 BindTextParam(pStmt, 8, i.Keywords);
1163
1164 res = sqlite3_step(pStmt);
1165 if(res != SQLITE_DONE) {
1166 sqlite3_finalize(pStmt);
1167 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1168 }
1169
1170 sqlite3_finalize(pStmt);
1171 FireInstrumentCountChanged(DstDir);
1172 }
1173
1174 void InstrumentsDb::SetInstrumentDescription(String Instr, String Desc) {
1175 dmsg(2,("InstrumentsDb: SetInstrumentDescription(Instr=%s,Desc=%s)\n", Instr.c_str(), Desc.c_str()));
1176
1177 BeginTransaction();
1178 try {
1179 int id = GetInstrumentId(Instr);
1180 if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1181
1182 std::stringstream sql;
1183 sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";
1184 sql << "WHERE instr_id="<< id;
1185
1186 ExecSql(sql.str(), Desc);
1187 } catch (Exception e) {
1188 EndTransaction();
1189 throw e;
1190 }
1191 EndTransaction();
1192 FireInstrumentInfoChanged(Instr);
1193 }
1194
1195 void InstrumentsDb::AddInstrumentsFromFile(String DbDir, String file, int Index, ScanProgress* pProgress) {
1196 dmsg(2,("InstrumentsDb: AddInstrumentsFromFile(DbDir=%s,File=%s,Index=%d)\n", DbDir.c_str(), file.c_str(), Index));
1197
1198 if (!InstrumentFileInfo::isSupportedFile(file)) return;
1199
1200 try {
1201 if (pProgress != NULL) {
1202 pProgress->SetStatus(0);
1203 pProgress->CurrentFile = file;
1204 }
1205
1206 int dirId = GetDirectoryId(DbDir);
1207 if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
1208
1209 File f = File(file);
1210 if (!f.Exist()) {
1211 std::stringstream ss;
1212 ss << "Fail to stat `" << file << "`: " << f.GetErrorMsg();
1213 throw Exception(ss.str());
1214 }
1215
1216 if (!f.IsFile()) {
1217 std::stringstream ss;
1218 ss << "`" << file << "` is not a regular file";
1219 throw Exception(ss.str());
1220 }
1221
1222 AddInstrumentsFromFilePriv(DbDir, dirId, file, f, Index, pProgress);
1223
1224 if (pProgress != NULL) {
1225 pProgress->SetScannedFileCount(pProgress->GetScannedFileCount() + 1);
1226 }
1227 } catch(Exception e) {
1228 e.PrintMessage();
1229 }
1230 }
1231
1232 void InstrumentsDb::AddInstrumentsFromFilePriv(String DbDir, const int dirId, String FilePath, File file, int Index, ScanProgress* pProgress) {
1233 dmsg(2,("InstrumentsDb: AddGigInstruments(DbDir=%s,FilePath=%s,Index=%d)\n", DbDir.c_str(), FilePath.c_str(), Index));
1234
1235 bool unlocked = false;
1236 InstrumentFileInfo* fileInfo = NULL;
1237 sqlite3_stmt* pStmt = NULL;
1238 try {
1239 fileInfo = InstrumentFileInfo::getFileInfoFor(FilePath);
1240 if (!fileInfo) return;
1241
1242 std::stringstream sql;
1243 sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";
1244 sql << "instr_nr,format_family,format_version,instr_size,";
1245 sql << "description,is_drum,product,artists,keywords) VALUES (";
1246 sql << dirId << ",?,?,?,?,?," << file.GetSize() << ",?,?,?,?,?)";
1247
1248 // instr_name 1
1249 // instr_file 2
1250 // instr_nr 3
1251 // format_family 4
1252 // format_version 5
1253 // description 6
1254 // is_drum 7
1255 // product 8
1256 // artists 9
1257 // keywords 10
1258
1259 int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
1260 if (res != SQLITE_OK) {
1261 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1262 }
1263
1264 BindTextParam(pStmt, 2, toEscapedFsPath(FilePath));
1265 BindTextParam(pStmt, 4, fileInfo->formatName());
1266 BindTextParam(pStmt, 5, fileInfo->formatVersion());
1267
1268 int instrIndex = (Index == -1) ? 0 : Index;
1269
1270 // Assume that it's locked and should be unlocked at this point
1271 // to be able to use the database from another threads
1272 if (!InTransaction) {
1273 DbInstrumentsMutex.Unlock();
1274 unlocked = true;
1275 } else {
1276 std::cerr << "Shouldn't be in transaction when adding instruments." << std::endl;
1277 }
1278
1279 optional<InstrumentInfo> info = fileInfo->getInstrumentInfo(0, pProgress);
1280 if (!InTransaction) DbInstrumentsMutex.Lock();
1281 while (info) {
1282 String instrumentName = info->instrumentName;
1283 if (instrumentName.empty())
1284 instrumentName = Path::getBaseName(FilePath);
1285 instrumentName = GetUniqueName(dirId, instrumentName);
1286
1287 BindTextParam(pStmt, 8, info->product);
1288 BindTextParam(pStmt, 9, info->artists);
1289 BindTextParam(pStmt, 10, info->keywords);
1290
1291 std::stringstream sql2;
1292 sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";
1293 sql2 << "instr_nr=" << instrIndex;
1294 String s = toEscapedFsPath(FilePath);
1295 if (ExecSqlInt(sql2.str(), s) > 0) goto next;
1296
1297 BindTextParam(pStmt, 1, instrumentName);
1298 BindIntParam(pStmt, 3, instrIndex);
1299
1300 BindTextParam(pStmt, 6, info->comments);
1301 BindIntParam(pStmt, 7, info->isDrum);
1302
1303 res = sqlite3_step(pStmt);
1304 if (res != SQLITE_DONE) {
1305 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1306 }
1307 res = sqlite3_reset(pStmt);
1308 FireInstrumentCountChanged(DbDir);
1309
1310 next:
1311 if (Index != -1) break;
1312
1313 instrIndex++;
1314 info = fileInfo->getInstrumentInfo(instrIndex, pProgress);
1315 }
1316 } catch (Exception e) {
1317 if (pStmt) sqlite3_finalize(pStmt);
1318 if (fileInfo) delete fileInfo;
1319 if (unlocked) DbInstrumentsMutex.Lock();
1320 std::stringstream ss;
1321 ss << "Failed to scan `" << FilePath << "`: " << e.Message();
1322 throw Exception(ss.str());
1323 } catch (...) {
1324 if (pStmt) sqlite3_finalize(pStmt);
1325 if (fileInfo) delete fileInfo;
1326 if (unlocked) DbInstrumentsMutex.Lock();
1327 throw Exception("Failed to scan `" + FilePath + "`");
1328 }
1329 if (pStmt) sqlite3_finalize(pStmt);
1330 if (fileInfo) delete fileInfo;
1331 if (unlocked) DbInstrumentsMutex.Lock();
1332 }
1333
1334 void InstrumentsDb::DirectoryTreeWalk(String AbstractPath, DirectoryHandler* pHandler) {
1335 int DirId = GetDirectoryId(AbstractPath);
1336 if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(AbstractPath));
1337 DirectoryTreeWalk(pHandler, AbstractPath, DirId, 0);
1338 }
1339
1340 void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String AbstractPath, int DirId, int Level) {
1341 if(Level == 1000) throw Exception("Possible infinite loop detected");
1342 pHandler->ProcessDirectory(AbstractPath, DirId);
1343
1344 String s;
1345 StringListPtr pDirs = GetDirectories(DirId);
1346 for(int i = 0; i < pDirs->size(); i++) {
1347 if (AbstractPath.length() == 1 && AbstractPath.at(0) == '/') {
1348 s = "/" + pDirs->at(i);
1349 } else {
1350 s = AbstractPath + "/" + pDirs->at(i);
1351 }
1352 DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);
1353 }
1354 }
1355
1356 StringListPtr InstrumentsDb::FindDirectories(String Dir, SearchQuery* pQuery, bool Recursive) {
1357 dmsg(2,("InstrumentsDb: FindDirectories(Dir=%s)\n", Dir.c_str()));
1358 DirectoryFinder directoryFinder(pQuery);
1359
1360 BeginTransaction();
1361 try {
1362 int DirId = GetDirectoryId(Dir);
1363 if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1364
1365 if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);
1366 else directoryFinder.ProcessDirectory(Dir, DirId);
1367 } catch (Exception e) {
1368 EndTransaction();
1369 throw e;
1370 }
1371 EndTransaction();
1372
1373 return directoryFinder.GetDirectories();
1374 }
1375
1376 StringListPtr InstrumentsDb::FindInstruments(String Dir, SearchQuery* pQuery, bool Recursive) {
1377 dmsg(2,("InstrumentsDb: FindInstruments(Dir=%s)\n", Dir.c_str()));
1378 InstrumentFinder instrumentFinder(pQuery);
1379
1380 BeginTransaction();
1381 try {
1382 int DirId = GetDirectoryId(Dir);
1383 if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1384
1385 if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);
1386 else instrumentFinder.ProcessDirectory(Dir, DirId);
1387 } catch (Exception e) {
1388 EndTransaction();
1389 throw e;
1390 }
1391 EndTransaction();
1392
1393 return instrumentFinder.GetInstruments();
1394 }
1395
1396 StringListPtr InstrumentsDb::FindLostInstrumentFiles() {
1397 dmsg(2,("InstrumentsDb: FindLostInstrumentFiles()\n"));
1398
1399 BeginTransaction();
1400 try {
1401 StringListPtr files = ExecSqlStringList("SELECT DISTINCT instr_file FROM instruments");
1402 StringListPtr result(new std::vector<String>);
1403 for (int i = 0; i < files->size(); i++) {
1404 File f(toNonEscapedFsPath(files->at(i)));
1405 if (!f.Exist()) result->push_back(files->at(i));
1406 }
1407 EndTransaction();
1408 return result;
1409 } catch (Exception e) {
1410 EndTransaction();
1411 throw e;
1412 }
1413 }
1414
1415 void InstrumentsDb::SetInstrumentFilePath(String OldPath, String NewPath) {
1416 if (OldPath == NewPath) return;
1417 StringListPtr instrs;
1418 BeginTransaction();
1419 try {
1420 std::vector<String> params(2);
1421 params[0] = toEscapedFsPath(NewPath);
1422 params[1] = toEscapedFsPath(OldPath);
1423 instrs = GetInstrumentsByFile(OldPath);
1424 ExecSql("UPDATE instruments SET instr_file=? WHERE instr_file=?", params);
1425 } catch (Exception e) {
1426 EndTransaction();
1427 throw e;
1428 }
1429 EndTransaction();
1430
1431 for (int i = 0; i < instrs->size(); i++) {
1432 FireInstrumentInfoChanged(instrs->at(i));
1433 }
1434 }
1435
1436 void InstrumentsDb::BeginTransaction() {
1437 dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));
1438 DbInstrumentsMutex.Lock();
1439 if (InTransaction) return;
1440
1441 if(db == NULL) return;
1442 sqlite3_stmt *pStmt = NULL;
1443
1444 InTransaction = true;
1445 int res = sqlite3_prepare(db, "BEGIN TRANSACTION", -1, &pStmt, NULL);
1446 if (res != SQLITE_OK) {
1447 std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1448 return;
1449 }
1450
1451 res = sqlite3_step(pStmt);
1452 if(res != SQLITE_DONE) {
1453 sqlite3_finalize(pStmt);
1454 std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1455 return;
1456 }
1457
1458 sqlite3_finalize(pStmt);
1459 }
1460
1461 void InstrumentsDb::EndTransaction() {
1462 dmsg(2,("InstrumentsDb: EndTransaction(InTransaction=%d)\n", InTransaction));
1463 if (!InTransaction) {
1464 DbInstrumentsMutex.Unlock();
1465 return;
1466 }
1467 InTransaction = false;
1468
1469 if (db == NULL) {
1470 DbInstrumentsMutex.Unlock();
1471 return;
1472 }
1473 sqlite3_stmt *pStmt = NULL;
1474
1475 int res = sqlite3_prepare(db, "END TRANSACTION", -1, &pStmt, NULL);
1476 if (res != SQLITE_OK) {
1477 std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1478 DbInstrumentsMutex.Unlock();
1479 return;
1480 }
1481
1482 res = sqlite3_step(pStmt);
1483 if(res != SQLITE_DONE) {
1484 sqlite3_finalize(pStmt);
1485 std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1486 DbInstrumentsMutex.Unlock();
1487 return;
1488 }
1489
1490 sqlite3_finalize(pStmt);
1491 DbInstrumentsMutex.Unlock();
1492 }
1493
1494 void InstrumentsDb::ExecSql(String Sql) {
1495 dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1496 std::vector<String> Params;
1497 ExecSql(Sql, Params);
1498 }
1499
1500 void InstrumentsDb::ExecSql(String Sql, String Param) {
1501 dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1502 std::vector<String> Params;
1503 Params.push_back(Param);
1504 ExecSql(Sql, Params);
1505 }
1506
1507 void InstrumentsDb::ExecSql(String Sql, std::vector<String>& Params) {
1508 dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Params)\n", Sql.c_str()));
1509 sqlite3_stmt *pStmt = NULL;
1510
1511 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1512 if (res != SQLITE_OK) {
1513 sqlite3_finalize(pStmt);
1514 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1515 }
1516
1517 for(int i = 0; i < Params.size(); i++) {
1518 BindTextParam(pStmt, i + 1, Params[i]);
1519 }
1520
1521 res = sqlite3_step(pStmt);
1522 if (res != SQLITE_DONE) {
1523 sqlite3_finalize(pStmt);
1524 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1525 }
1526
1527 sqlite3_finalize(pStmt);
1528 }
1529
1530 int InstrumentsDb::ExecSqlInt(String Sql) {
1531 dmsg(2,("InstrumentsDb: ExecSqlInt(Sql=%s)\n", Sql.c_str()));
1532 sqlite3_stmt *pStmt = NULL;
1533
1534 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1535 if (res != SQLITE_OK) {
1536 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1537 }
1538
1539 int i = -1;
1540 res = sqlite3_step(pStmt);
1541 if(res == SQLITE_ROW) {
1542 i = sqlite3_column_int(pStmt, 0);
1543 } else if (res != SQLITE_DONE) {
1544 sqlite3_finalize(pStmt);
1545 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1546 }
1547
1548 sqlite3_finalize(pStmt);
1549
1550 return i;
1551 }
1552
1553 int InstrumentsDb::ExecSqlInt(String Sql, String Param) {
1554 dmsg(2,("InstrumentsDb: ExecSqlInt(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1555 sqlite3_stmt *pStmt = NULL;
1556
1557 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1558 if (res != SQLITE_OK) {
1559 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1560 }
1561
1562 BindTextParam(pStmt, 1, Param);
1563
1564 int i = -1;
1565 res = sqlite3_step(pStmt);
1566 if(res == SQLITE_ROW) {
1567 i = sqlite3_column_int(pStmt, 0);
1568 } else if (res != SQLITE_DONE) {
1569 sqlite3_finalize(pStmt);
1570 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1571 }
1572
1573 sqlite3_finalize(pStmt);
1574 return i;
1575 }
1576
1577 String InstrumentsDb::ExecSqlString(String Sql) {
1578 dmsg(2,("InstrumentsDb: ExecSqlString(Sql=%s)\n", Sql.c_str()));
1579 sqlite3_stmt *pStmt = NULL;
1580
1581 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1582 if (res != SQLITE_OK) {
1583 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1584 }
1585
1586 String s;
1587 res = sqlite3_step(pStmt);
1588 if(res == SQLITE_ROW) {
1589 s = ToString(sqlite3_column_text(pStmt, 0));
1590 } else if (res != SQLITE_DONE) {
1591 sqlite3_finalize(pStmt);
1592 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1593 }
1594
1595 sqlite3_finalize(pStmt);
1596
1597 return s;
1598 }
1599
1600 IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {
1601 dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1602 std::vector<String> Params;
1603 return ExecSqlIntList(Sql, Params);
1604 }
1605
1606 IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, String Param) {
1607 dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1608 std::vector<String> Params;
1609 Params.push_back(Param);
1610 return ExecSqlIntList(Sql, Params);
1611 }
1612
1613 IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, std::vector<String>& Params) {
1614 dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1615 IntListPtr intList(new std::vector<int>);
1616
1617 sqlite3_stmt *pStmt = NULL;
1618
1619 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1620 if (res != SQLITE_OK) {
1621 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1622 }
1623
1624 for(int i = 0; i < Params.size(); i++) {
1625 BindTextParam(pStmt, i + 1, Params[i]);
1626 }
1627
1628 res = sqlite3_step(pStmt);
1629 while(res == SQLITE_ROW) {
1630 intList->push_back(sqlite3_column_int(pStmt, 0));
1631 res = sqlite3_step(pStmt);
1632 }
1633
1634 if (res != SQLITE_DONE) {
1635 sqlite3_finalize(pStmt);
1636 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1637 }
1638
1639 sqlite3_finalize(pStmt);
1640
1641 return intList;
1642 }
1643
1644 StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {
1645 dmsg(2,("InstrumentsDb: ExecSqlStringList(Sql=%s)\n", Sql.c_str()));
1646 StringListPtr stringList(new std::vector<String>);
1647
1648 sqlite3_stmt *pStmt = NULL;
1649
1650 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1651 if (res != SQLITE_OK) {
1652 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1653 }
1654
1655 res = sqlite3_step(pStmt);
1656 while(res == SQLITE_ROW) {
1657 stringList->push_back(ToString(sqlite3_column_text(pStmt, 0)));
1658 res = sqlite3_step(pStmt);
1659 }
1660
1661 if (res != SQLITE_DONE) {
1662 sqlite3_finalize(pStmt);
1663 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1664 }
1665
1666 sqlite3_finalize(pStmt);
1667
1668 return stringList;
1669 }
1670
1671 void InstrumentsDb::BindTextParam(sqlite3_stmt* pStmt, int Index, String Text) {
1672 if (pStmt == NULL) return;
1673 int res = sqlite3_bind_text(pStmt, Index, Text.c_str(), -1, SQLITE_TRANSIENT);
1674 if (res != SQLITE_OK) {
1675 sqlite3_finalize(pStmt);
1676 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1677 }
1678 }
1679
1680 void InstrumentsDb::BindIntParam(sqlite3_stmt* pStmt, int Index, int Param) {
1681 if (pStmt == NULL) return;
1682 int res = sqlite3_bind_int(pStmt, Index, Param);
1683 if (res != SQLITE_OK) {
1684 sqlite3_finalize(pStmt);
1685 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1686 }
1687 }
1688
1689 #ifndef WIN32
1690 void InstrumentsDb::Regexp(sqlite3_context* pContext, int argc, sqlite3_value** ppValue) {
1691 if (argc != 2) return;
1692
1693 String pattern = ToString(sqlite3_value_text(ppValue[0]));
1694 String str = ToString(sqlite3_value_text(ppValue[1]));
1695
1696 if(!fnmatch(pattern.c_str(), str.c_str(), FNM_CASEFOLD)) {
1697 sqlite3_result_int(pContext, 1);
1698 }
1699 }
1700 #endif
1701
1702 String InstrumentsDb::GetDirectoryPath(String File) {
1703 if (File.empty()) return String("");
1704 if (File.at(0) != '/') String("");
1705 if (File.length() == 1) return File;
1706 if (File.at(File.length() - 1) == '/') return File.substr(0, File.length() - 1);
1707 int i = (int) File.rfind('/', File.length() - 1);
1708 if(i == std::string::npos) return String("");
1709 if(i == 0) return String("/");
1710 return File.substr(0, i);
1711 }
1712
1713 String InstrumentsDb::GetFileName(String Path) {
1714 if (Path.length() < 2) return String("");
1715 if (Path.at(0) != '/') String("");
1716 if (Path.at(Path.length() - 1) == '/') return String("");
1717 int i = (int) Path.rfind('/', Path.length() - 1);
1718 return Path.substr(i + 1);
1719 }
1720
1721 void InstrumentsDb::CheckPathName(String Path) {
1722 if (Path.empty()) return;
1723
1724 int i = 0, j = (int)Path.find('/', i);
1725
1726 while(j != std::string::npos) {
1727 if (j + 1 >= Path.length()) return;
1728 if (Path.at(j + 1) == '/') throw Exception("Invalid path name: " + Path);
1729
1730 i = j + 1;
1731 j = (int) Path.find('/', i);
1732 }
1733 }
1734
1735 String InstrumentsDb::GetParentDirectory(String Dir) {
1736 if (Dir.length() < 2) return String("");
1737 if (Dir.at(0) != '/') String("");
1738 int i = (int) Dir.rfind('/', Dir.length() - 2);
1739 if (i == 0) return "/";
1740 return Dir.substr(0, i);
1741 }
1742
1743 void InstrumentsDb::Format() {
1744 {
1745 LockGuard lock(DbInstrumentsMutex);
1746
1747 if (db != NULL) {
1748 sqlite3_close(db);
1749 db = NULL;
1750 }
1751
1752 if (DbFile.empty()) DbFile = GetDefaultDBLocation();
1753 String bkp = DbFile + ".bkp";
1754 remove(bkp.c_str());
1755 if (rename(DbFile.c_str(), bkp.c_str()) && errno != ENOENT) {
1756 throw Exception(String("Failed to backup database: ") + strerror(errno));
1757 }
1758
1759 String f = DbFile;
1760 DbFile = "";
1761 CreateInstrumentsDb(f);
1762 }
1763 FireDirectoryCountChanged("/");
1764 FireInstrumentCountChanged("/");
1765 }
1766
1767 void InstrumentsDb::CheckFileName(String File) {
1768 if (File.empty()) throw Exception("Invalid file name: " + File);
1769 }
1770
1771 String InstrumentsDb::GetUniqueName(int DirId, String Name) {
1772 dmsg(2,("InstrumentsDb: GetUniqueInstrumentName(DirId=%d,Name=%s)\n", DirId, Name.c_str()));
1773
1774 if (GetInstrumentId(DirId, Name) == -1 && GetDirectoryId(DirId, Name) == -1) return Name;
1775 std::stringstream ss;
1776 for(int i = 2; i < 1001; i++) {
1777 ss.str("");
1778 ss << Name << '[' << i << ']';
1779 if (GetInstrumentId(DirId, ss.str()) == -1 && GetInstrumentId(DirId, ss.str()) == -1) {
1780 return ss.str();
1781 }
1782 }
1783
1784 throw Exception("Unable to find an unique name: " + Name);
1785 }
1786
1787 String InstrumentsDb::PrepareSubdirectory(String DbDir, String FsPath) {
1788 std::string dir = Path::getBaseName(FsPath);
1789 dir = toAbstractName(dir);
1790 if(dir.empty()) dir = "New Directory";
1791 dir = GetUniqueName(GetDirectoryId(DbDir), dir);
1792 dir = AppendNode(DbDir, dir);
1793 AddDirectory(dir);
1794 return dir;
1795 }
1796
1797 String InstrumentsDb::AppendNode(String DbDir, String Node) {
1798 if(DbDir.length() == 1 && DbDir.at(0) == '/') return DbDir + Node;
1799 if(DbDir.at(DbDir.length() - 1) == '/') return DbDir + Node;
1800 return DbDir + "/" + Node;
1801 }
1802
1803 String InstrumentsDb::toDbName(String AbstractName) {
1804 for (int i = 0; i < AbstractName.length(); i++) {
1805 if (AbstractName.at(i) == '\0') AbstractName.at(i) = '/';
1806 }
1807 return AbstractName;
1808 }
1809
1810 String InstrumentsDb::toEscapedPath(String AbstractName) {
1811 for (int i = 0; i < AbstractName.length(); i++) {
1812 if (AbstractName.at(i) == '\0') AbstractName.replace(i++, 1, "\\x2f");
1813 else if (AbstractName.at(i) == '\\') AbstractName.replace(i++, 1, "\\\\");
1814 else if (AbstractName.at(i) == '\'') AbstractName.replace(i++, 1, "\\'");
1815 else if (AbstractName.at(i) == '"') AbstractName.replace(i++, 1, "\\\"");
1816 else if (AbstractName.at(i) == '\r') AbstractName.replace(i++, 1, "\\r");
1817 else if (AbstractName.at(i) == '\n') AbstractName.replace(i++, 1, "\\n");
1818 }
1819 return AbstractName;
1820 }
1821
1822 String InstrumentsDb::toEscapedText(String text) {
1823 for (int i = 0; i < text.length(); i++) {
1824 if (text.at(i) == '\\') text.replace(i++, 1, "\\\\");
1825 else if (text.at(i) == '\'') text.replace(i++, 1, "\\'");
1826 else if (text.at(i) == '"') text.replace(i++, 1, "\\\"");
1827 else if (text.at(i) == '\r') text.replace(i++, 1, "\\r");
1828 else if (text.at(i) == '\n') text.replace(i++, 1, "\\n");
1829 }
1830 return text;
1831 }
1832
1833 String InstrumentsDb::toNonEscapedText(String text) {
1834 String sb;
1835 for (int i = 0; i < text.length(); i++) {
1836 char c = text.at(i);
1837 if(c == '\\') {
1838 if(i >= text.length()) {
1839 std::cerr << "Broken escape sequence!" << std::endl;
1840 break;
1841 }
1842 char c2 = text.at(++i);
1843 if(c2 == '\'') sb.push_back('\'');
1844 else if(c2 == '"') sb.push_back('"');
1845 else if(c2 == '\\') sb.push_back('\\');
1846 else if(c2 == 'r') sb.push_back('\r');
1847 else if(c2 == 'n') sb.push_back('\n');
1848 else std::cerr << "Unknown escape sequence \\" << c2 << std::endl;
1849 } else {
1850 sb.push_back(c);
1851 }
1852 }
1853 return sb;
1854 }
1855
1856 String InstrumentsDb::toEscapedFsPath(String FsPath) {
1857 #ifdef WIN32
1858 replace(FsPath.begin(), FsPath.end(), '\\', '/');
1859 #endif
1860 return toEscapedText(FsPath);
1861 }
1862
1863 String InstrumentsDb::toNonEscapedFsPath(String FsPath) {
1864 FsPath = toNonEscapedText(FsPath);
1865 #ifdef WIN32
1866 replace(FsPath.begin(), FsPath.end(), '/', '\\');
1867 #endif
1868 return FsPath;
1869 }
1870
1871 String InstrumentsDb::toAbstractName(String DbName) {
1872 for (int i = 0; i < DbName.length(); i++) {
1873 if (DbName.at(i) == '/') DbName.at(i) = '\0';
1874 }
1875 return DbName;
1876 }
1877
1878 void InstrumentsDb::FireDirectoryCountChanged(String Dir) {
1879 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1880 llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);
1881 }
1882 }
1883
1884 void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {
1885 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1886 llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);
1887 }
1888 }
1889
1890 void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {
1891 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1892 llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);
1893 }
1894 }
1895
1896 void InstrumentsDb::FireInstrumentCountChanged(String Dir) {
1897 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1898 llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);
1899 }
1900 }
1901
1902 void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {
1903 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1904 llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);
1905 }
1906 }
1907
1908 void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {
1909 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1910 llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);
1911 }
1912 }
1913
1914 void InstrumentsDb::FireJobStatusChanged(int JobId) {
1915 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1916 llInstrumentsDbListeners.GetListener(i)->JobStatusChanged(JobId);
1917 }
1918 }
1919
1920 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC