]> Creatis software - creaImageIO.git/blobdiff - src/CppSQLite3.cpp
#3185 creaImageIO Feature New Normal - Clean code
[creaImageIO.git] / src / CppSQLite3.cpp
index 5d82661eb62e49e2fdce0f76ea6954d63bf62177..4ad953f9287c513c1cb1394caf61e17c433505ed 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
-                                                                       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 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 2008/09/26 14:15:48 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.4 2010/03/16 15:46:13 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;
+
+}
+