1
0

Clip.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. // ProcessCopy.cpp: implementation of the CProcessCopy class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "AccessToSqlite.h"
  6. #include "..\UnicodeMacros.h"
  7. #include "Clip.h"
  8. #include "..\Crc32Dynamic.h"
  9. #include <Mmsystem.h>
  10. #define CATCH_SQLITE_EXCEPTION \
  11. catch (CppSQLite3Exception& e) \
  12. { \
  13. Log(StrF(_T("SQLITE Exception %d - %s"), e.errorCode(), e.errorMessage())); \
  14. ASSERT(!e.errorMessage()); \
  15. } \
  16. #define CATCH_SQLITE_EXCEPTION_AND_RETURN(bRet) \
  17. catch (CppSQLite3Exception& e) \
  18. { \
  19. Log(StrF(_T("SQLITE Exception %d - %s"), e.errorCode(), e.errorMessage())); \
  20. ASSERT(!e.errorMessage()); \
  21. return bRet; \
  22. } \
  23. #ifdef _DEBUG
  24. #undef THIS_FILE
  25. static char THIS_FILE[]=__FILE__;
  26. #define new DEBUG_NEW
  27. #endif
  28. /*----------------------------------------------------------------------------*\
  29. CClipFormat - holds the data of one clip format.
  30. \*----------------------------------------------------------------------------*/
  31. CClipFormat::CClipFormat(CLIPFORMAT cfType, HGLOBAL hgData)
  32. {
  33. m_cfType = cfType;
  34. m_hgData = hgData;
  35. bDeleteData = true;
  36. }
  37. CClipFormat::~CClipFormat()
  38. {
  39. Free();
  40. }
  41. void CClipFormat::Clear()
  42. {
  43. m_cfType = 0;
  44. m_hgData = 0;
  45. }
  46. void CClipFormat::Free()
  47. {
  48. if(bDeleteData)
  49. {
  50. if(m_hgData)
  51. {
  52. m_hgData = ::GlobalFree( m_hgData );
  53. m_hgData = NULL;
  54. }
  55. }
  56. }
  57. /*----------------------------------------------------------------------------*\
  58. CClipFormats - holds an array of CClipFormat
  59. \*----------------------------------------------------------------------------*/
  60. // returns a pointer to the CClipFormat in this array which matches the given type
  61. // or NULL if that type doesn't exist in this array.
  62. CClipFormat* CClipFormats::FindFormat(UINT cfType)
  63. {
  64. CClipFormat* pCF;
  65. int count = (int)GetSize();
  66. for(int i=0; i < count; i++)
  67. {
  68. pCF = &ElementAt(i);
  69. if(pCF->m_cfType == cfType)
  70. return pCF;
  71. }
  72. return NULL;
  73. }
  74. /*----------------------------------------------------------------------------*\
  75. CClip - holds multiple CClipFormats and CopyClipboard() statistics
  76. \*----------------------------------------------------------------------------*/
  77. DWORD CClip::m_LastAddedCRC = 0;
  78. long CClip::m_LastAddedID = -1;
  79. CClip::CClip() :
  80. m_ID(0),
  81. m_CRC(0),
  82. m_lParent(-1),
  83. m_lDontAutoDelete(FALSE),
  84. m_lShortCut(0),
  85. m_bIsGroup(FALSE)
  86. {
  87. }
  88. CClip::~CClip()
  89. {
  90. EmptyFormats();
  91. }
  92. void CClip::Clear()
  93. {
  94. m_ID = -1;
  95. m_Time = 0;
  96. m_Desc = "";
  97. m_CRC = 0;
  98. m_lParent = -1;
  99. m_lDontAutoDelete = FALSE;
  100. m_lShortCut = 0;
  101. m_bIsGroup = FALSE;
  102. m_csQuickPaste = "";
  103. EmptyFormats();
  104. }
  105. const CClip& CClip::operator=(const CClip &clip)
  106. {
  107. const CClipFormat* pCF;
  108. m_ID = clip.m_ID;
  109. m_Time = clip.m_Time;
  110. m_CRC = clip.m_CRC;
  111. m_lParent = clip.m_lParent;
  112. m_lDontAutoDelete = clip.m_lDontAutoDelete;
  113. m_lShortCut = clip.m_lShortCut;
  114. m_bIsGroup = clip.m_bIsGroup;
  115. m_csQuickPaste = clip.m_csQuickPaste;
  116. int nCount = (int)clip.m_Formats.GetSize();
  117. for(int i = 0; i < nCount; i++)
  118. {
  119. pCF = &clip.m_Formats.GetData()[i];
  120. LPVOID pvData = GlobalLock(pCF->m_hgData);
  121. if(pvData)
  122. {
  123. AddFormat(pCF->m_cfType, pvData, (UINT)GlobalSize(pCF->m_hgData));
  124. }
  125. GlobalUnlock(pCF->m_hgData);
  126. }
  127. //Set this after since in could get the wrong description in AddFormat
  128. m_Desc = clip.m_Desc;
  129. return *this;
  130. }
  131. void CClip::EmptyFormats()
  132. {
  133. // free global memory in m_Formats
  134. for(int i = (int)m_Formats.GetSize()-1; i >= 0; i--)
  135. {
  136. m_Formats[i].Free();
  137. m_Formats.RemoveAt( i );
  138. }
  139. }
  140. // Adds a new Format to this Clip by copying the given data.
  141. bool CClip::AddFormat(CLIPFORMAT cfType, void* pData, UINT nLen)
  142. {
  143. ASSERT(pData && nLen);
  144. HGLOBAL hGlobal = NewGlobalP(pData, nLen);
  145. ASSERT(hGlobal);
  146. // update the Clip statistics
  147. m_Time = m_Time.GetCurrentTime();
  148. CClipFormat format(cfType,hGlobal);
  149. CClipFormat *pFormat;
  150. pFormat = m_Formats.FindFormat(cfType);
  151. // if the format type already exists as part of this clip, replace the data
  152. if(pFormat)
  153. {
  154. pFormat->Free();
  155. pFormat->m_hgData = format.m_hgData;
  156. }
  157. else
  158. {
  159. m_Formats.Add(format);
  160. }
  161. format.m_hgData = 0; // now owned by m_Formats
  162. return true;
  163. }
  164. bool CClip::AddToDB(bool bCheckForDuplicates)
  165. {
  166. bool bResult;
  167. m_CRC = GenerateCRC();
  168. bResult = false;
  169. if(AddToMainTable())
  170. {
  171. bResult = AddToDataTable();
  172. }
  173. // should be emptied by AddToDataTable
  174. ASSERT(m_Formats.GetSize() == 0);
  175. return bResult;
  176. }
  177. DWORD CClip::GenerateCRC()
  178. {
  179. CClipFormat* pCF;
  180. DWORD dwCRC = 0xFFFFFFFF;
  181. CCrc32Dynamic *pCrc32 = new CCrc32Dynamic;
  182. if(pCrc32)
  183. {
  184. //Generate a CRC value for all copied data
  185. int nSize = (int)m_Formats.GetSize();
  186. for(int i = 0; i < nSize ; i++)
  187. {
  188. pCF = & m_Formats.ElementAt(i);
  189. const unsigned char *Data = (const unsigned char *)GlobalLock(pCF->m_hgData);
  190. if(Data)
  191. {
  192. pCrc32->GenerateCrc32((const LPBYTE)Data, (DWORD)GlobalSize(pCF->m_hgData), dwCRC);
  193. }
  194. GlobalUnlock(pCF->m_hgData);
  195. }
  196. dwCRC = ~dwCRC;
  197. delete pCrc32;
  198. }
  199. return dwCRC;
  200. }
  201. // assigns m_ID
  202. bool CClip::AddToMainTable()
  203. {
  204. try
  205. {
  206. m_Desc.Replace(_T("'"), _T("''"));
  207. m_csQuickPaste.Replace(_T("'"), _T("''"));
  208. CString cs;
  209. cs.Format(_T("insert into Main values(NULL, %d, '%s', %d, %d, %d, %d, %d, '%s');"),
  210. (long)m_Time.GetTime(),
  211. m_Desc,
  212. m_lShortCut,
  213. m_lDontAutoDelete,
  214. m_CRC,
  215. m_bIsGroup,
  216. m_lParent,
  217. m_csQuickPaste);
  218. theApp.m_db.execDML(cs);
  219. m_ID = (long)theApp.m_db.lastRowId();
  220. m_LastAddedCRC = m_CRC;
  221. m_LastAddedID = m_ID;
  222. }
  223. CATCH_SQLITE_EXCEPTION_AND_RETURN(false)
  224. return true;
  225. }
  226. // Empties m_Formats as it saves them to the Data Table.
  227. bool CClip::AddToDataTable()
  228. {
  229. CClipFormat* pCF;
  230. try
  231. {
  232. CppSQLite3Statement stmt = theApp.m_db.compileStatement(_T("insert into Data values (NULL, ?, ?, ?);"));
  233. for(int i = (int)m_Formats.GetSize()-1; i >= 0 ; i--)
  234. {
  235. pCF = & m_Formats.ElementAt(i);
  236. stmt.bind(1, m_ID);
  237. stmt.bind(2, GetFormatName(pCF->m_cfType));
  238. const unsigned char *Data = (const unsigned char *)GlobalLock(pCF->m_hgData);
  239. if(Data)
  240. {
  241. stmt.bind(3, Data, (int)GlobalSize(pCF->m_hgData));
  242. }
  243. GlobalUnlock(pCF->m_hgData);
  244. stmt.execDML();
  245. stmt.reset();
  246. m_Formats.RemoveAt(i);
  247. }
  248. }
  249. CATCH_SQLITE_EXCEPTION_AND_RETURN(false)
  250. return true;
  251. }
  252. // changes m_Time to be later than the latest clip entry in the db
  253. // ensures that pClip's time is not older than the last clip added
  254. // old times can happen on fast copies (<1 sec).
  255. void CClip::MakeLatestTime()
  256. {
  257. try
  258. {
  259. CppSQLite3Query q = theApp.m_db.execQuery(_T("SELECT lDate FROM Main ORDER BY lDate DESC LIMIT 1"));
  260. if(q.eof() == false)
  261. {
  262. long lLatestDate = q.getIntField(_T("lDate"));
  263. if(m_Time.GetTime() <= lLatestDate)
  264. {
  265. m_Time = lLatestDate + 1;
  266. }
  267. }
  268. }
  269. CATCH_SQLITE_EXCEPTION
  270. }
  271. BOOL CClip::LoadMainTable(long lID)
  272. {
  273. try
  274. {
  275. CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT * FROM Main WHERE lID = %d"), lID);
  276. if(q.eof() == false)
  277. {
  278. m_Time = q.getIntField(_T("lDate"));
  279. m_Desc = q.getStringField(_T("mText"));
  280. m_CRC = q.getIntField(_T("CRC"));
  281. m_lParent = q.getIntField(_T("lParentID"));
  282. m_lDontAutoDelete = q.getIntField(_T("lDontAutoDelete"));
  283. m_lShortCut = q.getIntField(_T("lShortCut"));
  284. m_bIsGroup = q.getIntField(_T("bIsGroup"));
  285. }
  286. }
  287. CATCH_SQLITE_EXCEPTION_AND_RETURN(FALSE)
  288. return TRUE;
  289. }
  290. // STATICS
  291. // Allocates a Global containing the requested Clip Format Data
  292. HGLOBAL CClip::LoadFormat(long lID, UINT cfType)
  293. {
  294. HGLOBAL hGlobal = 0;
  295. try
  296. {
  297. CString csSQL;
  298. csSQL.Format(
  299. _T("SELECT Data.ooData FROM Data ")
  300. _T("INNER JOIN Main ON Main.lID = Data.lParentID ")
  301. _T("WHERE Main.lID = %d ")
  302. _T("AND Data.strClipBoardFormat = \'%s\'"),
  303. lID,
  304. GetFormatName(cfType));
  305. CppSQLite3Query q = theApp.m_db.execQuery(csSQL);
  306. if(q.eof() == false)
  307. {
  308. int nDataLen = 0;
  309. const unsigned char *cData = q.getBlobField(0, nDataLen);
  310. if(cData == NULL)
  311. {
  312. return false;
  313. }
  314. hGlobal = NewGlobalP((LPVOID)cData, nDataLen);
  315. }
  316. }
  317. CATCH_SQLITE_EXCEPTION
  318. return hGlobal;
  319. }
  320. bool CClip::LoadFormats(long lID, bool bOnlyLoad_CF_TEXT)
  321. {
  322. CClipFormat cf;
  323. HGLOBAL hGlobal = 0;
  324. m_Formats.RemoveAll();
  325. try
  326. {
  327. //Open the data table for all that have the parent id
  328. //Order by Data.lID so that when generating CRC it's always in the same order as the first time
  329. //we generated it
  330. CString csSQL;
  331. csSQL.Format(
  332. _T("SELECT strClipBoardFormat, ooData FROM Data ")
  333. _T("INNER JOIN Main ON Main.lID = Data.lParentID ")
  334. _T("WHERE Main.lID = %d ORDER BY Data.lID desc"), lID);
  335. CppSQLite3Query q = theApp.m_db.execQuery(csSQL);
  336. while(q.eof() == false)
  337. {
  338. cf.m_cfType = GetFormatID(q.getStringField(_T("strClipBoardFormat")));
  339. if(bOnlyLoad_CF_TEXT)
  340. {
  341. if(cf.m_cfType != CF_TEXT && cf.m_cfType != CF_UNICODETEXT)
  342. {
  343. q.nextRow();
  344. continue;
  345. }
  346. }
  347. int nDataLen = 0;
  348. const unsigned char *cData = q.getBlobField(1, nDataLen);
  349. if(cData != NULL)
  350. {
  351. hGlobal = NewGlobalP((LPVOID)cData, nDataLen);
  352. }
  353. cf.m_hgData = hGlobal;
  354. m_Formats.Add(cf);
  355. q.nextRow();
  356. }
  357. // formats owns all the data
  358. cf.m_hgData = 0;
  359. }
  360. CATCH_SQLITE_EXCEPTION_AND_RETURN(false)
  361. return m_Formats.GetSize() > 0;
  362. }
  363. void CClip::LoadTypes(long lID, CClipTypes& types)
  364. {
  365. types.RemoveAll();
  366. try
  367. {
  368. CString csSQL;
  369. // get formats for Clip "lID" (Main.lID) using the corresponding Main.lDataID
  370. //Order by Data.lID so that when generating CRC it's always in the same order as the first time
  371. //we generated it
  372. csSQL.Format(
  373. _T("SELECT strClipBoardFormat FROM Data ")
  374. _T("INNER JOIN Main ON Main.lID = Data.lParentID ")
  375. _T("WHERE Main.lID = %d ORDER BY Data.lID desc"), lID);
  376. CppSQLite3Query q = theApp.m_db.execQuery(csSQL);
  377. while(q.eof() == false)
  378. {
  379. types.Add(GetFormatID(q.getStringField(0)));
  380. q.nextRow();
  381. }
  382. }
  383. CATCH_SQLITE_EXCEPTION
  384. }