]> Creatis software - creaImageIO.git/commitdiff
creation of an interface to manage DB descriptor files
authorFrederic Cervenansky <Frederic.Cervenansky@creatis.insa-lyon.fr>
Thu, 27 Aug 2009 11:47:02 +0000 (11:47 +0000)
committerFrederic Cervenansky <Frederic.Cervenansky@creatis.insa-lyon.fr>
Thu, 27 Aug 2009 11:47:02 +0000 (11:47 +0000)
src2/CppSQLite3.cpp
src2/CppSQLite3.h
src2/creaImageIOGimmick.cpp
src2/creaImageIOGimmickReaderDialog.cpp
src2/creaImageIOWxCustomizeConfigPanel.cpp
src2/creaImageIOWxDescriptorPanel.cpp [new file with mode: 0644]
src2/creaImageIOWxDescriptorPanel.h [new file with mode: 0644]
src2/creaImageIOWxGimmickView.cpp
src2/creaImageIOWxViewer.cpp

index 3d074d58c0b1c2e702d35b3ce729d6f06cbf84db..cf58159932b2acb7d1dce05e9e459d5dcfad07f7 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\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;
+
+}
+
index c45c9cb81ee30eedd8d001cab8dec3ad1997142f..9d5bcd41daf873644d72a8830c2f6ae95abeb5fd 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\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
+
index de6b11dd169ea626d5255a2a64b5f2813607ad10..9f12380f6d07da06df1a6b4c5f6957cd9920917a 100644 (file)
@@ -91,7 +91,6 @@ namespace creaImageIO
                }
        }
 
   ///////////////////////////////////////////////////////////////////////////
   // create a DB from a attributes descriptor file for medical images      //
   // @param i_name : DB name                                                                                      //
index d8c52e1d947fa096d9f26588aad5118b3d183b51..d890f701e9cc83727fc30dd2ef5c0bfb576b9a17 100644 (file)
@@ -1,6 +1,6 @@
 #include <creaImageIOGimmickReaderDialog.h>
 #include <creaImageIOWxGimmickReaderDialog.h>
