DatabaseUtilities.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. // DatabaseUtilites.cpp: implementation of the CDatabaseUtilites class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "CP_Main.h"
  6. #include "DatabaseUtilities.h"
  7. #include "ProcessPaste.h"
  8. #include <io.h>
  9. #include "AccessToSqlite.h"
  10. //////////////////////////////////////////////////////////////////////
  11. // Construction/Destruction
  12. //////////////////////////////////////////////////////////////////////
  13. BOOL CreateBackup(CString csPath)
  14. {
  15. CString csOriginal;
  16. int count = 0;
  17. // create a backup of the existing database
  18. do
  19. {
  20. count++;
  21. csOriginal = csPath + StrF(_T(".%03d"), count);
  22. // in case of some weird infinite loop
  23. if( count > 50 )
  24. {
  25. ASSERT(0);
  26. return FALSE;
  27. }
  28. } while( !::CopyFile(csPath, csOriginal, TRUE));
  29. return TRUE;
  30. }
  31. CString GetDBName()
  32. {
  33. return CGetSetOptions::GetDBPath();
  34. }
  35. CString GetOLDDefaultDBName()
  36. {
  37. CString csDefaultPath;
  38. LPMALLOC pMalloc;
  39. if(SUCCEEDED(::SHGetMalloc(&pMalloc)))
  40. {
  41. LPITEMIDLIST pidlPrograms;
  42. SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidlPrograms);
  43. TCHAR string[MAX_PATH];
  44. SHGetPathFromIDList(pidlPrograms, string);
  45. pMalloc->Free(pidlPrograms);
  46. pMalloc->Release();
  47. csDefaultPath = string;
  48. csDefaultPath += "\\Ditto\\";
  49. csDefaultPath += "DittoDB.mdb";
  50. }
  51. return csDefaultPath;
  52. }
  53. CString GetDefaultDBName()
  54. {
  55. CString csDefaultPath = _T("c:\\program files\\Ditto\\");
  56. if(g_Opt.m_bU3)
  57. {
  58. csDefaultPath = CGetSetOptions::GetPath(PATH_DATABASE);
  59. }
  60. else
  61. {
  62. //If portable then default to the running path
  63. if(CGetSetOptions::GetIsPortableDitto())
  64. {
  65. csDefaultPath.Empty();
  66. }
  67. else
  68. {
  69. LPMALLOC pMalloc;
  70. if(SUCCEEDED(::SHGetMalloc(&pMalloc)))
  71. {
  72. LPITEMIDLIST pidlPrograms;
  73. SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidlPrograms);
  74. TCHAR string[MAX_PATH];
  75. SHGetPathFromIDList(pidlPrograms, string);
  76. pMalloc->Free(pidlPrograms);
  77. pMalloc->Release();
  78. csDefaultPath = string;
  79. }
  80. FIX_CSTRING_PATH(csDefaultPath);
  81. csDefaultPath += "Ditto\\";
  82. }
  83. }
  84. if(FileExists(csDefaultPath) == FALSE)
  85. CreateDirectory(csDefaultPath, NULL);
  86. CString csTempName = csDefaultPath + "Ditto.db";
  87. int i = 1;
  88. while(FileExists(csTempName))
  89. {
  90. csTempName.Format(_T("%sDitto_%d.db"), csDefaultPath, i);
  91. i++;
  92. }
  93. csDefaultPath = csTempName;
  94. return csDefaultPath;
  95. }
  96. BOOL CheckDBExists(CString csDBPath)
  97. {
  98. //If this is the first time running this version then convert the old database to the new db
  99. if(csDBPath.IsEmpty() && g_Opt.m_bU3 == false)
  100. {
  101. csDBPath = GetDefaultDBName();
  102. if(FileExists(csDBPath) == FALSE && CGetSetOptions::GetIsPortableDitto() == FALSE)
  103. {
  104. CString csOldDB = CGetSetOptions::GetDBPathOld();
  105. if(csOldDB.IsEmpty())
  106. {
  107. csOldDB = GetOLDDefaultDBName();
  108. }
  109. if(FileExists(csOldDB))
  110. {
  111. //create the new sqlite db
  112. CreateDB(csDBPath);
  113. CAccessToSqlite Convert;
  114. Convert.ConvertDatabase(csDBPath, csOldDB);
  115. }
  116. }
  117. }
  118. BOOL bRet = FALSE;
  119. if(FileExists(csDBPath) == FALSE)
  120. {
  121. csDBPath = GetDefaultDBName();
  122. // -- create a new one
  123. bRet = CreateDB(csDBPath);
  124. }
  125. else
  126. {
  127. if(ValidDB(csDBPath) == FALSE)
  128. {
  129. //Db existed but was bad
  130. CString csMarkAsBad;
  131. csMarkAsBad = csDBPath;
  132. csMarkAsBad.Replace(_T("."), _T("_BAD."));
  133. CString csPath = GetDefaultDBName();
  134. CString cs;
  135. cs.Format(_T("%s \"%s\",\n")
  136. _T("%s \"%s\",\n")
  137. _T("%s,\n")
  138. _T("\"%s\""),
  139. theApp.m_Language.GetString("Database_Format", "Unrecognized Database Format"),
  140. csDBPath,
  141. theApp.m_Language.GetString("File_Renamed", "the file will be renamed"),
  142. csMarkAsBad,
  143. theApp.m_Language.GetString("New_Database", "and a new database will be created"),
  144. csPath);
  145. AfxMessageBox(cs);
  146. CFile::Rename(csDBPath, csMarkAsBad);
  147. csDBPath = csPath;
  148. bRet = CreateDB(csDBPath);
  149. }
  150. else
  151. bRet = TRUE;
  152. }
  153. if(bRet)
  154. {
  155. bRet = OpenDatabase(csDBPath);
  156. }
  157. return bRet;
  158. }
  159. BOOL OpenDatabase(CString csDB)
  160. {
  161. try
  162. {
  163. theApp.m_db.close();
  164. theApp.m_db.open(csDB);
  165. CGetSetOptions::SetDBPath(csDB);
  166. return TRUE;
  167. }
  168. CATCH_SQLITE_EXCEPTION
  169. return FALSE;
  170. }
  171. BOOL ValidDB(CString csPath, BOOL bUpgrade)
  172. {
  173. try
  174. {
  175. CppSQLite3DB db;
  176. db.open(csPath);
  177. db.execQuery(_T("SELECT lID, lDate, mText, lShortCut, lDontAutoDelete, ")
  178. _T("CRC, bIsGroup, lParentID, QuickPasteText ")
  179. _T("FROM Main"));
  180. db.execQuery(_T("SELECT lID, lParentID, strClipBoardFormat, ooData FROM Data"));
  181. db.execQuery(_T("SELECT lID, TypeText FROM Types"));
  182. //This was added later so try to add each time and catch the exception here
  183. try
  184. {
  185. db.execDML(_T("CREATE TRIGGER delete_data_trigger BEFORE DELETE ON Main FOR EACH ROW\n")
  186. _T("BEGIN\n")
  187. _T("DELETE FROM Data WHERE lParentID = old.lID;\n")
  188. _T("END\n"));
  189. }
  190. catch(CppSQLite3Exception& e)
  191. {
  192. e.errorCode();
  193. }
  194. //This was added later so try to add each time and catch the exception here
  195. try
  196. {
  197. db.execQuery(_T("SELECT lID, lClipID, lCopyBuffer FROM CopyBuffers"));
  198. }
  199. catch(CppSQLite3Exception& e)
  200. {
  201. e.errorCode();
  202. db.execDML(_T("CREATE TABLE CopyBuffers(")
  203. _T("lID INTEGER PRIMARY KEY AUTOINCREMENT, ")
  204. _T("lClipID INTEGER,")
  205. _T("lCopyBuffer INTEGER)"));
  206. db.execDML(_T("CREATE TRIGGER delete_copy_buffer_trigger BEFORE DELETE ON Main FOR EACH ROW\n")
  207. _T("BEGIN\n")
  208. _T("DELETE FROM CopyBuffers WHERE lClipID = old.lID;\n")
  209. _T("END\n"));
  210. }
  211. }
  212. CATCH_SQLITE_EXCEPTION_AND_RETURN(FALSE)
  213. return TRUE;
  214. }
  215. BOOL CreateDB(CString csPath)
  216. {
  217. try
  218. {
  219. CppSQLite3DB db;
  220. db.open(csPath);
  221. db.execDML(_T("CREATE TABLE Main(")
  222. _T("lID INTEGER PRIMARY KEY AUTOINCREMENT, ")
  223. _T("lDate INTEGER, ")
  224. _T("mText TEXT, ")
  225. _T("lShortCut INTEGER, ")
  226. _T("lDontAutoDelete INTEGER, ")
  227. _T("CRC INTEGER, ")
  228. _T("bIsGroup INTEGER, ")
  229. _T("lParentID INTEGER, ")
  230. _T("QuickPasteText TEXT)"));
  231. db.execDML(_T("CREATE TABLE Data(")
  232. _T("lID INTEGER PRIMARY KEY AUTOINCREMENT, ")
  233. _T("lParentID INTEGER, ")
  234. _T("strClipBoardFormat TEXT, ")
  235. _T("ooData BLOB);"));
  236. db.execDML(_T("CREATE TABLE Types(")
  237. _T("lID INTEGER PRIMARY KEY AUTOINCREMENT, ")
  238. _T("TypeText TEXT)"));
  239. db.execDML(_T("CREATE UNIQUE INDEX Main_ID on Main(lID ASC)"));
  240. db.execDML(_T("CREATE UNIQUE INDEX Data_ID on Data(lID ASC)"));
  241. db.execDML(_T("CREATE INDEX Main_Date on Main(lDate DESC)"));
  242. db.execDML(_T("CREATE TRIGGER delete_data_trigger BEFORE DELETE ON Main FOR EACH ROW\n")
  243. _T("BEGIN\n")
  244. _T("DELETE FROM Data WHERE lParentID = old.lID;\n")
  245. _T("END\n"));
  246. db.execDML(_T("CREATE TABLE CopyBuffers(")
  247. _T("lID INTEGER PRIMARY KEY AUTOINCREMENT, ")
  248. _T("lClipID INTEGER, ")
  249. _T("lCopyBuffer INTEGER)"));
  250. db.execDML(_T("CREATE TRIGGER delete_copy_buffer_trigger BEFORE DELETE ON Main FOR EACH ROW\n")
  251. _T("BEGIN\n")
  252. _T("DELETE FROM CopyBuffers WHERE lClipID = old.lID;\n")
  253. _T("END\n"));
  254. db.close();
  255. }
  256. CATCH_SQLITE_EXCEPTION_AND_RETURN(FALSE)
  257. return TRUE;
  258. }
  259. BOOL CompactDatabase()
  260. {
  261. // if(!theApp.CloseDB())
  262. // return FALSE;
  263. //
  264. // CString csDBName = GetDBName();
  265. // CString csTempDBName = csDBName;
  266. // csTempDBName.Replace(".mdb", "TempDBName.mdb");
  267. //
  268. // //Compact the database
  269. // try
  270. // {
  271. // CDaoWorkspace::CompactDatabase(csDBName, csTempDBName);//, dbLangGeneral, 0, "andrew");//DATABASE_PASSWORD);
  272. // }
  273. // catch(CDaoException* e)
  274. // {
  275. // AfxMessageBox(e->m_pErrorInfo->m_strDescription);
  276. // DeleteFile(csTempDBName);
  277. // e->Delete();
  278. // return FALSE;
  279. // }
  280. // catch(CMemoryException* e)
  281. // {
  282. // AfxMessageBox("Memory Exception");
  283. // DeleteFile(csTempDBName);
  284. // e->Delete();
  285. // return FALSE;
  286. // }
  287. //
  288. // //Since compacting the database creates a new db delete the old one and replace it
  289. // //with the compacted db
  290. // if(DeleteFile(csDBName))
  291. // {
  292. // try
  293. // {
  294. // CFile::Rename(csTempDBName, csDBName);
  295. // }
  296. // catch(CFileException *e)
  297. // {
  298. // e->ReportError();
  299. // e->Delete();
  300. // return FALSE;
  301. // }
  302. // }
  303. // else
  304. // AfxMessageBox("Error Compacting Database");
  305. return TRUE;
  306. }
  307. BOOL RepairDatabase()
  308. {
  309. // if(!theApp.CloseDB())
  310. // return FALSE;
  311. // try
  312. // {
  313. // CDaoWorkspace::RepairDatabase(GetDBName());
  314. // }
  315. // catch(CDaoException *e)
  316. // {
  317. // AfxMessageBox(e->m_pErrorInfo->m_strDescription);
  318. // e->Delete();
  319. // return FALSE;
  320. // }
  321. return TRUE;
  322. }
  323. BOOL RemoveOldEntries()
  324. {
  325. try
  326. {
  327. if(CGetSetOptions::GetCheckForMaxEntries())
  328. {
  329. long lMax = CGetSetOptions::GetMaxEntries();
  330. if(lMax >= 0)
  331. {
  332. CClipIDs IDs;
  333. CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lID, lShortCut, lDontAutoDelete FROM Main ORDER BY lDate DESC LIMIT -1 OFFSET %d"), lMax);
  334. while(q.eof() == false)
  335. {
  336. //Only delete entries that have no shortcut and don't have the flag set
  337. if(q.getIntField(_T("lShortCut")) == 0 && q.getIntField(_T("lDontAutoDelete")) == 0)
  338. IDs.Add(q.getIntField(_T("lID")));
  339. q.nextRow();
  340. }
  341. IDs.DeleteIDs();
  342. }
  343. }
  344. if(CGetSetOptions::GetCheckForExpiredEntries())
  345. {
  346. long lExpire = CGetSetOptions::GetExpiredEntries();
  347. if(lExpire)
  348. {
  349. CTime now = CTime::GetCurrentTime();
  350. now -= CTimeSpan(lExpire, 0, 0, 0);
  351. CClipIDs IDs;
  352. CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lID FROM Main ")
  353. _T("WHERE lDate < %d AND ")
  354. _T("lShortCut = 0 AND lDontAutoDelete = 0"), now.GetTime());
  355. while(q.eof() == false)
  356. {
  357. IDs.Add(q.getIntField(_T("lID")));
  358. q.nextRow();
  359. }
  360. IDs.DeleteIDs();
  361. }
  362. }
  363. }
  364. CATCH_SQLITE_EXCEPTION
  365. return TRUE;
  366. }
  367. BOOL EnsureDirectory(CString csPath)
  368. {
  369. TCHAR drive[_MAX_DRIVE];
  370. TCHAR dir[_MAX_DIR];
  371. TCHAR fname[_MAX_FNAME];
  372. TCHAR ext[_MAX_EXT];
  373. SPLITPATH(csPath, drive, dir, fname, ext);
  374. CString csDir(drive);
  375. csDir += dir;
  376. if(FileExists(csDir) == FALSE)
  377. {
  378. if(CreateDirectory(csDir, NULL))
  379. return TRUE;
  380. }
  381. else
  382. return TRUE;
  383. return FALSE;
  384. }
  385. // BOOL RunZippApp(CString csCommandLine)
  386. // {
  387. // CString csLocalPath = GETENV(_T("U3_HOST_EXEC_PATH"));
  388. // FIX_CSTRING_PATH(csLocalPath);
  389. //
  390. // CString csZippApp = GETENV(_T("U3_DEVICE_EXEC_PATH"));
  391. // FIX_CSTRING_PATH(csZippApp);
  392. // csZippApp += "7za.exe";
  393. //
  394. // csZippApp += " ";
  395. // csZippApp += csCommandLine;
  396. //
  397. // Log(csZippApp);
  398. //
  399. // STARTUPINFO StartupInfo;
  400. // PROCESS_INFORMATION ProcessInformation;
  401. //
  402. // ZeroMemory(&StartupInfo, sizeof(StartupInfo));
  403. // StartupInfo.cb = sizeof(StartupInfo);
  404. // ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
  405. //
  406. // StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
  407. // StartupInfo.wShowWindow = SW_HIDE;
  408. //
  409. // BOOL bRet = CreateProcess(NULL, csZippApp.GetBuffer(csZippApp.GetLength()), NULL, NULL, FALSE,
  410. // CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, NULL, csLocalPath,
  411. // &StartupInfo, &ProcessInformation);
  412. //
  413. // if(bRet)
  414. // {
  415. // WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
  416. //
  417. // DWORD dwExitCode;
  418. // GetExitCodeProcess(ProcessInformation.hProcess, &dwExitCode);
  419. //
  420. // CString cs;
  421. // cs.Format(_T("Exit code from unzip = %d"), dwExitCode);
  422. // Log(cs);
  423. //
  424. // if(dwExitCode != 0)
  425. // {
  426. // bRet = FALSE;
  427. // }
  428. // }
  429. // else
  430. // {
  431. // bRet = FALSE;
  432. // Log(_T("Create Process Failed"));
  433. // }
  434. //
  435. // csZippApp.ReleaseBuffer();
  436. //
  437. // return bRet;
  438. // }
  439. // BOOL CopyDownDatabase()
  440. // {
  441. // BOOL bRet = FALSE;
  442. //
  443. // CString csZippedPath = GETENV(_T("U3_APP_DATA_PATH"));
  444. // FIX_CSTRING_PATH(csZippedPath);
  445. //
  446. // CString csUnZippedPath = csZippedPath;
  447. // csUnZippedPath += "Ditto.db";
  448. //
  449. // csZippedPath += "Ditto.7z";
  450. //
  451. // CString csLocalPath = GETENV(_T("U3_HOST_EXEC_PATH"));
  452. // FIX_CSTRING_PATH(csLocalPath);
  453. //
  454. // if(FileExists(csZippedPath))
  455. // {
  456. // CString csCommandLine;
  457. //
  458. // //e = extract
  459. // //surround command line arguments with quotes
  460. // //-aoa = overight files with extracted files
  461. //
  462. // csCommandLine += "e ";
  463. // csCommandLine += "\"";
  464. // csCommandLine += csZippedPath;
  465. // csCommandLine += "\"";
  466. // csCommandLine += " -o";
  467. // csCommandLine += "\"";
  468. // csCommandLine += csLocalPath;
  469. // csCommandLine += "\"";
  470. // csCommandLine += " -aoa";
  471. //
  472. // bRet = RunZippApp(csCommandLine);
  473. //
  474. // csLocalPath += "Ditto.db";
  475. // }
  476. // else if(FileExists(csUnZippedPath))
  477. // {
  478. // csLocalPath += "Ditto.db";
  479. // bRet = CopyFile(csUnZippedPath, csLocalPath, FALSE);
  480. // }
  481. //
  482. // if(FileExists(csLocalPath) == FALSE)
  483. // {
  484. // Log(_T("Failed to copy files from device zip file"));
  485. // }
  486. //
  487. // g_Opt.nLastDbWriteTime = GetLastWriteTime(csLocalPath);
  488. //
  489. // return bRet;
  490. // }
  491. //BOOL CopyUpDatabase()
  492. //{
  493. // CStringA csZippedPath = "C:\\";//getenv("U3_APP_DATA_PATH");
  494. // FIX_CSTRING_PATH(csZippedPath);
  495. // csZippedPath += "Ditto.zip";
  496. // CStringA csLocalPath = GetDBName();//getenv("U3_HOST_EXEC_PATH");
  497. // //FIX_CSTRING_PATH(csLocalPath);
  498. // //csLocalPath += "Ditto.db";
  499. //
  500. // CZipper Zip;
  501. //
  502. // if(Zip.OpenZip(csZippedPath))
  503. // {
  504. // Zip.AddFileToZip(csLocalPath);
  505. // }
  506. //
  507. // return TRUE;
  508. //}