-////////////////////////////////////////////////////////////////////////////////\r
-// CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library.\r
-//\r
-// Copyright (c) 2004 Rob Groves. All Rights Reserved. rob.groves@btinternet.com\r
-// \r
-// Permission to use, copy, modify, and distribute this software and its\r
-// documentation for any purpose, without fee, and without a written\r
-// agreement, is hereby granted, provided that the above copyright notice, \r
-// this paragraph and the following two paragraphs appear in all copies, \r
-// modifications, and distributions.\r
-//\r
-// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,\r
-// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST\r
-// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,\r
-// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
-//\r
-// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT\r
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\r
-// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF\r
-// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION\r
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.\r
-//\r
-// V3.0 03/08/2004 -Initial Version for sqlite3\r
-//\r
-// V3.1 16/09/2004 -Implemented getXXXXField using sqlite3 functions\r
-// -Added CppSQLiteDB3::tableExists()\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "CppSQLite3.h"\r
-#include <cstdlib>\r
-\r
-\r
-// Named constant for passing to CppSQLite3Exception when passing it a string\r
-// that cannot be deleted.\r
-static const bool DONT_DELETE_MSG=false;\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Prototypes for SQLite functions not included in SQLite DLL, but copied below\r
-// from SQLite encode.c\r
-////////////////////////////////////////////////////////////////////////////////\r
-int sqlite3_encode_binary(const unsigned char *in, int n, unsigned char *out);\r
-int sqlite3_decode_binary(const unsigned char *in, unsigned char *out);\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-CppSQLite3Exception::CppSQLite3Exception(const int nErrCode,\r
- const char* szErrMess,\r
- bool bDeleteMsg/*=true*/) :\r
- mnErrCode(nErrCode)\r
-{\r
- mpszErrMess = sqlite3_mprintf("%s[%d]: %s",\r
- errorCodeAsString(nErrCode),\r
- nErrCode,\r
- szErrMess ? szErrMess : "");\r
- /*\r
- if (bDeleteMsg && szErrMess)\r
- {\r
- sqlite3_free(szErrMess);\r
- }\r
- */\r
-}\r
-\r
-CppSQLite3Exception::CppSQLite3Exception(const int nErrCode,\r
- char* szErrMess,\r
- bool bDeleteMsg/*=true*/) :\r
- mnErrCode(nErrCode)\r
-{\r
- mpszErrMess = sqlite3_mprintf("%s[%d]: %s",\r
- errorCodeAsString(nErrCode),\r
- nErrCode,\r
- szErrMess ? szErrMess : "");\r
- \r
- if (bDeleteMsg && szErrMess)\r
- {\r
- sqlite3_free(szErrMess);\r
- }\r
-}\r
- \r
-CppSQLite3Exception::CppSQLite3Exception(const CppSQLite3Exception& e) :\r
- mnErrCode(e.mnErrCode)\r
-{\r
- mpszErrMess = 0;\r
- if (e.mpszErrMess)\r
- {\r
- mpszErrMess = sqlite3_mprintf("%s", e.mpszErrMess);\r
- }\r
-}\r
-\r
-\r
-const char* CppSQLite3Exception::errorCodeAsString(int nErrCode)\r
-{\r
- switch (nErrCode)\r
- {\r
- case SQLITE_OK : return "SQLITE_OK";\r
- case SQLITE_ERROR : return "SQLITE_ERROR";\r
- case SQLITE_INTERNAL : return "SQLITE_INTERNAL";\r
- case SQLITE_PERM : return "SQLITE_PERM";\r
- case SQLITE_ABORT : return "SQLITE_ABORT";\r
- case SQLITE_BUSY : return "SQLITE_BUSY";\r
- case SQLITE_LOCKED : return "SQLITE_LOCKED";\r
- case SQLITE_NOMEM : return "SQLITE_NOMEM";\r
- case SQLITE_READONLY : return "SQLITE_READONLY";\r
- case SQLITE_INTERRUPT : return "SQLITE_INTERRUPT";\r
- case SQLITE_IOERR : return "SQLITE_IOERR";\r
- case SQLITE_CORRUPT : return "SQLITE_CORRUPT";\r
- case SQLITE_NOTFOUND : return "SQLITE_NOTFOUND";\r
- case SQLITE_FULL : return "SQLITE_FULL";\r
- case SQLITE_CANTOPEN : return "SQLITE_CANTOPEN";\r
- case SQLITE_PROTOCOL : return "SQLITE_PROTOCOL";\r
- case SQLITE_EMPTY : return "SQLITE_EMPTY";\r
- case SQLITE_SCHEMA : return "SQLITE_SCHEMA";\r
- case SQLITE_TOOBIG : return "SQLITE_TOOBIG";\r
- case SQLITE_CONSTRAINT : return "SQLITE_CONSTRAINT";\r
- case SQLITE_MISMATCH : return "SQLITE_MISMATCH";\r
- case SQLITE_MISUSE : return "SQLITE_MISUSE";\r
- case SQLITE_NOLFS : return "SQLITE_NOLFS";\r
- case SQLITE_AUTH : return "SQLITE_AUTH";\r
- case SQLITE_FORMAT : return "SQLITE_FORMAT";\r
- case SQLITE_RANGE : return "SQLITE_RANGE";\r
- case SQLITE_ROW : return "SQLITE_ROW";\r
- case SQLITE_DONE : return "SQLITE_DONE";\r
- case CPPSQLITE_ERROR : return "CPPSQLITE_ERROR";\r
- default: return "UNKNOWN_ERROR";\r
- }\r
-}\r
-\r
-\r
-CppSQLite3Exception::~CppSQLite3Exception()\r
-{\r
- if (mpszErrMess)\r
- {\r
- sqlite3_free(mpszErrMess);\r
- mpszErrMess = 0;\r
- }\r
-}\r
-\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-CppSQLite3Buffer::CppSQLite3Buffer()\r
-{\r
- mpBuf = 0;\r
-}\r
-\r
-\r
-CppSQLite3Buffer::~CppSQLite3Buffer()\r
-{\r
- clear();\r
-}\r
-\r
-\r
-void CppSQLite3Buffer::clear()\r
-{\r
- if (mpBuf)\r
- {\r
- sqlite3_free(mpBuf);\r
- mpBuf = 0;\r
- }\r
-\r
-}\r
-\r
-\r
-const char* CppSQLite3Buffer::format(const char* szFormat, ...)\r
-{\r
- clear();\r
- va_list va;\r
- va_start(va, szFormat);\r
- mpBuf = sqlite3_vmprintf(szFormat, va);\r
- va_end(va);\r
- return mpBuf;\r
-}\r
-\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-CppSQLite3Binary::CppSQLite3Binary() :\r
- mpBuf(0),\r
- mnBinaryLen(0),\r
- mnBufferLen(0),\r
- mnEncodedLen(0),\r
- mbEncoded(false)\r
-{\r
-}\r
-\r
-\r
-CppSQLite3Binary::~CppSQLite3Binary()\r
-{\r
- clear();\r
-}\r
-\r
-\r
-void CppSQLite3Binary::setBinary(const unsigned char* pBuf, int nLen)\r
-{\r
- mpBuf = allocBuffer(nLen);\r
- memcpy(mpBuf, pBuf, nLen);\r
-}\r
-\r
-\r
-void CppSQLite3Binary::setEncoded(const unsigned char* pBuf)\r
-{\r
- clear();\r
-\r
- mnEncodedLen = strlen((const char*)pBuf);\r
- mnBufferLen = mnEncodedLen + 1; // Allow for NULL terminator\r
-\r
- mpBuf = (unsigned char*)malloc(mnBufferLen);\r
-\r
- if (!mpBuf)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Cannot allocate memory",\r
- DONT_DELETE_MSG);\r
- }\r
-\r
- memcpy(mpBuf, pBuf, mnBufferLen);\r
- mbEncoded = true;\r
-}\r
-\r
-\r
-const unsigned char* CppSQLite3Binary::getEncoded()\r
-{\r
- if (!mbEncoded)\r
- {\r
- unsigned char* ptmp = (unsigned char*)malloc(mnBinaryLen);\r
- memcpy(ptmp, mpBuf, mnBinaryLen);\r
- mnEncodedLen = sqlite3_encode_binary(ptmp, mnBinaryLen, mpBuf);\r
- free(ptmp);\r
- mbEncoded = true;\r
- }\r
-\r
- return mpBuf;\r
-}\r
-\r
-\r
-const unsigned char* CppSQLite3Binary::getBinary()\r
-{\r
- if (mbEncoded)\r
- {\r
- // in/out buffers can be the same\r
- mnBinaryLen = sqlite3_decode_binary(mpBuf, mpBuf);\r
-\r
- if (mnBinaryLen == -1)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Cannot decode binary",\r
- DONT_DELETE_MSG);\r
- }\r
-\r
- mbEncoded = false;\r
- }\r
-\r
- return mpBuf;\r
-}\r
-\r
-\r
-int CppSQLite3Binary::getBinaryLength()\r
-{\r
- getBinary();\r
- return mnBinaryLen;\r
-}\r
-\r
-\r
-unsigned char* CppSQLite3Binary::allocBuffer(int nLen)\r
-{\r
- clear();\r
-\r
- // Allow extra space for encoded binary as per comments in\r
- // SQLite encode.c See bottom of this file for implementation\r
- // of SQLite functions use 3 instead of 2 just to be sure ;-)\r
- mnBinaryLen = nLen;\r
- mnBufferLen = 3 + (257*nLen)/254;\r
-\r
- mpBuf = (unsigned char*)malloc(mnBufferLen);\r
-\r
- if (!mpBuf)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Cannot allocate memory",\r
- DONT_DELETE_MSG);\r
- }\r
-\r
- mbEncoded = false;\r
-\r
- return mpBuf;\r
-}\r
-\r
-\r
-void CppSQLite3Binary::clear()\r
-{\r
- if (mpBuf)\r
- {\r
- mnBinaryLen = 0;\r
- mnBufferLen = 0;\r
- free(mpBuf);\r
- mpBuf = 0;\r
- }\r
-}\r
-\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-CppSQLite3Query::CppSQLite3Query()\r
-{\r
- mpVM = 0;\r
- mbEof = true;\r
- mnCols = 0;\r
- mbOwnVM = false;\r
-}\r
-\r
-\r
-CppSQLite3Query::CppSQLite3Query(const CppSQLite3Query& rQuery)\r
-{\r
- mpVM = rQuery.mpVM;\r
- // Only one object can own the VM\r
- const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;\r
- mbEof = rQuery.mbEof;\r
- mnCols = rQuery.mnCols;\r
- mbOwnVM = rQuery.mbOwnVM;\r
-}\r
-\r
-\r
-CppSQLite3Query::CppSQLite3Query(sqlite3* pDB,\r
- sqlite3_stmt* pVM,\r
- bool bEof,\r
- bool bOwnVM/*=true*/)\r
-{\r
- mpDB = pDB;\r
- mpVM = pVM;\r
- mbEof = bEof;\r
- mnCols = sqlite3_column_count(mpVM);\r
- mbOwnVM = bOwnVM;\r
-}\r
-\r
-\r
-CppSQLite3Query::~CppSQLite3Query()\r
-{\r
- try\r
- {\r
- finalize();\r
- }\r
- catch (...)\r
- {\r
- }\r
-}\r
-\r
-\r
-CppSQLite3Query& CppSQLite3Query::operator=(const CppSQLite3Query& rQuery)\r
-{\r
- try\r
- {\r
- finalize();\r
- }\r
- catch (...)\r
- {\r
- }\r
- mpVM = rQuery.mpVM;\r
- // Only one object can own the VM\r
- const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;\r
- mbEof = rQuery.mbEof;\r
- mnCols = rQuery.mnCols;\r
- mbOwnVM = rQuery.mbOwnVM;\r
- return *this;\r
-}\r
-\r
-\r
-int CppSQLite3Query::numFields()\r
-{\r
- checkVM();\r
- return mnCols;\r
-}\r
-\r
-\r
-const char* CppSQLite3Query::fieldValue(int nField)\r
-{\r
- checkVM();\r
-\r
- if (nField < 0 || nField > mnCols-1)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Invalid field index requested",\r
- DONT_DELETE_MSG);\r
- }\r
-\r
- return (const char*)sqlite3_column_text(mpVM, nField);\r
-}\r
-\r
-\r
-const char* CppSQLite3Query::fieldValue(const char* szField)\r
-{\r
- int nField = fieldIndex(szField);\r
- return (const char*)sqlite3_column_text(mpVM, nField);\r
-}\r
-\r
-\r
-int CppSQLite3Query::getIntField(int nField, int nNullValue/*=0*/)\r
-{\r
- if (fieldDataType(nField) == SQLITE_NULL)\r
- {\r
- return nNullValue;\r
- }\r
- else\r
- {\r
- return sqlite3_column_int(mpVM, nField);\r
- }\r
-}\r
-\r
-\r
-int CppSQLite3Query::getIntField(const char* szField, int nNullValue/*=0*/)\r
-{\r
- int nField = fieldIndex(szField);\r
- return getIntField(nField, nNullValue);\r
-}\r
-\r
-\r
-double CppSQLite3Query::getFloatField(int nField, double fNullValue/*=0.0*/)\r
-{\r
- if (fieldDataType(nField) == SQLITE_NULL)\r
- {\r
- return fNullValue;\r
- }\r
- else\r
- {\r
- return sqlite3_column_double(mpVM, nField);\r
- }\r
-}\r
-\r
-\r
-double CppSQLite3Query::getFloatField(const char* szField, double fNullValue/*=0.0*/)\r
-{\r
- int nField = fieldIndex(szField);\r
- return getFloatField(nField, fNullValue);\r
-}\r
-\r
-\r
-const char* CppSQLite3Query::getStringField(int nField, const char* szNullValue/*=""*/)\r
-{\r
- if (fieldDataType(nField) == SQLITE_NULL)\r
- {\r
- return szNullValue;\r
- }\r
- else\r
- {\r
- return (const char*)sqlite3_column_text(mpVM, nField);\r
- }\r
-}\r
-\r
-\r
-const char* CppSQLite3Query::getStringField(const char* szField, const char* szNullValue/*=""*/)\r
-{\r
- int nField = fieldIndex(szField);\r
- return getStringField(nField, szNullValue);\r
-}\r
-\r
-\r
-const unsigned char* CppSQLite3Query::getBlobField(int nField, int& nLen)\r
-{\r
- checkVM();\r
-\r
- if (nField < 0 || nField > mnCols-1)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Invalid field index requested",\r
- DONT_DELETE_MSG);\r
- }\r
-\r
- nLen = sqlite3_column_bytes(mpVM, nField);\r
- return (const unsigned char*)sqlite3_column_blob(mpVM, nField);\r
-}\r
-\r
-\r
-const unsigned char* CppSQLite3Query::getBlobField(const char* szField, int& nLen)\r
-{\r
- int nField = fieldIndex(szField);\r
- return getBlobField(nField, nLen);\r
-}\r
-\r
-\r
-bool CppSQLite3Query::fieldIsNull(int nField)\r
-{\r
- return (fieldDataType(nField) == SQLITE_NULL);\r
-}\r
-\r
-\r
-bool CppSQLite3Query::fieldIsNull(const char* szField)\r
-{\r
- int nField = fieldIndex(szField);\r
- return (fieldDataType(nField) == SQLITE_NULL);\r
-}\r
-\r
-\r
-int CppSQLite3Query::fieldIndex(const char* szField)\r
-{\r
- checkVM();\r
-\r
- if (szField)\r
- {\r
- for (int nField = 0; nField < mnCols; nField++)\r
- {\r
- const char* szTemp = sqlite3_column_name(mpVM, nField);\r
-\r
- if (strcmp(szField, szTemp) == 0)\r
- {\r
- return nField;\r
- }\r
- }\r
- }\r
-\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Invalid field name requested",\r
- DONT_DELETE_MSG);\r
-}\r
-\r
-\r
-const char* CppSQLite3Query::fieldName(int nCol)\r
-{\r
- checkVM();\r
-\r
- if (nCol < 0 || nCol > mnCols-1)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Invalid field index requested",\r
- DONT_DELETE_MSG);\r
- }\r
-\r
- return sqlite3_column_name(mpVM, nCol);\r
-}\r
-\r
-\r
-const char* CppSQLite3Query::fieldDeclType(int nCol)\r
-{\r
- checkVM();\r
-\r
- if (nCol < 0 || nCol > mnCols-1)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Invalid field index requested",\r
- DONT_DELETE_MSG);\r
- }\r
-\r
- return sqlite3_column_decltype(mpVM, nCol);\r
-}\r
-\r
-\r
-int CppSQLite3Query::fieldDataType(int nCol)\r
-{\r
- checkVM();\r
-\r
- if (nCol < 0 || nCol > mnCols-1)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Invalid field index requested",\r
- DONT_DELETE_MSG);\r
- }\r
-\r
- return sqlite3_column_type(mpVM, nCol);\r
-}\r
-\r
-\r
-bool CppSQLite3Query::eof()\r
-{\r
- checkVM();\r
- return mbEof;\r
-}\r
-\r
-\r
-void CppSQLite3Query::nextRow()\r
-{\r
- checkVM();\r
-\r
- int nRet = sqlite3_step(mpVM);\r
-\r
- if (nRet == SQLITE_DONE)\r
- {\r
- // no rows\r
- mbEof = true;\r
- }\r
- else if (nRet == SQLITE_ROW)\r
- {\r
- // more rows, nothing to do\r
- }\r
- else\r
- {\r
- nRet = sqlite3_finalize(mpVM);\r
- mpVM = 0;\r
- const char* szError = sqlite3_errmsg(mpDB);\r
- throw CppSQLite3Exception(nRet,\r
- (char*)szError,\r
- DONT_DELETE_MSG);\r
- }\r
-}\r
-\r
-\r
-void CppSQLite3Query::finalize()\r
-{\r
- if (mpVM && mbOwnVM)\r
- {\r
- int nRet = sqlite3_finalize(mpVM);\r
- mpVM = 0;\r
- if (nRet != SQLITE_OK)\r
- {\r
- const char* szError = sqlite3_errmsg(mpDB);\r
- throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
- }\r
- }\r
-}\r
-\r
-\r
-void CppSQLite3Query::checkVM()\r
-{\r
- if (mpVM == 0)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Null Virtual Machine pointer",\r
- DONT_DELETE_MSG);\r
- }\r
-}\r
-\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-CppSQLite3Table::CppSQLite3Table()\r
-{\r
- mpaszResults = 0;\r
- mnRows = 0;\r
- mnCols = 0;\r
- mnCurrentRow = 0;\r
-}\r
-\r
-\r
-CppSQLite3Table::CppSQLite3Table(const CppSQLite3Table& rTable)\r
-{\r
- mpaszResults = rTable.mpaszResults;\r
- // Only one object can own the results\r
- const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;\r
- mnRows = rTable.mnRows;\r
- mnCols = rTable.mnCols;\r
- mnCurrentRow = rTable.mnCurrentRow;\r
-}\r
-\r
-\r
-CppSQLite3Table::CppSQLite3Table(char** paszResults, int nRows, int nCols)\r
-{\r
- mpaszResults = paszResults;\r
- mnRows = nRows;\r
- mnCols = nCols;\r
- mnCurrentRow = 0;\r
-}\r
-\r
-\r
-CppSQLite3Table::~CppSQLite3Table()\r
-{\r
- try\r
- {\r
- finalize();\r
- }\r
- catch (...)\r
- {\r
- }\r
-}\r
-\r
-\r
-CppSQLite3Table& CppSQLite3Table::operator=(const CppSQLite3Table& rTable)\r
-{\r
- try\r
- {\r
- finalize();\r
- }\r
- catch (...)\r
- {\r
- }\r
- mpaszResults = rTable.mpaszResults;\r
- // Only one object can own the results\r
- const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;\r
- mnRows = rTable.mnRows;\r
- mnCols = rTable.mnCols;\r
- mnCurrentRow = rTable.mnCurrentRow;\r
- return *this;\r
-}\r
-\r
-\r
-void CppSQLite3Table::finalize()\r
-{\r
- if (mpaszResults)\r
- {\r
- sqlite3_free_table(mpaszResults);\r
- mpaszResults = 0;\r
- }\r
-}\r
-\r
-\r
-int CppSQLite3Table::numFields()\r
-{\r
- checkResults();\r
- return mnCols;\r
-}\r
-\r
-\r
-int CppSQLite3Table::numRows()\r
-{\r
- checkResults();\r
- return mnRows;\r
-}\r
-\r
-\r
-const char* CppSQLite3Table::fieldValue(int nField)\r
-{\r
- checkResults();\r
-\r
- if (nField < 0 || nField > mnCols-1)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Invalid field index requested",\r
- DONT_DELETE_MSG);\r
- }\r
-\r
- int nIndex = (mnCurrentRow*mnCols) + mnCols + nField;\r
- return mpaszResults[nIndex];\r
-}\r
-\r
-\r
-const char* CppSQLite3Table::fieldValue(const char* szField)\r
-{\r
- checkResults();\r
-\r
- if (szField)\r
- {\r
- for (int nField = 0; nField < mnCols; nField++)\r
- {\r
- if (strcmp(szField, mpaszResults[nField]) == 0)\r
- {\r
- int nIndex = (mnCurrentRow*mnCols) + mnCols + nField;\r
- return mpaszResults[nIndex];\r
- }\r
- }\r
- }\r
-\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Invalid field name requested",\r
- DONT_DELETE_MSG);\r
-}\r
-\r
-\r
-int CppSQLite3Table::getIntField(int nField, int nNullValue/*=0*/)\r
-{\r
- if (fieldIsNull(nField))\r
- {\r
- return nNullValue;\r
- }\r
- else\r
- {\r
- return atoi(fieldValue(nField));\r
- }\r
-}\r
-\r
-\r
-int CppSQLite3Table::getIntField(const char* szField, int nNullValue/*=0*/)\r
-{\r
- if (fieldIsNull(szField))\r
- {\r
- return nNullValue;\r
- }\r
- else\r
- {\r
- return atoi(fieldValue(szField));\r
- }\r
-}\r
-\r
-\r
-double CppSQLite3Table::getFloatField(int nField, double fNullValue/*=0.0*/)\r
-{\r
- if (fieldIsNull(nField))\r
- {\r
- return fNullValue;\r
- }\r
- else\r
- {\r
- return atof(fieldValue(nField));\r
- }\r
-}\r
-\r
-\r
-double CppSQLite3Table::getFloatField(const char* szField, double fNullValue/*=0.0*/)\r
-{\r
- if (fieldIsNull(szField))\r
- {\r
- return fNullValue;\r
- }\r
- else\r
- {\r
- return atof(fieldValue(szField));\r
- }\r
-}\r
-\r
-\r
-const char* CppSQLite3Table::getStringField(int nField, const char* szNullValue/*=""*/)\r
-{\r
- if (fieldIsNull(nField))\r
- {\r
- return szNullValue;\r
- }\r
- else\r
- {\r
- return fieldValue(nField);\r
- }\r
-}\r
-\r
-\r
-const char* CppSQLite3Table::getStringField(const char* szField, const char* szNullValue/*=""*/)\r
-{\r
- if (fieldIsNull(szField))\r
- {\r
- return szNullValue;\r
- }\r
- else\r
- {\r
- return fieldValue(szField);\r
- }\r
-}\r
-\r
-\r
-bool CppSQLite3Table::fieldIsNull(int nField)\r
-{\r
- checkResults();\r
- return (fieldValue(nField) == 0);\r
-}\r
-\r
-\r
-bool CppSQLite3Table::fieldIsNull(const char* szField)\r
-{\r
- checkResults();\r
- return (fieldValue(szField) == 0);\r
-}\r
-\r
-\r
-const char* CppSQLite3Table::fieldName(int nCol)\r
-{\r
- checkResults();\r
-\r
- if (nCol < 0 || nCol > mnCols-1)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Invalid field index requested",\r
- DONT_DELETE_MSG);\r
- }\r
-\r
- return mpaszResults[nCol];\r
-}\r
-\r
-\r
-void CppSQLite3Table::setRow(int nRow)\r
-{\r
- checkResults();\r
-\r
- if (nRow < 0 || nRow > mnRows-1)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Invalid row index requested",\r
- DONT_DELETE_MSG);\r
- }\r
-\r
- mnCurrentRow = nRow;\r
-}\r
-\r
-\r
-void CppSQLite3Table::checkResults()\r
-{\r
- if (mpaszResults == 0)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Null Results pointer",\r
- DONT_DELETE_MSG);\r
- }\r
-}\r
-\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-CppSQLite3Statement::CppSQLite3Statement()\r
-{\r
- mpDB = 0;\r
- mpVM = 0;\r
-}\r
-\r
-\r
-CppSQLite3Statement::CppSQLite3Statement(const CppSQLite3Statement& rStatement)\r
-{\r
- mpDB = rStatement.mpDB;\r
- mpVM = rStatement.mpVM;\r
- // Only one object can own VM\r
- const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0;\r
-}\r
-\r
-\r
-CppSQLite3Statement::CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM)\r
-{\r
- mpDB = pDB;\r
- mpVM = pVM;\r
-}\r
-\r
-\r
-CppSQLite3Statement::~CppSQLite3Statement()\r
-{\r
- try\r
- {\r
- finalize();\r
- }\r
- catch (...)\r
- {\r
- }\r
-}\r
-\r
-\r
-CppSQLite3Statement& CppSQLite3Statement::operator=(const CppSQLite3Statement& rStatement)\r
-{\r
- mpDB = rStatement.mpDB;\r
- mpVM = rStatement.mpVM;\r
- // Only one object can own VM\r
- const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0;\r
- return *this;\r
-}\r
-\r
-\r
-int CppSQLite3Statement::execDML()\r
-{\r
- checkDB();\r
- checkVM();\r
-\r
- const char* szError=0;\r
-\r
- int nRet = sqlite3_step(mpVM);\r
-\r
- if (nRet == SQLITE_DONE)\r
- {\r
- int nRowsChanged = sqlite3_changes(mpDB);\r
-\r
- nRet = sqlite3_reset(mpVM);\r
-\r
- if (nRet != SQLITE_OK)\r
- {\r
- szError = sqlite3_errmsg(mpDB);\r
- throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
- }\r
-\r
- return nRowsChanged;\r
- }\r
- else\r
- {\r
- nRet = sqlite3_reset(mpVM);\r
- szError = sqlite3_errmsg(mpDB);\r
- throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
- }\r
-}\r
-\r
-\r
-CppSQLite3Query CppSQLite3Statement::execQuery()\r
-{\r
- checkDB();\r
- checkVM();\r
-\r
- int nRet = sqlite3_step(mpVM);\r
-\r
- if (nRet == SQLITE_DONE)\r
- {\r
- // no rows\r
- return CppSQLite3Query(mpDB, mpVM, true/*eof*/, false);\r
- }\r
- else if (nRet == SQLITE_ROW)\r
- {\r
- // at least 1 row\r
- return CppSQLite3Query(mpDB, mpVM, false/*eof*/, false);\r
- }\r
- else\r
- {\r
- nRet = sqlite3_reset(mpVM);\r
- const char* szError = sqlite3_errmsg(mpDB);\r
- throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
- }\r
-}\r
-\r
-\r
-void CppSQLite3Statement::bind(int nParam, const char* szValue)\r
-{\r
- checkVM();\r
- int nRes = sqlite3_bind_text(mpVM, nParam, szValue, -1, SQLITE_TRANSIENT);\r
-\r
- if (nRes != SQLITE_OK)\r
- {\r
- throw CppSQLite3Exception(nRes,\r
- "Error binding string param",\r
- DONT_DELETE_MSG);\r
- }\r
-}\r
-\r
-\r
-void CppSQLite3Statement::bind(int nParam, const int nValue)\r
-{\r
- checkVM();\r
- int nRes = sqlite3_bind_int(mpVM, nParam, nValue);\r
-\r
- if (nRes != SQLITE_OK)\r
- {\r
- throw CppSQLite3Exception(nRes,\r
- "Error binding int param",\r
- DONT_DELETE_MSG);\r
- }\r
-}\r
-\r
-\r
-void CppSQLite3Statement::bind(int nParam, const double dValue)\r
-{\r
- checkVM();\r
- int nRes = sqlite3_bind_double(mpVM, nParam, dValue);\r
-\r
- if (nRes != SQLITE_OK)\r
- {\r
- throw CppSQLite3Exception(nRes,\r
- "Error binding double param",\r
- DONT_DELETE_MSG);\r
- }\r
-}\r
-\r
-\r
-void CppSQLite3Statement::bind(int nParam, const unsigned char* blobValue, int nLen)\r
-{\r
- checkVM();\r
- int nRes = sqlite3_bind_blob(mpVM, nParam,\r
- (const void*)blobValue, nLen, SQLITE_TRANSIENT);\r
-\r
- if (nRes != SQLITE_OK)\r
- {\r
- throw CppSQLite3Exception(nRes,\r
- "Error binding blob param",\r
- DONT_DELETE_MSG);\r
- }\r
-}\r
-\r
- \r
-void CppSQLite3Statement::bindNull(int nParam)\r
-{\r
- checkVM();\r
- int nRes = sqlite3_bind_null(mpVM, nParam);\r
-\r
- if (nRes != SQLITE_OK)\r
- {\r
- throw CppSQLite3Exception(nRes,\r
- "Error binding NULL param",\r
- DONT_DELETE_MSG);\r
- }\r
-}\r
-\r
-\r
-void CppSQLite3Statement::reset()\r
-{\r
- if (mpVM)\r
- {\r
- int nRet = sqlite3_reset(mpVM);\r
-\r
- if (nRet != SQLITE_OK)\r
- {\r
- const char* szError = sqlite3_errmsg(mpDB);\r
- throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
- }\r
- }\r
-}\r
-\r
-\r
-void CppSQLite3Statement::finalize()\r
-{\r
- if (mpVM)\r
- {\r
- int nRet = sqlite3_finalize(mpVM);\r
- mpVM = 0;\r
-\r
- if (nRet != SQLITE_OK)\r
- {\r
- const char* szError = sqlite3_errmsg(mpDB);\r
- throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
- }\r
- }\r
-}\r
-\r
-\r
-void CppSQLite3Statement::checkDB()\r
-{\r
- if (mpDB == 0)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Database not open",\r
- DONT_DELETE_MSG);\r
- }\r
-}\r
-\r
-\r
-void CppSQLite3Statement::checkVM()\r
-{\r
- if (mpVM == 0)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Null Virtual Machine pointer",\r
- DONT_DELETE_MSG);\r
- }\r
-}\r
-\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-CppSQLite3DB::CppSQLite3DB()\r
-{\r
- mpDB = 0;\r
- mnBusyTimeoutMs = 60000; // 60 seconds\r
-}\r
-\r
-\r
-CppSQLite3DB::CppSQLite3DB(const CppSQLite3DB& db)\r
-{\r
- mpDB = db.mpDB;\r
- mnBusyTimeoutMs = 60000; // 60 seconds\r
-}\r
-\r
-\r
-CppSQLite3DB::~CppSQLite3DB()\r
-{\r
- close();\r
-}\r
-\r
-\r
-CppSQLite3DB& CppSQLite3DB::operator=(const CppSQLite3DB& db)\r
-{\r
- mpDB = db.mpDB;\r
- mnBusyTimeoutMs = 60000; // 60 seconds\r
- return *this;\r
-}\r
-\r
-\r
-void CppSQLite3DB::open(const char* szFile)\r
-{\r
- int nRet = sqlite3_open(szFile, &mpDB);\r
-\r
- if (nRet != SQLITE_OK)\r
- {\r
- const char* szError = sqlite3_errmsg(mpDB);\r
- throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
- }\r
-\r
- setBusyTimeout(mnBusyTimeoutMs);\r
-}\r
-\r
-\r
-void CppSQLite3DB::close()\r
-{\r
- if (mpDB)\r
- {\r
- sqlite3_close(mpDB);\r
- mpDB = 0;\r
- }\r
-}\r
-\r
-\r
-CppSQLite3Statement CppSQLite3DB::compileStatement(const char* szSQL)\r
-{\r
- checkDB();\r
-\r
- sqlite3_stmt* pVM = compile(szSQL);\r
- return CppSQLite3Statement(mpDB, pVM);\r
-}\r
-\r
-\r
-bool CppSQLite3DB::tableExists(const char* szTable)\r
-{\r
- char szSQL[128];\r
- sprintf(szSQL,\r
- "select count(*) from sqlite_master where type='table' and name='%s'",\r
- szTable);\r
- int nRet = execScalar(szSQL);\r
- return (nRet > 0);\r
-}\r
-\r
-\r
-int CppSQLite3DB::execDML(const char* szSQL)\r
-{\r
- checkDB();\r
-\r
- char* szError=0;\r
-\r
- int nRet = sqlite3_exec(mpDB, szSQL, 0, 0, &szError);\r
-\r
- if (nRet == SQLITE_OK)\r
- {\r
- return sqlite3_changes(mpDB);\r
- }\r
- else\r
- {\r
- throw CppSQLite3Exception(nRet, szError);\r
- }\r
-}\r
-\r
-\r
-CppSQLite3Query CppSQLite3DB::execQuery(const char* szSQL)\r
-{\r
- checkDB();\r
-\r
- sqlite3_stmt* pVM = compile(szSQL);\r
-\r
- int nRet = sqlite3_step(pVM);\r
-\r
- if (nRet == SQLITE_DONE)\r
- {\r
- // no rows\r
- return CppSQLite3Query(mpDB, pVM, true/*eof*/);\r
- }\r
- else if (nRet == SQLITE_ROW)\r
- {\r
- // at least 1 row\r
- return CppSQLite3Query(mpDB, pVM, false/*eof*/);\r
- }\r
- else\r
- {\r
- nRet = sqlite3_finalize(pVM);\r
- const char* szError= sqlite3_errmsg(mpDB);\r
- throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
- }\r
-}\r
-\r
-\r
-int CppSQLite3DB::execScalar(const char* szSQL)\r
-{\r
- CppSQLite3Query q = execQuery(szSQL);\r
-\r
- if (q.eof() || q.numFields() < 1)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Invalid scalar query",\r
- DONT_DELETE_MSG);\r
- }\r
-\r
- return atoi(q.fieldValue(0));\r
-}\r
-\r
-\r
-CppSQLite3Table CppSQLite3DB::getTable(const char* szSQL)\r
-{\r
- checkDB();\r
-\r
- char* szError=0;\r
- char** paszResults=0;\r
- int nRet;\r
- int nRows(0);\r
- int nCols(0);\r
-\r
- nRet = sqlite3_get_table(mpDB, szSQL, &paszResults, &nRows, &nCols, &szError);\r
-\r
- if (nRet == SQLITE_OK)\r
- {\r
- return CppSQLite3Table(paszResults, nRows, nCols);\r
- }\r
- else\r
- {\r
- throw CppSQLite3Exception(nRet, szError);\r
- }\r
-}\r
-\r
-\r
-sqlite_int64 CppSQLite3DB::lastRowId()\r
-{\r
- return sqlite3_last_insert_rowid(mpDB);\r
-}\r
-\r
-\r
-void CppSQLite3DB::setBusyTimeout(int nMillisecs)\r
-{\r
- mnBusyTimeoutMs = nMillisecs;\r
- sqlite3_busy_timeout(mpDB, mnBusyTimeoutMs);\r
-}\r
-\r
-\r
-void CppSQLite3DB::checkDB()\r
-{\r
- if (!mpDB)\r
- {\r
- throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
- "Database not open",\r
- DONT_DELETE_MSG);\r
- }\r
-}\r
-\r
-\r
-sqlite3_stmt* CppSQLite3DB::compile(const char* szSQL)\r
-{\r
- checkDB();\r
-\r
- char* szError=0;\r
- const char* szTail=0;\r
- sqlite3_stmt* pVM;\r
-\r
- int nRet = sqlite3_prepare(mpDB, szSQL, -1, &pVM, &szTail);\r
-\r
- if (nRet != SQLITE_OK)\r
- {\r
- throw CppSQLite3Exception(nRet, szError);\r
- }\r
-\r
- return pVM;\r
-}\r
-\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// SQLite encode.c reproduced here, containing implementation notes and source\r
-// for sqlite3_encode_binary() and sqlite3_decode_binary() \r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-/*\r
-** 2002 April 25\r
-**\r
-** The author disclaims copyright to this source code. In place of\r
-** a legal notice, here is a blessing:\r
-**\r
-** May you do good and not evil.\r
-** May you find forgiveness for yourself and forgive others.\r
-** May you share freely, never taking more than you give.\r
-**\r
-*************************************************************************\r
-** This file contains helper routines used to translate binary data into\r
-** a null-terminated string (suitable for use in SQLite) and back again.\r
-** These are convenience routines for use by people who want to store binary\r
-** data in an SQLite database. The code in this file is not used by any other\r
-** part of the SQLite library.\r
-**\r
-** $Id: CppSQLite3.cpp,v 1.1 2009/02/09 10:09:33 guigues Exp $\r
-*/\r
-\r
-/*\r
-** How This Encoder Works\r
-**\r
-** The output is allowed to contain any character except 0x27 (') and\r
-** 0x00. This is accomplished by using an escape character to encode\r
-** 0x27 and 0x00 as a two-byte sequence. The escape character is always\r
-** 0x01. An 0x00 is encoded as the two byte sequence 0x01 0x01. The\r
-** 0x27 character is encoded as the two byte sequence 0x01 0x03. Finally,\r
-** the escape character itself is encoded as the two-character sequence\r
-** 0x01 0x02.\r
-**\r
-** To summarize, the encoder works by using an escape sequences as follows:\r
-**\r
-** 0x00 -> 0x01 0x01\r
-** 0x01 -> 0x01 0x02\r
-** 0x27 -> 0x01 0x03\r
-**\r
-** If that were all the encoder did, it would work, but in certain cases\r
-** it could double the size of the encoded string. For example, to\r
-** encode a string of 100 0x27 characters would require 100 instances of\r
-** the 0x01 0x03 escape sequence resulting in a 200-character output.\r
-** We would prefer to keep the size of the encoded string smaller than\r
-** this.\r
-**\r
-** To minimize the encoding size, we first add a fixed offset value to each \r
-** byte in the sequence. The addition is modulo 256. (That is to say, if\r
-** the sum of the original character value and the offset exceeds 256, then\r
-** the higher order bits are truncated.) The offset is chosen to minimize\r
-** the number of characters in the string that need to be escaped. For\r
-** example, in the case above where the string was composed of 100 0x27\r
-** characters, the offset might be 0x01. Each of the 0x27 characters would\r
-** then be converted into an 0x28 character which would not need to be\r
-** escaped at all and so the 100 character input string would be converted\r
-** into just 100 characters of output. Actually 101 characters of output - \r
-** we have to record the offset used as the first byte in the sequence so\r
-** that the string can be decoded. Since the offset value is stored as\r
-** part of the output string and the output string is not allowed to contain\r
-** characters 0x00 or 0x27, the offset cannot be 0x00 or 0x27.\r
-**\r
-** Here, then, are the encoding steps:\r
-**\r
-** (1) Choose an offset value and make it the first character of\r
-** output.\r
-**\r
-** (2) Copy each input character into the output buffer, one by\r
-** one, adding the offset value as you copy.\r
-**\r
-** (3) If the value of an input character plus offset is 0x00, replace\r
-** that one character by the two-character sequence 0x01 0x01.\r
-** If the sum is 0x01, replace it with 0x01 0x02. If the sum\r
-** is 0x27, replace it with 0x01 0x03.\r
-**\r
-** (4) Put a 0x00 terminator at the end of the output.\r
-**\r
-** Decoding is obvious:\r
-**\r
-** (5) Copy encoded characters except the first into the decode \r
-** buffer. Set the first encoded character aside for use as\r
-** the offset in step 7 below.\r
-**\r
-** (6) Convert each 0x01 0x01 sequence into a single character 0x00.\r
-** Convert 0x01 0x02 into 0x01. Convert 0x01 0x03 into 0x27.\r
-**\r
-** (7) Subtract the offset value that was the first character of\r
-** the encoded buffer from all characters in the output buffer.\r
-**\r
-** The only tricky part is step (1) - how to compute an offset value to\r
-** minimize the size of the output buffer. This is accomplished by testing\r
-** all offset values and picking the one that results in the fewest number\r
-** of escapes. To do that, we first scan the entire input and count the\r
-** number of occurances of each character value in the input. Suppose\r
-** the number of 0x00 characters is N(0), the number of occurances of 0x01\r
-** is N(1), and so forth up to the number of occurances of 0xff is N(255).\r
-** An offset of 0 is not allowed so we don't have to test it. The number\r
-** of escapes required for an offset of 1 is N(1)+N(2)+N(40). The number\r
-** of escapes required for an offset of 2 is N(2)+N(3)+N(41). And so forth.\r
-** In this way we find the offset that gives the minimum number of escapes,\r
-** and thus minimizes the length of the output string.\r
-*/\r
-\r
-/*\r
-** Encode a binary buffer "in" of size n bytes so that it contains\r
-** no instances of characters '\'' or '\000'. The output is \r
-** null-terminated and can be used as a string value in an INSERT\r
-** or UPDATE statement. Use sqlite3_decode_binary() to convert the\r
-** string back into its original binary.\r
-**\r
-** The result is written into a preallocated output buffer "out".\r
-** "out" must be able to hold at least 2 +(257*n)/254 bytes.\r
-** In other words, the output will be expanded by as much as 3\r
-** bytes for every 254 bytes of input plus 2 bytes of fixed overhead.\r
-** (This is approximately 2 + 1.0118*n or about a 1.2% size increase.)\r
-**\r
-** The return value is the number of characters in the encoded\r
-** string, excluding the "\000" terminator.\r
-*/\r
-int sqlite3_encode_binary(const unsigned char *in, int n, unsigned char *out){\r
- int i, j, e, m;\r
- int cnt[256];\r
- if( n<=0 ){\r
- out[0] = 'x';\r
- out[1] = 0;\r
- return 1;\r
- }\r
- memset(cnt, 0, sizeof(cnt));\r
- for(i=n-1; i>=0; i--){ cnt[in[i]]++; }\r
- m = n;\r
- for(i=1; i<256; i++){\r
- int sum;\r
- if( i=='\'' ) continue;\r
- sum = cnt[i] + cnt[(i+1)&0xff] + cnt[(i+'\'')&0xff];\r
- if( sum<m ){\r
- m = sum;\r
- e = i;\r
- if( m==0 ) break;\r
- }\r
- }\r
- out[0] = e;\r
- j = 1;\r
- for(i=0; i<n; i++){\r
- int c = (in[i] - e)&0xff;\r
- if( c==0 ){\r
- out[j++] = 1;\r
- out[j++] = 1;\r
- }else if( c==1 ){\r
- out[j++] = 1;\r
- out[j++] = 2;\r
- }else if( c=='\'' ){\r
- out[j++] = 1;\r
- out[j++] = 3;\r
- }else{\r
- out[j++] = c;\r
- }\r
- }\r
- out[j] = 0;\r
- return j;\r
-}\r
-\r
-/*\r
-** Decode the string "in" into binary data and write it into "out".\r
-** This routine reverses the encoding created by sqlite3_encode_binary().\r
-** The output will always be a few bytes less than the input. The number\r
-** of bytes of output is returned. If the input is not a well-formed\r
-** encoding, -1 is returned.\r
-**\r
-** The "in" and "out" parameters may point to the same buffer in order\r
-** to decode a string in place.\r
-*/\r
-int sqlite3_decode_binary(const unsigned char *in, unsigned char *out){\r
- int i, c, e;\r
- e = *(in++);\r
- i = 0;\r
- while( (c = *(in++))!=0 ){\r
- if( c==1 ){\r
- c = *(in++);\r
- if( c==1 ){\r
- c = 0;\r
- }else if( c==2 ){\r
- c = 1;\r
- }else if( c==3 ){\r
- c = '\'';\r
- }else{\r
- return -1;\r
- }\r
- }\r
- out[i++] = (c + e)&0xff;\r
- }\r
- return i;\r
-}\r
+////////////////////////////////////////////////////////////////////////////////
+
+// CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library.
+
+//
+
+// Copyright (c) 2004 Rob Groves. All Rights Reserved. rob.groves@btinternet.com
+
+//
+
+// Permission to use, copy, modify, and distribute this software and its
+
+// documentation for any purpose, without fee, and without a written
+
+// agreement, is hereby granted, provided that the above copyright notice,
+
+// this paragraph and the following two paragraphs appear in all copies,
+
+// modifications, and distributions.
+
+//
+
+// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
+
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
+
+// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
+
+// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+
+// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+
+// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
+
+// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION
+
+// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+//
+
+// V3.0 03/08/2004 -Initial Version for sqlite3
+
+//
+
+// V3.1 16/09/2004 -Implemented getXXXXField using sqlite3 functions
+
+// -Added CppSQLiteDB3::tableExists()
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "CppSQLite3.h"
+
+#include <cstdlib>
+
+
+
+
+
+// Named constant for passing to CppSQLite3Exception when passing it a string
+
+// that cannot be deleted.
+
+static const bool DONT_DELETE_MSG=false;
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Prototypes for SQLite functions not included in SQLite DLL, but copied below
+
+// from SQLite encode.c
+
+////////////////////////////////////////////////////////////////////////////////
+
+int sqlite3_encode_binary(const unsigned char *in, int n, unsigned char *out);
+
+int sqlite3_decode_binary(const unsigned char *in, unsigned char *out);
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+CppSQLite3Exception::CppSQLite3Exception(const int nErrCode,
+
+ const char* szErrMess,
+
+ bool bDeleteMsg/*=true*/) :
+
+ mnErrCode(nErrCode)
+
+{
+
+ mpszErrMess = sqlite3_mprintf("%s[%d]: %s",
+
+ errorCodeAsString(nErrCode),
+
+ nErrCode,
+
+ szErrMess ? szErrMess : "");
+
+ /*
+
+ if (bDeleteMsg && szErrMess)
+
+ {
+
+ sqlite3_free(szErrMess);
+
+ }
+
+ */
+
+}
+
+
+
+CppSQLite3Exception::CppSQLite3Exception(const int nErrCode,
+
+ char* szErrMess,
+
+ bool bDeleteMsg/*=true*/) :
+
+ mnErrCode(nErrCode)
+
+{
+
+ mpszErrMess = sqlite3_mprintf("%s[%d]: %s",
+
+ errorCodeAsString(nErrCode),
+
+ nErrCode,
+
+ szErrMess ? szErrMess : "");
+
+
+
+ if (bDeleteMsg && szErrMess)
+
+ {
+
+ sqlite3_free(szErrMess);
+
+ }
+
+}
+
+
+
+CppSQLite3Exception::CppSQLite3Exception(const CppSQLite3Exception& e) :
+
+ mnErrCode(e.mnErrCode)
+
+{
+
+ mpszErrMess = 0;
+
+ if (e.mpszErrMess)
+
+ {
+
+ mpszErrMess = sqlite3_mprintf("%s", e.mpszErrMess);
+
+ }
+
+}
+
+
+
+
+
+const char* CppSQLite3Exception::errorCodeAsString(int nErrCode)
+
+{
+
+ switch (nErrCode)
+
+ {
+
+ case SQLITE_OK : return "SQLITE_OK";
+
+ case SQLITE_ERROR : return "SQLITE_ERROR";
+
+ case SQLITE_INTERNAL : return "SQLITE_INTERNAL";
+
+ case SQLITE_PERM : return "SQLITE_PERM";
+
+ case SQLITE_ABORT : return "SQLITE_ABORT";
+
+ case SQLITE_BUSY : return "SQLITE_BUSY";
+
+ case SQLITE_LOCKED : return "SQLITE_LOCKED";
+
+ case SQLITE_NOMEM : return "SQLITE_NOMEM";
+
+ case SQLITE_READONLY : return "SQLITE_READONLY";
+
+ case SQLITE_INTERRUPT : return "SQLITE_INTERRUPT";
+
+ case SQLITE_IOERR : return "SQLITE_IOERR";
+
+ case SQLITE_CORRUPT : return "SQLITE_CORRUPT";
+
+ case SQLITE_NOTFOUND : return "SQLITE_NOTFOUND";
+
+ case SQLITE_FULL : return "SQLITE_FULL";
+
+ case SQLITE_CANTOPEN : return "SQLITE_CANTOPEN";
+
+ case SQLITE_PROTOCOL : return "SQLITE_PROTOCOL";
+
+ case SQLITE_EMPTY : return "SQLITE_EMPTY";
+
+ case SQLITE_SCHEMA : return "SQLITE_SCHEMA";
+
+ case SQLITE_TOOBIG : return "SQLITE_TOOBIG";
+
+ case SQLITE_CONSTRAINT : return "SQLITE_CONSTRAINT";
+
+ case SQLITE_MISMATCH : return "SQLITE_MISMATCH";
+
+ case SQLITE_MISUSE : return "SQLITE_MISUSE";
+
+ case SQLITE_NOLFS : return "SQLITE_NOLFS";
+
+ case SQLITE_AUTH : return "SQLITE_AUTH";
+
+ case SQLITE_FORMAT : return "SQLITE_FORMAT";
+
+ case SQLITE_RANGE : return "SQLITE_RANGE";
+
+ case SQLITE_ROW : return "SQLITE_ROW";
+
+ case SQLITE_DONE : return "SQLITE_DONE";
+
+ case CPPSQLITE_ERROR : return "CPPSQLITE_ERROR";
+
+ default: return "UNKNOWN_ERROR";
+
+ }
+
+}
+
+
+
+
+
+CppSQLite3Exception::~CppSQLite3Exception()
+
+{
+
+ if (mpszErrMess)
+
+ {
+
+ sqlite3_free(mpszErrMess);
+
+ mpszErrMess = 0;
+
+ }
+
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+CppSQLite3Buffer::CppSQLite3Buffer()
+
+{
+
+ mpBuf = 0;
+
+}
+
+
+
+
+
+CppSQLite3Buffer::~CppSQLite3Buffer()
+
+{
+
+ clear();
+
+}
+
+
+
+
+
+void CppSQLite3Buffer::clear()
+
+{
+
+ if (mpBuf)
+
+ {
+
+ sqlite3_free(mpBuf);
+
+ mpBuf = 0;
+
+ }
+
+
+
+}
+
+
+
+
+
+const char* CppSQLite3Buffer::format(const char* szFormat, ...)
+
+{
+
+ clear();
+
+ va_list va;
+
+ va_start(va, szFormat);
+
+ mpBuf = sqlite3_vmprintf(szFormat, va);
+
+ va_end(va);
+
+ return mpBuf;
+
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+CppSQLite3Binary::CppSQLite3Binary() :
+
+ mpBuf(0),
+
+ mnBinaryLen(0),
+
+ mnBufferLen(0),
+
+ mnEncodedLen(0),
+
+ mbEncoded(false)
+
+{
+
+}
+
+
+
+
+
+CppSQLite3Binary::~CppSQLite3Binary()
+
+{
+
+ clear();
+
+}
+
+
+
+
+
+void CppSQLite3Binary::setBinary(const unsigned char* pBuf, int nLen)
+
+{
+
+ mpBuf = allocBuffer(nLen);
+
+ memcpy(mpBuf, pBuf, nLen);
+
+}
+
+
+
+
+
+void CppSQLite3Binary::setEncoded(const unsigned char* pBuf)
+
+{
+
+ clear();
+
+
+
+ mnEncodedLen = strlen((const char*)pBuf);
+
+ mnBufferLen = mnEncodedLen + 1; // Allow for NULL terminator
+
+
+
+ mpBuf = (unsigned char*)malloc(mnBufferLen);
+
+
+
+ if (!mpBuf)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Cannot allocate memory",
+
+ DONT_DELETE_MSG);
+
+ }
+
+
+
+ memcpy(mpBuf, pBuf, mnBufferLen);
+
+ mbEncoded = true;
+
+}
+
+
+
+
+
+const unsigned char* CppSQLite3Binary::getEncoded()
+
+{
+
+ if (!mbEncoded)
+
+ {
+
+ unsigned char* ptmp = (unsigned char*)malloc(mnBinaryLen);
+
+ memcpy(ptmp, mpBuf, mnBinaryLen);
+
+ mnEncodedLen = sqlite3_encode_binary(ptmp, mnBinaryLen, mpBuf);
+
+ free(ptmp);
+
+ mbEncoded = true;
+
+ }
+
+
+
+ return mpBuf;
+
+}
+
+
+
+
+
+const unsigned char* CppSQLite3Binary::getBinary()
+
+{
+
+ if (mbEncoded)
+
+ {
+
+ // in/out buffers can be the same
+
+ mnBinaryLen = sqlite3_decode_binary(mpBuf, mpBuf);
+
+
+
+ if (mnBinaryLen == -1)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Cannot decode binary",
+
+ DONT_DELETE_MSG);
+
+ }
+
+
+
+ mbEncoded = false;
+
+ }
+
+
+
+ return mpBuf;
+
+}
+
+
+
+
+
+int CppSQLite3Binary::getBinaryLength()
+
+{
+
+ getBinary();
+
+ return mnBinaryLen;
+
+}
+
+
+
+
+
+unsigned char* CppSQLite3Binary::allocBuffer(int nLen)
+
+{
+
+ clear();
+
+
+
+ // Allow extra space for encoded binary as per comments in
+
+ // SQLite encode.c See bottom of this file for implementation
+
+ // of SQLite functions use 3 instead of 2 just to be sure ;-)
+
+ mnBinaryLen = nLen;
+
+ mnBufferLen = 3 + (257*nLen)/254;
+
+
+
+ mpBuf = (unsigned char*)malloc(mnBufferLen);
+
+
+
+ if (!mpBuf)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Cannot allocate memory",
+
+ DONT_DELETE_MSG);
+
+ }
+
+
+
+ mbEncoded = false;
+
+
+
+ return mpBuf;
+
+}
+
+
+
+
+
+void CppSQLite3Binary::clear()
+
+{
+
+ if (mpBuf)
+
+ {
+
+ mnBinaryLen = 0;
+
+ mnBufferLen = 0;
+
+ free(mpBuf);
+
+ mpBuf = 0;
+
+ }
+
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+CppSQLite3Query::CppSQLite3Query()
+
+{
+
+ mpVM = 0;
+
+ mbEof = true;
+
+ mnCols = 0;
+
+ mbOwnVM = false;
+
+}
+
+
+
+
+
+CppSQLite3Query::CppSQLite3Query(const CppSQLite3Query& rQuery)
+
+{
+
+ mpVM = rQuery.mpVM;
+
+ // Only one object can own the VM
+
+ const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;
+
+ mbEof = rQuery.mbEof;
+
+ mnCols = rQuery.mnCols;
+
+ mbOwnVM = rQuery.mbOwnVM;
+
+}
+
+
+
+
+
+CppSQLite3Query::CppSQLite3Query(sqlite3* pDB,
+
+ sqlite3_stmt* pVM,
+
+ bool bEof,
+
+ bool bOwnVM/*=true*/)
+
+{
+
+ mpDB = pDB;
+
+ mpVM = pVM;
+
+ mbEof = bEof;
+
+ mnCols = sqlite3_column_count(mpVM);
+
+ mbOwnVM = bOwnVM;
+
+}
+
+
+
+
+
+CppSQLite3Query::~CppSQLite3Query()
+
+{
+
+ try
+
+ {
+
+ finalize();
+
+ }
+
+ catch (...)
+
+ {
+
+ }
+
+}
+
+
+
+
+
+CppSQLite3Query& CppSQLite3Query::operator=(const CppSQLite3Query& rQuery)
+
+{
+
+ try
+
+ {
+
+ finalize();
+
+ }
+
+ catch (...)
+
+ {
+
+ }
+
+ mpVM = rQuery.mpVM;
+
+ // Only one object can own the VM
+
+ const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;
+
+ mbEof = rQuery.mbEof;
+
+ mnCols = rQuery.mnCols;
+
+ mbOwnVM = rQuery.mbOwnVM;
+
+ return *this;
+
+}
+
+
+
+
+
+int CppSQLite3Query::numFields()
+
+{
+
+ checkVM();
+
+ return mnCols;
+
+}
+
+
+
+
+
+const char* CppSQLite3Query::fieldValue(int nField)
+
+{
+
+ checkVM();
+
+
+
+ if (nField < 0 || nField > mnCols-1)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Invalid field index requested",
+
+ DONT_DELETE_MSG);
+
+ }
+
+
+
+ return (const char*)sqlite3_column_text(mpVM, nField);
+
+}
+
+
+
+
+
+const char* CppSQLite3Query::fieldValue(const char* szField)
+
+{
+
+ int nField = fieldIndex(szField);
+
+ return (const char*)sqlite3_column_text(mpVM, nField);
+
+}
+
+
+
+
+
+int CppSQLite3Query::getIntField(int nField, int nNullValue/*=0*/)
+
+{
+
+ if (fieldDataType(nField) == SQLITE_NULL)
+
+ {
+
+ return nNullValue;
+
+ }
+
+ else
+
+ {
+
+ return sqlite3_column_int(mpVM, nField);
+
+ }
+
+}
+
+
+
+
+
+int CppSQLite3Query::getIntField(const char* szField, int nNullValue/*=0*/)
+
+{
+
+ int nField = fieldIndex(szField);
+
+ return getIntField(nField, nNullValue);
+
+}
+
+
+
+
+
+double CppSQLite3Query::getFloatField(int nField, double fNullValue/*=0.0*/)
+
+{
+
+ if (fieldDataType(nField) == SQLITE_NULL)
+
+ {
+
+ return fNullValue;
+
+ }
+
+ else
+
+ {
+
+ return sqlite3_column_double(mpVM, nField);
+
+ }
+
+}
+
+
+
+
+
+double CppSQLite3Query::getFloatField(const char* szField, double fNullValue/*=0.0*/)
+
+{
+
+ int nField = fieldIndex(szField);
+
+ return getFloatField(nField, fNullValue);
+
+}
+
+
+
+
+
+const char* CppSQLite3Query::getStringField(int nField, const char* szNullValue/*=""*/)
+
+{
+
+ if (fieldDataType(nField) == SQLITE_NULL)
+
+ {
+
+ return szNullValue;
+
+ }
+
+ else
+
+ {
+
+ return (const char*)sqlite3_column_text(mpVM, nField);
+
+ }
+
+}
+
+
+
+
+
+const char* CppSQLite3Query::getStringField(const char* szField, const char* szNullValue/*=""*/)
+
+{
+
+ int nField = fieldIndex(szField);
+
+ return getStringField(nField, szNullValue);
+
+}
+
+
+
+
+
+const unsigned char* CppSQLite3Query::getBlobField(int nField, int& nLen)
+
+{
+
+ checkVM();
+
+
+
+ if (nField < 0 || nField > mnCols-1)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Invalid field index requested",
+
+ DONT_DELETE_MSG);
+
+ }
+
+
+
+ nLen = sqlite3_column_bytes(mpVM, nField);
+
+ return (const unsigned char*)sqlite3_column_blob(mpVM, nField);
+
+}
+
+
+
+
+
+const unsigned char* CppSQLite3Query::getBlobField(const char* szField, int& nLen)
+
+{
+
+ int nField = fieldIndex(szField);
+
+ return getBlobField(nField, nLen);
+
+}
+
+
+
+
+
+bool CppSQLite3Query::fieldIsNull(int nField)
+
+{
+
+ return (fieldDataType(nField) == SQLITE_NULL);
+
+}
+
+
+
+
+
+bool CppSQLite3Query::fieldIsNull(const char* szField)
+
+{
+
+ int nField = fieldIndex(szField);
+
+ return (fieldDataType(nField) == SQLITE_NULL);
+
+}
+
+
+
+
+
+int CppSQLite3Query::fieldIndex(const char* szField)
+
+{
+
+ checkVM();
+
+
+
+ if (szField)
+
+ {
+
+ for (int nField = 0; nField < mnCols; nField++)
+
+ {
+
+ const char* szTemp = sqlite3_column_name(mpVM, nField);
+
+
+
+ if (strcmp(szField, szTemp) == 0)
+
+ {
+
+ return nField;
+
+ }
+
+ }
+
+ }
+
+
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Invalid field name requested",
+
+ DONT_DELETE_MSG);
+
+}
+
+
+
+
+
+const char* CppSQLite3Query::fieldName(int nCol)
+
+{
+
+ checkVM();
+
+
+
+ if (nCol < 0 || nCol > mnCols-1)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Invalid field index requested",
+
+ DONT_DELETE_MSG);
+
+ }
+
+
+
+ return sqlite3_column_name(mpVM, nCol);
+
+}
+
+
+
+
+
+const char* CppSQLite3Query::fieldDeclType(int nCol)
+
+{
+
+ checkVM();
+
+
+
+ if (nCol < 0 || nCol > mnCols-1)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Invalid field index requested",
+
+ DONT_DELETE_MSG);
+
+ }
+
+
+
+ return sqlite3_column_decltype(mpVM, nCol);
+
+}
+
+
+
+
+
+int CppSQLite3Query::fieldDataType(int nCol)
+
+{
+
+ checkVM();
+
+
+
+ if (nCol < 0 || nCol > mnCols-1)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Invalid field index requested",
+
+ DONT_DELETE_MSG);
+
+ }
+
+
+
+ return sqlite3_column_type(mpVM, nCol);
+
+}
+
+
+
+
+
+bool CppSQLite3Query::eof()
+
+{
+
+ checkVM();
+
+ return mbEof;
+
+}
+
+
+
+
+
+void CppSQLite3Query::nextRow()
+
+{
+
+ checkVM();
+
+
+
+ int nRet = sqlite3_step(mpVM);
+
+
+
+ if (nRet == SQLITE_DONE)
+
+ {
+
+ // no rows
+
+ mbEof = true;
+
+ }
+
+ else if (nRet == SQLITE_ROW)
+
+ {
+
+ // more rows, nothing to do
+
+ }
+
+ else
+
+ {
+
+ nRet = sqlite3_finalize(mpVM);
+
+ mpVM = 0;
+
+ const char* szError = sqlite3_errmsg(mpDB);
+
+ throw CppSQLite3Exception(nRet,
+
+ (char*)szError,
+
+ DONT_DELETE_MSG);
+
+ }
+
+}
+
+
+
+
+
+void CppSQLite3Query::finalize()
+
+{
+
+ if (mpVM && mbOwnVM)
+
+ {
+
+ int nRet = sqlite3_finalize(mpVM);
+
+ mpVM = 0;
+
+ if (nRet != SQLITE_OK)
+
+ {
+
+ const char* szError = sqlite3_errmsg(mpDB);
+
+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+ }
+
+ }
+
+}
+
+
+
+
+
+void CppSQLite3Query::checkVM()
+
+{
+
+ if (mpVM == 0)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Null Virtual Machine pointer",
+
+ DONT_DELETE_MSG);
+
+ }
+
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+CppSQLite3Table::CppSQLite3Table()
+
+{
+
+ mpaszResults = 0;
+
+ mnRows = 0;
+
+ mnCols = 0;
+
+ mnCurrentRow = 0;
+
+}
+
+
+
+
+
+CppSQLite3Table::CppSQLite3Table(const CppSQLite3Table& rTable)
+
+{
+
+ mpaszResults = rTable.mpaszResults;
+
+ // Only one object can own the results
+
+ const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;
+
+ mnRows = rTable.mnRows;
+
+ mnCols = rTable.mnCols;
+
+ mnCurrentRow = rTable.mnCurrentRow;
+
+}
+
+
+
+
+
+CppSQLite3Table::CppSQLite3Table(char** paszResults, int nRows, int nCols)
+
+{
+
+ mpaszResults = paszResults;
+
+ mnRows = nRows;
+
+ mnCols = nCols;
+
+ mnCurrentRow = 0;
+
+}
+
+
+
+
+
+CppSQLite3Table::~CppSQLite3Table()
+
+{
+
+ try
+
+ {
+
+ finalize();
+
+ }
+
+ catch (...)
+
+ {
+
+ }
+
+}
+
+
+
+
+
+CppSQLite3Table& CppSQLite3Table::operator=(const CppSQLite3Table& rTable)
+
+{
+
+ try
+
+ {
+
+ finalize();
+
+ }
+
+ catch (...)
+
+ {
+
+ }
+
+ mpaszResults = rTable.mpaszResults;
+
+ // Only one object can own the results
+
+ const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;
+
+ mnRows = rTable.mnRows;
+
+ mnCols = rTable.mnCols;
+
+ mnCurrentRow = rTable.mnCurrentRow;
+
+ return *this;
+
+}
+
+
+
+
+
+void CppSQLite3Table::finalize()
+
+{
+
+ if (mpaszResults)
+
+ {
+
+ sqlite3_free_table(mpaszResults);
+
+ mpaszResults = 0;
+
+ }
+
+}
+
+
+
+
+
+int CppSQLite3Table::numFields()
+
+{
+
+ checkResults();
+
+ return mnCols;
+
+}
+
+
+
+
+
+int CppSQLite3Table::numRows()
+
+{
+
+ checkResults();
+
+ return mnRows;
+
+}
+
+
+
+
+
+const char* CppSQLite3Table::fieldValue(int nField)
+
+{
+
+ checkResults();
+
+
+
+ if (nField < 0 || nField > mnCols-1)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Invalid field index requested",
+
+ DONT_DELETE_MSG);
+
+ }
+
+
+
+ int nIndex = (mnCurrentRow*mnCols) + mnCols + nField;
+
+ return mpaszResults[nIndex];
+
+}
+
+
+
+
+
+const char* CppSQLite3Table::fieldValue(const char* szField)
+
+{
+
+ checkResults();
+
+
+
+ if (szField)
+
+ {
+
+ for (int nField = 0; nField < mnCols; nField++)
+
+ {
+
+ if (strcmp(szField, mpaszResults[nField]) == 0)
+
+ {
+
+ int nIndex = (mnCurrentRow*mnCols) + mnCols + nField;
+
+ return mpaszResults[nIndex];
+
+ }
+
+ }
+
+ }
+
+
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Invalid field name requested",
+
+ DONT_DELETE_MSG);
+
+}
+
+
+
+
+
+int CppSQLite3Table::getIntField(int nField, int nNullValue/*=0*/)
+
+{
+
+ if (fieldIsNull(nField))
+
+ {
+
+ return nNullValue;
+
+ }
+
+ else
+
+ {
+
+ return atoi(fieldValue(nField));
+
+ }
+
+}
+
+
+
+
+
+int CppSQLite3Table::getIntField(const char* szField, int nNullValue/*=0*/)
+
+{
+
+ if (fieldIsNull(szField))
+
+ {
+
+ return nNullValue;
+
+ }
+
+ else
+
+ {
+
+ return atoi(fieldValue(szField));
+
+ }
+
+}
+
+
+
+
+
+double CppSQLite3Table::getFloatField(int nField, double fNullValue/*=0.0*/)
+
+{
+
+ if (fieldIsNull(nField))
+
+ {
+
+ return fNullValue;
+
+ }
+
+ else
+
+ {
+
+ return atof(fieldValue(nField));
+
+ }
+
+}
+
+
+
+
+
+double CppSQLite3Table::getFloatField(const char* szField, double fNullValue/*=0.0*/)
+
+{
+
+ if (fieldIsNull(szField))
+
+ {
+
+ return fNullValue;
+
+ }
+
+ else
+
+ {
+
+ return atof(fieldValue(szField));
+
+ }
+
+}
+
+
+
+
+
+const char* CppSQLite3Table::getStringField(int nField, const char* szNullValue/*=""*/)
+
+{
+
+ if (fieldIsNull(nField))
+
+ {
+
+ return szNullValue;
+
+ }
+
+ else
+
+ {
+
+ return fieldValue(nField);
+
+ }
+
+}
+
+
+
+
+
+const char* CppSQLite3Table::getStringField(const char* szField, const char* szNullValue/*=""*/)
+
+{
+
+ if (fieldIsNull(szField))
+
+ {
+
+ return szNullValue;
+
+ }
+
+ else
+
+ {
+
+ return fieldValue(szField);
+
+ }
+
+}
+
+
+
+
+
+bool CppSQLite3Table::fieldIsNull(int nField)
+
+{
+
+ checkResults();
+
+ return (fieldValue(nField) == 0);
+
+}
+
+
+
+
+
+bool CppSQLite3Table::fieldIsNull(const char* szField)
+
+{
+
+ checkResults();
+
+ return (fieldValue(szField) == 0);
+
+}
+
+
+
+
+
+const char* CppSQLite3Table::fieldName(int nCol)
+
+{
+
+ checkResults();
+
+
+
+ if (nCol < 0 || nCol > mnCols-1)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Invalid field index requested",
+
+ DONT_DELETE_MSG);
+
+ }
+
+
+
+ return mpaszResults[nCol];
+
+}
+
+
+
+
+
+void CppSQLite3Table::setRow(int nRow)
+
+{
+
+ checkResults();
+
+
+
+ if (nRow < 0 || nRow > mnRows-1)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Invalid row index requested",
+
+ DONT_DELETE_MSG);
+
+ }
+
+
+
+ mnCurrentRow = nRow;
+
+}
+
+
+
+
+
+void CppSQLite3Table::checkResults()
+
+{
+
+ if (mpaszResults == 0)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Null Results pointer",
+
+ DONT_DELETE_MSG);
+
+ }
+
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+CppSQLite3Statement::CppSQLite3Statement()
+
+{
+
+ mpDB = 0;
+
+ mpVM = 0;
+
+}
+
+
+
+
+
+CppSQLite3Statement::CppSQLite3Statement(const CppSQLite3Statement& rStatement)
+
+{
+
+ mpDB = rStatement.mpDB;
+
+ mpVM = rStatement.mpVM;
+
+ // Only one object can own VM
+
+ const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0;
+
+}
+
+
+
+
+
+CppSQLite3Statement::CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM)
+
+{
+
+ mpDB = pDB;
+
+ mpVM = pVM;
+
+}
+
+
+
+
+
+CppSQLite3Statement::~CppSQLite3Statement()
+
+{
+
+ try
+
+ {
+
+ finalize();
+
+ }
+
+ catch (...)
+
+ {
+
+ }
+
+}
+
+
+
+
+
+CppSQLite3Statement& CppSQLite3Statement::operator=(const CppSQLite3Statement& rStatement)
+
+{
+
+ mpDB = rStatement.mpDB;
+
+ mpVM = rStatement.mpVM;
+
+ // Only one object can own VM
+
+ const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0;
+
+ return *this;
+
+}
+
+
+
+
+
+int CppSQLite3Statement::execDML()
+
+{
+
+ checkDB();
+
+ checkVM();
+
+
+
+ const char* szError=0;
+
+
+
+ int nRet = sqlite3_step(mpVM);
+
+
+
+ if (nRet == SQLITE_DONE)
+
+ {
+
+ int nRowsChanged = sqlite3_changes(mpDB);
+
+
+
+ nRet = sqlite3_reset(mpVM);
+
+
+
+ if (nRet != SQLITE_OK)
+
+ {
+
+ szError = sqlite3_errmsg(mpDB);
+
+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+ }
+
+
+
+ return nRowsChanged;
+
+ }
+
+ else
+
+ {
+
+ nRet = sqlite3_reset(mpVM);
+
+ szError = sqlite3_errmsg(mpDB);
+
+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+ }
+
+}
+
+
+
+
+
+CppSQLite3Query CppSQLite3Statement::execQuery()
+
+{
+
+ checkDB();
+
+ checkVM();
+
+
+
+ int nRet = sqlite3_step(mpVM);
+
+
+
+ if (nRet == SQLITE_DONE)
+
+ {
+
+ // no rows
+
+ return CppSQLite3Query(mpDB, mpVM, true/*eof*/, false);
+
+ }
+
+ else if (nRet == SQLITE_ROW)
+
+ {
+
+ // at least 1 row
+
+ return CppSQLite3Query(mpDB, mpVM, false/*eof*/, false);
+
+ }
+
+ else
+
+ {
+
+ nRet = sqlite3_reset(mpVM);
+
+ const char* szError = sqlite3_errmsg(mpDB);
+
+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+ }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::bind(int nParam, const char* szValue)
+
+{
+
+ checkVM();
+
+ int nRes = sqlite3_bind_text(mpVM, nParam, szValue, -1, SQLITE_TRANSIENT);
+
+
+
+ if (nRes != SQLITE_OK)
+
+ {
+
+ throw CppSQLite3Exception(nRes,
+
+ "Error binding string param",
+
+ DONT_DELETE_MSG);
+
+ }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::bind(int nParam, const int nValue)
+
+{
+
+ checkVM();
+
+ int nRes = sqlite3_bind_int(mpVM, nParam, nValue);
+
+
+
+ if (nRes != SQLITE_OK)
+
+ {
+
+ throw CppSQLite3Exception(nRes,
+
+ "Error binding int param",
+
+ DONT_DELETE_MSG);
+
+ }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::bind(int nParam, const double dValue)
+
+{
+
+ checkVM();
+
+ int nRes = sqlite3_bind_double(mpVM, nParam, dValue);
+
+
+
+ if (nRes != SQLITE_OK)
+
+ {
+
+ throw CppSQLite3Exception(nRes,
+
+ "Error binding double param",
+
+ DONT_DELETE_MSG);
+
+ }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::bind(int nParam, const unsigned char* blobValue, int nLen)
+
+{
+
+ checkVM();
+
+ int nRes = sqlite3_bind_blob(mpVM, nParam,
+
+ (const void*)blobValue, nLen, SQLITE_TRANSIENT);
+
+
+
+ if (nRes != SQLITE_OK)
+
+ {
+
+ throw CppSQLite3Exception(nRes,
+
+ "Error binding blob param",
+
+ DONT_DELETE_MSG);
+
+ }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::bindNull(int nParam)
+
+{
+
+ checkVM();
+
+ int nRes = sqlite3_bind_null(mpVM, nParam);
+
+
+
+ if (nRes != SQLITE_OK)
+
+ {
+
+ throw CppSQLite3Exception(nRes,
+
+ "Error binding NULL param",
+
+ DONT_DELETE_MSG);
+
+ }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::reset()
+
+{
+
+ if (mpVM)
+
+ {
+
+ int nRet = sqlite3_reset(mpVM);
+
+
+
+ if (nRet != SQLITE_OK)
+
+ {
+
+ const char* szError = sqlite3_errmsg(mpDB);
+
+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+ }
+
+ }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::finalize()
+
+{
+
+ if (mpVM)
+
+ {
+
+ int nRet = sqlite3_finalize(mpVM);
+
+ mpVM = 0;
+
+
+
+ if (nRet != SQLITE_OK)
+
+ {
+
+ const char* szError = sqlite3_errmsg(mpDB);
+
+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+ }
+
+ }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::checkDB()
+
+{
+
+ if (mpDB == 0)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Database not open",
+
+ DONT_DELETE_MSG);
+
+ }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::checkVM()
+
+{
+
+ if (mpVM == 0)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Null Virtual Machine pointer",
+
+ DONT_DELETE_MSG);
+
+ }
+
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+CppSQLite3DB::CppSQLite3DB()
+
+{
+
+ mpDB = 0;
+
+ mnBusyTimeoutMs = 60000; // 60 seconds
+
+}
+
+
+
+
+
+CppSQLite3DB::CppSQLite3DB(const CppSQLite3DB& db)
+
+{
+
+ mpDB = db.mpDB;
+
+ mnBusyTimeoutMs = 60000; // 60 seconds
+
+}
+
+
+
+
+
+CppSQLite3DB::~CppSQLite3DB()
+
+{
+
+ close();
+
+}
+
+
+
+
+
+CppSQLite3DB& CppSQLite3DB::operator=(const CppSQLite3DB& db)
+
+{
+
+ mpDB = db.mpDB;
+
+ mnBusyTimeoutMs = 60000; // 60 seconds
+
+ return *this;
+
+}
+
+
+
+
+
+void CppSQLite3DB::open(const char* szFile)
+
+{
+
+ int nRet = sqlite3_open(szFile, &mpDB);
+
+
+
+ if (nRet != SQLITE_OK)
+
+ {
+
+ const char* szError = sqlite3_errmsg(mpDB);
+
+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+ }
+
+
+
+ setBusyTimeout(mnBusyTimeoutMs);
+
+}
+
+
+
+
+
+void CppSQLite3DB::close()
+
+{
+
+ if (mpDB)
+
+ {
+
+ sqlite3_close(mpDB);
+
+ mpDB = 0;
+
+ }
+
+}
+
+
+
+
+
+CppSQLite3Statement CppSQLite3DB::compileStatement(const char* szSQL)
+
+{
+
+ checkDB();
+
+
+
+ sqlite3_stmt* pVM = compile(szSQL);
+
+ return CppSQLite3Statement(mpDB, pVM);
+
+}
+
+
+
+
+
+bool CppSQLite3DB::tableExists(const char* szTable)
+
+{
+
+ char szSQL[128];
+
+ sprintf(szSQL,
+
+ "select count(*) from sqlite_master where type='table' and name='%s'",
+
+ szTable);
+
+ int nRet = execScalar(szSQL);
+
+ return (nRet > 0);
+
+}
+
+
+
+
+
+int CppSQLite3DB::execDML(const char* szSQL)
+
+{
+
+ checkDB();
+
+
+
+ char* szError=0;
+
+
+
+ int nRet = sqlite3_exec(mpDB, szSQL, 0, 0, &szError);
+
+
+
+ if (nRet == SQLITE_OK)
+
+ {
+
+ return sqlite3_changes(mpDB);
+
+ }
+
+ else
+
+ {
+
+ throw CppSQLite3Exception(nRet, szError);
+
+ }
+
+}
+
+
+
+
+
+CppSQLite3Query CppSQLite3DB::execQuery(const char* szSQL)
+
+{
+
+ checkDB();
+
+
+
+ sqlite3_stmt* pVM = compile(szSQL);
+
+
+
+ int nRet = sqlite3_step(pVM);
+
+
+
+ if (nRet == SQLITE_DONE)
+
+ {
+
+ // no rows
+
+ return CppSQLite3Query(mpDB, pVM, true/*eof*/);
+
+ }
+
+ else if (nRet == SQLITE_ROW)
+
+ {
+
+ // at least 1 row
+
+ return CppSQLite3Query(mpDB, pVM, false/*eof*/);
+
+ }
+
+ else
+
+ {
+
+ nRet = sqlite3_finalize(pVM);
+
+ const char* szError= sqlite3_errmsg(mpDB);
+
+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+ }
+
+}
+
+
+
+
+
+int CppSQLite3DB::execScalar(const char* szSQL)
+
+{
+
+ CppSQLite3Query q = execQuery(szSQL);
+
+
+
+ if (q.eof() || q.numFields() < 1)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Invalid scalar query",
+
+ DONT_DELETE_MSG);
+
+ }
+
+
+
+ return atoi(q.fieldValue(0));
+
+}
+
+
+
+
+
+CppSQLite3Table CppSQLite3DB::getTable(const char* szSQL)
+
+{
+
+ checkDB();
+
+
+
+ char* szError=0;
+
+ char** paszResults=0;
+
+ int nRet;
+
+ int nRows(0);
+
+ int nCols(0);
+
+
+
+ nRet = sqlite3_get_table(mpDB, szSQL, &paszResults, &nRows, &nCols, &szError);
+
+
+
+ if (nRet == SQLITE_OK)
+
+ {
+
+ return CppSQLite3Table(paszResults, nRows, nCols);
+
+ }
+
+ else
+
+ {
+
+ throw CppSQLite3Exception(nRet, szError);
+
+ }
+
+}
+
+
+
+
+
+sqlite_int64 CppSQLite3DB::lastRowId()
+
+{
+
+ return sqlite3_last_insert_rowid(mpDB);
+
+}
+
+
+
+
+
+void CppSQLite3DB::setBusyTimeout(int nMillisecs)
+
+{
+
+ mnBusyTimeoutMs = nMillisecs;
+
+ sqlite3_busy_timeout(mpDB, mnBusyTimeoutMs);
+
+}
+
+
+
+
+
+void CppSQLite3DB::checkDB()
+
+{
+
+ if (!mpDB)
+
+ {
+
+ throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+ "Database not open",
+
+ DONT_DELETE_MSG);
+
+ }
+
+}
+
+
+
+
+
+sqlite3_stmt* CppSQLite3DB::compile(const char* szSQL)
+
+{
+
+ checkDB();
+
+
+
+ char* szError=0;
+
+ const char* szTail=0;
+
+ sqlite3_stmt* pVM;
+
+
+
+ int nRet = sqlite3_prepare(mpDB, szSQL, -1, &pVM, &szTail);
+
+
+
+ if (nRet != SQLITE_OK)
+
+ {
+
+ throw CppSQLite3Exception(nRet, szError);
+
+ }
+
+
+
+ return pVM;
+
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+// SQLite encode.c reproduced here, containing implementation notes and source
+
+// for sqlite3_encode_binary() and sqlite3_decode_binary()
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+/*
+
+** 2002 April 25
+
+**
+
+** The author disclaims copyright to this source code. In place of
+
+** a legal notice, here is a blessing:
+
+**
+
+** May you do good and not evil.
+
+** May you find forgiveness for yourself and forgive others.
+
+** May you share freely, never taking more than you give.
+
+**
+
+*************************************************************************
+
+** This file contains helper routines used to translate binary data into
+
+** a null-terminated string (suitable for use in SQLite) and back again.
+
+** These are convenience routines for use by people who want to store binary
+
+** data in an SQLite database. The code in this file is not used by any other
+
+** part of the SQLite library.
+
+**
+
+** $Id: CppSQLite3.cpp,v 1.2 2009/08/27 11:47:02 cervenansky Exp $
+
+*/
+
+
+
+/*
+
+** How This Encoder Works
+
+**
+
+** The output is allowed to contain any character except 0x27 (') and
+
+** 0x00. This is accomplished by using an escape character to encode
+
+** 0x27 and 0x00 as a two-byte sequence. The escape character is always
+
+** 0x01. An 0x00 is encoded as the two byte sequence 0x01 0x01. The
+
+** 0x27 character is encoded as the two byte sequence 0x01 0x03. Finally,
+
+** the escape character itself is encoded as the two-character sequence
+
+** 0x01 0x02.
+
+**
+
+** To summarize, the encoder works by using an escape sequences as follows:
+
+**
+
+** 0x00 -> 0x01 0x01
+
+** 0x01 -> 0x01 0x02
+
+** 0x27 -> 0x01 0x03
+
+**
+
+** If that were all the encoder did, it would work, but in certain cases
+
+** it could double the size of the encoded string. For example, to
+
+** encode a string of 100 0x27 characters would require 100 instances of
+
+** the 0x01 0x03 escape sequence resulting in a 200-character output.
+
+** We would prefer to keep the size of the encoded string smaller than
+
+** this.
+
+**
+
+** To minimize the encoding size, we first add a fixed offset value to each
+
+** byte in the sequence. The addition is modulo 256. (That is to say, if
+
+** the sum of the original character value and the offset exceeds 256, then
+
+** the higher order bits are truncated.) The offset is chosen to minimize
+
+** the number of characters in the string that need to be escaped. For
+
+** example, in the case above where the string was composed of 100 0x27
+
+** characters, the offset might be 0x01. Each of the 0x27 characters would
+
+** then be converted into an 0x28 character which would not need to be
+
+** escaped at all and so the 100 character input string would be converted
+
+** into just 100 characters of output. Actually 101 characters of output -
+
+** we have to record the offset used as the first byte in the sequence so
+
+** that the string can be decoded. Since the offset value is stored as
+
+** part of the output string and the output string is not allowed to contain
+
+** characters 0x00 or 0x27, the offset cannot be 0x00 or 0x27.
+
+**
+
+** Here, then, are the encoding steps:
+
+**
+
+** (1) Choose an offset value and make it the first character of
+
+** output.
+
+**
+
+** (2) Copy each input character into the output buffer, one by
+
+** one, adding the offset value as you copy.
+
+**
+
+** (3) If the value of an input character plus offset is 0x00, replace
+
+** that one character by the two-character sequence 0x01 0x01.
+
+** If the sum is 0x01, replace it with 0x01 0x02. If the sum
+
+** is 0x27, replace it with 0x01 0x03.
+
+**
+
+** (4) Put a 0x00 terminator at the end of the output.
+
+**
+
+** Decoding is obvious:
+
+**
+
+** (5) Copy encoded characters except the first into the decode
+
+** buffer. Set the first encoded character aside for use as
+
+** the offset in step 7 below.
+
+**
+
+** (6) Convert each 0x01 0x01 sequence into a single character 0x00.
+
+** Convert 0x01 0x02 into 0x01. Convert 0x01 0x03 into 0x27.
+
+**
+
+** (7) Subtract the offset value that was the first character of
+
+** the encoded buffer from all characters in the output buffer.
+
+**
+
+** The only tricky part is step (1) - how to compute an offset value to
+
+** minimize the size of the output buffer. This is accomplished by testing
+
+** all offset values and picking the one that results in the fewest number
+
+** of escapes. To do that, we first scan the entire input and count the
+
+** number of occurances of each character value in the input. Suppose
+
+** the number of 0x00 characters is N(0), the number of occurances of 0x01
+
+** is N(1), and so forth up to the number of occurances of 0xff is N(255).
+
+** An offset of 0 is not allowed so we don't have to test it. The number
+
+** of escapes required for an offset of 1 is N(1)+N(2)+N(40). The number
+
+** of escapes required for an offset of 2 is N(2)+N(3)+N(41). And so forth.
+
+** In this way we find the offset that gives the minimum number of escapes,
+
+** and thus minimizes the length of the output string.
+
+*/
+
+
+
+/*
+
+** Encode a binary buffer "in" of size n bytes so that it contains
+
+** no instances of characters '\'' or '\000'. The output is
+
+** null-terminated and can be used as a string value in an INSERT
+
+** or UPDATE statement. Use sqlite3_decode_binary() to convert the
+
+** string back into its original binary.
+
+**
+
+** The result is written into a preallocated output buffer "out".
+
+** "out" must be able to hold at least 2 +(257*n)/254 bytes.
+
+** In other words, the output will be expanded by as much as 3
+
+** bytes for every 254 bytes of input plus 2 bytes of fixed overhead.
+
+** (This is approximately 2 + 1.0118*n or about a 1.2% size increase.)
+
+**
+
+** The return value is the number of characters in the encoded
+
+** string, excluding the "\000" terminator.
+
+*/
+
+int sqlite3_encode_binary(const unsigned char *in, int n, unsigned char *out){
+
+ int i, j, e, m;
+
+ int cnt[256];
+
+ if( n<=0 ){
+
+ out[0] = 'x';
+
+ out[1] = 0;
+
+ return 1;
+
+ }
+
+ memset(cnt, 0, sizeof(cnt));
+
+ for(i=n-1; i>=0; i--){ cnt[in[i]]++; }
+
+ m = n;
+
+ for(i=1; i<256; i++){
+
+ int sum;
+
+ if( i=='\'' ) continue;
+
+ sum = cnt[i] + cnt[(i+1)&0xff] + cnt[(i+'\'')&0xff];
+
+ if( sum<m ){
+
+ m = sum;
+
+ e = i;
+
+ if( m==0 ) break;
+
+ }
+
+ }
+
+ out[0] = e;
+
+ j = 1;
+
+ for(i=0; i<n; i++){
+
+ int c = (in[i] - e)&0xff;
+
+ if( c==0 ){
+
+ out[j++] = 1;
+
+ out[j++] = 1;
+
+ }else if( c==1 ){
+
+ out[j++] = 1;
+
+ out[j++] = 2;
+
+ }else if( c=='\'' ){
+
+ out[j++] = 1;
+
+ out[j++] = 3;
+
+ }else{
+
+ out[j++] = c;
+
+ }
+
+ }
+
+ out[j] = 0;
+
+ return j;
+
+}
+
+
+
+/*
+
+** Decode the string "in" into binary data and write it into "out".
+
+** This routine reverses the encoding created by sqlite3_encode_binary().
+
+** The output will always be a few bytes less than the input. The number
+
+** of bytes of output is returned. If the input is not a well-formed
+
+** encoding, -1 is returned.
+
+**
+
+** The "in" and "out" parameters may point to the same buffer in order
+
+** to decode a string in place.
+
+*/
+
+int sqlite3_decode_binary(const unsigned char *in, unsigned char *out){
+
+ int i, c, e;
+
+ e = *(in++);
+
+ i = 0;
+
+ while( (c = *(in++))!=0 ){
+
+ if( c==1 ){
+
+ c = *(in++);
+
+ if( c==1 ){
+
+ c = 0;
+
+ }else if( c==2 ){
+
+ c = 1;
+
+ }else if( c==3 ){
+
+ c = '\'';
+
+ }else{
+
+ return -1;
+
+ }
+
+ }
+
+ out[i++] = (c + e)&0xff;
+
+ }
+
+ return i;
+
+}
+
-////////////////////////////////////////////////////////////////////////////////\r
-// CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library.\r
-//\r
-// Copyright (c) 2004 Rob Groves. All Rights Reserved. rob.groves@btinternet.com\r
-// \r
-// Permission to use, copy, modify, and distribute this software and its\r
-// documentation for any purpose, without fee, and without a written\r
-// agreement, is hereby granted, provided that the above copyright notice, \r
-// this paragraph and the following two paragraphs appear in all copies, \r
-// modifications, and distributions.\r
-//\r
-// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,\r
-// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST\r
-// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,\r
-// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
-//\r
-// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT\r
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\r
-// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF\r
-// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION\r
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.\r
-//\r
-// V3.0 03/08/2004 -Initial Version for sqlite3\r
-//\r
-// V3.1 16/09/2004 -Implemented getXXXXField using sqlite3 functions\r
-// -Added CppSQLiteDB3::tableExists()\r
-////////////////////////////////////////////////////////////////////////////////\r
-#ifndef _CppSQLite3_H_\r
-#define _CppSQLite3_H_\r
-\r
-#include "sqlite3.h"\r
-#include <cstdio>\r
-#include <cstring>\r
-\r
-#define CPPSQLITE_ERROR 1000\r
-\r
-class CppSQLite3Exception\r
-{\r
-public:\r
-\r
- CppSQLite3Exception(const int nErrCode,\r
- char* szErrMess,\r
- bool bDeleteMsg=true);\r
- CppSQLite3Exception(const int nErrCode,\r
- const char* szErrMess,\r
- bool bDeleteMsg=true);\r
- \r
- CppSQLite3Exception(const CppSQLite3Exception& e);\r
-\r
- virtual ~CppSQLite3Exception();\r
-\r
- const int errorCode() { return mnErrCode; }\r
-\r
- const char* errorMessage() { return mpszErrMess; }\r
-\r
- static const char* errorCodeAsString(int nErrCode);\r
-\r
-private:\r
-\r
- int mnErrCode;\r
- char* mpszErrMess;\r
-};\r
-\r
-\r
-class CppSQLite3Buffer\r
-{\r
-public:\r
-\r
- CppSQLite3Buffer();\r
-\r
- ~CppSQLite3Buffer();\r
-\r
- const char* format(const char* szFormat, ...);\r
-\r
- operator const char*() { return mpBuf; }\r
-\r
- void clear();\r
-\r
-private:\r
-\r
- char* mpBuf;\r
-};\r
-\r
-\r
-class CppSQLite3Binary\r
-{\r
-public:\r
-\r
- CppSQLite3Binary();\r
-\r
- ~CppSQLite3Binary();\r
-\r
- void setBinary(const unsigned char* pBuf, int nLen);\r
- void setEncoded(const unsigned char* pBuf);\r
-\r
- const unsigned char* getEncoded();\r
- const unsigned char* getBinary();\r
-\r
- int getBinaryLength();\r
-\r
- unsigned char* allocBuffer(int nLen);\r
-\r
- void clear();\r
-\r
-private:\r
-\r
- unsigned char* mpBuf;\r
- int mnBinaryLen;\r
- int mnBufferLen;\r
- int mnEncodedLen;\r
- bool mbEncoded;\r
-};\r
-\r
-\r
-class CppSQLite3Query\r
-{\r
-public:\r
-\r
- CppSQLite3Query();\r
-\r
- CppSQLite3Query(const CppSQLite3Query& rQuery);\r
-\r
- CppSQLite3Query(sqlite3* pDB,\r
- sqlite3_stmt* pVM,\r
- bool bEof,\r
- bool bOwnVM=true);\r
-\r
- CppSQLite3Query& operator=(const CppSQLite3Query& rQuery);\r
-\r
- virtual ~CppSQLite3Query();\r
-\r
- int numFields();\r
-\r
- int fieldIndex(const char* szField);\r
- const char* fieldName(int nCol);\r
-\r
- const char* fieldDeclType(int nCol);\r
- int fieldDataType(int nCol);\r
-\r
- const char* fieldValue(int nField);\r
- const char* fieldValue(const char* szField);\r
-\r
- int getIntField(int nField, int nNullValue=0);\r
- int getIntField(const char* szField, int nNullValue=0);\r
-\r
- double getFloatField(int nField, double fNullValue=0.0);\r
- double getFloatField(const char* szField, double fNullValue=0.0);\r
-\r
- const char* getStringField(int nField, const char* szNullValue="");\r
- const char* getStringField(const char* szField, const char* szNullValue="");\r
-\r
- const unsigned char* getBlobField(int nField, int& nLen);\r
- const unsigned char* getBlobField(const char* szField, int& nLen);\r
-\r
- bool fieldIsNull(int nField);\r
- bool fieldIsNull(const char* szField);\r
-\r
- bool eof();\r
-\r
- void nextRow();\r
-\r
- void finalize();\r
-\r
-private:\r
-\r
- void checkVM();\r
-\r
- sqlite3* mpDB;\r
- sqlite3_stmt* mpVM;\r
- bool mbEof;\r
- int mnCols;\r
- bool mbOwnVM;\r
-};\r
-\r
-\r
-class CppSQLite3Table\r
-{\r
-public:\r
-\r
- CppSQLite3Table();\r
-\r
- CppSQLite3Table(const CppSQLite3Table& rTable);\r
-\r
- CppSQLite3Table(char** paszResults, int nRows, int nCols);\r
-\r
- virtual ~CppSQLite3Table();\r
-\r
- CppSQLite3Table& operator=(const CppSQLite3Table& rTable);\r
-\r
- int numFields();\r
-\r
- int numRows();\r
-\r
- const char* fieldName(int nCol);\r
-\r
- const char* fieldValue(int nField);\r
- const char* fieldValue(const char* szField);\r
-\r
- int getIntField(int nField, int nNullValue=0);\r
- int getIntField(const char* szField, int nNullValue=0);\r
-\r
- double getFloatField(int nField, double fNullValue=0.0);\r
- double getFloatField(const char* szField, double fNullValue=0.0);\r
-\r
- const char* getStringField(int nField, const char* szNullValue="");\r
- const char* getStringField(const char* szField, const char* szNullValue="");\r
-\r
- bool fieldIsNull(int nField);\r
- bool fieldIsNull(const char* szField);\r
-\r
- void setRow(int nRow);\r
-\r
- void finalize();\r
-\r
-private:\r
-\r
- void checkResults();\r
-\r
- int mnCols;\r
- int mnRows;\r
- int mnCurrentRow;\r
- char** mpaszResults;\r
-};\r
-\r
-\r
-class CppSQLite3Statement\r
-{\r
-public:\r
-\r
- CppSQLite3Statement();\r
-\r
- CppSQLite3Statement(const CppSQLite3Statement& rStatement);\r
-\r
- CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM);\r
-\r
- virtual ~CppSQLite3Statement();\r
-\r
- CppSQLite3Statement& operator=(const CppSQLite3Statement& rStatement);\r
-\r
- int execDML();\r
-\r
- CppSQLite3Query execQuery();\r
-\r
- void bind(int nParam, const char* szValue);\r
- void bind(int nParam, const int nValue);\r
- void bind(int nParam, const double dwValue);\r
- void bind(int nParam, const unsigned char* blobValue, int nLen);\r
- void bindNull(int nParam);\r
-\r
- void reset();\r
-\r
- void finalize();\r
-\r
-private:\r
-\r
- void checkDB();\r
- void checkVM();\r
-\r
- sqlite3* mpDB;\r
- sqlite3_stmt* mpVM;\r
-};\r
-\r
-\r
-class CppSQLite3DB\r
-{\r
-public:\r
-\r
- CppSQLite3DB();\r
-\r
- virtual ~CppSQLite3DB();\r
-\r
- void open(const char* szFile);\r
-\r
- void close();\r
-\r
- bool tableExists(const char* szTable);\r
-\r
- int execDML(const char* szSQL);\r
-\r
- CppSQLite3Query execQuery(const char* szSQL);\r
-\r
- int execScalar(const char* szSQL);\r
-\r
- CppSQLite3Table getTable(const char* szSQL);\r
-\r
- CppSQLite3Statement compileStatement(const char* szSQL);\r
-\r
- sqlite_int64 lastRowId();\r
-\r
- void interrupt() { sqlite3_interrupt(mpDB); }\r
-\r
- void setBusyTimeout(int nMillisecs);\r
-\r
- static const char* SQLiteVersion() { return SQLITE_VERSION; }\r
-\r
-private:\r
-\r
- CppSQLite3DB(const CppSQLite3DB& db);\r
- CppSQLite3DB& operator=(const CppSQLite3DB& db);\r
-\r
- sqlite3_stmt* compile(const char* szSQL);\r
-\r
- void checkDB();\r
-\r
- sqlite3* mpDB;\r
- int mnBusyTimeoutMs;\r
-};\r
-\r
-#endif\r
+////////////////////////////////////////////////////////////////////////////////
+
+// CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library.
+
+//
+
+// Copyright (c) 2004 Rob Groves. All Rights Reserved. rob.groves@btinternet.com
+
+//
+
+// Permission to use, copy, modify, and distribute this software and its
+
+// documentation for any purpose, without fee, and without a written
+
+// agreement, is hereby granted, provided that the above copyright notice,
+
+// this paragraph and the following two paragraphs appear in all copies,
+
+// modifications, and distributions.
+
+//
+
+// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
+
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
+
+// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
+
+// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+
+// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+
+// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
+
+// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION
+
+// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+//
+
+// V3.0 03/08/2004 -Initial Version for sqlite3
+
+//
+
+// V3.1 16/09/2004 -Implemented getXXXXField using sqlite3 functions
+
+// -Added CppSQLiteDB3::tableExists()
+
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _CppSQLite3_H_
+
+#define _CppSQLite3_H_
+
+
+
+#include "sqlite3.h"
+
+#include <cstdio>
+
+#include <cstring>
+
+
+
+#define CPPSQLITE_ERROR 1000
+
+
+
+class CppSQLite3Exception
+
+{
+
+public:
+
+
+
+ CppSQLite3Exception(const int nErrCode,
+
+ char* szErrMess,
+
+ bool bDeleteMsg=true);
+
+ CppSQLite3Exception(const int nErrCode,
+
+ const char* szErrMess,
+
+ bool bDeleteMsg=true);
+
+
+
+ CppSQLite3Exception(const CppSQLite3Exception& e);
+
+
+
+ virtual ~CppSQLite3Exception();
+
+
+
+ const int errorCode() { return mnErrCode; }
+
+
+
+ const char* errorMessage() { return mpszErrMess; }
+
+
+
+ static const char* errorCodeAsString(int nErrCode);
+
+
+
+private:
+
+
+
+ int mnErrCode;
+
+ char* mpszErrMess;
+
+};
+
+
+
+
+
+class CppSQLite3Buffer
+
+{
+
+public:
+
+
+
+ CppSQLite3Buffer();
+
+
+
+ ~CppSQLite3Buffer();
+
+
+
+ const char* format(const char* szFormat, ...);
+
+
+
+ operator const char*() { return mpBuf; }
+
+
+
+ void clear();
+
+
+
+private:
+
+
+
+ char* mpBuf;
+
+};
+
+
+
+
+
+class CppSQLite3Binary
+
+{
+
+public:
+
+
+
+ CppSQLite3Binary();
+
+
+
+ ~CppSQLite3Binary();
+
+
+
+ void setBinary(const unsigned char* pBuf, int nLen);
+
+ void setEncoded(const unsigned char* pBuf);
+
+
+
+ const unsigned char* getEncoded();
+
+ const unsigned char* getBinary();
+
+
+
+ int getBinaryLength();
+
+
+
+ unsigned char* allocBuffer(int nLen);
+
+
+
+ void clear();
+
+
+
+private:
+
+
+
+ unsigned char* mpBuf;
+
+ int mnBinaryLen;
+
+ int mnBufferLen;
+
+ int mnEncodedLen;
+
+ bool mbEncoded;
+
+};
+
+
+
+
+
+class CppSQLite3Query
+
+{
+
+public:
+
+
+
+ CppSQLite3Query();
+
+
+
+ CppSQLite3Query(const CppSQLite3Query& rQuery);
+
+
+
+ CppSQLite3Query(sqlite3* pDB,
+
+ sqlite3_stmt* pVM,
+
+ bool bEof,
+
+ bool bOwnVM=true);
+
+
+
+ CppSQLite3Query& operator=(const CppSQLite3Query& rQuery);
+
+
+
+ virtual ~CppSQLite3Query();
+
+
+
+ int numFields();
+
+
+
+ int fieldIndex(const char* szField);
+
+ const char* fieldName(int nCol);
+
+
+
+ const char* fieldDeclType(int nCol);
+
+ int fieldDataType(int nCol);
+
+
+
+ const char* fieldValue(int nField);
+
+ const char* fieldValue(const char* szField);
+
+
+
+ int getIntField(int nField, int nNullValue=0);
+
+ int getIntField(const char* szField, int nNullValue=0);
+
+
+
+ double getFloatField(int nField, double fNullValue=0.0);
+
+ double getFloatField(const char* szField, double fNullValue=0.0);
+
+
+
+ const char* getStringField(int nField, const char* szNullValue="");
+
+ const char* getStringField(const char* szField, const char* szNullValue="");
+
+
+
+ const unsigned char* getBlobField(int nField, int& nLen);
+
+ const unsigned char* getBlobField(const char* szField, int& nLen);
+
+
+
+ bool fieldIsNull(int nField);
+
+ bool fieldIsNull(const char* szField);
+
+
+
+ bool eof();
+
+
+
+ void nextRow();
+
+
+
+ void finalize();
+
+
+
+private:
+
+
+
+ void checkVM();
+
+
+
+ sqlite3* mpDB;
+
+ sqlite3_stmt* mpVM;
+
+ bool mbEof;
+
+ int mnCols;
+
+ bool mbOwnVM;
+
+};
+
+
+
+
+
+class CppSQLite3Table
+
+{
+
+public:
+
+
+
+ CppSQLite3Table();
+
+
+
+ CppSQLite3Table(const CppSQLite3Table& rTable);
+
+
+
+ CppSQLite3Table(char** paszResults, int nRows, int nCols);
+
+
+
+ virtual ~CppSQLite3Table();
+
+
+
+ CppSQLite3Table& operator=(const CppSQLite3Table& rTable);
+
+
+
+ int numFields();
+
+
+
+ int numRows();
+
+
+
+ const char* fieldName(int nCol);
+
+
+
+ const char* fieldValue(int nField);
+
+ const char* fieldValue(const char* szField);
+
+
+
+ int getIntField(int nField, int nNullValue=0);
+
+ int getIntField(const char* szField, int nNullValue=0);
+
+
+
+ double getFloatField(int nField, double fNullValue=0.0);
+
+ double getFloatField(const char* szField, double fNullValue=0.0);
+
+
+
+ const char* getStringField(int nField, const char* szNullValue="");
+
+ const char* getStringField(const char* szField, const char* szNullValue="");
+
+
+
+ bool fieldIsNull(int nField);
+
+ bool fieldIsNull(const char* szField);
+
+
+
+ void setRow(int nRow);
+
+
+
+ void finalize();
+
+
+
+private:
+
+
+
+ void checkResults();
+
+
+
+ int mnCols;
+
+ int mnRows;
+
+ int mnCurrentRow;
+
+ char** mpaszResults;
+
+};
+
+
+
+
+
+class CppSQLite3Statement
+
+{
+
+public:
+
+
+
+ CppSQLite3Statement();
+
+
+
+ CppSQLite3Statement(const CppSQLite3Statement& rStatement);
+
+
+
+ CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM);
+
+
+
+ virtual ~CppSQLite3Statement();
+
+
+
+ CppSQLite3Statement& operator=(const CppSQLite3Statement& rStatement);
+
+
+
+ int execDML();
+
+
+
+ CppSQLite3Query execQuery();
+
+
+
+ void bind(int nParam, const char* szValue);
+
+ void bind(int nParam, const int nValue);
+
+ void bind(int nParam, const double dwValue);
+
+ void bind(int nParam, const unsigned char* blobValue, int nLen);
+
+ void bindNull(int nParam);
+
+
+
+ void reset();
+
+
+
+ void finalize();
+
+
+
+private:
+
+
+
+ void checkDB();
+
+ void checkVM();
+
+
+
+ sqlite3* mpDB;
+
+ sqlite3_stmt* mpVM;
+
+};
+
+
+
+
+
+class CppSQLite3DB
+
+{
+
+public:
+
+
+
+ CppSQLite3DB();
+
+
+
+ virtual ~CppSQLite3DB();
+
+
+
+ void open(const char* szFile);
+
+
+
+ void close();
+
+
+
+ bool tableExists(const char* szTable);
+
+
+
+ int execDML(const char* szSQL);
+
+
+
+ CppSQLite3Query execQuery(const char* szSQL);
+
+
+
+ int execScalar(const char* szSQL);
+
+
+
+ CppSQLite3Table getTable(const char* szSQL);
+
+
+
+ CppSQLite3Statement compileStatement(const char* szSQL);
+
+
+
+ sqlite_int64 lastRowId();
+
+
+
+ void interrupt() { sqlite3_interrupt(mpDB); }
+
+
+
+ void setBusyTimeout(int nMillisecs);
+
+
+
+ static const char* SQLiteVersion() { return SQLITE_VERSION; }
+
+
+
+private:
+
+
+
+ CppSQLite3DB(const CppSQLite3DB& db);
+
+ CppSQLite3DB& operator=(const CppSQLite3DB& db);
+
+
+
+ sqlite3_stmt* compile(const char* szSQL);
+
+
+
+ void checkDB();
+
+
+
+ sqlite3* mpDB;
+
+ int mnBusyTimeoutMs;
+
+};
+
+
+
+#endif
+
--- /dev/null
+#include "creaImageIOWxDescriptorPanel.h"
+#include <creaImageIOSystem.h>
+#include <gdcmGlobal.h>
+#include <gdcmDictSet.h>
+
+
+namespace creaImageIO
+{
+ // CTor
+
+WxDescriptorPanel::WxDescriptorPanel(wxWindow *parent)
+ : wxDialog(parent, -1,_T("Descriptor Creation"), wxDefaultPosition, wxSize(550,550))
+{
+
+
+ GimmickDebugMessage(1,"WxDescriptorPanel::WxDescriptorPanel"
+ <<std::endl);
+
+ lv = 0;
+ ownatt["FullFileName"] = "Full_File_Name";
+ ownatt["FullFileDirectory"] = "Full_File_Directory";
+
+
+ // START BUTTONS
+ wxButton *NewDescriptor = new wxButton(this, -1,_T("Create a new descriptor"), wxPoint(10,7) );
+ Connect( NewDescriptor->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxDescriptorPanel::OnNew );
+
+ wxButton *LoadDescriptor = new wxButton(this, -1,_T("Load a descriptor"), wxPoint(150,7) );
+ Connect( LoadDescriptor->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxDescriptorPanel::OnLoad );
+
+ wxStaticLine *line1 = new wxStaticLine(this, -1, wxPoint(5,40), wxSize(540,2));
+
+ // LEVEL
+ wxStaticText * LevelText=new wxStaticText(this,-1,_T(" Level: "), wxPoint(5,50));
+ LevelCtrl=new wxTextCtrl(this, ID_GR_CTRL,_T("patient"), wxPoint(50,50), wxSize(50,25));
+ wxButton *addLevel = new wxButton(this, ID_LEVEL_ADD,_T("add a level"), wxPoint(150,50) );
+ Connect( addLevel->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxDescriptorPanel::OnAddLevel );
+
+ wxStaticLine *line2 = new wxStaticLine(this, -1, wxPoint(5,75), wxSize(540,2));
+
+ // ATTRIBUTES
+
+ wxStaticText * GR=new wxStaticText(this,-1,_T(" DICOM Group: "), wxPoint(5,110));
+ GRCtrl=new wxTextCtrl(this, ID_GR_CTRL,_T("0x0010"), wxPoint(82,110), wxSize(50,25));
+ Connect( GRCtrl->GetId(), wxEVT_COMMAND_TEXT_UPDATED , (wxObjectEventFunction) &WxDescriptorPanel::OnDicomAttribute );
+
+ wxStaticText * EL=new wxStaticText(this,-1,_T(" DICOM Element: "), wxPoint(140,110));
+ ELCtrl=new wxTextCtrl(this, ID_EL_CTRL,_T("0x0010"), wxPoint(230,110), wxSize(50,25));
+ Connect( ELCtrl->GetId(), wxEVT_COMMAND_TEXT_UPDATED , (wxObjectEventFunction) &WxDescriptorPanel::OnDicomAttribute );
+
+
+ wxString choices[3];
+ choices[0] = "Unknow Attribute";
+ std::map<std::string, std::string>::iterator it_att =ownatt.begin();
+ for(int i = 1; it_att != ownatt.end(); it_att++, i++)
+ {
+ choices[i] = crea::std2wx(it_att->second);
+ }
+
+
+ AttributeCombo = new wxComboBox(this, ID_ATTRIBUTE_CTRL,_T(""),wxPoint(300,110), wxSize(120,25),3,choices, wxCB_READONLY);
+ AttributeCombo->SetSelection(0);
+
+
+ wxButton *addAttribute = new wxButton(this, ID_ATTRIBUTE_ADD,_T("add an attribute"), wxPoint(440,110) );
+ Connect( addAttribute->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxDescriptorPanel::OnAddAttribute );
+
+ wxStaticLine *line3 = new wxStaticLine(this, -1, wxPoint(5,140), wxSize(540,2));
+
+ // RESULT
+
+ ResultCtrl=new wxTextCtrl(this, ID_EL_CTRL,_T(""), wxPoint(5,150), wxSize(250,310), wxTE_READONLY| wxMac | wxTE_MULTILINE | wxTE_RICH );
+ wxButton *RemoveCtrl = new wxButton(this, ID_REMOVE_ADD,_T("Remove an entry"), wxPoint(280,200) );
+ Connect( RemoveCtrl->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxDescriptorPanel::OnRemove );
+
+ wxStaticLine *line4 = new wxStaticLine(this, -1, wxPoint(5,470), wxSize(540,2));
+ // VALIDATION BUTTON
+ wxButton *Ok = new wxButton(this, -1,_T("OK"), wxPoint(10,480) );
+ Connect( Ok->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxDescriptorPanel::OnOK );
+
+ wxButton *Apply = new wxButton(this, -1,_T("APPLY"), wxPoint(150,480) );
+ Connect( Apply->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxDescriptorPanel::OnApply );
+
+ wxButton *Cancel = new wxButton(this, wxID_CANCEL,_T("CANCEL"), wxPoint(250,480) );
+// Connect( Cancel->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxCloseEvent) &wxWindow::Close );
+
+ Layout();
+ CreateDescriptor(0);
+ }
+
+ /// Destructor
+ WxDescriptorPanel::~WxDescriptorPanel()
+ {
+ GimmickDebugMessage(1,"WxCustomizeConfigPanel::~WxCustomizeConfigPanel"
+ <<std::endl);
+ }
+
+ //////////////////////////////////////////////////////////
+ // Add an attribute //
+ // @param event : Wxevent //
+ // @return : - //
+ //////////////////////////////////////////////////
+ void WxDescriptorPanel::OnAddAttribute(wxCommandEvent& event)
+ {
+ std::string name_lv;
+ std::string name_att;
+ if (AttributeCombo->GetSelection() == 0)
+ {
+ name_att = "D" + GRCtrl->GetValue() + "_" + ELCtrl->GetValue();
+ }
+ else
+ { wxString wd = AttributeCombo->GetValue();
+ std::string st = crea::wx2std(wd);
+ name_att = OwnAttribute(st);
+ }
+ onAddAttribute(crea::wx2std(AttributeCombo->GetValue()), name_att);
+ }
+ //////////////////////////////////////////////////////////
+ // add an attribute //
+ // @param att : attribute //
+ // @param name_att : 's name //
+ // @param level : level to add the attribute //
+ // @return : - //
+ //////////////////////////////////////////////////
+ void WxDescriptorPanel::onAddAttribute( const std::string &att, const std::string &name_att,std::string level )
+ {
+ if(lv == 0)
+ {
+ wxMessageBox(_T("Need a level first!"),crea::std2wx("WARNING"),wxOK,this);
+ }
+ else
+ {
+ if( !att.empty() )
+ {
+ // Find Name of level
+ if(level.empty())
+ {
+ level = findLevel();
+ }
+
+ if (!addAtribute(level, name_att))
+ {
+ wxMessageBox(_T("Attribute already used in this level"),crea::std2wx("WARNING"),wxOK,this);
+ }
+ else
+ {
+ ResultCtrl->SetInsertionPoint(InsertPt);
+ for (int i = 1; i<=lv;i++)
+ {
+ ResultCtrl->WriteText(" ");
+ }
+ ResultCtrl->WriteText("| - ");
+ ResultCtrl->WriteText(att);
+ wxTextAttr ResultAttr(ResultCtrl->GetDefaultStyle());
+ ResultAttr.SetTextColour(*wxWHITE);
+ ResultCtrl->SetDefaultStyle(ResultAttr);
+ std::string text = " ";
+ ResultCtrl->WriteText(" " + name_att);
+ ResultAttr.SetTextColour(*wxBLACK);
+ ResultCtrl->SetDefaultStyle(ResultAttr);
+ ResultCtrl->WriteText("\n");
+ }
+ InsertPt = ResultCtrl->GetInsertionPoint();
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////
+ // add a level //
+ // @param event : Wxevent //
+ // @return : - //
+ //////////////////////////////////////////////////
+ void WxDescriptorPanel::OnAddLevel(wxCommandEvent& event)
+ {
+ if( !LevelCtrl->GetValue().IsEmpty() )
+ {
+ onAddLevel(crea::wx2std(LevelCtrl->GetValue()));
+ }
+ }
+
+ //////////////////////////////////////////////////////////
+ // add a level //
+ // @param level : level's name //
+ // @return : - //
+ //////////////////////////////////////////////////
+ void WxDescriptorPanel::onAddLevel(const std::string &level)
+ {
+ if(addLevel(crea::wx2std(level)))
+ {
+ wxMessageBox(_T("Level already used"),crea::std2wx(("WARNING")),wxOK,this);
+ return;
+ }
+
+ lv++;
+ ResultCtrl->SetInsertionPoint(InsertPt);
+ for (int i = 1; i<lv;i++)
+ {
+ ResultCtrl->WriteText(" ");
+ }
+ if(lv>1)
+ { ResultCtrl->WriteText("| \n");
+ for (int i = 1; i<lv;i++)
+ {
+ ResultCtrl->WriteText(" ");
+ }
+ ResultCtrl->WriteText("|_");
+ }
+
+ wxTextAttr ResultAttr(ResultCtrl->GetDefaultStyle());
+ ResultAttr.SetTextColour(*wxRED);
+ ResultCtrl->SetDefaultStyle(ResultAttr);
+ ResultCtrl->WriteText(level);
+ ResultAttr.SetTextColour(*wxBLACK);
+ ResultCtrl->SetDefaultStyle(ResultAttr);
+ ResultCtrl->WriteText("\n");
+ InsertPt = ResultCtrl->GetInsertionPoint();
+
+ }
+
+ //////////////////////////////////////////////////////////
+ // Find a DICOM attribute from group and element values //
+ // @param event : Wxevent //
+ // @return : - //
+ //////////////////////////////////////////////////
+ void WxDescriptorPanel::OnDicomAttribute(wxCommandEvent& event)
+ {
+ int i = 0;
+ if(!GRCtrl->GetValue().IsEmpty() && !ELCtrl->GetValue().IsEmpty()
+ && GRCtrl->GetValue().Len() == 6 && ELCtrl->GetValue().Len() == 6 && AttributeCombo->GetSelection() == 0)
+ {
+
+ std::string gr = crea::wx2std(GRCtrl->GetValue());
+ std::string el = crea::wx2std(ELCtrl->GetValue());
+ std::stringstream val;
+
+ unsigned short group;
+ unsigned short element;
+ val << std::dec << gr ;
+ val >> std::hex >> group;
+ val.clear();
+ val << std::dec << el ;
+ val >> std::hex >> element;
+
+ // Retrieve the name from gdcm dict
+ GDCM_NAME_SPACE::DictEntry* entry = GDCM_NAME_SPACE::Global::GetDicts()->GetDefaultPubDict()->GetEntry(group, element);
+ // AttributeCombo->Clear();
+ if(entry)
+ {
+ AttributeCombo->Delete(0);
+ AttributeCombo->Insert(crea::std2wx(entry->GetName()), 0);
+ }
+ else
+ {
+ AttributeCombo->Delete(0);
+ AttributeCombo->Insert(_T("Unknown Attribute"),0);
+ }
+ AttributeCombo->SetSelection(0);
+
+ }
+
+ }
+
+
+ //////////////////////////////////////////////////////////
+ // determine values for own attributes //
+ // @param name : attribute's name //
+ // @param key : indicates key map or not //
+ // @return : - //
+ //////////////////////////////////////////////////
+ std::string WxDescriptorPanel::OwnAttribute(const std::string name)
+ {
+ std::string result;
+
+ std::map<std::string, std::string>::iterator it_att = ownatt.begin();
+ for(; it_att != ownatt.end(); it_att++)
+ {
+ if(it_att->second == name)
+ {
+ result = it_att->first.c_str();
+ break;
+ }
+ }
+ return result;
+ }
+
+ //////////////////////////////////////////////////////////
+ // Find a level in function of position in Return Ctrl //
+ // @param - : //
+ // @return : - //
+ //////////////////////////////////////////////////
+ std::string WxDescriptorPanel::findLevel()
+ {
+ long column;
+ long line;
+
+ ResultCtrl->PositionToXY( ResultCtrl->GetInsertionPoint(),&column, &line);
+ std::string tx(crea::wx2std(ResultCtrl->GetRange(0, ResultCtrl->XYToPosition(0,line+1))).c_str());
+ std::string::size_type level_pos_start = tx.rfind("|_");
+ if(level_pos_start == -1)
+ {
+ level_pos_start = 0;
+ }
+ else
+ {
+ level_pos_start += 2;
+ }
+
+ std::string::size_type level_pos_end = tx.find_first_of("\n",level_pos_start);
+ return tx.substr(level_pos_start,level_pos_end - level_pos_start);
+ }
+
+ //////////////////////////////////////////////////////
+ // Remove an item //
+ // @param event : Wxevent //
+ // @return : - //
+ //////////////////////////////////////////////////
+ void WxDescriptorPanel::OnRemove(wxCommandEvent& event)
+ {
+ long line;
+ long column;
+ long pos_start;
+ long pos_end;
+
+ pos_start = ResultCtrl->GetInsertionPoint();
+ ResultCtrl->PositionToXY( pos_start,&column, &line);
+ if (line == 0)
+ {
+ std::string name("root");
+ RemoveLevel(name);
+ ResultCtrl->Clear();
+ lv = 0;
+ }
+ else
+ {
+ wxString text = ResultCtrl->GetLineText(line);
+ if ( text.Find("|_") == -1)
+ {
+ std::string level = findLevel();
+ // find GR and EL values to remove
+ std::string tx = crea::wx2std(text);
+ std::string::size_type EL_start_pos = tx.find_last_of(" ");
+ RemoveAttribute(level, tx.substr(EL_start_pos+1,tx.size() - EL_start_pos));
+ ResultCtrl->Remove( ResultCtrl->XYToPosition(0,line), ResultCtrl->XYToPosition(0,line+1));
+ }
+ else
+ {
+ RemoveLevel(crea::wx2std(text.AfterFirst('_')));
+ lv = text.Find("|")/3;
+ pos_start= ResultCtrl->XYToPosition(0,line-1);
+ ResultCtrl->SetInsertionPointEnd();
+ pos_end = ResultCtrl->GetInsertionPoint();
+ ResultCtrl->Remove(pos_start, pos_end);
+ }
+ }
+
+ }
+ //////////////////////////////////////////////////////
+ // create a descriptor structure //
+ // @param name : level's name to add //
+ // @return : boolean result //
+ //////////////////////////////////////////////////
+ void WxDescriptorPanel::CreateDescriptor(int type)
+ {
+ if(type == 0) // First initialization
+ {
+ outDscp.clear();
+ outDscp += "<level>";
+ outDscp += "\n";
+ outDscp += "root";
+ outDscp += "\n";
+ outDscp += "O Name Name 4";
+ outDscp += "\n";
+ }
+ if(type == 1)
+ {
+ if(lv > 1)
+ {
+ outDscp += "O NumberOfChildren ";
+ outDscp += crea::wx2std(LevelCtrl->GetValue());
+ outDscp += "s";
+ outDscp += "\n";
+ }
+ outDscp += "<level>";
+ outDscp += "\n";
+ outDscp += crea::wx2std(LevelCtrl->GetValue());
+ outDscp += "\n";
+
+ }
+ if(type == 2)
+ {
+ outDscp += "D";
+ outDscp += " ";
+ outDscp += crea::wx2std(GRCtrl->GetValue());
+ outDscp += " ";
+ outDscp += crea::wx2std(ELCtrl->GetValue());
+ outDscp += " ";
+ outDscp += "3";
+ outDscp += "\n";
+ }
+
+
+ }
+
+
+ //////////////////////////////////////////////////////
+ // add a level //
+ // @param name : level's name to add //
+ // @return : boolean result //
+ //////////////////////////////////////////////////
+ bool WxDescriptorPanel::addLevel(const std::string &name)
+ {
+ bool bfound = false;
+ std::map<std::string, std::vector <std::string> >::iterator it_tree = DscpTree.begin();
+ for (;it_tree != DscpTree.end(); it_tree++)
+ {
+ if(it_tree->first == name)
+ {
+ bfound = true;
+ break;
+ }
+ }
+ if(!bfound)
+ {
+ lvlist[lv] = name;
+ std::vector <std::string> branch;
+ DscpTree[name] = branch;
+ }
+ return bfound;
+ }
+
+ //////////////////////////////////////////////////////
+ // remove a level //
+ // @param name : level's name to remove //
+ // @return : boolean result //
+ //////////////////////////////////////////////////
+ bool WxDescriptorPanel::RemoveLevel(const std::string &name)
+ {
+ bool bresult = false;
+ std::map<int, std::string>::iterator it_list= lvlist.begin();
+ for(; it_list != lvlist.end(); it_list++)
+ {
+ if(it_list->second == name)
+ {
+ break;
+ }
+ }
+ std::map<int, std::string>::iterator it_list2 = it_list;
+ for(;it_list != lvlist.end(); it_list++)
+ {
+ std::map<std::string, std::vector <std::string> >::iterator it_tree = DscpTree.begin();
+ for (;it_tree != DscpTree.end(); it_tree++)
+ {
+ if(it_tree->first == name)
+ {
+ DscpTree.erase(it_tree);
+ break;
+ }
+ }
+ }
+ lvlist.erase(it_list2, lvlist.end());
+ return bresult;
+ }
+
+
+ //////////////////////////////////////////////////////
+ // add an attribute in a level //
+ // @param level : level's name to add attribute //
+ // @param name : attribute's name //
+ // @return : boolean result //
+ //////////////////////////////////////////////////
+ bool WxDescriptorPanel::addAtribute(const std::string &level, const std::string &name)
+ {
+ bool bresult = true;
+ std::map<std::string, std::vector <std::string> >::iterator it_tree = DscpTree.begin();
+ for (;it_tree != DscpTree.end(); it_tree++)
+ {
+ if (it_tree->first.c_str() == level)
+ {
+ std::vector<std::string>::iterator it_branch = it_tree->second.begin();
+ for(;it_branch != it_tree->second.end(); it_branch++)
+ {
+ if(it_branch->c_str() == name)
+ {
+ bresult = false;
+ }
+ }
+ if(bresult)
+ {
+ it_tree->second.push_back(name);
+ break;
+ }
+ }
+ }
+ return bresult;
+ }
+
+ //////////////////////////////////////////////////////
+ // remove an attribute from a level //
+ // @param level : level's name to remove attribute //
+ // @param name : attribute's name //
+ // @return : boolean result //
+ //////////////////////////////////////////////////
+ bool WxDescriptorPanel::RemoveAttribute(const std::string &level, const std::string &name)
+ {
+ bool bresult = false;
+ std::map<std::string, std::vector <std::string> >::iterator it_tree = DscpTree.begin();
+ for (;it_tree != DscpTree.end(); it_tree++)
+ {
+ if(it_tree->first == level)
+ {
+ std::vector<std::string>::iterator it_branch = it_tree->second.begin();
+ cout << it_tree->second.size();
+ for(;it_branch != it_tree->second.end(); it_branch++)
+ {
+ if(it_branch->c_str() == name)
+ {
+ bresult = true;
+ it_tree->second.erase(it_branch);
+ break;
+ }
+ }
+ }
+ }
+ return bresult;
+ }
+
+ //////////////////////////////////////////////////
+ // create a new descriptor //
+ // @param event : WxEvent //
+ // @return : - //
+ //////////////////////////////////////////////////
+ void WxDescriptorPanel::OnNew(wxCommandEvent &Event)
+ {
+ LevelCtrl->SetValue(_T("patient"));
+ ResultCtrl->Clear();
+ DscpTree.clear();
+ lv = 0;
+ }
+
+ //////////////////////////////////////////////////
+ // Load a descriptor file //
+ // @param event : WxEvent //
+ // @return : - //
+ //////////////////////////////////////////////////
+ void WxDescriptorPanel::OnLoad(wxCommandEvent &Event)
+ {
+ long style = wxOPEN | wxFILE_MUST_EXIST;
+ LevelCtrl->SetValue(_T("patient"));
+ ResultCtrl->Clear();
+ DscpTree.clear();
+ lv = 0;
+
+ std::string wc("*.dscp");
+ wxFileDialog* FD = new wxFileDialog( 0,
+ _T("Select file"),
+ _T(""),
+ _T(""),
+ crea::std2wx(wc),
+ style,
+ wxDefaultPosition);
+ if (FD->ShowModal()==wxID_OK)
+ {
+ loadDescriptor(crea::wx2std(FD->GetPath()).c_str());
+ }
+
+ }
+
+ //////////////////////////////////////////////////
+ // Save a descriptor //
+ // @param event : WxEvent //
+ // @return : - //
+ //////////////////////////////////////////////////
+ void WxDescriptorPanel::OnOK(wxCommandEvent &Event)
+ {
+ saveDescriptor();
+ wxWindow::Close();
+ }
+
+ /////////////////////////////////////////////////////
+ // Save a descriptor and apply it (create a new DB//
+ // @param event : WxEvent //
+ // @return : - //
+ /////////////////////////////////////////////////////
+ void WxDescriptorPanel::OnApply(wxCommandEvent &Event)
+ {
+ m_DscpFile = saveDescriptor();
+ wxWindow::Close();
+ SetReturnCode(ID_DSCP_APPLY);
+ }
+
+ const std::string WxDescriptorPanel::saveDescriptor()
+ {
+ std::string file = "";
+ long style = wxSAVE;
+ std::string wc("*.dscp");
+ wxFileDialog* FD = new wxFileDialog( 0,
+ _T("Select file"),
+ _T(""),
+ _T(""),
+ crea::std2wx(wc),
+ style,
+ wxDefaultPosition);
+
+
+ if (FD->ShowModal()==wxID_OK)
+ {
+ createDescriptorFile();
+ file = crea::wx2std(FD->GetPath()).c_str();
+ std::ofstream ofs(file.c_str());
+ ofs.clear();
+ ofs << outDscp;
+ ofs.close();
+ }
+ return file.c_str();
+ }
+
+ ///////////////////////////////////////////////////////
+ // Cancel action //
+ // @param event : WxEvent //
+ // @return : - //
+ ///////////////////////////////////////////////////////
+
+ void WxDescriptorPanel::OnCancel(wxCommandEvent& event)
+ {
+ }
+
+ ///////////////////////////////////////////////////////
+ // create a descriptor file //
+ // @param - : //
+ // @return : - //
+ ///////////////////////////////////////////////////////
+ void WxDescriptorPanel::createDescriptorFile()
+ {
+
+ outDscp.clear();
+ outDscp += "<level>";
+ outDscp += "\n";
+ outDscp += "Root";
+ outDscp += "\n";
+ outDscp += "O Name Name 4";
+ outDscp += "\n";
+ std::map<std::string, std::vector <std::string> >::iterator it_tree = DscpTree.begin();
+ std::map<int, std::string >::iterator it_lv_nb = lvlist.begin();
+ std::map<int, std::string >::iterator it_lv = lvlist.begin();
+ it_lv_nb++;
+ for (;it_lv != lvlist.end(); it_lv++, it_lv_nb++)
+ {
+ outDscp +="<level>";
+ outDscp += "\n";
+ outDscp += it_lv->second.c_str();
+ outDscp += "\n";
+ if(it_lv_nb != lvlist.end())
+ {
+ outDscp += "O NumberOfChildren ";
+ outDscp += it_lv_nb->second.c_str();
+ outDscp += "s";
+ outDscp += "\n";
+ }
+ std::vector<std::string>::iterator it_branch = DscpTree[it_lv->second.c_str()].begin();
+ for(;it_branch != DscpTree[it_lv->second.c_str()].end(); it_branch++)
+ {
+ std::string att = it_branch->c_str();
+ if(att[0] == 'D' && att[7] == '_' && att.size() == 14)
+ {
+ outDscp += "D ";
+ outDscp += att.substr(1,6) + " "; // GR
+ outDscp += att.substr(8,6) + " ";// EL
+ outDscp += "3";
+ outDscp += "\n";
+ }
+ else
+ {
+ outDscp += "O ";
+ outDscp += it_branch->c_str();
+ outDscp += " ";
+ outDscp += ownatt[att];
+ outDscp += " ";
+ outDscp += "2";
+ outDscp += "\n";
+ }
+ }
+
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////
+ // load a descriptor //
+ // @param i_name : file name to load //
+ // @return : - //
+ /////////////////////////////////////////////////////
+ void WxDescriptorPanel::loadDescriptor(const std::string i_name)
+ {
+ std::ifstream i_file(i_name.c_str());
+ std::stringstream buffer;
+ buffer << i_file.rdbuf();
+ std::string line;
+ std::string level;
+
+ bool bname;
+ int ilevel = -1;
+
+
+ while(std::getline(buffer, line))
+ {
+ if(line =="<level>")
+ { //increment levels.
+ ilevel++;
+ bname = true;
+ }
+ else if(bname)
+ {
+ // For each level, a name to describe it
+ level = line;
+ if(ilevel>0)
+ {
+ onAddLevel(level);
+ }
+ bname = false;
+ }
+ else
+ {
+ // split line to find all tags
+ std::vector<std::string> descriptors;
+ std::string separator = " ";
+ std::string::size_type last_pos = line.find_first_not_of(separator);
+ //find first separator
+ std::string::size_type pos = line.find_first_of(separator, last_pos);
+ while(std::string::npos != pos || std::string::npos != last_pos)
+ {
+ descriptors.push_back(line.substr(last_pos, pos - last_pos));
+ last_pos = line.find_first_not_of(separator, pos);
+ pos = line.find_first_of(separator, last_pos);
+ }
+
+ // By default, the last tag is at zero and not recorded but if take in count
+ unsigned int flag = 0;
+ if(descriptors.size() == 4)
+ {
+ std::stringstream val;
+ val << std::dec << descriptors[3];
+ val>> flag;
+ }
+
+ // if Dicom tag, use "group" and "element" descriptor
+ if(descriptors[0] == "D")
+ { std::stringstream val, val2;
+ unsigned short group;
+ unsigned short element;
+ val << std::dec << descriptors[1] ;
+ val >> std::hex >> group;
+ val2 << std::dec << descriptors[2];
+ val2 >> std::hex >> element;
+ std::string compose = "D";
+ compose += descriptors[1];
+ compose += "_";
+ compose += descriptors[2];
+ GDCM_NAME_SPACE::DictEntry* entry = GDCM_NAME_SPACE::Global::GetDicts()->GetDefaultPubDict()->GetEntry(group, element);
+ if(ilevel>0)
+ {
+ onAddAttribute( entry->GetName(),compose, level);
+ }
+ }
+ else // "O" means if user's own tag.
+ {
+ boost::algorithm::replace_all(descriptors[2],"_"," ");
+ if(ilevel>0 && descriptors[1] != "NumberOfChildren" )
+ {
+ onAddAttribute( descriptors[2].c_str(),descriptors[1].c_str(), level);
+ }
+ }
+ }
+ }
+ }
+
+//======================================================================
+
+//======================================================================
+
+} // EO namespace creaImageIO
+
+