-#include <BlockScopeWxApp.h>
+
 
 namespace creaImageIO
 {
@@ -16,7 +16,7 @@ namespace creaImageIO
                           int image_out_dim,
                           int nb_threads)
   {
-    BlockScopeWxApp app;
+
     
     creaImageIO::WxGimmickReaderDialog w(0,
                                         -1,
index 7ca2f2323a1f704fdc15ef0e2a39e00f83eb3334..f237eaf9f6f6d4dd3715b50fb8343852c3b97c4e 100644 (file)
@@ -42,10 +42,6 @@ namespace creaImageIO
        wxButton *save = new wxButton(this,wxID_ANY,_T("Save Changes"), wxPoint(5,130) );
        Connect( save->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxCustomizeConfigPanel::OnSaveConfig ); 
   
-
-    //topsizer->Add( mView,1,wxGROW,0);
-
-//    SetSizer( topsizer );     
     Layout(); 
   }
 
diff --git a/src2/creaImageIOWxDescriptorPanel.cpp b/src2/creaImageIOWxDescriptorPanel.cpp
new file mode 100644 (file)
index 0000000..f37554b
--- /dev/null
@@ -0,0 +1,782 @@
+#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
+
+
diff --git a/src2/creaImageIOWxDescriptorPanel.h b/src2/creaImageIOWxDescriptorPanel.h
new file mode 100644 (file)
index 0000000..2f95e81
--- /dev/null
@@ -0,0 +1,154 @@
+#ifndef __creaImageIOWxDescriptorPanel_h_INCLUDED__
+#define __creaImageIOWxDescriptorPanel_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+#include <creaWx.h>
+#include <string>
+#include <map>
+#include <vector>
+#include <creaImageIOWxGimmickView.h>
+#include <wx/listctrl.h>
+#include <wx/statline.h>
+
+
+#define ID_DESCRIPTOR 1500
+#define ID_LEVEL_CTRL       ID_DESCRIPTOR+1
+#define ID_LEVEL_ADD        ID_DESCRIPTOR+2
+#define ID_GR_CTRL              ID_DESCRIPTOR+3
+#define ID_EL_CTRL              ID_DESCRIPTOR+4
+#define ID_NAME_CTRL        ID_DESCRIPTOR+5
+#define ID_ATTRIBUTE_CTRL       ID_DESCRIPTOR+6
+#define ID_ATTRIBUTE_ADD        ID_DESCRIPTOR+7
+#define ID_REMOVE_ADD           ID_DESCRIPTOR+8
+#define ID_DSCP_APPLY           ID_DESCRIPTOR+9
+
+namespace creaImageIO
+{
+
+  /**
+   * \ingroup GUI
+   */
+  //=====================================================================
+ //=====================================================================
+ /// Gimmick DB are based on descriptors with a tree structure .
+ /// Ecah level contains attributes (DICOM or other) to identify data
+ /// WxDescriptorPanel allows creation, modification and save of descriptors. 
+ ///
+
+  class WxDescriptorPanel : public wxDialog
+  {
+  public:
+    WxDescriptorPanel();    
+       WxDescriptorPanel(wxWindow *parent);
+    ~WxDescriptorPanel();
+
+       // Get file to load Descriptor
+       const std::string& GetDescriptor(){ return m_DscpFile;}
+
+  private :
+
+    // WxControls
+       wxTextCtrl *LevelCtrl;  //TextCtrl to enter level's name
+       wxTextCtrl *GRCtrl;     // TextCtrl to enter DICOM Group value
+       wxTextCtrl *ELCtrl;     // TextCtrl to enter DICOM element value
+       wxTextCtrl *ResultCtrl; //TextCtrl to visualize Descriptor
+       wxComboBox *AttributeCombo; // Combox to choose Attribute values
+
+       /// Add an attribute (DICOM or own) 
+       void OnAddAttribute(wxCommandEvent& event);
+
+       /// Add an attribute (DICOM or own)
+       void onAddAttribute( const std::string &att, const std::string &name_att, std::string level = "");
+
+       /// Add a Level 
+       void OnAddLevel(wxCommandEvent& event);
+       
+       /// Add a Level 
+       void onAddLevel(const std::string &level);
+
+       /// Find a DICOM attribute from group and element values
+       void OnDicomAttribute(wxCommandEvent& event);
+
+       /// Remove a value (level or attribute)
+       void OnRemove(wxCommandEvent& event);
+
+       /// Create a new descriptor
+       void OnNew(wxCommandEvent& event);
+
+       /// Load an exsitant descriptor
+       void OnLoad(wxCommandEvent& event);
+
+       /// Save a descriptor
+       void OnOK(wxCommandEvent& event);
+
+       /// Save a descriptor and use it
+       void OnApply(wxCommandEvent& event);
+
+       /// Cancel
+       void OnCancel(wxCommandEvent& event);
+
+       /// Create a descriptor structure
+       void CreateDescriptor(int type);
+
+       /// add a level
+       bool addLevel(const std::string &name);
+
+       /// add an attribute
+       bool addAtribute(const std::string &level, const std::string &name);
+
+       /// remove an attribute
+       bool RemoveAttribute(const std::string &level, const std::string &name);
+
+       /// remove a level
+       bool RemoveLevel(const std::string &name);
+
+       /// Create a descriptor file
+       void createDescriptorFile();
+       
+       /// load a descriptor file
+       void loadDescriptor(const std::string i_name);
+
+       /// find a level'name 
+       std::string findLevel();
+
+       /// determine values for own attributes
+       std::string OwnAttribute(const std::string name);
+
+       /// save a descriptor in a file
+       const std::string saveDescriptor();
+
+       /// number of level 
+       int lv;
+
+       /// Insert point in result control
+       long InsertPt;
+
+       /// Output file for Descriptor
+       std::string m_DscpFile;
+
+       /// Output Descriptor
+       std::string outDscp; 
+       
+       // Vector of attributes
+       std::vector<std::string> VLevel;
+
+       // map of level, attributes
+       std::map<std::string, std::vector<std::string> > DscpTree;
+
+       // map of own application attributes
+       std::map<std::string, std::string> ownatt;
+
+       // List of added level
+       std::map<int, std::string> lvlist;
+
+  }; // class WxDescriptorPanel
+  //=====================================================================
+
+  
+} // EO namespace creaImageIO
+
+
+#endif // USE_WIDGETS
+// EOF
+#endif
+
index c3e2b07c20807c32ca585a052bdc2bfeb4d5120c..522b0547258f52655e1b3cc96a00118e30b52e21 100644 (file)
@@ -6,6 +6,7 @@
 #include <creaImageIOWxEditFieldsPanel.h>
 #include <creaImageIOWxAttributeSelectionPanel.h>
 #include <creaImageIOWxPACSConnectionPanel.h>
+#include <creaImageIOWxDescriptorPanel.h>
 
 using namespace crea;
 // Icons
@@ -36,15 +37,15 @@ namespace creaImageIO
   // The ids of the different tools
   enum
     {
-         TOOL_CREATEDB_ID = 1,
-      TOOL_ADDFILES_ID = 2,
-      TOOL_ADDDIR_ID = 3,
-         TOOL_ADDDATABASE_ID = 4,
-      TOOL_REMOVE_ID = 5,
-         TOOL_SYNCHRONIZE_ID = 6,
-      TOOL_HELP_ID = 7,
-         TOOL_SETTINGS_ID = 8,
-         TOOL_TOOLS_ID = 9
+         TOOL_ADDFILES_ID = 1,
+      TOOL_ADDDIR_ID = 2,
+         TOOL_ADDDATABASE_ID = 3,
+      TOOL_REMOVE_ID = 4,
+         TOOL_SYNCHRONIZE_ID = 5,
+      TOOL_HELP_ID = 6,
+         TOOL_SETTINGS_ID = 7,
+         TOOL_TOOLS_ID = 8,
+         TOOL_CREATEDB_ID = 9,
     };
   //======================================================================
 
@@ -204,12 +205,7 @@ namespace creaImageIO
     mToolBar = new wxToolBar(this,-1,wxDefaultPosition,wxDefaultSize,
                             style);
 
-       mToolAddFile = mToolBar->AddTool( TOOL_CREATEDB_ID, 
-                                     _T("Create database"),
-                                     mIcon->GetBitmap(Icon_create_database),
-                                     _T("Create DB from an Attributes Descriptor file")
-                                     );
-    mToolAddFile = mToolBar->AddTool( TOOL_ADDFILES_ID, 
+       mToolAddFile = mToolBar->AddTool( TOOL_ADDFILES_ID, 
                                      _T("Add file(s)"),
                                      mIcon->GetBitmap(Icon_page_down),
                                      _T("Add one or more file to database")
@@ -249,6 +245,12 @@ namespace creaImageIO
                                      mIcon->GetBitmap(Icon_tools),
                                      _T("Applies tools to images")
                                      );
+       mToolAddFile = mToolBar->AddTool( TOOL_CREATEDB_ID, 
+                                     _T("Create database"),
+                                     mIcon->GetBitmap(Icon_create_database),
+                                     _T("Create DB from an Attributes Descriptor file")
+                                     );
+
     //const wxBitmap& bitmap1, const wxString& shortHelpString = "", wxItemKind kind = wxITEM_NORMAL)
 
     mToolBar->Realize();
@@ -783,7 +785,8 @@ namespace creaImageIO
   {
                mViewer->StopPlayer();
                
-               wxDialog* dial = new wxDialog (this,-1,_T("Tools"),wxDefaultPosition, wxSize(300,250));
+       
+               wxDialog* dial = new wxDialog (this,-1,_T("Tools"),wxDefaultPosition, wxSize(550,350));
 
                wxSizer* buttonsSizer = dial->CreateSeparatedButtonSizer(wxOK|wxCANCEL);
                wxNotebook* nb= new wxNotebook(dial, -1, wxDefaultPosition, wxDefaultSize, 0);
@@ -797,6 +800,7 @@ namespace creaImageIO
                        WxGimmickTools * gimmickTools = new WxGimmickTools(nb, mCurrentDirectory);
                        nb->AddPage( gimmickTools, _T("Bruker Image Reader") );
 #endif
+                       
 
                dial->SetSizer(dialSizer, true);
                dial->Layout();
@@ -1027,21 +1031,6 @@ namespace creaImageIO
     mess << "Files\tscanned\t: " << p.GetNumberScannedFiles() << "\n";
     mess << "Files\thandled\t: " << p.GetNumberHandledFiles() << "\n\n";
     mess << "Files\tadded  \t: " << p.GetNumberAddedFiles()   << "\n\n";
-
-    /*    char times[500];
-    sprintf(times,"Time to parse dir \t\t: %ld ms \t%d°/o\nTime to read files info \t: %ld ms \t%d°/o\nTime to update structs \t: %ld ms \t%d°/o\nTime to update database \t: %ld ms \t%d°/o\nTotal time \t\t\t: %ld ms",
-           summary.parse_time,
-           (int)( summary.parse_time*100./summary.total_time),
-           summary.file_scan_time,
-           (int)(summary.file_scan_time*100./summary.total_time),
-           summary.update_structs_time,
-           (int)(summary.update_structs_time*100./summary.total_time),
-           summary.update_database_time,
-           (int)(summary.update_database_time*100./summary.total_time),
-           summary.total_time );
-    
-    mess << times;
-    */
     wxMessageBox(std2wx(mess.str()),_T("Addition result"),wxOK,this);
   }
 
@@ -1092,38 +1081,29 @@ namespace creaImageIO
   void WxGimmickView::OnCreateDB(wxCommandEvent& event)
   {
     
-         //Select DB
-         long style = wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST;
-         std::string wc("*.txt");
-         wxFileDialog* FD = new wxFileDialog( 0, 
-                                        _T("Select file"),
-                                        _T(""),
-                                        _T(""),
-                                        crea::std2wx(wc),
-                                        style,
-                                        wxDefaultPosition);
-    
-    if (FD->ShowModal()==wxID_OK)
-       {
-               wxBusyCursor busy;
-               wxArrayString afile;
-               FD->GetPaths(afile);
-               //get name of DB (file name)
-               std::string file = crea::wx2std(afile[0]);
-               size_t pos = file.find_last_of("\\");
-               std::string name = file.substr(pos+1);
-               std::string directory = file.substr(0,pos);
-               pos = name.find_last_of(".");
-               name = name.substr(0,pos);
-               //get directory to store DB
-               directory +=  "\\" + name + ".sqlite3";
-               //create createDB
-               mGimmick->createDB(name, file,directory);
-               //create TreeHandler
-               mGimmick->addDB(name, directory);
-               //create TreeView
-               CreateSingleTreeView(name);
-       }
+         WxDescriptorPanel * DescriptorPan = new WxDescriptorPanel(this);
+               DescriptorPan->Layout();
+               if ( DescriptorPan->ShowModal() == ID_DSCP_APPLY)
+               {
+                       wxBusyCursor busy;
+                       std::string file(DescriptorPan->GetDescriptor());
+                       if (!file.empty())
+                       {
+                               size_t pos = file.find_last_of("\\");
+                               std::string name = file.substr(pos+1);
+                               std::string directory = file.substr(0,pos);
+                               pos = name.find_last_of(".");
+                               name = name.substr(0,pos);
+                               //get directory to store DB
+                               directory +=  "\\" + name + ".sqlite3";
+                               //create createDB
+                               mGimmick->createDB(name, file,directory);
+                               //create TreeHandler
+                               mGimmick->addDB(name, directory);
+                               //create TreeView
+                               CreateSingleTreeView(name);
+                       }
+               }
   }
 
    //=================================================
index 193fedb7881179c91504be980052c55f178f2e13..cf9f13cf32d38ae8d26227981e4cd82167bba15d 100644 (file)
@@ -5,7 +5,7 @@
 #include <vtkCamera.h>
 #include <vtkRenderer.h>
 #include <vtkImageData.h>
-
+#include <creawxVTKRenderWindowInteractor.h>
 #include <creaMessageManager.h>
 #include <stdio.h>
 #include <time.h>