/[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 3091 - (show annotations) (download)
Mon Jan 16 15:01:21 2017 UTC (7 years, 3 months ago) by schoenebeck
File size: 73211 byte(s)
* Cleanup of instruments DB file creation and opening code.
* The instrument DB path of linuxsampler's --create-instruments-db argument
  is now optional, if it is missing, then a default location is used.
* Bumped version (2.0.0.svn39).

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

  ViewVC Help
Powered by ViewVC