mirror of
https://github.com/InoriRus/Kyty.git
synced 2026-08-28 05:06:40 +00:00
Initial commit
This commit is contained in:
+29
@@ -0,0 +1,29 @@
|
||||
file(GLOB sqlite_src
|
||||
"src/altered_sqlite3secure.c"
|
||||
)
|
||||
|
||||
|
||||
if (MINGW)
|
||||
if (CLANG)
|
||||
set_source_files_properties(${sqlite_src} PROPERTIES COMPILE_FLAGS "-Wno-unused-function -Wno-unknown-pragmas -Wno-unused-variable -Wno-sometimes-uninitialized")
|
||||
else()
|
||||
set_source_files_properties(${sqlite_src} PROPERTIES COMPILE_FLAGS "-Wno-return-local-addr -Wno-unused-but-set-variable -Wno-unused-function -Wno-unknown-pragmas -Wno-unused-variable -Wno-maybe-uninitialized -Wno-array-bounds")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (CLANG)
|
||||
set_source_files_properties(${sqlite_src} PROPERTIES COMPILE_FLAGS "-D_CRT_SECURE_NO_WARNINGS -Wno-builtin-macro-redefined -Wno-unused-function -Wno-unknown-pragmas -Wno-unused-variable -Wno-sometimes-uninitialized")
|
||||
else()
|
||||
set_source_files_properties(${sqlite_src} PROPERTIES COMPILE_FLAGS "-D_CRT_SECURE_NO_WARNINGS /wd4267 /wd4101")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#add_library(sqlite STATIC ${sqlite_src})
|
||||
add_library(sqlite_obj OBJECT ${sqlite_src})
|
||||
add_library(sqlite STATIC $<TARGET_OBJECTS:sqlite_obj>)
|
||||
|
||||
target_include_directories(sqlite PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
|
||||
target_include_directories(sqlite_obj PRIVATE $<TARGET_PROPERTY:sqlite,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
|
||||
Vendored
+195
@@ -0,0 +1,195 @@
|
||||
SPDX-License-Identifier: LGPL-3.0+ WITH WxWindows-exception-3.1
|
||||
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
|
||||
|
||||
wxWindows 3.1 EXCEPTION NOTICE
|
||||
|
||||
1. As a special exception, the copyright holders of this library give
|
||||
permission for additional uses of the text contained in this release of
|
||||
the library as licenced under the wxWindows Library Licence, applying
|
||||
either version 3.1 of the Licence, or (at your option) any later version
|
||||
of the Licence as published by the copyright holders of version 3.1 of
|
||||
the Licence document.
|
||||
|
||||
2. The exception is that you may use, copy, link, modify and
|
||||
distribute under your own terms, binary object code versions of works
|
||||
based on the Library.
|
||||
|
||||
3. If you copy code from files distributed under the terms of the GNU
|
||||
General Public Licence or the GNU Library General Public Licence into a
|
||||
copy of this library, as this licence permits, the exception does not
|
||||
apply to the code that you add in this way. To avoid misleading anyone
|
||||
as to the status of such modified files, you must delete this exception
|
||||
notice from such code and/or adjust the licensing conditions notice
|
||||
accordingly.
|
||||
|
||||
4. If you write modifications of your own for this library, it is your
|
||||
choice whether to permit this exception to apply to your modifications.
|
||||
If you do not wish that, you must delete the exception notice from such
|
||||
code and/or adjust the licensing conditions notice accordingly.
|
||||
+11792
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
#ifndef _3RDPARTY_SQLITE_INCLUDE_SQLITE3_OPTIONS_H_
|
||||
#define _3RDPARTY_SQLITE_INCLUDE_SQLITE3_OPTIONS_H_
|
||||
|
||||
#define SQLITE_HAS_CODEC 1
|
||||
#define SQLITE_ENABLE_COLUMN_METADATA 1 /* Access to meta-data about tables and queries */
|
||||
#define SQLITE_THREADSAFE 1 /* In serialized mode, SQLite can be safely used by multiple threads with no restriction. */
|
||||
#define SQLITE_TEMP_STORE 3 /* Always use memory */
|
||||
#define SQLITE_OS_OTHER 1 /* Omit its built-in operating system interfaces */
|
||||
#define SQLITE_OMIT_AUTOINIT 1 /* SQLite will not automatically initialize itself */
|
||||
|
||||
#endif /* _3RDPARTY_SQLITE_INCLUDE_SQLITE3_OPTIONS_H_ */
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
** Name: sqlite3secure.h
|
||||
** Purpose: Header file for SQLite codecs
|
||||
** Author: Ulrich Telle
|
||||
** Created: 2018-03-30
|
||||
** Copyright: (c) 2018 Ulrich Telle
|
||||
** License: LGPL-3.0+ WITH WxWindows-exception-3.1
|
||||
*/
|
||||
|
||||
#ifndef SQLITE3SECURE_H_
|
||||
#define SQLITE3SECURE_H_
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
// Symbols for ciphers
|
||||
#define CODEC_TYPE_UNKNOWN 0
|
||||
#define CODEC_TYPE_AES128 1
|
||||
#define CODEC_TYPE_AES256 2
|
||||
#define CODEC_TYPE_CHACHA20 3
|
||||
#define CODEC_TYPE_SQLCIPHER 4
|
||||
#define CODEC_TYPE_MAX 4
|
||||
|
||||
// Define Windows specific SQLite API functions (not defined in sqlite3.h)
|
||||
#if SQLITE_VERSION_NUMBER >= 3007014
|
||||
#if SQLITE_OS_WIN == 1
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#if SQLITE_VERSION_NUMBER >= 3024000
|
||||
SQLITE_API int sqlite3_win32_set_directory(unsigned long type, void* zValue);
|
||||
#else
|
||||
SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue);
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
|
||||
// Define functions for the configuration of the wxSQLite3 encryption extension
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
SQLITE_API int wxsqlite3_config(sqlite3* db, const char* paramName, int newValue);
|
||||
SQLITE_API int wxsqlite3_config_cipher(sqlite3* db, const char* cipherName, const char* paramName, int newValue);
|
||||
SQLITE_API unsigned char* wxsqlite3_codec_data(sqlite3* db, const char* zDbName, const char* paramName);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
All of the code and documentation in SQLite has been dedicated to the public domain by the authors. All code authors, and representatives of the companies they work for, have signed affidavits dedicating their contributions to the public domain and originals of those signed affidavits are stored in a firesafe at the main offices of Hwaci. Anyone is free to copy, modify, publish, use, compile, sell, or distribute the original SQLite code, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
|
||||
|
||||
The previous paragraph applies to the deliverable code and documentation in SQLite - those parts of the SQLite library that you actually bundle and ship with a larger application. Some scripts used as part of the build process (for example the "configure" scripts generated by autoconf) might fall under other open-source licenses. Nothing from these build scripts ever reaches the final deliverable SQLite library, however, and so the licenses associated with those scripts should not be a factor in assessing your rights to copy and use the SQLite library.
|
||||
|
||||
All of the deliverable code in SQLite has been written from scratch. No code has been taken from other projects or from the open internet. Every line of code can be traced back to its original author, and all of those authors have public domain dedications on file. So the SQLite code base is clean and is uncontaminated with licensed code from other projects.
|
||||
+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