/[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 1200 - (show annotations) (download)
Thu May 24 14:04:18 2007 UTC (12 years, 3 months ago) by iliev
File size: 61489 byte(s)
* Implemented instrument scanning in background
  and commands for monitoring the scan progress

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

  ViewVC Help
Powered by ViewVC