]> Creatis software - creaImageIO.git/blob - src/CppSQLite3.cpp
165f9110bebc1ed0baab8e592fc5e6d09ebebb9a
[creaImageIO.git] / src / CppSQLite3.cpp
1 ////////////////////////////////////////////////////////////////////////////////\r
2 // CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library.\r
3 //\r
4 // Copyright (c) 2004 Rob Groves. All Rights Reserved. rob.groves@btinternet.com\r
5 // \r
6 // Permission to use, copy, modify, and distribute this software and its\r
7 // documentation for any purpose, without fee, and without a written\r
8 // agreement, is hereby granted, provided that the above copyright notice, \r
9 // this paragraph and the following two paragraphs appear in all copies, \r
10 // modifications, and distributions.\r
11 //\r
12 // IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,\r
13 // INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST\r
14 // PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,\r
15 // EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
16 //\r
17 // THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT\r
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\r
19 // PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF\r
20 // ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION\r
21 // TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.\r
22 //\r
23 // V3.0         03/08/2004      -Initial Version for sqlite3\r
24 //\r
25 // V3.1         16/09/2004      -Implemented getXXXXField using sqlite3 functions\r
26 //                                              -Added CppSQLiteDB3::tableExists()\r
27 ////////////////////////////////////////////////////////////////////////////////\r
28 #include "CppSQLite3.h"\r
29 #include <cstdlib>\r
30 \r
31 \r
32 // Named constant for passing to CppSQLite3Exception when passing it a string\r
33 // that cannot be deleted.\r
34 static const bool DONT_DELETE_MSG=false;\r
35 \r
36 ////////////////////////////////////////////////////////////////////////////////\r
37 // Prototypes for SQLite functions not included in SQLite DLL, but copied below\r
38 // from SQLite encode.c\r
39 ////////////////////////////////////////////////////////////////////////////////\r
40 int sqlite3_encode_binary(const unsigned char *in, int n, unsigned char *out);\r
41 int sqlite3_decode_binary(const unsigned char *in, unsigned char *out);\r
42 \r
43 ////////////////////////////////////////////////////////////////////////////////\r
44 \r
45 ////////////////////////////////////////////////////////////////////////////////\r
46 \r
47 CppSQLite3Exception::CppSQLite3Exception(const int nErrCode,\r
48                                          const char* szErrMess,\r
49                                          bool bDeleteMsg/*=true*/) :\r
50   mnErrCode(nErrCode)\r
51 {\r
52   mpszErrMess = sqlite3_mprintf("%s[%d]: %s",\r
53                                 errorCodeAsString(nErrCode),\r
54                                 nErrCode,\r
55                                 szErrMess ? szErrMess : "");\r
56   /*\r
57   if (bDeleteMsg && szErrMess)\r
58     {\r
59       sqlite3_free(szErrMess);\r
60     }\r
61   */\r
62 }\r
63 \r
64 CppSQLite3Exception::CppSQLite3Exception(const int nErrCode,\r
65                                          char* szErrMess,\r
66                                          bool bDeleteMsg/*=true*/) :\r
67   mnErrCode(nErrCode)\r
68 {\r
69   mpszErrMess = sqlite3_mprintf("%s[%d]: %s",\r
70                                 errorCodeAsString(nErrCode),\r
71                                 nErrCode,\r
72                                 szErrMess ? szErrMess : "");\r
73   \r
74   if (bDeleteMsg && szErrMess)\r
75     {\r
76       sqlite3_free(szErrMess);\r
77     }\r
78 }\r
79                                                                         \r
80 CppSQLite3Exception::CppSQLite3Exception(const CppSQLite3Exception&  e) :\r
81                                                                         mnErrCode(e.mnErrCode)\r
82 {\r
83         mpszErrMess = 0;\r
84         if (e.mpszErrMess)\r
85         {\r
86                 mpszErrMess = sqlite3_mprintf("%s", e.mpszErrMess);\r
87         }\r
88 }\r
89 \r
90 \r
91 const char* CppSQLite3Exception::errorCodeAsString(int nErrCode)\r
92 {\r
93         switch (nErrCode)\r
94         {\r
95                 case SQLITE_OK          : return "SQLITE_OK";\r
96                 case SQLITE_ERROR       : return "SQLITE_ERROR";\r
97                 case SQLITE_INTERNAL    : return "SQLITE_INTERNAL";\r
98                 case SQLITE_PERM        : return "SQLITE_PERM";\r
99                 case SQLITE_ABORT       : return "SQLITE_ABORT";\r
100                 case SQLITE_BUSY        : return "SQLITE_BUSY";\r
101                 case SQLITE_LOCKED      : return "SQLITE_LOCKED";\r
102                 case SQLITE_NOMEM       : return "SQLITE_NOMEM";\r
103                 case SQLITE_READONLY    : return "SQLITE_READONLY";\r
104                 case SQLITE_INTERRUPT   : return "SQLITE_INTERRUPT";\r
105                 case SQLITE_IOERR       : return "SQLITE_IOERR";\r
106                 case SQLITE_CORRUPT     : return "SQLITE_CORRUPT";\r
107                 case SQLITE_NOTFOUND    : return "SQLITE_NOTFOUND";\r
108                 case SQLITE_FULL        : return "SQLITE_FULL";\r
109                 case SQLITE_CANTOPEN    : return "SQLITE_CANTOPEN";\r
110                 case SQLITE_PROTOCOL    : return "SQLITE_PROTOCOL";\r
111                 case SQLITE_EMPTY       : return "SQLITE_EMPTY";\r
112                 case SQLITE_SCHEMA      : return "SQLITE_SCHEMA";\r
113                 case SQLITE_TOOBIG      : return "SQLITE_TOOBIG";\r
114                 case SQLITE_CONSTRAINT  : return "SQLITE_CONSTRAINT";\r
115                 case SQLITE_MISMATCH    : return "SQLITE_MISMATCH";\r
116                 case SQLITE_MISUSE      : return "SQLITE_MISUSE";\r
117                 case SQLITE_NOLFS       : return "SQLITE_NOLFS";\r
118                 case SQLITE_AUTH        : return "SQLITE_AUTH";\r
119                 case SQLITE_FORMAT      : return "SQLITE_FORMAT";\r
120                 case SQLITE_RANGE       : return "SQLITE_RANGE";\r
121                 case SQLITE_ROW         : return "SQLITE_ROW";\r
122                 case SQLITE_DONE        : return "SQLITE_DONE";\r
123                 case CPPSQLITE_ERROR    : return "CPPSQLITE_ERROR";\r
124                 default: return "UNKNOWN_ERROR";\r
125         }\r
126 }\r
127 \r
128 \r
129 CppSQLite3Exception::~CppSQLite3Exception()\r
130 {\r
131         if (mpszErrMess)\r
132         {\r
133                 sqlite3_free(mpszErrMess);\r
134                 mpszErrMess = 0;\r
135         }\r
136 }\r
137 \r
138 \r
139 ////////////////////////////////////////////////////////////////////////////////\r
140 \r
141 CppSQLite3Buffer::CppSQLite3Buffer()\r
142 {\r
143         mpBuf = 0;\r
144 }\r
145 \r
146 \r
147 CppSQLite3Buffer::~CppSQLite3Buffer()\r
148 {\r
149         clear();\r
150 }\r
151 \r
152 \r
153 void CppSQLite3Buffer::clear()\r
154 {\r
155         if (mpBuf)\r
156         {\r
157                 sqlite3_free(mpBuf);\r
158                 mpBuf = 0;\r
159         }\r
160 \r
161 }\r
162 \r
163 \r
164 const char* CppSQLite3Buffer::format(const char* szFormat, ...)\r
165 {\r
166         clear();\r
167         va_list va;\r
168         va_start(va, szFormat);\r
169         mpBuf = sqlite3_vmprintf(szFormat, va);\r
170         va_end(va);\r
171         return mpBuf;\r
172 }\r
173 \r
174 \r
175 ////////////////////////////////////////////////////////////////////////////////\r
176 \r
177 CppSQLite3Binary::CppSQLite3Binary() :\r
178                                                 mpBuf(0),\r
179                                                 mnBinaryLen(0),\r
180                                                 mnBufferLen(0),\r
181                                                 mnEncodedLen(0),\r
182                                                 mbEncoded(false)\r
183 {\r
184 }\r
185 \r
186 \r
187 CppSQLite3Binary::~CppSQLite3Binary()\r
188 {\r
189         clear();\r
190 }\r
191 \r
192 \r
193 void CppSQLite3Binary::setBinary(const unsigned char* pBuf, int nLen)\r
194 {\r
195         mpBuf = allocBuffer(nLen);\r
196         memcpy(mpBuf, pBuf, nLen);\r
197 }\r
198 \r
199 \r
200 void CppSQLite3Binary::setEncoded(const unsigned char* pBuf)\r
201 {\r
202         clear();\r
203 \r
204         mnEncodedLen = strlen((const char*)pBuf);\r
205         mnBufferLen = mnEncodedLen + 1; // Allow for NULL terminator\r
206 \r
207         mpBuf = (unsigned char*)malloc(mnBufferLen);\r
208 \r
209         if (!mpBuf)\r
210         {\r
211                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
212                                                                 "Cannot allocate memory",\r
213                                                                 DONT_DELETE_MSG);\r
214         }\r
215 \r
216         memcpy(mpBuf, pBuf, mnBufferLen);\r
217         mbEncoded = true;\r
218 }\r
219 \r
220 \r
221 const unsigned char* CppSQLite3Binary::getEncoded()\r
222 {\r
223         if (!mbEncoded)\r
224         {\r
225                 unsigned char* ptmp = (unsigned char*)malloc(mnBinaryLen);\r
226                 memcpy(ptmp, mpBuf, mnBinaryLen);\r
227                 mnEncodedLen = sqlite3_encode_binary(ptmp, mnBinaryLen, mpBuf);\r
228                 free(ptmp);\r
229                 mbEncoded = true;\r
230         }\r
231 \r
232         return mpBuf;\r
233 }\r
234 \r
235 \r
236 const unsigned char* CppSQLite3Binary::getBinary()\r
237 {\r
238         if (mbEncoded)\r
239         {\r
240                 // in/out buffers can be the same\r
241                 mnBinaryLen = sqlite3_decode_binary(mpBuf, mpBuf);\r
242 \r
243                 if (mnBinaryLen == -1)\r
244                 {\r
245                         throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
246                                                                         "Cannot decode binary",\r
247                                                                         DONT_DELETE_MSG);\r
248                 }\r
249 \r
250                 mbEncoded = false;\r
251         }\r
252 \r
253         return mpBuf;\r
254 }\r
255 \r
256 \r
257 int CppSQLite3Binary::getBinaryLength()\r
258 {\r
259         getBinary();\r
260         return mnBinaryLen;\r
261 }\r
262 \r
263 \r
264 unsigned char* CppSQLite3Binary::allocBuffer(int nLen)\r
265 {\r
266         clear();\r
267 \r
268         // Allow extra space for encoded binary as per comments in\r
269         // SQLite encode.c See bottom of this file for implementation\r
270         // of SQLite functions use 3 instead of 2 just to be sure ;-)\r
271         mnBinaryLen = nLen;\r
272         mnBufferLen = 3 + (257*nLen)/254;\r
273 \r
274         mpBuf = (unsigned char*)malloc(mnBufferLen);\r
275 \r
276         if (!mpBuf)\r
277         {\r
278                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
279                                                                 "Cannot allocate memory",\r
280                                                                 DONT_DELETE_MSG);\r
281         }\r
282 \r
283         mbEncoded = false;\r
284 \r
285         return mpBuf;\r
286 }\r
287 \r
288 \r
289 void CppSQLite3Binary::clear()\r
290 {\r
291         if (mpBuf)\r
292         {\r
293                 mnBinaryLen = 0;\r
294                 mnBufferLen = 0;\r
295                 free(mpBuf);\r
296                 mpBuf = 0;\r
297         }\r
298 }\r
299 \r
300 \r
301 ////////////////////////////////////////////////////////////////////////////////\r
302 \r
303 CppSQLite3Query::CppSQLite3Query()\r
304 {\r
305         mpVM = 0;\r
306         mbEof = true;\r
307         mnCols = 0;\r
308         mbOwnVM = false;\r
309 }\r
310 \r
311 \r
312 CppSQLite3Query::CppSQLite3Query(const CppSQLite3Query& rQuery)\r
313 {\r
314         mpVM = rQuery.mpVM;\r
315         // Only one object can own the VM\r
316         const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;\r
317         mbEof = rQuery.mbEof;\r
318         mnCols = rQuery.mnCols;\r
319         mbOwnVM = rQuery.mbOwnVM;\r
320 }\r
321 \r
322 \r
323 CppSQLite3Query::CppSQLite3Query(sqlite3* pDB,\r
324                                                         sqlite3_stmt* pVM,\r
325                                                         bool bEof,\r
326                                                         bool bOwnVM/*=true*/)\r
327 {\r
328         mpDB = pDB;\r
329         mpVM = pVM;\r
330         mbEof = bEof;\r
331         mnCols = sqlite3_column_count(mpVM);\r
332         mbOwnVM = bOwnVM;\r
333 }\r
334 \r
335 \r
336 CppSQLite3Query::~CppSQLite3Query()\r
337 {\r
338         try\r
339         {\r
340                 finalize();\r
341         }\r
342         catch (...)\r
343         {\r
344         }\r
345 }\r
346 \r
347 \r
348 CppSQLite3Query& CppSQLite3Query::operator=(const CppSQLite3Query& rQuery)\r
349 {\r
350         try\r
351         {\r
352                 finalize();\r
353         }\r
354         catch (...)\r
355         {\r
356         }\r
357         mpVM = rQuery.mpVM;\r
358         // Only one object can own the VM\r
359         const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;\r
360         mbEof = rQuery.mbEof;\r
361         mnCols = rQuery.mnCols;\r
362         mbOwnVM = rQuery.mbOwnVM;\r
363         return *this;\r
364 }\r
365 \r
366 \r
367 int CppSQLite3Query::numFields()\r
368 {\r
369         checkVM();\r
370         return mnCols;\r
371 }\r
372 \r
373 \r
374 const char* CppSQLite3Query::fieldValue(int nField)\r
375 {\r
376         checkVM();\r
377 \r
378         if (nField < 0 || nField > mnCols-1)\r
379         {\r
380                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
381                                                                 "Invalid field index requested",\r
382                                                                 DONT_DELETE_MSG);\r
383         }\r
384 \r
385         return (const char*)sqlite3_column_text(mpVM, nField);\r
386 }\r
387 \r
388 \r
389 const char* CppSQLite3Query::fieldValue(const char* szField)\r
390 {\r
391         int nField = fieldIndex(szField);\r
392         return (const char*)sqlite3_column_text(mpVM, nField);\r
393 }\r
394 \r
395 \r
396 int CppSQLite3Query::getIntField(int nField, int nNullValue/*=0*/)\r
397 {\r
398         if (fieldDataType(nField) == SQLITE_NULL)\r
399         {\r
400                 return nNullValue;\r
401         }\r
402         else\r
403         {\r
404                 return sqlite3_column_int(mpVM, nField);\r
405         }\r
406 }\r
407 \r
408 \r
409 int CppSQLite3Query::getIntField(const char* szField, int nNullValue/*=0*/)\r
410 {\r
411         int nField = fieldIndex(szField);\r
412         return getIntField(nField, nNullValue);\r
413 }\r
414 \r
415 \r
416 double CppSQLite3Query::getFloatField(int nField, double fNullValue/*=0.0*/)\r
417 {\r
418         if (fieldDataType(nField) == SQLITE_NULL)\r
419         {\r
420                 return fNullValue;\r
421         }\r
422         else\r
423         {\r
424                 return sqlite3_column_double(mpVM, nField);\r
425         }\r
426 }\r
427 \r
428 \r
429 double CppSQLite3Query::getFloatField(const char* szField, double fNullValue/*=0.0*/)\r
430 {\r
431         int nField = fieldIndex(szField);\r
432         return getFloatField(nField, fNullValue);\r
433 }\r
434 \r
435 \r
436 const char* CppSQLite3Query::getStringField(int nField, const char* szNullValue/*=""*/)\r
437 {\r
438         if (fieldDataType(nField) == SQLITE_NULL)\r
439         {\r
440                 return szNullValue;\r
441         }\r
442         else\r
443         {\r
444                 return (const char*)sqlite3_column_text(mpVM, nField);\r
445         }\r
446 }\r
447 \r
448 \r
449 const char* CppSQLite3Query::getStringField(const char* szField, const char* szNullValue/*=""*/)\r
450 {\r
451         int nField = fieldIndex(szField);\r
452         return getStringField(nField, szNullValue);\r
453 }\r
454 \r
455 \r
456 const unsigned char* CppSQLite3Query::getBlobField(int nField, int& nLen)\r
457 {\r
458         checkVM();\r
459 \r
460         if (nField < 0 || nField > mnCols-1)\r
461         {\r
462                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
463                                                                 "Invalid field index requested",\r
464                                                                 DONT_DELETE_MSG);\r
465         }\r
466 \r
467         nLen = sqlite3_column_bytes(mpVM, nField);\r
468         return (const unsigned char*)sqlite3_column_blob(mpVM, nField);\r
469 }\r
470 \r
471 \r
472 const unsigned char* CppSQLite3Query::getBlobField(const char* szField, int& nLen)\r
473 {\r
474         int nField = fieldIndex(szField);\r
475         return getBlobField(nField, nLen);\r
476 }\r
477 \r
478 \r
479 bool CppSQLite3Query::fieldIsNull(int nField)\r
480 {\r
481         return (fieldDataType(nField) == SQLITE_NULL);\r
482 }\r
483 \r
484 \r
485 bool CppSQLite3Query::fieldIsNull(const char* szField)\r
486 {\r
487         int nField = fieldIndex(szField);\r
488         return (fieldDataType(nField) == SQLITE_NULL);\r
489 }\r
490 \r
491 \r
492 int CppSQLite3Query::fieldIndex(const char* szField)\r
493 {\r
494         checkVM();\r
495 \r
496         if (szField)\r
497         {\r
498                 for (int nField = 0; nField < mnCols; nField++)\r
499                 {\r
500                         const char* szTemp = sqlite3_column_name(mpVM, nField);\r
501 \r
502                         if (strcmp(szField, szTemp) == 0)\r
503                         {\r
504                                 return nField;\r
505                         }\r
506                 }\r
507         }\r
508 \r
509         throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
510                                                         "Invalid field name requested",\r
511                                                         DONT_DELETE_MSG);\r
512 }\r
513 \r
514 \r
515 const char* CppSQLite3Query::fieldName(int nCol)\r
516 {\r
517         checkVM();\r
518 \r
519         if (nCol < 0 || nCol > mnCols-1)\r
520         {\r
521                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
522                                                                 "Invalid field index requested",\r
523                                                                 DONT_DELETE_MSG);\r
524         }\r
525 \r
526         return sqlite3_column_name(mpVM, nCol);\r
527 }\r
528 \r
529 \r
530 const char* CppSQLite3Query::fieldDeclType(int nCol)\r
531 {\r
532         checkVM();\r
533 \r
534         if (nCol < 0 || nCol > mnCols-1)\r
535         {\r
536                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
537                                                                 "Invalid field index requested",\r
538                                                                 DONT_DELETE_MSG);\r
539         }\r
540 \r
541         return sqlite3_column_decltype(mpVM, nCol);\r
542 }\r
543 \r
544 \r
545 int CppSQLite3Query::fieldDataType(int nCol)\r
546 {\r
547         checkVM();\r
548 \r
549         if (nCol < 0 || nCol > mnCols-1)\r
550         {\r
551                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
552                                                                 "Invalid field index requested",\r
553                                                                 DONT_DELETE_MSG);\r
554         }\r
555 \r
556         return sqlite3_column_type(mpVM, nCol);\r
557 }\r
558 \r
559 \r
560 bool CppSQLite3Query::eof()\r
561 {\r
562         checkVM();\r
563         return mbEof;\r
564 }\r
565 \r
566 \r
567 void CppSQLite3Query::nextRow()\r
568 {\r
569         checkVM();\r
570 \r
571         int nRet = sqlite3_step(mpVM);\r
572 \r
573         if (nRet == SQLITE_DONE)\r
574         {\r
575                 // no rows\r
576                 mbEof = true;\r
577         }\r
578         else if (nRet == SQLITE_ROW)\r
579         {\r
580                 // more rows, nothing to do\r
581         }\r
582         else\r
583         {\r
584                 nRet = sqlite3_finalize(mpVM);\r
585                 mpVM = 0;\r
586                 const char* szError = sqlite3_errmsg(mpDB);\r
587                 throw CppSQLite3Exception(nRet,\r
588                                                                 (char*)szError,\r
589                                                                 DONT_DELETE_MSG);\r
590         }\r
591 }\r
592 \r
593 \r
594 void CppSQLite3Query::finalize()\r
595 {\r
596         if (mpVM && mbOwnVM)\r
597         {\r
598                 int nRet = sqlite3_finalize(mpVM);\r
599                 mpVM = 0;\r
600                 if (nRet != SQLITE_OK)\r
601                 {\r
602                         const char* szError = sqlite3_errmsg(mpDB);\r
603                         throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
604                 }\r
605         }\r
606 }\r
607 \r
608 \r
609 void CppSQLite3Query::checkVM()\r
610 {\r
611         if (mpVM == 0)\r
612         {\r
613                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
614                                                                 "Null Virtual Machine pointer",\r
615                                                                 DONT_DELETE_MSG);\r
616         }\r
617 }\r
618 \r
619 \r
620 ////////////////////////////////////////////////////////////////////////////////\r
621 \r
622 CppSQLite3Table::CppSQLite3Table()\r
623 {\r
624         mpaszResults = 0;\r
625         mnRows = 0;\r
626         mnCols = 0;\r
627         mnCurrentRow = 0;\r
628 }\r
629 \r
630 \r
631 CppSQLite3Table::CppSQLite3Table(const CppSQLite3Table& rTable)\r
632 {\r
633         mpaszResults = rTable.mpaszResults;\r
634         // Only one object can own the results\r
635         const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;\r
636         mnRows = rTable.mnRows;\r
637         mnCols = rTable.mnCols;\r
638         mnCurrentRow = rTable.mnCurrentRow;\r
639 }\r
640 \r
641 \r
642 CppSQLite3Table::CppSQLite3Table(char** paszResults, int nRows, int nCols)\r
643 {\r
644         mpaszResults = paszResults;\r
645         mnRows = nRows;\r
646         mnCols = nCols;\r
647         mnCurrentRow = 0;\r
648 }\r
649 \r
650 \r
651 CppSQLite3Table::~CppSQLite3Table()\r
652 {\r
653         try\r
654         {\r
655                 finalize();\r
656         }\r
657         catch (...)\r
658         {\r
659         }\r
660 }\r
661 \r
662 \r
663 CppSQLite3Table& CppSQLite3Table::operator=(const CppSQLite3Table& rTable)\r
664 {\r
665         try\r
666         {\r
667                 finalize();\r
668         }\r
669         catch (...)\r
670         {\r
671         }\r
672         mpaszResults = rTable.mpaszResults;\r
673         // Only one object can own the results\r
674         const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;\r
675         mnRows = rTable.mnRows;\r
676         mnCols = rTable.mnCols;\r
677         mnCurrentRow = rTable.mnCurrentRow;\r
678         return *this;\r
679 }\r
680 \r
681 \r
682 void CppSQLite3Table::finalize()\r
683 {\r
684         if (mpaszResults)\r
685         {\r
686                 sqlite3_free_table(mpaszResults);\r
687                 mpaszResults = 0;\r
688         }\r
689 }\r
690 \r
691 \r
692 int CppSQLite3Table::numFields()\r
693 {\r
694         checkResults();\r
695         return mnCols;\r
696 }\r
697 \r
698 \r
699 int CppSQLite3Table::numRows()\r
700 {\r
701         checkResults();\r
702         return mnRows;\r
703 }\r
704 \r
705 \r
706 const char* CppSQLite3Table::fieldValue(int nField)\r
707 {\r
708         checkResults();\r
709 \r
710         if (nField < 0 || nField > mnCols-1)\r
711         {\r
712                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
713                                                                 "Invalid field index requested",\r
714                                                                 DONT_DELETE_MSG);\r
715         }\r
716 \r
717         int nIndex = (mnCurrentRow*mnCols) + mnCols + nField;\r
718         return mpaszResults[nIndex];\r
719 }\r
720 \r
721 \r
722 const char* CppSQLite3Table::fieldValue(const char* szField)\r
723 {\r
724         checkResults();\r
725 \r
726         if (szField)\r
727         {\r
728                 for (int nField = 0; nField < mnCols; nField++)\r
729                 {\r
730                         if (strcmp(szField, mpaszResults[nField]) == 0)\r
731                         {\r
732                                 int nIndex = (mnCurrentRow*mnCols) + mnCols + nField;\r
733                                 return mpaszResults[nIndex];\r
734                         }\r
735                 }\r
736         }\r
737 \r
738         throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
739                                                         "Invalid field name requested",\r
740                                                         DONT_DELETE_MSG);\r
741 }\r
742 \r
743 \r
744 int CppSQLite3Table::getIntField(int nField, int nNullValue/*=0*/)\r
745 {\r
746         if (fieldIsNull(nField))\r
747         {\r
748                 return nNullValue;\r
749         }\r
750         else\r
751         {\r
752                 return atoi(fieldValue(nField));\r
753         }\r
754 }\r
755 \r
756 \r
757 int CppSQLite3Table::getIntField(const char* szField, int nNullValue/*=0*/)\r
758 {\r
759         if (fieldIsNull(szField))\r
760         {\r
761                 return nNullValue;\r
762         }\r
763         else\r
764         {\r
765                 return atoi(fieldValue(szField));\r
766         }\r
767 }\r
768 \r
769 \r
770 double CppSQLite3Table::getFloatField(int nField, double fNullValue/*=0.0*/)\r
771 {\r
772         if (fieldIsNull(nField))\r
773         {\r
774                 return fNullValue;\r
775         }\r
776         else\r
777         {\r
778                 return atof(fieldValue(nField));\r
779         }\r
780 }\r
781 \r
782 \r
783 double CppSQLite3Table::getFloatField(const char* szField, double fNullValue/*=0.0*/)\r
784 {\r
785         if (fieldIsNull(szField))\r
786         {\r
787                 return fNullValue;\r
788         }\r
789         else\r
790         {\r
791                 return atof(fieldValue(szField));\r
792         }\r
793 }\r
794 \r
795 \r
796 const char* CppSQLite3Table::getStringField(int nField, const char* szNullValue/*=""*/)\r
797 {\r
798         if (fieldIsNull(nField))\r
799         {\r
800                 return szNullValue;\r
801         }\r
802         else\r
803         {\r
804                 return fieldValue(nField);\r
805         }\r
806 }\r
807 \r
808 \r
809 const char* CppSQLite3Table::getStringField(const char* szField, const char* szNullValue/*=""*/)\r
810 {\r
811         if (fieldIsNull(szField))\r
812         {\r
813                 return szNullValue;\r
814         }\r
815         else\r
816         {\r
817                 return fieldValue(szField);\r
818         }\r
819 }\r
820 \r
821 \r
822 bool CppSQLite3Table::fieldIsNull(int nField)\r
823 {\r
824         checkResults();\r
825         return (fieldValue(nField) == 0);\r
826 }\r
827 \r
828 \r
829 bool CppSQLite3Table::fieldIsNull(const char* szField)\r
830 {\r
831         checkResults();\r
832         return (fieldValue(szField) == 0);\r
833 }\r
834 \r
835 \r
836 const char* CppSQLite3Table::fieldName(int nCol)\r
837 {\r
838         checkResults();\r
839 \r
840         if (nCol < 0 || nCol > mnCols-1)\r
841         {\r
842                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
843                                                                 "Invalid field index requested",\r
844                                                                 DONT_DELETE_MSG);\r
845         }\r
846 \r
847         return mpaszResults[nCol];\r
848 }\r
849 \r
850 \r
851 void CppSQLite3Table::setRow(int nRow)\r
852 {\r
853         checkResults();\r
854 \r
855         if (nRow < 0 || nRow > mnRows-1)\r
856         {\r
857                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
858                                                                 "Invalid row index requested",\r
859                                                                 DONT_DELETE_MSG);\r
860         }\r
861 \r
862         mnCurrentRow = nRow;\r
863 }\r
864 \r
865 \r
866 void CppSQLite3Table::checkResults()\r
867 {\r
868         if (mpaszResults == 0)\r
869         {\r
870                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
871                                                                 "Null Results pointer",\r
872                                                                 DONT_DELETE_MSG);\r
873         }\r
874 }\r
875 \r
876 \r
877 ////////////////////////////////////////////////////////////////////////////////\r
878 \r
879 CppSQLite3Statement::CppSQLite3Statement()\r
880 {\r
881         mpDB = 0;\r
882         mpVM = 0;\r
883 }\r
884 \r
885 \r
886 CppSQLite3Statement::CppSQLite3Statement(const CppSQLite3Statement& rStatement)\r
887 {\r
888         mpDB = rStatement.mpDB;\r
889         mpVM = rStatement.mpVM;\r
890         // Only one object can own VM\r
891         const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0;\r
892 }\r
893 \r
894 \r
895 CppSQLite3Statement::CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM)\r
896 {\r
897         mpDB = pDB;\r
898         mpVM = pVM;\r
899 }\r
900 \r
901 \r
902 CppSQLite3Statement::~CppSQLite3Statement()\r
903 {\r
904         try\r
905         {\r
906                 finalize();\r
907         }\r
908         catch (...)\r
909         {\r
910         }\r
911 }\r
912 \r
913 \r
914 CppSQLite3Statement& CppSQLite3Statement::operator=(const CppSQLite3Statement& rStatement)\r
915 {\r
916         mpDB = rStatement.mpDB;\r
917         mpVM = rStatement.mpVM;\r
918         // Only one object can own VM\r
919         const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0;\r
920         return *this;\r
921 }\r
922 \r
923 \r
924 int CppSQLite3Statement::execDML()\r
925 {\r
926         checkDB();\r
927         checkVM();\r
928 \r
929         const char* szError=0;\r
930 \r
931         int nRet = sqlite3_step(mpVM);\r
932 \r
933         if (nRet == SQLITE_DONE)\r
934         {\r
935                 int nRowsChanged = sqlite3_changes(mpDB);\r
936 \r
937                 nRet = sqlite3_reset(mpVM);\r
938 \r
939                 if (nRet != SQLITE_OK)\r
940                 {\r
941                         szError = sqlite3_errmsg(mpDB);\r
942                         throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
943                 }\r
944 \r
945                 return nRowsChanged;\r
946         }\r
947         else\r
948         {\r
949                 nRet = sqlite3_reset(mpVM);\r
950                 szError = sqlite3_errmsg(mpDB);\r
951                 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
952         }\r
953 }\r
954 \r
955 \r
956 CppSQLite3Query CppSQLite3Statement::execQuery()\r
957 {\r
958         checkDB();\r
959         checkVM();\r
960 \r
961         int nRet = sqlite3_step(mpVM);\r
962 \r
963         if (nRet == SQLITE_DONE)\r
964         {\r
965                 // no rows\r
966                 return CppSQLite3Query(mpDB, mpVM, true/*eof*/, false);\r
967         }\r
968         else if (nRet == SQLITE_ROW)\r
969         {\r
970                 // at least 1 row\r
971                 return CppSQLite3Query(mpDB, mpVM, false/*eof*/, false);\r
972         }\r
973         else\r
974         {\r
975                 nRet = sqlite3_reset(mpVM);\r
976                 const char* szError = sqlite3_errmsg(mpDB);\r
977                 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
978         }\r
979 }\r
980 \r
981 \r
982 void CppSQLite3Statement::bind(int nParam, const char* szValue)\r
983 {\r
984         checkVM();\r
985         int nRes = sqlite3_bind_text(mpVM, nParam, szValue, -1, SQLITE_TRANSIENT);\r
986 \r
987         if (nRes != SQLITE_OK)\r
988         {\r
989                 throw CppSQLite3Exception(nRes,\r
990                                                                 "Error binding string param",\r
991                                                                 DONT_DELETE_MSG);\r
992         }\r
993 }\r
994 \r
995 \r
996 void CppSQLite3Statement::bind(int nParam, const int nValue)\r
997 {\r
998         checkVM();\r
999         int nRes = sqlite3_bind_int(mpVM, nParam, nValue);\r
1000 \r
1001         if (nRes != SQLITE_OK)\r
1002         {\r
1003                 throw CppSQLite3Exception(nRes,\r
1004                                                                 "Error binding int param",\r
1005                                                                 DONT_DELETE_MSG);\r
1006         }\r
1007 }\r
1008 \r
1009 \r
1010 void CppSQLite3Statement::bind(int nParam, const double dValue)\r
1011 {\r
1012         checkVM();\r
1013         int nRes = sqlite3_bind_double(mpVM, nParam, dValue);\r
1014 \r
1015         if (nRes != SQLITE_OK)\r
1016         {\r
1017                 throw CppSQLite3Exception(nRes,\r
1018                                                                 "Error binding double param",\r
1019                                                                 DONT_DELETE_MSG);\r
1020         }\r
1021 }\r
1022 \r
1023 \r
1024 void CppSQLite3Statement::bind(int nParam, const unsigned char* blobValue, int nLen)\r
1025 {\r
1026         checkVM();\r
1027         int nRes = sqlite3_bind_blob(mpVM, nParam,\r
1028                                                                 (const void*)blobValue, nLen, SQLITE_TRANSIENT);\r
1029 \r
1030         if (nRes != SQLITE_OK)\r
1031         {\r
1032                 throw CppSQLite3Exception(nRes,\r
1033                                                                 "Error binding blob param",\r
1034                                                                 DONT_DELETE_MSG);\r
1035         }\r
1036 }\r
1037 \r
1038         \r
1039 void CppSQLite3Statement::bindNull(int nParam)\r
1040 {\r
1041         checkVM();\r
1042         int nRes = sqlite3_bind_null(mpVM, nParam);\r
1043 \r
1044         if (nRes != SQLITE_OK)\r
1045         {\r
1046                 throw CppSQLite3Exception(nRes,\r
1047                                                                 "Error binding NULL param",\r
1048                                                                 DONT_DELETE_MSG);\r
1049         }\r
1050 }\r
1051 \r
1052 \r
1053 void CppSQLite3Statement::reset()\r
1054 {\r
1055         if (mpVM)\r
1056         {\r
1057                 int nRet = sqlite3_reset(mpVM);\r
1058 \r
1059                 if (nRet != SQLITE_OK)\r
1060                 {\r
1061                         const char* szError = sqlite3_errmsg(mpDB);\r
1062                         throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
1063                 }\r
1064         }\r
1065 }\r
1066 \r
1067 \r
1068 void CppSQLite3Statement::finalize()\r
1069 {\r
1070         if (mpVM)\r
1071         {\r
1072                 int nRet = sqlite3_finalize(mpVM);\r
1073                 mpVM = 0;\r
1074 \r
1075                 if (nRet != SQLITE_OK)\r
1076                 {\r
1077                         const char* szError = sqlite3_errmsg(mpDB);\r
1078                         throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
1079                 }\r
1080         }\r
1081 }\r
1082 \r
1083 \r
1084 void CppSQLite3Statement::checkDB()\r
1085 {\r
1086         if (mpDB == 0)\r
1087         {\r
1088                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
1089                                                                 "Database not open",\r
1090                                                                 DONT_DELETE_MSG);\r
1091         }\r
1092 }\r
1093 \r
1094 \r
1095 void CppSQLite3Statement::checkVM()\r
1096 {\r
1097         if (mpVM == 0)\r
1098         {\r
1099                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
1100                                                                 "Null Virtual Machine pointer",\r
1101                                                                 DONT_DELETE_MSG);\r
1102         }\r
1103 }\r
1104 \r
1105 \r
1106 ////////////////////////////////////////////////////////////////////////////////\r
1107 \r
1108 CppSQLite3DB::CppSQLite3DB()\r
1109 {\r
1110         mpDB = 0;\r
1111         mnBusyTimeoutMs = 60000; // 60 seconds\r
1112 }\r
1113 \r
1114 \r
1115 CppSQLite3DB::CppSQLite3DB(const CppSQLite3DB& db)\r
1116 {\r
1117         mpDB = db.mpDB;\r
1118         mnBusyTimeoutMs = 60000; // 60 seconds\r
1119 }\r
1120 \r
1121 \r
1122 CppSQLite3DB::~CppSQLite3DB()\r
1123 {\r
1124         close();\r
1125 }\r
1126 \r
1127 \r
1128 CppSQLite3DB& CppSQLite3DB::operator=(const CppSQLite3DB& db)\r
1129 {\r
1130         mpDB = db.mpDB;\r
1131         mnBusyTimeoutMs = 60000; // 60 seconds\r
1132         return *this;\r
1133 }\r
1134 \r
1135 \r
1136 void CppSQLite3DB::open(const char* szFile)\r
1137 {\r
1138         int nRet = sqlite3_open(szFile, &mpDB);\r
1139 \r
1140         if (nRet != SQLITE_OK)\r
1141         {\r
1142                 const char* szError = sqlite3_errmsg(mpDB);\r
1143                 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
1144         }\r
1145 \r
1146         setBusyTimeout(mnBusyTimeoutMs);\r
1147 }\r
1148 \r
1149 \r
1150 void CppSQLite3DB::close()\r
1151 {\r
1152         if (mpDB)\r
1153         {\r
1154                 sqlite3_close(mpDB);\r
1155                 mpDB = 0;\r
1156         }\r
1157 }\r
1158 \r
1159 \r
1160 CppSQLite3Statement CppSQLite3DB::compileStatement(const char* szSQL)\r
1161 {\r
1162         checkDB();\r
1163 \r
1164         sqlite3_stmt* pVM = compile(szSQL);\r
1165         return CppSQLite3Statement(mpDB, pVM);\r
1166 }\r
1167 \r
1168 \r
1169 bool CppSQLite3DB::tableExists(const char* szTable)\r
1170 {\r
1171         char szSQL[128];\r
1172         sprintf(szSQL,\r
1173                         "select count(*) from sqlite_master where type='table' and name='%s'",\r
1174                         szTable);\r
1175         int nRet = execScalar(szSQL);\r
1176         return (nRet > 0);\r
1177 }\r
1178 \r
1179 \r
1180 int CppSQLite3DB::execDML(const char* szSQL)\r
1181 {\r
1182         checkDB();\r
1183 \r
1184         char* szError=0;\r
1185 \r
1186         int nRet = sqlite3_exec(mpDB, szSQL, 0, 0, &szError);\r
1187 \r
1188         if (nRet == SQLITE_OK)\r
1189         {\r
1190                 return sqlite3_changes(mpDB);\r
1191         }\r
1192         else\r
1193         {\r
1194                 throw CppSQLite3Exception(nRet, szError);\r
1195         }\r
1196 }\r
1197 \r
1198 \r
1199 CppSQLite3Query CppSQLite3DB::execQuery(const char* szSQL)\r
1200 {\r
1201         checkDB();\r
1202 \r
1203         sqlite3_stmt* pVM = compile(szSQL);\r
1204 \r
1205         int nRet = sqlite3_step(pVM);\r
1206 \r
1207         if (nRet == SQLITE_DONE)\r
1208         {\r
1209                 // no rows\r
1210                 return CppSQLite3Query(mpDB, pVM, true/*eof*/);\r
1211         }\r
1212         else if (nRet == SQLITE_ROW)\r
1213         {\r
1214                 // at least 1 row\r
1215                 return CppSQLite3Query(mpDB, pVM, false/*eof*/);\r
1216         }\r
1217         else\r
1218         {\r
1219                 nRet = sqlite3_finalize(pVM);\r
1220                 const char* szError= sqlite3_errmsg(mpDB);\r
1221                 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
1222         }\r
1223 }\r
1224 \r
1225 \r
1226 int CppSQLite3DB::execScalar(const char* szSQL)\r
1227 {\r
1228         CppSQLite3Query q = execQuery(szSQL);\r
1229 \r
1230         if (q.eof() || q.numFields() < 1)\r
1231         {\r
1232                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
1233                                                                 "Invalid scalar query",\r
1234                                                                 DONT_DELETE_MSG);\r
1235         }\r
1236 \r
1237         return atoi(q.fieldValue(0));\r
1238 }\r
1239 \r
1240 \r
1241 CppSQLite3Table CppSQLite3DB::getTable(const char* szSQL)\r
1242 {\r
1243         checkDB();\r
1244 \r
1245         char* szError=0;\r
1246         char** paszResults=0;\r
1247         int nRet;\r
1248         int nRows(0);\r
1249         int nCols(0);\r
1250 \r
1251         nRet = sqlite3_get_table(mpDB, szSQL, &paszResults, &nRows, &nCols, &szError);\r
1252 \r
1253         if (nRet == SQLITE_OK)\r
1254         {\r
1255                 return CppSQLite3Table(paszResults, nRows, nCols);\r
1256         }\r
1257         else\r
1258         {\r
1259                 throw CppSQLite3Exception(nRet, szError);\r
1260         }\r
1261 }\r
1262 \r
1263 \r
1264 sqlite_int64 CppSQLite3DB::lastRowId()\r
1265 {\r
1266         return sqlite3_last_insert_rowid(mpDB);\r
1267 }\r
1268 \r
1269 \r
1270 void CppSQLite3DB::setBusyTimeout(int nMillisecs)\r
1271 {\r
1272         mnBusyTimeoutMs = nMillisecs;\r
1273         sqlite3_busy_timeout(mpDB, mnBusyTimeoutMs);\r
1274 }\r
1275 \r
1276 \r
1277 void CppSQLite3DB::checkDB()\r
1278 {\r
1279         if (!mpDB)\r
1280         {\r
1281                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
1282                                                                 "Database not open",\r
1283                                                                 DONT_DELETE_MSG);\r
1284         }\r
1285 }\r
1286 \r
1287 \r
1288 sqlite3_stmt* CppSQLite3DB::compile(const char* szSQL)\r
1289 {\r
1290         checkDB();\r
1291 \r
1292         char* szError=0;\r
1293         const char* szTail=0;\r
1294         sqlite3_stmt* pVM;\r
1295 \r
1296         int nRet = sqlite3_prepare(mpDB, szSQL, -1, &pVM, &szTail);\r
1297 \r
1298         if (nRet != SQLITE_OK)\r
1299         {\r
1300                 throw CppSQLite3Exception(nRet, szError);\r
1301         }\r
1302 \r
1303         return pVM;\r
1304 }\r
1305 \r
1306 \r
1307 ////////////////////////////////////////////////////////////////////////////////\r
1308 // SQLite encode.c reproduced here, containing implementation notes and source\r
1309 // for sqlite3_encode_binary() and sqlite3_decode_binary() \r
1310 ////////////////////////////////////////////////////////////////////////////////\r
1311 \r
1312 /*\r
1313 ** 2002 April 25\r
1314 **\r
1315 ** The author disclaims copyright to this source code.  In place of\r
1316 ** a legal notice, here is a blessing:\r
1317 **\r
1318 **    May you do good and not evil.\r
1319 **    May you find forgiveness for yourself and forgive others.\r
1320 **    May you share freely, never taking more than you give.\r
1321 **\r
1322 *************************************************************************\r
1323 ** This file contains helper routines used to translate binary data into\r
1324 ** a null-terminated string (suitable for use in SQLite) and back again.\r
1325 ** These are convenience routines for use by people who want to store binary\r
1326 ** data in an SQLite database.  The code in this file is not used by any other\r
1327 ** part of the SQLite library.\r
1328 **\r
1329 ** $Id: CppSQLite3.cpp,v 1.2 2008/12/15 12:54:44 guigues Exp $\r
1330 */\r
1331 \r
1332 /*\r
1333 ** How This Encoder Works\r
1334 **\r
1335 ** The output is allowed to contain any character except 0x27 (') and\r
1336 ** 0x00.  This is accomplished by using an escape character to encode\r
1337 ** 0x27 and 0x00 as a two-byte sequence.  The escape character is always\r
1338 ** 0x01.  An 0x00 is encoded as the two byte sequence 0x01 0x01.  The\r
1339 ** 0x27 character is encoded as the two byte sequence 0x01 0x03.  Finally,\r
1340 ** the escape character itself is encoded as the two-character sequence\r
1341 ** 0x01 0x02.\r
1342 **\r
1343 ** To summarize, the encoder works by using an escape sequences as follows:\r
1344 **\r
1345 **       0x00  ->  0x01 0x01\r
1346 **       0x01  ->  0x01 0x02\r
1347 **       0x27  ->  0x01 0x03\r
1348 **\r
1349 ** If that were all the encoder did, it would work, but in certain cases\r
1350 ** it could double the size of the encoded string.  For example, to\r
1351 ** encode a string of 100 0x27 characters would require 100 instances of\r
1352 ** the 0x01 0x03 escape sequence resulting in a 200-character output.\r
1353 ** We would prefer to keep the size of the encoded string smaller than\r
1354 ** this.\r
1355 **\r
1356 ** To minimize the encoding size, we first add a fixed offset value to each \r
1357 ** byte in the sequence.  The addition is modulo 256.  (That is to say, if\r
1358 ** the sum of the original character value and the offset exceeds 256, then\r
1359 ** the higher order bits are truncated.)  The offset is chosen to minimize\r
1360 ** the number of characters in the string that need to be escaped.  For\r
1361 ** example, in the case above where the string was composed of 100 0x27\r
1362 ** characters, the offset might be 0x01.  Each of the 0x27 characters would\r
1363 ** then be converted into an 0x28 character which would not need to be\r
1364 ** escaped at all and so the 100 character input string would be converted\r
1365 ** into just 100 characters of output.  Actually 101 characters of output - \r
1366 ** we have to record the offset used as the first byte in the sequence so\r
1367 ** that the string can be decoded.  Since the offset value is stored as\r
1368 ** part of the output string and the output string is not allowed to contain\r
1369 ** characters 0x00 or 0x27, the offset cannot be 0x00 or 0x27.\r
1370 **\r
1371 ** Here, then, are the encoding steps:\r
1372 **\r
1373 **     (1)   Choose an offset value and make it the first character of\r
1374 **           output.\r
1375 **\r
1376 **     (2)   Copy each input character into the output buffer, one by\r
1377 **           one, adding the offset value as you copy.\r
1378 **\r
1379 **     (3)   If the value of an input character plus offset is 0x00, replace\r
1380 **           that one character by the two-character sequence 0x01 0x01.\r
1381 **           If the sum is 0x01, replace it with 0x01 0x02.  If the sum\r
1382 **           is 0x27, replace it with 0x01 0x03.\r
1383 **\r
1384 **     (4)   Put a 0x00 terminator at the end of the output.\r
1385 **\r
1386 ** Decoding is obvious:\r
1387 **\r
1388 **     (5)   Copy encoded characters except the first into the decode \r
1389 **           buffer.  Set the first encoded character aside for use as\r
1390 **           the offset in step 7 below.\r
1391 **\r
1392 **     (6)   Convert each 0x01 0x01 sequence into a single character 0x00.\r
1393 **           Convert 0x01 0x02 into 0x01.  Convert 0x01 0x03 into 0x27.\r
1394 **\r
1395 **     (7)   Subtract the offset value that was the first character of\r
1396 **           the encoded buffer from all characters in the output buffer.\r
1397 **\r
1398 ** The only tricky part is step (1) - how to compute an offset value to\r
1399 ** minimize the size of the output buffer.  This is accomplished by testing\r
1400 ** all offset values and picking the one that results in the fewest number\r
1401 ** of escapes.  To do that, we first scan the entire input and count the\r
1402 ** number of occurances of each character value in the input.  Suppose\r
1403 ** the number of 0x00 characters is N(0), the number of occurances of 0x01\r
1404 ** is N(1), and so forth up to the number of occurances of 0xff is N(255).\r
1405 ** An offset of 0 is not allowed so we don't have to test it.  The number\r
1406 ** of escapes required for an offset of 1 is N(1)+N(2)+N(40).  The number\r
1407 ** of escapes required for an offset of 2 is N(2)+N(3)+N(41).  And so forth.\r
1408 ** In this way we find the offset that gives the minimum number of escapes,\r
1409 ** and thus minimizes the length of the output string.\r
1410 */\r
1411 \r
1412 /*\r
1413 ** Encode a binary buffer "in" of size n bytes so that it contains\r
1414 ** no instances of characters '\'' or '\000'.  The output is \r
1415 ** null-terminated and can be used as a string value in an INSERT\r
1416 ** or UPDATE statement.  Use sqlite3_decode_binary() to convert the\r
1417 ** string back into its original binary.\r
1418 **\r
1419 ** The result is written into a preallocated output buffer "out".\r
1420 ** "out" must be able to hold at least 2 +(257*n)/254 bytes.\r
1421 ** In other words, the output will be expanded by as much as 3\r
1422 ** bytes for every 254 bytes of input plus 2 bytes of fixed overhead.\r
1423 ** (This is approximately 2 + 1.0118*n or about a 1.2% size increase.)\r
1424 **\r
1425 ** The return value is the number of characters in the encoded\r
1426 ** string, excluding the "\000" terminator.\r
1427 */\r
1428 int sqlite3_encode_binary(const unsigned char *in, int n, unsigned char *out){\r
1429   int i, j, e, m;\r
1430   int cnt[256];\r
1431   if( n<=0 ){\r
1432     out[0] = 'x';\r
1433     out[1] = 0;\r
1434     return 1;\r
1435   }\r
1436   memset(cnt, 0, sizeof(cnt));\r
1437   for(i=n-1; i>=0; i--){ cnt[in[i]]++; }\r
1438   m = n;\r
1439   for(i=1; i<256; i++){\r
1440     int sum;\r
1441     if( i=='\'' ) continue;\r
1442     sum = cnt[i] + cnt[(i+1)&0xff] + cnt[(i+'\'')&0xff];\r
1443     if( sum<m ){\r
1444       m = sum;\r
1445       e = i;\r
1446       if( m==0 ) break;\r
1447     }\r
1448   }\r
1449   out[0] = e;\r
1450   j = 1;\r
1451   for(i=0; i<n; i++){\r
1452     int c = (in[i] - e)&0xff;\r
1453     if( c==0 ){\r
1454       out[j++] = 1;\r
1455       out[j++] = 1;\r
1456     }else if( c==1 ){\r
1457       out[j++] = 1;\r
1458       out[j++] = 2;\r
1459     }else if( c=='\'' ){\r
1460       out[j++] = 1;\r
1461       out[j++] = 3;\r
1462     }else{\r
1463       out[j++] = c;\r
1464     }\r
1465   }\r
1466   out[j] = 0;\r
1467   return j;\r
1468 }\r
1469 \r
1470 /*\r
1471 ** Decode the string "in" into binary data and write it into "out".\r
1472 ** This routine reverses the encoding created by sqlite3_encode_binary().\r
1473 ** The output will always be a few bytes less than the input.  The number\r
1474 ** of bytes of output is returned.  If the input is not a well-formed\r
1475 ** encoding, -1 is returned.\r
1476 **\r
1477 ** The "in" and "out" parameters may point to the same buffer in order\r
1478 ** to decode a string in place.\r
1479 */\r
1480 int sqlite3_decode_binary(const unsigned char *in, unsigned char *out){\r
1481   int i, c, e;\r
1482   e = *(in++);\r
1483   i = 0;\r
1484   while( (c = *(in++))!=0 ){\r
1485     if( c==1 ){\r
1486       c = *(in++);\r
1487       if( c==1 ){\r
1488         c = 0;\r
1489       }else if( c==2 ){\r
1490         c = 1;\r
1491       }else if( c==3 ){\r
1492         c = '\'';\r
1493       }else{\r
1494         return -1;\r
1495       }\r
1496     }\r
1497     out[i++] = (c + e)&0xff;\r
1498   }\r
1499   return i;\r
1500 }\r