mirror of
https://github.com/InoriRus/Kyty.git
synced 2026-08-28 13:16:40 +00:00
Initial commit
This commit is contained in:
+3082
File diff suppressed because it is too large
Load Diff
+1695
File diff suppressed because it is too large
Load Diff
+197
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
** Name: rijndael.h
|
||||
** Purpose: Header file for the Rijndael cipher
|
||||
** Author: Ulrich Telle
|
||||
** Created: 2006-12-06
|
||||
** Copyright: (c) 2006-2018 Ulrich Telle
|
||||
** License: LGPL-3.0+ WITH WxWindows-exception-3.1
|
||||
**
|
||||
** Adjustments were made to make this code work with the wxSQLite3's
|
||||
** SQLite encryption extension.
|
||||
** The original code is public domain (see comments below).
|
||||
*/
|
||||
|
||||
/*
|
||||
/// \file rijndael.h Interface of the Rijndael cipher
|
||||
*/
|
||||
|
||||
#ifndef _RIJNDAEL_H_
|
||||
#define _RIJNDAEL_H_
|
||||
|
||||
/*
|
||||
// File : rijndael.h
|
||||
// Creation date : Sun Nov 5 2000 03:21:05 CEST
|
||||
// Author : Szymon Stefanek (stefanek@tin.it)
|
||||
//
|
||||
// Another implementation of the Rijndael cipher.
|
||||
// This is intended to be an easily usable library file.
|
||||
// This code is public domain.
|
||||
// Based on the Vincent Rijmen and K.U.Leuven implementation 2.4.
|
||||
//
|
||||
// Original Copyright notice:
|
||||
//
|
||||
// rijndael-alg-fst.c v2.4 April '2000
|
||||
// rijndael-alg-fst.h
|
||||
// rijndael-api-fst.c
|
||||
// rijndael-api-fst.h
|
||||
//
|
||||
// Optimised ANSI C code
|
||||
//
|
||||
// authors: v1.0: Antoon Bosselaers
|
||||
// v2.0: Vincent Rijmen, K.U.Leuven
|
||||
// v2.3: Paulo Barreto
|
||||
// v2.4: Vincent Rijmen, K.U.Leuven
|
||||
//
|
||||
// This code is placed in the public domain.
|
||||
//
|
||||
|
||||
//
|
||||
// This implementation works on 128 , 192 , 256 bit keys
|
||||
// and on 128 bit blocks
|
||||
//
|
||||
|
||||
//
|
||||
// Example of usage:
|
||||
//
|
||||
// // Input data
|
||||
// unsigned char key[32]; // The key
|
||||
// initializeYour256BitKey(); // Obviously initialized with sth
|
||||
// const unsigned char * plainText = getYourPlainText(); // Your plain text
|
||||
// int plainTextLen = strlen(plainText); // Plain text length
|
||||
//
|
||||
// // Encrypting
|
||||
// Rijndael rin;
|
||||
// unsigned char output[plainTextLen + 16];
|
||||
//
|
||||
// rin.init(Rijndael::CBC,Rijndael::Encrypt,key,Rijndael::Key32Bytes);
|
||||
// // It is a good idea to check the error code
|
||||
// int len = rin.padEncrypt(plainText,len,output);
|
||||
// if(len >= 0)useYourEncryptedText();
|
||||
// else encryptError(len);
|
||||
//
|
||||
// // Decrypting: we can reuse the same object
|
||||
// unsigned char output2[len];
|
||||
// rin.init(Rijndael::CBC,Rijndael::Decrypt,key,Rijndael::Key32Bytes));
|
||||
// len = rin.padDecrypt(output,len,output2);
|
||||
// if(len >= 0)useYourDecryptedText();
|
||||
// else decryptError(len);
|
||||
//
|
||||
*/
|
||||
|
||||
#define _MAX_KEY_COLUMNS (256/32)
|
||||
#define _MAX_ROUNDS 14
|
||||
#define MAX_IV_SIZE 16
|
||||
|
||||
/* We assume that unsigned int is 32 bits long.... */
|
||||
typedef unsigned char UINT8;
|
||||
typedef unsigned int UINT32;
|
||||
typedef unsigned short UINT16;
|
||||
|
||||
/* Error codes */
|
||||
#define RIJNDAEL_SUCCESS 0
|
||||
#define RIJNDAEL_UNSUPPORTED_MODE -1
|
||||
#define RIJNDAEL_UNSUPPORTED_DIRECTION -2
|
||||
#define RIJNDAEL_UNSUPPORTED_KEY_LENGTH -3
|
||||
#define RIJNDAEL_BAD_KEY -4
|
||||
#define RIJNDAEL_NOT_INITIALIZED -5
|
||||
#define RIJNDAEL_BAD_DIRECTION -6
|
||||
#define RIJNDAEL_CORRUPTED_DATA -7
|
||||
|
||||
#define RIJNDAEL_Direction_Encrypt 0
|
||||
#define RIJNDAEL_Direction_Decrypt 1
|
||||
|
||||
#define RIJNDAEL_Direction_Mode_ECB 0
|
||||
#define RIJNDAEL_Direction_Mode_CBC 1
|
||||
#define RIJNDAEL_Direction_Mode_CFB1 2
|
||||
|
||||
#define RIJNDAEL_Direction_KeyLength_Key16Bytes 0
|
||||
#define RIJNDAEL_Direction_KeyLength_Key24Bytes 1
|
||||
#define RIJNDAEL_Direction_KeyLength_Key32Bytes 2
|
||||
|
||||
#define RIJNDAEL_State_Valid 0
|
||||
#define RIJNDAEL_State_Invalid 1
|
||||
|
||||
/*
|
||||
/// Class implementing the Rijndael cipher. (For internal use only)
|
||||
*/
|
||||
|
||||
typedef struct _Rijndael
|
||||
{
|
||||
int m_state;
|
||||
int m_mode;
|
||||
int m_direction;
|
||||
UINT8 m_initVector[MAX_IV_SIZE];
|
||||
UINT32 m_uRounds;
|
||||
UINT8 m_expandedKey[_MAX_ROUNDS+1][4][4];
|
||||
} Rijndael;
|
||||
|
||||
void RijndaelCreate(Rijndael* rijndael);
|
||||
|
||||
/*
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// init(): Initializes the crypt session
|
||||
// Returns RIJNDAEL_SUCCESS or an error code
|
||||
// mode : Rijndael::ECB, Rijndael::CBC or Rijndael::CFB1
|
||||
// You have to use the same mode for encrypting and decrypting
|
||||
// dir : Rijndael::Encrypt or Rijndael::Decrypt
|
||||
// A cipher instance works only in one direction
|
||||
// (Well , it could be easily modified to work in both
|
||||
// directions with a single init() call, but it looks
|
||||
// useless to me...anyway , it is a matter of generating
|
||||
// two expanded keys)
|
||||
// key : array of unsigned octets , it can be 16 , 24 or 32 bytes long
|
||||
// this CAN be binary data (it is not expected to be null terminated)
|
||||
// keyLen : Rijndael::Key16Bytes , Rijndael::Key24Bytes or Rijndael::Key32Bytes
|
||||
// initVector: initialization vector, you will usually use 0 here
|
||||
*/
|
||||
/* BEGIN KYTY */
|
||||
/*int RijndaelInit(Rijndael* rijndael, int mode, int dir, UINT8* key, int keyLen, UINT8* initVector);*/
|
||||
int RijndaelInit(Rijndael* rijndael, int mode, int dir, UINT8* key, int keyLen, UINT8* initVector, int fyty);
|
||||
/* END KYTY */
|
||||
|
||||
/*
|
||||
// Encrypts the input array (can be binary data)
|
||||
// The input array length must be a multiple of 16 bytes, the remaining part
|
||||
// is DISCARDED.
|
||||
// so it actually encrypts inputLen / 128 blocks of input and puts it in outBuffer
|
||||
// Input len is in BITS!
|
||||
// outBuffer must be at least inputLen / 8 bytes long.
|
||||
// Returns the encrypted buffer length in BITS or an error code < 0 in case of error
|
||||
*/
|
||||
int RijndaelBlockEncrypt(Rijndael* rijndael, UINT8 *input, int inputLen, UINT8 *outBuffer);
|
||||
|
||||
/*
|
||||
// Encrypts the input array (can be binary data)
|
||||
// The input array can be any length , it is automatically padded on a 16 byte boundary.
|
||||
// Input len is in BYTES!
|
||||
// outBuffer must be at least (inputLen + 16) bytes long
|
||||
// Returns the encrypted buffer length in BYTES or an error code < 0 in case of error
|
||||
*/
|
||||
int RijndaelPadEncrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8 *outBuffer);
|
||||
|
||||
/*
|
||||
// Decrypts the input vector
|
||||
// Input len is in BITS!
|
||||
// outBuffer must be at least inputLen / 8 bytes long
|
||||
// Returns the decrypted buffer length in BITS and an error code < 0 in case of error
|
||||
*/
|
||||
int RijndaelBlockDecrypt(Rijndael* rijndael, UINT8 *input, int inputLen, UINT8 *outBuffer);
|
||||
|
||||
/*
|
||||
// Decrypts the input vector
|
||||
// Input len is in BYTES!
|
||||
// outBuffer must be at least inputLen bytes long
|
||||
// Returns the decrypted buffer length in BYTES and an error code < 0 in case of error
|
||||
*/
|
||||
int RijndaelPadDecrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8 *outBuffer);
|
||||
|
||||
void RijndaelInvalidate(Rijndael* rijndael);
|
||||
void RijndaelKeySched(Rijndael* rijndael, UINT8 key[_MAX_KEY_COLUMNS][4]);
|
||||
void RijndaelKeyEncToDec(Rijndael* rijndael);
|
||||
void RijndaelEncrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16]);
|
||||
void RijndaelDecrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16]);
|
||||
|
||||
#endif /* _RIJNDAEL_H_ */
|
||||
+382
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
** Name: sqlite3secure.c
|
||||
** Purpose: Amalgamation of the wxSQLite3 encryption extension for SQLite
|
||||
** Author: Ulrich Telle
|
||||
** Created: 2006-12-06
|
||||
** Copyright: (c) 2006-2019 Ulrich Telle
|
||||
** License: LGPL-3.0+ WITH WxWindows-exception-3.1
|
||||
*/
|
||||
|
||||
/* BEGIN KYTY */
|
||||
#include "sqlite3_options.h"
|
||||
/* END KYTY */
|
||||
|
||||
/*
|
||||
** Enable SQLite debug assertions if requested
|
||||
*/
|
||||
#ifndef SQLITE_DEBUG
|
||||
#if defined(SQLITE_ENABLE_DEBUG) && (SQLITE_ENABLE_DEBUG == 1)
|
||||
#define SQLITE_DEBUG 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** To enable the extension functions define SQLITE_ENABLE_EXTFUNC on compiling this module
|
||||
** To enable the reading CSV files define SQLITE_ENABLE_CSV on compiling this module
|
||||
** To enable the SHA3 support define SQLITE_ENABLE_SHA3 on compiling this module
|
||||
** To enable the CARRAY support define SQLITE_ENABLE_CARRAY on compiling this module
|
||||
** To enable the FILEIO support define SQLITE_ENABLE_FILEIO on compiling this module
|
||||
** To enable the SERIES support define SQLITE_ENABLE_SERIES on compiling this module
|
||||
*/
|
||||
#if defined(SQLITE_HAS_CODEC) || \
|
||||
defined(SQLITE_ENABLE_EXTFUNC) || \
|
||||
defined(SQLITE_ENABLE_CSV) || \
|
||||
defined(SQLITE_ENABLE_SHA3) || \
|
||||
defined(SQLITE_ENABLE_CARRAY) || \
|
||||
defined(SQLITE_ENABLE_FILEIO) || \
|
||||
defined(SQLITE_ENABLE_SERIES)
|
||||
#define sqlite3_open sqlite3_open_internal
|
||||
#define sqlite3_open16 sqlite3_open16_internal
|
||||
#define sqlite3_open_v2 sqlite3_open_v2_internal
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Enable the user authentication feature
|
||||
*/
|
||||
#ifndef SQLITE_USER_AUTHENTICATION
|
||||
#define SQLITE_USER_AUTHENTICATION 1
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
#include <windows.h>
|
||||
|
||||
/* SQLite functions only needed on Win32 */
|
||||
extern void sqlite3_win32_write_debug(const char *, int);
|
||||
extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
|
||||
extern char *sqlite3_win32_mbcs_to_utf8(const char *);
|
||||
extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int);
|
||||
extern char *sqlite3_win32_utf8_to_mbcs(const char *);
|
||||
extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int);
|
||||
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *);
|
||||
#endif
|
||||
|
||||
#include "sqlite3.c"
|
||||
|
||||
/*
|
||||
** Crypto algorithms
|
||||
*/
|
||||
#include "md5.c"
|
||||
#include "sha1.c"
|
||||
#include "sha2.c"
|
||||
#include "fastpbkdf2.c"
|
||||
|
||||
/* Prototypes for several crypto functions to make pedantic compilers happy */
|
||||
void chacha20_xor(unsigned char* data, size_t n, const unsigned char key[32], const unsigned char nonce[12], uint32_t counter);
|
||||
void poly1305(const unsigned char* msg, size_t n, const unsigned char key[32], unsigned char tag[16]);
|
||||
int poly1305_tagcmp(const unsigned char tag1[16], const unsigned char tag2[16]);
|
||||
void chacha20_rng(void* out, size_t n);
|
||||
|
||||
#include "chacha20poly1305.c"
|
||||
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
#include "sqlite3userauth.h"
|
||||
#include "userauth.c"
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_HAS_CODEC) || \
|
||||
defined(SQLITE_ENABLE_EXTFUNC) || \
|
||||
defined(SQLITE_ENABLE_CSV) || \
|
||||
defined(SQLITE_ENABLE_SHA3) || \
|
||||
defined(SQLITE_ENABLE_CARRAY) || \
|
||||
defined(SQLITE_ENABLE_FILEIO) || \
|
||||
defined(SQLITE_ENABLE_SERIES)
|
||||
#undef sqlite3_open
|
||||
#undef sqlite3_open16
|
||||
#undef sqlite3_open_v2
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_DISKIO
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
|
||||
/*
|
||||
** Get the codec argument for this pager
|
||||
*/
|
||||
static void*
|
||||
mySqlite3PagerGetCodec(Pager *pPager)
|
||||
{
|
||||
#if (SQLITE_VERSION_NUMBER >= 3006016)
|
||||
return sqlite3PagerGetCodec(pPager);
|
||||
#else
|
||||
return (pPager->xCodec) ? pPager->pCodecArg : NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the codec argument for this pager
|
||||
*/
|
||||
static void
|
||||
mySqlite3PagerSetCodec(Pager *pPager,
|
||||
void *(*xCodec)(void*,void*,Pgno,int),
|
||||
void (*xCodecSizeChng)(void*,int,int),
|
||||
void (*xCodecFree)(void*),
|
||||
void *pCodec)
|
||||
{
|
||||
sqlite3PagerSetCodec(pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec);
|
||||
}
|
||||
|
||||
/*
|
||||
** Declare function prototype for registering the codec extension functions
|
||||
*/
|
||||
static int
|
||||
registerCodecExtensions(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
||||
|
||||
/*
|
||||
** Codec implementation
|
||||
*/
|
||||
|
||||
/* BEGIN KYTY */
|
||||
/*#include "rijndael.c"*/
|
||||
/*#include "codec.c"*/
|
||||
#include "altered_rijndael.c"
|
||||
#include "altered_codec.c"
|
||||
/* END KYTY */
|
||||
#include "codecext.c"
|
||||
|
||||
#endif /* SQLITE_HAS_CODEC */
|
||||
#endif /* SQLITE_OMIT_DISKIO */
|
||||
|
||||
/*
|
||||
** Extension functions
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_EXTFUNC
|
||||
/* Prototype for initialization function of EXTENSIONFUNCTIONS extension */
|
||||
int RegisterExtensionFunctions(sqlite3 *db);
|
||||
#include "extensionfunctions.c"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** CSV import
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_CSV
|
||||
/* Prototype for initialization function of CSV extension */
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_csv_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
||||
#include "csv.c"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** SHA3
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_SHA3
|
||||
/* Prototype for initialization function of SHA3 extension */
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_shathree_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
||||
#include "shathree.c"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** CARRAY
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_CARRAY
|
||||
/* Prototype for initialization function of CARRAY extension */
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_carray_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
||||
#include "carray.c"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** FILEIO
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_FILEIO
|
||||
/* Prototype for initialization function of FILEIO extension */
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_fileio_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
||||
|
||||
/* MinGW specifics */
|
||||
#if (!defined(_WIN32) && !defined(WIN32)) || defined(__MINGW32__)
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
# if defined(__MINGW32__)
|
||||
# define DIRENT dirent
|
||||
# ifndef S_ISLNK
|
||||
# define S_ISLNK(mode) (0)
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "test_windirent.c"
|
||||
#include "fileio.c"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** SERIES
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_SERIES
|
||||
/* Prototype for initialization function of SERIES extension */
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_series_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
||||
#include "series.c"
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_HAS_CODEC) || \
|
||||
defined(SQLITE_ENABLE_EXTFUNC) || \
|
||||
defined(SQLITE_ENABLE_CSV) || \
|
||||
defined(SQLITE_ENABLE_SHA3) || \
|
||||
defined(SQLITE_ENABLE_CARRAY) || \
|
||||
defined(SQLITE_ENABLE_FILEIO) || \
|
||||
defined(SQLITE_ENABLE_SERIES)
|
||||
|
||||
static int
|
||||
registerCodecExtensions(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
CodecParameter* codecParameterTable = NULL;
|
||||
|
||||
if (sqlite3FindFunction(db, "wxsqlite3_config_table", 0, SQLITE_UTF8, 0) != NULL)
|
||||
{
|
||||
/* Return if codec extension functions are already defined */
|
||||
return rc;
|
||||
}
|
||||
|
||||
codecParameterTable = CloneCodecParameterTable();
|
||||
rc = (codecParameterTable != NULL) ? SQLITE_OK : SQLITE_NOMEM;
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_create_function_v2(db, "wxsqlite3_config_table", 0, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
codecParameterTable, wxsqlite3_config_table, 0, 0, (void(*)(void*)) FreeCodecParameterTable);
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_create_function(db, "wxsqlite3_config", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
codecParameterTable, wxsqlite3_config_params, 0, 0);
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_create_function(db, "wxsqlite3_config", 2, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
codecParameterTable, wxsqlite3_config_params, 0, 0);
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_create_function(db, "wxsqlite3_config", 3, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
codecParameterTable, wxsqlite3_config_params, 0, 0);
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_create_function(db, "wxsqlite3_codec_data", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
NULL, wxsqlite3_codec_data_sql, 0, 0);
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_create_function(db, "wxsqlite3_codec_data", 2, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
NULL, wxsqlite3_codec_data_sql, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
registerAllExtensions(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
/*
|
||||
** Register the encryption extension functions and
|
||||
** configure the encryption extension from URI parameters as default
|
||||
*/
|
||||
rc = CodecConfigureFromUri(db, NULL, 1);
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_EXTFUNC
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = RegisterExtensionFunctions(db);
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_CSV
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_csv_init(db, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_SHA3
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_shathree_init(db, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_CARRAY
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_carray_init(db, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FILEIO
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_fileio_init(db, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_SERIES
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_series_init(db, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Prototypes for sqlite3_open function variants to make pedantic compilers happy */
|
||||
SQLITE_API int sqlite3_open(const char *filename, sqlite3 **ppDb);
|
||||
SQLITE_API int sqlite3_open16(const void *filename, sqlite3 **ppDb);
|
||||
SQLITE_API int sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs);
|
||||
|
||||
SQLITE_API int sqlite3_open(
|
||||
const char *filename, /* Database filename (UTF-8) */
|
||||
sqlite3 **ppDb /* OUT: SQLite db handle */
|
||||
)
|
||||
{
|
||||
int ret = sqlite3_open_internal(filename, ppDb);
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = registerAllExtensions(*ppDb, NULL, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
SQLITE_API int sqlite3_open16(
|
||||
const void *filename, /* Database filename (UTF-16) */
|
||||
sqlite3 **ppDb /* OUT: SQLite db handle */
|
||||
)
|
||||
{
|
||||
int ret = sqlite3_open16_internal(filename, ppDb);
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = registerAllExtensions(*ppDb, NULL, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
SQLITE_API int sqlite3_open_v2(
|
||||
const char *filename, /* Database filename (UTF-8) */
|
||||
sqlite3 **ppDb, /* OUT: SQLite db handle */
|
||||
int flags, /* Flags */
|
||||
const char *zVfs /* Name of VFS module to use */
|
||||
)
|
||||
{
|
||||
int ret = sqlite3_open_v2_internal(filename, ppDb, flags, zVfs);
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = registerAllExtensions(*ppDb, NULL, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
Vendored
+406
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
** 2016-06-29
|
||||
**
|
||||
** 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 demonstrates how to create a table-valued-function that
|
||||
** returns the values in a C-language array.
|
||||
** Examples:
|
||||
**
|
||||
** SELECT * FROM carray($ptr,5)
|
||||
**
|
||||
** The query above returns 5 integers contained in a C-language array
|
||||
** at the address $ptr. $ptr is a pointer to the array of integers.
|
||||
** The pointer value must be assigned to $ptr using the
|
||||
** sqlite3_bind_pointer() interface with a pointer type of "carray".
|
||||
** For example:
|
||||
**
|
||||
** static int aX[] = { 53, 9, 17, 2231, 4, 99 };
|
||||
** int i = sqlite3_bind_parameter_index(pStmt, "$ptr");
|
||||
** sqlite3_bind_value(pStmt, i, aX, "carray", 0);
|
||||
**
|
||||
** There is an optional third parameter to determine the datatype of
|
||||
** the C-language array. Allowed values of the third parameter are
|
||||
** 'int32', 'int64', 'double', 'char*'. Example:
|
||||
**
|
||||
** SELECT * FROM carray($ptr,10,'char*');
|
||||
**
|
||||
** The default value of the third parameter is 'int32'.
|
||||
**
|
||||
** HOW IT WORKS
|
||||
**
|
||||
** The carray "function" is really a virtual table with the
|
||||
** following schema:
|
||||
**
|
||||
** CREATE TABLE carray(
|
||||
** value,
|
||||
** pointer HIDDEN,
|
||||
** count HIDDEN,
|
||||
** ctype TEXT HIDDEN
|
||||
** );
|
||||
**
|
||||
** If the hidden columns "pointer" and "count" are unconstrained, then
|
||||
** the virtual table has no rows. Otherwise, the virtual table interprets
|
||||
** the integer value of "pointer" as a pointer to the array and "count"
|
||||
** as the number of elements in the array. The virtual table steps through
|
||||
** the array, element by element.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/*
|
||||
** Allowed datatypes
|
||||
*/
|
||||
#define CARRAY_INT32 0
|
||||
#define CARRAY_INT64 1
|
||||
#define CARRAY_DOUBLE 2
|
||||
#define CARRAY_TEXT 3
|
||||
|
||||
/*
|
||||
** Names of types
|
||||
*/
|
||||
static const char *azType[] = { "int32", "int64", "double", "char*" };
|
||||
|
||||
|
||||
/* carray_cursor is a subclass of sqlite3_vtab_cursor which will
|
||||
** serve as the underlying representation of a cursor that scans
|
||||
** over rows of the result
|
||||
*/
|
||||
typedef struct carray_cursor carray_cursor;
|
||||
struct carray_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
sqlite3_int64 iRowid; /* The rowid */
|
||||
void *pPtr; /* Pointer to the array of values */
|
||||
sqlite3_int64 iCnt; /* Number of integers in the array */
|
||||
unsigned char eType; /* One of the CARRAY_type values */
|
||||
};
|
||||
|
||||
/*
|
||||
** The carrayConnect() method is invoked to create a new
|
||||
** carray_vtab that describes the carray virtual table.
|
||||
**
|
||||
** Think of this routine as the constructor for carray_vtab objects.
|
||||
**
|
||||
** All this routine needs to do is:
|
||||
**
|
||||
** (1) Allocate the carray_vtab object and initialize all fields.
|
||||
**
|
||||
** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
|
||||
** result set of queries against carray will look like.
|
||||
*/
|
||||
static int carrayConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
sqlite3_vtab *pNew;
|
||||
int rc;
|
||||
|
||||
/* Column numbers */
|
||||
#define CARRAY_COLUMN_VALUE 0
|
||||
#define CARRAY_COLUMN_POINTER 1
|
||||
#define CARRAY_COLUMN_COUNT 2
|
||||
#define CARRAY_COLUMN_CTYPE 3
|
||||
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x(value,pointer hidden,count hidden,ctype hidden)");
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is the destructor for carray_cursor objects.
|
||||
*/
|
||||
static int carrayDisconnect(sqlite3_vtab *pVtab){
|
||||
sqlite3_free(pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Constructor for a new carray_cursor object.
|
||||
*/
|
||||
static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
carray_cursor *pCur;
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destructor for a carray_cursor.
|
||||
*/
|
||||
static int carrayClose(sqlite3_vtab_cursor *cur){
|
||||
sqlite3_free(cur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Advance a carray_cursor to its next row of output.
|
||||
*/
|
||||
static int carrayNext(sqlite3_vtab_cursor *cur){
|
||||
carray_cursor *pCur = (carray_cursor*)cur;
|
||||
pCur->iRowid++;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return values of columns for the row at which the carray_cursor
|
||||
** is currently pointing.
|
||||
*/
|
||||
static int carrayColumn(
|
||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||
int i /* Which column to return */
|
||||
){
|
||||
carray_cursor *pCur = (carray_cursor*)cur;
|
||||
sqlite3_int64 x = 0;
|
||||
switch( i ){
|
||||
case CARRAY_COLUMN_POINTER: return SQLITE_OK;
|
||||
case CARRAY_COLUMN_COUNT: x = pCur->iCnt; break;
|
||||
case CARRAY_COLUMN_CTYPE: {
|
||||
sqlite3_result_text(ctx, azType[pCur->eType], -1, SQLITE_STATIC);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
default: {
|
||||
switch( pCur->eType ){
|
||||
case CARRAY_INT32: {
|
||||
int *p = (int*)pCur->pPtr;
|
||||
sqlite3_result_int(ctx, p[pCur->iRowid-1]);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case CARRAY_INT64: {
|
||||
sqlite3_int64 *p = (sqlite3_int64*)pCur->pPtr;
|
||||
sqlite3_result_int64(ctx, p[pCur->iRowid-1]);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case CARRAY_DOUBLE: {
|
||||
double *p = (double*)pCur->pPtr;
|
||||
sqlite3_result_double(ctx, p[pCur->iRowid-1]);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case CARRAY_TEXT: {
|
||||
const char **p = (const char**)pCur->pPtr;
|
||||
sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_result_int64(ctx, x);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the rowid for the current row. In this implementation, the
|
||||
** rowid is the same as the output value.
|
||||
*/
|
||||
static int carrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
carray_cursor *pCur = (carray_cursor*)cur;
|
||||
*pRowid = pCur->iRowid;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor has been moved off of the last
|
||||
** row of output.
|
||||
*/
|
||||
static int carrayEof(sqlite3_vtab_cursor *cur){
|
||||
carray_cursor *pCur = (carray_cursor*)cur;
|
||||
return pCur->iRowid>pCur->iCnt;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is called to "rewind" the carray_cursor object back
|
||||
** to the first row of output.
|
||||
*/
|
||||
static int carrayFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
carray_cursor *pCur = (carray_cursor *)pVtabCursor;
|
||||
if( idxNum ){
|
||||
pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
|
||||
pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
|
||||
if( idxNum<3 ){
|
||||
pCur->eType = CARRAY_INT32;
|
||||
}else{
|
||||
unsigned char i;
|
||||
const char *zType = (const char*)sqlite3_value_text(argv[2]);
|
||||
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
|
||||
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
|
||||
}
|
||||
if( i>=sizeof(azType)/sizeof(azType[0]) ){
|
||||
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
|
||||
"unknown datatype: %Q", zType);
|
||||
return SQLITE_ERROR;
|
||||
}else{
|
||||
pCur->eType = i;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
pCur->pPtr = 0;
|
||||
pCur->iCnt = 0;
|
||||
}
|
||||
pCur->iRowid = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** SQLite will invoke this method one or more times while planning a query
|
||||
** that uses the carray virtual table. This routine needs to create
|
||||
** a query plan for each invocation and compute an estimated cost for that
|
||||
** plan.
|
||||
**
|
||||
** In this implementation idxNum is used to represent the
|
||||
** query plan. idxStr is unused.
|
||||
**
|
||||
** idxNum is 2 if the pointer= and count= constraints exist,
|
||||
** 3 if the ctype= constraint also exists, and is 0 otherwise.
|
||||
** If idxNum is 0, then carray becomes an empty table.
|
||||
*/
|
||||
static int carrayBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
int i; /* Loop over constraints */
|
||||
int ptrIdx = -1; /* Index of the pointer= constraint, or -1 if none */
|
||||
int cntIdx = -1; /* Index of the count= constraint, or -1 if none */
|
||||
int ctypeIdx = -1; /* Index of the ctype= constraint, or -1 if none */
|
||||
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||
if( pConstraint->usable==0 ) continue;
|
||||
if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||
switch( pConstraint->iColumn ){
|
||||
case CARRAY_COLUMN_POINTER:
|
||||
ptrIdx = i;
|
||||
break;
|
||||
case CARRAY_COLUMN_COUNT:
|
||||
cntIdx = i;
|
||||
break;
|
||||
case CARRAY_COLUMN_CTYPE:
|
||||
ctypeIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( ptrIdx>=0 && cntIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
|
||||
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
|
||||
pIdxInfo->estimatedCost = (double)1;
|
||||
pIdxInfo->estimatedRows = 100;
|
||||
pIdxInfo->idxNum = 2;
|
||||
if( ctypeIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
|
||||
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
|
||||
pIdxInfo->idxNum = 3;
|
||||
}
|
||||
}else{
|
||||
pIdxInfo->estimatedCost = (double)2147483647;
|
||||
pIdxInfo->estimatedRows = 2147483647;
|
||||
pIdxInfo->idxNum = 0;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This following structure defines all the methods for the
|
||||
** carray virtual table.
|
||||
*/
|
||||
static sqlite3_module carrayModule = {
|
||||
0, /* iVersion */
|
||||
0, /* xCreate */
|
||||
carrayConnect, /* xConnect */
|
||||
carrayBestIndex, /* xBestIndex */
|
||||
carrayDisconnect, /* xDisconnect */
|
||||
0, /* xDestroy */
|
||||
carrayOpen, /* xOpen - open a cursor */
|
||||
carrayClose, /* xClose - close a cursor */
|
||||
carrayFilter, /* xFilter - configure scan constraints */
|
||||
carrayNext, /* xNext - advance a cursor */
|
||||
carrayEof, /* xEof - check for end of scan */
|
||||
carrayColumn, /* xColumn - read data */
|
||||
carrayRowid, /* xRowid - read data */
|
||||
0, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
};
|
||||
|
||||
/*
|
||||
** For testing purpose in the TCL test harness, we need a method for
|
||||
** setting the pointer value. The inttoptr(X) SQL function accomplishes
|
||||
** this. Tcl script will bind an integer to X and the inttoptr() SQL
|
||||
** function will use sqlite3_result_pointer() to convert that integer into
|
||||
** a pointer.
|
||||
**
|
||||
** This is for testing on TCL only.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
static void inttoptrFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
void *p;
|
||||
sqlite3_int64 i64;
|
||||
i64 = sqlite3_value_int64(argv[0]);
|
||||
if( sizeof(i64)==sizeof(p) ){
|
||||
memcpy(&p, &i64, sizeof(p));
|
||||
}else{
|
||||
int i32 = i64 & 0xffffffff;
|
||||
memcpy(&p, &i32, sizeof(p));
|
||||
}
|
||||
sqlite3_result_pointer(context, p, "carray", 0);
|
||||
}
|
||||
#endif /* SQLITE_TEST */
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_carray_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
rc = sqlite3_create_module(db, "carray", &carrayModule, 0);
|
||||
#ifdef SQLITE_TEST
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0,
|
||||
inttoptrFunc, 0, 0);
|
||||
}
|
||||
#endif /* SQLITE_TEST */
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
return rc;
|
||||
}
|
||||
+382
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
** This file contains the implementation for
|
||||
** - the ChaCha20 cipher
|
||||
** - the Poly1305 message digest
|
||||
**
|
||||
** The code was taken from the public domain implementation
|
||||
** of the sqleet project (https://github.com/resilar/sqleet)
|
||||
*/
|
||||
|
||||
#include "mystdint.h"
|
||||
#include <string.h>
|
||||
|
||||
#define ROL32(x, c) (((x) << (c)) | ((x) >> (32-(c))))
|
||||
#define ROR32(x, c) (((x) >> (c)) | ((x) << (32-(c))))
|
||||
|
||||
#define LOAD32_LE(p) \
|
||||
( ((uint32_t)((p)[0]) << 0) \
|
||||
| ((uint32_t)((p)[1]) << 8) \
|
||||
| ((uint32_t)((p)[2]) << 16) \
|
||||
| ((uint32_t)((p)[3]) << 24) \
|
||||
)
|
||||
#define LOAD32_BE(p) \
|
||||
( ((uint32_t)((p)[3]) << 0) \
|
||||
| ((uint32_t)((p)[2]) << 8) \
|
||||
| ((uint32_t)((p)[1]) << 16) \
|
||||
| ((uint32_t)((p)[0]) << 24) \
|
||||
)
|
||||
|
||||
#define STORE32_LE(p, v) \
|
||||
(p)[0] = ((v) >> 0) & 0xFF; \
|
||||
(p)[1] = ((v) >> 8) & 0xFF; \
|
||||
(p)[2] = ((v) >> 16) & 0xFF; \
|
||||
(p)[3] = ((v) >> 24) & 0xFF;
|
||||
#define STORE32_BE(p, v) \
|
||||
(p)[3] = ((v) >> 0) & 0xFF; \
|
||||
(p)[2] = ((v) >> 8) & 0xFF; \
|
||||
(p)[1] = ((v) >> 16) & 0xFF; \
|
||||
(p)[0] = ((v) >> 24) & 0xFF;
|
||||
#define STORE64_BE(p, v) \
|
||||
(p)[7] = ((v) >> 0) & 0xFF; \
|
||||
(p)[6] = ((v) >> 8) & 0xFF; \
|
||||
(p)[5] = ((v) >> 16) & 0xFF; \
|
||||
(p)[4] = ((v) >> 24) & 0xFF; \
|
||||
(p)[3] = ((v) >> 32) & 0xFF; \
|
||||
(p)[2] = ((v) >> 40) & 0xFF; \
|
||||
(p)[1] = ((v) >> 48) & 0xFF; \
|
||||
(p)[0] = ((v) >> 56) & 0xFF;
|
||||
|
||||
/*
|
||||
* ChaCha20 stream cipher
|
||||
*/
|
||||
static void chacha20_block(unsigned char out[64], const uint32_t in[16])
|
||||
{
|
||||
int i;
|
||||
uint32_t x[16];
|
||||
memcpy(x, in, sizeof(uint32_t) * 16);
|
||||
|
||||
#define QR(x, a, b, c, d) \
|
||||
x[a] += x[b]; x[d] ^= x[a]; x[d] = ROL32(x[d], 16); \
|
||||
x[c] += x[d]; x[b] ^= x[c]; x[b] = ROL32(x[b], 12); \
|
||||
x[a] += x[b]; x[d] ^= x[a]; x[d] = ROL32(x[d], 8); \
|
||||
x[c] += x[d]; x[b] ^= x[c]; x[b] = ROL32(x[b], 7);
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
/* Column round */
|
||||
QR(x, 0, 4, 8, 12)
|
||||
QR(x, 1, 5, 9, 13)
|
||||
QR(x, 2, 6, 10, 14)
|
||||
QR(x, 3, 7, 11, 15)
|
||||
/* Diagonal round */
|
||||
QR(x, 0, 5, 10, 15)
|
||||
QR(x, 1, 6, 11, 12)
|
||||
QR(x, 2, 7, 8, 13)
|
||||
QR(x, 3, 4, 9, 14)
|
||||
}
|
||||
#undef QR
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
const uint32_t v = x[i] + in[i];
|
||||
STORE32_LE(&out[4*i], v);
|
||||
}
|
||||
}
|
||||
|
||||
void chacha20_xor(unsigned char* data, size_t n, const unsigned char key[32],
|
||||
const unsigned char nonce[12], uint32_t counter)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t state[16];
|
||||
unsigned char block[64];
|
||||
static const unsigned char sigma[16] = "expand 32-byte k";
|
||||
|
||||
state[ 0] = LOAD32_LE(sigma + 0);
|
||||
state[ 1] = LOAD32_LE(sigma + 4);
|
||||
state[ 2] = LOAD32_LE(sigma + 8);
|
||||
state[ 3] = LOAD32_LE(sigma + 12);
|
||||
|
||||
state[ 4] = LOAD32_LE(key + 0);
|
||||
state[ 5] = LOAD32_LE(key + 4);
|
||||
state[ 6] = LOAD32_LE(key + 8);
|
||||
state[ 7] = LOAD32_LE(key + 12);
|
||||
state[ 8] = LOAD32_LE(key + 16);
|
||||
state[ 9] = LOAD32_LE(key + 20);
|
||||
state[10] = LOAD32_LE(key + 24);
|
||||
state[11] = LOAD32_LE(key + 28);
|
||||
|
||||
state[12] = counter;
|
||||
|
||||
state[13] = LOAD32_LE(nonce + 0);
|
||||
state[14] = LOAD32_LE(nonce + 4);
|
||||
state[15] = LOAD32_LE(nonce + 8);
|
||||
|
||||
while (n >= 64)
|
||||
{
|
||||
chacha20_block(block, state);
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
data[i] ^= block[i];
|
||||
}
|
||||
state[12]++;
|
||||
data += 64;
|
||||
n -= 64;
|
||||
}
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
chacha20_block(block, state);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
data[i] ^= block[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Poly1305 authentication tags
|
||||
*/
|
||||
void poly1305(const unsigned char* msg, size_t n, const unsigned char key[32],
|
||||
unsigned char tag[16])
|
||||
{
|
||||
uint32_t hibit;
|
||||
uint64_t d0, d1, d2, d3, d4;
|
||||
uint32_t h0, h1, h2, h3, h4;
|
||||
uint32_t r0, r1, r2, r3, r4;
|
||||
uint32_t s1, s2, s3, s4;
|
||||
unsigned char buf[16];
|
||||
|
||||
hibit = 1 << 24;
|
||||
h0 = h1 = h2 = h3 = h4 = 0;
|
||||
r0 = (LOAD32_LE(key + 0) >> 0) & 0x03FFFFFF;
|
||||
r1 = (LOAD32_LE(key + 3) >> 2) & 0x03FFFF03; s1 = r1 * 5;
|
||||
r2 = (LOAD32_LE(key + 6) >> 4) & 0x03FFC0FF; s2 = r2 * 5;
|
||||
r3 = (LOAD32_LE(key + 9) >> 6) & 0x03F03FFF; s3 = r3 * 5;
|
||||
r4 = (LOAD32_LE(key + 12) >> 8) & 0x000FFFFF; s4 = r4 * 5;
|
||||
while (n >= 16)
|
||||
{
|
||||
process_block:
|
||||
h0 += (LOAD32_LE(msg + 0) >> 0) & 0x03FFFFFF;
|
||||
h1 += (LOAD32_LE(msg + 3) >> 2) & 0x03FFFFFF;
|
||||
h2 += (LOAD32_LE(msg + 6) >> 4) & 0x03FFFFFF;
|
||||
h3 += (LOAD32_LE(msg + 9) >> 6) & 0x03FFFFFF;
|
||||
h4 += (LOAD32_LE(msg + 12) >> 8) | hibit;
|
||||
|
||||
#define MUL(a,b) ((uint64_t)(a) * (b))
|
||||
d0 = MUL(h0,r0) + MUL(h1,s4) + MUL(h2,s3) + MUL(h3,s2) + MUL(h4,s1);
|
||||
d1 = MUL(h0,r1) + MUL(h1,r0) + MUL(h2,s4) + MUL(h3,s3) + MUL(h4,s2);
|
||||
d2 = MUL(h0,r2) + MUL(h1,r1) + MUL(h2,r0) + MUL(h3,s4) + MUL(h4,s3);
|
||||
d3 = MUL(h0,r3) + MUL(h1,r2) + MUL(h2,r1) + MUL(h3,r0) + MUL(h4,s4);
|
||||
d4 = MUL(h0,r4) + MUL(h1,r3) + MUL(h2,r2) + MUL(h3,r1) + MUL(h4,r0);
|
||||
#undef MUL
|
||||
|
||||
h0 = d0 & 0x03FFFFFF; d1 += (d0 >> 26);
|
||||
h1 = d1 & 0x03FFFFFF; d2 += (d1 >> 26);
|
||||
h2 = d2 & 0x03FFFFFF; d3 += (d2 >> 26);
|
||||
h3 = d3 & 0x03FFFFFF; d4 += (d3 >> 26);
|
||||
h4 = d4 & 0x03FFFFFF; h0 += (d4 >> 26) * 5;
|
||||
|
||||
msg += 16;
|
||||
n -= 16;
|
||||
}
|
||||
if (n)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) buf[i] = msg[i];
|
||||
buf[i++] = 1;
|
||||
while (i < 16) buf[i++] = 0;
|
||||
msg = buf;
|
||||
hibit = 0;
|
||||
n = 16;
|
||||
goto process_block;
|
||||
}
|
||||
|
||||
r0 = h0 + 5;
|
||||
r1 = h1 + (r0 >> 26); *(volatile uint32_t *)&r0 = 0;
|
||||
r2 = h2 + (r1 >> 26); *(volatile uint32_t *)&r1 = 0;
|
||||
r3 = h3 + (r2 >> 26); *(volatile uint32_t *)&r2 = 0;
|
||||
r4 = h4 + (r3 >> 26); *(volatile uint32_t *)&r3 = 0;
|
||||
h0 = h0 + (r4 >> 26) * 5; *(volatile uint32_t *)&r4 = 0;
|
||||
|
||||
d0 = (uint64_t)LOAD32_LE(key + 16) + (h0 >> 0) + (h1 << 26);
|
||||
d1 = (uint64_t)LOAD32_LE(key + 20) + (h1 >> 6) + (h2 << 20) + (d0 >> 32);
|
||||
d2 = (uint64_t)LOAD32_LE(key + 24) + (h2 >> 12) + (h3 << 14) + (d1 >> 32);
|
||||
d3 = (uint64_t)LOAD32_LE(key + 28) + (h3 >> 18) + (h4 << 8) + (d2 >> 32);
|
||||
|
||||
STORE32_LE(tag + 0, d0); *(volatile uint32_t *)&s1 = 0;
|
||||
STORE32_LE(tag + 4, d1); *(volatile uint32_t *)&s2 = 0;
|
||||
STORE32_LE(tag + 8, d2); *(volatile uint32_t *)&s3 = 0;
|
||||
STORE32_LE(tag + 12, d3); *(volatile uint32_t *)&s4 = 0;
|
||||
*(volatile uint64_t *)&d0 = 0; *(volatile uint32_t *)&h0 = 0;
|
||||
*(volatile uint64_t *)&d1 = 0; *(volatile uint32_t *)&h1 = 0;
|
||||
*(volatile uint64_t *)&d2 = 0; *(volatile uint32_t *)&h2 = 0;
|
||||
*(volatile uint64_t *)&d3 = 0; *(volatile uint32_t *)&h3 = 0;
|
||||
*(volatile uint64_t *)&d4 = 0; *(volatile uint32_t *)&h4 = 0;
|
||||
}
|
||||
|
||||
int poly1305_tagcmp(const unsigned char tag1[16], const unsigned char tag2[16])
|
||||
{
|
||||
unsigned int d = 0;
|
||||
d |= tag1[ 0] ^ tag2[ 0];
|
||||
d |= tag1[ 1] ^ tag2[ 1];
|
||||
d |= tag1[ 2] ^ tag2[ 2];
|
||||
d |= tag1[ 3] ^ tag2[ 3];
|
||||
d |= tag1[ 4] ^ tag2[ 4];
|
||||
d |= tag1[ 5] ^ tag2[ 5];
|
||||
d |= tag1[ 6] ^ tag2[ 6];
|
||||
d |= tag1[ 7] ^ tag2[ 7];
|
||||
d |= tag1[ 8] ^ tag2[ 8];
|
||||
d |= tag1[ 9] ^ tag2[ 9];
|
||||
d |= tag1[10] ^ tag2[10];
|
||||
d |= tag1[11] ^ tag2[11];
|
||||
d |= tag1[12] ^ tag2[12];
|
||||
d |= tag1[13] ^ tag2[13];
|
||||
d |= tag1[14] ^ tag2[14];
|
||||
d |= tag1[15] ^ tag2[15];
|
||||
return d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Platform-specific entropy functions for seeding RNG
|
||||
*/
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#include <windows.h>
|
||||
#define RtlGenRandom SystemFunction036
|
||||
BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
|
||||
#pragma comment(lib, "advapi32.lib")
|
||||
static size_t entropy(void* buf, size_t n)
|
||||
{
|
||||
return RtlGenRandom(buf, n) ? n : 0;
|
||||
}
|
||||
#elif defined(__linux__) || defined(__unix__) || defined(__APPLE__)
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/ioctl.h>
|
||||
/* musl does not have <linux/random.h> so let's define RNDGETENTCNT here */
|
||||
#ifndef RNDGETENTCNT
|
||||
#define RNDGETENTCNT _IOR('R', 0x00, int)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Returns the number of urandom bytes read (either 0 or n) */
|
||||
static size_t read_urandom(void* buf, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
ssize_t ret;
|
||||
int fd, count;
|
||||
struct stat st;
|
||||
int errnold = errno;
|
||||
|
||||
do
|
||||
{
|
||||
fd = open("/dev/urandom", O_RDONLY, 0);
|
||||
}
|
||||
while (fd == -1 && errno == EINTR);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
|
||||
|
||||
/* Check the sanity of the device node */
|
||||
if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)
|
||||
#ifdef __linux__
|
||||
|| ioctl(fd, RNDGETENTCNT, &count) == -1
|
||||
#endif
|
||||
)
|
||||
{
|
||||
close(fd);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Read bytes */
|
||||
for (i = 0; i < n; i += ret)
|
||||
{
|
||||
while ((ret = read(fd, (char *)buf + i, n - i)) == -1)
|
||||
{
|
||||
if (errno != EAGAIN && errno != EINTR)
|
||||
{
|
||||
close(fd);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
|
||||
/* Verify that the random device returned non-zero data */
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if (((unsigned char*) buf)[i] != 0)
|
||||
{
|
||||
errno = errnold;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tiny n may unintentionally fall through! */
|
||||
fail:
|
||||
fprintf(stderr, "bad /dev/urandom RNG)\n");
|
||||
abort(); /* PANIC! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t entropy(void* buf, size_t n)
|
||||
{
|
||||
#if defined(__linux__) && defined(SYS_getrandom)
|
||||
if (syscall(SYS_getrandom, buf, n, 0) == n)
|
||||
return n;
|
||||
#elif defined(SYS_getentropy)
|
||||
if (syscall(SYS_getentropy, buf, n) == 0)
|
||||
return n;
|
||||
#endif
|
||||
return read_urandom(buf, n);
|
||||
}
|
||||
#else
|
||||
# error "Secure pseudorandom number generator not implemented for this OS"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ChaCha20 random number generator
|
||||
*/
|
||||
void chacha20_rng(void* out, size_t n)
|
||||
{
|
||||
static size_t available = 0;
|
||||
static uint32_t counter = 0;
|
||||
static unsigned char key[32], nonce[12], buffer[64] = { 0 };
|
||||
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex* mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG);
|
||||
sqlite3_mutex_enter(mutex);
|
||||
#endif
|
||||
|
||||
while (n > 0)
|
||||
{
|
||||
size_t m;
|
||||
if (available == 0)
|
||||
{
|
||||
if (counter == 0)
|
||||
{
|
||||
if (entropy(key, sizeof(key)) != sizeof(key))
|
||||
abort();
|
||||
if (entropy(nonce, sizeof(nonce)) != sizeof(nonce))
|
||||
abort();
|
||||
}
|
||||
chacha20_xor(buffer, sizeof(buffer), key, nonce, counter++);
|
||||
available = sizeof(buffer);
|
||||
}
|
||||
m = (available < n) ? available : n;
|
||||
memcpy(out, buffer + (sizeof(buffer) - available), m);
|
||||
out = (unsigned char *)out + m;
|
||||
available -= m;
|
||||
n -= m;
|
||||
}
|
||||
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex_leave(mutex);
|
||||
#endif
|
||||
}
|
||||
Vendored
+2868
File diff suppressed because it is too large
Load Diff
Vendored
+140
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
** Name: codec.h
|
||||
** Purpose: Header file for SQLite codecs
|
||||
** Author: Ulrich Telle
|
||||
** Created: 2006-12-06
|
||||
** Copyright: (c) 2006-2018 Ulrich Telle
|
||||
** License: LGPL-3.0+ WITH WxWindows-exception-3.1
|
||||
*/
|
||||
|
||||
#ifndef _CODEC_H_
|
||||
#define _CODEC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__BORLANDC__)
|
||||
#define __STDC__ 1
|
||||
#endif
|
||||
|
||||
#if defined(__BORLANDC__)
|
||||
#undef __STDC__
|
||||
#endif
|
||||
|
||||
/*
|
||||
// ATTENTION: Macro similar to that in pager.c
|
||||
// TODO: Check in case of new version of SQLite
|
||||
*/
|
||||
#define WX_PAGER_MJ_PGNO(x) ((PENDING_BYTE/(x))+1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End of the 'extern "C"' block */
|
||||
#endif
|
||||
|
||||
#include "rijndael.h"
|
||||
|
||||
#include "sqlite3secure.h"
|
||||
|
||||
#define CODEC_TYPE_DEFAULT CODEC_TYPE_CHACHA20
|
||||
|
||||
#ifndef CODEC_TYPE
|
||||
#define CODEC_TYPE CODEC_TYPE_DEFAULT
|
||||
#endif
|
||||
|
||||
#if CODEC_TYPE < 1 || CODEC_TYPE > CODEC_TYPE_MAX
|
||||
#error "Invalid codec type selected"
|
||||
#endif
|
||||
|
||||
#define MAXKEYLENGTH 32
|
||||
#define KEYLENGTH_AES128 16
|
||||
#define KEYLENGTH_AES256 32
|
||||
#define KEYSALT_LENGTH 16
|
||||
|
||||
#define CODEC_SHA_ITER 4001
|
||||
|
||||
typedef struct _Codec
|
||||
{
|
||||
int m_isEncrypted;
|
||||
int m_hmacCheck;
|
||||
/* Read cipher */
|
||||
int m_hasReadCipher;
|
||||
int m_readCipherType;
|
||||
void* m_readCipher;
|
||||
int m_readReserved;
|
||||
/* Write cipher */
|
||||
int m_hasWriteCipher;
|
||||
int m_writeCipherType;
|
||||
void* m_writeCipher;
|
||||
int m_writeReserved;
|
||||
|
||||
sqlite3* m_db; /* Pointer to DB */
|
||||
Btree* m_bt; /* Pointer to B-tree used by DB */
|
||||
unsigned char m_page[SQLITE_MAX_PAGE_SIZE+24];
|
||||
int m_pageSize;
|
||||
int m_reserved;
|
||||
int m_hasKeySalt;
|
||||
unsigned char m_keySalt[KEYSALT_LENGTH];
|
||||
} Codec;
|
||||
|
||||
static void wxsqlite3_config_table(sqlite3_context* context, int argc, sqlite3_value** argv);
|
||||
static void wxsqlite3_config_params(sqlite3_context* context, int argc, sqlite3_value** argv);
|
||||
|
||||
int wxsqlite3_config(sqlite3* db, const char* paramName, int newValue);
|
||||
int wxsqlite3_config_cipher(sqlite3* db, const char* cipherName, const char* paramName, int newValue);
|
||||
|
||||
static int GetCipherType(sqlite3* db);
|
||||
static void* GetCipherParams(sqlite3* db, int cypherType);
|
||||
static int CodecInit(Codec* codec);
|
||||
static void CodecTerm(Codec* codec);
|
||||
static void CodecClearKeySalt(Codec* codec);
|
||||
|
||||
static int CodecCopy(Codec* codec, Codec* other);
|
||||
|
||||
static void CodecGenerateReadKey(Codec* codec, char* userPassword, int passwordLength, unsigned char* cipherSalt);
|
||||
|
||||
static void CodecGenerateWriteKey(Codec* codec, char* userPassword, int passwordLength, unsigned char* cipherSalt);
|
||||
|
||||
static int CodecEncrypt(Codec* codec, int page, unsigned char* data, int len, int useWriteKey);
|
||||
|
||||
static int CodecDecrypt(Codec* codec, int page, unsigned char* data, int len);
|
||||
|
||||
static int CodecCopyCipher(Codec* codec, int read2write);
|
||||
|
||||
static int CodecSetup(Codec* codec, int cipherType, char* userPassword, int passwordLength);
|
||||
static int CodecSetupWriteCipher(Codec* codec, int cipherType, char* userPassword, int passwordLength);
|
||||
|
||||
static void CodecSetIsEncrypted(Codec* codec, int isEncrypted);
|
||||
static void CodecSetReadCipherType(Codec* codec, int cipherType);
|
||||
static void CodecSetWriteCipherType(Codec* codec, int cipherType);
|
||||
static void CodecSetHasReadCipher(Codec* codec, int hasReadCipher);
|
||||
static void CodecSetHasWriteCipher(Codec* codec, int hasWriteCipher);
|
||||
static void CodecSetDb(Codec* codec, sqlite3* db);
|
||||
static void CodecSetBtree(Codec* codec, Btree* bt);
|
||||
static void CodecSetReadReserved(Codec* codec, int reserved);
|
||||
static void CodecSetWriteReserved(Codec* codec, int reserved);
|
||||
|
||||
static int CodecIsEncrypted(Codec* codec);
|
||||
static int CodecHasReadCipher(Codec* codec);
|
||||
static int CodecHasWriteCipher(Codec* codec);
|
||||
static Btree* CodecGetBtree(Codec* codec);
|
||||
static int CodecGetReadReserved(Codec* codec);
|
||||
static int CodecGetWriteReserved(Codec* codec);
|
||||
static unsigned char* CodecGetPageBuffer(Codec* codec);
|
||||
static int CodecGetLegacyReadCipher(Codec* codec);
|
||||
static int CodecGetLegacyWriteCipher(Codec* codec);
|
||||
static int CodecGetPageSizeReadCipher(Codec* codec);
|
||||
static int CodecGetPageSizeWriteCipher(Codec* codec);
|
||||
static int CodecGetReservedReadCipher(Codec* codec);
|
||||
static int CodecGetReservedWriteCipher(Codec* codec);
|
||||
static int CodecReservedEqual(Codec* codec);
|
||||
|
||||
static void CodecPadPassword(char* password, int pswdlen, unsigned char pswd[32]);
|
||||
static void CodecRC4(unsigned char* key, int keylen,
|
||||
unsigned char* textin, int textlen,
|
||||
unsigned char* textout);
|
||||
static void CodecGetMD5Binary(unsigned char* data, int length, unsigned char* digest);
|
||||
static void CodecGetSHABinary(unsigned char* data, int length, unsigned char* digest);
|
||||
static void CodecGenerateInitialVector(int seed, unsigned char iv[16]);
|
||||
|
||||
#endif
|
||||
+640
@@ -0,0 +1,640 @@
|
||||
/*
|
||||
** Name: codecext.c
|
||||
** Purpose: Implementation of SQLite codec API
|
||||
** Author: Ulrich Telle
|
||||
** Created: 2006-12-06
|
||||
** Copyright: (c) 2006-2019 Ulrich Telle
|
||||
** License: LGPL-3.0+ WITH WxWindows-exception-3.1
|
||||
*/
|
||||
|
||||
#ifndef SQLITE_OMIT_DISKIO
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
|
||||
/*
|
||||
** Prototypes for codec functions
|
||||
*/
|
||||
int sqlite3CodecAttach(sqlite3* db, int nDb, const void* zKey, int nKey);
|
||||
void sqlite3CodecGetKey(sqlite3* db, int nDb, void** zKey, int* nKey);
|
||||
|
||||
/*
|
||||
** Include a "special" version of the VACUUM command
|
||||
*/
|
||||
#include "rekeyvacuum.c"
|
||||
|
||||
#include "codec.h"
|
||||
|
||||
void
|
||||
sqlite3_activate_see(const char *info)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
** Free the encryption data structure associated with a pager instance.
|
||||
** (called from the modified code in pager.c)
|
||||
*/
|
||||
static void
|
||||
sqlite3CodecFree(void *pCodecArg)
|
||||
{
|
||||
if (pCodecArg)
|
||||
{
|
||||
CodecTerm(pCodecArg);
|
||||
sqlite3_free(pCodecArg);
|
||||
pCodecArg = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sqlite3CodecSizeChange(void *pArg, int pageSize, int reservedSize)
|
||||
{
|
||||
Codec* pCodec = (Codec*) pArg;
|
||||
pCodec->m_pageSize = pageSize;
|
||||
pCodec->m_reserved = reservedSize;
|
||||
#if 0
|
||||
fprintf(stdout, "sqlite3CodecSizeChange c=0x%08x p=%d, r=%d\n", (unsigned int) pArg, pageSize, reservedSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
reportCodecError(Btree* pBt, int error)
|
||||
{
|
||||
pBt->pBt->pPager->errCode = error;
|
||||
setGetterMethod(pBt->pBt->pPager);
|
||||
pBt->pBt->db->errCode = error;
|
||||
}
|
||||
|
||||
/*
|
||||
// Encrypt/Decrypt functionality, called by pager.c
|
||||
*/
|
||||
static void*
|
||||
sqlite3Codec(void* pCodecArg, void* data, Pgno nPageNum, int nMode)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
Codec* codec = NULL;
|
||||
int pageSize;
|
||||
if (pCodecArg == NULL)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
codec = (Codec*) pCodecArg;
|
||||
if (!CodecIsEncrypted(codec))
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
pageSize = sqlite3BtreeGetPageSize(CodecGetBtree(codec));
|
||||
|
||||
switch(nMode)
|
||||
{
|
||||
case 0: /* Undo a "case 7" journal file encryption */
|
||||
case 2: /* Reload a page */
|
||||
case 3: /* Load a page */
|
||||
if (CodecHasReadCipher(codec))
|
||||
{
|
||||
rc = CodecDecrypt(codec, nPageNum, (unsigned char*) data, pageSize);
|
||||
if (rc != SQLITE_OK) reportCodecError(CodecGetBtree(codec), rc);
|
||||
}
|
||||
break;
|
||||
|
||||
case 6: /* Encrypt a page for the main database file */
|
||||
if (CodecHasWriteCipher(codec))
|
||||
{
|
||||
unsigned char* pageBuffer = CodecGetPageBuffer(codec);
|
||||
memcpy(pageBuffer, data, pageSize);
|
||||
data = pageBuffer;
|
||||
rc = CodecEncrypt(codec, nPageNum, (unsigned char*) data, pageSize, 1);
|
||||
if (rc != SQLITE_OK) reportCodecError(CodecGetBtree(codec), rc);
|
||||
}
|
||||
break;
|
||||
|
||||
case 7: /* Encrypt a page for the journal file */
|
||||
/* Under normal circumstances, the readkey is the same as the writekey. However,
|
||||
when the database is being rekeyed, the readkey is not the same as the writekey.
|
||||
The rollback journal must be written using the original key for the
|
||||
database file because it is, by nature, a rollback journal.
|
||||
Therefore, for case 7, when the rollback is being written, always encrypt using
|
||||
the database's readkey, which is guaranteed to be the same key that was used to
|
||||
read the original data.
|
||||
*/
|
||||
if (CodecHasReadCipher(codec))
|
||||
{
|
||||
unsigned char* pageBuffer = CodecGetPageBuffer(codec);
|
||||
memcpy(pageBuffer, data, pageSize);
|
||||
data = pageBuffer;
|
||||
rc = CodecEncrypt(codec, nPageNum, (unsigned char*) data, pageSize, 0);
|
||||
if (rc != SQLITE_OK) reportCodecError(CodecGetBtree(codec), rc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static void*
|
||||
mySqlite3PagerGetCodec(
|
||||
Pager *pPager
|
||||
);
|
||||
|
||||
static void
|
||||
mySqlite3PagerSetCodec(
|
||||
Pager *pPager,
|
||||
void *(*xCodec)(void*,void*,Pgno,int),
|
||||
void (*xCodecSizeChng)(void*,int,int),
|
||||
void (*xCodecFree)(void*),
|
||||
void *pCodec
|
||||
);
|
||||
|
||||
static int
|
||||
mySqlite3AdjustBtree(Btree* pBt, int nPageSize, int nReserved, int isLegacy)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
Pager* pager = sqlite3BtreePager(pBt);
|
||||
int pagesize = sqlite3BtreeGetPageSize(pBt);
|
||||
sqlite3BtreeSecureDelete(pBt, 1);
|
||||
if (nPageSize > 0)
|
||||
{
|
||||
pagesize = nPageSize;
|
||||
}
|
||||
|
||||
/* Adjust the page size and the reserved area */
|
||||
if (pager->nReserve != nReserved)
|
||||
{
|
||||
if (isLegacy != 0)
|
||||
{
|
||||
pBt->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
|
||||
}
|
||||
rc = sqlite3BtreeSetPageSize(pBt, pagesize, nReserved, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
sqlite3CodecAttach(sqlite3* db, int nDb, const void* zKey, int nKey)
|
||||
{
|
||||
/* Attach a key to a database. */
|
||||
Codec* codec = (Codec*) sqlite3_malloc(sizeof(Codec));
|
||||
int rc = (codec != NULL) ? CodecInit(codec) : SQLITE_NOMEM;
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
/* Unable to allocate memory for the codec base structure */
|
||||
return rc;
|
||||
}
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
CodecSetDb(codec, db);
|
||||
|
||||
/* No key specified, could mean either use the main db's encryption or no encryption */
|
||||
if (zKey == NULL || nKey <= 0)
|
||||
{
|
||||
/* No key specified */
|
||||
if (nDb != 0 && nKey > 0)
|
||||
{
|
||||
/* Main database possibly encrypted, no key explicitly given for attached database */
|
||||
Codec* mainCodec = (Codec*) mySqlite3PagerGetCodec(sqlite3BtreePager(db->aDb[0].pBt));
|
||||
/* Attached database, therefore use the key of main database, if main database is encrypted */
|
||||
if (mainCodec != NULL && CodecIsEncrypted(mainCodec))
|
||||
{
|
||||
rc = CodecCopy(codec, mainCodec);
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
CodecSetBtree(codec, db->aDb[nDb].pBt);
|
||||
mySqlite3AdjustBtree(db->aDb[nDb].pBt, CodecGetPageSizeWriteCipher(codec), CodecGetReservedWriteCipher(codec), CodecGetLegacyWriteCipher(codec));
|
||||
#if (SQLITE_VERSION_NUMBER >= 3006016)
|
||||
mySqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, sqlite3CodecSizeChange, sqlite3CodecFree, codec);
|
||||
#else
|
||||
#if (SQLITE_VERSION_NUMBER >= 3003014)
|
||||
sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, codec);
|
||||
#else
|
||||
sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, codec);
|
||||
#endif
|
||||
db->aDb[nDb].pAux = codec;
|
||||
db->aDb[nDb].xFreeAux = sqlite3CodecFree;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Replicating main codec failed, do not attach incomplete codec */
|
||||
sqlite3CodecFree(codec);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Main database not encrypted */
|
||||
sqlite3CodecFree(codec);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Main database not encrypted, no key given for attached database */
|
||||
sqlite3CodecFree(codec);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if (SQLITE_VERSION_NUMBER >= 3015000)
|
||||
const char* zDbName = db->aDb[nDb].zDbSName;
|
||||
#else
|
||||
const char* zDbName = db->aDb[nDb].zName;
|
||||
#endif
|
||||
const char* dbFileName = sqlite3_db_filename(db, zDbName);
|
||||
if (dbFileName != NULL)
|
||||
{
|
||||
/* Check whether key salt is provided in URI */
|
||||
const unsigned char* cipherSalt = (const unsigned char*)sqlite3_uri_parameter(dbFileName, "cipher_salt");
|
||||
if ((cipherSalt != NULL) && (strlen((const char*)cipherSalt) >= 2 * KEYSALT_LENGTH) && IsHexKey(cipherSalt, 2 * KEYSALT_LENGTH))
|
||||
{
|
||||
codec->m_hasKeySalt = 1;
|
||||
ConvertHex2Bin(cipherSalt, 2 * KEYSALT_LENGTH, codec->m_keySalt);
|
||||
}
|
||||
}
|
||||
|
||||
/* Configure cipher from URI in case of attached database */
|
||||
if (nDb > 0)
|
||||
{
|
||||
rc = CodecConfigureFromUri(db, zDbName, 0);
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
/* Key specified, setup encryption key for database */
|
||||
CodecSetBtree(codec, db->aDb[nDb].pBt);
|
||||
rc = CodecSetup(codec, GetCipherType(db), (char*) zKey, nKey);
|
||||
CodecClearKeySalt(codec);
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
mySqlite3AdjustBtree(db->aDb[nDb].pBt, CodecGetPageSizeWriteCipher(codec), CodecGetReservedWriteCipher(codec), CodecGetLegacyWriteCipher(codec));
|
||||
#if (SQLITE_VERSION_NUMBER >= 3006016)
|
||||
mySqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, sqlite3CodecSizeChange, sqlite3CodecFree, codec);
|
||||
#else
|
||||
#if (SQLITE_VERSION_NUMBER >= 3003014)
|
||||
sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, codec);
|
||||
#else
|
||||
sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, codec);
|
||||
#endif
|
||||
db->aDb[nDb].pAux = codec;
|
||||
db->aDb[nDb].xFreeAux = sqlite3CodecFree;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Setting up codec failed, do not attach incomplete codec */
|
||||
sqlite3CodecFree(codec);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
sqlite3CodecGetKey(sqlite3* db, int nDb, void** zKey, int* nKey)
|
||||
{
|
||||
/*
|
||||
// The unencrypted password is not stored for security reasons
|
||||
// therefore always return NULL
|
||||
// If the main database is encrypted a key length of 1 is returned.
|
||||
// In that case an attached database will get the same encryption key
|
||||
// as the main database if no key was explicitly given for the attached database.
|
||||
*/
|
||||
Codec* mainCodec = (Codec*) mySqlite3PagerGetCodec(sqlite3BtreePager(db->aDb[0].pBt));
|
||||
int keylen = (mainCodec != NULL && CodecIsEncrypted(mainCodec)) ? 1 : 0;
|
||||
*zKey = NULL;
|
||||
*nKey = keylen;
|
||||
}
|
||||
|
||||
static int
|
||||
dbFindIndex(sqlite3* db, const char* zDb)
|
||||
{
|
||||
int dbIndex = 0;
|
||||
if (zDb != NULL)
|
||||
{
|
||||
int found = 0;
|
||||
int index;
|
||||
for (index = 0; found == 0 && index < db->nDb; ++index)
|
||||
{
|
||||
struct Db* pDb = &db->aDb[index];
|
||||
#if (SQLITE_VERSION_NUMBER >= 3015000)
|
||||
if (sqlite3_stricmp(pDb->zDbSName, zDb) == 0)
|
||||
#else
|
||||
if (sqlite3_stricmp(pDb->zName, zDb) == 0)
|
||||
#endif
|
||||
{
|
||||
found = 1;
|
||||
dbIndex = index;
|
||||
}
|
||||
}
|
||||
if (found == 0) dbIndex = 0;
|
||||
}
|
||||
return dbIndex;
|
||||
}
|
||||
|
||||
int
|
||||
sqlite3_key(sqlite3 *db, const void *zKey, int nKey)
|
||||
{
|
||||
/* The key is only set for the main database, not the temp database */
|
||||
return sqlite3_key_v2(db, "main", zKey, nKey);
|
||||
}
|
||||
|
||||
int
|
||||
sqlite3_key_v2(sqlite3 *db, const char *zDbName, const void *zKey, int nKey)
|
||||
{
|
||||
int rc = SQLITE_ERROR;
|
||||
if ((db != NULL) && (zKey != NULL) && (nKey > 0))
|
||||
{
|
||||
int dbIndex;
|
||||
/* Configure cipher from URI parameters if requested */
|
||||
if (sqlite3FindFunction(db, "wxsqlite3_config_table", 0, SQLITE_UTF8, 0) == NULL)
|
||||
{
|
||||
/*
|
||||
** Encryption extension of database connection not yet initialized;
|
||||
** that is, sqlite3_key_v2 was called from the internal open function.
|
||||
** Therefore the URI should be checked for encryption configuration parameters.
|
||||
*/
|
||||
rc = CodecConfigureFromUri(db, zDbName, 0);
|
||||
}
|
||||
|
||||
/* The key is only set for the main database, not the temp database */
|
||||
dbIndex = dbFindIndex(db, zDbName);
|
||||
rc = sqlite3CodecAttach(db, dbIndex, zKey, nKey);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
sqlite3_rekey_v2(sqlite3 *db, const char *zDbName, const void *zKey, int nKey)
|
||||
{
|
||||
/* Changes the encryption key for an existing database. */
|
||||
int dbIndex = dbFindIndex(db, zDbName);
|
||||
int rc = SQLITE_ERROR;
|
||||
Btree* pBt = db->aDb[dbIndex].pBt;
|
||||
int nPagesize = sqlite3BtreeGetPageSize(pBt);
|
||||
int nReserved;
|
||||
Pager* pPager;
|
||||
Codec* codec;
|
||||
|
||||
sqlite3BtreeEnter(pBt);
|
||||
nReserved = sqlite3BtreeGetReserveNoMutex(pBt);
|
||||
sqlite3BtreeLeave(pBt);
|
||||
|
||||
pPager = sqlite3BtreePager(pBt);
|
||||
codec = (Codec*) mySqlite3PagerGetCodec(pPager);
|
||||
|
||||
if ((zKey == NULL || nKey == 0) && (codec == NULL || !CodecIsEncrypted(codec)))
|
||||
{
|
||||
/* Database not encrypted and key not specified, therefore do nothing */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
|
||||
if (codec == NULL || !CodecIsEncrypted(codec))
|
||||
{
|
||||
/* Database not encrypted, but key specified, therefore encrypt database */
|
||||
if (codec == NULL)
|
||||
{
|
||||
codec = (Codec*) sqlite3_malloc(sizeof(Codec));
|
||||
rc = (codec != NULL) ? CodecInit(codec) : SQLITE_NOMEM;
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
CodecSetDb(codec, db);
|
||||
CodecSetBtree(codec, pBt);
|
||||
rc = CodecSetupWriteCipher(codec, GetCipherType(db), (char*) zKey, nKey);
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
int nPagesizeWriteCipher = CodecGetPageSizeWriteCipher(codec);
|
||||
if (nPagesizeWriteCipher <= 0 || nPagesize == nPagesizeWriteCipher)
|
||||
{
|
||||
int nReservedWriteCipher;
|
||||
CodecSetHasReadCipher(codec, 0); /* Original database is not encrypted */
|
||||
mySqlite3AdjustBtree(pBt, CodecGetPageSizeWriteCipher(codec), CodecGetReservedWriteCipher(codec), CodecGetLegacyWriteCipher(codec));
|
||||
#if (SQLITE_VERSION_NUMBER >= 3006016)
|
||||
mySqlite3PagerSetCodec(pPager, sqlite3Codec, sqlite3CodecSizeChange, sqlite3CodecFree, codec);
|
||||
#else
|
||||
#if (SQLITE_VERSION_NUMBER >= 3003014)
|
||||
sqlite3PagerSetCodec(pPager, sqlite3Codec, codec);
|
||||
#else
|
||||
sqlite3pager_set_codec(pPager, sqlite3Codec, codec);
|
||||
#endif
|
||||
db->aDb[dbIndex].pAux = codec;
|
||||
db->aDb[dbIndex].xFreeAux = sqlite3CodecFree;
|
||||
#endif
|
||||
nReservedWriteCipher = CodecGetReservedWriteCipher(codec);
|
||||
if (nReserved != nReservedWriteCipher)
|
||||
{
|
||||
/* Use VACUUM to change the number of reserved bytes */
|
||||
char* err = NULL;
|
||||
CodecSetReadReserved(codec, nReserved);
|
||||
CodecSetWriteReserved(codec, nReservedWriteCipher);
|
||||
#if (SQLITE_VERSION_NUMBER >= 3027000)
|
||||
rc = sqlite3RunVacuumForRekey(&err, db, dbIndex, NULL, nReservedWriteCipher);
|
||||
#else
|
||||
rc = sqlite3RunVacuumForRekey(&err, db, dbIndex, nReservedWriteCipher);
|
||||
#endif
|
||||
goto leave_rekey;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Pagesize cannot be changed for an encrypted database */
|
||||
rc = SQLITE_ERROR;
|
||||
goto leave_rekey;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
else if (zKey == NULL || nKey == 0)
|
||||
{
|
||||
/* Database encrypted, but key not specified, therefore decrypt database */
|
||||
/* Keep read key, drop write key */
|
||||
CodecSetHasWriteCipher(codec, 0);
|
||||
if (nReserved > 0)
|
||||
{
|
||||
/* Use VACUUM to change the number of reserved bytes */
|
||||
char* err = NULL;
|
||||
CodecSetReadReserved(codec, nReserved);
|
||||
CodecSetWriteReserved(codec, 0);
|
||||
#if (SQLITE_VERSION_NUMBER >= 3027000)
|
||||
rc = sqlite3RunVacuumForRekey(&err, db, dbIndex, NULL, 0);
|
||||
#else
|
||||
rc = sqlite3RunVacuumForRekey(&err, db, dbIndex, 0);
|
||||
#endif
|
||||
goto leave_rekey;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Database encrypted and key specified, therefore re-encrypt database with new key */
|
||||
/* Keep read key, change write key to new key */
|
||||
rc = CodecSetupWriteCipher(codec, GetCipherType(db), (char*) zKey, nKey);
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
int nPagesizeWriteCipher = CodecGetPageSizeWriteCipher(codec);
|
||||
if (nPagesizeWriteCipher <= 0 || nPagesize == nPagesizeWriteCipher)
|
||||
{
|
||||
int nReservedWriteCipher = CodecGetReservedWriteCipher(codec);
|
||||
if (nReserved != nReservedWriteCipher)
|
||||
{
|
||||
/* Use VACUUM to change the number of reserved bytes */
|
||||
char* err = NULL;
|
||||
CodecSetReadReserved(codec, nReserved);
|
||||
CodecSetWriteReserved(codec, nReservedWriteCipher);
|
||||
#if (SQLITE_VERSION_NUMBER >= 3027000)
|
||||
rc = sqlite3RunVacuumForRekey(&err, db, dbIndex, NULL, nReservedWriteCipher);
|
||||
#else
|
||||
rc = sqlite3RunVacuumForRekey(&err, db, dbIndex, nReservedWriteCipher);
|
||||
#endif
|
||||
goto leave_rekey;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Pagesize cannot be changed for an encrypted database */
|
||||
rc = SQLITE_ERROR;
|
||||
goto leave_rekey;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Setup of write cipher failed */
|
||||
goto leave_rekey;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start transaction */
|
||||
#if (SQLITE_VERSION_NUMBER >= 3025000)
|
||||
rc = sqlite3BtreeBeginTrans(pBt, 1, 0);
|
||||
#else
|
||||
rc = sqlite3BtreeBeginTrans(pBt, 1);
|
||||
#endif
|
||||
if (!rc)
|
||||
{
|
||||
int pageSize = sqlite3BtreeGetPageSize(pBt);
|
||||
Pgno nSkip = WX_PAGER_MJ_PGNO(pageSize);
|
||||
#if (SQLITE_VERSION_NUMBER >= 3003014)
|
||||
DbPage *pPage;
|
||||
#else
|
||||
void *pPage;
|
||||
#endif
|
||||
Pgno n;
|
||||
/* Rewrite all pages using the new encryption key (if specified) */
|
||||
#if (SQLITE_VERSION_NUMBER >= 3007001)
|
||||
Pgno nPage;
|
||||
int nPageCount = -1;
|
||||
sqlite3PagerPagecount(pPager, &nPageCount);
|
||||
nPage = nPageCount;
|
||||
#elif (SQLITE_VERSION_NUMBER >= 3006000)
|
||||
int nPageCount = -1;
|
||||
int rc = sqlite3PagerPagecount(pPager, &nPageCount);
|
||||
Pgno nPage = (Pgno) nPageCount;
|
||||
#elif (SQLITE_VERSION_NUMBER >= 3003014)
|
||||
Pgno nPage = sqlite3PagerPagecount(pPager);
|
||||
#else
|
||||
Pgno nPage = sqlite3pager_pagecount(pPager);
|
||||
#endif
|
||||
|
||||
for (n = 1; rc == SQLITE_OK && n <= nPage; n++)
|
||||
{
|
||||
if (n == nSkip) continue;
|
||||
#if (SQLITE_VERSION_NUMBER >= 3010000)
|
||||
rc = sqlite3PagerGet(pPager, n, &pPage, 0);
|
||||
#elif (SQLITE_VERSION_NUMBER >= 3003014)
|
||||
rc = sqlite3PagerGet(pPager, n, &pPage);
|
||||
#else
|
||||
rc = sqlite3pager_get(pPager, n, &pPage);
|
||||
#endif
|
||||
if (!rc)
|
||||
{
|
||||
#if (SQLITE_VERSION_NUMBER >= 3003014)
|
||||
rc = sqlite3PagerWrite(pPage);
|
||||
sqlite3PagerUnref(pPage);
|
||||
#else
|
||||
rc = sqlite3pager_write(pPage);
|
||||
sqlite3pager_unref(pPage);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
/* Commit transaction if all pages could be rewritten */
|
||||
rc = sqlite3BtreeCommit(pBt);
|
||||
}
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
/* Rollback in case of error */
|
||||
#if (SQLITE_VERSION_NUMBER >= 3008007)
|
||||
/* Unfortunately this change was introduced in version 3.8.7.2 which cannot be detected using the SQLITE_VERSION_NUMBER */
|
||||
/* That is, compilation will fail for version 3.8.7 or 3.8.7.1 ==> Please change manually ... or upgrade to 3.8.7.2 or higher */
|
||||
sqlite3BtreeRollback(pBt, SQLITE_OK, 0);
|
||||
#elif (SQLITE_VERSION_NUMBER >= 3007011)
|
||||
sqlite3BtreeRollback(pbt, SQLITE_OK);
|
||||
#else
|
||||
sqlite3BtreeRollback(pbt);
|
||||
#endif
|
||||
}
|
||||
|
||||
leave_rekey:
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
|
||||
/*leave_final:*/
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
/* Set read key equal to write key if necessary */
|
||||
if (CodecHasWriteCipher(codec))
|
||||
{
|
||||
CodecCopyCipher(codec, 0);
|
||||
CodecSetHasReadCipher(codec, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
CodecSetIsEncrypted(codec, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Restore write key if necessary */
|
||||
if (CodecHasReadCipher(codec))
|
||||
{
|
||||
CodecCopyCipher(codec, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
CodecSetIsEncrypted(codec, 0);
|
||||
}
|
||||
}
|
||||
/* Reset reserved for read and write key */
|
||||
CodecSetReadReserved(codec, -1);
|
||||
CodecSetWriteReserved(codec, -1);
|
||||
|
||||
if (!CodecIsEncrypted(codec))
|
||||
{
|
||||
/* Remove codec for unencrypted database */
|
||||
#if (SQLITE_VERSION_NUMBER >= 3006016)
|
||||
mySqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL);
|
||||
#else
|
||||
#if (SQLITE_VERSION_NUMBER >= 3003014)
|
||||
sqlite3PagerSetCodec(pPager, NULL, NULL);
|
||||
#else
|
||||
sqlite3pager_set_codec(pPager, NULL, NULL);
|
||||
#endif
|
||||
db->aDb[dbIndex].pAux = NULL;
|
||||
db->aDb[dbIndex].xFreeAux = NULL;
|
||||
sqlite3CodecFree(codec);
|
||||
#endif
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sqlite3_rekey(sqlite3 *db, const void *zKey, int nKey)
|
||||
{
|
||||
return sqlite3_rekey_v2(db, "main", zKey, nKey);
|
||||
}
|
||||
|
||||
#endif /* SQLITE_HAS_CODEC */
|
||||
|
||||
#endif /* SQLITE_OMIT_DISKIO */
|
||||
Vendored
+948
@@ -0,0 +1,948 @@
|
||||
/*
|
||||
** 2016-05-28
|
||||
**
|
||||
** 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 the implementation of an SQLite virtual table for
|
||||
** reading CSV files.
|
||||
**
|
||||
** Usage:
|
||||
**
|
||||
** .load ./csv
|
||||
** CREATE VIRTUAL TABLE temp.csv USING csv(filename=FILENAME);
|
||||
** SELECT * FROM csv;
|
||||
**
|
||||
** The columns are named "c1", "c2", "c3", ... by default. Or the
|
||||
** application can define its own CREATE TABLE statement using the
|
||||
** schema= parameter, like this:
|
||||
**
|
||||
** CREATE VIRTUAL TABLE temp.csv2 USING csv(
|
||||
** filename = "../http.log",
|
||||
** schema = "CREATE TABLE x(date,ipaddr,url,referrer,userAgent)"
|
||||
** );
|
||||
**
|
||||
** Instead of specifying a file, the text of the CSV can be loaded using
|
||||
** the data= parameter.
|
||||
**
|
||||
** If the columns=N parameter is supplied, then the CSV file is assumed to have
|
||||
** N columns. If both the columns= and schema= parameters are omitted, then
|
||||
** the number and names of the columns is determined by the first line of
|
||||
** the CSV input.
|
||||
**
|
||||
** Some extra debugging features (used for testing virtual tables) are available
|
||||
** if this module is compiled with -DSQLITE_TEST.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/*
|
||||
** A macro to hint to the compiler that a function should not be
|
||||
** inlined.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
# define CSV_NOINLINE __attribute__((noinline))
|
||||
#elif defined(_MSC_VER) && _MSC_VER>=1310
|
||||
# define CSV_NOINLINE __declspec(noinline)
|
||||
#else
|
||||
# define CSV_NOINLINE
|
||||
#endif
|
||||
|
||||
|
||||
/* Max size of the error message in a CsvReader */
|
||||
#define CSV_MXERR 200
|
||||
|
||||
/* Size of the CsvReader input buffer */
|
||||
#define CSV_INBUFSZ 1024
|
||||
|
||||
/* A context object used when read a CSV file. */
|
||||
typedef struct CsvReader CsvReader;
|
||||
struct CsvReader {
|
||||
FILE *in; /* Read the CSV text from this input stream */
|
||||
char *z; /* Accumulated text for a field */
|
||||
int n; /* Number of bytes in z */
|
||||
int nAlloc; /* Space allocated for z[] */
|
||||
int nLine; /* Current line number */
|
||||
int bNotFirst; /* True if prior text has been seen */
|
||||
int cTerm; /* Character that terminated the most recent field */
|
||||
size_t iIn; /* Next unread character in the input buffer */
|
||||
size_t nIn; /* Number of characters in the input buffer */
|
||||
char *zIn; /* The input buffer */
|
||||
char zErr[CSV_MXERR]; /* Error message */
|
||||
};
|
||||
|
||||
/* Initialize a CsvReader object */
|
||||
static void csv_reader_init(CsvReader *p){
|
||||
p->in = 0;
|
||||
p->z = 0;
|
||||
p->n = 0;
|
||||
p->nAlloc = 0;
|
||||
p->nLine = 0;
|
||||
p->bNotFirst = 0;
|
||||
p->nIn = 0;
|
||||
p->zIn = 0;
|
||||
p->zErr[0] = 0;
|
||||
}
|
||||
|
||||
/* Close and reset a CsvReader object */
|
||||
static void csv_reader_reset(CsvReader *p){
|
||||
if( p->in ){
|
||||
fclose(p->in);
|
||||
sqlite3_free(p->zIn);
|
||||
}
|
||||
sqlite3_free(p->z);
|
||||
csv_reader_init(p);
|
||||
}
|
||||
|
||||
/* Report an error on a CsvReader */
|
||||
static void csv_errmsg(CsvReader *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
sqlite3_vsnprintf(CSV_MXERR, p->zErr, zFormat, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* Open the file associated with a CsvReader
|
||||
** Return the number of errors.
|
||||
*/
|
||||
static int csv_reader_open(
|
||||
CsvReader *p, /* The reader to open */
|
||||
const char *zFilename, /* Read from this filename */
|
||||
const char *zData /* ... or use this data */
|
||||
){
|
||||
if( zFilename ){
|
||||
p->zIn = sqlite3_malloc( CSV_INBUFSZ );
|
||||
if( p->zIn==0 ){
|
||||
csv_errmsg(p, "out of memory");
|
||||
return 1;
|
||||
}
|
||||
p->in = fopen(zFilename, "rb");
|
||||
if( p->in==0 ){
|
||||
sqlite3_free(p->zIn);
|
||||
csv_reader_reset(p);
|
||||
csv_errmsg(p, "cannot open '%s' for reading", zFilename);
|
||||
return 1;
|
||||
}
|
||||
}else{
|
||||
assert( p->in==0 );
|
||||
p->zIn = (char*)zData;
|
||||
p->nIn = strlen(zData);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The input buffer has overflowed. Refill the input buffer, then
|
||||
** return the next character
|
||||
*/
|
||||
static CSV_NOINLINE int csv_getc_refill(CsvReader *p){
|
||||
size_t got;
|
||||
|
||||
assert( p->iIn>=p->nIn ); /* Only called on an empty input buffer */
|
||||
assert( p->in!=0 ); /* Only called if reading froma file */
|
||||
|
||||
got = fread(p->zIn, 1, CSV_INBUFSZ, p->in);
|
||||
if( got==0 ) return EOF;
|
||||
p->nIn = got;
|
||||
p->iIn = 1;
|
||||
return p->zIn[0];
|
||||
}
|
||||
|
||||
/* Return the next character of input. Return EOF at end of input. */
|
||||
static int csv_getc(CsvReader *p){
|
||||
if( p->iIn >= p->nIn ){
|
||||
if( p->in!=0 ) return csv_getc_refill(p);
|
||||
return EOF;
|
||||
}
|
||||
return ((unsigned char*)p->zIn)[p->iIn++];
|
||||
}
|
||||
|
||||
/* Increase the size of p->z and append character c to the end.
|
||||
** Return 0 on success and non-zero if there is an OOM error */
|
||||
static CSV_NOINLINE int csv_resize_and_append(CsvReader *p, char c){
|
||||
char *zNew;
|
||||
int nNew = p->nAlloc*2 + 100;
|
||||
zNew = sqlite3_realloc64(p->z, nNew);
|
||||
if( zNew ){
|
||||
p->z = zNew;
|
||||
p->nAlloc = nNew;
|
||||
p->z[p->n++] = c;
|
||||
return 0;
|
||||
}else{
|
||||
csv_errmsg(p, "out of memory");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Append a single character to the CsvReader.z[] array.
|
||||
** Return 0 on success and non-zero if there is an OOM error */
|
||||
static int csv_append(CsvReader *p, char c){
|
||||
if( p->n>=p->nAlloc-1 ) return csv_resize_and_append(p, c);
|
||||
p->z[p->n++] = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read a single field of CSV text. Compatible with rfc4180 and extended
|
||||
** with the option of having a separator other than ",".
|
||||
**
|
||||
** + Input comes from p->in.
|
||||
** + Store results in p->z of length p->n. Space to hold p->z comes
|
||||
** from sqlite3_malloc64().
|
||||
** + Keep track of the line number in p->nLine.
|
||||
** + Store the character that terminates the field in p->cTerm. Store
|
||||
** EOF on end-of-file.
|
||||
**
|
||||
** Return 0 at EOF or on OOM. On EOF, the p->cTerm character will have
|
||||
** been set to EOF.
|
||||
*/
|
||||
static char *csv_read_one_field(CsvReader *p){
|
||||
int c;
|
||||
p->n = 0;
|
||||
c = csv_getc(p);
|
||||
if( c==EOF ){
|
||||
p->cTerm = EOF;
|
||||
return 0;
|
||||
}
|
||||
if( c=='"' ){
|
||||
int pc, ppc;
|
||||
int startLine = p->nLine;
|
||||
pc = ppc = 0;
|
||||
while( 1 ){
|
||||
c = csv_getc(p);
|
||||
if( c<='"' || pc=='"' ){
|
||||
if( c=='\n' ) p->nLine++;
|
||||
if( c=='"' ){
|
||||
if( pc=='"' ){
|
||||
pc = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if( (c==',' && pc=='"')
|
||||
|| (c=='\n' && pc=='"')
|
||||
|| (c=='\n' && pc=='\r' && ppc=='"')
|
||||
|| (c==EOF && pc=='"')
|
||||
){
|
||||
do{ p->n--; }while( p->z[p->n]!='"' );
|
||||
p->cTerm = (char)c;
|
||||
break;
|
||||
}
|
||||
if( pc=='"' && c!='\r' ){
|
||||
csv_errmsg(p, "line %d: unescaped %c character", p->nLine, '"');
|
||||
break;
|
||||
}
|
||||
if( c==EOF ){
|
||||
csv_errmsg(p, "line %d: unterminated %c-quoted field\n",
|
||||
startLine, '"');
|
||||
p->cTerm = (char)c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( csv_append(p, (char)c) ) return 0;
|
||||
ppc = pc;
|
||||
pc = c;
|
||||
}
|
||||
}else{
|
||||
/* If this is the first field being parsed and it begins with the
|
||||
** UTF-8 BOM (0xEF BB BF) then skip the BOM */
|
||||
if( (c&0xff)==0xef && p->bNotFirst==0 ){
|
||||
csv_append(p, (char)c);
|
||||
c = csv_getc(p);
|
||||
if( (c&0xff)==0xbb ){
|
||||
csv_append(p, (char)c);
|
||||
c = csv_getc(p);
|
||||
if( (c&0xff)==0xbf ){
|
||||
p->bNotFirst = 1;
|
||||
p->n = 0;
|
||||
return csv_read_one_field(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
while( c>',' || (c!=EOF && c!=',' && c!='\n') ){
|
||||
if( csv_append(p, (char)c) ) return 0;
|
||||
c = csv_getc(p);
|
||||
}
|
||||
if( c=='\n' ){
|
||||
p->nLine++;
|
||||
if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
|
||||
}
|
||||
p->cTerm = (char)c;
|
||||
}
|
||||
if( p->z ) p->z[p->n] = 0;
|
||||
p->bNotFirst = 1;
|
||||
return p->z;
|
||||
}
|
||||
|
||||
|
||||
/* Forward references to the various virtual table methods implemented
|
||||
** in this file. */
|
||||
static int csvtabCreate(sqlite3*, void*, int, const char*const*,
|
||||
sqlite3_vtab**,char**);
|
||||
static int csvtabConnect(sqlite3*, void*, int, const char*const*,
|
||||
sqlite3_vtab**,char**);
|
||||
static int csvtabBestIndex(sqlite3_vtab*,sqlite3_index_info*);
|
||||
static int csvtabDisconnect(sqlite3_vtab*);
|
||||
static int csvtabOpen(sqlite3_vtab*, sqlite3_vtab_cursor**);
|
||||
static int csvtabClose(sqlite3_vtab_cursor*);
|
||||
static int csvtabFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv);
|
||||
static int csvtabNext(sqlite3_vtab_cursor*);
|
||||
static int csvtabEof(sqlite3_vtab_cursor*);
|
||||
static int csvtabColumn(sqlite3_vtab_cursor*,sqlite3_context*,int);
|
||||
static int csvtabRowid(sqlite3_vtab_cursor*,sqlite3_int64*);
|
||||
|
||||
/* An instance of the CSV virtual table */
|
||||
typedef struct CsvTable {
|
||||
sqlite3_vtab base; /* Base class. Must be first */
|
||||
char *zFilename; /* Name of the CSV file */
|
||||
char *zData; /* Raw CSV data in lieu of zFilename */
|
||||
long iStart; /* Offset to start of data in zFilename */
|
||||
int nCol; /* Number of columns in the CSV file */
|
||||
unsigned int tstFlags; /* Bit values used for testing */
|
||||
} CsvTable;
|
||||
|
||||
/* Allowed values for tstFlags */
|
||||
#define CSVTEST_FIDX 0x0001 /* Pretend that constrained searchs cost less*/
|
||||
|
||||
/* A cursor for the CSV virtual table */
|
||||
typedef struct CsvCursor {
|
||||
sqlite3_vtab_cursor base; /* Base class. Must be first */
|
||||
CsvReader rdr; /* The CsvReader object */
|
||||
char **azVal; /* Value of the current row */
|
||||
int *aLen; /* Length of each entry */
|
||||
sqlite3_int64 iRowid; /* The current rowid. Negative for EOF */
|
||||
} CsvCursor;
|
||||
|
||||
/* Transfer error message text from a reader into a CsvTable */
|
||||
static void csv_xfer_error(CsvTable *pTab, CsvReader *pRdr){
|
||||
sqlite3_free(pTab->base.zErrMsg);
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("%s", pRdr->zErr);
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is the destructor fo a CsvTable object.
|
||||
*/
|
||||
static int csvtabDisconnect(sqlite3_vtab *pVtab){
|
||||
CsvTable *p = (CsvTable*)pVtab;
|
||||
sqlite3_free(p->zFilename);
|
||||
sqlite3_free(p->zData);
|
||||
sqlite3_free(p);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Skip leading whitespace. Return a pointer to the first non-whitespace
|
||||
** character, or to the zero terminator if the string has only whitespace */
|
||||
static const char *csv_skip_whitespace(const char *z){
|
||||
while( isspace((unsigned char)z[0]) ) z++;
|
||||
return z;
|
||||
}
|
||||
|
||||
/* Remove trailing whitespace from the end of string z[] */
|
||||
static void csv_trim_whitespace(char *z){
|
||||
size_t n = strlen(z);
|
||||
while( n>0 && isspace((unsigned char)z[n]) ) n--;
|
||||
z[n] = 0;
|
||||
}
|
||||
|
||||
/* Dequote the string */
|
||||
static void csv_dequote(char *z){
|
||||
int j;
|
||||
char cQuote = z[0];
|
||||
size_t i, n;
|
||||
|
||||
if( cQuote!='\'' && cQuote!='"' ) return;
|
||||
n = strlen(z);
|
||||
if( n<2 || z[n-1]!=z[0] ) return;
|
||||
for(i=1, j=0; i<n-1; i++){
|
||||
if( z[i]==cQuote && z[i+1]==cQuote ) i++;
|
||||
z[j++] = z[i];
|
||||
}
|
||||
z[j] = 0;
|
||||
}
|
||||
|
||||
/* Check to see if the string is of the form: "TAG = VALUE" with optional
|
||||
** whitespace before and around tokens. If it is, return a pointer to the
|
||||
** first character of VALUE. If it is not, return NULL.
|
||||
*/
|
||||
static const char *csv_parameter(const char *zTag, int nTag, const char *z){
|
||||
z = csv_skip_whitespace(z);
|
||||
if( strncmp(zTag, z, nTag)!=0 ) return 0;
|
||||
z = csv_skip_whitespace(z+nTag);
|
||||
if( z[0]!='=' ) return 0;
|
||||
return csv_skip_whitespace(z+1);
|
||||
}
|
||||
|
||||
/* Decode a parameter that requires a dequoted string.
|
||||
**
|
||||
** Return 1 if the parameter is seen, or 0 if not. 1 is returned
|
||||
** even if there is an error. If an error occurs, then an error message
|
||||
** is left in p->zErr. If there are no errors, p->zErr[0]==0.
|
||||
*/
|
||||
static int csv_string_parameter(
|
||||
CsvReader *p, /* Leave the error message here, if there is one */
|
||||
const char *zParam, /* Parameter we are checking for */
|
||||
const char *zArg, /* Raw text of the virtual table argment */
|
||||
char **pzVal /* Write the dequoted string value here */
|
||||
){
|
||||
const char *zValue;
|
||||
zValue = csv_parameter(zParam,(int)strlen(zParam),zArg);
|
||||
if( zValue==0 ) return 0;
|
||||
p->zErr[0] = 0;
|
||||
if( *pzVal ){
|
||||
csv_errmsg(p, "more than one '%s' parameter", zParam);
|
||||
return 1;
|
||||
}
|
||||
*pzVal = sqlite3_mprintf("%s", zValue);
|
||||
if( *pzVal==0 ){
|
||||
csv_errmsg(p, "out of memory");
|
||||
return 1;
|
||||
}
|
||||
csv_trim_whitespace(*pzVal);
|
||||
csv_dequote(*pzVal);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Return 0 if the argument is false and 1 if it is true. Return -1 if
|
||||
** we cannot really tell.
|
||||
*/
|
||||
static int csv_boolean(const char *z){
|
||||
if( sqlite3_stricmp("yes",z)==0
|
||||
|| sqlite3_stricmp("on",z)==0
|
||||
|| sqlite3_stricmp("true",z)==0
|
||||
|| (z[0]=='1' && z[1]==0)
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3_stricmp("no",z)==0
|
||||
|| sqlite3_stricmp("off",z)==0
|
||||
|| sqlite3_stricmp("false",z)==0
|
||||
|| (z[0]=='0' && z[1]==0)
|
||||
){
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check to see if the string is of the form: "TAG = BOOLEAN" or just "TAG".
|
||||
** If it is, set *pValue to be the value of the boolean ("true" if there is
|
||||
** not "= BOOLEAN" component) and return non-zero. If the input string
|
||||
** does not begin with TAG, return zero.
|
||||
*/
|
||||
static int csv_boolean_parameter(
|
||||
const char *zTag, /* Tag we are looking for */
|
||||
int nTag, /* Size of the tag in bytes */
|
||||
const char *z, /* Input parameter */
|
||||
int *pValue /* Write boolean value here */
|
||||
){
|
||||
int b;
|
||||
z = csv_skip_whitespace(z);
|
||||
if( strncmp(zTag, z, nTag)!=0 ) return 0;
|
||||
z = csv_skip_whitespace(z + nTag);
|
||||
if( z[0]==0 ){
|
||||
*pValue = 1;
|
||||
return 1;
|
||||
}
|
||||
if( z[0]!='=' ) return 0;
|
||||
z = csv_skip_whitespace(z+1);
|
||||
b = csv_boolean(z);
|
||||
if( b>=0 ){
|
||||
*pValue = b;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Parameters:
|
||||
** filename=FILENAME Name of file containing CSV content
|
||||
** data=TEXT Direct CSV content.
|
||||
** schema=SCHEMA Alternative CSV schema.
|
||||
** header=YES|NO First row of CSV defines the names of
|
||||
** columns if "yes". Default "no".
|
||||
** columns=N Assume the CSV file contains N columns.
|
||||
**
|
||||
** Only available if compiled with SQLITE_TEST:
|
||||
**
|
||||
** testflags=N Bitmask of test flags. Optional
|
||||
**
|
||||
** If schema= is omitted, then the columns are named "c0", "c1", "c2",
|
||||
** and so forth. If columns=N is omitted, then the file is opened and
|
||||
** the number of columns in the first row is counted to determine the
|
||||
** column count. If header=YES, then the first row is skipped.
|
||||
*/
|
||||
static int csvtabConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
CsvTable *pNew = 0; /* The CsvTable object to construct */
|
||||
int bHeader = -1; /* header= flags. -1 means not seen yet */
|
||||
int rc = SQLITE_OK; /* Result code from this routine */
|
||||
int i, j; /* Loop counters */
|
||||
#ifdef SQLITE_TEST
|
||||
int tstFlags = 0; /* Value for testflags=N parameter */
|
||||
#endif
|
||||
int b; /* Value of a boolean parameter */
|
||||
int nCol = -99; /* Value of the columns= parameter */
|
||||
CsvReader sRdr; /* A CSV file reader used to store an error
|
||||
** message and/or to count the number of columns */
|
||||
static const char *azParam[] = {
|
||||
"filename", "data", "schema",
|
||||
};
|
||||
char *azPValue[3]; /* Parameter values */
|
||||
# define CSV_FILENAME (azPValue[0])
|
||||
# define CSV_DATA (azPValue[1])
|
||||
# define CSV_SCHEMA (azPValue[2])
|
||||
|
||||
|
||||
assert( sizeof(azPValue)==sizeof(azParam) );
|
||||
memset(&sRdr, 0, sizeof(sRdr));
|
||||
memset(azPValue, 0, sizeof(azPValue));
|
||||
for(i=3; i<argc; i++){
|
||||
const char *z = argv[i];
|
||||
const char *zValue;
|
||||
for(j=0; j<sizeof(azParam)/sizeof(azParam[0]); j++){
|
||||
if( csv_string_parameter(&sRdr, azParam[j], z, &azPValue[j]) ) break;
|
||||
}
|
||||
if( j<sizeof(azParam)/sizeof(azParam[0]) ){
|
||||
if( sRdr.zErr[0] ) goto csvtab_connect_error;
|
||||
}else
|
||||
if( csv_boolean_parameter("header",6,z,&b) ){
|
||||
if( bHeader>=0 ){
|
||||
csv_errmsg(&sRdr, "more than one 'header' parameter");
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
bHeader = b;
|
||||
}else
|
||||
#ifdef SQLITE_TEST
|
||||
if( (zValue = csv_parameter("testflags",9,z))!=0 ){
|
||||
tstFlags = (unsigned int)atoi(zValue);
|
||||
}else
|
||||
#endif
|
||||
if( (zValue = csv_parameter("columns",7,z))!=0 ){
|
||||
if( nCol>0 ){
|
||||
csv_errmsg(&sRdr, "more than one 'columns' parameter");
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
nCol = atoi(zValue);
|
||||
if( nCol<=0 ){
|
||||
csv_errmsg(&sRdr, "column= value must be positive");
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
}else
|
||||
{
|
||||
csv_errmsg(&sRdr, "bad parameter: '%s'", z);
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
}
|
||||
if( (CSV_FILENAME==0)==(CSV_DATA==0) ){
|
||||
csv_errmsg(&sRdr, "must specify either filename= or data= but not both");
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
|
||||
if( (nCol<=0 || bHeader==1)
|
||||
&& csv_reader_open(&sRdr, CSV_FILENAME, CSV_DATA)
|
||||
){
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) goto csvtab_connect_oom;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
if( CSV_SCHEMA==0 ){
|
||||
sqlite3_str *pStr = sqlite3_str_new(0);
|
||||
char *zSep = "";
|
||||
int iCol = 0;
|
||||
sqlite3_str_appendf(pStr, "CREATE TABLE x(");
|
||||
if( nCol<0 && bHeader<1 ){
|
||||
nCol = 0;
|
||||
do{
|
||||
csv_read_one_field(&sRdr);
|
||||
nCol++;
|
||||
}while( sRdr.cTerm==',' );
|
||||
}
|
||||
if( nCol>0 && bHeader<1 ){
|
||||
for(iCol=0; iCol<nCol; iCol++){
|
||||
sqlite3_str_appendf(pStr, "%sc%d TEXT", zSep, iCol);
|
||||
zSep = ",";
|
||||
}
|
||||
}else{
|
||||
do{
|
||||
char *z = csv_read_one_field(&sRdr);
|
||||
if( (nCol>0 && iCol<nCol) || (nCol<0 && bHeader) ){
|
||||
sqlite3_str_appendf(pStr,"%s\"%w\" TEXT", zSep, z);
|
||||
zSep = ",";
|
||||
iCol++;
|
||||
}
|
||||
}while( sRdr.cTerm==',' );
|
||||
if( nCol<0 ){
|
||||
nCol = iCol;
|
||||
}else{
|
||||
while( iCol<nCol ){
|
||||
sqlite3_str_appendf(pStr,"%sc%d TEXT", zSep, ++iCol);
|
||||
zSep = ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
pNew->nCol = nCol;
|
||||
sqlite3_str_appendf(pStr, ")");
|
||||
CSV_SCHEMA = sqlite3_str_finish(pStr);
|
||||
if( CSV_SCHEMA==0 ) goto csvtab_connect_oom;
|
||||
}else if( nCol<0 ){
|
||||
do{
|
||||
csv_read_one_field(&sRdr);
|
||||
pNew->nCol++;
|
||||
}while( sRdr.cTerm==',' );
|
||||
}else{
|
||||
pNew->nCol = nCol;
|
||||
}
|
||||
pNew->zFilename = CSV_FILENAME; CSV_FILENAME = 0;
|
||||
pNew->zData = CSV_DATA; CSV_DATA = 0;
|
||||
#ifdef SQLITE_TEST
|
||||
pNew->tstFlags = tstFlags;
|
||||
#endif
|
||||
if( bHeader!=1 ){
|
||||
pNew->iStart = 0;
|
||||
}else if( pNew->zData ){
|
||||
pNew->iStart = (int)sRdr.iIn;
|
||||
}else{
|
||||
pNew->iStart = (int)(ftell(sRdr.in) - sRdr.nIn + sRdr.iIn);
|
||||
}
|
||||
csv_reader_reset(&sRdr);
|
||||
rc = sqlite3_declare_vtab(db, CSV_SCHEMA);
|
||||
if( rc ){
|
||||
csv_errmsg(&sRdr, "bad schema: '%s' - %s", CSV_SCHEMA, sqlite3_errmsg(db));
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
for(i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){
|
||||
sqlite3_free(azPValue[i]);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
|
||||
csvtab_connect_oom:
|
||||
rc = SQLITE_NOMEM;
|
||||
csv_errmsg(&sRdr, "out of memory");
|
||||
|
||||
csvtab_connect_error:
|
||||
if( pNew ) csvtabDisconnect(&pNew->base);
|
||||
for(i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){
|
||||
sqlite3_free(azPValue[i]);
|
||||
}
|
||||
if( sRdr.zErr[0] ){
|
||||
sqlite3_free(*pzErr);
|
||||
*pzErr = sqlite3_mprintf("%s", sRdr.zErr);
|
||||
}
|
||||
csv_reader_reset(&sRdr);
|
||||
if( rc==SQLITE_OK ) rc = SQLITE_ERROR;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Reset the current row content held by a CsvCursor.
|
||||
*/
|
||||
static void csvtabCursorRowReset(CsvCursor *pCur){
|
||||
CsvTable *pTab = (CsvTable*)pCur->base.pVtab;
|
||||
int i;
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
sqlite3_free(pCur->azVal[i]);
|
||||
pCur->azVal[i] = 0;
|
||||
pCur->aLen[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The xConnect and xCreate methods do the same thing, but they must be
|
||||
** different so that the virtual table is not an eponymous virtual table.
|
||||
*/
|
||||
static int csvtabCreate(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
return csvtabConnect(db, pAux, argc, argv, ppVtab, pzErr);
|
||||
}
|
||||
|
||||
/*
|
||||
** Destructor for a CsvCursor.
|
||||
*/
|
||||
static int csvtabClose(sqlite3_vtab_cursor *cur){
|
||||
CsvCursor *pCur = (CsvCursor*)cur;
|
||||
csvtabCursorRowReset(pCur);
|
||||
csv_reader_reset(&pCur->rdr);
|
||||
sqlite3_free(cur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Constructor for a new CsvTable cursor object.
|
||||
*/
|
||||
static int csvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
CsvTable *pTab = (CsvTable*)p;
|
||||
CsvCursor *pCur;
|
||||
size_t nByte;
|
||||
nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(int))*pTab->nCol;
|
||||
pCur = sqlite3_malloc64( nByte );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, nByte);
|
||||
pCur->azVal = (char**)&pCur[1];
|
||||
pCur->aLen = (int*)&pCur->azVal[pTab->nCol];
|
||||
*ppCursor = &pCur->base;
|
||||
if( csv_reader_open(&pCur->rdr, pTab->zFilename, pTab->zData) ){
|
||||
csv_xfer_error(pTab, &pCur->rdr);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Advance a CsvCursor to its next row of input.
|
||||
** Set the EOF marker if we reach the end of input.
|
||||
*/
|
||||
static int csvtabNext(sqlite3_vtab_cursor *cur){
|
||||
CsvCursor *pCur = (CsvCursor*)cur;
|
||||
CsvTable *pTab = (CsvTable*)cur->pVtab;
|
||||
int i = 0;
|
||||
char *z;
|
||||
do{
|
||||
z = csv_read_one_field(&pCur->rdr);
|
||||
if( z==0 ){
|
||||
break;
|
||||
}
|
||||
if( i<pTab->nCol ){
|
||||
if( pCur->aLen[i] < pCur->rdr.n+1 ){
|
||||
char *zNew = sqlite3_realloc64(pCur->azVal[i], pCur->rdr.n+1);
|
||||
if( zNew==0 ){
|
||||
csv_errmsg(&pCur->rdr, "out of memory");
|
||||
csv_xfer_error(pTab, &pCur->rdr);
|
||||
break;
|
||||
}
|
||||
pCur->azVal[i] = zNew;
|
||||
pCur->aLen[i] = pCur->rdr.n+1;
|
||||
}
|
||||
memcpy(pCur->azVal[i], z, pCur->rdr.n+1);
|
||||
i++;
|
||||
}
|
||||
}while( pCur->rdr.cTerm==',' );
|
||||
if( z==0 || (pCur->rdr.cTerm==EOF && i<pTab->nCol) ){
|
||||
pCur->iRowid = -1;
|
||||
}else{
|
||||
pCur->iRowid++;
|
||||
while( i<pTab->nCol ){
|
||||
sqlite3_free(pCur->azVal[i]);
|
||||
pCur->azVal[i] = 0;
|
||||
pCur->aLen[i] = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return values of columns for the row at which the CsvCursor
|
||||
** is currently pointing.
|
||||
*/
|
||||
static int csvtabColumn(
|
||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||
int i /* Which column to return */
|
||||
){
|
||||
CsvCursor *pCur = (CsvCursor*)cur;
|
||||
CsvTable *pTab = (CsvTable*)cur->pVtab;
|
||||
if( i>=0 && i<pTab->nCol && pCur->azVal[i]!=0 ){
|
||||
sqlite3_result_text(ctx, pCur->azVal[i], -1, SQLITE_STATIC);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the rowid for the current row.
|
||||
*/
|
||||
static int csvtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
CsvCursor *pCur = (CsvCursor*)cur;
|
||||
*pRowid = pCur->iRowid;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor has been moved off of the last
|
||||
** row of output.
|
||||
*/
|
||||
static int csvtabEof(sqlite3_vtab_cursor *cur){
|
||||
CsvCursor *pCur = (CsvCursor*)cur;
|
||||
return pCur->iRowid<0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Only a full table scan is supported. So xFilter simply rewinds to
|
||||
** the beginning.
|
||||
*/
|
||||
static int csvtabFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
CsvCursor *pCur = (CsvCursor*)pVtabCursor;
|
||||
CsvTable *pTab = (CsvTable*)pVtabCursor->pVtab;
|
||||
pCur->iRowid = 0;
|
||||
if( pCur->rdr.in==0 ){
|
||||
assert( pCur->rdr.zIn==pTab->zData );
|
||||
assert( pTab->iStart>=0 );
|
||||
assert( (size_t)pTab->iStart<=pCur->rdr.nIn );
|
||||
pCur->rdr.iIn = pTab->iStart;
|
||||
}else{
|
||||
fseek(pCur->rdr.in, pTab->iStart, SEEK_SET);
|
||||
pCur->rdr.iIn = 0;
|
||||
pCur->rdr.nIn = 0;
|
||||
}
|
||||
return csvtabNext(pVtabCursor);
|
||||
}
|
||||
|
||||
/*
|
||||
** Only a forward full table scan is supported. xBestIndex is mostly
|
||||
** a no-op. If CSVTEST_FIDX is set, then the presence of equality
|
||||
** constraints lowers the estimated cost, which is fiction, but is useful
|
||||
** for testing certain kinds of virtual table behavior.
|
||||
*/
|
||||
static int csvtabBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
pIdxInfo->estimatedCost = 1000000;
|
||||
#ifdef SQLITE_TEST
|
||||
if( (((CsvTable*)tab)->tstFlags & CSVTEST_FIDX)!=0 ){
|
||||
/* The usual (and sensible) case is to always do a full table scan.
|
||||
** The code in this branch only runs when testflags=1. This code
|
||||
** generates an artifical and unrealistic plan which is useful
|
||||
** for testing virtual table logic but is not helpful to real applications.
|
||||
**
|
||||
** Any ==, LIKE, or GLOB constraint is marked as usable by the virtual
|
||||
** table (even though it is not) and the cost of running the virtual table
|
||||
** is reduced from 1 million to just 10. The constraints are *not* marked
|
||||
** as omittable, however, so the query planner should still generate a
|
||||
** plan that gives a correct answer, even if they plan is not optimal.
|
||||
*/
|
||||
int i;
|
||||
int nConst = 0;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++){
|
||||
unsigned char op;
|
||||
if( pIdxInfo->aConstraint[i].usable==0 ) continue;
|
||||
op = pIdxInfo->aConstraint[i].op;
|
||||
if( op==SQLITE_INDEX_CONSTRAINT_EQ
|
||||
|| op==SQLITE_INDEX_CONSTRAINT_LIKE
|
||||
|| op==SQLITE_INDEX_CONSTRAINT_GLOB
|
||||
){
|
||||
pIdxInfo->estimatedCost = 10;
|
||||
pIdxInfo->aConstraintUsage[nConst].argvIndex = nConst+1;
|
||||
nConst++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
static sqlite3_module CsvModule = {
|
||||
0, /* iVersion */
|
||||
csvtabCreate, /* xCreate */
|
||||
csvtabConnect, /* xConnect */
|
||||
csvtabBestIndex, /* xBestIndex */
|
||||
csvtabDisconnect, /* xDisconnect */
|
||||
csvtabDisconnect, /* xDestroy */
|
||||
csvtabOpen, /* xOpen - open a cursor */
|
||||
csvtabClose, /* xClose - close a cursor */
|
||||
csvtabFilter, /* xFilter - configure scan constraints */
|
||||
csvtabNext, /* xNext - advance a cursor */
|
||||
csvtabEof, /* xEof - check for end of scan */
|
||||
csvtabColumn, /* xColumn - read data */
|
||||
csvtabRowid, /* xRowid - read data */
|
||||
0, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
};
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
/*
|
||||
** For virtual table testing, make a version of the CSV virtual table
|
||||
** available that has an xUpdate function. But the xUpdate always returns
|
||||
** SQLITE_READONLY since the CSV file is not really writable.
|
||||
*/
|
||||
static int csvtabUpdate(sqlite3_vtab *p,int n,sqlite3_value**v,sqlite3_int64*x){
|
||||
return SQLITE_READONLY;
|
||||
}
|
||||
static sqlite3_module CsvModuleFauxWrite = {
|
||||
0, /* iVersion */
|
||||
csvtabCreate, /* xCreate */
|
||||
csvtabConnect, /* xConnect */
|
||||
csvtabBestIndex, /* xBestIndex */
|
||||
csvtabDisconnect, /* xDisconnect */
|
||||
csvtabDisconnect, /* xDestroy */
|
||||
csvtabOpen, /* xOpen - open a cursor */
|
||||
csvtabClose, /* xClose - close a cursor */
|
||||
csvtabFilter, /* xFilter - configure scan constraints */
|
||||
csvtabNext, /* xNext - advance a cursor */
|
||||
csvtabEof, /* xEof - check for end of scan */
|
||||
csvtabColumn, /* xColumn - read data */
|
||||
csvtabRowid, /* xRowid - read data */
|
||||
csvtabUpdate, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
};
|
||||
#endif /* SQLITE_TEST */
|
||||
|
||||
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
/*
|
||||
** This routine is called when the extension is loaded. The new
|
||||
** CSV virtual table module is registered with the calling database
|
||||
** connection.
|
||||
*/
|
||||
int sqlite3_csv_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
int rc;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
rc = sqlite3_create_module(db, "csv", &CsvModule, 0);
|
||||
#ifdef SQLITE_TEST
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_module(db, "csv_wr", &CsvModuleFauxWrite, 0);
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
#else
|
||||
return SQLITE_OK;
|
||||
#endif
|
||||
}
|
||||
+1980
File diff suppressed because it is too large
Load Diff
+465
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
* fast-pbkdf2 - Optimal PBKDF2-HMAC calculation
|
||||
* Written in 2015 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#include "fastpbkdf2.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__clang__)
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#include "sha1.h"
|
||||
#include "sha2.h"
|
||||
|
||||
/* --- MSVC doesn't support C99 --- */
|
||||
#ifdef _MSC_VER
|
||||
#define restrict
|
||||
#define inline __inline
|
||||
#define _Pragma __pragma
|
||||
#endif
|
||||
|
||||
/* --- Common useful things --- */
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) > (b)) ? (b) : (a)
|
||||
#endif
|
||||
|
||||
static inline void write32_be(uint32_t n, uint8_t out[4])
|
||||
{
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4 && __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
*(uint32_t *)(out) = __builtin_bswap32(n);
|
||||
#else
|
||||
out[0] = (n >> 24) & 0xff;
|
||||
out[1] = (n >> 16) & 0xff;
|
||||
out[2] = (n >> 8) & 0xff;
|
||||
out[3] = n & 0xff;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void write64_be(uint64_t n, uint8_t out[8])
|
||||
{
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4 && __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
*(uint64_t *)(out) = __builtin_bswap64(n);
|
||||
#else
|
||||
write32_be((n >> 32) & 0xffffffff, out);
|
||||
write32_be(n & 0xffffffff, out + 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- Optional OpenMP parallelisation of consecutive blocks --- */
|
||||
#ifdef WITH_OPENMP
|
||||
# define OPENMP_PARALLEL_FOR _Pragma("omp parallel for")
|
||||
#else
|
||||
# define OPENMP_PARALLEL_FOR
|
||||
#endif
|
||||
|
||||
/* Prepare block (of blocksz bytes) to contain md padding denoting a msg-size
|
||||
* message (in bytes). block has a prefix of used bytes.
|
||||
*
|
||||
* Message length is expressed in 32 bits (so suitable for sha1, sha256, sha512). */
|
||||
static inline void md_pad(uint8_t *block, size_t blocksz, size_t used, size_t msg)
|
||||
{
|
||||
memset(block + used, 0, blocksz - used - 4);
|
||||
block[used] = 0x80;
|
||||
block += blocksz - 4;
|
||||
write32_be((uint32_t) (msg * 8), block);
|
||||
}
|
||||
|
||||
/* Internal function/type names for hash-specific things. */
|
||||
#define HMAC_CTX(_name) HMAC_ ## _name ## _ctx
|
||||
#define HMAC_INIT(_name) HMAC_ ## _name ## _init
|
||||
#define HMAC_UPDATE(_name) HMAC_ ## _name ## _update
|
||||
#define HMAC_FINAL(_name) HMAC_ ## _name ## _final
|
||||
|
||||
#define PBKDF2_F(_name) pbkdf2_f_ ## _name
|
||||
#define PBKDF2(_name) pbkdf2_ ## _name
|
||||
|
||||
/* This macro expands to decls for the whole implementation for a given
|
||||
* hash function. Arguments are:
|
||||
*
|
||||
* _name like 'sha1', added to symbol names
|
||||
* _blocksz block size, in bytes
|
||||
* _hashsz digest output, in bytes
|
||||
* _ctx hash context type
|
||||
* _init hash context initialisation function
|
||||
* args: (_ctx *c)
|
||||
* _update hash context update function
|
||||
* args: (_ctx *c, const void *data, size_t ndata)
|
||||
* _final hash context finish function
|
||||
* args: (void *out, _ctx *c)
|
||||
* _xform hash context raw block update function
|
||||
* args: (_ctx *c, const void *data)
|
||||
* _xcpy hash context raw copy function (only need copy hash state)
|
||||
* args: (_ctx * restrict out, const _ctx *restrict in)
|
||||
* _xtract hash context state extraction
|
||||
* args: args (_ctx *restrict c, uint8_t *restrict out)
|
||||
* _xxor hash context xor function (only need xor hash state)
|
||||
* args: (_ctx *restrict out, const _ctx *restrict in)
|
||||
*
|
||||
* The resulting function is named PBKDF2(_name).
|
||||
*/
|
||||
#define DECL_PBKDF2(_name, _blocksz, _hashsz, _ctx, \
|
||||
_init, _update, _xform, _final, _xcpy, _xtract, _xxor) \
|
||||
typedef struct { \
|
||||
_ctx inner; \
|
||||
_ctx outer; \
|
||||
} HMAC_CTX(_name); \
|
||||
\
|
||||
static inline void HMAC_INIT(_name)(HMAC_CTX(_name) *ctx, \
|
||||
const uint8_t *key, size_t nkey) \
|
||||
{ \
|
||||
/* Prepare key: */ \
|
||||
uint8_t k[_blocksz]; \
|
||||
\
|
||||
/* Shorten long keys. */ \
|
||||
if (nkey > _blocksz) \
|
||||
{ \
|
||||
_init(&ctx->inner); \
|
||||
_update(&ctx->inner, key, nkey); \
|
||||
_final(&ctx->inner, k); \
|
||||
\
|
||||
key = k; \
|
||||
nkey = _hashsz; \
|
||||
} \
|
||||
\
|
||||
/* Standard doesn't cover case where blocksz < hashsz. */ \
|
||||
assert(nkey <= _blocksz); \
|
||||
\
|
||||
/* Right zero-pad short keys. */ \
|
||||
if (k != key) \
|
||||
memcpy(k, key, nkey); \
|
||||
if (_blocksz > nkey) \
|
||||
memset(k + nkey, 0, _blocksz - nkey); \
|
||||
\
|
||||
{ \
|
||||
/* Start inner hash computation */ \
|
||||
uint8_t blk_inner[_blocksz]; \
|
||||
uint8_t blk_outer[_blocksz]; \
|
||||
size_t i; \
|
||||
\
|
||||
for (i = 0; i < _blocksz; i++) \
|
||||
{ \
|
||||
blk_inner[i] = 0x36 ^ k[i]; \
|
||||
blk_outer[i] = 0x5c ^ k[i]; \
|
||||
} \
|
||||
\
|
||||
_init(&ctx->inner); \
|
||||
_update(&ctx->inner, blk_inner, sizeof blk_inner); \
|
||||
\
|
||||
/* And outer. */ \
|
||||
_init(&ctx->outer); \
|
||||
_update(&ctx->outer, blk_outer, sizeof blk_outer); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void HMAC_UPDATE(_name)(HMAC_CTX(_name) *ctx, \
|
||||
const void *data, size_t ndata) \
|
||||
{ \
|
||||
_update(&ctx->inner, data, ndata); \
|
||||
} \
|
||||
\
|
||||
static inline void HMAC_FINAL(_name)(HMAC_CTX(_name) *ctx, \
|
||||
uint8_t out[_hashsz]) \
|
||||
{ \
|
||||
_final(&ctx->inner, out); \
|
||||
_update(&ctx->outer, out, _hashsz); \
|
||||
_final(&ctx->outer, out); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
/* --- PBKDF2 --- */ \
|
||||
static inline void PBKDF2_F(_name)(const HMAC_CTX(_name) *startctx, \
|
||||
uint32_t counter, \
|
||||
const uint8_t *salt, size_t nsalt, \
|
||||
uint32_t iterations, \
|
||||
uint8_t *out) \
|
||||
{ \
|
||||
uint8_t countbuf[4]; \
|
||||
uint8_t Ublock[_blocksz]; \
|
||||
HMAC_CTX(_name) ctx; \
|
||||
uint32_t i; \
|
||||
_ctx result; \
|
||||
\
|
||||
write32_be(counter, countbuf); \
|
||||
\
|
||||
/* Prepare loop-invariant padding block. */ \
|
||||
md_pad(Ublock, _blocksz, _hashsz, _blocksz + _hashsz); \
|
||||
\
|
||||
/* First iteration: \
|
||||
* U_1 = PRF(P, S || INT_32_BE(i)) \
|
||||
*/ \
|
||||
ctx = *startctx; \
|
||||
HMAC_UPDATE(_name)(&ctx, salt, nsalt); \
|
||||
HMAC_UPDATE(_name)(&ctx, countbuf, sizeof countbuf); \
|
||||
HMAC_FINAL(_name)(&ctx, Ublock); \
|
||||
result = ctx.outer; \
|
||||
\
|
||||
/* Subsequent iterations: \
|
||||
* U_c = PRF(P, U_{c-1}) \
|
||||
*/ \
|
||||
for (i = 1; i < iterations; i++) \
|
||||
{ \
|
||||
/* Complete inner hash with previous U */ \
|
||||
_xcpy(&ctx.inner, &startctx->inner); \
|
||||
_xform(&ctx.inner, Ublock); \
|
||||
_xtract(&ctx.inner, Ublock); \
|
||||
/* Complete outer hash with inner output */ \
|
||||
_xcpy(&ctx.outer, &startctx->outer); \
|
||||
_xform(&ctx.outer, Ublock); \
|
||||
_xtract(&ctx.outer, Ublock); \
|
||||
_xxor(&result, &ctx.outer); \
|
||||
} \
|
||||
\
|
||||
/* Reform result into output buffer. */ \
|
||||
_xtract(&result, out); \
|
||||
} \
|
||||
\
|
||||
static inline void PBKDF2(_name)(const uint8_t *pw, size_t npw, \
|
||||
const uint8_t *salt, size_t nsalt, \
|
||||
uint32_t iterations, \
|
||||
uint8_t *out, size_t nout) \
|
||||
{ \
|
||||
HMAC_CTX(_name) ctx; \
|
||||
uint32_t blocks_needed; \
|
||||
uint32_t counter; \
|
||||
assert(iterations); \
|
||||
assert(out && nout); \
|
||||
\
|
||||
/* Starting point for inner loop. */ \
|
||||
HMAC_INIT(_name)(&ctx, pw, npw); \
|
||||
\
|
||||
/* How many blocks do we need? */ \
|
||||
blocks_needed = (uint32_t)(nout + _hashsz - 1) / _hashsz; \
|
||||
\
|
||||
OPENMP_PARALLEL_FOR \
|
||||
for (counter = 1; counter <= blocks_needed; counter++) \
|
||||
{ \
|
||||
uint8_t block[_hashsz]; \
|
||||
size_t offset; \
|
||||
size_t taken; \
|
||||
PBKDF2_F(_name)(&ctx, counter, salt, nsalt, iterations, block); \
|
||||
\
|
||||
offset = (counter - 1) * _hashsz; \
|
||||
taken = MIN(nout - offset, _hashsz); \
|
||||
memcpy(out + offset, block, taken); \
|
||||
} \
|
||||
}
|
||||
|
||||
static inline void sha1_extract(sha1_ctx *restrict ctx, uint8_t *restrict out)
|
||||
{
|
||||
write32_be(ctx->h[0], out);
|
||||
write32_be(ctx->h[1], out + 4);
|
||||
write32_be(ctx->h[2], out + 8);
|
||||
write32_be(ctx->h[3], out + 12);
|
||||
write32_be(ctx->h[4], out + 16);
|
||||
}
|
||||
|
||||
static inline void sha1_cpy(sha1_ctx *restrict out, const sha1_ctx *restrict in)
|
||||
{
|
||||
out->h[0] = in->h[0];
|
||||
out->h[1] = in->h[1];
|
||||
out->h[2] = in->h[2];
|
||||
out->h[3] = in->h[3];
|
||||
out->h[4] = in->h[4];
|
||||
}
|
||||
|
||||
static inline void sha1_xor(sha1_ctx *restrict out, const sha1_ctx *restrict in)
|
||||
{
|
||||
out->h[0] ^= in->h[0];
|
||||
out->h[1] ^= in->h[1];
|
||||
out->h[2] ^= in->h[2];
|
||||
out->h[3] ^= in->h[3];
|
||||
out->h[4] ^= in->h[4];
|
||||
}
|
||||
|
||||
DECL_PBKDF2(sha1,
|
||||
SHA1_BLOCK_SIZE,
|
||||
SHA1_DIGEST_SIZE,
|
||||
sha1_ctx,
|
||||
sha1_init,
|
||||
sha1_update,
|
||||
sha1_transform,
|
||||
sha1_final,
|
||||
sha1_cpy,
|
||||
sha1_extract,
|
||||
sha1_xor)
|
||||
|
||||
static inline void sha256_extract(sha256_ctx *restrict ctx, uint8_t *restrict out)
|
||||
{
|
||||
write32_be(ctx->h[0], out);
|
||||
write32_be(ctx->h[1], out + 4);
|
||||
write32_be(ctx->h[2], out + 8);
|
||||
write32_be(ctx->h[3], out + 12);
|
||||
write32_be(ctx->h[4], out + 16);
|
||||
write32_be(ctx->h[5], out + 20);
|
||||
write32_be(ctx->h[6], out + 24);
|
||||
write32_be(ctx->h[7], out + 28);
|
||||
}
|
||||
|
||||
static inline void sha256_cpy(sha256_ctx *restrict out, const sha256_ctx *restrict in)
|
||||
{
|
||||
out->h[0] = in->h[0];
|
||||
out->h[1] = in->h[1];
|
||||
out->h[2] = in->h[2];
|
||||
out->h[3] = in->h[3];
|
||||
out->h[4] = in->h[4];
|
||||
out->h[5] = in->h[5];
|
||||
out->h[6] = in->h[6];
|
||||
out->h[7] = in->h[7];
|
||||
}
|
||||
|
||||
static inline void sha256_xor(sha256_ctx *restrict out, const sha256_ctx *restrict in)
|
||||
{
|
||||
out->h[0] ^= in->h[0];
|
||||
out->h[1] ^= in->h[1];
|
||||
out->h[2] ^= in->h[2];
|
||||
out->h[3] ^= in->h[3];
|
||||
out->h[4] ^= in->h[4];
|
||||
out->h[5] ^= in->h[5];
|
||||
out->h[6] ^= in->h[6];
|
||||
out->h[7] ^= in->h[7];
|
||||
}
|
||||
|
||||
DECL_PBKDF2(sha256,
|
||||
SHA256_BLOCK_SIZE,
|
||||
SHA256_DIGEST_SIZE,
|
||||
sha256_ctx,
|
||||
sha256_init,
|
||||
sha256_update,
|
||||
sha256_transform,
|
||||
sha256_final,
|
||||
sha256_cpy,
|
||||
sha256_extract,
|
||||
sha256_xor)
|
||||
|
||||
static inline void sha512_extract(sha512_ctx *restrict ctx, uint8_t *restrict out)
|
||||
{
|
||||
write64_be(ctx->h[0], out);
|
||||
write64_be(ctx->h[1], out + 8);
|
||||
write64_be(ctx->h[2], out + 16);
|
||||
write64_be(ctx->h[3], out + 24);
|
||||
write64_be(ctx->h[4], out + 32);
|
||||
write64_be(ctx->h[5], out + 40);
|
||||
write64_be(ctx->h[6], out + 48);
|
||||
write64_be(ctx->h[7], out + 56);
|
||||
}
|
||||
|
||||
static inline void sha512_cpy(sha512_ctx *restrict out, const sha512_ctx *restrict in)
|
||||
{
|
||||
out->h[0] = in->h[0];
|
||||
out->h[1] = in->h[1];
|
||||
out->h[2] = in->h[2];
|
||||
out->h[3] = in->h[3];
|
||||
out->h[4] = in->h[4];
|
||||
out->h[5] = in->h[5];
|
||||
out->h[6] = in->h[6];
|
||||
out->h[7] = in->h[7];
|
||||
}
|
||||
|
||||
static inline void sha512_xor(sha512_ctx *restrict out, const sha512_ctx *restrict in)
|
||||
{
|
||||
out->h[0] ^= in->h[0];
|
||||
out->h[1] ^= in->h[1];
|
||||
out->h[2] ^= in->h[2];
|
||||
out->h[3] ^= in->h[3];
|
||||
out->h[4] ^= in->h[4];
|
||||
out->h[5] ^= in->h[5];
|
||||
out->h[6] ^= in->h[6];
|
||||
out->h[7] ^= in->h[7];
|
||||
}
|
||||
|
||||
DECL_PBKDF2(sha512,
|
||||
SHA512_BLOCK_SIZE,
|
||||
SHA512_DIGEST_SIZE,
|
||||
sha512_ctx,
|
||||
sha512_init,
|
||||
sha512_update,
|
||||
sha512_transform,
|
||||
sha512_final,
|
||||
sha512_cpy,
|
||||
sha512_extract,
|
||||
sha512_xor)
|
||||
|
||||
void fastpbkdf2_hmac_sha1(const uint8_t *pw, size_t npw,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
uint32_t iterations,
|
||||
uint8_t *out, size_t nout)
|
||||
{
|
||||
PBKDF2(sha1)(pw, npw, salt, nsalt, iterations, out, nout);
|
||||
#if 0
|
||||
pbkdf2_sha1(pw, npw, salt, nsalt, iterations, out, nout);
|
||||
#endif
|
||||
}
|
||||
|
||||
void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
uint32_t iterations,
|
||||
uint8_t *out, size_t nout)
|
||||
{
|
||||
PBKDF2(sha256)(pw, npw, salt, nsalt, iterations, out, nout);
|
||||
}
|
||||
|
||||
void fastpbkdf2_hmac_sha512(const uint8_t *pw, size_t npw,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
uint32_t iterations,
|
||||
uint8_t *out, size_t nout)
|
||||
{
|
||||
PBKDF2(sha512)(pw, npw, salt, nsalt, iterations, out, nout);
|
||||
}
|
||||
|
||||
void sqlcipher_hmac(int algorithm, unsigned char* key, int nkey, unsigned char* in, int in_sz, unsigned char* in2, int in2_sz, unsigned char* out)
|
||||
{
|
||||
switch (algorithm)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
HMAC_sha1_ctx hctx;
|
||||
HMAC_sha1_init(&hctx, key, nkey);
|
||||
HMAC_sha1_update(&hctx, in, in_sz);
|
||||
if (in2 != NULL)
|
||||
{
|
||||
HMAC_sha1_update(&hctx, in2, in2_sz);
|
||||
}
|
||||
HMAC_sha1_final(&hctx, out);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
HMAC_sha256_ctx hctx;
|
||||
HMAC_sha256_init(&hctx, key, nkey);
|
||||
HMAC_sha256_update(&hctx, in, in_sz);
|
||||
if (in2 != NULL)
|
||||
{
|
||||
HMAC_sha256_update(&hctx, in2, in2_sz);
|
||||
}
|
||||
HMAC_sha256_final(&hctx, out);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
default:
|
||||
{
|
||||
HMAC_sha512_ctx hctx;
|
||||
HMAC_sha512_init(&hctx, key, nkey);
|
||||
HMAC_sha512_update(&hctx, in, in_sz);
|
||||
if (in2 != NULL)
|
||||
{
|
||||
HMAC_sha512_update(&hctx, in2, in2_sz);
|
||||
}
|
||||
HMAC_sha512_final(&hctx, out);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* fastpbkdf2 - Faster PBKDF2-HMAC calculation
|
||||
* Written in 2015 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef FASTPBKDF2_H
|
||||
#define FASTPBKDF2_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "mystdint.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Calculates PBKDF2-HMAC-SHA1.
|
||||
*
|
||||
* @p npw bytes at @p pw are the password input.
|
||||
* @p nsalt bytes at @p salt are the salt input.
|
||||
* @p iterations is the PBKDF2 iteration count and must be non-zero.
|
||||
* @p nout bytes of output are written to @p out. @p nout must be non-zero.
|
||||
*
|
||||
* This function cannot fail; it does not report errors.
|
||||
*/
|
||||
void fastpbkdf2_hmac_sha1(const uint8_t *pw, size_t npw,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
uint32_t iterations,
|
||||
uint8_t *out, size_t nout);
|
||||
|
||||
/** Calculates PBKDF2-HMAC-SHA256.
|
||||
*
|
||||
* @p npw bytes at @p pw are the password input.
|
||||
* @p nsalt bytes at @p salt are the salt input.
|
||||
* @p iterations is the PBKDF2 iteration count and must be non-zero.
|
||||
* @p nout bytes of output are written to @p out. @p nout must be non-zero.
|
||||
*
|
||||
* This function cannot fail; it does not report errors.
|
||||
*/
|
||||
void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
uint32_t iterations,
|
||||
uint8_t *out, size_t nout);
|
||||
|
||||
/** Calculates PBKDF2-HMAC-SHA512.
|
||||
*
|
||||
* @p npw bytes at @p pw are the password input.
|
||||
* @p nsalt bytes at @p salt are the salt input.
|
||||
* @p iterations is the PBKDF2 iteration count and must be non-zero.
|
||||
* @p nout bytes of output are written to @p out. @p nout must be non-zero.
|
||||
*
|
||||
* This function cannot fail; it does not report errors.
|
||||
*/
|
||||
void fastpbkdf2_hmac_sha512(const uint8_t *pw, size_t npw,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
uint32_t iterations,
|
||||
uint8_t *out, size_t nout);
|
||||
|
||||
/** Calculates SQLCipher HMAC.
|
||||
*
|
||||
* This function cannot fail; it does not report errors.
|
||||
*/
|
||||
void sqlcipher_hmac(int algorithm,
|
||||
unsigned char* key, int nkey,
|
||||
unsigned char* in, int in_sz,
|
||||
unsigned char* in2, int in2_sz,
|
||||
unsigned char* out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Vendored
+995
@@ -0,0 +1,995 @@
|
||||
/*
|
||||
** 2014-06-13
|
||||
**
|
||||
** 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 SQLite extension implements SQL functions readfile() and
|
||||
** writefile(), and eponymous virtual type "fsdir".
|
||||
**
|
||||
** WRITEFILE(FILE, DATA [, MODE [, MTIME]]):
|
||||
**
|
||||
** If neither of the optional arguments is present, then this UDF
|
||||
** function writes blob DATA to file FILE. If successful, the number
|
||||
** of bytes written is returned. If an error occurs, NULL is returned.
|
||||
**
|
||||
** If the first option argument - MODE - is present, then it must
|
||||
** be passed an integer value that corresponds to a POSIX mode
|
||||
** value (file type + permissions, as returned in the stat.st_mode
|
||||
** field by the stat() system call). Three types of files may
|
||||
** be written/created:
|
||||
**
|
||||
** regular files: (mode & 0170000)==0100000
|
||||
** symbolic links: (mode & 0170000)==0120000
|
||||
** directories: (mode & 0170000)==0040000
|
||||
**
|
||||
** For a directory, the DATA is ignored. For a symbolic link, it is
|
||||
** interpreted as text and used as the target of the link. For a
|
||||
** regular file, it is interpreted as a blob and written into the
|
||||
** named file. Regardless of the type of file, its permissions are
|
||||
** set to (mode & 0777) before returning.
|
||||
**
|
||||
** If the optional MTIME argument is present, then it is interpreted
|
||||
** as an integer - the number of seconds since the unix epoch. The
|
||||
** modification-time of the target file is set to this value before
|
||||
** returning.
|
||||
**
|
||||
** If three or more arguments are passed to this function and an
|
||||
** error is encountered, an exception is raised.
|
||||
**
|
||||
** READFILE(FILE):
|
||||
**
|
||||
** Read and return the contents of file FILE (type blob) from disk.
|
||||
**
|
||||
** FSDIR:
|
||||
**
|
||||
** Used as follows:
|
||||
**
|
||||
** SELECT * FROM fsdir($path [, $dir]);
|
||||
**
|
||||
** Parameter $path is an absolute or relative pathname. If the file that it
|
||||
** refers to does not exist, it is an error. If the path refers to a regular
|
||||
** file or symbolic link, it returns a single row. Or, if the path refers
|
||||
** to a directory, it returns one row for the directory, and one row for each
|
||||
** file within the hierarchy rooted at $path.
|
||||
**
|
||||
** Each row has the following columns:
|
||||
**
|
||||
** name: Path to file or directory (text value).
|
||||
** mode: Value of stat.st_mode for directory entry (an integer).
|
||||
** mtime: Value of stat.st_mtime for directory entry (an integer).
|
||||
** data: For a regular file, a blob containing the file data. For a
|
||||
** symlink, a text value containing the text of the link. For a
|
||||
** directory, NULL.
|
||||
**
|
||||
** If a non-NULL value is specified for the optional $dir parameter and
|
||||
** $path is a relative path, then $path is interpreted relative to $dir.
|
||||
** And the paths returned in the "name" column of the table are also
|
||||
** relative to directory $dir.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#if !defined(_WIN32) && !defined(WIN32)
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
# include <utime.h>
|
||||
# include <sys/time.h>
|
||||
#else
|
||||
# include "windows.h"
|
||||
# include <io.h>
|
||||
# include <direct.h>
|
||||
# include "test_windirent.h"
|
||||
# define dirent DIRENT
|
||||
# ifndef chmod
|
||||
# define chmod _chmod
|
||||
# endif
|
||||
# ifndef stat
|
||||
# define stat _stat
|
||||
# endif
|
||||
# define mkdir(path,mode) _mkdir(path)
|
||||
# define lstat(path,buf) stat(path,buf)
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
/*
|
||||
** Structure of the fsdir() table-valued function
|
||||
*/
|
||||
/* 0 1 2 3 4 5 */
|
||||
#define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)"
|
||||
#define FSDIR_COLUMN_NAME 0 /* Name of the file */
|
||||
#define FSDIR_COLUMN_MODE 1 /* Access mode */
|
||||
#define FSDIR_COLUMN_MTIME 2 /* Last modification time */
|
||||
#define FSDIR_COLUMN_DATA 3 /* File content */
|
||||
#define FSDIR_COLUMN_PATH 4 /* Path to top of search */
|
||||
#define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */
|
||||
|
||||
|
||||
/*
|
||||
** Set the result stored by context ctx to a blob containing the
|
||||
** contents of file zName. Or, leave the result unchanged (NULL)
|
||||
** if the file does not exist or is unreadable.
|
||||
**
|
||||
** If the file exceeds the SQLite blob size limit, through an
|
||||
** SQLITE_TOOBIG error.
|
||||
**
|
||||
** Throw an SQLITE_IOERR if there are difficulties pulling the file
|
||||
** off of disk.
|
||||
*/
|
||||
static void readFileContents(sqlite3_context *ctx, const char *zName){
|
||||
FILE *in;
|
||||
sqlite3_int64 nIn;
|
||||
void *pBuf;
|
||||
sqlite3 *db;
|
||||
int mxBlob;
|
||||
|
||||
in = fopen(zName, "rb");
|
||||
if( in==0 ){
|
||||
/* File does not exist or is unreadable. Leave the result set to NULL. */
|
||||
return;
|
||||
}
|
||||
fseek(in, 0, SEEK_END);
|
||||
nIn = ftell(in);
|
||||
rewind(in);
|
||||
db = sqlite3_context_db_handle(ctx);
|
||||
mxBlob = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, -1);
|
||||
if( nIn>mxBlob ){
|
||||
sqlite3_result_error_code(ctx, SQLITE_TOOBIG);
|
||||
fclose(in);
|
||||
return;
|
||||
}
|
||||
pBuf = sqlite3_malloc64( nIn ? nIn : 1 );
|
||||
if( pBuf==0 ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
fclose(in);
|
||||
return;
|
||||
}
|
||||
if( nIn==(sqlite3_int64)fread(pBuf, 1, (size_t)nIn, in) ){
|
||||
sqlite3_result_blob64(ctx, pBuf, nIn, sqlite3_free);
|
||||
}else{
|
||||
sqlite3_result_error_code(ctx, SQLITE_IOERR);
|
||||
sqlite3_free(pBuf);
|
||||
}
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the "readfile(X)" SQL function. The entire content
|
||||
** of the file named X is read and returned as a BLOB. NULL is returned
|
||||
** if the file does not exist or is unreadable.
|
||||
*/
|
||||
static void readfileFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zName;
|
||||
(void)(argc); /* Unused parameter */
|
||||
zName = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zName==0 ) return;
|
||||
readFileContents(context, zName);
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the error message contained in context ctx to the results of
|
||||
** vprintf(zFmt, ...).
|
||||
*/
|
||||
static void ctxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
|
||||
char *zMsg = 0;
|
||||
va_list ap;
|
||||
va_start(ap, zFmt);
|
||||
zMsg = sqlite3_vmprintf(zFmt, ap);
|
||||
sqlite3_result_error(ctx, zMsg, -1);
|
||||
sqlite3_free(zMsg);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
/*
|
||||
** This function is designed to convert a Win32 FILETIME structure into the
|
||||
** number of seconds since the Unix Epoch (1970-01-01 00:00:00 UTC).
|
||||
*/
|
||||
static sqlite3_uint64 fileTimeToUnixTime(
|
||||
LPFILETIME pFileTime
|
||||
){
|
||||
SYSTEMTIME epochSystemTime;
|
||||
ULARGE_INTEGER epochIntervals;
|
||||
FILETIME epochFileTime;
|
||||
ULARGE_INTEGER fileIntervals;
|
||||
|
||||
memset(&epochSystemTime, 0, sizeof(SYSTEMTIME));
|
||||
epochSystemTime.wYear = 1970;
|
||||
epochSystemTime.wMonth = 1;
|
||||
epochSystemTime.wDay = 1;
|
||||
SystemTimeToFileTime(&epochSystemTime, &epochFileTime);
|
||||
epochIntervals.LowPart = epochFileTime.dwLowDateTime;
|
||||
epochIntervals.HighPart = epochFileTime.dwHighDateTime;
|
||||
|
||||
fileIntervals.LowPart = pFileTime->dwLowDateTime;
|
||||
fileIntervals.HighPart = pFileTime->dwHighDateTime;
|
||||
|
||||
return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function attempts to normalize the time values found in the stat()
|
||||
** buffer to UTC. This is necessary on Win32, where the runtime library
|
||||
** appears to return these values as local times.
|
||||
*/
|
||||
static void statTimesToUtc(
|
||||
const char *zPath,
|
||||
struct stat *pStatBuf
|
||||
){
|
||||
HANDLE hFindFile;
|
||||
WIN32_FIND_DATAW fd;
|
||||
LPWSTR zUnicodeName;
|
||||
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
|
||||
zUnicodeName = sqlite3_win32_utf8_to_unicode(zPath);
|
||||
if( zUnicodeName ){
|
||||
memset(&fd, 0, sizeof(WIN32_FIND_DATAW));
|
||||
hFindFile = FindFirstFileW(zUnicodeName, &fd);
|
||||
if( hFindFile!=NULL ){
|
||||
pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime);
|
||||
pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime);
|
||||
pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime);
|
||||
FindClose(hFindFile);
|
||||
}
|
||||
sqlite3_free(zUnicodeName);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This function is used in place of stat(). On Windows, special handling
|
||||
** is required in order for the included time to be returned as UTC. On all
|
||||
** other systems, this function simply calls stat().
|
||||
*/
|
||||
static int fileStat(
|
||||
const char *zPath,
|
||||
struct stat *pStatBuf
|
||||
){
|
||||
#if defined(_WIN32)
|
||||
int rc = stat(zPath, pStatBuf);
|
||||
if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
|
||||
return rc;
|
||||
#else
|
||||
return stat(zPath, pStatBuf);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used in place of lstat(). On Windows, special handling
|
||||
** is required in order for the included time to be returned as UTC. On all
|
||||
** other systems, this function simply calls lstat().
|
||||
*/
|
||||
static int fileLinkStat(
|
||||
const char *zPath,
|
||||
struct stat *pStatBuf
|
||||
){
|
||||
#if defined(_WIN32)
|
||||
int rc = lstat(zPath, pStatBuf);
|
||||
if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
|
||||
return rc;
|
||||
#else
|
||||
return lstat(zPath, pStatBuf);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Argument zFile is the name of a file that will be created and/or written
|
||||
** by SQL function writefile(). This function ensures that the directory
|
||||
** zFile will be written to exists, creating it if required. The permissions
|
||||
** for any path components created by this function are set in accordance
|
||||
** with the current umask.
|
||||
**
|
||||
** If an OOM condition is encountered, SQLITE_NOMEM is returned. Otherwise,
|
||||
** SQLITE_OK is returned if the directory is successfully created, or
|
||||
** SQLITE_ERROR otherwise.
|
||||
*/
|
||||
static int makeDirectory(
|
||||
const char *zFile
|
||||
){
|
||||
char *zCopy = sqlite3_mprintf("%s", zFile);
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( zCopy==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
int nCopy = (int)strlen(zCopy);
|
||||
int i = 1;
|
||||
|
||||
while( rc==SQLITE_OK ){
|
||||
struct stat sStat;
|
||||
int rc2;
|
||||
|
||||
for(; zCopy[i]!='/' && i<nCopy; i++);
|
||||
if( i==nCopy ) break;
|
||||
zCopy[i] = '\0';
|
||||
|
||||
rc2 = fileStat(zCopy, &sStat);
|
||||
if( rc2!=0 ){
|
||||
if( mkdir(zCopy, 0777) ) rc = SQLITE_ERROR;
|
||||
}else{
|
||||
if( !S_ISDIR(sStat.st_mode) ) rc = SQLITE_ERROR;
|
||||
}
|
||||
zCopy[i] = '/';
|
||||
i++;
|
||||
}
|
||||
|
||||
sqlite3_free(zCopy);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function does the work for the writefile() UDF. Refer to
|
||||
** header comments at the top of this file for details.
|
||||
*/
|
||||
static int writeFile(
|
||||
sqlite3_context *pCtx, /* Context to return bytes written in */
|
||||
const char *zFile, /* File to write */
|
||||
sqlite3_value *pData, /* Data to write */
|
||||
mode_t mode, /* MODE parameter passed to writefile() */
|
||||
sqlite3_int64 mtime /* MTIME parameter (or -1 to not set time) */
|
||||
){
|
||||
#if !defined(_WIN32) && !defined(WIN32)
|
||||
if( S_ISLNK(mode) ){
|
||||
const char *zTo = (const char*)sqlite3_value_text(pData);
|
||||
if( symlink(zTo, zFile)<0 ) return 1;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
if( S_ISDIR(mode) ){
|
||||
if( mkdir(zFile, mode) ){
|
||||
/* The mkdir() call to create the directory failed. This might not
|
||||
** be an error though - if there is already a directory at the same
|
||||
** path and either the permissions already match or can be changed
|
||||
** to do so using chmod(), it is not an error. */
|
||||
struct stat sStat;
|
||||
if( errno!=EEXIST
|
||||
|| 0!=fileStat(zFile, &sStat)
|
||||
|| !S_ISDIR(sStat.st_mode)
|
||||
|| ((sStat.st_mode&0777)!=(mode&0777) && 0!=chmod(zFile, mode&0777))
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
sqlite3_int64 nWrite = 0;
|
||||
const char *z;
|
||||
int rc = 0;
|
||||
FILE *out = fopen(zFile, "wb");
|
||||
if( out==0 ) return 1;
|
||||
z = (const char*)sqlite3_value_blob(pData);
|
||||
if( z ){
|
||||
sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out);
|
||||
nWrite = sqlite3_value_bytes(pData);
|
||||
if( nWrite!=n ){
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
fclose(out);
|
||||
if( rc==0 && mode && chmod(zFile, mode & 0777) ){
|
||||
rc = 1;
|
||||
}
|
||||
if( rc ) return 2;
|
||||
sqlite3_result_int64(pCtx, nWrite);
|
||||
}
|
||||
}
|
||||
|
||||
if( mtime>=0 ){
|
||||
#if defined(_WIN32)
|
||||
/* Windows */
|
||||
FILETIME lastAccess;
|
||||
FILETIME lastWrite;
|
||||
SYSTEMTIME currentTime;
|
||||
LONGLONG intervals;
|
||||
HANDLE hFile;
|
||||
LPWSTR zUnicodeName;
|
||||
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
|
||||
|
||||
GetSystemTime(¤tTime);
|
||||
SystemTimeToFileTime(¤tTime, &lastAccess);
|
||||
intervals = Int32x32To64(mtime, 10000000) + 116444736000000000;
|
||||
lastWrite.dwLowDateTime = (DWORD)intervals;
|
||||
lastWrite.dwHighDateTime = intervals >> 32;
|
||||
zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile);
|
||||
if( zUnicodeName==0 ){
|
||||
return 1;
|
||||
}
|
||||
hFile = CreateFileW(
|
||||
zUnicodeName, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS, NULL
|
||||
);
|
||||
sqlite3_free(zUnicodeName);
|
||||
if( hFile!=INVALID_HANDLE_VALUE ){
|
||||
BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite);
|
||||
CloseHandle(hFile);
|
||||
return !bResult;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
#elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */
|
||||
/* Recent unix */
|
||||
struct timespec times[2];
|
||||
times[0].tv_nsec = times[1].tv_nsec = 0;
|
||||
times[0].tv_sec = time(0);
|
||||
times[1].tv_sec = mtime;
|
||||
if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
/* Legacy unix */
|
||||
struct timeval times[2];
|
||||
times[0].tv_usec = times[1].tv_usec = 0;
|
||||
times[0].tv_sec = time(0);
|
||||
times[1].tv_sec = mtime;
|
||||
if( utimes(zFile, times) ){
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function.
|
||||
** Refer to header comments at the top of this file for details.
|
||||
*/
|
||||
static void writefileFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zFile;
|
||||
mode_t mode = 0;
|
||||
int res;
|
||||
sqlite3_int64 mtime = -1;
|
||||
|
||||
if( argc<2 || argc>4 ){
|
||||
sqlite3_result_error(context,
|
||||
"wrong number of arguments to function writefile()", -1
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
zFile = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zFile==0 ) return;
|
||||
if( argc>=3 ){
|
||||
mode = (mode_t)sqlite3_value_int(argv[2]);
|
||||
}
|
||||
if( argc==4 ){
|
||||
mtime = sqlite3_value_int64(argv[3]);
|
||||
}
|
||||
|
||||
res = writeFile(context, zFile, argv[1], mode, mtime);
|
||||
if( res==1 && errno==ENOENT ){
|
||||
if( makeDirectory(zFile)==SQLITE_OK ){
|
||||
res = writeFile(context, zFile, argv[1], mode, mtime);
|
||||
}
|
||||
}
|
||||
|
||||
if( argc>2 && res!=0 ){
|
||||
if( S_ISLNK(mode) ){
|
||||
ctxErrorMsg(context, "failed to create symlink: %s", zFile);
|
||||
}else if( S_ISDIR(mode) ){
|
||||
ctxErrorMsg(context, "failed to create directory: %s", zFile);
|
||||
}else{
|
||||
ctxErrorMsg(context, "failed to write file: %s", zFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: lsmode(MODE)
|
||||
**
|
||||
** Given a numberic st_mode from stat(), convert it into a human-readable
|
||||
** text string in the style of "ls -l".
|
||||
*/
|
||||
static void lsModeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int i;
|
||||
int iMode = sqlite3_value_int(argv[0]);
|
||||
char z[16];
|
||||
(void)argc;
|
||||
if( S_ISLNK(iMode) ){
|
||||
z[0] = 'l';
|
||||
}else if( S_ISREG(iMode) ){
|
||||
z[0] = '-';
|
||||
}else if( S_ISDIR(iMode) ){
|
||||
z[0] = 'd';
|
||||
}else{
|
||||
z[0] = '?';
|
||||
}
|
||||
for(i=0; i<3; i++){
|
||||
int m = (iMode >> ((2-i)*3));
|
||||
char *a = &z[1 + i*3];
|
||||
a[0] = (m & 0x4) ? 'r' : '-';
|
||||
a[1] = (m & 0x2) ? 'w' : '-';
|
||||
a[2] = (m & 0x1) ? 'x' : '-';
|
||||
}
|
||||
z[10] = '\0';
|
||||
sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/*
|
||||
** Cursor type for recursively iterating through a directory structure.
|
||||
*/
|
||||
typedef struct fsdir_cursor fsdir_cursor;
|
||||
typedef struct FsdirLevel FsdirLevel;
|
||||
|
||||
struct FsdirLevel {
|
||||
DIR *pDir; /* From opendir() */
|
||||
char *zDir; /* Name of directory (nul-terminated) */
|
||||
};
|
||||
|
||||
struct fsdir_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
|
||||
int nLvl; /* Number of entries in aLvl[] array */
|
||||
int iLvl; /* Index of current entry */
|
||||
FsdirLevel *aLvl; /* Hierarchy of directories being traversed */
|
||||
|
||||
const char *zBase;
|
||||
int nBase;
|
||||
|
||||
struct stat sStat; /* Current lstat() results */
|
||||
char *zPath; /* Path to current entry */
|
||||
sqlite3_int64 iRowid; /* Current rowid */
|
||||
};
|
||||
|
||||
typedef struct fsdir_tab fsdir_tab;
|
||||
struct fsdir_tab {
|
||||
sqlite3_vtab base; /* Base class - must be first */
|
||||
};
|
||||
|
||||
/*
|
||||
** Construct a new fsdir virtual table object.
|
||||
*/
|
||||
static int fsdirConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
fsdir_tab *pNew = 0;
|
||||
int rc;
|
||||
(void)pAux;
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
(void)pzErr;
|
||||
rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA);
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
}
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is the destructor for fsdir vtab objects.
|
||||
*/
|
||||
static int fsdirDisconnect(sqlite3_vtab *pVtab){
|
||||
sqlite3_free(pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Constructor for a new fsdir_cursor object.
|
||||
*/
|
||||
static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
fsdir_cursor *pCur;
|
||||
(void)p;
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->iLvl = -1;
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Reset a cursor back to the state it was in when first returned
|
||||
** by fsdirOpen().
|
||||
*/
|
||||
static void fsdirResetCursor(fsdir_cursor *pCur){
|
||||
int i;
|
||||
for(i=0; i<=pCur->iLvl; i++){
|
||||
FsdirLevel *pLvl = &pCur->aLvl[i];
|
||||
if( pLvl->pDir ) closedir(pLvl->pDir);
|
||||
sqlite3_free(pLvl->zDir);
|
||||
}
|
||||
sqlite3_free(pCur->zPath);
|
||||
sqlite3_free(pCur->aLvl);
|
||||
pCur->aLvl = 0;
|
||||
pCur->zPath = 0;
|
||||
pCur->zBase = 0;
|
||||
pCur->nBase = 0;
|
||||
pCur->nLvl = 0;
|
||||
pCur->iLvl = -1;
|
||||
pCur->iRowid = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destructor for an fsdir_cursor.
|
||||
*/
|
||||
static int fsdirClose(sqlite3_vtab_cursor *cur){
|
||||
fsdir_cursor *pCur = (fsdir_cursor*)cur;
|
||||
|
||||
fsdirResetCursor(pCur);
|
||||
sqlite3_free(pCur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the error message for the virtual table associated with cursor
|
||||
** pCur to the results of vprintf(zFmt, ...).
|
||||
*/
|
||||
static void fsdirSetErrmsg(fsdir_cursor *pCur, const char *zFmt, ...){
|
||||
va_list ap;
|
||||
va_start(ap, zFmt);
|
||||
pCur->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Advance an fsdir_cursor to its next row of output.
|
||||
*/
|
||||
static int fsdirNext(sqlite3_vtab_cursor *cur){
|
||||
fsdir_cursor *pCur = (fsdir_cursor*)cur;
|
||||
mode_t m = pCur->sStat.st_mode;
|
||||
|
||||
pCur->iRowid++;
|
||||
if( S_ISDIR(m) ){
|
||||
/* Descend into this directory */
|
||||
int iNew = pCur->iLvl + 1;
|
||||
FsdirLevel *pLvl;
|
||||
if( iNew>=pCur->nLvl ){
|
||||
int nNew = iNew+1;
|
||||
sqlite3_int64 nByte = nNew*sizeof(FsdirLevel);
|
||||
FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc64(pCur->aLvl, nByte);
|
||||
if( aNew==0 ) return SQLITE_NOMEM;
|
||||
memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl));
|
||||
pCur->aLvl = aNew;
|
||||
pCur->nLvl = nNew;
|
||||
}
|
||||
pCur->iLvl = iNew;
|
||||
pLvl = &pCur->aLvl[iNew];
|
||||
|
||||
pLvl->zDir = pCur->zPath;
|
||||
pCur->zPath = 0;
|
||||
pLvl->pDir = opendir(pLvl->zDir);
|
||||
if( pLvl->pDir==0 ){
|
||||
fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
while( pCur->iLvl>=0 ){
|
||||
FsdirLevel *pLvl = &pCur->aLvl[pCur->iLvl];
|
||||
struct dirent *pEntry = readdir(pLvl->pDir);
|
||||
if( pEntry ){
|
||||
if( pEntry->d_name[0]=='.' ){
|
||||
if( pEntry->d_name[1]=='.' && pEntry->d_name[2]=='\0' ) continue;
|
||||
if( pEntry->d_name[1]=='\0' ) continue;
|
||||
}
|
||||
sqlite3_free(pCur->zPath);
|
||||
pCur->zPath = sqlite3_mprintf("%s/%s", pLvl->zDir, pEntry->d_name);
|
||||
if( pCur->zPath==0 ) return SQLITE_NOMEM;
|
||||
if( fileLinkStat(pCur->zPath, &pCur->sStat) ){
|
||||
fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
closedir(pLvl->pDir);
|
||||
sqlite3_free(pLvl->zDir);
|
||||
pLvl->pDir = 0;
|
||||
pLvl->zDir = 0;
|
||||
pCur->iLvl--;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
sqlite3_free(pCur->zPath);
|
||||
pCur->zPath = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return values of columns for the row at which the series_cursor
|
||||
** is currently pointing.
|
||||
*/
|
||||
static int fsdirColumn(
|
||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||
int i /* Which column to return */
|
||||
){
|
||||
fsdir_cursor *pCur = (fsdir_cursor*)cur;
|
||||
switch( i ){
|
||||
case FSDIR_COLUMN_NAME: {
|
||||
sqlite3_result_text(ctx, &pCur->zPath[pCur->nBase], -1, SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
|
||||
case FSDIR_COLUMN_MODE:
|
||||
sqlite3_result_int64(ctx, pCur->sStat.st_mode);
|
||||
break;
|
||||
|
||||
case FSDIR_COLUMN_MTIME:
|
||||
sqlite3_result_int64(ctx, pCur->sStat.st_mtime);
|
||||
break;
|
||||
|
||||
case FSDIR_COLUMN_DATA: {
|
||||
mode_t m = pCur->sStat.st_mode;
|
||||
if( S_ISDIR(m) ){
|
||||
sqlite3_result_null(ctx);
|
||||
#if !defined(_WIN32) && !defined(WIN32)
|
||||
}else if( S_ISLNK(m) ){
|
||||
char aStatic[64];
|
||||
char *aBuf = aStatic;
|
||||
sqlite3_int64 nBuf = 64;
|
||||
int n;
|
||||
|
||||
while( 1 ){
|
||||
n = readlink(pCur->zPath, aBuf, nBuf);
|
||||
if( n<nBuf ) break;
|
||||
if( aBuf!=aStatic ) sqlite3_free(aBuf);
|
||||
nBuf = nBuf*2;
|
||||
aBuf = sqlite3_malloc64(nBuf);
|
||||
if( aBuf==0 ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT);
|
||||
if( aBuf!=aStatic ) sqlite3_free(aBuf);
|
||||
#endif
|
||||
}else{
|
||||
readFileContents(ctx, pCur->zPath);
|
||||
}
|
||||
}
|
||||
case FSDIR_COLUMN_PATH:
|
||||
default: {
|
||||
/* The FSDIR_COLUMN_PATH and FSDIR_COLUMN_DIR are input parameters.
|
||||
** always return their values as NULL */
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the rowid for the current row. In this implementation, the
|
||||
** first row returned is assigned rowid value 1, and each subsequent
|
||||
** row a value 1 more than that of the previous.
|
||||
*/
|
||||
static int fsdirRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
fsdir_cursor *pCur = (fsdir_cursor*)cur;
|
||||
*pRowid = pCur->iRowid;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor has been moved off of the last
|
||||
** row of output.
|
||||
*/
|
||||
static int fsdirEof(sqlite3_vtab_cursor *cur){
|
||||
fsdir_cursor *pCur = (fsdir_cursor*)cur;
|
||||
return (pCur->zPath==0);
|
||||
}
|
||||
|
||||
/*
|
||||
** xFilter callback.
|
||||
**
|
||||
** idxNum==1 PATH parameter only
|
||||
** idxNum==2 Both PATH and DIR supplied
|
||||
*/
|
||||
static int fsdirFilter(
|
||||
sqlite3_vtab_cursor *cur,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
const char *zDir = 0;
|
||||
fsdir_cursor *pCur = (fsdir_cursor*)cur;
|
||||
(void)idxStr;
|
||||
fsdirResetCursor(pCur);
|
||||
|
||||
if( idxNum==0 ){
|
||||
fsdirSetErrmsg(pCur, "table function fsdir requires an argument");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
assert( argc==idxNum && (argc==1 || argc==2) );
|
||||
zDir = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zDir==0 ){
|
||||
fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
if( argc==2 ){
|
||||
pCur->zBase = (const char*)sqlite3_value_text(argv[1]);
|
||||
}
|
||||
if( pCur->zBase ){
|
||||
pCur->nBase = (int)strlen(pCur->zBase)+1;
|
||||
pCur->zPath = sqlite3_mprintf("%s/%s", pCur->zBase, zDir);
|
||||
}else{
|
||||
pCur->zPath = sqlite3_mprintf("%s", zDir);
|
||||
}
|
||||
|
||||
if( pCur->zPath==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if( fileLinkStat(pCur->zPath, &pCur->sStat) ){
|
||||
fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** SQLite will invoke this method one or more times while planning a query
|
||||
** that uses the generate_series virtual table. This routine needs to create
|
||||
** a query plan for each invocation and compute an estimated cost for that
|
||||
** plan.
|
||||
**
|
||||
** In this implementation idxNum is used to represent the
|
||||
** query plan. idxStr is unused.
|
||||
**
|
||||
** The query plan is represented by values of idxNum:
|
||||
**
|
||||
** (1) The path value is supplied by argv[0]
|
||||
** (2) Path is in argv[0] and dir is in argv[1]
|
||||
*/
|
||||
static int fsdirBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
int i; /* Loop over constraints */
|
||||
int idxPath = -1; /* Index in pIdxInfo->aConstraint of PATH= */
|
||||
int idxDir = -1; /* Index in pIdxInfo->aConstraint of DIR= */
|
||||
int seenPath = 0; /* True if an unusable PATH= constraint is seen */
|
||||
int seenDir = 0; /* True if an unusable DIR= constraint is seen */
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
|
||||
(void)tab;
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||
if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||
switch( pConstraint->iColumn ){
|
||||
case FSDIR_COLUMN_PATH: {
|
||||
if( pConstraint->usable ){
|
||||
idxPath = i;
|
||||
seenPath = 0;
|
||||
}else if( idxPath<0 ){
|
||||
seenPath = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FSDIR_COLUMN_DIR: {
|
||||
if( pConstraint->usable ){
|
||||
idxDir = i;
|
||||
seenDir = 0;
|
||||
}else if( idxDir<0 ){
|
||||
seenDir = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( seenPath || seenDir ){
|
||||
/* If input parameters are unusable, disallow this plan */
|
||||
return SQLITE_CONSTRAINT;
|
||||
}
|
||||
|
||||
if( idxPath<0 ){
|
||||
pIdxInfo->idxNum = 0;
|
||||
/* The pIdxInfo->estimatedCost should have been initialized to a huge
|
||||
** number. Leave it unchanged. */
|
||||
pIdxInfo->estimatedRows = 0x7fffffff;
|
||||
}else{
|
||||
pIdxInfo->aConstraintUsage[idxPath].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[idxPath].argvIndex = 1;
|
||||
if( idxDir>=0 ){
|
||||
pIdxInfo->aConstraintUsage[idxDir].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[idxDir].argvIndex = 2;
|
||||
pIdxInfo->idxNum = 2;
|
||||
pIdxInfo->estimatedCost = 10.0;
|
||||
}else{
|
||||
pIdxInfo->idxNum = 1;
|
||||
pIdxInfo->estimatedCost = 100.0;
|
||||
}
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Register the "fsdir" virtual table.
|
||||
*/
|
||||
static int fsdirRegister(sqlite3 *db){
|
||||
static sqlite3_module fsdirModule = {
|
||||
0, /* iVersion */
|
||||
0, /* xCreate */
|
||||
fsdirConnect, /* xConnect */
|
||||
fsdirBestIndex, /* xBestIndex */
|
||||
fsdirDisconnect, /* xDisconnect */
|
||||
0, /* xDestroy */
|
||||
fsdirOpen, /* xOpen - open a cursor */
|
||||
fsdirClose, /* xClose - close a cursor */
|
||||
fsdirFilter, /* xFilter - configure scan constraints */
|
||||
fsdirNext, /* xNext - advance a cursor */
|
||||
fsdirEof, /* xEof - check for end of scan */
|
||||
fsdirColumn, /* xColumn - read data */
|
||||
fsdirRowid, /* xRowid - read data */
|
||||
0, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
0, /* xShadowName */
|
||||
};
|
||||
|
||||
int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0);
|
||||
return rc;
|
||||
}
|
||||
#else /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
# define fsdirRegister(x) SQLITE_OK
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_fileio_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
|
||||
readfileFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8, 0,
|
||||
writefileFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0,
|
||||
lsModeFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fsdirRegister(db);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
# Source files of the wxSQLite3 encryption extension
|
||||
|
||||
The following document gives a short overview of all source files of which the wxSQLite3 encryption extension consists.
|
||||
|
||||
## Kernel of the wxSQLite3 encryption extension
|
||||
|
||||
The following files constitute the kernel of the **wxSQLite3** encryption extension:
|
||||
|
||||
| Filename | Description |
|
||||
| :--- | :--- |
|
||||
| codec.c | Implementation of the **wxSQLite3** encryption extension |
|
||||
| codec.h | Header for the **wxSQLite3** encryption extension |
|
||||
| codecext.c | Implementation of the **SQLite3** codec API |
|
||||
| rekeyvacuum.c | Adjusted VACUUM function for use on rekeying a database file |
|
||||
| sqlite3secure.c | _Amalgamation_ of the complete **wxSQLite3** encryption extension |
|
||||
| sqlite3secure.h | Header for the additional API functions of the **wxSQLite3** encryption extension |
|
||||
|
||||
All files, except `rekeyvacuum.c`, are licensed under `LGPL-3.0+ WITH WxWindows-exception-3.1`.
|
||||
|
||||
`rekeyvacuum.c` contains a slightly modified implementation of the function `sqlite3RunVacuum` from the **SQLite3** and stays in the public domain.
|
||||
|
||||
## Cryptograhic algorithms
|
||||
|
||||
The following files contain the implementations of cryptographic algorithms used by the **wxSQLite3** encryption extension:
|
||||
|
||||
| Filename | Description |
|
||||
| :--- | :--- |
|
||||
| chacha20poly1305.c | Implementation of ChaCha20 cipher and Poly1305 message authentication |
|
||||
| fastpbkdf2.c | Implementation of PBKDF2 functions |
|
||||
| fastpbkdf2.h | Header for PBKDF2 functions |
|
||||
| md5.c | Implementation of MD5 hash functions |
|
||||
| rijndael.c | Implementation of AES block cipher |
|
||||
| rijndael.h | Header for AES block cipher |
|
||||
| sha1.c | Implementation of SHA1 hash functions |
|
||||
| sha1.h | Header for SHA1 hash functions |
|
||||
| sha2.c | Implementation of SHA2 hash functions |
|
||||
| sha2.h | Header for SHA2 hash functions |
|
||||
|
||||
The files `chacha20poly1305.c`, `fastpbkdf2.*`, `md5.c`, and `sha1.*` are in the public domain.
|
||||
|
||||
The files `rijndael.*`, are licensed under `LGPL-3.0+ WITH WxWindows-exception-3.1`.
|
||||
|
||||
The files `sha2.*` are licensed under `BSD-3-Clause`.
|
||||
|
||||
## Windows-specific files
|
||||
|
||||
The following files are only used under Windows platforms for creating binaries:
|
||||
|
||||
| Filename | Description |
|
||||
| :--- | :--- |
|
||||
| sqlite3.def | Module definition specifying exported functions |
|
||||
| sqlite3.rc | Resource file specifying version information for the SQLite3 library |
|
||||
| sqlite3shell.rc | Resource file specifying version information for the SQLite3 shell |
|
||||
|
||||
All files are licensed under `LGPL-3.0+ WITH WxWindows-exception-3.1`.
|
||||
|
||||
## SQLite3 core
|
||||
|
||||
The following files belong to the **SQLite3** core:
|
||||
|
||||
| Filename | Description |
|
||||
| :--- | :--- |
|
||||
| shell.c | SQLite3 shell application |
|
||||
| sqlite3.c | SQLite3 source amalgamation |
|
||||
| sqlite3.h | SQLite3 header |
|
||||
| sqlite3ext.h | SQLite3 header for extensions |
|
||||
| test_windirent.c | Source for directory access under Windows used by `fileio` extension |
|
||||
| test_windirent.h | Header for directory access under Windows used by `fileio` extension |
|
||||
|
||||
All files are in the public domain.
|
||||
|
||||
## SQLite3 extensions
|
||||
|
||||
The following files belong to **SQLite3** extensions contained in the official **SQLite3** distribution:
|
||||
|
||||
| Filename | Description |
|
||||
| :--- | :--- |
|
||||
| carray.c | Table-valued function that returns the values in a C-language array |
|
||||
| csv.c | Virtual table for reading CSV files |
|
||||
| fileio.c | Functions `readfile` and `writefile`, and eponymous virtual table `fsdir` |
|
||||
| series.c | Table-valued-function implementing the function `generate_series` |
|
||||
| shathree.c | Functions computing SHA3 hashes |
|
||||
| sqlite3userauth.h | Header for user-authentication extension feature |
|
||||
| userauth.c | User-authentication extension feature (modified password hash function) |
|
||||
|
||||
All files are in the public domain.
|
||||
|
||||
## External SQLite3 extensions
|
||||
|
||||
The following file was posted to the SQLite mailing list:
|
||||
|
||||
| Filename | Description |
|
||||
| :--- | :--- |
|
||||
| extensionfunctions.c | The extension provides common mathematical and string functions |
|
||||
|
||||
The file `extensionfunctions.c` does not contain any specific license information. Since it was posted to the SQLite mailing list, it is assumed that the file is in the public domain like SQLite3 itself.
|
||||
Vendored
+306
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
|
||||
* MD5 Message-Digest Algorithm (RFC 1321).
|
||||
*
|
||||
* Homepage:
|
||||
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
|
||||
*
|
||||
* Author:
|
||||
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
|
||||
*
|
||||
* This software was written by Alexander Peslyak in 2001. No copyright is
|
||||
* claimed, and the software is hereby placed in the public domain.
|
||||
* In case this attempt to disclaim copyright and place the software in the
|
||||
* public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* (This is a heavily cut-down "BSD license".)
|
||||
*
|
||||
* This differs from Colin Plumb's older public domain implementation in that
|
||||
* no exactly 32-bit integer data type is required (any 32-bit or wider
|
||||
* unsigned integer data type will do), there's no compile-time endianness
|
||||
* configuration, and the function prototypes match OpenSSL's. No code from
|
||||
* Colin Plumb's implementation has been reused; this comment merely compares
|
||||
* the properties of the two independent implementations.
|
||||
*
|
||||
* The primary goals of this implementation are portability and ease of use.
|
||||
* It is meant to be fast, but not as fast as possible. Some known
|
||||
* optimizations are not included to reduce source code size and avoid
|
||||
* compile-time configuration.
|
||||
*/
|
||||
|
||||
#define MD5_HASHBYTES 16
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Any 32-bit or wider unsigned integer data type will do */
|
||||
typedef unsigned int MD5_u32plus;
|
||||
|
||||
typedef struct {
|
||||
MD5_u32plus lo, hi;
|
||||
MD5_u32plus a, b, c, d;
|
||||
unsigned char buffer[64];
|
||||
MD5_u32plus block[16];
|
||||
} MD5_CTX;
|
||||
|
||||
static void MD5_Init(MD5_CTX *ctx);
|
||||
static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
|
||||
static void MD5_Final(unsigned char *result, MD5_CTX *ctx);
|
||||
|
||||
/*
|
||||
* The basic MD5 functions.
|
||||
*
|
||||
* F and G are optimized compared to their RFC 1321 definitions for
|
||||
* architectures that lack an AND-NOT instruction, just like in Colin Plumb's
|
||||
* implementation.
|
||||
*/
|
||||
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
|
||||
#define H(x, y, z) (((x) ^ (y)) ^ (z))
|
||||
#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
|
||||
/*
|
||||
* The MD5 transformation for all four rounds.
|
||||
*/
|
||||
#define STEP(f, a, b, c, d, x, t, s) \
|
||||
(a) += f((b), (c), (d)) + (x) + (t); \
|
||||
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
|
||||
(a) += (b);
|
||||
|
||||
/*
|
||||
* SET reads 4 input bytes in little-endian byte order and stores them
|
||||
* in a properly aligned word in host byte order.
|
||||
*
|
||||
* The check for little-endian architectures that tolerate unaligned
|
||||
* memory accesses is just an optimization. Nothing will break if it
|
||||
* doesn't work.
|
||||
*/
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
|
||||
#define SET(n) \
|
||||
(*(MD5_u32plus *)&ptr[(n) * 4])
|
||||
#define GET(n) \
|
||||
SET(n)
|
||||
#else
|
||||
#define SET(n) \
|
||||
(ctx->block[(n)] = \
|
||||
(MD5_u32plus)ptr[(n) * 4] | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
|
||||
#define GET(n) \
|
||||
(ctx->block[(n)])
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This processes one or more 64-byte data blocks, but does NOT update
|
||||
* the bit counters. There are no alignment requirements.
|
||||
*/
|
||||
static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
|
||||
{
|
||||
const unsigned char *ptr;
|
||||
MD5_u32plus a, b, c, d;
|
||||
MD5_u32plus saved_a, saved_b, saved_c, saved_d;
|
||||
|
||||
ptr = (const unsigned char *)data;
|
||||
|
||||
a = ctx->a;
|
||||
b = ctx->b;
|
||||
c = ctx->c;
|
||||
d = ctx->d;
|
||||
|
||||
do {
|
||||
saved_a = a;
|
||||
saved_b = b;
|
||||
saved_c = c;
|
||||
saved_d = d;
|
||||
|
||||
/* Round 1 */
|
||||
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
|
||||
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
|
||||
STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
|
||||
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
|
||||
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
|
||||
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
|
||||
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
|
||||
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
|
||||
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
|
||||
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
|
||||
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
|
||||
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
|
||||
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
|
||||
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
|
||||
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
|
||||
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
|
||||
|
||||
/* Round 2 */
|
||||
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
|
||||
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
|
||||
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
|
||||
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
|
||||
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
|
||||
STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
|
||||
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
|
||||
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
|
||||
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
|
||||
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
|
||||
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
|
||||
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
|
||||
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
|
||||
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
|
||||
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
|
||||
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
|
||||
|
||||
/* Round 3 */
|
||||
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
|
||||
STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
|
||||
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
|
||||
STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
|
||||
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
|
||||
STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
|
||||
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
|
||||
STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
|
||||
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
|
||||
STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
|
||||
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
|
||||
STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
|
||||
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
|
||||
STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
|
||||
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
|
||||
STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
|
||||
|
||||
/* Round 4 */
|
||||
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
|
||||
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
|
||||
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
|
||||
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
|
||||
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
|
||||
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
|
||||
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
|
||||
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
|
||||
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
|
||||
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
|
||||
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
|
||||
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
|
||||
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
|
||||
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
|
||||
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
|
||||
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
|
||||
|
||||
a += saved_a;
|
||||
b += saved_b;
|
||||
c += saved_c;
|
||||
d += saved_d;
|
||||
|
||||
ptr += 64;
|
||||
} while (size -= 64);
|
||||
|
||||
ctx->a = a;
|
||||
ctx->b = b;
|
||||
ctx->c = c;
|
||||
ctx->d = d;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void MD5_Init(MD5_CTX *ctx)
|
||||
{
|
||||
ctx->a = 0x67452301;
|
||||
ctx->b = 0xefcdab89;
|
||||
ctx->c = 0x98badcfe;
|
||||
ctx->d = 0x10325476;
|
||||
|
||||
ctx->lo = 0;
|
||||
ctx->hi = 0;
|
||||
}
|
||||
|
||||
void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
|
||||
{
|
||||
MD5_u32plus saved_lo;
|
||||
unsigned long used, available;
|
||||
|
||||
saved_lo = ctx->lo;
|
||||
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
|
||||
ctx->hi++;
|
||||
ctx->hi += size >> 29;
|
||||
|
||||
used = saved_lo & 0x3f;
|
||||
|
||||
if (used) {
|
||||
available = 64 - used;
|
||||
|
||||
if (size < available) {
|
||||
memcpy(&ctx->buffer[used], data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&ctx->buffer[used], data, available);
|
||||
data = (const unsigned char *)data + available;
|
||||
size -= available;
|
||||
body(ctx, ctx->buffer, 64);
|
||||
}
|
||||
|
||||
if (size >= 64) {
|
||||
data = body(ctx, data, size & ~(unsigned long)0x3f);
|
||||
size &= 0x3f;
|
||||
}
|
||||
|
||||
memcpy(ctx->buffer, data, size);
|
||||
}
|
||||
|
||||
void MD5_Final(unsigned char *result, MD5_CTX *ctx)
|
||||
{
|
||||
unsigned long used, available;
|
||||
|
||||
used = ctx->lo & 0x3f;
|
||||
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
available = 64 - used;
|
||||
|
||||
if (available < 8) {
|
||||
memset(&ctx->buffer[used], 0, available);
|
||||
body(ctx, ctx->buffer, 64);
|
||||
used = 0;
|
||||
available = 64;
|
||||
}
|
||||
|
||||
memset(&ctx->buffer[used], 0, available - 8);
|
||||
|
||||
ctx->lo <<= 3;
|
||||
ctx->buffer[56] = ctx->lo;
|
||||
ctx->buffer[57] = ctx->lo >> 8;
|
||||
ctx->buffer[58] = ctx->lo >> 16;
|
||||
ctx->buffer[59] = ctx->lo >> 24;
|
||||
ctx->buffer[60] = ctx->hi;
|
||||
ctx->buffer[61] = ctx->hi >> 8;
|
||||
ctx->buffer[62] = ctx->hi >> 16;
|
||||
ctx->buffer[63] = ctx->hi >> 24;
|
||||
|
||||
body(ctx, ctx->buffer, 64);
|
||||
|
||||
result[0] = ctx->a;
|
||||
result[1] = ctx->a >> 8;
|
||||
result[2] = ctx->a >> 16;
|
||||
result[3] = ctx->a >> 24;
|
||||
result[4] = ctx->b;
|
||||
result[5] = ctx->b >> 8;
|
||||
result[6] = ctx->b >> 16;
|
||||
result[7] = ctx->b >> 24;
|
||||
result[8] = ctx->c;
|
||||
result[9] = ctx->c >> 8;
|
||||
result[10] = ctx->c >> 16;
|
||||
result[11] = ctx->c >> 24;
|
||||
result[12] = ctx->d;
|
||||
result[13] = ctx->d >> 8;
|
||||
result[14] = ctx->d >> 16;
|
||||
result[15] = ctx->d >> 24;
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
#ifndef MY_STDINT_H_
|
||||
#define MY_STDINT_H_
|
||||
|
||||
/*
|
||||
** MS Visual C++ 2008 and below do not provide the header file <stdint.h>
|
||||
** That is, we need to define the necessary types ourselves
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1600)
|
||||
typedef signed char int8_t;
|
||||
typedef short int16_t;
|
||||
typedef int int32_t;
|
||||
typedef long long int64_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
#define UINT8_MAX 255
|
||||
#define UINT16_MAX 65535
|
||||
#define UINT32_MAX 0xffffffffU /* 4294967295U */
|
||||
#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#endif /* MY_STDINT_H_ */
|
||||
Vendored
+760
@@ -0,0 +1,760 @@
|
||||
/*
|
||||
** 2012-11-13
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** The code in this file implements a compact but reasonably
|
||||
** efficient regular-expression matcher for posix extended regular
|
||||
** expressions against UTF8 text.
|
||||
**
|
||||
** This file is an SQLite extension. It registers a single function
|
||||
** named "regexp(A,B)" where A is the regular expression and B is the
|
||||
** string to be matched. By registering this function, SQLite will also
|
||||
** then implement the "B regexp A" operator. Note that with the function
|
||||
** the regular expression comes first, but with the operator it comes
|
||||
** second.
|
||||
**
|
||||
** The following regular expression syntax is supported:
|
||||
**
|
||||
** X* zero or more occurrences of X
|
||||
** X+ one or more occurrences of X
|
||||
** X? zero or one occurrences of X
|
||||
** X{p,q} between p and q occurrences of X
|
||||
** (X) match X
|
||||
** X|Y X or Y
|
||||
** ^X X occurring at the beginning of the string
|
||||
** X$ X occurring at the end of the string
|
||||
** . Match any single character
|
||||
** \c Character c where c is one of \{}()[]|*+?.
|
||||
** \c C-language escapes for c in afnrtv. ex: \t or \n
|
||||
** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX
|
||||
** \xXX Where XX is exactly 2 hex digits, unicode value XX
|
||||
** [abc] Any single character from the set abc
|
||||
** [^abc] Any single character not in the set abc
|
||||
** [a-z] Any single character in the range a-z
|
||||
** [^a-z] Any single character not in the range a-z
|
||||
** \b Word boundary
|
||||
** \w Word character. [A-Za-z0-9_]
|
||||
** \W Non-word character
|
||||
** \d Digit
|
||||
** \D Non-digit
|
||||
** \s Whitespace character
|
||||
** \S Non-whitespace character
|
||||
**
|
||||
** A nondeterministic finite automaton (NFA) is used for matching, so the
|
||||
** performance is bounded by O(N*M) where N is the size of the regular
|
||||
** expression and M is the size of the input string. The matcher never
|
||||
** exhibits exponential behavior. Note that the X{p,q} operator expands
|
||||
** to p copies of X following by q-p copies of X? and that the size of the
|
||||
** regular expression in the O(N*M) performance bound is computed after
|
||||
** this expansion.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
|
||||
/*
|
||||
** The following #defines change the names of some functions implemented in
|
||||
** this file to prevent name collisions with C-library functions of the
|
||||
** same name.
|
||||
*/
|
||||
#define re_match sqlite3re_match
|
||||
#define re_compile sqlite3re_compile
|
||||
#define re_free sqlite3re_free
|
||||
|
||||
/* The end-of-input character */
|
||||
#define RE_EOF 0 /* End of input */
|
||||
|
||||
/* The NFA is implemented as sequence of opcodes taken from the following
|
||||
** set. Each opcode has a single integer argument.
|
||||
*/
|
||||
#define RE_OP_MATCH 1 /* Match the one character in the argument */
|
||||
#define RE_OP_ANY 2 /* Match any one character. (Implements ".") */
|
||||
#define RE_OP_ANYSTAR 3 /* Special optimized version of .* */
|
||||
#define RE_OP_FORK 4 /* Continue to both next and opcode at iArg */
|
||||
#define RE_OP_GOTO 5 /* Jump to opcode at iArg */
|
||||
#define RE_OP_ACCEPT 6 /* Halt and indicate a successful match */
|
||||
#define RE_OP_CC_INC 7 /* Beginning of a [...] character class */
|
||||
#define RE_OP_CC_EXC 8 /* Beginning of a [^...] character class */
|
||||
#define RE_OP_CC_VALUE 9 /* Single value in a character class */
|
||||
#define RE_OP_CC_RANGE 10 /* Range of values in a character class */
|
||||
#define RE_OP_WORD 11 /* Perl word character [A-Za-z0-9_] */
|
||||
#define RE_OP_NOTWORD 12 /* Not a perl word character */
|
||||
#define RE_OP_DIGIT 13 /* digit: [0-9] */
|
||||
#define RE_OP_NOTDIGIT 14 /* Not a digit */
|
||||
#define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */
|
||||
#define RE_OP_NOTSPACE 16 /* Not a digit */
|
||||
#define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */
|
||||
|
||||
/* Each opcode is a "state" in the NFA */
|
||||
typedef unsigned short ReStateNumber;
|
||||
|
||||
/* Because this is an NFA and not a DFA, multiple states can be active at
|
||||
** once. An instance of the following object records all active states in
|
||||
** the NFA. The implementation is optimized for the common case where the
|
||||
** number of actives states is small.
|
||||
*/
|
||||
typedef struct ReStateSet {
|
||||
unsigned nState; /* Number of current states */
|
||||
ReStateNumber *aState; /* Current states */
|
||||
} ReStateSet;
|
||||
|
||||
/* An input string read one character at a time.
|
||||
*/
|
||||
typedef struct ReInput ReInput;
|
||||
struct ReInput {
|
||||
const unsigned char *z; /* All text */
|
||||
int i; /* Next byte to read */
|
||||
int mx; /* EOF when i>=mx */
|
||||
};
|
||||
|
||||
/* A compiled NFA (or an NFA that is in the process of being compiled) is
|
||||
** an instance of the following object.
|
||||
*/
|
||||
typedef struct ReCompiled ReCompiled;
|
||||
struct ReCompiled {
|
||||
ReInput sIn; /* Regular expression text */
|
||||
const char *zErr; /* Error message to return */
|
||||
char *aOp; /* Operators for the virtual machine */
|
||||
int *aArg; /* Arguments to each operator */
|
||||
unsigned (*xNextChar)(ReInput*); /* Next character function */
|
||||
unsigned char zInit[12]; /* Initial text to match */
|
||||
int nInit; /* Number of characters in zInit */
|
||||
unsigned nState; /* Number of entries in aOp[] and aArg[] */
|
||||
unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */
|
||||
};
|
||||
|
||||
/* Add a state to the given state set if it is not already there */
|
||||
static void re_add_state(ReStateSet *pSet, int newState){
|
||||
unsigned i;
|
||||
for(i=0; i<pSet->nState; i++) if( pSet->aState[i]==newState ) return;
|
||||
pSet->aState[pSet->nState++] = (ReStateNumber)newState;
|
||||
}
|
||||
|
||||
/* Extract the next unicode character from *pzIn and return it. Advance
|
||||
** *pzIn to the first byte past the end of the character returned. To
|
||||
** be clear: this routine converts utf8 to unicode. This routine is
|
||||
** optimized for the common case where the next character is a single byte.
|
||||
*/
|
||||
static unsigned re_next_char(ReInput *p){
|
||||
unsigned c;
|
||||
if( p->i>=p->mx ) return 0;
|
||||
c = p->z[p->i++];
|
||||
if( c>=0x80 ){
|
||||
if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){
|
||||
c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f);
|
||||
if( c<0x80 ) c = 0xfffd;
|
||||
}else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80
|
||||
&& (p->z[p->i+1]&0xc0)==0x80 ){
|
||||
c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
|
||||
p->i += 2;
|
||||
if( c<=0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
|
||||
}else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80
|
||||
&& (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
|
||||
c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
|
||||
| (p->z[p->i+2]&0x3f);
|
||||
p->i += 3;
|
||||
if( c<=0xffff || c>0x10ffff ) c = 0xfffd;
|
||||
}else{
|
||||
c = 0xfffd;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
static unsigned re_next_char_nocase(ReInput *p){
|
||||
unsigned c = re_next_char(p);
|
||||
if( c>='A' && c<='Z' ) c += 'a' - 'A';
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Return true if c is a perl "word" character: [A-Za-z0-9_] */
|
||||
static int re_word_char(int c){
|
||||
return (c>='0' && c<='9') || (c>='a' && c<='z')
|
||||
|| (c>='A' && c<='Z') || c=='_';
|
||||
}
|
||||
|
||||
/* Return true if c is a "digit" character: [0-9] */
|
||||
static int re_digit_char(int c){
|
||||
return (c>='0' && c<='9');
|
||||
}
|
||||
|
||||
/* Return true if c is a perl "space" character: [ \t\r\n\v\f] */
|
||||
static int re_space_char(int c){
|
||||
return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f';
|
||||
}
|
||||
|
||||
/* Run a compiled regular expression on the zero-terminated input
|
||||
** string zIn[]. Return true on a match and false if there is no match.
|
||||
*/
|
||||
static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
|
||||
ReStateSet aStateSet[2], *pThis, *pNext;
|
||||
ReStateNumber aSpace[100];
|
||||
ReStateNumber *pToFree;
|
||||
unsigned int i = 0;
|
||||
unsigned int iSwap = 0;
|
||||
int c = RE_EOF+1;
|
||||
int cPrev = 0;
|
||||
int rc = 0;
|
||||
ReInput in;
|
||||
|
||||
in.z = zIn;
|
||||
in.i = 0;
|
||||
in.mx = nIn>=0 ? nIn : (int)strlen((char const*)zIn);
|
||||
|
||||
/* Look for the initial prefix match, if there is one. */
|
||||
if( pRe->nInit ){
|
||||
unsigned char x = pRe->zInit[0];
|
||||
while( in.i+pRe->nInit<=in.mx
|
||||
&& (zIn[in.i]!=x ||
|
||||
strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0)
|
||||
){
|
||||
in.i++;
|
||||
}
|
||||
if( in.i+pRe->nInit>in.mx ) return 0;
|
||||
}
|
||||
|
||||
if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
|
||||
pToFree = 0;
|
||||
aStateSet[0].aState = aSpace;
|
||||
}else{
|
||||
pToFree = sqlite3_malloc64( sizeof(ReStateNumber)*2*pRe->nState );
|
||||
if( pToFree==0 ) return -1;
|
||||
aStateSet[0].aState = pToFree;
|
||||
}
|
||||
aStateSet[1].aState = &aStateSet[0].aState[pRe->nState];
|
||||
pNext = &aStateSet[1];
|
||||
pNext->nState = 0;
|
||||
re_add_state(pNext, 0);
|
||||
while( c!=RE_EOF && pNext->nState>0 ){
|
||||
cPrev = c;
|
||||
c = pRe->xNextChar(&in);
|
||||
pThis = pNext;
|
||||
pNext = &aStateSet[iSwap];
|
||||
iSwap = 1 - iSwap;
|
||||
pNext->nState = 0;
|
||||
for(i=0; i<pThis->nState; i++){
|
||||
int x = pThis->aState[i];
|
||||
switch( pRe->aOp[x] ){
|
||||
case RE_OP_MATCH: {
|
||||
if( pRe->aArg[x]==c ) re_add_state(pNext, x+1);
|
||||
break;
|
||||
}
|
||||
case RE_OP_ANY: {
|
||||
re_add_state(pNext, x+1);
|
||||
break;
|
||||
}
|
||||
case RE_OP_WORD: {
|
||||
if( re_word_char(c) ) re_add_state(pNext, x+1);
|
||||
break;
|
||||
}
|
||||
case RE_OP_NOTWORD: {
|
||||
if( !re_word_char(c) ) re_add_state(pNext, x+1);
|
||||
break;
|
||||
}
|
||||
case RE_OP_DIGIT: {
|
||||
if( re_digit_char(c) ) re_add_state(pNext, x+1);
|
||||
break;
|
||||
}
|
||||
case RE_OP_NOTDIGIT: {
|
||||
if( !re_digit_char(c) ) re_add_state(pNext, x+1);
|
||||
break;
|
||||
}
|
||||
case RE_OP_SPACE: {
|
||||
if( re_space_char(c) ) re_add_state(pNext, x+1);
|
||||
break;
|
||||
}
|
||||
case RE_OP_NOTSPACE: {
|
||||
if( !re_space_char(c) ) re_add_state(pNext, x+1);
|
||||
break;
|
||||
}
|
||||
case RE_OP_BOUNDARY: {
|
||||
if( re_word_char(c)!=re_word_char(cPrev) ) re_add_state(pThis, x+1);
|
||||
break;
|
||||
}
|
||||
case RE_OP_ANYSTAR: {
|
||||
re_add_state(pNext, x);
|
||||
re_add_state(pThis, x+1);
|
||||
break;
|
||||
}
|
||||
case RE_OP_FORK: {
|
||||
re_add_state(pThis, x+pRe->aArg[x]);
|
||||
re_add_state(pThis, x+1);
|
||||
break;
|
||||
}
|
||||
case RE_OP_GOTO: {
|
||||
re_add_state(pThis, x+pRe->aArg[x]);
|
||||
break;
|
||||
}
|
||||
case RE_OP_ACCEPT: {
|
||||
rc = 1;
|
||||
goto re_match_end;
|
||||
}
|
||||
case RE_OP_CC_INC:
|
||||
case RE_OP_CC_EXC: {
|
||||
int j = 1;
|
||||
int n = pRe->aArg[x];
|
||||
int hit = 0;
|
||||
for(j=1; j>0 && j<n; j++){
|
||||
if( pRe->aOp[x+j]==RE_OP_CC_VALUE ){
|
||||
if( pRe->aArg[x+j]==c ){
|
||||
hit = 1;
|
||||
j = -1;
|
||||
}
|
||||
}else{
|
||||
if( pRe->aArg[x+j]<=c && pRe->aArg[x+j+1]>=c ){
|
||||
hit = 1;
|
||||
j = -1;
|
||||
}else{
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit;
|
||||
if( hit ) re_add_state(pNext, x+n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(i=0; i<pNext->nState; i++){
|
||||
if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; }
|
||||
}
|
||||
re_match_end:
|
||||
sqlite3_free(pToFree);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Resize the opcode and argument arrays for an RE under construction.
|
||||
*/
|
||||
static int re_resize(ReCompiled *p, int N){
|
||||
char *aOp;
|
||||
int *aArg;
|
||||
aOp = sqlite3_realloc64(p->aOp, N*sizeof(p->aOp[0]));
|
||||
if( aOp==0 ) return 1;
|
||||
p->aOp = aOp;
|
||||
aArg = sqlite3_realloc64(p->aArg, N*sizeof(p->aArg[0]));
|
||||
if( aArg==0 ) return 1;
|
||||
p->aArg = aArg;
|
||||
p->nAlloc = N;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Insert a new opcode and argument into an RE under construction. The
|
||||
** insertion point is just prior to existing opcode iBefore.
|
||||
*/
|
||||
static int re_insert(ReCompiled *p, int iBefore, int op, int arg){
|
||||
int i;
|
||||
if( p->nAlloc<=p->nState && re_resize(p, p->nAlloc*2) ) return 0;
|
||||
for(i=p->nState; i>iBefore; i--){
|
||||
p->aOp[i] = p->aOp[i-1];
|
||||
p->aArg[i] = p->aArg[i-1];
|
||||
}
|
||||
p->nState++;
|
||||
p->aOp[iBefore] = (char)op;
|
||||
p->aArg[iBefore] = arg;
|
||||
return iBefore;
|
||||
}
|
||||
|
||||
/* Append a new opcode and argument to the end of the RE under construction.
|
||||
*/
|
||||
static int re_append(ReCompiled *p, int op, int arg){
|
||||
return re_insert(p, p->nState, op, arg);
|
||||
}
|
||||
|
||||
/* Make a copy of N opcodes starting at iStart onto the end of the RE
|
||||
** under construction.
|
||||
*/
|
||||
static void re_copy(ReCompiled *p, int iStart, int N){
|
||||
if( p->nState+N>=p->nAlloc && re_resize(p, p->nAlloc*2+N) ) return;
|
||||
memcpy(&p->aOp[p->nState], &p->aOp[iStart], N*sizeof(p->aOp[0]));
|
||||
memcpy(&p->aArg[p->nState], &p->aArg[iStart], N*sizeof(p->aArg[0]));
|
||||
p->nState += N;
|
||||
}
|
||||
|
||||
/* Return true if c is a hexadecimal digit character: [0-9a-fA-F]
|
||||
** If c is a hex digit, also set *pV = (*pV)*16 + valueof(c). If
|
||||
** c is not a hex digit *pV is unchanged.
|
||||
*/
|
||||
static int re_hex(int c, int *pV){
|
||||
if( c>='0' && c<='9' ){
|
||||
c -= '0';
|
||||
}else if( c>='a' && c<='f' ){
|
||||
c -= 'a' - 10;
|
||||
}else if( c>='A' && c<='F' ){
|
||||
c -= 'A' - 10;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
*pV = (*pV)*16 + (c & 0xff);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* A backslash character has been seen, read the next character and
|
||||
** return its interpretation.
|
||||
*/
|
||||
static unsigned re_esc_char(ReCompiled *p){
|
||||
static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]";
|
||||
static const char zTrans[] = "\a\f\n\r\t\v";
|
||||
int i, v = 0;
|
||||
char c;
|
||||
if( p->sIn.i>=p->sIn.mx ) return 0;
|
||||
c = p->sIn.z[p->sIn.i];
|
||||
if( c=='u' && p->sIn.i+4<p->sIn.mx ){
|
||||
const unsigned char *zIn = p->sIn.z + p->sIn.i;
|
||||
if( re_hex(zIn[1],&v)
|
||||
&& re_hex(zIn[2],&v)
|
||||
&& re_hex(zIn[3],&v)
|
||||
&& re_hex(zIn[4],&v)
|
||||
){
|
||||
p->sIn.i += 5;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
if( c=='x' && p->sIn.i+2<p->sIn.mx ){
|
||||
const unsigned char *zIn = p->sIn.z + p->sIn.i;
|
||||
if( re_hex(zIn[1],&v)
|
||||
&& re_hex(zIn[2],&v)
|
||||
){
|
||||
p->sIn.i += 3;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
for(i=0; zEsc[i] && zEsc[i]!=c; i++){}
|
||||
if( zEsc[i] ){
|
||||
if( i<6 ) c = zTrans[i];
|
||||
p->sIn.i++;
|
||||
}else{
|
||||
p->zErr = "unknown \\ escape";
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Forward declaration */
|
||||
static const char *re_subcompile_string(ReCompiled*);
|
||||
|
||||
/* Peek at the next byte of input */
|
||||
static unsigned char rePeek(ReCompiled *p){
|
||||
return p->sIn.i<p->sIn.mx ? p->sIn.z[p->sIn.i] : 0;
|
||||
}
|
||||
|
||||
/* Compile RE text into a sequence of opcodes. Continue up to the
|
||||
** first unmatched ")" character, then return. If an error is found,
|
||||
** return a pointer to the error message string.
|
||||
*/
|
||||
static const char *re_subcompile_re(ReCompiled *p){
|
||||
const char *zErr;
|
||||
int iStart, iEnd, iGoto;
|
||||
iStart = p->nState;
|
||||
zErr = re_subcompile_string(p);
|
||||
if( zErr ) return zErr;
|
||||
while( rePeek(p)=='|' ){
|
||||
iEnd = p->nState;
|
||||
re_insert(p, iStart, RE_OP_FORK, iEnd + 2 - iStart);
|
||||
iGoto = re_append(p, RE_OP_GOTO, 0);
|
||||
p->sIn.i++;
|
||||
zErr = re_subcompile_string(p);
|
||||
if( zErr ) return zErr;
|
||||
p->aArg[iGoto] = p->nState - iGoto;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compile an element of regular expression text (anything that can be
|
||||
** an operand to the "|" operator). Return NULL on success or a pointer
|
||||
** to the error message if there is a problem.
|
||||
*/
|
||||
static const char *re_subcompile_string(ReCompiled *p){
|
||||
int iPrev = -1;
|
||||
int iStart;
|
||||
unsigned c;
|
||||
const char *zErr;
|
||||
while( (c = p->xNextChar(&p->sIn))!=0 ){
|
||||
iStart = p->nState;
|
||||
switch( c ){
|
||||
case '|':
|
||||
case '$':
|
||||
case ')': {
|
||||
p->sIn.i--;
|
||||
return 0;
|
||||
}
|
||||
case '(': {
|
||||
zErr = re_subcompile_re(p);
|
||||
if( zErr ) return zErr;
|
||||
if( rePeek(p)!=')' ) return "unmatched '('";
|
||||
p->sIn.i++;
|
||||
break;
|
||||
}
|
||||
case '.': {
|
||||
if( rePeek(p)=='*' ){
|
||||
re_append(p, RE_OP_ANYSTAR, 0);
|
||||
p->sIn.i++;
|
||||
}else{
|
||||
re_append(p, RE_OP_ANY, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '*': {
|
||||
if( iPrev<0 ) return "'*' without operand";
|
||||
re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1);
|
||||
re_append(p, RE_OP_FORK, iPrev - p->nState + 1);
|
||||
break;
|
||||
}
|
||||
case '+': {
|
||||
if( iPrev<0 ) return "'+' without operand";
|
||||
re_append(p, RE_OP_FORK, iPrev - p->nState);
|
||||
break;
|
||||
}
|
||||
case '?': {
|
||||
if( iPrev<0 ) return "'?' without operand";
|
||||
re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1);
|
||||
break;
|
||||
}
|
||||
case '{': {
|
||||
int m = 0, n = 0;
|
||||
int sz, j;
|
||||
if( iPrev<0 ) return "'{m,n}' without operand";
|
||||
while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; }
|
||||
n = m;
|
||||
if( c==',' ){
|
||||
p->sIn.i++;
|
||||
n = 0;
|
||||
while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; }
|
||||
}
|
||||
if( c!='}' ) return "unmatched '{'";
|
||||
if( n>0 && n<m ) return "n less than m in '{m,n}'";
|
||||
p->sIn.i++;
|
||||
sz = p->nState - iPrev;
|
||||
if( m==0 ){
|
||||
if( n==0 ) return "both m and n are zero in '{m,n}'";
|
||||
re_insert(p, iPrev, RE_OP_FORK, sz+1);
|
||||
n--;
|
||||
}else{
|
||||
for(j=1; j<m; j++) re_copy(p, iPrev, sz);
|
||||
}
|
||||
for(j=m; j<n; j++){
|
||||
re_append(p, RE_OP_FORK, sz+1);
|
||||
re_copy(p, iPrev, sz);
|
||||
}
|
||||
if( n==0 && m>0 ){
|
||||
re_append(p, RE_OP_FORK, -sz);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '[': {
|
||||
int iFirst = p->nState;
|
||||
if( rePeek(p)=='^' ){
|
||||
re_append(p, RE_OP_CC_EXC, 0);
|
||||
p->sIn.i++;
|
||||
}else{
|
||||
re_append(p, RE_OP_CC_INC, 0);
|
||||
}
|
||||
while( (c = p->xNextChar(&p->sIn))!=0 ){
|
||||
if( c=='[' && rePeek(p)==':' ){
|
||||
return "POSIX character classes not supported";
|
||||
}
|
||||
if( c=='\\' ) c = re_esc_char(p);
|
||||
if( rePeek(p)=='-' ){
|
||||
re_append(p, RE_OP_CC_RANGE, c);
|
||||
p->sIn.i++;
|
||||
c = p->xNextChar(&p->sIn);
|
||||
if( c=='\\' ) c = re_esc_char(p);
|
||||
re_append(p, RE_OP_CC_RANGE, c);
|
||||
}else{
|
||||
re_append(p, RE_OP_CC_VALUE, c);
|
||||
}
|
||||
if( rePeek(p)==']' ){ p->sIn.i++; break; }
|
||||
}
|
||||
if( c==0 ) return "unclosed '['";
|
||||
p->aArg[iFirst] = p->nState - iFirst;
|
||||
break;
|
||||
}
|
||||
case '\\': {
|
||||
int specialOp = 0;
|
||||
switch( rePeek(p) ){
|
||||
case 'b': specialOp = RE_OP_BOUNDARY; break;
|
||||
case 'd': specialOp = RE_OP_DIGIT; break;
|
||||
case 'D': specialOp = RE_OP_NOTDIGIT; break;
|
||||
case 's': specialOp = RE_OP_SPACE; break;
|
||||
case 'S': specialOp = RE_OP_NOTSPACE; break;
|
||||
case 'w': specialOp = RE_OP_WORD; break;
|
||||
case 'W': specialOp = RE_OP_NOTWORD; break;
|
||||
}
|
||||
if( specialOp ){
|
||||
p->sIn.i++;
|
||||
re_append(p, specialOp, 0);
|
||||
}else{
|
||||
c = re_esc_char(p);
|
||||
re_append(p, RE_OP_MATCH, c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
re_append(p, RE_OP_MATCH, c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
iPrev = iStart;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Free and reclaim all the memory used by a previously compiled
|
||||
** regular expression. Applications should invoke this routine once
|
||||
** for every call to re_compile() to avoid memory leaks.
|
||||
*/
|
||||
void re_free(ReCompiled *pRe){
|
||||
if( pRe ){
|
||||
sqlite3_free(pRe->aOp);
|
||||
sqlite3_free(pRe->aArg);
|
||||
sqlite3_free(pRe);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Compile a textual regular expression in zIn[] into a compiled regular
|
||||
** expression suitable for us by re_match() and return a pointer to the
|
||||
** compiled regular expression in *ppRe. Return NULL on success or an
|
||||
** error message if something goes wrong.
|
||||
*/
|
||||
const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
|
||||
ReCompiled *pRe;
|
||||
const char *zErr;
|
||||
int i, j;
|
||||
|
||||
*ppRe = 0;
|
||||
pRe = sqlite3_malloc( sizeof(*pRe) );
|
||||
if( pRe==0 ){
|
||||
return "out of memory";
|
||||
}
|
||||
memset(pRe, 0, sizeof(*pRe));
|
||||
pRe->xNextChar = noCase ? re_next_char_nocase : re_next_char;
|
||||
if( re_resize(pRe, 30) ){
|
||||
re_free(pRe);
|
||||
return "out of memory";
|
||||
}
|
||||
if( zIn[0]=='^' ){
|
||||
zIn++;
|
||||
}else{
|
||||
re_append(pRe, RE_OP_ANYSTAR, 0);
|
||||
}
|
||||
pRe->sIn.z = (unsigned char*)zIn;
|
||||
pRe->sIn.i = 0;
|
||||
pRe->sIn.mx = (int)strlen(zIn);
|
||||
zErr = re_subcompile_re(pRe);
|
||||
if( zErr ){
|
||||
re_free(pRe);
|
||||
return zErr;
|
||||
}
|
||||
if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){
|
||||
re_append(pRe, RE_OP_MATCH, RE_EOF);
|
||||
re_append(pRe, RE_OP_ACCEPT, 0);
|
||||
*ppRe = pRe;
|
||||
}else if( pRe->sIn.i>=pRe->sIn.mx ){
|
||||
re_append(pRe, RE_OP_ACCEPT, 0);
|
||||
*ppRe = pRe;
|
||||
}else{
|
||||
re_free(pRe);
|
||||
return "unrecognized character";
|
||||
}
|
||||
|
||||
/* The following is a performance optimization. If the regex begins with
|
||||
** ".*" (if the input regex lacks an initial "^") and afterwards there are
|
||||
** one or more matching characters, enter those matching characters into
|
||||
** zInit[]. The re_match() routine can then search ahead in the input
|
||||
** string looking for the initial match without having to run the whole
|
||||
** regex engine over the string. Do not worry able trying to match
|
||||
** unicode characters beyond plane 0 - those are very rare and this is
|
||||
** just an optimization. */
|
||||
if( pRe->aOp[0]==RE_OP_ANYSTAR ){
|
||||
for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
|
||||
unsigned x = pRe->aArg[i];
|
||||
if( x<=127 ){
|
||||
pRe->zInit[j++] = (unsigned char)x;
|
||||
}else if( x<=0xfff ){
|
||||
pRe->zInit[j++] = (unsigned char)(0xc0 | (x>>6));
|
||||
pRe->zInit[j++] = 0x80 | (x&0x3f);
|
||||
}else if( x<=0xffff ){
|
||||
pRe->zInit[j++] = (unsigned char)(0xd0 | (x>>12));
|
||||
pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
|
||||
pRe->zInit[j++] = 0x80 | (x&0x3f);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j>0 && pRe->zInit[j-1]==0 ) j--;
|
||||
pRe->nInit = j;
|
||||
}
|
||||
return pRe->zErr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the regexp() SQL function. This function implements
|
||||
** the build-in REGEXP operator. The first argument to the function is the
|
||||
** pattern and the second argument is the string. So, the SQL statements:
|
||||
**
|
||||
** A REGEXP B
|
||||
**
|
||||
** is implemented as regexp(B,A).
|
||||
*/
|
||||
static void re_sql_func(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
ReCompiled *pRe; /* Compiled regular expression */
|
||||
const char *zPattern; /* The regular expression */
|
||||
const unsigned char *zStr;/* String being searched */
|
||||
const char *zErr; /* Compile error message */
|
||||
int setAux = 0; /* True to invoke sqlite3_set_auxdata() */
|
||||
|
||||
pRe = sqlite3_get_auxdata(context, 0);
|
||||
if( pRe==0 ){
|
||||
zPattern = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zPattern==0 ) return;
|
||||
zErr = re_compile(&pRe, zPattern, 0);
|
||||
if( zErr ){
|
||||
re_free(pRe);
|
||||
sqlite3_result_error(context, zErr, -1);
|
||||
return;
|
||||
}
|
||||
if( pRe==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
}
|
||||
setAux = 1;
|
||||
}
|
||||
zStr = (const unsigned char*)sqlite3_value_text(argv[1]);
|
||||
if( zStr!=0 ){
|
||||
sqlite3_result_int(context, re_match(pRe, zStr, -1));
|
||||
}
|
||||
if( setAux ){
|
||||
sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke this routine to register the regexp() function with the
|
||||
** SQLite database connection.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_regexp_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0,
|
||||
re_sql_func, 0, 0);
|
||||
return rc;
|
||||
}
|
||||
+298
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
** 2018-02-24
|
||||
**
|
||||
** 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 an adjusted version of function sqlite3RunVacuum
|
||||
** to allow reducing or removing reserved page space.
|
||||
** For this purpose the number of reserved bytes per page for the target
|
||||
** database is passed as an extra parameter to the adjusted function.
|
||||
**
|
||||
** NOTE: When upgrading to a new version of SQLite3 it is strongly
|
||||
** recommended to check the original function sqlite3RunVacuum of the
|
||||
** new version for relevant changes, and to incorporate them in the
|
||||
** adjusted function below.
|
||||
**
|
||||
** Change 0: Rename function to sqlite3RunVacuumForRekey()
|
||||
** Change 1: Add parameter 'int nRes'
|
||||
** Change 2: Remove local variable 'int nRes'
|
||||
** Change 3: Remove initialization 'nRes = sqlite3BtreeGetOptimalReserve(pMain)'
|
||||
**
|
||||
** This code is generated by the script rekeyvacuum.sh from SQLite version 3.29.0 amalgamation.
|
||||
*/
|
||||
SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuumForRekey(
|
||||
char **pzErrMsg, /* Write error message here */
|
||||
sqlite3 *db, /* Database connection */
|
||||
int iDb, /* Which attached DB to vacuum */
|
||||
sqlite3_value *pOut /* Write results here, if not NULL. VACUUM INTO */
|
||||
, int nRes){
|
||||
int rc = SQLITE_OK; /* Return code from service routines */
|
||||
Btree *pMain; /* The database being vacuumed */
|
||||
Btree *pTemp; /* The temporary database we vacuum into */
|
||||
u32 saved_mDbFlags; /* Saved value of db->mDbFlags */
|
||||
u64 saved_flags; /* Saved value of db->flags */
|
||||
int saved_nChange; /* Saved value of db->nChange */
|
||||
int saved_nTotalChange; /* Saved value of db->nTotalChange */
|
||||
u32 saved_openFlags; /* Saved value of db->openFlags */
|
||||
u8 saved_mTrace; /* Saved trace settings */
|
||||
Db *pDb = 0; /* Database to detach at end of vacuum */
|
||||
int isMemDb; /* True if vacuuming a :memory: database */
|
||||
int nDb; /* Number of attached databases */
|
||||
const char *zDbMain; /* Schema name of database to vacuum */
|
||||
const char *zOut; /* Name of output file */
|
||||
|
||||
if( !db->autoCommit ){
|
||||
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
|
||||
return SQLITE_ERROR; /* IMP: R-12218-18073 */
|
||||
}
|
||||
if( db->nVdbeActive>1 ){
|
||||
sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress");
|
||||
return SQLITE_ERROR; /* IMP: R-15610-35227 */
|
||||
}
|
||||
saved_openFlags = db->openFlags;
|
||||
if( pOut ){
|
||||
if( sqlite3_value_type(pOut)!=SQLITE_TEXT ){
|
||||
sqlite3SetString(pzErrMsg, db, "non-text filename");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
zOut = (const char*)sqlite3_value_text(pOut);
|
||||
db->openFlags &= ~SQLITE_OPEN_READONLY;
|
||||
db->openFlags |= SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE;
|
||||
}else{
|
||||
zOut = "";
|
||||
}
|
||||
|
||||
/* Save the current value of the database flags so that it can be
|
||||
** restored before returning. Then set the writable-schema flag, and
|
||||
** disable CHECK and foreign key constraints. */
|
||||
saved_flags = db->flags;
|
||||
saved_mDbFlags = db->mDbFlags;
|
||||
saved_nChange = db->nChange;
|
||||
saved_nTotalChange = db->nTotalChange;
|
||||
saved_mTrace = db->mTrace;
|
||||
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
|
||||
db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
|
||||
db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder
|
||||
| SQLITE_Defensive | SQLITE_CountRows);
|
||||
db->mTrace = 0;
|
||||
|
||||
zDbMain = db->aDb[iDb].zDbSName;
|
||||
pMain = db->aDb[iDb].pBt;
|
||||
isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
|
||||
|
||||
/* Attach the temporary database as 'vacuum_db'. The synchronous pragma
|
||||
** can be set to 'off' for this file, as it is not recovered if a crash
|
||||
** occurs anyway. The integrity of the database is maintained by a
|
||||
** (possibly synchronous) transaction opened on the main database before
|
||||
** sqlite3BtreeCopyFile() is called.
|
||||
**
|
||||
** An optimisation would be to use a non-journaled pager.
|
||||
** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but
|
||||
** that actually made the VACUUM run slower. Very little journalling
|
||||
** actually occurs when doing a vacuum since the vacuum_db is initially
|
||||
** empty. Only the journal header is written. Apparently it takes more
|
||||
** time to parse and run the PRAGMA to turn journalling off than it does
|
||||
** to write the journal header file.
|
||||
*/
|
||||
nDb = db->nDb;
|
||||
rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut);
|
||||
db->openFlags = saved_openFlags;
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
assert( (db->nDb-1)==nDb );
|
||||
pDb = &db->aDb[nDb];
|
||||
assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
|
||||
pTemp = pDb->pBt;
|
||||
if( pOut ){
|
||||
sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp));
|
||||
i64 sz = 0;
|
||||
if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3SetString(pzErrMsg, db, "output file already exists");
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
db->mDbFlags |= DBFLAG_VacuumInto;
|
||||
}
|
||||
|
||||
/* A VACUUM cannot change the pagesize of an encrypted database. */
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
if( db->nextPagesize ){
|
||||
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
|
||||
int nKey;
|
||||
char *zKey;
|
||||
sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey);
|
||||
if( nKey ) db->nextPagesize = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
|
||||
sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
|
||||
sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL);
|
||||
|
||||
/* Begin a transaction and take an exclusive lock on the main database
|
||||
** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below,
|
||||
** to ensure that we do not try to change the page-size on a WAL database.
|
||||
*/
|
||||
rc = execSql(db, pzErrMsg, "BEGIN");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeBeginTrans(pMain, pOut==0 ? 2 : 0, 0);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Do not attempt to change the page size for a WAL database */
|
||||
if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain))
|
||||
==PAGER_JOURNALMODE_WAL ){
|
||||
db->nextPagesize = 0;
|
||||
}
|
||||
|
||||
if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0)
|
||||
|| (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
|
||||
|| NEVER(db->mallocFailed)
|
||||
){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
sqlite3BtreeSetAutoVacuum(pTemp, db->nextAutovac>=0 ? db->nextAutovac :
|
||||
sqlite3BtreeGetAutoVacuum(pMain));
|
||||
#endif
|
||||
|
||||
/* Query the schema of the main database. Create a mirror schema
|
||||
** in the temporary database.
|
||||
*/
|
||||
db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */
|
||||
rc = execSqlF(db, pzErrMsg,
|
||||
"SELECT sql FROM \"%w\".sqlite_master"
|
||||
" WHERE type='table'AND name<>'sqlite_sequence'"
|
||||
" AND coalesce(rootpage,1)>0",
|
||||
zDbMain
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = execSqlF(db, pzErrMsg,
|
||||
"SELECT sql FROM \"%w\".sqlite_master"
|
||||
" WHERE type='index'",
|
||||
zDbMain
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
db->init.iDb = 0;
|
||||
|
||||
/* Loop through the tables in the main database. For each, do
|
||||
** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
|
||||
** the contents to the temporary database.
|
||||
*/
|
||||
rc = execSqlF(db, pzErrMsg,
|
||||
"SELECT'INSERT INTO vacuum_db.'||quote(name)"
|
||||
"||' SELECT*FROM\"%w\".'||quote(name)"
|
||||
"FROM vacuum_db.sqlite_master "
|
||||
"WHERE type='table'AND coalesce(rootpage,1)>0",
|
||||
zDbMain
|
||||
);
|
||||
assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
|
||||
db->mDbFlags &= ~DBFLAG_Vacuum;
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Copy the triggers, views, and virtual tables from the main database
|
||||
** over to the temporary database. None of these objects has any
|
||||
** associated storage, so all we have to do is copy their entries
|
||||
** from the SQLITE_MASTER table.
|
||||
*/
|
||||
rc = execSqlF(db, pzErrMsg,
|
||||
"INSERT INTO vacuum_db.sqlite_master"
|
||||
" SELECT*FROM \"%w\".sqlite_master"
|
||||
" WHERE type IN('view','trigger')"
|
||||
" OR(type='table'AND rootpage=0)",
|
||||
zDbMain
|
||||
);
|
||||
if( rc ) goto end_of_vacuum;
|
||||
|
||||
/* At this point, there is a write transaction open on both the
|
||||
** vacuum database and the main database. Assuming no error occurs,
|
||||
** both transactions are closed by this block - the main database
|
||||
** transaction by sqlite3BtreeCopyFile() and the other by an explicit
|
||||
** call to sqlite3BtreeCommit().
|
||||
*/
|
||||
{
|
||||
u32 meta;
|
||||
int i;
|
||||
|
||||
/* This array determines which meta meta values are preserved in the
|
||||
** vacuum. Even entries are the meta value number and odd entries
|
||||
** are an increment to apply to the meta value after the vacuum.
|
||||
** The increment is used to increase the schema cookie so that other
|
||||
** connections to the same database will know to reread the schema.
|
||||
*/
|
||||
static const unsigned char aCopy[] = {
|
||||
BTREE_SCHEMA_VERSION, 1, /* Add one to the old schema cookie */
|
||||
BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */
|
||||
BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */
|
||||
BTREE_USER_VERSION, 0, /* Preserve the user version */
|
||||
BTREE_APPLICATION_ID, 0, /* Preserve the application id */
|
||||
};
|
||||
|
||||
assert( 1==sqlite3BtreeIsInTrans(pTemp) );
|
||||
assert( pOut!=0 || 1==sqlite3BtreeIsInTrans(pMain) );
|
||||
|
||||
/* Copy Btree meta values */
|
||||
for(i=0; i<ArraySize(aCopy); i+=2){
|
||||
/* GetMeta() and UpdateMeta() cannot fail in this context because
|
||||
** we already have page 1 loaded into cache and marked dirty. */
|
||||
sqlite3BtreeGetMeta(pMain, aCopy[i], &meta);
|
||||
rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]);
|
||||
if( NEVER(rc!=SQLITE_OK) ) goto end_of_vacuum;
|
||||
}
|
||||
|
||||
if( pOut==0 ){
|
||||
rc = sqlite3BtreeCopyFile(pMain, pTemp);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeCommit(pTemp);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pOut==0 ){
|
||||
sqlite3BtreeSetAutoVacuum(pMain, sqlite3BtreeGetAutoVacuum(pTemp));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
assert( rc==SQLITE_OK );
|
||||
if( pOut==0 ){
|
||||
rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes,1);
|
||||
}
|
||||
|
||||
end_of_vacuum:
|
||||
/* Restore the original value of db->flags */
|
||||
db->init.iDb = 0;
|
||||
db->mDbFlags = saved_mDbFlags;
|
||||
db->flags = saved_flags;
|
||||
db->nChange = saved_nChange;
|
||||
db->nTotalChange = saved_nTotalChange;
|
||||
db->mTrace = saved_mTrace;
|
||||
sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
|
||||
|
||||
/* Currently there is an SQL level transaction open on the vacuum
|
||||
** database. No locks are held on any other files (since the main file
|
||||
** was committed at the btree level). So it safe to end the transaction
|
||||
** by manually setting the autoCommit flag to true and detaching the
|
||||
** vacuum database. The vacuum_db journal file is deleted when the pager
|
||||
** is closed by the DETACH.
|
||||
*/
|
||||
db->autoCommit = 1;
|
||||
|
||||
if( pDb ){
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
pDb->pSchema = 0;
|
||||
}
|
||||
|
||||
/* This both clears the schemas and reduces the size of the db->aDb[]
|
||||
** array. */
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
|
||||
return rc;
|
||||
}
|
||||
+1676
File diff suppressed because it is too large
Load Diff
+194
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
** Name: rijndael.h
|
||||
** Purpose: Header file for the Rijndael cipher
|
||||
** Author: Ulrich Telle
|
||||
** Created: 2006-12-06
|
||||
** Copyright: (c) 2006-2018 Ulrich Telle
|
||||
** License: LGPL-3.0+ WITH WxWindows-exception-3.1
|
||||
**
|
||||
** Adjustments were made to make this code work with the wxSQLite3's
|
||||
** SQLite encryption extension.
|
||||
** The original code is public domain (see comments below).
|
||||
*/
|
||||
|
||||
/*
|
||||
/// \file rijndael.h Interface of the Rijndael cipher
|
||||
*/
|
||||
|
||||
#ifndef _RIJNDAEL_H_
|
||||
#define _RIJNDAEL_H_
|
||||
|
||||
/*
|
||||
// File : rijndael.h
|
||||
// Creation date : Sun Nov 5 2000 03:21:05 CEST
|
||||
// Author : Szymon Stefanek (stefanek@tin.it)
|
||||
//
|
||||
// Another implementation of the Rijndael cipher.
|
||||
// This is intended to be an easily usable library file.
|
||||
// This code is public domain.
|
||||
// Based on the Vincent Rijmen and K.U.Leuven implementation 2.4.
|
||||
//
|
||||
// Original Copyright notice:
|
||||
//
|
||||
// rijndael-alg-fst.c v2.4 April '2000
|
||||
// rijndael-alg-fst.h
|
||||
// rijndael-api-fst.c
|
||||
// rijndael-api-fst.h
|
||||
//
|
||||
// Optimised ANSI C code
|
||||
//
|
||||
// authors: v1.0: Antoon Bosselaers
|
||||
// v2.0: Vincent Rijmen, K.U.Leuven
|
||||
// v2.3: Paulo Barreto
|
||||
// v2.4: Vincent Rijmen, K.U.Leuven
|
||||
//
|
||||
// This code is placed in the public domain.
|
||||
//
|
||||
|
||||
//
|
||||
// This implementation works on 128 , 192 , 256 bit keys
|
||||
// and on 128 bit blocks
|
||||
//
|
||||
|
||||
//
|
||||
// Example of usage:
|
||||
//
|
||||
// // Input data
|
||||
// unsigned char key[32]; // The key
|
||||
// initializeYour256BitKey(); // Obviously initialized with sth
|
||||
// const unsigned char * plainText = getYourPlainText(); // Your plain text
|
||||
// int plainTextLen = strlen(plainText); // Plain text length
|
||||
//
|
||||
// // Encrypting
|
||||
// Rijndael rin;
|
||||
// unsigned char output[plainTextLen + 16];
|
||||
//
|
||||
// rin.init(Rijndael::CBC,Rijndael::Encrypt,key,Rijndael::Key32Bytes);
|
||||
// // It is a good idea to check the error code
|
||||
// int len = rin.padEncrypt(plainText,len,output);
|
||||
// if(len >= 0)useYourEncryptedText();
|
||||
// else encryptError(len);
|
||||
//
|
||||
// // Decrypting: we can reuse the same object
|
||||
// unsigned char output2[len];
|
||||
// rin.init(Rijndael::CBC,Rijndael::Decrypt,key,Rijndael::Key32Bytes));
|
||||
// len = rin.padDecrypt(output,len,output2);
|
||||
// if(len >= 0)useYourDecryptedText();
|
||||
// else decryptError(len);
|
||||
//
|
||||
*/
|
||||
|
||||
#define _MAX_KEY_COLUMNS (256/32)
|
||||
#define _MAX_ROUNDS 14
|
||||
#define MAX_IV_SIZE 16
|
||||
|
||||
/* We assume that unsigned int is 32 bits long.... */
|
||||
typedef unsigned char UINT8;
|
||||
typedef unsigned int UINT32;
|
||||
typedef unsigned short UINT16;
|
||||
|
||||
/* Error codes */
|
||||
#define RIJNDAEL_SUCCESS 0
|
||||
#define RIJNDAEL_UNSUPPORTED_MODE -1
|
||||
#define RIJNDAEL_UNSUPPORTED_DIRECTION -2
|
||||
#define RIJNDAEL_UNSUPPORTED_KEY_LENGTH -3
|
||||
#define RIJNDAEL_BAD_KEY -4
|
||||
#define RIJNDAEL_NOT_INITIALIZED -5
|
||||
#define RIJNDAEL_BAD_DIRECTION -6
|
||||
#define RIJNDAEL_CORRUPTED_DATA -7
|
||||
|
||||
#define RIJNDAEL_Direction_Encrypt 0
|
||||
#define RIJNDAEL_Direction_Decrypt 1
|
||||
|
||||
#define RIJNDAEL_Direction_Mode_ECB 0
|
||||
#define RIJNDAEL_Direction_Mode_CBC 1
|
||||
#define RIJNDAEL_Direction_Mode_CFB1 2
|
||||
|
||||
#define RIJNDAEL_Direction_KeyLength_Key16Bytes 0
|
||||
#define RIJNDAEL_Direction_KeyLength_Key24Bytes 1
|
||||
#define RIJNDAEL_Direction_KeyLength_Key32Bytes 2
|
||||
|
||||
#define RIJNDAEL_State_Valid 0
|
||||
#define RIJNDAEL_State_Invalid 1
|
||||
|
||||
/*
|
||||
/// Class implementing the Rijndael cipher. (For internal use only)
|
||||
*/
|
||||
|
||||
typedef struct _Rijndael
|
||||
{
|
||||
int m_state;
|
||||
int m_mode;
|
||||
int m_direction;
|
||||
UINT8 m_initVector[MAX_IV_SIZE];
|
||||
UINT32 m_uRounds;
|
||||
UINT8 m_expandedKey[_MAX_ROUNDS+1][4][4];
|
||||
} Rijndael;
|
||||
|
||||
void RijndaelCreate(Rijndael* rijndael);
|
||||
|
||||
/*
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// init(): Initializes the crypt session
|
||||
// Returns RIJNDAEL_SUCCESS or an error code
|
||||
// mode : Rijndael::ECB, Rijndael::CBC or Rijndael::CFB1
|
||||
// You have to use the same mode for encrypting and decrypting
|
||||
// dir : Rijndael::Encrypt or Rijndael::Decrypt
|
||||
// A cipher instance works only in one direction
|
||||
// (Well , it could be easily modified to work in both
|
||||
// directions with a single init() call, but it looks
|
||||
// useless to me...anyway , it is a matter of generating
|
||||
// two expanded keys)
|
||||
// key : array of unsigned octets , it can be 16 , 24 or 32 bytes long
|
||||
// this CAN be binary data (it is not expected to be null terminated)
|
||||
// keyLen : Rijndael::Key16Bytes , Rijndael::Key24Bytes or Rijndael::Key32Bytes
|
||||
// initVector: initialization vector, you will usually use 0 here
|
||||
*/
|
||||
int RijndaelInit(Rijndael* rijndael, int mode, int dir, UINT8* key, int keyLen, UINT8* initVector);
|
||||
|
||||
/*
|
||||
// Encrypts the input array (can be binary data)
|
||||
// The input array length must be a multiple of 16 bytes, the remaining part
|
||||
// is DISCARDED.
|
||||
// so it actually encrypts inputLen / 128 blocks of input and puts it in outBuffer
|
||||
// Input len is in BITS!
|
||||
// outBuffer must be at least inputLen / 8 bytes long.
|
||||
// Returns the encrypted buffer length in BITS or an error code < 0 in case of error
|
||||
*/
|
||||
int RijndaelBlockEncrypt(Rijndael* rijndael, UINT8 *input, int inputLen, UINT8 *outBuffer);
|
||||
|
||||
/*
|
||||
// Encrypts the input array (can be binary data)
|
||||
// The input array can be any length , it is automatically padded on a 16 byte boundary.
|
||||
// Input len is in BYTES!
|
||||
// outBuffer must be at least (inputLen + 16) bytes long
|
||||
// Returns the encrypted buffer length in BYTES or an error code < 0 in case of error
|
||||
*/
|
||||
int RijndaelPadEncrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8 *outBuffer);
|
||||
|
||||
/*
|
||||
// Decrypts the input vector
|
||||
// Input len is in BITS!
|
||||
// outBuffer must be at least inputLen / 8 bytes long
|
||||
// Returns the decrypted buffer length in BITS and an error code < 0 in case of error
|
||||
*/
|
||||
int RijndaelBlockDecrypt(Rijndael* rijndael, UINT8 *input, int inputLen, UINT8 *outBuffer);
|
||||
|
||||
/*
|
||||
// Decrypts the input vector
|
||||
// Input len is in BYTES!
|
||||
// outBuffer must be at least inputLen bytes long
|
||||
// Returns the decrypted buffer length in BYTES and an error code < 0 in case of error
|
||||
*/
|
||||
int RijndaelPadDecrypt(Rijndael* rijndael, UINT8 *input, int inputOctets, UINT8 *outBuffer);
|
||||
|
||||
void RijndaelInvalidate(Rijndael* rijndael);
|
||||
void RijndaelKeySched(Rijndael* rijndael, UINT8 key[_MAX_KEY_COLUMNS][4]);
|
||||
void RijndaelKeyEncToDec(Rijndael* rijndael);
|
||||
void RijndaelEncrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16]);
|
||||
void RijndaelDecrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16]);
|
||||
|
||||
#endif /* _RIJNDAEL_H_ */
|
||||
Vendored
+423
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
** 2015-08-18
|
||||
**
|
||||
** 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 demonstrates how to create a table-valued-function using
|
||||
** a virtual table. This demo implements the generate_series() function
|
||||
** which gives similar results to the eponymous function in PostgreSQL.
|
||||
** Examples:
|
||||
**
|
||||
** SELECT * FROM generate_series(0,100,5);
|
||||
**
|
||||
** The query above returns integers from 0 through 100 counting by steps
|
||||
** of 5.
|
||||
**
|
||||
** SELECT * FROM generate_series(0,100);
|
||||
**
|
||||
** Integers from 0 through 100 with a step size of 1.
|
||||
**
|
||||
** SELECT * FROM generate_series(20) LIMIT 10;
|
||||
**
|
||||
** Integers 20 through 29.
|
||||
**
|
||||
** HOW IT WORKS
|
||||
**
|
||||
** The generate_series "function" is really a virtual table with the
|
||||
** following schema:
|
||||
**
|
||||
** CREATE TABLE generate_series(
|
||||
** value,
|
||||
** start HIDDEN,
|
||||
** stop HIDDEN,
|
||||
** step HIDDEN
|
||||
** );
|
||||
**
|
||||
** Function arguments in queries against this virtual table are translated
|
||||
** into equality constraints against successive hidden columns. In other
|
||||
** words, the following pairs of queries are equivalent to each other:
|
||||
**
|
||||
** SELECT * FROM generate_series(0,100,5);
|
||||
** SELECT * FROM generate_series WHERE start=0 AND stop=100 AND step=5;
|
||||
**
|
||||
** SELECT * FROM generate_series(0,100);
|
||||
** SELECT * FROM generate_series WHERE start=0 AND stop=100;
|
||||
**
|
||||
** SELECT * FROM generate_series(20) LIMIT 10;
|
||||
** SELECT * FROM generate_series WHERE start=20 LIMIT 10;
|
||||
**
|
||||
** The generate_series virtual table implementation leaves the xCreate method
|
||||
** set to NULL. This means that it is not possible to do a CREATE VIRTUAL
|
||||
** TABLE command with "generate_series" as the USING argument. Instead, there
|
||||
** is a single generate_series virtual table that is always available without
|
||||
** having to be created first.
|
||||
**
|
||||
** The xBestIndex method looks for equality constraints against the hidden
|
||||
** start, stop, and step columns, and if present, it uses those constraints
|
||||
** to bound the sequence of generated values. If the equality constraints
|
||||
** are missing, it uses 0 for start, 4294967295 for stop, and 1 for step.
|
||||
** xBestIndex returns a small cost when both start and stop are available,
|
||||
** and a very large cost if either start or stop are unavailable. This
|
||||
** encourages the query planner to order joins such that the bounds of the
|
||||
** series are well-defined.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
|
||||
/* series_cursor is a subclass of sqlite3_vtab_cursor which will
|
||||
** serve as the underlying representation of a cursor that scans
|
||||
** over rows of the result
|
||||
*/
|
||||
typedef struct series_cursor series_cursor;
|
||||
struct series_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
int isDesc; /* True to count down rather than up */
|
||||
sqlite3_int64 iRowid; /* The rowid */
|
||||
sqlite3_int64 iValue; /* Current value ("value") */
|
||||
sqlite3_int64 mnValue; /* Mimimum value ("start") */
|
||||
sqlite3_int64 mxValue; /* Maximum value ("stop") */
|
||||
sqlite3_int64 iStep; /* Increment ("step") */
|
||||
};
|
||||
|
||||
/*
|
||||
** The seriesConnect() method is invoked to create a new
|
||||
** series_vtab that describes the generate_series virtual table.
|
||||
**
|
||||
** Think of this routine as the constructor for series_vtab objects.
|
||||
**
|
||||
** All this routine needs to do is:
|
||||
**
|
||||
** (1) Allocate the series_vtab object and initialize all fields.
|
||||
**
|
||||
** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
|
||||
** result set of queries against generate_series will look like.
|
||||
*/
|
||||
static int seriesConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
sqlite3_vtab *pNew;
|
||||
int rc;
|
||||
|
||||
/* Column numbers */
|
||||
#define SERIES_COLUMN_VALUE 0
|
||||
#define SERIES_COLUMN_START 1
|
||||
#define SERIES_COLUMN_STOP 2
|
||||
#define SERIES_COLUMN_STEP 3
|
||||
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x(value,start hidden,stop hidden,step hidden)");
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is the destructor for series_cursor objects.
|
||||
*/
|
||||
static int seriesDisconnect(sqlite3_vtab *pVtab){
|
||||
sqlite3_free(pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Constructor for a new series_cursor object.
|
||||
*/
|
||||
static int seriesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
series_cursor *pCur;
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destructor for a series_cursor.
|
||||
*/
|
||||
static int seriesClose(sqlite3_vtab_cursor *cur){
|
||||
sqlite3_free(cur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Advance a series_cursor to its next row of output.
|
||||
*/
|
||||
static int seriesNext(sqlite3_vtab_cursor *cur){
|
||||
series_cursor *pCur = (series_cursor*)cur;
|
||||
if( pCur->isDesc ){
|
||||
pCur->iValue -= pCur->iStep;
|
||||
}else{
|
||||
pCur->iValue += pCur->iStep;
|
||||
}
|
||||
pCur->iRowid++;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return values of columns for the row at which the series_cursor
|
||||
** is currently pointing.
|
||||
*/
|
||||
static int seriesColumn(
|
||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||
int i /* Which column to return */
|
||||
){
|
||||
series_cursor *pCur = (series_cursor*)cur;
|
||||
sqlite3_int64 x = 0;
|
||||
switch( i ){
|
||||
case SERIES_COLUMN_START: x = pCur->mnValue; break;
|
||||
case SERIES_COLUMN_STOP: x = pCur->mxValue; break;
|
||||
case SERIES_COLUMN_STEP: x = pCur->iStep; break;
|
||||
default: x = pCur->iValue; break;
|
||||
}
|
||||
sqlite3_result_int64(ctx, x);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the rowid for the current row. In this implementation, the
|
||||
** first row returned is assigned rowid value 1, and each subsequent
|
||||
** row a value 1 more than that of the previous.
|
||||
*/
|
||||
static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
series_cursor *pCur = (series_cursor*)cur;
|
||||
*pRowid = pCur->iRowid;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor has been moved off of the last
|
||||
** row of output.
|
||||
*/
|
||||
static int seriesEof(sqlite3_vtab_cursor *cur){
|
||||
series_cursor *pCur = (series_cursor*)cur;
|
||||
if( pCur->isDesc ){
|
||||
return pCur->iValue < pCur->mnValue;
|
||||
}else{
|
||||
return pCur->iValue > pCur->mxValue;
|
||||
}
|
||||
}
|
||||
|
||||
/* True to cause run-time checking of the start=, stop=, and/or step=
|
||||
** parameters. The only reason to do this is for testing the
|
||||
** constraint checking logic for virtual tables in the SQLite core.
|
||||
*/
|
||||
#ifndef SQLITE_SERIES_CONSTRAINT_VERIFY
|
||||
# define SQLITE_SERIES_CONSTRAINT_VERIFY 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This method is called to "rewind" the series_cursor object back
|
||||
** to the first row of output. This method is always called at least
|
||||
** once prior to any call to seriesColumn() or seriesRowid() or
|
||||
** seriesEof().
|
||||
**
|
||||
** The query plan selected by seriesBestIndex is passed in the idxNum
|
||||
** parameter. (idxStr is not used in this implementation.) idxNum
|
||||
** is a bitmask showing which constraints are available:
|
||||
**
|
||||
** 1: start=VALUE
|
||||
** 2: stop=VALUE
|
||||
** 4: step=VALUE
|
||||
**
|
||||
** Also, if bit 8 is set, that means that the series should be output
|
||||
** in descending order rather than in ascending order.
|
||||
**
|
||||
** This routine should initialize the cursor and position it so that it
|
||||
** is pointing at the first row, or pointing off the end of the table
|
||||
** (so that seriesEof() will return true) if the table is empty.
|
||||
*/
|
||||
static int seriesFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
series_cursor *pCur = (series_cursor *)pVtabCursor;
|
||||
int i = 0;
|
||||
if( idxNum & 1 ){
|
||||
pCur->mnValue = sqlite3_value_int64(argv[i++]);
|
||||
}else{
|
||||
pCur->mnValue = 0;
|
||||
}
|
||||
if( idxNum & 2 ){
|
||||
pCur->mxValue = sqlite3_value_int64(argv[i++]);
|
||||
}else{
|
||||
pCur->mxValue = 0xffffffff;
|
||||
}
|
||||
if( idxNum & 4 ){
|
||||
pCur->iStep = sqlite3_value_int64(argv[i++]);
|
||||
if( pCur->iStep<1 ) pCur->iStep = 1;
|
||||
}else{
|
||||
pCur->iStep = 1;
|
||||
}
|
||||
for(i=0; i<argc; i++){
|
||||
if( sqlite3_value_type(argv[i])==SQLITE_NULL ){
|
||||
/* If any of the constraints have a NULL value, then return no rows.
|
||||
** See ticket https://www.sqlite.org/src/info/fac496b61722daf2 */
|
||||
pCur->mnValue = 1;
|
||||
pCur->mxValue = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( idxNum & 8 ){
|
||||
pCur->isDesc = 1;
|
||||
pCur->iValue = pCur->mxValue;
|
||||
if( pCur->iStep>0 ){
|
||||
pCur->iValue -= (pCur->mxValue - pCur->mnValue)%pCur->iStep;
|
||||
}
|
||||
}else{
|
||||
pCur->isDesc = 0;
|
||||
pCur->iValue = pCur->mnValue;
|
||||
}
|
||||
pCur->iRowid = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** SQLite will invoke this method one or more times while planning a query
|
||||
** that uses the generate_series virtual table. This routine needs to create
|
||||
** a query plan for each invocation and compute an estimated cost for that
|
||||
** plan.
|
||||
**
|
||||
** In this implementation idxNum is used to represent the
|
||||
** query plan. idxStr is unused.
|
||||
**
|
||||
** The query plan is represented by bits in idxNum:
|
||||
**
|
||||
** (1) start = $value -- constraint exists
|
||||
** (2) stop = $value -- constraint exists
|
||||
** (4) step = $value -- constraint exists
|
||||
** (8) output in descending order
|
||||
*/
|
||||
static int seriesBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
int i, j; /* Loop over constraints */
|
||||
int idxNum = 0; /* The query plan bitmask */
|
||||
int unusableMask = 0; /* Mask of unusable constraints */
|
||||
int nArg = 0; /* Number of arguments that seriesFilter() expects */
|
||||
int aIdx[3]; /* Constraints on start, stop, and step */
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
|
||||
/* This implementation assumes that the start, stop, and step columns
|
||||
** are the last three columns in the virtual table. */
|
||||
assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
|
||||
assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
|
||||
aIdx[0] = aIdx[1] = aIdx[2] = -1;
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||
int iCol; /* 0 for start, 1 for stop, 2 for step */
|
||||
int iMask; /* bitmask for those column */
|
||||
if( pConstraint->iColumn<SERIES_COLUMN_START ) continue;
|
||||
iCol = pConstraint->iColumn - SERIES_COLUMN_START;
|
||||
assert( iCol>=0 && iCol<=2 );
|
||||
iMask = 1 << iCol;
|
||||
if( pConstraint->usable==0 ){
|
||||
unusableMask |= iMask;
|
||||
continue;
|
||||
}else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
|
||||
idxNum |= iMask;
|
||||
aIdx[iCol] = i;
|
||||
}
|
||||
}
|
||||
for(i=0; i<3; i++){
|
||||
if( (j = aIdx[i])>=0 ){
|
||||
pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg;
|
||||
pIdxInfo->aConstraintUsage[j].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
|
||||
}
|
||||
}
|
||||
if( (unusableMask & ~idxNum)!=0 ){
|
||||
/* The start, stop, and step columns are inputs. Therefore if there
|
||||
** are unusable constraints on any of start, stop, or step then
|
||||
** this plan is unusable */
|
||||
return SQLITE_CONSTRAINT;
|
||||
}
|
||||
if( (idxNum & 3)==3 ){
|
||||
/* Both start= and stop= boundaries are available. This is the
|
||||
** the preferred case */
|
||||
pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0));
|
||||
pIdxInfo->estimatedRows = 1000;
|
||||
if( pIdxInfo->nOrderBy==1 ){
|
||||
if( pIdxInfo->aOrderBy[0].desc ) idxNum |= 8;
|
||||
pIdxInfo->orderByConsumed = 1;
|
||||
}
|
||||
}else{
|
||||
/* If either boundary is missing, we have to generate a huge span
|
||||
** of numbers. Make this case very expensive so that the query
|
||||
** planner will work hard to avoid it. */
|
||||
pIdxInfo->estimatedRows = 2147483647;
|
||||
}
|
||||
pIdxInfo->idxNum = idxNum;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This following structure defines all the methods for the
|
||||
** generate_series virtual table.
|
||||
*/
|
||||
static sqlite3_module seriesModule = {
|
||||
0, /* iVersion */
|
||||
0, /* xCreate */
|
||||
seriesConnect, /* xConnect */
|
||||
seriesBestIndex, /* xBestIndex */
|
||||
seriesDisconnect, /* xDisconnect */
|
||||
0, /* xDestroy */
|
||||
seriesOpen, /* xOpen - open a cursor */
|
||||
seriesClose, /* xClose - close a cursor */
|
||||
seriesFilter, /* xFilter - configure scan constraints */
|
||||
seriesNext, /* xNext - advance a cursor */
|
||||
seriesEof, /* xEof - check for end of scan */
|
||||
seriesColumn, /* xColumn - read data */
|
||||
seriesRowid, /* xRowid - read data */
|
||||
0, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
};
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_series_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( sqlite3_libversion_number()<3008012 ){
|
||||
*pzErrMsg = sqlite3_mprintf(
|
||||
"generate_series() requires SQLite 3.8.12 or later");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
rc = sqlite3_create_module(db, "generate_series", &seriesModule, 0);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
Vendored
+291
@@ -0,0 +1,291 @@
|
||||
/**
|
||||
* @file sha1.c SHA-1 in C
|
||||
*/
|
||||
|
||||
/*
|
||||
By Steve Reid <sreid@sea-to-sky.net>
|
||||
100% Public Domain
|
||||
|
||||
-----------------
|
||||
Modified 7/98
|
||||
By James H. Brown <jbrown@burgoyne.com>
|
||||
Still 100% Public Domain
|
||||
|
||||
Corrected a problem which generated improper hash values on 16 bit machines
|
||||
Routine SHA1Update changed from
|
||||
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
|
||||
len)
|
||||
to
|
||||
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
|
||||
long len)
|
||||
|
||||
The 'len' parameter was declared an int which works fine on 32 bit machines.
|
||||
However, on 16 bit machines an int is too small for the shifts being done
|
||||
against
|
||||
it. This caused the hash function to generate incorrect values if len was
|
||||
greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
|
||||
|
||||
Since the file IO in main() reads 16K at a time, any file 8K or larger would
|
||||
be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
|
||||
"a"s).
|
||||
|
||||
I also changed the declaration of variables i & j in SHA1Update to
|
||||
unsigned long from unsigned int for the same reason.
|
||||
|
||||
These changes should make no difference to any 32 bit implementations since
|
||||
an
|
||||
int and a long are the same size in those environments.
|
||||
|
||||
--
|
||||
I also corrected a few compiler warnings generated by Borland C.
|
||||
1. Added #include <process.h> for exit() prototype
|
||||
2. Removed unused variable 'j' in SHA1Final
|
||||
3. Changed exit(0) to return(0) at end of main.
|
||||
|
||||
ALL changes I made can be located by searching for comments containing 'JHB'
|
||||
-----------------
|
||||
Modified 8/98
|
||||
By Steve Reid <sreid@sea-to-sky.net>
|
||||
Still 100% public domain
|
||||
|
||||
1- Removed #include <process.h> and used return() instead of exit()
|
||||
2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
|
||||
3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
|
||||
|
||||
-----------------
|
||||
Modified 4/01
|
||||
By Saul Kravitz <Saul.Kravitz@celera.com>
|
||||
Still 100% PD
|
||||
Modified to run on Compaq Alpha hardware.
|
||||
|
||||
-----------------
|
||||
Modified 07/2002
|
||||
By Ralph Giles <giles@artofcode.com>
|
||||
Still 100% public domain
|
||||
modified for use with stdint types, autoconf
|
||||
code cleanup, removed attribution comments
|
||||
switched SHA1Final() argument order for consistency
|
||||
use SHA1_ prefix for public api
|
||||
move public api to sha1.h
|
||||
|
||||
-----------------
|
||||
Modified 02/2018
|
||||
By Ulrich Telle <github@telle-online.de>
|
||||
Still 100% public domain
|
||||
modified for use with fast-pbkdf2 (written by Joseph Birr-Pixton)
|
||||
detect endianess at run-time
|
||||
*/
|
||||
|
||||
/*
|
||||
Test Vectors (from FIPS PUB 180-1)
|
||||
"abc"
|
||||
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
|
||||
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
|
||||
A million repetitions of "a"
|
||||
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
|
||||
*/
|
||||
|
||||
#include "mystdint.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sha1.h"
|
||||
|
||||
#if 0
|
||||
/* TODO: asm doesn't compile under Linux, use generic C equivalent for now */
|
||||
#if __GNUC__ && (defined(__i386__) || defined(__x86_64__))
|
||||
/*
|
||||
* GCC by itself only generates left rotates. Use right rotates if
|
||||
* possible to be kinder to dinky implementations with iterative rotate
|
||||
* instructions.
|
||||
*/
|
||||
#define SHA_ROT(op, x, k) \
|
||||
({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; })
|
||||
#define rol(x,k) SHA_ROT("roll", x, k)
|
||||
#define ror(x,k) SHA_ROT("rorl", x, k)
|
||||
#else
|
||||
/* Generic C equivalent */
|
||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
#define ror(value, bits) (((value) << (32 - (bits))) | ((value) >> (bits)))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Generic C equivalent */
|
||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
#define ror(value, bits) (((value) << (32 - (bits))) | ((value) >> (bits)))
|
||||
|
||||
#define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
|
||||
|(rol(block[i],8)&0x00FF00FF))
|
||||
#define blk0be(i) block[i]
|
||||
#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
|
||||
^block[(i+2)&15]^block[i&15],1))
|
||||
|
||||
/*
|
||||
* (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
|
||||
*
|
||||
* Rl0() for little-endian and Rb0() for big-endian. Endianness is
|
||||
* determined at run-time.
|
||||
*/
|
||||
#define Rl0(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define Rb0(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define R1(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define R2(v,w,x,y,z,i) \
|
||||
z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2);
|
||||
#define R3(v,w,x,y,z,i) \
|
||||
z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2);
|
||||
#define R4(v,w,x,y,z,i) \
|
||||
z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2);
|
||||
|
||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||
void sha1_transform(sha1_ctx *context, const uint8_t buffer[64])
|
||||
{
|
||||
uint32_t a, b, c, d, e;
|
||||
static int one = 1;
|
||||
uint32_t block[16];
|
||||
memcpy(block, buffer, 64);
|
||||
|
||||
/* Copy context->h[] to working vars */
|
||||
a = context->h[0];
|
||||
b = context->h[1];
|
||||
c = context->h[2];
|
||||
d = context->h[3];
|
||||
e = context->h[4];
|
||||
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
if (1 == *(unsigned char*)&one) /* Check for endianess */
|
||||
{
|
||||
Rl0(a, b, c, d, e, 0); Rl0(e, a, b, c, d, 1); Rl0(d, e, a, b, c, 2); Rl0(c, d, e, a, b, 3);
|
||||
Rl0(b, c, d, e, a, 4); Rl0(a, b, c, d, e, 5); Rl0(e, a, b, c, d, 6); Rl0(d, e, a, b, c, 7);
|
||||
Rl0(c, d, e, a, b, 8); Rl0(b, c, d, e, a, 9); Rl0(a, b, c, d, e, 10); Rl0(e, a, b, c, d, 11);
|
||||
Rl0(d, e, a, b, c, 12); Rl0(c, d, e, a, b, 13); Rl0(b, c, d, e, a, 14); Rl0(a, b, c, d, e, 15);
|
||||
}
|
||||
else
|
||||
{
|
||||
Rb0(a, b, c, d, e, 0); Rb0(e, a, b, c, d, 1); Rb0(d, e, a, b, c, 2); Rb0(c, d, e, a, b, 3);
|
||||
Rb0(b, c, d, e, a, 4); Rb0(a, b, c, d, e, 5); Rb0(e, a, b, c, d, 6); Rb0(d, e, a, b, c, 7);
|
||||
Rb0(c, d, e, a, b, 8); Rb0(b, c, d, e, a, 9); Rb0(a, b, c, d, e, 10); Rb0(e, a, b, c, d, 11);
|
||||
Rb0(d, e, a, b, c, 12); Rb0(c, d, e, a, b, 13); Rb0(b, c, d, e, a, 14); Rb0(a, b, c, d, e, 15);
|
||||
}
|
||||
R1(e, a, b, c, d, 16); R1(d, e, a, b, c, 17); R1(c, d, e, a, b, 18); R1(b, c, d, e, a, 19);
|
||||
R2(a, b, c, d, e, 20); R2(e, a, b, c, d, 21); R2(d, e, a, b, c, 22); R2(c, d, e, a, b, 23);
|
||||
R2(b, c, d, e, a, 24); R2(a, b, c, d, e, 25); R2(e, a, b, c, d, 26); R2(d, e, a, b, c, 27);
|
||||
R2(c, d, e, a, b, 28); R2(b, c, d, e, a, 29); R2(a, b, c, d, e, 30); R2(e, a, b, c, d, 31);
|
||||
R2(d, e, a, b, c, 32); R2(c, d, e, a, b, 33); R2(b, c, d, e, a, 34); R2(a, b, c, d, e, 35);
|
||||
R2(e, a, b, c, d, 36); R2(d, e, a, b, c, 37); R2(c, d, e, a, b, 38); R2(b, c, d, e, a, 39);
|
||||
R3(a, b, c, d, e, 40); R3(e, a, b, c, d, 41); R3(d, e, a, b, c, 42); R3(c, d, e, a, b, 43);
|
||||
R3(b, c, d, e, a, 44); R3(a, b, c, d, e, 45); R3(e, a, b, c, d, 46); R3(d, e, a, b, c, 47);
|
||||
R3(c, d, e, a, b, 48); R3(b, c, d, e, a, 49); R3(a, b, c, d, e, 50); R3(e, a, b, c, d, 51);
|
||||
R3(d, e, a, b, c, 52); R3(c, d, e, a, b, 53); R3(b, c, d, e, a, 54); R3(a, b, c, d, e, 55);
|
||||
R3(e, a, b, c, d, 56); R3(d, e, a, b, c, 57); R3(c, d, e, a, b, 58); R3(b, c, d, e, a, 59);
|
||||
R4(a, b, c, d, e, 60); R4(e, a, b, c, d, 61); R4(d, e, a, b, c, 62); R4(c, d, e, a, b, 63);
|
||||
R4(b, c, d, e, a, 64); R4(a, b, c, d, e, 65); R4(e, a, b, c, d, 66); R4(d, e, a, b, c, 67);
|
||||
R4(c, d, e, a, b, 68); R4(b, c, d, e, a, 69); R4(a, b, c, d, e, 70); R4(e, a, b, c, d, 71);
|
||||
R4(d, e, a, b, c, 72); R4(c, d, e, a, b, 73); R4(b, c, d, e, a, 74); R4(a, b, c, d, e, 75);
|
||||
R4(e, a, b, c, d, 76); R4(d, e, a, b, c, 77); R4(c, d, e, a, b, 78); R4(b, c, d, e, a, 79);
|
||||
|
||||
/* Add the working vars back into context.state[] */
|
||||
context->h[0] += a;
|
||||
context->h[1] += b;
|
||||
context->h[2] += c;
|
||||
context->h[3] += d;
|
||||
context->h[4] += e;
|
||||
|
||||
/* Wipe variables */
|
||||
a = b = c = d = e = 0;
|
||||
memset(block, 0, 64);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize new context
|
||||
*
|
||||
* @param context SHA1-Context
|
||||
*/
|
||||
void sha1_init(sha1_ctx *context)
|
||||
{
|
||||
/* SHA1 initialization constants */
|
||||
context->h[0] = 0x67452301;
|
||||
context->h[1] = 0xefcdab89;
|
||||
context->h[2] = 0x98badcfe;
|
||||
context->h[3] = 0x10325476;
|
||||
context->h[4] = 0xc3d2e1f0;
|
||||
context->count[0] = context->count[1] = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run your data through this
|
||||
*
|
||||
* @param context SHA1-Context
|
||||
* @param p Buffer to run SHA1 on
|
||||
* @param len Number of bytes
|
||||
*/
|
||||
void sha1_update(sha1_ctx *context, const void *p, size_t len)
|
||||
{
|
||||
const uint8_t *data = p;
|
||||
size_t i, j;
|
||||
|
||||
j = (context->count[0] >> 3) & 63;
|
||||
if ((context->count[0] += (uint32_t) (len << 3)) < (len << 3))
|
||||
{
|
||||
context->count[1]++;
|
||||
}
|
||||
context->count[1] += (uint32_t) (len >> 29);
|
||||
if ((j + len) > 63)
|
||||
{
|
||||
memcpy(&context->buffer[j], data, (i = 64 - j));
|
||||
sha1_transform(context, context->buffer);
|
||||
for (; i + 63 < len; i += 64)
|
||||
{
|
||||
sha1_transform(context, data + i);
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
memcpy(&context->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add padding and return the message digest
|
||||
*
|
||||
* @param digest Generated message digest
|
||||
* @param context SHA1-Context
|
||||
*/
|
||||
void sha1_final(sha1_ctx *context, uint8_t digest[SHA1_DIGEST_SIZE])
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t finalcount[8];
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
finalcount[i] = (uint8_t) ((context->count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3 - (i & 3)) * 8)) & 255);
|
||||
}
|
||||
sha1_update(context, (uint8_t *) "\200", 1);
|
||||
while ((context->count[0] & 504) != 448)
|
||||
{
|
||||
sha1_update(context, (uint8_t *) "\0", 1);
|
||||
}
|
||||
sha1_update(context, finalcount, 8); /* Should cause SHA1_Transform */
|
||||
for (i = 0; i < SHA1_DIGEST_SIZE; i++)
|
||||
{
|
||||
digest[i] = (uint8_t)
|
||||
((context->h[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
|
||||
}
|
||||
|
||||
/* Wipe variables */
|
||||
i = 0;
|
||||
memset(context->buffer, 0, 64);
|
||||
/* fast-pbkdf2 needs access to the state*/
|
||||
/*memset(context->h, 0, 20);*/
|
||||
memset(context->count, 0, 8);
|
||||
memset(finalcount, 0, 8); /* SWR */
|
||||
}
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
/* public api for steve reid's public domain SHA-1 implementation */
|
||||
/* this file is in the public domain */
|
||||
|
||||
#ifndef SHA1_H_
|
||||
#define SHA1_H_ (1)
|
||||
|
||||
/** SHA-1 Context */
|
||||
typedef struct {
|
||||
uint32_t h[5];
|
||||
/**< Context state */
|
||||
uint32_t count[2];
|
||||
/**< Counter */
|
||||
uint8_t buffer[64]; /**< SHA-1 buffer */
|
||||
} sha1_ctx;
|
||||
|
||||
#define SHA1_BLOCK_SIZE 64
|
||||
/** SHA-1 Digest size in bytes */
|
||||
#define SHA1_DIGEST_SIZE 20
|
||||
|
||||
void sha1_init(sha1_ctx *context);
|
||||
|
||||
void sha1_update(sha1_ctx *context, const void *p, size_t len);
|
||||
|
||||
void sha1_final(sha1_ctx *context, uint8_t digest[SHA1_DIGEST_SIZE]);
|
||||
|
||||
void sha1_transform(sha1_ctx *context, const uint8_t buffer[64]);
|
||||
|
||||
#endif /* SHA1_H_ */
|
||||
Vendored
+962
@@ -0,0 +1,962 @@
|
||||
/*
|
||||
* FIPS 180-2 SHA-224/256/384/512 implementation
|
||||
* Last update: 02/02/2007
|
||||
* Issue date: 04/30/2005
|
||||
*
|
||||
* Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if 1
|
||||
#define UNROLL_LOOPS /* Enable loops unrolling */
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "sha2.h"
|
||||
|
||||
#define SHFR(x, n) (x >> n)
|
||||
#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
|
||||
#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
|
||||
#define CH(x, y, z) ((x & y) ^ (~x & z))
|
||||
#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
|
||||
|
||||
#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
|
||||
#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
|
||||
#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3))
|
||||
#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))
|
||||
|
||||
#define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39))
|
||||
#define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41))
|
||||
#define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7))
|
||||
#define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6))
|
||||
|
||||
#define UNPACK32(x, str) \
|
||||
{ \
|
||||
*((str) + 3) = (uint8) ((x) ); \
|
||||
*((str) + 2) = (uint8) ((x) >> 8); \
|
||||
*((str) + 1) = (uint8) ((x) >> 16); \
|
||||
*((str) + 0) = (uint8) ((x) >> 24); \
|
||||
}
|
||||
|
||||
#define PACK32(str, x) \
|
||||
{ \
|
||||
*(x) = ((uint32) *((str) + 3) ) \
|
||||
| ((uint32) *((str) + 2) << 8) \
|
||||
| ((uint32) *((str) + 1) << 16) \
|
||||
| ((uint32) *((str) + 0) << 24); \
|
||||
}
|
||||
|
||||
#define UNPACK64(x, str) \
|
||||
{ \
|
||||
*((str) + 7) = (uint8) ((x) ); \
|
||||
*((str) + 6) = (uint8) ((x) >> 8); \
|
||||
*((str) + 5) = (uint8) ((x) >> 16); \
|
||||
*((str) + 4) = (uint8) ((x) >> 24); \
|
||||
*((str) + 3) = (uint8) ((x) >> 32); \
|
||||
*((str) + 2) = (uint8) ((x) >> 40); \
|
||||
*((str) + 1) = (uint8) ((x) >> 48); \
|
||||
*((str) + 0) = (uint8) ((x) >> 56); \
|
||||
}
|
||||
|
||||
#define PACK64(str, x) \
|
||||
{ \
|
||||
*(x) = ((uint64) *((str) + 7) ) \
|
||||
| ((uint64) *((str) + 6) << 8) \
|
||||
| ((uint64) *((str) + 5) << 16) \
|
||||
| ((uint64) *((str) + 4) << 24) \
|
||||
| ((uint64) *((str) + 3) << 32) \
|
||||
| ((uint64) *((str) + 2) << 40) \
|
||||
| ((uint64) *((str) + 1) << 48) \
|
||||
| ((uint64) *((str) + 0) << 56); \
|
||||
}
|
||||
|
||||
/* Macros used for loops unrolling */
|
||||
|
||||
#define SHA256_SCR(i) \
|
||||
{ \
|
||||
w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \
|
||||
+ SHA256_F3(w[i - 15]) + w[i - 16]; \
|
||||
}
|
||||
|
||||
#define SHA512_SCR(i) \
|
||||
{ \
|
||||
w[i] = SHA512_F4(w[i - 2]) + w[i - 7] \
|
||||
+ SHA512_F3(w[i - 15]) + w[i - 16]; \
|
||||
}
|
||||
|
||||
#define SHA256_EXP(a, b, c, d, e, f, g, h, j) \
|
||||
{ \
|
||||
t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \
|
||||
+ sha256_k[j] + w[j]; \
|
||||
t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \
|
||||
wv[d] += t1; \
|
||||
wv[h] = t1 + t2; \
|
||||
}
|
||||
|
||||
#define SHA512_EXP(a, b, c, d, e, f, g ,h, j) \
|
||||
{ \
|
||||
t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \
|
||||
+ sha512_k[j] + w[j]; \
|
||||
t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \
|
||||
wv[d] += t1; \
|
||||
wv[h] = t1 + t2; \
|
||||
}
|
||||
|
||||
uint32 sha224_h0[8] =
|
||||
{0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
|
||||
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4};
|
||||
|
||||
uint32 sha256_h0[8] =
|
||||
{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
|
||||
|
||||
uint64 sha384_h0[8] =
|
||||
{li_64(cbbb9d5dc1059ed8), li_64(629a292a367cd507),
|
||||
li_64(9159015a3070dd17), li_64(152fecd8f70e5939),
|
||||
li_64(67332667ffc00b31), li_64(8eb44a8768581511),
|
||||
li_64(db0c2e0d64f98fa7), li_64(47b5481dbefa4fa4)};
|
||||
|
||||
uint64 sha512_h0[8] =
|
||||
{li_64(6a09e667f3bcc908), li_64(bb67ae8584caa73b),
|
||||
li_64(3c6ef372fe94f82b), li_64(a54ff53a5f1d36f1),
|
||||
li_64(510e527fade682d1), li_64(9b05688c2b3e6c1f),
|
||||
li_64(1f83d9abfb41bd6b), li_64(5be0cd19137e2179)};
|
||||
|
||||
uint32 sha256_k[64] =
|
||||
{0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
|
||||
|
||||
uint64 sha512_k[80] =
|
||||
{li_64(428a2f98d728ae22), li_64(7137449123ef65cd),
|
||||
li_64(b5c0fbcfec4d3b2f), li_64(e9b5dba58189dbbc),
|
||||
li_64(3956c25bf348b538), li_64(59f111f1b605d019),
|
||||
li_64(923f82a4af194f9b), li_64(ab1c5ed5da6d8118),
|
||||
li_64(d807aa98a3030242), li_64(12835b0145706fbe),
|
||||
li_64(243185be4ee4b28c), li_64(550c7dc3d5ffb4e2),
|
||||
li_64(72be5d74f27b896f), li_64(80deb1fe3b1696b1),
|
||||
li_64(9bdc06a725c71235), li_64(c19bf174cf692694),
|
||||
li_64(e49b69c19ef14ad2), li_64(efbe4786384f25e3),
|
||||
li_64(0fc19dc68b8cd5b5), li_64(240ca1cc77ac9c65),
|
||||
li_64(2de92c6f592b0275), li_64(4a7484aa6ea6e483),
|
||||
li_64(5cb0a9dcbd41fbd4), li_64(76f988da831153b5),
|
||||
li_64(983e5152ee66dfab), li_64(a831c66d2db43210),
|
||||
li_64(b00327c898fb213f), li_64(bf597fc7beef0ee4),
|
||||
li_64(c6e00bf33da88fc2), li_64(d5a79147930aa725),
|
||||
li_64(06ca6351e003826f), li_64(142929670a0e6e70),
|
||||
li_64(27b70a8546d22ffc), li_64(2e1b21385c26c926),
|
||||
li_64(4d2c6dfc5ac42aed), li_64(53380d139d95b3df),
|
||||
li_64(650a73548baf63de), li_64(766a0abb3c77b2a8),
|
||||
li_64(81c2c92e47edaee6), li_64(92722c851482353b),
|
||||
li_64(a2bfe8a14cf10364), li_64(a81a664bbc423001),
|
||||
li_64(c24b8b70d0f89791), li_64(c76c51a30654be30),
|
||||
li_64(d192e819d6ef5218), li_64(d69906245565a910),
|
||||
li_64(f40e35855771202a), li_64(106aa07032bbd1b8),
|
||||
li_64(19a4c116b8d2d0c8), li_64(1e376c085141ab53),
|
||||
li_64(2748774cdf8eeb99), li_64(34b0bcb5e19b48a8),
|
||||
li_64(391c0cb3c5c95a63), li_64(4ed8aa4ae3418acb),
|
||||
li_64(5b9cca4f7763e373), li_64(682e6ff3d6b2b8a3),
|
||||
li_64(748f82ee5defb2fc), li_64(78a5636f43172f60),
|
||||
li_64(84c87814a1f0ab72), li_64(8cc702081a6439ec),
|
||||
li_64(90befffa23631e28), li_64(a4506cebde82bde9),
|
||||
li_64(bef9a3f7b2c67915), li_64(c67178f2e372532b),
|
||||
li_64(ca273eceea26619c), li_64(d186b8c721c0c207),
|
||||
li_64(eada7dd6cde0eb1e), li_64(f57d4f7fee6ed178),
|
||||
li_64(06f067aa72176fba), li_64(0a637dc5a2c898a6),
|
||||
li_64(113f9804bef90dae), li_64(1b710b35131c471b),
|
||||
li_64(28db77f523047d84), li_64(32caab7b40c72493),
|
||||
li_64(3c9ebe0a15c9bebc), li_64(431d67c49c100d4c),
|
||||
li_64(4cc5d4becb3e42b6), li_64(597f299cfc657e2a),
|
||||
li_64(5fcb6fab3ad6faec), li_64(6c44198c4a475817)};
|
||||
|
||||
/* SHA-256 functions */
|
||||
|
||||
static
|
||||
void sha256_transf(sha256_ctx *ctx, const unsigned char *message,
|
||||
unsigned int block_nb)
|
||||
{
|
||||
uint32 w[64];
|
||||
uint32 wv[8];
|
||||
uint32 t1, t2;
|
||||
const unsigned char *sub_block;
|
||||
int i;
|
||||
|
||||
#ifndef UNROLL_LOOPS
|
||||
int j;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < (int) block_nb; i++) {
|
||||
sub_block = message + (i << 6);
|
||||
|
||||
#ifndef UNROLL_LOOPS
|
||||
for (j = 0; j < 16; j++) {
|
||||
PACK32(&sub_block[j << 2], &w[j]);
|
||||
}
|
||||
|
||||
for (j = 16; j < 64; j++) {
|
||||
SHA256_SCR(j);
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
wv[j] = ctx->h[j];
|
||||
}
|
||||
|
||||
for (j = 0; j < 64; j++) {
|
||||
t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6])
|
||||
+ sha256_k[j] + w[j];
|
||||
t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
|
||||
wv[7] = wv[6];
|
||||
wv[6] = wv[5];
|
||||
wv[5] = wv[4];
|
||||
wv[4] = wv[3] + t1;
|
||||
wv[3] = wv[2];
|
||||
wv[2] = wv[1];
|
||||
wv[1] = wv[0];
|
||||
wv[0] = t1 + t2;
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
ctx->h[j] += wv[j];
|
||||
}
|
||||
#else
|
||||
PACK32(&sub_block[ 0], &w[ 0]); PACK32(&sub_block[ 4], &w[ 1]);
|
||||
PACK32(&sub_block[ 8], &w[ 2]); PACK32(&sub_block[12], &w[ 3]);
|
||||
PACK32(&sub_block[16], &w[ 4]); PACK32(&sub_block[20], &w[ 5]);
|
||||
PACK32(&sub_block[24], &w[ 6]); PACK32(&sub_block[28], &w[ 7]);
|
||||
PACK32(&sub_block[32], &w[ 8]); PACK32(&sub_block[36], &w[ 9]);
|
||||
PACK32(&sub_block[40], &w[10]); PACK32(&sub_block[44], &w[11]);
|
||||
PACK32(&sub_block[48], &w[12]); PACK32(&sub_block[52], &w[13]);
|
||||
PACK32(&sub_block[56], &w[14]); PACK32(&sub_block[60], &w[15]);
|
||||
|
||||
SHA256_SCR(16); SHA256_SCR(17); SHA256_SCR(18); SHA256_SCR(19);
|
||||
SHA256_SCR(20); SHA256_SCR(21); SHA256_SCR(22); SHA256_SCR(23);
|
||||
SHA256_SCR(24); SHA256_SCR(25); SHA256_SCR(26); SHA256_SCR(27);
|
||||
SHA256_SCR(28); SHA256_SCR(29); SHA256_SCR(30); SHA256_SCR(31);
|
||||
SHA256_SCR(32); SHA256_SCR(33); SHA256_SCR(34); SHA256_SCR(35);
|
||||
SHA256_SCR(36); SHA256_SCR(37); SHA256_SCR(38); SHA256_SCR(39);
|
||||
SHA256_SCR(40); SHA256_SCR(41); SHA256_SCR(42); SHA256_SCR(43);
|
||||
SHA256_SCR(44); SHA256_SCR(45); SHA256_SCR(46); SHA256_SCR(47);
|
||||
SHA256_SCR(48); SHA256_SCR(49); SHA256_SCR(50); SHA256_SCR(51);
|
||||
SHA256_SCR(52); SHA256_SCR(53); SHA256_SCR(54); SHA256_SCR(55);
|
||||
SHA256_SCR(56); SHA256_SCR(57); SHA256_SCR(58); SHA256_SCR(59);
|
||||
SHA256_SCR(60); SHA256_SCR(61); SHA256_SCR(62); SHA256_SCR(63);
|
||||
|
||||
wv[0] = ctx->h[0]; wv[1] = ctx->h[1];
|
||||
wv[2] = ctx->h[2]; wv[3] = ctx->h[3];
|
||||
wv[4] = ctx->h[4]; wv[5] = ctx->h[5];
|
||||
wv[6] = ctx->h[6]; wv[7] = ctx->h[7];
|
||||
|
||||
SHA256_EXP(0,1,2,3,4,5,6,7, 0); SHA256_EXP(7,0,1,2,3,4,5,6, 1);
|
||||
SHA256_EXP(6,7,0,1,2,3,4,5, 2); SHA256_EXP(5,6,7,0,1,2,3,4, 3);
|
||||
SHA256_EXP(4,5,6,7,0,1,2,3, 4); SHA256_EXP(3,4,5,6,7,0,1,2, 5);
|
||||
SHA256_EXP(2,3,4,5,6,7,0,1, 6); SHA256_EXP(1,2,3,4,5,6,7,0, 7);
|
||||
SHA256_EXP(0,1,2,3,4,5,6,7, 8); SHA256_EXP(7,0,1,2,3,4,5,6, 9);
|
||||
SHA256_EXP(6,7,0,1,2,3,4,5,10); SHA256_EXP(5,6,7,0,1,2,3,4,11);
|
||||
SHA256_EXP(4,5,6,7,0,1,2,3,12); SHA256_EXP(3,4,5,6,7,0,1,2,13);
|
||||
SHA256_EXP(2,3,4,5,6,7,0,1,14); SHA256_EXP(1,2,3,4,5,6,7,0,15);
|
||||
SHA256_EXP(0,1,2,3,4,5,6,7,16); SHA256_EXP(7,0,1,2,3,4,5,6,17);
|
||||
SHA256_EXP(6,7,0,1,2,3,4,5,18); SHA256_EXP(5,6,7,0,1,2,3,4,19);
|
||||
SHA256_EXP(4,5,6,7,0,1,2,3,20); SHA256_EXP(3,4,5,6,7,0,1,2,21);
|
||||
SHA256_EXP(2,3,4,5,6,7,0,1,22); SHA256_EXP(1,2,3,4,5,6,7,0,23);
|
||||
SHA256_EXP(0,1,2,3,4,5,6,7,24); SHA256_EXP(7,0,1,2,3,4,5,6,25);
|
||||
SHA256_EXP(6,7,0,1,2,3,4,5,26); SHA256_EXP(5,6,7,0,1,2,3,4,27);
|
||||
SHA256_EXP(4,5,6,7,0,1,2,3,28); SHA256_EXP(3,4,5,6,7,0,1,2,29);
|
||||
SHA256_EXP(2,3,4,5,6,7,0,1,30); SHA256_EXP(1,2,3,4,5,6,7,0,31);
|
||||
SHA256_EXP(0,1,2,3,4,5,6,7,32); SHA256_EXP(7,0,1,2,3,4,5,6,33);
|
||||
SHA256_EXP(6,7,0,1,2,3,4,5,34); SHA256_EXP(5,6,7,0,1,2,3,4,35);
|
||||
SHA256_EXP(4,5,6,7,0,1,2,3,36); SHA256_EXP(3,4,5,6,7,0,1,2,37);
|
||||
SHA256_EXP(2,3,4,5,6,7,0,1,38); SHA256_EXP(1,2,3,4,5,6,7,0,39);
|
||||
SHA256_EXP(0,1,2,3,4,5,6,7,40); SHA256_EXP(7,0,1,2,3,4,5,6,41);
|
||||
SHA256_EXP(6,7,0,1,2,3,4,5,42); SHA256_EXP(5,6,7,0,1,2,3,4,43);
|
||||
SHA256_EXP(4,5,6,7,0,1,2,3,44); SHA256_EXP(3,4,5,6,7,0,1,2,45);
|
||||
SHA256_EXP(2,3,4,5,6,7,0,1,46); SHA256_EXP(1,2,3,4,5,6,7,0,47);
|
||||
SHA256_EXP(0,1,2,3,4,5,6,7,48); SHA256_EXP(7,0,1,2,3,4,5,6,49);
|
||||
SHA256_EXP(6,7,0,1,2,3,4,5,50); SHA256_EXP(5,6,7,0,1,2,3,4,51);
|
||||
SHA256_EXP(4,5,6,7,0,1,2,3,52); SHA256_EXP(3,4,5,6,7,0,1,2,53);
|
||||
SHA256_EXP(2,3,4,5,6,7,0,1,54); SHA256_EXP(1,2,3,4,5,6,7,0,55);
|
||||
SHA256_EXP(0,1,2,3,4,5,6,7,56); SHA256_EXP(7,0,1,2,3,4,5,6,57);
|
||||
SHA256_EXP(6,7,0,1,2,3,4,5,58); SHA256_EXP(5,6,7,0,1,2,3,4,59);
|
||||
SHA256_EXP(4,5,6,7,0,1,2,3,60); SHA256_EXP(3,4,5,6,7,0,1,2,61);
|
||||
SHA256_EXP(2,3,4,5,6,7,0,1,62); SHA256_EXP(1,2,3,4,5,6,7,0,63);
|
||||
|
||||
ctx->h[0] += wv[0]; ctx->h[1] += wv[1];
|
||||
ctx->h[2] += wv[2]; ctx->h[3] += wv[3];
|
||||
ctx->h[4] += wv[4]; ctx->h[5] += wv[5];
|
||||
ctx->h[6] += wv[6]; ctx->h[7] += wv[7];
|
||||
#endif /* !UNROLL_LOOPS */
|
||||
}
|
||||
}
|
||||
|
||||
void sha256_transform(sha256_ctx *ctx, const unsigned char *message)
|
||||
{
|
||||
sha256_transf(ctx, message, 1);
|
||||
}
|
||||
|
||||
void sha256(const unsigned char *message, unsigned int len, unsigned char *digest)
|
||||
{
|
||||
sha256_ctx ctx;
|
||||
|
||||
sha256_init(&ctx);
|
||||
sha256_update(&ctx, message, len);
|
||||
sha256_final(&ctx, digest);
|
||||
}
|
||||
|
||||
void sha256_init(sha256_ctx *ctx)
|
||||
{
|
||||
#ifndef UNROLL_LOOPS
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
ctx->h[i] = sha256_h0[i];
|
||||
}
|
||||
#else
|
||||
ctx->h[0] = sha256_h0[0]; ctx->h[1] = sha256_h0[1];
|
||||
ctx->h[2] = sha256_h0[2]; ctx->h[3] = sha256_h0[3];
|
||||
ctx->h[4] = sha256_h0[4]; ctx->h[5] = sha256_h0[5];
|
||||
ctx->h[6] = sha256_h0[6]; ctx->h[7] = sha256_h0[7];
|
||||
#endif /* !UNROLL_LOOPS */
|
||||
|
||||
ctx->len = 0;
|
||||
ctx->tot_len = 0;
|
||||
}
|
||||
|
||||
void sha256_update(sha256_ctx *ctx, const unsigned char *message,
|
||||
unsigned int len)
|
||||
{
|
||||
unsigned int block_nb;
|
||||
unsigned int new_len, rem_len, tmp_len;
|
||||
const unsigned char *shifted_message;
|
||||
|
||||
tmp_len = SHA256_BLOCK_SIZE - ctx->len;
|
||||
rem_len = len < tmp_len ? len : tmp_len;
|
||||
|
||||
memcpy(&ctx->block[ctx->len], message, rem_len);
|
||||
|
||||
if (ctx->len + len < SHA256_BLOCK_SIZE) {
|
||||
ctx->len += len;
|
||||
return;
|
||||
}
|
||||
|
||||
new_len = len - rem_len;
|
||||
block_nb = new_len / SHA256_BLOCK_SIZE;
|
||||
|
||||
shifted_message = message + rem_len;
|
||||
|
||||
sha256_transf(ctx, ctx->block, 1);
|
||||
sha256_transf(ctx, shifted_message, block_nb);
|
||||
|
||||
rem_len = new_len % SHA256_BLOCK_SIZE;
|
||||
|
||||
memcpy(ctx->block, &shifted_message[block_nb << 6],
|
||||
rem_len);
|
||||
|
||||
ctx->len = rem_len;
|
||||
ctx->tot_len += (block_nb + 1) << 6;
|
||||
}
|
||||
|
||||
void sha256_final(sha256_ctx *ctx, unsigned char *digest)
|
||||
{
|
||||
unsigned int block_nb;
|
||||
unsigned int pm_len;
|
||||
unsigned int len_b;
|
||||
|
||||
#ifndef UNROLL_LOOPS
|
||||
int i;
|
||||
#endif
|
||||
|
||||
block_nb = (1 + ((SHA256_BLOCK_SIZE - 9)
|
||||
< (ctx->len % SHA256_BLOCK_SIZE)));
|
||||
|
||||
len_b = (ctx->tot_len + ctx->len) << 3;
|
||||
pm_len = block_nb << 6;
|
||||
|
||||
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
|
||||
ctx->block[ctx->len] = 0x80;
|
||||
UNPACK32(len_b, ctx->block + pm_len - 4);
|
||||
|
||||
sha256_transf(ctx, ctx->block, block_nb);
|
||||
|
||||
#ifndef UNROLL_LOOPS
|
||||
for (i = 0 ; i < 8; i++) {
|
||||
UNPACK32(ctx->h[i], &digest[i << 2]);
|
||||
}
|
||||
#else
|
||||
UNPACK32(ctx->h[0], &digest[ 0]);
|
||||
UNPACK32(ctx->h[1], &digest[ 4]);
|
||||
UNPACK32(ctx->h[2], &digest[ 8]);
|
||||
UNPACK32(ctx->h[3], &digest[12]);
|
||||
UNPACK32(ctx->h[4], &digest[16]);
|
||||
UNPACK32(ctx->h[5], &digest[20]);
|
||||
UNPACK32(ctx->h[6], &digest[24]);
|
||||
UNPACK32(ctx->h[7], &digest[28]);
|
||||
#endif /* !UNROLL_LOOPS */
|
||||
}
|
||||
|
||||
/* SHA-512 functions */
|
||||
|
||||
static
|
||||
void sha512_transf(sha512_ctx *ctx, const unsigned char *message,
|
||||
unsigned int block_nb)
|
||||
{
|
||||
uint64 w[80];
|
||||
uint64 wv[8];
|
||||
uint64 t1, t2;
|
||||
const unsigned char *sub_block;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < (int) block_nb; i++) {
|
||||
sub_block = message + (i << 7);
|
||||
|
||||
#ifndef UNROLL_LOOPS
|
||||
for (j = 0; j < 16; j++) {
|
||||
PACK64(&sub_block[j << 3], &w[j]);
|
||||
}
|
||||
|
||||
for (j = 16; j < 80; j++) {
|
||||
SHA512_SCR(j);
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
wv[j] = ctx->h[j];
|
||||
}
|
||||
|
||||
for (j = 0; j < 80; j++) {
|
||||
t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6])
|
||||
+ sha512_k[j] + w[j];
|
||||
t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
|
||||
wv[7] = wv[6];
|
||||
wv[6] = wv[5];
|
||||
wv[5] = wv[4];
|
||||
wv[4] = wv[3] + t1;
|
||||
wv[3] = wv[2];
|
||||
wv[2] = wv[1];
|
||||
wv[1] = wv[0];
|
||||
wv[0] = t1 + t2;
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
ctx->h[j] += wv[j];
|
||||
}
|
||||
#else
|
||||
PACK64(&sub_block[ 0], &w[ 0]); PACK64(&sub_block[ 8], &w[ 1]);
|
||||
PACK64(&sub_block[ 16], &w[ 2]); PACK64(&sub_block[ 24], &w[ 3]);
|
||||
PACK64(&sub_block[ 32], &w[ 4]); PACK64(&sub_block[ 40], &w[ 5]);
|
||||
PACK64(&sub_block[ 48], &w[ 6]); PACK64(&sub_block[ 56], &w[ 7]);
|
||||
PACK64(&sub_block[ 64], &w[ 8]); PACK64(&sub_block[ 72], &w[ 9]);
|
||||
PACK64(&sub_block[ 80], &w[10]); PACK64(&sub_block[ 88], &w[11]);
|
||||
PACK64(&sub_block[ 96], &w[12]); PACK64(&sub_block[104], &w[13]);
|
||||
PACK64(&sub_block[112], &w[14]); PACK64(&sub_block[120], &w[15]);
|
||||
|
||||
SHA512_SCR(16); SHA512_SCR(17); SHA512_SCR(18); SHA512_SCR(19);
|
||||
SHA512_SCR(20); SHA512_SCR(21); SHA512_SCR(22); SHA512_SCR(23);
|
||||
SHA512_SCR(24); SHA512_SCR(25); SHA512_SCR(26); SHA512_SCR(27);
|
||||
SHA512_SCR(28); SHA512_SCR(29); SHA512_SCR(30); SHA512_SCR(31);
|
||||
SHA512_SCR(32); SHA512_SCR(33); SHA512_SCR(34); SHA512_SCR(35);
|
||||
SHA512_SCR(36); SHA512_SCR(37); SHA512_SCR(38); SHA512_SCR(39);
|
||||
SHA512_SCR(40); SHA512_SCR(41); SHA512_SCR(42); SHA512_SCR(43);
|
||||
SHA512_SCR(44); SHA512_SCR(45); SHA512_SCR(46); SHA512_SCR(47);
|
||||
SHA512_SCR(48); SHA512_SCR(49); SHA512_SCR(50); SHA512_SCR(51);
|
||||
SHA512_SCR(52); SHA512_SCR(53); SHA512_SCR(54); SHA512_SCR(55);
|
||||
SHA512_SCR(56); SHA512_SCR(57); SHA512_SCR(58); SHA512_SCR(59);
|
||||
SHA512_SCR(60); SHA512_SCR(61); SHA512_SCR(62); SHA512_SCR(63);
|
||||
SHA512_SCR(64); SHA512_SCR(65); SHA512_SCR(66); SHA512_SCR(67);
|
||||
SHA512_SCR(68); SHA512_SCR(69); SHA512_SCR(70); SHA512_SCR(71);
|
||||
SHA512_SCR(72); SHA512_SCR(73); SHA512_SCR(74); SHA512_SCR(75);
|
||||
SHA512_SCR(76); SHA512_SCR(77); SHA512_SCR(78); SHA512_SCR(79);
|
||||
|
||||
wv[0] = ctx->h[0]; wv[1] = ctx->h[1];
|
||||
wv[2] = ctx->h[2]; wv[3] = ctx->h[3];
|
||||
wv[4] = ctx->h[4]; wv[5] = ctx->h[5];
|
||||
wv[6] = ctx->h[6]; wv[7] = ctx->h[7];
|
||||
|
||||
j = 0;
|
||||
|
||||
do {
|
||||
SHA512_EXP(0,1,2,3,4,5,6,7,j); j++;
|
||||
SHA512_EXP(7,0,1,2,3,4,5,6,j); j++;
|
||||
SHA512_EXP(6,7,0,1,2,3,4,5,j); j++;
|
||||
SHA512_EXP(5,6,7,0,1,2,3,4,j); j++;
|
||||
SHA512_EXP(4,5,6,7,0,1,2,3,j); j++;
|
||||
SHA512_EXP(3,4,5,6,7,0,1,2,j); j++;
|
||||
SHA512_EXP(2,3,4,5,6,7,0,1,j); j++;
|
||||
SHA512_EXP(1,2,3,4,5,6,7,0,j); j++;
|
||||
} while (j < 80);
|
||||
|
||||
ctx->h[0] += wv[0]; ctx->h[1] += wv[1];
|
||||
ctx->h[2] += wv[2]; ctx->h[3] += wv[3];
|
||||
ctx->h[4] += wv[4]; ctx->h[5] += wv[5];
|
||||
ctx->h[6] += wv[6]; ctx->h[7] += wv[7];
|
||||
#endif /* !UNROLL_LOOPS */
|
||||
}
|
||||
}
|
||||
|
||||
void sha512_transform(sha512_ctx *ctx, const unsigned char *message)
|
||||
{
|
||||
sha512_transf(ctx, message, 1);
|
||||
}
|
||||
|
||||
void sha512(const unsigned char *message, unsigned int len,
|
||||
unsigned char *digest)
|
||||
{
|
||||
sha512_ctx ctx;
|
||||
|
||||
sha512_init(&ctx);
|
||||
sha512_update(&ctx, message, len);
|
||||
sha512_final(&ctx, digest);
|
||||
}
|
||||
|
||||
void sha512_init(sha512_ctx *ctx)
|
||||
{
|
||||
#ifndef UNROLL_LOOPS
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
ctx->h[i] = sha512_h0[i];
|
||||
}
|
||||
#else
|
||||
ctx->h[0] = sha512_h0[0]; ctx->h[1] = sha512_h0[1];
|
||||
ctx->h[2] = sha512_h0[2]; ctx->h[3] = sha512_h0[3];
|
||||
ctx->h[4] = sha512_h0[4]; ctx->h[5] = sha512_h0[5];
|
||||
ctx->h[6] = sha512_h0[6]; ctx->h[7] = sha512_h0[7];
|
||||
#endif /* !UNROLL_LOOPS */
|
||||
|
||||
ctx->len = 0;
|
||||
ctx->tot_len = 0;
|
||||
}
|
||||
|
||||
void sha512_update(sha512_ctx *ctx, const unsigned char *message,
|
||||
unsigned int len)
|
||||
{
|
||||
unsigned int block_nb;
|
||||
unsigned int new_len, rem_len, tmp_len;
|
||||
const unsigned char *shifted_message;
|
||||
|
||||
tmp_len = SHA512_BLOCK_SIZE - ctx->len;
|
||||
rem_len = len < tmp_len ? len : tmp_len;
|
||||
|
||||
memcpy(&ctx->block[ctx->len], message, rem_len);
|
||||
|
||||
if (ctx->len + len < SHA512_BLOCK_SIZE) {
|
||||
ctx->len += len;
|
||||
return;
|
||||
}
|
||||
|
||||
new_len = len - rem_len;
|
||||
block_nb = new_len / SHA512_BLOCK_SIZE;
|
||||
|
||||
shifted_message = message + rem_len;
|
||||
|
||||
sha512_transf(ctx, ctx->block, 1);
|
||||
sha512_transf(ctx, shifted_message, block_nb);
|
||||
|
||||
rem_len = new_len % SHA512_BLOCK_SIZE;
|
||||
|
||||
memcpy(ctx->block, &shifted_message[block_nb << 7],
|
||||
rem_len);
|
||||
|
||||
ctx->len = rem_len;
|
||||
ctx->tot_len += (block_nb + 1) << 7;
|
||||
}
|
||||
|
||||
void sha512_final(sha512_ctx *ctx, unsigned char *digest)
|
||||
{
|
||||
unsigned int block_nb;
|
||||
unsigned int pm_len;
|
||||
unsigned int len_b;
|
||||
|
||||
#ifndef UNROLL_LOOPS
|
||||
int i;
|
||||
#endif
|
||||
|
||||
block_nb = 1 + ((SHA512_BLOCK_SIZE - 17)
|
||||
< (ctx->len % SHA512_BLOCK_SIZE));
|
||||
|
||||
len_b = (ctx->tot_len + ctx->len) << 3;
|
||||
pm_len = block_nb << 7;
|
||||
|
||||
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
|
||||
ctx->block[ctx->len] = 0x80;
|
||||
UNPACK32(len_b, ctx->block + pm_len - 4);
|
||||
|
||||
sha512_transf(ctx, ctx->block, block_nb);
|
||||
|
||||
#ifndef UNROLL_LOOPS
|
||||
for (i = 0 ; i < 8; i++) {
|
||||
UNPACK64(ctx->h[i], &digest[i << 3]);
|
||||
}
|
||||
#else
|
||||
UNPACK64(ctx->h[0], &digest[ 0]);
|
||||
UNPACK64(ctx->h[1], &digest[ 8]);
|
||||
UNPACK64(ctx->h[2], &digest[16]);
|
||||
UNPACK64(ctx->h[3], &digest[24]);
|
||||
UNPACK64(ctx->h[4], &digest[32]);
|
||||
UNPACK64(ctx->h[5], &digest[40]);
|
||||
UNPACK64(ctx->h[6], &digest[48]);
|
||||
UNPACK64(ctx->h[7], &digest[56]);
|
||||
#endif /* !UNROLL_LOOPS */
|
||||
}
|
||||
|
||||
/* SHA-384 functions */
|
||||
|
||||
void sha384(const unsigned char *message, unsigned int len,
|
||||
unsigned char *digest)
|
||||
{
|
||||
sha384_ctx ctx;
|
||||
|
||||
sha384_init(&ctx);
|
||||
sha384_update(&ctx, message, len);
|
||||
sha384_final(&ctx, digest);
|
||||
}
|
||||
|
||||
void sha384_init(sha384_ctx *ctx)
|
||||
{
|
||||
#ifndef UNROLL_LOOPS
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
ctx->h[i] = sha384_h0[i];
|
||||
}
|
||||
#else
|
||||
ctx->h[0] = sha384_h0[0]; ctx->h[1] = sha384_h0[1];
|
||||
ctx->h[2] = sha384_h0[2]; ctx->h[3] = sha384_h0[3];
|
||||
ctx->h[4] = sha384_h0[4]; ctx->h[5] = sha384_h0[5];
|
||||
ctx->h[6] = sha384_h0[6]; ctx->h[7] = sha384_h0[7];
|
||||
#endif /* !UNROLL_LOOPS */
|
||||
|
||||
ctx->len = 0;
|
||||
ctx->tot_len = 0;
|
||||
}
|
||||
|
||||
void sha384_update(sha384_ctx *ctx, const unsigned char *message,
|
||||
unsigned int len)
|
||||
{
|
||||
unsigned int block_nb;
|
||||
unsigned int new_len, rem_len, tmp_len;
|
||||
const unsigned char *shifted_message;
|
||||
|
||||
tmp_len = SHA384_BLOCK_SIZE - ctx->len;
|
||||
rem_len = len < tmp_len ? len : tmp_len;
|
||||
|
||||
memcpy(&ctx->block[ctx->len], message, rem_len);
|
||||
|
||||
if (ctx->len + len < SHA384_BLOCK_SIZE) {
|
||||
ctx->len += len;
|
||||
return;
|
||||
}
|
||||
|
||||
new_len = len - rem_len;
|
||||
block_nb = new_len / SHA384_BLOCK_SIZE;
|
||||
|
||||
shifted_message = message + rem_len;
|
||||
|
||||
sha512_transf(ctx, ctx->block, 1);
|
||||
sha512_transf(ctx, shifted_message, block_nb);
|
||||
|
||||
rem_len = new_len % SHA384_BLOCK_SIZE;
|
||||
|
||||
memcpy(ctx->block, &shifted_message[block_nb << 7],
|
||||
rem_len);
|
||||
|
||||
ctx->len = rem_len;
|
||||
ctx->tot_len += (block_nb + 1) << 7;
|
||||
}
|
||||
|
||||
void sha384_final(sha384_ctx *ctx, unsigned char *digest)
|
||||
{
|
||||
unsigned int block_nb;
|
||||
unsigned int pm_len;
|
||||
unsigned int len_b;
|
||||
|
||||
#ifndef UNROLL_LOOPS
|
||||
int i;
|
||||
#endif
|
||||
|
||||
block_nb = (1 + ((SHA384_BLOCK_SIZE - 17)
|
||||
< (ctx->len % SHA384_BLOCK_SIZE)));
|
||||
|
||||
len_b = (ctx->tot_len + ctx->len) << 3;
|
||||
pm_len = block_nb << 7;
|
||||
|
||||
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
|
||||
ctx->block[ctx->len] = 0x80;
|
||||
UNPACK32(len_b, ctx->block + pm_len - 4);
|
||||
|
||||
sha512_transf(ctx, ctx->block, block_nb);
|
||||
|
||||
#ifndef UNROLL_LOOPS
|
||||
for (i = 0 ; i < 6; i++) {
|
||||
UNPACK64(ctx->h[i], &digest[i << 3]);
|
||||
}
|
||||
#else
|
||||
UNPACK64(ctx->h[0], &digest[ 0]);
|
||||
UNPACK64(ctx->h[1], &digest[ 8]);
|
||||
UNPACK64(ctx->h[2], &digest[16]);
|
||||
UNPACK64(ctx->h[3], &digest[24]);
|
||||
UNPACK64(ctx->h[4], &digest[32]);
|
||||
UNPACK64(ctx->h[5], &digest[40]);
|
||||
#endif /* !UNROLL_LOOPS */
|
||||
}
|
||||
|
||||
/* SHA-224 functions */
|
||||
|
||||
void sha224(const unsigned char *message, unsigned int len,
|
||||
unsigned char *digest)
|
||||
{
|
||||
sha224_ctx ctx;
|
||||
|
||||
sha224_init(&ctx);
|
||||
sha224_update(&ctx, message, len);
|
||||
sha224_final(&ctx, digest);
|
||||
}
|
||||
|
||||
void sha224_init(sha224_ctx *ctx)
|
||||
{
|
||||
#ifndef UNROLL_LOOPS
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
ctx->h[i] = sha224_h0[i];
|
||||
}
|
||||
#else
|
||||
ctx->h[0] = sha224_h0[0]; ctx->h[1] = sha224_h0[1];
|
||||
ctx->h[2] = sha224_h0[2]; ctx->h[3] = sha224_h0[3];
|
||||
ctx->h[4] = sha224_h0[4]; ctx->h[5] = sha224_h0[5];
|
||||
ctx->h[6] = sha224_h0[6]; ctx->h[7] = sha224_h0[7];
|
||||
#endif /* !UNROLL_LOOPS */
|
||||
|
||||
ctx->len = 0;
|
||||
ctx->tot_len = 0;
|
||||
}
|
||||
|
||||
void sha224_update(sha224_ctx *ctx, const unsigned char *message,
|
||||
unsigned int len)
|
||||
{
|
||||
unsigned int block_nb;
|
||||
unsigned int new_len, rem_len, tmp_len;
|
||||
const unsigned char *shifted_message;
|
||||
|
||||
tmp_len = SHA224_BLOCK_SIZE - ctx->len;
|
||||
rem_len = len < tmp_len ? len : tmp_len;
|
||||
|
||||
memcpy(&ctx->block[ctx->len], message, rem_len);
|
||||
|
||||
if (ctx->len + len < SHA224_BLOCK_SIZE) {
|
||||
ctx->len += len;
|
||||
return;
|
||||
}
|
||||
|
||||
new_len = len - rem_len;
|
||||
block_nb = new_len / SHA224_BLOCK_SIZE;
|
||||
|
||||
shifted_message = message + rem_len;
|
||||
|
||||
sha256_transf(ctx, ctx->block, 1);
|
||||
sha256_transf(ctx, shifted_message, block_nb);
|
||||
|
||||
rem_len = new_len % SHA224_BLOCK_SIZE;
|
||||
|
||||
memcpy(ctx->block, &shifted_message[block_nb << 6],
|
||||
rem_len);
|
||||
|
||||
ctx->len = rem_len;
|
||||
ctx->tot_len += (block_nb + 1) << 6;
|
||||
}
|
||||
|
||||
void sha224_final(sha224_ctx *ctx, unsigned char *digest)
|
||||
{
|
||||
unsigned int block_nb;
|
||||
unsigned int pm_len;
|
||||
unsigned int len_b;
|
||||
|
||||
#ifndef UNROLL_LOOPS
|
||||
int i;
|
||||
#endif
|
||||
|
||||
block_nb = (1 + ((SHA224_BLOCK_SIZE - 9)
|
||||
< (ctx->len % SHA224_BLOCK_SIZE)));
|
||||
|
||||
len_b = (ctx->tot_len + ctx->len) << 3;
|
||||
pm_len = block_nb << 6;
|
||||
|
||||
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
|
||||
ctx->block[ctx->len] = 0x80;
|
||||
UNPACK32(len_b, ctx->block + pm_len - 4);
|
||||
|
||||
sha256_transf(ctx, ctx->block, block_nb);
|
||||
|
||||
#ifndef UNROLL_LOOPS
|
||||
for (i = 0 ; i < 7; i++) {
|
||||
UNPACK32(ctx->h[i], &digest[i << 2]);
|
||||
}
|
||||
#else
|
||||
UNPACK32(ctx->h[0], &digest[ 0]);
|
||||
UNPACK32(ctx->h[1], &digest[ 4]);
|
||||
UNPACK32(ctx->h[2], &digest[ 8]);
|
||||
UNPACK32(ctx->h[3], &digest[12]);
|
||||
UNPACK32(ctx->h[4], &digest[16]);
|
||||
UNPACK32(ctx->h[5], &digest[20]);
|
||||
UNPACK32(ctx->h[6], &digest[24]);
|
||||
#endif /* !UNROLL_LOOPS */
|
||||
}
|
||||
|
||||
#ifdef TEST_VECTORS
|
||||
|
||||
/* FIPS 180-2 Validation tests */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void test(const unsigned char *vector, unsigned char *digest,
|
||||
unsigned int digest_size)
|
||||
{
|
||||
unsigned char output[2 * SHA512_DIGEST_SIZE + 1];
|
||||
int i;
|
||||
|
||||
output[2 * digest_size] = '\0';
|
||||
|
||||
for (i = 0; i < (int) digest_size ; i++) {
|
||||
sprintf((char *) output + 2 * i, "%02x", digest[i]);
|
||||
}
|
||||
|
||||
printf("H: %s\n", output);
|
||||
if (strcmp((char *) vector, (char *) output)) {
|
||||
fprintf(stderr, "Test failed.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
static const unsigned char *vectors[4][3] =
|
||||
{ /* SHA-224 */
|
||||
{
|
||||
"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7",
|
||||
"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525",
|
||||
"20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67",
|
||||
},
|
||||
/* SHA-256 */
|
||||
{
|
||||
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
|
||||
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1",
|
||||
"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0",
|
||||
},
|
||||
/* SHA-384 */
|
||||
{
|
||||
"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed"
|
||||
"8086072ba1e7cc2358baeca134c825a7",
|
||||
"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712"
|
||||
"fcc7c71a557e2db966c3e9fa91746039",
|
||||
"9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b"
|
||||
"07b8b3dc38ecc4ebae97ddd87f3d8985",
|
||||
},
|
||||
/* SHA-512 */
|
||||
{
|
||||
"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a"
|
||||
"2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
|
||||
"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018"
|
||||
"501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909",
|
||||
"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"
|
||||
"de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"
|
||||
}
|
||||
};
|
||||
|
||||
static const unsigned char message1[] = "abc";
|
||||
static const unsigned char message2a[] = "abcdbcdecdefdefgefghfghighijhi"
|
||||
"jkijkljklmklmnlmnomnopnopq";
|
||||
static const unsigned char message2b[] =
|
||||
"abcdefghbcdefghicdefghijdefghijkefghij"
|
||||
"klfghijklmghijklmnhijklmnoijklmnopjklm"
|
||||
"nopqklmnopqrlmnopqrsmnopqrstnopqrstu";
|
||||
unsigned char *message3;
|
||||
unsigned int message3_len = 1000000;
|
||||
unsigned char digest[SHA512_DIGEST_SIZE];
|
||||
|
||||
message3 = malloc(message3_len);
|
||||
if (message3 == NULL) {
|
||||
fprintf(stderr, "Can't allocate memory\n");
|
||||
return -1;
|
||||
}
|
||||
memset(message3, 'a', message3_len);
|
||||
|
||||
printf("SHA-2 FIPS 180-2 Validation tests\n\n");
|
||||
printf("SHA-224 Test vectors\n");
|
||||
|
||||
sha224(message1, strlen((char *) message1), digest);
|
||||
test(vectors[0][0], digest, SHA224_DIGEST_SIZE);
|
||||
sha224(message2a, strlen((char *) message2a), digest);
|
||||
test(vectors[0][1], digest, SHA224_DIGEST_SIZE);
|
||||
sha224(message3, message3_len, digest);
|
||||
test(vectors[0][2], digest, SHA224_DIGEST_SIZE);
|
||||
printf("\n");
|
||||
|
||||
printf("SHA-256 Test vectors\n");
|
||||
|
||||
sha256(message1, strlen((char *) message1), digest);
|
||||
test(vectors[1][0], digest, SHA256_DIGEST_SIZE);
|
||||
sha256(message2a, strlen((char *) message2a), digest);
|
||||
test(vectors[1][1], digest, SHA256_DIGEST_SIZE);
|
||||
sha256(message3, message3_len, digest);
|
||||
test(vectors[1][2], digest, SHA256_DIGEST_SIZE);
|
||||
printf("\n");
|
||||
|
||||
printf("SHA-384 Test vectors\n");
|
||||
|
||||
sha384(message1, strlen((char *) message1), digest);
|
||||
test(vectors[2][0], digest, SHA384_DIGEST_SIZE);
|
||||
sha384(message2b, strlen((char *) message2b), digest);
|
||||
test(vectors[2][1], digest, SHA384_DIGEST_SIZE);
|
||||
sha384(message3, message3_len, digest);
|
||||
test(vectors[2][2], digest, SHA384_DIGEST_SIZE);
|
||||
printf("\n");
|
||||
|
||||
printf("SHA-512 Test vectors\n");
|
||||
|
||||
sha512(message1, strlen((char *) message1), digest);
|
||||
test(vectors[3][0], digest, SHA512_DIGEST_SIZE);
|
||||
sha512(message2b, strlen((char *) message2b), digest);
|
||||
test(vectors[3][1], digest, SHA512_DIGEST_SIZE);
|
||||
sha512(message3, message3_len, digest);
|
||||
test(vectors[3][2], digest, SHA512_DIGEST_SIZE);
|
||||
printf("\n");
|
||||
|
||||
printf("All tests passed.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* TEST_VECTORS */
|
||||
|
||||
Vendored
+165
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* FIPS 180-2 SHA-224/256/384/512 implementation
|
||||
* Last update: 02/02/2007
|
||||
* Issue date: 04/30/2005
|
||||
*
|
||||
* Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SHA2_H
|
||||
#define SHA2_H
|
||||
|
||||
#define SHA224_DIGEST_SIZE ( 224 / 8)
|
||||
#define SHA256_DIGEST_SIZE ( 256 / 8)
|
||||
#define SHA384_DIGEST_SIZE ( 384 / 8)
|
||||
#define SHA512_DIGEST_SIZE ( 512 / 8)
|
||||
|
||||
#define SHA256_BLOCK_SIZE ( 512 / 8)
|
||||
#define SHA512_BLOCK_SIZE (1024 / 8)
|
||||
#define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE
|
||||
#define SHA224_BLOCK_SIZE SHA256_BLOCK_SIZE
|
||||
|
||||
#ifndef SHA2_TYPES
|
||||
#define SHA2_TYPES
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
typedef sqlite3_uint64 uint64;
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#define li_64(h) 0x##h##ui64
|
||||
#else
|
||||
#define li_64(h) 0x##h##ull
|
||||
#endif
|
||||
|
||||
#if 0 /* Start of original int64 defines */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if _MSC_VER >= 1310
|
||||
typedef unsigned long long uint64;
|
||||
#define li_64(h) 0x##h##ull
|
||||
#else
|
||||
typedef unsigned __int64 uint64;
|
||||
#define li_64(h) 0x##h##ui64
|
||||
#endif
|
||||
#elif defined(__BORLANDC__) && !defined(__MSDOS__)
|
||||
#define li_64(h) 0x##h##ull
|
||||
typedef __int64 uint64;
|
||||
#elif defined(__sun)
|
||||
#if defined(ULONG_MAX) && ULONG_MAX == 0xfffffffful
|
||||
#define li_64(h) 0x##h##ull
|
||||
typedef unsigned long long uint64;
|
||||
#elif defined(ULONG_LONG_MAX) && ULONG_LONG_MAX == 0xfffffffffffffffful
|
||||
#define li_64(h) 0x##h##ul
|
||||
typedef unsigned long uint64;
|
||||
#endif
|
||||
#elif defined(__MVS__)
|
||||
#define li_64(h) 0x##h##ull
|
||||
typedef unsigned int long long uint64;
|
||||
#elif defined(ULLONG_MAX) && ULLONG_MAX > 4294967295
|
||||
#if ULLONG_MAX == 18446744073709551615ull
|
||||
#define li_64(h) 0x##h##ull
|
||||
typedef unsigned long long uint64;
|
||||
#endif
|
||||
#elif defined(ULONG_LONG_MAX) && ULONG_LONG_MAX > 4294967295
|
||||
#if ULONG_LONG_MAX == 18446744073709551615
|
||||
#define li_64(h) 0x##h##ull
|
||||
typedef unsigned long long uint64;
|
||||
#endif
|
||||
#elif defined(ULONG_MAX) && ULONG_MAX > 4294967295
|
||||
#if ULONG_MAX == 18446744073709551615
|
||||
#define li_64(h) 0x##h##ul
|
||||
typedef unsigned long uint64;
|
||||
#endif
|
||||
#elif defined(UINT_MAX) && UINT_MAX > 4294967295
|
||||
#if UINT_MAX == 18446744073709551615
|
||||
#define li_64(h) 0x##h##u
|
||||
typedef unsigned int uint64;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* End of original int64 defines */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
unsigned int tot_len;
|
||||
unsigned int len;
|
||||
unsigned char block[2 * SHA256_BLOCK_SIZE];
|
||||
uint32 h[8];
|
||||
} sha256_ctx;
|
||||
|
||||
typedef struct {
|
||||
unsigned int tot_len;
|
||||
unsigned int len;
|
||||
unsigned char block[2 * SHA512_BLOCK_SIZE];
|
||||
uint64 h[8];
|
||||
} sha512_ctx;
|
||||
|
||||
typedef sha512_ctx sha384_ctx;
|
||||
typedef sha256_ctx sha224_ctx;
|
||||
|
||||
void sha224_init(sha224_ctx *ctx);
|
||||
void sha224_update(sha224_ctx *ctx, const unsigned char *message,
|
||||
unsigned int len);
|
||||
void sha224_final(sha224_ctx *ctx, unsigned char *digest);
|
||||
void sha224(const unsigned char *message, unsigned int len,
|
||||
unsigned char *digest);
|
||||
|
||||
void sha256_init(sha256_ctx * ctx);
|
||||
void sha256_update(sha256_ctx *ctx, const unsigned char *message,
|
||||
unsigned int len);
|
||||
void sha256_final(sha256_ctx *ctx, unsigned char *digest);
|
||||
void sha256_transform(sha256_ctx *ctx, const unsigned char *message);
|
||||
void sha256(const unsigned char *message, unsigned int len,
|
||||
unsigned char *digest);
|
||||
|
||||
void sha384_init(sha384_ctx *ctx);
|
||||
void sha384_update(sha384_ctx *ctx, const unsigned char *message,
|
||||
unsigned int len);
|
||||
void sha384_final(sha384_ctx *ctx, unsigned char *digest);
|
||||
void sha384(const unsigned char *message, unsigned int len,
|
||||
unsigned char *digest);
|
||||
|
||||
void sha512_init(sha512_ctx *ctx);
|
||||
void sha512_update(sha512_ctx *ctx, const unsigned char *message,
|
||||
unsigned int len);
|
||||
void sha512_final(sha512_ctx *ctx, unsigned char *digest);
|
||||
void sha512_transform(sha512_ctx *ctx, const unsigned char *message);
|
||||
void sha512(const unsigned char *message, unsigned int len,
|
||||
unsigned char *digest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !SHA2_H */
|
||||
|
||||
+716
@@ -0,0 +1,716 @@
|
||||
/*
|
||||
** 2017-03-08
|
||||
**
|
||||
** 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 SQLite extension implements functions that compute SHA3 hashes.
|
||||
** Two SQL functions are implemented:
|
||||
**
|
||||
** sha3(X,SIZE)
|
||||
** sha3_query(Y,SIZE)
|
||||
**
|
||||
** The sha3(X) function computes the SHA3 hash of the input X, or NULL if
|
||||
** X is NULL.
|
||||
**
|
||||
** The sha3_query(Y) function evalutes all queries in the SQL statements of Y
|
||||
** and returns a hash of their results.
|
||||
**
|
||||
** The SIZE argument is optional. If omitted, the SHA3-256 hash algorithm
|
||||
** is used. If SIZE is included it must be one of the integers 224, 256,
|
||||
** 384, or 512, to determine SHA3 hash variant that is computed.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#if 0
|
||||
typedef sqlite3_uint64 u64;
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
** The Hash Engine
|
||||
*/
|
||||
/*
|
||||
** Macros to determine whether the machine is big or little endian,
|
||||
** and whether or not that determination is run-time or compile-time.
|
||||
**
|
||||
** For best performance, an attempt is made to guess at the byte-order
|
||||
** using C-preprocessor macros. If that is unsuccessful, or if
|
||||
** -DSHA3_BYTEORDER=0 is set, then byte-order is determined
|
||||
** at run-time.
|
||||
*/
|
||||
#ifndef SHA3_BYTEORDER
|
||||
# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
|
||||
defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
|
||||
defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
|
||||
defined(__arm__)
|
||||
# define SHA3_BYTEORDER 1234
|
||||
# elif defined(sparc) || defined(__ppc__)
|
||||
# define SHA3_BYTEORDER 4321
|
||||
# else
|
||||
# define SHA3_BYTEORDER 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** State structure for a SHA3 hash in progress
|
||||
*/
|
||||
typedef struct SHA3Context SHA3Context;
|
||||
struct SHA3Context {
|
||||
union {
|
||||
u64 s[25]; /* Keccak state. 5x5 lines of 64 bits each */
|
||||
unsigned char x[1600]; /* ... or 1600 bytes */
|
||||
} u;
|
||||
unsigned nRate; /* Bytes of input accepted per Keccak iteration */
|
||||
unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */
|
||||
unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */
|
||||
};
|
||||
|
||||
/*
|
||||
** A single step of the Keccak mixing function for a 1600-bit state
|
||||
*/
|
||||
static void KeccakF1600Step(SHA3Context *p){
|
||||
int i;
|
||||
u64 b0, b1, b2, b3, b4;
|
||||
u64 c0, c1, c2, c3, c4;
|
||||
u64 d0, d1, d2, d3, d4;
|
||||
static const u64 RC[] = {
|
||||
0x0000000000000001ULL, 0x0000000000008082ULL,
|
||||
0x800000000000808aULL, 0x8000000080008000ULL,
|
||||
0x000000000000808bULL, 0x0000000080000001ULL,
|
||||
0x8000000080008081ULL, 0x8000000000008009ULL,
|
||||
0x000000000000008aULL, 0x0000000000000088ULL,
|
||||
0x0000000080008009ULL, 0x000000008000000aULL,
|
||||
0x000000008000808bULL, 0x800000000000008bULL,
|
||||
0x8000000000008089ULL, 0x8000000000008003ULL,
|
||||
0x8000000000008002ULL, 0x8000000000000080ULL,
|
||||
0x000000000000800aULL, 0x800000008000000aULL,
|
||||
0x8000000080008081ULL, 0x8000000000008080ULL,
|
||||
0x0000000080000001ULL, 0x8000000080008008ULL
|
||||
};
|
||||
# define a00 (p->u.s[0])
|
||||
# define a01 (p->u.s[1])
|
||||
# define a02 (p->u.s[2])
|
||||
# define a03 (p->u.s[3])
|
||||
# define a04 (p->u.s[4])
|
||||
# define a10 (p->u.s[5])
|
||||
# define a11 (p->u.s[6])
|
||||
# define a12 (p->u.s[7])
|
||||
# define a13 (p->u.s[8])
|
||||
# define a14 (p->u.s[9])
|
||||
# define a20 (p->u.s[10])
|
||||
# define a21 (p->u.s[11])
|
||||
# define a22 (p->u.s[12])
|
||||
# define a23 (p->u.s[13])
|
||||
# define a24 (p->u.s[14])
|
||||
# define a30 (p->u.s[15])
|
||||
# define a31 (p->u.s[16])
|
||||
# define a32 (p->u.s[17])
|
||||
# define a33 (p->u.s[18])
|
||||
# define a34 (p->u.s[19])
|
||||
# define a40 (p->u.s[20])
|
||||
# define a41 (p->u.s[21])
|
||||
# define a42 (p->u.s[22])
|
||||
# define a43 (p->u.s[23])
|
||||
# define a44 (p->u.s[24])
|
||||
# define ROL64(a,x) ((a<<x)|(a>>(64-x)))
|
||||
|
||||
for(i=0; i<24; i+=4){
|
||||
c0 = a00^a10^a20^a30^a40;
|
||||
c1 = a01^a11^a21^a31^a41;
|
||||
c2 = a02^a12^a22^a32^a42;
|
||||
c3 = a03^a13^a23^a33^a43;
|
||||
c4 = a04^a14^a24^a34^a44;
|
||||
d0 = c4^ROL64(c1, 1);
|
||||
d1 = c0^ROL64(c2, 1);
|
||||
d2 = c1^ROL64(c3, 1);
|
||||
d3 = c2^ROL64(c4, 1);
|
||||
d4 = c3^ROL64(c0, 1);
|
||||
|
||||
b0 = (a00^d0);
|
||||
b1 = ROL64((a11^d1), 44);
|
||||
b2 = ROL64((a22^d2), 43);
|
||||
b3 = ROL64((a33^d3), 21);
|
||||
b4 = ROL64((a44^d4), 14);
|
||||
a00 = b0 ^((~b1)& b2 );
|
||||
a00 ^= RC[i];
|
||||
a11 = b1 ^((~b2)& b3 );
|
||||
a22 = b2 ^((~b3)& b4 );
|
||||
a33 = b3 ^((~b4)& b0 );
|
||||
a44 = b4 ^((~b0)& b1 );
|
||||
|
||||
b2 = ROL64((a20^d0), 3);
|
||||
b3 = ROL64((a31^d1), 45);
|
||||
b4 = ROL64((a42^d2), 61);
|
||||
b0 = ROL64((a03^d3), 28);
|
||||
b1 = ROL64((a14^d4), 20);
|
||||
a20 = b0 ^((~b1)& b2 );
|
||||
a31 = b1 ^((~b2)& b3 );
|
||||
a42 = b2 ^((~b3)& b4 );
|
||||
a03 = b3 ^((~b4)& b0 );
|
||||
a14 = b4 ^((~b0)& b1 );
|
||||
|
||||
b4 = ROL64((a40^d0), 18);
|
||||
b0 = ROL64((a01^d1), 1);
|
||||
b1 = ROL64((a12^d2), 6);
|
||||
b2 = ROL64((a23^d3), 25);
|
||||
b3 = ROL64((a34^d4), 8);
|
||||
a40 = b0 ^((~b1)& b2 );
|
||||
a01 = b1 ^((~b2)& b3 );
|
||||
a12 = b2 ^((~b3)& b4 );
|
||||
a23 = b3 ^((~b4)& b0 );
|
||||
a34 = b4 ^((~b0)& b1 );
|
||||
|
||||
b1 = ROL64((a10^d0), 36);
|
||||
b2 = ROL64((a21^d1), 10);
|
||||
b3 = ROL64((a32^d2), 15);
|
||||
b4 = ROL64((a43^d3), 56);
|
||||
b0 = ROL64((a04^d4), 27);
|
||||
a10 = b0 ^((~b1)& b2 );
|
||||
a21 = b1 ^((~b2)& b3 );
|
||||
a32 = b2 ^((~b3)& b4 );
|
||||
a43 = b3 ^((~b4)& b0 );
|
||||
a04 = b4 ^((~b0)& b1 );
|
||||
|
||||
b3 = ROL64((a30^d0), 41);
|
||||
b4 = ROL64((a41^d1), 2);
|
||||
b0 = ROL64((a02^d2), 62);
|
||||
b1 = ROL64((a13^d3), 55);
|
||||
b2 = ROL64((a24^d4), 39);
|
||||
a30 = b0 ^((~b1)& b2 );
|
||||
a41 = b1 ^((~b2)& b3 );
|
||||
a02 = b2 ^((~b3)& b4 );
|
||||
a13 = b3 ^((~b4)& b0 );
|
||||
a24 = b4 ^((~b0)& b1 );
|
||||
|
||||
c0 = a00^a20^a40^a10^a30;
|
||||
c1 = a11^a31^a01^a21^a41;
|
||||
c2 = a22^a42^a12^a32^a02;
|
||||
c3 = a33^a03^a23^a43^a13;
|
||||
c4 = a44^a14^a34^a04^a24;
|
||||
d0 = c4^ROL64(c1, 1);
|
||||
d1 = c0^ROL64(c2, 1);
|
||||
d2 = c1^ROL64(c3, 1);
|
||||
d3 = c2^ROL64(c4, 1);
|
||||
d4 = c3^ROL64(c0, 1);
|
||||
|
||||
b0 = (a00^d0);
|
||||
b1 = ROL64((a31^d1), 44);
|
||||
b2 = ROL64((a12^d2), 43);
|
||||
b3 = ROL64((a43^d3), 21);
|
||||
b4 = ROL64((a24^d4), 14);
|
||||
a00 = b0 ^((~b1)& b2 );
|
||||
a00 ^= RC[i+1];
|
||||
a31 = b1 ^((~b2)& b3 );
|
||||
a12 = b2 ^((~b3)& b4 );
|
||||
a43 = b3 ^((~b4)& b0 );
|
||||
a24 = b4 ^((~b0)& b1 );
|
||||
|
||||
b2 = ROL64((a40^d0), 3);
|
||||
b3 = ROL64((a21^d1), 45);
|
||||
b4 = ROL64((a02^d2), 61);
|
||||
b0 = ROL64((a33^d3), 28);
|
||||
b1 = ROL64((a14^d4), 20);
|
||||
a40 = b0 ^((~b1)& b2 );
|
||||
a21 = b1 ^((~b2)& b3 );
|
||||
a02 = b2 ^((~b3)& b4 );
|
||||
a33 = b3 ^((~b4)& b0 );
|
||||
a14 = b4 ^((~b0)& b1 );
|
||||
|
||||
b4 = ROL64((a30^d0), 18);
|
||||
b0 = ROL64((a11^d1), 1);
|
||||
b1 = ROL64((a42^d2), 6);
|
||||
b2 = ROL64((a23^d3), 25);
|
||||
b3 = ROL64((a04^d4), 8);
|
||||
a30 = b0 ^((~b1)& b2 );
|
||||
a11 = b1 ^((~b2)& b3 );
|
||||
a42 = b2 ^((~b3)& b4 );
|
||||
a23 = b3 ^((~b4)& b0 );
|
||||
a04 = b4 ^((~b0)& b1 );
|
||||
|
||||
b1 = ROL64((a20^d0), 36);
|
||||
b2 = ROL64((a01^d1), 10);
|
||||
b3 = ROL64((a32^d2), 15);
|
||||
b4 = ROL64((a13^d3), 56);
|
||||
b0 = ROL64((a44^d4), 27);
|
||||
a20 = b0 ^((~b1)& b2 );
|
||||
a01 = b1 ^((~b2)& b3 );
|
||||
a32 = b2 ^((~b3)& b4 );
|
||||
a13 = b3 ^((~b4)& b0 );
|
||||
a44 = b4 ^((~b0)& b1 );
|
||||
|
||||
b3 = ROL64((a10^d0), 41);
|
||||
b4 = ROL64((a41^d1), 2);
|
||||
b0 = ROL64((a22^d2), 62);
|
||||
b1 = ROL64((a03^d3), 55);
|
||||
b2 = ROL64((a34^d4), 39);
|
||||
a10 = b0 ^((~b1)& b2 );
|
||||
a41 = b1 ^((~b2)& b3 );
|
||||
a22 = b2 ^((~b3)& b4 );
|
||||
a03 = b3 ^((~b4)& b0 );
|
||||
a34 = b4 ^((~b0)& b1 );
|
||||
|
||||
c0 = a00^a40^a30^a20^a10;
|
||||
c1 = a31^a21^a11^a01^a41;
|
||||
c2 = a12^a02^a42^a32^a22;
|
||||
c3 = a43^a33^a23^a13^a03;
|
||||
c4 = a24^a14^a04^a44^a34;
|
||||
d0 = c4^ROL64(c1, 1);
|
||||
d1 = c0^ROL64(c2, 1);
|
||||
d2 = c1^ROL64(c3, 1);
|
||||
d3 = c2^ROL64(c4, 1);
|
||||
d4 = c3^ROL64(c0, 1);
|
||||
|
||||
b0 = (a00^d0);
|
||||
b1 = ROL64((a21^d1), 44);
|
||||
b2 = ROL64((a42^d2), 43);
|
||||
b3 = ROL64((a13^d3), 21);
|
||||
b4 = ROL64((a34^d4), 14);
|
||||
a00 = b0 ^((~b1)& b2 );
|
||||
a00 ^= RC[i+2];
|
||||
a21 = b1 ^((~b2)& b3 );
|
||||
a42 = b2 ^((~b3)& b4 );
|
||||
a13 = b3 ^((~b4)& b0 );
|
||||
a34 = b4 ^((~b0)& b1 );
|
||||
|
||||
b2 = ROL64((a30^d0), 3);
|
||||
b3 = ROL64((a01^d1), 45);
|
||||
b4 = ROL64((a22^d2), 61);
|
||||
b0 = ROL64((a43^d3), 28);
|
||||
b1 = ROL64((a14^d4), 20);
|
||||
a30 = b0 ^((~b1)& b2 );
|
||||
a01 = b1 ^((~b2)& b3 );
|
||||
a22 = b2 ^((~b3)& b4 );
|
||||
a43 = b3 ^((~b4)& b0 );
|
||||
a14 = b4 ^((~b0)& b1 );
|
||||
|
||||
b4 = ROL64((a10^d0), 18);
|
||||
b0 = ROL64((a31^d1), 1);
|
||||
b1 = ROL64((a02^d2), 6);
|
||||
b2 = ROL64((a23^d3), 25);
|
||||
b3 = ROL64((a44^d4), 8);
|
||||
a10 = b0 ^((~b1)& b2 );
|
||||
a31 = b1 ^((~b2)& b3 );
|
||||
a02 = b2 ^((~b3)& b4 );
|
||||
a23 = b3 ^((~b4)& b0 );
|
||||
a44 = b4 ^((~b0)& b1 );
|
||||
|
||||
b1 = ROL64((a40^d0), 36);
|
||||
b2 = ROL64((a11^d1), 10);
|
||||
b3 = ROL64((a32^d2), 15);
|
||||
b4 = ROL64((a03^d3), 56);
|
||||
b0 = ROL64((a24^d4), 27);
|
||||
a40 = b0 ^((~b1)& b2 );
|
||||
a11 = b1 ^((~b2)& b3 );
|
||||
a32 = b2 ^((~b3)& b4 );
|
||||
a03 = b3 ^((~b4)& b0 );
|
||||
a24 = b4 ^((~b0)& b1 );
|
||||
|
||||
b3 = ROL64((a20^d0), 41);
|
||||
b4 = ROL64((a41^d1), 2);
|
||||
b0 = ROL64((a12^d2), 62);
|
||||
b1 = ROL64((a33^d3), 55);
|
||||
b2 = ROL64((a04^d4), 39);
|
||||
a20 = b0 ^((~b1)& b2 );
|
||||
a41 = b1 ^((~b2)& b3 );
|
||||
a12 = b2 ^((~b3)& b4 );
|
||||
a33 = b3 ^((~b4)& b0 );
|
||||
a04 = b4 ^((~b0)& b1 );
|
||||
|
||||
c0 = a00^a30^a10^a40^a20;
|
||||
c1 = a21^a01^a31^a11^a41;
|
||||
c2 = a42^a22^a02^a32^a12;
|
||||
c3 = a13^a43^a23^a03^a33;
|
||||
c4 = a34^a14^a44^a24^a04;
|
||||
d0 = c4^ROL64(c1, 1);
|
||||
d1 = c0^ROL64(c2, 1);
|
||||
d2 = c1^ROL64(c3, 1);
|
||||
d3 = c2^ROL64(c4, 1);
|
||||
d4 = c3^ROL64(c0, 1);
|
||||
|
||||
b0 = (a00^d0);
|
||||
b1 = ROL64((a01^d1), 44);
|
||||
b2 = ROL64((a02^d2), 43);
|
||||
b3 = ROL64((a03^d3), 21);
|
||||
b4 = ROL64((a04^d4), 14);
|
||||
a00 = b0 ^((~b1)& b2 );
|
||||
a00 ^= RC[i+3];
|
||||
a01 = b1 ^((~b2)& b3 );
|
||||
a02 = b2 ^((~b3)& b4 );
|
||||
a03 = b3 ^((~b4)& b0 );
|
||||
a04 = b4 ^((~b0)& b1 );
|
||||
|
||||
b2 = ROL64((a10^d0), 3);
|
||||
b3 = ROL64((a11^d1), 45);
|
||||
b4 = ROL64((a12^d2), 61);
|
||||
b0 = ROL64((a13^d3), 28);
|
||||
b1 = ROL64((a14^d4), 20);
|
||||
a10 = b0 ^((~b1)& b2 );
|
||||
a11 = b1 ^((~b2)& b3 );
|
||||
a12 = b2 ^((~b3)& b4 );
|
||||
a13 = b3 ^((~b4)& b0 );
|
||||
a14 = b4 ^((~b0)& b1 );
|
||||
|
||||
b4 = ROL64((a20^d0), 18);
|
||||
b0 = ROL64((a21^d1), 1);
|
||||
b1 = ROL64((a22^d2), 6);
|
||||
b2 = ROL64((a23^d3), 25);
|
||||
b3 = ROL64((a24^d4), 8);
|
||||
a20 = b0 ^((~b1)& b2 );
|
||||
a21 = b1 ^((~b2)& b3 );
|
||||
a22 = b2 ^((~b3)& b4 );
|
||||
a23 = b3 ^((~b4)& b0 );
|
||||
a24 = b4 ^((~b0)& b1 );
|
||||
|
||||
b1 = ROL64((a30^d0), 36);
|
||||
b2 = ROL64((a31^d1), 10);
|
||||
b3 = ROL64((a32^d2), 15);
|
||||
b4 = ROL64((a33^d3), 56);
|
||||
b0 = ROL64((a34^d4), 27);
|
||||
a30 = b0 ^((~b1)& b2 );
|
||||
a31 = b1 ^((~b2)& b3 );
|
||||
a32 = b2 ^((~b3)& b4 );
|
||||
a33 = b3 ^((~b4)& b0 );
|
||||
a34 = b4 ^((~b0)& b1 );
|
||||
|
||||
b3 = ROL64((a40^d0), 41);
|
||||
b4 = ROL64((a41^d1), 2);
|
||||
b0 = ROL64((a42^d2), 62);
|
||||
b1 = ROL64((a43^d3), 55);
|
||||
b2 = ROL64((a44^d4), 39);
|
||||
a40 = b0 ^((~b1)& b2 );
|
||||
a41 = b1 ^((~b2)& b3 );
|
||||
a42 = b2 ^((~b3)& b4 );
|
||||
a43 = b3 ^((~b4)& b0 );
|
||||
a44 = b4 ^((~b0)& b1 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize a new hash. iSize determines the size of the hash
|
||||
** in bits and should be one of 224, 256, 384, or 512. Or iSize
|
||||
** can be zero to use the default hash size of 256 bits.
|
||||
*/
|
||||
static void SHA3Init(SHA3Context *p, int iSize){
|
||||
memset(p, 0, sizeof(*p));
|
||||
if( iSize>=128 && iSize<=512 ){
|
||||
p->nRate = (1600 - ((iSize + 31)&~31)*2)/8;
|
||||
}else{
|
||||
p->nRate = (1600 - 2*256)/8;
|
||||
}
|
||||
#if SHA3_BYTEORDER==1234
|
||||
/* Known to be little-endian at compile-time. No-op */
|
||||
#elif SHA3_BYTEORDER==4321
|
||||
p->ixMask = 7; /* Big-endian */
|
||||
#else
|
||||
{
|
||||
static unsigned int one = 1;
|
||||
if( 1==*(unsigned char*)&one ){
|
||||
/* Little endian. No byte swapping. */
|
||||
p->ixMask = 0;
|
||||
}else{
|
||||
/* Big endian. Byte swap. */
|
||||
p->ixMask = 7;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Make consecutive calls to the SHA3Update function to add new content
|
||||
** to the hash
|
||||
*/
|
||||
static void SHA3Update(
|
||||
SHA3Context *p,
|
||||
const unsigned char *aData,
|
||||
unsigned int nData
|
||||
){
|
||||
unsigned int i = 0;
|
||||
#if SHA3_BYTEORDER==1234
|
||||
if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){
|
||||
for(; i+7<nData; i+=8){
|
||||
p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i];
|
||||
p->nLoaded += 8;
|
||||
if( p->nLoaded>=p->nRate ){
|
||||
KeccakF1600Step(p);
|
||||
p->nLoaded = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for(; i<nData; i++){
|
||||
#if SHA3_BYTEORDER==1234
|
||||
p->u.x[p->nLoaded] ^= aData[i];
|
||||
#elif SHA3_BYTEORDER==4321
|
||||
p->u.x[p->nLoaded^0x07] ^= aData[i];
|
||||
#else
|
||||
p->u.x[p->nLoaded^p->ixMask] ^= aData[i];
|
||||
#endif
|
||||
p->nLoaded++;
|
||||
if( p->nLoaded==p->nRate ){
|
||||
KeccakF1600Step(p);
|
||||
p->nLoaded = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** After all content has been added, invoke SHA3Final() to compute
|
||||
** the final hash. The function returns a pointer to the binary
|
||||
** hash value.
|
||||
*/
|
||||
static unsigned char *SHA3Final(SHA3Context *p){
|
||||
unsigned int i;
|
||||
if( p->nLoaded==p->nRate-1 ){
|
||||
const unsigned char c1 = 0x86;
|
||||
SHA3Update(p, &c1, 1);
|
||||
}else{
|
||||
const unsigned char c2 = 0x06;
|
||||
const unsigned char c3 = 0x80;
|
||||
SHA3Update(p, &c2, 1);
|
||||
p->nLoaded = p->nRate - 1;
|
||||
SHA3Update(p, &c3, 1);
|
||||
}
|
||||
for(i=0; i<p->nRate; i++){
|
||||
p->u.x[i+p->nRate] = p->u.x[i^p->ixMask];
|
||||
}
|
||||
return &p->u.x[p->nRate];
|
||||
}
|
||||
/* End of the hashing logic
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
** Implementation of the sha3(X,SIZE) function.
|
||||
**
|
||||
** Return a BLOB which is the SIZE-bit SHA3 hash of X. The default
|
||||
** size is 256. If X is a BLOB, it is hashed as is.
|
||||
** For all other non-NULL types of input, X is converted into a UTF-8 string
|
||||
** and the string is hashed without the trailing 0x00 terminator. The hash
|
||||
** of a NULL value is NULL.
|
||||
*/
|
||||
static void sha3Func(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
SHA3Context cx;
|
||||
int eType = sqlite3_value_type(argv[0]);
|
||||
int nByte = sqlite3_value_bytes(argv[0]);
|
||||
int iSize;
|
||||
if( argc==1 ){
|
||||
iSize = 256;
|
||||
}else{
|
||||
iSize = sqlite3_value_int(argv[1]);
|
||||
if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
|
||||
sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
|
||||
"384 512", -1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( eType==SQLITE_NULL ) return;
|
||||
SHA3Init(&cx, iSize);
|
||||
if( eType==SQLITE_BLOB ){
|
||||
SHA3Update(&cx, sqlite3_value_blob(argv[0]), nByte);
|
||||
}else{
|
||||
SHA3Update(&cx, sqlite3_value_text(argv[0]), nByte);
|
||||
}
|
||||
sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/* Compute a string using sqlite3_vsnprintf() with a maximum length
|
||||
** of 50 bytes and add it to the hash.
|
||||
*/
|
||||
static void hash_step_vformat(
|
||||
SHA3Context *p, /* Add content to this context */
|
||||
const char *zFormat,
|
||||
...
|
||||
){
|
||||
va_list ap;
|
||||
int n;
|
||||
char zBuf[50];
|
||||
va_start(ap, zFormat);
|
||||
sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
|
||||
va_end(ap);
|
||||
n = (int)strlen(zBuf);
|
||||
SHA3Update(p, (unsigned char*)zBuf, n);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sha3_query(SQL,SIZE) function.
|
||||
**
|
||||
** This function compiles and runs the SQL statement(s) given in the
|
||||
** argument. The results are hashed using a SIZE-bit SHA3. The default
|
||||
** size is 256.
|
||||
**
|
||||
** The format of the byte stream that is hashed is summarized as follows:
|
||||
**
|
||||
** S<n>:<sql>
|
||||
** R
|
||||
** N
|
||||
** I<int>
|
||||
** F<ieee-float>
|
||||
** B<size>:<bytes>
|
||||
** T<size>:<text>
|
||||
**
|
||||
** <sql> is the original SQL text for each statement run and <n> is
|
||||
** the size of that text. The SQL text is UTF-8. A single R character
|
||||
** occurs before the start of each row. N means a NULL value.
|
||||
** I mean an 8-byte little-endian integer <int>. F is a floating point
|
||||
** number with an 8-byte little-endian IEEE floating point value <ieee-float>.
|
||||
** B means blobs of <size> bytes. T means text rendered as <size>
|
||||
** bytes of UTF-8. The <n> and <size> values are expressed as an ASCII
|
||||
** text integers.
|
||||
**
|
||||
** For each SQL statement in the X input, there is one S segment. Each
|
||||
** S segment is followed by zero or more R segments, one for each row in the
|
||||
** result set. After each R, there are one or more N, I, F, B, or T segments,
|
||||
** one for each column in the result set. Segments are concatentated directly
|
||||
** with no delimiters of any kind.
|
||||
*/
|
||||
static void sha3QueryFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zSql = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int nCol; /* Number of columns in the result set */
|
||||
int i; /* Loop counter */
|
||||
int rc;
|
||||
int n;
|
||||
const char *z;
|
||||
SHA3Context cx;
|
||||
int iSize;
|
||||
|
||||
if( argc==1 ){
|
||||
iSize = 256;
|
||||
}else{
|
||||
iSize = sqlite3_value_int(argv[1]);
|
||||
if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
|
||||
sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
|
||||
"384 512", -1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( zSql==0 ) return;
|
||||
SHA3Init(&cx, iSize);
|
||||
while( zSql[0] ){
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
|
||||
if( rc ){
|
||||
char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
|
||||
zSql, sqlite3_errmsg(db));
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_result_error(context, zMsg, -1);
|
||||
sqlite3_free(zMsg);
|
||||
return;
|
||||
}
|
||||
if( !sqlite3_stmt_readonly(pStmt) ){
|
||||
char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_result_error(context, zMsg, -1);
|
||||
sqlite3_free(zMsg);
|
||||
return;
|
||||
}
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
z = sqlite3_sql(pStmt);
|
||||
n = (int)strlen(z);
|
||||
hash_step_vformat(&cx,"S%d:",n);
|
||||
SHA3Update(&cx,(unsigned char*)z,n);
|
||||
|
||||
/* Compute a hash over the result of the query */
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
SHA3Update(&cx,(const unsigned char*)"R",1);
|
||||
for(i=0; i<nCol; i++){
|
||||
switch( sqlite3_column_type(pStmt,i) ){
|
||||
case SQLITE_NULL: {
|
||||
SHA3Update(&cx, (const unsigned char*)"N",1);
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
|
||||
memcpy(&u, &v, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'I';
|
||||
SHA3Update(&cx, x, 9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
double r = sqlite3_column_double(pStmt,i);
|
||||
memcpy(&u, &r, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'F';
|
||||
SHA3Update(&cx,x,9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_text(pStmt, i);
|
||||
hash_step_vformat(&cx,"T%d:",n2);
|
||||
SHA3Update(&cx, z2, n2);
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
|
||||
hash_step_vformat(&cx,"B%d:",n2);
|
||||
SHA3Update(&cx, z2, n2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_shathree_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "sha3", 1, SQLITE_UTF8, 0,
|
||||
sha3Func, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha3", 2, SQLITE_UTF8, 0,
|
||||
sha3Func, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha3_query", 1, SQLITE_UTF8, 0,
|
||||
sha3QueryFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha3_query", 2, SQLITE_UTF8, 0,
|
||||
sha3QueryFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
Vendored
+18992
File diff suppressed because it is too large
Load Diff
Vendored
+223787
File diff suppressed because it is too large
Load Diff
+274
@@ -0,0 +1,274 @@
|
||||
EXPORTS
|
||||
sqlite3_aggregate_context
|
||||
sqlite3_aggregate_count
|
||||
sqlite3_auto_extension
|
||||
sqlite3_backup_finish
|
||||
sqlite3_backup_init
|
||||
sqlite3_backup_pagecount
|
||||
sqlite3_backup_remaining
|
||||
sqlite3_backup_step
|
||||
sqlite3_bind_blob
|
||||
sqlite3_bind_blob64
|
||||
sqlite3_bind_double
|
||||
sqlite3_bind_int
|
||||
sqlite3_bind_int64
|
||||
sqlite3_bind_null
|
||||
sqlite3_bind_parameter_count
|
||||
sqlite3_bind_parameter_index
|
||||
sqlite3_bind_parameter_name
|
||||
sqlite3_bind_pointer
|
||||
sqlite3_bind_text
|
||||
sqlite3_bind_text16
|
||||
sqlite3_bind_text64
|
||||
sqlite3_bind_value
|
||||
sqlite3_bind_zeroblob
|
||||
sqlite3_bind_zeroblob64
|
||||
sqlite3_blob_bytes
|
||||
sqlite3_blob_close
|
||||
sqlite3_blob_open
|
||||
sqlite3_blob_read
|
||||
sqlite3_blob_reopen
|
||||
sqlite3_blob_write
|
||||
sqlite3_busy_handler
|
||||
sqlite3_busy_timeout
|
||||
sqlite3_cancel_auto_extension
|
||||
sqlite3_changes
|
||||
sqlite3_clear_bindings
|
||||
sqlite3_close
|
||||
sqlite3_close_v2
|
||||
sqlite3_collation_needed
|
||||
sqlite3_collation_needed16
|
||||
sqlite3_column_blob
|
||||
sqlite3_column_bytes
|
||||
sqlite3_column_bytes16
|
||||
sqlite3_column_count
|
||||
sqlite3_column_database_name
|
||||
sqlite3_column_database_name16
|
||||
sqlite3_column_decltype
|
||||
sqlite3_column_decltype16
|
||||
sqlite3_column_double
|
||||
sqlite3_column_int
|
||||
sqlite3_column_int64
|
||||
sqlite3_column_name
|
||||
sqlite3_column_name16
|
||||
sqlite3_column_origin_name
|
||||
sqlite3_column_origin_name16
|
||||
sqlite3_column_table_name
|
||||
sqlite3_column_table_name16
|
||||
sqlite3_column_text
|
||||
sqlite3_column_text16
|
||||
sqlite3_column_type
|
||||
sqlite3_column_value
|
||||
sqlite3_commit_hook
|
||||
sqlite3_compileoption_get
|
||||
sqlite3_compileoption_used
|
||||
sqlite3_complete
|
||||
sqlite3_complete16
|
||||
sqlite3_config
|
||||
sqlite3_context_db_handle
|
||||
sqlite3_create_collation
|
||||
sqlite3_create_collation16
|
||||
sqlite3_create_collation_v2
|
||||
sqlite3_create_function
|
||||
sqlite3_create_function16
|
||||
sqlite3_create_function_v2
|
||||
sqlite3_create_module
|
||||
sqlite3_create_module_v2
|
||||
sqlite3_create_window_function
|
||||
sqlite3_data_count
|
||||
sqlite3_db_cacheflush
|
||||
sqlite3_db_config
|
||||
sqlite3_db_filename
|
||||
sqlite3_db_handle
|
||||
sqlite3_db_mutex
|
||||
sqlite3_db_readonly
|
||||
sqlite3_db_release_memory
|
||||
sqlite3_db_status
|
||||
sqlite3_declare_vtab
|
||||
sqlite3_enable_load_extension
|
||||
sqlite3_enable_shared_cache
|
||||
sqlite3_errcode
|
||||
sqlite3_errmsg
|
||||
sqlite3_errmsg16
|
||||
sqlite3_errstr
|
||||
sqlite3_exec
|
||||
sqlite3_expanded_sql
|
||||
sqlite3_expired
|
||||
sqlite3_extended_errcode
|
||||
sqlite3_extended_result_codes
|
||||
sqlite3_file_control
|
||||
sqlite3_finalize
|
||||
sqlite3_free
|
||||
sqlite3_free_table
|
||||
sqlite3_get_autocommit
|
||||
sqlite3_get_auxdata
|
||||
sqlite3_get_table
|
||||
sqlite3_global_recover
|
||||
sqlite3_initialize
|
||||
sqlite3_interrupt
|
||||
sqlite3_key
|
||||
sqlite3_key_v2
|
||||
sqlite3_keyword_check
|
||||
sqlite3_keyword_count
|
||||
sqlite3_keyword_name
|
||||
sqlite3_last_insert_rowid
|
||||
sqlite3_libversion
|
||||
sqlite3_libversion_number
|
||||
sqlite3_limit
|
||||
sqlite3_load_extension
|
||||
sqlite3_log
|
||||
sqlite3_malloc
|
||||
sqlite3_malloc64
|
||||
sqlite3_memory_alarm
|
||||
sqlite3_memory_highwater
|
||||
sqlite3_memory_used
|
||||
sqlite3_mprintf
|
||||
sqlite3_msize
|
||||
sqlite3_mutex_alloc
|
||||
sqlite3_mutex_enter
|
||||
sqlite3_mutex_free
|
||||
sqlite3_mutex_leave
|
||||
sqlite3_mutex_try
|
||||
sqlite3_next_stmt
|
||||
sqlite3_open
|
||||
sqlite3_open16
|
||||
sqlite3_open_v2
|
||||
sqlite3_os_end
|
||||
sqlite3_os_init
|
||||
sqlite3_overload_function
|
||||
sqlite3_prepare
|
||||
sqlite3_prepare16
|
||||
sqlite3_prepare16_v2
|
||||
sqlite3_prepare16_v3
|
||||
sqlite3_prepare_v2
|
||||
sqlite3_prepare_v3
|
||||
sqlite3_profile
|
||||
sqlite3_progress_handler
|
||||
sqlite3_randomness
|
||||
sqlite3_realloc
|
||||
sqlite3_realloc64
|
||||
sqlite3_rekey
|
||||
sqlite3_rekey_v2
|
||||
sqlite3_release_memory
|
||||
sqlite3_reset
|
||||
sqlite3_reset_auto_extension
|
||||
sqlite3_result_blob
|
||||
sqlite3_result_blob64
|
||||
sqlite3_result_double
|
||||
sqlite3_result_error
|
||||
sqlite3_result_error16
|
||||
sqlite3_result_error_code
|
||||
sqlite3_result_error_nomem
|
||||
sqlite3_result_error_toobig
|
||||
sqlite3_result_int
|
||||
sqlite3_result_int64
|
||||
sqlite3_result_null
|
||||
sqlite3_result_pointer
|
||||
sqlite3_result_subtype
|
||||
sqlite3_result_text
|
||||
sqlite3_result_text16
|
||||
sqlite3_result_text16be
|
||||
sqlite3_result_text16le
|
||||
sqlite3_result_text64
|
||||
sqlite3_result_value
|
||||
sqlite3_result_zeroblob
|
||||
sqlite3_result_zeroblob64
|
||||
sqlite3_rollback_hook
|
||||
sqlite3_rtree_geometry_callback
|
||||
sqlite3_rtree_query_callback
|
||||
sqlite3_set_authorizer
|
||||
sqlite3_set_auxdata
|
||||
sqlite3_set_last_insert_rowid
|
||||
sqlite3_shutdown
|
||||
sqlite3_sleep
|
||||
sqlite3_snprintf
|
||||
sqlite3_soft_heap_limit
|
||||
sqlite3_soft_heap_limit64
|
||||
sqlite3_sourceid
|
||||
sqlite3_sql
|
||||
sqlite3_status
|
||||
sqlite3_status64
|
||||
sqlite3_step
|
||||
sqlite3_stmt_busy
|
||||
sqlite3_stmt_isexplain
|
||||
sqlite3_stmt_readonly
|
||||
sqlite3_stmt_status
|
||||
sqlite3_str_append
|
||||
sqlite3_str_appendall
|
||||
sqlite3_str_appendchar
|
||||
sqlite3_str_appendf
|
||||
sqlite3_str_errcode
|
||||
sqlite3_str_finish
|
||||
sqlite3_strglob
|
||||
sqlite3_stricmp
|
||||
sqlite3_str_length
|
||||
sqlite3_strlike
|
||||
sqlite3_str_new
|
||||
sqlite3_strnicmp
|
||||
sqlite3_str_reset
|
||||
sqlite3_str_value
|
||||
sqlite3_str_vappendf
|
||||
sqlite3_system_errno
|
||||
sqlite3_table_column_metadata
|
||||
sqlite3_test_control
|
||||
sqlite3_thread_cleanup
|
||||
sqlite3_threadsafe
|
||||
sqlite3_total_changes
|
||||
sqlite3_trace
|
||||
sqlite3_trace_v2
|
||||
sqlite3_transfer_bindings
|
||||
sqlite3_update_hook
|
||||
sqlite3_uri_boolean
|
||||
sqlite3_uri_int64
|
||||
sqlite3_uri_parameter
|
||||
sqlite3_user_data
|
||||
sqlite3_user_add
|
||||
sqlite3_user_authenticate
|
||||
sqlite3_user_change
|
||||
sqlite3_user_delete
|
||||
sqlite3_value_blob
|
||||
sqlite3_value_bytes
|
||||
sqlite3_value_bytes16
|
||||
sqlite3_value_double
|
||||
sqlite3_value_dup
|
||||
sqlite3_value_free
|
||||
sqlite3_value_frombind
|
||||
sqlite3_value_int
|
||||
sqlite3_value_int64
|
||||
sqlite3_value_nochange
|
||||
sqlite3_value_numeric_type
|
||||
sqlite3_value_pointer
|
||||
sqlite3_value_subtype
|
||||
sqlite3_value_text
|
||||
sqlite3_value_text16
|
||||
sqlite3_value_text16be
|
||||
sqlite3_value_text16le
|
||||
sqlite3_value_type
|
||||
sqlite3_vfs_find
|
||||
sqlite3_vfs_register
|
||||
sqlite3_vfs_unregister
|
||||
sqlite3_vmprintf
|
||||
sqlite3_vsnprintf
|
||||
sqlite3_vtab_collation
|
||||
sqlite3_vtab_config
|
||||
sqlite3_vtab_nochange
|
||||
sqlite3_vtab_on_conflict
|
||||
sqlite3_wal_autocheckpoint
|
||||
sqlite3_wal_checkpoint
|
||||
sqlite3_wal_checkpoint_v2
|
||||
sqlite3_wal_hook
|
||||
sqlite3_win32_is_nt
|
||||
sqlite3_win32_mbcs_to_utf8
|
||||
sqlite3_win32_mbcs_to_utf8_v2
|
||||
sqlite3_win32_set_directory
|
||||
sqlite3_win32_set_directory16
|
||||
sqlite3_win32_set_directory8
|
||||
sqlite3_win32_sleep
|
||||
sqlite3_win32_unicode_to_utf8
|
||||
sqlite3_win32_utf8_to_mbcs
|
||||
sqlite3_win32_utf8_to_mbcs_v2
|
||||
sqlite3_win32_utf8_to_unicode
|
||||
sqlite3_win32_write_debug
|
||||
wxsqlite3_codec_data
|
||||
wxsqlite3_config
|
||||
wxsqlite3_config_cipher
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
** Version
|
||||
*/
|
||||
#include <windows.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,29,0,0
|
||||
PRODUCTVERSION 3,29,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "SQLite"
|
||||
VALUE "FileDescription", "SQLite3 Database Library (with encryption support)"
|
||||
VALUE "FileVersion", "3.29.0.0"
|
||||
VALUE "InternalName", "sqlite3.dll"
|
||||
VALUE "LegalCopyright", "Public Domain"
|
||||
VALUE "OriginalFilename", "sqlite3.dll"
|
||||
VALUE "ProductName", "SQLite3"
|
||||
VALUE "ProductVersion", "3.29.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
+634
@@ -0,0 +1,634 @@
|
||||
/*
|
||||
** 2006 June 7
|
||||
**
|
||||
** 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 header file defines the SQLite interface for use by
|
||||
** shared libraries that want to be imported as extensions into
|
||||
** an SQLite instance. Shared libraries that intend to be loaded
|
||||
** as extensions by SQLite should #include this file instead of
|
||||
** sqlite3.h.
|
||||
*/
|
||||
#ifndef SQLITE3EXT_H
|
||||
#define SQLITE3EXT_H
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** The following structure holds pointers to all of the SQLite API
|
||||
** routines.
|
||||
**
|
||||
** WARNING: In order to maintain backwards compatibility, add new
|
||||
** interfaces to the end of this structure only. If you insert new
|
||||
** interfaces in the middle of this structure, then older different
|
||||
** versions of SQLite will not be able to load each other's shared
|
||||
** libraries!
|
||||
*/
|
||||
struct sqlite3_api_routines {
|
||||
void * (*aggregate_context)(sqlite3_context*,int nBytes);
|
||||
int (*aggregate_count)(sqlite3_context*);
|
||||
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
|
||||
int (*bind_double)(sqlite3_stmt*,int,double);
|
||||
int (*bind_int)(sqlite3_stmt*,int,int);
|
||||
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
|
||||
int (*bind_null)(sqlite3_stmt*,int);
|
||||
int (*bind_parameter_count)(sqlite3_stmt*);
|
||||
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
|
||||
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
|
||||
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
|
||||
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
|
||||
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
|
||||
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
|
||||
int (*busy_timeout)(sqlite3*,int ms);
|
||||
int (*changes)(sqlite3*);
|
||||
int (*close)(sqlite3*);
|
||||
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||
int eTextRep,const char*));
|
||||
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||
int eTextRep,const void*));
|
||||
const void * (*column_blob)(sqlite3_stmt*,int iCol);
|
||||
int (*column_bytes)(sqlite3_stmt*,int iCol);
|
||||
int (*column_bytes16)(sqlite3_stmt*,int iCol);
|
||||
int (*column_count)(sqlite3_stmt*pStmt);
|
||||
const char * (*column_database_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_database_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_decltype)(sqlite3_stmt*,int i);
|
||||
const void * (*column_decltype16)(sqlite3_stmt*,int);
|
||||
double (*column_double)(sqlite3_stmt*,int iCol);
|
||||
int (*column_int)(sqlite3_stmt*,int iCol);
|
||||
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
|
||||
const char * (*column_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_origin_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_origin_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_table_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_table_name16)(sqlite3_stmt*,int);
|
||||
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
|
||||
const void * (*column_text16)(sqlite3_stmt*,int iCol);
|
||||
int (*column_type)(sqlite3_stmt*,int iCol);
|
||||
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
|
||||
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
|
||||
int (*complete)(const char*sql);
|
||||
int (*complete16)(const void*sql);
|
||||
int (*create_collation)(sqlite3*,const char*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*));
|
||||
int (*create_collation16)(sqlite3*,const void*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*));
|
||||
int (*create_function)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*));
|
||||
int (*create_function16)(sqlite3*,const void*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*));
|
||||
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
|
||||
int (*data_count)(sqlite3_stmt*pStmt);
|
||||
sqlite3 * (*db_handle)(sqlite3_stmt*);
|
||||
int (*declare_vtab)(sqlite3*,const char*);
|
||||
int (*enable_shared_cache)(int);
|
||||
int (*errcode)(sqlite3*db);
|
||||
const char * (*errmsg)(sqlite3*);
|
||||
const void * (*errmsg16)(sqlite3*);
|
||||
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
|
||||
int (*expired)(sqlite3_stmt*);
|
||||
int (*finalize)(sqlite3_stmt*pStmt);
|
||||
void (*free)(void*);
|
||||
void (*free_table)(char**result);
|
||||
int (*get_autocommit)(sqlite3*);
|
||||
void * (*get_auxdata)(sqlite3_context*,int);
|
||||
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
|
||||
int (*global_recover)(void);
|
||||
void (*interruptx)(sqlite3*);
|
||||
sqlite_int64 (*last_insert_rowid)(sqlite3*);
|
||||
const char * (*libversion)(void);
|
||||
int (*libversion_number)(void);
|
||||
void *(*malloc)(int);
|
||||
char * (*mprintf)(const char*,...);
|
||||
int (*open)(const char*,sqlite3**);
|
||||
int (*open16)(const void*,sqlite3**);
|
||||
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
|
||||
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
|
||||
void *(*realloc)(void*,int);
|
||||
int (*reset)(sqlite3_stmt*pStmt);
|
||||
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_double)(sqlite3_context*,double);
|
||||
void (*result_error)(sqlite3_context*,const char*,int);
|
||||
void (*result_error16)(sqlite3_context*,const void*,int);
|
||||
void (*result_int)(sqlite3_context*,int);
|
||||
void (*result_int64)(sqlite3_context*,sqlite_int64);
|
||||
void (*result_null)(sqlite3_context*);
|
||||
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
|
||||
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_value)(sqlite3_context*,sqlite3_value*);
|
||||
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
|
||||
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
|
||||
const char*,const char*),void*);
|
||||
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
|
||||
char * (*xsnprintf)(int,char*,const char*,...);
|
||||
int (*step)(sqlite3_stmt*);
|
||||
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
|
||||
char const**,char const**,int*,int*,int*);
|
||||
void (*thread_cleanup)(void);
|
||||
int (*total_changes)(sqlite3*);
|
||||
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
|
||||
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
|
||||
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
|
||||
sqlite_int64),void*);
|
||||
void * (*user_data)(sqlite3_context*);
|
||||
const void * (*value_blob)(sqlite3_value*);
|
||||
int (*value_bytes)(sqlite3_value*);
|
||||
int (*value_bytes16)(sqlite3_value*);
|
||||
double (*value_double)(sqlite3_value*);
|
||||
int (*value_int)(sqlite3_value*);
|
||||
sqlite_int64 (*value_int64)(sqlite3_value*);
|
||||
int (*value_numeric_type)(sqlite3_value*);
|
||||
const unsigned char * (*value_text)(sqlite3_value*);
|
||||
const void * (*value_text16)(sqlite3_value*);
|
||||
const void * (*value_text16be)(sqlite3_value*);
|
||||
const void * (*value_text16le)(sqlite3_value*);
|
||||
int (*value_type)(sqlite3_value*);
|
||||
char *(*vmprintf)(const char*,va_list);
|
||||
/* Added ??? */
|
||||
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
|
||||
/* Added by 3.3.13 */
|
||||
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
int (*clear_bindings)(sqlite3_stmt*);
|
||||
/* Added by 3.4.1 */
|
||||
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
|
||||
void (*xDestroy)(void *));
|
||||
/* Added by 3.5.0 */
|
||||
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
|
||||
int (*blob_bytes)(sqlite3_blob*);
|
||||
int (*blob_close)(sqlite3_blob*);
|
||||
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
|
||||
int,sqlite3_blob**);
|
||||
int (*blob_read)(sqlite3_blob*,void*,int,int);
|
||||
int (*blob_write)(sqlite3_blob*,const void*,int,int);
|
||||
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*),
|
||||
void(*)(void*));
|
||||
int (*file_control)(sqlite3*,const char*,int,void*);
|
||||
sqlite3_int64 (*memory_highwater)(int);
|
||||
sqlite3_int64 (*memory_used)(void);
|
||||
sqlite3_mutex *(*mutex_alloc)(int);
|
||||
void (*mutex_enter)(sqlite3_mutex*);
|
||||
void (*mutex_free)(sqlite3_mutex*);
|
||||
void (*mutex_leave)(sqlite3_mutex*);
|
||||
int (*mutex_try)(sqlite3_mutex*);
|
||||
int (*open_v2)(const char*,sqlite3**,int,const char*);
|
||||
int (*release_memory)(int);
|
||||
void (*result_error_nomem)(sqlite3_context*);
|
||||
void (*result_error_toobig)(sqlite3_context*);
|
||||
int (*sleep)(int);
|
||||
void (*soft_heap_limit)(int);
|
||||
sqlite3_vfs *(*vfs_find)(const char*);
|
||||
int (*vfs_register)(sqlite3_vfs*,int);
|
||||
int (*vfs_unregister)(sqlite3_vfs*);
|
||||
int (*xthreadsafe)(void);
|
||||
void (*result_zeroblob)(sqlite3_context*,int);
|
||||
void (*result_error_code)(sqlite3_context*,int);
|
||||
int (*test_control)(int, ...);
|
||||
void (*randomness)(int,void*);
|
||||
sqlite3 *(*context_db_handle)(sqlite3_context*);
|
||||
int (*extended_result_codes)(sqlite3*,int);
|
||||
int (*limit)(sqlite3*,int,int);
|
||||
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
|
||||
const char *(*sql)(sqlite3_stmt*);
|
||||
int (*status)(int,int*,int*,int);
|
||||
int (*backup_finish)(sqlite3_backup*);
|
||||
sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
|
||||
int (*backup_pagecount)(sqlite3_backup*);
|
||||
int (*backup_remaining)(sqlite3_backup*);
|
||||
int (*backup_step)(sqlite3_backup*,int);
|
||||
const char *(*compileoption_get)(int);
|
||||
int (*compileoption_used)(const char*);
|
||||
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void(*xDestroy)(void*));
|
||||
int (*db_config)(sqlite3*,int,...);
|
||||
sqlite3_mutex *(*db_mutex)(sqlite3*);
|
||||
int (*db_status)(sqlite3*,int,int*,int*,int);
|
||||
int (*extended_errcode)(sqlite3*);
|
||||
void (*log)(int,const char*,...);
|
||||
sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
|
||||
const char *(*sourceid)(void);
|
||||
int (*stmt_status)(sqlite3_stmt*,int,int);
|
||||
int (*strnicmp)(const char*,const char*,int);
|
||||
int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
|
||||
int (*wal_autocheckpoint)(sqlite3*,int);
|
||||
int (*wal_checkpoint)(sqlite3*,const char*);
|
||||
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
|
||||
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
|
||||
int (*vtab_config)(sqlite3*,int op,...);
|
||||
int (*vtab_on_conflict)(sqlite3*);
|
||||
/* Version 3.7.16 and later */
|
||||
int (*close_v2)(sqlite3*);
|
||||
const char *(*db_filename)(sqlite3*,const char*);
|
||||
int (*db_readonly)(sqlite3*,const char*);
|
||||
int (*db_release_memory)(sqlite3*);
|
||||
const char *(*errstr)(int);
|
||||
int (*stmt_busy)(sqlite3_stmt*);
|
||||
int (*stmt_readonly)(sqlite3_stmt*);
|
||||
int (*stricmp)(const char*,const char*);
|
||||
int (*uri_boolean)(const char*,const char*,int);
|
||||
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
|
||||
const char *(*uri_parameter)(const char*,const char*);
|
||||
char *(*xvsnprintf)(int,char*,const char*,va_list);
|
||||
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
|
||||
/* Version 3.8.7 and later */
|
||||
int (*auto_extension)(void(*)(void));
|
||||
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
|
||||
void(*)(void*),unsigned char);
|
||||
int (*cancel_auto_extension)(void(*)(void));
|
||||
int (*load_extension)(sqlite3*,const char*,const char*,char**);
|
||||
void *(*malloc64)(sqlite3_uint64);
|
||||
sqlite3_uint64 (*msize)(void*);
|
||||
void *(*realloc64)(void*,sqlite3_uint64);
|
||||
void (*reset_auto_extension)(void);
|
||||
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
|
||||
void(*)(void*), unsigned char);
|
||||
int (*strglob)(const char*,const char*);
|
||||
/* Version 3.8.11 and later */
|
||||
sqlite3_value *(*value_dup)(const sqlite3_value*);
|
||||
void (*value_free)(sqlite3_value*);
|
||||
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
|
||||
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
|
||||
/* Version 3.9.0 and later */
|
||||
unsigned int (*value_subtype)(sqlite3_value*);
|
||||
void (*result_subtype)(sqlite3_context*,unsigned int);
|
||||
/* Version 3.10.0 and later */
|
||||
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
|
||||
int (*strlike)(const char*,const char*,unsigned int);
|
||||
int (*db_cacheflush)(sqlite3*);
|
||||
/* Version 3.12.0 and later */
|
||||
int (*system_errno)(sqlite3*);
|
||||
/* Version 3.14.0 and later */
|
||||
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
|
||||
char *(*expanded_sql)(sqlite3_stmt*);
|
||||
/* Version 3.18.0 and later */
|
||||
void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
|
||||
/* Version 3.20.0 and later */
|
||||
int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
|
||||
sqlite3_stmt**,const char**);
|
||||
int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
|
||||
sqlite3_stmt**,const void**);
|
||||
int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
|
||||
void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
|
||||
void *(*value_pointer)(sqlite3_value*,const char*);
|
||||
int (*vtab_nochange)(sqlite3_context*);
|
||||
int (*value_nochange)(sqlite3_value*);
|
||||
const char *(*vtab_collation)(sqlite3_index_info*,int);
|
||||
/* Version 3.24.0 and later */
|
||||
int (*keyword_count)(void);
|
||||
int (*keyword_name)(int,const char**,int*);
|
||||
int (*keyword_check)(const char*,int);
|
||||
sqlite3_str *(*str_new)(sqlite3*);
|
||||
char *(*str_finish)(sqlite3_str*);
|
||||
void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
|
||||
void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
|
||||
void (*str_append)(sqlite3_str*, const char *zIn, int N);
|
||||
void (*str_appendall)(sqlite3_str*, const char *zIn);
|
||||
void (*str_appendchar)(sqlite3_str*, int N, char C);
|
||||
void (*str_reset)(sqlite3_str*);
|
||||
int (*str_errcode)(sqlite3_str*);
|
||||
int (*str_length)(sqlite3_str*);
|
||||
char *(*str_value)(sqlite3_str*);
|
||||
/* Version 3.25.0 and later */
|
||||
int (*create_window_function)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void (*xValue)(sqlite3_context*),
|
||||
void (*xInv)(sqlite3_context*,int,sqlite3_value**),
|
||||
void(*xDestroy)(void*));
|
||||
/* Version 3.26.0 and later */
|
||||
const char *(*normalized_sql)(sqlite3_stmt*);
|
||||
/* Version 3.28.0 and later */
|
||||
int (*stmt_isexplain)(sqlite3_stmt*);
|
||||
int (*value_frombind)(sqlite3_value*);
|
||||
};
|
||||
|
||||
/*
|
||||
** This is the function signature used for all extension entry points. It
|
||||
** is also defined in the file "loadext.c".
|
||||
*/
|
||||
typedef int (*sqlite3_loadext_entry)(
|
||||
sqlite3 *db, /* Handle to the database. */
|
||||
char **pzErrMsg, /* Used to set error string on failure. */
|
||||
const sqlite3_api_routines *pThunk /* Extension API function pointers. */
|
||||
);
|
||||
|
||||
/*
|
||||
** The following macros redefine the API routines so that they are
|
||||
** redirected through the global sqlite3_api structure.
|
||||
**
|
||||
** This header file is also used by the loadext.c source file
|
||||
** (part of the main SQLite library - not an extension) so that
|
||||
** it can get access to the sqlite3_api_routines structure
|
||||
** definition. But the main library does not want to redefine
|
||||
** the API. So the redefinition macros are only valid if the
|
||||
** SQLITE_CORE macros is undefined.
|
||||
*/
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
|
||||
#endif
|
||||
#define sqlite3_bind_blob sqlite3_api->bind_blob
|
||||
#define sqlite3_bind_double sqlite3_api->bind_double
|
||||
#define sqlite3_bind_int sqlite3_api->bind_int
|
||||
#define sqlite3_bind_int64 sqlite3_api->bind_int64
|
||||
#define sqlite3_bind_null sqlite3_api->bind_null
|
||||
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
|
||||
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
|
||||
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
|
||||
#define sqlite3_bind_text sqlite3_api->bind_text
|
||||
#define sqlite3_bind_text16 sqlite3_api->bind_text16
|
||||
#define sqlite3_bind_value sqlite3_api->bind_value
|
||||
#define sqlite3_busy_handler sqlite3_api->busy_handler
|
||||
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
|
||||
#define sqlite3_changes sqlite3_api->changes
|
||||
#define sqlite3_close sqlite3_api->close
|
||||
#define sqlite3_collation_needed sqlite3_api->collation_needed
|
||||
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
|
||||
#define sqlite3_column_blob sqlite3_api->column_blob
|
||||
#define sqlite3_column_bytes sqlite3_api->column_bytes
|
||||
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
|
||||
#define sqlite3_column_count sqlite3_api->column_count
|
||||
#define sqlite3_column_database_name sqlite3_api->column_database_name
|
||||
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
|
||||
#define sqlite3_column_decltype sqlite3_api->column_decltype
|
||||
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
|
||||
#define sqlite3_column_double sqlite3_api->column_double
|
||||
#define sqlite3_column_int sqlite3_api->column_int
|
||||
#define sqlite3_column_int64 sqlite3_api->column_int64
|
||||
#define sqlite3_column_name sqlite3_api->column_name
|
||||
#define sqlite3_column_name16 sqlite3_api->column_name16
|
||||
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
|
||||
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
|
||||
#define sqlite3_column_table_name sqlite3_api->column_table_name
|
||||
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
|
||||
#define sqlite3_column_text sqlite3_api->column_text
|
||||
#define sqlite3_column_text16 sqlite3_api->column_text16
|
||||
#define sqlite3_column_type sqlite3_api->column_type
|
||||
#define sqlite3_column_value sqlite3_api->column_value
|
||||
#define sqlite3_commit_hook sqlite3_api->commit_hook
|
||||
#define sqlite3_complete sqlite3_api->complete
|
||||
#define sqlite3_complete16 sqlite3_api->complete16
|
||||
#define sqlite3_create_collation sqlite3_api->create_collation
|
||||
#define sqlite3_create_collation16 sqlite3_api->create_collation16
|
||||
#define sqlite3_create_function sqlite3_api->create_function
|
||||
#define sqlite3_create_function16 sqlite3_api->create_function16
|
||||
#define sqlite3_create_module sqlite3_api->create_module
|
||||
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
|
||||
#define sqlite3_data_count sqlite3_api->data_count
|
||||
#define sqlite3_db_handle sqlite3_api->db_handle
|
||||
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
|
||||
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
|
||||
#define sqlite3_errcode sqlite3_api->errcode
|
||||
#define sqlite3_errmsg sqlite3_api->errmsg
|
||||
#define sqlite3_errmsg16 sqlite3_api->errmsg16
|
||||
#define sqlite3_exec sqlite3_api->exec
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_expired sqlite3_api->expired
|
||||
#endif
|
||||
#define sqlite3_finalize sqlite3_api->finalize
|
||||
#define sqlite3_free sqlite3_api->free
|
||||
#define sqlite3_free_table sqlite3_api->free_table
|
||||
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
|
||||
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
|
||||
#define sqlite3_get_table sqlite3_api->get_table
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_global_recover sqlite3_api->global_recover
|
||||
#endif
|
||||
#define sqlite3_interrupt sqlite3_api->interruptx
|
||||
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
|
||||
#define sqlite3_libversion sqlite3_api->libversion
|
||||
#define sqlite3_libversion_number sqlite3_api->libversion_number
|
||||
#define sqlite3_malloc sqlite3_api->malloc
|
||||
#define sqlite3_mprintf sqlite3_api->mprintf
|
||||
#define sqlite3_open sqlite3_api->open
|
||||
#define sqlite3_open16 sqlite3_api->open16
|
||||
#define sqlite3_prepare sqlite3_api->prepare
|
||||
#define sqlite3_prepare16 sqlite3_api->prepare16
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_profile sqlite3_api->profile
|
||||
#define sqlite3_progress_handler sqlite3_api->progress_handler
|
||||
#define sqlite3_realloc sqlite3_api->realloc
|
||||
#define sqlite3_reset sqlite3_api->reset
|
||||
#define sqlite3_result_blob sqlite3_api->result_blob
|
||||
#define sqlite3_result_double sqlite3_api->result_double
|
||||
#define sqlite3_result_error sqlite3_api->result_error
|
||||
#define sqlite3_result_error16 sqlite3_api->result_error16
|
||||
#define sqlite3_result_int sqlite3_api->result_int
|
||||
#define sqlite3_result_int64 sqlite3_api->result_int64
|
||||
#define sqlite3_result_null sqlite3_api->result_null
|
||||
#define sqlite3_result_text sqlite3_api->result_text
|
||||
#define sqlite3_result_text16 sqlite3_api->result_text16
|
||||
#define sqlite3_result_text16be sqlite3_api->result_text16be
|
||||
#define sqlite3_result_text16le sqlite3_api->result_text16le
|
||||
#define sqlite3_result_value sqlite3_api->result_value
|
||||
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
|
||||
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
|
||||
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
|
||||
#define sqlite3_snprintf sqlite3_api->xsnprintf
|
||||
#define sqlite3_step sqlite3_api->step
|
||||
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
|
||||
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
|
||||
#define sqlite3_total_changes sqlite3_api->total_changes
|
||||
#define sqlite3_trace sqlite3_api->trace
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
|
||||
#endif
|
||||
#define sqlite3_update_hook sqlite3_api->update_hook
|
||||
#define sqlite3_user_data sqlite3_api->user_data
|
||||
#define sqlite3_value_blob sqlite3_api->value_blob
|
||||
#define sqlite3_value_bytes sqlite3_api->value_bytes
|
||||
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
|
||||
#define sqlite3_value_double sqlite3_api->value_double
|
||||
#define sqlite3_value_int sqlite3_api->value_int
|
||||
#define sqlite3_value_int64 sqlite3_api->value_int64
|
||||
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
|
||||
#define sqlite3_value_text sqlite3_api->value_text
|
||||
#define sqlite3_value_text16 sqlite3_api->value_text16
|
||||
#define sqlite3_value_text16be sqlite3_api->value_text16be
|
||||
#define sqlite3_value_text16le sqlite3_api->value_text16le
|
||||
#define sqlite3_value_type sqlite3_api->value_type
|
||||
#define sqlite3_vmprintf sqlite3_api->vmprintf
|
||||
#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
|
||||
#define sqlite3_overload_function sqlite3_api->overload_function
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
|
||||
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
|
||||
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
|
||||
#define sqlite3_blob_close sqlite3_api->blob_close
|
||||
#define sqlite3_blob_open sqlite3_api->blob_open
|
||||
#define sqlite3_blob_read sqlite3_api->blob_read
|
||||
#define sqlite3_blob_write sqlite3_api->blob_write
|
||||
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
|
||||
#define sqlite3_file_control sqlite3_api->file_control
|
||||
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
|
||||
#define sqlite3_memory_used sqlite3_api->memory_used
|
||||
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
|
||||
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
|
||||
#define sqlite3_mutex_free sqlite3_api->mutex_free
|
||||
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
|
||||
#define sqlite3_mutex_try sqlite3_api->mutex_try
|
||||
#define sqlite3_open_v2 sqlite3_api->open_v2
|
||||
#define sqlite3_release_memory sqlite3_api->release_memory
|
||||
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
|
||||
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
|
||||
#define sqlite3_sleep sqlite3_api->sleep
|
||||
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
|
||||
#define sqlite3_vfs_find sqlite3_api->vfs_find
|
||||
#define sqlite3_vfs_register sqlite3_api->vfs_register
|
||||
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
|
||||
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
|
||||
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
|
||||
#define sqlite3_result_error_code sqlite3_api->result_error_code
|
||||
#define sqlite3_test_control sqlite3_api->test_control
|
||||
#define sqlite3_randomness sqlite3_api->randomness
|
||||
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
|
||||
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
|
||||
#define sqlite3_limit sqlite3_api->limit
|
||||
#define sqlite3_next_stmt sqlite3_api->next_stmt
|
||||
#define sqlite3_sql sqlite3_api->sql
|
||||
#define sqlite3_status sqlite3_api->status
|
||||
#define sqlite3_backup_finish sqlite3_api->backup_finish
|
||||
#define sqlite3_backup_init sqlite3_api->backup_init
|
||||
#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
|
||||
#define sqlite3_backup_remaining sqlite3_api->backup_remaining
|
||||
#define sqlite3_backup_step sqlite3_api->backup_step
|
||||
#define sqlite3_compileoption_get sqlite3_api->compileoption_get
|
||||
#define sqlite3_compileoption_used sqlite3_api->compileoption_used
|
||||
#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
|
||||
#define sqlite3_db_config sqlite3_api->db_config
|
||||
#define sqlite3_db_mutex sqlite3_api->db_mutex
|
||||
#define sqlite3_db_status sqlite3_api->db_status
|
||||
#define sqlite3_extended_errcode sqlite3_api->extended_errcode
|
||||
#define sqlite3_log sqlite3_api->log
|
||||
#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
|
||||
#define sqlite3_sourceid sqlite3_api->sourceid
|
||||
#define sqlite3_stmt_status sqlite3_api->stmt_status
|
||||
#define sqlite3_strnicmp sqlite3_api->strnicmp
|
||||
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
|
||||
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
|
||||
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
|
||||
#define sqlite3_wal_hook sqlite3_api->wal_hook
|
||||
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
|
||||
#define sqlite3_vtab_config sqlite3_api->vtab_config
|
||||
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
|
||||
/* Version 3.7.16 and later */
|
||||
#define sqlite3_close_v2 sqlite3_api->close_v2
|
||||
#define sqlite3_db_filename sqlite3_api->db_filename
|
||||
#define sqlite3_db_readonly sqlite3_api->db_readonly
|
||||
#define sqlite3_db_release_memory sqlite3_api->db_release_memory
|
||||
#define sqlite3_errstr sqlite3_api->errstr
|
||||
#define sqlite3_stmt_busy sqlite3_api->stmt_busy
|
||||
#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
|
||||
#define sqlite3_stricmp sqlite3_api->stricmp
|
||||
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
|
||||
#define sqlite3_uri_int64 sqlite3_api->uri_int64
|
||||
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
|
||||
#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
|
||||
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
|
||||
/* Version 3.8.7 and later */
|
||||
#define sqlite3_auto_extension sqlite3_api->auto_extension
|
||||
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
|
||||
#define sqlite3_bind_text64 sqlite3_api->bind_text64
|
||||
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
|
||||
#define sqlite3_load_extension sqlite3_api->load_extension
|
||||
#define sqlite3_malloc64 sqlite3_api->malloc64
|
||||
#define sqlite3_msize sqlite3_api->msize
|
||||
#define sqlite3_realloc64 sqlite3_api->realloc64
|
||||
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
|
||||
#define sqlite3_result_blob64 sqlite3_api->result_blob64
|
||||
#define sqlite3_result_text64 sqlite3_api->result_text64
|
||||
#define sqlite3_strglob sqlite3_api->strglob
|
||||
/* Version 3.8.11 and later */
|
||||
#define sqlite3_value_dup sqlite3_api->value_dup
|
||||
#define sqlite3_value_free sqlite3_api->value_free
|
||||
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
|
||||
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
|
||||
/* Version 3.9.0 and later */
|
||||
#define sqlite3_value_subtype sqlite3_api->value_subtype
|
||||
#define sqlite3_result_subtype sqlite3_api->result_subtype
|
||||
/* Version 3.10.0 and later */
|
||||
#define sqlite3_status64 sqlite3_api->status64
|
||||
#define sqlite3_strlike sqlite3_api->strlike
|
||||
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
|
||||
/* Version 3.12.0 and later */
|
||||
#define sqlite3_system_errno sqlite3_api->system_errno
|
||||
/* Version 3.14.0 and later */
|
||||
#define sqlite3_trace_v2 sqlite3_api->trace_v2
|
||||
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
|
||||
/* Version 3.18.0 and later */
|
||||
#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
|
||||
/* Version 3.20.0 and later */
|
||||
#define sqlite3_prepare_v3 sqlite3_api->prepare_v3
|
||||
#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3
|
||||
#define sqlite3_bind_pointer sqlite3_api->bind_pointer
|
||||
#define sqlite3_result_pointer sqlite3_api->result_pointer
|
||||
#define sqlite3_value_pointer sqlite3_api->value_pointer
|
||||
/* Version 3.22.0 and later */
|
||||
#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
|
||||
#define sqlite3_value_nochange sqlite3_api->value_nochange
|
||||
#define sqlite3_vtab_collation sqlite3_api->vtab_collation
|
||||
/* Version 3.24.0 and later */
|
||||
#define sqlite3_keyword_count sqlite3_api->keyword_count
|
||||
#define sqlite3_keyword_name sqlite3_api->keyword_name
|
||||
#define sqlite3_keyword_check sqlite3_api->keyword_check
|
||||
#define sqlite3_str_new sqlite3_api->str_new
|
||||
#define sqlite3_str_finish sqlite3_api->str_finish
|
||||
#define sqlite3_str_appendf sqlite3_api->str_appendf
|
||||
#define sqlite3_str_vappendf sqlite3_api->str_vappendf
|
||||
#define sqlite3_str_append sqlite3_api->str_append
|
||||
#define sqlite3_str_appendall sqlite3_api->str_appendall
|
||||
#define sqlite3_str_appendchar sqlite3_api->str_appendchar
|
||||
#define sqlite3_str_reset sqlite3_api->str_reset
|
||||
#define sqlite3_str_errcode sqlite3_api->str_errcode
|
||||
#define sqlite3_str_length sqlite3_api->str_length
|
||||
#define sqlite3_str_value sqlite3_api->str_value
|
||||
/* Version 3.25.0 and later */
|
||||
#define sqlite3_create_window_function sqlite3_api->create_window_function
|
||||
/* Version 3.26.0 and later */
|
||||
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
|
||||
/* Version 3.28.0 and later */
|
||||
#define sqlite3_stmt_isexplain sqlite3_api->isexplain
|
||||
#define sqlite3_value_frombind sqlite3_api->frombind
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
/* This case when the file really is being compiled as a loadable
|
||||
** extension */
|
||||
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
|
||||
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
|
||||
# define SQLITE_EXTENSION_INIT3 \
|
||||
extern const sqlite3_api_routines *sqlite3_api;
|
||||
#else
|
||||
/* This case when the file is being statically linked into the
|
||||
** application */
|
||||
# define SQLITE_EXTENSION_INIT1 /*no-op*/
|
||||
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
|
||||
# define SQLITE_EXTENSION_INIT3 /*no-op*/
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE3EXT_H */
|
||||
+373
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
** Name: sqlite3secure.c
|
||||
** Purpose: Amalgamation of the wxSQLite3 encryption extension for SQLite
|
||||
** Author: Ulrich Telle
|
||||
** Created: 2006-12-06
|
||||
** Copyright: (c) 2006-2019 Ulrich Telle
|
||||
** License: LGPL-3.0+ WITH WxWindows-exception-3.1
|
||||
*/
|
||||
|
||||
/*
|
||||
** Enable SQLite debug assertions if requested
|
||||
*/
|
||||
#ifndef SQLITE_DEBUG
|
||||
#if defined(SQLITE_ENABLE_DEBUG) && (SQLITE_ENABLE_DEBUG == 1)
|
||||
#define SQLITE_DEBUG 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** To enable the extension functions define SQLITE_ENABLE_EXTFUNC on compiling this module
|
||||
** To enable the reading CSV files define SQLITE_ENABLE_CSV on compiling this module
|
||||
** To enable the SHA3 support define SQLITE_ENABLE_SHA3 on compiling this module
|
||||
** To enable the CARRAY support define SQLITE_ENABLE_CARRAY on compiling this module
|
||||
** To enable the FILEIO support define SQLITE_ENABLE_FILEIO on compiling this module
|
||||
** To enable the SERIES support define SQLITE_ENABLE_SERIES on compiling this module
|
||||
*/
|
||||
#if defined(SQLITE_HAS_CODEC) || \
|
||||
defined(SQLITE_ENABLE_EXTFUNC) || \
|
||||
defined(SQLITE_ENABLE_CSV) || \
|
||||
defined(SQLITE_ENABLE_SHA3) || \
|
||||
defined(SQLITE_ENABLE_CARRAY) || \
|
||||
defined(SQLITE_ENABLE_FILEIO) || \
|
||||
defined(SQLITE_ENABLE_SERIES)
|
||||
#define sqlite3_open sqlite3_open_internal
|
||||
#define sqlite3_open16 sqlite3_open16_internal
|
||||
#define sqlite3_open_v2 sqlite3_open_v2_internal
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Enable the user authentication feature
|
||||
*/
|
||||
#ifndef SQLITE_USER_AUTHENTICATION
|
||||
#define SQLITE_USER_AUTHENTICATION 1
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
#include <windows.h>
|
||||
|
||||
/* SQLite functions only needed on Win32 */
|
||||
extern void sqlite3_win32_write_debug(const char *, int);
|
||||
extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
|
||||
extern char *sqlite3_win32_mbcs_to_utf8(const char *);
|
||||
extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int);
|
||||
extern char *sqlite3_win32_utf8_to_mbcs(const char *);
|
||||
extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int);
|
||||
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *);
|
||||
#endif
|
||||
|
||||
#include "sqlite3.c"
|
||||
|
||||
/*
|
||||
** Crypto algorithms
|
||||
*/
|
||||
#include "md5.c"
|
||||
#include "sha1.c"
|
||||
#include "sha2.c"
|
||||
#include "fastpbkdf2.c"
|
||||
|
||||
/* Prototypes for several crypto functions to make pedantic compilers happy */
|
||||
void chacha20_xor(unsigned char* data, size_t n, const unsigned char key[32], const unsigned char nonce[12], uint32_t counter);
|
||||
void poly1305(const unsigned char* msg, size_t n, const unsigned char key[32], unsigned char tag[16]);
|
||||
int poly1305_tagcmp(const unsigned char tag1[16], const unsigned char tag2[16]);
|
||||
void chacha20_rng(void* out, size_t n);
|
||||
|
||||
#include "chacha20poly1305.c"
|
||||
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
#include "sqlite3userauth.h"
|
||||
#include "userauth.c"
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_HAS_CODEC) || \
|
||||
defined(SQLITE_ENABLE_EXTFUNC) || \
|
||||
defined(SQLITE_ENABLE_CSV) || \
|
||||
defined(SQLITE_ENABLE_SHA3) || \
|
||||
defined(SQLITE_ENABLE_CARRAY) || \
|
||||
defined(SQLITE_ENABLE_FILEIO) || \
|
||||
defined(SQLITE_ENABLE_SERIES)
|
||||
#undef sqlite3_open
|
||||
#undef sqlite3_open16
|
||||
#undef sqlite3_open_v2
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_DISKIO
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
|
||||
/*
|
||||
** Get the codec argument for this pager
|
||||
*/
|
||||
static void*
|
||||
mySqlite3PagerGetCodec(Pager *pPager)
|
||||
{
|
||||
#if (SQLITE_VERSION_NUMBER >= 3006016)
|
||||
return sqlite3PagerGetCodec(pPager);
|
||||
#else
|
||||
return (pPager->xCodec) ? pPager->pCodecArg : NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the codec argument for this pager
|
||||
*/
|
||||
static void
|
||||
mySqlite3PagerSetCodec(Pager *pPager,
|
||||
void *(*xCodec)(void*,void*,Pgno,int),
|
||||
void (*xCodecSizeChng)(void*,int,int),
|
||||
void (*xCodecFree)(void*),
|
||||
void *pCodec)
|
||||
{
|
||||
sqlite3PagerSetCodec(pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec);
|
||||
}
|
||||
|
||||
/*
|
||||
** Declare function prototype for registering the codec extension functions
|
||||
*/
|
||||
static int
|
||||
registerCodecExtensions(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
||||
|
||||
/*
|
||||
** Codec implementation
|
||||
*/
|
||||
#include "rijndael.c"
|
||||
#include "codec.c"
|
||||
#include "codecext.c"
|
||||
|
||||
#endif /* SQLITE_HAS_CODEC */
|
||||
#endif /* SQLITE_OMIT_DISKIO */
|
||||
|
||||
/*
|
||||
** Extension functions
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_EXTFUNC
|
||||
/* Prototype for initialization function of EXTENSIONFUNCTIONS extension */
|
||||
int RegisterExtensionFunctions(sqlite3 *db);
|
||||
#include "extensionfunctions.c"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** CSV import
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_CSV
|
||||
/* Prototype for initialization function of CSV extension */
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_csv_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
||||
#include "csv.c"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** SHA3
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_SHA3
|
||||
/* Prototype for initialization function of SHA3 extension */
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_shathree_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
||||
#include "shathree.c"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** CARRAY
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_CARRAY
|
||||
/* Prototype for initialization function of CARRAY extension */
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_carray_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
||||
#include "carray.c"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** FILEIO
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_FILEIO
|
||||
/* Prototype for initialization function of FILEIO extension */
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_fileio_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
||||
|
||||
/* MinGW specifics */
|
||||
#if (!defined(_WIN32) && !defined(WIN32)) || defined(__MINGW32__)
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
# if defined(__MINGW32__)
|
||||
# define DIRENT dirent
|
||||
# ifndef S_ISLNK
|
||||
# define S_ISLNK(mode) (0)
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "test_windirent.c"
|
||||
#include "fileio.c"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** SERIES
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_SERIES
|
||||
/* Prototype for initialization function of SERIES extension */
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_series_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
||||
#include "series.c"
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_HAS_CODEC) || \
|
||||
defined(SQLITE_ENABLE_EXTFUNC) || \
|
||||
defined(SQLITE_ENABLE_CSV) || \
|
||||
defined(SQLITE_ENABLE_SHA3) || \
|
||||
defined(SQLITE_ENABLE_CARRAY) || \
|
||||
defined(SQLITE_ENABLE_FILEIO) || \
|
||||
defined(SQLITE_ENABLE_SERIES)
|
||||
|
||||
static int
|
||||
registerCodecExtensions(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
CodecParameter* codecParameterTable = NULL;
|
||||
|
||||
if (sqlite3FindFunction(db, "wxsqlite3_config_table", 0, SQLITE_UTF8, 0) != NULL)
|
||||
{
|
||||
/* Return if codec extension functions are already defined */
|
||||
return rc;
|
||||
}
|
||||
|
||||
codecParameterTable = CloneCodecParameterTable();
|
||||
rc = (codecParameterTable != NULL) ? SQLITE_OK : SQLITE_NOMEM;
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_create_function_v2(db, "wxsqlite3_config_table", 0, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
codecParameterTable, wxsqlite3_config_table, 0, 0, (void(*)(void*)) FreeCodecParameterTable);
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_create_function(db, "wxsqlite3_config", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
codecParameterTable, wxsqlite3_config_params, 0, 0);
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_create_function(db, "wxsqlite3_config", 2, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
codecParameterTable, wxsqlite3_config_params, 0, 0);
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_create_function(db, "wxsqlite3_config", 3, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
codecParameterTable, wxsqlite3_config_params, 0, 0);
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_create_function(db, "wxsqlite3_codec_data", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
NULL, wxsqlite3_codec_data_sql, 0, 0);
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_create_function(db, "wxsqlite3_codec_data", 2, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
NULL, wxsqlite3_codec_data_sql, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
registerAllExtensions(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
/*
|
||||
** Register the encryption extension functions and
|
||||
** configure the encryption extension from URI parameters as default
|
||||
*/
|
||||
rc = CodecConfigureFromUri(db, NULL, 1);
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_EXTFUNC
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = RegisterExtensionFunctions(db);
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_CSV
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_csv_init(db, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_SHA3
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_shathree_init(db, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_CARRAY
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_carray_init(db, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FILEIO
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_fileio_init(db, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_SERIES
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3_series_init(db, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Prototypes for sqlite3_open function variants to make pedantic compilers happy */
|
||||
SQLITE_API int sqlite3_open(const char *filename, sqlite3 **ppDb);
|
||||
SQLITE_API int sqlite3_open16(const void *filename, sqlite3 **ppDb);
|
||||
SQLITE_API int sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs);
|
||||
|
||||
SQLITE_API int sqlite3_open(
|
||||
const char *filename, /* Database filename (UTF-8) */
|
||||
sqlite3 **ppDb /* OUT: SQLite db handle */
|
||||
)
|
||||
{
|
||||
int ret = sqlite3_open_internal(filename, ppDb);
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = registerAllExtensions(*ppDb, NULL, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
SQLITE_API int sqlite3_open16(
|
||||
const void *filename, /* Database filename (UTF-16) */
|
||||
sqlite3 **ppDb /* OUT: SQLite db handle */
|
||||
)
|
||||
{
|
||||
int ret = sqlite3_open16_internal(filename, ppDb);
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = registerAllExtensions(*ppDb, NULL, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
SQLITE_API int sqlite3_open_v2(
|
||||
const char *filename, /* Database filename (UTF-8) */
|
||||
sqlite3 **ppDb, /* OUT: SQLite db handle */
|
||||
int flags, /* Flags */
|
||||
const char *zVfs /* Name of VFS module to use */
|
||||
)
|
||||
{
|
||||
int ret = sqlite3_open_v2_internal(filename, ppDb, flags, zVfs);
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = registerAllExtensions(*ppDb, NULL, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
** Version
|
||||
*/
|
||||
ID_SQLITE3 ICON "sqlite370.ico"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,29,0,0
|
||||
PRODUCTVERSION 3,29,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "SQLite"
|
||||
VALUE "FileDescription", "SQLite3 Database Shell (with encryption support)"
|
||||
VALUE "FileVersion", "3.29.0.0"
|
||||
VALUE "InternalName", "sqlite3shell.exe"
|
||||
VALUE "LegalCopyright", "Public Domain"
|
||||
VALUE "OriginalFilename", "sqlite3shell.exe"
|
||||
VALUE "ProductName", "SQLite3"
|
||||
VALUE "ProductVersion", "3.29.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
** 2014-09-08
|
||||
**
|
||||
** 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 the application interface definitions for the
|
||||
** user-authentication extension feature.
|
||||
**
|
||||
** To compile with the user-authentication feature, append this file to
|
||||
** end of an SQLite amalgamation header file ("sqlite3.h"), then add
|
||||
** the SQLITE_USER_AUTHENTICATION compile-time option. See the
|
||||
** user-auth.txt file in the same source directory as this file for
|
||||
** additional information.
|
||||
*/
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If a database contains the SQLITE_USER table, then the
|
||||
** sqlite3_user_authenticate() interface must be invoked with an
|
||||
** appropriate username and password prior to enable read and write
|
||||
** access to the database.
|
||||
**
|
||||
** Return SQLITE_OK on success or SQLITE_ERROR if the username/password
|
||||
** combination is incorrect or unknown.
|
||||
**
|
||||
** If the SQLITE_USER table is not present in the database file, then
|
||||
** this interface is a harmless no-op returnning SQLITE_OK.
|
||||
*/
|
||||
int sqlite3_user_authenticate(
|
||||
sqlite3 *db, /* The database connection */
|
||||
const char *zUsername, /* Username */
|
||||
const char *aPW, /* Password or credentials */
|
||||
int nPW /* Number of bytes in aPW[] */
|
||||
);
|
||||
|
||||
/*
|
||||
** The sqlite3_user_add() interface can be used (by an admin user only)
|
||||
** to create a new user. When called on a no-authentication-required
|
||||
** database, this routine converts the database into an authentication-
|
||||
** required database, automatically makes the added user an
|
||||
** administrator, and logs in the current connection as that user.
|
||||
** The sqlite3_user_add() interface only works for the "main" database, not
|
||||
** for any ATTACH-ed databases. Any call to sqlite3_user_add() by a
|
||||
** non-admin user results in an error.
|
||||
*/
|
||||
int sqlite3_user_add(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername, /* Username to be added */
|
||||
const char *aPW, /* Password or credentials */
|
||||
int nPW, /* Number of bytes in aPW[] */
|
||||
int isAdmin /* True to give new user admin privilege */
|
||||
);
|
||||
|
||||
/*
|
||||
** The sqlite3_user_change() interface can be used to change a users
|
||||
** login credentials or admin privilege. Any user can change their own
|
||||
** login credentials. Only an admin user can change another users login
|
||||
** credentials or admin privilege setting. No user may change their own
|
||||
** admin privilege setting.
|
||||
*/
|
||||
int sqlite3_user_change(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername, /* Username to change */
|
||||
const char *aPW, /* New password or credentials */
|
||||
int nPW, /* Number of bytes in aPW[] */
|
||||
int isAdmin /* Modified admin privilege for the user */
|
||||
);
|
||||
|
||||
/*
|
||||
** The sqlite3_user_delete() interface can be used (by an admin user only)
|
||||
** to delete a user. The currently logged-in user cannot be deleted,
|
||||
** which guarantees that there is always an admin user and hence that
|
||||
** the database cannot be converted into a no-authentication-required
|
||||
** database.
|
||||
*/
|
||||
int sqlite3_user_delete(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername /* Username to remove */
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of the 'extern "C"' block */
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE_USER_AUTHENTICATION */
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
** 2015 November 30
|
||||
**
|
||||
** 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 code to implement most of the opendir() family of
|
||||
** POSIX functions on Win32 using the MSVCRT.
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
#include "test_windirent.h"
|
||||
|
||||
/*
|
||||
** Implementation of the POSIX getenv() function using the Win32 API.
|
||||
** This function is not thread-safe.
|
||||
*/
|
||||
const char *windirent_getenv(
|
||||
const char *name
|
||||
){
|
||||
static char value[32768]; /* Maximum length, per MSDN */
|
||||
DWORD dwSize = sizeof(value) / sizeof(char); /* Size in chars */
|
||||
DWORD dwRet; /* Value returned by GetEnvironmentVariableA() */
|
||||
|
||||
memset(value, 0, sizeof(value));
|
||||
dwRet = GetEnvironmentVariableA(name, value, dwSize);
|
||||
if( dwRet==0 || dwRet>dwSize ){
|
||||
/*
|
||||
** The function call to GetEnvironmentVariableA() failed -OR-
|
||||
** the buffer is not large enough. Either way, return NULL.
|
||||
*/
|
||||
return 0;
|
||||
}else{
|
||||
/*
|
||||
** The function call to GetEnvironmentVariableA() succeeded
|
||||
** -AND- the buffer contains the entire value.
|
||||
*/
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the POSIX opendir() function using the MSVCRT.
|
||||
*/
|
||||
LPDIR opendir(
|
||||
const char *dirname
|
||||
){
|
||||
struct _finddata_t data;
|
||||
LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR));
|
||||
SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]);
|
||||
|
||||
if( dirp==NULL ) return NULL;
|
||||
memset(dirp, 0, sizeof(DIR));
|
||||
|
||||
/* TODO: Remove this if Unix-style root paths are not used. */
|
||||
if( sqlite3_stricmp(dirname, "/")==0 ){
|
||||
dirname = windirent_getenv("SystemDrive");
|
||||
}
|
||||
|
||||
memset(&data, 0, sizeof(struct _finddata_t));
|
||||
_snprintf(data.name, namesize, "%s\\*", dirname);
|
||||
dirp->d_handle = _findfirst(data.name, &data);
|
||||
|
||||
if( dirp->d_handle==BAD_INTPTR_T ){
|
||||
closedir(dirp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* TODO: Remove this block to allow hidden and/or system files. */
|
||||
if( is_filtered(data) ){
|
||||
next:
|
||||
|
||||
memset(&data, 0, sizeof(struct _finddata_t));
|
||||
if( _findnext(dirp->d_handle, &data)==-1 ){
|
||||
closedir(dirp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* TODO: Remove this block to allow hidden and/or system files. */
|
||||
if( is_filtered(data) ) goto next;
|
||||
}
|
||||
|
||||
dirp->d_first.d_attributes = data.attrib;
|
||||
strncpy(dirp->d_first.d_name, data.name, NAME_MAX);
|
||||
dirp->d_first.d_name[NAME_MAX] = '\0';
|
||||
|
||||
return dirp;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the POSIX readdir() function using the MSVCRT.
|
||||
*/
|
||||
LPDIRENT readdir(
|
||||
LPDIR dirp
|
||||
){
|
||||
struct _finddata_t data;
|
||||
|
||||
if( dirp==NULL ) return NULL;
|
||||
|
||||
if( dirp->d_first.d_ino==0 ){
|
||||
dirp->d_first.d_ino++;
|
||||
dirp->d_next.d_ino++;
|
||||
|
||||
return &dirp->d_first;
|
||||
}
|
||||
|
||||
next:
|
||||
|
||||
memset(&data, 0, sizeof(struct _finddata_t));
|
||||
if( _findnext(dirp->d_handle, &data)==-1 ) return NULL;
|
||||
|
||||
/* TODO: Remove this block to allow hidden and/or system files. */
|
||||
if( is_filtered(data) ) goto next;
|
||||
|
||||
dirp->d_next.d_ino++;
|
||||
dirp->d_next.d_attributes = data.attrib;
|
||||
strncpy(dirp->d_next.d_name, data.name, NAME_MAX);
|
||||
dirp->d_next.d_name[NAME_MAX] = '\0';
|
||||
|
||||
return &dirp->d_next;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the POSIX readdir_r() function using the MSVCRT.
|
||||
*/
|
||||
INT readdir_r(
|
||||
LPDIR dirp,
|
||||
LPDIRENT entry,
|
||||
LPDIRENT *result
|
||||
){
|
||||
struct _finddata_t data;
|
||||
|
||||
if( dirp==NULL ) return EBADF;
|
||||
|
||||
if( dirp->d_first.d_ino==0 ){
|
||||
dirp->d_first.d_ino++;
|
||||
dirp->d_next.d_ino++;
|
||||
|
||||
entry->d_ino = dirp->d_first.d_ino;
|
||||
entry->d_attributes = dirp->d_first.d_attributes;
|
||||
strncpy(entry->d_name, dirp->d_first.d_name, NAME_MAX);
|
||||
entry->d_name[NAME_MAX] = '\0';
|
||||
|
||||
*result = entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
next:
|
||||
|
||||
memset(&data, 0, sizeof(struct _finddata_t));
|
||||
if( _findnext(dirp->d_handle, &data)==-1 ){
|
||||
*result = NULL;
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
/* TODO: Remove this block to allow hidden and/or system files. */
|
||||
if( is_filtered(data) ) goto next;
|
||||
|
||||
entry->d_ino = (ino_t)-1; /* not available */
|
||||
entry->d_attributes = data.attrib;
|
||||
strncpy(entry->d_name, data.name, NAME_MAX);
|
||||
entry->d_name[NAME_MAX] = '\0';
|
||||
|
||||
*result = entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the POSIX closedir() function using the MSVCRT.
|
||||
*/
|
||||
INT closedir(
|
||||
LPDIR dirp
|
||||
){
|
||||
INT result = 0;
|
||||
|
||||
if( dirp==NULL ) return EINVAL;
|
||||
|
||||
if( dirp->d_handle!=NULL_INTPTR_T && dirp->d_handle!=BAD_INTPTR_T ){
|
||||
result = _findclose(dirp->d_handle);
|
||||
}
|
||||
|
||||
sqlite3_free(dirp);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* defined(WIN32) && defined(_MSC_VER) */
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
** 2015 November 30
|
||||
**
|
||||
** 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 declarations for most of the opendir() family of
|
||||
** POSIX functions on Win32 using the MSVCRT.
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER) && !defined(SQLITE_WINDIRENT_H)
|
||||
#define SQLITE_WINDIRENT_H
|
||||
|
||||
/*
|
||||
** We need several data types from the Windows SDK header.
|
||||
*/
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include "windows.h"
|
||||
|
||||
/*
|
||||
** We need several support functions from the SQLite core.
|
||||
*/
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** We need several things from the ANSI and MSVCRT headers.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <io.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/*
|
||||
** We may need several defines that should have been in "sys/stat.h".
|
||||
*/
|
||||
|
||||
#ifndef S_ISREG
|
||||
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
|
||||
#ifndef S_ISDIR
|
||||
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
|
||||
#ifndef S_ISLNK
|
||||
#define S_ISLNK(mode) (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** We may need to provide the "mode_t" type.
|
||||
*/
|
||||
|
||||
#ifndef MODE_T_DEFINED
|
||||
#define MODE_T_DEFINED
|
||||
typedef unsigned short mode_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** We may need to provide the "ino_t" type.
|
||||
*/
|
||||
|
||||
#ifndef INO_T_DEFINED
|
||||
#define INO_T_DEFINED
|
||||
typedef unsigned short ino_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** We need to define "NAME_MAX" if it was not present in "limits.h".
|
||||
*/
|
||||
|
||||
#ifndef NAME_MAX
|
||||
# ifdef FILENAME_MAX
|
||||
# define NAME_MAX (FILENAME_MAX)
|
||||
# else
|
||||
# define NAME_MAX (260)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** We need to define "NULL_INTPTR_T" and "BAD_INTPTR_T".
|
||||
*/
|
||||
|
||||
#ifndef NULL_INTPTR_T
|
||||
# define NULL_INTPTR_T ((intptr_t)(0))
|
||||
#endif
|
||||
|
||||
#ifndef BAD_INTPTR_T
|
||||
# define BAD_INTPTR_T ((intptr_t)(-1))
|
||||
#endif
|
||||
|
||||
/*
|
||||
** We need to provide the necessary structures and related types.
|
||||
*/
|
||||
|
||||
#ifndef DIRENT_DEFINED
|
||||
#define DIRENT_DEFINED
|
||||
typedef struct DIRENT DIRENT;
|
||||
typedef DIRENT *LPDIRENT;
|
||||
struct DIRENT {
|
||||
ino_t d_ino; /* Sequence number, do not use. */
|
||||
unsigned d_attributes; /* Win32 file attributes. */
|
||||
char d_name[NAME_MAX + 1]; /* Name within the directory. */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef DIR_DEFINED
|
||||
#define DIR_DEFINED
|
||||
typedef struct DIR DIR;
|
||||
typedef DIR *LPDIR;
|
||||
struct DIR {
|
||||
intptr_t d_handle; /* Value returned by "_findfirst". */
|
||||
DIRENT d_first; /* DIRENT constructed based on "_findfirst". */
|
||||
DIRENT d_next; /* DIRENT constructed based on "_findnext". */
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Provide a macro, for use by the implementation, to determine if a
|
||||
** particular directory entry should be skipped over when searching for
|
||||
** the next directory entry that should be returned by the readdir() or
|
||||
** readdir_r() functions.
|
||||
*/
|
||||
|
||||
#ifndef is_filtered
|
||||
# define is_filtered(a) ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM))
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Provide the function prototype for the POSIX compatiable getenv()
|
||||
** function. This function is not thread-safe.
|
||||
*/
|
||||
|
||||
extern const char *windirent_getenv(const char *name);
|
||||
|
||||
/*
|
||||
** Finally, we can provide the function prototypes for the opendir(),
|
||||
** readdir(), readdir_r(), and closedir() POSIX functions.
|
||||
*/
|
||||
|
||||
extern LPDIR opendir(const char *dirname);
|
||||
extern LPDIRENT readdir(LPDIR dirp);
|
||||
extern INT readdir_r(LPDIR dirp, LPDIRENT entry, LPDIRENT *result);
|
||||
extern INT closedir(LPDIR dirp);
|
||||
|
||||
#endif /* defined(WIN32) && defined(_MSC_VER) */
|
||||
+363
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
** 2014-09-08
|
||||
**
|
||||
** 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 the bulk of the implementation of the
|
||||
** user-authentication extension feature. Some parts of the user-
|
||||
** authentication code are contained within the SQLite core (in the
|
||||
** src/ subdirectory of the main source code tree) but those parts
|
||||
** that could reasonable be separated out are moved into this file.
|
||||
**
|
||||
** To compile with the user-authentication feature, append this file to
|
||||
** end of an SQLite amalgamation, then add the SQLITE_USER_AUTHENTICATION
|
||||
** compile-time option. See the user-auth.txt file in the same source
|
||||
** directory as this file for additional information.
|
||||
*/
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
#ifndef SQLITEINT_H
|
||||
# include "sqliteInt.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Prepare an SQL statement for use by the user authentication logic.
|
||||
** Return a pointer to the prepared statement on success. Return a
|
||||
** NULL pointer if there is an error of any kind.
|
||||
*/
|
||||
static sqlite3_stmt *sqlite3UserAuthPrepare(
|
||||
sqlite3 *db,
|
||||
const char *zFormat,
|
||||
...
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
char *zSql;
|
||||
int rc;
|
||||
va_list ap;
|
||||
int savedFlags = db->flags;
|
||||
|
||||
va_start(ap, zFormat);
|
||||
zSql = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zSql==0 ) return 0;
|
||||
db->flags |= SQLITE_WriteSchema;
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
db->flags = savedFlags;
|
||||
sqlite3_free(zSql);
|
||||
if( rc ){
|
||||
sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
}
|
||||
return pStmt;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if the sqlite_user table exists in database zDb.
|
||||
*/
|
||||
static int userTableExists(sqlite3 *db, const char *zDb){
|
||||
int rc;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
sqlite3BtreeEnterAll(db);
|
||||
if( db->init.busy==0 ){
|
||||
char *zErr = 0;
|
||||
sqlite3Init(db, &zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
}
|
||||
rc = sqlite3FindTable(db, "sqlite_user", zDb)!=0;
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if database zDb has a "sqlite_user" table and if it does
|
||||
** whether that table can authenticate zUser with nPw,zPw. Write one of
|
||||
** the UAUTH_* user authorization level codes into *peAuth and return a
|
||||
** result code.
|
||||
*/
|
||||
static int userAuthCheckLogin(
|
||||
sqlite3 *db, /* The database connection to check */
|
||||
const char *zDb, /* Name of specific database to check */
|
||||
u8 *peAuth /* OUT: One of UAUTH_* constants */
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
|
||||
*peAuth = UAUTH_Unknown;
|
||||
if( !userTableExists(db, "main") ){
|
||||
*peAuth = UAUTH_Admin; /* No sqlite_user table. Everybody is admin. */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( db->auth.zAuthUser==0 ){
|
||||
*peAuth = UAUTH_Fail;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pStmt = sqlite3UserAuthPrepare(db,
|
||||
"SELECT pw=sqlite_crypt(?1,pw), isAdmin FROM \"%w\".sqlite_user"
|
||||
" WHERE uname=?2", zDb);
|
||||
if( pStmt==0 ) return SQLITE_NOMEM;
|
||||
sqlite3_bind_blob(pStmt, 1, db->auth.zAuthPW, db->auth.nAuthPW,SQLITE_STATIC);
|
||||
sqlite3_bind_text(pStmt, 2, db->auth.zAuthUser, -1, SQLITE_STATIC);
|
||||
rc = sqlite3_step(pStmt);
|
||||
if( rc==SQLITE_ROW && sqlite3_column_int(pStmt,0) ){
|
||||
*peAuth = sqlite3_column_int(pStmt, 1) + UAUTH_User;
|
||||
}else{
|
||||
*peAuth = UAUTH_Fail;
|
||||
}
|
||||
return sqlite3_finalize(pStmt);
|
||||
}
|
||||
int sqlite3UserAuthCheckLogin(
|
||||
sqlite3 *db, /* The database connection to check */
|
||||
const char *zDb, /* Name of specific database to check */
|
||||
u8 *peAuth /* OUT: One of UAUTH_* constants */
|
||||
){
|
||||
int rc;
|
||||
u8 savedAuthLevel;
|
||||
assert( zDb!=0 );
|
||||
assert( peAuth!=0 );
|
||||
savedAuthLevel = db->auth.authLevel;
|
||||
db->auth.authLevel = UAUTH_Admin;
|
||||
rc = userAuthCheckLogin(db, zDb, peAuth);
|
||||
db->auth.authLevel = savedAuthLevel;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** If the current authLevel is UAUTH_Unknown, the take actions to figure
|
||||
** out what authLevel should be
|
||||
*/
|
||||
void sqlite3UserAuthInit(sqlite3 *db){
|
||||
if( db->auth.authLevel==UAUTH_Unknown ){
|
||||
u8 authLevel = UAUTH_Fail;
|
||||
sqlite3UserAuthCheckLogin(db, "main", &authLevel);
|
||||
db->auth.authLevel = authLevel;
|
||||
if( authLevel<UAUTH_Admin ) db->flags &= ~SQLITE_WriteSchema;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sqlite_crypt(X,Y) function.
|
||||
**
|
||||
** If Y is NULL then generate a new hash for password X and return that
|
||||
** hash. If Y is not null, then generate a hash for password X using the
|
||||
** same salt as the previous hash Y and return the new hash.
|
||||
*/
|
||||
void sqlite3CryptFunc(
|
||||
sqlite3_context *context,
|
||||
int NotUsed,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zIn;
|
||||
int nIn;
|
||||
u8 *zData;
|
||||
u8 *zOut;
|
||||
char zSalt[16];
|
||||
int nHash = 32;
|
||||
zIn = sqlite3_value_blob(argv[0]);
|
||||
nIn = sqlite3_value_bytes(argv[0]);
|
||||
if( sqlite3_value_type(argv[1])==SQLITE_BLOB
|
||||
&& sqlite3_value_bytes(argv[1])==nHash+sizeof(zSalt)
|
||||
){
|
||||
memcpy(zSalt, sqlite3_value_blob(argv[1]), sizeof(zSalt));
|
||||
}else{
|
||||
sqlite3_randomness(sizeof(zSalt), zSalt);
|
||||
}
|
||||
zData = sqlite3_malloc( nIn+sizeof(zSalt) );
|
||||
zOut = sqlite3_malloc( nHash+sizeof(zSalt) );
|
||||
if( zOut==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
}else{
|
||||
memcpy(zData, zSalt, sizeof(zSalt));
|
||||
memcpy(zData+sizeof(zSalt), zIn, nIn);
|
||||
memcpy(zOut, zSalt, sizeof(zSalt));
|
||||
sha256(zData, (unsigned int) nIn+sizeof(zSalt), zOut+sizeof(zSalt));
|
||||
sqlite3_result_blob(context, zOut, nHash+sizeof(zSalt), sqlite3_free);
|
||||
}
|
||||
if (zData != 0) sqlite3_free(zData);
|
||||
}
|
||||
|
||||
/*
|
||||
** If a database contains the SQLITE_USER table, then the
|
||||
** sqlite3_user_authenticate() interface must be invoked with an
|
||||
** appropriate username and password prior to enable read and write
|
||||
** access to the database.
|
||||
**
|
||||
** Return SQLITE_OK on success or SQLITE_ERROR if the username/password
|
||||
** combination is incorrect or unknown.
|
||||
**
|
||||
** If the SQLITE_USER table is not present in the database file, then
|
||||
** this interface is a harmless no-op returnning SQLITE_OK.
|
||||
*/
|
||||
int sqlite3_user_authenticate(
|
||||
sqlite3 *db, /* The database connection */
|
||||
const char *zUsername, /* Username */
|
||||
const char *zPW, /* Password or credentials */
|
||||
int nPW /* Number of bytes in aPW[] */
|
||||
){
|
||||
int rc;
|
||||
u8 authLevel = UAUTH_Fail;
|
||||
db->auth.authLevel = UAUTH_Unknown;
|
||||
sqlite3_free(db->auth.zAuthUser);
|
||||
sqlite3_free(db->auth.zAuthPW);
|
||||
memset(&db->auth, 0, sizeof(db->auth));
|
||||
db->auth.zAuthUser = sqlite3_mprintf("%s", zUsername);
|
||||
if( db->auth.zAuthUser==0 ) return SQLITE_NOMEM;
|
||||
db->auth.zAuthPW = sqlite3_malloc( nPW+1 );
|
||||
if( db->auth.zAuthPW==0 ) return SQLITE_NOMEM;
|
||||
memcpy(db->auth.zAuthPW,zPW,nPW);
|
||||
db->auth.nAuthPW = nPW;
|
||||
rc = sqlite3UserAuthCheckLogin(db, "main", &authLevel);
|
||||
db->auth.authLevel = authLevel;
|
||||
#if (SQLITE_VERSION_NUMBER >= 3025000)
|
||||
sqlite3ExpirePreparedStatements(db, 0);
|
||||
#else
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
#endif
|
||||
if( rc ){
|
||||
return rc; /* OOM error, I/O error, etc. */
|
||||
}
|
||||
if( authLevel<UAUTH_User ){
|
||||
return SQLITE_AUTH; /* Incorrect username and/or password */
|
||||
}
|
||||
return SQLITE_OK; /* Successful login */
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_user_add() interface can be used (by an admin user only)
|
||||
** to create a new user. When called on a no-authentication-required
|
||||
** database, this routine converts the database into an authentication-
|
||||
** required database, automatically makes the added user an
|
||||
** administrator, and logs in the current connection as that user.
|
||||
** The sqlite3_user_add() interface only works for the "main" database, not
|
||||
** for any ATTACH-ed databases. Any call to sqlite3_user_add() by a
|
||||
** non-admin user results in an error.
|
||||
*/
|
||||
int sqlite3_user_add(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername, /* Username to be added */
|
||||
const char *aPW, /* Password or credentials */
|
||||
int nPW, /* Number of bytes in aPW[] */
|
||||
int isAdmin /* True to give new user admin privilege */
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
sqlite3UserAuthInit(db);
|
||||
if( db->auth.authLevel<UAUTH_Admin ) return SQLITE_AUTH;
|
||||
if( !userTableExists(db, "main") ){
|
||||
if( !isAdmin ) return SQLITE_AUTH;
|
||||
pStmt = sqlite3UserAuthPrepare(db,
|
||||
"CREATE TABLE sqlite_user(\n"
|
||||
" uname TEXT PRIMARY KEY,\n"
|
||||
" isAdmin BOOLEAN,\n"
|
||||
" pw BLOB\n"
|
||||
") WITHOUT ROWID;");
|
||||
if( pStmt==0 ) return SQLITE_NOMEM;
|
||||
sqlite3_step(pStmt);
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
pStmt = sqlite3UserAuthPrepare(db,
|
||||
"INSERT INTO sqlite_user(uname,isAdmin,pw)"
|
||||
" VALUES(%Q,%d,sqlite_crypt(?1,NULL))",
|
||||
zUsername, isAdmin!=0);
|
||||
if( pStmt==0 ) return SQLITE_NOMEM;
|
||||
sqlite3_bind_blob(pStmt, 1, aPW, nPW, SQLITE_STATIC);
|
||||
sqlite3_step(pStmt);
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc ) return rc;
|
||||
if( db->auth.zAuthUser==0 ){
|
||||
assert( isAdmin!=0 );
|
||||
sqlite3_user_authenticate(db, zUsername, aPW, nPW);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_user_change() interface can be used to change a users
|
||||
** login credentials or admin privilege. Any user can change their own
|
||||
** login credentials. Only an admin user can change another users login
|
||||
** credentials or admin privilege setting. No user may change their own
|
||||
** admin privilege setting.
|
||||
*/
|
||||
int sqlite3_user_change(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername, /* Username to change */
|
||||
const char *aPW, /* Modified password or credentials */
|
||||
int nPW, /* Number of bytes in aPW[] */
|
||||
int isAdmin /* Modified admin privilege for the user */
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
u8 authLevel;
|
||||
|
||||
authLevel = db->auth.authLevel;
|
||||
if( authLevel<UAUTH_User ){
|
||||
/* Must be logged in to make a change */
|
||||
return SQLITE_AUTH;
|
||||
}
|
||||
if( strcmp(db->auth.zAuthUser, zUsername)!=0 ){
|
||||
if( db->auth.authLevel<UAUTH_Admin ){
|
||||
/* Must be an administrator to change a different user */
|
||||
return SQLITE_AUTH;
|
||||
}
|
||||
}else if( isAdmin!=(authLevel==UAUTH_Admin) ){
|
||||
/* Cannot change the isAdmin setting for self */
|
||||
return SQLITE_AUTH;
|
||||
}
|
||||
db->auth.authLevel = UAUTH_Admin;
|
||||
if( !userTableExists(db, "main") ){
|
||||
/* This routine is a no-op if the user to be modified does not exist */
|
||||
}else{
|
||||
pStmt = sqlite3UserAuthPrepare(db,
|
||||
"UPDATE sqlite_user SET isAdmin=%d, pw=sqlite_crypt(?1,NULL)"
|
||||
" WHERE uname=%Q", isAdmin, zUsername);
|
||||
if( pStmt==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
sqlite3_bind_blob(pStmt, 1, aPW, nPW, SQLITE_STATIC);
|
||||
sqlite3_step(pStmt);
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
}
|
||||
}
|
||||
db->auth.authLevel = authLevel;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_user_delete() interface can be used (by an admin user only)
|
||||
** to delete a user. The currently logged-in user cannot be deleted,
|
||||
** which guarantees that there is always an admin user and hence that
|
||||
** the database cannot be converted into a no-authentication-required
|
||||
** database.
|
||||
*/
|
||||
int sqlite3_user_delete(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername /* Username to remove */
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
if( db->auth.authLevel<UAUTH_Admin ){
|
||||
/* Must be an administrator to delete a user */
|
||||
return SQLITE_AUTH;
|
||||
}
|
||||
if( strcmp(db->auth.zAuthUser, zUsername)==0 ){
|
||||
/* Cannot delete self */
|
||||
return SQLITE_AUTH;
|
||||
}
|
||||
if( !userTableExists(db, "main") ){
|
||||
/* This routine is a no-op if the user to be deleted does not exist */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pStmt = sqlite3UserAuthPrepare(db,
|
||||
"DELETE FROM sqlite_user WHERE uname=%Q", zUsername);
|
||||
if( pStmt==0 ) return SQLITE_NOMEM;
|
||||
sqlite3_step(pStmt);
|
||||
return sqlite3_finalize(pStmt);
|
||||
}
|
||||
|
||||
#endif /* SQLITE_USER_AUTHENTICATION */
|
||||
Reference in New Issue
Block a user