/[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 3050 - (show annotations) (download)
Thu Dec 8 12:36:56 2016 UTC (7 years, 4 months ago) by schoenebeck
File size: 71458 byte(s)
* Instruments DB: Fixed memory access bug of general DB
  access code which lead to undefined behavior.

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

  ViewVC Help
Powered by ViewVC